diff -u --recursive --new-file v1.3.57/linux/CREDITS linux/CREDITS
--- v1.3.57/linux/CREDITS	Sat Jan  6 19:10:37 1996
+++ linux/CREDITS	Thu Jan 18 06:37:57 1996
@@ -149,7 +149,7 @@
 
 N: Andries Brouwer
 E: aeb@cwi.nl
-D: International character handling for keyboard and console
+D: random Linux hacker
 S: Bessemerstraat 21
 S: Amsterdam
 S: The Netherlands
@@ -601,7 +601,7 @@
 S: USA
 
 N: H.J. Lu
-E: hjl@nynexst.com
+E: hjl@gnu.ai.mit.edu
 D: GCC + libraries hacker
 
 N: Tuomas J. Lukka
@@ -722,7 +722,7 @@
 S: USA
 
 N: Harald Milz
-E: hm@ix.de
+E: hm@seneca.linux.de
 D: Linux Projects Map, Linux Commercial-HOWTO
 D: general Linux publicity in Germany, vacation port
 D: UUCP and CNEWS binary packages for LST
@@ -894,7 +894,8 @@
 S: Belgium
 
 N: Martin Schulze
-E: joey@infodrom.north.de
+E: joey@linux.de
+W: http://home.pages.de/~joey/
 D: Random Linux Hacker, Linux Promoter
 D: CD-List, Books-List, Ex-FAQ
 D: Linux-Support, -Mailbox, -Stammtisch
diff -u --recursive --new-file v1.3.57/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.57/linux/Documentation/Configure.help	Sun Jan 14 16:30:09 1996
+++ linux/Documentation/Configure.help	Wed Jan 17 09:21:51 1996
@@ -221,7 +221,7 @@
   This is for some buggy motherboards which cannot properly deal with
   the memory above 16MB. If you have more than 16MB of RAM and
   experience weird problems, you might want to try Y, everyone else
-  says N. Note for machines with more that 64MB of RAM: in order for the
+  says N. Note for machines with more than 64MB of RAM: in order for the
   kernel to be able to use the memory above 64MB, pass the command
   line option "mem=XXXM" (where XXX is the memory size in
   megabytes) to your kernel. See the documentation of your boot loader
@@ -379,7 +379,7 @@
 
 Kernel daemon support
 CONFIG_KERNELD
-  Normally when you have seleceted some drivers and/or filesystems
+  Normally when you have selected some drivers and/or filesystems
   to be created as loadable modules, you also have the responsibility
   to load the corresponding module (via insmod/modprobe) before you
   use it.  If you select Y here, the kernel will take care of this
@@ -1861,7 +1861,7 @@
   ext2 filesystem; you need the software available via ftp (user:
   anonymous) from
   sunsite.unc.edu:/pub/Linux/systm/Admin/quota_acct.tar.gz in order to
-  use it. Obviously, this is only useful for multi user systems. If
+  use it. Probably this is only useful for multi user systems. If
   unsure, say N.
 
 Standard (minix) fs support
diff -u --recursive --new-file v1.3.57/linux/Documentation/cdrom/optcd linux/Documentation/cdrom/optcd
--- v1.3.57/linux/Documentation/cdrom/optcd	Mon Oct 23 18:02:00 1995
+++ linux/Documentation/cdrom/optcd	Thu Jan 18 06:22:13 1996
@@ -43,4 +43,8 @@
 changed into #defines (you'll find them in .../include/linux/optcd.h) and
 include the messages generated in your bug report. Good luck.
 
+I have inserted code to support multisession. It works for me, although
+it is very slow during disk detection. At this time multisession support
+is to be considered experimental. Please mail me your experiences.
+
 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
diff -u --recursive --new-file v1.3.57/linux/MAGIC linux/MAGIC
--- v1.3.57/linux/MAGIC	Mon Dec 11 15:41:59 1995
+++ linux/MAGIC	Mon Jan 15 07:59:08 1996
@@ -74,6 +74,7 @@
 0x06	linux/lp.h
 0x12	linux/fs.h
 0x20	linux/cm206.h
+0x22	linux/scc.h
 'A'	linux/apm_bios.h
 'C'	linux/soundcard.h
 'K'	linux/kd.h
@@ -83,7 +84,6 @@
 'S'	linux/cdrom.h		conflict!
 'S'	linux/scsi.h		conflict!
 'T'	linux/soundcard.h	conflict!
-'T'	linux/scc.h		conflict!
 'T'	asm/termios.h		conflict!
 'V'	linux/vt.h
 'Y'	linux/cyclades.h	codes in 0x004359NN
diff -u --recursive --new-file v1.3.57/linux/Makefile linux/Makefile
--- v1.3.57/linux/Makefile	Sun Jan 14 16:30:09 1996
+++ linux/Makefile	Sun Jan 14 16:27:34 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 57
+SUBLEVEL = 58
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.57/linux/Rules.make linux/Rules.make
--- v1.3.57/linux/Rules.make	Sun Jan 14 16:30:09 1996
+++ linux/Rules.make	Mon Jan 15 07:59:14 1996
@@ -146,7 +146,7 @@
 
 $(SYMTAB_OBJS:.o=.ver): $(TOPDIR)/include/linux/autoconf.h
 
-$(TOPDIR)/include/linux/modversions.h: $(join $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver))
+$(TOPDIR)/include/linux/modversions.h: $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver))
 	@echo updating $(TOPDIR)/include/linux/modversions.h
 	@(echo "#ifdef MODVERSIONS";\
 	echo "#undef  CONFIG_MODVERSIONS";\
diff -u --recursive --new-file v1.3.57/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v1.3.57/linux/arch/alpha/config.in	Sun Jan 14 16:30:09 1996
+++ linux/arch/alpha/config.in	Sun Jan 14 16:22:16 1996
@@ -16,6 +16,7 @@
   MODULES=y
   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
 fi
+endmenu
 
 mainmenu_option next_comment
 comment 'General setup'
@@ -57,6 +58,7 @@
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+endmenu
 
 source drivers/block/Config.in
 
@@ -72,6 +74,7 @@
 if [ "$CONFIG_SCSI" != "n" ]; then
   source drivers/scsi/Config.in
 fi
+endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
@@ -81,6 +84,7 @@
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     source drivers/net/Config.in
   fi
+  endmenu
 fi
 
 mainmenu_option next_comment
@@ -90,6 +94,7 @@
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
   source drivers/cdrom/Config.in
 fi
+endmenu
 
 source fs/Config.in
 
@@ -102,6 +107,7 @@
 if [ "$CONFIG_SOUND" != "n" ]; then
   source drivers/sound/Config.in
 fi
+endmenu
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
@@ -111,3 +117,4 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+endmenu
diff -u --recursive --new-file v1.3.57/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v1.3.57/linux/arch/alpha/kernel/Makefile	Tue Dec 26 04:45:34 1995
+++ linux/arch/alpha/kernel/Makefile	Mon Jan 15 09:22:57 1996
@@ -12,8 +12,11 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
-OBJS  = entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
-	bios32.o ptrace.o time.o apecs.o lca.o
+all: kernel.o head.o
+
+O_TARGET := kernel.o
+O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
+	    bios32.o ptrace.o time.o apecs.o lca.o ksyms.c
 
 all: kernel.o head.o
 
@@ -21,11 +24,5 @@
 
 head.s: head.S $(TOPDIR)/include/asm-alpha/system.h
 	$(CPP) -traditional -o $*.s $<
-
-kernel.o: $(OBJS)
-	$(LD) -r -o kernel.o $(OBJS)
-
-dep:
-	$(CPP) -M *.c > .depend
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.57/linux/arch/alpha/kernel/ksyms.c linux/arch/alpha/kernel/ksyms.c
--- v1.3.57/linux/arch/alpha/kernel/ksyms.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/alpha/kernel/ksyms.c	Thu Jan 18 10:35:20 1996
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/alpha/kernel/ksyms.c
+ *
+ * Export the alpha-specific functions that are needed for loadable
+ * modules.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+# include <asm/io.h>
+# include <asm/hwrpb.h>
+
+extern void bcopy (const char *src, char *dst, int len);
+extern struct hwrpb_struct *hwrpb;
+
+/* these are C runtime functions with special calling conventions: */
+extern void __divl (void);
+extern void __reml (void);
+extern void __divq (void);
+extern void __remq (void);
+extern void __divlu (void);
+extern void __remlu (void);
+extern void __divqu (void);
+extern void __remqu (void);
+
+static struct symbol_table arch_symbol_table = {
+#include <linux/symtab_begin.h>
+	/* platform dependent support */
+	X(_inb),
+	X(_inw),
+	X(_inl),
+	X(_outb),
+	X(_outw),
+	X(_outl),
+	X(bcopy),	/* generated by gcc-2.7.0 for string assignments */
+	X(hwrpb),
+	X(__divl),
+	X(__reml),
+	X(__divq),
+	X(__remq),
+	X(__divlu),
+	X(__remlu),
+	X(__divqu),
+	X(__remqu),
+	X(strlen),	/* used by ftape */
+	X(memcmp),
+	X(memmove),
+	X(__constant_c_memset),
+#include <linux/symtab_end.h>
+};
+
+void arch_syms_export(void)
+{
+	register_symtab(&arch_symbol_table);
+}
diff -u --recursive --new-file v1.3.57/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.3.57/linux/arch/i386/config.in	Sun Jan 14 16:30:09 1996
+++ linux/arch/i386/config.in	Sun Jan 14 16:22:16 1996
@@ -12,6 +12,7 @@
   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
   bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
+endmenu
 
 mainmenu_option next_comment
 comment 'General setup'
@@ -32,6 +33,7 @@
 	"386		CONFIG_M386	\
 	 486		CONFIG_M486	\
 	 Pentium	CONFIG_M586" Pentium
+endmenu
 
 source drivers/block/Config.in
 
@@ -47,6 +49,7 @@
 if [ "$CONFIG_SCSI" != "n" ]; then
   source drivers/scsi/Config.in
 fi
+endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
@@ -56,6 +59,7 @@
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     source drivers/net/Config.in
   fi
+  endmenu
 fi
 
 mainmenu_option next_comment
@@ -65,6 +69,7 @@
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
   source drivers/cdrom/Config.in
 fi
+endmenu
 
 source fs/Config.in
 
@@ -77,6 +82,7 @@
 if [ "$CONFIG_SOUND" != "n" ]; then
   source drivers/sound/Config.in
 fi
+endmenu
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
@@ -86,3 +92,4 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+endmenu
diff -u --recursive --new-file v1.3.57/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v1.3.57/linux/arch/i386/defconfig	Sun Jan 14 16:30:09 1996
+++ linux/arch/i386/defconfig	Mon Jan 15 08:59:59 1996
@@ -6,7 +6,7 @@
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 # CONFIG_KERNELD is not set
 
 #
@@ -36,9 +36,9 @@
 #
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDE=y
-CONFIG_BLK_DEV_IDEATAPI=y
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_CMD640=y
 # CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_BLK_DEV_XD is not set
 
diff -u --recursive --new-file v1.3.57/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v1.3.57/linux/arch/i386/kernel/Makefile	Fri Nov 17 08:42:24 1995
+++ linux/arch/i386/kernel/Makefile	Mon Jan 15 08:09:28 1996
@@ -28,7 +28,7 @@
 
 O_TARGET := kernel.o
 O_OBJS   := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
-            ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o
+            ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o ksyms.o
 
 ifdef SMP
 
diff -u --recursive --new-file v1.3.57/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c
--- v1.3.57/linux/arch/i386/kernel/ksyms.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/i386/kernel/ksyms.c	Thu Jan 18 10:34:55 1996
@@ -0,0 +1,17 @@
+#include <linux/module.h>
+#include <linux/smp.h>
+
+
+static struct symbol_table arch_symbol_table = {
+#include <linux/symtab_begin.h>
+	/* platform dependent support */
+#ifdef __SMP__
+	X(apic_reg),		/* Needed internally for the I386 inlines */
+#endif
+#include <linux/symtab_end.h>
+};
+
+void arch_syms_export(void)
+{
+	register_symtab(&arch_symbol_table);
+}
diff -u --recursive --new-file v1.3.57/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v1.3.57/linux/arch/i386/kernel/setup.c	Tue Dec 26 04:45:35 1995
+++ linux/arch/i386/kernel/setup.c	Wed Jan 17 07:32:08 1996
@@ -196,7 +196,7 @@
 static const char * i586model(unsigned int nr)
 {
 	static const char *model[] = {
-		"0", "Pentium 60/66","Pentium 75+"
+		"0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83"
 	};
 	if (nr < sizeof(model)/sizeof(char *))
 		return model[nr];
diff -u --recursive --new-file v1.3.57/linux/arch/mips/config.in linux/arch/mips/config.in
--- v1.3.57/linux/arch/mips/config.in	Sun Jan 14 16:30:10 1996
+++ linux/arch/mips/config.in	Sun Jan 14 16:22:16 1996
@@ -47,10 +47,12 @@
 #  bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
 #fi
 bool 'System V IPC' CONFIG_SYSVIPC
+endmenu
 
 mainmenu_option next_comment
 comment 'Loadable module support'
 bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+endmenu
 
 source drivers/block/Config.in
 
@@ -66,6 +68,7 @@
 if [ "$CONFIG_SCSI" != "n" ]; then
   source drivers/scsi/Config.in
 fi
+endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
@@ -75,6 +78,7 @@
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     source drivers/net/Config.in
   fi
+  endmenu
 fi
 
 mainmenu_option next_comment
@@ -84,6 +88,7 @@
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
   source drivers/cdrom/Config.in
 fi
+endmenu
 
 source fs/Config.in
 
@@ -97,6 +102,7 @@
 if [ "$CONFIG_SOUND" != "n" ]; then
   source drivers/sound/Config.in
 fi
+endmenu
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
@@ -106,3 +112,4 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+endmenu
diff -u --recursive --new-file v1.3.57/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v1.3.57/linux/arch/sparc/config.in	Sat Nov 25 19:04:36 1995
+++ linux/arch/sparc/config.in	Sun Jan 14 16:22:16 1996
@@ -17,6 +17,7 @@
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+endmenu
 
 source drivers/block/Config.in
 
@@ -32,6 +33,7 @@
 if [ "$CONFIG_SCSI" != "n" ]; then
 	source drivers/scsi/Config.in
 fi
+endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
 	mainmenu_option next_comment
@@ -41,6 +43,7 @@
 	if [ "$CONFIG_NETDEVICES" = "y" ]; then
 		source drivers/net/Config.in
 	fi
+	endmenu
 fi
 
 source fs/Config.in
diff -u --recursive --new-file v1.3.57/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v1.3.57/linux/drivers/block/Config.in	Tue Jan  2 16:46:24 1996
+++ linux/drivers/block/Config.in	Sun Jan 14 16:22:16 1996
@@ -16,11 +16,9 @@
     bool '   Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE
   fi
   if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
-    bool '   Include support for IDE/ATAPI CDROM or TAPE' CONFIG_BLK_DEV_IDEATAPI
-    if [ "$CONFIG_BLK_DEV_IDEATAPI" = "y" ]; then
-      bool '      Include support for IDE/ATAPI CDROM' CONFIG_BLK_DEV_IDECD
-      bool '      Include ALPHA support for IDE/ATAPI TAPE' CONFIG_BLK_DEV_IDETAPE
-    fi
+    bool '   Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD
+    bool '   Include (ALPHA) IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE
+    bool '   Special CMD640 chipset support' CONFIG_BLK_DEV_CMD640
     if [ "$CONFIG_PCI" = "y" ]; then
       bool '   PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON
     fi
@@ -28,3 +26,4 @@
 fi
 
 bool 'XT harddisk support' CONFIG_BLK_DEV_XD
+endmenu
diff -u --recursive --new-file v1.3.57/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v1.3.57/linux/drivers/block/Makefile	Tue Jan  2 16:46:24 1996
+++ linux/drivers/block/Makefile	Sun Jan 14 16:22:14 1996
@@ -48,6 +48,10 @@
 L_OBJS += triton.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_CMD640),y)
+L_OBJS += cmd640.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_IDECD),y)
 L_OBJS += ide-cd.o
 endif
diff -u --recursive --new-file v1.3.57/linux/drivers/block/README.ide linux/drivers/block/README.ide
--- v1.3.57/linux/drivers/block/README.ide	Thu Jan  4 21:54:53 1996
+++ linux/drivers/block/README.ide	Sun Jan 14 16:22:14 1996
@@ -350,13 +350,19 @@
 as in:  hda=525,64,63
 
 If the BIOS does not support this form of drive translation, then several
-options remain, listed below in inverse order of popularity:
+options remain, listed below in order of popularity:
 
-	- boot from a floppy disk instead of the hard drive (takes 10 seconds).
 	- use a partition below the 1024 cyl boundary to hold the linux
 	boot files (kernel images and /boot directory), and place the rest
 	of linux anywhere else on the drive.  These files can reside in a DOS
 	partition, or in a tailor-made linux boot partition.
+	- use DiskManager software from OnTrack, supplied free with
+	many new hard drive purchases.
+	- use EZ-Drive software (similar to DiskManager).  Note though,
+	that LILO must *not* use the MBR when EZ-Drive is present.
+	Instead, install LILO on the first sector of your linux partition,
+	and mark it as "active" or "bootable" with fdisk.
+	- boot from a floppy disk instead of the hard drive (takes 10 seconds).
 
 If you cannot use drive translation, *and* your BIOS also restricts you to
 entering no more than 1024 cylinders in the geometry field in the CMOS setup,
diff -u --recursive --new-file v1.3.57/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c
--- v1.3.57/linux/drivers/block/cmd640.c	Sun Dec 17 11:43:12 1995
+++ linux/drivers/block/cmd640.c	Sun Jan 14 16:41:39 1996
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/block/cmd640.c	Version 0.02  Nov 30, 1995
+ *  linux/drivers/block/cmd640.c	Version 0.04  Jan 11, 1996
  *
- *  Copyright (C) 1995  Linus Torvalds & author (see below)
+ *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
  */
 
 /*
@@ -18,8 +18,49 @@
  *			read-ahead for versions 'B' and 'C' of chip by
  *			default, some code cleanup.
  *
+ *  Version 0.03	Added reset of secondary interface,
+ *			and black list for devices which are not compatible
+ *			with read ahead mode. Separate function for setting
+ *			readahead is added, possibly it will be called some
+ *			day from ioctl processing code.
+ *
+ *  Version 0.04	Now configs/compiles separate from ide.c  -ml
+ */
+
+/*
+ *  There is a known problem with current version of this driver.
+ *  If the only device on secondary interface is CD-ROM, at some
+ *  computers it is not recognized. In all reported cases CD-ROM
+ *  was 2x or 4x speed Mitsumi drive.
+ *
+ *  The following workarounds could work:
+ * 
+ *    1. put CD-ROM as slave on primary interface
+ *
+ *    2. or define symbol at next line as 0
+ * 
  */
 
+#define CMD640_NORMAL_INIT 1
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+
+#include "ide.h"
+
+extern ide_hwif_t ide_hwifs[];
+
+int cmd640_vlb = 0;
+
 /*
  * CMD640 specific registers definition.
  */
@@ -76,7 +117,7 @@
 
 /*
  * For some unknown reasons pcibios functions which read and write registers
- * do not work with cmd640. We use direct io instead.
+ * do not always work with cmd640. We use direct io instead.
  */
 
 /* PCI method 1 access */
@@ -230,6 +271,35 @@
 }
 
 /*
+ * Low level reset for controller, actually it has nothing specific for
+ * CMD640, but I don't know how to use standard reset routine before
+ * we recognized any drives.
+ */
+
+static void cmd640_reset_controller(int iface_no)
+{
+	int retry_count = 600;
+	int base_port = iface_no ? 0x170 : 0x1f0;
+
+	outb_p(4, base_port + 7);
+	udelay(5);
+	outb_p(0, base_port + 7);
+
+	do {
+		udelay(5);
+		retry_count -= 1;
+	} while ((inb_p(base_port + 7) & 0x80) && retry_count);
+
+	if (retry_count == 0)
+		printk("cmd640: failed to reset controller %d\n", iface_no);
+#if 0	
+	else
+		printk("cmd640: controller %d reset [%d]\n", 
+			iface_no, retry_count);
+#endif
+}
+
+/*
  * Probe for Cmd640x and initialize it if found
  */
 
@@ -282,31 +352,34 @@
 
 	/*
 	 * Set the maximum allowed bus speed (it is safest until we
-	 * 				      find how detect bus speed)
+	 * 				      find how to detect bus speed)
 	 * Normally PCI bus runs at 33MHz, but often works overclocked to 40
 	 */
 	bus_speed = (bus_type == vlb) ? 50 : 40; 
 
-#if 1	/* don't know if this is reliable yet */
 	/*
 	 * Enable readahead for versions above 'A'
 	 */
 	cmd_read_ahead = (cmd640_chip_version > 1);
-#else
-	cmd_read_ahead = 0;
-#endif
+
 	/*
 	 * Setup Control Register
 	 */
 	b = get_cmd640_reg(cmd640_key, CNTRL);	
+
+#if CMD640_NORMAL_INIT
 	if (second_port)
 		b |= CNTRL_ENA_2ND;
 	else
 		b &= ~CNTRL_ENA_2ND;
+#endif 
+
 	if (cmd_read_ahead)
 		b &= ~(CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
 	else
 		b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
+
+
 	put_cmd640_reg(cmd640_key, CNTRL, b);
 
 	/*
@@ -317,9 +390,11 @@
 		b = cmd_read_ahead ? 0 : (DIS_RA2 | DIS_RA3);
 		put_cmd640_reg(cmd640_key, ARTTIM23, b);
 		put_cmd640_reg(cmd640_key, DRWTIM23, 0);
+
+		cmd640_reset_controller(1);
 	}
 
-	serialized = 1;
+	ide_hwifs[0].serialized = 1;
 
 	printk("ide: buggy CMD640%c interface at ", 
 	       'A' - 1 + cmd640_chip_version);
@@ -360,6 +435,48 @@
 }
 
 /*
+ * Sets readahead mode for specific drive
+ *  in the future it could be called from ioctl
+ */
+
+static void set_readahead_mode(int mode, int if_num, int dr_num)
+{
+	static int masks[2][2] = 
+		{ 
+			{CNTRL_DIS_RA0, CNTRL_DIS_RA1}, 
+			{DIS_RA2, 	DIS_RA3}
+		};
+
+	int port = (if_num == 0) ? CNTRL : ARTTIM23;
+	int mask = masks[if_num][dr_num];
+	byte b;
+
+	b = get_cmd640_reg(cmd640_key, port);
+	if (mode)
+		b &= mask; /* Enable readahead for specific drive */
+	else
+		b |= mask; /* Disable readahed for specific drive */
+	put_cmd640_reg(cmd640_key, port, b);
+}		
+
+static struct readahead_black_list {
+	const char* 	name;
+	int		mode;	
+} drives_ra[] = {
+	{ "ST3655A",	0 },
+ 	{ NULL, 0 }
+};	
+
+static int known_drive_readahead(char* name) {
+	int i;
+
+	for (i = 0; drives_ra[i].name != NULL; i++)
+		if (strcmp(name, drives_ra[i].name) == 0)
+			return drives_ra[i].mode;
+	return -1;
+}
+
+/*
  * Tuning of drive parameters
  */
 
@@ -400,7 +517,7 @@
 	}
 }
 
-struct pio_timing {
+static struct pio_timing {
 	int	mc_time;	/* Minimal cycle time (ns) */
 	int	av_time;	/* Address valid to DIOR-/DIOW- setup (ns) */
 	int	ds_time;	/* DIOR data setup	(ns) */
@@ -413,7 +530,7 @@
 	{ 20,	50,	100 }	/* PIO Mode ? */
 };
 
-struct drive_pio_info {
+static struct drive_pio_info {
 	const char	*name;
 	int		pio;
 } drive_pios[] = {
@@ -426,6 +543,7 @@
 	{ "QUANTUM LPS240A", 0 },
 	{ "QUANTUM LPS270A", 3 },
 	{ "QUANTUM LPS540A", 3 },
+	{ "QUANTUM FIREBALL1080A", 3 },
 	{ NULL,	0 }
 };
 
@@ -480,7 +598,7 @@
 	outb_p((drv_num | 0xa) << 4, p_base + 6);
 	outb_p(0xef, p_base + 7);
 	for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++)
-		delay_10ms();
+		udelay(10000);
 }
 
 void cmd640_tune_drive(ide_drive_t* drive) {
@@ -491,6 +609,7 @@
 	int mc_time, av_time, ds_time;
 	struct hd_driveid* id;
 	int r1, r2;
+	int mode;
 
 	/*
 	 * Determine if drive is under cmd640 control
@@ -530,6 +649,13 @@
 				&r1, &r2);
 	set_pio_mode(interface_number, drive_number, max_pio);
 	cmd640_set_timing(interface_number, drive_number, r1, r2);
+
+	/*
+	 * Disable (or set) readahead mode for known drive
+	 */
+	if ((mode = known_drive_readahead(id->model)) != -1) {
+		set_readahead_mode(mode, interface_number, drive_number);
+		printk("Readahead %s,", mode ? "enabled" : "disabled");
+	}
 	printk ("Mode and Timing set to PIO%d (0x%x 0x%x)\n", max_pio, r1, r2);
 }
-
diff -u --recursive --new-file v1.3.57/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v1.3.57/linux/drivers/block/ide-cd.c	Sat Dec 30 15:50:53 1995
+++ linux/drivers/block/ide-cd.c	Sun Jan 14 16:22:15 1996
@@ -108,7 +108,6 @@
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
-#define _IDE_CD_C	/* used in blk.h */
 #include "ide.h"
 
 
diff -u --recursive --new-file v1.3.57/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v1.3.57/linux/drivers/block/ide-tape.c	Thu Jan  4 21:54:54 1996
+++ linux/drivers/block/ide-tape.c	Sun Jan 14 16:22:15 1996
@@ -300,8 +300,6 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 
-#define _IDE_TAPE_C			/* For ide_end_request in blk.h */
-
 /*
  *	Main Linux ide driver include file
  *
diff -u --recursive --new-file v1.3.57/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.57/linux/drivers/block/ide.c	Thu Jan  4 21:54:54 1996
+++ linux/drivers/block/ide.c	Sun Jan 14 16:22:15 1996
@@ -1,8 +1,9 @@
 /*
- *  linux/drivers/block/ide.c	Version 5.24  Jan 4, 1996
+ *  linux/drivers/block/ide.c	Version 5.25  Jan 11, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
+#define _IDE_C		/* needed by <linux/blk.h> */
 
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
@@ -109,7 +110,7 @@
  *			assembly syntax tweak to vlb_sync
  *			removeable drive support from scuba@cs.tu-berlin.de
  *			add transparent support for DiskManager-6.0x "Dynamic
- *			 Disk Overlay" (DDO), most of this in in genhd.c
+ *			 Disk Overlay" (DDO), most of this is in genhd.c
  *			eliminate "multiple mode turned off" message at boot
  *  Version 4.10	fix bug in ioctl for "hdparm -c3"
  *			fix DM6:DDO support -- now works with LILO, fdisk, ...
@@ -180,11 +181,13 @@
  *  Version 5.22	fix ide_xlate_1024() to work with/without drive->id
  *  Version 5.23	miscellaneous touch-ups
  *  Version 5.24	fix #if's for SUPPORT_CMD640
+ *  Version 5.25	more touch-ups, fix cdrom resets, ...
+ *			cmd640.c now configs/compiles separate from ide.c
  *
  *  Driver compile-time options are in ide.h
  *
  *  To do, in likely order of completion:
- *	- make cmd640.c and umc8672.c compile separately from ide.c
+ *	- make umc8672.c compile separately from ide.c
  *	- add ALI M1443/1445 chipset support from derekn@vw.ece.cmu.edu
  *	- add ioctls to get/set interface timings on various interfaces
  *	- add Promise Caching controller support from peterd@pnd-pc.demon.co.uk
@@ -222,18 +225,12 @@
 
 #include "ide.h"
 
-#if SUPPORT_CMD640
-void cmd640_tune_drive(ide_drive_t *);
-static int cmd640_vlb = 0;
-#endif
-
        ide_hwif_t	ide_hwifs[MAX_HWIFS];		/* hwif info */
 static ide_hwgroup_t	*irq_to_hwgroup [16];
 static const byte	ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
 
 static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168};
 static const byte	default_irqs[MAX_HWIFS]     = {14, 15, 11, 10};
-static int		serialized = 0;		/* "serialize" option */
 static int		disallow_unmask = 0;	/* for buggy hardware */
 
 #if (DISK_RECOVERY_TIME > 0)
@@ -881,7 +878,8 @@
 	err = ide_dump_status(drive, msg, stat);
 	if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL)
 		return;
-	if (rq->cmd != READ && rq->cmd != WRITE) { /* retry only "normal" i/o */
+	/* retry only "normal" I/O: */
+	if (rq->cmd != READ && rq->cmd != WRITE && drive->media != ide_cdrom) {
 		rq->errors = 1;
 		ide_end_drive_cmd(drive, stat, err);
 		return;
@@ -1346,7 +1344,7 @@
 #if FAKE_FDISK_FOR_EZDRIVE
 	if (block == 0 && drive->ezdrive) {
 		block = 1;
-		printk("%s: [EZD] accessing sector 1 instead of sector 0\n", drive->name);
+		printk("%s: [EZD] accessing sector 1 in place of sector 0\n", drive->name);
 	}
 #endif /* FAKE_FDISK_FOR_EZDRIVE */
 	((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
@@ -2210,8 +2208,11 @@
 			printk(", DMA");
 	}
 	printk("\n");
-#if SUPPORT_CMD640
-	cmd640_tune_drive(drive);	/* but can we tune a fish? */
+#ifdef CONFIG_BLK_DEV_CMD640
+	{
+		extern void cmd640_tune_drive (ide_drive_t *);
+		cmd640_tune_drive(drive);	/* but can we tune a fish? */
+	}
 #endif
 }
 
@@ -2527,10 +2528,6 @@
 #include "umc8672.c"	/* until we tidy up the interface some more */
 #endif
 
-#if SUPPORT_CMD640
-#include "cmd640.c"	/* until we tidy up the interface some more */
-#endif
-
 /*
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
@@ -2699,12 +2696,15 @@
 				init_qd6580();
 				goto done;
 #endif /* SUPPORT_QD6580 */
-#if SUPPORT_CMD640
+#ifdef CONFIG_BLK_DEV_CMD640
 			case -5: /* "cmd640_vlb" */
+				{
+				extern int cmd640_vlb;
 				if (hw > 1) goto bad_hwif;
-				cmd640_vlb = 1;
+					cmd640_vlb = 1;
+				}
 				break;
-#endif /* SUPPORT_CMD640 */
+#endif /* CONFIG_BLK_DEV_CMD640 */
 #if SUPPORT_HT6560B
 			case -4: /* "ht6560b" */
 				if (hw > 1) goto bad_hwif;
@@ -2736,7 +2736,7 @@
 			case -2: /* "serialize" */
 			do_serialize:
 				if (hw > 1) goto bad_hwif;
-				serialized = 1;
+				ide_hwifs[0].serialized = 1;
 				goto done;
 			case -1: /* "noprobe" */
 				hwif->noprobe = 1;
@@ -2890,7 +2890,7 @@
 	 * Check for serialization with ide1.
 	 * This code depends on us having already taken care of ide1.
 	 */
-	if (serialized && hwif->name[3] == '0' && ide_hwifs[1].present)
+	if (hwif->serialized && hwif->name[3] == '0' && ide_hwifs[1].present)
 		hwgroup = ide_hwifs[1].hwgroup;
 	/*
 	 * If this is the first interface in a group,
@@ -2941,23 +2941,14 @@
 
 #ifdef CONFIG_PCI
 
-void ide_pci_access_error (int rc)
-{
-	printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
-}
+#if SUPPORT_RZ1000
 
-#if SUPPORT_RZ1000 || SUPPORT_CMD640
-void buggy_interface_fallback (int rc)
+static void ide_pci_access_error (int rc)
 {
-	ide_pci_access_error (rc);
-	serialized = 1;
-	disallow_unmask = 1;
-	printk("serialized, disabled unmasking\n");
+	printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
 }
-#endif /* SUPPORT_RZ1000 || SUPPORT_CMD640 */
 
-#if SUPPORT_RZ1000
-void init_rz1000 (byte bus, byte fn)
+static void init_rz1000 (byte bus, byte fn)
 {
 	int rc;
 	unsigned short reg;
@@ -2970,8 +2961,12 @@
 	} else {
 		if ((rc = pcibios_read_config_word(bus, fn, 0x40, &reg))
 		 || (rc =  pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff)))
-			buggy_interface_fallback (rc);
-		else
+		{
+			ide_pci_access_error (rc);
+			ide_hwifs[0].serialized = 1;
+			disallow_unmask = 1;
+			printk("serialized, disabled unmasking\n");
+		} else
 			printk("disabled read-ahead\n");
 	}
 }
@@ -3012,7 +3007,7 @@
 	/*
 	 * Apparently the BIOS32 services on Intel motherboards are buggy,
 	 * and won't find the PCI_DEVICE_ID_INTEL_82371_1 for us.
-	 * So we instead search for PCI_DEVICE_ID_INTEL_82371_0, and then add 1.
+	 * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0, and then add 1.
 	 */
 	ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
 #endif
@@ -3038,8 +3033,11 @@
 	if (pcibios_present())
 		ide_init_pci ();
 #endif /* CONFIG_PCI */
-#if SUPPORT_CMD640
-	ide_probe_for_cmd640x();
+#ifdef CONFIG_BLK_DEV_CMD640
+	{
+		extern void ide_probe_for_cmd640x (void);
+		ide_probe_for_cmd640x();
+	}
 #endif
 
 	/*
diff -u --recursive --new-file v1.3.57/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v1.3.57/linux/drivers/block/ide.h	Thu Jan  4 21:54:54 1996
+++ linux/drivers/block/ide.h	Thu Jan 18 10:17:35 1996
@@ -37,9 +37,6 @@
 #ifndef SUPPORT_RZ1000			/* 1 to support RZ1000 chipset */
 #define SUPPORT_RZ1000		1	/* 0 to reduce kernel size */
 #endif
-#ifndef SUPPORT_CMD640			/* 1 to support CMD640 chipset */
-#define SUPPORT_CMD640		1	/* 0 to reduce kernel size */
-#endif
 #ifndef SUPPORT_UMC8672			/* 1 to support UMC8672 chipset */
 #define SUPPORT_UMC8672		1	/* 0 to reduce kernel size */
 #endif
@@ -59,6 +56,10 @@
 #define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
 #endif
 
+#if defined(CONFIG_BLK_DEV_IDECD) || defined(CONFIG_BLK_DEV_IDETAPE)
+#define CONFIG_BLK_DEV_IDEATAPI 1
+#endif
+
 /*
  * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
  */
@@ -393,6 +394,7 @@
 	char 		name[5];	/* name of interface, eg. "ide0" */
 	unsigned	noprobe : 1;	/* don't probe for this interface */
 	unsigned	present : 1;	/* this interface exists */
+	unsigned	serialized : 1;	/* valid only for ide_hwifs[0] */
 #if (DISK_RECOVERY_TIME > 0)
 	unsigned long	last_time;	/* time when previous rq was done */
 #endif
@@ -603,4 +605,3 @@
 #ifdef CONFIG_BLK_DEV_TRITON
 void ide_init_triton (byte, byte);
 #endif /* CONFIG_BLK_DEV_TRITON */
-
diff -u --recursive --new-file v1.3.57/linux/drivers/block/triton.c linux/drivers/block/triton.c
--- v1.3.57/linux/drivers/block/triton.c	Sun Dec 17 11:43:13 1995
+++ linux/drivers/block/triton.c	Sun Jan 14 16:42:13 1996
@@ -1,7 +1,7 @@
 /*
- *  linux/drivers/block/triton.c	Version 1.04  Dec 1, 1995
+ *  linux/drivers/block/triton.c	Version 1.05  Jan 11, 1996
  *
- *  Copyright (c) 1995  Mark Lord
+ *  Copyright (c) 1995-1996  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
@@ -95,11 +95,6 @@
  *
  * And, yes, Intel Zappa boards really *do* use the Triton IDE ports.
  */
-#define _TRITON_C
-#include <linux/config.h>
-#ifndef CONFIG_BLK_DEV_TRITON
-#define CONFIG_BLK_DEV_TRITON y
-#endif
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
@@ -127,15 +122,15 @@
  * Our Physical Region Descriptor (PRD) table should be large enough
  * to handle the biggest I/O request we are likely to see.  Since requests
  * can have no more than 256 sectors, and since the typical blocksize is
- * two sectors, we can get by with a limit of 128 entries here for the
+ * two sectors, we could get by with a limit of 128 entries here for the
  * usual worst case.  Most requests seem to include some contiguous blocks,
  * further reducing the number of table entries required.
  *
- * Note that the driver reverts to PIO mode for individual requests that exceed
+ * The driver reverts to PIO mode for individual requests that exceed
  * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
  * 100% of all crazy scenarios here is not necessary.
  *
- * As it turns out, though, we must allocate a full 4KB page for this,
+ * As it turns out though, we must allocate a full 4KB page for this,
  * so the two PRD tables (ide0 & ide1) will each get half of that,
  * allowing each to have about 256 entries (8 bytes each) from this.
  */
@@ -288,7 +283,7 @@
 	outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */
 	outb(reading, dma_base);			/* specify r/w */
 	outb(0x26, dma_base+2);				/* clear status bits */
-	ide_set_handler (drive, &dma_intr, WAIT_CMD);	/* issue cmd to drive */
+	ide_set_handler(drive, &dma_intr, WAIT_CMD);	/* issue cmd to drive */
 	OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 	outb(inb(dma_base)|1, dma_base);		/* begin DMA */
 	return 0;
@@ -316,6 +311,48 @@
 	printk(" fastPIO=%s\n",	((flags&9)==1)	? "on " : "off");
 }
 
+static void init_triton_dma (ide_hwif_t *hwif, unsigned short base)
+{
+	static unsigned long dmatable = 0;
+
+	printk("    %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+7);
+	if (check_region(base, 8)) {
+		printk(" -- ERROR, PORTS ALREADY IN USE");
+	} else {
+		request_region(base, 8, hwif->name);
+		hwif->dma_base = base;
+		if (!dmatable) {
+			/*
+			 * Since we know we are on a PCI bus, we could
+			 * actually use __get_free_pages() here instead
+			 * of __get_dma_pages() -- no ISA limitations.
+			 */
+			dmatable = __get_dma_pages(GFP_KERNEL, 0);
+		}
+		if (dmatable) {
+			hwif->dmatable = (unsigned long *) dmatable;
+			dmatable += (PRD_ENTRIES * PRD_BYTES);
+			outl(virt_to_bus(hwif->dmatable), base + 4);
+			hwif->dmaproc  = &triton_dmaproc;
+		}
+	}
+	printk("\n");
+}
+
+/*
+ * calc_mode() returns the ATA PIO mode number, based on the number
+ * of cycle clks passed in.  Assumes 33Mhz bus operation (30ns per clk).
+ */
+byte calc_mode (byte clks)
+{
+	if (clks == 3)	return 5;
+	if (clks == 4)	return 4;
+	if (clks <  6)	return 3;
+	if (clks <  8)	return 2;
+	if (clks < 13)	return 1;
+	return 0;
+}
+
 /*
  * ide_init_triton() prepares the IDE driver for DMA operation.
  * This routine is called once, from ide.c during driver initialization,
@@ -324,26 +361,33 @@
 void ide_init_triton (byte bus, byte fn)
 {
 	int rc = 0, h;
+	int dma_enabled = 0;
 	unsigned short bmiba, pcicmd;
 	unsigned int timings;
-	unsigned long dmatable = 0;
 	extern ide_hwif_t ide_hwifs[];
 
+	printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn);
 	/*
 	 * See if IDE and BM-DMA features are enabled:
 	 */
 	if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)))
 		goto quit;
-	if ((pcicmd & 5) != 5) {
-		if ((pcicmd & 1) == 0)
-			printk("ide: Triton IDE ports are not enabled\n");
-		else
-			printk("ide: Triton BM-DMA feature is not enabled\n");
+	if ((pcicmd & 1) == 0)  {
+		printk("ide: Triton IDE ports are not enabled\n");
 		goto quit;
 	}
-#if 0
-	(void) pcibios_write_config_word(bus, fn, 0x42, 0x8037); /* for my MC2112A */
-#endif
+	if ((pcicmd & 4) == 0) {
+		printk("ide: Triton BM-DMA feature is not enabled -- upgrade your BIOS\n");
+	} else {
+		/*
+		 * Get the bmiba base address
+		 */
+		if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba)))
+			goto quit;
+		bmiba &= 0xfff0;	/* extract port base address */
+		dma_enabled = 1;
+	}
+
 	/*
 	 * See if ide port(s) are enabled
 	 */
@@ -353,52 +397,32 @@
 		printk("ide: neither Triton IDE port is enabled\n");
 		goto quit;
 	}
-	printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn);
-
-	/*
-	 * Get the bmiba base address
-	 */
-	if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba)))
-		goto quit;
-	bmiba &= 0xfff0;	/* extract port base address */
 
 	/*
 	 * Save the dma_base port addr for each interface
 	 */
 	for (h = 0; h < MAX_HWIFS; ++h) {
+		byte s_clks, r_clks;
 		ide_hwif_t *hwif = &ide_hwifs[h];
-		unsigned short base, time;
-		if (hwif->io_base == 0x1f0 && (timings & 0x8000)) {
+		unsigned short time;
+		if (hwif->io_base == 0x1f0) {
 			time = timings & 0xffff;
-			base = bmiba;
-		} else if (hwif->io_base == 0x170 && (timings & 0x80000000)) {
+			if ((timings & 0x8000) == 0)	/* interface enabled? */
+				continue;
+			if (dma_enabled)
+				init_triton_dma(hwif, bmiba);
+		} else if (hwif->io_base == 0x170) {
 			time = timings >> 16;
-			base = bmiba + 8;
+			if ((timings & 0x8000) == 0)	/* interface enabled? */
+				continue;
+			if (dma_enabled)
+				init_triton_dma(hwif, bmiba + 8);
 		} else
 			continue;
-		printk("    %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+7);
-		if (check_region(base, 8)) {
-			printk(" -- ERROR, PORTS ALREADY IN USE");
-		} else {
-			request_region(base, 8, hwif->name);
-			hwif->dma_base = base;
-			if (!dmatable) {
-				/*
-				 * Since we know we are on a PCI bus, we could
-				 * actually use __get_free_pages() here instead
-				 * of __get_dma_pages() -- no ISA limitations.
-				 */
-				dmatable = __get_dma_pages(GFP_KERNEL, 0);
-			}
-			if (dmatable) {
-				hwif->dmatable = (unsigned long *) dmatable;
-				dmatable += (PRD_ENTRIES * PRD_BYTES);
-				outl(virt_to_bus(hwif->dmatable), base + 4);
-				hwif->dmaproc  = &triton_dmaproc;
-			}
-		}
-		printk("\n    %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
-		 hwif->name, time, ((~time>>12)&3)+2, ((~time>>8)&3)+1);
+		s_clks = ((~time >> 12) & 3) + 2;
+		r_clks = ((~time >>  8) & 3) + 1;
+		printk("    %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d (PIO mode%d)\n",
+		 hwif->name, time, s_clks, r_clks, calc_mode(s_clks+r_clks));
 		print_triton_drive_flags (0, time & 0xf);
 		print_triton_drive_flags (1, (time >> 4) & 0xf);
 	}
diff -u --recursive --new-file v1.3.57/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- v1.3.57/linux/drivers/cdrom/mcdx.c	Tue Nov 21 13:22:08 1995
+++ linux/drivers/cdrom/mcdx.c	Sun Jan 14 16:22:16 1996
@@ -1,7 +1,7 @@
 /*
  * The Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.5
+ * VERSION: 1.5a
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@
 
 #if RCS
 static const char *mcdx_c_version
-		= "mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp";
+		= "mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp";
 #endif
 
 #include <linux/version.h>
@@ -768,8 +768,10 @@
 		/* invalidate_inodes(ip->i_rdev); */
 		invalidate_buffers(ip->i_rdev);
 
+#if !MCDX_QUIET
 		if (-1 == mcdx_lockdoor(stuffp, 0, 3))
 				INFO(("close() Cannot unlock the door\n"));
+#endif
 
         /* eject if wished */
         if (stuffp->eject_sw) mcdx_eject(stuffp, 1);
@@ -794,10 +796,8 @@
 
 void mcdx_setup(char *str, int *pi)
 {
-#if MCDX_DEBUG
-    printk(MCDX ":: setup(%s, %d) called\n",
-	    str, pi[0]);
-#endif
+	if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
+	if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
 }
 
 /* DIRTY PART ******************************************************/ 
@@ -1051,10 +1051,10 @@
 {
 	int drive;
 
-	WARN(("Version 1.5 "
-			"mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp\n"));
-	INFO((": Version 1.5 "
-			"mcdx.c,v 1.19 1995/11/20 17:06:25 heiko Exp\n"));
+	WARN(("Version 1.5a "
+			"mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n"));
+	INFO((": Version 1.5a "
+			"mcdx.c,v 1.19.2.1 1996/01/13 21:25:55 heiko Exp\n"));
 
 	/* zero the pointer array */
 	for (drive = 0; drive < MCDX_NDRIVES; drive++)
@@ -1245,7 +1245,7 @@
 	stuffp->lock = current->pid;
 
 	do {
-	    int sig = 0;
+	    /* int sig = 0; */
 	    int to = 0;
 
 		/* wait for the drive become idle */
diff -u --recursive --new-file v1.3.57/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c
--- v1.3.57/linux/drivers/cdrom/optcd.c	Mon Nov 27 12:48:29 1995
+++ linux/drivers/cdrom/optcd.c	Thu Jan 18 06:22:13 1996
@@ -1,12 +1,13 @@
-/*	$Id: optcd.c,v 1.3 1995/08/24 19:54:27 root Exp root $
-	linux/drivers/block/optcd.c - Optics Storage 8000 AT CDROM driver
+/*	linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver
+	$Id: optcd.c,v 1.20 1996/01/17 19:44:39 root Exp root $
 
 	Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
 
+
 	Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
 	by Eberhard Moenkeberg (emoenke@gwdg.de). ISP16 detection and
-	configuration by Eric van der Maarel (maarel@marin.nl), with some data
-	communicated by Vadim V. Model (vadim@rbrf.msk.su).
+	configuration by Eric van der Maarel (maarel@marin.nl) and
+	Vadim Model (vadim@cecmow.enet.dec.com).
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
@@ -21,8 +22,11 @@
 	You should have received a copy of the GNU General Public License
 	along with this program; if not, write to the Free Software
 	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*	Revision history
+
 
-	History
 	14-5-95		v0.0	Plays sound tracks. No reading of data CDs yet.
 				Detection of disk change doesn't work.
 	21-5-95		v0.1	First ALPHA version. CD can be mounted. The
@@ -47,308 +51,379 @@
 				Updated README.optcd. Submitted for
 				inclusion in 1.3.21
 	29-9-95		v0.4a	Fixed bug that prevented compilation as module
+	25-10-95	v0.5	Started multisession code. Implementation
+				copied from Werner Zimmermann, who copied it
+				from Heiko Schlittermann's mcdx.
+	17-1-96		v0.6	Multisession works; some cleanup too.
 */
+
+/* Includes */
 
-#include <linux/module.h>
 
-#include <linux/errno.h>
+#include <linux/module.h>
 #include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
 #include <linux/ioport.h>
-#include <linux/major.h>
-
 #include <asm/io.h>
 
 #define MAJOR_NR OPTICS_CDROM_MAJOR
+#include <linux/blk.h>
 
-# include <linux/blk.h>
-#define optcd_port optcd	/* Needed for the modutils. */
-# include <linux/optcd.h>
-
-
-/* Some (Media)Magic */
-/* define types of drive the interface on an ISP16 card may be looking at */
-#define ISP16_DRIVE_X 0x00
-#define ISP16_SONY  0x02
-#define ISP16_PANASONIC0 0x02
-#define ISP16_SANYO0 0x02
-#define ISP16_MITSUMI  0x04
-#define ISP16_PANASONIC1 0x06
-#define ISP16_SANYO1 0x06
-#define ISP16_DRIVE_NOT_USED 0x08  /* not used */
-#define ISP16_DRIVE_SET_MASK 0xF1  /* don't change 0-bit or 4-7-bits*/
-/* ...for port */
-#define ISP16_DRIVE_SET_PORT 0xF8D
-/* set io parameters */
-#define ISP16_BASE_340  0x00
-#define ISP16_BASE_330  0x40
-#define ISP16_BASE_360  0x80
-#define ISP16_BASE_320  0xC0
-#define ISP16_IRQ_X  0x00
-#define ISP16_IRQ_5  0x04  /* shouldn't be used due to soundcard conflicts */
-#define ISP16_IRQ_7  0x08  /* shouldn't be used due to soundcard conflicts */
-#define ISP16_IRQ_3  0x0C
-#define ISP16_IRQ_9  0x10
-#define ISP16_IRQ_10  0x14
-#define ISP16_IRQ_11  0x18
-#define ISP16_DMA_X  0x03
-#define ISP16_DMA_3  0x00
-#define ISP16_DMA_5  0x00
-#define ISP16_DMA_6  0x01
-#define ISP16_DMA_7  0x02
-#define ISP16_IO_SET_MASK  0x20  /* don't change 5-bit */
-/* ...for port */
-#define ISP16_IO_SET_PORT  0xF8E
-/* enable the drive */
-#define ISP16_NO_IDE__ENABLE_CDROM_PORT  0xF90  /* ISP16 without IDE interface */
-#define ISP16_IDE__ENABLE_CDROM_PORT  0xF91  /* ISP16 with IDE interface */
-#define ISP16_ENABLE_CDROM  0x80  /* seven bit */
-
-/* the magic stuff */
-#define ISP16_CTRL_PORT  0xF8F
-#define ISP16_NO_IDE__CTRL  0xE2  /* ISP16 without IDE interface */
-#define ISP16_IDE__CTRL  0xE3  /* ISP16 with IDE interface */
-
-static short isp16_detect(void);
-static short isp16_no_ide__detect(void);
-static short isp16_with_ide__detect(void);
-static short isp16_config( int base, u_char drive_type, int irq, int dma );
-static short isp16_type; /* dependent on type of interface card */
-static u_char isp16_ctrl;
-static u_short isp16_enable_cdrom_port;
+#include <linux/cdrom.h>
+#include <linux/optcd.h>
 
+#ifdef PROBE_ISP16
+#include "optcd_isp16.h"	/* optional ISP16 detection/configuration */
+#endif
+
+/* Debug support */
 
-static short optcd_port = OPTCD_PORTBASE;
 
-/* Read current status/data availability flags */
-inline static int optFlags(void) {
-	return inb(STATUS_PORT) & FL_STDT;
-}
+/* Don't forget to add new debug flags here. */
+#if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
+    DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
+#define DEBUG(x) debug x
+static void debug(int debug_this, const char* fmt, ...)
+{
+	char s[1024];
+	va_list args;
 
-/* Wait for status available; return TRUE on timeout */
-static int sten_low(void) {
-	int no_status;
-	unsigned long count = 0;
-	while ((no_status = (optFlags() & FL_STEN)))
-		if (++count >= BUSY_TIMEOUT)
-			break;
-#ifdef DEBUG_DRIVE_IF
-	if (no_status)
-		printk("optcd: timeout waiting for STEN low\n");
-	else
-		printk("optcd: STEN low after %ld\n", count);
-#endif
-	return no_status;
-}
+	if (!debug_this)
+		return;
+
+	va_start(args, fmt);
+	vsprintf(s, fmt, args);
+	printk("optcd: %s\n", s);
+	va_end(args);
+}
+#else
+#define DEBUG(x)
+#endif
+
+/* Drive hardware/firmware characteristics
+   Identifiers in accordance with Optics Storage documentation */
+
+
+#define optcd_port optcd			/* Needed for the modutils. */
+static short optcd_port = OPTCD_PORTBASE;	/* I/O base of drive. */
+
+/* Drive registers, read */
+#define DATA_PORT	optcd_port	/* Read data/status */
+#define STATUS_PORT	optcd_port+1	/* Indicate data/status availability */
+
+/* Drive registers, write */
+#define COMIN_PORT	optcd_port	/* For passing command/parameter */
+#define RESET_PORT	optcd_port+1	/* Write anything and wait 0.5 sec */
+#define HCON_PORT	optcd_port+2	/* Host Xfer Configuration */
+
+
+/* Command completion/status read from DATA register */
+#define ST_DRVERR		0x80
+#define ST_DOOR_OPEN		0x40
+#define ST_MIXEDMODE_DISK	0x20
+#define ST_MODE_BITS		0x1c
+#define ST_M_STOP		0x00
+#define ST_M_READ		0x04
+#define ST_M_AUDIO		0x04
+#define ST_M_PAUSE		0x08
+#define ST_M_INITIAL		0x0c
+#define ST_M_ERROR		0x10
+#define ST_M_OTHERS		0x14
+#define	ST_MODE2TRACK		0x02
+#define	ST_DSK_CHG		0x01
+#define ST_L_LOCK		0x01
+#define ST_CMD_OK		0x00
+#define ST_OP_OK		0x01
+#define ST_PA_OK		0x02
+#define ST_OP_ERROR		0x05
+#define ST_PA_ERROR		0x06
+
+
+/* Error codes (appear as command completion code from DATA register) */
+/* Player related errors */
+#define ERR_ILLCMD	0x11	/* Illegal command to player module */
+#define ERR_ILLPARM	0x12	/* Illegal parameter to player module */
+#define ERR_SLEDGE	0x13
+#define ERR_FOCUS	0x14
+#define ERR_MOTOR	0x15
+#define ERR_RADIAL	0x16
+#define ERR_PLL		0x17	/* PLL lock error */
+#define ERR_SUB_TIM	0x18	/* Subcode timeout error */
+#define ERR_SUB_NF	0x19	/* Subcode not found error */
+#define ERR_TRAY	0x1a
+#define ERR_TOC		0x1b	/* Table of Contents read error */
+#define ERR_JUMP	0x1c
+/* Data errors */
+#define ERR_MODE	0x21
+#define ERR_FORM	0x22
+#define ERR_HEADADDR	0x23	/* Header Address not found */
+#define ERR_CRC		0x24
+#define ERR_ECC		0x25	/* Uncorrectable ECC error */
+#define ERR_CRC_UNC	0x26	/* CRC error and uncorrectable error */
+#define ERR_ILLBSYNC	0x27	/* Illegal block sync error */
+#define ERR_VDST	0x28	/* VDST not found */
+/* Timeout errors */
+#define ERR_READ_TIM	0x31	/* Read timeout error */
+#define ERR_DEC_STP	0x32	/* Decoder stopped */
+#define ERR_DEC_TIM	0x33	/* Decoder interrupt timeout error */
+/* Function abort codes */
+#define ERR_KEY		0x41	/* Key -Detected abort */
+#define ERR_READ_FINISH	0x42	/* Read Finish */
+/* Second Byte diagnostic codes */
+#define ERR_NOBSYNC	0x01	/* No block sync */
+#define ERR_SHORTB	0x02	/* Short block */
+#define ERR_LONGB	0x03	/* Long block */
+#define ERR_SHORTDSP	0x04	/* Short DSP word */
+#define ERR_LONGDSP	0x05	/* Long DSP word */
+
+
+/* Status availability flags read from STATUS register */
+#define FL_EJECT	0x20
+#define FL_WAIT		0x10	/* active low */
+#define FL_EOP		0x08	/* active low */
+#define FL_STEN		0x04	/* Status available when low */
+#define FL_DTEN		0x02	/* Data available when low */
+#define FL_DRQ		0x01	/* active low */
+#define FL_RESET	0xde	/* These bits are high after a reset */
+#define FL_STDT		(FL_STEN|FL_DTEN)
+
+
+/* Transfer mode, written to HCON register */
+#define HCON_DTS	0x08
+#define HCON_SDRQB	0x04
+#define HCON_LOHI	0x02
+#define HCON_DMA16	0x01
+
+
+/* Drive command set, written to COMIN register */
+/* Quick response commands */
+#define COMDRVST	0x20	/* Drive Status Read */
+#define COMERRST	0x21	/* Error Status Read */
+#define COMIOCTLISTAT	0x22	/* Status Read; reset disk changed bit */
+#define COMINITSINGLE	0x28	/* Initialize Single Speed */
+#define COMINITDOUBLE	0x29	/* Initialize Double Speed */
+#define COMUNLOCK	0x30	/* Unlock */
+#define COMLOCK		0x31	/* Lock */
+#define COMLOCKST	0x32	/* Lock/Unlock Status */
+#define COMVERSION	0x40	/* Get Firmware Revision */
+#define COMVOIDREADMODE	0x50	/* Void Data Read Mode */
+/* Read commands */
+#define COMFETCH	0x60	/* Prefetch Data */
+#define COMREAD		0x61	/* Read */
+#define COMREADRAW	0x62	/* Read Raw Data */
+#define COMREADALL	0x63	/* Read All 2646 Bytes */
+/* Player control commands */
+#define COMLEADIN	0x70	/* Seek To Lead-in */
+#define COMSEEK		0x71	/* Seek */
+#define COMPAUSEON	0x80	/* Pause On */
+#define COMPAUSEOFF	0x81	/* Pause Off */
+#define COMSTOP		0x82	/* Stop */
+#define COMOPEN		0x90	/* Open Tray Door */
+#define COMCLOSE	0x91	/* Close Tray Door */
+#define COMPLAY		0xa0	/* Audio Play */
+#define COMPLAY_TNO	0xa2	/* Audio Play By Track Number */
+#define COMSUBQ		0xb0	/* Read Sub-q Code */
+#define COMLOCATION	0xb1	/* Read Head Position */
+/* Audio control commands */
+#define COMCHCTRL	0xc0	/* Audio Channel Control */
+/* Miscellaneous (test) commands */
+#define COMDRVTEST	0xd0	/* Write Test Bytes */
+#define COMTEST		0xd1	/* Diagnostic Test */
+
+/* Low level drive interface. Only here we do actual I/O
+   Waiting for status / data available */
 
-/* Wait for data available; return TRUE on timeout */
-static int dten_low(void) {
-	int no_data;
+
+/* Busy wait until FLAG goes low. Return 0 on timeout. */
+inline static int flag_low(int flag, unsigned long timeout)
+{
+	int flag_high;
 	unsigned long count = 0;
-	while ((no_data = (optFlags() & FL_DTEN)))
-		if (++count >= BUSY_TIMEOUT)
+
+	while ((flag_high = (inb(STATUS_PORT) & flag)))
+		if (++count >= timeout)
 			break;
-#ifdef DEBUG_DRIVE_IF
-	if (no_data)
-		printk("optcd: timeout waiting for DTEN low\n");
-	else
-		printk("optcd: DTEN low after %ld\n", count);
-#endif
-	return no_data;
+
+	DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
+		flag, count, flag_high ? " timeout" : ""));
+	return !flag_high;
 }
 
-/* Facilities for polled waiting for status or data */
-static int sleep_timeout;		/* Max amount of time still to sleep */
-static unsigned char sleep_flags;	/* Flags read last time around */
+
+/* Timed waiting for status or data */
+static int sleep_timeout;	/* max # of ticks to sleep */
 static struct wait_queue *waitq = NULL;
 static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL};
 
-/* Timer routine: wake up when either of FL_STEN or FL_DTEN goes down,
- * or when timeout expires. Otherwise wait some more.
- */
-static void sleep_timer(void) {
-	if ((sleep_flags = optFlags()) != FL_STDT) {
-		wake_up(&waitq);
-		return;
-	}
-	if (--sleep_timeout <= 0) {
+#define SET_TIMER(func, jifs) \
+	delay_timer.expires = jiffies+(jifs); \
+	delay_timer.function = (void *) (func); \
+	add_timer(&delay_timer);
+#define CLEAR_TIMER	del_timer(&delay_timer)
+
+
+/* Timer routine: wake up when desired flag goes low,
+   or when timeout expires. */
+static void sleep_timer(void)
+{
+	int flags = inb(STATUS_PORT) & FL_STDT;
+
+	if (flags == FL_STDT && --sleep_timeout > 0) {
+		SET_TIMER(sleep_timer, HZ/100); /* multi-statement macro */
+	} else
 		wake_up(&waitq);
-		return;
-	}
-	SET_TIMER(sleep_timer, 1);
 }
 
-/* Sleep until any of FL_STEN or FL_DTEN go down, or until timeout.
- * sleep_timeout must be set first.
- */
-static int sleep_status(void) {
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: sleeping %d on status\n", sleep_timeout);
-#endif
-	if (sleep_timeout <= 0)		/* timeout immediately */
-		return FL_STDT;
-	if ((sleep_flags = optFlags()) == FL_STDT) {
-		SET_TIMER(sleep_timer, 1);
+
+/* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
+static int sleep_flag_low(int flag, unsigned long timeout)
+{
+	int flag_high;
+
+	DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
+
+	sleep_timeout = timeout;
+	flag_high = inb(STATUS_PORT) & flag;
+	if (flag_high && sleep_timeout > 0) {
+		SET_TIMER(sleep_timer, HZ/100);
 		sleep_on(&waitq);
+		flag_high = inb(STATUS_PORT) & flag;
 	}
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: woken up with %d to go, flags %d\n",
-		sleep_timeout, sleep_flags);
-#endif
-	return sleep_flags;
-}
 
-/* Sleep until status available; return TRUE on timeout */
-inline static int sleep_sten_low(void) {
-	int flags;
-	sleep_timeout = SLEEP_TIMEOUT;
-	flags = sleep_status();
-#ifdef DEBUG_DRIVE_IF
-	if (!(flags & FL_DTEN))
-		printk("optcd: DTEN while waiting for STEN\n");
-#endif
-	return flags & FL_STEN;
+	DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
+		flag, timeout, flag_high ? " timeout" : ""));
+	return !flag_high;
 }
+
+/* Low level drive interface. Only here we do actual I/O
+   Sending commands and parameters */
+
+
+/* Errors in the command protocol */
+#define ERR_IF_CMD_TIMEOUT	0x100
+#define ERR_IF_ERR_TIMEOUT	0x101
+#define ERR_IF_RESP_TIMEOUT	0x102
+#define ERR_IF_DATA_TIMEOUT	0x103
+#define ERR_IF_NOSTAT		0x104
 
-/* Sleep until data available; return TRUE on timeout */
-inline static int sleep_dten_low(void) {
-	int flags;
-	sleep_timeout = SLEEP_TIMEOUT;
-	flags = sleep_status();
-#ifdef DEBUG_DRIVE_IF
-	if (!(flags & FL_STEN))
-		printk("optcd: STEN while waiting for DTEN\n");
-#endif
-	return flags & FL_DTEN;
-}
 
 /* Send command code. Return <0 indicates error */
-static int optSendCmd(int cmd) {
+static int send_cmd(int cmd)
+{
 	unsigned char ack;
-#if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS)
-	printk("optcd: executing command 0x%02x\n", cmd);
-#endif
+
+	DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
+
 	outb(HCON_DTS, HCON_PORT);	/* Enable Suspend Data Transfer */
 	outb(cmd, COMIN_PORT);		/* Send command code */
-	if (sten_low())			/* Wait for status available */
+	if (!flag_low(FL_STEN, BUSY_TIMEOUT))	/* Wait for status */
 		return -ERR_IF_CMD_TIMEOUT;
 	ack = inb(DATA_PORT);		/* read command acknowledge */
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: acknowledge code 0x%02x\n", ack);
-#endif
 	outb(HCON_SDRQB, HCON_PORT);	/* Disable Suspend Data Transfer */
 	return ack==ST_OP_OK ? 0 : -ack;
 }
 
+
 /* Send command parameters. Return <0 indicates error */
-static int optSendParams(struct opt_Play_msf *params) {
+static int send_params(struct cdrom_msf *params)
+{
 	unsigned char ack;
-#if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS)
-	printk("optcd: params %02x:%02x:%02x %02x:%02x:%02x\n",
-		params->start.min, params->start.sec, params->start.frame,
-		params->end.min, params->end.sec, params->end.frame);
-#endif
-	outb(params -> start.min, COMIN_PORT);
-	outb(params -> start.sec, COMIN_PORT);
-	outb(params -> start.frame, COMIN_PORT);
-	outb(params -> end.min, COMIN_PORT);
-	outb(params -> end.sec, COMIN_PORT);
-	outb(params -> end.frame, COMIN_PORT);
-	if (sten_low())			/* Wait for status available */
+
+	DEBUG((DEBUG_DRIVE_IF, "sending parameters"
+		" %02x:%02x:%02x"
+		" %02x:%02x:%02x",
+		params->cdmsf_min0,
+		params->cdmsf_sec0,
+		params->cdmsf_frame0,
+		params->cdmsf_min1,
+		params->cdmsf_sec1,
+		params->cdmsf_frame1));
+
+	outb(params->cdmsf_min0, COMIN_PORT);
+	outb(params->cdmsf_sec0, COMIN_PORT);
+	outb(params->cdmsf_frame0, COMIN_PORT);
+	outb(params->cdmsf_min1, COMIN_PORT);
+	outb(params->cdmsf_sec1, COMIN_PORT);
+	outb(params->cdmsf_frame1, COMIN_PORT);
+	if (!flag_low(FL_STEN, BUSY_TIMEOUT))	/* Wait for status */
 		return -ERR_IF_CMD_TIMEOUT;
 	ack = inb(DATA_PORT);		/* read command acknowledge */
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: acknowledge code 0x%02x\n", ack);
-#endif
 	return ack==ST_PA_OK ? 0 : -ack;
 }
 
-/* Return execution status for quick response commands, i.e. busy wait.
- * Return value <0 indicates timeout.
- */
-static int optGetExecStatus(void) {
-	unsigned char exec_status;
-	if (sten_low())			/* Wait for status available */
+
+/* Send parameters for SEEK command. Return <0 indicates error */
+static int send_seek_params(struct cdrom_msf *params)
+{
+	unsigned char ack;
+
+	DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
+		" %02x:%02x:%02x",
+		params->cdmsf_min0,
+		params->cdmsf_sec0,
+		params->cdmsf_frame0));
+
+	outb(params->cdmsf_min0, COMIN_PORT);
+	outb(params->cdmsf_sec0, COMIN_PORT);
+	outb(params->cdmsf_frame0, COMIN_PORT);
+	if (!flag_low(FL_STEN, BUSY_TIMEOUT))	/* Wait for status */
 		return -ERR_IF_CMD_TIMEOUT;
-	exec_status = inb(DATA_PORT);	/* read command execution status */
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: returned execution status: 0x%02x\n", exec_status);
-#endif
-	return exec_status;
+	ack = inb(DATA_PORT);		/* read command acknowledge */
+	return ack==ST_PA_OK ? 0 : -ack;
 }
 
-/* Return execution status for slow commands. Only use when no data is
- * expected. Return value <0 indicates timeout.
- */
-static int optSleepTillExecStatus(void) {
+
+/* Wait for command execution status. Choice between busy waiting
+   and sleeping. Return value <0 indicates timeout. */
+inline static int get_exec_status(int busy_waiting)
+{
 	unsigned char exec_status;
-	if (sleep_sten_low())		/* Wait for status available */
+
+	if (busy_waiting
+	    ? !flag_low(FL_STEN, BUSY_TIMEOUT)
+	    : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
 		return -ERR_IF_CMD_TIMEOUT;
-	exec_status = inb(DATA_PORT);	/* read command execution status */
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: returned execution status: 0x%02x\n", exec_status);
-#endif
+
+	exec_status = inb(DATA_PORT);
+	DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
 	return exec_status;
 }
 
-/* Fetch status that has previously been waited for. <0 means not available */
-inline static int optStatus(void) {
-	unsigned char status;
-	if (optFlags() & FL_STEN)
-		return -ERR_IF_NOSTAT;
-	status = inb(DATA_PORT);
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: read status: 0x%02x\n", status);
-#endif
-	return status;
-}
 
-/* Wait for extra byte of data that a command returns */
-static int optGetData(void) {
+/* Wait busy for extra byte of data that a command returns.
+   Return value <0 indicates timeout. */
+inline static int get_data(int short_timeout)
+{
 	unsigned char data;
-	if (sten_low())
+
+	if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
 		return -ERR_IF_DATA_TIMEOUT;
+
 	data = inb(DATA_PORT);
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: read data: 0x%02x\n", data);
-#endif
+	DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
 	return data;
 }
 
-/* Read data that has previously been waited for. */
-inline static void optReadData(char *buf, int n) {
-	insb(DATA_PORT, buf, n);
-}
-
-/* Flush status and data fifos */
-inline static void optFlushData(void) {
-	while (optFlags() != FL_STDT)
-		inb(DATA_PORT);
-}
 
-/* Write something to RESET_PORT and wait. Return TRUE upon success. */
-static int optResetDrive(void) {
+/* Returns 0 if failed */
+static int reset_drive(void)
+{
 	unsigned long count = 0;
 	int flags;
-#ifdef DEBUG_DRIVE_IF
-	printk("optcd: reset drive\n");
-#endif
+
+	DEBUG((DEBUG_DRIVE_IF, "reset drive"));
+
 	outb(0, RESET_PORT);
 	while (++count < RESET_WAIT)
 		inb(DATA_PORT);
+
 	count = 0;
 	while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
 		if (++count >= BUSY_TIMEOUT)
 			break;
-#ifdef DEBUG_DRIVE_IF
-	if (flags == FL_RESET)
-		printk("optcd: drive reset\n");
-	else
-		printk("optcd: reset failed\n");
-#endif
+
+	DEBUG((DEBUG_DRIVE_IF, "reset %s",
+		flags == FL_RESET ? "succeeded" : "failed"));
+
 	if (flags != FL_RESET)
 		return 0;		/* Reset failed */
 	outb(HCON_SDRQB, HCON_PORT);	/* Disable Suspend Data Transfer */
@@ -356,345 +431,620 @@
 }
 
 
+/* Facilities for asynchronous operation */
+
+/* Read status/data availability flags FL_STEN and FL_DTEN */
+inline static int stdt_flags(void)
+{
+	return inb(STATUS_PORT) & FL_STDT;
+}
+
+
+/* Fetch status that has previously been waited for. <0 means not available */
+inline static int fetch_status(void)
+{
+	unsigned char status;
+
+	if (inb(STATUS_PORT) & FL_STEN)
+		return -ERR_IF_NOSTAT;
+
+	status = inb(DATA_PORT);
+	DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
+	return status;
+}
+
+
+/* Fetch data that has previously been waited for. */
+inline static void fetch_data(char *buf, int n)
+{
+	insb(DATA_PORT, buf, n);
+	DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
+}
+
+
+/* Flush status and data fifos */
+inline static void flush_data(void)
+{
+	while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
+		inb(DATA_PORT);
+	DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
+}
+
 /* Command protocol */
 
-/* Send a simple command and wait for response */
-inline static int optCmd(int cmd) {
-	int ack = optSendCmd(cmd);
+
+/* Send a simple command and wait for response. Command codes < COMFETCH
+   are quick response commands */
+inline static int exec_cmd(int cmd)
+{
+	int ack = send_cmd(cmd);
 	if (ack < 0)
 		return ack;
-	if (cmd < COMFETCH)		/* Quick response command */
-		return optGetExecStatus();
-	else				/* Slow command */
-		return optSleepTillExecStatus();
+	return get_exec_status(cmd < COMFETCH);
 }
 
-/* Send a command with parameters and wait for response */
-inline static int optPlayCmd(int cmd, struct opt_Play_msf *params) {
-	int ack = optSendCmd(cmd);
+
+/* Send a command with parameters. Don't wait for the response,
+ * which consists of data blocks read from the CD. */
+inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
+{
+	int ack = send_cmd(cmd);
 	if (ack < 0)
 		return ack;
-	if ((ack = optSendParams(params)) < 0)
-		return ack;
-	return optSleepTillExecStatus();
+	return send_params(params);
 }
 
-/* Send a command with parameters. Don't wait for the response,
- * which consists of the data blocks read. */
-inline static int optReadCmd(int cmd, struct opt_Play_msf *params) {
-	int ack = optSendCmd(cmd);
+
+/* Send a seek command with parameters and wait for response */
+inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
+{
+	int ack = send_cmd(cmd);
+	if (ack < 0)
+		return ack;
+	ack = send_seek_params(params);
 	if (ack < 0)
 		return ack;
-	return optSendParams(params);
+	return 0;
 }
 
 
+/* Send a command with parameters and wait for response */
+inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
+{
+	int ack = exec_read_cmd(cmd, params);
+	if (ack < 0)
+		return ack;
+	return get_exec_status(0);
+}
+
 /* Address conversion routines */
 
+
 /* Binary to BCD (2 digits) */
-inline static unsigned char bin2bcd(unsigned char p) {
-#ifdef DEBUG_CONV
-	if (p > 99)
-		printk("optcd: error bin2bcd %d\n", p);
-#endif
-	return (p % 10) | ((p / 10) << 4);
+inline static void single_bin2bcd(u_char *p)
+{
+	DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
+	*p = (*p % 10) | ((*p / 10) << 4);
 }
 
-/* Linear address to minute, second, frame form */
-static void hsg2msf(long hsg, struct msf *msf) {
-	hsg += 150;
-	msf -> min = hsg / 4500;
-	hsg %= 4500;
-	msf -> sec = hsg / 75;
-	msf -> frame = hsg % 75;
-#ifdef DEBUG_CONV
-	if (msf -> min >= 70)
-		printk("optcd: Error hsg2msf address Minutes\n");
-	if (msf -> sec >= 60)
-		printk("optcd: Error hsg2msf address Seconds\n");
-	if (msf -> frame >= 75)
-		printk("optcd: Error hsg2msf address Frames\n");
-#endif
-	msf -> min = bin2bcd(msf -> min);	/* convert to BCD */
-	msf -> sec = bin2bcd(msf -> sec);
-	msf -> frame = bin2bcd(msf -> frame);
+
+/* Convert entire msf struct */
+static void bin2bcd(struct cdrom_msf *msf)
+{
+	single_bin2bcd(&msf->cdmsf_min0);
+	single_bin2bcd(&msf->cdmsf_sec0);
+	single_bin2bcd(&msf->cdmsf_frame0);
+	single_bin2bcd(&msf->cdmsf_min1);
+	single_bin2bcd(&msf->cdmsf_sec1);
+	single_bin2bcd(&msf->cdmsf_frame1);
+}
+
+
+/* Linear block address to minute, second, frame form */
+static void lba2msf(int lba, struct cdrom_msf *msf)
+{
+	DEBUG((DEBUG_CONV, "lba2msf %d", lba));
+	lba += CD_MSF_OFFSET;
+	msf->cdmsf_min0 = lba / 4500; lba %= 4500;
+	msf->cdmsf_sec0 = lba / 75;
+	msf->cdmsf_frame0 = lba % 75;
+	msf->cdmsf_min1 = 0;
+	msf->cdmsf_sec1 = 0;
+	msf->cdmsf_frame1 = 0;
+	bin2bcd(msf);
 }
 
+
 /* Two BCD digits to binary */
-inline static int bcd2bin(unsigned char bcd) {
+inline static u_char bcd2bin(u_char bcd)
+{
+	DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
 	return (bcd >> 4) * 10 + (bcd & 0x0f);
 }
 
-/* Minute, second, frame address to linear address */
-static long msf2hsg(struct msf *mp) {
-#ifdef DEBUG_CONV
-	if (mp -> min >= 70)
-		printk("optcd: Error msf2hsg address Minutes\n");
-	if (mp -> sec >= 60)
-		printk("optcd: Error msf2hsg address Seconds\n");
-	if (mp -> frame >= 75)
-		printk("optcd: Error msf2hsg address Frames\n");
-#endif
-	return bcd2bin(mp -> frame)
-		+ bcd2bin(mp -> sec) * 75
-		+ bcd2bin(mp -> min) * 4500
-		- 150;
+
+union cd_addr {
+	struct {
+		u_char  minute;
+		u_char  second;
+		u_char  frame;
+	} msf;
+	int     lba;
+};
+
+
+static void msf2lba(union cd_addr *addr)
+{
+	addr->lba = addr->msf.minute * 4500
+	            + addr->msf.second * 75
+	            + addr->msf.frame - CD_MSF_OFFSET;
+}
+
+
+/* Minute, second, frame address BCD to binary or to linear address,
+   depending on MODE */
+static void msf_bcd2bin(union cd_addr *addr)
+{
+	addr->msf.minute = bcd2bin(addr->msf.minute);
+	addr->msf.second = bcd2bin(addr->msf.second);
+	addr->msf.frame = bcd2bin(addr->msf.frame);
 }
+
+/* High level drive commands */
+
 
+static int audio_status = CDROM_AUDIO_NO_STATUS;
+static char toc_uptodate = 0;
 
-/* Drive status and table of contents */
-
-static int optAudioStatus = CDROM_AUDIO_NO_STATUS;
-static char optDiskChanged = 1;
-static char optTocUpToDate = 0;
-static struct opt_DiskInfo DiskInfo;
-static struct opt_Toc Toc[MAX_TRACKS];
-
-/* Get CDROM status, flagging completion of audio play and disk changes. */
-static int optGetStatus(void) {
-	int st;
-	if ((st = optCmd(COMIOCTLISTAT)) < 0)
-		return st;
-	if (st == 0xff)
+/* Get drive status, flagging completion of audio play and disk changes. */
+static int drive_status(void)
+{
+	int status;
+
+	status = exec_cmd(COMIOCTLISTAT);
+	DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
+	if (status < 0)
+		return status;
+	if (status == 0xff)	/* No status available */
 		return -ERR_IF_NOSTAT;
-	if (((st & ST_MODE_BITS) != ST_M_AUDIO) &&
-		(optAudioStatus == CDROM_AUDIO_PLAY)) {
-		optAudioStatus = CDROM_AUDIO_COMPLETED;
-	}
-	if (st & ST_DSK_CHG) {
-		optDiskChanged = 1;
-		optTocUpToDate = 0;
-		optAudioStatus = CDROM_AUDIO_NO_STATUS;
-	}
-	return st;
-}
-
-/*
- * Read the current Q-channel info. Also used for reading the
- * table of contents.
- */
-static int optGetQChannelInfo(struct opt_Toc *qp) {
-	int st;
-#ifdef DEBUG_TOC
-	printk("optcd: starting optGetQChannelInfo\n");
-#endif
-	if ((st = optGetStatus()) < 0)
-		return st;
-	if ((st = optCmd(COMSUBQ)) < 0)
-		return st;
-	if ((qp -> ctrl_addr = st = optGetData()), st < 0) return st;
-	if ((qp -> track = st = optGetData()), st < 0) return st;
-	if ((qp -> pointIndex = st = optGetData()), st < 0) return st;
-	if ((qp -> trackTime.min = st = optGetData()), st < 0) return st;
-	if ((qp -> trackTime.sec = st = optGetData()), st < 0) return st;
-	if ((qp -> trackTime.frame = st = optGetData()), st < 0) return st;
-	if ((st = optGetData()) < 0) return st;		/* byte not used */
-	if ((qp -> diskTime.min = st = optGetData()), st < 0) return st;
-	if ((qp -> diskTime.sec = st = optGetData()), st < 0) return st;
-	if ((qp -> diskTime.frame = st = optGetData()), st < 0) return st;
-#ifdef DEBUG_TOC
-	printk("optcd: exiting optGetQChannelInfo\n");
-#endif
+
+	if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
+		(audio_status == CDROM_AUDIO_PLAY)) {
+		audio_status = CDROM_AUDIO_COMPLETED;
+	}
+
+	if (status & ST_DSK_CHG) {
+		toc_uptodate = 0;
+		audio_status = CDROM_AUDIO_NO_STATUS;
+	}
+
+	return status;
+}
+
+
+/* Read the current Q-channel info. Also used for reading the
+   table of contents. qp->cdsc_format must be set on entry to
+   indicate the desired address format */
+static int get_q_channel(struct cdrom_subchnl *qp)
+{
+	int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
+
+	status = drive_status();
+	if (status < 0)
+		return status;
+	qp->cdsc_audiostatus = audio_status;
+
+	status = exec_cmd(COMSUBQ);
+	if (status < 0)
+		return status;
+
+	d1 = get_data(0);
+	if (d1 < 0)
+		return d1;
+	qp->cdsc_adr = d1;
+	qp->cdsc_ctrl = d1 >> 4;
+
+	d2 = get_data(0);
+	if (d2 < 0)
+		return d2;
+	qp->cdsc_trk = bcd2bin(d2);
+
+	d3 = get_data(0);
+	if (d3 < 0)
+		return d3;
+	qp->cdsc_ind = bcd2bin(d3);
+
+	d4 = get_data(0);
+	if (d4 < 0)
+		return d4;
+	qp->cdsc_reladdr.msf.minute = d4;
+
+	d5 = get_data(0);
+	if (d5 < 0)
+		return d5;
+	qp->cdsc_reladdr.msf.second = d5;
+
+	d6 = get_data(0);
+	if (d6 < 0)
+		return d6;
+	qp->cdsc_reladdr.msf.frame = d6;
+
+	d7 = get_data(0);
+	if (d7 < 0)
+		return d7;
+	/* byte not used */
+
+	d8 = get_data(0);
+	if (d8 < 0)
+		return d8;
+	qp->cdsc_absaddr.msf.minute = d8;
+
+	d9 = get_data(0);
+	if (d9 < 0)
+		return d9;
+	qp->cdsc_absaddr.msf.second = d9;
+
+	d10 = get_data(0);
+	if (d10 < 0)
+		return d10;
+	qp->cdsc_absaddr.msf.frame = d10;
+
+	DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+		d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
+
+	msf_bcd2bin((union cd_addr *)/*%%*/&qp->cdsc_absaddr);
+	msf_bcd2bin((union cd_addr *)/*%%*/&qp->cdsc_reladdr);
+	if (qp->cdsc_format == CDROM_LBA) {
+		msf2lba((union cd_addr *)/*%%*/&qp->cdsc_absaddr);
+		msf2lba((union cd_addr *)/*%%*/&qp->cdsc_reladdr);
+	}
+
 	return 0;
 }
+
+/* Table of contents handling */
 
-#define QINFO_FIRSTTRACK	0xa0
-#define QINFO_LASTTRACK		0xa1
-#define QINFO_DISKLENGTH	0xa2
-
-static int optGetDiskInfo(void) {
-	int st, limit;
-	unsigned char test = 0;
-	struct opt_Toc qInfo;
-#ifdef DEBUG_TOC
-	printk("optcd: starting optGetDiskInfo\n");
-#endif
-	optDiskChanged = 0;
-	if ((st = optCmd(COMLEADIN)) < 0)
-		return st;
-	for (limit = 300; (limit > 0) && (test != 0x0f); limit--) {
-		if ((st = optGetQChannelInfo(&qInfo)) < 0)
-			return st;
-		switch (qInfo.pointIndex) {
-		case QINFO_FIRSTTRACK:
-			DiskInfo.first = bcd2bin(qInfo.diskTime.min);
-#ifdef DEBUG_TOC
-			printk("optcd: got first: %d\n", DiskInfo.first);
-#endif
-			test |= 0x01;
-			break;
-		case QINFO_LASTTRACK:
-			DiskInfo.last = bcd2bin(qInfo.diskTime.min);
-#ifdef DEBUG_TOC
-			printk("optcd: got last: %d\n", DiskInfo.last);
-#endif
-			test |= 0x02;
-			break;
-		case QINFO_DISKLENGTH:
-			DiskInfo.diskLength.min = qInfo.diskTime.min;
-			DiskInfo.diskLength.sec = qInfo.diskTime.sec-2;
-			DiskInfo.diskLength.frame = qInfo.diskTime.frame;
-#ifdef DEBUG_TOC
-			printk("optcd: got length: %x:%x.%x\n",
-				DiskInfo.diskLength.min,
-				DiskInfo.diskLength.sec,
-				DiskInfo.diskLength.frame);
+
+/* Errors in table of contents */
+#define ERR_TOC_MISSINGINFO	0x120
+#define ERR_TOC_MISSINGENTRY	0x121
+
+
+struct msf {
+	u_char  minute;
+	u_char  second;
+	u_char  frame;
+};
+
+struct cdrom_disk_info {
+	unsigned char	first;
+	unsigned char	last;
+	struct msf	disk_length;
+	struct msf	first_track;
+	/* Multisession info: */
+	unsigned char	next;
+	struct msf	next_session;
+	struct msf	last_session;
+	unsigned char	multi;
+	unsigned char	xa;
+	unsigned char	audio;
+};
+static struct cdrom_disk_info disk_info;
+
+#define MAX_TRACKS		111
+static struct cdrom_subchnl toc[MAX_TRACKS];
+
+#define QINFO_FIRSTTRACK	100 /* bcd2bin(0xa0) */
+#define QINFO_LASTTRACK		101 /* bcd2bin(0xa1) */
+#define QINFO_DISKLENGTH	102 /* bcd2bin(0xa2) */
+#define QINFO_NEXTSESSION	110 /* bcd2bin(0xb0) */
+
+#define I_FIRSTTRACK	0x01
+#define I_LASTTRACK	0x02
+#define I_DISKLENGTH	0x04
+#define I_NEXTSESSION	0x08
+#define I_ALL	(I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
+
+
+#if DEBUG_TOC
+void toc_debug_info(int i)
+{
+	printk("#%3d ctl %1x, adr %1x, track %2d index %3d"
+		"  %2d:%02d.%02d %2d:%02d.%02d\n",
+		i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
+		toc[i].cdsc_trk, toc[i].cdsc_ind,
+		toc[i].cdsc_reladdr.msf.minute,
+		toc[i].cdsc_reladdr.msf.second,
+		toc[i].cdsc_reladdr.msf.frame,
+		toc[i].cdsc_absaddr.msf.minute,
+		toc[i].cdsc_absaddr.msf.second,
+		toc[i].cdsc_absaddr.msf.frame);
+}
 #endif
-			test |= 0x04;
-			break;
-		default:
-			if ((test & 0x01)	/* Got no of first track */
-			 && (qInfo.pointIndex == DiskInfo.first)) {
-				/* StartTime of First Track */
-				DiskInfo.firstTrack.min = qInfo.diskTime.min;
-				DiskInfo.firstTrack.sec = qInfo.diskTime.sec;
-				DiskInfo.firstTrack.frame = qInfo.diskTime.frame;
-#ifdef DEBUG_TOC
-			printk("optcd: got start: %x:%x.%x\n",
-				DiskInfo.firstTrack.min,
-				DiskInfo.firstTrack.sec,
-				DiskInfo.firstTrack.frame);
+
+
+static int read_toc(void)
+{
+	int status, limit, count;
+	unsigned char got_info = 0;
+	struct cdrom_subchnl q_info;
+#if DEBUG_TOC
+	int i;
 #endif
-				test |= 0x08;
+
+	DEBUG((DEBUG_TOC, "starting read_toc"));
+
+	count = 0;
+	for (limit = 60; limit > 0; limit--) {
+		int index;
+
+		q_info.cdsc_format = CDROM_MSF;
+		status = get_q_channel(&q_info);
+		if (status < 0)
+			return status;
+
+		index = q_info.cdsc_ind;
+		if (index > 0 && index < MAX_TRACKS
+		    && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
+			toc[index] = q_info;
+			DEBUG((DEBUG_TOC, "got %d", index));
+			if (index < 100)
+				count++;
+
+			switch (q_info.cdsc_ind) {
+			case QINFO_FIRSTTRACK:
+				got_info |= I_FIRSTTRACK;
+				break;
+			case QINFO_LASTTRACK:
+				got_info |= I_LASTTRACK;
+				break;
+			case QINFO_DISKLENGTH:
+				got_info |= I_DISKLENGTH;
+				break;
+			case QINFO_NEXTSESSION:
+				got_info |= I_NEXTSESSION;
+				break;
 			}
 		}
+
+		if ((got_info & I_ALL) == I_ALL
+		    && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
+		       >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
+			break;
 	}
-#ifdef DEBUG_TOC
-	printk("optcd: exiting optGetDiskInfo\n");
-#endif
-	if (test != 0x0f)
+
+	/* Construct disk_info from TOC */
+	if (disk_info.first == 0) {
+		disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
+		disk_info.first_track.minute =
+			toc[disk_info.first].cdsc_absaddr.msf.minute;
+		disk_info.first_track.second =
+			toc[disk_info.first].cdsc_absaddr.msf.second;
+		disk_info.first_track.frame =
+			toc[disk_info.first].cdsc_absaddr.msf.frame;
+	}
+	disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
+	disk_info.disk_length.minute =
+			toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
+	disk_info.disk_length.second =
+			toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
+	disk_info.disk_length.frame =
+			toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
+	disk_info.next_session.minute =
+			toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
+	disk_info.next_session.second =
+			toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
+	disk_info.next_session.frame =
+			toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
+	disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
+	disk_info.last_session.minute =
+			toc[disk_info.next].cdsc_absaddr.msf.minute;
+	disk_info.last_session.second =
+			toc[disk_info.next].cdsc_absaddr.msf.second;
+	disk_info.last_session.frame =
+			toc[disk_info.next].cdsc_absaddr.msf.frame;
+	toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
+			disk_info.disk_length.minute;
+	toc[disk_info.last + 1].cdsc_absaddr.msf.second =
+			disk_info.disk_length.second;
+	toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
+			disk_info.disk_length.frame;
+#if DEBUG_TOC
+	for (i = 1; i <= disk_info.last + 1; i++)
+		toc_debug_info(i);
+	toc_debug_info(QINFO_FIRSTTRACK);
+	toc_debug_info(QINFO_LASTTRACK);
+	toc_debug_info(QINFO_DISKLENGTH);
+	toc_debug_info(QINFO_NEXTSESSION);
+#endif
+
+	DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
+		got_info, count));
+	if ((got_info & I_ALL) != I_ALL
+	    || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
+	       < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
 		return -ERR_TOC_MISSINGINFO;
 	return 0;
 }
 
-static int optGetToc(void) {	/* Presumes we have got DiskInfo */
-	int st, count, px, limit;
-	struct opt_Toc qInfo;
-#ifdef DEBUG_TOC
-	int i;
-	printk("optcd: starting optGetToc\n");
-#endif
-	for (count = 0; count < MAX_TRACKS; count++)
-		Toc[count].pointIndex = 0;
-	if ((st = optCmd(COMLEADIN)) < 0)
-		return st;
-	st = 0;
-	count = DiskInfo.last + 3;
-	for (limit = 300; (limit > 0) && (count > 0); limit--) {
-		if ((st = optGetQChannelInfo(&qInfo)) < 0)
+
+#ifdef MULTISESSION
+static int get_multi_disk_info(void)
+{
+	int sessions, status;
+	struct cdrom_msf multi_index;
+
+
+	for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
+		int count;
+
+		for (count = 100; count < MAX_TRACKS; count++) 
+			toc[count].cdsc_ind = 0;
+
+		multi_index.cdmsf_min0 = disk_info.next_session.minute;
+		multi_index.cdmsf_sec0 = disk_info.next_session.second;
+		multi_index.cdmsf_frame0 = disk_info.next_session.frame;
+		if (multi_index.cdmsf_sec0 >= 20)
+			multi_index.cdmsf_sec0 -= 20;
+		else {
+			multi_index.cdmsf_sec0 += 40;
+			multi_index.cdmsf_min0--;
+		}
+		DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
+			multi_index.cdmsf_min0,
+			multi_index.cdmsf_sec0,
+			multi_index.cdmsf_frame0));
+		bin2bcd(&multi_index);
+		multi_index.cdmsf_min1 = 0;
+		multi_index.cdmsf_sec1 = 0;
+		multi_index.cdmsf_frame1 = 1;
+
+		status = exec_read_cmd(COMREAD, &multi_index);
+		if (status < 0) {
+			DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
+				-status));
 			break;
-		px = bcd2bin(qInfo.pointIndex);
-		if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
-			if (Toc[px].pointIndex == 0) {
-				Toc[px] = qInfo;
-				count--;
-			}
+		}
+		status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
+				0 : -ERR_TOC_MISSINGINFO;
+		flush_data();
+		if (status < 0) {
+			DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
+			break;
+		}
+
+		status = read_toc();
+		if (status < 0) {
+			DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
+			break;
+		}
+
+		disk_info.multi = 1;
 	}
-	Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
-#ifdef DEBUG_TOC
-	printk("optcd: exiting optGetToc\n");
-	for (i = 1; i <= DiskInfo.last + 1; i++)
-		printk("i = %3d ctl-adr = %02x track %2d px "
-			"%02x %02x:%02x.%02x %02x:%02x.%02x\n",
-			i, Toc[i].ctrl_addr,
-			Toc[i].track,
-			Toc[i].pointIndex,
-			Toc[i].trackTime.min,
-			Toc[i].trackTime.sec,
-			Toc[i].trackTime.frame,
-			Toc[i].diskTime.min,
-			Toc[i].diskTime.sec,
-			Toc[i].diskTime.frame);
-	for (i = 100; i < 103; i++)
-		printk("i = %3d ctl-adr = %02x track %2d px "
-			"%02x %02x:%02x.%02x %02x:%02x.%02x\n",
-			i, Toc[i].ctrl_addr,
-			Toc[i].track,
-			Toc[i].pointIndex,
-			Toc[i].trackTime.min,
-			Toc[i].trackTime.sec,
-			Toc[i].trackTime.frame,
-			Toc[i].diskTime.min,
-			Toc[i].diskTime.sec,
-			Toc[i].diskTime.frame);
-#endif
-	return count ? -ERR_TOC_MISSINGENTRY : 0;
+
+	exec_cmd(COMSTOP);
+
+	if (status < 0)
+		return -EIO;
+	return 0;
 }
+#endif MULTISESSION
 
-static int optUpdateToc(void) {
-#ifdef DEBUG_TOC
-	printk("optcd: starting optUpdateToc\n");
-#endif
-	if (optTocUpToDate)
+
+static int update_toc(void)
+{
+	int status, count;
+
+	if (toc_uptodate)
 		return 0;
-	if (optGetDiskInfo() < 0)
+
+	DEBUG((DEBUG_TOC, "starting update_toc"));
+
+	disk_info.first = 0;
+	for (count = 0; count < MAX_TRACKS; count++) 
+		toc[count].cdsc_ind = 0;
+
+	status = exec_cmd(COMLEADIN);
+	if (status < 0)
 		return -EIO;
-	if (optGetToc() < 0)
+
+	status = read_toc();
+	if (status < 0) {
+		DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
 		return -EIO;
-	optTocUpToDate = 1;
-#ifdef DEBUG_TOC
-	printk("optcd: exiting optUpdateToc\n");
-#endif
+	}
+
+        /* Audio disk detection. Look at first track. */
+	disk_info.audio =
+		(toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
+
+	/* XA detection */
+	disk_info.xa = drive_status() & ST_MODE2TRACK;
+
+	/* Multisession detection: if we want this, define MULTISESSION */
+	disk_info.multi = 0;
+#ifdef MULTISESSION
+ 	if (disk_info.xa)
+		get_multi_disk_info();	/* Here disk_info.multi is set */
+#endif MULTISESSION
+	if (disk_info.multi)
+		printk("optcd: Multisession support experimental, "
+			"see linux/Documentation/cdrom/optcd\n");
+
+	DEBUG((DEBUG_TOC, "exiting update_toc"));
+
+	toc_uptodate = 1;
 	return 0;
 }
+
+/* Request handling */
+
+
+#define CURRENT_VALID \
+	(CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
+	 && CURRENT -> cmd == READ && CURRENT -> sector != -1)
 
 
-/* Buffers */
+#define BLOCKSIZE	2048
+#define BLOCKSIZE_RAW	2336
+#define BLOCKSIZE_ALL	2646
+#define N_BUFS		16
+#define NOBUF		-1
 
-#define OPT_BUF_SIZ		16
-#define OPT_BLOCKSIZE		2048
-#define OPT_BLOCKSIZE_RAW	2336
-#define OPT_BLOCKSIZE_ALL	2646
-#define OPT_NOBUF		-1
 
 /* Buffer for block size conversion. */
-static char opt_buf[OPT_BLOCKSIZE*OPT_BUF_SIZ];
-static volatile int opt_buf_bn[OPT_BUF_SIZ], opt_next_bn;
-static volatile int opt_buf_in = 0, opt_buf_out = OPT_NOBUF;
+static char buf[BLOCKSIZE * N_BUFS];
+static volatile int buf_bn[N_BUFS], next_bn;
+static volatile int buf_in = 0, buf_out = NOBUF;
 
-inline static void opt_invalidate_buffers(void) {
+inline static void opt_invalidate_buffers(void)
+{
 	int i;
-#ifdef DEBUG_BUFFERS
-	printk("optcd: executing opt_invalidate_buffers\n");
-#endif
-	for (i = 0; i < OPT_BUF_SIZ; i++)
-		opt_buf_bn[i] = OPT_NOBUF;
-	opt_buf_out = OPT_NOBUF;
+
+	DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
+
+	for (i = 0; i < N_BUFS; i++)
+		buf_bn[i] = NOBUF;
+	buf_out = NOBUF;
 }
 
-/*
- * Take care of the different block sizes between cdrom and Linux.
- * When Linux gets variable block sizes this will probably go away.
- */
-static void opt_transfer(void) {
-#if (defined DEBUG_BUFFERS) || (defined DEBUG_REQUEST)
-	printk("optcd: executing opt_transfer\n");
+
+/* Take care of the different block sizes between cdrom and Linux.
+   When Linux gets variable block sizes this will probably go away. */
+static void transfer(void)
+{
+#if DEBUG_BUFFERS | DEBUG_REQUEST
+	printk("optcd: executing transfer\n");
 #endif
+
 	if (!CURRENT_VALID)
 		return;
 	while (CURRENT -> nr_sectors) {
 		int bn = CURRENT -> sector / 4;
 		int i, offs, nr_sectors;
-		for (i = 0; i < OPT_BUF_SIZ && opt_buf_bn[i] != bn; ++i);
-#ifdef DEBUG_REQUEST
-		printk("optcd: found %d\n", i);
-#endif
-		if (i >= OPT_BUF_SIZ) {
-			opt_buf_out = OPT_NOBUF;
+		for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
+
+		DEBUG((DEBUG_REQUEST, "found %d", i));
+
+		if (i >= N_BUFS) {
+			buf_out = NOBUF;
 			break;
 		}
+
 		offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
 		nr_sectors = 4 - (CURRENT -> sector & 3);
-		if (opt_buf_out != i) {
-			opt_buf_out = i;
-			if (opt_buf_bn[i] != bn) {
-				opt_buf_out = OPT_NOBUF;
+
+		if (buf_out != i) {
+			buf_out = i;
+			if (buf_bn[i] != bn) {
+				buf_out = NOBUF;
 				continue;
 			}
 		}
+
 		if (nr_sectors > CURRENT -> nr_sectors)
 			nr_sectors = CURRENT -> nr_sectors;
-		memcpy(CURRENT -> buffer, opt_buf + offs, nr_sectors * 512);
+		memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
 		CURRENT -> nr_sectors -= nr_sectors;
 		CURRENT -> sector += nr_sectors;
 		CURRENT -> buffer += nr_sectors * 512;
@@ -704,216 +1054,219 @@
 
 /* State machine for reading disk blocks */
 
-enum opt_state_e {
-	OPT_S_IDLE,	/* 0 */
-	OPT_S_START,	/* 1 */
-	OPT_S_READ,	/* 2 */
-	OPT_S_DATA,	/* 3 */
-	OPT_S_STOP,	/* 4 */
-	OPT_S_STOPPING	/* 5 */
+enum state_e {
+	S_IDLE,		/* 0 */
+	S_START,	/* 1 */
+	S_READ,		/* 2 */
+	S_DATA,		/* 3 */
+	S_STOP,		/* 4 */
+	S_STOPPING	/* 5 */
 };
 
-static volatile enum opt_state_e opt_state = OPT_S_IDLE;
-#ifdef DEBUG_STATE
-static volatile enum opt_state_e opt_state_old = OPT_S_STOP;
-static volatile int opt_st_old = 0;
-static volatile long opt_state_n = 0;
+static volatile enum state_e state = S_IDLE;
+#if DEBUG_STATE
+static volatile enum state_e state_old = S_STOP;
+static volatile int flags_old = 0;
+static volatile long state_n = 0;
 #endif
 
-static volatile int opt_transfer_is_active = 0;
-static volatile int opt_error = 0;	/* do something with this?? */
-static int optTries;			/* ibid?? */
-
-static void opt_poll(void) {
-	static int optTimeout;
-	static volatile int opt_read_count = 1;
-	int st = 0;
-	int loop_ctl = 1;
+
+static volatile int transfer_is_active = 0;
+static volatile int error = 0;	/* %% do something with this?? */
+static int tries;		/* ibid?? */
+
+static void poll(void)
+{
+	static int timeout;
+	static volatile int read_count = 1;
+	int flags;
+	int loop_again = 1;
+	int status = 0;
 	int skip = 0;
 
-	if (opt_error) {
-		printk("optcd: I/O error 0x%02x\n", opt_error);
+	if (error) {
+		printk("optcd: I/O error 0x%02x\n", error);
 		opt_invalidate_buffers();
-#ifdef WARN_IF_READ_FAILURE
-		if (optTries == 5)
-			printk("optcd: read block %d failed; audio disk?\n",
-			        opt_next_bn);
-#endif
-		if (!optTries--) {
+		if (!tries--) {
 			printk("optcd: read block %d failed; Giving up\n",
-			       opt_next_bn);
-			if (opt_transfer_is_active) {
-				optTries = 0;
-				loop_ctl = 0;
-			}
+			       next_bn);
+			if (transfer_is_active)
+				loop_again = 0;
 			if (CURRENT_VALID)
 				end_request(0);
-			optTries = 5;
+			tries = 5;
 		}
-		opt_error = 0;
-		opt_state = OPT_S_STOP;
+		error = 0;
+		state = S_STOP;
 	}
 
-	while (loop_ctl)
+	while (loop_again)
 	{
-		loop_ctl = 0; /* each case must flip this back to 1 if we want
+		loop_again = 0; /* each case must flip this back to 1 if we want
 		                 to come back up here */
-#ifdef DEBUG_STATE
-		if (opt_state == opt_state_old)
-			opt_state_n++;
+
+#if DEBUG_STATE
+		if (state == state_old)
+			state_n++;
 		else {
-			opt_state_old = opt_state;
-			if (++opt_state_n > 1)
+			state_old = state;
+			if (++state_n > 1)
 				printk("optcd: %ld times in previous state\n",
-					opt_state_n);
-			printk("optcd: state %d\n", opt_state);
-			opt_state_n = 0;
+					state_n);
+			printk("optcd: state %d\n", state);
+			state_n = 0;
 		}
 #endif
-		switch (opt_state) {
-		case OPT_S_IDLE:
+
+		switch (state) {
+		case S_IDLE:
 			return;
-		case OPT_S_START:
-			if (optSendCmd(COMDRVST))
+		case S_START:
+			if (send_cmd(COMDRVST))
 				return;
-			opt_state = OPT_S_READ;
-			optTimeout = 3000;
+			state = S_READ;
+			timeout = READ_TIMEOUT;
 			break;
-		case OPT_S_READ: {
-			struct opt_Play_msf msf;
+		case S_READ: {
+			struct cdrom_msf msf;
 			if (!skip) {
-				if ((st = optStatus()) < 0)
+				status = fetch_status();
+				if (status < 0)
 					break;
-				if (st & ST_DSK_CHG) {
-					optDiskChanged = 1;
-					optTocUpToDate = 0;
+				if (status & ST_DSK_CHG) {
+					toc_uptodate = 0;
 					opt_invalidate_buffers();
 				}
 			}
 			skip = 0;
-			if ((st & ST_DOOR_OPEN) || (st & ST_DRVERR)) {
-				optDiskChanged = 1;
-				optTocUpToDate = 0;
-				printk((st & ST_DOOR_OPEN)
+			if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
+				toc_uptodate = 0;
+				printk((status & ST_DOOR_OPEN)
 				       ? "optcd: door open\n"
 				       : "optcd: disk removed\n");
-				if (opt_transfer_is_active) {
-					opt_state = OPT_S_START;
-					loop_ctl = 1;
+				if (transfer_is_active) {
+					state = S_START;
+					loop_again = 1;
 					break;
 				}
-				opt_state = OPT_S_IDLE;
+				state = S_IDLE;
 				while (CURRENT_VALID)
 					end_request(0);
 				return;
 			}
 			if (!CURRENT_VALID) {
-				opt_state = OPT_S_STOP;
-				loop_ctl = 1;
+				state = S_STOP;
+				loop_again = 1;
 				break;
 			}
-			opt_next_bn = CURRENT -> sector / 4;
-			hsg2msf(opt_next_bn, &msf.start);
-			opt_read_count = OPT_BUF_SIZ;
-			msf.end.min = 0;
-			msf.end.sec = 0;
-			msf.end.frame = opt_read_count;
-#ifdef DEBUG_REQUEST
-			printk("optcd: reading %x:%x.%x %x:%x.%x\n",
-				msf.start.min,
-				msf.start.sec,
-				msf.start.frame,
-				msf.end.min,
-				msf.end.sec,
-				msf.end.frame);
-			printk("optcd: opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n",
-				opt_next_bn,
-				opt_buf_in,
-				opt_buf_out,
-				opt_buf_bn[opt_buf_in]);
-#endif
-			optReadCmd(COMREAD, &msf);
-			opt_state = OPT_S_DATA;
-			optTimeout = READ_TIMEOUT;
+			next_bn = CURRENT -> sector / 4;
+			lba2msf(next_bn, &msf);
+			read_count = N_BUFS;
+			msf.cdmsf_frame1 = read_count; /* Not BCD! */
+
+			DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",
+				msf.cdmsf_min0,
+				msf.cdmsf_sec0,
+				msf.cdmsf_frame0,
+				msf.cdmsf_min1,
+				msf.cdmsf_sec1,
+				msf.cdmsf_frame1));
+			DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
+				" buf_out:%d buf_bn:%d",
+				next_bn,
+				buf_in,
+				buf_out,
+				buf_bn[buf_in]));
+
+			exec_read_cmd(COMREAD, &msf);
+			state = S_DATA;
+			timeout = READ_TIMEOUT;
 			break;
 		}
-		case OPT_S_DATA:
-			st = optFlags() & (FL_STEN|FL_DTEN);
-#ifdef DEBUG_STATE
-			if (st != opt_st_old) {
-				opt_st_old = st;
-				printk("optcd: st:%x\n", st);
+		case S_DATA:
+			flags = stdt_flags() & (FL_STEN|FL_DTEN);
+
+#if DEBUG_STATE
+			if (flags != flags_old) {
+				flags_old = flags;
+				printk("optcd: flags:%x\n", flags);
 			}
-			if (st == FL_STEN)
-				printk("timeout cnt: %d\n", optTimeout);
-#endif
-			switch (st) {
-			case FL_DTEN:
-#ifdef WARN_IF_READ_FAILURE
-				if (optTries == 5)
-					printk("optcd: read block %d failed; audio disk?\n",
-					       opt_next_bn);
+			if (flags == FL_STEN)
+				printk("timeout cnt: %d\n", timeout);
 #endif
-				if (!optTries--) {
-					printk("optcd: read block %d failed; Giving up\n",
-					       opt_next_bn);
-					if (opt_transfer_is_active) {
-						optTries = 0;
+
+			switch (flags) {
+			case FL_DTEN:		/* only STEN low */
+				if (!tries--) {
+					printk("optcd: read block %d failed; "
+						"Giving up\n", next_bn);
+					if (transfer_is_active) {
+						tries = 0;
 						break;
 					}
 					if (CURRENT_VALID)
 						end_request(0);
-					optTries = 5;
+					tries = 5;
 				}
-				opt_state = OPT_S_START;
-				optTimeout = READ_TIMEOUT;
-				loop_ctl = 1;
-			case (FL_STEN|FL_DTEN):
+				state = S_START;
+				timeout = READ_TIMEOUT;
+				loop_again = 1;
+			case (FL_STEN|FL_DTEN):	 /* both high */
 				break;
-			default:
-				optTries = 5;
-				if (!CURRENT_VALID && opt_buf_in == opt_buf_out) {
-					opt_state = OPT_S_STOP;
-					loop_ctl = 1;
+			default:	/* DTEN low */
+				tries = 5;
+				if (!CURRENT_VALID && buf_in == buf_out) {
+					state = S_STOP;
+					loop_again = 1;
 					break;
 				}
-				if (opt_read_count<=0)
-					printk("optcd: warning - try to read 0 frames\n");
-				while (opt_read_count) {
-					opt_buf_bn[opt_buf_in] = OPT_NOBUF;
-					if (dten_low()) { /* should be no waiting here!?? */
-						printk("read_count:%d CURRENT->nr_sectors:%ld opt_buf_in:%d\n",
-							opt_read_count,
+				if (read_count<=0)
+					printk("optcd: warning - try to read"
+						" 0 frames\n");
+				while (read_count) {
+					buf_bn[buf_in] = NOBUF;
+					if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
+					/* should be no waiting here!?? */
+						printk("read_count:%d "
+						   "CURRENT->nr_sectors:%ld "
+						   "buf_in:%d\n",
+							read_count,
 							CURRENT->nr_sectors,
-							opt_buf_in);
-						printk("opt_transfer_is_active:%x\n",
-							opt_transfer_is_active);
-						opt_read_count = 0;
-						opt_state = OPT_S_STOP;
-						loop_ctl = 1;
+							buf_in);
+						printk("transfer active: %x\n",
+							transfer_is_active);
+						read_count = 0;
+						state = S_STOP;
+						loop_again = 1;
 						end_request(0);
 						break;
 					}
-					optReadData(opt_buf+OPT_BLOCKSIZE*opt_buf_in, OPT_BLOCKSIZE);
-					opt_read_count--;
-#ifdef DEBUG_REQUEST
-					printk("OPT_S_DATA; ---I've read data- read_count: %d\n",
-					       opt_read_count);
-					printk("opt_next_bn:%d  opt_buf_in:%d opt_buf_out:%d  opt_buf_bn:%d\n",
-					       opt_next_bn,
-					       opt_buf_in,
-					       opt_buf_out,
-					       opt_buf_bn[opt_buf_in]);
-#endif
-					opt_buf_bn[opt_buf_in] = opt_next_bn++;
-					if (opt_buf_out == OPT_NOBUF)
-						opt_buf_out = opt_buf_in;
-					opt_buf_in = opt_buf_in + 1 ==
-						OPT_BUF_SIZ ? 0 : opt_buf_in + 1;
+					fetch_data(buf+
+					    BLOCKSIZE*buf_in,
+					    BLOCKSIZE);
+					read_count--;
+
+					DEBUG((DEBUG_REQUEST,
+						"S_DATA; ---I've read data- "
+						"read_count: %d",
+						read_count));
+					DEBUG((DEBUG_REQUEST,
+						"next_bn:%d  buf_in:%d "
+						"buf_out:%d  buf_bn:%d",
+						next_bn,
+						buf_in,
+						buf_out,
+						buf_bn[buf_in]));
+
+					buf_bn[buf_in] = next_bn++;
+					if (buf_out == NOBUF)
+						buf_out = buf_in;
+					buf_in = buf_in + 1 ==
+						N_BUFS ? 0 : buf_in + 1;
 				}
-				if (!opt_transfer_is_active) {
+				if (!transfer_is_active) {
 					while (CURRENT_VALID) {
-						opt_transfer();
+						transfer();
 						if (CURRENT -> nr_sectors == 0)
 							end_request(1);
 						else
@@ -922,442 +1275,663 @@
 				}
 
 				if (CURRENT_VALID
-				    && (CURRENT -> sector / 4 < opt_next_bn ||
+				    && (CURRENT -> sector / 4 < next_bn ||
 				    CURRENT -> sector / 4 >
-				     opt_next_bn + OPT_BUF_SIZ)) {
-					opt_state = OPT_S_STOP;
-					loop_ctl = 1;
+				     next_bn + N_BUFS)) {
+					state = S_STOP;
+					loop_again = 1;
 					break;
 				}
-				optTimeout = READ_TIMEOUT;
-				if (opt_read_count == 0) {
-					opt_state = OPT_S_STOP;
-					loop_ctl = 1;
+				timeout = READ_TIMEOUT;
+				if (read_count == 0) {
+					state = S_STOP;
+					loop_again = 1;
 					break;
 				}
 			}
 			break;
-		case OPT_S_STOP:
-			if (opt_read_count != 0)
+		case S_STOP:
+			if (read_count != 0)
 				printk("optcd: discard data=%x frames\n",
-					opt_read_count);
-			while (opt_read_count != 0) {
-				optFlushData();
-				opt_read_count--;
-			}
-			if (optSendCmd(COMDRVST))
+					read_count);
+			flush_data();
+			if (send_cmd(COMDRVST))
 				return;
-			opt_state = OPT_S_STOPPING;
-			optTimeout = 1000;
+			state = S_STOPPING;
+			timeout = STOP_TIMEOUT;
 			break;
-		case OPT_S_STOPPING:
-			if ((st = optStatus()) < 0 && optTimeout)
+		case S_STOPPING:
+			status = fetch_status();
+			if (status < 0 && timeout)
 					break;
-			if ((st != -1) && (st & ST_DSK_CHG)) {
-				optDiskChanged = 1;
-				optTocUpToDate = 0;
+			if ((status >= 0) && (status & ST_DSK_CHG)) {
+				toc_uptodate = 0;
 				opt_invalidate_buffers();
 			}
 			if (CURRENT_VALID) {
-				if (st != -1) {
-					opt_state = OPT_S_READ;
-					loop_ctl = 1;
+				if (status >= 0) {
+					state = S_READ;
+					loop_again = 1;
 					skip = 1;
 					break;
 				} else {
-					opt_state = OPT_S_START;
-					optTimeout = 1;
+					state = S_START;
+					timeout = 1;
 				}
 			} else {
-				opt_state = OPT_S_IDLE;
+				state = S_IDLE;
 				return;
 			}
 			break;
 		default:
-			printk("optcd: invalid state %d\n", opt_state);
+			printk("optcd: invalid state %d\n", state);
 			return;
 		} /* case */
 	} /* while */
 
-	if (!optTimeout--) {
-		printk("optcd: timeout in state %d\n", opt_state);
-		opt_state = OPT_S_STOP;
-		if (optCmd(COMSTOP) < 0)
+	if (!timeout--) {
+		printk("optcd: timeout in state %d\n", state);
+		state = S_STOP;
+		if (exec_cmd(COMSTOP) < 0)
 			return;
 	}
 
-	SET_TIMER(opt_poll, 1);
+	SET_TIMER(poll, HZ/100);
 }
 
 
-static void do_optcd_request(void) {
-#ifdef DEBUG_REQUEST
-	printk("optcd: do_optcd_request(%ld+%ld)\n",
-	       CURRENT -> sector, CURRENT -> nr_sectors);
-#endif
-	opt_transfer_is_active = 1;
+static void do_optcd_request(void)
+{
+	DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
+	       CURRENT -> sector, CURRENT -> nr_sectors));
+
+	if (disk_info.audio) {
+		printk("optcd: Error: tried to mount an Audio CD\n");
+		end_request(0);
+		return;
+	}
+
+	transfer_is_active = 1;
 	while (CURRENT_VALID) {
 		if (CURRENT->bh) {
 			if (!buffer_locked(CURRENT->bh))
 				panic(DEVICE_NAME ": block not locked");
 		}
-		opt_transfer();	/* First try to transfer block from buffers */
+		transfer();	/* First try to transfer block from buffers */
 		if (CURRENT -> nr_sectors == 0) {
 			end_request(1);
 		} else {	/* Want to read a block not in buffer */
-			opt_buf_out = OPT_NOBUF;
-			if (opt_state == OPT_S_IDLE) {
-				/* Should this block the request queue?? */
-				if (optUpdateToc() < 0) {
+			buf_out = NOBUF;
+			if (state == S_IDLE) {
+				/* %% Should this block the request queue?? */
+				if (update_toc() < 0) {
 					while (CURRENT_VALID)
 						end_request(0);
 					break;
 				}
 				/* Start state machine */
-				opt_state = OPT_S_START;
-				optTries = 5;
-				SET_TIMER(opt_poll, 1);	/* why not start right away?? */
+				state = S_START;
+				tries = 5;
+				/* %% why not start right away?? */
+				SET_TIMER(poll, HZ/100);
 			}
 			break;
 		}
 	}
-	opt_transfer_is_active = 0;
-#ifdef DEBUG_REQUEST
-	printk("opt_next_bn:%d  opt_buf_in:%d opt_buf_out:%d  opt_buf_bn:%d\n",
-	       opt_next_bn, opt_buf_in, opt_buf_out, opt_buf_bn[opt_buf_in]);
-	printk("optcd: do_optcd_request ends\n");
-#endif
+	transfer_is_active = 0;
+
+	DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",
+	       next_bn, buf_in, buf_out, buf_bn[buf_in]));
+	DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
 }
+
+/* IOCTLs */
 
 
-/* VFS calls */
+static char auto_eject = 0;
 
-static int opt_ioctl(struct inode *ip, struct file *fp,
-			unsigned int cmd, unsigned long arg) {
-	static struct opt_Play_msf opt_Play;	/* pause position */
-	int err;
-#ifdef DEBUG_VFS
-	printk("optcd: starting opt_ioctl, command 0x%x\n", cmd);
-#endif
-	if (!ip)
+static int cdrompause(void)
+{
+	int status;
+
+	if (audio_status != CDROM_AUDIO_PLAY)
 		return -EINVAL;
-	if (optGetStatus() < 0)
+
+	status = exec_cmd(COMPAUSEON);
+	if (status < 0) {
+		DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
 		return -EIO;
-	if ((err = optUpdateToc()) < 0)
-		return err;
+	}
+	audio_status = CDROM_AUDIO_PAUSED;
+	return 0;
+}
 
-	switch (cmd) {
-	case CDROMPAUSE: {
-		struct opt_Toc qInfo;
 
-		if (optAudioStatus != CDROM_AUDIO_PLAY)
-			return -EINVAL;
-		if (optGetQChannelInfo(&qInfo) < 0) {
-			/* didn't get q channel info */
-			optAudioStatus = CDROM_AUDIO_NO_STATUS;
-			return 0;
-		}
-		opt_Play.start = qInfo.diskTime;	/* restart point */
-		if (optCmd(COMPAUSEON) < 0)
-			return -EIO;
-		optAudioStatus = CDROM_AUDIO_PAUSED;
-		break;
-	}
-	case CDROMRESUME:
-		if (optAudioStatus != CDROM_AUDIO_PAUSED)
-			return -EINVAL;
-		if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
-			optAudioStatus = CDROM_AUDIO_ERROR;
-			return -EIO;
-		}
-		optAudioStatus = CDROM_AUDIO_PLAY;
-		break;
-	case CDROMPLAYMSF: {
-		int st;
-		struct cdrom_msf msf;
-
-		if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf)))
-			return st;
-		memcpy_fromfs(&msf, (void *) arg, sizeof msf);
-		opt_Play.start.min = bin2bcd(msf.cdmsf_min0);
-		opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0);
-		opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0);
-		opt_Play.end.min = bin2bcd(msf.cdmsf_min1);
-		opt_Play.end.sec = bin2bcd(msf.cdmsf_sec1);
-		opt_Play.end.frame = bin2bcd(msf.cdmsf_frame1);
-		if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
-			optAudioStatus = CDROM_AUDIO_ERROR;
-			return -EIO;
-		}
-		optAudioStatus = CDROM_AUDIO_PLAY;
-		break;
+static int cdromresume(void)
+{
+	int status;
+
+	if (audio_status != CDROM_AUDIO_PAUSED)
+		return -EINVAL;
+
+	status = exec_cmd(COMPAUSEOFF);
+	if (status < 0) {
+		DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
+		audio_status = CDROM_AUDIO_ERROR;
+		return -EIO;
 	}
-	case CDROMPLAYTRKIND: {
-		int st;
-		struct cdrom_ti ti;
-
-		if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof ti)))
-			return st;
-		memcpy_fromfs(&ti, (void *) arg, sizeof ti);
-		if (ti.cdti_trk0 < DiskInfo.first
-			|| ti.cdti_trk0 > DiskInfo.last
-			|| ti.cdti_trk1 < ti.cdti_trk0)
-			return -EINVAL;
-		if (ti.cdti_trk1 > DiskInfo.last)
-			ti.cdti_trk1 = DiskInfo.last;
-		opt_Play.start = Toc[ti.cdti_trk0].diskTime;
-		opt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
-#ifdef DEBUG_VFS
-		printk("optcd: play %02x:%02x.%02x to %02x:%02x.%02x\n",
-			opt_Play.start.min,
-			opt_Play.start.sec,
-			opt_Play.start.frame,
-			opt_Play.end.min,
-			opt_Play.end.sec,
-			opt_Play.end.frame);
-#endif
-		if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
-			optAudioStatus = CDROM_AUDIO_ERROR;
-			return -EIO;
-		}
-		optAudioStatus = CDROM_AUDIO_PLAY;
-		break;
+	audio_status = CDROM_AUDIO_PLAY;
+	return 0;
+}
+
+
+static int cdromplaymsf(unsigned long arg)
+{
+	int status;
+	struct cdrom_msf msf;
+
+	status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
+	if (status)
+		return status;
+	memcpy_fromfs(&msf, (void *) arg, sizeof msf);
+
+	bin2bcd(&msf);
+	status = exec_long_cmd(COMPLAY, &msf);
+	if (status < 0) {
+		DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
+		audio_status = CDROM_AUDIO_ERROR;
+		return -EIO;
 	}
-	case CDROMREADTOCHDR: {		/* Read the table of contents header. */
-		int st;
-		struct cdrom_tochdr tocHdr;
-
-		if ((st = verify_area(VERIFY_WRITE,(void *)arg,sizeof tocHdr)))
-			return st;
-		if (!optTocUpToDate)
-			optGetDiskInfo();
-		tocHdr.cdth_trk0 = DiskInfo.first;
-		tocHdr.cdth_trk1 = DiskInfo.last;
-		memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
-		break;
-	}
-	case CDROMREADTOCENTRY: {	/* Read a table of contents entry. */
-		int st;
-		struct cdrom_tocentry entry;
-		struct opt_Toc *tocPtr;
-
-		if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof entry)))
-			return st;
-		if ((st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry)))
-			return st;
-		memcpy_fromfs(&entry, (void *) arg, sizeof entry);
-		if (!optTocUpToDate)
-			optGetDiskInfo();
-		if (entry.cdte_track == CDROM_LEADOUT)
-			tocPtr = &Toc[DiskInfo.last + 1];
-		else if (entry.cdte_track > DiskInfo.last
-			|| entry.cdte_track < DiskInfo.first)
-			return -EINVAL;
-		else
-			tocPtr = &Toc[entry.cdte_track];
-		entry.cdte_adr = tocPtr -> ctrl_addr;
-		entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
-		switch (entry.cdte_format) {
-		case CDROM_LBA:
-			entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
-			break;
-		case CDROM_MSF:
-			entry.cdte_addr.msf.minute =
-				bcd2bin(tocPtr -> diskTime.min);
-			entry.cdte_addr.msf.second =
-				bcd2bin(tocPtr -> diskTime.sec);
-			entry.cdte_addr.msf.frame =
-				bcd2bin(tocPtr -> diskTime.frame);
-			break;
-		default:
-			return -EINVAL;
-		}
-		memcpy_tofs((void *) arg, &entry, sizeof entry);
-		break;
+
+	audio_status = CDROM_AUDIO_PLAY;
+	return 0;
+}
+
+
+static int cdromplaytrkind(unsigned long arg)
+{
+	int status;
+	struct cdrom_ti ti;
+	struct cdrom_msf msf;
+
+	status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
+	if (status)
+		return status;
+	memcpy_fromfs(&ti, (void *) arg, sizeof ti);
+
+	if (ti.cdti_trk0 < disk_info.first
+	    || ti.cdti_trk0 > disk_info.last
+	    || ti.cdti_trk1 < ti.cdti_trk0)
+		return -EINVAL;
+	if (ti.cdti_trk1 > disk_info.last)
+		ti.cdti_trk1 = disk_info.last;
+
+	msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
+	msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
+	msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
+	msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
+	msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
+	msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
+
+	DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
+		msf.cdmsf_min0,
+		msf.cdmsf_sec0,
+		msf.cdmsf_frame0,
+		msf.cdmsf_min1,
+		msf.cdmsf_sec1,
+		msf.cdmsf_frame1));
+
+	bin2bcd(&msf);
+	status = exec_long_cmd(COMPLAY, &msf);
+	if (status < 0) {
+		DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
+		audio_status = CDROM_AUDIO_ERROR;
+		return -EIO;
 	}
-	case CDROMSTOP:
-		optCmd(COMSTOP);
-		optAudioStatus = CDROM_AUDIO_NO_STATUS;
-		break;
-	case CDROMSTART:
-		optCmd(COMCLOSE);	/* What else can we do? */
-		break;
-	case CDROMEJECT:
-		optCmd(COMUNLOCK);
-		optCmd(COMOPEN);
-		break;
-	case CDROMVOLCTRL: {
-		int st;
-		struct cdrom_volctrl volctrl;
-
-		if ((st = verify_area(VERIFY_READ, (void *) arg,
-				sizeof(volctrl))))
-			return st;
-		memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
-		opt_Play.start.min = 0x10;
-		opt_Play.start.sec = 0x32;
-		opt_Play.start.frame = volctrl.channel0;
-		opt_Play.end.min = volctrl.channel1;
-		opt_Play.end.sec = volctrl.channel2;
-		opt_Play.end.frame = volctrl.channel3;
-		if (optPlayCmd(COMCHCTRL, &opt_Play) < 0)
-			return -EIO;
-		break;
+
+	audio_status = CDROM_AUDIO_PLAY;
+	return 0;
+}
+
+
+static int cdromreadtochdr(unsigned long arg)
+{
+	int status;
+	struct cdrom_tochdr tochdr;
+
+	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
+	if (status)
+		return status;
+
+	tochdr.cdth_trk0 = disk_info.first;
+	tochdr.cdth_trk1 = disk_info.last;
+
+	memcpy_tofs((void *) arg, &tochdr, sizeof tochdr);
+	return 0;
+}
+
+
+static int cdromreadtocentry(unsigned long arg)
+{
+	int status;
+	struct cdrom_tocentry entry;
+	struct cdrom_subchnl *tocptr;
+
+	status = verify_area(VERIFY_READ, (void *) arg, sizeof entry);
+	if (status)
+		return status;
+	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
+	if (status)
+		return status;
+	memcpy_fromfs(&entry, (void *) arg, sizeof entry);
+
+	if (entry.cdte_track == CDROM_LEADOUT)
+		tocptr = &toc[disk_info.last + 1];
+	else if (entry.cdte_track > disk_info.last
+		|| entry.cdte_track < disk_info.first)
+		return -EINVAL;
+	else
+		tocptr = &toc[entry.cdte_track];
+
+	entry.cdte_adr = tocptr->cdsc_adr;
+	entry.cdte_ctrl = tocptr->cdsc_ctrl;
+	entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
+	entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
+	entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
+	/* %% What should go into entry.cdte_datamode? */
+
+	if (entry.cdte_format == CDROM_LBA)
+		msf2lba((union cd_addr *)/*%%*/&entry.cdte_addr);
+	else if (entry.cdte_format != CDROM_MSF)
+		return -EINVAL;
+
+	memcpy_tofs((void *) arg, &entry, sizeof entry);
+	return 0;
+}
+
+
+static int cdromvolctrl(unsigned long arg)
+{
+	int status;
+	struct cdrom_volctrl volctrl;
+	struct cdrom_msf msf;
+
+	status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
+	if (status)
+		return status;
+	memcpy_fromfs(&volctrl, (char *) arg, sizeof volctrl);
+
+	msf.cdmsf_min0 = 0x10;
+	msf.cdmsf_sec0 = 0x32;
+	msf.cdmsf_frame0 = volctrl.channel0;
+	msf.cdmsf_min1 = volctrl.channel1;
+	msf.cdmsf_sec1 = volctrl.channel2;
+	msf.cdmsf_frame1 = volctrl.channel3;
+
+	status = exec_long_cmd(COMCHCTRL, &msf);
+	if (status < 0) {
+		DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
+		return -EIO;
 	}
-	case CDROMSUBCHNL: {	/* Get subchannel info */
-		int st;
-		struct cdrom_subchnl subchnl;
-		struct opt_Toc qInfo;
-
-		if ((st = verify_area(VERIFY_READ,
-				(void *) arg, sizeof subchnl)))
-			return st;
-		if ((st = verify_area(VERIFY_WRITE,
-				(void *) arg, sizeof subchnl)))
-			return st;
-		memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
-		if (optGetQChannelInfo(&qInfo) < 0)
-			return -EIO;
-		subchnl.cdsc_audiostatus = optAudioStatus;
-		subchnl.cdsc_adr = qInfo.ctrl_addr;
-		subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
-		subchnl.cdsc_trk = bcd2bin(qInfo.track);
-		subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex);
-		switch (subchnl.cdsc_format) {
-		case CDROM_LBA:
-			subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime);
-			subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime);
-			break;
-		case CDROM_MSF:
-			subchnl.cdsc_absaddr.msf.minute =
-				bcd2bin(qInfo.diskTime.min);
-			subchnl.cdsc_absaddr.msf.second =
-				bcd2bin(qInfo.diskTime.sec);
-			subchnl.cdsc_absaddr.msf.frame =
-				bcd2bin(qInfo.diskTime.frame);
-			subchnl.cdsc_reladdr.msf.minute =
-				bcd2bin(qInfo.trackTime.min);
-			subchnl.cdsc_reladdr.msf.second =
-				bcd2bin(qInfo.trackTime.sec);
-			subchnl.cdsc_reladdr.msf.frame =
-				bcd2bin(qInfo.trackTime.frame);
-			break;
-		default:
-			return -EINVAL;
-		}
-		memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
-		break;
+	return 0;
+}
+
+
+static int cdromsubchnl(unsigned long arg)
+{
+	int status;
+	struct cdrom_subchnl subchnl;
+
+	status = verify_area(VERIFY_READ, (void *) arg, sizeof subchnl);
+	if (status)
+		return status;
+	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
+	if (status)
+		return status;
+	memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
+
+	if (subchnl.cdsc_format != CDROM_LBA
+	    && subchnl.cdsc_format != CDROM_MSF)
+		return -EINVAL;
+
+	status = get_q_channel(&subchnl);
+	if (status < 0) {
+		DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
+		return -EIO;
 	}
-	case CDROMREADMODE1: {
-		int st;
-		struct cdrom_msf msf;
-		char buf[OPT_BLOCKSIZE];
-
-		if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf)))
-			return st;
-		if ((st = verify_area(VERIFY_WRITE,(void *)arg,OPT_BLOCKSIZE)))
-			return st;
-		memcpy_fromfs(&msf, (void *) arg, sizeof msf);
-		opt_Play.start.min = bin2bcd(msf.cdmsf_min0);
-		opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0);
-		opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0);
-		opt_Play.end.min = 0;
-		opt_Play.end.sec = 0;
-		opt_Play.end.frame = 1;	/* read only one frame */
-		st = optReadCmd(COMREAD, &opt_Play);
-#ifdef DEBUG_VFS
-		printk("optcd: COMREAD status 0x%x\n", st);
-#endif
-		sleep_dten_low();	/* error checking here?? */
-		optReadData(buf, OPT_BLOCKSIZE);
-		memcpy_tofs((void *) arg, &buf, OPT_BLOCKSIZE);
-		break;
+
+	memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
+	return 0;
+}
+
+
+static int cdromread(unsigned long arg, int blocksize, int cmd)
+{
+	int status;
+	struct cdrom_msf msf;
+	char buf[BLOCKSIZE_ALL];
+
+	status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
+	if (status)
+		return status;
+	status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
+	if (status)
+		return status;
+	memcpy_fromfs(&msf, (void *) arg, sizeof msf);
+
+	bin2bcd(&msf);
+	msf.cdmsf_min1 = 0;
+	msf.cdmsf_sec1 = 0;
+	msf.cdmsf_frame1 = 1;	/* read only one frame */
+	status = exec_read_cmd(cmd, &msf);
+
+	DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
+
+	if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
+		return -EIO;
+	fetch_data(buf, blocksize);
+
+	memcpy_tofs((void *) arg, &buf, blocksize);
+	return 0;
+}
+
+
+static int cdromseek(unsigned long arg)
+{
+	int status;
+	struct cdrom_msf msf;
+
+	status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
+	if (status)
+		return status;
+	memcpy_fromfs(&msf, (void *) arg, sizeof msf);
+
+	bin2bcd(&msf);
+	status = exec_seek_cmd(COMSEEK, &msf);
+
+	DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
+
+	if (status < 0)
+		return -EIO;
+	return 0;
+}
+
+
+#ifdef MULTISESSION
+static int cdrommultisession(unsigned long arg)
+{
+	int status;
+	struct cdrom_multisession ms;
+
+	status = verify_area(VERIFY_READ, (void*) arg, sizeof ms);
+	if (status)
+		return status;
+	status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
+	if (status)
+		return status;
+	memcpy_fromfs(&ms, (void*) arg, sizeof ms);
+
+	ms.addr.msf.minute = disk_info.last_session.minute;
+	ms.addr.msf.second = disk_info.last_session.second;
+	ms.addr.msf.frame = disk_info.last_session.frame;
+
+	if (ms.addr_format != CDROM_LBA
+	   && ms.addr_format != CDROM_MSF)
+		return -EINVAL;
+	if (ms.addr_format == CDROM_LBA)
+		msf2lba((union cd_addr *)/*%%*/&ms.addr);
+
+	ms.xa_flag = disk_info.xa;
+
+  	memcpy_tofs((void*) arg, &ms,
+		sizeof(struct cdrom_multisession));
+
+#if DEBUG_MULTIS
+ 	if (ms.addr_format == CDROM_MSF)
+               	printk("optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
+			ms.xa_flag,
+			ms.addr.msf.minute,
+			ms.addr.msf.second,
+			ms.addr.msf.frame);
+	else
+		printk("optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
+			ms.xa_flag,
+			ms.addr.lba,
+			disk_info.last_session.minute,
+			disk_info.last_session.second,
+			disk_info.last_session.frame);
+#endif DEBUG_MULTIS
+
+	return 0;
+}
+#endif MULTISESSION
+
+
+static int cdromreset(void)
+{
+	if (state != S_IDLE) {
+		error = 1;
+		tries = 0;
 	}
-	case CDROMMULTISESSION:
-		return -EINVAL; /* unluckily, not implemented yet */
 
-	default:
+	toc_uptodate = 0;
+	opt_invalidate_buffers();
+	audio_status = CDROM_AUDIO_NO_STATUS;
+
+	if (!reset_drive())
+		return -EIO;
+	return 0;
+}
+
+/* VFS calls */
+
+
+static int opt_ioctl(struct inode *ip, struct file *fp,
+                     unsigned int cmd, unsigned long arg)
+{
+	int err;
+
+	DEBUG((DEBUG_VFS, "starting opt_ioctl"));
+
+	if (!ip)
 		return -EINVAL;
+
+	if (cmd == CDROMRESET)
+		return cdromreset();
+
+	if (state != S_IDLE)
+		return -EBUSY;
+
+	err = drive_status();
+	if (err < 0) {
+		DEBUG((DEBUG_VFS, "drive_status: %02x", -err));
+		return -EIO;
+	}
+	err = update_toc();
+	if (err < 0) {
+		DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
+		return -EIO;
 	}
-#ifdef DEBUG_VFS
-	printk("optcd: exiting opt_ioctl\n");
+
+	DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
+
+	switch (cmd) {
+	case CDROMPAUSE:	return cdrompause();
+	case CDROMRESUME:	return cdromresume();
+	case CDROMPLAYMSF:	return cdromplaymsf(arg);
+	case CDROMPLAYTRKIND:	return cdromplaytrkind(arg);
+	case CDROMREADTOCHDR:	return cdromreadtochdr(arg);
+	case CDROMREADTOCENTRY:	return cdromreadtocentry(arg);
+
+	case CDROMSTOP:		err = exec_cmd(COMSTOP);
+				if (err < 0) {
+					DEBUG((DEBUG_VFS,
+						"exec_cmd COMSTOP: %02x",
+						-err));
+					return -EIO;
+				}
+				audio_status = CDROM_AUDIO_NO_STATUS;
+				break;
+	case CDROMSTART:	err = exec_cmd(COMCLOSE);  /* What else? */
+				if (err < 0) {
+					DEBUG((DEBUG_VFS,
+						"exec_cmd COMCLOSE: %02x",
+						-err));
+					return -EIO;
+				}
+				break;
+	case CDROMEJECT:	err = exec_cmd(COMUNLOCK);
+				if (err < 0) {
+					DEBUG((DEBUG_VFS,
+						"exec_cmd COMUNLOCK: %02x",
+						-err));
+					return -EIO;
+				}
+				err = exec_cmd(COMOPEN);
+				if (err < 0) {
+					DEBUG((DEBUG_VFS,
+						"exec_cmd COMOPEN: %02x",
+						-err));
+					return -EIO;
+				}
+				break;
+
+	case CDROMVOLCTRL:	return cdromvolctrl(arg);
+	case CDROMSUBCHNL:	return cdromsubchnl(arg);
+
+	case CDROMREADAUDIO:	return -EINVAL; /* not implemented */
+	case CDROMEJECT_SW:	auto_eject = (char) arg;
+				break;
+
+#ifdef MULTISESSION
+	case CDROMMULTISESSION:	return cdrommultisession(arg);
 #endif
+
+	case CDROM_GET_UPC:	return -EINVAL; /* not implemented */
+	case CDROMVOLREAD:	return -EINVAL; /* not implemented */
+
+	case CDROMREADRAW:
+			return cdromread(arg, BLOCKSIZE_RAW, COMREADRAW);
+	case CDROMREADCOOKED:
+			return cdromread(arg, BLOCKSIZE, COMREAD);
+	case CDROMSEEK:		return cdromseek(arg);
+	case CDROMPLAYBLK:	return -EINVAL; /* not implemented */
+	default:		return -EINVAL;
+	}
 	return 0;
 }
 
-static int optPresent = 0;
-static int opt_open_count = 0;
+
+static int open_count = 0;
 
 /* Open device special file; check that a disk is in. */
-static int opt_open(struct inode *ip, struct file *fp) {
-#ifdef DEBUG_VFS
-	printk("optcd: starting opt_open\n");
-#endif
-	if (!optPresent)
-		return -ENXIO;		/* no hardware */
-	if (!opt_open_count && opt_state == OPT_S_IDLE) {
-		int st;
+static int opt_open(struct inode *ip, struct file *fp)
+{
+	DEBUG((DEBUG_VFS, "starting opt_open"));
+
+	if (!open_count++ && state == S_IDLE) {
+		int status;
+
 		opt_invalidate_buffers();
-		if ((st = optGetStatus()) < 0)
+		status = drive_status();
+		if (status < 0) {
+			DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
 			return -EIO;
-		if (st & ST_DOOR_OPEN) {
-			optCmd(COMCLOSE);			/* close door */
-			if ((st = optGetStatus()) < 0)		/* try again */
+		}
+		DEBUG((DEBUG_VFS, "status: %02x", status));
+		if (status & ST_DOOR_OPEN) {
+			status = exec_cmd(COMCLOSE);	/* close door */
+			if (status < 0) {
+				DEBUG((DEBUG_VFS,
+					"exec_cmd COMCLOSE: %02x", -status));
+			}
+			status = drive_status();	/* try again */
+			if (status < 0) {
+				DEBUG((DEBUG_VFS,
+					"drive_status: %02x", -status));
 				return -EIO;
+			}
+			DEBUG((DEBUG_VFS, "status: %02x", status));
 		}
-		if (st & (ST_DOOR_OPEN|ST_DRVERR)) {
+		if (status & (ST_DOOR_OPEN|ST_DRVERR)) {
 			printk("optcd: no disk or door open\n");
 			return -EIO;
 		}
-		if (optUpdateToc() < 0)
+		status = exec_cmd(COMLOCK);		/* Lock door */
+		if (status < 0) {
+			DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
+		}
+		status = update_toc();	/* Read table of contents */
+		if (status < 0)	{
+			DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
 			return -EIO;
+		}
 	}
-	opt_open_count++;
 	MOD_INC_USE_COUNT;
-	optCmd(COMLOCK);		/* Lock door */
-#ifdef DEBUG_VFS
-	printk("optcd: exiting opt_open\n");
-#endif
+
+	DEBUG((DEBUG_VFS, "exiting opt_open"));
+
 	return 0;
 }
 
+
 /* Release device special file; flush all blocks from the buffer cache */
-static void opt_release(struct inode *ip, struct file *fp) {
-#ifdef DEBUG_VFS
-	printk("optcd: executing opt_release\n");
-	printk("inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
-		ip, ip -> i_rdev, fp);
-#endif
-	if (!--opt_open_count) {
+static void opt_release(struct inode *ip, struct file *fp)
+{
+	int status;
+
+	DEBUG((DEBUG_VFS, "executing opt_release"));
+	DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
+		ip, ip -> i_rdev, fp));
+
+	if (!--open_count) {
 		opt_invalidate_buffers();
 		sync_dev(ip -> i_rdev);
 		invalidate_buffers(ip -> i_rdev);
+	 	status = exec_cmd(COMUNLOCK);	/* Unlock door */
+		if (status < 0) {
+			DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
+		}
+		if (auto_eject) {
+			status = exec_cmd(COMOPEN);
+			DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
+		}
 		CLEAR_TIMER;
-		optCmd(COMUNLOCK);	/* Unlock door */
 	}
 	MOD_DEC_USE_COUNT;
 }
+
+/* Driver initialisation */
 
 
-/* Initialisation */
-
-static int version_ok(void) {
+/* Returns 1 if a drive is detected with a version string
+   starting with "DOLPHIN". Otherwise 0. */
+static int version_ok(void)
+{
 	char devname[100];
-	int count, i, ch;
+	int count, i, ch, status;
 
-	if (optCmd(COMVERSION) < 0)
+	status = exec_cmd(COMVERSION);
+	if (status < 0) {
+		DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
 		return 0;
-	if ((count = optGetData()) < 0)
+	}
+	if ((count = get_data(1)) < 0) {
+		DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
 		return 0;
+	}
 	for (i = 0, ch = -1; count > 0; count--) {
-		if ((ch = optGetData()) < 0)
+		if ((ch = get_data(1)) < 0) {
+			DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
 			break;
+		}
 		if (i < 99)
 			devname[i++] = ch;
 	}
 	devname[i] = '\0';
 	if (ch < 0)
 		return 0;
+
 	printk("optcd: Device %s detected\n", devname);
 	return ((devname[0] == 'D')
 	     && (devname[1] == 'O')
@@ -1386,17 +1960,57 @@
 };
 
 
+/* Flag indicates if ISP16 detection and initialisation should be skipped */
+#define skip_isp16_init	noisp16		/* Needed for the modutils. */
+static int skip_isp16_init = 0;
+
 /* Get kernel parameter when used as a kernel driver */
-void optcd_setup(char *str, int *ints) {
+void optcd_setup(char *str, int *ints)
+{
 	if (ints[0] > 0)
 		optcd_port = ints[1];
+	if (!strcmp(str ,"noisp16"))
+		skip_isp16_init = 1;
 }
 
-/*
- * Test for presence of drive and initialize it. Called at boot time.
- */
 
-int optcd_init(void) {
+#ifdef PROBE_ISP16
+/* If ISP16 I/O ports not already reserved, probe for an ISP16 interface card,
+   and enable SONY mode with no interrupts and no DMA.
+   (As far as I know, all Optics 8000 AT drives come with a SONY interface.
+   Interrupts and DMA are not supported).
+   Returns false only if ISP16 detected but couldn't be initialised. */
+static int probe_isp16(void)
+{
+	if (skip_isp16_init)
+		return 1;
+
+	if (check_region(ISP16_DRIVE_SET_PORT, 5))
+		return 1;
+
+	if (isp16_detect() < 0 ) {
+		printk( "No ISP16 cdrom interface found.\n" );
+		return 1;
+	}
+
+	isp16_sound_config();	/* Enable playing through speakers */
+
+	printk( "ISP16 cdrom interface detected.\n");
+	if (isp16_cdi_config(optcd_port, ISP16_SONY, 0, 0) < 0) {
+		printk( "ISP16 configure error.\n" );
+		return 0;
+	}
+	return 1;
+}
+#endif PROBE_ISP16
+
+
+/* Test for presence of drive and initialize it. Called at boot time
+   or during module initialisation. */
+int optcd_init(void)
+{
+	int status;
+
 	if (optcd_port <= 0) {
 		printk("optcd: no Optics Storage CDROM Initialization\n");
 		return -EIO;
@@ -1407,29 +2021,12 @@
 		return -EIO;
 	}
 
-	if (!check_region(ISP16_DRIVE_SET_PORT, 5)) {
-	/* If someone else has'nt already reserved these ports,
-	   probe for an ISP16 interface card, and enable SONY mode
-	   with no interrupts and no DMA. (As far as I know, all optics
-	   drives come with a SONY interface.) */
-  if ( (isp16_type=isp16_detect()) < 0 )
-    printk( "No ISP16 cdrom interface found.\n" );
-  else {
-    u_char expected_drive;
-
-    printk( "ISP16 cdrom interface (%s optional IDE) detected.\n",
-      (isp16_type==2)?"with":"without" );
-
-    expected_drive = (isp16_type?ISP16_SANYO1:ISP16_SANYO0);
-
-    if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) {
-      printk( "ISP16 cdrom interface has not been properly configured.\n" );
-      return -EIO;
-    }
-  }
-	}
+#ifdef PROBE_ISP16
+	if (!probe_isp16())
+		return -EIO;
+#endif
 
-	if (!optResetDrive()) {
+	if (!reset_drive()) {
 		printk("optcd: drive at 0x%x not ready\n", optcd_port);
 		return -EIO;
 	}
@@ -1437,8 +2034,10 @@
 		printk("optcd: unknown drive detected; aborting\n");
 		return -EIO;
 	}
-	if (optCmd(COMINITDOUBLE) < 0) {
+	status = exec_cmd(COMINITDOUBLE);
+	if (status < 0) {
 		printk("optcd: cannot init double speed mode\n");
+		DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
 		return -EIO;
 	}
 	if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
@@ -1446,22 +2045,26 @@
 		printk("optcd: unable to get major %d\n", MAJOR_NR);
 		return -EIO;
 	}
+
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	read_ahead[MAJOR_NR] = 4;
 	request_region(optcd_port, 4, "optcd");
-	optPresent = 1;
-	printk("optcd: 8000 AT CDROM at 0x%x\n", optcd_port);
+
+	printk("optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
 	return 0;
 }
 
+
 #ifdef MODULE
 int init_module(void)
 {
 	return optcd_init();
 }
 
-void cleanup_module(void) {
-	if ((unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL)) {
+
+void cleanup_module(void)
+{
+	if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
 		printk("optcd: what's that: can't unregister\n");
 		return;
 	}
@@ -1469,191 +2072,3 @@
 	printk("optcd: module released.\n");
 }
 #endif MODULE
-
-
-/*
- * -- ISP16 detection and configuration
- *
- *    Copyright (c) 1995, Eric van der Maarel <maarel@marin.nl>
- *
- *    Version 0.5
- *
- *    Detect cdrom interface on ISP16 soundcard.
- *    Configure cdrom interface.
- *
- *    Algorithm for the card with no IDE support option taken
- *    from the CDSETUP.SYS driver for MSDOS,
- *    by OPTi Computers, version 2.03.
- *    Algorithm for the IDE supporting ISP16 as communicated
- *    to me by Vadim Model and Leo Spiekman.
- *
- *    Use, modifification or redistribution of this software is
- *    allowed under the terms of the GPL.
- *
- */
-
-
-#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p))
-#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
-
-static short
-isp16_detect(void)
-{
-
-  if ( !( isp16_with_ide__detect() < 0 ) )
-    return(2);
-  else
-    return( isp16_no_ide__detect() );
-}
-
-static short
-isp16_no_ide__detect(void)
-{
-  u_char ctrl;
-  u_char enable_cdrom;
-  u_char io;
-  short i = -1;
-
-  isp16_ctrl = ISP16_NO_IDE__CTRL;
-  isp16_enable_cdrom_port = ISP16_NO_IDE__ENABLE_CDROM_PORT;
-
-  /* read' and write' are a special read and write, respectively */
-
-  /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */
-  ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC;
-  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
-
-  /* read' 3,4 and 5-bit from the cdrom enable port */
-  enable_cdrom = ISP16_IN( ISP16_NO_IDE__ENABLE_CDROM_PORT ) & 0x38;
-
-  if ( !(enable_cdrom & 0x20) ) {  /* 5-bit not set */
-    /* read' last 2 bits of ISP16_IO_SET_PORT */
-    io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03;
-    if ( ((io&0x01)<<1) == (io&0x02) ) {  /* bits are the same */
-      if ( io == 0 ) {  /* ...the same and 0 */
-        i = 0;
-        enable_cdrom |= 0x20;
-      }
-      else {  /* ...the same and 1 */  /* my card, first time 'round */
-        i = 1;
-        enable_cdrom |= 0x28;
-      }
-      ISP16_OUT( ISP16_NO_IDE__ENABLE_CDROM_PORT, enable_cdrom );
-    }
-    else {  /* bits are not the same */
-      ISP16_OUT( ISP16_CTRL_PORT, ctrl );
-      return(i); /* -> not detected: possibly incorrect conclusion */
-    }
-  }
-  else if ( enable_cdrom == 0x20 )
-    i = 0;
-  else if ( enable_cdrom == 0x28 )  /* my card, already initialised */
-    i = 1;
-
-  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
-
-  return(i);
-}
-
-static short
-isp16_with_ide__detect(void)
-{
-  u_char ctrl;
-  u_char tmp;
-
-  isp16_ctrl = ISP16_IDE__CTRL;
-  isp16_enable_cdrom_port = ISP16_IDE__ENABLE_CDROM_PORT;
-
-  /* read' and write' are a special read and write, respectively */
-
-  /* read' ISP16_CTRL_PORT and save */
-  ctrl = ISP16_IN( ISP16_CTRL_PORT );
-
-  /* write' zero to the ctrl port and get response */
-  ISP16_OUT( ISP16_CTRL_PORT, 0 );
-  tmp = ISP16_IN( ISP16_CTRL_PORT );
-
-  if ( tmp != 2 )  /* isp16 with ide option not detected */
-    return(-1);
-
-  /* restore ctrl port value */
-  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
-  
-  return(2);
-}
-
-static short
-isp16_config( int base, u_char drive_type, int irq, int dma )
-{
-  u_char base_code;
-  u_char irq_code;
-  u_char dma_code;
-  u_char i;
-
-  if ( (drive_type == ISP16_MITSUMI) && (dma != 0) )
-    printk( "Mitsumi cdrom drive has no dma support.\n" );
-
-  switch (base) {
-  case 0x340: base_code = ISP16_BASE_340; break;
-  case 0x330: base_code = ISP16_BASE_330; break;
-  case 0x360: base_code = ISP16_BASE_360; break;
-  case 0x320: base_code = ISP16_BASE_320; break;
-  default:
-    printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base );
-    return(-1);
-  }
-  switch (irq) {
-  case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */
-  case 5: irq_code = ISP16_IRQ_5;
-          printk( "Irq 5 shouldn't be used by cdrom interface on ISP16,"
-            " due to possible conflicts with the soundcard.\n");
-          break;
-  case 7: irq_code = ISP16_IRQ_7;
-          printk( "Irq 7 shouldn't be used by cdrom interface on ISP16,"
-            " due to possible conflicts with the soundcard.\n");
-          break;
-  case 3: irq_code = ISP16_IRQ_3; break;
-  case 9: irq_code = ISP16_IRQ_9; break;
-  case 10: irq_code = ISP16_IRQ_10; break;
-  case 11: irq_code = ISP16_IRQ_11; break;
-  default:
-    printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq );
-    return(-1);
-  }
-  switch (dma) {
-  case 0: dma_code = ISP16_DMA_X; break;  /* disable dma */
-  case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16,"
-            " due to conflict with the soundcard.\n");
-          return(-1); break;
-  case 3: dma_code = ISP16_DMA_3; break;
-  case 5: dma_code = ISP16_DMA_5; break;
-  case 6: dma_code = ISP16_DMA_6; break;
-  case 7: dma_code = ISP16_DMA_7; break;
-  default:
-    printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma );
-    return(-1);
-  }
-
-  if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 &&
-    drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 &&
-    drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI &&
-    drive_type != ISP16_DRIVE_X ) {
-    printk( "Drive type (code 0x%02X) not supported by cdrom"
-     " interface on ISP16.\n", drive_type );
-    return(-1);
-  }
-
-  /* set type of interface */
-  i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK;  /* clear some bits */
-  ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type );
-
-  /* enable cdrom on interface with ide support */
-  if ( isp16_type > 1 )
-    ISP16_OUT( isp16_enable_cdrom_port, ISP16_ENABLE_CDROM );
-
-  /* set base address, irq and dma */
-  i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK;  /* keep some bits */
-  ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code );
-
-  return(0);
-}
diff -u --recursive --new-file v1.3.57/linux/drivers/cdrom/optcd_isp16.h linux/drivers/cdrom/optcd_isp16.h
--- v1.3.57/linux/drivers/cdrom/optcd_isp16.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/cdrom/optcd_isp16.h	Thu Jan 18 06:22:13 1996
@@ -0,0 +1,337 @@
+/* linux/drivers/cdrom/optcd_isp16.h - ISP16 CDROM interface configuration
+   $Id: optcd_isp16.h,v 1.3 1996/01/15 18:43:11 root Exp root $
+
+   Extracts from linux/drivers/cdrom/sjcd.c
+   For copyrights see linux/drivers/cdrom/optcd.c
+*/
+
+
+/* Some (Media)Magic */
+/* define types of drive the interface on an ISP16 card may be looking at */
+#define ISP16_DRIVE_X 0x00
+#define ISP16_SONY  0x02
+#define ISP16_PANASONIC0 0x02
+#define ISP16_SANYO0 0x02
+#define ISP16_MITSUMI  0x04
+#define ISP16_PANASONIC1 0x06
+#define ISP16_SANYO1 0x06
+#define ISP16_DRIVE_NOT_USED 0x08  /* not used */
+#define ISP16_DRIVE_SET_MASK 0xF1  /* don't change 0-bit or 4-7-bits*/
+/* ...for port */
+#define ISP16_DRIVE_SET_PORT 0xF8D
+/* set io parameters */
+#define ISP16_BASE_340  0x00
+#define ISP16_BASE_330  0x40
+#define ISP16_BASE_360  0x80
+#define ISP16_BASE_320  0xC0
+#define ISP16_IRQ_X  0x00
+#define ISP16_IRQ_5  0x04  /* shouldn't be used due to soundcard conflicts */
+#define ISP16_IRQ_7  0x08  /* shouldn't be used due to soundcard conflicts */
+#define ISP16_IRQ_3  0x0C
+#define ISP16_IRQ_9  0x10
+#define ISP16_IRQ_10  0x14
+#define ISP16_IRQ_11  0x18
+#define ISP16_DMA_X  0x03
+#define ISP16_DMA_3  0x00
+#define ISP16_DMA_5  0x00
+#define ISP16_DMA_6  0x01
+#define ISP16_DMA_7  0x02
+#define ISP16_IO_SET_MASK  0x20  /* don't change 5-bit */
+/* ...for port */
+#define ISP16_IO_SET_PORT  0xF8E
+/* enable the card */
+#define ISP16_C928__ENABLE_PORT  0xF90  /* ISP16 with OPTi 82C928 chip */
+#define ISP16_C929__ENABLE_PORT  0xF91  /* ISP16 with OPTi 82C929 chip */
+#define ISP16_ENABLE_CDROM  0x80  /* seven bit */
+
+/* the magic stuff */
+#define ISP16_CTRL_PORT  0xF8F
+#define ISP16_C928__CTRL  0xE2  /* ISP16 with OPTi 82C928 chip */
+#define ISP16_C929__CTRL  0xE3  /* ISP16 with OPTi 82C929 chip */
+
+static short isp16_detect(void);
+static short isp16_c928__detect(void);
+static short isp16_c929__detect(void);
+static short isp16_cdi_config( int base, u_char drive_type, int irq, int dma );
+static void isp16_sound_config( void );
+static short isp16_type; /* dependent on type of interface card */
+static u_char isp16_ctrl;
+static u_short isp16_enable_port;
+
+/*static int sjcd_present = 0;*/
+static u_char special_mask = 0;
+
+static unsigned char defaults[ 16 ] = {
+  0xA8, 0xA8, 0x18, 0x18, 0x18, 0x18, 0x8E, 0x8E,
+  0x03, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00
+};
+/* ------------- */
+/*
+ * -- ISP16 detection and configuration
+ *
+ *    Copyright (c) 1995, Eric van der Maarel <maarel@marin.nl>
+ *
+ *    Version 0.5
+ *
+ *    Detect cdrom interface on ISP16 soundcard.
+ *    Configure cdrom interface.
+ *    Configure sound interface.
+ *
+ *    Algorithm for the card with OPTi 82C928 taken
+ *    from the CDSETUP.SYS driver for MSDOS,
+ *    by OPTi Computers, version 2.03.
+ *    Algorithm for the card with OPTi 82C929 as communicated
+ *    to me by Vadim Model and Leo Spiekman.
+ *
+ *    Use, modifification or redistribution of this software is
+ *    allowed under the terms of the GPL.
+ *
+ */
+
+
+#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p))
+#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
+
+static short
+isp16_detect(void)
+{
+
+  if ( !( isp16_c929__detect() < 0 ) )
+    return(2);
+  else
+    return( isp16_c928__detect() );
+}
+
+static short
+isp16_c928__detect(void)
+{
+  u_char ctrl;
+  u_char enable_cdrom;
+  u_char io;
+  short i = -1;
+
+  isp16_ctrl = ISP16_C928__CTRL;
+  isp16_enable_port = ISP16_C928__ENABLE_PORT;
+
+  /* read' and write' are a special read and write, respectively */
+
+  /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */
+  ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC;
+  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+
+  /* read' 3,4 and 5-bit from the cdrom enable port */
+  enable_cdrom = ISP16_IN( ISP16_C928__ENABLE_PORT ) & 0x38;
+
+  if ( !(enable_cdrom & 0x20) ) {  /* 5-bit not set */
+    /* read' last 2 bits of ISP16_IO_SET_PORT */
+    io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03;
+    if ( ((io&0x01)<<1) == (io&0x02) ) {  /* bits are the same */
+      if ( io == 0 ) {  /* ...the same and 0 */
+        i = 0;
+        enable_cdrom |= 0x20;
+      }
+      else {  /* ...the same and 1 */  /* my card, first time 'round */
+        i = 1;
+        enable_cdrom |= 0x28;
+      }
+      ISP16_OUT( ISP16_C928__ENABLE_PORT, enable_cdrom );
+    }
+    else {  /* bits are not the same */
+      ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+      return(i); /* -> not detected: possibly incorrect conclusion */
+    }
+  }
+  else if ( enable_cdrom == 0x20 )
+    i = 0;
+  else if ( enable_cdrom == 0x28 )  /* my card, already initialised */
+    i = 1;
+
+  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+
+  return(i);
+}
+
+static short
+isp16_c929__detect(void)
+{
+  u_char ctrl;
+  u_char tmp;
+
+  isp16_ctrl = ISP16_C929__CTRL;
+  isp16_enable_port = ISP16_C929__ENABLE_PORT;
+
+  /* read' and write' are a special read and write, respectively */
+
+  /* read' ISP16_CTRL_PORT and save */
+  ctrl = ISP16_IN( ISP16_CTRL_PORT );
+
+  /* write' zero to the ctrl port and get response */
+  ISP16_OUT( ISP16_CTRL_PORT, 0 );
+  tmp = ISP16_IN( ISP16_CTRL_PORT );
+
+  if ( tmp != 2 )  /* isp16 with 82C929 not detected */
+    return(-1);
+
+  /* restore ctrl port value */
+  ISP16_OUT( ISP16_CTRL_PORT, ctrl );
+  
+  return(2);
+}
+
+static short
+isp16_cdi_config( int base, u_char drive_type, int irq, int dma )
+{
+  u_char base_code;
+  u_char irq_code;
+  u_char dma_code;
+  u_char i;
+
+  if ( (drive_type == ISP16_MITSUMI) && (dma != 0) )
+    printk( "Mitsumi cdrom drive has no dma support.\n" );
+
+  switch (base) {
+  case 0x340: base_code = ISP16_BASE_340; break;
+  case 0x330: base_code = ISP16_BASE_330; break;
+  case 0x360: base_code = ISP16_BASE_360; break;
+  case 0x320: base_code = ISP16_BASE_320; break;
+  default:
+    printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base );
+    return(-1);
+  }
+  switch (irq) {
+  case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */
+  case 5: irq_code = ISP16_IRQ_5;
+          printk( "Irq 5 shouldn't be used by cdrom interface on ISP16,"
+            " due to possible conflicts with the soundcard.\n");
+          break;
+  case 7: irq_code = ISP16_IRQ_7;
+          printk( "Irq 7 shouldn't be used by cdrom interface on ISP16,"
+            " due to possible conflicts with the soundcard.\n");
+          break;
+  case 3: irq_code = ISP16_IRQ_3; break;
+  case 9: irq_code = ISP16_IRQ_9; break;
+  case 10: irq_code = ISP16_IRQ_10; break;
+  case 11: irq_code = ISP16_IRQ_11; break;
+  default:
+    printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq );
+    return(-1);
+  }
+  switch (dma) {
+  case 0: dma_code = ISP16_DMA_X; break;  /* disable dma */
+  case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16,"
+            " due to conflict with the soundcard.\n");
+          return(-1); break;
+  case 3: dma_code = ISP16_DMA_3; break;
+  case 5: dma_code = ISP16_DMA_5; break;
+  case 6: dma_code = ISP16_DMA_6; break;
+  case 7: dma_code = ISP16_DMA_7; break;
+  default:
+    printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma );
+    return(-1);
+  }
+
+  if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 &&
+    drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 &&
+    drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI &&
+    drive_type != ISP16_DRIVE_X ) {
+    printk( "Drive type (code 0x%02X) not supported by cdrom"
+     " interface on ISP16.\n", drive_type );
+    return(-1);
+  }
+
+  /* set type of interface */
+  i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK;  /* clear some bits */
+  ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type );
+
+  /* enable cdrom on interface with 82C929 chip */
+  if ( isp16_type > 1 )
+    ISP16_OUT( isp16_enable_port, ISP16_ENABLE_CDROM );
+
+  /* set base address, irq and dma */
+  i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK;  /* keep some bits */
+  ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code );
+
+  return(0);
+}
+
+static void isp16_sound_config( void )
+{
+  int i;
+  u_char saved;
+
+  saved = ISP16_IN( 0xF8D ) & 0x8F;
+    
+  ISP16_OUT( 0xF8D, 0x40 );
+
+  /*
+   * Now we should wait for a while...
+   */
+  for( i = 16*1024; i--; );
+  
+  ISP16_OUT( 0xF8D, saved );
+
+  ISP16_OUT( 0xF91, 0x1B );
+
+  for( i = 5*64*1024; i != 0; i-- )
+    if( !( inb( 0x534 ) & 0x80 ) ) break;
+
+  if( i > 0 ) {
+    saved = ( inb( 0x534 ) & 0xE0 ) | 0x0A;
+    outb( saved, 0x534 );
+
+    special_mask = ( inb( 0x535 ) >> 4 ) & 0x08;
+
+    saved = ( inb( 0x534 ) & 0xE0 ) | 0x0C;
+    outb( saved, 0x534 );
+
+    switch( inb( 0x535 ) ) {
+      case 0x09:
+      case 0x0A:
+        special_mask |= 0x05;
+        break;
+      case 0x8A:
+        special_mask = 0x0F;
+        break;
+      default:
+        i = 0;
+    }
+  }
+  if ( i == 0 ) {
+    printk( "Strange MediaMagic, but\n" );
+  }
+  else {
+    printk( "Conf:" );
+    saved = inb( 0x534 ) & 0xE0;
+    for( i = 0; i < 16; i++ ) {
+      outb( 0x20 | ( u_char )i, 0x534 );
+      outb( defaults[i], 0x535 );
+    }
+    for ( i = 0; i < 16; i++ ) {
+      outb( 0x20 | ( u_char )i, 0x534 );
+      saved = inb( 0x535 );
+      printk( " %02X", saved );
+    }
+    printk( "\n" );
+  }
+
+  ISP16_OUT( 0xF91, 0xA0 | special_mask );
+
+  /*
+   * The following have no explaination yet.
+   */
+  ISP16_OUT( 0xF90, 0xA2 );
+  ISP16_OUT( 0xF92, 0x03 );
+
+  /*
+   * Turn general sound on and set total volume.
+   */
+  ISP16_OUT( 0xF93, 0x0A );
+
+/*
+  outb( 0x04, 0x224 );
+  saved = inb( 0x225 );
+  outb( 0x04, 0x224 );
+  outb( saved, 0x225 );
+*/
+
+}
diff -u --recursive --new-file v1.3.57/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v1.3.57/linux/drivers/char/Config.in	Sun Jan 14 16:30:10 1996
+++ linux/drivers/char/Config.in	Sun Jan 14 16:22:16 1996
@@ -48,3 +48,4 @@
      bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   fi
 fi
+endmenu
diff -u --recursive --new-file v1.3.57/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.57/linux/drivers/char/Makefile	Wed Dec 27 09:12:13 1995
+++ linux/drivers/char/Makefile	Mon Jan 15 07:59:13 1996
@@ -95,6 +95,7 @@
 ifdef CONFIG_SOFT_WATCHDOG
 L_OBJS += softdog.o
 M = y
+# This is not modularized, so if configured then "mouse.c" will be resident
 endif
 
 ifdef CONFIG_QIC02_TAPE
@@ -106,16 +107,20 @@
 endif
 
 ifdef M
-L_OBJS += mouse.o
+LX_OBJS += mouse.o
 else
   ifdef MM
-  M_OBJS += mouse.o
+  MX_OBJS += mouse.o
   endif
 endif
-  
-ifdef CONFIG_SCC
+
+ifeq ($(CONFIG_SCC),y)
 L_OBJS += scc.o
-endif
+else
+  ifeq ($(CONFIG_SCC),m)
+  M_OBJS += scc.o
+  endif
+endif  
 
 ifdef CONFIG_TGA_CONSOLE
 L_OBJS += tga.o
diff -u --recursive --new-file v1.3.57/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
--- v1.3.57/linux/drivers/char/apm_bios.c	Mon Dec 11 15:42:02 1995
+++ linux/drivers/char/apm_bios.c	Sun Jan 14 19:08:31 1996
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
  * APM BIOS driver for Linux
  * Copyright 1994, 1995 Stephen Rothwell (Stephen.Rothwell@pd.necisa.oz.au)
  *
@@ -16,6 +16,10 @@
  *
  * October 1995, Rik Faith (faith@cs.unc.edu):
  *    Minor enhancements and updates (to the patch set) for 1.3.x
+ *    Documentation
+ * January 1996, Rik Faith (faith@cs.unc.edu):
+ *    Make /proc/apm easy to format (bump driver version)
+ *
  *
  * Reference:
  *
@@ -24,9 +28,9 @@
  *   Intel Order Number 241704-001.  Microsoft Part Number 781-110-X01.
  *
  * [This document is available free from Intel by calling 800.628.8686 (fax
- * 916.356.6100) or 800.548.4725.  It is also available from Microsoft by
- * calling 206.882.8080; and is ftpable from
- * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc]
+ * 916.356.6100) or 800.548.4725; or via anonymous ftp from
+ * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc.  It is also
+ * available from Microsoft by calling 206.882.8080.]
  *
  */
 
@@ -288,7 +292,7 @@
 
 static struct timer_list	apm_timer;
 
-static char			driver_version[] = "0.6b";
+static char			driver_version[] = "0.7";/* no spaces */
 
 #ifdef APM_DEBUG
 static char *	apm_event_name[] = {
@@ -882,69 +886,91 @@
 int apm_proc(char *buf)
 {
 	char *		p;
-	char *		power_stat;
-	char *		bat_stat;
 	unsigned short	bx;
 	unsigned short	cx;
 	unsigned short	dx;
 	unsigned short	error;
+	unsigned short  ac_line_status = 0xff;
+	unsigned short  battery_status = 0xff;
+	unsigned short  battery_flag   = 0xff;
+	unsigned short  percentage     = -1;
+	int             time_units     = -1;
+	char            *units         = "?";
 
 	if (apm_bios_info.version == 0)
 		return 0;
 	p = buf;
-	p += sprintf(p, "BIOS version: %d.%d\nFlags: 0x%02x\n",
-		     (apm_bios_info.version >> 8) & 0xff,
-		     apm_bios_info.version & 0xff,
-		     apm_bios_info.flags);
-	if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0)
-		return p - buf;
-	p += sprintf(p, "Entry %x:%lx cseg16 %x dseg %x",
-		     apm_bios_info.cseg, apm_bios_info.offset,
-		     apm_bios_info.cseg_16, apm_bios_info.dseg);
-	if (apm_bios_info.version > 0x100)
-		p += sprintf(p, " cseg len %x, dseg len %x",
-			     apm_bios_info.cseg_len, apm_bios_info.dseg_len);
-	*p++ = '\n';
-	error = apm_get_power_status(&bx, &cx, &dx);
-	if (error) {
-		strcpy(p, "Power status not available\n");
-		p += strlen(p);
-		return p - buf;
-	}
-	switch ((bx >> 8) & 0xff) {
-	case 0: power_stat = "off line"; break;
-	case 1: power_stat = "on line"; break;
-	case 2: power_stat = "on backup power"; break;
-	default: power_stat = "unknown"; break;
-	}
-	switch (bx & 0xff) {
-	case 0: bat_stat = "high"; break;
-	case 1: bat_stat = "low"; break;
-	case 2: bat_stat = "critical"; break;
-	case 3: bat_stat = "charging"; break;
-	default: bat_stat = "unknown"; break;
-	}
-	p += sprintf(p, "AC: %s\nBattery status: %s\nBattery life: ",
-		     power_stat, bat_stat);
-	if ((cx & 0xff) == 0xff) {
-		strcpy(p, "unknown");
-		p += strlen(p);
-	} else
-		p += sprintf(p, "%d%%", cx & 0xff);
-	*p++ = '\n';
-	if (apm_bios_info.version > 0x100) {
-		p += sprintf(p, "Battery flag: 0x%02x\nBattery life: ",
-			     (cx >> 8) & 0xff);
-		if (dx == 0xffff) {
-			strcpy(p, "unknown");
-			p += strlen(p);
+
+	if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) != 0) {
+		if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
+			ac_line_status = (bx >> 8) & 0xff;
+			battery_status = bx & 0xff;
+			if ((cx & 0xff) != 0xff)
+				percentage = cx & 0xff;
+	
+			if (apm_bios_info.version > 0x100) {
+				battery_flag = (cx >> 8) & 0xff;
+				if (dx != 0xffff) {
+					if ((dx & 0x8000) == 0x8000) {
+						units = "min";
+						time_units = dx & 0x7ffe;
+					} else {
+						units = "sec";
+						time_units = dx & 0x7fff;
+					}
+				}
+			}
 		}
-		else
-			p += sprintf(p, "%d %s", dx & 0x7fff,
-				     ((dx & 0x8000) == 0)
-				     ? "seconds" : "minutes");
-		*p++ = '\n';
 	}
+	/* Arguments, with symbols from linux/apm_bios.h.  Information is
+	   from the Get Power Status (0x0a) call unless otherwise noted.
+
+	   0) Linux driver version (this will change if format changes)
+	   1) APM BIOS Version.  Usually 1.0 or 1.1.
+	   2) APM flags from APM Installation Check (0x00):
+	      bit 0: APM_16_BIT_SUPPORT
+	      bit 1: APM_32_BIT_SUPPORT
+	      bit 2: APM_IDLE_SLOWS_CLOCK
+	      bit 3: APM_BIOS_DISABLED
+	      bit 4: APM_BIOS_DISENGAGED
+	   3) AC line status
+	      0x00: Off-line
+	      0x01: On-line
+	      0x02: On backup power (APM BIOS 1.1 only)
+	      0xff: Unknown
+	   4) Battery status
+	      0x00: High
+	      0x01: Low
+	      0x02: Critical
+	      0x03: Charging
+	      0xff: Unknown
+	   5) Battery flag
+	      bit 0: High
+	      bit 1: Low
+	      bit 2: Critical
+	      bit 3: Charging
+	      bit 7: No system battery
+	      0xff: Unknown
+	   6) Remaining battery life (percentage of charge):
+	      0-100: valid
+	      -1: Unknown
+	   7) Remaining battery life (time units):
+	      Number of remaining minutes or seconds
+	      -1: Unknown
+	   8) min = minutes; sec = seconds */
+	    
+	p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
+		     driver_version,
+		     (apm_bios_info.version >> 8) & 0xff,
+		     apm_bios_info.version & 0xff,
+		     apm_bios_info.flags,
+		     ac_line_status,
+		     battery_status,
+		     battery_flag,
+		     percentage,
+		     time_units,
+		     units );
+
 	return p - buf;
 }
 
@@ -1000,12 +1026,12 @@
 		set_limit(gdt[APM_DS >> 3], 64 * 1024);
 	} else {
 		set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
-		/*
-		 * This is not clear from the spec, but at least one
-		 * machine needs this to be a 64k segment.
-		 */
+		/* This is not clear from the spec, but at least one
+		   machine needs CS_16 to be a 64k segment, and the DEC
+		   Hinote Ultra CT475 (and others?) needs DS to be a 64k
+		   segment. */
 		set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
-		set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
+		set_limit(gdt[APM_DS >> 3], 64 * 1024);
 		apm_bios_info.version = 0x0101;
 		error = apm_driver_version(&apm_bios_info.version);
 		if (error != 0)
@@ -1047,10 +1073,12 @@
 			       (cx >> 8) & 0xff);
 			if (dx == 0xffff)
 				printk("unknown\n");
-			else
-				printk("%d %s\n", dx & 0x7fff,
-				       ((dx & 0x8000) == 0)
-				       ? "seconds" : "minutes");
+			else {
+				if ((dx & 0x8000)) 
+					printk("%d minutes\n", dx & 0x7ffe );
+				else
+					printk("%d seconds\n", dx & 0x7fff );
+			}
 		}
 	}
 
diff -u --recursive --new-file v1.3.57/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v1.3.57/linux/drivers/char/keyboard.c	Sat Nov 11 17:41:32 1995
+++ linux/drivers/char/keyboard.c	Sun Jan 14 16:22:17 1996
@@ -87,12 +87,6 @@
 extern void scrollback(int);
 extern void scrollfront(int);
 
-#ifdef __i386__
-#define fake_keyboard_interrupt() __asm__ __volatile__("int $0x21")
-#else
-#define fake_keyboard_interrupt() do ; while (0)
-#endif
-
 unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
 
 /*
@@ -128,6 +122,8 @@
 static volatile unsigned char reply_expected = 0;
 static volatile unsigned char acknowledge = 0;
 static volatile unsigned char resend = 0;
+/* used by kbd_bh - set by keyboard_interrupt */
+static volatile unsigned char do_poke_blanked_console = 0;
 
 extern void compute_shiftstate(void);
 
@@ -384,6 +380,7 @@
 		prev_scancode = 0;
 		goto end_kbd_intr;
 	}
+	do_poke_blanked_console = 1;
 	add_keyboard_randomness(scancode);
 
 	tty = ttytab[fg_console];
@@ -1178,11 +1175,10 @@
 		}
 		want_console = -1;
 	}
-	poke_blanked_console();
-	cli();
-	if ((inb_p(0x64) & kbd_read_mask) == 0x01)
-		fake_keyboard_interrupt();
-	sti();
+	if (do_poke_blanked_console) { /* do not unblank for a LED change */
+		do_poke_blanked_console = 0;
+		poke_blanked_console();
+	}
 }
 
 int kbd_init(void)
diff -u --recursive --new-file v1.3.57/linux/drivers/char/mouse.c linux/drivers/char/mouse.c
--- v1.3.57/linux/drivers/char/mouse.c	Wed Dec 27 09:12:13 1995
+++ linux/drivers/char/mouse.c	Mon Jan 15 07:59:13 1996
@@ -104,6 +104,14 @@
 
 #endif
 
+static struct symbol_table mouse_syms = {
+/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
+#include <linux/symtab_begin.h>
+	X(mouse_register),
+	X(mouse_deregister),
+#include <linux/symtab_end.h>
+};
+
 int mouse_init(void)
 {
 #ifndef MODULE
@@ -128,5 +136,6 @@
 		 MOUSE_MAJOR);
 		return -EIO;
 	}
-	return 0;
+
+	return register_symtab(&mouse_syms);
 }
diff -u --recursive --new-file v1.3.57/linux/drivers/char/tga.c linux/drivers/char/tga.c
--- v1.3.57/linux/drivers/char/tga.c	Tue Nov 21 13:22:09 1995
+++ linux/drivers/char/tga.c	Sat Jan 13 11:09:51 1996
@@ -421,6 +421,9 @@
  * dummy routines for the VESA blanking code, which is VGA only,
  * so we don't have to carry that stuff around for the TGA...
  */
+void vesa_powerdown(void)
+{
+}
 void vesa_blank(void)
 {
 }
diff -u --recursive --new-file v1.3.57/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v1.3.57/linux/drivers/char/tpqic02.c	Tue Nov 21 13:22:10 1995
+++ linux/drivers/char/tpqic02.c	Sun Jan 14 16:49:08 1996
@@ -193,8 +193,6 @@
  * Also, be careful to avoid IO conflicts with other devices!
  */
 
-#include <linux/autoconf.h>
-
 
 /*
 #define TDEBUG
diff -u --recursive --new-file v1.3.57/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.3.57/linux/drivers/char/tty_io.c	Wed Dec 13 09:02:45 1995
+++ linux/drivers/char/tty_io.c	Sun Jan 14 16:26:56 1996
@@ -73,6 +73,10 @@
 #include "vt_kern.h"
 #include "selection.h"
 
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
 #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
 #define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
 
@@ -211,8 +215,17 @@
 	int	retval = 0;
 	struct	tty_ldisc o_ldisc;
 
-	if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
-	    !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
+	if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
+		return -EINVAL;
+#ifdef CONFIG_KERNELD
+	/* Eduardo Blanco <ejbs@cs.cs.com.uy> */
+	if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
+		char modname [20];
+		sprintf(modname, "tty-ldisc-%d", ldisc);
+		request_module (modname);
+	}
+#endif
+	if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
 		return -EINVAL;
 
 	if (tty->ldisc.num == ldisc)
diff -u --recursive --new-file v1.3.57/linux/drivers/char/wd501p.h linux/drivers/char/wd501p.h
--- v1.3.57/linux/drivers/char/wd501p.h	Sun Jan 14 16:30:10 1996
+++ linux/drivers/char/wd501p.h	Sun Jan 14 16:50:12 1996
@@ -18,6 +18,8 @@
  *	Release 0.04.
  *
  */
+
+#include <linux/config.h>
  
 #define WATCHDOG_MINOR		130	/* Watchdog timer     */
 #define TEMP_MINOR		131	/* Temperature Sensor */
diff -u --recursive --new-file v1.3.57/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v1.3.57/linux/drivers/net/Config.in	Wed Dec 27 09:12:13 1995
+++ linux/drivers/net/Config.in	Mon Jan 15 07:59:08 1996
@@ -10,7 +10,7 @@
 if [ ! "$CONFIG_PPP" = "n" ]; then
   comment 'CCP compressors for PPP are only built as modules.'
 fi
-bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC
+tristate 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC
 tristate 'PLIP (parallel port) support' CONFIG_PLIP
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA
diff -u --recursive --new-file v1.3.57/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.57/linux/drivers/net/Makefile	Wed Dec 27 09:12:13 1995
+++ linux/drivers/net/Makefile	Mon Jan 15 07:59:13 1996
@@ -352,10 +352,10 @@
 # If anything built-in uses slhc, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
 ifdef CONFIG_SLHC_BUILTIN
-L_OBJS += slhc.o
+LX_OBJS += slhc.o
 else
   ifdef CONFIG_SLHC_MODULE
-  M_OBJS += slhc.o
+  MX_OBJS += slhc.o
   endif
 endif
 
diff -u --recursive --new-file v1.3.57/linux/drivers/net/README.tunnel linux/drivers/net/README.tunnel
--- v1.3.57/linux/drivers/net/README.tunnel	Tue Jun  6 11:22:07 1995
+++ linux/drivers/net/README.tunnel	Sun Jan 14 16:22:17 1996
@@ -113,9 +113,9 @@
 for machine A.  Machine A needs it's tunnel address to be on network 
 B so that when packets from machine B are unwrapped, the Linux 
 routing system knows that the address is a local one.  Due to a 
-feature of Linux, any packets recieved locally, bound for another
+feature of Linux, any packets received locally, bound for another
 local address, are simply routed through the loopback interface.
-This means that the tunnel device should never recieve packets.  Even
+This means that the tunnel device should never receive packets.  Even
 on machine B, it is the ethernet interface that is receiving wrapped
 packets, and once they are unwrapped they go back out the ethernet
 interface.  This could cause Linux to generate ICMP redirect messages
diff -u --recursive --new-file v1.3.57/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v1.3.57/linux/drivers/net/ne.c	Fri Nov 17 08:42:26 1995
+++ linux/drivers/net/ne.c	Wed Jan 17 09:11:43 1996
@@ -22,6 +22,7 @@
 			  sanity checks and bad clone support optional.
     Paul Gortmaker	: new reset code, reset card after probe at boot.
     Paul Gortmaker	: multiple card support for module users.
+    Paul Gortmaker	: Support for PCI ne2k clones, similar to lance.c
 
 */
 
@@ -32,10 +33,12 @@
 
 
 #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/bios32.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
@@ -90,6 +93,9 @@
 #define NESM_START_PG	0x40	/* First page of TX buffer */
 #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
 
+/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
+static unsigned char pci_irq_line = 0;
+
 int ne_probe(struct device *dev);
 static int ne_probe1(struct device *dev, int ioaddr);
 
@@ -131,16 +137,56 @@
 {"ne", ne_probe1, NE_IO_EXTENT, netcard_portlist};
 #else
 
+/*  Note that this probe only picks up one card at a time, even for multiple
+    PCI ne2k cards. Use "ether=0,0,eth1" if you have a second PCI ne2k card.
+    This keeps things consistent regardless of the bus type of the card. */
+
 int ne_probe(struct device *dev)
 {
     int i;
     int base_addr = dev ? dev->base_addr : 0;
 
+    /* First check any supplied i/o locations. User knows best. <cough> */
     if (base_addr > 0x1ff)	/* Check a single specified location. */
 	return ne_probe1(dev, base_addr);
     else if (base_addr != 0)	/* Don't probe at all. */
 	return ENXIO;
 
+    /* Then look for any installed PCI clones */
+#if defined(CONFIG_PCI)
+    if (pcibios_present()) {
+	int pci_index;
+	for (pci_index = 0; pci_index < 8; pci_index++) {
+		unsigned char pci_bus, pci_device_fn;
+		unsigned int pci_ioaddr;
+
+		/* Currently only Realtek are making PCI ne2k clones. */
+		if (pcibios_find_device (PCI_VENDOR_ID_REALTEK,
+				PCI_DEVICE_ID_REALTEK_8029, pci_index,
+				&pci_bus, &pci_device_fn) != 0)
+			break;	/* OK, now try to probe for std. ISA card */
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+				PCI_INTERRUPT_LINE, &pci_irq_line);
+		pcibios_read_config_dword(pci_bus, pci_device_fn,
+				PCI_BASE_ADDRESS_0, &pci_ioaddr);
+		/* Strip the I/O address out of the returned value */
+		pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+		/* Avoid already found cards from previous ne_probe() calls */
+		if (check_region(pci_ioaddr, NE_IO_EXTENT))
+			continue;
+		printk("ne.c: PCI BIOS reports ne2000 clone at i/o %#x, irq %d.\n",
+				pci_ioaddr, pci_irq_line);
+		if (ne_probe1(dev, pci_ioaddr) != 0) {	/* Shouldn't happen. */
+			printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
+			break;	/* Hrmm, try to probe for ISA card... */
+		}
+		pci_irq_line = 0;
+		return 0;
+	}
+    }
+#endif  /* defined(CONFIG_PCI) */
+
+    /* Last resort. The semi-risky ISA auto-probe. */
     for (i = 0; netcard_portlist[i]; i++) {
 	int ioaddr = netcard_portlist[i];
 	if (check_region(ioaddr, NE_IO_EXTENT))
@@ -289,6 +335,10 @@
     if (dev == NULL) {
 	printk("ne.c: Passed a NULL device.\n");
 	dev = init_etherdev(0, 0);
+    }
+
+    if (pci_irq_line) {
+	dev->irq = pci_irq_line;
     }
 
     if (dev->irq < 2) {
diff -u --recursive --new-file v1.3.57/linux/drivers/net/seeq8005.h linux/drivers/net/seeq8005.h
--- v1.3.57/linux/drivers/net/seeq8005.h	Tue Jul 11 10:02:49 1995
+++ linux/drivers/net/seeq8005.h	Sun Jan 14 16:22:17 1996
@@ -118,7 +118,7 @@
 #define	SEEQCFG2_SLOTSEL	(0x0040)	/* 0= standard IEEE802.3, 1= smaller,faster, non-standard */
 #define SEEQCFG2_NO_PREAM	(0x0080)	/* 1= user supplies Xmit preamble bytes */
 #define SEEQCFG2_ADDR_LEN	(0x0100)	/* 1= 2byte addresses */
-#define SEEQCFG2_REC_CRC	(0x0200)	/* 0= recieved packets will have CRC stripped from them */
+#define SEEQCFG2_REC_CRC	(0x0200)	/* 0= received packets will have CRC stripped from them */
 #define SEEQCFG2_XMIT_NO_CRC	(0x0400)	/* dont xmit CRC with each packet (user supplies it) */
 #define SEEQCFG2_LOOPBACK	(0x0800)
 #define SEEQCFG2_CTRLO		(0x1000)
@@ -133,7 +133,7 @@
 			unused:1,
 			data_follows:1,		/* if not set, process this as a header and pointer only */
 			chain_cont:1,		/* if set, more headers in chain 		only cmd bit valid in recv header */
-			xmit_recv:1;		/* if set, a xmit packet, else a recieve packet.*/
+			xmit_recv:1;		/* if set, a xmit packet, else a receive packet.*/
 	unsigned char	status;
 };
 
diff -u --recursive --new-file v1.3.57/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v1.3.57/linux/drivers/net/slhc.c	Mon Dec 11 15:42:03 1995
+++ linux/drivers/net/slhc.c	Mon Jan 15 07:59:13 1996
@@ -90,6 +90,8 @@
 static long decode(unsigned char **cpp);
 static unsigned char * put16(unsigned char *cp, unsigned short x);
 static unsigned short pull16(unsigned char **cpp);
+static void export_slhc_syms(void);
+static has_exported = 0;
 
 /* Initialize compression data structure
  *	slots must be in range 0 to 255 (zero meaning no compression)
@@ -101,6 +103,9 @@
 	register struct cstate *ts;
 	struct slcompress *comp;
 
+	if (!has_exported)
+		export_slhc_syms();
+
 	comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
 					    GFP_KERNEL);
 	if (! comp)
@@ -727,11 +732,31 @@
 	}
 }
 
+static struct symbol_table slhc_syms = {
+/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
+#include <linux/symtab_begin.h>
+        /* VJ header compression */
+        X(slhc_init),
+        X(slhc_free),
+        X(slhc_remember),
+        X(slhc_compress),
+        X(slhc_uncompress),
+        X(slhc_toss),
+#include <linux/symtab_end.h>
+};
+
+static void export_slhc_syms(void)
+{
+	register_symtab(&slhc_syms);
+	has_exported = 1;
+}
+
 #ifdef MODULE
 
 int init_module(void)
 {
 	printk("CSLIP: code copyright 1989 Regents of the University of California\n");
+	export_slhc_syms();
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.57/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v1.3.57/linux/drivers/pci/pci.c	Sat Dec 30 15:50:53 1995
+++ linux/drivers/pci/pci.c	Sun Jan 14 16:22:16 1996
@@ -85,6 +85,7 @@
 	DEVICE( MATROX,		MATROX_MGA_IMP,	"MGA Impression"),
 	DEVICE( CT,		CT_65545,	"65545"),
 	DEVICE( FD,		FD_36C70,	"TMC-18C30"),
+	DEVICE( SI,		SI_6201,	"6201"),
 	DEVICE( SI,		SI_6202,	"6202"),
 	DEVICE( SI,		SI_503,		"85C503"),
 	DEVICE( SI,		SI_501,		"85C501"),
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v1.3.57/linux/drivers/scsi/Config.in	Thu Jan  4 21:54:55 1996
+++ linux/drivers/scsi/Config.in	Wed Jan 17 07:27:35 1996
@@ -14,11 +14,12 @@
 mainmenu_option next_comment
 comment 'SCSI low-level drivers'
 
+dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
-dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC
+dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG.SCSI
 dep_tristate 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
 dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
 dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
@@ -37,3 +38,4 @@
 dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
 dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+endmenu
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.3.57/linux/drivers/scsi/Makefile	Tue Dec 26 04:45:36 1995
+++ linux/drivers/scsi/Makefile	Wed Jan 17 07:27:35 1996
@@ -33,6 +33,7 @@
 
 ifeq ($(CONFIG_SCSI),y)
 L_OBJS += hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+LX_OBJS += scsi_syms.o
 else
   ifeq ($(CONFIG_SCSI),m)
     MX_OBJS += scsi_syms.o
@@ -70,6 +71,14 @@
   ifeq ($(CONFIG_CHR_DEV_SG),m)
   M_OBJS += sg.o
   endif
+endif
+
+ifeq ($(CONFIG_SCSI_ADVANSYS),y)
+L_OBJS += advansys.o
+else
+	ifeq ($(CONFIG_SCSI_ADVANSYS),m)
+	M_OBJS += advansys.o
+	endif
 endif
 
 ifeq ($(CONFIG_SCSI_QLOGIC),y)
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v1.3.57/linux/drivers/scsi/advansys.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/advansys.c	Wed Jan 17 07:27:36 1996
@@ -0,0 +1,9061 @@
+/* $Id: advansys.c,v 1.11 1996/01/16 22:39:19 bobf Exp bobf $ */
+/*
+ * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
+ * 
+ * Copyright (c) 1995-1996 Advanced System Products, Inc.
+ * All Rights Reserved.
+ *
+ * This driver may be modified and freely distributed provided that
+ * the above copyright message and this comment are included in the
+ * distribution. The latest version of this driver is available at
+ * the AdvanSys FTP and BBS sites listed below.
+ *
+ * Please send questions, comments, bug reports to:
+ * bobf@advansys.com (Bob Frey)
+ */
+
+/* The driver has been tested with Linux 1.2.1 and 1.3.57 kernels. */
+#define ASC_VERSION "1.2"	/* AdvanSys Driver Version */
+
+/*
+
+  Documentation for the AdvanSys Driver
+
+  A. Adapters Supported by this Driver
+  B. Linux 1.2.X - Directions for Adding the AdvanSys Driver
+  C. Linux 1.3.X - Directions for Adding the AdvanSys Driver
+  D. Source Comments
+  E. Driver Compile Time Options and Debugging
+  F. Driver LILO Option
+  G. Release History
+  H. Known Problems or Issues
+  I. Credits
+  J. AdvanSys Contact Information
+
+
+  A. Adapters Supported by this Driver
+ 
+     AdvanSys (Advanced System Products, Inc.) manufactures the following
+     Bus-Mastering SCSI-2 Host Adapters for the ISA, EISA, VL, and PCI
+     buses. This Linux driver supports all of these adapters.
+     
+     The CDB counts below indicate the number of SCSI CDB (Command
+     Descriptor Block) requests that can be stored in the RISC chip
+     cache and board LRAM. The driver detect routine will display the
+     number of CDBs available for each adapter detected. This value
+     can be lowered in the BIOS by changing the 'Host Queue Size'
+     adapter setting.
+
+     Connectivity Products:
+       ABP920 - Bus-Master PCI 16 CDB
+       ABP930 - Bus-Master PCI 16 CDB
+       ABP5140 - Bus-Master PnP ISA 16 CDB
+   
+     Single Channel Products:
+       ABP542 - Bus-Master ISA 240 CDB
+       ABP5150 - Bus-Master ISA 240 CDB *
+       ABP742 - Bus-Master EISA 240 CDB
+       ABP842 - Bus-Master VL 240 CDB
+       ABP940 - Bus-Master PCI 240 CDB
+   
+     Dual Channel Products:
+       ABP950 - Dual Channel Bus-Master PCI 240 CDB Per Channel
+       ABP852 - Dual Channel Bus-Master VL 240 CDB Per Channel
+       ABP752 - Dual Channel Bus-Master EISA 240 CDB Per Channel
+
+     * This board is shipped by HP with the 4020i CD-R drive. It has
+       no BIOS so it cannot control a boot device, but it can control
+       any secondary devices.
+ 
+  B. Linux 1.2.X - Directions for Adding the AdvanSys Driver
+ 
+     There are two source files: advansys.h and advansys.c. Copy
+     both of these files to the directory /usr/src/linux/drivers/scsi.
+    
+     1. Add the following line to /usr/src/linux/arch/i386/config.in
+        after "comment 'SCSI low-level drivers'":
+    
+          bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
+    
+     2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c
+        after "#include "hosts.h"":
+    
+          #ifdef CONFIG_SCSI_ADVANSYS
+          #include "advansys.h"
+          #endif
+    
+        and after "static Scsi_Host_Template builtin_scsi_hosts[] =":
+    
+          #ifdef CONFIG_SCSI_ADVANSYS
+          ADVANSYS,
+          #endif
+    
+     3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile:
+    
+          ifdef CONFIG_SCSI_ADVANSYS
+          SCSI_SRCS := $(SCSI_SRCS) advansys.c
+          SCSI_OBJS := $(SCSI_OBJS) advansys.o
+          else
+          SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
+          endif
+
+     4. (Optional) If you would like to enable the LILO command line
+        and /etc/lilo.conf 'advansys' option, make the following changes.
+        This option can be used to disable I/O port scanning or to limit
+        I/O port scanning to specific addresses. Refer to the 'Driver
+        LILO Option' section below. Add the following lines to
+        /usr/src/linux/init/main.c in the prototype section:
+
+          extern void advansys_setup(char *str, int *ints);
+
+        and add the following lines to the bootsetups[] array.
+
+          #ifdef CONFIG_SCSI_ADVANSYS
+             { "advansys=", advansys_setup },
+          #endif
+
+     5. If you have the HP 4020i CD-R driver and Linux 1.2.X you should
+        add a fix to the CD-ROM target driver. This fix will allow
+        you to mount CDs with the iso9660 file system. Linux 1.3.X
+        already has this fix. In the file /usr/src/linux/drivers/scsi/sr.c
+        and function get_sectorsize() after the line:
+
+        if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048;
+
+        add the following line:
+
+        if(scsi_CDs[i].sector_size == 2340) scsi_CDs[i].sector_size = 2048;
+
+     6. In the directory /usr/src/linux run 'make config' to configure
+        the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to
+        make the kernel. If the AdvanSys driver is not configured, then
+        a loadable module can be built by running 'make modules' and
+        'make modules_install'. Use 'insmod' and 'rmmod' to install
+        and remove advansys.o.
+ 
+  C. Linux 1.3.X - Directions for Adding the AdvanSys Driver
+
+     There are two source files: advansys.h and advansys.c. Copy
+     both of these files to the directory /usr/src/linux/drivers/scsi.
+   
+     1. Add the following line to /usr/src/linux/drivers/scsi/Config.in
+        after "comment 'SCSI low-level drivers'":
+   
+          dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
+   
+     2. Add the following lines to /usr/src/linux/drivers/scsi/hosts.c
+        after "#include "hosts.h"":
+   
+          #ifdef CONFIG_SCSI_ADVANSYS
+          #include "advansys.h"
+          #endif
+   
+        and after "static Scsi_Host_Template builtin_scsi_hosts[] =":
+   
+          #ifdef CONFIG_SCSI_ADVANSYS
+          ADVANSYS,
+          #endif
+   
+     3. Add the following lines to /usr/src/linux/drivers/scsi/Makefile:
+   
+          ifeq ($(CONFIG_SCSI_ADVANSYS),y)
+          L_OBJS += advansys.o
+          else
+            ifeq ($(CONFIG_SCSI_ADVANSYS),m)
+            M_OBJS += advansys.o
+            endif
+          endif
+   
+     4. Add the following line to /usr/src/linux/include/linux/proc_fs.h
+        in the enum scsi_directory_inos array:
+   
+          PROC_SCSI_ADVANSYS,
+   
+     5. (Optional) If you would like to enable the LILO command line
+        and /etc/lilo.conf 'advansys' option, make the following changes.
+        This option can be used to disable I/O port scanning or to limit
+        I/O port scanning to specific addresses. Refer to the 'Driver
+        LILO Option' section below. Add the following lines to
+        /usr/src/linux/init/main.c in the prototype section:
+   
+          extern void advansys_setup(char *str, int *ints);
+   
+        and add the following lines to the bootsetups[] array.
+   
+          #ifdef CONFIG_SCSI_ADVANSYS
+             { "advansys=", advansys_setup },
+          #endif
+   
+     6. In the directory /usr/src/linux run 'make config' to configure
+        the AdvanSys driver, then run 'make vmlinux' or 'make zlilo' to
+        make the kernel. If the AdvanSys driver is not configured, then
+        a loadable module can be built by running 'make modules' and
+        'make modules_install'. Use 'insmod' and 'rmmod' to install
+        and remove advansys.o.
+
+  D. Source Comments
+ 
+     1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
+ 
+     2. This driver should be maintained in multiple files. But to make
+        it easier to include with Linux and to follow Linux conventions,
+        the whole driver is maintained in the source files advansys.h and
+        advansys.c. In this file logical sections of the driver begin with
+        a comment that contains '---'. The following are the logical sections
+        of the driver below.
+ 
+           --- Linux Version
+           --- Linux Include Files 
+           --- Driver Options
+           --- Asc Library Constants and Macros
+           --- Debugging Header
+           --- Driver Constants
+           --- Driver Macros
+           --- Driver Structures
+           --- Driver Data
+           --- Driver Function Prototypes
+           --- Linux 'Scsi_Host_Template' and advansys_setup() Functions
+           --- Loadable Driver Support
+           --- Miscellaneous Driver Functions
+           --- Functions Required by the Asc Library
+           --- Tracing and Debugging Functions
+           --- Asc Library Functions
+ 
+     3. The string 'XXX' is used to flag code that needs to be re-written
+        or that contains a problem that needs to be addressed.
+ 
+     4. I have stripped comments from and reformatted the source for the
+        Asc Library which is included in this file. I haven't done this
+        to obfuscate the code. Actually I have done this to deobfuscate
+        the code. The Asc Library source can be found under the following
+        headings.
+ 
+           --- Asc Library Constants and Macros
+           --- Asc Library Functions
+ 
+  E. Driver Compile Time Options and Debugging
+ 
+     In this source file the following constants can be defined. They are
+     defined in the source below. Both of these options are enabled by
+     default.
+ 
+     1. ADVANSYS_DEBUG - enable for debugging and assertions
+ 
+        The amount of debugging output can be controlled with the global
+        variable 'asc_dbglvl'. The higher the number the more output. By
+        default the debug level is 0.
+        
+        If the driver is loaded at boot time and the LILO Driver Option
+        is included in the system, the debug level can be changed by
+        specifying a 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. The
+        first three hex digits of the pseudo I/O Port must be set to
+        'deb' and the fourth hex digit specifies the debug level: 0 - F.
+        The following command line will look for an adapter at 0x330
+        and set the debug level to 2.
+
+           linux advansys=0x330,0x0,0x0,0x0,0xdeb2
+
+        If the driver is built as a loadable module this variable can be
+        defined when the driver is loaded. The following insmod command
+        will set the debug level to one.
+  
+           insmod advansys.o asc_dbglvl=1
+ 
+ 
+        Debugging Message Levels:
+           0: Errors Only
+           1: High-Level Tracing
+           2-N: Verbose Tracing
+ 
+        I don't know the approved way for turning on printk()s to the
+        console. Here's a program I use to do this. Debug output is
+        logged in /var/adm/messages.
+ 
+          main()
+          {
+                  syscall(103, 7, 0, 0);
+          }
+ 
+        I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c
+        prevents most level 1 debug messages from being lost.
+ 
+     2. ADVANSYS_STATS - enable statistics and tracing
+ 
+        For Linux 1.2.X if ADVANSYS_STATS_1_2_PRINT is defined every
+        10,000 I/O operations the driver will print statistics to the
+        console. This value can be changed by modifying the constant
+        used in advansys_queuecommand(). ADVANSYS_STATS_1_2_PRINT is
+        off by default.
+
+        For Linux 1.3.X statistics can be accessed by reading the
+        /proc/scsi/advansys/[0-9] files.
+
+        Note: these statistics are currently maintained on a global driver
+        basis and not per board.
+
+  F. Driver LILO Option
+ 
+     If init/main.c is modified as described in the 'Directions for Adding
+     the AdvanSys Driver to Linux' section (B.4.) above, the driver will
+     recognize the 'advansys' LILO command line and /etc/lilo.conf option.
+     This option can be used to either disable I/O port scanning or to limit
+     scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
+     PCI boards will still be searched for and detected. This option only
+     affects searching for ISA and VL boards.
+
+     Examples:
+       1. Eliminate I/O port scanning:
+            boot: linux advansys=
+              or
+            boot: linux advansys=0x0
+       2. Limit I/O port scanning to one I/O port:
+            boot: linux advansys=0x110
+       3. Limit I/O port scanning to four I/O ports:
+            boot: linux advansys=0x110,0x210,0x230,0x330
+
+     For a loadable module the same effect can be achieved by setting
+     the 'asc_iopflag' variable and 'asc_ioport' array when loading
+     the driver, e.g.
+
+           insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
+
+     If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_BOARD_SUPPORTED + 1)
+     I/O Port may be added to specify the driver debug level. Refer to
+     the 'Driver Compile Time Options and Debugging' section above for
+     more information.
+
+  G. Release History
+
+     12/23/95 BETA-1.0:
+         First Release
+
+     12/28/95 BETA-1.1:
+         1. Prevent advansys_detect() from being called twice.
+         2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
+
+     1/12/96 1.2:
+         1. Prevent re-entrancy in the interrupt handler which
+            resulted in the driver hanging Linux.
+         2. Fix problem that prevented ABP-940 cards from being
+            recognized on some PCI motherboards.
+         3. Add support for the ABP-5140 PnP ISA card.
+         4. Fix check condition return status.
+         5. Add conditionally compiled code for Linux 1.3.X.
+        
+  H. Known Problems or Issues
+
+     1. The setting for 'cmd_per_lun' needs to be changed. It is currently
+        less then what the AdvanSys boards can queue. Because the target and
+        mid-level Linux drivers base memory allocation on 'cmd_per_lun' (as
+        well as 'sg_tablesize') memory use gets out of hand with a large
+        'cmd_per_lun'. 'cmd_per_lun' should be per device instead of per
+        adapter. When the driver is compiled as a loadable module both
+        'cmd_per_lun' and 'sg_tablesize' are tuned down to try to prevent
+        memory allocation errors.
+
+     2. For the first scsi command sent to a device the driver increases
+        the timeout value. This gives the driver more time to perform
+        its own initialization for the board and each device. The timeout
+        value is only changed on the first scsi command for each device
+        and never thereafter.
+
+  I. Credits
+
+     Nathan Hartwell (mage@cdc3.cdc.net) provided the directions and
+     and basis for the Linux 1.3.X changes which were included in the
+     1.2 release.
+
+  J. AdvanSys Contact Information
+ 
+     Mail:                   Advanced System Products, Inc.
+                             1150 Ringwood Court
+                             San Jose, CA 95131 USA
+     Operator:               1-408-383-9400
+     FAX:                    1-408-383-9612
+     Tech Support:           1-800-525-7440
+     BBS:                    1-408-383-9540 (9600,N,8,1)
+     Interactive FAX:        1-408-383-9753
+     Customer Direct Sales:  1-800-883-1099
+     Tech Support E-Mail:    support@advansys.com
+     Linux Support E-Mail:   bobf@advansys.com
+     FTP Site:               ftp.advansys.com (login: anonymous)
+     Web Site:               http://www.advansys.com
+
+*/
+
+
+/*
+ * --- Linux Version
+ */
+
+/*
+ * The driver can be used in Linux 1.2.X or 1.3.X.
+ */
+#if !defined(LINUX_1_2) && !defined(LINUX_1_3)
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif /* LINUX_VERSION_CODE */
+#if LINUX_VERSION_CODE > 65536 + 3 * 256
+#define LINUX_1_3
+#else /* LINUX_VERSION_CODE */
+#define LINUX_1_2
+#endif /* LINUX_VERSION_CODE */
+#endif /* !defined(LINUX_1_2) && !defined(LINUX_1_3) */
+
+
+/*
+ * --- Linux Include Files 
+ */
+
+#ifdef MODULE
+#ifdef LINUX_1_3
+#include <linux/autoconf.h>
+#endif /* LINUX_1_3 */ 
+#include <linux/module.h>
+#endif /* MODULE */
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+#ifdef LINUX_1_3
+#include <linux/proc_fs.h>
+#endif /* LINUX_1_3 */ 
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+#ifdef LINUX_1_2
+#include "../block/blk.h"
+#else /* LINUX_1_3 */ 
+#include <linux/blk.h>
+#include <linux/stat.h>
+#endif /* LINUX_1_3 */ 
+#include "scsi.h"
+#include "hosts.h"
+#include "sd.h"
+#include "advansys.h"
+
+
+/*
+ * --- Driver Options
+ */
+#define ADVANSYS_DEBUG /* Enable for debugging and assertions. */
+#define ADVANSYS_STATS /* Enable for statistics and tracing. */
+#ifdef LINUX_1_2
+#undef ADVANSYS_STATS_1_2_PRINT /* Enable to print statistics to console. */
+#endif /* LINUX_1_2 */
+
+
+/*
+ * --- Asc Library Constants and Macros
+ */
+
+#define ASC_LIB_VERSION_MAJOR  1
+#define ASC_LIB_VERSION_MINOR  16
+#define ASC_LIB_SERIAL_NUMBER  53
+
+typedef unsigned char uchar;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+
+typedef int         BOOL;
+
+#ifndef NULL
+#define NULL     (0)
+#endif
+
+#ifndef TRUE
+#define TRUE     (1)
+#endif
+
+#ifndef FALSE
+#define FALSE    (0)
+#endif
+
+#define  REG     register
+
+#define rchar    REG char
+#define rshort   REG short
+#define rint     REG int
+#define rlong    REG long
+
+#define ruchar   REG uchar
+#define rushort  REG ushort
+#define ruint    REG uint
+#define rulong   REG ulong
+
+#define NULLPTR   ( void *)0
+#define FNULLPTR  ( void dosfar *)0UL
+#define EOF      (-1)
+#define EOS      '\0'
+#define ERR      (-1)
+#define UB_ERR   (uchar)(0xFF)
+#define UW_ERR   (uint)(0xFFFF)
+#define UL_ERR   (ulong)(0xFFFFFFFFUL)
+
+#define iseven_word( val )  ( ( ( ( uint )val) & ( uint )0x0001 ) == 0 )
+#define isodd_word( val )   ( ( ( ( uint )val) & ( uint )0x0001 ) != 0 )
+#define toeven_word( val )  ( ( ( uint )val ) & ( uint )0xFFFE )
+
+#define biton( val, bits )   ((( uint )( val >> bits ) & (uint)0x0001 ) != 0 )
+#define bitoff( val, bits )  ((( uint )( val >> bits ) & (uint)0x0001 ) == 0 )
+#define lbiton( val, bits )  ((( ulong )( val >> bits ) & (ulong)0x00000001UL ) != 0 )
+#define lbitoff( val, bits ) ((( ulong )( val >> bits ) & (ulong)0x00000001UL ) == 0 )
+
+#define  absh( val )    ( ( val ) < 0 ? -( val ) : ( val ) )
+
+#define  swapbyte( ch )  ( ( ( (ch) << 4 ) | ( (ch) >> 4 ) ) )
+
+#ifndef GBYTE
+#define GBYTE       (0x40000000UL)
+#endif
+
+#ifndef MBYTE
+#define MBYTE       (0x100000UL)
+#endif
+
+#ifndef KBYTE
+#define KBYTE       (0x400)
+#endif
+
+#define HI_BYTE(x) ( *( ( BYTE *)(&x)+1 ) )
+#define LO_BYTE(x) ( *( ( BYTE *)&x ) )
+
+#define HI_WORD(x) ( *( ( WORD *)(&x)+1 ) )
+#define LO_WORD(x) ( *( ( WORD *)&x ) )
+
+#ifndef MAKEWORD
+#define MAKEWORD(lo, hi)    ((WORD) (((WORD) lo) | ((WORD) hi << 8)))
+#endif
+
+#ifndef MAKELONG
+#define MAKELONG(lo, hi)    ((DWORD) (((DWORD) lo) | ((DWORD) hi << 16)))
+#endif
+
+#define SwapWords(dWord)        ((DWORD) ((dWord >> 16) | (dWord << 16)))
+#define SwapBytes(word)         ((WORD) ((word >> 8) | (word << 8)))
+
+#define BigToLittle(dWord) \
+    ((DWORD) (SwapWords(MAKELONG(SwapBytes(LO_WORD(dWord)), SwapBytes(HI_WORD(dWord))))))
+#define LittleToBig(dWord)      BigToLittle(dWord)
+
+#define Lptr
+#define dosfar
+#define far
+#define PortAddr			unsigned short
+#define Ptr2Func        	ulong
+
+#define inp(port)        	inb(port)
+#define inpw(port)       	inw(port)
+#define outp(port, byte)    outb((byte), (port))
+#define outpw(port, word)   outw((word), (port))
+
+#define ASC_MAX_SG_QUEUE	5
+#define ASC_MAX_SG_LIST		(1 + ((ASC_SG_LIST_PER_Q) * (ASC_MAX_SG_QUEUE)))
+
+#define CC_INIT_INQ_DISPLAY     FALSE
+
+#define CC_CLEAR_LRAM_SRB_PTR   FALSE
+#define CC_VERIFY_LRAM_COPY     FALSE
+
+#define CC_DEBUG_SG_LIST        FALSE
+#define CC_FAST_STRING_IO       FALSE
+
+#define CC_WRITE_IO_COUNT       FALSE
+#define CC_CLEAR_DMA_REMAIN     FALSE
+
+#define CC_DISABLE_PCI_PARITY_INT TRUE
+
+#define CC_LINK_BUSY_Q         FALSE
+
+#define CC_TARGET_MODE         FALSE
+
+#define CC_SCAM                FALSE
+
+#define CC_LITTLE_ENDIAN_HOST  TRUE
+
+#ifndef CC_TEST_LRAM_ENDIAN
+
+#if CC_LITTLE_ENDIAN_HOST
+#define CC_TEST_LRAM_ENDIAN     FALSE
+#else
+#define CC_TEST_LRAM_ENDIAN     TRUE
+#endif
+
+#endif
+
+#define CC_STRUCT_ALIGNED      TRUE
+
+#define CC_MEMORY_MAPPED_IO    FALSE
+
+#ifndef CC_TARGET_MODE
+#define CC_TARGET_MODE         FALSE
+#endif
+
+#ifndef CC_STRUCT_ALIGNED
+#define CC_STRUCT_ALIGNED      FALSE
+#endif
+
+#ifndef CC_LITTLE_ENDIAN_HOST
+#define CC_LITTLE_ENDIAN_HOST  TRUE
+#endif
+
+#if !CC_LITTLE_ENDIAN_HOST
+
+#ifndef CC_TEST_LRAM_ENDIAN
+#define CC_TEST_LRAM_ENDIAN    TRUE
+#endif
+
+#endif
+
+#ifndef CC_MEMORY_MAPPED_IO
+#define CC_MEMORY_MAPPED_IO    FALSE
+#endif
+
+#ifndef CC_WRITE_IO_COUNT
+#define CC_WRITE_IO_COUNT      FALSE
+#endif
+
+#ifndef CC_CLEAR_DMA_REMAIN
+#define CC_CLEAR_DMA_REMAIN    FALSE
+#endif
+
+#define ASC_CS_TYPE  unsigned short
+
+#ifndef asc_ptr_type
+#define asc_ptr_type
+#endif
+
+#ifndef CC_SCAM
+#define CC_SCAM  FALSE
+#endif
+
+#ifndef ASC_GET_PTR2FUNC
+#define ASC_GET_PTR2FUNC( fun )  ( Ptr2Func )( fun )
+#endif
+
+#define FLIP_BYTE_NIBBLE( x )    ( ((x<<4)& 0xFF) | (x>>4) )
+
+#define ASC_IS_ISA          (0x0001)
+#define ASC_IS_ISAPNP       (0x0081)
+#define ASC_IS_EISA         (0x0002)
+#define ASC_IS_PCI          (0x0004)
+#define ASC_IS_PCMCIA       (0x0008)
+#define ASC_IS_PNP          (0x0010)
+#define ASC_IS_MCA          (0x0020)
+#define ASC_IS_VL           (0x0040)
+
+#define ASC_ISA_PNP_PORT_ADDR  (0x279)
+#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
+
+#define ASC_IS_WIDESCSI_16  (0x0100)
+#define ASC_IS_WIDESCSI_32  (0x0200)
+
+#define ASC_IS_BIG_ENDIAN   (0x8000)
+
+#define ASC_CHIP_MIN_VER_VL      (0x01)
+#define ASC_CHIP_MAX_VER_VL      (0x07)
+
+#define ASC_CHIP_MIN_VER_PCI     (0x09)
+#define ASC_CHIP_MAX_VER_PCI     (0x0F)
+#define ASC_CHIP_VER_PCI_BIT     (0x08)
+
+#define ASC_CHIP_MIN_VER_ISA     (0x11)
+#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
+#define ASC_CHIP_MAX_VER_ISA     (0x27)
+#define ASC_CHIP_VER_ISA_BIT     (0x30)
+#define ASC_CHIP_VER_ISAPNP_BIT  (0x20)
+
+#define ASC_CHIP_VER_ASYN_BUG    (0x21)
+
+#define ASC_CHIP_MIN_VER_EISA (0x41)
+#define ASC_CHIP_MAX_VER_EISA (0x47)
+#define ASC_CHIP_VER_EISA_BIT (0x40)
+
+#define ASC_MAX_VL_DMA_ADDR     (0x07FFFFFFL)
+#define ASC_MAX_VL_DMA_COUNT    (0x07FFFFFFL)
+
+#define ASC_MAX_PCI_DMA_ADDR    (0xFFFFFFFFL)
+#define ASC_MAX_PCI_DMA_COUNT   (0xFFFFFFFFL)
+
+#define ASC_MAX_ISA_DMA_ADDR    (0x00FFFFFFL)
+#define ASC_MAX_ISA_DMA_COUNT   (0x00FFFFFFL)
+
+#define ASC_MAX_EISA_DMA_ADDR   (0x07FFFFFFL)
+#define ASC_MAX_EISA_DMA_COUNT  (0x07FFFFFFL)
+
+#if !CC_STRUCT_ALIGNED
+
+#define DvcGetQinfo( iop_base, s_addr, outbuf, words)  \
+        AscMemWordCopyFromLram( iop_base, s_addr, outbuf, words)
+
+#define DvcPutScsiQ( iop_base, s_addr, outbuf, words) \
+        AscMemWordCopyToLram( iop_base, s_addr, outbuf, words)
+
+#endif
+
+#define ASC_SCSI_ID_BITS  3
+#define ASC_SCSI_TIX_TYPE     uchar
+#define ASC_ALL_DEVICE_BIT_SET  0xFF
+
+#ifdef ASC_WIDESCSI_16
+
+#undef  ASC_SCSI_ID_BITS
+#define ASC_SCSI_ID_BITS  4
+#define ASC_ALL_DEVICE_BIT_SET  0xFFFF
+
+#endif
+
+#ifdef ASC_WIDESCSI_32
+
+#undef  ASC_SCSI_ID_BITS
+#define ASC_SCSI_ID_BITS  5
+#define ASC_ALL_DEVICE_BIT_SET  0xFFFFFFFFL
+
+#endif
+
+#if ASC_SCSI_ID_BITS == 3
+
+#define ASC_SCSI_BIT_ID_TYPE  uchar
+#define ASC_MAX_TID       7
+#define ASC_MAX_LUN       7
+#define ASC_SCSI_WIDTH_BIT_SET  0xFF
+
+#elif ASC_SCSI_ID_BITS == 4
+
+#define ASC_SCSI_BIT_ID_TYPE   ushort
+#define ASC_MAX_TID         15
+#define ASC_MAX_LUN         7
+#define ASC_SCSI_WIDTH_BIT_SET  0xFFFF
+
+#elif ASC_SCSI_ID_BITS == 5
+
+#define ASC_SCSI_BIT_ID_TYPE    ulong
+#define ASC_MAX_TID         31
+#define ASC_MAX_LUN         7
+#define ASC_SCSI_WIDTH_BIT_SET  0xFFFFFFFF
+
+#else
+
+#error  ASC_SCSI_ID_BITS definition is wrong
+
+#endif
+
+#define ASC_MAX_SENSE_LEN   32
+#define ASC_MIN_SENSE_LEN   14
+
+#define ASC_MAX_CDB_LEN     12
+
+#define SCSICMD_TestUnitReady     0x00
+#define SCSICMD_Rewind            0x01
+#define SCSICMD_Rezero            0x01
+#define SCSICMD_RequestSense      0x03
+#define SCSICMD_Format            0x04
+#define SCSICMD_FormatUnit        0x04
+#define SCSICMD_Read6             0x08
+#define SCSICMD_Write6            0x0A
+#define SCSICMD_Seek6             0x0B
+#define SCSICMD_Inquiry           0x12
+#define SCSICMD_Verify6           0x13
+#define SCSICMD_ModeSelect6       0x15
+#define SCSICMD_ModeSense6        0x1A
+
+#define SCSICMD_StartStopUnit     0x1B
+#define SCSICMD_LoadUnloadTape    0x1B
+#define SCSICMD_ReadCapacity      0x25
+#define SCSICMD_Read10            0x28
+#define SCSICMD_Write10           0x2A
+#define SCSICMD_Seek10            0x2B
+#define SCSICMD_Erase10           0x2C
+#define SCSICMD_WriteAndVerify10  0x2E
+#define SCSICMD_Verify10          0x2F
+
+#define SCSICMD_ModeSelect10      0x55
+#define SCSICMD_ModeSense10       0x5A
+
+#define SCSI_TYPE_DASD     0x00
+#define SCSI_TYPE_SASD     0x01
+#define SCSI_TYPE_PRN      0x02
+#define SCSI_TYPE_PROC     0x03
+
+#define SCSI_TYPE_WORM     0x04
+#define SCSI_TYPE_CDROM    0x05
+#define SCSI_TYPE_SCANNER  0x06
+#define SCSI_TYPE_OPTMEM   0x07
+#define SCSI_TYPE_MED_CHG  0x08
+#define SCSI_TYPE_COMM     0x09
+#define SCSI_TYPE_UNKNOWN  0x1F
+#define SCSI_TYPE_NO_DVC   0xFF
+
+#define ASC_SCSIDIR_NOCHK    0x00
+
+#define ASC_SCSIDIR_T2H      0x08
+
+#define ASC_SCSIDIR_H2T      0x10
+
+#define ASC_SCSIDIR_NODATA   0x18
+
+#define SCSI_SENKEY_NO_SENSE      0x00
+#define SCSI_SENKEY_UNDEFINED     0x01
+#define SCSI_SENKEY_NOT_READY     0x02
+#define SCSI_SENKEY_MEDIUM_ERR    0x03
+#define SCSI_SENKEY_HW_ERR        0x04
+#define SCSI_SENKEY_ILLEGAL       0x05
+#define SCSI_SENKEY_ATTENSION     0x06
+#define SCSI_SENKEY_PROTECTED     0x07
+#define SCSI_SENKEY_BLANK         0x08
+#define SCSI_SENKEY_V_UNIQUE      0x09
+#define SCSI_SENKEY_CPY_ABORT     0x0A
+#define SCSI_SENKEY_ABORT         0x0B
+#define SCSI_SENKEY_EQUAL         0x0C
+#define SCSI_SENKEY_VOL_OVERFLOW  0x0D
+#define SCSI_SENKEY_MISCOMP       0x0E
+#define SCSI_SENKEY_RESERVED      0x0F
+
+#define ASC_SRB_HOST( x )  ( ( uchar )( ( uchar )( x ) >> 4 ) )
+#define ASC_SRB_TID( x )   ( ( uchar )( ( uchar )( x ) & ( uchar )0x0F ) )
+
+#define ASC_SRB_LUN( x )   ( ( uchar )( ( uint )( x ) >> 13 ) )
+
+#define PUT_CDB1( x )   ( ( uchar )( ( uint )( x ) >> 8 ) )
+
+#define SS_GOOD              0x00
+#define SS_CHK_CONDITION     0x02
+#define SS_CONDITION_MET     0x04
+#define SS_TARGET_BUSY       0x08
+#define SS_INTERMID          0x10
+#define SS_INTERMID_COND_MET 0x14
+
+#define SS_RSERV_CONFLICT    0x18
+#define SS_CMD_TERMINATED    0x22
+
+#define SS_QUEUE_FULL        0x28
+
+#define MS_CMD_DONE    0x00
+#define MS_EXTEND      0x01
+#define MS_SDTR_LEN    0x03
+#define MS_SDTR_CODE   0x01
+
+#define M1_SAVE_DATA_PTR        0x02
+#define M1_RESTORE_PTRS         0x03
+#define M1_DISCONNECT           0x04
+#define M1_INIT_DETECTED_ERR    0x05
+#define M1_ABORT                0x06
+#define M1_MSG_REJECT           0x07
+#define M1_NO_OP                0x08
+#define M1_MSG_PARITY_ERR       0x09
+#define M1_LINK_CMD_DONE        0x0A
+#define M1_LINK_CMD_DONE_WFLAG  0x0B
+#define M1_BUS_DVC_RESET        0x0C
+#define M1_ABORT_TAG            0x0D
+#define M1_CLR_QUEUE            0x0E
+#define M1_INIT_RECOVERY        0x0F
+#define M1_RELEASE_RECOVERY     0x10
+#define M1_KILL_IO_PROC         0x11
+
+#define M2_QTAG_MSG_SIMPLE      0x20
+#define M2_QTAG_MSG_HEAD        0x21
+#define M2_QTAG_MSG_ORDERED     0x22
+#define M2_IGNORE_WIDE_RESIDUE  0x23
+
+typedef struct {
+	uchar               peri_dvc_type:5;
+	uchar               peri_qualifier:3;
+} ASC_SCSI_INQ0;
+
+typedef struct {
+	uchar               dvc_type_modifier:7;
+	uchar               rmb:1;
+} ASC_SCSI_INQ1;
+
+typedef struct {
+	uchar               ansi_apr_ver:3;
+	uchar               ecma_ver:3;
+	uchar               iso_ver:2;
+} ASC_SCSI_INQ2;
+
+typedef struct {
+	uchar               rsp_data_fmt:4;
+
+	uchar               res:2;
+	uchar               TemIOP:1;
+	uchar               aenc:1;
+} ASC_SCSI_INQ3;
+
+typedef struct {
+	uchar               StfRe:1;
+	uchar               CmdQue:1;
+	uchar               Reserved:1;
+	uchar               Linked:1;
+	uchar               Sync:1;
+	uchar               WBus16:1;
+	uchar               WBus32:1;
+	uchar               RelAdr:1;
+} ASC_SCSI_INQ7;
+
+typedef struct {
+	ASC_SCSI_INQ0       byte0;
+	ASC_SCSI_INQ1       byte1;
+	ASC_SCSI_INQ2       byte2;
+	ASC_SCSI_INQ3       byte3;
+	uchar               add_len;
+	uchar               res1;
+	uchar               res2;
+	ASC_SCSI_INQ7       byte7;
+	uchar               vendor_id[8];
+	uchar               product_id[16];
+	uchar               product_rev_level[4];
+} ASC_SCSI_INQUIRY;
+
+typedef struct asc_req_sense {
+	uchar               err_code:7;
+	uchar               info_valid:1;
+	uchar               segment_no;
+	uchar               sense_key:4;
+	uchar               reserved_bit:1;
+	uchar               sense_ILI:1;
+	uchar               sense_EOM:1;
+	uchar               file_mark:1;
+	uchar               info1[4];
+	uchar               add_sense_len;
+	uchar               cmd_sp_info[4];
+	uchar               asc;
+	uchar               ascq;
+
+	uchar               fruc;
+	uchar               sks_byte0:7;
+	uchar               sks_valid:1;
+	uchar               sks_bytes[2];
+	uchar               notused[2];
+	uchar               ex_sense_code;
+	uchar               info2[4];
+} ASC_REQ_SENSE;
+
+#define ASC_SG_LIST_PER_Q   7
+
+#define QS_FREE        0x00
+#define QS_READY       0x01
+#define QS_DISC1       0x02
+#define QS_DISC2       0x04
+#define QS_BUSY        0x08
+
+#define QS_ABORTED     0x40
+#define QS_DONE        0x80
+
+#define QC_NO_CALLBACK   0x01
+
+#define QC_SG_SWAP_QUEUE 0x02
+#define QC_SG_HEAD       0x04
+#define QC_DATA_IN       0x08
+#define QC_DATA_OUT      0x10
+
+#define QC_URGENT        0x20
+#define QC_MSG_OUT       0x40
+#define QC_REQ_SENSE     0x80
+
+#define QCSG_SG_XFER_LIST  0x02
+#define QCSG_SG_XFER_MORE  0x04
+#define QCSG_SG_XFER_END   0x08
+
+#define QD_IN_PROGRESS       0x00
+#define QD_NO_ERROR          0x01
+#define QD_ABORTED_BY_HOST   0x02
+#define QD_WITH_ERROR        0x04
+#define QD_INVALID_REQUEST   0x80
+#define QD_INVALID_HOST_NUM  0x81
+#define QD_INVALID_DEVICE    0x82
+#define QD_ERR_INTERNAL      0xFF
+
+#define QHSTA_NO_ERROR               0x00
+#define QHSTA_M_SEL_TIMEOUT          0x11
+#define QHSTA_M_DATA_OVER_RUN        0x12
+#define QHSTA_M_DATA_UNDER_RUN       0x12
+#define QHSTA_M_UNEXPECTED_BUS_FREE  0x13
+#define QHSTA_M_BAD_BUS_PHASE_SEQ    0x14
+
+#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
+#define QHSTA_D_ASC_DVC_ERROR_CODE_SET  0x22
+#define QHSTA_D_HOST_ABORT_FAILED       0x23
+#define QHSTA_D_EXE_SCSI_Q_FAILED       0x24
+#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
+
+#define QHSTA_D_ASPI_NO_BUF_POOL        0x26
+
+#define QHSTA_M_WTM_TIMEOUT         0x41
+#define QHSTA_M_BAD_CMPL_STATUS_IN  0x42
+#define QHSTA_M_NO_AUTO_REQ_SENSE   0x43
+#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
+#define QHSTA_M_TARGET_STATUS_BUSY  0x45
+#define QHSTA_M_BAD_TAG_CODE        0x46
+
+#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY  0x47
+
+#define QHSTA_D_LRAM_CMP_ERROR        0x81
+#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
+
+#define ASC_FLAG_SCSIQ_REQ        0x01
+#define ASC_FLAG_BIOS_SCSIQ_REQ   0x02
+#define ASC_FLAG_BIOS_ASYNC_IO    0x04
+#define ASC_FLAG_SRB_LINEAR_ADDR  0x08
+
+#define ASC_FLAG_WIN16            0x10
+#define ASC_FLAG_WIN32            0x20
+
+#define ASC_FLAG_DOS_VM_CALLBACK  0x80
+
+#define ASC_TAG_FLAG_ADD_ONE_BYTE     0x10
+#define ASC_TAG_FLAG_ISAPNP_ADD_BYTES 0x40
+
+#define ASC_SCSIQ_CPY_BEG              4
+#define ASC_SCSIQ_SGHD_CPY_BEG         2
+
+#define ASC_SCSIQ_B_FWD                0
+#define ASC_SCSIQ_B_BWD                1
+
+#define ASC_SCSIQ_B_STATUS             2
+#define ASC_SCSIQ_B_QNO                3
+
+#define ASC_SCSIQ_B_CNTL               4
+#define ASC_SCSIQ_B_SG_QUEUE_CNT       5
+
+#define ASC_SCSIQ_D_DATA_ADDR          8
+#define ASC_SCSIQ_D_DATA_CNT          12
+#define ASC_SCSIQ_B_SENSE_LEN         20
+#define ASC_SCSIQ_DONE_INFO_BEG       22
+#define ASC_SCSIQ_D_SRBPTR            22
+#define ASC_SCSIQ_B_TARGET_IX         26
+#define ASC_SCSIQ_B_CDB_LEN           28
+#define ASC_SCSIQ_B_TAG_CODE          29
+#define ASC_SCSIQ_W_VM_ID             30
+#define ASC_SCSIQ_DONE_STATUS         32
+#define ASC_SCSIQ_HOST_STATUS         33
+#define ASC_SCSIQ_SCSI_STATUS         34
+#define ASC_SCSIQ_CDB_BEG             36
+#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
+#define ASC_SCSIQ_DW_REMAIN_XFER_CNT  60
+#define ASC_SCSIQ_B_SG_WK_QP          49
+#define ASC_SCSIQ_B_SG_WK_IX          50
+#define ASC_SCSIQ_W_REQ_COUNT         52
+#define ASC_SCSIQ_B_LIST_CNT          6
+#define ASC_SCSIQ_B_CUR_LIST_CNT      7
+
+#define ASC_SGQ_B_SG_CNTL             4
+#define ASC_SGQ_B_SG_HEAD_QP          5
+#define ASC_SGQ_B_SG_LIST_CNT         6
+#define ASC_SGQ_B_SG_CUR_LIST_CNT     7
+#define ASC_SGQ_LIST_BEG              8
+
+#define ASC_DEF_SCSI1_QNG    2
+#define ASC_MAX_SCSI1_QNG    2
+#define ASC_DEF_SCSI2_QNG    16
+#define ASC_MAX_SCSI2_QNG    32
+
+#define ASC_TAG_CODE_MASK    0x23
+
+#define ASC_STOP_REQ_RISC_STOP      0x01
+
+#define ASC_STOP_ACK_RISC_STOP      0x03
+
+#define ASC_STOP_CLEAN_UP_BUSY_Q    0x10
+#define ASC_STOP_CLEAN_UP_DISC_Q    0x20
+#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
+#define ASC_STOP_SEND_INT_TO_HOST   0x80
+
+#define ASC_TIDLUN_TO_IX( tid, lun )  ( ASC_SCSI_TIX_TYPE )( (tid) + ((lun)<<ASC_SCSI_ID_BITS) )
+
+#define ASC_TID_TO_TARGET_ID( tid )   ( ASC_SCSI_BIT_ID_TYPE )( 0x01 << (tid) )
+#define ASC_TIX_TO_TARGET_ID( tix )   ( 0x01 << ( (tix) & ASC_MAX_TID ) )
+#define ASC_TIX_TO_TID( tix )  ( (tix) & ASC_MAX_TID )
+#define ASC_TID_TO_TIX( tid )  ( (tid) & ASC_MAX_TID )
+#define ASC_TIX_TO_LUN( tix )  ( ( (tix) >> ASC_SCSI_ID_BITS ) & ASC_MAX_LUN )
+
+#define ASC_QNO_TO_QADDR( q_no )      ( (ASC_QADR_BEG)+( ( int )(q_no) << 6 ) )
+
+typedef struct asc_scisq_1 {
+	uchar               status;
+	uchar               q_no;
+	uchar               cntl;
+	uchar               sg_queue_cnt;
+
+	uchar               target_id;
+	uchar               target_lun;
+
+	ulong               data_addr;
+	ulong               data_cnt;
+	ulong               sense_addr;
+	uchar               sense_len;
+	uchar               user_def;
+} ASC_SCSIQ_1;
+
+typedef struct asc_scisq_2 {
+	ulong               srb_ptr;
+	uchar               target_ix;
+
+	uchar               flag;
+	uchar               cdb_len;
+	uchar               tag_code;
+
+	ushort              vm_id;
+} ASC_SCSIQ_2;
+
+typedef struct asc_scsiq_3 {
+	uchar               done_stat;
+	uchar               host_stat;
+	uchar               scsi_stat;
+	uchar               scsi_msg;
+} ASC_SCSIQ_3;
+
+typedef struct asc_scsiq_4 {
+	uchar               cdb[ASC_MAX_CDB_LEN];
+	uchar               y_first_sg_list_qp;
+	uchar               y_working_sg_qp;
+	uchar               y_working_sg_ix;
+	uchar               y_cntl;
+	ushort              x_req_count;
+	ushort              x_reconnect_rtn;
+	ulong               x_saved_data_addr;
+	ulong               x_saved_data_cnt;
+} ASC_SCSIQ_4;
+
+typedef struct asc_q_done_info {
+	ASC_SCSIQ_2         d2;
+	ASC_SCSIQ_3         d3;
+	uchar               q_status;
+	uchar               q_no;
+	uchar               cntl;
+	uchar               sense_len;
+	uchar               user_def;
+	uchar               res;
+	ulong               remain_bytes;
+} ASC_QDONE_INFO;
+
+typedef struct asc_sg_list {
+	ulong               addr;
+	ulong               bytes;
+} ASC_SG_LIST;
+
+typedef struct asc_sg_head {
+	uchar               entry_cnt;
+
+	uchar               queue_cnt;
+
+	uchar               entry_to_copy;
+	uchar               res;
+	ASC_SG_LIST         sg_list[ASC_MAX_SG_LIST];
+} ASC_SG_HEAD;
+
+#define ASC_MIN_SG_LIST   2
+
+typedef struct asc_min_sg_head {
+	uchar               entry_cnt;
+
+	uchar               queue_cnt;
+
+	uchar               entry_to_copy;
+	uchar               res;
+	ASC_SG_LIST         sg_list[ASC_MIN_SG_LIST];
+} ASC_MIN_SG_HEAD;
+
+#define QCX_SORT        (0x0001)
+#define QCX_COALEASE    (0x0002)
+
+#if CC_LINK_BUSY_Q
+typedef struct asc_ext_scsi_q {
+	ulong               lba;
+	ushort              lba_len;
+	struct asc_scsi_q dosfar *next;
+	struct asc_scsi_q dosfar *join;
+	ushort              cntl;
+	ushort              buffer_id;
+	uchar               q_required;
+	uchar               res;
+} ASC_EXT_SCSI_Q;
+
+#endif
+
+typedef struct asc_scsi_q {
+	ASC_SCSIQ_1         q1;
+	ASC_SCSIQ_2         q2;
+	uchar dosfar       *cdbptr;
+
+	ASC_SG_HEAD dosfar *sg_head;
+
+#if CC_LINK_BUSY_Q
+	ASC_EXT_SCSI_Q      ext;
+#endif
+
+} ASC_SCSI_Q;
+
+typedef struct asc_scsi_req_q {
+	ASC_SCSIQ_1         r1;
+	ASC_SCSIQ_2         r2;
+	uchar dosfar       *cdbptr;
+	ASC_SG_HEAD dosfar *sg_head;
+
+#if CC_LINK_BUSY_Q
+	ASC_EXT_SCSI_Q      ext;
+#endif
+
+	uchar dosfar       *sense_ptr;
+
+	ASC_SCSIQ_3         r3;
+	uchar               cdb[ASC_MAX_CDB_LEN];
+	uchar               sense[ASC_MIN_SENSE_LEN];
+} ASC_SCSI_REQ_Q;
+
+typedef struct asc_risc_q {
+	uchar               fwd;
+	uchar               bwd;
+	ASC_SCSIQ_1         i1;
+	ASC_SCSIQ_2         i2;
+	ASC_SCSIQ_3         i3;
+	ASC_SCSIQ_4         i4;
+} ASC_RISC_Q;
+
+typedef struct asc_sg_list_q {
+
+	uchar               seq_no;
+	uchar               q_no;
+	uchar               cntl;
+	uchar               sg_head_qp;
+	uchar               sg_list_cnt;
+	uchar               sg_cur_list_cnt;
+
+} ASC_SG_LIST_Q;
+
+typedef struct asc_risc_sg_list_q {
+	uchar               fwd;
+	uchar               bwd;
+	ASC_SG_LIST_Q       sg;
+	ASC_SG_LIST         sg_list[7];
+} ASC_RISC_SG_LIST_Q;
+
+#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP  0x1000000UL
+#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP  1024
+
+#define ASCQ_ERR_NO_ERROR             0
+#define ASCQ_ERR_IO_NOT_FOUND         1
+#define ASCQ_ERR_LOCAL_MEM            2
+#define ASCQ_ERR_CHKSUM               3
+#define ASCQ_ERR_START_CHIP           4
+#define ASCQ_ERR_INT_TARGET_ID        5
+#define ASCQ_ERR_INT_LOCAL_MEM        6
+#define ASCQ_ERR_HALT_RISC            7
+#define ASCQ_ERR_GET_ASPI_ENTRY       8
+#define ASCQ_ERR_CLOSE_ASPI           9
+#define ASCQ_ERR_HOST_INQUIRY         0x0A
+#define ASCQ_ERR_SAVED_SRB_BAD        0x0B
+#define ASCQ_ERR_QCNTL_SG_LIST        0x0C
+#define ASCQ_ERR_Q_STATUS             0x0D
+#define ASCQ_ERR_WR_SCSIQ             0x0E
+#define ASCQ_ERR_PC_ADDR              0x0F
+#define ASCQ_ERR_SYN_OFFSET           0x10
+#define ASCQ_ERR_SYN_XFER_TIME        0x11
+#define ASCQ_ERR_LOCK_DMA             0x12
+#define ASCQ_ERR_UNLOCK_DMA           0x13
+#define ASCQ_ERR_VDS_CHK_INSTALL      0x14
+#define ASCQ_ERR_MICRO_CODE_HALT      0x15
+#define ASCQ_ERR_SET_LRAM_ADDR        0x16
+#define ASCQ_ERR_CUR_QNG              0x17
+#define ASCQ_ERR_SG_Q_LINKS           0x18
+#define ASCQ_ERR_SCSIQ_PTR            0x19
+#define ASCQ_ERR_ISR_RE_ENTRY         0x1A
+#define ASCQ_ERR_CRITICAL_RE_ENTRY    0x1B
+#define ASCQ_ERR_ISR_ON_CRITICAL      0x1C
+#define ASCQ_ERR_SG_LIST_ODD_ADDRESS  0x1D
+#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
+#define ASCQ_ERR_SCSIQ_NULL_PTR       0x1F
+#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR   0x20
+#define ASCQ_ERR_GET_NUM_OF_FREE_Q    0x21
+#define ASCQ_ERR_SEND_SCSI_Q          0x22
+#define ASCQ_ERR_HOST_REQ_RISC_HALT   0x23
+#define ASCQ_ERR_RESET_SDTR           0x24
+
+#define ASC_WARN_NO_ERROR             0x0000
+#define ASC_WARN_IO_PORT_ROTATE       0x0001
+#define ASC_WARN_EEPROM_CHKSUM        0x0002
+#define ASC_WARN_IRQ_MODIFIED         0x0004
+#define ASC_WARN_AUTO_CONFIG          0x0008
+#define ASC_WARN_CMD_QNG_CONFLICT     0x0010
+
+#define ASC_WARN_EEPROM_RECOVER       0x0020
+#define ASC_WARN_CFG_MSW_RECOVER      0x0040
+
+#define ASC_IERR_WRITE_EEPROM         0x0001
+#define ASC_IERR_MCODE_CHKSUM         0x0002
+#define ASC_IERR_SET_PC_ADDR          0x0004
+#define ASC_IERR_START_STOP_CHIP      0x0008
+
+#define ASC_IERR_IRQ_NO               0x0010
+
+#define ASC_IERR_SET_IRQ_NO           0x0020
+#define ASC_IERR_CHIP_VERSION         0x0040
+#define ASC_IERR_SET_SCSI_ID          0x0080
+#define ASC_IERR_GET_PHY_ADDR         0x0100
+#define ASC_IERR_BAD_SIGNATURE        0x0200
+#define ASC_IERR_NO_BUS_TYPE          0x0400
+#define ASC_IERR_SCAM                 0x0800
+#define ASC_IERR_SET_SDTR             0x1000
+#define ASC_IERR_RW_LRAM              0x8000
+
+#define ASC_DEF_IRQ_NO  10
+#define ASC_MAX_IRQ_NO  15
+#define ASC_MIN_IRQ_NO  10
+
+#define ASC_MIN_REMAIN_Q        (0x02)
+#define ASC_DEF_MAX_TOTAL_QNG   (0x40)
+
+#define ASC_MIN_TAG_Q_PER_DVC   (0x04)
+#define ASC_DEF_TAG_Q_PER_DVC   (0x04)
+
+#define ASC_MIN_FREE_Q        ASC_MIN_REMAIN_Q
+
+#define ASC_MIN_TOTAL_QNG     (( ASC_MAX_SG_QUEUE )+( ASC_MIN_FREE_Q ))
+
+#define ASC_MAX_TOTAL_QNG 240
+#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
+
+#define ASC_MAX_INRAM_TAG_QNG   16
+
+typedef struct asc_dvc_cfg {
+	ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
+
+	ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
+	ASC_SCSI_BIT_ID_TYPE disc_enable;
+	uchar               res;
+	uchar               chip_scsi_id:4;
+
+	uchar               isa_dma_speed:4;
+
+	uchar               isa_dma_channel;
+	uchar               chip_version;
+	ushort              pci_device_id;
+	ushort              lib_serial_no;
+	ushort              lib_version;
+	ushort              mcode_date;
+	ushort              mcode_version;
+	uchar               sdtr_data[ASC_MAX_TID + 1];
+	uchar               max_tag_qng[ASC_MAX_TID + 1];
+	uchar dosfar       *overrun_buf;
+
+} ASC_DVC_CFG;
+
+#define ASC_DEF_DVC_CNTL       0xFFFF
+#define ASC_DEF_CHIP_SCSI_ID   7
+#define ASC_DEF_ISA_DMA_SPEED  4
+
+#define ASC_INIT_STATE_NULL          0x0000
+#define ASC_INIT_STATE_BEG_GET_CFG   0x0001
+#define ASC_INIT_STATE_END_GET_CFG   0x0002
+#define ASC_INIT_STATE_BEG_SET_CFG   0x0004
+#define ASC_INIT_STATE_END_SET_CFG   0x0008
+#define ASC_INIT_STATE_BEG_LOAD_MC   0x0010
+#define ASC_INIT_STATE_END_LOAD_MC   0x0020
+#define ASC_INIT_STATE_BEG_INQUIRY   0x0040
+#define ASC_INIT_STATE_END_INQUIRY   0x0080
+#define ASC_INIT_RESET_SCSI_DONE     0x0100
+
+#define ASC_PCI_DEVICE_ID_REV_A      0x1100
+#define ASC_PCI_DEVICE_ID_REV_B      0x1200
+
+#define ASC_BUG_FIX_ADD_ONE_BYTE     0x0001
+
+#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
+
+#define ASC_MIN_TAGGED_CMD  7
+
+typedef struct asc_dvc_var {
+	PortAddr            iop_base;
+	ushort              err_code;
+	ushort              dvc_cntl;
+	ushort              bug_fix_cntl;
+	ushort              bus_type;
+	Ptr2Func            isr_callback;
+	Ptr2Func            exe_callback;
+
+	ASC_SCSI_BIT_ID_TYPE init_sdtr;
+
+	ASC_SCSI_BIT_ID_TYPE sdtr_done;
+
+	ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
+
+	ASC_SCSI_BIT_ID_TYPE unit_not_ready;
+
+	ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
+
+	ASC_SCSI_BIT_ID_TYPE start_motor;
+	uchar               scsi_reset_wait;
+	uchar               chip_no;
+
+	char                is_in_int;
+	uchar               max_total_qng;
+
+	uchar               cur_total_qng;
+
+	uchar               in_critical_cnt;
+
+	uchar               irq_no;
+	uchar               last_q_shortage;
+
+	ushort              init_state;
+	uchar               cur_dvc_qng[ASC_MAX_TID + 1];
+	uchar               max_dvc_qng[ASC_MAX_TID + 1];
+
+	ASC_SCSI_Q dosfar  *scsiq_busy_head[ASC_MAX_TID + 1];
+	ASC_SCSI_Q dosfar  *scsiq_busy_tail[ASC_MAX_TID + 1];
+
+	ulong               int_count;
+	ulong               req_count;
+	ulong               busy_count;
+
+	ASC_DVC_CFG dosfar *cfg;
+	Ptr2Func            saved_ptr2func;
+	ulong               reserved2;
+	ulong               reserved3;
+	ulong               max_dma_count;
+	ASC_SCSI_BIT_ID_TYPE no_scam;
+	ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
+} ASC_DVC_VAR;
+
+typedef int         (dosfar * ASC_ISR_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_QDONE_INFO dosfar *);
+typedef int         (dosfar * ASC_EXE_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *);
+
+typedef struct asc_dvc_inq_info {
+	uchar               type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+} ASC_DVC_INQ_INFO;
+
+typedef struct asc_cap_info {
+	ulong               lba;
+	ulong               blk_size;
+} ASC_CAP_INFO;
+
+typedef struct asc_cap_info_array {
+	ASC_CAP_INFO        cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+} ASC_CAP_INFO_ARRAY;
+
+#define ASC_IOADR_TABLE_MAX_IX  11
+#define ASC_IOADR_GAP   0x10
+#define ASC_SEARCH_IOP_GAP 0x10
+#define ASC_MIN_IOP_ADDR   ( PortAddr )0x0100
+#define ASC_MAX_IOP_ADDR   ( PortAddr )0x3F0
+
+#define ASC_IOADR_1     ( PortAddr )0x0110
+#define ASC_IOADR_2     ( PortAddr )0x0130
+#define ASC_IOADR_3     ( PortAddr )0x0150
+#define ASC_IOADR_4     ( PortAddr )0x0190
+#define ASC_IOADR_5     ( PortAddr )0x0210
+#define ASC_IOADR_6     ( PortAddr )0x0230
+#define ASC_IOADR_7     ( PortAddr )0x0250
+#define ASC_IOADR_8     ( PortAddr )0x0330
+#define ASC_IOADR_DEF   ASC_IOADR_8
+
+#define ASC_SYN_XFER_NO   8
+#define ASC_MAX_SDTR_PERIOD_INDEX  7
+#define ASC_SYN_MAX_OFFSET   0x0F
+#define ASC_DEF_SDTR_OFFSET  0x0F
+#define ASC_DEF_SDTR_INDEX   0x00
+
+#define SYN_XFER_NS_0  25
+#define SYN_XFER_NS_1  30
+#define SYN_XFER_NS_2  35
+#define SYN_XFER_NS_3  40
+#define SYN_XFER_NS_4  50
+#define SYN_XFER_NS_5  60
+#define SYN_XFER_NS_6  70
+#define SYN_XFER_NS_7  85
+
+#define ASC_SDTR_PERIOD_IX_MIN  7
+
+#define SYN_XMSG_WLEN  3
+
+typedef struct sdtr_xmsg {
+	uchar               msg_type;
+	uchar               msg_len;
+	uchar               msg_req;
+	uchar               xfer_period;
+	uchar               req_ack_offset;
+	uchar               res;
+} SDTR_XMSG;
+
+#define ASC_MCNTL_NO_SEL_TIMEOUT  ( ushort )0x0001
+#define ASC_MCNTL_NULL_TARGET     ( ushort )0x0002
+
+#define ASC_CNTL_INITIATOR         ( ushort )0x0001
+#define ASC_CNTL_BIOS_GT_1GB       ( ushort )0x0002
+#define ASC_CNTL_BIOS_GT_2_DISK    ( ushort )0x0004
+#define ASC_CNTL_BIOS_REMOVABLE    ( ushort )0x0008
+#define ASC_CNTL_NO_SCAM           ( ushort )0x0010
+#define ASC_CNTL_NO_PCI_FIX_ASYN_XFER ( ushort )0x0020
+
+#define ASC_CNTL_INT_MULTI_Q       ( ushort )0x0080
+
+#define ASC_CNTL_NO_LUN_SUPPORT    ( ushort )0x0040
+
+#define ASC_CNTL_NO_VERIFY_COPY    ( ushort )0x0100
+#define ASC_CNTL_RESET_SCSI        ( ushort )0x0200
+#define ASC_CNTL_INIT_INQUIRY      ( ushort )0x0400
+#define ASC_CNTL_INIT_VERBOSE      ( ushort )0x0800
+
+#define ASC_CNTL_SCSI_PARITY       ( ushort )0x1000
+#define ASC_CNTL_BURST_MODE        ( ushort )0x2000
+
+#define ASC_CNTL_USE_8_IOP_BASE    ( ushort )0x4000
+
+#define ASC_EEP_DVC_CFG_BEG_VL    2
+#define ASC_EEP_MAX_DVC_ADDR_VL   15
+
+#define ASC_EEP_DVC_CFG_BEG      32
+#define ASC_EEP_MAX_DVC_ADDR     45
+
+#define ASC_EEP_DEFINED_WORDS    10
+#define ASC_EEP_MAX_ADDR         63
+#define ASC_EEP_RES_WORDS         0
+#define ASC_EEP_MAX_RETRY        20
+#define ASC_MAX_INIT_BUSY_RETRY   8
+
+#define ASC_EEP_ISA_PNP_WSIZE    16
+
+typedef struct asceep_config {
+	ushort              cfg_lsw;
+	ushort              cfg_msw;
+
+	uchar               init_sdtr;
+	uchar               disc_enable;
+
+	uchar               use_cmd_qng;
+
+	uchar               start_motor;
+	uchar               max_total_qng;
+	uchar               max_tag_qng;
+	uchar               bios_scan;
+
+	uchar               power_up_wait;
+
+	uchar               no_scam;
+	uchar               chip_scsi_id:4;
+
+	uchar               isa_dma_speed:4;
+
+	uchar               sdtr_data[ASC_MAX_TID + 1];
+
+	uchar               adapter_info[6];
+
+	ushort              cntl;
+
+	ushort              chksum;
+} ASCEEP_CONFIG;
+
+#define ASC_EEP_CMD_READ          0x80
+#define ASC_EEP_CMD_WRITE         0x40
+#define ASC_EEP_CMD_WRITE_ABLE    0x30
+#define ASC_EEP_CMD_WRITE_DISABLE 0x00
+
+#define ASC_OVERRUN_BSIZE  0x00000048UL
+
+#define ASCV_MSGOUT_BEG         0x0000
+#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
+#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
+
+#define ASCV_MSGIN_BEG          (ASCV_MSGOUT_BEG+8)
+#define ASCV_MSGIN_SDTR_PERIOD  (ASCV_MSGIN_BEG+3)
+#define ASCV_MSGIN_SDTR_OFFSET  (ASCV_MSGIN_BEG+4)
+
+#define ASCV_SDTR_DATA_BEG      (ASCV_MSGIN_BEG+8)
+#define ASCV_SDTR_DONE_BEG      (ASCV_SDTR_DATA_BEG+8)
+#define ASCV_MAX_DVC_QNG_BEG    ( ushort )0x0020
+
+#define ASCV_ASCDVC_ERR_CODE_W  ( ushort )0x0030
+#define ASCV_MCODE_CHKSUM_W   ( ushort )0x0032
+#define ASCV_MCODE_SIZE_W     ( ushort )0x0034
+#define ASCV_STOP_CODE_B      ( ushort )0x0036
+#define ASCV_DVC_ERR_CODE_B   ( ushort )0x0037
+
+#define ASCV_OVERRUN_PADDR_D  ( ushort )0x0038
+#define ASCV_OVERRUN_BSIZE_D  ( ushort )0x003C
+
+#define ASCV_HALTCODE_W       ( ushort )0x0040
+#define ASCV_CHKSUM_W         ( ushort )0x0042
+#define ASCV_MC_DATE_W        ( ushort )0x0044
+#define ASCV_MC_VER_W         ( ushort )0x0046
+#define ASCV_NEXTRDY_B        ( ushort )0x0048
+#define ASCV_DONENEXT_B       ( ushort )0x0049
+#define ASCV_USE_TAGGED_QNG_B ( ushort )0x004A
+#define ASCV_SCSIBUSY_B       ( ushort )0x004B
+#define ASCV_CDBCNT_B         ( ushort )0x004C
+#define ASCV_CURCDB_B         ( ushort )0x004D
+#define ASCV_RCLUN_B          ( ushort )0x004E
+#define ASCV_BUSY_QHEAD_B     ( ushort )0x004F
+#define ASCV_DISC1_QHEAD_B    ( ushort )0x0050
+
+#define ASCV_DISC_ENABLE_B    ( ushort )0x0052
+#define ASCV_CAN_TAGGED_QNG_B ( ushort )0x0053
+#define ASCV_HOSTSCSI_ID_B    ( ushort )0x0055
+#define ASCV_MCODE_CNTL_B     ( ushort )0x0056
+#define ASCV_NULL_TARGET_B    ( ushort )0x0057
+
+#define ASCV_FREE_Q_HEAD_W    ( ushort )0x0058
+#define ASCV_DONE_Q_TAIL_W    ( ushort )0x005A
+#define ASCV_FREE_Q_HEAD_B    ( ushort )(ASCV_FREE_Q_HEAD_W+1)
+#define ASCV_DONE_Q_TAIL_B    ( ushort )(ASCV_DONE_Q_TAIL_W+1)
+
+#define ASCV_HOST_FLAG_B      ( ushort )0x005D
+
+#define ASCV_TOTAL_READY_Q_B  ( ushort )0x0064
+#define ASCV_VER_SERIAL_B     ( ushort )0x0065
+#define ASCV_HALTCODE_SAVED_W ( ushort )0x0066
+#define ASCV_WTM_FLAG_B       ( ushort )0x0068
+#define ASCV_RISC_FLAG_B      ( ushort )0x006A
+#define ASCV_REQ_SG_LIST_QP   ( ushort )0x006B
+
+#define ASC_HOST_FLAG_IN_ISR        0x01
+#define ASC_HOST_FLAG_ACK_INT       0x02
+
+#define ASC_RISC_FLAG_GEN_INT      0x01
+#define ASC_RISC_FLAG_REQ_SG_LIST  0x02
+
+#define IOP_CTRL         (0x0F)
+#define IOP_STATUS       (0x0E)
+#define IOP_INT_ACK      IOP_STATUS
+
+#define IOP_REG_IFC      (0x0D)
+
+#define IOP_SYN_OFFSET   (0x0B)
+#define IOP_REG_PC       (0x0C)
+#define IOP_RAM_ADDR     (0x0A)
+#define IOP_RAM_DATA     (0x08)
+#define IOP_EEP_DATA     (0x06)
+#define IOP_EEP_CMD      (0x07)
+
+#define IOP_VERSION      (0x03)
+#define IOP_CONFIG_HIGH  (0x04)
+#define IOP_CONFIG_LOW   (0x02)
+#define IOP_ASPI_ID_LOW  (0x01)
+#define IOP_ASPI_ID_HIGH (0x00)
+
+#define IOP_REG_DC1      (0x0E)
+#define IOP_REG_DC0      (0x0C)
+#define IOP_REG_SB       (0x0B)
+#define IOP_REG_DA1      (0x0A)
+#define IOP_REG_DA0      (0x08)
+#define IOP_REG_SC       (0x09)
+#define IOP_DMA_SPEED    (0x07)
+#define IOP_REG_FLAG     (0x07)
+#define IOP_FIFO_H       (0x06)
+#define IOP_FIFO_L       (0x04)
+#define IOP_REG_ID       (0x05)
+#define IOP_REG_QP       (0x03)
+#define IOP_REG_IH       (0x02)
+#define IOP_REG_IX       (0x01)
+#define IOP_REG_AX       (0x00)
+
+#define IFC_REG_LOCK      (0x00)
+#define IFC_REG_UNLOCK    (0x09)
+
+#define IFC_WR_EN_FILTER  (0x10)
+#define IFC_RD_NO_EEPROM  (0x10)
+#define IFC_SLEW_RATE     (0x20)
+#define IFC_ACT_NEG       (0x40)
+#define IFC_INP_FILTER    (0x80)
+
+#define IFC_INIT_DEFAULT  ( IFC_ACT_NEG | IFC_REG_UNLOCK )
+
+#define SC_SEL   (0x80)
+#define SC_BSY   (0x40)
+#define SC_ACK   (0x20)
+#define SC_REQ   (0x10)
+#define SC_ATN   (0x08)
+#define SC_IO    (0x04)
+#define SC_CD    (0x02)
+#define SC_MSG   (0x01)
+
+#define AscGetVarFreeQHead( port )       AscReadLramWord( port, ASCV_FREE_Q_HEAD_W )
+#define AscGetVarDoneQTail( port )       AscReadLramWord( port, ASCV_DONE_Q_TAIL_W )
+#define AscPutVarFreeQHead( port, val )  AscWriteLramWord( port, ASCV_FREE_Q_HEAD_W, val )
+#define AscPutVarDoneQTail( port, val )  AscWriteLramWord( port, ASCV_DONE_Q_TAIL_W, val )
+
+#define AscGetRiscVarFreeQHead( port )        AscReadLramByte( port, ASCV_NEXTRDY_B )
+#define AscGetRiscVarDoneQTail( port )        AscReadLramByte( port, ASCV_DONENEXT_B )
+#define AscPutRiscVarFreeQHead( port, val )   AscWriteLramByte( port, ASCV_NEXTRDY_B, val )
+#define AscPutRiscVarDoneQTail( port, val )   AscWriteLramByte( port, ASCV_DONENEXT_B, val )
+
+#define AscGetChipIFC( port )               inp( (port)+IOP_REG_IFC )
+#define AscPutChipIFC( port, data )         outp( (port)+IOP_REG_IFC, data )
+
+#define AscGetChipLramAddr( port )          ( ushort )inpw( ( PortAddr )((port)+IOP_RAM_ADDR) )
+#define AscSetChipLramAddr( port, addr )    outpw( ( PortAddr )( (port)+IOP_RAM_ADDR ), addr )
+#define AscPutChipLramData( port, data )    outpw( (port)+IOP_RAM_DATA, data )
+#define AscGetChipLramData( port )          inpw( (port)+IOP_RAM_DATA )
+
+#define AscWriteChipSyn( port, data )       outp( (port)+IOP_SYN_OFFSET, data )
+#define AscReadChipSyn( port )              inp( (port)+IOP_SYN_OFFSET )
+
+#define AscWriteChipIH( port, data )        outpw( (port)+IOP_REG_IH, data )
+#define AscReadChipIH( port )               inpw( (port)+IOP_REG_IH )
+
+#define AscWriteChipScsiID( port, data )    outp( (port)+IOP_REG_ID, data )
+#define AscReadChipScsiID( port )           inp( (port)+IOP_REG_ID )
+
+#define AscGetChipDmaSpeed( port )         ( uchar )inp( (port)+IOP_DMA_SPEED )
+#define AscSetChipDmaSpeed( port, data )   outp( (port)+IOP_DMA_SPEED, data )
+#define AscGetChipQP( port )               ( uchar )inp( (port)+IOP_REG_QP )
+#define AscSetPCAddr( port, data )         outpw( (port)+IOP_REG_PC, data )
+#define AscGetPCAddr( port )               inpw( (port)+IOP_REG_PC )
+#define AscGetChipVerNo( port )            ( uchar )inp( (port)+IOP_VERSION )
+
+#define AscGetChipEEPCmd( port )           ( uchar )inp( (port)+IOP_EEP_CMD )
+#define AscSetChipEEPCmd( port, data )     outp( (port)+IOP_EEP_CMD, data )
+#define AscGetChipEEPData( port )          inpw( (port)+IOP_EEP_DATA )
+#define AscSetChipEEPData( port, data )    outpw( (port)+IOP_EEP_DATA, data )
+
+#define AscGetChipControl( port )          ( uchar )inp( (port)+IOP_CTRL )
+#define AscSetChipControl( port, cc_val )  outp( (port)+IOP_CTRL, cc_val )
+
+#define AscGetChipStatus( port )           ( ASC_CS_TYPE )inpw( (port)+IOP_STATUS )
+#define AscSetChipStatus( port, cs_val )   outpw( (port)+IOP_STATUS, cs_val )
+
+#define AscGetChipCfgLsw( port )           ( ushort )inpw( (port)+IOP_CONFIG_LOW )
+#define AscGetChipCfgMsw( port )           ( ushort )inpw( (port)+IOP_CONFIG_HIGH )
+#define AscSetChipCfgLsw( port, data )     outpw( (port)+IOP_CONFIG_LOW, data )
+#define AscSetChipCfgMsw( port, data )     outpw( (port)+IOP_CONFIG_HIGH, data )
+
+#define AscIsIntPending( port )           ( AscGetChipStatus( port ) & CSW_INT_PENDING )
+#define AscGetChipScsiID( port )          ( ( AscGetChipCfgLsw( port ) >> 8 ) & ASC_MAX_TID )
+
+#define ASC_HALT_EXTMSG_IN     ( ushort )0x8000
+#define ASC_HALT_CHK_CONDITION ( ushort )0x8100
+#define ASC_HALT_SS_QUEUE_FULL ( ushort )0x8200
+#define ASC_HALT_SDTR_REJECTED ( ushort )0x4000
+
+#define ASC_MAX_QNO        0xF8
+#define ASC_DATA_SEC_BEG   ( ushort )0x0080
+#define ASC_DATA_SEC_END   ( ushort )0x0080
+#define ASC_CODE_SEC_BEG   ( ushort )0x0080
+#define ASC_CODE_SEC_END   ( ushort )0x0080
+#define ASC_QADR_BEG       (0x4000)
+#define ASC_QADR_USED      ( ushort )( ASC_MAX_QNO * 64 )
+#define ASC_QADR_END       ( ushort )0x7FFF
+#define ASC_QLAST_ADR      ( ushort )0x7FC0
+#define ASC_QBLK_SIZE      0x40
+#define ASC_BIOS_DATA_QBEG 0xF8
+
+#define ASC_MIN_ACTIVE_QNO 0x01
+
+#define ASC_QLINK_END      0xFF
+#define ASC_EEPROM_WORDS   0x10
+#define ASC_MAX_MGS_LEN    0x10
+
+#define ASC_BIOS_ADDR_DEF  0xDC00
+#define ASC_BIOS_SIZE      0x3800
+#define ASC_BIOS_RAM_OFF   0x3800
+#define ASC_BIOS_RAM_SIZE  0x800
+#define ASC_BIOS_MIN_ADDR  0xC000
+#define ASC_BIOS_MAX_ADDR  0xEC00
+#define ASC_BIOS_BANK_SIZE 0x0400
+
+#define ASC_MCODE_START_ADDR  0x0080
+
+#define ASC_CFG0_HOST_INT_ON    0x0020
+#define ASC_CFG0_BIOS_ON        0x0040
+#define ASC_CFG0_VERA_BURST_ON  0x0080
+#define ASC_CFG0_SCSI_PARITY_ON 0x0800
+
+#define ASC_CFG1_SCSI_TARGET_ON 0x0080
+#define ASC_CFG1_LRAM_8BITS_ON  0x0800
+
+#define ASC_CFG_MSW_CLR_MASK    0xF0C0
+
+#define CSW_TEST1             ( ASC_CS_TYPE )0x8000
+#define CSW_AUTO_CONFIG       ( ASC_CS_TYPE )0x4000
+#define CSW_RESERVED1         ( ASC_CS_TYPE )0x2000
+#define CSW_IRQ_WRITTEN       ( ASC_CS_TYPE )0x1000
+#define CSW_33MHZ_SELECTED    ( ASC_CS_TYPE )0x0800
+#define CSW_TEST2             ( ASC_CS_TYPE )0x0400
+#define CSW_TEST3             ( ASC_CS_TYPE )0x0200
+#define CSW_RESERVED2         ( ASC_CS_TYPE )0x0100
+#define CSW_DMA_DONE          ( ASC_CS_TYPE )0x0080
+#define CSW_FIFO_RDY          ( ASC_CS_TYPE )0x0040
+
+#define CSW_EEP_READ_DONE     ( ASC_CS_TYPE )0x0020
+
+#define CSW_HALTED            ( ASC_CS_TYPE )0x0010
+#define CSW_SCSI_RESET_ACTIVE ( ASC_CS_TYPE )0x0008
+
+#define CSW_PARITY_ERR        ( ASC_CS_TYPE )0x0004
+#define CSW_SCSI_RESET_LATCH  ( ASC_CS_TYPE )0x0002
+
+#define CSW_INT_PENDING       ( ASC_CS_TYPE )0x0001
+
+#define CIW_INT_ACK      ( ASC_CS_TYPE )0x0100
+#define CIW_TEST1        ( ASC_CS_TYPE )0x0200
+#define CIW_TEST2        ( ASC_CS_TYPE )0x0400
+#define CIW_SEL_33MHZ    ( ASC_CS_TYPE )0x0800
+
+#define CIW_IRQ_ACT      ( ASC_CS_TYPE )0x1000
+
+#define CC_CHIP_RESET   ( uchar )0x80
+#define CC_SCSI_RESET   ( uchar )0x40
+#define CC_HALT         ( uchar )0x20
+#define CC_SINGLE_STEP  ( uchar )0x10
+#define CC_DMA_ABLE     ( uchar )0x08
+#define CC_TEST         ( uchar )0x04
+#define CC_BANK_ONE     ( uchar )0x02
+#define CC_DIAG         ( uchar )0x01
+
+#define ASC_1000_ID0W      0x04C1
+#define ASC_1000_ID0W_FIX  0x00C1
+#define ASC_1000_ID1B      0x25
+
+#define ASC_EISA_BIG_IOP_GAP   (0x1C30-0x0C50)
+#define ASC_EISA_SMALL_IOP_GAP (0x0020)
+#define ASC_EISA_MIN_IOP_ADDR  (0x0C30)
+#define ASC_EISA_MAX_IOP_ADDR  (0xFC50)
+#define ASC_EISA_REV_IOP_MASK  (0x0C83)
+#define ASC_EISA_PID_IOP_MASK  (0x0C80)
+#define ASC_EISA_CFG_IOP_MASK  (0x0C86)
+
+#define ASC_GET_EISA_SLOT( iop )  ( PortAddr )( (iop) & 0xF000 )
+
+#define ASC_EISA_ID_740    0x01745004UL
+#define ASC_EISA_ID_750    0x01755004UL
+
+#define INS_HALTINT        ( ushort )0x6281
+#define INS_HALT           ( ushort )0x6280
+#define INS_SINT           ( ushort )0x6200
+#define INS_RFLAG_WTM      ( ushort )0x7380
+
+#define ASC_MC_SAVE_CODE_WSIZE  0x500
+#define ASC_MC_SAVE_DATA_WSIZE  0x40
+
+typedef struct asc_mc_saved {
+	ushort              data[ASC_MC_SAVE_DATA_WSIZE];
+	ushort              code[ASC_MC_SAVE_CODE_WSIZE];
+} ASC_MC_SAVED;
+
+int                 AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
+int                 AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
+void                AscWaitEEPRead(void);
+void                AscWaitEEPWrite(void);
+ushort              AscReadEEPWord(PortAddr, uchar);
+ushort              AscWriteEEPWord(PortAddr, uchar, ushort);
+ushort              AscGetEEPConfig(PortAddr, ASCEEP_CONFIG dosfar *, ushort);
+int                 AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG dosfar *, ushort);
+int                 AscSetEEPConfig(PortAddr, ASCEEP_CONFIG dosfar *, ushort);
+ushort              AscEEPSum(PortAddr, uchar, uchar);
+
+int                 AscStartChip(PortAddr);
+int                 AscStopChip(PortAddr);
+void                AscSetChipIH(PortAddr, ushort);
+int                 AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
+
+int                 AscIsChipHalted(PortAddr);
+
+void                AscSetChipCfgDword(PortAddr, ulong);
+ulong               AscGetChipCfgDword(PortAddr);
+
+void                AscAckInterrupt(PortAddr);
+void                AscDisableInterrupt(PortAddr);
+void                AscEnableInterrupt(PortAddr);
+void                AscSetBank(PortAddr, uchar);
+uchar               AscGetBank(PortAddr);
+int                 AscResetChipAndScsiBus(PortAddr);
+ushort              AscGetIsaDmaChannel(PortAddr);
+ushort              AscSetIsaDmaChannel(PortAddr, ushort);
+uchar               AscSetIsaDmaSpeed(PortAddr, uchar);
+uchar               AscGetIsaDmaSpeed(PortAddr);
+
+uchar               AscReadLramByte(PortAddr, ushort);
+ushort              AscReadLramWord(PortAddr, ushort);
+ulong               AscReadLramDWord(PortAddr, ushort);
+void                AscWriteLramWord(PortAddr, ushort, ushort);
+void                AscWriteLramDWord(PortAddr, ushort, ulong);
+void                AscWriteLramByte(PortAddr, ushort, uchar);
+int                 AscVerWriteLramDWord(PortAddr, ushort, ulong);
+int                 AscVerWriteLramWord(PortAddr, ushort, ushort);
+int                 AscVerWriteLramByte(PortAddr, ushort, uchar);
+
+ulong               AscMemSumLramWord(PortAddr, ushort, int);
+void                AscMemWordSetLram(PortAddr, ushort, ushort, int);
+void                AscMemWordCopyToLram(PortAddr, ushort, ushort dosfar *, int);
+void                AscMemDWordCopyToLram(PortAddr, ushort, ulong dosfar *, int);
+void                AscMemWordCopyFromLram(PortAddr, ushort, ushort dosfar *, int);
+int                 AscMemWordCmpToLram(PortAddr, ushort, ushort dosfar *, int);
+
+ushort              AscInitAscDvcVar(ASC_DVC_VAR asc_ptr_type *);
+ulong               AscLoadMicroCode(PortAddr, ushort,
+									 ushort dosfar *, ushort);
+ushort              AscInitFromEEP(ASC_DVC_VAR asc_ptr_type *);
+ushort              AscInitFromAscDvcVar(ASC_DVC_VAR asc_ptr_type *);
+ushort              AscInitMicroCodeVar(ASC_DVC_VAR asc_ptr_type * asc_dvc);
+
+void dosfar         AscInitPollIsrCallBack(ASC_DVC_VAR asc_ptr_type *,
+										   ASC_QDONE_INFO dosfar *);
+int                 AscTestExternalLram(ASC_DVC_VAR asc_ptr_type *);
+ushort              AscTestLramEndian(PortAddr);
+
+uchar               AscMsgOutSDTR(PortAddr, uchar, uchar);
+
+uchar               AscCalSDTRData(uchar, uchar);
+void                AscSetChipSDTR(PortAddr, uchar, uchar);
+int                 AscInitChipAllSynReg(ASC_DVC_VAR asc_ptr_type *, uchar);
+uchar               AscGetSynPeriodIndex(uchar);
+uchar               AscSynIndexToPeriod(uchar);
+uchar               AscAllocFreeQueue(PortAddr, uchar);
+uchar               AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
+int                 AscRiscHaltedAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong);
+int                 AscRiscHaltedAbortTIX(ASC_DVC_VAR asc_ptr_type *, uchar);
+int                 AscRiscHaltedAbortALL(ASC_DVC_VAR asc_ptr_type *);
+int                 AscHostReqRiscHalt(PortAddr);
+int                 AscStopQueueExe(PortAddr);
+int                 AscStartQueueExe(PortAddr);
+int                 AscCleanUpDiscQueue(PortAddr);
+int                 AscCleanUpBusyQueue(PortAddr);
+int                 _AscAbortTidBusyQueue(ASC_DVC_VAR asc_ptr_type *,
+										  ASC_QDONE_INFO dosfar *, uchar);
+int                 _AscAbortSrbBusyQueue(ASC_DVC_VAR asc_ptr_type *,
+										  ASC_QDONE_INFO dosfar *, ulong);
+int                 AscWaitTixISRDone(ASC_DVC_VAR asc_ptr_type *, uchar);
+int                 AscWaitISRDone(ASC_DVC_VAR asc_ptr_type *);
+ulong               AscGetOnePhyAddr(ASC_DVC_VAR asc_ptr_type *, uchar dosfar *, ulong);
+
+int                 AscSendScsiQueue(ASC_DVC_VAR asc_ptr_type * asc_dvc,
+									 ASC_SCSI_Q dosfar * scsiq,
+									 uchar n_q_required);
+int                 AscPutReadyQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *, uchar);
+int                 AscPutReadySgListQueue(ASC_DVC_VAR asc_ptr_type *,
+										   ASC_SCSI_Q dosfar *, uchar);
+int                 AscAbortScsiIO(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *);
+void                AscExeScsiIO(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *);
+int                 AscSetChipSynRegAtID(PortAddr, uchar, uchar);
+int                 AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
+ushort              AscInitLram(ASC_DVC_VAR asc_ptr_type *);
+int                 AscReInitLram(ASC_DVC_VAR asc_ptr_type *);
+ushort              AscInitQLinkVar(ASC_DVC_VAR asc_ptr_type *);
+int                 AscSetLibErrorCode(ASC_DVC_VAR asc_ptr_type *, ushort);
+int                 _AscWaitQDone(PortAddr, ASC_SCSI_Q dosfar *);
+
+int                 AscEnterCritical(void);
+void                AscLeaveCritical(int);
+
+int                 AscIsrChipHalted(ASC_DVC_VAR asc_ptr_type *);
+uchar               _AscCopyLramScsiDoneQ(PortAddr, ushort,
+										  ASC_QDONE_INFO dosfar *, ulong);
+int                 AscIsrQDone(ASC_DVC_VAR asc_ptr_type *);
+ushort              AscIsrExeBusyQueue(ASC_DVC_VAR asc_ptr_type *, uchar);
+int                 AscScsiSetupCmdQ(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *,
+									 uchar dosfar *, ulong);
+
+int                 AscScsiInquiry(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *,
+								   uchar dosfar *, int);
+int                 AscScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *);
+int                 AscScsiStartStopUnit(ASC_DVC_VAR asc_ptr_type *,
+										 ASC_SCSI_REQ_Q dosfar *, uchar);
+int                 AscScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *,
+										ASC_SCSI_REQ_Q dosfar *,
+										uchar dosfar *);
+
+ulong dosfar       *swapfarbuf4(uchar dosfar *);
+int                 PollQueueDone(ASC_DVC_VAR asc_ptr_type *,
+								  ASC_SCSI_REQ_Q dosfar *,
+								  int);
+int                 PollScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *,
+										 ASC_SCSI_REQ_Q dosfar *,
+										 ASC_CAP_INFO dosfar *);
+int                 PollScsiInquiry(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *,
+									uchar dosfar *, int);
+int                 PollScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *,
+										  ASC_SCSI_REQ_Q dosfar *);
+int                 PollScsiStartUnit(ASC_DVC_VAR asc_ptr_type *,
+									  ASC_SCSI_REQ_Q dosfar *);
+int                 InitTestUnitReady(ASC_DVC_VAR asc_ptr_type *,
+									  ASC_SCSI_REQ_Q dosfar *);
+void                AscDispInquiry(uchar, uchar, ASC_SCSI_INQUIRY dosfar *);
+int                 AscPollQDone(ASC_DVC_VAR asc_ptr_type *,
+								 ASC_SCSI_REQ_Q dosfar *, int);
+
+int                 AscSetBIOSBank(PortAddr, int, ushort);
+int                 AscSetVlBIOSBank(PortAddr, int);
+int                 AscSetEisaBIOSBank(PortAddr, int);
+int                 AscSetIsaBIOSBank(PortAddr, int);
+
+int                 AscIsBiosEnabled(PortAddr, ushort);
+void                AscResetScsiBus(PortAddr);
+void                AscClrResetScsiBus(PortAddr);
+
+void                AscSingleStepChip(PortAddr);
+uchar               AscSetChipScsiID(PortAddr, uchar);
+ushort              AscGetChipBiosAddress(PortAddr, ushort);
+ushort              AscSetChipBiosAddress(PortAddr, ushort, ushort);
+uchar               AscGetChipVersion(PortAddr, ushort);
+ushort              AscGetChipBusType(PortAddr);
+
+PortAddr            AscSearchIOPortAddr11(PortAddr);
+PortAddr            AscSearchIOPortAddr100(PortAddr);
+int                 AscFindSignature(PortAddr);
+void                AscToggleIRQAct(PortAddr);
+int                 AscResetChip(PortAddr);
+void                AscClrResetChip(PortAddr);
+
+short               itos(ushort, uchar dosfar *, short, short);
+int                 insnchar(uchar dosfar *, short, short, ruchar, short);
+void                itoh(ushort, ruchar dosfar *);
+void                btoh(uchar, ruchar dosfar *);
+void                ltoh(ulong, ruchar dosfar *);
+uchar dosfar       *todstr(ushort, uchar dosfar *);
+uchar dosfar       *tohstr(ushort, uchar dosfar *);
+uchar dosfar       *tobhstr(uchar, uchar dosfar *);
+uchar dosfar       *tolhstr(ulong, uchar dosfar *);
+
+void                AscSetISAPNPWaitForKey(void);
+uchar               AscGetChipIRQ(PortAddr, ushort);
+uchar               AscSetChipIRQ(PortAddr, uchar, ushort);
+uchar               AscGetChipScsiCtrl(PortAddr);
+
+ushort              AscGetEisaChipCfg(PortAddr);
+ushort              AscGetEisaChipGpReg(PortAddr);
+ushort              AscSetEisaChipCfg(PortAddr, ushort);
+ushort              AscSetEisaChipGpReg(PortAddr, ushort);
+
+ulong               AscGetEisaProductID(PortAddr);
+PortAddr            AscSearchIOPortAddrEISA(PortAddr);
+
+int                 AscPollQTailSync(PortAddr);
+int                 AscPollQHeadSync(PortAddr);
+int                 AscWaitQTailSync(PortAddr);
+
+int                 _AscRestoreMicroCode(PortAddr, ASC_MC_SAVED dosfar *);
+
+int                 AscSCAM(ASC_DVC_VAR asc_ptr_type *);
+
+ushort              SwapByteOfWord(ushort word_val);
+ulong               SwapWordOfDWord(ulong dword_val);
+ulong               AdjEndianDword(ulong dword_val);
+
+int                 AscAdjEndianScsiQ(ASC_SCSI_Q dosfar *);
+int                 AscAdjEndianQDoneInfo(ASC_QDONE_INFO dosfar *);
+
+extern int          DvcEnterCritical(void);
+extern void         DvcLeaveCritical(int);
+
+extern void         DvcInPortWords(PortAddr, ushort dosfar *, int);
+extern void         DvcOutPortWords(PortAddr, ushort dosfar *, int);
+extern void         DvcOutPortDWords(PortAddr, ulong dosfar *, int);
+
+extern void         DvcSleepMilliSecond(ulong);
+extern void         DvcDisplayString(uchar dosfar *);
+extern ulong        DvcGetPhyAddr(uchar dosfar * buf_addr, ulong buf_len);
+extern ulong        DvcGetSGList(ASC_DVC_VAR asc_ptr_type *, uchar dosfar *, ulong,
+								 ASC_SG_HEAD dosfar *);
+
+extern void         DvcSCAMDelayMS(ulong);
+extern int          DvcDisableCPUInterrupt(void);
+extern void         DvcRestoreCPUInterrupt(int);
+
+void                DvcPutScsiQ(PortAddr, ushort, ushort dosfar *, int);
+void                DvcGetQinfo(PortAddr, ushort, ushort dosfar *, int);
+
+PortAddr            AscSearchIOPortAddr(PortAddr, ushort);
+ushort              AscInitGetConfig(ASC_DVC_VAR asc_ptr_type *);
+ushort              AscInitSetConfig(ASC_DVC_VAR asc_ptr_type *);
+ushort              AscInitAsc1000Driver(ASC_DVC_VAR asc_ptr_type *);
+int                 AscInitScsiTarget(ASC_DVC_VAR asc_ptr_type *,
+									  ASC_DVC_INQ_INFO dosfar *,
+									  uchar dosfar *,
+									  ASC_CAP_INFO_ARRAY dosfar *,
+									  ushort);
+int                 AscInitPollBegin(ASC_DVC_VAR asc_ptr_type *);
+int                 AscInitPollEnd(ASC_DVC_VAR asc_ptr_type *);
+int                 AscInitPollTarget(ASC_DVC_VAR asc_ptr_type *,
+									  ASC_SCSI_REQ_Q dosfar *,
+									  ASC_SCSI_INQUIRY dosfar *,
+									  ASC_CAP_INFO dosfar *);
+int                 AscExeScsiQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *);
+
+int                 AscISR(ASC_DVC_VAR asc_ptr_type *);
+void                AscISR_AckInterrupt(ASC_DVC_VAR asc_ptr_type *);
+int                 AscISR_CheckQDone(ASC_DVC_VAR asc_ptr_type *,
+									  ASC_QDONE_INFO dosfar *,
+									  uchar dosfar *);
+
+int                 AscStartUnit(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_TIX_TYPE);
+int                 AscStopUnit(
+								   ASC_DVC_VAR asc_ptr_type * asc_dvc,
+								   ASC_SCSI_TIX_TYPE target_ix
+);
+
+uint                AscGetNumOfFreeQueue(ASC_DVC_VAR asc_ptr_type *, uchar, uchar);
+int                 AscSgListToQueue(int);
+int                 AscQueueToSgList(int);
+int                 AscSetDvcErrorCode(ASC_DVC_VAR asc_ptr_type *, uchar);
+
+int                 AscAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong);
+int                 AscResetDevice(ASC_DVC_VAR asc_ptr_type *, uchar);
+int                 AscResetSB(ASC_DVC_VAR asc_ptr_type *);
+
+void                AscEnableIsaDma(uchar);
+void                AscDisableIsaDma(uchar);
+
+ulong               AscGetMaxDmaAddress(ushort);
+ulong               AscGetMaxDmaCount(ushort);
+
+int                 AscSaveMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *);
+int                 AscRestoreOldMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *);
+int                 AscRestoreNewMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *);
+
+/*
+ * --- Debugging Header
+ */
+
+#ifdef ADVANSYS_DEBUG
+#define STATIC
+#else /* ADVANSYS_DEBUG */
+#define STATIC static
+#endif /* ADVANSYS_DEBUG */
+
+
+/*
+ * --- Driver Constants and Macros
+ */
+
+#define ASC_NUM_BOARD_SUPPORTED 4
+#define ASC_NUM_BUS				4
+
+/* Reference Scsi_Host hostdata */
+#define ASC_BOARD(host) ((struct asc_board *) &(host)->hostdata)
+
+#define NO_ISA_DMA	0xff		/* No ISA DMA Channel Used */
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* min */
+
+/* Asc Library return codes */
+#define ASC_TRUE		1
+#define ASC_FALSE		0
+#define ASC_NOERROR		1
+#define ASC_BUSY		0
+#define ASC_ERROR		(-1)
+
+/* Scsi_Cmnd function return codes */
+#define STATUS_BYTE(byte)	(byte)
+#define MSG_BYTE(byte)		((byte) << 8)
+#define HOST_BYTE(byte)		((byte) << 16)
+#define DRIVER_BYTE(byte)	((byte) << 24)
+
+/* asc_enqueue() flags */
+#define ASC_FRONT		1
+#define ASC_BACK		2
+
+/* PCI configuration declarations */
+
+#define ASC_PCI_REV_A_INIT		0x01
+#define ASC_PCI_REV_A_DONE		0x02
+#define ASC_PCI_REV_B_INIT		0x04
+#define ASC_PCI_REV_B_DONE		0x08
+
+#define PCI_BASE_CLASS_PREDEFINED			0x00
+#define PCI_BASE_CLASS_MASS_STORAGE			0x01
+#define PCI_BASE_CLASS_NETWORK				0x02
+#define PCI_BASE_CLASS_DISPLAY				0x03
+#define PCI_BASE_CLASS_MULTIMEDIA			0x04
+#define PCI_BASE_CLASS_MEMORY_CONTROLLER	0x05
+#define PCI_BASE_CLASS_BRIDGE_DEVICE		0x06
+
+/* MASS STORAGE */
+#define PCI_SUB_CLASS_SCSI_CONTROLLER			0x00
+#define PCI_SUB_CLASS_IDE_CONTROLLER			0x01
+#define PCI_SUB_CLASS_FLOPPY_DISK_CONTROLLER	0x02
+#define PCI_SUB_CLASS_IPI_BUS_CONTROLLER		0x03
+#define PCI_SUB_CLASS_OTHER_MASS_CONTROLLER		0x80
+
+/* NETWORK CONTROLLER */
+#define PCI_SUB_CLASS_ETHERNET_CONTROLLER		0x00
+#define PCI_SUB_CLASS_TOKEN_RING_CONTROLLER		0x01
+#define PCI_SUB_CLASS_FDDI_CONTROLLER			0x02
+#define PCI_SUB_CLASS_OTHER_NETWORK_CONTROLLER	0x80
+
+/* DISPLAY CONTROLLER */
+#define PCI_SUB_CLASS_VGA_CONTROLLER			0x00
+#define PCI_SUB_CLASS_XGA_CONTROLLER			0x01
+#define PCI_SUB_CLASS_OTHER_DISPLAY_CONTROLLER	0x80
+
+/* MULTIMEDIA CONTROLLER */
+#define PCI_SUB_CLASS_VIDEO_DEVICE				0x00
+#define PCI_SUB_CLASS_AUDIO_DEVICE				0x01
+#define PCI_SUB_CLASS_OTHER_MULTIMEDIA_DEVICE	0x80
+
+/* MEMORY CONTROLLER */
+#define PCI_SUB_CLASS_RAM_CONTROLLER			0x00
+#define PCI_SUB_CLASS_FLASH_CONTROLLER			0x01
+#define PCI_SUB_CLASS_OTHER_MEMORY_CONTROLLER	0x80
+
+/* BRIDGE CONTROLLER */
+#define PCI_SUB_CLASS_HOST_BRIDGE_CONTROLLER		0x00
+#define PCI_SUB_CLASS_ISA_BRIDGE_CONTROLLER			0x01
+#define PCI_SUB_CLASS_EISA_BRIDGE_CONTROLLER		0x02
+#define PCI_SUB_CLASS_MC_BRIDGE_CONTROLLER			0x03
+#define PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER	0x04
+#define PCI_SUB_CLASS_PCMCIA_BRIDGE_CONTROLLER		0x05
+#define PCI_SUB_CLASS_OTHER_BRIDGE_CONTROLLER		0x80
+
+#define PCI_MAX_SLOT			0x1F
+#define PCI_MAX_BUS				0xFF
+#define ASC_PCI_VENDORID		0x10CD
+#define PCI_IOADDRESS_MASK		0xFFFE
+
+/* PCI IO Port Addresses to generate special cycle */
+
+#define PCI_CONFIG_ADDRESS_MECH1		0x0CF8
+#define PCI_CONFIG_DATA_MECH1			0x0CFC
+
+#define PCI_CONFIG_FORWARD_REGISTER		0x0CFA	/* 0=type 0; 1=type 1; */
+
+#define PCI_CONFIG_BUS_NUMBER_MASK		0x00FF0000
+#define PCI_CONFIG_DEVICE_FUNCTION_MASK	0x0000FF00
+#define PCI_CONFIG_REGISTER_NUMBER_MASK	0x000000F8
+
+#define PCI_DEVICE_FOUND				0x0000
+#define PCI_DEVICE_NOT_FOUND			0xffff
+
+#define SUBCLASS_OFFSET 	0x0A
+#define CLASSCODE_OFFSET	0x0B
+#define VENDORID_OFFSET		0x00
+#define DEVICEID_OFFSET		0x02
+
+/*
+ * --- Driver Macros
+ */
+
+#ifndef ADVANSYS_STATS
+#define ASC_STATS(counter)
+#define ASC_STATS_ADD(counter, count)
+#else /* ADVANSYS_STATS */
+#define ASC_STATS(counter)				asc_stats.counter++
+#define ASC_STATS_ADD(counter, count)	asc_stats.counter += (count)
+#endif /* ADVANSYS_STATS */
+
+#ifndef ADVANSYS_DEBUG
+
+#define	ASC_DBG(lvl, s)
+#define	ASC_DBG1(lvl, s, a1)
+#define	ASC_DBG2(lvl, s, a1, a2)
+#define	ASC_DBG3(lvl, s, a1, a2, a3)
+#define	ASC_DBG4(lvl, s, a1, a2, a3, a4)
+#define	ASC_DBG_PRT_SCSI_HOST(lvl, s)
+#define	ASC_DBG_PRT_DVC_VAR(lvl, v)
+#define	ASC_DBG_PRT_DVC_CFG(lvl, c)
+#define	ASC_DBG_PRT_SCSI_Q(lvl, scsiqp)
+#define	ASC_DBG_PRT_QDONE_INFO(lvl, qdone)
+#define	ASC_DBG_PRT_HEX(lvl, name, start, length)
+#define	ASC_DBG_PRT_CDB(lvl, cdb, len)
+#define	ASC_DBG_PRT_SENSE(lvl, sense, len)
+#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
+#define ASC_ASSERT(a)
+
+#else /* ADVANSYS_DEBUG */
+
+/*
+ * Debugging Message Levels:
+ * 0: Errors Only
+ * 1: High-Level Tracing
+ * 2-N: Verbose Tracing
+ */
+
+#define	ASC_DBG(lvl, s) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			printk(s); \
+		} \
+	}
+
+#define	ASC_DBG1(lvl, s, a1) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			printk((s), (a1)); \
+		} \
+	}
+
+#define	ASC_DBG2(lvl, s, a1, a2) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			printk((s), (a1), (a2)); \
+		} \
+	}
+
+#define	ASC_DBG3(lvl, s, a1, a2, a3) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			printk((s), (a1), (a2), (a3)); \
+		} \
+	}
+
+#define	ASC_DBG4(lvl, s, a1, a2, a3, a4) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			printk((s), (a1), (a2), (a3), (a4)); \
+		} \
+	}
+
+#define	ASC_DBG_PRT_SCSI_HOST(lvl, s) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			asc_prt_scsi_host(s); \
+		} \
+	}
+
+#define	ASC_DBG_PRT_DVC_VAR(lvl, v) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			asc_prt_dvc_var(v); \
+		} \
+	}
+
+#define	ASC_DBG_PRT_DVC_CFG(lvl, c) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			asc_prt_dvc_cfg(c); \
+		} \
+	}
+
+#define	ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			asc_prt_scsi_q(scsiqp); \
+		} \
+	}
+
+#define	ASC_DBG_PRT_QDONE_INFO(lvl, qdone) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			asc_prt_qdone_info(qdone); \
+		} \
+	}
+
+#define	ASC_DBG_PRT_HEX(lvl, name, start, length) \
+	{ \
+		if (asc_dbglvl >= (lvl)) { \
+			asc_prt_hex((name), (start), (length)); \
+		} \
+	}
+
+#define	ASC_DBG_PRT_CDB(lvl, cdb, len) \
+		ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
+
+#define	ASC_DBG_PRT_SENSE(lvl, sense, len) \
+		ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
+
+#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
+		ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
+
+#define ASC_ASSERT(a) \
+	{ \
+		if (!(a)) { \
+			printk("ASC_ASSERT() Failure: file %s, line %d\n", \
+				__FILE__, __LINE__); \
+		} \
+	}
+#endif /* ADVANSYS_DEBUG */
+
+
+/*
+ * --- Driver Structures
+ */
+
+/*
+ * Structure allocated for each board.
+ *
+ * This structure is allocated by scsi_register() at the end
+ * of the 'Scsi_Host' structure starting at the 'hostdata'
+ * field. It is guaranteed to be allocated from DMA-able memory.
+ */
+struct asc_board {
+	/* Asc Library */
+	ASC_DVC_VAR			 board;					/* Board configuration */
+	ASC_DVC_CFG			 cfg;					/* Device configuration */
+	uchar				 overrun_buf[ASC_OVERRUN_BSIZE];
+	/* Queued Commands */
+	ASC_SCSI_BIT_ID_TYPE pending_tidmask;		/* Pending command mask */
+	Scsi_Cmnd			 *pending[ASC_MAX_TID];
+	/* Target Initialization */
+	ASC_SCSI_BIT_ID_TYPE init_tidmask;			/* Target initialized mask */
+	ASC_SCSI_REQ_Q		 scsireqq;
+	ASC_CAP_INFO		 cap_info;
+	ASC_SCSI_INQUIRY	 inquiry;
+};
+
+/*
+ * PCI configuration structures
+ */
+typedef struct _PCI_DATA_
+{
+	uchar	type;
+	uchar	bus;
+	uchar	slot;
+	uchar	func;
+	uchar	offset;
+} PCI_DATA;
+
+typedef struct _PCI_DEVICE_
+{
+	ushort	vendorID;
+	ushort	deviceID;
+	ushort	slotNumber;
+	ushort	slotFound;
+	uchar	busNumber;
+	uchar	maxBusNumber;
+	uchar	devFunc;
+	ushort	startSlot;
+	ushort	endSlot;
+	uchar	bridge;
+	uchar	type;
+} PCI_DEVICE;
+
+typedef struct _PCI_CONFIG_SPACE_
+{
+	ushort	vendorID;
+	ushort	deviceID;
+	ushort	command;
+	ushort	status;
+	uchar	revision;
+	uchar	classCode[3];
+	uchar	cacheSize;
+	uchar	latencyTimer;
+	uchar	headerType;
+	uchar	bist;
+	ulong	baseAddress[6];
+	ushort	reserved[4];
+	ulong	optionRomAddr;
+	ushort	reserved2[4];
+	uchar	irqLine;
+	uchar	irqPin;
+	uchar	minGnt;
+	uchar	maxLatency;
+} PCI_CONFIG_SPACE;
+
+#ifdef ADVANSYS_STATS
+struct asc_stats {
+	ulong 	command;		/* # calls to advansys_command() */
+	ulong 	queuecommand;	/* # calls to advansys_queuecommand() */
+	ulong 	abort;			/* # calls to advansys_abort() */
+	ulong 	reset;			/* # calls to advansys_reset() */
+	ulong 	biosparam;		/* # calls to advansys_biosparam() */
+	ulong 	interrupt;		/* # calls to advansys_interrupt() */
+	ulong 	callback;		/* # calls asc_isr_callback() */
+	ulong 	cont_cnt;		/* # non-scatter-gather I/O requests received */
+	ulong 	cont_xfer;		/* contiguous transfer total (512 byte units) */
+	ulong 	sg_cnt;			/* # scatter-gather I/O requests received */
+	ulong 	sg_elem;		/* scatter-gather element total */
+	ulong 	sg_xfer;		/* scatter-gather tranfer total (512 byte units) */
+	ulong 	error;			/* # AscExeScsiQueue() ASC_ERROR returns. */
+	/*
+	 * Number of times interrupts disabled in advansys_queuecommand() and
+	 * asc_isr_callback(), respectively. For the former indicates how many
+	 * times commands were pending when a new command was received.
+	 */
+	ulong 	cmd_disable;
+	ulong 	intr_disable;
+	/*
+	 * Number of times asc_enqueue() called. Indicates how many ASC_BUSY
+	 * returns have occurred.
+	 */
+	ulong 	enqueue;
+	ulong 	dequeue;		/* # calls to asc_dequeue(). */
+	/*
+	 * Number of times asc_rmqueue() called and the specified command
+	 * was found and removed.
+	 */
+	ulong 	rmqueue;
+} asc_stats;
+#endif /* ADVANSYS_STATS */
+
+
+/*
+ * --- Driver Data
+ */
+
+#ifdef LINUX_1_3
+struct proc_dir_entry proc_scsi_advansys =
+{
+	PROC_SCSI_ADVANSYS,				/* unsigned short low_ino */
+	8,								/* unsigned short namelen */
+	"advansys",						/* const char *name */
+	S_IFDIR | S_IRUGO | S_IXUGO,	/* mode_t mode */
+	2								/* nlink_t nlink */
+};
+#endif /* LINUX_1_3 */
+
+STATIC int asc_board_count; /* Number of boards detected in system. */
+STATIC struct Scsi_Host	*asc_host[ASC_NUM_BOARD_SUPPORTED];
+STATIC Scsi_Cmnd *asc_scsi_done; /* Commands needing done function call. */
+
+STATIC ushort asc_bus[ASC_NUM_BUS] = {
+	ASC_IS_ISA,
+	ASC_IS_VL,
+	ASC_IS_EISA,
+	ASC_IS_PCI,
+};
+
+/*
+ * Used with the LILO 'advansys' option to eliminate or
+ * limit I/O port probing at boot time, cf. advansys_setup().
+ */
+int asc_iopflag = ASC_FALSE;
+int asc_ioport[ASC_NUM_BOARD_SUPPORTED] = { 0, 0, 0, 0 };
+
+#ifdef ADVANSYS_DEBUG
+char *
+asc_bus_name[ASC_NUM_BUS] = {
+	"ASC_IS_ISA",
+	"ASC_IS_VL",
+	"ASC_IS_EISA",
+	"ASC_IS_PCI",
+};
+
+int		asc_dbglvl = 0;
+#endif /* ADVANSYS_DEBUG */
+
+
+/*
+ * --- Driver Function Prototypes
+ *
+ * advansys.h contains function prototypes for functions global to Linux.
+ */
+
+#ifdef LINUX_1_3
+STATIC int			asc_proc_copy(off_t, off_t, char *, int , char *, int);
+#endif /* LINUX_1_3 */
+STATIC void 		advansys_interrupt(int, struct pt_regs *);
+STATIC void 		advansys_command_done(Scsi_Cmnd *);
+STATIC int 			asc_execute_scsi_cmnd(Scsi_Cmnd *);
+STATIC void 		asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
+STATIC void			asc_execute_pending(struct Scsi_Host *);
+STATIC int 			asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *);
+STATIC int 			asc_srch_pci_dev(PCI_DEVICE *);
+STATIC uchar 		asc_scan_method(PCI_DEVICE *);
+STATIC int 			asc_pci_find_dev(PCI_DEVICE *);
+STATIC void 		asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *);
+STATIC ushort 		asc_get_cfg_word(PCI_DATA *);
+STATIC uchar 		asc_get_cfg_byte(PCI_DATA *);
+STATIC void			asc_enqueue(struct Scsi_Host *, Scsi_Cmnd *, int, int);
+STATIC Scsi_Cmnd 	*asc_dequeue(struct Scsi_Host *, int);
+STATIC int 			asc_rmqueue(struct Scsi_Host *, Scsi_Cmnd *, int);
+
+/* XXX - Asc Library Routines not supposed to be used directly */
+ushort 			AscGetChipBiosAddress(PortAddr, ushort);
+int             AscFindSignature(PortAddr);
+
+#ifdef ADVANSYS_STATS
+STATIC int		asc_prt_stats(char *, int);
+STATIC int		asc_prt_stats_line(char *, int, char *fmt, ...);
+#endif /* ADVANSYS_STATS */
+#ifdef ADVANSYS_DEBUG
+STATIC void 	asc_prt_scsi_host(struct Scsi_Host *);
+STATIC void 	asc_prt_dvc_cfg(ASC_DVC_CFG *);
+STATIC void 	asc_prt_dvc_var(ASC_DVC_VAR *);
+STATIC void 	asc_prt_scsi_q(ASC_SCSI_Q *);
+STATIC void 	asc_prt_qdone_info(ASC_QDONE_INFO *);
+STATIC void 	asc_prt_hex(char *f, uchar *, int);
+STATIC int 		interrupts_enabled(void);
+#endif /* ADVANSYS_DEBUG */
+
+
+/*
+ * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions
+ */
+
+#ifdef LINUX_1_3
+/*
+ * advansys_proc_info() - /proc/scsi/advansys/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset into /proc/scsi/advansys file
+ * 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 to
+ * /proc/scsi/advansys file.
+ */
+int
+advansys_proc_info(char *buffer, char **start, off_t offset, int length, 
+				   int hostno, int inout)
+{
+	struct Scsi_Host	*shp;
+	int					i;
+	char				*cp;
+	int					cplen;
+	int					cnt;
+	int					totcnt;
+	int					leftlen;
+	char				*curbuf;
+	off_t				advoffset;
+    Scsi_Device			*scd;
+	char				prtbuf[480];	/* 6 lines */
+
+	ASC_DBG(1, "advansys_proc_info: begin\n");
+
+	/*
+	 * User write not supported.
+	 */
+	if (inout == TRUE) {
+		return(-ENOSYS);
+	}
+
+	/*
+	 * User read of /proc/scsi/advansys file.
+	 */
+
+	/* Find the specified board. */
+	for (i = 0; i < asc_board_count; i++) {
+		if (asc_host[i]->host_no == hostno) {
+			break;
+		}
+	}
+	if (i == asc_board_count) {
+		return(-ENOENT);
+	}
+	shp = asc_host[i];
+
+	/* Always copy read data to the beginning of the buffer. */
+	*start = buffer;
+
+	curbuf = buffer;
+	advoffset = 0;
+	totcnt = 0;
+	leftlen = length;
+
+	/* Get board information. */
+	cp = (char *) advansys_info(shp);
+	strcat(cp, "\n");
+	cplen = strlen(cp);
+
+	/* Copy board information. */
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
+
+	/*
+	 * Get and copy information for each device attached to the board.
+	 */
+	cp = &prtbuf[0];
+	sprintf(cp, "\nDevices attached to SCSI Host %d:\n", shp->host_no);
+	cplen = strlen(cp);
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
+
+	cp = &prtbuf[0];
+    for (scd = scsi_devices; scd; scd = scd->next) {
+		if (scd->host == shp) {
+	    	proc_print_scsidevice(scd, cp, &cplen, 0);
+			cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+			totcnt += cnt;
+			leftlen -= cnt;
+			if (leftlen == 0) {
+				ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+				return totcnt;
+			}
+			advoffset += cplen;
+			curbuf += cnt;
+		}
+    }
+    
+#ifdef ADVANSYS_STATS
+	/*
+	 * prtbuf[] has about 6 lines worth of space. If the statistics ever
+	 * get longer than 6 lines, prtbuf[] should be increased in size. If
+	 * prtbuf[] is too small it will not be overwritten. Instead the user
+	 * just won't get all of the available statistics.
+	 */
+	cp = &prtbuf[0];
+	cplen = asc_prt_stats(cp, sizeof(prtbuf));
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
+#endif /* ADVANSYS_STATS */
+
+	ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+
+	return totcnt;
+}
+#endif /* LINUX_1_3 */
+
+
+/*
+ * advansys_detect()
+ *
+ * Detect function for AdvanSys adapters.
+ *
+ * Argument is a pointer to the host driver's scsi_hosts entry.
+ *
+ * Return number of adapters found.
+ *
+ * Note: Because this function is called during system initialization
+ * it must not call SCSI mid-level functions including scsi_malloc()
+ * and scsi_free().
+ */
+int
+advansys_detect(Scsi_Host_Template *tpnt)
+{
+	static int			detect_called = ASC_FALSE;
+	int					iop;
+	int					bus;
+	struct Scsi_Host	*shp;
+	ASC_DVC_VAR			*boardp;
+	int					ioport = 0;
+	PCI_DEVICE			pciDevice;
+	PCI_CONFIG_SPACE	pciConfig;
+	int					ret;
+	extern PortAddr		_asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX];
+
+
+	if (detect_called == ASC_FALSE) {
+		detect_called = ASC_TRUE;
+	} else {
+		printk("AdvanSys SCSI: advansys_detect() mulitple calls ignored\n");
+		return 0;
+	}
+
+	ASC_DBG(1, "advansys_detect: begin\n");
+
+#ifdef LINUX_1_3
+	tpnt->proc_dir = &proc_scsi_advansys;
+#endif /* LINUX_1_3 */
+
+#ifdef ADVANSYS_STATS
+	memset(&asc_stats, 0, sizeof(asc_stats));
+#endif /* ADVANSYS_STATS */
+
+	asc_board_count = 0;
+
+	/*
+	 * If I/O port probing has been modified, then verify and
+	 * clean-up the 'asc_ioport' list.
+	 */
+	if (asc_iopflag == ASC_TRUE) {
+		for (ioport = 0; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) {
+			ASC_DBG2(1, "asdvansys_detect: asc_ioport[%d] %x\n",
+				ioport, asc_ioport[ioport]);
+			if (asc_ioport[ioport] != 0) {
+				for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) {
+					if (_asc_def_iop_base[iop] == asc_ioport[ioport]) {
+						break;
+					}
+				}
+				if (iop == ASC_IOADR_TABLE_MAX_IX) {
+					printk("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
+						asc_ioport[ioport]);
+					asc_ioport[ioport] = 0;
+				}
+			}
+		}
+		ioport = 0;
+	}
+
+	memset(&pciDevice, 0, sizeof(PCI_DEVICE));
+	memset(&pciConfig, 0, sizeof(PCI_CONFIG_SPACE));
+	pciDevice.maxBusNumber = PCI_MAX_BUS;
+	pciDevice.endSlot = PCI_MAX_SLOT;
+
+	for (bus = 0; bus < ASC_NUM_BUS; bus++) {
+
+		ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
+			bus, asc_bus_name[bus]);
+		iop = 0;
+
+		while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
+
+			ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
+				asc_board_count);
+
+			switch (asc_bus[bus]) {
+			case ASC_IS_ISA:
+			case ASC_IS_VL:
+				if (asc_iopflag == ASC_FALSE) {
+					iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+				} else {
+					/*
+					 * ISA and VL I/O port scanning has either been
+					 * eliminated or limited to selected ports on
+					 * the LILO command line, /etc/lilo.conf, or
+					 * by setting variables when the module was loaded.
+					 */
+					ASC_DBG(1, "advansys_detect: I/O port scanning modified\n");
+				ioport_try_again:
+					iop = 0;
+					for (; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) {
+						if ((iop = asc_ioport[ioport]) != 0) {
+							break;
+						}
+					}
+					if (iop) {
+						ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n",
+							iop);
+						if (check_region(iop, ASC_IOADR_GAP) != 0) {
+							printk("AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
+							/* Don't try this I/O port twice. */
+							asc_ioport[ioport] = 0;
+							goto ioport_try_again;
+						} else if (AscFindSignature(iop) == ASC_FALSE) {
+							printk("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
+							/* Don't try this I/O port twice. */
+							asc_ioport[ioport] = 0;
+							goto ioport_try_again;
+						} else {
+							/*
+							 * If this isn't an ISA board, then it must be
+							 * a VL board. If currently looking an ISA
+							 * board is being looked for then try for
+							 * another ISA board in 'asc_ioport'.
+							 */
+							if (asc_bus[bus] == ASC_IS_ISA &&
+							    (AscGetChipVersion(iop, ASC_IS_ISA) &
+								 ASC_CHIP_VER_ISA_BIT) == 0) {
+							 	/*
+								 * Don't clear 'asc_ioport[ioport]'. Try
+								 * this board again for VL. Increment
+								 * 'ioport' past this board.
+								 */
+								 ioport++;
+								 goto ioport_try_again;
+							}
+						}
+						/*
+						 * This board appears good, don't try the I/O port
+						 * again by clearing its value. Increment 'ioport'
+						 * for the next iteration.
+						 */
+						asc_ioport[ioport++] = 0;
+					}
+				}
+				break;
+
+			case ASC_IS_EISA:
+				iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+				break;
+
+			case ASC_IS_PCI:
+					if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) {
+						iop = 0;
+					} else {
+						ASC_DBG2(2,
+							"advansys_detect: slotFound %d, busNumber %d\n",
+							pciDevice.slotFound, pciDevice.busNumber);
+						asc_get_pci_cfg(&pciDevice, &pciConfig);
+						iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK;
+						ASC_DBG2(2, "advansys_detect: iop %x, irqLine %d\n",
+							iop, pciConfig.irqLine);
+					}
+				break;
+
+			default:
+				ASC_DBG(0, "advansys_detect: unknown bus type\n");
+				break;
+			}
+			ASC_DBG1(1, "advansys_detect: iop %x\n", iop);
+
+			/*
+			 * Adapter not found, try next bus type.
+			 */
+			if (iop == 0) {
+				break;
+			}
+
+			/*
+			 * Adapter found.
+			 *
+			 * Register the adapter, get its configuration, and
+			 * initialize it.
+			 */
+			ASC_DBG(2, "advansys_detect: scsi_register()\n");
+			shp = scsi_register(tpnt, sizeof(struct asc_board));
+
+			/* Save a pointer to the Scsi_host of each found board. */
+			asc_host[asc_board_count++] = shp;
+
+			/* Initialize private per board data */
+			memset(ASC_BOARD(shp), 0, sizeof(struct asc_board));
+			boardp = &ASC_BOARD(shp)->board;
+			boardp->cfg = &ASC_BOARD(shp)->cfg;
+			boardp->cfg->overrun_buf = &ASC_BOARD(shp)->overrun_buf[0];
+			boardp->iop_base = iop;
+
+			/*
+			 * Set the board bus type and PCI IRQ for AscInitGetConfig().
+			 */
+			boardp->bus_type = asc_bus[bus];
+			switch (boardp->bus_type) {
+			case ASC_IS_ISA:
+				shp->unchecked_isa_dma = TRUE;
+				break;
+			case ASC_IS_EISA:
+				shp->unchecked_isa_dma = FALSE;
+				break;
+			case ASC_IS_VL:
+				shp->unchecked_isa_dma = FALSE;
+				break;
+			case ASC_IS_PCI:
+				shp->irq = boardp->irq_no = pciConfig.irqLine;
+				boardp->cfg->pci_device_id = pciConfig.deviceID;
+				shp->unchecked_isa_dma = FALSE;
+				break;
+			default:
+				ASC_DBG(0, "advansys_detect: unknown adapter type");
+				shp->unchecked_isa_dma = TRUE;
+				break;
+			}
+
+			/*
+			 * Get the board configuration.  AscInitGetConfig() may change
+			 * the board's bus_type value. The asc_bus[bus] value should no
+			 * longer be used.
+			 */
+			ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
+			switch(ret = AscInitGetConfig(boardp)) {
+			case 0:	/* No error */
+				break;
+			case ASC_WARN_IO_PORT_ROTATE:
+				ASC_DBG(0, "AscInitGetConfig: I/O port address modified\n");
+				break;
+			case ASC_WARN_EEPROM_CHKSUM:
+				ASC_DBG(0, "AscInitGetConfig: EEPROM checksum error\n");
+				break;
+			case ASC_WARN_IRQ_MODIFIED:
+				ASC_DBG(0, "AscInitGetConfig: IRQ modified\n");
+				break;
+			case ASC_WARN_CMD_QNG_CONFLICT:
+				ASC_DBG(0,
+					"AscInitGetConfig: Tag queuing enabled w/o disconnects\n");
+				break;
+			default:
+				ASC_DBG1(0, "AscInitGetConfig: Unknown warning: %x\n", ret);
+				break;
+			}
+			if (boardp->err_code != 0) {
+				ASC_DBG2(0,
+					"AscInitGetConfig: error: init_state %x, err_code %x\n",
+					boardp->init_state, boardp->err_code);
+				scsi_unregister(shp);
+				asc_board_count--;
+				continue;
+			}
+
+			/*
+			 * Modify board configuration.
+			 */
+			boardp->isr_callback = (Ptr2Func) asc_isr_callback;
+			boardp->exe_callback = (Ptr2Func) NULL;
+
+			ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n");
+			switch (ret = AscInitSetConfig(boardp)) {
+			case 0:	/* No error. */
+				break;
+			case ASC_WARN_IO_PORT_ROTATE:
+				ASC_DBG(0, "AscInitSetConfig: I/O port address modified\n");
+				break;
+			case ASC_WARN_EEPROM_CHKSUM:
+				ASC_DBG(0, "AscInitSetConfig: EEPROM checksum error\n");
+				break;
+			case ASC_WARN_IRQ_MODIFIED:
+				ASC_DBG(0, "AscInitSetConfig: IRQ modified\n");
+				break;
+			case ASC_WARN_CMD_QNG_CONFLICT:
+				ASC_DBG(0, "AscInitSetConfig: Tag queuing w/o disconnects\n");
+				break;
+			default:
+				ASC_DBG1(0, "AscInitSetConfig: Unknown warning: %x\n", ret);
+				break;
+			}
+			if (boardp->err_code != 0) {
+				ASC_DBG2(0,
+					"AscInitSetConfig: error: init_state %x, err_code %x\n",
+					boardp->init_state, boardp->err_code);
+				scsi_unregister(shp);
+				asc_board_count--;
+				continue;
+			}
+
+			/*
+			 * Finish initializing the 'Scsi_Host' structure.
+			 */
+
+			/* AscInitSetConfig() will set the IRQ for non-PCI boards. */
+			if (boardp->bus_type != ASC_IS_PCI) {
+				shp->irq = boardp->irq_no;
+			}
+
+			shp->io_port = boardp->iop_base;
+			shp->n_io_port = ASC_IOADR_GAP;
+			shp->this_id = boardp->cfg->chip_scsi_id;
+
+			/* Maximum number of queues this adapter can handle. */
+			shp->can_queue = boardp->max_total_qng;
+
+			/*
+			 * XXX - Command queuing limits are maintained per target
+			 * by AdvanSys adapters. Set 'cmd_per_lun' to the minimum
+			 * value of the all the target settings for the adapter.
+			 *
+			 * For now set 'cmd_per_lun' to 'max_total_qng'. This
+			 * value should be adjusted every time a new device is
+			 * found in asc_init_dev().
+			 *
+			 * XXX - memory allocation is done by the mid-level scsi
+			 * driver based on 'cmd_per_lun'. If 'sg_tablesize' is too large
+			 * allocation failures can occur in scsi_register_host().
+			 * A 'Scsi_Cmnd' structure is pre-allocated for each command
+			 * also DMA memory is reserved. Set it artificially low for now.
+			 *
+			 * shp->cmd_per_lun = boardp->max_total_qng;
+			 */
+#ifdef MODULE
+			shp->cmd_per_lun = 1;
+#else /* MODULE */
+			shp->cmd_per_lun = 4;
+#endif /* MODULE */
+			ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun);
+			
+			/* Maximum number of scatter-gather elements adapter can handle. */
+			/*
+			 * XXX - memory allocation is done by the mid-level scsi
+			 * driver based on sg_tablesize. If 'sg_tablesize' is too large
+			 * allocation failures can occur in scsi_register_host().
+			 */
+#ifdef MODULE
+			shp->sg_tablesize = 8;
+#else /* MODULE */
+			shp->sg_tablesize = ASC_MAX_SG_LIST;
+#endif /* MODULE */
+			ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
+				shp->sg_tablesize);
+
+			/* BIOS start address. */
+			shp->base = (char *) ((ulong) AscGetChipBiosAddress(
+												boardp->iop_base,
+												boardp->bus_type));
+
+			/*
+			 * Register Board Resources - I/O Port, DMA, IRQ
+			 */
+
+			/* Register I/O port range */
+			ASC_DBG(2, "advansys_detect: request_region()\n");
+			request_region(shp->io_port, shp->n_io_port, "advansys");
+
+			/* Register DMA channel for ISA bus. */
+			if ((boardp->bus_type & ASC_IS_ISA) == 0) {
+				shp->dma_channel = NO_ISA_DMA;
+			} else {
+				shp->dma_channel = boardp->cfg->isa_dma_channel;
+				if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) {
+					ASC_DBG2(0, "advansys_detect: request_dma() %d failed %d\n",
+						shp->dma_channel, ret);
+					release_region(shp->io_port, shp->n_io_port);
+					scsi_unregister(shp);
+					asc_board_count--;
+					continue;
+				}
+				AscEnableIsaDma(shp->dma_channel);
+			}
+
+			/* Register IRQ Number. */
+			ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
+			if ((ret = request_irq(shp->irq, advansys_interrupt,
+								SA_INTERRUPT, "advansys")) != 0) {
+				ASC_DBG1(0, "advansys_detect: request_irq() failed %d\n", ret);
+				release_region(shp->io_port, shp->n_io_port);
+				if (shp->dma_channel != NO_ISA_DMA) {
+					free_dma(shp->dma_channel);
+				}
+				scsi_unregister(shp);
+				asc_board_count--;
+				continue;
+			}
+
+			/*
+			 * Initialize board RISC chip and enable interrupts.
+			 */
+			ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
+			if (AscInitAsc1000Driver(boardp)) {
+				ASC_DBG2(0,
+					"AscInitAsc1000Driver: error: init_state %x, err_code %x\n",
+					boardp->init_state, boardp->err_code);
+				release_region(shp->io_port, shp->n_io_port);
+				if (shp->dma_channel != NO_ISA_DMA) {
+					free_dma(shp->dma_channel);
+				}
+				free_irq(shp->irq);
+				scsi_unregister(shp);
+				asc_board_count--;
+				continue;
+			}
+			ASC_DBG_PRT_SCSI_HOST(2, shp);
+		}
+	}
+
+	ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
+	return asc_board_count;
+}
+
+/*
+ * advansys_release()
+ *
+ * Release resources allocated for a single AdvanSys adapter.
+ */
+int
+advansys_release(struct Scsi_Host *shp)
+{
+	ASC_DBG(1, "advansys_release: begin\n");
+	free_irq(shp->irq);
+	if (shp->dma_channel != NO_ISA_DMA) {
+		ASC_DBG(1, "advansys_release: free_dma()\n");
+		free_dma(shp->dma_channel);
+	}
+	release_region(shp->io_port, shp->n_io_port);
+	scsi_unregister(shp);
+	ASC_DBG(1, "advansys_release: end\n");
+	return 0;
+}
+
+/*
+ * advansys_info()
+ *
+ * Return suitable for printing on the console with the argument
+ * adapter's configuration information.
+ */
+const char *
+advansys_info(struct Scsi_Host *shp)
+{
+	static char 	info[128];
+	ASC_DVC_VAR		*boardp;
+	char			*busname;
+
+	boardp = &ASC_BOARD(shp)->board;
+	ASC_DBG(1, "advansys_info: begin\n");
+	if (boardp->bus_type & ASC_IS_ISA) {
+		sprintf(info,
+			"AdvanSys SCSI %s: ISA (%u CDB): BIOS %X, IO %X-%X, IRQ %u, DMA %u",
+			ASC_VERSION, ASC_BOARD(shp)->board.max_total_qng,
+			(unsigned) shp->base, shp->io_port,
+			shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel);
+	} else {
+		switch (boardp->bus_type) {
+		case ASC_IS_EISA:
+			busname = "EISA";
+			break;
+		case ASC_IS_VL:
+			busname = "VL";
+			break;
+		case ASC_IS_PCI:
+			busname = "PCI";
+			break;
+		default:
+			busname = "?";
+			ASC_DBG1(0, "advansys_info: unknown bus type %d\n",
+				boardp->bus_type);
+			break;
+		}
+		/* No DMA channel for non-ISA busses. */
+		sprintf(info,
+			"AdvanSys SCSI %s: %s (%u CDB): BIOS %X, IO %X-%X, IRQ %u",
+			ASC_VERSION, busname, ASC_BOARD(shp)->board.max_total_qng,
+			(unsigned) shp->base, shp->io_port,
+			shp->io_port + (shp->n_io_port - 1), shp->irq);
+	}
+	ASC_DBG(1, "advansys_info: end\n");
+	return info;
+}
+
+/*
+ * advansys_command()
+ *
+ * Polled-I/O. Apparently host driver shouldn't return until
+ * command is finished.
+ *
+ * XXX - Can host driver block here instead of spinning on command status?
+ */
+int
+advansys_command(Scsi_Cmnd *scp)
+{
+	ASC_DBG1(1, "advansys_command: scp %x\n", (unsigned) scp);
+	ASC_STATS(command);
+	scp->SCp.Status = 0; /* Set to a known state */
+	advansys_queuecommand(scp, advansys_command_done);
+	while (scp->SCp.Status == 0) {
+		continue;
+	}
+	ASC_DBG1(1, "advansys_command: result %x\n", scp->result);
+	return scp->result;
+}
+
+/*
+ * advansys_queuecommand()
+ *
+ * This function always returns 0. Command return status is saved
+ * in the 'scp' result field.
+ */
+int
+advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
+{
+	struct Scsi_Host		*shp;
+	int						flags = 0;
+	int						interrupts_disabled;
+
+	ASC_STATS(queuecommand);
+	shp = scp->host;
+
+#ifdef LINUX_1_2
+	/*
+	 * For LINUX_1_3, if statistics are enabled they can be accessed
+	 * by reading /proc/scsi/advansys/[0-9].
+	 */
+#ifdef ADVANSYS_STATS_1_2_PRINT
+	/* Display statistics every 10000 commands. */
+	if ((asc_stats.queuecommand % 10000) == 0) {
+		printk("\n");
+		(void) asc_prt_stats(NULL, 0);
+		printk("\n");
+	}
+#endif /* ADVANSYS_STATS_1_2_PRINT */
+#endif /* LINUX_1_2 */
+
+	/*
+	 * If there are any pending commands for this board before trying
+	 * to execute them, disable interrupts to preserve request ordering.
+	 *
+	 * The typical case will be no pending commands and interrupts
+	 * not disabled.
+	 */
+	if (ASC_BOARD(shp)->pending_tidmask == 0) {
+		interrupts_disabled = ASC_FALSE;
+	} else {
+		ASC_STATS(cmd_disable);
+		/* Disable interrupts */
+		interrupts_disabled = ASC_TRUE;
+		save_flags(flags);
+		cli();
+		ASC_DBG1(1, "advansys_queuecommand: asc_execute_pending() %x\n",
+			ASC_BOARD(shp)->pending_tidmask);
+		asc_execute_pending(shp);
+	}
+
+	/*
+	 * Save the function pointer to Linux mid-level 'done' function and
+	 * execute the command.
+	 */
+	scp->scsi_done = done;
+	if (asc_execute_scsi_cmnd(scp) == ASC_BUSY) {
+		if (interrupts_disabled == ASC_FALSE) {
+			save_flags(flags);
+			cli();
+			interrupts_disabled = ASC_TRUE;
+		}
+		asc_enqueue(shp, scp, scp->target, ASC_BACK);
+	}
+
+	if (interrupts_disabled == ASC_TRUE) {
+		restore_flags(flags);
+	}
+
+	return 0;
+}
+
+/*
+ * advansys_abort()
+ *
+ * Abort the specified command and reset the device
+ * associated with the command 'scp'.
+ */
+int
+advansys_abort(Scsi_Cmnd *scp)
+{
+	ASC_DVC_VAR		*boardp;
+	int				flags;
+	int				ret;
+
+	ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp);
+	save_flags(flags);
+	cli();
+	ASC_STATS(abort);
+	if (scp->host == NULL) {
+		scp->result = HOST_BYTE(DID_ERROR);
+		ret = SCSI_ABORT_ERROR;
+	} else if (asc_rmqueue(scp->host, scp, scp->target) == ASC_TRUE) {
+		scp->result = HOST_BYTE(DID_ABORT);
+		ret = SCSI_ABORT_SUCCESS;
+		(void) AscResetDevice(&ASC_BOARD(scp->host)->board, scp->target);
+	} else {
+		/* Must enable interrupts for AscAbortSRB() */
+		sti();
+		boardp = &ASC_BOARD(scp->host)->board;
+		scp->result = HOST_BYTE(DID_ABORT);
+		switch (AscAbortSRB(boardp, (ulong) scp)) {
+		case ASC_TRUE:
+			/* asc_isr_callback() will be called */
+			ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
+			ret = SCSI_ABORT_PENDING;
+			break;
+		case ASC_FALSE:
+			/* Request has apparently already completed. */
+			ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n");
+			ret = SCSI_ABORT_NOT_RUNNING;
+			break;
+		case ASC_ERROR:
+		default:
+			ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n");
+			ret = SCSI_ABORT_ERROR;
+			break;
+		}
+		(void) AscResetDevice(boardp, scp->target);
+	}
+	restore_flags(flags);
+	ASC_DBG1(1, "advansys_abort: ret %d\n", ret);
+	return ret;
+}
+
+/*
+ * advansys_reset()
+ *
+ * Reset all devices and the SCSI bus for the board
+ * associated with 'scp'.
+ */
+int
+advansys_reset(Scsi_Cmnd *scp)
+{
+	ASC_DVC_VAR		*boardp;
+	int				flags;
+	Scsi_Cmnd		*tscp;
+	int				i;
+	int				ret;
+
+	ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp);
+	save_flags(flags);
+	cli();
+	ASC_STATS(reset);
+	if (scp->host == NULL) {
+		scp->result = HOST_BYTE(DID_ERROR);
+		ret = SCSI_RESET_ERROR;
+	} else {
+		/* Remove any pending commands, set DID_RESET, and done them.  */
+		for (i = 0; i < ASC_MAX_TID; i++) {
+			while ((tscp = asc_dequeue(scp->host, i)) != NULL) {
+				tscp->result = HOST_BYTE(DID_RESET);
+				tscp->scsi_done(tscp);
+			}
+		}
+		/* Must enable interrupts for AscResetSB() */
+		sti();
+		boardp = &ASC_BOARD(scp->host)->board;
+		scp->result = HOST_BYTE(DID_RESET);
+		switch (AscResetSB(boardp)) {
+		case ASC_TRUE:
+			ASC_DBG(1, "advansys_abort: AscResetSB() TRUE\n");
+			ret = SCSI_RESET_SUCCESS;
+			break;
+		case ASC_ERROR:
+		default:
+			ASC_DBG(1, "advansys_abort: AscResetSB() ERROR\n");
+			ret = SCSI_RESET_ERROR;
+			break;
+		}
+	}
+	restore_flags(flags);
+	ASC_DBG1(1, "advansys_reset: ret %d", ret);
+	return ret;
+}
+
+/*
+ * advansys_biosparam()
+ *
+ * Translate disk drive geometry if the "BIOS greater than 1 GB"
+ * support is enabled for a drive.
+ *
+ * ip (information pointer) is an int array with the following definition:
+ * ip[0]: heads
+ * ip[1]: sectors
+ * ip[2]: cylinders
+ */
+int
+#ifdef LINUX_1_2
+advansys_biosparam(Disk *dp, int dep, int ip[])
+#else /* LINUX_1_3 */
+advansys_biosparam(Disk *dp, kdev_t dep, int ip[])
+#endif /* LINUX_1_3 */
+{
+	ASC_DBG(1, "advansys_biosparam: begin\n");
+	ASC_STATS(biosparam);
+	if ((ASC_BOARD(dp->device->host)->board.dvc_cntl & ASC_CNTL_BIOS_GT_1GB) &&
+		dp->capacity > 0x200000) {
+			ip[0] = 255;
+			ip[1] = 64;
+	} else {
+			ip[0] = 64;
+			ip[1] = 32;
+	}
+	ip[2] = dp->capacity / (ip[0] * ip[1]);
+	ASC_DBG(1, "advansys_biosparam: end\n");
+	return 0;
+}
+
+/*
+ * advansys_setup()
+ *
+ * This function is called from init/main.c at boot time.
+ * It it passed LILO parameters that can be set from the
+ * LILO command line or in /etc/lilo.conf.
+ *
+ * It is used by the AdvanSys driver to either disable I/O
+ * port scanning or to limit scanning to 1 - 4 I/O ports.
+ * Regardless of the option setting EISA and PCI boards
+ * will still be searched for and detected. This option
+ * only affects searching for ISA and VL boards.
+ *
+ * If ADVANSYS_DEBUG is defined the driver debug level may
+ * be set using the 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port.
+ *
+ * Examples:
+ * 1. Eliminate I/O port scanning:
+ * 		boot: linux advansys=
+ *       or
+ * 		boot: linux advansys=0x0
+ * 2. Limit I/O port scanning to one I/O port:
+ *		boot: linux advansys=0x110
+ * 3. Limit I/O port scanning to four I/O ports:
+ *		boot: linux advansys=0x110,0x210,0x230,0x330
+ * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and
+ *    set the driver debug level to 2.
+ *		boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2
+ *
+ * ints[0] - number of arguments
+ * ints[1] - first argument
+ * ints[2] - second argument
+ * ...
+ */
+void
+advansys_setup(char *str, int *ints)
+{
+	int	i;
+
+	if (asc_iopflag == ASC_TRUE) {
+		printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n");
+		return;
+	}
+
+	asc_iopflag = ASC_TRUE;
+
+	if (ints[0] > ASC_NUM_BOARD_SUPPORTED) {
+#ifdef ADVANSYS_DEBUG
+		if ((ints[0] == ASC_NUM_BOARD_SUPPORTED + 1) &&
+		    (ints[ASC_NUM_BOARD_SUPPORTED + 1] >> 4 == 0xdeb)) {
+			asc_dbglvl = ints[ASC_NUM_BOARD_SUPPORTED + 1] & 0xf;
+		} else {
+#endif /* ADVANSYS_DEBUG */
+			printk("AdvanSys SCSI: only %d I/O ports accepted\n",
+				ASC_NUM_BOARD_SUPPORTED);
+#ifdef ADVANSYS_DEBUG
+		}
+#endif /* ADVANSYS_DEBUG */
+	}
+
+#ifdef ADVANSYS_DEBUG
+	ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]);
+	for (i = 1; i < ints[0]; i++) {
+		ASC_DBG2(1, " ints[%d] %x", i, ints[i]);
+	}
+	ASC_DBG(1, "\n");
+#endif /* ADVANSYS_DEBUG */
+
+	for (i = 1; i <= ints[0] && i <= ASC_NUM_BOARD_SUPPORTED; i++) {
+		asc_ioport[i-1] = ints[i];
+		ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n",
+			i - 1, asc_ioport[i-1]);
+	}
+}
+
+
+/*
+ * --- Loadable Driver Support
+ */
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = ADVANSYS;
+# include "scsi_module.c"
+#endif /* MODULE */
+
+
+/*
+ * --- Miscellaneous Driver Functions
+ */
+
+#ifdef LINUX_1_3
+/*
+ * asc_proc_copy() 
+ *
+ * Copy proc information to a read buffer considering the current read
+ * offset in the file and the remaining space in the read buffer.
+ */
+STATIC int
+asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
+			  char *cp, int cplen)
+{
+	int cnt = 0;
+	
+	ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
+			(unsigned) offset, (unsigned) advoffset, cplen);
+	if (offset <= advoffset) {
+		/* Read offset below current offset, copy everything. */
+		cnt = min(cplen, leftlen);
+		ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n",
+				(unsigned) curbuf, (unsigned) cp, cnt);
+		memcpy(curbuf, cp, cnt);
+	} else if (offset < advoffset + cplen) {
+		/* Read offset within current range, partial copy. */
+		cnt = (advoffset + cplen) - offset;
+		cp = (cp + cplen) - cnt;
+		cnt = min(cnt, leftlen);
+		ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n",
+				(unsigned) curbuf, (unsigned) cp, cnt);
+		memcpy(curbuf, cp, cnt);
+	}
+	return cnt;
+}
+#endif /* LINUX_1_3 */
+
+/*
+ * First-level interrupt handler.
+ */
+STATIC void
+advansys_interrupt(int irq, struct pt_regs *regs)
+{
+	int			i;
+	int			flags;
+	Scsi_Cmnd	*scp;
+	Scsi_Cmnd	*tscp;
+
+	/* Disable interrupts, if the aren't already disabled. */
+	save_flags(flags);
+	cli();
+
+	ASC_DBG(1, "advansys_interrupt: begin\n");
+	ASC_STATS(interrupt);
+	/*
+	 * Check for interrupts on all boards.
+	 * AscISR() will call asc_isr_callback().
+	 */
+	for (i = 0; i < asc_board_count; i++) {
+		while (AscIsIntPending(asc_host[i]->io_port)) {
+			ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
+			AscISR(&ASC_BOARD(asc_host[i])->board);
+		}
+	}
+	ASC_DBG(1, "advansys_interrupt: end\n");
+
+	/*
+	 * While interrupts are still disabled save the list of requests that
+	 * need their done function called. After re-enabling interrupts call
+	 * the done function which may re-enable interrupts anyway.
+	 */
+	if ((scp = asc_scsi_done) != NULL) {
+		asc_scsi_done = NULL;
+	}
+
+	/* Re-enable interrupts, if they were enabled on entry. */
+	restore_flags(flags);
+
+	while (scp) {
+		tscp = (Scsi_Cmnd *) scp->host_scribble;
+		scp->scsi_done(scp);
+		scp = tscp;
+	}
+
+	return;
+}
+
+/*
+ * Function used only with polled I/O requests that are initiated by
+ * advansys_command().
+ */
+STATIC void
+advansys_command_done(Scsi_Cmnd *scp)
+{
+	ASC_DBG1(1, "advansys_command_done: scp %x\n", (unsigned) scp);
+	scp->SCp.Status = 1;
+}
+
+/*
+ * Execute a single 'Scsi_Cmnd'.
+ *
+ * The function 'done' is called when the request has been completed.
+ *
+ * Scsi_Cmnd:
+ *
+ *  host - board controlling device
+ *  device - device to send command
+ *  target - target of device
+ *  lun - lun of device
+ *  cmd_len - length of SCSI CDB
+ *	cmnd - buffer for SCSI 8, 10, or 12 byte CDB
+ *  use_sg - if non-zero indicates scatter-gather request with use_sg elements
+ *
+ *  if (use_sg == 0)
+ *		request_buffer - buffer address for request
+ *		request_bufflen - length of request buffer
+ *  else
+ *		request_buffer - pointer to scatterlist structure
+ *
+ *  sense_buffer - sense command buffer
+ *
+ *  result (4 bytes of an int):
+ *   Byte Meaning
+ *   0	  SCSI Status Byte Code
+ *   1	  SCSI One Byte Message Code
+ *   2 	  Host Error Code
+ *   3	  Mid-Level Error Code
+ *
+ *  host driver fields:
+ *  SCp - Scsi_Pointer used for command processing status
+ *  scsi_done - used to save caller's done function
+ * 	host_scribble - used for pointer to another Scsi_Cmnd
+ *
+ * If this function returns ASC_NOERROR or ASC_ERROR the done
+ * function has been called. If ASC_BUSY is returned the request
+ * must be enqueued by the caller and re-tried later.
+ */
+STATIC int
+asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
+{
+	ASC_DVC_VAR		*boardp;
+	ASC_SCSI_Q		scsiq;
+	ASC_SG_HEAD		sghead;
+	int				ret;
+
+	ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n",
+		(unsigned) scp, (unsigned) scp->scsi_done);
+
+	boardp = &ASC_BOARD(scp->host)->board;
+
+	/*
+	 * If this is the first command, then initialize the device. If
+	 * no device is found set 'DID_BAD_TARGET' and return.
+	 */
+	if ((ASC_BOARD(scp->host)->init_tidmask &
+		 ASC_TIX_TO_TARGET_ID(scp->target)) == 0) {
+		if (asc_init_dev(boardp, scp) == ASC_FALSE) {
+			scp->result = HOST_BYTE(DID_BAD_TARGET);
+			scp->scsi_done(scp);
+			return ASC_ERROR;
+		}
+		ASC_BOARD(scp->host)->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target);
+	}
+
+	memset(&scsiq, 0, sizeof(ASC_SCSI_Q));
+
+	/*
+	 * Point the ASC_SCSI_Q to the 'Scsi_Cmnd'.
+	 */
+	scsiq.q2.srb_ptr = (ulong) scp;
+
+	/*
+	 * Build the ASC_SCSI_Q request.
+	 */
+	scsiq.cdbptr = &scp->cmnd[0];
+	scsiq.q2.cdb_len = scp->cmd_len;
+	scsiq.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+	scsiq.q1.target_lun = scp->lun;
+	scsiq.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
+	scsiq.q1.sense_addr = (ulong) &scp->sense_buffer[0];
+	scsiq.q1.sense_len = sizeof(scp->sense_buffer);
+	scsiq.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+
+	/*
+	 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
+	 * buffer command.
+	 */
+	if (scp->use_sg == 0) {
+		/*
+		 * CDB request of single contiguous buffer.
+		 */
+		ASC_STATS(cont_cnt);
+ 		/* request_buffer is already a real address. */
+		scsiq.q1.data_addr = (ulong) scp->request_buffer;
+		scsiq.q1.data_cnt = scp->request_bufflen;
+		ASC_STATS_ADD(cont_xfer, (scp->request_bufflen + 511) >> 9);
+		scsiq.q1.sg_queue_cnt = 0;
+		scsiq.sg_head = NULL;
+	} else {
+		/*
+		 * CDB scatter-gather request list.
+		 */
+		int					sgcnt;
+		struct scatterlist	*slp;
+
+		if (scp->use_sg > ASC_MAX_SG_LIST) {
+			ASC_DBG2(0, "asc_execute_scsi_cmnd: use_sg %d > %d\n",
+				scp->use_sg, ASC_MAX_SG_LIST);
+			scp->result = HOST_BYTE(DID_ERROR);
+			scp->scsi_done(scp);
+			return ASC_ERROR;
+		}
+
+		ASC_STATS(sg_cnt);
+
+		/*
+		 * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q
+		 * to point to it.
+		 */
+		memset(&sghead, 0, sizeof(ASC_SG_HEAD));
+
+		scsiq.q1.cntl |= QC_SG_HEAD;
+		scsiq.sg_head = &sghead;
+		scsiq.q1.data_cnt = 0;
+		scsiq.q1.data_addr = 0;
+		sghead.entry_cnt = scsiq.q1.sg_queue_cnt = scp->use_sg;
+		ASC_STATS_ADD(sg_elem, sghead.entry_cnt);
+
+		/*
+		 * Convert scatter-gather list into ASC_SG_HEAD list.
+		 */
+		slp = (struct scatterlist *) scp->request_buffer;
+		for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
+			sghead.sg_list[sgcnt].addr = (ulong) slp->address;
+			sghead.sg_list[sgcnt].bytes = slp->length;
+			ASC_STATS_ADD(sg_xfer, (slp->length + 511) >> 9);
+		}
+	}
+
+	ASC_DBG_PRT_SCSI_Q(2, &scsiq);
+	ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+	switch (ret = AscExeScsiQueue(boardp, &scsiq)) {
+	case ASC_NOERROR:
+		ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue() ASC_NOERROR\n");
+		break;
+	case ASC_BUSY:
+		/* Caller must enqueue request and retry later. */
+		break;
+	case ASC_ERROR:
+		ASC_DBG1(0,
+			"asc_execute_scsi_cmnd: AscExeScsiQueue() ASC_ERROR err_code %x\n",
+			boardp->err_code);
+		ASC_STATS(error);
+		scp->result = HOST_BYTE(DID_ERROR);
+		scp->scsi_done(scp);
+		break;
+	}
+
+	ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+	return ret;
+}
+
+/*
+ * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ */
+void
+asc_isr_callback(ASC_DVC_VAR *boardp, ASC_QDONE_INFO *qdonep)
+{
+	Scsi_Cmnd			*scp;
+	struct Scsi_Host	*shp;
+	int					flags;
+	Scsi_Cmnd			**scpp;
+
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ASC_DBG2(1, "asc_isr_callback: boardp %x, qdonep %x\n",
+		(unsigned) boardp, (unsigned) qdonep);
+	ASC_STATS(callback);
+	ASC_DBG_PRT_QDONE_INFO(2, qdonep);
+
+	/*
+	 * Get the Scsi_Cmnd structure and Scsi_Host structure for the
+	 * command that has been completed.
+	 */
+	scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr;
+	ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp);
+	ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+	shp = scp->host;
+	ASC_ASSERT(shp);
+	ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp);
+
+	/*
+	 * 'qdonep' contains the command's ending status.
+	 */
+	switch (qdonep->d3.done_stat) {
+	case QD_NO_ERROR:
+		ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
+		switch (qdonep->d3.host_stat) {
+		case QHSTA_NO_ERROR:
+			scp->result = 0;
+			break;
+		default:
+			/* QHSTA error occurred */
+			scp->result = HOST_BYTE(DID_ERROR);
+			break;
+		}
+		break;
+
+	case QD_WITH_ERROR:
+		ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
+		switch (qdonep->d3.host_stat) {
+		case QHSTA_NO_ERROR:
+			if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) {
+				ASC_DBG(2, "asc_isr_callback: SS_CHK_CONDITION\n");
+				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+					sizeof(scp->sense_buffer));
+				/*
+				 * Note: The status_byte() macro used by target drivers
+				 * defined in scsi.h shifts the status byte returned by
+				 * host drivers right by 1 bit. This is why target drivers
+				 * also use left shifted status byte definitions. For instance
+				 * target drivers use CHECK_CONDITION, defined to 0x1, instead
+				 * of the SCSI defined check condition value of 0x2.
+				 */
+				scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+					STATUS_BYTE(qdonep->d3.scsi_stat); 
+			} else {
+				scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); 
+			}
+			break;
+
+		default:
+			/* QHSTA error occurred */
+			ASC_DBG1(2, "asc_isr_callback: host_stat %x\n",
+				qdonep->d3.host_stat);
+			scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
+				STATUS_BYTE(qdonep->d3.scsi_stat);
+			break;
+		}
+		break;
+
+	case QD_ABORTED_BY_HOST:
+		ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
+		scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) |
+				STATUS_BYTE(qdonep->d3.scsi_stat);
+		break;
+
+	default:
+		ASC_DBG1(0, "asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat );
+		scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
+				STATUS_BYTE(qdonep->d3.scsi_stat);
+		break;
+	}
+
+	/*
+	 * Before calling 'scsi_done' for the current 'Scsi_Cmnd' and possibly
+	 * triggering more commands to be issued, try to start any pending
+	 * commands.
+	 */
+	if (ASC_BOARD(shp)->pending_tidmask != 0) {
+	 	/*
+		 * If there are any pending commands for this board before trying
+	 	 * to execute them, disable interrupts to preserve request ordering.
+		 */
+		ASC_STATS(intr_disable);
+		save_flags(flags);
+		cli();
+		ASC_DBG1(1, "asc_isr_callback: asc_execute_pending() %x\n",
+			ASC_BOARD(shp)->pending_tidmask);
+		asc_execute_pending(shp);
+		restore_flags(flags);
+	}
+
+	/* 
+	 * Because interrupts may be enabled by the 'Scsi_Cmnd' done function,
+	 * add the command to the end of the global done list. The done function
+	 * for the command will be called in advansys_interrupt().
+	 */
+	for (scpp = &asc_scsi_done; *scpp;
+	     scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) {
+		;
+	}
+	*scpp = scp;
+	scp->host_scribble = NULL;
+	return;
+}
+
+/*
+ * Execute as many pending requests as possible for the
+ * board specified by 'Scsi_Host'.
+ */
+STATIC void
+asc_execute_pending(struct Scsi_Host *shp)
+{
+	ASC_SCSI_BIT_ID_TYPE	scan_tidmask;
+	Scsi_Cmnd				*scp;
+	int						i;
+
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	/*
+	 * Execute pending commands for devices attached to
+	 * the current board in round-robin fashion.
+	 */
+	scan_tidmask = ASC_BOARD(shp)->pending_tidmask;
+	do {
+		for (i = 0; i < ASC_MAX_TID; i++) {
+			if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
+				if ((scp = asc_dequeue(shp, i)) == NULL) {
+					scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+				} else if (asc_execute_scsi_cmnd(scp) == ASC_BUSY) {
+					scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+					/* Put the request back at front of the list. */
+					asc_enqueue(shp, scp, i, ASC_FRONT);
+				}
+			}
+		}
+	} while (scan_tidmask);
+	return;
+}
+
+/*
+ * asc_init_dev()
+ *
+ * Perform one-time initialization of a device.
+ */
+STATIC int
+asc_init_dev(ASC_DVC_VAR *boardp, Scsi_Cmnd *scp)
+{
+	ASC_SCSI_REQ_Q			*scsireqq;
+	ASC_CAP_INFO			*cap_info;
+	ASC_SCSI_INQUIRY		*inquiry;
+	int						found;
+	ASC_SCSI_BIT_ID_TYPE	save_use_tagged_qng;
+	ASC_SCSI_BIT_ID_TYPE	save_can_tagged_qng;
+	int						ret;
+#ifdef ADVANSYS_DEBUG
+	ASC_SCSI_BIT_ID_TYPE	tidmask; /* target id bit mask: 1 - 128 */
+#endif /* ADVANSYS_DEBUG */
+
+	ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target);
+
+	/* Return true for the board's target id. */
+	if (boardp->cfg->chip_scsi_id == scp->target) {
+		return ASC_TRUE;
+	}
+
+	/*
+	 * XXX - Host drivers should not modify the timeout field.
+	 * But on the first command only add some extra time to
+	 * allow the driver to complete its initialization for the
+	 * device.
+	 */
+	scp->timeout += 2000;	/* Add 5 seconds to the request timeout. */
+
+	/* Set-up AscInitPollTarget() arguments. */
+	scsireqq = &ASC_BOARD(scp->host)->scsireqq;
+	memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
+	cap_info = &ASC_BOARD(scp->host)->cap_info;
+	memset(cap_info, 0, sizeof(ASC_CAP_INFO));
+	inquiry = &ASC_BOARD(scp->host)->inquiry;
+	memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
+
+	/*
+	 * XXX - AscInitPollBegin() re-initializes these fields to
+	 * zero. 'Or' in the new values and restore them before calling 
+	 * AscInitPollEnd(). Normally all targets are initialized within
+	 * a call to AscInitPollBegin() and AscInitPollEnd().
+	 */
+	save_use_tagged_qng = boardp->use_tagged_qng;
+    save_can_tagged_qng = boardp->cfg->can_tagged_qng;
+
+	ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n");
+	if (AscInitPollBegin(boardp)) {
+		ASC_DBG(0, "asc_init_dev: AscInitPollBegin() failed\n");
+		return ASC_FALSE;
+	}
+
+	scsireqq->sense_ptr = &scsireqq->sense[0];
+	scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN;
+	scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+	scsireqq->r1.target_lun = 0;
+	scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
+
+	found = ASC_FALSE;
+	ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
+	switch (ret = AscInitPollTarget(boardp, scsireqq, inquiry, cap_info)) {
+	case ASC_TRUE:
+		found = ASC_TRUE;
+#ifdef ADVANSYS_DEBUG
+		tidmask = ASC_TIX_TO_TARGET_ID(scp->target);
+		ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
+			cap_info->lba, cap_info->blk_size);
+		ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
+			inquiry->byte0.peri_dvc_type);
+		if (boardp->use_tagged_qng & tidmask) {
+			ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n",
+				boardp->max_dvc_qng[scp->target]);
+		} else {
+			ASC_DBG(1, "asc_init_dev: command queuing disabled\n");
+		}
+		if (boardp->init_sdtr & tidmask) {
+			ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n");
+		} else {
+			ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n");
+		}
+		/* Set bit means fix disabled. */
+		if (boardp->pci_fix_asyn_xfer & tidmask) {
+			ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n");
+		} else {
+			ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n");
+		}
+#endif /* ADVANSYS_DEBUG */
+		break;
+	case ASC_FALSE:
+		ASC_DBG(1, "asc_init_dev: no device found\n");
+		break;
+	case ASC_ERROR:
+		ASC_DBG(0, "asc_init_dev: AscInitPollTarget() ASC_ERROR\n");
+		break;
+	default:
+		ASC_DBG1(0, "asc_init_dev: AscInitPollTarget() unknown ret %d\n", ret);
+		break;
+	}
+
+	/* XXX - 'Or' in original tag bits. */
+	boardp->use_tagged_qng |= save_use_tagged_qng;
+	boardp->cfg->can_tagged_qng |= save_can_tagged_qng;
+
+	ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n");
+	AscInitPollEnd(boardp);
+
+#ifdef ASC_SET_CMD_PER_LUN
+	/*
+	 * XXX - Refer to the comment in advansys_detect()
+	 * regarding cmd_per_lun.
+	 */
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if (boardp->max_dvc_qng[i] < scp->host->cmd_per_lun) {
+			scp->host->cmd_per_lun = boardp->max_dvc_qng[i];
+		}
+	}
+#endif /* ASC_SET_CMD_PER_LUN */
+
+	return found;
+}
+
+/*
+ * Search for an AdvanSys PCI device in the PCI configuration space.
+ */
+STATIC int
+asc_srch_pci_dev(PCI_DEVICE *pciDevice)
+{
+	int ret;
+	static int scan = 1;
+
+	ASC_DBG(2, "asc_srch_pci_dev: begin\n");
+
+	if (scan) {
+		pciDevice->type = asc_scan_method(pciDevice);
+		scan = 0;
+		ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type);
+	}
+	ret = asc_pci_find_dev(pciDevice);
+	ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret);
+	if (ret == PCI_DEVICE_FOUND) {
+		pciDevice->slotNumber = pciDevice->slotFound + 1;
+		pciDevice->startSlot = pciDevice->slotFound + 1;
+	} else {
+		if (pciDevice->bridge > pciDevice->busNumber) {
+			ASC_DBG2(2, "asc_srch_pci_dev: bridge %x, busNumber %x\n",
+				pciDevice->bridge, pciDevice->busNumber);
+			pciDevice->busNumber++;
+			pciDevice->slotNumber = 0;
+			pciDevice->startSlot = 0;
+			pciDevice->endSlot = 0x0f;
+			ret = asc_srch_pci_dev(pciDevice);
+			ASC_DBG1(2, "asc_srch_pci_dev recursive call return %d\n", ret);
+		}
+	}
+	ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret);
+	return ret;
+}
+
+/*
+ * Determine the access method to be used for 'pciDevice'.
+ */
+STATIC uchar
+asc_scan_method(PCI_DEVICE *pciDevice)
+{
+	ushort data;
+	PCI_DATA pciData;
+	uchar type;
+	uchar slot;
+
+	ASC_DBG(2, "asc_scan_method: begin\n");
+	memset(&pciData, 0, sizeof(pciData));
+	for (type = 1; type < 3; type++) {
+		pciData.type = type;
+		for (slot = 0; slot < PCI_MAX_SLOT; slot++) {
+			pciData.slot = slot;
+			data = asc_get_cfg_word(&pciData);
+			if ((data != 0xFFFF) && (data != 0x0000)) {
+				ASC_DBG2(4, "asc_scan_method: data %x, type %d\n", data, type);
+				return (type);
+			}
+		}
+	}
+	ASC_DBG1(4, "asc_scan_method: type %d\n", type);
+	return (type);
+}
+
+/*
+ * Check for an AdvanSys PCI device in 'pciDevice'.
+ *
+ * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND.
+ */
+STATIC int
+asc_pci_find_dev(PCI_DEVICE *pciDevice)
+{
+	PCI_DATA pciData;
+	ushort vendorid, deviceid;
+	uchar classcode, subclass;
+	uchar lslot;
+
+	ASC_DBG(3, "asc_pci_find_dev: begin\n");
+	pciData.type = pciDevice->type;
+	pciData.bus = pciDevice->busNumber;
+	pciData.func = pciDevice->devFunc;
+	lslot = pciDevice->startSlot;
+	for (; lslot < pciDevice->endSlot; lslot++) {
+		pciData.slot = lslot;
+		pciData.offset = VENDORID_OFFSET;
+		vendorid = asc_get_cfg_word(&pciData);
+		ASC_DBG1(3, "asc_pci_find_dev: vendorid %x\n", vendorid);
+		if (vendorid != 0xffff) {
+			pciData.offset = DEVICEID_OFFSET;
+			deviceid = asc_get_cfg_word(&pciData);
+			ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid);
+			if ((vendorid == ASC_PCI_VENDORID) &&
+				((deviceid == ASC_PCI_DEVICE_ID_REV_A) ||
+				(deviceid == ASC_PCI_DEVICE_ID_REV_B))) {
+				pciDevice->slotFound = lslot;
+				ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n");
+				return PCI_DEVICE_FOUND;
+			} else {
+				pciData.offset = SUBCLASS_OFFSET;
+				subclass = asc_get_cfg_byte(&pciData);
+				pciData.offset = CLASSCODE_OFFSET;
+				classcode = asc_get_cfg_byte(&pciData);
+				if ((classcode & PCI_BASE_CLASS_BRIDGE_DEVICE) &&
+					(subclass & PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER)) {
+					pciDevice->bridge++;
+				}
+				ASC_DBG2(3, "asc_pci_find_dev: subclass %x, classcode %x\n",
+					subclass, classcode);
+			}
+		}
+	}
+	return PCI_DEVICE_NOT_FOUND;
+}
+
+/*
+ * Read PCI configuration data into 'pciConfig'.
+ */
+STATIC void
+asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig)
+{
+	PCI_DATA pciData;
+	uchar counter;
+	uchar *localConfig;
+
+	ASC_DBG1(4, "asc_get_pci_cfg: slot found - %d\n ",
+		pciDevice->slotFound);
+
+	pciData.type = pciDevice->type;
+	pciData.bus = pciDevice->busNumber;
+	pciData.slot = pciDevice->slotFound;
+	pciData.func = pciDevice->devFunc;
+	localConfig = (uchar *) pciConfig;
+
+	for (counter = 0; counter < sizeof(PCI_CONFIG_SPACE); counter++) {
+		pciData.offset = counter;
+		*localConfig = asc_get_cfg_byte(&pciData);
+		ASC_DBG1(4, "asc_get_pci_cfg: byte %x\n", *localConfig);
+		localConfig++;
+	}
+	ASC_DBG1(4, "asc_get_pci_cfg: counter %d\n", counter);
+}
+
+/*
+ * Read a word (16 bits) from the PCI configuration space.
+ *
+ * The configuration mechanism is checked for the correct access method.
+ */
+STATIC ushort
+asc_get_cfg_word(PCI_DATA *pciData)
+{
+	ushort tmp;
+	ulong address;
+	ulong lbus = pciData->bus;
+	ulong lslot = pciData->slot;
+	ulong lfunc = pciData->func;
+	uchar t2CFA, t2CF8;
+	ushort t1CF8, t1CFA, t1CFC, t1CFE;
+
+	ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %lu, slot %lu, func %lu\n",
+		pciData->type, lbus, lslot, lfunc);
+
+	/*
+	 * check type of configuration mechanism
+	 */
+	if (pciData->type == 2) {
+		/*
+		 * save these registers so we can restore them after we are done
+		 */
+		t2CFA = inp(0xCFA);	/* save PCI bus register */
+		t2CF8 = inp(0xCF8);	/* save config space enable register */
+
+		/*
+		 * go out and write the bus and enable registers
+		 */
+		/* set for type 1 cycle, if needed */
+		outp(0xCFA, pciData->bus);
+		/* set the function number */
+		outp(0xCF8, 0x10 | (pciData->func << 1)) ;
+
+		/*
+		 * read the configuration space type 2 locations
+		 */
+		tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset));
+	} else {
+		/*
+		 * type 1 configuration mechanism
+		 *
+		 * save the CONFIG_ADDRESS and CONFIG_DATA register values
+		 */
+		t1CFC = inpw(0xCFC);
+		t1CFE = inpw(0xCFE);
+		t1CF8 = inpw(0xCF8);
+		t1CFA = inpw(0xCFA);
+
+		/*
+		 * enable <31>, bus = <23:16>, slot = <15:11>,
+		 * func = <10:8>, reg = <7:2>
+		 */
+		address = (ulong) ((lbus << 16) | (lslot << 11) |
+			(lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
+
+		/*
+		 * write out the address to CONFIG_ADDRESS
+		 */
+		outl(address, 0xCF8);
+
+		/*
+		 * read in the word from CONFIG_DATA
+		 */
+		tmp = (ushort) ((inl(0xCFC) >>
+				 ((pciData->offset & 2) * 8)) & 0xFFFF);
+	}
+	ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp);
+	return tmp;
+}
+
+/*
+ * Reads a byte from the PCI configuration space.
+ *
+ * The configuration mechanism is checked for the correct access method.
+ */
+STATIC uchar
+asc_get_cfg_byte(PCI_DATA *pciData)
+{
+	uchar tmp;
+	ulong address;
+	ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
+	uchar t2CFA, t2CF8;
+	ushort t1CF8, t1CFA, t1CFC, t1CFE;
+
+	ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type);
+
+	/*
+	 * check type of configuration mechanism
+	 */
+	if (pciData->type == 2) {
+		/*
+		 * save these registers so we can restore them after we are done
+		 */
+		t2CFA = inp(0xCFA);	/* save PCI bus register */
+		t2CF8 = inp(0xCF8);	/* save config space enable register */
+
+		/*
+		 * go out and write the bus and enable registers
+		 */
+		/* set for type 1 cycle, if needed */
+		outp(0xCFA, pciData->bus);
+		/* set the function number */
+		outp(0xCF8, 0x10 | (pciData->func << 1));
+
+		/*
+		 * read the configuration space type 2 locations
+		 */
+		tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset));
+
+		/*
+		 * restore the registers used for our transaction
+		 */
+		outp(0xCF8, t2CF8);	/* restore the enable register */
+		outp(0xCFA, t2CFA);	/* restore PCI bus register */
+	} else {
+		/*
+		 * type 1 configuration mechanism
+		 *
+		 * save the CONFIG_ADDRESS and CONFIG_DATA register values
+		 */
+		t1CFC = inpw(0xCFC);
+		t1CFE = inpw(0xCFE);
+		t1CF8 = inpw(0xCF8);
+		t1CFA = inpw(0xCFA);
+
+		/*
+		 * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
+		 * reg = <7:2>
+		 */
+		address = (ulong) ((lbus << 16) | (lslot << 11) |
+			(lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
+
+		/*
+		 * write out the address to CONFIG_ADDRESS
+		 */
+		outl(address, 0xCF8);
+
+		/*
+		 * read in the word from CONFIG_DATA
+		 */
+		tmp = (uchar) ((inl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF);
+	}
+	ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp);
+	return tmp;
+}
+
+/*
+ * Add a 'Scsi_Cmnd' to the end of specified 'Scsi_Host' 
+ * target device pending command list. Set 'pending_tidmask'
+ * to indicate a command is queued for the device.
+ *
+ * 'flag' may be either ASC_FRONT or ASC_BACK.
+ *
+ * The 'Scsi_Cmnd' host_scribble field is used as a next pointer.
+ */
+STATIC void
+asc_enqueue(struct Scsi_Host *shp, Scsi_Cmnd *scp, int tid, int flag)
+{
+	Scsi_Cmnd	**scpp;
+
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
+	ASC_STATS(enqueue);
+	if (flag == ASC_FRONT) {
+		scp->host_scribble = (unsigned char *) ASC_BOARD(shp)->pending[tid];
+		ASC_BOARD(shp)->pending[tid] = (Scsi_Cmnd *) scp;
+	} else { /* ASC_BACK */
+		for (scpp = &ASC_BOARD(shp)->pending[tid]; *scpp;
+			 scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) {
+			;
+		}
+		*scpp = scp;
+		scp->host_scribble = NULL;
+	}
+	ASC_BOARD(shp)->pending_tidmask |= ASC_TIX_TO_TARGET_ID(tid);
+}
+
+/*
+ * Return first pending 'Scsi_Cmnd' on the specified 'Scsi_Host'
+ * for the specified target device. Clear the 'pending_tidmask'
+ * bit for the device if no more commands are left queued for it.
+ *
+ * The 'Scsi_Cmnd' host_scribble field is used as a next pointer.
+ */
+STATIC Scsi_Cmnd *
+asc_dequeue(struct Scsi_Host *shp, int tid)
+{
+	Scsi_Cmnd	*scp;
+
+	ASC_STATS(dequeue);
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	if ((scp = ASC_BOARD(shp)->pending[tid]) != NULL) {
+		ASC_BOARD(shp)->pending[tid] = (Scsi_Cmnd *) scp->host_scribble;
+	}
+	if (ASC_BOARD(shp)->pending[tid] == NULL) {
+		ASC_BOARD(shp)->pending_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+	}
+	return scp;
+}
+
+/*
+ * Remove the specified 'Scsi_Cmnd' from the specified 'Scsi_Host'
+ * for the specified target device. Clear the 'pending_tidmask'
+ * bit for the device if no more commands are left queued for it.
+ *
+ * The 'Scsi_Cmnd' host_scribble field is used as a next pointer.
+ *
+ * Return ASC_TRUE if the command was found and removed, otherwise
+ * return ASC_FALSE if the command was not found.
+ */
+STATIC int
+asc_rmqueue(struct Scsi_Host *shp, Scsi_Cmnd *scp, int tid)
+{
+	Scsi_Cmnd	**scpp;
+	int			ret;
+
+	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+	ret = ASC_FALSE;
+	for (scpp = &ASC_BOARD(shp)->pending[tid];
+	     *scpp; scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) {
+		if (*scpp == scp) {
+			*scpp = (Scsi_Cmnd *) scp->host_scribble;	
+			scp->host_scribble = NULL;
+			ASC_STATS(rmqueue);
+			ret = ASC_TRUE;
+		}
+	}
+	if (ASC_BOARD(shp)->pending[tid] == NULL) {
+		ASC_BOARD(shp)->pending_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+	}
+	return ret;
+}
+
+
+/*
+ * --- Functions Required by the Asc Library
+ */
+
+/*
+ * Delay for 'n' milliseconds. Don't use the 'jiffies'
+ * global variable which is incremented once every 5 ms
+ * from a timer interrupt, because this function may be
+ * called when interrupts are disabled.
+ */
+void
+DvcSleepMilliSecond(ulong n)
+{
+	ulong i;
+
+	ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n);
+	for (i = 0; i < n; i++) {
+		udelay(1000);
+	}
+}
+
+void
+DvcDisplayString(uchar *s)
+{
+	printk(s);
+}
+
+int
+DvcEnterCritical(void)
+{
+	int	flags;
+
+	save_flags(flags);
+	cli();
+	return flags;
+}
+
+void
+DvcLeaveCritical(int flags)
+{
+	restore_flags(flags);
+}
+
+/*
+ * Convert a virtual address to a virtual address.
+ *
+ * Apparently Linux is loaded V=R (virtual equals real). Just return
+ * the virtual address.
+ */
+ulong
+DvcGetPhyAddr(uchar *buf_addr, ulong buf_len)
+{
+	ulong phys_addr;
+
+	phys_addr = (ulong) buf_addr;
+	return phys_addr;
+}
+
+ulong
+DvcGetSGList(ASC_DVC_VAR *asc_dvc_sg, uchar *buf_addr, ulong buf_len,
+			 ASC_SG_HEAD *asc_sg_head_ptr)
+{
+	ulong buf_size;
+
+	buf_size = buf_len;
+	asc_sg_head_ptr->entry_cnt = 1;
+	asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr;
+	asc_sg_head_ptr->sg_list[0].bytes = buf_size;
+	return buf_size;
+}
+
+/*
+ * void
+ * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words)
+ *
+ * Calling/Exit State:
+ *	none
+ *
+ * Description:
+ * 	Output an ASC_SCSI_Q structure to the chip
+ */
+void
+DvcPutScsiQ(PortAddr iop_base, ushort s_addr, ushort *outbuf, int words)
+{
+	int	i;
+
+	ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", (uchar *) outbuf, 2 * words);
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < words; i++, outbuf++) {
+		if (i == 2 || i == 10) {
+			continue;
+		}
+		AscPutChipLramData(iop_base, *outbuf);
+	}
+}
+
+/*
+ * void
+ * DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words)
+ *
+ * Calling/Exit State:
+ *	none
+ *
+ * Description:
+ * 	Input an ASC_QDONE_INFO structure from the chip
+ */
+void
+DvcGetQinfo(PortAddr iop_base, ushort s_addr, ushort *inbuf, int words)
+{
+	int	i;
+
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < words; i++, inbuf++) {
+		if (i == 5) {
+			continue;
+		}
+		*inbuf = AscGetChipLramData(iop_base);
+	}
+	ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words);
+}
+
+/*
+ * void	DvcOutPortWords(ushort iop_base, ushort &outbuf, int words)
+ *
+ * Calling/Exit State:
+ *	none
+ *
+ * Description:
+ * 	output a buffer to an i/o port address
+ */
+void
+DvcOutPortWords(ushort iop_base, ushort *outbuf, int words)
+{
+	int	i;
+
+	for (i = 0; i < words; i++, outbuf++)
+		outpw(iop_base, *outbuf);
+}
+
+/*
+ * void	DvcInPortWords(ushort iop_base, ushort &outbuf, int words)
+ *
+ * Calling/Exit State:
+ *	none
+ *
+ * Description:
+ * 	input a buffer from an i/o port address
+ */
+void
+DvcInPortWords(ushort iop_base, ushort *inbuf, int words)
+{
+	int	i;
+
+	for (i = 0; i < words; i++, inbuf++)
+		*inbuf = inpw(iop_base);
+}
+
+
+/*
+ * void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords)
+ *
+ * Calling/Exit State:
+ *	none
+ *
+ * Description:
+ * 	output a buffer of 32-bit integers to an i/o port address in
+ *  16 bit integer units
+ */
+void  
+DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords)
+{
+	int		i;
+	int		words;
+	ushort	*pw;
+
+	pw = (ushort *) pdw;
+	words = dwords << 1;
+	for(i = 0; i < words; i++, pw++) {
+		outpw(port, *pw);
+	}
+	return;
+}
+
+
+/*
+ * --- Tracing and Debugging Functions
+ */
+
+#ifdef ADVANSYS_STATS
+
+#define ASC_PRT_STATS_NEXT() \
+	if (cp) { \
+		totlen += len; \
+		leftlen -= len; \
+		if (leftlen == 0) { \
+			return totlen; \
+		} \
+		cp += len; \
+	}
+
+/*
+ * asc_prt_stats()
+ *
+ * Note: no single line should be greater than 160 characters, cf.
+ * asc_prt_stats_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_stats(char *cp, int cplen)
+{
+ 	struct asc_stats	*s;
+	int					leftlen;
+	int					totlen;
+	int					len;
+
+ 	s = &asc_stats;
+	leftlen = cplen;
+	totlen = len = 0;
+
+	len = asc_prt_stats_line(cp, leftlen,
+"\nAdvanSys SCSI Host Driver Statistics:\n");
+	ASC_PRT_STATS_NEXT();
+	
+	len = asc_prt_stats_line(cp, leftlen,
+" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu,\n",
+		s->command, s->queuecommand, s->abort, s->reset, s->biosparam);
+	ASC_PRT_STATS_NEXT();
+
+	len = asc_prt_stats_line(cp, leftlen,
+" interrupt %lu, callback %lu, cmd_disable %lu, intr_disable %lu,\n",
+		s->interrupt, s->callback, s->cmd_disable, s->intr_disable);
+	ASC_PRT_STATS_NEXT();
+
+	len = asc_prt_stats_line(cp, leftlen,
+" error %lu, enqueue %lu, dequeue %lu, rmqueue %lu,\n",
+		s->error, s->enqueue, s->dequeue, s->rmqueue);
+	ASC_PRT_STATS_NEXT();
+
+	if (s->cont_cnt > 0) {
+		len = asc_prt_stats_line(cp, leftlen,
+" cont_cnt %lu, cont_xfer %lu: avg_xfer=%lu kb\n",
+			s->cont_cnt, s->cont_xfer, (s->cont_xfer/2)/s->cont_cnt);
+		ASC_PRT_STATS_NEXT();
+	}
+
+	if (s->sg_cnt > 0) {
+		len = asc_prt_stats_line(cp, leftlen,
+" sg_cnt %lu, sg_elem %lu, sg_xfer %lu: avg_elem=%lu, avg_size=%lu kb\n",
+			s->sg_cnt, s->sg_elem, s->sg_xfer,
+			s->sg_elem/s->sg_cnt, (s->sg_xfer/2)/s->sg_cnt);
+		ASC_PRT_STATS_NEXT();
+	}
+
+ 	return totlen;
+}
+
+/*
+ * asc_prt_stats_line()
+ *
+ * If 'cp' is NULL print to the console, otherwise print to a buffer.
+ *
+ * Return 0 if printing to the console, otherwise return the number of
+ * bytes written to the buffer.
+ *
+ * Note: If any single line is greater than 160 bytes the stack
+ * will be corrupted. 's[]' is defined to be 160 bytes.
+ */
+int
+asc_prt_stats_line(char *buf, int buflen, char *fmt, ...)
+{
+	va_list		args;
+	int			ret;
+	char		s[160];		/* 2 lines */
+
+	va_start(args, fmt);
+	ret = vsprintf(s, fmt, args);
+	if (buf == NULL) {
+		(void) printk(s);
+		ret = 0;
+	} else {
+		ret = min(buflen, ret);
+		memcpy(buf, s, ret);
+	}
+	va_end(args);
+	return ret;
+}
+#endif /* ADVANSYS_STATS */
+
+#ifdef ADVANSYS_DEBUG
+/*
+ * asc_prt_scsi_host()
+ */
+STATIC void 
+asc_prt_scsi_host(struct Scsi_Host *s)
+{
+	printk("Scsi_Host at addr %x\n", (unsigned) s);
+	printk(
+" next %x, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n",
+		(unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no,
+		s->last_reset);
+
+	printk(
+" host_wait %x, host_queue %x, hostt %x, block %x,\n",
+		(unsigned) s->host_wait, (unsigned) s->host_queue,
+		(unsigned) s->hostt, (unsigned) s->block);
+
+	printk(
+" wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n",
+		s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port,
+		s->irq, s->dma_channel);
+
+	printk(
+" this_id %d, can_queue %d,\n", s->this_id, s->can_queue);
+
+	printk(
+" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
+		s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
+		s->loaded_as_module);
+
+	printk("hostdata (struct asc_board)\n");
+	asc_prt_dvc_var(&ASC_BOARD(s)->board);
+	asc_prt_dvc_cfg(&ASC_BOARD(s)->cfg);
+	printk(" overrun_buf %x\n", (unsigned) &ASC_BOARD(s)->overrun_buf[0]);
+}
+
+/*
+ * asc_prt_dvc_var()
+ */
+STATIC void 
+asc_prt_dvc_var(ASC_DVC_VAR *h)
+{
+	printk("ASC_DVC_VAR at addr %x\n", (unsigned) h);
+
+	printk(
+" iop_base %x, err_code %x, dvc_cntl %x, bug_fix_cntl %d,\n",
+		h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
+
+	printk(
+" bus_type %d, isr_callback %x, exe_callback %x, init_sdtr %x,\n",
+		h->bus_type, (unsigned) h->isr_callback, (unsigned) h->exe_callback,
+		(unsigned) h->init_sdtr);
+
+	printk(
+" sdtr_done %x, use_tagged_qng %x, unit_not_ready %x, chip_no %x,\n",
+		(unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng,
+		(unsigned) h->unit_not_ready, (unsigned) h->chip_no);
+		
+	printk(
+" queue_full_or_busy %x, start_motor %x, scsi_reset_wait %x, irq_no %x,\n",
+		(unsigned) h->queue_full_or_busy, (unsigned) h->start_motor,
+		(unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
+
+	printk(
+" is_in_int %x, max_total_qng %x, cur_total_qng %x, in_critical_cnt %x,\n",
+		(unsigned) h->is_in_int, (unsigned) h->max_total_qng,
+		(unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt);
+
+	printk(
+" last_q_shortage %x, init_state %x, no_scam %x, pci_fix_asyn_xfer %x,\n",
+		(unsigned) h->last_q_shortage, (unsigned) h->init_state,
+		(unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer);
+
+	printk(
+" int_count %ld, req_count %ld, busy_count %ld, cfg %x, saved_ptr2func %x\n",
+		h->int_count, h->req_count, h->busy_count, (unsigned) h->cfg,
+		(unsigned) h->saved_ptr2func);
+}
+
+/*
+ * asc_prt_dvc_cfg()
+ */
+STATIC void 
+asc_prt_dvc_cfg(ASC_DVC_CFG *h)
+{
+	printk("ASC_DVC_CFG at addr %x\n", (unsigned) h);
+
+	printk(
+" can_tagged_qng %x, cmd_qng_enabled %x, disc_enable %x, res %x,\n",
+			h->can_tagged_qng, h->cmd_qng_enabled, h->disc_enable, h->res);
+
+	printk(
+" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
+			 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
+			 h->chip_version);
+
+	printk(
+" pci_device_id %d, lib_serial_no %d, lib_version %d, mcode_date %d,\n",
+		  h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date);
+
+	printk(
+" mcode_version %d, overrun_buf %x\n",
+			h->mcode_version, (unsigned) h->overrun_buf);
+}
+
+/*
+ * asc_prt_scsi_q()
+ */
+STATIC void 
+asc_prt_scsi_q(ASC_SCSI_Q *q)
+{
+	ASC_SG_HEAD	*sgp;
+	int i;
+
+	printk("ASC_SCSI_Q at addr %x\n", (unsigned) q);
+
+	printk(
+" target_ix %u, target_lun %u, srb_ptr %x, tag_code %u,\n",
+			q->q2.target_ix, q->q1.target_lun,
+			(unsigned) q->q2.srb_ptr, q->q2.tag_code);
+
+	printk(
+" data_addr %x, data_cnt %lu, sense_addr %x, sense_len %u,\n",
+			(unsigned) q->q1.data_addr, q->q1.data_cnt,
+			(unsigned) q->q1.sense_addr, q->q1.sense_len);
+
+	printk(
+" cdbptr %x, cdb_len %u, sg_head %x, sg_queue_cnt %u\n",
+			(unsigned) q->cdbptr, q->q2.cdb_len,
+			(unsigned) q->sg_head, q->q1.sg_queue_cnt);
+
+	if (q->sg_head) {
+		sgp = q->sg_head;
+		printk("ASC_SG_HEAD at addr %x\n", (unsigned) sgp);
+		printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt);
+		for (i = 0; i < sgp->entry_cnt; i++) {
+			printk(" [%u]: addr %x, bytes %lu\n",
+				i, (unsigned) sgp->sg_list[i].addr, sgp->sg_list[i].bytes);
+		}
+
+	}
+}
+
+/*
+ * asc_prt_qdone_info()
+ */
+STATIC void 
+asc_prt_qdone_info(ASC_QDONE_INFO *q)
+{
+	printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q);
+	printk(
+" srb_ptr %x, target_ix %u, cdb_len %u, tag_code %u, done_stat %x\n",
+			(unsigned) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+			q->d2.tag_code, q->d3.done_stat);
+	printk(
+" host_stat %x, scsi_stat %x, scsi_msg %x\n",
+			q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
+}
+
+/*
+ * asc_prt_hex()
+ *
+ * Print hexadecimal output in 4 byte groupings 32 bytes 
+ * or 8 double-words per line.
+ */
+STATIC void 
+asc_prt_hex(char *f, uchar *s, int l)
+{
+	int			i;
+	int			j;
+	int			k;
+	int			m;
+
+	printk("%s: (%d bytes)\n", f, l);
+
+	for (i = 0; i < l; i += 32) {
+		
+		/* Display a maximum of 8 double-words per line. */
+		if ((k = (l - i) / 4) >= 8) {
+			k = 8;
+			m = 0;
+		} else {
+			m = (l - i) % 4 ;
+		}
+
+		for (j = 0; j < k; j++) {
+			printk(" %2.2X%2.2X%2.2X%2.2X",
+				(unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1],
+				(unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]);
+		}
+
+		switch (m) {
+		case 0:
+		default:
+			break;
+		case 1:
+			printk(" %2.2X",
+				(unsigned) s[i+(j*4)+4]);
+			break;
+		case 2:
+			printk(" %2.2X%2.2X",
+				(unsigned) s[i+(j*4)+4],
+				(unsigned) s[i+(j*4)+5]);
+			break;
+		case 3:
+			printk(" %2.2X%2.2X%2.2X",
+				(unsigned) s[i+(j*4)+4],
+				(unsigned) s[i+(j*4)+5],
+				(unsigned) s[i+(j*4)+6]);
+			break;
+		}
+
+		printk("\n");
+	}
+}
+
+/*
+ * interrupts_enabled()
+ *
+ * Return 1 if interrupts are enabled, otherwise return 0.
+ */
+STATIC int
+interrupts_enabled(void)
+{
+	int flags;
+
+	save_flags(flags);
+	if (flags & 0x0200) {
+		return ASC_TRUE;
+	} else {
+		return ASC_FALSE;
+	}
+}
+
+#endif /* ADVANSYS_DEBUG */
+
+
+/*
+ * --- Asc Library Functions
+ */
+
+ushort
+AscGetEisaChipCfg(
+					 PortAddr iop_base
+)
+{
+	PortAddr            eisa_cfg_iop;
+
+	eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+	  (PortAddr) (ASC_EISA_CFG_IOP_MASK);
+	return (inpw(eisa_cfg_iop));
+}
+
+uchar
+AscSetChipScsiID(
+					PortAddr iop_base,
+					uchar new_host_id
+)
+{
+	ushort              cfg_lsw;
+
+	if (AscGetChipScsiID(iop_base) == new_host_id) {
+		return (new_host_id);
+	}
+	cfg_lsw = AscGetChipCfgLsw(iop_base);
+	cfg_lsw &= 0xF8FF;
+	cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8);
+	AscSetChipCfgLsw(iop_base, cfg_lsw);
+	return (AscGetChipScsiID(iop_base));
+}
+
+ushort
+AscGetChipBiosAddress(
+						 PortAddr iop_base,
+						 ushort bus_type
+)
+{
+	ushort              cfg_lsw;
+	ushort              bios_addr;
+
+	if ((bus_type & ASC_IS_EISA) != 0) {
+		cfg_lsw = AscGetEisaChipCfg(iop_base);
+		cfg_lsw &= 0x000F;
+		bios_addr = (ushort) (ASC_BIOS_MIN_ADDR +
+							  (cfg_lsw * ASC_BIOS_BANK_SIZE));
+		return (bios_addr);
+	}
+	cfg_lsw = AscGetChipCfgLsw(iop_base);
+	bios_addr = (ushort) (((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) + ASC_BIOS_MIN_ADDR);
+	return (bios_addr);
+}
+
+uchar
+AscGetChipVersion(
+					 PortAddr iop_base,
+					 ushort bus_type
+)
+{
+	if ((bus_type & ASC_IS_EISA) != 0) {
+
+		PortAddr            eisa_iop;
+		uchar               revision;
+
+		eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+		  (PortAddr) ASC_EISA_REV_IOP_MASK;
+		revision = inp(eisa_iop);
+		return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision));
+	}
+	return (AscGetChipVerNo(iop_base));
+}
+
+ushort
+AscGetChipBusType(
+					 PortAddr iop_base
+)
+{
+	ushort              chip_ver;
+
+	chip_ver = AscGetChipVerNo(iop_base);
+	if ((chip_ver >= ASC_CHIP_MIN_VER_VL) &&
+		(chip_ver <= ASC_CHIP_MAX_VER_VL)) {
+		if (((iop_base & 0x0C30) == 0x0C30) ||
+			((iop_base & 0x0C50) == 0x0C50)) {
+			return (ASC_IS_EISA);
+		}
+		return (ASC_IS_VL);
+	} else if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
+			   (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
+		if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
+			return (ASC_IS_ISAPNP);
+		}
+		return (ASC_IS_ISA);
+	} else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
+			   (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
+		return (ASC_IS_PCI);
+	} else {
+		return (0);
+	}
+}
+
+void
+AscEnableIsaDma(
+				   uchar dma_channel
+)
+{
+	if (dma_channel < 4) {
+		outp(0x000B, (ushort) (0xC0 | dma_channel));
+		outp(0x000A, dma_channel);
+	} else if (dma_channel < 8) {
+
+		outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4)));
+		outp(0x00D4, (ushort) (dma_channel - 4));
+	}
+	return;
+}
+
+ulong
+AscLoadMicroCode(
+					PortAddr iop_base,
+					ushort s_addr,
+					ushort dosfar * mcode_buf,
+					ushort mcode_size
+)
+{
+	ulong               chksum;
+	ushort              mcode_word_size;
+	ushort              mcode_chksum;
+
+	mcode_word_size = (ushort) (mcode_size >> 1);
+	AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
+	AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+
+	chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+	mcode_chksum = (ushort) AscMemSumLramWord(iop_base,
+											  (ushort) ASC_CODE_SEC_BEG,
+		  (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2));
+	AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
+	AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
+	return (chksum);
+}
+
+uchar               _hextbl_[16] =
+{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F'};
+
+uchar               _isa_pnp_inited = 0;
+
+PortAddr            _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] =
+{
+	0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
+	ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
+};
+
+PortAddr
+AscSearchIOPortAddr(
+					   PortAddr iop_beg,
+					   ushort bus_type
+)
+{
+	if (bus_type & ASC_IS_VL) {
+		while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+			if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) {
+				return (iop_beg);
+			}
+		}
+		return (0);
+	}
+	if (bus_type & ASC_IS_ISA) {
+		if (_isa_pnp_inited == 0) {
+			AscSetISAPNPWaitForKey();
+			_isa_pnp_inited++;
+		}
+		while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+			if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) {
+				return (iop_beg);
+			}
+		}
+		return (0);
+	}
+	if (bus_type & ASC_IS_EISA) {
+		if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
+			return (iop_beg);
+		}
+		return (0);
+	}
+	return (0);
+}
+
+PortAddr
+AscSearchIOPortAddr11(
+						 PortAddr s_addr
+)
+{
+
+	int                 i;
+	PortAddr            iop_base;
+
+	for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+		if (_asc_def_iop_base[i] > s_addr) {
+			break;
+		}
+	}
+	for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+		iop_base = _asc_def_iop_base[i];
+		if (AscFindSignature(iop_base)) {
+			return (iop_base);
+		}
+	}
+	return (0);
+}
+
+int
+AscFindSignature(
+					PortAddr iop_base
+)
+{
+	ushort              sig_word;
+
+	if ((inp((PortAddr) (iop_base + 1)) & 0xFF) == (uchar) ASC_1000_ID1B) {
+		sig_word = inpw(iop_base);
+		if ((sig_word == (ushort) ASC_1000_ID0W) ||
+			(sig_word == (ushort) ASC_1000_ID0W_FIX)) {
+			return (1);
+		}
+	}
+	return (0);
+}
+
+void
+AscToggleIRQAct(
+				   PortAddr iop_base
+)
+{
+	AscSetChipStatus(iop_base, CIW_IRQ_ACT);
+	AscSetChipStatus(iop_base, 0);
+	return;
+}
+
+#if CC_INIT_INQ_DISPLAY
+
+#endif
+
+void
+AscSetISAPNPWaitForKey(
+						  void)
+{
+
+	outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
+	outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
+	return;
+}
+
+uchar
+AscGetChipIRQ(
+				 PortAddr iop_base,
+				 ushort bus_type
+)
+{
+	ushort              cfg_lsw;
+	uchar               chip_irq;
+
+	if ((bus_type & ASC_IS_EISA) != 0) {
+
+		cfg_lsw = AscGetEisaChipCfg(iop_base);
+		chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10);
+		if ((chip_irq == 13) || (chip_irq > 15)) {
+
+			return (0);
+		}
+		return (chip_irq);
+	} else {
+
+		cfg_lsw = AscGetChipCfgLsw(iop_base);
+
+		if ((bus_type & ASC_IS_VL) != 0) {
+
+			chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07));
+			if ((chip_irq == 0) ||
+				(chip_irq == 4) ||
+				(chip_irq == 7)) {
+				return (0);
+			}
+			return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1)));
+		}
+		chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03));
+		if (chip_irq == 3)
+			chip_irq += (uchar) 2;
+		return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
+	}
+}
+
+uchar
+AscSetChipIRQ(
+				 PortAddr iop_base,
+				 uchar irq_no,
+				 ushort bus_type
+)
+{
+	ushort              cfg_lsw;
+
+	if ((bus_type & ASC_IS_VL) != 0) {
+
+		if (irq_no != 0) {
+			if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) {
+				irq_no = 0;
+			} else {
+				irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1));
+			}
+		}
+		cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3);
+		cfg_lsw |= (ushort) 0x0010;
+		AscSetChipCfgLsw(iop_base, cfg_lsw);
+		AscToggleIRQAct(iop_base);
+
+		cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0);
+		cfg_lsw |= (ushort) ((irq_no & 0x07) << 2);
+		AscSetChipCfgLsw(iop_base, cfg_lsw);
+		AscToggleIRQAct(iop_base);
+
+		return (AscGetChipIRQ(iop_base, bus_type));
+
+	} else if ((bus_type & (ASC_IS_ISA)) != 0) {
+
+		if (irq_no == 15)
+			irq_no -= (uchar) 2;
+		irq_no -= (uchar) ASC_MIN_IRQ_NO;
+		cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3);
+		cfg_lsw |= (ushort) ((irq_no & 0x03) << 2);
+		AscSetChipCfgLsw(iop_base, cfg_lsw);
+		return (AscGetChipIRQ(iop_base, bus_type));
+	} else {
+
+		return (0);
+	}
+}
+
+uchar
+AscGetChipScsiCtrl(
+					  PortAddr iop_base
+)
+{
+	uchar               sc;
+
+	AscSetBank(iop_base, 1);
+	sc = inp(iop_base + IOP_REG_SC);
+	AscSetBank(iop_base, 0);
+	return (sc);
+}
+
+extern uchar        _sdtr_period_tbl_[];
+
+int
+AscIsrChipHalted(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	SDTR_XMSG           sdtr_xmsg;
+	SDTR_XMSG           out_msg;
+	ushort              halt_q_addr;
+	int                 sdtr_accept;
+	ushort              int_halt_code;
+	ASC_SCSI_BIT_ID_TYPE scsi_busy;
+	ASC_SCSI_BIT_ID_TYPE target_id;
+	PortAddr            iop_base;
+	uchar               tag_code;
+	uchar               q_status;
+	uchar               halt_qp;
+	uchar               sdtr_data;
+	uchar               target_ix;
+	uchar               q_cntl, tid_no;
+	uchar               cur_dvc_qng;
+	uchar               asyn_sdtr;
+	uchar               scsi_status;
+
+	iop_base = asc_dvc->iop_base;
+	int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
+
+	halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
+	halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
+	target_ix = AscReadLramByte(iop_base,
+				   (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX));
+	q_cntl = AscReadLramByte(iop_base,
+						(ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL));
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
+	if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+
+		asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
+	} else {
+		asyn_sdtr = 0;
+	}
+	if (int_halt_code == ASC_HALT_EXTMSG_IN) {
+
+		AscMemWordCopyFromLram(iop_base,
+							   ASCV_MSGIN_BEG,
+							   (ushort dosfar *) & sdtr_xmsg,
+							   (ushort) (sizeof (SDTR_XMSG) >> 1));
+		if ((sdtr_xmsg.msg_type == MS_EXTEND) &&
+			(sdtr_xmsg.msg_len == MS_SDTR_LEN)) {
+			sdtr_accept = TRUE;
+			if (sdtr_xmsg.msg_req == MS_SDTR_CODE) {
+				if (sdtr_xmsg.req_ack_offset > ASC_SYN_MAX_OFFSET) {
+
+					sdtr_accept = FALSE;
+					sdtr_xmsg.req_ack_offset = ASC_SYN_MAX_OFFSET;
+				}
+				sdtr_data = AscCalSDTRData(sdtr_xmsg.xfer_period,
+										   sdtr_xmsg.req_ack_offset);
+				if (sdtr_xmsg.req_ack_offset == 0) {
+
+					q_cntl &= ~QC_MSG_OUT;
+					asc_dvc->init_sdtr &= ~target_id;
+					asc_dvc->sdtr_done &= ~target_id;
+					AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+				} else if ((sdtr_data == 0xFF)) {
+
+					q_cntl |= QC_MSG_OUT;
+					asc_dvc->init_sdtr &= ~target_id;
+					asc_dvc->sdtr_done &= ~target_id;
+					AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+				} else {
+					if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
+
+						q_cntl &= ~QC_MSG_OUT;
+						asc_dvc->sdtr_done |= target_id;
+						asc_dvc->init_sdtr |= target_id;
+						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
+					} else {
+
+						q_cntl |= QC_MSG_OUT;
+
+						AscMsgOutSDTR(iop_base,
+									  sdtr_xmsg.xfer_period,
+									  sdtr_xmsg.req_ack_offset);
+						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
+						asc_dvc->sdtr_done |= target_id;
+						asc_dvc->init_sdtr |= target_id;
+					}
+				}
+
+				AscWriteLramByte(iop_base,
+						 (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+								 q_cntl);
+				AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+				return (0);
+			}
+		}
+	} else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
+
+		q_cntl |= QC_REQ_SENSE;
+		if (((asc_dvc->init_sdtr & target_id) != 0) &&
+			((asc_dvc->sdtr_done & target_id) != 0)) {
+
+			sdtr_data = AscReadLramByte(iop_base,
+				  (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no));
+			AscMsgOutSDTR(iop_base,
+						  _sdtr_period_tbl_[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)],
+						  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
+			q_cntl |= QC_MSG_OUT;
+		}
+		AscWriteLramByte(iop_base,
+						 (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+						 q_cntl);
+
+		tag_code = AscReadLramByte(iop_base,
+					(ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE));
+		tag_code &= 0xDC;
+		AscWriteLramByte(iop_base,
+					 (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE),
+						 tag_code);
+
+		q_status = AscReadLramByte(iop_base,
+					  (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS));
+		q_status |= (QS_READY | QS_BUSY);
+		AscWriteLramByte(iop_base,
+					   (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+						 q_status);
+
+		scsi_busy = AscReadLramByte(iop_base,
+									(ushort) ASCV_SCSIBUSY_B);
+		scsi_busy &= ~target_id;
+		AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	} else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
+
+		AscMemWordCopyFromLram(iop_base,
+							   ASCV_MSGOUT_BEG,
+							   (ushort dosfar *) & out_msg,
+							   (ushort) (sizeof (SDTR_XMSG) >> 1));
+
+		if ((out_msg.msg_type == MS_EXTEND) &&
+			(out_msg.msg_len == MS_SDTR_LEN) &&
+			(out_msg.msg_req == MS_SDTR_CODE)) {
+
+			asc_dvc->init_sdtr &= ~target_id;
+			asc_dvc->sdtr_done &= ~target_id;
+			AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+
+		} else {
+
+		}
+
+		q_cntl &= ~QC_MSG_OUT;
+		AscWriteLramByte(iop_base,
+						 (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+						 q_cntl);
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	} else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
+
+		scsi_status = AscReadLramByte(iop_base,
+		  (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS));
+		cur_dvc_qng = AscReadLramByte(iop_base,
+					 (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix));
+		if ((cur_dvc_qng > 0) &&
+			(asc_dvc->cur_dvc_qng[tid_no] > 0)) {
+
+			scsi_busy = AscReadLramByte(iop_base,
+										(ushort) ASCV_SCSIBUSY_B);
+			scsi_busy |= target_id;
+			AscWriteLramByte(iop_base,
+							 (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+			asc_dvc->queue_full_or_busy |= target_id;
+
+			if (scsi_status == SS_QUEUE_FULL) {
+				if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
+					cur_dvc_qng -= 1;
+					asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng;
+
+					AscWriteLramByte(iop_base,
+									 (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) tid_no),
+									 cur_dvc_qng);
+				}
+			}
+		}
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	}
+	return (0);
+}
+
+uchar
+_AscCopyLramScsiDoneQ(
+						 PortAddr iop_base,
+						 ushort q_addr,
+						 ASC_QDONE_INFO dosfar * scsiq,
+						 ulong max_dma_count
+)
+{
+	ushort              _val;
+	uchar               sg_queue_cnt;
+
+	DvcGetQinfo(iop_base,
+				(ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG),
+				(ushort dosfar *) scsiq,
+			  (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2));
+
+#if !CC_LITTLE_ENDIAN_HOST
+	AscAdjEndianQDoneInfo(scsiq);
+#endif
+
+	_val = AscReadLramWord(iop_base,
+						   (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS));
+	scsiq->q_status = (uchar) _val;
+	scsiq->q_no = (uchar) (_val >> 8);
+
+	_val = AscReadLramWord(iop_base,
+						   (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL));
+	scsiq->cntl = (uchar) _val;
+	sg_queue_cnt = (uchar) (_val >> 8);
+
+	_val = AscReadLramWord(iop_base,
+						(ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
+	scsiq->sense_len = (uchar) _val;
+	scsiq->user_def = (uchar) (_val >> 8);
+
+	scsiq->remain_bytes = AscReadLramDWord(iop_base,
+				 (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+	scsiq->remain_bytes &= max_dma_count;
+
+	return (sg_queue_cnt);
+}
+
+int
+AscIsrQDone(
+			   ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	uchar               next_qp;
+	uchar               i;
+	uchar               n_q_used;
+	uchar               sg_list_qp;
+	uchar               sg_queue_cnt;
+	uchar               done_q_tail;
+
+	uchar               tid_no;
+	ASC_SCSI_BIT_ID_TYPE scsi_busy;
+	ASC_SCSI_BIT_ID_TYPE target_id;
+	PortAddr            iop_base;
+	ushort              q_addr;
+	ushort              sg_q_addr;
+	uchar               cur_target_qng;
+	ASC_QDONE_INFO      scsiq_buf;
+	ASC_QDONE_INFO dosfar *scsiq;
+	int                 false_overrun;
+	ASC_ISR_CALLBACK    asc_isr_callback;
+
+	uchar               tag_code;
+
+#if CC_LINK_BUSY_Q
+	ushort              n_busy_q_done;
+
+#endif
+
+	iop_base = asc_dvc->iop_base;
+	asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+
+	n_q_used = 1;
+	scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf;
+	done_q_tail = (uchar) AscGetVarDoneQTail(iop_base);
+	q_addr = ASC_QNO_TO_QADDR(done_q_tail);
+	next_qp = AscReadLramByte(iop_base,
+							  (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD));
+	if (next_qp != ASC_QLINK_END) {
+
+		AscPutVarDoneQTail(iop_base, next_qp);
+		q_addr = ASC_QNO_TO_QADDR(next_qp);
+
+		sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
+
+		AscWriteLramByte(iop_base,
+						 (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+			 (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED)));
+		tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
+		target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
+		if ((scsiq->cntl & QC_SG_HEAD) != 0) {
+			sg_q_addr = q_addr;
+			sg_list_qp = next_qp;
+			for (i = 0; i < sg_queue_cnt; i++) {
+				sg_list_qp = AscReadLramByte(iop_base,
+						   (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD));
+				sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
+				if (sg_list_qp == ASC_QLINK_END) {
+					AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS);
+					scsiq->d3.done_stat = QD_WITH_ERROR;
+					scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED;
+					goto FATAL_ERR_QDONE;
+				}
+				AscWriteLramByte(iop_base,
+						 (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+								 QS_FREE);
+			}
+
+			n_q_used = sg_queue_cnt + 1;
+			AscPutVarDoneQTail(iop_base, sg_list_qp);
+		}
+		if (asc_dvc->queue_full_or_busy & target_id) {
+
+			cur_target_qng = AscReadLramByte(iop_base,
+			(ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix));
+			if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
+				scsi_busy = AscReadLramByte(iop_base,
+											(ushort) ASCV_SCSIBUSY_B);
+				scsi_busy &= ~target_id;
+				AscWriteLramByte(iop_base,
+								 (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+				asc_dvc->queue_full_or_busy &= ~target_id;
+			}
+		}
+		if (asc_dvc->cur_total_qng >= n_q_used) {
+			asc_dvc->cur_total_qng -= n_q_used;
+			if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
+				asc_dvc->cur_dvc_qng[tid_no]--;
+			}
+		} else {
+			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
+			scsiq->d3.done_stat = QD_WITH_ERROR;
+			goto FATAL_ERR_QDONE;
+		}
+
+		if ((scsiq->d2.srb_ptr == 0UL) ||
+			((scsiq->q_status & QS_ABORTED) != 0)) {
+
+			return (0x11);
+		} else if (scsiq->q_status == QS_DONE) {
+
+			false_overrun = FALSE;
+
+			if (asc_dvc->bug_fix_cntl) {
+				if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) {
+					tag_code = AscReadLramByte(iop_base,
+						 (ushort) (q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE));
+					if (tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) {
+						if (scsiq->remain_bytes != 0UL) {
+							scsiq->remain_bytes--;
+							if (scsiq->remain_bytes == 0UL) {
+								false_overrun = TRUE;
+							}
+						}
+					}
+				}
+			}
+			if ((scsiq->d3.done_stat == QD_WITH_ERROR) &&
+				(scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN)) {
+				if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) {
+					scsiq->d3.done_stat = QD_NO_ERROR;
+					scsiq->d3.host_stat = QHSTA_NO_ERROR;
+				} else if (false_overrun) {
+					scsiq->d3.done_stat = QD_NO_ERROR;
+					scsiq->d3.host_stat = QHSTA_NO_ERROR;
+				}
+			}
+#if CC_CLEAR_LRAM_SRB_PTR
+			AscWriteLramDWord(iop_base,
+							(ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
+							  asc_dvc->int_count);
+#endif
+
+			if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+				(*asc_isr_callback) (asc_dvc, scsiq);
+			} else {
+				if ((AscReadLramByte(iop_base,
+						  (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) ==
+					 SCSICMD_StartStopUnit)) {
+
+					asc_dvc->unit_not_ready &= ~target_id;
+					if (scsiq->d3.done_stat != QD_NO_ERROR) {
+						asc_dvc->start_motor &= ~target_id;
+					}
+				}
+			}
+
+#if CC_LINK_BUSY_Q
+			n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, tid_no);
+			if (n_busy_q_done == 0) {
+
+				i = tid_no + 1;
+				while (TRUE) {
+					if (i > ASC_MAX_TID)
+						i = 0;
+					if (i == tid_no)
+						break;
+					n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, i);
+					if (n_busy_q_done != 0)
+						break;
+					i++;
+				}
+			}
+			if (n_busy_q_done == 0xFFFF)
+				return (0x80);
+#endif
+
+			return (1);
+		} else {
+
+			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
+
+		  FATAL_ERR_QDONE:
+			if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+				(*asc_isr_callback) (asc_dvc, scsiq);
+			}
+			return (0x80);
+		}
+	}
+	return (0);
+}
+
+int
+AscISR(
+		  ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	ASC_CS_TYPE         chipstat;
+	PortAddr            iop_base;
+	ushort              saved_ram_addr;
+	uchar               ctrl_reg;
+	uchar               saved_ctrl_reg;
+	int                 int_pending;
+	int                 status;
+	uchar               host_flag;
+
+	iop_base = asc_dvc->iop_base;
+	int_pending = FALSE;
+
+	asc_dvc->int_count++;
+
+	if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) ||
+		(asc_dvc->isr_callback == 0)) {
+
+		return (ERR);
+	}
+	if (asc_dvc->in_critical_cnt != 0) {
+		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
+		return (ERR);
+	}
+	if (asc_dvc->is_in_int) {
+		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
+		asc_dvc->busy_count++;
+		return (ERR);
+	}
+	asc_dvc->is_in_int = TRUE;
+	ctrl_reg = AscGetChipControl(iop_base);
+	saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
+								   CC_SINGLE_STEP | CC_DIAG | CC_TEST));
+
+	if ((chipstat = AscGetChipStatus(iop_base)) & CSW_INT_PENDING) {
+		int_pending = TRUE;
+		AscAckInterrupt(iop_base);
+
+		host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B);
+		AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+						 (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR));
+		saved_ram_addr = AscGetChipLramAddr(iop_base);
+
+		if ((chipstat & CSW_HALTED) &&
+			(ctrl_reg & CC_SINGLE_STEP)) {
+			if (AscIsrChipHalted(asc_dvc) == ERR) {
+
+				goto ISR_REPORT_QDONE_FATAL_ERROR;
+
+			} else {
+				saved_ctrl_reg &= ~CC_HALT;
+			}
+		} else {
+		  ISR_REPORT_QDONE_FATAL_ERROR:
+			if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
+				while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) {
+
+				}
+			} else {
+				do {
+					if ((status = AscIsrQDone(asc_dvc)) == 1) {
+
+						break;
+					}
+				} while (status == 0x11);
+			}
+			if ((status & 0x80) != 0)
+				int_pending = ERR;
+		}
+		AscSetChipLramAddr(iop_base, saved_ram_addr);
+		if (AscGetChipLramAddr(iop_base) != saved_ram_addr) {
+			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SET_LRAM_ADDR);
+		}
+		AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+	}
+	AscSetChipControl(iop_base, saved_ctrl_reg);
+	asc_dvc->is_in_int = FALSE;
+	return (int_pending);
+}
+
+int
+AscScsiSetupCmdQ(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					ASC_SCSI_REQ_Q dosfar * scsiq,
+					uchar dosfar * buf_addr,
+					ulong buf_len
+)
+{
+	ulong               phy_addr;
+
+	scsiq->r1.cntl = 0;
+	scsiq->r1.sg_queue_cnt = 0;
+	scsiq->r1.q_no = 0;
+	scsiq->r1.user_def = 0;
+	scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
+	scsiq->r3.scsi_stat = 0;
+	scsiq->r3.scsi_msg = 0;
+	scsiq->r3.host_stat = 0;
+	scsiq->r3.done_stat = 0;
+	scsiq->r2.vm_id = 0;
+	scsiq->r1.data_cnt = buf_len;
+
+	scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE;
+	scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ;
+	scsiq->r2.srb_ptr = (ulong) scsiq;
+	scsiq->r1.status = (uchar) QS_READY;
+	scsiq->r1.data_addr = 0L;
+
+	if (buf_len != 0L) {
+		if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+					(uchar dosfar *) buf_addr, scsiq->r1.data_cnt)) == 0L) {
+			return (ERR);
+		}
+		scsiq->r1.data_addr = phy_addr;
+	}
+	return (0);
+}
+
+uchar               _mcode_buf[] =
+{
+	0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xDD, 0x0A, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x23, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x88, 0x00, 0x00, 0x00, 0x00,
+	0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC8, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
+	0xB6, 0x00, 0x36, 0x00, 0x06, 0xD6, 0x0D, 0xD2, 0x15, 0xDE, 0x12, 0xDA, 0x00, 0xA2, 0xC8, 0x00,
+	0x92, 0x80, 0xE0, 0x97, 0x50, 0x00, 0xF5, 0x00, 0x0A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00,
+	0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00, 0x0A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80,
+	0x80, 0x62, 0x92, 0x80, 0x00, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01,
+	0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDC, 0x00, 0x68, 0x97, 0x7F, 0x23, 0x04, 0x61,
+	0x84, 0x01, 0xB2, 0x84, 0xCF, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE8, 0x01,
+	0x68, 0x97, 0xD4, 0x81, 0x00, 0x33, 0x02, 0x00, 0x82, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01,
+	0x01, 0xA1, 0x08, 0x01, 0x4F, 0x00, 0x46, 0x97, 0x07, 0xA6, 0x12, 0x01, 0x00, 0x33, 0x03, 0x00,
+	0x82, 0x88, 0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, 0x00, 0x82, 0x88, 0xCE, 0x00, 0x69, 0x60,
+	0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x86, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x32, 0x01,
+	0x86, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x42, 0x01, 0x00, 0x33, 0x04, 0x00,
+	0x82, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x2A, 0x98, 0x4D, 0x04, 0xD0, 0x84,
+	0x05, 0xD8, 0x0D, 0x23, 0x2A, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xB8, 0x88, 0xFB, 0x23, 0x02, 0x61,
+	0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x70, 0x01, 0x00, 0x33, 0x0A, 0x00, 0x82, 0x88,
+	0x4E, 0x00, 0x07, 0xA3, 0x7C, 0x01, 0x00, 0x33, 0x0B, 0x00, 0x82, 0x88, 0xCD, 0x04, 0x36, 0x2D,
+	0x00, 0x33, 0x1A, 0x00, 0x82, 0x88, 0x50, 0x04, 0x96, 0x81, 0x06, 0xAB, 0x90, 0x01, 0x96, 0x81,
+	0x4E, 0x00, 0x07, 0xA3, 0xA0, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x4A, 0x01, 0x00, 0x05, 0x8A, 0x81,
+	0x08, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xCC, 0x81,
+	0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xC2, 0x01,
+	0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0x82, 0x88, 0x06, 0x23, 0x2A, 0x98,
+	0xCD, 0x04, 0xB2, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xE2, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE8, 0x01,
+	0xB2, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xB2, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2,
+	0x10, 0x02, 0x04, 0x01, 0x0D, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x46, 0x97, 0x0A, 0x82,
+	0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x24, 0x97, 0x48, 0x04, 0xFF, 0x23, 0x84, 0x80,
+	0xB2, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
+	0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x66, 0xEB, 0x11, 0x23, 0xB8, 0x88, 0xC6, 0x97, 0xFA, 0x80,
+	0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x3E, 0x02, 0x00, 0x33, 0x31, 0x00, 0x82, 0x88, 0x04, 0x01,
+	0x03, 0xD8, 0x74, 0x98, 0x02, 0x96, 0x50, 0x82, 0xA2, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
+	0xB6, 0x2D, 0x02, 0xA6, 0x7A, 0x02, 0x07, 0xA6, 0x68, 0x02, 0x06, 0xA6, 0x6C, 0x02, 0x03, 0xA6,
+	0x70, 0x02, 0x00, 0x33, 0x10, 0x00, 0x82, 0x88, 0x4A, 0x95, 0x52, 0x82, 0xF8, 0x95, 0x52, 0x82,
+	0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x16, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23,
+	0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23,
+	0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAC, 0x02, 0x07, 0xA6,
+	0x68, 0x02, 0x06, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x12, 0x00, 0x82, 0x88, 0x00, 0x0E, 0x80, 0x63,
+	0x00, 0x43, 0x00, 0xA0, 0x9A, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61,
+	0x84, 0x01, 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
+	0xEC, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE4, 0x02, 0x04, 0x01, 0x8E, 0xC8, 0x00, 0x33,
+	0x1F, 0x00, 0x82, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x40, 0x98, 0xB6, 0x2D,
+	0x01, 0xA6, 0x0E, 0x03, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x2A, 0x03, 0x06, 0xA6, 0x2E, 0x03,
+	0x03, 0xA6, 0xFA, 0x03, 0x02, 0xA6, 0x7A, 0x02, 0x00, 0x33, 0x33, 0x00, 0x82, 0x88, 0x08, 0x23,
+	0xB3, 0x01, 0x04, 0x01, 0x0E, 0xD0, 0x00, 0x33, 0x14, 0x00, 0x82, 0x88, 0x10, 0x23, 0xB3, 0x01,
+	0x04, 0x01, 0x07, 0xCC, 0x00, 0x33, 0x15, 0x00, 0x82, 0x88, 0x4A, 0x95, 0xF0, 0x82, 0xF8, 0x95,
+	0xF0, 0x82, 0x44, 0x98, 0x80, 0x42, 0x40, 0x98, 0x48, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05,
+	0x07, 0x01, 0x00, 0xA2, 0x72, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x48, 0x98, 0x40, 0x98,
+	0x00, 0xA6, 0x34, 0x03, 0x07, 0xA6, 0x6A, 0x03, 0x03, 0xA6, 0x16, 0x04, 0x06, 0xA6, 0x6E, 0x03,
+	0x01, 0xA6, 0x34, 0x03, 0x00, 0x33, 0x25, 0x00, 0x82, 0x88, 0x4A, 0x95, 0x50, 0x83, 0xF8, 0x95,
+	0x50, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0x82, 0x88, 0x00, 0x01,
+	0x05, 0x05, 0xFF, 0xA2, 0x90, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x4C, 0x83, 0x05, 0x05,
+	0x01, 0xA6, 0x9A, 0x03, 0x00, 0xA6, 0xAA, 0x03, 0xF0, 0x83, 0x68, 0x98, 0x80, 0x42, 0x01, 0xA6,
+	0x9A, 0x03, 0xBA, 0x83, 0x00, 0x33, 0x2F, 0x00, 0x82, 0x88, 0x68, 0x98, 0x80, 0x42, 0x00, 0xA6,
+	0xAA, 0x03, 0xBA, 0x83, 0x00, 0x33, 0x26, 0x00, 0x82, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36,
+	0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0xF0, 0x83, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33,
+	0x20, 0x00, 0x82, 0x88, 0x03, 0xA6, 0xEE, 0x03, 0x07, 0xA6, 0xE6, 0x03, 0x06, 0xA6, 0xEA, 0x03,
+	0x00, 0x33, 0x17, 0x00, 0x82, 0x88, 0x4A, 0x95, 0xD4, 0x83, 0xF8, 0x95, 0xD4, 0x83, 0xFA, 0x83,
+	0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0x82, 0x88, 0xB6, 0x2D, 0x03, 0xA6, 0x16, 0x04,
+	0x07, 0xA6, 0x0E, 0x04, 0x06, 0xA6, 0x12, 0x04, 0x00, 0x33, 0x30, 0x00, 0x82, 0x88, 0x4A, 0x95,
+	0xFA, 0x83, 0xF8, 0x95, 0xFA, 0x83, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x24, 0x04, 0x00, 0x33,
+	0x18, 0x00, 0x82, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x2E, 0x04, 0x23, 0x01,
+	0x00, 0xA2, 0x50, 0x04, 0x0A, 0xA0, 0x40, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0x82, 0x88,
+	0x0B, 0xA0, 0x4C, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0x82, 0x88, 0x42, 0x23, 0xB8, 0x88,
+	0x00, 0x23, 0x22, 0xA3, 0xB2, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x6C, 0x04, 0x28, 0x23, 0x22, 0xA3,
+	0x78, 0x04, 0x02, 0x23, 0x22, 0xA3, 0x8E, 0x04, 0x42, 0x23, 0xB8, 0x88, 0x4A, 0x00, 0x06, 0x61,
+	0x00, 0xA0, 0x78, 0x04, 0x45, 0x23, 0xB8, 0x88, 0xC6, 0x97, 0x00, 0xA2, 0x8A, 0x04, 0x74, 0x98,
+	0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF6, 0x81, 0x47, 0x23, 0xB8, 0x88, 0x04, 0x01,
+	0x0C, 0xDE, 0x14, 0x01, 0x00, 0xA2, 0xA6, 0x04, 0xC6, 0x97, 0x74, 0x98, 0x00, 0x33, 0x00, 0x81,
+	0xC0, 0x20, 0x81, 0x62, 0x10, 0x82, 0x43, 0x23, 0xB8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23,
+	0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xC0, 0x04, 0x00, 0x33, 0x27, 0x00, 0x82, 0x88,
+	0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xC6, 0x97, 0xF4, 0x94,
+	0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0xEE, 0x04, 0x00, 0x05, 0x76, 0x00,
+	0x06, 0x61, 0x00, 0xA2, 0xE8, 0x04, 0xD6, 0x84, 0x08, 0x97, 0xCD, 0x04, 0xF2, 0x84, 0x48, 0x04,
+	0xFF, 0x23, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x02, 0x85, 0x02, 0x23,
+	0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23,
+	0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01, 0x04, 0x01,
+	0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00,
+	0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x2E, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00,
+	0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xA0, 0x05, 0x03, 0x03,
+	0x02, 0xA0, 0x5C, 0x05, 0x9C, 0x85, 0x00, 0x33, 0x2D, 0x00, 0x82, 0x88, 0x04, 0xA0, 0x82, 0x05,
+	0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x6E, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23,
+	0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x24, 0x97, 0xD0, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01,
+	0xD0, 0x84, 0x08, 0xA0, 0x88, 0x05, 0x9C, 0x85, 0x03, 0xA0, 0x8E, 0x05, 0x9C, 0x85, 0x01, 0xA0,
+	0x9A, 0x05, 0x88, 0x00, 0x80, 0x63, 0x78, 0x96, 0x4A, 0x85, 0x88, 0x86, 0x80, 0x63, 0x4A, 0x85,
+	0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xDE, 0x05, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23,
+	0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0xC0, 0x05, 0x00, 0x33, 0x37, 0x00, 0x82, 0x88,
+	0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, 0xB8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
+	0xD8, 0x05, 0x00, 0x33, 0x38, 0x00, 0x82, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00,
+	0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xF2, 0x05, 0xC0, 0x23, 0x07, 0x41,
+	0x00, 0x63, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63,
+	0x00, 0x63, 0x06, 0xA6, 0x14, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x02, 0xA6, 0xBC, 0x06, 0x00, 0x33,
+	0x39, 0x00, 0x82, 0x88, 0x00, 0x00, 0x01, 0xA0, 0xD6, 0x06, 0xA2, 0x95, 0x83, 0x03, 0x80, 0x63,
+	0x06, 0xA6, 0x28, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63,
+	0x01, 0x00, 0x06, 0xA6, 0x40, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x33, 0x3A, 0x00, 0x82, 0x88,
+	0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x32, 0x06, 0x06, 0xA6, 0x58, 0x06, 0x07, 0xA6,
+	0x64, 0x06, 0x00, 0x33, 0x3B, 0x00, 0x82, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6,
+	0x64, 0x06, 0x00, 0x63, 0x03, 0x03, 0x80, 0x63, 0x88, 0x00, 0x01, 0xA2, 0x78, 0x06, 0x07, 0xA2,
+	0xBC, 0x06, 0x00, 0x33, 0x35, 0x00, 0x82, 0x88, 0x07, 0xA6, 0x82, 0x06, 0x00, 0x33, 0x2A, 0x00,
+	0x82, 0x88, 0x03, 0x03, 0x03, 0xA2, 0x8E, 0x06, 0x07, 0x23, 0x80, 0x00, 0xC8, 0x86, 0x80, 0x63,
+	0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0x9E, 0x06, 0x00, 0x33, 0x29, 0x00, 0x82, 0x88, 0x00, 0x43,
+	0x00, 0xA2, 0xAA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0x94, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80,
+	0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x00, 0x63, 0x80, 0x67, 0x00, 0x33,
+	0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x20, 0x06,
+	0x00, 0x33, 0x2C, 0x00, 0x82, 0x88, 0x0C, 0xA2, 0xF0, 0x06, 0xA2, 0x95, 0x83, 0x03, 0x80, 0x63,
+	0x06, 0xA6, 0xEE, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x33, 0x3D, 0x00, 0x82, 0x88, 0x00, 0x00,
+	0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x06, 0x07, 0x07, 0xA6, 0x64, 0x06, 0xBF, 0x23,
+	0x04, 0x61, 0x84, 0x01, 0xB2, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01,
+	0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05,
+	0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00,
+	0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00,
+	0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00,
+	0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04,
+	0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01,
+	0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0x86, 0x07,
+	0x00, 0x33, 0x07, 0x00, 0x82, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00,
+	0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2,
+	0xA6, 0x07, 0x00, 0x05, 0x9C, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05,
+	0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08,
+	0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02,
+	0x00, 0xA0, 0xD6, 0x07, 0xD8, 0x87, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
+	0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2,
+	0x06, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0xE6, 0x07,
+	0xC6, 0x97, 0xF4, 0x94, 0xE6, 0x87, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x1C, 0x88,
+	0x02, 0x01, 0x04, 0xD8, 0x08, 0x97, 0xC6, 0x97, 0xF4, 0x94, 0x0C, 0x88, 0x75, 0x00, 0x00, 0xA3,
+	0x26, 0x08, 0x00, 0x05, 0x10, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
+	0x38, 0x08, 0x00, 0x33, 0x3E, 0x00, 0x82, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63,
+	0x38, 0x2B, 0x5E, 0x88, 0x38, 0x2B, 0x54, 0x88, 0x32, 0x09, 0x31, 0x05, 0x54, 0x98, 0x05, 0x05,
+	0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32,
+	0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A,
+	0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0x74, 0x08, 0x5D, 0x00, 0xFE, 0xC3,
+	0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
+	0x13, 0x23, 0xB8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01,
+	0x81, 0x62, 0xA2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2,
+	0xF1, 0xC7, 0x41, 0x23, 0xB8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xB2, 0x84,
+
+};
+
+ushort              _mcode_size = sizeof (_mcode_buf);
+ulong               _mcode_chksum = 0x012258FBUL;
+
+extern uchar        _sdtr_period_tbl_[];
+
+int
+AscExeScsiQueue(
+				   ASC_DVC_VAR asc_ptr_type * asc_dvc,
+				   ASC_SCSI_Q dosfar * scsiq
+)
+{
+	PortAddr            iop_base;
+	int                 last_int_level;
+	int                 sta;
+	ulong               addr;
+	uchar               sg_entry_cnt;
+	uchar               target_ix;
+	int                 n_q_required;
+	uchar               sg_entry_cnt_minus_one;
+	uchar               tid_no;
+	uchar               sdtr_data;
+	ASC_EXE_CALLBACK    asc_exe_callback;
+
+#if CC_DEBUG_SG_LIST
+	int                 i;
+
+#endif
+#if CC_LINK_BUSY_Q
+	ASC_SCSI_Q dosfar  *scsiq_tail;
+	ASC_SCSI_Q dosfar  *scsiq_next;
+	ASC_SCSI_Q dosfar  *scsiq_prev;
+
+#endif
+
+	iop_base = asc_dvc->iop_base;
+	asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback;
+	if (asc_dvc->err_code != 0)
+		return (ERR);
+	if (scsiq == (ASC_SCSI_Q dosfar *) 0L) {
+		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
+		return (ERR);
+	}
+	scsiq->q1.q_no = 0;
+	sta = 0;
+	target_ix = scsiq->q2.target_ix;
+	tid_no = ASC_TIX_TO_TID(target_ix);
+
+	n_q_required = 1;
+
+	if (scsiq->cdbptr[0] == SCSICMD_RequestSense) {
+
+		if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
+			((asc_dvc->sdtr_done & scsiq->q1.target_id) != 0)) {
+			sdtr_data = AscReadLramByte(iop_base,
+				  (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no));
+			AscMsgOutSDTR(iop_base,
+						  _sdtr_period_tbl_[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)],
+						  (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
+			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+		}
+	}
+	last_int_level = DvcEnterCritical();
+	if (asc_dvc->in_critical_cnt != 0) {
+		DvcLeaveCritical(last_int_level);
+		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
+		return (ERR);
+	}
+	asc_dvc->in_critical_cnt++;
+
+	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+
+		if ((sg_entry_cnt = scsiq->sg_head->entry_cnt) == 0) {
+			asc_dvc->in_critical_cnt--;
+			DvcLeaveCritical(last_int_level);
+			return (ERR);
+		}
+		if (sg_entry_cnt == 1) {
+			scsiq->q1.data_addr = scsiq->sg_head->sg_list[0].addr;
+			scsiq->q1.data_cnt = scsiq->sg_head->sg_list[0].bytes;
+			scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+			goto NON_SG_LIST_REQ;
+		}
+		if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+
+			return (ERR);
+		}
+		sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+
+#if CC_DEBUG_SG_LIST
+		if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
+			for (i = 0; i < sg_entry_cnt_minus_one; i++) {
+
+				addr = scsiq->sg_head->sg_list[i].addr +
+				  scsiq->sg_head->sg_list[i].bytes;
+
+				if (((ushort) addr & 0x0003) != 0) {
+					asc_dvc->in_critical_cnt--;
+					DvcLeaveCritical(last_int_level);
+					AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_LIST_ODD_ADDRESS);
+					return (ERR);
+				}
+			}
+		}
+#endif
+
+		if (asc_dvc->bug_fix_cntl) {
+			if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) {
+
+				addr = scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr +
+				  scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
+				if (((ushort) addr & 0x0003) != 0) {
+					if ((scsiq->cdbptr[0] == SCSICMD_Read6) ||
+						(scsiq->cdbptr[0] == SCSICMD_Read10)) {
+						if ((scsiq->q2.tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) == 0) {
+
+							scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes++;
+							scsiq->q2.tag_code |= ASC_TAG_FLAG_ADD_ONE_BYTE;
+						}
+					}
+				}
+			}
+		}
+		scsiq->sg_head->entry_to_copy = scsiq->sg_head->entry_cnt;
+		n_q_required = AscSgListToQueue(sg_entry_cnt);
+
+#if CC_LINK_BUSY_Q
+		scsiq_next = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_head[tid_no];
+		if (scsiq_next != (ASC_SCSI_Q dosfar *) 0L) {
+			goto link_scisq_to_busy_list;
+		}
+#endif
+
+		if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required)
+			 >= (uint) n_q_required) ||
+			((scsiq->q1.cntl & QC_URGENT) != 0)) {
+			if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+										n_q_required)) == 1) {
+
+				asc_dvc->in_critical_cnt--;
+				if (asc_exe_callback != 0) {
+					(*asc_exe_callback) (asc_dvc, scsiq);
+				}
+				DvcLeaveCritical(last_int_level);
+				return (sta);
+			}
+		}
+	} else {
+
+	  NON_SG_LIST_REQ:
+
+		if (asc_dvc->bug_fix_cntl) {
+			if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) {
+
+				addr = scsiq->q1.data_addr + scsiq->q1.data_cnt;
+				if ((scsiq->cdbptr[0] == SCSICMD_Read6) ||
+					(scsiq->cdbptr[0] == SCSICMD_Read10)) {
+					if (((ushort) addr & 0x0003) != 0) {
+						if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) {
+
+							if ((scsiq->q2.tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) == 0) {
+
+								scsiq->q2.tag_code |= ASC_TAG_FLAG_ADD_ONE_BYTE;
+								scsiq->q1.data_cnt++;
+							}
+						}
+					}
+				}
+			}
+		}
+		n_q_required = 1;
+
+#if CC_LINK_BUSY_Q
+		scsiq_next = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_head[tid_no];
+		if (scsiq_next != (ASC_SCSI_Q dosfar *) 0L) {
+			goto link_scisq_to_busy_list;
+		}
+#endif
+		if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
+			((scsiq->q1.cntl & QC_URGENT) != 0)) {
+			if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+										n_q_required)) == 1) {
+
+				asc_dvc->in_critical_cnt--;
+				if (asc_exe_callback != 0) {
+					(*asc_exe_callback) (asc_dvc, scsiq);
+				}
+				DvcLeaveCritical(last_int_level);
+				return (sta);
+			}
+		}
+	}
+
+#if CC_LINK_BUSY_Q
+	if (sta == 0) {
+
+	  link_scisq_to_busy_list:
+		scsiq->ext.q_required = n_q_required;
+		if (scsiq_next == (ASC_SCSI_Q dosfar *) 0L) {
+			asc_dvc->scsiq_busy_head[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
+			asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
+			scsiq->ext.next = (ASC_SCSI_Q dosfar *) 0L;
+			scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L;
+			scsiq->q1.status = QS_BUSY;
+			sta = 1;
+		} else {
+			scsiq_tail = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_tail[tid_no];
+			if (scsiq_tail->ext.next == (ASC_SCSI_Q dosfar *) 0L) {
+				if ((scsiq->q1.cntl & QC_URGENT) != 0) {
+
+					asc_dvc->scsiq_busy_head[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
+					scsiq->ext.next = scsiq_next;
+					scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L;
+				} else {
+					if (scsiq->ext.cntl & QCX_SORT) {
+						do {
+							scsiq_prev = scsiq_next;
+							scsiq_next = scsiq_next->ext.next;
+							if (scsiq->ext.lba < scsiq_prev->ext.lba)
+								break;
+						} while (scsiq_next != (ASC_SCSI_Q dosfar *) 0L);
+
+						scsiq_prev->ext.next = scsiq;
+						scsiq->ext.next = scsiq_next;
+						if (scsiq_next == (ASC_SCSI_Q dosfar *) 0L) {
+							asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
+						}
+						scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L;
+					} else {
+
+						scsiq_tail->ext.next = (ASC_SCSI_Q dosfar *) scsiq;
+						asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq;
+						scsiq->ext.next = (ASC_SCSI_Q dosfar *) 0L;
+						scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L;
+					}
+				}
+				scsiq->q1.status = QS_BUSY;
+				sta = 1;
+			} else {
+
+				AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_BAD_NEXT_PTR);
+				sta = ERR;
+			}
+		}
+	}
+#endif
+	asc_dvc->in_critical_cnt--;
+	DvcLeaveCritical(last_int_level);
+	return (sta);
+}
+
+int
+AscSendScsiQueue(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					ASC_SCSI_Q dosfar * scsiq,
+					uchar n_q_required
+)
+{
+	PortAddr            iop_base;
+	uchar               free_q_head;
+	uchar               next_qp;
+	uchar               tid_no;
+	uchar               target_ix;
+	int                 sta;
+
+	iop_base = asc_dvc->iop_base;
+	target_ix = scsiq->q2.target_ix;
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	sta = 0;
+	free_q_head = (uchar) AscGetVarFreeQHead(iop_base);
+	if (n_q_required > 1) {
+		if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
+									   free_q_head, (uchar) (n_q_required)))
+			!= (uchar) ASC_QLINK_END) {
+			asc_dvc->last_q_shortage = 0;
+			scsiq->sg_head->queue_cnt = n_q_required - 1;
+			scsiq->q1.q_no = free_q_head;
+
+			if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
+											  free_q_head)) == 1) {
+
+#if CC_WRITE_IO_COUNT
+				asc_dvc->req_count++;
+#endif
+
+				AscPutVarFreeQHead(iop_base, next_qp);
+				asc_dvc->cur_total_qng += (uchar) (n_q_required);
+				asc_dvc->cur_dvc_qng[tid_no]++;
+			}
+			return (sta);
+		}
+	} else if (n_q_required == 1) {
+
+		if ((next_qp = AscAllocFreeQueue(iop_base,
+										 free_q_head)) != ASC_QLINK_END) {
+
+			scsiq->q1.q_no = free_q_head;
+			if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
+										free_q_head)) == 1) {
+
+#if CC_WRITE_IO_COUNT
+				asc_dvc->req_count++;
+#endif
+
+				AscPutVarFreeQHead(iop_base, next_qp);
+				asc_dvc->cur_total_qng++;
+				asc_dvc->cur_dvc_qng[tid_no]++;
+			}
+			return (sta);
+		}
+	}
+	return (sta);
+}
+
+int
+AscSgListToQueue(
+					int sg_list
+)
+{
+	int                 n_sg_list_qs;
+
+	n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
+	if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
+		n_sg_list_qs++;
+	return (n_sg_list_qs + 1);
+}
+
+uint
+AscGetNumOfFreeQueue(
+						ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						uchar target_ix, uchar n_qs
+)
+{
+	uint                cur_used_qs;
+	uint                cur_free_qs;
+	ASC_SCSI_BIT_ID_TYPE target_id;
+	uchar               tid_no;
+
+	target_id = ASC_TIX_TO_TARGET_ID(target_ix);
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	if ((asc_dvc->unit_not_ready & target_id) ||
+		(asc_dvc->queue_full_or_busy & target_id)) {
+		return (0);
+	}
+	if (n_qs == 1) {
+		cur_used_qs = (uint) asc_dvc->cur_total_qng +
+		  (uint) asc_dvc->last_q_shortage +
+		  (uint) ASC_MIN_FREE_Q;
+	} else {
+		cur_used_qs = (uint) asc_dvc->cur_total_qng +
+		  (uint) ASC_MIN_FREE_Q;
+	}
+
+	if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
+		cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
+		if (asc_dvc->cur_dvc_qng[tid_no] >=
+			asc_dvc->max_dvc_qng[tid_no]) {
+			return (0);
+		}
+		return (cur_free_qs);
+	}
+	if (n_qs > 1) {
+		if (n_qs > asc_dvc->last_q_shortage) {
+			asc_dvc->last_q_shortage = n_qs;
+		}
+	}
+	return (0);
+}
+
+int
+AscPutReadyQueue(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					ASC_SCSI_Q dosfar * scsiq,
+					uchar q_no
+)
+{
+	ushort              q_addr;
+	uchar               tid_no;
+	uchar               sdtr_data;
+	uchar               syn_period_ix;
+	uchar               syn_offset;
+	PortAddr            iop_base;
+
+	iop_base = asc_dvc->iop_base;
+
+	if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
+		((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
+
+		tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
+
+		sdtr_data = AscReadLramByte(iop_base,
+				  (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no));
+		syn_period_ix = (sdtr_data >> 4) & (ASC_SYN_XFER_NO - 1);
+		syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
+		AscMsgOutSDTR(iop_base,
+					  _sdtr_period_tbl_[syn_period_ix],
+					  syn_offset);
+
+		scsiq->q1.cntl |= QC_MSG_OUT;
+	}
+	q_addr = ASC_QNO_TO_QADDR(q_no);
+
+	if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
+		scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE;
+	}
+	scsiq->q1.status = QS_FREE;
+
+	AscMemWordCopyToLram(iop_base,
+						 (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG),
+						 (ushort dosfar *) scsiq->cdbptr,
+						 (ushort) ((ushort) scsiq->q2.cdb_len >> 1));
+
+#if !CC_LITTLE_ENDIAN_HOST
+	AscAdjEndianScsiQ(scsiq);
+#endif
+
+	DvcPutScsiQ(iop_base,
+				(ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG),
+				(ushort dosfar *) & scsiq->q1.cntl,
+	  (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1)));
+
+#if CC_WRITE_IO_COUNT
+	AscWriteLramWord(iop_base,
+					 (ushort) (q_addr + (ushort) ASC_SCSIQ_W_REQ_COUNT),
+					 (ushort) asc_dvc->req_count);
+
+#endif
+
+#if CC_VERIFY_LRAM_COPY
+	if ((asc_dvc->dvc_cntl & ASC_CNTL_NO_VERIFY_COPY) == 0) {
+
+		if (AscMemWordCmpToLram(iop_base,
+							 (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG),
+								(ushort dosfar *) scsiq->cdbptr,
+								(ushort) (scsiq->q2.cdb_len >> 1)) != 0) {
+			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM);
+			return (ERR);
+		}
+		if (AscMemWordCmpToLram(iop_base,
+							 (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG),
+								(ushort dosfar *) & scsiq->q1.cntl,
+		 (ushort) (((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))
+			!= 0) {
+			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM);
+			return (ERR);
+		}
+	}
+#endif
+
+#if CC_CLEAR_DMA_REMAIN
+
+	AscWriteLramDWord(iop_base,
+		   (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_ADDR), 0UL);
+	AscWriteLramDWord(iop_base,
+			(ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT), 0UL);
+
+#endif
+
+	AscWriteLramWord(iop_base,
+					 (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+			 (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY));
+	return (1);
+}
+
+int
+AscPutReadySgListQueue(
+						  ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						  ASC_SCSI_Q dosfar * scsiq,
+						  uchar q_no
+)
+{
+	uchar               sg_list_dwords;
+	uchar               sg_index, i;
+	uchar               sg_entry_cnt;
+	uchar               next_qp;
+	ushort              q_addr;
+	int                 sta;
+	ASC_SG_HEAD dosfar *sg_head;
+	ASC_SG_LIST_Q       scsi_sg_q;
+	ulong               saved_data_addr;
+	ulong               saved_data_cnt;
+	PortAddr            iop_base;
+
+	iop_base = asc_dvc->iop_base;
+
+	sg_head = scsiq->sg_head;
+
+	saved_data_addr = scsiq->q1.data_addr;
+	saved_data_cnt = scsiq->q1.data_cnt;
+	scsiq->q1.data_addr = sg_head->sg_list[0].addr;
+	scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
+	sg_entry_cnt = sg_head->entry_cnt - 1;
+	if (sg_entry_cnt != 0) {
+		scsiq->q1.cntl |= QC_SG_HEAD;
+		q_addr = ASC_QNO_TO_QADDR(q_no);
+		sg_index = 1;
+		scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
+		scsi_sg_q.sg_head_qp = q_no;
+		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+		for (i = 0; i < sg_head->queue_cnt; i++) {
+			scsi_sg_q.seq_no = i + 1;
+			if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+				sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
+				sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+				if (i == 0) {
+					scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q;
+					scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q;
+				} else {
+					scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+					scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
+				}
+			} else {
+
+				scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+				sg_list_dwords = sg_entry_cnt << 1;
+				if (i == 0) {
+					scsi_sg_q.sg_list_cnt = sg_entry_cnt;
+					scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt;
+				} else {
+					scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+					scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+				}
+				sg_entry_cnt = 0;
+			}
+			next_qp = AscReadLramByte(iop_base,
+									  (ushort) (q_addr + ASC_SCSIQ_B_FWD));
+			scsi_sg_q.q_no = next_qp;
+			q_addr = ASC_QNO_TO_QADDR(next_qp);
+
+			AscMemWordCopyToLram(iop_base,
+								 (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG),
+								 (ushort dosfar *) & scsi_sg_q,
+								 (ushort) (sizeof (ASC_SG_LIST_Q) >> 1));
+
+			AscMemDWordCopyToLram(iop_base,
+								  (ushort) (q_addr + ASC_SGQ_LIST_BEG),
+							  (ulong dosfar *) & sg_head->sg_list[sg_index],
+								  (ushort) sg_list_dwords);
+
+			sg_index += ASC_SG_LIST_PER_Q;
+		}
+	} else {
+
+		scsiq->q1.cntl &= ~QC_SG_HEAD;
+	}
+	sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
+
+	scsiq->q1.data_addr = saved_data_addr;
+	scsiq->q1.data_cnt = saved_data_cnt;
+	return (sta);
+}
+
+int
+AscAbortSRB(
+			   ASC_DVC_VAR asc_ptr_type * asc_dvc,
+			   ulong srb_ptr
+)
+{
+	int                 sta;
+	ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
+	PortAddr            iop_base;
+
+	iop_base = asc_dvc->iop_base;
+	sta = ERR;
+	saved_unit_not_ready = asc_dvc->unit_not_ready;
+	asc_dvc->unit_not_ready = 0xFF;
+	AscWaitISRDone(asc_dvc);
+	if (AscStopQueueExe(iop_base) == 1) {
+		if (AscRiscHaltedAbortSRB(asc_dvc, srb_ptr) == 1) {
+			sta = 1;
+			AscCleanUpBusyQueue(iop_base);
+			AscStartQueueExe(iop_base);
+
+		} else {
+			sta = 0;
+			AscStartQueueExe(iop_base);
+		}
+	}
+	asc_dvc->unit_not_ready = saved_unit_not_ready;
+	return (sta);
+}
+
+int
+AscResetDevice(
+				  ASC_DVC_VAR asc_ptr_type * asc_dvc,
+				  uchar target_ix
+)
+{
+	PortAddr            iop_base;
+	int                 sta;
+	uchar               tid_no;
+	ASC_SCSI_BIT_ID_TYPE target_id;
+	int                 i;
+	ASC_SCSI_REQ_Q      scsiq_buf;
+	ASC_SCSI_REQ_Q dosfar *scsiq;
+	uchar dosfar       *buf;
+	ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
+
+	iop_base = asc_dvc->iop_base;
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	target_id = ASC_TID_TO_TARGET_ID(tid_no);
+	saved_unit_not_ready = asc_dvc->unit_not_ready;
+	asc_dvc->unit_not_ready = target_id;
+	sta = ERR;
+	AscWaitTixISRDone(asc_dvc, target_ix);
+	if (AscStopQueueExe(iop_base) == 1) {
+		if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) {
+
+			AscCleanUpBusyQueue(iop_base);
+			AscStartQueueExe(iop_base);
+
+			AscWaitTixISRDone(asc_dvc, target_ix);
+
+			sta = TRUE;
+			scsiq = (ASC_SCSI_REQ_Q dosfar *) & scsiq_buf;
+			buf = (uchar dosfar *) & scsiq_buf;
+			for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) {
+				*buf++ = 0x00;
+			}
+
+			scsiq->r1.status = (uchar) QS_READY;
+			scsiq->r2.cdb_len = 6;
+			scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE;
+			scsiq->r1.target_id = target_id;
+
+			scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0);
+			scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
+
+			scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT;
+			AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG,
+							 M1_BUS_DVC_RESET);
+
+			asc_dvc->unit_not_ready &= ~target_id;
+
+			asc_dvc->sdtr_done |= target_id;
+
+			if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q dosfar *) scsiq)
+				== 1) {
+				asc_dvc->unit_not_ready = target_id;
+				DvcSleepMilliSecond(1000);
+				_AscWaitQDone(iop_base, (ASC_SCSI_Q dosfar *) scsiq);
+				if (AscStopQueueExe(iop_base) == 1) {
+
+					AscCleanUpDiscQueue(iop_base);
+					AscStartQueueExe(iop_base);
+					if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+
+						AscSetRunChipSynRegAtID(iop_base, tid_no,
+											 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+					}
+					AscWaitTixISRDone(asc_dvc, target_ix);
+				}
+			} else {
+
+				sta = 0;
+			}
+
+			asc_dvc->sdtr_done &= ~target_id;
+		} else {
+			sta = ERR;
+			AscStartQueueExe(iop_base);
+		}
+	}
+	asc_dvc->unit_not_ready = saved_unit_not_ready;
+	return (sta);
+}
+
+int
+AscResetSB(
+			  ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	int                 sta;
+	int                 i;
+	PortAddr            iop_base;
+
+	iop_base = asc_dvc->iop_base;
+	asc_dvc->unit_not_ready = 0xFF;
+	sta = TRUE;
+	AscWaitISRDone(asc_dvc);
+	AscStopQueueExe(iop_base);
+
+	asc_dvc->sdtr_done = 0;
+	AscResetChipAndScsiBus(iop_base);
+
+	DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+
+#if CC_SCAM
+	if (!(asc_dvc->dvc_cntl & ASC_CNTL_NO_SCAM)) {
+		AscSCAM(asc_dvc);
+	}
+#endif
+	AscReInitLram(asc_dvc);
+
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		asc_dvc->cur_dvc_qng[i] = 0;
+		if (asc_dvc->pci_fix_asyn_xfer & (0x01 << i)) {
+
+			AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+		}
+	}
+
+	asc_dvc->err_code = 0;
+
+	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+		sta = ERR;
+	}
+	if (AscStartChip(iop_base) == 0) {
+		sta = ERR;
+	}
+	AscStartQueueExe(iop_base);
+	asc_dvc->unit_not_ready = 0;
+	asc_dvc->queue_full_or_busy = 0;
+	return (sta);
+}
+
+int
+AscSetRunChipSynRegAtID(
+						   PortAddr iop_base,
+						   uchar tid_no,
+						   uchar sdtr_data
+)
+{
+	int                 sta = FALSE;
+
+	if (AscHostReqRiscHalt(iop_base)) {
+		sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+
+		AscStartChip(iop_base);
+		return (sta);
+	}
+	return (sta);
+}
+
+int
+AscSetChipSynRegAtID(
+						PortAddr iop_base,
+						uchar id,
+						uchar sdtr_data
+)
+{
+	AscSetBank(iop_base, 1);
+	AscWriteChipScsiID(iop_base, id);
+	if (AscReadChipScsiID(iop_base) != (0x01 << id)) {
+		return (FALSE);
+	}
+	AscSetBank(iop_base, 0);
+	AscWriteChipSyn(iop_base, sdtr_data);
+	if (AscReadChipSyn(iop_base) != sdtr_data) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+int
+AscReInitLram(
+				 ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	AscInitLram(asc_dvc);
+	AscInitQLinkVar(asc_dvc);
+	return (0);
+}
+
+ushort
+AscInitLram(
+			   ASC_DVC_VAR asc_ptr_type * asc_dvc)
+{
+	uchar               i;
+	ushort              s_addr;
+	PortAddr            iop_base;
+	ushort              warn_code;
+
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+
+	AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
+			   (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1)
+	  );
+
+	i = ASC_MIN_ACTIVE_QNO;
+	s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
+
+	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+					 (uchar) (i + 1));
+	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+					 (uchar) (asc_dvc->max_total_qng));
+	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+					 (uchar) i);
+	i++;
+	s_addr += ASC_QBLK_SIZE;
+	for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
+		AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+						 (uchar) (i + 1));
+		AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+						 (uchar) (i - 1));
+		AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+						 (uchar) i);
+	}
+
+	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+					 (uchar) ASC_QLINK_END);
+	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+					 (uchar) (asc_dvc->max_total_qng - 1));
+	AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+					 (uchar) asc_dvc->max_total_qng);
+	i++;
+	s_addr += ASC_QBLK_SIZE;
+
+	for (; i <= (uchar) (asc_dvc->max_total_qng + 3);
+		 i++, s_addr += ASC_QBLK_SIZE) {
+
+		AscWriteLramByte(iop_base,
+						 (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i);
+		AscWriteLramByte(iop_base,
+						 (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i);
+		AscWriteLramByte(iop_base,
+						 (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i);
+	}
+
+	return (warn_code);
+}
+
+ushort
+AscInitQLinkVar(
+				   ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	PortAddr            iop_base;
+	int                 i;
+	ushort              lram_addr;
+
+	iop_base = asc_dvc->iop_base;
+	AscPutRiscVarFreeQHead(iop_base, 1);
+	AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+
+	AscPutVarFreeQHead(iop_base, 1);
+	AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+
+	AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
+					 (uchar) ((int) asc_dvc->max_total_qng + 1));
+	AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
+					 (uchar) ((int) asc_dvc->max_total_qng + 2));
+
+	AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B,
+					 asc_dvc->max_total_qng);
+
+	AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
+	AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+	AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
+	AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
+
+	AscWriteLramByte(iop_base, (ushort) ASCV_CDBCNT_B, 0);
+
+	lram_addr = ASC_QADR_BEG;
+	for (i = 0; i < 32; i++, lram_addr += 2) {
+		AscWriteLramWord(iop_base, lram_addr, 0);
+	}
+
+	return (0);
+}
+
+int
+AscSetLibErrorCode(
+					  ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					  ushort err_code
+)
+{
+	if (asc_dvc->err_code == 0) {
+
+		asc_dvc->err_code = err_code;
+		AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
+						 err_code);
+	}
+	return (err_code);
+}
+
+int
+_AscWaitQDone(
+				 PortAddr iop_base,
+				 ASC_SCSI_Q dosfar * scsiq
+)
+{
+	ushort              q_addr;
+	uchar               q_status;
+	int                 count = 0;
+
+	while (scsiq->q1.q_no == 0) ;
+	q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no);
+
+	do {
+		q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS);
+		DvcSleepMilliSecond(100L);
+		if (count++ > 30) {
+			return (0);
+		}
+	} while ((q_status & QS_READY) != 0);
+	return (1);
+}
+
+uchar               _sdtr_period_tbl_[ASC_SYN_XFER_NO] =
+{
+	SYN_XFER_NS_0,
+	SYN_XFER_NS_1,
+	SYN_XFER_NS_2,
+	SYN_XFER_NS_3,
+	SYN_XFER_NS_4,
+	SYN_XFER_NS_5,
+	SYN_XFER_NS_6,
+	SYN_XFER_NS_7};
+
+uchar
+AscMsgOutSDTR(
+				 PortAddr iop_base,
+				 uchar sdtr_period,
+				 uchar sdtr_offset
+)
+{
+	SDTR_XMSG           sdtr_buf;
+	uchar               sdtr_period_index;
+
+	sdtr_buf.msg_type = MS_EXTEND;
+	sdtr_buf.msg_len = MS_SDTR_LEN;
+	sdtr_buf.msg_req = MS_SDTR_CODE;
+	sdtr_buf.xfer_period = sdtr_period;
+	sdtr_offset &= ASC_SYN_MAX_OFFSET;
+	sdtr_buf.req_ack_offset = sdtr_offset;
+	AscMemWordCopyToLram(iop_base, ASCV_MSGOUT_BEG,
+						 (ushort dosfar *) & sdtr_buf, SYN_XMSG_WLEN);
+	if ((sdtr_period_index = AscGetSynPeriodIndex(sdtr_period)) <=
+		ASC_MAX_SDTR_PERIOD_INDEX) {
+		return ((sdtr_period_index << 4) | sdtr_offset);
+	} else {
+
+		return (0);
+	}
+}
+
+uchar
+AscCalSDTRData(
+				  uchar sdtr_period,
+				  uchar syn_offset
+)
+{
+	uchar               byte;
+	uchar               sdtr_period_ix;
+
+	sdtr_period_ix = AscGetSynPeriodIndex(sdtr_period);
+	if ((sdtr_period_ix > ASC_MAX_SDTR_PERIOD_INDEX) ||
+		(sdtr_period_ix > ASC_SDTR_PERIOD_IX_MIN)) {
+		return (0xFF);
+	}
+	byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
+	return (byte);
+}
+
+void
+AscSetChipSDTR(
+				  PortAddr iop_base,
+				  uchar sdtr_data,
+				  uchar tid_no
+)
+{
+
+	AscWriteChipSyn(iop_base, sdtr_data);
+	AscWriteLramByte(iop_base,
+				   (ushort) ((ushort) ASCV_SDTR_DONE_BEG + (ushort) tid_no),
+					 sdtr_data);
+	return;
+}
+
+uchar
+AscGetSynPeriodIndex(
+						uchar syn_time
+)
+{
+	if ((syn_time >= SYN_XFER_NS_0) && (syn_time <= SYN_XFER_NS_7)) {
+		if (syn_time <= SYN_XFER_NS_6) {
+			if (syn_time <= SYN_XFER_NS_5) {
+				if (syn_time <= SYN_XFER_NS_4) {
+					if (syn_time <= SYN_XFER_NS_3) {
+						if (syn_time <= SYN_XFER_NS_2) {
+							if (syn_time <= SYN_XFER_NS_1) {
+								if (syn_time <= SYN_XFER_NS_0) {
+									return (0);
+								} else
+									return (1);
+							} else {
+								return (2);
+							}
+						} else {
+							return (3);
+						}
+					} else {
+						return (4);
+					}
+				} else {
+					return (5);
+				}
+			} else {
+				return (6);
+			}
+		} else {
+			return (7);
+		}
+	} else {
+
+		return (8);
+	}
+}
+
+uchar
+AscAllocFreeQueue(
+					 PortAddr iop_base,
+					 uchar free_q_head
+)
+{
+	ushort              q_addr;
+	uchar               next_qp;
+	uchar               q_status;
+
+	q_addr = ASC_QNO_TO_QADDR(free_q_head);
+	q_status = (uchar) AscReadLramByte(iop_base,
+									(ushort) (q_addr + ASC_SCSIQ_B_STATUS));
+	next_qp = AscReadLramByte(iop_base,
+							  (ushort) (q_addr + ASC_SCSIQ_B_FWD));
+	if (((q_status & QS_READY) == 0) &&
+		(next_qp != ASC_QLINK_END)) {
+		return (next_qp);
+	}
+	return (ASC_QLINK_END);
+}
+
+uchar
+AscAllocMultipleFreeQueue(
+							 PortAddr iop_base,
+							 uchar free_q_head,
+							 uchar n_free_q
+)
+{
+	uchar               i;
+
+	for (i = 0; i < n_free_q; i++) {
+		if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
+			== ASC_QLINK_END) {
+			return (ASC_QLINK_END);
+		}
+	}
+	return (free_q_head);
+}
+
+int
+AscRiscHaltedAbortSRB(
+						 ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						 ulong srb_ptr
+)
+{
+	PortAddr            iop_base;
+	ushort              q_addr;
+	uchar               q_no;
+	ASC_QDONE_INFO      scsiq_buf;
+	ASC_QDONE_INFO dosfar *scsiq;
+	ASC_ISR_CALLBACK    asc_isr_callback;
+	int                 last_int_level;
+
+	iop_base = asc_dvc->iop_base;
+	asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+	last_int_level = DvcEnterCritical();
+	scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf;
+
+#if CC_LINK_BUSY_Q
+	_AscAbortSrbBusyQueue(asc_dvc, scsiq, srb_ptr);
+#endif
+
+	for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
+		 q_no++) {
+		q_addr = ASC_QNO_TO_QADDR(q_no);
+		scsiq->d2.srb_ptr = AscReadLramDWord(iop_base,
+						   (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR));
+		if (scsiq->d2.srb_ptr == srb_ptr) {
+			_AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
+			if (((scsiq->q_status & QS_READY) != 0) &&
+				((scsiq->q_status & QS_ABORTED) == 0) &&
+				((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) {
+
+				scsiq->q_status |= QS_ABORTED;
+				scsiq->d3.done_stat = QD_ABORTED_BY_HOST;
+				AscWriteLramDWord(iop_base,
+							(ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
+								  0L);
+				AscWriteLramByte(iop_base,
+							(ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+								 scsiq->q_status);
+				(*asc_isr_callback) (asc_dvc, scsiq);
+				return (1);
+			}
+		}
+	}
+	DvcLeaveCritical(last_int_level);
+	return (0);
+}
+
+int
+AscRiscHaltedAbortTIX(
+						 ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						 uchar target_ix
+)
+{
+	PortAddr            iop_base;
+	ushort              q_addr;
+	uchar               q_no;
+	ASC_QDONE_INFO      scsiq_buf;
+	ASC_QDONE_INFO dosfar *scsiq;
+	ASC_ISR_CALLBACK    asc_isr_callback;
+	int                 last_int_level;
+
+#if CC_LINK_BUSY_Q
+	uchar               tid_no;
+
+#endif
+
+	iop_base = asc_dvc->iop_base;
+	asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+	last_int_level = DvcEnterCritical();
+	scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf;
+
+#if CC_LINK_BUSY_Q
+
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	_AscAbortTidBusyQueue(asc_dvc, scsiq, tid_no);
+
+#endif
+
+	for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng;
+		 q_no++) {
+		q_addr = ASC_QNO_TO_QADDR(q_no);
+		_AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count);
+		if (((scsiq->q_status & QS_READY) != 0) &&
+			((scsiq->q_status & QS_ABORTED) == 0) &&
+			((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) {
+			if (scsiq->d2.target_ix == target_ix) {
+				scsiq->q_status |= QS_ABORTED;
+				scsiq->d3.done_stat = QD_ABORTED_BY_HOST;
+
+				AscWriteLramDWord(iop_base,
+							(ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
+								  0L);
+
+				AscWriteLramByte(iop_base,
+							(ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+								 scsiq->q_status);
+				(*asc_isr_callback) (asc_dvc, scsiq);
+			}
+		}
+	}
+	DvcLeaveCritical(last_int_level);
+	return (1);
+}
+
+#if CC_LINK_BUSY_Q
+
+#endif
+
+int
+AscHostReqRiscHalt(
+					  PortAddr iop_base
+)
+{
+	int                 count = 0;
+	int                 sta = 0;
+	uchar               saved_stop_code;
+
+	if (AscIsChipHalted(iop_base))
+		return (1);
+	saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+
+	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+					 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP
+	  );
+	do {
+		if (AscIsChipHalted(iop_base)) {
+			sta = 1;
+			break;
+		}
+		DvcSleepMilliSecond(100);
+	} while (count++ < 20);
+
+	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
+	return (sta);
+}
+
+int
+AscStopQueueExe(
+				   PortAddr iop_base
+)
+{
+	int                 count;
+
+	count = 0;
+	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
+		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+						 ASC_STOP_REQ_RISC_STOP);
+		do {
+			if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
+				ASC_STOP_ACK_RISC_STOP) {
+				return (1);
+			}
+			DvcSleepMilliSecond(100);
+		} while (count++ < 20);
+	}
+	return (0);
+}
+
+int
+AscStartQueueExe(
+					PortAddr iop_base
+)
+{
+	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
+		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+	}
+	return (1);
+}
+
+int
+AscCleanUpBusyQueue(
+					   PortAddr iop_base
+)
+{
+	int                 count;
+	uchar               stop_code;
+
+	count = 0;
+	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
+		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+						 ASC_STOP_CLEAN_UP_BUSY_Q);
+		do {
+			stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+			if ((stop_code & ASC_STOP_CLEAN_UP_BUSY_Q) == 0)
+				break;
+			DvcSleepMilliSecond(100);
+		} while (count++ < 20);
+	}
+	return (1);
+}
+
+int
+AscCleanUpDiscQueue(
+					   PortAddr iop_base
+)
+{
+	int                 count;
+	uchar               stop_code;
+
+	count = 0;
+	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
+		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+						 ASC_STOP_CLEAN_UP_DISC_Q);
+		do {
+			stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+			if ((stop_code & ASC_STOP_CLEAN_UP_DISC_Q) == 0)
+				break;
+			DvcSleepMilliSecond(100);
+		} while (count++ < 20);
+	}
+	return (1);
+}
+
+int
+AscWaitTixISRDone(
+					 ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					 uchar target_ix
+)
+{
+	uchar               cur_req;
+	uchar               tid_no;
+
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	while (TRUE) {
+		if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) {
+			break;
+		}
+		DvcSleepMilliSecond(1000L);
+		if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) {
+			break;
+		}
+	}
+	return (1);
+}
+
+int
+AscWaitISRDone(
+				  ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	int                 tid;
+
+	for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+		AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid));
+	}
+	return (1);
+}
+
+ulong
+AscGetOnePhyAddr(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					uchar dosfar * buf_addr,
+					ulong buf_size
+)
+{
+	ASC_MIN_SG_HEAD     sg_head;
+
+	sg_head.entry_cnt = ASC_MIN_SG_LIST;
+	if (DvcGetSGList(asc_dvc, (uchar dosfar *) buf_addr,
+				  buf_size, (ASC_SG_HEAD dosfar *) & sg_head) != buf_size) {
+		return (0L);
+	}
+	if (sg_head.entry_cnt > 1) {
+		return (0L);
+	}
+	return (sg_head.sg_list[0].addr);
+}
+
+ulong
+AscGetEisaProductID(
+					   PortAddr iop_base
+)
+{
+	PortAddr            eisa_iop;
+	ushort              product_id_high, product_id_low;
+	ulong               product_id;
+
+	eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
+	product_id_low = inpw(eisa_iop);
+	product_id_high = inpw(eisa_iop + 2);
+	product_id = ((ulong) product_id_high << 16) | (ulong) product_id_low;
+	return (product_id);
+}
+
+PortAddr
+AscSearchIOPortAddrEISA(
+						   PortAddr iop_base
+)
+{
+	ulong               eisa_product_id;
+
+	if (iop_base == 0) {
+		iop_base = ASC_EISA_MIN_IOP_ADDR;
+	} else {
+		if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+			return (0);
+		if ((iop_base & 0x0050) == 0x0050) {
+			iop_base += ASC_EISA_BIG_IOP_GAP;
+		} else {
+			iop_base += ASC_EISA_SMALL_IOP_GAP;
+		}
+	}
+	while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
+
+		eisa_product_id = AscGetEisaProductID(iop_base);
+		if ((eisa_product_id == ASC_EISA_ID_740) ||
+			(eisa_product_id == ASC_EISA_ID_750)) {
+			if (AscFindSignature(iop_base)) {
+
+				inpw(iop_base + 4);
+				return (iop_base);
+			}
+		}
+		if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+			return (0);
+		if ((iop_base & 0x0050) == 0x0050) {
+			iop_base += ASC_EISA_BIG_IOP_GAP;
+		} else {
+			iop_base += ASC_EISA_SMALL_IOP_GAP;
+		}
+	}
+	return (0);
+}
+
+int
+AscStartChip(
+				PortAddr iop_base
+)
+{
+	AscSetChipControl(iop_base, 0);
+	if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+		return (0);
+	}
+	return (1);
+}
+
+int
+AscStopChip(
+			   PortAddr iop_base
+)
+{
+	uchar               cc_val;
+
+	cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
+	AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT));
+	AscSetChipIH(iop_base, INS_HALT);
+	AscSetChipIH(iop_base, INS_RFLAG_WTM);
+	if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
+		return (0);
+	}
+	return (1);
+}
+
+int
+AscIsChipHalted(
+				   PortAddr iop_base
+)
+{
+
+	if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+		if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
+			return (1);
+		}
+	}
+	return (0);
+}
+
+void
+AscSetChipIH(
+				PortAddr iop_base,
+				ushort ins_code
+)
+{
+	AscSetBank(iop_base, 1);
+	AscWriteChipIH(iop_base, ins_code);
+	AscSetBank(iop_base, 0);
+	return;
+}
+
+void
+AscAckInterrupt(
+				   PortAddr iop_base
+)
+{
+
+	uchar               host_flag;
+	uchar               risc_flag;
+	ushort              loop;
+
+	loop = 0;
+	do {
+		risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
+		if (loop++ > 0x7FFF) {
+			break;
+		}
+	} while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
+
+	host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B);
+	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+					 (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT));
+
+	AscSetChipStatus(iop_base, CIW_INT_ACK);
+	loop = 0;
+	while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
+
+		AscSetChipStatus(iop_base, CIW_INT_ACK);
+		if (loop++ > 3) {
+			break;
+		}
+	}
+
+	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+	return;
+}
+
+void
+AscDisableInterrupt(
+					   PortAddr iop_base
+)
+{
+	ushort              cfg;
+
+	cfg = AscGetChipCfgLsw(iop_base);
+	AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
+	return;
+}
+
+void
+AscEnableInterrupt(
+					  PortAddr iop_base
+)
+{
+	ushort              cfg;
+
+	cfg = AscGetChipCfgLsw(iop_base);
+	AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
+	return;
+}
+
+void
+AscSetBank(
+			  PortAddr iop_base,
+			  uchar bank
+)
+{
+	uchar               val;
+
+	val = AscGetChipControl(iop_base) &
+	  (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET));
+	if (bank == 1) {
+		val |= CC_BANK_ONE;
+	} else if (bank == 2) {
+		val |= CC_DIAG | CC_BANK_ONE;
+	} else {
+		val &= ~CC_BANK_ONE;
+	}
+	AscSetChipControl(iop_base, val);
+	return;
+}
+
+int
+AscResetChipAndScsiBus(
+						  PortAddr iop_base
+)
+{
+	AscStopChip(iop_base);
+	AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
+	DvcSleepMilliSecond(200);
+
+	AscSetChipIH(iop_base, INS_RFLAG_WTM);
+	AscSetChipIH(iop_base, INS_HALT);
+
+	AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
+	AscSetChipControl(iop_base, CC_HALT);
+	DvcSleepMilliSecond(200);
+	return (AscIsChipHalted(iop_base));
+}
+
+ushort
+AscGetIsaDmaChannel(
+					   PortAddr iop_base
+)
+{
+	ushort              channel;
+
+	channel = AscGetChipCfgLsw(iop_base) & 0x0003;
+	if (channel == 0x03)
+		return (0);
+	else if (channel == 0x00)
+		return (7);
+	return (channel + 4);
+}
+
+ushort
+AscSetIsaDmaChannel(
+					   PortAddr iop_base,
+					   ushort dma_channel
+)
+{
+	ushort              cfg_lsw;
+	uchar               value;
+
+	if ((dma_channel >= 5) && (dma_channel <= 7)) {
+
+		if (dma_channel == 7)
+			value = 0x00;
+		else
+			value = dma_channel - 4;
+		cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
+		cfg_lsw |= value;
+		AscSetChipCfgLsw(iop_base, cfg_lsw);
+		return (AscGetIsaDmaChannel(iop_base));
+	}
+	return (0);
+}
+
+uchar
+AscSetIsaDmaSpeed(
+					 PortAddr iop_base,
+					 uchar speed_value
+)
+{
+	speed_value &= 0x07;
+	AscSetBank(iop_base, 1);
+	AscSetChipDmaSpeed(iop_base, speed_value);
+	AscSetBank(iop_base, 0);
+	return (AscGetIsaDmaSpeed(iop_base));
+}
+
+uchar
+AscGetIsaDmaSpeed(
+					 PortAddr iop_base
+)
+{
+	uchar               speed_value;
+
+	AscSetBank(iop_base, 1);
+	speed_value = AscGetChipDmaSpeed(iop_base);
+	speed_value &= 0x07;
+	AscSetBank(iop_base, 0);
+	return (speed_value);
+}
+
+ulong
+AscGetMaxDmaCount(
+					 ushort bus_type
+)
+{
+	if (bus_type & ASC_IS_ISA)
+		return (ASC_MAX_ISA_DMA_COUNT);
+	else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
+		return (ASC_MAX_VL_DMA_COUNT);
+	return (ASC_MAX_PCI_DMA_COUNT);
+}
+
+ushort
+AscInitGetConfig(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	ushort              warn_code;
+
+	warn_code = 0;
+	asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
+	if (asc_dvc->err_code != 0)
+		return (UW_ERR);
+	if (AscFindSignature(asc_dvc->iop_base)) {
+		warn_code |= AscInitAscDvcVar(asc_dvc);
+		warn_code |= AscInitFromEEP(asc_dvc);
+		asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
+
+		if (asc_dvc->scsi_reset_wait > 10)
+			asc_dvc->scsi_reset_wait = 10;
+
+	} else {
+		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+	}
+	return (warn_code);
+}
+
+ushort
+AscInitSetConfig(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	ushort              warn_code;
+
+	warn_code = 0;
+	asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
+	if (asc_dvc->err_code != 0)
+		return (UW_ERR);
+	if (AscFindSignature(asc_dvc->iop_base)) {
+		warn_code |= AscInitFromAscDvcVar(asc_dvc);
+		asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
+	} else {
+		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+	}
+	return (warn_code);
+}
+
+ushort
+AscInitAsc1000Driver(
+						ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	ushort              warn_code;
+	PortAddr            iop_base;
+
+	extern ushort       _mcode_size;
+	extern ulong        _mcode_chksum;
+	extern uchar        _mcode_buf[];
+
+	ASC_DBG(3, "AscInitAsc1000Driver: begin\n");
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+
+	if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
+		!(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
+
+		ASC_DBG(3, "AscInitAsc1000Driver: AscResetChipAndScsiBus()\n");
+		AscResetChipAndScsiBus(iop_base);
+		DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+	}
+	asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
+	if (asc_dvc->err_code != 0)
+		return (UW_ERR);
+	ASC_DBG(3, "AscInitAsc1000Driver: AscFindSignature()\n");
+	if (!AscFindSignature(asc_dvc->iop_base)) {
+		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+		return (warn_code);
+	}
+	ASC_DBG(3, "AscInitAsc1000Driver: AscDisableInterrupt()\n");
+	AscDisableInterrupt(iop_base);
+
+	ASC_DBG(3, "AscInitAsc1000Driver: AscInitLram()\n");
+	warn_code |= AscInitLram(asc_dvc);
+	if (asc_dvc->err_code != 0)
+		return (UW_ERR);
+	ASC_DBG(3, "AscInitAsc1000Driver: AscLoadMicroCode()\n");
+	if (AscLoadMicroCode(iop_base, 0, (ushort dosfar *) _mcode_buf,
+						 _mcode_size) != _mcode_chksum) {
+		asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+		return (warn_code);
+	}
+	ASC_DBG(3, "AscInitAsc1000Driver: AscInitMicroCodeVar()\n");
+	warn_code |= AscInitMicroCodeVar(asc_dvc);
+	asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
+	ASC_DBG(3, "AscInitAsc1000Driver: AscEnableInterrupt()\n");
+	AscEnableInterrupt(iop_base);
+	return (warn_code);
+}
+
+ushort
+AscInitAscDvcVar(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	int                 i;
+	PortAddr            iop_base;
+	ushort              warn_code;
+
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	asc_dvc->err_code = 0;
+
+	if ((asc_dvc->bus_type &
+		 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
+		asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
+	}
+#if CC_LINK_BUSY_Q
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L;
+		asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L;
+	}
+#endif
+
+	asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
+	asc_dvc->bug_fix_cntl = 0;
+	asc_dvc->pci_fix_asyn_xfer = 0;
+	asc_dvc->init_sdtr = 0;
+	asc_dvc->sdtr_done = 0;
+	asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
+	asc_dvc->cur_total_qng = 0;
+	asc_dvc->is_in_int = 0;
+	asc_dvc->scsi_reset_wait = 3;
+	asc_dvc->in_critical_cnt = 0;
+
+	asc_dvc->last_q_shortage = 0;
+	asc_dvc->use_tagged_qng = 0;
+	asc_dvc->cfg->can_tagged_qng = 0;
+	asc_dvc->no_scam = 0;
+	asc_dvc->irq_no = 10;
+	asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
+	asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
+	asc_dvc->cfg->cmd_qng_enabled = ASC_SCSI_WIDTH_BIT_SET;
+	asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
+	asc_dvc->cfg->chip_version = AscGetChipVersion(iop_base,
+												   asc_dvc->bus_type);
+	if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
+
+		AscPutChipIFC(iop_base, IFC_INIT_DEFAULT);
+		asc_dvc->bus_type = ASC_IS_ISAPNP;
+	}
+	asc_dvc->unit_not_ready = 0;
+	asc_dvc->queue_full_or_busy = 0;
+
+	if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+		asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base);
+		asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
+	}
+	asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
+	asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
+	  ASC_LIB_VERSION_MINOR;
+	asc_dvc->int_count = 0L;
+	asc_dvc->req_count = 0L;
+	asc_dvc->busy_count = 0L;
+	asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
+
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		asc_dvc->cfg->sdtr_data[i] =
+		  (uchar) (ASC_DEF_SDTR_OFFSET | (ASC_DEF_SDTR_INDEX << 4));
+		asc_dvc->cur_dvc_qng[i] = 0;
+		asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
+		asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L;
+		asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L;
+	}
+	return (warn_code);
+}
+
+ushort
+AscInitFromAscDvcVar(
+						ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	PortAddr            iop_base;
+	ushort              cfg_msw;
+	ushort              warn_code;
+
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+
+	cfg_msw = AscGetChipCfgMsw(iop_base);
+
+	if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+		cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+		warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+		AscSetChipCfgMsw(iop_base, cfg_msw);
+	}
+	if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+		warn_code |= ASC_WARN_AUTO_CONFIG;
+
+	}
+	if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
+		asc_dvc->cfg->cmd_qng_enabled) {
+		asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
+		warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+	}
+	if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
+
+		if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
+			!= asc_dvc->irq_no) {
+			asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
+		}
+	}
+	if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
+		asc_dvc->cfg->chip_scsi_id) {
+		asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
+	}
+	if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+		AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
+		AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
+	}
+	return (warn_code);
+}
+
+ushort
+AscInitFromEEP(
+				  ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	ASCEEP_CONFIG       eep_config_buf;
+	ASCEEP_CONFIG dosfar *eep_config;
+	PortAddr            iop_base;
+	ushort              chksum;
+	ushort              warn_code;
+	ushort              cfg_msw, cfg_lsw;
+	uchar               i;
+
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+
+	AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
+
+	AscStopQueueExe(iop_base);
+	if ((AscStopChip(iop_base) == FALSE) ||
+		(AscGetChipScsiCtrl(iop_base) != 0)) {
+		asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
+		AscResetChipAndScsiBus(iop_base);
+		DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
+	}
+	if (AscIsChipHalted(iop_base) == FALSE) {
+		asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+		return (warn_code);
+	}
+	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+		asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+		return (warn_code);
+	}
+	eep_config = (ASCEEP_CONFIG dosfar *) & eep_config_buf;
+
+	cfg_msw = AscGetChipCfgMsw(iop_base);
+	cfg_lsw = AscGetChipCfgLsw(iop_base);
+
+	if (asc_dvc->bus_type & ASC_IS_PCI) {
+#if CC_DISABLE_PCI_PARITY_INT
+		cfg_msw &= 0xFFC0;
+		AscSetChipCfgMsw(iop_base, cfg_msw);
+#endif
+		if (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) {
+			asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ADD_ONE_BYTE;
+		}
+	}
+	if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+		cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+		warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+		AscSetChipCfgMsw(iop_base, cfg_msw);
+	}
+	chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+
+	eep_config->cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+
+	if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+		warn_code |= ASC_WARN_AUTO_CONFIG;
+
+		if (asc_dvc->cfg->chip_version == 3) {
+
+			if (eep_config->cfg_lsw != cfg_lsw) {
+				warn_code |= ASC_WARN_EEPROM_RECOVER;
+				eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base);
+			}
+			if (eep_config->cfg_msw != cfg_msw) {
+				warn_code |= ASC_WARN_EEPROM_RECOVER;
+				eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+			}
+		}
+	}
+	eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+	if (chksum != eep_config->chksum) {
+		warn_code |= ASC_WARN_EEPROM_CHKSUM;
+	}
+	asc_dvc->init_sdtr = eep_config->init_sdtr;
+	asc_dvc->cfg->disc_enable = eep_config->disc_enable;
+
+	asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
+	asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed;
+	asc_dvc->start_motor = eep_config->start_motor;
+	asc_dvc->dvc_cntl = eep_config->cntl;
+	asc_dvc->no_scam = eep_config->no_scam;
+
+	if ((asc_dvc->bus_type & ASC_IS_PCI) &&
+		!(asc_dvc->dvc_cntl & ASC_CNTL_NO_PCI_FIX_ASYN_XFER)) {
+		if ((asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
+			(asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
+			asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET;
+		}
+	} else if (asc_dvc->bus_type & ASC_IS_ISAPNP) {
+
+		if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
+			== ASC_CHIP_VER_ASYN_BUG) {
+			asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET;
+		}
+	}
+	if (!AscTestExternalLram(asc_dvc)) {
+		if (asc_dvc->bus_type & ASC_IS_PCI) {
+			eep_config->cfg_msw |= 0x0800;
+			cfg_msw |= 0x0800;
+			AscSetChipCfgMsw(iop_base, cfg_msw);
+			eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+			eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
+		}
+	} else {
+#if CC_TEST_RW_LRAM
+		asc_dvc->err_code |= AscTestLramEndian(iop_base);
+#endif
+	}
+	if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
+		eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
+	}
+	if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
+		eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
+	}
+	if (eep_config->max_tag_qng > eep_config->max_total_qng) {
+		eep_config->max_tag_qng = eep_config->max_total_qng;
+	}
+	if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
+		eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+	}
+	asc_dvc->max_total_qng = eep_config->max_total_qng;
+
+	if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
+		eep_config->use_cmd_qng) {
+		eep_config->disc_enable = eep_config->use_cmd_qng;
+		warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+	}
+	asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
+	eep_config->chip_scsi_id &= ASC_MAX_TID;
+	asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id;
+
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		asc_dvc->cfg->sdtr_data[i] = eep_config->sdtr_data[i];
+		asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+	}
+
+	eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+	if (AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type) != 0) {
+		asc_dvc->err_code |= ASC_IERR_WRITE_EEPROM;
+	}
+	return (warn_code);
+}
+
+ushort
+AscInitMicroCodeVar(
+					   ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	int                 i;
+	ushort              warn_code;
+	PortAddr            iop_base;
+	ulong               phy_addr;
+
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		AscWriteLramByte(iop_base, (ushort) (ASCV_SDTR_DATA_BEG + i),
+						 asc_dvc->cfg->sdtr_data[i]);
+	}
+
+	AscInitQLinkVar(asc_dvc);
+
+	AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+					 asc_dvc->cfg->disc_enable);
+	AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
+					 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+	if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+								 (uchar dosfar *) asc_dvc->cfg->overrun_buf,
+									 ASC_OVERRUN_BSIZE)) == 0L) {
+		asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR;
+	} else {
+
+		phy_addr = (phy_addr & 0xFFFFFFF8UL) + 8;
+		AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr);
+		AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D,
+						  ASC_OVERRUN_BSIZE - 8);
+	}
+
+	asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base,
+											   (ushort) ASCV_MC_DATE_W);
+	asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base,
+												  (ushort) ASCV_MC_VER_W);
+	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+		asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+		return (warn_code);
+	}
+	if (AscStartChip(iop_base) != 1) {
+		asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+		return (warn_code);
+	}
+	return (warn_code);
+}
+
+void                dosfar
+AscInitPollIsrCallBack(
+						  ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						  ASC_QDONE_INFO dosfar * scsi_done_q
+)
+{
+	ASC_SCSI_REQ_Q dosfar *scsiq_req;
+	ASC_ISR_CALLBACK    asc_isr_callback;
+	uchar               cp_sen_len;
+	uchar               i;
+
+	if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) {
+		scsiq_req = (ASC_SCSI_REQ_Q dosfar *) scsi_done_q->d2.srb_ptr;
+		ASC_DBG2(3, "AscInitPollIsrCallBack: done_stat %x, host_stat %x\n",
+				 scsiq_req->r3.done_stat, scsiq_req->r3.host_stat);
+		scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat;
+		scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat;
+		scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat;
+		scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg;
+		if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) &&
+			(scsi_done_q->d3.host_stat == 0)) {
+			cp_sen_len = (uchar) ASC_MIN_SENSE_LEN;
+			if (scsiq_req->r1.sense_len < ASC_MIN_SENSE_LEN) {
+				cp_sen_len = (uchar) scsiq_req->r1.sense_len;
+			}
+			for (i = 0; i < cp_sen_len; i++) {
+				scsiq_req->sense[i] = scsiq_req->sense_ptr[i];
+			}
+		}
+	} else {
+		ASC_DBG1(3, "AscInitPollIsrCallBack: isr_callback %x\n",
+				 (unsigned) asc_dvc->isr_callback);
+		if (asc_dvc->isr_callback != 0) {
+			asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
+			(*asc_isr_callback) (asc_dvc, scsi_done_q);
+		}
+	}
+	return;
+}
+
+int
+AscTestExternalLram(
+					   ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	PortAddr            iop_base;
+	ushort              q_addr;
+	ushort              saved_word;
+	int                 sta;
+
+	iop_base = asc_dvc->iop_base;
+	sta = 0;
+
+	q_addr = ASC_QNO_TO_QADDR(241);
+	saved_word = AscReadLramWord(iop_base, q_addr);
+	if (AscVerWriteLramWord(iop_base, q_addr, 0x55AA) == 0) {
+		sta = 1;
+		AscWriteLramWord(iop_base, q_addr, saved_word);
+	}
+	return (sta);
+}
+
+#if CC_TEST_LRAM_ENDIAN
+
+#endif
+
+int
+AscWriteEEPCmdReg(
+					 PortAddr iop_base,
+					 uchar cmd_reg
+)
+{
+	uchar               read_back;
+	int                 retry;
+
+	retry = 0;
+	while (TRUE) {
+		AscSetChipEEPCmd(iop_base, cmd_reg);
+		DvcSleepMilliSecond(1);
+		read_back = AscGetChipEEPCmd(iop_base);
+		if (read_back == cmd_reg) {
+			return (1);
+		}
+		if (retry++ > ASC_EEP_MAX_RETRY) {
+			return (0);
+		}
+	}
+}
+
+int
+AscWriteEEPDataReg(
+					  PortAddr iop_base,
+					  ushort data_reg
+)
+{
+	ushort              read_back;
+	int                 retry;
+
+	retry = 0;
+	while (TRUE) {
+		AscSetChipEEPData(iop_base, data_reg);
+		DvcSleepMilliSecond(1);
+		read_back = AscGetChipEEPData(iop_base);
+		if (read_back == data_reg) {
+			return (1);
+		}
+		if (retry++ > ASC_EEP_MAX_RETRY) {
+			return (0);
+		}
+	}
+}
+
+void
+AscWaitEEPRead(
+				  void
+)
+{
+	DvcSleepMilliSecond(1);
+	return;
+}
+
+void
+AscWaitEEPWrite(
+				   void
+)
+{
+	DvcSleepMilliSecond(20);
+	return;
+}
+
+ushort
+AscReadEEPWord(
+				  PortAddr iop_base,
+				  uchar addr
+)
+{
+	ushort              read_wval;
+	uchar               cmd_reg;
+
+	AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+	AscWaitEEPRead();
+	cmd_reg = addr | ASC_EEP_CMD_READ;
+	AscWriteEEPCmdReg(iop_base, cmd_reg);
+	AscWaitEEPRead();
+	read_wval = AscGetChipEEPData(iop_base);
+	AscWaitEEPRead();
+	return (read_wval);
+}
+
+ushort
+AscWriteEEPWord(
+				   PortAddr iop_base,
+				   uchar addr,
+				   ushort word_val
+)
+{
+	ushort              read_wval;
+
+	read_wval = AscReadEEPWord(iop_base, addr);
+	if (read_wval != word_val) {
+		AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
+		AscWaitEEPRead();
+
+		AscWriteEEPDataReg(iop_base, word_val);
+		AscWaitEEPRead();
+
+		AscWriteEEPCmdReg(iop_base,
+						  (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr));
+		AscWaitEEPWrite();
+
+		AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+		AscWaitEEPRead();
+		return (AscReadEEPWord(iop_base, addr));
+	}
+	return (read_wval);
+}
+
+ushort
+AscGetEEPConfig(
+				   PortAddr iop_base,
+				   ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type
+)
+{
+	ushort              wval;
+	ushort              sum;
+	ushort dosfar      *wbuf;
+	int                 cfg_beg;
+	int                 cfg_end;
+	int                 s_addr;
+	int                 isa_pnp_wsize;
+
+	wbuf = (ushort dosfar *) cfg_buf;
+	sum = 0;
+
+	isa_pnp_wsize = 0;
+	for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) {
+		wval = AscReadEEPWord(iop_base, (uchar) s_addr);
+		sum += wval;
+		*wbuf = wval;
+	}
+
+	if (bus_type & ASC_IS_VL) {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+	} else {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR;
+	}
+
+	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1);
+		 s_addr++, wbuf++) {
+		wval = AscReadEEPWord(iop_base, (uchar) s_addr);
+		sum += wval;
+		*wbuf = wval;
+	}
+	*wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
+	return (sum);
+}
+
+int
+AscSetEEPConfigOnce(
+					   PortAddr iop_base,
+					   ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type
+)
+{
+	int                 n_error;
+	ushort dosfar      *wbuf;
+	ushort              sum;
+	int                 s_addr;
+	int                 cfg_beg;
+	int                 cfg_end;
+
+	wbuf = (ushort dosfar *) cfg_buf;
+	n_error = 0;
+	sum = 0;
+	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+		sum += *wbuf;
+		if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
+			n_error++;
+		}
+	}
+	if (bus_type & ASC_IS_VL) {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+	} else {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR;
+	}
+	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1);
+		 s_addr++, wbuf++) {
+		sum += *wbuf;
+		if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
+			n_error++;
+		}
+	}
+	*wbuf = sum;
+	if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) {
+		n_error++;
+	}
+	wbuf = (ushort dosfar *) cfg_buf;
+	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+		if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
+			n_error++;
+		}
+	}
+	for (s_addr = cfg_beg; s_addr <= cfg_end;
+		 s_addr++, wbuf++) {
+		if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
+			n_error++;
+		}
+	}
+	return (n_error);
+}
+
+int
+AscSetEEPConfig(
+				   PortAddr iop_base,
+				   ASCEEP_CONFIG dosfar * cfg_buf, ushort bus_type
+)
+{
+	int                 retry;
+	int                 n_error;
+
+	retry = 0;
+	while (TRUE) {
+		if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
+										   bus_type)) == 0) {
+			break;
+		}
+		if (++retry > ASC_EEP_MAX_RETRY) {
+			break;
+		}
+	}
+	return (n_error);
+}
+
+int
+AscInitPollBegin(
+					ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	PortAddr            iop_base;
+
+	iop_base = asc_dvc->iop_base;
+
+#if CC_INIT_INQ_DISPLAY
+	DvcDisplayString((uchar dosfar *) "\r\n");
+#endif
+
+	AscDisableInterrupt(iop_base);
+
+	asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY;
+
+	AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, 0x00);
+	asc_dvc->use_tagged_qng = 0;
+	asc_dvc->cfg->can_tagged_qng = 0;
+	asc_dvc->saved_ptr2func = (ulong) asc_dvc->isr_callback;
+	asc_dvc->isr_callback = ASC_GET_PTR2FUNC(AscInitPollIsrCallBack);
+	return (0);
+}
+
+int
+AscInitPollEnd(
+				  ASC_DVC_VAR asc_ptr_type * asc_dvc
+)
+{
+	PortAddr            iop_base;
+	int                 i;
+
+	iop_base = asc_dvc->iop_base;
+	asc_dvc->isr_callback = (Ptr2Func) asc_dvc->saved_ptr2func;
+	AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+					 asc_dvc->cfg->disc_enable);
+	AscWriteLramByte(iop_base, ASCV_USE_TAGGED_QNG_B,
+					 asc_dvc->use_tagged_qng);
+	AscWriteLramByte(iop_base, ASCV_CAN_TAGGED_QNG_B,
+					 asc_dvc->cfg->can_tagged_qng);
+
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		AscWriteLramByte(iop_base,
+					  (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) i),
+						 asc_dvc->max_dvc_qng[i]);
+	}
+
+	AscEnableInterrupt(iop_base);
+
+#if CC_INIT_INQ_DISPLAY
+	DvcDisplayString((uchar dosfar *) "\r\n");
+#endif
+	asc_dvc->init_state |= ASC_INIT_STATE_END_INQUIRY;
+
+	return (0);
+}
+
+int                 _asc_wait_slow_device_ = FALSE;
+
+int
+AscInitPollTarget(
+					 ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					 ASC_SCSI_REQ_Q dosfar * scsiq,
+					 ASC_SCSI_INQUIRY dosfar * inq,
+					 ASC_CAP_INFO dosfar * cap_info
+)
+{
+	uchar               tid_no, lun;
+	uchar               dvc_type;
+	ASC_SCSI_BIT_ID_TYPE tid_bits;
+	int                 dvc_found;
+	int                 support_read_cap;
+	int                 tmp_disable_init_sdtr;
+	ulong               phy_addr;
+
+	dvc_found = 0;
+	tmp_disable_init_sdtr = FALSE;
+	tid_bits = scsiq->r1.target_id;
+	lun = scsiq->r1.target_lun;
+	tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix);
+	if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+									 (uchar dosfar *) scsiq->sense_ptr,
+									 (ulong) scsiq->r1.sense_len)) == 0L) {
+		return (ERR);
+	}
+	scsiq->r1.sense_addr = phy_addr;
+	if (((asc_dvc->init_sdtr & tid_bits) != 0) &&
+		((asc_dvc->sdtr_done & tid_bits) == 0)) {
+
+		asc_dvc->init_sdtr &= ~tid_bits;
+		tmp_disable_init_sdtr = TRUE;
+	}
+	ASC_DBG(3, "AscInitPollTarget: PollScsiInquiry()\n");
+	if (PollScsiInquiry(asc_dvc, scsiq, (uchar dosfar *) inq,
+						sizeof (ASC_SCSI_INQUIRY)) == 1) {
+		dvc_found = 1;
+		support_read_cap = TRUE;
+		dvc_type = inq->byte0.peri_dvc_type;
+		if (dvc_type != SCSI_TYPE_UNKNOWN) {
+			if ((dvc_type != SCSI_TYPE_DASD) &&
+				(dvc_type != SCSI_TYPE_WORM) &&
+				(dvc_type != SCSI_TYPE_CDROM) &&
+				(dvc_type != SCSI_TYPE_OPTMEM)) {
+				asc_dvc->start_motor &= ~tid_bits;
+				support_read_cap = FALSE;
+			}
+			if ((dvc_type != SCSI_TYPE_DASD) ||
+				inq->byte1.rmb) {
+
+				if (!_asc_wait_slow_device_) {
+					DvcSleepMilliSecond(3000 - ((int) tid_no * 250));
+					_asc_wait_slow_device_ = TRUE;
+				}
+			}
+#if CC_INIT_INQ_DISPLAY
+			AscDispInquiry(tid_no, lun, inq);
+#endif
+
+			if (lun == 0) {
+
+				if ((inq->byte3.rsp_data_fmt >= 2) ||
+					(inq->byte2.ansi_apr_ver >= 2)) {
+
+					if (inq->byte7.CmdQue) {
+						asc_dvc->cfg->can_tagged_qng |= tid_bits;
+						if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) {
+							asc_dvc->use_tagged_qng |= tid_bits;
+							asc_dvc->max_dvc_qng[tid_no] =
+							  asc_dvc->cfg->max_tag_qng[tid_no];
+						}
+					}
+					if (!inq->byte7.Sync) {
+
+						asc_dvc->init_sdtr &= ~tid_bits;
+						asc_dvc->sdtr_done &= ~tid_bits;
+					} else if (tmp_disable_init_sdtr) {
+
+						asc_dvc->init_sdtr |= tid_bits;
+					}
+				} else {
+
+					asc_dvc->init_sdtr &= ~tid_bits;
+					asc_dvc->sdtr_done &= ~tid_bits;
+					asc_dvc->use_tagged_qng &= ~tid_bits;
+				}
+			}
+			if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
+				if (!(asc_dvc->init_sdtr & tid_bits)) {
+
+					AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
+											ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+				}
+			}
+			ASC_DBG(3, "AscInitPollTarget: InitTestUnitReady()\n");
+			if (InitTestUnitReady(asc_dvc, scsiq) != 1) {
+
+			} else {
+				if ((cap_info != 0L) && support_read_cap) {
+					ASC_DBG(3, "AscInitPollTarget: PollScsiReadCapacity()\n");
+					if (PollScsiReadCapacity(asc_dvc, scsiq,
+											 cap_info) != 1) {
+						cap_info->lba = 0L;
+						cap_info->blk_size = 0x0000;
+					} else {
+
+					}
+				}
+			}
+		} else {
+			asc_dvc->start_motor &= ~tid_bits;
+		}
+	} else {
+
+	}
+	return (dvc_found);
+}
+
+int
+PollQueueDone(
+				 ASC_DVC_VAR asc_ptr_type * asc_dvc,
+				 ASC_SCSI_REQ_Q dosfar * scsiq,
+				 int timeout_sec
+)
+{
+	int                 status;
+	int                 retry;
+
+	retry = 0;
+	do {
+		ASC_DBG(3, "PollQueueDone: AscExeScsiQueue()\n");
+		if ((status = AscExeScsiQueue(asc_dvc,
+									  (ASC_SCSI_Q dosfar *) scsiq)) == 1) {
+			ASC_DBG(3, "PollQueueDone: AscPollQDone()\n");
+			if ((status = AscPollQDone(asc_dvc, scsiq,
+									   timeout_sec)) != 1) {
+				ASC_DBG1(3, "PollQueueDone: AscPollQDone() status %x\n", status);
+				if (status == 0x80) {
+					if (retry++ > ASC_MAX_INIT_BUSY_RETRY) {
+						break;
+					}
+					scsiq->r3.done_stat = 0;
+					scsiq->r3.host_stat = 0;
+					scsiq->r3.scsi_stat = 0;
+					scsiq->r3.scsi_msg = 0;
+					DvcSleepMilliSecond(100);
+					continue;
+				}
+				scsiq->r3.done_stat = 0;
+				scsiq->r3.host_stat = 0;
+				scsiq->r3.scsi_stat = 0;
+				scsiq->r3.scsi_msg = 0;
+				ASC_DBG1(3, "PollQueueDone: AscAbortSRB() scsiq %x\n",
+						 (unsigned) scsiq);
+
+				AscAbortSRB(asc_dvc, (ulong) scsiq);
+			}
+			ASC_DBG1(3, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
+			return (scsiq->r3.done_stat);
+		}
+	} while ((status == 0) || (status == 0x80));
+	ASC_DBG(3, "PollQueueDone: done_stat QD_WITH_ERROR\n");
+	return (scsiq->r3.done_stat = QD_WITH_ERROR);
+}
+
+int
+PollScsiInquiry(
+				   ASC_DVC_VAR asc_ptr_type * asc_dvc,
+				   ASC_SCSI_REQ_Q dosfar * scsiq,
+				   uchar dosfar * buf,
+				   int buf_len
+)
+{
+	if (AscScsiInquiry(asc_dvc, scsiq, buf, buf_len) == ERR) {
+		return (scsiq->r3.done_stat = QD_WITH_ERROR);
+	}
+	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 4));
+}
+
+int
+PollScsiReadCapacity(
+						ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						ASC_SCSI_REQ_Q dosfar * scsiq,
+						ASC_CAP_INFO dosfar * cap_info
+)
+{
+	ASC_CAP_INFO        scsi_cap_info;
+	int                 status;
+
+	if (AscScsiReadCapacity(asc_dvc, scsiq,
+							(uchar dosfar *) & scsi_cap_info) == ERR) {
+		return (scsiq->r3.done_stat = QD_WITH_ERROR);
+	}
+	status = PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 8);
+	if (status == 1) {
+#if CC_LITTLE_ENDIAN_HOST
+		cap_info->lba = (ulong) * swapfarbuf4((uchar dosfar *) & scsi_cap_info.lba);
+		cap_info->blk_size = (ulong) * swapfarbuf4((uchar dosfar *) & scsi_cap_info.blk_size);
+#else
+		cap_info->lba = scsi_cap_info.lba;
+		cap_info->blk_size = scsi_cap_info.blk_size;
+#endif
+		return (scsiq->r3.done_stat);
+	}
+	return (scsiq->r3.done_stat = QD_WITH_ERROR);
+}
+
+ulong dosfar       *
+swapfarbuf4(
+			   uchar dosfar * buf
+)
+{
+	uchar               tmp;
+
+	tmp = buf[3];
+	buf[3] = buf[0];
+	buf[0] = tmp;
+
+	tmp = buf[1];
+	buf[1] = buf[2];
+	buf[2] = tmp;
+
+	return ((ulong dosfar *) buf);
+}
+
+int
+PollScsiTestUnitReady(
+						 ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						 ASC_SCSI_REQ_Q dosfar * scsiq
+)
+{
+	if (AscScsiTestUnitReady(asc_dvc, scsiq) == ERR) {
+		return (scsiq->r3.done_stat = QD_WITH_ERROR);
+	}
+	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 12));
+}
+
+int
+PollScsiStartUnit(
+					 ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					 ASC_SCSI_REQ_Q dosfar * scsiq
+)
+{
+	if (AscScsiStartStopUnit(asc_dvc, scsiq, 1) == ERR) {
+		return (scsiq->r3.done_stat = QD_WITH_ERROR);
+	}
+	return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 40));
+}
+
+int
+InitTestUnitReady(
+					 ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					 ASC_SCSI_REQ_Q dosfar * scsiq
+)
+{
+	ASC_SCSI_BIT_ID_TYPE tid_bits;
+	int                 retry;
+	ASC_REQ_SENSE dosfar *sen;
+
+	retry = 0;
+	tid_bits = scsiq->r1.target_id;
+	while (retry++ < 2) {
+		ASC_DBG(3, "InitTestUnitReady: PollScsiTestUnitReady()\n");
+		PollScsiTestUnitReady(asc_dvc, scsiq);
+		ASC_DBG1(3, "InitTestUnitReady: done_stat %x\n", scsiq->r3.done_stat);
+		if (scsiq->r3.done_stat == 0x01) {
+			return (1);
+		} else if (scsiq->r3.done_stat == QD_WITH_ERROR) {
+			DvcSleepMilliSecond(100);
+
+			sen = (ASC_REQ_SENSE dosfar *) scsiq->sense_ptr;
+
+			if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) &&
+				((sen->err_code & 0x70) != 0)) {
+
+				if (sen->sense_key == SCSI_SENKEY_NOT_READY) {
+
+					if (asc_dvc->start_motor & tid_bits) {
+						if (PollScsiStartUnit(asc_dvc, scsiq) == 1) {
+							retry = 0;
+							continue;
+						} else {
+							asc_dvc->start_motor &= ~tid_bits;
+							break;
+						}
+					} else {
+						DvcSleepMilliSecond(100);
+					}
+				} else if (sen->sense_key == SCSI_SENKEY_ATTENSION) {
+					DvcSleepMilliSecond(100);
+				} else {
+					break;
+				}
+			} else {
+				break;
+			}
+		} else if (scsiq->r3.done_stat == QD_ABORTED_BY_HOST) {
+			break;
+		} else {
+			break;
+		}
+	}
+	return (0);
+}
+
+#if CC_INIT_INQ_DISPLAY
+
+#endif
+
+int
+AscPollQDone(
+				ASC_DVC_VAR asc_ptr_type * asc_dvc,
+				ASC_SCSI_REQ_Q dosfar * scsiq,
+				int timeout_sec
+)
+{
+	int                 loop, loop_end;
+	int                 sta;
+	PortAddr            iop_base;
+
+	iop_base = asc_dvc->iop_base;
+	loop = 0;
+	loop_end = timeout_sec * 100;
+	sta = 1;
+
+	while (TRUE) {
+		ASC_DBG4(3,
+		 "AscPollQDone: loop %d, err_code %x, done_stat %x, scsi_stat %x\n",
+		 loop, asc_dvc->err_code, scsiq->r3.done_stat, scsiq->r3.scsi_stat);
+		if (asc_dvc->err_code != 0) {
+			scsiq->r3.done_stat = QD_WITH_ERROR;
+			sta = ERR;
+			break;
+		}
+		if (scsiq->r3.done_stat != QD_IN_PROGRESS) {
+			if ((scsiq->r3.done_stat == QD_WITH_ERROR) &&
+				(scsiq->r3.scsi_stat == SS_TARGET_BUSY)) {
+				sta = 0x80;
+				break;
+			}
+			break;
+		}
+		DvcSleepMilliSecond(10);
+		if (loop++ > loop_end) {
+			sta = 0;
+			break;
+		}
+		if (AscIsChipHalted(iop_base)) {
+			AscISR(asc_dvc);
+			loop = 0;
+		} else {
+			ASC_DBG(3, "AscPollQDone: AscIsIntPending()\n");
+			if (AscIsIntPending(iop_base)) {
+				ASC_DBG(3, "AscPollQDone: AscISR()\n");
+				AscISR(asc_dvc);
+			}
+		}
+	}
+	ASC_DBG1(3, "AscPollQDone: sta %x\n", sta);
+	return (sta);
+}
+
+uchar
+AscReadLramByte(
+				   PortAddr iop_base,
+				   ushort addr
+)
+{
+	uchar               byte_data;
+	ushort              word_data;
+
+	if (isodd_word(addr)) {
+		AscSetChipLramAddr(iop_base, addr - 1);
+		word_data = AscGetChipLramData(iop_base);
+
+#if CC_LITTLE_ENDIAN_HOST
+		byte_data = (uchar) ((word_data >> 8) & 0xFF);
+#else
+		byte_data = (uchar) (word_data & 0xFF);
+#endif
+
+	} else {
+		AscSetChipLramAddr(iop_base, addr);
+		word_data = AscGetChipLramData(iop_base);
+
+#if CC_LITTLE_ENDIAN_HOST
+		byte_data = (uchar) (word_data & 0xFF);
+#else
+		byte_data = (uchar) ((word_data >> 8) & 0xFF);
+#endif
+
+	}
+	return (byte_data);
+}
+
+ushort
+AscReadLramWord(
+				   PortAddr iop_base,
+				   ushort addr
+)
+{
+	ushort              word_data;
+
+	AscSetChipLramAddr(iop_base, addr);
+	word_data = AscGetChipLramData(iop_base);
+	return (word_data);
+}
+
+ulong
+AscReadLramDWord(
+					PortAddr iop_base,
+					ushort addr
+)
+{
+	ushort              val_low, val_high;
+	ulong               dword_data;
+
+	AscSetChipLramAddr(iop_base, addr);
+
+#if CC_LITTLE_ENDIAN_HOST
+	val_low = AscGetChipLramData(iop_base);
+
+	val_high = AscGetChipLramData(iop_base);
+#else
+	val_high = AscGetChipLramData(iop_base);
+	val_low = AscGetChipLramData(iop_base);
+#endif
+
+	dword_data = ((ulong) val_high << 16) | (ulong) val_low;
+	return (dword_data);
+}
+
+void
+AscWriteLramWord(
+					PortAddr iop_base,
+					ushort addr,
+					ushort word_val
+)
+{
+	AscSetChipLramAddr(iop_base, addr);
+	AscPutChipLramData(iop_base, word_val);
+	return;
+}
+
+void
+AscWriteLramDWord(
+					 PortAddr iop_base,
+					 ushort addr,
+					 ulong dword_val
+)
+{
+	ushort              word_val;
+
+	AscSetChipLramAddr(iop_base, addr);
+
+#if CC_LITTLE_ENDIAN_HOST
+	word_val = (ushort) dword_val;
+	AscPutChipLramData(iop_base, word_val);
+	word_val = (ushort) (dword_val >> 16);
+	AscPutChipLramData(iop_base, word_val);
+#else
+	word_val = (ushort) (dword_val >> 16);
+	AscPutChipLramData(iop_base, word_val);
+	word_val = (ushort) dword_val;
+	AscPutChipLramData(iop_base, word_val);
+#endif
+	return;
+}
+
+void
+AscWriteLramByte(
+					PortAddr iop_base,
+					ushort addr,
+					uchar byte_val
+)
+{
+	ushort              word_data;
+
+	if (isodd_word(addr)) {
+		addr--;
+		word_data = AscReadLramWord(iop_base, addr);
+		word_data &= 0x00FF;
+		word_data |= (((ushort) byte_val << 8) & 0xFF00);
+	} else {
+		word_data = AscReadLramWord(iop_base, addr);
+		word_data &= 0xFF00;
+		word_data |= ((ushort) byte_val & 0x00FF);
+	}
+	AscWriteLramWord(iop_base, addr, word_data);
+	return;
+}
+
+int
+AscVerWriteLramWord(
+					   PortAddr iop_base,
+					   ushort addr,
+					   ushort word_val
+)
+{
+	int                 sta;
+
+	sta = 0;
+	AscSetChipLramAddr(iop_base, addr);
+	AscPutChipLramData(iop_base, word_val);
+	AscSetChipLramAddr(iop_base, addr);
+	if (word_val != AscGetChipLramData(iop_base)) {
+		sta = ERR;
+	}
+	return (sta);
+}
+
+void
+AscMemWordCopyToLram(
+						PortAddr iop_base,
+						ushort s_addr,
+						ushort dosfar * s_buffer,
+						int words
+)
+{
+	AscSetChipLramAddr(iop_base, s_addr);
+	DvcOutPortWords(iop_base + IOP_RAM_DATA, s_buffer, words);
+	return;
+}
+
+void
+AscMemDWordCopyToLram(
+						 PortAddr iop_base,
+						 ushort s_addr,
+						 ulong dosfar * s_buffer,
+						 int dwords
+)
+{
+	AscSetChipLramAddr(iop_base, s_addr);
+	DvcOutPortDWords(iop_base + IOP_RAM_DATA, s_buffer, dwords);
+	return;
+}
+
+void
+AscMemWordCopyFromLram(
+						  PortAddr iop_base,
+						  ushort s_addr,
+						  ushort dosfar * d_buffer,
+						  int words
+)
+{
+	AscSetChipLramAddr(iop_base, s_addr);
+	DvcInPortWords(iop_base + IOP_RAM_DATA, d_buffer, words);
+	return;
+}
+
+ulong
+AscMemSumLramWord(
+					 PortAddr iop_base,
+					 ushort s_addr,
+					 rint words
+)
+{
+	ulong               sum;
+	int                 i;
+
+	sum = 0L;
+	for (i = 0; i < words; i++, s_addr += 2) {
+		sum += AscReadLramWord(iop_base, s_addr);
+	}
+	return (sum);
+}
+
+void
+AscMemWordSetLram(
+					 PortAddr iop_base,
+					 ushort s_addr,
+					 ushort set_wval,
+					 rint words
+)
+{
+	rint                i;
+
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < words; i++) {
+		AscPutChipLramData(iop_base, set_wval);
+	}
+	return;
+}
+
+int
+AscScsiInquiry(
+				  ASC_DVC_VAR asc_ptr_type * asc_dvc,
+				  ASC_SCSI_REQ_Q dosfar * scsiq,
+				  uchar dosfar * buf, int buf_len
+)
+{
+	if (AscScsiSetupCmdQ(asc_dvc, scsiq, buf,
+						 (ulong) buf_len) == ERR) {
+		return (scsiq->r3.done_stat = QD_WITH_ERROR);
+	}
+	scsiq->cdb[0] = (uchar) SCSICMD_Inquiry;
+	scsiq->cdb[1] = scsiq->r1.target_lun << 5;
+	scsiq->cdb[2] = 0;
+	scsiq->cdb[3] = 0;
+	scsiq->cdb[4] = buf_len;
+	scsiq->cdb[5] = 0;
+	scsiq->r2.cdb_len = 6;
+	return (0);
+}
+
+int
+AscScsiReadCapacity(
+					   ASC_DVC_VAR asc_ptr_type * asc_dvc,
+					   ASC_SCSI_REQ_Q dosfar * scsiq,
+					   uchar dosfar * info
+)
+{
+	if (AscScsiSetupCmdQ(asc_dvc, scsiq, info, 8L) == ERR) {
+		return (scsiq->r3.done_stat = QD_WITH_ERROR);
+	}
+	scsiq->cdb[0] = (uchar) SCSICMD_ReadCapacity;
+	scsiq->cdb[1] = scsiq->r1.target_lun << 5;
+	scsiq->cdb[2] = 0;
+	scsiq->cdb[3] = 0;
+	scsiq->cdb[4] = 0;
+	scsiq->cdb[5] = 0;
+	scsiq->cdb[6] = 0;
+	scsiq->cdb[7] = 0;
+	scsiq->cdb[8] = 0;
+	scsiq->cdb[9] = 0;
+	scsiq->r2.cdb_len = 10;
+	return (0);
+}
+
+int
+AscScsiTestUnitReady(
+						ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						ASC_SCSI_REQ_Q dosfar * scsiq
+)
+{
+	if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR,
+						 (ulong) 0L) == ERR) {
+		return (scsiq->r3.done_stat = QD_WITH_ERROR);
+	}
+	scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA;
+	scsiq->cdb[0] = (uchar) SCSICMD_TestUnitReady;
+	scsiq->cdb[1] = scsiq->r1.target_lun << 5;
+	scsiq->cdb[2] = 0;
+	scsiq->cdb[3] = 0;
+	scsiq->cdb[4] = 0;
+	scsiq->cdb[5] = 0;
+	scsiq->r2.cdb_len = 6;
+	return (0);
+}
+
+int
+AscScsiStartStopUnit(
+						ASC_DVC_VAR asc_ptr_type * asc_dvc,
+						ASC_SCSI_REQ_Q dosfar * scsiq,
+						uchar op_mode
+)
+{
+	if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, (ulong) 0L) == ERR) {
+		return (scsiq->r3.done_stat = QD_WITH_ERROR);
+	}
+	scsiq->r1.cntl = (uchar) ASC_SCSIDIR_NODATA;
+	scsiq->cdb[0] = (uchar) SCSICMD_StartStopUnit;
+	scsiq->cdb[1] = scsiq->r1.target_lun << 5;
+	scsiq->cdb[2] = 0;
+	scsiq->cdb[3] = 0;
+	scsiq->cdb[4] = op_mode;
+
+	scsiq->cdb[5] = 0;
+	scsiq->r2.cdb_len = 6;
+	return (0);
+}
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h
--- v1.3.57/linux/drivers/scsi/advansys.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/advansys.h	Wed Jan 17 07:27:36 1996
@@ -0,0 +1,131 @@
+/* $Id: advansys.h,v 1.10 1996/01/15 04:51:06 bobf Exp bobf $ */
+/*
+ * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
+ *
+ * Copyright (c) 1995-1996 Advanced System Products, Inc.
+ *
+ * This driver may be modified and freely distributed provided that
+ * the above copyright message and this comment are included in the
+ * distribution. The latest version of this driver is available at
+ * the AdvanSys FTP and BBS sites listed below.
+ *
+ * Please send questions, comments, and bug reports to:
+ * bobf@advansys.com (Bob Frey)
+ */
+
+#ifndef _ADVANSYS_H
+#define _ADVANSYS_H
+
+/* The driver can be used in Linux 1.2.X or 1.3.X. */
+#if !defined(LINUX_1_2) && !defined(LINUX_1_3)
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif /* LINUX_VERSION_CODE */
+#if LINUX_VERSION_CODE > 65536 + 3 * 256
+#define LINUX_1_3
+#else /* LINUX_VERSION_CODE */
+#define LINUX_1_2
+#endif /* LINUX_VERSION_CODE */
+#endif /* !defined(LINUX_1_2) && !defined(LINUX_1_3) */
+
+/*
+ * Scsi_Host_Template function prototypes.
+ */
+int advansys_detect(Scsi_Host_Template *);
+int advansys_release(struct Scsi_Host *);
+const char *advansys_info(struct Scsi_Host *);
+int advansys_command(Scsi_Cmnd *);
+int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+int advansys_abort(Scsi_Cmnd *);
+int advansys_reset(Scsi_Cmnd *);
+#ifdef LINUX_1_2
+int advansys_biosparam(Disk *, int, int[]);
+#else /* LINUX_1_3 */
+int advansys_biosparam(Disk *, kdev_t, int[]);
+extern struct proc_dir_entry proc_scsi_advansys;
+int advansys_proc_info(char *, char **, off_t, int, int, int);
+#endif /* LINUX_1_3 */
+
+/* init/main.c setup function */
+void advansys_setup(char *, int *);
+
+/*
+ * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h.
+ */
+#ifdef LINUX_1_2
+#define ADVANSYS { \
+	NULL,					/* struct SHT *next */ \
+	NULL,					/* int *usage_count */ \
+	"advansys",				/* char *name */ \
+	advansys_detect,		/* int (*detect)(struct SHT *) */ \
+	advansys_release,		/* int (*release)(struct Scsi_Host *) */ \
+	advansys_info,			/* const char *(*info)(struct Scsi_Host *) */ \
+	advansys_command, 		/* int (*command)(Scsi_Cmnd *) */ \
+	advansys_queuecommand, \
+			/* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
+	advansys_abort,			/* int (*abort)(Scsi_Cmnd *) */ \
+	advansys_reset,			/* int (*reset)(Scsi_Cmnd *) */ \
+	NULL,					/* int (*slave_attach)(int, int) */ \
+	advansys_biosparam,		/* int (* bios_param)(Disk *, int, int []) */ \
+	/* \
+	 * The following fields are set per adapter in advansys_detect(). \
+	 */ \
+	0,						/* int can_queue */ \
+	0,						/* int this_id */ \
+	0,						/* short unsigned int sg_tablesize */ \
+	0,						/* short cmd_per_lun */ \
+	0,						/* unsigned char present */	\
+	/* \
+	 * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+	 * must be set. The flag will be cleared in advansys_detect for non-ISA \
+	 * adapters. Refer to the comment in scsi_module.c for more information. \
+	 */ \
+	1,						/* unsigned unchecked_isa_dma:1 */ \
+	/* \
+	 * All adapters controlled by this driver are capable of large \
+	 * scatter-gather lists. This apparently obviates any performance
+	 * gain provided by setting 'use_clustering'. \
+	 */ \
+	DISABLE_CLUSTERING,		/* unsigned use_clustering:1 */ \
+}
+#else /* LINUX_1_3 */
+#define ADVANSYS { \
+	NULL,					/* struct SHT *next */ \
+	NULL,					/* long *usage_count */ \
+	&proc_scsi_advansys,	/* struct proc_dir_entry *proc_dir */ \
+	advansys_proc_info,	\
+			/* int (*proc_info)(char *, char **, off_t, int, int, int) */ \
+	"advansys",				/* const char *name */ \
+	advansys_detect,		/* int (*detect)(struct SHT *) */ \
+	advansys_release,		/* int (*release)(struct Scsi_Host *) */ \
+	advansys_info,			/* const char *(*info)(struct Scsi_Host *) */ \
+	advansys_command, 		/* int (*command)(Scsi_Cmnd *) */ \
+	advansys_queuecommand, \
+			/* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \
+	advansys_abort,			/* int (*abort)(Scsi_Cmnd *) */ \
+	advansys_reset,			/* int (*reset)(Scsi_Cmnd *) */ \
+	NULL,					/* int (*slave_attach)(int, int) */ \
+	advansys_biosparam,		/* int (* bios_param)(Disk *, kdev_t, int []) */ \
+	/* \
+	 * The following fields are set per adapter in advansys_detect(). \
+	 */ \
+	0,						/* int can_queue */ \
+	0,						/* int this_id */ \
+	0,						/* short unsigned int sg_tablesize */ \
+	0,						/* short cmd_per_lun */ \
+	0,						/* unsigned char present */	\
+	/* \
+	 * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+	 * must be set. The flag will be cleared in advansys_detect for non-ISA \
+	 * adapters. Refer to the comment in scsi_module.c for more information. \
+	 */ \
+	1,						/* unsigned unchecked_isa_dma:1 */ \
+	/* \
+	 * All adapters controlled by this driver are capable of large \
+	 * scatter-gather lists. This apparently obviates any performance
+	 * gain provided by setting 'use_clustering'. \
+	 */ \
+	DISABLE_CLUSTERING,		/* unsigned use_clustering:1 */ \
+}
+#endif /* LINUX_1_3 */
+#endif /* _ADVANSYS_H */
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v1.3.57/linux/drivers/scsi/aha1542.c	Mon Oct 23 18:02:07 1995
+++ linux/drivers/scsi/aha1542.c	Sun Jan 14 16:46:08 1996
@@ -15,10 +15,7 @@
  *        Accept parameters from LILO cmd-line. -- 1-Oct-94
  */
 
-#ifdef MODULE
-#include <linux/autoconf.h>
 #include <linux/module.h>
-#endif
 
 #include <linux/kernel.h>
 #include <linux/head.h>
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/aic7xxx.seq linux/drivers/scsi/aic7xxx.seq
--- v1.3.57/linux/drivers/scsi/aic7xxx.seq	Mon Nov 13 12:36:45 1995
+++ linux/drivers/scsi/aic7xxx.seq	Sun Jan 14 16:22:17 1996
@@ -136,9 +136,9 @@
 SEND_REJECT	= 0x11				# sending a message reject
 NO_IDENT	= 0x21				# no IDENTIFY after reconnect
 NO_MATCH	= 0x31				# no cmd match for reconnect
-MSG_SDTR	= 0x41				# SDTR message recieved
-MSG_WDTR	= 0x51				# WDTR message recieved
-MSG_REJECT	= 0x61				# Reject message recieved
+MSG_SDTR	= 0x41				# SDTR message received
+MSG_WDTR	= 0x51				# WDTR message received
+MSG_REJECT	= 0x61				# Reject message received
 BAD_STATUS	= 0x71				# Bad status from target
 RESIDUAL	= 0x81				# Residual byte count != 0
 ABORT_TAG	= 0x91				# Sent an ABORT_TAG message
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.3.57/linux/drivers/scsi/hosts.c	Thu Jan  4 21:54:55 1996
+++ linux/drivers/scsi/hosts.c	Wed Jan 17 07:27:36 1996
@@ -41,6 +41,10 @@
 
 #include "hosts.h"
 
+#ifdef CONFIG_SCSI_ADVANSYS
+#include "advansys.h"
+#endif
+
 #ifdef CONFIG_SCSI_AHA152X
 #include "aha152x.h"
 #endif
@@ -158,6 +162,9 @@
 
 static Scsi_Host_Template builtin_scsi_hosts[] =
 {
+#ifdef CONFIG_SCSI_ADVANSYS
+	ADVANSYS,
+#endif
 /* BusLogic must come before aha1542.c */
 #ifdef CONFIG_SCSI_BUSLOGIC
     BUSLOGIC,
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.57/linux/drivers/scsi/scsi.c	Thu Jan  4 21:54:56 1996
+++ linux/drivers/scsi/scsi.c	Mon Jan 15 08:18:22 1996
@@ -82,6 +82,8 @@
                  struct Scsi_Host *shpnt, char * scsi_result);
 void scsi_build_commandblocks(Scsi_Device * SDpnt);
 
+extern struct symbol_table scsi_symbol_table;
+
 
 static FreeSectorBitmap * dma_malloc_freelist = NULL;
 static int scsi_need_isa_bounce_buffers;
@@ -395,8 +397,8 @@
 
 
   /* Make sure we have something that is valid for DMA purposes */
-  scsi_result = ((!dma_malloc_freelist || !shpnt->unchecked_isa_dma)
-                 ? &scsi_result0[0] : scsi_malloc (512));
+  scsi_result = ( ( !shpnt->unchecked_isa_dma )
+                 ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
 
   if (scsi_result == NULL) {
     printk ("Unable to obtain scsi_result buffer\n");
@@ -489,7 +491,7 @@
 
     /* If we allocated a buffer so we could do DMA, free it now */
     if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
-      scsi_free (scsi_result, 512);
+      scsi_init_free (scsi_result, 512);
 
 }
 
@@ -2329,6 +2331,7 @@
     timer_table[SCSI_TIMER].fn = scsi_main_timeout;
     timer_table[SCSI_TIMER].expires = 0;
 
+    register_symtab(&scsi_symbol_table);
 
     /* Register the /proc/scsi/scsi entry */
 #if CONFIG_PROC_FS 
@@ -3116,8 +3119,6 @@
 #endif
 
 #ifdef MODULE
-
-extern struct symbol_table scsi_symbol_table;
 
 int init_module(void) {
     unsigned long size;
diff -u --recursive --new-file v1.3.57/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v1.3.57/linux/drivers/scsi/scsi_debug.c	Mon Oct 23 18:02:11 1995
+++ linux/drivers/scsi/scsi_debug.c	Sun Jan 14 16:48:28 1996
@@ -7,10 +7,7 @@
  *  anything out of the ordinary is seen.
  */
 
-#ifdef MODULE
-#include <linux/autoconf.h>
 #include <linux/module.h>
-#endif
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/.blurb linux/drivers/sound/.blurb
--- v1.3.57/linux/drivers/sound/.blurb	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/.blurb	Tue Jan  9 00:37:02 1996
@@ -1,8 +1,4 @@
 *********************************************************
-* IF YOU HAVE ANY PROBLEMS WITH THE SOUND DRIVER,       *
-* PLEASE READ THE SOUND-HOWTO. IT'S AVAILABLE FROM YOUR *
-* NEAREST LINUX FTP SITE AND CONTAINS ANSWER TO YOUR    *
-* PROBLEM.                                              *
 * Readme.cards (this directory) contains some card	*
 * specific instructions.				*
 *********************************************************
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/.objects linux/drivers/sound/.objects
--- v1.3.57/linux/drivers/sound/.objects	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/.objects	Tue Jan  9 00:37:02 1996
@@ -64,14 +64,10 @@
 	OBJS := $(OBJS)  pss.o
 endif
 
-ifdef CONFIG_SB16
-	OBJS := $(OBJS)  sb16_dsp.o
-endif
-
 ifdef CONFIG_SB
 	OBJS := $(OBJS)  sb16_midi.o sb_card.o sb_dsp.o sb_midi.o sb_mixer.o
 	OBJS := $(OBJS)  sb_card.o
-	OBJS := $(OBJS)  sb_dsp.o
+	OBJS := $(OBJS)  sb_dsp.o sb16_dsp.o
 	OBJS := $(OBJS)  sb_midi.o
 	OBJS := $(OBJS)  sb_mixer.o
 endif
@@ -92,12 +88,12 @@
 	OBJS := $(OBJS)  sscape.o
 endif
 
-ifdef CONFIG_SEQUENCER
-	OBJS := $(OBJS)  sys_timer.o
-endif
-
 ifdef CONFIG_TRIX
 	OBJS := $(OBJS)  trix.o
+endif
+
+ifdef CONFIG_SEQUENCER
+	OBJS := $(OBJS)  sys_timer.o
 endif
 
 ifdef CONFIG_UART6850
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/.version linux/drivers/sound/.version
--- v1.3.57/linux/drivers/sound/.version	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/.version	Tue Jan  9 00:37:03 1996
@@ -1,2 +1,2 @@
-3.5-alpha5
+3.5-alpha8
 0x030505
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v1.3.57/linux/drivers/sound/CHANGELOG	Mon Oct 23 18:02:13 1995
+++ linux/drivers/sound/CHANGELOG	Tue Jan  9 00:37:02 1996
@@ -1,5 +1,37 @@
-Changelog for version 3.5-alpha3
+Changelog for version 3.5-alpha8
 --------------------------------
+
+Since 3.5-alpha7
+- Linux kernel compatible configuration (_EXPERIMENTAL_). Enable
+  using command "cd /linux/drivers/sound;make script" and then
+  just run kernel's make config normally.
+- Minor fixes to the SB support. Hopefully the driver works with
+  all SB models now.
+- Added support for ESS ES1688 "AudioDrive" based cards.
+
+Since 3.5-alpha6
+- SB Pro and SB16 supports are no longer separately selectable options.
+  Enabling SB enables them too.
+- Changed all #ifndef EXCLUDE_xx stuff to #ifdef CONFIG_xx. Modified
+configure to handle this. 
+- Removed initialization messages from the
+modularized version. They can be enabled by using init_trace=1 in
+the insmod command line (insmod sound init_trace=1).
+- More AIX stuff.
+- Added support for syncronizing dsp/audio devices with /dev/sequencer.
+- mmap() support for dsp/audio devices.
+
+Since 3.5-alpha5
+- AIX port.
+- Changed some xxx_PATCH macros in soundcard.h to work with
+  big endian machines.
+
+Since 3.5-alpha4
+- Removed the 'setfx' stuff from the version distributed with kernel
+  sources. Running 'setfx' is required again.
+
+Since 3.5-alpha3
+- Moved stuff from the 'setfx' program to the AudioTriX Pro driver.
 
 Since 3.5-alpha2
 - Modifications to makefile and configure.c. Unnecessary sources
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v1.3.57/linux/drivers/sound/Config.in	Sun Oct 29 11:38:49 1995
+++ linux/drivers/sound/Config.in	Tue Jan  9 00:37:02 1996
@@ -1,8 +1,12 @@
 #
 # Sound driver configuration
 #
-# This is really ugly: it should probably be changed
-# to use the normal config script setup
+#--------
+# There is another confic script which is compatible with rest of
+# the kernel. It can be activated by running 'make script' in this
+# directory. Please note that this is an _experimental_ feature which
+# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro).
+#--------
 #
 $MAKE -C drivers/sound config || exit 1
 
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v1.3.57/linux/drivers/sound/Makefile	Sat Jan  6 19:10:40 1996
+++ linux/drivers/sound/Makefile	Tue Jan  9 00:36:59 1996
@@ -25,14 +25,6 @@
 	 mad16.o mad16_sb_midi.o cs4232.o maui.o sound_pnp.o
 endif
 
-ifndef HOSTCC
-#
-#	Running outside the kernel build.
-#
-CC	= gcc
-HOSTCC	= gcc
-CFLAGS	= -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486
-
 
 build:
 	@echo Compiling modularized sound driver
@@ -44,18 +36,27 @@
 
 .c.o:
 	$(CC) $(CFLAGS) -c $<
-endif
 
 ifeq ($(CONFIG_SOUND),y)
-OBJS += $(FIXEDOBJS)
 
 all:	local.h sound.a
 
+OBJS += $(FIXEDOBJS)
+
 else
 all:
 endif
 
+ifndef HOSTCC
+#
+#	Running outside the kernel build.
+#
+CC	= gcc
+HOSTCC	= gcc
+CFLAGS	= -D__KERNEL__ -DMODULE -DMODVERSIONS -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486
+else
 include $(TOPDIR)/Rules.make
+endif
 
 sound.a: $(OBJS) 
 	-rm -f sound.a
@@ -64,7 +65,7 @@
 
 clean:
 	rm -f core core.* *.o *.a tmp_make *~ x y z *%
-	rm -f configure sound_stub.c
+	rm -f configure sound_stub.c objects/*.o
 
 indent:
 	for n in *.c;do echo indent $$n;indent $$n;done
@@ -100,6 +101,24 @@
 #	@echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null
 	@echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h
 
+kernelconfig: setup-$(TARGET_OS)
+	rm -f configure
+	$(HOSTCC) -o configure configure.c
+	./configure fixedlocal > local.h
+	./configure fixeddefines > .defines
+	@echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h
+	@echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h
+#	@echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h 2>/dev/null
+#	@echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null
+	@echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h
+
+script: setup-$(TARGET_OS)
+	rm -f configure
+	$(HOSTCC) -o configure configure.c
+	./configure script > Config.in
+	./configure fixedlocal > local.h
+	./configure fixeddefines > .defines
+
 clrconf:
 	rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h .defines
 
@@ -118,4 +137,12 @@
 	$(LD) -r -o sound.o $(FIXEDOBJS) sound.a
 
 modules: local.h sound.o
-	ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o
+	ln -fs `pwd`/sound.o /usr/src/linux/modules/sound.o
+
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v1.3.57/linux/drivers/sound/Readme	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/Readme	Tue Jan  9 00:37:00 1996
@@ -1,9 +1,9 @@
 
-VoxWare v3.5-alpha5 release notes
+VoxWare v3.5-alpha4 release notes
 ---------------------------------
 
 IMPORTANT! This version of the driver is compatible only with Linux versions
-	   1.3.33 and later. It may work with earlier ones as a loadable
+	   1.3.58 and later. It may work with earlier ones as a loadable
 	   module but...
 
 	   Also this is an ALPHA test version which has not been tested
@@ -33,11 +33,11 @@
 after v3.0 (I will not add aditional features before v3.0 is ready).
 
    ====================================================
--  THIS VERSION ____REQUIRES____ Linux 1.3.33 OR LATER.
+-  THIS VERSION ____REQUIRES____ Linux 1.3.58 OR LATER.
    ====================================================
 
 -  THIS VERSION MAY NOT WORK WITH Linux VERSIONS RELEASED
-   AFTER end of Nov 1995. If this version doesn't compile with
+   AFTER end of Feb 1996. If this version doesn't compile with
    your kernel version, please use the sound driver version
    included in your kernel.
 
@@ -65,7 +65,7 @@
 	the snd-util-3.0.tar.gz package which does it).
 Ensoniq SoundScape (works but needs some improvements)
 MV Jazz16 based soundcards (ProSonic, 3D etc).
-SoundMan Wave (recording may not work, mixer support is limited)
+SoundMan Wave
 Mozart (OAK OTI-601 interface chip) based soundcards.
 MAD16 (an interface chip by OPTi) based soundcards (TB Tropez ???).
 (NOTE! The MAD16 looks similar to the Mozart chip. It could be a good
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v1.3.57/linux/drivers/sound/Readme.cards	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/Readme.cards	Tue Jan  9 00:37:01 1996
@@ -40,7 +40,7 @@
 		cards in the market (July95). It's likely that your card
 		is compatible just with SB Pro but there is also a non SB
 		compatible 16 bit mode. Usually it's MSS/WSS but could also
-		be a proprietary one like MV Jazz16.
+		be a proprietary one like MV Jazz16 or ESS ES688.
 
 Gravis Ultrasound (GUS)
 	GUS
@@ -117,6 +117,8 @@
 	Several companies (including Ensoniq, Reveal and Spea) are selling
 	cards based on this architecture.
 
+	NOTE! The new PnP SoundScape is not supported yet.
+
 MAD16 and Mozart based cards
 	The Mozart (OAK OTI-601) and MAD16 Pro (OPTi 82C929) interface
 	chips are used in many different soundcards, including some
@@ -337,12 +339,11 @@
 	  have one of them. In addition the MAD16 chip is used in some
 	  cards made by known manufacturers such as Turtle Beach (Tropez),
 	  Reveal (some models) and Diamond (latest ones).
-  "SoundBlaster Pro support",
-	- Enable this option if your card is SB Pro or SB16. Enable it
-	  also with any SB Pro clones. Answering 'n' saves some amount of
-	  memory but 'y' is the safe alterative.
-  "SoundBlaster 16 support",
-	- Enable if you have a SB16 (including the AWE32).
+  "Support for TB Maui"
+	- This is just an experimental extension to the MPU401 driver.
+	  Don't enable this option unless you are writing a .MOD
+	  player for Maui.
+
   "Audio Excel DSP 16 initialization support",
 	- Don't know much about this card. Look at aedsp16.c for more info.
 
@@ -468,6 +469,10 @@
 the 16 bit daughtercard if you have them. Note that enabling the daughter
 card disables GUS MAX driver.
 
+NOTE for owners of the 16 bit daughtercard: By default the daughtercard
+uses /dev/dsp (and /dev/audio). Command "ln -sf /dev/dsp1 /dev/dsp"
+selects the daughter card as the default device.
+
 With just the standard GUS enabled the configuration program prompts
 for the I/O, IRQ and DMA numbers for the card. Use the same values than
 with DOS.
@@ -559,23 +564,17 @@
 For this reason the driver asks for the name of a file containing the
 microcode (TRXPRO.HEX). This file is usually located in the directory
 where the DOS drivers were installed. You must have access to this file
-when configuring the driver.
-
-IMPORTANT!!!!!!!!!!!
-
-The OPL4/OPL3 chip and the (optional) effects daughtercard require 
-initialization after boot. Since information about the effect processor
-is not public, the initialization must be done by running a special program
-after boot. The setfx program is distributed in Linux binary form (only)
-in snd-util-3.0.tar.gz package.
-It's calls ioperm() so it must be run as root.
+when configuring the driver. 
 
-Another way to initialize the effects processor (and OPL4) is to boot DOS
-before running Linux.
+If you have the effects daughtercard, it must be initialized by running
+the setfx program of snd-util-3.0.tar.gz package. This step is not required
+when using the (future) binary distribution version of the driver.
 
 Ensoniq SoundScape
 ------------------
 
+NOTE!	The new PnP SoundScape is not supported yet.
+
 The SoundScape driver handles initialization of MSS and MPU supports
 itself so you don't need to enable other drivers than SoundScape
 (enable also the /dev/dsp, /dev/sequencer and MIDI supports).
@@ -695,11 +694,14 @@
 may also be called as TSUNAMI.BIN or something else (older cards?).
 
 The OPL4 synth will be inaccessible without loading the microcontroller code.
-Also remember to enable MPU401 support if you want to use the OPL4 mode.
+
+Also remember to enable SB MPU401 support if you want to use the OPL4 mode.
+(Don't enable the 'normal' MPU401 device as with some earlier driver
+versions (pre 3.5-alpha8)).
 
 NOTE!	Don't answer 'y' when the driver asks about SM Games support
 	(the next question after the MIDI0001.BIN name). However
-	aneswering 'y' is not dangerous. 
+	aneswering 'y' doesn't cause damage your computer so don't panic. 
 
 Sound Galaxies
 --------------
@@ -722,6 +724,11 @@
 There are some new Sound Galaxies in the market. I have no experience with
 them so read the card's manual carefully.
 
+ESS ES1688 'AudioDrive' based cards
+-----------------------------------
+
+Configure these cards just like SB Pro. Enable the 'SB MPU401 MIDI port'
+if you want to use MIDI features of the card.
 
 Reveal cards
 ------------
@@ -779,12 +786,6 @@
 the card is compatible with MSS, it's a better choise. Some cards
 don't work in the SB and MSS modes at the same time.
 
-There are some cards which will be supported by VoxWare sooner or later
-(currently at least cards based on the ESS chipset). Such cards are
-so common that there is some idea in writing the driver. Check the
-VoxWare home page (http://personal.eunet.fi/pp/voxware) for latest
-information.
-
 Then there are cards which are no longer manufactured and/or which
 are relatively rarely used (such as the 8 bit ProAudioSpectrum
 models). It's extremely unlikely that such cards never get supported.
@@ -837,8 +838,8 @@
 there is any plans to write a driver for the cards mentioned above. I 
 will put any news to the VoxWare www home page (see below).
 
-There are some common audio chipsets that are supported yet. For example
-the ESS chips and Sierra Aria. It's likely that these architectures
+There are some common audio chipsets that are not supported yet. For example
+Sierra Aria and IBM Mwave. It's possible that these architectures
 get some support in future but I can't make any promises. Just look
 at the home page for latest info.
 
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/Readme.modules linux/drivers/sound/Readme.modules
--- v1.3.57/linux/drivers/sound/Readme.modules	Fri Oct 13 14:44:33 1995
+++ linux/drivers/sound/Readme.modules	Tue Jan  9 00:37:02 1996
@@ -86,3 +86,14 @@
 NOTE!	This method is not normally required. You should use it only when
 	you have to use different configuration than normally. The sound=
 	command line parameter is error phrone and not recommended.
+
+Debugging and tracing
+---------------------
+
+Modularized sound driver doesn't display messages during initialization as
+the kernel compiled one does. This feature can be turned on by adding
+init_trace=1 to the insmod command line.
+
+For example:
+
+	insmod sound init_trace=1
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v1.3.57/linux/drivers/sound/ad1848.c	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/ad1848.c	Tue Jan  9 00:37:06 1996
@@ -44,7 +44,7 @@
 #define DEB1(x)
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)
+#if defined(CONFIG_AD1848)
 
 #include "ad1848_mixer.h"
 
@@ -72,6 +72,7 @@
 #define MD_4231		2
 #define MD_4231A	3
 #define MD_1845		4
+#define MD_4232		5
 
     /* Mixer parameters */
     int             recmask;
@@ -153,7 +154,8 @@
   unsigned long   flags;
   int             timeout = 90000;
 
-  while (timeout > 0 && inb (devc->base) == 0x80)	/*Are we initializing */
+  while (timeout > 0 &&
+	 inb (devc->base) == 0x80)	/*Are we initializing */
     timeout--;
 
   save_flags (flags);
@@ -436,11 +438,19 @@
 {
   int             i;
 
-  devc->recmask = 0;
-  if (devc->mode != MD_1848)
-    devc->supported_devices = MODE2_MIXER_DEVICES;
-  else
-    devc->supported_devices = MODE1_MIXER_DEVICES;
+  switch (devc->mode)
+    {
+    case MD_4231:
+      devc->supported_devices = MODE2_MIXER_DEVICES;
+      break;
+
+    case MD_4232:
+      devc->supported_devices = MODE3_MIXER_DEVICES;
+      break;
+
+    default:
+      devc->supported_devices = MODE1_MIXER_DEVICES;
+    }
 
   devc->supported_rec_devices = MODE1_REC_DEVICES;
 
@@ -466,7 +476,8 @@
 
   if (((cmd >> 8) & 0xff) == 'M')
     {
-      if (cmd & IOC_IN)
+
+      if (_IOC_DIR (cmd) & _IOC_WRITE)
 	switch (cmd & 0xff)
 	  {
 	  case SOUND_MIXER_RECSRC:
@@ -570,6 +581,7 @@
   devc->intr_active = 0;
   devc->opened = 1;
   devc->irq_mode = 0;
+  ad1848_trigger (dev, 0);
   restore_flags (flags);
 /*
  * Mute output until the playback really starts. This decreases clicking.
@@ -991,7 +1003,7 @@
   restore_flags (flags);
   devc->xfer_count = 0;
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
   if (dev == timer_installed && devc->timer_running)
     if ((fs & 0x01) != (old_fs & 0x01))
       {
@@ -1012,11 +1024,14 @@
 {
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
   unsigned long   flags;
+  int             timeout;
 
   save_flags (flags);
   cli ();
 
   ad_mute (devc);
+  ad_enter_MCE (devc);
+  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */
   ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */
 
   ad_write (devc, 15, 0);	/* Clear DMA counter */
@@ -1028,11 +1043,14 @@
       ad_write (devc, 31, 0);	/* Clear DMA counter */
     }
 
-  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */
+  for (timeout = 0; timeout < 1000 && !(inb (io_Status (devc)) & 0x80);
+       timeout++);		/* Wait for interrupt */
 
+  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */
   outb (0, io_Status (devc));	/* Clear interrupt status */
   outb (0, io_Status (devc));	/* Clear interrupt status */
   devc->irq_mode = 0;
+  ad_leave_MCE (devc);
 
   /* DMAbuf_reset_dma (dev); */
   restore_flags (flags);
@@ -1116,6 +1134,8 @@
   ad1848_info    *devc = &dev_info[nr_ad1848_devs];
   unsigned char   tmp1 = 0xff, tmp2 = 0xff;
 
+  DDB (printk ("ad1848_detect(%x)\n", io_base));
+
   if (ad_flags)
     *ad_flags = 0;
 
@@ -1149,6 +1169,8 @@
      *
      * If the I/O address is unused, it typically returns 0xff.
    */
+
+  DDB (printk ("ad1848_detect() - step A\n"));
   if ((inb (devc->base) & 0x80) != 0x00)	/* Not a AD1848 */
     {
       DDB (printk ("ad1848 detect error - step A (%02x)\n",
@@ -1162,6 +1184,7 @@
      * so try to avoid using it.
    */
 
+  DDB (printk ("ad1848_detect() - step B\n"));
   ad_write (devc, 0, 0xaa);
   ad_write (devc, 1, 0x45);	/* 0x55 with bit 0x10 clear */
 
@@ -1171,6 +1194,7 @@
       return 0;
     }
 
+  DDB (printk ("ad1848_detect() - step C\n"));
   ad_write (devc, 0, 0x45);
   ad_write (devc, 1, 0xaa);
 
@@ -1185,6 +1209,7 @@
      * try to change them.
    */
 
+  DDB (printk ("ad1848_detect() - step D\n"));
   tmp = ad_read (devc, 12);
   ad_write (devc, 12, (~tmp) & 0x0f);
 
@@ -1206,6 +1231,7 @@
      * with CS4231.
    */
 
+  DDB (printk ("ad1848_detect() - step F\n"));
   ad_write (devc, 12, 0);	/* Mode2=disabled */
 
   for (i = 0; i < 16; i++)
@@ -1220,6 +1246,7 @@
      * The bit 0x80 is always 1 in CS4248 and CS4231.
    */
 
+  DDB (printk ("ad1848_detect() - step G\n"));
   ad_write (devc, 12, 0x40);	/* Set mode2, clear 0x80 */
 
   tmp1 = ad_read (devc, 12);
@@ -1238,6 +1265,7 @@
          *
          *      Verify that setting I0 doesn't change I16.
        */
+      DDB (printk ("ad1848_detect() - step H\n"));
       ad_write (devc, 16, 0);	/* Set I16 to known value */
 
       ad_write (devc, 0, 0x45);
@@ -1255,6 +1283,7 @@
 	     * Verify that some bits of I25 are read only.
 	   */
 
+	  DDB (printk ("ad1848_detect() - step I\n"));
 	  tmp1 = ad_read (devc, 25);	/* Original bits */
 	  ad_write (devc, 25, ~tmp1);	/* Invert all bits */
 	  if ((ad_read (devc, 25) & 0xe7) == (tmp1 & 0xe7))
@@ -1266,10 +1295,7 @@
 	       */
 	      devc->chip_name = "CS4231";
 
-#ifdef MOZART_PORT
-	      if (devc->base != MOZART_PORT + 4)
-#endif
-		devc->mode = MD_4231;
+	      devc->mode = MD_4231;
 
 	      /*
 	       * It could be an AD1845 or CS4231A as well.
@@ -1277,6 +1303,7 @@
 	       * while the CS4231A reports different.
 	       */
 
+	      DDB (printk ("ad1848_detect() - step I\n"));
 	      id = ad_read (devc, 25) & 0xe7;
 
 	      switch (id)
@@ -1289,12 +1316,12 @@
 
 		case 0xa2:
 		  devc->chip_name = "CS4232";
-		  devc->mode = MD_4231A;
+		  devc->mode = MD_4232;
 		  break;
 
 		case 0xb2:
 		  devc->chip_name = "CS4232A";
-		  devc->mode = MD_4231A;
+		  devc->mode = MD_4232;
 		  break;
 
 		case 0x80:
@@ -1326,15 +1353,18 @@
 	    }
 	  ad_write (devc, 25, tmp1);	/* Restore bits */
 
+	  DDB (printk ("ad1848_detect() - step K\n"));
 	}
     }
 
+  DDB (printk ("ad1848_detect() - step L\n"));
   if (ad_flags)
     {
       if (devc->mode != MD_1848)
 	*ad_flags |= AD_F_CS4231;
     }
 
+  DDB (printk ("ad1848_detect() - Detected OK\n"));
   return 1;
 }
 
@@ -1360,6 +1390,7 @@
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
   };
   int             i, my_dev;
+
   ad1848_info    *devc = &dev_info[nr_ad1848_devs];
 
   if (!ad1848_detect (io_base, NULL, osp))
@@ -1402,14 +1433,17 @@
       for (i = 16; i < 32; i++)
 	ad_write (devc, i, init_values[i]);
 
-      if (devc->mode == MD_4231A)
+      if (devc->mode == MD_4231A || devc->mode == MD_4232)
 	ad_write (devc, 9, init_values[9] | 0x18);	/* Enable full calibration */
 
       if (devc->mode == MD_1845)
 	ad_write (devc, 27, init_values[27] | 0x08);	/* Alternate freq select enabled */
     }
   else
-    ad_write (devc, 9, ad_read (devc, 9) | 0x04);	/* Single DMA mode */
+    {
+      ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+      ad_write (devc, 9, ad_read (devc, 9) | 0x04);	/* Single DMA mode */
+    }
 
   outb (0, io_Status (devc));	/* Clear pending interrupts */
 
@@ -1420,7 +1454,8 @@
     sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
 	     "Generic audio codec (%s)", devc->chip_name);
 
-  printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
+  conf_printf2 (ad1848_pcm_operations[nr_ad1848_devs].name,
+		devc->base, devc->irq, dma_playback, dma_capture);
 
   if (num_audiodevs < MAX_AUDIO_DEV)
     {
@@ -1473,7 +1508,7 @@
       audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
       nr_ad1848_devs++;
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
       if (devc->mode != MD_1848 && devc->irq_ok)
 	ad1848_tmr_install (my_dev);
 #endif
@@ -1546,6 +1581,7 @@
   unsigned char   status;
   ad1848_info    *devc;
   int             dev;
+  int             alt_stat = 0xff;
 
   if (irq < 0 || irq > 15)
     {
@@ -1579,54 +1615,78 @@
 
   if (status & 0x01)
     {
-      int             alt_stat;
 
       if (devc->mode != MD_1848)
-	{
-	  alt_stat = ad_read (devc, 24);
-	  if (alt_stat & 0x40)	/* Timer interrupt */
-	    {
-	      devc->timer_ticks++;
-#ifndef EXCLUDE_SEQUENCER
-	      if (timer_installed == dev && devc->timer_running)
-		sound_timer_interrupt ();
-#endif
-	    }
-	}
-      else
-	alt_stat = 0xff;
+	alt_stat = ad_read (devc, 24);
 
       if (devc->opened && devc->irq_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
 	{
 	  DMAbuf_inputintr (dev);
 	}
 
-      if (devc->opened && devc->irq_mode & PCM_ENABLE_OUTPUT && alt_stat & 0x10)
+      if (devc->opened && devc->irq_mode & PCM_ENABLE_OUTPUT &&
+	  alt_stat & 0x10)
 	{
 	  DMAbuf_outputintr (dev, 1);
 	}
-    }
 
-  outb (0, io_Status (devc));	/* Clear interrupt status */
+      if (devc->mode != MD_1848 && alt_stat & 0x40)	/* Timer interrupt */
+	{
+	  devc->timer_ticks++;
+#ifdef CONFIG_SEQUENCER
+	  if (timer_installed == dev && devc->timer_running)
+	    sound_timer_interrupt ();
+#endif
+	}
+    }
 
+  if (devc->mode != MD_1848)
+    ad_write (devc, 24, ad_read (devc, 24) & ~alt_stat);	/* Selective ack */
+  else
+    outb (0, io_Status (devc));	/* Clear interrupt status */
 }
 
 /*
  * Some extra code for the MS Sound System
  */
 
+void
+check_opl3 (int base, struct address_info *hw_config)
+{
+
+  if (check_region (base, 4))
+    {
+      printk ("\n\nopl3.c: I/O port %x already in use\n\n", base);
+      return;
+    }
+
+  if (!opl3_detect (base, hw_config->osp))
+    return;
+
+  opl3_init (0, base, hw_config->osp);
+  request_region (base, 4, "OPL3/OPL2");
+}
+
 int
 probe_ms_sound (struct address_info *hw_config)
 {
   unsigned char   tmp;
 
+  DDB (printk ("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype));
+
   if (check_region (hw_config->io_base, 8))
     {
       printk ("MSS: I/O port conflict\n");
       return 0;
     }
 
-#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MSS)
+  if (hw_config->card_subtype == 1)	/* Has no IRQ/DMA registers */
+    {
+      /* check_opl3(0x388, hw_config); */
+      return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp);
+    }
+
+#if defined(CONFIG_AEDSP16) && defined(AEDSP16_MSS)
   /*
      * Initialize Audio Excel DSP 16 to MSS: before any operation
      * we must enable MSS I/O ports.
@@ -1635,9 +1695,6 @@
   InitAEDSP16_MSS (hw_config);
 #endif
 
-  if (hw_config->card_subtype == 1)	/* Has IRQ/DMA registers */
-    return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp);
-
   /*
      * Check if the IO port returns valid signature. The original MS Sound
      * system returns 0x04 while some cards (AudioTriX Pro for example)
@@ -1645,7 +1702,10 @@
    */
 
   if ((tmp = inb (hw_config->io_base + 3)) == 0xff)	/* Bus float */
-    return 0;
+    {
+      DDB (printk ("I/O address is inactive (%x)\n", tmp));
+      return 0;
+    }
   if ((tmp & 0x3f) != 0x04 &&
       (tmp & 0x3f) != 0x0f &&
       (tmp & 0x3f) != 0x00)
@@ -1700,11 +1760,22 @@
     1, 2, 0, 3
   };
 
-  int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+  int             config_port = hw_config->io_base + 0;
+  int             version_port = hw_config->io_base + 3;
 
   if (!ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp))
     return mem_start;
 
+  if (hw_config->card_subtype == 1)	/* Has no IRQ/DMA registers */
+    {
+      ad1848_init ("MS Sound System", hw_config->io_base + 4,
+		   hw_config->irq,
+		   hw_config->dma,
+		   hw_config->dma2, 0, hw_config->osp);
+      request_region (hw_config->io_base, 4, "WSS config");
+      return mem_start;
+    }
+
   /*
      * Set the IRQ and DMA addresses.
    */
@@ -1768,7 +1839,7 @@
   release_region (hw_config->io_base, 4);
 }
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
 /*
  * Timer stuff (for /dev/music).
  */
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h
--- v1.3.57/linux/drivers/sound/ad1848_mixer.h	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/ad1848_mixer.h	Tue Jan  9 00:36:53 1996
@@ -35,20 +35,6 @@
  * (Actually this is not a mapping but rather some kind of interleaving
  * solution).
  */
-#ifdef GUSMAX_MIXER
-#define MODE1_REC_DEVICES		(SOUND_MASK_LINE | SOUND_MASK_MIC | \
-					 SOUND_MASK_CD|SOUND_MASK_IMIX)
-
-#define MODE1_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_MIC | \
-					 SOUND_MASK_CD | \
-					 SOUND_MASK_IGAIN | \
-					 SOUND_MASK_PCM|SOUND_MASK_IMIX)
-
-#define MODE2_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
-					 SOUND_MASK_CD | SOUND_MASK_SPEAKER | \
-					 SOUND_MASK_IGAIN | \
-					 SOUND_MASK_PCM | SOUND_MASK_IMIX)
-#else	/* Generic mapping */
 #define MODE1_REC_DEVICES		(SOUND_MASK_LINE3 | SOUND_MASK_MIC | \
 					 SOUND_MASK_LINE1|SOUND_MASK_IMIX)
 
@@ -61,7 +47,8 @@
 					 SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \
 					 SOUND_MASK_IGAIN | \
 					 SOUND_MASK_PCM | SOUND_MASK_IMIX)
-#endif
+
+#define MODE3_MIXER_DEVICES		(MODE2_MIXER_DEVICES | SOUND_MASK_VOLUME)
 
 struct mixer_def {
 	unsigned int regno: 7;
@@ -93,8 +80,8 @@
 #define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r)	\
 	{{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}
 
-mixer_ent mix_devices[32][2] = {	/* As used in GUS MAX */
-MIX_ENT(SOUND_MIXER_VOLUME,	 0, 0, 0, 0,	 0, 0, 0, 0),
+mixer_ent mix_devices[32][2] = {
+MIX_ENT(SOUND_MIXER_VOLUME,	27, 1, 0, 4,	29, 1, 0, 4),
 MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0),
 MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0),
 MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5),
@@ -115,11 +102,11 @@
 
 static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] =
 {
-  0x5a5a,			/* Master Volume */
+  0x3232,			/* Master Volume */
   0x3232,			/* Bass */
   0x3232,			/* Treble */
   0x4b4b,			/* FM */
-  0x4040,			/* PCM */
+  0x3232,			/* PCM */
   0x4b4b,			/* PC Speaker */
   0x2020,			/* Ext Line */
   0x1010,			/* Mic */
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c
--- v1.3.57/linux/drivers/sound/adlib_card.c	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/adlib_card.c	Tue Jan  9 00:37:06 1996
@@ -29,7 +29,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812)
+#if defined(CONFIG_YM3812)
 
 long
 attach_adlib_card (long mem_start, struct address_info *hw_config)
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c
--- v1.3.57/linux/drivers/sound/aedsp16.c	Fri Oct 13 14:44:33 1995
+++ linux/drivers/sound/aedsp16.c	Tue Jan  9 00:37:07 1996
@@ -32,10 +32,10 @@
 #include "sound_config.h"
 
 #ifndef AEDSP16_BASE
-#define EXCLUDE_AEDSP16
+#undef CONFIG_AEDSP16
 #endif
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AEDSP16)
+#if defined(CONFIG_AEDSP16)
 /*
 
    READ THIS
@@ -865,4 +865,4 @@
 
 #endif /* 0 */
 
-#endif /* !EXCLUDE_AEDSP16 */
+#endif /* CONFIG_AEDSP16 */
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v1.3.57/linux/drivers/sound/audio.c	Thu Nov  9 11:23:51 1995
+++ linux/drivers/sound/audio.c	Tue Jan  9 00:37:08 1996
@@ -29,8 +29,7 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
 
 #include "ulaw.h"
 #include "coproc.h"
@@ -38,14 +37,6 @@
 #define ON		1
 #define OFF		0
 
-static int      wr_buff_no[MAX_AUDIO_DEV];	/*
-
-						 * != -1, if there is
-						 * a incomplete output
-						 * block in the queue.
-						 */
-static int      wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
-
 static int      audio_mode[MAX_AUDIO_DEV];
 static int      dev_nblock[MAX_AUDIO_DEV];	/* 1 if in noblocking mode */
 
@@ -53,12 +44,11 @@
 #define		AM_WRITE	1
 #define 	AM_READ		2
 
-static char    *wr_dma_buf[MAX_AUDIO_DEV];
 static int      audio_format[MAX_AUDIO_DEV];
 static int      local_conversion[MAX_AUDIO_DEV];
 
 static int
-set_format (int dev, long fmt)
+set_format (int dev, int fmt)
 {
   if (fmt != AFMT_QUERY)
     {
@@ -87,7 +77,7 @@
 audio_open (int dev, struct fileinfo *file)
 {
   int             ret;
-  long            bits;
+  int             bits;
   int             dev_type = dev & 0x0f;
   int             mode = file->mode & O_ACCMODE;
 
@@ -126,15 +116,25 @@
   else
     set_format (dev, bits);
 
-  wr_buff_no[dev] = -1;
   audio_mode[dev] = AM_NONE;
-  wr_buff_size[dev] = wr_buff_ptr[dev] = 0;
   dev_nblock[dev] = 0;
 
   return ret;
 }
 
 void
+sync_output (int dev)
+{
+  int             buf_no, buf_ptr, buf_size;
+  char           *dma_buf;
+
+  if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
+    {
+      DMAbuf_start_output (dev, buf_no, buf_ptr);
+    }
+}
+
+void
 audio_release (int dev, struct fileinfo *file)
 {
   int             mode;
@@ -142,12 +142,7 @@
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
 
-  if (wr_buff_no[dev] >= 0)
-    {
-      DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
-      wr_buff_no[dev] = -1;
-    }
+  sync_output (dev);
 
   if (audio_devs[dev]->coproc)
     audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM);
@@ -188,8 +183,9 @@
 int
 audio_write (int dev, struct fileinfo *file, const snd_rw_buf * buf, int count)
 {
-  int             c, p, l;
+  int             c, p, l, buf_no, buf_ptr, buf_size;
   int             err;
+  char           *dma_buf;
 
   dev = dev >> 4;
 
@@ -198,7 +194,6 @@
 
   if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
     {				/* Direction change */
-      wr_buff_no[dev] = -1;
     }
 
   if (audio_devs[dev]->flags & DMA_DUPLEX)
@@ -206,57 +201,41 @@
   else
     audio_mode[dev] = AM_WRITE;
 
-  if (!count)			/*
-				 * Flush output
-				 */
+  if (!count)			/* Flush output */
     {
-      if (wr_buff_no[dev] >= 0)
-	{
-	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
-	  wr_buff_no[dev] = -1;
-	}
+      sync_output (dev);
       return 0;
     }
 
   while (c)
-    {				/*
-				 * Perform output blocking
-				 */
-      if (wr_buff_no[dev] < 0)	/*
-				 * There is no incomplete buffers
-				 */
+    {
+      if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) < 0)
 	{
-	  if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev],
-						     &wr_buff_size[dev],
-						     dev_nblock[dev])) < 0)
+	  if ((buf_no = DMAbuf_getwrbuffer (dev, &dma_buf,
+					    &buf_size,
+					    dev_nblock[dev])) < 0)
 	    {
 	      /* Handle nonblocking mode */
-	      if (dev_nblock[dev] && wr_buff_no[dev] == -EAGAIN)
+	      if (dev_nblock[dev] && buf_no == -EAGAIN)
 		return p;	/* No more space. Return # of accepted bytes */
-	      return wr_buff_no[dev];
+	      return buf_no;
 	    }
-	  wr_buff_ptr[dev] = 0;
+	  buf_ptr = 0;
 	}
 
       l = c;
-      if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
-	l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
+      if (l > (buf_size - buf_ptr))
+	l = (buf_size - buf_ptr);
 
       if (!audio_devs[dev]->copy_from_user)
 	{			/*
 				 * No device specific copy routine
 				 */
-	  memcpy_fromfs (&wr_dma_buf[dev][wr_buff_ptr[dev]], &((buf)[p]), l);
+	  memcpy_fromfs (&dma_buf[buf_ptr], &((buf)[p]), l);
 	}
       else
 	audio_devs[dev]->copy_from_user (dev,
-			      wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
-
-
-      /*
-       * Insert local processing here
-       */
+					 dma_buf, buf_ptr, buf, p, l);
 
       if (local_conversion[dev] == AFMT_MU_LAW)
 	{
@@ -264,22 +243,23 @@
 	   * This just allows interrupts while the conversion is running
 	   */
 	  sti ();
-	  translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+	  translate_bytes (ulaw_dsp, (unsigned char *) &dma_buf[buf_ptr], l);
 	}
 
       c -= l;
       p += l;
-      wr_buff_ptr[dev] += l;
+      buf_ptr += l;
 
-      if (wr_buff_ptr[dev] >= wr_buff_size[dev])
+      if (buf_ptr >= buf_size)
 	{
-	  if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
+	  if ((err = DMAbuf_start_output (dev, buf_no, buf_ptr)) < 0)
 	    {
 	      return err;
 	    }
 
-	  wr_buff_no[dev] = -1;
 	}
+      else
+	DMAbuf_set_count (dev, buf_no, buf_ptr);
 
     }
 
@@ -291,7 +271,7 @@
 {
   int             c, p, l;
   char           *dmabuf;
-  int             buff_no;
+  int             buf_no;
 
   dev = dev >> 4;
   p = 0;
@@ -299,13 +279,7 @@
 
   if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
     {
-      if (wr_buff_no[dev] >= 0)
-	{
-	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
-	  if (!(audio_devs[dev]->flags & DMA_DUPLEX))
-	    wr_buff_no[dev] = -1;
-	}
+      sync_output (dev);
     }
 
   if (audio_devs[dev]->flags & DMA_DUPLEX)
@@ -315,15 +289,15 @@
 
   while (c)
     {
-      if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l,
-					 dev_nblock[dev])) < 0)
+      if ((buf_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l,
+					dev_nblock[dev])) < 0)
 	{
 	  /* Nonblocking mode handling. Return current # of bytes */
 
-	  if (dev_nblock[dev] && buff_no == -EAGAIN)
+	  if (dev_nblock[dev] && buf_no == -EAGAIN)
 	    return p;
 
-	  return buff_no;
+	  return buf_no;
 	}
 
       if (l > c)
@@ -345,7 +319,7 @@
 
       memcpy_tofs (&((buf)[p]), dmabuf, l);
 
-      DMAbuf_rmchars (dev, buff_no, l);
+      DMAbuf_rmchars (dev, buf_no, l);
 
       p += l;
       c -= l;
@@ -374,27 +348,16 @@
     switch (cmd)
       {
       case SNDCTL_DSP_SYNC:
-	if (wr_buff_no[dev] >= 0)
-	  {
-	    DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
-	    wr_buff_no[dev] = -1;
-	  }
+	sync_output (dev);
 	return DMAbuf_ioctl (dev, cmd, arg, 0);
 	break;
 
       case SNDCTL_DSP_POST:
-	if (wr_buff_no[dev] >= 0)
-	  {
-	    DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
-	    wr_buff_no[dev] = -1;
-	  }
+	sync_output (dev);
 	return 0;
 	break;
 
       case SNDCTL_DSP_RESET:
-	wr_buff_no[dev] = -1;
 	audio_mode[dev] = AM_NONE;
 	return DMAbuf_ioctl (dev, cmd, arg, 0);
 	break;
@@ -428,14 +391,16 @@
 
 	{
 	  audio_buf_info  info;
+	  char           *dma_buf;
+	  int             buf_no, buf_ptr, buf_size;
 
 	  int             err = DMAbuf_ioctl (dev, cmd, (ioctl_arg) & info, 1);
 
 	  if (err < 0)
 	    return err;
 
-	  if (wr_buff_no[dev] != -1)
-	    info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev];
+	  if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
+	    info.bytes += buf_size - buf_ptr;
 
 	  memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info));
 	  return 0;
@@ -482,8 +447,10 @@
 }
 
 int
-audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+audio_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
 {
+  char           *dma_buf;
+  int             buf_no, buf_ptr, buf_size;
 
   dev = dev >> 4;
 
@@ -493,7 +460,6 @@
       if (!(audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
 	return 0;		/* Not recording */
 
-
       return DMAbuf_select (dev, file, sel_type, wait);
       break;
 
@@ -501,7 +467,7 @@
       if (!(audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
 	return 0;		/* Wrong direction */
 
-      if (wr_buff_no[dev] != -1)
+      if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
 	{
 	  return 1;		/* There is space in the current buffer */
 	}
@@ -517,5 +483,4 @@
 }
 
 
-#endif
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v1.3.57/linux/drivers/sound/configure.c	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/configure.c	Tue Jan  9 00:37:10 1996
@@ -1,4 +1,4 @@
-#define DISABLED_OPTIONS 	(B(OPT_PNP))
+#define DISABLED_OPTIONS 	(B(OPT_PNP)|B(OPT_AEDSP16))
 /*
  * sound/configure.c  - Configuration program for the Linux Sound Driver
  *
@@ -67,6 +67,7 @@
 #define OPT_SEQUENCER	24
 #define OPT_LAST	24	/* Last defined OPT number */
 
+#define DUMMY_OPTS (B(OPT_MIDI_AUTO)|B(OPT_YM3812_AUTO))
 
 #define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \
 		  B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)| \
@@ -204,10 +205,13 @@
 char           *oldconf = "/etc/soundconf";
 
 int             old_config_used = 0;
+int             def_size, sb_base = 0;
 
 unsigned long   selected_options = 0;
 int             sb_dma = 0;
 
+int             dump_only = 0;
+
 void            build_defines (void);
 
 #include "hex2hex.h"
@@ -242,8 +246,7 @@
       fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
 
       perror ("stdin");
-      printf ("#undef CONFIGURE_SOUNDCARD\n");
-      printf ("#undef KERNEL_SOUNDCARD\n");
+      printf ("invalid_configuration__run_make_config_again\n");
       exit (-1);
     }
 
@@ -273,8 +276,7 @@
       fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
 
       perror ("stdin");
-      printf ("#undef CONFIGURE_SOUNDCARD\n");
-      printf ("#undef KERNEL_SOUNDCARD\n");
+      printf ("invalid_configuration__run_make_config_again\n");
       exit (-1);
     }
 
@@ -294,6 +296,74 @@
   return num;
 }
 
+#define FMT_HEX 1
+#define FMT_INT 2
+
+void
+ask_int_choice (int mask, char *macro,
+		char *question,
+		int format,
+		int defa,
+		char *choices)
+{
+  int             num, i;
+
+  if (dump_only)
+    {
+
+      for (i = 0; i < OPT_LAST; i++)
+	if (mask == B (i))
+	  {
+	    int             j;
+
+	    for (j = 0; j < strlen (choices); j++)
+	      if (choices[j] == '\'')
+		choices[j] = '_';
+
+	    printf ("\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n",
+		    hw_table[i].macro);
+	    if (format == FMT_INT)
+	      printf ("int '%s %s' %s %d\n", question, choices, macro, defa);
+	    else
+	      printf ("hex '%s %s' %s %x\n", question, choices, macro, defa);
+	    printf ("fi\n");
+	  }
+    }
+  else
+    {
+      if (!(mask & selected_options))
+	return;
+
+      fprintf (stderr, "\n%s\n", question);
+      fprintf (stderr, "Possible values are: %s\n", choices);
+
+      if (format == FMT_INT)
+	{
+	  if (defa == -1)
+	    fprintf (stderr, "\t(-1 disables this feature)\n");
+	  fprintf (stderr, "The default value is %d\n", defa);
+	  fprintf (stderr, "Enter the value: ");
+	  num = ask_value ("%d", defa);
+	  if (num == -1)
+	    return;
+	  fprintf (stderr, "%s set to %d.\n", question, num);
+	  printf ("#define %s %d\n", macro, num);
+	}
+      else
+	{
+	  if (defa == 0)
+	    fprintf (stderr, "\t(0 disables this feature)\n");
+	  fprintf (stderr, "The default value is %x\n", defa);
+	  fprintf (stderr, "Enter the value: ");
+	  num = ask_value ("%x", defa);
+	  if (num == 0)
+	    return;
+	  fprintf (stderr, "%s set to %x.\n", question, num);
+	  printf ("#define %s 0x%x\n", macro, num);
+	}
+    }
+}
+
 void
 rebuild_file (char *line)
 {
@@ -398,10 +468,30 @@
 	  if (strcmp (tmp, "SELECTED_SOUND_OPTIONS") == 0)
 	    continue;
 
+	  if (strcmp (tmp, "KERNEL_SOUNDCARD") == 0)
+	    continue;
+
 	  tmp[8] = 0;		/* Truncate the string */
 	  if (strcmp (tmp, "EXCLUDE_") == 0)
 	    continue;		/* Skip excludes */
 
+	  strncpy (tmp, id, i);
+	  tmp[7] = 0;		/* Truncate the string */
+
+	  if (strcmp (tmp, "CONFIG_") == 0)
+	    {
+	      strncpy (tmp, &id[7], i - 7);
+	      tmp[i - 7] = 0;
+
+	      for (i = 0; i <= OPT_LAST; i++)
+		if (strcmp (hw_table[i].macro, tmp) == 0)
+		  {
+		    selected_options |= (1 << i);
+		    break;
+		  }
+	      continue;
+	    }
+
 	  printf ("%s", buf);
 	  continue;
 	}
@@ -416,7 +506,11 @@
 	    i++;
 
 	  strncpy (tmp, id, i);
-	  tmp[i] = 0;
+	  tmp[7] = 0;		/* Truncate the string */
+	  if (strcmp (tmp, "CONFIG_") == 0)
+	    continue;
+
+	  strncpy (tmp, id, i);
 
 	  tmp[8] = 0;		/* Truncate the string */
 	  if (strcmp (tmp, "EXCLUDE_") != 0)
@@ -440,9 +534,9 @@
   for (i = 0; i <= OPT_LAST; i++)
     if (!hw_table[i].alias)
       if (selected_options & B (i))
-	printf ("#undef  EXCLUDE_%s\n", hw_table[i].macro);
+	printf ("#define CONFIG_%s\n", hw_table[i].macro);
       else
-	printf ("#define EXCLUDE_%s\n", hw_table[i].macro);
+	printf ("#undef  CONFIG_%s\n", hw_table[i].macro);
 
 
   printf ("\n");
@@ -452,9 +546,9 @@
   while (extra_options[i].name != NULL)
     {
       if (selected_options & extra_options[i].mask)
-	printf ("#undef  EXCLUDE_%s\n", extra_options[i].name);
+	printf ("#define CONFIG_%s\n", extra_options[i].name);
       else
-	printf ("#define EXCLUDE_%s\n", extra_options[i].name);
+	printf ("#undef  CONFIG_%s\n", extra_options[i].name);
       i++;
     }
 
@@ -502,16 +596,484 @@
   fclose (optf);
 }
 
+void
+ask_parameters (void)
+{
+  int             num;
+
+  build_defines ();
+  /*
+   * IRQ and DMA settings
+   */
+
+  ask_int_choice (B (OPT_AEDSP16), "AEDSP16_BASE",
+		  "I/O base for Audio Excel DSP 16",
+		  FMT_HEX,
+		  0x220,
+		  "220 or 240");
+
+  ask_int_choice (B (OPT_SB), "SBC_BASE",
+		  "I/O base for SB",
+		  FMT_HEX,
+		  0x220,
+		  "");
+
+  ask_int_choice (B (OPT_SB), "SBC_IRQ",
+		  "SoundBlaster IRQ",
+		  FMT_INT,
+		  7,
+		  "");
+
+  ask_int_choice (B (OPT_SB), "SBC_DMA",
+		  "SoundBlaster DMA",
+		  FMT_INT,
+		  1,
+		  "");
+
+  ask_int_choice (B (OPT_SB), "SB_DMA2",
+		  "SoundBlaster 16 bit DMA (if required)",
+		  FMT_INT,
+		  -1,
+		  "5, 6 or 7");
+
+  ask_int_choice (B (OPT_SB), "SB_MPU_BASE",
+		  "MPU401 I/O base of SB16, Jazz16 and ES1688",
+		  FMT_HEX,
+		  0,
+		  "");
+
+  ask_int_choice (B (OPT_SB), "SB_MPU_IRQ",
+		  "SB MPU401 IRQ (SB16, Jazz16 and ES1688)",
+		  FMT_INT,
+		  -1,
+		  "");
+
+  ask_int_choice (B (OPT_PAS), "PAS_IRQ",
+		  "PAS16 IRQ",
+		  FMT_INT,
+		  10,
+		  "");
+
+  ask_int_choice (B (OPT_PAS), "PAS_DMA",
+		  "PAS16 DMA",
+		  FMT_INT,
+		  3,
+		  "");
+
+  if (selected_options & B (OPT_PAS))
+    {
+      fprintf (stderr, "\nEnable Joystick port on ProAudioSpectrum (n/y) ? ");
+      if (think_positively (0))
+	printf ("#define PAS_JOYSTICK_ENABLE\n");
+
+
+      fprintf (stderr, "PAS16 could be noisy with some mother boards\n"
+	       "There is a command line switch (was it :T?)\n"
+	       "in the DOS driver for PAS16 which solves this.\n"
+	       "Don't enable this feature unless you have problems!\n"
+	       "Do you have to use this switch with DOS (y/n) ?");
+      if (think_positively (0))
+	printf ("#define BROKEN_BUS_CLOCK\n");
+    }
+
+
+  ask_int_choice (B (OPT_GUS), "GUS_BASE",
+		  "I/O base for Gravis UltraSound (GUS)",
+		  FMT_HEX,
+		  0x220,
+		  "210, 220, 230, 240, 250 or 260");
+
+
+  ask_int_choice (B (OPT_GUS), "GUS_IRQ",
+		  "GUS IRQ",
+		  FMT_INT,
+		  15,
+		  "");
+
+  ask_int_choice (B (OPT_GUS), "GUS_DMA",
+		  "GUS DMA",
+		  FMT_INT,
+		  6,
+		  "");
+
+  ask_int_choice (B (OPT_GUS), "GUS_DMA2",
+		  "Second DMA channel for GUS",
+		  FMT_INT,
+		  -1,
+		  "");
+
+  ask_int_choice (B (OPT_GUS16), "GUS16_BASE",
+		  "I/O base for the 16 bit daughtercard of GUS",
+		  FMT_HEX,
+		  0x530,
+		  "530, 604, E80 or F40");
+
+
+  ask_int_choice (B (OPT_GUS16), "GUS16_IRQ",
+		  "GUS 16 bit daughtercard IRQ",
+		  FMT_INT,
+		  7,
+		  "3, 4, 5, 7, or 9");
+
+  ask_int_choice (B (OPT_GUS16), "GUS16_DMA",
+		  "GUS DMA",
+		  FMT_INT,
+		  3,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_MPU401), "MPU_BASE",
+		  "I/O base for MPU401",
+		  FMT_HEX,
+		  0x330,
+		  "");
+
+  ask_int_choice (B (OPT_MPU401), "MPU_IRQ",
+		  "MPU401 IRQ",
+		  FMT_INT,
+		  9,
+		  "");
+
+  ask_int_choice (B (OPT_MAUI), "MAUI_BASE",
+		  "I/O base for Maui",
+		  FMT_HEX,
+		  0x330,
+		  "210, 230, 260, 290, 300, 320, 338 or 330");
+
+  ask_int_choice (B (OPT_MAUI), "MAUI_IRQ",
+		  "Maui IRQ",
+		  FMT_INT,
+		  9,
+		  "5, 9, 12 or 15");
+
+  ask_int_choice (B (OPT_UART6850), "U6850_BASE",
+		  "I/O base for UART 6850 MIDI port",
+		  FMT_HEX,
+		  0,
+		  "(Unknown)");
+
+  ask_int_choice (B (OPT_UART6850), "U6850_IRQ",
+		  "UART6850 IRQ",
+		  FMT_INT,
+		  -1,
+		  "(Unknown)");
+
+  ask_int_choice (B (OPT_PSS), "PSS_BASE",
+		  "PSS I/O base",
+		  FMT_HEX,
+		  0x220,
+		  "220 or 240");
+
+  ask_int_choice (B (OPT_PSS), "PSS_MSS_BASE",
+		  "PSS audio I/O base",
+		  FMT_HEX,
+		  0x530,
+		  "530, 604, E80 or F40");
+
+  ask_int_choice (B (OPT_PSS), "PSS_MSS_IRQ",
+		  "PSS audio IRQ",
+		  FMT_INT,
+		  11,
+		  "7, 9, 10 or 11");
+
+  ask_int_choice (B (OPT_PSS), "PSS_MSS_DMA",
+		  "PSS audio DMA",
+		  FMT_INT,
+		  3,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_PSS), "PSS_MPU_BASE",
+		  "PSS MIDI I/O base",
+		  FMT_HEX,
+		  0x330,
+		  "");
+
+  ask_int_choice (B (OPT_PSS), "PSS_MPU_IRQ",
+		  "PSS MIDI IRQ",
+		  FMT_INT,
+		  9,
+		  "3, 4, 5, 7 or 9");
+
+  ask_int_choice (B (OPT_MSS), "MSS_BASE",
+		  "MSS/WSS I/O base",
+		  FMT_HEX,
+		  0x530,
+		  "530, 604, E80 or F40");
+
+  ask_int_choice (B (OPT_MSS), "MSS_IRQ",
+		  "MSS/WSS IRQ",
+		  FMT_INT,
+		  11,
+		  "7, 9, 10 or 11");
+
+  ask_int_choice (B (OPT_MSS), "MSS_DMA",
+		  "MSS/WSS DMA",
+		  FMT_INT,
+		  3,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_SSCAPE), "SSCAPE_BASE",
+		  "Soundscape MIDI I/O base",
+		  FMT_HEX,
+		  0x330,
+		  "");
+
+  ask_int_choice (B (OPT_SSCAPE), "SSCAPE_IRQ",
+		  "Soundscape MIDI IRQ",
+		  FMT_INT,
+		  9,
+		  "");
+
+  ask_int_choice (B (OPT_SSCAPE), "SSCAPE_DMA",
+		  "Soundscape initialization DMA",
+		  FMT_INT,
+		  3,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_BASE",
+		  "Soundscape audio I/O base",
+		  FMT_HEX,
+		  0x534,
+		  "534, 608, E84 or F44");
+
+  ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_IRQ",
+		  "Soundscape audio IRQ",
+		  FMT_INT,
+		  11,
+		  "7, 9, 10 or 11");
+
+  ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_DMA",
+		  "Soundscape audio DMA",
+		  FMT_INT,
+		  0,
+		  "0, 1 or 3");
+
+  if (selected_options & B (OPT_SSCAPE))
+    {
+      int             reveal_spea;
+
+      fprintf (stderr, "Is your SoundScape card made/marketed by Reveal or Spea? ");
+      reveal_spea = think_positively (0);
+      if (reveal_spea)
+	printf ("#define REVEAL_SPEA\n");
+
+    }
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_BASE",
+		  "AudioTriX audio I/O base",
+		  FMT_HEX,
+		  0x530,
+		  "530, 604, E80 or F40");
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_IRQ",
+		  "AudioTriX audio IRQ",
+		  FMT_INT,
+		  11,
+		  "7, 9, 10 or 11");
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_DMA",
+		  "AudioTriX audio DMA",
+		  FMT_INT,
+		  0,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_DMA2",
+		  "AudioTriX second (duplex) DMA",
+		  FMT_INT,
+		  3,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_MPU_BASE",
+		  "AudioTriX MIDI I/O base",
+		  FMT_HEX,
+		  0x330,
+		  "330, 370, 3B0 or 3F0");
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_MPU_IRQ",
+		  "AudioTriX MIDI IRQ",
+		  FMT_INT,
+		  9,
+		  "3, 4, 5, 7 or 9");
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_SB_BASE",
+		  "AudioTriX SB I/O base",
+		  FMT_HEX,
+		  0x220,
+		  "220, 210, 230, 240, 250, 260 or 270");
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_SB_IRQ",
+		  "AudioTriX SB IRQ",
+		  FMT_INT,
+		  7,
+		  "3, 4, 5 or 7");
+
+  ask_int_choice (B (OPT_TRIX), "TRIX_SB_DMA",
+		  "AudioTriX SB DMA",
+		  FMT_INT,
+		  1,
+		  "1 or 3");
+
+  ask_int_choice (B (OPT_CS4232), "CS4232_BASE",
+		  "CS4232 audio I/O base",
+		  FMT_HEX,
+		  0x530,
+		  "530, 604, E80 or F40");
+
+  ask_int_choice (B (OPT_CS4232), "CS4232_IRQ",
+		  "CS4232 audio IRQ",
+		  FMT_INT,
+		  11,
+		  "5, 7, 9, 11, 12 or 15");
+
+  ask_int_choice (B (OPT_CS4232), "CS4232_DMA",
+		  "CS4232 audio DMA",
+		  FMT_INT,
+		  0,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_CS4232), "CS4232_DMA2",
+		  "CS4232 second (duplex) DMA",
+		  FMT_INT,
+		  3,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_CS4232), "CS4232_MPU_BASE",
+		  "CS4232 MIDI I/O base",
+		  FMT_HEX,
+		  0x330,
+		  "330, 370, 3B0 or 3F0");
+
+  ask_int_choice (B (OPT_CS4232), "CS4232_MPU_IRQ",
+		  "CS4232 MIDI IRQ",
+		  FMT_INT,
+		  9,
+		  "5, 7, 9, 11, 12 or 15");
+
+  ask_int_choice (B (OPT_MAD16), "MAD16_BASE",
+		  "MAD16 audio I/O base",
+		  FMT_HEX,
+		  0x530,
+		  "530, 604, E80 or F40");
+
+  ask_int_choice (B (OPT_MAD16), "MAD16_IRQ",
+		  "MAD16 audio IRQ",
+		  FMT_INT,
+		  11,
+		  "7, 9, 10 or 11");
+
+  ask_int_choice (B (OPT_MAD16), "MAD16_DMA",
+		  "MAD16 audio DMA",
+		  FMT_INT,
+		  3,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_MAD16), "MAD16_DMA2",
+		  "MAD16 second (duplex) DMA",
+		  FMT_INT,
+		  0,
+		  "0, 1 or 3");
+
+  ask_int_choice (B (OPT_MAD16), "MAD16_MPU_BASE",
+		  "MAD16 MIDI I/O base",
+		  FMT_HEX,
+		  0x330,
+		  "300, 310, 320 or 330 (0 disables)");
+
+  ask_int_choice (B (OPT_MAD16), "MAD16_MPU_IRQ",
+		  "MAD16 MIDI IRQ",
+		  FMT_INT,
+		  9,
+		  "5, 7, 9 or 10");
+  ask_int_choice (B (OPT_AUDIO), "DSP_BUFFSIZE",
+		  "Audio DMA buffer size",
+		  FMT_INT,
+		  65536,
+		  "4096, 16384, 32768 or 65536");
+}
+
+void
+dump_script (void)
+{
+  int             i;
+
+  for (i = 0; i <= OPT_LAST; i++)
+    if (!(DUMMY_OPTS & B (i)))
+      if (!(DISABLED_OPTIONS & B (i)))
+	{
+	  printf ("bool '%s' CONFIG_%s\n", questions[i], hw_table[i].macro);
+	}
+
+  dump_only = 1;
+  selected_options = 0;
+  ask_parameters ();
+
+  printf ("#\n$MAKE -C drivers/sound kernelconfig || exit 1\n");
+}
+
+void
+dump_fixed_local (void)
+{
+  int             i = 0;
+
+  printf ("/* Computer generated file. Please don't edit! */\n\n");
+  printf ("#define KERNEL_COMPATIBLE_CONFIG\n\n");
+  printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n\n", selected_options);
+
+  while (extra_options[i].name != NULL)
+    {
+      int             n = 0, j;
+
+      printf ("#if ");
+
+      for (j = 0; j < OPT_LAST; j++)
+	if (!(DISABLED_OPTIONS & B (j)))
+	  if (extra_options[i].mask & B (j))
+	    {
+	      if (n)
+		printf (" || ");
+	      if (!(n++ % 2))
+		printf ("\\\n  ");
+
+	      printf ("defined(CONFIG_%s)", hw_table[j].macro);
+	    }
+
+      printf ("\n");
+      printf ("#\tdefine CONFIG_%s\n", extra_options[i].name);
+      printf ("#endif\n\n");
+      i++;
+    }
+}
+
+void
+dump_fixed_defines (void)
+{
+  int             i = 0;
+
+  printf ("# Computer generated file. Please don't edit\n\n");
+
+  while (extra_options[i].name != NULL)
+    {
+      int             n = 0, j;
+
+      for (j = 0; j < OPT_LAST; j++)
+	if (!(DISABLED_OPTIONS & B (j)))
+	  if (extra_options[i].mask & B (j))
+	    {
+	      printf ("ifdef CONFIG_%s\n", hw_table[j].macro);
+	      printf ("CONFIG_%s=y\n", extra_options[i].name);
+	      printf ("endif\n\n");
+	    }
+
+      i++;
+    }
+}
+
 int
 main (int argc, char *argv[])
 {
-  int             i, num, def_size, full_driver = 1;
+  int             i, num, full_driver = 1;
   char            answ[10];
-  int             sb_base = 0;
   char            old_config_file[200];
 
-  fprintf (stderr, "\nConfiguring the sound support\n\n");
-
   if (getuid () != 0)		/* Not root */
     {
       char           *home;
@@ -528,8 +1090,25 @@
       if (strcmp (argv[1], "-o") == 0 &&
 	  use_old_config (oldconf))
 	exit (0);
+      else if (strcmp (argv[1], "script") == 0)
+	{
+	  dump_script ();
+	  exit (0);
+	}
+      else if (strcmp (argv[1], "fixedlocal") == 0)
+	{
+	  dump_fixed_local ();
+	  exit (0);
+	}
+      else if (strcmp (argv[1], "fixeddefines") == 0)
+	{
+	  dump_fixed_defines ();
+	  exit (0);
+	}
     }
 
+  fprintf (stderr, "\nConfiguring the sound support\n\n");
+
   if (access (oldconf, R_OK) == 0)
     {
       fprintf (stderr, "Old configuration exists in %s. Use it (y/n) ? ",
@@ -540,7 +1119,10 @@
 
     }
 
-  printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n\n");
+  printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n");
+  printf ("/*\tMaking changes to this file is not as simple as it may look.\t*/\n\n");
+  printf ("/*\tIf you change the CONFIG_ settings in local.h you\t*/\n");
+  printf ("/*\t_have_ to edit .defines too.\t*/\n\n");
 
   {
     /*
@@ -590,18 +1172,6 @@
       fprintf (stderr, "Do you want support for the MV Jazz16 (ProSonic etc.) ? ");
       if (think_positively (0))
 	{
-	  printf ("#define JAZZ16\n");
-	  do
-	    {
-	      fprintf (stderr, "\tValid 16 bit DMA channels for ProSonic/Jazz 16 are\n");
-	      fprintf (stderr, "\t1, 3, 5 (default), 7\n");
-	      fprintf (stderr, "\tEnter 16bit DMA channel for Prosonic : ");
-	      num = ask_value ("%d", 5);
-	    }
-	  while (num != 1 && num != 3 && num != 5 && num != 7);
-	  fprintf (stderr, "ProSonic 16 bit DMA set to %d\n", num);
-	  printf ("#define JAZZ_DMA16 %d\n", num);
-
 	  fprintf (stderr, "Do you have SoundMan Wave (n/y) ? ");
 
 	  if (think_positively (0))
@@ -687,9 +1257,8 @@
 
       if (sel1 == 0)
 	{
-	  printf ("#undef CONFIGURE_SOUNDCARD\n");
-	  printf ("#undef KERNEL_SOUNDCARD\n");
-	  fprintf (stderr, "ERROR!!!!!\nYou loose: you must select at least one mode when using Audio Excel!\n");
+	  printf ("invalid_configuration__run_make_config_again\n");
+	  fprintf (stderr, "ERROR!!!!!\nYou must select at least one mode when using Audio Excel!\n");
 	  exit (-1);
 	}
       if (selected_options & B (OPT_MPU401))
@@ -769,20 +1338,17 @@
 
   if (!(selected_options & ANY_DEVS))
     {
-      printf ("#undef CONFIGURE_SOUNDCARD\n");
-      printf ("#undef KERNEL_SOUNDCARD\n");
+      printf ("invalid_configuration__run_make_config_again\n");
       fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n\n");
       exit (0);
     }
-  else
-    printf ("#define KERNEL_SOUNDCARD\n");
 
   for (i = 0; i <= OPT_LAST; i++)
     if (!hw_table[i].alias)
       if (selected_options & B (i))
-	printf ("#undef  EXCLUDE_%s\n", hw_table[i].macro);
+	printf ("#define CONFIG_%s\n", hw_table[i].macro);
       else
-	printf ("#define EXCLUDE_%s\n", hw_table[i].macro);
+	printf ("#undef  CONFIG_%s\n", hw_table[i].macro);
 
 
   printf ("\n");
@@ -792,922 +1358,15 @@
   while (extra_options[i].name != NULL)
     {
       if (selected_options & extra_options[i].mask)
-	printf ("#undef  EXCLUDE_%s\n", extra_options[i].name);
+	printf ("#define CONFIG_%s\n", extra_options[i].name);
       else
-	printf ("#define EXCLUDE_%s\n", extra_options[i].name);
+	printf ("#undef  CONFIG_%s\n", extra_options[i].name);
       i++;
     }
 
   printf ("\n");
 
-
-
-  build_defines ();
-  /*
-   * IRQ and DMA settings
-   */
-
-  if (selected_options & B (OPT_AEDSP16))
-    {
-      fprintf (stderr, "\nI/O base for Audio Excel DSP 16 ?\n"
-	       "Warning:\n"
-	       "If you are using Audio Excel SoundBlaster emulation,\n"
-	"you must use the same I/O base for Audio Excel and SoundBlaster.\n"
-	       "The factory default is 220 (other possible value is 240)\n"
-	       "Enter the Audio Excel DSP 16 I/O base: ");
-
-      num = ask_value ("%x", 0x220);
-      fprintf (stderr, "Audio Excel DSP 16 I/O base set to %03x\n", num);
-      printf ("#define AEDSP16_BASE 0x%03x\n", num);
-    }
-
-  if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
-    {
-      fprintf (stderr, "\nI/O base for SB?\n"
-	       "The factory default is 220\n"
-	       "Enter the SB I/O base: ");
-
-      sb_base = num = ask_value ("%x", 0x220);
-      fprintf (stderr, "SB I/O base set to %03x\n", num);
-      printf ("#define SBC_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for SoundBlaster?\n"
-	       "The IRQ address is defined by the jumpers on your card.\n"
-	  "The factory default is either 5 or 7 (depending on the model).\n"
-	       "Valid values are 9(=2), 5, 7 and 10.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 7);
-      if (num != 9 && num != 5 && num != 7 && num != 10)
-	{
-
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 7;
-	}
-      fprintf (stderr, "SoundBlaster IRQ set to %d\n", num);
-
-      printf ("#define SBC_IRQ %d\n", num);
-
-      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS)))
-	{
-	  fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
-		   "For SB 1.0, 1.5 and 2.0 this MUST be 1\n"
-		   "SB Pro supports DMA channels 0, 1 and 3 (jumper)\n"
-		   "For SB16 give the 8 bit DMA# here\n"
-		   "The default value is 1\n"
-		   "Enter the value: ");
-
-	  num = ask_value ("%d", 1);
-	  if (num < 0 || num > 3)
-	    {
-
-	      fprintf (stderr, "*** Illegal input! ***\n");
-	      num = 1;
-	    }
-	  fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
-	  printf ("#define SBC_DMA %d\n", num);
-	  sb_dma = num;
-	}
-
-      if (selected_options & B (OPT_SB16))
-	{
-
-	  fprintf (stderr, "\n16 bit DMA channel for SoundBlaster 16?\n"
-		   "Possible values are 5, 6 or 7\n"
-		   "The default value is 6\n"
-		   "Enter the value: ");
-
-	  num = ask_value ("%d", 6);
-	  if ((num < 5 || num > 7) && (num != sb_dma))
-	    {
-
-	      fprintf (stderr, "*** Illegal input! ***\n");
-	      num = 6;
-	    }
-	  fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
-	  printf ("#define SB16_DMA %d\n", num);
-
-	  fprintf (stderr, "\nI/O base for SB16 Midi?\n"
-		   "Possible values are 300 and 330\n"
-		   "The factory default is 330\n"
-		   "Enter the SB16 Midi I/O base: ");
-
-	  num = ask_value ("%x", 0x330);
-	  fprintf (stderr, "SB16 Midi I/O base set to %03x\n", num);
-	  printf ("#define SB16MIDI_BASE 0x%03x\n", num);
-	}
-    }
-
-  if (selected_options & B (OPT_PAS))
-    {
-
-      if (selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
-	{
-	  fprintf (stderr, "\nIRQ number for ProAudioSpectrum?\n"
-		   "The recommended value is the IRQ used under DOS.\n"
-		   "Please refer to the ProAudioSpectrum User's Guide.\n"
-		   "The default value is 10.\n"
-		   "Enter the value: ");
-
-	  num = ask_value ("%d", 10);
-	  if (num == 6 || num < 3 || num > 15 || num == 2)	/*
-								 * Illegal
-								 */
-	    {
-
-	      fprintf (stderr, "*** Illegal input! ***\n");
-	      num = 10;
-	    }
-	  fprintf (stderr, "ProAudioSpectrum IRQ set to %d\n", num);
-	  printf ("#define PAS_IRQ %d\n", num);
-	}
-
-      if (selected_options & B (OPT_AUDIO))
-	{
-	  fprintf (stderr, "\nDMA number for ProAudioSpectrum?\n"
-		   "The recommended value is the DMA channel under DOS.\n"
-		   "Please refer to the ProAudioSpectrum User's Guide.\n"
-		   "The default value is 3\n"
-		   "Enter the value: ");
-
-	  num = ask_value ("%d", 3);
-	  if (num == 4 || num < 0 || num > 7)
-	    {
-
-	      fprintf (stderr, "*** Illegal input! ***\n");
-	      num = 3;
-	    }
-	  fprintf (stderr, "\nProAudioSpectrum DMA set to %d\n", num);
-	  printf ("#define PAS_DMA %d\n", num);
-	}
-      fprintf (stderr, "\nEnable Joystick port on ProAudioSpectrum (n/y) ? ");
-      if (think_positively (0))
-	printf ("#define PAS_JOYSTICK_ENABLE\n");
-
-      fprintf (stderr, "PAS16 could be noisy with some mother boards\n"
-	       "There is a command line switch (was it :T?)\n"
-	       "in the DOS driver for PAS16 which solves this.\n"
-	       "Don't enable this feature unless you have problems!\n"
-	       "Do you have to use this switch with DOS (y/n) ?");
-      if (think_positively (0))
-	printf ("#define BROKEN_BUS_CLOCK\n");
-    }
-
-  if (selected_options & B (OPT_GUS))
-    {
-      fprintf (stderr, "\nI/O base for Gravis Ultrasound?\n"
-	       "Valid choices are 210, 220, 230, 240, 250 or 260\n"
-	       "The factory default is 220\n"
-	       "Enter the GUS I/O base: ");
-
-      num = ask_value ("%x", 0x220);
-      if ((num > 0x260) || ((num & 0xf0f) != 0x200) || ((num & 0x0f0) > 0x060))
-	{
-
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 0x220;
-	}
-
-      if ((selected_options & B (OPT_SB)) && (num == sb_base))
-	{
-	  fprintf (stderr, "FATAL ERROR!!!!!!!!!!!!!!\n"
-		   "\t0x220 cannot be used if SoundBlaster is enabled.\n"
-		   "\tRun the config again.\n");
-	  printf ("#undef CONFIGURE_SOUNDCARD\n");
-	  printf ("#undef KERNEL_SOUNDCARD\n");
-	  exit (-1);
-	}
-      fprintf (stderr, "GUS I/O base set to %03x\n", num);
-      printf ("#define GUS_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for Gravis UltraSound?\n"
-	       "The recommended value is the IRQ used under DOS.\n"
-	       "Please refer to the Gravis Ultrasound User's Guide.\n"
-	       "The default value is 15.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 15);
-      if (num == 6 || num < 3 || num > 15 || num == 2)	/*
-							 * Invalid
-							 */
-	{
-
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 15;
-	}
-      fprintf (stderr, "Gravis UltraSound IRQ set to %d\n", num);
-      printf ("#define GUS_IRQ %d\n", num);
-
-      fprintf (stderr, "\nDMA number for Gravis UltraSound?\n"
-	       "The recommended value is the DMA channel under DOS.\n"
-	       "Please refer to the Gravis Ultrasound User's Guide.\n"
-	       "The default value is 6\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 6);
-      if (num == 4 || num < 0 || num > 7)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 6;
-	}
-      fprintf (stderr, "\nGravis UltraSound DMA set to %d\n", num);
-      printf ("#define GUS_DMA %d\n", num);
-
-      fprintf (stderr, "\nSecond DMA channel for GUS (optional)?\n"
-	       "The default value is 7 (-1 disables)\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 7);
-      if (num > 7)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 7;
-	}
-
-      fprintf (stderr, "\nGUS DMA2 set to %d\n", num);
-      printf ("#define GUS_DMA2 %d\n", num);
-
-      if (selected_options & B (OPT_GUS16))
-	{
-	  fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n"
-		   "The factory default is 530\n"
-		   "Other possible values are  604, E80 or F40\n"
-		   "Enter the GUS16 I/O base: ");
-
-	  num = ask_value ("%x", 0x530);
-	  fprintf (stderr, "GUS16 I/O base set to %03x\n", num);
-	  printf ("#define GUS16_BASE 0x%03x\n", num);
-
-	  fprintf (stderr, "\nIRQ number for GUS16?\n"
-		   "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n"
-		   "The default value is 7.\n"
-		   "Enter the value: ");
-
-	  num = ask_value ("%d", 7);
-	  if (num == 6 || num < 3 || num > 15)
-	    {
-	      fprintf (stderr, "*** Illegal input! ***\n");
-	      num = 7;
-	    }
-	  fprintf (stderr, "GUS16 IRQ set to %d\n", num);
-	  printf ("#define GUS16_IRQ %d\n", num);
-
-	  fprintf (stderr, "\nDMA number for GUS16?\n"
-		   "The default value is 3\n"
-		   "Enter the value: ");
-
-	  num = ask_value ("%d", 3);
-	  if (num < 0 || num > 3)
-	    {
-	      fprintf (stderr, "*** Illegal input! ***\n");
-	      num = 3;
-	    }
-	  fprintf (stderr, "\nGUS16 DMA set to %d\n", num);
-	  printf ("#define GUS16_DMA %d\n", num);
-	}
-    }
-
-  if (selected_options & B (OPT_MPU401))
-    {
-      fprintf (stderr, "\nI/O base for MPU-401?\n"
-	       "The factory default is 330\n"
-	       "Enter the MPU-401 I/O base: ");
-
-      num = ask_value ("%x", 0x330);
-      fprintf (stderr, "MPU-401 I/O base set to %03x\n", num);
-      printf ("#define MPU_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for MPU-401?\n"
-	       "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
-	       "The default value is 9.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 9);
-      if (num == 6 || num < 3 || num > 15)
-	{
-
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 5;
-	}
-      fprintf (stderr, "MPU-401 IRQ set to %d\n", num);
-      printf ("#define MPU_IRQ %d\n", num);
-    }
-
-  if (selected_options & B (OPT_MAUI))
-    {
-      fprintf (stderr, "\nI/O base for TB Maui (MIDI I/O of TB Tropez)?\n"
-	       "The factory default is 330\n"
-	"Valid alternatives are 210, 230, 260, 290, 300, 320, 338 and 330\n"
-	       "Enter the Maui/Tropez MIDI I/O base: ");
-
-      num = ask_value ("%x", 0x330);
-      fprintf (stderr, "Maui I/O base set to %03x\n", num);
-      printf ("#define MAUI_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for TB Maui (TB Tropez MIDI)?\n"
-	       "Valid numbers are: 5, 9, 12 and 15.\n"
-	       "The default value is 9.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 9);
-      if (num == 6 || num < 3 || num > 15)
-	{
-
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 5;
-	}
-      fprintf (stderr, "Maui/Tropez MIDI IRQ set to %d\n", num);
-      printf ("#define MAUI_IRQ %d\n", num);
-    }
-
-  if (selected_options & B (OPT_UART6850))
-    {
-      fprintf (stderr, "\nI/O base for 6850 UART Midi?\n"
-	       "Be carefull. No defaults.\n"
-	       "Enter the 6850 UART I/O base: ");
-
-      num = ask_value ("%x", 0);
-      if (num == 0)
-	{
-	  /*
-	     * Invalid value entered
-	   */
-	  printf ("#define EXCLUDE_UART6850\n");
-	}
-      else
-	{
-	  fprintf (stderr, "6850 UART I/O base set to %03x\n", num);
-	  printf ("#define U6850_BASE 0x%03x\n", num);
-
-	  fprintf (stderr, "\nIRQ number for 6850 UART?\n"
-		   "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
-		   "The default value is 5.\n"
-		   "Enter the value: ");
-
-	  num = ask_value ("%d", 5);
-	  if (num == 6 || num < 3 || num > 15)
-	    {
-
-	      fprintf (stderr, "*** Illegal input! ***\n");
-	      num = 5;
-	    }
-	  fprintf (stderr, "6850 UART IRQ set to %d\n", num);
-	  printf ("#define U6850_IRQ %d\n", num);
-	}
-    }
-
-  if (selected_options & B (OPT_PSS))
-    {
-      fprintf (stderr, "\nI/O base for PSS?\n"
-	       "The factory default is 220 (240 also possible)\n"
-	       "Enter the PSS I/O base: ");
-
-      num = ask_value ("%x", 0x220);
-      fprintf (stderr, "PSS I/O base set to %03x\n", num);
-      printf ("#define PSS_BASE 0x%03x\n", num);
-
-#if YOU_WANT_TO_WASTE_RESOURCES
-      fprintf (stderr, "\nIRQ number for PSS?\n"
-	       "Valid numbers are: 3, 4, 5, 7, 9(=2) or 10.\n"
-	       "The default value is 10.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 10);
-      if (num == 6 || num < 3 || num > 15)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 7;
-	}
-      fprintf (stderr, "PSS IRQ set to %d\n", num);
-      printf ("#define PSS_IRQ %d\n", num);
-
-      fprintf (stderr, "\nDMA number for ECHO-PSS?\n"
-	       "The default value is 5\n"
-	       "Valid values are 5, 6 and 7\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 5);
-      if (num < 5 || num > 7)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 5;
-	}
-      fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num);
-      printf ("#define PSS_DMA %d\n", num);
-#endif
-
-      fprintf (stderr, "\nMSS (MS Sound System) I/O base for the PSS card?\n"
-	       "The factory default is 530\n"
-	       "Other possible values are  604, E80 or F40\n"
-	       "Enter the MSS I/O base: ");
-
-      num = ask_value ("%x", 0x530);
-      fprintf (stderr, "PSS/MSS I/O base set to %03x\n", num);
-      printf ("#define PSS_MSS_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for the MSS mode of PSS ?\n"
-	       "Valid numbers are: 7, 9(=2), 10 and 11.\n"
-	       "The default value is 11.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 11);
-      if (num == 6 || num < 3 || num > 15)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 11;
-	}
-      fprintf (stderr, "PSS/MSS IRQ set to %d\n", num);
-      printf ("#define PSS_MSS_IRQ %d\n", num);
-
-      fprintf (stderr, "\nMSS DMA number for PSS?\n"
-	       "Valid values are 0, 1 and 3.\n"
-	       "The default value is 3\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 3);
-      if (num == 4 || num < 0 || num > 7)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 3;
-	}
-      fprintf (stderr, "\nPSS/MSS DMA set to %d\n", num);
-      printf ("#define PSS_MSS_DMA %d\n", num);
-
-      fprintf (stderr, "\nMIDI I/O base for PSS?\n"
-	       "The factory default is 330\n"
-	       "Enter the PSS MIDI I/O base: ");
-
-      num = ask_value ("%x", 0x330);
-      fprintf (stderr, "PSS/MIDI I/O base set to %03x\n", num);
-      printf ("#define PSS_MPU_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for PSS MIDI?\n"
-	       "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
-	       "The default value is 9.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 9);
-      if (num == 6 || num < 3 || num > 15)
-	{
-
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 5;
-	}
-      fprintf (stderr, "PSS MIDI IRQ set to %d\n", num);
-      printf ("#define PSS_MPU_IRQ %d\n", num);
-    }
-
-  if (selected_options & B (OPT_MSS))
-    {
-      fprintf (stderr, "\nI/O base for MSS (MS Sound System)?\n"
-	       "The factory default is 530\n"
-	       "Other possible values are  604, E80 or F40\n"
-	       "Enter the MSS I/O base: ");
-
-      num = ask_value ("%x", 0x530);
-      fprintf (stderr, "MSS I/O base set to %03x\n", num);
-      printf ("#define MSS_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for MSS?\n"
-	       "Valid numbers are: 7, 9(=2), 10 and 11.\n"
-	       "The default value is 10.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 10);
-      if (num == 6 || num < 3 || num > 15)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 7;
-	}
-      fprintf (stderr, "MSS IRQ set to %d\n", num);
-      printf ("#define MSS_IRQ %d\n", num);
-
-      fprintf (stderr, "\nDMA number for MSS?\n"
-	       "Valid values are 0, 1 and 3.\n"
-	       "The default value is 3\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 3);
-      if (num == 4 || num < 0 || num > 7)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 3;
-	}
-      fprintf (stderr, "\nMSS DMA set to %d\n", num);
-      printf ("#define MSS_DMA %d\n", num);
-    }
-
-  if (selected_options & B (OPT_SSCAPE))
-    {
-      int             reveal_spea;
-
-      fprintf (stderr, "\n(MIDI) I/O base for Ensoniq Soundscape?\n"
-	       "The factory default is 330\n"
-	       "Other possible values are 320, 340 or 350\n"
-	       "Enter the Soundscape I/O base: ");
-
-      num = ask_value ("%x", 0x330);
-      fprintf (stderr, "Soundscape I/O base set to %03x\n", num);
-      printf ("#define SSCAPE_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "Is your SoundScape card made/marketed by Reveal or Spea? ");
-      reveal_spea = think_positively (0);
-      if (reveal_spea)
-	printf ("#define REVEAL_SPEA\n");
-
-      fprintf (stderr, "\nIRQ number for Soundscape?\n");
-
-      if (reveal_spea)
-	fprintf (stderr, "Check valid interrupts from the manual of your card.\n");
-      else
-	fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 10.\n");
-
-      fprintf (stderr, "The default value is 9.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 9);
-      if (num == 6 || num < 3 || num > 15)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 9;
-	}
-      fprintf (stderr, "Soundscape IRQ set to %d\n", num);
-      printf ("#define SSCAPE_IRQ %d\n", num);
-
-      fprintf (stderr, "\nDMA number for Soundscape?\n"
-	       "Valid values are 1 and 3 (sometimes 0)"
-	       "The default value is 3\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 3);
-      if (num == 4 || num < 0 || num > 7)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 3;
-	}
-      fprintf (stderr, "\nSoundscape DMA set to %d\n", num);
-      printf ("#define SSCAPE_DMA %d\n", num);
-
-      fprintf (stderr, "\nMSS (MS Sound System) I/O base for the SSCAPE card?\n"
-	       "The factory default is 534\n"
-	       "Other possible values are  608, E84 or F44\n"
-	       "Enter the MSS I/O base: ");
-
-      num = ask_value ("%x", 0x534);
-      fprintf (stderr, "SSCAPE/MSS I/O base set to %03x\n", num);
-      printf ("#define SSCAPE_MSS_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for the MSS mode of SSCAPE ?\n");
-      if (reveal_spea)
-	fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 15.\n");
-      else
-	fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 10.\n");
-      fprintf (stderr, "The default value is 5.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 5);
-      if (num == 6 || num < 3 || num > 15)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 10;
-	}
-      fprintf (stderr, "SSCAPE/MSS IRQ set to %d\n", num);
-      printf ("#define SSCAPE_MSS_IRQ %d\n", num);
-
-      fprintf (stderr, "\nMSS DMA number for SSCAPE?\n"
-	       "Valid values are 0, 1 and 3.\n"
-	       "The default value is 3\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 3);
-      if (num == 4 || num < 0 || num > 7)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 3;
-	}
-      fprintf (stderr, "\nSSCAPE/MSS DMA set to %d\n", num);
-      printf ("#define SSCAPE_MSS_DMA %d\n", num);
-    }
-  if (selected_options & B (OPT_TRIX))
-    {
-
-      fprintf (stderr, "\nWindows Sound System I/O base for the AudioTriX card?\n"
-	       "The factory default is 530\n"
-	       "Other possible values are  604, E80 or F40\n"
-	       "Enter the MSS I/O base: ");
-
-      num = ask_value ("%x", 0x530);
-      fprintf (stderr, "AudioTriX MSS I/O base set to %03x\n", num);
-      printf ("#define TRIX_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for the WSS mode of AudioTriX ?\n"
-	       "Valid numbers are: 5, 7, 9(=2), 10 and 11.\n"
-	       "The default value is 11.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 11);
-      if (num != 5 && num != 7 && num != 9 && num != 10 && num != 11)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 11;
-	}
-      fprintf (stderr, " AudioTriX WSS IRQ set to %d\n", num);
-      printf ("#define TRIX_IRQ %d\n", num);
-
-      fprintf (stderr, "\nWSS DMA number for AudioTriX?\n"
-	       "Valid values are 0, 1 and 3.\n"
-	       "The default value is 3\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 3);
-      if (num != 0 && num != 1 && num != 3)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 3;
-	}
-      fprintf (stderr, "\nAudioTriX/WSS DMA set to %d\n", num);
-      printf ("#define TRIX_DMA %d\n", num);
-
-      fprintf (stderr, "\nSecond (capture) DMA number for AudioTriX?\n"
-	       "Valid values are 0, 1 and 3.\n"
-	       "The default value is 0\n"
-	       "(-1 disables the second DMA)\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 0);
-      if (num != 0 && num != 1 && num != 3 || num != -1)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 0;
-	}
-      fprintf (stderr, "\nAudioTriX/WSS DMA2 set to %d\n", num);
-      printf ("#define TRIX_DMA2 %d\n", num);
-
-      fprintf (stderr, "\nSoundBlaster I/O address for the AudioTriX card?\n"
-	       "The factory default is 220\n"
-	  "Other possible values are 200, 210, 230, 240, 250, 260 and 270\n"
-	       "Enter the MSS I/O base: ");
-
-      num = ask_value ("%x", 0x220);
-      fprintf (stderr, "AudioTriX SB I/O base set to %03x\n", num);
-      printf ("#define TRIX_SB_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for the SB mode of AudioTriX ?\n"
-	       "Valid numbers are: 3, 4, 5 and 7.\n"
-	       "The default value is 7.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 7);
-      if (num != 3 && num != 4 && num != 5 && num != 7)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 7;
-	}
-      fprintf (stderr, " AudioTriX SB IRQ set to %d\n", num);
-      printf ("#define TRIX_SB_IRQ %d\n", num);
-
-      fprintf (stderr, "\nSB DMA number for AudioTriX?\n"
-	       "Valid values are 1 and 3.\n"
-	       "The default value is 1\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 1);
-      if (num != 1 && num != 3)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 1;
-	}
-      fprintf (stderr, "\nAudioTriX/SB DMA set to %d\n", num);
-      printf ("#define TRIX_SB_DMA %d\n", num);
-
-      fprintf (stderr, "\nMIDI (MPU-401) I/O address for the AudioTriX card?\n"
-	       "The factory default is 330\n"
-	       "Other possible values are 330, 370, 3B0 and 3F0\n"
-	       "Enter the MPU I/O base: ");
-
-      num = ask_value ("%x", 0x330);
-      fprintf (stderr, "AudioTriX MIDI I/O base set to %03x\n", num);
-      printf ("#define TRIX_MPU_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nMIDI IRQ number for the AudioTriX ?\n"
-	       "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
-	       "The default value is 5.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 5);
-      if (num != 3 && num != 4 && num != 5 && num != 7 && num != 9)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 5;
-	}
-      fprintf (stderr, " AudioTriX MIDI IRQ set to %d\n", num);
-      printf ("#define TRIX_MPU_IRQ %d\n", num);
-    }
-
-  if (selected_options & B (OPT_CS4232))
-    {
-      int             dma1;
-
-      fprintf (stderr, "\nWindows Sound System I/O base for CS4232?\n"
-	       "The factory default is 534\n"
-	       "Other possible values are  608, E84 or F44\n"
-	       "Enter the MSS I/O base: ");
-
-      num = ask_value ("%x", 0x534);
-      fprintf (stderr, "CS4232 MSS I/O base set to %03x\n", num);
-      printf ("#define CS4232_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nIRQ number for the WSS mode of CS4232 ?\n"
-	       "Valid numbers are: 5, 7, 9(=2), 11, 12 or 15.\n"
-	       "The default value is 11.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 11);
-      if (num != 5 && num != 7 && num != 9 && num != 11 && num != 12 || num != 15)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 11;
-	}
-      fprintf (stderr, " CS4232 WSS IRQ set to %d\n", num);
-      printf ("#define CS4232_IRQ %d\n", num);
-
-      fprintf (stderr, "\nWSS DMA number for CS4232?\n"
-	       "Valid values are 0, 1 and 3.\n"
-	       "The default value is 0\n"
-	       "(select the lowes possible one if you want to\n"
-	       "use full duplex mode)\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 0);
-      if (num != 0 && num != 1 && num != 3)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 0;
-	}
-      fprintf (stderr, "\nCS4232/WSS DMA set to %d\n", num);
-      printf ("#define CS4232_DMA %d\n", num);
-      dma1 = num;
-
-      fprintf (stderr, "\n Second WSS DMA number for CS4232?\n"
-	       "Valid values are 0, 1 and 3.\n"
-	       "The default value is 3\n"
-	       "Enter the value (-1 disables duplex mode): ");
-
-      num = ask_value ("%d", 3);
-      if (num == dma1 || (num != -1 && num != 0 && num != 1 && num != 3))
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 3;
-	}
-      fprintf (stderr, "\nCS4232/WSS DMA2 set to %d\n", num);
-      printf ("#define CS4232_DMA2 %d\n", num);
-
-      fprintf (stderr, "\nMIDI (MPU-401) I/O address for the CS4232 card?\n"
-	       "The factory default is 330\n"
-	       "Other possible values are 330, 370, 3B0 and 3F0\n"
-	       "Enter the MPU I/O base: ");
-
-      num = ask_value ("%x", 0x330);
-      fprintf (stderr, "CS4232 MIDI I/O base set to %03x\n", num);
-      printf ("#define CS4232_MPU_BASE 0x%03x\n", num);
-
-      fprintf (stderr, "\nMIDI IRQ number for CS4232?\n"
-	       "Valid numbers are: 5, 7, 9(=2), 11, 12 or 15.\n"
-	       "The default value is 5.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 5);
-      if (num != 5 && num != 7 && num != 9 && num != 11 && num != 12 || num != 15)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 5;
-	}
-      fprintf (stderr, " CS4232 MIDI IRQ set to %d\n", num);
-      printf ("#define CS4232_MPU_IRQ %d\n", num);
-    }
-
-  if (selected_options & B (OPT_MAD16))
-    {
-      fprintf (stderr, "\n*** Options for the MAD16 and Mozart based cards ***\n\n");
-
-      fprintf (stderr, "\nWindows Sound System I/O base for the MAD16/Mozart card?\n"
-	       "The factory default is 530\n"
-	       "Other possible values are  604, E80 or F40\n"
-	       "(Check which ones are supported by your card!!!!!!)\n"
-	       "Enter the MSS I/O base: ");
-
-      num = ask_value ("%x", 0x530);
-      fprintf (stderr, "MAD16 MSS I/O base set to %03x\n", num);
-      printf ("#define MAD16_BASE 0x%03x\n", num);
-
-      if ((sb_base == 0x220 && (num == 0x530 || num == 0x480)) ||
-	  (sb_base == 0x240 && (num == 0xf40 || num == 0x604)))
-	{
-	  fprintf (stderr, "FATAL ERROR!!!!!!!!!!!!!!\n"
-		   "\tThis I/O port selection makes MAD16/Mozart\n"
-		   "\tto use 0x%03x as the SB port.\n"
-		   "\tThis conflicts with the true SB card.\n"
-		   "\tRun the config again and select another I/O base.\n",
-		   sb_base);
-	  printf ("#undef CONFIGURE_SOUNDCARD\n");
-	  printf ("#undef KERNEL_SOUNDCARD\n");
-	  exit (-1);
-	}
-
-      fprintf (stderr, "\nIRQ number for the WSS mode of MAD16/Mozart ?\n"
-	       "Valid numbers are: 7, 9(=2), 10 and 11.\n"
-	       "The default value is 11.\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 11);
-      if (num != 7 && num != 9 && num != 10 && num != 11)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 11;
-	}
-      fprintf (stderr, " MAD16 WSS IRQ set to %d\n", num);
-      printf ("#define MAD16_IRQ %d\n", num);
-
-      fprintf (stderr, "\nWSS DMA (playback) number for MAD16/Mozart?\n"
-	       "Valid values are 0, 1 and 3.\n"
-	       "The default value is 3\n"
-	       "Enter the value: ");
-
-      num = ask_value ("%d", 3);
-      if (num != 0 && num != 1 && num != 3)
-	{
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = 3;
-	}
-      fprintf (stderr, "\nMAD16/WSS DMA set to %d\n", num);
-      printf ("#define MAD16_DMA %d\n", num);
-
-      num = (num == 0) ? 1 : 0;
-
-      fprintf (stderr, "\nMAD16/Mozart supports full duplex mode if the\n"
-	       "card has a suitable codec chip (CS423x or AD1845).\n"
-	       "This mode requires another DMA channel (DMA%d)\n"
-	       "Do you want to enable this mode? (n/y)", num);
-
-      if (think_positively (0))
-	{
-	  fprintf (stderr, "\nMAD16/WSS capture DMA set to %d\n", num);
-	  printf ("#define MAD16_DMA2 %d\n", num);
-	}
-      else
-	printf ("#define MAD16_DMA2 -1\n");
-
-
-      fprintf (stderr, "\nMIDI (MPU-401/SB) I/O address for the MAD16 card?\n"
-	       "(This is the second MIDI port in TB Tropez)\n"
-	       "Other possible values are 330, 320, 310 and 300\n"
-	       "For 82C928 and Mozart you may use any nonzero value\n"
-	       "since the driver ignores this setting.\n"
-	       "The factory default is 330 (use 0 to disable)\n"
-	       "Enter the MIDI I/O base: ");
-
-      num = ask_value ("%x", 0x330);
-      if (num == 0)
-	fprintf (stderr, "MAD16/Mozart MIDI port disabled\n");
-      else
-	{
-	  fprintf (stderr, "MAD16 MIDI I/O base set to %03x\n", num);
-	  printf ("#define MAD16_MPU_BASE 0x%03x\n", num);
-
-	  fprintf (stderr, "\nMIDI IRQ number for the MAD16 ?\n"
-		   "Valid numbers are: 5, 7, 9(=2) and 10.\n"
-		   "The default value is 5.\n"
-		   "Enter the value: ");
-
-	  num = ask_value ("%d", 5);
-	  if (num != 3 && num != 4 && num != 5 && num != 7 && num != 9)
-	    {
-	      fprintf (stderr, "*** Illegal input! ***\n");
-	      num = 5;
-	    }
-	  fprintf (stderr, " MAD16 MIDI IRQ set to %d\n", num);
-	  printf ("#define MAD16_MPU_IRQ %d\n", num);
-	}
-    }
-
-  if (selected_options & B (OPT_AUDIO))
-    {
-      def_size = 65536;
-
-      fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n"
-	       "%d is recommended value for this configuration.\n"
-	       "Enter the value: ", def_size);
-
-      num = ask_value ("%d", def_size);
-      if (num != 4096 && num != 16384 && num != 32768 && num != 65536)
-	{
-
-	  fprintf (stderr, "*** Illegal input! ***\n");
-	  num = def_size;
-	}
-      fprintf (stderr, "The DMA buffer size set to %d\n", num);
-      printf ("#define DSP_BUFFSIZE %d\n", num);
-    }
+  ask_parameters ();
 
   printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
   fprintf (stderr, "The sound driver is now configured.\n");
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c
--- v1.3.57/linux/drivers/sound/cs4232.c	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/cs4232.c	Tue Jan  9 00:37:10 1996
@@ -34,7 +34,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_CS4232)
+#if defined(CONFIG_CS4232)
 
 #define KEY_PORT	0x279	/* Same as LPT1 status port */
 #define CSN_NUM		0x99	/* Just a random number */
@@ -44,6 +44,7 @@
 #define CS_OUT3(a, b, c)	{CS_OUT(a);CS_OUT(b);CS_OUT(c);}
 
 static int      mpu_base = 0, mpu_irq = 0;
+static int      mpu_detected = 0;
 
 int
 probe_cs4232_mpu (struct address_info *hw_config)
@@ -88,6 +89,9 @@
       return 0;
     }
 
+  if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp))
+    return 1;			/* The card is already active */
+
 /*
  * This version of the driver doesn't use the PnP method when configuring
  * the card but a simplified method defined by Crystal. This means that
@@ -108,14 +112,6 @@
 
   CS_OUT2 (0x06, CSN_NUM);
 
-/*
- * Ensure that there is no other codec using the same address.
- */
-
-  CS_OUT2 (0x15, 0x00);		/* Select logical device 0 (WSS/SB/FM) */
-  CS_OUT2 (0x33, 0x00);		/* Inactivate logical dev 0 */
-  if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp))
-    return 0;
 
 /*
  * Then set some config bytes. First logical device 0 
@@ -144,7 +140,7 @@
  * Initialize logical device 3 (MPU)
  */
 
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   if (mpu_base != 0 && mpu_irq != 0)
     {
       CS_OUT2 (0x15, 0x03);	/* Select logical device 3 (MPU) */
@@ -182,7 +178,7 @@
 	       0,
 	       hw_config->osp);
 
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   if (mpu_base != 0 && mpu_irq != 0)
     {
       static struct address_info hw_config2 =
@@ -201,6 +197,7 @@
 
       if (probe_mpu401 (&hw_config2))
 	{
+	  mpu_detected = 1;
 	  mem_start = attach_mpu401 (mem_start, &hw_config2);
 	}
       else
@@ -227,8 +224,8 @@
 		 dma2,		/* Capture DMA */
 		 0);
 
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
-  if (mpu_base != 0 && mpu_irq != 0)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+  if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
     {
       static struct address_info hw_config2 =
       {0};			/* Ensure it's initialized */
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- v1.3.57/linux/drivers/sound/dev_table.c	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/dev_table.c	Tue Jan  9 00:37:11 1996
@@ -30,8 +30,6 @@
 #define _DEV_TABLE_C_
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
 int             sound_started = 0;
 
 int             sndtable_get_cardcount (void);
@@ -48,6 +46,33 @@
   return -1;
 }
 
+static long
+start_services (long mem_start)
+{
+  int             soundcards_installed;
+
+  if (!(soundcards_installed = sndtable_get_cardcount ()))
+    return mem_start;		/* No cards detected */
+
+#ifdef CONFIG_AUDIO
+  if (num_audiodevs)		/* Audio devices present */
+    {
+      DMAbuf_init (0);
+      audio_init (0);
+    }
+#endif
+
+#ifdef CONFIG_MIDI
+  if (num_midis)
+    MIDIbuf_init (0);
+#endif
+
+#ifdef CONFIG_SEQUENCER
+  if (num_midis + num_synths)
+    sequencer_init (0);
+#endif
+  return mem_start;
+}
 
 static long
 start_cards (long mem_start)
@@ -56,7 +81,8 @@
   int             drv;
 
   sound_started = 1;
-  printk ("Sound initialization started\n");
+  if (trace_init)
+    printk ("Sound initialization started\n");
 
 /*
  * Check the number of cards actually defined in the table
@@ -83,27 +109,9 @@
 
 	if (sound_drivers[drv].probe (&snd_installed_cards[i].config))
 	  {
-	    int             tmp;
-
-	    printk ("snd%d",
-		    snd_installed_cards[i].card_type);
 
 	    mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config);
-	    printk (" at 0x%x",
-		    snd_installed_cards[i].config.io_base);
 
-	    if ((tmp = snd_installed_cards[i].config.irq) != 0)
-	      printk (" irq %d",
-		      (tmp > 0) ? tmp : -tmp);
-
-	    if (snd_installed_cards[i].config.dma >= 0)
-	      printk (" drq %d",
-		      snd_installed_cards[i].config.dma);
-	    if (snd_installed_cards[i].config.dma2 != -1)
-	      printk (",%d\n",
-		      snd_installed_cards[i].config.dma2);
-	    else
-	      printk ("\n");
 	  }
 	else
 	  snd_installed_cards[i].enabled = 0;	/*
@@ -111,7 +119,8 @@
 						 */
       }
 
-  printk ("Sound initialization complete\n");
+  if (trace_init)
+    printk ("Sound initialization complete\n");
   return mem_start;
 }
 
@@ -130,7 +139,8 @@
   if (!sound_started)
     return;
 
-  printk ("Sound unload started\n");
+  if (trace_init)
+    printk ("Sound unload started\n");
 
   for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
     if (snd_installed_cards[i].enabled)
@@ -141,7 +151,8 @@
 	    snd_installed_cards[i].enabled = 0;
 	  }
 
-  printk ("Sound unload complete\n");
+  if (trace_init)
+    printk ("Sound unload complete\n");
 }
 
 void
@@ -182,6 +193,8 @@
 {
   int             i, sel = -1, n = num_sound_cards;
 
+  DDB (printk ("sndtable_probe(%d)\n", unit));
+
   if (!unit)
     return TRUE;
 
@@ -221,16 +234,22 @@
       if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1)
 	{
 	  snd_installed_cards[sel].enabled = 0;
+	  DDB (printk ("Failed to find driver\n"));
 	  return FALSE;
 	}
+      DDB (printk ("Driver name '%s'\n", sound_drivers[drv].name));
 
-
-      snd_installed_cards[sel].config.card_subtype =
+      hw_config->card_subtype =
+	snd_installed_cards[sel].config.card_subtype =
 	sound_drivers[drv].card_subtype;
 
       if (sound_drivers[drv].probe (hw_config))
-	return TRUE;
+	{
+	  return TRUE;
+	  DDB (printk ("Hardware probed OK\n"));
+	}
 
+      DDB (printk ("Failed to find hardware\n"));
       snd_installed_cards[sel].enabled = 0;	/*
 						 * Mark as not detected
 						 */
@@ -278,26 +297,17 @@
 	  {
 
 	    DDB (printk ("Located card - calling attach routine\n"));
-	    printk ("snd%d", unit);
 	    if (sound_drivers[drv].attach (0, hw_config) != 0)
 	      panic ("sound: Invalid memory allocation\n");
 
 	    DDB (printk ("attach routine finished\n"));
-	    printk (" at 0x%x irq %d drq %d",
-		    snd_installed_cards[i].config.io_base,
-		    snd_installed_cards[i].config.irq,
-		    snd_installed_cards[i].config.dma);
-	    if (snd_installed_cards[i].config.dma2 != -1)
-	      printk (",%d\n",
-		      snd_installed_cards[i].config.dma2);
-	    else
-	      printk ("\n");
 	  }
+	start_services (0);
 	return TRUE;
       }
 
-  printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n",
-	  unit, num_sound_cards);
+  DDB (printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n",
+	       unit, num_sound_cards));
   return FALSE;
 }
 
@@ -413,7 +423,3 @@
 
   return &snd_installed_cards[ptr].config;
 }
-
-
-
-#endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v1.3.57/linux/drivers/sound/dev_table.h	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/dev_table.h	Tue Jan  9 00:36:54 1996
@@ -26,7 +26,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
-
 */
 
 #ifndef _DEV_TABLE_H_
@@ -77,6 +76,7 @@
 
 struct dma_buffparms {
 	int      dma_mode;	/* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
+	int	 closing;
 
 	/*
  	 * Pointers to raw buffers
@@ -104,6 +104,7 @@
        	int      qlen;
        	int      qhead;
        	int      qtail;
+	int	 cfrag;	/* Current incomplete fragment (write) */
 
 	int      nbufs;
 	int      counts[MAX_SUB_BUFFERS];
@@ -120,6 +121,9 @@
 	int	 mapping_flags;
 #define			DMA_MAP_MAPPED		0x00000001
 	char	neutral_byte;
+#ifdef OS_DMA_PARMS
+	OS_DMA_PARMS
+#endif
 };
 
 /*
@@ -265,7 +269,7 @@
 	struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0;
 	struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
 	extern struct sound_timer_operations default_sound_timer;
 	struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = 
 		{&default_sound_timer, NULL}; 
@@ -281,66 +285,64 @@
  */
 
 	struct driver_info sound_drivers[] = {
-#ifndef EXCLUDE_PSS
+#ifdef CONFIG_PSS
 	  {"PSSECHO", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss},
 	  {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu},
 	  {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss},
 #endif
-#ifndef EXCLUDE_MSS
+#ifdef CONFIG_MSS
 		{"MSS", 0, SNDCARD_MSS,	"MS Sound System",	attach_ms_sound, probe_ms_sound, unload_ms_sound},
 	/* MSS without IRQ/DMA config registers (for DEC Alphas) */
-		{"PCXBJ", 1, SNDCARD_PSEUDO_MSS,	"MS Sound System",	attach_ms_sound, probe_ms_sound, unload_ms_sound},
+		{"PCXBJ", 1, SNDCARD_PSEUDO_MSS,	"MS Sound System (AXP)",	attach_ms_sound, probe_ms_sound, unload_ms_sound},
 #endif
-#ifndef EXCLUDE_MAD16
+#ifdef CONFIG_MAD16
 		{"MAD16", 0, SNDCARD_MAD16,	"MAD16/Mozart (MSS)",		attach_mad16, probe_mad16, unload_mad16},
 		{"MAD16MPU", 0, SNDCARD_MAD16_MPU,	"MAD16/Mozart (MPU)",		attach_mad16_mpu, probe_mad16_mpu, unload_mad16_mpu},
 #endif
-#ifndef EXCLUDE_CS4232
+#ifdef CONFIG_CS4232
 		{"CS4232", 0, SNDCARD_CS4232,	"CS4232",		attach_cs4232, probe_cs4232, unload_cs4232},
 		{"CS4232MPU", 0, SNDCARD_CS4232_MPU,	"CS4232 MIDI",		attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu},
 #endif
-#ifndef EXCLUDE_YM3812
+#ifdef CONFIG_YM3812
 		{"OPL3", 0, SNDCARD_ADLIB,	"OPL-2/OPL-3 FM",		attach_adlib_card, probe_adlib, unload_adlib},
 #endif
-#ifndef EXCLUDE_PAS
+#ifdef CONFIG_PAS
 		{"PAS16", 0, SNDCARD_PAS,	"ProAudioSpectrum",	attach_pas_card, probe_pas, unload_pas},
 #endif
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
 		{"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401",	attach_mpu401, probe_mpu401, unload_mpu401},
 #endif
-#if !defined(EXCLUDE_MAUI)
+#if defined(CONFIG_MAUI)
 		{"MAUI", 0, SNDCARD_MAUI,"TB Maui",	attach_maui, probe_maui, unload_maui},
 #endif
-#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
 		{"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi",	attach_uart6850, probe_uart6850, unload_uart6850},
 #endif
-#ifndef EXCLUDE_SB
+#ifdef CONFIG_SB
 		{"SBLAST", 0, SNDCARD_SB,	"SoundBlaster",		attach_sb_card, probe_sb, unload_sb},
+#ifdef CONFIG_AUDIO
+		{"SBX", 0, SNDCARD_SB16,	"SoundBlaster 16bit",	sb16_dsp_init, sb16_dsp_detect, unload_sb16},
 #endif
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
-#ifndef EXCLUDE_AUDIO
-		{"SB16", 0, SNDCARD_SB16,	"SoundBlaster16",	sb16_dsp_init, sb16_dsp_detect, unload_sb16},
+#ifdef CONFIG_MIDI
+		{"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU",	attach_sb16midi, probe_sb16midi, unload_sb16midi},
 #endif
-#ifndef EXCLUDE_MIDI
-		{"SB16MIDI", 0, SNDCARD_SB16MIDI,"SB16 MIDI",	attach_sb16midi, probe_sb16midi, unload_sb16midi},
 #endif
-#endif
-#ifndef EXCLUDE_GUS16
+#ifdef CONFIG_GUS16
 		{"GUS16", 0, SNDCARD_GUS16,	"Ultrasound 16-bit opt.",	attach_gus_db16, probe_gus_db16, unload_gus_db16},
 #endif
-#ifndef EXCLUDE_GUS
+#ifdef CONFIG_GUS
 		{"GUS", 0, SNDCARD_GUS,	"Gravis Ultrasound",	attach_gus_card, probe_gus, unload_gus},
 #endif
-#ifndef EXCLUDE_SSCAPE
+#ifdef CONFIG_SSCAPE
 		{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq Soundscape",	attach_sscape, probe_sscape, unload_sscape},
 		{"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS,	"MS Sound System (SoundScape)",	attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound},
 #endif
-#ifndef EXCLUDE_TRIX
+#ifdef CONFIG_TRIX
 		{"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro",	attach_trix_wss, probe_trix_wss, unload_trix_wss},
 		{"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)",	attach_trix_sb, probe_trix_sb, unload_trix_sb},
 		{"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTriX MIDI",	attach_trix_mpu, probe_trix_mpu, unload_trix_mpu},
 #endif
-#ifndef EXCLUDE_PNP
+#ifdef CONFIG_PNP
 		{"AD1848", 0, 500, "PnP MSS",	attach_pnp_ad1848, probe_pnp_ad1848, unload_pnp_ad1848},
 #endif
 		{NULL, 0, 0,		"*?*",			NULL, NULL, NULL}
@@ -360,7 +362,7 @@
  */
 
 	struct card_info snd_installed_cards[] = {
-#ifndef EXCLUDE_PSS
+#ifdef CONFIG_PSS
 	     {SNDCARD_PSS, {PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE},
 #	ifdef PSS_MPU_BASE
 	     {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
@@ -369,7 +371,10 @@
 	     {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
 #	endif
 #endif
-#ifndef EXCLUDE_TRIX
+#ifdef CONFIG_TRIX
+#ifndef TRIX_DMA2
+#define TRIX_DMA2 TRIX_DMA
+#endif
 	     {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA, TRIX_DMA2}, SND_DEFAULT_ENABLE},
 #	ifdef TRIX_SB_BASE
 	     {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE},
@@ -378,26 +383,32 @@
 	     {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #	endif
 #endif
-#ifndef EXCLUDE_SSCAPE
+#ifdef CONFIG_SSCAPE
 	     {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
 	     {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
-#ifndef EXCLUDE_MAD16
+#ifdef CONFIG_MAD16
+#ifndef MAD16_DMA2
+#define MAD16_DMA2 MAD16_DMA
+#endif
 	     {SNDCARD_MAD16, {MAD16_BASE, MAD16_IRQ, MAD16_DMA, MAD16_DMA2}, SND_DEFAULT_ENABLE},
 #	ifdef MAD16_MPU_BASE
 	     {SNDCARD_MAD16_MPU, {MAD16_MPU_BASE, MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #	endif
 #endif
 
-#ifndef EXCLUDE_CS4232
+#ifdef CONFIG_CS4232
+#ifndef CS4232_DMA2
+#define CS4232_DMA2 CS4232_DMA
+#endif
 #	ifdef CS4232_MPU_BASE
 	     {SNDCARD_CS4232_MPU, {CS4232_MPU_BASE, CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #	endif
 	     {SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 
-#ifndef EXCLUDE_MSS
-#	ifdef PSEUDO_MSS
+#ifdef CONFIG_MSS
+#	ifndef PSEUDO_MSS
 		{SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
 #	else
 		{SNDCARD_PSEUDO_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
@@ -407,21 +418,21 @@
 #	endif
 #endif
 
-#ifndef EXCLUDE_PAS
+#ifdef CONFIG_PAS
 		{SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
 
-#ifndef EXCLUDE_SB
+#ifdef CONFIG_SB
 #	ifndef SBC_DMA
 #		define SBC_DMA		1
 #	endif
 		{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
-#if !defined(EXCLUDE_MAUI) 
+#if defined(CONFIG_MAUI) 
 		{SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
 		{SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #ifdef MPU2_BASE
 		{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
@@ -431,27 +442,30 @@
 #endif
 #endif
 
-#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
 		{SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
-#ifndef EXCLUDE_AUDIO
-		{SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA, -1}, SND_DEFAULT_ENABLE},
+#if defined(CONFIG_SB) 
+#if defined(CONFIG_AUDIO) && defined(SB_DMA2)
+		{SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB_DMA2, -1}, SND_DEFAULT_ENABLE},
 #endif
-#ifndef EXCLUDE_MIDI
-		{SNDCARD_SB16MIDI,{SB16MIDI_BASE, SBC_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#if defined(CONFIG_MIDI) && defined(SB_MPU_BASE)
+		{SNDCARD_SB16MIDI,{SB_MPU_BASE, SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 
-#ifndef EXCLUDE_GUS
-#ifndef EXCLUDE_GUS16
+#ifdef CONFIG_GUS
+#ifndef GUS_DMA2
+#define GUS_DMA2 GUS_DMA
+#endif
+#ifdef CONFIG_GUS16
 		{SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
 		{SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 
-#ifndef EXCLUDE_YM3812
+#ifdef CONFIG_YM3812
 		{SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE},
 #endif
 /* Define some expansion space */
@@ -473,8 +487,13 @@
 	int max_sound_cards = 20;
 #endif
 
+#   ifdef MODULE
+	int trace_init = 0;
+#   else
+	int trace_init = 1;
+#   endif
 #else
-	extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs;
+	extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs;
 	extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
 	extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths;
 	extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
@@ -486,6 +505,8 @@
 	extern struct card_info snd_installed_cards[];
 	extern int num_sound_cards;
 	extern int max_sound_cards;
+
+	extern int trace_init;
 
 long sndtable_init(long mem_start);
 int sndtable_get_cardcount (void);
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v1.3.57/linux/drivers/sound/dmabuf.c	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/dmabuf.c	Tue Jan  9 00:37:14 1996
@@ -29,16 +29,14 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
+#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
 
-#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
-
-static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] =
+static wait_handle *in_sleeper[MAX_AUDIO_DEV] =
 {NULL};
 static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] =
 {
   {0}};
-static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] =
+static wait_handle *out_sleeper[MAX_AUDIO_DEV] =
 {NULL};
 static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] =
 {
@@ -133,6 +131,9 @@
     }
 
   bsz &= ~0x03;			/* Force size which is multiple of 4 bytes */
+#ifdef OS_DMA_ALIGN_CHECK
+  OS_DMA_ALIGN_CHECK (bsz);
+#endif
 
   n = dsp_dev->buffsize / bsz;
   if (n > MAX_SUB_BUFFERS)
@@ -158,7 +159,9 @@
       out_sleep_flag[dev].mode = WK_NONE;
     }
   else
-    in_sleep_flag[dev].mode = WK_NONE;
+    {
+      in_sleep_flag[dev].mode = WK_NONE;
+    }
 
   dmap->flags = DMA_BUSY;	/* Other flags off */
   dmap->qlen = dmap->qhead = dmap->qtail = 0;
@@ -168,6 +171,8 @@
   dmap->dma_mode = DMODE_NONE;
   dmap->mapping_flags = 0;
   dmap->neutral_byte = 0x00;
+  dmap->cfrag = -1;
+  dmap->closing = 0;
 }
 
 static int
@@ -262,6 +267,8 @@
       }
   audio_devs[dev]->open_mode = mode;
   audio_devs[dev]->go = 1;
+  in_sleep_flag[dev].mode = WK_NONE;
+  out_sleep_flag[dev].mode = WK_NONE;
 
   audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, (ioctl_arg) 8, 1);
   audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, (ioctl_arg) 1, 1);
@@ -335,19 +342,19 @@
       save_flags (flags);
       cli ();
 
-      while (!(current->signal & ~current->blocked)
-	     && audio_devs[dev]->dmap_out->qlen)
+      while (!current_got_fatal_signal ()
+	     && audio_devs[dev]->dmap_out->qlen > 1)
 	{
 
 	  {
 	    unsigned long   tl;
 
-	    if (10 * HZ)
-	      current->timeout = tl = jiffies + (10 * HZ);
+	    if (HZ)
+	      current_set_timeout (tl = jiffies + (HZ));
 	    else
 	      tl = 0xffffffff;
 	    out_sleep_flag[dev].mode = WK_SLEEP;
-	    interruptible_sleep_on (&out_sleeper[dev]);
+	    module_interruptible_sleep_on (&out_sleeper[dev]);
 	    if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
 	      {
 		if (jiffies >= tl)
@@ -372,7 +379,7 @@
       cli ();
       if (audio_devs[dev]->local_qlen)	/* Device has hidden buffers */
 	{
-	  while (!((current->signal & ~current->blocked))
+	  while (!(current_got_fatal_signal ())
 		 && audio_devs[dev]->local_qlen (dev))
 	    {
 
@@ -380,11 +387,11 @@
 		unsigned long   tl;
 
 		if (HZ)
-		  current->timeout = tl = jiffies + (HZ);
+		  current_set_timeout (tl = jiffies + (HZ));
 		else
 		  tl = 0xffffffff;
 		out_sleep_flag[dev].mode = WK_SLEEP;
-		interruptible_sleep_on (&out_sleeper[dev]);
+		module_interruptible_sleep_on (&out_sleeper[dev]);
 		if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
 		  {
 		    if (jiffies >= tl)
@@ -404,7 +411,10 @@
 {
   unsigned long   flags;
 
-  if (!((current->signal & ~current->blocked))
+  audio_devs[dev]->dmap_out->closing = 1;
+  audio_devs[dev]->dmap_in->closing = 1;
+
+  if (!(current_got_fatal_signal ())
       && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
     {
       dma_sync (dev);
@@ -412,7 +422,6 @@
 
   save_flags (flags);
   cli ();
-  audio_devs[dev]->reset (dev);
 
   audio_devs[dev]->close (dev);
 
@@ -485,6 +494,14 @@
 
   save_flags (flags);
   cli ();
+#ifdef ALLOW_BUFFER_MAPPING
+  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
+    {
+      printk ("Sound: Can't read from mmapped device (1)\n");
+      return -EINVAL;
+    }
+  else
+#endif
   if (!dmap->qlen)
     {
       int             timeout;
@@ -520,11 +537,11 @@
 	unsigned long   tl;
 
 	if (timeout)
-	  current->timeout = tl = jiffies + (timeout);
+	  current_set_timeout (tl = jiffies + (timeout));
 	else
 	  tl = 0xffffffff;
 	in_sleep_flag[dev].mode = WK_SLEEP;
-	interruptible_sleep_on (&in_sleeper[dev]);
+	module_interruptible_sleep_on (&in_sleeper[dev]);
 	if (!(in_sleep_flag[dev].mode & WK_WAKEUP))
 	  {
 	    if (jiffies >= tl)
@@ -536,6 +553,7 @@
 	{
 	  printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
 	  err = EIO;
+	  audio_devs[dev]->reset (dev);
 	  ;
 	}
       else
@@ -559,6 +577,14 @@
 
   int             p = dmap->counts[dmap->qhead] + c;
 
+#ifdef ALLOW_BUFFER_MAPPING
+  if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
+    {
+      printk ("Sound: Can't read from mmapped device (2)\n");
+      return -EINVAL;
+    }
+  else
+#endif
   if (p >= dmap->fragment_size)
     {				/* This buffer is completely empty */
       dmap->counts[dmap->qhead] = 0;
@@ -623,6 +649,11 @@
   if (count < 2)
     return -EINVAL;
 
+#ifdef OS_DMA_MINBITS
+  if (bytes < OS_DMA_MINBITS)
+    bytes = OS_DMA_MINBITS;
+#endif
+
   dmap->fragment_size = (1 << bytes);
   dmap->max_fragments = count;
 
@@ -739,6 +770,10 @@
 	  if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
 	    dmap = dmap_in;
 
+#ifdef ALLOW_BUFFER_MAPPING
+	  if (dmap->mapping_flags & DMA_MAP_MAPPED)
+	    return -EINVAL;
+#endif
 
 	  if (!(dmap->flags & DMA_ALLOC_DONE))
 	    reorganize_buffers (dev, dmap);
@@ -758,7 +793,7 @@
 		    {
 		      int             tmp = audio_devs[dev]->local_qlen (dev);
 
-		      if (tmp & info->fragments)
+		      if (tmp && info->fragments)
 			tmp--;	/*
 				   * This buffer has been counted twice
 				 */
@@ -809,6 +844,18 @@
 	    activate_recording (dev, dmap_in);
 	  }
 
+#ifdef ALLOW_BUFFER_MAPPING
+	if ((changed & bits) & PCM_ENABLE_OUTPUT &&
+	    dmap_out->mapping_flags & DMA_MAP_MAPPED &&
+	    audio_devs[dev]->go)
+	  {
+	    if (!(dmap_out->flags & DMA_ALLOC_DONE))
+	      reorganize_buffers (dev, dmap_out);
+
+	    dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+	    DMAbuf_start_output (dev, 0, dmap_out->fragment_size);
+	  }
+#endif
 
 	audio_devs[dev]->enable_bits = bits;
 	if (changed && audio_devs[dev]->trigger)
@@ -819,6 +866,16 @@
       return snd_ioctl_return ((int *) arg, audio_devs[dev]->enable_bits);
       break;
 
+    case SNDCTL_DSP_SETSYNCRO:
+
+      if (!audio_devs[dev]->trigger)
+	return -EINVAL;
+
+      audio_devs[dev]->trigger (dev, 0);
+      audio_devs[dev]->go = 0;
+      return 0;
+      break;
+
     case SNDCTL_DSP_GETIPTR:
       {
 	count_info      info;
@@ -832,6 +889,10 @@
 	info.bytes += info.ptr;
 	memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info));
 
+#ifdef ALLOW_BUFFER_MAPPING
+	if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
+	  audio_devs[dev]->dmap_in->qlen = 0;	/* Acknowledge interrupts */
+#endif
 	restore_flags (flags);
 	return 0;
       }
@@ -850,6 +911,10 @@
 	info.bytes += info.ptr;
 	memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info));
 
+#ifdef ALLOW_BUFFER_MAPPING
+	if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+	  audio_devs[dev]->dmap_out->qlen = 0;	/* Acknowledge interrupts */
+#endif
 	restore_flags (flags);
 	return 0;
       }
@@ -879,6 +944,10 @@
 	  {
 	    /* OK to start the device */
 	    audio_devs[dev]->go = 1;
+
+	    if (audio_devs[dev]->trigger)
+	      audio_devs[dev]->trigger (dev,
+			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
 	  }
 }
 
@@ -902,7 +971,7 @@
   if (audio_devs[dev]->local_qlen)
     {
       tmp = audio_devs[dev]->local_qlen (dev);
-      if (tmp & len)
+      if (tmp && len)
 	tmp--;			/*
 				   * This buffer has been counted twice
 				 */
@@ -921,6 +990,13 @@
   int             abort, err = EIO;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
+#ifdef ALLOW_BUFFER_MAPPING
+  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+    {
+      printk ("Sound: Can't write to mmapped device (3)\n");
+      return -EINVAL;
+    }
+#endif
 
   if (dmap->dma_mode == DMODE_INPUT)	/* Direction change */
     {
@@ -983,11 +1059,11 @@
 	unsigned long   tl;
 
 	if (timeout)
-	  current->timeout = tl = jiffies + (timeout);
+	  current_set_timeout (tl = jiffies + (timeout));
 	else
 	  tl = 0xffffffff;
 	out_sleep_flag[dev].mode = WK_SLEEP;
-	interruptible_sleep_on (&out_sleeper[dev]);
+	module_interruptible_sleep_on (&out_sleeper[dev]);
 	if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
 	  {
 	    if (jiffies >= tl)
@@ -1001,8 +1077,9 @@
 	  err = EIO;
 	  abort = 1;
 	  ;
+	  audio_devs[dev]->reset (dev);
 	}
-      else if ((current->signal & ~current->blocked))
+      else if (current_got_fatal_signal ())
 	{
 	  err = EINTR;
 	  abort = 1;
@@ -1023,19 +1100,58 @@
 }
 
 int
+DMAbuf_get_curr_buffer (int dev, int *buf_no, char **dma_buf, int *buf_ptr, int *buf_size)
+{
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+  if (dmap->cfrag < 0)
+    return -1;
+
+  *dma_buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
+  *buf_ptr = dmap->counts[dmap->qtail];
+  *buf_size = dmap->fragment_size;
+  return *buf_no = dmap->cfrag;
+}
+
+int
+DMAbuf_set_count (int dev, int buff_no, int l)
+{
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+  if (buff_no == dmap->qtail)
+    {
+      dmap->cfrag = buff_no;
+      dmap->counts[buff_no] = l;
+    }
+  else
+    dmap->cfrag = -1;
+  return 0;
+}
+
+int
 DMAbuf_start_output (int dev, int buff_no, int l)
 {
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
+  dmap->cfrag = -1;
 /*
  * Bypass buffering if using mmaped access
  */
 
+#ifdef ALLOW_BUFFER_MAPPING
+  if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+    {
+      l = dmap->fragment_size;
+      dmap->counts[dmap->qtail] = l;
+      dmap->flags &= ~DMA_RESTART;
+      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+    }
+  else
+#else
   if (dmap != NULL)
+#endif
     {
 
-      if (buff_no != dmap->qtail)
-	printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
 
       dmap->qlen++;
       if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
@@ -1165,12 +1281,43 @@
   unsigned long   flags;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
 
+  int             p;
+
   dmap->byte_counter += dmap->counts[dmap->qhead];
 
 #ifdef OS_DMA_INTR
   sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
 #endif
 
+#ifdef ALLOW_BUFFER_MAPPING
+  if (dmap->mapping_flags & DMA_MAP_MAPPED)
+    {
+      /* mmapped access */
+
+      p = dmap->fragment_size * dmap->qhead;
+      memset (dmap->raw_buf + p,
+	      dmap->neutral_byte,
+	      dmap->fragment_size);
+
+      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+      dmap->qlen++;		/* Yes increment it (don't decrement) */
+      dmap->flags &= ~DMA_ACTIVE;
+      dmap->counts[dmap->qhead] = dmap->fragment_size;
+
+      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
+	{
+	  audio_devs[dev]->output_block (dev, dmap->raw_buf_phys +
+					 dmap->qhead * dmap->fragment_size,
+					 dmap->counts[dmap->qhead], 1,
+				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
+	  if (audio_devs[dev]->trigger)
+	    audio_devs[dev]->trigger (dev,
+			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+	}
+      dmap->flags |= DMA_ACTIVE;
+    }
+  else
+#endif
   if (event_type != 2)
     {
       if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
@@ -1184,6 +1331,27 @@
       dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
       dmap->flags &= ~DMA_ACTIVE;
 
+      if (event_type == 1 && dmap->qlen < 1)
+	{
+	  dmap->underrun_count++;
+	  /* Ignore underrun. Just move the tail pointer forward and go */
+	  if (dmap->closing)
+	    {
+	      audio_devs[dev]->halt_xfer (dev);
+	    }
+	  else
+	    {
+	      dmap->qlen++;
+	      dmap->cfrag = -1;
+	      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+
+	      p = dmap->fragment_size * dmap->qhead;
+	      memset (dmap->raw_buf + p,
+		      dmap->neutral_byte,
+		      dmap->fragment_size);
+	    }
+	}
+
       if (dmap->qlen)
 	{
 	  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
@@ -1198,21 +1366,6 @@
 	    }
 	  dmap->flags |= DMA_ACTIVE;
 	}
-      else if (event_type == 1)
-	{
-	  dmap->underrun_count++;
-	  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
-	      audio_devs[dev]->halt_output)
-	    audio_devs[dev]->halt_output (dev);
-	  else
-	    audio_devs[dev]->halt_xfer (dev);
-
-	  if ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
-	      audio_devs[dev]->flags & NEEDS_RESTART)
-	    dmap->flags |= DMA_RESTART;
-	  else
-	    dmap->flags &= ~DMA_RESTART;
-	}
     }				/* event_type != 2 */
 
   save_flags (flags);
@@ -1221,7 +1374,7 @@
     {
       {
 	out_sleep_flag[dev].mode = WK_WAKEUP;
-	wake_up (&out_sleeper[dev]);
+	module_wake_up (&out_sleeper[dev]);
       };
     }
   restore_flags (flags);
@@ -1239,21 +1392,47 @@
   sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
 #endif
 
+#ifdef ALLOW_BUFFER_MAPPING
+  if (dmap->mapping_flags & DMA_MAP_MAPPED)
+    {
+      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+      dmap->qlen++;
+
+      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
+	{
+	  audio_devs[dev]->start_input (dev, dmap->raw_buf_phys +
+					dmap->qtail * dmap->fragment_size,
+					dmap->fragment_size, 1,
+				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
+	  if (audio_devs[dev]->trigger)
+	    audio_devs[dev]->trigger (dev,
+			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+	}
+
+      dmap->flags |= DMA_ACTIVE;
+    }
+  else
+#endif
   if (dmap->qlen == (dmap->nbufs - 1))
     {
       printk ("Sound: Recording overrun\n");
       dmap->underrun_count++;
-      if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
-	  audio_devs[dev]->halt_input)
-	audio_devs[dev]->halt_input (dev);
-      else
-	audio_devs[dev]->halt_xfer (dev);
 
-      dmap->flags &= ~DMA_ACTIVE;
       if (audio_devs[dev]->flags & DMA_AUTOMODE)
-	dmap->flags |= DMA_RESTART;
-      else
-	dmap->flags &= ~DMA_RESTART;
+	{
+	  /* Force restart on next write */
+	  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+	      audio_devs[dev]->halt_input)
+	    audio_devs[dev]->halt_input (dev);
+	  else
+	    audio_devs[dev]->halt_xfer (dev);
+
+	  dmap->flags &= ~DMA_ACTIVE;
+	  if (audio_devs[dev]->flags & DMA_AUTOMODE)
+	    dmap->flags |= DMA_RESTART;
+	  else
+	    dmap->flags &= ~DMA_RESTART;
+	}
     }
   else
     {
@@ -1262,28 +1441,28 @@
 	printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
 		dev, dmap->qlen, dmap->nbufs);
       dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+    }
 
-      if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
-	{
-	  audio_devs[dev]->start_input (dev, dmap->raw_buf_phys +
-					dmap->qtail * dmap->fragment_size,
-					dmap->fragment_size, 1,
+  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
+    {
+      audio_devs[dev]->start_input (dev, dmap->raw_buf_phys +
+				    dmap->qtail * dmap->fragment_size,
+				    dmap->fragment_size, 1,
 				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
-	  if (audio_devs[dev]->trigger)
-	    audio_devs[dev]->trigger (dev,
+      if (audio_devs[dev]->trigger)
+	audio_devs[dev]->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
-	}
-
-      dmap->flags |= DMA_ACTIVE;
     }
 
+  dmap->flags |= DMA_ACTIVE;
+
   save_flags (flags);
   cli ();
   if ((in_sleep_flag[dev].mode & WK_SLEEP))
     {
       {
 	in_sleep_flag[dev].mode = WK_WAKEUP;
-	wake_up (&in_sleeper[dev]);
+	module_wake_up (&in_sleeper[dev]);
       };
     }
   restore_flags (flags);
@@ -1352,7 +1531,7 @@
 }
 
 int
-DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
 {
   struct dma_buffparms *dmap;
   unsigned long   flags;
@@ -1362,6 +1541,20 @@
     case SEL_IN:
       dmap = audio_devs[dev]->dmap_in;
 
+#ifdef ALLOW_BUFFER_MAPPING
+      if (dmap->mapping_flags & DMA_MAP_MAPPED)
+	{
+	  if (dmap->qlen)
+	    return 1;
+
+	  save_flags (flags);
+	  cli ();
+	  in_sleep_flag[dev].mode = WK_SLEEP;
+	  module_select_wait (&in_sleeper[dev], wait);
+	  restore_flags (flags);
+	  return 0;
+	}
+#endif
 
       if (dmap->dma_mode != DMODE_INPUT)
 	{
@@ -1384,7 +1577,7 @@
 	  save_flags (flags);
 	  cli ();
 	  in_sleep_flag[dev].mode = WK_SLEEP;
-	  select_wait (&in_sleeper[dev], wait);
+	  module_select_wait (&in_sleeper[dev], wait);
 	  restore_flags (flags);
 	  return 0;
 	}
@@ -1394,6 +1587,20 @@
     case SEL_OUT:
       dmap = audio_devs[dev]->dmap_out;
 
+#ifdef ALLOW_BUFFER_MAPPING
+      if (dmap->mapping_flags & DMA_MAP_MAPPED)
+	{
+	  if (dmap->qlen)
+	    return 1;
+
+	  save_flags (flags);
+	  cli ();
+	  out_sleep_flag[dev].mode = WK_SLEEP;
+	  module_select_wait (&out_sleeper[dev], wait);
+	  restore_flags (flags);
+	  return 0;
+	}
+#endif
 
       if (dmap->dma_mode == DMODE_INPUT)
 	{
@@ -1410,7 +1617,7 @@
 	  save_flags (flags);
 	  cli ();
 	  out_sleep_flag[dev].mode = WK_SLEEP;
-	  select_wait (&out_sleeper[dev], wait);
+	  module_select_wait (&out_sleeper[dev], wait);
 	  restore_flags (flags);
 	  return 0;
 	}
@@ -1425,7 +1632,7 @@
 }
 
 
-#else /* EXCLUDE_AUDIO */
+#else /* CONFIG_AUDIO */
 /*
  * Stub versions if audio services not included
  */
@@ -1513,6 +1720,4 @@
 {
   return;
 }
-#endif
-
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/experimental.txt linux/drivers/sound/experimental.txt
--- v1.3.57/linux/drivers/sound/experimental.txt	Tue Jul 11 10:02:52 1995
+++ linux/drivers/sound/experimental.txt	Thu Jan  1 02:00:00 1970
@@ -1,165 +0,0 @@
-This version contains some features which is may NOT be enabled by default. 
-I'm trying to release an official/reliable version soon so that the
-Linux version of Doom (and other games) becomes possible. For that reason
-I have disabled some features which are not reliable enough to be
-released for wide public. If you are interested to try them, please
-read this file carefully.
-
-1) ECHO PSS (Personal Sound System support)
-
-This version contains support for soundcards based on the AD20msp614
-chipset made by Analog Devices. This chipset consist of the
-AD1848 codec, ADSP-21xx DSP chip and a ESC614 ASIC and is used in some
-soundcards made by Orchid, Cardinal, Echo Speech Corporation, Western
-Digital and Wearnes Technology. The PSS support is by Marc M. Hoffman
-(marc.hoffman@analog.com). I received this stuff about a week ago and
-have not been able to test it yet.
-If you are interested, remove the B(OPT_PSS) from the DISABLED_OPTIONS
-(see above).
-You have also to enable the MSS support since I have not integrated
-the AD1848 driver with the PSS one yet.
-
-2) /dev/music (/dev/sequencer2)
-
-This version has a new device file called /dev/music. I have not
-implemented all parts of it but it's there. It's only interesting if
-you are writing a sequencer program yourself. Enable by creating
-the device file /dev/music. Use the script at the end of linux/Readme
-
-3) /dev/midi##
-
-These are tty like raw devices for MIDI ports. Since there is a minor
-incompatibility between different versions of Linux, I have disabled
-this feature by default. You just need to create the device files yourself.
-
-4) Support for hardware based u-Law/A-Law and ADPCM formats.
-
-The AD1848 (and compatibles) are able to do compression and
-decompression by hardware. This version has experimental support
-for some of them. Currently they are implemented just in the
-AD1848 driver. The GUS MAX (and the 16 bit daughtercard) support
-also 16->4 bit ADPCM (the IMA one) but it don't work yet.
-The argument ioctl(SNDCTL_DSP_SAMPLESIZE) can have some new values
-in addition to the 8 and 16 supported earlier. Look at soundcard.h
-for more info.
-(In case somebody dares to ask: The ASP chip of SB16 is not supported
-so the hardware compression/decompression doesn't work with it. Also
-the ADPCM format is different than the standard (IMA) one (I guess).
-This feature is enabled by default.
-
-5) Real time fix to /dev/dsp and /dev/audio drivers
-
-The following feature should help game writers. This stuff is enabled
-by default.
----------------- cut here ---------------------
-There is a new ioctl called SNDCTL_DSP_SETFRAGMENT. It accepts a
-int parameter which has format 0x00nn00ss where the nn is max number of 
-buffer fragments (between 0x02 and 0xff) and the ss gives indirectly the 
-size of a buffer fragment (fragment_size = (1 << ss)). Valid sizes are 
-between (ss=0x07 -> 128 bytes and ss=0x11 (17 dec) -> 128k).
-
-This ioctl must be used ONCE between open() and first call to 
-read()/write() or ioctl(SNDCTL_DSP_GETBLKSIZE). 
-
-You need just to force the fragment size to a value which is sufficiently 
-short (gives the 1/20th of sec with the speed/#channels/#bits you are using).
-
-Using a small number of fragments offers (I guess) a significant advantage.
-For example with 2 fragments the driver works as the following (at least 
-I hope so). Assuming that the process writes exactly 'fragment_size' of 
-bytes each time (this is really important).
-
-	1) When the process writes the first fragment, it will be copied to
-	the DMA buffer area and the playback begins. The write() returns
-	immediately and the process is free to continue.
-
-
-	2a) If the fragment gets played before the application writes a new
-	one, the device will be stoppen and restarted which causes a click.
-	When the process calls write next time, it will be processes as 
-	in step 1.
-
-	2b) If the process calls write before the buffer underflows, the
-	data will be queued and the process is free to continue. (There
-	is now one full and one partially played fragment in the kernel
-	buffers. This gives average delay of 1.5*fragment_time (for 
-	example 1/20th sec) before the last byte in the buffer gets played.
-
-
-	3a) If the device gets both fragments played before the next write
-	(underflow), there will be a click. The write will be processed as
-	in step 1.
-
-	3b) If the 1st fragment gets played before next write (the process
-	calls write during playback of the second fragment), it will be
-	processed as step 2b.
-
-	3c) If the process writes 3rd fragment when there is already 2
-	fragments in the queue (1 playing and 1 waiting), the process
-	will block until the 1st fragment gets played. It will then be
-	woken up and it continues as in step 2b. This means that
-	the process blocks for at most the time required to play a
-	buffer fragment.
-
-This method syncronizes the process and the audio device together 
-automaticly. The process will block at most the 'fragment_time'. Usually 
-less, depending on how much it needs time to do other things. The maximum
-delay between writing a byte and the time when it finally plays is
-at most 3 times the 'fragment_time'. 
-
-The delay depends on how much time the program needs to do it's 
-computations for the next sample (updating screen etc). If it's about
-80% of the 'fragment_time' the game will run almost without delays. If it 
-uses more time, there is a risk that the audio buffer gets empty.
-	
-The application code should be something like the following:
-
-int frag = 0x00020008;	/* 2 fragments of 2^8=256 bytes */
-int frag_size;
-
-int fd=open("/dev/dsp");
-ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
-ioctl(NDCTL_DSP_SPEED); /* And #channels & #bits if required */
-
-/*
- * Query the actual fragment sice since the driver may refuse
- * the requested one (unlikely but possible?)
- */
-
-ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size);
-
-while(True)
-{
-	do_computations();
-	write(fd, buf, frag_size);	/* Always the same size!!!!!!! */
-}
-
-I have tested this with a modified version of str.c. The algorithm works 
-as long as the playing program gets enough time to run. Hitting ENTER on 
-another virtual console causes a pause/click (with 2 frags of 64 bytes).
-
-NOTE! It's important to know that this call may be called just once and
-it must be done immediately after open(). The fragment size will remain
-in effect until the device is closed.
-------------------- cut here ---------------------
-
-6)	Detection and initialization code for Ensoniq Soundscape
-
-This version is able to initialize SoundScape (almost). However
-PCM recording and playback don't work. Also MIDI playback sounds wierd
-since the driver is not able to set volume controls properly.
-The soundscape support is disabled. You need to enable it by editing
-beginning of configure.c. Also read comments in sndscape/README.
-
-7)	select() support for /dev/audio and /dev/dsp. (/dev/midi## and
-	/dev/sequencer had it already in v2.90).
-
-There is now select() support in the audio/dsp driver (for Linux only).
-However I have not tried this feature yet. 
-There are also some new ioctl() calls (please look at soundcard.h).
-
-8)	MIDI recording in /dev/music (/dev/sequencer2)
-
-MIDI recording was earlier implemented only with full MPU-401 devices.
-This version has it also for dumb MIDI ports. However I have not tested it
-yet.
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v1.3.57/linux/drivers/sound/gus_card.c	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/gus_card.c	Tue Jan  9 00:37:14 1996
@@ -29,7 +29,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+#if defined(CONFIG_GUS)
 
 #include "gus_hw.h"
 
@@ -64,7 +64,7 @@
       if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
 	if (sound_alloc_dma (hw_config->dma2, "GUS(2)"))
 	  printk ("gus_card.c: Can't allocate DMA channel2\n");
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
       mem_start = gus_midi_init (mem_start);
 #endif
       return mem_start;
@@ -93,7 +93,7 @@
 	  if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
 	    if (sound_alloc_dma (hw_config->dma2, "GUS"))
 	      printk ("gus_card.c: Can't allocate DMA channel2\n");
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
 	  mem_start = gus_midi_init (mem_start);
 #endif
 	  return mem_start;
@@ -166,7 +166,7 @@
 
   sti ();
 
-#ifndef EXCLUDE_GUSMAX
+#ifdef CONFIG_GUSMAX
   if (have_gus_max)
     ad1848_interrupt (irq, NULL);
 #endif
@@ -183,16 +183,19 @@
 
       if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
 	{
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
 	  gus_midi_interrupt (0);
 #endif
 	}
 
       if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
 	{
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
 	  if (gus_timer_enabled)
-	    sound_timer_interrupt ();
+	    {
+	      sound_timer_interrupt ();
+	    }
+
 	  gus_write8 (0x45, 0);	/* Ack IRQ */
 	  gus_timer_command (4, 0x80);	/* Reset IRQ flags */
 
@@ -213,7 +216,7 @@
 /*
  * Some extra code for the 16 bit sampling option
  */
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16)
+#if defined(CONFIG_GUS16)
 
 int
 probe_gus_db16 (struct address_info *hw_config)
@@ -224,8 +227,10 @@
 long
 attach_gus_db16 (long mem_start, struct address_info *hw_config)
 {
+#ifdef CONFIG_GUS
   gus_pcm_volume = 100;
   gus_wave_volume = 90;
+#endif
 
   ad1848_init ("GUS 16 bit sampling", hw_config->io_base,
 	       hw_config->irq,
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c
--- v1.3.57/linux/drivers/sound/gus_midi.c	Wed Nov  8 07:11:35 1995
+++ linux/drivers/sound/gus_midi.c	Tue Jan  9 00:37:15 1996
@@ -29,11 +29,9 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
 #include "gus_hw.h"
 
-#if !defined(EXCLUDE_GUS) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_GUS) && defined(CONFIG_MIDI)
 
 static int      midi_busy = 0, input_opened = 0;
 static int      my_dev;
@@ -75,14 +73,8 @@
       input_opened = 1;
     }
 
-  if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
-    {
-      gus_midi_control |= MIDI_ENABLE_XMIT;
-    }
 
-  outb (gus_midi_control, u_MidiControl);	/*
-						   * Enable
-						 */
+  outb (gus_midi_control, u_MidiControl);	/* Enable */
 
   midi_busy = 1;
   qlen = qhead = qtail = output_used = 0;
@@ -276,37 +268,37 @@
   save_flags (flags);
   cli ();
 
-  stat = GUS_MIDI_STATUS ();
-
-  if (stat & MIDI_RCV_FULL)
+  while ((stat = GUS_MIDI_STATUS ()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY))
     {
-      data = inb (u_MidiData);
-      if (input_opened)
-	midi_input_intr (my_dev, data);
-    }
-
-  if (stat & MIDI_XMIT_EMPTY)
-    {
-      while (qlen && dump_to_midi (tmp_queue[qhead]))
+      if (stat & MIDI_RCV_FULL)
 	{
-	  qlen--;
-	  qhead++;
+	  data = inb (u_MidiData);
+	  if (input_opened)
+	    midi_input_intr (my_dev, data);
 	}
 
-      if (!qlen)
+      if (stat & MIDI_XMIT_EMPTY)
 	{
-	  /*
-	   * Disable Midi output interrupts, since no data in the buffer
-	   */
-	  gus_midi_control &= ~MIDI_ENABLE_XMIT;
-	  outb (gus_midi_control, u_MidiControl);
+	  while (qlen && dump_to_midi (tmp_queue[qhead]))
+	    {
+	      qlen--;
+	      qhead++;
+	    }
+
+	  if (!qlen)
+	    {
+	      /*
+	       * Disable Midi output interrupts, since no data in the buffer
+	       */
+	      gus_midi_control &= ~MIDI_ENABLE_XMIT;
+	      outb (gus_midi_control, u_MidiControl);
+	      outb (gus_midi_control, u_MidiControl);
+	    }
 	}
-    }
 
+    }
 
   restore_flags (flags);
 }
-
-#endif
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c
--- v1.3.57/linux/drivers/sound/gus_vol.c	Fri Oct 13 14:44:34 1995
+++ linux/drivers/sound/gus_vol.c	Tue Jan  9 00:37:15 1996
@@ -4,7 +4,7 @@
  * Greg Lee 1993.
  */
 #include "sound_config.h"
-#ifndef EXCLUDE_GUS
+#ifdef CONFIG_GUS
 #include "gus_linearvol.h"
 
 #define GUS_VOLUME	gus_wave_volume
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v1.3.57/linux/drivers/sound/gus_wave.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/gus_wave.c	Tue Jan  9 00:37:19 1996
@@ -31,7 +31,7 @@
 #include <linux/ultrasound.h>
 #include "gus_hw.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+#if defined(CONFIG_GUS)
 
 #define MAX_SAMPLE	150
 #define MAX_PATCH	256
@@ -112,7 +112,7 @@
 static int      gus_sampling_channels;
 static int      gus_sampling_bits;
 
-static struct wait_queue *dram_sleeper = NULL;
+static wait_handle *dram_sleeper = NULL;
 static volatile struct snd_wait dram_sleep_flag =
 {0};
 
@@ -1734,11 +1734,11 @@
 	    unsigned long   tl;
 
 	    if (HZ)
-	      current->timeout = tl = jiffies + (HZ);
+	      current_set_timeout (tl = jiffies + (HZ));
 	    else
 	      tl = 0xffffffff;
 	    dram_sleep_flag.mode = WK_SLEEP;
-	    interruptible_sleep_on (&dram_sleeper);
+	    module_interruptible_sleep_on (&dram_sleeper);
 	    if (!(dram_sleep_flag.mode & WK_WAKEUP))
 	      {
 		if (jiffies >= tl)
@@ -2829,7 +2829,7 @@
 			 SOUND_MASK_SYNTH|SOUND_MASK_PCM)
   if (((cmd >> 8) & 0xff) == 'M')
     {
-      if (cmd & IOC_IN)
+      if (_IOC_DIR (cmd) & _IOC_WRITE)
 	switch (cmd & 0xff)
 	  {
 	  case SOUND_MIXER_RECSRC:
@@ -3052,7 +3052,7 @@
 	  model_num = "MAX";
 	  gus_type = 0x40;
 	  mixer_type = CS4231;
-#ifndef EXCLUDE_GUSMAX
+#ifdef CONFIG_GUSMAX
 	  {
 	    unsigned char   max_config = 0x40;	/* Codec enable */
 
@@ -3098,10 +3098,8 @@
        */
     }
 
-
-  printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
-
   sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+  conf_printf (gus_info.name, hw_config);
 
   if (num_synths >= MAX_SYNTH_DEV)
     printk ("GUS Error: Too many synthesizers\n");
@@ -3109,7 +3107,7 @@
     {
       voice_alloc = &guswave_operations.alloc;
       synth_devs[num_synths++] = &guswave_operations;
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
       gus_tmr_install (gus_base + 8);
 #endif
     }
@@ -3157,7 +3155,7 @@
 void
 gus_wave_unload (void)
 {
-#ifndef EXCLUDE_GUSMAX
+#ifdef CONFIG_GUSMAX
   if (have_gus_max)
     {
       ad1848_unload (gus_base + 0x10c,
@@ -3389,7 +3387,7 @@
 	if ((dram_sleep_flag.mode & WK_SLEEP))
 	  {
 	    dram_sleep_flag.mode = WK_WAKEUP;
-	    wake_up (&dram_sleeper);
+	    module_wake_up (&dram_sleeper);
 	  };
 	break;
 
@@ -3426,7 +3424,7 @@
 
 }
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
 /*
  * Timer stuff
  */
@@ -3469,7 +3467,7 @@
       gus_timer_command (0x04, 0x02);	/* Start timer 2 */
     }
 
-  gus_timer_enabled = 0;
+  gus_timer_enabled = 1;
 }
 
 static unsigned int
@@ -3510,6 +3508,7 @@
     gus_write8 (0x45, 0x04);	/* Start timer 1 again */
   else
     gus_write8 (0x45, 0x08);	/* Start timer 2 again */
+  gus_timer_enabled = 1;
 }
 
 static struct sound_lowlev_timer gus_tmr =
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c
--- v1.3.57/linux/drivers/sound/ics2101.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/ics2101.c	Tue Jan  9 00:37:20 1996
@@ -28,7 +28,7 @@
  */
 
 #include "sound_config.h"
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+#if defined(CONFIG_GUS)
 
 #include <linux/ultrasound.h>
 #include "gus_hw.h"
@@ -134,7 +134,7 @@
 {
   if (((cmd >> 8) & 0xff) == 'M')
     {
-      if (cmd & IOC_IN)
+      if (_IOC_DIR (cmd) & _IOC_WRITE)
 	switch (cmd & 0xff)
 	  {
 	  case SOUND_MIXER_RECSRC:
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v1.3.57/linux/drivers/sound/mad16.c	Fri Oct 13 14:44:34 1995
+++ linux/drivers/sound/mad16.c	Tue Jan  9 00:37:20 1996
@@ -72,7 +72,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MAD16)
+#if defined(CONFIG_MAD16)
 
 static int      already_initialized = 0;
 
@@ -451,7 +451,7 @@
 {
   if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
     {
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
 
       if (mad_read (MC1_PORT) & 0x20)
 	hw_config->io_base = 0x240;
@@ -464,7 +464,7 @@
 #endif
     }
 
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   if (!already_initialized)
     return mem_start;
 
@@ -477,7 +477,7 @@
 int
 probe_mad16_mpu (struct address_info *hw_config)
 {
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   static int      mpu_attached = 0;
   static int      valid_ports[] =
   {0x330, 0x320, 0x310, 0x300};
@@ -497,7 +497,7 @@
   if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
     {
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
       unsigned char   tmp;
 
       tmp = mad_read (MC3_PORT);
@@ -597,7 +597,15 @@
 void
 unload_mad16_mpu (struct address_info *hw_config)
 {
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#ifdef CONFIG_MIDI
+  if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
+    {
+      mad16_sb_dsp_unload (hw_config);
+      return;
+    }
+#endif
+
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   unload_mpu401 (hw_config);
 #endif
 }
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/mad16_sb_midi.c linux/drivers/sound/mad16_sb_midi.c
--- v1.3.57/linux/drivers/sound/mad16_sb_midi.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/mad16_sb_midi.c	Tue Jan  9 00:37:21 1996
@@ -29,7 +29,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MAD16) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_MAD16) && defined(CONFIG_MIDI)
 
 #define sbc_base mad16_sb_base
 #include "sb.h"
@@ -39,6 +39,7 @@
 static int      mad16_sb_base = 0x220;
 static int      mad16_sb_irq = 0;
 static int      mad16_sb_dsp_ok = 0;
+static int      mad16_sb_dsp_attached = 0;
 static sound_os_info *midi_osp;
 
 int             mad16_sb_midi_mode = NORMAL_MIDI;
@@ -111,11 +112,11 @@
   int             loopc;
 
   outb (1, DSP_RESET);
-  tenmicrosec ();
+  tenmicrosec (midi_osp);
   outb (0, DSP_RESET);
-  tenmicrosec ();
-  tenmicrosec ();
-  tenmicrosec ();
+  tenmicrosec (midi_osp);
+  tenmicrosec (midi_osp);
+  tenmicrosec (midi_osp);
 
   for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++);	/*
 										   * Wait
@@ -165,6 +166,7 @@
  * mad16_sb_midi_init -- everything else is done elsewhere */
 {
 
+  mad16_sb_dsp_attached = 1;
   midi_osp = hw_config->osp;
   if (snd_set_irq_handler (mad16_sb_irq, mad16_sbintr, "MAD16 SB MIDI", midi_osp) < 0)
     {
@@ -174,11 +176,21 @@
 
   request_region (hw_config->io_base, 16, "mad16/Mozart MIDI");
 
-  printk (" <MAD16 MIDI (SB mode)>");
+  conf_printf ("MAD16 MIDI (SB mode)", hw_config);
   mad16_sb_midi_init (2);
 
   mad16_sb_dsp_ok = 1;
   return mem_start;
+}
+
+void
+mad16_sb_dsp_unload (struct address_info *hw_config)
+{
+  if (!mad16_sb_dsp_attached)
+    return;
+
+  release_region (hw_config->io_base, 16);
+  snd_release_irq (hw_config->irq);
 }
 
 static int
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v1.3.57/linux/drivers/sound/maui.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/maui.c	Tue Jan  9 00:37:21 1996
@@ -32,7 +32,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MAUI)
+#if defined(CONFIG_MAUI)
 
 static int      maui_base = 0x330;
 
@@ -191,13 +191,16 @@
       return 0;
     }
 
-  printk ("WaveFront hardware version %d.%d\n", tmp1, tmp2);
+  if (trace_init)
+    printk ("WaveFront hardware version %d.%d\n", tmp1, tmp2);
 
   if (!maui_write (0x9F))	/* Report firmware version */
     return 0;
   if ((tmp1 = maui_read ()) == -1 || (tmp2 = maui_read ()) == -1)
     return 0;
-  printk ("WaveFront firmware version %d.%d\n", tmp1, tmp2);
+
+  if (trace_init)
+    printk ("WaveFront firmware version %d.%d\n", tmp1, tmp2);
 
   if (!maui_write (0x85))	/* Report free DRAM */
     return 0;
@@ -206,7 +209,8 @@
     {
       tmp1 |= maui_read () << (7 * i);
     }
-  printk ("Available DRAM %dk\n", tmp1 / 1024);
+  if (trace_init)
+    printk ("Available DRAM %dk\n", tmp1 / 1024);
 
   request_region (hw_config->io_base + 2, 6, "Maui");
 
@@ -222,7 +226,7 @@
 {
   int             this_dev = num_midis;
 
-  printk (" <Maui>");
+  conf_printf ("Maui", hw_config);
 
   hw_config->irq *= -1;
   mem_start = attach_mpu401 (mem_start, hw_config);
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c
--- v1.3.57/linux/drivers/sound/midi_synth.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/midi_synth.c	Tue Jan  9 00:37:22 1996
@@ -32,11 +32,11 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_MIDI)
 
 #define _MIDI_SYNTH_C_
 
-static struct wait_queue *sysex_sleeper = NULL;
+static wait_handle *sysex_sleeper = NULL;
 static volatile struct snd_wait sysex_sleep_flag =
 {0};
 
@@ -47,7 +47,7 @@
 {0};
 static unsigned char prev_out_status[MAX_MIDI_DEV];
 
-#ifdef EXCLUDE_SEQUENCER
+#ifndef CONFIG_SEQUENCER
 #define STORE(cmd)
 #else
 #define STORE(cmd) \
@@ -472,6 +472,8 @@
   inc->m_prev_status = 0x00;
   restore_flags (flags);
 
+  sysex_sleep_flag.mode = WK_NONE;
+
   return 1;
 }
 
@@ -545,7 +547,7 @@
 
   sysex_sleep_flag.mode = WK_NONE;
 
-  for (i = 0; i < left && !(current->signal & ~current->blocked); i++)
+  for (i = 0; i < left && !current_got_fatal_signal (); i++)
     {
       unsigned char   data;
 
@@ -566,17 +568,17 @@
 	}
 
       while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
-	     !(current->signal & ~current->blocked))
+	     !current_got_fatal_signal ())
 
 	{
 	  unsigned long   tl;
 
 	  if (1)
-	    current->timeout = tl = jiffies + (1);
+	    current_set_timeout (tl = jiffies + (1));
 	  else
 	    tl = 0xffffffff;
 	  sysex_sleep_flag.mode = WK_SLEEP;
-	  interruptible_sleep_on (&sysex_sleeper);
+	  module_interruptible_sleep_on (&sysex_sleeper);
 	  if (!(sysex_sleep_flag.mode & WK_WAKEUP))
 	    {
 	      if (jiffies >= tl)
@@ -638,8 +640,8 @@
   int             orig_dev = synth_devs[dev]->midi_dev;
   int             chn, msg;
 
-  if (ctrl_num < 1 || ctrl_num > 127)
-    return;			/* NOTE! Controller # 0 ignored */
+  if (ctrl_num < 0 || ctrl_num > 127)
+    return;
   if (channel < 0 || channel > 15)
     return;
 
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/midi_synth.h linux/drivers/sound/midi_synth.h
--- v1.3.57/linux/drivers/sound/midi_synth.h	Fri Oct 13 14:44:34 1995
+++ linux/drivers/sound/midi_synth.h	Tue Jan  9 00:36:54 1996
@@ -15,7 +15,6 @@
 int midi_synth_patchmgr (int dev, struct patmgr_info *rec);
 void midi_synth_bender (int dev, int chn, int value);
 void midi_synth_setup_voice (int dev, int voice, int chn);
-void do_midi_msg (int synthno, unsigned char *msg, int mlen);
 int midi_synth_send_sysex(int dev, unsigned char *bytes,int len);
 
 #ifndef _MIDI_SYNTH_C_
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v1.3.57/linux/drivers/sound/midibuf.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/midibuf.c	Tue Jan  9 00:37:23 1996
@@ -29,7 +29,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_MIDI)
 
 /*
  * Don't make MAX_QUEUE_SIZE larger than 4000
@@ -37,12 +37,12 @@
 
 #define MAX_QUEUE_SIZE	4000
 
-static struct wait_queue *midi_sleeper[MAX_MIDI_DEV] =
+static wait_handle *midi_sleeper[MAX_MIDI_DEV] =
 {NULL};
 static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] =
 {
   {0}};
-static struct wait_queue *input_sleeper[MAX_MIDI_DEV] =
+static wait_handle *input_sleeper[MAX_MIDI_DEV] =
 {NULL};
 static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] =
 {
@@ -106,18 +106,18 @@
    */
 
   if (midi_devs[dev]->buffer_status != NULL)
-    while (!(current->signal & ~current->blocked) &&
+    while (!current_got_fatal_signal () &&
 	   midi_devs[dev]->buffer_status (dev))
 
       {
 	unsigned long   tl;
 
 	if (HZ / 10)
-	  current->timeout = tl = jiffies + (HZ / 10);
+	  current_set_timeout (tl = jiffies + (HZ / 10));
 	else
 	  tl = 0xffffffff;
 	midi_sleep_flag[dev].mode = WK_SLEEP;
-	interruptible_sleep_on (&midi_sleeper[dev]);
+	module_interruptible_sleep_on (&midi_sleeper[dev]);
 	if (!(midi_sleep_flag[dev].mode & WK_WAKEUP))
 	  {
 	    if (jiffies >= tl)
@@ -146,7 +146,7 @@
       if ((input_sleep_flag[dev].mode & WK_SLEEP))
 	{
 	  input_sleep_flag[dev].mode = WK_WAKEUP;
-	  wake_up (&input_sleeper[dev]);
+	  module_wake_up (&input_sleeper[dev]);
 	};
     }
 
@@ -185,7 +185,7 @@
 		(midi_sleep_flag[dev].mode & WK_SLEEP))
 	      {
 		midi_sleep_flag[dev].mode = WK_WAKEUP;
-		wake_up (&midi_sleeper[dev]);
+		module_wake_up (&midi_sleeper[dev]);
 	      };
 	  }
 
@@ -203,7 +203,6 @@
 MIDIbuf_open (int dev, struct fileinfo *file)
 {
   int             mode, err;
-  unsigned long   flags;
 
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
@@ -224,27 +223,20 @@
      *    Interrupts disabled. Be careful
    */
 
-  save_flags (flags);
-  cli ();
   if ((err = midi_devs[dev]->open (dev, mode,
 				   midi_input_intr, midi_output_intr)) < 0)
     {
-      restore_flags (flags);
       return err;
     }
 
   parms[dev].prech_timeout = 0;
 
-  midi_sleep_flag[dev].mode = WK_NONE;
-  input_sleep_flag[dev].mode = WK_NONE;
-
   midi_in_buf[dev] = (struct midi_buf *) kmalloc (sizeof (struct midi_buf), GFP_KERNEL);
 
   if (midi_in_buf[dev] == NULL)
     {
       printk ("midi: Can't allocate buffer\n");
       midi_devs[dev]->close (dev);
-      restore_flags (flags);
       return -EIO;
     }
   midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
@@ -257,20 +249,23 @@
       midi_devs[dev]->close (dev);
       kfree (midi_in_buf[dev]);
       midi_in_buf[dev] = NULL;
-      restore_flags (flags);
       return -EIO;
     }
   midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
-  if (!open_devs)
+  open_devs++;
 
+  midi_sleep_flag[dev].mode = WK_NONE;
+  input_sleep_flag[dev].mode = WK_NONE;
+
+  if (open_devs < 2)		/* This was first open */
     {
-      poll_timer.expires = (1) + jiffies;
-      add_timer (&poll_timer);
-    };				/*
-				   * Come back later
-				 */
-  open_devs++;
-  restore_flags (flags);
+      ;
+
+      {
+	poll_timer.expires = (1) + jiffies;
+	add_timer (&poll_timer);
+      };			/* Start polling */
+    }
 
   return err;
 }
@@ -284,6 +279,9 @@
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
 
+  if (dev < 0 || dev >= num_midis)
+    return;
+
   save_flags (flags);
   cli ();
 
@@ -298,18 +296,18 @@
 						   * devices
 						 */
 
-      while (!(current->signal & ~current->blocked) &&
+      while (!current_got_fatal_signal () &&
 	     DATA_AVAIL (midi_out_buf[dev]))
 
 	{
 	  unsigned long   tl;
 
 	  if (0)
-	    current->timeout = tl = jiffies + (0);
+	    current_set_timeout (tl = jiffies + (0));
 	  else
 	    tl = 0xffffffff;
 	  midi_sleep_flag[dev].mode = WK_SLEEP;
-	  interruptible_sleep_on (&midi_sleeper[dev]);
+	  module_interruptible_sleep_on (&midi_sleeper[dev]);
 	  if (!(midi_sleep_flag[dev].mode & WK_WAKEUP))
 	    {
 	      if (jiffies >= tl)
@@ -325,14 +323,17 @@
 				 */
     }
 
+  restore_flags (flags);
+
   midi_devs[dev]->close (dev);
+
   kfree (midi_in_buf[dev]);
   kfree (midi_out_buf[dev]);
   midi_in_buf[dev] = NULL;
   midi_out_buf[dev] = NULL;
+  if (open_devs < 2)
+    del_timer (&poll_timer);;
   open_devs--;
-  del_timer (&poll_timer);;
-  restore_flags (flags);
 }
 
 int
@@ -365,11 +366,11 @@
 	    unsigned long   tl;
 
 	    if (0)
-	      current->timeout = tl = jiffies + (0);
+	      current_set_timeout (tl = jiffies + (0));
 	    else
 	      tl = 0xffffffff;
 	    midi_sleep_flag[dev].mode = WK_SLEEP;
-	    interruptible_sleep_on (&midi_sleeper[dev]);
+	    module_interruptible_sleep_on (&midi_sleeper[dev]);
 	    if (!(midi_sleep_flag[dev].mode & WK_WAKEUP))
 	      {
 		if (jiffies >= tl)
@@ -377,7 +378,7 @@
 	      }
 	    midi_sleep_flag[dev].mode &= ~WK_SLEEP;
 	  };
-	  if ((current->signal & ~current->blocked))
+	  if (current_got_fatal_signal ())
 	    {
 	      restore_flags (flags);
 	      return -EINTR;
@@ -424,11 +425,11 @@
 	unsigned long   tl;
 
 	if (parms[dev].prech_timeout)
-	  current->timeout = tl = jiffies + (parms[dev].prech_timeout);
+	  current_set_timeout (tl = jiffies + (parms[dev].prech_timeout));
 	else
 	  tl = 0xffffffff;
 	input_sleep_flag[dev].mode = WK_SLEEP;
-	interruptible_sleep_on (&input_sleeper[dev]);
+	module_interruptible_sleep_on (&input_sleeper[dev]);
 	if (!(input_sleep_flag[dev].mode & WK_WAKEUP))
 	  {
 	    if (jiffies >= tl)
@@ -436,7 +437,7 @@
 	  }
 	input_sleep_flag[dev].mode &= ~WK_SLEEP;
       };
-      if ((current->signal & ~current->blocked))
+      if (current_got_fatal_signal ())
 	c = -EINTR;		/*
 				   * The user is getting restless
 				 */
@@ -501,7 +502,7 @@
 }
 
 int
-MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
 {
   dev = dev >> 4;
 
@@ -511,7 +512,7 @@
       if (!DATA_AVAIL (midi_in_buf[dev]))
 	{
 	  input_sleep_flag[dev].mode = WK_SLEEP;
-	  select_wait (&input_sleeper[dev], wait);
+	  module_select_wait (&input_sleeper[dev], wait);
 	  return 0;
 	}
       return 1;
@@ -521,7 +522,7 @@
       if (SPACE_AVAIL (midi_out_buf[dev]))
 	{
 	  midi_sleep_flag[dev].mode = WK_SLEEP;
-	  select_wait (&midi_sleeper[dev], wait);
+	  module_select_wait (&midi_sleeper[dev], wait);
 	  return 0;
 	}
       return 1;
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c
--- v1.3.57/linux/drivers/sound/mpu401.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/mpu401.c	Tue Jan  9 00:37:25 1996
@@ -35,14 +35,12 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
 #include "coproc.h"
 
 static int      init_sequence[20];	/* NOTE! pos 0 = len, start pos 1. */
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
 static int      timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
 
 #endif
@@ -122,7 +120,7 @@
 static void     timer_ext_event (struct mpu_config *devc, int event, int parm);
 
 static struct synth_info mpu_synth_info_proto =
-{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
 
 static struct synth_info mpu_synth_info[MAX_MIDI_DEV];
 
@@ -153,7 +151,7 @@
   0				/* Fx */
 };
 
-#ifdef EXCLUDE_SEQUENCER
+#ifndef CONFIG_SEQUENCER
 #define STORE(cmd)
 #else
 #define STORE(cmd) \
@@ -576,11 +574,11 @@
   devc = &dev_conf[dev];
 
   /*
-   * Sometimes it takes about 13000 loops before the output becomes ready
+   * Sometimes it takes about 30000 loops before the output becomes ready
    * (After reset). Normally it takes just about 10 loops.
    */
 
-  for (timeout = 3000; timeout > 0 && !output_ready (devc); timeout--);
+  for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--);
 
   save_flags (flags);
   cli ();
@@ -919,6 +917,7 @@
     {
       mpu_cmd (midi_dev, 0x8B, 0);	/* Enable data in stop mode */
       mpu_cmd (midi_dev, 0x34, 0);	/* Return timing bytes in stop mode */
+      mpu_cmd (midi_dev, 0x87, 0);	/* Enable pitch & controller */
     }
 
   return 0;
@@ -1129,9 +1128,6 @@
 	MPU_CAP_CLS | MPU_CAP_2PORT;
 
       revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
-      printk (" <MQX-%d%c MIDI Interface>",
-	      ports,
-	      revision_char);
       sprintf (mpu_synth_info[num_midis].name,
 	       "MQX-%d%c MIDI Interface #%d",
 	       ports,
@@ -1147,10 +1143,6 @@
 
       devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
 
-      printk (" <MPU-401 MIDI Interface %d.%d%c>",
-	      (int) (devc->version & 0xf0) >> 4,
-	      devc->version & 0x0f,
-	      revision_char);
       sprintf (mpu_synth_info[num_midis].name,
 	       "MPU-401 %d.%d%c Midi interface #%d",
 	       (int) (devc->version & 0xf0) >> 4,
@@ -1162,6 +1154,8 @@
   strcpy (mpu401_midi_operations[num_midis].info.name,
 	  mpu_synth_info[num_midis].name);
 
+  conf_printf (mpu_synth_info[num_midis].name, hw_config);
+
   mpu401_synth_operations[num_midis]->midi_dev = devc->devno = num_midis;
   mpu401_synth_operations[devc->devno]->info =
     &mpu_synth_info[devc->devno];
@@ -1273,7 +1267,7 @@
   tmp_devc.opened = 0;
   tmp_devc.osp = hw_config->osp;
 
-#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MPU401)
+#if defined(CONFIG_AEDSP16) && defined(AEDSP16_MPU401)
   /*
      * Initialize Audio Excel DSP 16 to MPU-401, before any operation.
    */
@@ -1311,7 +1305,7 @@
  *      Timer stuff
  ****************************************************/
 
-#if !defined(EXCLUDE_SEQUENCER)
+#if defined(CONFIG_SEQUENCER)
 
 static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0;
 static volatile int curr_tempo, curr_timebase, hw_timebase;
@@ -1827,7 +1821,5 @@
 #endif
 
 
-
-#endif
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v1.3.57/linux/drivers/sound/opl3.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/opl3.c	Tue Jan  9 00:37:27 1996
@@ -36,7 +36,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812)
+#if defined(CONFIG_YM3812)
 
 #include "opl3.h"
 
@@ -226,7 +226,7 @@
    */
 
   for (i = 0; i < 50; i++)
-    tenmicrosec ();
+    tenmicrosec (devc->osp);
 
   stat2 = inb (ioaddr);		/*
 				   * Read status after timers have expired
@@ -281,18 +281,18 @@
 	  int             tmp;
 
 	  outb (0x02, ioaddr - 8);	/* Select OPL4 ID register */
-	  tenmicrosec ();
+	  tenmicrosec (devc->osp);
 	  tmp = inb (ioaddr - 7);	/* Read it */
-	  tenmicrosec ();
+	  tenmicrosec (devc->osp);
 
 	  if (tmp == 0x20)	/* OPL4 should return 0x20 here */
 	    {
 	      detected_model = 4;
 
 	      outb (0xF8, ioaddr - 8);	/* Select OPL4 FM mixer control */
-	      tenmicrosec ();
+	      tenmicrosec (devc->osp);
 	      outb (0x1B, ioaddr - 7);	/* Write value */
-	      tenmicrosec ();
+	      tenmicrosec (devc->osp);
 	    }
 	  else
 	    detected_model = 3;
@@ -775,7 +775,7 @@
   outb ((unsigned char) (addr & 0xff), io_addr);
 
   if (!devc->model != 2)
-    tenmicrosec ();
+    tenmicrosec (devc->osp);
   else
     for (i = 0; i < 2; i++)
       inb (io_addr);
@@ -784,9 +784,9 @@
 
   if (devc->model != 2)
     {
-      tenmicrosec ();
-      tenmicrosec ();
-      tenmicrosec ();
+      tenmicrosec (devc->osp);
+      tenmicrosec (devc->osp);
+      tenmicrosec (devc->osp);
     }
   else
     for (i = 0; i < 2; i++)
@@ -1222,9 +1222,9 @@
   if (devc->model == 2)
     {
       if (devc->is_opl4)
-	printk (" <Yamaha OPL4/OPL3 FM>");
+	conf_printf2 ("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1);
       else
-	printk (" <Yamaha OPL-3 FM>");
+	conf_printf2 ("Yamaha OPL3 FM", ioaddr, 0, -1, -1);
 
       devc->v_alloc->max_voice = devc->nr_voice = 18;
       devc->fm_info.nr_drums = 0;
@@ -1242,7 +1242,7 @@
     }
   else
     {
-      printk (" <Yamaha 2-OP FM>");
+      conf_printf2 ("Yamaha OPL2 FM", ioaddr, 0, -1, -1);
       devc->v_alloc->max_voice = devc->nr_voice = 9;
       devc->fm_info.nr_drums = 0;
 
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v1.3.57/linux/drivers/sound/os.h	Sat Nov 11 17:41:33 1995
+++ linux/drivers/sound/os.h	Tue Jan  9 00:36:59 1996
@@ -1,7 +1,18 @@
+
 #define ALLOW_SELECT
-#undef ALLOW_BUFFER_MAPPING
 #undef NO_INLINE_ASM
-#undef SHORT_BANNERS
+#define SHORT_BANNERS
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#endif
 
 #include <linux/param.h>
 #include <linux/types.h>
@@ -22,6 +33,7 @@
 #include <linux/string.h>
 #include <linux/ioport.h>
 
+#include <linux/wrapper.h>
 
 #include <linux/soundcard.h>
 
@@ -46,3 +58,5 @@
 extern int sound_num_blocks;
 
 typedef int sound_os_info;
+
+#undef PSEUDO_DMA_AUTOINIT
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v1.3.57/linux/drivers/sound/pas2_card.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/pas2_card.c	Tue Jan  9 00:37:28 1996
@@ -30,7 +30,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
+#if defined(CONFIG_PAS)
 
 #define DEFINE_TRANSLATIONS
 #include "pas.h"
@@ -93,14 +93,14 @@
 
   if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
     {
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
       pas_pcm_interrupt (status, 1);
 #endif
       status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ;
     }
   if (status & I_S_MIDI_IRQ)
     {
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
       pas_midi_interrupt ();
 #endif
       status &= ~I_S_MIDI_IRQ;
@@ -259,7 +259,7 @@
   mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
   mix_write (5, PARALLEL_MIXER);
 
-#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
+#if defined(CONFIG_SB_EMULATION) && defined(CONFIG_SB)
 
   {
     struct address_info *sb_config;
@@ -369,17 +369,22 @@
 
       if ((pas_model = pas_read (CHIP_REV)))
 	{
-	  printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
+	  char            temp[100];
+
+	  sprintf (temp,
+		   "%s rev %d", pas_model_names[(int) pas_model],
+		   pas_read (BOARD_REV_ID));
+	  conf_printf (temp, hw_config);
 	}
 
       if (config_pas_hw (hw_config))
 	{
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
 	  mem_start = pas_pcm_init (mem_start, hw_config);
 #endif
 
-#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
+#if defined(CONFIG_SB_EMULATION) && defined(CONFIG_SB)
 
 	  sb_dsp_disable_midi ();	/*
 					 * The SB emulation don't support *
@@ -388,7 +393,7 @@
 #endif
 
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
 	  mem_start = pas_midi_init (mem_start);
 #endif
 
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c
--- v1.3.57/linux/drivers/sound/pas2_midi.c	Fri Oct 13 14:44:34 1995
+++ linux/drivers/sound/pas2_midi.c	Tue Jan  9 00:37:28 1996
@@ -29,11 +29,9 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
 #include "pas.h"
 
-#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_PAS) && defined(CONFIG_MIDI)
 
 static int      midi_busy = 0, input_opened = 0;
 static int      my_dev;
@@ -335,7 +333,5 @@
 					   * Acknowledge interrupts
 					 */
 }
-
-#endif
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c
--- v1.3.57/linux/drivers/sound/pas2_mixer.c	Fri Oct 13 14:44:34 1995
+++ linux/drivers/sound/pas2_mixer.c	Tue Jan  9 00:37:29 1996
@@ -31,7 +31,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
+#if defined(CONFIG_PAS)
 
 #include "pas.h"
 
@@ -264,7 +264,7 @@
 
   if (((cmd >> 8) & 0xff) == 'M')
     {
-      if (cmd & IOC_IN)
+      if (_IOC_DIR (cmd) & _IOC_WRITE)
 	return snd_ioctl_return ((int *) arg, pas_mixer_set (cmd & 0xff, get_fs_long ((long *) arg)));
       else
 	{			/*
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c
--- v1.3.57/linux/drivers/sound/pas2_pcm.c	Fri Oct 13 14:44:34 1995
+++ linux/drivers/sound/pas2_pcm.c	Tue Jan  9 00:37:29 1996
@@ -30,11 +30,9 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
 #include "pas.h"
 
-#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO)
+#if defined(CONFIG_PAS) && defined(CONFIG_AUDIO)
 
 #define TRACE(WHAT)		/*
 				   * * * (WHAT)   */
@@ -444,7 +442,5 @@
 	}
     }
 }
-
-#endif
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c
--- v1.3.57/linux/drivers/sound/patmgr.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/patmgr.c	Tue Jan  9 00:37:30 1996
@@ -30,9 +30,9 @@
 #define PATMGR_C
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SEQUENCER)
+#if defined(CONFIG_SEQUENCER)
 
-static struct wait_queue *server_procs[MAX_SYNTH_DEV] =
+static wait_handle *server_procs[MAX_SYNTH_DEV] =
 {NULL};
 static volatile struct snd_wait server_wait_flag[MAX_SYNTH_DEV] =
 {
@@ -49,7 +49,7 @@
 #define A_TO_S	1
 #define S_TO_A 	2
 
-static struct wait_queue *appl_proc = NULL;
+static wait_handle *appl_proc = NULL;
 static volatile struct snd_wait appl_wait_flag =
 {0};
 
@@ -83,7 +83,7 @@
       if ((appl_wait_flag.mode & WK_SLEEP))
 	{
 	  appl_wait_flag.mode = WK_WAKEUP;
-	  wake_up (&appl_proc);
+	  module_wake_up (&appl_proc);
 	};
     }
 
@@ -102,31 +102,18 @@
       return -EIO;
     }
 
-  while (!ok && !(current->signal & ~current->blocked))
+  while (!ok && !current_got_fatal_signal ())
     {
       save_flags (flags);
       cli ();
 
       while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
-	     !(current->signal & ~current->blocked))
+	     !current_got_fatal_signal ())
 	{
 
-	  {
-	    unsigned long   tl;
-
-	    if (0)
-	      current->timeout = tl = jiffies + (0);
-	    else
-	      tl = 0xffffffff;
-	    server_wait_flag[dev].mode = WK_SLEEP;
-	    interruptible_sleep_on (&server_procs[dev]);
-	    if (!(server_wait_flag[dev].mode & WK_WAKEUP))
-	      {
-		if (jiffies >= tl)
-		  server_wait_flag[dev].mode |= WK_TIMEOUT;
-	      }
-	    server_wait_flag[dev].mode &= ~WK_SLEEP;
-	  };
+	  server_wait_flag[dev].mode = WK_SLEEP;
+	  module_interruptible_sleep_on (&server_procs[dev]);
+	  server_wait_flag[dev].mode &= ~WK_SLEEP;;
 	}
 
       if (mbox[dev] && msg_direction[dev] == A_TO_S)
@@ -193,7 +180,7 @@
 	{
 	  {
 	    appl_wait_flag.mode = WK_WAKEUP;
-	    wake_up (&appl_proc);
+	    module_wake_up (&appl_proc);
 	  };
 	}
     }
@@ -224,27 +211,14 @@
 	{
 	  {
 	    server_wait_flag[dev].mode = WK_WAKEUP;
-	    wake_up (&server_procs[dev]);
+	    module_wake_up (&server_procs[dev]);
 	  };
 	}
 
 
-      {
-	unsigned long   tl;
-
-	if (0)
-	  current->timeout = tl = jiffies + (0);
-	else
-	  tl = 0xffffffff;
-	appl_wait_flag.mode = WK_SLEEP;
-	interruptible_sleep_on (&appl_proc);
-	if (!(appl_wait_flag.mode & WK_WAKEUP))
-	  {
-	    if (jiffies >= tl)
-	      appl_wait_flag.mode |= WK_TIMEOUT;
-	  }
-	appl_wait_flag.mode &= ~WK_SLEEP;
-      };
+      appl_wait_flag.mode = WK_SLEEP;
+      module_interruptible_sleep_on (&appl_proc);
+      appl_wait_flag.mode &= ~WK_SLEEP;;
 
       if (msg_direction[dev] != S_TO_A)
 	{
@@ -274,9 +248,19 @@
   unsigned long   flags;
   int             err = 0;
 
+  struct patmgr_info *tmp_mbox;
+
   if (!pmgr_opened[dev])
     return 0;
 
+  tmp_mbox = (struct patmgr_info *) kmalloc (sizeof (struct patmgr_info), GFP_KERNEL);
+
+  if (tmp_mbox == NULL)
+    {
+      printk ("pmgr: Couldn't allocate memory for a message\n");
+      return 0;
+    }
+
   save_flags (flags);
   cli ();
 
@@ -284,13 +268,8 @@
     printk ("  PATMGR: Server %d mbox full. Why?\n", dev);
   else
     {
-      if ((mbox[dev] =
-	   (struct patmgr_info *) kmalloc (sizeof (struct patmgr_info), GFP_KERNEL)) == NULL)
-	{
-	  printk ("pmgr: Couldn't allocate memory for a message\n");
-	  return 0;
-	}
 
+      mbox[dev] = tmp_mbox;
       mbox[dev]->key = PM_K_EVENT;
       mbox[dev]->command = event;
       mbox[dev]->parm1 = p1;
@@ -302,34 +281,20 @@
 	{
 	  {
 	    server_wait_flag[dev].mode = WK_WAKEUP;
-	    wake_up (&server_procs[dev]);
+	    module_wake_up (&server_procs[dev]);
 	  };
 	}
 
 
-      {
-	unsigned long   tl;
-
-	if (0)
-	  current->timeout = tl = jiffies + (0);
-	else
-	  tl = 0xffffffff;
-	appl_wait_flag.mode = WK_SLEEP;
-	interruptible_sleep_on (&appl_proc);
-	if (!(appl_wait_flag.mode & WK_WAKEUP))
-	  {
-	    if (jiffies >= tl)
-	      appl_wait_flag.mode |= WK_TIMEOUT;
-	  }
-	appl_wait_flag.mode &= ~WK_SLEEP;
-      };
-      if (mbox[dev])
-	kfree (mbox[dev]);
+      appl_wait_flag.mode = WK_SLEEP;
+      module_interruptible_sleep_on (&appl_proc);
+      appl_wait_flag.mode &= ~WK_SLEEP;;
       mbox[dev] = NULL;
       msg_direction[dev] = 0;
     }
 
   restore_flags (flags);
+  kfree (tmp_mbox);
 
   return err;
 }
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v1.3.57/linux/drivers/sound/pss.c	Mon Oct 23 18:02:16 1995
+++ linux/drivers/sound/pss.c	Tue Jan  9 00:37:31 1996
@@ -29,7 +29,7 @@
 
 #include "sound_config.h"
 
-#if defined (CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS) && !defined(EXCLUDE_AUDIO)
+#if defined(CONFIG_PSS) && defined(CONFIG_AUDIO)
 
 /*
  * PSS registers.
@@ -109,13 +109,6 @@
       return 0;
     }
 
-  if (irq != 3 && irq != 5 && irq != 7 && irq != 9 &&
-      irq != 10 && irq != 11 && irq != 12)
-    return 0;
-
-  if (dma != 5 && dma != 6 && dma != 7)
-    return 0;
-
   id = inw (REG (PSS_ID));
   if ((id >> 8) != 'E')
     {
@@ -329,6 +322,7 @@
 attach_pss (long mem_start, struct address_info *hw_config)
 {
   unsigned short  id;
+  char            tmp[100];
 
   devc->base = hw_config->io_base;
   devc->irq = hw_config->irq;
@@ -370,7 +364,8 @@
 #endif
 
   pss_initialized = 1;
-  printk (" <ECHO-PSS  Rev. %d>", id);
+  sprintf (tmp, "ECHO-PSS  Rev. %d", id);
+  conf_printf (tmp, hw_config);
 
   return mem_start;
 }
@@ -426,7 +421,7 @@
 	break;			/* No more input */
     }
 
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   return probe_mpu401 (hw_config);
 #else
   return 0
@@ -700,7 +695,7 @@
   int             prev_devs;
   long            ret;
 
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   prev_devs = num_midis;
   ret = attach_mpu401 (mem_start, hw_config);
 
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c
--- v1.3.57/linux/drivers/sound/sb16_dsp.c	Thu Nov  9 11:23:51 1995
+++ linux/drivers/sound/sb16_dsp.c	Tue Jan  9 00:37:32 1996
@@ -38,7 +38,7 @@
 #include "sb.h"
 #include "sb_mixer.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
+#if defined(CONFIG_SB) && defined(CONFIG_AUDIO)
 
 extern int      sbc_base;
 extern sound_os_info *sb_osp;
@@ -157,7 +157,7 @@
     {
     case SOUND_PCM_WRITE_RATE:
       if (local)
-	return dsp_set_speed ((long) arg);
+	return dsp_set_speed ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_speed (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_READ_RATE:
@@ -167,12 +167,12 @@
 
     case SNDCTL_DSP_STEREO:
       if (local)
-	return dsp_set_stereo ((long) arg);
+	return dsp_set_stereo ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_WRITE_CHANNELS:
       if (local)
-	return dsp_set_stereo ((long) arg - 1) + 1;
+	return dsp_set_stereo ((int) arg - 1) + 1;
       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1);
 
     case SOUND_PCM_READ_CHANNELS:
@@ -182,7 +182,7 @@
 
     case SNDCTL_DSP_SETFMT:
       if (local)
-	return dsp_set_bits ((long) arg);
+	return dsp_set_bits ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg)));
 
     case SOUND_PCM_READ_BITS:
@@ -260,9 +260,24 @@
   restore_flags (flags);
 }
 
+static unsigned long trg_buf;
+static int      trg_bytes;
+static int      trg_intrflag;
+static int      trg_restart;
+
 static void
 sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
 {
+  trg_buf = buf;
+  trg_bytes = count;
+  trg_intrflag = intrflag;
+  trg_restart = dma_restart;
+  irq_mode = IMODE_OUTPUT;
+}
+
+static void
+actually_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
   unsigned long   flags, cnt;
 
   cnt = count;
@@ -322,6 +337,16 @@
 static void
 sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
 {
+  trg_buf = buf;
+  trg_bytes = count;
+  trg_intrflag = intrflag;
+  trg_restart = dma_restart;
+  irq_mode = IMODE_INPUT;
+}
+
+static void
+actually_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
   unsigned long   flags, cnt;
 
   cnt = count;
@@ -415,7 +440,18 @@
   if (!bits)
     sb_dsp_command (0xd0);	/* Halt DMA */
   else if (bits & irq_mode)
-    sb_dsp_command (0xd4);	/* Continue DMA */
+    switch (irq_mode)
+      {
+      case IMODE_INPUT:
+	actually_start_input (my_dev, trg_buf, trg_bytes,
+			      trg_intrflag, trg_restart);
+	break;
+
+      case IMODE_OUTPUT:
+	actually_output_block (my_dev, trg_buf, trg_bytes,
+			       trg_intrflag, trg_restart);
+	break;
+      }
 }
 
 static void
@@ -491,7 +527,7 @@
 
   sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
 
-  printk (" <%s>", sb16_dsp_operations.name);
+  conf_printf (sb16_dsp_operations.name, hw_config);
 
   if (num_audiodevs < MAX_AUDIO_DEV)
     {
@@ -520,10 +556,18 @@
 sb16_dsp_detect (struct address_info *hw_config)
 {
   struct address_info *sb_config;
-  extern int      sbc_major;
+  extern int      sbc_major, Jazz16_detected;
+
+  extern void     Jazz16_set_dma16 (int dma);
 
   if (sb16_dsp_ok)
     return 1;			/* Can't drive two cards */
+
+  if (Jazz16_detected)
+    {
+      Jazz16_set_dma16 (hw_config->dma);
+      return 0;
+    }
 
   if (!(sb_config = sound_getconf (SNDCARD_SB)))
     {
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c
--- v1.3.57/linux/drivers/sound/sb16_midi.c	Fri Oct 13 14:44:43 1995
+++ linux/drivers/sound/sb16_midi.c	Tue Jan  9 00:37:33 1996
@@ -29,9 +29,7 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_SB) && defined(CONFIG_MIDI)
 
 #include "sb.h"
 
@@ -60,8 +58,12 @@
 static int      my_dev;
 extern int      sbc_base;
 
+extern int      Jazz16_detected;
+extern int      AudioDrive;
+
 static int      reset_sb16midi (void);
 static void     (*midi_input_intr) (int dev, unsigned char data);
+static volatile unsigned char input_byte;
 
 static void
 sb16midi_input_loop (void)
@@ -70,7 +72,9 @@
     {
       unsigned char   c = sb16midi_read ();
 
-      if (sb16midi_opened & OPEN_READ)
+      if (c == MPU_ACK)
+	input_byte = c;
+      else if (sb16midi_opened & OPEN_READ && midi_input_intr)
 	midi_input_intr (my_dev, c);
     }
 }
@@ -82,6 +86,13 @@
     sb16midi_input_loop ();
 }
 
+void
+sbmidiintr (int irq, struct pt_regs *dummy)
+{
+  if (input_avail ())
+    sb16midi_input_loop ();
+}
+
 static int
 sb16midi_open (int dev, int mode,
 	       void            (*input) (int dev, unsigned char data),
@@ -175,13 +186,13 @@
 				 */
 }
 
-#define MIDI_SYNTH_NAME	"SoundBlaster 16 Midi"
+#define MIDI_SYNTH_NAME	"SoundBlaster MPU"
 #define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
 #include "midi_synth.h"
 
 static struct midi_operations sb16midi_operations =
 {
-  {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI},
+  {"SoundBlaster MPU", 0, 0, SNDCARD_SB16MIDI},
   &std_midi_synth,
   {0},
   sb16midi_open,
@@ -196,7 +207,6 @@
   NULL
 };
 
-
 long
 attach_sb16midi (long mem_start, struct address_info *hw_config)
 {
@@ -206,18 +216,23 @@
   sb16midi_base = hw_config->io_base;
 
   if (!sb16midi_detected)
-    return -EIO;
+    return mem_start;
+
+  request_region (hw_config->io_base, 4, "SB MIDI");
 
   save_flags (flags);
   cli ();
   for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/*
 									 * Wait
 									 */
+  input_byte = 0;
   sb16midi_cmd (UART_MODE_ON);
 
   ok = 0;
   for (timeout = 50000; timeout > 0 && !ok; timeout--)
-    if (input_avail ())
+    if (input_byte == MPU_ACK)
+      ok = 1;
+    else if (input_avail ())
       if (sb16midi_read () == MPU_ACK)
 	ok = 1;
 
@@ -229,7 +244,7 @@
       return mem_start;
     }
 
-  printk (" <SoundBlaster MPU-401>");
+  conf_printf ("SoundBlaster MPU-401", hw_config);
 
   std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &sb16midi_operations;
@@ -239,23 +254,25 @@
 static int
 reset_sb16midi (void)
 {
-  unsigned long   flags;
   int             ok, timeout, n;
 
   /*
    * Send the RESET command. Try again if no success at the first time.
    */
 
+  if (inb (STATPORT) == 0xff)
+    return 0;
+
   ok = 0;
 
-  save_flags (flags);
-  cli ();
+  /*save_flags(flags);cli(); */
 
   for (n = 0; n < 2 && !ok; n++)
     {
       for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/*
 										 * Wait
 										 */
+      input_byte = 0;
       sb16midi_cmd (MPU_RESET);	/*
 				 * Send MPU-401 RESET Command
 				 */
@@ -266,7 +283,9 @@
        */
 
       for (timeout = 50000; timeout > 0 && !ok; timeout--)
-	if (input_avail ())
+	if (input_byte == MPU_ACK)	/* Interrupt */
+	  ok = 1;
+	else if (input_avail ())
 	  if (sb16midi_read () == MPU_ACK)
 	    ok = 1;
 
@@ -278,19 +297,28 @@
 				 * Flush input before enabling interrupts
 				 */
 
-  restore_flags (flags);
+  /* restore_flags(flags); */
 
   return ok;
 }
 
-
 int
 probe_sb16midi (struct address_info *hw_config)
 {
   int             ok = 0;
   extern int      sbc_major;
 
-  if (sbc_major < 4)
+  extern void     ess_midi_init (struct address_info *hw_config);
+  extern void     Jazz16_midi_init (struct address_info *hw_config);
+
+  if (check_region (hw_config->io_base, 4))
+    return 0;
+
+  if (AudioDrive)
+    ess_midi_init (hw_config);
+  else if (Jazz16_detected)
+    Jazz16_midi_init (hw_config);
+  else if (sbc_major < 4)
     return 0;			/* Not a SB16 */
 
   sb16midi_base = hw_config->io_base;
@@ -307,8 +335,7 @@
 void
 unload_sb16midi (struct address_info *hw_config)
 {
+  release_region (hw_config->io_base, 4);
 }
-
-#endif
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v1.3.57/linux/drivers/sound/sb_card.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/sb_card.c	Tue Jan  9 00:37:33 1996
@@ -32,18 +32,18 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
+#if defined(CONFIG_SB)
 
 #include "sb.h"
 
 long
 attach_sb_card (long mem_start, struct address_info *hw_config)
 {
-#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI)
   if (!sb_dsp_detect (hw_config))
     return mem_start;
   mem_start = sb_dsp_init (mem_start, hw_config);
-  request_region (hw_config->io_base, 16, "SB");
+  request_region (hw_config->io_base, 16, "SoundBlaster");
 #endif
 
   return mem_start;
@@ -59,7 +59,7 @@
       return 0;
     }
 
-#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_SBPRO)
+#if defined(CONFIG_AEDSP16) && defined(AEDSP16_SBPRO)
   /*
      * Initialize Audio Excel DSP 16 to SBPRO.
    */
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
--- v1.3.57/linux/drivers/sound/sb_dsp.c	Thu Nov  9 11:23:51 1995
+++ linux/drivers/sound/sb_dsp.c	Tue Jan  9 00:37:35 1996
@@ -35,23 +35,22 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
-
-#ifdef SM_WAVE
-#define JAZZ16
-#endif
+#if defined(CONFIG_SB)
 
 #include "sb.h"
 #include "sb_mixer.h"
 #undef SB_TEST_IRQ
 
 int             sbc_base = 0;
-static int      sbc_irq = 0;
+static int      sbc_irq = 0, sbc_dma;
 static int      open_mode = 0;	/* Read, write or both */
 int             Jazz16_detected = 0;
+int             AudioDrive = 0;	/* 1=ES1688 detected */
+static int      ess_mpu_irq = 0;
 int             sb_no_recording = 0;
 static int      dsp_count = 0;
 static int      trigger_bits;
+static int      mpu_base = 0, mpu_irq = 0;
 
 /*
  * The DSP channel can be used either for input or output. Variable
@@ -68,46 +67,32 @@
 				 * initialization  *  */
 static int      midi_disabled = 0;
 int             sb_dsp_highspeed = 0;
-int             sbc_major = 1, sbc_minor = 0;	/*
-
-
-						   * *  * * DSP version   */
+int             sbc_major = 1, sbc_minor = 0;
 static int      dsp_stereo = 0;
 static int      dsp_current_speed = DSP_DEFAULT_SPEED;
 static int      sb16 = 0;
 static int      irq_verified = 0;
 
 int             sb_midi_mode = NORMAL_MIDI;
-int             sb_midi_busy = 0;	/*
-
-
-					 * *  * * 1 if the process has output
-					 * to *  * MIDI   */
+int             sb_midi_busy = 0;
 int             sb_dsp_busy = 0;
 
-volatile int    sb_irq_mode = IMODE_NONE;	/*
-
-
-						 * *  * * IMODE_INPUT, *
-						 * IMODE_OUTPUT * * or *
-						 * IMODE_NONE   */
+volatile int    sb_irq_mode = IMODE_NONE;
 static volatile int irq_ok = 0;
 
 static int      dma8 = 1;
+static int      dsp_16bit = 0;
 
-#ifdef JAZZ16
 /* 16 bit support
  */
 
-static int      dsp_16bit = 0;
-static int      dma16 = 5;
+static int      dma16 = 1;
 
 static int      dsp_set_bits (int arg);
 static int      initialize_ProSonic16 (void);
 
 /* end of 16 bit support
  */
-#endif
 
 int             sb_duplex_midi = 0;
 static int      my_dev = 0;
@@ -116,11 +101,12 @@
 
 static int      dsp_speed (int);
 static int      dsp_set_stereo (int mode);
-int             sb_dsp_command (unsigned char val);
 static void     sb_dsp_reset (int dev);
 sound_os_info  *sb_osp = NULL;
 
-#if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
+static void     ess_init (void);
+
+#if defined(CONFIG_MIDI) || defined(CONFIG_AUDIO)
 
 /*
  * Common code for the midi and pcm functions
@@ -154,58 +140,83 @@
     }
 
   printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val);
-  printk ("IRQ conflict???\n");
   return 0;
 }
 
+static int
+ess_write (unsigned char reg, unsigned char data)
+{
+  /* Write a byte to an extended mode register of ES1688 */
+
+  if (!sb_dsp_command (reg))
+    return 0;
+
+  return sb_dsp_command (data);
+}
+
+static int
+ess_read (unsigned char reg)
+{
+/* Read a byte from an extended mode register of ES1688 */
+
+  int             i;
+
+  if (!sb_dsp_command (0xc0))	/* Read register command */
+    return -1;
+
+  if (!sb_dsp_command (reg))
+    return -1;
+
+  for (i = 1000; i; i--)
+    {
+      if (inb (DSP_DATA_AVAIL) & 0x80)
+	return inb (DSP_READ);
+    }
+
+  return -1;
+}
+
 void
 sbintr (int irq, struct pt_regs *dummy)
 {
   int             status;
 
-#ifndef EXCLUDE_SBPRO
-  if (sb16)
+  if (sb16 && !AudioDrive)
     {
       unsigned char   src = sb_getmixer (IRQ_STAT);	/* Interrupt source register */
 
-#ifndef EXCLUDE_SB16
       if (src & 3)
 	sb16_dsp_interrupt (irq);
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
       if (src & 4)
 	sb16midiintr (irq);	/*
 				 * SB MPU401 interrupt
 				 */
 #endif
 
-#endif
-
       if (!(src & 1))
 	return;			/*
 				 * Not a DSP interupt
 				 */
     }
-#endif
 
   status = inb (DSP_DATA_AVAIL);	/*
 					   * Clear interrupt
 					 */
-
   if (sb_intr_active)
     switch (sb_irq_mode)
       {
       case IMODE_OUTPUT:
-	sb_intr_active = 0;
+	if (!AudioDrive)
+	  sb_intr_active = 0;
 	DMAbuf_outputintr (my_dev, 1);
 	break;
 
       case IMODE_INPUT:
-	sb_intr_active = 0;
+	if (!AudioDrive)
+	  sb_intr_active = 0;
 	DMAbuf_inputintr (my_dev);
-	/*
-	 * A complete buffer has been input. Let's start new one
-	 */
 	break;
 
       case IMODE_INIT:
@@ -214,7 +225,7 @@
 	break;
 
       case IMODE_MIDI:
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
 	sb_midi_interrupt (irq);
 #endif
 	break;
@@ -240,24 +251,31 @@
 {
   int             loopc;
 
-  outb (1, DSP_RESET);
-  tenmicrosec ();
+  if (AudioDrive)
+    outb (3, DSP_RESET);	/* Reset FIFO too */
+  else
+    outb (1, DSP_RESET);
+
+  tenmicrosec (sb_osp);
   outb (0, DSP_RESET);
-  tenmicrosec ();
-  tenmicrosec ();
-  tenmicrosec ();
+  tenmicrosec (sb_osp);
+  tenmicrosec (sb_osp);
+  tenmicrosec (sb_osp);
 
   for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++);
 
   if (inb (DSP_READ) != 0xAA)
     return 0;			/* Sorry */
 
+  if (AudioDrive)
+    sb_dsp_command (0xc6);	/* Enable extended mode */
+
   return 1;
 }
 
 #endif
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
 
 static void
 dsp_speaker (char state)
@@ -269,12 +287,45 @@
 }
 
 static int
+ess_speed (int speed)
+{
+  int             rate;
+  unsigned char   bits = 0;
+
+  if (speed < 4000)
+    speed = 4000;
+  else if (speed > 48000)
+    speed = 48000;
+
+  if (speed > 22000)
+    {
+      bits = 0x80;
+      rate = 256 - (795500 + speed / 2) / speed;
+      speed = 795500 / (256 - rate);
+    }
+  else
+    {
+      rate = 128 - (397700 + speed / 2) / speed;
+      speed = 397700 / (128 - rate);
+    }
+
+  bits |= (unsigned char) rate;
+  ess_write (0xa1, bits);
+
+  dsp_current_speed = speed;
+  return speed;
+}
+
+static int
 dsp_speed (int speed)
 {
   unsigned char   tconst;
   unsigned long   flags;
   int             max_speed = 44100;
 
+  if (AudioDrive)
+    return ess_speed (speed);
+
   if (speed < 4000)
     speed = 4000;
 
@@ -306,7 +357,7 @@
   /*
    * Max. stereo speed is 22050
    */
-  if (dsp_stereo && speed > 22050 && Jazz16_detected == 0)
+  if (dsp_stereo && speed > 22050 && Jazz16_detected == 0 && AudioDrive == 0)
     speed = 22050;
 #endif
 
@@ -373,9 +424,6 @@
 {
   dsp_stereo = 0;
 
-#ifdef EXCLUDE_SBPRO
-  return 0;
-#else
   if (sbc_major < 3 || sb16)
     return 0;			/*
 				 * Sorry no stereo
@@ -389,14 +437,30 @@
 
   dsp_stereo = !!mode;
   return dsp_stereo;
-#endif
 }
 
+static unsigned long trg_buf;
+static int      trg_bytes;
+static int      trg_intrflag;
+static int      trg_restart;
+
 static void
-sb_dsp_output_block (int dev, unsigned long buf, int count,
+sb_dsp_output_block (int dev, unsigned long buf, int nr_bytes,
 		     int intrflag, int restart_dma)
 {
+  trg_buf = buf;
+  trg_bytes = nr_bytes;
+  trg_intrflag = intrflag;
+  trg_restart = restart_dma;
+  sb_irq_mode = IMODE_OUTPUT;
+}
+
+static void
+actually_output_block (int dev, unsigned long buf, int nr_bytes,
+		       int intrflag, int restart_dma)
+{
   unsigned long   flags;
+  int             count = nr_bytes;
 
   if (!sb_irq_mode)
     dsp_speaker (ON);
@@ -411,7 +475,17 @@
   dsp_count = count;
 
   sb_irq_mode = IMODE_OUTPUT;
-  if (sb_dsp_highspeed)
+
+  if (AudioDrive)
+    {
+      int             c = 0x10000 - count;	/* ES1688 increments the count */
+
+      ess_write (0xa4, (unsigned char) (c & 0xff));
+      ess_write (0xa5, (unsigned char) ((c >> 8) & 0xff));
+
+      ess_write (0xb8, ess_read (0xb8) | 0x01);		/* Go */
+    }
+  else if (sb_dsp_highspeed)
     {
       save_flags (flags);
       cli ();
@@ -451,6 +525,17 @@
 sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
 		    int restart_dma)
 {
+  trg_buf = buf;
+  trg_bytes = count;
+  trg_intrflag = intrflag;
+  trg_restart = restart_dma;
+  sb_irq_mode = IMODE_INPUT;
+}
+
+static void
+actually_start_input (int dev, unsigned long buf, int count, int intrflag,
+		      int restart_dma)
+{
   unsigned long   flags;
 
   if (sb_no_recording)
@@ -475,7 +560,17 @@
   dsp_count = count;
 
   sb_irq_mode = IMODE_INPUT;
-  if (sb_dsp_highspeed)
+
+  if (AudioDrive)
+    {
+      int             c = 0x10000 - count;	/* ES1688 increments the count */
+
+      ess_write (0xa4, (unsigned char) (c & 0xff));
+      ess_write (0xa5, (unsigned char) ((c >> 8) & 0xff));
+
+      ess_write (0xb8, ess_read (0xb8) | 0x01);		/* Go */
+    }
+  else if (sb_dsp_highspeed)
     {
       save_flags (flags);
       cli ();
@@ -515,13 +610,24 @@
 static void
 sb_dsp_trigger (int dev, int bits)
 {
-  if (bits == trigger_bits)
-    return;
 
   if (!bits)
     sb_dsp_command (0xd0);	/* Halt DMA */
   else if (bits & sb_irq_mode)
-    sb_dsp_command (0xd4);	/* Continue DMA */
+    {
+      switch (sb_irq_mode)
+	{
+	case IMODE_INPUT:
+	  actually_start_input (my_dev, trg_buf, trg_bytes,
+				trg_intrflag, trg_restart);
+	  break;
+
+	case IMODE_OUTPUT:
+	  actually_output_block (my_dev, trg_buf, trg_bytes,
+				 trg_intrflag, trg_restart);
+	  break;
+	}
+    }
 
   trigger_bits = bits;
 }
@@ -542,30 +648,61 @@
 				 * SB Pro
 				 */
     {
-#ifdef JAZZ16
-      /* Select correct dma channel
-         * for 16/8 bit acccess
-       */
-      audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8;
-      if (dsp_stereo)
-	sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
-      else
-	sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
-#else
-      /* 8 bit only cards use this
-       */
-      if (dsp_stereo)
-	sb_dsp_command (0xa8);
+      if (AudioDrive)
+	{
+
+	  /* ess_init(); */
+	  ess_write (0xb8, 0x0e);	/* Auto init DMA mode */
+	  ess_write (0xa8, (ess_read (0xa8) & ~0x04) |
+		     (2 - dsp_stereo));		/* Mono/stereo */
+	  ess_write (0xb9, 2);	/* Demand mode (2 bytes/xfer) */
+
+	  if (!dsp_stereo)
+	    {
+	      if (dsp_16bit == 0)
+		{		/* 8 bit mono */
+		  ess_write (0xb7, 0x51);
+		  ess_write (0xb7, 0xd0);
+		}
+	      else
+		{		/* 16 bit mono */
+		  ess_write (0xb7, 0x71);
+		  ess_write (0xb7, 0xf4);
+		}
+	    }
+	  else
+	    {			/* Stereo */
+	      if (!dsp_16bit)
+		{		/* 8 bit stereo */
+		  ess_write (0xb7, 0x51);
+		  ess_write (0xb7, 0x98);
+		}
+	      else
+		{		/* 16 bit stereo */
+		  ess_write (0xb7, 0x71);
+		  ess_write (0xb7, 0xbc);
+		}
+	    }
+
+	  ess_write (0xb1, (ess_read (0xb1) & 0x0f) | 0x50);
+	  ess_write (0xb2, (ess_read (0xb2) & 0x0f) | 0x50);
+	}
       else
-	sb_dsp_command (0xa0);
-#endif
-      dsp_speed (dsp_current_speed);	/*
-					 * Speed must be recalculated if
-					 * #channels * changes
-					 */
+	{			/* !AudioDrive */
+
+	  /* Select correct dma channel
+	     * for 16/8 bit acccess
+	   */
+	  audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8;
+	  if (dsp_stereo)
+	    sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
+	  else
+	    sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
+
+	  dsp_speed (dsp_current_speed);
+	}			/* !AudioDrive */
     }
   trigger_bits = 0;
-  sb_dsp_command (0xd0);	/* Halt DMA */
   return 0;
 }
 
@@ -573,34 +710,72 @@
 sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
 {
   dsp_cleanup ();
-  dsp_speaker (ON);
+  dsp_speaker (OFF);
 
-#ifndef EXCLUDE_SBPRO
-  if (sbc_major == 3)		/*
-				 * SB Pro
-				 */
+  if (sbc_major == 3)		/* SB Pro (at least ) */
     {
-#ifdef JAZZ16
-      /* 16 bit specific instructions
-       */
-      audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8;
-      if (Jazz16_detected != 2)	/* SM Wave */
-	sb_mixer_set_stereo (dsp_stereo);
-      if (dsp_stereo)
-	sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
+
+      if (AudioDrive)
+	{
+
+	  /* ess_init(); */
+	  ess_write (0xb8, 4);	/* Auto init DMA mode */
+	  ess_write (0xa8, ess_read (0xa8) |
+		     (2 - dsp_stereo));		/* Mono/stereo */
+	  ess_write (0xb9, 2);	/* Demand mode (2 bytes/xfer) */
+
+	  if (!dsp_stereo)
+	    {
+	      if (dsp_16bit == 0)
+		{		/* 8 bit mono */
+		  ess_write (0xb6, 0x80);
+		  ess_write (0xb7, 0x51);
+		  ess_write (0xb7, 0xd0);
+		}
+	      else
+		{		/* 16 bit mono */
+		  ess_write (0xb6, 0x00);
+		  ess_write (0xb7, 0x71);
+		  ess_write (0xb7, 0xf4);
+		}
+	    }
+	  else
+	    {			/* Stereo */
+	      if (!dsp_16bit)
+		{		/* 8 bit stereo */
+		  ess_write (0xb6, 0x80);
+		  ess_write (0xb7, 0x51);
+		  ess_write (0xb7, 0x98);
+		}
+	      else
+		{		/* 16 bit stereo */
+		  ess_write (0xb6, 0x00);
+		  ess_write (0xb7, 0x71);
+		  ess_write (0xb7, 0xbc);
+		}
+	    }
+
+	  ess_write (0xb1, (ess_read (0xb1) & 0x0f) | 0x50);
+	  ess_write (0xb2, (ess_read (0xb2) & 0x0f) | 0x50);
+	}
       else
-	sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
-#else
-      sb_mixer_set_stereo (dsp_stereo);
-#endif
-      dsp_speed (dsp_current_speed);	/*
-					 * Speed must be recalculated if
-					 * #channels * changes
-					 */
+	{			/* !AudioDrive */
+
+	  /* 16 bit specific instructions (Jazz16)
+	   */
+	  audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8;
+	  if (Jazz16_detected != 2)	/* SM Wave */
+	    sb_mixer_set_stereo (dsp_stereo);
+	  if (dsp_stereo)
+	    sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
+	  else
+	    sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
+	}			/* !AudioDrive */
+
     }
-#endif
+
   trigger_bits = 0;
-  sb_dsp_command (0xd0);	/* Halt DMA */
+  dsp_speaker (ON);
   return 0;
 }
 
@@ -653,11 +828,9 @@
 
   /* Allocate 8 bit dma
    */
-#ifdef JAZZ16
   audio_devs[my_dev]->dmachan1 = dma8;
-#endif
-#ifdef JAZZ16
-  /* Allocate 16 bit dma
+
+  /* Allocate 16 bit dma (jazz16)
    */
   if (Jazz16_detected != 0)
     if (dma16 != dma8)
@@ -669,7 +842,6 @@
 	    return -EBUSY;
 	  }
       }
-#endif
 
   sb_irq_mode = IMODE_NONE;
 
@@ -682,7 +854,6 @@
 static void
 sb_dsp_close (int dev)
 {
-#ifdef JAZZ16
   /* Release 16 bit dma channel
    */
   if (Jazz16_detected)
@@ -692,7 +863,6 @@
       if (dma16 != dma8)
 	sound_close_dma (dma16);
     }
-#endif
 
   /* DMAbuf_close_dma (dev); */
   sb_free_irq ();
@@ -704,14 +874,11 @@
   open_mode = 0;
 }
 
-#ifdef JAZZ16
-/* Function dsp_set_bits() only required for 16 bit cards
- */
 static int
 dsp_set_bits (int arg)
 {
   if (arg)
-    if (Jazz16_detected == 0)
+    if (Jazz16_detected == 0 && AudioDrive == 0)
       dsp_16bit = 0;
     else
       switch (arg)
@@ -725,11 +892,10 @@
 	default:
 	  dsp_16bit = 0;
 	}
+
   return dsp_16bit ? 16 : 8;
 }
 
-#endif /* ifdef JAZZ16 */
-
 static int
 sb_dsp_ioctl (int dev, unsigned int cmd, ioctl_arg arg, int local)
 {
@@ -737,7 +903,7 @@
     {
     case SOUND_PCM_WRITE_RATE:
       if (local)
-	return dsp_speed ((long) arg);
+	return dsp_speed ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_speed (get_fs_long ((long *) arg)));
       break;
 
@@ -749,7 +915,7 @@
 
     case SOUND_PCM_WRITE_CHANNELS:
       if (local)
-	return dsp_set_stereo ((long) arg - 1) + 1;
+	return dsp_set_stereo ((int) arg - 1) + 1;
       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1);
       break;
 
@@ -761,11 +927,10 @@
 
     case SNDCTL_DSP_STEREO:
       if (local)
-	return dsp_set_stereo ((long) arg);
+	return dsp_set_stereo ((int) arg);
       return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg)));
       break;
 
-#ifdef JAZZ16
       /* Word size specific cases here.
          * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS
        */
@@ -780,14 +945,6 @@
 	return dsp_16bit ? 16 : 8;
       return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8);
       break;
-#else
-    case SOUND_PCM_WRITE_BITS:
-    case SOUND_PCM_READ_BITS:
-      if (local)
-	return 8;
-      return snd_ioctl_return ((int *) arg, 8);	/* Only 8 bits/sample supported */
-      break;
-#endif /* ifdef JAZZ16  */
 
     case SOUND_PCM_WRITE_FILTER:
     case SOUND_PCM_READ_FILTER:
@@ -818,8 +975,6 @@
 #endif
 
 
-#ifdef JAZZ16
-
 /*
  * Initialization of a Media Vision ProSonic 16 Soundcard.
  * The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets
@@ -845,7 +1000,6 @@
   return 0xffff;
 }
 
-#ifdef SM_WAVE
 /*
  * Logitech Soundman Wave detection and initialization by Hannu Savolainen.
  *
@@ -914,7 +1068,7 @@
   outb ((control & 0xfe) | 2, mpu_base + 7);	/* xxxxxxx0 resets the mc */
 
   for (i = 0; i < 300; i++)	/* Wait at least 1ms */
-    tenmicrosec ();
+    tenmicrosec (sb_osp);
 
   outb (control & 0xfc, mpu_base + 7);	/* xxxxxx00 enables RAM */
 
@@ -923,7 +1077,7 @@
    */
   smw_putmem (mp_base, 0, 0x00);
   smw_putmem (mp_base, 1, 0xff);
-  tenmicrosec ();
+  tenmicrosec (sb_osp);
 
   if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff)
     {
@@ -995,8 +1149,6 @@
   return 1;
 }
 
-#endif
-
 static int
 initialize_ProSonic16 (void)
 {
@@ -1005,23 +1157,9 @@
   {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] =
   {0, 1, 0, 2, 0, 3, 0, 4};
 
-  struct address_info *mpu_config;
-
-  int             mpu_base, mpu_irq;
-
-  if ((mpu_config = sound_getconf (SNDCARD_MPU401)))
-    {
-      mpu_base = mpu_config->io_base;
-      mpu_irq = mpu_config->irq;
-    }
-  else
-    {
-      mpu_base = mpu_irq = 0;
-    }
-
   outb (0xAF, 0x201);		/* ProSonic/Jazz16 wakeup */
   for (x = 0; x < 1000; ++x)	/* wait 10 milliseconds */
-    tenmicrosec ();
+    tenmicrosec (sb_osp);
   outb (0x50, 0x201);
   outb ((sbc_base & 0x70) | ((mpu_base & 0x30) >> 4), 0x201);
 
@@ -1036,18 +1174,15 @@
 	return 1;
 
       if (sb_dsp_command (0xFB) &&	/* set DMA-channels and Interrupts */
-	  sb_dsp_command ((dma_translat[JAZZ_DMA16] << 4) | dma_translat[dma8]) &&
+	  sb_dsp_command ((dma_translat[dma16] << 4) | dma_translat[dma8]) &&
       sb_dsp_command ((int_translat[mpu_irq] << 4) | int_translat[sbc_irq]))
 	{
 	  Jazz16_detected = 1;
-	  if (mpu_base == 0)
-	    printk ("Jazz16: No MPU401 devices configured - MIDI port not initialized\n");
 
-#ifdef SM_WAVE
 	  if (mpu_base != 0)
 	    if (initialize_smw (mpu_base))
 	      Jazz16_detected = 2;
-#endif
+
 	  sb_dsp_disable_midi ();
 	}
 
@@ -1056,37 +1191,29 @@
   return 0;			/* No SB or ProSonic16 detected */
 }
 
-#endif /* ifdef JAZZ16  */
-
 int
 sb_dsp_detect (struct address_info *hw_config)
 {
   sbc_base = hw_config->io_base;
   sbc_irq = hw_config->irq;
+  sbc_dma = hw_config->dma;
   sb_osp = hw_config->osp;
 
   if (sb_dsp_ok)
     return 0;			/*
 				 * Already initialized
 				 */
-  dma8 = hw_config->dma;
-
-#ifdef JAZZ16
-  dma16 = JAZZ_DMA16;
+  dma8 = dma16 = hw_config->dma;
 
   if (!initialize_ProSonic16 ())
     return 0;
-#else
-  if (!sb_reset_dsp ())
-    return 0;
-#endif
 
   return 1;			/*
 				 * Detected
 				 */
 }
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
 static struct audio_operations sb_dsp_operations =
 {
   "SoundBlaster",
@@ -1111,16 +1238,154 @@
 
 #endif
 
+static void
+ess_init (void)			/* ESS1688 Initialization */
+{
+  unsigned char   cfg, irq_bits = 0, dma_bits = 0;
+
+  AudioDrive = 1;
+  midi_disabled = 1;
+
+  sb_reset_dsp ();		/* Turn on extended mode */
+
+/*
+ *    Set IRQ configuration register
+ */
+
+  cfg = 0x50;			/* Enable only DMA counter interrupt */
+
+  switch (sbc_irq)
+    {
+    case 2:
+    case 9:
+      irq_bits = 0;
+      break;
+
+    case 5:
+      irq_bits = 1;
+      break;
+
+    case 7:
+      irq_bits = 2;
+      break;
+
+    case 10:
+      irq_bits = 3;
+      break;
+
+    default:
+      irq_bits = 0;
+      cfg = 0x10;		/* Disable all interrupts */
+      printk ("\nESS1688: Invalid IRQ %d\n", sbc_irq);
+    }
+
+  if (!ess_write (0xb1, cfg | (irq_bits << 2)))
+    printk ("\nESS1688: Failed to write to IRQ config register\n");
+
+/*
+ *    Set DMA configuration register
+ */
+
+  cfg = 0x50;			/* Extended mode DMA ebable */
+
+  if (sbc_dma > 3 || sbc_dma < 0 || sbc_dma == 2)
+    {
+      dma_bits = 0;
+      cfg = 0x00;		/* Disable all DMA */
+      printk ("\nESS1688: Invalid DMA %d\n", sbc_dma);
+    }
+  else
+    {
+      if (sbc_dma == 3)
+	dma_bits = 3;
+      else
+	dma_bits = sbc_dma + 1;
+    }
+
+  if (!ess_write (0xb2, cfg | (dma_bits << 2)))
+    printk ("\nESS1688: Failed to write to DMA config register\n");
+
+/*
+ * Enable joystick and OPL3
+ */
+
+  cfg = sb_getmixer (0x40);
+  sb_setmixer (0x40, cfg | 0x03);
+}
+
+void
+ess_midi_init (struct address_info *hw_config)	/* called from sb16_midi.c */
+{
+  unsigned char   cfg, tmp;
+
+  cfg = sb_getmixer (0x40) & 0x03;
+
+  tmp = (hw_config->io_base & 0x0f0) >> 4;
+
+  if (tmp > 3)
+    {
+      sb_setmixer (0x40, cfg);
+      return;
+    }
+
+  cfg |= tmp << 3;
+
+  tmp = 1;			/* MPU enabled without interrupts */
+
+  switch (hw_config->irq)
+    {
+    case 9:
+      tmp = 0x4;
+      break;
+    case 5:
+      tmp = 0x5;
+      break;
+    case 7:
+      tmp = 0x6;
+      break;
+    case 10:
+      tmp = 0x7;
+      break;
+    }
+
+  cfg |= tmp << 5;
+
+  if (tmp != 1)
+    {
+      ess_mpu_irq = hw_config->irq;
+
+      if (snd_set_irq_handler (ess_mpu_irq, sbmidiintr, "ES1688 MIDI", sb_osp) < 0)
+	printk ("ES1688: Can't allocate IRQ%d\n", ess_mpu_irq);
+    }
+
+  sb_setmixer (0x40, cfg);
+}
+
+void
+Jazz16_midi_init (struct address_info *hw_config)
+{
+  mpu_base = hw_config->io_base;
+  mpu_irq = hw_config->irq;
+
+  initialize_ProSonic16 ();
+}
+
+void
+Jazz16_set_dma16 (int dma)
+{
+  dma16 = dma;
+
+  initialize_ProSonic16 ();
+}
+
 long
 sb_dsp_init (long mem_start, struct address_info *hw_config)
 {
   int             i;
+  int             ess_major = 0, ess_minor = 0;
 
-#ifndef EXCLUDE_SBPRO
   int             mixer_type = 0;
 
-#endif
-
   sb_osp = hw_config->osp;
   sbc_major = sbc_minor = 0;
   sb_dsp_command (0xe1);	/*
@@ -1158,7 +1423,6 @@
 
   if (sbc_major == 3 && sbc_minor == 1)
     {
-      int             ess_major = 0, ess_minor = 0;
 
 /*
  * Try to detect ESS chips.
@@ -1183,28 +1447,12 @@
 		}
 	    }
 	}
-
-      if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
-	printk ("Hmm... Could this be an ESS488 based card (rev %d)\n",
-		ess_minor & 0x0f);
-      else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
-	printk ("Hmm... Could this be an ESS688 based card (rev %d)\n",
-		ess_minor & 0x0f);
     }
 
   if (snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster", sb_osp) < 0)
     printk ("sb_dsp: Can't allocate IRQ\n");;
 
-#ifndef EXCLUDE_SBPRO
-  if (sbc_major >= 3)
-    mixer_type = sb_mixer_init (sbc_major);
-#else
-  if (sbc_major >= 3)
-    printk ("\n\n\n\nNOTE! SB Pro support is required with your soundcard!\n\n\n");
-#endif
-
-
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
   if (sbc_major >= 3)
     {
       if (Jazz16_detected)
@@ -1228,6 +1476,20 @@
 	{
 	  sprintf (sb_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
 	}
+      else if (ess_major != 0)
+	{
+	  if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
+	    sprintf (sb_dsp_operations.name, "ESS ES488 AudioDrive (rev %d)",
+		     ess_minor & 0x0f);
+	  else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
+	    {
+	      sprintf (sb_dsp_operations.name,
+		       "ESS ES1688 AudioDrive (rev %d)",
+		       ess_minor & 0x0f);
+	      sb_dsp_operations.format_mask |= AFMT_S16_LE;
+	      ess_init ();
+	    }
+	}
       else
 	{
 	  sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
@@ -1238,23 +1500,26 @@
       sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
     }
 
-  printk (" <%s>", sb_dsp_operations.name);
+  conf_printf (sb_dsp_operations.name, hw_config);
 
-#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
-  if (!sb16)			/*
-				 * There is a better driver for SB16
-				 */
-#endif
+  if (sbc_major >= 3)
+    mixer_type = sb_mixer_init (sbc_major);
+
+  if (!sb16)
     if (num_audiodevs < MAX_AUDIO_DEV)
       {
 	audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations;
+
+	if (AudioDrive)
+	  audio_devs[my_dev]->flags |= DMA_AUTOMODE;
+
 	audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
 	dma8 = audio_devs[my_dev]->dmachan1 = hw_config->dma;
 	audio_devs[my_dev]->dmachan2 = -1;
-	if (sound_alloc_dma (hw_config->dma, "soundblaster"))
+	if (sound_alloc_dma (hw_config->dma, "SoundBlaster"))
 	  printk ("sb_dsp.c: Can't allocate DMA channel\n");
-#ifdef JAZZ16
-	/* Allocate 16 bit dma
+
+	/* Allocate 16 bit dma (Jazz16)
 	 */
 	if (Jazz16_detected != 0)
 	  if (dma16 != dma8)
@@ -1264,15 +1529,14 @@
 		  printk ("Jazz16: Can't allocate 16 bit DMA channel\n");
 		}
 	    }
-#endif
       }
     else
       printk ("SB: Too many DSP devices available\n");
 #else
-  printk (" <SoundBlaster (configured without audio support)>");
+  conf_printf ("SoundBlaster (configured without audio support)", hw_config);
 #endif
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
   if (!midi_disabled && !sb16)	/*
 				 * Midi don't work in the SB emulation mode *
 				 * of PAS, SB16 has better midi interface
@@ -1288,16 +1552,20 @@
 sb_dsp_unload (void)
 {
   sound_free_dma (dma8);
-#ifdef JAZZ16
-  /* Allocate 16 bit dma
+
+  /* Free 16 bit dma (Jazz16)
    */
   if (Jazz16_detected != 0)
     if (dma16 != dma8)
       {
 	sound_free_dma (dma16);
       }
-#endif
   snd_release_irq (sbc_irq);
+
+  if (AudioDrive && ess_mpu_irq)
+    {
+      snd_release_irq (ess_mpu_irq);
+    }
 }
 
 void
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c
--- v1.3.57/linux/drivers/sound/sb_midi.c	Fri Oct 13 14:44:43 1995
+++ linux/drivers/sound/sb_midi.c	Tue Jan  9 00:37:35 1996
@@ -29,7 +29,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_SB) && defined(CONFIG_MIDI)
 
 #include "sb.h"
 #undef SB_TEST_IRQ
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v1.3.57/linux/drivers/sound/sb_mixer.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/sb_mixer.c	Tue Jan  9 00:37:36 1996
@@ -34,7 +34,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO)
+#if defined(CONFIG_SB)
 #define __SB_MIXER_C__
 
 #include "sb.h"
@@ -44,6 +44,7 @@
 extern int      sbc_base;
 extern int      Jazz16_detected;
 extern sound_os_info *sb_osp;
+extern int      AudioDrive;
 
 static int      mixer_initialized = 0;
 
@@ -64,9 +65,9 @@
   outb ((unsigned char) (port & 0xff), MIXER_ADDR);	/*
 							   * Select register
 							 */
-  tenmicrosec ();
+  tenmicrosec (sb_osp);
   outb ((unsigned char) (value & 0xff), MIXER_DATA);
-  tenmicrosec ();
+  tenmicrosec (sb_osp);
   restore_flags (flags);
 }
 
@@ -81,9 +82,9 @@
   outb ((unsigned char) (port & 0xff), MIXER_ADDR);	/*
 							   * Select register
 							 */
-  tenmicrosec ();
+  tenmicrosec (sb_osp);
   val = inb (MIXER_DATA);
-  tenmicrosec ();
+  tenmicrosec (sb_osp);
   restore_flags (flags);
 
   return val;
@@ -201,7 +202,6 @@
   return levels[dev];
 }
 
-#ifdef JAZZ16
 static char     smw_mix_regs[] =	/* Left mixer registers */
 {
   0x0b,				/* SOUND_MIXER_VOLUME */
@@ -293,8 +293,6 @@
   return left | (right << 8);
 }
 
-#endif
-
 static int
 sb_mixer_set (int dev, int value)
 {
@@ -304,10 +302,8 @@
   int             regoffs;
   unsigned char   val;
 
-#ifdef JAZZ16
   if (Jazz16_detected == 2)
     return smw_mixer_set (dev, value);
-#endif
 
   if (left > 100)
     left = 100;
@@ -449,7 +445,7 @@
 {
   if (((cmd >> 8) & 0xff) == 'M')
     {
-      if (cmd & IOC_IN)
+      if (_IOC_DIR (cmd) & _IOC_WRITE)
 	switch (cmd & 0xff)
 	  {
 	  case SOUND_MIXER_RECSRC:
@@ -539,8 +535,13 @@
     case 3:
       mixer_caps = SOUND_CAP_EXCL_INPUT;
 
-#ifdef JAZZ16
-      if (Jazz16_detected == 2)	/* SM Wave */
+      if (AudioDrive)
+	{
+	  supported_devices = ES688_MIXER_DEVICES;
+	  supported_rec_devices = ES688_RECORDING_DEVICES;
+	  iomap = &es688_mix;
+	}
+      else if (Jazz16_detected == 2)	/* SM Wave */
 	{
 	  supported_devices = 0;
 	  supported_rec_devices = 0;
@@ -549,7 +550,6 @@
 	  mixer_type = 1;
 	}
       else
-#endif
 #ifdef __SGNXPRO__
       if (mixer_type == 2)	/* A SGNXPRO was detected */
 	{
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h
--- v1.3.57/linux/drivers/sound/sb_mixer.h	Tue Jul 11 10:02:54 1995
+++ linux/drivers/sound/sb_mixer.h	Tue Jan  9 00:36:56 1996
@@ -50,6 +50,9 @@
 #define SB16_RECORDING_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
 					 SOUND_MASK_CD)
 
+#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
+#define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER)
+
 #define SB16_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
 					 SOUND_MASK_CD | \
 					 SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
@@ -131,6 +134,25 @@
 MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
 MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0)
 };
+mixer_tab es688_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,	0x32, 7, 4, 0x32, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,	0x36, 7, 4, 0x36, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,	0x14, 7, 4, 0x14, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,	0x3c, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,	0x3e, 7, 4, 0x3e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,	0x1a, 7, 4, 0x1a, 3, 4),
+MIX_ENT(SOUND_MIXER_CD,		0x38, 7, 4, 0x38, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_IGAIN,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE1,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE2,	0x3a, 7, 4, 0x3a, 3, 4),
+MIX_ENT(SOUND_MIXER_LINE3,	0x00, 0, 0, 0x00, 0, 0)
+};
 
 #ifdef	__SGNXPRO__
 mixer_tab sgnxpro_mix = {
@@ -187,7 +209,10 @@
   0x4b4b,			/* SB PCM */
   0x4b4b,			/* Recording level */
   0x4b4b,			/* Input gain */
-  0x4b4b};			/* Output gain */
+  0x4b4b,			/* Output gain */
+  0x4040,			/* Line1 */
+  0x4040,			/* Line2 */
+  0x1515			/* Line3 */
 
 #else  /* If the user selected just plain SB Pro */
 
@@ -206,7 +231,11 @@
   0x4b4b,			/* SB PCM */
   0x4b4b,			/* Recording level */
   0x4b4b,			/* Input gain */
-  0x4b4b};			/* Output gain */
+  0x4b4b,			/* Output gain */
+  0x4040,			/* Line1 */
+  0x4040,			/* Line2 */
+  0x1515			/* Line3 */
+};
 #endif /* SM_GAMES */
 
 static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v1.3.57/linux/drivers/sound/sequencer.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/sequencer.c	Tue Jan  9 00:37:39 1996
@@ -30,9 +30,7 @@
 #define SEQUENCER_C
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
 
 #include "midi_ctrl.h"
 
@@ -58,10 +56,10 @@
 #define SEQ_2	2
 static int      seq_mode = SEQ_1;
 
-static struct wait_queue *seq_sleeper = NULL;
+static wait_handle *seq_sleeper = NULL;
 static volatile struct snd_wait seq_sleep_flag =
 {0};
-static struct wait_queue *midi_sleeper = NULL;
+static wait_handle *midi_sleeper = NULL;
 static volatile struct snd_wait midi_sleep_flag =
 {0};
 
@@ -84,7 +82,7 @@
 static volatile int qhead = 0, qtail = 0, qlen = 0;
 static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
 static volatile int seq_playing = 0;
-static int      sequencer_busy = 0;
+static volatile int sequencer_busy = 0;
 static int      output_treshold;
 static int      pre_event_timeout;
 static unsigned synth_open_mask;
@@ -132,11 +130,11 @@
 	unsigned long   tl;
 
 	if (pre_event_timeout)
-	  current->timeout = tl = jiffies + (pre_event_timeout);
+	  current_set_timeout (tl = jiffies + (pre_event_timeout));
 	else
 	  tl = 0xffffffff;
 	midi_sleep_flag.mode = WK_SLEEP;
-	interruptible_sleep_on (&midi_sleeper);
+	module_interruptible_sleep_on (&midi_sleeper);
 	if (!(midi_sleep_flag.mode & WK_WAKEUP))
 	  {
 	    if (jiffies >= tl)
@@ -202,7 +200,7 @@
     {
       {
 	midi_sleep_flag.mode = WK_WAKEUP;
-	wake_up (&midi_sleeper);
+	module_wake_up (&midi_sleeper);
       };
     }
   restore_flags (flags);
@@ -276,9 +274,7 @@
   if (mode == OPEN_READ)
     return -EIO;
 
-  if (dev)			/*
-				 * Patch manager device
-				 */
+  if (dev)
     return pmgr_write (dev - 1, file, buf, count);
 
   c = count;
@@ -412,22 +408,9 @@
        * Sleep until there is enough space on the queue
        */
 
-      {
-	unsigned long   tl;
-
-	if (0)
-	  current->timeout = tl = jiffies + (0);
-	else
-	  tl = 0xffffffff;
-	seq_sleep_flag.mode = WK_SLEEP;
-	interruptible_sleep_on (&seq_sleeper);
-	if (!(seq_sleep_flag.mode & WK_WAKEUP))
-	  {
-	    if (jiffies >= tl)
-	      seq_sleep_flag.mode |= WK_TIMEOUT;
-	  }
-	seq_sleep_flag.mode &= ~WK_SLEEP;
-      };
+      seq_sleep_flag.mode = WK_SLEEP;
+      module_interruptible_sleep_on (&seq_sleeper);
+      seq_sleep_flag.mode &= ~WK_SLEEP;;
     }
 
   if (qlen >= SEQ_MAX_QUEUE)
@@ -729,7 +712,7 @@
 		{
 		  {
 		    seq_sleep_flag.mode = WK_WAKEUP;
-		    wake_up (&seq_sleeper);
+		    module_wake_up (&seq_sleeper);
 		  };
 		}
 	      restore_flags (flags);
@@ -769,7 +752,7 @@
 		{
 		  {
 		    seq_sleep_flag.mode = WK_WAKEUP;
-		    wake_up (&seq_sleeper);
+		    module_wake_up (&seq_sleeper);
 		  };
 		}
 	      restore_flags (flags);
@@ -819,7 +802,7 @@
   switch (cmd)
     {
     case LOCL_STARTAUDIO:
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
       DMAbuf_start_devices (parm);
 #endif
       break;
@@ -905,7 +888,7 @@
 		{
 		  {
 		    seq_sleep_flag.mode = WK_WAKEUP;
-		    wake_up (&seq_sleeper);
+		    module_wake_up (&seq_sleeper);
 		  };
 		}
 	      restore_flags (flags);
@@ -1041,7 +1024,7 @@
 	{
 	  {
 	    seq_sleep_flag.mode = WK_WAKEUP;
-	    wake_up (&seq_sleeper);
+	    module_wake_up (&seq_sleeper);
 	  };
 	}
       restore_flags (flags);
@@ -1095,6 +1078,7 @@
 {
   int             retval, mode, i;
   int             level, tmp;
+  unsigned long   flags;
 
   level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1;
 
@@ -1109,9 +1093,7 @@
       return -ENXIO;
     }
 
-  if (dev)			/*
-				 * Patch manager device
-				 */
+  if (dev)			/* Patch manager device */
     {
       int             err;
 
@@ -1125,19 +1107,22 @@
       if (pmgr_present[dev])
 	return -EBUSY;
       if ((err = pmgr_open (dev)) < 0)
-	return err;		/*
-				 * Failed
-				 */
+	return err;
 
       pmgr_present[dev] = 1;
       return err;
     }
 
+  save_flags (flags);
+  cli ();
   if (sequencer_busy)
     {
       printk ("Sequencer busy\n");
+      restore_flags (flags);
       return -EBUSY;
     }
+  sequencer_busy = 1;
+  restore_flags (flags);
 
   max_mididev = num_midis;
   max_synthdev = num_synths;
@@ -1173,6 +1158,7 @@
       if (tmr == NULL)
 	{
 	  printk ("sequencer: No timer for level 2\n");
+	  sequencer_busy = 0;
 	  return -ENXIO;
 	}
       setup_mode2 ();
@@ -1182,6 +1168,7 @@
     if (!max_mididev)
       {
 	printk ("Sequencer: No Midi devices. Input not possible\n");
+	sequencer_busy = 0;
 	return -ENXIO;
       }
 
@@ -1239,7 +1226,6 @@
       tmr->open (tmr_no, seq_mode);
     }
 
-  sequencer_busy = 1;
   seq_sleep_flag.mode = WK_NONE;
   midi_sleep_flag.mode = WK_NONE;
   output_treshold = SEQ_MAX_QUEUE / 2;
@@ -1262,7 +1248,7 @@
 
   n = 1;
 
-  while (!(current->signal & ~current->blocked) && n)
+  while (!current_got_fatal_signal () && n)
     {
       n = 0;
 
@@ -1282,11 +1268,11 @@
 	    unsigned long   tl;
 
 	    if (HZ / 10)
-	      current->timeout = tl = jiffies + (HZ / 10);
+	      current_set_timeout (tl = jiffies + (HZ / 10));
 	    else
 	      tl = 0xffffffff;
 	    seq_sleep_flag.mode = WK_SLEEP;
-	    interruptible_sleep_on (&seq_sleeper);
+	    module_interruptible_sleep_on (&seq_sleeper);
 	    if (!(seq_sleep_flag.mode & WK_WAKEUP))
 	      {
 		if (jiffies >= tl)
@@ -1324,7 +1310,7 @@
 
   if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ?
 			     1 : 0))
-    while (!(current->signal & ~current->blocked) && qlen)
+    while (!current_got_fatal_signal () && qlen)
       {
 	seq_sync ();
       }
@@ -1370,7 +1356,7 @@
 {
   unsigned long   flags;
 
-  if (qlen && !seq_playing && !(current->signal & ~current->blocked))
+  if (qlen && !seq_playing && !current_got_fatal_signal ())
     seq_startplay ();
 
   save_flags (flags);
@@ -1381,12 +1367,12 @@
       {
 	unsigned long   tl;
 
-	if (0)
-	  current->timeout = tl = jiffies + (0);
+	if (HZ)
+	  current_set_timeout (tl = jiffies + (HZ));
 	else
 	  tl = 0xffffffff;
 	seq_sleep_flag.mode = WK_SLEEP;
-	interruptible_sleep_on (&seq_sleeper);
+	module_interruptible_sleep_on (&seq_sleeper);
 	if (!(seq_sleep_flag.mode & WK_WAKEUP))
 	  {
 	    if (jiffies >= tl)
@@ -1427,11 +1413,11 @@
 	unsigned long   tl;
 
 	if (4)
-	  current->timeout = tl = jiffies + (4);
+	  current_set_timeout (tl = jiffies + (4));
 	else
 	  tl = 0xffffffff;
 	seq_sleep_flag.mode = WK_SLEEP;
-	interruptible_sleep_on (&seq_sleeper);
+	module_interruptible_sleep_on (&seq_sleeper);
 	if (!(seq_sleep_flag.mode & WK_WAKEUP))
 	  {
 	    if (jiffies >= tl)
@@ -1521,7 +1507,7 @@
       /*      printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */
       {
 	seq_sleep_flag.mode = WK_WAKEUP;
-	wake_up (&seq_sleeper);
+	module_wake_up (&seq_sleeper);
       };
     }
   restore_flags (flags);
@@ -1605,7 +1591,7 @@
 
       if (mode == OPEN_READ)
 	return 0;
-      while (qlen && !(current->signal & ~current->blocked))
+      while (qlen && !current_got_fatal_signal ())
 	seq_sync ();
       if (qlen)
 	return -EINTR;
@@ -1921,7 +1907,7 @@
 }
 
 int
-sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
 {
   unsigned long   flags;
 
@@ -1935,7 +1921,7 @@
       if (!iqlen)
 	{
 	  midi_sleep_flag.mode = WK_SLEEP;
-	  select_wait (&midi_sleeper, wait);
+	  module_select_wait (&midi_sleeper, wait);
 	  restore_flags (flags);
 	  return 0;
 	}
@@ -1947,10 +1933,10 @@
     case SEL_OUT:
       save_flags (flags);
       cli ();
-      if (qlen >= SEQ_MAX_QUEUE)
+      if ((SEQ_MAX_QUEUE - qlen) < output_treshold)
 	{
 	  seq_sleep_flag.mode = WK_SLEEP;
-	  select_wait (&seq_sleeper, wait);
+	  module_select_wait (&seq_sleeper, wait);
 	  restore_flags (flags);
 	  return 0;
 	}
@@ -2074,7 +2060,5 @@
 
   return mem_start;
 }
-
-#endif
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v1.3.57/linux/drivers/sound/sound_calls.h	Mon Oct 23 18:02:16 1995
+++ linux/drivers/sound/sound_calls.h	Tue Jan  9 00:36:57 1996
@@ -5,9 +5,11 @@
 int DMAbuf_open(int dev, int mode);
 int DMAbuf_release(int dev, int mode);
 int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock);
+int DMAbuf_get_curr_buffer(int dev, int *buff_no, char **dma_buf, int *buff_ptr, int *buff_size);
 int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock);
 int DMAbuf_rmchars(int dev, int buff_no, int c);
 int DMAbuf_start_output(int dev, int buff_no, int l);
+int DMAbuf_set_count(int dev, int buff_no, int l);
 int DMAbuf_ioctl(int dev, unsigned int cmd, ioctl_arg arg, int local);
 long DMAbuf_init(long mem_start);
 int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
@@ -16,7 +18,7 @@
 void DMAbuf_reset_dma (int dev);
 void DMAbuf_inputintr(int dev);
 void DMAbuf_outputintr(int dev, int underflow_flag);
-int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
 void DMAbuf_start_devices(unsigned int devmask);
 
 /*
@@ -32,7 +34,7 @@
 int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
 long audio_init (long mem_start);
 
-int audio_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+int audio_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
 
 /*
  *	System calls for the /dev/sequencer
@@ -52,7 +54,7 @@
 void seq_input_event(unsigned char *event, int len);
 void seq_copy_to_input (unsigned char *event, int len);
 
-int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
 
 /*
  *	System calls for the /dev/midi
@@ -68,7 +70,7 @@
 void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
 long MIDIbuf_init(long mem_start);
 
-int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
 
 /*
  *
@@ -77,7 +79,7 @@
 
 /*	From soundcard.c	*/
 void soundcard_init(void);
-void tenmicrosec(void);
+void tenmicrosec(sound_os_info *osp);
 void request_sound_timer (int count);
 void sound_stop_timer(void);
 int snd_ioctl_return(int *addr, int value);
@@ -85,6 +87,8 @@
 void snd_release_irq(int vect);
 void sound_dma_malloc(int dev);
 void sound_dma_free(int dev);
+void conf_printf(char *name, struct address_info *hw_config);
+void conf_printf2(char *name, int base, int irq, int dma, int dma2);
 
 /*	From sound_switch.c	*/
 int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
@@ -114,6 +118,7 @@
 long attach_sb16midi(long mem_start, struct address_info * hw_config);
 int probe_sb16midi(struct address_info *hw_config);
 void sb_midi_interrupt(int dummy);
+void sbmidiintr(int irq, struct pt_regs * dummy);
 
 /*	From sb_midi.c	*/
 void sb_midi_init(int model);
@@ -268,6 +273,7 @@
 int probe_mad16_mpu (struct address_info *hw_config);
 int mad16_sb_dsp_detect (struct address_info *hw_config);
 long mad16_sb_dsp_init (long mem_start, struct address_info *hw_config);
+void mad16_sb_dsp_unload(struct address_info *hw_config);
 
 /*	Unload routines from various source files*/
 void unload_pss(struct address_info *hw_info);
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h
--- v1.3.57/linux/drivers/sound/sound_config.h	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/sound_config.h	Tue Jan  9 00:36:57 1996
@@ -28,18 +28,8 @@
  *
  */
 
-#undef CONFIGURE_SOUNDCARD
-#undef DYNAMIC_BUFFER
-
-#include "local.h"
-
-#ifdef KERNEL_SOUNDCARD
-#define CONFIGURE_SOUNDCARD
-#define DYNAMIC_BUFFER
-#undef LOADABLE_SOUNDCARD
-#endif
-
 #include "os.h"
+#include "local.h"
 #include "soundvers.h"
 
 #if defined(ISC) || defined(SCO) || defined(SVR42)
@@ -51,13 +41,10 @@
 
 
 
-
 #ifndef SND_DEFAULT_ENABLE
 #define SND_DEFAULT_ENABLE	1
 #endif
 
-#ifdef CONFIGURE_SOUNDCARD
-
 #ifndef MAX_REALTIME_FACTOR
 #define MAX_REALTIME_FACTOR	4
 #endif
@@ -89,10 +76,16 @@
 #define PAS_BASE	0x388
 #endif
 
-#ifdef JAZZ16
-#ifndef JAZZ_DMA16
-#define JAZZ_DMA16	5
+#if defined(SB16_DMA) && !defined(SB_DMA2)
+#  define SB_DMA2 SB16_DMA
+#endif
+
+#if defined(SB16MIDI_BASE) && !defined(SB_MPU_BASE)
+#   define SB_MPU_BASE SB16MIDI_BASE
 #endif
+
+#ifndef SB_MPU_IRQ
+#  define SB_MPU_IRQ SBC_IRQ
 #endif
 
 /* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
@@ -198,5 +191,3 @@
 
 #define TIMER_ARMED	121234
 #define TIMER_NOT_ARMED	1
-
-#endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sound_pnp.c linux/drivers/sound/sound_pnp.c
--- v1.3.57/linux/drivers/sound/sound_pnp.c	Wed Nov  8 07:11:36 1995
+++ linux/drivers/sound/sound_pnp.c	Tue Jan  9 00:37:39 1996
@@ -28,7 +28,7 @@
  */
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PNP)
+#if defined(CONFIG_PNP)
 
 #include <linux/pnp.h>
 
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c
--- v1.3.57/linux/drivers/sound/sound_switch.c	Wed Nov  8 07:11:37 1995
+++ linux/drivers/sound/sound_switch.c	Tue Jan  9 00:37:40 1996
@@ -29,17 +29,11 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
 struct sbc_device
   {
     int             usecount;
   };
 
-static struct sbc_device sbc_devices[SND_NDEVS] =
-{
-  {0}};
-
 static int      in_use = 0;	/*
 
 
@@ -210,7 +204,7 @@
       return;
     }
 
-#ifdef EXCLUDE_AUDIO
+#ifndef CONFIG_AUDIO
   if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n"))
     return;
 #else
@@ -235,7 +229,7 @@
     }
 #endif
 
-#ifdef EXCLUDE_SEQUENCER
+#ifndef CONFIG_SEQUENCER
   if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n"))
     return;
 #else
@@ -255,7 +249,7 @@
     }
 #endif
 
-#ifdef EXCLUDE_MIDI
+#ifndef CONFIG_MIDI
   if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n"))
     return;
 #else
@@ -339,7 +333,7 @@
       return read_status (buf, count);
       break;
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -347,14 +341,14 @@
       break;
 #endif
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
     case SND_DEV_SEQ:
     case SND_DEV_SEQ2:
       return sequencer_read (dev, file, buf, count);
       break;
 #endif
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_read (dev, file, buf, count);
 #endif
@@ -375,14 +369,14 @@
   switch (dev & 0x0f)
     {
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
     case SND_DEV_SEQ:
     case SND_DEV_SEQ2:
       return sequencer_write (dev, file, buf, count);
       break;
 #endif
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -390,7 +384,7 @@
       break;
 #endif
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_write (dev, file, buf, count);
 #endif
@@ -407,7 +401,7 @@
 {
   int             retval;
 
-  DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
+  DEB (printk ("sound_open_sw(dev=%d)\n", dev));
 
   if ((dev >= SND_NDEVS) || (dev < 0))
     {
@@ -431,7 +425,7 @@
       return 0;
       break;
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
     case SND_DEV_SEQ:
     case SND_DEV_SEQ2:
       if ((retval = sequencer_open (dev, file)) < 0)
@@ -439,14 +433,14 @@
       break;
 #endif
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
     case SND_DEV_MIDIN:
       if ((retval = MIDIbuf_open (dev, file)) < 0)
 	return retval;
       break;
 #endif
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -460,7 +454,6 @@
       return -ENXIO;
     }
 
-  sbc_devices[dev].usecount++;
   in_use++;
 
   return 0;
@@ -484,20 +477,20 @@
     case SND_DEV_CTL:
       break;
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
     case SND_DEV_SEQ:
     case SND_DEV_SEQ2:
       sequencer_release (dev, file);
       break;
 #endif
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
     case SND_DEV_MIDIN:
       MIDIbuf_release (dev, file);
       break;
 #endif
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -508,8 +501,6 @@
     default:
       printk ("Sound error: Releasing unknown device 0x%02x\n", dev);
     }
-
-  sbc_devices[dev].usecount--;
   in_use--;
 }
 
@@ -527,7 +518,7 @@
 
 	switch (dtype)
 	  {
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
 	  case SND_DEV_DSP:
 	  case SND_DEV_DSP16:
 	  case SND_DEV_AUDIO:
@@ -559,14 +550,14 @@
       return mixer_devs[dev]->ioctl (dev, cmd, arg);
       break;
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
     case SND_DEV_SEQ:
     case SND_DEV_SEQ2:
       return sequencer_ioctl (dev, file, cmd, arg);
       break;
 #endif
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -574,7 +565,7 @@
       break;
 #endif
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_ioctl (dev, file, cmd, arg);
       break;
@@ -587,5 +578,3 @@
 
   return -EPERM;
 }
-
-#endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c
--- v1.3.57/linux/drivers/sound/sound_timer.c	Mon Oct 23 18:02:16 1995
+++ linux/drivers/sound/sound_timer.c	Tue Jan  9 00:37:40 1996
@@ -28,9 +28,7 @@
 #define SEQUENCER_C
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
-#if !defined(EXCLUDE_SEQUENCER)
+#if defined(CONFIG_SEQUENCER)
 
 static volatile int initialized = 0, opened = 0, tmr_running = 0;
 static volatile time_t tmr_offs, tmr_ctr;
@@ -351,5 +349,4 @@
   sound_timer_devs[n] = &sound_timer;
 }
 
-#endif
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v1.3.57/linux/drivers/sound/soundcard.c	Tue Dec 26 04:45:37 1995
+++ linux/drivers/sound/soundcard.c	Tue Jan  9 00:37:41 1996
@@ -29,15 +29,12 @@
 /*
  * Created modular version by Peter Trattler (peter@sbox.tu-graz.ac.at)
  */
-#include <linux/module.h>
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
 #include <linux/major.h>
 
-#ifndef EXCLUDE_PNP
+#ifdef CONFIG_PNP
 #include <linux/pnp.h>
 #endif
 
@@ -73,37 +70,37 @@
 }
 
 static int
-sound_read (struct inode *inode, struct file *file, char *buf, int count)
+sound_read (inode_handle * inode, file_handle * file, char *buf, int count)
 {
   int             dev;
 
-  dev = inode->i_rdev;
+  dev = inode_get_rdev (inode);
   dev = MINOR (dev);
-  files[dev].flags = file->f_flags;
+  files[dev].flags = file_get_flags (file);
 
   return sound_read_sw (dev, &files[dev], buf, count);
 }
 
 static int
-sound_write (struct inode *inode, struct file *file, const char *buf, int count)
+sound_write (inode_handle * inode, file_handle * file, const char *buf, int count)
 {
   int             dev;
 
-  dev = inode->i_rdev;
+  dev = inode_get_rdev (inode);
   dev = MINOR (dev);
-  files[dev].flags = file->f_flags;
+  files[dev].flags = file_get_flags (file);
 
   return sound_write_sw (dev, &files[dev], buf, count);
 }
 
 static int
-sound_lseek (struct inode *inode, struct file *file, off_t offset, int orig)
+sound_lseek (inode_handle * inode, file_handle * file, off_t offset, int orig)
 {
   return -EPERM;
 }
 
 static int
-sound_open (struct inode *inode, struct file *file)
+sound_open (inode_handle * inode, file_handle * file)
 {
   int             dev, retval;
   struct fileinfo tmp_file;
@@ -114,7 +111,7 @@
       return -EBUSY;
     }
 
-  dev = inode->i_rdev;
+  dev = inode_get_rdev (inode);
   dev = MINOR (dev);
 
   if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
@@ -124,7 +121,7 @@
     }
 
   tmp_file.mode = 0;
-  tmp_file.flags = file->f_flags;
+  tmp_file.flags = file_get_flags (file);
 
   if ((tmp_file.flags & O_ACCMODE) == O_RDWR)
     tmp_file.mode = OPEN_READWRITE;
@@ -145,13 +142,13 @@
 }
 
 static void
-sound_release (struct inode *inode, struct file *file)
+sound_release (inode_handle * inode, file_handle * file)
 {
   int             dev;
 
-  dev = inode->i_rdev;
+  dev = inode_get_rdev (inode);
   dev = MINOR (dev);
-  files[dev].flags = file->f_flags;
+  files[dev].flags = file_get_flags (file);
 
   sound_release_sw (dev, &files[dev]);
 #ifdef MODULE
@@ -160,31 +157,31 @@
 }
 
 static int
-sound_ioctl (struct inode *inode, struct file *file,
+sound_ioctl (inode_handle * inode, file_handle * file,
 	     unsigned int cmd, unsigned long arg)
 {
   int             dev, err;
 
-  dev = inode->i_rdev;
+  dev = inode_get_rdev (inode);
   dev = MINOR (dev);
-  files[dev].flags = file->f_flags;
+  files[dev].flags = file_get_flags (file);
 
-  if (cmd & IOC_INOUT)
+  if (_IOC_DIR (cmd) != _IOC_NONE)
     {
       /*
          * Have to validate the address given by the process.
        */
       int             len;
 
-      len = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+      len = _IOC_SIZE (cmd);
 
-      if (cmd & IOC_IN)
+      if (_IOC_DIR (cmd) == _IOC_WRITE)
 	{
 	  if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0)
 	    return err;
 	}
 
-      if (cmd & IOC_OUT)
+      if (_IOC_DIR (cmd) == _IOC_READ)
 	{
 	  if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0)
 	    return err;
@@ -198,32 +195,32 @@
 }
 
 static int
-sound_select (struct inode *inode, struct file *file, int sel_type, select_table * wait)
+sound_select (inode_handle * inode, file_handle * file, int sel_type, select_table_handle * wait)
 {
   int             dev;
 
-  dev = inode->i_rdev;
+  dev = inode_get_rdev (inode);
   dev = MINOR (dev);
-  files[dev].flags = file->f_flags;
+  files[dev].flags = file_get_flags (file);
 
   DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
 
   switch (dev & 0x0f)
     {
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
     case SND_DEV_SEQ:
     case SND_DEV_SEQ2:
       return sequencer_select (dev, &files[dev], sel_type, wait);
       break;
 #endif
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_select (dev, &files[dev], sel_type, wait);
       break;
 #endif
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -238,8 +235,98 @@
   return 0;
 }
 
+#ifdef ALLOW_BUFFER_MAPPING
+static int
+sound_mmap (inode_handle * inode, file_handle * file, vm_area_handle * vma)
+{
+  int             dev, dev_class;
+  unsigned long   size, i;
+  struct dma_buffparms *dmap = NULL;
+
+  dev = inode_get_rdev (inode);
+  dev = MINOR (dev);
+  files[dev].flags = file_get_flags (file);
+
+  dev_class = dev & 0x0f;
+  dev >>= 4;
+
+  if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO)
+    {
+      printk ("Sound: mmap() not supported for other than audio devices\n");
+      return -EINVAL;
+    }
+
+  if ((vma_get_flags (vma) & (VM_READ | VM_WRITE)) == (VM_READ | VM_WRITE))
+    {
+      printk ("Sound: Cannot do read/write mmap()\n");
+      return -EINVAL;
+    }
+
+  if (vma_get_flags (vma) & VM_READ)
+    {
+      dmap = audio_devs[dev]->dmap_in;
+    }
+  else if (vma_get_flags (vma) & VM_WRITE)
+    {
+      dmap = audio_devs[dev]->dmap_out;
+    }
+  else
+    {
+      printk ("Sound: Undefined mmap() access\n");
+      return -EINVAL;
+    }
+
+  if (dmap == NULL)
+    {
+      printk ("Sound: mmap() error. dmap == NULL\n");
+      return -EIO;
+    }
+
+  if (dmap->raw_buf == NULL)
+    {
+      printk ("Sound: mmap() called when raw_buf == NULL\n");
+      return -EIO;
+    }
+
+  if (dmap->mapping_flags)
+    {
+      printk ("Sound: mmap() called twice for the same DMA buffer\n");
+      return -EIO;
+    }
+
+  if (vma_get_offset (vma) != 0)
+    {
+      printk ("Sound: mmap() offset must be 0.\n");
+      return -EINVAL;
+    }
+
+  size = vma_get_end (vma) - vma_get_start (vma);
 
-static struct file_operations sound_fops =
+  if (size != dmap->bytes_in_use)
+    {
+      printk ("Sound: mmap() size = %ld. Should be %d\n",
+	      size, dmap->bytes_in_use);
+    }
+
+
+  if (remap_page_range (vma_get_start (vma), dmap->raw_buf_phys,
+			vma_get_end (vma) - vma_get_start (vma),
+			vma_get_page_prot (vma)))
+    return -EAGAIN;
+
+  vma_set_inode (vma, inode);
+  inode_inc_count (inode);
+
+  dmap->mapping_flags |= DMA_MAP_MAPPED;
+
+  memset (dmap->raw_buf,
+	  dmap->neutral_byte,
+	  dmap->bytes_in_use);
+  return 0;
+}
+#endif
+
+static struct file_operation_handle sound_fops =
 {
   sound_lseek,
   sound_read,
@@ -247,7 +334,11 @@
   NULL,				/* sound_readdir */
   sound_select,
   sound_ioctl,
+#ifdef ALLOW_BUFFER_MAPPING
+  sound_mmap,
+#else
   NULL,
+#endif
   sound_open,
   sound_release
 };
@@ -256,7 +347,7 @@
 soundcard_init (void)
 {
 #ifndef MODULE
-  register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
+  module_register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
   chrdev_registered = 1;
 #endif
 
@@ -265,14 +356,14 @@
   sndtable_init (0);		/* Initialize call tables and
 				   * detect cards */
 
-#ifndef EXCLUDE_PNP
+#ifdef CONFIG_PNP
   sound_pnp_init ();
 #endif
 
   if (sndtable_get_cardcount () == 0)
     return;			/* No cards detected */
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
   if (num_audiodevs)		/* Audio devices present */
     {
       DMAbuf_init (0);
@@ -280,12 +371,12 @@
     }
 #endif
 
-#ifndef EXCLUDE_MIDI
+#ifdef CONFIG_MIDI
   if (num_midis)
     MIDIbuf_init (0);
 #endif
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
   if (num_midis + num_synths)
     sequencer_init (0);
 #endif
@@ -309,6 +400,8 @@
   irqs = 0;
 }
 
+char            kernel_version[] = UTS_RELEASE;
+
 #endif
 
 static int      debugmem = 0;	/* switched off by default */
@@ -323,7 +416,7 @@
   int             ints[21];
   int             i;
 
-  if (0 < 0)
+  if (connect_wrapper (WRAPPER_VERSION) < 0)
     {
       printk ("Sound: Incompatible kernel (wrapper) version\n");
       return -EINVAL;
@@ -340,7 +433,7 @@
   if (i)
     sound_setup ("sound=", ints);
 
-  err = register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
+  err = module_register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
   if (err)
     {
       printk ("sound: driver already loaded/included in kernel\n");
@@ -369,9 +462,9 @@
       int             i;
 
       if (chrdev_registered)
-	unregister_chrdev (SOUND_MAJOR, "sound");
+	module_unregister_chrdev (SOUND_MAJOR, "sound");
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
       sound_stop_timer ();
 #endif
       sound_unload_drivers ();
@@ -388,7 +481,7 @@
 	    sound_free_dma (i);
 	  }
 
-#ifndef EXCLUDE_PNP
+#ifdef CONFIG_PNP
       sound_pnp_disconnect ();
 #endif
 
@@ -397,7 +490,7 @@
 #endif
 
 void
-tenmicrosec (void)
+tenmicrosec (sound_os_info * osp)
 {
   int             i;
 
@@ -466,7 +559,7 @@
 {
   if (dma_alloc_map[chn] != DMA_MAP_FREE)
     {
-      printk ("sound_free_dma: Bad access to DMA channel %d\n", chn);
+      /* printk ("sound_free_dma: Bad access to DMA channel %d\n", chn); */
       return;
     }
   free_dma (chn);
@@ -491,7 +584,7 @@
   restore_flags (flags);
 }
 
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
 
 
 static struct timer_list seq_timer =
@@ -507,6 +600,7 @@
   else
     count += seq_time;
 
+  ;
 
   {
     seq_timer.expires = ((count - jiffies)) + jiffies;
@@ -521,7 +615,7 @@
 }
 #endif
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
 
 #ifdef KMALLOC_DMA_BROKEN
 fatal_error__This_version_is_not_compatible_with_this_kernel;
@@ -535,6 +629,10 @@
   char           *start_addr, *end_addr;
   int             i, dma_pagesize;
 
+#ifdef ALLOW_BUFFER_MAPPING
+  dmap->mapping_flags &= ~DMA_MAP_MAPPED;
+#endif
+
   if (dmap->raw_buf != NULL)
     return 0;			/* Already done */
 
@@ -611,7 +709,7 @@
 
   for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
     {
-      mem_map[i].reserved = 1;
+      mem_map_reserve (i);
     }
 
   return 0;
@@ -622,6 +720,12 @@
 {
   if (dmap->raw_buf == NULL)
     return;
+
+#ifdef ALLOW_BUFFER_MAPPING
+  if (dmap->mapping_flags & DMA_MAP_MAPPED)
+    return;			/* Don't free mmapped buffer. Will use it next time */
+#endif
+
   {
     int             sz, size, i;
     unsigned long   start_addr, end_addr;
@@ -635,7 +739,7 @@
 
     for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
       {
-	mem_map[i].reserved = 0;
+	mem_map_unreserve (i);
       }
 
     free_pages ((unsigned long) dmap->raw_buf, sz);
@@ -651,13 +755,45 @@
   return -EINVAL;
 }
 
-#else
-
 void
-soundcard_init (void)		/* Dummy version */
+conf_printf (char *name, struct address_info *hw_config)
 {
+  if (!trace_init)
+    return;
+
+  printk ("<%s> at 0x%03x", name, hw_config->io_base);
+
+  if (hw_config->irq)
+    printk (" irq %d", hw_config->irq);
+
+  if (hw_config->dma != -1 || hw_config->dma2 != -1)
+    {
+      printk (" dma %d", hw_config->dma);
+      if (hw_config->dma2 != -1)
+	printk (",%d", hw_config->dma2);
+    }
+
+  printk ("\n");
 }
 
-#endif
+void
+conf_printf2 (char *name, int base, int irq, int dma, int dma2)
+{
+  if (!trace_init)
+    return;
+
+  printk ("<%s> at 0x%03x", name, base);
+
+  if (irq)
+    printk (" irq %d", irq);
 
+  if (dma != -1 || dma2 != -1)
+    {
+      printk (" dma %d", dma);
+      if (dma2 != -1)
+	printk (",%d", dma2);
+    }
+
+  printk ("\n");
+}
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h
--- v1.3.57/linux/drivers/sound/soundvers.h	Wed Nov  8 07:11:37 1995
+++ linux/drivers/sound/soundvers.h	Tue Jan  9 00:36:58 1996
@@ -1,2 +1,2 @@
-#define SOUND_VERSION_STRING "3.5-alpha5-951002"
+#define SOUND_VERSION_STRING "3.5-alpha8-960109"
 #define SOUND_INTERNAL_VERSION 0x030505
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v1.3.57/linux/drivers/sound/sscape.c	Wed Nov  8 07:11:37 1995
+++ linux/drivers/sound/sscape.c	Tue Jan  9 00:37:43 1996
@@ -29,7 +29,7 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SSCAPE)
+#if defined(CONFIG_SSCAPE)
 
 #include "coproc.h"
 
@@ -102,7 +102,7 @@
 {0};
 static struct sscape_info *devc = &dev_info;
 
-static struct wait_queue *sscape_sleeper = NULL;
+static wait_handle *sscape_sleeper = NULL;
 static volatile struct snd_wait sscape_sleep_flag =
 {0};
 
@@ -309,7 +309,7 @@
     {
       {
 	sscape_sleep_flag.mode = WK_WAKEUP;
-	wake_up (&sscape_sleeper);
+	module_wake_up (&sscape_sleeper);
       };
     }
 
@@ -318,7 +318,7 @@
       printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc));
     }
 
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   if (bits & 0x01)
     {
       mpuintr (irq, NULL);
@@ -338,35 +338,6 @@
 
 }
 
-static void
-sscape_enable_intr (struct sscape_info *devc, unsigned intr_bits)
-{
-  unsigned char   temp, orig;
-
-  temp = orig = sscape_read (devc, GA_INTENA_REG);
-  temp |= intr_bits;
-  temp |= 0x80;			/* Master IRQ enable */
-
-  if (temp == orig)
-    return;			/* No change */
-
-  sscape_write (devc, GA_INTENA_REG, temp);
-}
-
-static void
-sscape_disable_intr (struct sscape_info *devc, unsigned intr_bits)
-{
-  unsigned char   temp, orig;
-
-  temp = orig = sscape_read (devc, GA_INTENA_REG);
-  temp &= ~intr_bits;
-  if ((temp & ~0x80) == 0x00)
-    temp = 0x00;		/* Master IRQ disable */
-  if (temp == orig)
-    return;			/* No change */
-
-  sscape_write (devc, GA_INTENA_REG, temp);
-}
 
 static void
 do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode)
@@ -431,6 +402,7 @@
 	return -EIO;
     }
 
+  sscape_sleep_flag.mode = WK_NONE;
   return 0;
 }
 
@@ -445,7 +417,7 @@
   if (devc->dma_allocated)
     {
       sscape_write (devc, GA_DMAA_REG, 0x20);	/* DMA channel disabled */
-#ifndef EXCLUDE_NATIVE_PCM
+#ifdef CONFIG_NATIVE_PCM
 #endif
       devc->dma_allocated = 0;
     }
@@ -478,7 +450,7 @@
       cli ();
       if (devc->dma_allocated == 0)
 	{
-#ifndef EXCLUDE_NATIVE_PCM
+#ifdef CONFIG_NATIVE_PCM
 #endif
 
 	  devc->dma_allocated = 1;
@@ -523,11 +495,11 @@
 	unsigned long   tl;
 
 	if (1)
-	  current->timeout = tl = jiffies + (1);
+	  current_set_timeout (tl = jiffies + (1));
 	else
 	  tl = 0xffffffff;
 	sscape_sleep_flag.mode = WK_SLEEP;
-	interruptible_sleep_on (&sscape_sleeper);
+	module_interruptible_sleep_on (&sscape_sleeper);
 	if (!(sscape_sleep_flag.mode & WK_WAKEUP))
 	  {
 	    if (jiffies >= tl)
@@ -571,11 +543,11 @@
 	    unsigned long   tl;
 
 	    if (1)
-	      current->timeout = tl = jiffies + (1);
+	      current_set_timeout (tl = jiffies + (1));
 	    else
 	      tl = 0xffffffff;
 	    sscape_sleep_flag.mode = WK_SLEEP;
-	    interruptible_sleep_on (&sscape_sleeper);
+	    module_interruptible_sleep_on (&sscape_sleeper);
 	    if (!(sscape_sleep_flag.mode & WK_WAKEUP))
 	      {
 		if (jiffies >= tl)
@@ -604,11 +576,11 @@
 	    unsigned long   tl;
 
 	    if (1)
-	      current->timeout = tl = jiffies + (1);
+	      current_set_timeout (tl = jiffies + (1));
 	    else
 	      tl = 0xffffffff;
 	    sscape_sleep_flag.mode = WK_SLEEP;
-	    interruptible_sleep_on (&sscape_sleeper);
+	    module_interruptible_sleep_on (&sscape_sleeper);
 	    if (!(sscape_sleep_flag.mode & WK_WAKEUP))
 	      {
 		if (jiffies >= tl)
@@ -917,10 +889,10 @@
   if (old_hardware)
     {
       valid_interrupts = valid_interrupts_old;
-      printk (" <Ensoniq Soundscape (old)>");
+      conf_printf ("Ensoniq Soundscape (old)", hw_config);
     }
   else
-    printk (" <Ensoniq Soundscape>");
+    conf_printf ("Ensoniq Soundscape", hw_config);
 
   for (i = 0; i < sizeof (valid_interrupts); i++)
     if (hw_config->irq == valid_interrupts[i])
@@ -964,7 +936,7 @@
 
       case 9:			/* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
 	sscape_write (devc, i,
-		      (sscape_read (devc, i) & 0xf0) | 0x00);
+		      (sscape_read (devc, i) & 0xf0) | 0x08);
 	break;
 
       default:
@@ -986,7 +958,7 @@
   }
 #endif
 
-#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_MPU_EMU)
+#if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU)
   if (probe_mpu401 (hw_config))
     hw_config->always_detect = 1;
   {
@@ -1003,7 +975,7 @@
 #ifndef EXCLUDE_NATIVE_PCM
   /* Not supported yet */
 
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
   if (num_audiodevs < MAX_AUDIO_DEV)
     {
       audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations;
@@ -1088,7 +1060,6 @@
 
   if (old_hardware)		/* Check that it's really an old Spea/Reveal card. */
     {
-      int             status = 0;
       unsigned char   tmp;
       int             cc;
 
@@ -1153,7 +1124,7 @@
 
   int             i, irq_bits = 0xff;
 
-#ifdef EXCLUDE_NATIVE_PCM
+#ifndef CONFIG_NATIVE_PCM
   int             prev_devs = num_audiodevs;
 
 #endif
@@ -1192,7 +1163,7 @@
 	       0,
 	       devc->osp);
 
-#ifdef EXCLUDE_NATIVE_PCM
+#ifndef CONFIG_NATIVE_PCM
   if (num_audiodevs == (prev_devs + 1))		/* The AD1848 driver installed itself */
     audio_devs[prev_devs]->coproc = &sscape_coproc_operations;
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c
--- v1.3.57/linux/drivers/sound/sys_timer.c	Mon Oct 23 18:02:17 1995
+++ linux/drivers/sound/sys_timer.c	Tue Jan  9 00:37:43 1996
@@ -31,9 +31,7 @@
 #define SEQUENCER_C
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
-#ifndef EXCLUDE_SEQUENCER
+#ifdef CONFIG_SEQUENCER
 
 static volatile int opened = 0, tmr_running = 0;
 static volatile time_t tmr_offs, tmr_ctr;
@@ -113,6 +111,7 @@
   curr_timebase = HZ;
   opened = 1;
 
+  ;
 
   {
     def_tmr.expires = (1) + jiffies;
@@ -306,5 +305,4 @@
   def_tmr_arm
 };
 
-#endif
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v1.3.57/linux/drivers/sound/trix.c	Mon Oct 23 18:02:17 1995
+++ linux/drivers/sound/trix.c	Tue Jan  9 00:37:44 1996
@@ -30,12 +30,13 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_TRIX)
+#if defined(CONFIG_TRIX)
 
 #ifdef INCLUDE_TRIX_BOOT
 #include "trix_boot.h"
 #endif
 
+
 static int      kilroy_was_here = 0;	/* Don't detect twice */
 static int      sb_initialized = 0;
 static int      mpu_initialized = 0;
@@ -80,6 +81,7 @@
   outb (0x00, base + 6);	/* Reset */
   outb (0x50, 0x390);		/* ?????? */
 #endif
+
 }
 
 static int
@@ -324,20 +326,20 @@
 long
 attach_trix_sb (long mem_start, struct address_info *hw_config)
 {
-#ifndef EXCLUDE_SB
+#ifdef CONFIG_SB
   extern int      sb_no_recording;
 
   sb_dsp_disable_midi ();
   sb_no_recording = 1;
 #endif
-  printk (" <AudioTriX (SB)>");
+  conf_printf ("AudioTriX (SB)", hw_config);
   return mem_start;
 }
 
 long
 attach_trix_mpu (long mem_start, struct address_info *hw_config)
 {
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   return attach_mpu401 (mem_start, hw_config);
 #else
   return mem_start;
@@ -347,7 +349,7 @@
 int
 probe_trix_mpu (struct address_info *hw_config)
 {
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   unsigned char   conf;
   static char     irq_bits[] =
   {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5};
@@ -439,7 +441,7 @@
 void
 unload_trix_mpu (struct address_info *hw_config)
 {
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   unload_mpu401 (hw_config);
 #endif
 }
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c
--- v1.3.57/linux/drivers/sound/uart6850.c	Fri Oct 13 14:44:44 1995
+++ linux/drivers/sound/uart6850.c	Tue Jan  9 00:37:44 1996
@@ -30,9 +30,7 @@
 
 #include "sound_config.h"
 
-#ifdef CONFIGURE_SOUNDCARD
-
-#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
 
 #define	DATAPORT   (uart6850_base)	/*
 					   * * * Midi6850 Data I/O Port on IBM
@@ -117,9 +115,7 @@
   unsigned long   flags;
 
   if (!(uart6850_opened & OPEN_READ))
-    return;			/*
-				 * No longer required
-				 */
+    return;			/* Device has been closed */
 
   save_flags (flags);
   cli ();
@@ -150,6 +146,7 @@
       return -EBUSY;
     }
 
+  ;
   uart6850_cmd (UART_RESET);
 
   uart6850_input_loop ();
@@ -298,7 +295,7 @@
 
   restore_flags (flags);
 
-  printk (" <6850 Midi Interface>");
+  conf_printf ("6850 Midi Interface", hw_config);
 
   std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &uart6850_operations;
@@ -338,7 +335,5 @@
 {
   snd_release_irq (hw_config->irq);
 }
-
-#endif
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/drivers/sound/ulaw.h linux/drivers/sound/ulaw.h
--- v1.3.57/linux/drivers/sound/ulaw.h	Tue Jul 11 10:02:55 1995
+++ linux/drivers/sound/ulaw.h	Tue Jan  9 00:36:59 1996
@@ -1,74 +1,69 @@
-
-/*
- * This is a new ulaw.h made by Andy Fingerhut <jaf@dworkin.wustl.edu>
- */
-
 static unsigned char ulaw_dsp[] = {
-    2,    6,   10,   14,   18,   22,   26,   30,
-   34,   38,   42,   46,   50,   54,   58,   62,
-   65,   67,   69,   71,   73,   75,   77,   79,
-   81,   83,   85,   87,   89,   91,   93,   95,
-   97,   98,   99,  100,  101,  102,  103,  104,
-  105,  106,  107,  108,  109,  110,  111,  112,
-  112,  113,  113,  114,  114,  115,  115,  116,
-  116,  117,  117,  118,  118,  119,  119,  120,
-  120,  120,  121,  121,  121,  121,  122,  122,
-  122,  122,  123,  123,  123,  123,  124,  124,
-  124,  124,  124,  124,  125,  125,  125,  125,
-  125,  125,  125,  125,  126,  126,  126,  126,
-  126,  126,  126,  126,  126,  126,  126,  126,
-  127,  127,  127,  127,  127,  127,  127,  127,
-  127,  127,  127,  127,  127,  127,  127,  127,
-  127,  127,  127,  127,  127,  127,  127,  128,
-  253,  249,  245,  241,  237,  233,  229,  225,
-  221,  217,  213,  209,  205,  201,  197,  193,
-  190,  188,  186,  184,  182,  180,  178,  176,
-  174,  172,  170,  168,  166,  164,  162,  160,
-  158,  157,  156,  155,  154,  153,  152,  151,
-  150,  149,  148,  147,  146,  145,  144,  143,
-  143,  142,  142,  141,  141,  140,  140,  139,
-  139,  138,  138,  137,  137,  136,  136,  135,
-  135,  135,  134,  134,  134,  134,  133,  133,
-  133,  133,  132,  132,  132,  132,  131,  131,
-  131,  131,  131,  131,  130,  130,  130,  130,
-  130,  130,  130,  130,  129,  129,  129,  129,
-  129,  129,  129,  129,  129,  129,  129,  129,
-  128,  128,  128,  128,  128,  128,  128,  128,
-  128,  128,  128,  128,  128,  128,  128,  128,
-  128,  128,  128,  128,  128,  128,  128,  128
+     0,    0,    0,    0,    0,    0,    0,    0, 
+     0,    0,    0,    0,    0,    0,    0,    0, 
+     0,    0,    0,    0,    0,    0,    0,    0, 
+     0,    0,    0,    0,    0,    0,    0,    2, 
+     5,    9,   13,   17,   21,   25,   29,   33, 
+    37,   41,   45,   49,   53,   57,   61,   65, 
+    68,   70,   72,   74,   76,   78,   80,   82, 
+    84,   86,   88,   90,   92,   94,   96,   98, 
+   100,  101,  102,  103,  104,  105,  106,  107, 
+   108,  109,  110,  111,  112,  113,  114,  115, 
+   115,  116,  116,  117,  117,  118,  118,  119, 
+   119,  120,  120,  121,  121,  122,  122,  123, 
+   123,  123,  124,  124,  124,  124,  125,  125, 
+   125,  125,  126,  126,  126,  126,  127,  127, 
+   127,  127,  127,  127,  128,  128,  128,  128, 
+   128,  128,  128,  128,  128,  128,  128,  128, 
+   255,  255,  255,  255,  255,  255,  255,  255, 
+   255,  255,  255,  255,  255,  255,  255,  255, 
+   255,  255,  255,  255,  255,  255,  255,  255, 
+   255,  255,  255,  255,  255,  255,  255,  255, 
+   252,  248,  244,  240,  236,  232,  228,  224, 
+   220,  216,  212,  208,  204,  200,  196,  192, 
+   189,  187,  185,  183,  181,  179,  177,  175, 
+   173,  171,  169,  167,  165,  163,  161,  159, 
+   157,  156,  155,  154,  153,  152,  151,  150, 
+   149,  148,  147,  146,  145,  144,  143,  142, 
+   142,  141,  141,  140,  140,  139,  139,  138, 
+   138,  137,  137,  136,  136,  135,  135,  134, 
+   134,  134,  133,  133,  133,  133,  132,  132, 
+   132,  132,  131,  131,  131,  131,  130,  130, 
+   130,  130,  130,  130,  129,  129,  129,  129, 
+   129,  129,  129,  129,  128,  128,  128,  128, 
 };
 
 static unsigned char dsp_ulaw[] = {
-    0,    0,    0,    0,    0,    1,    1,    1,
-    1,    2,    2,    2,    2,    3,    3,    3,
-    3,    4,    4,    4,    4,    5,    5,    5,
-    5,    6,    6,    6,    6,    7,    7,    7,
-    7,    8,    8,    8,    8,    9,    9,    9,
-    9,   10,   10,   10,   10,   11,   11,   11,
-   11,   12,   12,   12,   12,   13,   13,   13,
-   13,   14,   14,   14,   14,   15,   15,   15,
-   15,   16,   16,   17,   17,   18,   18,   19,
-   19,   20,   20,   21,   21,   22,   22,   23,
-   23,   24,   24,   25,   25,   26,   26,   27,
-   27,   28,   28,   29,   29,   30,   30,   31,
-   31,   32,   33,   34,   35,   36,   37,   38,
-   39,   40,   41,   42,   43,   44,   45,   46,
-   47,   48,   50,   52,   54,   56,   58,   60,
-   62,   65,   69,   73,   77,   83,   91,  103,
-  255,  231,  219,  211,  205,  201,  197,  193,
-  190,  188,  186,  184,  182,  180,  178,  176,
-  175,  174,  173,  172,  171,  170,  169,  168,
-  167,  166,  165,  164,  163,  162,  161,  160,
-  159,  159,  158,  158,  157,  157,  156,  156,
-  155,  155,  154,  154,  153,  153,  152,  152,
-  151,  151,  150,  150,  149,  149,  148,  148,
-  147,  147,  146,  146,  145,  145,  144,  144,
-  143,  143,  143,  143,  142,  142,  142,  142,
-  141,  141,  141,  141,  140,  140,  140,  140,
-  139,  139,  139,  139,  138,  138,  138,  138,
-  137,  137,  137,  137,  136,  136,  136,  136,
-  135,  135,  135,  135,  134,  134,  134,  134,
-  133,  133,  133,  133,  132,  132,  132,  132,
-  131,  131,  131,  131,  130,  130,  130,  130,
-  129,  129,  129,  129,  128,  128,  128,  128
+    31,   31,   31,   32,   32,   32,   32,   33, 
+    33,   33,   33,   34,   34,   34,   34,   35, 
+    35,   35,   35,   36,   36,   36,   36,   37, 
+    37,   37,   37,   38,   38,   38,   38,   39, 
+    39,   39,   39,   40,   40,   40,   40,   41, 
+    41,   41,   41,   42,   42,   42,   42,   43, 
+    43,   43,   43,   44,   44,   44,   44,   45, 
+    45,   45,   45,   46,   46,   46,   46,   47, 
+    47,   47,   47,   48,   48,   49,   49,   50, 
+    50,   51,   51,   52,   52,   53,   53,   54, 
+    54,   55,   55,   56,   56,   57,   57,   58, 
+    58,   59,   59,   60,   60,   61,   61,   62, 
+    62,   63,   63,   64,   65,   66,   67,   68, 
+    69,   70,   71,   72,   73,   74,   75,   76, 
+    77,   78,   79,   81,   83,   85,   87,   89, 
+    91,   93,   95,   99,  103,  107,  111,  119, 
+   255,  247,  239,  235,  231,  227,  223,  221, 
+   219,  217,  215,  213,  211,  209,  207,  206, 
+   205,  204,  203,  202,  201,  200,  199,  198, 
+   197,  196,  195,  194,  193,  192,  191,  191, 
+   190,  190,  189,  189,  188,  188,  187,  187, 
+   186,  186,  185,  185,  184,  184,  183,  183, 
+   182,  182,  181,  181,  180,  180,  179,  179, 
+   178,  178,  177,  177,  176,  176,  175,  175, 
+   175,  175,  174,  174,  174,  174,  173,  173, 
+   173,  173,  172,  172,  172,  172,  171,  171, 
+   171,  171,  170,  170,  170,  170,  169,  169, 
+   169,  169,  168,  168,  168,  168,  167,  167, 
+   167,  167,  166,  166,  166,  166,  165,  165, 
+   165,  165,  164,  164,  164,  164,  163,  163, 
+   163,  163,  162,  162,  162,  162,  161,  161, 
+   161,  161,  160,  160,  160,  160,  159,  159, 
 };
diff -u --recursive --new-file v1.3.57/linux/fs/Config.in linux/fs/Config.in
--- v1.3.57/linux/fs/Config.in	Tue Jan  2 16:46:27 1996
+++ linux/fs/Config.in	Sun Jan 14 16:22:16 1996
@@ -27,3 +27,4 @@
 tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
+endmenu
diff -u --recursive --new-file v1.3.57/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.57/linux/fs/buffer.c	Sun Jan 14 16:30:11 1996
+++ linux/fs/buffer.c	Thu Jan 18 06:41:22 1996
@@ -56,6 +56,7 @@
 static struct buffer_head * next_to_age[NR_LIST] = {NULL, };
 static struct buffer_head * free_list[NR_SIZES] = {NULL, };
 static struct buffer_head * unused_list = NULL;
+struct buffer_head * reuse_list = NULL;
 static struct wait_queue * buffer_wait = NULL;
 
 int nr_buffers = 0;
@@ -459,7 +460,7 @@
 	struct buffer_head * tmp;
 
 	for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
-		if (tmp->b_dev == dev && tmp->b_blocknr == block)
+		if (tmp->b_blocknr == block && tmp->b_dev == dev)
 			if (tmp->b_size == size)
 				return tmp;
 			else {
@@ -980,10 +981,38 @@
 	}
 }
 
+/* 
+ * We can't put completed temporary IO buffer_heads directly onto the
+ * unused_list when they become unlocked, since the device driver
+ * end_request routines still expect access to the buffer_head's
+ * fields after the final unlock.  So, the device driver puts them on
+ * the reuse_list instead once IO completes, and we recover these to
+ * the unused_list here.
+ *
+ * The reuse_list receives buffers from interrupt routines, so we need
+ * to be IRQ-safe here.
+ */
+static inline void recover_reusable_buffer_heads(void)
+{
+	struct buffer_head *bh;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+	while (reuse_list) {
+		bh = reuse_list;
+		reuse_list = bh->b_next_free;
+		restore_flags(flags);
+		put_unused_buffer_head(bh);
+		cli();
+	}
+}
+
 static struct buffer_head * get_unused_buffer_head(void)
 {
 	struct buffer_head * bh;
 
+	recover_reusable_buffer_heads();
 	get_more_buffer_heads();
 	if (!unused_list)
 		return NULL;
@@ -1033,22 +1062,14 @@
 	return NULL;
 }
 
-static void read_buffers(struct buffer_head * bh[], int nrbuf)
-{
-	ll_rw_block(READ, nrbuf, bh);
-	bh += nrbuf;
-	do {
-		nrbuf--;
-		bh--;
-		wait_on_buffer(*bh);
-	} while (nrbuf > 0);
-}
-
 static int bread_page(unsigned long address, kdev_t dev, int b[], int size)
 {
-	struct buffer_head *bh, *next, *arr[MAX_BUF_PER_PAGE];
+	struct buffer_head *bh, *prev, *next, *arr[MAX_BUF_PER_PAGE];
 	int block, nr;
+	struct page *page;
 
+	page = mem_map + MAP_NR(address);
+	page->uptodate = 0;
 	bh = create_buffers(address, size);
 	if (!bh)
 		return -ENOMEM;
@@ -1057,6 +1078,17 @@
 	do {
 		struct buffer_head * tmp;
 		block = *(b++);
+
+		set_bit(BH_FreeOnIO, &next->b_state);
+		next->b_list = BUF_CLEAN;
+		next->b_dev = dev;
+		next->b_blocknr = block;
+		next->b_count = 1;
+		next->b_flushtime = 0;
+		clear_bit(BH_Dirty, &next->b_state);
+		clear_bit(BH_Req, &next->b_state);
+		set_bit(BH_Uptodate, &next->b_state);
+		
 		if (!block) {
 			memset(next->b_data, 0, size);
 			continue;
@@ -1071,32 +1103,47 @@
 			brelse(tmp);
 			continue;
 		}
-		arr[nr++] = next;
-		next->b_dev = dev;
-		next->b_blocknr = block;
-		next->b_count = 1;
-		next->b_flushtime = 0;
-		clear_bit(BH_Dirty, &next->b_state);
 		clear_bit(BH_Uptodate, &next->b_state);
-		clear_bit(BH_Req, &next->b_state);
-		next->b_list = BUF_CLEAN;
-	} while ((next = next->b_this_page) != NULL);
-
+		arr[nr++] = next;
+	} while (prev = next, (next = next->b_this_page) != NULL);
+	prev->b_this_page = bh;
+	
 	if (nr)
-		read_buffers(arr,nr);
-	++current->maj_flt;
-
-	while ((next = bh) != NULL) {
-		bh = bh->b_this_page;
-		put_unused_buffer_head(next);
+		ll_rw_block(READ, nr, arr);
+	else {
+		page->locked = 0;
+		page->uptodate = 1;
+		wake_up(&page->wait);
 	}
+	++current->maj_flt;
 	return 0;
 }
 
+void mark_buffer_uptodate(struct buffer_head * bh, int on)
+{
+	if (on) {
+		struct buffer_head *tmp = bh;
+		int page_uptodate = 1;
+		set_bit(BH_Uptodate, &bh->b_state);
+		do {
+			if (!test_bit(BH_Uptodate, &tmp->b_state)) {
+				page_uptodate = 0;
+				break;
+			}
+			tmp=tmp->b_this_page;
+		} while (tmp && tmp != bh);
+		if (page_uptodate)
+			mem_map[MAP_NR(bh->b_data)].uptodate = 1;
+	} else
+		clear_bit(BH_Uptodate, &bh->b_state);
+}
+
 /*
- * Generic "readpage" function for block devices that have the
- * normal bmap functionality. This is most of the block device
- * filesystems.
+ * Generic "readpage" function for block devices that have the normal
+ * bmap functionality. This is most of the block device filesystems.
+ * Reads the page asynchronously --- the unlock_buffer() and
+ * mark_buffer_uptodate() functions propogate buffer state into the
+ * page struct once IO has completed.
  */
 int generic_readpage(struct inode * inode, struct page * page)
 {
@@ -1104,6 +1151,9 @@
 	int *p, nr[PAGE_SIZE/512];
 	int i;
 
+	wait_on_page(page);
+	page->locked = 1;
+	
 	i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
 	block = page->offset >> inode->i_sb->s_blocksize_bits;
 	p = nr;
@@ -1114,20 +1164,11 @@
 		p++;
 	} while (i > 0);
 
-	/*
-	 * We should make this asynchronous, but this is good enough for now..
-	 */
-
 	/* IO start */
 	page->count++;
 	address = page_address(page);
 	bread_page(address, inode->i_dev, nr, inode->i_sb->s_blocksize);
-
-	/* IO ready (this part should be in the "page ready callback" function) */
-	page->uptodate = 1;
-	wake_up(&page->wait);
 	free_page(address);
-
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.57/linux/fs/ext/inode.c linux/fs/ext/inode.c
--- v1.3.57/linux/fs/ext/inode.c	Mon Nov 27 12:48:31 1995
+++ linux/fs/ext/inode.c	Mon Jan 15 07:59:09 1996
@@ -451,15 +451,24 @@
 	return err;
 }
 
-#ifdef MODULE
 
 static struct file_system_type ext_fs_type = {
         ext_read_super, "ext", 1, NULL
 };
 
-int init_module(void)
+int init_ext_fs(void)
 {
         return register_filesystem(&ext_fs_type);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	int status;
+
+	if ((status = init_ext_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/ext2/CHANGES linux/fs/ext2/CHANGES
--- v1.3.57/linux/fs/ext2/CHANGES	Sun Aug 13 14:45:34 1995
+++ linux/fs/ext2/CHANGES	Wed Jan 17 07:31:58 1996
@@ -1,5 +1,7 @@
 Changes from version 0.5a to version 0.5b
 =========================================
+	- Now that we have sysctl(), the immutable flag cannot be changed when
+	  the system is running at security level > 0.
 	- Some cleanups in the code.
 	- More consistency checks on directories.
 	- The ext2.diff patch from Tom May <ftom@netcom.com> has been
diff -u --recursive --new-file v1.3.57/linux/fs/ext2/ioctl.c linux/fs/ext2/ioctl.c
--- v1.3.57/linux/fs/ext2/ioctl.c	Wed Mar 22 10:33:59 1995
+++ linux/fs/ext2/ioctl.c	Wed Jan 17 07:31:58 1996
@@ -33,12 +33,13 @@
 	case EXT2_IOC_SETFLAGS:
 		flags = get_fs_long ((long *) arg);
 		/*
-		 * Only the super-user can change the IMMUTABLE flag
+		 * The IMMUTABLE flag can only be changed by the super user
+		 * when the security level is zero.
 		 */
 		if ((flags & EXT2_IMMUTABLE_FL) ^
 		    (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)) {
 			/* This test looks nicer. Thanks to Pauline Middelink */
-			if (!fsuser())
+			if (!fsuser() || securelevel > 0)
 				return -EPERM;
 		} else
 			if ((current->fsuid != inode->i_uid) && !fsuser())
diff -u --recursive --new-file v1.3.57/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v1.3.57/linux/fs/ext2/super.c	Mon Dec 11 15:42:04 1995
+++ linux/fs/ext2/super.c	Mon Jan 15 07:59:09 1996
@@ -685,15 +685,23 @@
 	return 0;
 }
 
-#ifdef MODULE
-
 static struct file_system_type ext2_fs_type = {
         ext2_read_super, "ext2", 1, NULL
 };
 
-int init_module(void)
+int init_ext2_fs(void)
 {
         return register_filesystem(&ext2_fs_type);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	int status;
+
+	if ((status = init_ext2_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/filesystems.c linux/fs/filesystems.c
--- v1.3.57/linux/fs/filesystems.c	Tue Jan  2 16:46:27 1996
+++ linux/fs/filesystems.c	Mon Jan 15 07:59:09 1996
@@ -44,74 +44,55 @@
 	device_setup();
 
 #ifdef CONFIG_EXT_FS
-	register_filesystem(&(struct file_system_type)
-		{ext_read_super, "ext", 1, NULL});
+	init_ext_fs();
 #endif
 
 #ifdef CONFIG_EXT2_FS
-	register_filesystem(&(struct file_system_type)
-		{ext2_read_super, "ext2", 1, NULL});
+	init_ext2_fs();
 #endif
 
 #ifdef CONFIG_XIA_FS
-	register_filesystem(&(struct file_system_type)
-		{xiafs_read_super, "xiafs", 1, NULL});
+	init_xiafs_fs();
 #endif
 
 #ifdef CONFIG_MINIX_FS
-	register_filesystem(&(struct file_system_type)
-		{minix_read_super, "minix", 1, NULL});
+	init_minix_fs();
 #endif
 
 #ifdef CONFIG_UMSDOS_FS
-	register_filesystem(&(struct file_system_type)
-	{UMSDOS_read_super,	"umsdos",	1, NULL});
+	init_umsdos_fs();
 #endif
 
 #ifdef CONFIG_MSDOS_FS
-	register_filesystem(&(struct file_system_type)
-		{msdos_read_super, "msdos", 1, NULL});
+	init_msdos_fs();
 #endif
 
 #ifdef CONFIG_PROC_FS
-	register_filesystem(&(struct file_system_type)
-		{proc_read_super, "proc", 0, NULL});
+	init_proc_fs();
 #endif
 
 #ifdef CONFIG_NFS_FS
-	register_filesystem(&(struct file_system_type)
-		{nfs_read_super, "nfs", 0, NULL});
+	init_nfs_fs();
 #endif
 
 #ifdef CONFIG_SMB_FS
-	register_filesystem(&(struct file_system_type)
-		{smb_read_super, "smbfs", 0, NULL});
+	init_smb_fs();
 #endif
 
 #ifdef CONFIG_NCP_FS
-	register_filesystem(&(struct file_system_type)
-		{ncp_read_super, "ncpfs", 0, NULL});
+	init_ncp_fs();
 #endif
 
 #ifdef CONFIG_ISO9660_FS
-	register_filesystem(&(struct file_system_type)
-		{isofs_read_super, "iso9660", 1, NULL});
+	init_iso9660_fs();
 #endif
 
 #ifdef CONFIG_SYSV_FS
-	register_filesystem(&(struct file_system_type)
-		{sysv_read_super, "xenix", 1, NULL});
-
-	register_filesystem(&(struct file_system_type)
-		{sysv_read_super, "sysv", 1, NULL});
-
-	register_filesystem(&(struct file_system_type)
-		{sysv_read_super, "coherent", 1, NULL});
+	init_sysv_fs();
 #endif
 
 #ifdef CONFIG_HPFS_FS
-	register_filesystem(&(struct file_system_type)
-		{hpfs_read_super, "hpfs", 1, NULL});
+	init_hpfs_fs();
 #endif
 
 #ifdef CONFIG_ROOT_NFS
diff -u --recursive --new-file v1.3.57/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v1.3.57/linux/fs/hpfs/hpfs_fs.c	Thu Jan  4 21:54:56 1996
+++ linux/fs/hpfs/hpfs_fs.c	Mon Jan 15 07:59:09 1996
@@ -1744,15 +1744,23 @@
 	kfree_s(qbh->data, 2048);
 }
 
-#ifdef MODULE
-
 static struct file_system_type hpfs_fs_type = {
         hpfs_read_super, "hpfs", 1, NULL
 };
 
-int init_module(void)
+int init_hpfs_fs(void)
 {
         return register_filesystem(&hpfs_fs_type);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	int status;
+
+	if ((status = init_hpfs_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v1.3.57/linux/fs/isofs/inode.c	Tue Dec 26 04:45:38 1995
+++ linux/fs/isofs/inode.c	Mon Jan 15 07:59:10 1996
@@ -801,15 +801,23 @@
 
 #endif
 
-#ifdef MODULE
-
 static struct file_system_type iso9660_fs_type = {
 	isofs_read_super, "iso9660", 1, NULL
 };
 
+int init_iso9660_fs(void)
+{
+        return register_filesystem(&iso9660_fs_type);
+}
+
+#ifdef MODULE
 int init_module(void)
 {
-	return register_filesystem(&iso9660_fs_type);
+	int status;
+
+	if ((status = init_iso9660_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v1.3.57/linux/fs/minix/inode.c	Thu Jan  4 21:54:57 1996
+++ linux/fs/minix/inode.c	Mon Jan 15 07:59:11 1996
@@ -873,15 +873,23 @@
 	return err;
 }
 
-#ifdef MODULE
-
 static struct file_system_type minix_fs_type = {
 	minix_read_super, "minix", 1, NULL
 };
 
+int init_minix_fs(void)
+{
+        return register_filesystem(&minix_fs_type);
+}
+
+#ifdef MODULE
 int init_module(void)
 {
-	return register_filesystem(&minix_fs_type);
+	int status;
+
+	if ((status = init_minix_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/msdos/Makefile linux/fs/msdos/Makefile
--- v1.3.57/linux/fs/msdos/Makefile	Tue Aug 15 20:39:04 1995
+++ linux/fs/msdos/Makefile	Mon Jan 15 07:59:11 1996
@@ -8,7 +8,8 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := msdos.o
-O_OBJS   := buffer.o namei.o inode.o file.o dir.o misc.o fat.o mmap.o
+O_OBJS   := buffer.o namei.o file.o dir.o misc.o fat.o mmap.o
+OX_OBJS  := inode.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.57/linux/fs/msdos/inode.c linux/fs/msdos/inode.c
--- v1.3.57/linux/fs/msdos/inode.c	Sun Jan 14 16:30:12 1996
+++ linux/fs/msdos/inode.c	Mon Jan 15 07:59:11 1996
@@ -515,15 +515,55 @@
 	return 0;
 }
 
-#ifdef MODULE
+static struct symbol_table msdos_syms = {
+/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
+#include <linux/symtab_begin.h>
+	/*
+	 * Support for umsdos fs
+	 *
+	 * These symbols are _always_ exported, in case someone
+	 * wants to install the umsdos module later.
+	 */
+	X(msdos_bmap),
+	X(msdos_create),
+	X(msdos_file_read),
+	X(msdos_file_write),
+	X(msdos_lookup),
+	X(msdos_mkdir),
+	X(msdos_mmap),
+	X(msdos_put_inode),
+	X(msdos_put_super),
+	X(msdos_read_inode),
+	X(msdos_read_super),
+	X(msdos_readdir),
+	X(msdos_rename),
+	X(msdos_rmdir),
+	X(msdos_smap),
+	X(msdos_statfs),
+	X(msdos_truncate),
+	X(msdos_unlink),
+	X(msdos_unlink_umsdos),
+	X(msdos_write_inode),
+#include <linux/symtab_end.h>
+};
 
 static struct file_system_type msdos_fs_type = {
 	msdos_read_super, "msdos", 1, NULL
 };
 
+int init_msdos_fs(void)
+{
+	int status;
+
+	if ((status = register_filesystem(&msdos_fs_type)) == 0)
+		status = register_symtab(&msdos_syms);
+	return status;
+}
+
+#ifdef MODULE
 int init_module(void)
 {
-	return register_filesystem(&msdos_fs_type);
+	return init_msdos_fs();
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v1.3.57/linux/fs/ncpfs/dir.c	Tue Jan  2 16:46:28 1996
+++ linux/fs/ncpfs/dir.c	Sun Jan 14 15:37:42 1996
@@ -551,6 +551,7 @@
         root->finfo.opened = 0;
 	i->attributes  = aDIR;
 	i->dataStreamSize = 1024;
+	i->volNumber = NCP_NUMBER_OF_VOLUMES+1;	/* illegal volnum */
 	ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
 	ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
 	ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
@@ -608,6 +609,7 @@
         do
 	{
 		if (   (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum)
+		    && (result->dir->finfo.i.volNumber == dir_info->volNumber)
 		    && (strcmp(result->finfo.i.entryName, name) == 0))
 		{
                         return result;
@@ -626,8 +628,9 @@
 {
 	struct nw_file_info finfo;
 	struct ncp_server *server;
-        struct ncp_inode_info *result_info;
-        int found_in_cache;
+	struct ncp_inode_info *result_info;
+	int found_in_cache;
+	char name[len+1];
 
 	*result = NULL;
 
@@ -671,7 +674,9 @@
 		}
 	}
 
-        result_info = ncp_find_inode(dir, __name);
+	memcpy(name, __name, len);
+	name[len] = 0;
+	result_info = ncp_find_inode(dir, name);
 
         if (result_info != 0)
 	{
@@ -710,7 +715,7 @@
                         DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
                                 i, c_entry[i].i.entryName);
 
-                        if (strcmp(c_entry[i].i.entryName, __name) == 0)
+                        if (strcmp(c_entry[i].i.entryName, name) == 0)
 			{
                                 DPRINTK("ncp_lookup: found in cache!\n");
 				finfo.i = c_entry[i].i;
@@ -724,20 +729,15 @@
 
         if (found_in_cache == 0)
 	{
-		char this_name[len+1];
-
-		memcpy(this_name, __name, len);
-		this_name[len] = 0;
-		str_upper(this_name);
+		str_upper(name);
 
 		DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
-			 NCP_ISTRUCT(dir)->entryName, this_name);
+			 NCP_ISTRUCT(dir)->entryName, name);
 
 		if (ncp_do_lookup(server,
 				  dir->i_ino == (int)&(NCP_SERVER(dir)->root)
 				  ? NULL : NCP_ISTRUCT(dir),
-				  this_name,
-				  &(finfo.i)) != 0)
+				  name, &(finfo.i)) != 0)
 		{
                         iput(dir);
                         return -ENOENT;
diff -u --recursive --new-file v1.3.57/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v1.3.57/linux/fs/ncpfs/inode.c	Tue Jan  2 16:46:28 1996
+++ linux/fs/ncpfs/inode.c	Mon Jan 15 07:59:11 1996
@@ -483,25 +483,31 @@
 int ncp_current_malloced;
 #endif
 
-#ifdef MODULE
-
 static struct file_system_type ncp_fs_type = {
         ncp_read_super, "ncpfs", 0, NULL
         };
 
-int
+int init_ncp_fs(void)
+{
+        return register_filesystem(&ncp_fs_type);
+}
+
+#ifdef MODULE
 init_module( void)
 {
+	int status;
+
         DPRINTK("ncpfs: init_module called\n");
 
 #ifdef DEBUG_NCP_MALLOC
         ncp_malloced = 0;
         ncp_current_malloced = 0;
 #endif
-
         ncp_init_dir_cache();
-        register_filesystem(&ncp_fs_type);
-        return 0;
+
+	if ((status = init_ncp_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void
diff -u --recursive --new-file v1.3.57/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v1.3.57/linux/fs/nfs/inode.c	Thu Jan  4 21:54:58 1996
+++ linux/fs/nfs/inode.c	Mon Jan 15 07:59:11 1996
@@ -288,17 +288,25 @@
 	return error;
 }
 
-#ifdef MODULE
-
 /* Every kernel module contains stuff like this. */
 
 static struct file_system_type nfs_fs_type = {
 	nfs_read_super, "nfs", 0, NULL
 };
 
+int init_nfs_fs(void)
+{
+        return register_filesystem(&nfs_fs_type);
+}
+
+#ifdef MODULE
 int init_module(void)
 {
-	return register_filesystem(&nfs_fs_type);
+	int status;
+
+	if ((status = init_nfs_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v1.3.57/linux/fs/nfs/nfsroot.c	Sun Jan 14 16:30:12 1996
+++ linux/fs/nfs/nfsroot.c	Wed Jan 17 07:32:09 1996
@@ -15,6 +15,7 @@
  *
  *	Alan Cox	:	Removed get_address name clash with FPU.
  *	Alan Cox	:	Reformatted a bit.
+ *	Michael Rausch  :	Fixed recognition of an incoming RARP answer.
  *
  */
 
@@ -317,6 +318,7 @@
 {
 	int retries = 0;
 	unsigned long timeout = 0;
+	volatile struct device **root_dev_ptr = (volatile struct device **) &root_dev;
 
 	/* Setup RARP protocol */
 	root_rarp_open();
@@ -329,16 +331,16 @@
 	 * [Actually we could now, but the nothing else running note still 
 	 *  applies.. - AC]
 	 */
-	for (retries = 0; retries < RARP_RETRIES && root_dev == NULL; retries++) {
+	for (retries = 0; retries < RARP_RETRIES && *root_dev_ptr == NULL; retries++) {
 		if (root_rarp_send() < 0)
 			break;
 		timeout = jiffies + (RARP_TIMEOUT * HZ);
-		while (jiffies < timeout && root_dev == NULL)
-			;;
+		while (jiffies < timeout && *root_dev_ptr == NULL)
+			;
 	}
 
 	root_rarp_close();
-	if (root_dev == NULL && timeout > 0) {
+	if (*root_dev_ptr == NULL && timeout > 0) {
 		printk(KERN_ERR "NFS: Timed out while waiting for RARP answer\n");
 		return -1;
 	}
diff -u --recursive --new-file v1.3.57/linux/fs/proc/Makefile linux/fs/proc/Makefile
--- v1.3.57/linux/fs/proc/Makefile	Sat Dec 30 15:50:54 1995
+++ linux/fs/proc/Makefile	Thu Jan 18 07:06:17 1996
@@ -8,12 +8,8 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := proc.o
-O_OBJS   := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o
+O_OBJS   := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o
+OX_OBJS  := procfs_syms.o
 M_OBJS   := $(O_TARGET)
-
-# For either CONFIG_SCSI=y or CONFIG_SCSI=m
-ifdef CONFIG_SCSI
-O_OBJS += scsi.o
-endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.57/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v1.3.57/linux/fs/proc/inode.c	Sat Dec 30 15:50:54 1995
+++ linux/fs/proc/inode.c	Thu Jan 18 10:09:25 1996
@@ -12,7 +12,6 @@
 #include <linux/stat.h>
 #include <linux/locks.h>
 #include <linux/limits.h>
-#include <linux/config.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -171,13 +170,11 @@
 			case PROC_NET:
 				inode->i_nlink = 2;
 				break;
-#ifdef CONFIG_SCSI
 			case PROC_SCSI:
                                 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
                                 inode->i_nlink = 2;
                                 inode->i_op = &proc_scsi_inode_operations;
                                 break;
-#endif
 			case PROC_KCORE:
 				inode->i_mode = S_IFREG | S_IRUSR;
 				inode->i_op = &proc_kcore_inode_operations;
diff -u --recursive --new-file v1.3.57/linux/fs/proc/net.c linux/fs/proc/net.c
--- v1.3.57/linux/fs/proc/net.c	Tue Dec 26 04:45:40 1995
+++ linux/fs/proc/net.c	Sun Jan 14 16:47:28 1996
@@ -24,16 +24,14 @@
  *
  *  proc net directory handling functions
  */
-#include <linux/autoconf.h>
-
-#include <asm/segment.h>
-
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
+
+#include <asm/segment.h>
 
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
diff -u --recursive --new-file v1.3.57/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c
--- v1.3.57/linux/fs/proc/procfs_syms.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/proc/procfs_syms.c	Mon Jan 15 09:09:16 1996
@@ -0,0 +1,35 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+
+static struct symbol_table procfs_syms = {
+/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
+#include <linux/symtab_begin.h>
+	X(proc_register),
+	X(proc_unregister),
+	X(in_group_p),
+	X(generate_cluster),
+	X(proc_net_inode_operations),
+	X(proc_net),
+#ifdef CONFIG_SCSI /* Ugh... */
+	X(proc_scsi),
+	X(proc_scsi_inode_operations),
+	X(dispatch_scsi_info_ptr),
+#endif
+#include <linux/symtab_end.h>
+};
+
+static struct file_system_type proc_fs_type = {
+	proc_read_super, "proc", 0, NULL
+};
+
+int init_proc_fs(void)
+{
+	int status;
+
+        if ((status = register_filesystem(&proc_fs_type)) == 0)
+		status = register_symtab(&procfs_syms);
+	return status;
+}
+
diff -u --recursive --new-file v1.3.57/linux/fs/proc/scsi.c linux/fs/proc/scsi.c
--- v1.3.57/linux/fs/proc/scsi.c	Sat Dec 30 15:50:55 1995
+++ linux/fs/proc/scsi.c	Sun Jan 14 16:48:05 1996
@@ -20,13 +20,13 @@
  *  TODO: Improve support to write to the driver files
  *	  Add some more comments
  */
-#include <linux/autoconf.h>
-#include <asm/segment.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/mm.h>
+
+#include <asm/segment.h>
 
 /* forward references */
 static int proc_readscsi(struct inode * inode, struct file * file,
diff -u --recursive --new-file v1.3.57/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v1.3.57/linux/fs/smbfs/inode.c	Tue Jan  2 16:46:28 1996
+++ linux/fs/smbfs/inode.c	Mon Jan 15 07:59:11 1996
@@ -403,15 +403,20 @@
 int smb_current_malloced;
 #endif
 
-#ifdef MODULE
-
 static struct file_system_type smb_fs_type = {
         smb_read_super, "smbfs", 0, NULL
         };
 
-int
-init_module( void)
+int init_smb_fs(void)
 {
+        return register_filesystem(&smb_fs_type);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	int status;
+
         DPRINTK("smbfs: init_module called\n");
 
 #ifdef DEBUG_SMB_MALLOC
@@ -420,7 +425,10 @@
 #endif
 
         smb_init_dir_cache();
-        return register_filesystem(&smb_fs_type);
+
+	if ((status = init_smb_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void
diff -u --recursive --new-file v1.3.57/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v1.3.57/linux/fs/smbfs/proc.c	Tue Jan  2 16:46:29 1996
+++ linux/fs/smbfs/proc.c	Sun Jan 14 16:22:17 1996
@@ -1664,7 +1664,7 @@
 	}
 	
 	if (server->packet[0] != 0x82) {
-		printk("smb_proc_connect: Did not recieve positive response "
+		printk("smb_proc_connect: Did not receive positive response "
                        "(err = %x)\n", 
 		       server->packet[0]);
                 smb_dont_catch_keepalive(server);
diff -u --recursive --new-file v1.3.57/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v1.3.57/linux/fs/sysv/inode.c	Mon Nov 27 12:48:32 1995
+++ linux/fs/sysv/inode.c	Mon Jan 15 07:59:12 1996
@@ -969,8 +969,6 @@
         return err;
 }
 
-#ifdef MODULE
-
 /* Every kernel module contains stuff like this. */
 
 static struct file_system_type sysv_fs_type[3] = {
@@ -979,7 +977,7 @@
 	{sysv_read_super, "coherent", 1, NULL}
 };
 
-int init_module(void)
+int init_sysv_fs(void)
 {
 	int i;
 	int ouch;
@@ -988,7 +986,17 @@
 		if ((ouch = register_filesystem(&sysv_fs_type[i])) != 0)
 			return ouch;
 	}
-	return 0;
+        return ouch;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	int status;
+
+	if ((status = init_sysv_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v1.3.57/linux/fs/umsdos/inode.c	Sun Dec 17 11:43:20 1995
+++ linux/fs/umsdos/inode.c	Mon Jan 15 07:59:12 1996
@@ -494,15 +494,23 @@
 }
 
 
-#ifdef MODULE
-
 static struct file_system_type umsdos_fs_type = {
 	UMSDOS_read_super, "umsdos", 1, NULL
 };
 
+int init_umsdos_fs(void)
+{
+        return register_filesystem(&umsdos_fs_type);
+}
+
+#ifdef MODULE
 int init_module(void)
 {
-	return register_filesystem(&umsdos_fs_type);
+	int status;
+
+	if ((status = init_umsdos_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/fs/xiafs/inode.c linux/fs/xiafs/inode.c
--- v1.3.57/linux/fs/xiafs/inode.c	Mon Nov 27 12:48:32 1995
+++ linux/fs/xiafs/inode.c	Mon Jan 15 07:59:13 1996
@@ -511,17 +511,25 @@
     return err;
 }
 
-#ifdef MODULE
-
 /* Every kernel module contains stuff like this. */
 
 static struct file_system_type xiafs_fs_type = {
 	xiafs_read_super, "xiafs", 1, NULL
 };
 
+int init_xiafs_fs(void)
+{
+        return register_filesystem(&xiafs_fs_type);
+}
+
+#ifdef MODULE
 int init_module(void)
 {
-	return register_filesystem(&xiafs_fs_type);
+	int status;
+
+	if ((status = init_xiafs_fs()) == 0)
+		register_symtab(0);
+	return status;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.57/linux/include/asm-alpha/param.h linux/include/asm-alpha/param.h
--- v1.3.57/linux/include/asm-alpha/param.h	Tue Dec 26 04:45:40 1995
+++ linux/include/asm-alpha/param.h	Sat Jan 13 11:09:26 1996
@@ -4,8 +4,7 @@
 #include <linux/config.h>
 
 #ifndef HZ
-# if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P) || \
-     defined(CONFIG_ALPHA_EB64P)
+# if defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P)
 #  define HZ	 977	/* Evaluation Boards seem to be a little odd */
 # else
 #  define HZ	1024	/* normal value for Alpha systems */
diff -u --recursive --new-file v1.3.57/linux/include/asm-i386/delay.h linux/include/asm-i386/delay.h
--- v1.3.57/linux/include/asm-i386/delay.h	Wed Nov  8 07:11:41 1995
+++ linux/include/asm-i386/delay.h	Thu Jan 18 06:32:06 1996
@@ -13,7 +13,11 @@
 
 extern __inline__ void __delay(int loops)
 {
-	__asm__(".align 2,0x90\n1:\tdecl %0\n\tjns 1b": :"a" (loops):"ax");
+	__asm__ __volatile__(
+		".align 2,0x90\n1:\tdecl %0\n\tjns 1b"
+		:/* no outputs */
+		:"a" (loops)
+		:"ax");
 }
 
 /*
diff -u --recursive --new-file v1.3.57/linux/include/linux/blk.h linux/include/linux/blk.h
--- v1.3.57/linux/include/linux/blk.h	Sun Dec 17 11:43:32 1995
+++ linux/include/linux/blk.h	Thu Jan 18 10:17:08 1996
@@ -340,7 +340,7 @@
 
 #if ! SCSI_MAJOR(MAJOR_NR)
 
-#if defined(_IDE_CD_C) || defined(_TRITON_C) || defined(_IDE_TAPE_C) /* shares copy with ide.c */
+#if defined(IDE_DRIVER) && !defined(_IDE_C) /* shared copy for IDE modules */
 void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
 #else
 
@@ -393,7 +393,7 @@
 	req->rq_status = RQ_INACTIVE;
 	wake_up(&wait_for_request);
 }
-#endif /* ndef _IDE_CD_C */
+#endif /* defined(IDE_DRIVER) && !defined(_IDE_C) */
 #endif /* ! SCSI_MAJOR(MAJOR_NR) */
 
 #endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */
diff -u --recursive --new-file v1.3.57/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v1.3.57/linux/include/linux/ext2_fs.h	Mon Dec 11 15:42:05 1995
+++ linux/include/linux/ext2_fs.h	Mon Jan 15 07:59:13 1996
@@ -475,6 +475,7 @@
 extern void ext2_write_super (struct super_block *);
 extern int ext2_remount (struct super_block *, int *, char *);
 extern struct super_block * ext2_read_super (struct super_block *,void *,int);
+extern int init_ext2_fs(void);
 extern void ext2_statfs (struct super_block *, struct statfs *, int);
 
 /* truncate.c */
diff -u --recursive --new-file v1.3.57/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h
--- v1.3.57/linux/include/linux/ext2_fs_sb.h	Tue Jul 11 10:02:59 1995
+++ linux/include/linux/ext2_fs_sb.h	Mon Jan 15 09:12:08 1996
@@ -16,6 +16,8 @@
 #ifndef _LINUX_EXT2_FS_SB
 #define _LINUX_EXT2_FS_SB
 
+#include <linux/ext2_fs.h>
+
 /*
  * The following is not needed anymore since the descriptors buffer
  * heads are now dynamically allocated
diff -u --recursive --new-file v1.3.57/linux/include/linux/ext_fs.h linux/include/linux/ext_fs.h
--- v1.3.57/linux/include/linux/ext_fs.h	Mon Dec 11 15:42:05 1995
+++ linux/include/linux/ext_fs.h	Mon Jan 15 07:59:13 1996
@@ -91,6 +91,7 @@
 extern void ext_put_super(struct super_block *);
 extern void ext_write_super(struct super_block *);
 extern struct super_block *ext_read_super(struct super_block *,void *,int);
+extern int init_ext_fs(void);
 extern void ext_read_inode(struct inode *);
 extern void ext_write_inode(struct inode *);
 extern void ext_put_inode(struct inode *);
diff -u --recursive --new-file v1.3.57/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.3.57/linux/include/linux/fs.h	Sun Jan 14 16:30:14 1996
+++ linux/include/linux/fs.h	Thu Jan 18 06:41:22 1996
@@ -136,14 +136,35 @@
 #define BH_Touched	4	/* 1 if the buffer has been touched (aging) */
 #define BH_Has_aged	5	/* 1 if the buffer has been aged (aging) */
 #define BH_Protected	6	/* 1 if the buffer is protected */
+#define BH_FreeOnIO	7	/* 1 to discard the buffer_head after IO */
 
+/*
+ * Try to keep the most commonly used fields in single cache lines (16
+ * bytes) to improve performance.  This ordering should be
+ * particularly beneficial on 32-bit processors.
+ * 
+ * We use the first 16 bytes for the data which is used in searches
+ * over the block hash lists (ie. getblk(), find_buffer() and
+ * friends).
+ * 
+ * The second 16 bytes we use for lru buffer scans, as used by
+ * sync_buffers() and refill_freelist().  -- sct
+ */
 struct buffer_head {
-	char * b_data;			/* pointer to data block (1024 bytes) */
-	unsigned long b_size;		/* block size */
+	/* First cache line: */
 	unsigned long b_blocknr;	/* block number */
 	kdev_t b_dev;			/* device (B_FREE = free) */
+	struct buffer_head * b_next;	/* Hash queue list */
+	struct buffer_head * b_this_page;	/* circular list of buffers in one page */
+
+	/* Second cache line: */
 	unsigned long b_state;		/* buffer state bitmap (see above) */
+	struct buffer_head * b_next_free;
 	unsigned int b_count;		/* users using this block */
+	unsigned long b_size;		/* block size */
+
+	/* Non-performance-critical data follows. */
+	char * b_data;			/* pointer to data block (1024 bytes) */
 	unsigned int b_list;		/* List that this buffer appears */
 	unsigned long b_flushtime;      /* Time when this (dirty) buffer
 					 * should be written */
@@ -151,10 +172,7 @@
 					 * last used. */
 	struct wait_queue * b_wait;
 	struct buffer_head * b_prev;		/* doubly linked list of hash-queue */
-	struct buffer_head * b_next;
 	struct buffer_head * b_prev_free;	/* doubly linked list of buffers */
-	struct buffer_head * b_next_free;
-	struct buffer_head * b_this_page;	/* circular list of buffers in one page */
 	struct buffer_head * b_reqnext;		/* request queue */
 };
 
@@ -507,13 +525,7 @@
 #define BUF_SHARED 5   /* Buffers shared */
 #define NR_LIST 6
 
-extern inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
-{
-	if (on)
-		set_bit(BH_Uptodate, &bh->b_state);
-	else
-		clear_bit(BH_Uptodate, &bh->b_state);
-}
+void mark_buffer_uptodate(struct buffer_head * bh, int on);
 
 extern inline void mark_buffer_clean(struct buffer_head * bh)
 {
diff -u --recursive --new-file v1.3.57/linux/include/linux/hpfs_fs.h linux/include/linux/hpfs_fs.h
--- v1.3.57/linux/include/linux/hpfs_fs.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/hpfs_fs.h	Mon Jan 15 07:59:13 1996
@@ -8,5 +8,6 @@
 /* The entry point for a VFS */
 
 extern struct super_block *hpfs_read_super (struct super_block *, void *, int);
+extern int init_hpfs_fs(void);
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- v1.3.57/linux/include/linux/iso_fs.h	Mon Dec 11 15:42:05 1995
+++ linux/include/linux/iso_fs.h	Mon Jan 15 07:59:14 1996
@@ -175,6 +175,7 @@
 
 extern void isofs_put_super(struct super_block *);
 extern struct super_block *isofs_read_super(struct super_block *,void *,int);
+extern int init_iso9660_fs(void);
 extern void isofs_read_inode(struct inode *);
 extern void isofs_put_inode(struct inode *);
 extern void isofs_statfs(struct super_block *, struct statfs *, int);
diff -u --recursive --new-file v1.3.57/linux/include/linux/locks.h linux/include/linux/locks.h
--- v1.3.57/linux/include/linux/locks.h	Mon Nov 27 12:48:36 1995
+++ linux/include/linux/locks.h	Thu Jan 18 06:52:42 1996
@@ -1,6 +1,16 @@
 #ifndef _LINUX_LOCKS_H
 #define _LINUX_LOCKS_H
 
+#ifndef _LINUX_MM_H
+#include <linux/mm.h>
+#endif
+
+/*
+ * Unlocked, temporary IO buffer_heads gets moved to the reuse_list
+ * once their page becomes unlocked.  
+ */
+extern struct buffer_head *reuse_list;
+
 /*
  * Buffer cache locking - note that interrupts may only unlock, not
  * lock buffers.
@@ -21,8 +31,36 @@
 
 extern inline void unlock_buffer(struct buffer_head * bh)
 {
+	struct buffer_head *tmp = bh;
+	int page_locked = 0;
+	unsigned long flags;
+	
 	clear_bit(BH_Lock, &bh->b_state);
 	wake_up(&bh->b_wait);
+	do {
+		if (test_bit(BH_Lock, &tmp->b_state)) {
+			page_locked = 1;
+			break;
+		}
+		tmp=tmp->b_this_page;
+	} while (tmp && tmp != bh);
+	save_flags(flags);
+	if (!page_locked) {
+		struct page *page = mem_map + MAP_NR(bh->b_data);
+		page->locked = 0;
+		wake_up(&page->wait);
+		tmp = bh;
+		cli();
+		do {
+			if (test_bit(BH_FreeOnIO, &tmp->b_state)) {
+				tmp->b_next_free = reuse_list;
+				reuse_list = tmp;
+				clear_bit(BH_FreeOnIO, &tmp->b_state);
+			}
+			tmp = tmp->b_this_page;
+		} while (tmp && tmp != bh);
+		restore_flags(flags);
+	}
 }
 
 /*
diff -u --recursive --new-file v1.3.57/linux/include/linux/mcdx.h linux/include/linux/mcdx.h
--- v1.3.57/linux/include/linux/mcdx.h	Tue Nov 21 13:22:13 1995
+++ linux/include/linux/mcdx.h	Sun Jan 14 16:22:16 1996
@@ -1,7 +1,7 @@
 /*
  * Definitions for the Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 1.5
+ * VERSION: 1.5a
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff -u --recursive --new-file v1.3.57/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v1.3.57/linux/include/linux/minix_fs.h	Thu Jan  4 21:54:59 1996
+++ linux/include/linux/minix_fs.h	Mon Jan 15 07:59:14 1996
@@ -116,6 +116,7 @@
 extern void minix_truncate(struct inode *);
 extern void minix_put_super(struct super_block *);
 extern struct super_block *minix_read_super(struct super_block *,void *,int);
+extern int init_minix_fs(void);
 extern void minix_write_super(struct super_block *);
 extern int minix_remount (struct super_block * sb, int * flags, char * data);
 extern void minix_read_inode(struct inode *);
diff -u --recursive --new-file v1.3.57/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.3.57/linux/include/linux/mm.h	Sun Jan 14 16:30:14 1996
+++ linux/include/linux/mm.h	Thu Jan 18 06:52:36 1996
@@ -105,6 +105,15 @@
 	pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
 };
 
+/*
+ * Try to keep the most commonly accessed fields in single cache lines
+ * here (16 bytes or greater).  This ordering should be particularly
+ * beneficial on 32-bit processors.
+ *
+ * The first line is data used in linear searches (eg. clock algorithm
+ * scans).  The second line is data used in page searches through the
+ * page-cache.  -- sct 
+ */
 typedef struct page {
 	unsigned int count;
 	unsigned dirty:16,
@@ -112,14 +121,19 @@
 		 uptodate:1,
 		 error:1,
 		 referenced:1,
-		 unused:4,
+		 locked:1,
+		 unused:3,
 		 reserved:1;
+	struct wait_queue *wait;
+	struct page *next;
+
+	struct page *next_hash;
 	unsigned long offset;
 	struct inode *inode;
-	struct wait_queue *wait;
 	struct page *write_list;
-	struct page *next, *prev;
-	struct page *next_hash, *prev_hash;
+
+	struct page *prev;
+	struct page *prev_hash;
 } mem_map_t;
 
 extern mem_map_t * mem_map;
diff -u --recursive --new-file v1.3.57/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v1.3.57/linux/include/linux/msdos_fs.h	Mon Dec 11 15:42:05 1995
+++ linux/include/linux/msdos_fs.h	Thu Jan 18 06:57:23 1996
@@ -164,6 +164,7 @@
 extern void msdos_put_super(struct super_block *sb);
 extern struct super_block *msdos_read_super(struct super_block *s,
 					    void *data,int);
+extern int init_msdos_fs(void);
 extern void msdos_statfs(struct super_block *sb,struct statfs *buf, int);
 extern int msdos_bmap(struct inode *inode,int block);
 extern void msdos_read_inode(struct inode *inode);
diff -u --recursive --new-file v1.3.57/linux/include/linux/ncp_fs.h linux/include/linux/ncp_fs.h
--- v1.3.57/linux/include/linux/ncp_fs.h	Thu Jan  4 21:54:59 1996
+++ linux/include/linux/ncp_fs.h	Thu Jan 18 06:59:37 1996
@@ -142,6 +142,7 @@
 /* linux/fs/ncpfs/inode.c */
 struct super_block *ncp_read_super(struct super_block *sb,
                                    void *raw_data, int silent);
+extern int init_ncp_fs(void);
 void ncp_invalidate_connection(struct ncp_server *server);
 int ncp_conn_is_valid(struct ncp_server *server);
 
diff -u --recursive --new-file v1.3.57/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v1.3.57/linux/include/linux/nfs_fs.h	Fri Nov 17 08:42:28 1995
+++ linux/include/linux/nfs_fs.h	Mon Jan 15 07:59:14 1996
@@ -98,6 +98,7 @@
 
 extern struct super_block *nfs_read_super(struct super_block *sb, 
 					  void *data,int);
+extern int init_nfs_fs(void);
 extern struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
 			       struct nfs_fattr *fattr);
 extern void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr);
diff -u --recursive --new-file v1.3.57/linux/include/linux/optcd.h linux/include/linux/optcd.h
--- v1.3.57/linux/include/linux/optcd.h	Mon Sep 18 14:54:09 1995
+++ linux/include/linux/optcd.h	Thu Jan 18 06:22:13 1996
@@ -1,200 +1,48 @@
+/*	linux/include/linux/optcd.h - Optics Storage 8000 AT CDROM driver
+	$Id: optcd.h,v 1.2 1996/01/15 18:43:44 root Exp root $
 
-/* Defines for the Optics Storage 8000AT CDROM drive. */
+	Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
 
-#ifndef _LINUX_OPTCD_H
 
+	Configuration file for linux/drivers/cdrom/optcd.c
+*/
+
+#ifndef _LINUX_OPTCD_H
 #define _LINUX_OPTCD_H
 
-/* Drive registers */
+
+/* I/O base of drive. Drive uses base to base+2.
+   This setting can be overridden with the kernel or insmod command
+   line option 'optcd=<portbase>'. Use address of 0 to disable driver. */
 #define OPTCD_PORTBASE	0x340
-/* Read */
-#define DATA_PORT	optcd_port	/* Read data/status */
-#define STATUS_PORT	optcd_port+1	/* Indicate data/status availability */
-/* Write */
-#define COMIN_PORT	optcd_port	/* For passing command/parameter */
-#define RESET_PORT	optcd_port+1	/* Write anything and wait 0.5 sec */
-#define HCON_PORT	optcd_port+2	/* Host Xfer Configuration */
-
-
-/* Command completion/status read from DATA register */
-#define ST_DRVERR		0x80
-#define ST_DOOR_OPEN		0x40
-#define ST_MIXEDMODE_DISK	0x20
-#define ST_MODE_BITS		0x1c
-#define ST_M_STOP		0x00
-#define ST_M_READ		0x04
-#define ST_M_AUDIO		0x04
-#define ST_M_PAUSE		0x08
-#define ST_M_INITIAL		0x0c
-#define ST_M_ERROR		0x10
-#define ST_M_OTHERS		0x14
-#define	ST_MODE2TRACK		0x02
-#define	ST_DSK_CHG		0x01
-#define ST_L_LOCK		0x01
-#define ST_CMD_OK		0x00
-#define ST_OP_OK		0x01
-#define ST_PA_OK		0x02
-#define ST_OP_ERROR		0x05
-#define ST_PA_ERROR		0x06
-
-/* Error codes (appear as command completion code from DATA register) */
-/* Player related errors */
-#define ERR_ILLCMD	0x11	/* Illegal command to player module */
-#define ERR_ILLPARM	0x12	/* Illegal parameter to player module */
-#define ERR_SLEDGE	0x13
-#define ERR_FOCUS	0x14
-#define ERR_MOTOR	0x15
-#define ERR_RADIAL	0x16
-#define ERR_PLL		0x17	/* PLL lock error */
-#define ERR_SUB_TIM	0x18	/* Subcode timeout error */
-#define ERR_SUB_NF	0x19	/* Subcode not found error */
-#define ERR_TRAY	0x1a
-#define ERR_TOC		0x1b	/* Table of Contents read error */
-#define ERR_JUMP	0x1c
-/* Data errors */
-#define ERR_MODE	0x21
-#define ERR_FORM	0x22
-#define ERR_HEADADDR	0x23	/* Header Address not found */
-#define ERR_CRC		0x24
-#define ERR_ECC		0x25	/* Uncorrectable ECC error */
-#define ERR_CRC_UNC	0x26	/* CRC error and uncorrectable error */
-#define ERR_ILLBSYNC	0x27	/* Illegal block sync error */
-#define ERR_VDST	0x28	/* VDST not found */
-/* Timeout errors */
-#define ERR_READ_TIM	0x31	/* Read timeout error */
-#define ERR_DEC_STP	0x32	/* Decoder stopped */
-#define ERR_DEC_TIM	0x33	/* Decoder interrupt timeout error */
-/* Function abort codes */
-#define ERR_KEY		0x41	/* Key -Detected abort */
-#define ERR_READ_FINISH	0x42	/* Read Finish */
-/* Second Byte diagnostic codes */
-#define ERR_NOBSYNC	0x01	/* No block sync */
-#define ERR_SHORTB	0x02	/* Short block */
-#define ERR_LONGB	0x03	/* Long block */
-#define ERR_SHORTDSP	0x04	/* Short DSP word */
-#define ERR_LONGDSP	0x05	/* Long DSP word */
-
-
-/* Status availability flags read from STATUS register */
-#define FL_EJECT	0x20
-#define FL_WAIT		0x10	/* active low */
-#define FL_EOP		0x08	/* active low */
-#define FL_STEN		0x04	/* Status available when low */
-#define FL_DTEN		0x02	/* Data available when low */
-#define FL_DRQ		0x01	/* active low */
-#define FL_RESET	0xde	/* These bits are high after a reset */
-#define FL_STDT		(FL_STEN|FL_DTEN)
-
-
-/* Transfer mode, written to HCON register */
-#define HCON_DTS	0x08
-#define HCON_SDRQB	0x04
-#define HCON_LOHI	0x02
-#define HCON_DMA16	0x01
-
-
-/* Drive command set, written to COMIN register */
-/* Quick response commands */
-#define COMDRVST	0x20	/* Drive Status Read */
-#define COMERRST	0x21	/* Error Status Read */
-#define COMIOCTLISTAT	0x22	/* Status Read; reset disk changed bit */
-#define COMINITSINGLE	0x28	/* Initialize Single Speed */
-#define COMINITDOUBLE	0x29	/* Initialize Double Speed */
-#define COMUNLOCK	0x30	/* Unlock */
-#define COMLOCK		0x31	/* Lock */
-#define COMLOCKST	0x32	/* Lock/Unlock Status */
-#define COMVERSION	0x40	/* Get Firmware Revision */
-#define COMVOIDREADMODE	0x50	/* Void Data Read Mode */
-/* Read commands */
-#define COMFETCH	0x60	/* Prefetch Data */
-#define COMREAD		0x61	/* Read */
-#define COMREADRAW	0x62	/* Read Raw Data */
-#define COMREADALL	0x63	/* Read All 2646 Bytes */
-/* Player control commands */
-#define COMLEADIN	0x70	/* Seek To Lead-in */
-#define COMSEEK		0x71	/* Seek */
-#define COMPAUSEON	0x80	/* Pause On */
-#define COMPAUSEOFF	0x81	/* Pause Off */
-#define COMSTOP		0x82	/* Stop */
-#define COMOPEN		0x90	/* Open Tray Door */
-#define COMCLOSE	0x91	/* Close Tray Door */
-#define COMPLAY		0xa0	/* Audio Play */
-#define COMPLAY_TNO	0xa2	/* Audio Play By Track Number */
-#define COMSUBQ		0xb0	/* Read Sub-q Code */
-#define COMLOCATION	0xb1	/* Read Head Position */
-/* Audio control commands */
-#define COMCHCTRL	0xc0	/* Audio Channel Control */
-/* Miscellaneous (test) commands */
-#define COMDRVTEST	0xd0	/* Write Test Bytes */
-#define COMTEST		0xd1	/* Diagnostic Test */
 
 
+/* enable / disable parts of driver by define / undef */
+#define	MULTISESSION		/* multisession support (ALPHA) */
+#define	PROBE_ISP16		/* ISP16 interface card probing */
+/* ISP16 probing can also be suppressed with kernel command line option
+   'noisp16', or with insmod parameter 'noisp16=1'. */
+
+
+/* Change 0 to 1 to debug various parts of the driver */
+#define	DEBUG_DRIVE_IF	0	/* Low level drive interface */
+#define	DEBUG_CONV	0	/* Address conversions */
+#define	DEBUG_BUFFERS	0	/* Buffering and block size conversion */
+#define	DEBUG_REQUEST	0	/* Request mechanism */
+#define	DEBUG_STATE	0	/* State machine */
+#define	DEBUG_TOC	0	/* Q-channel and Table of Contents */
+#define	DEBUG_MULTIS	0	/* Multisession code */
+#define	DEBUG_VFS	0	/* VFS interface */
+
+
+/* Various timeout loop repetition counts. Don't touch unless you know
+   what you're doing. */
 #define BUSY_TIMEOUT		10000000	/* for busy wait */
-#define SLEEP_TIMEOUT		400		/* for timer wait */
+#define FAST_TIMEOUT		100000		/* ibid. for probing */
+#define SLEEP_TIMEOUT		3000		/* for timer wait */
+#define MULTI_SEEK_TIMEOUT	500		/* for timer wait */
 #define READ_TIMEOUT		3000		/* for poll wait */
-#define RESET_WAIT		1000
-
-#define SET_TIMER(func, jifs) \
-	delay_timer.expires = jiffies+(jifs); \
-	delay_timer.function = (void *) (func); \
-	add_timer(&delay_timer);
-#define CLEAR_TIMER		del_timer(&delay_timer)
-
-#define MAX_TRACKS		104
-
-struct msf {
-	unsigned char	min;
-	unsigned char	sec;
-	unsigned char	frame;
-};
-
-struct opt_Play_msf {
-	struct msf	start;
-	struct msf	end;
-};
-
-struct opt_DiskInfo {
-	unsigned char	first;
-	unsigned char	last;
-	struct msf	diskLength;
-	struct msf	firstTrack;
-};
-
-struct opt_Toc {
-	unsigned char	ctrl_addr;
-	unsigned char	track;
-	unsigned char	pointIndex;
-	struct msf	trackTime;
-	struct msf	diskTime;
-};
-
-
-#define CURRENT_VALID \
-	(CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
-	 && CURRENT -> cmd == READ && CURRENT -> sector != -1)
-
-
-#undef	DEBUG_DRIVE_IF		/* Low level drive interface */
-#undef	DEBUG_COMMANDS		/* Commands sent to drive */
-#undef	DEBUG_VFS		/* VFS interface */
-#undef	DEBUG_CONV		/* Address conversions */
-#undef	DEBUG_TOC		/* Q-channel and Table of Contents */
-#undef	DEBUG_BUFFERS		/* Buffering and block size conversion */
-#undef	DEBUG_REQUEST		/* Request mechanism */
-#undef	DEBUG_STATE		/* State machine */
-
-
-/* Low level drive interface */
-
-/* Errors that can occur in the low level interface */
-#define ERR_IF_CMD_TIMEOUT	0x100
-#define ERR_IF_ERR_TIMEOUT	0x101
-#define ERR_IF_RESP_TIMEOUT	0x102
-#define ERR_IF_DATA_TIMEOUT	0x103
-#define ERR_IF_NOSTAT		0x104
-/* Errors in table of contents */
-#define ERR_TOC_MISSINGINFO	0x120
-#define ERR_TOC_MISSINGENTRY	0x121
+#define STOP_TIMEOUT		1000		/* for poll wait */
+#define RESET_WAIT		1000		/* busy wait at drive reset */
 
-/* End .h defines */
 #endif _LINUX_OPTCD_H
diff -u --recursive --new-file v1.3.57/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v1.3.57/linux/include/linux/pagemap.h	Sun Jan 14 16:30:14 1996
+++ linux/include/linux/pagemap.h	Thu Jan 18 06:41:22 1996
@@ -110,6 +110,13 @@
 	*p = page;
 }
 
+extern void __wait_on_page(struct page *);
+static inline void wait_on_page(struct page * page)
+{
+	if (page->locked)
+		__wait_on_page(page);
+}
+
 extern void update_vm_cache(struct inode *, unsigned long, const char *, int);
 
 #endif
diff -u --recursive --new-file v1.3.57/linux/include/linux/pci.h linux/include/linux/pci.h
--- v1.3.57/linux/include/linux/pci.h	Sat Dec 30 15:50:55 1995
+++ linux/include/linux/pci.h	Sun Jan 14 16:22:16 1996
@@ -296,6 +296,7 @@
 #define PCI_DEVICE_ID_FD_36C70		0x0000
 
 #define PCI_VENDOR_ID_SI		0x1039
+#define PCI_DEVICE_ID_SI_6201		0x0001
 #define PCI_DEVICE_ID_SI_6202		0x0002
 #define PCI_DEVICE_ID_SI_503		0x0008
 #define PCI_DEVICE_ID_SI_501		0x0406
diff -u --recursive --new-file v1.3.57/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.3.57/linux/include/linux/proc_fs.h	Sun Jan 14 16:30:14 1996
+++ linux/include/linux/proc_fs.h	Thu Jan 18 06:52:42 1996
@@ -98,6 +98,7 @@
 
 enum scsi_directory_inos {
 	PROC_SCSI_SCSI = 256,
+	PROC_SCSI_ADVANSYS,
 	PROC_SCSI_EATA,
 	PROC_SCSI_EATA_PIO,
 	PROC_SCSI_AHA152X,
@@ -223,6 +224,7 @@
 }
 
 extern struct super_block *proc_read_super(struct super_block *,void *,int);
+extern int init_proc_fs(void);
 extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
 extern void proc_statfs(struct super_block *, struct statfs *, int);
 extern void proc_read_inode(struct inode *);
diff -u --recursive --new-file v1.3.57/linux/include/linux/quota.h linux/include/linux/quota.h
--- v1.3.57/linux/include/linux/quota.h	Mon Dec 11 15:42:05 1995
+++ linux/include/linux/quota.h	Sun Jan 14 16:22:15 1996
@@ -192,8 +192,6 @@
 /*
  * declaration of quota_function calls in kernel.
  */
-int quota_off (kdev_t dev, short type);
-int sync_dquots (kdev_t dev, short type);
 
 extern void dquot_initialize(struct inode *inode, short type);
 extern void dquot_drop(struct inode *inode);
diff -u --recursive --new-file v1.3.57/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.3.57/linux/include/linux/sched.h	Sat Jan  6 19:10:40 1996
+++ linux/include/linux/sched.h	Thu Jan 18 06:52:36 1996
@@ -316,6 +316,8 @@
 extern unsigned long prof_len;
 extern unsigned long prof_shift;
 
+extern int securelevel;	/* system security level */
+
 #define CURRENT_TIME (xtime.tv_sec)
 
 extern void sleep_on(struct wait_queue ** p);
diff -u --recursive --new-file v1.3.57/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v1.3.57/linux/include/linux/smb_fs.h	Tue Jan  2 16:46:30 1996
+++ linux/include/linux/smb_fs.h	Thu Jan 18 06:59:37 1996
@@ -114,6 +114,7 @@
 /* linux/fs/smbfs/inode.c */
 struct super_block *smb_read_super(struct super_block *sb,
                                    void *raw_data, int silent);
+extern int init_smb_fs(void);
 int smb_notify_change(struct inode *inode, struct iattr *attr);
 void smb_invalidate_connection(struct smb_server *server);
 int smb_conn_is_valid(struct smb_server *server);
diff -u --recursive --new-file v1.3.57/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v1.3.57/linux/include/linux/soundcard.h	Wed Nov  8 07:11:42 1995
+++ linux/include/linux/soundcard.h	Tue Jan  9 00:36:58 1996
@@ -148,6 +148,16 @@
 #define SNDCTL_TMR_SELECT		_IOW ('T', 8, int)
 
 /*
+ *	Endian aware patch key generation algorithm.
+ */
+
+#if defined(_AIX) || defined(AIX)
+#  define _PATCHKEY(id) (0xfd00|id)
+#else
+#  define _PATCHKEY(id) ((id<<8)|0xfd)
+#endif
+
+/*
  *	Sample loading mechanism for internal synthesizers (/dev/sequencer)
  *	The following patch_info structure has been designed to support
  *	Gravis UltraSound. It tries to be universal format for uploading
@@ -155,9 +165,10 @@
  */
 
 struct patch_info {
-		short key;		/* Use GUS_PATCH here */
-#define GUS_PATCH	0x04fd
-#define OBSOLETE_GUS_PATCH	0x02fd
+		unsigned short key;		/* Use GUS_PATCH here */
+#define GUS_PATCH	_PATCHKEY(0x04)
+#define OBSOLETE_GUS_PATCH	_PATCHKEY(0x02)
+
 		short device_no;	/* Synthesizer number */
 		short instr_no;		/* Midi pgm# */
 
@@ -236,8 +247,8 @@
 
 struct sysex_info {
 		short key;		/* Use GUS_PATCH here */
-#define SYSEX_PATCH	0x05fd
-#define MAUI_PATCH	0x06fd		/* For future use */
+#define SYSEX_PATCH	_PATCHKEY(0x05)
+#define MAUI_PATCH	_PATCHKEY(0x06)
 		short device_no;	/* Synthesizer number */
 		long len;	/* Size of the sysex data in bytes */
 		unsigned char data[1];	/* Sysex data starts here */
@@ -488,9 +499,9 @@
 typedef unsigned char sbi_instr_data[32];
 
 struct sbi_instrument {
-		unsigned short	key;		/* 	Initialize to FM_PATCH or OPL3_PATCH */
-#define FM_PATCH	0x01fd
-#define OPL3_PATCH	0x03fd
+		unsigned short	key;	/* FM_PATCH or OPL3_PATCH */
+#define FM_PATCH	_PATCHKEY(0x01)
+#define OPL3_PATCH	_PATCHKEY(0x03)
 		short		device;		/*	Synth# (0-4)	*/
 		int 		channel;	/*	Program# to be initialized 	*/
 		sbi_instr_data	operators;	/*	Register settings for operator cells (.SBI format)	*/
@@ -507,6 +518,7 @@
 		int	synth_subtype;
 #define FM_TYPE_ADLIB			0x00
 #define FM_TYPE_OPL3			0x01
+#define MIDI_TYPE_MPU401		0x401
 
 #define SAMPLE_TYPE_GUS			0x10
 
@@ -628,6 +640,7 @@
 	} buffmem_desc;
 #define SNDCTL_DSP_MAPINBUF		_IOR ('P', 19, buffmem_desc)
 #define SNDCTL_DSP_MAPOUTBUF		_IOR ('P', 20, buffmem_desc)
+#define SNDCTL_DSP_SETSYNCRO		_IO  ('P', 21)
 
 #define SOUND_PCM_READ_RATE		_IOR ('P', 2, int)
 #define SOUND_PCM_READ_CHANNELS		_IOR ('P', 6, int)
@@ -650,6 +663,7 @@
 #define SOUND_PCM_GETCAPS		SNDCTL_DSP_GETCAPS
 #define SOUND_PCM_GETTRIGGER		SNDCTL_DSP_GETTRIGGER
 #define SOUND_PCM_SETTRIGGER		SNDCTL_DSP_SETTRIGGER
+#define SOUND_PCM_SETSYNCRO		SNDCTL_DSP_SETSYNCRO
 #define SOUND_PCM_GETIPTR		SNDCTL_DSP_GETIPTR
 #define SOUND_PCM_GETOPTR		SNDCTL_DSP_GETOPTR
 #define SOUND_PCM_MAPINBUF		SNDCTL_DSP_MAPINBUF
@@ -739,10 +753,18 @@
 #define SOUND_ONOFF_MIN		28
 #define SOUND_ONOFF_MAX		30
 #define SOUND_MIXER_MUTE	28	/* 0 or 1 */
-#define SOUND_MIXER_ENHANCE	29	/* Enhanced stereo (0, 40, 60 or 80) */
 #define SOUND_MIXER_LOUD	30	/* 0 or 1 */
 
 /* Note!	Number 31 cannot be used since the sign bit is reserved */
+
+
+/*
+ * SOUND_MIXER_ENHANCE is an unsupported and undocumented call which
+ * will be removed from the API in future.
+ */
+#define SOUND_MIXER_ENHANCE	29	/* Enhanced stereo (0, 40, 60 or 80) */
+
+
 
 #define SOUND_DEVICE_LABELS	{"Vol  ", "Bass ", "Trebl", "Synth", "Pcm  ", "Spkr ", "Line ", \
 				 "Mic  ", "CD   ", "Mix  ", "Pcm2 ", "Rec  ", "IGain", "OGain", \
diff -u --recursive --new-file v1.3.57/linux/include/linux/swapctl.h linux/include/linux/swapctl.h
--- v1.3.57/linux/include/linux/swapctl.h	Sun Jan 14 16:30:15 1996
+++ linux/include/linux/swapctl.h	Thu Jan 18 06:41:22 1996
@@ -42,6 +42,17 @@
 typedef kswapd_control_v1 kswapd_control_t;
 extern kswapd_control_t kswapd_ctl;
 
+typedef struct swapstat_v1
+{
+	int	wakeups;
+	int	pages_reclaimed;
+	int	pages_shm;
+	int	pages_mmap;
+	int	pages_swap;
+} swapstat_v1;
+typedef swapstat_v1 swapstat_t;
+extern swapstat_t swapstats;
+
 #define SC_VERSION	1
 #define SC_MAX_VERSION	1
 
diff -u --recursive --new-file v1.3.57/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v1.3.57/linux/include/linux/sysctl.h	Sun Jan 14 16:30:15 1996
+++ linux/include/linux/sysctl.h	Wed Jan 17 07:31:59 1996
@@ -54,6 +54,7 @@
 #define KERN_NRFILE	11
 #define KERN_MAXFILE	12
 #define KERN_MAXID	13
+#define KERN_SECURELVL	14	/* int: system security level */
 
 /* CTL_VM names: */
 #define VM_SWAPCTL	1	/* struct: Set vm swapping control */
diff -u --recursive --new-file v1.3.57/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v1.3.57/linux/include/linux/sysv_fs.h	Mon Dec 11 15:42:06 1995
+++ linux/include/linux/sysv_fs.h	Thu Jan 18 06:59:37 1996
@@ -390,6 +390,7 @@
 extern void sysv_truncate(struct inode *);
 extern void sysv_put_super(struct super_block *);
 extern struct super_block *sysv_read_super(struct super_block *,void *,int);
+extern int init_sysv_fs(void);
 extern void sysv_write_super(struct super_block *);
 extern void sysv_read_inode(struct inode *);
 extern int sysv_notify_change(struct inode *, struct iattr *);
diff -u --recursive --new-file v1.3.57/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h
--- v1.3.57/linux/include/linux/umsdos_fs.h	Mon Nov 27 12:48:36 1995
+++ linux/include/linux/umsdos_fs.h	Thu Jan 18 06:59:37 1996
@@ -136,6 +136,7 @@
 extern struct inode_operations umsdos_file_inode_operations;
 extern struct inode_operations umsdos_file_inode_operations_no_bmap;
 extern struct inode_operations umsdos_symlink_inode_operations;
+extern int init_umsdos_fs(void);
 
 #include <linux/umsdos_fs.p>
 
diff -u --recursive --new-file v1.3.57/linux/include/linux/wrapper.h linux/include/linux/wrapper.h
--- v1.3.57/linux/include/linux/wrapper.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/wrapper.h	Wed Jan 17 09:33:33 1996
@@ -0,0 +1,40 @@
+#ifndef _WRAPPER_H_
+#define _WRAPPER_H_
+#define wait_handle struct wait_queue
+#define file_handle struct file
+#define inode_handle struct inode
+#define select_table_handle select_table
+#define vm_area_handle struct vm_area_struct
+#define file_operation_handle file_operations
+
+#define connect_wrapper(x) 0
+#define current_got_fatal_signal() (current->signal & ~current->blocked)
+#define current_set_timeout(val) current->timeout = val
+
+#define module_interruptible_sleep_on interruptible_sleep_on
+#define module_wake_up wake_up
+#define module_select_wait select_wait
+#define module_register_chrdev register_chrdev
+#define module_unregister_chrdev unregister_chrdev
+#define module_register_blkdev register_blkdev
+#define module_unregister_blkdev unregister_blkdev
+
+#define inode_get_rdev(i) i->i_rdev
+#define inode_get_count(i) i->i_count
+#define inode_inc_count(i) i->i_count++
+#define inode_dec_count(i) i->i_count--
+
+#define file_get_flags(f) f->f_flags
+
+#define vma_set_inode(v,i) v->vm_inode = i
+#define vma_get_flags(v) v->vm_flags
+#define vma_get_offset(v) v->vm_offset
+#define vma_get_start(v) v->vm_start
+#define vma_get_end(v) v->vm_end
+#define vma_get_page_prot(v) v->vm_page_prot
+
+#define mem_map_reserve(p) mem_map[p].reserved = 1
+#define mem_map_unreserve(p) mem_map[p].reserved = 0
+#define mem_map_inc_count(p) mem_map[p].count++
+#define mem_map_dec_count(p) mem_map[p].count--
+#endif
diff -u --recursive --new-file v1.3.57/linux/include/linux/xia_fs.h linux/include/linux/xia_fs.h
--- v1.3.57/linux/include/linux/xia_fs.h	Mon Jun 12 17:03:19 1995
+++ linux/include/linux/xia_fs.h	Mon Jan 15 07:59:14 1996
@@ -95,6 +95,7 @@
 extern void xiafs_truncate(struct inode *);
 extern void xiafs_put_super(struct super_block *);
 extern struct super_block *xiafs_read_super(struct super_block *,void *,int);
+extern int init_xiafs_fs(void);
 extern void xiafs_read_inode(struct inode *);
 extern void xiafs_write_inode(struct inode *);
 extern void xiafs_put_inode(struct inode *);
diff -u --recursive --new-file v1.3.57/linux/include/net/route.h linux/include/net/route.h
--- v1.3.57/linux/include/net/route.h	Sun Jan 14 16:30:15 1996
+++ linux/include/net/route.h	Thu Jan 18 10:16:25 1996
@@ -26,6 +26,8 @@
 #ifndef _ROUTE_H
 #define _ROUTE_H
 
+#include <linux/config.h>
+
 /*
  * 0 - no debugging messages
  * 1 - rare events and bugs situations (default)
diff -u --recursive --new-file v1.3.57/linux/init/main.c linux/init/main.c
--- v1.3.57/linux/init/main.c	Sun Jan 14 16:30:15 1996
+++ linux/init/main.c	Wed Jan 17 07:27:36 1996
@@ -62,6 +62,7 @@
 extern void floppy_setup(char *str, int *ints);
 extern void st_setup(char *str, int *ints);
 extern void st0x_setup(char *str, int *ints);
+extern void advansys_setup(char *str, int *ints);
 extern void tmc8xx_setup(char *str, int *ints);
 extern void t128_setup(char *str, int *ints);
 extern void pas16_setup(char *str, int *ints);
@@ -201,6 +202,9 @@
 #ifdef CONFIG_SCSI
 	{ "max_scsi_luns=", scsi_luns_setup },
 #endif
+#ifdef CONFIG_SCSI_ADVANSYS
+	{ "advansys=", advansys_setup },
+#endif
 #if defined(CONFIG_BLK_DEV_HD)
 	{ "hd=", hd_setup },
 #endif
@@ -489,6 +493,7 @@
 
 
 extern void setup_arch(char **, unsigned long *, unsigned long *);
+extern void arch_syms_export(void);
 
 #ifndef __SMP__
 
@@ -635,6 +640,7 @@
 	apm_bios_init();
 #endif
 	dquot_init();
+	arch_syms_export();
 	sti();
 	check_bugs();
 
diff -u --recursive --new-file v1.3.57/linux/ipc/msg.c linux/ipc/msg.c
--- v1.3.57/linux/ipc/msg.c	Sun Jan 14 16:30:15 1996
+++ linux/ipc/msg.c	Sun Jan 14 16:46:37 1996
@@ -6,7 +6,7 @@
  *
  */
 
-#include <linux/autoconf.h>
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/msg.h>
@@ -190,7 +190,7 @@
 			return -EIDRM;
 		if ((msgflg & IPC_KERNELD) == 0)
 			/*
-			 * Non-root processes may recieve from kerneld! 
+			 * Non-root processes may receive from kerneld! 
 			 * i.e. no permission check if called from the kernel
 			 * otoh we don't want user level non-root snoopers...
 			 */
@@ -554,7 +554,7 @@
 /*
  * We do perhaps need a "flush" for waiting processes,
  * so that if they are terminated, a call from do_exit
- * will minimize the possibility of orphaned recieved
+ * will minimize the possibility of orphaned received
  * messages in the queue.  For now we just make sure
  * that the queue is shut down whenever kerneld dies.
  */
diff -u --recursive --new-file v1.3.57/linux/ipc/util.c linux/ipc/util.c
--- v1.3.57/linux/ipc/util.c	Sun Jan 14 16:30:15 1996
+++ linux/ipc/util.c	Wed Jan 17 07:32:09 1996
@@ -118,4 +118,7 @@
 	return -ENOSYS;
 }
 
+void kerneld_exit(void)
+{
+}
 #endif /* CONFIG_SYSVIPC */
diff -u --recursive --new-file v1.3.57/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.57/linux/kernel/ksyms.c	Sun Jan 14 16:30:15 1996
+++ linux/kernel/ksyms.c	Mon Jan 15 08:18:22 1996
@@ -41,28 +41,10 @@
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/sysctl.h>
+#include <linux/genhd.h>
 
 extern unsigned char aux_device_present, kbd_read_mask;
 
-#ifdef __alpha__
-# include <asm/io.h>
-# include <asm/hwrpb.h>
-
-extern void bcopy (const char *src, char *dst, int len);
-extern struct hwrpb_struct *hwrpb;
-
-/* these are C runtime functions with special calling conventions: */
-extern void __divl (void);
-extern void __reml (void);
-extern void __divq (void);
-extern void __remq (void);
-extern void __divlu (void);
-extern void __remlu (void);
-extern void __divqu (void);
-extern void __remqu (void);
-
-#endif
-
 #ifdef CONFIG_NET
 #include <linux/in.h>
 #include <linux/net.h>
@@ -84,9 +66,6 @@
 #include <net/tcp.h>
 #include <net/route.h>
 #include <linux/net_alias.h>
-#if defined(CONFIG_PPP) || defined(CONFIG_SLIP)
-#include "../drivers/net/slhc.h"
-#endif
 #endif
 #ifdef CONFIG_NET_ALIAS
 #include <linux/net_alias.h>
@@ -96,10 +75,6 @@
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #endif
-#if defined(CONFIG_MSDOS_FS) && !defined(CONFIG_UMSDOS_FS)
-#include <linux/msdos_fs.h>
-#endif
-
 #if defined(CONFIG_PROC_FS)
 #include <linux/proc_fs.h>
 #endif
@@ -111,6 +86,19 @@
 #include <linux/smp.h>
 #endif
 
+#ifndef CONFIG_SCSI
+#if defined(CONFIG_PROC_FS)
+/*
+ * This is all required so that if we load all of scsi as a module,
+ * that the scsi code will be able to talk to the /proc/scsi handling
+ * in the procfs.
+ */
+extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
+				off_t offset, int length, int inout);
+extern struct inode_operations proc_scsi_inode_operations;
+#endif
+#endif
+
 extern char *get_options(char *str, int *ints);
 extern void set_device_ro(int dev,int flag);
 extern struct file_operations * get_blkfops(unsigned int);
@@ -124,17 +112,6 @@
 #include "../drivers/net/8390.h"
 #endif
 
-#ifdef CONFIG_SCSI
-#include "../drivers/scsi/scsi.h"
-#include "../drivers/scsi/scsi_ioctl.h"
-#include "../drivers/scsi/hosts.h"
-#include "../drivers/scsi/constants.h"
-#include "../drivers/scsi/sd.h"
-#include <linux/scsicam.h>
-
-extern int generic_proc_info(char *, char **, off_t, int, int, int);
-#endif
-
 extern int sys_tz;
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
@@ -154,30 +131,6 @@
 		SYMBOL_NAME_STR (Using_Versions) },
 #endif
 
-	/* platform dependent support */
-#ifdef __alpha__
-	X(_inb),
-	X(_inw),
-	X(_inl),
-	X(_outb),
-	X(_outw),
-	X(_outl),
-	X(bcopy),	/* generated by gcc-2.7.0 for string assignments */
-	X(hwrpb),
-	X(__divl),
-	X(__reml),
-	X(__divq),
-	X(__remq),
-	X(__divlu),
-	X(__remlu),
-	X(__divqu),
-	X(__remqu),
-	X(strlen),	/* used by ftape */
-	X(memcmp),
-	X(memmove),
-	X(__constant_c_memset),
-#endif
-
 	/* stackable module support */
 	X(rename_module_symbol),
 	X(register_symtab),
@@ -361,9 +314,6 @@
 	X(interruptible_sleep_on),
 	X(schedule),
 	X(current_set),
-#if defined(__i386__) && defined(__SMP__)
-	X(apic_reg),		/* Needed internally for the I386 inlines */
-#endif	
 	X(jiffies),
 	X(xtime),
 	X(do_gettimeofday),
@@ -431,15 +381,6 @@
 	X(ethdev_init),
 	X(NS8390_init),
 #endif
-#if defined(CONFIG_PPP) || defined(CONFIG_SLIP)
-    	/* VJ header compression */
-	X(slhc_init),
-	X(slhc_free),
-	X(slhc_remember),
-	X(slhc_compress),
-	X(slhc_uncompress),
-	X(slhc_toss),
-#endif
 #ifdef CONFIG_NET_ALIAS
 #include <linux/net_alias.h>
 #endif
@@ -484,50 +425,24 @@
 	X(tty_register_ldisc),
 	X(kill_fasync),
 #endif
-#ifdef CONFIG_SCSI
-	/* Supports loadable scsi drivers 
- 	 * technically some of this stuff could be moved to scsi.c, but
- 	 * scsi.c is initialized before the memory manager is set up.
- 	 * So we add it here too.  There is a duplicate set in scsi.c
- 	 * that is used when the entire scsi subsystem is a loadable
- 	 * module.
-	 */
-	X(scsi_register_module),
-	X(scsi_unregister_module),
-	X(scsi_free),
-	X(scsi_malloc),
-	X(scsi_register),
-	X(scsi_unregister),
-	X(scsicam_bios_param),
- 	X(allocate_device),
- 	X(scsi_do_cmd),
- 	X(scsi_command_size),
- 	X(scsi_init_malloc),
- 	X(scsi_init_free),
- 	X(scsi_ioctl),
-	X(scsi_mark_host_bus_reset),
-  	X(print_command),
-      	X(print_msg),
-  	X(print_status),
- 	X(print_sense),
- 	X(dma_free_sectors),
- 	X(kernel_scsi_ioctl),
- 	X(need_isa_buffer),
- 	X(request_queueable),
-	X(generic_proc_info),
- 	X(scsi_devices),
-	X(gendisk_head), /* Needed for sd.c */
-	X(resetup_one_dev), /* Needed for sd.c */
-#if defined(CONFIG_PROC_FS)
-	X(proc_print_scsidevice),
-#endif
-#else
+#ifndef CONFIG_SCSI
 	/*
 	 * With no scsi configured, we still need to export a few
 	 * symbols so that scsi can be loaded later via insmod.
+	 * Don't remove this unless you are 100% sure of what you are
+	 * doing.  If you want to remove this, you don't know what
+	 * you are doing!
 	 */
 	X(gendisk_head),
 	X(resetup_one_dev),
+#if defined(CONFIG_PROC_FS)
+	/*
+	 * This is required so that if we load scsi later, that the
+	 * scsi code can attach to /proc/scsi in the correct manner.
+	 */
+	X(proc_scsi_inode_operations),
+	X(dispatch_scsi_info_ptr),
+#endif
 #endif
 	/* Added to make file system as module */
 	X(set_writetime),
@@ -547,38 +462,6 @@
 	X(insert_inode_hash),
 	X(event),
 	X(__down),
-#if defined(CONFIG_MSDOS_FS) && !defined(CONFIG_UMSDOS_FS)
-	/* support for umsdos fs */
-	X(msdos_bmap),
-	X(msdos_create),
-	X(msdos_file_read),
-	X(msdos_file_write),
-	X(msdos_lookup),
-	X(msdos_mkdir),
-	X(msdos_mmap),
-	X(msdos_put_inode),
-	X(msdos_put_super),
-	X(msdos_read_inode),
-	X(msdos_read_super),
-	X(msdos_readdir),
-	X(msdos_rename),
-	X(msdos_rmdir),
-	X(msdos_smap),
-	X(msdos_statfs),
-	X(msdos_truncate),
-	X(msdos_unlink),
-	X(msdos_unlink_umsdos),
-	X(msdos_write_inode),
-#endif
-#ifdef CONFIG_PROC_FS
-	X(proc_register),
-	X(proc_unregister),
-	X(in_group_p),
-	X(generate_cluster),
-	X(proc_scsi),
-	X(proc_net_inode_operations),
-	X(proc_net),
-#endif
 /* all busmice */
 	X(add_mouse_randomness),
 	X(fasync_helper),
diff -u --recursive --new-file v1.3.57/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.57/linux/kernel/sched.c	Sat Jan  6 19:10:42 1996
+++ linux/kernel/sched.c	Wed Jan 17 07:31:59 1996
@@ -38,6 +38,9 @@
 /*
  * kernel variables
  */
+
+int securelevel = 0;			/* system security level */
+
 long tick = 1000000 / HZ;               /* timer interrupt period */
 volatile struct timeval xtime;		/* The current time */
 int tickadj = 500/HZ;			/* microsecs */
diff -u --recursive --new-file v1.3.57/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v1.3.57/linux/kernel/sysctl.c	Sun Jan 14 16:30:16 1996
+++ linux/kernel/sysctl.c	Wed Jan 17 07:31:59 1996
@@ -5,7 +5,7 @@
  * Added /proc support, Dec 1995
  */
 
-#include <linux/autoconf.h>
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
@@ -81,6 +81,9 @@
 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
 #endif
 
+static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
+				    void *, size_t, void **);
+
 /* The default sysctl tables: */
 
 static ctl_table root_table[] = {
@@ -108,6 +111,8 @@
 	 0444, NULL, &proc_dointvec},
 	{KERN_MAXFILE, "file-max", &max_files, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+	{KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
+	 0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
 	{0}
 };
 
@@ -293,6 +298,27 @@
 	return 0;
 }
 
+/*
+ * This function only checks permission for changing the security level
+ * If the tests are successfull, the actual change is done by
+ * do_sysctl_strategy
+ */
+static int do_securelevel_strategy (ctl_table *table, 
+				    int *name, int nlen,
+				    void *oldval, size_t *oldlenp,
+				    void *newval, size_t newlen, void **context)
+{
+	int level;
+
+	if (newval && newlen) {
+		if (newlen != sizeof (int))
+			return -EINVAL;
+		memcpy_fromfs (&level, newval, newlen);
+		if (level < securelevel && current->pid != 1)
+			return -EPERM;
+	}
+	return 0;
+}
 
 struct ctl_table_header *register_sysctl_table(ctl_table * table, 
 					       int insert_at_head)
diff -u --recursive --new-file v1.3.57/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.57/linux/mm/filemap.c	Sun Jan 14 16:30:16 1996
+++ linux/mm/filemap.c	Thu Jan 18 06:41:22 1996
@@ -43,14 +43,20 @@
 
 void invalidate_inode_pages(struct inode * inode, unsigned long start)
 {
-	struct page ** p = &inode->i_pages;
+	struct page ** p;
 	struct page * page;
 
+repeat:
+	p = &inode->i_pages;
 	while ((page = *p) != NULL) {
 		unsigned long offset = page->offset;
 
 		/* page wholly truncated - free it */
 		if (offset >= start) {
+			if (page->locked) {
+				wait_on_page(page);
+				goto repeat;
+			}
 			inode->i_nrpages--;
 			if ((*p = page->next) != NULL)
 				(*p)->prev = page->prev;
@@ -107,7 +113,7 @@
 			page->referenced = 1;
 		else if (page->referenced)
 			page->referenced = 0;
-		else if (page->count) {
+		else if (page->count && !page->locked) {
 			/* The page is an old, unshared page --- try
                            to discard it. */
 			if (page->inode) {
@@ -179,13 +185,15 @@
 {
 	struct page * page;
 
+	offset &= PAGE_MASK;
 	if (!page_cache) {
 		page_cache = __get_free_page(GFP_KERNEL);
 		if (!page_cache)
 			return 0;
 	}
-#ifdef readahead_makes_sense_due_to_asynchronous_reads
-	offset = (offset + PAGE_SIZE) & PAGE_MASK;
+	if (offset >= inode->i_size)
+		return page_cache;
+#if 1
 	page = find_page(inode, offset);
 	if (page) {
 		page->count--;
@@ -202,11 +210,8 @@
 	add_page_to_inode_queue(inode, page);
 	add_page_to_hash_queue(inode, page);
 
-	/* 
-	 * And start IO on it..
-	 * (this should be asynchronous, but currently isn't)
-	 */
 	inode->i_op->readpage(inode, page);
+
 	free_page(page_cache);
 	return 0;
 #else
@@ -214,17 +219,41 @@
 #endif
 }
 
+/* 
+ * Wait for IO to complete on a locked page.
+ */
+void __wait_on_page(struct page *page)
+{
+	struct wait_queue wait = { current, NULL };
+
+	page->count++;
+	add_wait_queue(&page->wait, &wait);
+repeat:
+	current->state = TASK_UNINTERRUPTIBLE;
+	if (page->locked) {
+		schedule();
+		goto repeat;
+	}
+	remove_wait_queue(&page->wait, &wait);
+	page->count--;
+	current->state = TASK_RUNNING;
+}
+
+
 /*
  * This is a generic file read routine, and uses the
  * inode->i_op->readpage() function for the actual low-level
  * stuff.
  */
+#define READAHEAD_PAGES 3
+#define MAX_IO_PAGES 4
 int generic_file_read(struct inode * inode, struct file * filp, char * buf, int count)
 {
-	int read = 0;
+	int read = 0, newpage = 0;
 	unsigned long pos;
 	unsigned long page_cache = 0;
-
+	int pre_read = 0;
+	
 	if (count <= 0)
 		return 0;
 
@@ -232,6 +261,8 @@
 	do {
 		struct page *page;
 		unsigned long offset, addr, nr;
+		int i;
+		off_t p;
 
 		if (pos >= inode->i_size)
 			break;
@@ -278,21 +309,49 @@
 		add_page_to_inode_queue(inode, page);
 		add_page_to_hash_queue(inode, page);
 
-		/* 
-		 * And start IO on it..
-		 * (this should be asynchronous, but currently isn't)
-		 */
 		inode->i_op->readpage(inode, page);
+		/* We only set "newpage" when we encounter a
+                   completely uncached page.  This way, we do no
+                   readahead if we are still just reading data out of
+                   the cache (even if the cached page is not yet
+                   uptodate --- it may be currently being read as a
+                   result of previous readahead).  -- sct */
+		newpage = 1;
 
 found_page:
 		addr = page_address(page);
 		if (nr > count)
 			nr = count;
-		if (!page->uptodate) {
-			page_cache = try_to_read_ahead(inode, offset, page_cache);
-			if (!page->uptodate)
-				sleep_on(&page->wait);
+		/* We have two readahead cases.  First, do data
+                   pre-read if the current read request is for more
+                   than one page, so we can merge the adjacent
+                   requests. */
+		if (newpage && nr < count) {
+			if (pre_read > 0)
+				pre_read -= PAGE_SIZE;
+			else {
+				pre_read = (MAX_IO_PAGES-1) * PAGE_SIZE;
+				if (pre_read > (count - nr))
+					pre_read = count - nr;
+				for (i=0, p=pos; i<pre_read; i+=PAGE_SIZE) {
+					p += PAGE_SIZE;
+					page_cache = try_to_read_ahead(inode, p, page_cache);
+				}
+			}
+		}
+		else
+		/* Second, do readahead at the end of the read, if we
+                   are still waiting on the current IO to complete, if
+                   readahead is flagged for the file, and if we have
+                   finished with the current block. */
+		if (newpage && nr == count && filp->f_reada
+		    && !((pos + nr) & ~PAGE_MASK)) {
+			for (i=0, p=pos; i<READAHEAD_PAGES; i++) {
+				p += PAGE_SIZE;
+				page_cache = try_to_read_ahead(inode, p, page_cache);
+			}
 		}
+		wait_on_page(page);
 		if (nr > inode->i_size - pos)
 			nr = inode->i_size - pos;
 		memcpy_tofs(buf, (void *) (addr + offset), nr);
@@ -304,6 +363,7 @@
 	} while (count);
 
 	filp->f_pos = pos;
+	filp->f_reada = 1;
 	if (page_cache)
 		free_page(page_cache);
 	if (!IS_RDONLY(inode)) {
@@ -315,7 +375,7 @@
 
 /*
  * Find a cached page and wait for it to become up-to-date, return
- * the page address.
+ * the page address.  Increments the page count.
  */
 static inline unsigned long fill_page(struct inode * inode, unsigned long offset)
 {
@@ -344,8 +404,7 @@
 	add_page_to_hash_queue(inode, page);
 	inode->i_op->readpage(inode, page);
 found_page:
-	if (!page->uptodate)
-		sleep_on(&page->wait);
+	wait_on_page(page);
 	return page_address(page);
 }
 
diff -u --recursive --new-file v1.3.57/linux/mm/swap.c linux/mm/swap.c
--- v1.3.57/linux/mm/swap.c	Sun Jan 14 16:30:16 1996
+++ linux/mm/swap.c	Thu Jan 18 06:41:22 1996
@@ -58,6 +58,8 @@
 	RCL_ROUND_ROBIN		/* Balancing policy */
 };
 
+swapstat_t swapstats = {0};
+
 /* General swap control */
 
 /* Parse the kernel command line "swap=" option at load time: */
diff -u --recursive --new-file v1.3.57/linux/mm/vmscan.c linux/mm/vmscan.c
--- v1.3.57/linux/mm/vmscan.c	Sun Jan 14 16:30:16 1996
+++ linux/mm/vmscan.c	Thu Jan 18 06:43:09 1996
@@ -3,7 +3,9 @@
  *
  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  *
- *  Swap reorganised 29.12.95, 
+ *  Swap reorganised 29.12.95, Stephen Tweedie.
+ *  kswapd added: 7.1.96  sct
+ *  Version: $Id: vmscan.c,v 1.3.2.3 1996/01/17 02:43:11 linux Exp $
  */
 
 #include <linux/mm.h>
@@ -357,6 +359,7 @@
 int kswapd(void *unused)
 {
 	int i;
+	char *revision="$Revision: 1.3.2.3 $", *s, *e;
 	
 	current->session = 1;
 	current->pgrp = 1;
@@ -380,15 +383,21 @@
 				    namings for POSIX.4 realtime scheduling
 				    priorities.  */
 
-	printk ("Started kswapd v$Revision: 1.1.2.3 $\n");
 	init_swap_timer();
 	
+	if ((s = strchr(revision, ':')) &&
+	    (e = strchr(s, '$')))
+		s++, i = e - s;
+	else
+		s = revision, i = -1;
+	printk ("Started kswapd v%.*s\n", i, s);
+
 	while (1) {
 		kswapd_awake = 0;
 		current->signal = 0;
 		interruptible_sleep_on(&kswapd_wait);
 		kswapd_awake = 1;
-		
+		swapstats.wakeups++;
 		/* Do the background pageout: */
 		for (i=0; i < kswapd_ctl.maxpages; i++)
 			try_to_free_page(GFP_KERNEL, ~0UL);
diff -u --recursive --new-file v1.3.57/linux/net/Config.in linux/net/Config.in
--- v1.3.57/linux/net/Config.in	Wed Dec 13 09:02:47 1995
+++ linux/net/Config.in	Sun Jan 14 16:22:16 1996
@@ -20,3 +20,4 @@
 if [ "$CONFIG_NETLINK" = "y" ]; then
   bool 'Routing messages' CONFIG_RTNETLINK
 fi
+endmenu
diff -u --recursive --new-file v1.3.57/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v1.3.57/linux/net/ipv4/proc.c	Mon Nov 13 12:36:46 1995
+++ linux/net/ipv4/proc.c	Sun Jan 14 16:45:11 1996
@@ -30,7 +30,6 @@
  *		2 of the License, or (at your option) any later version.
  */
 #include <asm/system.h>
-#include <linux/autoconf.h>
 #include <linux/sched.h>
 #include <linux/socket.h>
 #include <linux/net.h>
diff -u --recursive --new-file v1.3.57/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v1.3.57/linux/net/ipv4/tcp.c	Thu Jan  4 21:54:59 1996
+++ linux/net/ipv4/tcp.c	Wed Jan 17 07:32:09 1996
@@ -256,7 +256,7 @@
  * 
  * Use of PSH (4.2.2.2)
  *   MAY aggregate data sent without the PSH flag. (does)
- *   MAY queue data recieved without the PSH flag. (does)
+ *   MAY queue data received without the PSH flag. (does)
  *   SHOULD collapse successive PSH flags when it packetizes data. (doesn't)
  *   MAY implement PSH on send calls. (doesn't, thus:)
  *     MUST NOT buffer data indefinitely (doesn't [1 second])
@@ -281,12 +281,12 @@
  *	[Follows BSD 1 byte of urgent data]
  * 
  * TCP Options (4.2.2.5)
- *   MUST be able to recieve TCP options in any segment. (does)
+ *   MUST be able to receive TCP options in any segment. (does)
  *   MUST ignore unsupported options (does)
  *   
  * Maximum Segment Size Option (4.2.2.6)
  *   MUST implement both sending and receiving MSS. (does)
- *   SHOULD send an MSS with every SYN where recieve MSS != 536 (MAY send
+ *   SHOULD send an MSS with every SYN where receive MSS != 536 (MAY send
  *     it always). (does, even when MSS == 536, which is legal)
  *   MUST assume MSS == 536 if no MSS received at connection setup (does)
  *   MUST calculate "effective send MSS" correctly:
@@ -798,7 +798,7 @@
 {
 	del_timer(&sk->retransmit_timer);
 	sk->ip_xmit_timeout = why;
-	if((int)when < 0)
+	if((long)when < 0)
 	{
 		when=3;
 		printk("Error: Negative timer in xmit_timer\n");
@@ -3643,10 +3643,10 @@
 			sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1;
 			if (sk->rto > 120*HZ)
 				sk->rto = 120*HZ;
-			if (sk->rto < 20)	/* Was 1*HZ, then 1 - turns out we must allow about
+			if (sk->rto < HZ/5)	/* Was 1*HZ, then 1 - turns out we must allow about
 						   .2 of a second because of BSD delayed acks - on a 100Mb/sec link
 						   .2 of a second is going to need huge windows (SIGH) */
-			sk->rto = 20;
+			sk->rto = HZ/5;
 		}
 	}
 
@@ -3743,8 +3743,8 @@
 				sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1;
 				if (sk->rto > 120*HZ)
 					sk->rto = 120*HZ;
-				if (sk->rto < 20)	/* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */
-					sk->rto = 20;
+				if (sk->rto < HZ/5)	/* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */
+					sk->rto = HZ/5;
 				sk->backoff = 0;
 			}
 			flag |= (2|4);	/* 2 is really more like 'don't adjust the rtt 
diff -u --recursive --new-file v1.3.57/linux/scripts/Configure linux/scripts/Configure
--- v1.3.57/linux/scripts/Configure	Sat Dec 30 15:50:56 1995
+++ linux/scripts/Configure	Wed Jan 17 09:33:33 1996
@@ -48,6 +48,9 @@
 function mainmenu_name () {
 	:
 }
+function endmenu () {
+	:
+}
 
 #
 # help prints the corresponding help text from Configure.help to stdout
@@ -262,6 +265,35 @@
           case "$ans" in
              [1-9] | [1-9][0-9] | [1-9][0-9][0-9] | [1-9][0-9][0-9][0-9] ) 
                  define_int "$2" "$ans"
+                 break;;
+             * ) help "$2"
+                 ;;
+          esac
+        done
+}
+#
+# define_hex sets the value of a hexadecimal argument
+#
+#	define_hex define value
+#
+function define_hex () {
+	echo "$1=$2" >>$CONFIG
+	echo "#define $1 0x$2" >>$CONFIG_H
+	eval "$1=$2"
+}
+
+#
+# hex processes an hexadecimal argument
+#
+#	hex question define default
+#
+function hex () {
+	def=$(eval echo "\${$2:-$3}")
+        while :; do
+          readln "$1 ($2) [$def] " "$def"
+          case "$ans" in
+             [1-9] | [1-9][0-9] | [1-9][0-9][0-9] | [1-9][0-9][0-9][0-9] ) 
+                 define_hex "$2" "$ans"
                  break;;
              * ) help "$2"
                  ;;
diff -u --recursive --new-file v1.3.57/linux/scripts/tkparse.c linux/scripts/tkparse.c
--- v1.3.57/linux/scripts/tkparse.c	Thu Nov  9 11:23:57 1995
+++ linux/scripts/tkparse.c	Sun Jan 14 16:22:16 1996
@@ -381,6 +381,11 @@
       tok = tok_fi;
       pnt += 2;
     }
+  else if (strncmp(pnt, "endmenu", 7) == 0) 
+    {
+      tok = tok_endmenu;
+      pnt += 7;
+    }
 
   if( tok == tok_unknown)
     {
@@ -476,6 +481,7 @@
     case tok_else:
     case tok_fi:
     case tok_sound:
+    case tok_endmenu:
       break;
     case tok_if:
       /*
@@ -692,6 +698,7 @@
 	  dump_if(cfg->cond);
 	  break;
 	case tok_nop:
+	case tok_endmenu:
 	  break;
 	default:
 	  printf("\n");
diff -u --recursive --new-file v1.3.57/linux/scripts/tkparse.h linux/scripts/tkparse.h
--- v1.3.57/linux/scripts/tkparse.h	Thu Nov  9 11:23:57 1995
+++ linux/scripts/tkparse.h	Sun Jan 14 16:22:16 1996
@@ -15,7 +15,9 @@
   tok_define,
   tok_choose,
   tok_choice,
+  tok_endmenu,
   tok_unknown
+
 };
 
 enum operator {
