diff -u --recursive --new-file v2.1.112/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.112/linux/Documentation/Configure.help	Tue Jul 28 14:21:07 1998
+++ linux/Documentation/Configure.help	Thu Jul 30 20:06:52 1998
@@ -417,10 +417,8 @@
 CONFIG_BLK_DEV_IDEDMA
   If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
   is capable of bus-master DMA operation (most Pentium PCI systems),
-  you will want to say Y here to reduce CPU overhead.  With this
-  option, Linux will automatically enable DMA transfers in most cases,
-  noting this with "DMA" appended to the drive identification info.
-  You can also use the "hdparm" utility to enable DMA for drives which
+  you will want to say Y here to reduce CPU overhead.
+  You can use the "hdparm" utility to enable DMA for drives which
   were not enabled automatically.  You can get the latest version of
   the hdparm utility via anonymous FTP from
   ftp://sunsite.unc.edu/pub/Linux/system/hardware/. 
@@ -430,6 +428,18 @@
 
   It is safe to say Y to this question.
 
+Use DMA by default when available
+CONFIG_IDEDMA_AUTO
+  Prior to kernel version 2.1.112, Linux used to automatically use
+  DMA for IDE drives and chipsets which support it.  Due to concerns
+  about a couple of cases where buggy hardware may have caused damage,
+  the default is now to NOT use DMA automatically.  To revert to the
+  previous behaviour, say Y to this question.
+  If you suspect your hardware is at all flakey, say N here.
+  Do NOT email the IDE kernel people regarding this issue!
+
+  It is nearly always safe to say Y to this question.
+
 Other IDE chipset support
 CONFIG_IDE_CHIPSETS
   Say Y here if you want to include enhanced support for various IDE
@@ -8662,6 +8672,11 @@
   this kernel on an Atari, say Y here and browse the material
   available in Documentation/m68k; otherwise say N.
 
+Hades support
+CONFIG_HADES
+  This option enables support for the Hades Atari clone. If you plan to
+  use this kernel on a Hades, say Y here; otherwise say N.
+
 Macintosh support
 CONFIG_MAC
   This option enables support for the Apple Macintosh series of
@@ -8801,6 +8816,18 @@
   compile it as a module, say M here and read
   Documentation/modules.txt.
 
+Atari ST-RAM swap support
+CONFIG_STRAM_SWAP
+  This enables support for using (parts of) ST-RAM as swap space,
+  instead of as normal system memory. This can first enhance system
+  performace if you have lots of alternate RAM (compared to the size
+  of ST-RAM), because executable code always will reside in faster
+  memory. ST-RAM will remain as ultra-fast swap space. On the other
+  hand, it allows much improved dynamic allocations of ST-RAM buffers
+  for device driver modules (e.g. floppy, ACSI, SLM printer, DMA
+  sound). The probability that such allocations at module load time
+  fail is drastically reduced.
+
 Atari ACSI support
 CONFIG_ATARI_ACSI
   This enables support for the Atari ACSI interface. The driver
@@ -8912,6 +8939,14 @@
   accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to
   use a Toshiba CD-ROM drive; otherwise, the option is not needed and
   would impact performance a bit, so say N.
+
+Hades SCSI DMA emulator (EXPERIMENTAL)
+CONFIG_TT_DMA_EMUL
+  This option enables code which emulates the TT SCSI DMA chip on the
+  Hades. This increases the SCSI transfer rates at least ten times
+  compared to PIO transfers. Note that this code is experimental and
+  has only been tested on a Hades with a 68060 processor. Before you
+  use this, make backups of your entire hard disk.
 
 Ariadne support
 CONFIG_ARIADNE
diff -u --recursive --new-file v2.1.112/linux/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd
--- v2.1.112/linux/Documentation/cdrom/ide-cd	Sat May  2 14:19:50 1998
+++ linux/Documentation/cdrom/ide-cd	Wed Jul 29 12:37:05 1998
@@ -6,11 +6,11 @@
 ---------------
 
 The ide-cd driver should work with all ATAPI ver 1.2 to ATAPI 2.6 compliant 
-cdrom drives which attach to an IDE interface.  Note that some cdrom vendors
+CDROM drives which attach to an IDE interface.  Note that some CDROM vendors
 (including Mitsumi, Sony, Creative, Aztech, and Goldstar) have made
 both ATAPI-compliant drives and drives which use a proprietary
 interface.  If your drive uses one of those proprietary interfaces,
-this driver will not work with it (but one of the other cdrom drivers
+this driver will not work with it (but one of the other CDROM drivers
 probably will).  This driver will not work with `ATAPI' drives which
 attach to the parallel port.  In addition, there is at least one drive
 (CyCDROM CR520ie) which attaches to the IDE port but is not ATAPI;
@@ -19,9 +19,9 @@
 
 This driver provides the following features:
 
- - Reading from data tracks, and mounting iso9660 filesystems.
+ - Reading from data tracks, and mounting ISO 9660 filesystems.
 
- - Playing audio tracks.  Most of the cdrom player programs floating
+ - Playing audio tracks.  Most of the CDROM player programs floating
    around should work; I usually use Workman.
 
  - Multisession support.
@@ -30,7 +30,7 @@
    from audio tracks.  The program cdda2wav can be used for this.
    Note, however, that only some drives actually support this.
 
- - There is now support for cdrom changers which comply with the 
+ - There is now support for CDROM changers which comply with the 
    ATAPI 2.6 draft standard (such as the NEC CDR-251).  This additional
    functionality includes a function call to query which slot is the
    currently selected slot, a function call to query which slots contain
@@ -67,15 +67,15 @@
 
 2. You should also ensure that the iso9660 filesystem is either
    compiled into the kernel or available as a loadable module.  You
-   can see if a filesystem is known to the kernel by cat'ing the file
+   can see if a filesystem is known to the kernel by catting
    /proc/filesystems.
 
-3. The cdrom drive should be connected to the host on an IDE
+3. The CDROM drive should be connected to the host on an IDE
    interface.  Each interface on a system is defined by an I/O port
    address and an IRQ number, the standard assignments being
    0x170 and 14 for the primary interface and 0x1f0 and 15 for the
    secondary interface.  Each interface can control up to two devices,
-   where each device can be a hard drive, a cdrom drive, a floppy drive, 
+   where each device can be a hard drive, a CDROM drive, a floppy drive, 
    or a tape drive.  The two devices on an interface are called `master'
    and `slave'; this is usually selectable via a jumper on the drive.
 
@@ -85,10 +85,10 @@
    `hdc' and `hdd'.  (Interfaces at other locations get other letters
    in the third position; see Documentation/ide.txt.)
 
-   If you want your cdrom drive to be found automatically by the
+   If you want your CDROM drive to be found automatically by the
    driver, you should make sure your IDE interface uses either the
    primary or secondary addresses mentioned above.  In addition, if
-   the cdrom drive is the only device on the IDE interface, it should
+   the CDROM drive is the only device on the IDE interface, it should
    be jumpered as `master'.  (If for some reason you cannot configure
    your system in this manner, you can probably still use the driver.
    You may have to pass extra configuration information to the kernel
@@ -117,33 +117,33 @@
 3. Basic usage
 --------------
 
-An iso9660 format cdrom can be mounted by putting the disc in the
-drive and typing (as root)
+An ISO 9660 CDROM can be mounted by putting the disc in the drive and 
+typing (as root)
 
   mount -t iso9660 /dev/cdrom /mnt/cdrom
 
 where it is assumed that /dev/cdrom is a link pointing to the actual
 device (as described in step 5 of the last section) and /mnt/cdrom is
 an empty directory.  You should now be able to see the contents of the
-cdrom under the /mnt/cdrom directory.  If you want to eject the cdrom,
+CDROM under the /mnt/cdrom directory.  If you want to eject the CDROM,
 you must first dismount it with a command like
 
   umount /mnt/cdrom
 
-Note that audio cds cannot be mounted.
+Note that audio CDs cannot be mounted.
 
-Some distributions set up /etc/fstab to always try to mount a cdrom
-filesystem on bootup.  It is not required to mount the cdrom in this
-manner, though, and it may be a nuisance if you change cdroms often.
+Some distributions set up /etc/fstab to always try to mount a CDROM
+filesystem on bootup.  It is not required to mount the CDROM in this
+manner, though, and it may be a nuisance if you change CDROMs often.
 You should feel free to remove the cdrom line from /etc/fstab and
-mount cdroms manually if that suits you better.
+mount CDROMs manually if that suits you better.
 
 Multisession and photocd discs should work with no special handling.
 The hpcdtoppm package (ftp.gwdg.de:/pub/linux/hpcdtoppm/) may be
 useful for reading photocds.
 
-To play an audio cd, you should first unmount and remove any data
-cdrom.  Any of the cdrom player programs should then work (workman,
+To play an audio CD, you should first unmount and remove any data
+CDROM.  Any of the CDROM player programs should then work (workman,
 workbone, cdplayer, etc.).  Lacking anything else, you could use the
 cdtester program in Documentation/cdrom/sbpcd.
 
@@ -155,7 +155,7 @@
 For supported changers, you can use the `cdchange' program (appended to
 the end of this file) to switch between changer slots.  Note that the
 drive should be unmounted before attempting this.  The program takes
-two arguments: the cdrom device, and the slot number to which you wish
+two arguments:  the CDROM device, and the slot number to which you wish
 to change.  If the slot number is -1, the drive is unloaded.
 
 
@@ -263,7 +263,7 @@
     means that the system did not see an interrupt from the drive when
     it was expecting one (on any feasible IRQ).  If <n> is negative,
     that means the system saw interrupts on multiple IRQ lines, when
-    it was expecting to receive just one from the cdrom drive.
+    it was expecting to receive just one from the CDROM drive.
 
   - Double-check your hardware configuration to make sure that the IRQ
     number of your IDE interface matches what the driver expects.
@@ -275,23 +275,23 @@
     had one report of a system which was shipped with IRQ 15 disabled
     by default.
 
-  - Note that many MS-DOS cdrom drivers will still function even if
+  - Note that many MS-DOS CDROM drivers will still function even if
     there are hardware problems with the interrupt setup; they
     apparently don't use interrupts.
 
   - If you own a Pioneer DR-A24X, you _will_ get nasty error messages 
     on boot such as "irq timeout: status=0x50 { DriveReady SeekComplete }"
-    The Pioneer DR-A24X cdrom drives are fairly popular these days.
+    The Pioneer DR-A24X CDROM drives are fairly popular these days.
     Unfortunately, these drives seem to become very confused when we perform
     the standard Linux ATA disk drive probe. If you own one of these drives,
-    you can bypass the ATA probing which confuses these cdrom drives, by 
+    you can bypass the ATA probing which confuses these CDROM drives, by 
     adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and runing 
     lilo (again where X is the drive letter corresponding to where your drive 
     is installed.)
     
 c. System hangups.
 
-  - If the system locks up when you try to access the cdrom, the most
+  - If the system locks up when you try to access the CDROM, the most
     likely cause is that you have a buggy IDE adapter which doesn't
     properly handle simultaneous transactions on multiple interfaces.
     The most notorious of these is the CMD640B chip.  This problem can
@@ -301,27 +301,27 @@
     foolproof.  See Documentation/ide.txt for more information
     about the `serialize' option and the CMD640B.
 
-  - Note that many MS-DOS cdrom drivers will work with such buggy
-    hardware, apparently because they never attempt to overlap cdrom
+  - Note that many MS-DOS CDROM drivers will work with such buggy
+    hardware, apparently because they never attempt to overlap CDROM
     operations with other disk activity.
 
 
-d. Can't mount a cdrom.
+d. Can't mount a CDROM.
 
   - If you get errors from mount, it may help to check `dmesg' to see
     if there are any more specific errors from the driver or from the
     filesystem.
 
-  - Make sure there's a cdrom loaded in the drive, and that's it's an
-    iso9660 format disc.  You can't mount an audio cd.
+  - Make sure there's a CDROM loaded in the drive, and that's it's an
+    ISO 9660 disc.  You can't mount an audio CD.
 
-  - With the cdrom in the drive and unmounted, try something like
+  - With the CDROM in the drive and unmounted, try something like
 
       cat /dev/cdrom | od | more
 
     If you see a dump, then the drive and driver are probably working
-    ok, and the problem is at the filesystem level (i.e., the cdrom is
-    not iso9660 format or has errors in the filesystem structure).
+    OK, and the problem is at the filesystem level (i.e., the CDROM is
+    not ISO 9660 or has errors in the filesystem structure).
 
   - If you see `not a block device' errors, check that the definitions
     of the device special files are correct.  They should be as
@@ -357,7 +357,7 @@
     which could cause this.  It was fixed in 1.3.0.  If you can't
     upgrade, you can probably work around the problem by specifying a
     blocksize of 2048 when mounting.  (Note that you won't be able to
-    directly execute binaries off the cdrom in that case.)
+    directly execute binaries off the CDROM in that case.)
 
     If you see this in kernels later than 1.3.0, please report it as a
     bug.
@@ -366,7 +366,7 @@
 f. Data corruption.
 
   - Random data corruption was occasionally observed with the Hitachi
-    CDR-7730 cdrom. If you experience data corruption, using "hdx=slow"
+    CDR-7730 CDROM. If you experience data corruption, using "hdx=slow"
     as a command line parameter may work around the problem, at the
     expense of low system performance.
 
@@ -377,7 +377,7 @@
 /*
  * cdchange.c  [-v]  <device>  [<slot>]
  *
- * This loads a cdrom from a specified slot in a changer, and displays 
+ * This loads a CDROM from a specified slot in a changer, and displays 
  * information about the changer status.  The drive should be unmounted before 
  * using this program.
  *
@@ -385,8 +385,8 @@
  * or no slot was specified.
  *
  * Based on code originally from Gerhard Zuber <zuber@berlin.snafu.de>.
- * Changer status information, and rewrite for the new common cdrom driver
- * interface by Erik Andersen <andersee@et.byu.edu>.
+ * Changer status information, and rewrite for the new Uniform CDROM driver
+ * interface by Erik Andersen <andersee@debian.org>.
  */
 
 #include <stdio.h>
diff -u --recursive --new-file v2.1.112/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.112/linux/MAINTAINERS	Tue Jul 28 14:21:07 1998
+++ linux/MAINTAINERS	Thu Jul 30 20:06:52 1998
@@ -290,7 +290,7 @@
 P:	Mark Lord
 M:	mlord@pobox.com
 L:	linux-kernel@vger.rutgers.edu
-S:	Maintained
+S:	Odd Fixes
 
 IDE/ATAPI CDROM DRIVER 
 P:	Erik Andersen
diff -u --recursive --new-file v2.1.112/linux/Makefile linux/Makefile
--- v2.1.112/linux/Makefile	Tue Jul 28 14:21:07 1998
+++ linux/Makefile	Thu Jul 30 11:17:11 1998
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 112
+SUBLEVEL = 113
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -111,6 +111,10 @@
 LIBS		=$(TOPDIR)/lib/lib.a
 SUBDIRS		=kernel drivers mm fs net ipc lib
 
+ifdef CONFIG_NUBUS
+DRIVERS := $(DRIVERS) drivers/nubus/nubus.a
+endif
+
 ifeq ($(CONFIG_ISDN),y)
 DRIVERS := $(DRIVERS) drivers/isdn/isdn.a
 endif
@@ -133,8 +137,16 @@
 DRIVERS := $(DRIVERS) drivers/pci/pci.a
 endif
 
+ifdef CONFIG_DIO
+DRIVERS := $(DRIVERS) drivers/dio/dio.a
+endif
+
 ifdef CONFIG_SBUS
 DRIVERS := $(DRIVERS) drivers/sbus/sbus.a
+endif
+
+ifdef CONFIG_ZORRO
+DRIVERS := $(DRIVERS) drivers/zorro/zorro.a
 endif
 
 ifdef CONFIG_PPC
diff -u --recursive --new-file v2.1.112/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.1.112/linux/arch/alpha/kernel/ptrace.c	Sun Jul 26 11:57:14 1998
+++ linux/arch/alpha/kernel/ptrace.c	Thu Jul 30 09:03:33 1998
@@ -13,7 +13,6 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
-#include <linux/debugreg.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.1.112/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.112/linux/arch/i386/defconfig	Sun Jul 26 11:57:14 1998
+++ linux/arch/i386/defconfig	Fri Jul 31 12:48:16 1998
@@ -65,6 +65,8 @@
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 CONFIG_BLK_DEV_RZ1000=y
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
diff -u --recursive --new-file v2.1.112/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.1.112/linux/arch/i386/kernel/ptrace.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/i386/kernel/ptrace.c	Thu Jul 30 09:03:33 1998
@@ -12,12 +12,12 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
-#include <linux/debugreg.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/processor.h>
+#include <asm/debugreg.h>
 
 /*
  * does not yet catch signals sent when the child dies.
diff -u --recursive --new-file v2.1.112/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.1.112/linux/arch/i386/kernel/traps.c	Thu Jul 16 18:09:23 1998
+++ linux/arch/i386/kernel/traps.c	Fri Jul 31 23:21:00 1998
@@ -27,6 +27,7 @@
 #include <asm/io.h>
 #include <asm/spinlock.h>
 #include <asm/atomic.h>
+#include <asm/debugreg.h>
 
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
@@ -294,24 +295,66 @@
 		unknown_nmi_error(reason, regs);
 }
 
+/*
+ * Careful - we must not do a lock-kernel until we have checked that the
+ * debug fault happened in user mode. Getting debug exceptions while
+ * in the kernel has to be handled without locking, to avoid deadlocks..
+ *
+ * Being careful here means that we don't have to be as careful in a
+ * lot of more complicated places (task switching can be a bit lazy
+ * about restoring all the debug state, and ptrace doesn't have to
+ * find every occurrence of the TF bit that could be saved away even
+ * by user code - and we don't have to be careful about what values
+ * can be written to the debug registers because there are no really
+ * bad cases).
+ */
 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
 {
-	lock_kernel();
-	if (regs->eflags & VM_MASK) {
-		handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
-		goto out;
+	unsigned int condition;
+	struct task_struct *tsk = current;
+
+	if (regs->eflags & VM_MASK)
+		goto debug_vm86;
+
+	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
+
+	/* Mask out spurious TF errors due to lazy TF clearing */
+	if (condition & DR_STEP) {
+		if ((tsk->flags & PF_PTRACED) == 0)
+			goto clear_TF;
 	}
-	force_sig(SIGTRAP, current);
-	current->tss.trap_no = 1;
-	current->tss.error_code = error_code;
-	if ((regs->xcs & 3) == 0) {
-		/* If this is a kernel mode trap, then reset db7 and allow us to continue */
-		__asm__("movl %0,%%db7"
-			: /* no output */
-			: "r" (0));
+
+	/* Mast out spurious debug traps due to lazy DR7 setting */
+	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
+		if (!tsk->tss.debugreg[7])
+			goto clear_dr7;
 	}
-out:
+
+	/* If this is a kernel mode trap, we need to reset db7 to allow us to continue sanely */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+	/* Ok, finally something we can handle */
+	tsk->tss.trap_no = 1;
+	tsk->tss.error_code = error_code;
+	force_sig(SIGTRAP, tsk);
+	return;
+
+debug_vm86:
+	lock_kernel();
+	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
 	unlock_kernel();
+	return;
+
+clear_dr7:
+	__asm__("movl %0,%%db7"
+		: /* no output */
+		: "r" (0));
+	return;
+
+clear_TF:
+	regs->eflags &= ~TF_MASK;
+	return;
 }
 
 /*
@@ -333,9 +376,9 @@
 	task->flags&=~PF_USEDFPU;
 	stts();
 
-	force_sig(SIGFPE, task);
 	task->tss.trap_no = 16;
 	task->tss.error_code = 0;
+	force_sig(SIGFPE, task);
 	unlock_kernel();
 }
 
@@ -434,7 +477,7 @@
 
 
 
-__initfunc(void trap_init(void))
+void __init trap_init(void)
 {
 	int i;
 	struct desc_struct * p;
diff -u --recursive --new-file v2.1.112/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.112/linux/arch/i386/mm/fault.c	Thu Jul 16 18:09:23 1998
+++ linux/arch/i386/mm/fault.c	Fri Jul 31 23:10:19 1998
@@ -100,10 +100,10 @@
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 
-	if (local_irq_count[smp_processor_id()])
-		die("page fault from irq handler",regs,error_code);
 	tsk = current;
 	mm = tsk->mm;
+	if (in_interrupt())
+		die("page fault from irq handler",regs,error_code);
 
 	down(&mm->mmap_sem);
 
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/amiga/Makefile linux/arch/m68k/amiga/Makefile
--- v2.1.112/linux/arch/m68k/amiga/Makefile	Tue Jun 23 10:01:20 1998
+++ linux/arch/m68k/amiga/Makefile	Thu Jul 30 11:08:19 1998
@@ -11,4 +11,8 @@
 O_OBJS   := config.o amiints.o cia.o chipram.o amisound.o
 OX_OBJS  := amiga_ksyms.o
 
+ifdef CONFIG_AMIGA_PCMCIA
+O_OBJS := $(O_OBJS) pcmcia.o
+endif
+
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/amiga/amiga_ksyms.c linux/arch/m68k/amiga/amiga_ksyms.c
--- v2.1.112/linux/arch/m68k/amiga/amiga_ksyms.c	Wed Apr  8 19:36:25 1998
+++ linux/arch/m68k/amiga/amiga_ksyms.c	Thu Jul 30 11:08:19 1998
@@ -2,6 +2,7 @@
 #include <linux/types.h>
 #include <linux/zorro.h>
 #include <asm/amigahw.h>
+#include <asm/amipcmcia.h>
 
 extern volatile u_short amiga_audio_min_period;
 extern u_short amiga_audio_period;
@@ -20,8 +21,11 @@
 EXPORT_SYMBOL(amiga_audio_period);
 EXPORT_SYMBOL(amiga_audio_min_period);
 
-EXPORT_SYMBOL(zorro_find);
-EXPORT_SYMBOL(zorro_get_board);
-EXPORT_SYMBOL(zorro_config_board);
-EXPORT_SYMBOL(zorro_unconfig_board);
-EXPORT_SYMBOL(zorro_unused_z2ram);
+#ifdef CONFIG_AMIGA_PCMCIA
+  EXPORT_SYMBOL(pcmcia_reset);
+  EXPORT_SYMBOL(pcmcia_copy_tuple);
+  EXPORT_SYMBOL(pcmcia_program_voltage);
+  EXPORT_SYMBOL(pcmcia_access_speed);
+  EXPORT_SYMBOL(pcmcia_write_enable);
+  EXPORT_SYMBOL(pcmcia_write_disable);
+#endif
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c
--- v2.1.112/linux/arch/m68k/amiga/amiints.c	Tue Feb 17 13:12:44 1998
+++ linux/arch/m68k/amiga/amiints.c	Thu Jul 30 11:08:19 1998
@@ -32,6 +32,7 @@
 #include <asm/traps.h>
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
+#include <asm/amipcmcia.h>
 
 extern int cia_request_irq(struct ciabase *base,int irq,
                            void (*handler)(int, void *, struct pt_regs *),
@@ -88,6 +89,10 @@
 	}
 	for (i = 0; i < AMI_IRQS; i++)
 		ami_ablecount[i] = 0;
+
+	/* turn off PCMCIA interrupts */
+	if (AMIGAHW_PRESENT(PCMCIA))
+		pcmcia_disable_irq();
 
 	/* turn off all interrupts and enable the master interrupt bit */
 	custom.intena = 0x7fff;
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v2.1.112/linux/arch/m68k/amiga/config.c	Thu Jul 16 18:09:23 1998
+++ linux/arch/m68k/amiga/config.c	Thu Jul 30 11:08:19 1998
@@ -51,6 +51,7 @@
 /* amiga specific keyboard functions */
 extern int amiga_keyb_init(void);
 extern int amiga_kbdrate (struct kbd_repeat *);
+extern void amiga_kbd_reset_setup(char*, int);
 /* amiga specific irq functions */
 extern void amiga_init_IRQ (void);
 extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
@@ -76,7 +77,6 @@
 #endif
 static void amiga_reset (void);
 static int amiga_wait_key (struct console *co);
-extern void zorro_init(void);
 extern void amiga_init_sound(void);
 static void amiga_savekmsg_init(void);
 static void amiga_mem_console_write(struct console *co, const char *b,
@@ -342,6 +342,7 @@
   mach_sched_init      = amiga_sched_init;
   mach_keyb_init       = amiga_keyb_init;
   mach_kbdrate         = amiga_kbdrate;
+  kbd_reset_setup      = amiga_kbd_reset_setup;
   mach_init_IRQ        = amiga_init_IRQ;
   mach_default_handler = &amiga_default_handler;
   mach_request_irq     = amiga_request_irq;
@@ -375,9 +376,7 @@
   mach_floppy_setup    = amiga_floppy_setup;
 #endif
   mach_reset           = amiga_reset;
-#ifdef CONFIG_DUMMY_CONSOLE  
   conswitchp           = &dummy_con;
-#endif
   kd_mksound           = amiga_mksound;
 #ifdef CONFIG_MAGIC_SYSRQ
   mach_sysrq_key = 0x5f;	     /* HELP */
@@ -398,27 +397,6 @@
   /* 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 ();
 
@@ -444,12 +422,8 @@
   if (AMIGAHW_PRESENT(MAGIC_REKICK))
 	  *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
 
-  zorro_init();
 #ifdef CONFIG_ZORRO
-  /*
-   * Identify all known AutoConfig Expansion Devices
-   */
-  zorro_identify();
+  zorro_init();
 #endif
 }
 
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/amiga/pcmcia.c linux/arch/m68k/amiga/pcmcia.c
--- v2.1.112/linux/arch/m68k/amiga/pcmcia.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/amiga/pcmcia.c	Thu Jul 30 11:08:19 1998
@@ -0,0 +1,113 @@
+/*
+** asm-m68k/pcmcia.c -- Amiga Linux PCMCIA support
+**                      most information was found by disassembling card.resource
+**                      I'm still looking for an official doc !
+**
+** Copyright 1997 by Alain Malek
+**
+** 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.
+**
+** Created: 12/10/97 by Alain Malek
+*/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <asm/amigayle.h>
+#include <asm/amipcmcia.h>
+
+/* gayle config byte for program voltage and access speed */
+static u_char cfg_byte = GAYLE_CFG_0V|GAYLE_CFG_150NS;
+
+void pcmcia_reset(void)
+{
+	unsigned long reset_start_time = jiffies;
+	unsigned char b;
+
+	gayle_reset = 0x00;
+	while (jiffies - reset_start_time < 1*HZ/100);
+	b = gayle_reset;
+}
+
+
+/* copy a tuple, including tuple header. return nb bytes copied */
+/* be carefull as this may trigger a GAYLE_IRQ_WR interrupt ! */
+
+int pcmcia_copy_tuple(unsigned char tuple_id, void *tuple, int max_len)
+{
+	unsigned char id, *dest;
+	int cnt, pos, len;
+
+	dest = tuple;
+	pos = 0;
+
+	id = gayle_attribute[pos];
+
+	while((id != CISTPL_END) && (pos < 0x10000)) {
+		len = (int)gayle_attribute[pos+2] + 2;
+		if (id == tuple_id) {
+			len = (len > max_len)?max_len:len;
+			for (cnt = 0; cnt < len; cnt++) {
+				*dest++ = gayle_attribute[pos+(cnt<<1)];
+			}
+
+			return len;
+		}
+		pos += len<<1;
+		id = gayle_attribute[pos];
+	}
+
+	return 0;
+}
+
+void pcmcia_program_voltage(int voltage)
+{
+	u_char v;
+
+	switch (voltage) {
+	case PCMCIA_0V:
+		v = GAYLE_CFG_0V;
+		break;
+	case PCMCIA_5V:
+		v = GAYLE_CFG_5V;
+		break;
+	case PCMCIA_12V:
+		v = GAYLE_CFG_12V;
+		break;
+	default:
+		v = GAYLE_CFG_0V;
+	}
+
+	cfg_byte = (cfg_byte & 0xfc) | v;
+	gayle.config = cfg_byte;
+
+}
+
+void pcmcia_access_speed(int speed)
+{
+	u_char s;
+
+	if (speed <= PCMCIA_SPEED_100NS)
+		s = GAYLE_CFG_100NS;
+	else if (speed <= PCMCIA_SPEED_150NS)
+		s = GAYLE_CFG_150NS;
+	else if (speed <= PCMCIA_SPEED_250NS)
+		s = GAYLE_CFG_250NS;
+	else
+		s = GAYLE_CFG_720NS;
+
+	cfg_byte = (cfg_byte & 0xf3) | s;
+	gayle.config = cfg_byte;
+}
+
+void pcmcia_write_enable(void)
+{
+	gayle.cardstatus = GAYLE_CS_WR|GAYLE_CS_DA;
+}
+
+void pcmcia_write_disable(void)
+{
+	gayle.cardstatus = 0;
+}
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- v2.1.112/linux/arch/m68k/atari/atakeyb.c	Tue Jun 23 10:01:20 1998
+++ linux/arch/m68k/atari/atakeyb.c	Thu Jul 30 11:08:19 1998
@@ -31,7 +31,6 @@
 #include <asm/atari_joystick.h>
 #include <asm/irq.h>
 
-extern unsigned char mach_keyboard_type;
 static void atakeyb_rep( unsigned long ignore );
 extern unsigned int keymap_count;
 
@@ -781,7 +780,7 @@
     keymap_count = 8;
 
     /* say that we don't have an AltGr key */
-    mach_keyboard_type = KB_84;
+    keyboard_type = KB_84;
 
     kb_state.state = KEYBOARD;
     kb_state.len = 0;
@@ -864,6 +863,6 @@
 }
 
 /* for "kbd-reset" cmdline param */
-__initfunc(void kbd_reset_setup(char *str, int *ints))
+__initfunc(void atari_kbd_reset_setup(char *str, int *ints))
 {
 }
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c
--- v2.1.112/linux/arch/m68k/atari/config.c	Thu Jul 16 18:09:23 1998
+++ linux/arch/m68k/atari/config.c	Thu Jul 30 11:08:19 1998
@@ -59,6 +59,7 @@
 extern int atari_keyb_init(void);
 extern int atari_kbdrate (struct kbd_repeat *);
 extern void atari_kbd_leds (unsigned int);
+extern void atari_kbd_reset_setup(char*, int);
 /* atari specific irq functions */
 extern void atari_init_IRQ (void);
 extern int atari_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -249,6 +250,7 @@
     mach_keyb_init       = atari_keyb_init;
     mach_kbdrate         = atari_kbdrate;
     mach_kbd_leds        = atari_kbd_leds;
+    kbd_reset_setup      = atari_kbd_reset_setup;
     mach_init_IRQ        = atari_init_IRQ;
     mach_request_irq     = atari_request_irq;
     mach_free_irq        = atari_free_irq;
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c
--- v2.1.112/linux/arch/m68k/atari/stram.c	Tue Jun 23 10:01:20 1998
+++ linux/arch/m68k/atari/stram.c	Thu Jul 30 11:08:19 1998
@@ -826,18 +826,23 @@
 						   unsigned long page, int isswap )
 {
 	struct vm_area_struct* vma;
+	int retval = 0;
 
 	/*
 	 * Go through process' page directory.
 	 */
 	if (!mm || mm == &init_mm)
 		return 0;
+	down(&mm->mmap_sem);
 	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;
+		if (unswap_vma( vma, pgd, entry, page, isswap )) {
+			retval = 1;
+			break;
+		}
 	}
-	return 0;
+	up(&mm->mmap_sem);
+	return retval;
 }
 
 
@@ -1160,7 +1165,7 @@
 
 
 /* setup parameters from command line */
-void stram_swap_setup( char *str, int *ints )
+__initfunc(void stram_swap_setup(char *str, int *ints))
 {
 	if (ints[0] >= 1)
 		max_swap_size = ((ints[1] < 0 ? 0 : ints[1]) * 1024) & PAGE_MASK;
@@ -1256,7 +1261,7 @@
         block_fsync             /* fsync */
 };
 
-int stram_device_init( void )
+__initfunc(int stram_device_init(void))
 {
 
     if (!MACH_IS_ATARI)
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.1.112/linux/arch/m68k/config.in	Wed Jun 24 22:54:03 1998
+++ linux/arch/m68k/config.in	Thu Jul 30 11:08:19 1998
@@ -60,10 +60,15 @@
     bool 'Use 68060 specific optimizations' CONFIG_OPTIMIZE_060
   fi
 fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_M68060" = "y" ]; then
+  define_bool CONFIG_060_WRITETHROUGH y
+fi
 bool 'Advanced processor options' CONFIG_ADVANCED_CPU
 if [ "$CONFIG_ADVANCED_CPU" = "y" ]; then
   bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
-  bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
+  if [ "$CONFIG_M68060" = "y" -a "$CONFIG_VME" = "n" ]; then
+    bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
+  fi
 fi
 endmenu
 
@@ -79,7 +84,10 @@
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 if [ "$CONFIG_AMIGA" = "y" ]; then
-  bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
+  bool 'Amiga Zorro (AutoConfig) bus support' CONFIG_ZORRO
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool 'Amiga 1200/600 PCMCIA support' CONFIG_AMIGA_PCMCIA
+  fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
@@ -131,23 +139,24 @@
 
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'A3000 WD33C93A support' CONFIG_A3000_SCSI
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
+  fi
+fi
+if [ "$CONFIG_ZORRO" = "y" ]; then
   tristate 'A2091 WD33C93A support' CONFIG_A2091_SCSI
   tristate 'GVP Series II WD33C93A support' CONFIG_GVP11_SCSI
   bool 'CyberStorm SCSI support' CONFIG_CYBERSTORM_SCSI
-  bool 'CyberStorm SCSI Mk II support' CONFIG_CYBERSTORMII_SCSI
+  bool 'CyberStorm Mk II SCSI support' CONFIG_CYBERSTORMII_SCSI
   bool 'Blizzard 2060 SCSI support' CONFIG_BLZ2060_SCSI
   bool 'Blizzard 1230IV/1260 SCSI support' CONFIG_BLZ1230_SCSI
   bool 'Fastlane SCSI support' CONFIG_FASTLANE_SCSI
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'A4000T SCSI support' CONFIG_A4000T_SCSI
     bool 'A4091 SCSI support' CONFIG_A4091_SCSI
     bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
-#    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
+    bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
 #    bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
   fi
-  if [ "$CONFIG_MAC" = "y" ]; then
-    bool '   Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
-  fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI
@@ -199,34 +208,37 @@
   comment 'CCP compressors for PPP are only built as modules.'
 fi
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
-if [ "$CONFIG_AMIGA" = "y" ]; then
+if [ "$CONFIG_ZORRO" = "y" ]; then
   tristate 'Ariadne support' CONFIG_ARIADNE
   tristate 'A2065 support' CONFIG_A2065
   tristate 'Hydra support' CONFIG_HYDRA
 fi
+if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+  tristate 'PCMCIA NE2000 support' CONFIG_APNE
+fi
 if [ "$CONFIG_APOLLO" = "y" ] ; then
   tristate 'Apollo 3c505 support' CONFIG_APOLLO_ELPLUS
 fi
-if [ "$CONFIG_ATARI" = "y" ]; then
-  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
+  bool 'MVME16x Ethernet support' CONFIG_MVME16x_NET
 fi
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
-  bool 'BVME6000 Ethernet support' CONFIG_APRICOT
+  bool 'BVME6000 Ethernet support' CONFIG_BVME6000_NET
 fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+  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
 endmenu
 
 fi
+fi
 
 source fs/Config.in
 
@@ -252,8 +264,10 @@
 fi
 
 tristate 'Parallel printer support' CONFIG_PRINTER
-if [ "$CONFIG_AMIGA" = "y" ]; then
+if [ "$CONFIG_ZORRO" = "y" ]; then
   dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER
+fi
+if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
@@ -275,11 +289,13 @@
 fi
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
+  bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
+fi
+if [ "$CONFIG_ZORRO" = "y" ]; then
   tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
   dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
   dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
   tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
-  bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
   bool 'Mac SCC serial support' CONFIG_MAC_SCC
@@ -317,7 +333,11 @@
   bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
   bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
 fi
-bool 'Support for user misc device modules' CONFIG_UMISC
+if [ "$CONFIG_VME" = "y" ]; then
+  define_bool CONFIG_UMISC y
+else
+  bool 'Support for user misc device modules' CONFIG_UMISC
+fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   bool 'Enhanced Real Time Clock Support' CONFIG_RTC
 fi
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- v2.1.112/linux/arch/m68k/defconfig	Tue Jun 23 10:01:20 1998
+++ linux/arch/m68k/defconfig	Thu Jul 30 11:08:19 1998
@@ -45,6 +45,7 @@
 # CONFIG_AMIGA_GSP is not set
 # CONFIG_GSP_RESOLVER is not set
 # CONFIG_GSP_A2410 is not set
+# CONFIG_AMIGA_PCMCIA is not set
 # CONFIG_HEARTBEAT is not set
 CONFIG_PROC_HARDWARE=y
 
@@ -148,6 +149,7 @@
 # CONFIG_ARIADNE is not set
 # CONFIG_A2065 is not set
 # CONFIG_HYDRA is not set
+# CONFIG_APNE is not set
 # CONFIG_ATARILANCE is not set
 # CONFIG_ATARI_BIONET is not set
 # CONFIG_ATARI_PAMSNET is not set
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/ifpsp060/iskeleton.S linux/arch/m68k/ifpsp060/iskeleton.S
--- v2.1.112/linux/arch/m68k/ifpsp060/iskeleton.S	Tue Feb 17 13:12:44 1998
+++ linux/arch/m68k/ifpsp060/iskeleton.S	Thu Jul 30 11:08:19 1998
@@ -72,14 +72,12 @@
 	beq	Lnotkern
 	rte
 Lnotkern:
-	tstl	SYMBOL_NAME(need_resched)
-	bne	Lmustsched
-	rte
-Lmustsched:
 	SAVE_ALL_INT
-
 	GET_CURRENT(%d0)
-	bral	SYMBOL_NAME(ret_from_exception)	| deliver signals, reschedule etc..
+	tstl	%curptr@(LTASK_NEEDRESCHED)
+	jne	SYMBOL_NAME(ret_from_exception)	| deliver signals,
+						| reschedule etc..
+	RESTORE_ALL
 
 |
 | _060_real_chk():
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.1.112/linux/arch/m68k/kernel/entry.S	Tue Jun 23 10:01:20 1998
+++ linux/arch/m68k/kernel/entry.S	Thu Jul 30 11:08:19 1998
@@ -114,7 +114,7 @@
 	| kernel stack, otherwise stack overflow can occur during
 	| heavy interupt load
 	andw	#ALLOWINT,%sr
-	tstl	SYMBOL_NAME(need_resched)
+	tstl	%curptr@(LTASK_NEEDRESCHED)
 	jne	SYMBOL_NAME(reschedule)
 	cmpl	#SYMBOL_NAME(task),%curptr	| task[0] cannot have signals
 	jeq	2f
@@ -582,6 +582,7 @@
 	.long SYMBOL_NAME(sys_getcwd)
 	.long SYMBOL_NAME(sys_capget)
 	.long SYMBOL_NAME(sys_capset)           /* 185 */
+	.long SYMBOL_NAME(sys_sigaltstack)
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/kernel/kgdb.c linux/arch/m68k/kernel/kgdb.c
--- v2.1.112/linux/arch/m68k/kernel/kgdb.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/kernel/kgdb.c	Thu Jul 30 11:08:19 1998
@@ -0,0 +1,1194 @@
+/*
+ *  arch/m68k/kernel/kgdb.c  --  Stub for GDB remote debugging protocol
+ *
+ *  Originally written by Glenn Engel, Lake Stevens Instrument Division
+ *
+ *  Contributed by HP Systems
+ *
+ *  Modified for SPARC by Stu Grossman, Cygnus Support.
+ *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
+ *  Modified and extended for Linux/68k by Roman Hodek
+ *
+ *  Send complaints, suggestions etc. to
+ *  <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ *  Copyright (C) 1996-97 Roman Hodek
+ */
+
+/*
+ *  kgdb usage notes:
+ *  -----------------
+ *
+ * If you select CONFIG_KGDB in the configuration, the kernel will be built
+ * with different gccc flags: "-g" is added to get debug infos, and
+ * "-fomit-frame-pointer" is omitted to make debugging easier. Since the
+ * resulting kernel will be quite big (approx. > 7 MB), it will be stripped
+ * before compresion. Such a kernel will behave just as usually, except if
+ * given a "debug=<device>" command line option. (Only serial devices are
+ * allowed for <device>, i.e. no printers or the like; possible values are
+ * machine depedend and are the same as for the usual debug device, the one
+ * for logging kernel messages.) If that option is given and the device can be
+ * initialized, the kernel will connect to the remote gdb in trap_init(). The
+ * serial parameters are fixed to 8N1 and 9600bps, for easyness of
+ * implementation.
+ *
+ * Of course, you need a remote machine a suitable gdb there. I.e., it must
+ * have support for a m68k-linux target built in. If the remote machine
+ * doesn't run Linux/68k itself, you have to build a cross gdb. This is done
+ * by
+ *    ./configure --target=m68k-linux
+ * in the gdb source directory. Until gdb comes with m68k-linux support by
+ * default, you have to apply some patches before. The remote debugging
+ * protocol itself is always built into gdb anyway, so you don't have to take
+ * special care about it.
+ *
+ * To start a debugging session, start that gdb with the debugging kernel
+ * image (the one with the symbols, vmlinux.debug) named on the command line.
+ * This file will be used by gdb to get symbol and debugging infos about the
+ * kernel. Next, select remote debug mode by
+ *    target remote <device>
+ * where <device> is the name of the serial device over which the debugged
+ * machine is connected. Maybe you have to adjust the baud rate by
+ *    set remotebaud <rate>
+ * or also other parameters with stty:
+ *    shell stty ... </dev/...
+ * If the kernel to debug has already booted, it waited for gdb and now
+ * connects, and you'll see a breakpoint being reported. If the kernel isn't
+ * running yet, start it now. The order of gdb and the kernel doesn't matter.
+ * Another thing worth knowing about in the getting-started phase is how to
+ * debug the remote protocol itself. This is activated with
+ *    set remotedebug 1
+ * gdb will then print out each packet sent or received. You'll also get some
+ * messages about the gdb stub on the console of the debugged machine.
+ *
+ * If all that works, you can use lots of the usual debugging techniques on
+ * the kernel, e.g. inspecting and changing variables/memory, setting
+ * breakpoints, single stepping and so on. It's also possible to interrupt the
+ * debugged kernel by pressing C-c in gdb. Have fun! :-)
+ *
+ * The gdb stub is entered (and thus the remote gdb gets control) in the
+ * following situations:
+ *
+ *  - If breakpoint() is called. This is just after kgdb initialization, or if
+ *    a breakpoint() call has been put somewhere into the kernel source.
+ *    (Breakpoints can of course also be set the usual way in gdb.)
+ *
+ *  - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel()
+ *    are entered. All the CPU exceptions are mapped to (more or less..., see
+ *    the hard_trap_info array below) appropriate signal, which are reported
+ *    to gdb. die_if_kernel() is usually called after some kind of access
+ *    error and thus is reported as SIGSEGV.
+ *
+ *  - When panic() is called. This is reported as SIGABRT.
+ *
+ *  - If C-c is received over the serial line, which is treated as
+ *    SIGINT.
+ *
+ * Of course, all these signals are just faked for gdb, since there is no
+ * signal concept as such for the kernel. It also isn't possible --obviously--
+ * to set signal handlers from inside gdb, or restart the kernel with a
+ * signal.
+ *
+ * Current limitations:
+ *
+ *  - While the kernel is stopped, interrupts are disabled for safety reasons
+ *    (i.e., variables not changing magically or the like). But this also
+ *    means that the clock isn't running anymore, and that interrupts from the
+ *    hardware may get lost/not be served in time. This can cause some device
+ *    errors...
+ *
+ *  - When single-stepping, only one instruction of the current thread is
+ *    executed, but interrupts are allowed for that time and will be serviced
+ *    if pending. Be prepared for that.
+ *
+ *  - All debugging happens in kernel virtual address space. There's no way to
+ *    access physical memory not mapped in kernel space, or to access user
+ *    space. A way to work around this is using get_user_long & Co. in gdb
+ *    expressions, but only for the current process.
+ *
+ *  - Interrupting the kernel only works if interrupts are currently allowed,
+ *    and the interrupt of the serial line isn't blocked by some other means
+ *    (IPL too high, disabled, ...)
+ *
+ *  - The gdb stub is currently not reentrant, i.e. errors that happen therein
+ *    (e.g. accesing invalid memory) may not be caught correctly. This could
+ *    be removed in future by introducing a stack of struct registers.
+ *
+ */
+
+/*
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to kgdb_init() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  (Linux/68k note: Due to the current design, kgdb has to be initialized
+ *  after traps and interrupts.)
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing a TRAP #15 instruction.
+ *
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ *    bBB..BB	    Set baud rate to BB..BB		   OK or BNN, then sets
+ *							   baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/linkage.h>
+
+#include <asm/setup.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/kgdb.h>
+#ifdef CONFIG_ATARI
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#endif
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#endif
+
+
+#undef DEBUG
+
+/*
+ * global variable: register structure
+ */
+
+struct gdb_regs kgdb_registers;
+
+/*
+ * serial i/o functions
+ */
+
+static int (*serial_out)( unsigned char c );
+static unsigned char (*serial_in)( void );
+static unsigned char (*serial_intr)( void );
+
+#define	putDebugChar(c)		serial_out(c)
+#define	getDebugChar()		serial_in()
+
+
+/***************************** Prototypes *****************************/
+
+static int hex( unsigned char ch);
+static void getpacket( char *buffer);
+static void putpacket( char *buffer, int expect_ack);
+static inline unsigned long *get_vbr( void );
+static int protected_read( char *p, unsigned long *vbr );
+static int protected_write( char *p, char val, unsigned long *vbr );
+static unsigned char *mem2hex( char *mem, char *buf, int count, int
+                               may_fault);
+static char *hex2mem( char *buf, char *mem, int count, int may_fault);
+static int computeSignal( int tt);
+static int hexToInt( char **ptr, int *intValue);
+extern asmlinkage void kgdb_intr( int intno, void *data, struct pt_regs *fp );
+static asmlinkage void handle_exception( void );
+static void show_gdbregs( void );
+#ifdef CONFIG_ATARI
+static int atari_mfp_out( unsigned char c );
+static unsigned char atari_mfp_in( void );
+static unsigned char atari_mfp_intr( void );
+static int atari_scc_out( unsigned char c );
+static unsigned char atari_scc_in( void );
+static unsigned char atari_scc_intr( void );
+#endif
+#ifdef CONFIG_AMIGA
+extern int amiga_ser_out( unsigned char c );
+extern unsigned char amiga_ser_in( void );
+#endif
+
+/************************* End of Prototypes **************************/
+
+
+int kgdb_initialized = 0;	/* !0 means we've been initialized */
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+
+static char input_buffer[BUFMAX];
+static char output_buffer[BUFMAX];
+static const char hexchars[]="0123456789abcdef";
+/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ 
+static int remote_debug = 0;
+
+/* sizes (in bytes) of CPU stack frames */
+static int frame_sizes[16] = {
+	8, 8, 12, 12,				/* $0..$3 */
+	16, 8, 8, 60,				/* $4..$7 */
+	8, 20, 32, 92,				/* $8..$B */
+	12, 4, 4, 4					/* $C..$F */
+};
+
+/*
+ * Convert ch from a hex digit to an int
+ */
+static int hex(unsigned char ch)
+{
+	if (ch >= 'a' && ch <= 'f')
+		return ch-'a'+10;
+	if (ch >= '0' && ch <= '9')
+		return ch-'0';
+	if (ch >= 'A' && ch <= 'F')
+		return ch-'A'+10;
+	return -1;
+}
+
+/*
+ * scan for the sequence $<data>#<checksum>
+ */
+static void getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	unsigned char ch;
+
+	do {
+		/*
+		 * wait around for the start character,
+		 * ignore all other characters
+		 */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+		checksum = 0;
+		xmitcsum = -1;
+		count = 0;
+	
+		/*
+		 * now, read until a # or end of buffer is found
+		 */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+
+		if (count >= BUFMAX)
+			continue;
+
+		buffer[count] = 0;
+#ifdef DEBUG
+		printk( "kgdb: received packet %s\n", buffer );
+#endif
+		
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum |= hex(getDebugChar() & 0x7f);
+
+			if (checksum != xmitcsum) {
+				if (remote_debug)
+					printk( "kgdb: bad checksum. count = 0x%x sent=0x%x "
+							"buf=%s\n", checksum, xmitcsum, buffer );
+				putDebugChar('-');	/* failed checksum */
+			}
+			else {
+				putDebugChar('+'); /* successful transfer */
+
+				/*
+				 * if a sequence char is present,
+				 * reply the sequence ID
+				 */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+
+					/*
+					 * remove sequence chars from buffer
+					 */
+					count = strlen(buffer);
+					for (i=3; i <= count; i++)
+						buffer[i-3] = buffer[i];
+				}
+			}
+		}
+	}
+	while (checksum != xmitcsum);
+}
+
+/*
+ * send the packet in buffer.
+ */
+static void putpacket(char *buffer, int expect_ack)
+{
+	unsigned char checksum;
+	int count;
+	unsigned char ch;
+
+	/*
+	 * $<packet info>#<checksum>.
+	 */
+
+#ifdef DEBUG
+	printk( "kgdb: sending packet %s\n", buffer );
+#endif
+	do {
+		putDebugChar('$');
+		checksum = 0;
+		count = 0;
+
+		while ((ch = buffer[count]) != 0) {
+			if (!(putDebugChar(ch)))
+				return;
+			checksum += ch;
+			count += 1;
+		}
+
+		putDebugChar('#');
+		putDebugChar(hexchars[checksum >> 4]);
+		putDebugChar(hexchars[checksum & 0xf]);
+
+	}
+	while (expect_ack && (getDebugChar() & 0x7f) != '+');
+}
+
+
+static inline unsigned long *get_vbr( void )
+
+{	unsigned long *vbr;
+	
+	__asm__ __volatile__ ( "movec	%/vbr,%0" : "=d" (vbr) : );
+	return( vbr );
+}
+
+static int protected_read( char *p, unsigned long *vbr )
+
+{	unsigned char val;
+	int rv;
+
+	__asm__ __volatile__
+		( "movel	%3@(8),%/a0\n\t"
+		  "movel	#Lberr1,%3@(8)\n\t"
+		  "movel	%/sp,%/a1\n\t"
+		  "moveq	#1,%1\n\t"
+		  "moveb	%2@,%0\n"
+		  "nop		\n\t"
+		  "moveq	#0,%1\n\t"
+	  "Lberr1:\t"
+		  "movel	%/a1,%/sp\n\t"
+		  "movel	%/a0,%3@(8)"
+		  : "=&d" (val), "=&r" (rv)
+		  : "a" (p), "a" (vbr)
+		  : "a0", "a1" );
+
+	return( rv ? -1 : val );
+}
+
+static int protected_write( char *p, char val, unsigned long *vbr )
+
+{	int rv;
+
+	__asm__ __volatile__
+		( "movel	%3@(8),%/a0\n\t"
+		  "movel	#Lberr2,%3@(8)\n\t"
+		  "movel	%/sp,%/a1\n\t"
+		  "moveq	#1,%0\n\t"
+		  "moveb	%2,%1@\n"
+		  "nop		\n\t"
+		  "moveq	#0,%0\n\t"
+	  "Lberr2:\t"
+		  "movel	%/a1,%/sp\n\t"
+		  "movel	%/a0,%3@(8)"
+		  : "=&r" (rv)
+		  : "a" (p), "d" (val), "a" (vbr)
+		  : "a0", "a1" );
+
+	return( rv );
+}
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ * If MAY_FAULT is non-zero, then we will handle memory faults by returning
+ * a 0, else treat a fault like any other fault in the stub.
+ */
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int ch;
+	unsigned long *vbr = get_vbr();
+	
+	for( ; count-- > 0; ++mem ) {
+		if ((ch = protected_read( mem, vbr )) < 0) {
+			/* bus error happened */
+			if (may_fault)
+				return 0;
+			else {
+				/* ignore, but print a warning */
+				printk( "Bus error on read from %p\n", mem );
+				ch = 0;
+			}
+		}
+		*buf++ = hexchars[(ch >> 4) & 0xf];
+		*buf++ = hexchars[ch & 0xf];
+	}
+
+	*buf = 0;
+
+	return buf;
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ */
+static char *hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+	unsigned long *vbr = get_vbr();
+
+	for( i = 0; i < count; i++, mem++ ) {
+		ch = hex(*buf++) << 4;
+		ch |= hex(*buf++);
+		if (protected_write( mem, ch, vbr )) {
+			/* bus error happened */
+			if (may_fault)
+				return 0;
+			else
+				/* ignore, but print a warning */
+				printk( "Bus error on write to %p\n", mem );
+		}
+	}
+
+	return mem;
+}
+
+/*
+ * This table contains the mapping between SPARC hardware trap types, and
+ * signals, which are primarily what GDB understands.  It also indicates
+ * which hardware traps we need to commandeer when initializing the stub.
+ */
+static struct hard_trap_info
+{
+	unsigned char tt;			/* Trap type code for MIPS R3xxx and R4xxx */
+	unsigned char signo;		/* Signal that we map this trap into */
+} hard_trap_info[] = {
+	{ 1,			SIGINT },	/* excep. 1 is used to fake SIGINT */
+	{ VEC_BUSERR,	SIGSEGV },	/* bus/access error */
+	{ VEC_ADDRERR,	SIGBUS },	/* address error */
+	{ VEC_ILLEGAL,	SIGILL },	/* illegal insn */
+	{ VEC_ZERODIV,	SIGFPE },	/* (integer) divison by zero */
+	{ VEC_CHK,		SIGILL },	/* CHK insn */
+	{ VEC_TRAP,		SIGFPE },	/* [F]TRAPcc insn */
+	{ VEC_PRIV,		SIGILL },	/* priviledge violation (cannot happen) */
+	{ VEC_TRACE,	SIGTRAP },	/* trace trap (single-stepping) */
+	{ VEC_LINE10,	SIGILL },	/* A-line insn */
+	{ VEC_LINE11,	SIGILL },	/* F-line insn */
+	{ VEC_COPROC,	SIGIOT },	/* coprocessor protocol error */
+	{ VEC_FORMAT,	SIGIOT },	/* frame format error */
+	{ VEC_UNINT,	SIGIOT },	/* uninitialized intr. (should not happen) */
+	{ VEC_SYS,		SIGILL },	/* TRAP #0 = system call (illegal in kernel) */
+	{ VEC_TRAP1,	SIGILL },	/* TRAP #1 */
+	{ VEC_TRAP2,	SIGILL },	/* TRAP #2 */
+	{ VEC_TRAP3,	SIGILL },	/* TRAP #3 */
+	{ VEC_TRAP4,	SIGILL },	/* TRAP #4 */
+	{ VEC_TRAP5,	SIGILL },	/* TRAP #5 */
+	{ VEC_TRAP6,	SIGILL },	/* TRAP #6 */
+	{ VEC_TRAP7,	SIGILL },	/* TRAP #7 */
+	{ VEC_TRAP8,	SIGILL },	/* TRAP #8 */
+	{ VEC_TRAP9,	SIGILL },	/* TRAP #9 */
+	{ VEC_TRAP10,	SIGILL },	/* TRAP #10 */
+	{ VEC_TRAP11,	SIGILL },	/* TRAP #11 */
+	{ VEC_TRAP12,	SIGILL },	/* TRAP #12 */
+	{ VEC_TRAP13,	SIGILL },	/* TRAP #13 */
+	{ VEC_TRAP14,	SIGABRT },	/* TRAP #14 (used by kgdb_abort) */
+	{ VEC_TRAP15,	SIGTRAP },	/* TRAP #15 (breakpoint) */
+	{ VEC_FPBRUC,	SIGFPE },	/* FPU */
+	{ VEC_FPIR,		SIGFPE },	/* FPU */
+	{ VEC_FPDIVZ,	SIGFPE },	/* FPU */
+	{ VEC_FPUNDER,	SIGFPE },	/* FPU */
+	{ VEC_FPOE,		SIGFPE },	/* FPU */
+	{ VEC_FPOVER,	SIGFPE },	/* FPU */
+	{ VEC_FPNAN,	SIGFPE },	/* FPU */
+	{ VEC_FPUNSUP,	SIGFPE },	/* FPU */
+	{ VEC_UNIMPEA,	SIGILL },	/* unimpl. effective address */
+	{ VEC_UNIMPII,	SIGILL },	/* unimpl. integer insn */
+
+	{ 0, 0 }					/* Must be last */
+};
+
+
+/*
+ * Set up exception handlers for tracing and breakpoints
+ */
+void kgdb_init(void)
+{
+    extern char m68k_debug_device[];
+
+	/* fake usage to avoid gcc warnings about unused stuff (they're used in
+	 * assembler code) The local variables will be optimized away... */
+	void (*fake1)(void) = handle_exception;
+	int *fake2 = frame_sizes;
+	(void)fake1; (void)fake2;
+	
+	/* We don't modify the real exception vectors here for the m68k.
+	 * handle_exception() will be called from bad_kernel_trap() or
+	 * die_if_kernel() as needed. */
+
+	/*
+	 * Initialize the serial port (name in 'm68k_debug_device')
+	 */
+
+	serial_in = NULL;
+	serial_out = NULL;
+	serial_intr = NULL;
+	
+#ifdef CONFIG_ATARI
+	if (MACH_IS_ATARI) {
+		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 init */
+			mfp.trn_stat  &= ~0x01; /* disable TX */
+			mfp.rcv_stat  &= ~0x01; /* disable RX */
+			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 */
+			mfp.rcv_stat  |= 0x01;  /* enable RX */
+
+			/* set function pointers */
+			serial_in = atari_mfp_in;
+			serial_out = atari_mfp_out;
+			serial_intr = atari_mfp_intr;
+
+			/* allocate interrupt */
+			request_irq( IRQ_MFP_RECFULL, kgdb_intr, IRQ_TYPE_FAST, "kgdb",
+						 NULL );
+	    }
+		else if (!strcmp( m68k_debug_device, "ser2" )) {
+			extern int atari_SCC_reset_done;
+
+			/* SCC Modem2 serial port init */
+			static unsigned char *p, scc_table[] = {
+				9, 0xc0,		/* Reset */
+				4, 0x44,		/* x16, 1 stopbit, no parity */
+				3, 0xc0,		/* receiver: 8 bpc */
+				5, 0xe2,		/* transmitter: 8 bpc, assert dtr/rts */
+				2, 0x60,		/* base int vector */
+				9, 0x09,		/* int enab, with status low */
+				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 */
+				15, 0,			/* no stat ints */
+				1, 0x10,		/* Rx int every char, other ints off */
+				0
+			};
+	    
+			(void)scc.cha_b_ctrl; /* reset reg pointer */
+			MFPDELAY();
+			for( p = scc_table; *p != 0; ) {
+				scc.cha_b_ctrl = *p++;
+				MFPDELAY();
+				scc.cha_b_ctrl = *p++;
+				MFPDELAY();
+				if (p[-2] == 9)
+					udelay(40);	/* extra delay after WR9 access */
+			}
+			/* avoid that atari_SCC.c resets the whole SCC again */
+			atari_SCC_reset_done = 1;
+
+			/* set function pointers */
+			serial_in = atari_scc_in;
+			serial_out = atari_scc_out;
+			serial_intr = atari_scc_intr;
+
+			/* allocate rx and spcond ints */
+			request_irq( IRQ_SCCB_RX, kgdb_intr, IRQ_TYPE_FAST, "kgdb", NULL );
+			request_irq( IRQ_SCCB_SPCOND, kgdb_intr, IRQ_TYPE_FAST, "kgdb",
+						 NULL );
+		}
+	}
+#endif
+	
+#ifdef CONFIG_AMIGA
+	if (MACH_IS_AMIGA) {
+		/* always use built-in serial port, no init required */
+		serial_in = amiga_ser_in;
+		serial_out = amiga_ser_out;
+	}
+#endif
+
+#ifdef CONFIG_ATARI
+	if (!serial_in || !serial_out) {
+		if (*m68k_debug_device)
+			printk( "kgdb_init failed: no valid serial device!\n" );
+		else
+			printk( "kgdb not enabled\n" );
+		return;
+	}
+#endif
+
+	/*
+	 * In case GDB is started before us, ack any packets
+	 * (presumably "$?#xx") sitting there.
+	 */
+
+	putDebugChar ('+');
+	kgdb_initialized = 1;
+	printk( KERN_INFO "kgdb initialized.\n" );
+}
+
+
+/*
+ * Convert the MIPS hardware trap type code to a unix signal number.
+ */
+static int computeSignal(int tt)
+{
+	struct hard_trap_info *ht;
+
+	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+		if (ht->tt == tt)
+			return ht->signo;
+
+	return SIGHUP;		/* default for things we don't know about */
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr)
+	{
+		hexValue = hex(**ptr);
+		if (hexValue < 0)
+			break;
+
+		*intValue = (*intValue << 4) | hexValue;
+		numChars ++;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+
+/*
+ * This assembler stuff copies a struct frame (passed as argument) into struct
+ * gdb_regs registers and then calls handle_exception. After return from
+ * there, register and the like are restored from 'registers', the stack is
+ * set up and execution is continued where registers->pc tells us.
+ */
+
+/* offsets in struct frame */
+#define FRAMEOFF_D1		"0"		/* d1..d5 */
+#define FRAMEOFF_A0		"5*4"	/* a0..a2 */
+#define FRAMEOFF_D0		"8*4"
+#define FRAMEOFF_SR		"11*4"
+#define FRAMEOFF_PC		"11*4+2"
+#define FRAMEOFF_VECTOR	"12*4+2"
+
+/* offsets in struct gdb_regs */
+#define GDBOFF_D0		"0"
+#define GDBOFF_D1		"1*4"
+#define GDBOFF_D6		"6*4"
+#define GDBOFF_A0		"8*4"
+#define GDBOFF_A3		"11*4"
+#define GDBOFF_A7		"15*4"
+#define GDBOFF_VECTOR	"16*4"
+#define GDBOFF_SR		"16*4+2"
+#define GDBOFF_PC		"17*4"
+#define GDBOFF_FP0		"18*4"
+#define GDBOFF_FPCTL	"42*4"
+
+__asm__
+( "	.globl " SYMBOL_NAME_STR(enter_kgdb) "\n"
+  SYMBOL_NAME_STR(enter_kgdb) ":\n"
+  /* return if not initialized */
+  "		tstl	"SYMBOL_NAME_STR(kgdb_initialized)"\n"
+  "		bne		1f\n"
+  "		rts		\n"
+  "1:	orw		#0x700,%sr\n"		/* disable interrupts while in stub */
+  "		tstl	%sp@+\n"			/* pop off return address */
+  "		movel	%sp@+,%a0\n"		/* get pointer to fp->ptregs (param) */
+  "		movel	#"SYMBOL_NAME_STR(kgdb_registers)",%a1\n" /* destination */
+  /* copy d0-d5/a0-a1 into gdb_regs */
+  "		movel	%a0@("FRAMEOFF_D0"),%a1@("GDBOFF_D0")\n"
+  "		moveml	%a0@("FRAMEOFF_D1"),%d1-%d5\n"
+  "		moveml	%d1-%d5,%a1@("GDBOFF_D1")\n"
+  "		moveml	%a0@("FRAMEOFF_A0"),%d0-%d2\n"
+  "		moveml	%d0-%d2,%a1@("GDBOFF_A0")\n"
+  /* copy sr and pc */
+  "		movel	%a0@("FRAMEOFF_PC"),%a1@("GDBOFF_PC")\n"
+  "		movew	%a0@("FRAMEOFF_SR"),%a1@("GDBOFF_SR")\n"
+  /* copy format/vector word */
+  "		movew	%a0@("FRAMEOFF_VECTOR"),%a1@("GDBOFF_VECTOR")\n"
+  /* save FPU regs */
+  "		fmovemx	%fp0-%fp7,%a1@("GDBOFF_FP0")\n"
+  "		fmoveml	%fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n"
+
+  /* set stack to CPU frame */
+  "		addl	#"FRAMEOFF_SR",%a0\n"
+  "		movel	%a0,%sp\n"
+  "		movew	%sp@(6),%d0\n"
+  "		andl	#0xf000,%d0\n"
+  "		lsrl	#8,%d0\n"
+  "		lsrl	#2,%d0\n"		/* get frame format << 2 */
+  "		lea		"SYMBOL_NAME_STR(frame_sizes)",%a2\n"
+  "		addl	%a2@(%d0),%sp\n"
+  "		movel	%sp,%a1@("GDBOFF_A7")\n" /* save a7 now */
+
+  /* call handle_exception() now that the stack is set up */
+  "Lcall_handle_excp:"
+  "		jsr		"SYMBOL_NAME_STR(handle_exception)"\n"
+
+  /* after return, first restore FPU registers */
+  "		movel	#"SYMBOL_NAME_STR(kgdb_registers)",%a0\n" /* source */
+  "		fmovemx	%a0@("GDBOFF_FP0"),%fp0-%fp7\n"
+  "		fmoveml	%a0@("GDBOFF_FPCTL"),%fpcr/%fpsr/%fpiar\n"
+  /* set new stack pointer */
+  "		movel	%a0@("GDBOFF_A7"),%sp\n"
+  "		clrw	%sp@-\n"		/* fake format $0 frame */
+  "		movel	%a0@("GDBOFF_PC"),%sp@-\n" /* new PC into frame */
+  "		movew	%a0@("GDBOFF_SR"),%sp@-\n" /* new SR into frame */
+  /* restore general registers */
+  "		moveml	%a0@("GDBOFF_D0"),%d0-%d7/%a0-%a6\n"
+  /* and jump to new PC */
+  "		rte"
+  );
+
+
+/*
+ * This is the entry point for the serial interrupt handler. It calls the
+ * machine specific function pointer 'serial_intr' to get the char that
+ * interrupted. If that was C-c, the stub is entered as above, but based on
+ * just a struct intframe, not a struct frame.
+ */
+
+__asm__
+( SYMBOL_NAME_STR(kgdb_intr) ":\n"
+  /* return if not initialized */
+  "		tstl	"SYMBOL_NAME_STR(kgdb_initialized)"\n"
+  "		bne		1f\n"
+  "2:	rts		\n"
+  "1:	movel	"SYMBOL_NAME_STR(serial_intr)",%a0\n"
+  "		jsr		(%a0)\n"			/* get char from serial */
+  "		cmpb	#3,%d0\n"			/* is it C-c ? */
+  "		bne		2b\n"				/* no -> just ignore  */
+  "		orw		#0x700,%sr\n"		/* disable interrupts */
+  "		subql	#1,"SYMBOL_NAME_STR(local_irq_count)"\n"
+  "		movel	%sp@(12),%sp\n"		/* revert stack to where 'inthandler' set
+									 * it up */
+  /* restore regs from frame */
+  "		moveml	%sp@+,%d1-%d5/%a0-%a2\n"
+  "		movel	%sp@+,%d0\n"
+  "		addql	#8,%sp\n"			/* throw away orig_d0 and stkadj */
+  /* save them into 'registers' */
+  "		moveml	%d0-%d7/%a0-%a6,"SYMBOL_NAME_STR(kgdb_registers)"\n"
+  "		movel	#"SYMBOL_NAME_STR(kgdb_registers)",%a1\n" /* destination */
+  /* copy sr and pc */
+  "		movel	%sp@(2),%a1@("GDBOFF_PC")\n"
+  "		movew	%sp@,%a1@("GDBOFF_SR")\n"
+  /* fake format 0 and vector 1 (translated to SIGINT) */
+  "		movew	#4,%a1@("GDBOFF_VECTOR")\n"
+  /* save FPU regs */
+  "		fmovemx	%fp0-%fp7,%a1@("GDBOFF_FP0")\n"
+  "		fmoveml	%fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n"
+  /* pop off the CPU stack frame */
+  "		addql	#8,%sp\n"
+  "		movel	%sp,%a1@("GDBOFF_A7")\n" /* save a7 now */
+  /* proceed as in enter_kgdb */
+  "		jbra	Lcall_handle_excp\n"
+  );
+
+/*
+ * This function does all command processing for interfacing to gdb.  It
+ * returns 1 if you should skip the instruction at the trap address, 0
+ * otherwise.
+ */
+static asmlinkage void handle_exception( void )
+{
+	int trap;			/* Trap type */
+	int sigval;
+	int addr;
+	int length;
+	char *ptr;
+
+	trap = kgdb_registers.vector >> 2;
+	sigval = computeSignal(trap);
+	/* clear upper half of vector/sr word */
+	kgdb_registers.vector = 0;
+	kgdb_registers.format = 0;
+	
+#ifndef DEBUG
+	if (remote_debug) {
+#endif
+		printk("in handle_exception() trap=%d sigval=%d\n", trap, sigval );
+		show_gdbregs();
+#ifndef DEBUG
+	}
+#endif
+
+	/*
+	 * reply to host that an exception has occurred
+	 */
+	ptr = output_buffer;
+
+	/*
+	 * Send trap type (converted to signal)
+	 */
+	*ptr++ = 'T';
+	*ptr++ = hexchars[sigval >> 4];
+	*ptr++ = hexchars[sigval & 0xf];
+
+	/*
+	 * Send Error PC
+	 */
+	*ptr++ = hexchars[GDBREG_PC >> 4];
+	*ptr++ = hexchars[GDBREG_PC & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex((char *)&kgdb_registers.pc, ptr, 4, 0);
+	*ptr++ = ';';
+
+	/*
+	 * Send frame pointer
+	 */
+	*ptr++ = hexchars[GDBREG_A6 >> 4];
+	*ptr++ = hexchars[GDBREG_A6 & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex((char *)&kgdb_registers.regs[GDBREG_A6], ptr, 4, 0);
+	*ptr++ = ';';
+
+	/*
+	 * Send stack pointer
+	 */
+	*ptr++ = hexchars[GDBREG_SP >> 4];
+	*ptr++ = hexchars[GDBREG_SP & 0xf];
+	*ptr++ = ':';
+	ptr = mem2hex((char *)&kgdb_registers.regs[GDBREG_SP], ptr, 4, 0);
+	*ptr++ = ';';
+
+	*ptr++ = 0;
+	putpacket(output_buffer,1);	/* send it off... */
+
+	/*
+	 * Wait for input from remote GDB
+	 */
+	for(;;) {
+		output_buffer[0] = 0;
+		getpacket(input_buffer);
+
+		switch (input_buffer[0]) {
+		  case '?':
+			output_buffer[0] = 'S';
+			output_buffer[1] = hexchars[sigval >> 4];
+			output_buffer[2] = hexchars[sigval & 0xf];
+			output_buffer[3] = 0;
+			break;
+
+		  case 'd':
+			/* toggle debug flag */
+			remote_debug = !remote_debug;
+			break;
+
+			/*
+			 * Return the value of the CPU registers
+			 */
+		  case 'g':
+			ptr = output_buffer;
+			ptr = mem2hex((char *)&kgdb_registers, ptr, NUMREGSBYTES, 0);
+			break;
+	  
+			/*
+			 * set the value of the CPU registers - return OK
+			 */
+		  case 'G':
+			ptr = &input_buffer[1];
+			ptr = hex2mem(ptr, (char *)&kgdb_registers, NUMREGSBYTES, 0);
+			strcpy(output_buffer,"OK");
+			break;
+
+			/*
+			 * Pn...=r...    Write register n
+			 */
+		  case 'P':
+			ptr = &input_buffer[1];
+			if (hexToInt(&ptr, &addr) && *ptr++ == '=') {
+				if (addr >= 0 && addr <= GDBREG_PC)
+					hex2mem(ptr, (char *)&kgdb_registers.regs[addr], 4, 0);
+				else if (addr >= GDBREG_FP0 && addr <= GDBREG_FP7)
+					hex2mem(ptr, (char *)&kgdb_registers.fpregs[addr-GDBREG_FP0],
+							12, 0);
+				else if (addr >= GDBREG_FPCR && addr <= GDBREG_FPIAR)
+					hex2mem(ptr, (char *)&kgdb_registers.fpcntl[addr-GDBREG_FPCR],
+							4, 0);
+			}
+			else
+				strcpy(output_buffer,"E01");
+			break;
+			
+			/*
+			 * mAA..AA,LLLL  Read LLLL bytes at address AA..AA
+			 */
+		  case 'm':
+			ptr = &input_buffer[1];
+
+			if (hexToInt(&ptr, &addr)
+				&& *ptr++ == ','
+				&& hexToInt(&ptr, &length)) {
+				if (mem2hex((char *)addr, output_buffer, length, 1))
+					break;
+				strcpy (output_buffer, "E03");
+			} else
+				strcpy(output_buffer,"E01");
+			break;
+
+			/*
+			 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
+			 */
+		  case 'M': 
+			ptr = &input_buffer[1];
+
+			if (hexToInt(&ptr, &addr)
+				&& *ptr++ == ','
+				&& hexToInt(&ptr, &length)
+				&& *ptr++ == ':') {
+				if (hex2mem(ptr, (char *)addr, length, 1))
+					strcpy(output_buffer, "OK");
+				else
+					strcpy(output_buffer, "E03");
+			}
+			else
+				strcpy(output_buffer, "E02");
+			break;
+
+			/*
+			 * cAA..AA    Continue at address AA..AA(optional)
+			 * sAA..AA    Step one instruction from AA..AA(optional)
+			 */
+		  case 'c':    
+		  case 's':    
+			/* try to read optional parameter, pc unchanged if no parm */
+
+			ptr = &input_buffer[1];
+			if (hexToInt(&ptr, &addr))
+				kgdb_registers.pc = addr;
+
+			kgdb_registers.sr &= 0x7fff;	/* clear Trace bit */
+			if (input_buffer[0] == 's')
+				kgdb_registers.sr |= 0x8000;	/* set it if step command */
+			
+			if (remote_debug)
+				printk( "cont; new PC=0x%08lx SR=0x%04x\n",
+						kgdb_registers.pc, kgdb_registers.sr );
+			
+			/*
+			 * Need to flush the instruction cache here, as we may
+			 * have deposited a breakpoint, and the icache probably
+			 * has no way of knowing that a data ref to some location
+			 * may have changed something that is in the instruction
+			 * cache.
+			 */
+
+			if (m68k_is040or060)
+				__asm__ __volatile__
+					( ".word 0xf4f8\n\t" /* CPUSHA I/D */
+					  ".word 0xf498" 	 /* CINVA  I */
+					);
+			else
+				__asm__ __volatile__
+					( "movec %/cacr,%/d0\n\t"
+					  "oriw  #0x0008,%/d0\n\t"
+					  "movec %/d0,%/cacr"
+					  : : : "d0" );
+
+			return;
+
+			/*
+			 * kill the program means reset the machine
+			 */
+		  case 'k' :
+		  case 'r':
+			if (mach_reset) {
+				/* reply OK before actual reset */
+				strcpy(output_buffer,"OK");
+				putpacket(output_buffer,0);
+				mach_reset();
+			}
+			else
+				strcpy(output_buffer,"E01");
+			break;
+
+			/*
+			 * Set baud rate (bBB)
+			 * FIXME: Needs to be written (in gdb, too...)
+			 */
+		  case 'b':
+			strcpy(output_buffer,"E01");
+			break;
+
+		}			/* switch */
+
+		/*
+		 * reply to the request
+		 */
+
+		putpacket(output_buffer,1);
+
+	}
+}
+
+
+/*
+ * Print registers (on target console)
+ * Used only to debug the stub...
+ */
+static void show_gdbregs( void )
+{
+	printk( "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
+			kgdb_registers.regs[0], kgdb_registers.regs[1],
+			kgdb_registers.regs[2], kgdb_registers.regs[3] );
+	printk( "d4: %08lx d5: %08lx d6: %08lx d7: %08lx\n",
+			kgdb_registers.regs[4], kgdb_registers.regs[5],
+			kgdb_registers.regs[6], kgdb_registers.regs[7] );
+	printk( "a0: %08lx a1: %08lx a2: %08lx a3: %08lx\n",
+			kgdb_registers.regs[8], kgdb_registers.regs[9],
+			kgdb_registers.regs[10], kgdb_registers.regs[11] );
+	printk( "a4: %08lx a5: %08lx a6: %08lx a7: %08lx\n",
+			kgdb_registers.regs[12], kgdb_registers.regs[13],
+			kgdb_registers.regs[14], kgdb_registers.regs[15] );
+	printk( "pc: %08lx sr: %04x\n", kgdb_registers.pc, kgdb_registers.sr );
+}
+
+
+/* -------------------- Atari serial I/O -------------------- */
+
+#ifdef CONFIG_ATARI
+
+static int atari_mfp_out( unsigned char c )
+
+{
+    while( !(mfp.trn_stat & 0x80) ) /* wait for tx buf empty */
+		barrier();
+    mfp.usart_dta = c;
+	return( 1 );
+}
+
+
+static unsigned char atari_mfp_in( void )
+
+{
+    while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */
+		barrier();
+    return( mfp.usart_dta );
+}
+
+
+static unsigned char atari_mfp_intr( void )
+
+{
+    return( mfp.usart_dta );
+}
+
+
+static int atari_scc_out( unsigned char c )
+
+{
+    do {
+		MFPDELAY();
+    } while( !(scc.cha_b_ctrl & 0x04) ); /* wait for tx buf empty */
+	MFPDELAY();
+    scc.cha_b_data = c;
+	return( 1 );
+}
+
+
+static unsigned char atari_scc_in( void )
+
+{
+    do {
+		MFPDELAY();
+    } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
+	MFPDELAY();
+    return( scc.cha_b_data );
+}
+
+
+static unsigned char atari_scc_intr( void )
+
+{	unsigned char c, stat;
+	
+	MFPDELAY();
+	scc.cha_b_ctrl = 1; /* RR1 */
+	MFPDELAY();
+	stat = scc.cha_b_ctrl;
+	MFPDELAY();
+    c = scc.cha_b_data;
+	MFPDELAY();
+	if (stat & 0x30) {
+		scc.cha_b_ctrl = 0x30; /* error reset for overrun and parity */
+		MFPDELAY();
+	}
+	scc.cha_b_ctrl = 0x38; /* reset highest IUS */
+	MFPDELAY();
+	return( c );
+}
+
+#endif
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/kernel/m68k_defs.h linux/arch/m68k/kernel/m68k_defs.h
--- v2.1.112/linux/arch/m68k/kernel/m68k_defs.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/kernel/m68k_defs.h	Thu Jul 30 11:08:19 1998
@@ -0,0 +1,8 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
+
+#define TS_MAGICKEY	0x5a5a5a5a
+#define TS_TSS 462
+#define TS_ESP0 482
+#define TS_FPU 486
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.1.112/linux/arch/m68k/kernel/process.c	Fri May  8 23:14:42 1998
+++ linux/arch/m68k/kernel/process.c	Thu Jul 30 11:08:19 1998
@@ -66,14 +66,14 @@
 	current->priority = -100;
 	current->counter = -100;
 	for (;;){
-		check_pgt_cache();
-		if (!need_resched)
+		if (!current->need_resched)
 #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
 			/* block out HSYNC on the atari (falcon) */
 			__asm__("stop #0x2200" : : : "cc");
 #else /* portable version */
 			__asm__("stop #0x2000" : : : "cc");
 #endif /* machine compilation types */ 
+		check_pgt_cache();
 		run_task_queue(&tq_scheduler);
 		schedule();
 	}
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.1.112/linux/arch/m68k/kernel/setup.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/kernel/setup.c	Thu Jul 30 11:08:19 1998
@@ -61,6 +61,8 @@
 int (*mach_keyb_init) (void) __initdata;
 int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
 void (*mach_kbd_leds) (unsigned int) = NULL;
+/* machine dependent "kbd-reset" setup function */
+void (*kbd_reset_setup) (char *, int) __initdata = NULL;
 /* machine dependent irq functions */
 void (*mach_init_IRQ) (void) __initdata;
 void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
@@ -102,7 +104,7 @@
 extern void config_sun3(void);
 extern void config_apollo(void);
 extern void config_mvme16x(void);
-extern void config_bmve6000(void);
+extern void config_bvme6000(void);
 extern void config_hp300(void);
 
 #define MASK_256K 0xfffc0000
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.1.112/linux/arch/m68k/kernel/signal.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/kernel/signal.c	Thu Jul 30 11:08:19 1998
@@ -147,6 +147,12 @@
 	return ret;
 }
 
+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+	return do_sigaltstack(uss, uoss, rdusp());
+}
+
 
 /*
  * Do a signal return; undo the signal stack.
@@ -177,31 +183,33 @@
 
 static unsigned char fpu_version = 0;	/* version number of fpu, set by setup_frame */
 
-static inline void restore_fpu_state(struct sigcontext *sc)
+static inline int restore_fpu_state(struct sigcontext *sc)
 {
+	int err = 1;
+
 	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;
+		goto out;
 	    if (CPU_IS_020_OR_030) {
 		if (m68k_fputype & FPU_68881 &&
 		    !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
-		    goto badframe;
+		    goto out;
 		if (m68k_fputype & FPU_68882 &&
 		    !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
-		    goto badframe;
+		    goto out;
 	    } else if (CPU_IS_040) {
 		if (!(sc->sc_fpstate[1] == 0x00 ||
                       sc->sc_fpstate[1] == 0x28 ||
                       sc->sc_fpstate[1] == 0x60))
-		    goto badframe;
+		    goto out;
 	    } else if (CPU_IS_060) {
 		if (!(sc->sc_fpstate[3] == 0x00 ||
                       sc->sc_fpstate[3] == 0x60 ||
 		      sc->sc_fpstate[3] == 0xe0))
-		    goto badframe;
+		    goto out;
 	    } else
-		goto badframe;
+		goto out;
 
 	    __asm__ volatile (".chip 68k/68881\n\t"
 			      "fmovemx %0,%/fp0-%/fp1\n\t"
@@ -213,10 +221,10 @@
 	__asm__ volatile (".chip 68k/68881\n\t"
 			  "frestore %0\n\t"
 			  ".chip 68k" : : "m" (*sc->sc_fpstate));
-	return;
+	err = 0;
 
-badframe:
-        do_exit(SIGSEGV);
+out:
+	return err;
 }
 
 #define FPCONTEXT_SIZE	216
@@ -224,42 +232,43 @@
 #define uc_formatvec	uc_filler[FPCONTEXT_SIZE/4]
 #define uc_extra	uc_filler[FPCONTEXT_SIZE/4+1]
 
-static inline void rt_restore_fpu_state(struct ucontext *uc)
+static inline int rt_restore_fpu_state(struct ucontext *uc)
 {
 	unsigned char fpstate[FPCONTEXT_SIZE];
 	int context_size = CPU_IS_060 ? 8 : 0;
 	fpregset_t fpregs;
+	int err = 1;
 
 	if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
-		goto badframe;
+		goto out;
 	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;
+			goto out;
 		if (CPU_IS_020_OR_030) {
 			if (m68k_fputype & FPU_68881 &&
 			    !(context_size == 0x18 || context_size == 0xb4))
-				goto badframe;
+				goto out;
 			if (m68k_fputype & FPU_68882 &&
 			    !(context_size == 0x38 || context_size == 0xd4))
-				goto badframe;
+				goto out;
 		} else if (CPU_IS_040) {
 			if (!(context_size == 0x00 ||
 			      context_size == 0x28 ||
 			      context_size == 0x60))
-				goto badframe;
+				goto out;
 		} else if (CPU_IS_060) {
 			if (!(fpstate[3] == 0x00 ||
 			      fpstate[3] == 0x60 ||
 			      fpstate[3] == 0xe0))
-				goto badframe;
+				goto out;
 		} else
-			goto badframe;
+			goto out;
 		if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
 				     sizeof(fpregs)))
-			goto badframe;
+			goto out;
 		__asm__ volatile (".chip 68k/68881\n\t"
 				  "fmovemx %0,%/fp0-%/fp7\n\t"
 				  "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
@@ -271,21 +280,23 @@
 	if (context_size &&
 	    __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1,
 			     context_size))
-		goto badframe;
+		goto out;
 	__asm__ volatile (".chip 68k/68881\n\t"
 			  "frestore %0\n\t"
 			  ".chip 68k" : : "m" (*fpstate));
-	return;
+	err = 0;
 
-badframe:
-        do_exit(SIGSEGV);
+out:
+	return err;
 }
 
 static inline int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp)
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
+		   int *pd0)
 {
 	int fsize, formatvec;
 	struct sigcontext context;
+	int err;
 
 	/* get previous context */
 	if (copy_from_user(&context, usc, sizeof(context)))
@@ -303,7 +314,7 @@
 	regs->format = formatvec >> 12;
 	regs->vector = formatvec & 0xfff;
 
-	restore_fpu_state(&context);
+	err = restore_fpu_state(&context);
 
 	fsize = frame_extra_sizes[regs->format];
 	if (fsize < 0) {
@@ -356,49 +367,55 @@
 		goto badframe;
 	}
 
-	return context.sc_d0;
+	*pd0 = context.sc_d0;
+	return err;
 
 badframe:
-        do_exit(SIGSEGV);
+	return 1;
 }
 
 static inline int
 rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
-		    struct ucontext *uc)
+		    struct ucontext *uc, int *pd0)
 {
 	int fsize, temp;
 	greg_t *gregs = uc->uc_mcontext.gregs;
+	unsigned long usp;
+	int err;
 
-	__get_user(temp, &uc->uc_mcontext.version);
+	err = __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]);
+	err |= __get_user(regs->d0, &gregs[0]);
+	err |= __get_user(regs->d1, &gregs[1]);
+	err |= __get_user(regs->d2, &gregs[2]);
+	err |= __get_user(regs->d3, &gregs[3]);
+	err |= __get_user(regs->d4, &gregs[4]);
+	err |= __get_user(regs->d5, &gregs[5]);
+	err |= __get_user(sw->d6, &gregs[6]);
+	err |= __get_user(sw->d7, &gregs[7]);
+	err |= __get_user(regs->a0, &gregs[8]);
+	err |= __get_user(regs->a1, &gregs[9]);
+	err |= __get_user(regs->a2, &gregs[10]);
+	err |= __get_user(sw->a3, &gregs[11]);
+	err |= __get_user(sw->a4, &gregs[12]);
+	err |= __get_user(sw->a5, &gregs[13]);
+	err |= __get_user(sw->a6, &gregs[14]);
+	err |= __get_user(usp, &gregs[15]);
+	wrusp(usp);
+	err |= __get_user(regs->pc, &gregs[16]);
+	err |= __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);
+	err |= __get_user(temp, &uc->uc_formatvec);
 	regs->format = temp >> 12;
 	regs->vector = temp & 0xfff;
 
-	rt_restore_fpu_state(uc);
+	err |= rt_restore_fpu_state(uc);
+
+	if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
+		goto badframe;
 
 	fsize = frame_extra_sizes[regs->format];
 	if (fsize < 0) {
@@ -449,10 +466,11 @@
 		goto badframe;
 	}
 
-	return regs->d0;
+	*pd0 = regs->d0;
+	return err;
 
 badframe:
-        do_exit(SIGSEGV);
+	return 1;
 }
 
 asmlinkage int do_sigreturn(unsigned long __unused)
@@ -462,6 +480,7 @@
 	unsigned long usp = rdusp();
 	struct sigframe *frame = (struct sigframe *)(usp - 24);
 	sigset_t set;
+	int d0;
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -475,10 +494,13 @@
 	current->blocked = set;
 	recalc_sigpending(current);
 	
-	return restore_sigcontext(regs, &frame->sc, frame + 1);
+	if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
+		goto badframe;
+	return d0;
 
 badframe:
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 asmlinkage int do_rt_sigreturn(unsigned long __unused)
@@ -488,6 +510,7 @@
 	unsigned long usp = rdusp();
 	struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
 	sigset_t set;
+	int d0;
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -498,10 +521,13 @@
 	current->blocked = set;
 	recalc_sigpending(current);
 	
-	return rt_restore_ucontext(regs, sw, &frame->uc);
+	if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
+		goto badframe;
+	return d0;
 
 badframe:
-	do_exit(SIGSEGV);
+	force_sig(SIGSEGV, current);
+	return 0;
 }
 
 /*
@@ -535,17 +561,18 @@
 	}
 }
 
-static inline void rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
+static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
 {
 	unsigned char fpstate[FPCONTEXT_SIZE];
 	int context_size = CPU_IS_060 ? 8 : 0;
+	int err = 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);
+	err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
 	if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
 		fpregset_t fpregs;
 		if (!CPU_IS_060)
@@ -566,11 +593,13 @@
 				  : "m" (*fpregs.f_fpregs),
 				    "m" (fpregs.f_pcr)
 				  : "memory");
-		copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, sizeof(fpregs));
+		err |= 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);
+		err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
+				    context_size);
+	return err;
 }
 
 static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
@@ -588,32 +617,34 @@
 	save_fpu_state(sc, regs);
 }
 
-static inline void rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
+static inline int 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;
+	int err = 0;
 
-	__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);
+	err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
+	err |= __put_user(regs->d0, &gregs[0]);
+	err |= __put_user(regs->d1, &gregs[1]);
+	err |= __put_user(regs->d2, &gregs[2]);
+	err |= __put_user(regs->d3, &gregs[3]);
+	err |= __put_user(regs->d4, &gregs[4]);
+	err |= __put_user(regs->d5, &gregs[5]);
+	err |= __put_user(sw->d6, &gregs[6]);
+	err |= __put_user(sw->d7, &gregs[7]);
+	err |= __put_user(regs->a0, &gregs[8]);
+	err |= __put_user(regs->a1, &gregs[9]);
+	err |= __put_user(regs->a2, &gregs[10]);
+	err |= __put_user(sw->a3, &gregs[11]);
+	err |= __put_user(sw->a4, &gregs[12]);
+	err |= __put_user(sw->a5, &gregs[13]);
+	err |= __put_user(sw->a6, &gregs[14]);
+	err |= __put_user(rdusp(), &gregs[15]);
+	err |= __put_user(regs->pc, &gregs[16]);
+	err |= __put_user(regs->sr, &gregs[17]);
+	err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
+	err |= rt_save_fpu_state(uc, regs);
+	return err;
 }
 
 static inline void push_cache (unsigned long vaddr)
@@ -708,60 +739,72 @@
 	}
 }
 
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+	unsigned long usp;
+
+	/* Default to using normal stack.  */
+	usp = rdusp();
+
+	/* This is the X/Open sanctioned signal stack switching.  */
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (!on_sig_stack(usp))
+			usp = current->sas_ss_sp + current->sas_ss_size;
+	}
+	return (void *)((usp - frame_size) & -8UL);
+}
+
 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;
+	int err = 0;
 
 	if (fsize < 0) {
 #ifdef DEBUG
 		printk ("setup_frame: Unknown frame format %#x\n",
 			regs->format);
 #endif
-		goto segv_and_exit;
+		goto give_sigsegv;
 	}
 
-	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 = get_sigframe(ka, regs, sizeof(*frame) + fsize);
 
 	if (fsize) {
-		if (copy_to_user (frame + 1, regs + 1, fsize))
-			goto segv_and_exit;
+		err |= copy_to_user (frame + 1, regs + 1, fsize);
 		regs->stkadj = fsize;
 	}
 
-	__put_user((current->exec_domain
-		    && current->exec_domain->signal_invmap
-		    && sig < 32
-		    ? current->exec_domain->signal_invmap[sig]
-		    : sig),
-		   &frame->sig);
+	err |= __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);
+	err |= __put_user(regs->vector, &frame->code);
+	err |= __put_user(&frame->sc, &frame->psc);
 
 	if (_NSIG_WORDS > 1)
-		copy_to_user(frame->extramask, &set->sig[1],
-			     sizeof(frame->extramask));
+		err |= 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;
+	err |= copy_to_user (&frame->sc, &context, sizeof(context));
 
 	/* Set up to return from userspace.  */
-	__put_user(frame->retcode, &frame->pretcode);
+	err |= __put_user(frame->retcode, &frame->pretcode);
 	/* addaw #20,sp */
-	__put_user(0xdefc0014, (long *)(frame->retcode + 0));
+	err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0));
 	/* moveq #,d0; trap #0 */
-	__put_user(0x70004e40 + (__NR_sigreturn << 16),
-		   (long *)(frame->retcode + 4));
+	err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
+			  (long *)(frame->retcode + 4));
+
+	if (err)
+		goto give_sigsegv;
 
 	push_cache ((unsigned long) &frame->retcode);
 
@@ -791,8 +834,10 @@
 	}
 	return;
 
-segv_and_exit:
-	do_exit(SIGSEGV);
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -800,48 +845,53 @@
 {
 	struct rt_sigframe *frame;
 	int fsize = frame_extra_sizes[regs->format];
+	int err = 0;
 
 	if (fsize < 0) {
 #ifdef DEBUG
 		printk ("setup_frame: Unknown frame format %#x\n",
 			regs->format);
 #endif
-		goto segv_and_exit;
+		goto give_sigsegv;
 	}
 
-	frame = (struct rt_sigframe *)((rdusp() - sizeof(*frame)) & -8);
-
-	/* XXX: Check here if we need to switch stacks.. */
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
 	if (fsize) {
-		if (copy_to_user (&frame->uc.uc_extra, regs + 1, fsize))
-			goto segv_and_exit;
+		err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
 		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;
+	err |= __put_user((current->exec_domain
+			   && current->exec_domain->signal_invmap
+			   && sig < 32
+			   ? current->exec_domain->signal_invmap[sig]
+			   : sig),
+			  &frame->sig);
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= __copy_to_user(&frame->info, info, sizeof(*info));
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user((void *)current->sas_ss_sp,
+			  &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(rdusp()),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= rt_setup_ucontext(&frame->uc, regs);
+	err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
 
 	/* Set up to return from userspace.  */
-	__put_user(frame->retcode, &frame->pretcode);
+	err |= __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));
+	err |= __put_user(0x203c, (short *)(frame->retcode + 0));
+	err |= __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
+	err |= __put_user(0x4e40, (short *)(frame->retcode + 6));
+
+	if (err)
+		goto give_sigsegv;
 
 	push_cache ((unsigned long) &frame->retcode);
 
@@ -871,8 +921,10 @@
 	}
 	return;
 
-segv_and_exit:
-	do_exit(SIGSEGV);
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
 }
 
 static inline void
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v2.1.112/linux/arch/m68k/kernel/sys_m68k.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/kernel/sys_m68k.c	Thu Jul 30 11:08:19 1998
@@ -66,6 +66,7 @@
 	struct file * file = NULL;
 	struct mmap_arg_struct a;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	error = -EFAULT;
 	if (copy_from_user(&a, arg, sizeof(a)))
@@ -78,11 +79,13 @@
 			goto out;
 	}
 	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
 	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
 	if (file)
 		fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return error;
 }
 
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c
--- v2.1.112/linux/arch/m68k/mac/config.c	Thu Jul 16 18:09:24 1998
+++ linux/arch/m68k/mac/config.c	Thu Jul 30 11:08:20 1998
@@ -63,6 +63,7 @@
 extern int mac_keyb_init(void);
 extern int mac_kbdrate(struct kbd_repeat *k);
 extern void mac_kbd_leds(unsigned int leds);
+extern void mac_kbd_reset_setup(char*, int);
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 extern void mac_mksound(unsigned int, unsigned int);
@@ -258,6 +259,7 @@
     mach_keyb_init       = mac_keyb_init;
     mach_kbdrate         = mac_kbdrate;
     mach_kbd_leds        = mac_kbd_leds;
+    kbd_reset_setup      = mac_kbd_reset_setup;
     mach_init_IRQ        = mac_init_IRQ;
     mach_request_irq     = mac_request_irq;
     mach_free_irq        = mac_free_irq;
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/mac/mackeyb.c linux/arch/m68k/mac/mackeyb.c
--- v2.1.112/linux/arch/m68k/mac/mackeyb.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/mac/mackeyb.c	Thu Jul 30 11:08:20 1998
@@ -750,3 +750,8 @@
 
 	return 0;
 }
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void mac_kbd_reset_setup(char *str, int *ints))
+{
+}
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.1.112/linux/arch/m68k/mm/fault.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/mm/fault.c	Thu Jul 30 11:08:20 1998
@@ -45,9 +45,10 @@
 #endif
 
 	down(&mm->mmap_sem);
+
 	vma = find_vma(mm, address);
 	if (!vma)
-	  goto bad_area;
+		goto bad_area;
 	if (vma->vm_flags & VM_IO)
 		goto bad_area;
 	if (vma->vm_start <= address)
@@ -86,7 +87,6 @@
 				goto bad_area;
 	}
 	handle_mm_fault(current, vma, address, write);
-	up(&mm->mmap_sem);
 
 	/* There seems to be a missing invalidate somewhere in do_no_page.
 	 * Until I found it, this one cures the problem and makes
@@ -94,6 +94,7 @@
 	 */
 	if (CPU_IS_040_OR_060)
 		flush_tlb_page(vma, address);
+	up(&mm->mmap_sem);
 	return 0;
 
 /*
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.1.112/linux/arch/m68k/mm/init.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/mm/init.c	Thu Jul 30 11:08:20 1998
@@ -76,7 +76,7 @@
 	total++;
 	if (PageReserved(mem_map+i))
 	    reserved++;
-	if (PageSwapCache(mem_map+i))
+	else if (PageSwapCache(mem_map+i))
 	    cached++;
 	else if (!atomic_read(&mem_map[i].count))
 	    free++;
@@ -91,6 +91,7 @@
     printk("%d pages nonshared\n",nonshared);
     printk("%d pages shared\n",shared);
     printk("%d pages swap cached\n",cached);
+    printk("%ld pages in page table cache\n",pgtable_cache_size);
     show_buffers();
 #ifdef CONFIG_NET
     show_net_buffers();
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/mm/kmap.c linux/arch/m68k/mm/kmap.c
--- v2.1.112/linux/arch/m68k/mm/kmap.c	Tue Feb 17 13:12:45 1998
+++ linux/arch/m68k/mm/kmap.c	Thu Jul 30 11:08:20 1998
@@ -19,10 +19,6 @@
 
 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)
 
diff -u --recursive --new-file v2.1.112/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.1.112/linux/arch/m68k/mm/memory.c	Tue Jun 23 10:01:21 1998
+++ linux/arch/m68k/mm/memory.c	Thu Jul 30 11:08:20 1998
@@ -21,14 +21,66 @@
 #include <asm/amigahw.h>
 #endif
 
-/* 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 */
-
-const char PgtabStr_bad_pmd[] = "Bad pmd in pte_alloc: %08lx\n";
-const char PgtabStr_bad_pgd[] = "Bad pgd in pmd_alloc: %08lx\n";
-const char PgtabStr_bad_pmdk[] = "Bad pmd in pte_alloc_kernel: %08lx\n";
-const char PgtabStr_bad_pgdk[] = "Bad pgd in pmd_alloc_kernel: %08lx\n";
+struct pgtable_cache_struct quicklists;
+
+void __bad_pte(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+	pmd_set(pmd, BAD_PAGETABLE);
+}
+
+void __bad_pmd(pgd_t *pgd)
+{
+	printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+	pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pmd_none(*pmd)) {
+		if (pte) {
+			clear_page((unsigned long)pte);
+			flush_page_to_ram((unsigned long)pte);
+			flush_tlb_kernel_page((unsigned long)pte);
+			nocache_page((unsigned long)pte);
+			pmd_set(pmd, pte);
+			return pte + offset;
+		}
+		pmd_set(pmd, BAD_PAGETABLE);
+		return NULL;
+	}
+	free_page((unsigned long)pte);
+	if (pmd_bad(*pmd)) {
+		__bad_pte(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+	pmd_t *pmd;
+
+	pmd = get_pointer_table();
+	if (pgd_none(*pgd)) {
+		if (pmd) {
+			pgd_set(pgd, pmd);
+			return pmd + offset;
+		}
+		pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
+		return NULL;
+	}
+	free_pointer_table(pmd);
+	if (pgd_bad(*pgd)) {
+		__bad_pmd(pgd);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + offset;
+}
+
 
 static struct ptable_desc {
 	struct ptable_desc *prev;
diff -u --recursive --new-file v2.1.112/linux/drivers/Makefile linux/drivers/Makefile
--- v2.1.112/linux/drivers/Makefile	Wed Jun 24 22:54:04 1998
+++ linux/drivers/Makefile	Thu Jul 30 11:17:11 1998
@@ -9,7 +9,13 @@
 
 SUB_DIRS     := block char net misc sound
 MOD_SUB_DIRS := $(SUB_DIRS) sbus
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp macintosh video
+ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \
+				 macintosh video dio zorro
+
+ifdef CONFIG_DIO
+SUB_DIRS += dio
+MOD_SUB_DIRS += dio
+endif
 
 ifdef CONFIG_PCI
 SUB_DIRS += pci
@@ -17,6 +23,14 @@
 
 ifdef CONFIG_SBUS
 SUB_DIRS += sbus
+endif
+
+ifdef CONFIG_ZORRO
+SUB_DIRS += zorro
+endif
+
+ifdef CONFIG_NUBUS
+SUB_DIRS += nubus
 endif
 
 ifdef CONFIG_VT
diff -u --recursive --new-file v2.1.112/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.1.112/linux/drivers/block/Config.in	Sun Jul 26 11:57:15 1998
+++ linux/drivers/block/Config.in	Thu Jul 30 20:06:52 1998
@@ -4,7 +4,14 @@
 mainmenu_option next_comment
 comment 'Block devices'
 
-tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD
+tristate 'Normal PC 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
+
 tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
 comment 'Please see Documentation/ide.txt for help/info on IDE drives'
 if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then
@@ -26,7 +33,10 @@
       bool '   Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
       if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
 	# Either the DMA code is buggy or the DMA hardware is unreliable. FIXME.
-        #bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
+        bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
+        if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+          bool '     Use DMA by default when available' CONFIG_IDEDMA_AUTO
+        fi
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
           bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
           if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
@@ -58,6 +68,17 @@
 fi
 if [ "$CONFIG_MCA" = "y" ]; then
   bool 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
+fi
+if [ "$CONFIG_ZORRO" = "y" ]; then
+  tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+  tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
+  if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
+    comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
+    bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
+    dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI
+  fi
 fi
 
 comment 'Additional Block Devices'
diff -u --recursive --new-file v2.1.112/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v2.1.112/linux/drivers/block/ataflop.c	Thu May  7 22:51:47 1998
+++ linux/drivers/block/ataflop.c	Thu Jul 30 11:17:11 1998
@@ -344,16 +344,10 @@
 	} while(0)
 
 #define	START_TIMEOUT()						\
-    do {							\
-        del_timer( &timeout_timer );				\
-        timeout_timer.expires = jiffies + FLOPPY_TIMEOUT;	\
-        add_timer( &timeout_timer );				\
-	} while(0)
+    mod_timer(&timeout_timer, jiffies + FLOPPY_TIMEOUT)
 
 #define	STOP_TIMEOUT()						\
-    do {							\
-        del_timer( &timeout_timer );				\
-	} while(0)
+    del_timer(&timeout_timer)
 
 
 /*
@@ -1409,27 +1403,25 @@
 
 static int floppy_revalidate (kdev_t dev)
 {
-  int drive = MINOR(dev) & 3;
+	int drive = MINOR(dev) & 3;
 
-  if (test_bit (drive, &changed_floppies) || test_bit (drive, &fake_change)
-      || unit[drive].disktype == 0)
-    {
-      if (UD.flags & FTD_MSG)
-          printk (KERN_ERR "floppy: clear format %p!\n", UDT);
-      BufferDrive = -1;
-      clear_bit (drive, &fake_change);
-      clear_bit (drive, &changed_floppies);
-      /* 
-       * MSch: clearing geometry makes sense only for autoprobe formats, 
-       * for 'permanent user-defined' parameter: restore default_params[] 
-       * here if flagged valid!
-       */
-      if (default_params[drive].blocks == 0)
-      UDT = 0;
-      else
-	UDT = &default_params[drive];
-    }
-  return 0;
+	if (test_bit(drive, &changed_floppies) ||
+	    test_bit(drive, &fake_change) ||
+	    unit[drive].disktype == 0) {
+		if (UD.flags & FTD_MSG)
+			printk(KERN_ERR "floppy: clear format %p!\n", UDT);
+		BufferDrive = -1;
+		clear_bit(drive, &fake_change);
+		clear_bit(drive, &changed_floppies);
+		/* MSch: clearing geometry makes sense only for autoprobe
+		   formats, for 'permanent user-defined' parameter:
+		   restore default_params[] here if flagged valid! */
+		if (default_params[drive].blocks == 0)
+			UDT = 0;
+		else
+			UDT = &default_params[drive];
+	}
+	return 0;
 }
 
 static __inline__ void copy_buffer(void *from, void *to)
@@ -1566,14 +1558,13 @@
 }
 
 
-static int
-invalidate_drive (kdev_t rdev)
+static int invalidate_drive(kdev_t rdev)
 {
-  /* invalidate the buffer track to force a reread */
-  BufferDrive = -1;
-  set_bit (MINOR(rdev) & 3, &fake_change);
-  check_disk_change (rdev);
-  return 0;
+	/* invalidate the buffer track to force a reread */
+	BufferDrive = -1;
+	set_bit(MINOR(rdev) & 3, &fake_change);
+	check_disk_change(rdev);
+	return 0;
 }
 
 static int fd_ioctl(struct inode *inode, struct file *filp,
@@ -1728,30 +1719,30 @@
 		/* no matching disk type found above - setting user_params */
 
 	       	if (cmd == FDDEFPRM) {
-		  /* set permanent type */
-		  dtp = &default_params[drive];
+			/* set permanent type */
+			dtp = &default_params[drive];
 		} else
-		  /* set user type (reset by disk change!) */
-		  dtp = &user_params[drive];
+			/* set user type (reset by disk change!) */
+			dtp = &user_params[drive];
 
 		dtp->name   = "user format";
 		dtp->blocks = setprm.size;
 		dtp->spt    = setprm.sect;
 		if (setprm.sect > 14) 
-		  dtp->fdc_speed = 3;
+			dtp->fdc_speed = 3;
 		else
-		  dtp->fdc_speed = 0;
+			dtp->fdc_speed = 0;
 		dtp->stretch = setprm.stretch;
 
 		if (UD.flags & FTD_MSG)
-		    printk (KERN_INFO "floppy%d: blk %d spt %d str %d!\n",
-		        drive, dtp->blocks, dtp->spt, dtp->stretch);
+			printk (KERN_INFO "floppy%d: blk %d spt %d str %d!\n",
+				drive, dtp->blocks, dtp->spt, dtp->stretch);
 
 		/* sanity check */
-		if (!dtp || setprm.track != dtp->blocks/dtp->spt/2 
-		    || setprm.head != 2) {
+		if (!dtp || setprm.track != dtp->blocks/dtp->spt/2 ||
+		    setprm.head != 2) {
 			redo_fd_request();
-		return -EINVAL;
+			return -EINVAL;
 		}
 
 		UDT = dtp;
@@ -1782,7 +1773,7 @@
 		return invalidate_drive (device);
 	case FDFMTEND:
 	case FDFLUSH:
-		return invalidate_drive (drive);
+		return invalidate_drive(device);
 	}
 	return -EINVAL;
 }
@@ -1925,70 +1916,68 @@
 
 static int floppy_open( struct inode *inode, struct file *filp )
 {
-  int drive, type;
-  int old_dev;
+	int drive, type;
+	int old_dev;
 
-  if (!filp)
-    {
-      DPRINT (("Weird, open called with filp=0\n"));
-      return -EIO;
-    }
-
-  drive = MINOR (inode->i_rdev) & 3;
-  type  = MINOR(inode->i_rdev) >> 2;
-  DPRINT(("fd_open: type=%d\n",type));
-  if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS)
-	return -ENXIO;
-
-  old_dev = fd_device[drive];
-
-  if (fd_ref[drive])
-    if (old_dev != inode->i_rdev)
-      return -EBUSY;
-
-  if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
-    return -EBUSY;
-
-  if (filp->f_flags & O_EXCL)
-    fd_ref[drive] = -1;
-  else
-    fd_ref[drive]++;
-
-  fd_device[drive] = inode->i_rdev;
-
-  if (old_dev && old_dev != inode->i_rdev)
-    invalidate_buffers(old_dev);
-
-  /* Allow ioctls if we have write-permissions even if read-only open */
-  if (filp->f_mode & 2 || permission (inode, 2) == 0)
-    filp->f_mode |= IOCTL_MODE_BIT;
-  if (filp->f_mode & 2)
-    filp->f_mode |= OPEN_WRITE_BIT;
-
-  MOD_INC_USE_COUNT;
-
-  if (filp->f_flags & O_NDELAY)
-    return 0;
-
-  if (filp->f_mode & 3) {
-	  check_disk_change( inode->i_rdev );
-	  if (filp->f_mode & 2) {
-		  if (UD.wpstat) {
-			  floppy_release(inode, filp);
-			  return -EROFS;
-		  }
-	  }
-  }
+	if (!filp) {
+		DPRINT (("Weird, open called with filp=0\n"));
+		return -EIO;
+	}
+
+	drive = MINOR(inode->i_rdev) & 3;
+	type  = MINOR(inode->i_rdev) >> 2;
+	DPRINT(("fd_open: type=%d\n",type));
+	if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS)
+		return -ENXIO;
+
+	old_dev = fd_device[drive];
+
+	if (fd_ref[drive] && old_dev != MINOR(inode->i_rdev))
+		return -EBUSY;
+
+	if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
+		return -EBUSY;
 
-  return 0;
+	MOD_INC_USE_COUNT;
+
+	if (filp->f_flags & O_EXCL)
+		fd_ref[drive] = -1;
+	else
+		fd_ref[drive]++;
+
+	fd_device[drive] = MINOR(inode->i_rdev);
+
+	if (old_dev && old_dev != MINOR(inode->i_rdev))
+		invalidate_buffers(MKDEV(FLOPPY_MAJOR, old_dev));
+
+	/* Allow ioctls if we have write-permissions even if read-only open */
+	if (filp->f_mode & 2 || permission (inode, 2) == 0)
+		filp->f_mode |= IOCTL_MODE_BIT;
+	if (filp->f_mode & 2)
+		filp->f_mode |= OPEN_WRITE_BIT;
+
+	if (filp->f_flags & O_NDELAY)
+		return 0;
+
+	if (filp->f_mode & 3) {
+		check_disk_change(inode->i_rdev);
+		if (filp->f_mode & 2) {
+			if (UD.wpstat) {
+				floppy_release(inode, filp);
+				return -EROFS;
+			}
+		}
+	}
+
+	return 0;
 }
 
 
 static int floppy_release( struct inode * inode, struct file * filp )
 {
-  int drive;
+	int drive;
 
-  drive = inode->i_rdev & 3;
+	drive = MINOR(inode->i_rdev) & 3;
 
 	/*
 	 * If filp is NULL, we're being called from blkdev_release
@@ -1999,16 +1988,15 @@
 	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
 		block_fsync (filp, filp->f_dentry);
 
-  if (fd_ref[drive] < 0)
-    fd_ref[drive] = 0;
-  else if (!fd_ref[drive]--)
-    {
-      printk(KERN_ERR "floppy_release with fd_ref == 0");
-      fd_ref[drive] = 0;
-    }
+	if (fd_ref[drive] < 0)
+		fd_ref[drive] = 0;
+	else if (!fd_ref[drive]--) {
+		printk(KERN_ERR "floppy_release with fd_ref == 0");
+		fd_ref[drive] = 0;
+	}
 
-  MOD_DEC_USE_COUNT;
-  return 0;
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 static struct file_operations floppy_fops = {
diff -u --recursive --new-file v2.1.112/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.1.112/linux/drivers/block/ide-cd.c	Thu May  7 22:51:48 1998
+++ linux/drivers/block/ide-cd.c	Wed Jul 29 12:37:05 1998
@@ -13,22 +13,31 @@
  * Suggestions are welcome. Patches that work are more welcome though. ;-)
  * For those wishing to work on this driver, please be sure you download
  * and comply with the latest ATAPI standard. This document can be
- * obtained by anonymous ftp from fission.dt.wdc.com in directory:
- * /pub/standards/SFF_atapi/spec/SFF8020-r2.6/PDF/8020r26.pdf
+ * obtained by anonymous ftp from:
+ * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
  *
  * Drives that deviate from the ATAPI standard will be accomodated as much
- * as possible via compile options.  Since I only have a few drives, you you
- * generally need to send me patches...
+ * as possable via compile time or command-line options.  Since I only have
+ * a few drives, you generally need to send me patches...
  *
  * ----------------------------------
  * TO DO LIST:
- * -Avoid printing error messages for expected errors from the drive.
- *    (If you are using a cd changer, you may get errors in the kernel
- *     logs that are completly expected.  Don't complain to me about this,
- *     unless you have a patch to fix it.  I am working on it...)
+ * -Implement Microsoft Media Status Notification per the spec at
+ *   http://www.microsoft.com/hwdev/respec/storspec.htm
+ *   This will allow us to get automagically notified when the media changes
+ *   on ATAPI drives (something the stock ATAPI spec is lacking).  Looks
+ *   very cool.  I discovered its existance the other day at work...
  * -Fix ide_cdrom_reset so that it works (it does nothing right now)
  * -Query the drive to find what features are available before trying to
  *   use them (like trying to close the tray in drives that can't).
+ * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on
+ *   boot
+ * -Handle older drives that can't report their speed. (i.e. check if they
+ *   support a version of ATAPI where they can report their speed before
+ *   checking their speed and believing what they return).
+ * -It seems we do not always honor it when Uniform gets a request to change 
+ *   the cdi->options.  We should _always_ check the options before doing stuff.
+ *   This must be fixed.
  *
  *
  * ----------------------------------
@@ -205,10 +214,13 @@
  *                         messages, since this is not an error.
  *                     -- Change error messages to be const
  *                     -- Remove a "\t" which looks ugly in the syslogs
+ * 4.14  July 17, 1998 -- Change to pointing to .ps version of ATAPI spec
+ *                         since the .pdf version doesn't seem to work...
+ *                     -- Updated the TODO list to something more current.
  *
  *************************************************************************/
 
-#define IDECD_VERSION "4.13"
+#define IDECD_VERSION "4.14"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -1157,7 +1169,7 @@
 		if (pc->buflen == 0)
 			cdrom_end_request (1, drive);
 		else {
-			/* Comment this out, because this always happins 
+			/* Comment this out, because this always happens 
 			   right after a reset occurs, and it is annoying to 
 			   always print expected stuff.  */
 			/*
diff -u --recursive --new-file v2.1.112/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- v2.1.112/linux/drivers/block/ide-cd.h	Thu May  7 22:51:48 1998
+++ linux/drivers/block/ide-cd.h	Wed Jul 29 12:37:05 1998
@@ -105,9 +105,9 @@
 #define ABORTED_COMMAND         0x0b
 #define MISCOMPARE              0x0e
 
-/* We want some additional flags for cd-rom drives.
+/* We want some additional flags for CDROM drives.
    To save space in the ide_drive_t struct, use some fields which
-   doesn't make sense for cd-roms -- `bios_cyl' and `bios_head'. */
+   doesn't make sense for CDROMs -- `bios_cyl' and `bios_head'. */
 
 /* Configuration flags.  These describe the capabilities of the drive.
    They generally do not change after initialization, unless we learn
diff -u --recursive --new-file v2.1.112/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c
--- v2.1.112/linux/drivers/block/ide-dma.c	Thu May  7 22:51:48 1998
+++ linux/drivers/block/ide-dma.c	Thu Jul 30 20:06:52 1998
@@ -210,7 +210,7 @@
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	if (id && (id->capability & 1) && !hwif->no_autodma) {
+	if (id && (id->capability & 1) && hwif->autodma) {
 		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
 		if (id->field_valid & 4)	/* UltraDMA */
 			if  ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
diff -u --recursive --new-file v2.1.112/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.1.112/linux/drivers/block/ide-pci.c	Thu Jul 16 18:09:24 1998
+++ linux/drivers/block/ide-pci.c	Thu Jul 30 20:06:52 1998
@@ -225,11 +225,14 @@
  */
 __initfunc(static void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d))
 {
-	unsigned int port, at_least_one_hwif_enabled = 0, no_autodma = 0, pciirq = 0;
+	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
 	unsigned short pcicmd = 0, tried_config = 0;
 	byte tmp = 0;
 	ide_hwif_t *hwif, *mate = NULL;
 
+#ifdef CONFIG_IDEDMA_AUTO
+	autodma = 1;
+#endif
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
 		printk("%s: error accessing PCI regs\n", d->name);
@@ -249,7 +252,7 @@
 			printk("%s: device disabled (BIOS)\n", d->name);
 			return;
 		}
-		no_autodma = 1;	/* default DMA off if we had to configure it here */
+		autodma = 0;	/* default DMA off if we had to configure it here */
 		goto check_if_enabled;
 	}
 	if (tried_config)
@@ -311,11 +314,11 @@
 			hwif->mate = mate;
 			mate->mate = hwif;
 		}
-		if (no_autodma)
-			hwif->no_autodma = 1;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513))
-			hwif->no_autodma = 1;	/* too many SIS-5513 systems have troubles */
+			autodma = 0;
+		if (autodma)
+			hwif->autodma = 1;
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
 		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
 			unsigned int extra = (!mate && IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246)) ? 16 : 0;
@@ -324,8 +327,7 @@
 				/*
  	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
  	 			 */
-printk("%s: %s enabling Bus-Master DMA\n", hwif->name, d->name);
-				hwif->no_autodma = 1;	/* default DMA off if we had to configure it here */
+				hwif->autodma = 0;	/* default DMA off if we had to configure it here */
 				(void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER);
 				if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
 					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
diff -u --recursive --new-file v2.1.112/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.1.112/linux/drivers/block/ide.c	Tue Jul 28 14:21:08 1998
+++ linux/drivers/block/ide.c	Thu Jul 30 20:06:52 1998
@@ -2289,7 +2289,7 @@
  * "idex=serialize"	: do not overlap operations on idex and ide(x^1)
  * "idex=four"		: four drives on idex and ide(x^1) share same ports
  * "idex=reset"		: reset interface before first use
- * "idex=nodma"		: do not enable DMA by default on either drive
+ * "idex=dma"		: enable DMA by default on both drives if possible
  *
  * The following are valid ONLY on ide0,
  * and the defaults for the base,ctl ports must not be altered.
@@ -2391,7 +2391,7 @@
 		/*
 		 * Be VERY CAREFUL changing this: note hardcoded indexes below
 		 */
-		const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "nodma", "four",
+		const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "four",
 			"qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL};
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
@@ -2479,8 +2479,8 @@
 				goto do_serialize;
 			}
 #endif /* CONFIG_BLK_DEV_4DRIVES */
-			case -6: /* nodma */
-				hwif->no_autodma = 1;
+			case -6: /* dma */
+				hwif->autodma = 1;
 				goto done;
 			case -5: /* "reset" */
 				hwif->reset = 1;
diff -u --recursive --new-file v2.1.112/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v2.1.112/linux/drivers/block/ide.h	Fri Jul 31 17:06:37 1998
+++ linux/drivers/block/ide.h	Fri Jul 31 23:38:40 1998
@@ -341,7 +341,7 @@
 	unsigned	serialized : 1;	/* serialized operation with mate hwif */
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
 	unsigned	reset      : 1;	/* reset after probe */
-	unsigned	no_autodma : 1;	/* don't automatically enable DMA at boot */
+	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
 	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
 	struct pci_dev	*pci_dev;	/* for pci chipsets */
 	ide_pci_devid_t	pci_devid;	/* for pci chipsets: {VID,DID} */
diff -u --recursive --new-file v2.1.112/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.1.112/linux/drivers/block/ll_rw_blk.c	Tue Jun 23 10:01:22 1998
+++ linux/drivers/block/ll_rw_blk.c	Thu Jul 30 11:17:11 1998
@@ -716,6 +716,9 @@
 		}
 	}
 }
+#ifdef CONFIG_STRAM_SWAP
+extern int stram_device_init( void );
+#endif
 
 /*
  * First step of what used to be end_request
@@ -796,6 +799,9 @@
 	memset(max_sectors, 0, sizeof(max_sectors));
 #ifdef CONFIG_AMIGA_Z2RAM
 	z2_init();
+#endif
+#ifdef CONFIG_STRAM_SWAP
+	stram_device_init();
 #endif
 #ifdef CONFIG_BLK_DEV_RAM
 	rd_init();
diff -u --recursive --new-file v2.1.112/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c
--- v2.1.112/linux/drivers/block/paride/pcd.c	Wed Jun 24 22:54:04 1998
+++ linux/drivers/block/paride/pcd.c	Wed Jul 29 12:37:05 1998
@@ -2,11 +2,11 @@
 	pcd.c	(c) 1997-8  Grant R. Guenther <grant@torque.net>
 		            Under the terms of the GNU public license.
 
-	This is high-level driver for parallel port ATAPI CDrom
+	This is a high-level driver for parallel port ATAPI CDROM
         drives based on chips supported by the paride module.
 
         By default, the driver will autoprobe for a single parallel
-        port ATAPI CDrom drive, but if their individual parameters are
+        port ATAPI CDROM drive, but if their individual parameters are
         specified, the driver can handle up to 4 drives.
 
         The behaviour of the pcd driver can be altered by setting
@@ -38,7 +38,7 @@
                         of the mode numbers supported by the adapter.
                         (-1 if not given)
 
-		<slv>   ATAPI CDroms can be jumpered to master or slave.
+		<slv>   ATAPI CDROMs can be jumpered to master or slave.
 			Set this to 0 to choose the master drive, 1 to
                         choose the slave, -1 (the default) to choose the
 			first drive found.
@@ -648,7 +648,7 @@
 
 	if (s) return -1;
 	if ((pcd_buffer[0] & 0x1f) != 5) {
-	  if (verbose) printk("%s: %s is not a CDrom\n",
+	  if (verbose) printk("%s: %s is not a CDROM\n",
 			PCD.name,PCD.drive?"Slave":"Master");
 	  return -1;
 	}
@@ -709,7 +709,7 @@
 
 	if (k) return 0;
 	
-	printk("%s: No CDrom drive found\n",name);
+	printk("%s: No CDROM drive found\n",name);
 	return -1;
 }
 
diff -u --recursive --new-file v2.1.112/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.112/linux/drivers/cdrom/cdrom.c	Wed Apr  1 20:11:48 1998
+++ linux/drivers/cdrom/cdrom.c	Wed Jul 29 12:37:06 1998
@@ -71,10 +71,19 @@
   of bytes not copied.  I was returning whatever non-zero stuff came back from 
   the copy_*_user functions directly, which would result in strange errors.
 
+2.13  July 17, 1998 -- Erik Andersen <andersee@debian.org>
+  -- Fixed a bug in CDROM_SELECT_SPEED where you couldn't lower the speed
+  of the drive.  Thanks to Tobias Ringstr|m <tori@prosolvia.se> for pointing
+  this out and providing a simple fix.
+  -- Fixed the procfs-unload-module bug with the fill_inode procfs callback.
+  thanks to Andrea Arcangeli <arcangeli@mbox.queen.it>
+  -- Fixed it so that the /proc entry now also shows up when cdrom is
+  compiled into the kernel.  Before it only worked when loaded as a module.
+
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 2.12"
-#define VERSION "Id: cdrom.c 2.12 1998/01/24 22:15:45 erik Exp"
+#define REVISION "Revision: 2.13"
+#define VERSION "Id: cdrom.c 2.13 1998/07/17 erik"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -104,14 +113,28 @@
 #include <linux/malloc.h> 
 #include <linux/cdrom.h>
 #include <linux/sysctl.h>
+#include <linux/proc_fs.h>
 #include <asm/fcntl.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 
+/* used to tell the module to turn on full debugging messages */
+static int debug = 0;
+/* default compatibility mode */
+static int autoclose=1;
+static int autoeject=0;
+static int lockdoor = 1;
+static int check_media_type = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM(autoclose, "i");
+MODULE_PARM(autoeject, "i");
+MODULE_PARM(lockdoor, "i");
+MODULE_PARM(check_media_type, "i");
 
 #if (ERRLOGMASK!=CD_NOTHING)
 #define cdinfo(type, fmt, args...) \
-	if (ERRLOGMASK & type) printk(KERN_INFO "cdrom: " fmt, ## args)
+        if ((ERRLOGMASK & type) || debug==1 ) \
+            printk(KERN_INFO "cdrom: " fmt, ## args)
 #else
 #define cdinfo(type, fmt, args...) 
 #endif
@@ -139,6 +162,7 @@
 			 struct cdrom_device_ops * cdo);
 static void sanitize_format(union cdrom_addr *addr, 
 		u_char * curr, u_char requested);
+static void cdrom_sysctl_register(void);
 typedef struct {
 	int data;
 	int audio;
@@ -176,6 +200,7 @@
 
 int register_cdrom(struct cdrom_device_info *cdi)
 {
+	static char banner_printed = 0;
 	int major = MAJOR (cdi->dev);
         struct cdrom_device_ops *cdo = cdi->ops;
         int *change_capability = (int *)&cdo->capability; /* hack */
@@ -184,6 +209,13 @@
 		return -1;
 	if (cdo->open == NULL || cdo->release == NULL)
 		return -2;
+	if ( !banner_printed ) {
+		printk(KERN_INFO "Uniform CDROM driver " REVISION "\n");
+		banner_printed = 1;
+#ifdef CONFIG_SYSCTL
+		cdrom_sysctl_register();
+#endif /* CONFIG_SYSCTL */ 
+	}
 	ENSURE(drive_status, CDC_DRIVE_STATUS );
 	ENSURE(media_changed, CDC_MEDIA_CHANGED);
 	ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
@@ -195,18 +227,17 @@
 	ENSURE(reset, CDC_RESET);
 	ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
 	ENSURE(dev_ioctl, CDC_IOCTLS);
-	cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK;
-					/* default compatibility mode */
 	cdi->mc_flags = 0;
 	cdo->n_minors = 0;
-
-	{
-	    static char banner_printed = 0;
-	    if ( !banner_printed ) {
-		printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n");
-		banner_printed = 1;
-	    }
-	}
+        cdi->options = CDO_USE_FFLAGS;
+	if (autoclose==1)
+		cdi->options |= (int) CDO_AUTO_CLOSE;
+	if (autoeject==1)
+		cdi->options |= (int) CDO_AUTO_EJECT;
+	if (lockdoor==1)
+		cdi->options |= (int) CDO_LOCK;
+	if (check_media_type==1)
+		cdi->options |= (int) CDO_CHECK_TYPE;
 
 	cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
 	cdi->next = topCdromPtr; 	
@@ -290,7 +321,7 @@
 	struct cdrom_device_ops *cdo = cdi->ops;
 	tracktype tracks;
 	cdinfo(CD_OPEN, "entering open_for_data\n");
-	/* Check if the driver can report drive status.  If it can we
+	/* Check if the driver can report drive status.  If it can, we
 	   can do clever things.  If it can't, well, we at least tried! */
 	if (cdo->drive_status != NULL) {
 		ret = cdo->drive_status(cdi, CDSL_CURRENT);
@@ -337,10 +368,15 @@
 	}
 	/* CD-Players which don't use O_NONBLOCK, workman
 	 * for example, need bit CDO_CHECK_TYPE cleared! */
-	if (cdi->options & CDO_CHECK_TYPE && tracks.data==0) {
-		cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 
-		ret=-EMEDIUMTYPE;
-		goto clean_up_and_return;
+	if (tracks.data==0) {
+		if (cdi->options & CDO_CHECK_TYPE) {
+		    cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 
+		    ret=-EMEDIUMTYPE;
+		    goto clean_up_and_return;
+		}
+		else {
+		    cdinfo(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set.\n");
+		}
 	}
 
 	cdinfo(CD_OPEN, "all seems well, opening the device.\n"); 
@@ -367,7 +403,7 @@
 	(notably ide-cd) lock the drive after every command.  This produced
 	a nasty bug where after mount failed, the drive would remain locked!  
 	This ensures that the drive gets unlocked after a mount fails.  This 
-	is a goto to avoid adding bloating the driver with redundant code. */ 
+	is a goto to avoid bloating the driver with redundant code. */ 
 clean_up_and_return:
 	cdinfo(CD_WARNING, "open failed.\n"); 
 	if (cdo->capability & ~cdi->mask & CDC_LOCK && 
@@ -379,8 +415,7 @@
 }
 
 /* This code is similar to that in open_for_data. The routine is called
-   in case a audio play operation is requested. It doesn't make much sense
-   to do this on a data disc.
+   whenever an audio play operation is requested.
 */
 int check_for_audio_disc(struct cdrom_device_info * cdi,
 			 struct cdrom_device_ops * cdo)
@@ -692,8 +727,6 @@
 		cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); 
 		if (!(cdo->capability & ~cdi->mask & CDC_SELECT_SPEED))
 			return -ENOSYS;
-		if ((int)arg > cdi->speed )
-			return -EINVAL;
 		return cdo->select_speed(cdi, arg);
 		}
 
@@ -1019,18 +1052,33 @@
 	{0}
 	};
 
-#endif /* endif CONFIG_SYSCTL */
-
-
-#ifdef MODULE
-
-#ifdef CONFIG_SYSCTL
-
 static struct ctl_table_header *cdrom_sysctl_header;
 
+/*
+ * This is called as the fill_inode function when an inode
+ * is going into (fill = 1) or out of service (fill = 0).
+ * We use it here to manage the module use counts.
+ *
+ * Note: only the top-level directory needs to do this; if
+ * a lower level is referenced, the parent will be as well.
+ */
+static void cdrom_procfs_modcount(struct inode *inode, int fill)
+{
+       if (fill)
+               MOD_INC_USE_COUNT;
+       else
+               MOD_DEC_USE_COUNT;
+}
+
 static void cdrom_sysctl_register(void)
 {
+	static int initialized = 0;
+
+	if ( initialized == 1 )
+		return;
 	cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 0);
+	cdrom_root_table->de->fill_inode = &cdrom_procfs_modcount;
+	initialized = 1;
 }
 
 static void cdrom_sysctl_unregister(void)
@@ -1038,6 +1086,8 @@
 	unregister_sysctl_table(cdrom_sysctl_header);
 }
 #endif /* endif CONFIG_SYSCTL */
+
+#ifdef MODULE
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.1.112/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c
--- v2.1.112/linux/drivers/cdrom/cdu31a.c	Thu Feb 12 20:56:05 1998
+++ linux/drivers/cdrom/cdu31a.c	Wed Jul 29 12:37:06 1998
@@ -5,6 +5,8 @@
 *
 * Colossians 3:17
 *
+*  See Documentation/cdrom/cdu31a for additional details about this driver.
+* 
 * The Sony interface device driver handles Sony interface CDROM
 * drives and provides a complete block-level interface as well as an
 * ioctl() interface compatible with the Sun (as specified in
@@ -106,69 +108,15 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * TODO: 
+ *       CDs with form1 and form2 sectors cause problems
+ *       with current read-ahead strategy.
  *
  * Credits:
  *    Heiko Eissfeldt <heiko@colossus.escape.de>
  *         For finding abug in the return of the track numbers.
- */
-/* conversion to Uniform cdrom layer.
-   TOC processing redone for proper multisession support.
-
-   TODO: 
-         CDs with form1 and form2 sectors cause problems
-         with current read-ahead strategy.
-   Heiko Eissfeldt Sep 97 */
-
-/*
+ *         TOC processing redone for proper multisession support.
  *
- * Setting up the Sony CDU31A/CDU33A drive interface card.  If
- * You have another card, you are on your own.
- * 
- *      +----------+-----------------+----------------------+
- *      |  JP1     |  34 Pin Conn    |                      |
- *      |  JP2     +-----------------+                      |
- *      |  JP3                                              |
- *      |  JP4                                              |
- *      |                                                   +--+
- *      |                                                   |  +-+
- *      |                                                   |  | |  External
- *      |                                                   |  | |  Connector
- *      |                                                   |  | |
- *      |                                                   |  +-+
- *      |                                                   +--+
- *      |                                                   |
- *      |                                          +--------+
- *      |                                          |
- *      +------------------------------------------+
- * 
- *    JP1 sets the Base Address, using the following settings:
- * 
- *      Address         Pin 1           Pin 2
- *      -------         -----           -----
- *      0x320           Short           Short
- *      0x330           Short           Open
- *      0x340           Open            Short
- *      0x360           Open            Open
- * 
- *    JP2 and JP3 configure the DMA channel; they must be set the same.
- * 
- *      DMA             Pin 1           Pin 2           Pin 3
- *      ---             -----           -----           -----
- *      1               On              Off             On
- *      2               Off             On              Off
- *      3               Off             Off             On
- * 
- *    JP4 Configures the IRQ:
- * 
- *      IRQ     Pin 1           Pin 2           Pin 3           Pin 4
- *      ---     -----           -----           -----           -----
- *      3       Off             Off             On              Off
- *      4       Off             Off*            Off             On
- *      5       On              Off             Off             Off
- *      6       Off             On              Off             Off
- * 
- *              * The documentation states to set this for interrupt
- *                4, but I think that is a mistake.
  *
  *  It probably a little late to be adding a history, but I guess I
  *  will start.
@@ -190,6 +138,10 @@
  *                     just dead code left over from the port.
  *                          Erik Andersen <andersee@debian.org>
  *
+ *  16 July 1998 -- Drive donated to Erik Andersen by John Kodis
+ *                   <kodis@jagunet.com>.  Work begun on fixing driver to
+ *                   work under 2.1.X.  Added temporary extra printks
+ *                   which seem to slow it down enough to work.
 */
 
 #include <linux/major.h>
@@ -257,6 +209,7 @@
 static int handle_sony_cd_attention(void);
 static int read_subcode(void);
 static void sony_get_toc(void);
+static int scd_spinup(void);
 /*static int scd_open(struct inode *inode, struct file *filp);*/
 static int scd_open(struct cdrom_device_info *, int);
 static void do_sony_cd_cmd(unsigned char cmd,
@@ -419,9 +372,10 @@
      /* we have no changer support */
      return -EINVAL;
   }
-
-  /*return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;*/
-  return sony_spun_up ? CDS_DISC_OK : CDS_TRAY_OPEN;
+  if (scd_spinup() == 0) {
+         sony_spun_up = 1;
+  }
+  return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;
 }
 
 static inline void
@@ -1680,7 +1634,6 @@
 #endif
 }
 
-static int scd_spinup(void);
 
 /*
  * The OS calls this to perform a read or write operation to the drive.
@@ -1984,8 +1937,11 @@
       session = 1;
       while (1)
       {
-#if DEBUG
-         printk("Trying session %d\n", session);
+/* This seems to slow things down enough to make it work.  This
+ * appears to be a problem in do_sony_cd_cmd.  This printk seems 
+ * to address the symptoms...  -Erik */
+#if 1
+         printk("cdu31a: Trying session %d\n", session);
 #endif
 	 parms[0] = session;
 	 do_sony_cd_cmd(SONY_READ_TOC_SPEC_CMD,
@@ -2001,6 +1957,8 @@
 	 if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
 	 {
 	    /* An error reading the TOC, this must be past the last session. */
+	     if (session == 1)
+		    printk("Yikes! Couldn't read any sessions!");
 	    break;
          }
 #if DEBUG
diff -u --recursive --new-file v2.1.112/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.112/linux/drivers/char/Makefile	Sun Jul 26 11:57:15 1998
+++ linux/drivers/char/Makefile	Thu Jul 30 11:17:11 1998
@@ -246,6 +246,16 @@
   endif
 endif
 
+ifeq ($(CONFIG_MACMOUSE),y)
+M = y
+L_OBJS += macmouse.o
+else
+  ifeq ($(CONFIG_MACMOUSE),m)
+    M_OBJS += macmouse.o
+    MM = m
+  endif
+endif
+
 ifdef CONFIG_SUN_MOUSE
 M = y
 endif
diff -u --recursive --new-file v2.1.112/linux/drivers/char/amikeyb.c linux/drivers/char/amikeyb.c
--- v2.1.112/linux/drivers/char/amikeyb.c	Thu Mar 26 15:57:02 1998
+++ linux/drivers/char/amikeyb.c	Thu Jul 30 11:17:11 1998
@@ -301,13 +301,13 @@
         return -EIO;
 
     /* setup key map */
-    memcpy(plain_map, amiplain_map, sizeof(plain_map));
-    memcpy(shift_map, amishift_map, sizeof(shift_map));
-    memcpy(altgr_map, amialtgr_map, sizeof(altgr_map));
-    memcpy(ctrl_map, amictrl_map, sizeof(ctrl_map));
-    memcpy(shift_ctrl_map, amishift_ctrl_map, sizeof(shift_ctrl_map));
-    memcpy(alt_map, amialt_map, sizeof(alt_map));
-    memcpy(ctrl_alt_map, amictrl_alt_map, sizeof(ctrl_alt_map));
+    memcpy(key_maps[0], amiplain_map, sizeof(plain_map));
+    memcpy(key_maps[1], amishift_map, sizeof(plain_map));
+    memcpy(key_maps[2], amialtgr_map, sizeof(plain_map));
+    memcpy(key_maps[4], amictrl_map, sizeof(plain_map));
+    memcpy(key_maps[5], amishift_ctrl_map, sizeof(plain_map));
+    memcpy(key_maps[8], amialt_map, sizeof(plain_map));
+    memcpy(key_maps[12], amictrl_alt_map, sizeof(plain_map));
 
     /*
      * Initialize serial data direction.
@@ -340,4 +340,9 @@
     k->rate  = key_repeat_rate  * 1000 / HZ;
     
     return( 0 );
+}
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void amiga_kbd_reset_setup(char *str, int *ints))
+{
 }
diff -u --recursive --new-file v2.1.112/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c
--- v2.1.112/linux/drivers/char/atarimouse.c	Tue Mar 10 10:03:31 1998
+++ linux/drivers/char/atarimouse.c	Thu Jul 30 11:17:11 1998
@@ -21,10 +21,10 @@
 #include <linux/random.h>
 #include <linux/poll.h>
 #include <linux/init.h>
+#include <linux/busmouse.h>
 
 #include <asm/setup.h>
 #include <asm/atarikb.h>
-#include <asm/atari_mouse.h>
 #include <asm/uaccess.h>
 
 static struct mouse_status mouse;
@@ -160,15 +160,21 @@
 
 __initfunc(int atari_mouse_init(void))
 {
-    mouse.active = 0;
-    mouse.ready = 0;
-    mouse.wait = NULL;
+	int r;
 
-    if (!MACH_IS_ATARI)
-	return -ENODEV;
-    printk(KERN_INFO "Atari mouse installed.\n");
-    misc_register(&atari_mouse);
-    return 0;
+	if (!MACH_IS_ATARI)
+		return -ENODEV;
+
+	mouse.active = 0;
+	mouse.ready = 0;
+	mouse.wait = NULL;
+
+	r = misc_register(&atari_mouse);
+	if (r)
+		return r;
+
+	printk(KERN_INFO "Atari mouse installed.\n");
+	return 0;
 }
 
 
@@ -201,8 +207,6 @@
 }
 
 #ifdef MODULE
-#include <asm/setup.h>
-
 int init_module(void)
 {
 	return atari_mouse_init();
diff -u --recursive --new-file v2.1.112/linux/drivers/char/dn_keyb.c linux/drivers/char/dn_keyb.c
--- v2.1.112/linux/drivers/char/dn_keyb.c	Thu Mar 26 15:57:02 1998
+++ linux/drivers/char/dn_keyb.c	Thu Jul 30 11:17:11 1998
@@ -573,13 +573,13 @@
 
 /*  printk("dn_keyb_init\n"); */
 
-  memcpy(plain_map, dnplain_map, sizeof(plain_map));
-  memcpy(shift_map, dnshift_map, sizeof(shift_map));
-  memcpy(altgr_map, dnaltgr_map, sizeof(altgr_map));
-  memcpy(ctrl_map, dnctrl_map, sizeof(ctrl_map));
-  memcpy(shift_ctrl_map, dnshift_ctrl_map, sizeof(shift_ctrl_map));
-  memcpy(alt_map, dnalt_map, sizeof(alt_map));
-  memcpy(ctrl_alt_map, dnctrl_alt_map, sizeof(ctrl_alt_map));
+  memcpy(key_maps[0], dnplain_map, sizeof(plain_map));
+  memcpy(key_maps[1], dnshift_map, sizeof(plain_map));
+  memcpy(key_maps[2], dnaltgr_map, sizeof(plain_map));
+  memcpy(key_maps[4], dnctrl_map, sizeof(plain_map));
+  memcpy(key_maps[5], dnshift_ctrl_map, sizeof(plain_map));
+  memcpy(key_maps[8], dnalt_map, sizeof(plain_map));
+  memcpy(key_maps[12], dnctrl_alt_map, sizeof(plain_map));
 
   mouse_dx=0; 
   mouse_dy=0; 
diff -u --recursive --new-file v2.1.112/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c
--- v2.1.112/linux/drivers/char/dsp56k.c	Mon Feb 23 18:12:04 1998
+++ linux/drivers/char/dsp56k.c	Thu Jul 30 11:17:11 1998
@@ -401,9 +401,7 @@
 			if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
 			if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
 
-			if(put_user(status, &hf->status) < 0)
-				return -EFAULT;
-			break;
+			return put_user(status, &hf->status);
 		}
 		case DSP56K_HOST_CMD:
 			if (arg > 31 || arg < 0)
@@ -427,27 +425,19 @@
  * Do I need this function at all???
  */
 #if 0
-static int dsp56k_select(struct inode *inode, struct file *file, int sel_type,
-			 select_table *wait)
+static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
 {
-	int dev = MINOR(inode->i_rdev) & 0x0f;
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev) & 0x0f;
 
 	switch(dev)
 	{
 	case DSP56K_DEV_56001:
-
-		switch(sel_type) {
-		case SEL_IN:		/* read */
-			return 1;
-		case SEL_OUT:		/* write */
-			return 1;
-		default:
-			return 1;
-		}
+		/* poll_wait(file, ???, wait); */
+		return POLLIN | POLLRDNORM | POLLOUT;
 
 	default:
 		printk("DSP56k driver: Unknown minor device: %d\n", dev);
-		return -ENXIO;
+		return 0;
 	}
 }
 #endif
@@ -530,22 +520,17 @@
 
 /****** Init and module functions ******/
 
-static int init_error = 0;
-
-__initfunc(void dsp56k_init(void))
+__initfunc(int dsp56k_init(void))
 {
-	if(!ATARIHW_PRESENT(DSP56K)) {
-		init_error = 1;
+	if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
 		printk("DSP56k driver: Hardware not present\n");
-		return;
+		return -ENODEV;
 	}
 
-#ifndef MODULE
 	if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
 		printk("DSP56k driver: Unable to register driver\n");
-		return;
+		return -ENODEV;
 	}
-#endif /* !MODULE */
 
 	dsp56k.in_use = 0;
 
@@ -555,20 +540,7 @@
 #ifdef MODULE
 int init_module(void)
 {
-	int r;
-
-	init_error = 0;
-	dsp56k_init();
-	if(init_error)
-		return -EPERM;
-
-	r = register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops);
-	if(r) {
-		printk("DSP56k driver: Unable to register driver\n");
-		return r;
-	}
-	
-	return 0;
+	return dsp56k_init();
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v2.1.112/linux/drivers/char/lp_intern.c linux/drivers/char/lp_intern.c
--- v2.1.112/linux/drivers/char/lp_intern.c	Tue Jun 23 10:01:22 1998
+++ linux/drivers/char/lp_intern.c	Thu Jul 30 11:17:12 1998
@@ -32,6 +32,12 @@
 #include <asm/atarihw.h>
 #include <asm/atariints.h>
 #endif
+#ifdef CONFIG_MVME16x
+#include <asm/mvme16xhw.h>
+#endif
+#ifdef CONFIG_BVME6000
+#include<asm/bvme6000hw.h>
+#endif
 #include <linux/lp_intern.h>
 
 static int minor = -1;
@@ -71,6 +77,25 @@
 	 break;
        }
 #endif
+#ifdef CONFIG_MVME16x
+    case MACH_MVME16x:
+      {
+	int wait = 0;
+	while (wait != lp_table[dev]->wait) wait++;
+        mvmelp.data = c;
+        break;
+      }
+#endif
+#ifdef CONFIG_BVME6000
+    case MACH_BVME6000:
+      {
+	int wait = 0;
+	while (wait != lp_table[dev]->wait) wait++;
+        bvmepit.padr = c;
+        bvmepit.pacr |= 0x02;
+        break;
+      }
+#endif
     }
 }
 
@@ -87,6 +112,14 @@
     case MACH_ATARI:
       return mfp.par_dt_reg & 1;
 #endif
+#ifdef CONFIG_MVME16x
+    case MACH_MVME16x:
+      return mvmelp.isr & 1;
+#endif
+#ifdef CONFIG_BVME6000
+    case MACH_BVME6000:
+      return 0 /* !(bvmepit.psr & 0x40) */ ;
+#endif
     default:
       return 0;
     }
@@ -103,6 +136,15 @@
 #endif
 #ifdef CONFIG_ATARI
     case MACH_ATARI:
+      return 0;
+#endif
+#ifdef CONFIG_MVME16x
+    case MACH_MVME16x:
+      return mvmelp.isr & 2;
+#endif
+#ifdef CONFIG_BVME6000
+    case MACH_BVME6000:
+      return 0;
 #endif
     default:
       return 0;
@@ -122,6 +164,14 @@
     case MACH_ATARI:
       return !(mfp.par_dt_reg & 1);
 #endif
+#ifdef CONFIG_MVME16x
+    case MACH_MVME16x:
+      return mvmelp.isr & 4;
+#endif
+#ifdef CONFIG_BVME6000
+    case MACH_BVME6000:
+      return 1;
+#endif
     default:
       return 0;
     }
@@ -129,6 +179,14 @@
 
 static void lp_int_interrupt(int irq, void *data, struct pt_regs *fp)
 {
+#ifdef CONFIG_MVME16x
+  if (MACH_IS_MVME16x)
+    mvmelp.ack_icr |= 0x08;
+#endif
+#ifdef CONFIG_BVME6000
+  if (MACH_IS_BVME6000)
+    bvmepit.pacr &= ~0x02;
+#endif
   lp_interrupt(minor);
 }
 
@@ -193,6 +251,62 @@
       tab.type = LP_ATARI;
     }
 #endif
+#ifdef CONFIG_MAC
+    if (MACH_IS_MAC)
+    	return -ENODEV;
+#endif
+#ifdef CONFIG_MVME16x
+    if (MACH_IS_MVME16x)
+    {
+      unsigned long flags;
+
+      if (!(mvme16x_config & MVME16x_CONFIG_GOT_LP))
+        return -ENODEV;
+
+      save_flags(flags);
+      cli();
+      mvmelp.ack_icr = 0x08;
+      mvmelp.flt_icr = 0x08;
+      mvmelp.sel_icr = 0x08;
+      mvmelp.pe_icr =  0x08;
+      mvmelp.bsy_icr = 0x08;
+      mvmelp.cr =      0x10;
+      mvmelp.ack_icr = 0xd9; /* Int on trailing edge of ACK */
+      restore_flags(flags);
+
+      if (lp_irq)
+        tab.irq = request_irq(MVME167_IRQ_PRN, lp_int_interrupt,
+          0, "builtin printer port", lp_int_interrupt);
+      tab.base = (void *)&mvmelp; /* dummy, not used */
+      tab.type = LP_MVME167;
+    }
+#endif
+#ifdef CONFIG_BVME6000
+    if (MACH_IS_BVME6000)
+    {
+      unsigned long flags;
+
+      save_flags(flags);
+      cli();
+      bvmepit.pgcr =   0x0f;
+      bvmepit.psrr =   0x18;
+      bvmepit.paddr =  0xff;
+      bvmepit.pcdr  =  (bvmepit.pcdr & 0xfc) | 0x02;
+      bvmepit.pcddr |= 0x03;
+      bvmepit.pacr =   0x78;
+      bvmepit.pbcr =   0x00;
+      bvmepit.pivr =   BVME_IRQ_PRN;
+      bvmepit.pgcr =   0x1f;
+      restore_flags(flags);
+
+      if (lp_irq)
+        tab.irq = request_irq(BVME_IRQ_PRN, lp_int_interrupt,
+          0, "builtin printer port", lp_int_interrupt);
+      tab.base = (void *)&bvmepit; /* dummy, not used */
+      tab.type = LP_BVME6000;
+    }
+#endif
+
 
   if ((minor = register_parallel(&tab, minor)) < 0) {
     printk("builtin lp init: cant get a minor\n");
@@ -205,6 +319,14 @@
       if (MACH_IS_ATARI)
 	free_irq(IRQ_MFP_BUSY, lp_int_interrupt);
 #endif
+#ifdef CONFIG_MVME16x
+      if (MACH_IS_MVME16x)
+        free_irq(MVME167_IRQ_PRN, lp_int_interrupt);
+#endif
+#ifdef CONFIG_BVME6000
+      if (MACH_IS_BVME6000)
+        free_irq(BVME_IRQ_PRN, lp_int_interrupt);
+#endif
     }
     return -ENODEV;
   }
@@ -228,6 +350,14 @@
 #ifdef CONFIG_ATARI
   if (MACH_IS_ATARI)
     free_irq(IRQ_MFP_BUSY, lp_int_interrupt);
+#endif
+#ifdef CONFIG_MVME16x
+  if (MACH_IS_MVME16x)
+    free_irq(MVME167_IRQ_PRN, lp_int_interrupt);
+#endif
+#ifdef CONFIG_BVME6000
+  if (MACH_IS_BVME6000)
+    free_irq(BVME_IRQ_PRN, lp_int_interrupt);
 #endif
 }
 unregister_parallel(minor);
diff -u --recursive --new-file v2.1.112/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c
--- v2.1.112/linux/drivers/char/lp_m68k.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/char/lp_m68k.c	Thu Jul 30 11:17:12 1998
@@ -173,13 +173,14 @@
 }
 
 #if WHICH_DRIVER == FORCE_INTERRUPT
-static long lp_write(struct inode *inode, struct file *file,
-		    const char *buf, unsigned long count)
+static ssize_t lp_write(struct file *file, const char *buf,
+			size_t count, loff_t *ppos)
 #else
-static long lp_write_interrupt(struct inode *inode, struct file *file,
-			      const char *buf, unsigned long count)
+static ssize_t lp_write_interrupt(struct file *file, const char *buf,
+				  size_t count, loff_t *ppos)
 #endif
 {
+  struct inode *inode = file->f_dentry->d_inode;
   unsigned long total_bytes_written = 0;
   unsigned int flags;
   int rc;
@@ -190,7 +191,9 @@
     lp_table[dev]->bytes_written = 0;	/* init buffer read-pointer */
     lp_error = 0;
     lp_table[dev]->copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
-    copy_from_user(lp_table[dev]->lp_buffer, buf, lp_table[dev]->copy_size);
+    if (copy_from_user(lp_table[dev]->lp_buffer, buf,
+		       lp_table[dev]->copy_size))
+      return -EFAULT;
     while (lp_table[dev]->copy_size) {
       save_flags(flags);
       cli();				/* no interrupts now */
@@ -223,10 +226,9 @@
       rc = total_bytes_written + lp_table[dev]->bytes_written;
 
       if (signal_pending(current)) {
-	if (rc)
-	  return rc;
-	else
-	  return -EINTR;
+	if (rc == 0)
+	  rc = -EINTR;
+	return rc;
       }
       if (lp_error) {
 
@@ -267,13 +269,14 @@
 
 #if WHICH_DRIVER != FORCE_INTERRUPT
 #if WHICH_DRIVER == FORCE_POLLING
-static long lp_write(struct inode *inode, struct file *file,
-		    const char *buf, unsigned long count)
+static ssize_t lp_write(struct file *file, const char *buf,
+			size_t count, loff_t *ppos)
 #else
-static long lp_write_polled(struct inode *inode, struct file *file,
-			   const char *buf, unsigned long count)
+static ssize_t lp_write_polled(struct file *file, const char *buf,
+			size_t count, loff_t *ppos)
 #endif
 {
+	struct inode *inode = file->f_dentry->d_inode;
 	char *temp = buf;
 	int dev = MINOR(inode->i_rdev);
 
@@ -287,52 +290,53 @@
 
 	temp = buf;
 	while (count > 0) {
-		if (lp_char_polled(get_user(temp), dev)) {
+		int c;
+		if (get_user(c, temp))
+			return -EFAULT;
+		if (lp_char_polled(c, dev)) {
 			/* only update counting vars if character was printed */
 			count--; temp++;
 #ifdef LP_DEBUG
 			lp_total_chars++;
 #endif
 		} else { /* if printer timed out */
+			unsigned long timeout = LP_TIMEOUT_POLLED;
+			int error = 0;
 			if (lp_table[dev]->lp_has_pout(dev)) {
 				printk(KERN_NOTICE "lp%d: out of paper\n",dev);
 				if (lp_table[dev]->flags & LP_ABORT)
-					return temp - buf ? temp-buf : -ENOSPC;
-				current->state = TASK_INTERRUPTIBLE;
-				current->timeout = jiffies + LP_TIMEOUT_POLLED;
-				schedule();
+					error = -ENOSPC;
 			} else if (!lp_table[dev]->lp_is_online(dev)) {
 				printk(KERN_NOTICE "lp%d: off-line\n",dev);
 				if (lp_table[dev]->flags & LP_ABORT)
-					return temp - buf ? temp-buf : -EIO;
-				current->state = TASK_INTERRUPTIBLE;
-				current->timeout = jiffies + LP_TIMEOUT_POLLED;
-				schedule();
+					error = -EIO;
 			} else
 	                /* not offline or out of paper. on fire? */
 			if (lp_table[dev]->lp_is_busy(dev)) {
 				printk(KERN_NOTICE "lp%d: on fire\n",dev);
 				if (lp_table[dev]->flags & LP_ABORT)
-					return temp - buf ? temp-buf : -EFAULT;
-				current->state = TASK_INTERRUPTIBLE;
-				current->timeout = jiffies + LP_TIMEOUT_POLLED;
-				schedule();
+					error = -EIO;
 			}
+			else
+				timeout = lp_table[dev]->time;
 
 			/* check for signals before going to sleep */
-			if (signal_pending(current)) {
+			if (error == 0 && signal_pending(current))
+				error = -EINTR;
+			if (error) {
 				if (temp != buf)
 					return temp-buf;
 				else
-					return -EINTR;
+					return error;
 			}
+
 #ifdef LP_DEBUG
 			printk("lp sleeping at %d characters for %d jiffies\n",
-				lp_total_chars, lp_table[dev]->time);
+				lp_total_chars, timeout);
 			lp_total_chars = 0;
 #endif
 			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + lp_table[dev]->time;
+			current->timeout = jiffies + timeout;
 			schedule();
 		}
 	}
@@ -343,13 +347,13 @@
 unsigned int lp_irq = 0;
 
 #if WHICH_DRIVER == PREFER_INTERRUPT
-static long lp_write(struct inode *inode, struct file *file,
-		    const char *buf, unsigned long count)
+static ssize_t lp_write(struct file *file, const char *buf, size_t count,
+			loff_t *ppos)
 {
 	if (lp_irq)
-		return lp_write_interrupt(inode, file, buf, count);
+		return lp_write_interrupt(file, buf, count, ppos);
 	else
-		return lp_write_polled(inode, file, buf, count);
+		return lp_write_polled(file, buf, count, ppos);
 }
 #endif
 
@@ -363,8 +367,12 @@
 	int dev = MINOR(inode->i_rdev);
 	int ret;
 
+	MOD_INC_USE_COUNT;
+
+	ret = -ENODEV;
 	if (dev >= MAX_LP)
-		return -ENODEV;
+		goto out_err;
+
 #ifdef CONFIG_KMOD
 	if (!lp_table[dev]) {
 		char modname[30];
@@ -374,22 +382,25 @@
 	}
 #endif
 	if (!lp_table[dev])
-		return -ENODEV;
+		goto out_err;
 	if (!(lp_table[dev]->flags & LP_EXIST))
-		return -ENODEV;
+		goto out_err;
+	ret = -EBUSY;
 	if (lp_table[dev]->flags & LP_BUSY)
-		return -EBUSY;
+		goto out_err;
 
 	lp_table[dev]->flags |= LP_BUSY;
 
 	ret = lp_table[dev]->lp_open(dev);
 	if (ret != 0) {
 		lp_table[dev]->flags &= ~LP_BUSY;
-	}
-	else {
-		MOD_INC_USE_COUNT;
+		goto out_err;
 	}
 	return ret;
+
+out_err:
+	MOD_DEC_USE_COUNT;
+	return ret;
 }
 
 static int lp_release(struct inode *inode, struct file *file)
@@ -407,15 +418,16 @@
 		    unsigned int cmd, unsigned long arg)
 {
 	unsigned int minor = MINOR(inode->i_rdev);
-	int retval = 0;
+	int retval = -ENODEV;
 
 #ifdef LP_DEBUG
 	printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
 #endif
 	if (minor >= max_lp)
-		return -ENODEV;
+		goto out;
 	if (!(lp_table[minor]->flags & LP_EXIST))
-		return -ENODEV;
+		goto out;
+	retval = 0;
 	switch (cmd) {
 	case LPTIME:
 		lp_table[minor]->time = arg;
@@ -437,11 +449,11 @@
 	        retval = lp_irq;
 		break;
 	default:
+		retval = -EINVAL;
 		if (lp_table[minor]->lp_ioctl)
 			retval = lp_table[minor]->lp_ioctl(minor, cmd, arg);
-		else
-			retval = -EINVAL;
 	}
+out:
 	return retval;
 }
 
diff -u --recursive --new-file v2.1.112/linux/drivers/char/macmouse.c linux/drivers/char/macmouse.c
--- v2.1.112/linux/drivers/char/macmouse.c	Thu Mar 26 15:57:03 1998
+++ linux/drivers/char/macmouse.c	Thu Jul 30 11:17:12 1998
@@ -227,7 +227,7 @@
 
 static unsigned int mouse_poll(struct file *file, poll_table *wait)
 {
-	poll_wait(&mouse.wait, wait);
+	poll_wait(file, &mouse.wait, wait);
 	if (mouse.ready)
 		return POLLIN | POLLRDNORM;
 	return 0;
diff -u --recursive --new-file v2.1.112/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.112/linux/drivers/char/mem.c	Tue Jul 21 00:15:31 1998
+++ linux/drivers/char/mem.c	Thu Jul 30 11:17:12 1998
@@ -546,7 +546,7 @@
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
     defined (CONFIG_AMIGAMOUSE) || defined (CONFIG_ATARIMOUSE) || \
-    defined (CONFIG_PCWATCHDOG) || \
+    defined (CONFIG_MACMOUSE) || defined (CONFIG_PCWATCHDOG) || \
     defined (CONFIG_APM) || defined (CONFIG_RTC) || \
     defined (CONFIG_SUN_MOUSE) || defined (CONFIG_NVRAM)
 	misc_init();
diff -u --recursive --new-file v2.1.112/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.112/linux/drivers/char/misc.c	Tue Jun 23 10:01:22 1998
+++ linux/drivers/char/misc.c	Thu Jul 30 11:17:12 1998
@@ -65,12 +65,14 @@
 static unsigned char misc_minors[DYNAMIC_MINORS / 8];
 
 #ifndef MODULE
+extern int adbdev_init(void);
 extern int bus_mouse_init(void);
 extern int psaux_init(void);
 extern int ms_bus_mouse_init(void);
 extern int atixl_busmouse_init(void);
 extern int amiga_mouse_init(void);
 extern int atari_mouse_init(void);
+extern int mac_mouse_init(void);
 extern int sun_mouse_init(void);
 extern int adb_mouse_init(void);
 extern void watchdog_init(void);
@@ -203,6 +205,9 @@
 	if (proc_misc)
 		proc_misc->read_proc = misc_read_proc;
 #endif /* PROC_FS */
+#ifdef CONFIG_MAC
+	adbdev_init();
+#endif
 #ifdef CONFIG_BUSMOUSE
 	bus_mouse_init();
 #endif
@@ -220,6 +225,9 @@
 #endif
 #ifdef CONFIG_ATARIMOUSE
 	atari_mouse_init();
+#endif
+#ifdef CONFIG_MACMOUSE
+	mac_mouse_init();
 #endif
 #ifdef CONFIG_SUN_MOUSE
 	sun_mouse_init();
diff -u --recursive --new-file v2.1.112/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.1.112/linux/drivers/char/n_tty.c	Tue Mar 17 22:18:14 1998
+++ linux/drivers/char/n_tty.c	Fri Jul 31 16:24:44 1998
@@ -190,7 +190,7 @@
  * opost_block --- to speed up block console writes, among other
  * things.
  */
-static int opost_block(struct tty_struct * tty,
+static ssize_t opost_block(struct tty_struct * tty,
 		       const unsigned char * inbuf, unsigned int nr)
 {
 	char	buf[80];
@@ -863,9 +863,9 @@
 static ssize_t read_chan(struct tty_struct *tty, struct file *file,
 			 unsigned char *buf, size_t nr)
 {
+	unsigned char *b = buf;
 	struct wait_queue wait = { current, NULL };
 	int c;
-	unsigned char *b = buf;
 	int minimum, time;
 	ssize_t retval = 0;
 	ssize_t size;
@@ -896,25 +896,23 @@
 		}
 	}
 
-	if (tty->icanon) {
-		minimum = time = 0;
-		current->timeout = (unsigned long) -1;
-	} else {
+	minimum = time = 0;
+	current->timeout = (unsigned long) -1;
+	if (!tty->icanon) {
 		time = (HZ / 10) * TIME_CHAR(tty);
 		minimum = MIN_CHAR(tty);
 		if (minimum) {
-		  	current->timeout = (unsigned long) -1;
 			if (time)
 				tty->minimum_to_wake = 1;
 			else if (!waitqueue_active(&tty->read_wait) ||
 				 (tty->minimum_to_wake > minimum))
 				tty->minimum_to_wake = minimum;
 		} else {
+			current->timeout = 0;
 			if (time) {
 				current->timeout = time + jiffies;
 				time = 0;
-			} else
-				current->timeout = 0;
+			}
 			tty->minimum_to_wake = minimum = 1;
 		}
 	}
@@ -922,10 +920,10 @@
 	add_wait_queue(&tty->read_wait, &wait);
 
 	disable_bh(TQUEUE_BH);
-	while (1) {
+	while (nr) {
 		/* First test for status change. */
 		if (tty->packet && tty->link->ctrl_status) {
-			if (b != buf || !nr)
+			if (b != buf)
 				break;
 			put_user(tty->link->ctrl_status, b++);
 			nr--;
@@ -966,7 +964,7 @@
 		current->state = TASK_RUNNING;
 
 		/* Deal with packet mode. */
-		if (tty->packet && b == buf && nr) {
+		if (tty->packet && b == buf) {
 			put_user(TIOCPKT_DATA, b++);
 			nr--;
 		}
@@ -1013,7 +1011,7 @@
 		if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
 			check_unthrottle(tty);
 
-		if (b - buf >= minimum || !nr)
+		if (b - buf >= minimum)
 			break;
 		if (time)
 			current->timeout = time + jiffies;
@@ -1027,25 +1025,27 @@
 	current->state = TASK_RUNNING;
 	current->timeout = 0;
 	size = b - buf;
-	if (size && nr)
-	        clear_bit(TTY_PUSH, &tty->flags);
-        if (!size && test_and_clear_bit(TTY_PUSH, &tty->flags))
-                goto do_it_again;
-	if (!size && !retval)
-	        clear_bit(TTY_PUSH, &tty->flags);
-	return (size ? size : retval);
+	if (size) {
+		retval = size;
+		if (nr)
+	       		clear_bit(TTY_PUSH, &tty->flags);
+	} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
+		 goto do_it_again;
+
+	return retval;
 }
 
 static ssize_t write_chan(struct tty_struct * tty, struct file * file,
 			  const unsigned char * buf, size_t nr)
 {
+	const unsigned char *b = buf;
 	struct wait_queue wait = { current, NULL };
 	int c;
-	const unsigned char *b = buf;
-	ssize_t retval = 0, num;
+	ssize_t retval = 0;
 
 	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-	if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
+	if (L_TOSTOP(tty) && 
+	    file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
 	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
 		retval = tty_check_change(tty);
 		if (retval)
@@ -1065,7 +1065,11 @@
 		}
 		if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
 			while (nr > 0) {
-				num = opost_block(tty, b, nr);
+				ssize_t num = opost_block(tty, b, nr);
+				if (num < 0) {
+					retval = num;
+					goto break_out;
+				}
 				b += num;
 				nr -= num;
 				if (nr == 0)
@@ -1081,7 +1085,7 @@
 			c = tty->driver.write(tty, 1, b, nr);
 			if (c < 0) {
 				retval = c;
-				break;
+				goto break_out;
 			}
 			b += c;
 			nr -= c;
@@ -1094,6 +1098,7 @@
 		}
 		schedule();
 	}
+break_out:
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&tty->write_wait, &wait);
 	return (b - buf) ? b - buf : retval;
diff -u --recursive --new-file v2.1.112/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v2.1.112/linux/drivers/char/vc_screen.c	Tue Jul 28 14:21:08 1998
+++ linux/drivers/char/vc_screen.c	Fri Jul 31 23:19:40 1998
@@ -21,8 +21,6 @@
  *	 - making it shorter - scr_readw are macros which expand in PRETTY long code
  */
 
-#include <linux/config.h>
-
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.112/linux/drivers/net/Config.in	Tue Jul 28 14:21:08 1998
+++ linux/drivers/net/Config.in	Thu Jul 30 11:17:12 1998
@@ -35,7 +35,7 @@
     bool 'MACE (Power Mac ethernet) support' CONFIG_MACE
     bool 'BMAC (G3 ethernet) support' CONFIG_BMAC
   fi
-  if [ "$CONFIG_APUS" = "y" ]; then
+  if [ "$CONFIG_ZORRO" = "y" ]; then
     tristate 'Ariadne support' CONFIG_ARIADNE
     tristate 'A2065 support' CONFIG_A2065
     tristate 'Hydra support' CONFIG_HYDRA
diff -u --recursive --new-file v2.1.112/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.1.112/linux/drivers/net/Makefile	Tue Jul 28 14:21:08 1998
+++ linux/drivers/net/Makefile	Thu Jul 30 11:17:12 1998
@@ -79,6 +79,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_DAYNAPORT), y)
+L_OBJS += daynaport.o
+CONFIG_8390_BUILTIN = y
+endif
+
+ifeq ($(CONFIG_APNE),y)
+L_OBJS += apne.o
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_APNE),m)
+  M_OBJS += apne.o
+  CONFIG_8390_MODULE = y
+  endif
+endif
+
+
 ifeq ($(CONFIG_SHAPER),y)
 L_OBJS += shaper.o
 else
diff -u --recursive --new-file v2.1.112/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.1.112/linux/drivers/net/Space.c	Tue Jul 28 14:21:08 1998
+++ linux/drivers/net/Space.c	Thu Jul 30 11:17:12 1998
@@ -91,6 +91,7 @@
 extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
 extern int hydra_probe(struct device *);
+extern int apne_probe(struct device *);
 extern int bionet_probe(struct device *);
 extern int pamsnet_probe(struct device *);
 extern int tlan_probe(struct device *);
@@ -365,6 +366,9 @@
 #endif
 #ifdef CONFIG_HYDRA		/* Hydra Systems Amiganet Ethernet board */
 	{hydra_probe, 0},
+#endif
+#ifdef CONFIG_APNE		/* A1200 PCMCIA NE2000 */
+	{apne_probe, 0},
 #endif
 #ifdef CONFIG_ATARI_BIONET	/* Atari Bionet Ethernet board */
 	{bionet_probe, 0},
diff -u --recursive --new-file v2.1.112/linux/drivers/net/apne.c linux/drivers/net/apne.c
--- v2.1.112/linux/drivers/net/apne.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/apne.c	Thu Jul 30 11:17:12 1998
@@ -0,0 +1,634 @@
+/*
+ * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200
+ *
+ * (C) Copyright 1997 Alain Malek
+ *                    (Alain.Malek@cryogen.com)
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is based on
+ *
+ * ne.c:       A general non-shared-memory NS8390 ethernet driver for linux
+ *             Written 1992-94 by Donald Becker.
+ *
+ * 8390.c:     A general NS8390 ethernet driver core for linux.
+ *             Written 1992-94 by Donald Becker.
+ *
+ * cnetdevice: A Sana-II ethernet driver for AmigaOS
+ *             Written by Bruce Abbott (bhabbott@inhb.co.nz)
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of the Linux
+ * distribution for more details.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/setup.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/amigayle.h>
+#include <asm/amipcmcia.h>
+
+#include "8390.h"
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE	 (dev->base_addr)
+#define NE_CMD	 		0x00
+#define NE_DATAPORT		0x10            /* NatSemi-defined port window offset. */
+#define NE_RESET		0x1f+GAYLE_ODD  /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT	0x20
+
+#define NE_EN0_ISR		0x07+GAYLE_ODD
+#define NE_EN0_DCFG		0x0e
+
+#define NE_EN0_RSARLO	0x08
+#define NE_EN0_RSARHI	0x09+GAYLE_ODD
+#define NE_EN0_RCNTLO	0x0a
+#define NE_EN0_RXCR		0x0c
+#define NE_EN0_TXCR		0x0d+GAYLE_ODD
+#define NE_EN0_RCNTHI	0x0b+GAYLE_ODD
+#define NE_EN0_IMR		0x0f+GAYLE_ODD
+
+#define NE1SM_START_PG	0x20	/* First page of TX buffer */
+#define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
+#define NESM_START_PG	0x40	/* First page of TX buffer */
+#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+
+int apne_probe(struct device *dev);
+static int apne_probe1(struct device *dev, int ioaddr);
+
+static int apne_open(struct device *dev);
+static int apne_close(struct device *dev);
+
+static void apne_reset_8390(struct device *dev);
+static void apne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+			  int ring_page);
+static void apne_block_input(struct device *dev, int count,
+								struct sk_buff *skb, int ring_offset);
+static void apne_block_output(struct device *dev, const int count,
+							const unsigned char *buf, const int start_page);
+static void apne_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static int init_pcmcia(void);
+
+/* IO base address used for nic */
+
+#define IOBASE 0x300
+
+/*
+   use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand
+   you can find the values to use by looking at the cnet.device
+   config file example (the default values are for the CNET40BC card)
+*/
+
+/*
+#define MANUAL_CONFIG 0x20
+#define MANUAL_OFFSET 0x3f8
+
+#define MANUAL_HWADDR0 0x00
+#define MANUAL_HWADDR1 0x12
+#define MANUAL_HWADDR2 0x34
+#define MANUAL_HWADDR3 0x56
+#define MANUAL_HWADDR4 0x78
+#define MANUAL_HWADDR5 0x9a
+*/
+
+#define WORDSWAP(a) ( (((a)>>8)&0xff) | ((a)<<8) )
+
+
+static const char *version =
+    "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
+
+
+__initfunc(int apne_probe(struct device *dev))
+{
+#ifndef MANUAL_CONFIG
+	char tuple[8];
+#endif
+        
+	if ( !(AMIGAHW_PRESENT(PCMCIA)) )
+		return (ENODEV);
+                                
+	printk("Looking for PCMCIA ethernet card : ");
+                                        
+	/* check if a card is inserted */
+	if (!(PCMCIA_INSERTED)) {
+		printk("NO PCMCIA card inserted\n");
+		return (ENODEV);
+	}
+                                                                                                
+	/* disable pcmcia irq for readtuple */
+	pcmcia_disable_irq();
+
+#ifndef MANUAL_CONFIG
+	if ((pcmcia_copy_tuple(CISTPL_FUNCID, tuple, 8) < 3) ||
+		(tuple[2] != CISTPL_FUNCID_NETWORK)) {
+		printk("not an ethernet card\n");
+		return (ENODEV);
+	}
+#endif
+
+	printk("ethernet PCMCIA card inserted\n");
+
+	if (init_pcmcia())
+		return apne_probe1(dev, IOBASE+GAYLE_IO);
+	else
+		return (ENODEV);
+
+}
+
+
+__initfunc(static int apne_probe1(struct device *dev, int ioaddr))
+{
+    int i;
+    unsigned char SA_prom[32];
+    int wordlength = 2;
+    const char *name = NULL;
+    int start_page, stop_page;
+#ifndef MANUAL_HWADDR0
+    int neX000, ctron;
+#endif
+    static unsigned version_printed = 0;
+    static int pcmcia_offsets[16]={
+                0,   1+GAYLE_ODD,   2,   3+GAYLE_ODD,
+                4,   5+GAYLE_ODD,   6,   7+GAYLE_ODD,
+                8,   9+GAYLE_ODD, 0xa, 0xb+GAYLE_ODD,
+              0xc, 0xd+GAYLE_ODD, 0xe, 0xf+GAYLE_ODD };
+
+    if (load_8390_module("apne.c"))
+        return -ENOSYS;
+
+    /* We should have a "dev" from Space.c or the static module table. */
+    if (dev == NULL) {
+	printk(KERN_ERR "apne.c: Passed a NULL device.\n");
+	dev = init_etherdev(0, 0);
+    }
+
+    if (ei_debug  &&  version_printed++ == 0)
+	printk(version);
+
+    printk("PCMCIA NE*000 ethercard probe");
+
+    /* Reset card. Who knows what dain-bramaged state it was left in. */
+    {	unsigned long reset_start_time = jiffies;
+
+	writeb(readb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+	while ((readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
+		if (jiffies - reset_start_time > 2*HZ/100) {
+			printk(" not found (no reset ack).\n");
+			return ENODEV;
+		}
+
+	writeb(0xff, ioaddr + NE_EN0_ISR);		/* Ack all intr. */
+    }
+
+#ifndef MANUAL_HWADDR0
+
+    /* Read the 16 bytes of station address PROM.
+       We must first initialize registers, similar to NS8390_init(eifdev, 0).
+       We can't reliably read the SAPROM address without this.
+       (I learned the hard way!). */
+    {
+	struct {unsigned long value, offset; } program_seq[] = {
+	    {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
+	    {0x48,	NE_EN0_DCFG},	/* Set byte-wide (0x48) access. */
+	    {0x00,	NE_EN0_RCNTLO},	/* Clear the count regs. */
+	    {0x00,	NE_EN0_RCNTHI},
+	    {0x00,	NE_EN0_IMR},	/* Mask completion irq. */
+	    {0xFF,	NE_EN0_ISR},
+	    {E8390_RXOFF, NE_EN0_RXCR},	/* 0x20  Set to monitor */
+	    {E8390_TXOFF, NE_EN0_TXCR},	/* 0x02  and loopback mode. */
+	    {32,	NE_EN0_RCNTLO},
+	    {0x00,	NE_EN0_RCNTHI},
+	    {0x00,	NE_EN0_RSARLO},	/* DMA starting at 0x0000. */
+	    {0x00,	NE_EN0_RSARHI},
+	    {E8390_RREAD+E8390_START, NE_CMD},
+	};
+	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+	    writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
+	}
+
+    }
+    for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
+	SA_prom[i] = readb(ioaddr + NE_DATAPORT);
+	SA_prom[i+1] = readb(ioaddr + NE_DATAPORT);
+	if (SA_prom[i] != SA_prom[i+1])
+	    wordlength = 1;
+    }
+
+    /*	At this point, wordlength *only* tells us if the SA_prom is doubled
+	up or not because some broken PCI cards don't respect the byte-wide
+	request in program_seq above, and hence don't have doubled up values. 
+	These broken cards would otherwise be detected as an ne1000.  */
+
+    if (wordlength == 2)
+	for (i = 0; i < 16; i++)
+		SA_prom[i] = SA_prom[i+i];
+    
+    if (wordlength == 2) {
+	/* We must set the 8390 for word mode. */
+	writeb(0x49, ioaddr + NE_EN0_DCFG);
+	start_page = NESM_START_PG;
+	stop_page = NESM_STOP_PG;
+    } else {
+	start_page = NE1SM_START_PG;
+	stop_page = NE1SM_STOP_PG;
+    }
+
+    neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
+    ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
+
+    /* Set up the rest of the parameters. */
+    if (neX000) {
+	name = (wordlength == 2) ? "NE2000" : "NE1000";
+    } else if (ctron) {
+	name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
+	start_page = 0x01;
+	stop_page = (wordlength == 2) ? 0x40 : 0x20;
+    } else {
+	printk(" not found.\n");
+	return ENXIO;
+
+    }
+
+#else
+    wordlength = 2;
+    /* We must set the 8390 for word mode. */
+    writeb(0x49, ioaddr + NE_EN0_DCFG);
+    start_page = NESM_START_PG;
+    stop_page = NESM_STOP_PG;
+
+    SA_prom[0] = MANUAL_HWADDR0;
+    SA_prom[1] = MANUAL_HWADDR1;
+    SA_prom[2] = MANUAL_HWADDR2;
+    SA_prom[3] = MANUAL_HWADDR3;
+    SA_prom[4] = MANUAL_HWADDR4;
+    SA_prom[5] = MANUAL_HWADDR5;
+    name = "NE2000";
+#endif
+
+    dev->base_addr = ioaddr;
+
+    /* Install the Interrupt handler */
+    if (request_irq(IRQ_AMIGA_PORTS, apne_interrupt, 0, "apne Ethernet", dev))
+        return -EAGAIN;
+
+
+    /* Allocate dev->priv and fill in 8390 specific dev fields. */
+    if (ethdev_init(dev)) {
+	printk (" unable to get memory for dev->priv.\n");
+	return -ENOMEM;
+    }
+
+    for(i = 0; i < ETHER_ADDR_LEN; i++) {
+	printk(" %2.2x", SA_prom[i]);
+	dev->dev_addr[i] = SA_prom[i];
+    }
+
+    printk("\n%s: %s found.\n",
+	   dev->name, name);
+
+    ei_status.name = name;
+    ei_status.tx_start_page = start_page;
+    ei_status.stop_page = stop_page;
+    ei_status.word16 = (wordlength == 2);
+
+    ei_status.rx_start_page = start_page + TX_PAGES;
+
+    ei_status.reset_8390 = &apne_reset_8390;
+    ei_status.block_input = &apne_block_input;
+    ei_status.block_output = &apne_block_output;
+    ei_status.get_8390_hdr = &apne_get_8390_hdr;
+    ei_status.reg_offset = pcmcia_offsets;
+    dev->open = &apne_open;
+    dev->stop = &apne_close;
+    NS8390_init(dev, 0);
+
+    pcmcia_ack_int(pcmcia_get_intreq());		/* ack PCMCIA int req */
+    pcmcia_enable_irq();
+
+    return 0;
+}
+
+static int
+apne_open(struct device *dev)
+{
+    ei_open(dev);
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+static int
+apne_close(struct device *dev)
+{
+    if (ei_debug > 1)
+	printk("%s: Shutting down ethercard.\n", dev->name);
+    ei_close(dev);
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+static void
+apne_reset_8390(struct device *dev)
+{
+    unsigned long reset_start_time = jiffies;
+
+    init_pcmcia();
+
+    if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies);
+
+    writeb(readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+    ei_status.txing = 0;
+    ei_status.dmaing = 0;
+
+    /* This check _should_not_ be necessary, omit eventually. */
+    while ((readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
+	if (jiffies - reset_start_time > 2*HZ/100) {
+	    printk("%s: ne_reset_8390() did not complete.\n", dev->name);
+	    break;
+	}
+    writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR);	/* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void
+apne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+
+    int nic_base = dev->base_addr;
+    int cnt;
+    char *ptrc;
+    short *ptrs;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_get_8390_hdr "
+	   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+	   dev->name, ei_status.dmaing, ei_status.irqlock,
+	   dev->interrupt);
+	return;
+    }
+
+    ei_status.dmaing |= 0x01;
+    writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
+    writeb(0, nic_base + NE_EN0_RCNTHI);
+    writeb(0, nic_base + NE_EN0_RSARLO);		/* On page boundary */
+    writeb(ring_page, nic_base + NE_EN0_RSARHI);
+    writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+    if (ei_status.word16) {
+        ptrs = (short*)hdr;
+        for(cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
+            *ptrs++ = readw(NE_BASE + NE_DATAPORT);
+    } else {
+        ptrc = (char*)hdr;
+        for(cnt = 0; cnt < sizeof(struct e8390_pkt_hdr); cnt++)
+            *ptrc++ = readb(NE_BASE + NE_DATAPORT);
+    }
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+
+    hdr->count = WORDSWAP(hdr->count);
+
+    ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using writeb. */
+
+static void
+apne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+    int nic_base = dev->base_addr;
+    char *buf = skb->data;
+    char *ptrc;
+    short *ptrs;
+    int cnt;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_block_input "
+	   "[DMAstat:%d][irqlock:%d][intr:%d].\n",
+	   dev->name, ei_status.dmaing, ei_status.irqlock,
+	   dev->interrupt);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    writeb(count >> 8, nic_base + NE_EN0_RCNTHI);
+    writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
+    writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
+    writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+    if (ei_status.word16) {
+      ptrs = (short*)buf;
+      for (cnt = 0; cnt < (count>>1); cnt++)
+        *ptrs++ = readw(NE_BASE + NE_DATAPORT);
+      if (count & 0x01) {
+	buf[count-1] = readb(NE_BASE + NE_DATAPORT);
+      }
+    } else {
+      ptrc = (char*)buf;
+      for (cnt = 0; cnt < count; cnt++)
+        *ptrc++ = readb(NE_BASE + NE_DATAPORT);
+    }
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+}
+
+static void
+apne_block_output(struct device *dev, int count,
+		const unsigned char *buf, const int start_page)
+{
+    int nic_base = NE_BASE;
+    unsigned long dma_start;
+    char *ptrc;
+    short *ptrs;
+    int cnt;
+
+    /* Round the count up for word writes.  Do we need to do this?
+       What effect will an odd byte count have on the 8390?
+       I should check someday. */
+    if (ei_status.word16 && (count & 0x01))
+      count++;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+	printk("%s: DMAing conflict in ne_block_output."
+	   "[DMAstat:%d][irqlock:%d][intr:%d]\n",
+	   dev->name, ei_status.dmaing, ei_status.irqlock,
+	   dev->interrupt);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    /* We should already be in page 0, but to be safe... */
+    writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+
+   /* Now the normal output. */
+    writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    writeb(count >> 8,   nic_base + NE_EN0_RCNTHI);
+    writeb(0x00, nic_base + NE_EN0_RSARLO);
+    writeb(start_page, nic_base + NE_EN0_RSARHI);
+
+    writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+    if (ei_status.word16) {
+        ptrs = (short*)buf;
+        for (cnt = 0; cnt < count>>1; cnt++)
+            writew(*ptrs++, NE_BASE+NE_DATAPORT);
+    } else {
+        ptrc = (char*)buf;
+        for (cnt = 0; cnt < count; cnt++)
+	    writeb(*ptrc++, NE_BASE + NE_DATAPORT);
+    }
+
+    dma_start = jiffies;
+
+    while ((readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
+	if (jiffies - dma_start > 2*HZ/100) {		/* 20ms */
+		printk("%s: timeout waiting for Tx RDC.\n", dev->name);
+		apne_reset_8390(dev);
+		NS8390_init(dev,1);
+		break;
+	}
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+    return;
+}
+
+static void apne_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned char pcmcia_intreq;
+
+    if (!(gayle.inten & GAYLE_IRQ_IRQ))
+        return;
+
+    pcmcia_intreq = pcmcia_get_intreq();
+
+    if (!(pcmcia_intreq & GAYLE_IRQ_IRQ)) {
+        pcmcia_ack_int(pcmcia_intreq);
+        return;
+    }
+    if (ei_debug > 3)
+        printk("pcmcia intreq = %x\n", pcmcia_intreq);
+    pcmcia_disable_irq();			/* to get rid of the sti() within ei_interrupt */
+    ei_interrupt(irq, dev_id, regs);
+    pcmcia_ack_int(pcmcia_get_intreq());
+    pcmcia_enable_irq();
+}
+
+#ifdef MODULE
+static char devicename[9] = {0, };
+
+static struct device apne_dev =
+{
+	devicename,
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, apne_probe,
+};
+
+int init_module(void)
+{
+	int err;
+	if ((err = register_netdev(&apne_dev))) {
+		if (err == -EIO)
+			printk("No PCMCIA NEx000 ethernet card found.\n");
+		return (err);
+	}
+	lock_8390_module();
+	return (0);
+}
+
+void cleanup_module(void)
+{
+	unregister_netdev(&apne_dev);
+
+	pcmcia_disable_irq();
+
+	free_irq(IRQ_AMIGA_PORTS, &apne_dev);
+
+	pcmcia_reset();
+
+	unlock_8390_module();
+}
+
+#endif
+
+static int init_pcmcia(void)
+{
+	u_char config;
+#ifndef MANUAL_CONFIG
+	u_char tuple[32];
+	int offset_len;
+#endif
+	u_long offset;
+
+	pcmcia_reset();
+	pcmcia_program_voltage(PCMCIA_0V);
+	pcmcia_access_speed(PCMCIA_SPEED_250NS);
+	pcmcia_write_enable();
+
+#ifdef MANUAL_CONFIG
+	config = MANUAL_CONFIG;
+#else
+	/* get and write config byte to enable IO port */
+
+	if (pcmcia_copy_tuple(CISTPL_CFTABLE_ENTRY, tuple, 32) < 3)
+		return 0;
+
+	config = tuple[2] & 0x3f;
+#endif
+#ifdef MANUAL_OFFSET
+	offset = MANUAL_OFFSET;
+#else
+	if (pcmcia_copy_tuple(CISTPL_CONFIG, tuple, 32) < 6)
+		return 0;
+
+	offset_len = (tuple[2] & 0x3) + 1;
+	offset = 0;
+	while(offset_len--) {
+		offset = (offset << 8) | tuple[4+offset_len];
+	}
+#endif
+
+	writeb(config, GAYLE_ATTRIBUTE+offset);
+
+	return 1;
+}
diff -u --recursive --new-file v2.1.112/linux/drivers/net/bmac.c linux/drivers/net/bmac.c
--- v2.1.112/linux/drivers/net/bmac.c	Tue Jul 28 14:21:08 1998
+++ linux/drivers/net/bmac.c	Fri Jul 31 23:19:40 1998
@@ -4,6 +4,7 @@
  *
  * Copyright (C) 1998 Randy Gobbel.
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c
--- v2.1.112/linux/drivers/net/daynaport.c	Tue Jul 28 14:21:08 1998
+++ linux/drivers/net/daynaport.c	Thu Jul 30 11:17:12 1998
@@ -281,13 +281,13 @@
 {
 	static unsigned version_printed = 0;
 
-	static unsigned char fwrd4_offsets[16]={
+	static int fwrd4_offsets[16]={
 		0,      4,      8,      12,
 		16,     20,     24,     28,
 		32,     36,     40,     44,
 		48,     52,     56,     60
 	};
-	static unsigned char back4_offsets[16]={
+	static int back4_offsets[16]={
 		60,     56,     52,     48,
 		44,     40,     36,     32,
 		28,     24,     20,     16,
diff -u --recursive --new-file v2.1.112/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.1.112/linux/drivers/net/eepro100.c	Tue Jul 28 14:21:08 1998
+++ linux/drivers/net/eepro100.c	Fri Jul 31 16:56:20 1998
@@ -1,13 +1,13 @@
 /* drivers/net/eepro100.c: An Intel i82557 Ethernet driver for Linux. */
 /*
    NOTICE: this version tested with kernels 1.3.72 and later only!
-	Written 1996-1998 by Donald Becker.
+	Written 1996-1997 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
 
 	This driver is for the Intel EtherExpress Pro 100B boards.
-	It should work with other i82557 and i82558 boards.
+	It should work with other i82557 boards (if any others exist).
 	To use a built-in driver, install as drivers/net/eepro100.c.
 	To use as a module, use the compile-command at the end of the file.
 
@@ -15,13 +15,11 @@
 	Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
 	For updates see
-		http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html
-	There is also a mailing list based at
-		linux-eepro100@cesdis.gsfc.nasa.gov
+	<base href="http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html">
 */
 
 static const char *version =
-"eepro100.c:v1.02 7/24/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
+"eepro100.c:v0.36 10/20/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
 
 /* A few user-configurable values that apply to all boards.
    First set are undocumented and spelled per Intel recommendations. */
@@ -35,15 +33,36 @@
 
 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
    Lower values use more memory, but are faster. */
-static int rx_copybreak = 200;
+/*
+ * NOTE! The value of 2000 means that this optimization never gets
+ * used. Rationale: it seems to be broken when in low-memory situations,
+ * apparently when alloc_skb() can return NULL the clever list of
+ * copy-buffers can get buggered. 
+ *
+ * My personal suspicion is that the allocation failure will cause
+ * us to not remove the skb from the list of available buffers, but
+ * we'd already have done a "skb_push()" with the data we got, so
+ * the buffer stays on the list but the available memory in it
+ * shrinks until we panic.
+ *
+ * Donald, when you fix this you can shrink this value again.
+ *
+ *		Linus
+ */
+static int rx_copybreak = 2000;
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
+static int max_interrupt_work = 200;
 
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
 #include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
 
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -56,6 +75,7 @@
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -64,44 +84,74 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+
+/* A nominally proper method to handle version dependencies is to use
+   LINUX_VERSION_CODE in version.h, but that triggers recompiles w/'make'. */
+#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
+#ifdef MODULE
+#if (LINUX_VERSION_CODE < VERSION(1,3,0))
+#define KERNEL_1_2
+#else /* 1.3.0 */
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
+#define NEW_MULTICAST
+#define LINUX_1_4
+#else
+#warning "This driver is tested for 1.3.44 and later development kernels only."
+#endif /* 1.3.44 */
+#endif
+#else
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
 #include <linux/delay.h>
+#endif
 
-/* Unused in the 2.0.* version, but retained for documentation. */
-#if LINUX_VERSION_CODE > 0x20118
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(multicast_filter_limit, "i");
+#ifdef HAVE_HEADER_CACHE
+#define LINUX_1_4
+#define NEW_MULTICAST
+#else
+#ifdef ETH_P_DDCMP				/* Warning: Bogus!  This means IS_LINUX_1_3. */
+#define KERNEL_1_3
+#else
+#define KERNEL_1_2
+#endif
 #endif
 
+#endif
+/* This should be in a header file. */
+#if (LINUX_VERSION_CODE < VERSION(1,3,44))
+struct device *init_etherdev(struct device *dev, int sizeof_priv,
+							 unsigned long *mem_startp);
+#endif
+#if LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#define virt_to_bus(addr)  ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+#else  /* 1.3.0 and later */
 #define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
 
 #if (LINUX_VERSION_CODE < 0x20123)
 #define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
-#if LINUX_VERSION_CODE < 0x20155
-#define pci_present() pcibios_present()
+#include <linux/bios32.h>
 #endif
 
-/* The total I/O port extent of the board.
-   The registers beyond 0x18 only exist on the i82558. */
+/* The total I/O port extent of the board.  Nominally 0x18, but rounded up
+   for PCI allocation. */
 #define SPEEDO3_TOTAL_SIZE 0x20
 
-int speedo_debug = 1;
+#ifdef HAVE_DEVLIST
+struct netdev_entry eepro100_drv =
+{"EEPro-100", eepro100_init, SPEEDO3_TOTAL_SIZE, NULL};
+#endif
+
+#ifdef SPEEDO3_DEBUG
+int speedo_debug = SPEEDO3_DEBUG;
+#else
+int speedo_debug = 3;
+#endif
 
 /*
 				Theory of Operation
@@ -133,7 +183,7 @@
 Despite the extra space overhead in each receive skbuff, the driver must use
 the simplified Rx buffer mode to assure that only a single data buffer is
 associated with each RxFD. The driver implements this by reserving space
-for the Rx descriptor at the head of each Rx skbuff.
+for the Rx descriptor at the head of each Rx skbuff
 
 The Speedo-3 has receive and command unit base addresses that are added to
 almost all descriptor pointers.  The driver sets these to zero, so that all
@@ -148,13 +198,10 @@
 
 The driver must use the complex Tx command+descriptor mode in order to
 have a indirect pointer to the skbuff data section.  Each Tx command block
-(TxCB) is associated with two immediately appended Tx Buffer Descriptor
+(TxCB) is associated with a single, immediately appended Tx buffer descriptor
 (TxBD).  A fixed ring of these TxCB+TxBD pairs are kept as part of the
 speedo_private data structure for each adapter instance.
 
-The newer i82558 explicitly supports this structure, and can read the two
-TxBDs in the same PCI burst as the TxCB.
-
 This ring structure is used for all normal transmit packets, but the
 transmit packet descriptors aren't long enough for most non-Tx commands such
 as CmdConfigure.  This is complicated by the possibility that the chip has
@@ -243,19 +290,26 @@
 #define PKT_BUF_SZ		1536
 
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((800*HZ)/1000)
+#define TX_TIMEOUT  ((400*HZ)/1000)
 
 /* How to wait for the command unit to accept a command.
    Typically this takes 0 ticks. */
-static inline void wait_for_cmd_done(long cmd_ioaddr)
+static inline void wait_for_cmd_done(int cmd_ioaddr)
 {
-	int wait = 100;
-	do   ;
-	while(inb(cmd_ioaddr) && --wait >= 0);
+  short wait = 100;
+  do   ;
+  while(inb(cmd_ioaddr) && --wait >= 0);
 }
 
 /* Operational parameter that usually are not changed. */
 
+#ifndef PCI_VENDOR_ID_INTEL		/* Now defined in linux/pci.h */
+#define PCI_VENDOR_ID_INTEL		0x8086 /* Hmmmm, how did they pick that? */
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82557
+#define PCI_DEVICE_ID_INTEL_82557	0x1229
+#endif
+
 /* The rest of these values should never change. */
 
 /* Offsets to the various registers.
@@ -310,23 +364,17 @@
 	u16 size;
 };
 
-/* Selected elements of the RxFD.status word. */
-enum RxFD_bits {
-	RxComplete=0x8000, RxOK=0x2000,
-	RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
-	RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
-};
+/* Elements of the RxFD.status word. */
+#define RX_COMPLETE 0x8000
 
 struct TxFD {					/* Transmit frame descriptor set. */
 	s32 status;
 	u32 link;					/* void * */
 	u32 tx_desc_addr;			/* Always points to the tx_buf_addr element. */
 	s32 count;					/* # of TBD (=1), Tx start thresh., etc. */
-	/* This constitutes two "TBD" entries -- we only use one. */
-	u32 tx_buf_addr0;			/* void *, frame to be transmitted.  */
-	s32 tx_buf_size0;			/* Length of Tx frame. */
-	u32 tx_buf_addr1;			/* void *, frame to be transmitted.  */
-	s32 tx_buf_size1;			/* Length of Tx frame. */
+	/* This constitutes a single "TBD" entry -- we only use one. */
+	u32 tx_buf_addr;			/* void *, frame to be transmitted.  */
+	s32 tx_buf_size;			/* Length of Tx frame. */
 };
 
 /* Elements of the dump_statistics block. This block must be lword aligned. */
@@ -361,6 +409,9 @@
 	/* Rx descriptor ring & addresses of receive-in-place skbuffs. */
 	struct RxFD *rx_ringp[RX_RING_SIZE];
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+#if (LINUX_VERSION_CODE < 0x10300)	/* Kernel v1.2.*. */
+	struct RxFD saved_skhead[RX_RING_SIZE];	/* Saved skbuff header chunk. */
+#endif
 	struct RxFD *last_rxf;	/* Last command sent. */
 	struct enet_statistics stats;
 	struct speedo_stats lstats;
@@ -372,7 +423,6 @@
 	u8 config_cmd_data[22];			/* .. and setup parameters. */
 	int mc_setup_frm_len;			 	/* The length of an allocated.. */
 	struct descriptor *mc_setup_frm; 	/* ..multicast setup frame. */
-	int in_interrupt;					/* Word-aligned dev->interrupt */
 	char rx_mode;						/* Current PROMISC/ALLMULTI setting. */
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
@@ -386,16 +436,11 @@
 /* The parameters for a CmdConfigure operation.
    There are so many options that it would be difficult to document each bit.
    We mostly use the default or recommended settings. */
-const char i82557_config_cmd[22] = {
+const char basic_config_cmd[22] = {
 	22, 0x08, 0, 0,  0, 0x80, 0x32, 0x03,  1, /* 1=Use MII  0=Use AUI */
 	0, 0x2E, 0,  0x60, 0,
 	0xf2, 0x48,   0, 0x40, 0xf2, 0x80, 		/* 0x40=Force full-duplex */
 	0x3f, 0x05, };
-const char i82558_config_cmd[22] = {
-	22, 0x08, 0, 1,  0, 0x80, 0x22, 0x03,  1, /* 1=Use MII  0=Use AUI */
-	0, 0x2E, 0,  0x60, 0x08, 0x88,
-	0x68, 0, 0x40, 0xf2, 0xBD, 		/* 0xBD->0xFD=Force full-duplex */
-	0x31, 0x05, };
 
 /* PHY media interface chips. */
 static const char *phys[] = {
@@ -407,12 +452,12 @@
 					 S80C24, I82555, DP83840A=10, };
 static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
 
-static void speedo_found1(struct device *dev, long ioaddr, int irq,
-						  int card_idx);
+static void speedo_found1(struct device *dev, int ioaddr, int irq,
+						  int options, int card_idx);
 
-static int read_eeprom(long ioaddr, int location);
-static int mdio_read(long ioaddr, int phy_id, int location);
-static int mdio_write(long ioaddr, int phy_id, int location, int value);
+static int read_eeprom(int ioaddr, int location);
+static int mdio_read(int ioaddr, int phy_id, int location);
+static int mdio_write(int ioaddr, int phy_id, int location, int value);
 static int speedo_open(struct device *dev);
 static void speedo_timer(unsigned long data);
 static void speedo_init_rx_ring(struct device *dev);
@@ -421,7 +466,9 @@
 static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int speedo_close(struct device *dev);
 static struct enet_statistics *speedo_get_stats(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
 static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
 static void set_rx_mode(struct device *dev);
 
 
@@ -430,8 +477,8 @@
 /* 'options' is used to pass a transceiver override or full-duplex flag
    e.g. "options=16" for FD, "options=32" for 100mbps-only. */
 static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #ifdef MODULE
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int debug = -1;			/* The debug level */
 #endif
 
@@ -441,97 +488,98 @@
 int eepro100_init(struct device *dev)
 {
 	int cards_found = 0;
-	static int pci_index = 0;
 
-	if (! pci_present())
-		return cards_found;
+	if (pci_present()) {
+		static int pci_index = 0;
 
-	for (; pci_index < 8; pci_index++) {
-		unsigned char pci_bus, pci_device_fn, pci_latency;
-		long ioaddr;
-		int irq;
-
-		u16 pci_command, new_command;
-
-		if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
-								PCI_DEVICE_ID_INTEL_82557,
-								pci_index, &pci_bus,
-								&pci_device_fn))
-			break;
-#if LINUX_VERSION_CODE >= 0x20155  ||  PCI_SUPPORT_1
-		{
-			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-			ioaddr = pdev->base_address[1];		/* Use [0] to mem-map */
-			irq = pdev->irq;
-		}
+		for (; pci_index < 8; pci_index++) {
+			unsigned char pci_bus, pci_device_fn, pci_latency;
+#if (LINUX_VERSION_CODE >= VERSION(2,1,85))
+			unsigned int pci_irq_line;
+			struct pci_dev *pdev;
+#else
+			unsigned char pci_irq_line;
+#endif
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
+			int pci_ioaddr;
+#else
+			long pci_ioaddr;
+#endif
+			unsigned short pci_command;
+
+			if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
+						PCI_DEVICE_ID_INTEL_82557,
+						pci_index, &pci_bus,
+						&pci_device_fn))
+			  break;
+#if (LINUX_VERSION_CODE >= VERSION(2,1,85))
+			pdev = pci_find_slot(pci_bus, pci_device_fn);
+			pci_irq_line = pdev->irq;
+			pci_ioaddr = pdev->base_address[1];
 #else
-		{
-			u32 pci_ioaddr;
-			u8 pci_irq_line;
 			pcibios_read_config_byte(pci_bus, pci_device_fn,
 									 PCI_INTERRUPT_LINE, &pci_irq_line);
 			/* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
 			pcibios_read_config_dword(pci_bus, pci_device_fn,
 									  PCI_BASE_ADDRESS_1, &pci_ioaddr);
-			ioaddr = pci_ioaddr;
-			irq = pci_irq_line;
-		}
 #endif
-		/* Remove I/O space marker in bit 0. */
-		ioaddr &= ~3;
-		if (speedo_debug > 2)
-			printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
-				   ioaddr, irq);
-
-		/* Get and check the bus-master and latency values. */
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_COMMAND, &pci_command);
-		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled this"
-				   " device!  Updating PCI command %4.4x->%4.4x.\n",
-				   pci_command, new_command);
-			pcibios_write_config_word(pci_bus, pci_device_fn,
-									  PCI_COMMAND, new_command);
+			/* Remove I/O space marker in bit 0. */
+			pci_ioaddr &= ~3;
+			if (speedo_debug > 2)
+				printk("Found Intel i82557 PCI Speedo at I/O %#x, IRQ %d.\n",
+					   (int)pci_ioaddr, pci_irq_line);
+
+			/* Get and check the bus-master and latency values. */
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_COMMAND, &pci_command);
+			if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+				printk("  PCI Master Bit has not been set! Setting...\n");
+				pci_command |= PCI_COMMAND_MASTER;
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, pci_command);
+			}
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+										 PCI_LATENCY_TIMER, &pci_latency);
+			if (pci_latency < 10) {
+				printk("  PCI latency timer (CFLT) is unreasonably low at %d."
+					   "  Setting to 255 clocks.\n", pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, 255);
+			} else if (speedo_debug > 1)
+				printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
+
+#ifdef MODULE
+			speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found],
+						  cards_found);
+#else
+			speedo_found1(dev, pci_ioaddr, pci_irq_line,
+						  dev ? dev->mem_start : 0, -1);
+#endif
+			dev = NULL;
+			cards_found++;
 		}
-		pcibios_read_config_byte(pci_bus, pci_device_fn,
-								 PCI_LATENCY_TIMER, &pci_latency);
-		if (pci_latency < 32) {
-			printk("  PCI latency timer (CFLT) is unreasonably low at %d."
-				   "  Setting to 32 clocks.\n", pci_latency);
-			pcibios_write_config_byte(pci_bus, pci_device_fn,
-									  PCI_LATENCY_TIMER, 32);
-		} else if (speedo_debug > 1)
-			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
-
-		speedo_found1(dev, ioaddr, irq, cards_found);
-		dev = NULL;
-		cards_found++;
 	}
 
 	return cards_found;
 }
 
-static void speedo_found1(struct device *dev, long ioaddr, int irq,
+static void speedo_found1(struct device *dev, int ioaddr, int irq, int options,
 						  int card_idx)
 {
 	static int did_version = 0;			/* Already printed version info. */
 	struct speedo_private *sp;
 	char *product;
-	int i, option;
+	int i;
 	u16 eeprom[0x40];
 
 	if (speedo_debug > 0  &&  did_version++ == 0)
 		printk(version);
 
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
 	dev = init_etherdev(dev, sizeof(struct speedo_private));
-
-	if (dev->mem_start > 0) 
-		option = dev->mem_start;
-	else if (card_idx >= 0  &&  options[card_idx] >= 0)
-		option = options[card_idx];
-	else
-		option = 0;
+#else
+	dev = init_etherdev(dev, sizeof(struct speedo_private), 0);
+#endif
 
 	/* Read the station address EEPROM before doing the reset.
 	   Perhaps this should even be done before accepting the device,
@@ -566,7 +614,7 @@
 	else
 		product = "Intel EtherExpress Pro 10/100";
 
-	printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
+	printk(KERN_INFO "%s: %s at %#3x, ", dev->name, product, ioaddr);
 
 	for (i = 0; i < 5; i++)
 		printk("%2.2X:", dev->dev_addr[i]);
@@ -595,6 +643,17 @@
 		if (eeprom[7] & 0x0700)
 			printk(KERN_INFO "    Secondary interface chip %s.\n",
 				   phys[(eeprom[7]>>8)&7]);
+#if defined(notdef)
+		/* ToDo: Read and set PHY registers through MDIO port. */
+		for (i = 0; i < 2; i++)
+			printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
+				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
+		for (i = 5; i < 7; i++)
+			printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
+				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
+		printk(KERN_INFO"  MDIO register %d is %4.4x.\n",
+			   25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25));
+#endif
 		if (((eeprom[6]>>8) & 0x3f) == DP83840
 			||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
 			int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
@@ -604,13 +663,13 @@
 				   mdi_reg23);
 			mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
 		}
-		if ((option >= 0) && (option & 0x70)) {
+		if ((options >= 0) && (options & 0x60)) {
 			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
-				   (option & 0x20 ? 100 : 10),
-				   (option & 0x10 ? "full" : "half"));
+				   (options & 0x20 ? 100 : 10),
+				   (options & 0x10 ? "full" : "half"));
 			mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
-					   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
-					   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+					   ((options & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
+					   ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */
 		}
 
 		/* Perform a system self-test. */
@@ -619,7 +678,11 @@
 		self_test_results[1] = -1;
 		outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort);
 		do {
+#ifdef _LINUX_DELAY_H
 			udelay(10);
+#else
+			SLOW_DOWN_IO;
+#endif
 		} while (self_test_results[1] == -1  &&  --boguscnt >= 0);
 
 		if (boguscnt < 0) {		/* Test optimized out. */
@@ -656,12 +719,12 @@
 	sp->next_module = root_speedo_dev;
 	root_speedo_dev = dev;
 
-	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
 			sp->full_duplex = full_duplex[card_idx];
-	}
-	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
+	} else
+		sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0;
+	sp->default_port = options >= 0 ? (options & 0x0f) : 0;
 
 	sp->phy[0] = eeprom[6];
 	sp->phy[1] = eeprom[7];
@@ -675,8 +738,12 @@
 	dev->hard_start_xmit = &speedo_start_xmit;
 	dev->stop = &speedo_close;
 	dev->get_stats = &speedo_get_stats;
+#ifdef NEW_MULTICAST
 	dev->set_multicast_list = &set_rx_mode;
+#endif
+#ifdef HAVE_PRIVATE_IOCTL
 	dev->do_ioctl = &speedo_ioctl;
+#endif
 
 	return;
 }
@@ -693,15 +760,20 @@
 #define EE_ENB			(0x4800 | EE_CS)
 
 /* Delay between EEPROM clock transitions.
-   This will actually work with no delay on 33Mhz PCI.  */
+   This is a "nasty" timing loop, but PC compatible machines are defined
+   to delay an ISA compatible period for the SLOW_DOWN_IO macro.  */
+#ifdef _LINUX_DELAY_H
 #define eeprom_delay(nanosec)		udelay(1);
+#else
+#define eeprom_delay(nanosec)	do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+#endif
 
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD	(5 << 6)
 #define EE_READ_CMD		(6 << 6)
 #define EE_ERASE_CMD	(7 << 6)
 
-static int read_eeprom(long ioaddr, int location)
+static int read_eeprom(int ioaddr, int location)
 {
 	int i;
 	unsigned short retval = 0;
@@ -718,6 +790,8 @@
 		eeprom_delay(100);
 		outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
 		eeprom_delay(150);
+		outw(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
+		eeprom_delay(250);
 	}
 	outw(EE_ENB, ee_addr);
 
@@ -734,11 +808,16 @@
 	return retval;
 }
 
-static int mdio_read(long ioaddr, int phy_id, int location)
+static int mdio_read(int ioaddr, int phy_id, int location)
 {
-	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
+	int val, boguscnt = 64*4;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
 	do {
+#ifdef _LINUX_DELAY_H
+		udelay(16);
+#else
+		SLOW_DOWN_IO;
+#endif
 		val = inl(ioaddr + SCBCtrlMDI);
 		if (--boguscnt < 0) {
 			printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
@@ -747,12 +826,17 @@
 	return val & 0xffff;
 }
 
-static int mdio_write(long ioaddr, int phy_id, int location, int value)
+static int mdio_write(int ioaddr, int phy_id, int location, int value)
 {
-	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
+	int val, boguscnt = 64*4;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
 		 ioaddr + SCBCtrlMDI);
 	do {
+#ifdef _LINUX_DELAY_H
+		udelay(16);
+#else
+		SLOW_DOWN_IO;
+#endif
 		val = inl(ioaddr + SCBCtrlMDI);
 		if (--boguscnt < 0) {
 			printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
@@ -766,42 +850,25 @@
 speedo_open(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 
 #ifdef notdef
 	/* We could reset the chip, but should not need to. */
 	outl(0, ioaddr + SCBPort);
-	udelay(10);
+	for (i = 40; i >= 0; i--)
+		SLOW_DOWN_IO;			/* At least 250ns */
 #endif
 
 	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ,
 					"Intel EtherExpress Pro 10/100 Ethernet", dev)) {
 		return -EAGAIN;
 	}
+
 	if (speedo_debug > 1)
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
 	MOD_INC_USE_COUNT;
 
-	/* Retrigger negotiation to reset previous errors. */
-	if ((sp->phy[0] & 0x8000) == 0) {
-		int phy_addr = sp->phy[0] & 0x1f;
-		/* Use 0x3300 for restarting NWay, other values to force xcvr:
-		   0x0000 10-HD
-		   0x0100 10-FD
-		   0x2000 100-HD 
-		   0x2100 100-FD
-		   0x
-		*/
-#ifdef notdef
-		int mii_ctrl[8] =
-		{ 0x3300, 0x3100, 0x0000, 0x0100, 0x2000, 0x2100, 0x0400, 0x3100};
-		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->if_port & 7]);
-#else
-		mdio_write(ioaddr, phy_addr, 0, 0x3300);
-#endif
-	}
-
 	/* Load the statistics block address. */
 	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
@@ -841,7 +908,6 @@
 
 	dev->if_port = sp->default_port;
 
-	sp->in_interrupt = 0;
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	dev->start = 1;
@@ -886,7 +952,7 @@
 	int tickssofar = jiffies - sp->last_rx_time;
 
 	if (speedo_debug > 3) {
-		long ioaddr = dev->base_addr;
+		int ioaddr = dev->base_addr;
 		printk(KERN_DEBUG "%s: Media selection tick, status %4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
@@ -912,32 +978,43 @@
 	int i;
 
 	sp->cur_rx = 0;
+	sp->dirty_rx = RX_RING_SIZE - 1;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
+#ifndef KERNEL_1_2
 		skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+#else
+		skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
+#endif
 		sp->rx_skbuff[i] = skb;
 		if (skb == NULL)
-			break;			/* OK.  Just initially short of Rx bufs. */
+			break;			/* Bad news!  */
 		skb->dev = dev;			/* Mark as being used by this device. */
+
+#if LINUX_VERSION_CODE >= 0x10300
 		rxf = (struct RxFD *)skb->tail;
-		sp->rx_ringp[i] = rxf;
 		skb_reserve(skb, sizeof(struct RxFD));
+#else
+		/* Save the data in the header region -- it's restored later. */
+		rxf = (struct RxFD *)(skb->data - sizeof(struct RxFD));
+		memcpy(&sp->saved_skhead[i], rxf, sizeof(struct RxFD));
+#endif
+		sp->rx_ringp[i] = rxf;
 		if (last_rxf)
 			last_rxf->link = virt_to_bus(rxf);
 		last_rxf = rxf;
 		rxf->status = 0x00000001; 			/* '1' is flag value only. */
 		rxf->link = 0;						/* None yet. */
+#if LINUX_VERSION_CODE < 0x10300
 		/* This field unused by i82557, we use it as a consistency check. */
-#ifdef final_version
-		rxf->rx_buf_addr = 0xffffffff;
+		rxf->rx_buf_addr = virt_to_bus(skb->data);
 #else
 		rxf->rx_buf_addr = virt_to_bus(skb->tail);
 #endif
 		rxf->count = 0;
 		rxf->size = PKT_BUF_SZ;
 	}
-	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 	/* Mark the last entry as end-of-list. */
 	last_rxf->status = 0xC0000002; 			/* '2' is flag value only. */
 	sp->last_rxf = last_rxf;
@@ -946,12 +1023,28 @@
 static void speedo_tx_timeout(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
+	int i;
 
 	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
 		   "command %4.4x.\n",
 		   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd));
+#ifndef final_version
+	printk(KERN_WARNING "%s:  Tx timeout  fill index %d  scavenge index %d.\n",
+		   dev->name, sp->cur_tx, sp->dirty_tx);
+	printk(KERN_WARNING "    Tx queue ");
+	for (i = 0; i < TX_RING_SIZE; i++)
+	  printk(" %8.8x", (int)sp->tx_ring[i].status);
+	printk(".\n" KERN_WARNING "    Rx ring ");
+	for (i = 0; i < RX_RING_SIZE; i++)
+	  printk(" %8.8x", (int)sp->rx_ringp[i]->status);
+	printk(".\n");
 
+#else
+	dev->if_port ^= 1;
+	printk(KERN_WARNING "  (Media type switching not yet implemented.)\n");
+	/* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */
+#endif
 	if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
 	  printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",
 			 dev->name);
@@ -961,14 +1054,9 @@
 	} else {
 	  outw(DRVR_INT, ioaddr + SCBCmd);
 	}
-	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
-	if ((sp->phy[0] & 0x8000) == 0) {
-		int phy_addr = sp->phy[0] & 0x1f;
-		mdio_write(ioaddr, phy_addr, 0, 0x0400);
-		mdio_write(ioaddr, phy_addr, 1, 0x0000);
-		mdio_write(ioaddr, phy_addr, 4, 0x0000);
-		mdio_write(ioaddr, phy_addr, 0, 0x8000);
-	}
+	/* Reset the MII transceiver. */
+	if ((sp->phy[0] & 0x8000) == 0)
+		mdio_write(ioaddr, sp->phy[0] & 0x1f, 0, 0x8000);
 	sp->stats.tx_errors++;
 	dev->trans_start = jiffies;
 	return;
@@ -978,7 +1066,7 @@
 speedo_start_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	int entry;
 
 	/* Block a timer-based transmit from overlapping.  This could better be
@@ -994,7 +1082,7 @@
 			return 1;
 		}
 		speedo_tx_timeout(dev);
-		return 1;
+		return 0;
 	}
 
 	/* Caution: the write order is important here, set the base address
@@ -1015,12 +1103,12 @@
 		sp->tx_ring[entry].link =
 		  virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
 		sp->tx_ring[entry].tx_desc_addr =
-		  virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0);
+		  virt_to_bus(&sp->tx_ring[entry].tx_buf_addr);
 		/* The data region is always in one buffer descriptor, Tx FIFO
 		   threshold of 256. */
 		sp->tx_ring[entry].count = 0x01208000;
-		sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data);
-		sp->tx_ring[entry].tx_buf_size0 = skb->len;
+		sp->tx_ring[entry].tx_buf_addr = virt_to_bus(skb->data);
+		sp->tx_ring[entry].tx_buf_size = skb->len;
 		/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
 		   than half full.  Argument against: we should be receiving packets
 		   and scavenging the queue.  Argument for: if so, it shouldn't
@@ -1037,7 +1125,7 @@
 	if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3)
 		sp->tx_full = 1;
 	else
-		clear_bit(0, (void*)&dev->tbusy);
+		dev->tbusy = 0;
 
 	dev->trans_start = jiffies;
 
@@ -1050,7 +1138,7 @@
 {
 	struct device *dev = (struct device *)dev_instance;
 	struct speedo_private *sp;
-	long ioaddr, boguscnt = max_interrupt_work;
+	int ioaddr, boguscnt = max_interrupt_work;
 	unsigned short status;
 
 #ifndef final_version
@@ -1063,11 +1151,8 @@
 	ioaddr = dev->base_addr;
 	sp = (struct speedo_private *)dev->priv;
 #ifndef final_version
-	/* A lock to prevent simultaneous entry on SMP machines. */
-	if (test_and_set_bit(0, (void*)&sp->in_interrupt)) {
-		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-			   dev->name);
-		sp->in_interrupt = 0;	/* Avoid halting machine. */
+	if (dev->interrupt) {
+		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
 		return;
 	}
 	dev->interrupt = 1;
@@ -1089,6 +1174,19 @@
 			speedo_rx(dev);
 
 		if (status & 0x1000) {
+#ifdef notdef
+		  int i;
+		  printk(KERN_WARNING"%s: The EEPro100 receiver left the ready"
+				 " state -- %4.4x!  Index %d (%d).\n", dev->name, status,
+				 sp->cur_rx, sp->cur_rx % RX_RING_SIZE);
+		  printk(KERN_WARNING "   Rx ring:\n ");
+		  for (i = 0; i < RX_RING_SIZE; i++)
+			printk("   %d %8.8x %8.8x %8.8x %d %d.\n",
+				   i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link,
+				   sp->rx_ringp[i]->rx_buf_addr, sp->rx_ringp[i]->count,
+				   sp->rx_ringp[i]->size);
+#endif
+
 		  if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
 			outw(RX_RESUMENR, ioaddr + SCBCmd);
 		  else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
@@ -1116,7 +1214,7 @@
 				/* Free the original skb. */
 				if (sp->tx_skbuff[entry]) {
 					sp->stats.tx_packets++;	/* Count only user packets. */
-					dev_free_skb(sp->tx_skbuff[entry]);
+					dev_kfree_skb(sp->tx_skbuff[entry]);
 					sp->tx_skbuff[entry] = 0;
 				}
 				dirty_tx++;
@@ -1135,7 +1233,7 @@
 				&& dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) {
 				/* The ring is no longer full, clear tbusy. */
 				sp->tx_full = 0;
-				clear_bit(0, (void*)&dev->tbusy);
+				dev->tbusy = 0;
 				mark_bh(NET_BH);
 			}
 
@@ -1155,8 +1253,19 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 
+#ifndef final_version
+	/* Special code for testing *only*. */
+	{
+		static int stopit = 100;
+		if (dev->start == 0  &&  --stopit < 0) {
+			printk(KERN_ALERT "%s: Emergency stop, interrupt is stuck.\n",
+				   dev->name);
+			free_irq(irq, dev);
+		}
+	}
+#endif
+
 	dev->interrupt = 0;
-	clear_bit(0, (void*)&sp->in_interrupt);
 	return;
 }
 
@@ -1166,96 +1275,150 @@
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int entry = sp->cur_rx % RX_RING_SIZE;
 	int status;
-	int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;
 
 	if (speedo_debug > 4)
 		printk(KERN_DEBUG " In speedo_rx().\n");
 	/* If we own the next entry, it's a new packet. Send it up. */
-	while (sp->rx_ringp[entry] != NULL &&
-		   (status = sp->rx_ringp[entry]->status) & RxComplete) {
+	while ((status = sp->rx_ringp[entry]->status) & RX_COMPLETE) {
 
 		if (speedo_debug > 4)
 			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
 				   sp->rx_ringp[entry]->count & 0x3fff);
-		if ((status & (RxErrTooBig|RxOK)) != RxOK) {
-			if (status & RxErrTooBig)
-				printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
-					   "status %8.8x!\n", dev->name, status);
-			else if ( ! (status & 0x2000)) {
-				/* There was a fatal error.  This *should* be impossible. */
-				sp->stats.rx_errors++;
-				printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "
-					   "status %8.8x.\n",
-					   dev->name, status);
-			}
+		if (status & 0x0200) {
+			printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "
+				   "status %8.8x!\n", dev->name, status);
+		} else if ( ! (status & 0x2000)) {
+			/* There was a fatal error.  This *should* be impossible. */
+			sp->stats.rx_errors++;
+			printk(KERN_ERR "%s: Anomalous event in speedo_rx(), status %8.8x.\n",
+				   dev->name, status);
 		} else {
+			/* Malloc up new buffer, compatible with net-2e. */
 			int pkt_len = sp->rx_ringp[entry]->count & 0x3fff;
 			struct sk_buff *skb;
+			int rx_in_place = 0;
 
 			/* Check if the packet is long enough to just accept without
 			   copying to a properly sized skbuff. */
-			if (pkt_len < rx_copybreak
-				&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
-				skb->dev = dev;
-				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				/* 'skb_put()' points to the start of sk_buff data area. */
-#if defined(__i386)   &&  notyet
+			if (pkt_len > rx_copybreak) {
+				struct sk_buff *newskb;
+				char *temp;
+
+				/* Pass up the skb already on the Rx ring. */
+				skb = sp->rx_skbuff[entry];
+#ifdef KERNEL_1_2
+				temp = skb->data;
+				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
+					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
+						   " in speedo_rx: %p vs. %p / %p.\n", dev->name,
+						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+						   temp, skb->data);
+				/* Get a fresh skbuff to replace the filled one. */
+				newskb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
+#else
+				temp = skb_put(skb, pkt_len);
+				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
+					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
+						   " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name,
+						   sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp);
+				/* Get a fresh skbuff to replace the filled one. */
+				newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+#endif
+				if (newskb) {
+					struct RxFD *rxf;
+					rx_in_place = 1;
+					sp->rx_skbuff[entry] = newskb;
+					newskb->dev = dev;
+#ifdef KERNEL_1_2
+					/* Restore the data in the old header region. */
+					memcpy(skb->data - sizeof(struct RxFD),
+						   &sp->saved_skhead[entry], sizeof(struct RxFD));
+					/* Save the data in this header region. */
+					rxf = (struct RxFD *)(newskb->data - sizeof(struct RxFD));
+					sp->rx_ringp[entry] = rxf;
+					memcpy(&sp->saved_skhead[entry], rxf, sizeof(struct RxFD));
+					rxf->rx_buf_addr = virt_to_bus(newskb->data);
+#else
+					rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail;
+					skb_reserve(newskb, sizeof(struct RxFD));
+					/* Unused by i82557, consistency check only. */
+					rxf->rx_buf_addr = virt_to_bus(newskb->tail);
+#endif
+					rxf->status = 0x00000001;
+				} else			/* No memory, drop the packet. */
+				  skb = 0;
+			} else
+#ifdef KERNEL_1_2
+				skb = alloc_skb(pkt_len, GFP_ATOMIC);
+#else
+				skb = dev_alloc_skb(pkt_len + 2);
+#endif
+			if (skb == NULL) {
+				int i;
+				printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);
+				/* Check that at least two ring entries are free.
+				   If not, free one and mark stats->rx_dropped++. */
+				/* ToDo: This is not correct!!!!  We should count the number
+				   of linked-in Rx buffer to very that we have at least two
+				   remaining. */
+				for (i = 0; i < RX_RING_SIZE; i++)
+					if (! ((sp->rx_ringp[(entry+i) % RX_RING_SIZE]->status)
+						   & RX_COMPLETE))
+						break;
+
+				if (i > RX_RING_SIZE -2) {
+					sp->stats.rx_dropped++;
+					sp->rx_ringp[entry]->status = 0;
+					sp->cur_rx++;
+				}
+				break;
+			}
+			skb->dev = dev;
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
+			if (! rx_in_place) {
+				skb_reserve(skb, 2);	/* 16 byte align the data fields */
+#if defined(__i386__)   &&  notyet
 				/* Packet is in one chunk -- we can copy + cksum. */
-				eth_io_copy_and_sum(skb,
-								bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+				eth_io_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
 									pkt_len, 0);
 #else
 				memcpy(skb_put(skb, pkt_len),
 					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
 #endif
-			} else {
-				void *temp;
-				/* Pass up the already-filled skbuff. */
-				skb = sp->rx_skbuff[entry];
-				sp->rx_skbuff[entry] = NULL;
-				temp = skb_put(skb, pkt_len);
-				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
-					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
-						   " in speedo_rx: %p vs. %p / %p.\n", dev->name,
-						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
-						   skb->head, temp);
 			}
 			skb->protocol = eth_type_trans(skb, dev);
+#else
+#ifdef KERNEL_1_3
+#warning This code has only been tested with later 1.3.* kernels.
+			skb->len = pkt_len;
+			memcpy(skb->data, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+				   pkt_len);
+			/* Needed for 1.3.*. */
+			skb->protocol = eth_type_trans(skb, dev);
+#else	/* KERNEL_1_2 */
+			skb->len = pkt_len;
+			if (! rx_in_place) {
+				memcpy(skb->data,
+					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
+			}
+#endif
+#endif
 			netif_rx(skb);
 			sp->stats.rx_packets++;
 		}
-		entry = (++sp->cur_rx) % RX_RING_SIZE;
-		if (--rx_work_limit < 0)
-			break;
-	}
 
-	/* Refill the Rx ring buffers. */
-	for (; sp->dirty_rx < sp->cur_rx; sp->dirty_rx++) {
-		struct RxFD *rxf;
-		entry = sp->dirty_rx % RX_RING_SIZE;
-		if (sp->rx_skbuff[entry] == NULL) {
-			struct sk_buff *skb;
-			/* Get a fresh skbuff to replace the consumed one. */
-			skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
-			sp->rx_skbuff[entry] = skb;
-			if (skb == NULL) {
-				sp->rx_ringp[entry] = NULL;
-				break;			/* Better luck next time!  */
-			}
-			rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
-			skb->dev = dev;
-			skb_reserve(skb, sizeof(struct RxFD));
-			rxf->rx_buf_addr = virt_to_bus(skb->tail);
-		} else {
-			rxf = sp->rx_ringp[entry];
+		/*	ToDo: This is better than before, but should be checked. */
+		{
+			struct RxFD *rxf = sp->rx_ringp[entry];
+			rxf->status = 0xC0000003; 		/* '3' for verification only */
+			rxf->link = 0;			/* None yet. */
+			rxf->count = 0;
+			rxf->size = PKT_BUF_SZ;
+			sp->last_rxf->link = virt_to_bus(rxf);
+			sp->last_rxf->status &= ~0xC0000000;
+			sp->last_rxf = rxf;
+			entry = (++sp->cur_rx) % RX_RING_SIZE;
 		}
-		rxf->status = 0xC0000001; 	/* '2' for driver use only. */
-		rxf->link = 0;			/* None yet. */
-		rxf->count = 0;
-		rxf->size = PKT_BUF_SZ;
-		sp->last_rxf->link = virt_to_bus(rxf);
-		sp->last_rxf->status &= ~0xC0000000;
-		sp->last_rxf = rxf;
 	}
 
 	sp->last_rx_time = jiffies;
@@ -1265,7 +1428,7 @@
 static int
 speedo_close(struct device *dev)
 {
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
 	int i;
 
@@ -1291,7 +1454,7 @@
 		sp->rx_skbuff[i] = 0;
 		/* Clear the Rx descriptors. */
 		if (skb)
-			dev_free_skb(skb);
+			dev_kfree_skb(skb);
 	}
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
@@ -1299,7 +1462,7 @@
 		sp->tx_skbuff[i] = 0;
 		/* Clear the Tx descriptors. */
 		if (skb)
-			dev_free_skb(skb);
+			dev_kfree_skb(skb);
 	}
 	if (sp->mc_setup_frm) {
 		kfree(sp->mc_setup_frm);
@@ -1344,7 +1507,7 @@
 speedo_get_stats(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 
 	if (sp->lstats.done_marker == 0xA007) {	/* Previous dump finished */
 		sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs;
@@ -1367,10 +1530,11 @@
 	return &sp->stats;
 }
 
+#ifdef HAVE_PRIVATE_IOCTL
 static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 	int phy = sp->phy[0] & 0x1f;
 
@@ -1381,7 +1545,7 @@
 		data[3] = mdio_read(ioaddr, data[0], data[1]);
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!suser())
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		mdio_write(ioaddr, data[0], data[1], data[2]);
 		return 0;
@@ -1389,6 +1553,7 @@
 		return -EOPNOTSUPP;
 	}
 }
+#endif  /* HAVE_PRIVATE_IOCTL */
 
 /* Set or clear the multicast filter for this adaptor.
    This is very ugly with Intel chips -- we usually have to execute an
@@ -1403,15 +1568,14 @@
 set_rx_mode(struct device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	char new_rx_mode;
 	unsigned long flags;
 	int entry, i;
 
 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
 		new_rx_mode = 3;
-	} else if ((dev->flags & IFF_ALLMULTI)  ||
-			   dev->mc_count > multicast_filter_limit) {
+	} else if (dev->flags & IFF_ALLMULTI) {
 		new_rx_mode = 1;
 	} else
 		new_rx_mode = 0;
@@ -1425,13 +1589,12 @@
 
 	if (new_rx_mode != sp->rx_mode) {
 		/* We must change the configuration. Construct a CmdConfig frame. */
-		memcpy(sp->config_cmd_data, i82558_config_cmd,
-			   sizeof(i82558_config_cmd));
+		memcpy(sp->config_cmd_data, basic_config_cmd,sizeof(basic_config_cmd));
 		sp->config_cmd_data[1] = (txfifo << 4) | rxfifo;
 		sp->config_cmd_data[4] = rxdmacount;
 		sp->config_cmd_data[5] = txdmacount + 0x80;
-		sp->config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
-		sp->config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
+		sp->config_cmd_data[15] = (new_rx_mode & 2) ? 0x49 : 0x48;
+		sp->config_cmd_data[19] = sp->full_duplex ? 0xC0 : 0x80;
 		sp->config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
 		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
 		  sp->config_cmd_data[15] |= 0x80;
@@ -1463,11 +1626,11 @@
 		}
 	}
 
-	if (new_rx_mode == 0  &&  dev->mc_count < 4) {
-		/* The simple case of 0-3 multicast list entries occurs often, and
+	if (new_rx_mode == 0  &&  dev->mc_count < 3) {
+		/* The simple case of 0-2 multicast list entries occurs often, and
 		   fits within one tx_ring[] entry. */
-		struct dev_mc_list *mclist;
 		u16 *setup_params, *eaddrs;
+		struct dev_mc_list *mclist;
 
 		save_flags(flags);
 		cli();
@@ -1495,9 +1658,11 @@
 		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
 		restore_flags(flags);
 	} else if (new_rx_mode == 0) {
+		/* This does not work correctly, but why not? */
 		struct dev_mc_list *mclist;
-		u16 *setup_params, *eaddrs;
+		u16 *eaddrs;
 		struct descriptor *mc_setup_frm = sp->mc_setup_frm;
+		u16 *setup_params = (u16 *)mc_setup_frm->params;
 		int i;
 
 		if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
@@ -1509,8 +1674,7 @@
 			sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24;
 			sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC);
 			if (sp->mc_setup_frm == NULL) {
-			  printk(KERN_ERR "%s: Failed to allocate a setup frame.\n",
-					 dev->name);
+			  printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", dev->name);
 				sp->rx_mode = -1; /* We failed, try again. */
 				return;
 			}
@@ -1524,7 +1688,7 @@
 		mc_setup_frm->status = 0;
 		mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
 		/* Link set below. */
-		setup_params = (u16 *)&mc_setup_frm->params;
+		setup_params = (u16 *)mc_setup_frm->params;
 		*setup_params++ = dev->mc_count*6;
 		/* Fill in the multicast addresses. */
 		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
@@ -1568,6 +1732,24 @@
 }
 
 #ifdef MODULE
+#if (LINUX_VERSION_CODE < VERSION(1,3,38))	/* 1.3.38 and later */
+char kernel_version[] = UTS_RELEASE;
+#endif
+
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+#endif
 
 int
 init_module(void)
@@ -1614,8 +1796,7 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
--- v2.1.112/linux/drivers/scsi/53c7xx.c	Sun Jun  7 11:16:33 1998
+++ linux/drivers/scsi/53c7xx.c	Thu Jul 30 11:17:10 1998
@@ -40,7 +40,8 @@
  *
  * Options for the NCR7xx driver
  *
- * nosync:0		-	disables synchronous negotiation
+ * noasync:0		-	disables sync and asynchronous negotiation
+ * nosync:0		-	disables synchronous negotiation (does async)
  * nodisconnect:0	-	disables disconnection
  * validids:0x??	-	Bitmask field that disallows certain ID's.
  *			-	e.g.	0x03	allows ID 0,1
@@ -273,6 +274,15 @@
 #define VALID_IDS
 #endif
 
+#ifdef CONFIG_BVME6000
+#include <asm/pgtable.h>
+#include <asm/bvme6000hw.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#define VALID_IDS
+#endif
+
 #include "scsi.h"
 #include "hosts.h"
 #include "53c7xx.h"
@@ -315,7 +325,6 @@
 static int disable (struct Scsi_Host *host);
 static int NCR53c7xx_run_tests (struct Scsi_Host *host);
 static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
-static void do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
 static int ncr_halt (struct Scsi_Host *host);
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
     *cmd);
@@ -347,7 +356,6 @@
 #ifdef FORCE_DSA_ALIGNMENT
 int CmdPageStart = (0 - Ent_dsa_zero - sizeof(struct NCR53c7x0_cmd)) & 0xff;
 #endif
-int flushsize;
 
 static char *setup_strings[] =
 	{"","","","","","","",""};
@@ -705,7 +713,7 @@
 	    h->max_id);
 	return -1;
     }
-    hostdata = (struct NCR53c7x0_hostdata *)h->hostdata;
+    hostdata = (struct NCR53c7x0_hostdata *)h->hostdata[0];
 
     save_flags(flags);
     cli();
@@ -738,7 +746,7 @@
     struct NCR53c7x0_hostdata *hostdata;
     if (!(h = find_host (host)))
 	return -1;
-    hostdata = (struct NCR53c7x0_hostdata *) h->hostdata;
+    hostdata = (struct NCR53c7x0_hostdata *) h->hostdata[0];
     if (on_or_off) 
 	hostdata->options |= OPTION_DISCONNECT;
     else
@@ -759,7 +767,7 @@
 static void 
 NCR53c7x0_driver_init (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int i, j;
     u32 *ncrcurrent;
 
@@ -791,9 +799,6 @@
     	hostdata->initiate_sdtr = 0;
     hostdata->talked_to = 0;
     hostdata->idle = 1;
-
-    if (!MACH_IS_MVME16x)
-	cache_push(virt_to_bus(hostdata->script), flushsize);
 }
 
 /* 
@@ -841,7 +846,7 @@
     int i, ccf;
     unsigned char revision;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     struct Scsi_Host *search;
     /* 
      * There are some things which we need to know about in order to provide
@@ -864,12 +869,17 @@
 	hostdata->valid_ids[i] = 1;	/* Default all ID's to scan */
 
     /* Parse commandline flags */
-    if (check_setup_strings("nosync",&flags,&val,buf))
+    if (check_setup_strings("noasync",&flags,&val,buf))
     {
 	hostdata->options |= OPTION_NO_ASYNC;
 	hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
     }
 
+    if (check_setup_strings("nosync",&flags,&val,buf))
+    {
+	hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
+    }
+
     if (check_setup_strings("nodisconnect",&flags,&val,buf))
 	hostdata->options &= ~OPTION_DISCONNECT;
 
@@ -982,26 +992,23 @@
      * default value may not be optimal anyway.
      * Even worse, it may never have been set up since reset.
      */
-	hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
-	revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
-	switch (revision) {
-		case 1:
-			revision = 0;
-			break;
-		case 2:
-			revision = 1;
-			break;
-		case 4: 
-			revision = 2;
-			break;
-		case 8:
-			revision = 3;
-			break;
-		default:
-			revision = 255;
-			break;
-	}
-	printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+    hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
+    revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
+    switch (revision) {
+	case 1: revision = 0;    break;
+	case 2: revision = 1;    break;
+	case 4: revision = 2;    break;
+	case 8: revision = 3;    break;
+	default: revision = 255; break;
+    }
+    printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+
+    if ((revision == 0 || revision == 255) && (hostdata->options & (OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS)))
+    {
+	printk ("scsi%d: Disabling sync working and disconnect/reselect\n",
+							host->host_no);
+	hostdata->options &= ~(OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS);
+    }
 
     /*
      * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
@@ -1070,28 +1077,13 @@
      * with another board.
      */
 
-#ifdef CONFIG_MVME16x
-    if (request_irq(IRQ_MVME16x_SCSI, do_NCR53c7x0_intr, 0, "SCSI-script", NULL))
-	panic ("Couldn't get SCSI IRQ");
-#ifdef MVME16x_INTFLY
-    else if (request_irq(IRQ_MVME16x_FLY, do_NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
-	panic ("Couldn't get INT_FLY IRQ");
-#endif
-#else
     for (search = first_host; search && !(search->hostt == the_template &&
 	search->irq == host->irq && search != host); search=search->next);
 
     if (!search) {
-#ifdef CONFIG_AMIGA
-	if (request_irq(IRQ_AMIGA_PORTS, do_NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
-#else
-	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
-#endif
-	    printk("scsi%d : IRQ%d not free, detaching\n"
-	           "         You have either a configuration problem, or a\n"
-                   "         broken BIOS.  You may wish to manually assign\n"
-	           "         an interrupt to the NCR board rather than using\n"
-                   "         an automatic setting.\n", 
+	if (request_irq(host->irq, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr))
+	{
+	    printk("scsi%d : IRQ%d not free, detaching\n",
 		host->host_no, host->irq);
 	    scsi_unregister (host);
 	    return -1;
@@ -1100,7 +1092,6 @@
 	printk("scsi%d : using interrupt handler previously installed for scsi%d\n",
 	    host->host_no, search->host_no);
     }
-#endif
 
     if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
         (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
@@ -1219,20 +1210,27 @@
     */
     size += 256;
 #endif
-	flushsize = size;
-    instance = scsi_register (tpnt, size);
+    /* Size should be < 8K, so we can fit it in two pages. */
+    if (size > 8192)
+      panic("53c7xx: hostdata > 8K");
+    instance = scsi_register (tpnt, 4);
     if (!instance)
 	return -1;
+    instance->hostdata[0] = __get_free_pages(GFP_ATOMIC, 1);
+    if (instance->hostdata[0] == 0)
+        panic ("53c7xx: Couldn't get hostdata memory");
+    memset((void *)instance->hostdata[0], 0, 8192);
+    cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
+    cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
+    kernel_set_cachemode(instance->hostdata[0], 8192, KERNELMAP_NOCACHE_SER);
 
     /* FIXME : if we ever support an ISA NCR53c7xx based board, we
        need to check if the chip is running in a 16 bit mode, and if so 
        unregister it if it is past the 16M (0x1000000) mark */
 
-    hostdata = (struct NCR53c7x0_hostdata *) 
-    	instance->hostdata;
+    hostdata = (struct NCR53c7x0_hostdata *)instance->hostdata[0];
     hostdata->size = size;
     hostdata->script_count = script_len / sizeof(u32);
-    hostdata = (struct NCR53c7x0_hostdata *) instance->hostdata;
     hostdata->board = board;
     hostdata->chip = chip;
 
@@ -1292,10 +1290,12 @@
 	    t = (void *)((u32)t + 255);
 	t = (void *)(((u32)t & ~0xff) + CmdPageStart);
         hostdata->free = t;
+#if 0
 	printk ("scsi: Registered size increased by 256 to %d\n", size);
 	printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart);
 	printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n",
 			(u32)tmp, (u32)t);
+#endif
     }
 #else
     hostdata->free = ROUNDUP(tmp, void *);
@@ -1350,7 +1350,7 @@
 NCR53c7x0_init_fixup (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned char tmp;
     int i, ncr_to_memory, memory_to_ncr;
     u32 base;
@@ -1407,7 +1407,7 @@
      * register.  Make sure SCRIPTS start automagically.
      */
 
-#if defined(CONFIG_MVME16x)
+#if defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
     /* We know better what we want than 16xBug does! */
     tmp = DMODE_10_BL_8 | DMODE_10_FC2;
 #else
@@ -1557,9 +1557,6 @@
 
     printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
 	virt_to_bus(hostdata->script), hostdata->script);
-
-    if (!MACH_IS_MVME16x)
-	cache_push(virt_to_bus(hostdata->script), flushsize);
 }
 
 /*
@@ -1581,7 +1578,7 @@
 NCR53c7xx_run_tests (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned long timeout;
     u32 start;
     int failed, i;
@@ -1613,8 +1610,6 @@
 	start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
     	hostdata->state = STATE_RUNNING;
 	printk ("scsi%d : test 1", host->host_no);
-	if (!MACH_IS_MVME16x)
-	    cache_push(virt_to_bus(hostdata->script), flushsize);
 	NCR53c7x0_write32 (DSP_REG, start);
 	if (hostdata->options & OPTION_DEBUG_TRACE)
 	    NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
@@ -1708,8 +1703,6 @@
 	    hostdata->test_completed = -1;
 	    start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
 	    hostdata->state = STATE_RUNNING;
-	    if(!MACH_IS_MVME16x)
-		cache_clear(virt_to_bus(hostdata->script), flushsize);
 	    NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
 	    NCR53c7x0_write32 (DSP_REG, start);
 	    if (hostdata->options & OPTION_DEBUG_TRACE)
@@ -1768,7 +1761,7 @@
     Scsi_Cmnd *c = cmd->cmd;
     struct Scsi_Host *host = c->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-    	host->hostdata;
+    	host->hostdata[0];
     int i;
 
     memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
@@ -1815,11 +1808,6 @@
 
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
 	dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
-
-    if (!MACH_IS_MVME16x) {
-	cache_push(virt_to_bus(hostdata->script), flushsize);
-    	cache_push(virt_to_bus(cmd->dsa), flushsize);
-    }
 }
 
 /* 
@@ -1871,7 +1859,7 @@
     Scsi_Cmnd *c = cmd->cmd;
     struct Scsi_Host *host = c->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-    	host->hostdata;
+    	host->hostdata[0];
     unsigned long flags;
     int left, found;
     volatile struct NCR53c7x0_cmd * linux_search;
@@ -1991,7 +1979,7 @@
 #endif
     u32 *dsp;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;		
+	host->hostdata[0];		
     unsigned long flags;
     NCR53c7x0_local_setup(host);
 
@@ -2071,7 +2059,7 @@
     int now_connected) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) 
-	host->hostdata;
+	host->hostdata[0];
     u32 *script;
     NCR53c7x0_local_setup(host);
 
@@ -2146,7 +2134,7 @@
 asynchronous (struct Scsi_Host *host, int target) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     NCR53c7x0_local_setup(host);
     set_synchronous (host, target, /* no offset */ 0, hostdata->saved_scntl3,
 	1);
@@ -2205,7 +2193,7 @@
 static void 
 synchronous (struct Scsi_Host *host, int target, char *msg) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int desire, divisor, i, limit;
     unsigned char scntl3, sxfer;
 /* The diagnostic message fits on one line, even with max. width integers */
@@ -2267,7 +2255,7 @@
     int print;
     Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;		
+	host->hostdata[0];		
     u32 dsps,*dsp;	/* Argument of the INT instruction */
 
     NCR53c7x0_local_setup(host);
@@ -2280,7 +2268,7 @@
     /* RGH 200597:  Need to disable for BVME6000, as it gets Check Conditions
      * and then dies.  Seems to handle Check Condition at startup, but
      * not mid kernel build. */
-    if (dsps == A_int_norm_emulateintfly && c && c->result == 2)
+    if (dsps == A_int_norm_emulateintfly && cmd && cmd->result == 2)
         dsps = A_int_err_check_condition;
 #endif
 
@@ -2459,12 +2447,23 @@
 
     	patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
 
-	c->cmnd[0] = REQUEST_SENSE;
-	c->cmnd[1] &= 0xe0;	/* Zero all but LUN */
-	c->cmnd[2] = 0;
-	c->cmnd[3] = 0;
-	c->cmnd[4] = sizeof(c->sense_buffer);
-	c->cmnd[5] = 0; 
+        /*
+         * The CDB is now mirrored in our local non-cached
+         * structure, but keep the old structure up to date as well,
+         * just in case anyone looks at it.
+         */
+
+	/*
+	 * XXX Need to worry about data buffer alignment/cache state
+	 * XXX here, but currently never get A_int_err_check_condition,
+	 * XXX so ignore problem for now.
+         */
+	cmd->cmnd[0] = c->cmnd[0] = REQUEST_SENSE;
+	cmd->cmnd[0] = c->cmnd[1] &= 0xe0;	/* Zero all but LUN */
+	cmd->cmnd[0] = c->cmnd[2] = 0;
+	cmd->cmnd[0] = c->cmnd[3] = 0;
+	cmd->cmnd[0] = c->cmnd[4] = sizeof(c->sense_buffer);
+	cmd->cmnd[0] = c->cmnd[5] = 0; 
 
 	/*
 	 * Disable dataout phase, and program datain to transfer to the 
@@ -2492,7 +2491,7 @@
 	 * status, etc are used.
     	 */
 
-	cmd->cmd->result = 0xffff;		
+	cmd->result = cmd->cmd->result = 0xffff;		
 
 	/* 
 	 * Restart command as a REQUEST SENSE.
@@ -2888,9 +2887,6 @@
 	    host->host_no, (unsigned) dsps);
 	return SPECIFIC_INT_PANIC;
     }
-
-    if (!MACH_IS_MVME16x)
-	flush_cache_all();
 }
 
 /* 
@@ -2928,11 +2924,8 @@
 NCR53c7x0_soft_reset (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     unsigned long flags;
-#ifdef CONFIG_MVME16x
-    volatile unsigned long v;
-#endif
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     NCR53c7x0_local_setup(host);
 
     save_flags(flags);
@@ -2941,15 +2934,19 @@
     /* Disable scsi chip and s/w level 7 ints */
 
 #ifdef CONFIG_MVME16x
-    v = *(volatile unsigned long *)0xfff4006c;
-    v &= ~0x8000;
-    *(volatile unsigned long *)0xfff4006c = v;
-    v = *(volatile unsigned long *)0xfff4202c;
-    v &= ~0x10;
-    *(volatile unsigned long *)0xfff4202c = v;
-#else
-    /* Anything specific for your hardware? */
+    if (MACH_IS_MVME16x)
+    {
+        volatile unsigned long v;
+
+        v = *(volatile unsigned long *)0xfff4006c;
+        v &= ~0x8000;
+        *(volatile unsigned long *)0xfff4006c = v;
+        v = *(volatile unsigned long *)0xfff4202c;
+        v &= ~0x10;
+        *(volatile unsigned long *)0xfff4202c = v;
+    }
 #endif
+    /* Anything specific for your hardware? */
 
     /*
      * Do a soft reset of the chip so that everything is 
@@ -3016,20 +3013,23 @@
 		SIEN_SGE | SIEN_MA);
 
 #ifdef CONFIG_MVME16x
-    /* Enable scsi chip and s/w level 7 ints */
+    if (MACH_IS_MVME16x)
+    {
+        volatile unsigned long v;
 
-    v = *(volatile unsigned long *)0xfff40080;
-    v = (v & ~(0xf << 28)) | (4 << 28);
-    *(volatile unsigned long *)0xfff40080 = v;
-    v = *(volatile unsigned long *)0xfff4006c;
-    v |= 0x8000;
-    *(volatile unsigned long *)0xfff4006c = v;
-    v = *(volatile unsigned long *)0xfff4202c;
-    v = (v & ~0xff) | 0x10 | 4;
-    *(volatile unsigned long *)0xfff4202c = v;
-#else
-    /* Anything needed for your hardware */
+        /* Enable scsi chip and s/w level 7 ints */
+        v = *(volatile unsigned long *)0xfff40080;
+        v = (v & ~(0xf << 28)) | (4 << 28);
+        *(volatile unsigned long *)0xfff40080 = v;
+        v = *(volatile unsigned long *)0xfff4006c;
+        v |= 0x8000;
+        *(volatile unsigned long *)0xfff4006c = v;
+        v = *(volatile unsigned long *)0xfff4202c;
+        v = (v & ~0xff) | 0x10 | 4;
+        *(volatile unsigned long *)0xfff4202c = v;
+    }
 #endif
+    /* Anything needed for your hardware? */
     restore_flags(flags);
 }
 
@@ -3042,7 +3042,7 @@
  *
  * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
  *	structures for this device, do so.  Attempt to complete all scheduled
- *	allocations using kmalloc(), putting NCR53c7x0_cmd structures on
+ *	allocations using get_free_page(), putting NCR53c7x0_cmd structures on
  *	the free list.  Teach programmers not to drink and hack.
  *
  * Inputs : cmd - SCSI command
@@ -3051,12 +3051,22 @@
  *	NULL on failure.
  */
 
+static void
+my_free_page (void *addr, int dummy)
+{
+    /* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING, which
+     * XXX may be invalid (CONFIG_060_WRITETHROUGH)
+     */
+    kernel_set_cachemode((u32)addr, 4096, KERNELMAP_FULL_CACHING);
+    free_page ((u32)addr);
+}
+
 static struct NCR53c7x0_cmd *
 allocate_cmd (Scsi_Cmnd *cmd) {
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) host->hostdata;
-    void *real;			/* Real address */
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
+    u32 real;			/* Real address */
     int size;			/* Size of *tmp */
     struct NCR53c7x0_cmd *tmp;
     unsigned long flags;
@@ -3094,28 +3104,31 @@
 	size += 256;
 #endif
 /* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
-	real = kmalloc (size, GFP_ATOMIC);
-	if (!real) {
-	    if (hostdata->options & OPTION_DEBUG_ALLOCATION)
-		printk ("scsi%d : kmalloc(%d) failed\n",
-		    host->host_no, size);
-	    break;
-	}
+
+        if (size > 4096)
+            panic ("53c7xx: allocate_cmd size > 4K");
+        real = get_free_page(GFP_ATOMIC);
+        if (real == 0)
+            panic ("53c7xx: Couldn't get memory for allocate_cmd");
+        memset((void *)real, 0, 4096);
+        cache_push(virt_to_phys((void *)real), 4096);
+        cache_clear(virt_to_phys((void *)real), 4096);
+        kernel_set_cachemode(real, 4096, KERNELMAP_NOCACHE_SER);
 	tmp = ROUNDUP(real, void *);
 #ifdef FORCE_DSA_ALIGNMENT
 	{
 	    if (((u32)tmp & 0xff) > CmdPageStart)
 		tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
 	    tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
-#ifdef DEBUG
+#if 0
 	    printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
-			size, (u32)real, (u32)tmp);
+			size, real, (u32)tmp);
 #endif
 	}
 #endif
-	tmp->real = real;
+	tmp->real = (void *)real;
 	tmp->size = size;			
-	tmp->free = ((void (*)(void *, int)) kfree);
+	tmp->free = ((void (*)(void *, int)) my_free_page);
 	save_flags (flags);
 	cli();
 	tmp->next = hostdata->free;
@@ -3153,7 +3166,7 @@
     NCR53c7x0_local_declare();
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-        host->hostdata;	
+        host->hostdata[0];	
     struct NCR53c7x0_cmd *tmp; 	/* NCR53c7x0_cmd structure for this command */
     int datain,  		/* Number of instructions per phase */
 	dataout;
@@ -3172,6 +3185,14 @@
     if (!(tmp = allocate_cmd (cmd)))
 	return NULL;
 
+    /*
+     * Copy CDB and initialised result fields from Scsi_Cmnd to NCR53c7x0_cmd.
+     * We do this because NCR53c7x0_cmd may have a special cache mode
+     * selected to cope with lack of bus snooping, etc.
+     */
+
+    memcpy(tmp->cmnd, cmd->cmnd, 12);
+    tmp->result = cmd->result;
 
     /*
      * Decide whether we need to generate commands for DATA IN,
@@ -3186,6 +3207,8 @@
     case READ_10:
     case READ_CAPACITY:
     case REQUEST_SENSE:
+    case READ_BLOCK_LIMITS:
+    case READ_TOC:
 	datain = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
     	dataout = 0;
 	break;
@@ -3213,13 +3236,17 @@
      * interrupt if a data phase is attempted on them.
      */
     case TEST_UNIT_READY:
+    case ALLOW_MEDIUM_REMOVAL:
     	datain = dataout = 0;
 	break;
     /*
      * We don't know about these commands, so generate code to handle
-     * both DATA IN and DATA OUT phases.
+     * both DATA IN and DATA OUT phases.  More efficient to identify them
+     * and add them to the above cases.
      */
     default:
+	printk("scsi%d : datain+dataout for command ", host->host_no);
+	print_command(cmd->cmnd);
 	datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
     }
 
@@ -3301,6 +3328,10 @@
     	hostdata->dsa_fixup(tmp);
 
     patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+    /*
+     * XXX is this giving 53c710 access to the Scsi_Cmnd in some way?
+     * Do we need to change it for caching reasons?
+     */
     patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
 
     if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
@@ -3362,7 +3393,7 @@
 	IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
     patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
     patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
-    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(tmp->cmnd));
     patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? 
     	    virt_to_bus (cmd_dataout)
 	: virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
@@ -3380,13 +3411,13 @@
  *	structure, and assign them to cmd->result when we're done.
  */
 #ifdef BIG_ENDIAN
-    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 2);
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 2);
     patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result) + 3);
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result) + 3);
 #else
-    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 1);
     patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result));
 #endif
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 1, 
@@ -3430,16 +3461,58 @@
  * Not bad, not good. We'll see.
  */
 
+    tmp->bounce.len = 0;	/* Assume aligned buffer */
+
     for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4, 
 	cmd_dataout += 4, ++i) {
-	u32 buf = cmd->use_sg ? 
-	    virt_to_bus(((struct scatterlist *)cmd->buffer)[i].address) :
-	    virt_to_bus(cmd->request_buffer);
+	u32 vbuf = cmd->use_sg ? 
+	    (u32)(((struct scatterlist *)cmd->buffer)[i].address) :
+	    (u32)(cmd->request_buffer);
+	u32 bbuf = virt_to_bus((void *)vbuf);
 	u32 count = cmd->use_sg ?
 	    ((struct scatterlist *)cmd->buffer)[i].length :
 	    cmd->request_bufflen;
 
+	/*
+	 * If we have buffers which are not aligned with 16 byte cache
+	 * lines, then we just hope nothing accesses the other parts of
+	 * those cache lines while the transfer is in progress.  That would
+	 * fill the cache, and subsequent reads of the dma data would pick
+	 * up the wrong thing.
+	 * XXX We need a bounce buffer to handle that correctly.
+	 */
+
+	if (((bbuf & 15) || (count & 15)) && (datain || dataout))
+	{
+	    /* Bounce buffer needed */
+	    if (cmd->use_sg)
+		printk ("53c7xx: Non-aligned buffer with use_sg\n");
+	    else if (datain && dataout)
+                printk ("53c7xx: Non-aligned buffer with datain && dataout\n");
+            else if (count > 256)
+		printk ("53c7xx: Non-aligned transfer > 256 bytes\n");
+	    else
+	    {
+		    if (datain)
+		    {
+			tmp->bounce.len = count;
+			tmp->bounce.addr = vbuf;
+			bbuf = virt_to_bus(tmp->bounce.buf);
+			tmp->bounce.buf[0] = 0xff;
+			tmp->bounce.buf[1] = 0xfe;
+			tmp->bounce.buf[2] = 0xfd;
+			tmp->bounce.buf[3] = 0xfc;
+	    	    }
+	    	    if (dataout)
+	    	    {
+			memcpy ((void *)tmp->bounce.buf, (void *)vbuf, count);
+			bbuf = virt_to_bus(tmp->bounce.buf);
+		    }
+	    }
+	}
+
 	if (datain) {
+            cache_clear(virt_to_phys((void *)vbuf), count);
 	    /* CALL other_in, WHEN NOT DATA_IN */  
 	    cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
 		DCMD_TCI_IO) << 24) | 
@@ -3449,13 +3522,14 @@
 	    /* MOVE count, buf, WHEN DATA_IN */
 	    cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
     	    	<< 24) | count;
-	    cmd_datain[3] = buf;
+	    cmd_datain[3] = bbuf;
 #if 0
 	    print_insn (host, cmd_datain, "dynamic ", 1);
 	    print_insn (host, cmd_datain + 2, "dynamic ", 1);
 #endif
 	}
 	if (dataout) {
+            cache_push(virt_to_phys((void *)vbuf), count);
 	    /* CALL other_out, WHEN NOT DATA_OUT */
 	    cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) | 
 		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
@@ -3464,7 +3538,7 @@
 	    /* MOVE count, buf, WHEN DATA+OUT */
 	    cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24) 
 		| count;
-	    cmd_dataout[3] = buf;
+	    cmd_dataout[3] = bbuf;
 #if 0
 	    print_insn (host, cmd_dataout, "dynamic ", 1);
 	    print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -3534,7 +3608,7 @@
 NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) host->hostdata;
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     unsigned long flags;
     Scsi_Cmnd *tmp;
 
@@ -3712,9 +3786,6 @@
      * soon as it is idle.
      */
 
-    if (!MACH_IS_MVME16x)
-	flush_cache_all();
-
     if (hostdata->idle) {
 	hostdata->idle = 0;
 	hostdata->state = STATE_RUNNING;
@@ -3788,7 +3859,7 @@
 	done = 1;
 	for (host = first_host; host && host->hostt == the_template;
 	    host = host->next) {
-	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
 	    cli();
 	    if (hostdata->issue_queue) {
 	    	if (hostdata->state == STATE_DISABLED) {
@@ -3860,7 +3931,7 @@
 intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = 
-    	(struct NCR53c7x0_hostdata *) host->hostdata;
+    	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     unsigned char sstat0_sist0, sist1, 		/* Registers */
 	    fatal; 				/* Did a fatal interrupt 
 						   occur ? */
@@ -4051,7 +4122,7 @@
 	struct Scsi_Host *host = first_host;
 
 	while (cnt < 4096) {
-		printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4);
+		printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4);
 		if (++i == 4096)
 			i = 0;
 		cnt++;
@@ -4070,20 +4141,6 @@
 }
 #endif
 
-/* Function : NCR53c7x0_intr
- *
- * Purpose : grab the global io_request_lock spin lock before entering the
- *      real interrupt routine.
- */
-static void
-do_NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
-    unsigned long flags;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-    NCR53c7x0_intr(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
 /*
  * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
  *
@@ -4103,7 +4160,7 @@
     NCR53c7x0_local_declare();
     struct Scsi_Host *host;			/* Host we are looking at */
     unsigned char istat; 			/* Values of interrupt regs */
-    struct NCR53c7x0_hostdata *hostdata;	/* host->hostdata */
+    struct NCR53c7x0_hostdata *hostdata;	/* host->hostdata[0] */
     struct NCR53c7x0_cmd *cmd,			/* command which halted */
 	**cmd_prev_ptr;
     u32 *dsa;					/* DSA */
@@ -4138,7 +4195,7 @@
 							) {
     	    NCR53c7x0_local_setup(host);
 
-	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
 	    hostdata->dsp_changed = 0;
 	    interrupted = 0;
 	    have_intfly = 0;
@@ -4200,6 +4257,11 @@
 				host->host_no);
 				continue;
 			}
+                        /* Copy the result over now; may not be complete,
+			 * but subsequent tests may as well be done on
+                         * cached memory.
+                         */
+                        tmp->result = cmd->result;
 #if 0
 			printk ("scsi%d : looking at result of 0x%x\n",
 			    host->host_no, cmd->cmd->result);
@@ -4211,6 +4273,10 @@
 
 			search_found = 1;
 
+			if (cmd->bounce.len)
+			    memcpy ((void *)cmd->bounce.addr,
+				(void *)cmd->bounce.buf, cmd->bounce.len);
+
 			/* Important - remove from list _before_ done is called */
 			if (cmd_prev_ptr)
 			    *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
@@ -4341,8 +4407,6 @@
 #endif
 		
 		hostdata->state = STATE_RUNNING;
-		if (!MACH_IS_MVME16x)
-		    flush_cache_all();
 		NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
 		if (hostdata->options & OPTION_DEBUG_TRACE) {
 #ifdef CYCLIC_TRACE
@@ -4380,7 +4444,7 @@
     NCR53c7x0_local_declare();
 #endif
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
 /* FIXME : this probably should change for production kernels; at the 
    least, counter should move to a per-host structure. */
     static int counter = 5;
@@ -4557,7 +4621,7 @@
     u32 dbc_dcmd, *dsp, *dsp_next;
     unsigned char dcmd, sbcl;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-    	host->hostdata;
+    	host->hostdata[0];
     int residual;
     enum {ACTION_ABORT, ACTION_ABORT_PRINT, ACTION_CONTINUE} action = 
 	ACTION_ABORT_PRINT;
@@ -4751,9 +4815,6 @@
 	print_insn (host, hostdata->dsp, "", 1);
     }
 #endif
-
-    if (!MACH_IS_MVME16x)
-	cache_push(virt_to_bus(hostdata->script), flushsize);
 }
 
 /*
@@ -4827,7 +4888,7 @@
      */
 
     if (retry == NEVER) {
-    	printk(KERN_ALERT "          mail ricahrd@sleepie.demon.co.uk\n");
+    	printk(KERN_ALERT "          mail richard@sleepie.demon.co.uk\n");
     	FATAL (host);
     }
 }
@@ -4847,7 +4908,7 @@
 intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned char dstat;	/* DSTAT */	
     u32 *dsp,
 	*next_dsp,		/* Current dsp */
@@ -5098,7 +5159,7 @@
  * FIXME : (void *) cast in virt_to_bus should be unnecessary, because
  * 	it should take const void * as argument.
  */
-#ifndef CONFIG_MVME16x
+#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
 	sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)", 
 	    (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,  
 	    insn[0], insn[1], bus_to_virt (insn[1]));
@@ -5106,12 +5167,12 @@
 	/* Remove virtual addresses to reduce output, as they are the same */
 	sprintf(buf, "%s0x%x (+%x) : 0x%08x 0x%08x", 
 	    (prefix ? prefix : ""), (u32)insn, ((u32)insn -
-		(u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4, 
+		(u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4, 
 	    insn[0], insn[1]);
 #endif
 	tmp = buf + strlen(buf);
 	if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)  {
-#ifndef CONFIG_MVME16x
+#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
 	    sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2], 
 		bus_to_virt(insn[2]));
 #else
@@ -5153,7 +5214,7 @@
     NCR53c7x0_local_declare();
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *) 
-	host->hostdata : NULL;
+	host->hostdata[0] : NULL;
     unsigned long flags;
     struct NCR53c7x0_cmd *curr, **prev;
     Scsi_Cmnd *me, **last;
@@ -5244,7 +5305,8 @@
          &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
-	if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+	if ((curr->result & 0xff) != 0xff && (curr->result & 0xff00) != 0xff00) {
+            cmd->result = curr->result;
 	    if (prev)
 		*prev = (struct NCR53c7x0_cmd *) curr->next;
 	    curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
@@ -5275,13 +5337,14 @@
 	cmd->host_scribble = NULL;
     }
 
-    if (((cmd->result & 0xff00) == 0xff00) ||
-	((cmd->result & 0xff) == 0xff)) {
+    if (curr == NULL || ((curr->result & 0xff00) == 0xff00) ||
+		((curr->result & 0xff) == 0xff)) {
 	printk ("scsi%d : did this command ever run?\n", host->host_no);
-	cmd->result = DID_ABORT << 16;
+	    cmd->result = DID_ABORT << 16;
     } else {
 	printk ("scsi%d : probably lost INTFLY, normal completion\n", 
 	    host->host_no);
+        cmd->result = curr->result;
 /* 
  * FIXME : We need to add an additional flag which indicates if a 
  * command was ever counted as BUSY, so if we end up here we can
@@ -5334,7 +5397,7 @@
     Scsi_Cmnd *nuke_list = NULL;
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = 
-    	(struct NCR53c7x0_hostdata *) host->hostdata;
+    	(struct NCR53c7x0_hostdata *) host->hostdata[0];
 
     NCR53c7x0_local_setup(host);
     save_flags(flags);
@@ -5403,7 +5466,7 @@
 static int 
 insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) cmd->host->hostdata;
+	(struct NCR53c7x0_hostdata *) cmd->host->hostdata[0];
     struct NCR53c7x0_cmd *ncmd = 
 	(struct NCR53c7x0_cmd *) cmd->host_scribble;
     int offset = 0, buffers;
@@ -5472,6 +5535,16 @@
     char *where;
     u32 *ptr;
     NCR53c7x0_local_setup (cmd->host);
+
+    if (check_address ((unsigned long) ncmd,sizeof (struct NCR53c7x0_cmd)) == 0)
+    {
+	printk("\nNCR53c7x0_cmd fields:\n");
+	printk("  bounce.len=0x%x, addr=0x%0x, buf[]=0x%02x %02x %02x %02x\n",
+	    ncmd->bounce.len, ncmd->bounce.addr, ncmd->bounce.buf[0],
+	    ncmd->bounce.buf[1], ncmd->bounce.buf[2], ncmd->bounce.buf[3]);
+	printk("  result=%04x, cdb[0]=0x%02x\n", ncmd->result, ncmd->cmnd[0]);
+    }
+
     for (i = 0; i < 2; ++i) {
 	if (check_address ((unsigned long) ncmd, 
 	    sizeof (struct NCR53c7x0_cmd)) == -1) 
@@ -5509,7 +5582,7 @@
 static void 
 print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int i, len;
     char *ptr;
     Scsi_Cmnd *cmd;
@@ -5551,6 +5624,7 @@
     cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
     printk("        + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
 	   (u32) virt_to_bus(cmd));
+    /* XXX Maybe we should access cmd->host_scribble->result here. RGH */
     if (cmd) {
 	printk("               result = 0x%x, target = %d, lun = %d, cmd = ",
 	    cmd->result, cmd->target, cmd->lun);
@@ -5583,7 +5657,7 @@
 static void 
 print_queues (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     u32 *dsa, *next_dsa;
     volatile u32 *ncrcurrent;
     int left;
@@ -5666,7 +5740,7 @@
 print_lots (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) host->hostdata;
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     u32 *dsp_next, *dsp, *dsa, dbc_dcmd;
     unsigned char dcmd, sbcl;
     int i, size;
@@ -5688,7 +5762,7 @@
 	        "         DSPS=0x%x, TEMP=0x%x (virt 0x%p), DMODE=0x%x\n"
 		"         SXFER=0x%x, SCNTL3=0x%x\n"
 		"         %s%s%sphase=%s, %d bytes in SCSI FIFO\n"
-		"         STEST0=0x%x\n",
+		"         SCRATCH=0x%x, saved2_dsa=0x%0lx\n",
 	    host->host_no, dbc_dcmd, NCR53c7x0_read32(DNAD_REG),
 		bus_to_virt(NCR53c7x0_read32(DNAD_REG)),
 	    virt_to_bus(dsa), dsa,
@@ -5705,8 +5779,9 @@
 	    	SSTAT1_REG : SSTAT2_REG)),
 	    (NCR53c7x0_read8 ((hostdata->chip / 100) == 8 ? 
 		SSTAT1_REG : SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT,
-	    ((hostdata->chip / 100) == 8) ?
-		NCR53c7x0_read8 (STEST0_REG_800) : 0);
+	    ((hostdata->chip / 100) == 8) ? NCR53c7x0_read8 (STEST0_REG_800) :
+		NCR53c7x0_read32(SCRATCHA_REG_800),
+	    hostdata->saved2_dsa);
 	printk ("scsi%d : DSP 0x%lx (virt 0x%p) ->\n", host->host_no, 
 	    virt_to_bus(dsp), dsp);
     	for (i = 6; i > 0; --i, dsp += size)
@@ -5741,7 +5816,7 @@
     NCR53c7x0_local_declare();
     unsigned long flags;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     NCR53c7x0_local_setup(host);
     save_flags (flags);
     cli();
@@ -5782,7 +5857,7 @@
 static void 
 hard_reset (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned long flags;
     save_flags (flags);
     cli();
@@ -5817,7 +5892,7 @@
 static Scsi_Cmnd *
 return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     struct NCR53c7x0_cmd *c;
     int i;
     u32 *ncrcurrent;
@@ -5883,7 +5958,7 @@
 static int 
 disable (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned long flags;
     Scsi_Cmnd *nuke_list, *tmp;
     save_flags(flags);
@@ -5922,7 +5997,7 @@
     unsigned long flags;
     unsigned char istat, tmp;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int stage;
     NCR53c7x0_local_setup(host);
 
@@ -6000,7 +6075,7 @@
 static void
 dump_events (struct Scsi_Host *host, int count) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     struct NCR53c7x0_event event;
     int i;
     unsigned long flags;
@@ -6064,7 +6139,7 @@
 int 
 NCR53c7x0_release(struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) host->hostdata;
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     struct NCR53c7x0_cmd *cmd, *tmp;
     shutdown (host);
     if (host->irq != IRQ_NONE)
@@ -6098,6 +6173,12 @@
 	    host->host_no, hostdata->num_cmds);
     if (hostdata->events) 
 	vfree ((void *)hostdata->events);
+
+    /* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING, which
+     * XXX may be invalid (CONFIG_060_WRITETHROUGH)
+     */
+    kernel_set_cachemode((u32)hostdata, 8192, KERNELMAP_FULL_CACHING);
+    free_pages ((u32)hostdata, 1);
     return 1;
 }
 Scsi_Host_Template driver_template = NCR53c7xx;
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/53c7xx.h linux/drivers/scsi/53c7xx.h
--- v2.1.112/linux/drivers/scsi/53c7xx.h	Sun Jun  7 11:16:33 1998
+++ linux/drivers/scsi/53c7xx.h	Thu Jul 30 11:17:10 1998
@@ -1125,6 +1125,15 @@
 
     int flags;				/* CMD_* flags */
 
+    unsigned char      cmnd[12];	/* CDB, copied from Scsi_Cmnd */
+    int                result;		/* Copy to Scsi_Cmnd when done */
+
+    struct {				/* Private non-cached bounce buffer */
+        unsigned char buf[256];
+	u32	      addr;
+        u32           len;
+    } bounce;
+
 /*
  * SDTR and WIDE messages are an either/or affair
  * in this message, since we will go into message out and send
@@ -1547,7 +1556,7 @@
     NCR53c7x0_address_memory = (void *) (host)->base;			\
     NCR53c7x0_address_io = (unsigned int) (host)->io_port;		\
     NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) 		\
-	host->hostdata)-> options & OPTION_MEMORY_MAPPED 
+	host->hostdata[0])-> options & OPTION_MEMORY_MAPPED 
 
 #ifdef BIG_ENDIAN
 /* These could be more efficient, given that we are always memory mapped,
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.112/linux/drivers/scsi/Makefile	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/Makefile	Thu Jul 30 11:17:10 1998
@@ -115,6 +115,22 @@
     endif
 endif
 
+ifeq ($(CONFIG_MVME16x_SCSI),y)
+L_OBJS += mvme16x.o 53c7xx.o
+else
+  ifeq ($(CONFIG_MVME16x_SCSI),m)
+  M_OBJS += mvme16x.o 53c7xx.o
+  endif
+endif
+
+ifeq ($(CONFIG_BVME6000_SCSI),y)
+L_OBJS += bvme6000.o 53c7xx.o
+else
+  ifeq ($(CONFIG_BVME6000_SCSI),m)
+  M_OBJS += bvme6000.o 53c7xx.o
+  endif
+endif
+
 ifeq ($(CONFIG_A4000T_SCSI),y)
 L_OBJS += amiga7xx.o 53c7xx.o
 else
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/amiga7xx.c linux/drivers/scsi/amiga7xx.c
--- v2.1.112/linux/drivers/scsi/amiga7xx.c	Fri May  8 23:14:49 1998
+++ linux/drivers/scsi/amiga7xx.c	Thu Jul 30 11:17:10 1998
@@ -33,14 +33,17 @@
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
+extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip, 
+		       u32 base, int io_port, int irq, int dma,
+		       long long options, int clock);
+
 int amiga7xx_detect(Scsi_Host_Template *tpnt)
 {
     static unsigned char called = 0;
     unsigned int key;
-    int num = 0;
-    unsigned long address;
+    int num = 0, clock;
     long long options;
-    struct ConfigDev *cd;
+    const struct ConfigDev *cd;
 
     if (called || !MACH_IS_AMIGA)
 	return 0;
@@ -50,6 +53,7 @@
 #ifdef CONFIG_WARPENGINE_SCSI
     if ((key = zorro_find(ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, 0, 0)))
     {
+	unsigned long address;
 	cd = zorro_get_board(key);
 	address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
 		cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
@@ -83,8 +87,9 @@
 
 #ifdef CONFIG_A4091_SCSI
     while ( (key = zorro_find(ZORRO_PROD_CBM_A4091_1, 0, 0)) ||
-	 (key = zorro_find(ZORRO_PROD_CBM_A4091_2, 0, 0)) )
+	    (key = zorro_find(ZORRO_PROD_CBM_A4091_2, 0, 0)) )
     {
+	unsigned long address;
 	cd = zorro_get_board(key);
 	address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
 		cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/amiga7xx.h linux/drivers/scsi/amiga7xx.h
--- v2.1.112/linux/drivers/scsi/amiga7xx.h	Fri Jul 31 17:07:58 1998
+++ linux/drivers/scsi/amiga7xx.h	Thu Jul 30 11:17:10 1998
@@ -35,7 +35,7 @@
 		       bios_param:          scsicam_bios_param,   \
 		       can_queue:           24,       \
 		       this_id:             7,               \
-		       sg_tablesize:        127,          \
+		       sg_tablesize:        63,          \
 		       cmd_per_lun:	    3,     \
 		       use_clustering:      DISABLE_CLUSTERING }
 #endif
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- v2.1.112/linux/drivers/scsi/atari_scsi.c	Sun Jun  7 11:16:34 1998
+++ linux/drivers/scsi/atari_scsi.c	Thu Jul 30 11:17:10 1998
@@ -206,7 +206,9 @@
 static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
                                              hostdata );
 static void falcon_get_lock( void );
+#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
 static void atari_scsi_reset_boot( void );
+#endif
 static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
 static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value);
 static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
@@ -675,7 +677,9 @@
         * IDE and floppy! */
        instance->irq = 0;
 
+#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
 	atari_scsi_reset_boot();
+#endif
 	NCR5380_init (instance, 0);
 
 	if (IS_A_TT()) {
@@ -864,6 +868,7 @@
 }
 
 	
+#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
 __initfunc(static void atari_scsi_reset_boot( void ))
 {
 	unsigned long end;
@@ -892,6 +897,7 @@
 
 	printk( " done\n" );
 }
+#endif
 
 
 const char * atari_scsi_info (struct Scsi_Host *host)
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/bvme6000.c linux/drivers/scsi/bvme6000.c
--- v2.1.112/linux/drivers/scsi/bvme6000.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/bvme6000.c	Thu Jul 30 11:17:10 1998
@@ -0,0 +1,58 @@
+/*
+ * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane
+ */
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/zorro.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bvme6000hw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "53c7xx.h"
+#include "bvme6000.h"
+
+#include<linux/stat.h>
+
+struct proc_dir_entry proc_scsi_bvme6000 = {
+    PROC_SCSI_BVME6000, 8, "BVME6000",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+extern ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+			u32 base, int io_port, int irq, int dma,
+			long long options, int clock);
+
+int bvme6000_scsi_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    int clock;
+    long long options;
+
+    if (called)
+	return 0;
+    if (!MACH_IS_BVME6000)
+	return 0;
+
+    tpnt->proc_dir = &proc_scsi_bvme6000;
+
+    options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+    clock = 40000000;	/* 66MHz SCSI Clock */
+
+    ncr53c7xx_init(tpnt, 0, 710, (u32)BVME_NCR53C710_BASE,
+			0, BVME_IRQ_SCSI, DMA_NONE,
+			options, clock);
+    called = 1;
+    return 1;
+}
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/bvme6000.h linux/drivers/scsi/bvme6000.h
--- v2.1.112/linux/drivers/scsi/bvme6000.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/bvme6000.h	Thu Jul 30 11:17:10 1998
@@ -0,0 +1,43 @@
+#ifndef BVME6000_SCSI_H
+#define BVME6000_SCSI_H
+
+#include <linux/types.h>
+
+int bvme6000_scsi_detect(Scsi_Host_Template *);
+const char *NCR53c7x0_info(void);
+int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int NCR53c7xx_abort(Scsi_Cmnd *);
+int NCR53c7x0_release (struct Scsi_Host *);
+int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 3
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 24
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_mvme16x;
+
+#define BVME6000_SCSI  {name:                "BVME6000 NCR53c710 SCSI", \
+		       detect:              bvme6000_scsi_detect,    \
+		       queuecommand:        NCR53c7xx_queue_command, \
+		       abort:               NCR53c7xx_abort,   \
+		       reset:               NCR53c7xx_reset,   \
+		       bios_param:          scsicam_bios_param,   \
+		       can_queue:           24,       \
+		       this_id:             7,               \
+		       sg_tablesize:        63,          \
+		       cmd_per_lun:	    3,     \
+		       use_clustering:      DISABLE_CLUSTERING }
+#endif
+#endif /* BVME6000_SCSI_H */
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/fastlane.c linux/drivers/scsi/fastlane.c
--- v2.1.112/linux/drivers/scsi/fastlane.c	Tue Jun 23 10:01:24 1998
+++ linux/drivers/scsi/fastlane.c	Thu Jul 30 11:17:10 1998
@@ -289,7 +289,9 @@
 		(struct fastlane_dma_registers *) (esp->dregs);
 
 	dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
+#ifdef __mc68000__
 	nop();
+#endif
 	dregs->ctrl_reg = ctrl_data;
 }
 
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.1.112/linux/drivers/scsi/hosts.c	Wed Jul  1 19:38:54 1998
+++ linux/drivers/scsi/hosts.c	Thu Jul 30 11:17:10 1998
@@ -41,10 +41,18 @@
 
 #include "hosts.h"
 
-#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI)
+#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI) || defined (CONFIG_GVP_TURBO_SCSI)
 #include "amiga7xx.h"
 #endif
 
+#ifdef CONFIG_MVME16x_SCSI
+#include "mvme16x.h"
+#endif
+
+#ifdef CONFIG_BVME6000_SCSI
+#include "bvme6000.h"
+#endif
+
 #ifdef CONFIG_A3000_SCSI
 #include "a3000.h"
 #endif
@@ -295,7 +303,7 @@
 static Scsi_Host_Template builtin_scsi_hosts[] =
 {
 #ifdef CONFIG_AMIGA
-#if defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4000T_SCSI) || defined(CONFIG_A4091_SCSI)
+#if defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4000T_SCSI) || defined(CONFIG_A4091_SCSI) || defined (CONFIG_GVP_TURBO_SCSI)
 	AMIGA7XX_SCSI,
 #endif
 #ifdef CONFIG_A3000_SCSI
@@ -330,6 +338,12 @@
 #endif
 #endif
 
+#ifdef CONFIG_MVME16x_SCSI
+	MVME16x_SCSI,
+#endif
+#ifdef CONFIG_BVME6000_SCSI
+	BVME6000_SCSI,
+#endif
 #ifdef CONFIG_SCSI_ADVANSYS
 	ADVANSYS,
 #endif
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/mac_NCR5380.c linux/drivers/scsi/mac_NCR5380.c
--- v2.1.112/linux/drivers/scsi/mac_NCR5380.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/mac_NCR5380.c	Thu Jul 30 11:17:10 1998
@@ -0,0 +1,3139 @@
+/* 
+ * NCR 5380 generic driver routines.  These should make it *trivial*
+ * 	to implement 5380 SCSI drivers under Linux with a non-trantor
+ *	architecture.
+ *
+ *	Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing 
+ *	(Unix and Linux consulting and custom programming)
+ * 	drew@colorado.edu
+ *	+1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 6. 
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
+ * this file, too:
+ *
+ *  - Some of the debug statements were incorrect (undefined variables and the
+ *    like). I fixed that.
+ *
+ *  - In information_transfer(), I think a #ifdef was wrong. Looking at the
+ *    possible DMA transfer size should also happen for REAL_DMA. I added this
+ *    in the #if statement.
+ *
+ *  - When using real DMA, information_transfer() should return in a DATAOUT
+ *    phase after starting the DMA. It has nothing more to do.
+ *
+ *  - The interrupt service routine should run main after end of DMA, too (not
+ *    only after RESELECTION interrupts). Additionally, it should _not_ test
+ *    for more interrupts after running main, since a DMA process may have
+ *    been started and interrupts are turned on now. The new int could happen
+ *    inside the execution of NCR5380_intr(), leading to recursive
+ *    calls.
+ *
+ *  - I've added a function merge_contiguous_buffers() that tries to
+ *    merge scatter-gather buffers that are located at contiguous
+ *    physical addresses and can be processed with the same DMA setup.
+ *    Since most scatter-gather operations work on a page (4K) of
+ *    4 buffers (1K), in more than 90% of all cases three interrupts and
+ *    DMA setup actions are saved.
+ *
+ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
+ *    and USLEEP, because these were messing up readability and will never be
+ *    needed for Atari SCSI.
+ * 
+ * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
+ *   stuff), and 'main' is executed in a bottom half if awoken by an
+ *   interrupt.
+ *
+ * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
+ *   constructs. In my eyes, this made the source rather unreadable, so I
+ *   finally replaced that by the *_PRINTK() macros.
+ *
+ */
+
+/*
+ * Further development / testing that should be done : 
+ * 1.  Test linked command handling code after Eric is ready with 
+ *     the high level code.
+ */
+
+/* 
+ * Michael: To port Romans driver to the Macintosh, I've left most of the code 
+ * unchanged, in order to make later implemantation of REAL_DMA easier. 
+ *
+ * Alan: In order to make it easier to read and as the 5380 based Mac's never
+ *	  have DMA I took the real DMA out of mac_scsi.c but not this file.
+ *
+ *	With luck we can merge this back with the ST folks in time.
+ *
+ * Changes:
+ * 
+ * - all Falcon-specific stuff (ST-DMA locking) was removed
+ *
+ * 
+ */
+
+#if (NDEBUG & NDEBUG_LISTS)
+#define LIST(x,y) \
+  { printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
+    if ((x)==(y)) udelay(5); }
+#define REMOVE(w,x,y,z) \
+  { printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, \
+	   (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
+    if ((x)==(y)) udelay(5); }
+#else
+#define LIST(x,y)
+#define REMOVE(w,x,y,z)
+#endif
+
+#ifndef notyet
+#undef LINKED
+#endif
+
+/*
+ * Design
+ * Issues :
+ *
+ * The other Linux SCSI drivers were written when Linux was Intel PC-only,
+ * and specifically for each board rather than each chip.  This makes their
+ * adaptation to platforms like the Mac (Some of which use NCR5380's)
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queuing
+ * routines were implemented, meaning their implementations of queued 
+ * commands were hacked on rather than designed in from the start.
+ *
+ * When I designed the Linux SCSI drivers I figured that 
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+ * Finally, when I get questions from users, I have no idea what 
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+ * This is a generic 5380 driver.  To use it on a different platform, 
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use 
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * As far as command queueing, two queues are maintained for 
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing.  This means that an 
+ * unlimited number of commands may be queued, letting 
+ * more commands propagate from the higher driver levels giving higher 
+ * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
+ * allowing multiple commands to propagate all the way to a SCSI-II device 
+ * while a command is already executing.
+ *
+ * To solve the multiple-boards-in-the-same-system problem, 
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system.  So, multiple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+ * SCSI code.  
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+ * number (updated for each public release) printed by the 
+ * NCR5380_print_options command, which should be called from the 
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+ * Issues specific to the NCR5380 : 
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
+ * piece of hardware that requires you to sit in a loop polling for 
+ * the REQ signal as long as you are connected.  Some devices are 
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
+ * while doing long seek operations.
+ * 
+ * The workaround for this is to keep track of devices that have
+ * disconnected.  If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like 
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ * 
+ * Some tweaking of N and M needs to be done.  An algorithm based 
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these 
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function.  It attempts to establish
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the 
+ * issue queue and calling NCR5380_select() if a nexus 
+ * is not established. 
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work.  If USLEEP
+ * was defined, and the target is idle for too long, the system
+ * will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr()  which will in turn call NCR5380_reselect
+ * to reestablish a nexus.  This will run main if necessary.
+ *
+ * On command termination, the done function will be called as 
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command 
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips.  To use it, you write a architecture specific functions 
+ * and macros and include this file in your driver.
+ *
+ * These macros control options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *	for commands that return with a CHECK CONDITION status. 
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
+ *
+ * These macros MUST be defined :
+ * 
+ * NCR5380_read(register)  - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register 
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions : 
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes 
+ *	that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are 
+ *	available as NCR5380_i386_dma_write_setup,
+ *	NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(instance); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+ * hardware), you must also define 
+ *  
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ * NCR5380_proc_info
+ *
+ * to be the global entry points into the specific driver, ie 
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+ * with the NCR5380* names and the user must provide a globally
+ * accessible wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID.  If the 
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used.  Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+ */
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *the_template = NULL;
+
+/* Macros ease life... :-) */
+#define	SETUP_HOSTDATA(in)				\
+    struct NCR5380_hostdata *hostdata =			\
+	(struct NCR5380_hostdata *)(in)->hostdata
+#define	HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+#define	NEXT(cmd)	((Scsi_Cmnd *)((cmd)->host_scribble))
+#define	NEXTADDR(cmd)	((Scsi_Cmnd **)&((cmd)->host_scribble))
+
+#define	HOSTNO		instance->host_no
+#define	H_NO(cmd)	(cmd)->host->host_no
+
+#ifdef SUPPORT_TAGS
+
+/*
+ * Functions for handling tagged queuing
+ * =====================================
+ *
+ * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
+ *
+ * Using consecutive numbers for the tags is no good idea in my eyes. There
+ * could be wrong re-usings if the counter (8 bit!) wraps and some early
+ * command has been preempted for a long time. My solution: a bitfield for
+ * remembering used tags.
+ *
+ * There's also the problem that each target has a certain queue size, but we
+ * cannot know it in advance :-( We just see a QUEUE_FULL status being
+ * returned. So, in this case, the driver internal queue size assumption is
+ * reduced to the number of active tags if QUEUE_FULL is returned by the
+ * target. The command is returned to the mid-level, but with status changed
+ * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
+ * correctly.
+ *
+ * We're also not allowed running tagged commands as long as an untagged
+ * command is active. And REQUEST SENSE commands after a contingent allegiance
+ * condition _must_ be untagged. To keep track whether an untagged command has
+ * been issued, the host->busy array is still employed, as it is without
+ * support for tagged queuing.
+ *
+ * One could suspect that there are possible race conditions between
+ * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
+ * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
+ * which already guaranteed to be running at most once. It is also the only
+ * place where tags/LUNs are allocated. So no other allocation can slip
+ * between that pair, there could only happen a reselection, which can free a
+ * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
+ * important: the tag bit must be cleared before 'nr_allocated' is decreased.
+ */
+
+/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
+#undef TAG_NONE
+#define TAG_NONE 0xff
+
+/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */
+#if (MAX_TAGS % 32) != 0
+#error "MAX_TAGS must be a multiple of 32!"
+#endif
+
+typedef struct {
+    char	allocated[MAX_TAGS/8];
+    int		nr_allocated;
+    int		queue_size;
+} TAG_ALLOC;
+
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+
+
+static void init_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+    
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    ta->nr_allocated = 0;
+	    /* At the beginning, assume the maximum queue size we could
+	     * support (MAX_TAGS). This value will be decreased if the target
+	     * returns QUEUE_FULL status.
+	     */
+	    ta->queue_size = MAX_TAGS;
+	}
+    }
+}
+
+
+/* Check if we can issue a command to this LUN: First see if the LUN is marked
+ * busy by an untagged command. If the command should use tagged queuing, also
+ * check that there is a free tag and the target's queue won't overflow. This
+ * function should be called with interrupts disabled to avoid race
+ * conditions.
+ */ 
+
+static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    if (hostdata->busy[cmd->target] & (1 << cmd->lun))
+	return( 1 );
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported)
+	return( 0 );
+    if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
+	TagAlloc[cmd->target][cmd->lun].queue_size ) {
+	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
+		    H_NO(cmd), cmd->target, cmd->lun );
+	return( 1 );
+    }
+    return( 0 );
+}
+
+
+/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
+ * must be called before!), or reserve the LUN in 'busy' if the command is
+ * untagged.
+ */
+
+static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    /* If we or the target don't support tagged queuing, allocate the LUN for
+     * an untagged command.
+     */
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+	cmd->tag = TAG_NONE;
+	hostdata->busy[cmd->target] |= (1 << cmd->lun);
+	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
+		    "command\n", H_NO(cmd), cmd->target, cmd->lun );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+
+	cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
+	set_bit( cmd->tag, &ta->allocated );
+	ta->nr_allocated++;
+	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
+		    "(now %d tags in use)\n",
+		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+		    ta->nr_allocated );
+    }
+}
+
+
+/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
+ * unlock the LUN.
+ */
+
+static void cmd_free_tag( Scsi_Cmnd *cmd )
+{
+    SETUP_HOSTDATA(cmd->host);
+
+    if (cmd->tag == TAG_NONE) {
+	hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
+		    H_NO(cmd), cmd->target, cmd->lun );
+    }
+    else if (cmd->tag >= MAX_TAGS) {
+	printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+		H_NO(cmd), cmd->tag );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+	clear_bit( cmd->tag, &ta->allocated );
+	ta->nr_allocated--;
+	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
+		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
+    }
+}
+
+
+static void free_all_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    ta->nr_allocated = 0;
+	}
+    }
+}
+
+#endif /* SUPPORT_TAGS */
+
+
+/*
+ * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+ *
+ * Purpose: Try to merge several scatter-gather requests into one DMA
+ *    transfer. This is possible if the scatter buffers lie on
+ *    physical contiguous addresses.
+ *
+ * Parameters: Scsi_Cmnd *cmd
+ *    The command to work on. The first scatter buffer's data are
+ *    assumed to be already transfered into ptr/this_residual.
+ */
+
+static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+{
+    unsigned long endaddr;
+#if (NDEBUG & NDEBUG_MERGING)
+    unsigned long oldlen = cmd->SCp.this_residual;
+    int		  cnt = 1;
+#endif
+
+    for (endaddr = VTOP(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+	 cmd->SCp.buffers_residual &&
+	 VTOP(cmd->SCp.buffer[1].address) == endaddr; ) {
+	
+	MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+		   cmd->SCp.buffer[1].address, endaddr);
+#if (NDEBUG & NDEBUG_MERGING)
+	++cnt;
+#endif
+	++cmd->SCp.buffer;
+	--cmd->SCp.buffers_residual;
+	cmd->SCp.this_residual += cmd->SCp.buffer->length;
+	endaddr += cmd->SCp.buffer->length;
+    }
+#if (NDEBUG & NDEBUG_MERGING)
+    if (oldlen != cmd->SCp.this_residual)
+	MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+		   cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+}
+
+/*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the 
+ *	start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+{
+    /* 
+     * Initialize the Scsi Pointer field so that all of the commands in the 
+     * various queues are valid.
+     */
+
+    if (cmd->use_sg) {
+	cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+	cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
+	cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	/* ++roman: Try to merge some scatter-buffers if they are at
+	 * contiguous physical addresses.
+	 */
+	merge_contiguous_buffers( cmd );
+    } else {
+	cmd->SCp.buffer = NULL;
+	cmd->SCp.buffers_residual = 0;
+	cmd->SCp.ptr = (char *) cmd->request_buffer;
+	cmd->SCp.this_residual = cmd->request_bufflen;
+    }
+}
+
+#include <linux/config.h>
+#include <linux/delay.h>
+
+#if 1
+static struct {
+    unsigned char mask;
+    const char * name;} 
+signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, 
+    { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" }, 
+    { SR_SEL, "SEL" }, {0, NULL}}, 
+basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+    {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, 
+    {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, 
+    {0, NULL}},
+mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, 
+    {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, 
+    "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+    {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+    {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, 
+    {0, NULL}};
+
+/*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+ *
+ * Purpose : print the SCSI bus signals for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance) {
+    unsigned char status, data, basr, mr, icr, i;
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+    data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+    status = NCR5380_read(STATUS_REG);
+    mr = NCR5380_read(MODE_REG);
+    icr = NCR5380_read(INITIATOR_COMMAND_REG);
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    restore_flags(flags);
+    printk("STATUS_REG: %02x ", status);
+    for (i = 0; signals[i].mask ; ++i) 
+	if (status & signals[i].mask)
+	    printk(",%s", signals[i].name);
+    printk("\nBASR: %02x ", basr);
+    for (i = 0; basrs[i].mask ; ++i) 
+	if (basr & basrs[i].mask)
+	    printk(",%s", basrs[i].name);
+    printk("\nICR: %02x ", icr);
+    for (i = 0; icrs[i].mask; ++i) 
+	if (icr & icrs[i].mask)
+	    printk(",%s", icrs[i].name);
+    printk("\nMODE: %02x ", mr);
+    for (i = 0; mrs[i].mask; ++i) 
+	if (mr & mrs[i].mask)
+	    printk(",%s", mrs[i].name);
+    printk("\n");
+}
+
+static struct {
+    unsigned char value;
+    const char *name;
+} phases[] = {
+    {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+    {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+    {PHASE_UNKNOWN, "UNKNOWN"}};
+
+/* 
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+    unsigned char status;
+    int i;
+
+    status = NCR5380_read(STATUS_REG);
+    if (!(status & SR_REQ)) 
+	printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+    else {
+	for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
+	    (phases[i].value != (status & PHASE_MASK)); ++i); 
+	printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+    }
+}
+
+#else /* !NDEBUG */
+
+/* dummies... */
+__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
+__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+
+#endif
+
+/*
+ * ++roman: New scheme of calling NCR5380_main()
+ * 
+ * If we're not in an interrupt, we can call our main directly, it cannot be
+ * already running. Else, we queue it on a task queue, if not 'main_running'
+ * tells us that a lower level is already executing it. This way,
+ * 'main_running' needs not be protected in a special way.
+ *
+ * queue_main() is a utility function for putting our main onto the task
+ * queue, if main_running is false. It should be called only from a
+ * interrupt or bottom half.
+ */
+
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+static volatile int main_running = 0;
+static struct tq_struct NCR5380_tqueue = {
+    NULL,		/* next */
+    0,			/* sync */
+    (void (*)(void*))NCR5380_main,  /* routine, must have (void *) arg... */
+    NULL		/* data */
+};
+
+static __inline__ void queue_main(void)
+{
+    if (!main_running) {
+	/* If in interrupt and NCR5380_main() not already running,
+	   queue it on the 'immediate' task queue, to be processed
+	   immediately after the current interrupt processing has
+	   finished. */
+	queue_task(&NCR5380_tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+    }
+    /* else: nothing to do: the running NCR5380_main() will pick up
+       any newly queued command. */
+}
+
+
+static void NCR5380_all_init (void)
+{
+    static int done = 0;
+    if (!done) {
+	INI_PRINTK("scsi : NCR5380_all_init()\n");
+	done = 1;
+    }
+}
+
+ 
+/*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+ * Purpose : called by probe code indicating the NCR5380 driver
+ *	     options that were selected.
+ *
+ * Inputs : instance, pointer to this instance.  Unused.
+ */
+
+static void NCR5380_print_options (struct Scsi_Host *instance)
+{
+    printk(" generic options"
+#ifdef AUTOSENSE 
+    " AUTOSENSE"
+#endif
+#ifdef REAL_DMA
+    " REAL DMA"
+#endif
+#ifdef PSEUDO_DMA
+    " PSEUDO DMA"
+#endif
+#ifdef PARITY
+    " PARITY"
+#endif
+#ifdef SUPPORT_TAGS
+    " SCSI-2 TAGGED QUEUING"
+#endif
+    );
+    printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+}
+
+/*
+ * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+ *
+ * Purpose : print commands in the various queues, called from
+ *	NCR5380_abort and NCR5380_debug to aid debugging.
+ *
+ * Inputs : instance, pointer to this instance.  
+ */
+
+static void NCR5380_print_status (struct Scsi_Host *instance)
+{
+    char *pr_bfr;
+    char *start;
+    int len;
+
+    NCR_PRINT(NDEBUG_ANY);
+    NCR_PRINT_PHASE(NDEBUG_ANY);
+
+    pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
+    if (!pr_bfr) {
+	printk("NCR5380_print_status: no memory for print buffer\n");
+	return;
+    }
+    len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
+    pr_bfr[len] = 0;
+    printk("\n%s\n", pr_bfr);
+    free_page((unsigned long) pr_bfr);
+}
+
+
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+*/
+
+#undef SPRINTF
+#define SPRINTF(fmt,args...) \
+  do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+	 pos += sprintf(pos, fmt , ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+
+#ifndef NCR5380_proc_info
+static
+#endif
+int NCR5380_proc_info (char *buffer, char **start, off_t offset,
+		       int length, int hostno, int inout)
+{
+    char *pos = buffer;
+    struct Scsi_Host *instance;
+    struct NCR5380_hostdata *hostdata;
+    Scsi_Cmnd *ptr;
+    unsigned long flags;
+    off_t begin = 0;
+#define check_offset()				\
+    do {					\
+	if (pos - buffer < offset - begin) {	\
+	    begin += pos - buffer;		\
+	    pos = buffer;			\
+	}					\
+    } while (0)
+
+    for (instance = first_instance; instance && HOSTNO != hostno;
+	 instance = instance->next)
+	;
+    if (!instance)
+	return(-ESRCH);
+    hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+    if (inout) { /* Has data been written to the file ? */
+	return(-ENOSYS);  /* Currently this is a no-op */
+    }
+    SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+    check_offset();
+    save_flags(flags);
+    cli();
+    SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
+    check_offset();
+    if (!hostdata->connected)
+	SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+    else
+	pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+				pos, buffer, length);
+    SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+    check_offset();
+    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	check_offset();
+    }
+
+    SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+    check_offset();
+    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+	 ptr = NEXT(ptr)) {
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	check_offset();
+    }
+
+    restore_flags(flags);
+    *start = buffer + (offset - begin);
+    if (pos - buffer < offset - begin)
+	return 0;
+    else if (pos - buffer - (offset - begin) < length)
+	return pos - buffer - (offset - begin);
+    return length;
+}
+
+static char *
+lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+{
+    int i, s;
+    unsigned char *command;
+    SPRINTF("scsi%d: destination target %d, lun %d\n",
+	    H_NO(cmd), cmd->target, cmd->lun);
+    SPRINTF("        command = ");
+    command = cmd->cmnd;
+    SPRINTF("%2d (0x%02x)", command[0], command[0]);
+    for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+	SPRINTF(" %02x", command[i]);
+    SPRINTF("\n");
+    return pos;
+}
+
+
+/* 
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializes *instance and corresponding 5380 chip.
+ *
+ * Inputs : instance - instantiation of the 5380 driver.  
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+ * 	set correctly.  I don't care about the irq and other fields. 
+ * 
+ */
+
+static void NCR5380_init (struct Scsi_Host *instance, int flags)
+{
+    int i;
+    SETUP_HOSTDATA(instance);
+
+    NCR5380_all_init();
+
+    hostdata->aborted = 0;
+    hostdata->id_mask = 1 << instance->this_id;
+    hostdata->id_higher_mask = 0;
+    for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+	if (i > hostdata->id_mask)
+	    hostdata->id_higher_mask |= i;
+    for (i = 0; i < 8; ++i)
+	hostdata->busy[i] = 0;
+#ifdef SUPPORT_TAGS
+    init_tags();
+#endif
+#if defined (REAL_DMA)
+    hostdata->dma_len = 0;
+#endif
+    hostdata->targets_present = 0;
+    hostdata->connected = NULL;
+    hostdata->issue_queue = NULL;
+    hostdata->disconnected_queue = NULL;
+    hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+    if (!the_template) {
+	the_template = instance->hostt;
+	first_instance = instance;
+    }
+	
+
+#ifndef AUTOSENSE
+    if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+	 printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+	        "        without AUTOSENSE option, contingent allegiance conditions may\n"
+	        "        be incorrectly cleared.\n", HOSTNO);
+#endif /* def AUTOSENSE */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+}
+
+/* 
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
+ *	void (*done)(Scsi_Cmnd *)) 
+ *
+ * Purpose :  enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *	a pointer to the command descriptor.
+ * 
+ * Returns : 0
+ *
+ * Side effects : 
+ *      cmd is added to the per instance issue_queue, with minor 
+ *	twiddling done to the host specific fields of cmd.  If the 
+ *	main coroutine is not running, it is restarted.
+ *
+ */
+
+/* Only make static if a wrapper function is used */
+#ifndef NCR5380_queue_command
+static
+#endif
+int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+    SETUP_HOSTDATA(cmd->host);
+    Scsi_Cmnd *tmp;
+    int oldto;
+    unsigned long flags;
+    extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+    switch (cmd->cmnd[0]) {
+    case WRITE_6:
+    case WRITE_10:
+	printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+	       H_NO(cmd));
+	cmd->result = (DID_ERROR << 16);
+	done(cmd);
+	return 0;
+    }
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+
+#ifdef NCR5380_STATS
+# if 0
+    if (!hostdata->connected && !hostdata->issue_queue &&
+	!hostdata->disconnected_queue) {
+	hostdata->timebase = jiffies;
+    }
+# endif
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_write[cmd->target] += cmd->request_bufflen;
+		hostdata->pendingw++;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_read[cmd->target] += cmd->request_bufflen;
+		hostdata->pendingr++;
+		break;
+	}
+#endif
+
+    /* 
+     * We use the host_scribble field as a pointer to the next command  
+     * in a queue 
+     */
+
+    NEXT(cmd) = NULL;
+    cmd->scsi_done = done;
+
+    cmd->result = 0;
+
+
+    /* 
+     * Insert the cmd into the issue queue. Note that REQUEST SENSE 
+     * commands are added to the head of the queue since any command will
+     * clear the contingent allegiance condition that exists and the 
+     * sense data is only guaranteed to be valid while the condition exists.
+     */
+
+    save_flags(flags);
+    cli();
+
+    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+	LIST(cmd, hostdata->issue_queue);
+	NEXT(cmd) = hostdata->issue_queue;
+	hostdata->issue_queue = cmd;
+    } else {
+	for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+	     NEXT(tmp); tmp = NEXT(tmp))
+	    ;
+	LIST(cmd, tmp);
+	NEXT(tmp) = cmd;
+    }
+    restore_flags(flags);
+
+    QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+	      (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+    /* If queue_command() is called from an interrupt (real one or bottom
+     * half), we let queue_main() do the job of taking care about main. If it
+     * is already running, this is a no-op, else main will be queued.
+     *
+     * If we're not in an interrupt, we can call NCR5380_main()
+     * unconditionally, because it cannot be already running.
+     */
+    if (in_interrupt() > 0 || ((flags >> 8) & 7) >= 6)
+	queue_main();
+    else
+	NCR5380_main();
+    return 0;
+}
+
+/*
+ * Function : NCR5380_main (void) 
+ *
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
+ *	be done on the NCR5380 host adapters in a system.  Both 
+ *	NCR5380_queue_command() and NCR5380_intr() will try to start it 
+ *	in case it is not running.
+ * 
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should 
+ *  reenable them.  This prevents reentrancy and kernel stack overflow.
+ */ 	
+    
+static void NCR5380_main (void)
+{
+    Scsi_Cmnd *tmp, *prev;
+    struct Scsi_Host *instance = first_instance;
+    struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+    int done;
+    unsigned long flags;
+    
+    /*
+     * We run (with interrupts disabled) until we're sure that none of 
+     * the host adapters have anything that can be done, at which point 
+     * we set main_running to 0 and exit.
+     *
+     * Interrupts are enabled before doing various other internal 
+     * instructions, after we've decided that we need to run through
+     * the loop again.
+     *
+     * this should prevent any race conditions.
+     * 
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which can
+     * alter queues and touch the Falcon lock.
+     */
+
+    /* Tell int handlers main() is now already executing.  Note that
+       no races are possible here. If an int comes in before
+       'main_running' is set here, and queues/executes main via the
+       task queue, it doesn't do any harm, just this instance of main
+       won't find any work left to do. */
+    if (main_running)
+    	return;
+    main_running = 1;
+
+    save_flags(flags);
+    do {
+	cli(); /* Freeze request queues */
+	done = 1;
+	
+	if (!hostdata->connected) {
+	    MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
+	    /*
+	     * Search through the issue_queue for a command destined
+	     * for a target that's not busy.
+	     */
+#if (NDEBUG & NDEBUG_LISTS)
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+		 tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+		;
+		/*printk("%p  ", tmp);*/
+	    if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+#endif
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
+		 prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+
+#if (NDEBUG & NDEBUG_LISTS)
+		if (prev != tmp)
+		    printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n",
+			   tmp, tmp->target, hostdata->busy[tmp->target],
+			   tmp->lun);
+#endif
+		/*  When we find one, remove it from the issue queue. */
+		if (
+#ifdef SUPPORT_TAGS
+		    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+#else
+		    !(hostdata->busy[tmp->target] & (1 << tmp->lun))
+#endif
+		    ) {
+		    cli(); /* ++guenther: just to be sure, this must be atomic */
+		    if (prev) {
+		        REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+			NEXT(prev) = NEXT(tmp);
+		    } else {
+		        REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+			hostdata->issue_queue = NEXT(tmp);
+		    }
+		    NEXT(tmp) = NULL;
+		    
+		    /* reenable interrupts after finding one */
+		    restore_flags(flags);
+		    
+		    /* 
+		     * Attempt to establish an I_T_L nexus here. 
+		     * On success, instance->hostdata->connected is set.
+		     * On failure, we must add the command back to the
+		     *   issue queue so we can keep trying.	
+		     */
+		    MAIN_PRINTK("scsi%d: main(): command for target %d "
+				"lun %d removed from issue_queue\n",
+				HOSTNO, tmp->target, tmp->lun);
+		    /* 
+		     * REQUEST SENSE commands are issued without tagged
+		     * queueing, even on SCSI-II devices because the 
+		     * contingent allegiance condition exists for the 
+		     * entire unit.
+		     */
+		    /* ++roman: ...and the standard also requires that
+		     * REQUEST SENSE command are untagged.
+		     */
+		    
+#ifdef SUPPORT_TAGS
+		    cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+#endif
+		    if (!NCR5380_select(instance, tmp, 
+			    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : 
+			    TAG_NEXT)) {
+			break;
+		    } else {
+			cli();
+			LIST(tmp, hostdata->issue_queue);
+			NEXT(tmp) = hostdata->issue_queue;
+			hostdata->issue_queue = tmp;
+#ifdef SUPPORT_TAGS
+			cmd_free_tag( tmp );
+#endif
+			restore_flags(flags);
+			MAIN_PRINTK("scsi%d: main(): select() failed, "
+				    "returned to issue_queue\n", HOSTNO);
+			if (hostdata->connected)
+			    break;
+		    }
+		} /* if target/lun/target queue is not busy */
+	    } /* for issue_queue */
+	} /* if (!hostdata->connected) */
+		
+	if (hostdata->connected 
+#ifdef REAL_DMA
+	    && !hostdata->dma_len
+#endif
+	    ) {
+	    restore_flags(flags);
+	    MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+			HOSTNO);
+	    NCR5380_information_transfer(instance);
+	    MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+	    done = 0;
+	}
+    } while (!done);
+
+    /* Better allow ints _after_ 'main_running' has been cleared, else
+       an interrupt could believe we'll pick up the work it left for
+       us, but we won't see it anymore here... */
+    main_running = 0;
+    restore_flags(flags);
+}
+
+
+#ifdef REAL_DMA
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : Called by interrupt handler when DMA finishes or a phase
+ *	mismatch occurs (which would finish the DMA transfer).  
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+static void NCR5380_dma_complete( struct Scsi_Host *instance )
+{
+    SETUP_HOSTDATA(instance);
+    int           transfered, saved_data = 0, overrun = 0, cnt, toPIO;
+    unsigned char **data, p;
+    volatile int  *count;
+
+    if (!hostdata->connected) {
+	printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+	       "no connected cmd\n", HOSTNO);
+	return;
+    }
+    
+    if (mac_read_overruns) {
+	p = hostdata->connected->SCp.phase;
+	if (p & SR_IO) {
+	    udelay(10);
+	    if ((((NCR5380_read(BUS_AND_STATUS_REG)) &
+		  (BASR_PHASE_MATCH|BASR_ACK)) ==
+		 (BASR_PHASE_MATCH|BASR_ACK))) {
+		saved_data = NCR5380_read(INPUT_DATA_REG);
+		overrun = 1;
+		DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
+	    }
+	}
+    }
+
+    DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+	       HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+	       NCR5380_read(STATUS_REG));
+
+    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+    hostdata->dma_len = 0;
+
+    data = (unsigned char **) &(hostdata->connected->SCp.ptr);
+    count = &(hostdata->connected->SCp.this_residual);
+    *data += transfered;
+    *count -= transfered;
+
+    if (mac_read_overruns) {
+	if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
+	    cnt = toPIO = mac_read_overruns;
+	    if (overrun) {
+		DMA_PRINTK("Got an input overrun, using saved byte\n");
+		*(*data)++ = saved_data;
+		(*count)--;
+		cnt--;
+		toPIO--;
+	    }
+	    DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
+	    NCR5380_transfer_pio(instance, &p, &cnt, data);
+	    *count -= toPIO - cnt;
+	}
+    }
+}
+#endif /* REAL_DMA */
+
+
+/*
+ * Function : void NCR5380_intr (int irq)
+ * 
+ * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ *	from the disconnected queue, and restarting NCR5380_main() 
+ *	as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+static void NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct Scsi_Host *instance = first_instance;
+    int done = 1;
+    unsigned char basr;
+
+    INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+    /* Look for pending interrupts */
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+    /* dispatch to appropriate routine if found and done=0 */
+    if (basr & BASR_IRQ) {
+	NCR_PRINT(NDEBUG_INTR);
+	if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+	    done = 0;
+	    ENABLE_IRQ();
+	    INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+	    NCR5380_reselect(instance);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if (basr & BASR_PARITY_ERROR) {
+	    INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+	    INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+	    (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else {
+	    /*  
+	     * The rest of the interrupt conditions can occur only during a
+	     * DMA transfer
+	     */
+
+#if defined(REAL_DMA)
+	    /*
+	     * We should only get PHASE MISMATCH and EOP interrupts if we have
+	     * DMA enabled, so do a sanity check based on the current setting
+	     * of the MODE register.
+	     */
+
+	    if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+		((basr & BASR_END_DMA_TRANSFER) || 
+		 !(basr & BASR_PHASE_MATCH))) {
+		    
+		INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+		NCR5380_dma_complete( instance );
+		done = 0;
+		ENABLE_IRQ();
+	    } else
+#endif /* REAL_DMA */
+	    {
+/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
+		if (basr & BASR_PHASE_MATCH)
+		    printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+			   "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+			   HOSTNO, basr, NCR5380_read(MODE_REG),
+			   NCR5380_read(STATUS_REG));
+		(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	    }
+	} /* if !(SELECTION || PARITY) */
+    } /* BASR & IRQ */
+    else {
+	printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+	       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+	       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+	(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    }
+    
+    if (!done) {
+	INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+	/* Put a call to NCR5380_main() on the queue... */
+	queue_main();
+    }
+}
+
+#ifdef NCR5380_STATS
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+{
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/
+		hostdata->pendingw--;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/
+		hostdata->pendingr--;
+		break;
+	}
+}
+#endif
+
+/* 
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
+ *	int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ *	including ARBITRATION, SELECTION, and initial message out for 
+ *	IDENTIFY and queue messages. 
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this 
+ * 	target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for 
+ *	new tag, TAG_NONE for untagged queueing, otherwise set to the tag for 
+ *	the command that is presently connected.
+ * 
+ * Returns : -1 if selection could not execute for some reason,
+ *	0 if selection succeeded or failed because the target 
+ * 	did not respond.
+ *
+ * Side effects : 
+ * 	If bus busy, arbitration failed, etc, NCR5380_select() will exit 
+ *		with registers as they should have been on entry - ie
+ *		SELECT_ENABLE will be set appropriately, the NCR5380
+ *		will cease to drive any SCSI bus signals.
+ *
+ *	If successful : I_T_L or I_T_L_Q nexus will be established, 
+ *		instance->connected will be set to cmd.  
+ * 		SELECT interrupt will be disabled.
+ *
+ *	If failed (no target) : cmd->scsi_done() will be called, and the 
+ *		cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char tmp[3], phase;
+    unsigned char *data;
+    int len;
+    unsigned long timeout;
+    unsigned long flags;
+
+    hostdata->restart_select = 0;
+    NCR_PRINT(NDEBUG_ARBITRATION);
+    ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+	       instance->this_id);
+
+    /* 
+     * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
+     * data bus during SELECTION.
+     */
+
+    save_flags(flags);
+    cli();
+    if (hostdata->connected) {
+	restore_flags(flags);
+	return -1;
+    }
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+
+    /* 
+     * Start arbitration.
+     */
+    
+    NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+    NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+    restore_flags(flags);
+
+    /* Wait for arbitration logic to complete */
+#if NCR_TIMEOUT
+    {
+      unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+      while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	   && jiffies < timeout && !hostdata->connected)
+	;
+      if (jiffies >= timeout)
+      {
+	printk("scsi : arbitration timeout at %d\n", __LINE__);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return -1;
+      }
+    }
+#else /* NCR_TIMEOUT */
+    while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	 && !hostdata->connected);
+#endif
+
+    ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
+
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	return -1;
+    }
+    /* 
+     * The arbitration delay is 2.2us, but this is a minimum and there is 
+     * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+     * the integral nature of udelay().
+     *
+     */
+
+    udelay(3);
+
+    /* Check for lost arbitration */
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+	(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+		   HOSTNO);
+	return -1;
+    }
+
+     /* after/during arbitration, BSY should be asserted.
+	IBM DPES-31080 Version S31Q works now */
+     /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
+					 ICR_ASSERT_BSY ) ;
+    
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+		   HOSTNO);
+	return -1;
+    }
+
+    /* 
+     * Again, bus clear + bus settle time is 1.2us, however, this is 
+     * a minimum so we'll udelay ceil(1.2)
+     */
+
+#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+    /* ++roman: But some targets (see above :-) seem to need a bit more... */
+    udelay(15);
+#else
+    udelay(2);
+#endif
+    
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+    /* 
+     * Now that we have won arbitration, start Selection process, asserting 
+     * the host and target ID's on the SCSI bus.
+     */
+
+    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+
+    /* 
+     * Raise ATN while SEL is true before BSY goes false from arbitration,
+     * since this is the only way to guarantee that we'll get a MESSAGE OUT
+     * phase immediately after selection.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | 
+	ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+    NCR5380_write(MODE_REG, MR_BASE);
+
+    /* 
+     * Reselect interrupts must be turned off prior to the dropping of BSY,
+     * otherwise we will trigger an interrupt.
+     */
+
+    if (hostdata->connected) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    /*
+     * The initiator shall then wait at least two deskew delays and release 
+     * the BSY signal.
+     */
+    udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
+
+    /* Reset BSY */
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | 
+	ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+    /* 
+     * Something weird happens when we cease to drive BSY - looks
+     * like the board/chip is letting us do another read before the 
+     * appropriate propagation delay has expired, and we're confusing
+     * a BSY signal from ourselves as the target's response to SELECTION.
+     *
+     * A small delay (the 'C++' frontend breaks the pipeline with an
+     * unnecessary jump, making it work on my 386-33/Trantor T128, the
+     * tighter 'C' code breaks and requires this) solves the problem - 
+     * the 1 us delay is arbitrary, and only used because this delay will 
+     * be the same on other platforms and since it works here, it should 
+     * work there.
+     *
+     * wingel suggests that this could be due to failing to wait
+     * one deskew delay.
+     */
+
+    udelay(1);
+
+    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
+
+    /* 
+     * The SCSI specification calls for a 250 ms timeout for the actual 
+     * selection.
+     */
+
+    timeout = jiffies + 25; 
+
+    /* 
+     * XXX very interesting - we're seeing a bounce where the BSY we 
+     * asserted is being reflected / still asserted (propagation delay?)
+     * and it's detecting as true.  Sigh.
+     */
+
+#if 0
+    /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+     * IO while SEL is true. But again, there are some disks out the in the
+     * world that do that nevertheless. (Somebody claimed that this announces
+     * reselection capability of the target.) So we better skip that test and
+     * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+     */
+
+    while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & 
+	(SR_BSY | SR_IO)));
+
+    if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == 
+	    (SR_SEL | SR_IO)) {
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	    NCR5380_reselect(instance);
+	    printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
+		    HOSTNO);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+    }
+#else
+    while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+#endif
+
+    /* 
+     * No less than two deskew delays after the initiator detects the 
+     * BSY signal is true, it shall release the SEL signal and may 
+     * change the DATA BUS.                                     -wingel
+     */
+
+    udelay(1);
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	if (hostdata->targets_present & (1 << cmd->target)) {
+	    printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+	    if (hostdata->restart_select)
+		printk(KERN_NOTICE "\trestart select\n");
+	    NCR_PRINT(NDEBUG_ANY);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+	}
+	cmd->result = DID_BAD_TARGET << 16;
+#ifdef NCR5380_STATS
+	collect_stats(hostdata, cmd);
+#endif
+#ifdef SUPPORT_TAGS
+	cmd_free_tag( cmd );
+#endif
+	cmd->scsi_done(cmd);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return 0;
+    } 
+
+    hostdata->targets_present |= (1 << cmd->target);
+
+    /*
+     * Since we followed the SCSI spec, and raised ATN while SEL 
+     * was true but before BSY was false during selection, the information
+     * transfer phase should be a MESSAGE OUT phase so that we can send the
+     * IDENTIFY message.
+     * 
+     * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+     * message (2 bytes) with a tag ID that we increment with every command
+     * until it wraps back to 0.
+     *
+     * XXX - it turns out that there are some broken SCSI-II devices,
+     *	     which claim to support tagged queuing but fail when more than
+     *	     some number of commands are issued at once.
+     */
+
+    /* Wait for start of REQ/ACK handshake */
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+    SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+	       HOSTNO, cmd->target);
+    tmp[0] = IDENTIFY(1, cmd->lun);
+
+#ifdef SUPPORT_TAGS
+    if (cmd->tag != TAG_NONE) {
+	tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+	tmp[2] = cmd->tag;
+	len = 3;
+    } else 
+	len = 1;
+#else
+    len = 1;
+    cmd->tag=0;
+#endif /* SUPPORT_TAGS */
+
+    /* Send message(s) */
+    data = tmp;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio(instance, &phase, &len, &data);
+    SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+    /* XXX need to handle errors here */
+    hostdata->connected = cmd;
+#ifndef SUPPORT_TAGS
+    hostdata->busy[cmd->target] |= (1 << cmd->lun);
+#endif    
+
+    initialize_SCp(cmd);
+
+
+    return 0;
+}
+
+/* 
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes are transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it 
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    register unsigned char p = *phase, tmp;
+    register int c = *count;
+    register unsigned char *d = *data;
+
+    /* 
+     * The NCR5380 chip will only drive the SCSI bus when the 
+     * phase specified in the appropriate bits of the TARGET COMMAND
+     * REGISTER match the STATUS REGISTER
+     */
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+    do {
+	/* 
+	 * Wait for assertion of REQ, after which the phase bits will be 
+	 * valid 
+	 */
+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+	HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+
+	/* Check for phase mismatch */	
+	if ((tmp & PHASE_MASK) != p) {
+	    PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+	    NCR_PRINT_PHASE(NDEBUG_PIO);
+	    break;
+	}
+
+	/* Do actual transfer from SCSI bus to / from memory */
+	if (!(p & SR_IO)) 
+	    NCR5380_write(OUTPUT_DATA_REG, *d);
+	else 
+	    *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+	++d;
+
+	/* 
+	 * The SCSI standard suggests that in MSGOUT phase, the initiator
+	 * should drop ATN on the last byte of the message phase
+	 * after REQ has been asserted for the handshake but before
+	 * the initiator raises ACK.
+	 */
+
+	if (!(p & SR_IO)) {
+	    if (!((p & SR_MSG) && c > 1)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA);
+		NCR_PRINT(NDEBUG_PIO);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+	    } else {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+		NCR_PRINT(NDEBUG_PIO);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+	    }
+	} else {
+	    NCR_PRINT(NDEBUG_PIO);
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+	}
+
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+	HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+/*
+ * We have several special cases to consider during REQ/ACK handshaking : 
+ * 1.  We were in MSGOUT phase, and we are on the last byte of the 
+ *	message.  ATN must be dropped as ACK is dropped.
+ *
+ * 2.  We are in a MSGIN phase, and we are on the last byte of the  
+ *	message.  We must exit with ACK asserted, so that the calling
+ *	code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3.  ACK and ATN are clear and the target may proceed as normal.
+ */
+	if (!(p == PHASE_MSGIN && c == 1)) {  
+	    if (p == PHASE_MSGOUT && c > 1)
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+	    else
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	} 
+    } while (--c);
+
+    PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+    *count = c;
+    *data = d;
+    tmp = NCR5380_read(STATUS_REG);
+    /* The phase read from the bus is valid if either REQ is (already)
+     * asserted or if ACK hasn't been released yet. The latter is the case if
+     * we're in MSGIN and all wanted bytes have been received. */
+    if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+	*phase = tmp & PHASE_MASK;
+    else 
+	*phase = PHASE_UNKNOWN;
+
+    if (!c || (*phase == p))
+	return 0;
+    else 
+	return -1;
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ * 
+ * Purpose : abort the currently established nexus.  Should only be 
+ * 	called from a routine which can drop into a 
+ * 
+ * Returns : 0 on success, -1 on failure.
+ */
+
+static int do_abort (struct Scsi_Host *host) 
+{
+    unsigned char tmp, *msgptr, phase;
+    int len;
+
+    /* Request message out phase */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    /* 
+     * Wait for the target to indicate a valid phase by asserting 
+     * REQ.  Once this happens, we'll have either a MSGOUT phase 
+     * and can immediately send the ABORT message, or we'll have some 
+     * other phase and will have to source/sink data.
+     * 
+     * We really don't care what value was on the bus or what value
+     * the target sees, so we just handshake.
+     */
+    
+    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+    if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		      ICR_ASSERT_ACK);
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+    }
+   
+    tmp = ABORT;
+    msgptr = &tmp;
+    len = 1;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio (host, &phase, &len, &msgptr);
+
+    /*
+     * If we got here, and the command completed successfully,
+     * we're about to go into bus free state.
+     */
+
+    return len ? -1 : 0;
+}
+
+#if defined(REAL_DMA) || defined(PSEUDO_DMA)
+/* 
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ *	or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes or transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+static int NCR5380_transfer_dma( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    SETUP_HOSTDATA(instance);
+    register int c = *count;
+    register unsigned char p = *phase;
+    register unsigned char *d = *data;
+    register int foo;
+    unsigned char tmp;
+    unsigned long flags;
+
+
+    if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+        *phase = tmp;
+        return -1;
+    }
+
+    if (mac_read_overruns && (p & SR_IO)) {
+	c -= mac_read_overruns;
+    }
+
+    DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+	       HOSTNO, (p & SR_IO) ? "reading" : "writing",
+	       c, (p & SR_IO) ? "to" : "from", d);
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+#ifdef REAL_DMA
+    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+#else /* PSEUDO_DMA! */
+#if defined(PSEUDO_DMA) && !defined(UNSAFE)
+    save_flags(flags);
+    cli();
+#endif
+    /* KLL May need eop and parity in 53c400 */
+    if (hostdata->flags & FLAG_NCR53C400)
+	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK
+	| MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE
+	| MR_MONITOR_BSY);
+    else
+#ifndef EMULATE_PSEUDO_DMA
+	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+#else
+        NCR5380_write(MODE_REG, MR_BASE);
+#endif
+#endif /* def REAL_DMA  */
+
+#ifdef REAL_DMA
+    /* On the Medusa, it is a must to initialize the DMA before
+     * starting the NCR. This is also the cleaner way for the TT.
+     */
+    save_flags(flags);
+    cli();
+    hostdata->dma_len = (p & SR_IO) ?
+        NCR5380_dma_read_setup(instance, d, c) : 
+        NCR5380_dma_write_setup(instance, d, c);
+    restore_flags(flags);
+#endif /* def REAL_DMA */
+
+#ifndef EMULATE_PSEUDO_DMA
+    if (p & SR_IO)
+	NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+    else {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+	NCR5380_write(START_DMA_SEND_REG, 0);
+    }
+#else
+    hostdata->dma_len = c;
+#endif
+
+#if defined(REAL_DMA)
+    return 0;
+#else /* defined(PSEUDO_DMA) */
+    if (p & SR_IO) {
+#ifdef DMA_WORKS_RIGHT
+        foo = NCR5380_pread(instance, d, c);
+#else
+	int diff = 1;
+	if (hostdata->flags & FLAG_NCR53C400) {
+	    diff=0;
+	}
+
+	if (!(foo = NCR5380_pread(instance, d, c - diff))) {
+	    /*
+	     * We can't disable DMA mode after successfully transferring 
+	     * what we plan to be the last byte, since that would open up
+	     * a race condition where if the target asserted REQ before 
+	     * we got the DMA mode reset, the NCR5380 would have latched
+	     * an additional byte into the INPUT DATA register and we'd
+	     * have dropped it.
+	     * 
+	     * The workaround was to transfer one fewer bytes than we 
+	     * intended to with the pseudo-DMA read function, wait for 
+	     * the chip to latch the last byte, read it, and then disable
+	     * pseudo-DMA mode.
+	     * 
+	     * After REQ is asserted, the NCR5380 asserts DRQ and ACK.
+	     * REQ is deasserted when ACK is asserted, and not reasserted
+	     * until ACK goes false.  Since the NCR5380 won't lower ACK
+	     * until DACK is asserted, which won't happen unless we twiddle
+	     * the DMA port or we take the NCR5380 out of DMA mode, we 
+	     * can guarantee that we won't handshake another extra 
+	     * byte.
+    	     */
+
+	    if (!(hostdata->flags & FLAG_NCR53C400)) {
+		while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
+		/* Wait for clean handshake */
+		while (NCR5380_read(STATUS_REG) & SR_REQ);
+		d[c - 1] = NCR5380_read(INPUT_DATA_REG);
+	    }
+	}
+#endif
+    } else {
+#ifdef DMA_WORKS_RIGHT
+        foo = NCR5380_pwrite(instance, d, c);
+#else
+        int timeout;
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	printk("About to pwrite %d bytes\n", c);
+#endif
+	if (!(foo = NCR5380_pwrite(instance, d, c))) {
+	    /*
+	     * Wait for the last byte to be sent.  If REQ is being asserted for 
+	     * the byte we're interested, we'll ACK it and it will go false.  
+	     */
+	    if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
+		timeout = 20000;
+#if 1
+#if 1
+		while (!(NCR5380_read(BUS_AND_STATUS_REG) & 
+			BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) &
+			BASR_PHASE_MATCH));
+#else
+		if (NCR5380_read(STATUS_REG) & SR_REQ) {
+		    for (; timeout && 
+			!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); 
+			--timeout);
+		    for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ);
+			--timeout);
+		} 
+#endif
+	
+
+#if (NDEBUG & NDEBUG_LAST_BYTE_SENT)
+		if (!timeout) 
+		    printk("scsi%d : timed out on last byte\n",
+			    instance->host_no);
+#endif
+
+
+		if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
+		    hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
+		    if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) {
+			hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
+#if (NDEBUG & NDEBUG_LAST_BYTE_SENT)
+			printk("scsi%d : last bit sent works\n", 
+			    instance->host_no);
+#endif
+		    }
+		}
+	    } else  {
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+		printk("Waiting for LASTBYTE\n");
+#endif
+		while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+		printk("Got LASTBYTE\n");
+#endif
+	    }
+#else
+	    udelay (5);
+#endif
+	}
+#endif
+    }
+
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) {
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	printk("53C400w: Checking for IRQ\n");
+#endif
+	if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) {
+#if (NDEBUG & NDEBUG_C400_PWRITE)
+	    printk("53C400w:    got it, reading reset interrupt reg\n");
+#endif
+	    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	} else {
+	    printk("53C400w:    IRQ NOT THERE!\n");
+	}
+    }
+
+    *data = d + c;
+    *count = 0;
+    *phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
+#if 0
+    NCR5380_print_phase(instance);
+#endif
+#if defined(PSEUDO_DMA) && !defined(UNSAFE)
+    restore_flags(flags);
+#endif /* defined(REAL_DMA_POLL) */
+    return foo;
+#endif /* def REAL_DMA */
+}
+#endif /* defined(REAL_DMA) || defined(PSEUDO_DMA) */
+
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target 
+ * 	directs us to.  Operates on the currently connected command, 
+ *	instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be 
+ *	modified if a command disconnects, *instance->connected will
+ *	change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here 
+ * 	to recover from an unexpected bus free condition.
+ */
+ 
+static void NCR5380_information_transfer (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned long flags;
+    unsigned char msgout = NOP;
+    int sink = 0;
+    int len;
+#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
+    int transfersize;
+#endif
+    unsigned char *data;
+    unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+    Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+    while (1) {
+	tmp = NCR5380_read(STATUS_REG);
+	/* We only have a valid SCSI phase when REQ is asserted */
+	if (tmp & SR_REQ) {
+	    phase = (tmp & PHASE_MASK); 
+	    if (phase != old_phase) {
+		old_phase = phase;
+		NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+	    }
+	    
+	    if (sink && (phase != PHASE_MSGOUT)) {
+		NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		    ICR_ASSERT_ACK);
+		while (NCR5380_read(STATUS_REG) & SR_REQ);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_ATN);
+		sink = 0;
+		continue;
+	    }
+
+	    switch (phase) {
+	    case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+		printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+		       "aborted\n", HOSTNO);
+		sink = 1;
+		do_abort(instance);
+		cmd->result = DID_ERROR  << 16;
+		cmd->done(cmd);
+		return;
+#endif
+	    case PHASE_DATAIN:
+		/* 
+		 * If there is no room left in the current buffer in the
+		 * scatter-gather list, move onto the next one.
+		 */
+
+		if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+		    ++cmd->SCp.buffer;
+		    --cmd->SCp.buffers_residual;
+		    cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		    cmd->SCp.ptr = cmd->SCp.buffer->address;
+		    /* ++roman: Try to merge some scatter-buffers if
+		     * they are at contiguous physical addresses.
+		     */
+		    merge_contiguous_buffers( cmd );
+		    INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+			       HOSTNO, cmd->SCp.this_residual,
+			       cmd->SCp.buffers_residual);
+		}
+
+		/*
+		 * The preferred transfer method is going to be 
+		 * PSEUDO-DMA for systems that are strictly PIO,
+		 * since we can let the hardware do the handshaking.
+		 *
+		 * For this to work, we need to know the transfersize
+		 * ahead of time, since the pseudo-DMA code will sit
+		 * in an unconditional loop.
+		 */
+
+/* ++roman: I suggest, this should be
+ *   #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
+
+#if defined(REAL_DMA) || defined(PSEUDO_DMA)
+		if (!cmd->device->borken &&
+		    !(hostdata->flags & FLAG_NO_PSEUDO_DMA) &&
+		    (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
+
+		    len = transfersize;
+		    cmd->SCp.phase = phase;
+		    if (NCR5380_transfer_dma(instance, &phase,
+			&len, (unsigned char **) &cmd->SCp.ptr)) {
+			/*
+			 * If the watchdog timer fires, all future
+			 * accesses to this device will use the
+			 * polled-IO. */ 
+			printk(KERN_NOTICE "scsi%d: switching target %d "
+			       "lun %d to slow handshake\n", HOSTNO,
+			       cmd->target, cmd->lun);
+			cmd->device->borken = 1;
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			    ICR_ASSERT_ATN);
+			sink = 1;
+			do_abort(instance);
+			cmd->result = DID_ERROR  << 16;
+			cmd->done(cmd);
+			/* XXX - need to source or sink data here, as appropriate */
+		    } else {
+#ifdef REAL_DMA
+			/* ++roman: When using real DMA,
+			 * information_transfer() should return after
+			 * starting DMA since it has nothing more to
+			 * do.
+			 */
+			return;
+#else			
+			/* Michael: When using pseudo-DMA emulation, we must 
+			 * take care to take into account the residual from 
+			 * the current transfer as determined by either the 
+			 * interrupt routine ot the pseudo-transfer functions
+			 * (whichever notices it first).
+			 */
+			if (mac_pdma_residual)
+			  len -= mac_pdma_residual;
+			cmd->SCp.this_residual -= transfersize - len;
+#endif
+		    }
+		} else
+#endif /* defined(REAL_DMA) || defined(PSEUDO_DMA) */
+		  NCR5380_transfer_pio(instance, &phase, 
+		    (int *) &cmd->SCp.this_residual, (unsigned char **)
+		    &cmd->SCp.ptr);
+		break;
+	    case PHASE_MSGIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_write(SELECT_ENABLE_REG, 0); 	/* disable reselects */
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Message = tmp;
+
+		switch (tmp) {
+		/*
+		 * Linking lets us reduce the time required to get the 
+		 * next command out to the device, hopefully this will
+		 * mean we don't waste another revolution due to the delays
+		 * required by ARBITRATION and another SELECTION.
+		 *
+		 * In the current implementation proposal, low level drivers
+		 * merely have to start the next command, pointed to by 
+		 * next_link, done() is called as with unlinked commands.
+		 */
+#ifdef LINKED
+		case LINKED_CMD_COMPLETE:
+		case LINKED_FLG_CMD_COMPLETE:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    
+		    LNK_PRINTK("scsi%d: target %d lun %d linked command "
+			       "complete.\n", HOSTNO, cmd->target, cmd->lun);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /*
+		     * Sanity check : A linked command should only terminate
+		     * with one of these messages if there are more linked
+		     * commands available.
+		     */
+
+		    if (!cmd->next_link) {
+			 printk(KERN_NOTICE "scsi%d: target %d lun %d "
+				"linked command complete, no next_link\n",
+				HOSTNO, cmd->target, cmd->lun);
+			    sink = 1;
+			    do_abort (instance);
+			    return;
+		    }
+
+		    initialize_SCp(cmd->next_link);
+		    /* The next command is still part of this process; copy it
+		     * and don't free it! */
+		    cmd->next_link->tag = cmd->tag;
+		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    LNK_PRINTK("scsi%d: target %d lun %d linked request "
+			       "done, calling scsi_done().\n",
+			       HOSTNO, cmd->target, cmd->lun);
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    cmd = hostdata->connected;
+		    break;
+#endif /* def LINKED */
+		case ABORT:
+		case COMMAND_COMPLETE: 
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    hostdata->connected = NULL;
+		    QU_PRINTK("scsi%d: command for target %d, lun %d "
+			      "completed\n", HOSTNO, cmd->target, cmd->lun);
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+		    if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+			/* Turn a QUEUE FULL status into BUSY, I think the
+			 * mid level cannot handle QUEUE FULL :-( (The
+			 * command is retried after BUSY). Also update our
+			 * queue size to the number of currently issued
+			 * commands now.
+			 */
+			/* ++Andreas: the mid level code knows about
+			   QUEUE_FULL now. */
+			TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
+			TAG_PRINTK("scsi%d: target %d lun %d returned "
+				   "QUEUE_FULL after %d commands\n",
+				   HOSTNO, cmd->target, cmd->lun,
+				   ta->nr_allocated);
+			if (ta->queue_size > ta->nr_allocated)
+			    ta->nr_allocated = ta->queue_size;
+		    }
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+		    /* 
+		     * I'm not sure what the correct thing to do here is : 
+		     * 
+		     * If the command that just executed is NOT a request 
+		     * sense, the obvious thing to do is to set the result
+		     * code to the values of the stored parameters.
+		     * 
+		     * If it was a REQUEST SENSE command, we need some way to
+		     * differentiate between the failure code of the original
+		     * and the failure code of the REQUEST sense - the obvious
+		     * case is success, where we fall through and leave the
+		     * result code unchanged.
+		     * 
+		     * The non-obvious place is where the REQUEST SENSE failed
+		     */
+
+		    if (cmd->cmnd[0] != REQUEST_SENSE) 
+			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    else if (status_byte(cmd->SCp.Status) != GOOD)
+			cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+		    
+#ifdef AUTOSENSE
+		    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
+			(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+			ASEN_PRINTK("scsi%d: performing request sense\n",
+				    HOSTNO);
+			cmd->cmnd[0] = REQUEST_SENSE;
+			cmd->cmnd[1] &= 0xe0;
+			cmd->cmnd[2] = 0;
+			cmd->cmnd[3] = 0;
+			cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+			cmd->cmnd[5] = 0;
+			cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+			cmd->use_sg = 0;
+			/* this is initialized from initialize_SCp 
+			cmd->SCp.buffer = NULL;
+			cmd->SCp.buffers_residual = 0;
+			*/
+			cmd->request_buffer = (char *) cmd->sense_buffer;
+			cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+			save_flags(flags);
+			cli();
+			LIST(cmd,hostdata->issue_queue);
+			NEXT(cmd) = hostdata->issue_queue;
+		        hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+		        restore_flags(flags);
+			QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+				  "issue queue\n", H_NO(cmd));
+		   } else
+#endif /* def AUTOSENSE */
+		   {
+#ifdef NCR5380_STATS
+		       collect_stats(hostdata, cmd);
+#endif
+		       cmd->scsi_done(cmd);
+		    }
+
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+		    
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+			barrier();
+
+		    return;
+		case MESSAGE_REJECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    switch (hostdata->last_message) {
+		    case HEAD_OF_QUEUE_TAG:
+		    case ORDERED_QUEUE_TAG:
+		    case SIMPLE_QUEUE_TAG:
+			/* The target obviously doesn't support tagged
+			 * queuing, even though it announced this ability in
+			 * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+			 * clear 'tagged_supported' and lock the LUN, since
+			 * the command is treated as untagged further on.
+			 */
+			cmd->device->tagged_supported = 0;
+			hostdata->busy[cmd->target] |= (1 << cmd->lun);
+			cmd->tag = TAG_NONE;
+			TAG_PRINTK("scsi%d: target %d lun %d rejected "
+				   "QUEUE_TAG message; tagged queuing "
+				   "disabled\n",
+				   HOSTNO, cmd->target, cmd->lun);
+			break;
+		    }
+		    break;
+		case DISCONNECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    save_flags(flags);
+		    cli();
+		    cmd->device->disconnect = 1;
+		    LIST(cmd,hostdata->disconnected_queue);
+		    NEXT(cmd) = hostdata->disconnected_queue;
+		    hostdata->connected = NULL;
+		    hostdata->disconnected_queue = cmd;
+		    restore_flags(flags);
+		    QU_PRINTK("scsi%d: command for target %d lun %d was "
+			      "moved from connected to the "
+			      "disconnected_queue\n", HOSTNO, 
+			      cmd->target, cmd->lun);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* Wait for bus free to avoid nasty timeouts */
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+		    	barrier();
+		    return;
+		/* 
+		 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+		 * operation, in violation of the SCSI spec so we can safely 
+		 * ignore SAVE/RESTORE pointers calls.
+		 *
+		 * Unfortunately, some disks violate the SCSI spec and 
+		 * don't issue the required SAVE_POINTERS message before
+		 * disconnecting, and we have to break spec to remain 
+		 * compatible.
+		 */
+		case SAVE_POINTERS:
+		case RESTORE_POINTERS:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    break;
+		case EXTENDED_MESSAGE:
+/* 
+ * Extended messages are sent in the following format :
+ * Byte 	
+ * 0		EXTENDED_MESSAGE == 1
+ * 1		length (includes one byte for code, doesn't 
+ *		include first two bytes)
+ * 2 		code
+ * 3..length+1	arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since print_msg() wants the whole thing.  
+ */
+		    extended_msg[0] = EXTENDED_MESSAGE;
+		    /* Accept first byte by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+		    EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+		    len = 2;
+		    data = extended_msg + 1;
+		    phase = PHASE_MSGIN;
+		    NCR5380_transfer_pio(instance, &phase, &len, &data);
+		    EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+			       (int)extended_msg[1], (int)extended_msg[2]);
+
+		    if (!len && extended_msg[1] <= 
+			(sizeof (extended_msg) - 1)) {
+			/* Accept third byte by clearing ACK */
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+			len = extended_msg[1] - 1;
+			data = extended_msg + 3;
+			phase = PHASE_MSGIN;
+
+			NCR5380_transfer_pio(instance, &phase, &len, &data);
+			EXT_PRINTK("scsi%d: message received, residual %d\n",
+				   HOSTNO, len);
+
+			switch (extended_msg[2]) {
+			case EXTENDED_SDTR:
+			case EXTENDED_WDTR:
+			case EXTENDED_MODIFY_DATA_POINTER:
+			case EXTENDED_EXTENDED_IDENTIFY:
+			    tmp = 0;
+			}
+		    } else if (len) {
+			printk(KERN_NOTICE "scsi%d: error receiving "
+			       "extended message\n", HOSTNO);
+			tmp = 0;
+		    } else {
+			printk(KERN_NOTICE "scsi%d: extended message "
+			       "code %02x length %d is too long\n",
+			       HOSTNO, extended_msg[2], extended_msg[1]);
+			tmp = 0;
+		    }
+		/* Fall through to reject message */
+
+		/* 
+  		 * If we get something weird that we aren't expecting, 
+ 		 * reject it.
+		 */
+		default:
+		    if (!tmp) {
+			printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+			print_msg (extended_msg);
+			printk("\n");
+		    } else if (tmp != EXTENDED_MESSAGE)
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "message %02x from target %d, lun %d\n",
+			       HOSTNO, tmp, cmd->target, cmd->lun);
+		    else
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "extended message "
+			       "code %02x, length %d from target %d, lun %d\n",
+			       HOSTNO, extended_msg[1], extended_msg[0],
+			       cmd->target, cmd->lun);
+   
+
+		    msgout = MESSAGE_REJECT;
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_ATN);
+		    break;
+		} /* switch (tmp) */
+		break;
+	    case PHASE_MSGOUT:
+		len = 1;
+		data = &msgout;
+		hostdata->last_message = msgout;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		if (msgout == ABORT) {
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    hostdata->connected = NULL;
+		    cmd->result = DID_ERROR << 16;
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    return;
+		}
+		msgout = NOP;
+		break;
+	    case PHASE_CMDOUT:
+		len = cmd->cmd_len;
+		data = cmd->cmnd;
+		/* 
+		 * XXX for performance reasons, on machines with a 
+		 * PSEUDO-DMA architecture we should probably 
+		 * use the dma transfer function.  
+		 */
+		NCR5380_transfer_pio(instance, &phase, &len, 
+		    &data);
+		break;
+	    case PHASE_STATIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Status = tmp;
+		break;
+	    default:
+		printk("scsi%d: unknown phase\n", HOSTNO);
+		NCR_PRINT(NDEBUG_ANY);
+	    } /* switch(phase) */
+	} /* if (tmp * SR_REQ) */ 
+    } /* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected 
+ *	field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q 
+ *	nexus has been reestablished,
+ *	
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+
+static void NCR5380_reselect (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char target_mask;
+    unsigned char lun, phase;
+    int len;
+#ifdef SUPPORT_TAGS
+    unsigned char tag;
+#endif
+    unsigned char msg[3];
+    unsigned char *data;
+    Scsi_Cmnd *tmp = NULL, *prev;
+/*    unsigned long flags; */
+
+    /*
+     * Disable arbitration, etc. since the host adapter obviously
+     * lost, and tell an interrupted NCR5380_select() to restart.
+     */
+
+    NCR5380_write(MODE_REG, MR_BASE);
+    hostdata->restart_select = 1;
+
+    target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+    RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+    /* 
+     * At this point, we have detected that our SCSI ID is on the bus,
+     * SEL is true and BSY was false for at least one bus settle delay
+     * (400 ns).
+     *
+     * We must assert BSY ourselves, until the target drops the SEL
+     * signal.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+    
+    while (NCR5380_read(STATUS_REG) & SR_SEL);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    /*
+     * Wait for target to go into MSGIN.
+     */
+
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+    len = 1;
+    data = msg;
+    phase = PHASE_MSGIN;
+    NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+    if (!msg[0] & 0x80) {
+	printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+	print_msg(msg);
+	do_abort(instance);
+	return;
+    }
+    lun = (msg[0] & 0x07);
+
+#ifdef SUPPORT_TAGS
+    /* If the phase is still MSGIN, the target wants to send some more
+     * messages. In case it supports tagged queuing, this is probably a
+     * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+     */
+    tag = TAG_NONE;
+    if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+	/* Accept previous IDENTIFY message by clearing ACK */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	len = 2;
+	data = msg+1;
+	if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+	    msg[1] == SIMPLE_QUEUE_TAG)
+	    tag = msg[2];
+	TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+		   "reselection\n", HOSTNO, target_mask, lun, tag);
+    }
+#endif
+    
+    /* 
+     * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
+     * just reestablished, and remove it from the disconnected queue.
+     */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
+	 tmp; prev = tmp, tmp = NEXT(tmp) ) {
+	if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+#ifdef SUPPORT_TAGS
+	    && (tag == tmp->tag) 
+#endif
+	    ) {
+	    if (prev) {
+		REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+		NEXT(prev) = NEXT(tmp);
+	    } else {
+		REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+		hostdata->disconnected_queue = NEXT(tmp);
+	    }
+	    NEXT(tmp) = NULL;
+	    break;
+	}
+    }
+    
+    if (!tmp) {
+	printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+#ifdef SUPPORT_TAGS
+		"tag %d "
+#endif
+		"not in disconnect_queue.\n",
+		HOSTNO, target_mask, lun
+#ifdef SUPPORT_TAGS
+		, tag
+#endif
+		);
+	/* 
+	 * Since we have an established nexus that we can't do anything
+	 * with, we must abort it.  
+	 */
+	do_abort(instance);
+	return;
+    }
+
+    /* Accept message by clearing ACK */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    hostdata->connected = tmp;
+    RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+	       HOSTNO, tmp->target, tmp->lun, tmp->tag);
+}
+
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the 
+ * 	host byte of the result field to, if zero DID_ABORTED is 
+ *	used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ * XXX - there is no way to abort the command that is currently 
+ * 	 connected, you have to wait for it to complete.  If this is 
+ *	 a problem, we could implement longjmp() / setjmp(), setjmp()
+ * 	 called where the loop started in NCR5380_main().
+ */
+
+#ifndef NCR5380_abort
+static
+#endif
+int NCR5380_abort (Scsi_Cmnd *cmd)
+{
+    struct Scsi_Host *instance = cmd->host;
+    SETUP_HOSTDATA(instance);
+    Scsi_Cmnd *tmp, **prev;
+    unsigned long flags;
+
+    printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+    print_Scsi_Cmnd (cmd);
+
+    NCR5380_print_status (instance);
+
+    save_flags(flags);
+    cli();
+    
+    ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+		NCR5380_read(BUS_AND_STATUS_REG),
+		NCR5380_read(STATUS_REG));
+
+#if 1
+/* 
+ * Case 1 : If the command is the currently executing command, 
+ * we'll set the aborted flag and return control so that 
+ * information transfer routine can exit cleanly.
+ */
+
+    if (hostdata->connected == cmd) {
+
+	ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+/*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
+
+/*	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+/* 
+ * Since we can't change phases until we've completed the current 
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
+
+/* 
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */ 
+
+	if (do_abort(instance) == 0) {
+	  hostdata->aborted = 1;
+	  hostdata->connected = NULL;
+	  cmd->result = DID_ABORT << 16;
+#ifdef SUPPORT_TAGS
+	  cmd_free_tag( cmd );
+#else
+	  hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+	  restore_flags(flags);
+	  cmd->scsi_done(cmd);
+	  return SCSI_ABORT_SUCCESS;
+	} else {
+/*	  restore_flags(flags); */
+	  printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+	  return SCSI_ABORT_ERROR;
+	} 
+   }
+#endif
+
+/* 
+ * Case 2 : If the command hasn't been issued yet, we simply remove it 
+ * 	    from the issue queue.
+ */
+    for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), 
+	tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+	tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+	if (cmd == tmp) {
+	    REMOVE(5, *prev, tmp, NEXT(tmp));
+	    (*prev) = NEXT(tmp);
+	    NEXT(tmp) = NULL;
+	    tmp->result = DID_ABORT << 16;
+	    restore_flags(flags);
+	    ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+			HOSTNO);
+	    /* Tagged queuing note: no tag to free here, hasn't been assigned
+	     * yet... */
+	    tmp->scsi_done(tmp);
+	    return SCSI_ABORT_SUCCESS;
+	}
+
+/* 
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ *	    and let the high level SCSI driver retry at a later time or 
+ *	    issue a reset.
+ *
+ *	    Timeouts, and therefore aborted commands, will be highly unlikely
+ *          and handling them cleanly in this situation would make the common
+ *	    case of noresets less efficient, and would pollute our code.  So,
+ *	    we fail.
+ */
+
+    if (hostdata->connected) {
+	restore_flags(flags);
+	ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+        return SCSI_ABORT_SNOOZE;
+    }
+
+/*
+ * Case 4: If the command is currently disconnected from the bus, and 
+ * 	there are no connected commands, we reconnect the I_T_L or 
+ *	I_T_L_Q nexus associated with it, go into message out, and send 
+ *      an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select().  The easiest way to implement this 
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we 
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that 
+ * device reselected.
+ * 
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+	 tmp = NEXT(tmp)) 
+        if (cmd == tmp) {
+            restore_flags(flags);
+	    ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
+  
+            if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
+		return SCSI_ABORT_BUSY;
+
+	    ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+	    do_abort (instance);
+
+	    save_flags(flags);
+	    cli();
+	    for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), 
+		tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+		tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+		    if (cmd == tmp) {
+		    REMOVE(5, *prev, tmp, NEXT(tmp));
+		    *prev = NEXT(tmp);
+		    NEXT(tmp) = NULL;
+		    tmp->result = DID_ABORT << 16;
+		    /* We must unlock the tag/LUN immediately here, since the
+		     * target goes to BUS FREE and doesn't send us another
+		     * message (COMMAND_COMPLETE or the like)
+		     */
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( tmp );
+#else
+		    hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+		    restore_flags(flags);
+		    tmp->scsi_done(tmp);
+		    return SCSI_ABORT_SUCCESS;
+		}
+	}
+
+/*
+ * Case 5 : If we reached this point, the command was not found in any of 
+ *	    the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+    restore_flags(flags);
+    printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+           KERN_INFO "        before abortion\n", HOSTNO); 
+
+/* Maybe it is sufficient just to release the ST-DMA lock... (if
+ * possible at all) At least, we should check if the lock could be
+ * released after the abort, in case it is kept due to some bug.
+ */
+
+    return SCSI_ABORT_NOT_RUNNING;
+}
+
+
+/* 
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags)
+ * 
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SCSI_RESET_WAKEUP
+ *
+ */ 
+
+static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+{
+    SETUP_HOSTDATA(cmd->host);
+    int           i;
+    unsigned long flags;
+#if 1
+    Scsi_Cmnd *connected, *disconnected_queue;
+#endif
+
+    NCR5380_print_status (cmd->host);
+
+    /* get in phase */
+    NCR5380_write( TARGET_COMMAND_REG,
+		   PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+    /* assert RST */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+    udelay (40);
+    /* reset NCR registers */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+    NCR5380_write( MODE_REG, MR_BASE );
+    NCR5380_write( TARGET_COMMAND_REG, 0 );
+    NCR5380_write( SELECT_ENABLE_REG, 0 );
+    /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+     * through anymore ... */
+    (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+      /* XXX see below                                            XXX */
+
+    /* MSch: old-style reset: actually abort all command processing here */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; to avoid problems with re-inserting the commands
+     * into the issue_queue (via scsi_done()), the aborted commands are
+     * remembered in local variables first.
+     */
+    save_flags(flags);
+    cli();
+    connected = (Scsi_Cmnd *)hostdata->connected;
+    hostdata->connected = NULL;
+    disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    restore_flags(flags);
+
+    /* In order to tell the mid-level code which commands were aborted, 
+     * set the command status to DID_RESET and call scsi_done() !!!
+     * This ultimately aborts processing of these commands in the mid-level.
+     */
+
+    if ((cmd = connected)) {
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+
+    for (i = 0; (cmd = disconnected_queue); ++i) {
+	disconnected_queue = NEXT(cmd);
+	NEXT(cmd) = NULL;
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+    if (i > 0)
+	ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+    /* since all commands have been explicitly terminated, we need to tell
+     * the midlevel code that the reset was SUCCESSFUL, and there is no 
+     * need to 'wake up' the commands by a request_sense
+     */
+    return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+#else /* 1 */
+
+    /* MSch: new-style reset handling: let the mid-level do what it can */
+
+    /* ++guenther: MID-LEVEL IS STILL BROKEN.
+     * Mid-level is supposed to requeue all commands that were active on the
+     * various low-level queues. In fact it does this, but that's not enough
+     * because all these commands are subject to timeout. And if a timeout
+     * happens for any removed command, *_abort() is called but all queues
+     * are now empty. Abort then gives up the falcon lock, which is fatal,
+     * since the mid-level will queue more commands and must have the lock
+     * (it's all happening inside timer interrupt handler!!).
+     * Even worse, abort will return NOT_RUNNING for all those commands not
+     * on any queue, so they won't be retried ...
+     *
+     * Conclusion: either scsi.c disables timeout for all resetted commands
+     * immediately, or we loose!  As of linux-2.0.20 it doesn't.
+     */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; so clear the low-level status here to avoid 
+     * conflicts when the mid-level code tries to wake up the affected 
+     * commands!
+     */
+
+    if (hostdata->issue_queue)
+	ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+    if (hostdata->connected) 
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+    if (hostdata->disconnected_queue)
+	ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+    save_flags(flags);
+    cli();
+    hostdata->issue_queue = NULL;
+    hostdata->connected = NULL;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    restore_flags(flags);
+
+    /* we did no complete reset of all commands, so a wakeup is required */
+    return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+#endif /* 1 */
+}
+
+/* Local Variables: */
+/* tab-width: 8     */
+/* End:             */
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/mac_scsi.c linux/drivers/scsi/mac_scsi.c
--- v2.1.112/linux/drivers/scsi/mac_scsi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/mac_scsi.c	Thu Jul 30 11:17:10 1998
@@ -0,0 +1,1107 @@
+/*
+ * mac_scsi.c   -- Device dependent functions for the Macintosh NCR5380 SCSI 
+ *		   port (MacII style machines, no DMA).
+ *
+ * based on:
+ */
+
+/*
+ * atari_scsi.c -- Device dependent functions for the Atari generic SCSI port
+ *
+ * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ *   Loosely based on the work of Robert De Vries' team and added:
+ *    - working real DMA
+ *    - Falcon support (untested yet!)   ++bjoern fixed and now it works
+ *    - lots of extensions and bug fixes.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#define NDEBUG_ABORT	0x800000
+#define NDEBUG_TAGS	0x1000000
+#define NDEBUG_MERGING	0x2000000
+
+#define NDEBUG (0)
+
+#define AUTOSENSE
+/* MSch: Tested the pseudo-DMA code on Atari for the Mac68k port ... */
+/* Defining neither PSEUDO_DMA nor REAL_DMA -> PIO transfer, sloooow ! */
+/*#define	REAL_DMA*/ /* never supported on NCR5380 Macs */
+/*
+ * Usage: define PSEUDO_DMA to use hardware-handshaked PIO mode (TBI)
+ *        undef  PSEUDO_DMA to use pure PIO mode
+ */
+
+/*#define PSEUDO_DMA*/	/* currently gives trouble on some Macs */
+
+#ifdef PSEUDO_DMA
+#define EMULATE_PSEUDO_DMA
+#define DMA_WORKS_RIGHT
+#define UNSAFE
+#endif
+
+/* Support tagged queuing? (on devices that are able to... :-) */
+#define	SUPPORT_TAGS
+#define	MAX_TAGS 32
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include <asm/setup.h>
+#include <asm/machw.h>
+#include <asm/macints.h>
+#include <asm/macintosh.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/bitops.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "mac_scsi.h"
+#include "NCR5380.h"
+#include "constants.h"
+#include <asm/io.h>
+
+#include <linux/stat.h>
+
+struct proc_dir_entry proc_scsi_mac = {
+    PROC_SCSI_MAC, 8, "mac_5380",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+/*
+ * Define RBV_HACK to run the SCSI driver on RBV Macs; undefine to
+ * try getting better interrupt latency
+ */
+#define RBV_HACK
+
+#ifdef RBV_HACK
+#define	ENABLE_IRQ()	mac_turnon_irq( IRQ_MAC_SCSI ); 
+#define	DISABLE_IRQ()	mac_turnoff_irq( IRQ_MAC_SCSI );
+#else
+#define	ENABLE_IRQ()	mac_enable_irq( IRQ_MAC_SCSI ); 
+#define	DISABLE_IRQ()	mac_disable_irq( IRQ_MAC_SCSI );
+#endif
+
+#define HOSTDATA_DMALEN		(((struct NCR5380_hostdata *) \
+				(mac_scsi_host->hostdata))->dma_len)
+
+/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
+ * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
+ * need ten times the standard value... */
+#ifndef CONFIG_MAC_SCSI_TOSHIBA_DELAY
+#define	AFTER_RESET_DELAY	(HZ/2)
+#else
+#define	AFTER_RESET_DELAY	(5*HZ/2)
+#endif
+
+/***************************** Prototypes *****************************/
+
+#ifdef REAL_DMA
+static int scsi_dma_is_ignored_buserr( unsigned char dma_stat );
+static void mac_scsi_fetch_restbytes( void );
+static long mac_scsi_dma_residual( struct Scsi_Host *instance );
+static int mac_classify_cmd( Scsi_Cmnd *cmd );
+static unsigned long mac_dma_xfer_len( unsigned long wanted_len,
+                                       Scsi_Cmnd *cmd, int write_flag );
+#endif
+#ifdef PSEUDO_DMA
+static int mac_pdma_read(struct Scsi_Host *instance, unsigned char *dst,
+			   int len);
+static int mac_pdma_write(struct Scsi_Host *instance, unsigned char *src,
+			   int len);
+static unsigned long mac_dma_xfer_len( unsigned long wanted_len,
+                                         Scsi_Cmnd *cmd, int write_flag );
+#endif
+static void scsi_mac_intr( int irq, void *dummy, struct pt_regs *fp);
+static void mac_scsi_reset_boot( void );
+static unsigned char mac_scsi_reg_read( unsigned char reg );
+static void mac_scsi_reg_write( unsigned char reg, unsigned char value);
+
+/************************* End of Prototypes **************************/
+
+
+static struct Scsi_Host *mac_scsi_host = NULL;
+#if 0
+static unsigned char (*mac_scsi_reg_read)( unsigned char reg );
+static void (*mac_scsi_reg_write)( unsigned char reg, unsigned char value );
+#endif
+
+#ifdef REAL_DMA
+static unsigned long	mac_dma_residual, mac_dma_startaddr;
+static short		mac_dma_active;
+/* pointer to the dribble buffer */
+static char		*mac_dma_buffer = NULL;
+/* precalculated physical address of the dribble buffer */
+static unsigned long	mac_dma_phys_buffer;
+/* != 0 tells the int handler to copy data from the dribble buffer */
+static char		*mac_dma_orig_addr;
+/* size of the dribble buffer; 4k seems enough, since the Falcon cannot use
+ * scatter-gather anyway, so most transfers are 1024 byte only. In the rare
+ * cases where requests to physical contiguous buffers have been merged, this
+ * request is <= 4k (one page). So I don't think we have to split transfers
+ * just due to this buffer size...
+ */
+#define	MAC_BUFFER_SIZE	(4096)
+#if 1  /* FIXME: is that an issue for Macs?? */
+/* mask for address bits that can't be used with the ST-DMA */
+static unsigned long	mac_dma_stram_mask;
+#define STRAM_ADDR(a)	(((a) & mac_dma_stram_mask) == 0)
+#endif
+/* number of bytes to cut from a transfer to handle NCR overruns */
+static int mac_read_overruns = 0;
+#endif
+#ifdef PSEUDO_DMA
+static unsigned long	mac_pdma_residual, mac_pdma_startaddr, mac_pdma_current;
+static short		mac_pdma_active;
+/* FIXME: is that an issue for Macs?? */
+/* mask for address bits that can't be used with the ST-DMA */
+static unsigned long	mac_dma_stram_mask;
+#define STRAM_ADDR(a)	(((a) & mac_dma_stram_mask) == 0)
+static int mac_read_overruns = 0;
+#endif
+static int setup_can_queue = -1;
+static int setup_cmd_per_lun = -1;
+static int setup_sg_tablesize = -1;
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+#endif
+static int setup_hostid = -1;
+
+
+#if defined(REAL_DMA)
+
+#if 0  /* FIXME */
+static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
+{
+	int i;
+	unsigned long	addr = SCSI_DMA_READ_P( dma_addr ), end_addr;
+
+	if (dma_stat & 0x01) {
+
+		/* A bus error happens when DMA-ing from the last page of a
+		 * physical memory chunk (DMA prefetch!), but that doesn't hurt.
+		 * Check for this case:
+		 */
+		
+		for( i = 0; i < boot_info.num_memory; ++i ) {
+			end_addr = boot_info.memory[i].addr +
+				boot_info.memory[i].size;
+			if (end_addr <= addr && addr <= end_addr + 4)
+				return( 1 );
+		}
+	}
+	return( 0 );
+}
+
+
+/* Dead code... wasn't called anyway :-) and causes some trouble, because at
+ * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
+ * to clear the DMA int pending bit before it allows other level 6 interrupts.
+ */
+static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned char	dma_stat = tt_scsi_dma.dma_ctrl;
+
+	/* Don't do anything if a NCR interrupt is pending. Probably it's just
+	 * masked... */
+	if (mac_irq_pending( IRQ_MAC_SCSI ))
+		return;
+	
+	printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
+	       SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
+	if (dma_stat & 0x80) {
+		if (!scsi_dma_is_ignored_buserr( dma_stat ))
+			printk( "SCSI DMA bus error -- bad DMA programming!\n" );
+	}
+	else {
+		/* Under normal circumstances we never should get to this point,
+		 * since both interrupts are triggered simultaneously and the 5380
+		 * int has higher priority. When this irq is handled, that DMA
+		 * interrupt is cleared. So a warning message is printed here.
+		 */
+		printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
+	}
+}
+#endif
+
+#endif
+
+void restore_irq(struct pt_regs *regs)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	flags = (flags & ~0x0700) | (regs->sr & 0x0700);
+	restore_flags(flags);
+}
+
+static int polled_scsi_on = 0;
+static unsigned char *mac_scsi_regp = NULL;
+
+void scsi_mac_polled (void)
+{
+	if (polled_scsi_on)
+	{
+		if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
+		{
+			printk("SCSI poll\n");
+			scsi_mac_intr(IRQ_MAC_SCSI, NULL, NULL);
+		}
+	}
+}
+
+static void scsi_mac_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned long flags;
+#ifdef REAL_DMA
+	int dma_stat;
+
+	dma_stat = mac_scsi_dma.dma_ctrl;
+
+	INT_PRINTK("scsi%d: NCR5380 interrupt, DMA status = %02x\n",
+		   mac_scsi_host->host_no, dma_stat & 0xff);
+
+	/* Look if it was the DMA that has interrupted: First possibility
+	 * is that a bus error occurred...
+	 */
+	if (dma_stat & 0x80) {
+		if (!scsi_dma_is_ignored_buserr( dma_stat )) {
+			printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
+			       SCSI_DMA_READ_P(dma_addr));
+			printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
+		}
+	}
+
+	/* If the DMA is active but not finished, we have the the case
+	 * that some other 5380 interrupt occurred within the DMA transfer.
+	 * This means we have residual bytes, if the desired end address
+	 * is not yet reached. Maybe we have to fetch some bytes from the
+	 * rest data register, too. The residual must be calculated from
+	 * the address pointer, not the counter register, because only the
+	 * addr reg counts bytes not yet written and pending in the rest
+	 * data reg!
+	 */
+	if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
+		mac_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
+												mac_dma_startaddr);
+
+		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
+			   mac_dma_residual);
+
+		if ((signed int)mac_dma_residual < 0)
+			mac_dma_residual = 0;
+		if ((dma_stat & 1) == 0) {
+			/* After read operations, we maybe have to
+			   transport some rest bytes */
+			mac_scsi_fetch_restbytes();
+		}
+		else {
+			/* There seems to be a nasty bug in some SCSI-DMA/NCR
+			   combinations: If a target disconnects while a write
+			   operation is going on, the address register of the
+			   DMA may be a few bytes farer than it actually read.
+			   This is probably due to DMA prefetching and a delay
+			   between DMA and NCR.  Experiments showed that the
+			   dma_addr is 9 bytes to high, but this could vary.
+			   The problem is, that the residual is thus calculated
+			   wrong and the next transfer will start behind where
+			   it should.  So we round up the residual to the next
+			   multiple of a sector size, if it isn't already a
+			   multiple and the originally expected transfer size
+			   was.  The latter condition is there to ensure that
+			   the correction is taken only for "real" data
+			   transfers and not for, e.g., the parameters of some
+			   other command.  These shouldn't disconnect anyway.
+			   */
+			if (mac_dma_residual & 0x1ff) {
+				DMA_PRINTK("SCSI DMA: DMA bug corrected, "
+					   "difference %ld bytes\n",
+					   512 - (mac_dma_residual & 0x1ff));
+				mac_dma_residual = (mac_dma_residual + 511) & ~0x1ff;
+			}
+		}
+		mac_scsi_dma.dma_ctrl = 0;
+	}
+
+	/* If the DMA is finished, fetch the rest bytes and turn it off */
+	if (dma_stat & 0x40) {
+		atari_dma_residual = 0;
+		if ((dma_stat & 1) == 0)
+			atari_scsi_fetch_restbytes();
+		tt_scsi_dma.dma_ctrl = 0;
+	}
+
+#endif /* REAL_DMA */
+
+#ifdef PSEUDO_DMA
+	/* determine if there is any residual for the current transfer */
+	if (mac_pdma_active) {
+	  /* probably EOP interrupt, signaling i.e. target disconnect.
+	   * We must figure out the residual from the source/destination
+	   * pointers here ... */
+	  /* Should check bus status here to make sure it wasn't reselect or reset */
+	  mac_pdma_residual = HOSTDATA_DMALEN - (mac_pdma_current - mac_pdma_startaddr);
+	  mac_pdma_active = 0;
+	}
+#endif
+
+#ifdef RBV_HACK
+	mac_turnoff_irq( IRQ_MAC_SCSI );
+#else
+	mac_disable_irq( IRQ_MAC_SCSI );
+#endif
+
+	save_flags(flags);
+#ifndef RBV_HACK	/* interferes with level triggered RBV IRQs ?? */
+	restore_irq(fp);
+#endif
+
+	if ( irq == IRQ_IDX(IRQ_MAC_SCSI) )
+		NCR5380_intr (irq, dummy, fp);
+
+	restore_flags(flags);
+
+	/* To be sure the int is not masked */
+#ifdef RBV_HACK
+	mac_turnon_irq( IRQ_MAC_SCSI );
+#else
+	mac_enable_irq( IRQ_MAC_SCSI );
+#endif
+
+	/* Clear the IRQ */
+	via_scsi_clear();
+}
+
+
+#ifdef REAL_DMA
+static void mac_scsi_fetch_restbytes( void )
+{
+	int nr;
+	char	*src, *dst;
+
+	/* fetch rest bytes in the DMA register */
+	dst = (char *)SCSI_DMA_READ_P( dma_addr );
+	if ((nr = ((long)dst & 3))) {
+		/* there are 'nr' bytes left for the last long address before the
+		   DMA pointer */
+		dst = (char *)( (unsigned long)dst & ~3 );
+		DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
+			   nr, (long)dst);
+		dst = (char *)PTOV(dst);  /* The content of the DMA pointer
+					   * is a physical address! */
+		DMA_PRINTK(" = virt addr 0x%08lx\n", (long)dst);
+		for( src = (char *)&mac_scsi_dma.dma_restdata; nr > 0; --nr )
+			*dst++ = *src++;
+	}
+}
+#endif /* REAL_DMA */
+
+#if 0  /* FIXME : how is the host ID determined on a Mac? */
+#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)
+#endif
+				   
+int mac_scsi_detect (Scsi_Host_Template *host)
+{
+	static int called = 0;
+	struct Scsi_Host *instance;
+
+	if (!MACH_IS_MAC || called)
+		return( 0 );
+
+	if (macintosh_config->scsi_type != MAC_SCSI_OLD)
+		return( 0 );
+
+	host->proc_dir = &proc_scsi_mac;
+
+	/* testing: IIfx SCSI without IOP ?? */
+	if (macintosh_config->ident == MAC_MODEL_IIFX)
+		mac_scsi_regp = via1_regp+0x8000;
+	else
+		mac_scsi_regp = via1_regp+0x10000;
+
+#if 0  /* maybe if different SCSI versions show up ? */
+	mac_scsi_reg_read  = IS_A_TT() ? atari_scsi_tt_reg_read :
+					   atari_scsi_falcon_reg_read;
+	mac_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :
+#endif					   atari_scsi_falcon_reg_write;
+
+	/* setup variables */
+	host->can_queue =
+		(setup_can_queue > 0) ? setup_can_queue :
+		MAC_SCSI_CAN_QUEUE;
+	host->cmd_per_lun =
+		(setup_cmd_per_lun > 0) ? setup_cmd_per_lun :
+		MAC_SCSI_CMD_PER_LUN;
+	host->sg_tablesize =
+		(setup_sg_tablesize >= 0) ? setup_sg_tablesize : MAC_SCSI_SG_TABLESIZE;
+
+	if (setup_hostid >= 0)
+		host->this_id = setup_hostid;
+	else {
+		/* use 7 as default */
+		host->this_id = 7;
+	}
+
+#ifdef SUPPORT_TAGS
+	if (setup_use_tagged_queuing < 0)
+		setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
+#endif
+
+	instance = scsi_register (host, sizeof (struct NCR5380_hostdata));
+	mac_scsi_host = instance;
+
+	/* truncation of machspec bit not critical as instance->irq never used */
+#if 0	/* Might work; problem was only with Falcon lock */
+	instance->irq = IRQ_MAC_SCSI;
+#else
+	instance->irq = 0;
+#endif
+	mac_scsi_reset_boot();
+	NCR5380_init (instance, 0);
+
+       	/* This int is actually "pseudo-slow", i.e. it acts like a slow
+	 * interrupt after having cleared the pending flag for the DMA
+	 * interrupt. */
+	request_irq(IRQ_MAC_SCSI, scsi_mac_intr, IRQ_TYPE_SLOW,
+	            "SCSI NCR5380", scsi_mac_intr);
+#ifdef REAL_DMA
+	tt_scsi_dma.dma_ctrl = 0;
+	atari_dma_residual = 0;
+
+	if (is_brokenscsi) {
+		/* While the read overruns (described by Drew Eckhardt in
+		 * NCR5380.c) never happened on TTs, they do in fact on the Medusa
+		 * (This was the cause why SCSI didn't work right for so long
+		 * there.) Since handling the overruns slows down a bit, I turned
+		 * the #ifdef's into a runtime condition.
+		 *
+		 * In principle it should be sufficient to do max. 1 byte with
+		 * PIO, but there is another problem on the Medusa with the DMA
+		 * rest data register. So 'atari_read_overruns' is currently set
+		 * to 4 to avoid having transfers that aren't a multiple of 4. If
+		 * the rest data bug is fixed, this can be lowered to 1.
+		 */
+		mac_read_overruns = 4;
+	}
+#endif /* REAL_DMA */
+
+#ifdef PSEUDO_DMA
+	mac_pdma_residual = 0;
+	mac_pdma_active   = 0;
+#endif
+
+	printk(KERN_INFO "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "
+#ifdef SUPPORT_TAGS
+			"TAGGED-QUEUING=%s "
+#endif
+			"HOSTID=%d",
+			instance->host_no, instance->hostt->can_queue,
+			instance->hostt->cmd_per_lun,
+			instance->hostt->sg_tablesize,
+#ifdef SUPPORT_TAGS
+			setup_use_tagged_queuing ? "yes" : "no",
+#endif
+			instance->hostt->this_id );
+	NCR5380_print_options (instance);
+	printk ("\n");
+
+	called = 1;
+	return( 1 );
+}
+
+#ifdef MODULE
+int mac_scsi_release (struct Scsi_Host *sh)
+{
+       	free_irq(IRQ_MAC_SCSI, scsi_mac_intr);
+	if (mac_dma_buffer)
+		scsi_init_free (mac_dma_buffer, MAC_BUFFER_SIZE);
+	return 1;
+}
+#endif
+
+void mac_scsi_setup( char *str, int *ints )
+{
+	/* Format of mac5380 parameter is:
+	 *   mac5380=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
+	 * Negative values mean don't change.
+	 */
+	
+	/* Grmbl... the standard parameter parsing can't handle negative numbers
+	 * :-( So let's do it ourselves!
+	 */
+
+	int i = ints[0]+1, fact;
+
+	while( str && (isdigit(*str) || *str == '-') && i <= 10) {
+		if (*str == '-')
+			fact = -1, ++str;
+		else
+			fact = 1;
+		ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
+		if ((str = strchr( str, ',' )) != NULL)
+			++str;
+	}
+	ints[0] = i-1;
+	
+	if (ints[0] < 1) {
+		printk( "mac_scsi_setup: no arguments!\n" );
+		return;
+	}
+
+	if (ints[0] >= 1) {
+		if (ints[1] > 0)
+			/* no limits on this, just > 0 */
+			setup_can_queue = ints[1];
+	}
+	if (ints[0] >= 2) {
+		if (ints[2] > 0)
+			setup_cmd_per_lun = ints[2];
+	}
+	if (ints[0] >= 3) {
+		if (ints[3] >= 0) {
+			setup_sg_tablesize = ints[3];
+			/* Must be <= SG_ALL (255) */
+			if (setup_sg_tablesize > SG_ALL)
+				setup_sg_tablesize = SG_ALL;
+		}
+	}
+	if (ints[0] >= 4) {
+		/* Must be between 0 and 7 */
+		if (ints[4] >= 0 && ints[4] <= 7)
+			setup_hostid = ints[4];
+		else if (ints[4] > 7)
+			printk( "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
+	}
+#ifdef SUPPORT_TAGS
+	if (ints[0] >= 5) {
+		if (ints[5] >= 0)
+			setup_use_tagged_queuing = !!ints[5];
+	}
+#endif
+}
+
+int mac_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+{
+	int		rv;
+	struct NCR5380_hostdata *hostdata =
+		(struct NCR5380_hostdata *)cmd->host->hostdata;
+
+	/* For doing the reset, SCSI interrupts must be disabled first,
+	 * since the 5380 raises its IRQ line while _RST is active and we
+	 * can't disable interrupts completely, since we need the timer.
+	 */
+	/* And abort a maybe active DMA transfer */
+       	mac_turnoff_irq( IRQ_MAC_SCSI );
+#ifdef REAL_DMA
+       	mac_scsi_dma.dma_ctrl = 0;
+#endif /* REAL_DMA */
+#ifdef PSEUDO_DMA
+	mac_pdma_active = 0;
+#endif
+
+	rv = NCR5380_reset(cmd, reset_flags);
+
+	/* Re-enable ints */
+       	mac_turnon_irq( IRQ_MAC_SCSI );
+
+	return( rv );
+}
+
+	
+static void mac_scsi_reset_boot( void )
+{
+	unsigned long end;
+	
+	/*
+	 * Do a SCSI reset to clean up the bus during initialization. No messing
+	 * with the queues, interrupts, or locks necessary here.
+	 */
+
+	printk( "Macintosh SCSI: resetting the SCSI bus..." );
+
+	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
+       	mac_turnoff_irq( IRQ_MAC_SCSI );
+
+	/* get in phase */
+	NCR5380_write( TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+
+	/* assert RST */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+	/* The min. reset hold time is 25us, so 40us should be enough */
+	udelay( 50 );
+	/* reset RST and interrupt */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+	for( end = jiffies + AFTER_RESET_DELAY; jiffies < end; )
+		barrier();
+
+	/* switch on SCSI IRQ again */
+       	mac_turnon_irq( IRQ_MAC_SCSI );
+
+	printk( " done\n" );
+}
+
+
+const char * mac_scsi_info (struct Scsi_Host *host)
+{
+	/* mac_scsi_detect() is verbose enough... */
+	static const char string[] = "Macintosh NCR5380 SCSI";
+	return string;
+}
+
+
+#if defined(REAL_DMA)
+
+unsigned long mac_scsi_dma_setup( struct Scsi_Host *instance, void *data,
+				   unsigned long count, int dir )
+{
+	unsigned long addr = VTOP( data );
+
+	DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, "
+		   "dir = %d\n", instance->host_no, data, addr, count, dir);
+
+	if (!STRAM_ADDR(addr)) {
+		/* If we have a non-DMAable address on a Falcon, use the dribble
+		 * buffer; 'orig_addr' != 0 in the read case tells the interrupt
+		 * handler to copy data from the dribble buffer to the originally
+		 * wanted address.
+		 */
+		if (dir)
+			memcpy( mac_dma_buffer, data, count );
+		else
+			mac_dma_orig_addr = data;
+		addr = mac_dma_phys_buffer;
+	}
+	
+	mac_dma_startaddr = addr;	/* Needed for calculating residual later. */
+  
+	/* Cache cleanup stuff: On writes, push any dirty cache out before sending
+	 * it to the peripheral. (Must be done before DMA setup, since at least
+	 * the ST-DMA begins to fill internal buffers right after setup. For
+	 * reads, invalidate any cache, may be altered after DMA without CPU
+	 * knowledge.
+	 * 
+	 * ++roman: For the Medusa, there's no need at all for that cache stuff,
+	 * because the hardware does bus snooping (fine!).
+	 */
+	dma_cache_maintenance( addr, count, dir );
+
+	if (count == 0)
+		printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n");
+
+	mac_scsi_dma.dma_ctrl = dir;
+	SCSI_DMA_WRITE_P( dma_addr, addr );
+	SCSI_DMA_WRITE_P( dma_cnt, count );
+	mac_scsi_dma.dma_ctrl = dir | 2;
+
+	return( count );
+}
+
+
+static long mac_scsi_dma_residual( struct Scsi_Host *instance )
+{
+	return( mac_dma_residual );
+}
+
+
+#define	CMD_SURELY_BLOCK_MODE	0
+#define	CMD_SURELY_BYTE_MODE	1
+#define	CMD_MODE_UNKNOWN		2
+
+static int mac_classify_cmd( Scsi_Cmnd *cmd )
+{
+	unsigned char opcode = cmd->cmnd[0];
+	
+	if (opcode == READ_DEFECT_DATA || opcode == READ_LONG ||
+		opcode == READ_BUFFER)
+		return( CMD_SURELY_BYTE_MODE );
+	else if (opcode == READ_6 || opcode == READ_10 ||
+		 opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE ||
+		 opcode == RECOVER_BUFFERED_DATA) {
+		/* In case of a sequential-access target (tape), special care is
+		 * needed here: The transfer is block-mode only if the 'fixed' bit is
+		 * set! */
+		if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1))
+			return( CMD_SURELY_BYTE_MODE );
+		else
+			return( CMD_SURELY_BLOCK_MODE );
+	}
+	else
+		return( CMD_MODE_UNKNOWN );
+}
+
+#endif	/* REAL_DMA */
+
+#if defined(REAL_DMA) || defined(PSEUDO_DMA)
+/* This function calculates the number of bytes that can be transferred via
+ * DMA. On the TT, this is arbitrary, but on the Falcon we have to use the
+ * ST-DMA chip. There are only multiples of 512 bytes possible and max.
+ * 255*512 bytes :-( This means also, that defining READ_OVERRUNS is not
+ * possible on the Falcon, since that would require to program the DMA for
+ * n*512 - atari_read_overrun bytes. But it seems that the Falcon doesn't have
+ * the overrun problem, so this question is academic :-)
+ */
+
+static unsigned long mac_dma_xfer_len( unsigned long wanted_len,
+					Scsi_Cmnd *cmd,
+					int write_flag )
+{
+	unsigned long	possible_len, limit;
+
+#if defined(REAL_DMA)
+	if (IS_A_TT())
+		/* TT SCSI DMA can transfer arbitrary #bytes */
+		return( wanted_len );
+
+	/* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
+	 * 255*512 bytes, but this should be enough)
+	 *
+	 * ++roman: Aaargl! Another Falcon-SCSI problem... There are some commands
+	 * that return a number of bytes which cannot be known beforehand. In this
+	 * case, the given transfer length is an "allocation length". Now it
+	 * can happen that this allocation length is a multiple of 512 bytes and
+	 * the DMA is used. But if not n*512 bytes really arrive, some input data
+	 * will be lost in the ST-DMA's FIFO :-( Thus, we have to distinguish
+	 * between commands that do block transfers and those that do byte
+	 * transfers. But this isn't easy... there are lots of vendor specific
+	 * commands, and the user can issue any command via the
+	 * SCSI_IOCTL_SEND_COMMAND.
+	 *
+	 * The solution: We classify SCSI commands in 1) surely block-mode cmd.s,
+	 * 2) surely byte-mode cmd.s and 3) cmd.s with unknown mode. In case 1)
+	 * and 3), the thing to do is obvious: allow any number of blocks via DMA
+	 * or none. In case 2), we apply some heuristic: Byte mode is assumed if
+	 * the transfer (allocation) length is < 1024, hoping that no cmd. not
+	 * explicitly known as byte mode have such big allocation lengths...
+	 * BTW, all the discussion above applies only to reads. DMA writes are
+	 * unproblematic anyways, since the targets aborts the transfer after
+	 * receiving a sufficient number of bytes.
+	 *
+	 * Another point: If the transfer is from/to an non-ST-RAM address, we
+	 * use the dribble buffer and thus can do only STRAM_BUFFER_SIZE bytes.
+	 */
+
+	if (write_flag) {
+		/* Write operation can always use the DMA, but the transfer size must
+		 * be rounded up to the next multiple of 512 (atari_dma_setup() does
+		 * this).
+		 */
+		possible_len = wanted_len;
+	}
+	else {
+		/* Read operations: if the wanted transfer length is not a multiple of
+		 * 512, we cannot use DMA, since the ST-DMA cannot split transfers
+		 * (no interrupt on DMA finished!)
+		 */
+		if (wanted_len & 0x1ff)
+			possible_len = 0;
+		else {
+			/* Now classify the command (see above) and decide whether it is
+			 * allowed to do DMA at all */
+			switch( falcon_classify_cmd( cmd )) {
+			  case CMD_SURELY_BLOCK_MODE:
+				possible_len = wanted_len;
+				break;
+			  case CMD_SURELY_BYTE_MODE:
+				possible_len = 0; /* DMA prohibited */
+				break;
+			  case CMD_MODE_UNKNOWN:
+			  default:
+				/* For unknown commands assume block transfers if the transfer
+				 * size/allocation length is >= 1024 */
+				possible_len = (wanted_len < 1024) ? 0 : wanted_len;
+				break;
+			}
+		}
+	}
+
+	/* Last step: apply the hard limit on DMA transfers */
+	limit = (atari_dma_buffer && !STRAM_ADDR( VTOP(cmd->SCp.ptr) )) ?
+		    STRAM_BUFFER_SIZE : 255*512;
+	if (possible_len > limit)
+		possible_len = limit;
+
+	if (possible_len != wanted_len)
+		DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes "
+			   "instead of %ld\n", possible_len, wanted_len);
+
+#else /* REAL_DMA */
+	possible_len = wanted_len;
+#endif
+	
+	return( possible_len );
+}
+#endif	/* REAL_DMA || PSEUDO_DMA */
+
+
+/* 
+ * FIXME !!!
+ */
+
+/* NCR5380 register access functions
+ */
+
+static unsigned char mac_scsi_reg_read( unsigned char reg )
+{
+	return( mac_scsi_regp[reg << 4] );
+}
+
+static void mac_scsi_reg_write( unsigned char reg, unsigned char value )
+{
+	mac_scsi_regp[reg << 4] = value;
+}
+
+#include "mac_NCR5380.c"
+
+#ifdef PSEUDO_DMA
+
+/*
+ * slightly optimized PIO transfer routines, experimental!
+ * command may time out if interrupts are left enabled
+ */
+
+static inline int mac_pdma_read (struct Scsi_Host *instance, unsigned char *dst,    int len)
+{
+    register unsigned char *d = dst;
+    register i = len;
+    register unsigned char p, tmp;
+
+#if (NDEBUG & NDEBUG_PSEUDO_DMA)
+    printk("pdma_read: reading %d bytes to %p\n", len, dst);
+#endif
+
+    mac_pdma_residual = len;
+    if (mac_pdma_active) {
+      printk("pseudo-DMA already active in pread!\n");
+      return -1;
+    }
+    mac_pdma_active = 1;
+    mac_pdma_startaddr = (unsigned long) dst;
+    mac_pdma_current   = (unsigned long) dst;
+
+    /* 
+     * Get the phase from the bus (sanity check) 
+     * Hopefully, the phase bits are valid here ...
+     */
+    p = NCR5380_read(STATUS_REG) & PHASE_MASK;
+    if (!(p & SR_IO)) {
+      PDMA_PRINTK("NCR5380_pread: initial phase mismatch!\n");
+      NCR_PRINT_PHASE(NDEBUG_ANY);
+      return -1;
+    }
+
+    /* 
+     * The NCR5380 chip will only drive the SCSI bus when the 
+     * phase specified in the appropriate bits of the TARGET COMMAND
+     * REGISTER match the STATUS REGISTER
+     */
+
+#if 0	/* done in transfer_dma */
+    p = PHASE_DATAIN;
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+#endif
+
+    for (; i; --i) {
+	HSH_PRINTK(" read %d ..", i);
+        /* check if we were interrupted ... */
+        if (!mac_pdma_active) {
+	  printk("pwrite: interrupt detected!\n");
+	  break;
+        }
+
+	/* 
+	 * Wait for assertion of REQ, after which the phase bits will be 
+	 * valid 
+	 */
+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
+		barrier();
+
+	HSH_PRINTK(" REQ ..");
+
+	/* Check for phase mismatch */	
+	if ((tmp & PHASE_MASK) != p) {
+            if (!mac_pdma_active) 
+	    	printk("scsi%d : phase mismatch after interrupt\n", instance->host_no);
+	    else
+	    	printk("scsi%d : phase mismatch w/o interrupt\n", instance->host_no);
+	    NCR_PRINT_PHASE(NDEBUG_ANY);
+	    break;
+	}
+
+	/* Do actual transfer from SCSI bus to memory */
+	*d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+	d++;
+	
+	/* Handshake ... */
+
+	/* Assert ACK */
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+	HSH_PRINTK(" ACK ..");
+
+	/* Wait for REQ to be dropped */
+	while (NCR5380_read(STATUS_REG) & SR_REQ)
+		barrier();
+	HSH_PRINTK(" /REQ ..");
+
+	/* Drop ACK */
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	HSH_PRINTK(" /ACK !\n");
+
+	mac_pdma_current = (unsigned long) d;
+	mac_pdma_residual--;
+    }
+
+#if (NDEBUG & NDEBUG_PSEUDO_DMA)
+    printk("pdma_read: read at %d bytes to %p\n", i, dst);
+#endif
+
+    if (mac_pdma_residual)
+      printk("pread: leaving with residual %ld of %ld\n", 
+      		mac_pdma_residual, len);
+    mac_pdma_active = 0;
+
+    /* ?? */
+#if 0
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+#endif
+    return 0;
+}
+		
+static inline int mac_pdma_write (struct Scsi_Host *instance, unsigned char *src,    int len)
+{
+    register unsigned char *s = src;
+    register i = len;
+    register unsigned char p, tmp;
+
+#if (NDEBUG & NDEBUG_PSEUDO_DMA)
+    printk("pdma_write: writing %d bytes from %p\n", len, src);
+#endif
+
+    mac_pdma_residual = len;
+    if (mac_pdma_active) {
+      printk("pseudo-DMA already active in pwrite!\n");
+      return -1;
+    }
+    mac_pdma_active = 1;
+    mac_pdma_startaddr = (unsigned long) src;
+    mac_pdma_current   = (unsigned long) src;
+
+    /* 
+     * Get the phase from the bus (sanity check) 
+     */
+    p = NCR5380_read(STATUS_REG) & PHASE_MASK;
+    if (p & SR_IO) {
+      printk("NCR5380_pwrite: initial phase mismatch!\n");
+      NCR_PRINT_PHASE(NDEBUG_ANY);
+      return -1;
+    }
+
+    /* 
+     * The NCR5380 chip will only drive the SCSI bus when the 
+     * phase specified in the appropriate bits of the TARGET COMMAND
+     * REGISTER match the STATUS REGISTER
+     */
+
+#if 0	/* already done in transfer_dma */ 
+    p = PHASE_DATAOUT;
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+#endif
+
+    for (; i; --i) {
+        /* check if we were interrupted ... */
+        if (!mac_pdma_active) {
+	  printk("pwrite: interrupt detected!\n");
+	  break;
+        }
+
+       	/* 
+	 * Wait for assertion of REQ, after which the phase bits will be 
+	 * valid 
+	 */
+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+	/* Check for phase mismatch */	
+	if ((tmp & PHASE_MASK) != p) {
+            if (!mac_pdma_active) 
+	    	printk("scsi%d : phase mismatch after interrupt\n", instance->host_no);
+	    else
+	    	printk("scsi%d : phase mismatch w/o interrupt\n", instance->host_no);
+	    NCR_PRINT_PHASE(NDEBUG_ANY);
+	    /* should we signal an error here?? */
+	    break;
+	}
+
+	/* Do actual transfer to SCSI bus from memory */
+
+	NCR5380_write(OUTPUT_DATA_REG, *s);
+
+	s++;
+	
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+		      ICR_ASSERT_DATA);
+
+	/* Handshake ... assert ACK */
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		      ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+
+	/* ... wait for REQ to be dropped */
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+	/* and drop ACK (and DATA) ! */
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+	mac_pdma_current = (unsigned long) s;
+	mac_pdma_residual--;
+    }
+
+#if (NDEBUG & NDEBUG_PSEUDO_DMA)
+    printk("pdma_write: write at %d bytes from %p\n", i, src);
+#endif
+
+    if (mac_pdma_residual)
+      printk("pwrite: leaving with residual %ld of len %ld \n", 
+      		mac_pdma_residual, len);
+    mac_pdma_active = 0;
+
+    return 0;
+
+}
+#endif /* PSEUDO_DMA */
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = MAC_SCSI;
+
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/mac_scsi.h linux/drivers/scsi/mac_scsi.h
--- v2.1.112/linux/drivers/scsi/mac_scsi.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/mac_scsi.h	Thu Jul 30 11:17:10 1998
@@ -0,0 +1,286 @@
+/*
+ * mac_scsi.h -- Header file for the Macintosh native SCSI driver
+ *
+ * based on Roman Hodeks atari_scsi.h
+ */
+
+/*
+ * atari_scsi.h -- Header file for the Atari native SCSI driver
+ *
+ * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * (Loosely based on the work of Robert De Vries' team)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+#ifndef MAC_SCSI_H
+#define MAC_SCSI_H
+
+/* (I_HAVE_OVERRUNS stuff removed) */
+
+#ifndef ASM
+int mac_scsi_abort (Scsi_Cmnd *);
+int mac_scsi_detect (Scsi_Host_Template *);
+const char * mac_scsi_info (struct Scsi_Host *host);
+int mac_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+int mac_scsi_reset (Scsi_Cmnd *, unsigned int);
+int mac_scsi_proc_info (char *, char **, off_t, int, int, int);
+#ifdef MODULE
+int mac_scsi_release (struct Scsi_Host *);
+#else
+#define mac_scsi_release NULL
+#endif
+
+/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
+ * values should work, too; try it! (but cmd_per_lun costs memory!) */
+
+/* But there seems to be a bug somewhere that requires CAN_QUEUE to be
+ * 2*CMD_PER_LUN. At least on a TT, no spurious timeouts seen since
+ * changed CMD_PER_LUN... */
+
+/* Note: The Falcon currently uses 8/1 setting due to unsolved problems with
+ * cmd_per_lun != 1 */
+
+#define MAC_SCSI_CAN_QUEUE		        16
+#define MAC_SCSI_CMD_PER_LUN		        8
+#define MAC_SCSI_SG_TABLESIZE		SG_ALL
+
+#define	DEFAULT_USE_TAGGED_QUEUING	0
+
+
+#if defined (HOSTS_C) || defined (MODULE)
+
+#define MAC_SCSI { NULL, NULL, NULL,				\
+  mac_scsi_proc_info,						\
+  "Macintosh NCR5380 SCSI",					\
+  mac_scsi_detect,						\
+  mac_scsi_release,						\
+  mac_scsi_info,						\
+  /* command */ NULL,						\
+  mac_scsi_queue_command,					\
+  mac_scsi_abort,						\
+  mac_scsi_reset,						\
+  /* slave_attach */	NULL,					\
+  /* bios_param */	NULL,					\
+  /* can queue */	0, /* initialized at run-time */	\
+  /* host_id */		0, /* initialized at run-time */	\
+  /* scatter gather */	0, /* initialized at run-time */	\
+  /* cmd per lun */	0, /* initialized at run-time */	\
+  /* present */		0,					\
+  /* unchecked ISA DMA */ 0,					\
+  /* use_clustering */	DISABLE_CLUSTERING }
+
+#endif
+
+#ifndef HOSTS_C
+
+#define	NCR5380_implementation_fields	/* none */
+
+#define NCR5380_read(reg)		  mac_scsi_reg_read( reg )
+#define NCR5380_write(reg, value) mac_scsi_reg_write( reg, value )
+
+#define NCR5380_intr mac_scsi_intr
+#define NCR5380_queue_command mac_scsi_queue_command
+#define NCR5380_abort mac_scsi_abort
+#define NCR5380_proc_info mac_scsi_proc_info
+#define NCR5380_dma_read_setup(inst,d,c) mac_scsi_dma_setup (inst, d, c, 0)
+#define NCR5380_dma_write_setup(inst,d,c) mac_scsi_dma_setup (inst, d, c, 1)
+#define NCR5380_dma_residual(inst) mac_scsi_dma_residual( inst )
+#define	NCR5380_dma_xfer_len(i,cmd,phase) \
+	mac_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+#ifdef PSEUDO_DMA
+#define NCR5380_pread(inst,d,l) mac_pdma_read (inst, d, l)
+#define NCR5380_pwrite(inst,d,l) mac_pdma_write (inst, d, l)
+#endif
+
+/* Debugging printk definitions:
+ *
+ *  ARB  -> arbitration
+ *  ASEN -> auto-sense
+ *  DMA  -> DMA
+ *  HSH  -> PIO handshake
+ *  INF  -> information transfer
+ *  INI  -> initialization
+ *  INT  -> interrupt
+ *  LNK  -> linked commands
+ *  MAIN -> NCR5380_main() control flow
+ *  NDAT -> no data-out phase
+ *  NWR  -> no write commands
+ *  PIO  -> PIO transfers
+ *  PDMA -> pseudo DMA (unused on MAC)
+ *  QU   -> queues
+ *  RSL  -> reselections
+ *  SEL  -> selections
+ *  USL  -> usleep cpde (unused on MAC)
+ *  LBS  -> last byte sent (unused on MAC)
+ *  RSS  -> restarting of selections
+ *  EXT  -> extended messages
+ *  ABRT -> aborting and resetting
+ *  TAG  -> queue tag handling
+ *  MER  -> merging of consec. buffers
+ *
+ */
+
+#if NDEBUG & NDEBUG_ARBITRATION
+#define ARB_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ARB_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_AUTOSENSE
+#define ASEN_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ASEN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_DMA
+#define DMA_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define DMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_HANDSHAKE
+#define HSH_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define HSH_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INFORMATION
+#define INF_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INF_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INIT
+#define INI_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INI_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INTR
+#define INT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LINKED
+#define LNK_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define LNK_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MAIN
+#define MAIN_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define MAIN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_DATAOUT
+#define NDAT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define NDAT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_WRITE
+#define NWR_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define NWR_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PIO
+#define PIO_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define PIO_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PSEUDO_DMA
+#define PDMA_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define PDMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_QUEUES
+#define QU_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define QU_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESELECTION
+#define RSL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define RSL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_SELECTION
+#define SEL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define SEL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_USLEEP
+#define USL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define USL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+#define LBS_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define LBS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESTART_SELECT
+#define RSS_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define RSS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_EXTENDED
+#define EXT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define EXT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_ABORT
+#define ABRT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ABRT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_TAGS
+#define TAG_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define TAG_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MERGING
+#define MER_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define MER_PRINTK(format, args...)
+#endif
+
+/* conditional macros for NCR5380_print_{,phase,status} */
+
+#define NCR_PRINT(mask)	\
+	((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0)
+
+#define NCR_PRINT_PHASE(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0)
+
+#define NCR_PRINT_STATUS(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0)
+
+#define NDEBUG_ANY	0xffffffff
+
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* MAC_SCSI_H */
+
+
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/mvme16x.c linux/drivers/scsi/mvme16x.c
--- v2.1.112/linux/drivers/scsi/mvme16x.c	Wed Apr  8 19:36:27 1998
+++ linux/drivers/scsi/mvme16x.c	Thu Jul 30 11:17:11 1998
@@ -8,7 +8,6 @@
 #include <linux/blk.h>
 #include <linux/sched.h>
 #include <linux/version.h>
-#include <linux/zorro.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -38,6 +37,8 @@
     int clock;
     long long options;
 
+    if (!MACH_IS_MVME16x)
+		return 0;
     if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
 	printk ("SCSI detection disabled, SCSI chip not present\n");
 	return 0;
@@ -52,7 +53,7 @@
     clock = 66000000;	/* 66MHz SCSI Clock */
 
     ncr53c7xx_init(tpnt, 0, 710, (u32)0xfff47000,
-			0, 0x55, DMA_NONE,
+			0, MVME16x_IRQ_SCSI, DMA_NONE,
 			options, clock);
     called = 1;
     return 1;
diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/mvme16x.h linux/drivers/scsi/mvme16x.h
--- v2.1.112/linux/drivers/scsi/mvme16x.h	Thu Mar 26 15:57:03 1998
+++ linux/drivers/scsi/mvme16x.h	Thu Jul 30 11:17:11 1998
@@ -7,7 +7,7 @@
 const char *NCR53c7x0_info(void);
 int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int NCR53c7xx_abort(Scsi_Cmnd *);
-int NCR53c7x0_release (Scsi_Host_Template *);
+int NCR53c7x0_release (struct Scsi_Host *);
 int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
 void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
 
@@ -28,26 +28,16 @@
 
 extern struct proc_dir_entry proc_scsi_mvme16x;
 
-#define MVME16x_SCSI {/* next */                NULL,            \
-		      /* usage_count */         NULL,	         \
-		      /* proc_dir_entry */      NULL, \
-		      /* proc_info */           NULL,            \
-		      /* name */                "MVME16x SCSI", \
-		      /* detect */              mvme16x_scsi_detect,    \
-		      /* release */             NULL,   \
-		      /* info */                NULL,	         \
-		      /* command */             NULL,            \
-		      /* queuecommand */        NCR53c7xx_queue_command, \
-		      /* abort */               NCR53c7xx_abort,   \
-		      /* reset */               NCR53c7xx_reset,   \
-		      /* slave_attach */        NULL,            \
-		      /* bios_param */          NULL /*scsicam_bios_param*/, \
-		      /* can_queue */           24,       \
-		      /* this_id */             7,               \
-		      /* sg_tablesize */        127,          \
-		      /* cmd_per_lun */	        3,     \
-		      /* present */             0,               \
-		      /* unchecked_isa_dma */   0,               \
-		      /* use_clustering */      DISABLE_CLUSTERING }
+#define MVME16x_SCSI  {name:                "MVME16x NCR53c710 SCSI", \
+		       detect:              mvme16x_scsi_detect,    \
+		       queuecommand:        NCR53c7xx_queue_command, \
+		       abort:               NCR53c7xx_abort,   \
+		       reset:               NCR53c7xx_reset,   \
+		       bios_param:          scsicam_bios_param,   \
+		       can_queue:           24,       \
+		       this_id:             7,               \
+		       sg_tablesize:        63,          \
+		       cmd_per_lun:	    3,     \
+		       use_clustering:      DISABLE_CLUSTERING }
 #endif
 #endif /* MVME16x_SCSI_H */
diff -u --recursive --new-file v2.1.112/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.1.112/linux/drivers/sound/Makefile	Tue Jul 21 00:15:31 1998
+++ linux/drivers/sound/Makefile	Thu Jul 30 11:17:12 1998
@@ -42,7 +42,7 @@
 
 ifeq ($(ARCH),m68k)
 
-obj-$(CONFIG_DMASOUND)		+= dmasound.o
+obj-$(CONFIG_DMASOUND)		+= dmasound.o sound_core.o
 
 else
 
diff -u --recursive --new-file v2.1.112/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.1.112/linux/drivers/sound/dmasound.c	Tue Jun 23 10:01:24 1998
+++ linux/drivers/sound/dmasound.c	Thu Jul 30 11:17:12 1998
@@ -73,6 +73,8 @@
 
 1996/9/25	++geert: modularization
 
+1998-06-10	++andreas: converted to use sound_core
+
 */
 
 
@@ -85,6 +87,8 @@
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/sound.h>
+#include <linux/init.h>
 
 #ifdef __mc68000__
 #include <asm/setup.h>
@@ -122,7 +126,9 @@
 #define HAS_8BIT_TABLES
 
 #ifdef MODULE
-static int chrdev_registered = 0;
+static int sq_unit = -1;
+static int mixer_unit = -1;
+static int state_unit = -1;
 static int irq_installed = 0;
 #endif /* MODULE */
 static char **sound_buffers = NULL;
@@ -258,7 +264,9 @@
 #define MAX_BUFSIZE		128	/* Limit for Amiga */
 
 static int catchRadius = 0, numBufs = 4, bufSize = 32;
-
+MODULE_PARM(catchRadius, "i");
+MODULE_PARM(numBufs, "i");
+MODULE_PARM(bufSize, "i");
 
 #define arraysize(x)	(sizeof(x)/sizeof(*(x)))
 #define min(x, y)	((x) < (y) ? (x) : (y))
@@ -510,74 +518,105 @@
 
 
 #ifdef CONFIG_ATARI
-static long ata_ct_law(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ct_s8(const u_char *userPtr, unsigned long userCount,
-		      u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ct_u8(const u_char *userPtr, unsigned long userCount,
-		      u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ctx_law(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount,
-			  u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount,
-			  u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount,
-			  u_char frame[], long *frameUsed, long frameLeft);
-static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount,
-			  u_char frame[], long *frameUsed, long frameLeft);
+static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft);
+static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft);
+static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft);
+static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft);
+static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft);
+static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft);
 #endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
-static long ami_ct_law(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft);
-static long ami_ct_s8(const u_char *userPtr, unsigned long userCount,
-		      u_char frame[], long *frameUsed, long frameLeft);
-static long ami_ct_u8(const u_char *userPtr, unsigned long userCount,
-		      u_char frame[], long *frameUsed, long frameLeft);
-static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
+static ssize_t ami_ct_law(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft);
+static ssize_t ami_ct_u8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft);
+static ssize_t ami_ct_s16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ami_ct_u16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ami_ct_s16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
 #endif /* CONFIG_AMIGA */
 
 #ifdef CONFIG_PMAC
-static long pmac_ct_law(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ct_s8(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ct_u8(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ct_s16(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ct_u16(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ctx_law(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ctx_s8(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ctx_u8(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ctx_s16(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
-static long pmac_ctx_u16(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft);
+static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft);
+static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
+static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft);
 #endif /* CONFIG_PMAC */
 
 /*** Machine definitions *****************************************************/
@@ -613,14 +652,14 @@
 } SETTINGS;
 
 typedef struct {
-	long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long);
-	long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long);
-	long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long);
-	long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long);
-	long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long);
-	long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long);
-	long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long);
-	long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long);
+	ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
 } TRANS;
 
 struct sound_settings {
@@ -645,9 +684,9 @@
 
 
 #ifdef CONFIG_ATARI
-static void *AtaAlloc(unsigned int size, int flags);
-static void AtaFree(void *, unsigned int size);
-static int AtaIrqInit(void);
+static void *AtaAlloc(unsigned int size, int flags) __init;
+static void AtaFree(void *, unsigned int size) __init;
+static int AtaIrqInit(void) __init;
 #ifdef MODULE
 static void AtaIrqCleanUp(void);
 #endif /* MODULE */
@@ -668,9 +707,9 @@
 #endif /* CONFIG_ATARI */
 
 #ifdef CONFIG_AMIGA
-static void *AmiAlloc(unsigned int size, int flags);
-static void AmiFree(void *, unsigned int);
-static int AmiIrqInit(void);
+static void *AmiAlloc(unsigned int size, int flags) __init;
+static void AmiFree(void *, unsigned int) __init;
+static int AmiIrqInit(void) __init;
 #ifdef MODULE
 static void AmiIrqCleanUp(void);
 #endif /* MODULE */
@@ -685,9 +724,9 @@
 #endif /* CONFIG_AMIGA */
 
 #ifdef CONFIG_PMAC
-static void *PMacAlloc(unsigned int size, int flags);
-static void PMacFree(void *ptr, unsigned int size);
-static int PMacIrqInit(void);
+static void *PMacAlloc(unsigned int size, int flags) __init;
+static void PMacFree(void *ptr, unsigned int size) __init;
+static int PMacIrqInit(void) __init;
 #ifdef MODULE
 static void PMacIrqCleanup(void);
 #endif /* MODULE */
@@ -720,10 +759,10 @@
 #if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
 static int sound_set_treble(int treble);
 #endif /* CONFIG_ATARI || CONFIG_AMIGA */
-static long sound_copy_translate(const u_char *userPtr,
-				 unsigned long userCount,
-				 u_char frame[], long *frameUsed,
-				 long frameLeft);
+static ssize_t sound_copy_translate(const u_char *userPtr,
+				    size_t userCount,
+				    u_char frame[], ssize_t *frameUsed,
+				    ssize_t frameLeft);
 
 
 /*
@@ -736,13 +775,6 @@
 
 static struct sound_mixer mixer;
 
-static void mixer_init(void);
-static int mixer_open(int open_mode);
-static int mixer_release(void);
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg);
-
-
 /*
  * Sound queue stuff, the heart of the driver
  */
@@ -787,16 +819,6 @@
 	interruptible_sleep_on(&queue);
 #define WAKE_UP(queue)	(wake_up_interruptible(&queue))
 
-static void sq_init(int numBufs, int bufSize, char **buffers);
-static void sq_play(void);
-static long sq_write(const char *src, unsigned long uLeft);
-static int sq_open(int open_mode);
-static void sq_reset(void);
-static int sq_sync(void);
-static int sq_release(void);
-static void init_settings(void);
-
-
 /*
  * /dev/sndstat
  */
@@ -809,23 +831,9 @@
 
 static struct sound_state state;
 
-static void state_init(void);
-static int state_open(int open_mode);
-static int state_release(void);
-static long state_read(char *dest, unsigned long count);
-
-
-/*** High level stuff ********************************************************/
+/*** Common stuff ********************************************************/
 
-
-static int sound_open(struct inode *inode, struct file *file);
-static int sound_fsync(struct file *filp, struct dentry *dentry);
-static int sound_release(struct inode *inode, struct file *file);
 static long long sound_lseek(struct file *file, long long offset, int orig);
-static ssize_t sound_read(struct file *file, char *buf, size_t count,
-			  loff_t *ppos);
-static ssize_t sound_write(struct file *file, const char *buf, size_t count,
-			   loff_t *ppos);
 static inline int ioctl_return(int *addr, int value)
 {
 	if (value < 0)
@@ -833,17 +841,13 @@
 
 	return put_user(value, addr)? -EFAULT: 0;
 }
-static int unknown_minor_dev(char *fname, int dev);
-static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg);
 
 
 /*** Config & Setup **********************************************************/
 
 
-void soundcard_init(void);
+void dmasound_init(void);
 void dmasound_setup(char *str, int *ints);
-void sound_setup(char *str, int *ints);		/* ++Martin: stub for now */
 
 
 /*** Translations ************************************************************/
@@ -874,11 +878,12 @@
  */
 
 #ifdef CONFIG_ATARI
-static long ata_ct_law(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
 {
 	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-	long count, used;
+	ssize_t count, used;
 	u_char *p = &frame[*frameUsed];
 
 	count = min(userCount, frameLeft);
@@ -893,14 +898,15 @@
 		count--;
 	}
 	*frameUsed += used;
-	return(used);
+	return used;
 }
 
 
-static long ata_ct_s8(const u_char *userPtr, unsigned long userCount,
-		      u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft)
 {
-	long count, used;
+	ssize_t count, used;
 	void *p = &frame[*frameUsed];
 
 	count = min(userCount, frameLeft);
@@ -914,10 +920,11 @@
 }
 
 
-static long ata_ct_u8(const u_char *userPtr, unsigned long userCount,
-		      u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed,
+			 ssize_t frameLeft)
 {
-	long count, used;
+	ssize_t count, used;
 
 	if (!sound.soft.stereo) {
 		u_char *p = &frame[*frameUsed];
@@ -947,17 +954,18 @@
 }
 
 
-static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
-	long count, used;
-	u_long data;
+	ssize_t count, used;
 
 	if (!sound.soft.stereo) {
 		u_short *p = (u_short *)&frame[*frameUsed];
 		count = min(userCount, frameLeft)>>1;
 		used = count*2;
 		while (count > 0) {
+			u_short data;
 			if (get_user(data, ((u_short *)userPtr)++))
 				return -EFAULT;
 			*p++ = data;
@@ -977,17 +985,18 @@
 }
 
 
-static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
-	long count, used;
-	u_long data;
+	ssize_t count, used;
 
 	if (!sound.soft.stereo) {
 		u_short *p = (u_short *)&frame[*frameUsed];
 		count = min(userCount, frameLeft)>>1;
 		used = count*2;
 		while (count > 0) {
+			u_short data;
 			if (get_user(data, ((u_short *)userPtr)++))
 				return -EFAULT;
 			data ^= 0x8000;
@@ -1001,6 +1010,7 @@
 		count = min(userCount, frameLeft)>>2;
 		used = count*4;
 		while (count > 0) {
+			u_long data;
 			if (get_user(data, ((u_int *)userPtr)++))
 				return -EFAULT;
 			*p++ = data ^ 0x80008000;
@@ -1012,11 +1022,11 @@
 }
 
 
-static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
-	long count, used;
-	u_long data;
+	ssize_t count, used;
 
 	count = frameLeft;
 	if (!sound.soft.stereo) {
@@ -1024,6 +1034,7 @@
 		count = min(userCount, frameLeft)>>1;
 		used = count*2;
 		while (count > 0) {
+			u_short data;
 			if (get_user(data, ((u_short *)userPtr)++))
 				return -EFAULT;
 			data = le2be16(data);
@@ -1037,6 +1048,7 @@
 		count = min(userCount, frameLeft)>>2;
 		used = count*4;
 		while (count > 0) {
+			u_long data;
 			if (get_user(data, ((u_int *)userPtr)++))
 				return -EFAULT;
 			data = le2be16dbl(data);
@@ -1049,11 +1061,11 @@
 }
 
 
-static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
-	long count, used;
-	u_long data;
+	ssize_t count, used;
 
 	count = frameLeft;
 	if (!sound.soft.stereo) {
@@ -1061,6 +1073,7 @@
 		count = min(userCount, frameLeft)>>1;
 		used = count*2;
 		while (count > 0) {
+			u_short data;
 			if (get_user(data, ((u_short *)userPtr)++))
 				return -EFAULT;
 			data = le2be16(data) ^ 0x8000;
@@ -1073,6 +1086,7 @@
 		count = min(userCount, frameLeft)>>2;
 		used = count;
 		while (count > 0) {
+			u_long data;
 			if (get_user(data, ((u_int *)userPtr)++))
 				return -EFAULT;
 			data = le2be16dbl(data) ^ 0x80008000;
@@ -1085,20 +1099,21 @@
 }
 
 
-static long ata_ctx_law(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
 {
 	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
 	/* this should help gcc to stuff everything into registers */
-	u_long data = sound.data;
 	long bal = sound.bal;
 	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long used, usedf;
+	ssize_t used, usedf;
 
 	used = userCount;
 	usedf = frameLeft;
 	if (!sound.soft.stereo) {
 		u_char *p = &frame[*frameUsed];
+		u_char data = sound.data;
 		while (frameLeft) {
 			u_char c;
 			if (bal < 0) {
@@ -1114,8 +1129,10 @@
 			frameLeft--;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	} else {
 		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = sound.data;
 		while (frameLeft >= 2) {
 			u_char c;
 			if (bal < 0) {
@@ -1134,28 +1151,29 @@
 			frameLeft -= 2;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	}
 	sound.bal = bal;
-	sound.data = data;
 	used -= userCount;
 	*frameUsed += usedf-frameLeft;
 	return(used);
 }
 
 
-static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
 {
 	/* this should help gcc to stuff everything into registers */
-	u_long data = sound.data;
 	long bal = sound.bal;
 	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long used, usedf;
+	ssize_t used, usedf;
 
 	used = userCount;
 	usedf = frameLeft;
 	if (!sound.soft.stereo) {
 		u_char *p = &frame[*frameUsed];
+		u_char data = sound.data;
 		while (frameLeft) {
 			if (bal < 0) {
 				if (!userCount)
@@ -1169,8 +1187,10 @@
 			frameLeft--;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	} else {
 		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = sound.data;
 		while (frameLeft >= 2) {
 			if (bal < 0) {
 				if (userCount < 2)
@@ -1184,28 +1204,29 @@
 			frameLeft -= 2;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	}
 	sound.bal = bal;
-	sound.data = data;
 	used -= userCount;
 	*frameUsed += usedf-frameLeft;
 	return(used);
 }
 
 
-static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
 {
 	/* this should help gcc to stuff everything into registers */
-	u_long data = sound.data;
 	long bal = sound.bal;
 	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long used, usedf;
+	ssize_t used, usedf;
 
 	used = userCount;
 	usedf = frameLeft;
 	if (!sound.soft.stereo) {
 		u_char *p = &frame[*frameUsed];
+		u_char data = sound.data;
 		while (frameLeft) {
 			if (bal < 0) {
 				if (!userCount)
@@ -1220,8 +1241,10 @@
 			frameLeft--;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	} else {
 		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = sound.data;
 		while (frameLeft >= 2) {
 			if (bal < 0) {
 				if (userCount < 2)
@@ -1236,28 +1259,29 @@
 			frameLeft -= 2;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	}
 	sound.bal = bal;
-	sound.data = data;
 	used -= userCount;
 	*frameUsed += usedf-frameLeft;
 	return(used);
 }
 
 
-static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount,
-			  u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
 {
 	/* this should help gcc to stuff everything into registers */
-	u_long data = sound.data;
 	long bal = sound.bal;
 	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long used, usedf;
+	ssize_t used, usedf;
 
 	used = userCount;
 	usedf = frameLeft;
 	if (!sound.soft.stereo) {
 		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = sound.data;
 		while (frameLeft >= 4) {
 			if (bal < 0) {
 				if (userCount < 2)
@@ -1272,8 +1296,10 @@
 			frameLeft -= 4;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	} else {
 		u_long *p = (u_long *)&frame[*frameUsed];
+		u_long data = sound.data;
 		while (frameLeft >= 4) {
 			if (bal < 0) {
 				if (userCount < 4)
@@ -1287,28 +1313,29 @@
 			frameLeft -= 4;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	}
 	sound.bal = bal;
-	sound.data = data;
 	used -= userCount;
 	*frameUsed += usedf-frameLeft;
 	return(used);
 }
 
 
-static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount,
-			  u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
 {
 	/* this should help gcc to stuff everything into registers */
-	u_long data = sound.data;
 	long bal = sound.bal;
 	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long used, usedf;
+	ssize_t used, usedf;
 
 	used = userCount;
 	usedf = frameLeft;
 	if (!sound.soft.stereo) {
 		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = sound.data;
 		while (frameLeft >= 4) {
 			if (bal < 0) {
 				if (userCount < 2)
@@ -1324,8 +1351,10 @@
 			frameLeft -= 4;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	} else {
 		u_long *p = (u_long *)&frame[*frameUsed];
+		u_long data = sound.data;
 		while (frameLeft >= 4) {
 			if (bal < 0) {
 				if (userCount < 4)
@@ -1340,28 +1369,29 @@
 			frameLeft -= 4;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	}
 	sound.bal = bal;
-	sound.data = data;
 	used -= userCount;
 	*frameUsed += usedf-frameLeft;
 	return(used);
 }
 
 
-static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount,
-			  u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
 {
 	/* this should help gcc to stuff everything into registers */
-	u_long data = sound.data;
 	long bal = sound.bal;
 	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long used, usedf;
+	ssize_t used, usedf;
 
 	used = userCount;
 	usedf = frameLeft;
 	if (!sound.soft.stereo) {
 		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = sound.data;
 		while (frameLeft >= 4) {
 			if (bal < 0) {
 				if (userCount < 2)
@@ -1377,8 +1407,10 @@
 			frameLeft -= 4;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	} else {
 		u_long *p = (u_long *)&frame[*frameUsed];
+		u_long data = sound.data;
 		while (frameLeft >= 4) {
 			if (bal < 0) {
 				if (userCount < 4)
@@ -1393,28 +1425,29 @@
 			frameLeft -= 4;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	}
 	sound.bal = bal;
-	sound.data = data;
 	used -= userCount;
 	*frameUsed += usedf-frameLeft;
 	return(used);
 }
 
 
-static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount,
-			  u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
 {
 	/* this should help gcc to stuff everything into registers */
-	u_long data = sound.data;
 	long bal = sound.bal;
 	long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
-	long used, usedf;
+	ssize_t used, usedf;
 
 	used = userCount;
 	usedf = frameLeft;
 	if (!sound.soft.stereo) {
 		u_short *p = (u_short *)&frame[*frameUsed];
+		u_short data = sound.data;
 		while (frameLeft >= 4) {
 			if (bal < 0) {
 				if (userCount < 2)
@@ -1430,8 +1463,10 @@
 			frameLeft -= 4;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	} else {
 		u_long *p = (u_long *)&frame[*frameUsed];
+		u_long data = sound.data;
 		while (frameLeft >= 4) {
 			if (bal < 0) {
 				if (userCount < 4)
@@ -1446,9 +1481,9 @@
 			frameLeft -= 4;
 			bal -= sSpeed;
 		}
+		sound.data = data;
 	}
 	sound.bal = bal;
-	sound.data = data;
 	used -= userCount;
 	*frameUsed += usedf-frameLeft;
 	return(used);
@@ -1457,11 +1492,12 @@
 
 
 #ifdef CONFIG_AMIGA
-static long ami_ct_law(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ami_ct_law(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
 {
 	char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
-	long count, used;
+	ssize_t count, used;
 
 	if (!sound.soft.stereo) {
 		u_char *p = &frame[*frameUsed];
@@ -1495,10 +1531,10 @@
 }
 
 
-static long ami_ct_s8(const u_char *userPtr, unsigned long userCount,
-		      u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
 {
-	long count, used;
+	ssize_t count, used;
 
 	if (!sound.soft.stereo) {
 		void *p = &frame[*frameUsed];
@@ -1523,10 +1559,10 @@
 }
 
 
-static long ami_ct_u8(const u_char *userPtr, unsigned long userCount,
-		      u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ami_ct_u8(const u_char *userPtr, size_t userCount,
+			 u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
 {
-	long count, used;
+	ssize_t count, used;
 
 	if (!sound.soft.stereo) {
 		char *p = &frame[*frameUsed];
@@ -1560,11 +1596,12 @@
 }
 
 
-static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ami_ct_s16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
-	long count, used;
-	u_long data;
+	ssize_t count, used;
+	u_short data;
 
 	if (!sound.soft.stereo) {
 		u_char *high = &frame[*frameUsed>>1];
@@ -1602,11 +1639,12 @@
 }
 
 
-static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ami_ct_u16be(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
-	long count, used;
-	u_long data;
+	ssize_t count, used;
+	u_short data;
 
 	if (!sound.soft.stereo) {
 		u_char *high = &frame[*frameUsed>>1];
@@ -1647,11 +1685,12 @@
 }
 
 
-static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ami_ct_s16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
-	long count, used;
-	u_long data;
+	ssize_t count, used;
+	u_short data;
 
 	if (!sound.soft.stereo) {
 		u_char *high = &frame[*frameUsed>>1];
@@ -1692,11 +1731,12 @@
 }
 
 
-static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
-	long count, used;
-	u_long data;
+	ssize_t count, used;
+	u_short data;
 
 	if (!sound.soft.stereo) {
 		u_char *high = &frame[*frameUsed>>1];
@@ -1738,11 +1778,12 @@
 #endif /* CONFIG_AMIGA */
 
 #ifdef CONFIG_PMAC
-static long pmac_ct_law(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
 {
 	short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
-	long count, used;
+	ssize_t count, used;
 	short *p = (short *) &frame[*frameUsed];
 	int val, stereo = sound.soft.stereo;
 
@@ -1769,10 +1810,11 @@
 }
 
 
-static long pmac_ct_s8(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
 {
-	long count, used;
+	ssize_t count, used;
 	short *p = (short *) &frame[*frameUsed];
 	int val, stereo = sound.soft.stereo;
 
@@ -1799,10 +1841,11 @@
 }
 
 
-static long pmac_ct_u8(const u_char *userPtr, unsigned long userCount,
-		       u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
 {
-	long count, used;
+	ssize_t count, used;
 	short *p = (short *) &frame[*frameUsed];
 	int val, stereo = sound.soft.stereo;
 
@@ -1829,10 +1872,11 @@
 }
 
 
-static long pmac_ct_s16(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
 {
-	long count, used;
+	ssize_t count, used;
 	int stereo = sound.soft.stereo;
 	short *fp = (short *) &frame[*frameUsed];
 
@@ -1857,11 +1901,12 @@
 	return stereo? used * 4: used * 2;
 }
 
-static long pmac_ct_u16(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
 {
-	long count, used;
-	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+	ssize_t count, used;
+	short mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
 	int stereo = sound.soft.stereo;
 	short *fp = (short *) &frame[*frameUsed];
 	short *up = (short *) userPtr;
@@ -1870,7 +1915,7 @@
 	userCount >>= (stereo? 2: 1);
 	used = count = min(userCount, frameLeft);
 	while (count > 0) {
-		int data;
+		short data;
 		if (get_user(data, up++))
 			return -EFAULT;
 		data ^= mask;
@@ -1888,8 +1933,9 @@
 }
 
 
-static long pmac_ctx_law(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
 	unsigned short *table = (unsigned short *)
 		(sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
@@ -1934,8 +1980,9 @@
 }
 
 
-static long pmac_ctx_s8(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
 {
 	unsigned int *p = (unsigned int *) &frame[*frameUsed];
 	unsigned int data = sound.data;
@@ -1978,8 +2025,9 @@
 }
 
 
-static long pmac_ctx_u8(const u_char *userPtr, unsigned long userCount,
-			u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
 {
 	unsigned int *p = (unsigned int *) &frame[*frameUsed];
 	unsigned int data = sound.data;
@@ -2022,8 +2070,9 @@
 }
 
 
-static long pmac_ctx_s16(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
 	unsigned int *p = (unsigned int *) &frame[*frameUsed];
 	unsigned int data = sound.data;
@@ -2066,8 +2115,9 @@
 }
 
 
-static long pmac_ctx_u16(const u_char *userPtr, unsigned long userCount,
-			 u_char frame[], long *frameUsed, long frameLeft)
+static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
+			    u_char frame[], ssize_t *frameUsed,
+			    ssize_t frameLeft)
 {
 	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
 	unsigned int *p = (unsigned int *) &frame[*frameUsed];
@@ -3425,12 +3475,12 @@
 #endif /* CONFIG_ATARI || CONFIG_AMIGA */
 
 
-static long sound_copy_translate(const u_char *userPtr,
-				 unsigned long userCount,
-				 u_char frame[], long *frameUsed,
-				 long frameLeft)
+static ssize_t sound_copy_translate(const u_char *userPtr,
+				    size_t userCount,
+				    u_char frame[], ssize_t *frameUsed,
+				    ssize_t frameLeft)
 {
-	long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL;
+	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
 
 	switch (sound.soft.format) {
 	case AFMT_MU_LAW:
@@ -3459,9 +3509,9 @@
 		break;
 	}
 	if (ct_func)
-		return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft));
+		return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
 	else
-		return(0);
+		return 0;
 }
 
 
@@ -3475,53 +3525,19 @@
 #define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
 
 
-static void mixer_init(void)
-{
-	mixer.busy = 0;
-	sound.treble = 0;
-	sound.bass = 0;
-	switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
-	case DMASND_TT:
-		atari_microwire_cmd(MW_LM1992_VOLUME(0));
-		sound.volume_left = 0;
-		atari_microwire_cmd(MW_LM1992_BALLEFT(0));
-		sound.volume_right = 0;
-		atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
-		atari_microwire_cmd(MW_LM1992_TREBLE(0));
-		atari_microwire_cmd(MW_LM1992_BASS(0));
-		break;
-	case DMASND_FALCON:
-		sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
-		sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
-		break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	case DMASND_AMIGA:
-		sound.volume_left = 64;
-		sound.volume_right = 64;
-		custom.aud[0].audvol = sound.volume_left;
-		custom.aud[3].audvol = 1;	/* For pseudo 14bit */
-		custom.aud[1].audvol = sound.volume_right;
-		custom.aud[2].audvol = 1;	/* For pseudo 14bit */
-		sound.treble = 50;
-		break;
-#endif /* CONFIG_AMIGA */
-	}
-}
-
-
-static int mixer_open(int open_mode)
+static int mixer_open(struct inode *inode, struct file *file)
 {
+	MOD_INC_USE_COUNT;
 	mixer.busy = 1;
-	return(0);
+	return 0;
 }
 
 
-static int mixer_release(void)
+static int mixer_release(struct inode *inode, struct file *file)
 {
 	mixer.busy = 0;
-	return(0);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 
@@ -3534,17 +3550,17 @@
 	case DMASND_FALCON:
 		switch (cmd) {
 		case SOUND_MIXER_READ_DEVMASK:
-			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
 		case SOUND_MIXER_READ_RECMASK:
-			return(IOCTL_OUT(arg, SOUND_MASK_MIC));
+			return IOCTL_OUT(arg, SOUND_MASK_MIC);
 		case SOUND_MIXER_READ_STEREODEVS:
-			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
+			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);
 		case SOUND_MIXER_READ_CAPS:
-			return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT));
+			return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);
 		case SOUND_MIXER_READ_VOLUME:
-			return(IOCTL_OUT(arg,
+			return IOCTL_OUT(arg,
 				VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
-				VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8));
+				VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
 		case SOUND_MIXER_WRITE_MIC:
 			IOCTL_IN(arg, data);
 			tt_dmasnd.input_gain =
@@ -3552,9 +3568,9 @@
 				RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
 			/* fall thru, return set value */
 		case SOUND_MIXER_READ_MIC:
-			return(IOCTL_OUT(arg,
+			return IOCTL_OUT(arg,
 				RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
-				RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8));
+				RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);
 		case SOUND_MIXER_READ_SPEAKER:
 			{
 				int porta;
@@ -3562,11 +3578,11 @@
 				sound_ym.rd_data_reg_sel = 14;
 				porta = sound_ym.rd_data_reg_sel;
 				sti();
-				return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+				return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
 			}
 		case SOUND_MIXER_WRITE_VOLUME:
 			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_volume(data)));
+			return IOCTL_OUT(arg, sound_set_volume(data));
 		case SOUND_MIXER_WRITE_SPEAKER:
 			{
 				int porta;
@@ -3577,7 +3593,7 @@
 					(data < 50 ? 0x40 : 0);
 				sound_ym.wd_data = porta;
 				sti();
-				return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
+				return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
 			}
 		}
 		break;
@@ -3585,23 +3601,23 @@
 	case DMASND_TT:
 		switch (cmd) {
 		case SOUND_MIXER_READ_DEVMASK:
-			return(IOCTL_OUT(arg,
+			return IOCTL_OUT(arg,
 					 SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
-					 (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0)));
+					 (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));
 		case SOUND_MIXER_READ_RECMASK:
-			return(IOCTL_OUT(arg, 0));
+			return IOCTL_OUT(arg, 0);
 		case SOUND_MIXER_READ_STEREODEVS:
-			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+			return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
 		case SOUND_MIXER_READ_VOLUME:
-			return(IOCTL_OUT(arg,
+			return IOCTL_OUT(arg,
 					 VOLUME_DB_TO_VOXWARE(sound.volume_left) |
-					 (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)));
+					 (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
 		case SOUND_MIXER_READ_BASS:
-			return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass)));
+			return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass));
 		case SOUND_MIXER_READ_TREBLE:
-			return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble)));
+			return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble));
 		case SOUND_MIXER_READ_OGAIN:
-			return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain)));
+			return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain));
 		case SOUND_MIXER_READ_SPEAKER:
 			{
 				int porta;
@@ -3610,22 +3626,22 @@
 					sound_ym.rd_data_reg_sel = 14;
 					porta = sound_ym.rd_data_reg_sel;
 					sti();
-					return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-				} else
-					return(-EINVAL);
+					return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
+				}
 			}
+			break;
 		case SOUND_MIXER_WRITE_VOLUME:
 			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_volume(data)));
+			return IOCTL_OUT(arg, sound_set_volume(data));
 		case SOUND_MIXER_WRITE_BASS:
 			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_bass(data)));
+			return IOCTL_OUT(arg, sound_set_bass(data));
 		case SOUND_MIXER_WRITE_TREBLE:
 			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_treble(data)));
+			return IOCTL_OUT(arg, sound_set_treble(data));
 		case SOUND_MIXER_WRITE_OGAIN:
 			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_gain(data)));
+			return IOCTL_OUT(arg, sound_set_gain(data));
 		case SOUND_MIXER_WRITE_SPEAKER:
 			if (MACH_IS_TT) {
 				int porta;
@@ -3636,9 +3652,8 @@
 					(data < 50 ? 0x40 : 0);
 				sound_ym.wd_data = porta;
 				sti();
-				return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
-			} else
-				return(-EINVAL);
+				return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
+			}
 		}
 		break;
 #endif /* CONFIG_ATARI */
@@ -3647,23 +3662,23 @@
 	case DMASND_AMIGA:
 		switch (cmd) {
 		case SOUND_MIXER_READ_DEVMASK:
-			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
+			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
 		case SOUND_MIXER_READ_RECMASK:
-			return(IOCTL_OUT(arg, 0));
+			return IOCTL_OUT(arg, 0);
 		case SOUND_MIXER_READ_STEREODEVS:
-			return(IOCTL_OUT(arg, SOUND_MASK_VOLUME));
+			return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
 		case SOUND_MIXER_READ_VOLUME:
-			return(IOCTL_OUT(arg,
+			return IOCTL_OUT(arg,
 				VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
-				VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
+				VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8);
 		case SOUND_MIXER_WRITE_VOLUME:
 			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_volume(data)));
+			return IOCTL_OUT(arg, sound_set_volume(data));
 		case SOUND_MIXER_READ_TREBLE:
-			return(IOCTL_OUT(arg, sound.treble));
+			return IOCTL_OUT(arg, sound.treble);
 		case SOUND_MIXER_WRITE_TREBLE:
 			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_treble(data)));
+			return IOCTL_OUT(arg, sound_set_treble(data));
 		}
 		break;
 #endif /* CONFIG_AMIGA */
@@ -3778,17 +3793,73 @@
 #endif
 	}
 
-	return(-EINVAL);
+	return -EINVAL;
 }
 
 
+static struct file_operations mixer_fops =
+{
+	sound_lseek,
+	NULL,			/* mixer_read */
+	NULL,			/* mixer_write */
+	NULL,			/* mixer_readdir */
+	NULL,			/* mixer_poll */
+	mixer_ioctl,
+	NULL,			/* mixer_mmap */
+	mixer_open,
+	mixer_release,
+};
+
+
+__initfunc(static void mixer_init(void))
+{
+#ifndef MODULE
+	int mixer_unit;
+#endif
+	mixer_unit = register_sound_mixer(&mixer_fops);
+	if (mixer_unit < 0)
+		return;
+
+	mixer.busy = 0;
+	sound.treble = 0;
+	sound.bass = 0;
+	switch (sound.mach.type) {
+#ifdef CONFIG_ATARI
+	case DMASND_TT:
+		atari_microwire_cmd(MW_LM1992_VOLUME(0));
+		sound.volume_left = 0;
+		atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+		sound.volume_right = 0;
+		atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+		atari_microwire_cmd(MW_LM1992_TREBLE(0));
+		atari_microwire_cmd(MW_LM1992_BASS(0));
+		break;
+	case DMASND_FALCON:
+		sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+		sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+		break;
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+	case DMASND_AMIGA:
+		sound.volume_left = 64;
+		sound.volume_right = 64;
+		custom.aud[0].audvol = sound.volume_left;
+		custom.aud[3].audvol = 1;	/* For pseudo 14bit */
+		custom.aud[1].audvol = sound.volume_right;
+		custom.aud[2].audvol = 1;	/* For pseudo 14bit */
+		sound.treble = 50;
+		break;
+#endif /* CONFIG_AMIGA */
+	}
+}
+
 
 /*
  * Sound queue stuff, the heart of the driver
  */
 
 
-static void sq_init(int numBufs, int bufSize, char **buffers)
+static void sq_setup(int numBufs, int bufSize, char **buffers)
 {
 #ifdef CONFIG_PMAC
 	int i;
@@ -3828,47 +3899,6 @@
 #endif /* CONFIG_PMAC */
 }
 
-static void
-init_settings(void)
-{
-	/* whatever you like as startup mode for /dev/dsp,
-	 * (/dev/audio hasn't got a startup mode). note that
-	 * once changed a new open() will *not* restore these!
-	 */
-	sound.dsp.format = AFMT_U8;
-	sound.dsp.stereo = 0;
-	sound.dsp.size = 8;
-
-	/* set minimum rate possible without expanding */
-	switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
-	case DMASND_TT:
-		sound.dsp.speed = 6258;
-		break;
-	case DMASND_FALCON:
-		sound.dsp.speed = 8195;
-		break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-	case DMASND_AMIGA:
-		sound.dsp.speed = 8000;
-		break;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PMAC
-	case DMASND_AWACS:
-		sound.dsp.speed = 8000;
-		break;
-#endif /* CONFIG_PMAC */
-	}
-
-	/* before the first open to /dev/dsp this wouldn't be set */
-	sound.soft = sound.dsp;
-	sound.hard = sound.dsp;
-
-	sound_silence();
-}
-
-
 static void sq_play(void)
 {
 	(*sound.mach.play)();
@@ -3877,18 +3907,19 @@
 
 /* ++TeSche: radically changed this one too */
 
-static long sq_write(const char *src, unsigned long uLeft)
+static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
+			loff_t *ppos)
 {
-	long uWritten = 0;
+	ssize_t uWritten = 0;
 	u_char *dest;
-	long uUsed, bUsed, bLeft;
+	ssize_t uUsed, bUsed, bLeft;
 
 	/* ++TeSche: Is something like this necessary?
 	 * Hey, that's an honest question! Or does any other part of the
 	 * filesystem already checks this situation? I really don't know.
 	 */
 	if (uLeft == 0)
-		return(0);
+		return 0;
 
 	/* The interrupt doesn't start to play the last, incomplete frame.
 	 * Thus we can append to it without disabling the interrupts! (Note
@@ -3911,10 +3942,10 @@
 		while (sq.count == sq.max_active) {
 			sq_play();
 			if (NON_BLOCKING(sq.open_mode))
-				return(uWritten > 0 ? uWritten : -EAGAIN);
+				return uWritten > 0 ? uWritten : -EAGAIN;
 			SLEEP(sq.write_queue, ONE_SECOND);
 			if (SIGNAL_RECEIVED)
-				return(uWritten > 0 ? uWritten : -EINTR);
+				return uWritten > 0 ? uWritten : -EINTR;
 		}
 
 		/* Here, we can avoid disabling the interrupt by first
@@ -3942,28 +3973,46 @@
 
 	sq_play();
 
-	return(uUsed < 0? uUsed: uWritten);
+	return uUsed < 0? uUsed: uWritten;
 }
 
 
-static int sq_open(int open_mode)
+static int sq_open(struct inode *inode, struct file *file)
 {
+	int rc = 0;
+
+	MOD_INC_USE_COUNT;
 	if (sq.busy) {
-		if (NON_BLOCKING(open_mode))
-			return(-EBUSY);
+		rc = -EBUSY;
+		if (NON_BLOCKING(file->f_flags))
+			goto err_out;
+		rc = -EINTR;
 		while (sq.busy) {
 			SLEEP(sq.open_queue, ONE_SECOND);
 			if (SIGNAL_RECEIVED)
-				return(-EINTR);
+				goto err_out;
 		}
+		rc = 0;
 	}
-	sq_init(numBufs, bufSize << 10, sound_buffers);
-	sq.open_mode = open_mode;
+	sq_setup(numBufs, bufSize << 10, sound_buffers);
+	sq.open_mode = file->f_flags;
 	sq.busy = 1;
 #ifdef CONFIG_ATARI
 	sq.ignore_int = 1;
 #endif /* CONFIG_ATARI */
-	return(0);
+	sound.minDev = MINOR(inode->i_rdev) & 0x0f;
+	sound.soft = sound.dsp;
+	sound.hard = sound.dsp;
+	sound_init();
+	if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
+		sound_set_speed(8000);
+		sound_set_stereo(0);
+		sound_set_format(AFMT_MU_LAW);
+	}
+	return 0;
+err_out:
+	MOD_DEC_USE_COUNT;
+	return rc;
 }
 
 
@@ -3976,7 +4025,7 @@
 }
 
 
-static int sq_sync(void)
+static int sq_fsync(struct file *filp, struct dentry *dentry)
 {
 	int rc = 0;
 
@@ -3996,47 +4045,195 @@
 	}
 
 	sq.syncing = 0;
-	return(rc);
+	return rc;
 }
 
-
-static int sq_release(void)
+static int sq_release(struct inode *inode, struct file *file)
 {
 	int rc = 0;
 	if (sq.busy) {
-		rc = sq_sync();
+		rc = sq_fsync(file, file->f_dentry);
 		sq.busy = 0;
 		WAKE_UP(sq.open_queue);
 		/* Wake up a process waiting for the queue being released.
 		 * Note: There may be several processes waiting for a call
 		 * to open() returning. */
 	}
-	return(rc);
+	sound.soft = sound.dsp;
+	sound.hard = sound.dsp;
+	sound_silence();
+	if (rc == 0)
+		MOD_DEC_USE_COUNT;
+	return rc;
 }
 
 
+static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		    u_long arg)
+{
+	u_long fmt;
+	int data;
+	int size, nbufs;
 
-/*
- * /dev/sndstat
- */
+	switch (cmd) {
+	case SNDCTL_DSP_RESET:
+		sq_reset();
+		return 0;
+	case SNDCTL_DSP_POST:
+	case SNDCTL_DSP_SYNC:
+		return sq_fsync(file, file->f_dentry);
+
+		/* ++TeSche: before changing any of these it's
+		 * probably wise to wait until sound playing has
+		 * settled down. */
+	case SNDCTL_DSP_SPEED:
+		sq_fsync(file, file->f_dentry);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, sound_set_speed(data));
+	case SNDCTL_DSP_STEREO:
+		sq_fsync(file, file->f_dentry);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, sound_set_stereo(data));
+	case SOUND_PCM_WRITE_CHANNELS:
+		sq_fsync(file, file->f_dentry);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
+	case SNDCTL_DSP_SETFMT:
+		sq_fsync(file, file->f_dentry);
+		IOCTL_IN(arg, data);
+		return IOCTL_OUT(arg, sound_set_format(data));
+	case SNDCTL_DSP_GETFMTS:
+		fmt = 0;
+		if (sound.trans) {
+			if (sound.trans->ct_ulaw)
+				fmt |= AFMT_MU_LAW;
+			if (sound.trans->ct_alaw)
+				fmt |= AFMT_A_LAW;
+			if (sound.trans->ct_s8)
+				fmt |= AFMT_S8;
+			if (sound.trans->ct_u8)
+				fmt |= AFMT_U8;
+			if (sound.trans->ct_s16be)
+				fmt |= AFMT_S16_BE;
+			if (sound.trans->ct_u16be)
+				fmt |= AFMT_U16_BE;
+			if (sound.trans->ct_s16le)
+				fmt |= AFMT_S16_LE;
+			if (sound.trans->ct_u16le)
+				fmt |= AFMT_U16_LE;
+		}
+		return IOCTL_OUT(arg, fmt);
+	case SNDCTL_DSP_GETBLKSIZE:
+		size = sq.block_size
+			* sound.soft.size * (sound.soft.stereo + 1)
+			/ (sound.hard.size * (sound.hard.stereo + 1));
+		return IOCTL_OUT(arg, size);
+	case SNDCTL_DSP_SUBDIVIDE:
+		break;
+	case SNDCTL_DSP_SETFRAGMENT:
+		if (sq.count || sq.playing || sq.syncing)
+			return -EINVAL;
+		IOCTL_IN(arg, size);
+		nbufs = size >> 16;
+		if (nbufs < 2 || nbufs > numBufs)
+			nbufs = numBufs;
+		size &= 0xffff;
+		if (size >= 8 && size <= 30) {
+			size = 1 << size;
+			size *= sound.hard.size * (sound.hard.stereo + 1);
+			size /= sound.soft.size * (sound.soft.stereo + 1);
+			if (size > (bufSize << 10))
+				size = bufSize << 10;
+		} else
+			size = bufSize << 10;
+		sq_setup(numBufs, size, sound_buffers);
+		sq.max_active = nbufs;
+		return 0;
+
+	default:
+		return mixer_ioctl(inode, file, cmd, arg);
+	}
+	return -EINVAL;
+}
 
 
-static void state_init(void)
+
+static struct file_operations sq_fops =
 {
-	state.busy = 0;
+	sound_lseek,
+	NULL,			/* sq_read */
+	sq_write,
+	NULL,			/* sq_readdir */
+	NULL,			/* sq_poll */
+	sq_ioctl,
+	NULL,			/* sq_mmap */
+	sq_open,
+	sq_release,
+};
+
+
+__initfunc(static void sq_init(void))
+{
+#ifndef MODULE
+	int sq_unit;
+#endif
+	sq_unit = register_sound_dsp(&sq_fops);
+	if (sq_unit < 0)
+		return;
+
+	/* whatever you like as startup mode for /dev/dsp,
+	 * (/dev/audio hasn't got a startup mode). note that
+	 * once changed a new open() will *not* restore these!
+	 */
+	sound.dsp.format = AFMT_U8;
+	sound.dsp.stereo = 0;
+	sound.dsp.size = 8;
+
+	/* set minimum rate possible without expanding */
+	switch (sound.mach.type) {
+#ifdef CONFIG_ATARI
+	case DMASND_TT:
+		sound.dsp.speed = 6258;
+		break;
+	case DMASND_FALCON:
+		sound.dsp.speed = 8195;
+		break;
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+	case DMASND_AMIGA:
+		sound.dsp.speed = 8000;
+		break;
+#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PMAC
+	case DMASND_AWACS:
+		sound.dsp.speed = 8000;
+		break;
+#endif /* CONFIG_PMAC */
+	}
+
+	/* before the first open to /dev/dsp this wouldn't be set */
+	sound.soft = sound.dsp;
+	sound.hard = sound.dsp;
+
+	sound_silence();
 }
 
+/*
+ * /dev/sndstat
+ */
+
 
 /* state.buf should not overflow! */
 
-static int state_open(int open_mode)
+static int state_open(struct inode *inode, struct file *file)
 {
 	char *buffer = state.buf, *mach = "";
 	int len = 0;
 
 	if (state.busy)
-		return(-EBUSY);
+		return -EBUSY;
 
+	MOD_INC_USE_COUNT;
 	state.ptr = 0;
 	state.busy = 1;
 
@@ -4128,294 +4325,77 @@
 	len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
 		       sq.playing, sq.syncing);
 	state.len = len;
-	return(0);
+	return 0;
 }
 
 
-static int state_release(void)
+static int state_release(struct inode *inode, struct file *file)
 {
 	state.busy = 0;
-	return(0);
+	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 
-static long state_read(char *dest, unsigned long count)
+static ssize_t state_read(struct file *file, char *buf, size_t count,
+			  loff_t *ppos)
 {
-	int n = state.len-state.ptr;
+	int n = state.len - state.ptr;
 	if (n > count)
 		n = count;
 	if (n <= 0)
-		return(0);
-	if (copy_to_user(dest, &state.buf[state.ptr], n))
+		return 0;
+	if (copy_to_user(buf, &state.buf[state.ptr], n))
 		return -EFAULT;
 	state.ptr += n;
-	return(n);
+	return n;
 }
 
 
-
-/*** High level stuff ********************************************************/
-
-
-static int sound_open(struct inode *inode, struct file *file)
+static struct file_operations state_fops =
 {
-	int dev = MINOR(inode->i_rdev) & 0x0f;
-	int rc = 0;
-
-	switch (dev) {
-	case SND_DEV_STATUS:
-		rc = state_open(file->f_flags);
-		break;
-	case SND_DEV_CTL:
-		rc = mixer_open(file->f_flags);
-		break;
-	case SND_DEV_DSP:
-	case SND_DEV_AUDIO:
-		rc = sq_open(file->f_flags);
-		if (rc == 0) {
-			sound.minDev = dev;
-			sound.soft = sound.dsp;
-			sound.hard = sound.dsp;
-			sound_init();
-			if (dev == SND_DEV_AUDIO) {
-				sound_set_speed(8000);
-				sound_set_stereo(0);
-				sound_set_format(AFMT_MU_LAW);
-			}
-		}
-		break;
-	default:
-		rc = -ENXIO;
-	}
-#ifdef MODULE
-	if (rc >= 0)
-		MOD_INC_USE_COUNT;
-#endif
-	return(rc);
-}
-
-
-static int sound_fsync(struct file *filp, struct dentry *dentry)
-{
-	int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f;
-
-	switch (dev) {
-	case SND_DEV_STATUS:
-	case SND_DEV_CTL:
-		return(0);
-	case SND_DEV_DSP:
-	case SND_DEV_AUDIO:
-		return(sq_sync());
-	default:
-		return(unknown_minor_dev("sound_fsync", dev));
-	}
-}
+	sound_lseek,
+	state_read,
+	NULL,			/* state_write */
+	NULL,			/* state_readdir */
+	NULL,			/* state_poll */
+	NULL,			/* state_ioctl */
+	NULL,			/* state_mmap */
+	state_open,
+	state_release,
+};
 
 
-static int sound_release(struct inode *inode, struct file *file)
+__initfunc(static void state_init(void))
 {
-	int dev = MINOR(inode->i_rdev);
-
-	switch (dev & 0x0f) {
-	case SND_DEV_STATUS:
-		state_release();
-		break;
-	case SND_DEV_CTL:
-		mixer_release();
-		break;
-	case SND_DEV_DSP:
-	case SND_DEV_AUDIO:
-		sq_release();
-		sound.soft = sound.dsp;
-		sound.hard = sound.dsp;
-		sound_silence();
-		break;
-	default:
-		return unknown_minor_dev("sound_release", dev);
-	}
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
+#ifndef MODULE
+	int state_unit;
 #endif
-	return 0;
+	state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
+	if (state_unit < 0)
+		return;
+	state.busy = 0;
 }
 
 
+/*** Common stuff ********************************************************/
+
 static long long sound_lseek(struct file *file, long long offset, int orig)
 {
 	return -ESPIPE;
 }
 
 
-static ssize_t sound_read(struct file *file, char *buf, size_t count,
-			  loff_t *ppos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	int dev = MINOR(inode->i_rdev);
-
-	switch (dev & 0x0f) {
-	case SND_DEV_STATUS:
-		return(state_read(buf, count));
-	case SND_DEV_CTL:
-	case SND_DEV_DSP:
-	case SND_DEV_AUDIO:
-		return(-EPERM);
-	default:
-		return(unknown_minor_dev("sound_read", dev));
-	}
-}
-
-
-static ssize_t sound_write(struct file *file, const char *buf, size_t count,
-			   loff_t *ppos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	int dev = MINOR(inode->i_rdev);
-
-	switch (dev & 0x0f) {
-	case SND_DEV_STATUS:
-	case SND_DEV_CTL:
-		return(-EPERM);
-	case SND_DEV_DSP:
-	case SND_DEV_AUDIO:
-		return(sq_write(buf, count));
-	default:
-		return(unknown_minor_dev("sound_write", dev));
-	}
-}
-
-
-static int unknown_minor_dev(char *fname, int dev)
-{
-	/* printk("%s: Unknown minor device %d\n", fname, dev); */
-	return(-ENXIO);
-}
-
-
-static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg)
-{
-	int dev = MINOR(inode->i_rdev);
-	u_long fmt;
-	int data;
-	int size, nbufs;
-
-	switch (dev & 0x0f) {
-	case SND_DEV_STATUS:
-		return(-EPERM);
-	case SND_DEV_CTL:
-		return(mixer_ioctl(inode, file, cmd, arg));
-	case SND_DEV_AUDIO:
-	case SND_DEV_DSP:
-		switch (cmd) {
-		case SNDCTL_DSP_RESET:
-			sq_reset();
-			return(0);
-		case SNDCTL_DSP_POST:
-		case SNDCTL_DSP_SYNC:
-			return(sound_fsync(file, file->f_dentry));
-
-			/* ++TeSche: before changing any of these it's
-			 * probably wise to wait until sound playing has
-			 * settled down. */
-		case SNDCTL_DSP_SPEED:
-			sound_fsync(file, file->f_dentry);
-			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_speed(data)));
-		case SNDCTL_DSP_STEREO:
-			sound_fsync(file, file->f_dentry);
-			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_stereo(data)));
-		case SOUND_PCM_WRITE_CHANNELS:
-			sound_fsync(file, file->f_dentry);
-			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1));
-		case SNDCTL_DSP_SETFMT:
-			sound_fsync(file, file->f_dentry);
-			IOCTL_IN(arg, data);
-			return(IOCTL_OUT(arg, sound_set_format(data)));
-		case SNDCTL_DSP_GETFMTS:
-			fmt = 0;
-			if (sound.trans) {
-				if (sound.trans->ct_ulaw)
-					fmt |= AFMT_MU_LAW;
-				if (sound.trans->ct_alaw)
-					fmt |= AFMT_A_LAW;
-				if (sound.trans->ct_s8)
-					fmt |= AFMT_S8;
-				if (sound.trans->ct_u8)
-					fmt |= AFMT_U8;
-				if (sound.trans->ct_s16be)
-					fmt |= AFMT_S16_BE;
-				if (sound.trans->ct_u16be)
-					fmt |= AFMT_U16_BE;
-				if (sound.trans->ct_s16le)
-					fmt |= AFMT_S16_LE;
-				if (sound.trans->ct_u16le)
-					fmt |= AFMT_U16_LE;
-			}
-			return(IOCTL_OUT(arg, fmt));
-		case SNDCTL_DSP_GETBLKSIZE:
-			size = sq.block_size
-				* sound.soft.size * (sound.soft.stereo + 1)
-				/ (sound.hard.size * (sound.hard.stereo + 1));
-			return(IOCTL_OUT(arg, size));
-		case SNDCTL_DSP_SUBDIVIDE:
-			break;
-		case SNDCTL_DSP_SETFRAGMENT:
-			if (sq.count || sq.playing || sq.syncing)
-				return -EINVAL;
-			IOCTL_IN(arg, size);
-			nbufs = size >> 16;
-			if (nbufs < 2 || nbufs > numBufs)
-				nbufs = numBufs;
-			size &= 0xffff;
-			if (size >= 8 && size <= 30) {
-				size = 1 << size;
-				size *= sound.hard.size * (sound.hard.stereo + 1);
-				size /= sound.soft.size * (sound.soft.stereo + 1);
-				if (size > (bufSize << 10))
-					size = bufSize << 10;
-			} else
-				size = bufSize << 10;
-			sq_init(numBufs, size, sound_buffers);
-			sq.max_active = nbufs;
-			break;
-
-		default:
-			return(mixer_ioctl(inode, file, cmd, arg));
-		}
-		break;
-
-	default:
-		return(unknown_minor_dev("sound_ioctl", dev));
-	}
-	return(-EINVAL);
-}
-
-
-static struct file_operations sound_fops =
-{
-	sound_lseek,
-	sound_read,
-	sound_write,
-	NULL,
-	NULL,                      /* select */
-	sound_ioctl,
-	NULL,
-	sound_open,
-	sound_release,
-	sound_fsync
-};
-
-
-
 /*** Config & Setup **********************************************************/
 
 
-void soundcard_init(void)
+__initfunc(void dmasound_init(void))
 {
 	int has_sound = 0;
 	int i;
+#ifdef CONFIG_PMAC
+	struct device_node *np;
+#endif
 
 #ifdef __mc68000__
 	switch (m68k_machtype) {
@@ -4448,8 +4428,6 @@
 #endif /* __mc68000__ */
 
 #ifdef CONFIG_PMAC
-	struct device_node *np;
-
 	np = find_devices("awacs");
 	if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
 		int vol;
@@ -4517,15 +4495,10 @@
 		}
 	}
 
-#ifndef MODULE
-	/* Register driver with the VFS. */
-	register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
-#endif
-
-	sq_init(numBufs, bufSize << 10, sound_buffers);
+	sq_setup(numBufs, bufSize << 10, sound_buffers);
 
 	/* Set default settings. */
-	init_settings();
+	sq_init();
 
 	/* Set up /dev/sndstat. */
 	state_init();
@@ -4547,15 +4520,10 @@
 	return;
 }
 
-void sound_setup(char *str, int *ints)
-{
-	/* ++Martin: stub, could possibly be merged with soundcard.c et al later */
-}
-
 
 #define MAXARGS		8	/* Should be sufficient for now */
 
-void dmasound_setup(char *str, int *ints)
+__initfunc(void dmasound_setup(char *str, int *ints))
 {
 	/* check the bootstrap parameter for "dmasound=" */
 
@@ -4586,28 +4554,9 @@
 
 #ifdef MODULE
 
-static int dmasound[MAXARGS] = { 0 };
-
 int init_module(void)
 {
-	int err, i = 0;
-	int ints[MAXARGS+1];
-
-	while (i < MAXARGS && dmasound[i])
-		ints[i + 1] = dmasound[i++];
-	ints[0] = i;
-
-	if (i)
-		dmasound_setup("dmasound=", ints);
-
-	err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
-	if (err) {
-		printk("dmasound: driver already loaded/included in kernel\n");
-		return err;
-	}
-	chrdev_registered = 1;
-	soundcard_init();
-
+	dmasound_init();
 	return 0;
 }
 
@@ -4616,12 +4565,6 @@
 {
 	int i;
 
-	if (MOD_IN_USE)
-		return;
-
-	if (chrdev_registered)
-		unregister_chrdev(SOUND_MAJOR, "sound");
-
 	if (irq_installed) {
 		sound_silence();
 		sound.mach.irqcleanup();
@@ -4632,6 +4575,13 @@
 			sound.mach.dma_free(sound_buffers[i], bufSize << 10);
 		kfree(sound_buffers);
 	}
+
+	if (mixer_unit >= 0)
+		unregister_sound_mixer(mixer_unit);
+	if (state_unit >= 0)
+		unregister_sound_special(state_unit);
+	if (sq_unit >= 0)
+		unregister_sound_dsp(sq_unit);
 }
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.112/linux/drivers/video/atafb.c linux/drivers/video/atafb.c
--- v2.1.112/linux/drivers/video/atafb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/atafb.c	Fri Jul 31 23:19:40 1998
@@ -47,7 +47,6 @@
 #define ATAFB_EXT
 #define ATAFB_FALCON
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/cgsixfb.c linux/drivers/video/cgsixfb.c
--- v2.1.112/linux/drivers/video/cgsixfb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/cgsixfb.c	Fri Jul 31 23:19:40 1998
@@ -6,6 +6,7 @@
  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.1.112/linux/drivers/video/clgenfb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/clgenfb.c	Fri Jul 31 23:19:40 1998
@@ -2,7 +2,6 @@
  * Based on retz3fb.c and clgen.c
  */
  
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/creatorfb.c linux/drivers/video/creatorfb.c
--- v2.1.112/linux/drivers/video/creatorfb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/creatorfb.c	Fri Jul 31 23:19:40 1998
@@ -4,6 +4,7 @@
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- v2.1.112/linux/drivers/video/cyberfb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/cyberfb.c	Fri Jul 31 23:19:40 1998
@@ -20,8 +20,6 @@
  * for more details.
  */
 
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/dnfb.c linux/drivers/video/dnfb.c
--- v2.1.112/linux/drivers/video/dnfb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/dnfb.c	Fri Jul 31 23:19:40 1998
@@ -5,7 +5,6 @@
 #include <linux/tty.h>
 #include <linux/malloc.h>
 #include <linux/delay.h>
-#include <linux/config.h>
 #include <linux/interrupt.h>
 #include <asm/setup.h>
 #include <asm/segment.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/dummycon.c linux/drivers/video/dummycon.c
--- v2.1.112/linux/drivers/video/dummycon.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/dummycon.c	Fri Jul 31 23:19:40 1998
@@ -5,6 +5,7 @@
  *  available, usually until fbcon takes console over.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 #include <linux/tty.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-afb.h linux/drivers/video/fbcon-afb.h
--- v2.1.112/linux/drivers/video/fbcon-afb.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-afb.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  Amiga bitplanes (afb)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_AFB_MODULE)
 #define FBCON_HAS_AFB
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c
--- v2.1.112/linux/drivers/video/fbcon-cfb16.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb16.c	Fri Jul 31 23:19:40 1998
@@ -9,6 +9,7 @@
  *  more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/tty.h>
 #include <linux/console.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb16.h linux/drivers/video/fbcon-cfb16.h
--- v2.1.112/linux/drivers/video/fbcon-cfb16.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb16.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  16 bpp packed pixel (cfb16)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB16) || defined(CONFIG_FBCON_CFB16_MODULE)
 #define FBCON_HAS_CFB16
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb2.h linux/drivers/video/fbcon-cfb2.h
--- v2.1.112/linux/drivers/video/fbcon-cfb2.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb2.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  2 bpp packed pixel (cfb2)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB2) || defined(CONFIG_FBCON_CFB2_MODULE)
 #define FBCON_HAS_CFB2
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb24.c linux/drivers/video/fbcon-cfb24.c
--- v2.1.112/linux/drivers/video/fbcon-cfb24.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb24.c	Fri Jul 31 23:19:40 1998
@@ -9,6 +9,7 @@
  *  more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/tty.h>
 #include <linux/console.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb24.h linux/drivers/video/fbcon-cfb24.h
--- v2.1.112/linux/drivers/video/fbcon-cfb24.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb24.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  24 bpp packed pixel (cfb24)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB24) || defined(CONFIG_FBCON_CFB24_MODULE)
 #define FBCON_HAS_CFB24
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb32.c linux/drivers/video/fbcon-cfb32.c
--- v2.1.112/linux/drivers/video/fbcon-cfb32.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb32.c	Fri Jul 31 23:19:40 1998
@@ -9,6 +9,7 @@
  *  more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/tty.h>
 #include <linux/console.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb32.h linux/drivers/video/fbcon-cfb32.h
--- v2.1.112/linux/drivers/video/fbcon-cfb32.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb32.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  32 bpp packed pixel (cfb32)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB32) || defined(CONFIG_FBCON_CFB32_MODULE)
 #define FBCON_HAS_CFB32
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb4.h linux/drivers/video/fbcon-cfb4.h
--- v2.1.112/linux/drivers/video/fbcon-cfb4.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb4.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  4 bpp packed pixel (cfb4)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB4) || defined(CONFIG_FBCON_CFB4_MODULE)
 #define FBCON_HAS_CFB4
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c
--- v2.1.112/linux/drivers/video/fbcon-cfb8.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb8.c	Fri Jul 31 23:19:40 1998
@@ -9,6 +9,7 @@
  *  more details.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/tty.h>
 #include <linux/console.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-cfb8.h linux/drivers/video/fbcon-cfb8.h
--- v2.1.112/linux/drivers/video/fbcon-cfb8.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-cfb8.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  8 bpp packed pixel (cfb8)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_CFB8) || defined(CONFIG_FBCON_CFB8_MODULE)
 #define FBCON_HAS_CFB8
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-ilbm.h linux/drivers/video/fbcon-ilbm.h
--- v2.1.112/linux/drivers/video/fbcon-ilbm.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-ilbm.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  Amiga interleaved bitplanes (ilbm)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_ILBM) || defined(CONFIG_FBCON_ILBM_MODULE)  
 #define FBCON_HAS_ILBM 
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-iplan2p2.h linux/drivers/video/fbcon-iplan2p2.h
--- v2.1.112/linux/drivers/video/fbcon-iplan2p2.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-iplan2p2.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  Atari interleaved bitplanes (2 planes) (iplan2p2)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P2_MODULE)
 #define FBCON_HAS_IPLAN2P2
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-iplan2p4.h linux/drivers/video/fbcon-iplan2p4.h
--- v2.1.112/linux/drivers/video/fbcon-iplan2p4.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-iplan2p4.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  Atari interleaved bitplanes (4 planes) (iplan2p4)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P4) || defined(CONFIG_FBCON_IPLAN2P4_MODULE)
 #define FBCON_HAS_IPLAN2P4
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-iplan2p8.h linux/drivers/video/fbcon-iplan2p8.h
--- v2.1.112/linux/drivers/video/fbcon-iplan2p8.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-iplan2p8.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  Atari interleaved bitplanes (8 planes) (iplan2p8)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_IPLAN2P8) || defined(CONFIG_FBCON_IPLAN2P8_MODULE)
 #define FBCON_HAS_IPLAN2P8
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-mac.h linux/drivers/video/fbcon-mac.h
--- v2.1.112/linux/drivers/video/fbcon-mac.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-mac.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  Mac variable bpp packed pixels (mac)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_MAC) || defined(CONFIG_FBCON_MAC_MODULE)
 #define FBCON_HAS_MAC
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-mfb.h linux/drivers/video/fbcon-mfb.h
--- v2.1.112/linux/drivers/video/fbcon-mfb.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-mfb.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  Monochrome (mfb)
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_MFB_MODULE)
 #define FBCON_HAS_MFB
diff -u --recursive --new-file v2.1.112/linux/drivers/video/fbcon-vga.h linux/drivers/video/fbcon-vga.h
--- v2.1.112/linux/drivers/video/fbcon-vga.h	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/fbcon-vga.h	Fri Jul 31 23:19:40 1998
@@ -2,6 +2,8 @@
      *  VGA characters/attributes
      */
 
+#include <linux/config.h>
+
 #ifdef MODULE
 #if defined(CONFIG_FBCON_VGA) || defined(CONFIG_FBCON_VGA_MODULE)
 #define FBCON_HAS_VGA
diff -u --recursive --new-file v2.1.112/linux/drivers/video/font_acorn_8x8.c linux/drivers/video/font_acorn_8x8.c
--- v2.1.112/linux/drivers/video/font_acorn_8x8.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/font_acorn_8x8.c	Fri Jul 31 23:19:40 1998
@@ -1,5 +1,7 @@
 /* Acorn-like font definition, with PC graphics characters */
 
+#include <linux/config.h>
+
 #include "font.h"
 
 static unsigned char acorndata_8x8[] = {
diff -u --recursive --new-file v2.1.112/linux/drivers/video/macfb.c linux/drivers/video/macfb.c
--- v2.1.112/linux/drivers/video/macfb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/macfb.c	Fri Jul 31 23:19:40 1998
@@ -2,7 +2,6 @@
  *	We've been given MAC frame buffer info by the booter. Now go set it up
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/macmodes.c linux/drivers/video/macmodes.c
--- v2.1.112/linux/drivers/video/macmodes.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/macmodes.c	Fri Jul 31 23:19:40 1998
@@ -8,8 +8,6 @@
  *  more details.
  */
 
-
-#include <linux/config.h>
 #include <linux/tty.h>
 #include <linux/fb.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/promcon.c linux/drivers/video/promcon.c
--- v2.1.112/linux/drivers/video/promcon.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/promcon.c	Fri Jul 31 23:19:40 1998
@@ -5,7 +5,6 @@
  * Copyright (C) 1998  Jakub Jelinek  (jj@ultra.linux.cz)
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c
--- v2.1.112/linux/drivers/video/retz3fb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/retz3fb.c	Fri Jul 31 23:19:40 1998
@@ -20,8 +20,6 @@
  * for more details.
  */
 
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c
--- v2.1.112/linux/drivers/video/skeletonfb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/skeletonfb.c	Fri Jul 31 23:19:40 1998
@@ -8,7 +8,6 @@
  * for more details.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- v2.1.112/linux/drivers/video/tgafb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/tgafb.c	Fri Jul 31 23:19:40 1998
@@ -21,8 +21,6 @@
  *
  * KNOWN PROBLEMS/TO DO ==================================================== */
 
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.1.112/linux/drivers/video/vesafb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/vesafb.c	Fri Jul 31 23:19:40 1998
@@ -8,7 +8,6 @@
  *
  */ 
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/vfb.c linux/drivers/video/vfb.c
--- v2.1.112/linux/drivers/video/vfb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/vfb.c	Fri Jul 31 23:19:40 1998
@@ -8,7 +8,6 @@
  *  more details.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c
--- v2.1.112/linux/drivers/video/vgacon.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/vgacon.c	Fri Jul 31 23:19:40 1998
@@ -33,7 +33,7 @@
  *  more details.
  */
 
-
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- v2.1.112/linux/drivers/video/virgefb.c	Tue Jul 28 14:21:09 1998
+++ linux/drivers/video/virgefb.c	Fri Jul 31 23:19:40 1998
@@ -16,7 +16,6 @@
 
 #undef VIRGEFBDEBUG
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.112/linux/drivers/zorro/Makefile linux/drivers/zorro/Makefile
--- v2.1.112/linux/drivers/zorro/Makefile	Tue Jun 23 10:01:24 1998
+++ linux/drivers/zorro/Makefile	Thu Jul 30 11:10:22 1998
@@ -1,12 +1,32 @@
 #
-# Makefile for the linux/drivers/zorro/ directory.
+# Makefile for the Zorro bus specific drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
 #
 
 SUB_DIRS     :=
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS)
 
-L_OBJS   := zorro.o
 L_TARGET := zorro.a
+
+# Nasty trick as nobody references zorrosyms.o, but we still want it linked.
+ifeq ($(CONFIG_MODULES),y)
+O_TARGET = zorro_syms.o
+OX_OBJS  = zorrosyms.o
+O_OBJS   = zorro.o
+L_OBJS   := zorro_syms.o
+else
+L_OBJS   := zorro.o
+endif
+
+ifdef CONFIG_PROC_FS
+L_OBJS   += proc.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.112/linux/drivers/zorro/proc.c linux/drivers/zorro/proc.c
--- v2.1.112/linux/drivers/zorro/proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/zorro/proc.c	Thu Jul 30 11:10:22 1998
@@ -0,0 +1,167 @@
+/*
+ *	$Id: proc.c,v 1.1.2.1 1998/06/07 23:21:01 geert Exp $
+ *
+ *	Procfs interface for the Zorro bus.
+ *
+ *	Copyright (C) 1998 Geert Uytterhoeven
+ *
+ *	Heavily based on the procfs interface for the PCI bus, which is
+ *
+ *	Copyright (C) 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/types.h>
+#include <linux/zorro.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/amigahw.h>
+#include <asm/setup.h>
+
+static loff_t
+proc_bus_zorro_lseek(struct file *file, loff_t off, int whence)
+{
+	loff_t new;
+
+	switch (whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	case 2:
+		new = sizeof(struct ConfigDev) + off;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (new < 0 || new > sizeof(struct ConfigDev))
+		return -EINVAL;
+	return (file->f_pos = new);
+}
+
+static ssize_t
+proc_bus_zorro_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+	struct inode *ino = file->f_dentry->d_inode;
+	struct proc_dir_entry *dp = ino->u.generic_ip;
+	struct ConfigDev *cd = dp->data;
+	int pos = *ppos;
+
+	if (pos >= sizeof(struct ConfigDev))
+		return 0;
+	if (nbytes >= sizeof(struct ConfigDev))
+		nbytes = sizeof(struct ConfigDev);
+	if (pos + nbytes > sizeof(struct ConfigDev))
+		nbytes = sizeof(struct ConfigDev) - pos;
+	if (copy_to_user(buf, cd, nbytes))
+		return -EFAULT;
+	*ppos += nbytes;
+
+	return nbytes;
+}
+
+static struct file_operations proc_bus_zorro_operations = {
+	proc_bus_zorro_lseek,
+	proc_bus_zorro_read,
+	NULL,		/* write */
+	NULL,		/* readdir */
+	NULL,		/* poll */
+	NULL,		/* ioctl */
+	NULL,		/* mmap */
+	NULL,		/* no special open code */
+	NULL,		/* no special release code */
+	NULL		/* can't fsync */
+};
+
+static struct inode_operations proc_bus_zorro_inode_operations = {
+	&proc_bus_zorro_operations, /* default base directory file-ops */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+int
+get_zorro_dev_info(char *buf, char **start, off_t pos, int count, int wr)
+{
+	u_int slot;
+	off_t at = 0;
+	int len, cnt;
+
+	for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) {
+		struct ConfigDev *cd = &zorro_autocon[slot];
+		u16 manuf = cd->cd_Rom.er_Manufacturer;
+		u8 prod = cd->cd_Rom.er_Product;
+		u8 epc;
+		if (manuf == ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) &&
+		    prod == ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE)) {
+		    /* GVP quirk */
+		    u32 addr = (u32)cd->cd_BoardAddr;
+		    epc = (*(u16 *)ZTWO_VADDR(addr+0x8000)) & GVP_PRODMASK;
+		} else
+		    epc = 0;
+		len = sprintf(buf, "%02x\t%04x%02x%02x\t%08x\t%08x\t%02x\n",
+			      slot, manuf, prod, epc, (u32)cd->cd_BoardAddr,
+			      cd->cd_BoardSize, cd->cd_Rom.er_Type);
+		at += len;
+		if (at >= pos) {
+			if (!*start) {
+				*start = buf + (pos - (at - len));
+				cnt = at - pos;
+			} else
+				cnt += len;
+			buf += len;
+		}
+	}
+	return (count > cnt) ? cnt : count;
+}
+
+static struct proc_dir_entry proc_zorro_devices = {
+	PROC_BUS_ZORRO_DEVICES, 7, "devices",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_array_inode_operations,
+	get_zorro_dev_info
+};
+
+static struct proc_dir_entry *proc_bus_zorro_dir;
+
+__initfunc(static int zorro_proc_attach_device(u_int slot))
+{
+	struct proc_dir_entry *entry;
+	char name[4];
+
+	sprintf(name, "%02x", slot);
+	entry = create_proc_entry(name, S_IFREG | S_IRUGO, proc_bus_zorro_dir);
+	if (!entry)
+		return -ENOMEM;
+	entry->ops = &proc_bus_zorro_inode_operations;
+	entry->data = &zorro_autocon[slot];
+	entry->size = sizeof(struct ConfigDev);
+	return 0;
+}
+
+__initfunc(void zorro_proc_init(void))
+{
+	u_int slot;
+
+	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
+		return;
+	proc_bus_zorro_dir = create_proc_entry("zorro", S_IFDIR, proc_bus);
+	proc_register(proc_bus_zorro_dir, &proc_zorro_devices);
+	for (slot = 0; slot < zorro_num_autocon; slot++)
+	    zorro_proc_attach_device(slot);
+}
diff -u --recursive --new-file v2.1.112/linux/drivers/zorro/zorro.c linux/drivers/zorro/zorro.c
--- v2.1.112/linux/drivers/zorro/zorro.c	Tue Jun 23 10:01:24 1998
+++ linux/drivers/zorro/zorro.c	Thu Jul 30 11:10:22 1998
@@ -1,7 +1,9 @@
 /*
- *    linux/arch/m68k/amiga/zorro.c
+ *    $Id: zorro.c,v 1.1.2.1 1998/06/07 23:21:02 geert Exp $
  *
- *    Copyright (C) 1995 Geert Uytterhoeven
+ *    Zorro Bus Services
+ *
+ *    Copyright (C) 1995-1998 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
@@ -9,892 +11,22 @@
  */
 
 
-#include <linux/config.h>
 #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
-     */
-
-struct Manufacturer {
-    const char *Name;
-    u_short Manuf;
-    u_short NumProd;
-    const struct Product *Products;
-};
-
-struct Product {
-    const char *Name;
-    u_char Class;
-    u_char Prod;
-};
-
-struct GVP_Product {
-    const char *Name;
-    u_char Class;
-    u_char EPC;
-};
-
-
-    /*
-     *  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 MANUF(name, id) \
-    { name, ZORRO_MANUF_##id, ARRAYSIZE(Prod_##id), Prod_##id },
-
-#define END \
-    };
-
-
-    /*
-     *  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(MACROSYSTEMS_USA_2)
-    PROD("Warp Engine", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE)
-END
-
-BEGIN_PROD(KUPKE_1)
-    PROD("Golem RAM Box 2MB", RAM, KUPKE_GOLEM_RAM_BOX_2MB)
-END
-
-BEGIN_PROD(MEMPHIS)
-    PROD("Stormbringer", TURBO, MEMPHIS_STORMBRINGER)
-END
-
-BEGIN_PROD(3_STATE)
-    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(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", VIDEO, A_SQUARED_LIVE_2000)
-END
-
-BEGIN_PROD(COMSPEC_COMMUNICATIONS)
-    PROD("AX2000", RAM, COMSPEC_COMMUNICATIONS_AX2000)
-END
-
-BEGIN_PROD(ANAKIN_RESEARCH)
-    PROD("Easyl", TABLET, ANAKIN_RESEARCH_EASYL)
-END
-
-BEGIN_PROD(MICROBOTICS)
-    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_ASSOCIATES_ALEGRA)
-END
-
-BEGIN_PROD(EXPANSION_TECHNOLOGIES)
-END
-
-BEGIN_PROD(ASDG)
-    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_1)
-    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_1)
-    PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_2)
-END
-
-BEGIN_PROD(CBM_UNIVERSITY_OF_LOWELL)
-    PROD("A2410 HiRes", GFX, CBM_A2410)
-END
-
-BEGIN_PROD(AMERISTAR)
-    PROD("A2065", ETHERNET, AMERISTAR_A2065)
-    PROD("A560", ARCNET, AMERISTAR_A560)
-    PROD("A4066", ETHERNET, AMERISTAR_A4066)
-END
-
-BEGIN_PROD(SUPRA)
-    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(COMPUTER_SYSTEMS_ASSOCIATES)
-    PROD("Magnum 40", TURBO_SCSI, CSA_MAGNUM)
-    PROD("12 Gauge", SCSI, CSA_12_GAUGE)
-END
-
-BEGIN_PROD(MARC_MICHAEL_GROTH)
-END
-
-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", UNKNOWN, BYTEBOX_A500)
-END
-
-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(CALIFORNIA_ACCESS_SYNERGY)
-    PROD("Malibu", SCSI, CALIFORNIA_ACCESS_SYNERGY_MALIBU)
-END
-
-BEGIN_PROD(XETEC)
-    PROD("FastCard", SCSI, XETEC_FASTCARD)
-    PROD("FastCard", RAM, XETEC_FASTCARD_RAM)
-    PROD("FastCard Plus", SCSI, XETEC_FASTCARD_PLUS)
-END
-
-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_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_ALFADATA_1)
-    PROD("ALF 3", SCSI, BSC_ALF_3_1)
-END
-
-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(CARDCO_2)
-    PROD("Kronos", SCSI, CARDCO_KRONOS_2000_2)
-    PROD("A1000", SCSI, CARDCO_A1000_2)
-END
-
-BEGIN_PROD(JOCHHEIM)
-    PROD(NULL, RAM, JOCHHEIM_RAM)
-END
-
-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, 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(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(INTERWORKS_NETWORK)
-END
-
-BEGIN_PROD(HARDITAL_SYNTHESIS)
-    PROD("TQM 68030+68882", TURBO, HARDITAL_SYNTHESIS_TQM_68030_68882)
-END
-
-BEGIN_PROD(APPLIED_ENGINEERING)
-    PROD("DL2000", MODEM, APPLIED_ENGINEERING_DL2000)
-    PROD("RAM Works", RAM, APPLIED_ENGINEERING_RAM_WORKS)
-END
-
-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(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", GFX, IMPULSE_FIRECRACKER_24)
-END
-
-BEGIN_PROD(IVS)
-    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_1)
-    PROD("Connection", MULTIIO, VECTOR_CONNECTION_1)
-END
-
-BEGIN_PROD(XPERT_PRODEV)
-    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", ETHERNET, HYDRA_SYSTEMS_AMIGANET)
-END
-
-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(NULL, MULTIIO, TRICERATOPS_MULTI_IO)
-END
-
-BEGIN_PROD(APPLIED_MAGIC)
-    PROD("DMI Resolver", GFX, APPLIED_MAGIC_DMI_RESOLVER)
-    PROD("Digital Broadcaster", VIDEO, APPLIED_MAGIC_DIGITAL_BROADCASTER)
-END
-
-BEGIN_PROD(GFX_BASE)
-    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", 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(PROTAR)
-END
-
-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("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(MAINHATTAN_DATA)
-    PROD(NULL, IDE, MAINHATTAN_DATA_IDE)
-END
-
-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(NULL, MULTIIO, AMITRIX_MULTI_IO)
-    PROD("CD-RAM", RAM, AMITRIX_CD_RAM)
-END
-
-BEGIN_PROD(ARMAX)
-    PROD("OmniBus", GFX, ARMAX_OMNIBUS)
-END
-
-BEGIN_PROD(ZEUS)
-    PROD("Spider", VIDEO, ZEUS_SPIDER)
-END
-
-BEGIN_PROD(NEWTEK)
-    PROD("VideoToaster", VIDEO, NEWTEK_VIDEOTOASTER)
-END
-
-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(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(APOLLO_1)
-    PROD("A1200", FPU_RAM, APOLLO_A1200)
-END
-
-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(MACROSYSTEMS_USA)
-    PROD("Warp Engine 40xx", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE_40xx)
-END
-
-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, MICRONIK_RCA_120)
-END
-
-BEGIN_PROD(MICRONIK2)
-    PROD("Z3i A1200 Zorro III + SCSI", SCSI, MICRONIK2_Z3I)
-END
-
-BEGIN_PROD(MEGAMICRO)
-    PROD("SCRAM 500", SCSI, MEGAMICRO_SCRAM_500)
-    PROD("SCRAM 500", RAM, MEGAMICRO_SCRAM_500_RAM)
-END
-
-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(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, ITH_ISDN_MASTER_II)
-END
-
-BEGIN_PROD(VMC)
-    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, INFORMATION_ISDN_ENGINE_I)
-END
-
-BEGIN_PROD(VORTEX)
-    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(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", MACEMU, READYSOFT_AMAX_II_IV)
-END
-
-BEGIN_PROD(PHASE5)
-    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)
-    PROD("Blizzard 603e+", TURBO_SCSI, PHASE5_BLIZZARD_603E_PLUS)
-END
-
-BEGIN_PROD(DPS)
-    PROD("Personal Animation Recorder", VIDEO, DPS_PERSONAL_ANIMATION_RECORDER)
-END
-
-BEGIN_PROD(APOLLO_2)
-    PROD("A620 68020", TURBO, APOLLO_A620_68020_1)
-    PROD("A620 68020", TURBO, APOLLO_A620_68020_2)
-END
-
-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_LP)
-    PROD("Delfina", AUDIO, PETSOFF_LP_DELFINA)
-    PROD("Delfina Lite", AUDIO, PETSOFF_LP_DELFINA_LITE)
-END
-
-BEGIN_PROD(UWE_GERLACH)
-    PROD("RAM/ROM", MISC, UWE_GERLACH_RAM_ROM)
-END
-
-BEGIN_PROD(ACT)
-    PROD("Prelude", AUDIO, ACT_PRELUDE)
-END
-
-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_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", SCANNER, CAMERON_PERSONAL_A4)
-END
-
-BEGIN_PROD(REIS_WARE)
-    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_PROD(COMBITEC_2)
-    PROD(NULL, HD, COMBITEC_HD)
-    PROD("SRAM", RAM, COMBITEC_SRAM)
-END
-
-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("ZEUS Electronic Development", ZEUS)
-    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("ACT", ACT)
-    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
      */
 
-u_int zorro_num_autocon;
+u_int zorro_num_autocon = 0;
 struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO];
-static u32 BoardPartFlags[ZORRO_NUM_AUTO] = { 0, };
+static u32 zorro_autocon_parts[ZORRO_NUM_AUTO] = { 0, };
 
    
     /*
@@ -907,7 +39,7 @@
      *
      *  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
+     *  with the GVP boards that use 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.
@@ -923,33 +55,33 @@
 
 u_int zorro_find(zorro_id id, u_int part, u_int index)
 {
-    u_int manuf = ZORRO_MANUF(id);
-    u_int prod = ZORRO_PROD(id);
-    u_int epc = ZORRO_EPC(id);
+    u16 manuf = ZORRO_MANUF(id);
+    u8 prod = ZORRO_PROD(id);
+    u8 epc = ZORRO_EPC(id);
     u_int key;
     const struct ConfigDev *cd;
-    u_long addr;
+    u32 addr;
 
     if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
-	return(0);
+	return 0;
 
     if (part > 31) {
 	printk("zorro_find: bad part %d\n", part);
-	return(0);
+	return 0;
     }
 
-    for (key = index + 1; key <= zorro_num_autocon; key++) {
+    for (key = index+1; key <= zorro_num_autocon; key++) {
 	cd = &zorro_autocon[key-1];
-	addr = (u_long)cd->cd_BoardAddr;
+	addr = (u32)cd->cd_BoardAddr;
 	if ((cd->cd_Rom.er_Manufacturer == manuf) &&
 	    (cd->cd_Rom.er_Product == prod) &&
-	    !(BoardPartFlags[key-1] & (1<<part)) &&
+	    !(zorro_autocon_parts[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;
+	     prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE) || /* GVP quirk */
+	     (*(u16 *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK) == epc))
+	    return key;
     }
-    return(key <= zorro_num_autocon ? key : 0);
+    return 0;
 }
 
 
@@ -959,14 +91,11 @@
 
 const struct ConfigDev *zorro_get_board(u_int key)
 {
-    const struct ConfigDev *cd = NULL;
-
-    if ((key < 1) || (key > zorro_num_autocon))
+    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 NULL;
+    }
+    return &zorro_autocon[key-1];
 }
 
 
@@ -980,11 +109,11 @@
 	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))
+    else if (zorro_autocon_parts[key-1] & (1<<part))
 	printk("zorro_config_board: key %d part %d is already configured\n",
 	       key, part);
     else
-	BoardPartFlags[key-1] |= 1<<part;
+	zorro_autocon_parts[key-1] |= 1<<part;
 }
 
 
@@ -1000,183 +129,13 @@
 	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)))
+    else if (!(zorro_autocon_parts[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).
-     */
-
-static int identify(u_int devnum, char *buf, int verbose)
-{
-    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
-     */
-
-void zorro_identify(void)
-{
-    u_int i;
-    char tmp[256];
-
-    if (!AMIGAHW_PRESENT(ZORRO))
-	return;
-
-    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
-     */
-
-int zorro_get_list(char *buffer)
-{
-    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++) {
-	    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);
+	zorro_autocon_parts[key-1] &= ~(1<<part);
 }
 
-#endif /* CONFIG_ZORRO */
-
 
     /*
      *  Bitmask indicating portions of available Zorro II RAM that are unused
@@ -1194,9 +153,9 @@
 u32 zorro_unused_z2ram[4] = { 0, 0, 0, 0 };
 
 
-static void mark_region(u_long addr, u_long size, int flag)
+__initfunc(static void mark_region(u32 addr, u_int size, int flag))
 {
-    u_long start, end, chunk;
+    u32 start, end;
 
     if (flag) {
 	start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK;
@@ -1210,11 +169,11 @@
     start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START;
     end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START;
     while (start < end) {
-	chunk = start>>Z2RAM_CHUNKSHIFT;
+	u32 chunk = start>>Z2RAM_CHUNKSHIFT;
 	if (flag)
-	    set_bit( chunk, zorro_unused_z2ram );
+	    set_bit(chunk, zorro_unused_z2ram);
 	else
-	    clear_bit( chunk, zorro_unused_z2ram );
+	    clear_bit(chunk, zorro_unused_z2ram);
 	start += Z2RAM_CHUNKSIZE;
     }
 }
@@ -1224,22 +183,47 @@
      *  Initialization
      */
 
-void zorro_init(void)
+__initfunc(void zorro_init(void))
 {
-    u_int i;
-    const struct ConfigDev *cd;
+    u_int i, j;
+    u32 disabled_z2mem = 0;
 
-    if (!AMIGAHW_PRESENT(ZORRO))
+    if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO)) {
+	printk("Zorro: No Zorro bus detected\n");
 	return;
+    }
+
+    printk("Zorro: Probing AutoConfig expansion devices: %d device%s\n",
+	   zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
 
     /* Mark all available Zorro II memory */
     for (i = 0; i < zorro_num_autocon; i++) {
-	cd = &zorro_autocon[i];
+	const struct ConfigDev *cd = &zorro_autocon[i];
 	if (cd->cd_Rom.er_Type & ERTF_MEMLIST)
-	    mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1);
+	    mark_region((u32)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);
+	if (m68k_memory[i].addr < 16*1024*1024) {
+	    if (AMIGAHW_PRESENT(ZORRO3)) {
+		/* don't use Zorro II RAM as system memory on Zorro III */
+		/* capable machines */
+		if (i == 0) {
+		    /* don't cut off the branch we're sitting on */
+		    printk("Warning: kernel runs in Zorro II memory\n");
+		} else {
+		    disabled_z2mem += m68k_memory[i].size;
+		    m68k_num_memory--;
+		    for (j = i; j < m68k_num_memory; j++)
+			m68k_memory[j] = m68k_memory[j+1];
+		    i--;
+		    continue;
+		}
+	    }
+	    mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0);
+	}
+    if (disabled_z2mem)
+	printk("%dK of Zorro II memory will not be used as system memory\n",
+	       disabled_z2mem>>10);
 }
diff -u --recursive --new-file v2.1.112/linux/drivers/zorro/zorrosyms.c linux/drivers/zorro/zorrosyms.c
--- v2.1.112/linux/drivers/zorro/zorrosyms.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/zorro/zorrosyms.c	Thu Jul 30 11:10:22 1998
@@ -0,0 +1,23 @@
+/*
+ *	$Id: zorrosyms.c,v 1.1.2.1 1998/06/07 23:21:02 geert Exp $
+ *
+ *	Zorro Bus Services -- Exported Symbols
+ *
+ *	Copyright (C) 1998 Geert Uytterhoeven
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/zorro.h>
+
+    /* Board configuration */
+
+EXPORT_SYMBOL(zorro_find);
+EXPORT_SYMBOL(zorro_get_board);
+EXPORT_SYMBOL(zorro_config_board);
+EXPORT_SYMBOL(zorro_unconfig_board);
+
+    /* Z2 memory */
+
+EXPORT_SYMBOL(zorro_unused_z2ram);
+
diff -u --recursive --new-file v2.1.112/linux/fs/coda/dir.c linux/fs/coda/dir.c
--- v2.1.112/linux/fs/coda/dir.c	Thu Jul 16 18:09:28 1998
+++ linux/fs/coda/dir.c	Fri Jul 31 16:22:12 1998
@@ -578,7 +578,7 @@
 	struct inode *old_inode = old_dentry->d_inode;
 	struct inode *new_inode = new_dentry->d_inode;
         struct coda_inode_info *new_cnp, *old_cnp;
-        int error, rehash = 0, update = 1;
+        int error;
 
 	ENTRY;
 	coda_vfs_stat.rename++;
@@ -598,8 +598,6 @@
 	if (new_inode == old_inode)
 		return 0;
 
-	if (new_dir == old_dir)
-		goto do_rename;
 	/* make sure target is not in use */
 	if (new_inode && S_ISDIR(new_inode->i_mode)) { 
 		/*
@@ -612,38 +610,11 @@
                         return -EBUSY;
         }
 
+	/* the C library will do unlink/create etc */
 	if ( coda_crossvol_rename == 0 && 
 	     old_cnp->c_fid.Volume != new_cnp->c_fid.Volume )
 		return -EXDEV;
 
-	/* if the volumeid are the same we can reuse the inode,
-	   otherwise we need a new inode, since the new file 
-	   will have a new inode number. */
-
-	/* if moving a directory, clean the dcache */
-	if (S_ISDIR(old_inode->i_mode) && old_dentry->d_count > 1) 
-		shrink_dcache_parent(old_dentry);
-
-#if 0
-	if (old_dentry->d_count > 1) {
-		return -EBUSY;
-	}
-#endif
-
-	if (new_dentry->d_count > 1) {
-		return -EBUSY;
-	}
-	d_drop(old_dentry);
-	update = 0;
-
- do_rename:
-	if (!list_empty(&new_dentry->d_hash)) {
-		d_drop(new_dentry);
-		rehash = update;
-	}
-	if ( new_inode ) 
-		d_delete(new_dentry);
-
         error = venus_rename(old_dir->i_sb, &(old_cnp->c_fid), 
 			     &(new_cnp->c_fid), old_length, new_length, 
 			     (const char *) old_name, (const char *)new_name);
@@ -652,14 +623,13 @@
                 CDEBUG(D_INODE, "returned error %d\n", error);
                 return error;
         }
-	/* Update the dcache if needed */
-	if (rehash) {
-		d_add(new_dentry, NULL);
-	}
-	if (update)
-	        d_move(old_dentry, new_dentry);
-	
-        CDEBUG(D_INODE, "result %d\n", error); 
+
+	coda_flag_inode(new_inode, C_VATTR);
+	coda_flag_inode(old_dir, C_VATTR);
+	coda_flag_inode(new_dir, C_VATTR);
+
+	CDEBUG(D_INODE, "result %d\n", error); 
+	d_move(old_dentry, new_dentry);
 
 	EXIT;
 	return 0;
diff -u --recursive --new-file v2.1.112/linux/fs/coda/upcall.c linux/fs/coda/upcall.c
--- v2.1.112/linux/fs/coda/upcall.c	Tue Jul 21 00:15:32 1998
+++ linux/fs/coda/upcall.c	Fri Jul 31 16:22:12 1998
@@ -897,6 +897,7 @@
 		  inode = coda_fid_to_inode(fid, sb);
 		  if ( inode ) { 
 			  CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n", inode->i_ino);
+			  coda_purge_children(inode);
                           coda_purge_dentries(inode);
 		  }else 
 			  CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
diff -u --recursive --new-file v2.1.112/linux/fs/devices.c linux/fs/devices.c
--- v2.1.112/linux/fs/devices.c	Tue Mar 17 22:18:15 1998
+++ linux/fs/devices.c	Fri Jul 31 17:42:33 1998
@@ -49,13 +49,13 @@
 	len = sprintf(page, "Character devices:\n");
 	for (i = 0; i < MAX_CHRDEV ; i++) {
 		if (chrdevs[i].fops) {
-			len += sprintf(page+len, "%2d %s\n", i, chrdevs[i].name);
+			len += sprintf(page+len, "%3d %s\n", i, chrdevs[i].name);
 		}
 	}
 	len += sprintf(page+len, "\nBlock devices:\n");
 	for (i = 0; i < MAX_BLKDEV ; i++) {
 		if (blkdevs[i].fops) {
-			len += sprintf(page+len, "%2d %s\n", i, blkdevs[i].name);
+			len += sprintf(page+len, "%3d %s\n", i, blkdevs[i].name);
 		}
 	}
 	return len;
diff -u --recursive --new-file v2.1.112/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.1.112/linux/fs/filesystems.c	Wed Jun 24 22:54:08 1998
+++ linux/fs/filesystems.c	Fri Jul 31 16:22:13 1998
@@ -39,7 +39,7 @@
 #include <linux/nls.h>
 
 #ifdef CONFIG_CODA_FS
-extern int init_coda_fs(void);
+extern int init_coda(void);
 #endif
 
 #ifdef CONFIG_DEVPTS_FS
@@ -97,7 +97,7 @@
 #endif
 
 #ifdef CONFIG_CODA_FS
-	init_coda_fs();
+	init_coda();
 #endif
 
 #ifdef CONFIG_SMB_FS
diff -u --recursive --new-file v2.1.112/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.112/linux/fs/proc/array.c	Sun Jul 26 11:57:18 1998
+++ linux/fs/proc/array.c	Thu Jul 30 11:10:24 1998
@@ -1201,12 +1201,8 @@
 extern int get_rtc_status (char *);
 extern int get_locks_status (char *, char **, off_t, int);
 extern int get_swaparea_info (char *);
-#ifdef CONFIG_ZORRO
-extern int zorro_get_list(char *);
-#endif
-#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
 extern int get_hardware_list(char *);
-#endif
+extern int get_stram_list(char *);
 
 static long get_root_array(char * page, int type, char **start,
 	off_t offset, unsigned long length)
@@ -1283,13 +1279,13 @@
 #endif
 		case PROC_LOCKS:
 			return get_locks_status(page, start, offset, length);
-#ifdef CONFIG_ZORRO
-		case PROC_ZORRO:
-			return zorro_get_list(page);
-#endif
-#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+#ifdef CONFIG_PROC_HARDWARE
 		case PROC_HARDWARE:
 			return get_hardware_list(page);
+#endif
+#ifdef CONFIG_STRAM_PROC
+		case PROC_STRAM:
+			return get_stram_list(page);
 #endif
 	}
 	return -EBADF;
diff -u --recursive --new-file v2.1.112/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.112/linux/fs/proc/root.c	Sun Jul 26 11:57:18 1998
+++ linux/fs/proc/root.c	Thu Jul 30 11:10:24 1998
@@ -18,6 +18,9 @@
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
+#ifdef CONFIG_ZORRO
+#include <linux/zorro.h>
+#endif
 
 /*
  * Offset of the first process in the /proc root directory..
@@ -499,25 +502,25 @@
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_array_inode_operations
 };
-#ifdef CONFIG_ZORRO
-static struct proc_dir_entry proc_root_zorro = {
-	PROC_ZORRO, 5, "zorro",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, &proc_array_inode_operations
-};
-#endif
 static struct proc_dir_entry proc_root_cpuinfo = {
 	PROC_CPUINFO, 7, "cpuinfo",
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_array_inode_operations
 };
-#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+#if defined (CONFIG_PROC_HARDWARE)
 static struct proc_dir_entry proc_root_hardware = {
 	PROC_HARDWARE, 8, "hardware",
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_array_inode_operations
 };
 #endif
+#ifdef CONFIG_STRAM_PROC
+static struct proc_dir_entry proc_root_stram = {
+	PROC_STRAM, 5, "stram",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_array_inode_operations
+};
+#endif
 static struct proc_dir_entry proc_root_self = {
 	PROC_SELF, 4, "self",
 	S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
@@ -641,9 +644,6 @@
 	proc_register(&proc_root, &proc_root_meminfo);
 	proc_register(&proc_root, &proc_root_kmsg);
 	proc_register(&proc_root, &proc_root_version);
-#ifdef CONFIG_ZORRO
-	proc_register(&proc_root, &proc_root_zorro);
-#endif
 	proc_register(&proc_root, &proc_root_cpuinfo);
 	proc_register(&proc_root, &proc_root_self);
 	proc_net = create_proc_entry("net", S_IFDIR, 0);
@@ -687,8 +687,11 @@
 #endif
 	proc_register(&proc_root, &proc_openprom);
 #endif
-#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+#ifdef CONFIG_PROC_HARDWARE
 	proc_register(&proc_root, &proc_root_hardware);
+#endif
+#ifdef CONFIG_STRAM_PROC
+	proc_register(&proc_root, &proc_root_stram);
 #endif
 	proc_register(&proc_root, &proc_root_slab);
 
diff -u --recursive --new-file v2.1.112/linux/include/asm-i386/debugreg.h linux/include/asm-i386/debugreg.h
--- v2.1.112/linux/include/asm-i386/debugreg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/debugreg.h	Fri Jul 31 12:53:37 1998
@@ -0,0 +1,64 @@
+#ifndef _I386_DEBUGREG_H
+#define _I386_DEBUGREG_H
+
+
+/* Indicate the register numbers for a number of the specific
+   debug registers.  Registers 0-3 contain the addresses we wish to trap on */
+#define DR_FIRSTADDR 0        /* u_debugreg[DR_FIRSTADDR] */
+#define DR_LASTADDR 3         /* u_debugreg[DR_LASTADDR]  */
+
+#define DR_STATUS 6           /* u_debugreg[DR_STATUS]     */
+#define DR_CONTROL 7          /* u_debugreg[DR_CONTROL] */
+
+/* Define a few things for the status register.  We can use this to determine
+   which debugging register was responsible for the trap.  The other bits
+   are either reserved or not of interest to us. */
+
+#define DR_TRAP0	(0x1)		/* db0 */
+#define DR_TRAP1	(0x2)		/* db1 */
+#define DR_TRAP2	(0x4)		/* db2 */
+#define DR_TRAP3	(0x8)		/* db3 */
+
+#define DR_STEP		(0x4000)	/* single-step */
+#define DR_SWITCH	(0x8000)	/* task switch */
+
+/* Now define a bunch of things for manipulating the control register.
+   The top two bytes of the control register consist of 4 fields of 4
+   bits - each field corresponds to one of the four debug registers,
+   and indicates what types of access we trap on, and how large the data
+   field is that we are looking at */
+
+#define DR_CONTROL_SHIFT 16 /* Skip this many bits in ctl register */
+#define DR_CONTROL_SIZE 4   /* 4 control bits per register */
+
+#define DR_RW_EXECUTE (0x0)   /* Settings for the access types to trap on */
+#define DR_RW_WRITE (0x1)
+#define DR_RW_READ (0x3)
+
+#define DR_LEN_1 (0x0) /* Settings for data length to trap on */
+#define DR_LEN_2 (0x4)
+#define DR_LEN_4 (0xC)
+
+/* The low byte to the control register determine which registers are
+   enabled.  There are 4 fields of two bits.  One bit is "local", meaning
+   that the processor will reset the bit after a task switch and the other
+   is global meaning that we have to explicitly reset the bit.  With linux,
+   you can use either one, since we explicitly zero the register when we enter
+   kernel mode. */
+
+#define DR_LOCAL_ENABLE_SHIFT 0    /* Extra shift to the local enable bit */
+#define DR_GLOBAL_ENABLE_SHIFT 1   /* Extra shift to the global enable bit */
+#define DR_ENABLE_SIZE 2           /* 2 enable bits per register */
+
+#define DR_LOCAL_ENABLE_MASK (0x55)  /* Set  local bits for all 4 regs */
+#define DR_GLOBAL_ENABLE_MASK (0xAA) /* Set global bits for all 4 regs */
+
+/* The second byte to the control register has a few special things.
+   We can slow the instruction pipeline for instructions coming via the
+   gdt or the ldt if we want to.  I am not sure why this is an advantage */
+
+#define DR_CONTROL_RESERVED (0xFC00) /* Reserved by Intel */
+#define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
+#define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
+
+#endif
diff -u --recursive --new-file v2.1.112/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h
--- v2.1.112/linux/include/asm-i386/hardirq.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-i386/hardirq.h	Fri Jul 31 23:22:53 1998
@@ -9,7 +9,8 @@
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
  */
-#define in_interrupt() (local_irq_count[smp_processor_id()] + local_bh_count[smp_processor_id()] != 0)
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+	(local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
 
 #ifndef __SMP__
 
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/amigayle.h linux/include/asm-m68k/amigayle.h
--- v2.1.112/linux/include/asm-m68k/amigayle.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/amigayle.h	Thu Jul 30 11:08:20 1998
@@ -0,0 +1,105 @@
+/*
+** asm-m68k/amigayle.h -- This header defines the registers of the gayle chip
+**                        found on the Amiga 1200
+**                        This information was found by disassembling card.resource,
+**                        so the definitions may not be 100% correct
+**                        anyone has an official doc ?
+**
+** Copyright 1997 by Alain Malek
+**
+** 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.
+**
+** Created: 11/28/97 by Alain Malek
+*/
+
+#ifndef _M68K_AMIGAYLE_H_
+#define _M68K_AMIGAYLE_H_
+
+#include <asm/amigahw.h>
+#include <asm/io.h>
+
+/* memory layout */
+
+#define GAYLE_RAM		(0x600000+zTwoBase)
+#define GAYLE_RAMSIZE		(0x400000)
+#define GAYLE_ATTRIBUTE		(0xa00000+zTwoBase)
+#define GAYLE_ATTRIBUTESIZE	(0x020000)
+#define GAYLE_IO		(0xa20000+zTwoBase)	/* 16bit and even 8bit registers */
+#define GAYLE_IOSIZE		(0x010000)
+#define GAYLE_IO_8BITODD	(0xa30000+zTwoBase)	/* odd 8bit registers */
+
+/* offset for accessing odd IO registers */
+#define GAYLE_ODD		(GAYLE_IO_8BITODD-GAYLE_IO-1)
+
+/* GAYLE registers */
+
+struct GAYLE {
+	u_char cardstatus;
+	u_char pad0[0x1000-1];
+
+	u_char intreq;
+	u_char pad1[0x1000-1];
+
+	u_char inten;
+	u_char pad2[0x1000-1];
+
+	u_char config;
+	u_char pad3[0x1000-1];
+};
+
+#define GAYLE_ADDRESS	(0xda8000)	/* gayle main registers base address */
+
+#define GAYLE_RESET	(0xa40000)	/* write 0x00 to start reset,
+                                           read 1 byte to stop reset */
+
+#define gayle (*(volatile struct GAYLE *)(zTwoBase+GAYLE_ADDRESS))
+#define gayle_reset (*(volatile u_char *)(zTwoBase+GAYLE_RESET))
+
+#define gayle_attribute ((volatile u_char *)(GAYLE_ATTRIBUTE))
+
+#define gayle_inb(a) readb( GAYLE_IO+(a)+(((a)&1)*GAYLE_ODD) )
+#define gayle_outb(v,a) writeb( v, GAYLE_IO+(a)+(((a)&1)*GAYLE_ODD) )
+
+#define gayle_inw(a) readw( GAYLE_IO+(a) )
+#define gayle_outw(v,a) writew( v, GAYLE_IO+(a) )
+
+/* GAYLE_CARDSTATUS bit def */
+
+#define GAYLE_CS_CCDET		0x40	/* credit card detect */
+#define GAYLE_CS_BVD1		0x20	/* battery voltage detect 1 */
+#define GAYLE_CS_SC		0x20	/* credit card status change */
+#define GAYLE_CS_BVD2		0x10	/* battery voltage detect 2 */
+#define GAYLE_CS_DA		0x10	/* digital audio */
+#define GAYLE_CS_WR		0x08	/* write enable (1 == enabled) */
+#define GAYLE_CS_BSY		0x04	/* credit card busy */
+#define GAYLE_CS_IRQ		0x04	/* interrupt request */
+
+/* GAYLE_IRQ bit def */
+
+#define GAYLE_IRQ_IDE		0x80
+#define GAYLE_IRQ_CCDET		0x40
+#define GAYLE_IRQ_BVD1		0x20
+#define GAYLE_IRQ_SC		0x20
+#define GAYLE_IRQ_BVD2		0x10
+#define GAYLE_IRQ_DA		0x10
+#define GAYLE_IRQ_WR		0x08
+#define GAYLE_IRQ_BSY		0x04
+#define GAYLE_IRQ_IRQ		0x04
+#define GAYLE_IRQ_IDEACK1	0x02
+#define GAYLE_IRQ_IDEACK0	0x01
+
+/* GAYLE_CONFIG bit def
+   (bit 0-1 for program voltage, bit 2-3 for access speed */
+
+#define GAYLE_CFG_0V		0x00
+#define GAYLE_CFG_5V		0x01
+#define GAYLE_CFG_12V		0x02
+
+#define GAYLE_CFG_100NS		0x08
+#define GAYLE_CFG_150NS		0x04
+#define GAYLE_CFG_250NS		0x00
+#define GAYLE_CFG_720NS		0x0c
+
+#endif /* asm-m68k/amigayle.h */
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/amipcmcia.h linux/include/asm-m68k/amipcmcia.h
--- v2.1.112/linux/include/asm-m68k/amipcmcia.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/amipcmcia.h	Thu Jul 30 11:08:20 1998
@@ -0,0 +1,110 @@
+/*
+** asm-m68k/pcmcia.h -- Amiga Linux PCMCIA Definitions
+**
+** Copyright 1997 by Alain Malek
+**
+** 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.
+**
+** Created: 12/10/97 by Alain Malek
+*/
+
+#ifndef __AMIGA_PCMCIA_H__
+#define __AMIGA_PCMCIA_H__
+
+#include <asm/amigayle.h>
+
+/* prototypes */
+
+void pcmcia_reset(void);
+int pcmcia_copy_tuple(unsigned char tuple_id, void *tuple, int max_len);
+void pcmcia_program_voltage(int voltage);
+void pcmcia_access_speed(int speed);
+void pcmcia_write_enable(void);
+void pcmcia_write_disable(void);
+
+static inline u_char pcmcia_read_status(void)
+{
+	return (gayle.cardstatus & 0x7c);
+}
+
+static inline u_char pcmcia_get_intreq(void)
+{
+	return (gayle.intreq);
+}
+
+static inline void pcmcia_ack_int(u_char intreq)
+{
+	gayle.intreq = ((intreq & 0x2c) ^ 0x2c) | 0xc0;
+}
+
+static inline void pcmcia_enable_irq(void)
+{
+	gayle.inten = GAYLE_IRQ_IDE|GAYLE_IRQ_IRQ;
+}
+
+static inline void pcmcia_disable_irq(void)
+{
+	gayle.inten = GAYLE_IRQ_IDE;
+}
+
+#define PCMCIA_INSERTED	(gayle.cardstatus & GAYLE_CS_CCDET)
+
+/* valid voltages for pcmcia_ProgramVoltage */
+
+#define PCMCIA_0V	0
+#define PCMCIA_5V	5
+#define PCMCIA_12V	12
+
+/* valid speeds for pcmcia_AccessSpeed */
+
+#define PCMCIA_SPEED_100NS	100
+#define PCMCIA_SPEED_150NS	150
+#define PCMCIA_SPEED_250NS	250
+#define PCMCIA_SPEED_720NS	720
+
+/* PCMCIA Tuple codes */
+
+#define CISTPL_NULL		0x00
+#define CISTPL_DEVICE		0x01
+#define CISTPL_LONGLINK_CB	0x02
+#define CISTPL_CONFIG_CB	0x04
+#define CISTPL_CFTABLE_ENTRY_CB	0x05
+#define CISTPL_LONGLINK_MFC	0x06
+#define CISTPL_BAR		0x07
+#define CISTPL_CHECKSUM		0x10
+#define CISTPL_LONGLINK_A	0x11
+#define CISTPL_LONGLINK_C	0x12
+#define CISTPL_LINKTARGET	0x13
+#define CISTPL_NO_LINK		0x14
+#define CISTPL_VERS_1		0x15
+#define CISTPL_ALTSTR		0x16
+#define CISTPL_DEVICE_A		0x17
+#define CISTPL_JEDEC_C		0x18
+#define CISTPL_JEDEC_A		0x19
+#define CISTPL_CONFIG		0x1a
+#define CISTPL_CFTABLE_ENTRY	0x1b
+#define CISTPL_DEVICE_OC	0x1c
+#define CISTPL_DEVICE_OA	0x1d
+#define CISTPL_DEVICE_GEO	0x1e
+#define CISTPL_DEVICE_GEO_A	0x1f
+#define CISTPL_MANFID		0x20
+#define CISTPL_FUNCID		0x21
+#define CISTPL_FUNCE		0x22
+#define CISTPL_SWIL		0x23
+#define CISTPL_END		0xff
+
+/* FUNCID */
+
+#define CISTPL_FUNCID_MULTI	0x00
+#define CISTPL_FUNCID_MEMORY	0x01
+#define CISTPL_FUNCID_SERIAL	0x02
+#define CISTPL_FUNCID_PARALLEL	0x03
+#define CISTPL_FUNCID_FIXED	0x04
+#define CISTPL_FUNCID_VIDEO	0x05
+#define CISTPL_FUNCID_NETWORK	0x06
+#define CISTPL_FUNCID_AIMS	0x07
+#define CISTPL_FUNCID_SCSI	0x08
+
+#endif
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/bitops.h linux/include/asm-m68k/bitops.h
--- v2.1.112/linux/include/asm-m68k/bitops.h	Tue Jul 21 00:15:33 1998
+++ linux/include/asm-m68k/bitops.h	Thu Jul 30 11:08:20 1998
@@ -229,6 +229,30 @@
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int ffs(int x)
+{
+	int cnt;
+
+	asm ("bfffo %1{#0:#0}" : "=d" (cnt) : "dm" (x & -x));
+
+	return 32 - cnt;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
 #endif /* __KERNEL__ */
 
 /* Bitmap functions for the minix filesystem */
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h
--- v2.1.112/linux/include/asm-m68k/entry.h	Tue Jun 23 10:01:28 1998
+++ linux/include/asm-m68k/entry.h	Thu Jul 30 11:08:20 1998
@@ -45,6 +45,7 @@
 LTASK_SIGPENDING =  8
 LTASK_ADDRLIMIT	 = 12
 LTASK_EXECDOMAIN = 16
+LTASK_NEEDRESCHED = 20
 
 LTSS_KSP	= 0
 LTSS_USP	= 4
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/kgdb.h linux/include/asm-m68k/kgdb.h
--- v2.1.112/linux/include/asm-m68k/kgdb.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/kgdb.h	Thu Jul 30 11:08:20 1998
@@ -0,0 +1,83 @@
+/*
+ *  include/asm-m68k/kgdb.h
+ *
+ *  Copyright (C) 1996 Roman Hodek
+ */
+
+#ifndef __ASM_M68k_KGDB_H
+#define __ASM_M68k_KGDB_H
+
+/*
+ * Structure to save all register values in, already in the order gdb wants
+ * it. Note that the upper half of the SR field is recycled for the FORMAT and
+ * VECTOR fields. Hope that doesn't confuse gdb... That upper half is ignored
+ * on exiting the stub, so gdb can modify it as it likes.
+ */
+
+#define GDBREG_A6	14
+#define GDBREG_A7	15
+#define GDBREG_SP	15
+#define GDBREG_SR	16
+#define GDBREG_PC	17
+#define GDBREG_FP0	18
+#define GDBREG_FP7	25
+#define GDBREG_FPCR	26
+#define GDBREG_FPIAR 28
+
+#define GDBOFFA_D6	(6*4)
+#define GDBOFFA_A3	(11*4)
+
+#define NUMREGSBYTES	180
+
+#ifndef __ASSEMBLY__
+
+struct gdb_regs {
+    long		   regs[16];		/* d0-a7 */
+    unsigned	   format :  4; 	/* frame format specifier */
+    unsigned	   vector : 12; 	/* vector offset */
+    unsigned short sr;				/* status register */
+    unsigned long  pc;				/* program counter */
+	unsigned long  fpregs[8*3];		/* fp0-fp7 */
+	unsigned long  fpcntl[3];		/* fpcr, fpsr, fpiar */
+};
+
+extern struct gdb_regs kgdb_registers;
+extern void kgdb_init( void );
+struct frame;
+extern asmlinkage void enter_kgdb( struct pt_regs *fp );
+
+extern int kgdb_initialized;
+
+/*
+ * This function will generate a breakpoint exception.  It is used at the
+ * beginning of a program to sync up with a debugger and can be used
+ * otherwise as a quick means to stop program execution and "break" into
+ * the debugger.
+ */
+extern inline void breakpoint( void )
+{
+	if (!kgdb_initialized)
+		/* if kgdb not inited, do nothing */
+		return;
+	
+	/* breakpoint instruction is TRAP #15 */
+	__asm__ __volatile__ ( "trap #15" );
+}
+
+/*
+ * This function will report a SIGABORT to gdb.
+ */
+extern inline void kgdb_abort( void )
+{
+	if (!kgdb_initialized)
+		/* if kgdb not inited, do nothing */
+		return;
+	
+	/* TRAP #14 is reported as SIGABORT */
+	__asm__ __volatile__ ( "trap #14" );
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_M68k_KGDB_H */
+
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h
--- v2.1.112/linux/include/asm-m68k/machdep.h	Tue Feb 17 13:12:49 1998
+++ linux/include/asm-m68k/machdep.h	Thu Jul 30 11:08:20 1998
@@ -13,6 +13,7 @@
 extern int (*mach_keyb_init) (void);
 extern int (*mach_kbdrate) (struct kbd_repeat *);
 extern void (*mach_kbd_leds) (unsigned int);
+extern void (*kbd_reset_setup) (char *, int);
 /* machine dependent irq functions */
 extern void (*mach_init_IRQ) (void);
 extern void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.1.112/linux/include/asm-m68k/pgtable.h	Wed Jul  1 19:38:56 1998
+++ linux/include/asm-m68k/pgtable.h	Thu Jul 30 11:08:20 1998
@@ -5,8 +5,8 @@
 #include <asm/setup.h>
 
 #ifndef __ASSEMBLY__
-
-#include <asm/processor.h>	/* For TASK_SIZE */
+#include <asm/processor.h>
+#include <linux/tasks.h>
 
 /*
  * This file contains the functions and defines necessary to modify and use
@@ -266,7 +266,7 @@
 #define PTRS_PER_PTE	1024
 #define PTRS_PER_PMD	8
 #define PTRS_PER_PGD	128
-#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
+#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
 
 /* the no. of pointers that fit on a page: this will go away */
 #define PTRS_PER_PAGE	(PAGE_SIZE/sizeof(void*))
@@ -283,6 +283,10 @@
 typedef pmd_table pmd_tablepage[PMD_TABLES_PER_PAGE];
 typedef pte_table pte_tablepage[PTE_TABLES_PER_PAGE];
 
+/* Virtual address region for use by kernel_map() */
+#define	KMAP_START	0xd0000000
+#define	KMAP_END	0xf0000000
+
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 8MB value just means that there will be a 8MB "hole" after the
  * physical memory until the kernel virtual memory starts.  That means that
@@ -293,6 +297,7 @@
 #define VMALLOC_OFFSET	(8*1024*1024)
 #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END KMAP_START
 
 #endif /* __ASSEMBLY__ */
 
@@ -599,86 +604,106 @@
 }
 
 extern struct pgtable_cache_struct {
+	unsigned long *pmd_cache;
 	unsigned long *pte_cache;
+/* This counts in units of pointer tables, of which can be eight per page. */
 	unsigned long pgtable_cache_sz;
 } quicklists;
+
 #define pgd_quicklist ((unsigned long *)0)
-#define pmd_quicklist ((unsigned long *)0)
+#define pmd_quicklist (quicklists.pmd_cache)
 #define pte_quicklist (quicklists.pte_cache)
-#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+/* This isn't accurate because of fragmentation of allocated pages for
+   pointer tables, but that should not be a problem. */
+#define pgtable_cache_size ((quicklists.pgtable_cache_sz+7)/8)
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset);
+extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset);
+
+extern pmd_t *get_pointer_table(void);
+extern void free_pointer_table(pmd_t *);
+extern pmd_t *get_kpointer_table(void);
+extern void free_kpointer_table(pmd_t *);
 
-/* We don't use pgd cache yet, so this is a dummy routine */
-extern __inline__ pgd_t *get_pgd_fast(void)
+extern __inline__ pte_t *get_pte_fast(void)
 {
-	return (pgd_t *)0;
+	unsigned long *ret;
+
+	ret = pte_quicklist;
+	if (ret) {
+		pte_quicklist = (unsigned long *)*ret;
+		ret[0] = ret[1];
+		quicklists.pgtable_cache_sz -= 8;
+	}
+	return (pte_t *)ret;
 }
 
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
+extern __inline__ void free_pte_fast(pte_t *pte)
 {
+	*(unsigned long *)pte = (unsigned long)pte_quicklist;
+	pte_quicklist = (unsigned long *)pte;
+	quicklists.pgtable_cache_sz += 8;
 }
 
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+extern __inline__ void free_pte_slow(pte_t *pte)
 {
+	cache_page((unsigned long)pte);
+	free_page((unsigned long) pte);
 }
 
-/* We don't use pmd cache yet, so this is a dummy routine */
 extern __inline__ pmd_t *get_pmd_fast(void)
 {
-	return (pmd_t *)0;
+	unsigned long *ret;
+
+	ret = pmd_quicklist;
+	if (ret) {
+		pmd_quicklist = (unsigned long *)*ret;
+		ret[0] = ret[1];
+		quicklists.pgtable_cache_sz--;
+	}
+	return (pmd_t *)ret;
 }
 
 extern __inline__ void free_pmd_fast(pmd_t *pmd)
 {
+	*(unsigned long *)pmd = (unsigned long)pmd_quicklist;
+	pmd_quicklist = (unsigned long *) pmd;
+	quicklists.pgtable_cache_sz++;
 }
 
 extern __inline__ void free_pmd_slow(pmd_t *pmd)
 {
+	free_pointer_table(pmd);
 }
 
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-
-extern __inline__ pte_t *get_pte_fast(void)
+/* The pgd cache is folded into the pmd cache, so these are dummy routines. */
+extern __inline__ pgd_t *get_pgd_fast(void)
 {
-        unsigned long *ret;
-
-        if((ret = (unsigned long *)pte_quicklist) != NULL) {
-                pte_quicklist = (unsigned long *)(*ret);
-                ret[0] = ret[1];
-                pgtable_cache_size--;
-        }
-        return (pte_t *)ret;
+	return (pgd_t *)0;
 }
 
-extern __inline__ void free_pte_fast(pte_t *pte)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
-        *(unsigned long *)pte = (unsigned long) pte_quicklist;
-        pte_quicklist = (unsigned long *) pte;
-        pgtable_cache_size++;
 }
 
-extern __inline__ void free_pte_slow(pte_t *pte)
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-	cache_page((unsigned long)pte);
-	free_page((unsigned long)pte);
 }
 
 extern void __bad_pte(pmd_t *pmd);
+extern void __bad_pmd(pgd_t *pgd);
 
-extern const char PgtabStr_bad_pmd[];
-extern const char PgtabStr_bad_pgd[];
-extern const char PgtabStr_bad_pmdk[];
-extern const char PgtabStr_bad_pgdk[];
-
-#define pte_free		free_pte_fast
-#define pte_free_kernel		free_pte_fast
-#define pte_alloc_kernel	pte_alloc
+extern inline void pte_free(pte_t * pte)
+{
+	free_pte_fast(pte);
+}
 
 extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
 	if (pmd_none(*pmd)) {
-		pte_t * page = (pte_t *)get_pte_fast();
-		
+		pte_t * page = get_pte_fast();
+
 		if (!page)
 			return get_pte_slow(pmd, address);
 		pmd_set(pmd,page);
@@ -691,39 +716,39 @@
 	return (pte_t *) pmd_page(*pmd) + address;
 }
 
-extern pmd_t *get_pointer_table (void);
-extern void free_pointer_table (pmd_t *);
-extern pmd_t *get_kpointer_table (void);
-extern void free_kpointer_table (pmd_t *);
-
 extern inline void pmd_free(pmd_t * pmd)
 {
-	free_pointer_table (pmd);
+	free_pmd_fast(pmd);
 }
 
 extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
 {
 	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
 	if (pgd_none(*pgd)) {
-		pmd_t *page = get_pointer_table();
-		if (pgd_none(*pgd)) {
-			if (page) {
-				pgd_set(pgd, page);
-				return page + address;
-			}
-			pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
-			return NULL;
-		}
-		free_pointer_table(page);
+		pmd_t *page = get_pmd_fast();
+
+		if (!page)
+			return get_pmd_slow(pgd, address);
+		pgd_set(pgd, page);
+		return page + address;
 	}
 	if (pgd_bad(*pgd)) {
-		printk(PgtabStr_bad_pgd, pgd_val(*pgd));
-		pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
+		__bad_pmd(pgd);
 		return NULL;
 	}
 	return (pmd_t *) pgd_page(*pgd) + address;
 }
 
+extern inline void pte_free_kernel(pte_t * pte)
+{
+	free_pte_fast(pte);
+}
+
+extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+{
+	return pte_alloc(pmd, address);
+}
+
 extern inline void pmd_free_kernel(pmd_t * pmd)
 {
 	free_kpointer_table(pmd);
@@ -745,8 +770,7 @@
 		free_kpointer_table(page);
 	}
 	if (pgd_bad(*pgd)) {
-		printk(PgtabStr_bad_pgdk, pgd_val(*pgd));
-		pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
+		__bad_pmd(pgd);
 		return NULL;
 	}
 	return (pmd_t *) pgd_page(*pgd) + address;
@@ -754,26 +778,19 @@
 
 extern inline void pgd_free(pgd_t * pgd)
 {
-	free_pointer_table ((pmd_t *) pgd);
+	free_pmd_fast((pmd_t *)pgd);
 }
 
 extern inline pgd_t * pgd_alloc(void)
 {
-	pgd_t *ret = (pgd_t *)get_pointer_table ();
-	
-	if (ret) {
-		pgd_t * init;
-
-		init = pgd_offset(&init_mm, 0);
-		memcpy(ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
-			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof (pgd_t));
-	}
-	return ret;
+	pgd_t *pgd = (pgd_t *)get_pmd_fast();
+	if (!pgd)
+		pgd = (pgd_t *)get_pointer_table();
+	return pgd;
 }
 
 extern inline void set_pgdir(unsigned long address, pgd_t entry)
 {
-	/* Nothing to do on m68k */
 }
 
 /*
@@ -828,13 +845,9 @@
 #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << PAGE_SHIFT))
 #endif
 
+#endif /* __ASSEMBLY__ */
+
 #define module_map      vmalloc
 #define module_unmap    vfree
-#define module_shrink	vshrink
-
-/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
-#define PageSkip(page)		(0)
-
-#endif /* __ASSEMBLY__ */
 
 #endif /* _M68K_PGTABLE_H */
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/signal.h linux/include/asm-m68k/signal.h
--- v2.1.112/linux/include/asm-m68k/signal.h	Tue Jun 23 10:01:28 1998
+++ linux/include/asm-m68k/signal.h	Thu Jul 30 11:08:20 1998
@@ -72,8 +72,7 @@
 /*
  * SA_FLAGS values:
  *
- * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
- *   (++roman: SA_ONSTACK is supported on m68k)
+ * SA_ONSTACK indicates that a registered stack_t will be used.
  * 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_NOCLDSTOP flag to turn off SIGCHLD when children stop.
@@ -95,6 +94,15 @@
 #define SA_NOMASK	SA_NODEFER
 #define SA_ONESHOT	SA_RESETHAND
 #define SA_INTERRUPT	0x20000000 /* dummy -- ignored */
+
+/* 
+ * sigaltstack controls
+ */
+#define SS_ONSTACK	1
+#define SS_DISABLE	2
+
+#define MINSIGSTKSZ	2048
+#define SIGSTKSZ	8192
 
 #ifdef __KERNEL__
 /*
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/termios.h linux/include/asm-m68k/termios.h
--- v2.1.112/linux/include/asm-m68k/termios.h	Wed Apr  8 19:36:29 1998
+++ linux/include/asm-m68k/termios.h	Thu Jul 30 11:08:20 1998
@@ -55,6 +55,7 @@
 #define N_AX25		5
 #define N_X25		6	/* X.25 async */
 #define N_6PACK		7
+#define N_MASC		8	/* Reserved fo Mobitex module <kaz@cafe.net> */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.112/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- v2.1.112/linux/include/asm-m68k/unistd.h	Tue Jun 23 10:01:28 1998
+++ linux/include/asm-m68k/unistd.h	Thu Jul 30 11:08:20 1998
@@ -190,6 +190,7 @@
 #define __NR_getcwd		183
 #define __NR_capget		184
 #define __NR_capset		185
+#define __NR_sigaltstack	186
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
@@ -329,13 +330,16 @@
  */
 static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
-	register long retval __asm__ ("d0") = __NR_clone;
-	register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+	pid_t pid;
 	mm_segment_t fs;
 
 	fs = get_fs();
 	set_fs (KERNEL_DS);
 
+	{
+	register long retval __asm__ ("d0");
+	register long clone_arg __asm__ ("d1") = flags | CLONE_VM;
+
 	__asm__ __volatile__
 	  ("clrl %%d2\n\t"
 	   "trap #0\n\t"		/* Linux/m68k system call */
@@ -352,9 +356,11 @@
 	   : "0" (__NR_clone), "i" (__NR_exit),
 	     "r" (arg), "a" (fn), "d" (clone_arg), "r" (current)
 	   : "d0", "d2");
+	pid = retval;
+	}
 
 	set_fs (fs);
-	return retval;
+	return pid;
 }
 
 static inline pid_t wait(int * wait_stat)
diff -u --recursive --new-file v2.1.112/linux/include/linux/amifd.h linux/include/linux/amifd.h
--- v2.1.112/linux/include/linux/amifd.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/amifd.h	Thu Jul 30 11:17:12 1998
@@ -0,0 +1,61 @@
+#ifndef _AMIFD_H
+#define _AMIFD_H
+
+/* Definitions for the Amiga floppy driver */
+
+#include <linux/fd.h>
+
+#define FD_MAX_UNITS    4	/* Max. Number of drives */
+#define FLOPPY_MAX_SECTORS	22	/* Max. Number of sectors per track */
+
+#ifndef ASSEMBLER
+
+struct fd_data_type {
+    char *name;			/* description of data type */
+    int sects;			/* sectors per track */
+#ifdef __STDC__
+    int (*read_fkt)(int);
+    void (*write_fkt)(int);
+#else
+    int (*read_fkt)();		/* read whole track */
+    void (*write_fkt)();		/* write whole track */
+#endif
+};
+
+/*
+** Floppy type descriptions
+*/
+
+struct fd_drive_type {
+    unsigned long code;		/* code returned from drive */
+    char *name;			/* description of drive */
+    unsigned int tracks;	/* number of tracks */
+    unsigned int heads;		/* number of heads */
+    unsigned int read_size;	/* raw read size for one track */
+    unsigned int write_size;	/* raw write size for one track */
+    unsigned int sect_mult;	/* sectors and gap multiplier (HD = 2) */
+    unsigned int precomp1;	/* start track for precomp 1 */
+    unsigned int precomp2;	/* start track for precomp 2 */
+    unsigned int step_delay;	/* time (in ms) for delay after step */
+    unsigned int settle_time;	/* time to settle after dir change */
+    unsigned int side_time;	/* time needed to change sides */
+};
+
+struct amiga_floppy_struct {
+    struct fd_drive_type *type;	/* type of floppy for this unit */
+    struct fd_data_type *dtype;	/* type of floppy for this unit */
+    int track;			/* current track (-1 == unknown) */
+    unsigned char *trackbuf;    /* current track (kmaloc()'d */
+
+    int blocks;			/* total # blocks on disk */
+
+    int changed;		/* true when not known */
+    int disk;			/* disk in drive (-1 == unknown) */
+    int motor;			/* true when motor is at speed */
+    int busy;			/* true when drive is active */
+    int dirty;			/* true when trackbuf is not on disk */
+    int status;			/* current error code for unit */
+};
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.112/linux/include/linux/amifdreg.h linux/include/linux/amifdreg.h
--- v2.1.112/linux/include/linux/amifdreg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/amifdreg.h	Thu Jul 30 11:17:12 1998
@@ -0,0 +1,81 @@
+#ifndef _LINUX_AMIFDREG_H
+#define _LINUX_AMIFDREG_H
+
+/*
+** CIAAPRA bits (read only)
+*/
+
+#define DSKRDY      (0x1<<5)        /* disk ready when low */
+#define DSKTRACK0   (0x1<<4)        /* head at track zero when low */
+#define DSKPROT     (0x1<<3)        /* disk protected when low */
+#define DSKCHANGE   (0x1<<2)        /* low when disk removed */
+
+/*
+** CIAAPRB bits (read/write)
+*/
+
+#define DSKMOTOR    (0x1<<7)        /* motor on when low */
+#define DSKSEL3     (0x1<<6)        /* select drive 3 when low */
+#define DSKSEL2     (0x1<<5)        /* select drive 2 when low */
+#define DSKSEL1     (0x1<<4)        /* select drive 1 when low */
+#define DSKSEL0     (0x1<<3)        /* select drive 0 when low */
+#define DSKSIDE     (0x1<<2)        /* side selection: 0 = upper, 1 = lower */
+#define DSKDIREC    (0x1<<1)        /* step direction: 0=in, 1=out (to trk 0) */
+#define DSKSTEP     (0x1)           /* pulse low to step head 1 track */
+
+/*
+** DSKBYTR bits (read only)
+*/
+
+#define DSKBYT      (1<<15)         /* register contains valid byte when set */
+#define DMAON       (1<<14)         /* disk DMA enabled */
+#define DISKWRITE   (1<<13)         /* disk write bit in DSKLEN enabled */
+#define WORDEQUAL   (1<<12)         /* DSKSYNC register match when true */
+/* bits 7-0 are data */
+
+/*
+** ADKCON/ADKCONR bits
+*/
+
+#ifndef SETCLR
+#define ADK_SETCLR      (1<<15)     /* control bit */
+#endif
+#define ADK_PRECOMP1    (1<<14)     /* precompensation selection */
+#define ADK_PRECOMP0    (1<<13)     /* 00=none, 01=140ns, 10=280ns, 11=500ns */
+#define ADK_MFMPREC     (1<<12)     /* 0=GCR precomp., 1=MFM precomp. */
+#define ADK_WORDSYNC    (1<<10)     /* enable DSKSYNC auto DMA */
+#define ADK_MSBSYNC     (1<<9)      /* when 1, enable sync on MSbit (for GCR) */
+#define ADK_FAST        (1<<8)      /* bit cell: 0=2us (GCR), 1=1us (MFM) */
+ 
+/*
+** DSKLEN bits
+*/
+
+#define DSKLEN_DMAEN    (1<<15)
+#define DSKLEN_WRITE    (1<<14)
+
+/*
+** INTENA/INTREQ bits
+*/
+
+#define DSKINDEX    (0x1<<4)        /* DSKINDEX bit */
+
+/*
+** Misc
+*/
+ 
+#define MFM_SYNC    0x4489          /* standard MFM sync value */
+
+/* Values for FD_COMMAND */
+#define FD_RECALIBRATE		0x07	/* move to track 0 */
+#define FD_SEEK			0x0F	/* seek track */
+#define FD_READ			0xE6	/* read with MT, MFM, SKip deleted */
+#define FD_WRITE		0xC5	/* write with MT, MFM */
+#define FD_SENSEI		0x08	/* Sense Interrupt Status */
+#define FD_SPECIFY		0x03	/* specify HUT etc */
+#define FD_FORMAT		0x4D	/* format one track */
+#define FD_VERSION		0x10	/* get version code */
+#define FD_CONFIGURE		0x13	/* configure FIFO operation */
+#define FD_PERPENDICULAR	0x12	/* perpendicular r/w mode */
+
+#endif /* _LINUX_AMIFDREG_H */
diff -u --recursive --new-file v2.1.112/linux/include/linux/atari_rootsec.h linux/include/linux/atari_rootsec.h
--- v2.1.112/linux/include/linux/atari_rootsec.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/atari_rootsec.h	Thu Jul 30 11:17:12 1998
@@ -0,0 +1,34 @@
+#ifndef _LINUX_ATARI_ROOTSEC_H
+#define _LINUX_ATARI_ROOTSEC_H
+
+/*
+ * linux/include/linux/atari_rootsec.h
+ * definitions for Atari Rootsector layout
+ * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
+ *
+ * modified for ICD/Supra partitioning scheme restricted to at most 12
+ * partitions
+ * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
+ */
+
+struct partition_info
+{
+  u_char flg;			/* bit 0: active; bit 7: bootable */
+  char id[3];			/* "GEM", "BGM", "XGM", or other */
+  u32 st;			/* start of partition */
+  u32 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];
+  u32 hd_siz;				/* size of disk in blocks */
+  struct partition_info part[4];
+  u32 bsl_st;				/* start of bad sector list */
+  u32 bsl_cnt;				/* length of bad sector list */
+  u16 checksum;				/* checksum for bootable disks */
+} __attribute__ ((__packed__));
+
+#endif /* _LINUX_ATARI_ROOTSEC_H */
diff -u --recursive --new-file v2.1.112/linux/include/linux/console_struct.h linux/include/linux/console_struct.h
--- v2.1.112/linux/include/linux/console_struct.h	Tue Jul 28 14:21:09 1998
+++ linux/include/linux/console_struct.h	Fri Jul 31 23:19:40 1998
@@ -15,8 +15,6 @@
  */
 #define CUR_DEFAULT CUR_UNDERLINE
 
-#include <linux/config.h>
-
 #define NPAR 16
 
 struct vc_data {
diff -u --recursive --new-file v2.1.112/linux/include/linux/debugreg.h linux/include/linux/debugreg.h
--- v2.1.112/linux/include/linux/debugreg.h	Mon Nov 20 22:34:54 1995
+++ linux/include/linux/debugreg.h	Wed Dec 31 16:00:00 1969
@@ -1,61 +0,0 @@
-#ifndef _LINUX_DEBUGREG_H
-#define _LINUX_DEBUGREG_H
-
-
-/* Indicate the register numbers for a number of the specific
-   debug registers.  Registers 0-3 contain the addresses we wish to trap on */
-#define DR_FIRSTADDR 0        /* u_debugreg[DR_FIRSTADDR] */
-#define DR_LASTADDR 3         /* u_debugreg[DR_LASTADDR]  */
-
-#define DR_STATUS 6           /* u_debugreg[DR_STATUS]     */
-#define DR_CONTROL 7          /* u_debugreg[DR_CONTROL] */
-
-/* Define a few things for the status register.  We can use this to determine
-   which debugging register was responsible for the trap.  The other bits
-   are either reserved or not of interest to us. */
-
-#define DR_TRAP0 (0x1) /* Trap due to db0 */
-#define DR_TRAP1 (0x2) /* Trap due to db1 */
-#define DR_TRAP2 (0x4) /* Trap due to db2 */
-#define DR_TRAP3 (0x8) /* Trap due to db3 */
-
-/* Now define a bunch of things for manipulating the control register.
-   The top two bytes of the control register consist of 4 fields of 4
-   bits - each field corresponds to one of the four debug registers,
-   and indicates what types of access we trap on, and how large the data
-   field is that we are looking at */
-
-#define DR_CONTROL_SHIFT 16 /* Skip this many bits in ctl register */
-#define DR_CONTROL_SIZE 4   /* 4 control bits per register */
-
-#define DR_RW_EXECUTE (0x0)   /* Settings for the access types to trap on */
-#define DR_RW_WRITE (0x1)
-#define DR_RW_READ (0x3)
-
-#define DR_LEN_1 (0x0) /* Settings for data length to trap on */
-#define DR_LEN_2 (0x4)
-#define DR_LEN_4 (0xC)
-
-/* The low byte to the control register determine which registers are
-   enabled.  There are 4 fields of two bits.  One bit is "local", meaning
-   that the processor will reset the bit after a task switch and the other
-   is global meaning that we have to explicitly reset the bit.  With linux,
-   you can use either one, since we explicitly zero the register when we enter
-   kernel mode. */
-
-#define DR_LOCAL_ENABLE_SHIFT 0    /* Extra shift to the local enable bit */
-#define DR_GLOBAL_ENABLE_SHIFT 1   /* Extra shift to the global enable bit */
-#define DR_ENABLE_SIZE 2           /* 2 enable bits per register */
-
-#define DR_LOCAL_ENABLE_MASK (0x55)  /* Set  local bits for all 4 regs */
-#define DR_GLOBAL_ENABLE_MASK (0xAA) /* Set global bits for all 4 regs */
-
-/* The second byte to the control register has a few special things.
-   We can slow the instruction pipeline for instructions coming via the
-   gdt or the ldt if we want to.  I am not sure why this is an advantage */
-
-#define DR_CONTROL_RESERVED (0xFC00) /* Reserved by Intel */
-#define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
-#define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
-
-#endif
diff -u --recursive --new-file v2.1.112/linux/include/linux/kd.h linux/include/linux/kd.h
--- v2.1.112/linux/include/linux/kd.h	Fri Jul 31 17:07:03 1998
+++ linux/include/linux/kd.h	Thu Jul 30 11:18:31 1998
@@ -132,6 +132,27 @@
 
 #define KDSIGACCEPT	0x4B4E	/* accept kbd generated signals */
 
+struct hwclk_time {
+	unsigned	sec;	/* 0..59 */
+	unsigned	min;	/* 0..59 */
+	unsigned	hour;	/* 0..23 */
+	unsigned	day;	/* 1..31 */
+	unsigned	mon;	/* 0..11 */
+	unsigned	year;	/* 70... */
+	int		wday;	/* 0..6, 0 is Sunday, -1 means unknown/don't set */
+};
+
+#define KDGHWCLK        0x4B50	/* get hardware clock */
+#define KDSHWCLK        0x4B51  /* set hardware clock */
+
+struct kbd_repeat {
+	int delay;	/* in msec; <= 0: don't change */
+	int rate;	/* in msec; <= 0: don't change */
+};
+
+#define KDKBDREP        0x4B52  /* set keyboard delay/repeat rate;
+				 * actually used values are returned */
+
 #define KDFONTOP	0x4B72	/* font operations */
 
 struct console_font_op {
diff -u --recursive --new-file v2.1.112/linux/include/linux/keyboard.h linux/include/linux/keyboard.h
--- v2.1.112/linux/include/linux/keyboard.h	Sat May 24 09:10:25 1997
+++ linux/include/linux/keyboard.h	Thu Jul 30 11:17:12 1998
@@ -25,6 +25,7 @@
 extern unsigned short *key_maps[MAX_NR_KEYMAPS];
 extern unsigned short plain_map[NR_KEYS];
 extern struct wait_queue * keypress_wait;
+extern unsigned char keyboard_type;
 #endif
 
 #define MAX_NR_FUNC	256	/* max nr of strings assigned to keys */
diff -u --recursive --new-file v2.1.112/linux/include/linux/lp_m68k.h linux/include/linux/lp_m68k.h
--- v2.1.112/linux/include/linux/lp_m68k.h	Tue May 13 22:41:19 1997
+++ linux/include/linux/lp_m68k.h	Thu Jul 30 11:17:12 1998
@@ -92,7 +92,9 @@
 LP_AMIGA = 1,
 LP_ATARI = 2,
 LP_MFC = 3,
-LP_IOEXT = 4
+LP_IOEXT = 4,
+LP_MVME167 = 5,
+LP_BVME6000 = 6
 };
 
 /*
diff -u --recursive --new-file v2.1.112/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.112/linux/include/linux/proc_fs.h	Fri Jul 31 17:05:54 1998
+++ linux/include/linux/proc_fs.h	Fri Jul 31 23:38:32 1998
@@ -44,7 +44,6 @@
 	PROC_MD,
 	PROC_RTC,
 	PROC_LOCKS,
-	PROC_ZORRO,
 	PROC_HARDWARE,
 	PROC_SLABINFO,
 	PROC_PARPORT,
@@ -182,10 +181,13 @@
 	PROC_SCSI_ESP,
 	PROC_SCSI_QLOGICPTI,
 	PROC_SCSI_AMIGA7XX,
+	PROC_SCSI_MVME16x,
+	PROC_SCSI_BVME6000,
 	PROC_SCSI_A3000,
 	PROC_SCSI_A2091,
 	PROC_SCSI_GVP11,
 	PROC_SCSI_ATARI,
+	PROC_SCSI_MAC,
 	PROC_SCSI_IDESCSI,
 	PROC_SCSI_MESH,
 	PROC_SCSI_53C94,
@@ -208,16 +210,18 @@
 enum bus_directory_inos {
 	PROC_BUS_PCI = PROC_MCA_LAST,
 	PROC_BUS_PCI_DEVICES,
+	PROC_BUS_ZORRO,
+	PROC_BUS_ZORRO_DEVICES,
 	PROC_BUS_LAST
 };
 
 enum fs_directory_inos {
-	PROC_FS_CODA = PROC_MCA_LAST,
+	PROC_FS_CODA = PROC_BUS_LAST,
 	PROC_FS_LAST
 };
 
 enum fs_coda_directory_inos {
-	PROC_VFS_STATS = PROC_MCA_LAST,
+	PROC_VFS_STATS = PROC_FS_LAST,
 	PROC_UPCALL_STATS,
 	PROC_PERMISSION_STATS,
 	PROC_CACHE_INV_STATS,
diff -u --recursive --new-file v2.1.112/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.112/linux/include/linux/sched.h	Fri Jul 31 17:05:53 1998
+++ linux/include/linux/sched.h	Fri Jul 31 23:38:27 1998
@@ -312,7 +312,6 @@
 
 #define PF_USEDFPU	0x00100000	/* task used FPU this quantum (SMP) */
 #define PF_DTRACE	0x00200000	/* delayed trace (used on m68k) */
-#define PF_ONSIGSTK	0x00400000	/* works on signal stack (m68k only) */
 
 /*
  * Limit the stack by to some sane default: root can always
diff -u --recursive --new-file v2.1.112/linux/include/linux/smp_lock.h linux/include/linux/smp_lock.h
--- v2.1.112/linux/include/linux/smp_lock.h	Fri Jul 31 17:05:53 1998
+++ linux/include/linux/smp_lock.h	Fri Jul 31 23:38:27 1998
@@ -50,7 +50,7 @@
 
 	lock_depth = tsk->lock_depth;
 	tsk->lock_depth = lock_depth+1;
-	if (lock_depth)
+	if (!lock_depth)
 		spin_lock(&kernel_flag);
 }
 
diff -u --recursive --new-file v2.1.112/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.112/linux/include/linux/socket.h	Fri Jul 31 17:05:52 1998
+++ linux/include/linux/socket.h	Fri Jul 31 12:12:31 1998
@@ -116,9 +116,9 @@
 #define SCM_CONNECT	0x03		/* rw: struct scm_connect	*/
 
 struct ucred {
-	__kernel_pid_t	pid;
-	__kernel_uid_t	uid;
-	__kernel_gid_t	gid;
+	__u32	pid;
+	__u32	uid;
+	__u32	gid;
 };
 
 /* Socket types. */
diff -u --recursive --new-file v2.1.112/linux/include/linux/sunrpc/xprt.h linux/include/linux/sunrpc/xprt.h
--- v2.1.112/linux/include/linux/sunrpc/xprt.h	Fri Jul 31 17:09:54 1998
+++ linux/include/linux/sunrpc/xprt.h	Fri Jul 31 23:40:02 1998
@@ -117,6 +117,9 @@
 
 struct rpc_xprt {
 	struct rpc_xprt *	link;		/* list of all clients */
+	struct rpc_xprt *	rx_pending;	/* receive pending list */
+	
+	int 			rx_pending_flag;/* are we on the pending list ? */
 
 	struct file *		file;		/* VFS layer */
 	struct socket *		sock;		/* BSD socket layer */
diff -u --recursive --new-file v2.1.112/linux/include/linux/zorro.h linux/include/linux/zorro.h
--- v2.1.112/linux/include/linux/zorro.h	Tue Jun 23 10:01:29 1998
+++ linux/include/linux/zorro.h	Thu Jul 30 11:10:25 1998
@@ -1,12 +1,7 @@
 /*
- *  linux/zorro.h -- Amiga AutoConfig (Zorro) Expansion Device Definitions
+ *  linux/zorro.h -- Amiga AutoConfig (Zorro) Bus Definitions
  *
- *  Copyright (C) 1995 Geert Uytterhoeven
- *
- *  Please update arch/m68k/amiga/zorro.c if you make changes here!
- *
- *  Many IDs were obtained from ExpName/Identify ((C) Richard Körber)
- *  and by looking at the NetBSD-Amiga kernel sources
+ *  Copyright (C) 1995-1998 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
@@ -19,52 +14,6 @@
 #ifndef __ASSEMBLY__
 
     /*
-     *  Zorro Product Classes
-     *
-     *  Make sure to keep these in sync with arch/m68k/amiga/zorro.c!
-     */
-
-enum Zorro_Classes {
-    ZORRO_CLASS_UNKNOWN = 0x00,
-    ZORRO_CLASS_ARCNET,
-    ZORRO_CLASS_AUDIO,
-    ZORRO_CLASS_BRIDGE,
-    ZORRO_CLASS_DSP,
-    ZORRO_CLASS_ETHERNET,
-    ZORRO_CLASS_ETHERNET_PARALLEL,
-    ZORRO_CLASS_FLASHROM,
-    ZORRO_CLASS_FPU_RAM,
-    ZORRO_CLASS_GFX,
-    ZORRO_CLASS_GFXRAM,
-    ZORRO_CLASS_HD,
-    ZORRO_CLASS_HD_RAM,
-    ZORRO_CLASS_IDE,
-    ZORRO_CLASS_IDE_RAM,
-    ZORRO_CLASS_IDE_FLOPPY,
-    ZORRO_CLASS_ISDN,
-    ZORRO_CLASS_MACEMU,
-    ZORRO_CLASS_MISC,
-    ZORRO_CLASS_MODEM,
-    ZORRO_CLASS_MULTIIO,
-    ZORRO_CLASS_RAM,
-    ZORRO_CLASS_SCANNER,
-    ZORRO_CLASS_SCSI,
-    ZORRO_CLASS_SCSI_IDE,
-    ZORRO_CLASS_SCSI_RAM,
-    ZORRO_CLASS_SCSI_SERIAL,
-    ZORRO_CLASS_SERIAL,
-    ZORRO_CLASS_TABLET,
-    ZORRO_CLASS_TURBO,
-    ZORRO_CLASS_TURBO_RAM,
-    ZORRO_CLASS_TURBO_HD,
-    ZORRO_CLASS_TURBO_IDE,
-    ZORRO_CLASS_TURBO_SCSI,
-    ZORRO_CLASS_TURBO_SCSI_RAM,
-    ZORRO_CLASS_VIDEO,
-};
-
-
-    /*
      *  Known Zorro Boards
      *
      *  Each Zorro board has a 32-bit ID of the form
@@ -462,7 +411,7 @@
 #define ZORRO_MANUF_ARMAX					0x0885
 #define  ZORRO_PROD_ARMAX_OMNIBUS				ZORRO_ID(ARMAX, 0x00, 0)
 
-#define ZORRO_MANUF_ZEUS					0x088d
+#define ZORRO_MANUF_ZEUS					0x088D
 #define  ZORRO_PROD_ZEUS_SPIDER					ZORRO_ID(ZEUS, 0x04, 0)
 
 #define ZORRO_MANUF_NEWTEK					0x088F
@@ -623,7 +572,6 @@
 
     /*
      *  Test and illegal Manufacturer IDs.
-     *  These do NOT appear in arch/m68k/amiga/zorro.c!
      */
 
 #define ZORRO_MANUF_HACKER					0x07DB
@@ -659,25 +607,25 @@
 struct Node {
     struct  Node *ln_Succ;	/* Pointer to next (successor) */
     struct  Node *ln_Pred;	/* Pointer to previous (predecessor) */
-    u_char  ln_Type;
-    char    ln_Pri;		/* Priority, for sorting */
-    char    *ln_Name;		/* ID string, null terminated */
-};
+    __u8    ln_Type;
+    __s8    ln_Pri;		/* Priority, for sorting */
+    __s8    *ln_Name;		/* ID string, null terminated */
+} __attribute__ ((packed));
 
 struct ExpansionRom {
     /* -First 16 bytes of the expansion ROM */
-    u_char	er_Type;	/* Board type, size and flags */
-    u_char	er_Product;	/* Product number, assigned by manufacturer */
-    u_char	er_Flags;	/* Flags */
-    u_char	er_Reserved03;	/* Must be zero ($ff inverted) */
-    u_short	er_Manufacturer;/* Unique ID,ASSIGNED BY COMMODORE-AMIGA! */
-    u_long	er_SerialNumber;/* Available for use by manufacturer */
-    u_short	er_InitDiagVec;	/* Offset to optional "DiagArea" structure */
-    u_char	er_Reserved0c;
-    u_char	er_Reserved0d;
-    u_char	er_Reserved0e;
-    u_char	er_Reserved0f;
-};
+    __u8  er_Type;		/* Board type, size and flags */
+    __u8  er_Product;		/* Product number, assigned by manufacturer */
+    __u8  er_Flags;		/* Flags */
+    __u8  er_Reserved03;	/* Must be zero ($ff inverted) */
+    __u16 er_Manufacturer;	/* Unique ID, ASSIGNED BY COMMODORE-AMIGA! */
+    __u32 er_SerialNumber;	/* Available for use by manufacturer */
+    __u16 er_InitDiagVec;	/* Offset to optional "DiagArea" structure */
+    __u8  er_Reserved0c;
+    __u8  er_Reserved0d;
+    __u8  er_Reserved0e;
+    __u8  er_Reserved0f;
+} __attribute__ ((packed));
 
 /* er_Type board type bits */
 #define ERT_TYPEMASK	0xc0
@@ -690,17 +638,17 @@
 
 struct ConfigDev {
     struct Node 	cd_Node;
-    u_char		cd_Flags;	/* (read/write) */
-    u_char		cd_Pad; 	/* reserved */
+    __u8  		cd_Flags;	/* (read/write) */
+    __u8  		cd_Pad; 	/* reserved */
     struct ExpansionRom cd_Rom; 	/* copy of board's expansion ROM */
     void		*cd_BoardAddr;	/* where in memory the board was placed */
-    u_long		cd_BoardSize;	/* size of board in bytes */
-    u_short		cd_SlotAddr;	/* which slot number (PRIVATE) */
-    u_short		cd_SlotSize;	/* number of slots (PRIVATE) */
+    __u32 		cd_BoardSize;	/* size of board in bytes */
+    __u16  		cd_SlotAddr;	/* which slot number (PRIVATE) */
+    __u16  		cd_SlotSize;	/* number of slots (PRIVATE) */
     void		*cd_Driver;	/* pointer to node of driver */
     struct ConfigDev	*cd_NextCD;	/* linked list of drivers to config */
-    u_long		cd_Unused[4];	/* for whatever the driver wants */
-};
+    __u32 		cd_Unused[4];	/* for whatever the driver wants */
+} __attribute__ ((packed));
 
 #else /* __ASSEMBLY__ */
 
@@ -745,7 +693,7 @@
 
 #ifdef __KERNEL__
 
-extern unsigned int zorro_num_autocon;		/* # of autoconfig devices found */
+extern unsigned int zorro_num_autocon;	/* # of autoconfig devices found */
 extern struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO];
 
 
@@ -753,6 +701,9 @@
      *  Zorro Functions
      */
 
+extern void zorro_init(void);
+extern void zorro_proc_init(void);
+
 extern unsigned int zorro_find(zorro_id id, unsigned int part, unsigned int index);
 extern const struct ConfigDev *zorro_get_board(unsigned int key);
 extern void zorro_config_board(unsigned int key, unsigned int part);
@@ -768,7 +719,7 @@
      *  the corresponding bits.
      */
 
-extern u32 zorro_unused_z2ram[4];
+extern __u32 zorro_unused_z2ram[4];
 
 #define Z2RAM_START		(0x00200000)
 #define Z2RAM_END		(0x00a00000)
@@ -777,13 +728,6 @@
 #define Z2RAM_CHUNKMASK		(0x0000ffff)
 #define Z2RAM_CHUNKSHIFT	(16)
 
-
-    /*
-     *  Verbose Board Identification
-     */
-
-extern void zorro_identify(void);
-extern int zorro_get_list(char *buffer);
 
 #endif /* !__ASSEMBLY__ */
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.112/linux/init/main.c linux/init/main.c
--- v2.1.112/linux/init/main.c	Tue Jul 28 14:21:10 1998
+++ linux/init/main.c	Thu Jul 30 11:17:12 1998
@@ -240,9 +240,13 @@
 #ifdef CONFIG_ATARI_SCSI
 extern void atari_scsi_setup (char *str, int *ints);
 #endif
+extern void stram_swap_setup (char *str, int *ints);
 extern void wd33c93_setup (char *str, int *ints);
 extern void gvp11_setup (char *str, int *ints);
 extern void ncr53c7xx_setup (char *str, int *ints);
+#ifdef CONFIG_MAC_SCSI
+extern void mac_scsi_setup (char *str, int *ints);
+#endif
 
 #ifdef CONFIG_CYCLADES
 extern void cy_setup(char *str, int *ints);
@@ -717,7 +721,12 @@
 #ifdef CONFIG_ATARI_SCSI
 	{ "atascsi=", atari_scsi_setup },
 #endif
-#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) || defined(CONFIG_A4091_SCSI)
+#ifdef CONFIG_STRAM_SWAP
+	{ "stram_swap=", stram_swap_setup },
+#endif
+#if defined(CONFIG_A4000T_SCSI) || defined(CONFIG_WARPENGINE_SCSI) \
+	    || defined(CONFIG_A4091_SCSI) || defined(CONFIG_MVME16x_SCSI) \
+	    || defined(CONFIG_BVME6000_SCSI)
         { "53c7xx=", ncr53c7xx_setup },
 #endif
 #if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \
@@ -726,6 +735,9 @@
 #endif
 #if defined(CONFIG_GVP11_SCSI)
 	{ "gvp11=", gvp11_setup },
+#endif
+#ifdef CONFIG_MAC_SCSI
+	{ "mac5380=", mac_scsi_setup },
 #endif
 #ifdef CONFIG_CYCLADES
 	{ "cyclades=", cy_setup },
diff -u --recursive --new-file v2.1.112/linux/kernel/printk.c linux/kernel/printk.c
--- v2.1.112/linux/kernel/printk.c	Thu Jul 16 18:09:30 1998
+++ linux/kernel/printk.c	Wed Jul 29 23:01:04 1998
@@ -28,7 +28,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define LOG_BUF_LEN	8192
+#define LOG_BUF_LEN	(16384)
 
 static char buf[1024];
 
diff -u --recursive --new-file v2.1.112/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.112/linux/mm/filemap.c	Tue Jul 21 00:15:33 1998
+++ linux/mm/filemap.c	Thu Jul 30 14:21:36 1998
@@ -853,13 +853,15 @@
 	unsigned long count = desc->count;
 	struct file *file = (struct file *) desc->buf;
 	struct inode *inode = file->f_dentry->d_inode;
+	mm_segment_t old_fs;
 
 	if (size > count)
 		size = count;
 	down(&inode->i_sem);
+	old_fs = get_fs();
 	set_fs(KERNEL_DS);
 	written = file->f_op->write(file, area, size, &file->f_pos);
-	set_fs(USER_DS);
+	set_fs(old_fs);
 	up(&inode->i_sem);
 	if (written < 0) {
 		desc->error = written;
diff -u --recursive --new-file v2.1.112/linux/mm/memory.c linux/mm/memory.c
--- v2.1.112/linux/mm/memory.c	Tue Jul 28 14:21:10 1998
+++ linux/mm/memory.c	Fri Jul 31 12:47:59 1998
@@ -955,14 +955,14 @@
 
 void check_pgt_cache(void)
 {
-        if(pgtable_cache_size > pgt_cache_water[0]) {
-                do {
-                        if(pgd_quicklist)
-                                free_pgd_slow(get_pgd_fast());
-                        if(pmd_quicklist)
-                                free_pmd_slow(get_pmd_fast());
-                        if(pte_quicklist)
-                                free_pte_slow(get_pte_fast());
-                } while(pgtable_cache_size > pgt_cache_water[1]);
-        }
+	if (pgtable_cache_size > pgt_cache_water[1]) {
+		do {
+			if (pgd_quicklist)
+				free_pgd_slow(get_pgd_fast());
+			if (pmd_quicklist)
+				free_pmd_slow(get_pmd_fast());
+			if (pte_quicklist)
+				free_pte_slow(get_pte_fast());
+		} while (pgtable_cache_size > pgt_cache_water[0]);
+	}
 }
diff -u --recursive --new-file v2.1.112/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.1.112/linux/mm/swap_state.c	Tue Mar 17 22:18:15 1998
+++ linux/mm/swap_state.c	Wed Jul 29 14:18:02 1998
@@ -146,41 +146,22 @@
 			"on page %08lx\n", page_address(page));
 	}
 	/*
-	 * This will be a legal case once we have a more mature swap cache.
+	 * This is a legal case, but warn about it.
 	 */
 	if (atomic_read(&page->count) == 1) {
-		printk ("VM: Removing page cache on unshared page %08lx\n", 
+		printk (KERN_WARNING 
+			"VM: Removing page cache on unshared page %08lx\n", 
 			page_address(page));
-		return;
 	}
 
-	
 #ifdef DEBUG_SWAP
 	printk("DebugVM: remove_from_swap_cache(%08lx count %d)\n",
 	       page_address(page), atomic_read(&page->count));
 #endif
-	remove_page_from_hash_queue (page);
-	remove_page_from_inode_queue (page);
 	PageClearSwapCache (page);
-	__free_page (page);
+	remove_inode_page(page);
 }
 
-
-long find_in_swap_cache(struct page *page)
-{
-#ifdef SWAP_CACHE_INFO
-	swap_cache_find_total++;
-#endif
-	if (PageSwapCache (page))  {
-		long entry = page->offset;
-#ifdef SWAP_CACHE_INFO
-		swap_cache_find_success++;
-#endif	
-		remove_from_swap_cache (page);
-		return entry;
-	}
-	return 0;
-}
 
 int delete_from_swap_cache(struct page *page)
 {
diff -u --recursive --new-file v2.1.112/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.1.112/linux/net/core/skbuff.c	Tue Jul 28 14:21:10 1998
+++ linux/net/core/skbuff.c	Tue Jul 28 22:33:02 1998
@@ -90,7 +90,7 @@
 
 void skb_under_panic(struct sk_buff *skb, int sz, void *here)
 {
-        panic("skput:over: %p:%d put:%d dev:%s",
+        panic("skput:under: %p:%d put:%d dev:%s",
                 here, skb->len, sz, skb->dev ? skb->dev->name : "<NULL>");
 }
 
diff -u --recursive --new-file v2.1.112/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- v2.1.112/linux/net/ipv4/ip_masq.c	Thu Mar 26 15:57:13 1998
+++ linux/net/ipv4/ip_masq.c	Fri Jul 31 23:01:29 1998
@@ -1528,7 +1528,7 @@
 				if (csum_tcpudp_magic(iph->saddr, iph->daddr, len,
 						      iph->protocol, skb->csum))
 				{
-					IP_MASQ_WARNING( "failed TCP/UDP checksum from %d.%d.%d.%d!\n",
+					IP_MASQ_DEBUG(2, "failed TCP/UDP checksum from %d.%d.%d.%d!\n",
 					       NIPQUAD(iph->saddr));
 					return -1;
 				}
diff -u --recursive --new-file v2.1.112/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.112/linux/net/ipv4/tcp_ipv4.c	Tue Jul 28 14:21:10 1998
+++ linux/net/ipv4/tcp_ipv4.c	Tue Jul 28 22:33:02 1998
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.148 1998/07/23 12:28:25 freitag Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.150 1998/07/28 17:45:07 freitag Exp $
  *
  *		IPv4 specific functions
  *
@@ -771,10 +771,11 @@
 	tp = &sk->tp_pinfo.af_tcp;
 	seq = ntohl(th->seq);
 	if (sk->state != TCP_LISTEN && 
-   	    !between(seq, tp->snd_una, max(tp->snd_una+32768,tp->snd_nxt))) {
+   	    !between(seq, tp->snd_una-16384, max(tp->snd_una+32768,tp->snd_nxt))) {
 		if (net_ratelimit()) 
-			printk(KERN_DEBUG "icmp packet outside the tcp window:"
-					  " s:%d %u,%u,%u\n",
+			printk(KERN_WARNING 
+				"icmp packet outside the tcp window:"
+				" state:%d seq:%u win:%u,%u\n",
 			       (int)sk->state, seq, tp->snd_una, tp->snd_nxt); 
 		return; 
 	}
@@ -1332,11 +1333,6 @@
 	if (!newsk) 
 		goto exit;
 
-	if (newsk->rcvbuf < (3 * newsk->mtu))
-		newsk->rcvbuf = min ((3 * newsk->mtu), sysctl_rmem_max);
-	if (newsk->sndbuf < (3 * newsk->mtu))
-		newsk->sndbuf = min ((3 * newsk->mtu), sysctl_wmem_max);
- 
 	sk->tp_pinfo.af_tcp.syn_backlog--;
 	sk->ack_backlog++;
 
@@ -1353,6 +1349,11 @@
 	newsk->opt = req->af.v4_req.opt;
 	newsk->mtu = mtu;
 
+	if (newsk->rcvbuf < (3 * newsk->mtu))
+		newsk->rcvbuf = min ((3 * newsk->mtu), sysctl_rmem_max);
+	if (newsk->sndbuf < (3 * newsk->mtu))
+		newsk->sndbuf = min ((3 * newsk->mtu), sysctl_wmem_max);
+ 
 	tcp_v4_hash(newsk);
 	add_to_prot_sklist(newsk);
 
diff -u --recursive --new-file v2.1.112/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.1.112/linux/net/sunrpc/xprt.c	Fri May  8 23:14:58 1998
+++ linux/net/sunrpc/xprt.c	Wed Jul 29 12:33:44 1998
@@ -32,6 +32,8 @@
  *  tasks that rely on callbacks.
  *
  *  Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de>
+ *
+ *  TCP callback races fixes (C) 1998 Red Hat Software <alan@redhat.com>
  */
 
 #define __KERNEL_SYSCALLS__
@@ -693,40 +695,107 @@
 }
 
 /*
- * data_ready callback for TCP.
+ *	TCP task queue stuff
  */
-static void
-tcp_data_ready(struct sock *sk, int len)
+ 
+static struct rpc_xprt *rpc_xprt_pending = NULL;	/* Chain by rx_pending of rpc_xprt's */
+
+static struct tq_struct rpc_tcp_tqueue = { 0, 0, 0, 0 };
+
+
+/*
+ *	This is protected from tcp_data_ready by the bh atomicity guarantees
+ */
+
+static void tcp_rpc_bh_run(void)
+{
+	struct rpc_xprt *xprt;
+	int result;
+
+	dprintk("tcp_rpc_bh_run: Queue Running\n");
+	
+	/*
+	 *	Empty each pending socket
+	 */
+	 
+	while((xprt=rpc_xprt_pending)!=NULL)
+	{
+		int safe_retry=0;
+		
+		rpc_xprt_pending=xprt->rx_pending;
+		xprt->rx_pending_flag=0;
+		
+		dprintk("tcp_rpc_run_bh: Processing %p\n", xprt);
+		
+		do 
+		{
+			if (safe_retry++ > 50)
+				break;
+			result = tcp_input_record(xprt);
+		}
+		while (result >= 0);
+	
+		switch (result) {
+			case -EAGAIN:
+				continue;
+			case -ENOTCONN:
+			case -EPIPE:
+				xprt_disconnect(xprt);
+				continue;
+			default:
+				printk(KERN_WARNING "RPC: unexpected error %d from tcp_input_record\n",
+					result);
+		}
+	}
+}
+
+
+static void tcp_rpc_bh_queue(void)
+{
+	rpc_tcp_tqueue.routine=(void *)(void *)tcp_rpc_bh_run;
+	queue_task(&rpc_tcp_tqueue, &tq_immediate);
+	dprintk("RPC:     tcp_rpc_bh_queue: immediate op queued\n");
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ *	data_ready callback for TCP. We can't just jump into the
+ *	tcp recvmsg functions inside of the network receive bh or
+ * 	bad things occur. We queue it to pick up after networking
+ *	is done.
+ */
+ 
+static void tcp_data_ready(struct sock *sk, int len)
 {
 	struct rpc_xprt	*xprt;
-	int		result, safe_retry = 0;
 
 	dprintk("RPC:      tcp_data_ready...\n");
 	if (!(xprt = xprt_from_sock(sk)))
+	{
+		printk("Not a socket with xprt %p\n", sk);
 		return;
+	}
 	dprintk("RPC:      tcp_data_ready client %p\n", xprt);
 	dprintk("RPC:      state %x conn %d dead %d zapped %d\n",
 				sk->state, xprt->connected,
 				sk->dead, sk->zapped);
-
-	do {
-		if (safe_retry++ > 20)
-			return;
-		result = tcp_input_record(xprt);
-	} while (result >= 0);
-
-	switch (result) {
-	case -EAGAIN:
-		return;
-	case -ENOTCONN:
-	case -EPIPE:
-		xprt_disconnect(xprt);
-		return;
-	default:
-		printk("RPC: unexpected error %d from tcp_input_record\n",
-			result);
+	/*
+	 *	If we are not waiting for the RPC bh run then
+	 *	we are now
+	 */
+	if (!xprt->rx_pending_flag)
+	{
+		dprintk("RPC:     xprt queue\n");
+		if(rpc_xprt_pending==NULL)
+			tcp_rpc_bh_queue();
+		xprt->rx_pending_flag=1;
+		xprt->rx_pending=rpc_xprt_pending;
+		rpc_xprt_pending=xprt;
 	}
+	else
+		dprintk("RPC:     xprt queued already %p\n", xprt);
 }
+
 
 static void
 tcp_state_change(struct sock *sk)
