diff -u --recursive --new-file v2.1.86/linux/CREDITS linux/CREDITS
--- v2.1.86/linux/CREDITS	Thu Feb 12 20:56:03 1998
+++ linux/CREDITS	Sun Feb 15 12:16:44 1998
@@ -33,6 +33,12 @@
 S: B-2610 Wilrijk-Antwerpen
 S: Belgium
 
+N: C. Scott Ananian
+E: cananian@alumni.princeton.edu
+W: http://www.pdos.lcs.mit.edu/~cananian
+P: 1024/85AD9EED AD C0 49 08 91 67 DF D7  FA 04 1A EE 09 E8 44 B0
+D: pty improvements.
+
 N: Erik Andersen
 E: andersee@debian.org
 W: http://www.inconnect.com/~andersen
@@ -124,10 +130,12 @@
 S: Germany
 
 N: Fred Baumgarten
-E: dc6iq@insu1.etec.uni-karlsruhe.de
+E: dc6iq@insl1.etec.uni-karlsruhe.de
+E: dc6iq@adacom.org
+E: dc6iq@db0ais.#hes.deu.eu (packet radio)
 D: NET-2 & netstat(8)
-S: Kandelstrasse 27
-S: 76297 Stutensee
+S: Soevener Strasse 11
+S: 53773 Hennef
 S: Germany
 
 N: Donald Becker
@@ -356,7 +364,7 @@
 N: Eddie C. Dost
 E: ecd@skynet.be
 D: Linux/Sparc kernel hacker
-D: New Linux/Sparc maintainer (while davem is at SGI)
+D: Linux/Sparc maintainer
 S: Rue de la Chapelle 51
 S: 4850 Moresnet
 S: Belgium
@@ -675,6 +683,11 @@
 S: D - 72072 Tuebingen
 S: Germany
 
+N: Jauder Ho
+E: jauderho@transmeta.com
+D: bug toaster (A1 sauce makes all the difference)
+D: Transmeta BOFH in my free time
+
 N: Dirk Hohndel
 E: hohndel@aib.com
 D: The XFree86[tm] Project
@@ -1036,7 +1049,7 @@
 N: Pavel Machek
 E: pavel@atrey.karlin.mff.cuni.cz
 D: Softcursor for vga, hypertech cdrom support, vcsa bugfix
-D: Network block device
+D: Network block device, sun4/330 port 
 S: Volkova 1131
 S: 198 00 Praha 9
 S: Czech Republic
@@ -1162,8 +1175,8 @@
 D: New Linux-Activists maintainer
 D: Linux Emacs elf/qmagic support + other libc/gcc things
 D: Yee bore de yee bore! ;-)
-S: 2 Bristol Court
-S: East Brunswick, New Jersey 08816
+S: 111 Alta Tierra Court
+S: Los Gatos, CA 95032
 S: USA
 
 N: Rick Miller
diff -u --recursive --new-file v2.1.86/linux/Documentation/hayes-esp.txt linux/Documentation/hayes-esp.txt
--- v2.1.86/linux/Documentation/hayes-esp.txt	Mon Aug 11 16:57:59 1997
+++ linux/Documentation/hayes-esp.txt	Thu Feb 12 15:47:44 1998
@@ -1,14 +1,37 @@
-HAYES ESP DRIVER VERSION 1.6
+HAYES ESP DRIVER VERSION 2.0
+
+A big thanks to the people at Hayes, especially Alan Adamson.  Their support
+has enabled me to provide enhancements to the driver.
+
+Please report your experiences with this driver to me (arobinso@nyx.net).  I
+am looking for both positive and negative feedback.
+
+*** IMPORTANT CHANGES FOR 2.0 ***
+Support for PIO mode.  Five situations will cause PIO mode to be used:
+1) A multiport card is detected.  PIO mode will always be used.  (8 port cards
+do not support DMA).
+2) The DMA channel is set to an invalid value (anything other than 1 or 3).
+3) The DMA buffer/channel could not be allocated.  The port will revert to PIO
+mode until it is reopened.
+4) Less than 33 bytes need to be transferred to/from the FIFOs.  PIO mode will
+be used for that transfer only.
+5) A port needs to do a DMA transfer and another port is already using the
+DMA channel.  PIO mode will be used for that transfer only.
+
+A patch for setserial (2.12) is included to allow the ESP enhanced mode
+configuration to be viewed and changed.
+***
+
+This package contains the files needed to compile a module to support the Hayes
+ESP card.  The drivers are basically a modified version of the serial drivers.
 
 Features:
 
 - Uses the enhanced mode of the ESP card, allowing a wider range of
   interrupts and features than compatibilty mode
-- Uses DMA to transfer data to and from the ESP's FIFOs, reducing CPU load
+- Uses DMA and 16 bit PIO mode to transfer data to and from the ESP's FIFOs,
+  reducing CPU load
 - Supports primary and secondary ports
-- Special version of setserial can be used to view/change the enhanced mode
-  configuration.  The setserial patch is distributed with the standalone
-  driver distribution.  See http://www.nyx.net/~arobinso for more information.
 
 To compile/install:
 
@@ -47,7 +70,8 @@
 insmod esp divisor=0,0,0,0,0,0,0x84,0
 
 The dma= option can be used to set the DMA channel.  The channel can be either
-1 or 3.  For example, to set the dma channel to 3, the insmod command would be:
+1 or 3.  Specifying any other value will force the driver to use PIO mode.
+For example, to set the dma channel to 3, the insmod command would be:
 
 insmod esp dma=3
 
diff -u --recursive --new-file v2.1.86/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.1.86/linux/Documentation/ioctl-number.txt	Tue Dec  2 11:41:44 1997
+++ linux/Documentation/ioctl-number.txt	Tue Feb 10 16:58:15 1998
@@ -1,5 +1,5 @@
 Ioctl Numbers
-1 Sep 1997
+28 Jan 1998
 Michael Chastain
 <mec@shout.net>
 
@@ -86,7 +86,7 @@
 'W'	28-2F	linux/iso16-relay.h	in development
 'Y'	all	linux/cyclades.h
 'a'	all	various, see http://lrcwww.epfl.ch/linux-atm/magic.html
-'b'	00-3F	bit3 vme host bridge	in development:
+'b'	00-FF	bit3 vme host bridge	in development:
 					<mailto:natalia@nikhefk.nikhef.nl>
 'c'	all	linux/comstats.h
 'f'	all	linux/ext2_fs.h
@@ -108,6 +108,8 @@
 'w'	all	CERN SCI driver		in development
 'z'	00-3F	CAN bus card		in development:
 					<mailto:hdstich@connectu.ulm.circular.de>
+'z'	40-7F	CAN bas card		in development:
+					<mailto:oe@port.de>
 0x89	00-0F	asm-i386/sockios.h
 0x89	10-DF	linux/sockios.h
 0x89	E0-EF	linux/sockios.h		SIOCPROTOPRIVATE range
diff -u --recursive --new-file v2.1.86/linux/Documentation/m68k/framebuffer.txt linux/Documentation/m68k/framebuffer.txt
--- v2.1.86/linux/Documentation/m68k/framebuffer.txt	Tue May 13 22:41:00 1997
+++ linux/Documentation/m68k/framebuffer.txt	Thu Feb 12 16:30:11 1998
@@ -3,7 +3,7 @@
 		----------------------------------
 
 Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
-Last revised: March 23, 1997
+Last revised: January 24, 1998
 
 
 0. Introduction
@@ -23,85 +23,47 @@
 --------------------------
 
 From the user's point of view, the frame buffer device looks just like any
-other device in /dev. It's a character device using major 29, the minor is
-divided into a frame buffer number in the upper 3 bits (allowing max. 8 frame
-buffers simultaneously) and a resolution code in the lower 5 bits of the minor.
+other device in /dev. It's a character device using major 29; the minor
+specifies the frame buffer number.
 
 By convention, the following device nodes are used (numbers indicate the device
 minor numbers):
 
-    First frame buffer
-	 0 = /dev/fb0current		Current resolution
-	 1 = /dev/fb0autodetect		Default resolution
-	 2 = /dev/fb0predefined0	Predefined resolutions (22)
-	     ...
-	23 = /dev/fb0predefined21
-	24 = /dev/fb0user0		User defined resolutions (8)
-	     ...
-	31 = /dev/fb0user7                              
-
-    Second frame buffer
-	32 = /dev/fb1current		Current resolution
-	33 = /dev/fb1autodetect		Default resolution
-	34 = /dev/fb1predefined0	Predefined resolutions (22)
-	     ...
-	55 = /dev/fb1predefined21
-	56 = /dev/fb1user0		User defined resolutions (8)
-	     ...                                          
-	63 = /dev/fb1user7                                 
+      0 = /dev/fb0	First frame buffer
+     32 = /dev/fb1	Second frame buffer
+	  ...
+    224 = /dev/fb7	8th frame buffer
 
-and so on...
+For backwards compatibility, you may want to create the following symbolic
+links:
+
+    /dev/fb0current -> fb0
+    /dev/fb1current -> fb1
 
-The device with (minor & 31) == 0 (/dev/fb?current) stands for the frame buffer
-together with the currently set video parameters; (minor & 31) == 1
-(/dev/fb?autodetect) is the video mode detected at boot time. Any other minor
-stands for some predefined or user defined video mode.
-
-The predefined entries (/dev/fb?predefined*) usually have a device dependent
-name, e.g. for major 29, minor 5, we have /dev/fb0multiscan on Amiga and
-/dev/fb0ttmid on Atari. These are meant to contain hardware dependent
-resolutions.
-
-The user defined resolutions (/dev/fb?user?) are meant to be filled in by the
-user. This way the user can store his favorite 8 resolutions during boot up.
-
-Note: if you need more than 8 user defined resolutions, you can always override
-the predefined resolutions by storing them in one of the predefined entries.
-But this is not recommended. Similarly, if there are more than 22 predefined
-resolutions, the device writer can decide to store them in the user defined
-entries.
-
-If the device is opened (for writing), the frame buffer driver switches to the
-selected video mode. Thus, you can switch video modes by writing to a frame
-buffer device, e.g.
-
-    > /dev/fb0ttlow
-
-will switch your video to TT low mode. Note: if you specify a resolution which
-contains a value that's not possible on your hardware, the frame buffer device
-will round it up (if possible) or return an error condition.
+and so on...
 
 The frame buffer devices are also `normal' memory devices, this means, you can
 read and write their contents. You can, for example, make a screen snapshot by
 
-  cp /dev/fb0current myfile
+  cp /dev/fb0 myfile
 
 There also can be more than one frame buffer at a time, e.g. if you have a
 graphics card in addition to the built-in hardware. The corresponding frame
-buffer devices (/dev/fb0* and /dev/fb1* etc.) work independently.
+buffer devices (/dev/fb0 and /dev/fb1 etc.) work independently.
 
 Application software that uses the frame buffer device (e.g. the X server) will
-use /dev/fb0current by default. You can specify an alternative resolution by
-setting the environment variable $FRAMEBUFFER to the path name of a frame
-buffer device, e.g. (for sh/bash users):
+use /dev/fb0 by default (older software uses /dev/fb0current). You can specify
+an alternative frame buffer device by setting the environment variable
+$FRAMEBUFFER to the path name of a frame buffer device, e.g. (for sh/bash
+users):
 
-    export FRAMEBUFFER=/dev/fb0multiscan
+    export FRAMEBUFFER=/dev/fb1
 
 or (for csh users):
 
-    setenv FRAMEBUFFER /dev/fb0multiscan
+    setenv FRAMEBUFFER /dev/fb1
 
-After this the X server will use the multiscan video mode.
+After this the X server will use the second frame buffer.
 
 
 2. Programmer's View of /dev/fb*
@@ -152,23 +114,20 @@
 --------------------------------------
 
 Frame buffer resolutions are maintained using the utility `fbset'. It allows to
-change the video mode properties of the current or a user defined resolution.
-It's main usage is to tune video modes and to store custom resolutions into one
-of the /dev/fb?user?  entries, e.g. during boot up in one of your /etc/rc.* or
-/etc/init.d/* files, after which those resolutions can be used by applications.
+change the video mode properties of the current resolution. It's main usage is
+to change the current video mode, e.g. during boot up in one of your /etc/rc.*
+or /etc/init.d/* files.
 
 Fbset uses a video mode database stored in a configuration file, so you can
-easily add your own modes and refer to them with a simple identifier. The fbset
-install script also creates the special device nodes for the device dependent
-predefined resolutions.
+easily add your own modes and refer to them with a simple identifier.
 
 
 4. The X Server
 ---------------
 
 The X server (XF68_FBDev) is the most notable application program for the frame
-buffer device. The current X server is part of the XFree86/XFree68 release 3.2
-package and has 2 modes:
+buffer device. The current X server is part of the XFree86/XFree68 release
+3.3.1 package and has 2 modes:
 
   - If the `Display' subsection for the `fbdev' driver in the /etc/XF86Config
     file contains a
@@ -347,7 +306,7 @@
   - The mighty kernel sources:
       o linux/include/linux/fb.h
       o linux/drivers/char/fbmem.c
-      o linux/arch/m68k/*/*fb.c
+      o linux/drivers/video/*fb.c
 
 
 8. Downloading
diff -u --recursive --new-file v2.1.86/linux/Documentation/m68k/kernel-options.txt linux/Documentation/m68k/kernel-options.txt
--- v2.1.86/linux/Documentation/m68k/kernel-options.txt	Sat Nov 29 10:33:18 1997
+++ linux/Documentation/m68k/kernel-options.txt	Thu Feb 12 16:30:11 1998
@@ -3,8 +3,8 @@
 				  Command Line Options for Linux/m68k
 				  ===================================
 
-Date: Oct 6, 1997
-Linux/m68k version: 2.0.21
+Last Update: Nov 28, 1997
+Linux/m68k version: 2.1.64
 Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek)
 Update: jds@kom.auc.dk (Jes Sorensen)
 
@@ -191,6 +191,7 @@
  - "ser2": SCC channel B serial port ("Modem2"); parameters: 9600bps, 8N1
  - "ser" : default serial port
            This is "ser2" for a Falcon, and "ser1" for any other machine
+ - "midi": The MIDI port; parameters: 31250bps, 8N1
  - "par" : parallel port
            The printing routine for this implements a timeout for the
            case there's no printer connected (else the kernel would
@@ -408,19 +409,7 @@
   Often, extended interval video hardware has to be activated somehow.
 For this, see the "sw_*" options below.
 
-4.1.6) sw_acia, sw_snd6, sw_snd7
---------------------------------
-
-This specifies the method for turning on extended internal video
-hardware, like OverScan. Several methods are in use:
-
-  sw_acia: Set RTS of the keyboard ACIA high
-  sw_snd6: Set bit 6 of the PSG port A
-  sw_snd7: Set bit 7 of the PSG port A
-
-These sub-options are generally only useful together with "internal:".
-
-4.1.7) external:
+4.1.6) external:
 ----------------
 
 Syntax:
@@ -509,13 +498,13 @@
 therefore we don't support hardware-dependend functions like hardware-scroll,
 panning or blanking.
 
-4.1.8) eclock:
+4.1.7) eclock:
 --------------
 
 The external pixel clock attached to the Falcon VIDEL shifter. This
 currently works only with the ScreenWonder!
 
-4.1.9) monitorcap:
+4.1.8) monitorcap:
 -------------------
 
 Syntax: monitorcap:<vmin>;<vmax>;<hmin>;<hmax>
@@ -532,7 +521,7 @@
 
   The defaults for TV/SC1224/SC1435 cover both PAL and NTSC standards.
 
-4.1.10) keep
+4.1.9) keep
 ------------
 
 If this option is given, the framebuffer device doesn't do any video
@@ -650,7 +639,62 @@
     can be performed in optimal order. Not all SCSI devices support
     tagged queuing (:-().
 
+4.6 switches=
+-------------
+
+Syntax: switches=<list of switches>
+
+  With this option you can switch some hardware lines that are often
+used to enable/disable certain hardware extensions. Examples are
+OverScan, overclocking, ...
+
+  The <list of switches> is a comma-separated list of the following
+items:
+
+  ikbd: set RTS of the keyboard ACIA high
+  midi: set RTS of the MIDI ACIA high
+  snd6: set bit 6 of the PSG port A
+  snd7: set bit 6 of the PSG port A
+
+It doesn't make sense to mention a switch more than once (no
+difference to only once), but you can give as many switches as you
+want to enable different features. The switch lines are set as early
+as possible during kernel initialization (even before determining the
+present hardware.)
+
+  All of the items can also be prefixed with "ov_", i.e. "ov_ikbd",
+"ov_midi", ... These options are meant for switching on an OverScan
+video extension. The difference to the bare option is that the
+switch-on is done after video initialization, and somehow synchronized
+to the HBLANK. A speciality is that ov_ikbd and ov_midi are switched
+off before rebooting, so that OverScan is disabled and TOS boots
+correctly.
+
+  If you give an option both, with and without the "ov_" prefix, the
+earlier initialization ("ov_"-less) takes precedence. But the
+switching-off on reset still happens in this case.
+
+4.5) stram_swap=
+----------------
+
+Syntax: stram_swap=<do_swap>[,<max_swap>]
 
+  This option is available only if the kernel has been compiled with
+CONFIG_STRAM_SWAP enabled. Normally, the kernel then determines
+dynamically whether to actually use ST-RAM as swap space. (Currently,
+the fraction of ST-RAM must be less or equal 1/3 of total memory to
+enable this swapping.) You can override the kernel's decision by
+specifying this option. 1 for <do_swap> means always enable the swap,
+even if you have less alternate RAM. 0 stands for never swap to
+ST-RAM, even if it's small enough compared to the rest of memory.
+
+  If ST-RAM swapping is enabled, the kernel usually uses all free
+ST-RAM as swap "device". (If the kernel resides in ST-RAM, the region
+allocated by it is obviously never used for swapping :-) You can also
+limit this amount by specifying the second parameter, <max_swap>, if
+you want to use parts of ST-RAM as normal system memory. <max_swap> is
+in kBytes and the number should be a multiple of 4 (otherwise: rounded
+down).
 
 5) Options for Amiga Only:
 ==========================
diff -u --recursive --new-file v2.1.86/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.86/linux/MAINTAINERS	Wed Feb  4 11:35:59 1998
+++ linux/MAINTAINERS	Sun Feb 15 12:17:04 1998
@@ -348,8 +348,8 @@
 S:	Maintained
 
 MENUCONFIG:
-P:	William Roadcap
-M:	roadcapw@cfw.com
+P:	Michael Elizabeth Chastain
+M:	mec@shout.net
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
@@ -518,8 +518,8 @@
 S:	Maintained
 
 SPARC:
-P:	David S. Miller
-M:	davem@caip.rutgers.edu
+P:	Eddie C. Dost
+M:	ecd@skynet.be
 L:	sparclinux@vger.rutgers.edu
 S:	Maintained
 
diff -u --recursive --new-file v2.1.86/linux/Makefile linux/Makefile
--- v2.1.86/linux/Makefile	Thu Feb 12 20:56:03 1998
+++ linux/Makefile	Thu Feb 12 20:56:41 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 86
+SUBLEVEL = 87
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/Makefile linux/arch/alpha/Makefile
--- v2.1.86/linux/arch/alpha/Makefile	Mon Jan 12 14:51:14 1998
+++ linux/arch/alpha/Makefile	Thu Feb 12 13:31:28 1998
@@ -18,8 +18,12 @@
 SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib \
 	arch/alpha/math-emu
 CORE_FILES := arch/alpha/kernel/kernel.o arch/alpha/mm/mm.o $(CORE_FILES)
-LIBS := $(TOPDIR)/arch/alpha/math-emu/math-emu.a \
-	$(TOPDIR)/arch/alpha/lib/lib.a $(LIBS) $(TOPDIR)/arch/alpha/lib/lib.a
+
+ifeq ($(CONFIG_MATHEMU),y)
+  CORE_FILES := $(CORE_FILES) arch/alpha/math-emu/math-emu.o
+endif
+
+LIBS := arch/alpha/lib/lib.a $(LIBS) arch/alpha/lib/lib.a
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.1.86/linux/arch/alpha/config.in	Thu Feb 12 20:56:03 1998
+++ linux/arch/alpha/config.in	Thu Feb 12 13:31:28 1998
@@ -245,6 +245,12 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Kernel FP software completion' CONFIG_MATHEMU
+else
+  define_bool CONFIG_MATHEMU y
+fi
+
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.86/linux/arch/alpha/defconfig	Fri Jan 30 11:28:05 1998
+++ linux/arch/alpha/defconfig	Thu Feb 12 13:31:28 1998
@@ -30,14 +30,19 @@
 # CONFIG_ALPHA_JENSEN is not set
 # CONFIG_ALPHA_NONAME is not set
 # CONFIG_ALPHA_MIKASA is not set
+# CONFIG_ALPHA_NORITAKE is not set
 CONFIG_ALPHA_ALCOR=y
+# CONFIG_ALPHA_MIATA is not set
+# CONFIG_ALPHA_SABLE is not set
+# CONFIG_ALPHA_BOOK1 is not set
 # CONFIG_ALPHA_P2K is not set
 CONFIG_PCI=y
-CONFIG_PCI_OLD_PROC=y
 CONFIG_ALPHA_EV5=y
 CONFIG_ALPHA_CIA=y
 CONFIG_ALPHA_SRM=y
+CONFIG_ALPHA_EISA=y
 CONFIG_TGA_CONSOLE=y
+CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
@@ -70,28 +75,35 @@
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_EZ is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
 # Networking options
 #
+# CONFIG_PACKET is not set
 # CONFIG_NETLINK is not set
 # CONFIG_FIREWALL is not set
 # CONFIG_NET_ALIAS is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
 # CONFIG_IP_ACCT is not set
+# CONFIG_IP_MASQUERADE is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
 
 #
 # (it is safe to leave these untouched)
 #
-# CONFIG_INET_PCTCP is not set
 # CONFIG_INET_RARP is not set
-CONFIG_PATH_MTU_DISCOVERY=y
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 
@@ -100,7 +112,6 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
-# CONFIG_AX25 is not set
 
 #
 # SCSI support
@@ -121,6 +132,7 @@
 #
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
 
 #
 # SCSI low-level drivers
@@ -139,11 +151,15 @@
 # CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
 # CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 CONFIG_SCSI_QLOGIC_ISP=y
 # CONFIG_SCSI_SEAGATE is not set
@@ -177,13 +193,19 @@
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
 # CONFIG_PPP is not set
-# CONFIG_NET_RADIO is not set
 # CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
+# CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
 
 #
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -192,6 +214,7 @@
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
 #
 # CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CDROM=y
 
 #
 # Filesystems
@@ -199,25 +222,29 @@
 # CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-# CONFIG_ROOT_NFS is not set
 # CONFIG_NFSD is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
-CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
+# CONFIG_NTFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_MAC_PARTITION is not set
+# CONFIG_NLS is not set
 
 #
 # Character devices
@@ -225,6 +252,7 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_MOUSE=y
@@ -236,12 +264,18 @@
 # CONFIG_PC110_PAD is not set
 # CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_VIDEO_DEV is not set
 # CONFIG_NVRAM is not set
 # CONFIG_JOYSTICK is not set
+# CONFIG_MISC_RADIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
 
 #
 # Sound
@@ -252,4 +286,5 @@
 # Kernel hacking
 #
 # CONFIG_PROFILE is not set
+CONFIG_MATHEMU=y
 # CONFIG_MAGIC_SYSRQ is not set
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v2.1.86/linux/arch/alpha/kernel/Makefile	Mon Jan 12 14:51:14 1998
+++ linux/arch/alpha/kernel/Makefile	Thu Feb 12 13:31:28 1998
@@ -16,7 +16,7 @@
 
 O_TARGET := kernel.o
 O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
-	    bios32.o ptrace.o time.o
+	    bios32.o ptrace.o time.o fpreg.o
 OX_OBJS  := alpha_ksyms.o
 
 
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.1.86/linux/arch/alpha/kernel/alpha_ksyms.c	Thu Feb 12 20:56:04 1998
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Thu Feb 12 13:31:28 1998
@@ -21,6 +21,7 @@
 #include <asm/checksum.h>
 #include <linux/interrupt.h>
 #include <asm/softirq.h>
+#include <asm/fpu.h>
 
 #define __KERNEL_SYSCALLS__
 #include <asm/unistd.h>
@@ -88,6 +89,8 @@
 EXPORT_SYMBOL(hwrpb);
 EXPORT_SYMBOL(wrusp);
 EXPORT_SYMBOL(start_thread);
+EXPORT_SYMBOL(alpha_read_fp_reg);
+EXPORT_SYMBOL(alpha_write_fp_reg);
 
 /* In-kernel system calls.  */
 EXPORT_SYMBOL(__kernel_thread);
@@ -109,6 +112,11 @@
 EXPORT_SYMBOL(csum_partial_copy);
 EXPORT_SYMBOL(csum_partial_copy_from_user);
 EXPORT_SYMBOL(csum_ipv6_magic);
+
+#ifdef CONFIG_MATHEMU_MODULE
+extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
+EXPORT_SYMBOL(alpha_fp_emul_imprecise);
+#endif
 
 /*
  * The following are specially called from the uaccess assembly stubs.
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.1.86/linux/arch/alpha/kernel/entry.S	Thu Feb 12 20:56:04 1998
+++ linux/arch/alpha/kernel/entry.S	Thu Feb 12 16:44:15 1998
@@ -1046,7 +1046,7 @@
 	.quad sys_bdflush			/* 300 */
 	.quad sys_sethae
 	.quad sys_mount
-	.quad sys_adjtimex
+	.quad sys_old_adjtimex
 	.quad sys_swapoff
 	.quad sys_getdents			/* 305 */
 	.quad alpha_create_module
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/fpreg.c linux/arch/alpha/kernel/fpreg.c
--- v2.1.86/linux/arch/alpha/kernel/fpreg.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/alpha/kernel/fpreg.c	Thu Feb 12 13:31:28 1998
@@ -0,0 +1,104 @@
+/*
+ * kernel/fpreg.c
+ *
+ * (C) Copyright 1998 Linus Torvalds
+ */
+
+unsigned long
+alpha_read_fp_reg (unsigned long reg)
+{
+	unsigned long r;
+
+	switch (reg) {
+	      case  0: asm ("stt  $f0,%0" : "m="(r)); break;
+	      case  1: asm ("stt  $f1,%0" : "m="(r)); break;
+	      case  2: asm ("stt  $f2,%0" : "m="(r)); break;
+	      case  3: asm ("stt  $f3,%0" : "m="(r)); break;
+	      case  4: asm ("stt  $f4,%0" : "m="(r)); break;
+	      case  5: asm ("stt  $f5,%0" : "m="(r)); break;
+	      case  6: asm ("stt  $f6,%0" : "m="(r)); break;
+	      case  7: asm ("stt  $f7,%0" : "m="(r)); break;
+	      case  8: asm ("stt  $f8,%0" : "m="(r)); break;
+	      case  9: asm ("stt  $f9,%0" : "m="(r)); break;
+	      case 10: asm ("stt $f10,%0" : "m="(r)); break;
+	      case 11: asm ("stt $f11,%0" : "m="(r)); break;
+	      case 12: asm ("stt $f12,%0" : "m="(r)); break;
+	      case 13: asm ("stt $f13,%0" : "m="(r)); break;
+	      case 14: asm ("stt $f14,%0" : "m="(r)); break;
+	      case 15: asm ("stt $f15,%0" : "m="(r)); break;
+	      case 16: asm ("stt $f16,%0" : "m="(r)); break;
+	      case 17: asm ("stt $f17,%0" : "m="(r)); break;
+	      case 18: asm ("stt $f18,%0" : "m="(r)); break;
+	      case 19: asm ("stt $f19,%0" : "m="(r)); break;
+	      case 20: asm ("stt $f20,%0" : "m="(r)); break;
+	      case 21: asm ("stt $f21,%0" : "m="(r)); break;
+	      case 22: asm ("stt $f22,%0" : "m="(r)); break;
+	      case 23: asm ("stt $f23,%0" : "m="(r)); break;
+	      case 24: asm ("stt $f24,%0" : "m="(r)); break;
+	      case 25: asm ("stt $f25,%0" : "m="(r)); break;
+	      case 26: asm ("stt $f26,%0" : "m="(r)); break;
+	      case 27: asm ("stt $f27,%0" : "m="(r)); break;
+	      case 28: asm ("stt $f28,%0" : "m="(r)); break;
+	      case 29: asm ("stt $f29,%0" : "m="(r)); break;
+	      case 30: asm ("stt $f30,%0" : "m="(r)); break;
+	      case 31: asm ("stt $f31,%0" : "m="(r)); break;
+	      default:
+		break;
+	}
+	return r;
+}
+
+#if 1
+/*
+ * This is IMHO the better way of implementing LDT().  But it
+ * has the disadvantage that gcc 2.7.0 refuses to compile it
+ * (invalid operand constraints), so instead, we use the uglier
+ * macro below.
+ */
+# define LDT(reg,val)	\
+  asm volatile ("ldt $f"#reg",%0" : : "m"(val));
+#else
+# define LDT(reg,val)	\
+  asm volatile ("ldt $f"#reg",0(%0)" : : "r"(&val));
+#endif
+
+void
+alpha_write_fp_reg (unsigned long reg, unsigned long val)
+{
+	switch (reg) {
+	      case  0: LDT( 0, val); break;
+	      case  1: LDT( 1, val); break;
+	      case  2: LDT( 2, val); break;
+	      case  3: LDT( 3, val); break;
+	      case  4: LDT( 4, val); break;
+	      case  5: LDT( 5, val); break;
+	      case  6: LDT( 6, val); break;
+	      case  7: LDT( 7, val); break;
+	      case  8: LDT( 8, val); break;
+	      case  9: LDT( 9, val); break;
+	      case 10: LDT(10, val); break;
+	      case 11: LDT(11, val); break;
+	      case 12: LDT(12, val); break;
+	      case 13: LDT(13, val); break;
+	      case 14: LDT(14, val); break;
+	      case 15: LDT(15, val); break;
+	      case 16: LDT(16, val); break;
+	      case 17: LDT(17, val); break;
+	      case 18: LDT(18, val); break;
+	      case 19: LDT(19, val); break;
+	      case 20: LDT(20, val); break;
+	      case 21: LDT(21, val); break;
+	      case 22: LDT(22, val); break;
+	      case 23: LDT(23, val); break;
+	      case 24: LDT(24, val); break;
+	      case 25: LDT(25, val); break;
+	      case 26: LDT(26, val); break;
+	      case 27: LDT(27, val); break;
+	      case 28: LDT(28, val); break;
+	      case 29: LDT(29, val); break;
+	      case 30: LDT(30, val); break;
+	      case 31: LDT(31, val); break;
+	      default:
+		break;
+	}
+}
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.1.86/linux/arch/alpha/kernel/head.S	Mon Jan 12 14:51:14 1998
+++ linux/arch/alpha/kernel/head.S	Thu Feb 12 13:31:28 1998
@@ -121,37 +121,3 @@
 	call_pal PAL_cserve
 	ret	($26)
 	.end	cserve_dis
-
-	#
-	# The following two functions don't need trapb/excb instructions
-	# around the mf_fpcr/mt_fpcr instructions because (a) the kernel
-	# never generates arithmetic faults and (b) call_pal instructions
-	# are implied trap barriers.
-	#
-	.align 3
-	.globl	rdfpcr
-	.ent	rdfpcr
-rdfpcr:
-	lda	$30,-0x10($30)
-	stt	$f0,0($30)
-	mf_fpcr	$f0
-	stt	$f0,8($30)
-	ldt	$f0,0($30)
-	ldq	$0,8($30)
-	lda	$30,0x10($30)
-	ret	($26)
-	.end	rdfpcr
-
-	.align 3
-	.globl	wrfpcr
-	.ent	wrfpcr
-wrfpcr:
-	lda	$30,-0x10($30)
-	stt	$f0,0($30)
-	stq	$16,8($30)
-	ldt	$f0,8($30)
-	mt_fpcr	$f0
-	ldt	$f0,0($30)
-	lda	$30,0x10($30)
-	ret	($26)
-	.end	wrfpcr
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.1.86/linux/arch/alpha/kernel/osf_sys.c	Fri Jan 30 11:28:05 1998
+++ linux/arch/alpha/kernel/osf_sys.c	Thu Feb 12 16:44:15 1998
@@ -24,6 +24,7 @@
 #include <linux/a.out.h>
 #include <linux/utsname.h>
 #include <linux/time.h>
+#include <linux/timex.h>
 #include <linux/major.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
@@ -925,6 +926,7 @@
 extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
 asmlinkage int sys_utimes(char *, struct timeval *);
 extern int sys_wait4(pid_t, int *, int, struct rusage *);
+extern int do_adjtimex(struct timex *);
 
 struct timeval32
 {
@@ -1269,4 +1271,58 @@
 	return 0;
 fault:
 	return -EFAULT;
+}
+
+
+struct timex32 {
+	unsigned int modes;	/* mode selector */
+	long offset;		/* time offset (usec) */
+	long freq;		/* frequency offset (scaled ppm) */
+	long maxerror;		/* maximum error (usec) */
+	long esterror;		/* estimated error (usec) */
+	int status;		/* clock command/status */
+	long constant;		/* pll time constant */
+	long precision;		/* clock precision (usec) (read only) */
+	long tolerance;		/* clock frequency tolerance (ppm)
+				 * (read only)
+				 */
+	struct timeval32 time;	/* (read only) */
+	long tick;		/* (modified) usecs between clock ticks */
+
+	long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
+	long jitter;            /* pps jitter (us) (ro) */
+	int shift;              /* interval duration (s) (shift) (ro) */
+	long stabil;            /* pps stability (scaled ppm) (ro) */
+	long jitcnt;            /* jitter limit exceeded (ro) */
+	long calcnt;            /* calibration intervals (ro) */
+	long errcnt;            /* calibration errors (ro) */
+	long stbcnt;            /* stability limit exceeded (ro) */
+
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+	int  :32; int  :32; int  :32; int  :32;
+};
+
+asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
+{
+        struct timex txc;
+	int ret;
+
+	/* copy relevant bits of struct timex. */
+	if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) ||
+	    copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - 
+			   offsetof(struct timex32, time)))
+	  return -EFAULT;
+	
+	if ((ret = do_adjtimex(&txc)))
+	  return ret;
+	
+	/* copy back to timex32 */
+	if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) ||
+	    (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) - 
+			  offsetof(struct timex32, tick))) ||
+	    (put_tv32(&txc_p->time, &txc.time)))
+	  return -EFAULT;
+
+	return 0;
 }
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.1.86/linux/arch/alpha/kernel/traps.c	Thu Feb 12 20:56:04 1998
+++ linux/arch/alpha/kernel/traps.c	Thu Feb 12 13:31:28 1998
@@ -105,14 +105,24 @@
 	do_exit(SIGSEGV);
 }
 
+#ifndef CONFIG_MATHEMU
+static long dummy_alpha_fp_emul_imprecise(struct pt_regs *r, unsigned long wm)
+{
+  return 0;
+}
+
+long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask)
+  = dummy_alpha_fp_emul_imprecise;
+#else
+long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask);
+#endif
+
 asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
 			    unsigned long a2, unsigned long a3,
 			    unsigned long a4, unsigned long a5,
 			    struct pt_regs regs)
 {
 	if ((summary & 1)) {
-		extern long alpha_fp_emul_imprecise (struct pt_regs * regs,
-						     unsigned long write_mask);
 		/*
 		 * Software-completion summary bit is set, so try to
 		 * emulate the instruction.
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/math-emu/Makefile linux/arch/alpha/math-emu/Makefile
--- v2.1.86/linux/arch/alpha/math-emu/Makefile	Thu Dec 21 22:22:05 1995
+++ linux/arch/alpha/math-emu/Makefile	Thu Feb 12 13:31:28 1998
@@ -2,11 +2,11 @@
 # Makefile for math-emulator files...
 #
 
-OBJS  = fp-emul.o ieee-math.o
+O_TARGET := math-emu.o
+O_OBJS   := fp-emul.o ieee-math.o
 
-math-emu.a: $(OBJS)
-	$(AR) rcs $@ $(OBJS)
-
-dep:
+ifeq ($(CONFIG_MATHEMU),m)
+M_OBJS   := $(O_TARGET)
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c
--- v2.1.86/linux/arch/alpha/math-emu/fp-emul.c	Mon Jun 16 16:35:53 1997
+++ linux/arch/alpha/math-emu/fp-emul.c	Thu Feb 12 13:31:28 1998
@@ -1,5 +1,5 @@
+#include <linux/module.h>
 #include <linux/types.h>
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
@@ -52,111 +52,33 @@
 #define MISC_TRAPB	0x0000
 #define MISC_EXCB	0x0400
 
-
-extern unsigned long	rdfpcr (void);
-extern void		wrfpcr (unsigned long);
+extern unsigned long alpha_read_fp_reg (unsigned long reg);
+extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
 
 
-unsigned long
-alpha_read_fp_reg (unsigned long reg)
-{
-	unsigned long r;
+#ifdef MODULE
 
-	switch (reg) {
-	      case  0: asm ("stt  $f0,%0" : "m="(r)); break;
-	      case  1: asm ("stt  $f1,%0" : "m="(r)); break;
-	      case  2: asm ("stt  $f2,%0" : "m="(r)); break;
-	      case  3: asm ("stt  $f3,%0" : "m="(r)); break;
-	      case  4: asm ("stt  $f4,%0" : "m="(r)); break;
-	      case  5: asm ("stt  $f5,%0" : "m="(r)); break;
-	      case  6: asm ("stt  $f6,%0" : "m="(r)); break;
-	      case  7: asm ("stt  $f7,%0" : "m="(r)); break;
-	      case  8: asm ("stt  $f8,%0" : "m="(r)); break;
-	      case  9: asm ("stt  $f9,%0" : "m="(r)); break;
-	      case 10: asm ("stt $f10,%0" : "m="(r)); break;
-	      case 11: asm ("stt $f11,%0" : "m="(r)); break;
-	      case 12: asm ("stt $f12,%0" : "m="(r)); break;
-	      case 13: asm ("stt $f13,%0" : "m="(r)); break;
-	      case 14: asm ("stt $f14,%0" : "m="(r)); break;
-	      case 15: asm ("stt $f15,%0" : "m="(r)); break;
-	      case 16: asm ("stt $f16,%0" : "m="(r)); break;
-	      case 17: asm ("stt $f17,%0" : "m="(r)); break;
-	      case 18: asm ("stt $f18,%0" : "m="(r)); break;
-	      case 19: asm ("stt $f19,%0" : "m="(r)); break;
-	      case 20: asm ("stt $f20,%0" : "m="(r)); break;
-	      case 21: asm ("stt $f21,%0" : "m="(r)); break;
-	      case 22: asm ("stt $f22,%0" : "m="(r)); break;
-	      case 23: asm ("stt $f23,%0" : "m="(r)); break;
-	      case 24: asm ("stt $f24,%0" : "m="(r)); break;
-	      case 25: asm ("stt $f25,%0" : "m="(r)); break;
-	      case 26: asm ("stt $f26,%0" : "m="(r)); break;
-	      case 27: asm ("stt $f27,%0" : "m="(r)); break;
-	      case 28: asm ("stt $f28,%0" : "m="(r)); break;
-	      case 29: asm ("stt $f29,%0" : "m="(r)); break;
-	      case 30: asm ("stt $f30,%0" : "m="(r)); break;
-	      case 31: asm ("stt $f31,%0" : "m="(r)); break;
-	      default:
-		break;
-	}
-	return r;
-}
+MODULE_DESCRIPTION("FP Software completion module");
 
+extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long);
+static long (*save_emul)(struct pt_regs *, unsigned long);
+long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long);
 
-#if 0
-/*
- * This is IMHO the better way of implementing LDT().  But it
- * has the disadvantage that gcc 2.7.0 refuses to compile it
- * (invalid operand constraints), so instead, we use the uglier
- * macro below.
- */
-# define LDT(reg,val)	\
-  asm volatile ("ldt $f"#reg",%0" :: "m"(val));
-#else
-# define LDT(reg,val)	\
-  asm volatile ("ldt $f"#reg",0(%0)" :: "r"(&val));
-#endif
+int init_module(void)
+{
+	save_emul = alpha_fp_emul_imprecise;
+	alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise;
+	return 0;
+}
 
-void
-alpha_write_fp_reg (unsigned long reg, unsigned long val)
+void cleanup_module(void)
 {
-	switch (reg) {
-	      case  0: LDT( 0, val); break;
-	      case  1: LDT( 1, val); break;
-	      case  2: LDT( 2, val); break;
-	      case  3: LDT( 3, val); break;
-	      case  4: LDT( 4, val); break;
-	      case  5: LDT( 5, val); break;
-	      case  6: LDT( 6, val); break;
-	      case  7: LDT( 7, val); break;
-	      case  8: LDT( 8, val); break;
-	      case  9: LDT( 9, val); break;
-	      case 10: LDT(10, val); break;
-	      case 11: LDT(11, val); break;
-	      case 12: LDT(12, val); break;
-	      case 13: LDT(13, val); break;
-	      case 14: LDT(14, val); break;
-	      case 15: LDT(15, val); break;
-	      case 16: LDT(16, val); break;
-	      case 17: LDT(17, val); break;
-	      case 18: LDT(18, val); break;
-	      case 19: LDT(19, val); break;
-	      case 20: LDT(20, val); break;
-	      case 21: LDT(21, val); break;
-	      case 22: LDT(22, val); break;
-	      case 23: LDT(23, val); break;
-	      case 24: LDT(24, val); break;
-	      case 25: LDT(25, val); break;
-	      case 26: LDT(26, val); break;
-	      case 27: LDT(27, val); break;
-	      case 28: LDT(28, val); break;
-	      case 29: LDT(29, val); break;
-	      case 30: LDT(30, val); break;
-	      case 31: LDT(31, val); break;
-	      default:
-		break;
-	}
+	alpha_fp_emul_imprecise = save_emul;
 }
 
+#define alpha_fp_emul_imprecise  do_alpha_fp_emul_imprecise
+
+#endif /* MODULE */
 
 /*
  * Emulate the floating point instruction at address PC.  Returns 0 if
@@ -334,6 +256,8 @@
 	unsigned long trigger_pc = regs->pc - 4;
 	unsigned long insn, opcode, rc;
 
+	MOD_INC_USE_COUNT;
+
 	/*
 	 * Turn off the bits corresponding to registers that are the
 	 * target of instructions that set bits in the exception
@@ -354,12 +278,14 @@
 		      case OPC_PAL:
 		      case OPC_JSR:
 		      case 0x30 ... 0x3f:	/* branches */
+			MOD_DEC_USE_COUNT;
 			return 0;
 
 		      case OPC_MISC:
 			switch (insn & 0xffff) {
 			      case MISC_TRAPB:
 			      case MISC_EXCB:
+				MOD_DEC_USE_COUNT;
 				return 0;
 
 			      default:
@@ -386,11 +312,13 @@
 			{
 			    /* re-execute insns in trap-shadow: */
 			    regs->pc = trigger_pc + 4;
+			    MOD_DEC_USE_COUNT;
 			    return 1;
 			}
 			break;
 		}
 		trigger_pc -= 4;
 	}
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
diff -u --recursive --new-file v2.1.86/linux/arch/alpha/math-emu/ieee-math.c linux/arch/alpha/math-emu/ieee-math.c
--- v2.1.86/linux/arch/alpha/math-emu/ieee-math.c	Thu Apr 11 23:49:30 1996
+++ linux/arch/alpha/math-emu/ieee-math.c	Thu Feb 12 13:31:28 1998
@@ -137,9 +137,8 @@
 static inline void
 mul64 (const unsigned long a, const unsigned long b, unsigned long c[2])
 {
-	asm ("mulq  %2,%3,%0\n\t"
-	     "umulh %2,%3,%1"
-	     : "r="(c[0]), "r="(c[1]) : "r"(a), "r"(b));
+	c[0] = a * b;
+	asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b));
 }
 
 
@@ -276,7 +275,7 @@
 {
 	unsigned long res, sticky;
 
-	if (!a->f[0] && !a->f[1]) {
+	if (!a->e && !a->f[0] && !a->f[1]) {
 		*b = (unsigned long) a->s << 63;	/* return +/-0 */
 		return 0;
 	}
@@ -356,7 +355,7 @@
 {
 	unsigned long res, sticky;
 
-	if (!a->f[0] && !a->f[1]) {
+	if (!a->e && !a->f[0] && !a->f[1]) {
 		*b = (unsigned long) a->s << 63;	/* return +/-0 */
 		return 0;
 	}
@@ -384,7 +383,7 @@
 			a->e = -0x3ff;
 		}
 	}
-	if (a->e > 0x3ff) {
+	if (a->e >= 0x3ff) {
 		res = FPCR_OVF | FPCR_INE;
 		if (f & IEEE_TRAP_ENABLE_OVF) {
 			a->e -= 0x600;	/* scale down result by 2^alpha */
@@ -1143,12 +1142,9 @@
 		return 0;
 	}
 	op_c.s = op_a.s ^ op_b.s;
-	op_c.e = op_a.e + op_b.e;
+	op_c.e = op_a.e + op_b.e - 55;
 	mul64(op_a.f[0], op_b.f[0], op_c.f);
 
-	normalize(&op_c);
-	op_c.e -= 55;		/* drop the 55 original bits. */
-
 	return round_s_ieee(f, &op_c, c);
 }
 
@@ -1200,11 +1196,8 @@
 		return 0;
 	}
 	op_c.s = op_a.s ^ op_b.s;
-	op_c.e = op_a.e + op_b.e;
+	op_c.e = op_a.e + op_b.e - 55;
 	mul64(op_a.f[0], op_b.f[0], op_c.f);
-
-	normalize(&op_c);
-	op_c.e -= 55;	/* drop the 55 original bits. */
 
 	return round_t_ieee(f, &op_c, c);
 }
diff -u --recursive --new-file v2.1.86/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.1.86/linux/arch/i386/kernel/head.S	Thu Feb 12 20:56:04 1998
+++ linux/arch/i386/kernel/head.S	Sun Feb 15 12:11:23 1998
@@ -637,3 +637,12 @@
 	.quad 0x00809a0000000000	/* 0x50 APM CS 16 code (16 bit) */
 	.quad 0x00c0920000000000	/* 0x58 APM DS    data */
 	.fill 2*NR_TASKS,8,0		/* space for LDT's and TSS's etc */
+
+/*
+ * This is to aid debugging, the various locking macros will be putting
+ * code fragments here.  When an oops occurs we'd rather know that it's
+ * inside the .text.lock section rather than as some offset from whatever
+ * function happens to be last in the .text segment.
+ */
+.section .text.lock
+ENTRY(stext_lock)
diff -u --recursive --new-file v2.1.86/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.86/linux/arch/i386/kernel/irq.c	Thu Feb 12 20:56:04 1998
+++ linux/arch/i386/kernel/irq.c	Mon Feb 16 15:02:01 1998
@@ -570,22 +570,31 @@
 
 unsigned long __global_save_flags(void)
 {
-	return global_irq_holder == (unsigned char) smp_processor_id();
+	if (!local_irq_count[smp_processor_id()])
+		return global_irq_holder == (unsigned char) smp_processor_id();
+	else {
+		unsigned long x;
+		__save_flags(x);
+		return x;
+	}
 }
 
 void __global_restore_flags(unsigned long flags)
 {
-	switch (flags) {
-	case 0:
-		__global_sti();
-		break;
-	case 1:
-		__global_cli();
-		break;
-	default:
-		printk("global_restore_flags: %08lx (%08lx)\n",
-			flags, (&flags)[-1]);
-	}
+	if (!local_irq_count[smp_processor_id()]) {
+		switch (flags) {
+		case 0:
+			__global_sti();
+			break;
+		case 1:
+			__global_cli();
+			break;
+		default:
+			printk("global_restore_flags: %08lx (%08lx)\n",
+				flags, (&flags)[-1]);
+		}
+	} else
+		__restore_flags(flags);
 }
 
 #endif
@@ -707,10 +716,8 @@
 
 		irq_exit(cpu, irq);
 		__restore_flags(flags);
-	} else {
-		enable_IO_APIC_irq(irq);
+	} else
 		spin_unlock_irqrestore(&irq_controller_lock, flags);
-	}
 }
 #endif
 
diff -u --recursive --new-file v2.1.86/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.86/linux/arch/i386/kernel/smp.c	Thu Feb 12 20:56:04 1998
+++ linux/arch/i386/kernel/smp.c	Mon Feb 16 15:00:48 1998
@@ -1420,7 +1420,9 @@
 	 * want to be able to accept NMI tlb invalidates
 	 * during this time.
 	 */
+	spin_lock(&irq_controller_lock);
 	ack_APIC_irq ();
+	spin_unlock(&irq_controller_lock);
 
 	smp_local_timer_interrupt(regs);
 }
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v2.1.86/linux/arch/m68k/Makefile	Thu Jul 31 13:09:16 1997
+++ linux/arch/m68k/Makefile	Thu Feb 12 16:30:11 1998
@@ -26,6 +26,7 @@
 
 LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
 
+# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
 CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
 
 ifdef CONFIG_OPTIMIZE_040
@@ -33,7 +34,7 @@
 endif
 
 ifdef CONFIG_OPTIMIZE_060
-CFLAGS := $(CFLAGS) -m68020-40
+CFLAGS := $(CFLAGS) -m68060
 endif
 
 ifdef CONFIG_KGDB
@@ -63,10 +64,14 @@
 SUBDIRS := $(SUBDIRS) arch/m68k/mac
 endif
 
-ifdef CONFIG_VT
-# add in console.a after {amiga,atari}.o that need it
-CORE_FILES := $(CORE_FILES) arch/m68k/console/console.a
-SUBDIRS := $(SUBDIRS) arch/m68k/console
+ifdef CONFIG_APOLLO
+CORE_FILES := $(CORE_FILES) arch/m68k/apollo/apollo.o
+SUBDIRS := $(SUBDIRS) arch/m68k/apollo
+endif
+
+ifdef CONFIG_MVME16x
+CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o
+SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x
 endif
 
 ifdef CONFIG_M68040
@@ -98,9 +103,6 @@
 else
 	gzip -9c vmlinux >vmlinux.gz
 endif
-
-bootstrap: dummy
-	@$(MAKEBOOT) bootstrap
 
 archclean:
 	rm -f vmlinux.gz
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile
--- v2.1.86/linux/arch/m68k/amiga/Makefile	Wed Apr 23 19:01:14 1997
+++ linux/arch/m68k/amiga/Makefile	Thu Feb 12 16:30:12 1998
@@ -8,16 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := amiga.o
-O_OBJS   := config.o amikeyb.o amiints.o cia.o \
-            chipram.o amisound.o amifb.o zorro.o
+O_OBJS   := config.o amiints.o cia.o chipram.o amisound.o zorro.o
 OX_OBJS  := amiga_ksyms.o
-
-ifdef CONFIG_FB_CYBER
-O_OBJS := $(O_OBJS) cyberfb.o
-endif
-
-ifdef CONFIG_FB_RETINAZ3
-O_OBJS := $(O_OBJS) retz3fb.o
-endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c
--- v2.1.86/linux/arch/m68k/amiga/amiints.c	Tue May 13 22:41:01 1997
+++ linux/arch/m68k/amiga/amiints.c	Thu Feb 12 16:30:12 1998
@@ -331,7 +331,7 @@
 
 inline void amiga_do_irq(int irq, struct pt_regs *fp)
 {
-	kstat.interrupts[SYS_IRQS + irq]++;
+	kstat.irqs[0][SYS_IRQS + irq]++;
 	ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp);
 }
 
@@ -340,7 +340,7 @@
 	irq_node_t *node, *slow_nodes;
 	unsigned short flags;
 
-	kstat.interrupts[SYS_IRQS + irq]++;
+	kstat.irqs[0][SYS_IRQS + irq]++;
 	if (server->count++)
 		server->reentrance = 1;
 	/* serve first fast and normal handlers */
@@ -489,7 +489,7 @@
 		if (node->flags & IRQ_FLG_STD)
 			continue;
 		len += sprintf(buf+len, "ami  %2d: %10u ", i,
-		               kstat.interrupts[SYS_IRQS + i]);
+		               kstat.irqs[0][SYS_IRQS + i]);
 		do {
 			if (ami_servers[i]) {
 				if (node->flags & IRQ_FLG_FAST)
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/cia.c linux/arch/m68k/amiga/cia.c
--- v2.1.86/linux/arch/m68k/amiga/cia.c	Tue May 13 22:41:01 1997
+++ linux/arch/m68k/amiga/cia.c	Thu Feb 12 16:30:12 1998
@@ -145,7 +145,7 @@
 	custom.intreq = base->int_mask;
 	for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
 		if (ints & 1) {
-			kstat.interrupts[irq]++;
+			kstat.irqs[0][irq]++;
 			base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
 		}
 		ints >>= 1;
@@ -181,7 +181,7 @@
 	for (i = 0; i < CIA_IRQS; i++) {
 		if (!(base->irq_list[i].flags & IRQ_FLG_STD)) {
 			len += sprintf(buf+len, "cia  %2d: %10d ", j + i,
-			               kstat.interrupts[SYS_IRQS + j + i]);
+			               kstat.irqs[0][SYS_IRQS + j + i]);
 			if (base->irq_list[i].flags & IRQ_FLG_LOCK)
 				len += sprintf(buf+len, "L ");
 			else
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v2.1.86/linux/arch/m68k/amiga/config.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/amiga/config.c	Thu Feb 12 16:30:12 1998
@@ -31,13 +31,13 @@
 #include <asm/machdep.h>
 #include <linux/zorro.h>
 
-u_long amiga_model;
-u_long amiga_eclock;
-u_long amiga_masterclock;
-u_long amiga_colorclock;
-u_long amiga_chipset;
-u_char amiga_vblank;
-u_char amiga_psfreq;
+unsigned long amiga_model;
+unsigned long amiga_eclock;
+unsigned long amiga_masterclock;
+unsigned long amiga_colorclock;
+unsigned long amiga_chipset;
+unsigned char amiga_vblank;
+unsigned char amiga_psfreq;
 struct amiga_hw_present amiga_hw_present;
 
 static const char *amiga_models[] = {
@@ -54,8 +54,10 @@
 /* amiga specific irq functions */
 extern void amiga_init_IRQ (void);
 extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
-extern int amiga_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-                              unsigned long flags, const char *devname, void *dev_id);
+extern int amiga_request_irq (unsigned int irq,
+			      void (*handler)(int, void *, struct pt_regs *),
+                              unsigned long flags, const char *devname,
+			      void *dev_id);
 extern void amiga_free_irq (unsigned int irq, void *dev_id);
 extern void amiga_enable_irq (unsigned int);
 extern void amiga_disable_irq (unsigned int);
@@ -69,28 +71,50 @@
 static int amiga_hwclk (int, struct hwclk_time *);
 static int amiga_set_clock_mmss (unsigned long);
 extern void amiga_mksound( unsigned int count, unsigned int ticks );
-#ifdef CONFIG_BLK_DEV_FD
-extern int amiga_floppy_init (void);
+#ifdef CONFIG_AMIGA_FLOPPY
 extern void amiga_floppy_setup(char *, int *);
 #endif
 static void amiga_reset (void);
-static void amiga_wait_key(void);
+static int amiga_wait_key (struct console *co);
 extern struct consw fb_con;
-extern struct fb_info *amiga_fb_init(long *);
 extern void zorro_init(void);
 extern void amiga_init_sound(void);
 static void amiga_savekmsg_init(void);
-static void amiga_mem_console_write(const char *b, unsigned int count);
-static void amiga_serial_console_write(const char *s, unsigned int count);
+static void amiga_mem_console_write(struct console *co, const char *b,
+				    unsigned int count);
+void amiga_serial_console_write(struct console *co, const char *s,
+				unsigned int count);
 static void amiga_debug_init(void);
-
-extern void amiga_video_setup(char *, int *);
-extern void amiga_init_sound(void);
+#ifdef CONFIG_HEARTBEAT
+static void amiga_heartbeat(int on);
+#endif
 
 static struct console amiga_console_driver = {
-    NULL, NULL, amiga_wait_key
+	"debug",
+	NULL,			/* write */
+	NULL,			/* read */
+	NULL,			/* device */
+	amiga_wait_key,		/* wait_key */
+	NULL,			/* unblank */
+	NULL,			/* setup */
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
 };
 
+#ifdef CONFIG_MAGIC_SYSRQ
+static char amiga_sysrq_xlate[128] =
+	"\0001234567890-=\\\000\000"					/* 0x00 - 0x0f */
+	"qwertyuiop[]\000123"							/* 0x10 - 0x1f */
+	"asdfghjkl;'\000\000456"						/* 0x20 - 0x2f */
+	"\000zxcvbnm,./\000+789"						/* 0x30 - 0x3f */
+	" \177\t\r\r\000\177\000\000\000-\000\000\000\000\000"	/* 0x40 - 0x4f */
+	"\000\201\202\203\204\205\206\207\210\211()/*+\000"	/* 0x50 - 0x5f */
+	"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"	/* 0x60 - 0x6f */
+	"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 0x70 - 0x7f */
+#endif
+
 extern void (*kd_mksound)(unsigned int, unsigned int);
 
     /*
@@ -100,7 +124,7 @@
 int amiga_parse_bootinfo(const struct bi_record *record)
 {
     int unknown = 0;
-    const u_long *data = record->data;
+    const unsigned long *data = record->data;
 
     switch (record->tag) {
 	case BI_AMIGA_MODEL:
@@ -120,11 +144,11 @@
 	    break;
 
 	case BI_AMIGA_VBLANK:
-	    amiga_vblank = *(const u_char *)data;
+	    amiga_vblank = *(const unsigned char *)data;
 	    break;
 
 	case BI_AMIGA_PSFREQ:
-	    amiga_psfreq = *(const u_char *)data;
+	    amiga_psfreq = *(const unsigned char *)data;
 	    break;
 
 	case BI_AMIGA_AUTOCON:
@@ -147,10 +171,10 @@
 }
 
     /*
-     *  Setup the Amiga configuration info
+     *  Identify builtin hardware
      */
 
-__initfunc(void config_amiga(void))
+__initfunc(static void amiga_identify(void))
 {
   /* Fill in some default values, if necessary */
   if (amiga_eclock == 0)
@@ -158,8 +182,6 @@
 
   memset(&amiga_hw_present, 0, sizeof(amiga_hw_present));
 
-  amiga_debug_init();
-
   printk("Amiga hardware found: ");
   if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO)
     printk("[%s] ", amiga_models[amiga_model-AMI_500]);
@@ -171,6 +193,7 @@
   case AMI_600:
   case AMI_1200:
     AMIGAHW_SET(A1200_IDE);
+    AMIGAHW_SET(PCMCIA);
   case AMI_500:
   case AMI_500PLUS:
   case AMI_1000:
@@ -300,11 +323,22 @@
   AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL ");
   AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC ");
   AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK ");
-  if (AMIGAHW_SET(ZORRO))
-    printk("ZORRO%s ", AMIGAHW_SET(ZORRO3) ? "3" : "");
+  AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA ");
+  if (AMIGAHW_PRESENT(ZORRO))
+    printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : "");
   printk("\n");
 
 #undef AMIGAHW_ANNOUNCE
+}
+
+    /*
+     *  Setup the Amiga configuration info
+     */
+
+__initfunc(void config_amiga(void))
+{
+  amiga_debug_init();
+  amiga_identify();
 
   mach_sched_init      = amiga_sched_init;
   mach_keyb_init       = amiga_keyb_init;
@@ -338,15 +372,21 @@
 
   mach_hwclk           = amiga_hwclk;
   mach_set_clock_mmss  = amiga_set_clock_mmss;
-#ifdef CONFIG_BLK_DEV_FD
-  mach_floppy_init     = amiga_floppy_init;
+#ifdef CONFIG_AMIGA_FLOPPY
   mach_floppy_setup    = amiga_floppy_setup;
 #endif
   mach_reset           = amiga_reset;
   conswitchp           = &fb_con;
-  mach_fb_init         = amiga_fb_init;
-  mach_video_setup     = amiga_video_setup;
   kd_mksound           = amiga_mksound;
+#ifdef CONFIG_MAGIC_SYSRQ
+  mach_sysrq_key = 0x5f;	     /* HELP */
+  mach_sysrq_shift_state = 0x03; /* SHIFT+ALTGR */
+  mach_sysrq_shift_mask = 0xff;  /* all modifiers except CapsLock */
+  mach_sysrq_xlate = amiga_sysrq_xlate;
+#endif
+#ifdef CONFIG_HEARTBEAT
+  mach_heartbeat = amiga_heartbeat;
+#endif
 
   /* Fill in the clock values (based on the 700 kHz E-Clock) */
   amiga_masterclock = 40*amiga_eclock;	/* 28 MHz */
@@ -357,15 +397,51 @@
   /* ensure that the DMA master bit is set */
   custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
 
+  /* don't use Z2 RAM as system memory on Z3 capable machines */
+  if (AMIGAHW_PRESENT(ZORRO3)) {
+    int i, j;
+    unsigned long z2mem = 0;
+    for (i = 0; i < m68k_num_memory; i++)
+      if (m68k_memory[i].addr < 16*1024*1024) {
+	if (i == 0) {
+	  /* don't cut off the branch we're sitting on */
+	  printk("Warning: kernel runs in Zorro II memory\n");
+	  continue;
+	}
+	z2mem += m68k_memory[i].size;
+	m68k_num_memory--;
+	for (j = i; j < m68k_num_memory; j++)
+	  m68k_memory[j] = m68k_memory[j+1];
+      }
+    if (z2mem)
+      printk("%ldK of Zorro II memory will not be used as system memory\n",
+	     z2mem>>10);
+  }
+
   /* initialize chipram allocator */
   amiga_chip_init ();
 
+  /* debugging using chipram */
+  if (!strcmp( m68k_debug_device, "mem" )){
+	  if (!AMIGAHW_PRESENT(CHIP_RAM))
+		  printk("Warning: no chipram present for debugging\n");
+	  else {
+		  amiga_savekmsg_init();
+		  amiga_console_driver.write = amiga_mem_console_write;
+		  register_console(&amiga_console_driver);
+	  }
+  }
+
+  /* our beloved beeper */
+  if (AMIGAHW_PRESENT(AMI_AUDIO))
+	  amiga_init_sound();
+
   /*
    * 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;
+	  *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
 
   zorro_init();
 #ifdef CONFIG_ZORRO
@@ -373,7 +449,7 @@
    * Identify all known AutoConfig Expansion Devices
    */
   zorro_identify();
-#endif /* CONFIG_ZORRO */
+#endif
 }
 
 static unsigned short jiffy_ticks;
@@ -383,7 +459,7 @@
 {
 	jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
 
-	ciab.cra &= 0xC0;	 /* turn off timer A, continuous mode, from Eclk */
+	ciab.cra &= 0xC0;   /* turn off timer A, continuous mode, from Eclk */
 	ciab.talo = jiffy_ticks % 256;
 	ciab.tahi = jiffy_ticks / 256;
 
@@ -392,7 +468,8 @@
 	 * Please don't change this to use ciaa, as it interferes with the
 	 * SCSI code. We'll have to take a look at this later
 	 */
-	request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK, "timer", NULL);
+	request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK,
+		    "timer", NULL);
 	/* start timer */
 	ciab.cra |= 0x11;
 }
@@ -462,11 +539,12 @@
 	*monp  = tod->month1      * 10 + tod->month2;
 	*yearp = tod->year1       * 10 + tod->year2;
 
-	if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE))
+	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;
 }
@@ -521,11 +599,12 @@
 			t->mon  = tod->month1      * 10 + tod->month2 - 1;
 			t->year = tod->year1       * 10 + tod->year2;
 
-			if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE))
+			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;
@@ -589,7 +668,7 @@
 	return 0;
 }
 
-static void amiga_wait_key (void)
+static int amiga_wait_key (struct console *co)
 {
     int i;
 
@@ -613,6 +692,7 @@
 	if (ciaa.pra & 0x40)
 	    break;
     }
+    return 0;
 }
 
 void dbprintf(const char *fmt , ...)
@@ -707,16 +787,17 @@
 #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;
+    unsigned long magic1;		/* SAVEKMSG_MAGIC1 */
+    unsigned long magic2;		/* SAVEKMSG_MAGIC2 */
+    unsigned long magicptr;		/* address of magic1 */
+    unsigned long size;
     char data[0];
 };
 
 static struct savekmsg *savekmsg = NULL;
 
-static void amiga_mem_console_write(const char *s, unsigned int count)
+static void amiga_mem_console_write(struct console *co, const char *s,
+				    unsigned int count)
 {
     if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) {
         memcpy(savekmsg->data+savekmsg->size, s, count);
@@ -740,7 +821,8 @@
 	;
 }
 
-static void amiga_serial_console_write(const char *s, unsigned int count)
+void amiga_serial_console_write(struct console *co, const char *s,
+				       unsigned int count)
 {
     while (count--) {
 	if (*s == '\n')
@@ -752,19 +834,27 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 void amiga_serial_puts(const char *s)
 {
-    amiga_serial_console_write(s, strlen(s));
+    amiga_serial_console_write(NULL, s, strlen(s));
+}
+
+int amiga_serial_console_wait_key(struct console *co)
+{
+    int ch;
+
+    while (!(custom.intreqr & IF_RBF))
+	barrier();
+    ch = custom.serdatr & 0xff;
+    /* clear the interrupt, so that another character can be read */
+    custom.intreq = IF_RBF;
+    return ch;
 }
 
-void amiga_serial_gets(char *s, int len)
+void amiga_serial_gets(struct console *co, char *s, int len)
 {
     int ch, cnt = 0;
 
     while (1) {
-	while (!(custom.intreqr & IF_RBF))
-	    barrier();
-	ch = custom.serdatr & 0xff;
-	/* clear the interrupt, so that another character can be read */
-	custom.intreq = IF_RBF;
+	ch = amiga_serial_console_wait_key(co);
 
 	/* Check for backspace. */
 	if (ch == 8 || ch == 127) {
@@ -803,17 +893,19 @@
 	if (!strcmp( m68k_debug_device, "ser" )) {
 		/* no initialization required (?) */
 		amiga_console_driver.write = amiga_serial_console_write;
-	} else if (!strcmp( m68k_debug_device, "mem" )) {
-		amiga_savekmsg_init();
-		amiga_console_driver.write = amiga_mem_console_write;
+		register_console(&amiga_console_driver);
 	}
-	register_console(&amiga_console_driver);
-
-	/* our beloved beeper */
-	if (AMIGAHW_PRESENT(AMI_AUDIO))
-		amiga_init_sound();
 }
 
+#ifdef CONFIG_HEARTBEAT
+static void amiga_heartbeat(int on)
+{
+    if (on)
+	ciaa.pra &= ~2;
+    else
+	ciaa.pra |= 2;
+}
+#endif
 
     /*
      *  Amiga specific parts of /proc
@@ -888,6 +980,7 @@
     AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
     AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374");
     AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick");
+    AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot");
     if (AMIGAHW_PRESENT(ZORRO))
 	len += sprintf(buffer+len, "\tZorro%s AutoConfig: %d Expansion Device%s\n",
 		       AMIGAHW_PRESENT(ZORRO3) ? " III" : "",
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/s3blit.h linux/arch/m68k/amiga/s3blit.h
--- v2.1.86/linux/arch/m68k/amiga/s3blit.h	Sun May 19 21:54:25 1996
+++ linux/arch/m68k/amiga/s3blit.h	Wed Dec 31 16:00:00 1969
@@ -1,74 +0,0 @@
-/* s3 commands */
-#define S3_BITBLT       0xc011
-#define S3_TWOPOINTLINE 0x2811
-#define S3_FILLEDRECT   0x40b1
-
-#define S3_FIFO_EMPTY 0x0400
-#define S3_HDW_BUSY   0x0200
-
-/* Enhanced register mapping (MMIO mode) */
-
-#define S3_READ_SEL      0xbee8 /* offset f */
-#define S3_MULT_MISC     0xbee8 /* offset e */
-#define S3_ERR_TERM      0x92e8
-#define S3_FRGD_COLOR    0xa6e8
-#define S3_BKGD_COLOR    0xa2e8
-#define S3_PIXEL_CNTL    0xbee8 /* offset a */
-#define S3_FRGD_MIX      0xbae8
-#define S3_BKGD_MIX      0xb6e8
-#define S3_CUR_Y         0x82e8
-#define S3_CUR_X         0x86e8
-#define S3_DESTY_AXSTP   0x8ae8
-#define S3_DESTX_DIASTP  0x8ee8
-#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */
-#define S3_MAJ_AXIS_PCNT 0x96e8
-#define S3_CMD           0x9ae8
-#define S3_GP_STAT       0x9ae8
-#define S3_ADVFUNC_CNTL  0x4ae8
-#define S3_WRT_MASK      0xaae8
-#define S3_RD_MASK       0xaee8
-
-/* Enhanced register mapping (Packed MMIO mode, write only) */
-#define S3_ALT_CURXY     0x8100
-#define S3_ALT_CURXY2    0x8104
-#define S3_ALT_STEP      0x8108
-#define S3_ALT_STEP2     0x810c
-#define S3_ALT_ERR       0x8110
-#define S3_ALT_CMD       0x8118
-#define S3_ALT_MIX       0x8134
-#define S3_ALT_PCNT      0x8148
-#define S3_ALT_PAT       0x8168
-
-/* Drawing modes */
-#define S3_NOTCUR          0x0000
-#define S3_LOGICALZERO     0x0001
-#define S3_LOGICALONE      0x0002
-#define S3_LEAVEASIS       0x0003
-#define S3_NOTNEW          0x0004
-#define S3_CURXORNEW       0x0005
-#define S3_NOT_CURXORNEW   0x0006
-#define S3_NEW             0x0007
-#define S3_NOTCURORNOTNEW  0x0008
-#define S3_CURORNOTNEW     0x0009
-#define S3_NOTCURORNEW     0x000a
-#define S3_CURORNEW        0x000b
-#define S3_CURANDNEW       0x000c
-#define S3_NOTCURANDNEW    0x000d
-#define S3_CURANDNOTNEW    0x000e
-#define S3_NOTCURANDNOTNEW 0x000f
-
-#define S3_CRTC_ADR    0x03d4
-#define S3_CRTC_DATA   0x03d5
-
-#define S3_REG_LOCK2 0x39
-#define S3_HGC_MODE  0x45
-
-#define S3_HWGC_ORGX_H 0x46
-#define S3_HWGC_ORGX_L 0x47
-#define S3_HWGC_ORGY_H 0x48
-#define S3_HWGC_ORGY_L 0x49
-#define S3_HWGC_DX     0x4e
-#define S3_HWGC_DY     0x4f
-
-
-#define S3_LAW_CTL 0x58
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/amiga/zorro.c linux/arch/m68k/amiga/zorro.c
--- v2.1.86/linux/arch/m68k/amiga/zorro.c	Thu Jul 31 13:09:16 1997
+++ linux/arch/m68k/amiga/zorro.c	Thu Feb 12 16:30:12 1998
@@ -13,996 +13,1221 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/init.h>
-#include <linux/zorro.h>
 #include <asm/setup.h>
 #include <asm/bitops.h>
 #include <asm/amigahw.h>
+#include <linux/zorro.h>
 
 
 #ifdef CONFIG_ZORRO
 
-   /*
-    *    Zorro Expansion Device Manufacturers and Products
-    */
+    /*
+     *  Zorro Expansion Device Manufacturers and Products
+     */
 
 struct Manufacturer {
-   char *Name;
-   u_short ID;
-   u_short NumProd;
-   struct Product *Products;
+    const char *Name;
+    u_short Manuf;
+    u_short NumProd;
+    const struct Product *Products;
 };
 
 struct Product {
-   char *Name;
-   u_char ID;
+    const char *Name;
+    u_char Class;
+    u_char Prod;
 };
 
 struct GVP_Product {
-   char *Name;
-   enum GVP_ident ID;
+    const char *Name;
+    u_char Class;
+    u_char EPC;
 };
 
 
-   /*
-    *    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 },
+    /*
+     *  Macro's to make life easier
+     */
+
+#define ARRAYSIZE(x)		(sizeof(x)/sizeof(*(x)))
+
+#define BEGIN_PROD(id) \
+    static struct Product Prod_##id[] = {
+#define PROD(name, class, id) \
+    { name, ZORRO_CLASS_##class, ZORRO_PROD(ZORRO_PROD_##id) },
+
+#define BEGIN_GVP_PROD \
+    static struct GVP_Product Ext_Prod_GVP[] = {
+#define GVP_PROD(name, class, id) \
+    { name, ZORRO_CLASS_##class, ZORRO_EPC(ZORRO_PROD_##id) },
 
-#define BEGIN_MANUF static struct Manufacturer Manufacturers[] = {
+#define BEGIN_MANUF \
+    static struct Manufacturer Manufacturers[] = {
 #define MANUF(name, id) \
-   { name, MANUF_##id, sizeof(Prod_##id)/sizeof(struct Product), Prod_##id },
+    { name, ZORRO_MANUF_##id, ARRAYSIZE(Prod_##id), Prod_##id },
 
-#define END };
+#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)
-    */
+    /*
+     *  Recognized Zorro Expansion Devices
+     */
+
+BEGIN_PROD(PACIFIC_PERIPHERALS)
+    PROD("SE 2000 A500", HD, PACIFIC_PERIPHERALS_SE_2000_A500)
+    PROD(NULL, SCSI, PACIFIC_PERIPHERALS_SCSI)
+END
 
-BEGIN_PROD(PACIFIC)
-   PROD("SE 2000 A500", SE_2000_A500)
-   PROD("HD Controller", PACIFIC_HD)
+BEGIN_PROD(MACROSYSTEMS_USA_2)
+    PROD("Warp Engine", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE)
 END
 
-BEGIN_PROD(KUPKE)
-   PROD("Golem RAM Box 2MB", GOLEM_BOX_2)
+BEGIN_PROD(KUPKE_1)
+    PROD("Golem RAM Box 2MB", RAM, KUPKE_GOLEM_RAM_BOX_2MB)
 END
 
 BEGIN_PROD(MEMPHIS)
-   PROD("Stormbringer", STORMBRINGER)
+    PROD("Stormbringer", TURBO, MEMPHIS_STORMBRINGER)
 END
 
 BEGIN_PROD(3_STATE)
-   PROD("Megamix 2000 RAM", MEGAMIX_2000)
+    PROD("Megamix 2000", RAM, 3_STATE_MEGAMIX_2000)
+END
+
+BEGIN_PROD(COMMODORE_BRAUNSCHWEIG)
+    PROD("A2088 XT/A2286 AT", BRIDGE, CBM_A2088_A2286)
+    PROD("A2286 AT", BRIDGE, CBM_A2286)
+    PROD("A4091", SCSI, CBM_A4091_1)
+    PROD("A2386-SX", BRIDGE, CBM_A2386SX_1)
+END
+
+BEGIN_PROD(COMMODORE_WEST_CHESTER_1)
+    PROD("A2090/A2090A", SCSI, CBM_A2090A)
+    PROD("A590/A2091", SCSI, CBM_A590_A2091_1)
+    PROD("A590/A2091", SCSI, CBM_A590_A2091_2)
+    PROD("A2090B 2090 Autoboot", SCSI, CBM_A2090B)
+    PROD("A2060", ARCNET, CBM_A2060)
+    PROD("A590/A2052/A2058/A2091", RAM, CBM_A590_A2052_A2058_A2091)
+    PROD("A560", RAM, CBM_A560_RAM)
+    PROD("A2232 Prototype", MULTIIO, CBM_A2232_PROTOTYPE)
+    PROD("A2232", MULTIIO, CBM_A2232)
+    PROD("A2620 68020/RAM", TURBO_RAM, CBM_A2620)
+    PROD("A2630 68030/RAM", TURBO_RAM, CBM_A2630)
+    PROD("A4091", SCSI, CBM_A4091_2)
+    PROD("A2065", ETHERNET, CBM_A2065_1)
+    PROD("Romulator Card", UNKNOWN, CBM_ROMULATOR)
+    PROD("A3000 Test Fixture", MISC, CBM_A3000_TEST_FIXTURE)
+    PROD("A2386-SX", BRIDGE, CBM_A2386SX_2)
+    PROD("A2065", ETHERNET, CBM_A2065_2)
+END
+
+BEGIN_PROD(COMMODORE_WEST_CHESTER_2)
+    PROD("A2090/A2090A Combitec/MacroSystem", SCSI, CBM_A2090A_CM)
+END
+
+BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2)
+    PROD("EXP8000", RAM, PPS_EXP8000)
+END
+
+BEGIN_PROD(KOLFF_COMPUTER_SUPPLIES)
+    PROD("KCS Power PC Board", BRIDGE, KCS_POWER_PC_BOARD)
 END
 
-BEGIN_PROD(COMMODORE2)
-   PROD("A2088 XT Bridgeboard", A2088)
-   PROD("A2286 AT Bridgeboard", A2286)
-   PROD("A4091 SCSI Controller", A4091_2)
-   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("A2065 Ethernet Card", A2065_2)
-   PROD("Romulator Card", ROMULATOR)
-   PROD("A3000 Test Fixture", A3000TESTFIX)
-   PROD("A2386-SX Bridgeboard", A2386SX_2)
-   PROD("A2065 Ethernet Card", A2065)
-END
-
-BEGIN_PROD(COMMODORE3)
-   PROD("A2090A Combitec/MacroSystem", A2090A_CM)
-END
-
-BEGIN_PROD(KCS)
-   PROD("KCS Power PC Board", POWER_BOARD)
-END
-
-BEGIN_PROD(CARDCO)
-   PROD("Kronos 2000 SCSI Controller", KRONOS_2000_SCSI)
-   PROD("A1000 SCSI Controller", A1000_SCSI)
-   PROD("Escort SCSI Controller", ESCORT_SCSI)
-   PROD("Cardco A2410 Hires Graphics card", CC_A2410)
+BEGIN_PROD(CARDCO_1)
+    PROD("Kronos 2000", SCSI, CARDCO_KRONOS_2000_1)
+    PROD("A1000", SCSI, CARDCO_A1000_1)
+    PROD("Escort", SCSI, CARDCO_ESCORT)
+    PROD("A2410 HiRes", GFX, CARDCO_A2410)
 END
 
 BEGIN_PROD(A_SQUARED)
-   PROD("Live! 2000", LIVE_2000)
+    PROD("Live! 2000", VIDEO, A_SQUARED_LIVE_2000)
 END
 
-BEGIN_PROD(COMSPEC)
-   PROD("AX2000", AX2000)
+BEGIN_PROD(COMSPEC_COMMUNICATIONS)
+    PROD("AX2000", RAM, COMSPEC_COMMUNICATIONS_AX2000)
 END
 
-BEGIN_PROD(ANAKIN)
-   PROD("Easyl Tablet", EASYL)
+BEGIN_PROD(ANAKIN_RESEARCH)
+    PROD("Easyl", TABLET, ANAKIN_RESEARCH_EASYL)
 END
 
 BEGIN_PROD(MICROBOTICS)
-   PROD("StarBoard II", STARBOARD_II)
-   PROD("StarDrive", STARDRIVE)
-   PROD("8-Up (Rev A)", 8_UP_A)
-   PROD("8-Up (Rev Z)", 8_UP_Z)
-   PROD("Delta Card RAM", DELTA_RAM)
-   PROD("8-Star RAM", 8_STAR_RAM)
-   PROD("8-Star", 8_STAR)
-   PROD("VXL RAM", VXL_RAM)
-   PROD("VXL-30 Turbo Board", VXL_30)
-   PROD("Delta Card", DELTA)
-   PROD("MBX 1200", MBX_1200)
-   PROD("Hardframe 2000", HARDFRAME_2000)
-   PROD("MBX 1200", MBX_1200_2)
+    PROD("StarBoard II", RAM, MICROBOTICS_STARBOARD_II)
+    PROD("StarDrive", SCSI, MICROBOTICS_STARDRIVE)
+    PROD("8-Up (Rev A)", RAM, MICROBOTICS_8_UP_A)
+    PROD("8-Up (Rev Z)", RAM, MICROBOTICS_8_UP_Z)
+    PROD("Delta", RAM, MICROBOTICS_DELTA_RAM)
+    PROD("8-Star", RAM, MICROBOTICS_8_STAR_RAM)
+    PROD("8-Star", MISC, MICROBOTICS_8_STAR)
+    PROD("VXL RAM*32", RAM, MICROBOTICS_VXL_RAM_32)
+    PROD("VXL-30", TURBO, MICROBOTICS_VXL_68030)
+    PROD("Delta", MISC, MICROBOTICS_DELTA)
+    PROD("MBX 1200/1200z", RAM, MICROBOTICS_MBX_1200_1200Z_RAM)
+    PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_1)
+    PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_2)
+    PROD("MBX 1200/1200z", MISC, MICROBOTICS_MBX_1200_1200Z)
 END
 
-BEGIN_PROD(ACCESS)
+BEGIN_PROD(ACCESS_ASSOCIATES_ALEGRA)
 END
 
-BEGIN_PROD(EXPANSION_TECH)
+BEGIN_PROD(EXPANSION_TECHNOLOGIES)
 END
 
 BEGIN_PROD(ASDG)
-   PROD("Memory Expansion", ASDG_MEMORY)
-   PROD("Memory Expansion", ASDG_MEMORY_2)
-   PROD("Lan Rover Ethernet", LAN_ROVER)
-   PROD("Twin-X Serial Card", TWIN_X)
+    PROD(NULL, RAM, ASDG_MEMORY_1)
+    PROD(NULL, RAM, ASDG_MEMORY_2)
+    PROD("EB-920 Lan Rover", ETHERNET, ASDG_EB920_LAN_ROVER)
+    PROD("GPIB/Dual IEEE-488/Twin-X", MULTIIO, ASDG_GPIB_DUALIEEE488_TWIN_X)
 END
 
-BEGIN_PROD(IMTRONICS)
-   PROD("Hurricane 2800 68030", HURRICANE_2800)
-   PROD("Hurricane 2800 68030", HURRICANE_2800_2)
+BEGIN_PROD(IMTRONICS_1)
+    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_1)
+    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_2)
 END
 
-BEGIN_PROD(UNIV_OF_LOWELL)
-   PROD("A2410 Hires Graphics Card", A2410)
+BEGIN_PROD(CBM_UNIVERSITY_OF_LOWELL)
+    PROD("A2410 HiRes", GFX, CBM_A2410)
 END
 
 BEGIN_PROD(AMERISTAR)
-   PROD("A2065 Ethernet Card", AMERISTAR2065)
-   PROD("A560 Arcnet Card", A560)
-   PROD("A4066 Ethernet Card", A4066)
+    PROD("A2065", ETHERNET, AMERISTAR_A2065)
+    PROD("A560", ARCNET, AMERISTAR_A560)
+    PROD("A4066", ETHERNET, AMERISTAR_A4066)
 END
 
 BEGIN_PROD(SUPRA)
-   PROD("SupraDrive 4x4 SCSI Controller", SUPRADRIVE_4x4)
-   PROD("2000 DMA HD", SUPRA_2000)
-   PROD("500 HD/RAM", SUPRA_500)
-   PROD("500XP/2000 RAM", SUPRA_500XP)
-   PROD("500RX/2000 RAM", SUPRA_500RX)
-   PROD("2400zi Modem", SUPRA_2400ZI)
-   PROD("Wordsync SCSI Controller", WORDSYNC)
-   PROD("Wordsync II SCSI Controller", WORDSYNC_II)
-   PROD("2400zi+ Modem", SUPRA_2400ZIPLUS)
+    PROD("SupraDrive 4x4", SCSI, SUPRA_SUPRADRIVE_4x4)
+    PROD("1000", RAM, SUPRA_1000_RAM)
+    PROD("2000 DMA", SCSI, SUPRA_2000_DMA)
+    PROD("500", SCSI_RAM, SUPRA_500)
+    PROD("500", SCSI, SUPRA_500_SCSI)
+    PROD("500XP/2000", RAM, SUPRA_500XP_2000_RAM)
+    PROD("500RX/2000", RAM, SUPRA_500RX_2000_RAM)
+    PROD("2400zi", MODEM, SUPRA_2400ZI)
+    PROD("500XP/SupraDrive WordSync", SCSI, SUPRA_500XP_SUPRADRIVE_WORDSYNC)
+    PROD("SupraDrive WordSync II", SCSI, SUPRA_SUPRADRIVE_WORDSYNC_II)
+    PROD("2400zi+", MODEM, SUPRA_2400ZIPLUS)
 END
 
-BEGIN_PROD(CSA)
-   PROD("Magnum 40 SCSI Controller", MAGNUM)
-   PROD("12 Gauge SCSI Controller", 12GAUGE)
+BEGIN_PROD(COMPUTER_SYSTEMS_ASSOCIATES)
+    PROD("Magnum 40", TURBO_SCSI, CSA_MAGNUM)
+    PROD("12 Gauge", SCSI, CSA_12_GAUGE)
 END
 
-BEGIN_PROD(MTEC2)
-   PROD("AT500 RAM", AT500_2)
+BEGIN_PROD(MARC_MICHAEL_GROTH)
 END
 
-BEGIN_PROD(GVP3)
-   PROD("Impact SCSI/Memory", IMPACT)
+BEGIN_PROD(M_TECH)
+    PROD("AT500", RAM, MTEC_AT500_1)
+END
+
+BEGIN_PROD(GREAT_VALLEY_PRODUCTS_1)
+    PROD("Impact Series I", SCSI_RAM, GVP_IMPACT_SERIES_I)
 END
 
 BEGIN_PROD(BYTEBOX)
-   PROD("A500", BYTEBOX_A500)
+    PROD("A500", UNKNOWN, BYTEBOX_A500)
 END
 
-BEGIN_PROD(POWER_COMPUTING)
-   PROD("DKB 3128 RAM", DKB_3128)
-   PROD("Rapid Fire SCSI Controller", RAPID_FIRE)
-   PROD("DKB 1202 RAM", DKB_1202)
-   PROD("DKB Cobra / Viper II Turbo Board", VIPER_II_COBRA)
-   PROD("WildFire 060 Turbo Board", WILDFIRE_060)
-   PROD("WildFire 060 Turbo Board", WILDFIRE_060_2)
-END
-
-BEGIN_PROD(GVP)
-   PROD("Impact Series-I SCSI 4K", IMPACT_I_4K)
-   PROD("Impact Series-I SCSI 16K/2", IMPACT_I_16K_2)
-   PROD("Impact Series-I SCSI 16K/3", IMPACT_I_16K_3)
-   PROD("Impact 3001 IDE", IMPACT_3001_IDE)
-/* PROD("Impact 3001 RAM", IMPACT_3001_RAM) */
-   PROD("Generic GVP product", GVP)
-   PROD("Series II SCSI Controller", GVPIISCSI)
-   PROD("Series II SCSI Controller", GVPIISCSI_2)
-   PROD("Series II RAM", GVPIIRAM)
-   PROD("A2000 68030 Turbo Board", GVP_A2000_030)
-/* PROD("Impact 3001 IDE", IMPACT_3001_IDE_2) */
-   PROD("GFORCE 040 with SCSI Controller", GFORCE_040_SCSI)
-   PROD("IV-24 Graphics Board", GVPIV_24)
-   PROD("GFORCE 040 Turbo Board", GFORCE_040)
-/* 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)
+BEGIN_PROD(DKB_POWER_COMPUTING)
+    PROD("SecureKey", UNKNOWN, DKB_POWER_COMPUTING_SECUREKEY)
+    PROD("DKM 3128", RAM, DKB_POWER_COMPUTING_DKM_3128)
+    PROD("Rapid Fire", SCSI, DKB_POWER_COMPUTING_RAPID_FIRE)
+    PROD("DKM 1202", FPU_RAM, DKB_POWER_COMPUTING_DKM_1202)
+    PROD("Cobra/Viper II 68EC030", TURBO, DKB_POWER_COMPUTING_COBRA_VIPER_II_68EC030)
+    PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_1)
+    PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_2)
+END
+
+BEGIN_PROD(GREAT_VALLEY_PRODUCTS_2)
+    PROD("Impact Series I (4K)", SCSI, GVP_IMPACT_SERIES_I_4K)
+    PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_2)
+    PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_3)
+    PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_1)
+    PROD("Impact 3001", RAM, GVP_IMPACT_3001_RAM)
+    PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_1)
+/*  PROD(NULL, UNKNOWN, GVP_EPC_BASE) */
+    PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_2)
+/*  PROD("A2000 030", TURBO, GVP_A2000_030) */
+/*  PROD("GForce 040", TURBO_SCSI, GFORCE_040_SCSI_2) */
+    PROD("GForce 040/060", TURBO_SCSI, GVP_GFORCE_040_060)
+    PROD("Impact Vision 24", GFX, GVP_IMPACT_VISION_24)
+    PROD("GForce 040", TURBO, GVP_GFORCE_040_2)
+END
+
+BEGIN_GVP_PROD					/* ZORRO_PROD_GVP_EPC_BASE */
+    GVP_PROD("GForce 040", TURBO, GVP_GFORCE_040_1)
+    GVP_PROD("GForce 040", TURBO_SCSI, GVP_GFORCE_040_SCSI_1)
+    GVP_PROD("A1291", SCSI, GVP_A1291)
+    GVP_PROD("Combo 030 R4", TURBO, GVP_COMBO_030_R4)
+    GVP_PROD("Combo 030 R4", TURBO_SCSI, GVP_COMBO_030_R4_SCSI)
+    GVP_PROD("Phone Pak", UNKNOWN, GVP_PHONEPAK)
+    GVP_PROD("IO-Extender", MULTIIO, GVP_IO_EXTENDER)
+    GVP_PROD("GForce 030", TURBO, GVP_GFORCE_030)
+    GVP_PROD("GForce 030", TURBO_SCSI, GVP_GFORCE_030_SCSI)
+    GVP_PROD("A530", TURBO, GVP_A530)
+    GVP_PROD("A530", TURBO_SCSI, GVP_A530_SCSI)
+    GVP_PROD("Combo 030 R3", TURBO, GVP_COMBO_030_R3)
+    GVP_PROD("Combo 030 R3", TURBO_SCSI, GVP_COMBO_030_R3_SCSI)
+    GVP_PROD("Series-II", SCSI, GVP_SERIES_II)
 END
 
-BEGIN_PROD(SYNERGY)
+BEGIN_PROD(CALIFORNIA_ACCESS_SYNERGY)
+    PROD("Malibu", SCSI, CALIFORNIA_ACCESS_SYNERGY_MALIBU)
 END
 
 BEGIN_PROD(XETEC)
-   PROD("FastCard SCSI Controller", FASTCARD_SCSI)
-   PROD("FastCard RAM", FASTCARD_RAM)
+    PROD("FastCard", SCSI, XETEC_FASTCARD)
+    PROD("FastCard", RAM, XETEC_FASTCARD_RAM)
+    PROD("FastCard Plus", SCSI, XETEC_FASTCARD_PLUS)
 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)
+BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS)
+    PROD("Mercury", TURBO, PPS_MERCURY)
+    PROD("A3000 68040", TURBO, PPS_A3000_68040)
+    PROD("A2000 68040", TURBO, PPS_A2000_68040)
+    PROD("Zeus", TURBO_SCSI_RAM, PPS_ZEUS)
+    PROD("A500 68040", TURBO, PPS_A500_68040)
 END
 
 BEGIN_PROD(XEBEC)
 END
 
-BEGIN_PROD(SPIRIT)
-   PROD("HDA 506 Harddisk", HDA_506)
-   PROD("OctaByte RAM", OCTABYTE_RAM)
+BEGIN_PROD(SPIRIT_TECHNOLOGY)
+    PROD("Insider IN1000", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN1000)
+    PROD("Insider IN500", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN500)
+    PROD("SIN500", RAM, SPIRIT_TECHNOLOGY_SIN500)
+    PROD("HDA 506", HD, SPIRIT_TECHNOLOGY_HDA_506)
+    PROD("AX-S", MISC, SPIRIT_TECHNOLOGY_AX_S)
+    PROD("OctaByte", RAM, SPIRIT_TECHNOLOGY_OCTABYTE)
+    PROD("Inmate", SCSI_RAM, SPIRIT_TECHNOLOGY_INMATE)
+END
+
+BEGIN_PROD(SPIRIT_TECHNOLOGY_2)
 END
 
-BEGIN_PROD(BSC)
-   PROD("ALF 3 SCSI Controller", ALF_3_SCSI)
+BEGIN_PROD(BSC_ALFADATA_1)
+    PROD("ALF 3", SCSI, BSC_ALF_3_1)
 END
 
-BEGIN_PROD(BSC3)
-   PROD("ALF 2 SCSI Controller", ALF_2_SCSI)
-   PROD("ALF 2 SCSI Controller", ALF_2_SCSI_2)
-   PROD("ALF 3 SCSI Controller", ALF_3_SCSI_2)
+BEGIN_PROD(BSC_ALFADATA_2)
+    PROD("ALF 2", SCSI, BSC_ALF_2_1)
+    PROD("ALF 2", SCSI, BSC_ALF_2_2)
+    PROD("ALF 3", SCSI, BSC_ALF_3_2)
 END
 
-BEGIN_PROD(C_LTD)
-   PROD("Kronos SCSI Controller", KRONOS_SCSI)
-   PROD("A1000 SCSI Controller", A1000_SCSI_2)
+BEGIN_PROD(CARDCO_2)
+    PROD("Kronos", SCSI, CARDCO_KRONOS_2000_2)
+    PROD("A1000", SCSI, CARDCO_A1000_2)
 END
 
 BEGIN_PROD(JOCHHEIM)
-   PROD("Jochheim RAM", JOCHHEIM_RAM)
+    PROD(NULL, RAM, JOCHHEIM_RAM)
 END
 
-BEGIN_PROD(CHECKPOINT)
-   PROD("Serial Solution", SERIAL_SOLUTION)
+BEGIN_PROD(CHECKPOINT_TECHNOLOGIES)
+    PROD("Serial Solution", SERIAL, CHECKPOINT_TECHNOLOGIES_SERIAL_SOLUTION)
+END
+
+BEGIN_PROD(EDOTRONIK)
+    PROD("IEEE-488 Interface Board", UNKNOWN, EDOTRONIK_IEEE_488)
+    PROD("CBM-8032 Board", UNKNOWN, EDOTRONIK_8032)
+    PROD(NULL, SERIAL, EDOTRONIK_MULTISERIAL)
+    PROD("24Bit Realtime Video Digitizer", UNKNOWN, EDOTRONIK_VIDEODIGITIZER)
+    PROD("32Bit Parallel I/O Interface", UNKNOWN, EDOTRONIK_PARALLEL_IO)
+    PROD("PIC Prototyping Board", UNKNOWN, EDOTRONIK_PIC_PROTOYPING)
+    PROD("16 Channel ADC Interface", UNKNOWN, EDOTRONIK_ADC)
+    PROD("VME-Bus Controller", UNKNOWN, EDOTRONIK_VME)
+    PROD("DSP96000 Realtime Data Acquisition", DSP, EDOTRONIK_DSP96000)
+END
+
+BEGIN_PROD(NES_INC)
+    PROD(NULL, RAM, NES_INC_RAM)
 END
 
 BEGIN_PROD(ICD)
-   PROD("Advantage 2000 SCSI Controller", ADVANTAGE_2000)
+    PROD("Advantage 2000", SCSI, ICD_ADVANTAGE_2000_SCSI)
+    PROD("Advantage", IDE, ICD_ADVANTAGE_2000_SCSI)
+    PROD("Advantage 2080", RAM, ICD_ADVANTAGE_2080_RAM)
+END
+
+BEGIN_PROD(KUPKE_2)
+    PROD("Omti", HD, KUPKE_OMTI)
+    PROD("Golem SCSI-II", SCSI, KUPKE_SCSI_II)
+    PROD("Golem Box", UNKNOWN, KUPKE_GOLEM_BOX)
+    PROD("030/882", TURBO, KUPKE_030_882)
+    PROD("Golem", SCSI, KUPKE_SCSI_AT)
 END
 
-BEGIN_PROD(KUPKE2)
-   PROD("Golem SCSI-II Controller", KUPKE_SCSI_II)
-   PROD("Golem Box", GOLEM_BOX)
-   PROD("030/882 Turbo Board", KUPKE_TURBO)
-   PROD("Golem SCSI/AT Controller", KUPKE_SCSI_AT)
+BEGIN_PROD(GREAT_VALLEY_PRODUCTS_3)
+    PROD("A2000-RAM8/2", MISC, GVP_A2000_RAM8)
+    PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_2)
 END
 
-BEGIN_PROD(GVP4)
-   PROD("A2000-RAM8/2", A2000_RAM8)
+BEGIN_PROD(INTERWORKS_NETWORK)
 END
 
-BEGIN_PROD(INTERWORKS_NET)
+BEGIN_PROD(HARDITAL_SYNTHESIS)
+    PROD("TQM 68030+68882", TURBO, HARDITAL_SYNTHESIS_TQM_68030_68882)
 END
 
-BEGIN_PROD(HARDITAL)
-   PROD("TQM 68030+68882 Turbo Board", TQM)
+BEGIN_PROD(APPLIED_ENGINEERING)
+    PROD("DL2000", MODEM, APPLIED_ENGINEERING_DL2000)
+    PROD("RAM Works", RAM, APPLIED_ENGINEERING_RAM_WORKS)
 END
 
-BEGIN_PROD(BSC2)
-   PROD("Oktagon 2008 SCSI Controller", OKTAGON_SCSI)
-   PROD("Tandem AT-2008/508 IDE Controller", TANDEM)
-   PROD("Alpha RAM 1200", ALPHA_RAM_1200)
-   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("Framebuffer", BSC_FRAEMBUFFER)
-   PROD("Graffiti Graphics Board (RAM)", GRAFFITI_RAM)
-   PROD("Graffiti Graphics Board (REG)", GRAFFITI_REG)
-   PROD("ISDN MasterCard", ISDN_MASTERCARD)
-   PROD("ISDN MasterCard II", ISDN_MASTERCARD_2)
+BEGIN_PROD(BSC_ALFADATA_3)
+    PROD("Oktagon 2008", SCSI, BSC_OKTAGON_2008)
+    PROD("Tandem AT-2008/508", IDE, BSC_TANDEM_AT_2008_508)
+    PROD("Alpha RAM 1200", RAM, BSC_ALFA_RAM_1200)
+    PROD("Oktagon 2008", RAM, BSC_OKTAGON_2008_RAM)
+    PROD("MultiFace I", MULTIIO, BSC_MULTIFACE_I)
+    PROD("MultiFace II", MULTIIO, BSC_MULTIFACE_II)
+    PROD("MultiFace III", MULTIIO, BSC_MULTIFACE_III)
+    PROD("Framebuffer", MISC, BSC_FRAMEBUFFER)
+    PROD("Graffiti", GFXRAM, BSC_GRAFFITI_RAM)
+    PROD("Graffiti", GFX, BSC_GRAFFITI_REG)
+    PROD("ISDN MasterCard", ISDN, BSC_ISDN_MASTERCARD)
+    PROD("ISDN MasterCard II", ISDN, BSC_ISDN_MASTERCARD_II)
 END
 
-BEGIN_PROD(ADV_SYS_SOFT)
-   PROD("Nexus SCSI Controller", NEXUS_SCSI)
-   PROD("Nexus RAM", NEXUS_RAM)
+BEGIN_PROD(PHOENIX)
+    PROD("ST506", HD, PHOENIX_ST506)
+    PROD(NULL, SCSI, PHOENIX_SCSI)
+    PROD(NULL, RAM, PHOENIX_RAM)
+END
+
+BEGIN_PROD(ADVANCED_STORAGE_SYSTEMS)
+    PROD("Nexus", SCSI, ADVANCED_STORAGE_SYSTEMS_NEXUS)
+    PROD("Nexus", RAM, ADVANCED_STORAGE_SYSTEMS_NEXUS_RAM)
 END
 
 BEGIN_PROD(IMPULSE)
-   PROD("FireCracker 24", FIRECRACKER_24)
+    PROD("FireCracker 24", GFX, IMPULSE_FIRECRACKER_24)
 END
 
 BEGIN_PROD(IVS)
-   PROD("GrandSlam PIC 2 RAM", GRANDSLAM_PIC_2)
-   PROD("GrandSlam PIC 1 RAM", GRANDSLAM_PIC_1)
-   PROD("OverDrive HD", IVS_OVERDRIVE)
-   PROD("Trumpcard Classic SCSI Controller", TRUMPCARD_CLASSIC)
-   PROD("Trumpcard Pro SCSI Controller", TRUMPCARD_PRO)
-   PROD("Meta-4 RAM", META_4)
-   PROD("Wavetools Sound Board", WAVETOOLS)
-   PROD("Vector SCSI Controller", VECTOR)
-   PROD("Vector SCSI Controller", VECTOR_2)
+    PROD("GrandSlam PIC 2", RAM, IVS_GRANDSLAM_PIC_2)
+    PROD("GrandSlam PIC 1", RAM, IVS_GRANDSLAM_PIC_1)
+    PROD("OverDrive", HD, IVS_OVERDRIVE)
+    PROD("TrumpCard Classic", SCSI, IVS_TRUMPCARD_CLASSIC)
+    PROD("TrumpCard Pro/GrandSlam", SCSI, IVS_TRUMPCARD_PRO_GRANDSLAM)
+    PROD("Meta-4", RAM, IVS_META_4)
+    PROD("Wavetools", AUDIO, IVS_WAVETOOLS)
+    PROD("Vector", SCSI, IVS_VECTOR_1)
+    PROD("Vector", SCSI, IVS_VECTOR_2)
 END
 
-BEGIN_PROD(VECTOR)
-   PROD("Connection Serial IO", CONNECTION)
+BEGIN_PROD(VECTOR_1)
+    PROD("Connection", MULTIIO, VECTOR_CONNECTION_1)
 END
 
 BEGIN_PROD(XPERT_PRODEV)
-   PROD("Visiona Graphics Board (RAM)", VISIONA_RAM)
-   PROD("Visiona Graphics Board (REG)", VISIONA_REG)
-   PROD("Merlin Graphics Board (RAM)", MERLIN_RAM)
-   PROD("Merlin Graphics Board (REG)", MERLIN_REG)
-   PROD("Merlin Graphics Board (REG)", MERLIN_REG_2)
+    PROD("Visiona", GFXRAM, XPERT_PRODEV_VISIONA_RAM)
+    PROD("Visiona", GFX, XPERT_PRODEV_VISIONA_REG)
+    PROD("Merlin", GFXRAM, XPERT_PRODEV_MERLIN_RAM)
+    PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_1)
+    PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_2)
 END
 
 BEGIN_PROD(HYDRA_SYSTEMS)
-   PROD("Amiganet Board", AMIGANET)
+    PROD("Amiganet", ETHERNET, HYDRA_SYSTEMS_AMIGANET)
 END
 
-BEGIN_PROD(SUNRIZE)
-   PROD("AD516 Audio", AD516)
+BEGIN_PROD(SUNRIZE_INDUSTRIES)
+    PROD("AD1012", AUDIO, SUNRIZE_INDUSTRIES_AD1012)
+    PROD("AD516", AUDIO, SUNRIZE_INDUSTRIES_AD516)
+    PROD("DD512", AUDIO, SUNRIZE_INDUSTRIES_DD512)
 END
 
 BEGIN_PROD(TRICERATOPS)
-   PROD("Multi I/O Board", TRICERATOPS)
+    PROD(NULL, MULTIIO, TRICERATOPS_MULTI_IO)
 END
 
 BEGIN_PROD(APPLIED_MAGIC)
-   PROD("DMI Resolver Graphics Board", DMI_RESOLVER)
-   PROD("Digital Broadcaster", DIGITAL_BCASTER)
+    PROD("DMI Resolver", GFX, APPLIED_MAGIC_DMI_RESOLVER)
+    PROD("Digital Broadcaster", VIDEO, APPLIED_MAGIC_DIGITAL_BROADCASTER)
 END
 
 BEGIN_PROD(GFX_BASE)
-   PROD("GDA-1 Graphics Board (RAM)", GDA_1_RAM)
-   PROD("GDA-1 Graphics Board (REG)", GDA_1_REG)
+    PROD("GDA-1 VRAM", GFX, GFX_BASE_GDA_1_VRAM)
+    PROD("GDA-1", GFX, GFX_BASE_GDA_1)
 END
 
 BEGIN_PROD(ROCTEC)
-   PROD("RH 800C Hard Disk Controller", RH_800C)
-   PROD("RH 800C RAM", RH_800C_RAM)
+    PROD("RH 800C", HD, ROCTEC_RH_800C)
+    PROD("RH 800C", RAM, ROCTEC_RH_800C_RAM)
+END
+
+BEGIN_PROD(KATO)
+    PROD("Melody MPEG", AUDIO, KATO_MELODY)
+    PROD("Rainbow II", GFX, HELFRICH_RAINBOW_II)	/* ID clash!! */
+    PROD("Rainbow III", GFX, HELFRICH_RAINBOW_III)	/* ID clash!! */
+END
+
+BEGIN_PROD(ATLANTIS)
 END
 
-BEGIN_PROD(HELFRICH1)
-   PROD("Rainbow3 Graphics Board", RAINBOW3)
+BEGIN_PROD(PROTAR)
 END
 
-BEGIN_PROD(SW_RESULT_ENTS)
-   PROD("GG2+ Bus Converter", GG2PLUS)
+BEGIN_PROD(ACS)
+END
+
+BEGIN_PROD(SOFTWARE_RESULTS_ENTERPRISES)
+    PROD("Golden Gate 2 Bus+", BRIDGE, SOFTWARE_RESULTS_ENTERPRISES_GOLDEN_GATE_2_BUS_PLUS)
 END
 
 BEGIN_PROD(MASOBOSHI)
-   PROD("Master Card RAM", MASTER_CARD_RAM)
-   PROD("Master Card SCSI Controller", MASTER_CARD_SCSI)
-   PROD("MVD 819", MVD_819)
+    PROD("MasterCard SC201", RAM, MASOBOSHI_MASTER_CARD_SC201)
+    PROD("MasterCard MC702", SCSI_IDE, MASOBOSHI_MASTER_CARD_MC702)
+    PROD("MVD 819", UNKNOWN, MASOBOSHI_MVD_819)
 END
 
-BEGIN_PROD(VILLAGE_TRONIC)
-   PROD("Domino Graphics Board (RAM)", DOMINO_RAM)
-   PROD("Domino Graphics Board (REG)", DOMINO_REG)
-   PROD("Picasso II Graphics Board (RAM)", PICASSO_II_RAM)
-   PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG)
-   PROD("Picasso II/II+ Graphics Board (Segmented Mode)", PICASSO_II_SEGM)
-   PROD("Picassio IV Graphics Board", PICASSO_IV)
-   PROD("Picassio IV Graphics Board", PICASSO_IV_2)
-   PROD("Picassio IV Graphics Board", PICASSO_IV_3)
-   PROD("Picassio IV Graphics Board", PICASSO_IV_4)
-   PROD("Ariadne Ethernet Card", ARIADNE)
+BEGIN_PROD(MAINHATTAN_DATA)
+    PROD(NULL, IDE, MAINHATTAN_DATA_IDE)
 END
 
-BEGIN_PROD(UTILITIES_ULTD)
-   PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE)
-   PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE2)
+BEGIN_PROD(VILLAGE_TRONIC)
+    PROD("Domino", GFXRAM, VILLAGE_TRONIC_DOMINO_RAM)
+    PROD("Domino", GFX, VILLAGE_TRONIC_DOMINO_REG)
+    PROD("Domino 16M Prototype", GFX, VILLAGE_TRONIC_DOMINO_16M_PROTOTYPE)
+    PROD("Picasso II/II+", GFXRAM, VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM)
+    PROD("Picasso II/II+", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG)
+    PROD("Picasso II/II+ (Segmented Mode)", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE)
+    PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1)
+    PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2)
+    PROD("Picasso IV Z2", GFX, VILLAGE_TRONIC_PICASSO_IV_Z2_REG)
+    PROD("Picasso IV Z3", GFX, VILLAGE_TRONIC_PICASSO_IV_Z3)
+    PROD("Ariadne", ETHERNET_PARALLEL, VILLAGE_TRONIC_ARIADNE)
+END
+
+BEGIN_PROD(UTILITIES_UNLIMITED)
+    PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE)
+    PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE2)
 END
 
 BEGIN_PROD(AMITRIX)
-   PROD("Multi-IO", AMITRIX_MULTI_IO)
-   PROD("CD-RAM Memory", AMITRIX_CD_RAM)
+    PROD(NULL, MULTIIO, AMITRIX_MULTI_IO)
+    PROD("CD-RAM", RAM, AMITRIX_CD_RAM)
 END
 
 BEGIN_PROD(ARMAX)
-   PROD("OmniBus Graphics Board", OMNIBUS)
+    PROD("OmniBus", GFX, ARMAX_OMNIBUS)
 END
 
 BEGIN_PROD(NEWTEK)
-   PROD("VideoToaster", VIDEOTOASTER)
+    PROD("VideoToaster", VIDEO, NEWTEK_VIDEOTOASTER)
 END
 
-BEGIN_PROD(MTEC)
-   PROD("AT500 IDE Controller", AT500)
-   PROD("68030 Turbo Board", MTEC_68030)
-   PROD("68020i Turbo Board", MTEC_68020I)
-   PROD("A1200 T68030/42 RTC Turbo Board", MTEC_T1230)
-   PROD("8MB RAM", MTEC_RAM)
+BEGIN_PROD(M_TECH_GERMANY)
+    PROD("AT500", IDE, MTEC_AT500_2)
+    PROD("68030", TURBO, MTEC_68030)
+    PROD("68020i", TURBO, MTEC_68020I)
+    PROD("A1200 T68030 RTC", TURBO, MTEC_A1200_T68030_RTC)
+    PROD("Viper Mk V/E-Matrix 530", TURBO_RAM, MTEC_VIPER_MK_V_E_MATRIX_530)
+    PROD("8MB", RAM, MTEC_8_MB_RAM)
+    PROD("Viper Mk V/E-Matrix 530 SCSI/IDE", SCSI_IDE, MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE)
 END
 
-BEGIN_PROD(GVP2)
-   PROD("EGS 28/24 Spectrum Graphics Board (RAM)", SPECTRUM_RAM)
-   PROD("EGS 28/24 Spectrum Graphics Board (REG)", SPECTRUM_REG)
+BEGIN_PROD(GREAT_VALLEY_PRODUCTS_4)
+    PROD("EGS 28/24 Spectrum", GFX, GVP_EGS_28_24_SPECTRUM_REG)
+    PROD("EGS 28/24 Spectrum", GFXRAM, GVP_EGS_28_24_SPECTRUM_RAM)
 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("VideoCruncher", VIDEOCRUNCHER)
-   PROD("SD64 Graphics Board (RAM)", SD64_RAM)
-   PROD("SD64 Graphics Board (REG)", SD64_REG)
+BEGIN_PROD(APOLLO_1)
+    PROD("A1200", FPU_RAM, APOLLO_A1200)
 END
 
-BEGIN_PROD(MACROSYSTEMS)
-   PROD("Warp Engine 40xx SCSI Controller", WARP_ENGINE)
+BEGIN_PROD(HELFRICH_2)
+    PROD("Piccolo", GFXRAM, HELFRICH_PICCOLO_RAM)
+    PROD("Piccolo", GFX, HELFRICH_PICCOLO_REG)
+    PROD("PeggyPlus MPEG", VIDEO, HELFRICH_PEGGY_PLUS_MPEG)
+    PROD("VideoCruncher", VIDEO, HELFRICH_VIDEOCRUNCHER)
+    PROD("Piccolo SD64", GFXRAM, HELFRICH_SD64_RAM)
+    PROD("Piccolo SD64", GFX, HELFRICH_SD64_REG)
 END
 
-BEGIN_PROD(ELBOX)
-   PROD("Elbox 1200/4 RAM", ELBOX_1200)
+BEGIN_PROD(MACROSYSTEMS_USA)
+    PROD("Warp Engine 40xx", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE_40xx)
 END
 
-BEGIN_PROD(HARMS_PROF)
-   PROD("030 plus", HARMS_030_PLUS)
-   PROD("3500 Turbo board", 3500_TURBO)
+BEGIN_PROD(ELBOX_COMPUTER)
+    PROD("1200/4", RAM, ELBOX_COMPUTER_1200_4)
+END
+
+BEGIN_PROD(HARMS_PROFESSIONAL)
+    PROD("030 Plus", TURBO, HARMS_PROFESSIONAL_030_PLUS)
+    PROD("3500 Professional", TURBO_RAM, HARMS_PROFESSIONAL_3500)
 END
 
 BEGIN_PROD(MICRONIK)
-   PROD("RCA 120 RAM", RCA_120)
+    PROD("RCA 120", RAM, MICRONIK_RCA_120)
+END
+
+BEGIN_PROD(MICRONIK2)
+    PROD("Z3i A1200 Zorro III + SCSI", SCSI, MICRONIK2_Z3I)
 END
 
-BEGIN_PROD(MEGA_MICRO)
-   PROD("SCRAM 500 SCSI Controller", SCRAM_500_SCSI)
-   PROD("SCRAM 500 RAM", SCRAM_500_RAM)
+BEGIN_PROD(MEGAMICRO)
+    PROD("SCRAM 500", SCSI, MEGAMICRO_SCRAM_500)
+    PROD("SCRAM 500", RAM, MEGAMICRO_SCRAM_500_RAM)
 END
 
-BEGIN_PROD(IMTRONICS2)
-   PROD("Hurricane 2800 68030", HURRICANE_2800_3)
-   PROD("Hurricane 2800 68030", HURRICANE_2800_4)
+BEGIN_PROD(IMTRONICS_2)
+    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_3)
+    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_4)
 END
 
-BEGIN_PROD(KUPKE3)
-   PROD("Golem HD 3000", GOLEM_3000)
+BEGIN_PROD(INDIVIDUAL_COMPUTERS)
+    PROD("Buddha", IDE, INDIVIDUAL_COMPUTERS_BUDDHA)
+    PROD("Catweasel", IDE_FLOPPY, INDIVIDUAL_COMPUTERS_CATWEASEL)
+END
+
+BEGIN_PROD(KUPKE_3)
+    PROD("Golem HD 3000", HD, KUPKE_GOLEM_HD_3000)
 END
 
 BEGIN_PROD(ITH)
-   PROD("ISDN-Master II", ISDN_MASTER_II)
+    PROD("ISDN-Master II", ISDN, ITH_ISDN_MASTER_II)
 END
 
 BEGIN_PROD(VMC)
-   PROD("ISDN Blaster Z2", ISDN_BLASTER_Z2)
-   PROD("HyperCom 4", HYPERCOM_4)
+    PROD("ISDN Blaster Z2", ISDN, VMC_ISDN_BLASTER_Z2)
+    PROD("HyperCom 4", MULTIIO, VMC_HYPERCOM_4)
 END
 
 BEGIN_PROD(INFORMATION)
-   PROD("ISDN Engine I", ISDN_ENGINE_I)
+    PROD("ISDN Engine I", ISDN, INFORMATION_ISDN_ENGINE_I)
 END
 
 BEGIN_PROD(VORTEX)
-   PROD("Golden Gate 80386SX Board", GOLDEN_GATE_386SX)
-   PROD("Golden Gate RAM", GOLDEN_GATE_RAM)
-   PROD("Golden Gate 80486 Board", GOLDEN_GATE_486)
+    PROD("Golden Gate 80386SX", BRIDGE, VORTEX_GOLDEN_GATE_80386SX)
+    PROD("Golden Gate", RAM, VORTEX_GOLDEN_GATE_RAM)
+    PROD("Golden Gate 80486", BRIDGE, VORTEX_GOLDEN_GATE_80486)
 END
 
-BEGIN_PROD(DATAFLYER)
-   PROD("4000SX SCSI Controller", DATAFLYER_4000SXS)
-   PROD("4000SX RAM", DATAFLYER_4000SXR)
+BEGIN_PROD(EXPANSION_SYSTEMS)
+    PROD("DataFlyer 4000SX", SCSI, EXPANSION_SYSTEMS_DATAFLYER_4000SX)
+    PROD("DataFlyer 4000SX", RAM, EXPANSION_SYSTEMS_DATAFLYER_4000SX_RAM)
 END
 
 BEGIN_PROD(READYSOFT)
-   PROD("AMax II/IV", AMAX)
+    PROD("AMax II/IV", MACEMU, READYSOFT_AMAX_II_IV)
 END
 
 BEGIN_PROD(PHASE5)
-   PROD("Blizzard RAM", BLIZZARD_RAM)
-   PROD("Blizzard", BLIZZARD)
-   PROD("Blizzard 1220-IV Turbo Board", BLIZZARD_1220_IV)
-   PROD("FastLane RAM", FASTLANE_RAM)
-   PROD("FastLane/Blizzard 1230-II/CyberSCSI", FASTLANE_SCSI)
-   PROD("Blizzard 1220/CyberStorm", CYBERSTORM_SCSI)
-   PROD("Blizzard 1230-III Turbo Board", BLIZZARD_1230_III)
-   PROD("Blizzard 1230-IV/1260 Turbo Board", BLIZZARD_1230_IV)
-   PROD("Blizzard 2060 SCSI Controller", BLIZZARD_2060SCSI)
-   PROD("CyberStorm Mk II", CYBERSTORM_II)
-   PROD("CyberVision64 Graphics Board", CYBERVISION)
-   PROD("CyberVision64-3D Graphics Board Prototype)", CYBERVISION3D_PRT)
-   PROD("CyberVision64-3D Graphics Board", CYBERVISION3D)
+    PROD("Blizzard", RAM, PHASE5_BLIZZARD_RAM)
+    PROD("Blizzard", TURBO, PHASE5_BLIZZARD)
+    PROD("Blizzard 1220-IV", TURBO, PHASE5_BLIZZARD_1220_IV)
+    PROD("FastLane Z3", RAM, PHASE5_FASTLANE_Z3_RAM)
+    PROD("Blizzard 1230-II/Fastlane Z3/CyberSCSI/CyberStorm060", TURBO_SCSI, PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060)
+    PROD("Blizzard 1220/CyberStorm", TURBO_SCSI, PHASE5_BLIZZARD_1220_CYBERSTORM)
+    PROD("Blizzard 1230", TURBO, PHASE5_BLIZZARD_1230)
+    PROD("Blizzard 1230-IV/1260", TURBO, PHASE5_BLIZZARD_1230_IV_1260)
+    PROD("Blizzard 2060", TURBO, PHASE5_BLIZZARD_2060)
+    PROD("CyberStorm Mk II", FLASHROM, PHASE5_CYBERSTORM_MK_II)
+    PROD("CyberVision64", GFX, PHASE5_CYBERVISION64)
+    PROD("CyberVision64-3D Prototype", GFX, PHASE5_CYBERVISION64_3D_PROTOTYPE)
+    PROD("CyberVision64-3D", GFX, PHASE5_CYBERVISION64_3D)
+    PROD("CyberStorm Mk III", TURBO_SCSI, PHASE5_CYBERSTORM_MK_III)
 END
 
 BEGIN_PROD(DPS)
-   PROD("Personal Animation Recorder", DPS_PAR)
+    PROD("Personal Animation Recorder", VIDEO, DPS_PERSONAL_ANIMATION_RECORDER)
 END
 
-BEGIN_PROD(APOLLO2)
-   PROD("A620 68020 Accelerator", A620)
-   PROD("A620 68020 Accelerator", A620_2)
+BEGIN_PROD(APOLLO_2)
+    PROD("A620 68020", TURBO, APOLLO_A620_68020_1)
+    PROD("A620 68020", TURBO, APOLLO_A620_68020_2)
 END
 
-BEGIN_PROD(APOLLO)
-   PROD("AT-Apollo", AT_APOLLO)
-   PROD("Turbo Board", APOLLO_TURBO)
+BEGIN_PROD(APOLLO_3)
+    PROD("AT-Apollo", UNKNOWN, APOLLO_AT_APOLLO)
+    PROD("1230/1240/1260/2030/4040/4060", TURBO, APOLLO_1230_1240_1260_2030_4040_4060)
 END
 
-BEGIN_PROD(PETSOFF)
-   PROD("Delfina DSP", DELFINA)
+BEGIN_PROD(PETSOFF_LP)
+    PROD("Delfina", DSP, PETSOFF_LP_DELFINA)
 END
 
 BEGIN_PROD(UWE_GERLACH)
-   PROD("RAM/ROM", UG_RAM_ROM)
+    PROD("RAM/ROM", MISC, UWE_GERLACH_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("Toccata Sound Board", TOCCATA)
-   PROD("Retina Z3 Graphics Board", RETINA_Z3)
-   PROD("VLab Motion", VLAB_MOTION)
-   PROD("Altais Graphics Board", ALTAIS)
-   PROD("Falcon '040 Turbo Board", FALCON_040)
+BEGIN_PROD(MACROSYSTEMS_GERMANY)
+    PROD("Maestro", AUDIO, MACROSYSTEMS_MAESTRO)
+    PROD("VLab", VIDEO, MACROSYSTEMS_VLAB)
+    PROD("Maestro Pro", AUDIO, MACROSYSTEMS_MAESTRO_PRO)
+    PROD("Retina", GFX, MACROSYSTEMS_RETINA)
+    PROD("MultiEvolution", SCSI, MACROSYSTEMS_MULTI_EVOLUTION)
+    PROD("Toccata", AUDIO, MACROSYSTEMS_TOCCATA)
+    PROD("Retina Z3", GFX, MACROSYSTEMS_RETINA_Z3)
+    PROD("VLab Motion", VIDEO, MACROSYSTEMS_VLAB_MOTION)
+    PROD("Altais", GFX, MACROSYSTEMS_ALTAIS)
+    PROD("Falcon '040", TURBO, MACROSYSTEMS_FALCON_040)
 END
 
 BEGIN_PROD(COMBITEC)
 END
 
-BEGIN_PROD(SKI)
-   PROD("MAST Fireball SCSI Controller", MAST_FIREBALL)
-   PROD("SCSI / Dual Serial", SKI_SCSI_SERIAL)
+BEGIN_PROD(SKI_PERIPHERALS)
+    PROD("MAST Fireball", SCSI, SKI_PERIPHERALS_MAST_FIREBALL)
+    PROD("SCSI/Dual Serial", SCSI_SERIAL, SKI_PERIPHERALS_SCSI_DUAL_SERIAL)
+END
+
+BEGIN_PROD(REIS_WARE_2)
+    PROD("Scan King", SCANNER, REIS_WARE_SCAN_KING)
 END
 
 BEGIN_PROD(CAMERON)
-   PROD("Personal A4", PERSONAL_A4)
+    PROD("Personal A4", SCANNER, CAMERON_PERSONAL_A4)
 END
 
 BEGIN_PROD(REIS_WARE)
-   PROD("Handyscanner", RW_HANDYSCANNER)
+    PROD("Handyscanner", SCANNER, REIS_WARE_HANDYSCANNER)
 END
 
+BEGIN_PROD(PHOENIX_2)
+    PROD("ST506", HD, PHOENIX_ST506_2)
+    PROD(NULL, SCSI, PHOENIX_SCSI_2)
+    PROD(NULL, RAM, PHOENIX_RAM_2)
+END
 
-BEGIN_MANUF
-   MANUF("Pacific Peripherals", PACIFIC)
-   MANUF("Kupke", KUPKE)
-   MANUF("Memphis", MEMPHIS)
-   MANUF("3-State", 3_STATE)
-   MANUF("Commodore", COMMODORE2)
-   MANUF("Commodore", COMMODORE)
-   MANUF("Commodore", COMMODORE3)
-   MANUF("Kolff Computer Supplies", KCS)
-   MANUF("Cardco", CARDCO)
-   MANUF("A-Squared", A_SQUARED)
-   MANUF("ComSpec Communications", COMSPEC)
-   MANUF("Anakin", ANAKIN)
-   MANUF("MicroBotics", MICROBOTICS)
-   MANUF("Access Associates", ACCESS)
-   MANUF("Expansion Technologies", EXPANSION_TECH)
-   MANUF("ASDG", ASDG)
-   MANUF("Imtronics", IMTRONICS)
-   MANUF("University of Lowell", UNIV_OF_LOWELL)
-   MANUF("Ameristar", AMERISTAR)
-   MANUF("Supra", SUPRA)
-   MANUF("Computer Systems Ass.", CSA)
-   MANUF("M-Tech", MTEC2)
-   MANUF("Great Valley Products", GVP3)
-   MANUF("ByteBox", BYTEBOX)
-   MANUF("Power Computing", POWER_COMPUTING)
-   MANUF("Great Valley Products", GVP)
-   MANUF("Synergy", SYNERGY)
-   MANUF("Xetec", XETEC)
-   MANUF("Progressive Peripherals", PPI)
-   MANUF("Xebec", XEBEC)
-   MANUF("Spirit", SPIRIT)
-   MANUF("BSC", BSC)
-   MANUF("BSC", BSC3)
-   MANUF("C Ltd.", C_LTD)
-   MANUF("Jochheim", JOCHHEIM)
-   MANUF("Checkpoint Technologies", CHECKPOINT)
-   MANUF("ICD", ICD)
-   MANUF("Kupke", KUPKE2)
-   MANUF("Great Valley Products", GVP4)
-   MANUF("Interworks Network", INTERWORKS_NET)
-   MANUF("Hardital Synthesis", HARDITAL)
-   MANUF("BSC", BSC2)
-   MANUF("Advanced Systems & Software", ADV_SYS_SOFT)
-   MANUF("Impulse", IMPULSE)
-   MANUF("IVS", IVS)
-   MANUF("Vector", VECTOR)
-   MANUF("XPert/ProDev", XPERT_PRODEV)
-   MANUF("Hydra Systems", HYDRA_SYSTEMS)
-   MANUF("Sunrize Industries", SUNRIZE)
-   MANUF("Triceratops", TRICERATOPS)
-   MANUF("Applied Magic", APPLIED_MAGIC)
-   MANUF("GFX-Base", GFX_BASE)
-   MANUF("RocTec", ROCTEC)
-   MANUF("Helfrich", HELFRICH1)
-   MANUF("Software Result Enterprises", SW_RESULT_ENTS)
-   MANUF("Masoboshi", MASOBOSHI)
-   MANUF("Village Tronic", VILLAGE_TRONIC)
-   MANUF("Utilities Unlimited", UTILITIES_ULTD)
-   MANUF("Amitrix", AMITRIX)
-   MANUF("ArMax", ARMAX)
-   MANUF("NewTek", NEWTEK)
-   MANUF("M-Tech", MTEC)
-   MANUF("Great Valley Products", GVP2)
-   MANUF("Helfrich", HELFRICH2)
-   MANUF("MacroSystems", MACROSYSTEMS)
-   MANUF("ElBox Computer", ELBOX)
-   MANUF("Harms Professional", HARMS_PROF)
-   MANUF("Micronik", MICRONIK)
-   MANUF("MegaMicro", MEGA_MICRO)
-   MANUF("Imtronics", IMTRONICS2)
-   MANUF("Kupke", KUPKE3)
-   MANUF("ITH", ITH)
-   MANUF("VMC", VMC)
-   MANUF("Information", INFORMATION)
-   MANUF("Vortex", VORTEX)
-   MANUF("DataFlyer", DATAFLYER)
-   MANUF("ReadySoft", READYSOFT)
-   MANUF("Phase5", PHASE5)
-   MANUF("DPS", DPS)
-   MANUF("Apollo", APOLLO2)
-   MANUF("Apollo", APOLLO)
-   MANUF("Petsoff LP", PETSOFF)
-   MANUF("Uwe Gerlach", UWE_GERLACH)
-   MANUF("MacroSystems", MACROSYSTEMS2)
-   MANUF("Combitec", COMBITEC)
-   MANUF("SKI Peripherals", SKI)
-   MANUF("Cameron", CAMERON)
-   MANUF("Reis-Ware", REIS_WARE)
+BEGIN_PROD(COMBITEC_2)
+    PROD(NULL, HD, COMBITEC_HD)
+    PROD("SRAM", RAM, COMBITEC_SRAM)
 END
 
-#define NUM_MANUF (sizeof(Manufacturers)/sizeof(struct Manufacturer))
-#define NUM_GVP_PROD (sizeof(Ext_Prod_GVP)/sizeof(struct GVP_Product))
+BEGIN_PROD(HACKER)	/* Unused */
+END
+
+
+BEGIN_MANUF
+    MANUF("Pacific Peripherals", PACIFIC_PERIPHERALS)
+    MANUF("MacroSystems USA", MACROSYSTEMS_USA_2)
+    MANUF("Kupke", KUPKE_1)
+    MANUF("Memphis", MEMPHIS)
+    MANUF("3-State", 3_STATE)
+    MANUF("Commodore Braunschweig", COMMODORE_BRAUNSCHWEIG)
+    MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_1)
+    MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_2)
+    MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2)
+    MANUF("Kolff Computer Supplies", KOLFF_COMPUTER_SUPPLIES)
+    MANUF("Cardco Ltd.", CARDCO_1)
+    MANUF("A-Squared", A_SQUARED)
+    MANUF("Comspec Communications", COMSPEC_COMMUNICATIONS)
+    MANUF("Anakin Research", ANAKIN_RESEARCH)
+    MANUF("Microbotics", MICROBOTICS)
+    MANUF("Access Associates Alegra", ACCESS_ASSOCIATES_ALEGRA)
+    MANUF("Expansion Technologies (Pacific Cypress)", EXPANSION_TECHNOLOGIES)
+    MANUF("ASDG", ASDG)
+    MANUF("Ronin/Imtronics", IMTRONICS_1)
+    MANUF("Commodore/University of Lowell", CBM_UNIVERSITY_OF_LOWELL)
+    MANUF("Ameristar", AMERISTAR)
+    MANUF("Supra", SUPRA)
+    MANUF("Computer Systems Assosiates", COMPUTER_SYSTEMS_ASSOCIATES)
+    MANUF("Marc Michael Groth", MARC_MICHAEL_GROTH)
+    MANUF("M-Tech", M_TECH)
+    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_1)
+    MANUF("ByteBox", BYTEBOX)
+    MANUF("DKB/Power Computing", DKB_POWER_COMPUTING)
+    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_2)
+    MANUF("California Access (Synergy)", CALIFORNIA_ACCESS_SYNERGY)
+    MANUF("Xetec", XETEC)
+    MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS)
+    MANUF("Xebec", XEBEC)
+    MANUF("Spirit Technology", SPIRIT_TECHNOLOGY)
+    MANUF("Spirit Technology", SPIRIT_TECHNOLOGY_2)
+    MANUF("BSC/Alfadata", BSC_ALFADATA_1)
+    MANUF("BSC/Alfadata", BSC_ALFADATA_2)
+    MANUF("Cardco Ltd.", CARDCO_2)
+    MANUF("Jochheim", JOCHHEIM)
+    MANUF("Checkpoint Technologies", CHECKPOINT_TECHNOLOGIES)
+    MANUF("Edotronik", EDOTRONIK)
+    MANUF("NES Inc.", NES_INC)
+    MANUF("ICD", ICD)
+    MANUF("Kupke", KUPKE_2)
+    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_3)
+    MANUF("Interworks Network", INTERWORKS_NETWORK)
+    MANUF("Hardital Synthesis", HARDITAL_SYNTHESIS)
+    MANUF("Applied Engineering", APPLIED_ENGINEERING)
+    MANUF("BSC/Alfadata", BSC_ALFADATA_3)
+    MANUF("Phoenix", PHOENIX)
+    MANUF("Advanced Storage Systems", ADVANCED_STORAGE_SYSTEMS)
+    MANUF("Impulse", IMPULSE)
+    MANUF("IVS", IVS)
+    MANUF("Vector", VECTOR_1)
+    MANUF("XPert ProDev", XPERT_PRODEV)
+    MANUF("Hydra Systems", HYDRA_SYSTEMS)
+    MANUF("Sunrize Industries", SUNRIZE_INDUSTRIES)
+    MANUF("Triceratops", TRICERATOPS)
+    MANUF("Applied Magic Inc.", APPLIED_MAGIC)
+    MANUF("GFX-Base", GFX_BASE)
+    MANUF("RocTec", ROCTEC)
+    MANUF("Kato", KATO)
+    MANUF("Atlantis", ATLANTIS)
+    MANUF("Protar", PROTAR)
+    MANUF("ACS", ACS)
+    MANUF("Software Results Enterprises", SOFTWARE_RESULTS_ENTERPRISES)
+    MANUF("Masoboshi", MASOBOSHI)
+    MANUF("Mainhattan-Data (A-Team)", MAINHATTAN_DATA)
+    MANUF("Village Tronic", VILLAGE_TRONIC)
+    MANUF("Utilities Unlimited", UTILITIES_UNLIMITED)
+    MANUF("Amitrix", AMITRIX)
+    MANUF("ArMax", ARMAX)
+    MANUF("NewTek", NEWTEK)
+    MANUF("M-Tech Germany", M_TECH_GERMANY)
+    MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_4)
+    MANUF("Apollo", APOLLO_1)
+    MANUF("Ingenieurbüro Helfrich", HELFRICH_2)
+    MANUF("MacroSystems USA", MACROSYSTEMS_USA)
+    MANUF("ElBox Computer", ELBOX_COMPUTER)
+    MANUF("Harms Professional", HARMS_PROFESSIONAL)
+    MANUF("Micronik", MICRONIK)
+    MANUF("Micronik", MICRONIK2)
+    MANUF("MegaMicro", MEGAMICRO)
+    MANUF("Ronin/Imtronics", IMTRONICS_2)
+    MANUF("Individual Computers", INDIVIDUAL_COMPUTERS)
+    MANUF("Kupke", KUPKE_3)
+    MANUF("ITH", ITH)
+    MANUF("VMC", VMC)
+    MANUF("Information", INFORMATION)
+    MANUF("Vortex", VORTEX)
+    MANUF("Expansion Systems", EXPANSION_SYSTEMS)
+    MANUF("ReadySoft", READYSOFT)
+    MANUF("Phase 5", PHASE5)
+    MANUF("DPS", DPS)
+    MANUF("Apollo", APOLLO_2)
+    MANUF("Apollo", APOLLO_3)
+    MANUF("Petsoff LP", PETSOFF_LP)
+    MANUF("Uwe Gerlach", UWE_GERLACH)
+    MANUF("MacroSystems Germany", MACROSYSTEMS_GERMANY)
+    MANUF("Combitec", COMBITEC)
+    MANUF("SKI Peripherals", SKI_PERIPHERALS)
+    MANUF("Reis-Ware", REIS_WARE_2)
+    MANUF("Cameron", CAMERON)
+    MANUF("Reis-Ware", REIS_WARE)
+    MANUF("Hacker Test Board", HACKER)	/* Unused */
+    MANUF("Phoenix", PHOENIX_2)
+    MANUF("Combitec", COMBITEC_2)
+END
+
+#define NUM_MANUF		(ARRAYSIZE(Manufacturers))
+#define NUM_GVP_PROD		(ARRAYSIZE(Ext_Prod_GVP))
+
+
+    /*
+     *  Zorro product classes
+     *
+     *  Make sure to keep these in sync with include/linux/zorro.h!
+     */
+
+static const char *classnames[] = {
+    NULL,				    /* ZORRO_CLASS_UNKNOWN */
+    "ArcNet Card",			    /* ZORRO_CLASS_ARCNET */
+    "Audio Board",			    /* ZORRO_CLASS_AUDIO */
+    "ISA Bus Bridge",			    /* ZORRO_CLASS_BRIDGE */
+    "DSP Board",			    /* ZORRO_CLASS_DSP */
+    "Ethernet Card",			    /* ZORRO_CLASS_ETHERNET */
+    "Ethernet Card and Parallel Ports",	    /* ZORRO_CLASS_ETHERNET_PARALLEL */
+    "Flash ROM",			    /* ZORRO_CLASS_FLASHROM */
+    "FPU and RAM Expansion",		    /* ZORRO_CLASS_FPU_RAM */
+    "Graphics Board",			    /* ZORRO_CLASS_GFX */
+    "Graphics Board (RAM)",		    /* ZORRO_CLASS_GFXRAM */
+    "HD Controller",			    /* ZORRO_CLASS_HD */
+    "HD Controller and RAM Expansion",	    /* ZORRO_CLASS_HD_RAM */
+    "IDE Interface",			    /* ZORRO_CLASS_IDE */
+    "IDE Interface and RAM Expansion",	    /* ZORRO_CLASS_IDE_RAM */
+    "IDE Interface and Floppy Controller",  /* ZORRO_CLASS_IDE_FLOPPY */
+    "ISDN Interface",			    /* ZORRO_CLASS_ISDN */
+    "Macintosh Emulator",		    /* ZORRO_CLASS_MACEMU */
+    "Miscellaneous Expansion Card",	    /* ZORRO_CLASS_MISC */
+    "Modem",				    /* ZORRO_CLASS_MODEM */
+    "Multi I/O",			    /* ZORRO_CLASS_MULTIIO */
+    "RAM Expansion",			    /* ZORRO_CLASS_RAM */
+    "Scanner Interface",		    /* ZORRO_CLASS_SCANNER */
+    "SCSI Host Adapter",		    /* ZORRO_CLASS_SCSI */
+    "SCSI Host Adapter and IDE Interface",  /* ZORRO_CLASS_SCSI_IDE */
+    "SCSI Host Adapter and RAM Expansion",  /* ZORRO_CLASS_SCSI_RAM */
+    "SCSI Host Adapter and Serial Card",    /* ZORRO_CLASS_SCSI_SERIAL */
+    "Multi Serial",			    /* ZORRO_CLASS_SERIAL */
+    "Drawing Tablet Interface",		    /* ZORRO_CLASS_TABLET */
+    "Accelerator",			    /* ZORRO_CLASS_TURBO */
+    "Accelerator and RAM Expansion",	    /* ZORRO_CLASS_TURBO_RAM */
+    "Accelerator and HD Controller",	    /* ZORRO_CLASS_TURBO_HD */
+    "Accelerator and IDE Interface",	    /* ZORRO_CLASS_TURBO_IDE */
+    "Accelerator and SCSI Host Adapter",    /* ZORRO_CLASS_TURBO_SCSI */
+    "Accelerator, SCSI Host Adapter and RAM Expansion",    /* ZORRO_CLASS_TURBO_SCSI */
+    "Video Board",			    /* ZORRO_CLASS_VIDEO */
+};
+
+static inline const char *get_class_name(enum Zorro_Classes class)
+{
+    if (class < ARRAYSIZE(classnames))
+	return(classnames[class]);
+    else
+	return("(**Illegal**)");
+}
 
 #endif /* CONFIG_ZORRO */
 
 
-   /*
-    *    Expansion Devices
-    */
+    /*
+     *  Expansion Devices
+     */
 
-int zorro_num_autocon;
+u_int zorro_num_autocon;
 struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO];
-static u_long BoardPartFlags[ZORRO_NUM_AUTO] = { 0, };
+static u32 BoardPartFlags[ZORRO_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);
-    *       }
-    */
+    /*
+     *  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 which use the same
+     *  method as GVP. Drivers for boards which are not using this
+     *  method do not need to think of this - just set index = 0.
+     *
+     *  Example:
+     *
+     *      while ((key = zorro_find(ZORRO_PROD_MY_BOARD, 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)
+u_int zorro_find(zorro_id id, u_int part, u_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 <= zorro_num_autocon; key++) {
-      cd = &zorro_autocon[key-1];
-      if ((cd->cd_Rom.er_Manufacturer == manuf) &&
-          (cd->cd_Rom.er_Product == prod) &&
-          !(BoardPartFlags[key-1] & (1<<part)))
-         break;
-   }
-   return(key <= zorro_num_autocon ? key : 0);
+    u_int manuf = ZORRO_MANUF(id);
+    u_int prod = ZORRO_PROD(id);
+    u_int epc = ZORRO_EPC(id);
+    u_int key;
+    const struct ConfigDev *cd;
+    u_long addr;
+
+    if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
+	return(0);
+
+    if (part > 31) {
+	printk("zorro_find: bad part %d\n", part);
+	return(0);
+    }
+
+    for (key = index + 1; key <= zorro_num_autocon; key++) {
+	cd = &zorro_autocon[key-1];
+	addr = (u_long)cd->cd_BoardAddr;
+	if ((cd->cd_Rom.er_Manufacturer == manuf) &&
+	    (cd->cd_Rom.er_Product == prod) &&
+	    !(BoardPartFlags[key-1] & (1<<part)) &&
+	    (manuf != ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) ||
+	     prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE) ||
+	     (*(u_short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK) == epc))
+	    break;
+    }
+    return(key <= zorro_num_autocon ? key : 0);
 }
 
 
-   /*
-    *    Get the board for a specified key
-    */
+    /*
+     *  Get the board corresponding to a specific key
+     */
 
-struct ConfigDev *zorro_get_board(int key)
+const struct ConfigDev *zorro_get_board(u_int key)
 {
-   struct ConfigDev *cd = NULL;
+    const struct ConfigDev *cd = NULL;
 
-   if ((key < 1) || (key > zorro_num_autocon))
-      printk("zorro_get_board: bad key %d\n", key);
-   else
-      cd = &zorro_autocon[key-1];
+    if ((key < 1) || (key > zorro_num_autocon))
+	printk("zorro_get_board: bad key %d\n", key);
+    else
+	cd = &zorro_autocon[key-1];
 
-   return(cd);
+    return(cd);
 }
 
 
-   /*
-    *    Mark a part of a board as configured
-    */
+    /*
+     *  Mark a part of a board as configured
+     */
 
-void zorro_config_board(int key, int part)
+void zorro_config_board(u_int key, u_int part)
 {
-   if ((key < 1) || (key > zorro_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;
+    if ((key < 1) || (key > zorro_num_autocon))
+	printk("zorro_config_board: bad key %d\n", key);
+    else if (part > 31)
+	printk("zorro_config_board: bad part %d\n", part);
+    else if (BoardPartFlags[key-1] & (1<<part))
+	printk("zorro_config_board: key %d part %d is already configured\n",
+	       key, 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
-    */
+    /*
+     *  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)
+void zorro_unconfig_board(u_int key, u_int part)
 {
-   if ((key < 1) || (key > zorro_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);
+    if ((key < 1) || (key > zorro_num_autocon))
+	printk("zorro_unconfig_board: bad key %d\n", key);
+    else if (part > 31)
+	printk("zorro_unconfig_board: bad part %d\n", part);
+    else if (!(BoardPartFlags[key-1] & (1<<part)))
+	printk("zorro_config_board: key %d part %d is not yet configured\n",
+	       key, 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).
-    */
+    /*
+     *  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)
+static int identify(u_int devnum, char *buf, int verbose)
 {
-   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 = &zorro_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 {
-		       /*
-			* The epc must be read as a short from the
-			* hardware.
-			*/
-                  epc = *(unsigned short *)ZTWO_VADDR(addr+0x8000) &
-                        GVP_PRODMASK;
-                  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);
+    const struct ConfigDev *cd = &zorro_autocon[devnum];
+    u32 configured = BoardPartFlags[devnum];
+    u_int manuf = cd->cd_Rom.er_Manufacturer;
+    u_int prod = cd->cd_Rom.er_Product;
+    u_int class = ZORRO_CLASS_UNKNOWN;
+    u_int epc = 0;
+    const char *manufname = "Unknown";
+    const char *prodname = "Unknown";
+    const char *classname;
+    u_int i, j, k, len = 0;
+    u_long addr = (u_long)cd->cd_BoardAddr;
+    u_long size = cd->cd_BoardSize;
+    char mag;
+    int identified = 0, gvp = 0;
+
+    if (manuf != ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) ||
+	prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE)) {
+	for (i = 0; i < NUM_MANUF; i++)
+	    if (Manufacturers[i].Manuf == manuf) {
+		manufname = Manufacturers[i].Name;
+		for (j = 0; j < Manufacturers[i].NumProd; j++)
+		    if (Manufacturers[i].Products[j].Prod == prod) {
+			prodname = Manufacturers[i].Products[j].Name;
+			class = Manufacturers[i].Products[j].Class;
+			identified = 1;
+			break;
+		    }
+	    }
+	/* Put workarounds for ID clashes here */
+	if (manuf == ZORRO_MANUF(ZORRO_PROD_HELFRICH_RAINBOW_III) &&
+	    prod == ZORRO_PROD(ZORRO_PROD_HELFRICH_RAINBOW_III))
+	    manufname = "Ingenieurbüro Helfrich";
+    } else {
+	manufname = "Great Valley Products";
+	gvp = 1;
+	epc = *(u_short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK;
+	for (k = 0; k < NUM_GVP_PROD; k++)
+	    if (epc == Ext_Prod_GVP[k].EPC) {
+		prodname = Ext_Prod_GVP[k].Name;
+		class = Ext_Prod_GVP[k].Class;
+		identified = 1;
+		break;
+	    }
+    }
+    classname = get_class_name(class);
+    if (size & 0xfffff) {
+	size >>= 10;
+	mag = 'K';
+    } else {
+	size >>= 20;
+	mag = 'M';
+    }
+    if (verbose) {
+	const char *zorro;
+	int is_mem = cd->cd_Rom.er_Type & ERTF_MEMLIST;
+	switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) {
+	    case ERT_ZORROII:
+		zorro = "Zorro II";
+		break;
+	    case ERT_ZORROIII:
+		zorro = "Zorro III";
+		break;
+	    default:
+		zorro = "Unknown Zorro";
+		break;
+	}
+	if (!prodname)
+	    prodname = "Unknown";
+	if (!classname)
+	    classname = "Unknown";
+	len = sprintf(buf, "  Device %d at 0x%08lx: ID=%04x:%02x", devnum,
+		      addr, manuf, prod);
+	if (gvp)
+	    len += sprintf(buf+len, ":%02x", epc);
+	len += sprintf(buf+len, ", %s, %ld%c", zorro, size, mag);
+	if (is_mem)
+	    len += sprintf(buf+len, ", System RAM");
+	else
+	    len += sprintf(buf+len, ", Configured=%08x", configured);
+	len += sprintf(buf+len, "\n"
+				"    Manufacturer: %s\n"
+				"    Product Name: %s\n"
+				"    Board Class : %s\n",
+				manufname, prodname, classname);
+    } else {
+	len = sprintf(buf, " %c%08lx: ", configured ? '*' : ' ', addr);
+	if (identified) {
+	    len += sprintf(buf+len, "%s", manufname);
+	    if (prodname)
+		len += sprintf(buf+len, " %s", prodname);
+	    if (classname)
+		len += sprintf(buf+len, " %s", classname);
+	} else if (manuf == ZORRO_MANUF_HACKER)
+	    len += sprintf(buf+len, "Hacker Test Board %02x", prod);
+	else if (gvp)
+	    len += sprintf(buf+len, "[%04x:%02x:%02x] made by %s", manuf, prod,
+			   epc, manufname);
+	else
+	    len += sprintf(buf+len, "[%04x:%02x] made by %s", manuf, prod,
+			   manufname);
+	len += sprintf(buf+len, " (%ld%c)\n", size, mag);
+	if (!identified && manuf != ZORRO_MANUF_HACKER)
+	    len += sprintf(buf+len, "    Please report this unknown device to "
+				    "zorro@linux-m68k.org\n");
+    }
+    return(len);
 }
 
 
-   /*
-    *    Identify all known AutoConfig Expansion Devices
-    */
+    /*
+     *  Identify all known AutoConfig Expansion Devices
+     */
 
 void zorro_identify(void)
 {
-   int i;
-   char tmp[160];
+    u_int i;
+    char tmp[256];
 
-   if (!AMIGAHW_PRESENT(ZORRO))
-      return;
+    if (!AMIGAHW_PRESENT(ZORRO))
+	return;
 
-   printk("Probing AutoConfig expansion device(s):\n");
-   for (i = 0; i < zorro_num_autocon; i++) {
-      identify(i, tmp);
-      printk(tmp);
-   }
-   if (!zorro_num_autocon)
-      printk("No AutoConfig expansion devices present.\n");
+    printk("Probing AutoConfig expansion device(s):\n");
+    for (i = 0; i < zorro_num_autocon; i++) {
+	identify(i, tmp, 0);
+	printk(tmp);
+    }
+    if (!zorro_num_autocon)
+	printk("No AutoConfig expansion devices present.\n");
 }
 
 
-   /*
-    *    Get the list of all AutoConfig Expansion Devices
-    */
+    /*
+     *  Get the list of all AutoConfig Expansion Devices
+     */
 
 int zorro_get_list(char *buffer)
 {
-   int i, j, len = 0;
-   char tmp[160];
+    u_int i, len = 0, len2;
+    char tmp[256];
 
-   if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
-      len = sprintf(buffer, "AutoConfig expansion devices:\n");
-      for (i = 0; i < zorro_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);
+    if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
+	len = sprintf(buffer, "AutoConfig expansion devices:\n");
+	for (i = 0; i < zorro_num_autocon; i++) {
+	    len2 = identify(i, tmp, 1);
+	    if (len+len2 >= 4075) {
+		len += sprintf(buffer+len, "4K limit reached!\n");
+		break;
+	    }
+	    strcpy(buffer+len, tmp);
+	    len += len2;
+	}
+    }
+    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
-    */
+    /*
+     *  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 };
+u32 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;
+    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;
-   }
+    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
-    */
+    /*
+     *  Initialization
+     */
 
-__initfunc(void zorro_init(void))
+void zorro_init(void)
 {
-   int i;
-   struct ConfigDev *cd;
+    u_int i;
+    const struct ConfigDev *cd;
 
-   if (!AMIGAHW_PRESENT(ZORRO))
-      return;
+    if (!AMIGAHW_PRESENT(ZORRO))
+	return;
 
-   /* Mark all available Zorro II memory */
-   for (i = 0; i < zorro_num_autocon; i++) {
-      cd = &zorro_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 < m68k_num_memory; i++)
-      mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0);
+    /* Mark all available Zorro II memory */
+    for (i = 0; i < zorro_num_autocon; i++) {
+	cd = &zorro_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 < m68k_num_memory; i++)
+	mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0);
 }
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/apollo/Makefile linux/arch/m68k/apollo/Makefile
--- v2.1.86/linux/arch/m68k/apollo/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/apollo/Makefile	Thu Feb 12 16:30:12 1998
@@ -0,0 +1,14 @@
+#
+# 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 := apollo.o
+O_OBJS   := config.o dn_ints.o \
+
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/apollo/config.c linux/arch/m68k/apollo/config.c
--- v2.1.86/linux/arch/m68k/apollo/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/apollo/config.c	Thu Feb 12 16:30:12 1998
@@ -0,0 +1,245 @@
+#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 <asm/setup.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/apollohw.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+
+extern struct consw fb_con;
+extern void dn_sched_init(void (*handler)(int,void *,struct pt_regs *));
+extern int dn_keyb_init(void);
+extern int dn_dummy_kbdrate(struct kbd_repeat *);
+extern void dn_init_IRQ(void);
+#if 0
+extern void (*dn_default_handler[])(int,void *,struct pt_regs *);
+#endif
+extern int dn_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void dn_free_irq(unsigned int irq, void *dev_id);
+extern void dn_enable_irq(unsigned int);
+extern void dn_disable_irq(unsigned int);
+extern int dn_get_irq_list(char *);
+extern unsigned long dn_gettimeoffset(void);
+extern void dn_gettod(int *, int *, int *, int *, int *, int *);
+extern int dn_dummy_hwclk(int, struct hwclk_time *);
+extern int dn_dummy_set_clock_mmss(unsigned long);
+extern void dn_mksound(unsigned int count, unsigned int ticks);
+extern void dn_dummy_reset(void);
+extern void dn_dummy_waitbut(void);
+extern struct fb_info *dn_fb_init(long *);
+extern void dn_dummy_debug_init(void);
+extern void (*kd_mksound)(unsigned int, unsigned int);
+extern void dn_dummy_video_setup(char *,int *);
+extern void dn_process_int(int irq, struct pt_regs *fp);
+
+static struct console dn_console_driver;
+static void dn_debug_init(void);
+static void dn_timer_int(int irq,void *, struct pt_regs *);
+static void (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL;
+
+int dn_serial_console_wait_key(void) {
+
+	while(!(sio01.srb_csrb & 1))
+		barrier();
+	return sio01.rhrb_thrb;
+}
+
+void dn_serial_console_write (const char *str,unsigned int count)
+{
+   while(count--) {
+	if (*str == '\n') { 
+    	sio01.rhrb_thrb = (unsigned char)'\r';
+       	while (!(sio01.srb_csrb & 0x4))
+                ;
+ 	}
+    sio01.rhrb_thrb = (unsigned char)*str++;
+    while (!(sio01.srb_csrb & 0x4))
+            ;
+  }	
+}
+ 
+void dn_serial_print (const char *str)
+{
+    while (*str) {
+        if (*str == '\n') {
+            sio01.rhrb_thrb = (unsigned char)'\r';
+            while (!(sio01.srb_csrb & 0x4))
+                ;
+        }
+        sio01.rhrb_thrb = (unsigned char)*str++;
+        while (!(sio01.srb_csrb & 0x4))
+            ;
+    }
+}
+
+void config_apollo(void) {
+
+	dn_serial_print("Config apollo !\n");
+#if 0
+	dn_debug_init();	
+#endif
+	printk("Config apollo !\n");
+
+
+	mach_sched_init=dn_sched_init; /* */
+	mach_keyb_init=dn_keyb_init;
+	mach_kbdrate=dn_dummy_kbdrate;
+	mach_init_IRQ=dn_init_IRQ;
+	mach_default_handler=NULL;
+	mach_request_irq     = dn_request_irq;
+	mach_free_irq        = dn_free_irq;
+	enable_irq      = dn_enable_irq;
+	disable_irq     = dn_disable_irq;
+	mach_get_irq_list    = dn_get_irq_list;
+	mach_gettimeoffset   = dn_gettimeoffset;
+	mach_gettod	     = dn_gettod; /* */
+	mach_max_dma_address = 0xffffffff;
+	mach_hwclk           = dn_dummy_hwclk; /* */
+	mach_set_clock_mmss  = dn_dummy_set_clock_mmss; /* */
+	mach_process_int     = dn_process_int;
+#ifdef CONFIG_BLK_DEV_FD
+	mach_floppy_init     = dn_dummy_floppy_init;
+	mach_floppy_setup    = dn_dummy_floppy_setup;
+#endif
+	mach_reset	     = dn_dummy_reset;  /* */
+	conswitchp	     = &fb_con;
+#if 0
+	mach_fb_init 	     = dn_fb_init; 
+	mach_video_setup     = dn_dummy_video_setup; 
+#endif
+	kd_mksound	     = dn_mksound;
+
+}		
+
+void dn_timer_int(int irq, void *dev_id, struct pt_regs *fp) {
+
+	volatile unsigned char x;
+
+	sched_timer_handler(irq,dev_id,fp);
+	
+	x=*(volatile unsigned char *)(IO_BASE+0x10803);
+	x=*(volatile unsigned char *)(IO_BASE+0x10805);
+
+}
+
+void dn_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) {
+
+	dn_serial_print("dn sched_init\n");
+
+#if 0
+	/* program timer 2 */
+	*(volatile unsigned char *)(IO_BASE+0x10803)=0x00;
+	*(volatile unsigned char *)(IO_BASE+0x10809)=0;
+	*(volatile unsigned char *)(IO_BASE+0x1080b)=50;
+
+	/* program timer 3 */
+	*(volatile unsigned char *)(IO_BASE+0x10801)=0x00;
+	*(volatile unsigned char *)(IO_BASE+0x1080c)=0;
+	*(volatile unsigned char *)(IO_BASE+0x1080f)=50;	
+#endif
+	/* program timer 1 */       	
+	*(volatile unsigned char *)(IO_BASE+0x10803)=0x01;
+	*(volatile unsigned char *)(IO_BASE+0x10801)=0x40;
+	*(volatile unsigned char *)(IO_BASE+0x10805)=0x09;
+	*(volatile unsigned char *)(IO_BASE+0x10807)=0xc4;
+
+	/* enable IRQ of PIC B */
+	*(volatile unsigned char *)(IO_BASE+PICA+1)&=(~8);
+
+
+
+	printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803));
+	printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803));
+
+	sched_timer_handler=timer_routine;
+	request_irq(0,dn_timer_int,0,NULL,NULL);
+
+	
+}
+
+unsigned long dn_gettimeoffset(void) {
+
+	return 0xdeadbeef;
+
+}
+
+void dn_gettod(int *yearp, int *monp, int *dayp,
+	       int *hourp, int *minp, int *secp) {
+
+  *yearp=rtc->year;
+  *monp=rtc->month;
+  *dayp=rtc->day_of_month;
+  *hourp=rtc->hours;
+  *minp=rtc->minute;
+  *secp=rtc->second;
+
+printk("gettod: %d %d %d %d %d %d\n",*yearp,*monp,*dayp,*hourp,*minp,*secp);
+
+}
+
+int dn_dummy_hwclk(int op, struct hwclk_time *t) {
+
+  dn_serial_print("hwclk !\n");
+
+  if(!op) { /* read */
+    t->sec=rtc->second;
+    t->min=rtc->minute;
+    t->hour=rtc->hours;
+    t->day=rtc->day_of_month;
+    t->wday=rtc->day_of_week;
+    t->mon=rtc->month;
+    t->year=rtc->year;
+  } else {
+    rtc->second=t->sec;
+    rtc->minute=t->min;
+    rtc->hours=t->hour;
+    rtc->day_of_month=t->day;
+    if(t->wday!=-1)
+      rtc->day_of_week=t->wday;
+    rtc->month=t->mon;
+    rtc->year=t->year;
+  }
+
+  dn_serial_print("hwclk end!\n");
+  return 0;
+
+}
+
+int dn_dummy_set_clock_mmss(unsigned long nowtime) {
+
+  printk("set_clock_mmss\n");
+
+  return 0;
+
+}
+
+void dn_dummy_reset(void) {
+
+  dn_serial_print("The end !\n");
+
+  for(;;);
+
+}
+	
+void dn_dummy_waitbut(void) {
+
+  dn_serial_print("waitbut\n");
+
+}
+
+#if 0
+void dn_debug_init(void) {
+
+  dn_console_driver.write=dn_serial_console_write;
+  register_console(&dn_console_driver);
+
+}
+#endif
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/apollo/dn_debug.c linux/arch/m68k/apollo/dn_debug.c
--- v2.1.86/linux/arch/m68k/apollo/dn_debug.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/apollo/dn_debug.c	Thu Feb 12 16:30:12 1998
@@ -0,0 +1,23 @@
+#include <stdarg.h>
+
+#define DN_DEBUG_BUFFER_BASE 0x82800000
+#define DN_DEBUG_BUFFER_SIZE 8*1024*1024
+
+static char *current_dbg_ptr=DN_DEBUG_BUFFER_BASE;
+
+int dn_deb_printf(const char *fmt, ...) {
+
+	va_list args;
+	int i;
+
+	if(current_dbg_ptr<(DN_DEBUG_BUFFER_BASE + DN_DEBUG_BUFFER_SIZE)) {
+		va_start(args,fmt);
+		i=vsprintf(current_dbg_ptr,fmt,args);
+		va_end(args);
+		current_dbg_ptr+=i;
+	
+		return i;
+	}
+	else 
+		return 0;
+}
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/apollo/dn_ints.c linux/arch/m68k/apollo/dn_ints.c
--- v2.1.86/linux/arch/m68k/apollo/dn_ints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/apollo/dn_ints.c	Thu Feb 12 16:30:12 1998
@@ -0,0 +1,166 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+#include <asm/apollohw.h>
+
+static irq_handler_t dn_irqs[16];
+
+extern void write_keyb_cmd(u_short length, u_char *cmd);
+static char BellOnCommand[] =  { 0xFF, 0x21, 0x81 },
+		    BellOffCommand[] = { 0xFF, 0x21, 0x82 };
+
+void dn_process_int(int irq, struct pt_regs *fp) {
+
+#if 0
+  unsigned char x;
+#endif 
+
+#if 0
+  printk("Aha DN interrupt ! : %d\n",irq);
+#endif
+
+  if(dn_irqs[irq-160].handler) {
+    dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp);
+  }
+  else {
+    printk("spurious irq %d occured\n",irq);
+  }
+
+#if 0  
+  printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803));
+  x=*(volatile unsigned char *)(IO_BASE+0x10805);
+#endif
+
+  *(volatile unsigned char *)(IO_BASE+0x11000)=0x20;
+  *(volatile unsigned char *)(IO_BASE+0x11100)=0x20;
+
+}
+
+void dn_init_IRQ(void) {
+
+  int i;
+
+  printk("Init IRQ\n");
+
+  for(i=0;i<16;i++) {
+    dn_irqs[i].handler=NULL;
+    dn_irqs[i].flags=IRQ_FLG_STD;
+    dn_irqs[i].dev_id=NULL;
+    dn_irqs[i].devname=NULL;
+  }
+  
+}
+
+int dn_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) {
+
+  printk("dn request IRQ\n");
+
+  if((irq<0) || (irq>15)) {
+    printk("Trying to request illegal IRQ\n");
+    return -ENXIO;
+  }
+
+  if(!dn_irqs[irq].handler) {
+    dn_irqs[irq].handler=handler;
+    dn_irqs[irq].flags=IRQ_FLG_STD;
+    dn_irqs[irq].dev_id=dev_id;
+    dn_irqs[irq].devname=devname;
+    if(irq<8)
+      *(volatile unsigned char *)(IO_BASE+PICA+1)&=~(1<<irq);
+    else
+      *(volatile unsigned char *)(IO_BASE+PICB+1)&=~(1<<(irq-8));
+    return 0;
+  }
+  else {
+    printk("Trying to request already assigned irq %d\n",irq);
+    return -ENXIO;
+  }
+
+}
+
+void dn_free_irq(unsigned int irq, void *dev_id) {
+
+  printk("dn free irq\n");
+
+  if((irq<0) || (irq>15)) {
+    printk("Trying to free illegal IRQ\n");
+    return ;
+  }
+
+  if(irq<8)
+    *(volatile unsigned char *)(IO_BASE+PICA+1)|=(1<<irq);
+  else
+    *(volatile unsigned char *)(IO_BASE+PICB+1)|=(1<<(irq-8));  
+
+  dn_irqs[irq].handler=NULL;
+  dn_irqs[irq].flags=IRQ_FLG_STD;
+  dn_irqs[irq].dev_id=NULL;
+  dn_irqs[irq].devname=NULL;
+
+  return ;
+
+}
+
+void dn_enable_irq(unsigned int irq) {
+
+  printk("dn enable irq\n");
+
+}
+
+void dn_disable_irq(unsigned int irq) {
+
+  printk("dn disable irq\n");
+
+}
+
+int dn_get_irq_list(char *buf) {
+
+  printk("dn get irq list\n");
+
+  return 0;
+
+}
+
+struct fb_info *dn_dummy_fb_init(long *mem_start) {
+
+  printk("fb init\n");
+
+  return NULL;
+
+}
+
+static void dn_nosound (unsigned long ignored) {
+
+	write_keyb_cmd(sizeof(BellOffCommand),BellOffCommand);
+
+}
+
+void dn_mksound( unsigned int count, unsigned int ticks ) {
+
+	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
+       										 dn_nosound };
+
+	del_timer( &sound_timer );
+	if(count) {
+		write_keyb_cmd(sizeof(BellOnCommand),BellOnCommand);
+		if (ticks) {
+       		sound_timer.expires = jiffies + ticks;
+			add_timer( &sound_timer );
+		}
+	}
+	else
+		write_keyb_cmd(sizeof(BellOffCommand),BellOffCommand);
+}
+
+void dn_dummy_video_setup(char *options,int *ints) {
+
+  printk("no video yet\n");
+
+}
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/Makefile linux/arch/m68k/atari/Makefile
--- v2.1.86/linux/arch/m68k/atari/Makefile	Fri Jan  3 01:33:25 1997
+++ linux/arch/m68k/atari/Makefile	Thu Feb 12 16:30:12 1998
@@ -8,8 +8,8 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := atari.o
-O_OBJS	 := config.o atakeyb.o ataints.o \
-            stdma.o atasound.o joystick.o stram.o atafb.o
+O_OBJS	 := config.o time.o debug.o atakeyb.o ataints.o stdma.o atasound.o \
+            joystick.o stram.o
 OX_OBJS  := atari_ksyms.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c
--- v2.1.86/linux/arch/m68k/atari/ataints.c	Mon Jun 16 16:35:53 1997
+++ linux/arch/m68k/atari/ataints.c	Thu Feb 12 16:30:12 1998
@@ -166,7 +166,7 @@
 asmlinkage void IRQ_NAME(n);						   \
 /* Dummy function to allow asm with operands.  */			   \
 void atari_slow_irq_##n##_dummy (void) {				   \
-__asm__ (ALIGN_STR "\n"							   \
+__asm__ (__ALIGN_STR "\n"						   \
 SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t"			   \
 "	addql	#1,"SYMBOL_NAME_STR(local_irq_count)"\n"		   \
 	SAVE_ALL_INT "\n"						   \
@@ -190,7 +190,7 @@
 "	andw	#0xfeff,%%sr\n"		/* set IPL = 6 again */		   \
 "	orb 	#(1<<(%c3&7)),%a4:w\n"	/* now unmask the int again */	   \
 "	jbra	"SYMBOL_NAME_STR(ret_from_interrupt)"\n"		   \
-	 : : "i" (&kstat.interrupts[n+8]), "i" (&irq_handler[n+8]),	   \
+	 : : "i" (&kstat.irqs[0][n+8]), "i" (&irq_handler[n+8]),	   \
 	     "n" (PT_OFF_SR), "n" (n),					   \
 	     "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a)	   \
 		        : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b))	   \
@@ -270,7 +270,7 @@
 
 /* Dummy function to allow asm with operands.  */
 void atari_fast_prio_irq_dummy (void) {
-__asm__ (ALIGN_STR "\n"
+__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
@@ -294,7 +294,7 @@
 	addql	#8,%%sp
 	addql	#4,%%sp
 	jbra	"SYMBOL_NAME_STR(ret_from_interrupt)
-	 : : "i" (&kstat.interrupts), "n" (PT_OFF_FORMATVEC)
+	 : : "i" (&kstat.irqs), "n" (PT_OFF_FORMATVEC)
 );
 }
 
@@ -304,7 +304,7 @@
  */
 asmlinkage void falcon_hblhandler(void);
 asm(".text\n"
-ALIGN_STR "\n"
+__ALIGN_STR "\n"
 SYMBOL_NAME_STR(falcon_hblhandler) ":
 	orw	#0x200,%sp@	/* set saved ipl to 2 */
 	rte");
@@ -314,6 +314,8 @@
 
 extern void atari_microwire_cmd( int cmd );
 
+extern int atari_SCC_reset_done;
+
 /*
  * void atari_init_IRQ (void)
  *
@@ -358,7 +360,7 @@
 		tt_mfp.int_mk_b = 0xff;
 	}
 
-	if (ATARIHW_PRESENT(SCC)) {
+	if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) {
 		scc.cha_a_ctrl = 9;
 		MFPDELAY();
 		scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
@@ -374,10 +376,13 @@
 		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)
+		/* If no SCU and no Hades, the HSYNC interrupt needs to be
+		 * disabled this way. (Else _inthandler in kernel/sys_call.S
+		 * gets overruns)
 		 */
-		vectors[VEC_INT2] = falcon_hblhandler;
+
+		if (!MACH_IS_HADES)
+			vectors[VEC_INT2] = falcon_hblhandler;
 	}
 
 	if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
@@ -414,7 +419,14 @@
                       unsigned long flags, const char *devname, void *dev_id)
 {
 	int vector;
-	
+
+	/*
+	 * The following is a hack to make some PCI card drivers work,
+	 * which set the SA_SHIRQ flag.
+	 */
+
+	flags &= ~SA_SHIRQ;
+
 	if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
 		printk ("%s: Bad irq type %ld requested from %s\n",
 		        __FUNCTION__, flags, devname);
@@ -600,11 +612,11 @@
 			continue;
 		if (i < STMFP_SOURCE_BASE)
 			len += sprintf(buf+len, "auto %2d: %10u ",
-				       i, kstat.interrupts[i]);
+				       i, kstat.irqs[0][i]);
 		else
 			len += sprintf(buf+len, "vec $%02x: %10u ",
 				       IRQ_SOURCE_TO_VECTOR(i),
-				       kstat.interrupts[i]);
+				       kstat.irqs[0][i]);
 
 		if (irq_handler[i].handler != atari_call_irq_list) {
 			len += sprintf(buf+len, "%s\n", irq_param[i].devname);
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- v2.1.86/linux/arch/m68k/atari/atakeyb.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/atari/atakeyb.c	Thu Feb 12 16:30:12 1998
@@ -32,7 +32,6 @@
 #include <asm/atari_joystick.h>
 #include <asm/irq.h>
 
-extern int ovsc_switchmode;
 extern unsigned char mach_keyboard_type;
 static void atakeyb_rep( unsigned long ignore );
 extern unsigned int keymap_count;
@@ -504,23 +503,6 @@
 	}
     }
 
-#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 */;
@@ -537,26 +519,6 @@
     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
@@ -581,7 +543,6 @@
 	}
     }
 }
-#endif
 
 /* Reset (without touching the clock) */
 void ikbd_reset(void)
@@ -828,33 +789,28 @@
 
     atari_turnoff_irq(IRQ_MFP_ACIA);
     do {
-	acia.key_ctrl = ACIA_RESET;		/* reset ACIA */
+	/* reset IKBD ACIA */
+	acia.key_ctrl = ACIA_RESET |
+			(atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0;
 	(void)acia.key_ctrl;
 	(void)acia.key_data;
 
-	acia.mid_ctrl = ACIA_RESET;		/* reset other ACIA */
+	/* reset MIDI ACIA */
+	acia.mid_ctrl = ACIA_RESET |
+			(atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
 	(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
+	/* RTS low (except if switch selected), transmit interrupt disabled */
+	acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
+			((atari_switches & ATARI_SWITCH_IKBD) ?
+			 ACIA_RHTID : ACIA_RLTID);
 	   
-	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S;
+	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
+			(atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
     }
     /* make sure the interrupt line is up */
     while ((mfp.par_dt_reg & 0x10) == 0);
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/atari_ksyms.c linux/arch/m68k/atari/atari_ksyms.c
--- v2.1.86/linux/arch/m68k/atari/atari_ksyms.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/atari/atari_ksyms.c	Thu Feb 12 16:30:12 1998
@@ -7,24 +7,32 @@
 #include <asm/atarikb.h>
 #include <asm/atari_joystick.h>
 #include <asm/atari_stdma.h>
+#include <asm/atari_stram.h>
 
 extern void atari_microwire_cmd( int cmd );
+extern int atari_MFP_init_done;
+extern int atari_SCC_init_done;
 extern int atari_SCC_reset_done;
 
 EXPORT_SYMBOL(atari_mch_cookie);
+EXPORT_SYMBOL(atari_mch_type);
 EXPORT_SYMBOL(atari_hw_present);
-EXPORT_SYMBOL(is_medusa);
-EXPORT_SYMBOL(is_hades);
+EXPORT_SYMBOL(atari_switches);
+EXPORT_SYMBOL(atari_dont_touch_floppy_select);
 EXPORT_SYMBOL(atari_register_vme_int);
 EXPORT_SYMBOL(atari_unregister_vme_int);
 EXPORT_SYMBOL(stdma_lock);
 EXPORT_SYMBOL(stdma_release);
 EXPORT_SYMBOL(stdma_others_waiting);
 EXPORT_SYMBOL(stdma_islocked);
+EXPORT_SYMBOL(atari_stram_alloc);
+EXPORT_SYMBOL(atari_stram_free);
 
 EXPORT_SYMBOL(atari_mouse_buttons);
 EXPORT_SYMBOL(atari_mouse_interrupt_hook);
 EXPORT_SYMBOL(atari_MIDI_interrupt_hook);
+EXPORT_SYMBOL(atari_MFP_init_done);
+EXPORT_SYMBOL(atari_SCC_init_done);
 EXPORT_SYMBOL(atari_SCC_reset_done);
 EXPORT_SYMBOL(ikbd_write);
 EXPORT_SYMBOL(ikbd_mouse_y0_top);
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/atasound.c linux/arch/m68k/atari/atasound.c
--- v2.1.86/linux/arch/m68k/atari/atasound.c	Fri Dec 20 01:19:58 1996
+++ linux/arch/m68k/atari/atasound.c	Thu Feb 12 16:30:12 1998
@@ -1,17 +1,16 @@
 /*
-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 COPYING in the main directory of this archive
-for more details.
-
-*/
+ * 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 COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
 
 
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c
--- v2.1.86/linux/arch/m68k/atari/config.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/atari/config.c	Thu Feb 12 16:30:12 1998
@@ -27,35 +27,33 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
-#include <linux/mc146818rtc.h>
-#include <linux/kd.h>
-#include <linux/tty.h>
 #include <linux/console.h>
-#include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
 #include <asm/atarihw.h>
-#include <asm/atarihdreg.h>
 #include <asm/atariints.h>
-
+#include <asm/atari_stram.h>
 #include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
 #include <asm/machdep.h>
 
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-
 u_long atari_mch_cookie;
+u_long atari_mch_type = 0;
 struct atari_hw_present atari_hw_present;
+u_long atari_switches = 0;
+int atari_dont_touch_floppy_select = 0;
+int atari_rtc_year_offset;
 
-extern char m68k_debug_device[];
+/* local function prototypes */
+static void atari_reset( void );
+#ifdef CONFIG_ATARI_FLOPPY
+extern void atari_floppy_setup(char *, int *);
+#endif
+static void atari_get_model(char *model);
+static int atari_get_hardware_list(char *buffer);
 
-static void atari_sched_init(void (*)(int, void *, struct pt_regs *));
 /* atari specific keyboard functions */
 extern int atari_keyb_init(void);
 extern int atari_kbdrate (struct kbd_repeat *);
@@ -68,33 +66,36 @@
 extern void atari_enable_irq (unsigned int);
 extern void atari_disable_irq (unsigned int);
 extern int atari_get_irq_list (char *buf);
-static void atari_get_model(char *model);
-static int atari_get_hardware_list(char *buffer);
-/* atari specific timer functions */
-static unsigned long atari_gettimeoffset (void);
-static void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
-static void atari_gettod (int *, int *, int *, int *, int *, int *);
-static int atari_mste_hwclk (int, struct hwclk_time *);
-static int atari_hwclk (int, struct hwclk_time *);
-static int atari_mste_set_clock_mmss (unsigned long);
-static int atari_set_clock_mmss (unsigned long);
 extern void atari_mksound( unsigned int count, unsigned int ticks );
-static void atari_reset( void );
-#ifdef CONFIG_BLK_DEV_FD
-extern int atari_floppy_init (void);
-extern void atari_floppy_setup(char *, int *);
+#ifdef CONFIG_HEARTBEAT
+static void atari_heartbeat( int on );
 #endif
 extern struct consw fb_con;
-extern struct fb_info *atari_fb_init(long *);
-static void atari_debug_init(void);
-extern void atari_video_setup(char *, int *);
-
-static struct console atari_console_driver;
-
-/* Can be set somewhere, if a SCC master reset has already be done and should
- * not be repeated; used by kgdb */
-int atari_SCC_reset_done = 0;
 
+/* atari specific timer functions (in time.c) */
+extern void atari_sched_init(void (*)(int, void *, struct pt_regs *));
+extern unsigned long atari_gettimeoffset (void);
+extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *);
+extern void atari_tt_gettod (int *, int *, int *, int *, int *, int *);
+extern int atari_mste_hwclk (int, struct hwclk_time *);
+extern int atari_tt_hwclk (int, struct hwclk_time *);
+extern int atari_mste_set_clock_mmss (unsigned long);
+extern int atari_tt_set_clock_mmss (unsigned long);
+
+/* atari specific debug functions (in debug.c) */
+extern void atari_debug_init(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static char atari_sysrq_xlate[128] =
+	"\000\0331234567890-=\177\t"					/* 0x00 - 0x0f */
+	"qwertyuiop[]\r\000as"							/* 0x10 - 0x1f */
+	"dfghjkl;'`\000\\zxcv"							/* 0x20 - 0x2f */
+	"bnm,./\000\000\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
+	"\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
+	"\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+	"\000\000\000()/*789456123"						/* 0x60 - 0x6f */
+	"0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 0x70 - 0x7f */
+#endif
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 
@@ -237,18 +238,62 @@
 	case BI_ATARI_MCH_COOKIE:
 	    atari_mch_cookie = *data;
 	    break;
+	case BI_ATARI_MCH_TYPE:
+	    atari_mch_type = *data;
+	    break;
 	default:
 	    unknown = 1;
     }
     return(unknown);
 }
 
+
+/* Parse the Atari-specific switches= option. */
+__initfunc(void atari_switches_setup( const char *str, unsigned len ))
+{
+    char switches[len+1];
+    char *p;
+    int ovsc_shift;
+
+    /* copy string to local array, strtok works destructively... */
+    strncpy( switches, str, len );
+    switches[len] = 0;
+    atari_switches = 0;
+
+    /* parse the options */
+    for( p = strtok( switches, "," ); p; p = strtok( NULL, "," ) ) {
+	ovsc_shift = 0;
+	if (strncmp( p, "ov_", 3 ) == 0) {
+	    p += 3;
+	    ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
+	}
+	
+	if (strcmp( p, "ikbd" ) == 0) {
+	    /* RTS line of IKBD ACIA */
+	    atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
+	}
+	else if (strcmp( p, "midi" ) == 0) {
+	    /* RTS line of MIDI ACIA */
+	    atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
+	}
+	else if (strcmp( p, "snd6" ) == 0) {
+	    atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
+	}
+	else if (strcmp( p, "snd7" ) == 0) {
+	    atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
+	}
+    }
+}
+
+
     /*
      *  Setup the Atari configuration info
      */
 
 __initfunc(void config_atari(void))
 {
+    unsigned short tos_version;
+
     memset(&atari_hw_present, 0, sizeof(atari_hw_present));
 
     atari_debug_init();
@@ -267,22 +312,40 @@
     mach_get_irq_list	 = atari_get_irq_list;
     mach_gettimeoffset   = atari_gettimeoffset;
     mach_reset           = atari_reset;
-#ifdef CONFIG_BLK_DEV_FD
-    mach_floppy_init	 = atari_floppy_init;
+#ifdef CONFIG_ATARI_FLOPPY
     mach_floppy_setup	 = atari_floppy_setup;
 #endif
     conswitchp	         = &fb_con;
-    mach_fb_init         = atari_fb_init;
     mach_max_dma_address = 0xffffff;
-    mach_video_setup	 = atari_video_setup;
     kd_mksound		 = atari_mksound;
+#ifdef CONFIG_MAGIC_SYSRQ
+    mach_sysrq_key = 98;          /* HELP */
+    mach_sysrq_shift_state = 8;   /* Alt */
+    mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */
+    mach_sysrq_xlate = atari_sysrq_xlate;
+#endif
+#ifdef CONFIG_HEARTBEAT
+    mach_heartbeat = atari_heartbeat;
+#endif
 
+    /* Set switches as requested by the user */
+    if (atari_switches & ATARI_SWITCH_IKBD)
+	acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
+    if (atari_switches & ATARI_SWITCH_MIDI)
+	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+    if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
+	sound_ym.rd_data_reg_sel = 14;
+	sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+			   ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
+			   ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
+    }
+	
     /* ++bjoern: 
      * Determine hardware present
      */
 
     printk( "Atari hardware found: " );
-    if (is_medusa || is_hades) {
+    if (MACH_IS_MEDUSA || MACH_IS_HADES) {
         /* There's no Atari video hardware on the Medusa, but all the
          * addresses below generate a DTACK so no bus error occurs! */
     }
@@ -324,12 +387,12 @@
 	ATARIHW_SET(SCSI_DMA);
         printk( "TT_SCSI_DMA " );
     }
-    if (!is_hades && hwreg_present( &st_dma.dma_hi )) {
+    if (!MACH_IS_HADES && 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 */
+    if (MACH_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 &&
@@ -346,11 +409,12 @@
 	ATARIHW_SET(YM_2149);
         printk( "YM2149 " );
     }
-    if (!is_medusa && !is_hades && hwreg_present( &tt_dmasnd.ctrl )) {
+    if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+	hwreg_present( &tt_dmasnd.ctrl )) {
 	ATARIHW_SET(PCM_8BIT);
         printk( "PCM " );
     }
-    if (!is_hades && hwreg_present( &codec.unused5 )) {
+    if (!MACH_IS_HADES && hwreg_present( &codec.unused5 )) {
 	ATARIHW_SET(CODEC);
         printk( "CODEC " );
     }
@@ -364,7 +428,7 @@
 	(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 && !is_hades
+	!MACH_IS_MEDUSA && !MACH_IS_HADES
 #endif
 	) {
 	ATARIHW_SET(SCC_DMA);
@@ -378,7 +442,7 @@
 	ATARIHW_SET( ST_ESCC );
 	printk( "ST_ESCC " );
     }
-    if (is_hades)
+    if (MACH_IS_HADES)
     {
         ATARIHW_SET( VME );
         printk( "VME " );
@@ -393,20 +457,22 @@
 	ATARIHW_SET(ANALOG_JOY);
         printk( "ANALOG_JOY " );
     }
-    if (!is_hades && hwreg_present( blitter.halftone )) {
+    if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) {
 	ATARIHW_SET(BLITTER);
         printk( "BLITTER " );
     }
-    if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) {
+    if (hwreg_present((void *)0xfff00039)) {
 	ATARIHW_SET(IDE);
         printk( "IDE " );
     }
 #if 1 /* This maybe wrong */
-    if (!is_medusa && !is_hades &&
+    if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
 	hwreg_present( &tt_microwire.data ) &&
 	hwreg_present( &tt_microwire.mask ) &&
 	(tt_microwire.mask = 0x7ff,
+	 udelay(1),
 	 tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
+	 udelay(1),
 	 tt_microwire.data != 0)) {
 	ATARIHW_SET(MICROWIRE);
 	while (tt_microwire.mask != 0x7ff) ;
@@ -416,24 +482,24 @@
     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;
+        mach_gettod = atari_tt_gettod;
+        mach_hwclk = atari_tt_hwclk;
+        mach_set_clock_mmss = atari_tt_set_clock_mmss;
     }
-    if (!is_hades && hwreg_present( &mste_rtc.sec_ones)) {
+    if (!MACH_IS_HADES && 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 && !is_hades &&
+    if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
 	hwreg_present( &dma_wd.fdc_speed ) &&
 	hwreg_write( &dma_wd.fdc_speed, 0 )) {
 	    ATARIHW_SET(FDCSPEED);
 	    printk( "FDC_SPEED ");
     }
-    if (!is_hades && !ATARIHW_PRESENT(ST_SCSI)) {
+    if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
 	ATARIHW_SET(ACSI);
         printk( "ACSI " );
     }
@@ -491,153 +557,24 @@
               : "d0" );
 
     }
-}
-
-__initfunc(static void
-atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)))
-{
-    /* 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 */
-    request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
-                "timer", timer_routine);
-}
-
-/* ++andreas: gettimeoffset fixed to check for pending interrupt */
-
-#define TICK_SIZE 10000
-  
-/* This is always executed with interrupts disabled.  */
-static 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)
-
-
-static void atari_mste_gettod (int *yearp, int *monp, int *dayp,
-			       int *hourp, int *minp, int *secp)
-{
-    int hr24=0, hour;
-    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;
-    hour = val.hr_ones + val.hr_tens * 10;
-    if (!hr24) {
-        if (hour == 12 || hour == 12 + 20)
-	    hour -= 12;
-	if (hour >= 20)
-	    hour += 12 - 20;
-    }
-    *hourp = hour;
-    *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;	
-}
-
-  
-static void atari_gettod (int *yearp, int *monp, int *dayp,
-			  int *hourp, int *minp, int *secp)
-{
-    unsigned char	ctrl;
-    unsigned short tos_version;
-    int hour, pm;
-
-    while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
-    while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
+    /*
+     * On the Hades map the PCI memory, I/O and configuration areas
+     * (0x80000000 - 0xbfffffff).
+     *
+     * Settings: supervisor only, non-cacheable, serialized, read and write.
+     */
 
-    *secp  = RTC_READ(RTC_SECONDS);
-    *minp  = RTC_READ(RTC_MINUTES);
-    hour = RTC_READ(RTC_HOURS);
-    *dayp  = RTC_READ(RTC_DAY_OF_MONTH);
-    *monp  = RTC_READ(RTC_MONTH);
-    *yearp = RTC_READ(RTC_YEAR);
-    pm = hour & 0x80;
-    hour &= ~0x80;
-
-    ctrl = RTC_READ(RTC_CONTROL); 
-
-    if (!(ctrl & RTC_DM_BINARY)) {
-        BCD_TO_BIN(*secp);
-        BCD_TO_BIN(*minp);
-        BCD_TO_BIN(hour);
-        BCD_TO_BIN(*dayp);
-        BCD_TO_BIN(*monp);
-        BCD_TO_BIN(*yearp);
-    }
-    if (!(ctrl & RTC_24H)) {
-	if (!pm && hour == 12)
-	    hour = 0;
-	else if (pm && hour != 12)
-            hour += 12;
+    if (MACH_IS_HADES) {
+        __asm__ __volatile__ ("movel %0,%/d0\n\t"
+                              ".chip 68040\n\t"
+                              "movec %%d0,%%itt0\n\t"
+                              "movec %%d0,%%dtt0\n\t"
+                              ".chip 68k\n\t"
+                              : /* no outputs */
+                              : "g" (0x803fa040)
+                              : "d0");
     }
-    *hourp = hour;
-
-    /* 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
@@ -647,403 +584,29 @@
        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 || is_hades) ? 0xfff : *(unsigned short *)0xFF000002;
-    *yearp += (tos_version < 0x306) ? 70 : 68;
+    tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
+		  0xfff : *(unsigned short *)0xff000002;
+    atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
 }
 
-#define HWCLK_POLL_INTERVAL	5
-
-static int atari_mste_hwclk( int op, struct hwclk_time *t )
+#ifdef CONFIG_HEARTBEAT
+static void atari_heartbeat( int on )
 {
-    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;
-        if (!hr24) {
-	    if (hour > 11)
-		hour += 20 - 12;
-	    if (hour == 0 || hour == 20)
-		hour += 12;
-        }
-        val.hr_ones = hour % 10;
-        val.hr_tens = hour / 10;
-        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;
-        hour = val.hr_ones + val.hr_tens * 10;
-	if (!hr24) {
-	    if (hour == 12 || hour == 12 + 20)
-		hour -= 12;
-	    if (hour >= 20)
-                hour += 12 - 20;
-        }
-	t->hour = hour;
-	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;
-}
+    unsigned char tmp;
+    unsigned long flags;
 
-static 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;
-    int pm = 0;
-
-    /* Tos version at Physical 2.  See above for explanation why we
-       cannot use PTOV(2).  */
-    tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xff000002;
-
-    ctrl = RTC_READ(RTC_CONTROL); /* control registers are
-                                   * independent 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)) {
-	    if (hour > 11) {
-		pm = 0x80;
-		if (hour != 12)
-		    hour -= 12;
-	    }
-	    else if (hour == 0)
-		hour = 12;
-        }
-        
-        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);
-        }
-    }
+    if (atari_dont_touch_floppy_select)
+	return;
     
-    /* 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 + pm);
-        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 (hour & 0x80) {
-	    hour &= ~0x80;
-	    pm = 1;
-	}
-
-	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 (!pm && hour == 12)
-		hour = 0;
-	    else if (pm && hour != 12)
-		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 );
-}
-
-
-static 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;
-}
-
-static 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;
-}
-
-static inline void ata_mfp_out (char c)
-{
-    while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
-	barrier ();
-    mfp.usart_dta = c;
-}
-
-static void atari_mfp_console_write (const char *str, unsigned int count)
-{
-    while (count--) {
-	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;
-}
-
-static void atari_scc_console_write (const char *str, unsigned int count)
-{
-    while (count--) {
-	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 */
+    sound_ym.rd_data_reg_sel = 14; /* Select PSG 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 );
-}
-
-static void atari_par_console_write (const char *str, unsigned int count)
-{
-    static int printer_present = 1;
-
-    if (!printer_present)
-	return;
-
-    while (count--) {
-	if (*str == '\n')
-	    if (!ata_par_out( '\r' )) {
-		printer_present = 0;
-		return;
-	    }
-	if (!ata_par_out( *str++ )) {
-	    printer_present = 0;
-	    return;
-	}
-    }
+    sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
+    restore_flags(flags);
 }
-
-
-__initfunc(static void atari_debug_init(void))
-{
-#ifdef CONFIG_KGDB
-	/* if the m68k_debug_device is used by the GDB stub, do nothing here */
-	if (kgdb_initialized)
-		return(NULL);
 #endif
 
-    if (!strcmp( m68k_debug_device, "ser" )) {
-	/* defaults to ser2 for a Falcon and ser1 otherwise */
-	strcpy( m68k_debug_device, 
-		((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 */
-	atari_console_driver.write = atari_mfp_console_write;
-    }
-    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();
-	}
-	atari_console_driver.write = atari_scc_console_write;
-    }
-    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 */
-	atari_console_driver.write = atari_par_console_write;
-    }
-    if (atari_console_driver.write)
-	register_console(&atari_console_driver);
-}
-
 /* ++roman:
  *
  * This function does a reset on machines that lack the ability to
@@ -1082,11 +645,16 @@
 
     /* 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_hades ? 0x7fe00030 :
-                 (is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004);
-
-    acia.key_ctrl = ACIA_RESET;             /* reset ACIA for switch off OverScan, if it's active */
-
+    reset_addr = MACH_IS_HADES ? 0x7fe00030 :
+                 MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
+		 *(unsigned long *) 0xff000004;
+
+    /* reset ACIA for switch off OverScan, if it's active */
+    if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+	acia.key_ctrl = ACIA_RESET;
+    if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+	acia.mid_ctrl = ACIA_RESET;
+    
     /* processor independent: turn off interrupts and reset the VBR;
      * the caches must be left enabled, else prefetching the final jump
      * instruction doesn't work. */
@@ -1126,8 +694,21 @@
 	   "nop\n\t"
 	   ".chip 68040\n\t"
 	   "cinva %%bc\n\t"
+	   "nop\n\t"
 	   "pflusha\n\t"
+	   "nop\n\t"
 	   "movec %%d0,%%tc\n\t"
+	   "nop\n\t"
+	   /* the following setup of transparent translations is needed on the
+	    * Afterburner040 to successfully reboot. Other machines shouldn't
+	    * care about a different tt regs setup, they also didn't care in
+	    * the past that the regs weren't turned off. */
+	   "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */
+	   "movec %%d0,%%itt0\n\t"
+	   "movec %%d0,%%itt1\n\t"
+	   "orw   #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */
+	   "movec %%d0,%%dtt0\n\t"
+	   "movec %%d0,%%dtt1\n\t"
 	   ".chip 68k\n\t"
            "jmp %0@"
            : /* no outputs */
@@ -1154,22 +735,24 @@
 		strcat (model, "ST");
 	    break;
 	case ATARI_MCH_STE:
-	    if ((atari_mch_cookie & 0xffff) == 0x10)
+	    if (MACH_IS_MSTE)
 		strcat (model, "Mega STE");
 	    else
 		strcat (model, "STE");
 	    break;
 	case ATARI_MCH_TT:
-	    if (is_medusa)
+	    if (MACH_IS_MEDUSA)
 		/* Medusa has TT _MCH cookie */
 		strcat (model, "Medusa");
-	    else if (is_hades)
+	    else if (MACH_IS_HADES)
 		strcat(model, "Hades");
 	    else
 		strcat (model, "TT");
 	    break;
 	case ATARI_MCH_FALCON:
 	    strcat (model, "Falcon");
+	    if (MACH_IS_AB40)
+		strcat (model, " (with Afterburner040)");
 	    break;
 	default:
 	    sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
@@ -1225,3 +808,10 @@
 
     return(len);
 }
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/debug.c linux/arch/m68k/atari/debug.c
--- v2.1.86/linux/arch/m68k/atari/debug.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/atari/debug.c	Thu Feb 12 16:30:12 1998
@@ -0,0 +1,359 @@
+/*
+ * linux/arch/m68k/atari/debug.c
+ *
+ * Atari debugging and serial console stuff
+ *
+ * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
+ *  
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+
+extern char m68k_debug_device[];
+
+/* Flag that Modem1 port is already initialized and used */
+int atari_MFP_init_done = 0;
+/* Flag that Modem1 port is already initialized and used */
+int atari_SCC_init_done = 0;
+/* Can be set somewhere, if a SCC master reset has already be done and should
+ * not be repeated; used by kgdb */
+int atari_SCC_reset_done = 0;
+
+static struct console atari_console_driver = {
+	"debug",
+	NULL,			/* write */
+	NULL,			/* read */
+	NULL,			/* device */
+	NULL,			/* wait_key */
+	NULL,			/* unblank */
+	NULL,			/* setup */
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+
+static inline void ata_mfp_out (char c)
+{
+    while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
+	barrier ();
+    mfp.usart_dta = c;
+}
+
+void atari_mfp_console_write (struct console *co, const char *str,
+			      unsigned int count)
+{
+    while (count--) {
+	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 atari_scc_console_write (struct console *co, const char *str,
+			      unsigned int count)
+{
+    while (count--) {
+	if (*str == '\n')
+	    ata_scc_out( '\r' );
+	ata_scc_out( *str++ );
+    }
+}
+
+static inline void ata_midi_out (char c)
+{
+    while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */
+	barrier ();
+    acia.mid_data = c;
+}
+
+void atari_midi_console_write (struct console *co, const char *str,
+			       unsigned int count)
+{
+    while (count--) {
+	if (*str == '\n')
+	    ata_midi_out( '\r' );
+	ata_midi_out( *str++ );
+    }
+}
+
+static int ata_par_out (char c)
+{
+    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 );
+}
+
+static void atari_par_console_write (struct console *co, const char *str,
+				     unsigned int count)
+{
+    static int printer_present = 1;
+
+    if (!printer_present)
+	return;
+
+    while (count--) {
+	if (*str == '\n')
+	    if (!ata_par_out( '\r' )) {
+		printer_present = 0;
+		return;
+	    }
+	if (!ata_par_out( *str++ )) {
+	    printer_present = 0;
+	    return;
+	}
+    }
+}
+
+#ifdef CONFIG_SERIAL_CONSOLE
+int atari_mfp_console_wait_key(struct console *co)
+{
+    while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */
+	barrier();
+    return( mfp.usart_dta );
+}
+
+int atari_scc_console_wait_key(struct console *co)
+{
+    do {
+	MFPDELAY();
+    } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
+    MFPDELAY();
+    return( scc.cha_b_data );
+}
+
+int atari_midi_console_wait_key(struct console *co)
+{
+    while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */
+	barrier();
+    return( acia.mid_data );
+}
+#endif
+
+/* The following two functions do a quick'n'dirty initialization of the MFP or
+ * SCC serial ports. They're used by the debugging interface, kgdb, and the
+ * serial console code. */
+#ifndef CONFIG_SERIAL_CONSOLE
+__initfunc(static void atari_init_mfp_port( int cflag ))
+#else
+void atari_init_mfp_port( int cflag )
+#endif
+{
+    /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
+     * bps, resp., and work only correct if there's a RSVE or RSSPEED */
+    static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
+    int baud = cflag & CBAUD;
+    int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
+    int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
+
+    if (cflag & CBAUDEX)
+	baud += B38400;
+    if (baud < B1200 || baud > B38400+2)
+	baud = B9600; /* use default 9600bps for non-implemented rates */
+    baud -= B1200; /* baud_table[] starts at 1200bps */
+	
+    mfp.trn_stat &= ~0x01; /* disable TX */
+    mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
+    mfp.tim_ct_cd &= 0x70;  /* stop timer D */
+    mfp.tim_dt_d = baud_table[baud];
+    mfp.tim_ct_cd |= 0x01;  /* start timer D, 1:4 */
+    mfp.trn_stat |= 0x01;  /* enable TX */
+
+    atari_MFP_init_done = 1;
+}
+
+#define SCC_WRITE(reg,val)				\
+    do {						\
+	scc.cha_b_ctrl = (reg);				\
+	MFPDELAY();					\
+	scc.cha_b_ctrl = (val);				\
+	MFPDELAY();					\
+    } while(0)
+
+/* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a
+ * delay of ~ 60us. */
+#define LONG_DELAY()				\
+    do {					\
+	int i;					\
+	for( i = 100; i > 0; --i )		\
+	    MFPDELAY();				\
+    } while(0)
+    
+#ifndef CONFIG_SERIAL_CONSOLE
+__initfunc(static void atari_init_scc_port( int cflag ))
+#else
+void atari_init_scc_port( int cflag )
+#endif
+{
+    extern int atari_SCC_reset_done;
+    static int clksrc_table[9] =
+	/* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
+    	{ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
+    static int brgsrc_table[9] =
+	/* reg 14: 0 = RTxC, 2 = PCLK */
+    	{ 2, 2, 2, 2, 2, 2, 0, 2, 2 };
+    static int clkmode_table[9] =
+	/* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
+    	{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
+    static int div_table[9] =
+	/* reg12 (BRG low) */
+    	{ 208, 138, 103, 50, 24, 11, 1, 0, 0 };
+
+    int baud = cflag & CBAUD;
+    int clksrc, clkmode, div, reg3, reg5;
+    
+    if (cflag & CBAUDEX)
+	baud += B38400;
+    if (baud < B1200 || baud > B38400+2)
+	baud = B9600; /* use default 9600bps for non-implemented rates */
+    baud -= B1200; /* tables starts at 1200bps */
+
+    clksrc  = clksrc_table[baud];
+    clkmode = clkmode_table[baud];
+    div     = div_table[baud];
+    if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
+	/* special treatment for TT, where rates >= 38400 are done via TRxC */
+	clksrc = 0x28; /* TRxC */
+	clkmode = baud == 6 ? 0xc0 :
+		  baud == 7 ? 0x80 : /* really 76800bps */
+			      0x40;  /* really 153600bps */
+	div = 0;
+    }
+
+    reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
+    reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
+    
+    (void)scc.cha_b_ctrl;	/* reset reg pointer */
+    SCC_WRITE( 9, 0xc0 );	/* reset */
+    LONG_DELAY();		/* extra delay after WR9 access */
+    SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+		  0x04 /* 1 stopbit */ |
+		  clkmode );
+    SCC_WRITE( 3, reg3 );
+    SCC_WRITE( 5, reg5 );
+    SCC_WRITE( 9, 0 );		/* no interrupts */
+    LONG_DELAY();		/* extra delay after WR9 access */
+    SCC_WRITE( 10, 0 );		/* NRZ mode */
+    SCC_WRITE( 11, clksrc );	/* main clock source */
+    SCC_WRITE( 12, div );	/* BRG value */
+    SCC_WRITE( 13, 0 );		/* BRG high byte */
+    SCC_WRITE( 14, brgsrc_table[baud] );
+    SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+    SCC_WRITE( 3, reg3 | 1 );
+    SCC_WRITE( 5, reg5 | 8 );
+    
+    atari_SCC_reset_done = 1;
+    atari_SCC_init_done = 1;
+}
+
+#ifndef CONFIG_SERIAL_CONSOLE 
+__initfunc(static void atari_init_midi_port( int cflag ))
+#else
+void atari_init_midi_port( int cflag )
+#endif
+{
+    int baud = cflag & CBAUD;
+    int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
+    /* warning 7N1 isn't possible! (instead 7O2 is used...) */
+    int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
+    int div;
+
+    /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
+     * default) the standard MIDI speed 31250. */
+    if (cflag & CBAUDEX)
+	baud += B38400;
+    if (baud == B4800)
+	div = ACIA_DIV64; /* really 7812.5 bps */
+    else if (baud == B38400+2 /* 115200 */)
+	div = ACIA_DIV1; /* really 500 kbps (does that work??) */
+    else
+	div = ACIA_DIV16; /* 31250 bps, standard for MIDI */
+
+    /* RTS low, ints disabled */
+    acia.mid_ctrl = div | csize | parity |
+		    ((atari_switches & ATARI_SWITCH_MIDI) ?
+		     ACIA_RHTID : ACIA_RLTID);
+}
+
+__initfunc(void atari_debug_init(void))
+{
+#ifdef CONFIG_KGDB
+    /* the m68k_debug_device is used by the GDB stub, do nothing here */
+    return;
+#endif
+    if (!strcmp( m68k_debug_device, "ser" )) {
+	/* defaults to ser2 for a Falcon and ser1 otherwise */
+	strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" );
+
+    }
+
+    if (!strcmp( m68k_debug_device, "ser1" )) {
+	/* ST-MFP Modem1 serial port */
+	atari_init_mfp_port( B9600|CS8 );
+	atari_console_driver.write = atari_mfp_console_write;
+    }
+    else if (!strcmp( m68k_debug_device, "ser2" )) {
+	/* SCC Modem2 serial port */
+	atari_init_scc_port( B9600|CS8 );
+	atari_console_driver.write = atari_scc_console_write;
+    }
+    else if (!strcmp( m68k_debug_device, "midi" )) {
+	/* MIDI port */
+	atari_init_midi_port( B9600|CS8 );
+	atari_console_driver.write = atari_midi_console_write;
+    }
+    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 */
+	atari_console_driver.write = atari_par_console_write;
+    }
+    if (atari_console_driver.write)
+	register_console(&atari_console_driver);
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c
--- v2.1.86/linux/arch/m68k/atari/joystick.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/atari/joystick.c	Thu Feb 12 16:30:12 1998
@@ -82,15 +82,16 @@
     return 0;
 }
 
-static long write_joystick(struct inode *inode, struct file *file,
-			   const char *buffer, unsigned long count)
+static ssize_t write_joystick(struct file *file, const char *buffer,
+			      size_t count, loff_t *ppos)
 {
     return -EINVAL;
 }
 
-static long read_joystick(struct inode *inode, struct file *file,
-			  char *buffer, unsigned long count)
+static ssize_t read_joystick(struct file *file, char *buffer, size_t count,
+			     loff_t *ppos)
 {
+    struct inode *inode = file->f_dentry->d_inode;
     int minor = DEVICE_NR(inode->i_rdev);
 
     if (count < 2)
@@ -109,7 +110,7 @@
 
 static unsigned int joystick_poll(struct file *file, poll_table *wait)
 {
-    int minor = DEVICE_NR(file->f_inode->i_rdev);
+    int minor = DEVICE_NR(file->f_dentry->d_inode->i_rdev);
 
     poll_wait(&joystick[minor].wait, wait);
     if (joystick[minor].ready)
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c
--- v2.1.86/linux/arch/m68k/atari/stdma.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/atari/stdma.c	Thu Feb 12 16:30:12 1998
@@ -1,6 +1,5 @@
-
 /*
- *  linux/atari/stmda.c
+ *  linux/arch/m68k/atari/stmda.c
  *
  *  Copyright (C) 1994 Roman Hodek
  *
@@ -37,7 +36,6 @@
 #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>
 
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c
--- v2.1.86/linux/arch/m68k/atari/stram.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/atari/stram.c	Thu Feb 12 16:30:12 1998
@@ -1,157 +1,56 @@
+/*
+ * arch/m68k/atari/stram.c: Functions for ST-RAM allocations
+ *
+ * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/swap.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
 #include <asm/setup.h>
-#include <asm/atarihw.h>
+#include <asm/machdep.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/atarihw.h>
+#include <asm/atari_stram.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 = atari_stram_start;
-  stramsize = 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);
+#ifdef CONFIG_STRAM_SWAP
+#define MAJOR_NR    Z2RAM_MAJOR
+#include <linux/blk.h>
+#undef DEVICE_NAME
+#define DEVICE_NAME	"stram"
 #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);
+#undef DEBUG
 
 #ifdef DEBUG
-      printk ("stram_alloc: splitting %d to %ld\n", dp->length,
-	      newsize);
+#define	DPRINTK(fmt,args...) printk( fmt, ##args )
+#else
+#define DPRINTK(fmt,args...)
 #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);
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC)
+/* abbrev for the && above... */
+#define DO_PROC
+#include <linux/proc_fs.h>
 #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>
-#include <linux/init.h>
-
-/* ++roman:
+/* Pre-swapping comments:
+ *
+ * ++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
@@ -173,72 +72,1414 @@
  * 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.)
+ */
+
+/*
+ * New Nov 1997: Use ST-RAM as swap space!
+ *
+ * In the past, there were often problems with modules that require ST-RAM
+ * buffers. Such drivers have to use __get_dma_pages(), which unfortunately
+ * often isn't very successful in allocating more than 1 page :-( [1] The net
+ * result was that most of the time you couldn't insmod such modules (ataflop,
+ * ACSI, SCSI on Falcon, Atari internal framebuffer, not to speak of acsi_slm,
+ * which needs a 1 MB buffer... :-).
+ *
+ * To overcome this limitation, ST-RAM can now be turned into a very
+ * high-speed swap space. If a request for an ST-RAM buffer comes, the kernel
+ * now tries to unswap some pages on that swap device to make some free (and
+ * contiguous) space. This works much better in comparison to
+ * __get_dma_pages(), since used swap pages can be selectively freed by either
+ * moving them to somewhere else in swap space, or by reading them back into
+ * system memory. Ok, there operation of unswapping isn't really cheap (for
+ * each page, one has to go through the page tables of all processes), but it
+ * doesn't happen that often (only when allocation ST-RAM, i.e. when loading a
+ * module that needs ST-RAM). But it at least makes it possible to load such
+ * modules!
+ *
+ * It could also be that overall system performance increases a bit due to
+ * ST-RAM swapping, since slow ST-RAM isn't used anymore for holding data or
+ * executing code in. It's then just a (very fast, compared to disk) back
+ * storage for not-so-often needed data. (But this effect must be compared
+ * with the loss of total memory...) Don't know if the effect is already
+ * visible on a TT, where the speed difference between ST- and TT-RAM isn't
+ * that dramatic, but it should on machines where TT-RAM is really much faster
+ * (e.g. Afterburner).
  * 
+ *   [1]: __get_free_pages() does a fine job if you only want one page, but if
+ * you want more (contiguous) pages, it can give you such a block only if
+ * there's already a free one. The algorithm can't try to free buffers or swap
+ * out something in order to make more free space, since all that page-freeing
+ * mechanisms work "target-less", i.e. they just free something, but not in a
+ * specific place. I.e., __get_free_pages() can't do anything to free
+ * *adjacent* pages :-( This situation becomes even worse for DMA memory,
+ * since the freeing algorithms are also blind to DMA capability of pages.
+ */
+
+#ifdef CONFIG_STRAM_SWAP
+#define ALIGN_IF_SWAP(x)	PAGE_ALIGN(x)
+#else
+#define ALIGN_IF_SWAP(x)	(x)
+#endif
+
+/* map entry for reserved swap page (used as buffer) */
+#define SWP_RSVD			0x80
+
+/* get index of swap page at address 'addr' */
+#define SWAP_NR(addr)		(((unsigned long)(addr)-swap_start) >> PAGE_SHIFT)
+
+/* get address of swap page #'nr' */
+#define SWAP_ADDR(nr)		((void *)(swap_start + ((nr)<<PAGE_SHIFT)))
+
+/* get number of pages for 'n' bytes (already page-aligned) */
+#define N_PAGES(n)			((n) >> PAGE_SHIFT)
+
+/* The following two numbers define the maximum fraction of ST-RAM in total
+ * memory, below that the kernel would automatically use ST-RAM as swap
+ * space. This decision can be overriden with stram_swap= */
+#define MAX_STRAM_FRACTION_NOM		1
+#define MAX_STRAM_FRACTION_DENOM	3
+
+/* Start and end of the (pre-mem_init) reserved ST-RAM region */
+static unsigned long rsvd_stram_beg, rsvd_stram_end;
+
+/* Start and end (virtual) of ST-RAM */
+static unsigned long stram_start, stram_end;
+
+/* set after memory_init() executed and allocations via start_mem aren't
+ * possible anymore */
+static int mem_init_done = 0;
+
+/* set if kernel is in ST-RAM */
+static int kernel_in_stram;
+
+typedef struct stram_block {
+	struct stram_block *next;
+	unsigned long start;
+	unsigned long size;
+	unsigned flags;
+	const char *owner;
+} BLOCK;
+
+/* values for flags field */
+#define BLOCK_FREE		0x01	/* free structure in the BLOCKs pool */
+#define BLOCK_KMALLOCED	0x02	/* structure allocated by kmalloc() */
+#define BLOCK_STATIC	0x04	/* pre-mem_init() allocated block */
+#define BLOCK_GFP		0x08	/* block allocated with __get_dma_pages() */
+#define BLOCK_INSWAP	0x10	/* block allocated in swap space */
+
+/* list of allocated blocks */
+static BLOCK *alloc_list = NULL;
+
+/* We can't always use kmalloc() to allocate BLOCK structures, since
+ * stram_alloc() can be called rather early. So we need some pool of
+ * statically allocated structures. 20 of them is more than enough, so in most
+ * cases we never should need to call kmalloc(). */
+#define N_STATIC_BLOCKS	20
+static BLOCK static_blocks[N_STATIC_BLOCKS];
+
+#ifdef CONFIG_STRAM_SWAP
+/* max. number of bytes to use for swapping
+ *  0 = no ST-RAM swapping
+ * -1 = do swapping (to whole ST-RAM) if it's less than MAX_STRAM_FRACTION of
+ *      total memory
  */
-   
+static int max_swap_size = -1;
 
-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 */
+/* start and end of swapping area */
+static unsigned long swap_start, swap_end;
 
+/* The ST-RAM's swap info structure */
+static struct swap_info_struct *stram_swap_info;
 
+/* The ST-RAM's swap type */
+static int stram_swap_type;
+
+/* major and minor device number of the ST-RAM device; for the major, we use
+ * the same as Amiga z2ram, which is really similar and impossible on Atari,
+ * and for the minor a relatively odd number to avoid the user creating and
+ * using that device. */
+#define	STRAM_MAJOR		Z2RAM_MAJOR
+#define	STRAM_MINOR		13
+
+/* Some impossible pointer value */
+#define MAGIC_FILE_P	(struct file *)0xffffdead
+
+#ifdef DO_PROC
+static unsigned stat_swap_read = 0;
+static unsigned stat_swap_write = 0;
+static unsigned stat_swap_move = 0;
+static unsigned stat_swap_force = 0;
+#endif /* DO_PROC */
+
+#endif /* CONFIG_STRAM_SWAP */
+
+/***************************** Prototypes *****************************/
+
+#ifdef CONFIG_STRAM_SWAP
+static int swap_init( unsigned long start_mem, unsigned long swap_data );
+static inline int unswap_pte( struct vm_area_struct * vma, unsigned long
+                              address, pte_t *dir, unsigned long entry,
+                              unsigned long page, int isswap );
+static inline int unswap_pmd( struct vm_area_struct * vma, pmd_t *dir,
+                              unsigned long address, unsigned long size,
+                              unsigned long offset, unsigned long entry,
+                              unsigned long page, int isswap );
+static inline int unswap_pgd( struct vm_area_struct * vma, pgd_t *dir,
+                              unsigned long address, unsigned long size,
+                              unsigned long entry, unsigned long page, int
+                              isswap );
+static int unswap_vma( struct vm_area_struct * vma, pgd_t *pgdir, unsigned
+                       long entry, unsigned long page, int isswap );
+static int unswap_process( struct mm_struct * mm, unsigned long entry,
+                           unsigned long page, int isswap );
+static int unswap_by_move( unsigned char *map, unsigned long max, unsigned
+                           long start, unsigned long n_pages );
+static int unswap_by_read( unsigned char *map, unsigned long max, unsigned
+                           long start, unsigned long n_pages );
+static void *get_stram_region( unsigned long n_pages );
+static void free_stram_region( unsigned long offset, unsigned long n_pages
+                               );
+static int in_some_region( unsigned long addr );
+static unsigned long find_free_region( unsigned long n_pages, unsigned long
+                                       *total_free, unsigned long
+                                       *region_free );
+static void do_stram_request( void );
+static int stram_open( struct inode *inode, struct file *filp );
+static int stram_release( struct inode *inode, struct file *filp );
+static void do_z2_request( void );
+#endif
+static int get_gfp_order( unsigned long size );
+static void reserve_region( unsigned long addr, unsigned long end );
+static BLOCK *add_region( void *addr, unsigned long size );
+static BLOCK *find_region( void *addr );
+static int remove_region( BLOCK *block );
+
+/************************* End of Prototypes **************************/
+
+
+/* ------------------------------------------------------------------------ */
+/*							   Public Interface								*/
+/* ------------------------------------------------------------------------ */
+
+/*
+ * This init function is called very early by atari/config.c
+ * It initializes some internal variables needed for stram_alloc()
+ */
 __initfunc(void atari_stram_init( void ))
+{
+	int i;
 
-{	int		i;
+	/* initialize static blocks */
+	for( i = 0; i < N_STATIC_BLOCKS; ++i )
+		static_blocks[i].flags = BLOCK_FREE;
+
+	/* determine whether kernel code resides in ST-RAM (then ST-RAM is the
+	 * first memory block at virtual 0x0) */
+	stram_start = PTOV( 0 );
+	kernel_in_stram = (stram_start == 0);
 
 	for( i = 0; i < m68k_num_memory; ++i ) {
 		if (m68k_memory[i].addr == 0) {
-			rsvd_stram_beg = PTOV( 0x800 ); /* skip super-only first 2 KB! */
+			/* skip first 2kB or page (supervisor-only!) */
+			rsvd_stram_beg = stram_start + ALIGN_IF_SWAP(0x800);
 			rsvd_stram_end = rsvd_stram_beg;
-			stram_end = rsvd_stram_beg - 0x800 + m68k_memory[i].size;
+			stram_end = stram_start + m68k_memory[i].size;
 			return;
 		}
 	}
 	/* Should never come here! (There is always ST-Ram!) */
+	panic( "atari_stram_init: no ST-RAM found!" );
 }
 
 
-void *atari_stram_alloc( long size, unsigned long *start_mem )
+/*
+ * This function is called from mem_init() to reserve the pages needed for
+ * ST-RAM management.
+ */
+__initfunc(void atari_stram_reserve_pages( unsigned long start_mem ))
+{
+#ifdef CONFIG_STRAM_SWAP
+	/* if max_swap_size is negative (i.e. no stram_swap= option given),
+	 * determine at run time whether to use ST-RAM swapping */
+	if (max_swap_size < 0)
+		/* Use swapping if ST-RAM doesn't make up more than MAX_STRAM_FRACTION
+		 * of total memory. In that case, the max. size is set to 16 MB,
+		 * because ST-RAM can never be bigger than that.
+		 * Also, never use swapping on a Hades, there's no separate ST-RAM in
+		 * that machine. */
+		max_swap_size =
+			(!MACH_IS_HADES &&
+			 (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <=
+			  max_mapnr*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0;
+	DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size );
+#endif
 
+	/* always reserve first page of ST-RAM, the first 2 kB are
+	 * supervisor-only! */
+	set_bit( PG_reserved, &mem_map[MAP_NR(stram_start)].flags );
+
+#ifdef CONFIG_STRAM_SWAP
+	if (!max_swap_size) {
+	  fallback:
+#endif
+		DPRINTK( "atari_stram_reserve_pages: swapping disabled\n" );
+		if (!kernel_in_stram) {
+			/* Reserve all pages that have been marked by pre-mem_init
+			 * stram_alloc() (e.g. for the screen memory). */
+			reserve_region( rsvd_stram_beg, rsvd_stram_end );
+			DPRINTK( "atari_stram_reserve_pages: reseverved %08lx-%08lx\n",
+					 rsvd_stram_beg, rsvd_stram_end );
+		}
+		/* else (kernel in ST-RAM): nothing to do, ST-RAM buffers are
+		 * kernel data */
+#ifdef CONFIG_STRAM_SWAP
+	}
+	else {
+		unsigned long swap_data;
+		BLOCK *p;
+
+		/* determine first page to use as swap:
+		 * if the kernel is in TT-RAM, this is the first page of (usable)
+		 * ST-RAM; else if there were already some allocations (probable...),
+		 * use the lowest address of these (the list is sorted by address!);
+		 * otherwise just use the end of kernel data (= start_mem) */
+		swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE :
+					 alloc_list ? alloc_list->start :
+					 start_mem;
+		/* decrement by one page, rest of kernel assumes that first swap page
+		 * is always reserved and maybe doesn't handle SWP_ENTRY == 0
+		 * correctly */
+		swap_start -= PAGE_SIZE;
+		swap_end = stram_end;
+		if (swap_end-swap_start > max_swap_size)
+			swap_end =  swap_start + max_swap_size;
+		DPRINTK( "atari_stram_reserve_pages: swapping enabled; "
+				 "swap=%08lx-%08lx\n", swap_start, swap_end );
+		
+		/* reserve some amount of memory for maintainance of swapping itself:
+		 * 1 page for the lockmap, and one page for each 4096 (PAGE_SIZE) swap
+		 * pages. (1 byte for each page) */
+		swap_data = start_mem;
+		start_mem += PAGE_ALIGN(SWAP_NR(swap_end)) + PAGE_SIZE;
+		/* correct swap_start if necessary */
+		if (swap_start == swap_data)
+			swap_start = start_mem;
+		
+		if (!swap_init( start_mem, swap_data )) {
+			printk( KERN_ERR "ST-RAM swap space initialization failed\n" );
+			max_swap_size = 0;
+			goto fallback;
+		}
+		/* reserve region for swapping meta-data */
+		reserve_region( swap_data, start_mem );
+		/* reserve swapping area itself */
+		reserve_region( swap_start+PAGE_SIZE, swap_end );
+
+		/* Formerly static areas have been included in the swap area. */
+		for( p = alloc_list; p; p = p->next ) {
+			if (p->flags & BLOCK_STATIC)
+				p->flags = (p->flags & ~BLOCK_STATIC) | BLOCK_INSWAP;
+		}
+
+		/*
+		 * If the whole ST-RAM is used for swapping, there are no allocatable
+		 * dma pages left. But unfortunately, some shared parts of the kernel
+		 * (particularily the SCSI mid-level) call __get_dma_pages()
+		 * unconditionally :-( These calls then fail, and scsi.c even doesn't
+		 * check for NULL return values and just crashes. The quick fix for
+		 * this (instead of doing much clean up work in the SCSI code) is to
+		 * pretend all pages are DMA-able by setting mach_max_dma_address to
+		 * ULONG_MAX. This doesn't change any functionality so far, since
+		 * get_dma_pages() shouldn't be used on Atari anyway anymore (better
+		 * use atari_stram_alloc()), and the Atari SCSI drivers don't need DMA
+		 * memory. But unfortunately there's now no kind of warning (even not
+		 * a NULL return value) if you use get_dma_pages() nevertheless :-(
+		 * You just will get non-DMA-able memory...
+		 */
+		mach_max_dma_address = 0xffffffff;
+
+		/*
+		 * Ok, num_physpages needs not be really exact, but it's better to
+		 * subtract the pages set aside for swapping.
+		 */
+		num_physpages -= SWAP_NR(swap_end)-1;
+	}
+#endif
+	
+	mem_init_done = 1;
+}
+
+
+/*
+ * This is main public interface: somehow allocate a ST-RAM block
+ * There are three strategies:
+ * 
+ *  - If we're before mem_init(), we have to make a static allocation. The
+ *    region is taken in the kernel data area (if the kernel is in ST-RAM) or
+ *    from the start of ST-RAM (if the kernel is in TT-RAM) and added to the
+ *    rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel
+ *    address space in the latter case.
+ * 
+ *  - If mem_init() already has been called and ST-RAM swapping is enabled,
+ *    try to get the memory from the (pseudo) swap-space, either free already
+ *    or by moving some other pages out of the swap.
+ *
+ *  - If mem_init() already has been called, and ST-RAM swapping is not
+ *    enabled, the only possibility is to try with __get_dma_pages(). This has
+ *    the disadvantage that it's very hard to get more than 1 page, and it is
+ *    likely to fail :-(
+ * 
+ */
+void *atari_stram_alloc( long size, unsigned long *start_mem,
+						 const char *owner )
 {
-	static int				kernel_in_stram = -1;
+	void *addr = NULL;
+	BLOCK *block;
+	int flags;
+
+	DPRINTK( "atari_stram_alloc(size=%08lx,*start_mem=%08lx,owner=%s)\n",
+			 size, start_mem ? *start_mem : 0xffffffff, owner );
 	
-	void	*adr = 0;
+	if (start_mem && mem_init_done) {
+		printk( KERN_ERR "atari_stram_alloc called with start_mem!=NULL "
+				"after mem_init() from %p\n", __builtin_return_address(0) );
+		return( NULL );
+	}
+	if (!start_mem && !mem_init_done) {
+		printk( KERN_ERR "atari_stram_alloc called with start_mem==NULL "
+				"before mem_init() from %p\n", __builtin_return_address(0) );
+		return( NULL );
+	}
+
+	size = ALIGN_IF_SWAP(size);
+	DPRINTK( "atari_stram_alloc: rounded size = %08lx\n", size );
+	if (!mem_init_done) {
+		/* before mem_init(): allocate "statically", i.e. either in the kernel
+		 * data space (current end in *start_mem), or at the end of currently
+		 * reserved ST-RAM. */
+		if (kernel_in_stram) {
+			/* Get memory from kernel data space */
+			*start_mem = ALIGN_IF_SWAP(*start_mem);
+			addr = (void *)*start_mem;
+			*start_mem += size;
+			DPRINTK( "atari_stram_alloc: pre-mem_init and k/ST: "
+					 "shifted start_mem to %08lx, addr=%p\n",
+					 *start_mem, addr );
+		}
+		else {
+			/* Get memory from rsvd_stram_beg */
+			if (rsvd_stram_end + size < stram_end) {
+				addr = (void *) rsvd_stram_end;
+				rsvd_stram_end += size;
+				DPRINTK( "atari_stram_alloc: pre-mem_init and k/TT: "
+						 "shifted rsvd_stram_end to %08lx, addr=%p\n",
+						 rsvd_stram_end, addr );
+			}
+		}
+		flags = BLOCK_STATIC;
+	}
+#ifdef CONFIG_STRAM_SWAP
+	else if (max_swap_size) {
+		/* If swapping is active (can only be the case after mem_init()!):
+		 * make some free space in the swap "device". */
+		DPRINTK( "atari_stram_alloc: after mem_init, swapping ok, "
+				 "calling get_region\n" );
+		addr = get_stram_region( N_PAGES(size) );
+		flags = BLOCK_INSWAP;
+	}
+#endif
+	else {
+		/* After mem_init() and no swapping: can only resort to
+		 * __get_dma_pages() */
+		addr = (void *)__get_dma_pages(GFP_KERNEL, get_gfp_order(size));
+		flags = BLOCK_GFP;
+		DPRINTK( "atari_stram_alloc: after mem_init, swapping off, "
+				 "get_pages=%p\n", addr );
+	}
+
+	if (addr) {
+		if (!(block = add_region( addr, size ))) {
+			/* out of memory for BLOCK structure :-( */
+			DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- "
+					 "freeing again\n" );
+			if (flags == BLOCK_STATIC)
+				rsvd_stram_end -= size;
+#ifdef CONFIG_STRAM_SWAP
+			else if (flags == BLOCK_INSWAP)
+				free_stram_region( SWAP_NR(addr), N_PAGES(size) );
+#endif
+			else
+				free_pages( (unsigned long)addr, get_gfp_order(size));
+			return( NULL );
+		}
+		block->owner = owner;
+		block->flags |= flags;
+	}
+	return( addr );
+}
+
+void atari_stram_free( void *addr )
+
+{
+	BLOCK *block;
+
+	DPRINTK( "atari_stram_free(addr=%p)\n", addr );
+
+	if (!(block = find_region( addr ))) {
+		printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p "
+				"from %p\n", addr, __builtin_return_address(0) );
+		return;
+	}
+	DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, "
+			 "flags=%02x\n", block, block->size, block->owner, block->flags );
 	
-	if (kernel_in_stram < 0)
-		kernel_in_stram = (PTOV( 0 ) == 0);
+#ifdef CONFIG_STRAM_SWAP
+	if (!max_swap_size) {
+#endif
+		if (block->flags & BLOCK_GFP) {
+			DPRINTK( "atari_stram_free: is kmalloced, order_size=%d\n",
+					 get_gfp_order(block->size) );
+			free_pages( (unsigned long)addr, get_gfp_order(block->size) );
+		}
+		else
+			goto fail;
+#ifdef CONFIG_STRAM_SWAP
+	}
+	else if (block->flags & (BLOCK_INSWAP|BLOCK_STATIC)) {
+		DPRINTK( "atari_stram_free: is swap-alloced\n" );
+		free_stram_region( SWAP_NR(block->start), N_PAGES(block->size) );
+	}
+	else
+		goto fail;
+#endif
+	remove_region( block );
+	return;
+
+  fail:
+	printk( KERN_ERR "atari_stram_free: cannot free block at %p "
+			"(called from %p)\n", addr, __builtin_return_address(0) );
+}
+
+
+#ifdef CONFIG_STRAM_SWAP
+
+
+/* ------------------------------------------------------------------------ */
+/*						   Main Swapping Functions							*/
+/* ------------------------------------------------------------------------ */
 
-	if (kernel_in_stram) {
-		/* Get memory from kernel data space */
-		adr = (void *) *start_mem;
-		*start_mem += size;
+
+/*
+ * Initialize ST-RAM swap device
+ * (lots copied and modified from sys_swapon() in mm/swapfile.c)
+ */
+__initfunc(static int swap_init( unsigned long start_mem,
+								 unsigned long swap_data ))
+{
+	static struct dentry fake_dentry[3];
+	struct swap_info_struct *p;
+	struct inode swap_inode;
+	unsigned int type;
+	unsigned long addr;
+	int i, j, k, prev;
+
+	DPRINTK( "swap_init(start_mem=%08lx, swap_data=%08lx)\n",
+			 start_mem, swap_data );
+	
+	/* need at least one page for swapping to (and this also isn't very
+	 * much... :-) */
+	if (swap_end - swap_start < 2*PAGE_SIZE) {
+		printk( KERN_WARNING "stram_swap_init: swap space too small\n" );
+		return( 0 );
+	}
+	
+	/* find free slot in swap_info */
+	for( p = swap_info, type = 0; type < nr_swapfiles; type++, p++ )
+		if (!(p->flags & SWP_USED))
+			break;
+	if (type >= MAX_SWAPFILES) {
+		printk( KERN_WARNING "stram_swap_init: max. number of "
+				"swap devices exhausted\n" );
+		return( 0 );
+	}
+	if (type >= nr_swapfiles)
+		nr_swapfiles = type+1;
+
+	stram_swap_info = p;
+	stram_swap_type = type;
+
+	/* fake some dir cache entries to give us some name in /dev/swaps */
+	fake_dentry[0].d_covers = &fake_dentry[1];
+	fake_dentry[0].d_parent = &fake_dentry[0];
+	fake_dentry[1].d_parent = &fake_dentry[2];
+	fake_dentry[1].d_name.name = "stram (internal)";
+	fake_dentry[1].d_name.len = 16;
+	fake_dentry[2].d_covers = &fake_dentry[2];
+	fake_dentry[2].d_parent = &fake_dentry[2];
+	
+	p->flags        = SWP_USED;
+	p->swap_file    = &fake_dentry[0];
+	p->swap_device  = 0;
+	p->swap_lockmap = (unsigned char *)(swap_data);
+	p->swap_map	    = (unsigned char *)(swap_data + PAGE_SIZE);
+	p->cluster_nr   = 0;
+	p->next         = -1;
+	p->prio         = 0x7ff0;	/* a rather high priority, but not the higest
+								 * to give the user a chance to override */
+
+	/* call stram_open() directly, avoids at least the overhead in
+	 * constructing a dummy file structure... */
+	p->swap_device = MKDEV( STRAM_MAJOR, STRAM_MINOR );
+	swap_inode.i_rdev = p->swap_device;
+	stram_open( &swap_inode, MAGIC_FILE_P );
+	p->max = SWAP_NR(swap_end);
+
+	/* initialize lockmap */
+	memset( p->swap_lockmap, 0, PAGE_SIZE );
+
+	/* initialize swap_map: set regions that are already allocated or belong
+	 * to kernel data space to SWP_RSVD, otherwise to free */
+	j = 0; /* # of free pages */
+	k = 0; /* # of already allocated pages (from pre-mem_init stram_alloc()) */
+	p->lowest_bit = 0;
+	p->highest_bit = 0;
+	for( i = 1, addr = (unsigned long)SWAP_ADDR(1); i < p->max;
+		 i++, addr += PAGE_SIZE ) {
+		if (in_some_region( addr )) {
+			p->swap_map[i] = SWP_RSVD;
+			++k;
+		}
+		else if (kernel_in_stram && addr < start_mem ) {
+			p->swap_map[i] = SWP_RSVD;
+		}
+		else {
+			p->swap_map[i] = 0;
+			++j;
+			if (!p->lowest_bit) p->lowest_bit = i;
+			p->highest_bit = i;
+		}
+	}
+	/* first page always reserved (and doesn't really belong to swap space) */
+	p->swap_map[0] = SWP_RSVD;
+
+	/* now swapping to this device ok */
+	p->pages = j + k;
+	nr_swap_pages += j;
+	p->flags = SWP_WRITEOK;
+
+	/* insert swap space into swap_list */
+	prev = -1;
+	for (i = swap_list.head; i >= 0; i = swap_info[i].next) {
+		if (p->prio >= swap_info[i].prio) {
+			break;
+		}
+		prev = i;
+	}
+	p->next = i;
+	if (prev < 0) {
+		swap_list.head = swap_list.next = p - swap_info;
+	} else {
+		swap_info[prev].next = p - swap_info;
+	}
+
+	printk( KERN_INFO "Using %dk (%d pages) of ST-RAM as swap space.\n",
+			p->pages << 2, p->pages );
+	return( 1 );
+}
+
+
+/*
+ * The swap entry has been read in advance, and we return 1 to indicate
+ * that the page has been used or is no longer needed.
+ */
+static inline int unswap_pte( struct vm_area_struct * vma, unsigned long
+							  address, pte_t *dir, unsigned long entry,
+							  unsigned long page, int isswap )
+{
+	pte_t pte = *dir;
+
+	if (pte_none(pte))
+		return 0;
+	if (pte_present(pte)) {
+		struct page *pg;
+		unsigned long page_nr = MAP_NR(pte_page(pte));
+		unsigned long pg_swap_entry;
+
+		if (page_nr >= max_mapnr)
+			return 0;
+		pg = mem_map + page_nr;
+		if (!(pg_swap_entry = in_swap_cache(pg)))
+			return 0;
+		if (pg_swap_entry != entry)
+			return 0;
+		if (isswap) {
+			DPRINTK( "unswap_pte: page %08lx = entry %08lx was in swap cache; "
+					 "exchanging to %08lx\n",
+					 page_address(pg), entry, page );
+			pg->offset = page;
+			swap_free(entry);
+			return 1;
+		}
+		else {
+			DPRINTK( "unswap_pte: page %08lx = entry %08lx was in swap cache; "
+					 "deleted there\n", page_address(pg), entry );
+			delete_from_swap_cache(pg);
+			set_pte(dir, pte_mkdirty(pte));
+			free_page(page);
+			return 1;
+		}
+	}
+	if (pte_val(pte) != entry)
+		return 0;
+
+	if (isswap) {
+		DPRINTK( "unswap_pte: replacing entry %08lx by %08lx", entry, page );
+		set_pte(dir, __pte(page));
 	}
 	else {
-		/* Get memory from rsvd_stram_beg */
-		if (rsvd_stram_end + size < stram_end) {
-			adr = (void *) rsvd_stram_end;
-			rsvd_stram_end += size;
+		DPRINTK( "unswap_pte: replacing entry %08lx by new page %08lx",
+				 entry, page );
+		set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page,vma->vm_page_prot))));
+		++vma->vm_mm->rss;
+	}
+	swap_free(entry);
+	return 1;
+}
+
+static inline int unswap_pmd( struct vm_area_struct * vma, pmd_t *dir,
+							  unsigned long address, unsigned long size,
+							  unsigned long offset, unsigned long entry,
+							  unsigned long page, int isswap )
+{
+	pte_t * pte;
+	unsigned long end;
+
+	if (pmd_none(*dir))
+		return 0;
+	if (pmd_bad(*dir)) {
+		printk("unswap_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
+		pmd_clear(dir);
+		return 0;
+	}
+	pte = pte_offset(dir, address);
+	offset += address & PMD_MASK;
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		if (unswap_pte( vma, offset+address-vma->vm_start, pte, entry, 
+						page, isswap ))
+			return 1;
+		address += PAGE_SIZE;
+		pte++;
+	} while (address < end);
+	return 0;
+}
+
+static inline int unswap_pgd( struct vm_area_struct * vma, pgd_t *dir,
+							  unsigned long address, unsigned long size,
+							  unsigned long entry, unsigned long page,
+							  int isswap )
+{
+	pmd_t * pmd;
+	unsigned long offset, end;
+
+	if (pgd_none(*dir))
+		return 0;
+	if (pgd_bad(*dir)) {
+		printk("unswap_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
+		pgd_clear(dir);
+		return 0;
+	}
+	pmd = pmd_offset(dir, address);
+	offset = address & PGDIR_MASK;
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	do {
+		if (unswap_pmd( vma, pmd, address, end - address, offset, entry,
+						page, isswap ))
+			return 1;
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+	return 0;
+}
+
+static int unswap_vma( struct vm_area_struct * vma, pgd_t *pgdir,
+					   unsigned long entry, unsigned long page, int isswap )
+{
+	unsigned long start = vma->vm_start, end = vma->vm_end;
+
+	while( start < end ) {
+		if (unswap_pgd( vma, pgdir, start, end - start, entry, page, isswap ))
+			return 1;
+		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+		pgdir++;
+	}
+	return 0;
+}
+
+static int unswap_process( struct mm_struct * mm, unsigned long entry, 
+						   unsigned long page, int isswap )
+{
+	struct vm_area_struct* vma;
+
+	/*
+	 * Go through process' page directory.
+	 */
+	if (!mm || mm == &init_mm)
+		return 0;
+	for( vma = mm->mmap; vma; vma = vma->vm_next ) {
+		pgd_t * pgd = pgd_offset(mm, vma->vm_start);
+		if (unswap_vma( vma, pgd, entry, page, isswap ))
+			return 1;
+	}
+	return 0;
+}
+
+
+static int unswap_by_move( unsigned char *map, unsigned long max,
+						   unsigned long start, unsigned long n_pages )
+{
+	struct task_struct *p;
+	unsigned long entry, rover = (start == 1) ? n_pages+1 : 1;
+	unsigned long i, j;
+
+	DPRINTK( "unswapping %lu..%lu by moving in swap\n",
+			 start, start+n_pages-1 );
+	
+	/* can free the allocated pages by moving them to other swap pages */
+	for( i = start; i < start+n_pages; ++i ) {
+		if (!map[i]) {
+			map[i] = SWP_RSVD;
+			DPRINTK( "unswap: page %lu was free\n", i );
+			continue;
+		}
+		else if (map[i] == SWP_RSVD) {
+			printk( KERN_ERR "get_stram_region: page %lu already "
+					"reserved??\n", i );
+		}
+		DPRINTK( "unswap: page %lu is alloced, count=%u\n", i, map[i] );
+
+		/* find a free page not in our region */
+		for( j = rover; j != rover-1; j = (j == max-1) ? 1 : j+1 ) {
+			if (j >= start && j < start+n_pages)
+				continue;
+			if (!map[j]) {
+				rover = j+1;
+				break;
+			}
+		}
+		if (j == rover-1) {
+			printk( KERN_ERR "get_stram_region: not enough free swap "
+					"pages now??\n" );
+			return( -ENOMEM );
+		}
+		DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n",
+				 i, map[i], j, map[j], nr_swap_pages );
+		
+		--nr_swap_pages;
+		entry = SWP_ENTRY( stram_swap_type, j );
+		if (stram_swap_info->lowest_bit == j)
+			stram_swap_info->lowest_bit++;
+		if (stram_swap_info->highest_bit == j)
+			stram_swap_info->highest_bit--;
+		
+		memcpy( SWAP_ADDR(j), SWAP_ADDR(i), PAGE_SIZE );
+#ifdef DO_PROC
+		stat_swap_move++;
+#endif
+
+		while( map[i] ) {
+			for_each_task(p) {
+				if (unswap_process( p->mm, SWP_ENTRY( stram_swap_type, i ),
+									entry, 1 )) {
+					map[j]++;
+					goto repeat;
+				}
+			}
+			if (map[i] && map[i] != 127) {
+				printk( KERN_ERR "get_stram_region: ST-RAM swap page %lu "
+						"not used by any process\n", i );
+				/* quit while loop and overwrite bad map entry */
+				break;
+			}
+			else if (!map[i]) {
+				/* somebody else must have swapped in that page, so free the
+				 * new one (we're moving to) */
+				DPRINTK( "unswap: map[i] became 0, also clearing map[j]\n" );
+				map[j] = 0;
+			}
+		  repeat:
+		}
+
+		DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n",
+				 i, map[i], j, map[j], nr_swap_pages );
+		map[i] = SWP_RSVD;
+		if (stram_swap_info->lowest_bit == i)
+			stram_swap_info->lowest_bit++;
+		if (stram_swap_info->highest_bit == i)
+			stram_swap_info->highest_bit--;
+		--nr_swap_pages;
+	}
+	return( 0 );
+}
+
+static int unswap_by_read( unsigned char *map, unsigned long max,
+						   unsigned long start, unsigned long n_pages )
+{
+	struct task_struct *p;
+	unsigned long entry, page = 0;
+	unsigned long i;
+
+	DPRINTK( "unswapping %lu..%lu by reading in\n",
+			 start, start+n_pages-1 );
+
+	for( i = start; i < start+n_pages; ++i ) {
+		if (map[i] == SWP_RSVD) {
+			printk( KERN_ERR "get_stram_region: page %lu already "
+					"reserved??\n", i );
+			continue;
+		}
+		entry = SWP_ENTRY( stram_swap_type, i );
+		DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n",
+				 i, map[i], nr_swap_pages );
+
+		while( map[i] ) {
+			if (!page && !(page = __get_free_page(GFP_KERNEL))) {
+				printk( KERN_NOTICE "get_stram_region: out of memory\n" );
+				return( -ENOMEM );
+			}
+			DPRINTK( "unswap: reading swap page %lu to %08lx\n", i, page );
+			read_swap_page( entry, (char *)page );
+
+			for_each_task(p) {
+				if (unswap_process( p->mm, entry, page, 0 )) {
+					page = 0;
+#ifdef DO_PROC
+					stat_swap_force++;
+#endif
+					break;
+				}
+			}
+			if (page) {
+				/*
+				 * If we couldn't find an entry, there are several
+				 * possible reasons: someone else freed it first,
+				 * we freed the last reference to an overflowed entry,
+				 * or the system has lost track of the use counts.
+				 */
+				if (map[i] && map[i] != SWP_RSVD-1)
+					printk( KERN_ERR "get_stram_region: swap entry %08lx "
+							"not used by any process\n", entry );
+				/* quit while loop and overwrite bad map entry */
+				if (!map[i]) {
+					DPRINTK( "unswap: map[i] became 0\n" );
+				}
+				break;
+			}
+		}
+
+		DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n",
+				 i, map[i], nr_swap_pages );
+		map[i] = SWP_RSVD;
+		if (stram_swap_info->lowest_bit == i)
+			stram_swap_info->lowest_bit++;
+		if (stram_swap_info->highest_bit == i)
+			stram_swap_info->highest_bit--;
+		--nr_swap_pages;
+	}
+
+	if (page)
+		free_page(page);
+	return( 0 );
+}
+
+/*
+ * reserve a region in ST-RAM swap space for an allocation
+ */
+static void *get_stram_region( unsigned long n_pages )
+{
+	unsigned char *map = stram_swap_info->swap_map;
+	unsigned long max = stram_swap_info->max;
+	unsigned long start, total_free, region_free;
+	int err;
+	void *ret = NULL;
+	
+	DPRINTK( "get_stram_region(n_pages=%lu)\n", n_pages );
+	
+	/* disallow writing to the swap device now */
+	stram_swap_info->flags = SWP_USED;
+
+	/* find a region of n_pages pages in the swap space including as much free
+	 * pages as possible (and excluding any already-reserved pages). */
+	if (!(start = find_free_region( n_pages, &total_free, &region_free )))
+		goto end;
+	DPRINTK( "get_stram_region: region starts at %lu, has %lu free pages\n",
+			 start, region_free );
+
+	err = ((total_free-region_free >= n_pages-region_free) ?
+		   unswap_by_move( map, max, start, n_pages ) :
+		   unswap_by_read( map, max, start, n_pages ));
+	if (err)
+		goto end;
+
+	ret = SWAP_ADDR(start);
+  end:
+	/* allow using swap device again */
+	stram_swap_info->flags = SWP_WRITEOK;
+	DPRINTK( "get_stram_region: returning %p\n", ret );
+	return( ret );
+}
+
+
+/*
+ * free a reserved region in ST-RAM swap space
+ */
+static void free_stram_region( unsigned long offset, unsigned long n_pages )
+{
+	unsigned char *map = stram_swap_info->swap_map;
+
+	DPRINTK( "free_stram_region(offset=%lu,n_pages=%lu)\n", offset, n_pages );
+
+	if (offset < 1 || offset + n_pages > stram_swap_info->max) {
+		printk( KERN_ERR "free_stram_region: Trying to free non-ST-RAM\n" );
+		return;
+	}
+
+	/* un-reserve the freed pages */
+	for( ; n_pages > 0; ++offset, --n_pages ) {
+		if (map[offset] != SWP_RSVD)
+			printk( KERN_ERR "free_stram_region: Swap page %lu was not "
+					"reserved\n", offset );
+		map[offset] = 0;
+	}
+
+	/* update swapping meta-data */
+	if (offset < stram_swap_info->lowest_bit)
+		stram_swap_info->lowest_bit = offset;
+	if (offset+n_pages-1 > stram_swap_info->highest_bit)
+		stram_swap_info->highest_bit = offset+n_pages-1;
+	if (stram_swap_info->prio > swap_info[swap_list.next].prio)
+		swap_list.next = swap_list.head;
+	nr_swap_pages += n_pages;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/*						Utility Functions for Swapping						*/
+/* ------------------------------------------------------------------------ */
+
+
+/* is addr in some of the allocated regions? */
+static int in_some_region( unsigned long addr )
+{
+	BLOCK *p;
+	
+	for( p = alloc_list; p; p = p->next ) {
+		if (p->start <= addr && addr < p->start + p->size)
+			return( 1 );
+	}
+	return( 0 );
+}
+
+
+static unsigned long find_free_region( unsigned long n_pages,
+									   unsigned long *total_free,
+									   unsigned long *region_free )
+{
+	unsigned char *map = stram_swap_info->swap_map;
+	unsigned long max = stram_swap_info->max;
+	unsigned long head, tail, max_start;
+	long nfree, max_free;
+
+	/* first scan the swap space for a suitable place for the allocation */
+	head = 1;
+	max_start = 0;
+	max_free = -1;
+	*total_free = 0;
+
+  start_over:
+	/* increment tail until final window size reached, and count free pages */
+	nfree = 0;
+	for( tail = head; tail-head < n_pages && tail < max-n_pages; ++tail ) {
+		if (map[tail] == SWP_RSVD) {
+			head = tail+1;
+			goto start_over;
+		}
+		if (!map[tail]) {
+			++nfree;
+			++*total_free;
 		}
 	}
+	if (tail-head < n_pages)
+		goto out;
+	if (nfree > max_free) {
+		max_start = head;
+		max_free  = nfree;
+		if (max_free >= n_pages)
+			/* don't need more free pages... :-) */
+			goto out;
+	}
 	
-	return( adr );
+	/* now shift the window and look for the area where as much pages as
+	 * possible are free */
+	while( tail < max ) {
+		nfree -= (map[head++] == 0);
+		if (map[tail] == SWP_RSVD) {
+			head = tail+1;
+			goto start_over;
+		}
+		if (!map[tail]) {
+			++nfree;
+			++*total_free;
+		}
+		++tail;
+		if (nfree > max_free) {
+			max_start = head;
+			max_free  = nfree;
+			if (max_free >= n_pages)
+				/* don't need more free pages... :-) */
+				goto out;
+		}
+	}
+
+  out:
+	if (max_free < 0) {
+		printk( KERN_NOTICE "get_stram_region: ST-RAM too full or fragmented "
+				"-- can't allocate %lu pages\n", n_pages );
+		return( 0 );
+	}
+
+	*region_free = max_free;
+	return( max_start );
 }
 
-void atari_stram_free( void *ptr )
 
+/* setup parameters from command line */
+void stram_swap_setup( char *str, int *ints )
 {
-	/* Sorry, this is a dummy. It isn't needed anyway. */
+	if (ints[0] >= 1)
+		max_swap_size = ((ints[1] < 0 ? 0 : ints[1]) * 1024) & PAGE_MASK;
 }
 
+
+/* ------------------------------------------------------------------------ */
+/*								ST-RAM device								*/
+/* ------------------------------------------------------------------------ */
+
+static int stram_blocksizes[14] = {
+	0, 0, 0, 0, 0, 0, 0, 0,	0, 0, 0, 0, 0, 4096 };
+static int stram_sizes[14] = {
+	0, 0, 0, 0, 0, 0, 0, 0,	0, 0, 0, 0, 0, 0 };
+static int refcnt = 0;
+
+static void do_stram_request( void )
+{
+	unsigned long start, len;
+
+	while( CURRENT ) {
+		if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+			panic("stram: request list destroyed");
+		if (CURRENT->bh) {
+			if (!buffer_locked(CURRENT->bh))
+				panic("stram: block not locked");
+		}
+		
+		start = swap_start + (CURRENT->sector << 9);
+		len   = CURRENT->current_nr_sectors << 9;
+		if ((start + len) > swap_end) {
+			printk( KERN_ERR "stram: bad access beyond end of device: "
+					"block=%ld, count=%ld\n",
+					CURRENT->sector,
+					CURRENT->current_nr_sectors );
+			end_request( 0 );
+			continue;
+		}
+
+		if (CURRENT->cmd == READ) {
+			memcpy( CURRENT->buffer, (char *)start, len );
+#ifdef DO_PROC
+			stat_swap_read += N_PAGES(len);
 #endif
+		}
+		else {
+			memcpy( (char *)start, CURRENT->buffer, len );
+#ifdef DO_PROC
+			stat_swap_write += N_PAGES(len);
+#endif
+		}
+		end_request( 1 );
+	}
+}
 
 
+static int stram_open( struct inode *inode, struct file *filp )
+{
+	if (filp != MAGIC_FILE_P) {
+		printk( KERN_NOTICE "Only kernel can open ST-RAM device\n" );
+		return( -EPERM );
+	}
+	if (MINOR(inode->i_rdev) != STRAM_MINOR)
+		return( -ENXIO );
+	if (refcnt)
+		return( -EBUSY );
+	++refcnt;
+	return( 0 );
+}
+
+static int stram_release( struct inode *inode, struct file *filp )
+{
+	if (filp != MAGIC_FILE_P) {
+		printk( KERN_NOTICE "Only kernel can close ST-RAM device\n" );
+		return( -EPERM );
+	}
+	if (refcnt > 0)
+		--refcnt;
+	return( 0 );
+}
+
+
+static struct file_operations stram_fops = {
+        NULL,                   /* lseek - default */
+        block_read,             /* read - general block-dev read */
+        block_write,            /* write - general block-dev write */
+        NULL,                   /* readdir - bad */
+        NULL,                   /* select */
+        NULL,                   /* ioctl */
+        NULL,                   /* mmap */
+        stram_open,             /* open */
+        stram_release,          /* release */
+        block_fsync             /* fsync */
+};
+
+int stram_device_init( void )
+{
+
+    if (!MACH_IS_ATARI)
+    	/* no point in initializing this, I hope */
+	return( -ENXIO );
+
+    if (!max_swap_size)
+        /* swapping not enabled */
+	return( -ENXIO );
+	
+    if (register_blkdev( STRAM_MAJOR, "stram", &stram_fops)) {
+        printk( KERN_ERR "stram: Unable to get major %d\n", STRAM_MAJOR );
+        return( -ENXIO );
+    }
+
+    blk_dev[STRAM_MAJOR].request_fn = do_stram_request;
+    blksize_size[STRAM_MAJOR] = stram_blocksizes;
+	stram_sizes[STRAM_MINOR] = (swap_end - swap_start)/1024;
+    blk_size[STRAM_MAJOR] = stram_sizes;
+	do_z2_request(); /* to avoid warning */
+	return( 0 );
+}
+
+/* to avoid warning */
+static void do_z2_request( void ) { }
+
+#endif /* CONFIG_STRAM_SWAP */
+
+
+/* ------------------------------------------------------------------------ */
+/*							Misc Utility Functions							*/
+/* ------------------------------------------------------------------------ */
+
+
+/* return log2 of #pages for size */
+static int get_gfp_order( unsigned long size )
+{
+	int order;
+
+	size = N_PAGES( size + PAGE_SIZE -1 );
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+
+	return( order );
+}
+
+
+/* reserve a range of pages in mem_map[] */
+static void reserve_region( unsigned long addr, unsigned long end )
+{
+	mem_map_t *mapp = &mem_map[MAP_NR(addr)];
+
+	for( ; addr < end; addr += PAGE_SIZE, ++mapp )
+		set_bit( PG_reserved, &mapp->flags );
+}
+
+
+
+/* ------------------------------------------------------------------------ */
+/*							  Region Management								*/
+/* ------------------------------------------------------------------------ */
+
+
+/* insert a region into the alloced list (sorted) */
+static BLOCK *add_region( void *addr, unsigned long size )
+{
+	BLOCK **p, *n = NULL;
+	int i;
+
+	for( i = 0; i < N_STATIC_BLOCKS; ++i ) {
+		if (static_blocks[i].flags & BLOCK_FREE) {
+			n = &static_blocks[i];
+			n->flags = 0;
+			break;
+		}
+	}
+	if (!n && mem_init_done) {
+		/* if statics block pool exhausted and we can call kmalloc() already
+		 * (after mem_init()), try that */
+		n = kmalloc( sizeof(BLOCK), GFP_KERNEL );
+		if (n)
+			n->flags = BLOCK_KMALLOCED;
+	}
+	if (!n) {
+		printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" );
+		return( NULL );
+	}
+	n->start = (unsigned long)addr;
+	n->size  = size;
+
+	for( p = &alloc_list; *p; p = &((*p)->next) )
+		if ((*p)->start > (unsigned long)addr) break;
+	n->next = *p;
+	*p = n;
+
+	return( n );
+}
+
+
+/* find a region (by start addr) in the alloced list */
+static BLOCK *find_region( void *addr )
+{
+	BLOCK *p;
+	
+	for( p = alloc_list; p; p = p->next ) {
+		if (p->start == (unsigned long)addr)
+			return( p );
+		if (p->start > (unsigned long)addr)
+			break;
+	}
+	return( NULL );
+}
+
+
+/* remove a block from the alloced list */
+static int remove_region( BLOCK *block )
+{
+	BLOCK **p;
+	
+	for( p = &alloc_list; *p; p = &((*p)->next) )
+		if (*p == block) break;
+	if (!*p)
+		return( 0 );
+
+	*p = block->next;
+	if (block->flags & BLOCK_KMALLOCED)
+		kfree( block );
+	else
+		block->flags |= BLOCK_FREE;
+	return( 1 );
+}
+
+
+
+/* ------------------------------------------------------------------------ */
+/*						 /proc statistics file stuff						*/
+/* ------------------------------------------------------------------------ */
+
+#ifdef DO_PROC
+
+#define	PRINT_PROC(fmt,args...) len += sprintf( buf+len, fmt, ##args )
+
+int get_stram_list( char *buf )
+{
+	int len = 0;
+	BLOCK *p;
+#ifdef CONFIG_STRAM_SWAP
+    int i;
+	unsigned char *map = stram_swap_info->swap_map;
+	unsigned long max = stram_swap_info->max;
+	unsigned free = 0, used = 0, rsvd = 0;
+#endif
+
+#ifdef CONFIG_STRAM_SWAP
+	if (max_swap_size) {
+		for( i = 1; i < max; ++i ) {
+			if (!map[i])
+				++free;
+			else if (map[i] == SWP_RSVD)
+				++rsvd;
+			else
+				++used;
+		}
+		PRINT_PROC(
+			"Total ST-RAM:      %8lu kB\n"
+			"Total ST-RAM swap: %8lu kB\n"
+			"Free swap:         %8u kB\n"
+			"Used swap:         %8u kB\n"
+			"Allocated swap:    %8u kB\n"
+			"Swap Reads:        %8u\n"
+			"Swap Writes:       %8u\n"
+			"Swap Moves:        %8u\n"
+			"Swap Forced Reads: %8u\n",
+			(stram_end - stram_start) >> 10,
+			(max-1) << (PAGE_SHIFT-10),
+			free << (PAGE_SHIFT-10),
+			used << (PAGE_SHIFT-10),
+			rsvd << (PAGE_SHIFT-10),
+			stat_swap_read,
+			stat_swap_write,
+			stat_swap_move,
+			stat_swap_force );
+	}
+	else {
+#endif
+		PRINT_PROC( "ST-RAM swapping disabled\n" );
+		PRINT_PROC(
+			"Total ST-RAM:      %8lu kB\n"
+			"Reserved ST-RAM:   %8lu kB\n",
+			(stram_end - stram_start) >> 10,
+			(rsvd_stram_end - rsvd_stram_beg) >> 10 );
+#ifdef CONFIG_STRAM_SWAP
+	}
+#endif
+
+	PRINT_PROC( "Allocated regions:\n" );
+	for( p = alloc_list; p; p = p->next ) {
+		if (len + 50 >= PAGE_SIZE)
+			break;
+		PRINT_PROC( "0x%08lx-0x%08lx: %s (",
+					VTOP(p->start), VTOP(p->start+p->size-1), p->owner );
+		if (p->flags & BLOCK_STATIC)
+			PRINT_PROC( "static)\n" );
+		else if (p->flags & BLOCK_GFP)
+			PRINT_PROC( "page-alloced)\n" );
+		else if (p->flags & BLOCK_INSWAP)
+			PRINT_PROC( "in swap)\n" );
+		else
+			PRINT_PROC( "??)\n" );
+	}
+
+	return( len );
+}
+
+#endif
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/atari/time.c linux/arch/m68k/atari/time.c
--- v2.1.86/linux/arch/m68k/atari/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/atari/time.c	Thu Feb 12 16:30:12 1998
@@ -0,0 +1,416 @@
+/*
+ * linux/arch/m68k/atari/time.c
+ *
+ * Atari time and real time clock stuff
+ *
+ * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
+ *  
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mc146818rtc.h>
+#include <linux/kd.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+
+__initfunc(void
+atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)))
+{
+    /* 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 */
+    request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
+                "timer", timer_routine);
+}
+
+/* ++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, hour;
+    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;
+    hour = val.hr_ones + val.hr_tens * 10;
+    if (!hr24) {
+        if (hour == 12 || hour == 12 + 20)
+	    hour -= 12;
+	if (hour >= 20)
+	    hour += 12 - 20;
+    }
+    *hourp = hour;
+    *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_tt_gettod (int *yearp, int *monp, int *dayp,
+		      int *hourp, int *minp, int *secp)
+{
+    unsigned char	ctrl;
+    int hour, pm;
+
+    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);
+    hour = RTC_READ(RTC_HOURS);
+    *dayp  = RTC_READ(RTC_DAY_OF_MONTH);
+    *monp  = RTC_READ(RTC_MONTH);
+    *yearp = RTC_READ(RTC_YEAR);
+    pm = hour & 0x80;
+    hour &= ~0x80;
+
+    ctrl = RTC_READ(RTC_CONTROL); 
+
+    if (!(ctrl & RTC_DM_BINARY)) {
+        BCD_TO_BIN(*secp);
+        BCD_TO_BIN(*minp);
+        BCD_TO_BIN(hour);
+        BCD_TO_BIN(*dayp);
+        BCD_TO_BIN(*monp);
+        BCD_TO_BIN(*yearp);
+    }
+    if (!(ctrl & RTC_24H)) {
+	if (!pm && hour == 12)
+	    hour = 0;
+	else if (pm && hour != 12)
+            hour += 12;
+    }
+    *hourp = hour;
+
+    /* Adjust values (let the setup valid) */
+    *yearp += atari_rtc_year_offset;
+}
+
+#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;
+        if (!hr24) {
+	    if (hour > 11)
+		hour += 20 - 12;
+	    if (hour == 0 || hour == 20)
+		hour += 12;
+        }
+        val.hr_ones = hour % 10;
+        val.hr_tens = hour / 10;
+        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;
+        hour = val.hr_ones + val.hr_tens * 10;
+	if (!hr24) {
+	    if (hour == 12 || hour == 12 + 20)
+		hour -= 12;
+	    if (hour >= 20)
+                hour += 12 - 20;
+        }
+	t->hour = hour;
+	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_tt_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 char	ctrl;
+    int pm = 0;
+
+    ctrl = RTC_READ(RTC_CONTROL); /* control registers are
+                                   * independent 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 - atari_rtc_year_offset;
+        wday = t->wday + (t->wday >= 0);
+        
+        if (!(ctrl & RTC_24H)) {
+	    if (hour > 11) {
+		pm = 0x80;
+		if (hour != 12)
+		    hour -= 12;
+	    }
+	    else if (hour == 0)
+		hour = 12;
+        }
+        
+        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 + pm);
+        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 (hour & 0x80) {
+	    hour &= ~0x80;
+	    pm = 1;
+	}
+
+	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 (!pm && hour == 12)
+		hour = 0;
+	    else if (pm && hour != 12)
+		hour += 12;
+        }
+
+        t->sec  = sec;
+        t->min  = min;
+        t->hour = hour;
+        t->day  = day;
+        t->mon  = mon - 1;
+        t->year = year + atari_rtc_year_offset;
+        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_tt_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;
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.1.86/linux/arch/m68k/config.in	Thu Feb 12 20:56:04 1998
+++ linux/arch/m68k/config.in	Thu Feb 12 16:30:12 1998
@@ -23,7 +23,19 @@
 
 bool 'Amiga support' CONFIG_AMIGA
 bool 'Atari support' CONFIG_ATARI
+if [ "$CONFIG_ATARI" = "y" ]; then
+  bool '  Hades support' CONFIG_HADES
+  if [ "$CONFIG_HADES" = "y" ]; then
+    define_bool CONFIG_PCI y
+  fi  
+fi
 bool 'Macintosh support' CONFIG_MAC
+bool 'Apollo support' CONFIG_APOLLO
+bool 'VME (Motorola and BVM) support' CONFIG_VME
+if [ "$CONFIG_VME" = "y" ]; then
+  bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
+# bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
+fi
 
 comment 'Processor type'
 bool '68020 support' CONFIG_M68020
@@ -56,19 +68,19 @@
 
 if [ "$CONFIG_AMIGA" = "y" ]; then
   bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
-  bool 'Amiga OCS chipset support' CONFIG_AMIFB_OCS
-  bool 'Amiga ECS chipset support' CONFIG_AMIFB_ECS
-  bool 'Amiga AGA chipset support' CONFIG_AMIFB_AGA
-  bool 'Amiga Cybervision support' CONFIG_FB_CYBER
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
-  fi
 #  bool 'Amiga GSP (TMS340x0) support' CONFIG_AMIGA_GSP
 #  if [ "$CONFIG_AMIGA_GSP" = "y" ]; then
 #    bool 'DMI Resolver support' CONFIG_GSP_RESOLVER
 #    bool 'A2410 support' CONFIG_GSP_A2410
 #  fi
 fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+  bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
+  bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC
+fi
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+  bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
+fi
 endmenu
 
 #
@@ -77,7 +89,17 @@
 mainmenu_option next_comment
 comment 'Floppy, IDE, and other block devices'
 
-tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
+if [ "$CONFIG_AMIGA" = "y" ]; then
+  tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+  tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
+fi
+if [ "$CONFIG_MAC" = "y" ]; then
+  tristate 'Macintosh IWM floppy support' CONFIG_MAC_FLOPPY
+fi
+#Normal floppy disk support' CONFIG_BLK_DEV_FD
+
 tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
 if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
   dep_tristate '   Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
@@ -85,6 +107,16 @@
   dep_tristate '   Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
   dep_tristate '   Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
   dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
+  if [ "$CONFIG_AMIGA" = "y" ]; then
+    bool '   Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool '   Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA
+      bool '   Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
+    fi
+  fi
+  if [ "$CONFIG_ATARI" = "y" ]; then
+    bool '   Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
+  fi
 fi
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
@@ -138,6 +170,7 @@
 bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
 
 bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+bool 'SCSI logging facility' CONFIG_SCSI_LOGGING
 
 mainmenu_option next_comment
 comment 'SCSI low-level drivers'
@@ -155,14 +188,26 @@
     bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
-    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
+    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
+#    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
   fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
   bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+  if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then
+    bool 'Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL
+  fi
+fi
+if [ "$CONFIG_MAC" = "y" ]; then
+  bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI
 fi
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
+  bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
+fi
+
 endmenu
 
 fi
@@ -195,12 +240,21 @@
   tristate 'A2065 support' CONFIG_A2065
   tristate 'Hydra support' CONFIG_HYDRA
 fi
+if [ "$CONFIG_APOLLO" = "y" ] ; then
+  tristate 'Apollo 3c505 support' CONFIG_APOLLO_ELPLUS
+fi
 if [ "$CONFIG_ATARI" = "y" ]; then
-  bool 'Atari Lance support' CONFIG_ATARILANCE
-if [ "$CONFIG_ATARI_ACSI" = "y" ]; then
-  bool 'BioNet-100 support' CONFIG_ATARI_BIONET
-  bool 'PAMsNet support' CONFIG_ATARI_PAMSNET
+  tristate 'Atari Lance support' CONFIG_ATARILANCE
+  if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
+    tristate 'BioNet-100 support' CONFIG_ATARI_BIONET
+    tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET
+  fi
+fi
+if [ "$CONFIG_MAC" = "y" ]; then
+  bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT
 fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
+  bool 'MVME16x Ethernet support' CONFIG_APRICOT
 fi
 fi
 endmenu
@@ -220,14 +274,23 @@
 
 source fs/Config.in
 
+if [ "$CONFIG_VME" = "n" ]; then
+  define_bool CONFIG_FB y
+  source drivers/video/Config.in
+fi
+
 source fs/nls/Config.in
 
 mainmenu_option next_comment
 comment 'Character devices'
-
-define_bool CONFIG_VT y
-define_bool CONFIG_VT_CONSOLE y
-define_bool CONFIG_FB_CONSOLE y
+ 
+if [ "$CONFIG_VME" = "n" ]; then
+  define_bool CONFIG_VT y
+  if [ "$CONFIG_VT" = "y" ]; then
+    bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
+  fi
+  define_bool CONFIG_FB_CONSOLE y
+fi
 
 if [ "$CONFIG_ATARI" = "y" ]; then
   define_bool CONFIG_NVRAM y
@@ -241,6 +304,9 @@
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari mouse support' CONFIG_ATARIMOUSE
 fi
+if [ "$CONFIG_MAC" = "y" ]; then
+   bool 'Mac ADB mouse support' CONFIG_MACMOUSE
+fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
   tristate 'Atari SCC serial support' CONFIG_ATARI_SCC
@@ -260,11 +326,25 @@
   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
   bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
 fi
-if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
-     "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
-     "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
-  bool 'Serial console support' CONFIG_SERIAL_CONSOLE
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
+  if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
+       "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
+       "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then
+    bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
+  fi
+fi
+if [ "$CONFIG_MAC" = "y" ]; then
+  bool 'Mac SCC serial support' CONFIG_MAC_SCC
 fi
+if [ "$CONFIG_VME" = "y" ]; then
+  define_bool CONFIG_SERIAL_CONSOLE y
+  bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
+  bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
+fi
+if [ "$CONFIG_APOLLO" = "y" ]; then
+  bool 'Support for DN serial port (dummy)' CONFIG_SERIAL
+  bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
+fi 
 bool 'Support for user serial device modules' CONFIG_USERIAL
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
@@ -274,6 +354,9 @@
 bool 'Support for user misc device modules' CONFIG_UMISC
 if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then
   define_bool CONFIG_ABSTRACT_CONSOLE y
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+  bool 'Enhanced Real Time Clock Support' CONFIG_RTC
 fi
 endmenu
 
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- v2.1.86/linux/arch/m68k/defconfig	Thu Jul 31 13:09:16 1997
+++ linux/arch/m68k/defconfig	Thu Feb 12 16:30:12 1998
@@ -42,11 +42,6 @@
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_ZORRO=y
-CONFIG_AMIFB_OCS=y
-CONFIG_AMIFB_ECS=y
-CONFIG_AMIFB_AGA=y
-# CONFIG_FB_CYBER is not set
-# CONFIG_FB_RETINAZ3 is not set
 # CONFIG_AMIGA_GSP is not set
 # CONFIG_GSP_RESOLVER is not set
 # CONFIG_GSP_A2410 is not set
@@ -54,7 +49,8 @@
 #
 # Block device driver configuration
 #
-CONFIG_BLK_DEV_FD=y
+CONFIG_AMIGA_FLOPPY=y
+CONFIG_ATARI_FLOPPY=y
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_IDE is not set
 # CONFIG_BLK_DEV_IDEDISK is not set
@@ -62,6 +58,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_IDEDOUBLER is not set
 # CONFIG_AMIGA_Z2RAM is not set
 # CONFIG_ATARI_ACSI is not set
 # CONFIG_ACSI_MULTI_LUN is not set
@@ -132,6 +129,9 @@
 # CONFIG_BLZ2060_SCSI is not set
 # CONFIG_BLZ1230_SCSI is not set
 # CONFIG_FASTLANE_SCSI is not set
+# CONFIG_A4000T_SCSI is not set
+# CONFIG_A4091_SCSI is not set
+# CONFIG_WARPENGINE_SCSI is not set
 CONFIG_ATARI_SCSI=y
 
 #
@@ -169,6 +169,21 @@
 # CONFIG_AFFS_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_UFS_FS is not set
+
+#
+# Frame buffer devices
+#
+CONFIG_FB_AMIGA=y
+CONFIG_FB_AMIGA_OCS=y
+CONFIG_FB_AMIGA_ECS=y
+CONFIG_FB_AMIGA_AGA=y
+# CONFIG_FB_CYBER is not set
+# CONFIG_FB_RETINAZ3 is not set
+# CONFIG_FB_ATARI is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+
+CONFIG_NLS_CODEPAGE_437=y
 
 #
 # Character devices
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S
--- v2.1.86/linux/arch/m68k/ifpsp060/iskeleton.S	Thu Jul 31 13:09:16 1997
+++ linux/arch/m68k/ifpsp060/iskeleton.S	Thu Feb 12 16:30:12 1998
@@ -183,7 +183,7 @@
 |
 | _060_lock_page():
 |
-| Entry point for the operating system's routine to "lock" a 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 
@@ -208,7 +208,7 @@
 |
 | _060_unlock_page():
 |
-| Entry point for the operating system's routine to "unlock" a
+| 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.
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/ifpsp060/os.S linux/arch/m68k/ifpsp060/os.S
--- v2.1.86/linux/arch/m68k/ifpsp060/os.S	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/ifpsp060/os.S	Thu Feb 12 16:30:12 1998
@@ -345,7 +345,6 @@
 copyinae:	
 	movs.b		(%a0)+,%d1		| fetch user byte
 	move.b		%d1,(%a1)+		| write supervisor byte
-	subq.l		#0x1,%d0		| are we through yet?
 	dbra		%d0,morein		| are we through yet?
 	moveq		#0,%d0			| return success
 	rts
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile
--- v2.1.86/linux/arch/m68k/kernel/Makefile	Sat Aug 16 09:51:07 1997
+++ linux/arch/m68k/kernel/Makefile	Thu Feb 12 16:30:12 1998
@@ -10,19 +10,26 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
-all: kernel.o head.o
+all: head.o kernel.o
 O_TARGET := kernel.o
 O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
 	  setup.o sys_m68k.o time.o
-ifdef CONFIG_VT
-O_OBJS += console.o
-endif
 OX_OBJS := m68k_ksyms.o
 
 ifdef CONFIG_KGDB
 O_OBJS += kgdb.o
 endif
 
-head.o: head.S
+ifdef CONFIG_PCI
+O_OBJS += bios32.o
+endif
+
+head.o: head.S m68k_defs.h
+
+m68k_defs.h: m68k_defs.c m68k_defs.head $(TOPDIR)/include/linux/sched.h
+	$(CC) ${CFLAGS} -S m68k_defs.c
+	cp m68k_defs.head m68k_defs.h
+	sed -n < m68k_defs.s >> m68k_defs.h '/^#define/s/ #/ /p'
+	rm m68k_defs.s
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c
--- v2.1.86/linux/arch/m68k/kernel/bios32.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/kernel/bios32.c	Thu Feb 12 16:30:12 1998
@@ -0,0 +1,580 @@
+/*
+ * bios32.c - PCI BIOS functions for Alpha systems not using BIOS
+ *	      emulation code.
+ *
+ * Written by Wout Klaren.
+ *
+ * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#if 0
+# define DBG_DEVS(args)		printk args
+#else
+# define DBG_DEVS(args)
+#endif
+
+#ifdef CONFIG_PCI
+
+/*
+ * PCI support for Linux/m68k. Currently only the Hades is supported.
+ *
+ * Notes:
+ *
+ * 1. The PCI memory area starts at address 0x80000000 and the
+ *    I/O area starts at 0xB0000000. Therefore these offsets
+ *    are added to the base addresses when they are read and
+ *    substracted when they are written.
+ *
+ * 2. The support for PCI bridges in the DEC Alpha version has
+ *    been removed in this version.
+ */
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define KB		1024
+#define MB		(1024*KB)
+#define GB		(1024*MB)
+
+#define MAJOR_REV	0
+#define MINOR_REV	0
+
+/*
+ * Base addresses of the PCI memory and I/O areas on the Hades.
+ */
+
+static unsigned long pci_mem_base = 0;
+static unsigned long pci_io_base = 0;
+
+/*
+ * Align VAL to ALIGN, which must be a power of two.
+ */
+
+#define ALIGN(val,align)	(((val) + ((align) - 1)) & ~((align) - 1))
+
+/*
+ * Calculate the address of the PCI configuration area of the given
+ * device.
+ *
+ * BUG: boards with multiple functions are probably not correctly
+ * supported.
+ */
+
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+			unsigned char where, unsigned long *pci_addr)
+{
+	static const unsigned long pci_conf_base[] = { 0xA0080000, 0xA0040000,
+						       0xA0020000, 0xA0010000 };
+	int device = device_fn >> 3;
+
+	DBG_DEVS(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p)\n",
+		  bus, device_fn, where, pci_addr));
+
+	if (device > 3) {
+		DBG_DEVS(("mk_conf_addr: device (%d) > 3, returning -1\n", device));
+		return -1;
+	}
+
+	*pci_addr = pci_conf_base[device] | (where);
+	DBG_DEVS(("mk_conf_addr: returning pci_addr 0x%lx\n", *pci_addr));
+	return 0;
+}
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn,
+			     unsigned char where, unsigned char *value)
+{
+	unsigned long pci_addr;
+
+	*value = 0xff;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = *((unsigned char *)pci_addr);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word(unsigned char bus, unsigned char device_fn,
+			     unsigned char where, unsigned short *value)
+{
+	unsigned long pci_addr;
+
+	*value = 0xffff;
+
+	if (where & 0x1)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = le16_to_cpu(*((unsigned short *)pci_addr));
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword(unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned int *value)
+{
+	unsigned long pci_addr;
+
+	*value = 0xffffffff;
+
+	if (where & 0x3)
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = le32_to_cpu(*((unsigned int *)pci_addr));
+
+	if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5))
+	{
+		if ((*value & PCI_BASE_ADDRESS_SPACE) ==
+		    PCI_BASE_ADDRESS_SPACE_IO)
+			*value += pci_io_base;
+		else
+		{
+			if (*value == 0)
+			{
+				/*
+				 * Base address is 0. Test if this base
+				 * address register is used.
+				 */
+
+				*((unsigned long *)pci_addr) = 0xffffffff;
+				if (*((unsigned long *)pci_addr) != 0)
+					*value += pci_mem_base;
+			}
+			else
+				*value += pci_mem_base;
+		}
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte(unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned char value)
+{
+	unsigned long pci_addr;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*((unsigned char *)pci_addr) = value;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word(unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned short value)
+{
+	unsigned long pci_addr;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*((unsigned short *)pci_addr) = cpu_to_le16(value);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword(unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned int value)
+{
+	unsigned long pci_addr;
+
+	if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5))
+	{
+		if ((value & PCI_BASE_ADDRESS_SPACE) ==
+		    PCI_BASE_ADDRESS_SPACE_IO)
+			value -= pci_io_base;
+		else
+			value -= pci_mem_base;
+	}
+
+	*((unsigned int *)pci_addr) = cpu_to_le32(value);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Macro to enable programming of the PCI devices. On the Hades this
+ * define should be true, because the Hades has no PCI BIOS.
+ */
+
+#define PCI_MODIFY		1
+
+#if PCI_MODIFY
+
+/*
+ * Leave some room for a VGA card. We assume that the VGA card is
+ * always in the first 32M of PCI memory. For the time being we do
+ * not program the VGA card, because to make this work we also
+ * need to change the frame buffer device.
+ */
+
+#define FIRST_IO_ADDR	0x10000
+#define FIRST_MEM_ADDR	0x02000000
+
+static unsigned int io_base = FIRST_IO_ADDR;	/* Skip first 64K. */
+static unsigned int mem_base = FIRST_MEM_ADDR;	/* Skip first 32M. */
+
+/*
+ * Disable PCI device DEV so that it does not respond to I/O or memory
+ * accesses.
+ */
+
+__initfunc(static void disable_dev(struct pci_dev *dev))
+{
+	struct pci_bus *bus;
+	unsigned short cmd;
+
+	if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
+	    dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
+	    dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+		return;
+
+	bus = dev->bus;
+	pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
+
+	cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER);
+	pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd);
+}
+
+/*
+ * Layout memory and I/O for a device:
+ */
+
+#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2)
+
+__initfunc(static void layout_dev(struct pci_dev *dev))
+{
+	struct pci_bus *bus;
+	unsigned short cmd;
+	unsigned int base, mask, size, reg;
+	unsigned int alignto;
+
+	/*
+	 * Skip video cards for the time being.
+	 */
+
+	if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
+	    dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
+	    dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+		return;
+
+	bus = dev->bus;
+	pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
+
+	for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4)
+	{
+		/*
+		 * Figure out how much space and of what type this
+		 * device wants.
+		 */
+
+		pcibios_write_config_dword(bus->number, dev->devfn, reg,
+					   0xffffffff);
+		pcibios_read_config_dword(bus->number, dev->devfn, reg, &base);
+
+		if (!base)
+		{
+			/* this base-address register is unused */
+			continue;
+		}
+
+		/*
+		 * We've read the base address register back after
+		 * writing all ones and so now we must decode it.
+		 */
+
+		if (base & PCI_BASE_ADDRESS_SPACE_IO)
+		{
+			/*
+			 * I/O space base address register.
+			 */
+
+			cmd |= PCI_COMMAND_IO;
+
+			base &= PCI_BASE_ADDRESS_IO_MASK;
+			mask = (~base << 1) | 0x1;
+			size = (mask & base) & 0xffffffff;
+			/* align to multiple of size of minimum base */
+			alignto = MAX(0x400, size) ;
+			base = ALIGN(io_base, alignto);
+			io_base = base + size;
+			pcibios_write_config_dword(bus->number, dev->devfn,
+						   reg, base | 0x1);
+			DBG_DEVS(("layout_dev: IO address: %lX\n", base));
+		}
+		else
+		{
+			unsigned int type;
+
+			/*
+			 * Memory space base address register.
+			 */
+
+			cmd |= PCI_COMMAND_MEMORY;
+			type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+			base &= PCI_BASE_ADDRESS_MEM_MASK;
+			mask = (~base << 1) | 0x1;
+			size = (mask & base) & 0xffffffff;
+			switch (type)
+			{
+			case PCI_BASE_ADDRESS_MEM_TYPE_32:
+				break;
+
+			case PCI_BASE_ADDRESS_MEM_TYPE_64:
+				printk("bios32 WARNING: "
+				       "ignoring 64-bit device in "
+				       "slot %d, function %d: \n",
+				       PCI_SLOT(dev->devfn),
+				       PCI_FUNC(dev->devfn));
+				reg += 4;	/* skip extra 4 bytes */
+				continue;
+
+			case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+				printk("bios32 WARNING: slot %d, function %d "
+				       "requests memory below 1MB---don't "
+				       "know how to do that.\n",
+				       PCI_SLOT(dev->devfn),
+				       PCI_FUNC(dev->devfn));
+				continue;
+			}
+
+			/*
+			 * Align to multiple of size of minimum base
+			 */
+
+			alignto = MAX(0x1000, size) ;
+			base = ALIGN(mem_base, alignto);
+			mem_base = base + size;
+			pcibios_write_config_dword(bus->number, dev->devfn,
+						   reg, base);
+		}
+	}
+
+	/*
+	 * Enable device:
+	 */
+
+	if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
+	    dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
+	    dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
+	    dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+	{
+		/*
+		 * All of these (may) have I/O scattered all around
+		 * and may not use i/o-base address registers at all.
+		 * So we just have to always enable I/O to these
+		 * devices.
+		 */
+		cmd |= PCI_COMMAND_IO;
+	}
+
+	pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND,
+				  cmd | PCI_COMMAND_MASTER);
+	DBG_DEVS(("layout_dev: bus %d  slot 0x%x  VID 0x%x  DID 0x%x  class 0x%x\n",
+		  bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
+}
+
+__initfunc(static void layout_bus(struct pci_bus *bus))
+{
+	struct pci_dev *dev;
+
+	DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
+
+	if (!bus->devices && !bus->children)
+		return;
+
+	/*
+	 * Align the current bases on appropriate boundaries (4K for
+	 * IO and 1MB for memory).
+	 */
+
+	io_base = ALIGN(io_base, 4*KB);
+	mem_base = ALIGN(mem_base, 1*MB);
+
+	/*
+	 * PCI devices might have been setup by a PCI BIOS emulation
+	 * running under TOS. In these cases there is a
+	 * window during which two devices may have an overlapping
+	 * address range.  To avoid this causing trouble, we first
+	 * turn off the I/O and memory address decoders for all PCI
+	 * devices.  They'll be re-enabled only once all address
+	 * decoders are programmed consistently.
+	 */
+
+	for (dev = bus->devices; dev; dev = dev->sibling)
+	{
+		if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+			disable_dev(dev);
+	}
+
+	/*
+	 * Allocate space to each device:
+	 */
+
+	DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
+
+	for (dev = bus->devices; dev; dev = dev->sibling)
+	{
+		if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+			layout_dev(dev);
+	}
+}
+
+#endif /* !PCI_MODIFY */
+
+/*
+ * Given the vendor and device ids, find the n'th instance of that device
+ * in the system.
+ */
+
+int pcibios_find_device(unsigned short vendor, unsigned short device_id,
+			unsigned short index, unsigned char *bus,
+			unsigned char *devfn)
+{
+	unsigned int curr = 0;
+	struct pci_dev *dev;
+
+	for (dev = pci_devices; dev; dev = dev->next)
+	{
+		if (dev->vendor == vendor && dev->device == device_id)
+		{
+			if (curr == index)
+			{
+				*devfn = dev->devfn;
+				*bus = dev->bus->number;
+				return PCIBIOS_SUCCESSFUL;
+			}
+			++curr;
+		}
+	}
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+/*
+ * Given the class, find the n'th instance of that device
+ * in the system.
+ */
+
+int pcibios_find_class(unsigned int class_code, unsigned short index,
+		       unsigned char *bus, unsigned char *devfn)
+{
+	unsigned int curr = 0;
+	struct pci_dev *dev;
+
+	for (dev = pci_devices; dev; dev = dev->next)
+	{
+		if (dev->class == class_code)
+		{
+			if (curr == index)
+			{
+				*devfn = dev->devfn;
+				*bus = dev->bus->number;
+				return PCIBIOS_SUCCESSFUL;
+			}
+			++curr;
+		}
+	}
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pcibios_present(void)
+{
+	if (MACH_IS_HADES)
+		return 1;
+	else
+		return 0;
+}
+
+__initfunc(unsigned long pcibios_init(unsigned long mem_start,
+				      unsigned long mem_end))
+{
+	printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
+
+#if !PCI_MODIFY
+	printk("...NOT modifying existing PCI configuration\n");
+#endif
+
+	return mem_start;
+}
+
+/*
+ * static inline void hades_fixup(void)
+ *
+ * Assign IRQ numbers as used by Linux to the interrupt pins
+ * of the PCI cards.
+ */
+
+__initfunc(static inline void hades_fixup(void))
+{
+	char irq_tab[4] = {
+			    IRQ_TT_MFP_IO0,	/* Slot 0. */
+			    IRQ_TT_MFP_IO1,	/* Slot 1. */
+			    IRQ_TT_MFP_SCC,	/* Slot 2. */
+			    IRQ_TT_MFP_SCSIDMA	/* Slot 3. */
+			  };
+	struct pci_dev *dev;
+	unsigned char slot;
+
+	/*
+	 * Go through all devices, fixing up irqs as we see fit:
+	 */
+
+	for (dev = pci_devices; dev; dev = dev->next)
+	{
+		if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+		{
+			slot = PCI_SLOT(dev->devfn);	/* Determine slot number. */
+			dev->irq = irq_tab[slot];
+#if PCI_MODIFY
+			pcibios_write_config_byte(dev->bus->number, dev->devfn,
+						  PCI_INTERRUPT_LINE, dev->irq);
+#endif
+		}
+	}
+}
+
+__initfunc(unsigned long pcibios_fixup(unsigned long mem_start,
+				       unsigned long mem_end))
+{
+#if PCI_MODIFY
+	/*
+	 * Scan the tree, allocating PCI memory and I/O space.
+	 */
+
+	layout_bus(&pci_root);
+#endif
+
+	pci_mem_base = 0x80000000;
+	pci_io_base = 0xB0000000;
+
+	/*
+	 * Now is the time to do all those dirty little deeds...
+	 */
+
+	hades_fixup();
+
+	return mem_start;
+}
+#endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c
--- v2.1.86/linux/arch/m68k/kernel/console.c	Thu Jul 31 13:09:16 1997
+++ linux/arch/m68k/kernel/console.c	Wed Dec 31 16:00:00 1969
@@ -1,2748 +0,0 @@
-/*
- *  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 vt_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
-#define 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/config.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/console.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 <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/console_struct.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);
-static int con_open(struct tty_struct *, struct file *);
-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);
-static void set_vesa_blanking(unsigned long arg);
-extern void vesa_blank(void);
-extern void vesa_unblank(void);
-extern void compute_shiftstate(void);
-extern void reset_palette(int currcons);
-extern void set_palette(void);
-void poke_blanked_console(void);
-void do_blank_screen(int);
-
-#if 0
-/* Make sure there are no references left to this variables.  */
-unsigned long	video_num_lines;
-unsigned long	video_num_columns;
-unsigned long	video_size_row;
-#endif
-
-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];
-struct vc vc_cons [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 int vesa_off_interval = 0;
-static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-
-/*
- * fg_console is the current virtual console,
- * last_console is the last used one,
- * want_console is the console we want to switch to,
- * kmsg_redirect is the console for kernel messages,
- */
-int fg_console = 0;
-int last_console = 0;
-int want_console = -1;
-int kmsg_redirect = 0;
-
-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 palette		(vc_cons[currcons].d->vc_palette)
-#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
-
-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 */
-	/* don't update in graphics mode */
-	if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
-	    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;
-	}
-
-	/* don't update in graphics mode */
-	if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
-	    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 };
-
-/* the default colour table, for VGA+ colour systems */
-int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
-    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
-    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
-int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
-    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
-
-/*
- * 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 min_y, max_y;
-
-	if (new_x < 0)
-		x = 0;
-	else
-		if (new_x >= cols)
-			x = cols - 1;
-		else
-			x = new_x;
- 	if (decom) {
-		min_y = top;
-		max_y = bottom;
-	} else {
-		min_y = 0;
-		max_y = rows;
-	}
-	if (new_y < min_y)
-		y = min_y;
-	else if (new_y >= max_y)
-		y = max_y - 1;
-	else
-		y = new_y;
-	pos = video_mem_start + y * cols + x;
-	need_wrap = 0;
-}
-
-/* for absolute user moves, when decom is set */
-static void gotoxay(int currcons, int new_x, int new_y)
-{
-	gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
-}
-
-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 inline 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) and through set_selection */
-int mouse_reporting(void)
-{
-	int currcons = fg_console;
-
-	return report_mouse;
-}
-
-int tioclinux(struct tty_struct *tty, unsigned long arg)
-{
-	char type, data;
-
-	if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
-		return -EINVAL;
-	if (current->tty != tty && !suser())
-		return -EPERM;
-	if (get_user(type, (char *)arg))
-		return -EFAULT;
-	switch (type)
-	{
-		case 2:
-			return set_selection(arg, tty, 1);
-		case 3:
-			return paste_selection(tty);
-		case 4:
-			do_unblank_screen();
-			return 0;
-		case 5:
-			return sel_loadlut(arg);
-		case 6:
-			
-	/*
-	 * Make it possible to react to Shift+Mousebutton.
-	 * Note that 'shift_state' is an undocumented
-	 * kernel-internal variable; programs not closely
-	 * related to the kernel should not use this.
-	 */
-	 		data = shift_state;
-			return put_user(data, (char *) arg);
-		case 7:
-			data = mouse_reporting();
-			return put_user(data, (char *) arg);
-		case 10:
-			set_vesa_blanking(arg);
-			return 0;
-		case 11:	/* set kmsg redirect */
-			if (!suser())
-				return -EPERM;
-			if (get_user(data, (char *)arg+1))
-					return -EFAULT;
-			kmsg_redirect = data;
-			return 0;
-		case 12:	/* get fg_console */
-			return fg_console;
-	}
-	return -EINVAL;
-}
-
-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;
-				gotoxay(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;
-		case 14: /* set vesa powerdown interval */
-			vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
-			break;
-	}
-}
-
-static inline 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 void con_flush_chars(struct tty_struct *tty)
-{
-	unsigned int currcons;
-	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
-
-	currcons = vt->vc_num;
-	if (vcmode != KD_GRAPHICS)
-		set_cursor(currcons);
-}	
-
-static int do_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);
-		if (from_user)
-			get_user(c, buf);
-		else
-			c = *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 a control character 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.
-                 * Certain characters (as given by the CTRL_ALWAYS
-                 * bitmap) are always displayed as control characters,
-                 * as the console would be pretty useless without
-                 * them; to display an arbitrary font position use the
-                 * direct-to-font zone in UTF-8 mode.
-                 */
-                ok = tc && (c >= 32 ||
-                            (!utf && !(((disp_ctrl ? CTRL_ALWAYS
-                                         : CTRL_ACTION) >> c) & 1)))
-                        && (c != 127 || disp_ctrl)
-			&& (c != 128+27);
-
-		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 && !utf && 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;
-				}
-				
-				while (count)
-				{
-					enable_bh(CONSOLE_BH);
-					if (from_user)
-						get_user(c, buf);
-					else
-						c = *buf;
-					disable_bh(CONSOLE_BH);
-					tc = translate[toggle_meta ? (c|0x80) : c];
-					if (!tc ||
-					    !(c >= 32
-					      || !(((disp_ctrl ? CTRL_ALWAYS
-						   : CTRL_ACTION) >> c) & 1)))
-					  break;
-					tc = conv_uni_to_pc(tc);
-					if (tc == -4)
-					  tc = conv_uni_to_pc(0xfffd);
-					else if (tc == -3)
-					  tc = c;
-
-					buf++; n++; count--;
-					if (tc & ~console_charmask)
-					  continue; /* Conversion failed */
-
-					*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 0:
-			continue;
-		    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 */
-			    reset_palette (currcons);
-			    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) {
-				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() ;
-				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]--;
-				gotoxay(currcons,x,par[0]);
-				continue;
-			    case 'H': case 'f':
-				if (par[0]) par[0]--;
-				if (par[1]) par[1]--;
-				gotoxay(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];
-					gotoxay(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;
-		}
-	}
-	enable_bh(CONSOLE_BH);
-	return n;
-}
-
-static int con_write(struct tty_struct * tty, int from_user,
-		     const unsigned char *buf, int count)
-{
-	int	retval;
-	
-	retval = do_con_write(tty, from_user, buf, count);
-	con_flush_chars(tty);
-	
-	return retval;
-}
-
-static void con_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	do_con_write(tty, 0, &ch, 1);
-}
-
-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 */
-
-#ifdef CONFIG_VT_CONSOLE
-void vt_console_print(const char * b, unsigned int count)
-{
-   int currcons = fg_console;
-   unsigned char c;
-   const char *start = b;
-   ushort cnt        = 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("vt_console_print: tty %d not allocated ??\n", currcons+1);
-	   printing = 0;
-	   return;
-   }
-
-   /* undraw cursor first */
-   hide_cursor(currcons);
-
-   /* Contrived structure to try to emulate original need_wrap behaviour
-    * Problems caused when we have need_wrap set on '\n' character */
-
-   while (count-- > 0) {
-	   c = *(b++);
-	   if (c == 10 || c == 13 || c == 8 || need_wrap) {
-			if ((cnt = b - start - 1) > 0) {
-				sw->con_putcs(vc_cons[currcons].d,
-					      start, cnt, y, x);
-				x += cnt;
-				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 ((cnt = b - start) > 0) {
-	   sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
-	   x += cnt;
-	   if (x == cols){
-		   x--;
-		   need_wrap = 1;
-	   }
-   }
-   
-   set_cursor(currcons);
-   poke_blanked_console();
-   printing = 0;
-}
-
-static int vt_console_device(void)
-{
-	return MKDEV(TTY_MAJOR, fg_console + 1);
-}
-
-extern void keyboard_wait_for_keypress(void);
-
-struct console vt_console_driver = {
-	vt_console_print, do_unblank_screen,
-        keyboard_wait_for_keypress, vt_console_device
-};
-#endif
-
-/*
- * 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.
- */
-__initfunc(unsigned long con_init(unsigned long kmem_start))
-{
-	const 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.put_char = con_put_char;
-	console_driver.flush_chars = con_flush_chars;
-	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 */
-#ifdef CONFIG_VT_CONSOLE
-	if (!serial_debug)
-		register_console(&vt_console_driver);
-	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);
-#endif
-	init_bh(CONSOLE_BH, console_bh);
-	return kmem_start;
-}
-
-void vesa_powerdown_screen(void)
-{
-	int currcons = fg_console;
-
-	timer_active &= ~(1<<BLANK_TIMER);
-	timer_table[BLANK_TIMER].fn = unblank_screen;
-
-	/* Power down if currently suspended (1 or 2),
-	 * suspend if currently blanked (0),
-	 * else do nothing (i.e. already powered down (3)).
-	 * Called only if powerdown features are allowed.
-	 */
-	switch (vesa_blank_mode) {
-	case 0:
-		sw->con_blank(2);
-		break;
-	case 1:
-	case 2:
-		sw->con_blank(4);
-		break;
-	}
-}
-
-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) {
-		if (vesa_off_interval && !nopowersave) {
-			timer_table[BLANK_TIMER].fn = vesa_powerdown_screen;
-			timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval;
-			timer_active |= (1<<BLANK_TIMER);
-		} else {
-			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);
-		if (!nopowersave)
-			sw->con_blank(vesa_blank_mode + 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.
- */
-static 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.
- *
- * Currently we only support 8 pixels wide fonts, at a maximum height
- * of 32 pixels. Userspace fontdata is stored with 32 bytes reserved
- * for each character which is kinda wasty, but this is done in order
- * to maintain compatibility with the EGA/VGA fonts. It is upto the
- * actual low-level console-driver convert data into its favorite
- * format (maybe we should add a `fontoffset' field to the `display'
- * structure so we wont have to convert the fontdata all the time.
- * /Jes
- */
-
-#define cmapsz 8192
-
-static int set_get_font(char * arg, int set, int ch512)
-{
-#ifdef CAN_LOAD_EGA_FONTS
-	int i, unit, size;
-	char *charmap;
-
-	if (!arg)
-		return -EINVAL;
-
-
-	size = ch512 ? 2*cmapsz : cmapsz;
-
-	charmap = (char *)kmalloc(size, GFP_USER);
-
-	if (set){
-		if (copy_from_user(charmap, arg, size)) {
-			kfree(charmap);
-			return -EFAULT;
-		}
-
-		for (unit = 32; unit > 0; unit--)
-			for (i = 0; i < (ch512 ? 512 : 256); i++)
-				if (charmap[32*i+unit-1])
-					goto nonzero;
-	nonzero:
-		i = conswitchp->con_set_font(vc_cons[fg_console].d, 8,
-					     unit, charmap);
-	}else{
-		memset(charmap, 0, size);
-		i = conswitchp->con_get_font(vc_cons[fg_console].d,
-					     &unit, &unit, charmap);
-		if (i == 0 && copy_to_user(arg, charmap, size))
-			i = -EFAULT;
-	}
-	kfree(charmap);
-
-	return i;
-#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.
- */
-
-static int set_get_cmap(unsigned char *arg, int set)
-{
-	int i, j, k;
-
-	for (i = 0; i < 16; i++)
-		if (set) {
-			get_user(default_red[i], arg++);
-			get_user(default_grn[i], arg++);
-			get_user(default_blu[i], arg++);
-		} else {
-			put_user(default_red[i], arg++);
-			put_user(default_grn[i], arg++);
-			put_user(default_blu[i], arg++);
-		}
-	if (set) {
-		for (i = 0; i < MAX_NR_CONSOLES; i++)
-			if (vc_cons_allocated(i))
-				for (j = k = 0; j < 16; j++) {
-					vc_cons[i].d->vc_palette[k++] =
-						default_red[j];
-					vc_cons[i].d->vc_palette[k++] =
-						default_grn[j];
-					vc_cons[i].d->vc_palette[k++] =
-						default_blu[j];
-				}
-		set_palette();
-	}
-	return 0;
-}
-
-int con_set_cmap (unsigned char *arg)
-{
-	return set_get_cmap (arg, 1);
-}
-
-int con_get_cmap (unsigned char *arg)
-{
-	return set_get_cmap (arg, 0);
-}
-
-void reset_palette(int currcons)
-{
-	int j, k;
-	for (j = k = 0; j < 16; j++) {
-		palette[k++] = default_red[j];
-		palette[k++] = default_grn[j];
-		palette[k++] = default_blu[j];
-	}
-	set_palette() ;
-}
-
-void set_palette(void)
-{
-	if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS)
-		conswitchp->con_set_palette(vc_cons[fg_console].d, color_table);
-}
-
-/*
- * 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, int ch512)
-{
-	int i;
-
-	i = set_get_font (arg,1,ch512);
-  	if ( !i ) {
-		hashtable_contents_valid = 0;
-      		video_mode_512ch = ch512;
-      		console_charmask = ch512 ? 0x1ff : 0x0ff;
-	}
-	return i;
-}
-
-int con_get_font (char *arg)
-{
-	return set_get_font (arg,0,video_mode_512ch);
-}
-
-/*
- * 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;
-}
-
-static void set_vesa_blanking(unsigned long arg)
-{
-	char *argp = (char *)arg + 1;
-	unsigned int mode;
-	get_user(mode, argp);
-	vesa_blank_mode = (mode < 4) ? mode : 0;
-}
-
-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 v2.1.86/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.1.86/linux/arch/m68k/kernel/entry.S	Mon Dec  1 11:15:39 1997
+++ linux/arch/m68k/kernel/entry.S	Thu Feb 12 16:30:12 1998
@@ -37,6 +37,8 @@
 #include <asm/setup.h>
 #include <asm/segment.h>
 
+#include "m68k_defs.h"
+
 .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)
@@ -63,9 +65,7 @@
 
 ENTRY(reschedule)
 	| save top of frame
-	pea	%sp@
-	jbsr	SYMBOL_NAME(set_esp0)
-	addql	#4,%sp
+	movel	%sp,%curptr@(TS_ESP0)
 
 	pea	SYMBOL_NAME(ret_from_exception)
 	jmp	SYMBOL_NAME(schedule)
@@ -98,9 +98,7 @@
 
 	GET_CURRENT(%d0)
 	| save top of frame
-	pea	%sp@
-	jbsr	SYMBOL_NAME(set_esp0)
-	addql	#4,%sp
+	movel	%sp,%curptr@(TS_ESP0)
 
 	cmpl	#NR_syscalls,%d2
 	jcc	badsys
@@ -112,6 +110,10 @@
 SYMBOL_NAME_LABEL(ret_from_exception)
 	btst	#5,%sp@(LPT_OFF_SR)	| check if returning to kernel
 	bnes	2f			| if so, skip resched, signals
+	| only allow interrupts when we are really the last one on the
+	| kernel stack, otherwise stack overflow can occur during
+	| heavy interupt load
+	andw	#ALLOWINT,%sr
 	tstl	SYMBOL_NAME(need_resched)
 	jne	SYMBOL_NAME(reschedule)
 	cmpl	#SYMBOL_NAME(task),%curptr	| task[0] cannot have signals
@@ -122,16 +124,8 @@
 5:
 	tstl	%curptr@(LTASK_STATE)	| state
 	jne	SYMBOL_NAME(reschedule)
-	tstl	%curptr@(LTASK_COUNTER)	| counter
-	jeq	SYMBOL_NAME(reschedule)
 
-	movel	%curptr@(LTASK_BLOCKED),%d0
-	movel	%d0,%d1			| save blocked in d1 for sig handling
-	notl	%d0
-	btst	#LPF_PTRACED_BIT,%curptr@(LTASK_FLAGS+LPF_PTRACED_OFF)
-	jeq	1f
-	moveq	#-1,%d0			| let the debugger see all signals
-1:	andl	%curptr@(LTASK_SIGNAL),%d0
+	tstl	%curptr@(LTASK_SIGPENDING)
 	jne	Lsignal_return
 2:	RESTORE_ALL
 
@@ -139,7 +133,7 @@
 	subql	#4,%sp			| dummy return address
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
-	movel	%d1,%sp@-
+	clrl	%sp@-
 	bsrl	SYMBOL_NAME(do_signal)
 	addql	#8,%sp
 	RESTORE_SWITCH_STACK
@@ -184,11 +178,6 @@
 #endif
 	jhi	2b
 #endif
-	/* Let the rest run with interrupts allowed.  This is safe since
-	   the kernel never uses a non-standard ipl and this is the outer
-	   level interrupt. */
-	andw	#ALLOWINT,%sr
-
 	/* check if we need to do software interrupts */
 
 	movel	SYMBOL_NAME(bh_active),%d0
@@ -229,12 +218,26 @@
 	RESTORE_SWITCH_STACK
 	rts
 
+ENTRY(sys_rt_sigsuspend)
+	SAVE_SWITCH_STACK
+	pea	%sp@(SWITCH_STACK_SIZE)
+	jbsr	SYMBOL_NAME(do_rt_sigsuspend)
+	addql	#4,%sp
+	RESTORE_SWITCH_STACK
+	rts
+
 ENTRY(sys_sigreturn)
 	SAVE_SWITCH_STACK
 	jbsr	SYMBOL_NAME(do_sigreturn)
 	RESTORE_SWITCH_STACK
 	rts
 
+ENTRY(sys_rt_sigreturn)
+	SAVE_SWITCH_STACK
+	jbsr	SYMBOL_NAME(do_rt_sigreturn)
+	RESTORE_SWITCH_STACK
+	rts
+
 SYMBOL_NAME_LABEL(resume)
 	/*
 	 * Beware - when entering resume, offset of tss is in d1,
@@ -251,11 +254,6 @@
 	/* save sr */
 	movew	%sr,%a0@(LTSS_SR)
 
-#if 0
-	/* disable interrupts */
-	oriw	#0x0700,%sr
-#endif
-
 	/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
 	movec	%sfc,%d0
 	movew	%d0,%a0@(LTSS_FS)
@@ -415,7 +413,7 @@
 	.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_ni_syscall)				/* old break syscall holder */
 	.long SYMBOL_NAME(sys_stat)
 	.long SYMBOL_NAME(sys_lseek)
 	.long SYMBOL_NAME(sys_getpid)		/* 20 */
@@ -429,11 +427,11 @@
 	.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_ni_syscall)				/* old stty syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)				/* old gtty syscall holder */
 	.long SYMBOL_NAME(sys_access)
 	.long SYMBOL_NAME(sys_nice)
-	.long SYMBOL_NAME(sys_ftime)		/* 35 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 35 */		/* old ftime syscall holder */
 	.long SYMBOL_NAME(sys_sync)
 	.long SYMBOL_NAME(sys_kill)
 	.long SYMBOL_NAME(sys_rename)
@@ -442,7 +440,7 @@
 	.long SYMBOL_NAME(sys_dup)
 	.long SYMBOL_NAME(sys_pipe)
 	.long SYMBOL_NAME(sys_times)
-	.long SYMBOL_NAME(sys_prof)
+	.long SYMBOL_NAME(sys_ni_syscall)				/* old prof syscall holder */
 	.long SYMBOL_NAME(sys_brk)		/* 45 */
 	.long SYMBOL_NAME(sys_setgid)
 	.long SYMBOL_NAME(sys_getgid)
@@ -450,14 +448,14 @@
 	.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_ni_syscall)				/* old phys syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)				/* old lock syscall holder */
 	.long SYMBOL_NAME(sys_ioctl)
 	.long SYMBOL_NAME(sys_fcntl)		/* 55 */
-	.long SYMBOL_NAME(sys_mpx)
+	.long SYMBOL_NAME(sys_ni_syscall)				/* old mpx syscall holder */
 	.long SYMBOL_NAME(sys_setpgid)
-	.long SYMBOL_NAME(sys_ulimit)
-	.long SYMBOL_NAME(sys_olduname)
+	.long SYMBOL_NAME(sys_ni_syscall)				/* old ulimit syscall holder */
+	.long SYMBOL_NAME(sys_ni_syscall)
 	.long SYMBOL_NAME(sys_umask)		/* 60 */
 	.long SYMBOL_NAME(sys_chroot)
 	.long SYMBOL_NAME(sys_ustat)
@@ -496,7 +494,7 @@
 	.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_ni_syscall)				/* old profil syscall holder */
 	.long SYMBOL_NAME(sys_statfs)
 	.long SYMBOL_NAME(sys_fstatfs)		/* 100 */
 	.long SYMBOL_NAME(sys_ioperm)
@@ -507,7 +505,7 @@
 	.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)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* iopl for i386 */ /* 110 */
 	.long SYMBOL_NAME(sys_vhangup)
 	.long SYMBOL_NAME(sys_idle)
@@ -568,9 +566,19 @@
 	.long SYMBOL_NAME(sys_query_module)
 	.long SYMBOL_NAME(sys_poll)
 	.long SYMBOL_NAME(sys_nfsservctl)
+	.long SYMBOL_NAME(sys_setresgid)	/* 170 */
+	.long SYMBOL_NAME(sys_getresgid)
 	.long SYMBOL_NAME(sys_prctl)
-	.long SYMBOL_NAME(sys_pread)
+	.long SYMBOL_NAME(sys_rt_sigreturn)
+	.long SYMBOL_NAME(sys_rt_sigaction)
+	.long SYMBOL_NAME(sys_rt_sigprocmask)	/* 175 */
+	.long SYMBOL_NAME(sys_rt_sigpending)
+	.long SYMBOL_NAME(sys_rt_sigtimedwait)
+	.long SYMBOL_NAME(sys_rt_sigqueueinfo)
+	.long SYMBOL_NAME(sys_rt_sigsuspend)
+	.long SYMBOL_NAME(sys_pread)		/* 180 */
 	.long SYMBOL_NAME(sys_pwrite)
+	.long SYMBOL_NAME(sys_lchown);
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v2.1.86/linux/arch/m68k/kernel/head.S	Thu Jul 31 13:09:16 1997
+++ linux/arch/m68k/kernel/head.S	Thu Feb 12 16:30:12 1998
@@ -14,6 +14,7 @@
 ** 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
+** 95/11/18 Richard Hirst: Added MVME166 support
 ** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
 ** 			      Magnum- and FX-alternate ram
 **
@@ -72,8 +73,7 @@
 #include <asm/pgtable.h>
 
 .globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
-.globl SYMBOL_NAME(availmem), SYMBOL_NAME(is_medusa)
-.globl SYMBOL_NAME(is_hades)
+.globl SYMBOL_NAME(availmem), SYMBOL_NAME(mvme_bdid_ptr)
 .globl SYMBOL_NAME(m68k_pgtable_cachemode)
 .globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
 
@@ -145,6 +145,7 @@
 
 #define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
 #define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
+#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
 
 #define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
 #define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
@@ -162,6 +163,7 @@
 	.long	BOOTINFOV_MAGIC
 	.long	MACH_AMIGA, AMIGA_BOOTI_VERSION
 	.long	MACH_ATARI, ATARI_BOOTI_VERSION
+	.long	MACH_MVME16x, MVME16x_BOOTI_VERSION
 	.long	0
 1:	jra	SYMBOL_NAME(_start)
 
@@ -249,33 +251,25 @@
 #ifdef CONFIG_ATARI
 	is_not_atari(Lnotypetest)
 
-	moveq	#0,%d3			/* base addr for others: 0x00000000 */
-	moveq	#0,%d2			/* no Hades */
-	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 */
-	tstb	0xb0000000
-	nop
-	movel	#0xff000000,%d2		/* Computer is a Hades */
-	moveq	#0,%d3
-Ltest_berr:
-	movel	%a0,%sp
-	lea	%pc@(SYMBOL_NAME(is_hades)),%a0
-	movel	%d2,%a0@
-	lea	%pc@(SYMBOL_NAME(is_medusa)),%a0
-	movel	%d3,%a0@
-	lea     %pc@(Liobase),%a0
-	movel   %d2,%a0@		/* On a Hades the iobase must be set
-					   before opening the serial port. */
+	/* get special machine type (Medusa/Hades/AB40) */
+	moveq	#0,%d3 /* default if tag doesn't exist */
+	movew	#BI_ATARI_MCH_TYPE,%d0
+	jbsr	Lget_bi_record
+	tstl	%d0
+	jbmi	1f
+	movel	%a0@,%d3
+1:	
+	/* %d3 is not clobbered until Atari page tables are set up,
+	 * where it is used again. */
+
+	/* On the Hades, the iobase must be set up before opening the
+	 * serial port. There are no I/O regs at 0x00ffxxxx at all. */
+	moveq	#0,%d0
+	cmpl	#ATARI_MACH_HADES,%d3
+	jbne	1f
+	movel	#0xff000000,%d0		/* Hades I/O base addr: 0xff000000 */
+1:	lea     %pc@(Liobase),%a0
+	movel   %d0,%a0@
 Lnotypetest:
 #endif
 
@@ -543,10 +537,15 @@
    area.
 */
 
-	movel   %pc@(is_medusa),%d3
-	bne     1f
-	movel   %pc@(is_hades),%d3
-1:
+	/* I/O base addr for non-Medusa, non-Hades: 0x00000000 */
+	moveq	#0,%d0
+	cmpl	#ATARI_MACH_MEDUSA,%d3
+	jbeq	2f
+	cmpl	#ATARI_MACH_HADES,%d3
+	jbne	1f
+2:	movel	#0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */
+1:	movel	%d0,%d3
+	
 	/* Let the root table point to the new pointer table */
 	lea	%a4@(PTR_TABLE_SIZE<<2),%a4
 	movel	%a4,%a0
@@ -616,6 +615,30 @@
 Lnotatari:
 #endif
 
+#if defined(CONFIG_MVME16x)
+	is_not_mvme16x(Lnot16x)
+
+	/* Get pointer to board ID data */
+	movel	%d2,%sp@-
+	.long	0x4e4f0070		/* trap 0x70 - .BRD_ID */
+	movel	%sp@+,%d2
+	lea	%pc@(SYMBOL_NAME(mvme_bdid_ptr)),%a0
+	movel	%d2,%a0@
+
+	/*
+	 * On MVME16x we have already created kernel page tables for
+	 * 4MB of RAM at address 0, so now need to do a transparent
+	 * mapping of the top of memory space.  Make it 0.5GByte for now.
+	 */
+
+	movel	#0xe01f0000,%d2		/* logical address base */
+	orw	#0xa040,%d2		/* add in magic bits */
+	.long	0x4e7b2005		/* movec d2,ittr1 */
+	.long	0x4e7b2007		/* movec d2,dttr1 */
+
+Lnot16x:
+#endif
+
 /*
  * Setup a transparent mapping of the physical memory we are executing in.
  *
@@ -810,6 +833,26 @@
 Lmapphysnotatari:
 #endif
 
+#if defined(CONFIG_MVME16x)
+	is_not_mvme16x(Lmapphysnot16x)
+	/*
+	 * save physaddr of phys mem in register a3
+	 */
+	moveq	#'L',%d7
+	jbsr	Lserial_putc
+
+	.word	0xf4d8		/* CINVA I/D    */
+	.word	0xf518		/* pflusha      */
+	.long	0x4e7bd807	/* movec a5,srp */
+	.long	0x4e7bd806	/* movec a5,urp */
+	movel	#(TC_ENABLE+TC_PAGE4K),%d0
+	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
+	jra	LdoneMMUenable	/* branch to continuation of startup */
+
+Lmapphysnot16x:
+
+#endif
+
 LdoneMMUenable:
 
 /*
@@ -833,30 +876,6 @@
 
 	putc('N')
 
-#if 0
-	putr()
-	lea	SYMBOL_NAME(kernel_pmd_table),%a0
-	moveq	#63,%d0
-1:	moveq	#7,%d1
-	putn(%a0)
-	putc(':')
-	putc(' ')
-2:	putn(%a0@+)
-	dbra	%d1,2b
-	putr()
-	dbra	%d0,1b
-	putr()
-	movel	SYMBOL_NAME(kpt),%a0
-	moveq	#639,%d0
-1:	moveq	#7,%d1
-	putn(%a0)
-	putc(':')
-	putc(' ')
-2:	putn(%a0@+)
-	dbra	%d1,2b
-	putr()
-	dbra	%d0,1b
-#endif
 /*
  * Enable caches
  */
@@ -899,6 +918,7 @@
 /* jump to the kernel start */
 	putr()
 
+	subl	%a6,%a6 /* clear a6 for gdb */
 	jbsr	SYMBOL_NAME(start_kernel)
 
 /*
@@ -1048,6 +1068,13 @@
  */
 Lserial_putc:
 	moveml	%a0/%a1,%sp@-
+#if defined(CONFIG_MVME16x)
+	cmpil	#MACH_MVME16x,%d4
+	jne	2f
+	moveb	%d7,%sp@-
+	.long	0x4e4f0020
+2:
+#endif
 #ifdef CONFIG_AMIGA
 	cmpil	#MACH_AMIGA,%d4
 	jne	2f
@@ -1130,6 +1157,7 @@
 	moveml	%sp@+,%d0-%d2/%d7
 	rts
 
+#if 0
 Lshowtest:
 	moveml	%a0/%d7,%sp@-
 	putc('A')
@@ -1158,7 +1186,7 @@
 	putr()
 	moveml	%sp@+,%a0/%d7
 	rts
-
+#endif
 	.data
 	.even
 Lcustom:
@@ -1169,9 +1197,7 @@
 	.long 0
 SYMBOL_NAME_LABEL(availmem)
 	.long 0
-SYMBOL_NAME_LABEL(is_medusa)
-	.long 0
-SYMBOL_NAME_LABEL(is_hades)
-	.long 0
 SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
+	.long 0
+SYMBOL_NAME_LABEL(mvme_bdid_ptr)
 	.long 0
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- v2.1.86/linux/arch/m68k/kernel/ints.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/kernel/ints.c	Thu Feb 12 16:30:12 1998
@@ -53,7 +53,7 @@
 
 unsigned int local_irq_count[NR_CPUS];
 
-int __m68k_bh_counter;
+unsigned int local_bh_count[NR_CPUS];
 
 static void dummy_enable_irq(unsigned int irq);
 static void dummy_disable_irq(unsigned int irq);
@@ -214,7 +214,7 @@
 {
 	if (vec >= VEC_INT1 && vec <= VEC_INT7) {
 		vec -= VEC_SPUR;
-		kstat.interrupts[vec]++;
+		kstat.irqs[0][vec]++;
 		irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
 	} else {
 		if (mach_process_int)
@@ -233,7 +233,7 @@
 	if (mach_default_handler) {
 		for (i = 0; i < SYS_IRQS; i++) {
 			len += sprintf(buf+len, "auto %2d: %10u ", i,
-			               i ? kstat.interrupts[i] : num_spurious);
+			               i ? kstat.irqs[0][i] : num_spurious);
 			if (irq_list[i].flags & IRQ_FLG_LOCK)
 				len += sprintf(buf+len, "L ");
 			else
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/m68k_defs.c linux/arch/m68k/kernel/m68k_defs.c
--- v2.1.86/linux/arch/m68k/kernel/m68k_defs.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/kernel/m68k_defs.c	Thu Feb 12 16:30:12 1998
@@ -0,0 +1,23 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+
+#define DEFINE(sym, val) \
+	asm volatile("\n#define " #sym " %0" : : "i" (val))
+
+int main(void)
+{
+	DEFINE(TS_TSS, offsetof(struct task_struct, tss));
+	DEFINE(TS_ESP0, offsetof(struct task_struct, tss.esp0));
+	DEFINE(TS_FPU, offsetof(struct task_struct, tss.fp));
+	return 0;
+}
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- v2.1.86/linux/arch/m68k/kernel/m68k_ksyms.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Thu Feb 12 16:30:12 1998
@@ -26,16 +26,15 @@
 
 /* platform dependent support */
 
-EXPORT_SYMBOL(memcmp);
 EXPORT_SYMBOL(m68k_machtype);
 EXPORT_SYMBOL(m68k_cputype);
 EXPORT_SYMBOL(m68k_is040or060);
 EXPORT_SYMBOL(cache_push);
-EXPORT_SYMBOL(cache_push_v);
 EXPORT_SYMBOL(cache_clear);
 EXPORT_SYMBOL(mm_vtop);
 EXPORT_SYMBOL(mm_ptov);
 EXPORT_SYMBOL(mm_end_of_chunk);
+EXPORT_SYMBOL(kernel_map);
 EXPORT_SYMBOL(m68k_debug_device);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(dump_thread);
@@ -43,7 +42,7 @@
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(local_irq_count);
-EXPORT_SYMBOL(__m68k_bh_counter);
+EXPORT_SYMBOL(local_bh_count);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
@@ -55,6 +54,7 @@
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memcmp);
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.1.86/linux/arch/m68k/kernel/process.c	Sat Aug 16 09:51:07 1997
+++ linux/arch/m68k/kernel/process.c	Thu Feb 12 16:30:12 1998
@@ -65,7 +65,7 @@
 	current->priority = -100;
 	current->counter = -100;
 	for (;;){
-		if (!resched_needed())
+		if (!need_resched)
 #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
 			/* block out HSYNC on the atari (falcon) */
 			__asm__("stop #0x2200" : : : "cc");
@@ -113,17 +113,14 @@
 		printk("USP: %08lx\n", rdusp());
 }
 
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-}
-
 void flush_thread(void)
 {
+	unsigned long zero = 0;
 	set_fs(USER_DS);
-	current->tss.fs = USER_DS;
+	current->tss.fs = __USER_DS;
+	asm volatile (".chip 68k/68881\n\t"
+		      "frestore %0@\n\t"
+		      ".chip 68k" : : "a" (&zero));
 }
 
 /*
@@ -160,10 +157,6 @@
 	return ret;
 }
 
-void release_thread(struct task_struct *dead_task)
-{
-}
-
 int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 		 struct task_struct * p, struct pt_regs * regs)
 {
@@ -190,13 +183,12 @@
 	 * Must save the current SFC/DFC value, NOT the value when
 	 * the parent was last descheduled - RGH  10-08-96
 	 */
-	p->tss.fs = get_fs();
+	p->tss.fs = get_fs().seg;
 
 	/* Copy the current fpu state */
 	asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory");
 
-	if((!CPU_IS_060 && p->tss.fpstate[0]) ||
-	   (CPU_IS_060 && p->tss.fpstate[2]))
+	if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2])
 	  asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
 			"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
 			: : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0])
@@ -215,7 +207,7 @@
 
   /* First dump the fpu context to avoid protocol violation.  */
   asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-  if((!CPU_IS_060 && !fpustate[0]) || (CPU_IS_060 && !fpustate[2]))
+  if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
      return 0;
 
   asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.1.86/linux/arch/m68k/kernel/ptrace.c	Sat Aug 16 09:51:07 1997
+++ linux/arch/m68k/kernel/ptrace.c	Thu Feb 12 16:30:12 1998
@@ -10,7 +10,6 @@
  * this archive for more details.
  */
 
-#include <stddef.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -24,6 +23,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
+#include <asm/processor.h>
 
 /*
  * does not yet catch signals sent when the child dies.
@@ -439,7 +439,7 @@
 			long tmp;
 
 			ret = -EIO;
-			if ((unsigned long) data >= NSIG)
+			if ((unsigned long) data >= _NSIG)
 				goto out;
 			if (request == PTRACE_SYSCALL)
 				child->flags |= PF_TRACESYS;
@@ -477,7 +477,7 @@
 			long tmp;
 
 			ret = -EIO;
-			if ((unsigned long) data >= NSIG)
+			if ((unsigned long) data >= _NSIG)
 				goto out;
 			child->flags &= ~PF_TRACESYS;
 			tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
@@ -494,7 +494,7 @@
 			long tmp;
 
 			ret = -EIO;
-			if ((unsigned long) data >= NSIG)
+			if ((unsigned long) data >= _NSIG)
 				goto out;
 			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 			wake_up_process(child);
@@ -509,6 +509,59 @@
 			goto out;
 		}
 
+		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+		  	int i;
+			unsigned long tmp;
+			for (i = 0; i < 19; i++) {
+			    tmp = get_reg(child, i);
+			    if (i == PT_SR)
+				tmp >>= 16;
+			    if (put_user(tmp, (unsigned long *) data)) {
+				ret = -EFAULT;
+				goto out;
+			    }
+			    data += sizeof(long);
+			}
+			ret = 0;
+			goto out;
+		}
+
+		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+			int i;
+			unsigned long tmp;
+			for (i = 0; i < 19; i++) {
+			    if (get_user(tmp, (unsigned long *) data)) {
+				ret = -EFAULT;
+				goto out;
+			    }
+			    if (i == PT_SR) {
+				tmp &= SR_MASK;
+				tmp <<= 16;
+				tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+			    }
+			    put_reg(child, i, tmp);
+			    data += sizeof(long);
+			}
+			ret = 0;
+			goto out;
+		}
+
+		case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+			ret = 0;
+			if (copy_to_user((void *)data, &child->tss.fp,
+					 sizeof(struct user_m68kfp_struct)))
+				ret = -EFAULT;
+			goto out;
+		}
+
+		case PTRACE_SETFPREGS: { /* Set the child FPU state. */
+			ret = 0;
+			if (copy_from_user(&child->tss.fp, (void *)data,
+					   sizeof(struct user_m68kfp_struct)))
+				ret = -EFAULT;
+			goto out;
+		}
+
 		default:
 			ret = -EIO;
 			goto out;
@@ -533,9 +586,10 @@
 	 * 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;
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
 out:
 	unlock_kernel();
 }
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.1.86/linux/arch/m68k/kernel/setup.c	Mon Jun 16 16:35:53 1997
+++ linux/arch/m68k/kernel/setup.c	Thu Feb 12 16:30:12 1998
@@ -36,15 +36,13 @@
 #include <asm/pgtable.h>
 #endif
 
-u_long m68k_machtype;
-u_long m68k_cputype;
-u_long m68k_fputype;
-u_long m68k_mmutype;
+unsigned long m68k_machtype;
+unsigned long m68k_cputype;
+unsigned long m68k_fputype;
+unsigned long m68k_mmutype;
 
 int m68k_is040or060 = 0;
 
-char m68k_debug_device[6] = "";
-
 extern int end;
 extern unsigned long availmem;
 
@@ -56,6 +54,8 @@
 static char m68k_command_line[CL_SIZE];
 char saved_command_line[CL_SIZE];
 
+char m68k_debug_device[6] = "";
+
 void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata;
 /* machine dependent keyboard functions */
 int (*mach_keyb_init) (void) __initdata;
@@ -74,23 +74,34 @@
 int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
 void (*mach_reset)( void );
-struct fb_info *(*mach_fb_init)(long *) __initdata;
 long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-void (*mach_video_setup) (char *, int *) __initdata;
-#ifdef CONFIG_BLK_DEV_FD
-int (*mach_floppy_init) (void) __initdata = NULL;
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
 void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
 void (*mach_floppy_eject) (void) = NULL;
 #endif
+#ifdef CONFIG_HEARTBEAT
+void (*mach_heartbeat) (int) = NULL;
+#endif
+
+extern void base_trap_init(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+int mach_sysrq_key = -1;
+int mach_sysrq_shift_state = 0;
+int mach_sysrq_shift_mask = 0;
+char *mach_sysrq_xlate = NULL;
+#endif
 
 extern int amiga_parse_bootinfo(const struct bi_record *);
 extern int atari_parse_bootinfo(const struct bi_record *);
+extern int mac_parse_bootinfo(const struct bi_record *);
 
 extern void config_amiga(void);
 extern void config_atari(void);
 extern void config_mac(void);
 extern void config_sun3(void);
 extern void config_apollo(void);
+extern void config_mvme16x(void);
 
 #define MASK_256K 0xfffc0000
 
@@ -132,6 +143,8 @@
 		    unknown = amiga_parse_bootinfo(record);
 		else if (MACH_IS_ATARI)
 		    unknown = atari_parse_bootinfo(record);
+		else if (MACH_IS_MAC)
+		    unknown = mac_parse_bootinfo(record);
 		else
 		    unknown = 1;
 	}
@@ -145,7 +158,6 @@
 __initfunc(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;
@@ -158,19 +170,15 @@
 	else if (CPU_IS_060)
 		m68k_is040or060 = 6;
 
+	base_trap_init();
+
 	/* clear the fpu if we have one */
 	if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
 		volatile int zero = 0;
 		asm __volatile__ ("frestore %0" : : "m" (zero));
 	}
 
-	memory_start = availmem;
-	memory_end = 0;
-
-	for (i = 0; i < m68k_num_memory; i++)
-		memory_end += m68k_memory[i].size & MASK_256K;
-
-	init_task.mm->start_code = 0;
+	init_task.mm->start_code = PAGE_OFFSET;
 	init_task.mm->end_code = (unsigned long) &_etext;
 	init_task.mm->end_data = (unsigned long) &_edata;
 	init_task.mm->brk = (unsigned long) &_end;
@@ -190,6 +198,15 @@
 		if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0;
 		i = 1;
 	    }
+#ifdef CONFIG_ATARI
+	    /* This option must be parsed very early */
+	    if (!strncmp( p, "switches=", 9 )) {
+		extern void atari_switches_setup( const char *, int );
+		atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ?
+				           (q - (p+9)) : strlen(p+9) );
+		i = 1;
+	    }
+#endif
 
 	    if (i) {
 		/* option processed, delete it */
@@ -202,9 +219,6 @@
 	    }
 	}
 
-	*memory_start_p = memory_start;
-	*memory_end_p = memory_end;
-
 	switch (m68k_machtype) {
 #ifdef CONFIG_AMIGA
 	    case MACH_AMIGA:
@@ -231,6 +245,11 @@
 	    	config_apollo();
 	    	break;
 #endif
+#ifdef CONFIG_MVME16x
+	    case MACH_MVME16x:
+	    	config_mvme16x();
+	    	break;
+#endif
 	    default:
 		panic ("No configuration setup");
 	}
@@ -241,6 +260,11 @@
 		initrd_end = initrd_start + m68k_ramdisk.size;
 	}
 #endif
+
+	*memory_start_p = availmem;
+	*memory_end_p = 0;
+	for (i = 0; i < m68k_num_memory; i++)
+		*memory_end_p += m68k_memory[i].size & MASK_256K;
 }
 
 int get_cpuinfo(char * buffer)
@@ -337,15 +361,7 @@
     return(len);
 }
 
-#ifdef CONFIG_BLK_DEV_FD
-__initfunc(int floppy_init(void))
-{
-	if (mach_floppy_init)
-		return mach_floppy_init();
-	else
-		return 0;
-}
-
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
 __initfunc(void floppy_setup(char *str, int *ints))
 {
 	if (mach_floppy_setup)
@@ -373,8 +389,16 @@
 		*year = *mon = *day = *hour = *min = *sec = 0;
 }
 
-__initfunc(void video_setup (char *options, int *ints))
+void check_bugs(void)
 {
-	if (mach_video_setup)
-		mach_video_setup (options, ints);
+#ifndef CONFIG_FPU_EMU
+	if (m68k_fputype == 0) {
+		printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
+				"WHICH IS REQUIRED BY LINUX/M68K ***\n" );
+		printk( KERN_EMERG "Upgrade your hardware or join the FPU "
+				"emulation project\n" );
+		printk( KERN_EMERG "(see http://no-fpu.linux-m68k.org)\n" );
+		panic( "no FPU" );
+	}
+#endif
 }
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.1.86/linux/arch/m68k/kernel/signal.c	Sat Aug 16 09:51:07 1997
+++ linux/arch/m68k/kernel/signal.c	Thu Feb 12 16:30:12 1998
@@ -12,13 +12,15 @@
  * Linux/m68k support by Hamish Macdonald
  *
  * 68060 fixes by Jesper Skov
+ *
+ * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
  */
 
 /*
  * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
  * Atari :-) Current limitation: Only one sigstack can be active at one time.
- * If a second signal with SA_STACK set arrives while working on a sigstack,
- * SA_STACK is ignored. This behaviour avoids lots of trouble with nested
+ * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
+ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
  * signal handlers!
  */
 
@@ -30,22 +32,19 @@
 #include <linux/wait.h>
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
+#include <linux/stddef.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/traps.h>
+#include <asm/ucontext.h>
 
-#define offsetof(type, member)  ((size_t)(&((type *)0)->member))
-
-#define _S(nr) (1<<((nr)-1))
-
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
 			 int options, unsigned long *ru);
-
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
 
 const int frame_extra_sizes[16] = {
   0,
@@ -67,54 +66,232 @@
 };
 
 /*
- * atomically swap in the new signal mask, and wait for a signal.
+ * 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;
+	old_sigset_t mask = regs->d3;
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending(current);
+
+	regs->d0 = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, regs))
+			return -EINTR;
+	}
+}
+
+asmlinkage int
+do_rt_sigsuspend(struct pt_regs *regs)
+{
+	sigset_t *unewset = (sigset_t *)regs->d1;
+	size_t sigsetsize = (size_t)regs->d2;
+	sigset_t saveset, newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending(current);
 
-	current->blocked = newmask & _BLOCKABLE;
 	regs->d0 = -EINTR;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(oldmask, regs))
+		if (do_signal(&saveset, regs))
 			return -EINTR;
 	}
 }
 
+asmlinkage int 
+sys_sigaction(int sig, const struct old_sigaction *act,
+	      struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+	char *pretcode;
+	int sig;
+	int code;
+	struct sigcontext *psc;
+	char retcode[8];
+	unsigned long extramask[_NSIG_WORDS-1];
+	struct sigcontext sc;
+};
+
+struct rt_sigframe
+{
+	char *pretcode;
+	int sig;
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	struct ucontext uc;
+	char retcode[8];
+};
+
+
 static unsigned char fpu_version = 0;	/* version number of fpu, set by setup_frame */
 
-asmlinkage int do_sigreturn(unsigned long __unused)
+static inline void restore_fpu_state(struct sigcontext *sc)
 {
-	struct sigcontext context;
-	struct pt_regs *regs;
-	struct switch_stack *sw;
-	int fsize = 0;
-	int formatvec = 0;
-	unsigned long fp;
-	unsigned long usp = rdusp();
+	if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
+	    /* Verify the frame format.  */
+	    if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
+		goto badframe;
+	    if (CPU_IS_020_OR_030) {
+		if (m68k_fputype & FPU_68881 &&
+		    !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
+		    goto badframe;
+		if (m68k_fputype & FPU_68882 &&
+		    !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
+		    goto badframe;
+	    } else if (CPU_IS_040) {
+		if (!(sc->sc_fpstate[1] == 0x00 ||
+                      sc->sc_fpstate[1] == 0x28 ||
+                      sc->sc_fpstate[1] == 0x60))
+		    goto badframe;
+	    } else if (CPU_IS_060) {
+		if (!(sc->sc_fpstate[3] == 0x00 ||
+                      sc->sc_fpstate[3] == 0x60 ||
+		      sc->sc_fpstate[3] == 0xe0))
+		    goto badframe;
+	    } else
+		goto badframe;
 
-#if 0
-	printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
-#endif
+	    __asm__ volatile (".chip 68k/68881\n\t"
+			      "fmovemx %0,%/fp0-%/fp1\n\t"
+			      "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
+			      ".chip 68k"
+			      : /* no outputs */
+			      : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
+	}
+	__asm__ volatile (".chip 68k/68881\n\t"
+			  "frestore %0\n\t"
+			  ".chip 68k" : : "m" (*sc->sc_fpstate));
+	return;
+
+badframe:
+        do_exit(SIGSEGV);
+}
 
-	/* get stack frame pointer */
-	sw = (struct switch_stack *) &__unused;
-	regs = (struct pt_regs *) (sw + 1);
+#define FPCONTEXT_SIZE	216
+#define uc_fpstate	uc_filler[0]
+#define uc_formatvec	uc_filler[FPCONTEXT_SIZE/4]
+#define uc_extra	uc_filler[FPCONTEXT_SIZE/4+1]
 
-	/* get previous context (including pointer to possible extra junk) */
-	if (copy_from_user(&context,(void *)usp, sizeof(context)))
+static inline void rt_restore_fpu_state(struct ucontext *uc)
+{
+	unsigned char fpstate[FPCONTEXT_SIZE];
+	int context_size = CPU_IS_060 ? 8 : 0;
+	fpregset_t fpregs;
+
+	if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
+		goto badframe;
+	if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
+		if (!CPU_IS_060)
+			context_size = fpstate[1];
+		/* Verify the frame format.  */
+		if (!CPU_IS_060 && (fpstate[0] != fpu_version))
+			goto badframe;
+		if (CPU_IS_020_OR_030) {
+			if (m68k_fputype & FPU_68881 &&
+			    !(context_size == 0x18 || context_size == 0xb4))
+				goto badframe;
+			if (m68k_fputype & FPU_68882 &&
+			    !(context_size == 0x38 || context_size == 0xd4))
+				goto badframe;
+		} else if (CPU_IS_040) {
+			if (!(context_size == 0x00 ||
+			      context_size == 0x28 ||
+			      context_size == 0x60))
+				goto badframe;
+		} else if (CPU_IS_060) {
+			if (!(fpstate[3] == 0x00 ||
+			      fpstate[3] == 0x60 ||
+			      fpstate[3] == 0xe0))
+				goto badframe;
+		} else
+			goto badframe;
+		if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
+				     sizeof(fpregs)))
+			goto badframe;
+		__asm__ volatile (".chip 68k/68881\n\t"
+				  "fmovemx %0,%/fp0-%/fp7\n\t"
+				  "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
+				  ".chip 68k"
+				  : /* no outputs */
+				  : "m" (*fpregs.f_fpregs),
+				    "m" (fpregs.f_pcr));
+	}
+	if (context_size &&
+	    __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1,
+			     context_size))
 		goto badframe;
+	__asm__ volatile (".chip 68k/68881\n\t"
+			  "frestore %0\n\t"
+			  ".chip 68k" : : "m" (*fpstate));
+	return;
 
-	fp = usp + sizeof (context);
+badframe:
+        do_exit(SIGSEGV);
+}
 
-	/* restore signal mask */
-	current->blocked = context.sc_mask & _BLOCKABLE;
+static inline int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp)
+{
+	int fsize, formatvec;
+	struct sigcontext context;
 
+	/* get previous context */
+	if (copy_from_user(&context, usc, sizeof(context)))
+		goto badframe;
+	
 	/* restore passed registers */
-	regs->d0 = context.sc_d0;
 	regs->d1 = context.sc_d1;
 	regs->a0 = context.sc_a0;
 	regs->a1 = context.sc_a1;
@@ -125,43 +302,8 @@
 	formatvec = context.sc_formatvec;
 	regs->format = formatvec >> 12;
 	regs->vector = formatvec & 0xfff;
-	if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){
-	    /* Verify the frame format.  */
-	    if (!CPU_IS_060 && (context.sc_fpstate[0] != fpu_version))
-	      goto badframe;
-	    if (m68k_fputype & FPU_68881)
-	      {
-		if (context.sc_fpstate[1] != 0x18
-		    && context.sc_fpstate[1] != 0xb4)
-		  goto badframe;
-	      }
-	    else if (m68k_fputype & FPU_68882)
-	      {
-		if (context.sc_fpstate[1] != 0x38
-		    && context.sc_fpstate[1] != 0xd4)
-		  goto badframe;
-	      }
-	    else if (m68k_fputype & FPU_68040)
-	      {
-		if (!(context.sc_fpstate[1] == 0x00 ||
-                      context.sc_fpstate[1] == 0x28 ||
-                      context.sc_fpstate[1] == 0x60))
-		  goto badframe;
-	      }
-	    else if (m68k_fputype & FPU_68060)
-	      {
-		if (!(context.sc_fpstate[3] == 0x00 ||
-                      context.sc_fpstate[3] == 0x60 ||
-		      context.sc_fpstate[3] == 0xe0))
-		  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));
+
+	restore_fpu_state(&context);
 
 	fsize = frame_extra_sizes[regs->format];
 	if (fsize < 0) {
@@ -174,14 +316,13 @@
 		goto badframe;
 	}
 
-	if (context.sc_usp != fp+fsize)
-		current->flags &= ~PF_ONSIGSTK;
-
 	/* OK.	Make room on the supervisor stack for the extra junk,
 	 * if necessary.
 	 */
 
 	if (fsize) {
+		struct switch_stack *sw = (struct switch_stack *)regs - 1;
+		regs->d0 = context.sc_d0;
 #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
 		__asm__ __volatile__
 			("   movel %0,%/a0\n\t"
@@ -215,127 +356,494 @@
 		goto badframe;
 	}
 
+	return context.sc_d0;
+
+badframe:
+        do_exit(SIGSEGV);
+}
+
+static inline int
+rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
+		    struct ucontext *uc)
+{
+	int fsize, temp;
+	greg_t *gregs = uc->uc_mcontext.gregs;
+
+	__get_user(temp, &uc->uc_mcontext.version);
+	if (temp != MCONTEXT_VERSION)
+		goto badframe;
+	/* restore passed registers */
+	__get_user(regs->d0, &gregs[0]);
+	__get_user(regs->d1, &gregs[1]);
+	__get_user(regs->d2, &gregs[2]);
+	__get_user(regs->d3, &gregs[3]);
+	__get_user(regs->d4, &gregs[4]);
+	__get_user(regs->d5, &gregs[5]);
+	__get_user(sw->d6, &gregs[6]);
+	__get_user(sw->d7, &gregs[7]);
+	__get_user(regs->a0, &gregs[8]);
+	__get_user(regs->a1, &gregs[9]);
+	__get_user(regs->a2, &gregs[10]);
+	__get_user(sw->a3, &gregs[11]);
+	__get_user(sw->a4, &gregs[12]);
+	__get_user(sw->a5, &gregs[13]);
+	__get_user(sw->a6, &gregs[14]);
+	__get_user(temp, &gregs[15]);
+	wrusp(temp);
+	__get_user(regs->pc, &gregs[16]);
+	__get_user(temp, &gregs[17]);
+	regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
+	regs->orig_d0 = -1;		/* disable syscall checks */
+	__get_user(temp, &uc->uc_formatvec);
+	regs->format = temp >> 12;
+	regs->vector = temp & 0xfff;
+
+	rt_restore_fpu_state(uc);
+
+	fsize = frame_extra_sizes[regs->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) {
+#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 */
+			 "   lsrl  #2,%1\n\t"
+			 "   subql #1,%1\n\t"
+			 "2: movesl %4@+,%2\n\t"
+			 "3: movel %2,%/a0@+\n\t"
+			 "   dbra %1,2b\n\t"
+			 "   bral " SYMBOL_NAME_STR(ret_from_signal) "\n"
+			 "4:\n"
+			 ".section __ex_table,\"a\"\n"
+			 "   .align 4\n"
+			 "   .long 2b,4b\n"
+			 "   .long 3b,4b\n"
+			 ".previous"
+			 : /* no outputs, it doesn't ever return */
+			 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
+			   "n" (frame_offset), "a" (&uc->uc_extra)
+			 : "a0");
+#undef frame_offset
+		/*
+		 * If we ever get here an exception occured while
+		 * building the above stack-frame.
+		 */
+		goto badframe;
+	}
+
 	return regs->d0;
+
 badframe:
         do_exit(SIGSEGV);
 }
 
+asmlinkage int do_sigreturn(unsigned long __unused)
+{
+	struct switch_stack *sw = (struct switch_stack *) &__unused;
+	struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+	unsigned long usp = rdusp();
+	struct sigframe *frame = (struct sigframe *)(usp - 24);
+	sigset_t set;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
+	    (_NSIG_WORDS > 1 &&
+	     __copy_from_user(&set.sig[1], &frame->extramask,
+			      sizeof(frame->extramask))))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	current->blocked = set;
+	recalc_sigpending(current);
+	
+	return restore_sigcontext(regs, &frame->sc, frame + 1);
+
+badframe:
+	do_exit(SIGSEGV);
+}
+
+asmlinkage int do_rt_sigreturn(unsigned long __unused)
+{
+	struct switch_stack *sw = (struct switch_stack *) &__unused;
+	struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+	unsigned long usp = rdusp();
+	struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
+	sigset_t set;
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	current->blocked = set;
+	recalc_sigpending(current);
+	
+	return rt_restore_ucontext(regs, sw, &frame->uc);
+
+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".
+ * Set up a signal frame.
  */
 
-#define UFRAME_SIZE(fs) (sizeof(struct sigcontext)/4 + 6 + fs/4)
+static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
+{
+	__asm__ volatile (".chip 68k/68881\n\t"
+			  "fsave %0\n\t"
+			  ".chip 68k"
+			  : : "m" (*sc->sc_fpstate) : "memory");
+
+	if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
+		fpu_version = sc->sc_fpstate[0];
+		if (CPU_IS_020_OR_030 &&
+		    regs->vector >= (VEC_FPBRUC * 4) &&
+		    regs->vector <= (VEC_FPNAN * 4)) {
+			/* Clear pending exception in 68882 idle frame */
+			if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
+				sc->sc_fpstate[0x38] |= 1 << 3;
+		}
+		__asm__ volatile (".chip 68k/68881\n\t"
+				  "fmovemx %/fp0-%/fp1,%0\n\t"
+				  "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
+				  ".chip 68k"
+				  : /* no outputs */
+				  : "m" (*sc->sc_fpregs),
+				    "m" (*sc->sc_fpcntl)
+				  : "memory");
+	}
+}
 
-static inline void setup_frame (struct sigaction * sa, struct pt_regs *regs,
-				int signr, unsigned long oldmask)
+static inline void rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
 {
-	struct sigcontext context;
-	unsigned long *frame, *tframe;
+	unsigned char fpstate[FPCONTEXT_SIZE];
+	int context_size = CPU_IS_060 ? 8 : 0;
+
+	__asm__ volatile (".chip 68k/68881\n\t"
+			  "fsave %0\n\t"
+			  ".chip 68k"
+			  : : "m" (*fpstate) : "memory");
+
+	__put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
+	if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
+		fpregset_t fpregs;
+		if (!CPU_IS_060)
+			context_size = fpstate[1];
+		fpu_version = fpstate[0];
+		if (CPU_IS_020_OR_030 &&
+		    regs->vector >= (VEC_FPBRUC * 4) &&
+		    regs->vector <= (VEC_FPNAN * 4)) {
+			/* Clear pending exception in 68882 idle frame */
+			if (*(unsigned short *) fpstate == 0x1f38)
+				fpstate[0x38] |= 1 << 3;
+		}
+		__asm__ volatile (".chip 68k/68881\n\t"
+				  "fmovemx %/fp0-%/fp7,%0\n\t"
+				  "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
+				  ".chip 68k"
+				  : /* no outputs */
+				  : "m" (*fpregs.f_fpregs),
+				    "m" (fpregs.f_pcr)
+				  : "memory");
+		copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, sizeof(fpregs));
+	}
+	if (context_size)
+		copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
+			     context_size);
+}
+
+static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+			     unsigned long mask)
+{
+	sc->sc_mask = mask;
+	sc->sc_usp = rdusp();
+	sc->sc_d0 = regs->d0;
+	sc->sc_d1 = regs->d1;
+	sc->sc_a0 = regs->a0;
+	sc->sc_a1 = regs->a1;
+	sc->sc_sr = regs->sr;
+	sc->sc_pc = regs->pc;
+	sc->sc_formatvec = regs->format << 12 | regs->vector;
+	save_fpu_state(sc, regs);
+}
+
+static inline void rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
+{
+	struct switch_stack *sw = (struct switch_stack *)regs - 1;
+	greg_t *gregs = uc->uc_mcontext.gregs;
+
+	__put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
+	__put_user(regs->d0, &gregs[0]);
+	__put_user(regs->d1, &gregs[1]);
+	__put_user(regs->d2, &gregs[2]);
+	__put_user(regs->d3, &gregs[3]);
+	__put_user(regs->d4, &gregs[4]);
+	__put_user(regs->d5, &gregs[5]);
+	__put_user(sw->d6, &gregs[6]);
+	__put_user(sw->d7, &gregs[7]);
+	__put_user(regs->a0, &gregs[8]);
+	__put_user(regs->a1, &gregs[9]);
+	__put_user(regs->a2, &gregs[10]);
+	__put_user(sw->a3, &gregs[11]);
+	__put_user(sw->a4, &gregs[12]);
+	__put_user(sw->a5, &gregs[13]);
+	__put_user(sw->a6, &gregs[14]);
+	__put_user(rdusp(), &gregs[15]);
+	__put_user(regs->pc, &gregs[16]);
+	__put_user(regs->sr, &gregs[17]);
+	__put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
+	rt_save_fpu_state(uc, regs);
+}
+
+static inline void push_cache (unsigned long vaddr)
+{
+	/*
+	 * Using the old cache_push_v() was really a big waste.
+	 *
+	 * What we are trying to do is to flush 8 bytes to ram.
+	 * Flushing 2 cache lines of 16 bytes is much cheaper than
+	 * flushing 1 or 2 pages, as previously done in
+	 * cache_push_v().
+	 *                                                     Jes
+	 */
+	if (CPU_IS_040) {
+		unsigned long temp;
+
+		__asm__ __volatile__ (".chip 68040\n\t"
+				      "nop\n\t"
+				      "ptestr (%1)\n\t"
+				      "movec %%mmusr,%0\n\t"
+				      ".chip 68k"
+				      : "=r" (temp)
+				      : "a" (vaddr));
+
+		temp &= PAGE_MASK;
+		temp |= vaddr & ~PAGE_MASK;
+
+		__asm__ __volatile__ (".chip 68040\n\t"
+				      "nop\n\t"
+				      "cpushl %%bc,(%0)\n\t"
+				      ".chip 68k"
+				      : : "a" (temp));
+		if (((vaddr + 8) ^ vaddr) & ~15) {
+			if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
+				__asm__ __volatile__ (".chip 68040\n\t"
+						      "nop\n\t"
+						      "ptestr (%1)\n\t"
+						      "movec %%mmusr,%0\n\t"
+						      ".chip 68k"
+						      : "=r" (temp)
+						      : "a" (vaddr + 8));
+
+			temp &= PAGE_MASK;
+			temp |= (vaddr + 8) & ~PAGE_MASK;
+
+			__asm__ __volatile__ (".chip 68040\n\t"
+					      "nop\n\t"
+					      "cpushl %%bc,(%0)\n\t"
+					      ".chip 68k"
+					      : : "a" (temp));
+		}
+	}
+	else if (CPU_IS_060) {
+		unsigned long temp;
+		__asm__ __volatile__ (".chip 68060\n\t"
+				      "plpar (%0)\n\t"
+				      ".chip 68k"
+				      : "=a" (temp)
+				      : "0" (vaddr));
+		__asm__ __volatile__ (".chip 68060\n\t"
+				      "cpushl %%bc,(%0)\n\t"
+				      ".chip 68k"
+				      : : "a" (temp));
+		if (((vaddr + 8) ^ vaddr) & ~15) {
+			if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
+				__asm__ __volatile__ (".chip 68060\n\t"
+						      "plpar (%0)\n\t"
+						      ".chip 68k"
+						      : "=a" (temp)
+						      : "0" (vaddr + 8));
+			__asm__ __volatile__ (".chip 68060\n\t"
+					      "cpushl %%bc,(%0)\n\t"
+					      ".chip 68k"
+					      : : "a" (temp));
+		}
+	}
+	else {
+		/*
+		 * 68030/68020 have no writeback cache;
+		 * still need to clear icache.
+		 * Note that vaddr is guaranteed to be long word aligned.
+		 */
+		unsigned long temp;
+		asm volatile ("movec %%cacr,%0" : "=r" (temp));
+		temp += 4;
+		asm volatile ("movec %0,%%caar\n\t"
+			      "movec %1,%%cacr"
+			      : : "r" (vaddr), "r" (temp));
+		asm volatile ("movec %0,%%caar\n\t"
+			      "movec %1,%%cacr"
+			      : : "r" (vaddr + 4), "r" (temp));
+	}
+}
+
+static void setup_frame (int sig, struct k_sigaction *ka,
+			 sigset_t *set, struct pt_regs *regs)
+{
+	struct sigframe *frame;
 	int fsize = frame_extra_sizes[regs->format];
+	struct sigcontext context;
 
 	if (fsize < 0) {
+#ifdef DEBUG
 		printk ("setup_frame: Unknown frame format %#x\n",
 			regs->format);
-		do_exit(SIGSEGV);
+#endif
+		goto segv_and_exit;
 	}
 
-	frame = (unsigned long *)rdusp();
-	if (!(current->flags & PF_ONSIGSTK) && (sa->sa_flags & SA_STACK)) {
-		frame = (unsigned long *)sa->sa_restorer;
+	frame = (struct sigframe *)((rdusp() - sizeof(*frame) - fsize) & -8);
+
+	if (!(current->flags & PF_ONSIGSTK) && (ka->sa.sa_flags & SA_ONSTACK)) {
+		frame = (struct sigframe *)(((unsigned long)ka->sa.sa_restorer
+					     - sizeof(*frame) - fsize) & -8);
 		current->flags |= PF_ONSIGSTK;
 	}
-	frame -= UFRAME_SIZE(fsize);
 
 	if (fsize) {
-		if (copy_to_user (frame + UFRAME_SIZE(0), regs + 1, fsize))
-			do_exit(SIGSEGV);
+		if (copy_to_user (frame + 1, regs + 1, fsize))
+			goto segv_and_exit;
 		regs->stkadj = fsize;
 	}
 
-/* set up the "normal" stack seen by the signal handler */
-	tframe = frame;
+	__put_user((current->exec_domain
+		    && current->exec_domain->signal_invmap
+		    && sig < 32
+		    ? current->exec_domain->signal_invmap[sig]
+		    : sig),
+		   &frame->sig);
+
+	__put_user(regs->vector, &frame->code);
+	__put_user(&frame->sc, &frame->psc);
+
+	if (_NSIG_WORDS > 1)
+		copy_to_user(frame->extramask, &set->sig[1],
+			     sizeof(frame->extramask));
+
+	setup_sigcontext(&context, regs, set->sig[0]);
+	if (copy_to_user (&frame->sc, &context, sizeof(context)))
+		goto segv_and_exit;
+
+	/* Set up to return from userspace.  */
+	__put_user(frame->retcode, &frame->pretcode);
+	/* addaw #20,sp */
+	__put_user(0xdefc0014, (long *)(frame->retcode + 0));
+	/* moveq #,d0; trap #0 */
+	__put_user(0x70004e40 + (__NR_sigreturn << 16),
+		   (long *)(frame->retcode + 4));
 
-	/* return address points to code on stack */
+	push_cache ((unsigned long) &frame->retcode);
 
-	if(put_user((ulong)(frame+4), tframe))
-		do_exit(SIGSEGV);
-	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++;
+	/*
+	 * no matter what frame format we were using before, we
+	 * will do the "RTE" using a normal 4 word frame.
+	 */
+	regs->format = 0;
 
-	__put_user(regs->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	      = rdusp();
-	context.sc_d0	      = regs->d0;
-	context.sc_d1	      = regs->d1;
-	context.sc_a0	      = regs->a0;
-	context.sc_a1	      = regs->a1;
-	context.sc_sr	      = regs->sr;
-	context.sc_pc	      = regs->pc;
-	context.sc_formatvec  = (regs->format << 12 | regs->vector);
-	__asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory");
-	if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){
-		fpu_version = context.sc_fpstate[0];
-		__asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t"
-				  "fmoveml %/fpcr/%/fpsr/%/fpiar,%1"
-				  : /* no outputs */
-				  : "m" (*context.sc_fpregs),
-				  "m" (*context.sc_fpcntl)
-				  : "memory");
+	/* Set up registers for signal handler */
+	wrusp ((unsigned long) frame);
+	regs->pc = (unsigned long) ka->sa.sa_handler;
+
+	/* Prepare to skip over the extra stuff in the exception frame.  */
+	if (regs->stkadj) {
+		struct pt_regs *tregs =
+			(struct pt_regs *)((ulong)regs + regs->stkadj);
+#if DEBUG
+		printk("Performing stackadjust=%04x\n", regs->stkadj);
+#endif
+		/* This must be copied with decreasing addresses to
+                   handle overlaps.  */
+		tregs->vector = regs->vector;
+		tregs->format = regs->format;
+		tregs->pc = regs->pc;
+		tregs->sr = regs->sr;
 	}
-	if (copy_to_user (tframe, &context, sizeof(context)))
-		do_exit(SIGSEGV);
+	return;
+
+segv_and_exit:
+	do_exit(SIGSEGV);
+}
+
+static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
+			    sigset_t *set, struct pt_regs *regs)
+{
+	struct rt_sigframe *frame;
+	int fsize = frame_extra_sizes[regs->format];
+
+	if (fsize < 0) {
+#ifdef DEBUG
+		printk ("setup_frame: Unknown frame format %#x\n",
+			regs->format);
+#endif
+		goto segv_and_exit;
+	}
+
+	frame = (struct rt_sigframe *)((rdusp() - sizeof(*frame)) & -8);
+
+	/* XXX: Check here if we need to switch stacks.. */
+
+	if (fsize) {
+		if (copy_to_user (&frame->uc.uc_extra, regs + 1, fsize))
+			goto segv_and_exit;
+		regs->stkadj = fsize;
+	}
+
+	__put_user((current->exec_domain
+		    && current->exec_domain->signal_invmap
+		    && sig < 32
+		    ? current->exec_domain->signal_invmap[sig]
+		    : sig),
+		   &frame->sig);
+	__put_user(&frame->info, &frame->pinfo);
+	__put_user(&frame->uc, &frame->puc);
+	__copy_to_user(&frame->info, info, sizeof(*info));
+
+	/* Clear all the bits of the ucontext we don't use.  */
+	clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+	rt_setup_ucontext(&frame->uc, regs);
+	if (copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)))
+		goto segv_and_exit;
+
+	/* Set up to return from userspace.  */
+	__put_user(frame->retcode, &frame->pretcode);
+	/* movel #,d0; trap #0 */
+	__put_user(0x203c, (short *)(frame->retcode + 0));
+	__put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
+	__put_user(0x4e40, (short *)(frame->retcode + 6));
+
+	push_cache ((unsigned long) &frame->retcode);
 
 	/*
 	 * no matter what frame format we were using before, we
@@ -345,7 +853,7 @@
 
 	/* Set up registers for signal handler */
 	wrusp ((unsigned long) frame);
-	regs->pc = (unsigned long) sa->sa_handler;
+	regs->pc = (unsigned long) ka->sa.sa_handler;
 
 	/* Prepare to skip over the extra stuff in the exception frame.  */
 	if (regs->stkadj) {
@@ -361,13 +869,18 @@
 		tregs->pc = regs->pc;
 		tregs->sr = regs->sr;
 	}
+	return;
+
+segv_and_exit:
+	do_exit(SIGSEGV);
 }
 
 /*
  * OK, we're invoking a handler
  */
-static inline void handle_signal(unsigned long signr, struct sigaction *sa,
-				 unsigned long oldmask, struct pt_regs *regs)
+static void
+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
+	      sigset_t *oldset, struct pt_regs *regs)
 {
 	/* are we from a system call? */
 	if (regs->orig_d0 >= 0) {
@@ -378,7 +891,7 @@
 				break;
 
 			case -ERESTARTSYS:
-				if (!(sa->sa_flags & SA_RESTART)) {
+				if (!(ka->sa.sa_flags & SA_RESTART)) {
 					regs->d0 = -EINTR;
 					break;
 				}
@@ -390,12 +903,19 @@
 	}
 
 	/* set up the stack frame */
-	setup_frame(sa, regs, signr, oldmask);
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(sig, ka, info, oldset, regs);
+	else
+		setup_frame(sig, ka, oldset, regs);
 
-	if (sa->sa_flags & SA_ONESHOT)
-		sa->sa_handler = NULL;
-	if (!(sa->sa_flags & SA_NOMASK))
-		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = NULL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending(current);
+	}
 }
 
 /*
@@ -407,29 +927,28 @@
  * 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)
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
-	unsigned long mask = ~current->blocked;
-	unsigned long signr;
-	struct sigaction * sa;
+	siginfo_t info;
+	struct k_sigaction *ka;
 
 	current->tss.esp0 = (unsigned long) regs;
 
-	/* If the process is traced, all signals are passed to the debugger. */
-	if (current->flags & PF_PTRACED)
-		mask = ~0UL;
-	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),"=d" (signr)
-			:"0" (current->signal), "1" (signr));
-		sa = current->sig->action + signr;
-		signr++;
+	if (!oldset)
+		oldset = &current->blocked;
+
+	for (;;) {
+		int signr;
+
+		signr = dequeue_signal(&current->blocked, &info);
+
+		if (!signr)
+			break;
 
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
+			regs->sr &= ~PS_T;
 
 			/* Did we come from a system call? */
 			if (regs->orig_d0 >= 0) {
@@ -443,11 +962,12 @@
 			}
 			notify_parent(current, SIGCHLD);
 			schedule();
+
+			/* We're back.  Did the debugger cancel the sig?  */
 			if (!(signr = current->exit_code)) {
 			discard_frame:
-			    /* Make sure that a faulted bus cycle
-			       isn't restarted (only needed on the
-			       68030).  */
+			    /* Make sure that a faulted bus cycle isn't
+			       restarted (only needed on the 680[23]0).  */
 			    if (regs->format == 10 || regs->format == 11) {
 				regs->stkadj = frame_extra_sizes[regs->format];
 				regs->format = 0;
@@ -455,26 +975,43 @@
 			    continue;
 			}
 			current->exit_code = 0;
+
+			/* The debugger continued.  Ignore SIGSTOP.  */
 			if (signr == SIGSTOP)
 				goto discard_frame;
-			if (_S(signr) & current->blocked) {
-				current->signal |= _S(signr);
-				mask &= ~_S(signr);
+
+			/* Update the siginfo structure.  Is this good?  */
+			if (signr != info.si_signo) {
+				info.si_signo = signr;
+				info.si_errno = 0;
+				info.si_code = SI_USER;
+				info.si_pid = current->p_pptr->pid;
+				info.si_uid = current->p_pptr->uid;
+			}
+
+			/* If the (new) signal is now blocked, requeue it.  */
+			if (sigismember(&current->blocked, signr)) {
+				send_sig_info(signr, &info, current);
 				continue;
 			}
-			sa = current->sig->action + signr - 1;
 		}
-		if (sa->sa_handler == SIG_IGN) {
+
+		ka = &current->sig->action[signr-1];
+		if (ka->sa.sa_handler == SIG_IGN) {
 			if (signr != SIGCHLD)
 				continue;
-			/* check for SIGCHLD: it's special */
-			while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0)
+			/* Check for SIGCHLD: it's special.  */
+			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
 				/* nothing */;
 			continue;
 		}
-		if (sa->sa_handler == SIG_DFL) {
+
+		if (ka->sa.sa_handler == SIG_DFL) {
+			int exit_code = signr;
+
 			if (current->pid == 1)
 				continue;
+
 			switch (signr) {
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
@@ -482,31 +1019,35 @@
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
 				if (is_orphaned_pgrp(current->pgrp))
 					continue;
+				/* FALLTHRU */
+
 			case SIGSTOP:
-				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))
+				if (!(current->p_pptr->sig->action[SIGCHLD-1]
+				      .sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				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, regs))
-					signr |= 0x80;
-				}
-				/* fall through */
+				if (current->binfmt
+				    && current->binfmt->core_dump
+				    && current->binfmt->core_dump(signr, regs))
+					exit_code |= 0x80;
+				/* FALLTHRU */
+
 			default:
-				current->signal |= _S(signr & 0x7f);
+				sigaddset(&current->signal, signr);
 				current->flags |= PF_SIGNALED;
-				do_exit(signr);
+				do_exit(exit_code);
+				/* NOTREACHED */
 			}
 		}
-		handle_signal(signr, sa, oldmask, regs);
+
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal(signr, ka, &info, oldset, regs);
 		return 1;
 	}
 
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v2.1.86/linux/arch/m68k/kernel/sys_m68k.c	Thu Jul 31 13:09:16 1997
+++ linux/arch/m68k/kernel/sys_m68k.c	Thu Feb 12 16:30:12 1998
@@ -17,6 +17,7 @@
 #include <linux/stat.h>
 #include <linux/mman.h>
 #include <linux/file.h>
+#include <linux/utsname.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -308,6 +309,10 @@
 	    }
 	  if (!--i && len)
 	    {
+	      /*
+	       * No need to page align here since it is done by
+	       * virt_to_phys_040().
+	       */
 	      addr += PAGE_SIZE;
 	      i = PAGE_SIZE / 16;
 	      /* Recompute physical address when crossing a page
@@ -462,7 +467,14 @@
 	    }
 	  if (!--i && len)
 	    {
+
+	      /*
+	       * We just want to jump to the first cache line
+	       * in the next page.
+	       */
 	      addr += PAGE_SIZE;
+	      addr &= PAGE_MASK;
+
 	      i = PAGE_SIZE / 16;
 	      /* Recompute physical address when crossing a page
 	         boundary. */
@@ -559,13 +571,13 @@
 				cacr |= 4;
 			if (cache & FLUSH_CACHE_DATA)
 				cacr |= 0x400;
-			len >>= 4;
+			len >>= 2;
 			while (len--) {
 				__asm__ __volatile__ ("movec %1, %%caar\n\t"
 						      "movec %0, %%cacr"
 						      : /* no outputs */
 						      : "r" (cacr), "r" (addr));
-				addr += 16;
+				addr += 4;
 			}
 		} else {
 			/* Flush the whole cache, even if page granularity requested. */
@@ -587,4 +599,14 @@
 out:
 	unlock_kernel();
 	return ret;
+}
+
+/*
+ * Old cruft
+ */
+asmlinkage int sys_pause(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule();
+	return -ERESTARTNOHAND;
 }
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c
--- v2.1.86/linux/arch/m68k/kernel/time.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/kernel/time.c	Thu Feb 12 16:30:12 1998
@@ -66,11 +66,35 @@
 	 */
 	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
 	    xtime.tv_usec > 500000 - (tick >> 1) &&
-	    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 */
+	}
+#ifdef CONFIG_HEARTBEAT
+	/* use power LED as a heartbeat instead -- much more useful
+	   for debugging -- based on the version for PReP by Cort */
+	/* acts like an actual heart beat -- ie thump-thump-pause... */
+	if (mach_heartbeat) {
+	    static unsigned cnt = 0, period = 0, dist = 0;
+
+	    if (cnt == 0 || cnt == dist)
+		mach_heartbeat( 1 );
+	    else if (cnt == 7 || cnt == dist+7)
+		mach_heartbeat( 0 );
+
+	    if (++cnt > period) {
+		cnt = 0;
+		/* The hyperbolic function below modifies the heartbeat period
+		 * length in dependency of the current (5min) load. It goes
+		 * through the points f(0)=126, f(1)=86, f(5)=51,
+		 * f(inf)->30. */
+		period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+		dist = period / 4;
+	    }
+	}
+#endif /* CONFIG_HEARTBEAT */
 }
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v2.1.86/linux/arch/m68k/kernel/traps.c	Mon Jun 16 16:35:54 1997
+++ linux/arch/m68k/kernel/traps.c	Thu Feb 12 16:30:13 1998
@@ -36,6 +36,7 @@
 #include <asm/traps.h>
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
+#include <asm/siginfo.h>
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
@@ -64,23 +65,10 @@
     __ALIGN_STR "\n"
     SYMBOL_NAME_STR(nmihandler) ": rte");
 
-__initfunc(void trap_init (void))
+__initfunc(void base_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;
-        }
+	__asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
 
 	if (CPU_IS_040) {
 		/* set up FPSP entry points */
@@ -134,6 +122,23 @@
 	}
 }
 
+__initfunc(void trap_init (void))
+{
+	int i;
+
+	for (i = 48; i < 64; i++)
+		if (!vectors[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;
+	}
+}
+
 void set_evector(int vecnum, void (*handler)(void))
 {
 	if (vecnum >= 0 && vecnum <= 256)
@@ -202,7 +207,7 @@
 			return;
 	}
 
-	if (fslw & (MMU060_DESC_ERR | MMU060_WP)) {
+	if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
 		unsigned long errorcode;
 		unsigned long addr = fp->un.fmt4.effaddr;
 		errorcode = ((fslw & MMU060_WP) ? 1 : 0) |
@@ -230,9 +235,9 @@
 static inline unsigned long probe040 (int iswrite, int fc, unsigned long addr)
 {
 	unsigned long mmusr;
-	unsigned long fs = get_fs();
+	mm_segment_t fs = get_fs();
 
-	set_fs (fc);
+	set_fs (MAKE_MM_SEG(fc));
 
 	if (iswrite)
 		/* write */
@@ -261,7 +266,7 @@
 			     unsigned long wbd,
 			     struct frame *fp)
 {
-	unsigned long fs = get_fs ();
+	mm_segment_t fs = get_fs ();
 	unsigned long mmusr;
 	unsigned long errorcode;
 
@@ -277,7 +282,7 @@
 	  /* just return if we can't perform the writeback */
 	  return;
 
-	set_fs (wbs & WBTM_040);
+	set_fs (MAKE_MM_SEG(wbs & WBTM_040));
 	switch (wbs & WBSIZ_040) {
 	    case BA_SIZE_BYTE:
 		put_user (wbd & 0xff, (char *)wba);
@@ -833,34 +838,37 @@
 asmlinkage void trap_c(struct frame *fp)
 {
 	int sig;
+	siginfo_t info;
 
-	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);
+	if (fp->ptregs.sr & PS_S) {
+		if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
+			/* traced a trapping instruction */
+			current->flags |= PF_DTRACE;
+		} else
+			bad_super_trap(fp);
 		return;
 	}
 
 	/* send the appropriate signal to the user program */
 	switch ((fp->ptregs.vector) >> 2) {
 	    case VEC_ADDRERR:
+		info.si_code = BUS_ADRALN;
 		sig = SIGBUS;
 		break;
-	    case VEC_BUSERR:
-		sig = SIGSEGV;
-		break;
 	    case VEC_ILLEGAL:
-	    case VEC_PRIV:
 	    case VEC_LINE10:
 	    case VEC_LINE11:
+		info.si_code = ILL_ILLOPC;
+		sig = SIGILL;
+		break;
+	    case VEC_PRIV:
+		info.si_code = ILL_PRVOPC;
+		sig = SIGILL;
+		break;
 	    case VEC_COPROC:
+		info.si_code = ILL_COPROC;
+		sig = SIGILL;
+		break;
 	    case VEC_TRAP1:
 	    case VEC_TRAP2:
 	    case VEC_TRAP3:
@@ -875,51 +883,76 @@
 	    case VEC_TRAP12:
 	    case VEC_TRAP13:
 	    case VEC_TRAP14:
+		info.si_code = ILL_ILLTRP;
 		sig = SIGILL;
 		break;
 	    case VEC_FPBRUC:
+	    case VEC_FPOE:
+	    case VEC_FPNAN:
+		info.si_code = FPE_FLTINV;
+		sig = SIGFPE;
+		break;
 	    case VEC_FPIR:
+		info.si_code = FPE_FLTRES;
+		sig = SIGFPE;
+		break;
 	    case VEC_FPDIVZ:
+		info.si_code = FPE_FLTDIV;
+		sig = SIGFPE;
+		break;
 	    case VEC_FPUNDER:
-	    case VEC_FPOE:
+		info.si_code = FPE_FLTUND;
+		sig = SIGFPE;
+		break;
 	    case VEC_FPOVER:
-	    case VEC_FPNAN:
-		{
-		  unsigned char fstate[FPSTATESIZE];
-
-		  __asm__ __volatile__ (".chip 68k/68881\n\t"
-		  			"fsave %0@\n\t"
-		  			".chip 68k" : : "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__ (".chip 68k/68881\n\t"
-		      			    "frestore %0@\n\t"
-					    ".chip 68k" : : "a" (fstate));
-		    }
-		}
-		/* fall through */
+		info.si_code = FPE_FLTOVF;
+		sig = SIGFPE;
+		break;
 	    case VEC_ZERODIV:
+		info.si_code = FPE_INTDIV;
+		sig = SIGFPE;
+		break;
+	    case VEC_CHK:
 	    case VEC_TRAP:
+		info.si_code = FPE_INTOVF;
 		sig = SIGFPE;
 		break;
 	    case VEC_TRACE:		/* ptrace single step */
-		fp->ptregs.sr &= ~PS_T;
+		info.si_code = TRAP_TRACE;
+		sig = SIGTRAP;
+		break;
 	    case VEC_TRAP15:		/* breakpoint */
+		info.si_code = TRAP_BRKPT;
 		sig = SIGTRAP;
 		break;
 	    default:
+		info.si_code = ILL_ILLOPC;
 		sig = SIGILL;
 		break;
 	}
-
-	send_sig (sig, current, 1);
-}
-
-asmlinkage void set_esp0 (unsigned long ssp)
-{
-  current->tss.esp0 = ssp;
+	info.si_signo = sig;
+	info.si_errno = 0;
+	switch (fp->ptregs.format) {
+	    default:
+		info.si_addr = (void *) fp->ptregs.pc;
+		break;
+	    case 2:
+		info.si_addr = (void *) fp->un.fmt2.iaddr;
+		break;
+	    case 7:
+		info.si_addr = (void *) fp->un.fmt7.effaddr;
+		break;
+	    case 9:
+		info.si_addr = (void *) fp->un.fmt9.iaddr;
+		break;
+	    case 10:
+		info.si_addr = (void *) fp->un.fmta.daddr;
+		break;
+	    case 11:
+		info.si_addr = (void *) fp->un.fmtb.daddr;
+		break;
+	}
+	force_sig_info (sig, &info, current);
 }
 
 void die_if_kernel (char *str, struct pt_regs *fp, int nr)
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/Makefile linux/arch/m68k/mac/Makefile
--- v2.1.86/linux/arch/m68k/mac/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/Makefile	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,16 @@
+#
+# Makefile for Linux arch/m68k/mac 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,-m68020
+
+O_TARGET := mac.o
+O_OBJS	 := config.o ksyms.o bootparse.o macints.o via6522.o \
+		mackeyb.o adb-bus.o macboing.o debug.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c
--- v2.1.86/linux/arch/m68k/mac/adb-bus.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/adb-bus.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,2134 @@
+/*
+ *	MACII	ADB keyboard handler.
+ *		Copyright (c) 1997 Alan Cox
+ *
+ *	Derived from code 
+ *		Copyright (C) 1996 Paul Mackerras.
+ *
+ *	MSch (9/97) Partial rewrite of interrupt handler to MacII style
+ *	ADB handshake, based on:
+ *		- Guide to Mac Hardware
+ *		- Guido Koerber's session with a logic analyzer
+ */
+ 
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include "via6522.h"
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/adb.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/setup.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+
+
+#define MACII		/* For now - will be a switch */
+
+/* Bits in B data register: all active low */
+#define TREQ		0x08		/* Transfer request (input) */
+#define TACK		0x10		/* Transfer acknowledge (output) */
+#define TIP		0x20		/* Transfer in progress (output) */
+
+/* Bits in B data register: ADB transaction states MacII */
+#define ST_MASK		0x30		/* mask for selecting ADB state bits */
+/* ADB transaction states according to GMHW */
+#define ST_CMD		0x00		/* ADB state: command byte */
+#define ST_EVEN		0x10		/* ADB state: even data byte */
+#define ST_ODD		0x20		/* ADB state: odd data byte */
+#define ST_IDLE		0x30		/* ADB state: idle, nothing to send */
+
+/* Bits in ACR */
+#define SR_CTRL		0x1c		/* Shift register control bits */
+#ifdef USE_ORIG
+#define SR_EXT		0x1c		/* Shift on external clock */
+#else
+#define SR_EXT		0x0c		/* Shift on external clock */
+#endif
+#define SR_OUT		0x10		/* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET		0x80		/* set bits in IER */
+#define IER_CLR		0		/* clear bits in IER */
+#define SR_INT		0x04		/* Shift register full/empty */
+#define SR_DATA		0x08		/* Shift register data */
+#define SR_CLOCK	0x10		/* Shift register clock */
+
+static struct adb_handler {
+    void (*handler)(unsigned char *, int, struct pt_regs *);
+} adb_handler[16];
+
+static enum adb_state {
+    idle,
+    sent_first_byte,
+    sending,
+    reading,
+    read_done,
+    awaiting_reply
+} adb_state;
+
+static struct adb_request *current_req;
+static struct adb_request *last_req;
+static unsigned char cuda_rbuf[16];
+static unsigned char *reply_ptr;
+static int reply_len;
+static int reading_reply;
+static int data_index;
+static int first_byte;
+static int prefix_len;
+
+static int status = ST_IDLE|TREQ;
+static int last_status;
+/*static int adb_delay;*/
+int in_keybinit = 1;
+
+static void adb_start(void);
+extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs);
+extern void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs);
+extern void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs);
+extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs);
+
+/*
+ * Misc. defines for testing 
+ */
+
+extern int console_loglevel;
+
+#define ADBDEBUG_STATUS		(1)
+#define ADBDEBUG_STATE		(2)
+#define ADBDEBUG_READ		(4)
+#define ADBDEBUG_WRITE		(8)
+#define ADBDEBUG_START		(16)
+#define ADBDEBUG_RETRY		(32)
+#define ADBDEBUG_POLL		(64)
+#define ADBDEBUG_INT		(128)
+#define ADBDEBUG_PROT		(256)
+#define ADBDEBUG_SRQ		(512)
+#define ADBDEBUG_REQUEST	(1024)
+#define ADBDEBUG_INPUT		(2048)
+#define ADBDEBUG_DEVICE		(4096)
+
+
+#define DEBUG_ADB
+
+#ifdef DEBUG_ADB
+#define ADBDEBUG	(ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST)
+#else
+#define ADBDEBUG	(0)
+#endif
+
+#define TRY_CUDA
+
+void adb_bus_init(void)
+{
+	unsigned long flags;
+	unsigned char c;
+	
+	save_flags(flags);
+	cli();
+	
+	/*
+	 *	Setup ADB
+	 */
+	 
+	switch(macintosh_config->adb_type)
+	{
+	
+		case MAC_ADB_II:
+			printk("adb: MacII style keyboard/mouse driver.\n");
+			/* Set the lines up. We want TREQ as input TACK|TIP as output */
+		 	via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ));
+			/*
+			 * Docs suggest TREQ should be output - that seems nuts
+			 * BSD agrees here :-)
+			 * Setup vPCR ??
+			 */
+
+#ifdef USE_ORIG
+		 	/* Lower the bus signals (MacII is active low it seems ???) */
+		 	via_write(via1, vBufB, via_read(via1, vBufB)&~TACK);
+#else
+			/* Corresponding state: idle (clear state bits) */
+		 	via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+			last_status = (via_read(via1, vBufB)&~ST_MASK);
+#endif
+		 	/* Shift register on input */
+		 	c=via_read(via1, vACR);
+		 	c&=~SR_CTRL;		/* Clear shift register bits */
+		 	c|=SR_EXT;		/* Shift on external clock; out or in? */
+		 	via_write(via1, vACR, c);
+		 	/* Wipe any pending data and int */
+		 	via_read(via1, vSR);
+
+		 	/* This is interrupts on enable SR for keyboard */
+		 	via_write(via1, vIER, IER_SET|SR_INT); 
+		 	/* This clears the interrupt bit */
+		 	via_write(via1, vIFR, SR_INT);
+#if 0 	
+		 	ct=1000;
+ 			while( ct-- && (via_read(via1, vBufB)&TREQ))
+ 				udelay(1000);
+		 	if(ct<0)
+ 				printk("No sync occured\n");
+ 			ct=1000;
+ 			while( ct-- && !(via_read(via1, vIFR)&SR_INT))
+ 				udelay(1000);
+		 	if(ct<0)
+		 		printk("No sync 2 occured\n");
+		 	via_read(via1, vSR);
+		 	via_write(via1, vBufB, via_read(via1, vBufB)|TACK);
+		 	while( ct-- && !(via_read(via1, vBufB)&TREQ))
+ 				udelay(1000);
+		 	if(ct<0)
+ 				printk("No sync 3 occured\n");
+ 			ct=1000;
+ 			while( ct-- && !(via_read(via1, vIFR)&SR_INT))
+ 				udelay(1000);
+		 	if(ct<0)
+ 				printk("No sync 4 occured\n");
+		 	via_read(via1, vSR);
+ 			via_write(via1, vBufB, via_read(via1, vBufB)|TIP);
+#endif
+		 	/*
+		 	 *	Ok we probably ;) have a ready to use adb bus. Its also
+		 	 *	hopefully idle (Im assuming the mac didnt leave a half
+		 	 *	complete transaction on booting us).
+ 			 */
+ 
+			request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, 
+				    "adb interrupt", adb_interrupt);
+			adb_state = idle;
+			break;
+			/*
+			 *	Unsupported; but later code doesn't notice !!
+			 */
+		case MAC_ADB_CUDA:
+			printk("adb: CUDA interface.\n");
+#ifdef TRY_CUDA
+			/* don't know what to set up here ... */
+			adb_state = idle;
+			/* Set the lines up. We want TREQ as input TACK|TIP as output */
+		 	via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ));
+			request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, 
+				    "adb CUDA interrupt", adb_cuda_interrupt);
+			break;
+#else
+			goto nosupp;
+#endif
+		case MAC_ADB_IISI:
+			printk("adb: Using IIsi hardware.\n");
+			goto nosupp;
+		default:
+			printk("adb: Unknown hardware interface.\n");
+		nosupp:
+			printk("adb: Interface unsupported.\n");
+			restore_flags(flags);	
+			return;
+	}
+
+	/*
+	 * XXX: interrupt only registered if supported HW !!
+	 * -> unsupported HW will just time out on keyb_init!
+	 */
+#if 0
+	request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, 
+		    "adb interrupt", adb_interrupt);
+#endif
+#ifdef DEBUG_ADB_INTS
+	request_irq(IRQ_MAC_ADB_CL, adb_clock_interrupt, IRQ_FLG_LOCK, 
+		    "adb clock interrupt", adb_clock_interrupt);
+	request_irq(IRQ_MAC_ADB_SD, adb_data_interrupt, IRQ_FLG_LOCK, 
+		    "adb data interrupt", adb_data_interrupt);
+#endif
+
+	printk("adb: init done.\n");
+	restore_flags(flags);	
+} 
+	
+#define WAIT_FOR(cond, what)				\
+    do {						\
+	for (x = 1000; !(cond); --x) {			\
+	    if (x == 0) {				\
+		printk("Timeout waiting for " what);	\
+		return 0;				\
+	    }						\
+	    __delay(100*160);					\
+	}						\
+    } while (0)
+
+/* 
+ *	Construct and send an adb request 
+ *	This function is the main entry point into the ADB driver from 
+ *	kernel code; it takes the request data supplied and populates the
+ *	adb_request structure.
+ *	In order to keep this interface independent from any assumption about
+ *	the underlying ADB hardware, we take requests in CUDA format here, 
+ *	the ADB packet 'prefixed' with a packet type code.
+ *	Non-CUDA hardware is confused by this, so we strip the packet type
+ *	here depending on hardware type ...
+ */
+int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
+	     int nbytes, ...)
+{
+	va_list list;
+	int i, start;
+
+	va_start(list, nbytes);
+
+	/*
+	 * skip first byte if not CUDA 
+	 */
+	if (macintosh_config->adb_type != MAC_ADB_CUDA) {
+		start =  va_arg(list, int);
+		nbytes--;
+	}
+	req->nbytes = nbytes;
+	req->done = done;
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+	if (console_loglevel == 10)
+		printk("adb_request, data bytes: ");
+#endif
+	for (i = 0; i < nbytes; ++i) {
+		req->data[i] = va_arg(list, int);
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+		if (console_loglevel == 10)
+			printk("%x ", req->data[i]);
+#endif
+	}
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+	if (console_loglevel == 10)
+		printk(" !\n");
+#endif
+	va_end(list);
+	/* 
+	 * XXX: This might be fatal if no reply is generated (i.e. Listen) ! 
+	 * Currently, the interrupt handler 'fakes' a reply on non-TALK 
+	 * commands for this reason.
+	 * Also, we need a CUDA_AUTOPOLL emulation here for non-CUDA 
+	 * Macs, and some mechanism to remember the last issued TALK
+	 * request for resending it repeatedly on timeout!
+	 */
+	req->reply_expected = 1;
+	return adb_send_request(req);
+}
+
+/* 
+ *	Construct an adb request for later sending
+ *	This function only populates the adb_request structure, without 
+ *	actually queueing it.
+ *	Reason: Poll requests and Talk requests need to be handled in a way
+ *	different from 'user' requests; no reply_expected is set and 
+ *	Poll requests need to be placed at the head of the request queue.
+ *	Using adb_request results in implicit queueing at the tail of the 
+ *	request queue (duplicating the Poll) with reply_expected set.
+ *	No adjustment of packet data is necessary, as this mechanisnm is not
+ *	used by CUDA hardware (Autopoll used instead).
+ */
+int adb_build_request(struct adb_request *req, void (*done)(struct adb_request *),
+	     int nbytes, ...)
+{
+	va_list list;
+	int i;
+
+	req->nbytes = nbytes;
+	req->done = done;
+	va_start(list, nbytes);
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+	if (console_loglevel == 10)
+		printk("adb__build_request, data bytes: ");
+#endif
+	/*
+	 * skip first byte if not CUDA ?
+	 */
+	for (i = 0; i < nbytes; ++i) {
+		req->data[i] = va_arg(list, int);
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+		if (console_loglevel == 10)
+			printk("%x ", req->data[i]);
+#endif
+	}
+#if (ADBDEBUG & ADBDEBUG_REQUEST)
+	if (console_loglevel == 10)
+		printk(" !\n");
+#endif
+	va_end(list);
+
+	req->reply_expected = 0;
+	return 0;
+}
+
+/*
+ *	Send an ADB poll (Talk, tagged on the front of the request queue)
+ */
+void adb_queue_poll(void)
+{
+	static int pod=0;
+	static int in_poll=0;
+	static struct adb_request r;
+	unsigned long flags;
+
+	if(in_poll)
+		printk("Double poll!\n");
+
+	in_poll++;
+	pod++;
+	if(pod>7) /* 15 */
+		pod=0;
+
+#if (ADBDEBUG & ADBDEBUG_POLL)
+	if (console_loglevel == 10)
+		printk("adb: Polling %d\n",pod);
+#endif
+
+	/* XXX: that's a TALK, register 0, MacII version */
+	adb_build_request(&r,NULL, 1, (pod<<4|0xC));
+
+	r.reply_expected=0;
+	r.done=NULL;
+	r.sent=0;
+	r.got_reply=0;
+	r.reply_len=0;
+	save_flags(flags);
+	cli();
+	/* Poll inserted at head of queue ... */
+	r.next=current_req;
+	current_req=&r;
+	restore_flags(flags);
+	adb_start();
+	in_poll--;
+}
+
+/*
+ *	Send an ADB retransmit (Talk, appended to the request queue)
+ */
+void adb_retransmit(int device)
+{
+	static int in_retransmit=0;
+	static struct adb_request rt;
+	unsigned long flags;
+
+	if(in_retransmit)
+		printk("Double retransmit!\n");
+
+	in_retransmit++;
+
+#if (ADBDEBUG & ADBDEBUG_POLL)
+	if (console_loglevel == 10)
+		printk("adb: Sending retransmit: %d\n", device);
+#endif
+
+	/* MacII version */
+	adb_build_request(&rt,NULL, 1, (device<<4|0xC));
+
+	rt.reply_expected = 0;
+	rt.done           = NULL;
+	rt.sent           = 0;
+	rt.got_reply      = 0;
+	rt.reply_len      = 0;
+	rt.next           = NULL;
+
+	save_flags(flags);
+	cli();
+
+	/* Retransmit inserted at tail of queue ... */
+
+	if (current_req != NULL) 
+	{
+		last_req->next = &rt;
+		last_req = &rt;
+	}
+	else
+	{
+		current_req = &rt;
+		last_req = &rt;
+	}
+
+	/* always restart driver (send_retransmit used in place of adb_start!)*/
+
+	if (adb_state == idle)
+		adb_start();
+
+	restore_flags(flags);
+	in_retransmit--;
+}
+
+/*
+ * Queue an ADB request; start ADB transfer if necessary
+ */
+int adb_send_request(struct adb_request *req)
+{
+	unsigned long flags;
+
+	req->next = 0;
+	req->sent = 0;
+	req->got_reply = 0;
+	req->reply_len = 0;
+	save_flags(flags); 
+	cli();
+
+	if (current_req != NULL) 
+	{
+		last_req->next = req;
+		last_req = req;
+	}
+	else
+	{
+		current_req = req;
+		last_req = req;
+		if (adb_state == idle)
+			adb_start();
+	}
+
+	restore_flags(flags);
+	return 0;
+}
+
+static int nclock, ndata;
+
+static int need_poll    = 0;
+static int command_byte = 0;
+static int last_reply   = 0;
+static int last_active  = 0;
+
+static struct adb_request *retry_req;
+
+/*
+ * Start sending ADB packet 
+ */
+static void adb_start(void)
+{
+	unsigned long flags;
+	struct adb_request *req;
+
+	/*
+	 * We get here on three 'sane' conditions:
+	 * 1) called from send_adb_request, if adb_state == idle
+	 * 2) called from within adb_interrupt, if adb_state == idle 
+	 *    (after receiving, or after sending a LISTEN) 
+	 * 3) called from within adb_interrupt, if adb_state == sending 
+	 *    and no reply is expected (immediate next command).
+	 * Maybe we get here on SRQ as well ??
+	 */
+
+	/* get the packet to send */
+	req = current_req;
+	/* assert adb_state == idle */
+	if (adb_state != idle) {
+		printk("ADB: adb_start called while driver busy (%p %x %x)!\n",
+			req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
+		return;
+	}
+	if (req == 0)
+		return;
+	save_flags(flags); 
+	cli();
+	
+#if (ADBDEBUG & ADBDEBUG_START)
+	if (console_loglevel == 10)
+		printk("adb_start: request %p ", req);
+#endif
+
+	nclock = 0;
+	ndata  = 0;
+
+	/* 
+	 * IRQ signaled ?? (means ADB controller wants to send, or might 
+	 * be end of packet if we were reading)
+	 */
+	if ((via_read(via1, vBufB)& TREQ) == 0) 
+	{
+		switch(macintosh_config->adb_type)
+		{
+			/*
+			 *	FIXME - we need to restart this on a timer
+			 *	or a collision at boot hangs us.
+			 *	Never set adb_state to idle here, or adb_start 
+			 *	won't be called again from send_request!
+			 *	(need to re-check other cases ...)
+			 */
+			case MAC_ADB_CUDA:
+				/* printk("device busy - fail\n"); */
+				restore_flags(flags);
+				/* a byte is coming in from the CUDA */
+				return;			
+			case MAC_ADB_II:
+				/*
+				 * if the interrupt handler set the need_poll
+				 * flag, it's hopefully a SRQ poll or re-Talk
+				 * so we try to send here anyway
+				 */
+				if (!need_poll) {
+					printk("device busy - retry %p state %d status %x!\n", 
+						req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
+					retry_req = req;
+					/* set ADB status here ? */
+					restore_flags(flags);
+					return;
+				} else {
+#if (ADBDEBUG & ADBDEBUG_START)
+					if (console_loglevel == 10)
+						printk("device busy - polling; state %d status %x!\n", 
+							adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ));
+#endif
+					need_poll = 0;
+					break;
+				}
+		}
+	}
+
+#if 0
+	/*
+	 * Bus idle ?? Not sure about this one; SRQ might need ST_CMD here!
+	 * OTOH: setting ST_CMD in the interrupt routine would make the 
+	 * ADB contoller shift in before this routine starts shifting out ...
+	 */
+	if ((via_read(via1, vBufB)&ST_MASK) != ST_IDLE) 
+	{
+#if (ADBDEBUG & ADBDEBUG_STATE)
+		if (console_loglevel == 10)
+			printk("ADB bus not idle (%x), retry later!\n", 
+				via_read(via1, vBufB)&(ST_MASK|TREQ));
+#endif
+		retry_req = req;
+		restore_flags(flags);
+		return;							
+	}
+#endif
+
+	/*
+	 * Another retry pending? (sanity check)
+	 */
+	if (retry_req) {
+#if (ADBDEBUG & ADBDEBUG_RETRY)
+		if (console_loglevel == 10)
+		if (retry_req == req)
+			/* new requests are appended at tail of request queue */
+			printk("adb_start: retry %p pending ! \n", req);
+		else
+			/* poll requests are added to the head of queue */
+			printk("adb_start: retry %p pending, req %p (poll?) current! \n",
+				retry_req, req);
+#endif
+		retry_req = NULL;
+	}
+
+	/*
+	 * Seems OK, go for it!
+	 */
+	switch(macintosh_config->adb_type)
+	{
+		case MAC_ADB_CUDA:
+			/* store command byte (first byte is 'type' byte) */
+			command_byte = req->data[1];
+			/* set the shift register to shift out and send a byte */
+			via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); 
+			via_write(via1, vSR, req->data[0]);
+			via_write(via1, vBufB, via_read(via1, vBufB)&~TIP);
+			break;
+		case MAC_ADB_II:
+			/* store command byte */
+			command_byte = req->data[0];
+			/* Output mode */
+			via_write(via1, vACR, via_read(via1, vACR)|SR_OUT);
+			/* Load data */
+			via_write(via1, vSR, req->data[0]);
+#ifdef USE_ORIG
+			/* Turn off TIP/TACK - this should tell the external logic to
+			   start the external shift clock */
+/*			via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));*/
+			via_write(via1, vBufB, via_read(via1, vBufB)|(TIP|TACK));
+#else
+			/* set ADB state to 'command' */
+			via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_CMD);
+#endif
+			break;
+	}
+#if (ADBDEBUG & ADBDEBUG_START)
+	if (console_loglevel == 10)
+		printk("sent first byte of %d: %x, (%x %x) ... ", 
+			req->nbytes, req->data[0], adb_state, 
+			(via_read(via1, vBufB) & (ST_MASK|TREQ)) );
+#endif
+	adb_state = sent_first_byte;
+	data_index = 1;
+	restore_flags(flags);
+}
+
+/*
+ * Poll the ADB state (maybe obsolete now that interrupt-driven ADB runs)
+ */
+void adb_poll(void)
+{
+	unsigned char c;
+	unsigned long flags;
+	save_flags(flags);
+	cli();
+	c=via_read(via1, vIFR);
+#if (ADBDEBUG & ADBDEBUG_POLL)
+#ifdef DEBUG_ADB_INTS
+	if (console_loglevel == 10) {
+		printk("adb_poll: IFR %x state %x cl %d dat %d ", 
+			c, adb_state, nclock, ndata);
+		if (c & (SR_CLOCK|SR_DATA)) {
+			if (c & SR_CLOCK)
+				printk("adb clock event ");
+			if (c & SR_DATA)
+				printk("adb data event ");
+		}
+	}
+#else
+	if (console_loglevel == 10)
+		printk("adb_poll: IFR %x state %x ", 
+			c, adb_state);
+#endif
+	if (console_loglevel == 10)
+		printk("\r");
+#endif
+	if (c & SR_INT)
+	{
+#if (ADBDEBUG & ADBDEBUG_POLL)
+		if (console_loglevel == 10)
+			printk("adb_poll: adb interrupt event\n");
+#endif
+		adb_interrupt(0, 0, 0);
+	}
+	restore_flags(flags);
+}
+
+/*
+ * Debugging gimmicks
+ */
+void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+	nclock++;
+}
+
+void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+	ndata++;
+}
+
+/*
+ * The notorious ADB interrupt handler - does all of the protocol handling, 
+ * except for starting new send operations. Relies heavily on the ADB 
+ * controller sending and receiving data, thereby generating SR interrupts
+ * for us. This means there has to be always activity on the ADB bus, otherwise
+ * the whole process dies and has to be re-kicked by sending TALK requests ...
+ * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
+ * ADB the problem isn't solved yet (retransmit of the latest active TALK seems
+ * a good choice; either on timeout or on a timer interrupt).
+ *
+ * The basic ADB state machine was left unchanged from the original MacII code
+ * by Alan Cox, which was based on the CUDA driver for PowerMac. 
+ * The syntax of the ADB status lines seems to be totally different on MacII, 
+ * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for
+ * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start 
+ * and end of a receive packet are signaled by asserting /IRQ on the interrupt
+ * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on 
+ * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the 
+ * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB 
+ * protocol with a logic analyzer!!)
+ * CUDA seems to use /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP|TACK
+ * for sending, and /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP for
+ * receiving. No clue how timeouts are handled; SRQ seems to be sent as a 
+ * separate packet. Quite a few changes have been made outside the handshake 
+ * code, so I don't know if the CUDA code still behaves as before. 
+ *
+ * Note: As of 21/10/97, the MacII ADB part works including timeout detection
+ * and retransmit (Talk to the last active device). Cleanup of code and 
+ * testing of the CUDA functionality is required, though. 
+ * Note2: As of 13/12/97, CUDA support is definitely broken ...
+ * Next TODO: implementation of IIsi ADB protocol (maybe the USE_ORIG 
+ * conditionals can be a start?)
+ */
+void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+	int x, adbdir;
+	struct adb_request *req;
+
+	last_status = status;
+
+#ifdef USE_ORIG
+	status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
+#else
+	if (macintosh_config->adb_type==MAC_ADB_CUDA)
+		status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
+	else
+		/* status bits (0x8->0x20) and direction (0x10 ??) CLASH !! */
+		status = (via_read(via1, vBufB) & (ST_MASK|TREQ)); 
+#endif
+	adbdir = (via_read(via1, vACR) & SR_OUT);
+#if (ADBDEBUG & ADBDEBUG_INT)
+	if (console_loglevel == 10)
+		printk("adb_interrupt: state=%d status=%x last=%x direction=%x\n", 
+			adb_state, status, last_status, adbdir);
+#endif
+
+
+	switch (adb_state) 
+	{
+		case idle:
+			if(macintosh_config->adb_type==MAC_ADB_CUDA)
+			{
+				/* CUDA has sent us the first byte of data - unsolicited */
+				if (status != TREQ)
+					printk("cuda: state=idle, status=%x\n", status);
+				x = via_read(via1, vSR); 
+				via_write(via1, vBufB, via_read(via1,vBufB)&~TIP);
+			}
+			else if(macintosh_config->adb_type==MAC_ADB_II)
+			{
+#if (ADBDEBUG & ADBDEBUG_STATUS)
+				if (status == TREQ && !adbdir) 
+					/* that's: not IRQ, idle, input -> weird */
+					printk("adb_macII: idle, status=%x dir=%x\n",
+						status, adbdir);
+#endif
+				x = via_read(via1, vSR);
+				first_byte = x;
+#if (ADBDEBUG & ADBDEBUG_READ)
+				if (console_loglevel == 10)
+					printk("adb_macII: receiving unsol. packet: %x (%x %x) ", 
+						x, adb_state, status);
+#endif
+#ifdef USE_ORIG
+				via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));
+#else
+				/* set ADB state = even for first data byte */
+				via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
+#endif
+			}
+			adb_state = reading;
+			reply_ptr = cuda_rbuf;
+			reply_len = 0;
+			reading_reply = 0;
+			prefix_len = 0;
+			if (macintosh_config->adb_type==MAC_ADB_II) {
+				*reply_ptr++ = ADB_PACKET;
+				*reply_ptr++ = first_byte;
+				*reply_ptr++ = command_byte; /*first_byte;*/
+				reply_len    = 3;
+				prefix_len   = 3;
+			}
+			break;
+
+		case awaiting_reply:
+			if(macintosh_config->adb_type==MAC_ADB_CUDA)
+			{
+				/* CUDA has sent us the first byte of data of a reply */
+				if (status != TREQ)
+					printk("cuda: state=awaiting_reply, status=%x\n", status);
+				x = via_read(via1, vSR); 
+				via_write(via1,vBufB, 
+					via_read(via1, vBufB)&~TIP);
+			} else if(macintosh_config->adb_type==MAC_ADB_II) {
+				/* handshake etc. for II ?? */
+				x = via_read(via1, vSR);
+				first_byte = x;
+#if (ADBDEBUG & ADBDEBUG_READ)
+				if (console_loglevel == 10)
+					printk("adb_macII: reading reply: %x (%x %x) ",
+						x, adb_state, status);
+#endif
+#ifdef USE_ORIG
+				via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));
+#else
+				/* set ADB state = even for first data byte */
+				via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
+#endif
+			}
+			adb_state = reading;			
+			reply_ptr = current_req->reply;
+			reading_reply = 1;
+			reply_len  = 0;
+			prefix_len = 0;
+			if (macintosh_config->adb_type==MAC_ADB_II) {
+				*reply_ptr++ = ADB_PACKET;
+				*reply_ptr++ = first_byte;
+				*reply_ptr++ = first_byte; /* should be command  byte */
+				reply_len    = 3;
+				prefix_len   = 3;
+			}
+			break;
+
+		case sent_first_byte:
+			if(macintosh_config->adb_type==MAC_ADB_CUDA)
+			{
+				if (status == TREQ + TIP + SR_OUT) 
+				{
+					/* collision */
+					via_write(via1, vACR,
+						via_read(via1, vACR)&~SR_OUT); 
+					x = via_read(via1, vSR); 
+					via_write(via1, vBufB,
+						via_read(via1,vBufB)|TIP|TACK); 
+					adb_state = idle;
+				}
+				else
+				{
+					/* assert status == TIP + SR_OUT */
+					if (status != TIP + SR_OUT)
+						printk("cuda: state=sent_first_byte status=%x\n", status);
+					via_write(via1,vSR,current_req->data[1]); 
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)^TACK); 
+					data_index = 2;
+					adb_state = sending;
+				}
+			}
+			else if(macintosh_config->adb_type==MAC_ADB_II)
+			{
+				/* how to detect a collision here ?? */
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+				if (console_loglevel == 10)
+					printk(" sending: %x (%x %x) ",
+						current_req->data[1], adb_state, status);
+#endif
+				/* maybe we're already done (Talk, or Poll)? */
+				if (data_index >= current_req->nbytes) 
+				{
+					/* assert it's a Talk ?? */
+					if ( (command_byte&0xc) != 0xc
+					    && console_loglevel == 10 )
+						printk("ADB: single byte command, no Talk: %x!\n", 
+							command_byte);
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+					if (console_loglevel == 10)
+						printk(" -> end (%d of %d) (%x %x)!\n",
+							data_index, current_req->nbytes, adb_state, status);
+#endif
+					current_req->sent = 1;
+					if (current_req->reply_expected) 
+					{
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+						if (console_loglevel == 10)
+							printk("ADB: reply expected on poll!\n");
+#endif
+						adb_state = awaiting_reply;
+						reading_reply = 0;
+					} else {
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+						if (console_loglevel == 10)
+							printk("ADB: no reply for poll, not calling done()!\n");
+#endif
+						req = current_req;
+						current_req = req->next;
+#if 0	/* XXX Not sure about that one ... probably better enabled */
+						if (req->done)
+							(*req->done)(req);
+#endif
+						adb_state = idle;
+						reading_reply = 0;
+					}
+					/* set to shift in */
+					via_write(via1, vACR,
+						via_read(via1, vACR) & ~SR_OUT);
+					x=via_read(via1, vSR);
+#ifdef USE_ORIG
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)|TACK|TIP);
+#else
+					/* set ADB state idle - might get SRQ */
+					via_write(via1, vBufB,
+						(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#endif
+					break;
+				}
+#if (ADBDEBUG & ADBDEBUG_STATUS)
+				if(!(status==(ST_CMD|TREQ) && adbdir == SR_OUT))
+					printk("adb_macII: sent_first_byte, weird status=%x dir=%x\n", 
+					status, adbdir);
+#endif
+				/* SR already set to shift out; send byte */
+				via_write(via1, vSR, current_req->data[1]);
+#ifdef USE_ORIG
+				via_write(via1, vBufB,
+					via_read(via1, vBufB)^TACK);
+#else
+				/* set state to ST_EVEN (first byte was: ST_CMD) */
+				via_write(via1, vBufB,
+					(via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
+#endif
+				data_index=2;			
+				adb_state = sending;
+			}
+			break;
+
+		case sending:
+			req = current_req;
+			if (data_index >= req->nbytes) 
+			{
+				/* end of packet */
+				if(macintosh_config->adb_type==MAC_ADB_CUDA)
+				{
+					via_write(via1, vACR,
+						via_read(via1, vACR)&~SR_OUT); 
+					x = via_read(via1, vSR); 
+					via_write(via1, vBufB,
+						via_read(via1,vBufB)|TACK|TIP); 
+				}
+				else if(macintosh_config->adb_type==MAC_ADB_II)
+				{
+					/*
+					 * XXX Not sure: maybe only switch to 
+					 * input mode on Talk ??
+					 */
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+					if (console_loglevel == 10)
+						printk(" -> end (%d of %d) (%x %x)!\n",
+							data_index-1, req->nbytes, adb_state, status);
+#endif
+					/* set to shift in */
+					via_write(via1, vACR,
+						via_read(via1, vACR) & ~SR_OUT);
+					x=via_read(via1, vSR);
+#ifdef USE_ORIG
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)|TACK|TIP);
+#else
+					/* set ADB state idle - might get SRQ */
+					via_write(via1, vBufB,
+						(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#endif
+				}
+				req->sent = 1;
+				if (req->reply_expected) 
+				{
+					/* 
+					 * maybe fake a reply here on Listen ?? 
+					 * Otherwise, a Listen hangs on success
+					 */
+					if ( ((req->data[0]&0xc) == 0xc) )
+						adb_state = awaiting_reply;
+					else {
+						/*
+						 * Reply expected, but none
+						 * possible -> fake reply.
+						 * Problem: sending next command
+						 * should probably be done 
+						 * without setting bus to 'idle'!
+						 * (except if no more commands)
+						 */
+#if (ADBDEBUG & ADBDEBUG_PROT)
+						printk("ADB: reply expected on Listen, faking reply\n");
+#endif
+						/* make it look weird */
+						/* XXX: return reply_len -1? */
+						/* XXX: fake ADB header? */
+						req->reply[0] = req->reply[1] = req->reply[2] = 0xFF;  
+						req->reply_len = 3;
+						req->got_reply = 1;
+						current_req = req->next;
+						if (req->done)
+							(*req->done)(req);
+						/* 
+						 * ready with this one, run 
+						 * next command or repeat last
+						 * Talk (=idle on II)
+						 */
+						/* set state to idle !! */
+						adb_state = idle;
+						if (current_req || retry_req)
+							adb_start();
+					}
+				}
+				else
+				{
+					current_req = req->next;
+					if (req->done)
+						(*req->done)(req);
+					/* not sure about this */
+					/* 
+					 * MS: Must set idle, no new request 
+					 *     started else !
+					 */
+					adb_state = idle;
+					/* 
+					 * requires setting ADB state to idle,
+					 * maybe read a byte ! (done above)
+					 */
+					if (current_req || retry_req)
+						adb_start();
+				}
+			}
+			else 
+			{
+				if(macintosh_config->adb_type==MAC_ADB_CUDA)
+				{
+					via_write(via1, vSR, req->data[data_index++]); 
+					via_write(via1, vBufB, 
+						via_read(via1, vBufB)^TACK); 
+				}
+				else if(macintosh_config->adb_type==MAC_ADB_II)
+				{
+#if (ADBDEBUG & ADBDEBUG_WRITE)
+					if (console_loglevel == 10)
+						printk(" %x (%x %x) ",
+							req->data[data_index], adb_state, status);
+#endif
+					via_write(via1, vSR, req->data[data_index++]);
+#ifdef USE_ORIG
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)^TACK);
+#else
+					/* invert state bits, toggle ODD/EVEN */
+					x = via_read(via1, vBufB);
+					via_write(via1, vBufB,
+						(x&~ST_MASK)|~(x&ST_MASK));
+#endif
+				}
+			}
+			break;
+
+		case reading:
+#ifdef POLL_ON_TIMEOUT
+			if((reply_len-prefix_len)==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+#else
+			if( (first_byte == 0xFF && (reply_len-prefix_len)==2 
+			     && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || 
+			    ((reply_len-prefix_len)==3 
+			     && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
+#endif
+			{
+				/*
+				 * possible timeout (in fact, most probably a 
+				 * timeout, since SRQ can't be signaled without
+				 * transfer on the bus).
+				 * The last three bytes seen were FF, together 
+				 * with the starting byte (in case we started
+				 * on 'idle' or 'awaiting_reply') this probably
+				 * makes four. So this is mostl likely #5!
+				 * The timeout signal is a pattern 1 0 1 0 0..
+				 * on /INT, meaning we missed it :-(
+				 */
+				x = via_read(via1, vSR);
+				if (x != 0xFF)
+					printk("ADB: mistaken timeout/SRQ!\n");
+
+				/* 
+				 * ADB status bits: either even or odd.
+				 * adb_state: need to set 'idle' here.
+				 * Maybe saner: set 'need_poll' or 
+				 * 'need_resend' here, fall through to 
+				 * read_done ??
+				 */
+#if (ADBDEBUG & ADBDEBUG_READ)
+				if (console_loglevel == 10)
+					printk(" -> read aborted: %x (%x %x)!\n", 
+						x, adb_state, status);
+#endif
+
+#ifdef USE_ORIG
+				via_write(via1, vBufB,
+					via_read(via1, vBufB)|TACK|TIP);
+#else
+#if 0	/* XXX leave status unchanged!! - need to check this again! */
+				/* set ADB state to idle (required by adb_start()) */
+				via_write(via1, vBufB,
+					(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#endif
+#endif
+
+				/*
+				 * What if the timeout happens on reading a 
+				 * reply ?? Assemble error reply and call 
+				 * current_request->done()? Keep request 
+				 * on queue?
+				 */
+
+				/* prevent 'busy' in adb_start() */
+				need_poll = 1;
+
+				/*
+				 * Timeout: /IRQ alternates high/low during 
+				 *          4 'FF' bytes (1 0 1 0 0...)
+				 *	    We're on byte 5, so we need one 
+				 *	    more backlog here (TBI) ....
+				 */
+				if ((status&TREQ) != (last_status&TREQ)) {
+#if (ADBDEBUG & ADBDEBUG_SRQ)
+					if (console_loglevel == 10)
+						printk("ADB: reply timeout, resending!\n");
+#endif
+					/*
+					 * first byte received should be the 
+					 * command byte timing out !!
+					 */
+					if (first_byte != 0xff)
+						command_byte = first_byte;
+
+					/*
+					 * compute target for retransmit: if
+					 * last_active is set, use that one, 
+					 * else use command_byte
+					 */
+					if (last_active == -1)
+						last_active = (command_byte&0xf0)>>4;
+					adb_state = idle;
+					/* resend if TALK, don't poll! */
+					if (current_req)
+						adb_start();
+					else
+					/* 
+					 * XXX: need to count the timeouts ?? 
+					 * restart last active TALK ??
+					 * If no current_req, reuse old one!
+					 */
+						adb_retransmit(last_active);
+
+				} else {
+				/*
+				 * SRQ: NetBSD suggests /IRQ is asserted!?
+				 */
+					if (status&TREQ)
+						printk("ADB: SRQ signature w/o /INT!\n");
+#if (ADBDEBUG & ADBDEBUG_SRQ)
+					if (console_loglevel == 10)
+						printk("ADB: empty SRQ packet!\n");
+#endif
+					/* Terminate the SRQ packet and poll */
+					adb_state = idle;
+					adb_queue_poll();
+				}
+				/*
+				 * Leave ADB status lines unchanged (means /IRQ
+				 * will still be low when entering adb_start!)
+				 */
+				break;
+			}
+			if((reply_len-prefix_len)>3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+			{
+				/* SRQ tacked on data packet */
+				/* Check /IRQ here ?? */
+#if (ADBDEBUG & ADBDEBUG_SRQ)
+				if (console_loglevel == 10)
+					printk("\nADB: Packet with SRQ!\n");
+#endif
+				/* Terminate the packet (SRQ never ends) */
+				x = via_read(via1, vSR);
+				adb_state = read_done;
+				reply_len -= 3;
+				reply_ptr -= 3;
+				need_poll = 1;
+				/* need to continue; next byte not seen else */
+				/* 
+				 * XXX: not at all sure here; maybe need to 
+				 * send away the reply and poll immediately?
+				 */
+			} else {
+				/* Sanity check */
+				if(reply_len>15)
+					reply_len=0;
+				/* read byte */
+				*reply_ptr = via_read(via1, vSR); 
+				x = *reply_ptr;
+#if (ADBDEBUG & ADBDEBUG_READ)
+				if (console_loglevel == 10)
+					printk(" %x (%x %x) ", 
+						*reply_ptr, adb_state, status);
+#endif
+				reply_ptr++;
+				reply_len++;
+			}
+			/* The usual handshake ... */
+			if(macintosh_config->adb_type==MAC_ADB_CUDA)
+			{
+				if (status == TIP)
+				{
+					/* that's all folks */
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)|TACK|TIP); 
+					adb_state = read_done;
+				}
+				else 
+				{
+					/* assert status == TIP | TREQ */
+					if (status != TIP + TREQ)
+						printk("cuda: state=reading status=%x\n", status);
+					via_write(via1, vBufB, 
+						via_read(via1, vBufB)^TACK); 
+				}
+			}
+			if(macintosh_config->adb_type==MAC_ADB_II)
+			{
+				/*
+				 * NetBSD hints that the next to last byte 
+				 * is sent with IRQ !! 
+				 * Guido found out it's the last one (0x0),
+				 * but IRQ should be asserted already.
+				 * Problem with timeout detection: First
+				 * transition to /IRQ might be second 
+				 * byte of timeout packet! 
+				 * Timeouts are signaled by 4x FF.
+				 */
+				if(!(status&TREQ) && x == 0x00) /* != 0xFF */
+				{
+#if (ADBDEBUG & ADBDEBUG_READ)
+					if (console_loglevel == 10)
+						printk(" -> read done!\n");
+#endif
+#ifdef USE_ORIG
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)|TACK|TIP);
+#else
+#if 0		/* XXX: we take one more byte (why?), so handshake! */
+					/* set ADB state to idle */
+					via_write(via1, vBufB,
+						(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
+#else
+					/* invert state bits, toggle ODD/EVEN */
+					x = via_read(via1, vBufB);
+					via_write(via1, vBufB,
+						(x&~ST_MASK)|~(x&ST_MASK));
+#endif
+#endif
+					/* adjust packet length */
+					reply_len--;
+					reply_ptr--;
+					adb_state = read_done;
+				}
+				else
+				{
+#if (ADBDEBUG & ADBDEBUG_STATUS)
+					if(status!=TIP+TREQ)
+						printk("macII_adb: state=reading status=%x\n", status);
+#endif
+#ifdef USE_ORIG
+					via_write(via1, vBufB, 
+						via_read(via1, vBufB)^TACK);
+#else
+					/* not caught: ST_CMD */
+					/* required for re-entry 'reading'! */
+					if ((status&ST_MASK) == ST_IDLE) {
+						/* (in)sanity check - set even */
+						via_write(via1, vBufB,
+							(via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
+					} else {
+						/* invert state bits, toggle ODD/EVEN */
+						x = via_read(via1, vBufB);
+						via_write(via1, vBufB,
+							(x&~ST_MASK)|~(x&ST_MASK));
+					}
+#endif
+				}
+			}
+			break;
+
+		case read_done:
+			x = via_read(via1, vSR); 
+#if (ADBDEBUG & ADBDEBUG_READ)
+			if (console_loglevel == 10)
+				printk("ADB: read done: %x (%x %x)!\n", 
+					x, adb_state, status);
+#endif
+			if (reading_reply) 
+			{
+				req = current_req;
+				req->reply_len = reply_ptr - req->reply;
+				req->got_reply = 1;
+				current_req = req->next;
+				if (req->done)
+					(*req->done)(req);
+			}
+			else
+			{
+				adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+			}
+
+			/*
+			 * remember this device ID; it's the latest we got a 
+			 * reply from!
+			 */
+			last_reply = command_byte;
+			last_active = (command_byte&0xf0)>>4;
+
+
+			/*
+			 * Assert status = ST_IDLE ??
+			 */
+			/* 
+			 * SRQ seen before, initiate poll now
+			 */
+			if (need_poll) {
+#if (ADBDEBUG & ADBDEBUG_POLL)
+				if (console_loglevel == 10)
+					printk("ADB: initiate poll!\n");
+#endif
+				adb_state = idle;
+				/*
+				 * set ADB status bits?? (unchanged above!)
+				 */
+				adb_queue_poll();
+				need_poll = 0;
+				/* hope this is ok; queue_poll runs adb_start */
+				break;
+			}
+
+#ifdef USE_ORIG
+			/*
+			 * This will fail - TREQ is active low -> 0 is IRQ !!
+			 */ 
+			if (status == TREQ) 
+			{
+				via_write(via1, vBufB,
+					via_read(via1, vBufB)|~TIP); 
+#else
+			/*
+			 * /IRQ seen, so the ADB controller has data for us
+			 */
+			if (!(status&TREQ)) 
+			{
+				/* set ADB state to idle */
+				via_write(via1, vBufB,
+					(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); 
+#endif
+				adb_state = reading;
+				reply_ptr = cuda_rbuf;
+				reply_len = 0;
+				prefix_len = 0;
+				if (macintosh_config->adb_type==MAC_ADB_II) {
+					*reply_ptr++ = ADB_PACKET;
+					*reply_ptr++ = command_byte;
+					reply_len    = 2;
+					prefix_len   = 2;
+				}
+				reading_reply = 0;
+			}
+			else 
+			{
+				/*
+				 * no IRQ, send next packet or wait
+				 */
+				adb_state = idle;
+				if (current_req)
+					adb_start();
+				else
+					adb_retransmit(last_active);
+			}
+			break;
+
+		default:
+#if (ADBDEBUG & ADBDEBUG_STATE)
+			printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
+#endif
+	}
+}
+
+/*
+ * Restart of CUDA support: please modify this interrupt handler while 
+ * working at the Quadra etc. ADB driver. We can try to merge them later, or
+ * remove the CUDA stuff from the MacII handler
+ */
+
+void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+	int x, status;
+	struct adb_request *req;
+
+	status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
+	if (console_loglevel == 10)
+		printk("adb_interrupt: state=%d status=%x\n", adb_state, status);
+
+	switch (adb_state) 
+	{
+		case idle:
+			if(macintosh_config->adb_type==MAC_ADB_CUDA)
+			{
+				/* CUDA has sent us the first byte of data - unsolicited */
+				if (status != TREQ)
+					printk("cuda: state=idle, status=%x want=%x\n", 
+						status, TREQ);
+				x = via_read(via1, vSR); 
+				via_write(via1, vBufB, via_read(via1,vBufB)&~TIP);
+			}
+			else if(macintosh_config->adb_type==MAC_ADB_II)
+			{
+				if (status != TREQ)
+					printk("adb_macII: state=idle status=%x want=%x\n",
+						status, TREQ);
+				x = via_read(via1, vSR);
+				via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));
+			}
+			adb_state = reading;
+			reply_ptr = cuda_rbuf;
+			reply_len = 0;
+			reading_reply = 0;
+			break;
+
+		case awaiting_reply:
+			if(macintosh_config->adb_type==MAC_ADB_CUDA)
+			{
+				/* CUDA has sent us the first byte of data of a reply */
+				if (status != TREQ)
+					printk("cuda: state=awaiting_reply, status=%x want=%x\n", 
+						status, TREQ);
+				x = via_read(via1, vSR); 
+				via_write(via1,vBufB, 
+					via_read(via1, vBufB)&~TIP);
+			}
+			adb_state = reading;			
+			reply_ptr = current_req->reply;
+			reading_reply = 1;
+			reply_len = 0;
+			break;
+
+		case sent_first_byte:
+			if(macintosh_config->adb_type==MAC_ADB_CUDA)
+			{
+				if (status == TREQ + TIP + SR_OUT) 
+				{
+					/* collision */
+					if (console_loglevel == 10)
+						printk("cuda: send collision!\n");
+					via_write(via1, vACR,
+						via_read(via1, vACR)&~SR_OUT); 
+					x = via_read(via1, vSR); 
+					via_write(via1, vBufB,
+						via_read(via1,vBufB)|TIP|TACK); 
+					adb_state = idle;
+				}
+				else
+				{
+					/* assert status == TIP + SR_OUT */
+					if (status != TIP + SR_OUT)
+						printk("cuda: state=sent_first_byte status=%x want=%x\n", 
+							status, TIP + SR_OUT);
+					via_write(via1,vSR,current_req->data[1]); 
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)^TACK); 
+					data_index = 2;
+					adb_state = sending;
+				}
+			}
+			else if(macintosh_config->adb_type==MAC_ADB_II)
+			{
+				if(status!=TIP+SR_OUT)
+					printk("adb_macII: state=send_first_byte status=%x want=%x\n", 
+						status, TIP+SR_OUT);
+				via_write(via1, vSR, current_req->data[1]);
+				via_write(via1, vBufB,
+					via_read(via1, vBufB)^TACK);
+				data_index=2;			
+				adb_state = sending;
+			}
+			break;
+
+		case sending:
+			req = current_req;
+			if (data_index >= req->nbytes) 
+			{
+				if(macintosh_config->adb_type==MAC_ADB_CUDA)
+				{
+					via_write(via1, vACR,
+						via_read(via1, vACR)&~SR_OUT); 
+					x = via_read(via1, vSR); 
+					via_write(via1, vBufB,
+						via_read(via1,vBufB)|TACK|TIP); 
+				}
+				else if(macintosh_config->adb_type==MAC_ADB_II)
+				{
+					via_write(via1, vACR,
+						via_read(via1, vACR) & ~SR_OUT);
+					x=via_read(via1, vSR);
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)|TACK|TIP);
+				}
+				req->sent = 1;
+				if (req->reply_expected) 
+				{
+					adb_state = awaiting_reply;
+				}
+				else
+				{
+					current_req = req->next;
+					if (req->done)
+						(*req->done)(req);
+					/* not sure about this */
+					adb_state = idle;
+					adb_start();
+				}
+			}
+			else 
+			{
+				if(macintosh_config->adb_type==MAC_ADB_CUDA)
+				{
+					via_write(via1, vSR, req->data[data_index++]); 
+					via_write(via1, vBufB, 
+						via_read(via1, vBufB)^TACK); 
+				}
+				else if(macintosh_config->adb_type==MAC_ADB_II)
+				{
+					via_write(via1, vSR, req->data[data_index++]);
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)^TACK);
+				}
+			}
+			break;
+
+		case reading:
+			if(reply_len==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+			{
+				/* Terminate the SRQ packet */
+				printk("CUDA: Got an SRQ\n");
+				adb_state = idle;
+				adb_queue_poll();
+				break;
+			}
+			/* Sanity check - botched in orig. code! */
+			if(reply_len>15) {
+				printk("CUDA: reply buffer overrun!\n");
+				/* wrap buffer */
+				reply_len=0;
+				if (reading_reply)
+					reply_ptr = current_req->reply;
+				else
+					reply_ptr = cuda_rbuf;
+			}
+			*reply_ptr = via_read(via1, vSR); 
+			if (console_loglevel == 10)
+				printk(" %p-> %x (%x %x) ", 
+					reply_ptr, *reply_ptr, adb_state, status);
+			reply_ptr++;
+			reply_len++;
+			if(macintosh_config->adb_type==MAC_ADB_CUDA)
+			{
+				if (status == TIP)
+				{
+					/* that's all folks */
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)|TACK|TIP); 
+					adb_state = read_done;
+				}
+				else 
+				{
+					/* assert status == TIP | TREQ */
+					if (status != TIP + TREQ)
+						printk("cuda: state=reading status=%x want=%x\n", 
+							status, TIP + TREQ);
+					via_write(via1, vBufB, 
+						via_read(via1, vBufB)^TACK); 
+				}
+			}
+			if(macintosh_config->adb_type==MAC_ADB_II)
+			{
+				if( status == TIP)
+				{
+					via_write(via1, vBufB,
+						via_read(via1, vBufB)|TACK|TIP);
+					adb_state = read_done;
+				}
+				else
+				{
+					if(status!=TIP+TREQ)
+						printk("macII_adb: state=reading status=%x\n", status);
+					via_write(via1, vBufB, 
+						via_read(via1, vBufB)^TACK);
+				}
+			}
+			break;
+
+		case read_done:
+			x = via_read(via1, vSR); 
+			if (reading_reply) 
+			{
+				req = current_req;
+				req->reply_len = reply_ptr - req->reply;
+				req->got_reply = 1;
+				current_req = req->next;
+				if (req->done)
+					(*req->done)(req);
+			}
+			else
+			{
+				adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+			}
+
+			if (status == TREQ) 
+			{
+				via_write(via1, vBufB,
+					via_read(via1, vBufB)|~TIP); 
+				adb_state = reading;
+				reply_ptr = cuda_rbuf;
+				reading_reply = 0;
+			}
+			else 
+			{
+				adb_state = idle;
+				adb_start();
+			}
+			break;
+
+		default:
+			printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
+	}
+}
+
+/*
+ *	The 'reply delivery' routine; determines which device sent the 
+ *	request and calls the appropriate handler. 
+ *	Reply data are expected in CUDA format (again, argh...) so we need
+ *	to fake this in the interrupt handler for MacII.
+ *	Only one handler per device ID is currently possible.
+ *	XXX: is the ID field here representing the default or real ID?
+ */
+static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs)
+{
+	int i, id;
+
+	switch (buf[0]) 
+	{
+		case ADB_PACKET:
+			/* what's in buf[1] ?? */
+			id = buf[2] >> 4;
+#if 0
+			xmon_printf("adb packet: ");
+			for (i = 0; i < nb; ++i)
+				xmon_printf(" %x", buf[i]);
+			xmon_printf(", id = %d\n", id);
+#endif
+#if (ADBDEBUG & ADBDEBUG_INPUT)
+			if (console_loglevel == 10) {
+				printk("adb_input: adb packet ");
+				for (i = 0; i < nb; ++i)
+					printk(" %x", buf[i]);
+				printk(", id = %d\n", id);
+			}
+#endif
+			if (adb_handler[id].handler != 0) 
+			{
+				(*adb_handler[id].handler)(buf, nb, regs);
+			}
+			break;
+
+		default:
+#if (ADBDEBUG & ADBDEBUG_INPUT)
+			if (console_loglevel == 10) {
+				printk("adb_input: data from via (%d bytes):", nb);
+				for (i = 0; i < nb; ++i)
+					printk(" %.2x", buf[i]);
+				printk("\n");
+			}
+#endif
+	}
+}
+
+/* Ultimately this should return the number of devices with
+   the given default id. */
+
+int adb_register(int default_id,
+	     void (*handler)(unsigned char *, int, struct pt_regs *))
+{
+	if (adb_handler[default_id].handler != 0)
+		panic("Two handlers for ADB device %d\n", default_id);
+	adb_handler[default_id].handler = handler;
+	return 1;
+}
+
+/*
+ * /dev/adb device driver.
+ */
+
+#define ADB_MAJOR	56	/* major number for /dev/adb */
+
+#define ADB_MAX_MINOR	64	/* range of ADB minors */
+#define ADB_TYPE_SHIFT	4	/* # bits for device ID/type in subdevices */
+
+#define ADB_TYPE_RAW	0	/* raw device; unbuffered */
+#define ADB_TYPE_BUFF	1	/* raw device; buffered */
+#define ADB_TYPE_COOKED	2	/* 'cooked' device */
+
+
+extern void adbdev_init(void);
+
+struct adbdev_state {
+	struct adb_request req;
+};
+
+static struct wait_queue *adb_wait;
+
+static int adb_wait_reply(struct adbdev_state *state, struct file *file)
+{
+	int ret = 0;
+	struct wait_queue wait = { current, NULL };
+
+	add_wait_queue(&adb_wait, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+
+	while (!state->req.got_reply) {
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			break;
+		}
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&adb_wait, &wait);
+
+	return ret;
+}
+
+static void adb_write_done(struct adb_request *req)
+{
+	if (!req->got_reply) {
+		req->reply_len = 0;
+		req->got_reply = 1;
+	}
+	wake_up_interruptible(&adb_wait);
+}
+
+struct file_operations *adb_raw[16];
+struct file_operations *adb_buffered[16];
+struct file_operations *adb_cooked[16];
+
+static int adb_open(struct inode *inode, struct file *file)
+{
+	int adb_type, adb_subtype;
+	struct adbdev_state *state;
+
+	if (MINOR(inode->i_rdev) > ADB_MAX_MINOR)
+		return -ENXIO;
+
+	switch (MINOR(inode->i_rdev) >> ADB_TYPE_SHIFT) {
+		case ADB_TYPE_RAW:
+			/* see code below */
+			break;
+		case ADB_TYPE_BUFF:
+			/* TBI */
+			return -ENXIO;
+		case ADB_TYPE_COOKED:
+			/* subtypes such as kbd, mouse, ... */
+			adb_subtype = MINOR(inode->i_rdev) & ~ADB_TYPE_SHIFT;
+			if ((file->f_op = adb_cooked[adb_subtype]))
+				return file->f_op->open(inode,file);
+			else
+				return -ENODEV;
+	}
+
+	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
+	if (state == 0)
+		return -ENOMEM;
+	file->private_data = state;
+	state->req.reply_expected = 0;
+	return 0;
+}
+
+static void adb_release(struct inode *inode, struct file *file)
+{
+	struct adbdev_state *state = file->private_data;
+
+	if (state) {
+		file->private_data = NULL;
+		if (state->req.reply_expected && !state->req.got_reply)
+			if (adb_wait_reply(state, file))
+				return;
+		kfree(state);
+	}
+	return;
+}
+
+static int adb_lseek(struct inode *inode, struct file *file, 
+		     off_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int adb_read(struct inode *inode, struct file *file,
+		     char *buf, int count)
+{
+	int ret;
+	struct adbdev_state *state = file->private_data;
+
+	if (count < 2)
+		return -EINVAL;
+	if (count > sizeof(state->req.reply))
+		count = sizeof(state->req.reply);
+	ret = verify_area(VERIFY_WRITE, buf, count);
+	if (ret)
+		return ret;
+
+	if (!state->req.reply_expected)
+		return 0;
+
+	ret = adb_wait_reply(state, file);
+	if (ret)
+		return ret;
+
+	state->req.reply_expected = 0;
+	ret = state->req.reply_len;
+	copy_to_user(buf, state->req.reply, ret);
+
+	return ret;
+}
+
+static int adb_write(struct inode *inode, struct file *file,
+		      const char *buf, int count)
+{
+	int ret, i;
+	struct adbdev_state *state = file->private_data;
+
+	if (count < 2 || count > sizeof(state->req.data))
+		return -EINVAL;
+	ret = verify_area(VERIFY_READ, buf, count);
+	if (ret)
+		return ret;
+
+	if (state->req.reply_expected && !state->req.got_reply) {
+		/* A previous request is still being processed.
+		   Wait for it to finish. */
+		ret = adb_wait_reply(state, file);
+		if (ret)
+			return ret;
+	}
+
+	state->req.nbytes = count;
+	state->req.done = adb_write_done;
+	state->req.got_reply = 0;
+	copy_from_user(state->req.data, buf, count);
+#if 0
+	switch (adb_hardware) {
+	case ADB_NONE:
+		return -ENXIO;
+	case ADB_VIACUDA:
+		state->req.reply_expected = 1;
+		cuda_send_request(&state->req);
+		break;
+	default:
+#endif
+		if (state->req.data[0] != ADB_PACKET)
+			return -EINVAL;
+		for (i = 1; i < state->req.nbytes; ++i)
+			state->req.data[i] = state->req.data[i+1];
+		state->req.reply_expected =
+			((state->req.data[0] & 0xc) == 0xc);
+		adb_send_request(&state->req);
+#if 0
+		break;
+	}
+#endif
+
+	return count;
+}
+
+static struct file_operations adb_fops = {
+	adb_lseek,
+	adb_read,
+	adb_write,
+	NULL,		/* no readdir */
+	NULL,		/* no poll yet */
+	NULL,		/* no ioctl yet */
+	NULL,		/* no mmap */
+	adb_open,
+	adb_release
+};
+
+int adbdev_register(int subtype, struct file_operations *fops)
+{
+	if (subtype < 0 || subtype > 15)
+		return -EINVAL;
+	if (adb_cooked[subtype])
+		return -EBUSY;
+	adb_cooked[subtype] = fops;
+	return 0;
+}
+
+int adbdev_unregister(int subtype)
+{
+	if (subtype < 0 || subtype > 15)
+		return -EINVAL;
+	if (!adb_cooked[subtype])
+		return -ENODEV;
+	adb_cooked[subtype] = NULL;
+	return 0;
+}
+
+void adbdev_init()
+{
+	if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
+		printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
+}
+
+
+#if 0 /* old ADB device */
+
+/*
+ * Here are the file operations we export for /dev/adb.
+ */
+
+#define ADB_MINOR	140	/* /dev/adb is c 10 140 */
+
+extern void adbdev_inits(void);
+
+struct adbdev_state {
+	struct adb_request req;
+};
+
+static struct wait_queue *adb_wait;
+
+static int adb_wait_reply(struct adbdev_state *state, struct file *file)
+{
+	int ret = 0;
+	struct wait_queue wait = { current, NULL };
+
+#if (ADBDEBUG & ADBDEBUG_DEVICE)
+	printk("ADB request: wait_reply (blocking ... \n");
+#endif
+
+	add_wait_queue(&adb_wait, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+
+	while (!state->req.got_reply) {
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			break;
+		}
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&adb_wait, &wait);
+
+	return ret;
+}
+
+static void adb_write_done(struct adb_request *req)
+{
+	if (!req->got_reply) {
+		req->reply_len = 0;
+		req->got_reply = 1;
+	}
+	wake_up_interruptible(&adb_wait);
+}
+
+static int adb_open(struct inode *inode, struct file *file)
+{
+	struct adbdev_state *state;
+
+	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
+	if (state == 0)
+		return -ENOMEM;
+	file->private_data = state;
+	state->req.reply_expected = 0;
+	return 0;
+}
+
+static void adb_release(struct inode *inode, struct file *file)
+{
+	struct adbdev_state *state = file->private_data;
+
+	if (state) {
+		file->private_data = NULL;
+		if (state->req.reply_expected && !state->req.got_reply)
+			if (adb_wait_reply(state, file))
+				return;
+		kfree(state);
+	}
+	return;
+}
+
+static int adb_lseek(struct inode *inode, struct file *file,
+		     off_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int adb_read(struct inode *inode, struct file *file,
+		    char *buf, int count)
+{
+	int ret;
+	struct adbdev_state *state = file->private_data;
+
+	if (count < 2)
+		return -EINVAL;
+	if (count > sizeof(state->req.reply))
+		count = sizeof(state->req.reply);
+	ret = verify_area(VERIFY_WRITE, buf, count);
+	if (ret)
+		return ret;
+
+	if (!state->req.reply_expected)
+		return 0;
+
+	ret = adb_wait_reply(state, file);
+	if (ret)
+		return ret;
+
+	ret = state->req.reply_len;
+	memcpy_tofs(buf, state->req.reply, ret);
+	state->req.reply_expected = 0;
+
+	return ret;
+}
+
+static int adb_write(struct inode *inode, struct file *file,
+		     const char *buf, int count)
+{
+	int ret;
+	struct adbdev_state *state = file->private_data;
+
+	if (count < 2 || count > sizeof(state->req.data))
+		return -EINVAL;
+	ret = verify_area(VERIFY_READ, buf, count);
+	if (ret)
+		return ret;
+
+	if (state->req.reply_expected && !state->req.got_reply) {
+		/* A previous request is still being processed.
+		   Wait for it to finish. */
+		ret = adb_wait_reply(state, file);
+		if (ret)
+			return ret;
+	}
+
+	state->req.nbytes = count;
+	state->req.done = adb_write_done;
+	memcpy_fromfs(state->req.data, buf, count);
+	state->req.reply_expected = 1;
+	state->req.got_reply = 0;
+	adb_send_request(&state->req);
+
+	return count;
+}
+
+static struct file_operations adb_fops = {
+	adb_lseek,
+	adb_read,
+	adb_write,
+	NULL,		/* no readdir */
+	NULL,		/* no select */
+	NULL,		/* no ioctl */
+	NULL,		/* no mmap */
+	adb_open,
+	adb_release
+};
+
+static struct miscdevice adb_dev = {
+	ADB_MINOR,
+	"adb",
+	&adb_fops
+};
+
+void adbdev_init(void)
+{
+	misc_register(&adb_dev);
+}
+
+#endif /* old ADB device */
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/bootparse.c linux/arch/m68k/mac/bootparse.c
--- v2.1.86/linux/arch/m68k/mac/bootparse.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/bootparse.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,121 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/macintosh.h>
+
+/*
+ *	Booter vars
+ */
+ 
+int boothowto;
+int _boothowto;
+ 
+/*
+ *	Called early to parse the environment (passed to us from the booter)
+ *	into a bootinfo struct. Will die as soon as we have our own booter
+ */
+
+#define atol(x)	simple_strtoul(x,NULL,0)
+ 
+void parse_booter(char *env)
+{
+ 	char *name;
+ 	char *value;
+#if 0
+ 	while(0 && *env)
+#else
+ 	while(*env)
+#endif
+ 	{
+ 		name=env;
+ 		value=name;
+ 		while(*value!='='&&*value)
+ 			value++;
+ 		if(*value=='=')
+ 			*value++=0;
+ 		env=value;
+ 		while(*env)
+ 			env++;
+ 		env++;
+#if 0 			
+ 		if(strcmp(name,"VIDEO_ADDR")==0)
+ 			mac_mch.videoaddr=atol(value);
+ 		if(strcmp(name,"ROW_BYTES")==0)
+ 			mac_mch.videorow=atol(value); 			
+ 		if(strcmp(name,"SCREEN_DEPTH")==0)
+ 			mac_mch.videodepth=atol(value);
+ 		if(strcmp(name,"DIMENSIONS")==0)
+ 			mac_mch.dimensions=atol(value);
+#endif 			
+ 		if(strcmp(name,"BOOTTIME")==0)
+ 			mac_bi_data.boottime=atol(value);
+ 		if(strcmp(name,"GMTBIAS")==0)
+ 			mac_bi_data.gmtbias=atol(value);
+ 		if(strcmp(name,"BOOTERVER")==0)
+ 			mac_bi_data.bootver=atol(value);
+ 		if(strcmp(name,"MACOS_VIDEO")==0)
+ 			mac_bi_data.videological=atol(value);
+ 		if(strcmp(name,"MACOS_SCC")==0)
+ 			mac_bi_data.sccbase=atol(value);
+ 		if(strcmp(name,"MACHINEID")==0)
+ 			mac_bi_data.id=atol(value);
+ 		if(strcmp(name,"MEMSIZE")==0)
+ 			mac_bi_data.memsize=atol(value);
+ 		if(strcmp(name,"SERIAL_MODEM_FLAGS")==0)
+ 			mac_bi_data.serialmf=atol(value);
+ 		if(strcmp(name,"SERIAL_MODEM_HSKICLK")==0)
+ 			mac_bi_data.serialhsk=atol(value);
+ 		if(strcmp(name,"SERIAL_MODEM_GPICLK")==0)
+ 			mac_bi_data.serialgpi=atol(value);
+ 		if(strcmp(name,"SERIAL_PRINT_FLAGS")==0)
+ 			mac_bi_data.printmf=atol(value);
+ 		if(strcmp(name,"SERIAL_PRINT_HSKICLK")==0)
+ 			mac_bi_data.printhsk=atol(value);
+ 		if(strcmp(name,"SERIAL_PRINT_GPICLK")==0)
+ 			mac_bi_data.printgpi=atol(value);
+ 		if(strcmp(name,"PROCESSOR")==0)
+ 			mac_bi_data.cpuid=atol(value);
+ 		if(strcmp(name,"ROMBASE")==0)
+ 			mac_bi_data.rombase=atol(value);
+ 		if(strcmp(name,"TIMEDBRA")==0)
+ 			mac_bi_data.timedbra=atol(value);
+ 		if(strcmp(name,"ADBDELAY")==0)
+ 			mac_bi_data.adbdelay=atol(value);
+ 	}
+#if 0	/* XXX: TODO with m68k_mach_* */
+ 	/* Fill in the base stuff */
+ 	boot_info.machtype=MACH_MAC;
+ 	/* Read this from the macinfo we got ! */
+/*	boot_info.cputype=CPU_68020|FPUB_68881;*/
+/* 	boot_info.memory[0].addr=0;*/
+/* 	boot_info.memory[0].size=((mac_bi_data.id>>7)&31)<<20;*/
+ 	boot_info.num_memory=1;		/* On a MacII */
+ 	boot_info.ramdisk_size=0;	/* For now */
+ 	*boot_info.command_line=0;
+#endif
+ }
+ 
+
+void print_booter(char *env)
+{
+ 	char *name;
+ 	char *value;
+ 	while(*env)
+ 	{
+ 		name=env;
+ 		value=name;
+ 		while(*value!='='&&*value)
+ 			value++;
+ 		if(*value=='=')
+ 			*value++=0;
+ 		env=value;
+ 		while(*env)
+ 			env++;
+ 		env++;
+ 		printk("%s=%s\n", name,value);
+ 	}
+ }
+ 
+
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c
--- v2.1.86/linux/arch/m68k/mac/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/config.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,575 @@
+/*
+ *  linux/arch/m68k/mac/config.c
+ *
+ * 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.
+ */
+
+/*
+ * Miscellaneous linux stuff
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+/* keyb */
+#include <linux/random.h>
+#include <linux/delay.h>
+/* keyb */
+#include <linux/init.h>
+
+#define BOOTINFO_COMPAT_1_0
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+
+#include "via6522.h"
+
+/* old bootinfo stuff */
+
+struct mac_booter_data mac_bi_data = {0,};
+int mac_bisize = sizeof mac_bi_data;
+
+struct compat_bootinfo compat_boot_info ={0,};
+int compat_bisize = sizeof compat_boot_info;
+
+int compat_bi = 0;
+
+/* New bootinfo stuff */
+
+extern int m68k_num_memory;
+extern struct mem_info m68k_memory[NUM_MEMINFO];
+
+extern struct mem_info m68k_ramdisk;
+
+extern char m68k_command_line[CL_SIZE];
+
+void *mac_env;		/* Loaded by the boot asm */
+
+extern int mac_keyb_init(void);
+extern int mac_kbdrate(struct kbd_repeat *k);
+extern void mac_kbd_leds(unsigned int leds);
+
+extern void (*kd_mksound)(unsigned int, unsigned int);
+extern void mac_mksound(unsigned int, unsigned int);
+extern int mac_floppy_init(void);
+extern void mac_floppy_setup(char *,int *);
+
+extern void mac_gettod (int *, int *, int *, int *, int *, int *);
+
+extern void nubus_sweep_video(void);
+extern void via_init_clock(void (*func)(int, void *, struct pt_regs *));
+extern void mac_debugging_long(int, long);
+
+/* Mac specific debug functions (in debug.c) */
+extern void mac_debug_init(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static char mac_sysrq_xlate[128] =
+	"\000\0331234567890-=\177\t"					/* 0x00 - 0x0f */
+	"qwertyuiop[]\r\000as"							/* 0x10 - 0x1f */
+	"dfghjkl;'`\000\\zxcv"							/* 0x20 - 0x2f */
+	"bnm,./\000\000\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
+	"\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
+	"\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+	"\000\000\000()/*789456123"						/* 0x60 - 0x6f */
+	"0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 0x70 - 0x7f */
+#endif
+
+extern void (*kd_mksound)(unsigned int, unsigned int);
+
+void mac_get_model(char *str)
+{
+	strcpy(str,"Macintosh");
+}
+
+void mac_bang(int irq, void *vector, struct pt_regs *p)
+{
+	printk("Resetting ...\n");
+	mac_reset();
+}
+
+void mac_sched_init(void (*vector)(int, void *, struct pt_regs *))
+{
+	via_init_clock(vector);
+}
+
+unsigned long mac_gettimeoffset (void)
+{
+	return 0L;
+}
+
+extern int console_loglevel;
+
+void mac_gettod (int *yearp, int *monp, int *dayp,
+		 int *hourp, int *minp, int *secp)
+{
+	unsigned long time;
+	int leap, oldleap, isleap;
+	int mon_days[14] = { -1, 31, 27, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
+
+	time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */
+
+#if 0
+	printk("mac_gettod: boottime 0x%lx gmtbias %ld \n",
+		mac_bi_data.boottime, mac_bi_data.gmtbias);
+#endif	
+
+	*minp = time / 60;
+	*secp = time - (*minp * 60);
+	time  = *minp;				/* minutes now */
+
+	*hourp = time / 60;
+	*minp  = time - (*hourp * 60);
+	time   = *hourp;			/* hours now */
+
+	*dayp  = time / 24;
+	*hourp = time - (*dayp * 24);
+	time   = *dayp;				/* days now ... */
+
+	/* for leap day calculation */
+	*yearp = (time / 365) + 1970;		/* approx. year */
+
+	/* leap year calculation - there's an easier way, I bet */
+	/* calculate leap days up to previous year */
+	oldleap =  (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400;
+	/* calculate leap days incl. this year */
+	leap    =  *yearp/4 - *yearp/100 + *yearp/400;
+	/* this year a leap year ?? */
+	isleap  = (leap != oldleap);
+
+	/* adjust days: days, excluding past leap days since epoch */
+	time  -= oldleap - (1970/4 - 1970/100 + 1970/400);
+
+	/* precise year, and day in year */
+	*yearp = (time / 365);			/* #years since epoch */
+	*dayp  = time - (*yearp * 365) + 1;	/* #days this year (0: Jan 1) */
+	*yearp += 70;				/* add epoch :-) */
+	time = *dayp;
+	
+	if (isleap)				/* add leap day ?? */
+		mon_days[2] = 28;
+
+	/* count the months */
+	for (*monp = 1; time > mon_days[*monp]; (*monp)++) 
+		time -= mon_days[*monp];
+
+	*dayp = time;
+
+#if 1
+	printk("mac_gettod: %d-%d-%d %d:%d.%d GMT (GMT offset %d)\n",
+		*yearp, *monp, *dayp, *hourp, *minp, *secp, 
+		(signed long) mac_bi_data.gmtbias);
+#endif
+
+	return;
+}
+
+void mac_waitbut (void)
+{
+	;
+}
+
+extern struct consw fb_con;
+extern struct fb_info *mac_fb_init(long *);
+extern void mac_video_setup(char *, int *);
+
+void mac_debug_init (void)
+{
+	;
+}
+
+void (*mac_handlers[8])(int, void *, struct pt_regs *)=
+{
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler,
+	mac_default_handler
+};
+
+    /*
+     *  Parse a Macintosh-specific record in the bootinfo
+     */
+
+__initfunc(int mac_parse_bootinfo(const struct bi_record *record))
+{
+    int unknown = 0;
+    const u_long *data = record->data;
+
+    if (compat_bi)
+        return(unknown);
+
+    switch (record->tag) {
+	case BI_MAC_MODEL:
+	    mac_bi_data.id = *data;
+	    break;
+	case BI_MAC_VADDR:
+	    mac_bi_data.videoaddr = *data;
+	    break;
+	case BI_MAC_VDEPTH:
+	    mac_bi_data.videodepth = *data;
+	    break;
+	case BI_MAC_VROW:
+	    mac_bi_data.videorow = *data;
+	    break;
+	case BI_MAC_VDIM:
+	    mac_bi_data.dimensions = *data;
+	    break;
+	case BI_MAC_VLOGICAL:
+	    mac_bi_data.videological = *data;
+	    break;
+	case BI_MAC_SCCBASE:
+	    mac_bi_data.sccbase = *data;
+	    break;
+	case BI_MAC_BTIME:
+	    mac_bi_data.boottime = *data;
+	    break;
+	case BI_MAC_GMTBIAS:
+	    mac_bi_data.gmtbias = *data;
+	    break;
+	case BI_MAC_MEMSIZE:
+	    mac_bi_data.memsize = *data;
+	    break;
+	case BI_MAC_CPUID:
+	    mac_bi_data.cpuid = *data;
+	    break;
+	default:
+	    unknown = 1;
+    }
+    return(unknown);
+}
+
+__initfunc(void mac_copy_compat(void))
+{
+    int i;
+
+    compat_bi = 1;
+    
+    for (i=0; i<compat_boot_info.num_memory; i++) {
+    	m68k_memory[m68k_num_memory].addr = compat_boot_info.memory[i].addr;
+    	m68k_memory[m68k_num_memory].size = compat_boot_info.memory[i].size;
+	m68k_num_memory++;
+    }
+
+    m68k_ramdisk.addr = compat_boot_info.ramdisk_addr;
+    m68k_ramdisk.size = compat_boot_info.ramdisk_size;
+
+    strncpy(m68k_command_line, (const char *)compat_boot_info.command_line, 
+            CL_SIZE);
+    m68k_command_line[CL_SIZE-1] = '\0';
+                                
+    mac_bi_data.id = compat_boot_info.bi_mac.id;
+    mac_bi_data.videoaddr =  compat_boot_info.bi_mac.videoaddr;
+    mac_bi_data.videodepth = compat_boot_info.bi_mac.videodepth;
+    mac_bi_data.videorow = compat_boot_info.bi_mac.videorow;
+    mac_bi_data.dimensions = compat_boot_info.bi_mac.dimensions;
+    mac_bi_data.videological = compat_boot_info.bi_mac.videological;
+    mac_bi_data.sccbase = compat_boot_info.bi_mac.sccbase;
+    mac_bi_data.boottime = compat_boot_info.bi_mac.boottime;
+    mac_bi_data.gmtbias = compat_boot_info.bi_mac.gmtbias;
+    mac_bi_data.memsize = compat_boot_info.bi_mac.memsize;
+    mac_bi_data.cpuid = compat_boot_info.bi_mac.cpuid;
+
+}
+
+__initfunc(void config_mac(void))
+{
+
+    if (MACH_IS_ATARI || MACH_IS_AMIGA) {
+      printk("ERROR: no Mac, but config_mac() called!! \n");
+    }
+    
+    mac_debugging_penguin(5);
+
+    mac_debug_init();
+        
+    mach_sched_init      = mac_sched_init;
+    mach_keyb_init       = mac_keyb_init;
+    mach_kbdrate         = mac_kbdrate;
+    mach_kbd_leds        = mac_kbd_leds;
+    mach_init_IRQ        = mac_init_IRQ;
+    mach_request_irq     = mac_request_irq;
+    mach_free_irq        = mac_free_irq;
+    enable_irq           = mac_enable_irq;
+    disable_irq          = mac_disable_irq;
+#if 1
+    mach_default_handler = &mac_handlers;
+#endif
+    mach_get_model	 = mac_get_model;
+    mach_get_irq_list	 = mac_get_irq_list;
+    mach_gettimeoffset   = mac_gettimeoffset;
+    mach_gettod          = mac_gettod;
+#if 0
+    mach_mksound         = mac_mksound;
+#endif
+    mach_reset           = mac_reset;
+#ifdef CONFIG_BLK_DEV_FD
+    mach_floppy_init	 = mac_floppy_init;
+    mach_floppy_setup	 = mac_floppy_setup;
+#endif
+    conswitchp	         = &fb_con;
+    mach_max_dma_address = 0xffffffff;
+#if 0
+    mach_debug_init	 = mac_debug_init;
+    mach_video_setup	 = mac_video_setup;
+#endif
+    kd_mksound		 = mac_mksound;
+#ifdef CONFIG_MAGIC_SYSRQ
+    mach_sysrq_key = 98;          /* HELP */
+    mach_sysrq_shift_state = 8;   /* Alt */
+    mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */
+    mach_sysrq_xlate = mac_sysrq_xlate;
+#endif
+#ifdef CONFIG_HEARTBEAT
+#if 0
+    mach_heartbeat = mac_heartbeat;
+    mach_heartbeat_irq = IRQ_MAC_TIMER;
+#endif
+#endif
+
+    /*
+     * Determine hardware present
+     */
+     
+    mac_identify();
+    mac_report_hardware();
+
+    /* goes on forever if timers broken */
+#ifdef MAC_DEBUG_SOUND
+    mac_mksound(1000,10);
+#endif
+
+    /*
+     * Check for machine specific fixups.
+     */
+
+    nubus_sweep_video();
+}	
+
+
+/*
+ *	Macintosh Table
+ */
+ 
+struct mac_model *macintosh_config;
+
+static struct mac_model mac_data_table[]=
+{
+	/*
+	 *	Original MacII hardware
+	 *	
+	 */
+	 
+	{	MAC_MODEL_II,	"II",		MAC_ADB_II,	MAC_VIA_II,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_NUBUS},
+	{	MAC_MODEL_IIX,	"IIx",		MAC_ADB_II,	MAC_VIA_II,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_NUBUS},
+	{	MAC_MODEL_IICX,	"IIcx",		MAC_ADB_II,	MAC_VIA_II,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_NUBUS},
+	{	MAC_MODEL_SE30, "SE/30",	MAC_ADB_II,	MAC_VIA_II,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_NUBUS},
+	
+	/*
+	 *	Weirdified MacII hardware - all subtley different. Gee thanks
+	 *	Apple. All these boxes seem to have VIA2 in a different place to
+	 *	the MacII (+1A000 rather than +4000)
+	 *
+	 *	The IIfx apparently has different ADB hardware, and stuff
+	 *	so zany nobody knows how to drive it.
+	 */
+
+	{	MAC_MODEL_IICI,	"IIci",	MAC_ADB_II,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_IIFX,	"IIfx",	MAC_ADB_NONE,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_IISI, "IIsi",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_IIVI,	"IIvi",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_IIVX,	"IIvx",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	
+	/*
+	 *	Classic models (guessing: similar to SE/30 ?? Nope, similar to LC ...)
+	 */
+
+	{	MAC_MODEL_CLII, "Classic II",		MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,     MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_CCL,  "Color Classic",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,     MAC_ETHER_NONE,	MAC_NUBUS},
+
+	/*
+	 *	Some Mac LC machines. Basically the same as the IIci
+	 */
+	
+	{	MAC_MODEL_LCII,	"LC II",  MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_LCIII,"LC III", MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+
+	/*
+	 *	Quadra (only 68030 ones will actually work!). Not much odd. Video is at
+	 *	0xF9000000, via is like a MacII. We label it differently as some of the
+	 *	stuff connected to VIA2 seems different. Better SCSI chip and ???? onboard ethernet
+	 *	in all cases using a NatSemi SONIC. The 700, 900 and 950 have some I/O chips in the wrong
+	 *	place to confuse us. The 840 seems to have a scsi location of its own
+	 */	 
+	 
+	{	MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q610, "Quadra 610", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+ 	{	MAC_MODEL_Q650, "Quadra 650", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	/*	The Q700 does have a NS Sonic */
+#if 0
+	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q800, "Quadra 800", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+#else
+	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+#endif
+	/* Does the 840 have ethernet ??? documents seem to indicate its not quite a
+	   Quadra in this respect ? */
+	{	MAC_MODEL_Q840, "Quadra 840", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II,	        MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_Q900, "Quadra 900", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q950, "Quadra 950", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE, MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+
+	/* 
+	 *	Performa - more LC type machines
+	 */
+
+	{	MAC_MODEL_P460, "Performa 460", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P475, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
+	{	MAC_MODEL_P520, "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P550, "Performa 550", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P575, "Performa 575", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_TV,   "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+#if 0	/* other sources seem to suggest the P630/Q630/LC630 is more like LCIII */
+	{	MAC_MODEL_P630, "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+#endif
+	/*
+	 *	Centris - just guessing again; maybe like Quadra
+	 */
+
+	{	MAC_MODEL_C610, "Centris 610",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_C650, "Centris 650",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+
+	/*
+	 *      Power books - seem similar to early Quadras ? (most have 030 though)
+	 */
+
+	{	MAC_MODEL_PB140,  "PowerBook 140",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB145,  "PowerBook 145",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	/*	The PB150 has IDE, and IIci style VIA */
+	{	MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_QUADRA, MAC_IDE_PB,	  MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB160,  "PowerBook 160",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB165,  "PowerBook 165",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB165C, "PowerBook 165c",  MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB170,  "PowerBook 170",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB180,  "PowerBook 180",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB180C, "PowerBook 180c",  MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB190,  "PowerBook 190cs", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB520,  "PowerBook 520",   MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+
+	/*
+	 *      Power book Duos - similar to Power books, I hope
+	 */
+
+	{	MAC_MODEL_PB210,  "PowerBook Duo 210",  MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB230,  "PowerBook Duo 230",  MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB250,  "PowerBook Duo 250",  MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB280,  "PowerBook Duo 280",  MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+
+	/*
+	 *	Other stuff ??
+	 */
+	{	-1, NULL, 0,0,0,}
+};
+
+void mac_identify(void)
+{
+	struct mac_model *m=&mac_data_table[0];
+
+	/* Penguin data useful? */	
+	int model = mac_bi_data.id;
+	if (!model) {
+		/* no bootinfo model id -> NetBSD booter was used! */
+		/* XXX FIXME: breaks for model > 31 */
+		model=(mac_bi_data.cpuid>>2)&63;
+		printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+	}
+
+	printk ("Detected Macintosh model: %d \n", model);
+	
+	while(m->ident != -1)
+	{
+		if(m->ident == model)
+			break;
+		m++;
+	}
+	if(m->ident==-1)
+	{
+		printk("\nUnknown macintosh model %d, probably unsupported.\n", 
+			model);
+		mac_debugging_long(1, (long) 0x55555555);
+		mac_debugging_long(1, (long) model);
+		model = MAC_MODEL_Q800;
+		printk("Defaulting to: Quadra800, model id %d\n", model);
+		printk("Please report this case to linux-mac68k@wave.lm.com\n");
+		m=&mac_data_table[0];
+		while(m->ident != -1)
+		{
+			if(m->ident == model)
+				break;
+			m++;
+		}
+		if(m->ident==-1)
+			mac_boom(5);
+	}
+
+	/*
+	 * Report booter data:
+	 */
+	printk (" Penguin (bootinfo version %d) data:\n", 2-compat_bi);
+	printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %d x %d\n", 
+		mac_bi_data.videoaddr, mac_bi_data.videorow, 
+		mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, 
+		mac_bi_data.dimensions >> 16); 
+	printk (" Boottime: 0x%lx GMTBias: 0x%lx \n",
+		mac_bi_data.boottime, mac_bi_data.gmtbias); 
+	printk (" Videological 0x%lx, SCC at 0x%lx \n",
+		mac_bi_data.videological, mac_bi_data.sccbase); 
+	printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+		mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); 
+	printk ("Ramdisk: addr 0x%lx size 0x%lx\n", 
+		m68k_ramdisk.addr, m68k_ramdisk.size);
+
+	/*
+	 *	Save the pointer
+	 */
+
+	macintosh_config=m;
+
+	/*
+	 * TODO: set the various fields in macintosh_config->hw_present here!
+	 */
+
+}
+
+void mac_report_hardware(void)
+{
+	printk("Apple Macintosh %s\n", macintosh_config->name);
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c
--- v2.1.86/linux/arch/m68k/mac/debug.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/debug.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,366 @@
+/*
+ * linux/arch/m68k/mac/debug.c
+ *
+ * Shamelessly stolen (SCC code and general framework) from:
+ *
+ * linux/arch/m68k/atari/debug.c
+ *
+ * Atari debugging and serial console stuff
+ *
+ * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek
+ *  
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#define BOOTINFO_COMPAT_1_0
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/machw.h>
+#include <asm/macints.h>
+
+extern char m68k_debug_device[];
+
+extern struct compat_bootinfo compat_boot_info;
+
+extern unsigned long mac_videobase;
+extern unsigned long mac_videodepth;
+extern unsigned long mac_rowbytes;
+
+/*
+ * These two auxiliary debug functions should go away ASAP. Only usage: 
+ * before the console output is up (after head.S come some other crucial
+ * setup routines :-) it permits writing 'data' to the screen as bit patterns
+ * (good luck reading those). Helped to figure that the bootinfo contained
+ * garbage data on the amount and size of memory chunks ...
+ *
+ * The 'pos' argument now simply means 'linefeed after print' ...
+ */
+
+static int peng=0, line=0;
+
+void mac_debugging_short(int pos, short num)
+{
+	unsigned char *pengoffset;
+	unsigned char *pptr;
+	int i;
+
+	if (!MACH_IS_MAC) {
+		/* printk("debug: %d !\n", num); */
+		return;
+	}
+
+	/* calculate current offset */
+	pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+		    +80*peng;
+	
+	pptr=pengoffset;
+	
+	for(i=0;i<8*sizeof(short);i++) /* # of bits */
+	{
+		/*        value        mask for bit i, reverse order */
+		*pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00);
+	}
+
+	peng++;
+
+	if (pos) {
+		line++;
+		peng = 0;
+	}
+}
+
+void mac_debugging_long(int pos, long addr)
+{
+	unsigned char *pengoffset;
+	unsigned char *pptr;
+	int i;
+
+	if (!MACH_IS_MAC) {
+		/* printk("debug: #%ld !\n", addr); */
+		return;
+	}
+	
+	pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes)
+		    +80*peng;
+	
+	pptr=pengoffset;
+	
+	for(i=0;i<8*sizeof(long);i++) /* # of bits */
+	{
+		*pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00);
+	}
+
+	peng++;
+
+	if (pos) {
+		line++;
+		peng = 0;
+	}
+}
+
+/*
+ * Penguin - used by head.S console; obsolete
+ */
+char that_penguin[]={
+#include "that_penguin.h"
+};
+
+/* 
+ * B/W version of penguin, unfinished - any takers??
+ */
+static char bw_penguin[]={
+#include "bw_penguin.h"
+};
+
+void mac_debugging_penguin(int peng)
+{
+	unsigned char *pengoffset;
+	unsigned char *pptr;
+	unsigned char *bwpdptr=bw_penguin;
+	int i;
+
+	if (!MACH_IS_MAC) 
+		return;
+
+	if (compat_boot_info.bi_mac.videodepth ==1) 
+		pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes)
+			   +5*peng;
+	else
+		pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes)
+			   +20*peng;
+	
+	pptr=pengoffset;
+	
+	for(i=0;i<36;i++)
+	{
+		memcpy(pptr,bwpdptr,4);
+		bwpdptr+=4;
+		pptr+=mac_rowbytes;
+	}
+}
+
+/*
+ * B/W version of flaming Mac, unfinished (see above).
+ */
+static char bw_kaboom_map[]={
+#include "bw_mac.h"
+};
+
+static void mac_boom_boom(void)
+{
+	static unsigned char *boomoffset=NULL;
+	unsigned char *pptr;
+	unsigned char *bwpdptr=bw_kaboom_map;
+	int i;
+	
+	if(!boomoffset)
+		if (compat_boot_info.bi_mac.videodepth == 1) {
+			boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes);
+		} else {
+			boomoffset=(unsigned char *)(mac_videobase+256*mac_rowbytes);
+		}
+	else
+		if (compat_boot_info.bi_mac.videodepth == 1)
+			boomoffset+=5;
+		else
+			boomoffset+=32;	
+
+	pptr=boomoffset;
+	
+	for(i=0;i<36;i++)
+	{
+		memcpy(pptr,bwpdptr,4);
+		bwpdptr+=4;
+		pptr+=mac_rowbytes;
+	}
+}
+
+void mac_boom(int booms)
+{
+	int i;
+
+	if (!MACH_IS_MAC) 
+		return;
+
+	for(i=0;i<booms;i++)
+		mac_boom_boom();
+	while(1);
+}
+
+
+#if 0
+/*
+ * TODO: serial debug code
+ */
+
+/* Flag that serial port is already initialized and used */
+int mac_SCC_init_done = 0;
+/* Can be set somewhere, if a SCC master reset has already be done and should
+ * not be repeated; used by kgdb */
+int mac_SCC_reset_done = 0;
+
+static struct console mac_console_driver = {
+	"debug",
+	NULL,			/* write */
+	NULL,			/* read */
+	NULL,			/* device */
+	NULL,			/* wait_key */
+	NULL,			/* unblank */
+	NULL,			/* setup */
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+static int scc_port;
+
+static inline void mac_scc_out (char c)
+{
+    do {
+	MFPDELAY();
+    } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+    MFPDELAY();
+    scc.cha_b_data = c;
+}
+
+void mac_scc_console_write (struct console *co, const char *str,
+			      unsigned int count)
+{
+    while (count--) {
+	if (*str == '\n')
+	    mac_scc_out( '\r' );
+	mac_scc_out( *str++ );
+    }
+}
+
+#ifdef CONFIG_SERIAL_CONSOLE
+int mac_scc_console_wait_key(struct console *co)
+{
+    do {
+	MFPDELAY();
+    } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
+    MFPDELAY();
+    return( scc.cha_b_data );
+}
+#endif
+
+/* The following two functions do a quick'n'dirty initialization of the MFP or
+ * SCC serial ports. They're used by the debugging interface, kgdb, and the
+ * serial console code. */
+#define SCC_WRITE(reg,val)				\
+    do {						\
+	scc.cha_b_ctrl = (reg);				\
+	MFPDELAY();					\
+	scc.cha_b_ctrl = (val);				\
+	MFPDELAY();					\
+    } while(0)
+
+/* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a
+ * delay of ~ 60us. */
+#define LONG_DELAY()				\
+    do {					\
+	int i;					\
+	for( i = 100; i > 0; --i )		\
+	    MFPDELAY();				\
+    } while(0)
+    
+#ifndef CONFIG_SERIAL_CONSOLE
+__initfunc(static void mac_init_scc_port( int cflag, int port ))
+#else
+void mac_init_scc_port( int cflag, int port )
+#endif
+{
+    extern int mac_SCC_reset_done;
+    static int clksrc_table[9] =
+	/* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
+    	{ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
+    static int brgsrc_table[9] =
+	/* reg 14: 0 = RTxC, 2 = PCLK */
+    	{ 2, 2, 2, 2, 2, 2, 0, 2, 2 };
+    static int clkmode_table[9] =
+	/* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
+    	{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
+    static int div_table[9] =
+	/* reg12 (BRG low) */
+    	{ 208, 138, 103, 50, 24, 11, 1, 0, 0 };
+
+    int baud = cflag & CBAUD;
+    int clksrc, clkmode, div, reg3, reg5;
+    
+    if (cflag & CBAUDEX)
+	baud += B38400;
+    if (baud < B1200 || baud > B38400+2)
+	baud = B9600; /* use default 9600bps for non-implemented rates */
+    baud -= B1200; /* tables starts at 1200bps */
+
+    clksrc  = clksrc_table[baud];
+    clkmode = clkmode_table[baud];
+    div     = div_table[baud];
+
+    reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
+    reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
+    
+    (void)scc.cha_b_ctrl;	/* reset reg pointer */
+    SCC_WRITE( 9, 0xc0 );	/* reset */
+    LONG_DELAY();		/* extra delay after WR9 access */
+    SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+		  0x04 /* 1 stopbit */ |
+		  clkmode );
+    SCC_WRITE( 3, reg3 );
+    SCC_WRITE( 5, reg5 );
+    SCC_WRITE( 9, 0 );		/* no interrupts */
+    LONG_DELAY();		/* extra delay after WR9 access */
+    SCC_WRITE( 10, 0 );		/* NRZ mode */
+    SCC_WRITE( 11, clksrc );	/* main clock source */
+    SCC_WRITE( 12, div );	/* BRG value */
+    SCC_WRITE( 13, 0 );		/* BRG high byte */
+    SCC_WRITE( 14, brgsrc_table[baud] );
+    SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+    SCC_WRITE( 3, reg3 | 1 );
+    SCC_WRITE( 5, reg5 | 8 );
+    
+    mac_SCC_reset_done = 1;
+    mac_SCC_init_done = 1;
+}
+
+
+__initfunc(void mac_debug_init(void))
+{
+#ifdef CONFIG_KGDB
+    /* the m68k_debug_device is used by the GDB stub, do nothing here */
+    return;
+#endif
+    if (!strcmp( m68k_debug_device, "ser" )) {
+	strcpy( m68k_debug_device, "ser1" );
+    }
+    if (!strcmp( m68k_debug_device, "ser1" )) {
+	/* ST-MFP Modem1 serial port */
+	mac_init_scc_port( B9600|CS8, 0 );
+	mac_console_driver.write = mac_scc_console_write;
+    }
+    else if (!strcmp( m68k_debug_device, "ser2" )) {
+	/* SCC Modem2 serial port */
+	mac_init_scc_port( B9600|CS8, 1 );
+	mac_console_driver.write = mac_scc_console_write;
+    }
+    if (mac_console_driver.write)
+	register_console(&mac_console_driver);
+}
+#endif
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/ksyms.c linux/arch/m68k/mac/ksyms.c
--- v2.1.86/linux/arch/m68k/mac/ksyms.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/ksyms.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,7 @@
+#include <linux/module.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+/* Hook for mouse driver */
+extern void (*mac_mouse_interrupt_hook) (char *);
+
+EXPORT_SYMBOL(mac_mouse_interrupt_hook);
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/macboing.c linux/arch/m68k/mac/macboing.c
--- v2.1.86/linux/arch/m68k/mac/macboing.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/macboing.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,92 @@
+/*
+ *	Mac bong noise generator. Note - we ought to put a boingy noise
+ *	here 8)
+ */
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#include <asm/macintosh.h>
+#include <asm/mac_asc.h>
+
+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]))
+
+static void nosound( unsigned long ignored );
+static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
+
+static volatile unsigned char *asc_base=(void *)0x50F14000;
+
+
+void mac_mksound( unsigned int hz, unsigned int ticks )
+{
+	static int inited = 0;
+	unsigned long flags;
+	int samples=512;
+
+	if(!inited)
+	{
+		int i=0;
+		int j=0;
+		int k=0;
+		int l=0;
+		for(i=0;i<samples;i++)
+		{
+			asc_base[i]=sine_data[j];
+			asc_base[i+512]=sine_data[j];
+			asc_base[i+1024]=sine_data[j];
+			asc_base[i+1536]=sine_data[j];
+			j++;
+			if(j==DATA_SIZE)
+				j=0;
+			if(i&1)
+				k++;
+			if(k==DATA_SIZE)
+				k=0;
+			if((i&3)==3)
+				l++;
+			if(l==DATA_SIZE)
+				l=0;	
+		}
+		inited=1;
+	}
+	save_flags(flags);
+	cli();
+	del_timer( &sound_timer );
+
+	if (hz > 20 && hz < 32767) {
+		int i;
+		u_long asc_pulses=((hz<<5)*samples)/468;
+		for(i=0;i<4;i++)
+		{
+			asc_base[ASC_FREQ(i,0)]=0x00;
+			asc_base[ASC_FREQ(i,1)]=20;
+			asc_base[ASC_FREQ(i,2)]=0x00;
+			asc_base[ASC_FREQ(i,3)]=20;
+			asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF;
+			asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF;
+			asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF;
+			asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF;
+		}
+		asc_base[ASC_CHAN]=0x03;
+		asc_base[ASC_VOLUME]=128;
+		asc_base[ASC_MODE]=ASC_MODE_SAMPLE;
+		asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE;
+		if (ticks) {
+			sound_timer.expires = jiffies + ticks;
+			add_timer( &sound_timer );
+		}
+	} else {
+		nosound( 0 );
+	}
+	restore_flags(flags);
+}
+
+
+static void nosound( unsigned long ignored )
+{
+	asc_base[ASC_ENABLE]=0;
+}	
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c
--- v2.1.86/linux/arch/m68k/mac/macints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/macints.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,979 @@
+/*
+ *	Macintosh interrupts
+ *
+ * General design:
+ * In contrary to the Amiga and Atari platforms, the Mac hardware seems to 
+ * exclusively use the autovector interrupts (the 'generic level0-level7' 
+ * interrupts with exception vectors 0x19-0x1f). The following interrupt levels
+ * are used:
+ *	1	- VIA1
+ *		  - slot 0: one second interrupt
+ *		  - slot 1: VBlank
+ *		  - slot 2: ADB data ready (SR full)
+ *		  - slot 3: ADB data  (CB2)
+ *		  - slot 4: ADB clock (CB1)
+ *		  - slot 5: timer 2
+ *		  - slot 6: timer 1
+ *		  - slot 7: status of IRQ; signals 'any enabled int.'
+ *
+ *	2	- VIA2, RBV or OSS
+ *		  - slot 0: SCSI DRQ
+ *		  - slot 1: NUBUS IRQ
+ *		  - slot 3: SCSI IRQ
+ *
+ *	4	- SCC
+ *		  - subdivided into Channel B and Channel A interrupts 
+ *
+ *	6	- Off switch (??)
+ *
+ *	7	- Debug output
+ *
+ * Using the autovector irq numbers for Linux/m68k hardware interrupts without
+ * the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt 
+ * handling in kernel versions 2.0.x, so the following strategy is used:
+ *
+ * - mac_init_IRQ installs the low-level entry points for the via1 and via2 
+ *   exception vectors and the corresponding handlers (C functions); these 
+ *   entry points just add the machspec bit and call the handlers proper.
+ *   (in principle, the C functions can be installed as the exception vectors 
+ *   directly, as they are hardcoded anyway; that's the current method). 
+ *
+ * - via[12]_irq determine what interrupt sources have triggered the interrupt,
+ *   and call the corresponding device interrupt handlers. 
+ *   (currently, via1_irq and via2_irq just call via_irq, passing the via base
+ *   address. RBV interrupts are handled by (you guessed it) rbv_irq).
+ *   Some interrupt functions want to have the interrupt number passed, so 
+ *   via_irq and rbv_irq need to generate the 'fake' numbers from scratch.
+ *
+ * - for the request/free/enable/disable business, interrupt sources are 
+ *   numbered internally (suggestion: keep irq 0-7 unused :-). One bit in the 
+ *   irq number specifies the via# to use, i.e. via1 interrupts are 8-16, 
+ *   via2 interrupts 17-32, rbv interrupts ...
+ *   The device interrupt table and the irq_enable bitmap is maintained by 
+ *   the machspec interrupt code; all device drivers should only use these 
+ *   functions ! 
+ *
+ * - For future porting to version 2.1 (and removing of the machspec bit) it 
+ *   should be sufficient to use the same numbers (everything > 7 is assumed 
+ *   to be machspec, according to Jes!).
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h> /* for intr_count */
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include "via6522.h"
+
+#include <asm/macints.h>
+
+/*
+ * Interrupt handler and parameter types
+ */
+struct irqhandler {
+	void	(*handler)(int, void *, struct pt_regs *);
+	void	*dev_id;
+};
+
+struct irqparam {
+	unsigned long	flags;
+	const char	*devname;
+};
+
+struct irqflags {
+        unsigned int disabled;
+	unsigned int pending;
+};
+
+/*
+ * Array with irq's and their parameter data. 
+ */
+static struct irqhandler  via1_handler[8];
+static struct irqhandler  via2_handler[8];
+static struct irqhandler   rbv_handler[8];
+static struct irqhandler   scc_handler[8];
+static struct irqhandler nubus_handler[8];
+
+static struct irqhandler *handler_table[8];
+
+/*
+ * 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  via1_param[8];
+static struct irqparam  via2_param[8];
+static struct irqparam   rbv_param[8];
+static struct irqparam   scc_param[8];
+static struct irqparam nubus_param[8];
+
+static struct irqparam *param_table[8];
+
+/*
+ * This array holds the 'disabled' and 'pending' software flags maintained
+ * by mac_{enable,disable}_irq and the generic via_irq function.
+ */
+
+static struct irqflags irq_flags[8];
+
+/*
+ * This array holds the pointers to the various VIA or other interrupt 
+ * controllers
+ */
+
+static volatile unsigned char *via_table[8];
+
+#ifdef VIABASE_WEIRDNESS
+/*
+ * VIA2 / RBV default base address 
+ */
+
+volatile unsigned char *via2_regp = ((volatile unsigned char *)VIA2_BAS);
+volatile unsigned char *rbv_regp  = ((volatile unsigned char *)VIA2_BAS_IIci);
+#endif
+
+/*
+ * Flags to control via2 / rbv behaviour
+ */ 
+
+static int via2_is_rbv = 0;
+static int rbv_clear = 0;
+
+/*
+ * console_loglevel determines NMI handler function
+ */
+
+extern int console_loglevel;
+
+/*
+ * ADB test hooks
+ */
+extern int in_keybinit;
+void adb_queue_poll(void);
+
+/* Defined in entry.S; only increments 'num_spurious' */
+asmlinkage void bad_interrupt(void);
+
+void nubus_wtf(int slot, void *via, struct pt_regs *regs);
+
+void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *regs);
+void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs);
+
+static void via_do_nubus(int slot, void *via, struct pt_regs *regs);
+
+/*#define DEBUG_VIA*/
+
+void mac_init_IRQ(void)
+{
+        int i;
+
+	mac_debugging_penguin(6);
+
+#ifdef DEBUG_MACINTS
+	printk("Mac interrupt stuff initializing ...\n");
+#endif
+        /* initialize the hardwired (primary, autovector) IRQs */
+
+	/* level 1 IRQ: VIA1, always present */
+	sys_request_irq(1, via1_irq, IRQ_FLG_LOCK, "via1", via1_irq);
+
+	/* via2 or rbv?? */
+	if (macintosh_config->via_type == MAC_VIA_IIci) {
+		/* VIA2 is part of the RBV: different base, other offsets */
+		via2_is_rbv = 1;
+		/* LC III weirdness: IFR seems to behave like VIA2 */
+		/* FIXME: maybe also for LC II ?? */ 
+		if (macintosh_config->ident == MAC_MODEL_LCIII) {
+			rbv_clear = 0x0;
+		} else {
+			rbv_clear = 0x80;
+		}
+		/* level 2 IRQ: RBV/OSS; we only care about RBV for now */
+		sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
+	} else
+		/* level 2 IRQ: VIA2 */
+		sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq);
+
+	/* 
+	 * level 4 IRQ: SCC - use 'master' interrupt routine that calls the 
+	 *		registered channel-specific interrupts in turn.
+	 *		Currently, one interrupt per channel is used, solely
+	 *		to pass the correct async_info as parameter!
+	 */
+#if 0	/* doesn't seem to work yet */
+	sys_request_irq(4, mac_SCC_handler, IRQ_FLG_STD, "INT4", mac_SCC_handler);
+#else
+	sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler);
+#endif
+	/* Alan uses IRQ 5 for SCC ?? */
+	sys_request_irq(5, mac_debug_handler, IRQ_FLG_STD, "INT5", mac_debug_handler);
+
+	/* level 6 */
+	sys_request_irq(6, mac_bang, IRQ_FLG_LOCK, "offswitch", mac_bang);
+
+	/* level 7 (or NMI) : debug stuff */
+	sys_request_irq(7, mac_nmi_handler, IRQ_FLG_STD, "NMI", mac_nmi_handler);
+
+	/* initialize the handler tables for VIAs */
+	for (i = 0; i < 8; i++) {
+		 via1_handler[i].handler = mac_default_handler;
+		 via1_handler[i].dev_id  = NULL;
+		 via1_param[i].flags     = IRQ_FLG_STD;
+		 via1_param[i].devname   = NULL;
+
+		 via2_handler[i].handler = mac_default_handler;
+		 via2_handler[i].dev_id  = NULL;
+		 via2_param[i].flags     = IRQ_FLG_STD;
+		 via2_param[i].devname   = NULL;
+
+		  rbv_handler[i].handler = mac_default_handler;
+		  rbv_handler[i].dev_id  = NULL;
+		  rbv_param[i].flags     = IRQ_FLG_STD;
+		  rbv_param[i].devname   = NULL;
+
+		  scc_handler[i].handler = mac_default_handler;
+		  scc_handler[i].dev_id  = NULL;
+		  scc_param[i].flags     = IRQ_FLG_STD;
+		  scc_param[i].devname   = NULL;
+
+		/* NUBUS interrupts routed through VIA2 slot 2 - special */
+		nubus_handler[i].handler = nubus_wtf;
+		nubus_handler[i].dev_id  = NULL;
+		nubus_param[i].flags     = IRQ_FLG_STD;
+		nubus_param[i].devname   = NULL;
+
+	}
+
+	/* initialize the handler tables (level 1 -> via_handler[0] !!!) */
+	via_table[0]     =  via1_regp;
+	handler_table[0] =  &via1_handler[0];
+	param_table[0]   =  &via1_param[0];
+
+	if (via2_is_rbv) {
+		via_table[1]     =  rbv_regp;
+		handler_table[1] =  &rbv_handler[0];
+		param_table[1]   =  &rbv_param[0];
+	} else {
+		via_table[1]     =  via2_regp;
+		handler_table[1] =  &via2_handler[0];
+		param_table[1]   =  &via2_param[0];
+	}
+	via_table[2]     =  NULL;
+	via_table[3]     =  NULL;
+	
+	handler_table[2] =   &rbv_handler[0];
+	handler_table[3] = &nubus_handler[0];
+
+	param_table[2]   =   &rbv_param[0];
+	param_table[3]   = &nubus_param[0];
+
+	mac_debugging_penguin(7);
+#ifdef DEBUG_MACINTS
+	printk("Mac interrupt init done!\n");
+#endif
+}
+
+/*
+ *	We have no machine specific interrupts on a macintoy
+ *      Yet, we need to register/unregister interrupts ... :-)
+ *      Currently unimplemented: Test for valid irq number, chained irqs,
+ *      Nubus interrupts.
+ */
+ 
+int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                              unsigned long flags, const char *devname, void *dev_id)
+{
+	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+	int irqidx =  (irq & IRQ_IDX_MASK);
+	struct irqhandler *via_handler;
+	struct irqparam   *via_param;
+	volatile unsigned char *via;
+
+#ifdef DEBUG_MACINTS
+	printk ("%s: IRQ %d on VIA%d[%d] requested from %s\n",
+	        __FUNCTION__, irq, srcidx+1, irqidx, devname);
+#endif
+
+	if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
+		printk ("%s: Bad irq type %ld requested from %s\n",
+		        __FUNCTION__, flags, devname);
+		return -EINVAL;
+	}
+
+	/* figure out what VIA is handling this irq */
+        if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) {
+		/* non-via irqs unimplemented */
+		printk ("%s: Bad irq source %d on VIA %d requested from %s\n",
+		        __FUNCTION__, irq, srcidx, devname);
+		return -EINVAL;
+	} 
+
+	/* figure out if SCC pseudo-irq */
+        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+		/* set specific SCC handler */
+		scc_handler[irqidx].handler = handler;
+		scc_handler[irqidx].dev_id  = dev_id;
+		scc_param[irqidx].flags     = flags;
+		scc_param[irqidx].devname   = devname;
+		/* and done! */
+		return 0;
+	} 
+
+	via         = (volatile unsigned char *) via_table[srcidx];
+	if (!via) 
+		return -EINVAL;
+
+	via_handler = handler_table[srcidx];
+	via_param   = param_table[srcidx];
+
+	/* check for conflicts or possible replacement */
+
+	/* set the handler - no chained irqs yet !! */
+	via_handler[irqidx].handler = handler;
+	via_handler[irqidx].dev_id  = dev_id;
+	via_param[irqidx].flags     = flags;
+	via_param[irqidx].devname   = devname;
+
+	/* and turn it on ... */
+	if (srcidx == SRC_VIA2 && via2_is_rbv)
+		via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+	else
+		via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
+
+
+	if (irq == IRQ_IDX(IRQ_MAC_SCSI)) {
+		/*
+		 * Set vPCR for SCSI interrupts. (what about RBV here?)
+		 */
+		via_write(via, vPCR, 0x66);
+	}
+
+	return 0;
+}
+                            
+void mac_free_irq (unsigned int irq, void *dev_id)
+{
+	unsigned long flags;
+	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+	int irqidx =  (irq & IRQ_IDX_MASK);
+	struct irqhandler *via_handler;
+	struct irqparam   *via_param;
+	volatile unsigned char *via;
+
+#ifdef DEBUG_MACINTS
+	printk ("%s: IRQ %d on VIA%d[%d] freed\n",
+	        __FUNCTION__, irq, srcidx+1, irqidx);
+#endif
+
+	/* figure out what VIA is handling this irq */
+	if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) {
+		/* non-via irqs unimplemented */
+		return;
+	} 
+
+	save_flags(flags);
+	cli();
+
+	/* figure out if SCC pseudo-irq */
+        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) {
+		/* clear specific SCC handler */
+		scc_handler[irqidx].handler = mac_default_handler;
+		scc_handler[irqidx].dev_id  = NULL;
+		scc_param[irqidx].flags     = IRQ_FLG_STD;
+		scc_param[irqidx].devname   = NULL;
+		/* and done! */
+		restore_flags(flags);
+		return;
+	} 
+
+	via         = (volatile unsigned char *) via_table[srcidx];
+	via_handler = handler_table[srcidx];
+	via_param   = param_table[srcidx];
+
+	if ( !via || (via_handler[irqidx].dev_id != dev_id) ) {
+		restore_flags(flags);
+		goto not_found;
+	}
+
+	/* clear the handler - no chained irqs yet !! */
+	via_handler[irqidx].handler = mac_default_handler;
+	via_handler[irqidx].dev_id  = NULL;
+	via_param[irqidx].flags     = IRQ_FLG_STD;
+	via_param[irqidx].devname   = NULL;
+
+	/* and turn it off */
+	if (srcidx == SRC_VIA2 && via2_is_rbv)
+		via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+	else
+		via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
+
+	restore_flags(flags);
+	return;
+
+not_found:
+	printk("%s: tried to remove invalid irq\n", __FUNCTION__);
+	return;
+
+}
+
+/*
+ * {en,dis}able_irq have the usual semantics of temporary blocking the
+ * interrupt, but not loosing requests that happen between disabling and
+ * enabling. On Atari, this is done with the MFP mask registers.
+ *
+ * On the Mac, this isn't possible: there is no VIA mask register. 
+ * Needs to be implemented in software, setting 'mask' bits in a separate
+ * struct for each interrupt controller. These mask bits need to be checked
+ * by the VIA interrupt routine which should ignore requests for masked IRQs 
+ * (after possibly ack'ing them).
+ *
+ * On second thought: some of the IRQ sources _can_ be turned off via bits
+ * in the VIA output registers. Need to check this ...
+ *
+ * TBI: According to the VIA docs, clearing a bit in the IER has the effect of 
+ * blocking generation of the interrupt, but the internal interrupt condition 
+ * is preserved. So the IER might be used as mask register here, and turnon_irq
+ * would need to clear the interrupt bit in the IFR to prevent getting an 
+ * interrupt at all.
+ *
+ * Implementation note: the irq no's here are the _machspec_ irqs, hence the 
+ * hack with srcidx to figure out which VIA/RBV handles the interrupt. 
+ * That's fundamentally different when it comes to the interrupt handlers 
+ * proper: these get the interrupt level no. as argument, all information about
+ * which source triggered the int. is buried in the VIA IFR ... The int. level 
+ * points us to the proper handler, so we could do a sanity check there ...
+ */
+
+void mac_enable_irq (unsigned int irq)
+{
+        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+        int irqidx = (irq & IRQ_IDX_MASK);
+
+	irq_flags[srcidx].disabled &= ~(1<<irqidx);
+	/*
+	 * Call handler here if irq_flags[srcidx].pending & 1<<irqidx ?? 
+	 * The structure of via_irq prevents this, sort of: it warns if
+	 * no true events are pending. Maybe that's being changed ...
+	 * Other problem: is it always possible to call an interrupt handler, 
+	 * or should that depend on the current interrupt level?
+	 */
+}
+
+void mac_disable_irq (unsigned int irq)
+{
+        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+        int irqidx = (irq & IRQ_IDX_MASK);
+
+	irq_flags[srcidx].disabled |= (1<<irqidx);
+}
+
+/*
+ * In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not
+ * "stored". This is done with the VIA interrupt enable register
+ */
+
+void mac_turnon_irq( unsigned int irq )
+{
+        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+        int irqidx = (irq & IRQ_IDX_MASK);
+	volatile unsigned char *via;
+
+	via         = (volatile unsigned char *) via_table[srcidx];
+	if (!via) 
+		return;
+
+	if (srcidx == SRC_VIA2 && via2_is_rbv)
+	        via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
+	else
+	        via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
+
+}
+
+void mac_turnoff_irq( unsigned int irq )
+{
+        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+        int irqidx = (irq & IRQ_IDX_MASK);
+	volatile unsigned char *via;
+
+	via         = (volatile unsigned char *) via_table[srcidx];
+	if (!via) 
+		return;
+
+	if (srcidx == SRC_VIA2 && via2_is_rbv)
+		via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
+	else
+		via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
+}
+
+/*
+ * These functions currently only handle the software-maintained irq pending
+ * list for disabled irqs - manipulating the actual irq flags in the via would
+ * require clearing single bits in the via, such as (probably) 
+ * via_write(via, vIFR, (via_read(via, vIFR)&(1<<irqidx))); - don't know if 
+ * this has side-effects ...
+ */
+
+void mac_clear_pending_irq( unsigned int irq )
+{
+        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+        int irqidx = (irq & IRQ_IDX_MASK);
+
+	irq_flags[srcidx].pending &= ~(1<<irqidx);
+}
+
+int  mac_irq_pending( unsigned int irq )
+{
+        int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
+        int irqidx = (irq & IRQ_IDX_MASK);
+
+	return (irq_flags[srcidx].pending & (1<<irqidx));
+}
+
+int mac_get_irq_list (char *buf)
+{
+	return 0;
+}
+
+void via_scsi_clear(void)
+{
+	volatile unsigned char deep_magic;
+	if (via2_is_rbv) {
+		via_write(rbv_regp, rIFR, (1<<3)|(1<<0)|0x80);
+		deep_magic = via_read(rbv_regp, rBufB);
+	} else
+		deep_magic = via_read(via2_regp, vBufB);
+	mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) );
+}
+
+
+void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+#ifdef DEBUG_VIA
+	printk("Unexpected IRQ %d\n", irq);
+#endif
+}
+
+static int num_debug[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (num_debug[irq] < 10) {
+		printk("DEBUG: Unexpected IRQ %d\n", irq);
+		num_debug[irq]++;
+	}
+}
+
+void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
+{
+	/* 
+	 * generate debug output on NMI switch if 'debug' kernel option given
+	 * (only works with Penguin!)
+	 */
+	if ( console_loglevel >= 8 ) {
+#if 0
+		show_state();
+		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);
+		if (intr_count == 1)
+			dump_stack((struct frame *)fp);
+#else
+		/* printk("NMI "); */
+#endif
+	}
+}
+
+/*
+ * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
+ * via6522.c :-), disable/pending masks added.
+ * The int *viaidx etc. is just to keep the prototype happy ...
+ */
+
+static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs)
+{
+	unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
+	int i;
+	int ct = 0;
+	struct irqhandler *via_handler = handler_table[*viaidx];
+	struct irqparam   *via_param   = param_table[*viaidx];
+
+	/* to be changed, possibly: for each non'masked', enabled IRQ, read 
+	 * flag bit, ack and call handler ...
+         * Currently: all pending irqs ack'ed en bloc.
+	 * If ack for masked IRQ required: keep 'pending' info separate.
+	 */
+
+        /* shouldn't we disable interrupts here ?? */
+
+	
+	/*
+	 *	Shouldnt happen
+	 */
+	 
+	if(events==0)
+	{
+		printk("via_irq: nothing pending!\n");
+		return;
+	}
+
+#ifdef DEBUG_VIA	
+	/*
+	 * limited verbosity for VIA interrupts
+	 */
+#if 0
+	if ( (*viaidx == 0 && events != 1<<6) 		/* timer int */
+	  || (*viaidx == 1 && events != 1<<3) )		/* SCSI IRQ */
+#else
+	if ( *viaidx == 0 && (events & 1<<2) ) 
+#endif
+		printk("via_irq: irq %d events %x !\n", (*viaidx)+1, events);
+#endif
+
+	do {
+		/*
+		 *	Clear the pending flag
+		 */
+		 
+		via_write(via, vIFR, events);
+		 
+		/*
+		 *	Now see what bits are raised
+		 */
+		 
+		for(i=0;i<7;i++)
+		{
+			/* determine machspec. irq no. */
+			int irq = ((*viaidx)+1)* 8 + i;
+		        /* call corresponding handlers */
+		        if (events&(1<<i)) {
+			        if (irq_flags[*viaidx].disabled & (1<<i)) {
+				        /* irq disabled -> mark pending */
+				        irq_flags[*viaidx].pending |= (1<<i);
+				} else {
+				        /* irq enabled -> call handler */
+				        (via_handler[i].handler)(irq, via, regs);
+				}
+			}
+			/* and call handlers for pending irqs - first ?? */
+			if (    (irq_flags[*viaidx].pending  & (1<<i))
+			    && !(irq_flags[*viaidx].disabled & (1<<i)) ) {
+				/* call handler for re-enabled irq */
+			        (via_handler[i].handler)(irq, via, regs);
+				/* and clear pending flag :-) */
+				irq_flags[*viaidx].pending  &= ~(1<<i);
+			}
+		}
+	
+		/*
+		 *	And done ... check for more punishment!
+		 */
+
+		events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
+		ct++;
+		if(events && ct>8)
+		{
+		        printk("via%d: stuck events %x\n", (*viaidx)+1, events);
+		        break;
+		}
+	}
+	while(events);
+#if 0
+	scsi_mac_polled();
+#endif
+}
+
+/*
+ * Caution: the following stuff is called from process_int as _autovector_ 
+ * system interrupts. So irq is always in the range 0-7 :-( and the selection
+ * of the appropriate VIA is up to the irq handler here based on the autovec 
+ * irq number. There's no information whatsoever about which source on the VIA
+ * triggered the int - and that's what the machspec irq no's are about. 
+ * Broken design :-((((
+ */
+
+/*
+ *	System interrupts
+ */
+
+void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int srcidx = IRQ_IDX(irq) - 1;
+	via_irq((unsigned char *)via1_regp, &srcidx, regs);
+}
+
+
+/*
+ *	Nubus / SCSI interrupts, VIA style (could be wrapped into via1_irq or
+ *	via_irq directly by selecting the regp based on the irq!)
+ */
+ 
+void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int srcidx = IRQ_IDX(irq) - 1;
+	via_irq((unsigned char *)via2_regp, &srcidx, regs);
+}
+
+/*
+ *	Nubus / SCSI interrupts; RBV style
+ *	The RBV is different. RBV appears to stand for randomly broken
+ *	VIA (or even real broken VIA).
+ */
+ 
+void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int srcidx = IRQ_IDX(irq) - 1;	/* MUST be 1 !! */
+	volatile unsigned char *via = rbv_regp;
+	unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
+	int i;
+	int ct = 0;
+	struct irqhandler *via_handler = handler_table[srcidx];
+	struct irqparam   *via_param   = param_table[srcidx];
+
+#ifdef DEBUG_VIA	
+	/*
+	 * limited verbosity for RBV interrupts (add more if needed)
+	 */
+	if ( srcidx == 1 && events != 1<<3 )		/* SCSI IRQ */
+		printk("rbv_irq: irq %d (%d) events %x !\n", irq, srcidx+1, events);
+#endif
+
+	/* to be changed, possibly: for each non'masked', enabled IRQ, read 
+	 * flag bit, ack and call handler ...
+         * Currently: all pending irqs ack'ed en bloc.
+	 * If ack for masked IRQ required: keep 'pending' info separate.
+	 */
+
+        /* shouldn't we disable interrupts here ?? */
+
+	
+	/*
+	 *	Shouldnt happen
+	 */
+	 
+	if(events==0)
+	{
+		printk("rbv_irq: nothing pending!\n");
+		return;
+	}
+	
+	do {
+		/*
+		 *	Clear the pending flag
+		 */
+		 
+		via_write(via, rIFR, events | rbv_clear);
+		 
+		/*
+		 *	Now see what bits are raised
+		 */
+		 
+		for(i=0;i<7;i++)
+		{
+			/* determine machspec. irq no. */
+			int irq = (srcidx+1)* 8 + i;
+		        /* call corresponding handlers */
+		        if (events&(1<<i)) {
+			        if (irq_flags[srcidx].disabled & (1<<i))
+				        /* irq disabled -> mark pending */
+				        irq_flags[srcidx].pending |= (1<<i);
+				else
+				        /* irq enabled -> call handler */
+				        (via_handler[i].handler)(irq, via, regs);
+			}
+			/* and call handlers for pending irqs - first ?? */
+			if (    (irq_flags[srcidx].pending  & (1<<i))
+			    && !(irq_flags[srcidx].disabled & (1<<i)) ) {
+				/* call handler for re-enabled irq */
+			        (via_handler[i].handler)(irq, via, regs);
+				/* and clear pending flag :-) */
+				irq_flags[srcidx].pending  &= ~(1<<i);
+			}
+		}
+	
+		/*
+		 *	And done ... check for more punishment!
+		 */
+
+		events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
+		ct++;
+		if(events && ct>8)
+		{
+		        printk("rbv: stuck events %x\n",events);
+			for(i=0;i<7;i++)
+			{
+				if(events&(1<<i))
+				{
+					printk("rbv - bashing source %d\n",
+						i);
+					via_write(via, rIER, 1<<i);
+					via_write(via, rIFR, (1<<i) | rbv_clear);
+				}
+			}
+		        break;
+		}
+	}
+	while(events);
+#if 0
+	scsi_mac_polled();
+#endif
+}
+
+/*
+ *	Unexpected via interrupt
+ */
+ 
+void via_wtf(int slot, void *via, struct pt_regs *regs)
+{
+#ifdef DEBUG_VIA
+	printk("Unexpected event %d on via %p\n",slot,via);
+#endif
+}
+
+void nubus_wtf(int slot, void *via, struct pt_regs *regs)
+{
+#ifdef DEBUG_VIA
+	printk("Unexpected interrupt on nubus slot %d\n",slot);
+#endif
+}
+
+void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) 
+		if (scc_handler[i].handler != mac_default_handler)
+			(scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
+
+}
+
+/*
+ *	Nubus handling
+ *      Caution: slot numbers are currently 'hardcoded' to the range 9-15!
+ *      In general, the same request_irq() functions as above can be used if
+ *      the interrupt numbers specifed in macints.h are used.
+ */
+ 
+static int nubus_active=0;
+ 
+int nubus_request_irq(int slot, void (*handler)(int,void *,struct pt_regs *))
+{
+	slot-=9;
+/*	printk("Nubus request irq for slot %d\n",slot);*/
+	if(nubus_handler[slot].handler!=nubus_wtf)
+		return -EBUSY;
+	nubus_handler[slot].handler=handler;
+	nubus_handler[slot].dev_id =handler;
+	nubus_param[slot].flags    = IRQ_FLG_LOCK;
+	nubus_param[slot].devname  = "nubus";
+
+	/* 
+	 * if no nubus int. was active previously: register the main nubus irq
+	 * handler now!
+	 */
+
+	if (!nubus_active)
+	  request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK, 
+		      "nubus dispatch", via_do_nubus);
+
+	nubus_active|=1<<slot;
+/*	printk("program slot %d\n",slot);*/
+/*	printk("via2=%p\n",via2);*/
+#if 0
+	via_write(via2, vDirA, 
+		via_read(via2, vDirA)|(1<<slot));
+	via_write(via2, vBufA, 0);
+#endif		
+	if (!via2_is_rbv) {
+		/* Make sure the bit is an input */
+		via_write(via2_regp, vDirA, 
+			via_read(via2_regp, vDirA)&~(1<<slot));
+	}
+/*	printk("nubus irq on\n");*/
+	return 0;
+}
+
+int nubus_free_irq(int slot)
+{
+	slot-=9;
+	nubus_active&=~(1<<slot);
+	nubus_handler[slot].handler=nubus_wtf;
+	nubus_handler[slot].dev_id = NULL;
+	nubus_param[slot].flags    = IRQ_FLG_STD;
+	nubus_param[slot].devname  = NULL;
+
+	if (via2_is_rbv)
+		via_write(rbv_regp, rBufA, 1<<slot);
+	else {
+		via_write(via2_regp, vDirA, 
+			via_read(via2_regp, vDirA)|(1<<slot));
+		via_write(via2_regp, vBufA, 1<<slot);
+		via_write(via2_regp, vDirA, 
+			via_read(via2_regp, vDirA)&~(1<<slot));
+	}
+	return 0;
+}
+
+static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
+{
+	unsigned char map;
+	int i;
+	int ct=0;
+
+/*	printk("nubus interrupt\n");*/
+		
+	/* lock the nubus interrupt */
+	if (via2_is_rbv) 
+		via_write(rbv_regp, rIFR, 0x82);
+	else
+		via_write(via2_regp, vIFR, 0x82);
+	
+	while(1)
+	{
+		if (via2_is_rbv)
+			map = ~via_read(rbv_regp, rBufA);
+		else
+			map = ~via_read(via2_regp, vBufA);
+		
+#ifdef DEBUG_VIA
+		printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#endif
+		if( (map = (map&nubus_active)) ==0 )
+			break;
+
+		if(ct++>2)
+		{
+			printk("nubus stuck events - %d/%d\n", map, nubus_active);
+			return;
+		}
+
+		for(i=0;i<7;i++)
+		{
+			if(map&(1<<i))
+			{
+				(nubus_handler[i].handler)(i+9, via, regs);
+			}
+		}
+		/* clear it */
+		if (via2_is_rbv)
+			via_write(rbv_regp, rIFR, 0x02);
+		else
+			via_write(via2_regp, vIFR, 0x02);
+
+	}
+	
+	/* And done */
+}
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/mackeyb.c linux/arch/m68k/mac/mackeyb.c
--- v2.1.86/linux/arch/m68k/mac/mackeyb.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/mackeyb.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,766 @@
+/*
+ *  linux/arch/m68k/mac/mackeyb.c
+ *
+ * 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.
+ */
+
+/*
+ * misc. keyboard stuff (everything not in adb-bus.c or keyb_m68k.c)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+/* keyb */
+#include <linux/keyboard.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+/* keyb */
+
+#include <asm/setup.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+/* for keyboard_input stuff */
+#include <asm/adb.h>
+#define KEYB_KEYREG	0	/* register # for key up/down data */
+#define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
+#define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
+/* end keyboard_input stuff */
+
+#include <asm/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_ll.h>
+
+static void kbd_repeat(unsigned long);
+static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
+static int last_keycode;
+
+static void input_keycode(int, int);
+
+extern struct kbd_struct kbd_table[];
+
+extern void handle_scancode(unsigned char);
+extern void put_queue(int);
+
+/* keyb */
+static void mac_leds_done(struct adb_request *);
+static void keyboard_input(unsigned char *, int, struct pt_regs *);
+static void mouse_input(unsigned char *, int, struct pt_regs *);
+/* Hook for mouse driver */
+void (*mac_mouse_interrupt_hook) (char *);
+int mac_emulate_button2;
+int mac_emulate_button3;
+/* The mouse driver - for debugging */
+extern void mac_mouse_interrupt(char *);
+/* end keyb */
+
+/* this map indicates which keys shouldn't autorepeat. */
+static unsigned char dont_repeat[128] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,	/* esc...option */
+	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */
+	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, 1, 0, 0, 0, 0, /* scroll lock */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/*
+ * Mac private key maps
+ */
+u_short mac_plain_map[NR_KEYS] = {
+	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
+	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
+	0xfb79,	0xfb74,	0xf031,	0xf032,	0xf033,	0xf034,	0xf036,	0xf035,
+	0xf03d,	0xf039,	0xf037,	0xf02d,	0xf038,	0xf030,	0xf05d,	0xfb6f,
+	0xfb75,	0xf05b,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf027,
+	0xfb6b,	0xf03b,	0xf05c,	0xf02c,	0xf02f,	0xfb6e,	0xfb6d,	0xf02e,
+	0xf009,	0xf020,	0xf060,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xfb61,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf109,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
+	0xf101,	0xf119,	0xf100,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short mac_shift_map[NR_KEYS] = {
+	0xfb41,	0xfb53,	0xfb44,	0xfb46,	0xfb48,	0xfb47,	0xfb5a,	0xfb58,
+	0xfb43,	0xfb56,	0xf200,	0xfb42,	0xfb51,	0xfb57,	0xfb45,	0xfb52,
+	0xfb59,	0xfb54,	0xf021,	0xf040,	0xf023,	0xf024,	0xf05e,	0xf025,
+	0xf02b,	0xf028,	0xf026,	0xf05f,	0xf02a,	0xf029,	0xf07d,	0xfb4f,
+	0xfb55,	0xf07b,	0xfb49,	0xfb50,	0xf201,	0xfb4c,	0xfb4a,	0xf022,
+	0xfb4b,	0xf03a,	0xf07c,	0xf03c,	0xf03f,	0xfb4e,	0xfb4d,	0xf03e,
+	0xf009,	0xf020,	0xf07e,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xfb41,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf10e,	0xf10f,	0xf110,	0xf10c,	0xf111,	0xf112,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf203,	0xf200,	0xf113,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf20b,	0xf116,	0xf10d,	0xf117,
+	0xf10b,	0xf20a,	0xf10a,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short mac_altgr_map[NR_KEYS] = {
+	0xf914,	0xfb73,	0xf917,	0xf919,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
+	0xf916,	0xfb76,	0xf200,	0xf915,	0xfb71,	0xfb77,	0xf918,	0xfb72,
+	0xfb79,	0xfb74,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
+	0xf200,	0xf05d,	0xf07b,	0xf05c,	0xf05b,	0xf07d,	0xf07e,	0xfb6f,
+	0xfb75,	0xf200,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf200,
+	0xfb6b,	0xf200,	0xf200,	0xf200,	0xf200,	0xfb6e,	0xfb6d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf90a,	0xf90b,	0xf90c,	0xf90d,	0xf90e,	0xf90f,
+	0xf910,	0xf911,	0xf914,	0xf912,	0xf913,	0xf200,	0xf200,	0xf200,
+	0xf510,	0xf511,	0xf512,	0xf50e,	0xf513,	0xf514,	0xf200,	0xf516,
+	0xf200,	0xf10c,	0xf200,	0xf202,	0xf200,	0xf515,	0xf200,	0xf517,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf50f,	0xf117,
+	0xf50d,	0xf119,	0xf50c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short mac_ctrl_map[NR_KEYS] = {
+	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
+	0xf019,	0xf014,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01e,	0xf01d,
+	0xf200,	0xf200,	0xf01f,	0xf01f,	0xf07f,	0xf200,	0xf01d,	0xf00f,
+	0xf015,	0xf01b,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf007,
+	0xf00b,	0xf200,	0xf01c,	0xf200,	0xf07f,	0xf00e,	0xf00d,	0xf20e,
+	0xf200,	0xf000,	0xf000,	0xf008,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf001,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf204,	0xf200,	0xf109,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
+	0xf101,	0xf119,	0xf100,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short mac_shift_ctrl_map[NR_KEYS] = {
+	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
+	0xf019,	0xf014,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf00f,
+	0xf015,	0xf200,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf200,
+	0xf00b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf00e,	0xf00d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf001,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf200,	0xf117,
+	0xf200,	0xf119,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf20c,
+};
+
+u_short mac_alt_map[NR_KEYS] = {
+	0xf861,	0xf873,	0xf864,	0xf866,	0xf868,	0xf867,	0xf87a,	0xf878,
+	0xf863,	0xf876,	0xf200,	0xf862,	0xf871,	0xf877,	0xf865,	0xf872,
+	0xf879,	0xf874,	0xf831,	0xf832,	0xf833,	0xf834,	0xf836,	0xf835,
+	0xf83d,	0xf839,	0xf837,	0xf82d,	0xf838,	0xf830,	0xf85d,	0xf86f,
+	0xf875,	0xf85b,	0xf869,	0xf870,	0xf80d,	0xf86c,	0xf86a,	0xf827,
+	0xf86b,	0xf83b,	0xf85c,	0xf82c,	0xf82f,	0xf86e,	0xf86d,	0xf82e,
+	0xf809,	0xf820,	0xf860,	0xf87f,	0xf200,	0xf81b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf210,	0xf211,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf900,	0xf901,	0xf902,	0xf903,	0xf904,	0xf905,
+	0xf906,	0xf907,	0xf861,	0xf908,	0xf909,	0xf200,	0xf200,	0xf200,
+	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
+	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf509,	0xf200,	0xf50b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
+	0xf501,	0xf119,	0xf500,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short mac_ctrl_alt_map[NR_KEYS] = {
+	0xf801,	0xf813,	0xf804,	0xf806,	0xf808,	0xf807,	0xf81a,	0xf818,
+	0xf803,	0xf816,	0xf200,	0xf802,	0xf811,	0xf817,	0xf805,	0xf812,
+	0xf819,	0xf814,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80f,
+	0xf815,	0xf200,	0xf809,	0xf810,	0xf201,	0xf80c,	0xf80a,	0xf200,
+	0xf80b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80e,	0xf80d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf801,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
+	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf509,	0xf200,	0xf50b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
+	0xf501,	0xf119,	0xf500,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+extern unsigned int keymap_count;
+
+#if 0
+ushort *mac_key_maps[MAX_NR_KEYMAPS] = {
+	mac_plain_map, mac_shift_map, mac_altgr_map, 0,
+	mac_ctrl_map, mac_shift_ctrl_map, 0, 0,
+	mac_alt_map, 0, 0, 0,
+	mac_ctrl_alt_map,	0
+};
+#endif
+
+/*
+ * Misc. defines for testing 
+ */
+
+extern int console_loglevel;
+
+static struct adb_request led_request;
+extern int in_keybinit;
+
+/*
+ * machdep keyboard routines, interface and key repeat method modeled after
+ * drivers/macintosh/keyb_mac.c
+ */
+
+int mac_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+		     char raw_mode)
+{
+	if (!raw_mode) {
+		/*
+		 * Convert R-shift/control/option to L version.
+		 * Remap keycode 0 (A) to the unused keycode 0x5a.
+		 * Other parts of the system assume 0 is not a valid keycode.
+		 */
+		switch (keycode) {
+		case 0x7b: keycode = 0x38; break; /* R-shift */
+		case 0x7c: keycode = 0x3a; break; /* R-option */
+		case 0x7d: keycode = 0x36; break; /* R-control */
+		case 0:	   keycode = 0x5a; break; /* A */
+		}
+	}
+	*keycodep = keycode;
+	return 1;
+}
+
+int mac_kbd_unexpected_up(unsigned char keycode)
+{
+	return 0x80;
+}
+
+static void
+keyboard_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+	/* first check this is from register 0 */
+	if (nb != 5 || (data[2] & 3) != KEYB_KEYREG)
+		return;		/* ignore it */
+	kbd_pt_regs = regs;
+	input_keycode(data[3], 0);
+	if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f)))
+		input_keycode(data[4], 0);
+}
+
+static void
+input_keycode(int keycode, int repeat)
+{
+	struct kbd_struct *kbd;
+	int up_flag;
+
+ 	kbd = kbd_table + fg_console;
+	up_flag = (keycode & 0x80);
+        keycode &= 0x7f;
+	if (!repeat)
+		del_timer(&repeat_timer);
+
+	/*
+	 * XXX: Add mouse button 2+3 fake codes here if mouse open.
+	 *	As we only report up/down events, keep track of faked buttons.
+	 *	Really messy; might need to check if keyboard is in
+	 *	VC_RAW mode for X?.
+	 *	Might also want to know how many buttons need to be emulated.
+	 *	-> hide this as function in arch/m68k/mac ?
+	 *	Current emulation buttons: right alt/option and control
+	 *	(wanted: command and alt/option, or KP= and KP( ...)
+	 *	Debug version; might be rewritten to be faster on normal keys.
+	 */
+	if (mac_mouse_interrupt_hook || console_loglevel >= 8) {
+		unsigned char button, button2, button3, fake_event;
+		static unsigned char button2state=0, button3state=0; /* up */
+		/* faked ADB packet: device type ff, handler 4 ! */
+		static char data[6] = { 0xff, 0x40, 0x3c, 0x80, 0x80, 0x80 };
+
+		button = 0;
+		fake_event = 0;
+		switch (keycode) {	/* which 'button' ? */
+			case 0x7c:	/* R-option */
+				button2 = (!up_flag);		/* new state */
+				if (button2 != button2state)	/* change ? */
+					button = 2; 
+				button2state = button2;		/* save state */
+				fake_event = 2;
+				break; 
+			case 0x7d:	/* R-control */
+				button3 = (!up_flag);		/* new state */
+				if (button3 != button3state)	/* change ? */ 
+					button = 3; 
+				button3state = button3; 	/* save state */
+				fake_event = 3;
+				break; 
+		}
+#ifdef DEBUG_ADBMOUSE
+		if (fake_event && console_loglevel >= 8)
+			printk("fake event: button2 %d button3 %d button %d\n",
+				 button2state, button3state, button);
+#endif
+		if (button) {		/* there's been a button state change */
+			/* fake a mouse packet : send all bytes, change one! */
+			data[button+2] = (up_flag ? 0x80 : 0);
+			if (mac_mouse_interrupt_hook)
+				mac_mouse_interrupt_hook(data);
+#ifdef DEBUG_ADBMOUSE
+			else
+				printk("mouse_fake: data %2x %2x %2x buttons %2x \n", 
+					data[3], data[4], data[5],
+					~( (data[3] & 0x80 ? 0 : 4) 
+					 | (data[4] & 0x80 ? 0 : 1) 
+					 | (data[5] & 0x80 ? 0 : 2) )&7 );
+#endif
+		}
+		/*
+		 * for mouse 3-button emulation: don't process 'fake' keys!
+		 * Keys might autorepeat, and console state gets generally messed
+		 * up enough so that selection stops working.
+		 */
+		if (fake_event)
+			return;
+	}
+
+	/*
+	 * Convert R-shift/control/option to L version.
+	 */
+	switch (keycode) {
+		case 0x7b: keycode = 0x38; break; /* R-shift */
+		case 0x7c: keycode = 0x3a; break; /* R-option */
+		case 0x7d: keycode = 0x36; break; /* R-control */
+		case 0x0:  if (kbd->kbdmode != VC_RAW) 
+			       keycode = 0x5a; /* A; keycode 0 deprecated */
+			       break; 
+	}
+
+	if (kbd->kbdmode != VC_RAW) {
+		if (!up_flag && !dont_repeat[keycode]) {
+			last_keycode = keycode;
+			repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2);
+			add_timer(&repeat_timer);
+		}
+
+		/*
+		 * XXX fix caps-lock behaviour by turning the key-up
+		 * transition into a key-down transition.
+		 * MSch: need to turn each caps-lock event into a down-up
+		 * double event (keyboard code assumes caps-lock is a toggle)
+		 */
+#if 0
+		if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK))
+			up_flag = 0;
+#else
+		if (keycode == 0x39) {
+			handle_scancode(keycode);	/* down */
+			up_flag = 0x80;			/* see below ... */
+		}
+#endif
+	}
+
+	handle_scancode(keycode + up_flag);
+}
+
+static void
+kbd_repeat(unsigned long xxx)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	input_keycode(last_keycode, 1);
+	restore_flags(flags);
+}
+
+  /* [ACA:23-Mar-97] Three button mouse support.  This is designed to
+     function with MkLinux DR-2.1 style X servers.  It only works with
+     three-button mice that conform to Apple's multi-button mouse
+     protocol. */
+
+  /*
+    The X server for MkLinux DR2.1 uses the following unused keycodes to
+    read the mouse:
+
+    0x7e  This indicates that the next two keycodes should be interpreted
+          as mouse information.  The first following byte's high bit
+          represents the state of the left button.  The lower seven bits
+          represent the x-axis acceleration.  The lower seven bits of the
+          second byte represent y-axis acceleration.
+
+    0x3f  The x server interprets this keycode as a middle button
+          release.
+
+    0xbf  The x server interprets this keycode as a middle button
+          depress.
+
+    0x40  The x server interprets this keycode as a right button
+          release.
+
+    0xc0  The x server interprets this keycode as a right button
+          depress.
+
+    NOTES: There should be a better way of handling mice in the X server.
+    The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead
+    of two.  The three mouse buttons should then, in the X server, be read
+    as the high-bits of all three bytes.  The x and y motions can still be
+    in the first two bytes.  Maybe I'll do this...
+  */
+
+  /*
+    Handler 4 -- Apple Extended mouse protocol.
+
+    For Apple's 3-button mouse protocol the data array will contain the
+    following values:
+
+		BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = 0100 0000 Extended protocol register.
+	      Bits 6-7 are the device id, which should be 1.
+	      Bits 4-5 are resolution which is in "units/inch".
+	      The Logitech MouseMan returns these bits clear but it has
+	      200/300cpi resolution.
+	      Bits 0-3 are unique vendor id.
+    data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+	      Bits 2-3 should be 8 + 4.
+		      Bits 4-7 should be 3 for a mouse device.
+    data[3] = bxxx xxxx Left button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+    data[5] = byyy bxxx Third button and fourth button.  Y is additional
+	      high bits of y-axis motion.  XY is additional
+	      high bits of x-axis motion.
+
+    NOTE: data[0] and data[2] are confirmed by the parent function and
+    need not be checked here.
+  */
+
+  /*
+    Handler 1 -- 100cpi original Apple mouse protocol.
+    Handler 2 -- 200cpi original Apple mouse protocol.
+
+    For Apple's standard one-button mouse protocol the data array will
+    contain the following values:
+
+                BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = ???? ???? (?)
+    data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+    data[3] = bxxx xxxx First button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+
+    NOTE: data[0] is confirmed by the parent function and need not be
+    checked here.
+  */
+
+static void
+mouse_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+	struct kbd_struct *kbd;
+	int i;
+
+	if (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG) {
+		printk("data from mouse:");
+		for (i = 0; i < nb; ++i)
+			printk(" %x", data[i]);
+		printk("\n");
+		return;
+	}
+
+	if (mac_mouse_interrupt_hook) {
+		mac_mouse_interrupt_hook(data);
+		/*
+		 * passing the mouse data to i.e. the X server as done for
+		 * Xpmac will confuse applications on a sane X server :-)
+		 */
+		return;
+	} 
+#ifdef DEBUG_ADBMOUSE
+	else
+		if (console_loglevel >= 8)
+		    printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", 
+			data[3], data[4], data[5],
+			~((data[3] & 0x80 ? 0 : 4) 
+			| (data[4] & 0x80 ? 0 : 1)
+			| (data[5] & 0x80 ? 0 : 2))&7,
+			((data[4]&0x7f) < 64 ? (data[4]&0x7f) : (data[4]&0x7f)-128 ),
+			((data[3]&0x7f) < 64 ? -(data[3]&0x7f) : 128-(data[3]&0x7f) ) );
+#endif
+
+
+	kbd = kbd_table + fg_console;
+
+#if 0	/* The entirely insane way of MkLinux handling mouse input */
+	/* Requires put_queue which is static in keyboard.c :-( */
+	/* Only send mouse codes when keyboard is in raw mode. */
+	if (kbd->kbdmode == VC_RAW) {
+		static unsigned char uch_ButtonStateSecond = 0;
+		unsigned char uchButtonSecond;
+
+		/* Send first button, second button and movement. */
+		put_queue( 0x7e );
+		put_queue( data[3] );
+		put_queue( data[4] );
+
+		/* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */
+
+		/* Store the button state. */
+		uchButtonSecond = (data[4] & 0x80);
+
+		/* Send second button. */
+		if (uchButtonSecond != uch_ButtonStateSecond) {
+			put_queue( 0x3f | uchButtonSecond );
+			uch_ButtonStateSecond = uchButtonSecond;
+		}
+
+		/* Macintosh 3-button mouse (handler 4). */
+		if ((nb == 6) && (data[1] & 0x40)) {
+			static unsigned char uch_ButtonStateThird = 0;
+			unsigned char uchButtonThird;
+
+			/* Store the button state for speed. */
+			uchButtonThird = (data[5] & 0x80);
+
+			/* Send third button. */
+			if (uchButtonThird != uch_ButtonStateThird) {
+				put_queue( 0x40 | uchButtonThird );
+				uch_ButtonStateThird = uchButtonThird;
+			}
+		}
+	}
+#endif	/* insane MkLinux mouse hack */
+}
+
+/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
+static unsigned char mac_ledmap[8] = {
+    0,		/* none */
+    4,		/* scroll lock */
+    1,		/* num lock */
+    5,		/* scroll + num lock */
+    2,		/* caps lock */
+    6,		/* caps + scroll lock */
+    3,		/* caps + num lock */
+    7,		/* caps + num + scroll lock */
+};
+
+static int leds_pending;
+
+void mac_kbd_leds(unsigned int leds)
+{
+	if (led_request.got_reply) {
+#ifdef DEBUG_ADB
+		if (console_loglevel == 10)
+			printk("mac_kbd_leds: got reply, sending request!\n");
+#endif
+		adb_request(&led_request, mac_leds_done, 4, ADB_PACKET,
+			     ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG),
+			     0xff, ~mac_ledmap[leds]);
+	} else
+		leds_pending = leds | 0x100;
+}
+
+static void mac_leds_done(struct adb_request *req)
+{
+	int leds;
+
+	if (leds_pending) {
+		leds = leds_pending & 0xff;
+		leds_pending = 0;
+		mac_kbd_leds(leds);
+	}
+	mark_bh(KEYBOARD_BH);
+}
+
+int mac_kbdrate(struct kbd_repeat *k)
+{
+	return 0;
+}
+
+int mac_keyb_init(void)
+{
+	static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req;
+	volatile int ct;
+
+	/* setup key map */
+	key_maps[0]  = mac_plain_map;
+	key_maps[1]  = mac_shift_map;
+	key_maps[2]  = mac_altgr_map;
+	key_maps[4]  = mac_ctrl_map;
+	key_maps[5]  = mac_shift_ctrl_map;
+	key_maps[8]  = mac_alt_map;
+	/* key_maps[9]  = atashift_alt_map; */
+	key_maps[12] = mac_ctrl_alt_map;
+	/* key_maps[13] = atashift_ctrl_alt_map; */
+	memcpy (plain_map, mac_plain_map, sizeof(plain_map));
+	keymap_count = 7;
+
+	/* initialize mouse interrupt hook */
+	mac_mouse_interrupt_hook = NULL;
+	/* assume broken mouse :-) */
+	mac_emulate_button2 = 1;
+	mac_emulate_button3 = 1;
+
+	/*
+	 * Might put that someplace else, possibly ....
+	 */
+	adb_bus_init();
+
+	/* the input functions ... */	
+	adb_register(ADB_KEYBOARD, keyboard_input);
+	adb_register(ADB_MOUSE, mouse_input);
+
+	/* turn on ADB auto-polling in the CUDA */
+	
+	/*
+	 *	Older boxes don't support CUDA_* targets and CUDA commands
+	 *	instead we emulate them in the adb_request hook to make
+	 *	the code interfaces saner.
+	 *
+	 *	Note XXX: the Linux PMac and this code both assume the
+	 *	devices are at their primary ids and do not do device
+	 *	assignment. This isn't ideal. We should fix it to follow
+	 *	the reassignment specs.
+	 */
+
+	if (macintosh_config->adb_type == MAC_ADB_CUDA) {
+		printk("CUDA autopoll on ...\n");
+		adb_request(&autopoll_req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
+		ct=0; 
+		while (!autopoll_req.got_reply && ++ct<1000)
+		{
+			adb_poll();
+				udelay(10);
+		}
+		if(ct==1000)
+			printk("Keyboard timed out.\n");
+	}
+
+	/*
+	 *	XXX: all ADB requests now in CUDA format; adb_request takes 
+	 *	care of that for other Macs.
+	 */
+
+	printk("Configuring keyboard\n");
+
+	/* 
+	 * turn on all leds - the keyboard driver will turn them back off 
+	 * via mac_kbd_leds if everything works ok!
+	 */
+	printk("leds on ...\n");
+	adb_request(&led_request, NULL, 4, ADB_PACKET,
+		     ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~7);
+
+	/*
+	 * The polling stuff should go away as soon as the ADB driver is stable
+	 */
+	ct = 0;
+	adb_poll();
+	while (!led_request.got_reply && ++ct<1000)
+	{
+		adb_poll();
+		udelay(10);
+	}
+	if(ct==1000)
+		printk("Keyboard timed out.\n");
+
+#if 1
+	printk("Configuring coding mode ...\n");
+
+	/* 
+	 * get the keyboard to send separate codes for
+	 * left and right shift, control, option keys. 
+	 */
+	adb_request(&confcod_req, NULL, 4, ADB_PACKET, 
+		     ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3);
+
+	ct=0; 
+	adb_poll();
+	while (!confcod_req.got_reply && ++ct<1000)
+	{
+		adb_poll();
+		udelay(10);
+	}
+	if(ct==1000)
+		printk("Keyboard timed out.\n");
+#endif
+
+#if 0	/* seems to hurt, at least Geert's Mac */
+	printk("Configuring mouse (3-button mode) ...\n");
+
+	/* 
+	 * XXX: taken from the PPC driver again ... 
+	 * Try to switch the mouse (id 3) to handler 4, for three-button
+	 * mode. (0x20 is Service Request Enable, 0x03 is Device ID). 
+	 */
+	adb_request(&mouse_req, NULL, 4, ADB_PACKET,
+		    ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 );
+
+	ct=0; 
+	adb_poll();
+	while (!mouse_req.got_reply && ++ct<1000)
+	{
+		adb_poll();
+		udelay(10);
+	}
+	if(ct==1000)
+		printk("Mouse timed out.\n");
+#endif
+
+#if 0
+	printk("Start polling keyboard ...\n");
+
+	/* 
+	 *	get the keyboard to send data back, via the adb_input hook
+	 *	XXX: was never used properly, and the driver takes care
+	 *	of polling and timeout retransmits now.
+	 *	Might be of use if we want to start talking to a specific
+	 *	device here...
+	 */
+	adb_request(&readkey_req, NULL, 2, ADB_PACKET, 
+		     ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG));
+#endif
+
+	/*
+	 * fake 'request done' for the driver if requests timed out
+	 */
+
+	autopoll_req.got_reply = 1;
+#if 0
+	/* XXX: results in race and hang with mac_kbd_leds and serial (why ?) */
+	led_request.got_reply  = 1;
+#endif
+	confcod_req.got_reply  = 1;
+
+	in_keybinit = 0;
+	printk("Keyboard init done\n");
+
+	return 0;
+}
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/via6522.c linux/arch/m68k/mac/via6522.c
--- v2.1.86/linux/arch/m68k/mac/via6522.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/via6522.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,591 @@
+
+/*
+ *	6522 Versatile Interface Adapter (VIA)
+ *
+ *	There are two of these on the Mac II. Some IRQ's are vectored
+ *	via them as are assorted bits and bobs - eg rtc, adb.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/macintosh.h> 
+#include <asm/macints.h> 
+#include "via6522.h"
+
+volatile unsigned char *via1=(unsigned char *)VIABASE;
+volatile unsigned char *via2=(unsigned char *)VIABASE2;
+
+unsigned char via1_clock, via1_datab;
+
+static int rbv=0;
+
+/*
+ * Debugging the VBL ints
+ */
+
+extern int console_loglevel;
+
+/*
+ *	VIA1 - hardwired vectors
+ */
+
+#if 0 /* gone to macints.[ch] */
+extern void via_wtf(int slot, void *via, struct pt_regs *regs);
+static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs);
+
+extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
+
+static struct via_irq_tab via1_func_tab=
+{
+	{
+		via_wtf,	/* One second interrupt */
+		via_wtf,	/* Vblank */
+		via_wtf,       	/* ADB data ready */
+		via_wtf,	/* ADB data */
+		via_wtf,	/* ADB clock */
+		via_wtf,
+		via_wtf,	/* Slot 6 is replaced by the timer */
+		via_wtf
+	}
+};
+
+static struct via_irq_tab via2_func_tab=
+{
+	{
+		via_wtf,
+		via_do_nubus,
+		via_wtf,
+		via_wtf,
+		via_wtf,
+		via_wtf,
+		via_wtf,
+		via_wtf
+	}
+};
+
+static struct via_irq_tab nubus_func_tab=
+{
+	{
+		via_wtf,
+		via_wtf,
+		via_wtf,
+		via_wtf,
+		via_wtf,
+		via_wtf,
+		via_wtf,
+		via_wtf
+	}
+};
+#endif
+
+extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
+
+#define MAC_CLOCK_TICK		(783300/HZ)	/* ticks per HZ */
+#define MAC_CLOCK_LOW		(MAC_CLOCK_TICK&0xFF)
+#define MAC_CLOCK_HIGH		(MAC_CLOCK_TICK>>8)
+
+
+void via_init_clock(void (*func)(int, void *, struct pt_regs *))
+{
+	unsigned char c;
+
+/*	mac_debugging_penguin(6);*/
+	
+	switch(macintosh_config->via_type)
+	{
+		/*
+		 *      CI, SI, VX, LC 
+		 */
+		case MAC_VIA_IIci:
+			via1=(void *)0x50F00000;
+			via2=(void *)0x50F26000;
+			rbv=1;
+			break;
+		/*
+		 *      Quadra and early MacIIs agree on the VIA locations
+		 */
+		case MAC_VIA_QUADRA:
+		case MAC_VIA_II:
+			via1=(void *)0x50F00000;
+			via2=(void *)0x50F02000;
+			break;
+		default:
+	}
+	via1_clock=via_read(via1, vACR);
+	via1_datab=via_read(via1, vBufB);
+
+	/*
+	 * Tell what MacOS left us with
+	 */
+
+	printk("via_init: boot via1 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n",
+		(int)via1_clock, (int)via_read(via1, vPCR), 
+		(int)via_read(via1, vBufA), (int)via_read(via1, vDirA),
+		(int)via_read(via1, vBufB), (int)via_read(via1, vDirB));
+
+	if (rbv == 0)
+		printk("via_init: boot via2 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n",
+			(int)via_read(via2, vACR), (int)via_read(via2, vPCR), 
+			(int)via_read(via2, vBufA), (int)via_read(via2, vDirA),
+			(int)via_read(via2, vBufB), (int)via_read(via2, vDirB));
+
+	/*
+	 *	Shut it down
+	 */
+
+	via_write(via1,vIER, 0x7F);	 
+	
+	/*
+	 *	Kill the timers
+	 */
+	 
+	via_write(via1,vT1LL,0);
+	via_write(via1,vT1LH,0);
+	via_write(via1,vT1CL,0);
+	via_write(via1,vT1CH,0);
+	via_write(via1,vT2CL,0);
+	via_write(via1,vT2CH,0);
+	
+	/*
+	 *	Now do via2
+	 */
+
+	if(rbv==0) 
+	{
+		via_write(via2,vT1LL,0);
+		via_write(via2,vT1LH,0);
+		via_write(via2,vT1CL,0);
+		via_write(via2,vT1CH,0);
+		via_write(via2,vT2CL,0);
+		via_write(via2,vT2CH,0);
+		via_write(via2,vIER, 0x7F);	 
+	}
+	else
+	{
+		/*
+		 *	Init the RBV chip a bit
+		 */
+		
+		via_write(via2, rIER,0x7F);
+	}
+
+	/*
+	 *	Disable the timer latches
+	 */
+	
+	c=via_read(via1,vACR);
+	via_write(via1,vACR,c&0x3F);
+
+	if(rbv==0) 
+	{
+		c=via_read(via2,vACR);
+		via_write(via2,vACR,c&0x3F);
+	}
+	  
+	/*
+	 *	Now start the clock - we want 100Hz
+	 */
+	 
+	via_write(via1,vACR,via_read(via1,vACR)|0x40);
+	
+	via_write(via1,vT1LL, MAC_CLOCK_LOW);
+	via_write(via1,vT1LH, MAC_CLOCK_HIGH);
+	via_write(via1,vT1CL, MAC_CLOCK_LOW);
+	via_write(via1,vT1CH, MAC_CLOCK_HIGH);
+	
+	/*
+	 *	And enable its interrupt
+	 */
+	
+	request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
+
+/*	mac_debugging_penguin(7);*/
+
+	/* 
+	 * SE/30: disable video int. 
+	 * XXX: testing for SE/30 VBL
+	 */
+
+	if (macintosh_config->ident == MAC_MODEL_SE30 
+	    && console_loglevel != 10) {
+		c = via_read(via1, vBufB);
+		via_write(via1, vBufB, c|(0x40));
+		c = via_read(via1, vDirB);
+		via_write(via1, vDirB, c|(0x40));
+	} 
+
+	/*
+	 * XXX: use positive edge
+	 */
+
+	if (console_loglevel == 10) {
+		c = via_read(via1, vPCR);
+		via_write(via1, vPCR, c|(0x1));
+	}
+
+#if 0 /* gone to mac_init_IRQ */
+	/*
+	 * Set vPCR for SCSI interrupts.
+	 *
+	 * That is: CA1 negative edge int., CA2 indep., positive edge int.;
+	 *	    CB1 negative edge int., CB2 indep., positive edge int..
+	 */
+        via_write(via2,vPCR, 0x66);
+#endif                                                                  
+
+}
+
+#if 0 /* moved to macints.c */
+
+static void via_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
+	struct pt_regs *regs)
+{
+	unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
+	int i;
+	int ct=0;	
+
+	/*
+	 *	Shouldnt happen
+	 */
+	 
+	if(events==0)
+	{
+		printk("via_irq: nothing pending!\n");
+		return;
+	}
+
+	do {
+		/*
+		 *	Clear the pending flag
+		 */
+
+		/* HACK HACK - FIXME !!! - just testing some keyboard ideas */
+	
+		/* events&=~(1<<4); */		 
+		via_write(via, vIFR, events);
+	 
+		/*
+		 *	Now see what bits are raised
+		 */
+	 
+		for(i=0;i<7;i++)
+		{
+			if(events&(1<<i))
+				(irqtab->vector[i])(i, via, regs);
+		}
+	
+		/*
+		 *	And done..
+		 */
+		events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
+		ct++;
+		if(events && ct>8)
+		{
+		        printk("via: stuck events %x\n",events);
+		        break;
+		}
+	}
+	while(events);
+
+	scsi_mac_polled();
+}
+
+/*
+ *
+ *	The RBV is different. RBV appears to stand for randomly broken
+ *	VIA.
+ */
+
+static void rbv_irq(volatile unsigned char *via, struct via_irq_tab *irqtab,
+	struct pt_regs *regs)
+{
+	unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
+	int i;
+	int ct=0;	
+
+	/*
+	 *	Shouldnt happen
+	 */
+	 
+	if(events==0)
+	{
+		printk("rbv_irq: nothing pending!\n");
+		return;
+	}
+
+	do {
+		/*
+		 *	Clear the pending flag
+		 */
+
+		/* HACK HACK - FIXME !!! - just testing some keyboard ideas */
+	
+		/* events&=~(1<<4); */		 
+		via_write(via, rIFR, events);
+	 
+		/*
+		 *	Now see what bits are raised
+		 */
+	 
+		for(i=0;i<7;i++)
+		{
+			if(events&(1<<i))
+				(irqtab->vector[i])(i, via, regs);
+		}
+	
+		/*
+		 *	And done..
+		 */
+		events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
+		ct++;
+		if(events && ct>8)
+		{
+		        printk("rbv: stuck events %x\n",events);
+			for(i=0;i<7;i++)
+			{
+				if(events&(1<<i))
+				{
+					printk("rbv - bashing source %d\n",
+						i);
+					via_write(via, rIER, i);
+					via_write(via, rIFR, i);
+				}
+			}
+		        break;
+		}
+	}
+	while(events);
+}
+
+/*
+ *	System interrupts
+ */
+
+void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	via_irq(via1, &via1_func_tab, regs);
+}
+
+/*
+ *	Nubus interrupts
+ */
+ 
+void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+/*	printk("via2 interrupt\n");*/
+	if(rbv)
+		rbv_irq(via2, &via2_func_tab, regs);
+	else
+		via_irq(via2, &via2_func_tab, regs);
+}
+
+/*
+ *	Unexpected via interrupt
+ */
+ 
+void via_wtf(int slot, volatile void *via, struct pt_regs *regs)
+{
+	printk("Unexpected event %d on via %p\n",slot,via);
+}
+
+void nubus_wtf(int slot, volatile void *via, struct pt_regs *regs)
+{
+	printk("Unexpected interrupt on nubus slot %d\n",slot);
+}
+
+#endif
+
+/*
+ *	The power switch - yes its software!
+ */
+ 
+void mac_reset(void)
+{
+	if(rbv)	{
+		via_write(via2, rBufB, via_read(via2, rBufB)&~0x04);
+	} else {
+		/* Direction of vDirB is output */
+		via_write(via2,vDirB,via_read(via2,vDirB)|0x04);
+		/* Send a value of 0 on that line */
+		via_write(via2,vBufB,via_read(via2,vBufB)&~0x04);
+	}
+	/* We never make it this far... */
+	/* XXX - delay do we need to spin here ? */
+	while(1);	/* Just in case .. */
+}
+
+/*
+ *	Set up the keyboard
+ */
+ 
+void via_setup_keyboard(void)
+{
+#if 0 /* moved to adb */
+	via1_func_tab.vector[2]=adb_interrupt;
+#else
+	request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, "adb interrupt",
+		    adb_interrupt);
+#endif
+}
+
+/*
+ *	Floppy hook
+ */
+
+void via1_set_head(int head)
+{
+	if(head==0)
+		via_write(via1, vBufA, via_read(via1, vBufA)&~0x20);
+	else
+		via_write(via1, vBufA, via_read(via1, vBufA)|0x20);
+}
+
+#if 0 /* moved to macints.c */
+
+
+/*
+ *    Set up the SCSI
+ */
+
+void via_scsi_disable(void)
+{
+	if (rbv)
+		via_write(via2, rIER, (1<<3)|(1<<0));
+	else
+		via_write(via2, vIER, (1<<3)|(1<<0));
+}
+
+void via_scsi_enable(void)
+{
+	if (rbv)
+		via_write(via2, rIER, (1<<3)|(1<<0)|0x80);
+	else
+		via_write(via2, vIER, (1<<3)|(1<<0)|0x80);
+}
+
+void via_scsi_clear(void)
+{
+        if (rbv) 
+		via_write(via2, rIFR, (1<<3)|(1<<0)|0x80);
+	volatile unsigned char deep_magic=via_read(via2, vBufB);
+	via_scsi_enable();
+}
+ 
+void via_setup_scsi(void (*handler)(int,volatile void *,struct pt_regs *))
+{
+	via2_func_tab.vector[0]=handler;        /* SCSI DRQ */
+	via2_func_tab.vector[3]=handler;        /* SCSI IRQ */
+	via_write(via2, vPCR, 0x66);		/* Edge direction! */
+	via_scsi_enable();
+}
+
+/*
+ *	Nubus handling
+ */
+ 
+static int nubus_active=0;
+ 
+int nubus_request_irq(int slot, void (*handler)(int,void *,struct pt_regs *))
+{
+	slot-=9;
+/*	printk("Nubus request irq for slot %d\n",slot);*/
+	if(nubus_func_tab.vector[slot]==nubus_wtf)
+		return -EBUSY;
+	nubus_func_tab.vector[slot]=handler;
+	nubus_active|=1<<slot;
+/*	printk("program slot %d\n",slot);*/
+/*	printk("via2=%p\n",via2);*/
+#if 0
+	via_write(via2, vDirA, 
+		via_read(via2, vDirA)|(1<<slot));
+	via_write(via2, vBufA, 0);
+#endif		
+	if (!rbv) {
+	/* Make sure the bit is an input */
+	via_write(via2, vDirA, 
+		via_read(via2, vDirA)&~(1<<slot));
+	}
+/*	printk("nubus irq on\n");*/
+	return 0;
+}
+
+int nubus_free_irq(int slot)
+{
+	slot-=9;
+	nubus_active&=~(1<<slot);
+	nubus_func_tab.vector[slot]=nubus_wtf;
+	if (rbv) {
+		via_write(via2, rBufA, 1<<slot);
+	} else {
+		via_write(via2, vDirA, 
+			via_read(via2, vDirA)|(1<<slot));
+		via_write(via2, vBufA, 1<<slot);
+		via_write(via2, vDirA, 
+			via_read(via2, vDirA)&~(1<<slot));
+	}
+	return 0;
+}
+
+static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs)
+{
+	unsigned char map;
+	int i;
+	int ct=0;
+
+/*	printk("nubus interrupt\n");*/
+		
+	if (rbv) {
+		via_write(via2, rIFR, 0x82);	/* lock the nubus interrupt */
+	} else {
+		via_write(via2, vIFR, 0x82);	/* lock the nubus interrupt */
+		
+	while(1)
+	{
+		if(rbv)
+			map=~via_read(via2, rBufA);
+		else
+			map=~via_read(via2, vBufA);
+		if((map=(map&nubus_active))==0)
+			break;
+		if(ct++>2)
+		{
+			printk("nubus stuck events - %d/%d\n", map, nubus_active);
+			return;
+		}
+		for(i=0;i<7;i++)
+		{
+			if(map&(1<<i))
+			{
+				(nubus_func_tab.vector[i])(i+9, via, regs);
+			}
+		}
+		if (rbv)
+			via_write(via2, rIFR, 0x02);	/* clear it */
+		else
+			via_write(via2, vIFR, 0x02);	/* clear it */
+	}
+	
+	/* And done */
+}
+#endif
+
+void nubus_init_via(void)
+{
+	if (rbv) {
+		via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
+		via_write(via2, rIER, 0x82);	/* Interrupts on */
+	} else {
+		/* Assert the nubus active */
+		via_write(via2, vDirB, via_read(via2, vDirB)|0x02);
+		via_write(via2, vBufB, via_read(via2, vBufB)|0x02);
+		/* Make the nubus interrupt source register all output (disable) */
+		/* via_write(via2, vDirA, 0xFF); */
+		via_write(via2, vIER, 0x82);	/* Interrupts on */
+	}
+	printk("BTW  boot via1 acr=%X datab=%X pcr=%X\n",
+		(int)via1_clock, (int)via1_datab, (int)via_read(via1, vPCR));
+}
+
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mac/via6522.h linux/arch/m68k/mac/via6522.h
--- v2.1.86/linux/arch/m68k/mac/via6522.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/via6522.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,111 @@
+/*
+ *	6522 Versatile Interface Adapter (VIA)
+ *
+ *	There are two of these on the Mac II. Some IRQ's are vectored
+ *	via them as are assorted bits and bobs - eg rtc, adb. The picture
+ *	is a bit incomplete as the Mac documentation doesnt cover this well
+ */
+ 
+#define VIABASE		0x50F00000
+#define VIABASE2	0x50F02000
+
+/*
+ *	Not all of these are true post MacII I think
+ */
+ 
+#define VIA1A_vSccWrReq	0x80	/* SCC write */
+#define VIA1A_vRev8	0x40	/* Revision 8 board ??? */
+#define VIA1A_vHeadSel	0x20	/* Head select for IWM */
+#define VIA1A_vOverlay	0x10
+#define VIA1A_vSync	0x08
+#define VIA1A_vVolume	0x07	/* Audio volume mask */
+	
+#define VIA1B_vSound	0x80	/* Audio on/off */
+#define VIA1B_vMystery	0x40
+#define VIA1B_vADBS2	0x20	/* ADB state 2 */
+#define VIA1B_vADBS1	0x10	/* ADB state 1 */
+#define VIA1B_vADBInt	0x08	/* ADB interrupt */
+#define VIA1B_vRTCEnb	0x04	/* Real time clock */
+#define VIA1B_vRTCClk	0x02
+#define VIA1B_vRTCData	0x01
+
+/*
+ *	VIA2 A register is the interrupt lines raised off the nubus 
+ *	slots.
+ */
+ 
+#define VIA2A_vIRQE	0x20
+#define VIA2A_vIRQD	0x10
+#define VIA2A_vIRQC	0x08
+#define VIA2A_vIRQB	0x04
+#define VIA2A_vIRQA	0x02
+#define VIA2A_vIRQ9	0x01
+
+/*
+ *	Register B has the fun stuff in it
+ */
+
+#define VIA2B_vPower	0x04	/* Off switch */
+#define VIA2B_vBusLk	0x02
+#define VIA2B_vCDis	0x01
+
+extern __inline__ void via_write(volatile unsigned char *via,int reg, int v)
+{
+	via[reg]=v;
+}
+
+extern __inline__ int via_read(volatile unsigned char *via,int reg)
+{
+	return (int)via[reg];
+}
+
+extern volatile unsigned char *via1,*via2;
+
+/*
+ *	6522 registers - see databook
+ */
+ 
+#define vBufB	0x0000
+#define vBufA	0x0200
+#define vDirB	0x0400
+#define vDirA	0x0600
+#define vT1CL	0x0800
+#define vT1CH	0x0a00
+#define vT1LL	0x0c00
+#define vT1LH	0x0e00
+#define vT2CL	0x1000
+#define vT2CH	0x1200
+#define vSR	0x1400
+#define vACR	0x1600
+#define vPCR	0x1800
+#define vIFR	0x1a00
+#define vIER	0x1c00 
+#define vANH	0x1e00  /* register A (no shake) */
+
+#define rBufB	0x00
+#define rBufA	0x02
+/*#define rIFR	0x03*/
+#define rIFR	0x1A03
+#define rVideo	0x10
+#define rSlot	0x12
+/*#define rIER	0x13*/
+#define rIER	0x1C13
+/*
+#define R_rIFR	0x03
+#define R_rIER	0x13
+#define W_rIFR	0x1A03
+#define W_rIER	0x1C13
+*/
+/*
+ *	VIA interrupt
+ */
+ 
+struct via_irq_tab
+{
+	void (*vector[8])(int, void *, struct pt_regs *);
+};
+
+extern void via1_irq(int, void *, struct pt_regs *);
+extern void via2_irq(int, void *, struct pt_regs *);
+
+extern void via_setup_keyboard(void);
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mm/Makefile linux/arch/m68k/mm/Makefile
--- v2.1.86/linux/arch/m68k/mm/Makefile	Fri Nov 22 05:56:35 1996
+++ linux/arch/m68k/mm/Makefile	Thu Feb 12 16:30:13 1998
@@ -8,6 +8,6 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS	 := init.o fault.o memory.o extable.o
+O_OBJS	 := init.o fault.o memory.o kmap.o extable.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.1.86/linux/arch/m68k/mm/fault.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/mm/fault.c	Thu Feb 12 16:30:13 1998
@@ -101,11 +101,15 @@
 bad_area:
 	up(&mm->mmap_sem);
 
-	/* Are we prepared to handle this fault?  */
+	/* User mode accesses just cause a SIGSEGV */
+	if (user_mode(regs)) {
+		force_sig (SIGSEGV, tsk);
+		return 1;
+	}
+
+	/* Are we prepared to handle this kernel fault?  */
 	if ((fixup = search_exception_table(regs->pc)) != 0) {
 		struct pt_regs *tregs;
-		printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
-		       current->comm, regs->pc, fixup);
 		/* Create a new four word stack frame, discarding the old
 		   one.  */
 		regs->stkadj = frame_extra_sizes[regs->format];
@@ -115,12 +119,6 @@
 		tregs->pc = fixup;
 		tregs->sr = regs->sr;
 		return -1;
-	}
-
-	if (user_mode(regs)) {
-		/* User memory access */
-		force_sig (SIGSEGV, tsk);
-		return 1;
 	}
 
 /*
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.1.86/linux/arch/m68k/mm/init.c	Mon Jun 16 16:35:54 1997
+++ linux/arch/m68k/mm/init.c	Thu Feb 12 16:30:13 1998
@@ -23,6 +23,9 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/machdep.h>
+#ifdef CONFIG_ATARI
+#include <asm/atari_stram.h>
+#endif
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void init_kpointer_table(void);
@@ -63,6 +66,7 @@
 {
     unsigned long i;
     int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0;
+    int cached = 0;
 
     printk("\nMem-info:\n");
     show_free_areas();
@@ -72,6 +76,8 @@
 	total++;
 	if (PageReserved(mem_map+i))
 	    reserved++;
+	if (PageSwapCache(mem_map+i))
+	    cached++;
 	else if (!atomic_read(&mem_map[i].count))
 	    free++;
 	else if (atomic_read(&mem_map[i].count) == 1)
@@ -84,6 +90,7 @@
     printk("%d reserved pages\n",reserved);
     printk("%d pages nonshared\n",nonshared);
     printk("%d pages shared\n",shared);
+    printk("%d pages swap cached\n",cached);
     show_buffers();
 #ifdef CONFIG_NET
     show_net_buffers();
@@ -293,8 +300,6 @@
 /*
  * 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.
  */
 __initfunc(unsigned long paging_init(unsigned long start_mem,
 				     unsigned long end_mem))
@@ -321,6 +326,18 @@
 		for (i = 0; i < 16; i++)
 			pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
 	}
+	/* Fix the PAGE_NONE value. */
+	if (CPU_IS_040_OR_060) {
+		/* On the 680[46]0 we can use the _PAGE_SUPER bit.  */
+		pgprot_val(protection_map[0]) |= _PAGE_SUPER;
+		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER;
+	} else {
+		/* Otherwise we must fake it. */
+		pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT;
+		pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER;
+		pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT;
+		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER;
+	}
 
 	/*
 	 * Map the physical memory available into the kernel virtual
@@ -412,42 +429,15 @@
 	high_memory = (void *) end_mem;
 	max_mapnr = num_physpages = MAP_NR(end_mem);
 
-	start_mem = PAGE_ALIGN(start_mem);
-	while (start_mem < end_mem) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
-		start_mem += PAGE_SIZE;
+	tmp = start_mem = PAGE_ALIGN(start_mem);
+	while (tmp < end_mem) {
+		clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
+		tmp += 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);
-		}
-	}
-	
+	if (MACH_IS_ATARI)
+		atari_stram_reserve_pages( start_mem );
 #endif
 
 	for (tmp = 0 ; tmp < end_mem ; tmp += PAGE_SIZE) {
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mm/kmap.c linux/arch/m68k/mm/kmap.c
--- v2.1.86/linux/arch/m68k/mm/kmap.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mm/kmap.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,564 @@
+/*
+ *  linux/arch/m68k/mm/kmap.c
+ *
+ *  Copyright (C) 1997 Roman Hodek
+ */
+
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/malloc.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+
+extern pte_t *kernel_page_table (unsigned long *memavailp);
+
+/* Virtual address region for use by kernel_map() */
+#define	KMAP_START	0xd0000000
+#define	KMAP_END	0xf0000000
+
+/* Granularity of kernel_map() allocations */
+#define KMAP_STEP	(256*1024)
+
+/* Size of pool of KMAP structures; that is needed, because kernel_map() can
+ * be called at times where kmalloc() isn't initialized yet. */
+#define	KMAP_POOL_SIZE	16
+
+/* structure for maintainance of kmap regions */
+typedef struct kmap {
+	struct kmap *next, *prev;	/* linking of list */
+	unsigned long addr;			/* start address of region */
+	unsigned long mapaddr;		/* address returned to user */
+	unsigned long size;			/* size of region */
+	unsigned free : 1;			/* flag whether free or allocated */
+	unsigned kmalloced : 1;		/* flag whether got this from kmalloc() */
+	unsigned pool_alloc : 1;	/* flag whether got this is alloced in pool */
+} KMAP;
+
+KMAP kmap_pool[KMAP_POOL_SIZE] = {
+	{ NULL, NULL, KMAP_START, KMAP_START, KMAP_END-KMAP_START, 1, 0, 1 },
+	{ NULL, NULL, 0, 0, 0, 0, 0, 0 },
+};
+
+/*
+ * anchor of kmap region list
+ *
+ * The list is always ordered by addresses, and regions are always adjacent,
+ * i.e. there must be no holes between them!
+ */
+KMAP *kmap_regions = &kmap_pool[0];
+
+/* for protecting the kmap_regions list against races */
+static struct semaphore kmap_sem = MUTEX;
+
+
+
+/*
+ * Low-level allocation and freeing of KMAP structures
+ */
+static KMAP *alloc_kmap( int use_kmalloc )
+{
+	KMAP *p;
+	int i;
+
+	/* first try to get from the pool if possible */
+	for( i = 0; i < KMAP_POOL_SIZE; ++i ) {
+		if (!kmap_pool[i].pool_alloc) {
+			kmap_pool[i].kmalloced = 0;
+			kmap_pool[i].pool_alloc = 1;
+			return( &kmap_pool[i] );
+		}
+	}
+	
+	if (use_kmalloc && (p = (KMAP *)kmalloc( sizeof(KMAP), GFP_KERNEL ))) {
+		p->kmalloced = 1;
+		return( p );
+	}
+	
+	return( NULL );
+}
+
+static void free_kmap( KMAP *p )
+{
+	if (p->kmalloced)
+		kfree( p );
+	else
+		p->pool_alloc = 0;
+}
+
+
+/*
+ * Get a free region from the kmap address range
+ */
+static KMAP *kmap_get_region( unsigned long size, int use_kmalloc )
+{
+	KMAP *p, *q;
+
+	/* look for a suitable free region */
+	for( p = kmap_regions; p; p = p->next )
+		if (p->free && p->size >= size)
+			break;
+	if (!p) {
+		printk( KERN_ERR "kernel_map: address space for "
+				"allocations exhausted\n" );
+		return( NULL );
+	}
+	
+	if (p->size > size) {
+		/* if free region is bigger than we need, split off the rear free part
+		 * into a new region */
+		if (!(q = alloc_kmap( use_kmalloc ))) {
+			printk( KERN_ERR "kernel_map: out of memory\n" );
+			return( NULL );
+		}
+		q->addr = p->addr + size;
+		q->size = p->size - size;
+		p->size = size;
+		q->free = 1;
+
+		q->prev = p;
+		q->next = p->next;
+		p->next = q;
+		if (q->next) q->next->prev = q;
+	}
+	
+	p->free = 0;
+	return( p );
+}
+
+
+/*
+ * Free a kernel_map region again
+ */
+static void kmap_put_region( KMAP *p )
+{
+	KMAP *q;
+
+	p->free = 1;
+
+	/* merge with previous region if possible */
+	q = p->prev;
+	if (q && q->free) {
+		if (q->addr + q->size != p->addr) {
+			printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" );
+			return;
+		}
+		q->size += p->size;
+		q->next = p->next;
+		if (p->next) p->next->prev = q;
+		free_kmap( p );
+		p = q;
+	}
+
+	/* merge with following region if possible */
+	q = p->next;
+	if (q && q->free) {
+		if (p->addr + p->size != q->addr) {
+			printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" );
+			return;
+		}
+		p->size += q->size;
+		p->next = q->next;
+		if (q->next) q->next->prev = p;
+		free_kmap( q );
+	}
+}
+
+
+/*
+ * kernel_map() helpers
+ */
+static inline pte_t *
+pte_alloc_kernel_map(pmd_t *pmd, unsigned long address,
+		     unsigned long *memavailp)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t *page = kernel_page_table(memavailp);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_set(pmd, page);
+				memset( page, 0, PAGE_SIZE );
+				return page + address;
+			}
+			pmd_set(pmd, BAD_PAGETABLE);
+			return NULL;
+		}
+		if (memavailp)
+			panic("kernel_map: slept during init?!?");
+		cache_page((unsigned long) page);
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk( KERN_ERR "Bad pmd in pte_alloc_kernel_map: %08lx\n",
+		       pmd_val(*pmd));
+		pmd_set(pmd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+static inline void
+kernel_map_pte(pte_t *pte, unsigned long address, unsigned long size,
+	       unsigned long phys_addr, pgprot_t prot)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		pte_val(*pte) = phys_addr + pgprot_val(prot);
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address < end);
+}
+
+static inline int
+kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size,
+		unsigned long phys_addr, pgprot_t prot,
+		unsigned long *memavailp)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+
+	if (CPU_IS_040_OR_060) {
+		do {
+			pte_t *pte = pte_alloc_kernel_map(pmd, address, memavailp);
+			if (!pte)
+				return -ENOMEM;
+			kernel_map_pte(pte, address, end - address,
+				       address + phys_addr, prot);
+			address = (address + PMD_SIZE) & PMD_MASK;
+			pmd++;
+		} while (address < end);
+	} else {
+		/* On the 68030 we use early termination page descriptors.
+		   Each one points to 64 pages (256K). */
+		int i = (address >> (PMD_SHIFT-4)) & 15;
+		do {
+			(&pmd_val(*pmd))[i++] = (address + phys_addr) | pgprot_val(prot);
+			address += PMD_SIZE / 16;
+		} while (address < end);
+	}
+	return 0;
+}
+
+
+/*
+ * Map some physical address range into the kernel address space. The
+ * code is copied and adapted from map_chunk().
+ */
+/* Rewritten by Andreas Schwab to remove all races. */
+
+unsigned long kernel_map(unsigned long phys_addr, unsigned long size,
+			 int cacheflag, unsigned long *memavailp)
+{
+	unsigned long retaddr, from, end;
+	pgd_t *dir;
+	pgprot_t prot;
+	KMAP *kmap;
+
+	/* Round down 'phys_addr' to 256 KB and adjust size */
+	retaddr = phys_addr & (KMAP_STEP-1);
+	size += retaddr;
+	phys_addr &= ~(KMAP_STEP-1);
+	/* Round up the size to 256 KB. It doesn't hurt if too much is
+	   mapped... */
+	size = (size + KMAP_STEP - 1) & ~(KMAP_STEP-1);
+	
+	down( &kmap_sem );
+	if (!(kmap = kmap_get_region( size, memavailp == NULL )))
+		return( 0 );
+	from = kmap->addr;
+	retaddr += from;
+	kmap->mapaddr = retaddr;
+	end = from + size;
+	up( &kmap_sem );
+
+	if (CPU_IS_040_OR_060) {
+		pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_GLOBAL040 |
+				    _PAGE_ACCESSED | _PAGE_DIRTY);
+		switch (cacheflag) {
+		case KERNELMAP_FULL_CACHING:
+			pgprot_val(prot) |= _PAGE_CACHE040;
+			break;
+		case KERNELMAP_NOCACHE_SER:
+		default:
+			pgprot_val(prot) |= _PAGE_NOCACHE_S;
+			break;
+		case KERNELMAP_NOCACHE_NONSER:
+			pgprot_val(prot) |= _PAGE_NOCACHE;
+			break;
+		case KERNELMAP_NO_COPYBACK:
+			pgprot_val(prot) |= _PAGE_CACHE040W;
+			break;
+		}
+	} else
+		pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_ACCESSED |
+				    _PAGE_DIRTY |
+				    ((cacheflag == KERNELMAP_FULL_CACHING ||
+				      cacheflag == KERNELMAP_NO_COPYBACK)
+				     ? 0 : _PAGE_NOCACHE030));
+
+	phys_addr -= from;
+	dir = pgd_offset_k(from);
+	while (from < end) {
+		pmd_t *pmd = pmd_alloc_kernel(dir, from);
+
+		if (kernel_map_pmd(pmd, from, end - from, phys_addr + from,
+				   prot, memavailp)) {
+			printk( KERN_ERR "kernel_map: out of memory\n" );
+			return 0UL;
+		}
+		from = (from + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+
+	return retaddr;
+}
+
+
+/*
+ * kernel_unmap() helpers
+ */
+static inline void pte_free_kernel_unmap( pmd_t *pmd )
+{
+	unsigned long page = pmd_page(*pmd);
+	mem_map_t *pagemap = &mem_map[MAP_NR(page)];
+	
+	pmd_clear(pmd);
+	cache_page(page);
+
+	if (PageReserved( pagemap )) {
+		/* need to unreserve pages that were allocated with memavailp != NULL;
+		 * this works only if 'page' is page-aligned */
+		if (page & ~PAGE_MASK)
+			return;
+		clear_bit( PG_reserved, &pagemap->flags );
+		atomic_set( &pagemap->count, 1 );
+	}
+	free_page( page );
+}
+
+/*
+ * This not only unmaps the requested region, but also loops over the whole
+ * pmd to determine whether the other pte's are clear (so that the page can be
+ * freed.) If so, it returns 1, 0 otherwise.
+ */
+static inline int
+kernel_unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
+{
+	pte_t *pte;
+	unsigned long addr2, end, end2;
+	int all_clear = 1;
+
+	if (pmd_none(*pmd))
+		return( 0 );
+	if (pmd_bad(*pmd)) {
+		printk( KERN_ERR "kernel_unmap_pte_range: bad pmd (%08lx)\n",
+				pmd_val(*pmd) );
+		pmd_clear(pmd);
+		return( 0 );
+	}
+	address &= ~PMD_MASK;
+	addr2 = 0;
+	pte = pte_offset(pmd, addr2);
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	end2 = addr2 + PMD_SIZE;
+	while( addr2 < end2 ) {
+		if (!pte_none(*pte)) {
+			if (address <= addr2 && addr2 < end)
+				pte_clear(pte);
+			else
+				all_clear = 0;
+		}
+		++pte;
+		addr2 += PAGE_SIZE;
+	}
+	return( all_clear );
+}
+
+static inline void
+kernel_unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
+{
+	pmd_t * pmd;
+	unsigned long end;
+
+	if (pgd_none(*dir))
+		return;
+	if (pgd_bad(*dir)) {
+		printk( KERN_ERR "kernel_unmap_pmd_range: bad pgd (%08lx)\n",
+				pgd_val(*dir) );
+		pgd_clear(dir);
+		return;
+	}
+	pmd = pmd_offset(dir, address);
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	
+	if (CPU_IS_040_OR_060) {
+		do {
+			if (kernel_unmap_pte_range(pmd, address, end - address))
+				pte_free_kernel_unmap( pmd );
+			address = (address + PMD_SIZE) & PMD_MASK;
+			pmd++;
+		} while (address < end);
+	} else {
+		/* On the 68030 clear the early termination descriptors */
+		int i = (address >> (PMD_SHIFT-4)) & 15;
+		do {
+			(&pmd_val(*pmd))[i++] = 0;
+			address += PMD_SIZE / 16;
+		} while (address < end);
+	}
+}
+
+/*
+ * Unmap a kernel_map()ed region again
+ */
+void kernel_unmap( unsigned long addr )
+{
+	unsigned long end;
+	pgd_t *dir;
+	KMAP *p;
+
+	down( &kmap_sem );
+	
+	/* find region for 'addr' in list; must search for mapaddr! */
+	for( p = kmap_regions; p; p = p->next )
+		if (!p->free && p->mapaddr == addr)
+			break;
+	if (!p) {
+		printk( KERN_ERR "kernel_unmap: trying to free invalid region\n" );
+		return;
+	}
+	addr = p->addr;
+	end = addr + p->size;
+	kmap_put_region( p );
+
+	dir = pgd_offset_k( addr );
+	while( addr < end ) {
+		kernel_unmap_pmd_range( dir, addr, end - addr );
+		addr = (addr + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+	
+	up( &kmap_sem );
+	/* flushing for a range would do, but there's no such function for kernel
+	 * address space... */
+	flush_tlb_all();
+}
+
+
+/*
+ * kernel_set_cachemode() helpers
+ */
+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 (CPU_IS_040_OR_060) {
+		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;
+	}
+	/* flushing for a range would do, but there's no such function for kernel
+	 * address space... */
+	flush_tlb_all();
+}
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.1.86/linux/arch/m68k/mm/memory.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/m68k/mm/memory.c	Thu Feb 12 16:30:13 1998
@@ -18,8 +18,6 @@
 #include <asm/traps.h>
 #include <asm/amigahw.h>
 
-extern pte_t *kernel_page_table (unsigned long *memavailp);
-
 /* Strings for `extern inline' functions in <asm/pgtable.h>.  If put
    directly into these functions, they are output for every file that
    includes pgtable.h */
@@ -349,10 +347,10 @@
 	/* no match, too, so get the actual physical address from the MMU. */
 
 	if (CPU_IS_060) {
-	  unsigned long fs = get_fs();
+	  mm_segment_t fs = get_fs();
 	  unsigned long  paddr;
 
-	  set_fs (SUPER_DATA);
+	  set_fs (MAKE_MM_SEG(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
@@ -368,9 +366,9 @@
 
 	} else if (CPU_IS_040) {
 	  unsigned long mmusr;
-	  unsigned long fs = get_fs();
+	  mm_segment_t fs = get_fs();
 
-	  set_fs (SUPER_DATA);
+	  set_fs (MAKE_MM_SEG(SUPER_DATA));
 
 	  asm volatile (".chip 68040\n\t"
 			"ptestr (%1)\n\t"
@@ -380,6 +378,9 @@
 			: "a" (vaddr));
 	  set_fs (fs);
 
+	  if (mmusr & MMU_T_040) {
+	    return (vaddr);	/* Transparent translation */
+	  }
 	  if (mmusr & MMU_R_040)
 	    return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
 
@@ -452,7 +453,7 @@
 
 	/*
 	 * if on an amiga and address is in first 16M, move it 
-	 * to the ZTWO_ADDR range
+	 * to the ZTWO_VADDR range
 	 */
 	if (MACH_IS_AMIGA && paddr < 16*1024*1024)
 		return ZTWO_VADDR(paddr);
@@ -495,33 +496,6 @@
 	     if (CPU_IS_060) cleari040(paddr);	\
 	} while(0)
 
-/* push page defined by virtual address in both caches */
-#define	pushv040(vaddr)						\
-	do { unsigned long _tmp1, _tmp2;			\
-	__asm__ __volatile__ ("nop\n\t"				\
-			      ".chip 68040\n\t"			\
-			      "ptestr (%2)\n\t"			\
-			      "movec %%mmusr,%0\n\t"		\
-			      "andw #0xf000,%0\n\t"		\
-			      "movel %0,%1\n\t"			\
-			      "nop\n\t"				\
-			      "cpushp %%bc,(%1)\n\t"		\
-			      ".chip 68k"			\
-			      : "=d" (_tmp1), "=a" (_tmp2)	\
-			      : "a" (vaddr));			\
-	} while (0)
-
-/* push page defined by virtual address in both caches */
-#define	pushv060(vaddr)					\
-	do { unsigned long _tmp;			\
-	__asm__ __volatile__ (".chip 68060\n\t"		\
-			      "plpar (%0)\n\t"		\
-			      "cpushp %%bc,(%0)\n\t"	\
-			      ".chip 68k"		\
-			      : "=a" (_tmp)		\
-			      : "0" (vaddr));		\
-	} while (0)
-
 
 /*
  * 040: Hit every page containing an address in the range paddr..paddr+len-1.
@@ -632,64 +606,11 @@
 }
 
 
-/*
- * cache_push_v() semantics: Write back any dirty cache data in the given
- * area, and invalidate those entries at least in the instruction cache. This
- * is intended to be used after data has been written that can be executed as
- * code later. The range is defined by a _user_mode_ _virtual_ address  (or,
- * more exactly, the space is defined by the %sfc/%dfc register.)
- */
-
-void cache_push_v (unsigned long vaddr, int len)
-{
-    if (CPU_IS_040) {
-	int tmp = PAGE_SIZE;
-
-	/* on 68040, push cache lines for pages in the range */
-	len += vaddr & (PAGE_SIZE - 1);
-
-	/*
-	 * Work around bug I17 in the 68060 affecting some instruction
-	 * lines not being invalidated properly.
-	 */
-	vaddr &= PAGE_MASK;
-
-	do {
-	    pushv040(vaddr);
-	    vaddr += tmp;
-	} while ((len -= tmp) > 0);
-    }
-    else if (CPU_IS_060) {
-	int tmp = PAGE_SIZE;
-
-	/* on 68040, push cache lines for pages in the range */
-	len += vaddr & (PAGE_SIZE - 1);
-	do {
-	    pushv060(vaddr);
-	    vaddr += tmp;
-	} while ((len -= tmp) > 0);
-    }
-    /* 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 cleari040
 #undef push040
 #undef pushcl040
 #undef pushcli040
-#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)
 {
@@ -700,227 +621,4 @@
 			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 (CPU_IS_040_OR_060) {
-		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 && CPU_IS_040_OR_060) {
-			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 (CPU_IS_040_OR_060) {
-			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 (CPU_IS_040_OR_060) {
-		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 v2.1.86/linux/arch/m68k/mvme16x/16xints.c linux/arch/m68k/mvme16x/16xints.c
--- v2.1.86/linux/arch/m68k/mvme16x/16xints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme16x/16xints.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,144 @@
+/*
+ * arch/m68k/mvme16x/16xints.c
+ *
+ * Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * based on 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/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+static struct {
+	void		(*handler)(int, void *, struct pt_regs *);
+	unsigned long	flags;
+	void		*dev_id;
+	const char	*devname;
+	unsigned	count;
+} irq_tab[192];
+
+/*
+ * void mvme16x_init_IRQ (void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the mvme16x IRQ handling routines.  Should probably ensure
+ * that the base vectors for the VMEChip2 and PCCChip2 are valid.
+ */
+
+void mvme16x_init_IRQ (void)
+{
+	int i;
+
+	for (i = 0; i < 192; i++) {
+		irq_tab[i].handler = mvme16x_defhand;
+		irq_tab[i].flags = IRQ_FLG_STD;
+		irq_tab[i].dev_id = NULL;
+		irq_tab[i].devname = NULL;
+		irq_tab[i].count = 0;
+	}
+}
+
+int mvme16x_request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+	if (irq < 64 || irq > 255) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
+
+	if (!(irq_tab[irq-64].flags & IRQ_FLG_STD)) {
+		if (irq_tab[irq-64].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %d from %s is not replaceable\n",
+			       __FUNCTION__, irq, irq_tab[irq-64].devname);
+			return -EBUSY;
+		}
+		if (flags & IRQ_FLG_REPLACE) {
+			printk("%s: %s can't replace IRQ %d from %s\n",
+			       __FUNCTION__, devname, irq, irq_tab[irq-64].devname);
+			return -EBUSY;
+		}
+	}
+	irq_tab[irq-64].handler = handler;
+	irq_tab[irq-64].flags   = flags;
+	irq_tab[irq-64].dev_id  = dev_id;
+	irq_tab[irq-64].devname = devname;
+	return 0;
+}
+
+void mvme16x_free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq < 64 || irq > 255) {
+		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
+
+	if (irq_tab[irq-64].dev_id != dev_id)
+		printk("%s: Removing probably wrong IRQ %d from %s\n",
+		       __FUNCTION__, irq, irq_tab[irq-64].devname);
+
+	irq_tab[irq-64].handler = mvme16x_defhand;;
+	irq_tab[irq-64].flags   = IRQ_FLG_STD;
+	irq_tab[irq-64].dev_id  = NULL;
+	irq_tab[irq-64].devname = NULL;
+}
+
+void mvme16x_process_int (unsigned long vec, struct pt_regs *fp)
+{
+	if (vec < 64 || vec > 255)
+		panic ("mvme16x_process_int: Illegal vector %ld", vec);
+	irq_tab[vec-64].count++;
+	irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
+}
+
+int mvme16x_get_irq_list (char *buf)
+{
+	int i, len = 0;
+
+	for (i = 0; i < 192; i++) {
+		if (irq_tab[i].count)
+			len += sprintf (buf+len, "Vec 0x%02x: %8d  %s\n",
+			    i+64, irq_tab[i].count,
+			    irq_tab[i].devname ? irq_tab[i].devname : "free");
+	}
+	return len;
+}
+
+
+static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+	panic ("Unknown interrupt 0x%02x", irq);
+}
+
+
+void mvme16x_enable_irq (unsigned int irq)
+{
+}
+
+
+void mvme16x_disable_irq (unsigned int irq)
+{
+}
+
+
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mvme16x/Makefile linux/arch/m68k/mvme16x/Makefile
--- v2.1.86/linux/arch/m68k/mvme16x/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme16x/Makefile	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/mvme16x 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 := mvme16x.o
+O_OBJS   := config.o 16xints.o
+#OX_OBJS = ksyms.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c
--- v2.1.86/linux/arch/m68k/mvme16x/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mvme16x/config.c	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,403 @@
+/*
+ *  arch/m68k/mvme16x/config.c
+ *
+ *  Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * Based on:
+ *
+ *  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.
+ */
+
+#include <linux/config.h>
+#include <stdarg.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 <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/mvme16xhw.h>
+
+typedef struct {
+	unsigned char
+		ctrl,
+		bcd_sec,
+		bcd_min,
+		bcd_hr,
+		bcd_dow,
+		bcd_dom,
+		bcd_mth,
+		bcd_year;
+} MK48T08;
+
+#define RTC_WRITE	0x80
+#define RTC_READ	0x40
+#define RTC_STOP	0x20
+
+int atari_SCC_reset_done = 1;		/* So SCC doesn't get reset */
+u_long atari_mch_cookie = 0;
+
+MK48T08 * volatile rtc = (MK48T08 *)0xfffc1ff8;
+
+extern void mvme16x_process_int (int level, struct pt_regs *regs);
+extern void mvme16x_init_IRQ (void);
+extern void mvme16x_free_irq (unsigned int, void *);
+extern int  mvme16x_get_irq_list (char *);
+extern void mvme16x_enable_irq (unsigned int);
+extern void mvme16x_disable_irq (unsigned int);
+static void mvme16x_get_model(char *model);
+static int  mvme16x_get_hardware_list(char *buffer);
+extern int  mvme16x_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void mvme16x_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int  mvme16x_keyb_init(void);
+extern int  mvme16x_kbdrate (struct kbd_repeat *);
+extern unsigned long mvme16x_gettimeoffset (void);
+extern void mvme16x_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec);
+extern int mvme16x_hwclk (int, struct hwclk_time *);
+extern int mvme16x_set_clock_mmss (unsigned long);
+extern void mvme16x_check_partition (struct gendisk *hd, unsigned int dev);
+extern void mvme16x_mksound( unsigned int count, unsigned int ticks );
+extern void mvme16x_reset (void);
+extern void mvme16x_waitbut(void);
+
+int bcd2int (unsigned char b);
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via mvme16x_process_int() */
+
+static void (*tick_handler)(int, void *, struct pt_regs *);
+
+
+unsigned short mvme16x_config;
+
+
+int mvme16x_kbdrate (struct kbd_repeat *k)
+{
+	return 0;
+}
+
+void mvme16x_mksound( unsigned int count, unsigned int ticks )
+{
+}
+
+void mvme16x_reset()
+{
+	printk ("\r\n\nCalled mvme16x_reset\r\n"
+			"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r");
+	/* The string of returns is to delay the reset until the whole
+	 * message is output.  Assert reset bit in GCSR */
+	*(volatile char *)0xfff40107 = 0x80;
+}
+
+static void mvme16x_get_model(char *model)
+{
+    p_bdid p = (p_bdid)mvme_bdid_ptr;
+    char suf[4];
+
+    suf[1] = p->brdsuffix[0];
+    suf[2] = p->brdsuffix[1];
+    suf[3] = '\0';
+    suf[0] = suf[1] ? '-' : '\0';
+
+    sprintf(model, "Motorola MVME%x%s", p->brdno, suf);
+}
+
+
+static int mvme16x_get_hardware_list(char *buffer)
+{
+    p_bdid p = (p_bdid)mvme_bdid_ptr;
+    int len = 0;
+
+    if (p->brdno == 0x0162 || p->brdno == 0x0172)
+    {
+	unsigned char rev = *(unsigned char *)MVME162_VERSION_REG;
+
+	len += sprintf (buffer+len, "VMEchip2        %spresent\n",
+			rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : "");
+	len += sprintf (buffer+len, "SCSI interface  %spresent\n",
+			rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : "");
+	len += sprintf (buffer+len, "Ethernet i/f    %spresent\n",
+			rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : "");
+    }
+    else
+	*buffer = '\0';
+
+    return (len);
+}
+
+
+__initfunc(void config_mvme16x(void))
+{
+    p_bdid p = (p_bdid)mvme_bdid_ptr;
+    char id[40];
+
+    mach_sched_init      = mvme16x_sched_init;
+    mach_keyb_init       = mvme16x_keyb_init;
+    mach_kbdrate         = mvme16x_kbdrate;
+    mach_init_IRQ        = mvme16x_init_IRQ;
+    mach_gettimeoffset   = mvme16x_gettimeoffset;
+    mach_gettod  	 = mvme16x_gettod;
+    mach_hwclk           = mvme16x_hwclk;
+    mach_set_clock_mmss	 = mvme16x_set_clock_mmss;
+/*  kd_mksound           = mvme16x_mksound; */
+    mach_reset		 = mvme16x_reset;
+    mach_free_irq	 = mvme16x_free_irq;
+    mach_process_int	 = mvme16x_process_int;
+    mach_get_irq_list	 = mvme16x_get_irq_list;
+    mach_request_irq	 = mvme16x_request_irq;
+    enable_irq           = mvme16x_enable_irq;
+    disable_irq          = mvme16x_disable_irq;
+    mach_get_model       = mvme16x_get_model;
+    mach_get_hardware_list = mvme16x_get_hardware_list;
+
+    /* Report board revision */
+
+    if (strncmp("BDID", p->bdid, 4))
+    {
+	printk ("\n\nBug call .BRD_ID returned garbage - giving up\n\n");
+	while (1)
+		;
+    }
+    mvme16x_get_model(id);
+    printk ("\nBRD_ID: %s   BUG %x.%x %02x/%02x/%02x\n", id, p->rev>>4,
+					p->rev&0xf, p->yr, p->mth, p->day);
+    if (p->brdno == 0x0162 || p->brdno == 0x172)
+    {
+	unsigned char rev = *(unsigned char *)MVME162_VERSION_REG;
+
+	mvme16x_config = rev | MVME16x_CONFIG_GOT_SCCA;
+
+	printk ("MVME%x Hardware status:\n", p->brdno);
+	printk ("    CPU Type           68%s040\n",
+			rev & MVME16x_CONFIG_GOT_FPU ? "" : "LC");
+	printk ("    CPU clock          %dMHz\n",
+			rev & MVME16x_CONFIG_SPEED_32 ? 32 : 25);
+	printk ("    VMEchip2           %spresent\n",
+			rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : "");
+	printk ("    SCSI interface     %spresent\n",
+			rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : "");
+	printk ("    Ethernet interface %spresent\n",
+			rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : "");
+    }
+    else
+	mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401;
+}
+
+static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+    *(volatile unsigned char *)0xfff4201b |= 8;
+    tick_handler(irq, dev_id, fp);
+}
+
+void mvme16x_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+    tick_handler = timer_routine;
+    /* Using PCCchip2 or MC2 chip tick timer 1 */
+    *(volatile unsigned long *)0xfff42008 = 0;
+    *(volatile unsigned long *)0xfff42004 = 10000;	/* 10ms */
+    *(volatile unsigned char *)0xfff42017 |= 3;
+    *(volatile unsigned char *)0xfff4201b = 0x16;
+    if (request_irq(IRQ_MVME16x_TIMER, mvme16x_timer_int, 0,
+				"timer", mvme16x_timer_int))
+	panic ("Couldn't register timer int");
+}
+
+
+/* This is always executed with interrupts disabled.  */
+unsigned long mvme16x_gettimeoffset (void)
+{
+    return (*(volatile unsigned long *)0xfff42008);
+}
+
+extern void mvme16x_gettod (int *year, int *mon, int *day, int *hour,
+                           int *min, int *sec)
+{
+	rtc->ctrl = RTC_READ;
+	*year = bcd2int (rtc->bcd_year);
+	*mon = bcd2int (rtc->bcd_mth);
+	*day = bcd2int (rtc->bcd_dom);
+	*hour = bcd2int (rtc->bcd_hr);
+	*min = bcd2int (rtc->bcd_min);
+	*sec = bcd2int (rtc->bcd_sec);
+	rtc->ctrl = 0;
+}
+
+int bcd2int (unsigned char b)
+{
+	return ((b>>4)*10 + (b&15));
+}
+
+int mvme16x_hwclk(int op, struct hwclk_time *t)
+{
+	return 0;
+}
+
+int mvme16x_set_clock_mmss (unsigned long nowtime)
+{
+	return 0;
+}
+
+/*
+ * console_map_init(), here to avoid having to modify drivers/block/genhd.c
+ */
+
+void console_map_init(void)
+{
+}
+
+/*
+ * fbmem_init(), here to avoid having to modify drivers/char/mem.c
+ */
+
+void fbmem_init(void)
+{
+}
+
+/* Avoid mods to drivers/char/tty_io.c */
+
+unsigned long con_init(unsigned long kmem_start)
+{
+	return (kmem_start);
+}
+
+/* Avoid mods to drivers/char/tty_io.c */
+
+int vcs_init(void)
+{
+	return (0);
+}
+
+/* Avoid mods to drivers/char/tty_io.c */
+
+int kbd_init(void)
+{
+	return (0);
+}
+
+/* Avoid mods to init/main.c */
+
+void no_scroll(char *str, int *ints)
+{
+}
+
+/* Avoid mods to kernel/panic.c */
+
+void do_unblank_screen(void)
+{
+}
+
+int mvme16x_keyb_init (void)
+{
+	return 0;
+}
+
+void mvme16x_set_vectors (void)
+{
+	p_bdid p = (p_bdid)mvme_bdid_ptr;
+	unsigned long *new = (unsigned long *)vectors;
+	unsigned long *old = (unsigned long *)0xffe00000;;
+
+	*(new+4) = *(old+4);		/* Illegal instruction */
+	*(new+9) = *(old+9);		/* Trace */
+	*(new+47) = *(old+47);		/* Trap #15 */
+
+	if (p->brdno == 0x0162 || p->brdno == 0x172)
+		*(new+0x5e) = *(old+0x5e);	/* ABORT switch */
+	else
+		*(new+0x6e) = *(old+0x6e);	/* ABORT switch */
+}
+
+/*-------------------  Serial console stuff ------------------------*/
+
+extern void mvme167_serial_console_setup(int cflag);
+extern void serial167_write(struct console *co, const char *str, unsigned cnt);
+extern void vme_scc_write(struct console *co, const char *str, unsigned cnt);
+
+
+void mvme16x_init_console_port (struct console *co, int cflag)
+{
+	p_bdid p = (p_bdid)mvme_bdid_ptr;
+
+	switch (p->brdno)
+	{
+#ifdef CONFIG_MVME162_SCC
+	case 0x0162:
+	case 0x0172:
+		co->write = vme_scc_write;
+		return;
+#endif
+#ifdef CONFIG_SERIAL167
+	case 0x0166:
+	case 0x0167:
+	case 0x0176:
+	case 0x0177:
+		co->write = serial167_write;
+		mvme167_serial_console_setup (cflag);
+		return;
+#endif
+	default:
+		panic ("No console support for MVME%x\n", p->brdno);
+	}
+	return;
+}
+
+
+#ifdef CONFIG_MVME162_SCC
+
+static void scc_delay (void)
+{
+	int n;
+	char i;
+
+	for (n = 0; n < 20; n++)
+		i = *(volatile char *)0;
+}
+
+static void scc_write (char ch)
+{
+	volatile char *p = (volatile char *)SCC_A_ADDR;
+
+	do {
+		scc_delay();
+	}
+	while (!(*p & 4));
+	scc_delay();
+	*p = 8;
+	scc_delay();
+	*p = ch;
+}
+
+
+void vme_scc_write (struct console *co, const char *str, unsigned count)
+{
+	unsigned long	flags;
+
+	save_flags(flags);
+	cli();
+
+	while (count--)
+	{
+		if (*str == '\n')
+			scc_write ('\r');
+		scc_write (*str++);
+	}
+	restore_flags(flags);
+}
+#endif
diff -u --recursive --new-file v2.1.86/linux/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds
--- v2.1.86/linux/arch/m68k/vmlinux.lds	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/vmlinux.lds	Thu Feb 12 16:30:13 1998
@@ -31,8 +31,7 @@
 	CONSTRUCTORS
 	}
 
-  . = ALIGN(8192);
-  init_task : { *(init_task) }	/* The initial task and kernel stack */
+  .bss : { *(.bss) }		/* BSS */
 
   _edata = .;			/* End of data section */
 
@@ -40,13 +39,11 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
-  . = ALIGN(4096);
+  . = ALIGN(8192);
   __init_end = .;
 
-  __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
+  init_task : { *(init_task) }	/* The initial task and kernel stack */
+
   _end = . ;
 
   /* Stabs debugging sections.  */
diff -u --recursive --new-file v2.1.86/linux/arch/sparc/ap1000/tnet.c linux/arch/sparc/ap1000/tnet.c
--- v2.1.86/linux/arch/sparc/ap1000/tnet.c	Thu Feb 12 20:56:04 1998
+++ linux/arch/sparc/ap1000/tnet.c	Wed Feb 11 16:16:43 1998
@@ -578,7 +578,7 @@
 
 static void free_skb(struct sk_buff *skb, int op)
 {
-	dev_kfree_skb(skb,op);
+	dev_kfree_skb(skb);
 }
 
 void tnet_send_ip(int cid,struct sk_buff *skb)
diff -u --recursive --new-file v2.1.86/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.86/linux/drivers/block/floppy.c	Fri Jan 23 18:10:31 1998
+++ linux/drivers/block/floppy.c	Fri Feb 13 17:02:11 1998
@@ -148,7 +148,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-static int can_use_virtual_dma=2;
+static int can_use_virtual_dma=0;
 /* =======
  * can use virtual DMA:
  * 0 = use of virtual DMA disallowed by config
diff -u --recursive --new-file v2.1.86/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.1.86/linux/drivers/block/ll_rw_blk.c	Sun Dec 28 12:05:44 1997
+++ linux/drivers/block/ll_rw_blk.c	Thu Feb 12 14:12:44 1998
@@ -35,6 +35,11 @@
 DECLARE_TASK_QUEUE(tq_disk);
 
 /*
+ * Protect the request list against multiple users..
+ */
+spinlock_t current_lock = SPIN_LOCK_UNLOCKED;
+
+/*
  * used to wait on when there are no free requests
  */
 struct wait_queue * wait_for_request = NULL;
diff -u --recursive --new-file v2.1.86/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.1.86/linux/drivers/char/bttv.c	Fri Jan 23 18:10:31 1998
+++ linux/drivers/char/bttv.c	Fri Feb 13 15:12:57 1998
@@ -1297,11 +1297,10 @@
 			struct video_audio v;
 			if(copy_from_user(&v,arg, sizeof(v)))
 				return -EFAULT;
+			if(v.audio!=0)
+				return -EINVAL;
 			if(v.flags&VIDEO_AUDIO_MUTE)
 				audio(btv, AUDIO_MUTE);
-			if(v.audio<0||v.audio>2)
-				return -EINVAL;
-			bt848_muxsel(btv,v.audio);
 			if(!(v.flags&VIDEO_AUDIO_MUTE))
 				audio(btv, AUDIO_UNMUTE);
 			btv->audio_dev=v;
diff -u --recursive --new-file v2.1.86/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.1.86/linux/drivers/char/esp.c	Mon Dec  1 09:45:43 1997
+++ linux/drivers/char/esp.c	Thu Feb 12 15:47:44 1998
@@ -29,9 +29,8 @@
  *     by Chris Faylor.
  *
  * Most recent changes: (Andrew J. Robinson)
- *   Added rx_trigger, tx_trigger, flow_off, flow_on, and rx_timeout options.
- *   ESP enhanced mode configuration can be viewed/changed by a patched
- *   version of setserial. 
+ *   Support for PIO mode.  This allows the driver to work properly with
+ *     multiport cards.
  *
  * This module exports the following rs232 io functions:
  *
@@ -94,13 +93,14 @@
 
 static char *dma_buffer;
 static int dma_bytes;
+static struct esp_pio_buffer *free_pio_buf;
 
 #define DMA_BUFFER_SZ 1024
 
 #define WAKEUP_CHARS 1024
 
 static char *serial_name = "ESP serial driver";
-static char *serial_version = "1.6";
+static char *serial_version = "2.0";
 
 static DECLARE_TASK_QUEUE(tq_esp);
 
@@ -135,7 +135,7 @@
 #define DBG_CNT(s)
 #endif
 
-static struct esp_struct *IRQ_ports[16];
+static struct esp_struct *ports;
 
 static void change_speed(struct esp_struct *info);
 static void rs_wait_until_sent(struct tty_struct *, int);
@@ -290,181 +290,249 @@
 	queue_task(&info->tqueue, &tq_esp);
 	mark_bh(ESP_BH);
 }
-
-static void receive_chars_dma(struct esp_struct *info)
+static _INLINE_ struct esp_pio_buffer *get_pio_buffer(void)
 {
-	info->stat_flags &= ~(ESP_STAT_RX_TIMEOUT | ESP_STAT_NEED_DMA_RX);
+	struct esp_pio_buffer *buf;
 
-	serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
-	serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL);
-	dma_bytes = serial_in(info, UART_ESI_STAT1) << 8;
-	dma_bytes |= serial_in(info, UART_ESI_STAT2);
+	if (free_pio_buf) {
+		buf = free_pio_buf;
+		free_pio_buf = buf->next;
+	} else {
+		buf = (struct esp_pio_buffer *)
+			kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC);
+	}
 
-	if (!dma_bytes)
-		return;
-        
-	info->stat_flags |= ESP_STAT_DMA_RX;
-        disable_dma(dma);
-        clear_dma_ff(dma);
-        set_dma_mode(dma, DMA_MODE_READ);
-        set_dma_addr(dma, virt_to_bus(dma_buffer));
-        set_dma_count(dma, dma_bytes);
-        enable_dma(dma);
-        serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
+	return buf;
 }
 
-static void do_ttybuf(void *private_)
+static _INLINE_ void release_pio_buffer(struct esp_pio_buffer *buf)
 {
-	struct esp_struct	*info = (struct esp_struct *) private_;
-	struct tty_struct	*tty;
-	int avail_bytes, x_bytes;
-	unsigned long int flags;
+	buf->next = free_pio_buf;
+	free_pio_buf = buf;
+}
 
-	save_flags(flags); cli();
+static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes)
+{
+	struct tty_struct *tty = info->tty;
+	int i;
+	struct esp_pio_buffer *pio_buf;
+	struct esp_pio_buffer *err_buf;
+	unsigned char status_mask;
+
+	pio_buf = get_pio_buffer();
+
+	if (!pio_buf)
+		return;
+
+	err_buf = get_pio_buffer();
+
+	if (!err_buf) {
+		release_pio_buffer(pio_buf);
+		return;
+	}
+
+	sti();
+	
+	status_mask = (info->read_status_mask >> 2) & 0x07;
+		
+	for (i = 0; i < num_bytes - 1; i += 2) {
+		*((unsigned short *)(pio_buf->data + i)) =
+			inw(info->port + UART_ESI_RX);
+		err_buf->data[i] = serial_in(info, UART_ESI_RWS);
+		err_buf->data[i + 1] = (err_buf->data[i] >> 3) & status_mask;
+		err_buf->data[i] &= status_mask;
+	}
+
+	if (num_bytes & 0x0001) {
+		pio_buf->data[num_bytes - 1] = serial_in(info, UART_ESI_RX);
+		err_buf->data[num_bytes - 1] =
+			(serial_in(info, UART_ESI_RWS) >> 3) & status_mask;
+	}
+
+	cli();
+
+	/* make sure everything is still ok since interrupts were enabled */
 	tty = info->tty;
 
 	if (!tty) {
-		restore_flags(flags);
+		release_pio_buffer(pio_buf);
+		release_pio_buffer(err_buf);
+		info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
 		return;
 	}
 
-	avail_bytes = TTY_FLIPBUF_SIZE - tty->flip.count;
+	status_mask = (info->ignore_status_mask >> 2) & 0x07;
 
-	if (avail_bytes) {
-		if (info->tty_buf->count < avail_bytes)
-			x_bytes = info->tty_buf->count;
-		else
-			x_bytes = avail_bytes;
+	for (i = 0; i < num_bytes; i++) {
+		if (!(err_buf->data[i] & status_mask)) {
+			*(tty->flip.char_buf_ptr++) = pio_buf->data[i];
 
-		tty->flip.count += x_bytes;
-		memcpy(tty->flip.char_buf_ptr, info->tty_buf->char_buf,
-			x_bytes);
-		memcpy(tty->flip.flag_buf_ptr, info->tty_buf->flag_buf,
-			x_bytes);
-		tty->flip.char_buf_ptr += x_bytes;
-		tty->flip.flag_buf_ptr += x_bytes;
-		info->tty_buf->count -= x_bytes;
-		info->tty_buf->char_buf_ptr -= x_bytes;
-		info->tty_buf->flag_buf_ptr -= x_bytes;
-
-		if (info->tty_buf->count) {
-			memmove(info->tty_buf->char_buf,
-				info->tty_buf->char_buf + x_bytes,
-				info->tty_buf->count);
-			queue_task(&info->tty_buf->tqueue,
-						&tq_timer);
-		}
+			if (err_buf->data[i] & 0x04) {
+				*(tty->flip.flag_buf_ptr++) = TTY_BREAK;
 
-		queue_task(&tty->flip.tqueue, &tq_timer);
-	} else {
-		queue_task(&info->tty_buf->tqueue, &tq_timer);
+				if (info->flags & ASYNC_SAK)
+					do_SAK(tty);
+			}
+			else if (err_buf->data[i] & 0x02)
+				*(tty->flip.flag_buf_ptr++) = TTY_FRAME;
+			else if (err_buf->data[i] & 0x01)
+				*(tty->flip.flag_buf_ptr++) = TTY_PARITY;
+			else
+				*(tty->flip.flag_buf_ptr++) = 0;
+		
+			tty->flip.count++;
+		}
 	}
 
-	restore_flags(flags);
+	queue_task(&tty->flip.tqueue, &tq_timer);
+
+	info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
+	release_pio_buffer(pio_buf);
+	release_pio_buffer(err_buf);
+}
+
+static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes)
+{
+	info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
+	dma_bytes = num_bytes;
+	info->stat_flags |= ESP_STAT_DMA_RX;
+        disable_dma(dma);
+        clear_dma_ff(dma);
+        set_dma_mode(dma, DMA_MODE_READ);
+        set_dma_addr(dma, virt_to_bus(dma_buffer));
+        set_dma_count(dma, dma_bytes);
+        enable_dma(dma);
+        serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
 }
 
 static _INLINE_ void receive_chars_dma_done(struct esp_struct *info,
 					    int status)
 {
 	struct tty_struct *tty = info->tty;
-	int num_bytes, bytes_left, x_bytes;
-	struct tty_flip_buffer *buffer;
-
-	if (!(info->stat_flags & ESP_STAT_DMA_RX))
-		return;
+	int num_bytes;
 
 	disable_dma(dma);
 	clear_dma_ff(dma);
 
 	info->stat_flags &= ~ESP_STAT_DMA_RX;
-	bytes_left = num_bytes = dma_bytes - get_dma_residue(dma);
+	num_bytes = dma_bytes - get_dma_residue(dma);
 	info->icount.rx += num_bytes;
-	buffer = &(tty->flip);
-
-	if (info->tty_buf->count && (tty->flip.count < TTY_FLIPBUF_SIZE))
-		do_ttybuf(info);
-
-	while (bytes_left > 0) {
-		if ((buffer->count + bytes_left) > TTY_FLIPBUF_SIZE)
-			x_bytes = TTY_FLIPBUF_SIZE - buffer->count;
-		else
-			x_bytes = bytes_left;
 
-		memcpy(buffer->char_buf_ptr,
-			 dma_buffer + (num_bytes - bytes_left), x_bytes);
-		buffer->char_buf_ptr += x_bytes;
-		buffer->count += x_bytes;
-		memset(buffer->flag_buf_ptr, 0, x_bytes);
-		buffer->flag_buf_ptr += x_bytes;
-		bytes_left -= x_bytes;
-
-		if (bytes_left > 0) {
-			if (buffer == info->tty_buf)
-				break;
-			else
-				buffer = info->tty_buf;
-		}
-	}
+	memcpy(tty->flip.char_buf_ptr, dma_buffer, num_bytes);
+	tty->flip.char_buf_ptr += num_bytes;
+	tty->flip.count += num_bytes;
+	memset(tty->flip.flag_buf_ptr, 0, num_bytes);
+	tty->flip.flag_buf_ptr += num_bytes;
 
 	if (num_bytes > 0) {
-		buffer->flag_buf_ptr--;
+		tty->flip.flag_buf_ptr--;
 
 		status &= (0x1c & info->read_status_mask);
 
 		if (status & info->ignore_status_mask) {
-			buffer->count--;
-			buffer->char_buf_ptr--;
-			buffer->flag_buf_ptr--;
+			tty->flip.count--;
+			tty->flip.char_buf_ptr--;
+			tty->flip.flag_buf_ptr--;
 		} else if (status & 0x10) {
-			*buffer->flag_buf_ptr = TTY_BREAK;
+			*tty->flip.flag_buf_ptr = TTY_BREAK;
 			(info->icount.brk)++;
 			if (info->flags & ASYNC_SAK)
 				do_SAK(tty);
 		} else if (status & 0x08) {
-			*buffer->flag_buf_ptr = TTY_FRAME;
+			*tty->flip.flag_buf_ptr = TTY_FRAME;
 			(info->icount.frame)++;
 		}
 		else if (status & 0x04) {
-			*buffer->flag_buf_ptr = TTY_PARITY;
+			*tty->flip.flag_buf_ptr = TTY_PARITY;
 			(info->icount.parity)++;
 		}
 
-		buffer->flag_buf_ptr++;
+		tty->flip.flag_buf_ptr++;
 		
-		if (buffer == info->tty_buf)
-			queue_task(&info->tty_buf->tqueue, &tq_timer);
-
 		queue_task(&tty->flip.tqueue, &tq_timer);
 	}
 
 	if (dma_bytes != num_bytes) {
+		num_bytes = dma_bytes - num_bytes;
 		dma_bytes = 0;
-		receive_chars_dma(info);
+		receive_chars_dma(info, num_bytes);
 	} else
 		dma_bytes = 0;
 }
 
-static void transmit_chars_dma(struct esp_struct *info)
+static _INLINE_ void transmit_chars_pio(struct esp_struct *info,
+					int space_avail)
 {
-	info->stat_flags &= ~ESP_STAT_NEED_DMA_TX;
+	int i;
+	struct esp_pio_buffer *pio_buf;
 
-	if ((info->xmit_cnt <= 0) || info->tty->stopped) {
-		info->IER &= ~UART_IER_THRI;
-		serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
-		serial_out(info, UART_ESI_CMD2, info->IER);
+	pio_buf = get_pio_buffer();
+
+	if (!pio_buf)
 		return;
+
+	while (space_avail && info->xmit_cnt) {
+		if (info->xmit_tail + space_avail <= ESP_XMIT_SIZE) {
+			memcpy(pio_buf->data,
+			       &(info->xmit_buf[info->xmit_tail]),
+			       space_avail);
+		} else {
+			i = ESP_XMIT_SIZE - info->xmit_tail;
+			memcpy(pio_buf->data,
+			       &(info->xmit_buf[info->xmit_tail]), i);
+			memcpy(&(pio_buf->data[i]), info->xmit_buf,
+			       space_avail - i);
+		}
+
+		info->xmit_cnt -= space_avail;
+		info->xmit_tail = (info->xmit_tail + space_avail) &
+			(ESP_XMIT_SIZE - 1);
+
+		sti();
+
+		for (i = 0; i < space_avail - 1; i += 2) {
+			outw(*((unsigned short *)(pio_buf->data + i)),
+			     info->port + UART_ESI_TX);
+		}
+
+		if (space_avail & 0x0001)
+			serial_out(info, UART_ESI_TX,
+				   pio_buf->data[space_avail - 1]);
+
+		cli();
+
+		if (info->xmit_cnt) {
+			serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
+			serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
+			space_avail = serial_in(info, UART_ESI_STAT1) << 8;
+			space_avail |= serial_in(info, UART_ESI_STAT2);
+
+			if (space_avail > info->xmit_cnt)
+				space_avail = info->xmit_cnt;
+		}
 	}
-	
-	serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
-	serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
-	dma_bytes = serial_in(info, UART_ESI_STAT1) << 8;
-	dma_bytes |= serial_in(info, UART_ESI_STAT2);
 
-	if (!dma_bytes)
-		return;
+	if (info->xmit_cnt < WAKEUP_CHARS) {
+		rs_sched_event(info, ESP_EVENT_WRITE_WAKEUP);
 
-	if (dma_bytes > info->xmit_cnt)
-		dma_bytes = info->xmit_cnt;
+#ifdef SERIAL_DEBUG_INTR
+		printk("THRE...");
+#endif
+
+		if (info->xmit_cnt <= 0) {
+			info->IER &= ~UART_IER_THRI;
+			serial_out(info, UART_ESI_CMD1,
+				   ESI_SET_SRV_MASK);
+			serial_out(info, UART_ESI_CMD2, info->IER);
+		}
+	}
+
+	release_pio_buffer(pio_buf);
+}
+
+static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes)
+{
+	dma_bytes = num_bytes;
 
 	if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) {
 		memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]),
@@ -507,9 +575,6 @@
 {
 	int num_bytes;
 
-	if (!(info->stat_flags & ESP_STAT_DMA_TX))
-		return;
-
 	disable_dma(dma);
 	clear_dma_ff(dma);
 
@@ -564,8 +629,7 @@
 #ifdef SERIAL_DEBUG_OPEN
 			printk("scheduling hangup...");
 #endif
-			queue_task(&info->tqueue_hangup,
-					   &tq_scheduler);
+			queue_task(&info->tqueue_hangup, &tq_scheduler);
 		}
 	}
 }
@@ -575,92 +639,104 @@
  */
 static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct esp_struct * info, *stop_port = 0;
+	struct esp_struct * info;
 	unsigned err_status;
 	unsigned int scratch;
-	int pre_bytes;
-	
+
 #ifdef SERIAL_DEBUG_INTR
 	printk("rs_interrupt_single(%d)...", irq);
 #endif
-	
-	/* This routine will currently check ALL ports when an interrupt */
-	/* is received from ANY port */
+	info = (struct esp_struct *)dev_id;
+	err_status = 0;
+	scratch = serial_in(info, UART_ESI_SID);
 
-	info = IRQ_ports[irq];
-
-	if (!info)
+	cli();
+	
+	if (!info->tty) {
+		sti();
 		return;
+	}
 
-	do {
-		if (!info->tty) {
-			info = info->next_port;
-			continue;
-		}
-
-		pre_bytes = dma_bytes;
-		err_status = 0;
-		scratch = serial_in(info, UART_ESI_SID);
-		if (scratch & 0x04) { /* error - check for rx timeout */
-			serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT);
-			err_status = serial_in(info, UART_ESI_STAT1);
-			serial_in(info, UART_ESI_STAT2);
+	if (scratch & 0x04) { /* error */
+		serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT);
+		err_status = serial_in(info, UART_ESI_STAT1);
+		serial_in(info, UART_ESI_STAT2);
 
-			if (err_status & 0x01)
-				info->stat_flags |= ESP_STAT_RX_TIMEOUT;
+		if (err_status & 0x01)
+			info->stat_flags |= ESP_STAT_RX_TIMEOUT;
 
-			if (err_status & 0x20)	/* UART status */
-				check_modem_status(info);
+		if (err_status & 0x20) /* UART status */
+			check_modem_status(info);
 
-			if (err_status & 0x80)	/* Start break */
-				wake_up_interruptible(&info->break_wait);
-		}
+		if (err_status & 0x80) /* Start break */
+			wake_up_interruptible(&info->break_wait);
+	}
 		
-		if ((scratch & 0x88)  || /* DMA completed or timed out */
-			(err_status & 0x1c) /* receive error */) {
-				receive_chars_dma_done(info, err_status);
-				transmit_chars_dma_done(info);
-		}
+	if ((scratch & 0x88) || /* DMA completed or timed out */
+	    (err_status & 0x1c) /* receive error */) {
+		if (info->stat_flags & ESP_STAT_DMA_RX)
+			receive_chars_dma_done(info, err_status);
+		else if (info->stat_flags & ESP_STAT_DMA_TX)
+			transmit_chars_dma_done(info);
+	}
 
-		if (((scratch & 0x01) ||
-			(info->stat_flags & ESP_STAT_RX_TIMEOUT)) &&
-			(info->IER & UART_IER_RDI))
-			if (dma_bytes)
-				info->stat_flags |= ESP_STAT_NEED_DMA_RX;
-			else
-				receive_chars_dma(info);
+	if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) &&
+	    ((scratch & 0x01) || (info->stat_flags & ESP_STAT_RX_TIMEOUT)) &&
+	    (info->IER & UART_IER_RDI)) {
+		int num_bytes;
 
-		if ((scratch & 0x02) && (info->IER & UART_IER_THRI))
-			if (dma_bytes)
-				info->stat_flags |= ESP_STAT_NEED_DMA_TX;
+		serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
+		serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL);
+		num_bytes = serial_in(info, UART_ESI_STAT1) << 8;
+		num_bytes |= serial_in(info, UART_ESI_STAT2);
+
+		if (num_bytes > (TTY_FLIPBUF_SIZE - info->tty->flip.count))
+		  num_bytes = TTY_FLIPBUF_SIZE - info->tty->flip.count;
+
+		if (num_bytes) {
+			if (dma_bytes ||
+			    (info->stat_flags & ESP_STAT_USE_PIO) ||
+			    (num_bytes <= ESP_PIO_THRESHOLD))
+				receive_chars_pio(info, num_bytes);
 			else
-				transmit_chars_dma(info);
-
-		info->last_active = jiffies;
-
-		if (pre_bytes && !dma_bytes)  /* released DMA */
-			stop_port = info;
-
-		info = info->next_port;
-	} while ((info->irq == irq) && (info != IRQ_ports[irq]));
+				receive_chars_dma(info, num_bytes);
+		}
+	}
+	
+	if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) &&
+	    (scratch & 0x02) && (info->IER & UART_IER_THRI)) {
+		if ((info->xmit_cnt <= 0) || info->tty->stopped) {
+			info->IER &= ~UART_IER_THRI;
+			serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
+			serial_out(info, UART_ESI_CMD2, info->IER);
+		} else {
+			int num_bytes;
 
-	if (stop_port) {
-		while ((info != stop_port) && (!dma_bytes)) {
-			if (info->tty) {
-				if (info->stat_flags & ESP_STAT_NEED_DMA_RX)
-					receive_chars_dma(info);
-				if ((info->stat_flags & ESP_STAT_NEED_DMA_TX)
-				    && !dma_bytes)
-					transmit_chars_dma(info);
+			serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
+			serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
+			num_bytes = serial_in(info, UART_ESI_STAT1) << 8;
+			num_bytes |= serial_in(info, UART_ESI_STAT2);
+
+			if (num_bytes > info->xmit_cnt)
+				num_bytes = info->xmit_cnt;
+
+			if (num_bytes) {
+				if (dma_bytes ||
+				    (info->stat_flags & ESP_STAT_USE_PIO) ||
+				    (num_bytes <= ESP_PIO_THRESHOLD))
+					transmit_chars_pio(info, num_bytes);
+				else
+					transmit_chars_dma(info, num_bytes);
 			}
-			
-			info = info->next_port;
 		}
 	}
 
+	info->last_active = jiffies;
+
 #ifdef SERIAL_DEBUG_INTR
 	printk("end.\n");
 #endif
+	sti();
 }
 
 /*
@@ -734,7 +810,11 @@
 {
 	/* put ESPC in enhanced mode */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
-	serial_out(info, UART_ESI_CMD2, 0x31);
+	
+	if (info->stat_flags & ESP_STAT_NEVER_DMA)
+		serial_out(info, UART_ESI_CMD2, 0x01);
+	else
+		serial_out(info, UART_ESI_CMD2, 0x31);
 
 	/* disable interrupts for now */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
@@ -742,8 +822,14 @@
 
 	/* set interrupt and DMA channel */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_IRQ);
-	serial_out(info, UART_ESI_CMD2, (dma << 4) | 0x01);
+
+	if (info->stat_flags & ESP_STAT_NEVER_DMA)
+		serial_out(info, UART_ESI_CMD2, 0x01);
+	else
+		serial_out(info, UART_ESI_CMD2, (dma << 4) | 0x01);
+
 	serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ);
+
 	if (info->line % 8)	/* secondary port */
 		serial_out(info, UART_ESI_CMD2, 0x0d);	/* shared */
 	else if (info->irq == 9)
@@ -753,7 +839,12 @@
 
 	/* set error status mask (check this) */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_ERR_MASK);
-	serial_out(info, UART_ESI_CMD2, 0xbd);
+
+	if (info->stat_flags & ESP_STAT_NEVER_DMA)
+		serial_out(info, UART_ESI_CMD2, 0xa1);
+	else
+		serial_out(info, UART_ESI_CMD2, 0xbd);
+
 	serial_out(info, UART_ESI_CMD2, 0x00);
 
 	/* set DMA timeout */
@@ -767,9 +858,9 @@
 	serial_out(info, UART_ESI_CMD2, tx_trigger >> 8);
 	serial_out(info, UART_ESI_CMD2, tx_trigger);
 
-	/* Set clock scaling */
+	/* Set clock scaling and wait states */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_PRESCALAR);
-	serial_out(info, UART_ESI_CMD2, ESPC_SCALE);
+	serial_out(info, UART_ESI_CMD2, 0x04 | ESPC_SCALE);
 
 	/* set reinterrupt pacing */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_REINTR);
@@ -780,43 +871,23 @@
 {
 	unsigned long flags;
 	int	retval=0;
-	int next_irq;
-	struct esp_struct *next_info = 0;
         unsigned int num_chars;
 
 	save_flags(flags); cli();
 
-	if (info->flags & ASYNC_INITIALIZED)
-		goto errout;
+	if (info->flags & ASYNC_INITIALIZED) {
+		restore_flags(flags);
+		return retval;
+	}
 
 	if (!info->xmit_buf) {
 		info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL);
 		if (!info->xmit_buf) {
-			retval = -ENOMEM;
-			goto errout;
+			restore_flags(flags);
+			return -ENOMEM;
 		}
 	}
 
-	if (!info->tty_buf) {
-		info->tty_buf = (struct tty_flip_buffer *)kmalloc(
-			sizeof(struct tty_flip_buffer), GFP_KERNEL);
-
-		if (!info->tty_buf) {
-			free_page((unsigned long) info->xmit_buf);
-			info->xmit_buf = 0;
-			retval = -ENOMEM;
-			goto errout;
-		}
-
-		memset(info->tty_buf, 0, sizeof(struct tty_flip_buffer));
-		info->tty_buf->tqueue.routine = do_ttybuf;
-		info->tty_buf->tqueue.data = info;
-	} 
-
-	info->tty_buf->count = 0;
-	info->tty_buf->char_buf_ptr = info->tty_buf->char_buf;
-	info->tty_buf->flag_buf_ptr = info->tty_buf->flag_buf;
-
 #ifdef SERIAL_DEBUG_OPEN
 	printk("starting up ttys%d (irq %d)...", info->line, info->irq);
 #endif
@@ -841,44 +912,45 @@
 	serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
 	serial_out(info, UART_ESI_CMD2, rx_timeout);
 
-	info->stat_flags = 0;
+	/* clear all flags except the "never DMA" flag */
+	info->stat_flags &= ESP_STAT_NEVER_DMA;
+
+	if (info->stat_flags & ESP_STAT_NEVER_DMA)
+		info->stat_flags |= ESP_STAT_USE_PIO;
 
 	/*
-	 * Allocate the IRQ if necessary
+	 * Allocate the IRQ
 	 */
-	if (!IRQ_ports[info->irq]) {
-		retval = request_irq(info->irq, rs_interrupt_single,
-					SA_INTERRUPT, "esp serial", NULL);
-
-		if (!retval) {
-			int i = 1;
-
-			while ((i < 16) && !IRQ_ports[i])
-				i++;	
-
-			if (i == 16) {
-				dma_buffer = (char *)__get_dma_pages(GFP_KERNEL,
-					__get_order(DMA_BUFFER_SZ));
 
-				if (!dma_buffer)
-					retval = -ENOMEM;
-				else
-					retval = request_dma(dma, "esp serial");
+	retval = request_irq(info->irq, rs_interrupt_single, SA_SHIRQ,
+			     "esp serial", info);
 
-				if (retval)
-					free_irq(info->irq, NULL);
-			}
+	if (retval) {
+		if (suser()) {
+			if (info->tty)
+				set_bit(TTY_IO_ERROR,
+					&info->tty->flags);
+			retval = 0;
 		}
+		
+		restore_flags(flags);
+		return retval;
+	}
 
-		if (retval) {
-			if (suser()) {
-				if (info->tty)
-					set_bit(TTY_IO_ERROR,
-						&info->tty->flags);
-				retval = 0;
-			}
-			goto errout;
+	if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) {
+		dma_buffer = (char *)__get_dma_pages(
+			GFP_KERNEL, __get_order(DMA_BUFFER_SZ));
+
+		/* use PIO mode if DMA buf/chan cannot be allocated */
+		if (!dma_buffer)
+			info->stat_flags |= ESP_STAT_USE_PIO;
+		else if (request_dma(dma, "esp serial")) {
+			free_pages((unsigned int)dma_buffer,
+				   __get_order(DMA_BUFFER_SZ));
+			dma_buffer = 0;
+			info->stat_flags |= ESP_STAT_USE_PIO;
 		}
+			
 	}
 
 	info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
@@ -899,38 +971,6 @@
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
-	/* Remove port from "closed" chain */
-	if (info->next_port)
-		info->next_port->prev_port = info->prev_port;
-	if (info->prev_port)
-		info->prev_port->next_port = info->next_port;
-	else
-		IRQ_ports[0] = info->next_port;
-
-	/*
-	 * Insert serial port into IRQ chain.
-	 */
-	next_irq = info->irq;
-
-	do {
-		next_info = IRQ_ports[next_irq];
-		
-		if (++next_irq > 15)
-			next_irq = 1;
-	} while (!next_info && (next_irq != info->irq));
-
-	if (!next_info) {
-		info->next_port = info;
-		info->prev_port = info;
-	} else {
-		info->next_port = next_info;
-		info->prev_port = next_info->prev_port;
-		next_info->prev_port->next_port = info;
-		next_info->prev_port = info;
-	}
-
-	IRQ_ports[info->irq] = info;
-
 	/*
 	 * Set up the tty->alt_speed kludge
 	 */
@@ -953,10 +993,6 @@
 	info->flags |= ASYNC_INITIALIZED;
 	restore_flags(flags);
 	return 0;
-
-errout:
-	restore_flags(flags);
-	return retval;
 }
 
 /*
@@ -984,67 +1020,36 @@
 	wake_up_interruptible(&info->delta_msr_wait);
 	wake_up_interruptible(&info->break_wait);
 
-	/* stop a DMA transfer on the port being closed, and start the next
-	   one */
+	/* stop a DMA transfer on the port being closed */
 	   
 	if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
-		struct esp_struct *curr = info->next_port;
-		
 		disable_dma(dma);
 		clear_dma_ff(dma);
 		dma_bytes = 0;
-
-		while ((curr != info) && (!dma_bytes)) {
-			if (curr->tty) {
-				if (curr->stat_flags & ESP_STAT_NEED_DMA_RX)
-					receive_chars_dma(curr);
-				if ((curr->stat_flags & ESP_STAT_NEED_DMA_TX)
-				    && !dma_bytes)
-					transmit_chars_dma(curr);
-			}
-
-			curr = curr->next_port;
-		}
 	}
 	
 	/*
-	 * First unlink the serial port from the IRQ chain...
+	 * Free the IRQ
 	 */
-	info->next_port->prev_port = info->prev_port;
-	info->prev_port->next_port = info->next_port;
+	free_irq(info->irq, info);
 
-	if (IRQ_ports[info->irq] == info) {
-		if ((info->next_port == info) ||
-			(info->next_port->irq != info->irq))
-			IRQ_ports[info->irq] = 0;
-		else
-			IRQ_ports[info->irq] = info->next_port;
-	}
+	if (dma_buffer) {
+		struct esp_struct *current_port = ports;
 
-	/* Stick it on the "closed" chain */
-	info->next_port = IRQ_ports[0];
-	if (info->next_port)
-		info->next_port->prev_port = info;
-	info->prev_port = 0;
-	IRQ_ports[0] = info;
-	
-	/*
-	 * Free the IRQ, if necessary
-	 */
-	if (!IRQ_ports[info->irq]) {
-		int i = 1;
+		while (current_port) {
+			if ((current_port != info) &&
+			    (current_port->flags & ASYNC_INITIALIZED))
+				break;
 
-		while ((i < 16) && !IRQ_ports[i])
-			i++;
+			current_port = current_port->next_port;
+		}
 
-		if (i == 16) {
+		if (!current_port) {
 			free_dma(dma);
-			free_pages((unsigned int)dma_buffer, 
-				__get_order(DMA_BUFFER_SZ));
+			free_pages((unsigned int)dma_buffer,
+				   __get_order(DMA_BUFFER_SZ));
 			dma_buffer = 0;
-		}
-
-		free_irq(info->irq, NULL);
+		}		
 	}
 
 	if (info->xmit_buf) {
@@ -1052,25 +1057,6 @@
 		info->xmit_buf = 0;
 	}
 
-	if (info->tty_buf) {
-		/* code borrowed from tty_io.c */
-		if (info->tty_buf->tqueue.sync) {
-			struct tq_struct *tq, *prev;
-
-			for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
-				if (tq == &info->tty_buf->tqueue) {
-					if (prev)
-						prev->next = tq->next;
-					else
-						tq_timer = tq->next;
-					break;
-				}
-			}
-		}
-		kfree(info->tty_buf);
-		info->tty_buf = 0;
-	}
-
 	info->IER = 0;
 	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 	serial_out(info, UART_ESI_CMD2, 0x00);
@@ -1477,9 +1463,9 @@
 {
 	struct serial_struct new_serial;
 	struct esp_struct old_info;
-	unsigned int		change_irq;
+	unsigned int change_irq;
 	unsigned int change_flow;
-	int 			i, retval = 0;
+	int retval = 0;
 	struct esp_struct *current_async;
 
 	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
@@ -1522,102 +1508,97 @@
 		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
 			       (new_serial.flags & ASYNC_USR_MASK));
 		info->custom_divisor = new_serial.custom_divisor;
-		goto check_and_exit;
-	}
-
-	if (new_serial.irq == 2)
-		new_serial.irq = 9;
-
-	if (change_irq) {
-		i = 1;
-
-		while ((i < 16) && !IRQ_ports[i])
-			i++;
+	} else {
+		if (new_serial.irq == 2)
+			new_serial.irq = 9;
 
-		if (i < 16) {
-			current_async = IRQ_ports[i];
+		if (change_irq) {
+			current_async = ports;
 
-			do {
+			while (current_async) {
 				if ((current_async->line >= info->line) &&
 				    (current_async->line < (info->line + 8))) {
 					if (current_async == info) {
 						if (current_async->count > 1)
 							return -EBUSY;
-					} else
+					} else if (current_async->count)
 						return -EBUSY;
 				}
 
 				current_async = current_async->next_port;
-			} while (current_async != IRQ_ports[i]);
+			}
 		}
-	}
-
-	/*
-	 * OK, past this point, all the error checking has been done.
-	 * At this point, we start making changes.....
-	 */
-
-	info->flags = ((info->flags & ~ASYNC_FLAGS) |
-			(new_serial.flags & ASYNC_FLAGS));
-	info->custom_divisor = new_serial.custom_divisor;
-	info->close_delay = new_serial.close_delay * HZ/100;
-	info->closing_wait = new_serial.closing_wait * HZ/100;
-	flow_off = new_serial.reserved[2];
-	flow_on = new_serial.reserved[3];
-
-	if ((new_serial.reserved[0] != rx_trigger) ||
-	    (new_serial.reserved[1] != tx_trigger)) {
-		unsigned long flags;
-
-		rx_trigger = new_serial.reserved[0];
-		tx_trigger = new_serial.reserved[1];
-		save_flags(flags); cli();
-		serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
-		serial_out(info, UART_ESI_CMD2, rx_trigger >> 8);
-		serial_out(info, UART_ESI_CMD2, rx_trigger);
-		serial_out(info, UART_ESI_CMD2, tx_trigger >> 8);
-		serial_out(info, UART_ESI_CMD2, tx_trigger);
-		restore_flags(flags);
-	}
 
-	if (((unsigned char)(new_serial.reserved_char[1]) != rx_timeout)) {
-		unsigned long flags;
+		/*
+		 * OK, past this point, all the error checking has been done.
+		 * At this point, we start making changes.....
+		 */
 
-		rx_timeout = (unsigned char)(new_serial.reserved_char[1]);
-		save_flags(flags); cli();
+		info->flags = ((info->flags & ~ASYNC_FLAGS) |
+			       (new_serial.flags & ASYNC_FLAGS));
+		info->custom_divisor = new_serial.custom_divisor;
+		info->close_delay = new_serial.close_delay * HZ/100;
+		info->closing_wait = new_serial.closing_wait * HZ/100;
+		flow_off = new_serial.reserved[2];
+		flow_on = new_serial.reserved[3];
+
+		if ((new_serial.reserved[0] != rx_trigger) ||
+		    (new_serial.reserved[1] != tx_trigger)) {
+			unsigned long flags;
+
+			rx_trigger = new_serial.reserved[0];
+			tx_trigger = new_serial.reserved[1];
+			save_flags(flags); cli();
+			serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
+			serial_out(info, UART_ESI_CMD2, rx_trigger >> 8);
+			serial_out(info, UART_ESI_CMD2, rx_trigger);
+			serial_out(info, UART_ESI_CMD2, tx_trigger >> 8);
+			serial_out(info, UART_ESI_CMD2, tx_trigger);
+			restore_flags(flags);
+		}
+
+		if (((unsigned char)(new_serial.reserved_char[1]) !=
+		     rx_timeout)) {
+			unsigned long flags;
+
+			rx_timeout = (unsigned char)
+				(new_serial.reserved_char[1]);
+			save_flags(flags); cli();
+
+			if (info->IER & UART_IER_RDI) {
+				serial_out(info, UART_ESI_CMD1,
+					   ESI_SET_RX_TIMEOUT);
+				serial_out(info, UART_ESI_CMD2, rx_timeout);
+			}
 
-		if (info->IER & UART_IER_RDI) {
-			serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
-			serial_out(info, UART_ESI_CMD2, rx_timeout);
+			restore_flags(flags);
 		}
 
-		restore_flags(flags);
-	}
+		if (change_irq) {
+			/*
+			 * We need to shutdown the serial port at the old
+			 * port/irq combination.
+			 */
+			shutdown(info);
 
-	if (change_irq) {
-		/*
-		 * We need to shutdown the serial port at the old
-		 * port/irq combination.
-		 */
-		shutdown(info);
+			current_async = ports;
 
-		current_async = IRQ_ports[0];
-		while (current_async != 0) {
-			if ((current_async->line >= info->line) &&
-				(current_async->line < (info->line + 8)))
-				current_async->irq = new_serial.irq;
+			while (current_async) {
+				if ((current_async->line >= info->line) &&
+				    (current_async->line < (info->line + 8)))
+					current_async->irq = new_serial.irq;
 
-			current_async = current_async->next_port;
-		}
+				current_async = current_async->next_port;
+			}
 
-		serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ);
-		if (info->irq == 9)
-			serial_out(info, UART_ESI_CMD2, 0x02);
-		else
-			serial_out(info, UART_ESI_CMD2, info->irq);
+			serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ);
+			if (info->irq == 9)
+				serial_out(info, UART_ESI_CMD2, 0x02);
+			else
+				serial_out(info, UART_ESI_CMD2, info->irq);
+		}
 	}
-	
-check_and_exit:
+
 	if (info->flags & ASYNC_INITIALIZED) {
 		if (((old_info.flags & ASYNC_SPD_MASK) !=
 		     (info->flags & ASYNC_SPD_MASK)) ||
@@ -1635,6 +1616,7 @@
 		}
 	} else
 		retval = startup(info);
+
 	return retval;
 }
 
@@ -2237,43 +2219,24 @@
 static int esp_open(struct tty_struct *tty, struct file * filp)
 {
 	struct esp_struct	*info;
-	int 			i, retval, line;
+	int 			retval, line;
 	unsigned long		page;
 
 	line = MINOR(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_PORTS))
 		return -ENODEV;
 
-	/* check whether or not the port is on the closed chain */
+	/* find the port in the chain */
 
-	info = IRQ_ports[0];
+	info = ports;
 
 	while (info && (info->line != line))
 		info = info->next_port;
 
-	/* if the port is not on the closed chain, look for it on the */
-	/* open chain */
-
 	if (!info) {
-		i = 1;
-
-		while ((i < 16) && !IRQ_ports[i])
-			i++;
-
-		if (i < 16) {
-			info = IRQ_ports[i];
-
-			do {
-				if (info->line == line)
-					break;
-				info = info->next_port;
-			} while (info != IRQ_ports[i]);
-		}
-	}
-
-	if (!info || (info->line != line) || 
-		serial_paranoia_check(info, tty->device, "esp_open"))
+		serial_paranoia_check(info, tty->device, "esp_open");
 		return -ENODEV;
+	}
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("esp_open %s%d, count = %d\n", tty->driver.name, info->line,
@@ -2379,8 +2342,7 @@
 					info->irq = 4;
 			}
 
-			if (IRQ_ports[0] &&
-			    (IRQ_ports[0]->port == (info->port - 8))) {
+			if (ports && (ports->port == (info->port - 8))) {
 				release_region(*region_start,
 					       info->port - *region_start);
 			} else
@@ -2414,14 +2376,11 @@
 	int i, offset;
 	int region_start;
 	struct esp_struct * info;
+	struct esp_struct *last_primary = 0;
 	int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380};
 	
 	init_bh(ESP_BH, do_serial_bh);
 
-	for (i = 0; i < 16; i++) {
-		IRQ_ports[i] = 0;
-	}
-
 	for (i = 0; i < NR_PRIMARY; i++)
 		if (irq[i] != 0)
 			if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) ||
@@ -2431,7 +2390,7 @@
 				irq[i] = 9;
 
 	if ((dma != 1) && (dma != 3))
-		dma = 1;
+		dma = 0;
 
 	if ((rx_trigger < 1) || (rx_trigger > 1023))
 		rx_trigger = 768;
@@ -2552,21 +2511,27 @@
 		info->tqueue_hangup.data = info;
 		info->callout_termios = esp_callout_driver.init_termios;
 		info->normal_termios = esp_driver.init_termios;
-
-		if (IRQ_ports[0])
-			IRQ_ports[0]->prev_port = info;
-		info->next_port = IRQ_ports[0];
-		info->prev_port = 0;
-		IRQ_ports[0] = info;
+		info->next_port = ports;
+		ports = info;
 		printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ",
 			info->line, info->port, info->irq);
-		if (info->line % 8)
+
+		if (info->line % 8) {
 			printk("secondary port\n");
-		else {
+			/* 8 port cards can't do DMA */
+			info->stat_flags |= ESP_STAT_NEVER_DMA;
+
+			if (last_primary)
+				last_primary->stat_flags |= ESP_STAT_NEVER_DMA;
+		} else {
 			printk("primary port\n");
+			last_primary = info;
 			irq[i] = info->irq;
 		}
 
+		if (!dma)
+			info->stat_flags |= ESP_STAT_NEVER_DMA;
+
 		info = (struct esp_struct *)kmalloc(sizeof(struct esp_struct),
 			GFP_KERNEL);
 		if (!info)
@@ -2605,7 +2570,8 @@
 	unsigned long flags;
 	int e1, e2;
 	unsigned int region_start, region_end;
-	struct esp_struct *current_async, *temp_async;
+	struct esp_struct *temp_async;
+	struct esp_pio_buffer *pio_buf;
 
 	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
 	save_flags(flags);
@@ -2619,22 +2585,21 @@
 		       e2);
 	restore_flags(flags);
 
-	current_async = IRQ_ports[0];
-	while (current_async != 0) {
-		if (current_async->port != 0) {
-			region_start = region_end = current_async->port;
-			temp_async = current_async;
+	while (ports) {
+		if (ports->port) {
+			region_start = region_end = ports->port;
+			temp_async = ports;
 
-			while (temp_async != 0) {
+			while (temp_async) {
 				if ((region_start - temp_async->port) == 8) {
 					region_start = temp_async->port;
 					temp_async->port = 0;
-					temp_async = current_async;
+					temp_async = ports;
 				} else if ((temp_async->port - region_end)
 					   == 8) {
 					region_end = temp_async->port;
 					temp_async->port = 0;
-					temp_async = current_async;
+					temp_async = ports;
 				} else
 					temp_async = temp_async->next_port;
 			}
@@ -2643,9 +2608,9 @@
 				       region_end - region_start + 8);
 		}
 
-		temp_async = current_async->next_port;
-		kfree(current_async);
-		current_async = temp_async;
+		temp_async = ports->next_port;
+		kfree(ports);
+		ports = temp_async;
 	}
 
 	if (dma_buffer)
@@ -2654,5 +2619,11 @@
 
 	if (tmp_buf)
 		free_page((unsigned long)tmp_buf);
+
+	while (free_pio_buf) {
+		pio_buf = free_pio_buf->next;
+		kfree(free_pio_buf);
+		free_pio_buf = pio_buf;
+	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.86/linux/drivers/char/esp.h linux/drivers/char/esp.h
--- v2.1.86/linux/drivers/char/esp.h	Tue Dec 31 11:30:29 1996
+++ linux/drivers/char/esp.h	Thu Feb 12 15:47:44 1998
@@ -46,10 +46,13 @@
 #define ESI_NO_COMMAND		0xff
 
 #define ESP_STAT_RX_TIMEOUT	0x01
-#define ESP_STAT_NEED_DMA_RX	0x02
-#define ESP_STAT_NEED_DMA_TX    0x04
-#define ESP_STAT_DMA_RX		0x08
-#define ESP_STAT_DMA_TX		0x10
+#define ESP_STAT_DMA_RX		0x02
+#define ESP_STAT_DMA_TX		0x04
+#define ESP_STAT_NEVER_DMA      0x08
+#define ESP_STAT_USE_PIO        0x10
+
+/* Always use PIO for this number (or less) of bytes */
+#define ESP_PIO_THRESHOLD       32
 
 #define ESP_EVENT_WRITE_WAKEUP	0
 #define ESP_MAGIC		0x53ee
@@ -82,7 +85,6 @@
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
-	struct tty_flip_buffer	*tty_buf;
 	struct tq_struct	tqueue;
 	struct tq_struct	tqueue_hangup;
 	struct termios		normal_termios;
@@ -93,9 +95,13 @@
 	struct wait_queue	*break_wait;
 	struct async_icount	icount;	/* kernel counters for the 4 input interrupts */
 	struct esp_struct	*next_port; /* For the linked list */
-	struct esp_struct	*prev_port;
 };
 
+struct esp_pio_buffer
+{
+	unsigned char data[1024];
+	struct esp_pio_buffer *next;
+};
 
 #endif /* ESP_H */
 
diff -u --recursive --new-file v2.1.86/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.1.86/linux/drivers/char/pty.c	Sat Jun 28 10:31:36 1997
+++ linux/drivers/char/pty.c	Thu Feb 12 16:25:04 1998
@@ -2,6 +2,9 @@
  *  linux/drivers/char/pty.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Added support for a Unix98-style ptmx device.
+ *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
  */
 
 #include <linux/errno.h>
@@ -191,6 +194,45 @@
 	return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
 }
 
+/*
+ * Return the minor device number of a given pty.  This lets us
+ * open a master pty with the multi-headed ptmx device, then
+ * find out which one we got after it is open, with an ioctl.
+ */
+static int pty_get_device_minor(struct tty_struct *tty, unsigned int *value)
+{
+	unsigned int result = MINOR(tty->device);
+	return put_user(result, value);
+}
+/* Set the lock flag on a pty */
+static int pty_set_lock(struct tty_struct *tty, int * arg)
+{
+	int val;
+	if (get_user(val,arg))
+		return -EFAULT;
+	if (val)
+		set_bit(TTY_PTY_LOCK, &tty->flags);
+	else
+		clear_bit(TTY_PTY_LOCK, &tty->flags);
+	return 0;
+}
+
+static int pty_ioctl(struct tty_struct *tty, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	if (!tty) {
+		printk("pty_ioctl called with NULL tty!\n");
+		return -EIO;
+	}
+	switch(cmd) {
+	case TIOCGPTN: /* Get PT Number */
+		return pty_get_device_minor(tty, (unsigned int *)arg);
+	case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+		return pty_set_lock(tty, (int *) arg);
+	}
+	return -ENOIOCTLCMD;
+}
+
 static void pty_flush_buffer(struct tty_struct *tty)
 {
 	struct tty_struct *to = tty->link;
@@ -225,6 +267,8 @@
 	retval = -EIO;
 	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
 		goto out;
+	if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
+		goto out;
 	if (tty->link->count != 1)
 		goto out;
 
@@ -304,6 +348,12 @@
 	old_pty_slave_driver.minor_start = 192;
 	old_pty_slave_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS;
 	old_pty_slave_driver.other = &old_pty_driver;
+
+	/* only the master pty gets this ioctl (which is why we
+	 * assign it here, instead of up with the rest of the
+	 * pty_driver initialization. <cananian@alumni.princeton.edu>
+	 */
+	pty_driver.ioctl = pty_ioctl;
 
 	if (tty_register_driver(&pty_driver))
 		panic("Couldn't register pty driver");
diff -u --recursive --new-file v2.1.86/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.1.86/linux/drivers/char/tty_io.c	Wed Dec 31 16:40:08 1997
+++ linux/drivers/char/tty_io.c	Thu Feb 12 16:25:04 1998
@@ -51,6 +51,9 @@
  *
  * Rewrote init_dev and release_dev to eliminate races.
  *	-- Bill Hawes <whawes@star.net>, June 97
+ *
+ * Added support for a Unix98-style ptmx device.
+ *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
  */
 
 #include <linux/config.h>
@@ -91,6 +94,7 @@
 #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
 #define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
 #define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
+#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2)
 
 #undef TTY_DEBUG_HANGUP
 
@@ -1171,7 +1175,6 @@
 static int tty_open(struct inode * inode, struct file * filp)
 {
 	struct tty_struct *tty;
-	int minor;
 	int noctty, retval;
 	kdev_t device;
 	unsigned short saved_flags;
@@ -1203,12 +1206,39 @@
                 device = c->device(c);
 		noctty = 1;
 	}
-	minor = MINOR(device);
-
+	if (device == PTMX_DEV) {
+		/* find a free pty. */
+		struct tty_driver *driver = tty_drivers;
+		int minor;
+
+		/* find the pty driver */
+		for (driver=tty_drivers; driver; driver=driver->next)
+			if (driver->major == PTY_MASTER_MAJOR)
+				break;
+		if (!driver) return -ENODEV;
+
+		/* find a minor device that is not in use. */
+		for (minor=driver->minor_start;
+		     minor<driver->minor_start+driver->num;
+		     minor++) {
+			device = MKDEV(driver->major, minor);
+			retval = init_dev(device, &tty);
+			if (retval==0) break; /* success! */
+		}
+		if (minor==driver->minor_start+driver->num) /* no success */
+			return -EIO; /* no free ptys */
+		
+		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+		noctty = 1;
+		goto init_dev_done;
+	}
+	
 	retval = init_dev(device, &tty);
 	if (retval)
 		return retval;
+
 	/* N.B. this error exit may leave filp->f_flags with O_NONBLOCK set */
+init_dev_done:
 	filp->private_data = tty;
 	check_tty_count(tty, "tty_open");
 	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
@@ -1932,7 +1962,7 @@
 }
 
 static struct tty_driver dev_tty_driver, dev_console_driver,
-	dev_syscons_driver;
+	dev_syscons_driver, dev_ptmx_driver;
 
 /*
  * Ok, now we can initialize the rest of the tty devices and can count
@@ -1973,6 +2003,17 @@
 
 	if (tty_register_driver(&dev_syscons_driver))
 		panic("Couldn't register /dev/console driver\n");
+
+	dev_ptmx_driver = dev_tty_driver;
+	dev_ptmx_driver.driver_name = "/dev/ptmx";
+	dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5;
+	dev_ptmx_driver.major= MAJOR(PTMX_DEV);
+	dev_ptmx_driver.minor_start = MINOR(PTMX_DEV);
+	dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+	dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX;
+
+	if (tty_register_driver(&dev_ptmx_driver))
+		panic("Couldn't register /dev/ptmx driver\n");
 
 #ifdef CONFIG_VT
 	dev_console_driver = dev_tty_driver;
diff -u --recursive --new-file v2.1.86/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.1.86/linux/drivers/isdn/isdn_common.c	Thu Feb 12 20:56:06 1998
+++ linux/drivers/isdn/isdn_common.c	Wed Feb 11 16:23:08 1998
@@ -261,10 +261,10 @@
 #endif
 
 static __inline void
-isdn_trash_skb(struct sk_buff *skb, int rw)
+isdn_trash_skb(struct sk_buff *skb)
 {
 	SET_SKB_FREE(skb);
-	kfree_skb(skb, rw);
+	kfree_skb(skb);
 }
 
 static void
diff -u --recursive --new-file v2.1.86/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c
--- v2.1.86/linux/drivers/misc/parport_procfs.c	Thu Feb 12 20:56:07 1998
+++ linux/drivers/misc/parport_procfs.c	Thu Feb 12 16:46:29 1998
@@ -32,7 +32,7 @@
 static int irq_write_proc(struct file *file, const char *buffer,
 					  unsigned long count, void *data)
 {
-	unsigned int newirq, oldirq;
+	int newirq, oldirq;
 	struct parport *pp = (struct parport *)data;
 	
 	if (count > 5 )  /* more than 4 digits + \n for a irq 0x?? 0?? ??  */
diff -u --recursive --new-file v2.1.86/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.1.86/linux/drivers/pci/oldproc.c	Fri Jan 30 11:28:08 1998
+++ linux/drivers/pci/oldproc.c	Thu Feb 12 15:03:09 1998
@@ -70,6 +70,10 @@
 	DEVICE( VLSI,		VLSI_82C597,	"82C597-AFC2"),
 	DEVICE( VLSI,		VLSI_82C541,	"82C541 Lynx"),
 	DEVICE( VLSI,		VLSI_82C543,	"82C543 Lynx ISA"),
+	DEVICE( VLSI,		VLSI_82C532,	"82C532"),
+	DEVICE( VLSI,		VLSI_82C534,	"82C534"),
+	DEVICE( VLSI,		VLSI_82C535,	"82C535"),
+	DEVICE( VLSI,		VLSI_82C147,	"82C147"),
 	DEVICE( VLSI,		VLSI_VAS96011,	"VAS96011 (Golden Gate II)"),
 	DEVICE( ADL,		ADL_2301,	"2301"),
 	DEVICE( NS,		NS_87415,	"87415"),
@@ -90,6 +94,7 @@
 	DEVICE( DEC,		DEC_TULIP_PLUS,	"DC21041"),
 	DEVICE( DEC,		DEC_21142,	"DC21142"),
 	DEVICE( DEC,		DEC_21052,	"DC21052"),
+	DEVICE( DEC,		DEC_21150,	"DC21150"),
 	DEVICE( DEC,		DEC_21152,	"DC21152"),
 	DEVICE( CIRRUS,		CIRRUS_7548,	"GD 7548"),
 	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430"),
@@ -108,10 +113,12 @@
 	DEVICE( IBM,		IBM_FIRE_CORAL,	"Fire Coral"),
 	DEVICE( IBM,		IBM_TR,		"Token Ring"),
 	DEVICE( IBM,		IBM_82G2675,	"82G2675"),
+	DEVICE( IBM,		IBM_MCA,	"MicroChannel"),
 	DEVICE( IBM,		IBM_82351,	"82351"),
 	DEVICE( WD,		WD_7197,	"WD 7197"),
 	DEVICE( AMD,		AMD_LANCE,	"79C970"),
 	DEVICE( AMD,		AMD_SCSI,	"53C974"),
+	DEVICE( TRIDENT,	TRIDENT_9397,	"Cyber9397"),
 	DEVICE( TRIDENT,	TRIDENT_9420,	"TG 9420"),
 	DEVICE( TRIDENT,	TRIDENT_9440,	"TG 9440"),
 	DEVICE( TRIDENT,	TRIDENT_9660,	"TG 9660 / Cyber9385"),
@@ -121,6 +128,7 @@
 	DEVICE( MATROX,		MATROX_MIL,	"Millennium"),
 	DEVICE( MATROX,		MATROX_MYS,	"Mystique"),
 	DEVICE( MATROX,		MATROX_MIL_2,	"Millennium II"),
+	DEVICE( MATROX,		MATROX_MIL_2_AGP,"Millennium II AGP"),
 	DEVICE( MATROX,		MATROX_MGA_IMP,	"MGA Impression"),
 	DEVICE( CT,		CT_65545,	"65545"),
 	DEVICE( CT,		CT_65548,	"65548"),
@@ -146,6 +154,9 @@
 	DEVICE( HP,		HP_J2585B,	"J2585B (Lassen)"),
 	DEVICE( PCTECH,		PCTECH_RZ1000,  "RZ1000 (buggy)"),
 	DEVICE( PCTECH,		PCTECH_RZ1001,  "RZ1001 (buggy?)"),
+	DEVICE( PCTECH,		PCTECH_SAMURAI_0,"Samurai 0"),
+	DEVICE( PCTECH,		PCTECH_SAMURAI_1,"Samurai 1"),
+	DEVICE( PCTECH,		PCTECH_SAMURAI_IDE,"Samurai IDE"),
 	DEVICE( DPT,		DPT,		"SmartCache/Raid"),
 	DEVICE( OPTI,		OPTI_92C178,	"92C178"),
 	DEVICE( OPTI,		OPTI_82C557,	"82C557 Viper-M"),
@@ -155,6 +166,7 @@
 	DEVICE( OPTI,		OPTI_82C701,	"82C701 FireStar Plus"),
 	DEVICE( OPTI,		OPTI_82C814,	"82C814 Firebridge 1"),
 	DEVICE( OPTI,		OPTI_82C822,	"82C822"),
+	DEVICE( OPTI,		OPTI_82C825,	"82C825 Firebridge 2"),
 	DEVICE( SGS,		SGS_2000,	"STG 2000X"),
 	DEVICE( SGS,		SGS_1764,	"STG 1764X"),
 	DEVICE( BUSLOGIC,	BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC"),
@@ -164,6 +176,7 @@
 	DEVICE( TI,		TI_TVP4020,	"TVP4020 Permedia 2"),
 	DEVICE( TI,		TI_PCI1130,	"PCI1130"),
 	DEVICE( TI,		TI_PCI1131,	"PCI1131"),
+	DEVICE( TI,		TI_PCI1250,	"PCI1250"),
 	DEVICE( OAK,		OAK_OTI107,	"OTI107"),
 	DEVICE( WINBOND2,	WINBOND2_89C940,"NE2000-PCI"),
 	DEVICE( MOTOROLA,	MOTOROLA_MPC105,"MPC105 Eagle"),
@@ -216,12 +229,15 @@
 	DEVICE( VISION,		VISION_QD8500,	"QD-8500"),
 	DEVICE( VISION,		VISION_QD8580,	"QD-8580"),
 	DEVICE( BROOKTREE,	BROOKTREE_848,	"Bt848"),
+	DEVICE( BROOKTREE,	BROOKTREE_849A,	"Bt849"),
+	DEVICE( BROOKTREE,	BROOKTREE_8474,	"Bt8474"),
 	DEVICE( SIERRA,		SIERRA_STB,	"STB Horizon 64"),
 	DEVICE( ACC,		ACC_2056,	"2056"),
 	DEVICE( WINBOND,	WINBOND_83769,	"W83769F"),
 	DEVICE( WINBOND,	WINBOND_82C105,	"SL82C105"),
 	DEVICE( WINBOND,	WINBOND_83C553,	"W83C553"),
 	DEVICE( DATABOOK,      	DATABOOK_87144,	"DB87144"),
+	DEVICE( PLX,		PLX_9080,	"PCI9080 I2O"),
 	DEVICE( 3COM,		3COM_3C590,	"3C590 10bT"),
 	DEVICE( 3COM,		3COM_3C595TX,	"3C595 100bTX"),
 	DEVICE( 3COM,		3COM_3C595T4,	"3C595 100bT4"),
@@ -241,9 +257,11 @@
 	DEVICE( AL,		AL_M1523,	"M1523"),
 	DEVICE( AL,		AL_M1531,	"M1531 Aladdin IV"),
 	DEVICE( AL,		AL_M1533,	"M1533 Aladdin IV"),
+	DEVICE( AL,		AL_M3307,	"M3307 MPEG-1 decoder"),
 	DEVICE( AL,		AL_M4803,	"M4803"),
 	DEVICE( AL,		AL_M5219,	"M5219"),
 	DEVICE( AL,		AL_M5229,	"M5229 TXpro"),
+	DEVICE( AL,		AL_M5237,	"M5237 USB"),
 	DEVICE( SURECOM,	SURECOM_NE34,	"NE-34PCI LAN"),
 	DEVICE( NEOMAGIC,       NEOMAGIC_MAGICGRAPH_NM2070,     "Magicgraph NM2070"),
 	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"),
@@ -251,6 +269,7 @@
 	DEVICE( NEOMAGIC,	NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"),
 	DEVICE( ASP,		ASP_ABP940,	"ABP940"),
 	DEVICE( ASP,		ASP_ABP940U,	"ABP940U"),
+	DEVICE( ASP,		ASP_ABP940UW,	"ABP940UW"),
 	DEVICE( CERN,		CERN_SPSB_PMC,	"STAR/RD24 SCI-PCI (PMC)"),
 	DEVICE( CERN,		CERN_SPSB_PCI,	"STAR/RD24 SCI-PCI (PMC)"),
 	DEVICE( IMS,		IMS_8849,	"8849"),
@@ -265,6 +284,7 @@
 	DEVICE( REALTEK,	REALTEK_8129,	"8129"),
 	DEVICE( TRUEVISION,	TRUEVISION_T1000,"TARGA 1000"),
 	DEVICE( INIT,		INIT_320P,	"320 P"),
+	DEVICE( INIT,		INIT_360P,	"360 P"),
 	DEVICE( VIA,		VIA_82C505,	"VT 82C505"),
 	DEVICE( VIA,		VIA_82C561,	"VT 82C561"),
 	DEVICE( VIA,		VIA_82C586_1,	"VT 82C586 Apollo IDE"),
@@ -272,11 +292,13 @@
 	DEVICE( VIA,		VIA_82C585,	"VT 82C585 Apollo VP1/VPX"),
 	DEVICE( VIA,		VIA_82C586_0,	"VT 82C586 Apollo ISA"),
 	DEVICE( VIA,		VIA_82C595,	"VT 82C595 Apollo VP2"),
+	DEVICE( VIA,		VIA_82C597_0,	"VT 82C597 Apollo VP3"),
 	DEVICE( VIA,		VIA_82C926,	"VT 82C926 Amazon"),
 	DEVICE( VIA,		VIA_82C416,	"VT 82C416MV"),
 	DEVICE( VIA,		VIA_82C595_97,	"VT 82C595 Apollo VP2/97"),
 	DEVICE( VIA,		VIA_82C586_2,	"VT 82C586 Apollo USB"),
 	DEVICE( VIA,		VIA_82C586_3,	"VT 82C586B Apollo ACPI"),
+	DEVICE( VIA,		VIA_82C597_1,	"VT 82C597 Apollo VP3 AGP"),
 	DEVICE( VORTEX,		VORTEX_GDT60x0,	"GDT 60x0"),
 	DEVICE( VORTEX,		VORTEX_GDT6000B,"GDT 6000b"),
 	DEVICE( VORTEX,		VORTEX_GDT6x10,	"GDT 6110/6510"),
@@ -315,23 +337,33 @@
 	DEVICE( FORE,		FORE_PCA200E,	 "PCA-200E"),
 	DEVICE( IMAGINGTECH,	IMAGINGTECH_ICPCI, "MVC IC-PCI"),
 	DEVICE( PHILIPS,	PHILIPS_SAA7146,"SAA7146"),
-	DEVICE( PLX,		PLX_9060,	"PCI9060 i960 bridge"),
+	DEVICE( CYCLONE,	CYCLONE_SDK,	"SDK"),
 	DEVICE( ALLIANCE,	ALLIANCE_PROMOTIO, "Promotion-6410"),
 	DEVICE( ALLIANCE,	ALLIANCE_PROVIDEO, "Provideo"),
 	DEVICE( ALLIANCE,	ALLIANCE_AT24,	"AT24"),
 	DEVICE( ALLIANCE,	ALLIANCE_AT3D,	"AT3D"),
 	DEVICE( VMIC,		VMIC_VME,	"VMIVME-7587"),
+	DEVICE( DIGI,		DIGI_EPC,	"AccelPort EPC"),
  	DEVICE( DIGI,		DIGI_RIGHTSWITCH, "RightSwitch SE-6"),
+	DEVICE( DIGI,		DIGI_XEM,	"AccelPort Xem"),
+	DEVICE( DIGI,		DIGI_XR,	"AccelPort Xr"),
+	DEVICE( DIGI,		DIGI_CX,	"AccelPort C/X"),
+	DEVICE( DIGI,		DIGI_XRJ,	"AccelPort Xr/J"),
+	DEVICE( DIGI,		DIGI_EPCJ,	"AccelPort EPC/J"),
 	DEVICE( MUTECH,		MUTECH_MV1000,	"MV-1000"),
 	DEVICE( RENDITION,	RENDITION_VERITE,"Verite 1000"),
 	DEVICE( RENDITION,	RENDITION_VERITE2100,"Verite 2100"),
 	DEVICE( TOSHIBA,	TOSHIBA_601,	"Laptop"),
+	DEVICE( TOSHIBA,	TOSHIBA_TOPIC95,"ToPIC95"),
+	DEVICE( TOSHIBA,	TOSHIBA_TOPIC97,"ToPIC97"),
 	DEVICE( RICOH,		RICOH_RL5C466,	"RL5C466"),
+	DEVICE( ARTOP,		ARTOP_ATP850UF,	"ATP850UF"),
 	DEVICE( ZEITNET,	ZEITNET_1221,	"1221"),
 	DEVICE( ZEITNET,	ZEITNET_1225,	"1225"),
 	DEVICE( OMEGA,		OMEGA_82C092G,	"82C092G"),
 	DEVICE( LITEON,		LITEON_LNE100TX,"LNE100TX"),
 	DEVICE( NP,		NP_PCI_FDDI,	"NP-PCI"),       
+	DEVICE( ATT,		ATT_L56XMF,	"L56xMF"),
 	DEVICE( SPECIALIX,	SPECIALIX_XIO,	"XIO/SIO host"),
 	DEVICE( SPECIALIX,	SPECIALIX_RIO,	"RIO host"),
 	DEVICE( AURAVISION,	AURAVISION_VXP524,"VXP524"),
@@ -349,11 +381,12 @@
 	DEVICE( CYCLADES,	CYCLOM_Y_Hi,	"Cyclom-Y above 1Mbyte"),
 	DEVICE( CYCLADES,	CYCLOM_Z_Lo,	"Cyclom-Z below 1Mbyte"),
 	DEVICE( CYCLADES,	CYCLOM_Z_Hi,	"Cyclom-Z above 1Mbyte"),
+	DEVICE( O2,		O2_6832,	"6832"),
 	DEVICE( 3DFX,		3DFX_VOODOO,	"Voodoo"),
+	DEVICE( SIGMADES,	SIGMADES_6425,	"REALmagic64/GX"),
 	DEVICE( STALLION,	STALLION_ECHPCI832,"EasyConnection 8/32"),
 	DEVICE( STALLION,	STALLION_ECHPCI864,"EasyConnection 8/64"),
 	DEVICE( STALLION,	STALLION_EIOPCI,"EasyIO"),
-	DEVICE( SIGMADES,	SIGMADES_6425,	"REALmagic64/GX"),
 	DEVICE( OPTIBASE,	OPTIBASE_FORGE,	"MPEG Forge"),
 	DEVICE( OPTIBASE,	OPTIBASE_FUSION,"MPEG Fusion"),
 	DEVICE( OPTIBASE,	OPTIBASE_VPLEX,	"VideoPlex"),
@@ -391,6 +424,7 @@
 	DEVICE( S3,		S3_ViRGE_MX,	"ViRGE/MX"),
 	DEVICE( S3,		S3_ViRGE_MXP,	"ViRGE/MX+"),
 	DEVICE( S3,		S3_ViRGE_MXPMV,	"ViRGE/MX+MV"),
+	DEVICE( S3,		S3_SONICVIBES,	"SonicVibes"),
 	DEVICE( INTEL,		INTEL_82375,	"82375EB"),
 	DEVICE( INTEL,		INTEL_82424,	"82424ZX Saturn"),
 	DEVICE( INTEL,		INTEL_82378,	"82378IB"),
@@ -615,6 +649,7 @@
 	      case PCI_VENDOR_ID_ACC:		return "ACC MICROELECTRONICS";
 	      case PCI_VENDOR_ID_WINBOND:	return "Winbond";
 	      case PCI_VENDOR_ID_DATABOOK:	return "Databook";
+	      case PCI_VENDOR_ID_PLX:		return "PLX";
 	      case PCI_VENDOR_ID_3COM:		return "3Com";
 	      case PCI_VENDOR_ID_SMC:		return "SMC";
 	      case PCI_VENDOR_ID_AL:		return "Acer Labs";
@@ -638,7 +673,7 @@
 	      case PCI_VENDOR_ID_FORE:		return "Fore Systems";
 	      case PCI_VENDOR_ID_IMAGINGTECH:	return "Imaging Technology";
 	      case PCI_VENDOR_ID_PHILIPS:	return "Philips";
-	      case PCI_VENDOR_ID_PLX:		return "PLX";
+	      case PCI_VENDOR_ID_CYCLONE:	return "Cyclone";
 	      case PCI_VENDOR_ID_ALLIANCE:	return "Alliance";
 	      case PCI_VENDOR_ID_VMIC:		return "VMIC";
 	      case PCI_VENDOR_ID_DIGI:		return "Digi Intl.";
@@ -646,10 +681,12 @@
 	      case PCI_VENDOR_ID_RENDITION:	return "Rendition";
 	      case PCI_VENDOR_ID_TOSHIBA:	return "Toshiba";
 	      case PCI_VENDOR_ID_RICOH:		return "Ricoh";
+	      case PCI_VENDOR_ID_ARTOP:		return "Artop Electronics";
 	      case PCI_VENDOR_ID_ZEITNET:	return "ZeitNet";
 	      case PCI_VENDOR_ID_OMEGA:		return "Omega Micro";
 	      case PCI_VENDOR_ID_LITEON:	return "LiteOn";
 	      case PCI_VENDOR_ID_NP:		return "Network Peripherals";
+	      case PCI_VENDOR_ID_ATT:		return "Lucent (ex-AT&T) Microelectronics";
 	      case PCI_VENDOR_ID_SPECIALIX:	return "Specialix";
 	      case PCI_VENDOR_ID_AURAVISION:	return "Auravision";
 	      case PCI_VENDOR_ID_IKON:		return "Ikon";
@@ -657,6 +694,7 @@
 	      case PCI_VENDOR_ID_COMPEX:	return "Compex";
 	      case PCI_VENDOR_ID_RP:		return "Comtrol";
 	      case PCI_VENDOR_ID_CYCLADES:	return "Cyclades";
+	      case PCI_VENDOR_ID_O2:		return "O2 Micro";
 	      case PCI_VENDOR_ID_3DFX:		return "3Dfx";
 	      case PCI_VENDOR_ID_STALLION:	return "Stallion Technologies";
 	      case PCI_VENDOR_ID_SIGMADES:	return "Sigma Designs";
@@ -868,4 +906,4 @@
 	return len;
 }
 
-#endif
+#endif /* CONFIG_PROC_FS */
diff -u --recursive --new-file v2.1.86/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.1.86/linux/drivers/sbus/char/vfc_dev.c	Wed Jul 16 19:22:51 1997
+++ linux/drivers/sbus/char/vfc_dev.c	Wed Feb 11 16:19:56 1998
@@ -666,9 +666,6 @@
 int vfc_init(void)
 #endif
 {
-#ifdef MODULE
-	register_symtab(0);
-#endif
 	return vfc_probe();
 }
 
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.1.86/linux/drivers/scsi/BusLogic.c	Fri Jan 23 18:10:32 1998
+++ linux/drivers/scsi/BusLogic.c	Sat Jan 31 02:00:00 1998
@@ -6,8 +6,7 @@
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
-  Free Software Foundation, provided that none of the source code or runtime
-  copyright notices are removed or modified.
+  Free Software Foundation.
 
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
@@ -27,17 +26,17 @@
 */
 
 
-#define BusLogic_DriverVersion		"2.0.10"
-#define BusLogic_DriverDate		"11 August 1997"
+#define BusLogic_DriverVersion		"2.0.11"
+#define BusLogic_DriverDate		"31 January 1998"
 
 
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
-#include <linux/kernel_stat.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
@@ -45,30 +44,43 @@
 #include <linux/bios32.h>
 #include <asm/dma.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/system.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
 #include "BusLogic.h"
+#include "FlashPoint.c"
 
 
 /*
-  BusLogic_CommandLineEntryCount is a count of the number of "BusLogic="
-  entries provided on the Linux Kernel Command Line.
+  BusLogic_DriverOptionsCount is a count of the number of BusLogic Driver
+  Options specifications provided via the Linux Kernel Command Line or via
+  the Loadable Kernel Module Installation Facility.
 */
 
 static int
-  BusLogic_CommandLineEntryCount =	0;
+  BusLogic_DriverOptionsCount =			0;
 
 
 /*
-  BusLogic_CommandLineEntries is an array of Command Line Entry structures
-  representing the "BusLogic=" entries provided on the Linux Kernel Command
-  Line.
+  BusLogic_DriverOptions is an array of Driver Options structures representing
+  BusLogic Driver Options specifications provided via the Linux Kernel Command
+  Line or via the Loadable Kernel Module Installation Facility.
 */
 
-static BusLogic_CommandLineEntry_T
-  BusLogic_CommandLineEntries[BusLogic_MaxHostAdapters];
+static BusLogic_DriverOptions_T
+  BusLogic_DriverOptions[BusLogic_MaxHostAdapters];
+
+
+/*
+  BusLogic_Options can be assigned a string by the Loadable Kernel Module
+  Installation Facility to be parsed for BusLogic Driver Options
+  specifications.
+*/
+
+static char
+  *BusLogic_Options =				NULL;
 
 
 /*
@@ -77,7 +89,7 @@
 */
 
 static BusLogic_ProbeOptions_T
-  BusLogic_ProbeOptions =		{ 0 };
+  BusLogic_ProbeOptions =			{ 0 };
 
 
 /*
@@ -86,7 +98,17 @@
 */
 
 static BusLogic_GlobalOptions_T
-  BusLogic_GlobalOptions =		{ 0 };
+  BusLogic_GlobalOptions =			{ 0 };
+
+
+/*
+  BusLogic_FirstRegisteredHostAdapter and BusLogic_LastRegisteredHostAdapter
+  are pointers to the first and last registered BusLogic Host Adapters.
+*/
+
+static BusLogic_HostAdapter_T
+  *BusLogic_FirstRegisteredHostAdapter =	NULL,
+  *BusLogic_LastRegisteredHostAdapter =		NULL;
 
 
 /*
@@ -99,11 +121,11 @@
 
 
 /*
-  BusLogic_ProbeInfoCount is the numbers of entries in BusLogic_ProbeInfoList.
+  BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList.
 */
 
 static int
-  BusLogic_ProbeInfoCount =		0;
+  BusLogic_ProbeInfoCount =			0;
 
 
 /*
@@ -114,7 +136,7 @@
 */
 
 static BusLogic_ProbeInfo_T
-  BusLogic_ProbeInfoList[BusLogic_MaxHostAdapters] =	{ { 0 } };
+  *BusLogic_ProbeInfoList =			NULL;
 
 
 /*
@@ -133,8 +155,8 @@
 */
 
 static BusLogic_CCB_T
-  *BusLogic_FirstCompletedCCB =		NULL,
-  *BusLogic_LastCompletedCCB =		NULL;
+  *BusLogic_FirstCompletedCCB =			NULL,
+  *BusLogic_LastCompletedCCB =			NULL;
 
 
 /*
@@ -181,6 +203,17 @@
 
 static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 {
+  HostAdapter->NextAll = NULL;
+  if (BusLogic_FirstRegisteredHostAdapter == NULL)
+    {
+      BusLogic_FirstRegisteredHostAdapter = HostAdapter;
+      BusLogic_LastRegisteredHostAdapter = HostAdapter;
+    }
+  else
+    {
+      BusLogic_LastRegisteredHostAdapter->NextAll = HostAdapter;
+      BusLogic_LastRegisteredHostAdapter = HostAdapter;
+    }
   HostAdapter->Next = NULL;
   if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != NULL)
     {
@@ -202,14 +235,33 @@
 
 static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 {
+  if (HostAdapter == BusLogic_FirstRegisteredHostAdapter)
+    {
+      BusLogic_FirstRegisteredHostAdapter =
+	BusLogic_FirstRegisteredHostAdapter->NextAll;
+      if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
+	BusLogic_LastRegisteredHostAdapter = NULL;
+    }
+  else
+    {
+      BusLogic_HostAdapter_T *PreviousHostAdapter =
+	BusLogic_FirstRegisteredHostAdapter;
+      while (PreviousHostAdapter != NULL &&
+	     PreviousHostAdapter->NextAll != HostAdapter)
+	PreviousHostAdapter = PreviousHostAdapter->NextAll;
+      if (PreviousHostAdapter != NULL)
+	PreviousHostAdapter->NextAll = HostAdapter->NextAll;
+    }
+  HostAdapter->NextAll = NULL;
   if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != HostAdapter)
     {
-      BusLogic_HostAdapter_T *LastHostAdapter =
+      BusLogic_HostAdapter_T *PreviousHostAdapter =
 	BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
-      while (LastHostAdapter != NULL && LastHostAdapter->Next != HostAdapter)
-	LastHostAdapter = LastHostAdapter->Next;
-      if (LastHostAdapter != NULL)
-	LastHostAdapter->Next = HostAdapter->Next;
+      while (PreviousHostAdapter != NULL &&
+	     PreviousHostAdapter->Next != HostAdapter)
+	PreviousHostAdapter = PreviousHostAdapter->Next;
+      if (PreviousHostAdapter != NULL)
+	PreviousHostAdapter->Next = HostAdapter->Next;
     }
   else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] =
 	 HostAdapter->Next;
@@ -218,85 +270,33 @@
 
 
 /*
-  BusLogic_CreateMailboxes allocates the Outgoing and Incoming Mailboxes for
-  Host Adapter.
-*/
-
-static boolean BusLogic_CreateMailboxes(BusLogic_HostAdapter_T *HostAdapter)
-{
-  /*
-    FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes.
-  */
-  if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
-  /*
-    Allocate space for the Outgoing and Incoming Mailboxes.
-  */
-  HostAdapter->FirstOutgoingMailbox =
-    (BusLogic_OutgoingMailbox_T *)
-      scsi_init_malloc(HostAdapter->MailboxCount
-		       * (sizeof(BusLogic_OutgoingMailbox_T)
-			  + sizeof(BusLogic_IncomingMailbox_T)),
-		       (HostAdapter->BounceBuffersRequired
-			? GFP_ATOMIC | GFP_DMA
-			: GFP_ATOMIC));
-  if (HostAdapter->FirstOutgoingMailbox == NULL)
-    {
-      BusLogic_Error("UNABLE TO ALLOCATE MAILBOXES - DETACHING\n",
-		     HostAdapter, HostAdapter->HostNumber);
-      return false;
-    }
-  HostAdapter->LastOutgoingMailbox =
-    HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
-  HostAdapter->FirstIncomingMailbox =
-    (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1);
-  HostAdapter->LastIncomingMailbox =
-    HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
-  return true;
-}
-
-
-/*
-  BusLogic_DestroyMailboxes deallocates the Outgoing and Incoming Mailboxes
-  for Host Adapter.
-*/
-
-static void BusLogic_DestroyMailboxes(BusLogic_HostAdapter_T *HostAdapter)
-{
-  if (HostAdapter->FirstOutgoingMailbox == NULL) return;
-  scsi_init_free((char *) HostAdapter->FirstOutgoingMailbox,
-		 HostAdapter->MailboxCount
-		 * (sizeof(BusLogic_OutgoingMailbox_T)
-		    + sizeof(BusLogic_IncomingMailbox_T)));
-}
-
-
-/*
-  BusLogic_CreateCCB allocates and initializes a single Command Control
-  Block (CCB) for Host Adapter, and adds it to Host Adapter's free list.
-*/
-
-static boolean BusLogic_CreateCCB(BusLogic_HostAdapter_T *HostAdapter)
-{
-  BusLogic_CCB_T *CCB = (BusLogic_CCB_T *)
-    scsi_init_malloc(sizeof(BusLogic_CCB_T),
-		     (HostAdapter->BounceBuffersRequired
-		      ? GFP_ATOMIC | GFP_DMA
-		      : GFP_ATOMIC));
-  if (CCB == NULL) return false;
-  memset(CCB, 0, sizeof(BusLogic_CCB_T));
-  CCB->HostAdapter = HostAdapter;
-  CCB->Status = BusLogic_CCB_Free;
-  if (BusLogic_FlashPointHostAdapterP(HostAdapter))
-    {
-      CCB->CallbackFunction = BusLogic_QueueCompletedCCB;
-      CCB->BaseAddress = HostAdapter->IO_Address;
+  BusLogic_InitializeCCBs initializes a group of Command Control Blocks (CCBs)
+  for Host Adapter from the BlockSize bytes located at BlockPointer.  The newly
+  created CCBs are added to Host Adapter's free list.
+*/
+
+static void BusLogic_InitializeCCBs(BusLogic_HostAdapter_T *HostAdapter,
+				    void *BlockPointer, int BlockSize)
+{
+  BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) BlockPointer;
+  memset(BlockPointer, 0, BlockSize);
+  CCB->AllocationGroupHead = true;
+  while ((BlockSize -= sizeof(BusLogic_CCB_T)) >= 0)
+    {
+      CCB->Status = BusLogic_CCB_Free;
+      CCB->HostAdapter = HostAdapter;
+      if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+	{
+	  CCB->CallbackFunction = BusLogic_QueueCompletedCCB;
+	  CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress;
+	}
+      CCB->Next = HostAdapter->Free_CCBs;
+      CCB->NextAll = HostAdapter->All_CCBs;
+      HostAdapter->Free_CCBs = CCB;
+      HostAdapter->All_CCBs = CCB;
+      HostAdapter->AllocatedCCBs++;
+      CCB++;
     }
-  CCB->Next = HostAdapter->Free_CCBs;
-  CCB->NextAll = HostAdapter->All_CCBs;
-  HostAdapter->Free_CCBs = CCB;
-  HostAdapter->All_CCBs = CCB;
-  HostAdapter->AllocatedCCBs++;
-  return true;
 }
 
 
@@ -306,14 +306,21 @@
 
 static boolean BusLogic_CreateInitialCCBs(BusLogic_HostAdapter_T *HostAdapter)
 {
-  int Allocated;
-  for (Allocated = 0; Allocated < HostAdapter->InitialCCBs; Allocated++)
-    if (!BusLogic_CreateCCB(HostAdapter))
-      {
-	BusLogic_Error("UNABLE TO ALLOCATE CCB %d - DETACHING\n",
-		       HostAdapter, Allocated);
-	return false;
-      }
+  int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T);
+  while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs)
+    {
+      void *BlockPointer = kmalloc(BlockSize,
+				   (HostAdapter->BounceBuffersRequired
+				    ? GFP_ATOMIC | GFP_DMA
+				    : GFP_ATOMIC));
+      if (BlockPointer == NULL)
+	{
+	  BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n",
+			 HostAdapter);
+	  return false;
+	}
+      BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize);
+    }
   return true;
 }
 
@@ -330,7 +337,8 @@
   while ((CCB = NextCCB) != NULL)
     {
       NextCCB = CCB->NextAll;
-      scsi_init_free((char *) CCB, sizeof(BusLogic_CCB_T));
+      if (CCB->AllocationGroupHead)
+	kfree(CCB);
     }
 }
 
@@ -346,18 +354,35 @@
 					  int AdditionalCCBs,
 					  boolean SuccessMessageP)
 {
-  int Allocated;
+  int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T);
+  int PreviouslyAllocated = HostAdapter->AllocatedCCBs;
   if (AdditionalCCBs <= 0) return;
-  for (Allocated = 0; Allocated < AdditionalCCBs; Allocated++)
-    if (!BusLogic_CreateCCB(HostAdapter)) break;
-  if (Allocated > 0 && SuccessMessageP)
-    BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n",
-		    HostAdapter, Allocated, HostAdapter->AllocatedCCBs);
-  if (Allocated > 0) return;
+  while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs)
+    {
+      void *BlockPointer = kmalloc(BlockSize,
+				   (HostAdapter->BounceBuffersRequired
+				    ? GFP_ATOMIC | GFP_DMA
+				    : GFP_ATOMIC));
+      if (BlockPointer == NULL) break;
+      BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize);
+    }
+  if (HostAdapter->AllocatedCCBs > PreviouslyAllocated)
+    {
+      if (SuccessMessageP)
+	BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n",
+			HostAdapter,
+			HostAdapter->AllocatedCCBs - PreviouslyAllocated,
+			HostAdapter->AllocatedCCBs);
+      return;
+    }
   BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter);
-  HostAdapter->DriverQueueDepth =
-    HostAdapter->AllocatedCCBs - (HostAdapter->MaxTargetDevices - 1);
-  HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth;
+  if (HostAdapter->DriverQueueDepth >
+      HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount)
+    {
+      HostAdapter->DriverQueueDepth =
+	HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount;
+      HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth;
+    }
 }
 
 
@@ -413,47 +438,6 @@
 
 
 /*
-  BusLogic_CreateTargetDeviceStatistics creates the Target Device Statistics
-  structure for Host Adapter.
-*/
-
-static boolean BusLogic_CreateTargetDeviceStatistics(BusLogic_HostAdapter_T
-						     *HostAdapter)
-{
-  HostAdapter->TargetDeviceStatistics =
-    (BusLogic_TargetDeviceStatistics_T *)
-      scsi_init_malloc(HostAdapter->MaxTargetDevices
-		       * sizeof(BusLogic_TargetDeviceStatistics_T),
-		       GFP_ATOMIC);
-  if (HostAdapter->TargetDeviceStatistics == NULL)
-    {
-      BusLogic_Error("UNABLE TO ALLOCATE TARGET DEVICE STATISTICS - "
-		     "DETACHING\n", HostAdapter, HostAdapter->HostNumber);
-      return false;
-    }
-  memset(HostAdapter->TargetDeviceStatistics, 0,
-	 HostAdapter->MaxTargetDevices
-	 * sizeof(BusLogic_TargetDeviceStatistics_T));
-  return true;
-}
-
-
-/*
-  BusLogic_DestroyTargetDeviceStatistics destroys the Target Device Statistics
-  structure for Host Adapter.
-*/
-
-static void BusLogic_DestroyTargetDeviceStatistics(BusLogic_HostAdapter_T
-						   *HostAdapter)
-{
-  if (HostAdapter->TargetDeviceStatistics == NULL) return;
-  scsi_init_free((char *) HostAdapter->TargetDeviceStatistics,
-		 HostAdapter->MaxTargetDevices
-		 * sizeof(BusLogic_TargetDeviceStatistics_T));
-}
-
-
-/*
   BusLogic_Command sends the command OperationCode to HostAdapter, optionally
   providing ParameterLength bytes of ParameterData and receiving at most
   ReplyLength bytes of ReplyData; any excess reply data is received but
@@ -494,7 +478,7 @@
     If the IRQ Channel has not yet been acquired, then interrupts must be
     disabled while issuing host adapter commands since a Command Complete
     interrupt could occur if the IRQ Channel was previously enabled by another
-    BusLogic Host Adapter or other driver sharing the same IRQ Channel.
+    BusLogic Host Adapter or another driver sharing the same IRQ Channel.
   */
   if (!HostAdapter->IRQ_ChannelAcquired)
     {
@@ -572,7 +556,7 @@
 	  Result = -1;
 	  goto Done;
 	}
-      if (BusLogic_GlobalOptions.Bits.TraceConfiguration)
+      if (BusLogic_GlobalOptions.TraceConfiguration)
 	BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: "
 			"(Modify I/O Address)\n", HostAdapter,
 			OperationCode, StatusRegister.All);
@@ -607,9 +591,11 @@
       if (InterruptRegister.Bits.CommandComplete) break;
       if (HostAdapter->HostAdapterCommandCompleted) break;
       if (StatusRegister.Bits.DataInRegisterReady)
-	if (++ReplyBytes <= ReplyLength)
-	  *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
-	else BusLogic_ReadDataInRegister(HostAdapter);
+	{
+	  if (++ReplyBytes <= ReplyLength)
+	    *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
+	  else BusLogic_ReadDataInRegister(HostAdapter);
+	}
       if (OperationCode == BusLogic_FetchHostAdapterLocalRAM &&
 	  StatusRegister.Bits.HostAdapterReady) break;
       udelay(100);
@@ -621,34 +607,24 @@
       goto Done;
     }
   /*
-    If testing Command Complete Interrupts, wait a short while in case the
-    loop immediately above terminated due to the Command Complete bit being
-    set in the Interrupt Register, but the interrupt hasn't actually been
-    processed yet.  Otherwise, acknowledging the interrupt here could prevent
-    the interrupt test from succeeding.
-  */
-  if (OperationCode == BusLogic_TestCommandCompleteInterrupt)
-    udelay(10000);
-  /*
     Clear any pending Command Complete Interrupt.
   */
   BusLogic_InterruptReset(HostAdapter);
   /*
     Provide tracing information if requested.
   */
-  if (BusLogic_GlobalOptions.Bits.TraceConfiguration)
-    if (OperationCode != BusLogic_TestCommandCompleteInterrupt)
-      {
-	int i;
-	BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:",
-			HostAdapter, OperationCode,
-			StatusRegister.All, ReplyLength, ReplyBytes);
-	if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes;
-	for (i = 0; i < ReplyLength; i++)
-	  BusLogic_Notice(" %02X", HostAdapter,
-			  ((unsigned char *) ReplyData)[i]);
-	BusLogic_Notice("\n", HostAdapter);
-      }
+  if (BusLogic_GlobalOptions.TraceConfiguration)
+    {
+      int i;
+      BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:",
+		      HostAdapter, OperationCode,
+		      StatusRegister.All, ReplyLength, ReplyBytes);
+      if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes;
+      for (i = 0; i < ReplyLength; i++)
+	BusLogic_Notice(" %02X", HostAdapter,
+			((unsigned char *) ReplyData)[i]);
+      BusLogic_Notice("\n", HostAdapter);
+    }
   /*
     Process Command Invalid conditions.
   */
@@ -705,38 +681,63 @@
 
 
 /*
+  BusLogic_AppendProbeAddressISA appends a single ISA I/O Address to the list
+  of I/O Address and Bus Probe Information to be checked for potential BusLogic
+  Host Adapters.
+*/
+
+static void BusLogic_AppendProbeAddressISA(BusLogic_IO_Address_T IO_Address)
+{
+  BusLogic_ProbeInfo_T *ProbeInfo;
+  if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return;
+  ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+  ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+  ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+  ProbeInfo->IO_Address = IO_Address;
+}
+
+
+/*
   BusLogic_InitializeProbeInfoListISA initializes the list of I/O Address and
   Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters
   only from the list of standard BusLogic MultiMaster ISA I/O Addresses.
 */
 
-static void BusLogic_InitializeProbeInfoListISA(void)
+static void BusLogic_InitializeProbeInfoListISA(BusLogic_HostAdapter_T
+						*PrototypeHostAdapter)
 {
-  int StandardAddressIndex;
-  /*
-    If BusLogic_Setup has provided an I/O Address probe list, do not override
-    the Kernel Command Line specifications.
-  */
-  if (BusLogic_ProbeInfoCount > 0) return;
   /*
-    If a Kernel Command Line specification has requested that ISA Bus Probes
+    If BusLogic Driver Options specifications requested that ISA Bus Probes
     be inhibited, do not proceed further.
   */
-  if (BusLogic_ProbeOptions.Bits.NoProbeISA) return;
+  if (BusLogic_ProbeOptions.NoProbeISA) return;
   /*
     Append the list of standard BusLogic MultiMaster ISA I/O Addresses.
   */
-  StandardAddressIndex = 0;
-  while (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters &&
-	 StandardAddressIndex < BusLogic_ISA_StandardAddressesCount)
-    {
-      BusLogic_ProbeInfo_T *ProbeInfo =
-	&BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-      ProbeInfo->IO_Address =
-	BusLogic_ISA_StandardAddresses[StandardAddressIndex++];
-      ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-      ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
-    }
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe330
+      : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x330);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe334
+      : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x334);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe230
+      : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x230);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe234
+      : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x234);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe130
+      : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x130);
+  if (BusLogic_ProbeOptions.LimitedProbeISA
+      ? BusLogic_ProbeOptions.Probe134
+      : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)
+    BusLogic_AppendProbeAddressISA(0x134);
 }
 
 
@@ -783,25 +784,26 @@
   I/O Addresses.  It returns the number of PCI MultiMaster Host Adapters found.
 */
 
-static int BusLogic_InitializeMultiMasterProbeInfo(void)
+static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
+						   *PrototypeHostAdapter)
 {
-  boolean StandardAddressSeen[BusLogic_ISA_StandardAddressesCount];
   BusLogic_ProbeInfo_T *PrimaryProbeInfo =
     &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount];
   int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1;
   int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0;
   boolean ForceBusDeviceScanningOrder = false;
   boolean ForceBusDeviceScanningOrderChecked = false;
-  unsigned char Bus, DeviceFunction, IRQ_Channel;
+  boolean StandardAddressSeen[6];
+  unsigned char Bus, DeviceFunction;
   unsigned int BaseAddress0, BaseAddress1;
+  unsigned char IRQ_Channel;
   BusLogic_IO_Address_T IO_Address;
   BusLogic_PCI_Address_T PCI_Address;
   unsigned short Index = 0;
-  int StandardAddressIndex, i;
-  if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters)
-    return 0;
+  int i;
+  if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0;
   BusLogic_ProbeInfoCount++;
-  for (i = 0; i < BusLogic_ISA_StandardAddressesCount; i++)
+  for (i = 0; i < 6; i++)
     StandardAddressSeen[i] = false;
   /*
     Iterate over the MultiMaster PCI Host Adapters.  For each enumerated host
@@ -826,8 +828,7 @@
 	pcibios_read_config_byte(Bus, DeviceFunction,
 				 PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
       {
-	BusLogic_HostAdapter_T HostAdapterPrototype;
-	BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+	BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
 	BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation;
 	BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
 	unsigned char Device = DeviceFunction >> 3;
@@ -859,7 +860,7 @@
 			   NULL, Bus, Device, IO_Address);
 	    continue;
 	  }
-	if (BusLogic_GlobalOptions.Bits.TraceProbe)
+	if (BusLogic_GlobalOptions.TraceProbe)
 	  {
 	    BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter "
 			    "detected at\n", NULL);
@@ -871,7 +872,7 @@
 	  Issue the Inquire PCI Host Adapter Information command to determine
 	  the ISA Compatible I/O Port.  If the ISA Compatible I/O Port is
 	  known and enabled, note that the particular Standard ISA I/O
-	  Address need not be probed.
+	  Address should not be probed.
 	*/
 	HostAdapter->IO_Address = IO_Address;
 	if (BusLogic_Command(HostAdapter,
@@ -880,8 +881,7 @@
 			     sizeof(PCIHostAdapterInformation))
 	    == sizeof(PCIHostAdapterInformation))
 	  {
-	    if (PCIHostAdapterInformation.ISACompatibleIOPort <
-		BusLogic_ISA_StandardAddressesCount)
+	    if (PCIHostAdapterInformation.ISACompatibleIOPort < 6)
 	      StandardAddressSeen[PCIHostAdapterInformation
 				  .ISACompatibleIOPort] = true;
 	  }
@@ -933,10 +933,10 @@
 	*/
 	if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330)
 	  {
-	    PrimaryProbeInfo->IO_Address = IO_Address;
-	    PrimaryProbeInfo->PCI_Address = PCI_Address;
 	    PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
 	    PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+	    PrimaryProbeInfo->IO_Address = IO_Address;
+	    PrimaryProbeInfo->PCI_Address = PCI_Address;
 	    PrimaryProbeInfo->Bus = Bus;
 	    PrimaryProbeInfo->Device = Device;
 	    PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -946,10 +946,10 @@
 	  {
 	    BusLogic_ProbeInfo_T *ProbeInfo =
 	      &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-	    ProbeInfo->IO_Address = IO_Address;
-	    ProbeInfo->PCI_Address = PCI_Address;
 	    ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
 	    ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+	    ProbeInfo->IO_Address = IO_Address;
+	    ProbeInfo->PCI_Address = PCI_Address;
 	    ProbeInfo->Bus = Bus;
 	    ProbeInfo->Device = Device;
 	    ProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -978,31 +978,48 @@
     then the Primary I/O Address must be probed explicitly before any PCI
     host adapters are probed.
   */
-  if (PrimaryProbeInfo->IO_Address == 0 &&
-      !BusLogic_ProbeOptions.Bits.NoProbeISA)
-    {
-      PrimaryProbeInfo->IO_Address = BusLogic_ISA_StandardAddresses[0];
-      PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-      PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
-    }
+  if (!BusLogic_ProbeOptions.NoProbeISA)
+    if (PrimaryProbeInfo->IO_Address == 0 &&
+	(BusLogic_ProbeOptions.LimitedProbeISA
+	 ? BusLogic_ProbeOptions.Probe330
+	 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0))
+      {
+	PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+	PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+	PrimaryProbeInfo->IO_Address = 0x330;
+      }
   /*
     Append the list of standard BusLogic MultiMaster ISA I/O Addresses,
     omitting the Primary I/O Address which has already been handled.
   */
-  if (!BusLogic_ProbeOptions.Bits.NoProbeISA)
-    for (StandardAddressIndex = 1;
-	 StandardAddressIndex < BusLogic_ISA_StandardAddressesCount;
-	 StandardAddressIndex++)
-      if (!StandardAddressSeen[StandardAddressIndex] &&
-	  BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
-	{
-	  BusLogic_ProbeInfo_T *ProbeInfo =
-	    &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-	  ProbeInfo->IO_Address =
-	    BusLogic_ISA_StandardAddresses[StandardAddressIndex];
-	  ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-	  ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
-	}
+  if (!BusLogic_ProbeOptions.NoProbeISA)
+    {
+      if (!StandardAddressSeen[1] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe334
+	   : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x334);
+      if (!StandardAddressSeen[2] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe230
+	   : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x230);
+      if (!StandardAddressSeen[3] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe234
+	   : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x234);
+      if (!StandardAddressSeen[4] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe130
+	   : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x130);
+      if (!StandardAddressSeen[5] &&
+	  (BusLogic_ProbeOptions.LimitedProbeISA
+	   ? BusLogic_ProbeOptions.Probe134
+	   : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
+	BusLogic_AppendProbeAddressISA(0x134);
+    }
   return PCIMultiMasterCount;
 }
 
@@ -1014,11 +1031,13 @@
   number of FlashPoint Host Adapters found.
 */
 
-static int BusLogic_InitializeFlashPointProbeInfo(void)
+static int BusLogic_InitializeFlashPointProbeInfo(BusLogic_HostAdapter_T
+						  *PrototypeHostAdapter)
 {
   int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0;
-  unsigned char Bus, DeviceFunction, IRQ_Channel;
+  unsigned char Bus, DeviceFunction;
   unsigned int BaseAddress0, BaseAddress1;
+  unsigned char IRQ_Channel;
   BusLogic_IO_Address_T IO_Address;
   BusLogic_PCI_Address_T PCI_Address;
   unsigned short Index = 0;
@@ -1065,7 +1084,7 @@
 			   NULL, Bus, Device, IO_Address);
 	    continue;
 	  }
-	if (BusLogic_GlobalOptions.Bits.TraceProbe)
+	if (BusLogic_GlobalOptions.TraceProbe)
 	  {
 	    BusLogic_Notice("BusLogic: FlashPoint Host Adapter "
 			    "detected at\n", NULL);
@@ -1077,10 +1096,10 @@
 	  {
 	    BusLogic_ProbeInfo_T *ProbeInfo =
 	      &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-	    ProbeInfo->IO_Address = IO_Address;
-	    ProbeInfo->PCI_Address = PCI_Address;
 	    ProbeInfo->HostAdapterType = BusLogic_FlashPoint;
 	    ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+	    ProbeInfo->IO_Address = IO_Address;
+	    ProbeInfo->PCI_Address = PCI_Address;
 	    ProbeInfo->Bus = Bus;
 	    ProbeInfo->Device = Device;
 	    ProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -1116,44 +1135,41 @@
   FlashPoint and PCI MultiMaster Host Adapters are present, this driver will
   probe for FlashPoint Host Adapters first unless the BIOS primary disk is
   controlled by the first PCI MultiMaster Host Adapter, in which case
-  MultiMaster Host Adapters will be probed first.  The Kernel Command Line
-  options "MultiMasterFirst" and "FlashPointFirst" can be used to force a
-  particular probe order.
+  MultiMaster Host Adapters will be probed first.  The BusLogic Driver Options
+  specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force
+  a particular probe order.
 */
 
-static void BusLogic_InitializeProbeInfoList(void)
+static void BusLogic_InitializeProbeInfoList(BusLogic_HostAdapter_T
+					     *PrototypeHostAdapter)
 {
   /*
-    If BusLogic_Setup has provided an I/O Address probe list, do not override
-    the Kernel Command Line specifications.
-  */
-  if (BusLogic_ProbeInfoCount > 0) return;
-  /*
     If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint
     Host Adapters; otherwise, default to the standard ISA MultiMaster probe.
   */
-  if (!BusLogic_ProbeOptions.Bits.NoProbePCI && pcibios_present())
+  if (!BusLogic_ProbeOptions.NoProbePCI && pcibios_present())
     {
-      if (BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst)
+      if (BusLogic_ProbeOptions.MultiMasterFirst)
 	{
-	  BusLogic_InitializeMultiMasterProbeInfo();
-	  BusLogic_InitializeFlashPointProbeInfo();
+	  BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
+	  BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
 	}
-      else if (BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst)
+      else if (BusLogic_ProbeOptions.FlashPointFirst)
 	{
-	  BusLogic_InitializeFlashPointProbeInfo();
-	  BusLogic_InitializeMultiMasterProbeInfo();
+	  BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+	  BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
 	}
       else
 	{
-	  int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo();
-	  int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo();
+	  int FlashPointCount =
+	    BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+	  int PCIMultiMasterCount =
+	    BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
 	  if (FlashPointCount > 0 && PCIMultiMasterCount > 0)
 	    {
 	      BusLogic_ProbeInfo_T *ProbeInfo =
 		&BusLogic_ProbeInfoList[FlashPointCount];
-	      BusLogic_HostAdapter_T HostAdapterPrototype;
-	      BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+	      BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
 	      BusLogic_FetchHostAdapterLocalRAMRequest_T
 		FetchHostAdapterLocalRAMRequest;
 	      BusLogic_BIOSDriveMapByte_T Drive0MapByte;
@@ -1195,7 +1211,7 @@
 	    }
 	}
     }
-  else BusLogic_InitializeProbeInfoListISA();
+  else BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter);
 }
 
 
@@ -1240,20 +1256,14 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
     {
-      FlashPoint_Info_T *FlashPointInfo = (FlashPoint_Info_T *)
-	scsi_init_malloc(sizeof(FlashPoint_Info_T), GFP_ATOMIC);
-      int Retries = 10;
-      if (FlashPointInfo == NULL)
-	return BusLogic_Failure(HostAdapter, "ALLOCATING FLASHPOINT INFO");
-      FlashPointInfo->BaseAddress = HostAdapter->IO_Address;
+      FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
+      FlashPointInfo->BaseAddress =
+	(BusLogic_Base_Address_T) HostAdapter->IO_Address;
       FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel;
       FlashPointInfo->Present = false;
-      while (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 &&
-	       FlashPointInfo->Present) &&
-	     --Retries >= 0) ;
-      if (!FlashPointInfo->Present)
+      if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 &&
+	    FlashPointInfo->Present))
 	{
-	  scsi_init_free((char *) FlashPointInfo, sizeof(FlashPoint_Info_T));
 	  BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at "
 			 "PCI Bus %d Device %d\n", HostAdapter,
 			 HostAdapter->Bus, HostAdapter->Device);
@@ -1264,8 +1274,7 @@
 			 HostAdapter);
 	  return false;
 	}
-      HostAdapter->FlashPointInfo = FlashPointInfo;
-      if (BusLogic_GlobalOptions.Bits.TraceProbe)
+      if (BusLogic_GlobalOptions.TraceProbe)
 	BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n",
 			HostAdapter, HostAdapter->IO_Address);
       /*
@@ -1283,7 +1292,7 @@
   StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
   InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
   GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter);
-  if (BusLogic_GlobalOptions.Bits.TraceProbe)
+  if (BusLogic_GlobalOptions.TraceProbe)
     BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, "
 		    "Geometry 0x%02X\n", HostAdapter,
 		    HostAdapter->IO_Address, StatusRegister.All,
@@ -1318,12 +1327,16 @@
 
 
 /*
-  BusLogic_HardResetHostAdapter issues a Hard Reset to the Host Adapter,
-  and waits for Host Adapter Diagnostics to complete.
+  BusLogic_HardwareResetHostAdapter issues a Hardware Reset to the Host Adapter
+  and waits for Host Adapter Diagnostics to complete.  If HardReset is true, a
+  Hard Reset is performed which also initiates a SCSI Bus Reset.  Otherwise, a
+  Soft Reset is performed which only resets the Host Adapter without forcing a
+  SCSI Bus Reset.
 */
 
-static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
-					     *HostAdapter)
+static boolean BusLogic_HardwareResetHostAdapter(BusLogic_HostAdapter_T
+						   *HostAdapter,
+						 boolean HardReset)
 {
   BusLogic_StatusRegister_T StatusRegister;
   int TimeoutCounter;
@@ -1332,9 +1345,11 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
     {
-      HostAdapter->FlashPointInfo->ReportDataUnderrun = true;
+      FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
+      FlashPointInfo->HostSoftReset = !HardReset;
+      FlashPointInfo->ReportDataUnderrun = true;
       HostAdapter->CardHandle =
-	FlashPoint_HardResetHostAdapter(HostAdapter->FlashPointInfo);
+	FlashPoint_HardwareResetHostAdapter(FlashPointInfo);
       if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) return false;
       /*
 	Indicate the Host Adapter Hard Reset completed successfully.
@@ -1342,10 +1357,12 @@
       return true;
     }
   /*
-    Issue a Hard Reset Command to the Host Adapter.  The Host Adapter should
-    respond by setting Diagnostic Active in the Status Register.
+    Issue a Hard Reset or Soft Reset Command to the Host Adapter.  The Host
+    Adapter should respond by setting Diagnostic Active in the Status Register.
   */
-  BusLogic_HardReset(HostAdapter);
+  if (HardReset)
+    BusLogic_HardReset(HostAdapter);
+  else BusLogic_SoftReset(HostAdapter);
   /*
     Wait until Diagnostic Active is set in the Status Register.
   */
@@ -1356,8 +1373,8 @@
       if (StatusRegister.Bits.DiagnosticActive) break;
       udelay(100);
     }
-  if (BusLogic_GlobalOptions.Bits.TraceHardReset)
-    BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Active, "
+  if (BusLogic_GlobalOptions.TraceHardwareReset)
+    BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, "
 		    "Status 0x%02X\n", HostAdapter,
 		    HostAdapter->IO_Address, StatusRegister.All);
   if (TimeoutCounter < 0) return false;
@@ -1377,8 +1394,8 @@
       if (!StatusRegister.Bits.DiagnosticActive) break;
       udelay(100);
     }
-  if (BusLogic_GlobalOptions.Bits.TraceHardReset)
-    BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Completed, "
+  if (BusLogic_GlobalOptions.TraceHardwareReset)
+    BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, "
 		    "Status 0x%02X\n", HostAdapter,
 		    HostAdapter->IO_Address, StatusRegister.All);
   if (TimeoutCounter < 0) return false;
@@ -1396,8 +1413,8 @@
 	break;
       udelay(100);
     }
-  if (BusLogic_GlobalOptions.Bits.TraceHardReset)
-    BusLogic_Notice("BusLogic_HardReset(0x%X): Host Adapter Ready, "
+  if (BusLogic_GlobalOptions.TraceHardwareReset)
+    BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, "
 		    "Status 0x%02X\n", HostAdapter,
 		    HostAdapter->IO_Address, StatusRegister.All);
   if (TimeoutCounter < 0) return false;
@@ -1447,25 +1464,27 @@
     Issue the Inquire Configuration command if the IRQ Channel is unknown.
   */
   if (HostAdapter->IRQ_Channel == 0)
-    if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration,
-			 NULL, 0, &Configuration, sizeof(Configuration))
-	== sizeof(Configuration))
-      {
-	if (Configuration.IRQ_Channel9)
-	  HostAdapter->IRQ_Channel = 9;
-	else if (Configuration.IRQ_Channel10)
-	  HostAdapter->IRQ_Channel = 10;
-	else if (Configuration.IRQ_Channel11)
-	  HostAdapter->IRQ_Channel = 11;
-	else if (Configuration.IRQ_Channel12)
-	  HostAdapter->IRQ_Channel = 12;
-	else if (Configuration.IRQ_Channel14)
-	  HostAdapter->IRQ_Channel = 14;
-	else if (Configuration.IRQ_Channel15)
-	  HostAdapter->IRQ_Channel = 15;
-	else Result = false;
-      }
-    else Result = false;
+    {
+      if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration,
+			   NULL, 0, &Configuration, sizeof(Configuration))
+	  == sizeof(Configuration))
+	{
+	  if (Configuration.IRQ_Channel9)
+	    HostAdapter->IRQ_Channel = 9;
+	  else if (Configuration.IRQ_Channel10)
+	    HostAdapter->IRQ_Channel = 10;
+	  else if (Configuration.IRQ_Channel11)
+	    HostAdapter->IRQ_Channel = 11;
+	  else if (Configuration.IRQ_Channel12)
+	    HostAdapter->IRQ_Channel = 12;
+	  else if (Configuration.IRQ_Channel14)
+	    HostAdapter->IRQ_Channel = 14;
+	  else if (Configuration.IRQ_Channel15)
+	    HostAdapter->IRQ_Channel = 15;
+	  else Result = false;
+	}
+      else Result = false;
+    }
   /*
     Issue the Inquire Extended Setup Information command.  Only genuine
     BusLogic Host Adapters and true clones support this command.  Adaptec 1542C
@@ -1484,7 +1503,7 @@
   /*
     Provide tracing information if requested and return.
   */
-  if (BusLogic_GlobalOptions.Bits.TraceProbe)
+  if (BusLogic_GlobalOptions.TraceProbe)
     BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter,
 		    HostAdapter->IO_Address, (Result ? "Found" : "Not Found"));
   return Result;
@@ -1512,7 +1531,7 @@
   BusLogic_GeometryRegister_T GeometryRegister;
   BusLogic_RequestedReplyLength_T RequestedReplyLength;
   unsigned char *TargetPointer, Character;
-  int i;
+  int TargetID, i;
   /*
     Configuration Information for FlashPoint Host Adapters is provided in the
     FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function.
@@ -1521,7 +1540,7 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
     {
-      FlashPoint_Info_T *FlashPointInfo = HostAdapter->FlashPointInfo;
+      FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
       TargetPointer = HostAdapter->ModelName;
       *TargetPointer++ = 'B';
       *TargetPointer++ = 'T';
@@ -1550,8 +1569,8 @@
       HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit;
       HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
       HostAdapter->MaxLogicalUnits = 32;
-      HostAdapter->InitialCCBs = 64;
-      HostAdapter->IncrementalCCBs = 16;
+      HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize;
+      HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize;
       HostAdapter->DriverQueueDepth = 255;
       HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth;
       HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted;
@@ -1698,12 +1717,14 @@
   HostAdapter->HostAdapterBusType =
     BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4'];
   if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus)
-    if (Configuration.DMA_Channel5)
-      HostAdapter->DMA_Channel = 5;
-    else if (Configuration.DMA_Channel6)
-      HostAdapter->DMA_Channel = 6;
-    else if (Configuration.DMA_Channel7)
-      HostAdapter->DMA_Channel = 7;
+    {
+      if (Configuration.DMA_Channel5)
+	HostAdapter->DMA_Channel = 5;
+      else if (Configuration.DMA_Channel6)
+	HostAdapter->DMA_Channel = 6;
+      else if (Configuration.DMA_Channel7)
+	HostAdapter->DMA_Channel = 7;
+    }
   /*
     Determine whether Extended Translation is enabled and save it in
     the Host Adapter structure.
@@ -1837,7 +1858,7 @@
   HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
   HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8);
   /*
-    Select appropriate values for the Driver Queue Depth, Mailbox Count,
+    Select appropriate values for the Mailbox Count, Driver Queue Depth, 
     Initial CCBs, and Incremental CCBs variables based on whether or not Strict
     Round Robin Mode is supported.  If Strict Round Robin Mode is supported,
     then there is no performance degradation in using the maximum possible
@@ -1868,18 +1889,16 @@
   if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0)
     {
       HostAdapter->StrictRoundRobinModeSupport = true;
-      HostAdapter->MailboxCount = 255;
-      HostAdapter->InitialCCBs = 64;
-      HostAdapter->IncrementalCCBs = 16;
+      HostAdapter->MailboxCount = BusLogic_MaxMailboxes;
     }
   else
     {
       HostAdapter->StrictRoundRobinModeSupport = false;
       HostAdapter->MailboxCount = 32;
-      HostAdapter->InitialCCBs = 32;
-      HostAdapter->IncrementalCCBs = 8;
     }
   HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount;
+  HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize;
+  HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize;
   /*
     Tagged Queuing support is available and operates properly on all "W" series
     MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with
@@ -1931,57 +1950,32 @@
   */
 Common:
   /*
-    Initialize the Host Adapter Name and Interrupt Label fields from the
-    Model Name.
+    Initialize the Host Adapter Full Model Name and Interrupt Label fields
+    from the Model Name.
   */
   strcpy(HostAdapter->FullModelName, "BusLogic ");
   strcat(HostAdapter->FullModelName, HostAdapter->ModelName);
   strcpy(HostAdapter->InterruptLabel, HostAdapter->FullModelName);
   /*
     Select an appropriate value for the Tagged Queue Depth either from a
-    Command Line Entry, or based on whether this Host Adapter requires that ISA
-    Bounce Buffers be used.  The Tagged Queue Depth is left at 0 for automatic
-    determination in BusLogic_SelectQueueDepths.  Initialize the Untagged Queue
-    Depth.  Tagged Queuing is disabled by default when the Tagged Queue Depth
-    is 1 since queuing multiple commands is not possible.
-  */
-  if (HostAdapter->CommandLineEntry != NULL &&
-      HostAdapter->CommandLineEntry->TaggedQueueDepth > 0)
-    HostAdapter->TaggedQueueDepth =
-      HostAdapter->CommandLineEntry->TaggedQueueDepth;
-  else if (HostAdapter->BounceBuffersRequired)
-    HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthBounceBuffers;
-  else HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthAutomatic;
-  HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
-  if (HostAdapter->UntaggedQueueDepth > HostAdapter->TaggedQueueDepth &&
-      HostAdapter->TaggedQueueDepth > 0)
-    HostAdapter->UntaggedQueueDepth = HostAdapter->TaggedQueueDepth;
-  if (HostAdapter->TaggedQueueDepth == 1)
-    HostAdapter->TaggedQueuingPermitted = 0;
-  /*
-    Select an appropriate value for Bus Settle Time either from a Command
-    Line Entry, or from BusLogic_DefaultBusSettleTime.
-  */
-  if (HostAdapter->CommandLineEntry != NULL &&
-      HostAdapter->CommandLineEntry->BusSettleTime > 0)
-    HostAdapter->BusSettleTime = HostAdapter->CommandLineEntry->BusSettleTime;
-  else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime;
-  /*
-    Select an appropriate value for Local Options from a Command Line Entry.
-  */
-  if (HostAdapter->CommandLineEntry != NULL)
-    HostAdapter->LocalOptions = HostAdapter->CommandLineEntry->LocalOptions;
-  /*
-    Select appropriate values for the Error Recovery Strategy array either from
-    a Command Line Entry, or using BusLogic_ErrorRecovery_Default.
-  */
-  if (HostAdapter->CommandLineEntry != NULL)
-    memcpy(HostAdapter->ErrorRecoveryStrategy,
-	   HostAdapter->CommandLineEntry->ErrorRecoveryStrategy,
-	   sizeof(HostAdapter->ErrorRecoveryStrategy));
-  else memset(HostAdapter->ErrorRecoveryStrategy,
-	      BusLogic_ErrorRecovery_Default,
-	      sizeof(HostAdapter->ErrorRecoveryStrategy));
+    BusLogic Driver Options specification, or based on whether this Host
+    Adapter requires that ISA Bounce Buffers be used.  The Tagged Queue Depth
+    is left at 0 for automatic determination in BusLogic_SelectQueueDepths.
+    Initialize the Untagged Queue Depth.
+  */
+  for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+    {
+      unsigned char QueueDepth = 0;
+      if (HostAdapter->DriverOptions != NULL &&
+	  HostAdapter->DriverOptions->QueueDepth[TargetID] > 0)
+	QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID];
+      else if (HostAdapter->BounceBuffersRequired)
+	QueueDepth = BusLogic_TaggedQueueDepthBB;
+      HostAdapter->QueueDepth[TargetID] = QueueDepth;
+    }
+  if (HostAdapter->BounceBuffersRequired)
+    HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB;
+  else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
   /*
     Tagged Queuing is only allowed if Disconnect/Reconnect is permitted.
     Therefore, mask the Tagged Queuing Permitted Default bits with the
@@ -1989,15 +1983,34 @@
   */
   HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted;
   /*
-    Combine the default Tagged Queuing Permitted bits with any Command
-    Line Entry Tagged Queuing specification.
+    Combine the default Tagged Queuing Permitted bits with any BusLogic Driver
+    Options Tagged Queuing specification.
   */
-  if (HostAdapter->CommandLineEntry != NULL)
+  if (HostAdapter->DriverOptions != NULL)
     HostAdapter->TaggedQueuingPermitted =
-      (HostAdapter->CommandLineEntry->TaggedQueuingPermitted &
-       HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask) |
+      (HostAdapter->DriverOptions->TaggedQueuingPermitted &
+       HostAdapter->DriverOptions->TaggedQueuingPermittedMask) |
       (HostAdapter->TaggedQueuingPermitted &
-       ~HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask);
+       ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask);
+  /*
+    Select appropriate values for the Error Recovery Strategy array
+    either from a BusLogic Driver Options specification, or using
+    BusLogic_ErrorRecovery_Default.
+  */
+  for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+    if (HostAdapter->DriverOptions != NULL)
+      HostAdapter->ErrorRecoveryStrategy[TargetID] =
+	HostAdapter->DriverOptions->ErrorRecoveryStrategy[TargetID];
+    else HostAdapter->ErrorRecoveryStrategy[TargetID] =
+	   BusLogic_ErrorRecovery_Default;
+  /*
+    Select an appropriate value for Bus Settle Time either from a BusLogic
+    Driver Options specification, or from BusLogic_DefaultBusSettleTime.
+  */
+  if (HostAdapter->DriverOptions != NULL &&
+      HostAdapter->DriverOptions->BusSettleTime > 0)
+    HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime;
+  else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime;
   /*
     Indicate reading the Host Adapter Configuration completed successfully.
   */
@@ -2017,7 +2030,8 @@
   unsigned short SynchronousPermitted, FastPermitted;
   unsigned short UltraPermitted, WidePermitted;
   unsigned short DisconnectPermitted, TaggedQueuingPermitted;
-  boolean CommonSynchronousNegotiation, CommonErrorRecovery;
+  boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth;
+  boolean CommonErrorRecovery;
   char SynchronousString[BusLogic_MaxTargetDevices+1];
   char WideString[BusLogic_MaxTargetDevices+1];
   char DisconnectString[BusLogic_MaxTargetDevices+1];
@@ -2083,22 +2097,26 @@
 	  CommonSynchronousNegotiation = true;
 	}
       else if (SynchronousPermitted == AllTargetsMask)
-	if (FastPermitted == 0)
-	  {
-	    SynchronousMessage = "Slow";
-	    CommonSynchronousNegotiation = true;
-	  }
-	else if (FastPermitted == AllTargetsMask)
-	  if (UltraPermitted == 0)
+	{
+	  if (FastPermitted == 0)
 	    {
-	      SynchronousMessage = "Fast";
+	      SynchronousMessage = "Slow";
 	      CommonSynchronousNegotiation = true;
 	    }
-	  else if (UltraPermitted == AllTargetsMask)
+	  else if (FastPermitted == AllTargetsMask)
 	    {
-	      SynchronousMessage = "Ultra";
-	      CommonSynchronousNegotiation = true;
+	      if (UltraPermitted == 0)
+		{
+		  SynchronousMessage = "Fast";
+		  CommonSynchronousNegotiation = true;
+		}
+	      else if (UltraPermitted == AllTargetsMask)
+		{
+		  SynchronousMessage = "Ultra";
+		  CommonSynchronousNegotiation = true;
+		}
 	    }
+	}
       if (!CommonSynchronousNegotiation)
 	{
 	  for (TargetID = 0;
@@ -2175,9 +2193,20 @@
 		     HostAdapter, HostAdapter->DriverQueueDepth,
 		     HostAdapter->DriverScatterGatherLimit);
   BusLogic_Info("  Tagged Queue Depth: ", HostAdapter);
-  if (HostAdapter->TaggedQueueDepth > 0)
-    BusLogic_Info("%d", HostAdapter, HostAdapter->TaggedQueueDepth);
-  else BusLogic_Info("Automatic", HostAdapter);
+  CommonTaggedQueueDepth = true;
+  for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0])
+      {
+	CommonTaggedQueueDepth = false;
+	break;
+      }
+  if (CommonTaggedQueueDepth)
+    {
+      if (HostAdapter->QueueDepth[0] > 0)
+	BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]);
+      else BusLogic_Info("Automatic", HostAdapter);
+    }
+  else BusLogic_Info("Individual", HostAdapter);
   BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter,
 		HostAdapter->UntaggedQueueDepth);
   CommonErrorRecovery = true;
@@ -2314,51 +2343,6 @@
 
 
 /*
-  BusLogic_TestInterrupts tests for proper functioning of the Host Adapter
-  Interrupt Register and that interrupts generated by the Host Adapter are
-  getting through to the Interrupt Handler.  A large proportion of initial
-  problems with installing PCI Host Adapters are due to configuration problems
-  where either the Host Adapter or Motherboard is configured incorrectly, and
-  interrupts do not get through as a result.
-*/
-
-static boolean BusLogic_TestInterrupts(BusLogic_HostAdapter_T *HostAdapter)
-{
-  unsigned int InitialInterruptCount, FinalInterruptCount;
-  int TestCount = 5, i;
-  /*
-    FlashPoint Host Adapters do not provide for an interrupt test.
-  */
-  if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
-  /*
-    Inhibit the Interrupt Test if requested.
-  */
-  if (HostAdapter->LocalOptions.Bits.InhibitInterruptTest) return true;
-  /*
-    Issue the Test Command Complete Interrupt commands.
-  */
- 
-  InitialInterruptCount = kstat_irqs(HostAdapter->IRQ_Channel);
-  for (i = 0; i < TestCount; i++)
-    BusLogic_Command(HostAdapter, BusLogic_TestCommandCompleteInterrupt,
-		     NULL, 0, NULL, 0);
-  FinalInterruptCount = kstat_irqs(HostAdapter->IRQ_Channel);
-  /*
-    Verify that BusLogic_InterruptHandler was called at least TestCount
-    times.  Shared IRQ Channels could cause more than TestCount interrupts to
-    occur, but there should never be fewer than TestCount, unless one or more
-    interrupts were lost.
-  */
-  if (FinalInterruptCount < InitialInterruptCount + TestCount)
-    return BusLogic_Failure(HostAdapter, "HOST ADAPTER INTERRUPT TEST");
-  /*
-    Indicate the Host Adapter Interrupt Test completed successfully.
-  */
-  return true;
-}
-
-
-/*
   BusLogic_InitializeHostAdapter initializes Host Adapter.  This is the only
   function called during SCSI Host Adapter detection which modifies the state
   of the Host Adapter from its initial power on or hard reset state.
@@ -2377,20 +2361,31 @@
     for each Target Device.
   */
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
-  memset(HostAdapter->TaggedQueuingActive, false,
-	 sizeof(HostAdapter->TaggedQueuingActive));
-  memset(HostAdapter->CommandSuccessfulFlag, false,
-	 sizeof(HostAdapter->CommandSuccessfulFlag));
-  memset(HostAdapter->ActiveCommands, 0,
-	 sizeof(HostAdapter->ActiveCommands));
-  memset(HostAdapter->CommandsSinceReset, 0,
-	 sizeof(HostAdapter->CommandsSinceReset));
+    {
+      HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
+      HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
+      HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false;
+      HostAdapter->ActiveCommands[TargetID] = 0;
+      HostAdapter->CommandsSinceReset[TargetID] = 0;
+    }
   /*
     FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes.
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter)) goto Done;
   /*
+    Initialize the Outgoing and Incoming Mailbox pointers.
+  */
+  HostAdapter->FirstOutgoingMailbox =
+    (BusLogic_OutgoingMailbox_T *) HostAdapter->MailboxSpace;
+  HostAdapter->LastOutgoingMailbox =
+    HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
+  HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
+  HostAdapter->FirstIncomingMailbox =
+    (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1);
+  HostAdapter->LastIncomingMailbox =
+    HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
+  HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
+  /*
     Initialize the Outgoing and Incoming Mailbox structures.
   */
   memset(HostAdapter->FirstOutgoingMailbox, 0,
@@ -2398,11 +2393,6 @@
   memset(HostAdapter->FirstIncomingMailbox, 0,
 	 HostAdapter->MailboxCount * sizeof(BusLogic_IncomingMailbox_T));
   /*
-    Initialize the pointers to the Next Mailboxes.
-  */
-  HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
-  HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
-  /*
     Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes.
   */
   ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount;
@@ -2443,11 +2433,14 @@
     Announce Successful Initialization.
   */
 Done:
-  if (HostAdapter->HostAdapterInitialized)
-    BusLogic_Warning("*** %s Initialized Successfully ***\n",
-		     HostAdapter, HostAdapter->FullModelName);
-  else BusLogic_Info("*** %s Initialized Successfully ***\n",
-		     HostAdapter, HostAdapter->FullModelName);
+  if (!HostAdapter->HostAdapterInitialized)
+    {
+      BusLogic_Info("*** %s Initialized Successfully ***\n",
+		    HostAdapter, HostAdapter->FullModelName);
+      BusLogic_Info("\n", HostAdapter);
+    }
+  else BusLogic_Warning("*** %s Initialized Successfully ***\n",
+			HostAdapter, HostAdapter->FullModelName);
   HostAdapter->HostAdapterInitialized = true;
   /*
     Indicate the Host Adapter Initialization completed successfully.
@@ -2458,7 +2451,7 @@
 
 /*
   BusLogic_TargetDeviceInquiry inquires about the Target Devices accessible
-  through Host Adapter and reports on the results.
+  through Host Adapter.
 */
 
 static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
@@ -2469,7 +2462,7 @@
   BusLogic_SetupInformation_T SetupInformation;
   BusLogic_SynchronousPeriod_T SynchronousPeriod;
   BusLogic_RequestedReplyLength_T RequestedReplyLength;
-  int TargetDevicesFound = 0, TargetID;
+  int TargetID;
   /*
     Wait a few seconds between the Host Adapter Hard Reset which initiates
     a SCSI Bus Reset and issuing any SCSI Commands.  Some SCSI devices get
@@ -2481,13 +2474,11 @@
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
   /*
-    Inhibit the Target Devices Inquiry if requested.
+    Inhibit the Target Device Inquiry if requested.
   */
-  if (HostAdapter->LocalOptions.Bits.InhibitTargetInquiry)
-    {
-      BusLogic_Info("  Target Device Inquiry Inhibited\n", HostAdapter);
-      return true;
-    }
+  if (HostAdapter->DriverOptions != NULL &&
+      HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
+    return true;
   /*
     Issue the Inquire Target Devices command for host adapters with firmware
     version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command
@@ -2503,6 +2494,9 @@
 			   &InstalledDevices, sizeof(InstalledDevices))
 	  != sizeof(InstalledDevices))
 	return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES");
+      for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+	HostAdapter->TargetFlags[TargetID].TargetExists =
+	  (InstalledDevices & (1 << TargetID) ? true : false);
     }
   else
     {
@@ -2512,10 +2506,9 @@
 	  != sizeof(InstalledDevicesID0to7))
 	return BusLogic_Failure(HostAdapter,
 				"INQUIRE INSTALLED DEVICES ID 0 TO 7");
-      InstalledDevices = 0;
       for (TargetID = 0; TargetID < 8; TargetID++)
-	if (InstalledDevicesID0to7[TargetID] != 0)
-	  InstalledDevices |= (1 << TargetID);
+	HostAdapter->TargetFlags[TargetID].TargetExists =
+	  (InstalledDevicesID0to7[TargetID] != 0 ? true : false);
     }
   /*
     Issue the Inquire Setup Information command.
@@ -2526,6 +2519,19 @@
 		       &SetupInformation, sizeof(SetupInformation))
       != sizeof(SetupInformation))
     return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION");
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+      HostAdapter->SynchronousOffset[TargetID] =
+	(TargetID < 8
+	 ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset
+	 : SetupInformation.SynchronousValuesID8to15[TargetID-8].Offset);
+  if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0)
+    for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+      HostAdapter->TargetFlags[TargetID].WideTransfersActive =
+	(TargetID < 8
+	 ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID)
+	    ? true : false)
+	 : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID-8))
+	    ? true : false));
   /*
     Issue the Inquire Synchronous Period command.
   */
@@ -2537,69 +2543,96 @@
 			   &SynchronousPeriod, sizeof(SynchronousPeriod))
 	  != sizeof(SynchronousPeriod))
 	return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD");
+      for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+	HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID];
     }
   else
     for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
       if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0)
-	SynchronousPeriod[TargetID] =
+	HostAdapter->SynchronousPeriod[TargetID] =
 	  20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID]
 				   .TransferPeriod;
-      else SynchronousPeriod[TargetID] = 0;
   /*
-    Save the Installed Devices, Synchronous Values, and Synchronous Period
-    information in the Host Adapter structure.
+    Indicate the Target Device Inquiry completed successfully.
+  */
+  return true;
+}
+
+
+/*
+  BusLogic_ReportTargetDeviceInfo reports about the Target Devices accessible
+  through Host Adapter.
+*/
+
+static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
+					    *HostAdapter)
+{
+  int TargetID;
+  /*
+    Inhibit the Target Device Inquiry and Reporting if requested.
   */
-  HostAdapter->InstalledDevices = InstalledDevices;
-  memcpy(HostAdapter->SynchronousValues,
-	 SetupInformation.SynchronousValuesID0to7,
-	 sizeof(BusLogic_SynchronousValues8_T));
-  if (HostAdapter->HostWideSCSI)
-    memcpy(&HostAdapter->SynchronousValues[8],
-	   SetupInformation.SynchronousValuesID8to15,
-	   sizeof(BusLogic_SynchronousValues8_T));
-  memcpy(HostAdapter->SynchronousPeriod, SynchronousPeriod,
-	 sizeof(BusLogic_SynchronousPeriod_T));
+  if (BusLogic_MultiMasterHostAdapterP(HostAdapter) &&
+      HostAdapter->DriverOptions != NULL &&
+      HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
+    return;
   /*
     Report on the Target Devices found.
   */
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (HostAdapter->InstalledDevices & (1 << TargetID))
-      {
-	int SynchronousPeriod = HostAdapter->SynchronousPeriod[TargetID];
-	if (SynchronousPeriod > 10)
-	  {
-	    int SynchronousTransferRate = 100000000 / SynchronousPeriod;
-	    int RoundedSynchronousTransferRate =
-	      (SynchronousTransferRate + 5000) / 10000;
-	    BusLogic_Info("  Target %d: Synchronous at "
-			  "%d.%02d mega-transfers/second, offset %d\n",
-			  HostAdapter, TargetID,
-			  RoundedSynchronousTransferRate / 100,
-			  RoundedSynchronousTransferRate % 100,
-			  HostAdapter->SynchronousValues[TargetID].Offset);
-	  }
-	else if (SynchronousPeriod > 0)
-	  {
-	    int SynchronousTransferRate = 100000000 / SynchronousPeriod;
-	    int RoundedSynchronousTransferRate =
-	      (SynchronousTransferRate + 50000) / 100000;
-	    BusLogic_Info("  Target %d: Synchronous at "
-			  "%d.%01d mega-transfers/second, offset %d\n",
-			  HostAdapter, TargetID,
-			  RoundedSynchronousTransferRate / 10,
-			  RoundedSynchronousTransferRate % 10,
-			  HostAdapter->SynchronousValues[TargetID].Offset);
-	  }
-	else BusLogic_Info("  Target %d: Asynchronous\n",
-			   HostAdapter, TargetID);
-	TargetDevicesFound++;
-      }
-  if (TargetDevicesFound == 0)
-    BusLogic_Info("  No Target Devices Found\n", HostAdapter);
-  /*
-    Indicate the Target Device Inquiry completed successfully.
-  */
-  return true;
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (TargetFlags->TargetExists && !TargetFlags->TargetInfoReported)
+	{
+	  int SynchronousTransferRate = 0;
+	  if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+	    {
+	      boolean WideTransfersActive;
+	      FlashPoint_InquireTargetInfo(
+		HostAdapter->CardHandle, TargetID,
+		&HostAdapter->SynchronousPeriod[TargetID],
+		&HostAdapter->SynchronousOffset[TargetID],
+		&WideTransfersActive);
+	      TargetFlags->WideTransfersActive = WideTransfersActive;
+	    }
+	  else if (TargetFlags->WideTransfersSupported &&
+		   (HostAdapter->WidePermitted & (1 << TargetID)) &&
+		   strcmp(HostAdapter->FirmwareVersion, "5.06L") < 0)
+	    TargetFlags->WideTransfersActive = true;
+	  if (HostAdapter->SynchronousPeriod[TargetID] > 0)
+	    SynchronousTransferRate =
+	      100000 / HostAdapter->SynchronousPeriod[TargetID];
+	  if (TargetFlags->WideTransfersActive)
+	    SynchronousTransferRate <<= 1;
+	  if (SynchronousTransferRate >= 9950)
+	    {
+	      SynchronousTransferRate = (SynchronousTransferRate + 50) / 100;
+	      BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at "
+			    "%d.%01d MB/sec, offset %d\n",
+			    HostAdapter, TargetID,
+			    HostAdapter->QueueDepth[TargetID],
+			    (TargetFlags->WideTransfersActive ? "Wide " : ""),
+			    SynchronousTransferRate / 10,
+			    SynchronousTransferRate % 10,
+			    HostAdapter->SynchronousOffset[TargetID]);
+	    }
+	  else if (SynchronousTransferRate > 0)
+	    {
+	      SynchronousTransferRate = (SynchronousTransferRate + 5) / 10;
+	      BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at "
+			    "%d.%02d MB/sec, offset %d\n",
+			    HostAdapter, TargetID,
+			    HostAdapter->QueueDepth[TargetID],
+			    (TargetFlags->WideTransfersActive ? "Wide " : ""),
+			    SynchronousTransferRate / 100,
+			    SynchronousTransferRate % 100,
+			    HostAdapter->SynchronousOffset[TargetID]);
+	    }
+	  else BusLogic_Info("Target %d: Queue Depth %d, Asynchronous\n",
+			     HostAdapter, TargetID,
+			     HostAdapter->QueueDepth[TargetID]);
+	  TargetFlags->TargetInfoReported = true;
+	}
+    }
 }
 
 
@@ -2629,9 +2662,11 @@
 
 
 /*
-  BusLogic_SelectQueueDepths selects Queue Depths for each Target Device
-  based on the Host Adapter's Total Queue Depth and the number, type, speed,
-  and capabilities of the Target Devices.
+  BusLogic_SelectQueueDepths selects Queue Depths for each Target Device based
+  on the Host Adapter's Total Queue Depth and the number, type, speed, and
+  capabilities of the Target Devices.  When called for the last Host Adapter,
+  it reports on the Target Device Information for all BusLogic Host Adapters
+  since all the Target Devices have now been probed.
 */
 
 static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
@@ -2639,41 +2674,60 @@
 {
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Host->hostdata;
-  int TaggedQueueDepth = HostAdapter->TaggedQueueDepth;
-  int UntaggedQueueDepth = HostAdapter->UntaggedQueueDepth;
-  int TaggedDeviceCount = 0, UntaggedDeviceCount = 0;
-  int DesiredCCBs = HostAdapter->MaxTargetDevices - 1;
+  int TaggedDeviceCount = 0, AutomaticTaggedDeviceCount = 0;
+  int UntaggedDeviceCount = 0, AutomaticTaggedQueueDepth = 0;
+  int AllocatedQueueDepth = 0;
   SCSI_Device_T *Device;
-  for (Device = DeviceList; Device != NULL; Device = Device->next)
-    if (Device->host == Host)
+  int TargetID;
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    if (HostAdapter->TargetFlags[TargetID].TargetExists)
       {
-	if (Device->tagged_supported &&
-	    (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
-	  TaggedDeviceCount++;
+	int QueueDepth = HostAdapter->UntaggedQueueDepth;
+	if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported &&
+	    (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
+	  {
+	    QueueDepth = HostAdapter->QueueDepth[TargetID];
+	    TaggedDeviceCount++;
+	    if (QueueDepth == 0) AutomaticTaggedDeviceCount++;
+	  }
 	else UntaggedDeviceCount++;
+	HostAdapter->QueueDepth[TargetID] = QueueDepth;
+	AllocatedQueueDepth += QueueDepth;
       }
-  if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0)
+  HostAdapter->TargetDeviceCount = TaggedDeviceCount + UntaggedDeviceCount;
+  if (AutomaticTaggedDeviceCount > 0)
     {
-      TaggedQueueDepth =
-	1 + ((HostAdapter->HostAdapterQueueDepth
-	      - UntaggedDeviceCount * UntaggedQueueDepth)
-	     / TaggedDeviceCount);
-      if (TaggedQueueDepth > BusLogic_PreferredTaggedQueueDepth)
-	TaggedQueueDepth = BusLogic_PreferredTaggedQueueDepth;
-    }
-  for (Device = DeviceList; Device != NULL; Device = Device->next)
+      AutomaticTaggedQueueDepth =
+	(HostAdapter->HostAdapterQueueDepth - AllocatedQueueDepth)
+	/ AutomaticTaggedDeviceCount;
+      if (AutomaticTaggedQueueDepth > BusLogic_MaxAutomaticTaggedQueueDepth)
+	AutomaticTaggedQueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth;
+      if (AutomaticTaggedQueueDepth < BusLogic_MinAutomaticTaggedQueueDepth)
+	AutomaticTaggedQueueDepth = BusLogic_MinAutomaticTaggedQueueDepth;
+      for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+	if (HostAdapter->TargetFlags[TargetID].TargetExists &&
+	    HostAdapter->QueueDepth[TargetID] == 0)
+	  {
+	    AllocatedQueueDepth += AutomaticTaggedQueueDepth;
+	    HostAdapter->QueueDepth[TargetID] = AutomaticTaggedQueueDepth;
+	  }
+    }
+  for (Device = DeviceList; Device != NULL; Device = Device->next)
     if (Device->host == Host)
-      {
-	if (Device->tagged_supported &&
-	    (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
-	  Device->queue_depth = TaggedQueueDepth;
-	else Device->queue_depth = UntaggedQueueDepth;
-	HostAdapter->QueueDepth[Device->id] = Device->queue_depth;
-	DesiredCCBs += Device->queue_depth;
-      }
+      Device->queue_depth = HostAdapter->QueueDepth[Device->id];
+  /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */
+  AllocatedQueueDepth += HostAdapter->TargetDeviceCount;
+  if (AllocatedQueueDepth > HostAdapter->DriverQueueDepth)
+    AllocatedQueueDepth = HostAdapter->DriverQueueDepth;
   BusLogic_CreateAdditionalCCBs(HostAdapter,
-				DesiredCCBs - HostAdapter->AllocatedCCBs,
+				AllocatedQueueDepth
+				- HostAdapter->AllocatedCCBs,
 				false);
+  if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
+    for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
+	 HostAdapter != NULL;
+	 HostAdapter = HostAdapter->NextAll)
+      BusLogic_ReportTargetDeviceInfo(HostAdapter);
 }
 
 
@@ -2687,50 +2741,48 @@
 
 int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
 {
-  int BusLogicHostAdapterCount = 0, CommandLineEntryIndex = 0, ProbeIndex;
-  char *MessageBuffer = NULL;
-  if (BusLogic_ProbeOptions.Bits.NoProbe) return 0;
-  BusLogic_InitializeProbeInfoList();
+  int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex;
+  BusLogic_HostAdapter_T *PrototypeHostAdapter;
+  if (BusLogic_ProbeOptions.NoProbe) return 0;
+  BusLogic_ProbeInfoList = (BusLogic_ProbeInfo_T *)
+    kmalloc(BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T),
+	    GFP_ATOMIC);
+  if (BusLogic_ProbeInfoList == NULL)
+    {
+      BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL);
+      return 0;
+    }
+  memset(BusLogic_ProbeInfoList, 0,
+	 BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T));
+  PrototypeHostAdapter = (BusLogic_HostAdapter_T *)
+    kmalloc(sizeof(BusLogic_HostAdapter_T), GFP_ATOMIC);
+  if (PrototypeHostAdapter == NULL)
+    {
+      kfree(BusLogic_ProbeInfoList);
+      BusLogic_Error("BusLogic: Unable to allocate Prototype "
+		     "Host Adapter\n", NULL);
+      return 0;
+    }
+  memset(PrototypeHostAdapter, 0, sizeof(BusLogic_HostAdapter_T));
+  if (BusLogic_Options != NULL)
+    BusLogic_ParseDriverOptions(BusLogic_Options);
+  BusLogic_InitializeProbeInfoList(PrototypeHostAdapter);
   for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++)
     {
       BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex];
-      BusLogic_HostAdapter_T HostAdapterPrototype;
-      BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+      BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
       SCSI_Host_T *Host;
       if (ProbeInfo->IO_Address == 0) continue;
       memset(HostAdapter, 0, sizeof(BusLogic_HostAdapter_T));
-      HostAdapter->IO_Address = ProbeInfo->IO_Address;
-      HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
       HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType;
       HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType;
+      HostAdapter->IO_Address = ProbeInfo->IO_Address;
+      HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
       HostAdapter->Bus = ProbeInfo->Bus;
       HostAdapter->Device = ProbeInfo->Device;
       HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
       HostAdapter->AddressCount =
-	BusLogic_HostAdapter_AddressCount[HostAdapter->HostAdapterType];
-      if (MessageBuffer == NULL)
-	MessageBuffer =
-	  scsi_init_malloc(BusLogic_MessageBufferSize, GFP_ATOMIC);
-      if (MessageBuffer == NULL)
-	{
-	  BusLogic_Error("BusLogic: Unable to allocate Message Buffer\n",
-			 HostAdapter);
-	  return BusLogicHostAdapterCount;
-	}
-      HostAdapter->MessageBuffer = MessageBuffer;
-      /*
-	If an explicit I/O Address was specified, Initialize the Command Line
-	Entry field and inhibit the check for whether the I/O Address range is
-	already in use.
-      */
-      if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount &&
-	  BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address ==
-	  HostAdapter->IO_Address)
-	HostAdapter->CommandLineEntry =
-	  &BusLogic_CommandLineEntries[CommandLineEntryIndex++];
-      else if (check_region(HostAdapter->IO_Address,
-			    HostAdapter->AddressCount) < 0)
-	continue;
+	BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
       /*
 	Probe the Host Adapter.  If unsuccessful, abort further initialization.
       */
@@ -2739,22 +2791,20 @@
 	Hard Reset the Host Adapter.  If unsuccessful, abort further
 	initialization.
       */
-      if (!BusLogic_HardResetHostAdapter(HostAdapter)) continue;
+      if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) continue;
       /*
 	Check the Host Adapter.  If unsuccessful, abort further initialization.
       */
       if (!BusLogic_CheckHostAdapter(HostAdapter)) continue;
       /*
-	Initialize the Command Line Entry field if an explicit I/O Address
-	was not specified.
+	Initialize the Driver Options field if provided.
       */
-      if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount &&
-	  BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == 0)
-	HostAdapter->CommandLineEntry =
-	  &BusLogic_CommandLineEntries[CommandLineEntryIndex++];
+      if (DriverOptionsIndex < BusLogic_DriverOptionsCount)
+	HostAdapter->DriverOptions =
+	  &BusLogic_DriverOptions[DriverOptionsIndex++];
       /*
 	Announce the Driver Version and Date, Author's Name, Copyright Notice,
-	and Contact Address.
+	and Electronic Mail Address.
       */
       BusLogic_AnnounceDriver(HostAdapter);
       /*
@@ -2772,8 +2822,7 @@
       */
       Host = scsi_register(HostTemplate, sizeof(BusLogic_HostAdapter_T));
       HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata;
-      memcpy(HostAdapter, &HostAdapterPrototype,
-	     sizeof(BusLogic_HostAdapter_T));
+      memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T));
       HostAdapter->SCSI_Host = Host;
       HostAdapter->HostNumber = Host->host_no;
       Host->select_queue_depths = BusLogic_SelectQueueDepths;
@@ -2786,18 +2835,14 @@
       BusLogic_RegisterHostAdapter(HostAdapter);
       /*
 	Read the Host Adapter Configuration, Configure the Host Adapter,
-	Acquire the System Resources necessary to use the Host Adapter,
-	then Test Interrupts, Create the Mailboxes, Initial CCBs, and
-	Target Device Statistics, Initialize the Host Adapter, and
-	finally perform Target Device Inquiry.
+	Acquire the System Resources necessary to use the Host Adapter, then
+	Create the Initial CCBs, Initialize the Host Adapter, and finally
+	perform Target Device Inquiry.
       */
       if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
 	  BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
 	  BusLogic_AcquireResources(HostAdapter) &&
-	  BusLogic_TestInterrupts(HostAdapter) &&
-	  BusLogic_CreateMailboxes(HostAdapter) &&
 	  BusLogic_CreateInitialCCBs(HostAdapter) &&
-	  BusLogic_CreateTargetDeviceStatistics(HostAdapter) &&
 	  BusLogic_InitializeHostAdapter(HostAdapter) &&
 	  BusLogic_TargetDeviceInquiry(HostAdapter))
 	{
@@ -2807,7 +2852,6 @@
 	    Name of the Host Adapter will appear, and initialize the SCSI
 	    Host structure.
 	  */
-	  MessageBuffer = NULL;
 	  release_region(HostAdapter->IO_Address,
 			 HostAdapter->AddressCount);
 	  request_region(HostAdapter->IO_Address,
@@ -2819,24 +2863,22 @@
       else
 	{
 	  /*
-	    An error occurred during Host Adapter Configuration Querying,
-	    Host Adapter Configuration, Resource Acquisition, Interrupt
-	    Testing, CCB Creation, Host Adapter Initialization, or Target
-	    Device Inquiry, so remove Host Adapter from the list of
-	    registered BusLogic Host Adapters, destroy the Target Device
-	    Statistics, CCBs, and Mailboxes, Release the System Resources,
-	    and Unregister the SCSI Host.
+	    An error occurred during Host Adapter Configuration Querying, Host
+	    Adapter Configuration, Resource Acquisition, CCB Creation, Host
+	    Adapter Initialization, or Target Device Inquiry, so remove Host
+	    Adapter from the list of registered BusLogic Host Adapters, destroy
+	    the CCBs, Release the System Resources, and Unregister the SCSI
+	    Host.
 	  */
-	  BusLogic_DestroyTargetDeviceStatistics(HostAdapter);
 	  BusLogic_DestroyCCBs(HostAdapter);
-	  BusLogic_DestroyMailboxes(HostAdapter);
 	  BusLogic_ReleaseResources(HostAdapter);
 	  BusLogic_UnregisterHostAdapter(HostAdapter);
 	  scsi_unregister(Host);
 	}
     }
-  if (MessageBuffer != NULL)
-    scsi_init_free(MessageBuffer, BusLogic_MessageBufferSize);
+  kfree(PrototypeHostAdapter);
+  kfree(BusLogic_ProbeInfoList);
+  BusLogic_ProbeInfoList = NULL;
   return BusLogicHostAdapterCount;
 }
 
@@ -2852,21 +2894,16 @@
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Host->hostdata;
   /*
-    FlashPoint Host Adapters must also be released by the FlashPoint
+    FlashPoint Host Adapters must first be released by the FlashPoint
     SCCB Manager.
   */
   if (BusLogic_FlashPointHostAdapterP(HostAdapter))
-    {
-      FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle);
-      scsi_init_free((char *) HostAdapter->FlashPointInfo,
-		     sizeof(FlashPoint_Info_T));
-    }
+    FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle);
   /*
-    Destroy the CCBs and Mailboxes, and release any system resources acquired
-    to support Host Adapter.
+    Destroy the CCBs and release any system resources acquired to
+    support Host Adapter.
   */
   BusLogic_DestroyCCBs(HostAdapter);
-  BusLogic_DestroyMailboxes(HostAdapter);
   BusLogic_ReleaseResources(HostAdapter);
   /*
     Release usage of the I/O Address range.
@@ -2989,27 +3026,29 @@
       BusLogic_CCB_T *CCB = (BusLogic_CCB_T *)
 	Bus_to_Virtual(NextIncomingMailbox->CCB);
       if (CompletionCode != BusLogic_AbortedCommandNotFound)
-	if (CCB->Status == BusLogic_CCB_Active ||
-	    CCB->Status == BusLogic_CCB_Reset)
-	  {
-	    /*
-	      Save the Completion Code for this CCB and queue the CCB
-	      for completion processing.
-	    */
-	    CCB->CompletionCode = CompletionCode;
-	    BusLogic_QueueCompletedCCB(CCB);
-	  }
-	else
-	  {
-	    /*
-	      If a CCB ever appears in an Incoming Mailbox and is not marked as
-	      status Active or Reset, then there is most likely a bug in the
-	      Host Adapter firmware.
-	    */
-	    BusLogic_Warning("Illegal CCB #%ld status %d in "
-			     "Incoming Mailbox\n", HostAdapter,
-			     CCB->SerialNumber, CCB->Status);
-	  }
+	{
+	  if (CCB->Status == BusLogic_CCB_Active ||
+	      CCB->Status == BusLogic_CCB_Reset)
+	    {
+	      /*
+		Save the Completion Code for this CCB and queue the CCB
+		for completion processing.
+	      */
+	      CCB->CompletionCode = CompletionCode;
+	      BusLogic_QueueCompletedCCB(CCB);
+	    }
+	  else
+	    {
+	      /*
+		If a CCB ever appears in an Incoming Mailbox and is not marked
+		as status Active or Reset, then there is most likely a bug in
+		the Host Adapter firmware.
+	      */
+	      BusLogic_Warning("Illegal CCB #%ld status %d in "
+			       "Incoming Mailbox\n", HostAdapter,
+			       CCB->SerialNumber, CCB->Status);
+	    }
+	}
       NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree;
       if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox)
 	NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
@@ -3048,10 +3087,9 @@
 			   "%d Completed\n", HostAdapter,
 			   CCB->SerialNumber, TargetID);
 	  BusLogic_IncrementErrorCounter(
-	    &HostAdapter->TargetDeviceStatistics[TargetID]
-			  .BusDeviceResetsCompleted);
+	    &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted);
+	  HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
 	  HostAdapter->CommandsSinceReset[TargetID] = 0;
-	  HostAdapter->TaggedQueuingActive[TargetID] = false;
 	  HostAdapter->LastResetCompleted[TargetID] = jiffies;
 	  /*
 	    Place CCB back on the Host Adapter's free list.
@@ -3102,16 +3140,17 @@
 			       HostAdapter, CCB->SerialNumber, CCB->TargetID);
 	      break;
 	    case BusLogic_CommandCompletedWithoutError:
-	      HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+	      HostAdapter->TargetStatistics[CCB->TargetID]
 			   .CommandsCompleted++;
-	      HostAdapter->CommandSuccessfulFlag[CCB->TargetID] = true;
+	      HostAdapter->TargetFlags[CCB->TargetID]
+			   .CommandSuccessfulFlag = true;
 	      Command->result = DID_OK << 16;
 	      break;
 	    case BusLogic_CommandAbortedAtHostRequest:
 	      BusLogic_Warning("CCB #%ld to Target %d Aborted\n",
 			       HostAdapter, CCB->SerialNumber, CCB->TargetID);
 	      BusLogic_IncrementErrorCounter(
-		&HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+		&HostAdapter->TargetStatistics[CCB->TargetID]
 			      .CommandAbortsCompleted);
 	      Command->result = DID_ABORT << 16;
 	      break;
@@ -3122,9 +3161,9 @@
 					   CCB->TargetDeviceStatus);
 	      if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout)
 		{
-		  HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+		  HostAdapter->TargetStatistics[CCB->TargetID]
 			       .CommandsCompleted++;
-		  if (BusLogic_GlobalOptions.Bits.TraceErrors)
+		  if (BusLogic_GlobalOptions.TraceErrors)
 		      {
 			int i;
 			BusLogic_Notice("CCB #%ld Target %d: Result %X Host "
@@ -3148,6 +3187,22 @@
 	      break;
 	    }
 	  /*
+	    When an INQUIRY command completes normally, save the
+	    CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit
+	    Wide Data Transfers Supported) bits.
+	  */
+	  if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 &&
+	      CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally)
+	    {
+	      BusLogic_TargetFlags_T *TargetFlags =
+		&HostAdapter->TargetFlags[CCB->TargetID];
+	      SCSI_Inquiry_T *InquiryResult =
+		(SCSI_Inquiry_T *) Command->request_buffer;
+	      TargetFlags->TargetExists = true;
+	      TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue;
+	      TargetFlags->WideTransfersSupported = InquiryResult->WBus16;
+	    }
+	  /*
 	    Place CCB back on the Host Adapter's free list.
 	  */
 	  BusLogic_DeallocateCCB(CCB);
@@ -3172,7 +3227,7 @@
 {
   BusLogic_HostAdapter_T *FirstHostAdapter =
     BusLogic_RegisteredHostAdapters[IRQ_Channel];
-  boolean HostAdapterResetRequested = false;
+  boolean HostAdapterResetRequired = false;
   BusLogic_HostAdapter_T *HostAdapter;
   BusLogic_Lock_T Lock;
   /*
@@ -3214,8 +3269,8 @@
 	      */
 	      if (InterruptRegister.Bits.ExternalBusReset)
 		{
-		  HostAdapter->HostAdapterResetRequested = true;
-		  HostAdapterResetRequested = true;
+		  HostAdapter->HostAdapterExternalReset = true;
+		  HostAdapterResetRequired = true;
 		}
 	      else if (InterruptRegister.Bits.IncomingMailboxLoaded)
 		BusLogic_ScanIncomingMailboxes(HostAdapter);
@@ -3229,11 +3284,20 @@
 	    Check if there is a pending interrupt for this Host Adapter.
 	  */
 	  if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
-	    if (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)
-		== FlashPoint_ExternalBusReset)
+	    switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
 	      {
-		HostAdapter->HostAdapterResetRequested = true;
-		HostAdapterResetRequested = true;
+	      case FlashPoint_NormalInterrupt:
+		break;
+	      case FlashPoint_ExternalBusReset:
+		HostAdapter->HostAdapterExternalReset = true;
+		HostAdapterResetRequired = true;
+		break;
+	      case FlashPoint_InternalError:
+		BusLogic_Warning("Internal FlashPoint Error detected"
+				 " - Resetting Host Adapter\n", HostAdapter);
+		HostAdapter->HostAdapterInternalError = true;
+		HostAdapterResetRequired = true;
+		break;
 	      }
 	}
       /*
@@ -3250,14 +3314,16 @@
     Iterate over the Host Adapters performing any requested
     Host Adapter Resets.
   */
-  if (HostAdapterResetRequested)
+  if (HostAdapterResetRequired)
     for (HostAdapter = FirstHostAdapter;
 	 HostAdapter != NULL;
 	 HostAdapter = HostAdapter->Next)
-      if (HostAdapter->HostAdapterResetRequested)
+      if (HostAdapter->HostAdapterExternalReset ||
+	  HostAdapter->HostAdapterInternalError)
 	{
 	  BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
-	  HostAdapter->HostAdapterResetRequested = false;
+	  HostAdapter->HostAdapterExternalReset = false;
+	  HostAdapter->HostAdapterInternalError = false;
 	  scsi_mark_host_reset(HostAdapter->SCSI_Host);
 	}
 }
@@ -3294,8 +3360,7 @@
 	{
 	  HostAdapter->ActiveCommands[CCB->TargetID]++;
 	  if (CCB->Opcode != BusLogic_BusDeviceReset)
-	    HostAdapter->TargetDeviceStatistics[CCB->TargetID]
-			 .CommandsAttempted++;
+	    HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++;
 	}
       return true;
     }
@@ -3313,8 +3378,10 @@
 {
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
-  BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics =
-    HostAdapter->TargetDeviceStatistics;
+  BusLogic_TargetFlags_T *TargetFlags =
+    &HostAdapter->TargetFlags[Command->target];
+  BusLogic_TargetStatistics_T *TargetStatistics =
+    HostAdapter->TargetStatistics;
   unsigned char *CDB = Command->cmnd;
   int CDB_Length = Command->cmd_len;
   int TargetID = Command->target;
@@ -3372,13 +3439,9 @@
       int Segment;
       CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather;
       CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T);
-#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
       if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
 	CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
-      else CCB->DataPointer = (BusLogic_BusAddress_T) CCB->ScatterGatherList;
-#else
-      CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
-#endif
+      else CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList);
       for (Segment = 0; Segment < SegmentCount; Segment++)
 	{
 	  CCB->ScatterGatherList[Segment].SegmentByteCount =
@@ -3392,22 +3455,20 @@
     case READ_6:
     case READ_10:
       CCB->DataDirection = BusLogic_DataInLengthChecked;
-      TargetDeviceStatistics[TargetID].ReadCommands++;
+      TargetStatistics[TargetID].ReadCommands++;
       BusLogic_IncrementByteCounter(
-	&TargetDeviceStatistics[TargetID].TotalBytesRead, BufferLength);
+	&TargetStatistics[TargetID].TotalBytesRead, BufferLength);
       BusLogic_IncrementSizeBucket(
-	TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets,
-	BufferLength);
+	TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength);
       break;
     case WRITE_6:
     case WRITE_10:
       CCB->DataDirection = BusLogic_DataOutLengthChecked;
-      TargetDeviceStatistics[TargetID].WriteCommands++;
+      TargetStatistics[TargetID].WriteCommands++;
       BusLogic_IncrementByteCounter(
-	&TargetDeviceStatistics[TargetID].TotalBytesWritten, BufferLength);
+	&TargetStatistics[TargetID].TotalBytesWritten, BufferLength);
       BusLogic_IncrementSizeBucket(
-	TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets,
-	BufferLength);
+	TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength);
       break;
     default:
       CCB->DataDirection = BusLogic_UncheckedDataTransfer;
@@ -3435,20 +3496,18 @@
     necessary to wait until there are no pending commands for a target device
     before queuing tagged commands.
   */
-  HostAdapter->TaggedQueuingSupported[TargetID] =
-    Command->device->tagged_supported;
   if (HostAdapter->CommandsSinceReset[TargetID]++ >=
 	BusLogic_MaxTaggedQueueDepth &&
-      !HostAdapter->TaggedQueuingActive[TargetID] &&
+      !TargetFlags->TaggedQueuingActive &&
       HostAdapter->ActiveCommands[TargetID] == 0 &&
-      HostAdapter->TaggedQueuingSupported[TargetID] &&
+      TargetFlags->TaggedQueuingSupported &&
       (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
     {
-      HostAdapter->TaggedQueuingActive[TargetID] = true;
+      TargetFlags->TaggedQueuingActive = true;
       BusLogic_Notice("Tagged Queuing now active for Target %d\n",
 		      HostAdapter, TargetID);
     }
-  if (HostAdapter->TaggedQueuingActive[TargetID])
+  if (TargetFlags->TaggedQueuingActive)
     {
       BusLogic_QueueTag_T QueueTag = BusLogic_SimpleQueueTag;
       /*
@@ -3458,7 +3517,7 @@
 	write nearer the head position continue to arrive without interruption.
 	Therefore, for each Target Device this driver keeps track of the last
 	time either the queue was empty or an Ordered Queue Tag was issued.  If
-	more than 3 seconds (one fifth of the 15 second disk timeout) have
+	more than 4 seconds (one fifth of the 20 second disk timeout) have
 	elapsed since this last sequence point, this command will be issued
 	with an Ordered Queue Tag rather than a Simple Queue Tag, which forces
 	the Target Device to complete all previously queued commands before
@@ -3466,7 +3525,7 @@
       */
       if (HostAdapter->ActiveCommands[TargetID] == 0)
 	HostAdapter->LastSequencePoint[TargetID] = jiffies;
-      else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 3*HZ)
+      else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4*HZ)
 	{
 	  HostAdapter->LastSequencePoint[TargetID] = jiffies;
 	  QueueTag = BusLogic_OrderedQueueTag;
@@ -3520,7 +3579,7 @@
       */
       CCB->Status = BusLogic_CCB_Active;
       HostAdapter->ActiveCommands[TargetID]++;
-      TargetDeviceStatistics[TargetID].CommandsAttempted++;
+      TargetStatistics[TargetID].CommandsAttempted++;
       FlashPoint_StartCCB(HostAdapter->CardHandle, CCB);
       /*
 	The Command may have already completed and BusLogic_QueueCompletedCCB
@@ -3551,7 +3610,7 @@
   BusLogic_CCB_T *CCB;
   int Result;
   BusLogic_IncrementErrorCounter(
-    &HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsRequested);
+    &HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested);
   /*
     Acquire exclusive access to Host Adapter.
   */
@@ -3605,7 +3664,7 @@
 	Firmware version 5.xx does generate Abort Tag messages, so it is
 	possible to abort commands when Tagged Queuing is active.
       */
-      if (HostAdapter->TaggedQueuingActive[TargetID] &&
+      if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
 	  HostAdapter->FirmwareVersion[0] < '5')
 	{
 	  BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - "
@@ -3619,8 +3678,7 @@
 	  BusLogic_Warning("Aborting CCB #%ld to Target %d\n",
 			   HostAdapter, CCB->SerialNumber, TargetID);
 	  BusLogic_IncrementErrorCounter(
-	    &HostAdapter->TargetDeviceStatistics[TargetID]
-			  .CommandAbortsAttempted);
+	    &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted);
 	  Result = SCSI_ABORT_PENDING;
 	}
       else
@@ -3639,7 +3697,7 @@
       BusLogic_Warning("Aborting CCB #%ld to Target %d\n",
 		       HostAdapter, CCB->SerialNumber, TargetID);
       BusLogic_IncrementErrorCounter(
-	&HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsAttempted);
+	&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted);
       FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB);
       /*
 	The Abort may have already been completed and
@@ -3674,11 +3732,24 @@
   BusLogic_Lock_T Lock;
   BusLogic_CCB_T *CCB;
   int TargetID, Result;
-  if (Command == NULL)
-    BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets);
-  else BusLogic_IncrementErrorCounter(
-	 &HostAdapter->TargetDeviceStatistics[Command->target]
-		       .HostAdapterResetsRequested);
+  boolean HardReset;
+  if (HostAdapter->HostAdapterExternalReset)
+    {
+      BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets);
+      HardReset = false;
+    }
+  else if (HostAdapter->HostAdapterInternalError)
+    {
+      BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors);
+      HardReset = true;
+    }
+  else
+    {
+      BusLogic_IncrementErrorCounter(
+	&HostAdapter->TargetStatistics[Command->target]
+		      .HostAdapterResetsRequested);
+      HardReset = true;
+    }
   /*
     Acquire exclusive access to Host Adapter.
   */
@@ -3724,20 +3795,25 @@
 	}
     }
   if (Command == NULL)
-    BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n",
-		     HostAdapter, HostAdapter->FullModelName);
+    {
+      if (HostAdapter->HostAdapterInternalError)
+	BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n",
+			 HostAdapter, HostAdapter->FullModelName);
+      else BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n",
+			    HostAdapter, HostAdapter->FullModelName);
+    }
   else
     {
       BusLogic_Warning("Resetting %s due to Target %d\n", HostAdapter,
 		       HostAdapter->FullModelName, Command->target);
       BusLogic_IncrementErrorCounter(
-	&HostAdapter->TargetDeviceStatistics[Command->target]
+	&HostAdapter->TargetStatistics[Command->target]
 		      .HostAdapterResetsAttempted);
     }
   /*
     Attempt to Reset and Reinitialize the Host Adapter.
   */
-  if (!(BusLogic_HardResetHostAdapter(HostAdapter) &&
+  if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) &&
 	BusLogic_InitializeHostAdapter(HostAdapter)))
     {
       BusLogic_Error("Resetting %s Failed\n", HostAdapter,
@@ -3747,7 +3823,7 @@
     }
   if (Command != NULL)
     BusLogic_IncrementErrorCounter(
-      &HostAdapter->TargetDeviceStatistics[Command->target]
+      &HostAdapter->TargetStatistics[Command->target]
 		    .HostAdapterResetsCompleted);
   /*
     Mark all currently executing CCBs as having been Reset.
@@ -3762,7 +3838,8 @@
     Note that a timer interrupt may occur here, but all active CCBs have
     already been marked Reset and so a reentrant call will return Pending.
   */
-  BusLogic_Delay(HostAdapter->BusSettleTime);
+  if (HardReset)
+    BusLogic_Delay(HostAdapter->BusSettleTime);
   /*
     If this is a Synchronous Reset, perform completion processing for
     the Command being Reset.
@@ -3818,7 +3895,7 @@
   BusLogic_Lock_T Lock;
   int Result = -1;
   BusLogic_IncrementErrorCounter(
-    &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsRequested);
+    &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested);
   /*
     Acquire exclusive access to Host Adapter.
   */
@@ -3892,7 +3969,7 @@
 	while there are tagged commands outstanding.  Therefore, in that case a
 	full Host Adapter Hard Reset and SCSI Bus Reset must be done.
       */
-      if (HostAdapter->TaggedQueuingActive[TargetID] &&
+      if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
 	  HostAdapter->ActiveCommands[TargetID] > 0 &&
 	  HostAdapter->FirmwareVersion[0] < '5')
 	goto Done;
@@ -3959,7 +4036,7 @@
     processing performed.
   */
   BusLogic_IncrementErrorCounter(
-    &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted);
+    &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsAttempted);
   HostAdapter->BusDeviceResetPendingCCB[TargetID] = CCB;
   HostAdapter->LastResetAttempted[TargetID] = jiffies;
   for (XCCB = HostAdapter->All_CCBs; XCCB != NULL; XCCB = XCCB->NextAll)
@@ -4008,11 +4085,11 @@
     it has been less than 10 minutes since the last reset occurred, or since
     the system was initialized if no prior resets have occurred.
   */
-  if (HostAdapter->TaggedQueuingActive[TargetID] &&
+  if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
       jiffies - HostAdapter->LastResetCompleted[TargetID] < 10*60*HZ)
     {
       HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
-      HostAdapter->TaggedQueuingActive[TargetID] = false;
+      HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
       BusLogic_Warning("Tagged Queuing now disabled for Target %d\n",
 		       HostAdapter, TargetID);
     }
@@ -4033,10 +4110,10 @@
 	forcing a Hard Reset before the Bus Device Reset has had a chance to
 	clear the error condition.
       */
-      if (HostAdapter->CommandSuccessfulFlag[TargetID] ||
+      if (HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag ||
 	  jiffies - HostAdapter->LastResetAttempted[TargetID] < HZ/10)
 	{
-	  HostAdapter->CommandSuccessfulFlag[TargetID] = false;
+	  HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false;
 	  return BusLogic_SendBusDeviceReset(HostAdapter, Command, ResetFlags);
 	}
       /* Fall through to Hard Reset case. */
@@ -4077,16 +4154,18 @@
   struct buffer_head *BufferHead;
   if (HostAdapter->ExtendedTranslationEnabled &&
       Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */)
-    if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */)
-      {
-	DiskParameters->Heads = 255;
-	DiskParameters->Sectors = 63;
-      }
-    else
-      {
-	DiskParameters->Heads = 128;
-	DiskParameters->Sectors = 32;
-      }
+    {
+      if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */)
+	{
+	  DiskParameters->Heads = 255;
+	  DiskParameters->Sectors = 63;
+	}
+      else
+	{
+	  DiskParameters->Heads = 128;
+	  DiskParameters->Sectors = 32;
+	}
+    }
   else
     {
       DiskParameters->Heads = 64;
@@ -4106,24 +4185,28 @@
   */
   if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55)
     {
-      struct partition *PartitionEntry =
-	(struct partition *) (BufferHead->b_data + 0x1BE);
+      PartitionTable_T *FirstPartitionEntry =
+	(PartitionTable_T *) (BufferHead->b_data + 0x1BE);
+      PartitionTable_T *PartitionEntry = FirstPartitionEntry;
       int SavedCylinders = DiskParameters->Cylinders, PartitionNumber;
+      unsigned char PartitionEntryEndHead, PartitionEntryEndSector;
       for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++)
 	{
-	  if (PartitionEntry->end_head == 64-1)
+	  PartitionEntryEndHead = PartitionEntry->end_head;
+	  PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F;
+	  if (PartitionEntryEndHead == 64-1)
 	    {
 	      DiskParameters->Heads = 64;
 	      DiskParameters->Sectors = 32;
 	      break;
 	    }
-	  else if (PartitionEntry->end_head == 128-1)
+	  else if (PartitionEntryEndHead == 128-1)
 	    {
 	      DiskParameters->Heads = 128;
 	      DiskParameters->Sectors = 32;
 	      break;
 	    }
-	  else if (PartitionEntry->end_head == 255-1)
+	  else if (PartitionEntryEndHead == 255-1)
 	    {
 	      DiskParameters->Heads = 255;
 	      DiskParameters->Sectors = 63;
@@ -4131,14 +4214,29 @@
 	    }
 	  PartitionEntry++;
 	}
+      if (PartitionNumber == 4)
+	{
+	  PartitionEntryEndHead = FirstPartitionEntry->end_head;
+	  PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F;
+	}
       DiskParameters->Cylinders =
 	Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
-      if (SavedCylinders != DiskParameters->Cylinders)
+      if (PartitionNumber < 4 &&
+	  PartitionEntryEndSector == DiskParameters->Sectors)
 	{
-	  BusLogic_Warning("Warning: Extended Translation Setting "
-			   "(> 1GB Switch) does not match\n", HostAdapter);
-	  BusLogic_Warning("Partition Table - Adopting %d/%d Geometry "
-			   "from Partition Table\n", HostAdapter,
+	  if (DiskParameters->Cylinders != SavedCylinders)
+	    BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n",
+			     HostAdapter,
+			     DiskParameters->Heads, DiskParameters->Sectors);
+	}
+      else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0)
+	{
+	  BusLogic_Warning("Warning: Partition Table appears to "
+			   "have Geometry %d/%d which is\n", HostAdapter,
+			   PartitionEntryEndHead + 1,
+			   PartitionEntryEndSector);
+	  BusLogic_Warning("not compatible with current BusLogic "
+			   "Host Adapter Geometry %d/%d\n", HostAdapter,
 			   DiskParameters->Heads, DiskParameters->Sectors);
 	}
     }
@@ -4156,22 +4254,21 @@
 			       int HostNumber, int WriteFlag)
 {
   BusLogic_HostAdapter_T *HostAdapter;
-  BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics;
-  int IRQ_Channel, TargetID, Length;
+  BusLogic_TargetStatistics_T *TargetStatistics;
+  int TargetID, Length;
   char *Buffer;
   if (WriteFlag) return 0;
-  for (IRQ_Channel = 0; IRQ_Channel < NR_IRQS; IRQ_Channel++)
+  for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
+       HostAdapter != NULL;
+       HostAdapter = HostAdapter->NextAll)
+    if (HostAdapter->HostNumber == HostNumber) break;
+  if (HostAdapter == NULL)
     {
-      HostAdapter = BusLogic_RegisteredHostAdapters[IRQ_Channel];
-      while (HostAdapter != NULL)
-	{
-	  if (HostAdapter->HostNumber == HostNumber) break;
-	  HostAdapter = HostAdapter->Next;
-	}
-      if (HostAdapter != NULL) break;
+      BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n",
+		     NULL, HostNumber);
+      return 0;
     }
-  if (HostAdapter == NULL) return -1;
-  TargetDeviceStatistics = HostAdapter->TargetDeviceStatistics;
+  TargetStatistics = HostAdapter->TargetStatistics;
   Buffer = HostAdapter->MessageBuffer;
   Length = HostAdapter->MessageBufferLength;
   Length += sprintf(&Buffer[Length], "\n\
@@ -4182,100 +4279,105 @@
   Length += sprintf(&Buffer[Length], "\n\n\
 			   DATA TRANSFER STATISTICS\n\
 \n\
-Target	Tagged Queuing	Queue Depth  Commands Attempted	 Commands Completed\n\
-======	==============	===========  ==================	 ==================\n");
+Target	Tagged Queuing	Queue Depth  Active  Attempted	Completed\n\
+======	==============	===========  ======  =========	=========\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
-      {
-	Length +=
-	  sprintf(&Buffer[Length], "  %2d	%s", TargetID,
-		  (HostAdapter->TaggedQueuingSupported[TargetID]
-		   ? (HostAdapter->TaggedQueuingActive[TargetID]
-		      ? "    Active"
-		      : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
-			 ? "  Permitted" : "   Disabled"))
-		   : "Not Supported"));
-	Length += sprintf(&Buffer[Length],
-			  "	    %3d		 %9u	     %9u\n",
-			  HostAdapter->QueueDepth[TargetID],
-			  TargetDeviceStatistics[TargetID].CommandsAttempted,
-			  TargetDeviceStatistics[TargetID].CommandsCompleted);
-      }
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
+      Length +=
+	sprintf(&Buffer[Length], "  %2d	%s", TargetID,
+		(TargetFlags->TaggedQueuingSupported
+		 ? (TargetFlags->TaggedQueuingActive
+		    ? "    Active"
+		    : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
+		       ? "  Permitted" : "   Disabled"))
+		 : "Not Supported"));
+      Length += sprintf(&Buffer[Length],
+			"	    %3d       %3u    %9u	%9u\n",
+			HostAdapter->QueueDepth[TargetID],
+			HostAdapter->ActiveCommands[TargetID],
+			TargetStatistics[TargetID].CommandsAttempted,
+			TargetStatistics[TargetID].CommandsCompleted);
+    }
   Length += sprintf(&Buffer[Length], "\n\
 Target  Read Commands  Write Commands   Total Bytes Read    Total Bytes Written\n\
 ======  =============  ==============  ===================  ===================\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
-      {
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
+      Length +=
+	sprintf(&Buffer[Length], "  %2d	  %9u	 %9u", TargetID,
+		TargetStatistics[TargetID].ReadCommands,
+		TargetStatistics[TargetID].WriteCommands);
+      if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0)
 	Length +=
-	  sprintf(&Buffer[Length], "  %2d	  %9u	 %9u", TargetID,
-		  TargetDeviceStatistics[TargetID].ReadCommands,
-		  TargetDeviceStatistics[TargetID].WriteCommands);
-	if (TargetDeviceStatistics[TargetID].TotalBytesRead.Billions > 0)
-	  Length +=
-	    sprintf(&Buffer[Length], "     %9u%09u",
-		    TargetDeviceStatistics[TargetID].TotalBytesRead.Billions,
-		    TargetDeviceStatistics[TargetID].TotalBytesRead.Units);
-	else
-	  Length +=
-	    sprintf(&Buffer[Length], "		%9u",
-		    TargetDeviceStatistics[TargetID].TotalBytesRead.Units);
-	if (TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions > 0)
-	  Length +=
-	    sprintf(&Buffer[Length], "   %9u%09u\n",
-		    TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions,
-		    TargetDeviceStatistics[TargetID].TotalBytesWritten.Units);
-	else
-	  Length +=
-	    sprintf(&Buffer[Length], "	     %9u\n",
-		    TargetDeviceStatistics[TargetID].TotalBytesWritten.Units);
-      }
+	  sprintf(&Buffer[Length], "     %9u%09u",
+		  TargetStatistics[TargetID].TotalBytesRead.Billions,
+		  TargetStatistics[TargetID].TotalBytesRead.Units);
+      else
+	Length +=
+	  sprintf(&Buffer[Length], "		%9u",
+		  TargetStatistics[TargetID].TotalBytesRead.Units);
+      if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0)
+	Length +=
+	  sprintf(&Buffer[Length], "   %9u%09u\n",
+		  TargetStatistics[TargetID].TotalBytesWritten.Billions,
+		  TargetStatistics[TargetID].TotalBytesWritten.Units);
+      else
+	Length +=
+	  sprintf(&Buffer[Length], "	     %9u\n",
+		  TargetStatistics[TargetID].TotalBytesWritten.Units);
+    }
   Length += sprintf(&Buffer[Length], "\n\
 Target  Command    0-1KB      1-2KB      2-4KB      4-8KB     8-16KB\n\
 ======  =======  =========  =========  =========  =========  =========\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
-      {
-	Length +=
-	  sprintf(&Buffer[Length],
-		  "  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[0],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[1],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[2],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[3],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[4]);
-	Length +=
-	  sprintf(&Buffer[Length],
-		  "  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[0],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[1],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[2],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[3],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[4]);
-      }
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
+      Length +=
+	sprintf(&Buffer[Length],
+		"  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[0],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[1],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[2],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[3],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[4]);
+      Length +=
+	sprintf(&Buffer[Length],
+		"  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[0],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[1],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[2],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[3],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[4]);
+    }
   Length += sprintf(&Buffer[Length], "\n\
 Target  Command   16-32KB    32-64KB   64-128KB   128-256KB   256KB+\n\
 ======  =======  =========  =========  =========  =========  =========\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
-      {
-	Length +=
-	  sprintf(&Buffer[Length],
-		  "  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[5],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[6],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[7],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[8],
-		  TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[9]);
-	Length +=
-	  sprintf(&Buffer[Length],
-		  "  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[5],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[6],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[7],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[8],
-		  TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[9]);
-      }
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
+      Length +=
+	sprintf(&Buffer[Length],
+		"  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[5],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[6],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[7],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[8],
+		TargetStatistics[TargetID].ReadCommandSizeBuckets[9]);
+      Length +=
+	sprintf(&Buffer[Length],
+		"  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[5],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[6],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[7],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[8],
+		TargetStatistics[TargetID].WriteCommandSizeBuckets[9]);
+    }
   Length += sprintf(&Buffer[Length], "\n\n\
 			   ERROR RECOVERY STATISTICS\n\
 \n\
@@ -4284,21 +4386,26 @@
   ID	\\\\\\\\ Attempted ////  \\\\\\\\ Attempted ////  \\\\\\\\ Attempted ////\n\
 ======	 ===== ===== =====    ===== ===== =====	   ===== ===== =====\n");
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
+    {
+      BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+      if (!TargetFlags->TargetExists) continue;
       Length +=
 	sprintf(&Buffer[Length], "\
   %2d	 %5d %5d %5d    %5d %5d %5d	   %5d %5d %5d\n", TargetID,
-		TargetDeviceStatistics[TargetID].CommandAbortsRequested,
-		TargetDeviceStatistics[TargetID].CommandAbortsAttempted,
-		TargetDeviceStatistics[TargetID].CommandAbortsCompleted,
-		TargetDeviceStatistics[TargetID].BusDeviceResetsRequested,
-		TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted,
-		TargetDeviceStatistics[TargetID].BusDeviceResetsCompleted,
-		TargetDeviceStatistics[TargetID].HostAdapterResetsRequested,
-		TargetDeviceStatistics[TargetID].HostAdapterResetsAttempted,
-		TargetDeviceStatistics[TargetID].HostAdapterResetsCompleted);
+		TargetStatistics[TargetID].CommandAbortsRequested,
+		TargetStatistics[TargetID].CommandAbortsAttempted,
+		TargetStatistics[TargetID].CommandAbortsCompleted,
+		TargetStatistics[TargetID].BusDeviceResetsRequested,
+		TargetStatistics[TargetID].BusDeviceResetsAttempted,
+		TargetStatistics[TargetID].BusDeviceResetsCompleted,
+		TargetStatistics[TargetID].HostAdapterResetsRequested,
+		TargetStatistics[TargetID].HostAdapterResetsAttempted,
+		TargetStatistics[TargetID].HostAdapterResetsCompleted);
+    }
   Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n",
 		    HostAdapter->ExternalHostAdapterResets);
+  Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n",
+		    HostAdapter->HostAdapterInternalErrors);
   if (Length >= BusLogic_MessageBufferSize)
     BusLogic_Error("Message Buffer length %d exceeds size %d\n",
 		   HostAdapter, Length, BusLogic_MessageBufferSize);
@@ -4340,17 +4447,22 @@
 	     Buffer);
       HostAdapter->MessageBufferLength += Length;
       if (BeginningOfLine)
-	printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
-	       HostAdapter->HostNumber, Buffer);
+	{
+	  if (Buffer[0] != '\n' || Length > 1)
+	    printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
+		   HostAdapter->HostNumber, Buffer);
+	}
       else printk("%s", Buffer);
     }
   else
     {
       if (BeginningOfLine)
-	if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized)
-	  printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
-		 HostAdapter->HostNumber, Buffer);
-	else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer);
+	{
+	  if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized)
+	    printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
+		   HostAdapter->HostNumber, Buffer);
+	  else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer);
+	}
       else printk("%s", Buffer);
     }
   BeginningOfLine = (Buffer[Length-1] == '\n');
@@ -4358,364 +4470,548 @@
 
 
 /*
-  BusLogic_Setup handles processing of Kernel Command Line Arguments.
+  BusLogic_ParseKeyword parses an individual option keyword.  It returns true
+  and updates the pointer if the keyword is recognized and false otherwise.
+*/
 
-  For the BusLogic driver, a Kernel Command Line Entry comprises the driver
-  identifier "BusLogic=" optionally followed by a comma-separated sequence of
-  integers and then optionally followed by a comma-separated sequence of
-  strings.  Each command line entry applies to one BusLogic Host Adapter.
-  Multiple command line entries may be used in systems which contain multiple
-  BusLogic Host Adapters.
+static boolean BusLogic_ParseKeyword(char **StringPointer, char *Keyword)
+{
+  char *Pointer = *StringPointer;
+  while (*Keyword != '\0')
+    {
+      char StringChar = *Pointer++;
+      char KeywordChar = *Keyword++;
+      if (StringChar >= 'A' && StringChar <= 'Z')
+	StringChar += 'a' - 'Z';
+      if (KeywordChar >= 'A' && KeywordChar <= 'Z')
+	KeywordChar += 'a' - 'Z';
+      if (StringChar != KeywordChar) return false;
+    }
+  *StringPointer = Pointer;
+  return true;
+}
 
-  The first integer specified is the I/O Address at which the Host Adapter is
-  located.  If unspecified, it defaults to 0 which means to apply this entry to
-  the first BusLogic Host Adapter found during the default probe sequence.  If
-  any I/O Address parameters are provided on the command line, then the default
-  probe sequence is omitted.
-
-  The second integer specified is the Tagged Queue Depth to use for Target
-  Devices that support Tagged Queuing.  The Queue Depth is the number of SCSI
-  commands that are allowed to be concurrently presented for execution.  If
-  unspecified, it defaults to 0 which means to use a value determined
-  automatically based on the Host Adapter's Total Queue Depth and the number,
-  type, speed, and capabilities of the detected Target Devices.  For Host
-  Adapters that require ISA Bounce Buffers, the Tagged Queue Depth is
-  automatically set to BusLogic_TaggedQueueDepthBounceBuffers to avoid
-  excessive preallocation of DMA Bounce Buffer memory.  Target Devices that do
-  not support Tagged Queuing use a Queue Depth of BusLogic_UntaggedQueueDepth.
-
-  The third integer specified is the Bus Settle Time in seconds.  This is
-  the amount of time to wait between a Host Adapter Hard Reset which initiates
-  a SCSI Bus Reset and issuing any SCSI Commands.  If unspecified, it defaults
-  to 0 which means to use the value of BusLogic_DefaultBusSettleTime.
-
-  The fourth integer specified is the Local Options.  If unspecified, it
-  defaults to 0.  Note that Local Options are only applied to a specific Host
-  Adapter.
 
-  The fifth integer specified is the Global Options.  If unspecified, it
-  defaults to 0.  Note that Global Options are applied across all Host
-  Adapters.
+/*
+  BusLogic_ParseDriverOptions handles processing of BusLogic Driver Options
+  specifications.
 
-  The string options are used to provide control over Tagged Queuing, Error
-  Recovery, and Host Adapter Probing.
+  BusLogic Driver Options may be specified either via the Linux Kernel Command
+  Line or via the Loadable Kernel Module Installation Facility.  Driver Options
+  for multiple host adapters may be specified either by separating the option
+  strings by a semicolon, or by specifying multiple "BusLogic=" strings on the
+  command line.  Individual option specifications for a single host adapter are
+  separated by commas.  The Probing and Debugging Options apply to all host
+  adapters whereas the remaining options apply individually only to the
+  selected host adapter.
 
-  The Tagged Queuing specification begins with "TQ:" and allows for explicitly
-  specifying whether Tagged Queuing is permitted on Target Devices that support
-  it.  The following specification options are available:
-
-  TQ:Default		Tagged Queuing will be permitted based on the firmware
-			version of the BusLogic Host Adapter and based on
-			whether the Tagged Queue Depth value allows queuing
-			multiple commands.
-
-  TQ:Enable		Tagged Queuing will be enabled for all Target Devices
-			on this Host Adapter overriding any limitation that
-			would otherwise be imposed based on the Host Adapter
-			firmware version.
-
-  TQ:Disable		Tagged Queuing will be disabled for all Target Devices
-			on this Host Adapter.
-
-  TQ:<Per-Target-Spec>	Tagged Queuing will be controlled individually for each
-			Target Device.  <Per-Target-Spec> is a sequence of "Y",
-			"N", and "X" characters.  "Y" enabled Tagged Queuing,
-			"N" disables Tagged Queuing, and "X" accepts the
-			default based on the firmware version.  The first
-			character refers to Target Device 0, the second to
-			Target Device 1, and so on; if the sequence of "Y",
-			"N", and "X" characters does not cover all the Target
-			Devices, unspecified characters are assumed to be "X".
-
-  Note that explicitly requesting Tagged Queuing may lead to problems; this
-  facility is provided primarily to allow disabling Tagged Queuing on Target
-  Devices that do not implement it correctly.
-
-  The Error Recovery Strategy specification begins with "ER:" and allows for
-  explicitly specifying the Error Recovery action to be performed when
-  ResetCommand is called due to a SCSI Command failing to complete
-  successfully.  The following specification options are available:
-
-  ER:Default		Error Recovery will select between the Hard Reset and
-			Bus Device Reset options based on the recommendation
-			of the SCSI Subsystem.
-
-  ER:HardReset		Error Recovery will initiate a Host Adapter Hard Reset
-			which also causes a SCSI Bus Reset.
-
-  ER:BusDeviceReset	Error Recovery will send a Bus Device Reset message to
-			the individual Target Device causing the error.  If
-			Error Recovery is again initiated for this Target
-			Device and no SCSI Command to this Target Device has
-			completed successfully since the Bus Device Reset
-			message was sent, then a Hard Reset will be attempted.
-
-  ER:None		Error Recovery will be suppressed.  This option should
-			only be selected if a SCSI Bus Reset or Bus Device
-			Reset will cause the Target Device to fail completely
-			and unrecoverably.
-
-  ER:<Per-Target-Spec>	Error Recovery will be controlled individually for each
-			Target Device.  <Per-Target-Spec> is a sequence of "D",
-			"H", "B", and "N" characters.  "D" selects Default, "H"
-			selects Hard Reset, "B" selects Bus Device Reset, and
-			"N" selects None.  The first character refers to Target
-			Device 0, the second to Target Device 1, and so on; if
-			the sequence of "D", "H", "B", and "N" characters does
-			not cover all the possible Target Devices, unspecified
-			characters are assumed to be "D".
-
-  The Host Adapter Probing specification comprises the following strings:
-
-  NoProbe		No probing of any kind is to be performed, and hence
-			no BusLogic Host Adapters will be detected.
-
-  NoProbeISA		No probing of the standard ISA I/O Addresses will
-			be done, and hence only PCI MultiMaster and FlashPoint
-			Host Adapters will be detected.
-
-  NoProbePCI		No interrogation of PCI Configuration Space will be
-			made, and hence only ISA Multimaster Host Adapters
-			will be detected, as well as PCI Multimaster Host
-			Adapters that have their ISA Compatible I/O Port
-			set to "Primary" or "Alternate".
-
-  NoSortPCI		PCI MultiMaster Host Adapters will be enumerated in
-			the order provided by the PCI BIOS, ignoring any
-			setting of the AutoSCSI "Use Bus And Device # For PCI
-			Scanning Seq." option.
-
-  MultiMasterFirst	By default, if both FlashPoint and PCI MultiMaster
-			Host Adapters are present, this driver will probe for
-			FlashPoint Host Adapters first unless the BIOS primary
-			disk is controlled by the first PCI MultiMaster Host
-			Adapter, in which case MultiMaster Host Adapters will
-			be probed first.  This option forces MultiMaster Host
-			Adapters to be probed first.
-
-  FlashPointFirst	By default, if both FlashPoint and PCI MultiMaster
-			Host Adapters are present, this driver will probe for
-			FlashPoint Host Adapters first unless the BIOS primary
-			disk is controlled by the first PCI MultiMaster Host
-			Adapter, in which case MultiMaster Host Adapters will
-			be probed first.  This option forces FlashPoint Host
-			Adapters to be probed first.
-
-  Debug			Sets all the tracing bits in BusLogic_GlobalOptions.
-
-*/
-
-void BusLogic_Setup(char *Strings, int *Integers)
-{
-  BusLogic_CommandLineEntry_T *CommandLineEntry =
-    &BusLogic_CommandLineEntries[BusLogic_CommandLineEntryCount++];
-  int IntegerCount = Integers[0];
-  int TargetID, i;
-  CommandLineEntry->IO_Address = 0;
-  CommandLineEntry->TaggedQueueDepth = 0;
-  CommandLineEntry->BusSettleTime = 0;
-  CommandLineEntry->TaggedQueuingPermitted = 0;
-  CommandLineEntry->TaggedQueuingPermittedMask = 0;
-  CommandLineEntry->LocalOptions.All = 0;
-  memset(CommandLineEntry->ErrorRecoveryStrategy,
-	 BusLogic_ErrorRecovery_Default,
-	 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-  if (IntegerCount > 5)
-    BusLogic_Error("BusLogic: Unexpected Command Line Integers "
-		   "ignored\n", NULL);
-  if (IntegerCount >= 1)
-    {
-      BusLogic_IO_Address_T IO_Address = Integers[1];
-      if (IO_Address > 0)
-	{
-	  BusLogic_ProbeInfo_T *ProbeInfo;
-	  for (i = 0; ; i++)
-	    if (BusLogic_ISA_StandardAddresses[i] == 0)
-	      {
-		BusLogic_Error("BusLogic: Invalid Command Line Entry "
-			       "(illegal I/O Address 0x%X)\n",
-			       NULL, IO_Address);
-		return;
-	      }
-	    else if (i < BusLogic_ProbeInfoCount &&
-		     IO_Address == BusLogic_ProbeInfoList[i].IO_Address)
-	      {
-		BusLogic_Error("BusLogic: Invalid Command Line Entry "
-			       "(duplicate I/O Address 0x%X)\n",
-			       NULL, IO_Address);
-		return;
-	      }
-	    else if (IO_Address >= 0x400 ||
-		     IO_Address == BusLogic_ISA_StandardAddresses[i]) break;
-	  ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
-	  ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
-	  ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
-	}
-      CommandLineEntry->IO_Address = IO_Address;
-    }
-  if (IntegerCount >= 2)
-    {
-      unsigned short TaggedQueueDepth = Integers[2];
-      if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth)
-	{
-	  BusLogic_Error("BusLogic: Invalid Command Line Entry "
-			 "(illegal Tagged Queue Depth %d)\n",
-			 NULL, TaggedQueueDepth);
+  The BusLogic Driver Probing Options comprise the following:
+
+  IO:<integer>
+
+    The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI
+    MultiMaster Host Adapter.  If neither "IO:" nor "NoProbeISA" options are
+    specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses
+    will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134).  Multiple
+    "IO:" options may be specified to precisely determine the I/O Addresses to
+    be probed, but the probe order will always follow the standard list.
+
+  NoProbe
+
+    The "NoProbe" option disables all probing and therefore no BusLogic Host
+    Adapters will be detected.
+
+  NoProbeISA
+
+    The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O
+    Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters
+    will be detected.
+
+  NoProbePCI
+
+    The "NoProbePCI" options disables the interrogation of PCI Configuration
+    Space and therefore only ISA Multimaster Host Adapters will be detected, as
+    well as PCI Multimaster Host Adapters that have their ISA Compatible I/O
+    Port set to "Primary" or "Alternate".
+
+  NoSortPCI
+
+    The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be
+    enumerated in the order provided by the PCI BIOS, ignoring any setting of
+    the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
+
+  MultiMasterFirst
+
+    The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed
+    before FlashPoint Host Adapters.  By default, if both FlashPoint and PCI
+    MultiMaster Host Adapters are present, this driver will probe for
+    FlashPoint Host Adapters first unless the BIOS primary disk is controlled
+    by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host
+    Adapters will be probed first.
+
+  FlashPointFirst
+
+    The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed
+    before MultiMaster Host Adapters.
+
+  The BusLogic Driver Tagged Queuing Options allow for explicitly specifying
+  the Queue Depth and whether Tagged Queuing is permitted for each Target
+  Device (assuming that the Target Device supports Tagged Queuing).  The Queue
+  Depth is the number of SCSI Commands that are allowed to be concurrently
+  presented for execution (either to the Host Adapter or Target Device).  Note
+  that explicitly enabling Tagged Queuing may lead to problems; the option to
+  enable or disable Tagged Queuing is provided primarily to allow disabling
+  Tagged Queuing on Target Devices that do not implement it correctly.  The
+  following options are available:
+
+  QueueDepth:<integer>
+
+    The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
+    Target Devices that support Tagged Queuing.  If no Queue Depth option is
+    provided, the Queue Depth will be determined automatically based on the
+    Host Adapter's Total Queue Depth and the number, type, speed, and
+    capabilities of the detected Target Devices.  For Host Adapters that
+    require ISA Bounce Buffers, the Queue Depth is automatically set by default
+    to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA
+    Bounce Buffer memory.  Target Devices that do not support Tagged Queuing
+    always use a Queue Depth of BusLogic_UntaggedQueueDepth.
+
+  QueueDepth:[<integer>,<integer>...]
+
+    The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth
+    individually for each Target Device.  If an <integer> is omitted, the
+    associated Target Device will have its Queue Depth selected automatically.
+
+  TaggedQueuing:Default
+
+    The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing
+    based on the firmware version of the BusLogic Host Adapter and based on
+    whether the Queue Depth allows queuing multiple commands.
+
+  TaggedQueuing:Enable
+
+    The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for
+    all Target Devices on this Host Adapter, overriding any limitation that
+    would otherwise be imposed based on the Host Adapter firmware version.
+
+  TaggedQueuing:Disable
+
+    The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing
+    for all Target Devices on this Host Adapter.
+
+  TaggedQueuing:<Target-Spec>
+
+    The "TaggedQueuing:<Target-Spec>" or "TQ:<Target-Spec>" option controls
+    Tagged Queuing individually for each Target Device.  <Target-Spec> is a
+    sequence of "Y", "N", and "X" characters.  "Y" enables Tagged Queuing, "N"
+    disables Tagged Queuing, and "X" accepts the default based on the firmware
+    version.  The first character refers to Target Device 0, the second to
+    Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters
+    does not cover all the Target Devices, unspecified characters are assumed
+    to be "X".
+
+  The BusLogic Driver Error Recovery Option allows for explicitly specifying
+  the Error Recovery action to be performed when BusLogic_ResetCommand is
+  called due to a SCSI Command failing to complete successfully.  The following
+  options are available:
+
+  ErrorRecovery:Default
+
+    The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard
+    Reset and Bus Device Reset options based on the recommendation of the SCSI
+    Subsystem.
+
+  ErrorRecovery:HardReset
+
+    The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host
+    Adapter Hard Reset which also causes a SCSI Bus Reset.
+
+  ErrorRecovery:BusDeviceReset
+
+    The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send
+    a Bus Device Reset message to the individual Target Device causing the
+    error.  If Error Recovery is again initiated for this Target Device and no
+    SCSI Command to this Target Device has completed successfully since the Bus
+    Device Reset message was sent, then a Hard Reset will be attempted.
+
+  ErrorRecovery:None
+
+    The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery.
+    This option should only be selected if a SCSI Bus Reset or Bus Device Reset
+    will cause the Target Device or a critical operation to suffer a complete
+    and unrecoverable failure.
+
+  ErrorRecovery:<Target-Spec>
+
+    The "ErrorRecovery:<Target-Spec>" or "ER:<Target-Spec>" option controls
+    Error Recovery individually for each Target Device.  <Target-Spec> is a
+    sequence of "D", "H", "B", and "N" characters.  "D" selects Default, "H"
+    selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None.
+    The first character refers to Target Device 0, the second to Target Device
+    1, and so on; if the sequence of "D", "H", "B", and "N" characters does not
+    cover all the possible Target Devices, unspecified characters are assumed
+    to be "D".
+
+  The BusLogic Driver Miscellaneous Options comprise the following:
+
+  BusSettleTime:<seconds>
+
+    The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in
+    seconds.  The Bus Settle Time is the amount of time to wait between a Host
+    Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI
+    Commands.  If unspecified, it defaults to BusLogic_DefaultBusSettleTime.
+
+  InhibitTargetInquiry
+
+    The "InhibitTargetInquiry" option inhibits the execution of an Inquire
+    Target Devices or Inquire Installed Devices command on MultiMaster Host
+    Adapters.  This may be necessary with some older Target Devices that do not
+    respond correctly when Logical Units above 0 are addressed.
+
+  The BusLogic Driver Debugging Options comprise the following:
+
+  TraceProbe
+
+    The "TraceProbe" option enables tracing of Host Adapter Probing.
+
+  TraceHardwareReset
+
+    The "TraceHardwareReset" option enables tracing of Host Adapter Hardware
+    Reset.
+
+  TraceConfiguration
+
+    The "TraceConfiguration" option enables tracing of Host Adapter
+    Configuration.
+
+  TraceErrors
+
+    The "TraceErrors" option enables tracing of SCSI Commands that return an
+    error from the Target Device.  The CDB and Sense Data will be printed for
+    each SCSI Command that fails.
+
+  Debug
+
+    The "Debug" option enables all debugging options.
+
+  The following examples demonstrate setting the Queue Depth for Target Devices
+  1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target
+  Devices on the second host adapter to 31, and the Bus Settle Time on the
+  second host adapter to 30 seconds.
+
+  Linux Kernel Command Line:
+
+    linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30
+
+  LILO Linux Boot Loader (in /etc/lilo.conf):
+
+    append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"
+
+  INSMOD Loadable Kernel Module Installation Facility:
+
+    insmod BusLogic.o \
+	'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"'
+
+  NOTE: Module Utilities 2.1.71 or later is required for correct parsing
+	of driver options containing commas.
+
+*/
+
+static void BusLogic_ParseDriverOptions(char *OptionsString)
+{
+  while (true)
+    {
+      BusLogic_DriverOptions_T *DriverOptions =
+	&BusLogic_DriverOptions[BusLogic_DriverOptionsCount++];
+      int TargetID;
+      memset(DriverOptions, 0, sizeof(BusLogic_DriverOptions_T));
+      for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+	DriverOptions->ErrorRecoveryStrategy[TargetID] =
+	  BusLogic_ErrorRecovery_Default;
+      while (*OptionsString != '\0' && *OptionsString != ';')
+	{
+	  /* Probing Options. */
+	  if (BusLogic_ParseKeyword(&OptionsString, "IO:"))
+	    {
+	      BusLogic_IO_Address_T IO_Address =
+		simple_strtoul(OptionsString, &OptionsString, 0);
+	      BusLogic_ProbeOptions.LimitedProbeISA = true;
+	      switch (IO_Address)
+		{
+		case 0x330:
+		  BusLogic_ProbeOptions.Probe330 = true;
+		  break;
+		case 0x334:
+		  BusLogic_ProbeOptions.Probe334 = true;
+		  break;
+		case 0x230:
+		  BusLogic_ProbeOptions.Probe230 = true;
+		  break;
+		case 0x234:
+		  BusLogic_ProbeOptions.Probe234 = true;
+		  break;
+		case 0x130:
+		  BusLogic_ProbeOptions.Probe130 = true;
+		  break;
+		case 0x134:
+		  BusLogic_ProbeOptions.Probe134 = true;
+		  break;
+		default:
+		  BusLogic_Error("BusLogic: Invalid Driver Options "
+				 "(illegal I/O Address 0x%X)\n",
+				 NULL, IO_Address);
+		  return;
+		}
+	    }
+	  else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA"))
+	    BusLogic_ProbeOptions.NoProbeISA = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI"))
+	    BusLogic_ProbeOptions.NoProbePCI = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe"))
+	    BusLogic_ProbeOptions.NoProbe = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI"))
+	    BusLogic_ProbeOptions.NoSortPCI = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst"))
+	    BusLogic_ProbeOptions.MultiMasterFirst = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst"))
+	    BusLogic_ProbeOptions.FlashPointFirst = true;
+	  /* Tagged Queuing Options. */
+	  else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") ||
+		   BusLogic_ParseKeyword(&OptionsString, "QD:["))
+	    {
+	      for (TargetID = 0;
+		   TargetID < BusLogic_MaxTargetDevices;
+		   TargetID++)
+		{
+		  unsigned short QueueDepth =
+		    simple_strtoul(OptionsString, &OptionsString, 0);
+		  if (QueueDepth > BusLogic_MaxTaggedQueueDepth)
+		    {
+		      BusLogic_Error("BusLogic: Invalid Driver Options "
+				     "(illegal Queue Depth %d)\n",
+				     NULL, QueueDepth);
+		      return;
+		    }
+		  DriverOptions->QueueDepth[TargetID] = QueueDepth;
+		  if (*OptionsString == ',')
+		    OptionsString++;
+		  else if (*OptionsString == ']')
+		    break;
+		  else
+		    {
+		      BusLogic_Error("BusLogic: Invalid Driver Options "
+				     "(',' or ']' expected at '%s')\n",
+				     NULL, OptionsString);
+		      return;
+		    }
+		}
+	      if (*OptionsString != ']')
+		{
+		  BusLogic_Error("BusLogic: Invalid Driver Options "
+				 "(']' expected at '%s')\n",
+				 NULL, OptionsString);
+		  return;
+		}
+	      else OptionsString++;
+	    }
+	  else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") ||
+		   BusLogic_ParseKeyword(&OptionsString, "QD:"))
+	    {
+	      unsigned short QueueDepth =
+		simple_strtoul(OptionsString, &OptionsString, 0);
+	      if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth)
+		{
+		  BusLogic_Error("BusLogic: Invalid Driver Options "
+				 "(illegal Queue Depth %d)\n",
+				 NULL, QueueDepth);
+		  return;
+		}
+	      for (TargetID = 0;
+		   TargetID < BusLogic_MaxTargetDevices;
+		   TargetID++)
+		DriverOptions->QueueDepth[TargetID] = QueueDepth;
+	    }
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") ||
+		   BusLogic_ParseKeyword(&OptionsString, "TQ:"))
+	    {
+	      if (BusLogic_ParseKeyword(&OptionsString, "Default"))
+		{
+		  DriverOptions->TaggedQueuingPermitted = 0x0000;
+		  DriverOptions->TaggedQueuingPermittedMask = 0x0000;
+		}
+	      else if (BusLogic_ParseKeyword(&OptionsString, "Enable"))
+		{
+		  DriverOptions->TaggedQueuingPermitted = 0xFFFF;
+		  DriverOptions->TaggedQueuingPermittedMask = 0xFFFF;
+		}
+	      else if (BusLogic_ParseKeyword(&OptionsString, "Disable"))
+		{
+		  DriverOptions->TaggedQueuingPermitted = 0x0000;
+		  DriverOptions->TaggedQueuingPermittedMask = 0xFFFF;
+		}
+	      else
+		{
+		  unsigned short TargetBit;
+		  for (TargetID = 0, TargetBit = 1;
+		       TargetID < BusLogic_MaxTargetDevices;
+		       TargetID++, TargetBit <<= 1)
+		    switch (*OptionsString++)
+		      {
+		      case 'Y':
+			DriverOptions->TaggedQueuingPermitted |= TargetBit;
+			DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+			break;
+		      case 'N':
+			DriverOptions->TaggedQueuingPermitted &= ~TargetBit;
+			DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+			break;
+		      case 'X':
+			break;
+		      default:
+			OptionsString--;
+			TargetID = BusLogic_MaxTargetDevices;
+			break;
+		      }
+		}
+	    }
+	  /* Error Recovery Option. */
+	  else if (BusLogic_ParseKeyword(&OptionsString, "ErrorRecovery:") ||
+		   BusLogic_ParseKeyword(&OptionsString, "ER:"))
+	    {
+	      if (BusLogic_ParseKeyword(&OptionsString, "Default"))
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  DriverOptions->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_Default;
+	      else if (BusLogic_ParseKeyword(&OptionsString, "HardReset"))
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  DriverOptions->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_HardReset;
+	      else if (BusLogic_ParseKeyword(&OptionsString, "BusDeviceReset"))
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  DriverOptions->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_BusDeviceReset;
+	      else if (BusLogic_ParseKeyword(&OptionsString, "None"))
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  DriverOptions->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_None;
+	      else
+		for (TargetID = 0;
+		     TargetID < BusLogic_MaxTargetDevices;
+		     TargetID++)
+		  switch (*OptionsString++)
+		    {
+		    case 'D':
+		      DriverOptions->ErrorRecoveryStrategy[TargetID] =
+			BusLogic_ErrorRecovery_Default;
+		      break;
+		    case 'H':
+		      DriverOptions->ErrorRecoveryStrategy[TargetID] =
+			BusLogic_ErrorRecovery_HardReset;
+		      break;
+		    case 'B':
+		      DriverOptions->ErrorRecoveryStrategy[TargetID] =
+			BusLogic_ErrorRecovery_BusDeviceReset;
+		      break;
+		    case 'N':
+		      DriverOptions->ErrorRecoveryStrategy[TargetID] =
+			BusLogic_ErrorRecovery_None;
+		      break;
+		    default:
+		      OptionsString--;
+		      TargetID = BusLogic_MaxTargetDevices;
+		      break;
+		    }
+	    }
+	  /* Miscellaneous Options. */
+	  else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") ||
+		   BusLogic_ParseKeyword(&OptionsString, "BST:"))
+	    {
+	      unsigned short BusSettleTime =
+		simple_strtoul(OptionsString, &OptionsString, 0);
+	      if (BusSettleTime > 5 * 60)
+		{
+		  BusLogic_Error("BusLogic: Invalid Driver Options "
+				 "(illegal Bus Settle Time %d)\n",
+				 NULL, BusSettleTime);
+		  return;
+		}
+	      DriverOptions->BusSettleTime = BusSettleTime;
+	    }
+	  else if (BusLogic_ParseKeyword(&OptionsString,
+					 "InhibitTargetInquiry"))
+	    DriverOptions->LocalOptions.InhibitTargetInquiry = true;
+	  /* Debugging Options. */
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe"))
+	      BusLogic_GlobalOptions.TraceProbe = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset"))
+	      BusLogic_GlobalOptions.TraceHardwareReset = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration"))
+	      BusLogic_GlobalOptions.TraceConfiguration = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors"))
+	      BusLogic_GlobalOptions.TraceErrors = true;
+	  else if (BusLogic_ParseKeyword(&OptionsString, "Debug"))
+	    {
+	      BusLogic_GlobalOptions.TraceProbe = true;
+	      BusLogic_GlobalOptions.TraceHardwareReset = true;
+	      BusLogic_GlobalOptions.TraceConfiguration = true;
+	      BusLogic_GlobalOptions.TraceErrors = true;
+	    }
+	  if (*OptionsString == ',')
+	    OptionsString++;
+	  else if (*OptionsString != ';' && *OptionsString != '\0')
+	    {
+	      BusLogic_Error("BusLogic: Unexpected Driver Option '%s' "
+			     "ignored\n", NULL, OptionsString);
+	      *OptionsString = '\0';
+	    }
+	}
+      if (!(BusLogic_DriverOptionsCount == 0 ||
+	    BusLogic_ProbeInfoCount == 0 ||
+	    BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount))
+	{
+	  BusLogic_Error("BusLogic: Invalid Driver Options "
+			 "(all or no I/O Addresses must be specified)\n", NULL);
 	  return;
 	}
-      CommandLineEntry->TaggedQueueDepth = TaggedQueueDepth;
+      /*
+	Tagged Queuing is disabled when the Queue Depth is 1 since queuing
+	multiple commands is not possible.
+      */
+      for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+	if (DriverOptions->QueueDepth[TargetID] == 1)
+	  {
+	    unsigned short TargetBit = 1 << TargetID;
+	    DriverOptions->TaggedQueuingPermitted &= ~TargetBit;
+	    DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+	  }
+      if (*OptionsString == ';') OptionsString++;
+      if (*OptionsString == '\0') return;
     }
-  if (IntegerCount >= 3)
-    CommandLineEntry->BusSettleTime = Integers[3];
-  if (IntegerCount >= 4)
-    CommandLineEntry->LocalOptions.All = Integers[4];
-  if (IntegerCount >= 5)
-    BusLogic_GlobalOptions.All |= Integers[5];
-  if (!(BusLogic_CommandLineEntryCount == 0 ||
-	BusLogic_ProbeInfoCount == 0 ||
-	BusLogic_CommandLineEntryCount == BusLogic_ProbeInfoCount))
+}
+
+
+/*
+  BusLogic_Setup handles processing of Kernel Command Line Arguments.
+*/
+
+void BusLogic_Setup(char *CommandLineString, int *CommandLineIntegers)
+{
+  if (CommandLineIntegers[0] != 0)
     {
-      BusLogic_Error("BusLogic: Invalid Command Line Entry "
-		     "(all or no I/O Addresses must be specified)\n", NULL);
+      BusLogic_Error("BusLogic: Obsolete Command Line Entry "
+		     "Format Ignored\n", NULL);
       return;
     }
-  if (Strings == NULL) return;
-  while (*Strings != '\0')
-    if (strncmp(Strings, "TQ:", 3) == 0)
-      {
-	Strings += 3;
-	if (strncmp(Strings, "Default", 7) == 0)
-	  Strings += 7;
-	else if (strncmp(Strings, "Enable", 6) == 0)
-	  {
-	    Strings += 6;
-	    CommandLineEntry->TaggedQueuingPermitted = 0xFFFF;
-	    CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
-	  }
-	else if (strncmp(Strings, "Disable", 7) == 0)
-	  {
-	    Strings += 7;
-	    CommandLineEntry->TaggedQueuingPermitted = 0x0000;
-	    CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
-	  }
-	else
-	  for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
-	    switch (*Strings++)
-	      {
-	      case 'Y':
-		CommandLineEntry->TaggedQueuingPermitted |= 1 << TargetID;
-		CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
-		break;
-	      case 'N':
-		CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
-		break;
-	      case 'X':
-		break;
-	      default:
-		Strings--;
-		TargetID = BusLogic_MaxTargetDevices;
-		break;
-	      }
-      }
-    else if (strncmp(Strings, "ER:", 3) == 0)
-      {
-	Strings += 3;
-	if (strncmp(Strings, "Default", 7) == 0)
-	  Strings += 7;
-	else if (strncmp(Strings, "HardReset", 9) == 0)
-	  {
-	    Strings += 9;
-	    memset(CommandLineEntry->ErrorRecoveryStrategy,
-		   BusLogic_ErrorRecovery_HardReset,
-		   sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-	  }
-	else if (strncmp(Strings, "BusDeviceReset", 14) == 0)
-	  {
-	    Strings += 14;
-	    memset(CommandLineEntry->ErrorRecoveryStrategy,
-		   BusLogic_ErrorRecovery_BusDeviceReset,
-		   sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-	  }
-	else if (strncmp(Strings, "None", 4) == 0)
-	  {
-	    Strings += 4;
-	    memset(CommandLineEntry->ErrorRecoveryStrategy,
-		   BusLogic_ErrorRecovery_None,
-		   sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-	  }
-	else
-	  for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
-	    switch (*Strings++)
-	      {
-	      case 'D':
-		CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		  BusLogic_ErrorRecovery_Default;
-		break;
-	      case 'H':
-		CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		  BusLogic_ErrorRecovery_HardReset;
-		break;
-	      case 'B':
-		CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		  BusLogic_ErrorRecovery_BusDeviceReset;
-		break;
-	      case 'N':
-		CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		  BusLogic_ErrorRecovery_None;
-		break;
-	      default:
-		Strings--;
-		TargetID = BusLogic_MaxTargetDevices;
-		break;
-	      }
-      }
-    else if (strcmp(Strings, "NoProbe") == 0 ||
-	     strcmp(Strings, "noprobe") == 0)
-      {
-	Strings += 7;
-	BusLogic_ProbeOptions.Bits.NoProbe = true;
-      }
-    else if (strncmp(Strings, "NoProbeISA", 10) == 0)
-      {
-	Strings += 10;
-	BusLogic_ProbeOptions.Bits.NoProbeISA = true;
-      }
-    else if (strncmp(Strings, "NoProbePCI", 10) == 0)
-      {
-	Strings += 10;
-	BusLogic_ProbeOptions.Bits.NoProbePCI = true;
-      }
-    else if (strncmp(Strings, "NoSortPCI", 9) == 0)
-      {
-	Strings += 9;
-	BusLogic_ProbeOptions.Bits.NoSortPCI = true;
-      }
-    else if (strncmp(Strings, "MultiMasterFirst", 16) == 0)
-      {
-	Strings += 16;
-	BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst = true;
-      }
-    else if (strncmp(Strings, "FlashPointFirst", 15) == 0)
-      {
-	Strings += 15;
-	BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst = true;
-      }
-    else if (strncmp(Strings, "Debug", 5) == 0)
-      {
-	Strings += 5;
-	BusLogic_GlobalOptions.Bits.TraceProbe = true;
-	BusLogic_GlobalOptions.Bits.TraceHardReset = true;
-	BusLogic_GlobalOptions.Bits.TraceConfiguration = true;
-	BusLogic_GlobalOptions.Bits.TraceErrors = true;
-      }
-    else if (*Strings == ',')
-      Strings++;
-    else
-      {
-	BusLogic_Error("BusLogic: Unexpected Command Line String '%s' "
-		       "ignored\n", NULL, Strings);
-	break;
-      }
+  if (CommandLineString == NULL || *CommandLineString == '\0') return;
+  BusLogic_ParseDriverOptions(CommandLineString);
 }
 
 
@@ -4724,6 +5020,8 @@
 */
 
 #ifdef MODULE
+
+MODULE_PARM(BusLogic_Options, "s");
 
 SCSI_Host_Template_T driver_template = BUSLOGIC;
 
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v2.1.86/linux/drivers/scsi/BusLogic.h	Fri Feb  6 15:33:40 1998
+++ linux/drivers/scsi/BusLogic.h	Mon Feb 16 15:34:59 1998
@@ -6,8 +6,7 @@
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
-  Free Software Foundation, provided that none of the source code or runtime
-  copyright notices are removed or modified.
+  Free Software Foundation.
 
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
@@ -27,6 +26,9 @@
 */
 
 
+#include <linux/config.h>
+
+
 /*
   Define types for some of the structures that interface with the rest
   of the Linux Kernel and SCSI Subsystem.
@@ -35,6 +37,7 @@
 typedef kdev_t KernelDevice_T;
 typedef struct proc_dir_entry PROC_DirectoryEntry_T;
 typedef struct pt_regs Registers_T;
+typedef struct partition PartitionTable_T;
 typedef Scsi_Host_Template SCSI_Host_Template_T;
 typedef struct Scsi_Host SCSI_Host_T;
 typedef struct scsi_device SCSI_Device_T;
@@ -63,19 +66,19 @@
   Define the BusLogic SCSI Host Template structure.
 */
 
-#define BUSLOGIC							 \
-  { proc_dir:          &BusLogic_ProcDirectoryEntry,	/* /proc Directory Entry     */	 \
-    proc_info:         BusLogic_ProcDirectoryInfo,	/* /proc Info Function	     */	 \
-    name:              "BusLogic",			/* Driver Name		     */	 \
-    detect:            BusLogic_DetectHostAdapter,	/* Detect Host Adapter	     */	 \
-    release:           BusLogic_ReleaseHostAdapter,	/* Release Host Adapter	     */	 \
-    info:              BusLogic_DriverInfo,		/* Driver Info Function	     */	 \
-    queuecommand:      BusLogic_QueueCommand,		/* Queue Command Function    */	 \
-    abort:             BusLogic_AbortCommand,		/* Abort Command Function    */	 \
-    reset:             BusLogic_ResetCommand,		/* Reset Command Function    */	 \
-    bios_param:        BusLogic_BIOSDiskParameters,	/* BIOS Disk Parameters	     */	 \
-    unchecked_isa_dma: 1,				/* Default Unchecked ISA DMA */	 \
-    use_clustering:    ENABLE_CLUSTERING }		/* Enable Clustering	     */
+#define BUSLOGIC							       \
+  { proc_dir:       &BusLogic_ProcDirectoryEntry, /* ProcFS Directory Entry */ \
+    proc_info:      BusLogic_ProcDirectoryInfo,	  /* ProcFS Info Function   */ \
+    name:           "BusLogic",			  /* Driver Name            */ \
+    detect:         BusLogic_DetectHostAdapter,	  /* Detect Host Adapter    */ \
+    release:        BusLogic_ReleaseHostAdapter,  /* Release Host Adapter   */ \
+    info:           BusLogic_DriverInfo,	  /* Driver Info Function   */ \
+    queuecommand:   BusLogic_QueueCommand,	  /* Queue Command Function */ \
+    abort:          BusLogic_AbortCommand,	  /* Abort Command Function */ \
+    reset:          BusLogic_ResetCommand,	  /* Reset Command Function */ \
+    bios_param:     BusLogic_BIOSDiskParameters,  /* BIOS Disk Parameters   */ \
+    unchecked_isa_dma: 1,			  /* Default Initial Value  */ \
+    use_clustering: ENABLE_CLUSTERING }		  /* Enable Clustering	    */
 
 
 /*
@@ -86,6 +89,24 @@
 
 
 /*
+  FlashPoint support is only available for the Intel x86 Architecture with
+  CONFIG_PCI set.
+*/
+
+#ifndef __i386__
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+#endif
+
+#ifndef CONFIG_PCI
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+#define BusLogic_InitializeProbeInfoListISA \
+  BusLogic_InitializeProbeInfoList
+#endif
+
+
+/*
   Define the maximum number of BusLogic Host Adapters supported by this driver.
 */
 
@@ -109,16 +130,17 @@
 
 
 /*
-  Define the maximum, preferred, and default Queue Depth to allow for Target
-  Devices depending on whether or not they support Tagged Queuing and whether
-  or not ISA Bounce Buffers are required.
+  Define the maximum, maximum automatic, minimum automatic, and default Queue
+  Depth to allow for Target Devices depending on whether or not they support
+  Tagged Queuing and whether or not ISA Bounce Buffers are required.
 */
 
-#define BusLogic_MaxTaggedQueueDepth		63
-#define BusLogic_PreferredTaggedQueueDepth	28
-#define BusLogic_TaggedQueueDepthBounceBuffers	2
-#define BusLogic_TaggedQueueDepthAutomatic	0
+#define BusLogic_MaxTaggedQueueDepth		64
+#define BusLogic_MaxAutomaticTaggedQueueDepth	28
+#define BusLogic_MinAutomaticTaggedQueueDepth	7
+#define BusLogic_TaggedQueueDepthBB		3
 #define BusLogic_UntaggedQueueDepth		3
+#define BusLogic_UntaggedQueueDepthBB		2
 
 
 /*
@@ -132,11 +154,29 @@
 
 
 /*
+  Define the maximum number of Mailboxes that should be used for MultiMaster
+  Host Adapters.  This number is chosen to be larger than the maximum Host
+  Adapter Queue Depth and small enough so that the Host Adapter structure
+  does not cross an allocation block size boundary.
+*/
+
+#define BusLogic_MaxMailboxes			211
+
+
+/*
+  Define the number of CCBs that should be allocated as a group to optimize
+  Kernel memory allocation.
+*/
+
+#define BusLogic_CCB_AllocationGroupSize	7
+
+
+/*
   Define the Host Adapter Line and Message Buffer Sizes.
 */
 
 #define BusLogic_LineBufferSize			100
-#define BusLogic_MessageBufferSize		9900
+#define BusLogic_MessageBufferSize		9700
 
 
 /*
@@ -155,7 +195,27 @@
 
 static char
   *BusLogic_MessageLevelMap[] =
-    { KERN_INFO, KERN_INFO, KERN_NOTICE, KERN_WARNING, KERN_ERR };
+    { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR };
+
+
+/*
+  Define Driver Message macros.
+*/
+
+#define BusLogic_Announce(Format, Arguments...) \
+  BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments)
+
+#define BusLogic_Info(Format, Arguments...) \
+  BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments)
+
+#define BusLogic_Notice(Format, Arguments...) \
+  BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments)
+
+#define BusLogic_Warning(Format, Arguments...) \
+  BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments)
+
+#define BusLogic_Error(Format, Arguments...) \
+  BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments)
 
 
 /*
@@ -175,11 +235,34 @@
 #define BusLogic_FlashPointAddressCount		256
 
 static int
-  BusLogic_HostAdapter_AddressCount[3] =
+  BusLogic_HostAdapterAddressCount[3] =
     { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount };
 
 
 /*
+  Define macros for testing the Host Adapter Type.
+*/
+
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
+
+#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
+  (HostAdapter->HostAdapterType == BusLogic_MultiMaster)
+
+#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
+  (HostAdapter->HostAdapterType == BusLogic_FlashPoint)
+
+#else
+
+#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
+  (true)
+
+#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
+  (false)
+
+#endif
+
+
+/*
   Define the possible Host Adapter Bus Types.
 */
 
@@ -192,6 +275,7 @@
   BusLogic_VESA_Bus =				4,
   BusLogic_MCA_Bus =				5
 }
+__attribute__ ((packed))
 BusLogic_HostAdapterBusType_T;
 
 static char
@@ -245,6 +329,13 @@
 
 
 /*
+  Define a 32 bit Base Address data type.
+*/
+
+typedef unsigned int BusLogic_Base_Address_T;
+
+
+/*
   Define a 32 bit Bus Address data type.
 */
 
@@ -276,11 +367,10 @@
 
 typedef struct BusLogic_ProbeInfo
 {
+  BusLogic_HostAdapterType_T HostAdapterType;
+  BusLogic_HostAdapterBusType_T HostAdapterBusType;
   BusLogic_IO_Address_T IO_Address;
   BusLogic_PCI_Address_T PCI_Address;
-  BusLogic_HostAdapterType_T HostAdapterType:2;
-  BusLogic_HostAdapterBusType_T HostAdapterBusType:3;
-  unsigned char :3;
   unsigned char Bus;
   unsigned char Device;
   unsigned char IRQ_Channel;
@@ -289,35 +379,24 @@
 
 
 /*
-  BusLogic_ISA_StandardAddresses is the list of standard ISA I/O Addresses at
-  which BusLogic MultiMaster Host Adapters may potentially be found.  The first
-  I/O Address 0x330 is known as the "Primary" I/O Address.  A Host Adapter
-  configured to use the Primary I/O Address will always be the preferred boot
-  device.
-*/
-
-#define BusLogic_ISA_StandardAddressesCount	6
-
-static BusLogic_IO_Address_T
-  BusLogic_ISA_StandardAddresses[BusLogic_ISA_StandardAddressesCount] =
-    { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134 };
-
-
-/*
   Define the Probe Options.
 */
 
-typedef union BusLogic_ProbeOptions
+typedef struct BusLogic_ProbeOptions
 {
-  unsigned short All;
-  struct {
-    boolean NoProbe:1;					/* Bit 0 */
-    boolean NoProbeISA:1;				/* Bit 1 */
-    boolean NoProbePCI:1;				/* Bit 2 */
-    boolean NoSortPCI:1;				/* Bit 3 */
-    boolean ProbeMultiMasterFirst:1;			/* Bit 4 */
-    boolean ProbeFlashPointFirst:1;			/* Bit 5 */
-  } Bits;
+  boolean NoProbe:1;					/* Bit 0 */
+  boolean NoProbeISA:1;					/* Bit 1 */
+  boolean NoProbePCI:1;					/* Bit 2 */
+  boolean NoSortPCI:1;					/* Bit 3 */
+  boolean MultiMasterFirst:1;				/* Bit 4 */
+  boolean FlashPointFirst:1;				/* Bit 5 */
+  boolean LimitedProbeISA:1;				/* Bit 6 */
+  boolean Probe330:1;					/* Bit 7 */
+  boolean Probe334:1;					/* Bit 8 */
+  boolean Probe230:1;					/* Bit 9 */
+  boolean Probe234:1;					/* Bit 10 */
+  boolean Probe130:1;					/* Bit 11 */
+  boolean Probe134:1;					/* Bit 12 */
 }
 BusLogic_ProbeOptions_T;
 
@@ -326,15 +405,12 @@
   Define the Global Options.
 */
 
-typedef union BusLogic_GlobalOptions
+typedef struct BusLogic_GlobalOptions
 {
-  unsigned short All;
-  struct {
-    boolean TraceProbe:1;				/* Bit 0 */
-    boolean TraceHardReset:1;				/* Bit 1 */
-    boolean TraceConfiguration:1;			/* Bit 2 */
-    boolean TraceErrors:1;				/* Bit 3 */
-  } Bits;
+  boolean TraceProbe:1;					/* Bit 0 */
+  boolean TraceHardwareReset:1;				/* Bit 1 */
+  boolean TraceConfiguration:1;				/* Bit 2 */
+  boolean TraceErrors:1;				/* Bit 3 */
 }
 BusLogic_GlobalOptions_T;
 
@@ -343,13 +419,9 @@
   Define the Local Options.
 */
 
-typedef union BusLogic_LocalOptions
+typedef struct BusLogic_LocalOptions
 {
-  unsigned short All;
-  struct {
-    boolean InhibitTargetInquiry:1;			/* Bit 0 */
-    boolean InhibitInterruptTest:1;			/* Bit 1 */
-  } Bits;
+  boolean InhibitTargetInquiry:1;			/* Bit 0 */
 }
 BusLogic_LocalOptions_T;
 
@@ -607,10 +679,13 @@
   unsigned char Signature;				/* Byte 17 */
   unsigned char CharacterD;				/* Byte 18 */
   unsigned char HostBusType;				/* Byte 19 */
-  unsigned char :8;					/* Byte 20 */
-  unsigned char :8;					/* Byte 21 */
+  unsigned char WideTransfersPermittedID0to7;		/* Byte 20 */
+  unsigned char WideTransfersActiveID0to7;		/* Byte 21 */
   BusLogic_SynchronousValues8_T SynchronousValuesID8to15; /* Bytes 22-29 */
   unsigned char DisconnectPermittedID8to15;		/* Byte 30 */
+  unsigned char :8;					/* Byte 31 */
+  unsigned char WideTransfersPermittedID8to15;		/* Byte 32 */
+  unsigned char WideTransfersActiveID8to15;		/* Byte 33 */
 }
 BusLogic_SetupInformation_T;
 
@@ -1052,6 +1127,21 @@
 
 
 /*
+  Define the Driver CCB Status Codes.
+*/
+
+typedef enum
+{
+  BusLogic_CCB_Free =				0,
+  BusLogic_CCB_Active =				1,
+  BusLogic_CCB_Completed =			2,
+  BusLogic_CCB_Reset =				3
+}
+__attribute__ ((packed))
+BusLogic_CCB_Status_T;
+
+
+/*
   Define the 32 Bit Mode Command Control Block (CCB) structure.  The first 40
   bytes are defined by and common to both the MultiMaster Firmware and the
   FlashPoint SCCB Manager.  The next 60 bytes are defined by the FlashPoint
@@ -1101,27 +1191,26 @@
     FlashPoint SCCB Manager Defined Portion.
   */
   void (*CallbackFunction)(struct BusLogic_CCB *);	/* Bytes 40-43 */
-  BusLogic_IO_Address_T BaseAddress;			/* Bytes 44-47 */
+  BusLogic_Base_Address_T BaseAddress;			/* Bytes 44-47 */
   BusLogic_CompletionCode_T CompletionCode;		/* Byte 48 */
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
   unsigned char :8;					/* Byte 49 */
   unsigned short OS_Flags;				/* Bytes 50-51 */
   unsigned char Private[48];				/* Bytes 52-99 */
+#endif
   /*
     BusLogic Linux Driver Defined Portion.
   */
-  struct BusLogic_HostAdapter *HostAdapter;
-  SCSI_Command_T *Command;
-  enum { BusLogic_CCB_Free =	    0,
-	 BusLogic_CCB_Active =	    1,
-	 BusLogic_CCB_Completed =   2,
-	 BusLogic_CCB_Reset =	    3 } Status;
+  boolean AllocationGroupHead;
+  BusLogic_CCB_Status_T Status;
   unsigned long SerialNumber;
+  SCSI_Command_T *Command;
+  struct BusLogic_HostAdapter *HostAdapter;
   struct BusLogic_CCB *Next;
   struct BusLogic_CCB *NextAll;
   BusLogic_ScatterGatherSegment_T
     ScatterGatherList[BusLogic_ScatterGatherLimit];
 }
-__attribute__ ((packed))
 BusLogic_CCB_T;
 
 
@@ -1154,32 +1243,48 @@
 
 
 /*
-  Define the Linux BusLogic Driver Command Line Entry structure.
+  Define the BusLogic Driver Options structure.
 */
 
-typedef struct BusLogic_CommandLineEntry
+typedef struct BusLogic_DriverOptions
 {
-  BusLogic_IO_Address_T IO_Address;
-  unsigned short TaggedQueueDepth;
-  unsigned short BusSettleTime;
   unsigned short TaggedQueuingPermitted;
   unsigned short TaggedQueuingPermittedMask;
+  unsigned short BusSettleTime;
   BusLogic_LocalOptions_T LocalOptions;
+  unsigned char QueueDepth[BusLogic_MaxTargetDevices];
   BusLogic_ErrorRecoveryStrategy_T
     ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
 }
-BusLogic_CommandLineEntry_T;
+BusLogic_DriverOptions_T;
 
 
 /*
-  Define the Host Adapter Target Device Statistics structure.
+  Define the Host Adapter Target Flags structure.
+*/
+
+typedef struct BusLogic_TargetFlags
+{
+  boolean TargetExists:1;
+  boolean TaggedQueuingSupported:1;
+  boolean WideTransfersSupported:1;
+  boolean TaggedQueuingActive:1;
+  boolean WideTransfersActive:1;
+  boolean CommandSuccessfulFlag:1;
+  boolean TargetInfoReported:1;
+}
+BusLogic_TargetFlags_T;
+
+
+/*
+  Define the Host Adapter Target Statistics structure.
 */
 
 #define BusLogic_SizeBuckets			10
 
 typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets];
 
-typedef struct BusLogic_TargetDeviceStatistics
+typedef struct BusLogic_TargetStatistics
 {
   unsigned int CommandsAttempted;
   unsigned int CommandsCompleted;
@@ -1199,7 +1304,7 @@
   unsigned short HostAdapterResetsAttempted;
   unsigned short HostAdapterResetsCompleted;
 }
-BusLogic_TargetDeviceStatistics_T;
+BusLogic_TargetStatistics_T;
 
 
 /*
@@ -1218,7 +1323,7 @@
 
 typedef struct FlashPoint_Info
 {
-  BusLogic_IO_Address_T BaseAddress;			/* Bytes 0-3 */
+  BusLogic_Base_Address_T BaseAddress;			/* Bytes 0-3 */
   boolean Present;					/* Byte 4 */
   unsigned char IRQ_Channel;				/* Byte 5 */
   unsigned char SCSI_ID;				/* Byte 6 */
@@ -1253,12 +1358,14 @@
 
 
 /*
-  Define the Linux BusLogic Driver Host Adapter structure.
+  Define the BusLogic Driver Host Adapter structure.
 */
 
 typedef struct BusLogic_HostAdapter
 {
   SCSI_Host_T *SCSI_Host;
+  BusLogic_HostAdapterType_T HostAdapterType;
+  BusLogic_HostAdapterBusType_T HostAdapterBusType;
   BusLogic_IO_Address_T IO_Address;
   BusLogic_PCI_Address_T PCI_Address;
   unsigned short AddressCount;
@@ -1267,18 +1374,16 @@
   unsigned char FirmwareVersion[6];
   unsigned char FullModelName[18];
   unsigned char InterruptLabel[68];
+  unsigned char Bus;
+  unsigned char Device;
   unsigned char IRQ_Channel;
   unsigned char DMA_Channel;
   unsigned char SCSI_ID;
-  unsigned char Bus;
-  unsigned char Device;
-  BusLogic_HostAdapterType_T HostAdapterType;
-  BusLogic_HostAdapterBusType_T HostAdapterBusType:3;
   boolean IRQ_ChannelAcquired:1;
   boolean DMA_ChannelAcquired:1;
   boolean ExtendedTranslationEnabled:1;
   boolean ParityCheckingEnabled:1;
-  boolean BusResetEnabled;
+  boolean BusResetEnabled:1;
   boolean LevelSensitiveInterrupt:1;
   boolean HostWideSCSI:1;
   boolean HostDifferentialSCSI:1;
@@ -1292,8 +1397,9 @@
   boolean StrictRoundRobinModeSupport:1;
   boolean SCAM_Enabled:1;
   boolean SCAM_Level2:1;
-  boolean HostAdapterInitialized;
-  boolean HostAdapterResetRequested:1;
+  boolean HostAdapterInitialized:1;
+  boolean HostAdapterExternalReset:1;
+  boolean HostAdapterInternalError:1;
   volatile boolean HostAdapterCommandCompleted:1;
   unsigned short HostAdapterScatterGatherLimit;
   unsigned short DriverScatterGatherLimit;
@@ -1305,7 +1411,6 @@
   unsigned short AllocatedCCBs;
   unsigned short DriverQueueDepth;
   unsigned short HostAdapterQueueDepth;
-  unsigned short TaggedQueueDepth;
   unsigned short UntaggedQueueDepth;
   unsigned short BusSettleTime;
   unsigned short SynchronousPermitted;
@@ -1315,26 +1420,24 @@
   unsigned short DisconnectPermitted;
   unsigned short TaggedQueuingPermitted;
   unsigned short ExternalHostAdapterResets;
-  BusLogic_LocalOptions_T LocalOptions;
+  unsigned short HostAdapterInternalErrors;
+  unsigned short TargetDeviceCount;
+  unsigned short MessageBufferLength;
   BusLogic_BusAddress_T BIOS_Address;
-  BusLogic_InstalledDevices_T InstalledDevices;
-  BusLogic_SynchronousValues_T SynchronousValues;
-  BusLogic_SynchronousPeriod_T SynchronousPeriod;
-  BusLogic_CommandLineEntry_T *CommandLineEntry;
-  FlashPoint_Info_T *FlashPointInfo;
+  BusLogic_DriverOptions_T *DriverOptions;
+  FlashPoint_Info_T FlashPointInfo;
   FlashPoint_CardHandle_T CardHandle;
   struct BusLogic_HostAdapter *Next;
-  char *MessageBuffer;
-  int MessageBufferLength;
+  struct BusLogic_HostAdapter *NextAll;
   BusLogic_CCB_T *All_CCBs;
   BusLogic_CCB_T *Free_CCBs;
   BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
   BusLogic_ErrorRecoveryStrategy_T
     ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
-  boolean TaggedQueuingSupported[BusLogic_MaxTargetDevices];
-  boolean TaggedQueuingActive[BusLogic_MaxTargetDevices];
-  boolean CommandSuccessfulFlag[BusLogic_MaxTargetDevices];
+  BusLogic_TargetFlags_T TargetFlags[BusLogic_MaxTargetDevices];
   unsigned char QueueDepth[BusLogic_MaxTargetDevices];
+  unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices];
+  unsigned char SynchronousOffset[BusLogic_MaxTargetDevices];
   unsigned char ActiveCommands[BusLogic_MaxTargetDevices];
   unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices];
   unsigned long LastSequencePoint[BusLogic_MaxTargetDevices];
@@ -1346,7 +1449,11 @@
   BusLogic_IncomingMailbox_T *FirstIncomingMailbox;
   BusLogic_IncomingMailbox_T *LastIncomingMailbox;
   BusLogic_IncomingMailbox_T *NextIncomingMailbox;
-  BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics;
+  BusLogic_TargetStatistics_T TargetStatistics[BusLogic_MaxTargetDevices];
+  unsigned char MailboxSpace[BusLogic_MaxMailboxes
+			     * (sizeof(BusLogic_OutgoingMailbox_T)
+				+ sizeof(BusLogic_IncomingMailbox_T))];
+  char MessageBuffer[BusLogic_MessageBufferSize];
 }
 BusLogic_HostAdapter_T;
 
@@ -1365,6 +1472,41 @@
 
 
 /*
+  Define a structure for the SCSI Inquiry command results.
+*/
+
+typedef struct SCSI_Inquiry
+{
+  unsigned char PeripheralDeviceType:5;			/* Byte 0 Bits 0-4 */
+  unsigned char PeripheralQualifier:3;			/* Byte 0 Bits 5-7 */
+  unsigned char DeviceTypeModifier:7;			/* Byte 1 Bits 0-6 */
+  boolean RMB:1;					/* Byte 1 Bit 7 */
+  unsigned char ANSI_ApprovedVersion:3;			/* Byte 2 Bits 0-2 */
+  unsigned char ECMA_Version:3;				/* Byte 2 Bits 3-5 */
+  unsigned char ISO_Version:2;				/* Byte 2 Bits 6-7 */
+  unsigned char ResponseDataFormat:4;			/* Byte 3 Bits 0-3 */
+  unsigned char :2;					/* Byte 3 Bits 4-5 */
+  boolean TrmIOP:1;					/* Byte 3 Bit 6 */
+  boolean AENC:1;					/* Byte 3 Bit 7 */
+  unsigned char AdditionalLength;			/* Byte 4 */
+  unsigned char :8;					/* Byte 5 */
+  unsigned char :8;					/* Byte 6 */
+  boolean SftRe:1;					/* Byte 7 Bit 0 */
+  boolean CmdQue:1;					/* Byte 7 Bit 1 */
+  boolean :1;						/* Byte 7 Bit 2 */
+  boolean Linked:1;					/* Byte 7 Bit 3 */
+  boolean Sync:1;					/* Byte 7 Bit 4 */
+  boolean WBus16:1;					/* Byte 7 Bit 5 */
+  boolean WBus32:1;					/* Byte 7 Bit 6 */
+  boolean RelAdr:1;					/* Byte 7 Bit 7 */
+  unsigned char VendorIdentification[8];		/* Bytes 8-15 */
+  unsigned char ProductIdentification[16];		/* Bytes 16-31 */
+  unsigned char ProductRevisionLevel[4];		/* Bytes 32-35 */
+}
+SCSI_Inquiry_T;
+
+
+/*
   BusLogic_AcquireHostAdapterLock acquires exclusive access to Host Adapter.
 */
 
@@ -1540,6 +1682,19 @@
 
 
 /*
+  Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and
+  32 Bit Kernel Virtual Addresses.  This avoids compilation warnings
+  on 64 Bit architectures.
+*/
+
+static inline
+BusLogic_BusAddress_T Virtual_to_32Bit_Virtual(void *VirtualAddress)
+{
+  return (BusLogic_BusAddress_T) (unsigned long) VirtualAddress;
+}
+
+
+/*
   BusLogic_IncrementErrorCounter increments Error Counter by 1, stopping at
   65535 rather than wrapping around to 0.
 */
@@ -1577,93 +1732,38 @@
 {
   int Index = 0;
   if (Amount < 8*1024)
-    if (Amount < 2*1024)
-      Index = (Amount < 1*1024 ? 0 : 1);
-    else Index = (Amount < 4*1024 ? 2 : 3);
+    {
+      if (Amount < 2*1024)
+	Index = (Amount < 1*1024 ? 0 : 1);
+      else Index = (Amount < 4*1024 ? 2 : 3);
+    }
   else if (Amount < 128*1024)
-    if (Amount < 32*1024)
-      Index = (Amount < 16*1024 ? 4 : 5);
-    else Index = (Amount < 64*1024 ? 6 : 7);
+    {
+      if (Amount < 32*1024)
+	Index = (Amount < 16*1024 ? 4 : 5);
+      else Index = (Amount < 64*1024 ? 6 : 7);
+    }
   else Index = (Amount < 256*1024 ? 8 : 9);
   CommandSizeBuckets[Index]++;
 }
 
 
 /*
-  If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT, and use the
-  ISA only probe function as the general one.
+  Define compatibility macros between Linux 2.0 and Linux 2.1.
 */
 
-#ifndef CONFIG_PCI
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
+#if LINUX_VERSION_CODE < 0x20100
 
-#define BusLogic_InitializeProbeInfoListISA BusLogic_InitializeProbeInfoList
+#define MODULE_PARM(Variable, Type)
 
 #endif
 
 
 /*
-  FlashPoint support is only available for the Intel x86 Architecture.
-*/
-
-#ifndef __i386__
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
-/*
-  Define macros for testing the Host Adapter Type.
-*/
-
-#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
-
-#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
-  (HostAdapter->HostAdapterType == BusLogic_MultiMaster)
-
-#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
-  (HostAdapter->HostAdapterType == BusLogic_FlashPoint)
-
-#else
-
-#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
-  (true)
-
-#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
-  (false)
-
-#endif
-
-
-/*
-  Define Driver Message Macros.
-*/
-
-#define BusLogic_Announce(Format, Arguments...) \
-  BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments)
-
-#define BusLogic_Info(Format, Arguments...) \
-  BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments)
-
-#define BusLogic_Notice(Format, Arguments...) \
-  BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments)
-
-#define BusLogic_Warning(Format, Arguments...) \
-  BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments)
-
-#define BusLogic_Error(Format, Arguments...) \
-  BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments)
-
-
-/*
   Define the version number of the FlashPoint Firmware (SCCB Manager).
 */
 
-#define FlashPoint_FirmwareVersion		"5.01"
+#define FlashPoint_FirmwareVersion		"5.02"
 
 
 /*
@@ -1671,35 +1771,22 @@
 */
 
 #define FlashPoint_NormalInterrupt		0x00
+#define FlashPoint_InternalError		0xFE
 #define FlashPoint_ExternalBusReset		0xFF
 
 
 /*
-  Define prototypes for the FlashPoint SCCB Manager Functions.
-*/
-
-extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *);
-extern FlashPoint_CardHandle_T
-       FlashPoint_HardResetHostAdapter(FlashPoint_Info_T *);
-extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
-extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
-extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
-extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T);
-extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T);
-
-
-/*
   Define prototypes for the forward referenced BusLogic Driver
   Internal Functions.
 */
 
-static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB);
+static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *);
 static void BusLogic_InterruptHandler(int, void *, Registers_T *);
 static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *,
-				     SCSI_Command_T *,
-				     unsigned int);
-static void BusLogic_Message(BusLogic_MessageLevel_T, char *Format,
+				     SCSI_Command_T *, unsigned int);
+static void BusLogic_Message(BusLogic_MessageLevel_T, char *,
 			     BusLogic_HostAdapter_T *, ...);
+static void BusLogic_ParseDriverOptions(char *);
 
 
 #endif /* BusLogic_DriverVersion */
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/FlashPoint.c linux/drivers/scsi/FlashPoint.c
--- v2.1.86/linux/drivers/scsi/FlashPoint.c	Mon Aug 11 00:10:00 1997
+++ linux/drivers/scsi/FlashPoint.c	Sat Jan 31 02:00:00 1998
@@ -19,40 +19,15 @@
 #include <linux/config.h>
 
 
-/*
-  If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT.
-*/
-
-#ifndef CONFIG_PCI
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
-/*
-  FlashPoint support is only available for the Intel x86 Architecture.
-*/
-
-#ifndef __i386__
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
 #ifndef CONFIG_SCSI_OMIT_FLASHPOINT
 
 
 #define UNIX
 #define FW_TYPE		_SCCB_MGR_
 #define MAX_CARDS	8
+#undef BUSTYPE_PCI
 
 
-#include <asm/io.h>
-
 #define OS_InPortByte(port)		inb(port)
 #define OS_InPortWord(port)		inw(port)
 #define OS_InPortLong(port)		inl(port)
@@ -68,7 +43,7 @@
 */
 
 #define SccbMgr_sense_adapter		FlashPoint_ProbeHostAdapter
-#define SccbMgr_config_adapter		FlashPoint_HardResetHostAdapter
+#define SccbMgr_config_adapter		FlashPoint_HardwareResetHostAdapter
 #define SccbMgr_unload_card		FlashPoint_ReleaseHostAdapter
 #define SccbMgr_start_sccb		FlashPoint_StartCCB
 #define SccbMgr_abort_sccb		FlashPoint_AbortCCB
@@ -169,6 +144,7 @@
 #define stwidn				FPT_stwidn
 #define sxfrp				FPT_sxfrp
 #define utilEERead			FPT_utilEERead
+#define utilEEReadOrg			FPT_utilEEReadOrg
 #define utilEESendCmdAddr		FPT_utilEESendCmdAddr
 #define utilEEWrite			FPT_utilEEWrite
 #define utilEEWriteOnOff		FPT_utilEEWriteOnOff
@@ -1317,9 +1293,9 @@
  *
  *   Description:  Register definitions for HARPOON ASIC.
  *
- *   $Date: 1997/01/31 02:14:28 $
+ *   $Date: 1997/07/09 21:44:36 $
  *
- *   $Revision: 1.6 $
+ *   $Revision: 1.9 $
  *
  *----------------------------------------------------------------------*/
 
@@ -2070,9 +2046,14 @@
 UCHAR RdStack(USHORT port, UCHAR index);
 void  WrStack(USHORT portBase, UCHAR index, UCHAR data);
 UCHAR ChkIfChipInitialized(USHORT ioPort);
+
+#if defined(V302)
 UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun);
+#endif
+
 void SendMsg(USHORT port, UCHAR message);
 void  queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code);
+UCHAR scsellDOS(USHORT p_port, UCHAR targ_id);
 #else
 UCHAR sfm(ULONG port, PSCCB pcurrSCCB);
 void  scsiStartAuto(ULONG port);
@@ -2090,7 +2071,11 @@
 UCHAR RdStack(ULONG port, UCHAR index);
 void  WrStack(ULONG portBase, UCHAR index, UCHAR data);
 UCHAR ChkIfChipInitialized(ULONG ioPort);
+
+#if defined(V302)
 UCHAR GetTarLun(ULONG port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tar, PUCHAR lun);
+#endif
+
 void SendMsg(ULONG port, UCHAR message);
 void  queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code);
 #endif
@@ -2130,6 +2115,7 @@
 void  utilEEWriteOnOff(USHORT p_port,UCHAR p_mode);
 void  utilEEWrite(USHORT p_port, USHORT ee_data, USHORT ee_addr);
 USHORT utilEERead(USHORT p_port, USHORT ee_addr);
+USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr);
 void  utilEESendCmdAddr(USHORT p_port, UCHAR ee_cmd, USHORT ee_addr);
 #else
 void  Wait1Second(ULONG p_port);
@@ -2137,6 +2123,7 @@
 void  utilEEWriteOnOff(ULONG p_port,UCHAR p_mode);
 void  utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr);
 USHORT utilEERead(ULONG p_port, USHORT ee_addr);
+USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr);
 void  utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr);
 #endif
 
@@ -2339,7 +2326,7 @@
 extern unsigned int SccbGlobalFlags;
 
 
-#ident "$Id: sccb.c 1.17 1997/02/11 21:06:41 mohan Exp $"
+#ident "$Id: sccb.c 1.18 1997/06/10 16:47:04 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -2353,9 +2340,9 @@
  *   Description:  Functions relating to handling of the SCCB interface
  *                 between the device driver and the HARPOON.
  *
- *   $Date: 1997/02/11 21:06:41 $
+ *   $Date: 1997/06/10 16:47:04 $
  *
- *   $Revision: 1.17 $
+ *   $Revision: 1.18 $
  *
  *----------------------------------------------------------------------*/
 
@@ -2477,6 +2464,7 @@
 		if(ChkIfChipInitialized(ioport) == FALSE)
 		{
 			pCurrNvRam = NULL;
+		   WR_HARPOON(ioport+hp_semaphore, 0x00);
 			XbowInit(ioport, 0);             /*Must Init the SCSI before attempting */
 			DiagEEPROM(ioport);
 		}
@@ -3036,6 +3024,7 @@
 		if(ChkIfChipInitialized(ioport) == FALSE)
 		{
 			pCurrNvRam = NULL;
+		   WR_HARPOON(ioport+hp_semaphore, 0x00);
 			XbowInit(ioport, 0);                /*Must Init the SCSI before attempting */
 			DiagEEPROM(ioport);
 		}
@@ -4802,7 +4791,23 @@
                may not show up if another device reselects us in 1.5us or
                less.  SRR Wednesday, 3/8/1995.
              */
-	   while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL))) ;
+	   while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)) &&
+		  !((RDW_HARPOON((ioport+hp_intstat)) & PHASE) &&
+		    RD_HARPOON((ioport+hp_scsisig)) ==
+		    (SCSI_BSY | SCSI_REQ | SCSI_CD | SCSI_MSG | SCSI_IOBIT))) ;
+
+	   /*
+	     The additional loop exit condition above detects a timing problem
+	     with the revision D/E harpoon chips.  The caller should reset the
+	     host adapter to recover when 0xFE is returned.
+	   */
+	   if (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)))
+	     {
+	       mOS_Lock((PSCCBcard)pCurrCard);
+	       MENABLE_INT(ioport);
+	       mOS_UnLock((PSCCBcard)pCurrCard);
+	       return 0xFE;
+	     }
 
          WRW_HARPOON((ioport+hp_intstat), (BUS_FREE | ITAR_DISC));
 
@@ -5347,7 +5352,7 @@
 }
 
 #endif
-#ident "$Id: sccb_dat.c 1.9 1997/01/31 02:12:58 mohan Exp $"
+#ident "$Id: sccb_dat.c 1.10 1997/02/22 03:16:02 awin Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -5361,9 +5366,9 @@
  *   Description:  Functions relating to handling of the SCCB interface 
  *                 between the device driver and the HARPOON.
  *
- *   $Date: 1997/01/31 02:12:58 $
+ *   $Date: 1997/02/22 03:16:02 $
  *
- *   $Revision: 1.9 $
+ *   $Revision: 1.10 $
  *
  *----------------------------------------------------------------------*/
 
@@ -5378,18 +5383,19 @@
 /*#include <target.h>*/
 /*#include <harpoon.h>*/
 
+/*
+**  IMPORTANT NOTE!!!
+**
+**  You MUST preassign all data to a valid value or zero.  This is
+**  required due to the MS compiler bug under OS/2 and Solaris Real-Mode
+**  driver environment.
+*/
+
 
-#if defined(OS2) || defined (SOLARIS_REAL_MODE)
-SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { 0 };
-SCCBCARD BL_Card[MAX_CARDS] = { 0 };
-SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { 0 };
-NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { 0 };
-#else
-SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
-SCCBCARD BL_Card[MAX_CARDS];
-SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR];
-NVRAMINFO nvRamInfo[MAX_MB_CARDS];
-#endif
+SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { { { 0 } } };
+SCCBCARD BL_Card[MAX_CARDS] = { { 0 } };
+SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { { { 0 } } };
+NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { { 0 } };
 
 
 #if defined(OS2)
@@ -5402,23 +5408,23 @@
 #endif
 
 #if defined(DOS)
-UCHAR first_time;
+UCHAR first_time = 0;
 #endif
 
-UCHAR mbCards;
+UCHAR mbCards = 0;
 UCHAR scamHAString[] = {0x63, 0x07, 'B', 'U', 'S', 'L', 'O', 'G', 'I', 'C', \
 								' ', 'B', 'T', '-', '9', '3', '0', \
 								0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, \
 								0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
 
-USHORT default_intena;
+USHORT default_intena = 0;
 
 #if defined(BUGBUG)
-UCHAR    debug_int[MAX_CARDS][debug_size];
-UCHAR    debug_index[MAX_CARDS];
-UCHAR    reserved_1[3];
+UCHAR    debug_int[MAX_CARDS][debug_size] = { 0 };
+UCHAR    debug_index[MAX_CARDS] = { 0 };
+UCHAR    reserved_1[3] = { 0 };
 #endif
-#ident "$Id: scsi.c 1.19 1997/01/31 02:08:14 mohan Exp $"
+#ident "$Id: scsi.c 1.23 1997/07/09 21:42:54 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -5433,9 +5439,9 @@
  *                 selection/reselection, sync negotiation, message-in
  *                 decoding.
  *
- *   $Date: 1997/01/31 02:08:14 $
+ *   $Date: 1997/07/09 21:42:54 $
  *
- *   $Revision: 1.19 $
+ *   $Revision: 1.23 $
  *
  *----------------------------------------------------------------------*/
 
@@ -5483,11 +5489,13 @@
 	while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
 			(TimeOutLoop++ < 20000) ){}
 
+
 	WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
 
 	message = RD_HARPOON(port+hp_scsidata_0);
 
-	WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+	WR_HARPOON(port+hp_scsisig, SCSI_ACK + S_MSGI_PH);
+
 
 	if (TimeOutLoop > 20000)
 		message = 0x00;   /* force message byte = 0 if Time Out on Req */
@@ -5495,6 +5503,10 @@
 	if ((RDW_HARPOON((port+hp_intstat)) & PARITY) &&
 		(RD_HARPOON(port+hp_addstat) & SCSI_PAR_ERR))
 	{
+		WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+		WR_HARPOON(port+hp_xferstat, 0);
+		WR_HARPOON(port+hp_fiforead, 0);
+		WR_HARPOON(port+hp_fifowrite, 0);
 		if (pCurrSCCB != NULL)
 		{
 			pCurrSCCB->Sccb_scsimsg = SMPARITY;
@@ -5503,6 +5515,7 @@
 		do
 		{
 			ACCEPT_MSG_ATN(port);
+			TimeOutLoop = 0;
 			while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
 				(TimeOutLoop++ < 20000) ){}
 			if (TimeOutLoop > 20000)
@@ -5524,6 +5537,10 @@
 		}while(1);
 
 	}
+	WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+	WR_HARPOON(port+hp_xferstat, 0);
+	WR_HARPOON(port+hp_fiforead, 0);
+	WR_HARPOON(port+hp_fifowrite, 0);
 	return(message);
 }
 
@@ -5894,12 +5911,20 @@
 void sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard)
 #endif
 {
+
+#if defined(V302)
 #ifdef DOS
    UCHAR our_target,message, msgRetryCount;
    extern UCHAR lun, tag;
 #else
    UCHAR our_target,message,lun,tag, msgRetryCount;
 #endif
+
+#else  /* V302 */
+   UCHAR our_target, message, lun = 0, tag, msgRetryCount;
+#endif /* V302 */
+
+
    PSCCBMgr_tar_info currTar_Info;
 	PSCCB currSCCB;
 
@@ -5972,7 +5997,103 @@
 	msgRetryCount = 0;
 	do
 	{
+
+#if defined(V302)
+
 		message = GetTarLun(port, p_card, our_target, pCurrCard, &tag, &lun);
+
+#else /* V302 */
+
+		currTar_Info = &sccbMgrTbl[p_card][our_target];
+		tag = 0;
+
+
+		while(!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ))
+		{
+			if (! (RD_HARPOON(port+hp_scsisig) & SCSI_BSY))
+			{
+
+				WRW_HARPOON((port+hp_intstat), PHASE);
+				return;
+			}
+		}
+
+		WRW_HARPOON((port+hp_intstat), PHASE);
+		if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) == S_MSGI_PH)
+		{
+
+			message = sfm(port,pCurrCard->currentSCCB);
+			if (message)
+			{
+
+				if (message <= (0x80 | LUN_MASK))
+				{
+					lun = message & (UCHAR)LUN_MASK;
+
+#if !defined(DOS)
+					if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING)
+					{
+						if (currTar_Info->TarTagQ_Cnt != 0)
+						{
+
+							if (!(currTar_Info->TarLUN_CA))
+							{
+								ACCEPT_MSG(port);    /*Release the ACK for ID msg. */
+
+
+								message = sfm(port,pCurrCard->currentSCCB);
+								if (message)
+								{
+									ACCEPT_MSG(port);
+								}
+
+								else
+   								message = FALSE;
+
+								if(message != FALSE)
+								{
+									tag = sfm(port,pCurrCard->currentSCCB);
+
+									if (!(tag)) 
+										message = FALSE;
+								}
+
+							} /*C.A. exists! */
+
+						} /*End Q cnt != 0 */
+
+					} /*End Tag cmds supported! */
+#endif /* !DOS */
+
+				} /*End valid ID message.  */
+
+				else
+				{
+
+					ACCEPT_MSG_ATN(port);
+				}
+
+			} /* End good id message. */
+
+			else
+			{
+
+				message = FALSE;
+			}
+		}
+		else
+		{
+			ACCEPT_MSG_ATN(port);
+
+		   while (!(RDW_HARPOON((port+hp_intstat)) & (PHASE | RESET)) &&
+			  !(RD_HARPOON(port+hp_scsisig) & SCSI_REQ) &&
+			  (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ;
+
+			return;
+		}
+	
+#endif /* V302 */
+
 		if(message == FALSE)
 		{
 			msgRetryCount++;
@@ -6071,6 +6192,8 @@
 	  (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ;
 }
 
+#if defined(V302)
+
 #if defined(DOS)
 UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun)
 #else
@@ -6162,6 +6285,7 @@
 	return(TRUE);
 }
 
+#endif /* V302 */
 
 #if defined(DOS)
 void SendMsg(USHORT port, UCHAR message)
@@ -6469,6 +6593,10 @@
 				ACCEPT_MSG(port);
 			WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
 		}
+	}else
+	{
+			if(pCurrSCCB->Sccb_scsimsg == SMPARITY)
+				WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
 	}
 }
 
@@ -7386,6 +7514,7 @@
    p_sccb->Sccb_scsistat      = BUS_FREE_ST;
    p_sccb->SccbStatus         = SCCB_IN_PROCESS;
    p_sccb->Sccb_scsimsg       = SMNO_OP;
+
 }
 
 
@@ -9222,7 +9351,7 @@
       currSCCB->Sccb_XferCnt = currSCCB->DataLength - currSCCB->Sccb_ATC;
       }
 }
-#ident "$Id: scam.c 1.16 1997/01/31 02:11:12 mohan Exp $"
+#ident "$Id: scam.c 1.17 1997/03/20 23:49:37 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -9237,9 +9366,9 @@
  *                 and the determination of the SCSI IDs to be assigned
  *                 to all perspective SCSI targets.
  *
- *   $Date: 1997/01/31 02:11:12 $
+ *   $Date: 1997/03/20 23:49:37 $
  *
- *   $Revision: 1.16 $
+ *   $Revision: 1.17 $
  *
  *----------------------------------------------------------------------*/
 
@@ -9468,7 +9597,7 @@
      	if (((ScamFlg & SCAM_ENABLED) && (scamInfo[i].state == LEGACY))
 			|| (i != p_our_id))
         	{
-         scsell(p_port,i);
+         scsellDOS(p_port,i);
   	      }
   	}
 #endif
@@ -9885,6 +10014,7 @@
             }
 
          if ((ret_data & 0x1F) == 0)
+	   {
 /*
 				if(bit_cnt != 0 || bit_cnt != 8)
 				{
@@ -9899,6 +10029,7 @@
                return(0x00);
             else
                return(0xFF);
+	   }
 
          } /*bit loop */
 
@@ -10090,6 +10221,90 @@
       }
 }
 
+#if defined(DOS)
+/*---------------------------------------------------------------------
+ *
+ * Function: scsell for DOS
+ *
+ * Description: Select the specified device ID using a selection timeout
+ *              less than 2ms.  This was specially required to solve
+ *              the problem with Plextor 12X CD-ROM drive. This drive
+ *					 was responding the Selection at the end of 4ms and 
+ *					 hanging the system.
+ *
+ *---------------------------------------------------------------------*/
+
+UCHAR scsellDOS(USHORT p_port, UCHAR targ_id)
+{
+   USHORT i;
+
+   WR_HARPOON(p_port+hp_page_ctrl,
+      (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE));
+
+   ARAM_ACCESS(p_port);
+
+   WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) | SCAM_TIMER));
+   WR_HARPOON(p_port+hp_seltimeout,TO_2ms);
+
+
+   for (i = p_port+CMD_STRT; i < p_port+CMD_STRT+12; i+=2) {
+      WRW_HARPOON(i, (MPM_OP+ACOMMAND));
+      }
+   WRW_HARPOON(i, (BRH_OP+ALWAYS+    NP));
+
+   WRW_HARPOON((p_port+hp_intstat),
+	       (RESET | TIMEOUT | SEL | BUS_FREE | AUTO_INT));
+
+   WR_HARPOON(p_port+hp_select_id, targ_id);
+
+   WR_HARPOON(p_port+hp_portctrl_0, SCSI_PORT);
+   WR_HARPOON(p_port+hp_autostart_3, (SELECT | CMD_ONLY_STRT));
+   WR_HARPOON(p_port+hp_scsictrl_0, (SEL_TAR | ENA_RESEL));
+
+
+   while (!(RDW_HARPOON((p_port+hp_intstat)) &
+	    (RESET | PROG_HLT | TIMEOUT | AUTO_INT))) {}
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & RESET)
+         Wait(p_port, TO_250ms);
+
+   DISABLE_AUTO(p_port);
+
+   WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) & ~SCAM_TIMER));
+   WR_HARPOON(p_port+hp_seltimeout,TO_290ms);
+
+   SGRAM_ACCESS(p_port);
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & (RESET | TIMEOUT) ) {
+
+      WRW_HARPOON((p_port+hp_intstat),
+		  (RESET | TIMEOUT | SEL | BUS_FREE | PHASE));
+
+      WR_HARPOON(p_port+hp_page_ctrl,
+         (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+      return(FALSE);  /*No legacy device */
+      }
+
+   else {
+
+      while(!(RDW_HARPOON((p_port+hp_intstat)) & BUS_FREE)) {
+				if (RD_HARPOON(p_port+hp_scsisig) & SCSI_REQ)
+					{
+					WR_HARPOON(p_port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+      			ACCEPT_MSG(p_port);
+					}
+		}
+
+      WRW_HARPOON((p_port+hp_intstat), CLR_ALL_INT_1);
+
+      WR_HARPOON(p_port+hp_page_ctrl,
+         (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+      return(TRUE);  /*Found one of them oldies! */
+      }
+}
+#endif  /* DOS */
 
 /*---------------------------------------------------------------------
  *
@@ -10252,10 +10467,12 @@
       match--;
 
       if (match == 0xFF)
+	{
          if (p_id_string[0] & BIT(5))
             match = 7;
          else
             match = MAX_SCSI_TAR-1;
+	}
       }
 
 
@@ -10300,10 +10517,12 @@
       match--;
 
       if (match == 0xFF)
+	{
          if (p_id_string[0] & BIT(5))
             match = 7;
          else
             match = MAX_SCSI_TAR-1;
+	}
       }
 
    return(NO_ID_AVAIL);
@@ -10362,7 +10581,7 @@
    utilEEWrite(p_port, sum_data, EEPROM_CHECK_SUM/2);
    utilEEWriteOnOff(p_port,0);   /* Turn off write access */
 }
-#ident "$Id: diagnose.c 1.9 1997/01/31 02:09:48 mohan Exp $"
+#ident "$Id: diagnose.c 1.10 1997/06/10 16:51:47 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -10376,9 +10595,9 @@
  *   Description:  Diagnostic funtions for testing the integrity of
  *                 the HARPOON.
  *
- *   $Date: 1997/01/31 02:09:48 $
+ *   $Date: 1997/06/10 16:51:47 $
  *
- *   $Revision: 1.9 $
+ *   $Revision: 1.10 $
  *
  *----------------------------------------------------------------------*/
 
@@ -10419,7 +10638,7 @@
    WR_HARPOON(port+hp_scsireset,(DMA_RESET | HPSCSI_RESET | PROG_RESET | \
 				 FIFO_CLR));
 
-   WR_HARPOON(port+hp_scsireset,0x00);
+   WR_HARPOON(port+hp_scsireset,SCSI_INI);
 
    WR_HARPOON(port+hp_clkctrl_0,CLKCTRL_DEFAULT);
 
@@ -10703,8 +10922,8 @@
    temp += 0x70D3;
    utilEEWrite(p_port, 0x0010, BIOS_CONFIG/2);
    temp += 0x0010;
-   utilEEWrite(p_port, 0x0007, SCAM_CONFIG/2);
-   temp += 0x0007;
+   utilEEWrite(p_port, 0x0003, SCAM_CONFIG/2);
+   temp += 0x0003;
    utilEEWrite(p_port, 0x0007, ADAPTER_SCSI_ID/2);
    temp += 0x0007;
 
@@ -10807,7 +11026,7 @@
 
 }
 
-#ident "$Id: utility.c 1.22 1997/01/31 02:12:23 mohan Exp $"
+#ident "$Id: utility.c 1.23 1997/06/10 16:55:06 mohan Exp $"
 /*----------------------------------------------------------------------
  *
  *
@@ -10821,9 +11040,9 @@
  *   Description:  Utility functions relating to queueing and EEPROM
  *                 manipulation and any other garbage functions.
  *
- *   $Date: 1997/01/31 02:12:23 $
+ *   $Date: 1997/06/10 16:55:06 $
  *
- *   $Revision: 1.22 $
+ *   $Revision: 1.23 $
  *
  *----------------------------------------------------------------------*/
 /*#include <globals.h>*/
@@ -11617,10 +11836,13 @@
 	 ee_value &= ~SEE_DO;
 
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value |= SEE_CLK;          /* Clock  data! */
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value &= ~SEE_CLK;
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  }
    ee_value &= (EXT_ARB_ACK | SCSI_TERM_ENA_H);
    WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS));
@@ -11632,7 +11854,6 @@
    WR_HARPOON(p_port+hp_ee_ctrl, ee_value);       /* Turn off Master Select */
 }
 
-
 /*---------------------------------------------------------------------
  *
  * Function: Read EEPROM
@@ -11648,6 +11869,40 @@
 USHORT utilEERead(ULONG p_port, USHORT ee_addr)
 #endif
 {
+   USHORT i, ee_data1, ee_data2;
+
+	i = 0;
+	ee_data1 = utilEEReadOrg(p_port, ee_addr);
+	do
+	{
+		ee_data2 = utilEEReadOrg(p_port, ee_addr);
+
+		if(ee_data1 == ee_data2)
+			return(ee_data1);
+
+		ee_data1 = ee_data2;
+		i++;
+
+	}while(i < 4);
+
+	return(ee_data1);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Read EEPROM Original 
+ *
+ * Description: Read a word from the EEPROM at the desired
+ *              address.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr)
+#else
+USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr)
+#endif
+{
 
    UCHAR ee_value;
    USHORT i, ee_data;
@@ -11666,8 +11921,10 @@
 
 	  ee_value |= SEE_CLK;          /* Clock  data! */
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value &= ~SEE_CLK;
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 
 	  ee_data <<= 1;
 
@@ -11722,10 +11979,13 @@
 		 ee_value &= ~SEE_DO;
 
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value |= SEE_CLK;                         /* Clock  data! */
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value &= ~SEE_CLK;
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  }
 
 
@@ -11744,10 +12004,13 @@
 		 ee_value &= ~SEE_DO;
 
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value |= SEE_CLK;                         /* Clock  data! */
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 	  ee_value &= ~SEE_CLK;
 	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
 
 	  i >>= 1;
 	  }
@@ -11783,6 +12046,114 @@
 	return(lrc);
 }
 
+
+
+/*
+  The following inline definitions avoid type conflicts.
+*/
+
+static inline unsigned char
+FlashPoint__ProbeHostAdapter(FlashPoint_Info_T *FlashPointInfo)
+{
+  return FlashPoint_ProbeHostAdapter((PSCCBMGR_INFO) FlashPointInfo);
+}
+
+
+static inline FlashPoint_CardHandle_T
+FlashPoint__HardwareResetHostAdapter(FlashPoint_Info_T *FlashPointInfo)
+{
+  return FlashPoint_HardwareResetHostAdapter((PSCCBMGR_INFO) FlashPointInfo);
+}
+
+static inline void
+FlashPoint__ReleaseHostAdapter(FlashPoint_CardHandle_T CardHandle)
+{
+  FlashPoint_ReleaseHostAdapter(CardHandle);
+}
+
+
+static inline void
+FlashPoint__StartCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB)
+{
+  FlashPoint_StartCCB(CardHandle, (PSCCB) CCB);
+}
+
+
+static inline void
+FlashPoint__AbortCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB)
+{
+  FlashPoint_AbortCCB(CardHandle, (PSCCB) CCB);
+}
+
+
+static inline boolean
+FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle)
+{
+  return FlashPoint_InterruptPending(CardHandle);
+}
+
+
+static inline int
+FlashPoint__HandleInterrupt(FlashPoint_CardHandle_T CardHandle)
+{
+  return FlashPoint_HandleInterrupt(CardHandle);
+}
+
+
+#define FlashPoint_ProbeHostAdapter	    FlashPoint__ProbeHostAdapter
+#define FlashPoint_HardwareResetHostAdapter FlashPoint__HardwareResetHostAdapter
+#define FlashPoint_ReleaseHostAdapter	    FlashPoint__ReleaseHostAdapter
+#define FlashPoint_StartCCB		    FlashPoint__StartCCB
+#define FlashPoint_AbortCCB		    FlashPoint__AbortCCB
+#define FlashPoint_InterruptPending	    FlashPoint__InterruptPending
+#define FlashPoint_HandleInterrupt	    FlashPoint__HandleInterrupt
+
+
+/*
+  FlashPoint_InquireTargetInfo returns the Synchronous Period, Synchronous
+  Offset, and Wide Transfers Active information for TargetID on CardHandle.
+*/
+
+void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T CardHandle,
+				  int TargetID,
+				  unsigned char *SynchronousPeriod,
+				  unsigned char *SynchronousOffset,
+				  unsigned char *WideTransfersActive)
+{
+  SCCBMGR_TAR_INFO *TargetInfo =
+    &sccbMgrTbl[((SCCBCARD *)CardHandle)->cardIndex][TargetID];
+  if ((TargetInfo->TarSyncCtrl & SYNC_OFFSET) > 0)
+    {
+      *SynchronousPeriod = 5 * ((TargetInfo->TarSyncCtrl >> 5) + 1);
+      *SynchronousOffset = TargetInfo->TarSyncCtrl & SYNC_OFFSET;
+    }
+  else
+    {
+      *SynchronousPeriod = 0;
+      *SynchronousOffset = 0;
+    }
+  *WideTransfersActive = (TargetInfo->TarSyncCtrl & NARROW_SCSI ? 0 : 1);
+}
+
+
+#else  /* CONFIG_SCSI_OMIT_FLASHPOINT */
+
+
+/*
+  Define prototypes for the FlashPoint SCCB Manager Functions.
+*/
+
+extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *);
+extern FlashPoint_CardHandle_T
+       FlashPoint_HardwareResetHostAdapter(FlashPoint_Info_T *);
+extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
+extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
+extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
+extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T);
+extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T);
+extern void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T,
+					 int, unsigned char *,
+					 unsigned char *, unsigned char *);
 
 
 #endif /* CONFIG_SCSI_OMIT_FLASHPOINT */
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.86/linux/drivers/scsi/Makefile	Fri Jan 23 18:10:32 1998
+++ linux/drivers/scsi/Makefile	Thu Feb 12 15:48:43 1998
@@ -464,14 +464,6 @@
 
 include $(TOPDIR)/Rules.make
 
-# This gives correct output but uses old-style "excessive compilation".
-# This will be fixed soon (about December 1997 or January 1998).
-BusLogic.o: BusLogic.c FlashPoint.c ../../include/linux/autoconf.h
-	$(CC) $(CFLAGS) -c BusLogic.c -o BusLogic.O
-	$(CC) $(CFLAGS) -c FlashPoint.c -o FlashPoint.O
-	$(LD) -r -o BusLogic.o BusLogic.O FlashPoint.O
-	rm -f BusLogic.O FlashPoint.O
-
 53c8xx_d.h 53c8xx_u.h : 53c7,8xx.scr script_asm.pl
 	ln -sf 53c7,8xx.scr fake.c
 	$(CPP) -traditional -DCHIP=810 fake.c | grep -v '^#' | perl script_asm.pl 
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/README.BusLogic linux/drivers/scsi/README.BusLogic
--- v2.1.86/linux/drivers/scsi/README.BusLogic	Mon Aug 11 00:10:00 1997
+++ linux/drivers/scsi/README.BusLogic	Sat Jan 31 02:00:00 1998
@@ -1,10 +1,10 @@
 	   BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
 
-			 Version 2.0.10 for Linux 2.0
+			 Version 2.0.11 for Linux 2.0
 
 			      PRODUCTION RELEASE
 
-				11 August 1997
+				31 January 1998
 
 			       Leonard N. Zubkoff
 			       Dandelion Digital
@@ -15,27 +15,34 @@
 
 				 INTRODUCTION
 
-BusLogic, Inc. designs and manufactures a variety of high performance SCSI host
-adapters which share a common programming interface across a diverse collection
-of bus architectures by virtue of their MultiMaster ASIC technology.  This
-driver supports all present BusLogic MultiMaster Host Adapters, and should
+BusLogic, Inc. designed and manufactured a variety of high performance SCSI
+host adapters which share a common programming interface across a diverse
+collection of bus architectures by virtue of their MultiMaster ASIC technology.
+BusLogic was acquired by Mylex Corporation in February 1996, but the products
+supported by this driver originated under the BusLogic name and so that name is
+retained in the source code and documentation.
+
+This driver supports all present BusLogic MultiMaster Host Adapters, and should
 support any future MultiMaster designs with little or no modification.  More
-recently, BusLogic has introduced the FlashPoint Host Adapters, which are less
+recently, BusLogic introduced the FlashPoint Host Adapters, which are less
 costly and rely on the host CPU, rather than including an onboard processor.
-Mylex/BusLogic has recently provided me with the FlashPoint Driver Developer's
-Kit, which comprises documentation and freely redistributable source code for
-the FlashPoint SCCB Manager.  The SCCB Manager is the library of code that runs
-on the host CPU and performs functions analogous to the firmware on the
-MultiMaster Host Adapters.  Thanks to their having provided the SCCB Manager,
-this driver now supports the FlashPoint Host Adapters as well.
+Despite not having an onboard CPU, the FlashPoint Host Adapters perform very
+well and have very low command latency.  BusLogic has recently provided me with
+the FlashPoint Driver Developer's Kit, which comprises documentation and freely
+redistributable source code for the FlashPoint SCCB Manager.  The SCCB Manager
+is the library of code that runs on the host CPU and performs functions
+analogous to the firmware on the MultiMaster Host Adapters.  Thanks to their
+having provided the SCCB Manager, this driver now supports the FlashPoint Host
+Adapters as well.
 
 My primary goals in writing this completely new BusLogic driver for Linux are
 to achieve the full performance that BusLogic SCSI Host Adapters and modern
 SCSI peripherals are capable of, and to provide a highly robust driver that can
 be depended upon for high performance mission critical applications.  All of
 the major performance and error recovery features can be configured from the
-Linux kernel command line, allowing individual installations to tune driver
-performance and error recovery to their particular needs.
+Linux kernel command line or at module initialization time, allowing individual
+installations to tune driver performance and error recovery to their particular
+needs.
 
 The latest information on Linux support for BusLogic SCSI Host Adapters, as
 well as the most recent release of this driver and the latest firmware for the
@@ -48,33 +55,35 @@
 relevant to SCSI operations, and a detailed description of your system's
 hardware configuration.
 
-BusLogic has been an excellent company to work with and I highly recommend
-their products to the Linux community.  In November 1995, I was offered the
+Mylex has been an excellent company to work with and I highly recommend their
+products to the Linux community.  In November 1995, I was offered the
 opportunity to become a beta test site for their latest MultiMaster product,
 the BT-948 PCI Ultra SCSI Host Adapter, and then again for the BT-958 PCI Wide
 Ultra SCSI Host Adapter in January 1996.  This was mutually beneficial since
-BusLogic received a degree and kind of testing that their own testing group
-cannot readily achieve, and the Linux community has available high performance
-host adapters that have been well tested with Linux even before being brought
-to market.  This relationship has also given me the opportunity to interact
+Mylex received a degree and kind of testing that their own testing group cannot
+readily achieve, and the Linux community has available high performance host
+adapters that have been well tested with Linux even before being brought to
+market.  This relationship has also given me the opportunity to interact
 directly with their technical staff, to understand more about the internal
 workings of their products, and in turn to educate them about the needs and
-potential of the Linux community.  Their interest and support is greatly
-appreciated.
+potential of the Linux community.
+
+More recently, Mylex has reaffirmed the company's interest in supporting the
+Linux community, and I am now working on a Linux driver for the DAC960 PCI RAID
+Controllers.  Mylex's interest and support is greatly appreciated.
 
-Unlike some other vendors, if you contact BusLogic Technical Support with a
+Unlike some other vendors, if you contact Mylex Technical Support with a
 problem and are running Linux, they will not tell you that your use of their
 products is unsupported.  Their latest product marketing literature even states
-"BusLogic SCSI host adapters are compatible with all major operating systems
+"Mylex SCSI host adapters are compatible with all major operating systems
 including: ... Linux ...".
 
-BusLogic, Inc. is located at 4151 Burton Drive, Santa Clara, California, 95054,
-USA and can be reached by Voice at 408/492-9090 or by FAX at 408/492-1542.
-BusLogic maintains a World Wide Web site at http://www.buslogic.com, an
-anonymous FTP site at ftp.buslogic.com, and a BBS at 408/492-1984.  BusLogic
-Technical Support can be reached by electronic mail at techsup@buslogic.com, by
-Voice at 408/654-0760, or by FAX at 408/492-1542.  Contact information for
-offices in Europe and Japan is available on the Web site.
+Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont, California
+94555, USA and can be reached at 510/796-6100 or on the World Wide Web at
+http://www.mylex.com.  Mylex Technical Support can be reached by electronic
+mail at techsup@mylex.com, by Voice at 510/608-2400, or by FAX at 510/745-7715.
+Contact information for offices in Europe and Japan is available on the Web
+site.
 
 
 				DRIVER FEATURES
@@ -83,15 +92,46 @@
 
   During system initialization, the driver reports extensively on the host
   adapter hardware configuration, including the synchronous transfer parameters
-  negotiated with each target device.  In addition, the driver tests the
-  hardware interrupt configuration to verify that interrupts are actually
-  delivered correctly to the interrupt handler.  This should catch a high
-  percentage of PCI motherboard configuration errors early, because when the
-  host adapter is probed successfully, most of the remaining problems appear to
-  be related to interrupts.  Most often, any remaining hardware problems are
-  related to the specific configuration of devices on the SCSI bus, and the
-  quality of cabling and termination used.  Finally, this BusLogic driver
-  should never incorrectly attempt to support an Adaptec 154x Host Adapter.
+  requested and negotiated with each target device.  AutoSCSI settings for
+  Synchronous Negotiation, Wide Negotiation, and Disconnect/Reconnect are
+  reported for each target device, as well as the status of Tagged Queuing and
+  Error Recovery.  If the same setting is in effect for all target devices,
+  then a single word or phrase is used; otherwise, a letter is provided for
+  each target device to indicate the individual status.  The following examples
+  should clarify this reporting format:
+
+    Synchronous Negotiation: Ultra
+
+      Synchronous negotiation is enabled for all target devices and the host
+      adapter will attempt to negotiate for 20.0 mega-transfers/second.
+
+    Synchronous Negotiation: Fast
+
+      Synchronous negotiation is enabled for all target devices and the host
+      adapter will attempt to negotiate for 10.0 mega-transfers/second.
+
+    Synchronous Negotiation: Slow
+
+      Synchronous negotiation is enabled for all target devices and the host
+      adapter will attempt to negotiate for 5.0 mega-transfers/second.
+
+    Synchronous Negotiation: Disabled
+
+      Synchronous negotiation is disabled and all target devices are limited to
+      asynchronous operation.
+
+    Synchronous Negotiation: UFSNUUU#UUUUUUUU
+
+      Synchronous negotiation to Ultra speed is enabled for target devices 0
+      and 4 through 15, to Fast speed for target device 1, to Slow speed for
+      target device 2, and is not permitted to target device 3.  The host
+      adapter's SCSI ID is represented by the "#".
+
+    The status of Wide Negotiation, Disconnect/Reconnect, and Tagged Queuing
+    are reported as "Enabled", Disabled", or a sequence of "Y" and "N" letters.
+
+    The Error Recovery option is reported as "Default", "Hard Reset",
+    "Bus Device Reset", "None" or a sequence of "D", "H", "B", and "N" letters.
 
 o Performance Features
 
@@ -103,16 +143,15 @@
   addition, BusLogic's Strict Round Robin Mode is used to optimize host adapter
   performance, and scatter/gather I/O can support as many segments as can be
   effectively utilized by the Linux I/O subsystem.  Control over the use of
-  tagged queuing for each target device as well as selection of the tagged
-  queue depth is available from the kernel command line.  By default, the queue
-  depth is automatically determined based on the number, type, speed, and
-  capabilities of the target devices found.  In addition, tagged queuing is
-  automatically disabled whenever the host adapter firmware version is known
-  not to implement it correctly, or whenever a tagged queue depth of 1 is
-  selected.  Tagged queuing is also disabled for individual target devices if
-  disconnect/reconnect is disabled for that device.  In performance testing,
-  sustained disk writes of 7.3MB per second have been observed to a /dev/sd
-  device.
+  tagged queuing for each target device as well as individual selection of the
+  tagged queue depth is available through driver options provided on the kernel
+  command line or at module initialization time.  By default, the queue depth
+  is determined automatically based on the host adapter's total queue depth and
+  the number, type, speed, and capabilities of the target devices found.  In
+  addition, tagged queuing is automatically disabled whenever the host adapter
+  firmware version is known not to implement it correctly, or whenever a tagged
+  queue depth of 1 is selected.  Tagged queuing is also disabled for individual
+  target devices if disconnect/reconnect is disabled for that device.
 
 o Robustness Features
 
@@ -121,15 +160,15 @@
   a selection is made between a full host adapter hard reset and SCSI bus reset
   versus sending a bus device reset message to the individual target device
   based on the recommendation of the SCSI subsystem.  Error recovery strategies
-  are selectable from the kernel command line individually for each target
-  device, and also include sending a bus device reset to the specific target
-  device associated with the command being reset, as well as suppressing error
+  are selectable through driver options individually for each target device,
+  and also include sending a bus device reset to the specific target device
+  associated with the command being reset, as well as suppressing error
   recovery entirely to avoid perturbing an improperly functioning device.  If
   the bus device reset error recovery strategy is selected and sending a bus
   device reset does not restore correct operation, the next command that is
   reset will force a full host adapter hard reset and SCSI bus reset.  SCSI bus
   resets caused by other devices and detected by the host adapter are also
-  handled by issuing a hard reset to the host adapter and re-initialization.
+  handled by issuing a soft reset to the host adapter and re-initialization.
   Finally, if tagged queuing is active and more than one command reset occurs
   in a 10 minute interval, or if a command reset occurs within the first 10
   minutes of operation, then tagged queuing will be disabled for that target
@@ -138,15 +177,6 @@
   lock up or crash, and thereby allowing a clean shutdown and restart after the
   offending component is removed.
 
-o Extensive Testing
-
-  This driver has undergone extensive testing and improvement over a period of
-  several months, and is routinely being used on heavily loaded systems.  Over
-  300 people retrieved the driver during the beta test period.  In addition to
-  testing in normal system operation, error recovery tests have been performed
-  to verify proper system recovery in the case of simulated dropped interrupts,
-  external SCSI bus resets, and SCSI command errors due to bad CD-ROM media.
-
 o PCI Configuration Support
 
   On PCI systems running kernels compiled with PCI BIOS support enabled, this
@@ -159,8 +189,8 @@
 
 o /proc File System Support
 
-  Copies of the host adapter configuration information together with data
-  transfer and error recovery statistics are now available through the
+  Copies of the host adapter configuration information together with updated
+  data transfer and error recovery statistics are available through the
   /proc/scsi/BusLogic/<N> interface.
 
 o Shared Interrupts Support
@@ -168,16 +198,6 @@
   On systems that support shared interrupts, any number of BusLogic Host
   Adapters may share the same interrupt request channel.
 
-o Wide SCSI Support
-
-  All BusLogic MultiMaster SCSI Host Adapters share a common programming
-  interface, except for the inevitable improvements and extensions as new
-  models are released, so support for Wide SCSI data transfer has automatically
-  been available without explicit driver support.  When used with Linux 2.0.x,
-  this driver adds explicit support for up to 15 target devices and 64 logical
-  units per target device, to fully exploit the capabilities of the newest
-  BusLogic Wide SCSI Host Adapters.
-
 
 			    SUPPORTED HOST ADAPTERS
 
@@ -188,16 +208,21 @@
 
 FlashPoint Series PCI Host Adapters:
 
-FlashPoint LT (BT-930)	Ultra SCSI-2
-FlashPoint DL (BT-932)	Dual Channel Ultra SCSI-2
-FlashPoint LW (BT-950)	Wide Ultra SCSI-2
-FlashPoint DW (BT-952)	Dual Channel Wide Ultra SCSI-2
+FlashPoint LT (BT-930)	Ultra SCSI-3
+FlashPoint LT (BT-930R)	Ultra SCSI-3 with RAIDPlus
+FlashPoint LT (BT-920)	Ultra SCSI-3 (BT-930 without BIOS)
+FlashPoint DL (BT-932)	Dual Channel Ultra SCSI-3
+FlashPoint DL (BT-932R)	Dual Channel Ultra SCSI-3 with RAIDPlus
+FlashPoint LW (BT-950)	Wide Ultra SCSI-3
+FlashPoint LW (BT-950R)	Wide Ultra SCSI-3 with RAIDPlus
+FlashPoint DW (BT-952)	Dual Channel Wide Ultra SCSI-3
+FlashPoint DW (BT-952R)	Dual Channel Wide Ultra SCSI-3 with RAIDPlus
 
 MultiMaster "W" Series Host Adapters:
 
-BT-948	    PCI		Ultra SCSI-2
-BT-958	    PCI		Wide Ultra SCSI-2
-BT-958D	    PCI		Wide Differential Ultra SCSI-2
+BT-948	    PCI		Ultra SCSI-3
+BT-958	    PCI		Wide Ultra SCSI-3
+BT-958D	    PCI		Wide Differential Ultra SCSI-3
 
 MultiMaster "C" Series Host Adapters:
 
@@ -231,6 +256,39 @@
 AMI FastDisk Host Adapters that are true BusLogic MultiMaster clones are also
 supported by this driver.
 
+BusLogic SCSI Host Adapters are available packaged both as bare boards and as
+retail kits.  The BT- model numbers above refer to the bare board packaging.
+The retail kit model numbers are found by replacing BT- with KT- in the above
+list.  The retail kit includes the bare board and manual as well as cabling and
+driver media and documentation that are not provided with bare boards.
+
+
+			 FLASHPOINT INSTALLATION NOTES
+
+o RAIDPlus Support
+
+  FlashPoint Host Adapters now include RAIDPlus, Mylex's bootable software
+  RAID.  RAIDPlus is not supported on Linux, and there are no plans to support
+  it.  The MD driver in Linux 2.0 provides for concatenation (LINEAR) and
+  striping (RAID-0), and support for mirroring (RAID-1), fixed parity (RAID-4),
+  and distributed parity (RAID-5) is available separately.  The built-in Linux
+  RAID support is generally more flexible and is expected to perform better
+  than RAIDPlus, so there is little impetus to include RAIDPlus support in the
+  BusLogic driver.
+
+o Enabling UltraSCSI Transfers
+
+  FlashPoint Host Adapters ship with their configuration set to "Factory
+  Default" settings that are conservative and do not allow for UltraSCSI speed
+  to be negotiated.  This results in fewer problems when these host adapters
+  are installed in systems with cabling or termination that is not sufficient
+  for UltraSCSI operation, or where existing SCSI devices do not properly
+  respond to synchronous transfer negotiation for UltraSCSI speed.  AutoSCSI
+  may be used to load "Optimum Performance" settings which allow UltraSCSI
+  speed to be negotiated with all devices, or UltraSCSI speed can be enabled on
+  an individual basis.  It is recommended that SCAM be manually disabled after
+  the "Optimum Performance" settings are loaded.
+
 
 		      BT-948/958/958D INSTALLATION NOTES
 
@@ -284,113 +342,254 @@
   so as to recognize the host adapters in the same order as they are enumerated
   by the host adapter's BIOS.
 
-o Mega-Transfers/Second
+o Enabling UltraSCSI Transfers
+
+  The BT-948/958/958D ship with their configuration set to "Factory Default"
+  settings that are conservative and do not allow for UltraSCSI speed to be
+  negotiated.  This results in fewer problems when these host adapters are
+  installed in systems with cabling or termination that is not sufficient for
+  UltraSCSI operation, or where existing SCSI devices do not properly respond
+  to synchronous transfer negotiation for UltraSCSI speed.  AutoSCSI may be
+  used to load "Optimum Performance" settings which allow UltraSCSI speed to be
+  negotiated with all devices, or UltraSCSI speed can be enabled on an
+  individual basis.  It is recommended that SCAM be manually disabled after the
+  "Optimum Performance" settings are loaded.
+
+
+				DRIVER OPTIONS
+
+BusLogic Driver Options may be specified either via the Linux Kernel Command
+Line or via the Loadable Kernel Module Installation Facility.  Driver Options
+for multiple host adapters may be specified either by separating the option
+strings by a semicolon, or by specifying multiple "BusLogic=" strings on the
+command line.  Individual option specifications for a single host adapter are
+separated by commas.  The Probing and Debugging Options apply to all host
+adapters whereas the remaining options apply individually only to the
+selected host adapter.
+
+The BusLogic Driver Probing Options comprise the following:
+
+IO:<integer>
+
+  The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI
+  MultiMaster Host Adapter.  If neither "IO:" nor "NoProbeISA" options are
+  specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses
+  will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134).  Multiple
+  "IO:" options may be specified to precisely determine the I/O Addresses to
+  be probed, but the probe order will always follow the standard list.
+
+NoProbe
+
+  The "NoProbe" option disables all probing and therefore no BusLogic Host
+  Adapters will be detected.
+
+NoProbeISA
+
+  The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O
+  Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters
+  will be detected.
 
-  The driver reports on the synchronous transfer parameters negotiated between
-  the host adapter and target devices in units of "mega-transfers/second".  For
-  wide devices, the unit of transfer is 16 bits if wide negotiation has been
-  successfully completed.  Therefore, the total transfer rate to wide devices
-  will generally be twice the synchronous tranfer rate reported by the driver.
+NoProbePCI
 
+  The "NoProbePCI" options disables the interrogation of PCI Configuration
+  Space and therefore only ISA Multimaster Host Adapters will be detected, as
+  well as PCI Multimaster Host Adapters that have their ISA Compatible I/O
+  Port set to "Primary" or "Alternate".
 
-			     COMMAND LINE OPTIONS
+NoSortPCI
 
-Many features of this driver are configurable by specification of appropriate
-kernel command line options.  A full description of the command line options
-may be found in the comments before BusLogic_Setup in the kernel source code
-file "BusLogic.c".  The following examples may be useful as a starting point:
+  The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be
+  enumerated in the order provided by the PCI BIOS, ignoring any setting of
+  the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
 
-  "BusLogic=NoProbe"
+MultiMasterFirst
 
-    No probing of any kind is to be performed, and hence no BusLogic Host
-    Adapters will be detected.
+  The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed
+  before FlashPoint Host Adapters.  By default, if both FlashPoint and PCI
+  MultiMaster Host Adapters are present, this driver will probe for
+  FlashPoint Host Adapters first unless the BIOS primary disk is controlled
+  by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host
+  Adapters will be probed first.
 
-  "BusLogic=NoProbeISA"
+FlashPointFirst
 
-    No probing of the standard ISA I/O Addresses will be done, and hence only
-    PCI Host Adapters will be detected.
+  The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed
+  before MultiMaster Host Adapters.
 
-  "BusLogic=NoProbePCI"
+The BusLogic Driver Tagged Queuing Options allow for explicitly specifying
+the Queue Depth and whether Tagged Queuing is permitted for each Target
+Device (assuming that the Target Device supports Tagged Queuing).  The Queue
+Depth is the number of SCSI Commands that are allowed to be concurrently
+presented for execution (either to the Host Adapter or Target Device).  Note
+that explicitly enabling Tagged Queuing may lead to problems; the option to
+enable or disable Tagged Queuing is provided primarily to allow disabling
+Tagged Queuing on Target Devices that do not implement it correctly.  The
+following options are available:
 
-    No interrogation of PCI Configuration Space will be made, and hence only
-    ISA Multimaster Host Adapters will be detected, as well as PCI Multimaster
-    Host Adapters that have their ISA Compatible I/O Port set to "Primary" or
-    "Alternate".
+QueueDepth:<integer>
 
-  "BusLogic=NoSortPCI"
+  The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
+  Target Devices that support Tagged Queuing.  If no Queue Depth option is
+  provided, the Queue Depth will be determined automatically based on the
+  Host Adapter's Total Queue Depth and the number, type, speed, and
+  capabilities of the detected Target Devices.  For Host Adapters that
+  require ISA Bounce Buffers, the Queue Depth is automatically set by default
+  to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA
+  Bounce Buffer memory.  Target Devices that do not support Tagged Queuing
+  always use a Queue Depth of BusLogic_UntaggedQueueDepth.
 
-    PCI MultiMaster Host Adapters will be enumerated in the order provided by
-    the PCI BIOS, ignoring any setting of the AutoSCSI "Use Bus And Device #
-    For PCI Scanning Seq." option.
+QueueDepth:[<integer>,<integer>...]
 
-  "BusLogic=MultiMasterFirst"
+  The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth
+  individually for each Target Device.  If an <integer> is omitted, the
+  associated Target Device will have its Queue Depth selected automatically.
 
-    By default, if both FlashPoint and PCI MultiMaster Host Adapters are
-    present, this driver will probe for FlashPoint Host Adapters first unless
-    the BIOS primary disk is controlled by the first PCI MultiMaster Host
-    Adapter, in which case MultiMaster Host Adapters will be probed first.
-    This option forces MultiMaster Host Adapters to be probed first.
+TaggedQueuing:Default
 
-  "BusLogic=FlashPointFirst"
+  The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing
+  based on the firmware version of the BusLogic Host Adapter and based on
+  whether the Queue Depth allows queuing multiple commands.
 
-    By default, if both FlashPoint and PCI MultiMaster Host Adapters are
-    present, this driver will probe for FlashPoint Host Adapters first unless
-    the BIOS primary disk is controlled by the first PCI MultiMaster Host
-    Adapter, in which case MultiMaster Host Adapters will be probed first.
-    This option forces FlashPoint Host Adapters to be probed first.
+TaggedQueuing:Enable
 
-  "BusLogic=0x330"
+  The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for
+  all Target Devices on this Host Adapter, overriding any limitation that
+  would otherwise be imposed based on the Host Adapter firmware version.
 
-    This command line limits probing to the single I/O port at 0x330.
+TaggedQueuing:Disable
 
-  "BusLogic=0,1"
+  The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing
+  for all Target Devices on this Host Adapter.
 
-    This command line selects default probing and a tagged queue depth of 1
-    which also disables tagged queuing.  It may be useful if problems arise
-    during installation on a system with a flaky SCSI configuration.  In cases
-    of a marginal SCSI configuration it may also be beneficial to disable fast
-    transfers and/or synchronous negotiation using AutoSCSI on FlashPoint and
-    "W" and "C" series MultiMaster host adapters.  Disconnect/reconnect may
-    also be disabled for fast devices such as disk drives, but should not be
-    disabled for tape drives or other devices where a single command may take
-    over a second to execute.
+TaggedQueuing:<Target-Spec>
 
-  "BusLogic=0,0,30"
+  The "TaggedQueuing:<Target-Spec>" or "TQ:<Target-Spec>" option controls
+  Tagged Queuing individually for each Target Device.  <Target-Spec> is a
+  sequence of "Y", "N", and "X" characters.  "Y" enables Tagged Queuing, "N"
+  disables Tagged Queuing, and "X" accepts the default based on the firmware
+  version.  The first character refers to Target Device 0, the second to
+  Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters
+  does not cover all the Target Devices, unspecified characters are assumed
+  to be "X".
 
-    This command line selects default probing and automatic tagged queue depth
-    selection, but changes the bus settle time to 30 seconds.  It may be useful
-    with SCSI devices that take an unusually long time to become ready to
-    accept commands after a SCSI bus reset.  Some tape drives will not respond
-    properly immediately after a SCSI bus reset, especially if a tape is
-    present in the drive.
+The BusLogic Driver Error Recovery Option allows for explicitly specifying
+the Error Recovery action to be performed when BusLogic_ResetCommand is
+called due to a SCSI Command failing to complete successfully.  The following
+options are available:
 
-  "BusLogic=TQ:Disable"
+ErrorRecovery:Default
 
-    This command line selects default probing and disables tagged queuing.
+  The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard
+  Reset and Bus Device Reset options based on the recommendation of the SCSI
+  Subsystem.
 
-  "BusLogic=0,15,TQ:N"
+ErrorRecovery:HardReset
 
-    This command line selects a tagged queue depth of 15 and disables tagged
-    queuing for target 0, while allowing tagged queuing for all other target
-    devices.
+  The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host
+  Adapter Hard Reset which also causes a SCSI Bus Reset.
 
-Note that limiting the tagged queue depth or disabling tagged queuing can
-substantially impact performance.
+ErrorRecovery:BusDeviceReset
 
+  The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send
+  a Bus Device Reset message to the individual Target Device causing the
+  error.  If Error Recovery is again initiated for this Target Device and no
+  SCSI Command to this Target Device has completed successfully since the Bus
+  Device Reset message was sent, then a Hard Reset will be attempted.
 
-				 INSTALLATION
+ErrorRecovery:None
 
-This distribution was prepared for Linux kernel version 2.0.30, but should be
-compatible with 2.0.4 or any later 2.0 series kernel if BusLogic.patch is also
-applied.
+  The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery.
+  This option should only be selected if a SCSI Bus Reset or Bus Device Reset
+  will cause the Target Device or a critical operation to suffer a complete
+  and unrecoverable failure.
+
+ErrorRecovery:<Target-Spec>
+
+  The "ErrorRecovery:<Target-Spec>" or "ER:<Target-Spec>" option controls
+  Error Recovery individually for each Target Device.  <Target-Spec> is a
+  sequence of "D", "H", "B", and "N" characters.  "D" selects Default, "H"
+  selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None.
+  The first character refers to Target Device 0, the second to Target Device
+  1, and so on; if the sequence of "D", "H", "B", and "N" characters does not
+  cover all the possible Target Devices, unspecified characters are assumed
+  to be "D".
+
+The BusLogic Driver Miscellaneous Options comprise the following:
+
+BusSettleTime:<seconds>
+
+  The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in
+  seconds.  The Bus Settle Time is the amount of time to wait between a Host
+  Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI
+  Commands.  If unspecified, it defaults to BusLogic_DefaultBusSettleTime.
+
+InhibitTargetInquiry
+
+  The "InhibitTargetInquiry" option inhibits the execution of an Inquire
+  Target Devices or Inquire Installed Devices command on MultiMaster Host
+  Adapters.  This may be necessary with some older Target Devices that do not
+  respond correctly when Logical Units above 0 are addressed.
+
+The BusLogic Driver Debugging Options comprise the following:
+
+TraceProbe
+
+  The "TraceProbe" option enables tracing of Host Adapter Probing.
+
+TraceHardwareReset
+
+  The "TraceHardwareReset" option enables tracing of Host Adapter Hardware
+  Reset.
+
+TraceConfiguration
+
+  The "TraceConfiguration" option enables tracing of Host Adapter
+  Configuration.
+
+TraceErrors
+
+  The "TraceErrors" option enables tracing of SCSI Commands that return an
+  error from the Target Device.  The CDB and Sense Data will be printed for
+  each SCSI Command that fails.
+
+Debug
+
+  The "Debug" option enables all debugging options.
+
+The following examples demonstrate setting the Queue Depth for Target Devices
+1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target
+Devices on the second host adapter to 31, and the Bus Settle Time on the
+second host adapter to 30 seconds.
+
+Linux Kernel Command Line:
+
+  linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30
+
+LILO Linux Boot Loader (in /etc/lilo.conf):
+
+  append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"
+
+INSMOD Loadable Kernel Module Installation Facility:
+
+  insmod BusLogic.o \
+      'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"'
+
+NOTE: Module Utilities 2.1.71 or later is required for correct parsing
+      of driver options containing commas.
+
+
+			      DRIVER INSTALLATION
+
+This distribution was prepared for Linux kernel version 2.0.33, but should be
+compatible with 2.0.4 or any later 2.0 series kernel.
 
 To install the new BusLogic SCSI driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf BusLogic-2.0.10.tar.gz
+  tar -xvzf BusLogic-2.0.11.tar.gz
   mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
-  patch -p < BusLogic.patch	    # Only for kernels prior to 2.0.30
+  patch -p < BusLogic.patch
   cd linux
   make config
   make depend
@@ -398,11 +597,6 @@
 
 Then install "arch/i386/boot/zImage" as your standard kernel, run lilo if
 appropriate, and reboot.
-
-Be sure to answer "y" to the "BusLogic SCSI support" query during the "make
-config" step.  If your system was already configured for the old BusLogic
-driver or for an older version of this driver, you may omit the "make config"
-step above.
 
 
 		      BUSLOGIC ANNOUNCEMENTS MAILING LIST
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/README.Mylex linux/drivers/scsi/README.Mylex
--- v2.1.86/linux/drivers/scsi/README.Mylex	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/README.Mylex	Sat Jan 31 02:00:00 1998
@@ -0,0 +1,6 @@
+Please see the file README.BusLogic for information about Linux support for
+Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters.
+
+The Mylex DAC960 PCI RAID Controllers are not supported at the present time,
+but work on a Linux driver for the DAC960 is in progress.  Please consult
+http://www.dandelion.com/Linux/ for further information on the DAC960 driver.
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.1.86/linux/drivers/scsi/hosts.h	Fri Feb  6 15:33:40 1998
+++ linux/drivers/scsi/hosts.h	Mon Feb 16 15:34:59 1998
@@ -371,7 +371,13 @@
 
     void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
-    unsigned long hostdata[0];  /* Used for storage of host specific stuff */
+    /*
+     * We should ensure that this is aligned, both for better performance
+     * and also because some compilers (m68k) don't automatically force
+     * alignment to a 4-byte boundary.
+     */
+    unsigned long hostdata[0]  /* Used for storage of host specific stuff */
+        __attribute__ ((aligned (4)));
 };
 
 extern struct Scsi_Host * scsi_hostlist;
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/ibmmca.h linux/drivers/scsi/ibmmca.h
--- v2.1.86/linux/drivers/scsi/ibmmca.h	Wed Feb  4 11:36:00 1998
+++ linux/drivers/scsi/ibmmca.h	Thu Feb 12 16:25:04 1998
@@ -19,29 +19,29 @@
 extern struct proc_dir_entry proc_scsi_ibmmca;
 
 /*initialization for Scsi_host_template type */
-#define IBMMCA {                                      \
-          NULL,                 /*next*/              \
-          NULL,                 /*usage_count*/       \
-          &proc_scsi_ibmmca,    /*proc_dir*/          \
-          ibmmca_proc_info,     /*proc info fn*/      \
-          "IBMMCA",             /*name*/              \
-          ibmmca_detect,        /*detect fn*/         \
-          ibmmca_release,       /*release fn*/        \
-          NULL,                 /*info fn*/           \
-          ibmmca_command,       /*command fn*/        \
-          ibmmca_queuecommand,  /*queuecommand fn*/   \
-          ibmmca_abort,         /*abort fn*/          \
-          ibmmca_reset,         /*reset fn*/          \
-          NULL,                 /*slave_attach fn*/   \
-          ibmmca_biosparam,     /*bios fn*/           \
-          16,                   /*can_queue*/         \
-          7,                    /*set by detect*/     \
-          16,                   /*sg_tablesize*/      \
-          1,                    /*cmd_per_lun*/       \
-          0,                    /*present*/           \
-          0,                    /*unchecked_isa_dma*/ \
-          ENABLE_CLUSTERING     /*use_clustering*/    \
-        }
+/*
+ * 2/8/98
+ * Note to maintainer of IBMMCA.  Do not change this initializer back to
+ * the old format.  Please ask eric@andante.jic.com if you have any questions
+ * about this, but it will break things in the future.
+ */
+#define IBMMCA {						      \
+          proc_dir:       &proc_scsi_ibmmca,    /*proc_dir*/          \
+	  proc_info:	  ibmmca_proc_info,     /*proc info fn*/      \
+          name:           "IBMMCA",             /*name*/              \
+          detect:         ibmmca_detect,        /*detect fn*/         \
+          release:        ibmmca_release,       /*release fn*/        \
+          command:        ibmmca_command,       /*command fn*/        \
+          queuecommand:   ibmmca_queuecommand,  /*queuecommand fn*/   \
+          abort:          ibmmca_abort,         /*abort fn*/          \
+          reset:          ibmmca_reset,         /*reset fn*/          \
+          bios_param:     ibmmca_biosparam,     /*bios fn*/           \
+          can_queue:      16,                   /*can_queue*/         \
+          this_id:        7,                    /*set by detect*/     \
+          sg_tablesize:   16,                   /*sg_tablesize*/      \
+          cmd_per_lun:    1,                    /*cmd_per_lun*/       \
+          use_clustering: ENABLE_CLUSTERING     /*use_clustering*/    \
+          }
 
 #endif /* _IBMMCA_H */
 
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.1.86/linux/drivers/scsi/pci2000.c	Wed Nov  5 12:59:49 1997
+++ linux/drivers/scsi/pci2000.c	Thu Feb 12 15:42:55 1998
@@ -653,7 +653,7 @@
 
 #ifdef MODULE
 /* Eventually this will go into an include file, but this will be later */
-Scsi_Host_Template driver_template = PCI2220I;
+Scsi_Host_Template driver_template = PCI2000;
 
 #include "scsi_module.c"
 #endif
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.1.86/linux/drivers/scsi/scsi.h	Fri Feb  6 15:33:40 1998
+++ linux/drivers/scsi/scsi.h	Mon Feb 16 15:34:59 1998
@@ -685,7 +685,7 @@
 #define INIT_SCSI_REQUEST       \
     if (!CURRENT) {             \
 	CLEAR_INTR;             \
-	restore_flags(flags);	\
+	spin_unlock_irqrestore(&current_lock,flags);	\
 	return;                 \
     }                           \
     if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)           \
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.1.86/linux/drivers/scsi/scsi_error.c	Mon Jan 19 22:13:17 1998
+++ linux/drivers/scsi/scsi_error.c	Thu Feb 12 16:25:04 1998
@@ -1785,7 +1785,7 @@
          * This needs to be attached to task[0] instead.
          */
 
-	sigfillset(&current->blocked);
+	siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
         current->fs->umask = 0;
 
 	/*
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.1.86/linux/drivers/scsi/sd.c	Sat Jan 10 10:50:07 1998
+++ linux/drivers/scsi/sd.c	Thu Feb 12 16:25:04 1998
@@ -91,7 +91,7 @@
 {
     if( disknum <= 26 )
     {
-        sprintf(buffer, "sd%c", 'a' + (disknum >> 4));
+        sprintf(buffer, "sd%c", 'a' + disknum);
     }
     else
     {
@@ -101,8 +101,8 @@
          * For larger numbers of disks, we need to go to a new
          * naming scheme.
          */
-        min1 = (disknum >> 4) / 26;
-        min2 = (disknum >> 4) % 26;
+        min1 = disknum / 26;
+        min2 = disknum % 26;
         sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2);
     }
 }
@@ -516,11 +516,11 @@
     unsigned long flags;
     int flag = 0;
 
-    save_flags(flags);
     while (1==1){
-	cli();
+	spin_lock_irqsave(&current_lock, flags);
+
 	if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
-	    restore_flags(flags);
+            spin_unlock_irqrestore(&current_lock, flags);
 	    return;
 	}
 
@@ -535,6 +535,7 @@
          */
         if( SDev->host->in_recovery )
           {
+            spin_unlock_irqrestore(&current_lock, flags);
             return;
           }
 
@@ -554,6 +555,7 @@
 	     */
 	    if( SDev->removable && !in_interrupt() )
 	    {
+                spin_unlock(&current_lock);
                 scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
 		/* scsi_ioctl may allow CURRENT to change, so start over. */
 		SDev->was_reset = 0;
@@ -585,7 +587,7 @@
 	 * Using a "sti()" gets rid of the latency problems but causes
 	 * race conditions and crashes.
 	 */
-	restore_flags(flags);
+        spin_unlock_irqrestore(&current_lock, flags);
 
 	/* This is a performance enhancement. We dig down into the request
 	 * list and try to find a queueable request (i.e. device not busy,
@@ -603,7 +605,7 @@
 	if (!SCpnt && sd_template.nr_dev > 1){
 	    struct request *req1;
 	    req1 = NULL;
-	    cli();
+	    spin_lock_irqsave(&current_lock, flags);
 	    req = CURRENT;
 	    while(req){
 		SCpnt = scsi_request_queueable(req,
@@ -618,7 +620,7 @@
 		else
 		    req1->next = req->next;
 	    }
-	    restore_flags(flags);
+            spin_unlock_irqrestore(&current_lock, flags);
 	}
 
 	if (!SCpnt) return; /* Could not find anything to do */
diff -u --recursive --new-file v2.1.86/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.1.86/linux/drivers/scsi/sr.c	Thu Jan  8 20:35:43 1998
+++ linux/drivers/scsi/sr.c	Thu Feb 12 16:25:04 1998
@@ -761,7 +761,13 @@
 
 	if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2;
 
-	if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten)
+        /*
+         * Note: The scsi standard says that READ_6 is *optional*, while
+         * READ_10 is mandatory.   Thus there is no point in using
+         * READ_6.
+         */
+	if (scsi_CDs[dev].ten)
+          
     {
 		if (realcount > 0xffff)
 	{
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.1.86/linux/drivers/sound/Config.in	Thu Feb 12 20:56:10 1998
+++ linux/drivers/sound/Config.in	Sun Feb 15 12:10:12 1998
@@ -1,19 +1,19 @@
 dep_tristate 'ProAudioSpectrum 16 support' CONFIG_PAS $CONFIG_SOUND
 if [ "$CONFIG_PAS" = "y" ]; then
-    int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10
-    int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3
+    int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10
+    int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' CONFIG_PAS_DMA 3
 fi
 
 dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND
 if [ "$CONFIG_SB" = "y" ]; then
-    hex 'I/O base for SB Check from manual of the card' SBC_BASE 220
-    int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7
-    int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1
-    int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5
-    hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330
+    hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220
+    int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7
+    int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1
+    int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' CONFIG_SB_DMA2 5
+    hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' CONFIG_SB_MPU_BASE 330
     comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.'
     comment 'Enter -1 to the following question if you have something else such as SB16/32.'
-    int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1
+    int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1
 fi
 
 dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB $CONFIG_SOUND
@@ -23,116 +23,116 @@
     bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 
     bool 'GUS MAX support' CONFIG_GUSMAX
     if [ "$CONFIG_GUS" = "y" ]; then
-	hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220
-	int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15
-	int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6
-	int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1
+	hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' CONFIG_GUS_BASE 220
+	int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' CONFIG_GUS_IRQ 15
+	int 'GUS DMA 1, 3, 5, 6 or 7' CONFIG_GUS_DMA 6
+	int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' CONFIG_GUS_DMA2 -1
 	if [ "$CONFIG_GUS16" = "y" ]; then
-	    hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530
-	    int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7
-	    int 'GUS DMA 0, 1 or 3' GUS16_DMA 3
+	    hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' CONFIG_GUS16_BASE 530
+	    int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' CONFIG_GUS16_IRQ 7
+	    int 'GUS DMA 0, 1 or 3' CONFIG_GUS16_DMA 3
 	fi
     fi
 fi
 
 dep_tristate 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 $CONFIG_SOUND
 if [ "$CONFIG_MPU401" = "y" ]; then
-    hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330
-    int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9
+    hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330
+    int 'MPU401 IRQ Check from manual of the card' CONFIG_MPU_IRQ 9
 fi
 
 dep_tristate 'PSS (ECHO-ADI2111) support' CONFIG_PSS $CONFIG_SOUND
 if [ "$CONFIG_PSS" = "y" ]; then
-    hex 'PSS I/O base 220 or 240' PSS_BASE 220
-    hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530
-    int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11
-    int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3
-    hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330
-    int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9
-    bool '  Have DSPxxx.LD firmware file' PSS_HAVE_BOOT
-    if [ "$PSS_HAVE_BOOT" = "y" ]; then
-       string '  Full pathname of DSPxxx.LD firmware file' PSS_BOOT_FILE
+    hex 'PSS I/O base 220 or 240' CONFIG_PSS_BASE 220
+    hex 'PSS audio I/O base 530, 604, E80 or F40' CONFIG_PSS_MSS_BASE 530
+    int 'PSS audio IRQ 7, 9, 10 or 11' CONFIG_PSS_MSS_IRQ 11
+    int 'PSS audio DMA 0, 1 or 3' CONFIG_PSS_MSS_DMA 3
+    hex 'PSS MIDI I/O base ' CONFIG_PSS_MPU_BASE 330
+    int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_PSS_MPU_IRQ 9
+    bool '  Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT
+    if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then
+       string '  Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE
     fi
 fi
 
 dep_tristate 'Microsoft Sound System support' CONFIG_MSS $CONFIG_SOUND
 if [ "$CONFIG_MSS" = "y" ]; then
-    hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530
-    int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11
-    int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3
-    int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1
+    hex 'MSS/WSS I/O base 530, 604, E80 or F40' CONFIG_MSS_BASE 530
+    int 'MSS/WSS IRQ 7, 9, 10 or 11' CONFIG_MSS_IRQ 11
+    int 'MSS/WSS DMA 0, 1 or 3' CONFIG_MSS_DMA 3
+    int 'MSS/WSS second DMA (if possible) 0, 1 or 3' CONFIG_MSS_DMA2 -1
 fi
 
 dep_tristate 'Ensoniq SoundScape support' CONFIG_SSCAPE $CONFIG_SOUND
 if [ "$CONFIG_SSCAPE" = "y" ]; then
-    hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330
-    int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9
-    int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3
-    hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534
-    int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11
+    hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' CONFIG_SSCAPE_BASE 330
+    int 'SoundScape MIDI IRQ ' CONFIG_SSCAPE_IRQ 9
+    int 'SoundScape initialization DMA 0, 1 or 3' CONFIG_SSCAPE_DMA 3
+    hex 'SoundScape audio I/O base 534, 608, E84 or F44' CONFIG_SSCAPE_MSS_BASE 534
+    int 'SoundScape audio IRQ 7, 9, 10 or 11' CONFIG_SSCAPE_MSS_IRQ 11
 fi
 
 dep_tristate 'MediaTrix AudioTrix Pro support' CONFIG_TRIX $CONFIG_SOUND
 if [ "$CONFIG_TRIX" = "y" ]; then
-    hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' TRIX_BASE 530
-    int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11
-    int 'OPL3-SA1 audio DMA 0, 1 or 3' TRIX_DMA 0
-    int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3
-    hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330
-    int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9
-    hex 'OPL3-SA1 SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220
-    int 'OPL3-SA1 SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7
-    int 'OPL3-SA1 SB DMA 1 or 3' TRIX_SB_DMA 1
-    bool '  Have TRXPRO.HEX firmware file' TRIX_HAVE_BOOT
-    if [ "$TRIX_HAVE_BOOT" = "y" ]; then
-	string '  Full pathname of TRXPRO.HEX firmware file' TRIX_BOOT_FILE
+    hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_TRIX_BASE 530
+    int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_TRIX_IRQ 11
+    int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_TRIX_DMA 0
+    int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' CONFIG_TRIX_DMA2 3
+    hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_TRIX_MPU_BASE 330
+    int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_TRIX_MPU_IRQ 9
+    hex 'OPL3-SA1 SB I/O base 220, 210, 230, 240, 250, 260 or 270' CONFIG_TRIX_SB_BASE 220
+    int 'OPL3-SA1 SB IRQ 3, 4, 5 or 7' CONFIG_TRIX_SB_IRQ 7
+    int 'OPL3-SA1 SB DMA 1 or 3' CONFIG_TRIX_SB_DMA 1
+    bool '  Have TRXPRO.HEX firmware file' CONFIG_TRIX_HAVE_BOOT
+    if [ "$CONFIG_TRIX_HAVE_BOOT" = "y" ]; then
+	string '  Full pathname of TRXPRO.HEX firmware file' CONFIG_TRIX_BOOT_FILE
     fi
 fi
 
 dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16 $CONFIG_SOUND
 if [ "$CONFIG_MAD16" = "y" ]; then
-    hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530
-    int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11
-    int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3
-    int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0
-    hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330
-    int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9
+    hex 'MAD16 audio I/O base 530, 604, E80 or F40' CONFIG_MAD16_BASE 530
+    int 'MAD16 audio IRQ 7, 9, 10 or 11' CONFIG_MAD16_IRQ 11
+    int 'MAD16 audio DMA 0, 1 or 3' CONFIG_MAD16_DMA 3
+    int 'MAD16 second (duplex) DMA 0, 1 or 3' CONFIG_MAD16_DMA2 0
+    hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' CONFIG_MAD16_MPU_BASE 330
+    int 'MAD16 MIDI IRQ 5, 7, 9 or 10' CONFIG_MAD16_MPU_IRQ 9
 fi
 
 dep_tristate 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 $CONFIG_SOUND
 if [ "$CONFIG_CS4232" = "y" ]; then
-    hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530
-    int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11
-    int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0
-    int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3
-    hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330
-    int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9
+    hex 'CS4232 audio I/O base 530, 604, E80 or F40' CONFIG_CS4232_BASE 530
+    int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_IRQ 11
+    int 'CS4232 audio DMA 0, 1 or 3' CONFIG_CS4232_DMA 0
+    int 'CS4232 second (duplex) DMA 0, 1 or 3' CONFIG_CS4232_DMA2 3
+    hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_CS4232_MPU_BASE 330
+    int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9
 fi
 
 dep_tristate 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI $CONFIG_SOUND
 if [ "$CONFIG_MAUI" = "y" ]; then
-    hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330
-    int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9
-    bool '  Have OSWF.MOT firmware file' MAUI_HAVE_BOOT
-    if [ "$MAUI_HAVE_BOOT" = "y" ]; then
-	string '  Full pathname of OSWF.MOT firmware file' MAUI_BOOT_FILE
+    hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330
+    int 'Maui IRQ 5, 9, 12 or 15' CONFIG_MAUI_IRQ 9
+    bool '  Have OSWF.MOT firmware file' CONFIG_MAUI_HAVE_BOOT
+    if [ "$CONFIG_MAUI_HAVE_BOOT" = "y" ]; then
+	string '  Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE
     fi
 fi
 
 dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_OPL3SA1 $CONFIG_SOUND
 if [ "$CONFIG_OPL3SA1" = "y" ]; then
-    hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' OPL3SA1_BASE 530
-    int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' OPL3SA1_IRQ 11
-    int 'OPL3-SA1 audio DMA 0, 1 or 3' OPL3SA1_DMA 0
-    int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' OPL3SA1_DMA2 3
-    hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' OPL3SA1_MPU_BASE 330
-    int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' OPL3SA1_MPU_IRQ 9
+    hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA1_BASE 530
+    int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_OPL3SA1_IRQ 11
+    int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA 0
+    int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA2 3
+    hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_OPL3SA1_MPU_BASE 330
+    int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_OPL3SA1_MPU_IRQ 9
 fi
 
 dep_tristate 'SoftOSS software wave table engine' CONFIG_SOFTOSS $CONFIG_SOUND
 if [ "$CONFIG_SOFTOSS" = "y" ]; then
-    int 'Sampling rate for SoftOSS 8000 to 48000' SOFTOSS_RATE 22050
-    int 'Max # of concurrent voices for SoftOSS 4 to 32' SOFTOSS_VOICES 32
+    int 'Sampling rate for SoftOSS 8000 to 48000' CONFIG_SOFTOSS_RATE 22050
+    int 'Max # of concurrent voices for SoftOSS 4 to 32' CONFIG_SOFTOSS_VOICES 32
 fi
 
 dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 $CONFIG_SOUND
@@ -140,8 +140,8 @@
 
 dep_tristate '6850 UART support' CONFIG_UART6850 $CONFIG_SOUND
 if [ "$CONFIG_UART6850" = "y" ]; then
-    hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
-    int 'UART6850 IRQ (Unknown)' U6850_IRQ -1
+    hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0
+    int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1
 fi
 
 
@@ -153,7 +153,7 @@
    dep_tristate 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND
 
    if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
-      hex '  I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
+      hex '  I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
    fi
 
    if [ "$CONFIG_AEDSP16" = "y" ]; then
@@ -165,10 +165,10 @@
          if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then
 	    comment 'Audio Excel DSP 16 [Sound Blaster Pro]'
             hex 'I/O base for Audio Excel DSP 16 220 or 240' \
-	                                           AEDSP16_BASE $SBC_BASE
+	                                           CONFIG_AEDSP16_BASE $CONFIG_SB_BASE
             int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \
-	                                           AEDSP16_SBC_IRQ $SBC_IRQ
-            int 'Audio Excel DSP 16 DMA 0, 1 or 3' AEDSP16_SBC_DMA $SBC_DMA
+	                                           CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ
+            int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA
          fi
       fi
    
@@ -176,10 +176,10 @@
          bool 'Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS
          if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then
 	    comment 'Audio Excel DSP 16 [Microsoft Sound System]'
-	    hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
+	    hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
             int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \
-	                                           AEDSP16_MSS_IRQ $MSS_IRQ
-            int 'Audio Excel DSP 16 DMA 0, 1 or 3' AEDSP16_MSS_DMA $MSS_DMA
+	                                           CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ
+            int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA
          fi
       fi
 
@@ -189,10 +189,10 @@
 	    comment 'Audio Excel DSP 16 [MPU-401]'
 	    if [ "$CONFIG_AEDSP16_SBPRO" != "y" \
 	         -a "$CONFIG_AEDSP16_MSS" != "y" ]; then
-	       hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
+	       hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
 	    fi
             int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' \
-	    						AEDSP16_MPU_IRQ $MPU_IRQ
+	    						CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ
          fi
       fi
    fi
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.1.86/linux/drivers/sound/Makefile	Sun Jan  4 10:40:16 1998
+++ linux/drivers/sound/Makefile	Sun Feb 15 12:10:12 1998
@@ -258,48 +258,48 @@
 hex2hex: hex2hex.c
 	$(HOSTCC) -o hex2hex hex2hex.c
 
-ifeq ($(MAUI_HAVE_BOOT),y)
+ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
 
-MAUI_BOOT_FILE := $(patsubst "%", %, $(MAUI_BOOT_FILE))
+CONFIG_MAUI_BOOT_FILE := $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE))
 
 maui.o: maui_boot.h
 
-maui_boot.h: $(MAUI_BOOT_FILE) bin2hex
-	bin2hex maui_os < "$(MAUI_BOOT_FILE)" > $@
+maui_boot.h: $(CONFIG_MAUI_BOOT_FILE) bin2hex
+	bin2hex maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@
 	@ ( \
-	    echo 'ifeq ($(strip $(MAUI_BOOT_FILE)),$$(strip $$(MAUI_BOOT_FILE)))'; \
+	    echo 'ifeq ($(strip $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_BOOT_FILE)))'; \
 	    echo 'FILES_BOOT_UP_TO_DATE += $@'; \
 	    echo 'endif' \
 	) > .$@.boot
 
 endif
 
-ifeq ($(PSS_HAVE_BOOT),y)
+ifeq ($(CONFIG_PSS_HAVE_BOOT),y)
 
-PSS_BOOT_FILE := $(patsubst "%", %, $(PSS_BOOT_FILE))
+CONFIG_PSS_BOOT_FILE := $(patsubst "%", %, $(CONFIG_PSS_BOOT_FILE))
 
 pss.o: pss_boot.h
 
-pss_boot.h: $(PSS_BOOT_FILE) bin2hex
-	bin2hex pss_synth < "$(PSS_BOOT_FILE)" > $@
+pss_boot.h: $(CONFIG_PSS_BOOT_FILE) bin2hex
+	bin2hex pss_synth < "$(CONFIG_PSS_BOOT_FILE)" > $@
 	@ ( \
-	    echo 'ifeq ($(strip $(PSS_BOOT_FILE)),$$(strip $$(PSS_BOOT_FILE)))'; \
+	    echo 'ifeq ($(strip $(CONFIG_PSS_BOOT_FILE)),$$(strip $$(CONFIG_PSS_BOOT_FILE)))'; \
 	    echo 'FILES_BOOT_UP_TO_DATE += $@'; \
 	    echo 'endif' \
 	) > .$@.boot
 
 endif
 
-ifeq ($(TRIX_HAVE_BOOT),y)
+ifeq ($(CONFIG_TRIX_HAVE_BOOT),y)
 
-TRIX_BOOT_FILE := $(patsubst "%", %, $(TRIX_BOOT_FILE))
+CONFIG_TRIX_BOOT_FILE := $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE))
 
 trix.o: trix_boot.h
 
-trix_boot.h: $(TRIX_BOOT_FILE) hex2hex
-	hex2hex trix_boot < "$(TRIX_BOOT_FILE)" > $@
+trix_boot.h: $(CONFIG_TRIX_BOOT_FILE) hex2hex
+	hex2hex trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@
 	@ ( \
-	    echo 'ifeq ($(strip $(TRIX_BOOT_FILE)),$$(strip $$(strip $$(TRIX_BOOT_FILE)))'; \
+	    echo 'ifeq ($(strip $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_BOOT_FILE)))'; \
 	    echo 'FILES_BOOT_UP_TO_DATE += $@'; \
 	    echo 'endif' \
 	) > .$@.boot
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v2.1.86/linux/drivers/sound/Readme.cards	Tue Dec 23 13:52:02 1997
+++ linux/drivers/sound/Readme.cards	Sun Feb 15 12:10:12 1998
@@ -3,7 +3,7 @@
 
 This document describes configuring soundcards with freeware version of
 Open Sound Systems (OSS/Free). Information about the commercial version
-(OSS/Linux) and it's configuration is available from 
+(OSS/Linux) and its configuration is available from 
 http://www.opensound.com/linux.html. Information presented here is
 not valid for OSS/Linux. 
 
@@ -67,7 +67,7 @@
 2. Trying to use a PnP (Plug & Play) card just like an ordinary soundcard
 -------------------------------------------------------------------------
 
-Plug & Play is a protocol defined by Intel and Microsoft. It let's operating
+Plug & Play is a protocol defined by Intel and Microsoft. It lets operating
 systems to easily identify and reconfigure I/O ports, IRQs and DMAs of ISA
 cards. The problem with PnP cards is that the standard Linux doesn't currently
 (versions 2.1.x and earlier) don't support PnP. This means that you will have
@@ -293,25 +293,26 @@
 4Front Technologies SoftOSS
 
 	SoftOSS is a software based wave table emulation which works with
-	any 16 bit stereo soundcard. Due to it's nature a fast CPU is
-	required (P133 is minumum). Althoug SoftOSS doesn _not_ use MMX
+	any 16 bit stereo soundcard. Due to its nature a fast CPU is
+	required (P133 is minimum). Although SoftOSS does _not_ use MMX
 	instructions it has proven out that recent processors (which appear
 	to have MMX) perform significantly better with SoftOSS than earlier
 	ones. For example a P166MMX beats a PPro200. SoftOSS should not be used
 	on 486 or 386 machines.
 
-	The amount of CPU load caused by SoftOSS can be controlled by 
-	selecting the SOFTOSS_RATE and SOFTOSS_VOICES parameters properly
-	(they will be prompted by make config). It's recommended to set
-	SOFTOSS_VOICES to 32. If you have a P166MMX or faster (PPro200 is
-	not faster) you can set SOFTOSS_RATE to 44100 (kHz). However with
-	slower systems it recommended to use sampling rates around 22050
-	or even 16000 kHz. Selecting too high values for these parameters
-        may hang your system when playing MIDI files with hight degree of
-	polyphony (number of concurrently playing notes). It's also possible to
-	decrease SOFTOSS_VOICES. This makes it possible to use higher sampling
-	rates. However using fewer voices decreases playback quality more than
-	decreasing the sampling rate.
+	The amount of CPU load caused by SoftOSS can be controlled by
+	selecting the CONFIG_SOFTOSS_RATE and CONFIG_SOFTOSS_VOICES
+	parameters properly (they will be prompted by make config). It's
+	recommended to set CONFIG_SOFTOSS_VOICES to 32. If you have a
+	P166MMX or faster (PPro200 is not faster) you can set
+	CONFIG_SOFTOSS_RATE to 44100 (kHz). However with slower systems it
+	recommended to use sampling rates around 22050 or even 16000 kHz.
+	Selecting too high values for these parameters may hang your
+	system when playing MIDI files with hight degree of polyphony
+	(number of concurrently playing notes). It's also possible to
+	decrease CONFIG_SOFTOSS_VOICES. This makes it possible to use
+	higher sampling rates. However using fewer voices decreases
+	playback quality more than decreasing the sampling rate.
 
 	SoftOSS keeps the samples loaded on system's RAM so large RAM is
 	required. SoftOSS should never be used on machines with less than 16M
@@ -330,7 +331,7 @@
 
         *********************************************************************
 	IMPORTANT NOTICE! The original patch set distributed with Gravis 
-	Ultrasound card is not in public domain (even it's available from
+	Ultrasound card is not in public domain (even though it's available from
 	some ftp sites). You should contact Voice Crystal (www.voicecrystal.com)
 	if you like to use these patches with SoftOSS included in OSS/Free.
         *********************************************************************
@@ -1125,9 +1126,9 @@
 
 The following configuration parameters have worked fine for the PCM12
 in Markus Kuhn's system, many other configurations might work, too:
-MAD16_BASE=0x530, MAD16_IRQ=11, MAD16_DMA=3, MAD16_DMA2=0,
-MAD16_MPU_BASE=0x330, MAD16_MPU_IRQ=10, DSP_BUFFSIZE=65536,
-SELECTED_SOUND_OPTIONS=0x00281000.
+CONFIG_MAD16_BASE=0x530, CONFIG_MAD16_IRQ=11, CONFIG_MAD16_DMA=3, 
+CONFIG_MAD16_DMA2=0, CONFIG_MAD16_MPU_BASE=0x330, CONFIG_MAD16_MPU_IRQ=10,
+DSP_BUFFSIZE=65536, SELECTED_SOUND_OPTIONS=0x00281000.
 
 The miroSOUND PCM1 pro and the PCM20 are very similar to the PCM12.
 Perhaps the same ACI driver also works for these cards, however this
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/Readme.modules linux/drivers/sound/Readme.modules
--- v2.1.86/linux/drivers/sound/Readme.modules	Tue Sep 30 08:46:46 1997
+++ linux/drivers/sound/Readme.modules	Sun Feb 15 12:10:12 1998
@@ -1,84 +1,71 @@
-Building a loadable sound driver
+Building a modular sound driver
 ================================
 
-Loadable module support in version 3.5 of the driver is mostly rewritten since
-the previous version (3.0.1). This means that some things have changed.
-
-To compile the sound driver as a loadable module you have to perform
-the following steps:
-
-1) Install modules-1.2.8.tar.gz package (or later if available).
-2a) Check that symbol remap_page_range is defined in linux/init/ksyms.c.
-Insert a line containing "X(remap_page_range)," if required. The driver will
-not load if this line is missing.
-2b) Recompile kernel with soundcard support disabled.
-3) Boot the new kernel.
-4) cd to the sound driver source directory (this directory). It's no
-longer required that the sound driver sources are installed in the
-kernel source tree (linux/drivers/sound). When installing a separately
-distributed sound driver you may install the sources for example to
-/usr/src/sound.
-5) Execute make in the sound driver source directory. Enter
-configuration parameters as described in Readme.cards. Then just wait until
-the driver is compiled OK.
-6) Copy sound.o to the directory where insmod expects to find it. 
-("make install" copies it to /lib/modules/misc).
-7) Use command "insmod sound" to load the driver.
-
-8) The sound driver can be removed using command "rmmod sound".
-
-
-Parameters accepted by the loadable sound driver
-================================================
-
-Setting DMA buffer size
------------------------
-
-The driver allocates a DMA buffer (or two for full duplex devices)
-every time the audio device (/dev/dsp or /dev/audio) is opened
-and frees it when the device is closed. Size of this buffer is defined
-when the driver is configured (the last question). The buffer size
-can be redefined when loading the driver if required (note that this is 
-an optional feature which is not normally required). The buffer size
-is redefined by adding dma_pagesize= parameter to the insmod command line.
-For example:
-
-	insmod sound dma_buffsize=32768
-
-Minimum buffer size is 4096 and the maximum depends on the DMA channel. 
-For 8 bit channels (0 to 3) the limit is 64k and for 16 bit ones (5 to 7)
-it's 128k. Driver selects a suitable buffer size automatically in case
-you try to specify an invalid size.
-
-Q: What is the right DMA buffer size?
-
-A: It depends on the sampling rate, machine speed and the load of the system.
-Large buffers are required on slow machines, when recording/playing CD-quality
-audio or when there are other processes running on the same system. Also
-recording to hard disk is likely to require large buffers.
-
-Very small buffers are sufficient when you are just playing 8kHz audio files 
-on an empty P133 system. Using a 128k buffer just wastes 120k (or 250k)
-of valuable physical RAM memory. 
-
-The right buffer size can be easily found by making some experiments
-with the dma_buffsize= parameter. I use usually 16k buffers on a DX4/100 system
-and 64k on an old 386 system. 
-
-NOTE!	DMA buffers are used only by /dev/audio# and /dev/dsp# devices.
-	Other device files don't use them but there are two exceptions:
-	GUS driver uses DMA buffers when loading samples to the card.
-	Ensoniq SoundScape driver uses them when downloading the microcode
-	file (sndscape.co[012]) to the card. Using large buffers doesn't
-	increase performance in these cases.
-
-Debugging and tracing
----------------------
-
-Modularized sound driver doesn't display messages during initialization as
-the kernel compiled one does. This feature can be turned on by adding
-trace_init=1 to the insmod command line.
-
-For example:
-
-	insmod sound trace_init=1
+  The following information is current as of linux-2.1.85. Check the other
+readme files, especially Readme.cards, for information not specific to
+making sound modular.
+
+  First, configure your kernel. This is an idea of what you should be
+setting in the sound section:
+
+<M> Sound card support 
+
+<M> 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support 
+
+  I have SoundBlaster. Select your card from the list.
+
+<M> Generic OPL2/OPL3 FM synthesizer support 
+<M> FM synthesizer (YM3812/OPL-3) support 
+
+  If you don't set these, you will probably find you can play .wav files
+but not .midi. As the help for them says, set them unless you know your
+card does not use one of these chips for FM support.
+
+  Once you are configured, make zlilo, modules, modules_install; reboot.
+Note that it is no longer necessary or possible to configure sound in the
+drivers/sound dir. Now one simply configures and makes one's kernel and
+modules in the usual way.
+
+ Then, add to your /etc/modules.conf or /etc/conf.modules something like:
+
+alias char-major-14 sb
+post-install sb modprobe  "-k" "adlib_card"
+options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
+options adlib_card io=0x388     # FM synthetiser
+
+  The effect of this is that the sound driver and all necessary bits and
+pieces autoload on demand, assuming you use kerneld (a sound choice) and
+autoclean when not in use. Also, options for the device drivers are
+set. They will not work without them. Change as appropriate for your card.
+If you are not yet using the very cool kerneld, you will have to "modprobe
+-k sb" yourself to get things going. Eventually things may be fixed so
+that this kludgery is not necessary; for the time being, it seems to work
+well.
+
+  Replace 'sb' with the driver for your card, and give it the right
+options. To find the filename of the driver, look in
+/lib/modules/<kernel-version>/misc. Mine looks like:
+
+adlib_card.o # This is the generic OPLx driver
+opl3.o # The OPL3 driver
+sb.o # <<The SoundBlaster driver. Yours may differ.>>
+sound.o # The sound driver
+uart401.o # Used by sb, maybe other cards
+
+ Whichever card you have, try feeding it the options that would be the
+default if you were making the driver wired, not as modules. You can look
+at the init_module() code for the card to see what args are expected.
+
+ Note that at present there is no way to configure the io, irq and other
+parameters for the modular drivers as one does for the wired drivers.. One
+needs to pass the modules the necessary parameters as arguments, either
+with /etc/modules.conf or with command-line args to modprobe, e.g.
+
+modprobe -k sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
+modprobe -k adlib_card io=0x388
+
+ recommend using /etc/modules.conf.
+
+  I'm afraid I know nothing about anything but my setup, being more of a
+text-mode guy anyway. If you have options for other cards or other helpful
+hints, send them to me, Jim Bray, jb@as220.org, http://as220.org/jb.
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.1.86/linux/drivers/sound/dev_table.h	Tue Jan 20 16:44:57 1998
+++ linux/drivers/sound/dev_table.h	Sun Feb 15 12:10:12 1998
@@ -460,31 +460,31 @@
 struct card_info snd_installed_cards[] = 
 {
 #ifdef CONFIG_PSS
-	{SNDCARD_PSS, {PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE},
-#ifdef PSS_MPU_BASE
-	{SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_PSS, {CONFIG_PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_PSS_MPU_BASE
+	{SNDCARD_PSS_MPU, {CONFIG_PSS_MPU_BASE, CONFIG_PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
-#ifdef PSS_MSS_BASE
-	{SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_PSS_MSS_BASE
+	{SNDCARD_PSS_MSS, {CONFIG_PSS_MSS_BASE, CONFIG_PSS_MSS_IRQ, CONFIG_PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 #ifdef CONFIG_TRIX
-#ifndef TRIX_DMA2
-#define TRIX_DMA2 TRIX_DMA
+#ifndef CONFIG_TRIX_DMA2
+#define CONFIG_TRIX_DMA2 CONFIG_TRIX_DMA
 #endif
-	{SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA, TRIX_DMA2}, SND_DEFAULT_ENABLE},
-#ifdef TRIX_SB_BASE
-	{SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_TRXPRO, {CONFIG_TRIX_BASE, CONFIG_TRIX_IRQ, CONFIG_TRIX_DMA, CONFIG_TRIX_DMA2}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_TRIX_SB_BASE
+	{SNDCARD_TRXPRO_SB, {CONFIG_TRIX_SB_BASE, CONFIG_TRIX_SB_IRQ, CONFIG_TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
-#ifdef TRIX_MPU_BASE
-	{SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_TRIX_MPU_BASE
+	{SNDCARD_TRXPRO_MPU, {CONFIG_TRIX_MPU_BASE, CONFIG_TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 
 #ifdef CONFIG_OPL3SA1
-	{SNDCARD_OPL3SA1, {OPL3SA1_BASE, OPL3SA1_IRQ, OPL3SA1_DMA, OPL3SA1_DMA2}, SND_DEFAULT_ENABLE},
-#ifdef OPL3SA1_MPU_BASE
-	{SNDCARD_OPL3SA1_MPU, {OPL3SA1_MPU_BASE, OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_OPL3SA1, {CONFIG_OPL3SA1_BASE, CONFIG_OPL3SA1_IRQ, CONFIG_OPL3SA1_DMA, CONFIG_OPL3SA1_DMA2}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_OPL3SA1_MPU_BASE
+	{SNDCARD_OPL3SA1_MPU, {CONFIG_OPL3SA1_MPU_BASE, CONFIG_OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 
@@ -493,39 +493,39 @@
 #endif
 
 #ifdef CONFIG_SSCAPE
-	{SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
-	{SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_SSCAPE, {CONFIG_SSCAPE_BASE, CONFIG_SSCAPE_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_SSCAPE_MSS, {CONFIG_SSCAPE_MSS_BASE, CONFIG_SSCAPE_MSS_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
 #ifdef CONFIG_MAD16
-#ifndef MAD16_DMA2
-#define MAD16_DMA2 MAD16_DMA
+#ifndef CONFIG_MAD16_DMA2
+#define CONFIG_MAD16_DMA2 CONFIG_MAD16_DMA
 #endif
-	{SNDCARD_MAD16, {MAD16_BASE, MAD16_IRQ, MAD16_DMA, MAD16_DMA2}, SND_DEFAULT_ENABLE},
-#ifdef MAD16_MPU_BASE
-	{SNDCARD_MAD16_MPU, {MAD16_MPU_BASE, MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_MAD16, {CONFIG_MAD16_BASE, CONFIG_MAD16_IRQ, CONFIG_MAD16_DMA, CONFIG_MAD16_DMA2}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_MAD16_MPU_BASE
+	{SNDCARD_MAD16_MPU, {CONFIG_MAD16_MPU_BASE, CONFIG_MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 
 #ifdef CONFIG_CS4232
-#ifndef CS4232_DMA2
-#define CS4232_DMA2 CS4232_DMA
+#ifndef CONFIG_CS4232_DMA2
+#define CONFIG_CS4232_DMA2 CONFIG_CS4232_DMA
 #endif
-#ifdef CS4232_MPU_BASE
-	{SNDCARD_CS4232_MPU, {CS4232_MPU_BASE, CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_CS4232_MPU_BASE
+	{SNDCARD_CS4232_MPU, {CONFIG_CS4232_MPU_BASE, CONFIG_CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
-	{SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE},
+	{SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 
 
 #ifdef CONFIG_MSS
-#ifndef MSS_DMA2
-#define MSS_DMA2 -1
+#ifndef CONFIG_MSS_DMA2
+#define CONFIG_MSS_DMA2 -1
 #endif
 
 #ifdef DESKPROXL
-	{SNDCARD_DESKPROXL, {MSS_BASE, MSS_IRQ, MSS_DMA, MSS_DMA2}, SND_DEFAULT_ENABLE},
+	{SNDCARD_DESKPROXL, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE},
 #else
-	{SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, MSS_DMA2}, SND_DEFAULT_ENABLE},
+	{SNDCARD_MSS, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 #ifdef MSS2_BASE
 	{SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, MSS2_DMA2}, SND_DEFAULT_ENABLE},
@@ -534,53 +534,53 @@
 
 
 #ifdef CONFIG_PAS
-	{SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_PAS, {CONFIG_PAS_BASE, CONFIG_PAS_IRQ, CONFIG_PAS_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifdef CONFIG_SB
-#ifndef SBC_DMA
-#define SBC_DMA		1
+#ifndef CONFIG_SB_DMA
+#define CONFIG_SB_DMA		1
 #endif
-#ifndef SB_DMA2
-#define SB_DMA2		-1
+#ifndef CONFIG_SB_DMA2
+#define CONFIG_SB_DMA2		-1
 #endif
-	{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, SB_DMA2}, SND_DEFAULT_ENABLE},
+	{SNDCARD_SB, {CONFIG_SB_BASE, CONFIG_SB_IRQ, CONFIG_SB_DMA, CONFIG_SB_DMA2}, SND_DEFAULT_ENABLE},
 #ifdef SB2_BASE
 	{SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 #if defined(CONFIG_MAUI) 
-	{SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 
 #if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
-	{SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #ifdef MPU2_BASE
 	{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 #ifdef MPU3_BASE
-	{SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_MPU401, {MPU3_BASE, MPU3_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 
 #if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
-	{SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 
 #if defined(CONFIG_SB) 
-#if defined(CONFIG_MIDI) && defined(SB_MPU_BASE)
-	{SNDCARD_SB16MIDI,{SB_MPU_BASE, SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#if defined(CONFIG_MIDI) && defined(CONFIG_SB_MPU_BASE)
+	{SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 
 #ifdef CONFIG_GUS
-#ifndef GUS_DMA2
-#define GUS_DMA2 GUS_DMA
+#ifndef CONFIG_GUS_DMA2
+#define CONFIG_GUS_DMA2 CONFIG_GUS_DMA
 #endif
 #ifdef CONFIG_GUS16
-	{SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, -1}, SND_DEFAULT_ENABLE},
+	{SNDCARD_GUS16, {CONFIG_GUS16_BASE, CONFIG_GUS16_IRQ, CONFIG_GUS16_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
-	{SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA2}, SND_DEFAULT_ENABLE},
+	{SNDCARD_GUS, {CONFIG_GUS_BASE, CONFIG_GUS_IRQ, CONFIG_GUS_DMA, CONFIG_GUS_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 
 #if defined(CONFIG_YM3812) 
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/lowlevel/Config.tmpl linux/drivers/sound/lowlevel/Config.tmpl
--- v2.1.86/linux/drivers/sound/lowlevel/Config.tmpl	Tue Oct 28 02:10:48 1997
+++ linux/drivers/sound/lowlevel/Config.tmpl	Sun Feb 15 12:10:12 1998
@@ -14,10 +14,10 @@
          if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then
 	    comment 'Audio Excel DSP 16 [Sound Blaster Pro]'
             hex 'I/O base for Audio Excel DSP 16 220 or 240' \
-	                                           AEDSP16_BASE $SBC_BASE
+	                                           CONFIG_AEDSP16_BASE $CONFIG_SB_BASE
             int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \
-	                                           AEDSP16_SBC_IRQ $SBC_IRQ
-            int 'Audio Excel DSP 16 DMA 0, 1 or 3' AEDSP16_SBC_DMA $SBC_DMA
+	                                           CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ
+            int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA
          fi
       fi
    
@@ -25,10 +25,10 @@
          bool 'Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS
          if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then
 	    comment 'Audio Excel DSP 16 [Microsoft Sound System]'
-	    hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
+	    hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
             int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \
-	                                           AEDSP16_MSS_IRQ $MSS_IRQ
-            int 'Audio Excel DSP 16 DMA 0, 1 or 3' AEDSP16_MSS_DMA $MSS_DMA
+	                                           CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ
+            int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA
          fi
       fi
 
@@ -38,10 +38,10 @@
 	    comment 'Audio Excel DSP 16 [MPU-401]'
 	    if [ "$CONFIG_AEDSP16_SBPRO" != "y" \
 	         -a "$CONFIG_AEDSP16_MSS" != "y" ]; then
-	       hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220
+	       hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
 	    fi
             int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' \
-	    						AEDSP16_MPU_IRQ $MPU_IRQ
+	    						CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ
          fi
       fi
 
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/lowlevel/aedsp16.c linux/drivers/sound/lowlevel/aedsp16.c
--- v2.1.86/linux/drivers/sound/lowlevel/aedsp16.c	Sun Jan  4 10:40:16 1998
+++ linux/drivers/sound/lowlevel/aedsp16.c	Sun Feb 15 12:10:13 1998
@@ -33,7 +33,7 @@
  * Sanity checks
  */
 
-#if !defined(AEDSP16_BASE)
+#if !defined(CONFIG_AEDSP16_BASE)
 # undef CONFIG_AEDSP16
 #else
 # if defined(MODULE) && defined(CONFIG_AEDSP16_MODULE)
@@ -1181,8 +1181,8 @@
 	if (ae_config.init & INIT_MSS)
 		return FALSE;
 /*
- * We must check the AEDSP16_BASE region too because these are the I/O ports
- * to access card's control registers.
+ * We must check the CONFIG_AEDSP16_BASE region too because these are the I/O 
+ * ports to access card's control registers.
  */
 	if (!(ae_config.init & INIT_MPU401)) {
 		if (check_region(ae_config.base_io, IOBASE_REGION_SIZE)) {
@@ -1193,8 +1193,8 @@
 	}
 
 /*
- * We must allocate the AEDSP16_BASE region too because these are the I/O ports
- * to access card's control registers.
+ * We must allocate the CONFIG_AEDSP16_BASE region too because these are the 
+ * I/O ports to access card's control registers.
  */
 	if (!(ae_config.init & INIT_MPU401))
 		request_region(ae_config.base_io, IOBASE_REGION_SIZE,
@@ -1229,8 +1229,8 @@
 		return FALSE;
 
 /*
- * We must check the AEDSP16_BASE region too because these are the I/O ports
- * to access card's control registers.
+ * We must check the CONFIG_AEDSP16_BASE region too because these are the I/O 
+ * ports to access card's control registers.
  */
 	if (!(ae_config.init & (INIT_MSS | INIT_SBPRO))) {
 		if (check_region(ae_config.base_io, IOBASE_REGION_SIZE)) {
@@ -1271,19 +1271,19 @@
 	int initialized = FALSE;
 
 #if !defined(MODULE)
-	ae_config.base_io = AEDSP16_BASE;
+	ae_config.base_io = CONFIG_AEDSP16_BASE;
 #if defined(CONFIG_AEDSP16_SBPRO)
-	ae_config.irq = AEDSP16_SBC_IRQ;
-	ae_config.dma = AEDSP16_SBC_DMA;
+	ae_config.irq = CONFIG_AEDSP16_SB_IRQ;
+	ae_config.dma = CONFIG_AEDSP16_SB_DMA;
 #endif
 #if defined(CONFIG_AEDSP16_MSS)
-	ae_config.mss_base = MSS_BASE;
-	ae_config.irq = AEDSP16_MSS_IRQ;
-	ae_config.dma = AEDSP16_MSS_DMA;
+	ae_config.mss_base = CONFIG_MSS_BASE;
+	ae_config.irq = CONFIG_AEDSP16_MSS_IRQ;
+	ae_config.dma = CONFIG_AEDSP16_MSS_DMA;
 #endif
 #if defined(CONFIG_AEDSP16_MPU401)
-	ae_config.mpu_base = MPU_BASE;
-	ae_config.mpu_irq = AEDSP16_MPU_IRQ;
+	ae_config.mpu_base = CONFIG_MPU_BASE;
+	ae_config.mpu_irq = CONFIG_AEDSP16_MPU_IRQ;
 #endif
 #endif /* !MODULE */
 	DBG(("Initializing BASE[0x%x] IRQ[%d] DMA[%d] MIRQ[%d]\n",
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v2.1.86/linux/drivers/sound/maui.c	Tue Dec 23 13:52:02 1997
+++ linux/drivers/sound/maui.c	Sun Feb 15 12:10:13 1998
@@ -41,7 +41,7 @@
 static int      (*orig_load_patch) (int dev, int format, const char *addr,
 			      int offs, int count, int pmgr_flag) = NULL;
 
-#ifdef MAUI_HAVE_BOOT
+#ifdef CONFIG_MAUI_HAVE_BOOT
 #include "maui_boot.h"
 #else
 static unsigned char *maui_os = NULL;
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v2.1.86/linux/drivers/sound/pss.c	Tue Dec 30 10:59:17 1997
+++ linux/drivers/sound/pss.c	Sun Feb 15 12:10:13 1998
@@ -54,7 +54,7 @@
 
 #include "coproc.h"
 
-#ifdef PSS_HAVE_BOOT
+#ifdef CONFIG_PSS_HAVE_BOOT
 #include "pss_boot.h"
 #else
 static unsigned char *pss_synth = NULL;
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c
--- v2.1.86/linux/drivers/sound/softoss.c	Fri Jan 30 11:28:08 1998
+++ linux/drivers/sound/softoss.c	Sun Feb 15 12:10:13 1998
@@ -1503,14 +1503,14 @@
 	devc->bits = 16;
 	devc->max_playahead = 32;
 
-#ifdef SOFTOSS_RATE
-	devc->speed = SOFTOSS_RATE;
+#ifdef CONFIG_SOFTOSS_RATE
+	devc->speed = CONFIG_SOFTOSS_RATE;
 #else
 	devc->speed = 32000;
 #endif
 
-#ifdef SOFTOSS_VOICES
-	devc->default_max_voices = SOFTOSS_VOICES;
+#ifdef CONFIG_SOFTOSS_VOICES
+	devc->default_max_voices = CONFIG_SOFTOSS_VOICES;
 #else
 	devc->default_max_voices = 32;
 #endif
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h
--- v2.1.86/linux/drivers/sound/sound_config.h	Sat Nov 29 10:33:21 1997
+++ linux/drivers/sound/sound_config.h	Sun Feb 15 12:10:13 1998
@@ -12,7 +12,7 @@
 
 
 #include "local.h.master"
-
+#include <linux/config.h>
 #include "os.h"
 #include "soundvers.h"
 
@@ -43,20 +43,20 @@
 
 #define FM_MONO		0x388	/* This is the I/O address used by AdLib */
 
-#ifndef PAS_BASE
-#define PAS_BASE	0x388
+#ifndef CONFIG_PAS_BASE
+#define CONFIG_PAS_BASE	0x388
 #endif
 
-#if defined(SB16_DMA) && !defined(SB_DMA2)
-#  define SB_DMA2 SB16_DMA
+#if defined(CONFIG_SB16_DMA) && !defined(CONFIG_SB_DMA2)
+#  define CONFIG_SB_DMA2 CONFIG_SB16_DMA
 #endif
 
-#if defined(SB16MIDI_BASE) && !defined(SB_MPU_BASE)
-#   define SB_MPU_BASE SB16MIDI_BASE
+#if defined(SB16MIDI_BASE) && !defined(CONFIG_SB_MPU_BASE)
+#   define CONFIG_SB_MPU_BASE SB16MIDI_BASE
 #endif
 
-#ifndef SB_MPU_IRQ
-#  define SB_MPU_IRQ SBC_IRQ
+#ifndef CONFIG_SB_MPU_IRQ
+#  define CONFIG_SB_MPU_IRQ CONFIG_SB_IRQ
 #endif
 
 /* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v2.1.86/linux/drivers/sound/sscape.c	Thu Feb 12 20:56:10 1998
+++ linux/drivers/sound/sscape.c	Sun Feb 15 12:10:13 1998
@@ -964,7 +964,7 @@
 	}
 	if (mpu_irq == -1 && mpu_io != -1)
 	{
-		  printk(KERN_ERR "MPU_IRQ must be specified if MPU_IO is set.\n");
+		  printk(KERN_ERR "CONFIG_MPU_IRQ must be specified if CONFIG_MPU_IO is set.\n");
 		  return -EINVAL;
 	}
 	config.irq = irq;
diff -u --recursive --new-file v2.1.86/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.1.86/linux/drivers/sound/trix.c	Tue Dec 23 13:52:02 1997
+++ linux/drivers/sound/trix.c	Sun Feb 15 12:10:13 1998
@@ -27,7 +27,7 @@
 #endif
 #endif
 
-#ifdef TRIX_HAVE_BOOT
+#ifdef CONFIG_TRIX_HAVE_BOOT
 #include "trix_boot.h"
 #else
 static unsigned char *trix_boot = NULL;
@@ -506,12 +506,12 @@
 
 	if (sb_io != -1 && (sb_irq == -1 || sb_dma == -1))
 	  {
-		  printk(KERN_INFO "SB_IRQ and SB_DMA must be specified if SB_IO is set.\n");
+		  printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n");
 		  return -EINVAL;
 	  }
 	if (mpu_io != -1 && mpu_irq == -1)
 	  {
-		  printk(KERN_INFO "MPU_IRQ must be specified if MPU_IO is set.\n");
+		  printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n");
 		  return -EINVAL;
 	  }
 	if (!trix_boot)
diff -u --recursive --new-file v2.1.86/linux/fs/adfs/super.c linux/fs/adfs/super.c
--- v2.1.86/linux/fs/adfs/super.c	Tue Jan 20 16:44:58 1998
+++ linux/fs/adfs/super.c	Wed Feb 11 16:19:56 1998
@@ -331,11 +331,7 @@
 #ifdef MODULE
 int init_module (void)
 {
-	int status;
-
-	if ((status = init_adfs_fs()) == 0)
-		register_symtab(0);
-	return status;
+	return (init_adfs_fs());
 }
 
 void cleanup_module (void)
diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c
--- v2.1.86/linux/fs/ufs/ufs_dir.c	Sat Nov  8 09:52:02 1997
+++ linux/fs/ufs/ufs_dir.c	Thu Feb 12 16:27:15 1998
@@ -8,6 +8,9 @@
  *
  * swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
  *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
  */
 
 #include <linux/fs.h>
@@ -28,17 +31,18 @@
 	struct ufs_direct * de;
 	struct super_block * sb;
 	int de_reclen;
-	__u32 s_flags, bytesex;
+	__u32 flags;
 
-	/* Isn't that already done but the upper layer??? */
+	/* Isn't that already done in the upper layer???
+         * the VFS layer really needs some explicit documentation!
+         */
 	if (!inode || !S_ISDIR(inode->i_mode))
 		return -EBADF;
 
 	sb = inode->i_sb;
-        s_flags = sb->u.ufs_sb.s_flags;
-        bytesex = s_flags & UFS_BYTESEX;
+        flags = sb->u.ufs_sb.s_flags;
 
-	if (s_flags & UFS_DEBUG) {
+	if (flags & UFS_DEBUG) {
 	        printk("ufs_readdir: ino %lu  f_pos %lu\n",
 	               inode->i_ino, (unsigned long) filp->f_pos);
 	        ufs_print_inode(inode);
@@ -92,20 +96,23 @@
 		       && offset < sb->s_blocksize) {
 			de = (struct ufs_direct *) (bh->b_data + offset);
 	                /* XXX - put in a real ufs_check_dir_entry() */
-	                if ((de->d_reclen == 0) || (de->d_namlen == 0)) {
+	                if ((de->d_reclen == 0) || (NAMLEN(de) == 0)) {
 			/* SWAB16() was unneeded -- compare to 0 */
-	                        filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize;
+	                        filp->f_pos = (filp->f_pos &
+				              (sb->s_blocksize - 1)) +
+				               sb->s_blocksize;
 	                        brelse(bh);
 	                        return stored;
 	                }
-#if 0
+#if 0 /* XXX */
 			if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
 			/* XXX - beware about de having to be swabped somehow */
 						   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;
+				filp->f_pos = (filp->f_pos &
+				              (sb->s_blocksize - 1)) +
+					       sb->s_blocksize;
 				brelse (bh);
 				return stored;
 			}
@@ -121,11 +128,12 @@
 				 * during the copy operation. */
 				unsigned long version = inode->i_version;
 
-	                        if (s_flags & UFS_DEBUG) {
+	                        if (flags & UFS_DEBUG) {
 	                                printk("ufs_readdir: filldir(%s,%u)\n",
 	                                       de->d_name, SWAB32(de->d_ino));
 	                        }
-				error = filldir(dirent, de->d_name, SWAB16(de->d_namlen), filp->f_pos, SWAB32(de->d_ino));
+				error = filldir(dirent, de->d_name, NAMLEN(de),
+				                filp->f_pos, SWAB32(de->d_ino));
 				if (error)
 					break;
 				if (version != inode->i_version)
diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- v2.1.86/linux/fs/ufs/ufs_inode.c	Tue Oct 21 05:26:13 1997
+++ linux/fs/ufs/ufs_inode.c	Thu Feb 12 16:27:15 1998
@@ -9,8 +9,18 @@
  * Clean swab support on 19970406
  * by Francois-Rene Rideau <rideau@ens.fr>
  *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
  */
 
+#undef DEBUG_UFS_INODE
+/*#define DEBUG_UFS_INODE 1*/
+/* Uncomment the line above when hacking ufs inode code */
+
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 #include <linux/sched.h>
@@ -25,29 +35,30 @@
 	       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.i_data[0], inode->u.ufs_i.i_data[1],
-		inode->u.ufs_i.i_data[2], inode->u.ufs_i.i_data[3],
-		inode->u.ufs_i.i_data[4], inode->u.ufs_i.i_data[5],
-		inode->u.ufs_i.i_data[6], inode->u.ufs_i.i_data[7],
-		inode->u.ufs_i.i_data[8], inode->u.ufs_i.i_data[9],
-		inode->u.ufs_i.i_data[10], inode->u.ufs_i.i_data[11]);
+		inode->u.ufs_i.i_u1.i_data[0], inode->u.ufs_i.i_u1.i_data[1],
+		inode->u.ufs_i.i_u1.i_data[2], inode->u.ufs_i.i_u1.i_data[3],
+		inode->u.ufs_i.i_u1.i_data[4], inode->u.ufs_i.i_u1.i_data[5],
+		inode->u.ufs_i.i_u1.i_data[6], inode->u.ufs_i.i_u1.i_data[7],
+		inode->u.ufs_i.i_u1.i_data[8], inode->u.ufs_i.i_u1.i_data[9],
+		inode->u.ufs_i.i_u1.i_data[10], inode->u.ufs_i.i_u1.i_data[11]);
 	printk("  gen 0x%8.8x ib <0x%x 0x%x 0x%x>\n",
 		inode->u.ufs_i.i_gen,
-		inode->u.ufs_i.i_data[UFS_IND_BLOCK],
-		inode->u.ufs_i.i_data[UFS_DIND_BLOCK],
-		inode->u.ufs_i.i_data[UFS_TIND_BLOCK]);
+		inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK],
+		inode->u.ufs_i.i_u1.i_data[UFS_DIND_BLOCK],
+		inode->u.ufs_i.i_u1.i_data[UFS_TIND_BLOCK]);
 }
 
-#define inode_bmap(inode, nr) ((inode)->u.ufs_i.i_data[(nr)])
+#define inode_bmap(inode, nr) ((inode)->u.ufs_i.i_u1.i_data[(nr)])
 
 static inline int block_bmap (struct inode *inode, int block, int nr)
 {
 	struct buffer_head *bh;
 	int tmp;
-	__u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
+	__u32 flags = inode->i_sb->u.ufs_sb.s_flags;
 	/* XXX Split in fsize big blocks (Can't bread 8Kb). */ 
 	tmp = nr >> (inode->i_sb->u.ufs_sb.s_fshift - 2);
-	bh = bread (inode->i_dev, block + tmp, inode->i_sb->u.ufs_sb.s_fsize);
+	bh = bread (inode->i_dev, inode->i_sb->u.ufs_sb.s_blockbase + block +
+	            tmp, inode->i_sb->s_blocksize);
 	if (!bh)
 		return 0;
 	nr &= ~(inode->i_sb->u.ufs_sb.s_fmask) >> 2;
@@ -75,13 +86,16 @@
 		return 0;
 	}
 	if (lbn < UFS_NDADDR)
-		return ufs_dbn (inode->i_sb, inode_bmap (inode, lbn), boff);
+		return (inode->i_sb->u.ufs_sb.s_blockbase +
+			ufs_dbn (inode->i_sb, inode_bmap (inode, lbn), boff));
 	lbn -= UFS_NDADDR;
 	if (lbn < addr_per_block) {
 		i = inode_bmap (inode, UFS_IND_BLOCK);
 		if (!i)
 			return 0;
-		return ufs_dbn (inode->i_sb, block_bmap (inode, i, lbn), boff);
+		return (inode->i_sb->u.ufs_sb.s_blockbase +
+			ufs_dbn (inode->i_sb,
+				block_bmap (inode, i, lbn), boff));
 	}
 	lbn -= addr_per_block;
 	if (lbn < (1 << (addr_per_block_bits * 2))) {
@@ -91,9 +105,10 @@
 		i = block_bmap (inode, i, lbn >> addr_per_block_bits);
 		if (!i)
 			return 0;
-		return ufs_dbn (inode->i_sb,
+		return (inode->i_sb->u.ufs_sb.s_blockbase +
+			ufs_dbn (inode->i_sb,
 				block_bmap (inode, i, lbn & (addr_per_block-1)),
-				boff);
+				boff));
 	}
 	lbn -= (1 << (addr_per_block_bits * 2));
 	i = inode_bmap (inode, UFS_TIND_BLOCK);
@@ -106,8 +121,9 @@
 			(lbn >> addr_per_block_bits) & (addr_per_block - 1));
 	if (!i)
 		return 0;
-	return ufs_dbn (inode->i_sb,
-			block_bmap (inode, i, lbn & (addr_per_block-1)), boff);
+	return (inode->i_sb->u.ufs_sb.s_blockbase +
+		ufs_dbn (inode->i_sb,
+			block_bmap (inode, i, lbn & (addr_per_block-1)), boff));
 }
 
 /* XXX - ufs_read_inode is a mess */
@@ -116,28 +132,30 @@
 	struct super_block * sb;
 	struct ufs_inode * ufsip;
 	struct buffer_head * bh;
-	__u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
+	__u32 flags = inode->i_sb->u.ufs_sb.s_flags;
 
 	sb = inode->i_sb;
 
 	if (ufs_ino_ok(inode)) {
-	        printk("ufs_read_inode: bad inum %lu", inode->i_ino);
+	        printk("ufs_read_inode: bad inum %lu\n", inode->i_ino);
 
 	        return;
 	}
 
-#if 0
+#ifdef DEBUG_UFS_INODE
 	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,
+	           inode->i_sb->u.ufs_sb.s_blockbase +
 	           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);
+	           (inode->i_ino%sb->u.ufs_sb.s_ipg)/
+	           (sb->u.ufs_sb.s_inopb/sb->u.ufs_sb.s_fsfrag),
+	           sb->s_blocksize);
 	if (!bh) {
-	        printk("ufs_read_inode: can't read inode %lu from dev %d/%d",
+	        printk("ufs_read_inode: can't read inode %lu from dev %d/%d\n",
 	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
 	        return;
 	}
@@ -176,23 +194,21 @@
 	 * random users can't get at these files, since they get dynamically
 	 * "chown()ed" to root.
 	 */
-	if (SWAB16(ufsip->ui_suid) == UFS_USEEFT) {
-	        /* EFT */
+	if (UFS_UID(ufsip) >= UFS_USEEFT) {
 	        inode->i_uid = 0;
 	        printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n",
-	               SWAB32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
-	               inode->i_uid);
+	               UFS_UID(ufsip), inode->i_ino, MAJOR(inode->i_dev),
+	               MINOR(inode->i_dev), inode->i_uid);
 	} else {
-	        inode->i_uid = SWAB16(ufsip->ui_suid);
+	        inode->i_uid = UFS_UID(ufsip);
 	}
-	if (SWAB16(ufsip->ui_sgid) == UFS_USEEFT) {
-	        /* EFT */
+	if (UFS_GID(ufsip) >= UFS_USEEFT) {
 	        inode->i_gid = 0;
 	        printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n",
-	               SWAB32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev),
-	               inode->i_gid);
+	               UFS_GID(ufsip), inode->i_ino, MAJOR(inode->i_dev),
+	               MINOR(inode->i_dev), inode->i_gid);
 	} else {
-	        inode->i_gid = SWAB16(ufsip->ui_sgid);
+	        inode->i_gid = UFS_GID(ufsip);
 	}
 
 	/*
@@ -249,13 +265,19 @@
 	    S_ISLNK(inode->i_mode)) {
 	        int i;
 
-	        for (i = 0; i < UFS_NDADDR; i++) {
-	                inode->u.ufs_i.i_data[i] = SWAB32(ufsip->ui_db[i]);
-	        }
-	        for (i = 0; i < UFS_NINDIR; i++) {
-	                inode->u.ufs_i.i_data[UFS_IND_BLOCK + i] =
-							SWAB32(ufsip->ui_ib[i]);
-	        }
+		if (inode->i_blocks) {
+		        for (i = 0; i < UFS_NDADDR; i++) {
+		                inode->u.ufs_i.i_u1.i_data[i] =
+				       SWAB32(ufsip->ui_u2.ui_addr.ui_db[i]);
+		        }
+		        for (i = 0; i < UFS_NINDIR; i++) {
+		                inode->u.ufs_i.i_u1.i_data[UFS_IND_BLOCK + i] =
+				       SWAB32(ufsip->ui_u2.ui_addr.ui_ib[i]);
+	        	}
+		} else /* fast symlink */ {
+			memcpy(inode->u.ufs_i.i_u1.i_symlink,
+			       ufsip->ui_u2.ui_symlink, 60);
+		}
 	}
 
 	/* KRR - I need to check the SunOS header files, but for the time
@@ -265,17 +287,15 @@
 	 * the code.
 	 */
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
-	  inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_db);
+	  inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_u2.ui_addr.ui_db);
 	}
 
-	/* XXX - implement fast and slow symlinks */
-
 	inode->u.ufs_i.i_flags = SWAB32(ufsip->ui_flags);
 	inode->u.ufs_i.i_gen = SWAB32(ufsip->ui_gen); /* XXX - is this i_version? */
-	inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_shadow); /* XXX */
-	inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_uid);
-	inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_gid);
-	inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_oeftflag);
+	inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_u3.ui_sun.ui_shadow); /* XXX */
+	inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_u3.ui_sun.ui_uid);
+	inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_u3.ui_sun.ui_gid);
+	inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_u3.ui_sun.ui_oeftflag);
 
 	brelse(bh);
 
diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_namei.c linux/fs/ufs/ufs_namei.c
--- v2.1.86/linux/fs/ufs/ufs_namei.c	Thu Dec  4 01:27:48 1997
+++ linux/fs/ufs/ufs_namei.c	Fri Feb 13 11:11:29 1998
@@ -9,6 +9,9 @@
  * Clean swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406
  * Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109
  *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
  */
 
 #include <linux/fs.h>
@@ -17,20 +20,21 @@
 #include "ufs_swab.h"
 
 /*
- * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
- * stolen from ext2fs
+ * NOTE1: unlike strncmp, ufs_match returns 1 for success, 0 for failure
+ * (stolen from ext2fs.)
+ * NOTE2: flags *is* used, though this is hidden by macros like NAMLEN.
  */
-static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 bytesex)
+static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 flags)
 {
 	if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */
 		return 0;
 	/*
 	 * "" means "." ---> so paths like "/usr/lib//libc.a" work
 	 */
-	if (!len && (SWAB16(d->d_namlen) == 1) && (d->d_name[0] == '.') &&
+	if (!len && (NAMLEN(d) == 1) && (d->d_name[0] == '.') &&
   	   (d->d_name[1] == '\0'))
   		return 1;
-	if (len != SWAB16(d->d_namlen))
+	if (len != NAMLEN(d))
 		return 0;
 	return !memcmp(name, d->d_name, len);
 }
@@ -38,89 +42,88 @@
 int ufs_lookup (struct inode *dir, struct dentry *dentry)
 {
   /* XXX - this is all fucked up! */
-  /* XXX - and it's been broken since linux has this new dentry interface:
-   * allows reading of files, but screws the whole dcache, even outside
-   * of the ufs partition, so that umount'ing won't suffice to fix it --
-   * reboot needed
-   */
 	unsigned long int lfragno, fragno;
 	struct buffer_head * bh;
 	struct ufs_direct * d;
+	struct super_block * sb = dir->i_sb;
 	const char *name = dentry->d_name.name;
 	int len = dentry->d_name.len;
-	__u32 bytesex;
+	__u32 flags;
         struct inode *inode;
 
 	/* XXX - isn't that already done by the upper layer? */
         if (!dir || !S_ISDIR(dir->i_mode))
 		return -EBADF;
 
-	bytesex = dir->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX;
+	flags = sb->u.ufs_sb.s_flags;
 
-	if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG)
+	if (flags & UFS_DEBUG)
 		printk("Passed name: %s\nPassed length: %d\n", name, len);
 
-
 	/* debugging hacks:
 	 * 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;
+	        sb->u.ufs_sb.s_flags ^= UFS_DEBUG;
 	        printk("UFS debugging %s\n",
-	               (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
+	               (sb->u.ufs_sb.s_flags & UFS_DEBUG) ?
 	               "on": "off");
 		goto not_found;
 	        /*return(-ENOENT);*/
 	}
 
 	/*
-	 * Touching /xyzzy.i in a filesystem toggles debugging for ufs_inode.c.
+	 * 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;
+	        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) ?
+	               (sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ?
 	               "on": "off");
 		goto not_found;
 	        /*return(-ENOENT);*/
 	}
 
+	/*
+	 * Touching /xyzzy.n in a filesystem toggles debugging for ufs_namei.c
+	 */
 	if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) &&
 	    (dir->i_ino == UFS_ROOTINO)) {
-	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_NAMEI;
+	        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) ?
+	               (sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ?
 	               "on": "off");
 		goto not_found;
 	        /*return(-ENOENT);*/
 	}
 
+	/*
+	 * Touching /xyzzy.l in a filesystem toggles debugging for ufs_symlink.c
+	 */
 	if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) &&
 	    (dir->i_ino == UFS_ROOTINO)) {
-	        dir->i_sb->u.ufs_sb.s_flags ^= UFS_DEBUG_LINKS;
+	        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) ?
+	               (sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ?
 	               "on": "off");
 		goto not_found;
 	        /*return(-ENOENT);*/
 	}
 
-
 	/* Now for the real thing */
 
-	if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) {
+ 	if (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++) {
+ 	for (lfragno = 0; lfragno < dir->i_blocks; lfragno++) {
 	        fragno = ufs_bmap(dir, lfragno);
+ 		/* ufs_bmap() reads the block (frag) size in s_blocksize */
 	        /* 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) {
+ 	        if (flags & UFS_DEBUG) {
 	                printk("ufs_lookup: ino %lu lfragno %lu  fragno %lu\n",
 	                       dir->i_ino, lfragno, fragno);
 	        }
@@ -129,7 +132,7 @@
 			goto not_found;
 			/*return(-ENOENT);*/
 	        }
-	        bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize);
+	        bh = bread(dir->i_dev, fragno, sb->s_blocksize);
 	        if (bh == NULL) {
 	                printk("ufs_lookup: bread failed: "
                                "ino %lu, lfragno %lu",
@@ -138,17 +141,17 @@
 	        }
 	        d = (struct ufs_direct *)(bh->b_data);
 	        while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <=
-	               dir->i_sb->s_blocksize) {
+	               sb->s_blocksize) {
 	                /* XXX - skip block if d_reclen or d_namlen is 0 */
-	                if ((d->d_reclen == 0) || (d->d_namlen == 0)) {
+	                if ((d->d_reclen == 0) || (NAMLEN(d) == 0)) {
 			/* no need to SWAB16(): test against 0 */
-	                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                        if (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) {
+	                if (flags & UFS_DEBUG) {
 	                        printk("lfragno 0x%lx  "
 					"direct d 0x%x  "
 					"d_ino %u  "
@@ -158,30 +161,31 @@
 				        (unsigned int)((unsigned long)d),
 					SWAB32(d->d_ino),
 					SWAB16(d->d_reclen),
-					SWAB16(d->d_namlen),d->d_name);
+					NAMLEN(d),d->d_name);
 	                }
-	                if ((SWAB16(d->d_namlen) == len) &&
+	                if ((NAMLEN(d) == len) &&
 	                    /* XXX - don't use strncmp() - see ext2fs */
-	                    (ufs_match(len, name, d, bytesex))) {
+	                    (ufs_match(len, name, d, flags))) {
 	                        /* We have a match */
 /* XXX - I only superficially understand how things work,
  * so use at your own risk... -- Fare'
  */
-				inode = iget(dir->i_sb, SWAB32(d->d_ino));
+				inode = iget(sb, SWAB32(d->d_ino));
 				brelse(bh);
 				if(!inode) { return -EACCES; }
                                 d_add(dentry,inode);
 	                        return(0);
 	                } else {
 	                        /* XXX - bounds checking */
-	                        if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
+	                        if (flags & UFS_DEBUG) {
 	                                printk("ufs_lookup: "
 						"wanted (%s,%d) got (%s,%d)\n",
 	                                       name, len,
-					       d->d_name, SWAB16(d->d_namlen));
+					       d->d_name, NAMLEN(d));
 	                        }
 	                }
-			d = (struct ufs_direct *)((char *)d + SWAB16(d->d_reclen));
+			d = (struct ufs_direct *)((char *)d +
+			     SWAB16(d->d_reclen));
 	        }
 	        brelse(bh);
 	}
diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
--- v2.1.86/linux/fs/ufs/ufs_super.c	Fri Dec  5 07:20:44 1997
+++ linux/fs/ufs/ufs_super.c	Thu Feb 12 16:27:15 1998
@@ -19,8 +19,19 @@
  *
  * Clean swab support on 19970406 by
  * Francois-Rene Rideau <rideau@ens.fr>
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
  */
 
+#undef DEBUG_UFS_SUPER
+/*#define DEBUG_UFS_SUPER 1*/
+/* Uncomment the line above when hacking ufs superblock code */
+
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -42,7 +53,7 @@
 	NULL,			/* XXX - ufs_write_inode() */
 	ufs_put_inode,
 	NULL,			/* XXX - ufs_delete_inode() */
-	NULL,			/* notify_change() */
+	NULL,			/* XXX - notify_change() */
 	ufs_put_super,
 	NULL,			/* XXX - ufs_write_super() */
 	ufs_statfs,
@@ -89,23 +100,26 @@
 		kdevname(sb->s_dev), function, error_buf);
 }
 
-#if 0 /* unused */
+#ifdef DEBUG_UFS_SUPER
 static void
 ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
 {
+	__u32 flags = sb->u.ufs_sb.s_flags;
 
 	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_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_fsize:  0x%8.8x\n", usb->fs_fsize);
+	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);
+	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_clean:  0x%8.8x\n", usb->fs_clean);
+	printk("fs_state:  0x%8.8x\n", UFS_STATE(usb));
+	printk("fs_magic:  0x%8.8x\n", usb->fs_magic);
+	printk("fs_fsmnt:  `%s'\n", usb->fs_fsmnt);
 
 	return;
 }
@@ -116,7 +130,9 @@
 {
 	struct ufs_superblock * usb;	/* normalized to local byteorder */
 	struct buffer_head * bh1, *bh2;
-	__u32 bytesex = 0;
+	__u32 flags = UFS_DEBUG_INITIAL; /* for sb->u.ufs_sb.s_flags */
+	static int offsets[] = { 0, 96, 160 };	/* different superblock locations */
+	int i;
 
 	/* sb->s_dev and sb->s_flags are set by our caller
 	 * data is the mystery argument to sys_mount()
@@ -127,102 +143,137 @@
 
 	MOD_INC_USE_COUNT;
 	lock_super (sb);
+	set_blocksize (sb->s_dev, BLOCK_SIZE);
 
 	/* 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))) {
-		brelse(bh1);
-	        printk ("ufs_read_super: unable to read superblock\n");
+	for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
+		if (!(bh1 = bread(sb->s_dev, offsets[i] + UFS_SBLOCK/BLOCK_SIZE,
+		            BLOCK_SIZE)) ||
+		    !(bh2 = bread(sb->s_dev, offsets[i] +
+		            UFS_SBLOCK/BLOCK_SIZE + 1, BLOCK_SIZE))) {
+			brelse(bh1);
+		        printk ("ufs_read_super: unable to read superblock\n");
+			goto ufs_read_super_lose;
+		}
+		/* XXX - redo this so we can free it later... */
+		usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL);
+		if (usb == NULL) {
+			brelse(bh1);
+			brelse(bh2);
+		        printk ("ufs_read_super: get_free_page() failed\n");
+			goto ufs_read_super_lose;
+		}
+
+		memcpy((char *)usb, bh1->b_data, BLOCK_SIZE);
+		memcpy((char *)usb + BLOCK_SIZE, bh2->b_data,
+		       sizeof(struct ufs_superblock) - BLOCK_SIZE);
 
-		goto ufs_read_super_lose;
-	}
-	/* XXX - redo this so we can free it later... */
-	usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL);
-	if (usb == NULL) {
 		brelse(bh1);
 		brelse(bh2);
-	        printk ("ufs_read_super: get_free_page() failed\n");
 
-		goto ufs_read_super_lose;
-	}
-
-	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);
-
-	switch (le32_to_cpup(&usb->fs_magic)) {
-		case UFS_MAGIC:
-			bytesex = UFS_LITTLE_ENDIAN;
-			ufs_superblock_le_to_cpus(usb);
-			break;
-		case UFS_CIGAM:
-			bytesex = UFS_BIG_ENDIAN;
-			ufs_superblock_be_to_cpus(usb);
-			break;
-			/* usb is now normalized to local byteorder */
-		default:
-	                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));
-			goto ufs_read_super_lose;
+		switch (le32_to_cpup(&usb->fs_magic)) {
+			case UFS_MAGIC:
+				flags |= UFS_LITTLE_ENDIAN;
+				ufs_superblock_le_to_cpus(usb);
+				goto found;
+			case UFS_CIGAM:
+				flags |= UFS_BIG_ENDIAN;
+				ufs_superblock_be_to_cpus(usb);
+				goto found;
+				/* usb is now normalized to local byteorder */
+			default:
+		}
 	}
-
+	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));
+	goto ufs_read_super_lose;
+found:
+#ifdef DEBUG_UFS_SUPER
+	printk("ufs_read_super: superblock offset 0x%2.2x\n", offsets[i]);
+#endif
 	/* 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);
+	if ((usb->fs_bsize != 4096) && (usb->fs_bsize != 8192)) {
+	        printk("ufs_read_super: invalid fs_bsize = %d\n",
+	               usb->fs_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);
+	if ((usb->fs_fsize != 512) && (usb->fs_fsize != 1024)) {
+	        printk("ufs_read_super: invalid fs_fsize = %d\n",
+	               usb->fs_fsize);
 	        goto ufs_read_super_lose;
 	}
+	if (usb->fs_fsize != BLOCK_SIZE) {
+		set_blocksize (sb->s_dev, usb->fs_fsize);
+	}
 
+	flags |= UFS_VANILLA;
+	/* XXX more consistency check */
 #ifdef DEBUG_UFS_SUPER
-	printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt);
+	printk("ufs_read_super: maxsymlinklen 0x%8.8x\n",
+	        usb->fs_u.fs_44.fs_maxsymlinklen);
 #endif
+	if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) {
+        	if (usb->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) {
+                	flags |= UFS_44BSD;
+                } else {
+                	flags |= UFS_OLD;	/* 4.2BSD */
+                }
+	} else if (offsets[i] > 0) {
+		flags |= UFS_NEXT;
+	} else {
+		flags |= UFS_SUN;
+	}
 
-	if (usb->fs_state == UFS_FSOK - usb->fs_time) {
-	        switch(usb->fs_clean) {
-	                case UFS_FSCLEAN:
 #ifdef DEBUG_UFS_SUPER
-	                  printk("ufs_read_super: fs is clean\n");
+	ufs_print_super_stuff(sb, usb);
+#endif
+	if (    ((flags&UFS_ST_MASK)==UFS_ST_44BSD)
+             || ((flags&UFS_ST_MASK)==UFS_ST_OLD)
+             || ((flags&UFS_ST_MASK)==UFS_ST_NEXT)
+             || ( ((flags&UFS_ST_MASK)==UFS_ST_SUN)
+                  && UFS_STATE(usb) == UFS_FSOK - usb->fs_time)) {
+		switch(usb->fs_clean) {
+			case UFS_FSACTIVE:	/* 0x00 */
+				printk("ufs_read_super: fs is active\n");
+				sb->s_flags |= MS_RDONLY;
+				break;
+			case UFS_FSCLEAN:	/* 0x01 */
+#ifdef DEBUG_UFS_SUPER
+				printk("ufs_read_super: fs is clean\n");
+#endif
+				break;
+			case UFS_FSSTABLE:	/* 0x02 */
+#ifdef DEBUG_UFS_SUPER
+				printk("ufs_read_super: fs is stable\n");
 #endif
-	                  break;
-	                case UFS_FSSTABLE:
+				break;
+			case UFS_FSOSF1:	/* 0x03 */
+				/* XXX is this correct for DEC OSF/1? */
 #ifdef DEBUG_UFS_SUPER
-	                  printk("ufs_read_super: fs is stable\n");
+				printk("ufs_read_super: fs is clean and stable (OSF/1)\n");
 #endif
-	                  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;
-	        }
+				break;
+			case UFS_FSBAD:		/* 0xFF */
+				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) */
+		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 */
@@ -238,7 +289,7 @@
 	/* 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 = bytesex | UFS_DEBUG_INITIAL ;
+	sb->u.ufs_sb.s_flags = flags ;
 	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;
@@ -257,6 +308,7 @@
 	sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask)
 					>> usb->fs_fshift);
 	sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */
+	sb->u.ufs_sb.s_blockbase = offsets[i];
 	sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
 
 #ifdef DEBUG_UFS_SUPER
@@ -271,6 +323,7 @@
 
 ufs_read_super_lose:
 	/* XXX - clean up */
+	set_blocksize (sb->s_dev, BLOCK_SIZE);
 	sb->s_dev = 0;
 	unlock_super (sb);
 	MOD_DEC_USE_COUNT;
@@ -285,6 +338,7 @@
 
 	lock_super (sb);
 	/* XXX - sync fs data, set state to ok, and flush buffers */
+	set_blocksize (sb->s_dev, BLOCK_SIZE);
 	sb->s_dev = 0;
 
 	/* XXX - free allocated kernel memory */
diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_swab.c linux/fs/ufs/ufs_swab.c
--- v2.1.86/linux/fs/ufs/ufs_swab.c	Fri Jan 30 11:28:09 1998
+++ linux/fs/ufs/ufs_swab.c	Thu Feb 12 16:27:15 1998
@@ -36,6 +36,10 @@
  *   2) instead of byteswapping, use [bl]e_to_cpu:
  *     it might be that we run on a VAX!
  *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
  * HOWTO continue adding swab support:
  *	basically, anywhere metadata is bread() (i.e. mapped to block device),
  *      data should either be SWAB()ed on the fly,
@@ -106,33 +110,69 @@
 
 /*
  * Here are the whole-structure swabping routines...
+ * They were fun to design, but I don't understand why we
+ * need a copy of the superblock, anyway. -- Fare'
  */
 
 extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb) {
 #ifndef __BIG_ENDIAN
+	__u16 sb_type = 1;	/* SUN type superblock */
+
+	if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0)
+		sb_type = 0;	/* 4.4BSD (FreeBSD) type superblock */
+ 
 	be32_to_cpus__between(*usb,fs_link,fs_fmod);
         /* XXX - I dunno what to do w/ fs_csp,
          * but it is unused by the current code, so that's ok for now.
          */
 	be32_to_cpus(&usb->fs_cpc);
-        be16_to_cpus__between(*usb,fs_opostbl,fs_sparecon);
-        be32_to_cpus__between(*usb,fs_sparecon,fs_qbmask);
-        be64_to_cpus((__u64 *) &usb->fs_qbmask);
-        be64_to_cpus((__u64 *) &usb->fs_qfmask);
+	if (sb_type) {
+        	be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon);
+        	be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask);
+                /* Might fail on strictly aligning 64-bit big-endian
+                 * architectures. Ouch!
+                 */
+        	be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask);
+        	be64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask);
+	} else {
+        	be16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon);
+        	be32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize);
+        	be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize);
+        	be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask);
+        	be64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask);
+        	be32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state);
+	}
 	be32_to_cpus__between(*usb,fs_postblformat,fs_magic);
 #endif
 }
 extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb) {
 #ifndef __LITTLE_ENDIAN
+	__u16 sb_type = 1;	/* SUN type superblock */
+
+	if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0)
+		sb_type = 0;	/* 4.4BSD (FreeBSD) type superblock */
+ 
 	le32_to_cpus__between(*usb,fs_link,fs_fmod);
         /* XXX - I dunno what to do w/ fs_csp,
          * but it is unused by the current code, so that's ok for now.
          */
 	le32_to_cpus(&usb->fs_cpc);
-        le16_to_cpus__between(*usb,fs_opostbl,fs_sparecon);
-        le32_to_cpus__between(*usb,fs_sparecon,fs_qbmask);
-        le64_to_cpus(&usb->fs_qbmask);
-        le64_to_cpus(&usb->fs_qfmask);
+	if (sb_type) {
+        	le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_sun.fs_sparecon);
+        	le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_sun.fs_qbmask);
+                /* Might fail on strictly aligning 64-bit big-endian
+                 * architectures. Ouch!
+                 */
+        	le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qbmask);
+        	le64_to_cpus((__u64 *) &usb->fs_u.fs_sun.fs_qfmask);
+	} else {
+        	le16_to_cpus__between(*usb,fs_opostbl,fs_u.fs_44.fs_sparecon);
+        	le32_to_cpus__between(*usb,fs_u.fs_sun.fs_sparecon,fs_u.fs_44.fs_maxfilesize);
+        	le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_maxfilesize);
+        	le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qbmask);
+        	le64_to_cpus((__u64 *) &usb->fs_u.fs_44.fs_qfmask);
+        	le32_to_cpus((__s32 *) &usb->fs_u.fs_44.fs_state);
+	}
 	le32_to_cpus__between(*usb,fs_postblformat,fs_magic);
 #endif
 }
diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_swab.h linux/fs/ufs/ufs_swab.h
--- v2.1.86/linux/fs/ufs/ufs_swab.h	Sun Nov  9 14:51:04 1997
+++ linux/fs/ufs/ufs_swab.h	Thu Feb 12 16:27:15 1998
@@ -18,42 +18,104 @@
  *    to support them.
  * (2) for a read/write ufs driver, we should distinguish
  *    between byteswapping for read or write accesses!
+ *    naming should then be UFS16_TO_CPU and suches.
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
  */
 
 #include <linux/ufs_fs.h>
 #include <asm/byteorder.h>
 
 /*
- * These are only valid inside ufs routines,
- * after bytesex has been initialized to sb->u.ufs_sb.s_flags&UFS_BYTESEX
+ * These are only valid inside ufs routines, after a variable named flags
+ * has been made visible in current scope and properly initialized:
+	__u32 flags = sb->u.ufs_sb.s_flags ;
  */
-#define SWAB16(x) ufs_swab16(bytesex,x)
-#define SWAB32(x) ufs_swab32(bytesex,x)
-#define SWAB64(x) ufs_swab64(bytesex,x)
+#define SWAB16(x) ufs_swab16(flags,x)
+#define SWAB32(x) ufs_swab32(flags,x)
+#define SWAB64(x) ufs_swab64(flags,x)
 
-extern __inline__ __const__ __u16 ufs_swab16(__u32 bytesex, __u16 x) {
-	if (bytesex == UFS_LITTLE_ENDIAN) {
+extern __inline__ __const__ __u16 ufs_swab16(__u32 flags, __u16 x) {
+	if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
 		return le16_to_cpu(x);
 	} else {
 		return be16_to_cpu(x);
 	}
 }
-extern __inline__ __const__ __u32 ufs_swab32(__u32 bytesex, __u32 x) {
-	if (bytesex == UFS_LITTLE_ENDIAN) {
+extern __inline__ __const__ __u32 ufs_swab32(__u32 flags, __u32 x) {
+	if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
 		return le32_to_cpu(x);
 	} else {
 		return be32_to_cpu(x);
 	}
 }
-extern __inline__ __const__ __u64 ufs_swab64(__u32 bytesex, __u64 x) {
-	if (bytesex == UFS_LITTLE_ENDIAN) {
+extern __inline__ __const__ __u64 ufs_swab64(__u32 flags, __u64 x) {
+	if ((flags&UFS_BYTESEX) == UFS_LITTLE_ENDIAN) {
 		return le64_to_cpu(x);
 	} else {
 		return be64_to_cpu(x);
 	}
 }
 
+
+/*
+ * These are for in-core superblock normalization.
+ * It might or not be a bad idea once we go to a read/write driver,
+ * as all critical info should be copied to the sb info structure anyway.
+ * So better replace them with a static inline function
+ * ufs_superblock_to_sb_info() in ufs_super.c
+ */
 extern void ufs_superblock_le_to_cpus(struct ufs_superblock * usb);
 extern void ufs_superblock_be_to_cpus(struct ufs_superblock * usb);
+
+
+/*
+ * These also implicitly depend on variable flags...
+ * NAMLEN(foo) is already normalized to local format, so don't SWAB16() it!
+ */
+
+#define NAMLEN(direct) ufs_namlen(flags,direct)
+extern __inline__ __u16 ufs_namlen(__u32 flags, struct ufs_direct * direct) {
+	if ( (flags&UFS_DE_MASK) == UFS_DE_OLD) {
+        	return SWAB16(direct->d_u.d_namlen);
+	} else /* UFS_DE_44BSD */ {
+        	return direct->d_u.d_44.d_namlen;
+	}
+}
+
+/* Here is how the uid is computed:
+   if the file system is 4.2BSD, get it from oldids.
+   if it has sun extension and oldids is USEEFT, get it from ui_sun.
+   if it is 4.4 or Hurd, get it from ui_44 (which is the same as ui_hurd).
+   depends on implicit variable flags being initialized from
+	__u32 flags = sb->u.ufs_sb.s_flags;
+*/
+#define UFS_UID(ino)	ufs_uid(flags,ino)
+#define UFS_GID(ino)	ufs_gid(flags,ino)
+
+extern __inline__ __u32 ufs_uid(__u32 flags,struct ufs_inode * ino) {
+	switch(flags&UFS_UID_MASK) {
+		case UFS_UID_EFT:
+			return SWAB32(ino->ui_u3.ui_sun.ui_uid) ;
+		case UFS_UID_44BSD:
+                  	return SWAB32(ino->ui_u3.ui_44.ui_uid) ;
+		case UFS_UID_OLD:
+		default:
+                	return SWAB16(ino->ui_u1.oldids.suid) ;
+	}
+}
+extern __inline__ __u32 ufs_gid(__u32 flags,struct ufs_inode * ino) {
+	switch(flags&UFS_UID_MASK) {
+		case UFS_UID_EFT:
+			return SWAB32(ino->ui_u3.ui_sun.ui_gid) ;
+		case UFS_UID_44BSD:
+                  	return SWAB32(ino->ui_u3.ui_44.ui_gid) ;
+		case UFS_UID_OLD:
+		default:
+                	return SWAB16(ino->ui_u1.oldids.sgid) ;
+	}
+}
 
 #endif /* _UFS_SWAB_H */
diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c
--- v2.1.86/linux/fs/ufs/ufs_symlink.c	Sun Jan  4 00:53:41 1998
+++ linux/fs/ufs/ufs_symlink.c	Thu Feb 12 16:27:15 1998
@@ -8,6 +8,9 @@
  *
  * Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109
  *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
  */
 
 #include <linux/fs.h>
@@ -22,13 +25,14 @@
 ufs_readlink(struct dentry * dentry, char * buffer, int buflen)
 {
 	struct inode * inode = dentry->d_inode;
+	struct super_block * sb = inode->i_sb;
 	unsigned long int block;
 	struct buffer_head * bh = NULL;
 	char * link;
 	int i;
 	char c;
 
-	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
+	if (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));
 	}
@@ -37,16 +41,16 @@
 		return -EINVAL;
 	}
    
-	if (buflen > inode->i_sb->s_blocksize - 1)
-		buflen = inode->i_sb->s_blocksize - 1;
+	if (buflen > sb->s_blocksize - 1)
+		buflen = 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)) {
+	        if (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);
+	        bh = bread(inode->i_dev, block, sb->s_blocksize);
 		if (!bh) {
 	                printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n",
 	                       inode->i_ino, MAJOR(inode->i_dev),
@@ -55,9 +59,8 @@
 		}
 		link = bh->b_data;
 		/* no need to bswap */
-	}
-	else {
-	        link = (char *)&(inode->u.ufs_i.i_data[0]);
+	} else /* fast symlink */ {
+	        link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]);
 	}
 	i = 0;
 	while (i < buflen && (c = link[i])) {
@@ -88,7 +91,7 @@
 	        /* read the link from disk */
 	        /* XXX - error checking */
 	        block = ufs_bmap(inode, 0);
-	        bh = bread(inode->i_dev, block, BLOCK_SIZE);
+	        bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize);
 	        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),
@@ -97,9 +100,8 @@
 	                return ERR_PTR(-EIO);
 	        }
 	        link = bh->b_data;
-	} else {
-	        /* fast symlink */
-	        link = (char *)&(inode->u.ufs_i.i_data[0]);
+	} else /* fast symlink */ {
+	        link = (char *)&(inode->u.ufs_i.i_u1.i_symlink[0]);
 	}
 	base = lookup_dentry(link, base, 1);
 	brelse (bh);
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/Makefile linux/fs/umsdos/Makefile
--- v2.1.86/linux/fs/umsdos/Makefile	Tue Aug 15 05:07:02 1995
+++ linux/fs/umsdos/Makefile	Thu Feb 12 13:36:57 1998
@@ -6,10 +6,13 @@
 # unless it's something special (ie not a .c file).
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
-
 O_TARGET := umsdos.o
-O_OBJS   := dir.o emd.o file.o inode.o ioctl.o mangle.o namei.o \
-		rdir.o symlink.o #check.o
+
+O_OBJS   := dir.o  file.o inode.o ioctl.o mangle.o namei.o \
+		rdir.o symlink.o emd.o 
+
+#check.o
+
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt
--- v2.1.86/linux/fs/umsdos/README-WIP.txt	Wed Dec 31 16:00:00 1969
+++ linux/fs/umsdos/README-WIP.txt	Thu Feb 12 13:36:57 1998
@@ -0,0 +1,89 @@
+Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing
+(started by Peter T. Waltenberg <peterw@karaka.chch.cri.nz>)
+
+Current status (980211) - UMSDOS dentry-WIP-Beta 0.82:
+
+(1) pure MSDOS (no --linux-.--- EMD file):
+
+- readdir - works
+- lookup - works
+- read file - works
+
+- creat file - works
+- write file - works
+- mkdir - works
+- rmdir - questionable. probable problem on non-empty dirs.
+
+Notes: possible very minor problems with dentry/inode/... kernel structures (very rare)
+
+
+(2) umsdos (with --linux-.--- EMD file):
+
+- readdir - works. problems with symlink/hardlink resolving. see below.
+- lookup -  works. problems with symlink/hardlink resolving. see below.
+- permissions/owners stuff - works
+- long file names - works
+- read file - works
+- switching MSDOS/UMSDOS - untested
+- switching UMSDOS/MSDOS - untested
+- pseudo root things - commented out mostly currently. To be fixed when
+  dentries stuff is straightened out.
+- resolve symlink - seems to work (ls -l shows both symlink and filename it
+  points to, but dereferencing does not work. see below)
+- dereference symlink - for some strange reason does not work. Is
+  follow_symlink now obligatory (in contrary what is said in
+  linux/Documentation/fs/vfs.txt ?) - working on it
+- hard links - totally defunct currently.
+- special files (block/char device, fifos, sockets...) - seems to work ok.
+- other ioctls - mostly untested
+
+- create symlink	- WARNING: NONE OF WRITE OPERATIONS FIXED YET!
+- create hardlink	- WARNING: NONE OF WRITE OPERATIONS FIXED YET!
+- creat file		- WARNING: NONE OF WRITE OPERATIONS FIXED YET!
+- write file		- WARNING: NONE OF WRITE OPERATIONS FIXED YET!
+- mkdir			- WARNING: NONE OF WRITE OPERATIONS FIXED YET!
+- rmdir 		- WARNING: NONE OF WRITE OPERATIONS FIXED YET!
+- umssyncing		- WARNING: NONE OF WRITE OPERATIONS FIXED YET!
+
+Notes: heavy dentry kernel structures trashing. Probably some other kernel
+structures compromised. Have SysRq support compiled in, and use
+Sync/Emergency-remount-RO. And don't try mounting read/write yet - and then
+you should have no big problems... 
+
+Notes2: kernel structures trashing seems to be _MUCH_ lower if no
+symlinks/hardlink present. (hardlinks seem to be biggest problem)
+
+------------------------------------------------------------------------------
+
+Some general notes:
+
+There is great amount of kernel log messages. Use SysRq log-level 5 to turn
+most of them off, or 4 to turn all but really fatal ones off. Probably good
+idea to kill klogd/syslogd so it will only go to console.
+
+It should work enough to test it, but probably not enough to give you second
+chance to umount/rmmod module, recompile it, and reinsert it again. This is
+first on my list of things to get fixed, as it would greatly improve speed
+of compile/test/reboot/set_environment/recompile cycle by removing
+'reboot/set_environment' component.
+
+But I need some help from someone knowing about dentries/inodes use more
+than I. If you can help, please contact me...
+
+I'm unfortunatelly totally out of time to read linux-kernel, but I do check
+for any messages having UMSDOS in subject, and read them. I should reply to
+any direct Email in few days. If I don't - probably I never got your
+message. You can try mnalis@open.hr or mnalis@voyager.hr; however
+mnalis@jagor.srce.hr is preferable one.
+
+------------------------------------------------------------------------------
+
+some of my notes for myself:
+
+- hardlinks/symlinks. test with files in not_the_same_dir
+- also test not_the_same_dir for other file operations like rename etc.
+- iput: device 00:00 inode 318 still has aliases! problem. Check in iput()
+  for device 0,0. Probably null pointer passed arount when it shouldn't be ?
+- dput/iput problem...
+- what about .dotfiles ? working ? multiple dots ? etc....
+
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.1.86/linux/fs/umsdos/dir.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/umsdos/dir.c	Thu Feb 12 13:36:57 1998
@@ -24,11 +24,58 @@
 
 #define UMSDOS_SPECIAL_DIRFPOS	3
 extern struct inode *pseudo_root;
+
+
+/* P.T.Waltenberg
+   I've retained this to facilitate the lookup of some of the hard-wired files/directories UMSDOS
+   uses. It's easier to do once than hack all the other instances. Probably safer as well
+*/   
+int compat_UMSDOS_lookup(struct inode *dir,const char *name,int len, struct inode **inode)
+{
+  int rv;
+  struct dentry *dentry;
+
+  dentry = creat_dentry (name, len, NULL);
+  rv =  UMSDOS_lookup(dir,dentry);
+  
+  if (inode) *inode = dentry->d_inode;
+  return rv;
+}    
+
+
+int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct inode **inode)
+{
+  int rv;
+  struct dentry *dentry;
+
+  dentry = creat_dentry (name, len, NULL);
+  rv = umsdos_real_lookup(dir,dentry);
+  if (inode) *inode = dentry->d_inode;
+  
+  return rv;
+}    
+
+
+int compat_msdos_create(struct inode *dir,const char *name,int len, int mode, struct inode **inode)
+{
+  int rv;
+  struct dentry *dentry;
+
+  dentry = creat_dentry (name, len, NULL);
+  rv = msdos_create(dir,dentry,mode);
+  if(inode != NULL) *inode = dentry->d_inode;
+  
+  return rv;
+}    
+
+
 /*
 	So  grep *  doesn't complain in the presence of directories.
 */
-long UMSDOS_dir_read(struct inode *inode,struct file *filp,
-	char *buf, unsigned long count)
+int UMSDOS_dir_read(struct file *filp,
+		    char *buff,
+		    size_t size,
+		    loff_t * count)
 {
 	return -EISDIR;
 }
@@ -43,554 +90,585 @@
 /*
 	Record a single entry the first call.
 	Return -EINVAL the next one.
+	NOTE: filldir DOES NOT use a dentry
 */
 static int umsdos_dir_once(
 	void * buf,
-	const char * name,
-	int name_len,
+	const char *name,
+	int len,
 	off_t offset,
 	ino_t ino)
 {
-	int ret = -EINVAL;
-	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
-	if (d->count == 0){
-		#if 0
-			char zname[100];
-			memcpy (zname,name,name_len);
-			zname[name_len] = '\0';
-			Printk (("dir_once :%s: offset %Ld\n",zname,offset));
-		#endif
-		ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
-		d->stop = ret < 0;
-		d->count = 1;
-	}
-	return ret;
+  int ret = -EINVAL;
+  struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
+  if (d->count == 0){
+#if 0
+    char zname[100];
+    memcpy (zname,dentry->d_name,dentry->d_len);
+    zname[name_len] = '\0';
+    Printk ((KERN_DEBUG "dir_once :%s: offset %Ld\n",zname,offset));
+#endif
+    ret = d->filldir (d->dirbuf,name,len,offset,ino);
+    d->stop = ret < 0;
+    d->count = 1;
+  }
+  return ret;
 }
 
 /*
-	Read count directory entries from directory filp
-	Return a negative value from linux/errno.h.
-	Return > 0 if success (The amount of byte written by filldir).
-
-	This function is used by the normal readdir VFS entry point and by
-	some function who try to find out info on a file from a pure MSDOS
-	inode. See umsdos_locate_ancestor() below.
+  Read count directory entries from directory filp
+  Return a negative value from linux/errno.h.
+  Return > 0 if success (The amount of byte written by filldir).
+  
+  This function is used by the normal readdir VFS entry point and by
+  some function who try to find out info on a file from a pure MSDOS
+  inode. See umsdos_locate_ancestor() below.
 */
 static int umsdos_readdir_x(
-	struct inode *dir,		/* Point to a description of the super block */
-	struct file *filp,		/* Point to a directory which is read */
-    void *dirbuf,			/* Will hold count directory entry */
-							/* but filled by the filldir function */
-	int internal_read,		/* Called for internal purpose */
-	struct umsdos_dirent *u_entry,	/* Optional umsdos entry */
-	int follow_hlink,
-	filldir_t filldir)
-{
-	int ret = 0;
-	
-	umsdos_startlookup(dir);	
-	if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
-		&& dir == pseudo_root
-		&& !internal_read){
-		/*
-			We don't need to simulate this pseudo directory
-			when umsdos_readdir_x is called for internal operation
-			of umsdos. This is why dirent_in_fs is tested
-		*/
-		/* #Specification: pseudo root / directory /DOS
-			When umsdos operates in pseudo root mode (C:\linux is the
-			linux root), it simulate a directory /DOS which points to
-			the real root of the file system.
-		*/
-		if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS
-			,dir->i_sb->s_mounted->i_ino) == 0){
-			filp->f_pos++;
-		}
-	}else if (filp->f_pos < 2
-		|| (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
-		/* #Specification: readdir / . and ..
-			The msdos filesystem manage the . and .. entry properly
-			so the EMD file won't hold any info about it.
-
-			In readdir, we assume that for the root directory
-			the read position will be 0 for ".", 1 for "..". For
-			a non root directory, the read position will be 0 for "."
-			and 32 for "..".
-		*/
-		/*
-			This is a trick used by the msdos file system (fs/msdos/dir.c)
-			to manage . and .. for the root directory of a file system.
-			Since there is no such entry in the root, fs/msdos/dir.c
-			use the following:
-
-			if f_pos == 0, return ".".
-			if f_pos == 1, return "..".
-
-			So let msdos handle it
-
-			Since umsdos entries are much larger, we share the same f_pos.
-			if f_pos is 0 or 1 or 32, we are clearly looking at . and
-			..
-
-			As soon as we get f_pos == 2 or f_pos == 64, then back to
-			0, but this time we are reading the EMD file.
-
-			Well, not so true. The problem, is that UMSDOS_REC_SIZE is
-			also 64, so as soon as we read the first record in the
-			EMD, we are back at offset 64. So we set the offset
-			to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
-			.. entry from msdos.
-			
-			Now (linux 1.3), umsdos_readdir can read more than one
-			entry even if we limit (umsdos_dir_once) to only one:
-			It skips over hidden file. So we switch to
-			UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
-			the .. entry.
-		*/
-		int last_f_pos = filp->f_pos;	
-		struct UMSDOS_DIR_ONCE bufk;
-		bufk.dirbuf = dirbuf;
-		bufk.filldir = filldir;
-		bufk.count = 0;
-		ret = fat_readdir(dir,filp,&bufk,umsdos_dir_once);
-		if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
-		if (u_entry != NULL) u_entry->flags = 0;
-	}else{
-		struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
-		if (emd_dir != NULL){
-			off_t start_fpos = filp->f_pos;
-			if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
-			PRINTK (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size));
-			ret = 0;
-			while (filp->f_pos < emd_dir->i_size){
-				struct umsdos_dirent entry;
-				off_t cur_f_pos = filp->f_pos;
-				if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){
-					ret = -EIO;
-					break;
-				}else if (entry.name_len != 0){
-					/* #Specification: umsdos / readdir
-						umsdos_readdir() should fill a struct dirent with
-						an inode number. The cheap way to get it is to
-						do a lookup in the MSDOS directory for each
-						entry processed by the readdir() function.
-						This is not very efficient, but very simple. The
-						other way around is to maintain a copy of the inode
-						number in the EMD file. This is a problem because
-						this has to be maintained in sync using tricks.
-						Remember that MSDOS (the OS) does not update the
-						modification time (mtime) of a directory. There is
-						no easy way to tell that a directory was modified
-						during a DOS session and synchronise the EMD file.
-
-						Suggestion welcome.
-
-						So the easy way is used!
-					*/
-					struct umsdos_info info;
-					struct inode *inode;
-					int lret;
-					umsdos_parse (entry.name,entry.name_len,&info);
-					info.f_pos = cur_f_pos;
-					umsdos_manglename (&info);
-					lret = umsdos_real_lookup (dir,info.fake.fname
-						,info.fake.len,&inode);
-					PRINTK (("Cherche inode de %s lret %d flags %d\n"
-						,info.fake.fname,lret,entry.flags));
-					if (lret == 0
-						&& (entry.flags & UMSDOS_HLINK)
-						&& follow_hlink){
-						struct inode *rinode;
-						lret = umsdos_hlink2inode (inode,&rinode);
-						inode = rinode;
-					}
-					if (lret == 0){
-						/* #Specification: pseudo root / reading real root
-							The pseudo root (/linux) is logically
-							erased from the real root. This mean that
-							ls /DOS, won't show "linux". This avoids
-							infinite recursion /DOS/linux/DOS/linux while
-							walking the file system.
-						*/
-						if (inode != pseudo_root
-							&& (internal_read
-								|| !(entry.flags & UMSDOS_HIDDEN))){
-							if (filldir (dirbuf 
-								,entry.name,entry.name_len
-								,cur_f_pos, inode->i_ino) < 0){
-								filp->f_pos = cur_f_pos;
-							}
-							PRINTK (("Trouve ino %ld ",inode->i_ino));
-							if (u_entry != NULL) *u_entry = entry;
-							iput (inode);
-							break;
-						}
-						iput (inode);
-					}else{
-						/* #Specification: umsdos / readdir / not in MSDOS
-							During a readdir operation, if the file is not
-							in the MSDOS directory anymore, the entry is
-							removed from the EMD file silently.
-						*/
-						ret = umsdos_writeentry (dir,emd_dir,&info,1);
-						if (ret != 0){
-							break;
-						}
-					}
-				}
-			}
-			/*
-				If the fillbuf has failed, f_pos is back to 0.
-				To avoid getting back into the . and .. state
-				(see comments at the beginning), we put back
-				the special offset.
-			*/
-			if (filp->f_pos == 0) filp->f_pos = start_fpos;
-			iput(emd_dir);
-		}
+			    struct inode *dir,		/* Point to a description of the super block */
+			    struct file *filp,		/* Point to a directory which is read */
+			    void *dirbuf,			/* Will hold count directory entry */
+			    /* but filled by the filldir function */
+			    int internal_read,		/* Called for internal purpose */
+			    struct umsdos_dirent *u_entry,	/* Optional umsdos entry */
+			    int follow_hlink,
+			    filldir_t filldir)
+{
+  int ret = 0;
+  struct inode *root_inode;
+  
+  root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO);
+  umsdos_startlookup(dir);	
+  if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
+      && pseudo_root
+      && dir == pseudo_root
+      && !internal_read){
+      
+      Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
+    /*
+      We don't need to simulate this pseudo directory
+      when umsdos_readdir_x is called for internal operation
+      of umsdos. This is why dirent_in_fs is tested
+    */
+    /* #Specification: pseudo root / directory /DOS
+       When umsdos operates in pseudo root mode (C:\linux is the
+       linux root), it simulate a directory /DOS which points to
+       the real root of the file system.
+    */
+    if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS
+		 ,UMSDOS_ROOT_INO) == 0){
+      filp->f_pos++;
+    }
+  }else if (filp->f_pos < 2
+	    || (dir != root_inode && filp->f_pos == 32)){
+    /* #Specification: readdir / . and ..
+       The msdos filesystem manage the . and .. entry properly
+       so the EMD file won't hold any info about it.
+       
+       In readdir, we assume that for the root directory
+       the read position will be 0 for ".", 1 for "..". For
+       a non root directory, the read position will be 0 for "."
+       and 32 for "..".
+    */
+    /*
+      This is a trick used by the msdos file system (fs/msdos/dir.c)
+      to manage . and .. for the root directory of a file system.
+      Since there is no such entry in the root, fs/msdos/dir.c
+      use the following:
+      
+      if f_pos == 0, return ".".
+      if f_pos == 1, return "..".
+      
+      So let msdos handle it
+      
+      Since umsdos entries are much larger, we share the same f_pos.
+      if f_pos is 0 or 1 or 32, we are clearly looking at . and
+      ..
+      
+      As soon as we get f_pos == 2 or f_pos == 64, then back to
+      0, but this time we are reading the EMD file.
+      
+      Well, not so true. The problem, is that UMSDOS_REC_SIZE is
+      also 64, so as soon as we read the first record in the
+      EMD, we are back at offset 64. So we set the offset
+      to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
+      .. entry from msdos.
+      
+      Now (linux 1.3), umsdos_readdir can read more than one
+      entry even if we limit (umsdos_dir_once) to only one:
+      It skips over hidden file. So we switch to
+      UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
+      the .. entry.
+    */
+    int last_f_pos = filp->f_pos;	
+    struct UMSDOS_DIR_ONCE bufk;
+
+    Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
+
+    bufk.dirbuf = dirbuf;
+    bufk.filldir = filldir;
+    bufk.count = 0;
+
+    ret = fat_readdir(filp,&bufk,umsdos_dir_once);
+    if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
+    if (u_entry != NULL) u_entry->flags = 0;
+  }else{
+    struct inode *emd_dir;
+    Printk (("umsdos_readdir_x: normal file /mn/?\n"));
+    emd_dir = umsdos_emd_dir_lookup(dir,0);
+    if (emd_dir != NULL){
+      off_t start_fpos = filp->f_pos;
+      Printk (("umsdos_readdir_x: emd_dir->i_ino=%d\n",emd_dir->i_ino));
+      if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
+      Printk (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size));
+      ret = 0;
+      while (filp->f_pos < emd_dir->i_size){
+	struct umsdos_dirent entry;
+	off_t cur_f_pos = filp->f_pos;
+	if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){
+	  ret = -EIO;
+	  break;
+	}else if (entry.name_len != 0){
+	  /* #Specification: umsdos / readdir
+	     umsdos_readdir() should fill a struct dirent with
+	     an inode number. The cheap way to get it is to
+	     do a lookup in the MSDOS directory for each
+	     entry processed by the readdir() function.
+	     This is not very efficient, but very simple. The
+	     other way around is to maintain a copy of the inode
+	     number in the EMD file. This is a problem because
+	     this has to be maintained in sync using tricks.
+	     Remember that MSDOS (the OS) does not update the
+	     modification time (mtime) of a directory. There is
+	     no easy way to tell that a directory was modified
+	     during a DOS session and synchronise the EMD file.
+	     
+	     Suggestion welcome.
+	     
+	     So the easy way is used!
+	  */
+	  struct umsdos_info info;
+	  struct inode *inode;
+	  
+	  int lret;
+	  umsdos_parse (entry.name,entry.name_len,&info);
+	  info.f_pos = cur_f_pos;
+	  umsdos_manglename (&info);
+	  /* FIXME, fake a dentry --> /mn/ fixed ? */
+	  lret = compat_umsdos_real_lookup (dir,info.fake.fname,
+					    info.fake.len,&inode);
+	  Printk (("Cherche inode de %s lret %d flags %d\n"
+		   ,info.fake.fname,lret,entry.flags));
+	  if (lret == 0
+	      && (entry.flags & UMSDOS_HLINK)
+	      && follow_hlink){
+	    struct inode *rinode;
+	    lret = umsdos_hlink2inode (inode,&rinode);
+	    inode = rinode;
+	  }
+	  if (lret == 0){
+	    /* #Specification: pseudo root / reading real root
+	       The pseudo root (/linux) is logically
+	       erased from the real root. This mean that
+	       ls /DOS, won't show "linux". This avoids
+	       infinite recursion /DOS/linux/DOS/linux while
+	       walking the file system.
+	    */
+	    if (inode != pseudo_root
+		&& (internal_read
+		    || !(entry.flags & UMSDOS_HIDDEN))){
+	      if (filldir (dirbuf, 
+			   entry.name,
+			   entry.name_len,
+			   cur_f_pos, 
+			   inode->i_ino) < 0){
+		filp->f_pos = cur_f_pos;
+	      }
+	      Printk (("Trouve ino %ld ",inode->i_ino));
+	      if (u_entry != NULL) *u_entry = entry;
+	      iput (inode);
+	      break;
+	    }
+	    iput (inode);
+	  }else{
+	    /* #Specification: umsdos / readdir / not in MSDOS
+	       During a readdir operation, if the file is not
+	       in the MSDOS directory anymore, the entry is
+	       removed from the EMD file silently.
+	    */
+	    Printk (("'Silently' removing EMD for file\n"));
+	    ret = umsdos_writeentry (dir,emd_dir,&info,1);
+	    if (ret != 0){
+	      break;
+	    }
+	  }
 	}
-	umsdos_endlookup(dir);	
-	PRINTK (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret));
-	return ret;
+      }
+      /*
+	If the fillbuf has failed, f_pos is back to 0.
+	To avoid getting back into the . and .. state
+	(see comments at the beginning), we put back
+	the special offset.
+      */
+      if (filp->f_pos == 0) filp->f_pos = start_fpos;
+      iput(emd_dir);
+    }
+  }
+  umsdos_endlookup(dir);	
+  Printk (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret));
+  return ret;
 }
+
+
 /*
-	Read count directory entries from directory filp
-	Return a negative value from linux/errno.h.
-	Return 0 or positive if successful
+  Read count directory entries from directory filp
+  Return a negative value from linux/errno.h.
+  Return 0 or positive if successful
 */
 static int UMSDOS_readdir(
-	struct inode *dir,		/* Point to a description of the super block */
-	struct file *filp,		/* Point to a directory which is read */
-	void *dirbuf,			/* Will hold directory entries  */
-	filldir_t filldir)
-{
-	int ret = 0;
-	int count = 0;
-	struct UMSDOS_DIR_ONCE bufk;
-	bufk.dirbuf = dirbuf;
-	bufk.filldir = filldir;
-	bufk.stop = 0;
-	PRINTK (("UMSDOS_readdir in\n"));
-	while (ret == 0 && bufk.stop == 0){
-		struct umsdos_dirent entry;
-		bufk.count = 0;
-		ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once);
-		if (bufk.count == 0) break;
-		count += bufk.count;
-	}
-	PRINTK (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count
-		,filp->f_pos));
-	return count?:ret;
+			  struct file *filp,		/* Point to a directory which is read */
+			  void *dirbuf,			/* Will hold directory entries  */
+			  filldir_t filldir)
+{
+  struct inode *dir = filp->f_dentry->d_inode;
+  int ret = 0;
+  int count = 0;
+  struct UMSDOS_DIR_ONCE bufk;
+  bufk.dirbuf = dirbuf;
+  bufk.filldir = filldir;
+  bufk.stop = 0;
+
+  Printk (("UMSDOS_readdir in\n"));
+  while (ret == 0 && bufk.stop == 0){
+    struct umsdos_dirent entry;
+    bufk.count = 0;
+    Printk (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%d)\n",dir,filp,&bufk,0,&entry,1,umsdos_dir_once));
+    ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once);
+    if (bufk.count == 0) break;
+    count += bufk.count;
+  }
+  Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count
+	   ,filp->f_pos));
+  return count?:ret;
 }
+
 /*
-	Complete the inode content with info from the EMD file
+  Complete the inode content with info from the EMD file
 */
 void umsdos_lookup_patch (
-	struct inode *dir,
-	struct inode *inode,
-	struct umsdos_dirent *entry,
-	off_t  emd_pos)
-{
-	/*
-		This function modify the state of a dir inode. It decides
-		if the dir is a umsdos dir or a dos dir. This is done
-		deeper in umsdos_patch_inode() called at the end of this function.
-
-		umsdos_patch_inode() may block because it is doing disk access.
-		At the same time, another process may get here to initialise
-		the same dir inode. There is 3 cases.
-
-		1-The inode is already initialised. We do nothing.
-		2-The inode is not initialised. We lock access and do it.
-		3-Like 2 but another process has lock the inode, so we try
-		  to lock it and right after check if initialisation is still
-		  needed.
-
-
-		Thanks to the mem option of the kernel command line, it was
-		possible to consistently reproduce this problem by limiting
-		my mem to 4 meg and running X.
-	*/
-	/*
-		Do this only if the inode is freshly read, because we will lose
-		the current (updated) content.
-	*/
-	/*
-		A lookup of a mount point directory yield the inode into
-		the other fs, so we don't care about initialising it. iget()
-		does this automatically.
-	*/
-	if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){
-		if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode);
-		if (!umsdos_isinit(inode)){
-			/* #Specification: umsdos / lookup / inode info
-				After successfully reading an inode from the MSDOS
-				filesystem, we use the EMD file to complete it.
-				We update the following field.
-
-				uid, gid, atime, ctime, mtime, mode.
-
-				We rely on MSDOS for mtime. If the file
-				was modified during an MSDOS session, at least
-				mtime will be meaningful. We do this only for regular
-				file.
-				
-				We don't rely on MSDOS for mtime for directory because
-				the MSDOS directory date is creation time (strange
-				MSDOS behavior) which fit nowhere in the three UNIX
-				time stamp.
-			*/
-			if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime;
-			inode->i_mode  = entry->mode;
-			inode->i_rdev  = to_kdev_t(entry->rdev);
-			inode->i_atime = entry->atime;
-			inode->i_ctime = entry->ctime;
-			inode->i_mtime = entry->mtime;
-			inode->i_uid   = entry->uid;
-			inode->i_gid   = entry->gid;
-			/* #Specification: umsdos / conversion mode
-				The msdos fs can do some inline conversion
-				of the data of a file. It can translate
-				silently from MsDOS text file format to Unix
-				one (crlf -> lf) while reading, and the reverse
-				while writing. This is activated using the mount
-				option conv=....
-
-				This is not useful for Linux file in promoted
-				directory. It can even be harmful. For this
-				reason, the binary (no conversion) mode is
-				always activated.
-			*/
-			/* #Specification: umsdos / conversion mode / todo
-				A flag could be added to file and directories
-				forcing an automatic conversion mode (as
-				done with the msdos fs).
-				
-				This flag could be setup on a directory basis
-				(instead of file) and all file in it would
-				logically inherited. If the conversion mode
-				is active (conv=) then the i_binary flag would
-				be left untouched in those directories.
-				
-				It was proposed that the sticky bit was used
-				to set this. The problem is that new file would
-				be written incorrectly. The other problem is that
-				the sticky bit has a meaning for directories. So
-				another bit should be used (there is some space
-				in the EMD file for it) and a special utilities
-				would be used to assign the flag to a directory).
-				I don't think it is useful to assign this flag
-				on a single file.
-			*/
-
-			MSDOS_I(inode)->i_binary = 1;
-			/* #Specification: umsdos / i_nlink
-				The nlink field of an inode is maintain by the MSDOS file system
-				for directory and by UMSDOS for other file. The logic is that
-				MSDOS is already figuring out what to do for directories and
-				does nothing for other files. For MSDOS, there are no hard link
-				so all file carry nlink==1. UMSDOS use some info in the
-				EMD file to plug the correct value.
-			*/
-			if (!S_ISDIR(entry->mode)){
-				if (entry->nlink > 0){
-					inode->i_nlink = entry->nlink;
-				}else{
-					printk ("UMSDOS: lookup_patch entry->nlink < 1 ???\n");
-				}
-			}
-			umsdos_patch_inode(inode,dir,emd_pos);
-		}
-		if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode);
-if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n");
+			  struct inode *dir,
+			  struct inode *inode,
+			  struct umsdos_dirent *entry,
+			  off_t  emd_pos)
+{
+  /*
+    This function modify the state of a dir inode. It decides
+    if the dir is a umsdos dir or a dos dir. This is done
+    deeper in umsdos_patch_inode() called at the end of this function.
+    
+    umsdos_patch_inode() may block because it is doing disk access.
+    At the same time, another process may get here to initialise
+    the same dir inode. There is 3 cases.
+    
+    1-The inode is already initialised. We do nothing.
+    2-The inode is not initialised. We lock access and do it.
+    3-Like 2 but another process has lock the inode, so we try
+    to lock it and right after check if initialisation is still
+    needed.
+    
+    
+    Thanks to the mem option of the kernel command line, it was
+    possible to consistently reproduce this problem by limiting
+    my mem to 4 meg and running X.
+  */
+  /*
+    Do this only if the inode is freshly read, because we will lose
+    the current (updated) content.
+  */
+  /*
+    A lookup of a mount point directory yield the inode into
+    the other fs, so we don't care about initialising it. iget()
+    does this automatically.
+  */
+  if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){
+    if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode);
+    if (!umsdos_isinit(inode)){
+      /* #Specification: umsdos / lookup / inode info
+	 After successfully reading an inode from the MSDOS
+	 filesystem, we use the EMD file to complete it.
+	 We update the following field.
+	 
+	 uid, gid, atime, ctime, mtime, mode.
+	 
+	 We rely on MSDOS for mtime. If the file
+	 was modified during an MSDOS session, at least
+	 mtime will be meaningful. We do this only for regular
+	 file.
+	 
+	 We don't rely on MSDOS for mtime for directory because
+	 the MSDOS directory date is creation time (strange
+	 MSDOS behavior) which fit nowhere in the three UNIX
+	 time stamp.
+      */
+      if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime;
+      inode->i_mode  = entry->mode;
+      inode->i_rdev  = to_kdev_t(entry->rdev);
+      inode->i_atime = entry->atime;
+      inode->i_ctime = entry->ctime;
+      inode->i_mtime = entry->mtime;
+      inode->i_uid   = entry->uid;
+      inode->i_gid   = entry->gid;
+      /* #Specification: umsdos / conversion mode
+	 The msdos fs can do some inline conversion
+	 of the data of a file. It can translate
+	 silently from MsDOS text file format to Unix
+	 one (crlf -> lf) while reading, and the reverse
+	 while writing. This is activated using the mount
+	 option conv=....
+	 
+	 This is not useful for Linux file in promoted
+	 directory. It can even be harmful. For this
+	 reason, the binary (no conversion) mode is
+	 always activated.
+      */
+      /* #Specification: umsdos / conversion mode / todo
+	 A flag could be added to file and directories
+	 forcing an automatic conversion mode (as
+	 done with the msdos fs).
+	 
+	 This flag could be setup on a directory basis
+	 (instead of file) and all file in it would
+	 logically inherited. If the conversion mode
+	 is active (conv=) then the i_binary flag would
+	 be left untouched in those directories.
+	 
+	 It was proposed that the sticky bit was used
+	 to set this. The problem is that new file would
+	 be written incorrectly. The other problem is that
+	 the sticky bit has a meaning for directories. So
+	 another bit should be used (there is some space
+	 in the EMD file for it) and a special utilities
+	 would be used to assign the flag to a directory).
+	 I don't think it is useful to assign this flag
+	 on a single file.
+      */
+      
+      MSDOS_I(inode)->i_binary = 1;
+      /* #Specification: umsdos / i_nlink
+	 The nlink field of an inode is maintain by the MSDOS file system
+	 for directory and by UMSDOS for other file. The logic is that
+	 MSDOS is already figuring out what to do for directories and
+	 does nothing for other files. For MSDOS, there are no hard link
+	 so all file carry nlink==1. UMSDOS use some info in the
+	 EMD file to plug the correct value.
+      */
+      if (!S_ISDIR(entry->mode)){
+	if (entry->nlink > 0){
+	  inode->i_nlink = entry->nlink;
+	}else{
+	  printk (KERN_ERR "UMSDOS: lookup_patch entry->nlink < 1 ???\n");
 	}
+      }
+      umsdos_patch_inode(inode,dir,emd_pos);
+    }
+    if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode);
+    if (inode->u.umsdos_i.i_emd_owner==0) printk (KERN_WARNING "emd_owner still 0 ???\n");
+  }
 }
 struct UMSDOS_DIRENT_K{
-	off_t f_pos; /* will hold the offset of the entry in EMD */
-	ino_t ino;
+  off_t f_pos; /* will hold the offset of the entry in EMD */
+  ino_t ino;
 };
 
 /*
-	Just to record the offset of one entry.
+  Just to record the offset of one entry.
 */
 static int umsdos_filldir_k(
-	void * buf,
-	const char * name,
-	int name_len,
-	off_t offset,
-	ino_t ino)
-{
-	struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf;
-	d->f_pos = offset;
-	d->ino = ino;
-	return 0;
+			    void * buf,
+			    const char *name,
+			    int len,
+			    off_t offset,
+			    ino_t ino)
+{
+  struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf;
+  d->f_pos = offset;
+  d->ino = ino;
+  return 0;
 }
 
 struct UMSDOS_DIR_SEARCH{
-	struct umsdos_dirent *entry;
-	int found;
-	ino_t search_ino;
+  struct umsdos_dirent *entry;
+  int found;
+  ino_t search_ino;
 };
 
 static int umsdos_dir_search (
-	void * buf,
-	const char * name,
-	int name_len,
-	off_t offset,
-	ino_t ino)
-{
-	int ret = 0;
-	struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf;
-	if (d->search_ino == ino){
-		d->found = 1;
-		memcpy (d->entry->name,name,name_len);
-		d->entry->name[name_len] = '\0';
-		d->entry->name_len = name_len;
-		ret = 1;	/* So fat_readdir will terminate */
-	}
-	return ret;
+			      void * buf,
+			      const char *name,
+			      int len,
+			      off_t offset,
+			      ino_t ino)
+{
+  int ret = 0;
+  struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf;
+  if (d->search_ino == ino){
+    d->found = 1;
+    memcpy (d->entry->name,name,len);
+    d->entry->name[len] = '\0';
+    d->entry->name_len = len;
+    ret = 1;	/* So fat_readdir will terminate */
+  }
+  return ret;
 }
 
 
 /*
-	Locate entry of an inode in a directory.
-	Return 0 or a negative error code.
-
-	Normally, this function must succeed. It means a strange corruption
-	in the file system if not.
+  Locate entry of an inode in a directory.
+  Return 0 or a negative error code.
+  
+  Normally, this function must succeed. It means a strange corruption
+  in the file system if not.
 */
 int umsdos_inode2entry (
-	struct inode *dir,
-	struct inode *inode,
-	struct umsdos_dirent *entry)	/* Will hold the entry */
-{
-	int ret = -ENOENT;
-	if (inode == pseudo_root){
-		/*
-			Quick way to find the name.
-			Also umsdos_readdir_x won't show /linux anyway
-		*/
-		memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1);
-		entry->name_len = UMSDOS_PSDROOT_LEN;
-		ret = 0;
-	}else{
-		struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
-		iput (emddir);
-		if (emddir == NULL){
-			/* This is a DOS directory */
-			struct UMSDOS_DIR_SEARCH bufk;
-			struct file filp;
-			filp.f_reada = 1;
-			filp.f_pos = 0;
-			bufk.entry = entry;
-			bufk.search_ino = inode->i_ino;
-			fat_readdir (dir,&filp,&bufk,umsdos_dir_search);
-			if (bufk.found){
-				ret = 0;
-				inode->u.umsdos_i.i_dir_owner = dir->i_ino;
-				inode->u.umsdos_i.i_emd_owner = 0;
-				umsdos_setup_dir_inode(inode);
-			}
-		}else{
-			/* skip . and .. see umsdos_readdir_x() */
-			struct file filp;
-			filp.f_reada = 1;
-			filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
-			while (1){
-				struct UMSDOS_DIRENT_K bufk;
-				if (umsdos_readdir_x(dir,&filp,&bufk
-					,1,entry,0,umsdos_filldir_k) < 0){
-					printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
-						,inode->i_ino);
-					break;
-				}else if (bufk.ino == inode->i_ino){
-					ret = 0;
-					umsdos_lookup_patch (dir,inode,entry,bufk.f_pos);
-					break;
-				}
-			}
-		}
+			struct inode *dir,
+			struct inode *inode,
+			struct umsdos_dirent *entry)	/* Will hold the entry */
+{
+  int ret = -ENOENT;
+  if (pseudo_root && inode == pseudo_root){
+    /*
+      Quick way to find the name.
+      Also umsdos_readdir_x won't show /linux anyway
+    */
+    memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1);
+    entry->name_len = UMSDOS_PSDROOT_LEN;
+    ret = 0;
+  }else{
+    struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
+    iput (emddir);
+    if (emddir == NULL){
+      /* This is a DOS directory */
+      struct UMSDOS_DIR_SEARCH bufk;
+      struct file filp;
+      Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) /mn/\n"));
+      filp.f_reada = 1;
+      filp.f_pos = 0;
+      bufk.entry = entry;
+      bufk.search_ino = inode->i_ino;
+      fat_readdir (&filp,&bufk,umsdos_dir_search);
+      if (bufk.found){
+	ret = 0;
+	inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+	inode->u.umsdos_i.i_emd_owner = 0;
+	umsdos_setup_dir_inode(inode);
+      }
+    }else{
+      /* skip . and .. see umsdos_readdir_x() */
+      struct file filp;
+      filp.f_reada = 1;
+      filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
+      Printk ((KERN_ERR "umsdos_inode2entry skip./..: WARNING: Known filp problem. segfaulting :) /mn/\n"));
+      while (1){
+	struct UMSDOS_DIRENT_K bufk;
+	if (umsdos_readdir_x(dir,&filp,&bufk
+			     ,1,entry,0,umsdos_filldir_k) < 0){
+	  printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
+		  ,inode->i_ino);
+	  break;
+	}else if (bufk.ino == inode->i_ino){
+	  ret = 0;
+	  umsdos_lookup_patch (dir,inode,entry,bufk.f_pos);
+	  break;
 	}
-	return ret;
+      }
+    }
+  }
+  return ret;
 }
+
+
 /*
-	Locate the parent of a directory and the info on that directory
-	Return 0 or a negative error code.
+  Locate the parent of a directory and the info on that directory
+  Return 0 or a negative error code.
 */
 static int umsdos_locate_ancestor (
-	struct inode *dir,
-	struct inode **result,
-	struct umsdos_dirent *entry)
-{
-	int ret;
-	umsdos_patch_inode (dir,NULL,0);
-	ret = umsdos_real_lookup (dir,"..",2,result);
-	PRINTK (("result %d %p ",ret,*result));
-	if (ret == 0){
-		struct inode *adir = *result;
-		ret = umsdos_inode2entry (adir,dir,entry);
-	}
-	PRINTK (("\n"));
-	return ret;
-}
-/*
-	Build the path name of an inode (relative to the file system.
-	This function is need to set (pseudo) hard link.
-
-	It uses the same strategy as the standard getcwd().
+				   struct inode *dir,
+				   struct inode **result,
+				   struct umsdos_dirent *entry)
+{
+  int ret;
+  
+  umsdos_patch_inode (dir,NULL,0);
+  /* FIXME */
+  ret = compat_umsdos_real_lookup (dir,"..",2,result);
+  Printk (("result %d %p ",ret,*result));
+  if (ret == 0){
+    struct inode *adir = *result;
+    ret = umsdos_inode2entry (adir,dir,entry);
+  }
+  Printk (("\n"));
+  return ret;
+}
+/*
+  Build the path name of an inode (relative to the file system.
+  This function is need to set (pseudo) hard link.
+  
+  It uses the same strategy as the standard getcwd().
 */
 int umsdos_locate_path (
-	struct inode *inode,
-	char *path)
+			struct inode *inode,
+			char *path)
 {
-	int ret = 0;
-	struct inode *dir = inode;
-	char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-	if (bpath == NULL){
-		ret = -ENOMEM;
-	}else{
-		struct umsdos_dirent entry;
-		char *ptbpath = bpath+PATH_MAX-1;
-		*ptbpath = '\0';
-		PRINTK (("locate_path mode %x ",inode->i_mode));
-		if (!S_ISDIR(inode->i_mode)){
-			ret = umsdos_get_dirowner (inode,&dir);
-			PRINTK (("locate_path ret %d ",ret));
-			if (ret == 0){
-				ret = umsdos_inode2entry (dir,inode,&entry);
-				if (ret == 0){
-					ptbpath -= entry.name_len;
-					memcpy (ptbpath,entry.name,entry.name_len);
-					PRINTK (("ptbpath :%s: ",ptbpath));
-				}
-			}
-		}else{
-			atomic_inc(&dir->i_count);
-		}
-		if (ret == 0){
-			while (dir != dir->i_sb->s_mounted){
-				struct inode *adir;
-				ret = umsdos_locate_ancestor (dir,&adir,&entry);
-				iput (dir);
-				dir = NULL;
-				PRINTK (("ancestor %d ",ret));
-				if (ret == 0){
-					*--ptbpath = '/';
-					ptbpath -= entry.name_len;
-					memcpy (ptbpath,entry.name,entry.name_len);
-					dir = adir;
-					PRINTK (("ptbpath :%s: ",ptbpath));
-				}else{
-					break;
-				}
-			}
-		}
-		strcpy (path,ptbpath);
-		kfree (bpath);
+  int ret = 0;
+  struct inode *dir = inode;
+  struct inode *root_inode;
+  char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+  root_inode = iget(inode->i_sb,UMSDOS_ROOT_INO);
+  if (bpath == NULL){
+    ret = -ENOMEM;
+  }else{
+    struct umsdos_dirent entry;
+    char *ptbpath = bpath+PATH_MAX-1;
+    *ptbpath = '\0';
+    Printk (("locate_path mode %x ",inode->i_mode));
+    if (!S_ISDIR(inode->i_mode)){
+      ret = umsdos_get_dirowner (inode,&dir);
+      Printk (("locate_path ret %d ",ret));
+      if (ret == 0){
+	ret = umsdos_inode2entry (dir,inode,&entry);
+	if (ret == 0){
+	  ptbpath -= entry.name_len;
+	  memcpy (ptbpath,entry.name,entry.name_len);
+	  Printk (("ptbpath :%s: ",ptbpath));
 	}
-	PRINTK (("\n"));
+      }
+    }else{
+      dir->i_count++;
+    }
+    if (ret == 0){
+      while (dir != root_inode){
+	struct inode *adir;
+	ret = umsdos_locate_ancestor (dir,&adir,&entry);
 	iput (dir);
-	return ret;
+	dir = NULL;
+	Printk (("ancestor %d ",ret));
+	if (ret == 0){
+	  *--ptbpath = '/';
+	  ptbpath -= entry.name_len;
+	  memcpy (ptbpath,entry.name,entry.name_len);
+	  dir = adir;
+	  Printk (("ptbpath :%s: ",ptbpath));
+	}else{
+	  break;
+	}
+      }
+    }
+    strcpy (path,ptbpath);
+    kfree (bpath);
+  }
+  Printk (("\n"));
+  iput (dir);
+  return ret;
 }
 
 /*
@@ -598,205 +676,262 @@
 */
 int umsdos_is_pseudodos (
 	struct inode *dir,
-	const char *name,
-	int len)
+	struct dentry *dentry)
 {
-	/* #Specification: pseudo root / DOS hard coded
-		The pseudo sub-directory DOS in the pseudo root is hard coded.
-		The name is DOS. This is done this way to help standardised
-		the umsdos layout. The idea is that from now on /DOS is
-		a reserved path and nobody will think of using such a path
-		for a package.
-	*/
-	return dir == pseudo_root
-		&& len == 3
-		&& name[0] == 'D' && name[1] == 'O' && name[2] == 'S';
+  /* #Specification: pseudo root / DOS hard coded
+     The pseudo sub-directory DOS in the pseudo root is hard coded.
+     The name is DOS. This is done this way to help standardised
+     the umsdos layout. The idea is that from now on /DOS is
+     a reserved path and nobody will think of using such a path
+     for a package.
+  */
+  return pseudo_root
+    && dir == pseudo_root
+    && dentry->d_name.len == 3
+    && dentry->d_name.name[0] == 'D' 
+    && dentry->d_name.name[1] == 'O' 
+    && dentry->d_name.name[2] == 'S';
 }
+
 /*
-	Check if a file exist in the current directory.
-	Return 0 if ok, negative error code if not (ex: -ENOENT).
+  Check if a file exist in the current directory.
+  Return 0 if ok, negative error code if not (ex: -ENOENT).
 */
 static int umsdos_lookup_x (
-	struct inode *dir,
-	const char *name,
-	int len,
-	struct inode **result,	/* Will hold inode of the file, if successful */
-	int nopseudo)			/* Don't care about pseudo root mode */
-{
-	int ret = -ENOENT;
-	*result = NULL;
-	umsdos_startlookup(dir);	
-	if (len == 1 && name[0] == '.'){
-		*result = dir;
-		atomic_inc(&dir->i_count);
-		ret = 0;
-	}else if (len == 2 && name[0] == '.' && name[1] == '.'){
-		if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
-			/* #Specification: pseudo root / .. in real root
-				Whenever a lookup is those in the real root for
-				the directory .., and pseudo root is active, the
-				pseudo root is returned.
-			*/
-			ret = 0;
-			*result = pseudo_root;
-			atomic_inc(&pseudo_root->i_count);
-		}else{
-			/* #Specification: locating .. / strategy
-				We use the msdos filesystem to locate the parent directory.
-				But it is more complicated than that.
-				
-				We have to step back even further to
-				get the parent of the parent, so we can get the EMD
-				of the parent of the parent. Using the EMD file, we can
-				locate all the info on the parent, such a permissions
-				and owner.
-			*/
-			ret = umsdos_real_lookup (dir,"..",2,result);
-			PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result));
-			if (ret == 0
-				&& *result != dir->i_sb->s_mounted
-				&& *result != pseudo_root){
-				struct inode *aadir;
-				struct umsdos_dirent entry;
-				ret = umsdos_locate_ancestor (*result,&aadir,&entry);
-				iput (aadir);
-			}
-		}
-	}else if (umsdos_is_pseudodos(dir,name,len)){
-		/* #Specification: pseudo root / lookup(DOS)
-			A lookup of DOS in the pseudo root will always succeed
-			and return the inode of the real root.
-		*/
-		*result = dir->i_sb->s_mounted;
-		atomic_inc(&((*result)->i_count));
-		ret = 0;
-	}else{
-		struct umsdos_info info;
-		ret = umsdos_parse (name,len,&info);
-		if (ret == 0) ret = umsdos_findentry (dir,&info,0);
-		PRINTK (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret
-			,info.fake.len));
-		if (ret == 0){
-			/* #Specification: umsdos / lookup
-				A lookup for a file is done in two step. First, we locate
-				the file in the EMD file. If not present, we return
-				an error code (-ENOENT). If it is there, we repeat the
-				operation on the msdos file system. If this fails, it means
-				that the file system is not in sync with the emd file.
-				We silently remove this entry from the emd file,
-				and return ENOENT.
-			*/
-			struct inode *inode;
-			ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result);
-			inode = *result;
-			if (inode == NULL){
-				printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n"
-					,info.fake.fname);
-				umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
-			}else{
-				umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
-				PRINTK (("lookup ino %ld flags %d\n",inode->i_ino
-					,info.entry.flags));
-				if (info.entry.flags & UMSDOS_HLINK){
-					ret = umsdos_hlink2inode (inode,result);
-				}
-				if (*result == pseudo_root && !nopseudo){
-					/* #Specification: pseudo root / dir lookup
-						For the same reason as readdir, a lookup in /DOS for
-						the pseudo root directory (linux) will fail.
-					*/
-					/*
-						This has to be allowed for resolving hard link
-						which are recorded independently of the pseudo-root
-						mode.
-					*/
-					iput (pseudo_root);
-					*result = NULL;
-					ret = -ENOENT;
-				}
-			}
-		}
+			    struct inode *dir,
+			    struct dentry *dentry,
+			    int nopseudo)/* Don't care about pseudo root mode */
+{
+  int ret = -ENOENT;
+  struct inode *root_inode;
+  struct inode *pseudo_root_inode=NULL;
+  int len = dentry->d_name.len;
+  const char *name = dentry->d_name.name;
+  root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO);
+  /*	pseudo_root_inode = iget( ... ) ? */
+  dentry->d_inode = NULL;
+  umsdos_startlookup(dir);	
+  if (len == 1 && name[0] == '.'){
+    dentry->d_inode = dir;
+    dir->i_count++;
+    ret = 0;
+  }else if (len == 2 && name[0] == '.' && name[1] == '.'){
+    if (pseudo_root && dir == pseudo_root_inode){
+      /* #Specification: pseudo root / .. in real root
+	 Whenever a lookup is those in the real root for
+	 the directory .., and pseudo root is active, the
+	 pseudo root is returned.
+      */
+      ret = 0;
+      dentry->d_inode = pseudo_root;
+      pseudo_root->i_count++;
+    }else{
+      /* #Specification: locating .. / strategy
+	 We use the msdos filesystem to locate the parent directory.
+	 But it is more complicated than that.
+	 
+	 We have to step back even further to
+	 get the parent of the parent, so we can get the EMD
+	 of the parent of the parent. Using the EMD file, we can
+	 locate all the info on the parent, such a permissions
+	 and owner.
+      */
+      
+      ret = compat_umsdos_real_lookup (dir,"..",2,&dentry->d_inode);
+      Printk (("ancestor ret %d dir %p *result %p ",ret,dir,dentry->d_inode));
+      if (ret == 0
+	  && dentry->d_inode != root_inode
+	  && dentry->d_inode != pseudo_root){
+	struct inode *aadir;
+	struct umsdos_dirent entry;
+	ret = umsdos_locate_ancestor (dentry->d_inode,&aadir,&entry);
+	iput (aadir);
+      }
+    }
+  }else if (umsdos_is_pseudodos(dir,dentry)){
+    /* #Specification: pseudo root / lookup(DOS)
+       A lookup of DOS in the pseudo root will always succeed
+       and return the inode of the real root.
+    */
+    dentry->d_inode = root_inode;
+    (dentry->d_inode)->i_count++;
+    ret = 0;
+  }else{
+    struct umsdos_info info;
+    ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
+    if (ret == 0) ret = umsdos_findentry (dir,&info,0);
+    Printk (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret
+	     ,info.fake.len));
+    if (ret == 0){
+      /* #Specification: umsdos / lookup
+	 A lookup for a file is done in two step. First, we locate
+	 the file in the EMD file. If not present, we return
+	 an error code (-ENOENT). If it is there, we repeat the
+	 operation on the msdos file system. If this fails, it means
+	 that the file system is not in sync with the emd file.
+	 We silently remove this entry from the emd file,
+	 and return ENOENT.
+      */
+      struct inode *inode;
+      
+      ret = compat_umsdos_real_lookup (dir,info.fake.fname,info.fake.len,&inode);
+
+      Printk (("umsdos_lookup_x: compat_umsdos_real_lookup for %25s returned %d with inode=%p\n", info.fake.fname, ret, inode));
+
+      if (inode == NULL){
+	printk (KERN_WARNING "UMSDOS: Erase entry %s, out of sync with MsDOS\n"
+		,info.fake.fname);
+	umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
+      }else{
+        Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%d\n",inode->i_ino));
+
+        /* we've found it. now get inode and put it in dentry. Is this ok /mn/ ? */
+        dentry->d_inode = iget(dir->i_sb, inode->i_ino);
+        
+	umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
+	Printk (("lookup ino %ld flags %d\n",inode->i_ino
+		 ,info.entry.flags));
+	if (info.entry.flags & UMSDOS_HLINK){
+	  Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ HLINK\n"));
+	  ret = umsdos_hlink2inode (inode,&dentry->d_inode);
 	}
-	umsdos_endlookup(dir);	
-	iput (dir);
-	return ret;
+	if (pseudo_root && dentry->d_inode == pseudo_root && !nopseudo){
+	  /* #Specification: pseudo root / dir lookup
+	     For the same reason as readdir, a lookup in /DOS for
+	     the pseudo root directory (linux) will fail.
+	  */
+	  /*
+	    This has to be allowed for resolving hard link
+	    which are recorded independently of the pseudo-root
+	    mode.
+	  */
+	  Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n"));
+	  iput (pseudo_root);
+	  dentry->d_inode = NULL;
+	  ret = -ENOENT;
+	}
+      }
+    }
+  }
+  umsdos_endlookup(dir);	
+  iput (dir);
+  Printk ((KERN_DEBUG "umsdos_lookup_x: returning %d\n", ret));
+  return ret;
 }
+
+
 /*
-	Check if a file exist in the current directory.
-	Return 0 if ok, negative error code if not (ex: -ENOENT).
+  Check if a file exist in the current directory.
+  Return 0 if ok, negative error code if not (ex: -ENOENT).
+  
+  
 */
 int UMSDOS_lookup (
-	struct inode *dir,
-	const char *name,
-	int len,
-	struct inode **result)	/* Will hold inode of the file, if successful */
+		   struct inode *dir,
+		   struct dentry *dentry)
 {
-	return umsdos_lookup_x(dir,name,len,result,0);
+  return umsdos_lookup_x(dir,dentry,0);
 }
+
+
+
 /*
-	Locate the inode pointed by a (pseudo) hard link
-	Return 0 if ok, a negative error code if not.
+  Locate the inode pointed by a (pseudo) hard link
+  Return 0 if ok, a negative error code if not.
 */
 int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
 {
-	int ret = -EIO;
-	char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-	*result = NULL;
-	if (path == NULL){
-		ret = -ENOMEM;
-		iput (hlink);
-	}else{
-		struct file filp;
-		filp.f_reada = 1;
-		filp.f_pos = 0;
-		PRINTK (("hlink2inode "));
-		if (umsdos_file_read_kmem (hlink,&filp,path,hlink->i_size)
-			==hlink->i_size){
-			struct inode *dir;
-			char *pt = path;
-			dir = hlink->i_sb->s_mounted;
-			path[hlink->i_size] = '\0';
-			iput (hlink);
-			atomic_inc(&dir->i_count);
-			while (1){
-				char *start = pt;
-				int len;
-				while (*pt != '\0' && *pt != '/') pt++;
-				len = (int)(pt - start);
-				if (*pt == '/') *pt++ = '\0';
-				if (dir->u.umsdos_i.i_emd_dir == 0){
-					/* This is a DOS directory */
-					ret = umsdos_rlookup_x(dir,start,len,result,1);
-				}else{
-					ret = umsdos_lookup_x(dir,start,len,result,1);
-				}
-				PRINTK (("h2n lookup :%s: -> %d ",start,ret));
-				if (ret == 0 && *pt != '\0'){
-					dir = *result;
-				}else{
-					break;
-				}
-			}
-		}else{
-			iput (hlink);
-		}
-		PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result));
-		kfree (path);
-	}
-	return ret;
+  struct inode *root_inode;
+  int ret = -EIO;
+  struct dentry *dentry_src, *dentry_dst;
+  char *path;
+  
+#if 0  	/* FIXME: DELME */
+  Printk (("FIXME: just test. hlink2inode returning -ENOENT\n /mn/\n"));
+  return -ENOENT;	/* /mn/ FIXME just for test */
+#endif
+  
+  path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+
+  root_inode = iget(hlink->i_sb,UMSDOS_ROOT_INO);
+  *result = NULL;
+  if (path == NULL){
+    ret = -ENOMEM;
+    iput (hlink);
+  }else{
+    struct file filp;
+    loff_t offs = 0;
+
+    dentry_src = creat_dentry ("hlink-mn", 8, hlink);
+
+    memset (&filp, 0, sizeof (filp));
+
+    filp.f_pos = 0;
+    filp.f_reada = 1;
+    filp.f_flags = O_RDONLY;
+    filp.f_dentry = dentry_src;
+    filp.f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with dummy values so we won't segfault */
+    
+    Printk (("hlink2inode "));
+    if (umsdos_file_read_kmem (hlink, &filp, path, hlink->i_size, &offs) == hlink->i_size)
+      {
+	struct inode *dir;
+	char *pt = path;
+	dir = root_inode;
+	path[hlink->i_size] = '\0';
+/*	iput (hlink); / * FIXME! /mn/ */
+	dir->i_count++;
+	while (1)
+	  {
+	    char *start = pt;
+	    int len;
+	    while (*pt != '\0' && *pt != '/') pt++;
+	    len = (int)(pt - start);
+	    if (*pt == '/') *pt++ = '\0';
+	    /* FIXME. /mn/ fixed ? */
+
+            dentry_dst = creat_dentry (start, len, NULL);
+
+	    if (dir->u.umsdos_i.i_emd_dir == 0){
+	      /* This is a DOS directory */
+		
+	      Printk (("hlink2inode /mn/: doing umsdos_rlookup_x on %20s\n", dentry_dst->d_name.name));
+	      ret = umsdos_rlookup_x(dir,dentry_dst,1);
+	    }else{
+	      Printk (("hlink2inode /mn/: doing umsdos_lookup_x on %20s\n", dentry_dst->d_name.name));
+	      ret = umsdos_lookup_x(dir,dentry_dst,1);
+	    }
+	    Printk (("  returned %d\n", ret));
+
+	    Printk (("h2n lookup :%s: -> %d ",start,ret));
+	    if (ret == 0 && *pt != '\0'){
+	      dir = dentry_dst->d_inode;
+	    }else{
+	      break;
+	    }
+	  }
+      }else{
+	  Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n"));
+	  iput (hlink); /* FIXME */
+      }
+    Printk (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result));
+    kfree (path);
+  }
+  return ret;
 }
 
+
 static struct file_operations umsdos_dir_operations = {
 	NULL,				/* lseek - default */
-	UMSDOS_dir_read,	/* read */
+	UMSDOS_dir_read,		/* read */
 	NULL,				/* write - bad */
-	UMSDOS_readdir,		/* readdir */
+	UMSDOS_readdir,			/* readdir */
 	NULL,				/* poll - default */
-	UMSDOS_ioctl_dir,	/* ioctl - default */
+	UMSDOS_ioctl_dir,		/* ioctl - default */
 	NULL,				/* mmap */
 	NULL,				/* no special open code */
 	NULL,				/* no special release code */
-	NULL				/* fsync */
+	NULL				/* fsync */	/* in original NULL. changed to file_fsync. FIXME? /mn/ */
 };
 
 struct inode_operations umsdos_dir_inode_operations = {
@@ -811,14 +946,17 @@
 	UMSDOS_mknod,		/* mknod */
 	UMSDOS_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* readpage */
+	NULL,                   /* followlink */
+	generic_readpage,	/* readpage */	/* in original NULL. changed to generic_readpage. FIXME? /mn/ */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	fat_bmap,		/* bmap */	/* in original NULL. changed to fat_bmap. FIXME? /mn/ */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* updatepage */
+	NULL,			/* revalidate */
+	
 };
-
-
 
 
 
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v2.1.86/linux/fs/umsdos/emd.c	Mon Dec  1 10:34:11 1997
+++ linux/fs/umsdos/emd.c	Thu Feb 12 13:36:57 1998
@@ -17,36 +17,141 @@
 
 #include <asm/uaccess.h>
 
+#include <asm/delay.h>
+
 #define PRINTK(x)
 #define Printk(x) printk x
 
 /*
-	Read a file into kernel space memory
-*/
-long umsdos_file_read_kmem (struct inode *inode,
-	struct file *filp,
-	char *buf,
-	unsigned long count)
-{
-	int ret;
-	mm_segment_t old_fs = get_fs();	
-	set_fs (KERNEL_DS);
-	ret = fat_file_read(inode,filp,buf,count);
-	set_fs (old_fs);
-	return ret;
+ * makes dentry. for name name with length len. /mn/
+ * if inode is not NULL, puts it also.
+ *
+ */
+ 
+struct dentry *creat_dentry (const char *name, const int len, const struct inode *inode)
+{
+    struct dentry *ret, *parent=NULL;	/* FIXME /mn/: whatis parent ?? */
+    struct qstr qname;
+    
+    if (inode)
+      Printk (("/mn/ creat_dentry: creating dentry with inode=%d for %20s\n", inode->i_ino, name));
+    else
+      Printk (("/mn/ creat_dentry: creating empty dentry for %20s\n", name));
+
+    qname.name = name;
+    qname.len = len;
+    qname.hash = 0;
+
+    ret = d_alloc (parent,&qname);	/* create new dentry */
+    ret->d_inode = inode;
+}
+
+
+
+/*
+ *	Read a file into kernel space memory
+ *	returns how many bytes read (from fat_file_read)
+ */
+
+ssize_t umsdos_file_read_kmem (struct inode *emd_dir,
+			    struct file *filp,
+			    char *buf,
+			    size_t count,
+			    loff_t *offs
+			    )
+{
+    int ret;
+
+    struct dentry *old_dentry;
+    mm_segment_t old_fs = get_fs();
+
+    set_fs (KERNEL_DS);
+
+    old_dentry=filp->f_dentry;	/* save it */
+    filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir);
+    *offs = filp->f_pos;
+    
+    Printk ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%ld, offs=%p\n", filp, buf, count, offs));
+    Printk ((KERN_DEBUG "  using emd=%d\n", emd_dir->i_ino));
+    Printk ((KERN_DEBUG "  inode=%d, i_size=%d\n", filp->f_dentry->d_inode->i_ino,filp->f_dentry->d_inode->i_size));
+    Printk ((KERN_DEBUG "  ofs=%ld\n", *offs));
+    Printk ((KERN_DEBUG "  f_pos=%ld\n", filp->f_pos));
+    Printk ((KERN_DEBUG "  name=%12s\n", filp->f_dentry->d_name.name));
+    Printk ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
+    Printk ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
+    Printk ((KERN_DEBUG "  f_owner=%d\n", filp->f_owner));
+    Printk ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
+    Printk ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+
+    ret = fat_file_read(filp,buf,count,offs);
+    Printk ((KERN_DEBUG "fat_file_read returned with %ld!\n", ret));
+
+    filp->f_pos = *offs;	/* we needed *filp only for this? grrrr... /mn/ */
+    				/* FIXME: I have no idea what f_pos is used for. It seems to be used this way before offs was introduced.
+    				   this probably needs fixing /mn/ */
+
+    filp->f_dentry=old_dentry;			/* restore orig. dentry (it is dentry of file we need info about. Dunno why it gets passed to us
+    						   since we have no use for it, expect to store totally unrelated data of offset of EMD_FILE
+    						   end not directory in it. But what the hell now... fat_file_read requires it also, but prolly expects
+    						   it to be file* of EMD not file we want to read EMD entry about... ugh. complicated to explain :) /mn/ */
+    						   
+    						 /* FIXME: we probably need to destroy originl filp->f_dentry first ? Do we ? And how ? this way we leave all sorts of dentries, inodes etc. lying around */
+    						 /* Also FIXME: all the same problems in umsdos_file_write_kmem */
+
+    Printk ((KERN_DEBUG "  (ret) using emd=%d\n", emd_dir->i_ino));
+    Printk ((KERN_DEBUG "  (ret) inode=%d, i_size=%d\n", filp->f_dentry->d_inode->i_ino,filp->f_dentry->d_inode->i_size));
+    Printk ((KERN_DEBUG "  (ret) ofs=%ld\n", *offs));
+    Printk ((KERN_DEBUG "  (ret) f_pos=%ld\n", filp->f_pos));
+    Printk ((KERN_DEBUG "  (ret) name=%12s\n", filp->f_dentry->d_name.name));
+    Printk ((KERN_DEBUG "  (ret) i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
+    Printk ((KERN_DEBUG "  (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
+    Printk ((KERN_DEBUG "  (ret) f_owner=%d\n", filp->f_owner));
+    Printk ((KERN_DEBUG "  (ret) f_version=%ld\n", filp->f_version));
+    Printk ((KERN_DEBUG "  (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+
+#if 0
+    {
+      struct umsdos_dirent *mydirent=buf;
+
+      Printk ((KERN_DEBUG "  (DDD) uid=%d\n",mydirent->uid));
+      Printk ((KERN_DEBUG "  (DDD) gid=%d\n",mydirent->gid));
+      Printk ((KERN_DEBUG "  (DDD) name=>%20s<\n",mydirent->name));
+    }
+#endif  
+    
+    set_fs (old_fs);
+    return ret;
 }
+
+
 /*
 	Write to a file from kernel space
 */
-long umsdos_file_write_kmem (struct inode *inode,
-	struct file *filp,
-	const char *buf,
-	unsigned long count)
+ssize_t umsdos_file_write_kmem (struct inode *emd_dir,
+				struct file *filp,
+				const char *buf,
+				size_t  count,
+				loff_t *offs
+				)
 {
 	int ret;
 	mm_segment_t old_fs = get_fs();
+	struct dentry *old_dentry;	/* FIXME /mn/: whatis parent ?? */
+	
 	set_fs (KERNEL_DS);
-	ret = fat_file_write(inode,filp,buf,count);
+	ret = fat_file_write(filp,buf,count,offs);
+
+	old_dentry=filp->f_dentry;	/* save it */
+	filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir);
+
+	*offs = filp->f_pos;
+
+	ret = fat_file_write (filp,buf,count,offs);
+	PRINTK ((KERN_DEBUG "fat_file_write returned with %ld!\n", ret));
+
+	filp->f_pos = *offs;
+	filp->f_dentry=old_dentry;
+
 	set_fs (old_fs);
 	return ret;
 }
@@ -58,12 +163,16 @@
 
 	Return 0 if ok, a negative error code if not.
 */
-long umsdos_emd_dir_write (struct inode *emd_dir,
-	struct file *filp,
-	char *buf,	/* buffer in kernel memory, not in user space */
-	unsigned long count)
+ssize_t umsdos_emd_dir_write (struct inode *emd_dir,
+			   struct file *filp,
+			   char *buf,	/* buffer in kernel memory, not in user space */
+			   size_t  count,
+			   loff_t *offs
+			   )
 {
 	int written;
+	loff_t myofs=0;
+	
 #ifdef __BIG_ENDIAN
 	struct umsdos_dirent *d = (struct umsdos_dirent *)buf;
 #endif
@@ -78,7 +187,11 @@
 	d->rdev = cpu_to_le16 (d->rdev);
 	d->mode = cpu_to_le16 (d->mode);
 #endif	
-	written = umsdos_file_write_kmem (emd_dir,filp,buf,count);
+	
+	if (offs) myofs=*offs;	/* if offs is not NULL, read it */
+	written = umsdos_file_write_kmem (emd_dir, filp, buf, count, &myofs);
+	if (offs) *offs=myofs;	/* if offs is not NULL, store myofs there */
+	
 #ifdef __BIG_ENDIAN	
 	d->nlink = le16_to_cpu (d->nlink);
 	d->uid = le16_to_cpu (d->uid);
@@ -91,25 +204,36 @@
 #endif	
 	return written != count ? -EIO : 0;
 }
+
+
+
 /*
-	Read a block of bytes from one EMD file.
-	The block of data is NOT in user space.
-	Return 0 if ok, -EIO if any error.
-*/
-long umsdos_emd_dir_read (struct inode *emd_dir,
+ *	Read a block of bytes from one EMD file.
+ *	The block of data is NOT in user space.
+ *	Return 0 if ok, -EIO if any error.
+ */
+ 
+ssize_t umsdos_emd_dir_read (struct inode *emd_dir,
 	struct file *filp,
 	char *buf,	/* buffer in kernel memory, not in user space */
-	unsigned long count)
+	size_t count,
+	loff_t *offs
+	)
 {
+	loff_t myofs=0;
 	long int ret = 0;
 	int sizeread;
+	
+	
 #ifdef __BIG_ENDIAN
 	struct umsdos_dirent *d = (struct umsdos_dirent *)buf;
 #endif
+
+	if (offs) myofs=*offs;	/* if offs is not NULL, read it */
 	filp->f_flags = 0;
-	sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count);
+	sizeread = umsdos_file_read_kmem (emd_dir, filp, buf, count, &myofs);
 	if (sizeread != count){
-		printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %ld)\n"
+		printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n"
 			,filp->f_pos,sizeread,count);
 		ret = -EIO;
 	}
@@ -123,49 +247,105 @@
 	d->rdev = le16_to_cpu (d->rdev);
 	d->mode = le16_to_cpu (d->mode);
 #endif	
+	if (offs) *offs=myofs;	/* if offs is not NULL, store myofs there */
 	return ret;
 
 }
+
+
+
+
+/*
+	Locate the EMD file in a directory .
+
+	Return NULL if error. If ok, dir->u.umsdos_i.emd_inode 
+*/
+struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat)
+{
+    struct inode *ret = NULL;
+    int res;
+    Printk (("Entering umsdos_emd_dir_lookup\n"));
+    if (dir->u.umsdos_i.i_emd_dir != 0){
+	ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
+	Printk (("umsdos_emd_dir_lookup: deja trouve %ld %p\n"
+		 ,dir->u.umsdos_i.i_emd_dir,ret));
+    } else {
+      Printk ((KERN_DEBUG "umsdos /mn/: Looking for %20s -", UMSDOS_EMD_FILE));
+      res = compat_umsdos_real_lookup (dir, UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, &ret);
+      Printk ((KERN_DEBUG "-returned %d\n", res));
+	Printk ((KERN_DEBUG "emd_dir_lookup "));
+	if (ret != NULL){
+	    Printk ((KERN_DEBUG "Found --linux "));
+	    dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+	} else if (creat) {
+                        int code;
+                        Printk ((KERN_ERR " * ERROR * /mn/: creat not yet implemented!!!!" ));
+                        Printk ((KERN_DEBUG "avant create "));
+                        atomic_inc(&dir->i_count);
+
+                        code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
+                                ,S_IFREG|0777,&ret);
+                        Printk ((KERN_DEBUG "Creat EMD code %d ret %x ",code,ret));
+                        if (ret != NULL){
+                                dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+                        }else{
+                                printk ("UMSDOS: Can't create EMD file\n");
+                        }
+	}
+	
+	if (ret != NULL){
+	  /* Disable UMSDOS_notify_change() for EMD file */
+	  ret->u.umsdos_i.i_emd_owner = 0xffffffff;
+	}
+
+    }
+    
+    Printk ((KERN_DEBUG "umsdos_emd_dir_lookup returning %p /mn/\n", ret));
+    if (ret != NULL) Printk ((KERN_DEBUG " debug : returning ino=%d\n",ret->i_ino));
+    return ret;
+}
+
 /*
-	Locate the EMD file in a directory and optionally, creates it.
+	creates an EMD file
 
 	Return NULL if error. If ok, dir->u.umsdos_i.emd_inode 
 */
-struct inode *umsdos_emd_dir_lookup(struct inode *dir, int creat)
+
+struct inode *umsdos_emd_dir_create(struct inode *dir, struct dentry *dentry,int mode)
 {
 	struct inode *ret = NULL;
 	if (dir->u.umsdos_i.i_emd_dir != 0){
 		ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
-		PRINTK (("deja trouve %d %x [%d] "
-			,dir->u.umsdos_i.i_emd_dir,ret,
-			 atomic_read(&ret->i_count)));
+		Printk (("deja trouve %d %x",dir->u.umsdos_i.i_emd_dir,ret));
 	}else{
-		umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret);
-		PRINTK (("emd_dir_lookup "));
-		if (ret != NULL){
-			PRINTK (("Find --linux "));
-			dir->u.umsdos_i.i_emd_dir = ret->i_ino;
-		}else if (creat){
-			int code;
-			PRINTK (("avant create "));
-			atomic_inc(&dir->i_count);
-			code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
-				,S_IFREG|0777,&ret);
-			PRINTK (("Creat EMD code %d ret %x ",code,ret));
-			if (ret != NULL){
-				dir->u.umsdos_i.i_emd_dir = ret->i_ino;
-			}else{
-				printk ("UMSDOS: Can't create EMD file\n");
-			}
-		}
+	    
+	    int code;
+	    Printk (("avant create "));
+	    dir->i_count++;
+	    /*			
+	       code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
+	       ,S_IFREG|0777,&ret);
+	       
+	       FIXME, I think I need a new dentry here
+	    */
+	    code = compat_msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN, S_IFREG|0777, &ret);
+	    Printk (("Creat EMD code %d ret %x ",code,ret));
+	    if (ret != NULL){
+		dir->u.umsdos_i.i_emd_dir = ret->i_ino;
+	    }else{
+		printk ("UMSDOS: Can't create EMD file\n");
+	    }
 	}
+
 	if (ret != NULL){
-		/* Disable UMSDOS_notify_change() for EMD file */
-		ret->u.umsdos_i.i_emd_owner = 0xffffffff;
+	    /* Disable UMSDOS_notify_change() for EMD file */
+	    ret->u.umsdos_i.i_emd_owner = 0xffffffff;
 	}
 	return ret;
 }
 
+
+
 /*
 	Read an entry from the EMD file.
 	Support variable length record.
@@ -176,18 +356,28 @@
 	struct file *filp,
 	struct umsdos_dirent *entry)
 {
-	int ret = umsdos_emd_dir_read(emd_dir,filp,(char*)entry,UMSDOS_REC_SIZE);
-	if (ret == 0){
+	int ret;
+	Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n"));
+	Printk (("umsdos_emd_dir_readentry /mn/: trying to lookup %12s (ino=%d) using EMD %d\n", filp->f_dentry->d_name.name, filp->f_dentry->d_inode->i_ino, emd_dir->i_ino));
+    
+	ret = umsdos_emd_dir_read(emd_dir, filp, (char*)entry, UMSDOS_REC_SIZE, NULL);
+	if (ret == 0){ /* note /mn/: is this wrong? ret is allways 0 or -EIO. but who knows. It used to work this way... */
 		/* Variable size record. Maybe, we have to read some more */
 		int recsize = umsdos_evalrecsize (entry->name_len);
+		Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: FIXME if %d > %d?\n",recsize, UMSDOS_REC_SIZE));
 		if (recsize > UMSDOS_REC_SIZE){
-			ret = umsdos_emd_dir_read(emd_dir,filp
-				,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE);
+			ret = umsdos_emd_dir_read(emd_dir, filp
+				,((char*)entry)+UMSDOS_REC_SIZE,recsize - UMSDOS_REC_SIZE,NULL);
 			
 		}
 	}
+	Printk (("umsdos_emd_dir_readentry /mn/: returning %d.\n", ret));
 	return ret;
 }
+
+
+
+
 /*
 	Write an entry in the EMD file.
 	Return 0 if ok, -EIO if some error.
@@ -202,6 +392,12 @@
 	struct file filp;
 	struct umsdos_dirent *entry = &info->entry;
 	struct umsdos_dirent entry0;
+	
+	Printk (("umsdos_writeentry /mn/: entering...\n"));
+	
+	Printk ((KERN_ERR "umsdos_writeentry /mn/: FIXME! this is READ ONLY FOR NOW. RETURNING...\n"));
+	return -EIO;
+	
 	if (free_entry){
 		/* #Specification: EMD file / empty entries
 			Unused entry in the EMD file are identify
@@ -222,15 +418,20 @@
 		*/
 		memset (entry->spare,0,sizeof(entry->spare));
 	}
+
+	Printk (("umsdos_writeentry /mn/: if passed...\n"));
+
 	filp.f_pos = info->f_pos;
 	filp.f_reada = 0;
-	ret = umsdos_emd_dir_write(emd_dir,&filp,(char*)entry,info->recsize);
+	ret = umsdos_emd_dir_write(emd_dir, &filp,(char*)entry,info->recsize,NULL);
 	if (ret != 0){
 		printk ("UMSDOS: problem with EMD file. Can't write\n");
 	}else{
 		dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-		dir->i_dirt = 1;
+		/* dir->i_dirt = 1; FIXME iput/dput ??? */
 	}
+
+	Printk (("umsdos_writeentry /mn/: returning...\n"));
 	return ret;
 }
 
@@ -242,6 +443,10 @@
 	struct file filp;
 };
 
+
+
+
+
 /*
 	Fill the read buffer and take care of the byte remaining inside.
 	Unread bytes are simply move to the beginning.
@@ -256,6 +461,9 @@
 	int mustmove = buf->size - buf->pos;
 	int mustread;
 	int remain;
+	
+	Printk ((KERN_DEBUG "Entering umsdos_fillbuf, for inode %d, buf=%p\n",inode->i_ino, buf));
+	
 	if (mustmove > 0){
 		memcpy (buf->buffer,buf->buffer+buf->pos,mustmove);
 	}
@@ -264,8 +472,8 @@
 	remain = inode->i_size - buf->filp.f_pos;
 	if (remain < mustread) mustread = remain;
 	if (mustread > 0){
-		ret = umsdos_emd_dir_read (inode,&buf->filp,buf->buffer+mustmove
-			,mustread);
+		ret = umsdos_emd_dir_read (inode, &buf->filp,buf->buffer+mustmove
+			,mustread,NULL);
 		if (ret == 0) buf->size = mustmove + mustread;		
 	}else if (mustmove){
 		buf->size = mustmove;
@@ -274,6 +482,8 @@
 	return ret;
 }
 
+
+
 /*
 	General search, locate a name in the EMD file or an empty slot to
 	store it. if info->entry.name_len == 0, search the first empty
@@ -308,6 +518,7 @@
 		record, multiple contiguous record are allocated.
 	*/
 	int ret = -ENOENT;
+	/* FIXME */
 	struct inode *emd_dir = umsdos_emd_dir_lookup(dir,1);
 	if (emd_dir != NULL){
 		struct umsdos_dirent *entry = &info->entry;
@@ -320,10 +531,21 @@
 		}empty;
 		/* Read several entries at a time to speed up the search */
 		struct find_buffer buf;
-		buf.pos = 0;
-		buf.size = 0;
+		struct dentry *dentry;
+
+		memset (&buf.filp, 0, sizeof (buf.filp));
+
+		dentry = creat_dentry ("umsfind-mn", 10, emd_dir);
+	
 		buf.filp.f_pos = 0;
 		buf.filp.f_reada = 1;
+		buf.filp.f_flags = O_RDONLY;
+		buf.filp.f_dentry = dentry;
+        	buf.filp.f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with dummy values so we won't segfault */
+
+		buf.pos = 0;
+		buf.size = 0;
+
 		empty.found = 0;
 		empty.posok = emd_dir->i_size;
 		empty.onesize = 0;
@@ -388,6 +610,7 @@
 	*pt_emd_dir = emd_dir;
 	return ret;
 }
+
 /*
 	Add a new entry in the emd file
 	Return 0 if ok or a negative error code.
@@ -405,11 +628,12 @@
 		ret = -EEXIST;
 	}else if (ret == -ENOENT){
 		ret = umsdos_writeentry(dir,emd_dir,info,0);
-		PRINTK (("umsdos_newentry EDM ret = %d\n",ret));
+		Printk (("umsdos_newentry EDM ret = %d\n",ret));
 	}
 	iput (emd_dir);
 	return ret;
 }
+
 /*
 	Create a new hidden link.
 	Return 0 if ok, an error code if not.
@@ -475,15 +699,24 @@
 */
 int umsdos_isempty (struct inode *dir)
 {
+	struct dentry *dentry;
+	
 	int ret = 2;
 	struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
 	/* If the EMD file does not exist, it is certainly empty :-) */
 	if (emd_dir != NULL){
 		struct file filp;
 		/* Find an empty slot */
+		memset (&filp, 0, sizeof (filp));
+
+		dentry = creat_dentry ("isempty-mn", 10, dir);
+	
 		filp.f_pos = 0;
 		filp.f_reada = 1;
 		filp.f_flags = O_RDONLY;
+		filp.f_dentry = dentry;
+        	filp.f_op = &umsdos_file_operations;	/* /mn/ - we have to fill it with dummy values so we won't segfault */
+        	
 		ret = 1;
 		while (filp.f_pos < emd_dir->i_size){
 			struct umsdos_dirent entry;
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v2.1.86/linux/fs/umsdos/file.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/umsdos/file.c	Thu Feb 12 13:36:57 1998
@@ -21,43 +21,57 @@
 
 #define PRINTK(x)
 #define Printk(x)	printk x
+
+
 /*
 	Read a file into user space memory
 */
-static long UMSDOS_file_read(
-	struct inode *inode,
+static ssize_t UMSDOS_file_read(
 	struct file *filp,
 	char *buf,
-	unsigned long count)
+	size_t  count,
+	loff_t *ppos
+	)
 {
+	struct dentry * dentry = filp->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	
 	/* We have to set the access time because msdos don't care */
-	int ret = fat_file_read(inode,filp,buf,count);
+	/* FIXME */
+	int ret = fat_file_read(filp,buf,count,ppos);
 	if (!IS_RDONLY(inode)){
 		inode->i_atime = CURRENT_TIME;
+		/* FIXME 
 		inode->i_dirt = 1;
+		*/
 	}
 	return ret;
 }
+
+
 /*
 	Write a file from user space memory
 */
-static long UMSDOS_file_write(
-	struct inode *inode,
+static ssize_t UMSDOS_file_write(
 	struct file *filp,
 	const char *buf,
-	unsigned long count)
+	size_t count,
+	loff_t *ppos)
 {
-	return fat_file_write(inode,filp,buf,count);
+	return fat_file_write(filp,buf,count,ppos);
 }
+
+
 /*
 	Truncate a file to 0 length.
 */
 static void UMSDOS_truncate(struct inode *inode)
 {
-	PRINTK (("UMSDOS_truncate\n"));
+	Printk (("UMSDOS_truncate\n"));
 	fat_truncate (inode);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-	inode->i_dirt = 1;
+	
+	/*FIXME	inode->i_dirt = 1; */
 }
 
 /* Function for normal file system (512 bytes hardware sector size) */
@@ -86,18 +100,20 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	fat_bmap,		/* bmap */
-	UMSDOS_truncate,/* truncate */
+	UMSDOS_truncate,	/* truncate */
 	NULL,			/* permission */
 	fat_smap		/* smap */
 };
+
 /* For other with larger and unaligned file system */
 struct file_operations umsdos_file_operations_no_bmap = {
 	NULL,				/* lseek - default */
-	UMSDOS_file_read,	/* read */
-	UMSDOS_file_write,	/* write */
+	UMSDOS_file_read,		/* read */
+	UMSDOS_file_write,		/* write */
 	NULL,				/* readdir - bad */
 	NULL,				/* poll - default */
 	NULL,				/* ioctl - default */
@@ -119,10 +135,11 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,                   /* follow link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
-	UMSDOS_truncate,/* truncate */
+	UMSDOS_truncate,	/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
 };
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.1.86/linux/fs/umsdos/inode.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/umsdos/inode.c	Thu Feb 12 13:36:57 1998
@@ -19,96 +19,116 @@
 #include <linux/stat.h>
 #include <linux/umsdos_fs.h>
 
-struct inode *pseudo_root=NULL;		/* Useful to simulate the pseudo DOS */
-									/* directory. See UMSDOS_readdir_x() */
+struct inode *pseudo_root=NULL;	/* Useful to simulate the pseudo DOS */
+                                /* directory. See UMSDOS_readdir_x() */
 
 /* #Specification: convention / PRINTK Printk and printk
-	Here is the convention for the use of printk inside fs/umsdos
-
-	printk carry important message (error or status).
-	Printk is for debugging (it is a macro defined at the beginning of
-		   most source.
-	PRINTK is a nulled Printk macro.
-
-	This convention makes the source easier to read, and Printk easier
-	to shut off.
+   Here is the convention for the use of printk inside fs/umsdos
+   
+   printk carry important message (error or status).
+   Printk is for debugging (it is a macro defined at the beginning of
+   most source.
+   PRINTK is a nulled Printk macro.
+   
+   This convention makes the source easier to read, and Printk easier
+   to shut off.
 */
 #define PRINTK(x)
 #define Printk(x) printk x
 
-
 void UMSDOS_put_inode(struct inode *inode)
 {
-	PRINTK (("put inode %x owner %x pos %d dir %x\n",inode
-		,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos
-		,inode->u.umsdos_i.i_emd_dir));
-	if (inode != NULL && inode == pseudo_root){
-		printk ("Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
-	}
-	fat_put_inode(inode);
+  Printk ((KERN_DEBUG "put inode %x (%d) owner %x pos %d dir %x\n",inode, inode->i_ino
+	   ,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos
+	   ,inode->u.umsdos_i.i_emd_dir));
+  if (inode && pseudo_root && inode == pseudo_root){
+    printk (KERN_ERR "Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
+  }
+
+#if 1
+  fat_put_inode(inode);
+#else  
+  Printk ((KERN_WARNING "UMSDOS_put_inode: skipping ! FIXME /mn/\n"));
+#endif
 }
 
 
 void UMSDOS_put_super(struct super_block *sb)
 {
-	msdos_put_super(sb);
-	MOD_DEC_USE_COUNT;
+  Printk (("UMSDOS_put_super: /mn/ entering\n"));
+  msdos_put_super(sb);
+  MOD_DEC_USE_COUNT;
 }
 
 
-void UMSDOS_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
-{
-	fat_statfs(sb,buf,bufsiz);
-}
-
 
 /*
-	Call msdos_lookup, but set back the original msdos function table.
-	Return 0 if ok, or a negative error code if not.
+  Call msdos_lookup, but set back the original msdos function table.
+  Return 0 if ok, or a negative error code if not.
 */
 int umsdos_real_lookup (
-	struct inode *dir,
-	const char *name,
-	int len,
-	struct inode **result)	/* Will hold inode of the file, if successful */
-{
-	int ret;
-	atomic_inc(&dir->i_count);
-	ret = msdos_lookup (dir,name,len,result);
-	return ret;
+			struct inode *dir,
+			struct dentry *dentry
+			)	/* Will hold inode of the file, if successful */
+{
+  int ret;
+  
+  Printk (("umsdos_real_lookup /mn/: looking for %s /",dentry->d_name.name));
+  dir->i_count++;  /* /mn/ what is this and why ? locking? */
+  ret = msdos_lookup (dir,dentry);
+  Printk (("/ returned %d\n", ret));
+  
+  return ret;
 }
+
 /*
-	Complete the setup of an directory inode.
-	First, it completes the function pointers, then
-	it locates the EMD file. If the EMD is there, then plug the
-	umsdos function table. If not, use the msdos one.
+  Complete the setup of an directory inode.
+  First, it completes the function pointers, then
+  it locates the EMD file. If the EMD is there, then plug the
+  umsdos function table. If not, use the msdos one.
 */
 void umsdos_setup_dir_inode (struct inode *inode)
 {
-	inode->u.umsdos_i.i_emd_dir = 0;
-	{
-		struct inode *emd_dir = umsdos_emd_dir_lookup (inode,0);
-		extern struct inode_operations umsdos_rdir_inode_operations;
-		inode->i_op = emd_dir != NULL
-			? &umsdos_dir_inode_operations
-			: &umsdos_rdir_inode_operations;
-		iput (emd_dir);
-	}
+  inode->u.umsdos_i.i_emd_dir = 0;
+  {
+    struct inode *emd_dir = NULL;
+    extern struct inode_operations umsdos_rdir_inode_operations;
+
+    emd_dir = umsdos_emd_dir_lookup (inode,0);
+    Printk (("umsdos_setup_dir_inode: umsdos_emd_dir_lookup for inode=%p returned %p\n",inode,emd_dir));
+
+    if (emd_dir == NULL) {
+      Printk (("umsdos_setup_dir_inode /mn/: Setting up dir_inode_ops --> eg. NOT using EMD.\n"));
+      inode->i_op = &umsdos_rdir_inode_operations;
+    } else {
+      Printk (("umsdos_setup_dir_inode /mn/: Setting up rdir_inode_ops --> eg. using EMD.\n"));
+      inode->i_op = &umsdos_dir_inode_operations;
+    }
+    
+    iput (emd_dir);
+  }
 }
+
+
 /*
 	Add some info into an inode so it can find its owner quickly
 */
 void umsdos_set_dirinfo(
-	struct inode *inode,
-	struct inode *dir,
-	off_t f_pos)
-{
-	struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1);
-	inode->u.umsdos_i.i_dir_owner = dir->i_ino;
-	inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
-	iput (emd_owner);
-	inode->u.umsdos_i.pos = f_pos;
+			struct inode *inode,
+			struct inode *dir,
+			off_t f_pos)
+{
+    struct inode *emd_owner;
+    /* FIXME, I don't have a clue on this one */
+    Printk (("umsdos_set_dirinfo: /mn/ FIXME: no clue\n"));
+    emd_owner = umsdos_emd_dir_lookup(dir,1);
+    inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+    inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
+    iput (emd_owner);
+    inode->u.umsdos_i.pos = f_pos;
 }
+
+
 /*
 	Tells if an Umsdos inode has been "patched" once.
 	Return != 0 if so.
@@ -123,80 +143,94 @@
 	return atomic_read(&inode->i_count) > 1;
 #endif
 }
+
+
 /*
-	Connect the proper tables in the inode and add some info.
+  Connect the proper tables in the inode and add some info.
 */
 void umsdos_patch_inode (
-	struct inode *inode,
-	struct inode *dir,		/* May be NULL */
-	off_t f_pos)
-{
-	/*
-		This function is called very early to setup the inode, somewhat
-		too early (called by UMSDOS_read_inode). At this point, we can't
-		do to much, such as lookup up EMD files and so on. This causes
-		confusion in the kernel. This is why some initialisation
-		will be done when dir != NULL only.
-
-		UMSDOS do run piggy back on top of msdos fs. It looks like something
-		is missing in the VFS to accommodate stacked fs. Still unclear what
-		(quite honestly).
-
-		Well, maybe one! A new entry "may_unmount" which would allow
-		the stacked fs to allocate some inode permanently and release
-		them at the end. Doing that now introduce a problem. unmount
-		always fail because some inodes are in use.
-	*/
-	if (!umsdos_isinit(inode)){
-		inode->u.umsdos_i.i_emd_dir = 0;
-		if (S_ISREG(inode->i_mode)){
-			if (inode->i_op->bmap != NULL){
-				inode->i_op = &umsdos_file_inode_operations;
-			}else{
-				inode->i_op = &umsdos_file_inode_operations_no_bmap;
-			}
-		}else if (S_ISDIR(inode->i_mode)){
-			if (dir != NULL){
-				umsdos_setup_dir_inode(inode);
-			}
-		}else if (S_ISLNK(inode->i_mode)){
-			inode->i_op = &umsdos_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);
-		}
-		if (dir != NULL){
-			/* #Specification: inode / umsdos info
-				The first time an inode is seen (inode->i_count == 1),
-				the inode number of the EMD file which control this inode
-				is tagged to this inode. It allows operation such
-				as notify_change to be handled.
-			*/
-			/*
-				This is done last because it also control the
-				status of umsdos_isinit()
-			*/
-			umsdos_set_dirinfo (inode,dir,f_pos);
-		}
-	}else if (dir != NULL){
-		/*
-			Test to see if the info is maintained.
-			This should be removed when the file system will be proven.
-		*/
-		struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1);
-		iput (emd_owner);
-		if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){
-			printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
-				,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner);
-		}
-	}
+			 struct inode *inode,
+			 struct inode *dir,		/* May be NULL */
+			 off_t f_pos)
+{
+  /*
+    This function is called very early to setup the inode, somewhat
+    too early (called by UMSDOS_read_inode). At this point, we can't
+    do to much, such as lookup up EMD files and so on. This causes
+    confusion in the kernel. This is why some initialisation
+    will be done when dir != NULL only.
+    
+    UMSDOS do run piggy back on top of msdos fs. It looks like something
+    is missing in the VFS to accommodate stacked fs. Still unclear what
+    (quite honestly).
+    
+    Well, maybe one! A new entry "may_unmount" which would allow
+    the stacked fs to allocate some inode permanently and release
+    them at the end. Doing that now introduce a problem. unmount
+    always fail because some inodes are in use.
+  */
+  if (!umsdos_isinit(inode)){
+    inode->u.umsdos_i.i_emd_dir = 0;
+    if (S_ISREG(inode->i_mode)){
+      if (inode->i_op->bmap != NULL){
+        Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n"));
+	inode->i_op = &umsdos_file_inode_operations;
+      }else{
+        Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
+	inode->i_op = &umsdos_file_inode_operations_no_bmap;
+      }
+    }else if (S_ISDIR(inode->i_mode)){
+      if (dir != NULL){
+	umsdos_setup_dir_inode(inode);
+      }
+    }else if (S_ISLNK(inode->i_mode)){
+      Printk (("umsdos_patch_inode /mn/: seting i_op = umsdos_symlink_inode_operations\n"));
+      inode->i_op = &umsdos_symlink_inode_operations;
+    }else if (S_ISCHR(inode->i_mode)){
+      Printk (("umsdos_patch_inode /mn/: seting i_op = chrdev_inode_operations\n"));
+      inode->i_op = &chrdev_inode_operations;
+    }else if (S_ISBLK(inode->i_mode)){
+      Printk (("umsdos_patch_inode /mn/: seting i_op = blkdev_inode_operations\n"));
+      inode->i_op = &blkdev_inode_operations;
+    }else if (S_ISFIFO(inode->i_mode)){
+      Printk (("umsdos_patch_inode /mn/: uhm, init_fifo\n"));
+      init_fifo(inode);
+    }
+    if (dir != NULL){
+      /* #Specification: inode / umsdos info
+	 The first time an inode is seen (inode->i_count == 1),
+	 the inode number of the EMD file which control this inode
+	 is tagged to this inode. It allows operation such
+	 as notify_change to be handled.
+      */
+      /*
+	This is done last because it also control the
+	status of umsdos_isinit()
+      */
+      Printk (("umsdos_patch_inode /mn/: here we go: calling umsdos_set_dirinfo (%p,%p,%d)\n", inode, dir, f_pos));
+      umsdos_set_dirinfo (inode,dir,f_pos);
+    }
+  }else if (dir != NULL){
+    /*
+      Test to see if the info is maintained.
+      This should be removed when the file system will be proven.
+    */
+      /* FIXME, again, not a clue */
+      struct inode *emd_owner;
+      Printk (("umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n"));
+      emd_owner = umsdos_emd_dir_lookup(dir,1);
+      iput (emd_owner);
+      if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){
+	  printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
+		  ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner);
+    }
+  }
 }
+
+
 /*
-	Get the inode of the directory which owns this inode.
-	Return 0 if ok, -EIO if error.
+  Get the inode of the directory which owns this inode.
+  Return 0 if ok, -EIO if error.
 */
 int umsdos_get_dirowner(
 	struct inode *inode,
@@ -217,14 +251,17 @@
 	}
 	return ret;
 }
+
+
+
 /*
 	Load an inode from disk.
 */
 void UMSDOS_read_inode(struct inode *inode)
 {
-	PRINTK (("read inode %x ino = %d ",inode,inode->i_ino));
+	Printk (("UMSDOS_read_inode %x ino = %d ",inode,inode->i_ino));
 	msdos_read_inode(inode);
-	PRINTK (("ino = %d %d\n",inode->i_ino,atomic_read(&inode->i_count)));
+	PRINTK (("ino after msdos_read_inode= %d\n",inode->i_ino));
 	if (S_ISDIR(inode->i_mode)
 		&& (inode->u.umsdos_i.u.dir_info.creating != 0
 			|| inode->u.umsdos_i.u.dir_info.looking != 0
@@ -250,6 +287,7 @@
 	umsdos_patch_inode(inode,NULL,0);
 }
 
+
 /*
 	Update the disk with the inode content
 */
@@ -257,7 +295,7 @@
 {
 	struct iattr newattrs;
 
-	PRINTK (("UMSDOS_write_inode emd %d\n",inode->u.umsdos_i.i_emd_owner));
+	PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n",inode->u.umsdos_i.i_emd_owner));
 	fat_write_inode(inode);
 	newattrs.ia_mtime = inode->i_mtime;
 	newattrs.ia_atime = inode->i_atime;
@@ -268,244 +306,288 @@
 		to update the EMD entry associated with this inode.
 		But it has the side effect to re"dirt" the inode.
 	*/
+	/* FIXME, notify_change now takes a dentry, not an
+	   inode so, the emd update needs to be done here
 	UMSDOS_notify_change (inode, &newattrs);
-	inode->i_dirt = 0;
+	*/
+	
+	/* FIXME inode->i_dirt = 0; */
 }
 
-int UMSDOS_notify_change(struct inode *inode, struct iattr *attr)
+int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr)
 {
-	int ret = 0;
-
-	if ((ret = inode_change_ok(inode, attr)) != 0)
-		return ret;
-
-	if (inode->i_nlink > 0){
-		/* #Specification: notify_change / i_nlink > 0
-			notify change is only done for inode with nlink > 0. An inode
-			with nlink == 0 is no longer associated with any entry in
-			the EMD file, so there is nothing to update.
-		*/
-		unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
-		if (inode == inode->i_sb->s_mounted){
-			/* #Specification: root inode / attributes
-				I don't know yet how this should work. Normally
-				the attributes (permissions bits, owner, times) of
-				a directory are stored in the EMD file of its parent.
-
-				One thing we could do is store the attributes of the root
-				inode in its own EMD file. A simple entry named "." could
-				be used for this special case. It would be read once
-				when the file system is mounted and update in
-				UMSDOS_notify_change() (right here).
-
-				I am not sure of the behavior of the root inode for
-				a real UNIX file system. For now, this is a nop.
-			*/
-		}else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){
-			/* This inode is not a EMD file nor an inode used internally
-				by MSDOS, so we can update its status.
-				See emd.c
-			*/
-			struct inode *emd_owner = iget (inode->i_sb,i_emd_owner);
-			PRINTK (("notify change %p ",inode));
-			if (emd_owner == NULL){
-				printk ("UMSDOS: emd_owner = NULL ???");
-				ret = -EPERM;
-			}else{
-				struct file filp;
-				struct umsdos_dirent entry;
-				filp.f_pos = inode->u.umsdos_i.pos;
-				filp.f_reada = 0;
-				PRINTK (("pos = %d ",filp.f_pos));
-				/* Read only the start of the entry since we don't touch */
-				/* the name */
-				ret = umsdos_emd_dir_read (emd_owner,&filp,(char*)&entry
-					,UMSDOS_REC_SIZE);
-				if (ret == 0){
-					if (attr->ia_valid & ATTR_UID)
-						entry.uid = attr->ia_uid;
-					if (attr->ia_valid & ATTR_GID)
-						entry.gid = attr->ia_gid;
-					if (attr->ia_valid & ATTR_MODE)
-						entry.mode = attr->ia_mode;
-					if (attr->ia_valid & ATTR_ATIME)
-						entry.atime = attr->ia_atime;
-					if (attr->ia_valid & ATTR_MTIME)
-						entry.mtime = attr->ia_mtime;
-					if (attr->ia_valid & ATTR_CTIME)
-						entry.ctime = attr->ia_ctime;
-
-					entry.nlink = inode->i_nlink;
-					filp.f_pos = inode->u.umsdos_i.pos;
-					ret = umsdos_emd_dir_write (emd_owner,&filp,(char*)&entry
-						,UMSDOS_REC_SIZE);
-
-					PRINTK (("notify pos %d ret %d nlink %d "
-						,inode->u.umsdos_i.pos
-						,ret,entry.nlink));
-					/* #Specification: notify_change / msdos fs
-						notify_change operation are done only on the
-						EMD file. The msdos fs is not even called.
-					*/
-				}
-				iput (emd_owner);
-			}
-			PRINTK (("\n"));
-		}
+  int ret = 0;
+  struct inode *inode = dentry->d_inode;
+  
+  Printk (("UMSDOS_notify_change: /mn/ completly untested\n"));
+  
+  if ((ret = inode_change_ok(inode, attr)) != 0)
+    return ret;
+  
+  if (inode->i_nlink > 0){
+    /* #Specification: notify_change / i_nlink > 0
+       notify change is only done for inode with nlink > 0. An inode
+       with nlink == 0 is no longer associated with any entry in
+       the EMD file, so there is nothing to update.
+    */
+    unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
+    if (inode == iget(inode->i_sb,UMSDOS_ROOT_INO)){
+      /* #Specification: root inode / attributes
+	 I don't know yet how this should work. Normally
+	 the attributes (permissions bits, owner, times) of
+	 a directory are stored in the EMD file of its parent.
+	 
+	 One thing we could do is store the attributes of the root
+	 inode in its own EMD file. A simple entry named "." could
+	 be used for this special case. It would be read once
+	 when the file system is mounted and update in
+	 UMSDOS_notify_change() (right here).
+	 
+	 I am not sure of the behavior of the root inode for
+	 a real UNIX file system. For now, this is a nop.
+      */
+    }else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){
+      /* This inode is not a EMD file nor an inode used internally
+	 by MSDOS, so we can update its status.
+	 See emd.c
+      */
+      struct inode *emd_owner = iget (inode->i_sb,i_emd_owner);
+      Printk (("notify change %p ",inode));
+      if (emd_owner == NULL){
+	printk ("UMSDOS: emd_owner = NULL ???");
+	ret = -EPERM;
+      }else{
+	struct file filp;
+	struct umsdos_dirent entry;
+	loff_t offs;
+	offs = 0;
+	filp.f_pos = inode->u.umsdos_i.pos;
+	filp.f_reada = 0;
+	Printk (("pos = %d ",filp.f_pos));
+	/* Read only the start of the entry since we don't touch */
+	/* the name */
+	ret = umsdos_emd_dir_read (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs);
+	if (ret == 0){
+	  if (attr->ia_valid & ATTR_UID)
+	    entry.uid = attr->ia_uid;
+	  if (attr->ia_valid & ATTR_GID)
+	    entry.gid = attr->ia_gid;
+	  if (attr->ia_valid & ATTR_MODE)
+	    entry.mode = attr->ia_mode;
+	  if (attr->ia_valid & ATTR_ATIME)
+	    entry.atime = attr->ia_atime;
+	  if (attr->ia_valid & ATTR_MTIME)
+	    entry.mtime = attr->ia_mtime;
+	  if (attr->ia_valid & ATTR_CTIME)
+	    entry.ctime = attr->ia_ctime;
+	  
+	  entry.nlink = inode->i_nlink;
+	  filp.f_pos = inode->u.umsdos_i.pos;
+	  offs = 0; /* FIXME */
+	  ret = umsdos_emd_dir_write (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs);
+	  
+	  Printk (("notify pos %d ret %d nlink %d "
+		   ,inode->u.umsdos_i.pos
+		   ,ret,entry.nlink));
+	  /* #Specification: notify_change / msdos fs
+	     notify_change operation are done only on the
+	     EMD file. The msdos fs is not even called.
+	  */
 	}
-	if (ret == 0)
-		inode_setattr(inode, attr);
-	return ret;
+	iput (emd_owner);
+      }
+      Printk (("\n"));
+    }
+  }
+  if (ret == 0)
+    inode_setattr(inode, attr);
+  return ret;
 }
 
 /* #Specification: function name / convention
-	A simple convention for function name has been used in
-	the UMSDOS file system. First all function use the prefix
-	umsdos_ to avoid name clash with other part of the kernel.
-
-	And standard VFS entry point use the prefix UMSDOS (upper case)
-	so it's easier to tell them apart.
+   A simple convention for function name has been used in
+   the UMSDOS file system. First all function use the prefix
+   umsdos_ to avoid name clash with other part of the kernel.
+   
+   And standard VFS entry point use the prefix UMSDOS (upper case)
+   so it's easier to tell them apart.
+   N.B. (FIXME) PTW, the order and contents of this struct changed
 */
 
 static struct super_operations umsdos_sops = {
-	UMSDOS_read_inode,
-	UMSDOS_notify_change,
-	UMSDOS_write_inode,
-	UMSDOS_put_inode,
-	UMSDOS_put_super,
-	NULL, /* added in 0.96c */
-	UMSDOS_statfs,
-	NULL
+    UMSDOS_read_inode,		/* read_inode */
+    UMSDOS_write_inode,		/* write_inode */
+    UMSDOS_put_inode,		/* put_inode */
+    NULL,			/* delete_inode */ 
+    UMSDOS_notify_change,	/* notify_change */
+    UMSDOS_put_super,		/* put_super */
+    NULL,			/* write_super */
+    fat_statfs,			/* statfs */
+    NULL			/* remount_fs*/
 };
 
 /*
-	Read the super block of an Extended MS-DOS FS.
+  Read the super block of an Extended MS-DOS FS.
 */
 struct super_block *UMSDOS_read_super(
-	struct super_block *s,
-	void *data,
-	int silent)
-{
-	/* #Specification: mount / options
-		Umsdos run on top of msdos. Currently, it supports no
-		mount option, but happily pass all option received to
-		the msdos driver. I am not sure if all msdos mount option
-		make sense with Umsdos. Here are at least those who
-		are useful.
-			uid=
-			gid=
-
-		These options affect the operation of umsdos in directories
-		which do not have an EMD file. They behave like normal
-		msdos directory, with all limitation of msdos.
-	*/
-	struct super_block *sb;
-	MOD_INC_USE_COUNT;
-	sb = msdos_read_super(s,data,silent);
-	printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n"
-		,UMSDOS_VERSION,UMSDOS_RELEASE);
-	if (sb != NULL){
-		MSDOS_SB(sb)->options.dotsOK = 0;  /* disable hidden==dotfile */
-		sb->s_op = &umsdos_sops;
-		PRINTK (("umsdos_read_super %p\n",sb->s_mounted));
-		umsdos_setup_dir_inode (sb->s_mounted);
-		PRINTK (("End umsdos_read_super\n"));
-		if (s == super_blocks){
-			/* #Specification: pseudo root / mount
-				When a umsdos fs is mounted, a special handling is done
-				if it is the root partition. We check for the presence
-				of the file /linux/etc/init or /linux/etc/rc or
-				/linux/sbin/init. If one is there, we do a chroot("/linux").
-
-				We check both because (see init/main.c) the kernel
-				try to exec init at different place and if it fails
-				it tries /bin/sh /etc/rc. To be consistent with
-				init/main.c, many more test would have to be done
-				to locate init. Any complain ?
-
-				The chroot is done manually in init/main.c but the
-				info (the inode) is located at mount time and store
-				in a global variable (pseudo_root) which is used at
-				different place in the umsdos driver. There is no
-				need to store this variable elsewhere because it
-				will always be one, not one per mount.
-
-				This feature allows the installation
-				of a linux system within a DOS system in a subdirectory.
-
-				A user may install its linux stuff in c:\linux
-				avoiding any clash with existing DOS file and subdirectory.
-				When linux boots, it hides this fact, showing a normal
-				root directory with /etc /bin /tmp ...
-
-				The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
-				in the macro UMSDOS_PSDROOT_NAME.
-			*/
-
-			struct inode *pseudo;
-			Printk (("Mounting root\n"));
-			if (umsdos_real_lookup (sb->s_mounted,UMSDOS_PSDROOT_NAME
-					,UMSDOS_PSDROOT_LEN,&pseudo)==0
-				&& S_ISDIR(pseudo->i_mode)){
-				struct inode *etc = NULL;
-				struct inode *sbin = NULL;
-				int pseudo_ok = 0;
-				Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME));
-				if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0
-					&& S_ISDIR(etc->i_mode)){
-					struct inode *init = NULL;
-					struct inode *rc = NULL;
-					Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
-					if ((umsdos_real_lookup (etc,"init",4,&init)==0
-							&& S_ISREG(init->i_mode))
-						|| (umsdos_real_lookup (etc,"rc",2,&rc)==0
-							&& S_ISREG(rc->i_mode))){
-						pseudo_ok = 1;
-					}
-					iput (init);
-					iput (rc);
-				}
-				if (!pseudo_ok
-					&& umsdos_real_lookup (pseudo,"sbin",4,&sbin)==0
-					&& S_ISDIR(sbin->i_mode)){
-					struct inode *init = NULL;
-					Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME));
-					if (umsdos_real_lookup (sbin,"init",4,&init)==0
-							&& S_ISREG(init->i_mode)){
-						pseudo_ok = 1;
-					}
-					iput (init);
-				}
-				if (pseudo_ok){
-					umsdos_setup_dir_inode (pseudo);
-					Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
-					pseudo_root = pseudo;
-					atomic_inc(&pseudo->i_count);
-					pseudo = NULL;
-				}
-				iput (sbin);
-				iput (etc);
-			}
-			iput (pseudo);
-		}
-	} else {
-		MOD_DEC_USE_COUNT;
+				      struct super_block *sb,
+				      void *data,
+				      int silent)
+{
+  /* #Specification: mount / options
+     Umsdos run on top of msdos. Currently, it supports no
+     mount option, but happily pass all option received to
+     the msdos driver. I am not sure if all msdos mount option
+     make sense with Umsdos. Here are at least those who
+     are useful.
+     uid=
+     gid=
+     
+     These options affect the operation of umsdos in directories
+     which do not have an EMD file. They behave like normal
+     msdos directory, with all limitation of msdos.
+  */
+    struct super_block *res;
+    struct inode *pseudo=NULL;
+    Printk (("UMSDOS /mn/: starting UMSDOS_read_super\n"));
+    MOD_INC_USE_COUNT;
+    Printk (("UMSDOS /mn/: sb = %p\n",sb));
+    res = msdos_read_super(sb,data,silent);
+    Printk (("UMSDOS /mn/: res = %p\n",res));
+    printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
+	  
+    if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; }
+
+    MSDOS_SB(res)->options.dotsOK = 0;  /* disable hidden==dotfile */
+    res->s_op = &umsdos_sops;
+    Printk (("umsdos /mn/: here goes the iget ROOT_INO\n"));
+
+    pseudo = iget(res,UMSDOS_ROOT_INO); 		
+    Printk (("umsdos_read_super %p\n",pseudo));
+
+    umsdos_setup_dir_inode (pseudo);
+    
+#if 0	/* disabled /mn/ test FIXME */    
+
+    /* if (s == super_blocks){ FIXME, super_blocks no longer exported */
+    if(pseudo) {
+      /* #Specification: pseudo root / mount
+	 When a umsdos fs is mounted, a special handling is done
+	 if it is the root partition. We check for the presence
+	 of the file /linux/etc/init or /linux/etc/rc or
+	 /linux/sbin/init. If one is there, we do a chroot("/linux").
+	 
+	 We check both because (see init/main.c) the kernel
+	 try to exec init at different place and if it fails
+	 it tries /bin/sh /etc/rc. To be consistent with
+	 init/main.c, many more test would have to be done
+	 to locate init. Any complain ?
+	 
+	 The chroot is done manually in init/main.c but the
+	 info (the inode) is located at mount time and store
+	 in a global variable (pseudo_root) which is used at
+	 different place in the umsdos driver. There is no
+	 need to store this variable elsewhere because it
+	 will always be one, not one per mount.
+	 
+	 This feature allows the installation
+	 of a linux system within a DOS system in a subdirectory.
+	 
+	 A user may install its linux stuff in c:\linux
+	 avoiding any clash with existing DOS file and subdirectory.
+	 When linux boots, it hides this fact, showing a normal
+	 root directory with /etc /bin /tmp ...
+	 
+	 The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
+	 in the macro UMSDOS_PSDROOT_NAME.
+      */
+      struct dentry *root, *etc, *etc_rc, *init, *sbin; /* FIXME */
+
+      root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL);
+      sbin = creat_dentry ("sbin", 4, NULL);
+      
+      Printk (("Mounting root\n"));
+      if (umsdos_real_lookup (pseudo,root)==0
+          && (root->d_inode != NULL)
+	  && S_ISDIR(root->d_inode->i_mode)){
+	
+	int pseudo_ok = 0;
+	Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME));
+	etc = creat_dentry ("etc", 3, NULL);
+	
+	
+	/* if (umsdos_real_lookup (pseudo,"etc",3,etc)==0 */
+	if(umsdos_real_lookup(pseudo, etc) == 0
+	   && S_ISDIR(etc->d_inode->i_mode)){
+
+	    Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
+	    
+	    init = creat_dentry ("init", 4, NULL);
+	    etc_rc = creat_dentry ("rc", 2, NULL);
+	  
+	    /* if ((umsdos_real_lookup (etc,"init",4,init)==0*/
+	    if((umsdos_real_lookup(pseudo, init) == 0
+		&& S_ISREG(init->d_inode->i_mode))
+	       /*	|| (umsdos_real_lookup (etc,"rc",2,&rc)==0*/
+	       || (umsdos_real_lookup(pseudo, etc_rc) == 0
+		   && S_ISREG(etc_rc->d_inode->i_mode))){
+		pseudo_ok = 1;
+	  }
+	    /* FIXME !!!!!! */
+	    /* iput(init); */
+	    /* iput(rc); */
 	}
-	return sb;
+	if (!pseudo_ok
+	/* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0*/
+	    && umsdos_real_lookup(pseudo, sbin) == 0
+	    && S_ISDIR(sbin->d_inode->i_mode)){
+	  
+	  Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME));
+	  /* if (umsdos_real_lookup (sbin,"init",4,init)==0 */
+	  if(umsdos_real_lookup(pseudo, init) == 0	
+	     && S_ISREG(init->d_inode->i_mode)){
+	    pseudo_ok = 1;
+	  }
+	  /* FIXME !!! 
+	     iput (init); */
+	}
+	if (pseudo_ok){
+	  umsdos_setup_dir_inode (pseudo);
+	  Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
+	  pseudo_root = pseudo;
+	  pseudo->i_count++;
+	  pseudo = NULL;
+	}
+	/* FIXME 
+	
+	iput (sbin);
+	iput (etc);
+	*/
+      }
+      
+      Printk (("umsdos_read_super /mn/: Pseudo should be iput-ed here...\n"));
+
+      iput (pseudo); /* FIXME */
+    }
+
+#endif /* disabled */
+
+    Printk (("umsdos_read_super /mn/: returning %p\n",res));
+    return res;
 }
 
 
 
 static struct file_system_type umsdos_fs_type = {
-	"umsdos",
-	FS_REQUIRES_DEV,
-	UMSDOS_read_super,
-	NULL
+  "umsdos",
+  FS_REQUIRES_DEV,
+  UMSDOS_read_super,
+  NULL
 };
 
 __initfunc(int init_umsdos_fs(void))
 {
-	return register_filesystem(&umsdos_fs_type);
+  return register_filesystem(&umsdos_fs_type);
 }
 
 #ifdef MODULE
@@ -513,12 +595,12 @@
 
 int init_module(void)
 {
-	return init_umsdos_fs();
+  return init_umsdos_fs();
 }
 
 void cleanup_module(void)
 {
-	unregister_filesystem(&umsdos_fs_type);
+  unregister_filesystem(&umsdos_fs_type);
 }
 
 #endif
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v2.1.86/linux/fs/umsdos/ioctl.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/umsdos/ioctl.c	Thu Feb 12 13:36:57 1998
@@ -34,18 +34,18 @@
 	off_t offset,
 	ino_t ino)
 {
-	int ret = -EINVAL;
-	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
-	if (d->count == 0){
-		copy_to_user (d->ent->d_name,name,name_len);
-		put_user ('\0',d->ent->d_name+name_len);
-		put_user (name_len,&d->ent->d_reclen);
-		put_user (ino,&d->ent->d_ino);
-		put_user (offset,&d->ent->d_off);
-		d->count = 1;
-		ret = 0;
-	}
-	return ret;
+  int ret = -EINVAL;
+  struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
+  if (d->count == 0){
+    copy_to_user (d->ent->d_name,name,name_len);
+    put_user ('\0',d->ent->d_name+name_len);
+    put_user (name_len,&d->ent->d_reclen);
+    put_user (ino,&d->ent->d_ino);
+    put_user (offset,&d->ent->d_off);
+    d->count = 1;
+    ret = 0;
+  }
+  return ret;
 }
 
 
@@ -53,266 +53,281 @@
 	Perform special function on a directory
 */
 int UMSDOS_ioctl_dir (
-	struct inode *dir,
-	struct file *filp,
-	unsigned int cmd,
-	unsigned long data)
+		      struct inode *dir,
+		      struct file *filp,
+		      unsigned int cmd,
+		      unsigned long data)
 {
-	int ret = -EPERM;
-	int err;
-	/* #Specification: ioctl / acces
-		Only root (effective id) is allowed to do IOCTL on directory
-		in UMSDOS. EPERM is returned for other user.
+  int ret = -EPERM;
+  int err;
+  /* #Specification: ioctl / acces
+     Only root (effective id) is allowed to do IOCTL on directory
+     in UMSDOS. EPERM is returned for other user.
+  */
+  /*
+    Well, not all cases require write access, but it simplifies
+    the code, and let's face it, there is only one client (umssync)
+    for all this.
+  */
+  if ((err = verify_area(VERIFY_WRITE,(void*)data,sizeof(struct umsdos_ioctl))) < 0) {
+    ret = err;
+  }else if (current->euid == 0
+	    || cmd == UMSDOS_GETVERSION){
+    struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data;
+    ret = -EINVAL;
+    /* #Specification: ioctl / prototypes
+       The official prototype for the umsdos ioctl on directory
+       is:
+       
+       int ioctl (
+       int fd,		// File handle of the directory
+       int cmd,	// command
+       struct umsdos_ioctl *data)
+       
+       The struct and the commands are defined in linux/umsdos_fs.h.
+       
+       umsdos_progs/umsdosio.c provide an interface in C++ to all
+       these ioctl. umsdos_progs/udosctl is a small utility showing
+       all this.
+       
+       These ioctl generally allow one to work on the EMD or the
+       DOS directory independently. These are essential to implement
+       the synchronise.
+    */
+    Printk (("ioctl %d ",cmd));
+    if (cmd == UMSDOS_GETVERSION){
+      /* #Specification: ioctl / UMSDOS_GETVERSION
+	 The field version and release of the structure
+	 umsdos_ioctl are filled with the version and release
+	 number of the fs code in the kernel. This will allow
+	 some form of checking. Users won't be able to run
+	 incompatible utility such as the synchroniser (umssync).
+	 umsdos_progs/umsdosio.c enforce this checking.
+	 
+	 Return always 0.
+      */
+      put_user(UMSDOS_VERSION,&idata->version);
+      put_user(UMSDOS_RELEASE,&idata->release);
+      ret = 0;
+    }else if (cmd == UMSDOS_READDIR_DOS){
+      /* #Specification: ioctl / UMSDOS_READDIR_DOS
+	 One entry is read from the DOS directory at the current
+	 file position. The entry is put as is in the dos_dirent
+	 field of struct umsdos_ioctl.
+	 
+	 Return > 0 if success.
+      */
+      struct UMSDOS_DIR_ONCE bufk;
+      bufk.count = 0;
+      bufk.ent = &idata->dos_dirent;
+  
+      fat_readdir(filp,&bufk,umsdos_ioctl_fill); 
+     
+      ret = bufk.count == 1 ? 1 : 0;
+    }else if (cmd == UMSDOS_READDIR_EMD){
+      /* #Specification: ioctl / UMSDOS_READDIR_EMD
+	 One entry is read from the EMD at the current
+	 file position. The entry is put as is in the umsdos_dirent
+	 field of struct umsdos_ioctl. The corresponding mangled
+	 DOS entry name is put in the dos_dirent field.
+	 
+	 All entries are read including hidden links. Blank
+	 entries are skipped.
+	 
+	 Return > 0 if success.
+      */
+      struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0);
+      if (emd_dir != NULL){
+	while (1){
+	  if (filp->f_pos >= emd_dir->i_size){
+	    ret = 0;
+	    break;
+	  }else{
+	    struct umsdos_dirent entry;
+	    off_t f_pos = filp->f_pos;
+	    ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry);
+	    if (ret < 0){
+	      break;
+	    }else if (entry.name_len > 0){
+	      struct umsdos_info info;
+	      ret = entry.name_len;
+	      umsdos_parse (entry.name,entry.name_len,&info);
+	      info.f_pos = f_pos;
+	      umsdos_manglename(&info);
+	      copy_to_user(&idata->umsdos_dirent,&entry
+			   ,sizeof(entry));
+	      copy_to_user(&idata->dos_dirent.d_name
+			   ,info.fake.fname,info.fake.len+1);
+	      break;
+	    }
+	  }
+	}
+	iput (emd_dir);
+      }else{
+				/* The absence of the EMD is simply seen as an EOF */
+	ret = 0;
+      }
+    }else if (cmd == UMSDOS_INIT_EMD){
+      /* #Specification: ioctl / UMSDOS_INIT_EMD
+	 The UMSDOS_INIT_EMD command make sure the EMD
+	 exist for a directory. If it does not, it is
+	 created. Also, it makes sure the directory functions
+	 table (struct inode_operations) is set to the UMSDOS
+	 semantic. This mean that umssync may be applied to
+	 an "opened" msdos directory, and it will change behavior
+	 on the fly.
+	 
+	 Return 0 if success.
+      */
+      extern struct inode_operations umsdos_rdir_inode_operations;
+      struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1);
+      ret = emd_dir != NULL;
+      iput (emd_dir);
+      
+      dir->i_op = ret
+	? &umsdos_dir_inode_operations
+	: &umsdos_rdir_inode_operations;
+    }else{
+      struct umsdos_ioctl data;
+      copy_from_user (&data,idata,sizeof(data));
+      if (cmd == UMSDOS_CREAT_EMD){
+	/* #Specification: ioctl / UMSDOS_CREAT_EMD
+	   The umsdos_dirent field of the struct umsdos_ioctl is used
+	   as is to create a new entry in the EMD of the directory.
+	   The DOS directory is not modified.
+	   No validation is done (yet).
+	   
+	   Return 0 if success.
+	*/
+	struct umsdos_info info;
+	/* This makes sure info.entry and info in general is correctly */
+	/* initialised */
+	memcpy (&info.entry,&data.umsdos_dirent
+		,sizeof(data.umsdos_dirent));
+	umsdos_parse (data.umsdos_dirent.name
+		      ,data.umsdos_dirent.name_len,&info);
+	ret = umsdos_newentry (dir,&info);
+      }else if (cmd == UMSDOS_RENAME_DOS){
+	struct dentry *old_dentry,*new_dentry; /* FIXME */
+	/* #Specification: ioctl / UMSDOS_RENAME_DOS
+	   A file or directory is rename in a DOS directory
+	   (not moved across directory). The source name
+	   is in the dos_dirent.name field and the destination
+	   is in umsdos_dirent.name field.
+	   
+	   This ioctl allows umssync to rename a mangle file
+	   name before syncing it back in the EMD.
 	*/
+	dir->i_count+=2;
 	/*
-		Well, not all cases require write access, but it simplifies
-		the code, and let's face it, there is only one client (umssync)
-		for all this.
+	  ret = msdos_rename (dir
+	  ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
+	  ,dir
+	  ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
 	*/
-	if ((err = verify_area(VERIFY_WRITE,(void*)data,sizeof(struct umsdos_ioctl))) < 0) {
-		ret = err;
-	}else if (current->euid == 0
-		|| cmd == UMSDOS_GETVERSION){
-		struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data;
-		ret = -EINVAL;
-		/* #Specification: ioctl / prototypes
-			The official prototype for the umsdos ioctl on directory
-			is:
-
-			int ioctl (
-				int fd,		// File handle of the directory
-				int cmd,	// command
-				struct umsdos_ioctl *data)
-
-			The struct and the commands are defined in linux/umsdos_fs.h.
-
-			umsdos_progs/umsdosio.c provide an interface in C++ to all
-			these ioctl. umsdos_progs/udosctl is a small utility showing
-			all this.
-
-			These ioctl generally allow one to work on the EMD or the
-			DOS directory independently. These are essential to implement
-			the synchronise.
-		*/
-		PRINTK (("ioctl %d ",cmd));
-		if (cmd == UMSDOS_GETVERSION){
-			/* #Specification: ioctl / UMSDOS_GETVERSION
-				The field version and release of the structure
-				umsdos_ioctl are filled with the version and release
-				number of the fs code in the kernel. This will allow
-				some form of checking. Users won't be able to run
-				incompatible utility such as the synchroniser (umssync).
-				umsdos_progs/umsdosio.c enforce this checking.
-
-				Return always 0.
-			*/
-			put_user(UMSDOS_VERSION,&idata->version);
-			put_user(UMSDOS_RELEASE,&idata->release);
-			ret = 0;
-		}else if (cmd == UMSDOS_READDIR_DOS){
-			/* #Specification: ioctl / UMSDOS_READDIR_DOS
-				One entry is read from the DOS directory at the current
-				file position. The entry is put as is in the dos_dirent
-				field of struct umsdos_ioctl.
-
-				Return > 0 if success.
-			*/
-			struct UMSDOS_DIR_ONCE bufk;
-			bufk.count = 0;
-			bufk.ent = &idata->dos_dirent;
-			fat_readdir(dir,filp,&bufk,umsdos_ioctl_fill);
-			ret = bufk.count == 1 ? 1 : 0;
-		}else if (cmd == UMSDOS_READDIR_EMD){
-			/* #Specification: ioctl / UMSDOS_READDIR_EMD
-				One entry is read from the EMD at the current
-				file position. The entry is put as is in the umsdos_dirent
-				field of struct umsdos_ioctl. The corresponding mangled
-				DOS entry name is put in the dos_dirent field.
-
-				All entries are read including hidden links. Blank
-				entries are skipped.
-
-				Return > 0 if success.
-			*/
-			struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0);
-			if (emd_dir != NULL){
-				while (1){
-					if (filp->f_pos >= emd_dir->i_size){
-						ret = 0;
-						break;
-					}else{
-						struct umsdos_dirent entry;
-						off_t f_pos = filp->f_pos;
-						ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry);
-						if (ret < 0){
-							break;
-						}else if (entry.name_len > 0){
-							struct umsdos_info info;
-							ret = entry.name_len;
-							umsdos_parse (entry.name,entry.name_len,&info);
-							info.f_pos = f_pos;
-							umsdos_manglename(&info);
-							copy_to_user(&idata->umsdos_dirent,&entry
-								,sizeof(entry));
-							copy_to_user(&idata->dos_dirent.d_name
-								,info.fake.fname,info.fake.len+1);
-							break;
-						}
-					}
-				}
-				iput (emd_dir);
-			}else{
-				/* The absence of the EMD is simply seen as an EOF */
-				ret = 0;
-			}
-		}else if (cmd == UMSDOS_INIT_EMD){
-			/* #Specification: ioctl / UMSDOS_INIT_EMD
-				The UMSDOS_INIT_EMD command make sure the EMD
-				exist for a directory. If it does not, it is
-				created. Also, it makes sure the directory functions
-				table (struct inode_operations) is set to the UMSDOS
-				semantic. This mean that umssync may be applied to
-				an "opened" msdos directory, and it will change behavior
-				on the fly.
-
-				Return 0 if success.
-			*/
-			extern struct inode_operations umsdos_rdir_inode_operations;
-			struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1);
-			ret = emd_dir != NULL;
-			iput (emd_dir);
-					
-			dir->i_op = ret
-				? &umsdos_dir_inode_operations
-				: &umsdos_rdir_inode_operations;
-		}else{
-			struct umsdos_ioctl data;
-			copy_from_user (&data,idata,sizeof(data));
-			if (cmd == UMSDOS_CREAT_EMD){
-				/* #Specification: ioctl / UMSDOS_CREAT_EMD
-					The umsdos_dirent field of the struct umsdos_ioctl is used
-					as is to create a new entry in the EMD of the directory.
-					The DOS directory is not modified.
-					No validation is done (yet).
-
-					Return 0 if success.
-				*/
-				struct umsdos_info info;
-				/* This makes sure info.entry and info in general is correctly */
-				/* initialised */
-				memcpy (&info.entry,&data.umsdos_dirent
-					,sizeof(data.umsdos_dirent));
-				umsdos_parse (data.umsdos_dirent.name
-					,data.umsdos_dirent.name_len,&info);
-				ret = umsdos_newentry (dir,&info);
-			}else if (cmd == UMSDOS_RENAME_DOS){
-				/* #Specification: ioctl / UMSDOS_RENAME_DOS
-					A file or directory is rename in a DOS directory
-					(not moved across directory). The source name
-					is in the dos_dirent.name field and the destination
-					is in umsdos_dirent.name field.
-
-					This ioctl allows umssync to rename a mangle file
-					name before syncing it back in the EMD.
-				*/
-				atomic_add(2, &dir->i_count);
-				ret = msdos_rename (dir
-					,data.dos_dirent.d_name,data.dos_dirent.d_reclen
-					,dir
-					,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
-			}else if (cmd == UMSDOS_UNLINK_EMD){
-				/* #Specification: ioctl / UMSDOS_UNLINK_EMD
-					The umsdos_dirent field of the struct umsdos_ioctl is used
-					as is to remove an entry from the EMD of the directory.
-					No validation is done (yet). The mode field is used
-					to validate S_ISDIR or S_ISREG.
-
-					Return 0 if success.
-				*/
-				struct umsdos_info info;
-				/* This makes sure info.entry and info in general is correctly */
-				/* initialised */
-				memcpy (&info.entry,&data.umsdos_dirent
-					,sizeof(data.umsdos_dirent));
-				umsdos_parse (data.umsdos_dirent.name
-					,data.umsdos_dirent.name_len,&info);
-				ret = umsdos_delentry (dir,&info
-					,S_ISDIR(data.umsdos_dirent.mode));
-			}else if (cmd == UMSDOS_UNLINK_DOS){
-				/* #Specification: ioctl / UMSDOS_UNLINK_DOS
-					The dos_dirent field of the struct umsdos_ioctl is used to
-					execute a msdos_unlink operation. The d_name and d_reclen
-					fields are used.
-
-					Return 0 if success.
-				*/
-				atomic_inc(&dir->i_count);
-				ret = msdos_unlink (dir,data.dos_dirent.d_name
-					,data.dos_dirent.d_reclen);
-			}else if (cmd == UMSDOS_RMDIR_DOS){
-				/* #Specification: ioctl / UMSDOS_RMDIR_DOS
-					The dos_dirent field of the struct umsdos_ioctl is used to
-					execute a msdos_unlink operation. The d_name and d_reclen
-					fields are used.
-
-					Return 0 if success.
-				*/
-				atomic_inc(&dir->i_count);
-				ret = msdos_rmdir (dir,data.dos_dirent.d_name
-					,data.dos_dirent.d_reclen);
-			}else if (cmd == UMSDOS_STAT_DOS){
-				/* #Specification: ioctl / UMSDOS_STAT_DOS
-					The dos_dirent field of the struct umsdos_ioctl is
-					used to execute a stat operation in the DOS directory.
-					The d_name and d_reclen fields are used.
-
-					The following field of umsdos_ioctl.stat are filled.
-
-					st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
-					Return 0 if success.
-				*/
-				struct inode *inode;
-				ret = umsdos_real_lookup (dir,data.dos_dirent.d_name
-					,data.dos_dirent.d_reclen,&inode);
-				if (ret == 0){
-					data.stat.st_ino = inode->i_ino;
-					data.stat.st_mode = inode->i_mode;
-					data.stat.st_size = inode->i_size;
-					data.stat.st_atime = inode->i_atime;
-					data.stat.st_ctime = inode->i_ctime;
-					data.stat.st_mtime = inode->i_mtime;
-					copy_to_user (&idata->stat,&data.stat,sizeof(data.stat));
-					iput (inode);
-				}
-			}else if (cmd == UMSDOS_DOS_SETUP){
-				/* #Specification: ioctl / UMSDOS_DOS_SETUP
-					The UMSDOS_DOS_SETUP ioctl allow changing the
-					default permission of the MsDOS file system driver
-					on the fly. The MsDOS driver apply global permission
-					to every file and directory. Normally these permissions
-					are controlled by a mount option. This is not
-					available for root partition, so a special utility
-					(umssetup) is provided to do this, normally in
-					/etc/rc.local.
-
-					Be aware that this apply ONLY to MsDOS directory
-					(those without EMD --linux-.---). Umsdos directory
-					have independent (standard) permission for each
-					and every file.
-
-					The field umsdos_dirent provide the information needed.
-					umsdos_dirent.uid and gid sets the owner and group.
-					umsdos_dirent.mode set the permissions flags.
-				*/
-				dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
-				dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
-				dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
-				ret = 0;
-			}
-		}
+	old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL);
+	new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL);
+	ret = msdos_rename(dir,old_dentry,dir,new_dentry);
+      }else if (cmd == UMSDOS_UNLINK_EMD){
+       /* #Specification: ioctl / UMSDOS_UNLINK_EMD
+	  The umsdos_dirent field of the struct umsdos_ioctl is used
+	  as is to remove an entry from the EMD of the directory.
+	  No validation is done (yet). The mode field is used
+	  to validate S_ISDIR or S_ISREG.
+	  
+	  Return 0 if success.
+       */
+	struct umsdos_info info;
+       /* This makes sure info.entry and info in general is correctly */
+       /* initialised */
+	memcpy (&info.entry,&data.umsdos_dirent
+		,sizeof(data.umsdos_dirent));
+	umsdos_parse (data.umsdos_dirent.name
+		      ,data.umsdos_dirent.name_len,&info);
+	ret = umsdos_delentry (dir,&info
+			       ,S_ISDIR(data.umsdos_dirent.mode));
+      }else if (cmd == UMSDOS_UNLINK_DOS){
+	struct dentry *dentry; /* FIXME */
+	/* #Specification: ioctl / UMSDOS_UNLINK_DOS
+	   The dos_dirent field of the struct umsdos_ioctl is used to
+	   execute a msdos_unlink operation. The d_name and d_reclen
+	   fields are used.
+	   
+	   Return 0 if success.
+	*/
+	dir->i_count++;
+	/*
+	  ret = msdos_unlink (dir,data.dos_dirent.d_name,data.dos_dirent.d_reclen);
+	*/
+	ret = msdos_unlink(dir,dentry);
+      }else if (cmd == UMSDOS_RMDIR_DOS){
+	struct dentry *dentry; /* FIXME */
+	/* #Specification: ioctl / UMSDOS_RMDIR_DOS
+	   The dos_dirent field of the struct umsdos_ioctl is used to
+	   execute a msdos_unlink operation. The d_name and d_reclen
+	   fields are used.
+	   
+	   Return 0 if success.
+	*/
+	dir->i_count++;
+	/*
+	  ret = msdos_rmdir (dir,data.dos_dirent.d_name
+	  ,data.dos_dirent.d_reclen);
+	*/
+	ret = msdos_rmdir(dir,dentry);
+      }else if (cmd == UMSDOS_STAT_DOS){
+       /* #Specification: ioctl / UMSDOS_STAT_DOS
+	  The dos_dirent field of the struct umsdos_ioctl is
+	  used to execute a stat operation in the DOS directory.
+	  The d_name and d_reclen fields are used.
+	  
+	  The following field of umsdos_ioctl.stat are filled.
+	  
+	  st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
+	  Return 0 if success.
+       */
+	struct inode *inode;
+
+	  ret = compat_umsdos_real_lookup (dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen, &inode);
+	if (ret == 0){
+	  data.stat.st_ino = inode->i_ino;
+	  data.stat.st_mode = inode->i_mode;
+	  data.stat.st_size = inode->i_size;
+	  data.stat.st_atime = inode->i_atime;
+	  data.stat.st_ctime = inode->i_ctime;
+	  data.stat.st_mtime = inode->i_mtime;
+	  copy_to_user (&idata->stat,&data.stat,sizeof(data.stat));
+	  iput (inode);
 	}
-	PRINTK (("ioctl return %d\n",ret));
-	return ret;
+      }else if (cmd == UMSDOS_DOS_SETUP){
+      /* #Specification: ioctl / UMSDOS_DOS_SETUP
+	 The UMSDOS_DOS_SETUP ioctl allow changing the
+	 default permission of the MsDOS file system driver
+	 on the fly. The MsDOS driver apply global permission
+	 to every file and directory. Normally these permissions
+	 are controlled by a mount option. This is not
+	 available for root partition, so a special utility
+	 (umssetup) is provided to do this, normally in
+	 /etc/rc.local.
+	 
+	 Be aware that this apply ONLY to MsDOS directory
+	 (those without EMD --linux-.---). Umsdos directory
+	 have independent (standard) permission for each
+	 and every file.
+	 
+	 The field umsdos_dirent provide the information needed.
+	 umsdos_dirent.uid and gid sets the owner and group.
+	 umsdos_dirent.mode set the permissions flags.
+      */
+	dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
+	dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
+	dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
+	ret = 0;
+      }
+    }
+  }
+  Printk (("ioctl return %d\n",ret));
+  return ret;
 }
 
 
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/mangle.c linux/fs/umsdos/mangle.c
--- v2.1.86/linux/fs/umsdos/mangle.c	Sun Feb 25 01:17:59 1996
+++ linux/fs/umsdos/mangle.c	Thu Feb 12 13:36:57 1998
@@ -13,472 +13,474 @@
 #include <linux/umsdos_fs.h>
 
 /*
-	Complete the mangling of the MSDOS fake name
-	based on the position of the entry in the EMD file.
+  Complete the mangling of the MSDOS fake name
+  based on the position of the entry in the EMD file.
 
-	Simply complete the job of umsdos_parse; fill the extension.
+  Simply complete the job of umsdos_parse; fill the extension.
 
-	Beware that info->f_pos must be set.
+  Beware that info->f_pos must be set.
 */
 void umsdos_manglename (struct umsdos_info *info)
 {
-	if (info->msdos_reject){
-		/* #Specification: file name / non MSDOS conforming / mangling
-			Each non MSDOS conforming file has a special extension
-			build from the entry position in the EMD file.
-
-			This number is then transform in a base 32 number, where
-			each digit is expressed like hexadecimal number, using
-			digit and letter, except it uses 22 letters from 'a' to 'v'.
-			The number 32 comes from 2**5. It is faster to split a binary
-			number using a base which is a power of two. And I was 32
-			when I started this project. Pick your answer :-) .
-
-			If the result is '0', it is replace with '_', simply
-			to make it odd.
-
-			This is true for the first two character of the extension.
-			The last one is taken from a list of odd character, which
-			are:
-
-				{ } ( ) ! ` ^ & @
-
-			With this scheme, we can produce 9216 ( 9* 32 * 32)
-			different extensions which should not clash with any useful
-			extension already popular or meaningful. Since most directory
-			have much less than 32 * 32 files in it, the first character
-			of the extension of any mangle name will be {.
-
-			Here are the reason to do this (this kind of mangling).
-
-			-The mangling is deterministic. Just by the extension, we
-			 are able to locate the entry in the EMD file.
-
-			-By keeping to beginning of the file name almost unchanged,
-			 we are helping the MSDOS user.
-
-			-The mangling produces names not too ugly, so an msdos user
-			 may live with it (remember it, type it, etc...).
-
-			-The mangling produces names ugly enough so no one will
-			 ever think of using such a name in real life. This is not
-			 fool proof. I don't think there is a total solution to this.
-		*/
-		union {
-			int entry_num;
-			struct {
-				unsigned num1:5,num2:5,num3:5;
-			}num;
-		} u;
-		char *pt = info->fake.fname + info->fake.len;
-		/* lookup for encoding the last character of the extension */
-		/* It contain valid character after the ugly one to make sure */
-		/* even if someone overflow the 32 * 32 * 9 limit, it still do */
-		/* something */
-		#define SPECIAL_MANGLING '{','}','(',')','!','`','^','&','@'
-		static char lookup3[]={
-			SPECIAL_MANGLING,
-			/* This is the start of lookup12 */
-			'_','1','2','3','4','5','6','7','8','9',
-			'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
-			'p','q','r','s','t','u','v' 
-		};
-		#define lookup12 (lookup3+9)
-		u.entry_num = info->f_pos / UMSDOS_REC_SIZE;
-		if (u.entry_num > (9* 32 * 32)){
-			printk ("UMSDOS: More than 9216 file in a directory.\n"
-				"This may break the mangling strategy.\n"
-				"Not a killer problem. See doc.\n");
-		}
-		*pt++ = '.';
-		*pt++ = lookup3 [u.num.num3];
-		*pt++ = lookup12[u.num.num2];
-		*pt++ = lookup12[u.num.num1];
-		*pt = '\0';		/* help doing printk */	
-		info->fake.len += 4;
-		info->msdos_reject = 0;		/* Avoid mangling twice */
-	}
+  if (info->msdos_reject){
+    /* #Specification: file name / non MSDOS conforming / mangling
+       Each non MSDOS conforming file has a special extension
+       build from the entry position in the EMD file.
+
+       This number is then transform in a base 32 number, where
+       each digit is expressed like hexadecimal number, using
+       digit and letter, except it uses 22 letters from 'a' to 'v'.
+       The number 32 comes from 2**5. It is faster to split a binary
+       number using a base which is a power of two. And I was 32
+       when I started this project. Pick your answer :-) .
+
+       If the result is '0', it is replace with '_', simply
+       to make it odd.
+
+       This is true for the first two character of the extension.
+       The last one is taken from a list of odd character, which
+       are:
+
+       { } ( ) ! ` ^ & @
+       
+       With this scheme, we can produce 9216 ( 9* 32 * 32)
+       different extensions which should not clash with any useful
+       extension already popular or meaningful. Since most directory
+       have much less than 32 * 32 files in it, the first character
+       of the extension of any mangle name will be {.
+       
+       Here are the reason to do this (this kind of mangling).
+       
+       -The mangling is deterministic. Just by the extension, we
+       are able to locate the entry in the EMD file.
+
+       -By keeping to beginning of the file name almost unchanged,
+       we are helping the MSDOS user.
+       
+       -The mangling produces names not too ugly, so an msdos user
+       may live with it (remember it, type it, etc...).
+       
+       -The mangling produces names ugly enough so no one will
+       ever think of using such a name in real life. This is not
+       fool proof. I don't think there is a total solution to this.
+    */
+    union {
+      int entry_num;
+      struct {
+	unsigned num1:5,num2:5,num3:5;
+      }num;
+    } u;
+    char *pt = info->fake.fname + info->fake.len;
+    /* lookup for encoding the last character of the extension */
+    /* It contain valid character after the ugly one to make sure */
+    /* even if someone overflow the 32 * 32 * 9 limit, it still do */
+    /* something */
+#define SPECIAL_MANGLING '{','}','(',')','!','`','^','&','@'
+    static char lookup3[]={
+      SPECIAL_MANGLING,
+      /* This is the start of lookup12 */
+      '_','1','2','3','4','5','6','7','8','9',
+      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
+      'p','q','r','s','t','u','v' 
+    };
+#define lookup12 (lookup3+9)
+    u.entry_num = info->f_pos / UMSDOS_REC_SIZE;
+    if (u.entry_num > (9* 32 * 32)){
+      printk ("UMSDOS: More than 9216 file in a directory.\n"
+	      "This may break the mangling strategy.\n"
+	      "Not a killer problem. See doc.\n");
+    }
+    *pt++ = '.';
+    *pt++ = lookup3 [u.num.num3];
+    *pt++ = lookup12[u.num.num2];
+    *pt++ = lookup12[u.num.num1];
+    *pt = '\0';		/* help doing printk */	
+    info->fake.len += 4;
+    info->msdos_reject = 0;		/* Avoid mangling twice */
+  }
 }
 
 /*
-	Evaluate the record size needed to store of name of len character.
-	The value returned is a multiple of UMSDOS_REC_SIZE.
+  Evaluate the record size needed to store of name of len character.
+  The value returned is a multiple of UMSDOS_REC_SIZE.
 */
 int umsdos_evalrecsize (int len)
 {
-	struct umsdos_dirent dirent;
-	int nbrec = 1+((len-1+(dirent.name-(char*)&dirent))
-                   / UMSDOS_REC_SIZE);
-	return nbrec * UMSDOS_REC_SIZE;
-	/*
-	GLU	This should be inlined or something to speed it up to the max.
-	GLU	nbrec is absolutely not needed to return the value.
-	*/
+  struct umsdos_dirent dirent;
+  int nbrec = 1+((len-1+(dirent.name-(char*)&dirent))
+		 / UMSDOS_REC_SIZE);
+  return nbrec * UMSDOS_REC_SIZE;
+  /*
+    GLU	This should be inlined or something to speed it up to the max.
+    GLU	nbrec is absolutely not needed to return the value.
+  */
 }
 #ifdef TEST
 int umsdos_evalrecsize_old (int len)
 {
-	struct umsdos_dirent dirent;
-	int size = len + (dirent.name-(char*)&dirent);
-	int nbrec = size / UMSDOS_REC_SIZE;
-	int extra = size % UMSDOS_REC_SIZE;
-	if (extra > 0) nbrec++;
-	return nbrec * UMSDOS_REC_SIZE;
+  struct umsdos_dirent dirent;
+  int size = len + (dirent.name-(char*)&dirent);
+  int nbrec = size / UMSDOS_REC_SIZE;
+  int extra = size % UMSDOS_REC_SIZE;
+  if (extra > 0) nbrec++;
+  return nbrec * UMSDOS_REC_SIZE;
 }
 #endif
+
+
 /*
-	Fill the struct info with the full and msdos name of a file
-	Return 0 if all is ok, a negative error code otherwise.
+  Fill the struct info with the full and msdos name of a file
+  Return 0 if all is ok, a negative error code otherwise.
 */
 int umsdos_parse (
-	const char *fname,
-	int len,
-	struct umsdos_info *info)
+		  const char *fname,
+		  int len,
+		  struct umsdos_info *info)
 {
-	int ret = -ENAMETOOLONG;
-	/* #Specification: file name / too long
-		If a file name exceed UMSDOS maxima, the file name is silently
-		truncated. This makes it conformant with the other file system
-		of Linux (minix and ext2 at least).
-	*/
-	if (len > UMSDOS_MAXNAME) len = UMSDOS_MAXNAME;
-	{
-		const char *firstpt=NULL;	/* First place we saw a . in fname */
-		/* #Specification: file name / non MSDOS conforming / base length 0
-			file name beginning with a period '.' are invalid for MsDOS.
-			It needs absolutely a base name. So the file name is mangled
-		*/
-		int ivldchar = fname[0] == '.';/* At least one invalid character */
-		int msdos_len = len;
-		int base_len;
-		/*
-			cardinal_per_size tells if there exist at least one
-			DOS pseudo devices on length n. See the test below.
-		*/
-		static const char cardinal_per_size[9]={
-			0, 0, 0, 1, 1, 0, 1, 0, 1
-		};
-		/*
-			lkp translate all character to acceptable character (for DOS).
-			When lkp[n] == n, it means also it is an acceptable one.
-			So it serve both as a flag and as a translator.
-		*/
-		static char lkp[256];
-		static char is_init=0;
-		if (!is_init){
-			/*
-				Initialisation of the array is easier and less error prone
-				like this.
-			*/
-			int i;
-			static const char *spc = "\"*+,/:;<=>?[\\]|~";
-			is_init = 1;
-			for (i=0; i<=32; i++) lkp[i] = '#';
-			for (i=33; i<'A'; i++) lkp[i] = (char)i;
-			for (i='A'; i<='Z'; i++) lkp[i] = (char)(i+('a'-'A'));
-			for (i='Z'+1; i<127; i++) lkp[i] = (char)i;
-			for (i=128; i<256; i++) lkp[i] = '#';
-
-			lkp['.'] = '_';
-			while (*spc != '\0') lkp[(unsigned char)(*spc++)] = '#';
-		}
-		/*	GLU
-			file name which are longer than 8+'.'+3 are invalid for MsDOS.
-			So the file name is to be mangled no more test needed.
-			This Speed Up for long and very long name.
-			The position of the last point is no more necessary anyway.
-		*/
-		if (len<=(8+1+3)){
-			const char *pt = fname;
-			const char *endpt = fname + len;
-			while (pt < endpt){
-				if (*pt == '.'){
-					if (firstpt != NULL){
-						/* 2 . in a file name. Reject */
-						ivldchar = 1;
-						break;
-					}else{
-						int extlen = (int)(endpt - pt);
-						firstpt = pt;
-						if (firstpt - fname > 8){
-							/* base name longer than 8: reject */
-							ivldchar = 1;
-							break;
-						}else if (extlen > 4){
-							/* Extension longer than 4 (including .): reject */
-							ivldchar = 1;
-							break;
-						}else if (extlen == 1){
-							/* #Specification: file name / non MSDOS conforming / last char == .
-								If the last character of a file name is
-								a period, mangling is applied. MsDOS do
-								not support those file name.
-							*/
-							ivldchar = 1;
-							break;
-						}else if (extlen == 4){
-							/* #Specification: file name / non MSDOS conforming / mangling clash
-								To avoid clash with	the umsdos mangling, any file
-								with a special character as the first character
-								of the extension will be mangled. This solve the
-								following problem:
-
-								#
-								touch FILE
-								# FILE is invalid for DOS, so mangling is applied
-								# file.{_1 is created in the DOS directory
-								touch file.{_1
-								# To UMSDOS file point to a single DOS entry.
-								# So file.{_1 has to be mangled.
-								#
-							*/	
-							static char special[]={
-								SPECIAL_MANGLING,'\0'
-							};
-							if (strchr(special,firstpt[1])!= NULL){
-								ivldchar = 1;
-								break;
-							}
-						}
-					}
-				}else if (lkp[(unsigned char)(*pt)] != *pt){
-					ivldchar = 1;
-					break;
-				}
-				pt++;
-			}
-		}else{
-			ivldchar = 1;
-		}
-		if (ivldchar
-			|| (firstpt == NULL && len > 8)
-			|| (len == UMSDOS_EMD_NAMELEN
-				&& memcmp(fname,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN)==0)){
-			/* #Specification: file name / --linux-.---
-				The name of the EMD file --linux-.--- is map to a mangled
-				name. So UMSDOS does not restrict its use.
-			*/
-			/* #Specification: file name / non MSDOS conforming / mangling
-				Non MSDOS conforming file name must use some alias to fit
-				in the MSDOS name space.
-
-				The strategy is simple. The name is simply truncated to
-				8 char. points are replace with underscore and a
-				number is given as an extension. This number correspond
-				to the entry number in the EMD file. The EMD file
-				only need to carry the real name.
-
-				Upper case is also convert to lower case.
-				Control character are converted to #.
-				Space are converted to #.
-				The following character are also converted to #.
-				#
-					" * + , / : ; < = > ? [ \ ] | ~
-				#
-
-				Sometime, the problem is not in MsDOS itself but in
-				command.com.
-			*/
-			int i;
-			char *pt = info->fake.fname;
-			base_len = msdos_len = (msdos_len>8) ? 8 : msdos_len;
-			/*
-				There is no '.' any more so we know for a fact that
-				the base length is the length.
-			*/
-			memcpy (info->fake.fname,fname,msdos_len);
-			for (i=0; i<msdos_len; i++, pt++) *pt = lkp[(unsigned char)(*pt)];
-			*pt = '\0';	/* GLU	C'est sur on a un 0 a la fin */
-			info->msdos_reject = 1;
-			/*
-				The numeric extension is added only when we know
-				the position in the EMD file, in umsdos_newentry(),
-				umsdos_delentry(), and umsdos_findentry().
-				See umsdos_manglename().
-			*/
-		}else{
-			/* Conforming MSDOS file name */
-			strncpy (info->fake.fname,fname,len);
-			info->msdos_reject = 0;
-			base_len = firstpt != NULL ? (int)(firstpt - fname) : len;
-		}
-		if (cardinal_per_size[base_len]){
-			/* #Specification: file name / MSDOS devices / mangling
-				To avoid unreachable file from MsDOS, any MsDOS conforming
-				file with a basename equal to one of the MsDOS pseudo
-				devices will be mangled.
-
-				If a file such as "prn" was created, it would be unreachable
-				under MsDOS because prn is assumed to be the printer, even
-				if the file does have an extension.
-
-				Since the extension is unimportant to MsDOS, we must patch
-				the basename also. We simply insert a minus '-'. To avoid
-				conflict with valid file with a minus in front (such as
-				"-prn"), we add an mangled extension like any other
-				mangled file name.
-
-				Here is the list of DOS pseudo devices:
-
-				#
-					"prn","con","aux","nul",
-					"lpt1","lpt2","lpt3","lpt4",
-					"com1","com2","com3","com4",
-					"clock$"
-				#
-
-				and some standard ones for common DOS programs
-
-					"emmxxxx0","xmsxxxx0","setverxx"
-
-				(Thanks to Chris Hall <CAH17@PHOENIX.CAMBRIDGE.AC.UK>
-				 for pointing these to me).
-
-				Is there one missing ?
-			*/
-			/* This table must be ordered by length */
-			static const char *tbdev[]={
-				"prn","con","aux","nul",
-				"lpt1","lpt2","lpt3","lpt4",
-				"com1","com2","com3","com4",
-				"clock$",
-				"emmxxxx0","xmsxxxx0","setverxx"
-			};
-			/* Tell where to find in tbdev[], the first name of */
-			/* a certain length */
-			static const char start_ind_dev[9]={
-				0, 0, 0, 4, 12, 12, 13, 13, 16 
-			};
-			char basen[9];
-			int i;
-			for (i=start_ind_dev[base_len-1]; i<start_ind_dev[base_len]; i++){
-				if (memcmp(info->fake.fname,tbdev[i],base_len)==0){
-					memcpy (basen,info->fake.fname,base_len);
-					basen[base_len] = '\0';		/* GLU	C'est sur on a un 0 a la fin */
-					/*
-					GLU	On ne fait cela que si necessaire, on essaye d'etre le
-					GLU	simple dans le cas general (le plus frequent).
-					*/
-					info->fake.fname[0] = '-';
-					strcpy (info->fake.fname+1,basen);	/* GLU	C'est sur on a un 0 a la fin */
-					msdos_len = (base_len==8) ? 8 : base_len + 1;
-					info->msdos_reject = 1;
-					break;
-				}
-			}
-		}
-		info->fake.fname[msdos_len] = '\0';	/* Help doing printk */
-		/* GLU	Ce zero devrais deja y etre ! (invariant ?) */
-		info->fake.len = msdos_len;
-		/* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ?*/
-		memcpy (info->entry.name,fname,len);
-		info->entry.name_len = len;
-		ret = 0;
+  int ret = -ENAMETOOLONG;
+  /* #Specification: file name / too long
+     If a file name exceed UMSDOS maxima, the file name is silently
+     truncated. This makes it conformant with the other file system
+     of Linux (minix and ext2 at least).
+  */
+  if (len > UMSDOS_MAXNAME) len = UMSDOS_MAXNAME;
+  {
+    const char *firstpt=NULL;	/* First place we saw a . in fname */
+    /* #Specification: file name / non MSDOS conforming / base length 0
+       file name beginning with a period '.' are invalid for MsDOS.
+       It needs absolutely a base name. So the file name is mangled
+    */
+    int ivldchar = fname[0] == '.';/* At least one invalid character */
+    int msdos_len = len;
+    int base_len;
+    /*
+      cardinal_per_size tells if there exist at least one
+      DOS pseudo devices on length n. See the test below.
+    */
+    static const char cardinal_per_size[9]={
+      0, 0, 0, 1, 1, 0, 1, 0, 1
+    };
+    /*
+      lkp translate all character to acceptable character (for DOS).
+      When lkp[n] == n, it means also it is an acceptable one.
+      So it serve both as a flag and as a translator.
+    */
+    static char lkp[256];
+    static char is_init=0;
+    if (!is_init){
+      /*
+	Initialisation of the array is easier and less error prone
+	like this.
+      */
+      int i;
+      static const char *spc = "\"*+,/:;<=>?[\\]|~";
+      is_init = 1;
+      for (i=0; i<=32; i++) lkp[i] = '#';
+      for (i=33; i<'A'; i++) lkp[i] = (char)i;
+      for (i='A'; i<='Z'; i++) lkp[i] = (char)(i+('a'-'A'));
+      for (i='Z'+1; i<127; i++) lkp[i] = (char)i;
+      for (i=128; i<256; i++) lkp[i] = '#';
+      
+      lkp['.'] = '_';
+      while (*spc != '\0') lkp[(unsigned char)(*spc++)] = '#';
+    }
+    /*	GLU
+	file name which are longer than 8+'.'+3 are invalid for MsDOS.
+	So the file name is to be mangled no more test needed.
+	This Speed Up for long and very long name.
+	The position of the last point is no more necessary anyway.
+    */
+    if (len<=(8+1+3)){
+      const char *pt = fname;
+      const char *endpt = fname + len;
+      while (pt < endpt){
+	if (*pt == '.'){
+	  if (firstpt != NULL){
+	    /* 2 . in a file name. Reject */
+	    ivldchar = 1;
+	    break;
+	  }else{
+	    int extlen = (int)(endpt - pt);
+	    firstpt = pt;
+	    if (firstpt - fname > 8){
+	      /* base name longer than 8: reject */
+	      ivldchar = 1;
+	      break;
+	    }else if (extlen > 4){
+	      /* Extension longer than 4 (including .): reject */
+	      ivldchar = 1;
+	      break;
+	    }else if (extlen == 1){
+	      /* #Specification: file name / non MSDOS conforming / last char == .
+		 If the last character of a file name is
+		 a period, mangling is applied. MsDOS do
+		 not support those file name.
+	      */
+	      ivldchar = 1;
+	      break;
+	    }else if (extlen == 4){
+	      /* #Specification: file name / non MSDOS conforming / mangling clash
+		 To avoid clash with	the umsdos mangling, any file
+		 with a special character as the first character
+		 of the extension will be mangled. This solve the
+		 following problem:
+		 
+		 #
+		 touch FILE
+		 # FILE is invalid for DOS, so mangling is applied
+		 # file.{_1 is created in the DOS directory
+		 touch file.{_1
+		 # To UMSDOS file point to a single DOS entry.
+		 # So file.{_1 has to be mangled.
+		 #
+	      */	
+	      static char special[]={
+		SPECIAL_MANGLING,'\0'
+	      };
+	      if (strchr(special,firstpt[1])!= NULL){
+		ivldchar = 1;
+		break;
+	      }
+	    }
+	  }
+	}else if (lkp[(unsigned char)(*pt)] != *pt){
+	  ivldchar = 1;
+	  break;
 	}
-	/*
-		Evaluate how many record are needed to store this entry.
-	*/
-	info->recsize = umsdos_evalrecsize (len);
-	return ret;
+	pt++;
+      }
+    }else{
+      ivldchar = 1;
+    }
+    if (ivldchar
+	|| (firstpt == NULL && len > 8)
+	|| (len == UMSDOS_EMD_NAMELEN
+	    && memcmp(fname,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN)==0)){
+      /* #Specification: file name / --linux-.---
+	 The name of the EMD file --linux-.--- is map to a mangled
+	 name. So UMSDOS does not restrict its use.
+      */
+      /* #Specification: file name / non MSDOS conforming / mangling
+	 Non MSDOS conforming file name must use some alias to fit
+	 in the MSDOS name space.
+	 
+	 The strategy is simple. The name is simply truncated to
+	 8 char. points are replace with underscore and a
+	 number is given as an extension. This number correspond
+	 to the entry number in the EMD file. The EMD file
+	 only need to carry the real name.
+	 
+	 Upper case is also convert to lower case.
+	 Control character are converted to #.
+	 Space are converted to #.
+	 The following character are also converted to #.
+	 #
+	 " * + , / : ; < = > ? [ \ ] | ~
+	 #
+	 
+	 Sometime, the problem is not in MsDOS itself but in
+	 command.com.
+      */
+      int i;
+      char *pt = info->fake.fname;
+      base_len = msdos_len = (msdos_len>8) ? 8 : msdos_len;
+      /*
+	There is no '.' any more so we know for a fact that
+	the base length is the length.
+      */
+      memcpy (info->fake.fname,fname,msdos_len);
+      for (i=0; i<msdos_len; i++, pt++) *pt = lkp[(unsigned char)(*pt)];
+      *pt = '\0';	/* GLU	C'est sur on a un 0 a la fin */
+      info->msdos_reject = 1;
+      /*
+	The numeric extension is added only when we know
+	the position in the EMD file, in umsdos_newentry(),
+	umsdos_delentry(), and umsdos_findentry().
+	See umsdos_manglename().
+      */
+    }else{
+      /* Conforming MSDOS file name */
+      strncpy (info->fake.fname,fname,len);
+      info->msdos_reject = 0;
+      base_len = firstpt != NULL ? (int)(firstpt - fname) : len;
+    }
+    if (cardinal_per_size[base_len]){
+      /* #Specification: file name / MSDOS devices / mangling
+	 To avoid unreachable file from MsDOS, any MsDOS conforming
+	 file with a basename equal to one of the MsDOS pseudo
+	 devices will be mangled.
+	 
+	 If a file such as "prn" was created, it would be unreachable
+	 under MsDOS because prn is assumed to be the printer, even
+	 if the file does have an extension.
+	 
+	 Since the extension is unimportant to MsDOS, we must patch
+	 the basename also. We simply insert a minus '-'. To avoid
+	 conflict with valid file with a minus in front (such as
+	 "-prn"), we add an mangled extension like any other
+	 mangled file name.
+	 
+	 Here is the list of DOS pseudo devices:
+	 
+	 #
+	 "prn","con","aux","nul",
+	 "lpt1","lpt2","lpt3","lpt4",
+	 "com1","com2","com3","com4",
+	 "clock$"
+	 #
+	 
+	 and some standard ones for common DOS programs
+	 
+	 "emmxxxx0","xmsxxxx0","setverxx"
+	 
+	 (Thanks to Chris Hall <CAH17@PHOENIX.CAMBRIDGE.AC.UK>
+	 for pointing these to me).
+	 
+	 Is there one missing ?
+      */
+      /* This table must be ordered by length */
+      static const char *tbdev[]={
+	"prn","con","aux","nul",
+	"lpt1","lpt2","lpt3","lpt4",
+	"com1","com2","com3","com4",
+	"clock$",
+	"emmxxxx0","xmsxxxx0","setverxx"
+      };
+      /* Tell where to find in tbdev[], the first name of */
+      /* a certain length */
+      static const char start_ind_dev[9]={
+	0, 0, 0, 4, 12, 12, 13, 13, 16 
+      };
+      char basen[9];
+      int i;
+      for (i=start_ind_dev[base_len-1]; i<start_ind_dev[base_len]; i++){
+	if (memcmp(info->fake.fname,tbdev[i],base_len)==0){
+	  memcpy (basen,info->fake.fname,base_len);
+	  basen[base_len] = '\0';		/* GLU	C'est sur on a un 0 a la fin */
+	  /*
+	    GLU	On ne fait cela que si necessaire, on essaye d'etre le
+	    GLU	simple dans le cas general (le plus frequent).
+	  */
+	  info->fake.fname[0] = '-';
+	  strcpy (info->fake.fname+1,basen);	/* GLU	C'est sur on a un 0 a la fin */
+	  msdos_len = (base_len==8) ? 8 : base_len + 1;
+	  info->msdos_reject = 1;
+	  break;
+	}
+      }
+    }
+    info->fake.fname[msdos_len] = '\0';	/* Help doing printk */
+    /* GLU	Ce zero devrais deja y etre ! (invariant ?) */
+    info->fake.len = msdos_len;
+    /* Pourquoi ne pas utiliser info->fake.len partout ??? plus long ?*/
+    memcpy (info->entry.name,fname,len);
+    info->entry.name_len = len;
+    ret = 0;
+  }
+  /*
+    Evaluate how many record are needed to store this entry.
+  */
+  info->recsize = umsdos_evalrecsize (len);
+  return ret;
 }
 
 #ifdef TEST
 
 struct MANG_TEST{
-	char *fname;		/* Name to validate */
-	int msdos_reject;	/* Expected msdos_reject flag */
-	char *msname;		/* Expected msdos name */
+  char *fname;		/* Name to validate */
+  int msdos_reject;	/* Expected msdos_reject flag */
+  char *msname;		/* Expected msdos name */
 };
 
 struct MANG_TEST tb[]={
-	"hello",		0,	"hello",
-	"hello.1",		0,	"hello.1",
-	"hello.1_",		0,	"hello.1_",
-	"prm",			0,	"prm",
-
+  "hello",		0,	"hello",
+  "hello.1",		0,	"hello.1",
+  "hello.1_",		0,	"hello.1_",
+  "prm",		0,	"prm",
+  
 #ifdef PROPOSITION
-	"HELLO",		1,	"hello",
-	"Hello.1",		1,	"hello.1",
-	"Hello.c",		1,	"hello.c",
+  "HELLO",		1,	"hello",
+  "Hello.1",		1,	"hello.1",
+  "Hello.c",		1,	"hello.c",
 #elseif
 /*
-	Je trouve les trois exemples ci-dessous tres "malheureux".
-	Je propose de mettre en minuscule dans un passe preliminaire,
-	et de tester apres si il y a d'autres caracters "mechants".
-	Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement
-	modifiable que ca. Mais c'est pour le principe.
-	Evidemment cela augmente les chances de "Collision",
-	par exemple: entre "HELLO" et "Hello", mais ces problemes
-	peuvent etre traiter ailleur avec les autres collisions.
+  Je trouve les trois exemples ci-dessous tres "malheureux".
+  Je propose de mettre en minuscule dans un passe preliminaire,
+  et de tester apres si il y a d'autres caracters "mechants".
+  Bon, je ne l'ai pas fait, parceque ce n'est pas si facilement
+  modifiable que ca. Mais c'est pour le principe.
+  Evidemment cela augmente les chances de "Collision",
+  par exemple: entre "HELLO" et "Hello", mais ces problemes
+  peuvent etre traiter ailleur avec les autres collisions.
 */
-	"HELLO",		1,	"hello",
-	"Hello.1",		1,	"hello_1",
-	"Hello.c",		1,	"hello_c",
+  "HELLO",		1,	"hello",
+  "Hello.1",		1,	"hello_1",
+  "Hello.c",		1,	"hello_c",
 #endif
-
-	"hello.{_1",		1,	"hello_{_",
-	"hello\t",		1,	"hello#",
-	"hello.1.1",		1,	"hello_1_",
-	"hel,lo",		1,	"hel#lo",
-	"Salut.Tu.vas.bien?",	1,	"salut_tu",
-	".profile",		1,	"_profile",
-	".xv",			1,	"_xv",
-	"toto.",		1,	"toto_",
-	"clock$.x",		1,	"-clock$",
-	"emmxxxx0",		1,	"-emmxxxx",
-	"emmxxxx0.abcd",	1,	"-emmxxxx",
-	"aux",			1,	"-aux",
-	"prn",			1,	"-prn",
-	"prn.abc",		1,	"-prn",
-	"PRN",			1,	"-prn",
-/* 
-GLU	ATTENTION : Le resultat de ceux-ci sont differents avec ma version
-GLU	du mangle par rapport au mangle originale.
-GLU	CAUSE: La maniere de calculer la variable baselen. 
-GLU		Pour toi c'est toujours 3
-GLU		Pour moi c'est respectivement 7, 8 et 8
-*/
-	"PRN.abc",		1,	"prn_abc",
-	"Prn.abcd",		1,	"prn_abcd",
-	"prn.abcd",		1,	"prn_abcd",
-	"Prn.abcdefghij",	1,	"prn_abcd"
+  
+  "hello.{_1",		1,	"hello_{_",
+  "hello\t",		1,	"hello#",
+  "hello.1.1",		1,	"hello_1_",
+  "hel,lo",		1,	"hel#lo",
+  "Salut.Tu.vas.bien?",	1,	"salut_tu",
+  ".profile",		1,	"_profile",
+  ".xv",			1,	"_xv",
+  "toto.",		1,	"toto_",
+  "clock$.x",		1,	"-clock$",
+  "emmxxxx0",		1,	"-emmxxxx",
+  "emmxxxx0.abcd",	1,	"-emmxxxx",
+  "aux",			1,	"-aux",
+  "prn",			1,	"-prn",
+  "prn.abc",		1,	"-prn",
+  "PRN",			1,	"-prn",
+  /* 
+     GLU	ATTENTION : Le resultat de ceux-ci sont differents avec ma version
+     GLU	du mangle par rapport au mangle originale.
+     GLU	CAUSE: La maniere de calculer la variable baselen. 
+     GLU		Pour toi c'est toujours 3
+     GLU		Pour moi c'est respectivement 7, 8 et 8
+  */
+  "PRN.abc",		1,	"prn_abc",
+  "Prn.abcd",		1,	"prn_abcd",
+  "prn.abcd",		1,	"prn_abcd",
+  "Prn.abcdefghij",	1,	"prn_abcd"
 };
 
 int main (int argc, char *argv[])
 {
-	int i,rold,rnew;
-	printf ("Testing the umsdos_parse.\n");
-	for (i=0; i<sizeof(tb)/sizeof(tb[0]); i++){
-		struct MANG_TEST *pttb = tb+i;
-		struct umsdos_info info;
-		int ok = umsdos_parse (pttb->fname,strlen(pttb->fname),&info);
-		if (strcmp(info.fake.fname,pttb->msname)!=0){
-			printf ("**** %s -> ",pttb->fname);
-			printf ("%s <> %s\n",info.fake.fname,pttb->msname);
-		}else if (info.msdos_reject != pttb->msdos_reject){
-			printf ("**** %s -> %s ",pttb->fname,pttb->msname);
-			printf ("%d <> %d\n",info.msdos_reject,pttb->msdos_reject);
-		}else{
-			printf ("     %s -> %s %d\n",pttb->fname,pttb->msname
-				,pttb->msdos_reject);
-		}
-	}
-	printf ("Testing the new umsdos_evalrecsize.");
-	for (i=0; i<UMSDOS_MAXNAME ; i++){
-		rnew=umsdos_evalrecsize (i);
-		rold=umsdos_evalrecsize_old (i);
-		if (!(i%UMSDOS_REC_SIZE)){
-			printf ("\n%d:\t",i);
-		}
-		if (rnew!=rold){
-			printf ("**** %d newres: %d != %d \n", i, rnew, rold);
-		}else{
-			printf(".");
-		}
-	}
-	printf ("\nEnd of Testing.\n");
-
-	return 0;
+  int i,rold,rnew;
+  printf ("Testing the umsdos_parse.\n");
+  for (i=0; i<sizeof(tb)/sizeof(tb[0]); i++){
+    struct MANG_TEST *pttb = tb+i;
+    struct umsdos_info info;
+    int ok = umsdos_parse (pttb->fname,strlen(pttb->fname),&info);
+    if (strcmp(info.fake.fname,pttb->msname)!=0){
+      printf ("**** %s -> ",pttb->fname);
+      printf ("%s <> %s\n",info.fake.fname,pttb->msname);
+    }else if (info.msdos_reject != pttb->msdos_reject){
+      printf ("**** %s -> %s ",pttb->fname,pttb->msname);
+      printf ("%d <> %d\n",info.msdos_reject,pttb->msdos_reject);
+    }else{
+      printf ("     %s -> %s %d\n",pttb->fname,pttb->msname
+	      ,pttb->msdos_reject);
+    }
+  }
+  printf ("Testing the new umsdos_evalrecsize.");
+  for (i=0; i<UMSDOS_MAXNAME ; i++){
+    rnew=umsdos_evalrecsize (i);
+    rold=umsdos_evalrecsize_old (i);
+    if (!(i%UMSDOS_REC_SIZE)){
+      printf ("\n%d:\t",i);
+    }
+    if (rnew!=rold){
+      printf ("**** %d newres: %d != %d \n", i, rnew, rold);
+    }else{
+      printf(".");
+    }
+  }
+  printf ("\nEnd of Testing.\n");
+  
+  return 0;
 }
 
 #endif
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.1.86/linux/fs/umsdos/namei.c	Sun Dec 21 17:41:24 1997
+++ linux/fs/umsdos/namei.c	Thu Feb 12 13:36:57 1998
@@ -31,97 +31,97 @@
 */
 static int umsdos_waitcreate(struct inode *dir)
 {
-	int ret = 0;
-	if (dir->u.umsdos_i.u.dir_info.creating
-		&& dir->u.umsdos_i.u.dir_info.pid != current->pid){
-		sleep_on(&dir->u.umsdos_i.u.dir_info.p);
-		ret = 1;
-	}
-	return ret;
+  int ret = 0;
+  if (dir->u.umsdos_i.u.dir_info.creating
+      && dir->u.umsdos_i.u.dir_info.pid != current->pid){
+    sleep_on(&dir->u.umsdos_i.u.dir_info.p);
+    ret = 1;
+  }
+  return ret;
 }
 /*
 	Wait for any lookup process to finish
 */
 static void umsdos_waitlookup (struct inode *dir)
 {
-	while (dir->u.umsdos_i.u.dir_info.looking){
-		sleep_on(&dir->u.umsdos_i.u.dir_info.p);
-	}
+  while (dir->u.umsdos_i.u.dir_info.looking){
+    sleep_on(&dir->u.umsdos_i.u.dir_info.p);
+  }
 }
 /*
 	Lock all other process out of this directory.
 */
 void umsdos_lockcreate (struct inode *dir)
 {
-	/* #Specification: file creation / not atomic
-		File creation is a two step process. First we create (allocate)
-		an entry in the EMD file and then (using the entry offset) we
-		build a unique name for MSDOS. We create this name in the msdos
-		space.
-
-		We have to use semaphore (sleep_on/wake_up) to prevent lookup
-		into a directory when we create a file or directory and to
-		prevent creation while a lookup is going on. Since many lookup
-		may happen at the same time, the semaphore is a counter.
-
-		Only one creation is allowed at the same time. This protection
-		may not be necessary. The problem arise mainly when a lookup
-		or a readdir is done while a file is partially created. The
-		lookup process see that as a "normal" problem and silently
-		erase the file from the EMD file. Normal because a file
-		may be erased during a MSDOS session, but not removed from
-		the EMD file.
-
-		The locking is done on a directory per directory basis. Each
-		directory inode has its wait_queue.
-
-		For some operation like hard link, things even get worse. Many
-		creation must occur at once (atomic). To simplify the design
-		a process is allowed to recursively lock the directory for
-		creation. The pid of the locking process is kept along with
-		a counter so a second level of locking is granted or not.
-	*/
-	/*
-		Wait for any creation process to finish except
-		if we (the process) own the lock
-	*/
-	while (umsdos_waitcreate(dir)!=0);
-	dir->u.umsdos_i.u.dir_info.creating++;
-	dir->u.umsdos_i.u.dir_info.pid = current->pid;
-	umsdos_waitlookup (dir);
+  /* #Specification: file creation / not atomic
+     File creation is a two step process. First we create (allocate)
+     an entry in the EMD file and then (using the entry offset) we
+     build a unique name for MSDOS. We create this name in the msdos
+     space.
+     
+     We have to use semaphore (sleep_on/wake_up) to prevent lookup
+     into a directory when we create a file or directory and to
+     prevent creation while a lookup is going on. Since many lookup
+     may happen at the same time, the semaphore is a counter.
+
+     Only one creation is allowed at the same time. This protection
+     may not be necessary. The problem arise mainly when a lookup
+     or a readdir is done while a file is partially created. The
+     lookup process see that as a "normal" problem and silently
+     erase the file from the EMD file. Normal because a file
+     may be erased during a MSDOS session, but not removed from
+     the EMD file.
+     
+     The locking is done on a directory per directory basis. Each
+     directory inode has its wait_queue.
+     
+     For some operation like hard link, things even get worse. Many
+     creation must occur at once (atomic). To simplify the design
+     a process is allowed to recursively lock the directory for
+     creation. The pid of the locking process is kept along with
+     a counter so a second level of locking is granted or not.
+  */
+  /*
+    Wait for any creation process to finish except
+    if we (the process) own the lock
+  */
+  while (umsdos_waitcreate(dir)!=0);
+  dir->u.umsdos_i.u.dir_info.creating++;
+  dir->u.umsdos_i.u.dir_info.pid = current->pid;
+  umsdos_waitlookup (dir);
 }
 /*
 	Lock all other process out of those two directories.
 */
 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
 {
-	/*
-		We must check that both directory are available before
-		locking anyone of them. This is to avoid some deadlock.
-		Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
-		this to me.
-	*/
-	while (1){
-		if (umsdos_waitcreate(dir1)==0
-			&& umsdos_waitcreate(dir2)==0){
-			/* We own both now */
-			dir1->u.umsdos_i.u.dir_info.creating++;
-			dir1->u.umsdos_i.u.dir_info.pid = current->pid;
-			dir2->u.umsdos_i.u.dir_info.creating++;
-			dir2->u.umsdos_i.u.dir_info.pid = current->pid;
-			break;
-		}
-	}
-	umsdos_waitlookup(dir1);
-	umsdos_waitlookup(dir2);
+  /*
+    We must check that both directory are available before
+    locking anyone of them. This is to avoid some deadlock.
+    Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
+    this to me.
+  */
+  while (1){
+    if (umsdos_waitcreate(dir1)==0
+	&& umsdos_waitcreate(dir2)==0){
+      /* We own both now */
+      dir1->u.umsdos_i.u.dir_info.creating++;
+      dir1->u.umsdos_i.u.dir_info.pid = current->pid;
+      dir2->u.umsdos_i.u.dir_info.creating++;
+      dir2->u.umsdos_i.u.dir_info.pid = current->pid;
+      break;
+    }
+  }
+  umsdos_waitlookup(dir1);
+  umsdos_waitlookup(dir2);
 }
 /*
 	Wait until creation is finish in this directory.
 */
 void umsdos_startlookup (struct inode *dir)
 {
-	while (umsdos_waitcreate (dir) != 0);
-	dir->u.umsdos_i.u.dir_info.looking++;
+  while (umsdos_waitcreate (dir) != 0);
+  dir->u.umsdos_i.u.dir_info.looking++;
 }
 
 /*
@@ -129,25 +129,27 @@
 */
 void umsdos_unlockcreate (struct inode *dir)
 {
-	dir->u.umsdos_i.u.dir_info.creating--;
-	if (dir->u.umsdos_i.u.dir_info.creating < 0){
-		printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
-			,dir->u.umsdos_i.u.dir_info.creating);
-	}
-	wake_up (&dir->u.umsdos_i.u.dir_info.p);
+  dir->u.umsdos_i.u.dir_info.creating--;
+  if (dir->u.umsdos_i.u.dir_info.creating < 0){
+    printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
+	    ,dir->u.umsdos_i.u.dir_info.creating);
+  }
+  wake_up (&dir->u.umsdos_i.u.dir_info.p);
 }
+
 /*
 	Tell directory lookup is over.
 */
 void umsdos_endlookup (struct inode *dir)
 {
-	dir->u.umsdos_i.u.dir_info.looking--;
-	if (dir->u.umsdos_i.u.dir_info.looking < 0){
-		printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
-			,dir->u.umsdos_i.u.dir_info.looking);
-	}
-	wake_up (&dir->u.umsdos_i.u.dir_info.p);
+  dir->u.umsdos_i.u.dir_info.looking--;
+  if (dir->u.umsdos_i.u.dir_info.looking < 0){
+    printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
+	    ,dir->u.umsdos_i.u.dir_info.looking);
+  }
+  wake_up (&dir->u.umsdos_i.u.dir_info.p);
 }
+
 #else
 static void umsdos_lockcreate (struct inode *dir){}
 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}
@@ -156,152 +158,155 @@
 void umsdos_endlookup (struct inode *dir){}
 #endif
 static int umsdos_nevercreat(
-	struct inode *dir,
-	const char *name,		/* Name of the file to add */
-	int len,
-	int errcod)				/* Length of the name */
+			     struct inode *dir,
+			     struct dentry *dentry,
+			     int errcod)				/* Length of the name */
 {
-	int ret = 0;
-	if (umsdos_is_pseudodos(dir,name,len)){
-		/* #Specification: pseudo root / any file creation /DOS
-			The pseudo sub-directory /DOS can't be created!
-			EEXIST is returned.
-
-			The pseudo sub-directory /DOS can't be removed!
-			EPERM is returned.
-		*/
-		ret = -EPERM;
-		ret = errcod;
-	}else if (name[0] == '.'
-		&& (len == 1 || (len == 2 && name[1] == '.'))){
-		/* #Specification: create / . and ..
-			If one try to creates . or .., it always fail and return
-			EEXIST.
-
-			If one try to delete . or .., it always fail and return
-			EPERM.
-
-			This should be test at the VFS layer level to avoid
-			duplicating this in all file systems. Any comments ?
-		*/
-		ret = errcod;
-	}
-	return ret;
+  const char *name = dentry->d_name.name;
+  int len = dentry->d_name.len;
+  int ret = 0;
+  if (umsdos_is_pseudodos(dir,dentry)){
+    /* #Specification: pseudo root / any file creation /DOS
+       The pseudo sub-directory /DOS can't be created!
+       EEXIST is returned.
+       
+       The pseudo sub-directory /DOS can't be removed!
+       EPERM is returned.
+    */
+    ret = -EPERM;
+    ret = errcod;
+  }else if (name[0] == '.'
+	    && (len == 1 || (len == 2 && name[1] == '.'))){
+    /* #Specification: create / . and ..
+       If one try to creates . or .., it always fail and return
+       EEXIST.
+       
+       If one try to delete . or .., it always fail and return
+       EPERM.
+       
+       This should be test at the VFS layer level to avoid
+       duplicating this in all file systems. Any comments ?
+    */
+    ret = errcod;
+  }
+  return ret;
 }
 	
 /*
-	Add a new file (ordinary or special) into the alternate directory.
-	The file is added to the real MSDOS directory. If successful, it
-	is then added to the EDM file.
-
-	Return the status of the operation. 0 mean success.
+  Add a new file (ordinary or special) into the alternate directory.
+  The file is added to the real MSDOS directory. If successful, it
+  is then added to the EDM file.
+  
+  Return the status of the operation. 0 mean success.
 */
 static int umsdos_create_any (
-	struct inode *dir,
-	const char *name,		/* Name of the file to add */
-	int len,				/* Length of the name */
-	int mode,				/* Permission bit + file type ??? */
-	int rdev,				/* major, minor or 0 for ordinary file */
-							/* and symlinks */
-	char flags,
-	struct inode **result)	/* Will hold the inode of the newly created */
-							/* file */
+   struct inode *dir,
+   struct dentry *dentry,  /* name/length etc*/
+   int mode,		   /* Permission bit + file type ??? */
+   int rdev,		   /* major, minor or 0 for ordinary file */
+   /* and symlinks */
+   char flags
+   )	/* Will hold the inode of the newly created */
+     /* file */
 {
-	int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
+    
+  int ret = umsdos_nevercreat(dir,dentry,-EEXIST);
+  if (ret == 0){
+    struct umsdos_info info;
+    ret = umsdos_parse(dentry->d_name.name,dentry->d_name.len,&info);
+  
+    if (ret == 0){
+      info.entry.mode = mode;
+      info.entry.rdev = rdev;
+      info.entry.flags = flags;
+      info.entry.uid = current->fsuid;
+      info.entry.gid = (dir->i_mode & S_ISGID)
+	? dir->i_gid : current->fsgid;
+      info.entry.ctime = info.entry.atime = info.entry.mtime
+	= CURRENT_TIME;
+      info.entry.nlink = 1;
+      umsdos_lockcreate(dir);
+      ret = umsdos_newentry (dir,&info);
+      if (ret == 0){
+	dir->i_count++;
+      /* FIXME
+	 ret = msdos_create (dir,info.fake.fname,info.fake.len
+	 ,S_IFREG|0777,result);
+      */
+	ret =msdos_create(dir,dentry,S_IFREG|0777);
 	if (ret == 0){
-		struct umsdos_info info;
-		ret = umsdos_parse (name,len,&info);
-		*result = NULL;
-		if (ret == 0){
-			info.entry.mode = mode;
-			info.entry.rdev = rdev;
-			info.entry.flags = flags;
-			info.entry.uid = current->fsuid;
-			info.entry.gid = (dir->i_mode & S_ISGID)
-				? dir->i_gid : current->fsgid;
-			info.entry.ctime = info.entry.atime = info.entry.mtime
-				= CURRENT_TIME;
-			info.entry.nlink = 1;
-			umsdos_lockcreate(dir);
-			ret = umsdos_newentry (dir,&info);
-			if (ret == 0){
-				atomic_inc(&dir->i_count);
-				ret = msdos_create (dir,info.fake.fname,info.fake.len
-					,S_IFREG|0777,result);
-				if (ret == 0){
-					struct inode *inode = *result;
-					umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
-					PRINTK (("inode %p[%d] ",inode,
-						 atomic_read(&inode->i_count)));
-					PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
-						,info.fake.fname,current->pid,info.f_pos));
-				}else{
-					/* #Specification: create / file exist in DOS
-						Here is a situation. Trying to create a file with
-						UMSDOS. The file is unknown to UMSDOS but already
-						exist in the DOS directory.
-
-						Here is what we are NOT doing:
-
-						We could silently assume that everything is fine
-						and allows the creation to succeed.
-
-						It is possible not all files in the partition
-						are mean to be visible from linux. By trying to create
-						those file in some directory, one user may get access
-						to those file without proper permissions. Looks like
-						a security hole to me. Off course sharing a file system
-						with DOS is some kind of security hole :-)
-
-						So ?
-
-						We return EEXIST in this case.
-						The same is true for directory creation.
-					*/
-					if (ret == -EEXIST){
-						printk ("UMSDOS: out of sync, Creation error [%ld], "
-							"deleting %s %d %d pos %ld\n",dir->i_ino
-							,info.fake.fname,-ret,current->pid,info.f_pos);
-					}
-					umsdos_delentry (dir,&info,0);
-				}
-				PRINTK (("umsdos_create %s ret = %d pos %d\n"
-					,info.fake.fname,ret,info.f_pos));
-			}
-			umsdos_unlockcreate(dir);
-		}
+	  struct inode *inode = dentry->d_inode;
+	  umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
+	  Printk (("inode %p[%d] ",inode,inode->i_count));
+	  Printk (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
+		   ,info.fake.fname,current->pid,info.f_pos));
+	}else{
+	  /* #Specification: create / file exist in DOS
+	     Here is a situation. Trying to create a file with
+	     UMSDOS. The file is unknown to UMSDOS but already
+	     exist in the DOS directory.
+	     
+	     Here is what we are NOT doing:
+	     
+	     We could silently assume that everything is fine
+	     and allows the creation to succeed.
+	     
+	     It is possible not all files in the partition
+	     are mean to be visible from linux. By trying to create
+	     those file in some directory, one user may get access
+	     to those file without proper permissions. Looks like
+	     a security hole to me. Off course sharing a file system
+	     with DOS is some kind of security hole :-)
+	     
+	     So ?
+	     
+	     We return EEXIST in this case.
+	     The same is true for directory creation.
+	  */
+	  if (ret == -EEXIST){
+	    printk ("UMSDOS: out of sync, Creation error [%ld], "
+		    "deleting %s %d %d pos %ld\n",dir->i_ino
+		    ,info.fake.fname,-ret,current->pid,info.f_pos);
+	  }
+	  umsdos_delentry (dir,&info,0);
 	}
-	iput (dir);
-	return ret;
+	Printk (("umsdos_create %s ret = %d pos %d\n"
+		 ,info.fake.fname,ret,info.f_pos));
+      }
+      umsdos_unlockcreate(dir);
+    }
+  }
+  d_add(dentry,dir);
+  return ret;
 }
 /*
 	Initialise the new_entry from the old for a rename operation.
 	(Only useful for umsdos_rename_f() below).
 */
 static void umsdos_ren_init(
-	struct umsdos_info *new_info,
-	struct umsdos_info *old_info,
-	int flags)		/* 0 == copy flags from old_name */
-					/* != 0, this is the value of flags */
+      struct umsdos_info *new_info,
+      struct umsdos_info *old_info,
+      int flags)		/* 0 == copy flags from old_name */
+     /* != 0, this is the value of flags */
 {
-	new_info->entry.mode = old_info->entry.mode;
-	new_info->entry.rdev = old_info->entry.rdev;
-	new_info->entry.uid = old_info->entry.uid;
-	new_info->entry.gid = old_info->entry.gid;
-	new_info->entry.ctime = old_info->entry.ctime;
-	new_info->entry.atime = old_info->entry.atime;
-	new_info->entry.mtime = old_info->entry.mtime;
-	new_info->entry.flags = flags ? flags : old_info->entry.flags;
-	new_info->entry.nlink = old_info->entry.nlink;
+  new_info->entry.mode = old_info->entry.mode;
+  new_info->entry.rdev = old_info->entry.rdev;
+  new_info->entry.uid = old_info->entry.uid;
+  new_info->entry.gid = old_info->entry.gid;
+  new_info->entry.ctime = old_info->entry.ctime;
+  new_info->entry.atime = old_info->entry.atime;
+  new_info->entry.mtime = old_info->entry.mtime;
+  new_info->entry.flags = flags ? flags : old_info->entry.flags;
+  new_info->entry.nlink = old_info->entry.nlink;
 }
 
 #define chkstk() \
-	if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
-		printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
-		, current->comm,STACK_MAGIC \
-		,*(unsigned long *)current->kernel_stack_page \
-		,__LINE__); \
-	}
+if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
+    printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
+	   , current->comm,STACK_MAGIC \
+	   ,*(unsigned long *)current->kernel_stack_page \
+	   ,__LINE__); \
+}
 
 #undef chkstk
 #define chkstk() do { } while (0)
@@ -310,798 +315,802 @@
 	Rename a file (move) in the file system.
 */
 static int umsdos_rename_f(
-	struct inode * old_dir,
-	const char * old_name,
-	int old_len,
-	struct inode * new_dir,
-	const char * new_name,
-	int new_len,
-	int flags)		/* 0 == copy flags from old_name */
-					/* != 0, this is the value of flags */
+			   struct inode * old_dir,
+			   struct dentry *old_dentry,
+			   struct inode * new_dir,
+			   struct dentry *new_dentry,
+			   int flags)		/* 0 == copy flags from old_name */
+     /* != 0, this is the value of flags */
 {
-	int ret = -EPERM;
-	struct umsdos_info old_info;
-	int old_ret = umsdos_parse (old_name,old_len,&old_info);
-	struct umsdos_info new_info;
-	int new_ret = umsdos_parse (new_name,new_len,&new_info);
-chkstk();
-	PRINTK (("umsdos_rename %d %d ",old_ret,new_ret));
-	if (old_ret == 0 && new_ret == 0){
-		umsdos_lockcreate2(old_dir,new_dir);
-chkstk();
-		PRINTK (("old findentry "));
-		ret = umsdos_findentry(old_dir,&old_info,0);
-chkstk();
-		PRINTK (("ret %d ",ret));
-		if (ret == 0){
-			/* check sticky bit on old_dir */
-			if ( !(old_dir->i_mode & S_ISVTX) ||
-			    current->fsuid == old_info.entry.uid ||
-			    current->fsuid == old_dir->i_uid ||
-			    fsuser()) {
-				/* Does new_name already exist? */
-				PRINTK(("new findentry "));
-				ret = umsdos_findentry(new_dir,&new_info,0);
-				if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
-				    !(new_dir->i_mode & S_ISVTX) ||
-				    current->fsuid == new_info.entry.uid ||
-				    current->fsuid == new_dir->i_uid ||
-				    fsuser()) {
-					PRINTK (("new newentry "));
-					umsdos_ren_init(&new_info,&old_info,flags);
-					ret = umsdos_newentry (new_dir,&new_info);
-chkstk();
-					PRINTK (("ret %d %d ",ret,new_info.fake.len));
-					if (ret == 0){
-						PRINTK (("msdos_rename "));
-						atomic_inc(&old_dir->i_count);
-						atomic_inc(&new_dir->i_count);	/* Both inode are needed later */
-						ret = msdos_rename (old_dir
-								    ,old_info.fake.fname,old_info.fake.len
-								    ,new_dir
-								    ,new_info.fake.fname,new_info.fake.len);
-chkstk();
-						PRINTK (("after m_rename ret %d ",ret));
-						if (ret != 0){
-							umsdos_delentry (new_dir,&new_info
-									 ,S_ISDIR(new_info.entry.mode));
-chkstk();
-						}else{
-							ret = umsdos_delentry (old_dir,&old_info
-									       ,S_ISDIR(old_info.entry.mode));
-chkstk();
-							if (ret == 0){
-								/*
-								   This UMSDOS_lookup does not look very useful.
-								   It makes sure that the inode of the file will
-								   be correctly setup (umsdos_patch_inode()) in
-								   case it is already in use.
-								   
-								   Not very efficient ...
-								   */
-								struct inode *inode;
-								atomic_inc(&new_dir->i_count);
-								PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
-								ret = UMSDOS_lookup (new_dir,new_name,new_len
-										     ,&inode);
-chkstk();
-								if (ret != 0){
-									printk ("UMSDOS: partial rename for file %s\n"
-										,new_info.entry.name);
-								}else{
-									/*
-									   Update f_pos so notify_change will succeed
-									   if the file was already in use.
-									   */
-									umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
-chkstk();
-									iput (inode);
-								}
-							}
-						}
-					}
-				}else{
-					/* sticky bit set on new_dir */
-					PRINTK(("sticky set on new "));
-					ret = -EPERM;
-				}
-			}else{
-				/* sticky bit set on old_dir */
-				PRINTK(("sticky set on old "));
-				ret = -EPERM;
-			}
+  int ret = -EPERM;
+  struct umsdos_info old_info;
+  int old_ret = umsdos_parse (old_dentry->d_name.name,
+			      old_dentry->d_name.len,&old_info);
+  struct umsdos_info new_info;
+  int new_ret = umsdos_parse (new_dentry->d_name.name,
+			      new_dentry->d_name.len,&new_info);
+  chkstk();
+  Printk (("umsdos_rename %d %d ",old_ret,new_ret));
+  if (old_ret == 0 && new_ret == 0){
+    umsdos_lockcreate2(old_dir,new_dir);
+    chkstk();
+    Printk (("old findentry "));
+    ret = umsdos_findentry(old_dir,&old_info,0);
+    chkstk();
+    Printk (("ret %d ",ret));
+    if (ret == 0){
+      /* check sticky bit on old_dir */
+      if ( !(old_dir->i_mode & S_ISVTX) || fsuser() ||
+	   current->fsuid == old_info.entry.uid ||
+	   current->fsuid == old_dir->i_uid ) {
+	/* Does new_name already exist? */
+	PRINTK(("new findentry "));
+	ret = umsdos_findentry(new_dir,&new_info,0);
+	if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
+	    !(new_dir->i_mode & S_ISVTX) || fsuser() ||
+	    current->fsuid == new_info.entry.uid ||
+	    current->fsuid == new_dir->i_uid ) {
+	  PRINTK (("new newentry "));
+	  umsdos_ren_init(&new_info,&old_info,flags);
+	  ret = umsdos_newentry (new_dir,&new_info);
+	  chkstk();
+	  PRINTK (("ret %d %d ",ret,new_info.fake.len));
+	  if (ret == 0){
+	    struct dentry *old, *new;
+	    old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL);
+	    new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL);
+
+	    PRINTK (("msdos_rename "));
+	    old_dir->i_count++;
+	    new_dir->i_count++;	/* Both inode are needed later */
+	    ret = msdos_rename (old_dir,
+				old,
+				new_dir,
+				new);
+	    chkstk();
+	    PRINTK (("after m_rename ret %d ",ret));
+	    if (ret != 0){
+	      umsdos_delentry (new_dir,&new_info
+			       ,S_ISDIR(new_info.entry.mode));
+	      chkstk();
+	    }else{
+	      ret = umsdos_delentry (old_dir,&old_info
+				     ,S_ISDIR(old_info.entry.mode));
+	      chkstk();
+	      if (ret == 0){
+		/*
+		  This UMSDOS_lookup does not look very useful.
+		  It makes sure that the inode of the file will
+		  be correctly setup (umsdos_patch_inode()) in
+		  case it is already in use.
+		  
+		  Not very efficient ...
+		*/
+		struct inode *inode;
+		new_dir->i_count++;
+		PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
+		ret = UMSDOS_lookup (new_dir,new_dentry);
+		inode = new_dentry->d_inode;
+		chkstk();
+		if (ret != 0){
+		  printk ("UMSDOS: partial rename for file %s\n"
+			  ,new_info.entry.name);
+		}else{
+		  /*
+		    Update f_pos so notify_change will succeed
+		    if the file was already in use.
+		  */
+		  umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
+		  chkstk();
+		  /* iput (inode); FIXME */
 		}
-		umsdos_unlockcreate(old_dir);
-		umsdos_unlockcreate(new_dir);
+	      }
+	    }
+	  }
+	}else{
+	  /* sticky bit set on new_dir */
+	  Printk(("sticky set on new "));
+	  ret = -EPERM;
 	}
-	iput (old_dir);
-	iput (new_dir);
-	PRINTK (("\n"));
-	return ret;
+      }else{
+	/* sticky bit set on old_dir */
+	Printk(("sticky set on old "));
+	ret = -EPERM;
+      }
+    }
+    umsdos_unlockcreate(old_dir);
+    umsdos_unlockcreate(new_dir);
+  }
+  d_move(old_dentry,new_dentry);
+  Printk (("\n"));
+  return ret;
 }
 /*
 	Setup un Symbolic link or a (pseudo) hard link
 	Return a negative error code or 0 if ok.
 */
 static int umsdos_symlink_x(
-	struct inode * dir,
-	const char * name,
-	int len,
-	const char * symname,	/* name will point to this path */
-	int mode,
-	char flags)
+			    struct inode * dir,
+			    struct dentry *dentry,
+			    const char * symname,	/* name will point to this path */
+			    int mode,
+			    char flags)
 {
-	/* #Specification: symbolic links / strategy
-		A symbolic link is simply a file which hold a path. It is
-		implemented as a normal MSDOS file (not very space efficient :-()
-
-		I see 2 different way to do it. One is to place the link data
-		in unused entry of the EMD file. The other is to have a separate
-		file dedicated to hold all symbolic links data.
-
-		Let's go for simplicity...
-	*/
-	struct inode *inode;
-	int ret;
-	atomic_inc(&dir->i_count);/* We keep the inode in case we need it */
-						/* later */
-	ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
-	PRINTK (("umsdos_symlink ret %d ",ret));
-	if (ret == 0){
-		int len = strlen(symname);
-		struct file filp;
-		filp.f_pos = 0;
-		/* Make the inode acceptable to MSDOS */
-		ret = umsdos_file_write_kmem (inode,&filp,symname,len);
-		iput (inode);
-		if (ret >= 0){
-			if (ret != len){
-				ret = -EIO;
-				printk ("UMSDOS: "
-					"Can't write symbolic link data\n");
-			}else{
-				ret = 0;
-			}
-		}
-		if (ret != 0){
-			UMSDOS_unlink (dir,name,len);
-			dir = NULL;
-		}
-	}
-	iput (dir);
-	PRINTK (("\n"));
-	return ret;
+  /* #Specification: symbolic links / strategy
+     A symbolic link is simply a file which hold a path. It is
+     implemented as a normal MSDOS file (not very space efficient :-()
+     
+     I see 2 different way to do it. One is to place the link data
+     in unused entry of the EMD file. The other is to have a separate
+     file dedicated to hold all symbolic links data.
+     
+     Let's go for simplicity...
+  */
+  
+  
+  int ret;
+  dir->i_count++;/* We keep the inode in case we need it */
+  /* later */
+  ret = umsdos_create_any (dir,dentry,mode,0,flags);
+  Printk (("umsdos_symlink ret %d ",ret));
+  if (ret == 0){
+    int len = strlen(symname);
+    struct file filp;
+    filp.f_pos = 0;
+    /* Make the inode acceptable to MSDOS FIXME */
+    Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n"));
+    ret = umsdos_file_write_kmem (dentry->d_inode->i_ino, &filp,symname,ret,NULL);	/* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast... */
+    /* dput(dentry); ?? where did this come from FIXME */
+    if (ret >= 0){
+      if (ret != len){
+	ret = -EIO;
+	printk ("UMSDOS: "
+		"Can't write symbolic link data\n");
+      }else{
+	ret = 0;
+      }
+    }
+    if (ret != 0){
+      UMSDOS_unlink (dir,dentry);
+      dir = NULL;
+    }
+  }
+  d_instantiate(dentry,dir);
+  Printk (("\n"));
+  return ret;
 }
 /*
-	Setup un Symbolic link.
-	Return a negative error code or 0 if ok.
+  Setup un Symbolic link.
+  Return a negative error code or 0 if ok.
 */
 int UMSDOS_symlink(
-	struct inode * dir,
-	const char * name,
-	int len,
-	const char * symname)	/* name will point to this path */
+   struct inode * dir,
+   struct dentry *dentry,
+   const char * symname
+   )
 {
-	return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
+  return umsdos_symlink_x (dir,dentry,symname,S_IFLNK|0777,0);
 }
 /*
-	Add a link to an inode in a directory
+  Add a link to an inode in a directory
 */
 int UMSDOS_link (
-	struct inode * oldinode,
-	struct inode * dir,
-	const char * name,
-	int len)
+		 struct dentry * olddentry,
+		 struct inode * dir,
+		 struct dentry *dentry)
 {
-	/* #Specification: hard link / strategy
-		Well ... hard link are difficult to implement on top of an
-		MsDOS fat file system. Unlike UNIX file systems, there are no
-		inode. A directory entry hold the functionality of the inode
-		and the entry.
-
-		We will used the same strategy as a normal Unix file system
-		(with inode) except we will do it symbolically (using paths).
-
-		Because anything can happen during a DOS session (defragment,
-		directory sorting, etc...), we can't rely on MsDOS pseudo
-		inode number to record the link. For this reason, the link
-		will be done using hidden symbolic links. The following
-		scenario illustrate how it work.
-		
-		Given a file /foo/file
-
-		#
-			ln /foo/file /tmp/file2
-
-			become internally
-
-			mv /foo/file /foo/-LINK1
-			ln -s /foo/-LINK1 /foo/file
-			ln -s /foo/-LINK1 /tmp/file2
-		#
-
-		Using this strategy, we can operate on /foo/file or /foo/file2.
-		We can remove one and keep the other, like a normal Unix hard link.
-		We can rename /foo/file or /tmp/file2 independently.
-			
-		The entry -LINK1 will be hidden. It will hold a link count.
-		When all link are erased, the hidden file is erased too.
-	*/
-	/* #Specification: weakness / hard link
-		The strategy for hard link introduces a side effect that
-		may or may not be acceptable. Here is the sequence
-
-		#
-		mkdir subdir1
-		touch subdir1/file
-		mkdir subdir2
-		ln    subdir1/file subdir2/file
-		rm    subdir1/file
-		rmdir subdir1
-		rmdir: subdir1: Directory not empty
-		#
-
-		This happen because there is an invisible file (--link) in
-		subdir1 which is referenced by subdir2/file.
-
-		Any idea ?
-	*/
-	/* #Specification: weakness / hard link / rename directory
-		Another weakness of hard link come from the fact that
-		it is based on hidden symbolic links. Here is an example.
-
-		#
-		mkdir /subdir1
-		touch /subdir1/file
-		mkdir /subdir2
-		ln    /subdir1/file subdir2/file
-		mv    /subdir1 subdir3
-		ls -l /subdir2/file
-		#
-
-		Since /subdir2/file is a hidden symbolic link
-		to /subdir1/..hlinkNNN, accessing it will fail since
-		/subdir1 does not exist anymore (has been renamed).
-	*/
-	int ret = 0;
-	if (S_ISDIR(oldinode->i_mode)){
-		/* #Specification: hard link / directory
-			A hard link can't be made on a directory. EPERM is returned
-			in this case.
-		*/
-		ret = -EPERM;
-	}else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){
-		struct inode *olddir;
-		ret = umsdos_get_dirowner(oldinode,&olddir);
-		PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
-			,oldinode->u.umsdos_i.i_dir_owner,olddir,
-			 atomic_read(&olddir->i_count)));
+    struct inode *oldinode = olddentry->d_inode;
+  /* #Specification: hard link / strategy
+     Well ... hard link are difficult to implement on top of an
+     MsDOS fat file system. Unlike UNIX file systems, there are no
+     inode. A directory entry hold the functionality of the inode
+     and the entry.
+     
+     We will used the same strategy as a normal Unix file system
+     (with inode) except we will do it symbolically (using paths).
+     
+     Because anything can happen during a DOS session (defragment,
+     directory sorting, etc...), we can't rely on MsDOS pseudo
+     inode number to record the link. For this reason, the link
+     will be done using hidden symbolic links. The following
+     scenario illustrate how it work.
+     
+     Given a file /foo/file
+     
+     #
+     ln /foo/file /tmp/file2
+     
+     become internally
+     
+     mv /foo/file /foo/-LINK1
+     ln -s /foo/-LINK1 /foo/file
+     ln -s /foo/-LINK1 /tmp/file2
+     #
+     
+     Using this strategy, we can operate on /foo/file or /foo/file2.
+     We can remove one and keep the other, like a normal Unix hard link.
+     We can rename /foo/file or /tmp/file2 independently.
+     
+     The entry -LINK1 will be hidden. It will hold a link count.
+     When all link are erased, the hidden file is erased too.
+  */
+  /* #Specification: weakness / hard link
+     The strategy for hard link introduces a side effect that
+     may or may not be acceptable. Here is the sequence
+     
+     #
+     mkdir subdir1
+     touch subdir1/file
+     mkdir subdir2
+     ln    subdir1/file subdir2/file
+     rm    subdir1/file
+     rmdir subdir1
+     rmdir: subdir1: Directory not empty
+     #
+     
+     This happen because there is an invisible file (--link) in
+     subdir1 which is referenced by subdir2/file.
+     
+     Any idea ?
+  */
+  /* #Specification: weakness / hard link / rename directory
+     Another weakness of hard link come from the fact that
+     it is based on hidden symbolic links. Here is an example.
+     
+     #
+     mkdir /subdir1
+     touch /subdir1/file
+     mkdir /subdir2
+     ln    /subdir1/file subdir2/file
+     mv    /subdir1 subdir3
+     ls -l /subdir2/file
+     #
+     
+     Since /subdir2/file is a hidden symbolic link
+     to /subdir1/..hlinkNNN, accessing it will fail since
+     /subdir1 does not exist anymore (has been renamed).
+  */
+  int ret = 0;
+  if (S_ISDIR(oldinode->i_mode)){
+    /* #Specification: hard link / directory
+       A hard link can't be made on a directory. EPERM is returned
+       in this case.
+    */
+    ret = -EPERM;
+  }else if ((ret = umsdos_nevercreat(dir,dentry,-EPERM))==0){
+    struct inode *olddir;
+    ret = umsdos_get_dirowner(oldinode,&olddir);
+    Printk (("umsdos_link dir_owner = %d -> %p [%d] "
+	     ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
+    if (ret == 0){
+      struct umsdos_dirent entry;
+      umsdos_lockcreate2(dir,olddir);
+      ret = umsdos_inode2entry (olddir,oldinode,&entry);
+      if (ret == 0){
+	Printk (("umsdos_link :%s: ino %d flags %d "
+		 ,entry.name
+		 ,oldinode->i_ino,entry.flags));
+	if (!(entry.flags & UMSDOS_HIDDEN)){
+	  /* #Specification: hard link / first hard link
+	     The first time a hard link is done on a file, this
+	     file must be renamed and hidden. Then an internal
+	     symbolic link must be done on the hidden file.
+	     
+	     The second link is done after on this hidden file.
+	     
+	     It is expected that the Linux MSDOS file system
+	     keeps the same pseudo inode when a rename operation
+	     is done on a file in the same directory.
+	  */
+	  struct umsdos_info info;
+	  ret = umsdos_newhidden (olddir,&info);
+	  if (ret == 0){
+	    Printk (("olddir[%d] ",olddir->i_count));
+	    ret = umsdos_rename_f( 
+				  olddentry->d_inode,
+				  olddentry,
+				  dir,
+				  dentry,
+				   UMSDOS_HIDDEN);
+	    if (ret == 0){
+	      char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+	      if (path == NULL){
+		ret = -ENOMEM;
+	      }else{
+		struct dentry *temp;
+		temp = creat_dentry (entry.name, entry.name_len, NULL);
+		Printk (("olddir[%d] ",olddir->i_count));
+		ret = umsdos_locate_path (oldinode,path);
+		Printk (("olddir[%d] ",olddir->i_count));
 		if (ret == 0){
-			struct umsdos_dirent entry;
-			umsdos_lockcreate2(dir,olddir);
-			ret = umsdos_inode2entry (olddir,oldinode,&entry);
-			if (ret == 0){
-				PRINTK (("umsdos_link :%s: ino %d flags %d "
-					,entry.name
-					,oldinode->i_ino,entry.flags));
-				if (!(entry.flags & UMSDOS_HIDDEN)){
-					/* #Specification: hard link / first hard link
-						The first time a hard link is done on a file, this
-						file must be renamed and hidden. Then an internal
-						symbolic link must be done on the hidden file.
-
-						The second link is done after on this hidden file.
-
-						It is expected that the Linux MSDOS file system
-						keeps the same pseudo inode when a rename operation
-						is done on a file in the same directory.
-					*/
-					struct umsdos_info info;
-					ret = umsdos_newhidden (olddir,&info);
-					if (ret == 0){
-						atomic_add(2, &olddir->i_count);
-						PRINTK (("olddir[%d] ",
-							 atomic_read(&olddir->i_count)));
-						ret = umsdos_rename_f (olddir,entry.name
-							,entry.name_len
-							,olddir,info.entry.name,info.entry.name_len
-							,UMSDOS_HIDDEN);
-						if (ret == 0){
-							char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-							if (path == NULL){
-								ret = -ENOMEM;
-							}else{
-								PRINTK (("olddir[%d] ",
-									 atomic_read(&olddir->i_count)));
-								ret = umsdos_locate_path (oldinode,path);
-								PRINTK (("olddir[%d] ",
-									 atomic_read(&olddir->i_count)));
-								if (ret == 0){
-									atomic_inc(&olddir->i_count);
-									ret = umsdos_symlink_x (olddir
-										,entry.name
-										,entry.name_len,path
-										,S_IFREG|0777,UMSDOS_HLINK);
-									if (ret == 0){
-										atomic_inc(&dir->i_count);
-										ret = umsdos_symlink_x (dir,name,len
-											,path
-											,S_IFREG|0777,UMSDOS_HLINK);
-									}
-								}
-								kfree (path);
-							}
-						}
-					}
-				}else{
-					char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-					if (path == NULL){
-						ret = -ENOMEM;
-					}else{
-						ret = umsdos_locate_path (oldinode,path);
-						if (ret == 0){
-							atomic_inc(&dir->i_count);
-							ret = umsdos_symlink_x (dir,name,len,path
-											,S_IFREG|0777,UMSDOS_HLINK);
-						}
-						kfree (path);
-					}
-				}
-			}
-			umsdos_unlockcreate(olddir);
-			umsdos_unlockcreate(dir);
+		  olddir->i_count++;
+		  ret = umsdos_symlink_x (olddir
+					  ,temp
+					  ,path
+					  ,S_IFREG|0777,UMSDOS_HLINK);
+		  if (ret == 0){
+		    dir->i_count++;
+		    ret = umsdos_symlink_x (dir,dentry,
+					    path,
+					    S_IFREG|0777,UMSDOS_HLINK);
+		  }
 		}
-		iput (olddir);
+		kfree (path);
+	      }
+	    }
+	  }
+	}else{
+	  char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
+	  if (path == NULL){
+	    ret = -ENOMEM;
+	  }else{
+	    ret = umsdos_locate_path (oldinode,path);
+	    if (ret == 0){
+	      dir->i_count++;
+	      ret = umsdos_symlink_x (dir,dentry,path
+				      ,S_IFREG|0777,UMSDOS_HLINK);
+	    }
+	    kfree (path);
+	  }
 	}
-	if (ret == 0){
-		struct iattr newattrs;
-		oldinode->i_nlink++;
-		newattrs.ia_valid = 0;
-		ret = UMSDOS_notify_change(oldinode, &newattrs);
-	}
-	iput (oldinode);
-	iput (dir);
-	PRINTK (("umsdos_link %d\n",ret));
-	return ret;
+      }
+      umsdos_unlockcreate(olddir);
+      umsdos_unlockcreate(dir);
+    }
+    iput (olddir);
+  }
+  if (ret == 0){
+    struct iattr newattrs;
+    oldinode->i_nlink++;
+    newattrs.ia_valid = 0;
+    ret = UMSDOS_notify_change(olddentry, &newattrs);
+  }
+  dput (olddentry);
+  dput (dentry);
+  Printk (("umsdos_link %d\n",ret));
+  return ret;
 }
 /*
-	Add a new file into the alternate directory.
-	The file is added to the real MSDOS directory. If successful, it
-	is then added to the EDM file.
-
-	Return the status of the operation. 0 mean success.
+  Add a new file into the alternate directory.
+  The file is added to the real MSDOS directory. If successful, it
+  is then added to the EDM file.
+  
+  Return the status of the operation. 0 mean success.
 */
 int UMSDOS_create (
-	struct inode *dir,
-	const char *name,		/* Name of the file to add */
-	int len,				/* Length of the name */
-	int mode,				/* Permission bit + file type ??? */
-	struct inode **result)	/* Will hold the inode of the newly created */
+		   struct inode *dir,
+		   struct dentry *dentry, /* Length of the name */
+		   int mode		  /* Permission bit + file type ??? */
+		   )	/* Will hold the inode of the newly created */
 							/* file */
 {
-	return umsdos_create_any (dir,name,len,mode,0,0,result);
+  return umsdos_create_any (dir,dentry,mode,0,0);
 }
 /*
 	Add a sub-directory in a directory
 */
 int UMSDOS_mkdir(
-	struct inode * dir,
-	const char * name,
-	int len,
-	int mode)
+		 struct inode * dir,
+		 struct dentry *dentry,
+		 int mode)
 {
-	int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
-	if (ret == 0){
-		struct umsdos_info info;
-		ret = umsdos_parse (name,len,&info);
-		PRINTK (("umsdos_mkdir %d\n",ret));
-		if (ret == 0){
-			info.entry.mode = mode | S_IFDIR;
-			info.entry.rdev = 0;
-			info.entry.uid = current->fsuid;
-			info.entry.gid = (dir->i_mode & S_ISGID)
-				? dir->i_gid : current->fsgid;
-			info.entry.ctime = info.entry.atime = info.entry.mtime
-				= CURRENT_TIME;
-			info.entry.flags = 0;
-			umsdos_lockcreate(dir);
-			info.entry.nlink = 1;
-			ret = umsdos_newentry (dir,&info);
-			PRINTK (("newentry %d ",ret));
-			if (ret == 0){
-				atomic_inc(&dir->i_count);
-				ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
-				if (ret != 0){
-					umsdos_delentry (dir,&info,1);
-					/* #Specification: mkdir / Directory already exist in DOS
-						We do the same thing as for file creation.
-						For all user it is an error.
-					*/
-				}else{
-					/* #Specification: mkdir / umsdos directory / create EMD
-						When we created a new sub-directory in a UMSDOS
-						directory (one with full UMSDOS semantic), we
-						create immediately an EMD file in the new
-						sub-directory so it inherit UMSDOS semantic.
-					*/
-					struct inode *subdir;
-					ret = umsdos_real_lookup (dir,info.fake.fname
-						,info.fake.len,&subdir);
-					if (ret == 0){
-						struct inode *result;
-						ret = msdos_create (subdir,UMSDOS_EMD_FILE
-							,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
-						subdir = NULL;
-						iput (result);
-					}
-					if (ret < 0){
-						printk ("UMSDOS: Can't create empty --linux-.---\n");
-					}
-					iput (subdir);
-				}
-			}
-			umsdos_unlockcreate(dir);
-		}
+  int ret = umsdos_nevercreat(dir,dentry,-EEXIST);
+  if (ret == 0){
+    struct umsdos_info info;
+    ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
+    Printk (("umsdos_mkdir %d\n",ret));
+    if (ret == 0){
+      info.entry.mode = mode | S_IFDIR;
+      info.entry.rdev = 0;
+      info.entry.uid = current->fsuid;
+      info.entry.gid = (dir->i_mode & S_ISGID)
+	? dir->i_gid : current->fsgid;
+      info.entry.ctime = info.entry.atime = info.entry.mtime
+	= CURRENT_TIME;
+      info.entry.flags = 0;
+      umsdos_lockcreate(dir);
+      info.entry.nlink = 1;
+      ret = umsdos_newentry (dir,&info);
+      Printk (("newentry %d ",ret));
+      if (ret == 0){
+	struct dentry *temp;
+	temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+	dir->i_count++;
+	ret = msdos_mkdir (dir, temp, mode);
+	if (ret != 0){
+	  umsdos_delentry (dir,&info,1);
+	  /* #Specification: mkdir / Directory already exist in DOS
+	     We do the same thing as for file creation.
+	     For all user it is an error.
+	  */
+	}else{
+	  /* #Specification: mkdir / umsdos directory / create EMD
+	     When we created a new sub-directory in a UMSDOS
+	     directory (one with full UMSDOS semantic), we
+	     create immediately an EMD file in the new
+	     sub-directory so it inherit UMSDOS semantic.
+	  */
+	  struct inode *subdir;
+	  ret = compat_umsdos_real_lookup (dir,info.fake.fname,
+					   info.fake.len,&subdir);
+	  if (ret == 0){
+	    struct inode *result;
+	    struct dentry *tdentry;
+	    tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+
+	    ret = msdos_create (subdir, tdentry,S_IFREG|0777);
+	    subdir = NULL;
+	    /* iput (result); FIXME */
+	  }
+	  if (ret < 0){
+	    printk ("UMSDOS: Can't create empty --linux-.---\n");
+	  }
+	  /* iput (subdir); FIXME */
 	}
-	PRINTK (("umsdos_mkdir %d\n",ret));
-	iput (dir);
-	return ret;
+      }
+      umsdos_unlockcreate(dir);
+    }
+  }
+  Printk (("umsdos_mkdir %d\n",ret));
+  dput (dentry);
+  return ret;
 }
 /*
 	Add a new device special file into a directory.
 */
 int UMSDOS_mknod(
 	struct inode * dir,
-	const char * name,
-	int len,
+	struct dentry *dentry,         
 	int mode,
 	int rdev)
 {
-	/* #Specification: Special files / strategy
-		Device special file, pipes, etc ... are created like normal
-		file in the msdos file system. Of course they remain empty.
-
-		One strategy was to create those files only in the EMD file
-		since they were not important for MSDOS. The problem with
-		that, is that there were not getting inode number allocated.
-		The MSDOS filesystems is playing a nice game to fake inode
-		number, so why not use it.
-
-		The absence of inode number compatible with those allocated
-		for ordinary files was causing major trouble with hard link
-		in particular and other parts of the kernel I guess.
-	*/
-	struct inode *inode;
-	int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
-	iput (inode);
-	return ret;
+  /* #Specification: Special files / strategy
+     Device special file, pipes, etc ... are created like normal
+     file in the msdos file system. Of course they remain empty.
+     
+     One strategy was to create those files only in the EMD file
+     since they were not important for MSDOS. The problem with
+     that, is that there were not getting inode number allocated.
+     The MSDOS filesystems is playing a nice game to fake inode
+     number, so why not use it.
+     
+     The absence of inode number compatible with those allocated
+     for ordinary files was causing major trouble with hard link
+     in particular and other parts of the kernel I guess.
+  */
+  int ret = umsdos_create_any (dir,dentry,mode,rdev,0);
+  dput(dentry);
+  return ret;
 }
 
 /*
-	Remove a sub-directory.
+  Remove a sub-directory.
 */
 int UMSDOS_rmdir(
 	struct inode * dir,
-	const char * name,
-	int len)
+	struct dentry *dentry)
 {
-	/* #Specification: style / iput strategy
-		In the UMSDOS project, I am trying to apply a single
-		programming style regarding inode management. Many
-		entry point are receiving an inode to act on, and must
-		do an iput() as soon as they are finished with
-		the inode.
-
-		For simple case, there is no problem. When you introduce
-		error checking, you end up with many iput placed around the
-		code.
-
-		The coding style I use all around is one where I am trying
-		to provide independent flow logic (I don't know how to
-		name this). With this style, code is easier to understand
-		but you rapidly get iput() all around. Here is an exemple
-		of what I am trying to avoid.
-
-		#
-		if (a){
-			...
-			if(b){
-				...
-			}
-			...
-			if (c){
-				// Complex state. Was b true ? 
-				...
-			}
-			...
-		}
-		// Weird state
-		if (d){
-			// ...
-		}
-		// Was iput finally done ?
-		return status;
-		#
-
-		Here is the style I am using. Still sometime I do the
-		first when things are very simple (or very complicated :-( )
-
-		#
-		if (a){
-			if (b){
-				...
-			}else if (c){
-				// A single state gets here
-			}
-		}else if (d){
-			...
-		}
-		return status;
-		#
-
-		Again, while this help clarifying the code, I often get a lot
-		of iput(), unlike the first style, where I can place few 
-		"strategic" iput(). "strategic" also mean, more difficult
-		to place.
-
-		So here is the style I will be using from now on in this project.
-		There is always an iput() at the end of a function (which has
-		to do an iput()). One iput by inode. There is also one iput()
-		at the places where a successful operation is achieved. This
-		iput() is often done by a sub-function (often from the msdos
-		file system). So I get one too many iput() ? At the place
-		where an iput() is done, the inode is simply nulled, disabling
-		the last one.
-
-		#
-		if (a){
-			if (b){
-				...
-			}else if (c){
-				msdos_rmdir(dir,...);
-				dir = NULL;
-			}
-		}else if (d){
-			...
-		}
-		iput (dir);
-		return status;
-		#
-
-		Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
-		pair goes against this practice of "forgetting" the inode as soon
-		as possible.
-	*/		
-	int ret = umsdos_nevercreat(dir,name,len,-EPERM);
-	if (ret == 0){
-		struct inode *sdir;
-		atomic_inc(&dir->i_count);
-		ret = UMSDOS_lookup (dir,name,len,&sdir);
-		PRINTK (("rmdir lookup %d ",ret));
-		if (ret == 0){
-			int empty;
-			umsdos_lockcreate(dir);
-			if (atomic_read(&sdir->i_count) > 1){
-				ret = -EBUSY;
-			}else if ((empty = umsdos_isempty (sdir)) != 0){
-				PRINTK (("isempty %d i_count %d ",empty,
-					 atomic_read(&sdir->i_count)));
+  /* #Specification: style / iput strategy
+     In the UMSDOS project, I am trying to apply a single
+     programming style regarding inode management. Many
+     entry point are receiving an inode to act on, and must
+     do an iput() as soon as they are finished with
+     the inode.
+     
+     For simple case, there is no problem. When you introduce
+     error checking, you end up with many iput placed around the
+     code.
+     
+     The coding style I use all around is one where I am trying
+     to provide independent flow logic (I don't know how to
+     name this). With this style, code is easier to understand
+     but you rapidly get iput() all around. Here is an exemple
+     of what I am trying to avoid.
+     
+     #
+     if (a){
+     ...
+     if(b){
+     ...
+     }
+     ...
+     if (c){
+     // Complex state. Was b true ? 
+     ...
+     }
+     ...
+     }
+     // Weird state
+     if (d){
+     // ...
+     }
+     // Was iput finally done ?
+     return status;
+     #
+     
+     Here is the style I am using. Still sometime I do the
+     first when things are very simple (or very complicated :-( )
+     
+     #
+     if (a){
+     if (b){
+     ...
+     }else if (c){
+     // A single state gets here
+     }
+     }else if (d){
+     ...
+     }
+     return status;
+     #
+     
+     Again, while this help clarifying the code, I often get a lot
+     of iput(), unlike the first style, where I can place few 
+     "strategic" iput(). "strategic" also mean, more difficult
+     to place.
+     
+     So here is the style I will be using from now on in this project.
+     There is always an iput() at the end of a function (which has
+     to do an iput()). One iput by inode. There is also one iput()
+     at the places where a successful operation is achieved. This
+     iput() is often done by a sub-function (often from the msdos
+     file system). So I get one too many iput() ? At the place
+     where an iput() is done, the inode is simply nulled, disabling
+     the last one.
+     
+     #
+     if (a){
+     if (b){
+     ...
+     }else if (c){
+     msdos_rmdir(dir,...);
+     dir = NULL;
+     }
+     }else if (d){
+     ...
+     }
+     iput (dir);
+     return status;
+     #
+     
+     Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
+     pair goes against this practice of "forgetting" the inode as soon
+     as possible.
+  */		
+
+  int ret = umsdos_nevercreat(dir,dentry,-EPERM);
+  if (ret == 0){
+    volatile struct inode *sdir;
+    dir->i_count++;
+    ret = UMSDOS_lookup (dir, dentry);
+    sdir = dentry->d_inode;
+    Printk (("rmdir lookup %d ",ret));
+    if (ret == 0){
+      int empty;
+      umsdos_lockcreate(dir);
+      if (sdir->i_count > 1){
+	ret = -EBUSY;
+      }else if ((empty = umsdos_isempty (sdir)) != 0){
+	struct dentry *tdentry;
+	tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_FILE, NULL);
+	Printk (("isempty %d i_count %d ",empty,sdir->i_count));
 				/* check sticky bit */
-				if ( !(dir->i_mode & S_ISVTX) ||
-				    current->fsuid == sdir->i_uid ||
-				    current->fsuid == dir->i_uid ||
-				    fsuser()) {
-					if (empty == 1){
-						/* We have to removed the EMD file */
-						ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
-								   ,UMSDOS_EMD_NAMELEN);
-						sdir = NULL;
-					}
-					/* sdir must be free before msdos_rmdir() */
-					iput (sdir);
-					sdir = NULL;
-					PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
-					if (ret == 0){
-						struct umsdos_info info;
-						atomic_inc(&dir->i_count);
-						umsdos_parse (name,len,&info);
-						/* The findentry is there only to complete */
-						/* the mangling */
-						umsdos_findentry (dir,&info,2);
-						ret = msdos_rmdir (dir,info.fake.fname
-								   ,info.fake.len);
-						if (ret == 0){
-							ret = umsdos_delentry (dir,&info,1);
-						}
-					}
-				}else{
-					/* sticky bit set and we don't have permission */
-					PRINTK(("sticky set "));
-					ret = -EPERM;
-				}
-			}else{	
-				/*
-					The subdirectory is not empty, so leave it there
-				*/
-				ret = -ENOTEMPTY;
-			}
-			iput(sdir);
-			umsdos_unlockcreate(dir);
-		}	
+	if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+	     current->fsuid == sdir->i_uid ||
+	     current->fsuid == dir->i_uid ) {
+	  if (empty == 1){
+	    /* We have to removed the EMD file */
+	    ret = msdos_unlink (sdir, tdentry);
+	    sdir = NULL;
+	  }
+	  /* sdir must be free before msdos_rmdir() */
+	  /* iput (sdir); FIXME */
+	  sdir = NULL;
+	  Printk (("isempty ret %d nlink %d ",ret,dir->i_nlink));
+	  if (ret == 0){
+	    struct umsdos_info info;
+	    struct dentry *temp;
+	    dir->i_count++;
+	    umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
+	    /* The findentry is there only to complete */
+	    /* the mangling */
+	    umsdos_findentry (dir,&info,2);
+	    temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+	    
+	    ret = msdos_rmdir (dir, temp);
+	    if (ret == 0){
+	      ret = umsdos_delentry (dir,&info,1);
+	    }
+	  }
+	}else{
+	  /* sticky bit set and we don't have permission */
+	  Printk(("sticky set "));
+	  ret = -EPERM;
 	}
-	iput (dir);
-	PRINTK (("umsdos_rmdir %d\n",ret));
-	return ret;
+      }else{	
+	/*
+	  The subdirectory is not empty, so leave it there
+	*/
+	ret = -ENOTEMPTY;
+      }
+      /* iput(sdir); FIXME */
+      umsdos_unlockcreate(dir);
+    }	
+  }
+  dput(dentry);
+  Printk (("umsdos_rmdir %d\n",ret));
+  return ret;
 }
+
+
+
 /*
-	Remove a file from the directory.
+  Remove a file from the directory.
 */
 int UMSDOS_unlink (
 	struct inode * dir,
-	const char * name,
-	int len)
+	struct dentry *dentry)
 {
-	int ret = umsdos_nevercreat(dir,name,len,-EPERM);
-	if (ret == 0){
-		struct umsdos_info info;
-		ret = umsdos_parse (name,len,&info);
-		if (ret == 0){
-			umsdos_lockcreate(dir);
-			ret = umsdos_findentry(dir,&info,1);
-			if (ret == 0){
-				PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
+  int ret = umsdos_nevercreat(dir,dentry,-EPERM);
+  if (ret == 0){
+    struct umsdos_info info;
+    ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
+    if (ret == 0){
+      umsdos_lockcreate(dir);
+      ret = umsdos_findentry(dir,&info,1);
+      if (ret == 0){
+	Printk (("UMSDOS_unlink %s ",info.fake.fname));
 				/* check sticky bit */
-				if ( !(dir->i_mode & S_ISVTX) ||
-				    current->fsuid == info.entry.uid ||
-				    current->fsuid == dir->i_uid ||
-				    fsuser()) {
-					if (info.entry.flags & UMSDOS_HLINK){
-						/* #Specification: hard link / deleting a link
-						   When we deletes a file, and this file is a link
-						   we must subtract 1 to the nlink field of the
-						   hidden link.
-						   
-						   If the count goes to 0, we delete this hidden
-						   link too.
-						   */
-						/*
-						   First, get the inode of the hidden link
-						   using the standard lookup function.
-						   */
-						struct inode *inode;
-						atomic_inc(&dir->i_count);
-						ret = UMSDOS_lookup (dir,name,len,&inode);
-						if (ret == 0){
-							PRINTK (("unlink nlink = %d ",inode->i_nlink));
-							inode->i_nlink--;
-							if (inode->i_nlink == 0){
-								struct inode *hdir = iget(inode->i_sb
-											  ,inode->u.umsdos_i.i_dir_owner);
-								struct umsdos_dirent entry;
-								ret = umsdos_inode2entry (hdir,inode,&entry);
-								if (ret == 0){
-									ret = UMSDOS_unlink (hdir,entry.name
-											     ,entry.name_len);
-								}else{
-									iput (hdir);
-								}
-							}else{
-								struct iattr newattrs;
-								newattrs.ia_valid = 0;
-								ret = UMSDOS_notify_change (inode, &newattrs);
-							}
-							iput (inode);
-						}
-					}
-					if (ret == 0){
-						ret = umsdos_delentry (dir,&info,0);
-						if (ret == 0){
-							PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
-							atomic_inc(&dir->i_count);
-							ret = msdos_unlink_umsdos (dir,info.fake.fname
-										   ,info.fake.len);
-							PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
-								 ,info.entry.mode,ret));
-						}
-					}
-				}else{
-					/* sticky bit set and we've not got permission */
-					PRINTK(("sticky set "));
-					ret = -EPERM;
-				}
-			}
-			umsdos_unlockcreate(dir);
+	if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+	     current->fsuid == info.entry.uid ||
+	     current->fsuid == dir->i_uid ) {
+	  if (info.entry.flags & UMSDOS_HLINK){
+	    /* #Specification: hard link / deleting a link
+	       When we deletes a file, and this file is a link
+	       we must subtract 1 to the nlink field of the
+	       hidden link.
+	       
+	       If the count goes to 0, we delete this hidden
+	       link too.
+	    */
+	    /*
+	      First, get the inode of the hidden link
+	      using the standard lookup function.
+	    */
+	    struct inode *inode;
+	    dir->i_count++;
+	    ret = UMSDOS_lookup (dir,dentry);
+	    inode = dentry->d_inode;
+	    if (ret == 0){
+	      Printk (("unlink nlink = %d ",inode->i_nlink));
+	      inode->i_nlink--;
+	      if (inode->i_nlink == 0){
+		struct inode *hdir = iget(inode->i_sb
+					  ,inode->u.umsdos_i.i_dir_owner);
+		struct umsdos_dirent entry;
+		ret = umsdos_inode2entry (hdir,inode,&entry);
+		if (ret == 0){
+		  ret = UMSDOS_unlink (hdir,dentry);
+		}else{
+		    /* iput (hdir); FIXME */
 		}
-	}	
-	iput (dir);
-	PRINTK (("umsdos_unlink %d\n",ret));
-	return ret;
+	      }else{
+		struct iattr newattrs;
+		newattrs.ia_valid = 0;
+		ret = UMSDOS_notify_change (dentry, &newattrs);
+	      }
+	      /* iput (inode); FIXME */
+	    }
+	  }
+	  if (ret == 0){
+	    ret = umsdos_delentry (dir,&info,0);
+	    if (ret == 0){
+	      struct dentry *temp;
+	      Printk (("Avant msdos_unlink %s ",info.fake.fname));
+	      dir->i_count++;
+	      temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+	      ret = msdos_unlink_umsdos (dir, temp);
+	      Printk (("msdos_unlink %s %o ret %d ",info.fake.fname
+		       ,info.entry.mode,ret));
+	    }
+	  }
+	}else{
+	  /* sticky bit set and we've not got permission */
+	  Printk(("sticky set "));
+	  ret = -EPERM;
+	}
+      }
+      umsdos_unlockcreate(dir);
+    }
+  }	
+  dput(dentry);
+  Printk (("umsdos_unlink %d\n",ret));
+  return ret;
 }
 
+
+
 /*
 	Rename a file (move) in the file system.
 */
 int UMSDOS_rename(
-	struct inode * old_dir,
-	const char * old_name,
-	int old_len,
-	struct inode * new_dir,
-	const char * new_name,
-	int new_len)
+		  struct inode * old_dir,
+		  struct dentry * old_dentry,
+		  struct inode * new_dir,
+		  struct dentry * new_dentry)
 {
-	/* #Specification: weakness / rename
-		There is a case where UMSDOS rename has a different behavior
-		than normal UNIX file system. Renaming an open file across
-		directory boundary does not work. Renaming an open file within
-		a directory does work however.
-
-		The problem (not sure) is in the linux VFS msdos driver.
-		I believe this is not a bug but a design feature, because
-		an inode number represent some sort of directory address
-		in the MSDOS directory structure. So moving the file into
-		another directory does not preserve the inode number.
-	*/
-	int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
-	if (ret == 0){
-		/* umsdos_rename_f eat the inode and we may need those later */
-		atomic_inc(&old_dir->i_count);
-		atomic_inc(&new_dir->i_count);
-		ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
-			,new_len,0);
-		if (ret == -EEXIST){
-			/* #Specification: rename / new name exist
-			        If the destination name already exist, it will
-				silently be removed. EXT2 does it this way
-				and this is the spec of SUNOS. So does UMSDOS.
-
-				If the destination is an empty directory it will
-				also be removed.
-			*/
-			/* #Specification: rename / new name exist / possible flaw
-				The code to handle the deletion of the target (file
-				and directory) use to be in umsdos_rename_f, surrounded
-				by proper directory locking. This was insuring that only
-				one process could achieve a rename (modification) operation
-				in the source and destination directory. This was also
-				insuring the operation was "atomic".
-
-				This has been changed because this was creating a kernel
-				stack overflow (stack is only 4k in the kernel). To avoid
-				the code doing the deletion of the target (if exist) has
-				been moved to a upper layer. umsdos_rename_f is tried
-				once and if it fails with EEXIST, the target is removed
-				and umsdos_rename_f is done again.
-
-				This makes the code cleaner and (not sure) solve a
-				deadlock problem one tester was experiencing.
-
-				The point is to mention that possibly, the semantic of
-				"rename" may be wrong. Anyone dare to check that :-)
-				Be aware that IF it is wrong, to produce the problem you
-				will need two process trying to rename a file to the
-				same target at the same time. Again, I am not sure it
-				is a problem at all.
-			*/
-			/* This is not super efficient but should work */
-			atomic_inc(&new_dir->i_count);
-			ret = UMSDOS_unlink (new_dir,new_name,new_len);
-chkstk();
-			PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
-			if (ret == -EISDIR){
-				atomic_inc(&new_dir->i_count);
-				ret = UMSDOS_rmdir (new_dir,new_name,new_len);
-chkstk();
-				PRINTK (("rename rmdir ret %d -- ",ret));
-			}
-			if (ret == 0){
-				ret = umsdos_rename_f (old_dir,old_name,old_len
-					,new_dir,new_name,new_len,0);
-				new_dir = old_dir = NULL;
-			}
-		}
-	}
-	iput (new_dir);
-	iput (old_dir);
-	return ret;
+  /* #Specification: weakness / rename
+     There is a case where UMSDOS rename has a different behavior
+     than normal UNIX file system. Renaming an open file across
+     directory boundary does not work. Renaming an open file within
+     a directory does work however.
+     
+     The problem (not sure) is in the linux VFS msdos driver.
+     I believe this is not a bug but a design feature, because
+     an inode number represent some sort of directory address
+     in the MSDOS directory structure. So moving the file into
+     another directory does not preserve the inode number.
+  */
+  int ret = umsdos_nevercreat(new_dir,new_dentry,-EEXIST);
+  if (ret == 0){
+    /* umsdos_rename_f eat the inode and we may need those later */
+    old_dir->i_count++;
+    new_dir->i_count++;
+    ret = umsdos_rename_f (old_dir,old_dentry,new_dir,new_dentry,0);
+    if (ret == -EEXIST){
+      /* #Specification: rename / new name exist
+	 If the destination name already exist, it will
+	 silently be removed. EXT2 does it this way
+	 and this is the spec of SUNOS. So does UMSDOS.
+	 
+	 If the destination is an empty directory it will
+	 also be removed.
+      */
+      /* #Specification: rename / new name exist / possible flaw
+	 The code to handle the deletion of the target (file
+	 and directory) use to be in umsdos_rename_f, surrounded
+	 by proper directory locking. This was insuring that only
+	 one process could achieve a rename (modification) operation
+	 in the source and destination directory. This was also
+	 insuring the operation was "atomic".
+	 
+	 This has been changed because this was creating a kernel
+	 stack overflow (stack is only 4k in the kernel). To avoid
+	 the code doing the deletion of the target (if exist) has
+	 been moved to a upper layer. umsdos_rename_f is tried
+	 once and if it fails with EEXIST, the target is removed
+	 and umsdos_rename_f is done again.
+	 
+	 This makes the code cleaner and (not sure) solve a
+	 deadlock problem one tester was experiencing.
+	 
+	 The point is to mention that possibly, the semantic of
+	 "rename" may be wrong. Anyone dare to check that :-)
+	 Be aware that IF it is wrong, to produce the problem you
+	 will need two process trying to rename a file to the
+	 same target at the same time. Again, I am not sure it
+	 is a problem at all.
+      */
+      /* This is not super efficient but should work */
+      new_dir->i_count++;
+      ret = UMSDOS_unlink (new_dir,new_dentry);
+      chkstk();
+      Printk (("rename unlink ret %d -- ",ret));
+      if (ret == -EISDIR){
+	new_dir->i_count++;
+	ret = UMSDOS_rmdir (new_dir,new_dentry);
+	chkstk();
+	Printk (("rename rmdir ret %d -- ",ret));
+      }
+      if (ret == 0){
+	ret = umsdos_rename_f(old_dir,old_dentry,
+			      new_dir,new_dentry,0);
+	new_dir = old_dir = NULL;
+      }
+    }
+  }
+  dput (new_dentry);
+  dput (old_dentry);
+  return ret;
 }
 
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.1.86/linux/fs/umsdos/rdir.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/umsdos/rdir.c	Thu Feb 12 13:36:57 1998
@@ -32,240 +32,270 @@
 
 static int rdir_filldir(
 	void * buf,
-	const char * name,
+	const char *name,
 	int name_len,
 	off_t offset,
 	ino_t ino)
 {
-	int ret = 0;
-	struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf;
-	if (d->real_root){
-		/* real root of a pseudo_rooted partition */
-		if (name_len != UMSDOS_PSDROOT_LEN
-			|| memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){
-			/* So it is not the /linux directory */
-			if (name_len == 2
-				&& name[0] == '.'
-				&& name[1] == '.'){
+  int ret = 0;
+  struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR*) buf;
+  Printk ((KERN_DEBUG "rdir_filldir /mn/: entering\n"));
+  if (d->real_root){
+    Printk ((KERN_DEBUG "rdir_filldir /mn/: real root!\n"));
+    /* real root of a pseudo_rooted partition */
+    if (name_len != UMSDOS_PSDROOT_LEN
+	|| memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0){
+      /* So it is not the /linux directory */
+      if (name_len == 2
+	  && name[0] == '.'
+	  && name[1] == '.'){
 				/* Make sure the .. entry points back to the pseudo_root */
-				ino = pseudo_root->i_ino;
-			}
-			ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
-		}
-	}else{
-		/* Any DOS directory */
-		ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
-	}
-	return ret;
+	ino = pseudo_root->i_ino;
+      }
+      ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
+    }
+  }else{
+    /* Any DOS directory */
+    Printk ((KERN_DEBUG "rdir_filldir /mn/: calling d->filldir (%p) for %12s (%d)\n",d->filldir,name,ino));
+    ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
+  }
+  return ret;
 }
 
 
 static int UMSDOS_rreaddir (
-	struct inode *dir,
 	struct file *filp,
-    void *dirbuf,
+	void *dirbuf,
 	filldir_t filldir)
 {
-	struct RDIR_FILLDIR bufk;
-	bufk.filldir = filldir;
-	bufk.dirbuf = dirbuf;
-	bufk.real_root = pseudo_root != NULL
-		&& dir == dir->i_sb->s_mounted
-		&& dir == pseudo_root->i_sb->s_mounted;
-	return fat_readdir(dir,filp,&bufk,rdir_filldir);
+  struct RDIR_FILLDIR bufk;
+  struct inode *dir = filp->f_dentry->d_inode;
+  
+  Printk ((KERN_DEBUG "UMSDOS_rreaddir /mn/: entering %p %p\n", filldir, dirbuf));
+
+  
+  bufk.filldir = filldir;
+  bufk.dirbuf = dirbuf;
+  bufk.real_root = pseudo_root
+    && dir == iget(dir->i_sb,UMSDOS_ROOT_INO)
+    && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO);
+  Printk ((KERN_DEBUG "UMSDOS_rreaddir /mn/: calling fat_readdir with filldir=%p and exiting\n",filldir));
+  return fat_readdir(filp, &bufk, rdir_filldir);
 }
 
+
 /*
-	Lookup into a non promoted directory.
-	If the result is a directory, make sure we find out if it is
-	a promoted one or not (calling umsdos_setup_dir_inode(inode)).
+  Lookup into a non promoted directory.
+  If the result is a directory, make sure we find out if it is
+  a promoted one or not (calling umsdos_setup_dir_inode(inode)).
 */
 int umsdos_rlookup_x(
-	struct inode *dir,
-	const char *name,
-	int len,
-	struct inode **result,	/* Will hold inode of the file, if successful */
-	int nopseudo)			/* Don't care about pseudo root mode */
-							/* so locating "linux" will work */
+   struct inode *dir,
+   struct dentry *dentry,
+   int nopseudo)   /* Don't care about pseudo root mode */
+     /* so locating "linux" will work */
 {
-	int ret;
-	if (pseudo_root != NULL
-		&& len == 2
-		&& name[0] == '.'
-		&& name[1] == '.'
-		&& dir == dir->i_sb->s_mounted
-		&& dir == pseudo_root->i_sb->s_mounted){
-		*result = pseudo_root;
-		atomic_inc(&pseudo_root->i_count);
-		ret = 0;
-		/* #Specification: pseudo root / DOS/..
-			In the real root directory (c:\), the directory ..
-			is the pseudo root (c:\linux).
-		*/
-	}else{
-		ret = umsdos_real_lookup (dir,name,len,result);
-		if (ret == 0){
-			struct inode *inode = *result;
-			if (inode == pseudo_root && !nopseudo){
-				/* #Specification: pseudo root / DOS/linux
-					Even in the real root directory (c:\), the directory
-					/linux won't show
-				*/
-				ret = -ENOENT;
-				iput (pseudo_root);
-				*result = NULL;
-			}else if (S_ISDIR(inode->i_mode)){
-				/* We must place the proper function table */
-				/* depending if this is a MsDOS directory or an UMSDOS directory */
-				umsdos_setup_dir_inode(inode);
-			}
-		}
-	}
-	iput (dir);
-	return ret;
+  int len = dentry->d_name.len;
+  const char *name = dentry->d_name.name;
+  struct inode *inode;
+  int ret;
+  if (pseudo_root
+      && len == 2
+      && name[0] == '.'
+      && name[1] == '.'
+      && dir == iget(dir->i_sb,UMSDOS_ROOT_INO)
+      && dir == iget(pseudo_root->i_sb,UMSDOS_ROOT_INO) ){
+    /*    *result = pseudo_root;*/
+    Printk (("umsdos_rlookup_x: we are at pseudo-root thingy?\n"));
+    pseudo_root->i_count++;
+    ret = 0;
+    /* #Specification: pseudo root / DOS/..
+       In the real root directory (c:\), the directory ..
+       is the pseudo root (c:\linux).
+    */
+  }else{
+    ret = umsdos_real_lookup (dir, dentry); inode=dentry->d_inode;
+    Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup for %s in %d returned %d\n", name, dir->i_ino, ret));
+    Printk ((KERN_DEBUG "umsdos_rlookup_x: umsdos_real_lookup: inode is %p resolving to ", inode));
+    if (inode) {	/* /mn/ FIXME: DEL_ME */
+        Printk ((KERN_DEBUG "i_ino=%d\n",inode->i_ino));
+    } else {
+        Printk ((KERN_DEBUG "NONE!\n"));
+    }
+    if ((ret == 0) && inode){
+      
+      if (pseudo_root && inode == pseudo_root && !nopseudo){
+      /* #Specification: pseudo root / DOS/linux
+	 Even in the real root directory (c:\), the directory
+	 /linux won't show
+      */
+        Printk (("umsdos_rlookup_x: do the pseudo-thingy...\n"));
+	ret = -ENOENT;
+	iput (pseudo_root);
+       
+      }else if (S_ISDIR(inode->i_mode)){
+	/* We must place the proper function table */
+	/* depending if this is a MsDOS directory or an UMSDOS directory */
+        Printk (("umsdos_rlookup_x: setting up setup_dir_inode %d...\n", inode->i_ino));
+	umsdos_setup_dir_inode (inode);
+      }
+    }
+  }
+  iput (dir);
+  Printk ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
+  return ret;
 }
+
+
 int UMSDOS_rlookup(
 	struct inode *dir,
-	const char *name,
-	int len,
-	struct inode **result)	/* Will hold inode of the file, if successful */
+	struct dentry *dentry
+	)
 {
-	return umsdos_rlookup_x(dir,name,len,result,0);
+  Printk ((KERN_DEBUG "UMSDOS_rlookup /mn/: executing umsdos_rlookup_x for ino=%d in %20s\n",dir->i_ino,dentry->d_name.name));
+  return umsdos_rlookup_x(dir,dentry,0);
 }
 
+
 static int UMSDOS_rrmdir (
 	struct inode *dir,
-	const char *name,
-	int len)
+	struct dentry *dentry)
 {
-	/* #Specification: dual mode / rmdir in a DOS directory
-		In a DOS (not EMD in it) directory, we use a reverse strategy
-		compared with an Umsdos directory. We assume that a subdirectory
-		of a DOS directory is also a DOS directory. This is not always
-		true (umssync may be used anywhere), but make sense.
-
-		So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
-		then we check if it is a Umsdos directory. We check if it is
-		really empty (only . .. and --linux-.--- in it). If it is true
-		we remove the EMD and do a msdos_rmdir() again.
-
-		In a Umsdos directory, we assume all subdirectory are also
-		Umsdos directory, so we check the EMD file first.
-	*/
-	int ret;
-	if (umsdos_is_pseudodos(dir,name,len)){
-		/* #Specification: pseudo root / rmdir /DOS
-			The pseudo sub-directory /DOS can't be removed!
-			This is done even if the pseudo root is not a Umsdos
-			directory anymore (very unlikely), but an accident (under
-			MsDOS) is always possible.
-
-			EPERM is returned.
-		*/
-		ret = -EPERM;
+  /* #Specification: dual mode / rmdir in a DOS directory
+     In a DOS (not EMD in it) directory, we use a reverse strategy
+     compared with an Umsdos directory. We assume that a subdirectory
+     of a DOS directory is also a DOS directory. This is not always
+     true (umssync may be used anywhere), but make sense.
+     
+     So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
+     then we check if it is a Umsdos directory. We check if it is
+     really empty (only . .. and --linux-.--- in it). If it is true
+     we remove the EMD and do a msdos_rmdir() again.
+
+     In a Umsdos directory, we assume all subdirectory are also
+     Umsdos directory, so we check the EMD file first.
+  */
+  int ret;
+  if (umsdos_is_pseudodos(dir,dentry)){
+    /* #Specification: pseudo root / rmdir /DOS
+       The pseudo sub-directory /DOS can't be removed!
+       This is done even if the pseudo root is not a Umsdos
+       directory anymore (very unlikely), but an accident (under
+       MsDOS) is always possible.
+       
+       EPERM is returned.
+    */
+    ret = -EPERM;
+  }else{
+    umsdos_lockcreate (dir);
+    dir->i_count++;
+    ret = msdos_rmdir (dir,dentry);
+    if (ret == -ENOTEMPTY){
+      struct inode *sdir;
+      dir->i_count++;
+      
+      ret = UMSDOS_rlookup (dir,dentry);
+      sdir = dentry->d_inode;
+      PRINTK (("rrmdir lookup %d ",ret));
+      if (ret == 0){
+	int empty;
+	if ((empty = umsdos_isempty (sdir)) != 0){
+	  PRINTK (("isempty %d i_count %d ",empty,
+		   atomic_read(&sdir->i_count)));
+	  if (empty == 2){
+	    /*
+	      Not a Umsdos directory, so the previous msdos_rmdir
+	      was not lying :-)
+	    */
+	    ret = -ENOTEMPTY;
+	  }else if (empty == 1){
+	    /* We have to removed the EMD file */
+	    struct dentry *temp;
+	    temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+	    ret = msdos_unlink(sdir, temp);
+	    sdir = NULL;
+	    if (ret == 0){
+	      dir->i_count++;
+	      ret = msdos_rmdir (dir,dentry);
+	    }
+	  }
 	}else{
-		umsdos_lockcreate (dir);
-		atomic_inc(&dir->i_count);
-		ret = msdos_rmdir (dir,name,len);
-		if (ret == -ENOTEMPTY){
-			struct inode *sdir;
-			atomic_inc(&dir->i_count);
-			ret = UMSDOS_rlookup (dir,name,len,&sdir);
-			PRINTK (("rrmdir lookup %d ",ret));
-			if (ret == 0){
-				int empty;
-				if ((empty = umsdos_isempty (sdir)) != 0){
-					PRINTK (("isempty %d i_count %d ",empty,
-						 atomic_read(&sdir->i_count)));
-					if (empty == 2){
-						/*
-							Not a Umsdos directory, so the previous msdos_rmdir
-							was not lying :-)
-						*/
-						ret = -ENOTEMPTY;
-					}else if (empty == 1){
-						/* We have to removed the EMD file */
-						ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
-							,UMSDOS_EMD_NAMELEN);
-						sdir = NULL;
-						if (ret == 0){
-							atomic_inc(&dir->i_count);
-							ret = msdos_rmdir (dir,name,len);
-						}
-					}
-				}else{
-					ret = -ENOTEMPTY;
-				}
-				iput (sdir);
-			}
-		}
-		umsdos_unlockcreate (dir);
+	  ret = -ENOTEMPTY;
 	}
-	iput (dir);
-	return ret;
+	iput (sdir);
+      }
+    }
+    umsdos_unlockcreate (dir);
+  }
+  iput (dir);
+  return ret;
 }
 
 /* #Specification: dual mode / introduction
-	One goal of UMSDOS is to allow a practical and simple coexistence
-	between MsDOS and Linux in a single partition. Using the EMD file
-	in each directory, UMSDOS add Unix semantics and capabilities to
-	normal DOS file system. To help and simplify coexistence, here is
-	the logic related to the EMD file.
-
-	If it is missing, then the directory is managed by the MsDOS driver.
-	The names are limited to DOS limits (8.3). No links, no device special
-	and pipe and so on.
-
-	If it is there, it is the directory. If it is there but empty, then
-	the directory looks empty. The utility umssync allows synchronisation
-	of the real DOS directory and the EMD.
-
-	Whenever umssync is applied to a directory without EMD, one is
-	created on the fly. The directory is promoted to full unix semantic.
-	Of course, the ls command will show exactly the same content as before
-	the umssync session.
-
-	It is believed that the user/admin will promote directories to unix
-	semantic as needed.
-
-	The strategy to implement this is to use two function table (struct
-	inode_operations). One for true UMSDOS directory and one for directory
-	with missing EMD.
-
-	Functions related to the DOS semantic (but aware of UMSDOS) generally
-	have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
-	from the one with full UMSDOS semantic.
+   One goal of UMSDOS is to allow a practical and simple coexistence
+   between MsDOS and Linux in a single partition. Using the EMD file
+   in each directory, UMSDOS add Unix semantics and capabilities to
+   normal DOS file system. To help and simplify coexistence, here is
+   the logic related to the EMD file.
+   
+   If it is missing, then the directory is managed by the MsDOS driver.
+   The names are limited to DOS limits (8.3). No links, no device special
+   and pipe and so on.
+
+   If it is there, it is the directory. If it is there but empty, then
+   the directory looks empty. The utility umssync allows synchronisation
+   of the real DOS directory and the EMD.
+
+   Whenever umssync is applied to a directory without EMD, one is
+   created on the fly. The directory is promoted to full unix semantic.
+   Of course, the ls command will show exactly the same content as before
+   the umssync session.
+
+   It is believed that the user/admin will promote directories to unix
+   semantic as needed.
+
+   The strategy to implement this is to use two function table (struct
+   inode_operations). One for true UMSDOS directory and one for directory
+   with missing EMD.
+
+   Functions related to the DOS semantic (but aware of UMSDOS) generally
+   have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
+   from the one with full UMSDOS semantic.
 */
 static struct file_operations umsdos_rdir_operations = {
-	NULL,				/* lseek - default */
-	UMSDOS_dir_read,	/* read */
-	NULL,				/* write - bad */
-	UMSDOS_rreaddir,	/* readdir */
-	NULL,				/* poll - default */
-	UMSDOS_ioctl_dir,	/* ioctl - default */
-	NULL,				/* mmap */
-	NULL,				/* no special open code */
-	NULL,				/* no special release code */
-	NULL				/* fsync */
+  NULL,				/* lseek - default */
+  UMSDOS_dir_read,		/* read */
+  NULL,				/* write - bad */
+  UMSDOS_rreaddir,		/* readdir */
+  NULL,				/* poll - default */
+  UMSDOS_ioctl_dir,		/* ioctl - default */
+  NULL,				/* mmap */
+  NULL,				/* no special open code */
+  NULL,				/* no special release code */
+  NULL				/* fsync */
 };
 
 struct inode_operations umsdos_rdir_inode_operations = {
-	&umsdos_rdir_operations,	/* default directory file-ops */
-	msdos_create,		/* create */
-	UMSDOS_rlookup,		/* lookup */
-	NULL,				/* link */
-	msdos_unlink,		/* unlink */
-	NULL,				/* symlink */
-	msdos_mkdir,		/* mkdir */
-	UMSDOS_rrmdir,		/* rmdir */
-	NULL,				/* mknod */
-	msdos_rename,		/* rename */
-	NULL,				/* readlink */
-	NULL,				/* readpage */
-	NULL,				/* writepage */
-	NULL,				/* bmap */
-	NULL,				/* truncate */
-	NULL				/* permission */
+  &umsdos_rdir_operations,	/* default directory file-ops */
+  msdos_create,			/* create */
+  UMSDOS_rlookup,		/* lookup */
+  NULL,				/* link */
+  msdos_unlink,			/* unlink */
+  NULL,				/* symlink */
+  msdos_mkdir,			/* mkdir */
+  UMSDOS_rrmdir,		/* rmdir */
+  NULL,				/* mknod */
+  msdos_rename,			/* rename */
+  NULL,				/* readlink */
+  NULL,				/* followlink */
+  NULL,				/* readpage */
+  NULL,				/* writepage */
+  NULL,				/* bmap */
+  NULL,				/* truncate */
+  NULL,				/* permission */
+  NULL,				/* smap */
+  NULL,				/* updatepage */
+  NULL,				/* revalidate */
 };
 
 
diff -u --recursive --new-file v2.1.86/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c
--- v2.1.86/linux/fs/umsdos/symlink.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/umsdos/symlink.c	Thu Feb 12 13:36:57 1998
@@ -22,38 +22,99 @@
 #define PRINTK(x)
 #define Printk(x)	printk x
 
+static struct file_operations umsdos_symlink_operations;
+
+
 /*
 	Read the data associate with the symlink.
 	Return length read in buffer or  a negative error code.
+	FIXME, this is messed up.
+	
+	/mn/ WIP fixing...
 */
 static int umsdos_readlink_x (
-	struct inode *inode,
+	struct dentry *dentry,
 	char *buffer,
-	long (*msdos_read)(struct inode *, struct file *, char *, unsigned long),
 	int bufsiz)
 {
-	int ret = inode->i_size;
+	int ret = dentry->d_inode->i_size;
+	loff_t loffs = 0;
 	struct file filp;
+	
+	memset (&filp, 0, sizeof (filp));
+	
 	filp.f_pos = 0;
 	filp.f_reada = 0;
+	filp.f_flags = O_RDONLY;
+	filp.f_dentry = dentry;
+        filp.f_op = &umsdos_symlink_operations;	 /* /mn/ - we have to fill it with dummy values so we won't segfault */
+
 	if (ret > bufsiz) ret = bufsiz;
-	if ((*msdos_read) (inode, &filp, buffer,ret) != ret){
+
+        Printk ((KERN_WARNING "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%ld, offs=%d\n", &filp, buffer, ret, loffs));
+        Printk ((KERN_WARNING "  f_op=%p\n", filp.f_op));
+        Printk ((KERN_WARNING "  inode=%d, i_size=%d\n", filp.f_dentry->d_inode->i_ino,filp.f_dentry->d_inode->i_size));
+        Printk ((KERN_WARNING "  f_pos=%ld\n", filp.f_pos));
+        Printk ((KERN_WARNING "  name=%12s\n", filp.f_dentry->d_name.name));
+        Printk ((KERN_WARNING "  i_binary(sb)=%d\n", MSDOS_I(filp.f_dentry->d_inode)->i_binary ));
+        Printk ((KERN_WARNING "  f_count=%d, f_flags=%d\n", filp.f_count, filp.f_flags));
+        Printk ((KERN_WARNING "  f_owner=%d\n", filp.f_owner));
+        Printk ((KERN_WARNING "  f_version=%ld\n", filp.f_version));
+        Printk ((KERN_WARNING "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp.f_reada, filp.f_ramax, filp.f_raend, filp.f_ralen, filp.f_rawin));
+
+
+	/* FIXME */
+	Printk (("umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %ld)\n", &filp, buffer, ret, loffs));
+	if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret){
 		ret = -EIO;
 	}
+#if 0
+    {
+      struct umsdos_dirent *mydirent=buffer;
+
+      Printk ((KERN_DEBUG "  (DDD) uid=%d\n",mydirent->uid));
+      Printk ((KERN_DEBUG "  (DDD) gid=%d\n",mydirent->gid));
+      Printk ((KERN_DEBUG "  (DDD) name=>%20s<\n",mydirent->name));
+    }
+#endif  
+
+	Printk (("umsdos_readlink_x: FIXME /mn/: fat_file_read returned offs=%ld ret=%d\n", loffs, ret));
 	return ret;
 }
 
-static int UMSDOS_readlink(struct inode * inode, char * buffer, int buflen)
+
+
+static int UMSDOS_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
 	int ret;
 
-	ret = umsdos_readlink_x (inode,buffer,fat_file_read,buflen);
-	PRINTK (("readlink %d %x bufsiz %d\n",ret,inode->i_mode,buflen));
-	iput(inode);
+	Printk (("UMSDOS_readlink: calling umsdos_readlink_x for %20s\n", dentry->d_name.name));
+	ret = umsdos_readlink_x (dentry, buffer, buflen);
+	Printk (("readlink %d bufsiz %d\n", ret, buflen));
+	/* dput(dentry); / * FIXME /mn/ */
+	Printk (("UMSDOS_readlink /mn/: FIXME! skipped dput(dentry). returning %d\n", ret));
 	return ret;
 	
 }
 
+static struct dentry *UMSDOS_followlink(struct dentry * dentry,	struct dentry * base)
+{
+	int ret;
+	char symname[256];
+	struct inode *inode = dentry->d_inode;
+	mm_segment_t old_fs = get_fs();
+	Printk ((KERN_ERR "UMSDOS_followlink /mn/: (%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name));
+
+	set_fs (KERNEL_DS);	/* we read into kernel space */
+	ret = umsdos_readlink_x (dentry, &symname, 256);
+	set_fs (old_fs);
+	
+	base = creat_dentry (symname, ret, NULL);
+/*	UMSDOS_lookup (dentry->d_parent->d_inode, base);*/
+	
+	return base;
+}
+
 static struct file_operations umsdos_symlink_operations = {
 	NULL,				/* lseek - default */
 	NULL,				/* read */
@@ -67,8 +128,9 @@
 	NULL				/* fsync */
 };
 
+
 struct inode_operations umsdos_symlink_inode_operations = {
-	&umsdos_symlink_operations,	/* default file operations */
+	NULL,	/* default file operations */
 	NULL,			/* create */
 	NULL,			/* lookup */
 	NULL,			/* link */
@@ -79,11 +141,16 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	UMSDOS_readlink,	/* readlink */
-	NULL,			/* readpage */
+	NULL/*UMSDOS_followlink*/,	/* followlink */	/* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */
+	generic_readpage,	/* readpage */	/* in original NULL. changed to generic_readpage. FIXME? /mn/ */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	fat_bmap,		/* bmap */	/* in original NULL. changed to fat_bmap. FIXME? /mn/ */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* updatepage */
+	NULL			/* revalidate */
+	
 };
 
 
diff -u --recursive --new-file v2.1.86/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.1.86/linux/fs/vfat/namei.c	Fri Jan 23 18:10:32 1998
+++ linux/fs/vfat/namei.c	Sun Feb 15 11:38:01 1998
@@ -1761,12 +1761,15 @@
 	new_inode->i_mtime  = old_inode->i_mtime;
 	new_inode->i_atime  = old_inode->i_atime;
 	new_inode->i_ctime  = old_inode->i_ctime;
+	new_inode->i_nlink  = old_inode->i_nlink;
+	new_inode->i_op     = old_inode->i_op;
 	MSDOS_I(new_inode)->i_ctime_ms = MSDOS_I(old_inode)->i_ctime_ms;
 
 	MSDOS_I(new_inode)->i_start = MSDOS_I(old_inode)->i_start;
 	MSDOS_I(new_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart;
 	MSDOS_I(new_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs;
 
+	fat_cache_inval_inode(old_inode);
 	mark_inode_dirty(new_inode);
 
 	old_dir->i_version = ++event;
diff -u --recursive --new-file v2.1.86/linux/include/asm-alpha/fpu.h linux/include/asm-alpha/fpu.h
--- v2.1.86/linux/include/asm-alpha/fpu.h	Mon Jan 12 14:49:36 1998
+++ linux/include/asm-alpha/fpu.h	Thu Feb 12 13:31:28 1998
@@ -81,7 +81,38 @@
 	return fp;
 }
 
-extern unsigned long rdfpcr(void);
-extern void wrfpcr(unsigned long);
+#ifdef __KERNEL__
+
+/* The following two functions don't need trapb/excb instructions
+   around the mf_fpcr/mt_fpcr instructions because (a) the kernel
+   never generates arithmetic faults and (b) call_pal instructions
+   are implied trap barriers.  */
+
+static inline unsigned long rdfpcr(void)
+{
+	unsigned long tmp, ret;
+	__asm__ ("stt $f0,%0\n\t"
+		 "mf_fpcr $f0\n\t"
+		 "stt $f0,%1\n\t"
+		 "ldt $f0,%0"
+		: "=m"(tmp), "=m"(ret));
+	return ret;
+}
+
+static inline void wrfpcr(unsigned long val)
+{
+	unsigned long tmp;
+	__asm__ __volatile__ (
+		"stt $f0,%0\n\t"
+		"ldt $f0,%1\n\t"
+		"mt_fpcr $f0\n\t"
+		"ldt $f0,%0"
+		: "=m"(tmp) : "m"(val));
+}
+
+extern unsigned long alpha_read_fp_reg (unsigned long reg);
+extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
+
+#endif /* __KERNEL__ */
 
 #endif /* __ASM_ALPHA_FPU_H */
diff -u --recursive --new-file v2.1.86/linux/include/asm-alpha/ioctls.h linux/include/asm-alpha/ioctls.h
--- v2.1.86/linux/include/asm-alpha/ioctls.h	Thu Dec  4 13:09:01 1997
+++ linux/include/asm-alpha/ioctls.h	Thu Feb 12 16:25:04 1998
@@ -86,6 +86,8 @@
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454
diff -u --recursive --new-file v2.1.86/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v2.1.86/linux/include/asm-alpha/unistd.h	Thu Feb 12 20:56:12 1998
+++ linux/include/asm-alpha/unistd.h	Thu Feb 12 16:44:15 1998
@@ -240,7 +240,7 @@
 #define __NR_bdflush		300
 #define __NR_sethae		301
 #define __NR_mount		302
-#define __NR_adjtimex		303
+#define __NR_old_adjtimex	303
 #define __NR_swapoff		304
 #define __NR_getdents		305
 #define __NR_create_module	306
diff -u --recursive --new-file v2.1.86/linux/include/asm-arm/ioctls.h linux/include/asm-arm/ioctls.h
--- v2.1.86/linux/include/asm-arm/ioctls.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/ioctls.h	Thu Feb 12 16:25:04 1998
@@ -47,6 +47,8 @@
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
 #define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX		0x5451
diff -u --recursive --new-file v2.1.86/linux/include/asm-i386/ioctls.h linux/include/asm-i386/ioctls.h
--- v2.1.86/linux/include/asm-i386/ioctls.h	Thu Dec  4 13:09:01 1997
+++ linux/include/asm-i386/ioctls.h	Thu Feb 12 16:25:04 1998
@@ -47,6 +47,8 @@
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
 #define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX		0x5451
diff -u --recursive --new-file v2.1.86/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.1.86/linux/include/asm-i386/pgtable.h	Fri Feb  6 15:32:54 1998
+++ linux/include/asm-i386/pgtable.h	Mon Feb 16 15:33:43 1998
@@ -200,7 +200,8 @@
  * memory. 
  */
 #define _PAGE_PRESENT	0x001
-#define _PAGE_RW	0x002
+#define _PAGE_PROTNONE	0x002		/* If not present */
+#define _PAGE_RW	0x002		/* If present */
 #define _PAGE_USER	0x004
 #define _PAGE_WT	0x008
 #define _PAGE_PCD	0x010
@@ -213,7 +214,7 @@
 #define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
-#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
 #define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
@@ -291,7 +292,7 @@
 } while (0)
 
 #define pte_none(x)	(!pte_val(x))
-#define pte_present(x)	(pte_val(x) & _PAGE_PRESENT)
+#define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
 #define pte_clear(xp)	do { pte_val(*(xp)) = 0; } while (0)
 
 #define pmd_none(x)	(!pmd_val(x))
@@ -489,9 +490,9 @@
 {
 }
 
-#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
+#define SWP_TYPE(entry) (((entry) >> 2) & 0x3f)
 #define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
+#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 8))
 
 #define module_map      vmalloc
 #define module_unmap    vfree
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/amigahw.h linux/include/asm-m68k/amigahw.h
--- v2.1.86/linux/include/asm-m68k/amigahw.h	Fri Dec 20 01:20:02 1996
+++ linux/include/asm-m68k/amigahw.h	Thu Feb 12 16:30:13 1998
@@ -103,6 +103,7 @@
     AMIGAHW_DECLARE(ALICE_PAL);		/* PAL Alice (8374) */
     AMIGAHW_DECLARE(ALICE_NTSC);	/* NTSC Alice (8374) */
     AMIGAHW_DECLARE(MAGIC_REKICK);	/* A3000 Magic Hard Rekick */
+    AMIGAHW_DECLARE(PCMCIA);		/* PCMCIA Slot */
     AMIGAHW_DECLARE(ZORRO);		/* Zorro AutoConfig */
     AMIGAHW_DECLARE(ZORRO3);		/* Zorro III */
 };
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/amigamouse.h linux/include/asm-m68k/amigamouse.h
--- v2.1.86/linux/include/asm-m68k/amigamouse.h	Thu Feb 29 07:41:01 1996
+++ linux/include/asm-m68k/amigamouse.h	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-#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 v2.1.86/linux/include/asm-m68k/amihdreg.h linux/include/asm-m68k/amihdreg.h
--- v2.1.86/linux/include/asm-m68k/amihdreg.h	Sun Mar 31 13:50:11 1996
+++ linux/include/asm-m68k/amihdreg.h	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-#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 v2.1.86/linux/include/asm-m68k/apollohw.h linux/include/asm-m68k/apollohw.h
--- v2.1.86/linux/include/asm-m68k/apollohw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/apollohw.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,71 @@
+/* apollohw.h : some structures to access apollo HW */
+
+#ifndef _ASMm68k_APOLLOHW_H_
+#define _ASMm68k_APOLLOHW_H_
+
+
+/* 
+   see scn2681 data sheet for more info. 
+   member names are read_write.
+*/
+
+#define DECLARE_2681_FIELD(x) unsigned char x; unsigned char dummy##x
+
+struct SCN2681 {
+
+	DECLARE_2681_FIELD(mra);
+	DECLARE_2681_FIELD(sra_csra);
+	DECLARE_2681_FIELD(BRGtest_cra);
+	DECLARE_2681_FIELD(rhra_thra);
+	DECLARE_2681_FIELD(ipcr_acr);
+	DECLARE_2681_FIELD(isr_imr);
+	DECLARE_2681_FIELD(ctu_ctur);
+	DECLARE_2681_FIELD(ctl_ctlr);
+	DECLARE_2681_FIELD(mrb);
+	DECLARE_2681_FIELD(srb_csrb);
+	DECLARE_2681_FIELD(tst_crb);
+	DECLARE_2681_FIELD(rhrb_thrb);
+	DECLARE_2681_FIELD(reserved);
+	DECLARE_2681_FIELD(ip_opcr);
+	DECLARE_2681_FIELD(startCnt_setOutBit);
+	DECLARE_2681_FIELD(stopCnt_resetOutBit);
+
+};
+
+#if 0
+struct mc146818 {
+
+	unsigned int second1:4, second2:4, alarm_second1:4, alarm_second2:4,
+		     minute1:4, minute2:4, alarm_minute1:4, alarm_minute2:4;
+	unsigned int hours1:4, hours2:4, alarm_hours1:4, alarm_hours2:4,
+		     day_of_week1:4, day_of_week2:4, day_of_month1:4, day_of_month2:4;
+	unsigned int month1:4, month2:4, year1:4, year2:4, :16;
+
+};
+#endif
+
+struct mc146818 {
+        unsigned char second, alarm_second;
+        unsigned char minute, alarm_minute;
+        unsigned char hours, alarm_hours;
+        unsigned char day_of_week, day_of_month;
+        unsigned char month, year;
+};
+
+#define IO_BASE 0x80000000
+
+#define SIO01_PHYSADDR 0x10400
+#define SIO23_PHYSADDR 0x10500
+#define RTC_PHYSADDR 0x10900
+#define PICA 0x11000
+#define PICB 0x11100
+#define sio01 ((*(volatile struct SCN2681 *)(IO_BASE + SIO01_PHYSADDR)))
+#define sio23 ((*(volatile struct SCN2681 *)(IO_BASE + SIO01_PHYSADDR)))
+#define rtc (((volatile struct mc146818 *)(IO_BASE + RTC_PHYSADDR)))
+
+#define inb(addr) (*((volatile unsigned char *)(addr)))
+#define outb(val,addr) (*((volatile unsigned char *)(addr)) = (val))
+#define inw(addr) (*((volatile unsigned short *)(addr)))
+#define outw(val,addr) (*((volatile unsigned short *)(addr)) = (val))
+
+#endif
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atari_SCCserial.h linux/include/asm-m68k/atari_SCCserial.h
--- v2.1.86/linux/include/asm-m68k/atari_SCCserial.h	Wed May 15 23:05:11 1996
+++ linux/include/asm-m68k/atari_SCCserial.h	Thu Feb 12 16:30:13 1998
@@ -28,6 +28,10 @@
 #define SCC_BAUD_BASE_NONE	0		/* for not connected or unused
 						 * clock sources */
 
+#define SCC_BAUD_BASE_MVME_PCLK	781250	/* 12.5 MHz */
+#define SCC_BAUD_BASE_BVM	460800	/* 7.3728 MHz */
+#define SCC_BAUD_BASE_MVME	625000	/* 10.000 MHz */
+
 /* The SCC configuration structure */
 
 struct atari_SCCserial {
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atari_rootsec.h linux/include/asm-m68k/atari_rootsec.h
--- v2.1.86/linux/include/asm-m68k/atari_rootsec.h	Wed Sep 25 00:47:41 1996
+++ linux/include/asm-m68k/atari_rootsec.h	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-#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 */
-} __attribute__((__packed__));
-
-#endif /* _LINUX_ATARI_ROOTSEC_H */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atari_stram.h linux/include/asm-m68k/atari_stram.h
--- v2.1.86/linux/include/asm-m68k/atari_stram.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/atari_stram.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,17 @@
+#ifndef _M68K_ATARI_STRAM_H
+#define _M68K_ATARI_STRAM_H
+
+/*
+ * Functions for Atari ST-RAM management
+ */
+
+/* public interface */
+void *atari_stram_alloc( long size, unsigned long *start_mem,
+						 const char *owner );
+void atari_stram_free( void *);
+
+/* functions called internally by other parts of the kernel */
+void atari_stram_init( void);
+void atari_stram_reserve_pages( unsigned long start_mem );
+
+#endif /*_M68K_ATARI_STRAM_H */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/atarihdreg.h linux/include/asm-m68k/atarihdreg.h
--- v2.1.86/linux/include/asm-m68k/atarihdreg.h	Thu Apr 18 16:35:24 1996
+++ linux/include/asm-m68k/atarihdreg.h	Wed Dec 31 16:00:00 1969
@@ -1,24 +0,0 @@
-#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 v2.1.86/linux/include/asm-m68k/atarihw.h linux/include/asm-m68k/atarihw.h
--- v2.1.86/linux/include/asm-m68k/atarihw.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/atarihw.h	Thu Feb 12 16:30:13 1998
@@ -21,15 +21,38 @@
 #define _LINUX_ATARIHW_H_
 
 #include <linux/types.h>
+#include <asm/bootinfo.h>
 
 extern u_long atari_mch_cookie;
-
-/* 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
-
+extern u_long atari_mch_type;
+extern u_long atari_switches;
+extern int atari_rtc_year_offset;
+extern int atari_dont_touch_floppy_select;
+
+/* convenience macros for testing machine type */
+#define MACH_IS_ST	((atari_mch_cookie >> 16) == ATARI_MCH_ST)
+#define MACH_IS_STE	((atari_mch_cookie >> 16) == ATARI_MCH_STE && \
+			 (atari_mch_cookie & 0xffff) == 0)
+#define MACH_IS_MSTE	((atari_mch_cookie >> 16) == ATARI_MCH_STE && \
+			 (atari_mch_cookie & 0xffff) == 0x10)
+#define MACH_IS_TT	((atari_mch_cookie >> 16) == ATARI_MCH_TT)
+#define MACH_IS_FALCON	((atari_mch_cookie >> 16) == ATARI_MCH_FALCON)
+#define MACH_IS_MEDUSA	(atari_mch_type == ATARI_MACH_MEDUSA)
+#define MACH_IS_HADES	(atari_mch_type == ATARI_MACH_HADES)
+#define MACH_IS_AB40	(atari_mch_type == ATARI_MACH_AB40)
+
+/* values for atari_switches */
+#define ATARI_SWITCH_IKBD	0x01
+#define ATARI_SWITCH_MIDI	0x02
+#define ATARI_SWITCH_SND6	0x04
+#define ATARI_SWITCH_SND7	0x08
+#define ATARI_SWITCH_OVSC_SHIFT	16
+#define ATARI_SWITCH_OVSC_IKBD	(ATARI_SWITCH_IKBD << ATARI_SWITCH_OVSC_SHIFT)
+#define ATARI_SWITCH_OVSC_MIDI	(ATARI_SWITCH_MIDI << ATARI_SWITCH_OVSC_SHIFT)
+#define ATARI_SWITCH_OVSC_SND6	(ATARI_SWITCH_SND6 << ATARI_SWITCH_OVSC_SHIFT)
+#define ATARI_SWITCH_OVSC_SND7	(ATARI_SWITCH_SND7 << ATARI_SWITCH_OVSC_SHIFT)
+#define ATARI_SWITCH_OVSC_MASK	0xffff0000
+	
 /*
  * 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
@@ -92,14 +115,6 @@
 #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;
-extern int is_hades;
-
 /* 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.,
@@ -116,11 +131,11 @@
 
 {
 	if (writeflag) {
-		if (!is_medusa || CPU_IS_060)
+		if (!MACH_IS_MEDUSA || CPU_IS_060)
 			cache_push( paddr, len );
 	}
 	else {
-		if (!is_medusa)
+		if (!MACH_IS_MEDUSA)
 			cache_clear( paddr, len );
 	}
 }
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h
--- v2.1.86/linux/include/asm-m68k/bitops.h	Wed Dec  3 06:18:17 1997
+++ linux/include/asm-m68k/bitops.h	Thu Feb 12 16:30:13 1998
@@ -14,7 +14,23 @@
  * They use the standard big-endian m680x0 bit ordering.
  */
 
-extern __inline__ int test_and_set_bit(int nr,void * vaddr)
+#define test_and_set_bit(nr,vaddr) \
+  (__builtin_constant_p(nr) ? \
+   __constant_test_and_set_bit(nr, vaddr) : \
+   __generic_test_and_set_bit(nr, vaddr))
+
+extern __inline__ int __constant_test_and_set_bit(int nr,void * vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bset %1,%2; sne %0"
+	     : "=d" (retval)
+	     : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+
+	return retval;
+}
+
+extern __inline__ int __generic_test_and_set_bit(int nr,void * vaddr)
 {
 	char retval;
 
@@ -24,13 +40,40 @@
 	return retval;
 }
 
-extern __inline__ void set_bit(int nr, void * vaddr)
+#define set_bit(nr,vaddr) \
+  (__builtin_constant_p(nr) ? \
+   __constant_set_bit(nr, vaddr) : \
+   __generic_set_bit(nr, vaddr))
+
+extern __inline__ void __constant_set_bit(int nr, void * vaddr)
+{
+	__asm__ __volatile__ ("bset %0,%1"
+	     : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+}
+
+extern __inline__ void __generic_set_bit(int nr, void * vaddr)
 {
 	__asm__ __volatile__ ("bfset %1@{%0:#1}"
 	     : : "d" (nr^31), "a" (vaddr));
 }
 
-extern __inline__ int test_and_clear_bit(int nr, void * vaddr)
+#define test_and_clear_bit(nr,vaddr) \
+  (__builtin_constant_p(nr) ? \
+   __constant_test_and_clear_bit(nr, vaddr) : \
+   __generic_test_and_clear_bit(nr, vaddr))
+
+extern __inline__ int __constant_test_and_clear_bit(int nr, void * vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bclr %1,%2; sne %0"
+	     : "=d" (retval)
+	     : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+
+	return retval;
+}
+
+extern __inline__ int __generic_test_and_clear_bit(int nr, void * vaddr)
 {
 	char retval;
 
@@ -40,13 +83,40 @@
 	return retval;
 }
 
-extern __inline__ void clear_bit(int nr, void * vaddr)
+#define clear_bit(nr,vaddr) \
+  (__builtin_constant_p(nr) ? \
+   __constant_clear_bit(nr, vaddr) : \
+   __generic_clear_bit(nr, vaddr))
+
+extern __inline__ void __constant_clear_bit(int nr, void * vaddr)
+{
+	__asm__ __volatile__ ("bclr %0,%1"
+	     : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+}
+
+extern __inline__ void __generic_clear_bit(int nr, void * vaddr)
 {
 	__asm__ __volatile__ ("bfclr %1@{%0:#1}"
 	     : : "d" (nr^31), "a" (vaddr));
 }
 
-extern __inline__ int test_and_change_bit(int nr, void * vaddr)
+#define test_and_change_bit(nr,vaddr) \
+  (__builtin_constant_p(nr) ? \
+   __constant_test_and_change_bit(nr, vaddr) : \
+   __generic_test_and_change_bit(nr, vaddr))
+
+extern __inline__ int __constant_test_and_change_bit(int nr, void * vaddr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bchg %1,%2; sne %0"
+	     : "=d" (retval)
+	     : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+
+	return retval;
+}
+
+extern __inline__ int __generic_test_and_change_bit(int nr, void * vaddr)
 {
 	char retval;
 
@@ -56,7 +126,18 @@
 	return retval;
 }
 
-extern __inline__ void change_bit(int nr, void * vaddr)
+#define change_bit(nr,vaddr) \
+  (__builtin_constant_p(nr) ? \
+   __constant_change_bit(nr, vaddr) : \
+   __generic_change_bit(nr, vaddr))
+
+extern __inline__ void __constant_change_bit(int nr, void * vaddr)
+{
+	__asm__ __volatile__ ("bchg %0,%1"
+	     : : "di" (nr & 7), "m" (((char *)vaddr)[(nr^31) >> 3]));
+}
+
+extern __inline__ void __generic_change_bit(int nr, void * vaddr)
 {
 	__asm__ __volatile__ ("bfchg %1@{%0:#1}"
 	     : : "d" (nr^31), "a" (vaddr));
@@ -256,8 +337,5 @@
 	res = ext2_find_first_zero_bit (p, size - 32 * (p - addr));
 	return (p - addr) * 32 + res;
 }
-
-
-/* Byte swapping (swab16 and swab32) is now in asm/byteorder.h . */
 
 #endif /* _M68K_BITOPS_H */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- v2.1.86/linux/include/asm-m68k/bootinfo.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/bootinfo.h	Thu Feb 12 16:30:13 1998
@@ -93,7 +93,73 @@
      */
 
 #define BI_ATARI_MCH_COOKIE	0x8000	/* _MCH cookie from TOS (u_long) */
+#define BI_ATARI_MCH_TYPE	0x8001	/* special machine type (u_long) */
+					/* (values are ATARI_MACH_* defines */
 
+/* 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
+
+/* mch_type values */
+#define ATARI_MACH_NORMAL	0	/* no special machine type */
+#define ATARI_MACH_MEDUSA	1	/* Medusa 040 */
+#define ATARI_MACH_HADES	2	/* Hades 040 or 060 */
+#define ATARI_MACH_AB40		3	/* Afterburner040 on Falcon */
+
+    /*
+     *  Macintosh-specific tags
+     */
+
+#define BI_MAC_MODEL		0x8000	/* Mac Gestalt ID (model type) */
+#define BI_MAC_VADDR		0x8001	/* Mac video base address */
+#define BI_MAC_VDEPTH		0x8002	/* Mac video depth */
+#define BI_MAC_VROW		0x8003	/* Mac video rowbytes */
+#define BI_MAC_VDIM		0x8004	/* Mac video dimensions */
+#define BI_MAC_VLOGICAL		0x8005	/* Mac video logical base */
+#define BI_MAC_SCCBASE		0x8006	/* Mac SCC base address */
+#define BI_MAC_BTIME		0x8007	/* Mac boot time */
+#define BI_MAC_GMTBIAS		0x8008	/* Mac GMT timezone offset */
+#define BI_MAC_MEMSIZE		0x8009	/* Mac RAM size (sanity check) */
+#define BI_MAC_CPUID		0x800a	/* Mac CPU type (sanity check) */
+
+    /*
+     * Mac: compatibility with old booter data format (temporarily)
+     */
+
+#ifndef __ASSEMBLY__
+
+struct mac_booter_data 
+{
+	unsigned long videoaddr;
+	unsigned long videorow;
+	unsigned long videodepth;
+	unsigned long dimensions;
+	unsigned long args;
+	unsigned long boottime;
+	unsigned long gmtbias;
+	unsigned long bootver;
+	unsigned long videological;
+	unsigned long sccbase;
+	unsigned long id;
+	unsigned long memsize;
+	unsigned long serialmf;
+	unsigned long serialhsk;
+	unsigned long serialgpi;
+	unsigned long printmf;
+	unsigned long printhsk;
+	unsigned long printgpi;
+	unsigned long cpuid;
+	unsigned long rombase;
+	unsigned long adbdelay;
+	unsigned long timedbra;
+};
+
+extern struct mac_booter_data 
+	mac_bi_data;
+
+#endif
 
     /*
      * Stuff for bootinfo interface versioning
@@ -129,7 +195,9 @@
 #endif /* __ASSEMBLY__ */
 
 #define AMIGA_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
-#define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 0 )
+#define ATARI_BOOTI_VERSION    MK_BI_VERSION( 2, 1 )
+#define MAC_BOOTI_VERSION      MK_BI_VERSION( 2, 0 )
+#define MVME16x_BOOTI_VERSION  MK_BI_VERSION( 2, 0 )
 
 
 #ifdef BOOTINFO_COMPAT_1_0
@@ -140,6 +208,7 @@
 
 #define COMPAT_AMIGA_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
 #define COMPAT_ATARI_BOOTI_VERSION    MK_BI_VERSION( 1, 0 )
+#define COMPAT_MAC_BOOTI_VERSION      MK_BI_VERSION( 1, 0 )
 
 #include <linux/zorro.h>
 
@@ -162,6 +231,67 @@
     unsigned long mch_cookie;
 };
 
+#ifndef __ASSEMBLY__
+
+#define MACHW_DECLARE(name)    unsigned name : 1
+#define MACHW_SET(name)                (boot_info.bi_mac.hw_present.name = 1)
+#define MACHW_PRESENT(name)    (boot_info.bi_mac.hw_present.name)
+
+struct compat_bi_Macintosh
+{
+	unsigned long videoaddr;
+	unsigned long videorow;
+	unsigned long videodepth;
+	unsigned long dimensions;
+	unsigned long args;
+	unsigned long boottime;
+	unsigned long gmtbias;
+	unsigned long bootver;
+	unsigned long videological;
+	unsigned long sccbase;
+	unsigned long id;
+	unsigned long memsize;
+	unsigned long serialmf;
+	unsigned long serialhsk;
+	unsigned long serialgpi;
+	unsigned long printmf;
+	unsigned long printhsk;
+	unsigned long printgpi;
+	unsigned long cpuid;
+	unsigned long rombase;
+	unsigned long adbdelay;
+	unsigned long timedbra;
+	struct {
+		/* video hardware */
+		/* sound hardware */
+		/* disk storage interfaces */
+		MACHW_DECLARE(MAC_SCSI);        /* Directly mapped NCR5380 */
+		MACHW_DECLARE(IDE);             /* IDE Interface */
+		/* other I/O hardware */
+		MACHW_DECLARE(SCC);             /* Serial Communications Contr. */
+		/* DMA */
+		MACHW_DECLARE(SCSI_DMA);        /* DMA for the NCR5380 */
+		/* real time clocks */
+		MACHW_DECLARE(RTC_CLK);         /* clock chip */
+		/* supporting hardware */
+		MACHW_DECLARE(VIA1);            /* Versatile Interface Ad. 1 */
+		MACHW_DECLARE(VIA2);            /* Versatile Interface Ad. 2 */
+		MACHW_DECLARE(RBV);             /* Versatile Interface Ad. 2+ */
+		/* NUBUS */
+		MACHW_DECLARE(NUBUS);           /* NUBUS */
+	} hw_present;
+};
+#else
+
+#define BI_videoaddr	BI_un
+#define BI_videorow	BI_videoaddr+4
+#define BI_videodepth	BI_videorow+4
+#define BI_dimensions	BI_videodepth+4
+#define BI_args		BI_dimensions+4
+#define BI_cpuid	BI_args+56
+
+#endif
+
 struct compat_mem_info {
     unsigned long addr;
     unsigned long size;
@@ -200,13 +330,15 @@
     unsigned long ramdisk_addr;
     char command_line[COMPAT_CL_SIZE];
     union {
-	struct compat_bi_Amiga bi_ami;
-	struct compat_bi_Atari bi_ata;
+	struct compat_bi_Amiga     bi_ami;
+	struct compat_bi_Atari     bi_ata;
+	struct compat_bi_Macintosh bi_mac;
     } bi_un;
 };
 
 #define bi_amiga	bi_un.bi_ami
 #define bi_atari	bi_un.bi_ata
+#define bi_mac		bi_un.bi_mac
 
 #endif /* BOOTINFO_COMPAT_1_0 */
 
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/bugs.h linux/include/asm-m68k/bugs.h
--- v2.1.86/linux/include/asm-m68k/bugs.h	Wed Dec 27 12:46:49 1995
+++ linux/include/asm-m68k/bugs.h	Thu Feb 12 16:30:13 1998
@@ -11,6 +11,4 @@
  *	void check_bugs(void);
  */
 
-static void check_bugs(void)
-{
-}
+extern void check_bugs(void);	/* in arch/m68k/kernel/setup.c */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h
--- v2.1.86/linux/include/asm-m68k/entry.h	Mon Jun 16 16:36:00 1997
+++ linux/include/asm-m68k/entry.h	Thu Feb 12 16:30:13 1998
@@ -40,12 +40,11 @@
 /*
  * 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_STATE	 =  0
+LTASK_FLAGS	 =  4
+LTASK_SIGPENDING =  8
+LTASK_ADDRLIMIT	 = 12
+LTASK_EXECDOMAIN = 16
 
 LTSS_KSP	= 0
 LTSS_USP	= 4
@@ -55,7 +54,7 @@
 LTSS_FPCTXT	= 24
 
 /* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY)
+#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
 	/* block out HSYNC on the atari */
 #define ALLOWINT 0xfbff
 #define	MAX_NOINT_IPL	3
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/font.h linux/include/asm-m68k/font.h
--- v2.1.86/linux/include/asm-m68k/font.h	Sun May 19 21:54:29 1996
+++ linux/include/asm-m68k/font.h	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/*
- *  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 COPYING 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 *height, 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[]);
-
-
-/* Max. length for the name of a predefined font */
-#define MAX_FONT_NAME	32
-
-#endif /* _ASM_M68K_FONT_H_ */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/hardirq.h linux/include/asm-m68k/hardirq.h
--- v2.1.86/linux/include/asm-m68k/hardirq.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-m68k/hardirq.h	Thu Feb 12 16:30:13 1998
@@ -4,7 +4,6 @@
 #include <linux/tasks.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
 
 #define hardirq_trylock(cpu)	(++local_irq_count[cpu], (cpu) == 0)
 #define hardirq_endlock(cpu)	(--local_irq_count[cpu])
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v2.1.86/linux/include/asm-m68k/ide.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/ide.h	Thu Feb 12 16:30:13 1998
@@ -33,28 +33,18 @@
 
 #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 <linux/interrupt.h>	/* intr_count */
-#include <asm/atarihw.h>
-#include <asm/atarihdreg.h>
-#include <asm/atariints.h>
-#include <asm/atari_stdma.h>
-#endif /* CONFIG_ATARI */
-
 #include <asm/setup.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
+#ifdef CONFIG_ATARI
+#include <asm/atari_stdma.h>
+#endif
+
 typedef unsigned char * ide_ioreg_t;
 
 #ifndef MAX_HWIFS
-#define MAX_HWIFS	1
+#define MAX_HWIFS	4	/* same as the other archs */
 #endif
 
 static __inline int ide_default_irq (ide_ioreg_t base)
@@ -62,68 +52,12 @@
 	return 0;
 }
 
-static __inline__ ide_ioreg_t ide_default_io_base (int index)
-{
-	if (index)
-		return NULL;
-#ifdef CONFIG_AMIGA
-	if (MACH_IS_AMIGA) {
-		if (AMIGAHW_PRESENT(A4000_IDE)) {
-			printk("Gayle IDE interface (A%d style)\n", 4000);
-			return ((ide_ioreg_t)ZTWO_VADDR(HD_BASE_A4000));
-		}
-		if (AMIGAHW_PRESENT(A1200_IDE)) {
-			printk("Gayle IDE interface (A%d style)\n", 1200);
-			return ((ide_ioreg_t)ZTWO_VADDR(HD_BASE_A1200));
-		}
-	}
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_ATARI
-	if (MACH_IS_ATARI) {
-		if (ATARIHW_PRESENT(IDE)) {
-			printk("Falcon IDE interface\n");
-			return ((ide_ioreg_t) ATA_HD_BASE);
-		}
-	}
-#endif /* CONFIG_ATARI */
-	return NULL;
-}
-
+/*
+ *  Can we do this in a generic manner??
+ */
 static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
 {
-	*p++ = base;
-#ifdef CONFIG_AMIGA
-	if (MACH_IS_AMIGA) {
-		*p++ = base + AMI_HD_ERROR;
-		*p++ = base + AMI_HD_NSECTOR;
-		*p++ = base + AMI_HD_SECTOR;
-		*p++ = base + AMI_HD_LCYL;
-		*p++ = base + AMI_HD_HCYL;
-		*p++ = base + AMI_HD_SELECT;
-		*p++ = base + AMI_HD_STATUS;
-		*p++ = base + AMI_HD_CMD;
-		if (AMIGAHW_PRESENT(A4000_IDE))
-			*p++ = (ide_ioreg_t) ZTWO_VADDR(HD_A4000_IRQ);
-		else if (AMIGAHW_PRESENT(A1200_IDE))
-			*p++ = (ide_ioreg_t) ZTWO_VADDR(HD_A1200_IRQ);
-		if (irq != NULL)
-			*irq = IRQ_AMIGA_PORTS;
-	}
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_ATARI
-	if (MACH_IS_ATARI) {
-		*p++ = base + ATA_HD_ERROR;
-		*p++ = base + ATA_HD_NSECTOR;
-		*p++ = base + ATA_HD_SECTOR;
-		*p++ = base + ATA_HD_LCYL;
-		*p++ = base + ATA_HD_HCYL;
-		*p++ = base + ATA_HD_CURRENT;
-		*p++ = base + ATA_HD_STATUS;
-		*p++ = base + ATA_HD_CMD;
-		if (irq != NULL)
-			*irq = IRQ_MFP_IDE;
-	}
-#endif /* CONFIG_ATARI */
+    printk("ide_init_hwif_ports: must not be called\n");
 }
 
 typedef union {
@@ -363,23 +297,6 @@
 
 #endif /* CONFIG_ATARI */
 
-static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port)
-{
-#ifdef CONFIG_AMIGA
-	if (MACH_IS_AMIGA) {
-		unsigned char ch;
-		ch = inb(irq_port);
-		if (!(ch & 0x80))
-			return(0);
-		if (AMIGAHW_PRESENT(A1200_IDE)) {
-			(void) inb(status_port);
-			outb(0x7c | (ch & 0x03), irq_port);
-		}
-	}
-#endif /* CONFIG_AMIGA */
-	return(1);
-}
-
 #define T_CHAR          (0x0000)        /* char:  don't touch  */
 #define T_SHORT         (0x4000)        /* short: 12 -> 21     */
 #define T_INT           (0x8000)        /* int:   1234 -> 4321 */
@@ -488,6 +405,8 @@
 	}
 #endif /* CONFIG_ATARI */
 }
+
+#define ide_ack_intr(hwif) (hwif)->ack_intr((hwif))
 
 /*
  * On the Atari, we sometimes can't enable interrupts:
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/init.h linux/include/asm-m68k/init.h
--- v2.1.86/linux/include/asm-m68k/init.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-m68k/init.h	Thu Feb 12 16:30:13 1998
@@ -1,6 +1,10 @@
 #ifndef _M68K_INIT_H
 #define _M68K_INIT_H
 
+#include <linux/config.h>
+
+#ifndef CONFIG_KGDB
+
 #define __init __attribute__ ((__section__ (".text.init")))
 #define __initdata __attribute__ ((__section__ (".data.init")))
 #define __initfunc(__arginit) \
@@ -11,4 +15,19 @@
 #define __FINIT		.previous
 #define __INITDATA	.section	".data.init",#alloc,#write
 
+#else
+
+/* gdb doesn't like it all if the code for one source file isn't together in
+ * the executable, so we must avoid the .init sections :-( */
+	
+#define __init
+#define __initdata
+#define __initfunc(__arginit) __arginit
+/* For assembly routines */
+#define __INIT
+#define __FINIT
+#define __INITDATA
+
+#endif /* CONFIG_KGDB */
+	
 #endif
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h
--- v2.1.86/linux/include/asm-m68k/io.h	Fri Nov 22 05:56:36 1996
+++ linux/include/asm-m68k/io.h	Thu Feb 12 16:30:13 1998
@@ -3,15 +3,29 @@
 
 #ifdef __KERNEL__
 
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_ATARI
+#include <asm/atarihw.h>
+
+#define SLOW_DOWN_IO	do { if (MACH_IS_ATARI) MFPDELAY(); } while (0)
+#endif
+
 /*
  * readX/writeX() are used to access memory mapped devices. On some
  * architectures the memory mapped IO stuff needs to be accessed
  * differently. On the m68k architecture, we just read/write the
  * memory location directly.
  */
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
+/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates
+ * two accesses to memory, which may be undesireable for some devices.
+ */
+#define readb(addr) \
+    ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
+#define readw(addr) \
+    ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
+#define readl(addr) \
+    ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
 
 #define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
 #define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
@@ -44,10 +58,16 @@
 }
 
 /*
- * IO bus memory addresses are 1:1 with the physical address
+ * IO bus memory addresses are 1:1 with the physical address,
+ * except on the PCI bus of the Hades.
  */
+#ifdef CONFIG_HADES
+#define virt_to_bus(a) (virt_to_phys(a) + (MACH_IS_HADES ? 0x80000000 : 0))
+#define bus_to_virt(a) (phys_to_virt((a) - (MACH_IS_HADES ? 0x80000000 : 0)))
+#else
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
+#endif
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/ioctls.h linux/include/asm-m68k/ioctls.h
--- v2.1.86/linux/include/asm-m68k/ioctls.h	Thu Dec  4 13:09:01 1997
+++ linux/include/asm-m68k/ioctls.h	Thu Feb 12 16:25:04 1998
@@ -47,6 +47,8 @@
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
 #define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX		0x5451
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/keyboard.h linux/include/asm-m68k/keyboard.h
--- v2.1.86/linux/include/asm-m68k/keyboard.h	Sat May 24 09:10:24 1997
+++ linux/include/asm-m68k/keyboard.h	Thu Feb 12 16:30:13 1998
@@ -49,8 +49,16 @@
 	mach_kbd_leds(leds);
 }
 
+#ifdef CONFIG_MAGIC_SYSRQ
+#define kbd_is_sysrq(keycode)	((keycode) == mach_sysrq_key && \
+								 (up_flag || \
+								  (shift_state & mach_sysrq_shift_mask) == \
+								  mach_sysrq_shift_state))
+#define kbd_sysrq_xlate			mach_sysrq_xlate
+#endif
+
 #define kbd_init_hw	mach_keyb_init
 
 #endif /* __KERNEL__ */
 
-#endif /* __ASMm68k_KEYBOARD_H */
+#endif /* __M68K_KEYBOARD_H */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/mac_asc.h linux/include/asm-m68k/mac_asc.h
--- v2.1.86/linux/include/asm-m68k/mac_asc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mac_asc.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,27 @@
+/*
+ *	Apple Sound Chip 
+ */
+ 
+#ifndef __ASM_MAC_ASC_H
+#define __ASM_MAC_ASC_H
+
+/*
+ *	ASC offsets and controls
+ */
+ 
+#define ASC_BUF_BASE	0x00	/* RAM buffer offset */
+#define ASC_BUF_SIZE	0x800
+
+#define ASC_CONTROL	0x800
+#define ASC_CONTROL_OFF		0x00
+#define ASC_FREQ(chan,byte)	((0x810)+((chan)<<3)+(byte))
+#define ASC_ENABLE	0x801
+#define ASC_ENABLE_SAMPLE	0x02
+#define ASC_MODE	0x802
+#define ASC_MODE_SAMPLE		0x02
+
+#define ASC_VOLUME	0x806
+#define ASC_CHAN	0x807	/* ??? */
+
+ 
+#endif
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/mac_mouse.h linux/include/asm-m68k/mac_mouse.h
--- v2.1.86/linux/include/asm-m68k/mac_mouse.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mac_mouse.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,23 @@
+#ifndef _ASM_MAC_MOUSE_H
+#define _ASM_MAC_MOUSE_H
+
+/*
+ * linux/include/asm-m68k/mac_mouse.h
+ * header file for Macintosh ADB mouse driver
+ * 27-10-97 Michael Schmitz
+ * copied from:
+ * 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 v2.1.86/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h
--- v2.1.86/linux/include/asm-m68k/machdep.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/machdep.h	Thu Feb 12 16:30:13 1998
@@ -30,13 +30,15 @@
 extern int (*mach_hwclk)(int, struct hwclk_time*);
 extern int (*mach_set_clock_mmss)(unsigned long);
 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 struct fb_info *(*mach_fb_init)(long *);
 extern long mach_max_dma_address;
-extern void (*mach_video_setup)(char *, int *);
 extern void (*mach_floppy_setup)(char *, int *);
 extern void (*mach_floppy_eject)(void);
+extern void (*mach_heartbeat) (int);
+extern int mach_sysrq_key;
+extern int mach_sysrq_shift_state;
+extern int mach_sysrq_shift_mask;
+extern char *mach_sysrq_xlate;
 
 #endif /* _M68K_MACHDEP_H */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/machw.h linux/include/asm-m68k/machw.h
--- v2.1.86/linux/include/asm-m68k/machw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/machw.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,108 @@
+/*
+** linux/machw.h -- This header defines some macros and pointers for
+**                    the various Macintosh custom hardware registers.
+**
+** Copyright 1997 by Michael Schmitz
+**
+** 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.
+**
+*/
+
+#ifndef _ASM_MACHW_H_
+#define _ASM_MACHW_H_
+
+#include <linux/types.h>
+
+/* Mac SCSI Controller 5380 */
+
+#define	MAC_5380_BAS	(0x50F10000) /* This is definitely wrong!! */
+struct MAC_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	mac_scsi       ((*(volatile struct MAC_5380 *)MAC_5380_BAS))
+
+/*
+** SCC Z8530
+*/
+ 
+#define MAC_SCC_BAS (0x50F04000)
+struct MAC_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 mac_scc ((*(volatile struct SCC*)MAC_SCC_BAS))
+
+/*
+** VIA 6522
+*/
+
+#define VIA1_BAS	(0x50F00000)
+#define VIA2_BAS	(0x50F02000)
+#define VIA2_BAS_IIci	(0x50F26000)
+struct VIA
+ {
+  u_char buf_b;
+  u_char dummy1[0x199];
+  u_char buf_a;
+  u_char dummy2[0x199];
+  u_char dir_b;
+  u_char dummy3[0x199];
+  u_char dir_a;
+  u_char dummy4[0x199];
+  u_char timer1_cl;
+  u_char dummy5[0x199];
+  u_char timer1_ch;
+  u_char dummy6[0x199];
+  u_char timer1_ll;
+  u_char dummy7[0x199];
+  u_char timer1_lh;
+  u_char dummy8[0x199];
+  u_char timer2_cl;
+  u_char dummy9[0x199];
+  u_char timer2_ch;
+  u_char dummy10[0x199];
+  u_char sr;
+  u_char dummy11[0x199];
+  u_char acr;
+  u_char dummy12[0x199];
+  u_char pcr;
+  u_char dummy13[0x199];
+  u_char int_fl;
+  u_char dummy14[0x199];
+  u_char int_en;
+  u_char dummy15[0x199];
+  u_char anr;
+  u_char dummy16[0x199];
+ };
+
+# define via_1         ((*(volatile struct VIA *)VIA1_BAS))
+# define via_2         ((*(volatile struct VIA *)VIA2_BAS))
+# define via1_regp    ((volatile unsigned char *)VIA1_BAS)
+
+# define via2_regp    ((volatile unsigned char *)VIA2_BAS)
+# define via2_ci_regp ((volatile unsigned char *)VIA2_BAS_IIci)
+# define rbv_regp     ((volatile unsigned char *)VIA2_BAS_IIci)
+ 
+#endif /* linux/machw.h */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/macintosh.h linux/include/asm-m68k/macintosh.h
--- v2.1.86/linux/include/asm-m68k/macintosh.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/macintosh.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,139 @@
+#ifndef __ASM_MACINTOSH_H
+#define __ASM_MACINTOSH_H
+
+/*
+ *	Apple Macintoshisms
+ */
+ 
+extern void mac_reset(void);
+extern void mac_init_IRQ(void);
+extern int mac_request_irq (unsigned int, void (*)(int, void *, 
+				struct pt_regs *),
+				unsigned long, const char *, void *);
+extern void mac_free_irq(unsigned int, void *);
+extern void mac_enable_irq(unsigned int);
+extern void mac_disable_irq(unsigned int);
+extern int mac_get_irq_list(char *);
+#if 0
+extern void mac_default_handler(int irq);
+#endif
+extern void mac_identify(void);
+extern void mac_report_hardware(void);
+extern void mac_debugging_penguin(int);
+extern void mac_boom(int);
+extern void mac_video_setup(char *,int *);
+
+/*
+ *	Floppy driver magic hook - probably shouldnt be here
+ */
+ 
+extern void via1_set_head(int);
+
+extern void parse_booter(char *ptr);
+extern void print_booter(char *ptr);
+
+/*
+ *	Macintosh Table
+ */
+ 
+struct mac_model *macintosh_config;
+
+
+struct mac_model
+{
+	short ident;
+	char *name;
+	char adb_type;
+	char via_type;
+	char scsi_type;
+	char ide_type;
+	char scc_type;
+	char ether_type;
+	char nubus_type;
+};
+
+#define MAC_ADB_NONE		0
+#define MAC_ADB_II		1
+#define MAC_ADB_IISI		2
+#define MAC_ADB_CUDA		3
+
+#define MAC_VIA_II		1
+#define MAC_VIA_IIci		2
+#define MAC_VIA_QUADRA		3
+
+#define MAC_SCSI_NONE		0
+#define MAC_SCSI_OLD		1
+#define MAC_SCSI_QUADRA		2
+#define MAC_SCSI_QUADRA2	3
+#define MAC_SCSI_QUADRA3	4
+
+#define MAC_IDE_NONE		0
+#define MAC_IDE_QUADRA		1
+#define MAC_IDE_PB		2
+
+#define MAC_SCC_II		1
+#define MAC_SCC_QUADRA		2
+#define MAC_SCC_QUADRA2		3
+
+#define MAC_ETHER_NONE		0	
+#define MAC_ETHER_SONIC		1
+
+#define MAC_NO_NUBUS		0
+#define MAC_NUBUS		1
+
+/*
+ *	Gestalt numbers
+ */
+ 
+#define MAC_MODEL_II		6
+#define MAC_MODEL_IIX		7
+#define MAC_MODEL_IICX		8
+#define MAC_MODEL_SE30		9
+#define MAC_MODEL_IICI		11
+#define MAC_MODEL_IIFX		13	/* And well numbered it is too */
+#define MAC_MODEL_IISI		18
+#define MAC_MODEL_Q900		20
+#define MAC_MODEL_PB170		25
+#define MAC_MODEL_Q700		22
+#define MAC_MODEL_CLII		23
+#define MAC_MODEL_PB140		25
+#define MAC_MODEL_Q950		26
+#define MAC_MODEL_LCIII		27	/* aka: P450 */
+#define MAC_MODEL_PB210		29
+#define MAC_MODEL_C650		30
+#define MAC_MODEL_PB230		32
+#define MAC_MODEL_PB180		33
+#define MAC_MODEL_PB160		34
+#define MAC_MODEL_Q800		35
+#define MAC_MODEL_Q650		36 
+#define MAC_MODEL_LCII		37	/* aka: P400/405/410/430 */
+#define MAC_MODEL_PB250		38
+#define MAC_MODEL_IIVI		44
+#define MAC_MODEL_IIVX		48
+#define MAC_MODEL_CCL		49
+#define MAC_MODEL_PB165C	50
+#define MAC_MODEL_C610		52
+#define MAC_MODEL_Q610		53
+#define MAC_MODEL_PB145		54
+#define MAC_MODEL_P520		56	/* aka: LC520 */
+#define MAC_MODEL_C660		60
+#define MAC_MODEL_P460		62	/* aka: LCIII+, P466/7 */
+#define MAC_MODEL_PB180C	71
+#define MAC_MODEL_PB520		72
+#define MAC_MODEL_PB270C	77
+#define MAC_MODEL_Q840		78
+#define MAC_MODEL_P550		80
+#define MAC_MODEL_PB165		84
+#define MAC_MODEL_PB190 	85
+#define MAC_MODEL_TV		88
+#define MAC_MODEL_P475		89	/* aka: LC475, P476 */
+#define MAC_MODEL_P575		92	/* aka: LC575/580, P577/578/508 */
+#define MAC_MODEL_Q605		94
+#define MAC_MODEL_Q630		98	/* aka: LC630, P630/631/636/640 */
+#define MAC_MODEL_PB280		102
+#define MAC_MODEL_PB280C	103
+#define MAC_MODEL_PB150		115
+
+extern struct mac_model *macintosh_config;
+ 
+#endif
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/macints.h linux/include/asm-m68k/macints.h
--- v2.1.86/linux/include/asm-m68k/macints.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/macints.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,160 @@
+/*
+** macints.h -- Macintosh Linux interrupt handling structs and prototypes
+**
+** Copyright 1997 by Michael Schmitz
+**
+** 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.
+**
+*/
+
+#ifndef _ASM_MACINTS_H_
+#define _ASM_MACINTS_H_
+
+#include <asm/irq.h>
+
+/*
+** Macintosh Interrupt sources.
+**
+** Note: these are all routed via the generic VIA interrupt routine!
+**
+*/
+
+#define SRC_VIA1		0
+#define SRC_VIA2		1
+
+#define VIA1_SOURCE_BASE	8
+#define VIA2_SOURCE_BASE	16
+#define RBF_SOURCE_BASE		24
+#define MAC_SCC_SOURCE_BASE	32
+#define NUBUS_SOURCE_BASE	40
+#define NUBUS_MAX_SOURCES	8
+
+/* FIXME: sources not contigous ... */
+#define NUM_MAC_SOURCES   (NUBUS_SOURCE_BASE+NUBUS_MAX_SOURCES-VIA1_SOURCE_BASE)
+
+#define IRQ_SRC_MASK (VIA1_SOURCE_BASE|VIA2_SOURCE_BASE|MAC_SCC_SOURCE_BASE)
+#define IRQ_IDX_MASK 7
+
+/* 
+ * quick hack to adapt old MACHSPEC-aware source
+ */
+#define	IRQ_IDX(irq)	(irq)
+
+#if 0
+/* convert vector number to int source number */
+#define IRQ_VECTOR_TO_SOURCE(v)	(v)
+
+/* convert irq_handler index to vector number */
+#define IRQ_SOURCE_TO_VECTOR(i)	(i)
+#endif
+
+/* interrupt service types */
+#define IRQ_TYPE_SLOW     0
+#define IRQ_TYPE_FAST     1
+#define IRQ_TYPE_PRIO     2
+
+#define	IRQ_SPURIOUS      (0)
+
+/* auto-vector interrupts */
+#define IRQ_AUTO_1        (1)
+#define IRQ_AUTO_2        (2)
+#define IRQ_AUTO_3        (3)
+#define IRQ_AUTO_4        (4)
+#define IRQ_AUTO_5        (5)
+#define IRQ_AUTO_6        (6)
+#define IRQ_AUTO_7        (7)
+
+/* VIA1 interrupts */
+#define IRQ_VIA1_0	  (8)	/* one second int. */
+#define IRQ_VIA1_1        (9)	/* VBlank int. */
+#define IRQ_MAC_VBL	  IRQ_VIA1_1
+#define IRQ_VIA1_2 	  (10)	/* ADB SR shifts complete */
+#define IRQ_MAC_ADB	  IRQ_VIA1_2
+#define IRQ_MAC_ADB_SR	  IRQ_VIA1_2
+#define IRQ_VIA1_3	  (11)	/* ADB SR CB2 ?? */
+#define IRQ_MAC_ADB_SD	  IRQ_VIA1_3
+#define IRQ_VIA1_4        (12)	/* ADB SR ext. clock pulse */
+#define IRQ_MAC_ADB_CL	  IRQ_VIA1_4
+#define IRQ_VIA1_5	  (13)
+#define IRQ_MAC_TIMER_2	  IRQ_VIA1_5
+#define IRQ_VIA1_6	  (14)
+#define IRQ_MAC_TIMER_1	  IRQ_VIA1_6
+#define IRQ_VIA1_7        (15)
+
+/* VIA2 interrupts */
+#define IRQ_VIA2_0	  (16)
+#define IRQ_MAC_SCSIDRQ	  IRQ_VIA2_0
+#define IRQ_VIA2_1        (17)
+#define IRQ_MAC_NUBUS	  IRQ_VIA2_1
+#define IRQ_VIA2_2 	  (18)
+#define IRQ_VIA2_3	  (19)
+#define IRQ_MAC_SCSI	  IRQ_VIA2_3
+#define IRQ_VIA2_4        (20)
+#define IRQ_VIA2_5	  (21)
+#define IRQ_VIA2_6	  (22)
+#define IRQ_VIA2_7        (23)
+
+/* RBV interrupts */
+#define IRQ_RBV_0	  (24)
+#define IRQ_RBV_1	  (25)
+#define IRQ_RBV_2 	  (26)
+#define IRQ_RBV_3	  (27)
+#define IRQ_RBV_4	  (28)
+#define IRQ_RBV_5	  (29)
+#define IRQ_RBV_6	  (30)
+#define IRQ_RBV_7	  (31)
+
+#define IRQ_SCC 	     (32)
+#define IRQ_SCCB	     (32)
+#define IRQ_SCCA	     (33)
+#if 0 /* FIXME: are there multiple interrupt conditions on the SCC ?? */
+/* SCC interrupts */
+#define IRQ_SCCB_TX	     (32)
+#define IRQ_SCCB_STAT	     (33)
+#define IRQ_SCCB_RX	     (34)
+#define IRQ_SCCB_SPCOND	     (35)
+#define IRQ_SCCA_TX	     (36)
+#define IRQ_SCCA_STAT	     (37)
+#define IRQ_SCCA_RX	     (38)
+#define IRQ_SCCA_SPCOND	     (39)
+#endif
+
+#define IRQ_NUBUS_1	     (40)
+
+#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 VIA_ENABLE	0
+#define VIA_PENDING	1
+#define VIA_SERVICE	2
+#define VIA_MASK	3
+
+/* 
+ * Utility functions for setting/clearing bits in the interrupt registers of
+ * the VIA. 
+ */
+
+void mac_enable_irq( unsigned irq );
+void mac_disable_irq( unsigned irq );
+void mac_turnon_irq( unsigned irq );
+void mac_turnoff_irq( unsigned irq );
+void mac_clear_pending_irq( unsigned irq );
+int  mac_irq_pending( unsigned irq );
+int  nubus_request_irq(int slot, void (*handler)(int,void *,struct pt_regs *));
+int  nubus_free_irq(int slot);
+
+unsigned long mac_register_nubus_int( void );
+void mac_unregister_nubus_int( unsigned long );
+
+extern void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs);
+extern void via1_irq(int irq, void *dev_id, struct pt_regs *regs);
+extern void via2_irq(int irq, void *dev_id, struct pt_regs *regs);
+extern void  rbv_irq(int irq, void *dev_id, struct pt_regs *regs);
+extern void mac_bang(int irq, void *dev_id, struct pt_regs *regs);
+		
+extern void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs);
+
+#endif /* asm/macints.h */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/mvme16xhw.h linux/include/asm-m68k/mvme16xhw.h
--- v2.1.86/linux/include/asm-m68k/mvme16xhw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mvme16xhw.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,118 @@
+#ifndef _M68K_MVME16xHW_H_
+#define _M68K_MVME16xHW_H_
+
+#include <asm/irq.h>
+
+/* Board ID data structure - pointer to this retrieved from Bug by head.S */
+
+/* Note, bytes 12 and 13 are board no in BCD (0162,0166,0167,0177,etc) */
+
+extern long mvme_bdid_ptr;
+
+typedef struct {
+	char	bdid[4];
+	u_char	rev, mth, day, yr;
+	u_short	size, reserved;
+	u_short	brdno;
+	char brdsuffix[2];
+	u_long	options;
+	u_short	clun, dlun, ctype, dnum;
+	u_long	option2;
+} t_bdid, *p_bdid;
+
+
+typedef struct {
+	u_char	ack_icr,
+		flt_icr,
+		sel_icr,
+		pe_icr,
+		bsy_icr,
+		spare1,
+		isr,
+		cr,
+		spare2,
+		spare3,
+		spare4,
+		data;
+} lpr_ctrl;
+
+#define LPR_REGS	((volatile lpr_ctrl *)0xfff42030)
+
+#define I596_BASE	0xfff46000
+
+#define SCC_A_ADDR	0xfff45005
+#define SCC_B_ADDR	0xfff45001
+
+#define IRQ_MVME162_TYPE_PRIO	0
+
+#define IRQ_MVME167_PRN		0x54
+#define IRQ_MVME16x_I596	0x57
+#define IRQ_MVME16x_SCSI	0x55
+#define IRQ_MVME16x_FLY		0x7f
+#define IRQ_MVME167_SER_ERR	0x5c
+#define IRQ_MVME167_SER_MODEM	0x5d
+#define IRQ_MVME167_SER_TX	0x5e
+#define IRQ_MVME167_SER_RX	0x5f
+#define IRQ_MVME16x_TIMER	0x59
+
+/* SCC interrupts, for MVME162 */
+#define IRQ_MVME162_SCC_BASE		0x40
+#define IRQ_MVME162_SCCB_TX		0x40
+#define IRQ_MVME162_SCCB_STAT		0x42
+#define IRQ_MVME162_SCCB_RX		0x44
+#define IRQ_MVME162_SCCB_SPCOND		0x46
+#define IRQ_MVME162_SCCA_TX		0x48
+#define IRQ_MVME162_SCCA_STAT		0x4a
+#define IRQ_MVME162_SCCA_RX		0x4c
+#define IRQ_MVME162_SCCA_SPCOND		0x4e
+
+/* MVME162 version register */
+
+#define MVME162_VERSION_REG	0xfff4202e
+
+extern unsigned short mvme16x_config;
+
+/* Lower 8 bits must match the revision register in the MC2 chip */
+
+#define MVME16x_CONFIG_SPEED_32		0x0001
+#define MVME16x_CONFIG_NO_VMECHIP2	0x0002
+#define MVME16x_CONFIG_NO_SCSICHIP	0x0004
+#define MVME16x_CONFIG_NO_ETHERNET	0x0008
+#define MVME16x_CONFIG_GOT_FPU		0x0010
+
+#define MVME16x_CONFIG_GOT_LP		0x0100
+#define MVME16x_CONFIG_GOT_CD2401	0x0200
+#define MVME16x_CONFIG_GOT_SCCA		0x0400
+#define MVME16x_CONFIG_GOT_SCCB		0x0800
+
+/* Specials for the ethernet driver */
+
+#define CA()		(((struct i596_reg *)dev->base_addr)->ca = 1)
+
+#define MPU_PORT(c,x)	\
+  ((struct i596_reg *)(dev->base_addr))->porthi = ((c) | (u32)(x)) & 0xffff; \
+  ((struct i596_reg *)(dev->base_addr))->portlo = ((c) | (u32)(x)) >> 16
+
+#define SCP_SYSBUS	0x00000054
+
+#define WSWAPrfd(x)	((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPrbd(x)	((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPiscp(x)	((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPscb(x)	((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPcmd(x)	((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPtbd(x)	((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPchar(x)	((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ */
+#define PORT_RESET	0x00	/* reset 82596 */
+#define PORT_SELFTEST	0x01	/* selftest */
+#define PORT_ALTSCP	0x02	/* alternate SCB address */
+#define PORT_ALTDUMP	0x03	/* Alternate DUMP address */
+
+#define ISCP_BUSY	0x00010000
+
+#endif /* _M68K_MVME16xHW_H_ */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.1.86/linux/include/asm-m68k/pgtable.h	Sat Aug 16 09:51:09 1997
+++ linux/include/asm-m68k/pgtable.h	Thu Feb 12 16:30:13 1998
@@ -26,7 +26,7 @@
 		asm __volatile__ ("nop\n\t"		\
 				  ".chip 68040\n\t"	\
 				  "cinva %%ic\n\t"	\
-				  ".chip 68k");		\
+				  ".chip 68k" : );	\
 	else {						\
 		unsigned long _tmp;			\
 		asm __volatile__ ("movec %%cacr,%0\n\t"	\
@@ -136,9 +136,12 @@
 }
 
 /* Push n pages at kernel virtual address and clear the icache */
-extern inline void flush_pages_to_ram (unsigned long address, int n)
+extern inline void flush_icache_range (unsigned long address,
+				       unsigned long endaddr)
 {
     if (CPU_IS_040_OR_060) {
+	short n = (endaddr - address + PAGE_SIZE - 1) / PAGE_SIZE;
+
 	while (n--) {
 	    __asm__ __volatile__ ("nop\n\t"
 				  ".chip 68040\n\t"
@@ -159,7 +162,6 @@
     }
 }
 
-#define flush_icache_range(start, end)		do { } while (0)
 
 /*
  * flush all user-space atc entries.
@@ -223,7 +225,7 @@
 extern inline void flush_tlb_kernel_page(unsigned long addr)
 {
 	if (CPU_IS_040_OR_060) {
-		unsigned long old_fs = get_fs();
+		mm_segment_t old_fs = get_fs();
 		set_fs(KERNEL_DS);
 		__asm__ __volatile__(".chip 68040\n\t"
 				     "pflush (%0)\n\t"
@@ -298,6 +300,8 @@
 #define _PAGE_RONLY	0x004
 #define _PAGE_ACCESSED	0x008
 #define _PAGE_DIRTY	0x010
+#define _PAGE_SUPER	0x080	/* 68040 supervisor only */
+#define _PAGE_FAKE_SUPER 0x200	/* fake supervisor only on 680[23]0 */
 #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 */
@@ -440,7 +444,7 @@
 { 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 int pte_present(pte_t pte)	{ return pte_val(pte) & (_PAGE_PRESENT | _PAGE_FAKE_SUPER); }
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
 
 extern inline int pmd_none2(pmd_t *pmd)		{ return !pmd_val(*pmd); }
@@ -728,12 +732,15 @@
 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().
+ * Map some physical address range into the kernel address space.
  */
 extern unsigned long kernel_map(unsigned long paddr, unsigned long size,
 				int nocacheflag, unsigned long *memavailp );
 /*
+ * Unmap a region alloced by kernel_map().
+ */
+extern void kernel_unmap( unsigned long addr );
+/*
  * Change the cache mode of some kernel address range.
  */
 extern void kernel_set_cachemode( unsigned long address, unsigned long size,
@@ -758,6 +765,8 @@
  * I don't know what is going on here, but since these were changed,
  * swapping hasn't been working on the 68040.
  */
+/* With the new handling of PAGE_NONE the old definitions definitely
+   don't work any more.  */
 
 #define SWP_TYPE(entry)  (((entry) >> 2) & 0x7f)
 #if 0
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.1.86/linux/include/asm-m68k/processor.h	Fri Jan 16 20:37:01 1998
+++ linux/include/asm-m68k/processor.h	Thu Feb 12 16:30:13 1998
@@ -48,7 +48,7 @@
 
 #define INIT_TSS  { \
 	sizeof(init_stack) + (unsigned long) init_stack, 0, \
-	PS_S, KERNEL_DS, \
+	PS_S, __KERNEL_DS, \
 	{0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \
 }
 
@@ -58,13 +58,6 @@
 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__ (".chip 68k/68881\n\t"
-			      "frestore %0@\n\t"
-			      ".chip 68k" : : "a" (&nilstate));
-
 	/* reads from user space */
 	set_fs(USER_DS);
 
@@ -74,7 +67,16 @@
 }
 
 /* Free all resources held by a thread. */
-extern void release_thread(struct task_struct *);
+static inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+static inline void exit_thread(void)
+{
+}
 
 /*
  * Return saved PC of a blocked thread.
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/ptrace.h linux/include/asm-m68k/ptrace.h
--- v2.1.86/linux/include/asm-m68k/ptrace.h	Sat May 24 09:10:24 1997
+++ linux/include/asm-m68k/ptrace.h	Thu Feb 12 16:30:13 1998
@@ -58,6 +58,12 @@
 	unsigned long  retpc;
 };
 
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+#define PTRACE_GETFPREGS          14
+#define PTRACE_SETFPREGS          15
+
 #ifdef __KERNEL__
 
 #ifndef PS_S
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/segment.h linux/include/asm-m68k/segment.h
--- v2.1.86/linux/include/asm-m68k/segment.h	Fri Nov 22 05:56:36 1996
+++ linux/include/asm-m68k/segment.h	Thu Feb 12 16:30:13 1998
@@ -4,43 +4,53 @@
 /* define constants */
 /* Address spaces (FC0-FC2) */
 #define USER_DATA     (1)
-#ifndef USER_DS
-#define USER_DS       (USER_DATA)
+#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)
+#ifndef __KERNEL_DS
+#define __KERNEL_DS   (SUPER_DATA)
 #endif
 #define SUPER_PROGRAM (6)
 #define CPU_SPACE     (7)
 
 #ifndef __ASSEMBLY__
 
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
+#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
+#define USER_DS		MAKE_MM_SEG(__USER_DS)
+#define KERNEL_DS	MAKE_MM_SEG(__KERNEL_DS)
+
 /*
  * Get/set the SFC/DFC registers for MOVES instructions
  */
 
-static inline unsigned long get_fs(void)
+static inline mm_segment_t get_fs(void)
 {
-	unsigned long _v;
-	__asm__ ("movec %/dfc,%0":"=r" (_v):);
+	mm_segment_t _v;
+	__asm__ ("movec %/dfc,%0":"=r" (_v.seg):);
 
 	return _v;
 }
 
-static inline unsigned long get_ds(void)
+static inline mm_segment_t get_ds(void)
 {
     /* return the supervisor data space code */
     return KERNEL_DS;
 }
 
-static inline void set_fs(unsigned long val)
+static inline void set_fs(mm_segment_t val)
 {
 	__asm__ __volatile__ ("movec %0,%/sfc\n\t"
 			      "movec %0,%/dfc\n\t"
-			      : /* no outputs */ : "r" (val) : "memory");
+			      : /* no outputs */ : "r" (val.seg) : "memory");
 }
+
+#define segment_eq(a,b)	((a).seg == (b).seg)
 
 #endif /* __ASSEMBLY__ */
 
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/serial.h linux/include/asm-m68k/serial.h
--- v2.1.86/linux/include/asm-m68k/serial.h	Thu Jul 31 13:09:18 1997
+++ linux/include/asm-m68k/serial.h	Thu Feb 12 16:30:13 1998
@@ -32,6 +32,8 @@
 #define SER_IOEXT	106	/* Amiga GVP IO-Extender (16c552) */
 #define SER_MFC_III	107	/* Amiga BSC Multiface Card III (MC68681) */
 #define SER_WHIPPET	108	/* Amiga Hisoft Whippet PCMCIA (16c550B) */
+#define SER_SCC_MVME	109	/* MVME162/MVME172 ports */
+#define SER_SCC_MAC	110	/* Macintosh SCC channel */
 
 struct serial_struct {
 	int	type;
@@ -99,33 +101,33 @@
  *
  */
 
-struct async_struct;
+struct m68k_async_struct;
 
 typedef struct {
-	void (*init)( struct async_struct *info );
-	void (*deinit)( struct async_struct *info, int leave_dtr );
-	void (*enab_tx_int)( struct async_struct *info, int enab_flag );
-	int  (*check_custom_divisor)( struct async_struct *info, int baud_base,
+	void (*init)( struct m68k_async_struct *info );
+	void (*deinit)( struct m68k_async_struct *info, int leave_dtr );
+	void (*enab_tx_int)( struct m68k_async_struct *info, int enab_flag );
+	int  (*check_custom_divisor)( struct m68k_async_struct *info, int baud_base,
 				     int divisor );
-	void (*change_speed)( struct async_struct *info );
-	void (*throttle)( struct async_struct *info, int status );
-	void (*set_break)( struct async_struct *info, int break_flag );
-	void (*get_serial_info)( struct async_struct *info,
+	void (*change_speed)( struct m68k_async_struct *info );
+	void (*throttle)( struct m68k_async_struct *info, int status );
+	void (*set_break)( struct m68k_async_struct *info, int break_flag );
+	void (*get_serial_info)( struct m68k_async_struct *info,
 				struct serial_struct *retinfo );
-	unsigned int (*get_modem_info)( struct async_struct *info );
-	int  (*set_modem_info)( struct async_struct *info, int new_dtr,
+	unsigned int (*get_modem_info)( struct m68k_async_struct *info );
+	int  (*set_modem_info)( struct m68k_async_struct *info, int new_dtr,
 			       int new_rts );
 	int  (*ioctl)( struct tty_struct *tty, struct file *file,
-		      struct async_struct *info, unsigned int cmd,
+		      struct m68k_async_struct *info, unsigned int cmd,
 		      unsigned long arg );
-	void (*stop_receive)( struct async_struct *info );
-	int  (*trans_empty)( struct async_struct *info );
-	int  (*check_open)( struct async_struct *info, struct tty_struct *tty,
+	void (*stop_receive)( struct m68k_async_struct *info );
+	int  (*trans_empty)( struct m68k_async_struct *info );
+	int  (*check_open)( struct m68k_async_struct *info, struct tty_struct *tty,
 			   struct file *file );
 } SERIALSWITCH;
 
 /*
- * Definitions for async_struct (and serial_struct) flags field
+ * Definitions for m68k_async_struct (and serial_struct) flags field
  */
 #define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
 				   on the callout port */
@@ -191,16 +193,18 @@
 #include <linux/termios.h>
 #include <linux/tqueue.h>
 
-/*
- * Counters of the input lines (CTS, DSR, RI, CD) interrupts
- */
-struct async_icount {
-	__u32	cts, dsr, rng, dcd, tx, rx;
-	__u32	frame, parity, overrun, brk;
-	__u32	buf_overrun;
+#include <linux/config.h>	/* for Mac SCC extensions */
+
+#ifdef CONFIG_MAC
+#define NUM_ZSREGS    16
+struct mac_zschannel {
+	volatile unsigned char *control;
+	volatile unsigned char *data;
 };
+struct m68k_async_private;
+#endif
 
-struct async_struct {
+struct m68k_async_struct {
 	int			magic;
 	int			baud_base;
 	int			port;
@@ -233,15 +237,14 @@
 	int			xmit_tail;
 	int			xmit_cnt;
 	struct tq_struct	tqueue;
-	struct tq_struct	tqueue_hangup;
 	struct termios		normal_termios;
 	struct termios		callout_termios;
 	struct wait_queue	*open_wait;
 	struct wait_queue	*close_wait;
 	struct wait_queue	*delta_msr_wait;
 	struct async_icount	icount;	/* kernel counters for the 4 input interrupts */
-	struct async_struct	*next_port; /* For the linked list */
-	struct async_struct	*prev_port;
+	struct m68k_async_struct	*next_port; /* For the linked list */
+	struct m68k_async_struct	*prev_port;
 	void			*board_base; /* board-base address for use with
 						boards carrying several UART's,
 						like some Amiga boards. */
@@ -254,8 +257,41 @@
 						interrupt, instead of checking
 						IRQ-registers on all UART's */
 	SERIALSWITCH		*sw;		/* functions to manage this port */
+#ifdef CONFIG_MAC
+	struct m68k_async_private	*private;
+#endif
 };
 
+#ifdef CONFIG_MAC
+struct m68k_async_private {
+	struct m68k_async_info	*zs_next;	/* For IRQ servicing chain */
+	struct mac_zschannel	*zs_channel;	/* Channel registers */
+	struct mac_zschannel	*zs_chan_a;	/* A side registers */
+	unsigned char		read_reg_zero;
+
+	char			soft_carrier;	/* Use soft carrier on this */
+	char			break_abort;	/* console, process brk/abrt */
+	char			kgdb_channel;	/* Kgdb running on this channel */
+	char			is_cons;	/* Is this our console. */
+	unsigned char		tx_active;	/* character being xmitted */
+	unsigned char		tx_stopped;	/* output is suspended */
+
+	/* We need to know the current clock divisor
+	 * to read the bps rate the chip has currently
+	 * loaded.
+	 */
+	unsigned char		clk_divisor;	/* May be 1, 16, 32, or 64 */
+	int			zs_baud;
+
+	/* Current write register values */
+	unsigned char		curregs[NUM_ZSREGS];
+
+	/* Values we need to set next opportunity */
+	unsigned char		pendregs[NUM_ZSREGS];
+
+	char			change_needed;
+};
+#endif
 #define SERIAL_MAGIC 0x5301
 
 /*
@@ -275,7 +311,7 @@
 /* Export to allow PCMCIA to use this - Dave Hinds */
 extern int register_serial(struct serial_struct *req);
 extern void unregister_serial(int line);
-extern struct async_struct rs_table[];
+extern struct m68k_async_struct rs_table[];
 extern task_queue tq_serial;
 
 
@@ -283,14 +319,14 @@
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
  */
-static __inline__ void rs_sched_event(struct async_struct *info, int event)
+static __inline__ void rs_sched_event(struct m68k_async_struct *info, int event)
 {
 	info->event |= 1 << event;
 	queue_task(&info->tqueue, &tq_serial);
 	mark_bh(SERIAL_BH);
 }
 
-static __inline__ void rs_receive_char( struct async_struct *info,
+static __inline__ void rs_receive_char( struct m68k_async_struct *info,
 					    int ch, int err )
 {
 	struct tty_struct *tty = info->tty;
@@ -305,10 +341,10 @@
 	*tty->flip.flag_buf_ptr++ = err;
 	*tty->flip.char_buf_ptr++ = ch;
 	info->icount.rx++;
-	queue_task(&tty->flip.tqueue, &tq_timer);
+	tty_flip_buffer_push(tty);
 }
 
-static __inline__ int rs_get_tx_char( struct async_struct *info )
+static __inline__ int rs_get_tx_char( struct m68k_async_struct *info )
 {
 	unsigned char ch;
 	
@@ -330,14 +366,14 @@
 	return( ch );
 }
 
-static __inline__ int rs_no_more_tx( struct async_struct *info )
+static __inline__ int rs_no_more_tx( struct m68k_async_struct *info )
 {
 	return( info->xmit_cnt <= 0 ||
 			info->tty->stopped ||
 			info->tty->hw_stopped );
 }
 
-static __inline__ void rs_dcd_changed( struct async_struct *info, int dcd )
+static __inline__ void rs_dcd_changed( struct m68k_async_struct *info, int dcd )
 
 {
 	/* update input line counter */
@@ -356,7 +392,8 @@
 #ifdef SERIAL_DEBUG_OPEN
 			printk("scheduling hangup...");
 #endif
-			queue_task(&info->tqueue_hangup, &tq_scheduler);
+			if (info->tty)
+				tty_hangup(info->tty);
 		}
 	}
 }
@@ -365,13 +402,13 @@
 void rs_stop( struct tty_struct *tty );
 void rs_start( struct tty_struct *tty );
 
-static __inline__ void rs_check_cts( struct async_struct *info, int cts )
+static __inline__ void rs_check_cts( struct m68k_async_struct *info, int cts )
 {
 	/* update input line counter */
 	info->icount.cts++;
 	wake_up_interruptible(&info->delta_msr_wait);
 	
-	if ((info->flags & ASYNC_CTS_FLOW) && info->tty)
+	if ((info->flags & ASYNC_CTS_FLOW) && info->tty) {
 		if (info->tty->hw_stopped) {
 			if (cts) {
 #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
@@ -388,7 +425,7 @@
 				rs_stop( info->tty );
 			}
 		}
-		
+	}
 }
 
 
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/setup.h linux/include/asm-m68k/setup.h
--- v2.1.86/linux/include/asm-m68k/setup.h	Wed Apr 23 19:01:28 1997
+++ linux/include/asm-m68k/setup.h	Thu Feb 12 16:30:13 1998
@@ -30,12 +30,14 @@
      *  Linux/m68k Architectures
      */
 
-#define MACH_AMIGA   1
-#define MACH_ATARI   2
-#define MACH_MAC     3
-#define MACH_APOLLO  4
-#define MACH_SUN3    5
-/* MVME 166/167/162/147?? */
+#define MACH_AMIGA    1
+#define MACH_ATARI    2
+#define MACH_MAC      3
+#define MACH_APOLLO   4
+#define MACH_SUN3     5
+#define MACH_MVME147  6
+#define MACH_MVME16x  7
+#define MACH_BVME6000 8
 
 #ifdef __KERNEL__
 
@@ -45,7 +47,8 @@
 
 #if !defined(CONFIG_AMIGA)
 #  define MACH_IS_AMIGA (0)
-#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
 #  define MACH_IS_AMIGA (m68k_machtype == MACH_AMIGA)
 #else
 #  define MACH_AMIGA_ONLY
@@ -55,7 +58,8 @@
 
 #if !defined(CONFIG_ATARI)
 #  define MACH_IS_ATARI (0)
-#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_APOLLO) \
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
 #  define MACH_IS_ATARI (m68k_machtype == MACH_ATARI)
 #else
 #  define MACH_ATARI_ONLY
@@ -63,18 +67,56 @@
 #  define MACH_TYPE (MACH_ATARI)
 #endif
 
-#if defined(CONFIG_MAC)
-#  error Currently no Mac support!
+#if !defined(CONFIG_MAC)
+#  define MACH_IS_MAC (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_ATARI) || defined(CONFIG_APOLLO)
+#  define MACH_IS_MAC (m68k_machtype == MACH_MAC)
+#else
+#  define CONFIG_MAC_ONLY
+#  define MACH_IS_MAC (1)
+#  define MACH_TYPE (MACH_MAC)
 #endif
 
 #if defined(CONFIG_SUN3)
 #  error Currently no Sun-3 support!
+#else
+#define MACH_IS_SUN3 (0)
+#endif
+
+#if !defined (CONFIG_APOLLO)
+#  define MACH_IS_APOLLO (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+#  define MACH_IS_APOLLO (m68k_machtype == MACH_APOLLO)
+#else
+#  define CONFIG_APOLLO_ONLY
+#  define MACH_IS_APOLLO (1)
+#  define MACH_TYPE (MACH_APOLLO)
 #endif
 
-#if defined(CONFIG_APOLLO)
-#  error Currently no Apollo support!
+#if !defined (CONFIG_MVME16x)
+#  define MACH_IS_MVME16x (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_BVME6000)
+#  define MACH_IS_MVME16x (m68k_machtype == MACH_MVME16x)
+#else
+#  define CONFIG_MVME16x_ONLY
+#  define MACH_IS_MVME16x (1)
+#  define MACH_TYPE (MACH_MVME16x)
 #endif
 
+#if !defined (CONFIG_BVME6000)
+#  define MACH_IS_BVME6000 (0)
+#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) || defined(CONFIG_ATARI) \
+	|| defined(CONFIG_APOLLO) || defined(CONFIG_MVME16x)
+#  define MACH_IS_BVME6000 (m68k_machtype == MACH_BVME6000)
+#else
+#  define CONFIG_BVME6000_ONLY
+#  define MACH_IS_BVME6000 (1)
+#  define MACH_TYPE (MACH_BVME6000)
+#endif
+
+
 #ifndef MACH_TYPE
 #  define MACH_TYPE (m68k_machtype)
 #endif
@@ -89,7 +131,7 @@
      *
      *      CPU_68020 == MMU_68851
      *      CPU_68030 == MMU_68030
-     *      CPU_68040 == FPU_68040 == MMU_68040
+     *      CPU_68040 == FPU_68040 == MMU_68040 (not strictly, think of 68LC040!)
      *      CPU_68060 == FPU_68060 == MMU_68060
      */
 
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/siginfo.h linux/include/asm-m68k/siginfo.h
--- v2.1.86/linux/include/asm-m68k/siginfo.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/siginfo.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,195 @@
+#ifndef _M68K_SIGINFO_H
+#define _M68K_SIGINFO_H
+
+#include <linux/types.h>
+
+/* This is copied from asm-alpha/siginfo.h.  */
+
+typedef union sigval {
+	int sival_int;
+	void *sival_ptr;
+} sigval_t;
+
+#define SI_MAX_SIZE	128
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct siginfo {
+	int si_signo;
+	int si_errno;
+	int si_code;
+
+	union {
+		int _pad[SI_PAD_SIZE];
+
+		/* kill() */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+		} _kill;
+
+		/* POSIX.1b timers */
+		struct {
+			unsigned int _timer1;
+			unsigned int _timer2;
+		} _timer;
+
+		/* POSIX.1b signals */
+		struct {
+			pid_t _pid;		/* sender's pid */
+			uid_t _uid;		/* sender's uid */
+			sigval_t _sigval;
+		} _rt;
+
+		/* SIGCHLD */
+		struct {
+			pid_t _pid;		/* which child */
+			int _status;		/* exit code */
+			clock_t _utime;
+			clock_t _stime;
+		} _sigchld;
+
+		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+		struct {
+			void *_addr; /* faulting insn/memory ref. */
+		} _sigfault;
+
+		/* SIGPOLL */
+		struct {
+			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */
+			int _fd;
+		} _sigpoll;
+	} _sifields;
+} siginfo_t;
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid		_sifields._kill._pid
+#define si_uid		_sifields._kill._uid
+#define si_status	_sifields._sigchld._status
+#define si_utime	_sifields._sigchld._utime
+#define si_stime	_sifields._sigchld._stime
+#define si_value	_sifields._rt._sigval
+#define si_int		_sifields._rt._sigval.sival_int
+#define si_ptr		_sifields._rt._sigval.sival_ptr
+#define si_addr		_sifields._sigfault._addr
+#define si_band		_sifields._sigpoll._band
+#define si_fd		_sifields._sigpoll._fd
+
+/*
+ * si_code values
+ * Digital reserves positive values for kernel-generated signals.
+ */
+#define SI_USER		0	/* sent by kill, sigsend, raise */
+#define SI_KERNEL	0x80	/* sent by the kernel from somewhere */
+#define SI_QUEUE	-1	/* sent by sigqueue */
+#define SI_TIMER	-2	/* sent by timer expiration */
+#define SI_MESGQ	-3	/* sent by real time mesq state change */
+#define SI_ASYNCIO	-4	/* sent by AIO completion */
+
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+
+/*
+ * SIGILL si_codes
+ */
+#define ILL_ILLOPC	1	/* illegal opcode */
+#define ILL_ILLOPN	2	/* illegal operand */
+#define ILL_ILLADR	3	/* illegal addressing mode */
+#define ILL_ILLTRP	4	/* illegal trap */
+#define ILL_PRVOPC	5	/* privileged opcode */
+#define ILL_PRVREG	6	/* privileged register */
+#define ILL_COPROC	7	/* coprocessor error */
+#define ILL_BADSTK	8	/* internal stack error */
+#define NSIGILL		8
+
+/*
+ * SIGFPE si_codes
+ */
+#define FPE_INTDIV	1	/* integer divide by zero */
+#define FPE_INTOVF	2	/* integer overflow */
+#define FPE_FLTDIV	3	/* floating point divide by zero */
+#define FPE_FLTOVF	4	/* floating point overflow */
+#define FPE_FLTUND	5	/* floating point underflow */
+#define FPE_FLTRES	6	/* floating point inexact result */
+#define FPE_FLTINV	7	/* floating point invalid operation */
+#define FPE_FLTSUB	8	/* subscript out of range */
+#define NSIGFPE		8
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_MAPERR	1	/* address not mapped to object */
+#define SEGV_ACCERR	2	/* invalid permissions for mapped object */
+#define NSIGSEGV	2
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_ADRALN	1	/* invalid address alignment */
+#define BUS_ADRERR	2	/* non-existant physical address */
+#define BUS_OBJERR	3	/* object specific hardware error */
+#define NSIGBUS		3
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_BRKPT	1	/* process breakpoint */
+#define TRAP_TRACE	2	/* process trace trap */
+#define NSIGTRAP	2
+
+/*
+ * SIGCHLD si_codes
+ */
+#define CLD_EXITED	1	/* child has exited */
+#define CLD_KILLED	2	/* child was killed */
+#define CLD_DUMPED	3	/* child terminated abnormally */
+#define CLD_TRAPPED	4	/* traced child has trapped */
+#define CLD_STOPPED	5	/* child has stopped */
+#define CLD_CONTINUED	6	/* stopped child has continued */
+#define NSIGCHLD	6
+
+/*
+ * SIGPOLL si_codes
+ */
+#define POLL_IN		1	/* data input available */
+#define POLL_OUT	2	/* output buffers available */
+#define POLL_MSG	3	/* input message available */
+#define POLL_ERR	4	/* i/o error */
+#define POLL_PRI	5	/* high priority input available */
+#define POLL_HUP	6	/* device disconnected */
+#define NSIGPOLL	6
+
+/*
+ * sigevent definitions
+ * 
+ * It seems likely that SIGEV_THREAD will have to be handled from 
+ * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the
+ * thread manager then catches and does the appropriate nonsense.
+ * However, everything is written out here so as to not get lost.
+ */
+#define SIGEV_SIGNAL	0	/* notify via signal */
+#define SIGEV_NONE	1	/* other notification: meaningless */
+#define SIGEV_THREAD	2	/* deliver via thread creation */
+
+#define SIGEV_MAX_SIZE	64
+#define SIGEV_PAD_SIZE	((SIGEV_MAX_SIZE/sizeof(int)) - 3)
+
+typedef struct sigevent {
+	sigval_t sigev_value;
+	int sigev_signo;
+	int sigev_notify;
+	union {
+		int _pad[SIGEV_PAD_SIZE];
+
+		struct {
+			void (*_function)(sigval_t);
+			void *_attribute;	/* really pthread_attr_t */
+		} _sigev_thread;
+	} _sigev_un;
+} sigevent_t;
+
+#define sigev_notify_function	_sigev_un._sigev_thread._function
+#define sigev_notify_attributes	_sigev_un._sigev_thread._attribute
+
+#endif
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/signal.h linux/include/asm-m68k/signal.h
--- v2.1.86/linux/include/asm-m68k/signal.h	Mon Apr  8 14:36:14 1996
+++ linux/include/asm-m68k/signal.h	Mon Feb 16 14:48:05 1998
@@ -1,10 +1,32 @@
 #ifndef _M68K_SIGNAL_H
 #define _M68K_SIGNAL_H
 
-typedef unsigned long sigset_t;		/* at least 32 bits */
+#include <linux/types.h>
 
-#define _NSIG             32
-#define NSIG		_NSIG
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifdef __KERNEL__
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+#define _NSIG		64
+#define _NSIG_BPW	32
+#define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
+
+typedef unsigned long old_sigset_t;		/* at least 32 bits */
+
+typedef struct {
+	unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG		32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
 
 #define SIGHUP		 1
 #define SIGINT		 2
@@ -43,22 +65,36 @@
 #define SIGPWR		30
 #define	SIGUNUSED	31
 
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN	32
+#define SIGRTMAX	(_NSIG-1)
+
 /*
- * 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_FLAGS values:
+ *
+ * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
+ *   (++roman: SA_ONSTACK is supported on m68k)
  * 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.
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
  */
-#define SA_NOCLDSTOP	1
-#define SA_SHIRQ	0x04000000
-#define SA_STACK	0x08000000
+#define SA_NOCLDSTOP	0x00000001
+#define SA_NOCLDWAIT	0x00000002 /* not supported yet */
+#define SA_SIGINFO	0x00000004
+#define SA_ONSTACK	0x08000000
 #define SA_RESTART	0x10000000
-#define SA_INTERRUPT	0x20000000
-#define SA_NOMASK	0x40000000
-#define SA_ONESHOT	0x80000000
+#define SA_NODEFER	0x40000000
+#define SA_RESETHAND	0x80000000
+
+#define SA_NOMASK	SA_NODEFER
+#define SA_ONESHOT	SA_RESETHAND
+#define SA_INTERRUPT	0x20000000 /* dummy -- ignored */
 
 #ifdef __KERNEL__
 /*
@@ -66,9 +102,11 @@
  * irq handling routines.
  *
  * SA_INTERRUPT is also used by the irq handling routines.
+ * SA_SHIRQ is for shared interrupt support on PCI and EISA.
  */
-#define SA_PROBE SA_ONESHOT
-#define SA_SAMPLE_RANDOM SA_RESTART
+#define SA_PROBE		SA_ONESHOT
+#define SA_SAMPLE_RANDOM	SA_RESTART
+#define SA_SHIRQ		0x04000000
 #endif
 
 #define SIG_BLOCK          0	/* for blocking signals */
@@ -82,15 +120,78 @@
 #define SIG_IGN	((__sighandler_t)1)	/* ignore signal */
 #define SIG_ERR	((__sighandler_t)-1)	/* error return from signal */
 
+#ifdef __KERNEL__
+struct old_sigaction {
+	__sighandler_t sa_handler;
+	old_sigset_t sa_mask;
+	unsigned long sa_flags;
+	void (*sa_restorer)(void);
+};
+
+struct k_sigaction {
+	struct sigaction sa;
+};
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
 struct sigaction {
 	__sighandler_t sa_handler;
 	sigset_t sa_mask;
 	unsigned long sa_flags;
 	void (*sa_restorer)(void);
 };
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+	void *ss_sp;
+	int ss_flags;
+	size_t ss_size;
+} stack_t;
 
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
-#endif
+
+#define __HAVE_ARCH_SIG_BITOPS
+
+extern __inline__ void sigaddset(sigset_t *set, int _sig)
+{
+	__asm__("bfset %0{%1,#1}" : "=m" (*set) : "id" ((_sig - 1) ^ 31)
+		: "cc");
+}
+
+extern __inline__ void sigdelset(sigset_t *set, int _sig)
+{
+	__asm__("bfclr %0{%1,#1}" : "=m"(*set) : "id"((_sig - 1) ^ 31)
+		: "cc");
+}
+
+extern __inline__ int __const_sigismember(sigset_t *set, int _sig)
+{
+	unsigned long sig = _sig - 1;
+	return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW));
+}
+
+extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
+{
+	char ret;
+	__asm__("bftst %1{%2,#1}\n\t sne %0"
+		: "=rm"(ret) : "m"(*set), "id"((_sig-1) ^ 31) : "cc");
+	return ret;
+}
+
+#define sigismember(set,sig)			\
+	(__builtin_constant_p(sig) ?		\
+	 __const_sigismember(set,sig) :		\
+	 __gen_sigismember(set,sig))
+
+#define sigmask(sig)	(1UL << ((sig) - 1))
+
+extern __inline__ int sigfindinword(unsigned long word)
+{
+	__asm__("bfffo %1{#0,#0},%0" : "=d"(word) : "d"(word & -word) : "cc");
+	return word ^ 31;
+}
+
+#endif /* __KERNEL__ */
 
 #endif /* _M68K_SIGNAL_H */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/socket.h linux/include/asm-m68k/socket.h
--- v2.1.86/linux/include/asm-m68k/socket.h	Thu Mar 27 14:40:07 1997
+++ linux/include/asm-m68k/socket.h	Thu Feb 12 16:30:13 1998
@@ -33,4 +33,10 @@
 #define SO_SECURITY_ENCRYPTION_TRANSPORT	23
 #define SO_SECURITY_ENCRYPTION_NETWORK		24
 
+#define SO_BINDTODEVICE	25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
+
 #endif /* _ASM_SOCKET_H */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/softirq.h linux/include/asm-m68k/softirq.h
--- v2.1.86/linux/include/asm-m68k/softirq.h	Sat May 24 09:10:24 1997
+++ linux/include/asm-m68k/softirq.h	Thu Feb 12 16:30:13 1998
@@ -44,22 +44,22 @@
 	bh_mask &= ~(1 << nr);
 }
 
-extern int __m68k_bh_counter;
+extern unsigned int local_bh_count[NR_CPUS];
 
 extern inline void start_bh_atomic(void)
 {
-	__m68k_bh_counter++;
+	local_bh_count[smp_processor_id()]++;
 	barrier();
 }
 
 extern inline void end_bh_atomic(void)
 {
 	barrier();
-	__m68k_bh_counter--;
+	local_bh_count[smp_processor_id()]--;
 }
 
 /* These are for the irq's testing the lock */
-#define softirq_trylock()  (__m68k_bh_counter ? 0 : (__m68k_bh_counter=1))
-#define softirq_endlock()  (__m68k_bh_counter = 0)
+#define softirq_trylock(cpu)  (local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1))
+#define softirq_endlock(cpu)  (local_bh_count[cpu] = 0)
 
 #endif
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v2.1.86/linux/include/asm-m68k/system.h	Sat May 24 09:10:24 1997
+++ linux/include/asm-m68k/system.h	Thu Feb 12 16:30:13 1998
@@ -8,15 +8,12 @@
 extern inline unsigned long rdusp(void) {
   	unsigned long usp;
 
-	__asm__ __volatile__("movec %/usp,%0"
-			     : "=d" (usp));
+	__asm__ __volatile__("move %/usp,%0" : "=a" (usp));
 	return usp;
 }
 
 extern inline void wrusp(unsigned long usp) {
-	__asm__ __volatile__("movec %0,%/usp"
-			     :
-			     : "d" (usp));
+	__asm__ __volatile__("move %0,%/usp" : : "a" (usp));
 }
 
 /*
@@ -63,7 +60,7 @@
 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)
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) && !defined(CONFIG_HADES)
 /* block out HSYNC on the atari */
 #define __sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory")
 #else /* portable version */
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/ucontext.h linux/include/asm-m68k/ucontext.h
--- v2.1.86/linux/include/asm-m68k/ucontext.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/ucontext.h	Thu Feb 12 16:30:13 1998
@@ -0,0 +1,32 @@
+#ifndef _M68K_UCONTEXT_H
+#define _M68K_UCONTEXT_H
+
+typedef int greg_t;
+#define NGREG 18
+typedef greg_t gregset_t[NGREG];
+
+typedef struct fpregset {
+	int f_pcr;
+	int f_psr;
+	int f_fpiaddr;
+	int f_fpregs[8][3];
+} fpregset_t;
+
+struct mcontext {
+	int version;
+	gregset_t gregs;
+	fpregset_t fpregs;
+};
+
+#define MCONTEXT_VERSION 2
+
+struct ucontext {
+	unsigned long	  uc_flags;
+	struct ucontext  *uc_link;
+	stack_t		  uc_stack;
+	struct mcontext	  uc_mcontext;
+	unsigned long	  uc_filler[80];
+	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+};
+
+#endif
diff -u --recursive --new-file v2.1.86/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- v2.1.86/linux/include/asm-m68k/unistd.h	Mon Dec  1 11:15:39 1997
+++ linux/include/asm-m68k/unistd.h	Thu Feb 12 16:30:13 1998
@@ -174,9 +174,19 @@
 #define __NR_query_module	167
 #define __NR_poll		168
 #define __NR_nfsservctl		169
-#define __NR_prctl		170
-#define __NR_pread		171
-#define __NR_pwrite		172
+#define __NR_setresgid		170
+#define __NR_getresgid		171
+#define __NR_prctl		172
+#define __NR_rt_sigreturn	173
+#define __NR_rt_sigaction	174
+#define __NR_rt_sigprocmask	175
+#define __NR_rt_sigpending	176
+#define __NR_rt_sigtimedwait	177
+#define __NR_rt_sigqueueinfo	178
+#define __NR_rt_sigsuspend	179
+#define __NR_pread		180
+#define __NR_pwrite		181
+#define __NR_lchown		182
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
@@ -319,7 +329,7 @@
 {
 	register long retval __asm__ ("d0") = __NR_clone;
 	register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
-	unsigned long fs;
+	mm_segment_t fs;
 
 	fs = get_fs();
 	set_fs (KERNEL_DS);
diff -u --recursive --new-file v2.1.86/linux/include/asm-mips/ioctls.h linux/include/asm-mips/ioctls.h
--- v2.1.86/linux/include/asm-mips/ioctls.h	Fri Jan 23 18:10:32 1998
+++ linux/include/asm-mips/ioctls.h	Thu Feb 12 16:25:04 1998
@@ -99,6 +99,8 @@
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
 #define TIOCSERCONFIG	0x5488
 #define TIOCSERGWILD	0x5489
diff -u --recursive --new-file v2.1.86/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- v2.1.86/linux/include/asm-ppc/dma.h	Mon Jan 12 15:18:13 1998
+++ linux/include/asm-ppc/dma.h	Sun Feb 15 12:10:13 1998
@@ -124,8 +124,8 @@
 #define SND_DMA2 ppc_cs4232_dma2
 #else
 #ifdef CONFIG_MSS
-#define SND_DMA1 MSS_DMA
-#define SND_DMA2 MSS_DMA2
+#define SND_DMA1 CONFIG_MSS_DMA
+#define SND_DMA2 CONFIG_MSS_DMA2
 #else
 #define SND_DMA1 -1
 #define SND_DMA2 -1
diff -u --recursive --new-file v2.1.86/linux/include/asm-ppc/ioctls.h linux/include/asm-ppc/ioctls.h
--- v2.1.86/linux/include/asm-ppc/ioctls.h	Thu Dec  4 13:09:01 1997
+++ linux/include/asm-ppc/ioctls.h	Thu Feb 12 16:25:04 1998
@@ -86,6 +86,8 @@
 #define TIOCSBRK	0x5427  /* BSD compatibility */
 #define TIOCCBRK	0x5428  /* BSD compatibility */
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454
diff -u --recursive --new-file v2.1.86/linux/include/asm-sparc/ioctls.h linux/include/asm-sparc/ioctls.h
--- v2.1.86/linux/include/asm-sparc/ioctls.h	Thu Dec  4 13:09:01 1997
+++ linux/include/asm-sparc/ioctls.h	Thu Feb 12 16:25:04 1998
@@ -75,6 +75,9 @@
 #define TIOCGPGRP	_IOR('t', 131, int)
 #define TIOCSCTTY	_IO('t', 132)
 #define TIOCGSID	_IOR('t', 133, int)
+/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
+#define TIOCGPTN	_IOR('t', 134, unsigned int) /* Get Pty Number */
+#define TIOCSPTLCK	_IOW('t', 135, int) /* Lock/unlock PTY */
 
 /* Little f */
 #define FIOCLEX		_IO('f', 1)
diff -u --recursive --new-file v2.1.86/linux/include/asm-sparc64/ioctls.h linux/include/asm-sparc64/ioctls.h
--- v2.1.86/linux/include/asm-sparc64/ioctls.h	Mon Jan 12 15:15:58 1998
+++ linux/include/asm-sparc64/ioctls.h	Thu Feb 12 16:25:04 1998
@@ -76,6 +76,9 @@
 #define TIOCGPGRP	_IOR('t', 131, int)
 #define TIOCSCTTY	_IO('t', 132)
 #define TIOCGSID	_IOR('t', 133, int)
+/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
+#define TIOCGPTN	_IOR('t', 134, unsigned int) /* Get Pty Number */
+#define TIOCSPTLCK	_IOW('t', 135, int) /* Lock/unlock PTY */
 
 /* Little f */
 #define FIOCLEX		_IO('f', 1)
diff -u --recursive --new-file v2.1.86/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.1.86/linux/include/linux/blk.h	Fri Feb  6 15:32:55 1998
+++ linux/include/linux/blk.h	Mon Feb 16 15:34:11 1998
@@ -5,6 +5,15 @@
 #include <linux/locks.h>
 #include <linux/config.h>
 
+#include <asm/spinlock.h>
+
+/*
+ * Spinlock for protecting the request queue which
+ * is mucked around with in interrupts on potentially
+ * multiple CPU's..
+ */
+extern spinlock_t current_lock;
+
 /*
  * NR_REQUEST is the number of entries in the request-queue.
  * NOTE that writes may use only the low 2/3 of these: reads
diff -u --recursive --new-file v2.1.86/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.86/linux/include/linux/pci.h	Fri Jan 30 11:28:10 1998
+++ linux/include/linux/pci.h	Thu Feb 12 15:03:09 1998
@@ -281,6 +281,10 @@
 #define PCI_DEVICE_ID_VLSI_82C597	0x0009
 #define PCI_DEVICE_ID_VLSI_82C541	0x000c
 #define PCI_DEVICE_ID_VLSI_82C543	0x000d
+#define PCI_DEVICE_ID_VLSI_82C532	0x0101
+#define PCI_DEVICE_ID_VLSI_82C534	0x0102
+#define PCI_DEVICE_ID_VLSI_82C535	0x0104
+#define PCI_DEVICE_ID_VLSI_82C147	0x0105
 #define PCI_DEVICE_ID_VLSI_VAS96011	0x0702
 
 #define PCI_VENDOR_ID_ADL		0x1005
@@ -311,6 +315,7 @@
 #define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014
 #define PCI_DEVICE_ID_DEC_21142		0x0019
 #define PCI_DEVICE_ID_DEC_21052		0x0021
+#define PCI_DEVICE_ID_DEC_21150		0x0022
 #define PCI_DEVICE_ID_DEC_21152		0x0024
 
 #define PCI_VENDOR_ID_CIRRUS		0x1013
@@ -333,7 +338,10 @@
 #define PCI_DEVICE_ID_IBM_FIRE_CORAL	0x000a
 #define PCI_DEVICE_ID_IBM_TR		0x0018
 #define PCI_DEVICE_ID_IBM_82G2675	0x001d
+#define PCI_DEVICE_ID_IBM_MCA		0x0020
 #define PCI_DEVICE_ID_IBM_82351		0x0022
+#define PCI_DEVICE_ID_IBM_SERVERAID	0x002e
+#define PCI_DEVICE_ID_IBM_MPEG2		0x007d
 
 #define PCI_VENDOR_ID_WD		0x101c
 #define PCI_DEVICE_ID_WD_7197		0x3296
@@ -343,6 +351,7 @@
 #define PCI_DEVICE_ID_AMD_SCSI		0x2020
 
 #define PCI_VENDOR_ID_TRIDENT		0x1023
+#define PCI_DEVICE_ID_TRIDENT_9397	0x9397
 #define PCI_DEVICE_ID_TRIDENT_9420	0x9420
 #define PCI_DEVICE_ID_TRIDENT_9440	0x9440
 #define PCI_DEVICE_ID_TRIDENT_9660	0x9660
@@ -356,6 +365,7 @@
 #define PCI_DEVICE_ID_MATROX_MIL	0x0519
 #define PCI_DEVICE_ID_MATROX_MYS	0x051A
 #define PCI_DEVICE_ID_MATROX_MIL_2	0x051b
+#define PCI_DEVICE_ID_MATROX_MIL_2_AGP	0x051f
 #define PCI_DEVICE_ID_MATROX_MGA_IMP	0x0d10
 
 #define PCI_VENDOR_ID_CT		0x102c
@@ -376,8 +386,8 @@
 #define PCI_VENDOR_ID_SI		0x1039
 #define PCI_DEVICE_ID_SI_6201		0x0001
 #define PCI_DEVICE_ID_SI_6202		0x0002
-#define PCI_DEVICE_ID_SI_6205		0x0205
 #define PCI_DEVICE_ID_SI_503		0x0008
+#define PCI_DEVICE_ID_SI_6205		0x0205
 #define PCI_DEVICE_ID_SI_501		0x0406
 #define PCI_DEVICE_ID_SI_496		0x0496
 #define PCI_DEVICE_ID_SI_601		0x0601
@@ -395,6 +405,9 @@
 #define PCI_VENDOR_ID_PCTECH		0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000	0x1000
 #define PCI_DEVICE_ID_PCTECH_RZ1001	0x1001
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_0	0x3000
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_1	0x3010
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
 
 #define PCI_VENDOR_ID_DPT               0x1044   
 #define PCI_DEVICE_ID_DPT               0xa400  
@@ -408,6 +421,7 @@
 #define PCI_DEVICE_ID_OPTI_82C701	0xc701
 #define PCI_DEVICE_ID_OPTI_82C814	0xc814
 #define PCI_DEVICE_ID_OPTI_82C822	0xc822
+#define PCI_DEVICE_ID_OPTI_82C825	0xd568
 
 #define PCI_VENDOR_ID_SGS		0x104a
 #define PCI_DEVICE_ID_SGS_2000		0x0008
@@ -423,6 +437,7 @@
 #define PCI_DEVICE_ID_TI_TVP4020	0x3d07
 #define PCI_DEVICE_ID_TI_PCI1130	0xac12
 #define PCI_DEVICE_ID_TI_PCI1131	0xac15
+#define PCI_DEVICE_ID_TI_PCI1250	0xac16
 
 #define PCI_VENDOR_ID_OAK		0x104e
 #define PCI_DEVICE_ID_OAK_OTI107	0x0107
@@ -516,6 +531,8 @@
 
 #define PCI_VENDOR_ID_BROOKTREE		0x109e
 #define PCI_DEVICE_ID_BROOKTREE_848	0x0350
+#define PCI_DEVICE_ID_BROOKTREE_849A	0x0351
+#define PCI_DEVICE_ID_BROOKTREE_8474	0x8474
 
 #define PCI_VENDOR_ID_SIERRA		0x10a8
 #define PCI_DEVICE_ID_SIERRA_STB	0x0000
@@ -531,6 +548,9 @@
 #define PCI_VENDOR_ID_DATABOOK		0x10b3
 #define PCI_DEVICE_ID_DATABOOK_87144	0xb106
 
+#define PCI_VENDOR_ID_PLX		0x10b5
+#define PCI_DEVICE_ID_PLX_9080		0x9080
+
 #define PCI_VENDOR_ID_3COM		0x10b7
 #define PCI_DEVICE_ID_3COM_3C590	0x5900
 #define PCI_DEVICE_ID_3COM_3C595TX	0x5950
@@ -555,9 +575,11 @@
 #define PCI_DEVICE_ID_AL_M1523		0x1523
 #define PCI_DEVICE_ID_AL_M1531		0x1531
 #define PCI_DEVICE_ID_AL_M1533		0x1533
+#define PCI_DEVICE_ID_AL_M3307		0x3307
 #define PCI_DEVICE_ID_AL_M4803		0x5215
 #define PCI_DEVICE_ID_AL_M5219		0x5219
 #define PCI_DEVICE_ID_AL_M5229		0x5229
+#define PCI_DEVICE_ID_AL_M5237		0x5237
 
 #define PCI_VENDOR_ID_MITSUBISHI	0x10ba
 
@@ -573,6 +595,7 @@
 #define PCI_VENDOR_ID_ASP		0x10cd
 #define PCI_DEVICE_ID_ASP_ABP940	0x1200
 #define PCI_DEVICE_ID_ASP_ABP940U	0x1300
+#define PCI_DEVICE_ID_ASP_ABP940UW	0x2300
 
 #define PCI_VENDOR_ID_CERN		0x10dc
 #define PCI_DEVICE_ID_CERN_SPSB_PMC	0x0001
@@ -607,6 +630,7 @@
 
 #define PCI_VENDOR_ID_INIT		0x1101
 #define PCI_DEVICE_ID_INIT_320P		0x9100
+#define PCI_DEVICE_ID_INIT_360P		0x9500
 
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_82C505	0x0505
@@ -616,11 +640,13 @@
 #define PCI_DEVICE_ID_VIA_82C585	0x0585
 #define PCI_DEVICE_ID_VIA_82C586_0	0x0586
 #define PCI_DEVICE_ID_VIA_82C595	0x0595
+#define PCI_DEVICE_ID_VIA_82C597_0	0x0597
 #define PCI_DEVICE_ID_VIA_82C926	0x0926
 #define PCI_DEVICE_ID_VIA_82C416	0x1571
 #define PCI_DEVICE_ID_VIA_82C595_97	0x1595
 #define PCI_DEVICE_ID_VIA_82C586_2	0x3038
 #define PCI_DEVICE_ID_VIA_82C586_3	0x3040
+#define PCI_DEVICE_ID_VIA_82C597_1	0x8597
 
 #define PCI_VENDOR_ID_VORTEX		0x1119
 #define PCI_DEVICE_ID_VORTEX_GDT60x0	0x0000
@@ -670,8 +696,8 @@
 #define PCI_VENDOR_ID_PHILIPS		0x1131
 #define PCI_DEVICE_ID_PHILIPS_SAA7146	0x7146
 
-#define PCI_VENDOR_ID_PLX		0x113c
-#define PCI_DEVICE_ID_PLX_9060		0x0001
+#define PCI_VENDOR_ID_CYCLONE		0x113c
+#define PCI_DEVICE_ID_CYCLONE_SDK	0x0001
 
 #define PCI_VENDOR_ID_ALLIANCE		0x1142
 #define PCI_DEVICE_ID_ALLIANCE_PROMOTIO	0x3210
@@ -683,7 +709,13 @@
 #define PCI_DEVICE_ID_VMIC_VME		0x7587
 
 #define PCI_VENDOR_ID_DIGI		0x114f
+#define PCI_DEVICE_ID_DIGI_EPC		0x0002
 #define PCI_DEVICE_ID_DIGI_RIGHTSWITCH	0x0003
+#define PCI_DEVICE_ID_DIGI_XEM		0x0004
+#define PCI_DEVICE_ID_DIGI_XR		0x0005
+#define PCI_DEVICE_ID_DIGI_CX		0x0006
+#define PCI_DEVICE_ID_DIGI_XRJ		0x0009
+#define PCI_DEVICE_ID_DIGI_EPCJ		0x000a
 
 #define PCI_VENDOR_ID_MUTECH		0x1159
 #define PCI_DEVICE_ID_MUTECH_MV1000	0x0001
@@ -694,10 +726,15 @@
 
 #define PCI_VENDOR_ID_TOSHIBA		0x1179
 #define PCI_DEVICE_ID_TOSHIBA_601	0x0601
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95	0x060a
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97	0x060f
 
 #define PCI_VENDOR_ID_RICOH		0x1180
 #define PCI_DEVICE_ID_RICOH_RL5C466	0x0466
 
+#define PCI_VENDOR_ID_ARTOP		0x1191
+#define PCI_DEVICE_ID_ARTOP_ATP850UF	0x0005
+
 #define PCI_VENDOR_ID_ZEITNET		0x1193
 #define PCI_DEVICE_ID_ZEITNET_1221	0x0001
 #define PCI_DEVICE_ID_ZEITNET_1225	0x0002
@@ -711,6 +748,9 @@
 #define PCI_VENDOR_ID_NP		0x11bc
 #define PCI_DEVICE_ID_NP_PCI_FDDI	0x0001
 
+#define PCI_VENDOR_ID_ATT		0x11c1
+#define PCI_DEVICE_ID_ATT_L56XMF	0x0440
+
 #define PCI_VENDOR_ID_SPECIALIX		0x11cb
 #define PCI_DEVICE_ID_SPECIALIX_XIO	0x4000
 #define PCI_DEVICE_ID_SPECIALIX_RIO	0x8000
@@ -742,17 +782,20 @@
 #define PCI_DEVICE_ID_CYCLOM_Z_Lo	0x0200
 #define PCI_DEVICE_ID_CYCLOM_Z_Hi	0x0201
 
+#define PCI_VENDOR_ID_O2		0x1217
+#define PCI_DEVICE_ID_O2_6832		0x6832
+
 #define PCI_VENDOR_ID_3DFX		0x121a
 #define PCI_DEVICE_ID_3DFX_VOODOO	0x0001
 
+#define PCI_VENDOR_ID_SIGMADES		0x1236
+#define PCI_DEVICE_ID_SIGMADES_6425	0x6401
+
 #define PCI_VENDOR_ID_STALLION		0x124d
 #define PCI_DEVICE_ID_STALLION_ECHPCI832 0x0000
 #define PCI_DEVICE_ID_STALLION_ECHPCI864 0x0002
 #define PCI_DEVICE_ID_STALLION_EIOPCI	0x0003
 
-#define PCI_VENDOR_ID_SIGMADES		0x1236
-#define PCI_DEVICE_ID_SIGMADES_6425	0x6401
-
 #define PCI_VENDOR_ID_OPTIBASE		0x1255
 #define PCI_DEVICE_ID_OPTIBASE_FORGE	0x1110
 #define PCI_DEVICE_ID_OPTIBASE_FUSION	0x1210
@@ -809,6 +852,7 @@
 #define PCI_DEVICE_ID_S3_ViRGE_MX	0x8c01
 #define PCI_DEVICE_ID_S3_ViRGE_MXP	0x8c02
 #define PCI_DEVICE_ID_S3_ViRGE_MXPMV	0x8c03
+#define PCI_DEVICE_ID_S3_SONICVIBES	0xca00
 
 #define PCI_VENDOR_ID_INTEL		0x8086
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
diff -u --recursive --new-file v2.1.86/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.1.86/linux/include/linux/tty.h	Fri Feb  6 15:32:54 1998
+++ linux/include/linux/tty.h	Mon Feb 16 15:33:43 1998
@@ -282,6 +282,7 @@
 #define TTY_CLOSING 7
 #define TTY_HW_COOK_OUT 14
 #define TTY_HW_COOK_IN 15
+#define TTY_PTY_LOCK 16
 
 #define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
 
diff -u --recursive --new-file v2.1.86/linux/include/linux/tty_driver.h linux/include/linux/tty_driver.h
--- v2.1.86/linux/include/linux/tty_driver.h	Fri Feb  6 15:32:54 1998
+++ linux/include/linux/tty_driver.h	Mon Feb 16 15:33:43 1998
@@ -213,6 +213,7 @@
 #define SYSTEM_TYPE_TTY			0x0001
 #define SYSTEM_TYPE_CONSOLE		0x0002
 #define SYSTEM_TYPE_SYSCONS		0x0003
+#define SYSTEM_TYPE_SYSPTMX		0x0004
 
 /* pty subtypes (magic, used by tty_io.c) */
 #define PTY_TYPE_MASTER			0x0001
diff -u --recursive --new-file v2.1.86/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h
--- v2.1.86/linux/include/linux/ufs_fs.h	Fri Feb  6 15:32:54 1998
+++ linux/include/linux/ufs_fs.h	Thu Feb 12 16:27:15 1998
@@ -9,6 +9,13 @@
  * Clean swab support by Fare <rideau@ens.fr>
  * just hope no one is using NNUUXXI on __?64 structure elements
  * 64-bit clean thanks to Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
  */
 
 #ifndef __LINUX_UFS_FS_H
@@ -49,13 +56,45 @@
 #define UFS_FSACTIVE  ((char)0x00)
 #define UFS_FSCLEAN   ((char)0x01)
 #define UFS_FSSTABLE  ((char)0x02)
+#define UFS_FSOSF1    ((char)0x03)	/* is this correct for DEC OSF/1? */
 #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
+/* From here to next blank line, s_flags for ufs_sb_info */
+/* endianness */
+#define UFS_BYTESEX		0x00000001	/* mask; leave room to 0xF */
+#define UFS_LITTLE_ENDIAN	0x00000000
+#define UFS_BIG_ENDIAN		0x00000001
+/* directory entry encoding */
+#define UFS_DE_MASK		0x00000010	/* mask for the following */
+#define UFS_DE_OLD		0x00000000
+#define UFS_DE_44BSD		0x00000010
+/* uid encoding */
+#define UFS_UID_MASK		0x00000060	/* mask for the following */
+#define UFS_UID_OLD		0x00000000
+#define UFS_UID_44BSD		0x00000020
+#define UFS_UID_EFT		0x00000040
+/* superblock state encoding */
+#define UFS_ST_MASK		0x00000700	/* mask for the following */
+#define UFS_ST_OLD		0x00000000
+#define UFS_ST_44BSD		0x00000100
+#define UFS_ST_SUN		0x00000200
+#define UFS_ST_NEXT		0x00000400
+/* filesystem flavors (combo of features) */
+#define UFS_FEATURES		0x00FFFFF0	/* room for extension */
+#define UFS_VANILLA		0x00000000
+#define UFS_OLD			0x00000000	/* 4.2BSD */
+#define UFS_44BSD		0x00000130
+#define UFS_HURD		0x00000130
+#define UFS_SUN			0x00000200
+#define UFS_NEXT		0x00000400
+/* we preserve distinction in flavor identification even without difference,
+ * because yet-to-be-supported features may introduce difference in the future
+ */
+/* last but not least, debug flags */
+#define UFS_DEBUG       	0x01000000
+#define UFS_DEBUG_INODE 	0x02000000
+#define UFS_DEBUG_NAMEI 	0x04000000
+#define UFS_DEBUG_LINKS 	0x08000000
 
 #ifdef UFS_HEAVY_DEBUG
 #  define UFS_DEBUG_INITIAL UFS_DEBUG
@@ -63,10 +102,9 @@
 #  define UFS_DEBUG_INITIAL 0
 #endif
 
-/* (!) HERE WE ASSUME EITHER BIG OR LITTLE ENDIAN UFSes */
-#define UFS_LITTLE_ENDIAN 0x00000000	/* 0x00010000 */
-#define UFS_BIG_ENDIAN    0x00010000	/* 0x00020000 */
-#define UFS_BYTESEX	  0x00010000	/* 0x00030000 */
+/* fs_inodefmt options */
+#define UFS_42INODEFMT	-1
+#define UFS_44INODEFMT	2
 
 #define UFS_ADDR_PER_BLOCK(sb)		((sb)->u.ufs_sb.s_bsize >> 2)
 #define UFS_ADDR_PER_BLOCK_BITS(sb)	((sb)->u.ufs_sb.s_bshift - 2)
@@ -87,6 +125,12 @@
 /* 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)
 
+/* current filesystem state; method depends on flags */
+#define UFS_STATE(usb) \
+		( ((flags&UFS_ST_MASK) == UFS_ST_OLD) \
+                  ? (usb)->fs_u.fs_sun.fs_state /* old normal way */ \
+                  : (usb)->fs_u.fs_44.fs_state /* 4.4BSD way */ )
+
 #define	UFS_MAXNAMLEN 255
 
 #define ufs_lbn(sb, block)		((block) >> (sb)->u.ufs_sb.s_lshift)
@@ -101,8 +145,14 @@
 struct ufs_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[UFS_MAXNAMLEN + 1];	/* file name */
+	union {
+		__u16	d_namlen;		/* actual length of d_name */
+		struct {
+			__u8	d_type;		/* file type */
+			__u8	d_namlen;	/* length of string in d_name */
+		} d_44;
+	} d_u;
+	__u8	d_name[UFS_MAXNAMLEN + 1];	/* file name */
 };
 
 #define MAXMNTLEN 512
@@ -193,10 +243,24 @@
 	__u32	fs_csp[MAXCSBUFS];	/* list of fs_cs info buffers */
 	__u32	fs_cpc;		/* cyl per cycle in postbl */
 	__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 */
-	__u32	fs_qbmask[2];		/* ~usb_bmask */
-	__u32	fs_qfmask[2];		/* ~usb_fmask */
+	union {
+		struct {
+			__s32	fs_sparecon[55];/* reserved for future constants */
+			__s32	fs_state;	/* file system state time stamp */
+			__u32	fs_qbmask[2];	/* ~usb_bmask */
+			__u32	fs_qfmask[2];	/* ~usb_fmask */
+		} fs_sun;
+		struct {
+			__s32	fs_sparecon[50];/* reserved for future constants */
+			__s32	fs_contigsumsize;/* size of cluster summary array */
+			__s32	fs_maxsymlinklen;/* max length of an internal symlink */
+			__s32	fs_inodefmt;	/* format of on-disk inodes */
+			__u64	fs_maxfilesize;	/* max representable file size */
+			__u32	fs_qbmask[2];	/* ~usb_bmask */
+			__u32	fs_qfmask[2];	/* ~usb_fmask */
+			__s32	fs_state;	/* file system state time stamp */
+		} fs_44;
+	} fs_u;
 	__s32	fs_postblformat;	/* format of positional layout tables */
 	__s32	fs_nrpos;		/* number of rotational positions */
 	__s32	fs_postbloff;		/* (__s16) rotation block list head */
@@ -211,24 +275,50 @@
 struct ufs_inode {
 	__u16	ui_mode;		/*  0x0 */
 	__u16	ui_nlink;		/*  0x2 */
-	__u16	ui_suid;		/*  0x4 */
-	__u16	ui_sgid;		/*  0x6 */
+	union {
+		struct {
+			__u16	suid;	/*  0x4 */
+			__u16	sgid;	/*  0x6 */
+		} oldids;
+		__u32	inumber;	/*  0x4 lsf: inode number */
+		__u32	author;		/*  0x4 GNU HURD: author */
+	} ui_u1;
 	__u64	ui_size;		/*  0x8 */
 	struct ufs_timeval ui_atime;	/* 0x10 access */
 	struct ufs_timeval ui_mtime;	/* 0x18 modification */
 	struct ufs_timeval ui_ctime;	/* 0x20 creation */
-	__u32	ui_db[UFS_NDADDR];	/* 0x28 data blocks */
-	__u32	ui_ib[UFS_NINDIR];	/* 0x58 indirect blocks */
+	union {
+		struct {
+			__u32	ui_db[UFS_NDADDR];/* 0x28 data blocks */
+			__u32	ui_ib[UFS_NINDIR];/* 0x58 indirect blocks */
+		} ui_addr;
+		__u8	ui_symlink[4*(UFS_NDADDR+UFS_NINDIR)];/* 0x28 fast symlink */
+	} ui_u2;
 	__u32	ui_flags;		/* 0x64 unused -- "status flags (chflags)" ??? */
 	__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 */
+	union {
+		struct {
+			__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 */
+		} ui_sun;
+		struct {
+			__u32	ui_uid;	/* 0x70 File owner */
+			__u32	ui_gid;	/* 0x74 File group */
+			__s32	ui_spare[2];/* 0x78 reserved */
+		} ui_44;
+		struct {
+			__u32	ui_uid;	/* 0x70 */
+			__u32	ui_gid;	/* 0x74 */
+			__u16	ui_modeh;/* 0x78 mode high bits */
+			__u16	ui_spare;/* 0x7A unused */
+			__u32	ui_trans;/* 0x7c filesystem translator */
+		} ui_hurd;
+	} ui_u3;
 };
-
-
+ 
 #ifdef __KERNEL__
 /*
  * Function prototypes
diff -u --recursive --new-file v2.1.86/linux/include/linux/ufs_fs_i.h linux/include/linux/ufs_fs_i.h
--- v2.1.86/linux/include/linux/ufs_fs_i.h	Thu Oct  3 00:35:01 1996
+++ linux/include/linux/ufs_fs_i.h	Fri Feb 13 11:11:29 1998
@@ -6,15 +6,18 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_fs_i.h,v 1.2 1996/05/03 04:02:25 davem Exp $
- *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
  */
 
 #ifndef _LINUX_UFS_FS_I_H
 #define _LINUX_UFS_FS_I_H
 
 struct ufs_inode_info {
-	__u32	i_data[15];
+	union {
+		__u32	i_data[15];
+		__u8	i_symlink[4*15];	/* fast symlink */
+	} i_u1;
 	__u64	i_size;
 	__u32	i_flags;
 	__u32	i_gen;
diff -u --recursive --new-file v2.1.86/linux/include/linux/ufs_fs_sb.h linux/include/linux/ufs_fs_sb.h
--- v2.1.86/linux/include/linux/ufs_fs_sb.h	Fri Feb  6 15:32:54 1998
+++ linux/include/linux/ufs_fs_sb.h	Fri Feb 13 11:11:29 1998
@@ -6,8 +6,8 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_fs_sb.h,v 1.6 1996/06/01 15:31:08 ecd Exp $
- *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
  */
 
 #ifndef __LINUX_UFS_FS_SB_H
@@ -35,6 +35,7 @@
 	__u32	s_lshift;
 	__u32	s_lmask;
 	__u32	s_fsfrag;
+	__u32	s_blockbase;	/* offset of NeXTstep superblock */
 };
 
 #endif /* __LINUX_UFS_FS_SB_H */
diff -u --recursive --new-file v2.1.86/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h
--- v2.1.86/linux/include/linux/umsdos_fs.h	Fri Feb  6 15:34:49 1998
+++ linux/include/linux/umsdos_fs.h	Mon Feb 16 15:36:43 1998
@@ -4,6 +4,8 @@
 #define UMSDOS_VERSION	0
 #define UMSDOS_RELEASE	4
 
+#define UMSDOS_ROOT_INO 1
+
 /* This is the file acting as a directory extension */
 #define UMSDOS_EMD_FILE		"--linux-.---"
 #define UMSDOS_EMD_NAMELEN	12
@@ -20,32 +22,34 @@
 #include <linux/ioctl.h>
 #endif
 
+
 struct umsdos_fake_info {
-	char fname[13];
-	int  len;
+  char fname[13];
+  int  len;
 };
 
 #define UMSDOS_MAXNAME	220
 /* This structure is 256 bytes large, depending on the name, only part */
 /* of it is written to disk */
+/* nice though it would be, I can't change this and preserve backward compatibility */
 struct umsdos_dirent {
-	unsigned char name_len;	/* if == 0, then this entry is not used */
-	unsigned char  flags;	/* UMSDOS_xxxx */
-	unsigned short nlink;	/* How many hard links point to this entry */
-	uid_t		 uid;		/* Owner user id */
-	gid_t		 gid;		/* Group id */
-	time_t		atime;		/* Access time */
-	time_t		mtime;		/* Last modification time */
-	time_t		ctime;		/* Creation time */
-	dev_t		rdev;		/* major and minor number of a device */
-							/* special file */
-	umode_t		mode;		/* Standard UNIX permissions bits + type of */
-	char	spare[12];		/* unused bytes for future extensions */
-							/* file, see linux/stat.h */
-	char name[UMSDOS_MAXNAME];	/* Not '\0' terminated */
-							/* but '\0' padded, so it will allow */
-							/* for adding news fields in this record */
-							/* by reducing the size of name[] */
+  unsigned char name_len;	/* if == 0, then this entry is not used */
+  unsigned char  flags;	/* UMSDOS_xxxx */
+  unsigned short nlink;	/* How many hard links point to this entry */
+  uid_t uid;		/* Owner user id */
+  gid_t	gid;		/* Group id */
+  time_t atime;		/* Access time */
+  time_t mtime;		/* Last modification time */
+  time_t ctime;		/* Creation time */
+  dev_t	rdev;		/* major and minor number of a device */
+  /* special file */
+  umode_t mode;		/* Standard UNIX permissions bits + type of */
+  char	spare[12];	/* unused bytes for future extensions */
+  /* file, see linux/stat.h */
+  char name[UMSDOS_MAXNAME];	/* Not '\0' terminated */
+  /* but '\0' padded, so it will allow */
+  /* for adding news fields in this record */
+  /* by reducing the size of name[] */
 };
 #define UMSDOS_HIDDEN	1	/* Never show this entry in directory search */
 #define UMSDOS_HLINK	2	/* It is a (pseudo) hard link */
@@ -58,15 +62,16 @@
 #define UMSDOS_REC_SIZE		64
 
 /* Translation between MSDOS name and UMSDOS name */
+
 struct umsdos_info{
-	int msdos_reject;	/* Tell if the file name is invalid for MSDOS */
-						/* See umsdos_parse */
-	struct umsdos_fake_info fake;
-	struct umsdos_dirent entry;
-	off_t f_pos;		/* offset of the entry in the EMD file */
-						/* or offset where the entry may be store */
-						/* if it is a new entry */
-	int recsize;		/* Record size needed to store entry */
+  int msdos_reject;	/* Tell if the file name is invalid for MSDOS */
+  /* See umsdos_parse */
+  struct umsdos_fake_info fake;  
+  struct umsdos_dirent entry;
+  off_t f_pos;		/* offset of the entry in the EMD file */
+  /* or offset where the entry may be store */
+  /* if it is a new entry */
+  int recsize;		/* Record size needed to store entry */
 };
 
 /* Definitions for ioctl (number randomly chosen) */
@@ -88,38 +93,39 @@
 #define UMSDOS_RENAME_DOS  _IO(0x04,220) /* rename a file/directory in the DOS */
 									/* directory only */
 struct umsdos_ioctl{
-	struct dirent dos_dirent;
-	struct umsdos_dirent umsdos_dirent;
-	/* The following structure is used to exchange some data */
-	/* with utilities (umsdos_progs/util/umsdosio.c). The first */
-	/* releases were using struct stat from "sys/stat.h". This was */
-	/* causing some problem for cross compilation of the kernel */
-	/* Since I am not really using the structure stat, but only some field */
-	/* of it, I have decided to replicate the structure here */
-	/* for compatibility with the binaries out there */
-	struct {
-		dev_t		st_dev;
-		unsigned short	__pad1;
-		ino_t		st_ino;
-		umode_t		st_mode;
-		nlink_t		st_nlink;
-		uid_t		st_uid;
-		gid_t		st_gid;
-		dev_t		st_rdev;
-		unsigned short	__pad2;
-		off_t		st_size;
-		unsigned long	st_blksize;
-		unsigned long	st_blocks;
-		time_t		st_atime;
-		unsigned long	__unused1;
-		time_t		st_mtime;
-		unsigned long	__unused2;
-		time_t		st_ctime;
-		unsigned long	__unused3;
-		unsigned long	__unused4;
-		unsigned long	__unused5;
-	}stat;
-	char version,release;
+  struct dirent dos_dirent;
+  struct umsdos_dirent umsdos_dirent;
+  /* The following structure is used to exchange some data */
+  /* with utilities (umsdos_progs/util/umsdosio.c). The first */
+  /* releases were using struct stat from "sys/stat.h". This was */
+  /* causing some problem for cross compilation of the kernel */
+  /* Since I am not really using the structure stat, but only some field */
+  /* of it, I have decided to replicate the structure here */
+  /* for compatibility with the binaries out there */
+  /* FIXME PTW 1998, this has probably changed */
+  struct {
+    dev_t		st_dev;
+    unsigned short	__pad1;
+    ino_t		st_ino;
+    umode_t		st_mode;
+    nlink_t		st_nlink;
+    uid_t		st_uid;
+    gid_t		st_gid;
+    dev_t		st_rdev;
+    unsigned short	__pad2;
+    off_t		st_size;
+    unsigned long	st_blksize;
+    unsigned long	st_blocks;
+    time_t		st_atime;
+    unsigned long	__unused1;
+    time_t		st_mtime;
+    unsigned long	__unused2;
+    time_t		st_ctime;
+    unsigned long	__unused3;
+    unsigned long	__unused4;
+    unsigned long	__unused5;
+  }stat;
+  char version,release;
 };
 
 /* Different macros to access struct umsdos_dirent */
@@ -135,7 +141,6 @@
 extern struct file_operations  umsdos_file_operations;
 extern struct inode_operations umsdos_file_inode_operations;
 extern struct inode_operations umsdos_file_inode_operations_no_bmap;
-extern struct inode_operations umsdos_file_inode_operations_readpage;
 extern struct inode_operations umsdos_symlink_inode_operations;
 extern int init_umsdos_fs(void);
 
diff -u --recursive --new-file v2.1.86/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- v2.1.86/linux/include/linux/umsdos_fs.p	Mon Jun 16 16:36:00 1997
+++ linux/include/linux/umsdos_fs.p	Thu Feb 12 13:36:57 1998
@@ -1,10 +1,10 @@
 /* check.c 23/01/95 03.38.30 */
 void check_page_tables (void);
 /* dir.c 22/06/95 00.22.12 */
-long UMSDOS_dir_read (struct inode *inode,
-	 struct file *filp,
+int  UMSDOS_dir_read ( struct file *filp,
 	 char *buf,
-	 unsigned long count);
+	 size_t size,
+	 loff_t *count);
 void umsdos_lookup_patch (struct inode *dir,
 	 struct inode *inode,
 	 struct umsdos_dirent *entry,
@@ -13,29 +13,35 @@
 	 struct inode *inode,
 	 struct umsdos_dirent *entry);
 int umsdos_locate_path (struct inode *inode, char *path);
-int umsdos_is_pseudodos (struct inode *dir, const char *name, int len);
-int UMSDOS_lookup (struct inode *dir,
+int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry);
+int compat_UMSDOS_lookup (struct inode *dir,
 	 const char *name,
 	 int len,
 	 struct inode **result);
+int UMSDOS_lookup(struct inode *dir,struct dentry *dentry);
+	 
 int umsdos_hlink2inode (struct inode *hlink, struct inode **result);
 /* emd.c 22/06/95 00.22.04 */
-long umsdos_file_read_kmem (struct inode *inode,
+ssize_t umsdos_file_read_kmem (struct inode *emd_dir,
 	 struct file *filp,
 	 char *buf,
-	 unsigned long count);
-long umsdos_file_write_kmem (struct inode *inode,
+	 size_t count,
+	 loff_t *offs);
+ssize_t umsdos_file_write_kmem (struct inode *emd_dir,
 	 struct file *filp,
 	 const char *buf,
-	 unsigned long count);
-long umsdos_emd_dir_write (struct inode *emd_dir,
+	 size_t count,
+	 loff_t *offs);
+ssize_t umsdos_emd_dir_write (struct inode *emd_dir,
 	 struct file *filp,
 	 char *buf,
-	 unsigned long count);
-long umsdos_emd_dir_read (struct inode *emd_dir,
+	 size_t count,
+	 loff_t *offs);
+ssize_t umsdos_emd_dir_read (struct inode *emd_dir,
 	 struct file *filp,
 	 char *buf,
-	 unsigned long count);
+	 size_t count,
+	 loff_t *loffs);
 struct inode *umsdos_emd_dir_lookup (struct inode *dir, int creat);
 int umsdos_emd_dir_readentry (struct inode *emd_dir,
 	 struct file *filp,
@@ -57,13 +63,14 @@
 /* inode.c 12/06/95 09.49.40 */
 void UMSDOS_put_inode (struct inode *inode);
 void UMSDOS_put_super (struct super_block *sb);
-void UMSDOS_statfs (struct super_block *sb,
+int UMSDOS_statfs (struct super_block *sb,
 	 struct statfs *buf,
 	 int bufsiz);
-int umsdos_real_lookup (struct inode *dir,
+int compat_umsdos_real_lookup (struct inode *dir,
 	 const char *name,
 	 int len,
 	 struct inode **result);
+int umsdos_real_lookup(struct inode *inode,struct dentry *dentry);	 
 void umsdos_setup_dir_inode (struct inode *inode);
 void umsdos_set_dirinfo (struct inode *inode,
 	 struct inode *dir,
@@ -75,7 +82,7 @@
 int umsdos_get_dirowner (struct inode *inode, struct inode **result);
 void UMSDOS_read_inode (struct inode *inode);
 void UMSDOS_write_inode (struct inode *inode);
-int UMSDOS_notify_change (struct inode *inode, struct iattr *attr);
+int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr);
 struct super_block *UMSDOS_read_super (struct super_block *s,
 	 void *data,
 	 int silent);
@@ -87,50 +94,40 @@
 /* mangle.c 25/01/95 02.25.38 */
 void umsdos_manglename (struct umsdos_info *info);
 int umsdos_evalrecsize (int len);
-int umsdos_parse (const char *fname, int len, struct umsdos_info *info);
+int umsdos_parse (const char *name,int len, struct umsdos_info *info);
 /* namei.c 25/01/95 02.25.38 */
 void umsdos_lockcreate (struct inode *dir);
 void umsdos_startlookup (struct inode *dir);
 void umsdos_unlockcreate (struct inode *dir);
 void umsdos_endlookup (struct inode *dir);
+
 int UMSDOS_symlink (struct inode *dir,
-	 const char *name,
-	 int len,
-	 const char *symname);
-int UMSDOS_link (struct inode *oldinode,
-	 struct inode *dir,
-	 const char *name,
-	 int len);
+		    struct dentry *dentry,
+		    const char *symname);
+int UMSDOS_link (struct dentry *olddentry,
+		 struct inode *dir,
+		 struct dentry *dentry);
 int UMSDOS_create (struct inode *dir,
-	 const char *name,
-	 int len,
-	 int mode,
-	 struct inode **result);
+		   struct dentry *dentry,
+		   int mode);
+
 int UMSDOS_mkdir (struct inode *dir,
-	 const char *name,
-	 int len,
-	 int mode);
+		  struct dentry *dentry,
+		  int mode);
 int UMSDOS_mknod (struct inode *dir,
-	 const char *name,
-	 int len,
-	 int mode,
-	 int rdev);
-int UMSDOS_rmdir (struct inode *dir, const char *name, int len);
-int UMSDOS_unlink (struct inode *dir, const char *name, int len);
+		  struct dentry *dentry,
+		  int mode,
+		  int rdev);
+int UMSDOS_rmdir (struct inode *dir,struct dentry *dentry);
+int UMSDOS_unlink (struct inode *dir, struct dentry *dentry);
 int UMSDOS_rename (struct inode *old_dir,
-	 const char *old_name,
-	 int old_len,
-	 struct inode *new_dir,
-	 const char *new_name,
-	 int new_len);
+		   struct dentry *old_dentry,
+		   struct inode *new_dir,
+		   struct dentry *new_dentry);
 /* rdir.c 22/03/95 03.31.42 */
 int umsdos_rlookup_x (struct inode *dir,
-	 const char *name,
-	 int len,
-	 struct inode **result,
+	 struct dentry *dentry,
 	 int nopseudo);
 int UMSDOS_rlookup (struct inode *dir,
-	 const char *name,
-	 int len,
-	 struct inode **result);
+		    struct dentry *dentry);
 /* symlink.c 23/01/95 03.38.30 */
diff -u --recursive --new-file v2.1.86/linux/kernel/time.c linux/kernel/time.c
--- v2.1.86/linux/kernel/time.c	Mon Dec  8 23:58:05 1997
+++ linux/kernel/time.c	Thu Feb 12 16:44:15 1998
@@ -216,32 +216,24 @@
 /* adjtimex mainly allows reading (and writing, if superuser) of
  * kernel time-keeping variables. used by xntpd.
  */
-asmlinkage int sys_adjtimex(struct timex *txc_p)
+int do_adjtimex(struct timex *txc)
 {
         long ltemp, mtemp, save_adjust;
-	struct timex txc;		/* Local copy of parameter */
-
-	/* Copy the user data space into the kernel copy
-	 * structure. But bear in mind that the structures
-	 * may change
-	 */
-	if(copy_from_user(&txc, txc_p, sizeof(struct timex)))
-		return -EFAULT;
 
 	/* In order to modify anything, you gotta be super-user! */
-	if (txc.modes && !suser())
+	if (txc->modes && !suser())
 		return -EPERM;
 		
 	/* Now we validate the data before disabling interrupts */
 
-	if (txc.modes != ADJ_OFFSET_SINGLESHOT && (txc.modes & ADJ_OFFSET))
+	if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
 	  /* adjustment Offset limited to +- .512 seconds */
-		if (txc.offset <= - MAXPHASE || txc.offset >= MAXPHASE )
+		if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
 			return -EINVAL;	
 
 	/* if the quartz is off by more than 10% something is VERY wrong ! */
-	if (txc.modes & ADJ_TICK)
-		if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ)
+	if (txc->modes & ADJ_TICK)
+		if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ)
 			return -EINVAL;
 
 	cli(); /* SMP: global cli() is enough protection. */
@@ -250,37 +242,37 @@
 	save_adjust = time_adjust;
 
 	/* If there are input parameters, then process them */
-	if (txc.modes)
+	if (txc->modes)
 	{
 	    if (time_state == TIME_BAD)
 		time_state = TIME_OK;
 
-	    if (txc.modes & ADJ_STATUS)
-		time_status = txc.status;
+	    if (txc->modes & ADJ_STATUS)
+		time_status = txc->status;
 
-	    if (txc.modes & ADJ_FREQUENCY)
-		time_freq = txc.freq;
+	    if (txc->modes & ADJ_FREQUENCY)
+		time_freq = txc->freq;
 
-	    if (txc.modes & ADJ_MAXERROR)
-		time_maxerror = txc.maxerror;
+	    if (txc->modes & ADJ_MAXERROR)
+		time_maxerror = txc->maxerror;
 
-	    if (txc.modes & ADJ_ESTERROR)
-		time_esterror = txc.esterror;
+	    if (txc->modes & ADJ_ESTERROR)
+		time_esterror = txc->esterror;
 
-	    if (txc.modes & ADJ_TIMECONST)
-		time_constant = txc.constant;
+	    if (txc->modes & ADJ_TIMECONST)
+		time_constant = txc->constant;
 
-	    if (txc.modes & ADJ_OFFSET)
-	      if ((txc.modes == ADJ_OFFSET_SINGLESHOT)
+	    if (txc->modes & ADJ_OFFSET)
+	      if ((txc->modes == ADJ_OFFSET_SINGLESHOT)
 		  || !(time_status & STA_PLL))
 		{
-		  time_adjust = txc.offset;
+		  time_adjust = txc->offset;
 		}
 	      else if ((time_status & STA_PLL)||(time_status & STA_PPSTIME))
 		{
 		  ltemp = (time_status & STA_PPSTIME &&
 			   time_status & STA_PPSSIGNAL) ?
-		    pps_offset : txc.offset;
+		    pps_offset : txc->offset;
 
 		  /*
 		   * Scale the phase adjustment and
@@ -335,30 +327,46 @@
 		  else if (time_freq < -time_tolerance)
 		    time_freq = -time_tolerance;
 		} /* STA_PLL || STA_PPSTIME */
-	    if (txc.modes & ADJ_TICK)
-	      tick = txc.tick;
+	    if (txc->modes & ADJ_TICK)
+	      tick = txc->tick;
 
 	}
-	txc.offset	   = save_adjust;
-	txc.freq	   = time_freq;
-	txc.maxerror	   = time_maxerror;
-	txc.esterror	   = time_esterror;
-	txc.status	   = time_status;
-	txc.constant	   = time_constant;
-	txc.precision	   = time_precision;
-	txc.tolerance	   = time_tolerance;
-	txc.time	   = xtime;
-	txc.tick	   = tick;
-	txc.ppsfreq	   = pps_freq;
-	txc.jitter	   = pps_jitter;
-	txc.shift	   = pps_shift;
-	txc.stabil	   = pps_stabil;
-	txc.jitcnt	   = pps_jitcnt;
-	txc.calcnt	   = pps_calcnt;
-	txc.errcnt	   = pps_errcnt;
-	txc.stbcnt	   = pps_stbcnt;
+	txc->offset	   = save_adjust;
+	txc->freq	   = time_freq;
+	txc->maxerror	   = time_maxerror;
+	txc->esterror	   = time_esterror;
+	txc->status	   = time_status;
+	txc->constant	   = time_constant;
+	txc->precision	   = time_precision;
+	txc->tolerance	   = time_tolerance;
+	txc->time	   = xtime;
+	txc->tick	   = tick;
+	txc->ppsfreq	   = pps_freq;
+	txc->jitter	   = pps_jitter;
+	txc->shift	   = pps_shift;
+	txc->stabil	   = pps_stabil;
+	txc->jitcnt	   = pps_jitcnt;
+	txc->calcnt	   = pps_calcnt;
+	txc->errcnt	   = pps_errcnt;
+	txc->stbcnt	   = pps_stbcnt;
 
 	sti();
+	return 0;
+}
+
+asmlinkage int sys_adjtimex(struct timex *txc_p)
+{
+	struct timex txc;		/* Local copy of parameter */
+	int ret;
+
+	/* Copy the user data space into the kernel copy
+	 * structure. But bear in mind that the structures
+	 * may change
+	 */
+	if(copy_from_user(&txc, txc_p, sizeof(struct timex)))
+		return -EFAULT;
+	if ((ret = do_adjtimex(&txc)))
+	  return ret;
 
 	return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : time_state;
 }
diff -u --recursive --new-file v2.1.86/linux/mm/memory.c linux/mm/memory.c
--- v2.1.86/linux/mm/memory.c	Mon Jan 12 14:33:20 1998
+++ linux/mm/memory.c	Mon Feb 16 13:05:07 1998
@@ -877,12 +877,14 @@
 		do_no_page(tsk, vma, address, write_access, pte, entry);
 		return;
 	}
-	set_pte(pte, pte_mkyoung(entry));
+	entry = pte_mkyoung(entry);
+	set_pte(pte, entry);
 	flush_tlb_page(vma, address);
 	if (!write_access)
 		return;
 	if (pte_write(entry)) {
-		set_pte(pte, pte_mkdirty(entry));
+		entry = pte_mkdirty(entry);
+		set_pte(pte, entry);
 		flush_tlb_page(vma, address);
 		return;
 	}
diff -u --recursive --new-file v2.1.86/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.1.86/linux/net/bridge/br.c	Thu Jan 15 14:33:06 1998
+++ linux/net/bridge/br.c	Wed Feb 11 16:16:43 1998
@@ -1386,7 +1386,7 @@
 
 static int br_drop(struct sk_buff *skb)
 {
-	kfree_skb(skb, 0);
+	kfree_skb(skb);
 	return(1);
 }
 
@@ -1396,7 +1396,7 @@
 
 static int br_dev_drop(struct sk_buff *skb)
 {
-	dev_kfree_skb(skb, 0);
+	dev_kfree_skb(skb);
 	return(1);
 }
 
diff -u --recursive --new-file v2.1.86/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.86/linux/net/core/dev.c	Thu Feb 12 20:56:14 1998
+++ linux/net/core/dev.c	Fri Feb 13 10:54:37 1998
@@ -1323,7 +1323,7 @@
 #endif
 		dev_mc_upload(dev);
 		printk(KERN_INFO "device %s %s promiscuous mode\n",
-		       dev->name, (dev->flags&IFF_PROMISC) ? "entered" : "leaved");
+		       dev->name, (dev->flags&IFF_PROMISC) ? "entered" : "left");
 	}
 }
 
diff -u --recursive --new-file v2.1.86/linux/net/core/neighbour.c linux/net/core/neighbour.c
--- v2.1.86/linux/net/core/neighbour.c	Thu Feb 12 20:56:14 1998
+++ linux/net/core/neighbour.c	Wed Feb 11 16:16:43 1998
@@ -1127,7 +1127,7 @@
 		return;
 
 	if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH) < 0) {
-		kfree_skb(skb, 0);
+		kfree_skb(skb);
 		return;
 	}
 	nlh = (struct nlmsghdr*)skb->data;
@@ -1147,7 +1147,7 @@
 		return;
 
 	if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH) < 0) {
-		kfree_skb(skb, 0);
+		kfree_skb(skb);
 		return;
 	}
 	nlh = (struct nlmsghdr*)skb->data;
diff -u --recursive --new-file v2.1.86/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.1.86/linux/net/ipv4/devinet.c	Mon Jan 12 15:28:27 1998
+++ linux/net/ipv4/devinet.c	Wed Feb 11 16:16:43 1998
@@ -784,7 +784,7 @@
 		return;
 	}
 	if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {
-		kfree_skb(skb, 0);
+		kfree_skb(skb);
 		netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL);
 		return;
 	}
diff -u --recursive --new-file v2.1.86/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
--- v2.1.86/linux/net/ipv4/fib_hash.c	Sun Nov 30 14:00:39 1997
+++ linux/net/ipv4/fib_hash.c	Wed Feb 11 16:16:43 1998
@@ -715,7 +715,7 @@
 	if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id,
 			  f->fn_type, f->fn_scope, &f->fn_key, z, f->fn_tos,
 			  FIB_INFO(f)) < 0) {
-		kfree_skb(skb, 0);
+		kfree_skb(skb);
 		return;
 	}
 	NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_ROUTE;
diff -u --recursive --new-file v2.1.86/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.1.86/linux/net/ipv6/addrconf.c	Mon Jan 12 15:28:28 1998
+++ linux/net/ipv6/addrconf.c	Wed Feb 11 16:16:43 1998
@@ -1530,7 +1530,7 @@
 		return;
 	}
 	if (inet6_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {
-		kfree_skb(skb, 0);
+		kfree_skb(skb);
 		netlink_set_err(rtnl, 0, RTMGRP_IPV6_IFADDR, EINVAL);
 		return;
 	}
diff -u --recursive --new-file v2.1.86/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.1.86/linux/net/ipv6/route.c	Thu Feb 12 20:56:15 1998
+++ linux/net/ipv6/route.c	Wed Feb 11 16:16:43 1998
@@ -1749,7 +1749,7 @@
 		return;
 	}
 	if (rt6_fill_node(skb, rt, event, 0, 0) < 0) {
-		kfree_skb(skb, 0);
+		kfree_skb(skb);
 		netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
 		return;
 	}
diff -u --recursive --new-file v2.1.86/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- v2.1.86/linux/net/netlink/af_netlink.c	Mon Jan 12 15:28:28 1998
+++ linux/net/netlink/af_netlink.c	Wed Feb 11 16:16:43 1998
@@ -370,7 +370,7 @@
 			if (nonblock) {
 				sti();
 				netlink_unlock(sk);
-				kfree_skb(skb, 0);
+				kfree_skb(skb);
 				return -EAGAIN;
 			}
 			interruptible_sleep_on(sk->sleep);
@@ -378,7 +378,7 @@
 			sti();
 
 			if (signal_pending(current)) {
-				kfree_skb(skb, 0);
+				kfree_skb(skb);
 				return -ERESTARTSYS;
 			}
 			goto retry;
@@ -392,7 +392,7 @@
 		netlink_unlock(sk);
 		return len;
 	}
-	kfree_skb(skb, 0);
+	kfree_skb(skb);
 	return -ECONNREFUSED;
 }
 
@@ -466,8 +466,8 @@
 	netlink_unlock_table(protocol, allocation == GFP_KERNEL);
 
 	if (skb2)
-		kfree_skb(skb2, 0);
-	kfree_skb(skb, 0);
+		kfree_skb(skb2);
+	kfree_skb(skb);
 }
 
 void netlink_set_err(struct sock *ssk, pid_t pid, unsigned group, int code)
@@ -630,7 +630,7 @@
 static void netlink_destroy_callback(struct netlink_callback *cb)
 {
 	if (cb->skb)
-		kfree_skb(cb->skb, 0);
+		kfree_skb(cb->skb);
 	kfree(cb);
 }
 
diff -u --recursive --new-file v2.1.86/linux/scripts/Configure linux/scripts/Configure
--- v2.1.86/linux/scripts/Configure	Mon Jun 16 16:36:02 1997
+++ linux/scripts/Configure	Thu Feb 12 16:20:10 1998
@@ -12,10 +12,10 @@
 #
 #              ***** IMPORTANT COMPATIBILITY NOTE ****
 # If configuration changes are made which might adversely effect 
-# Menuconfig or xconfig, please notify the respective authors so that 
+# Menuconfig or xconfig, please notify the respective maintainers so that 
 # those utilities can be updated in parallel.
 #
-# Menuconfig:  <roadcapw@cfw.com>
+# Menuconfig:  <mec@shout.net>
 # xconfig:     <apenwarr@foxnet.net>  <eric@aib.com>
 #              ****************************************
 #
diff -u --recursive --new-file v2.1.86/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.1.86/linux/scripts/Menuconfig	Fri Jan 23 18:10:32 1998
+++ linux/scripts/Menuconfig	Thu Feb 12 16:20:10 1998
@@ -19,7 +19,8 @@
 # Portions of this script were borrowed from the original Configure
 # script.
 #
-# Please send comments / questions / bug fixes to roadcapw@cfw.com
+# William Roadcap was the original author of Menuconfig.
+# Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
 #
 # 070497 Bernhard Kaindl (bkaindl@netway.at) - get default values for
 # new bool, tristate and dep_tristate parameters from the defconfig file.
@@ -726,9 +727,8 @@
 Menuconfig has encountered a possible error in one of the kernel's
 configuration files and is unable to continue.
 
-Please report this to the author <roadcapw@cfw.com>.  You may also
-send a problem report to linux-kernel@vger.rutgers.edu or post a
-message to the linux.dev.kernel news group.
+Please report this to the maintainer <mec@shout.net>.  You may also
+send a problem report to <linux-kernel@vger.rutgers.edu>.
 
 Please indicate the kernel version you are trying to configure and
 which menu you were trying to enter when this error occurred.
@@ -788,8 +788,8 @@
 "make clean all" command.
 
 If you have verified that your ncurses install is correct, you may email
-the author <roadcapw@cfw.com> or post a message on the linux.dev.kernel
-news group for additional assistance. 
+the maintainer <mec@shout.net> or post a message to
+<linux-kernel@vger.rutgers.edu> for additional assistance. 
 
 EOM
 			cleanup
diff -u --recursive --new-file v2.1.86/linux/scripts/README.Menuconfig linux/scripts/README.Menuconfig
--- v2.1.86/linux/scripts/README.Menuconfig	Thu Apr 18 04:38:54 1996
+++ linux/scripts/README.Menuconfig	Thu Feb 12 16:20:10 1998
@@ -188,7 +188,7 @@
 intact.  Please DO NOT contact Savio with questions about lxdialog.
 He will not be able to assist.
 
-Please feel free to send any questions, comments or suggestions to
-William Roadcap <roadcapw@cfw.com>.
+William Roadcap was the original author of Menuconfig.
+Michael Elizabeth Chastain <mec@shout.net> is the current maintainer.
 
 <END OF FILE>
