diff -u --recursive --new-file v2.0.0/linux/Documentation/Changes linux/Documentation/Changes
--- v2.0.0/linux/Documentation/Changes	Thu Jun  6 22:35:43 1996
+++ linux/Documentation/Changes	Sat Jun 29 12:00:45 1996
@@ -491,8 +491,13 @@
 Linux C++ Library
 =================
 
+ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.3.bin.tar.gz
 ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.4.bin.tar.gz
+
+Use libc5.2.18 with 2.7.1.3, libc5.3.12 with 2.7.1.4
+
 Installation notes:
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.3
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.4
 
 Dynamic Linker
diff -u --recursive --new-file v2.0.0/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v2.0.0/linux/Documentation/devices.tex	Mon May 13 23:02:46 1996
+++ linux/Documentation/devices.tex	Mon Jun 10 08:14:43 1996
@@ -42,7 +42,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: May 12, 1996}
+\date{Last revised: June 9, 1996}
 \maketitle
 %
 \noindent
@@ -78,6 +78,10 @@
 In particular, please don't sent patches for this list to Linus, at
 least not without contacting me first.
 
+I do not have any information about these devices beyond what appears
+on this list.  Any such information requests will be deleted without
+reply.
+
 \section{Major numbers}
 
 \begin{devicelist}
@@ -157,7 +161,7 @@
 \major{39}{}{char }{ML-16P experimental I/O board}
 \major{  }{}{block}{Reserved for Linux/AP+}
 \major{40}{}{char }{Matrox Meteor frame grabber}
-\major{  }{}{block}{Syquest EZ135 removable drive}
+\major{  }{}{block}{Syquest EZ135 parallel port removable drive}
 \major{41}{}{char }{Yet Another Micro Monitor}
 \major{42}{}{}{Demo/sample use}
 \major{43}{}{char }{isdn4linux virtual modem}
@@ -169,7 +173,9 @@
 \major{49}{}{char }{SDL RISCom serial card -- alternate devices}
 \major{50}{}{char }{Reserved for GLINT}
 \major{51}{}{char }{Baycom radio modem}
-\major{52}{--59}{}{Unallocated}
+\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card}
+\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers}
+\major{54}{--59}{}{Unallocated}
 \major{60}{--63}{}{Local/experimental use}
 \major{64}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
@@ -972,8 +978,8 @@
 \major{40}{}{char }{Matrox Meteor frame grabber}
 	\minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber}
 \\
-\major{  }{}{block}{Syquest EZ135 removable drive}
-	\minor{0}{/dev/eza}{First EZ135 drive whole disk}
+\major{  }{}{block}{Syquest EZ135 parallel port removable drive}
+	\minor{0}{/dev/eza}{Parallel EZ135 drive whole disk}
 \end{devicelist}
 
 \noindent
@@ -1065,7 +1071,32 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{52}{--59}{}{Unallocated}
+\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card}
+	\minor{0}{/dev/dcbri0}{First DataComm card}
+	\minor{1}{/dev/dcbri1}{Second DataComm card}
+	\minor{2}{/dev/dcbri2}{Third DataComm card}
+	\minor{3}{/dev/dcbri3}{Fourth DataComm card}
+\end{devicelist}
+
+\begin{devicelist}
+\major{53}{}{char }{BDM interface for remote debugging MC683xx
+microcontrollers}
+	\minor{0}{/dev/pd\_bdm0}{PD BDM interface on {\file lp0}}
+	\minor{1}{/dev/pd\_bdm1}{PD BDM interface on {\file lp1}}
+	\minor{2}{/dev/pd\_bdm2}{PD BDM interface on {\file lp2}}
+	\minor{4}{/dev/icd\_bdm0}{ICD BDM interface on {\file lp0}}
+	\minor{5}{/dev/icd\_bdm1}{ICD BDM interface on {\file lp1}}
+	\minor{6}{/dev/icd\_bdm2}{ICD BDM interface on {\file lp2}}
+\end{devicelist}
+
+\noindent
+This device is used for the interfacing to the MC683xx
+microcontrollers via Background Debug Mode by use of a Parallel Port
+interface. PD is the Motorola Public Domain Interface and ICD is the
+commercial interface by P\&E.
+
+\begin{devicelist}
+\major{54}{--59}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
@@ -1119,7 +1150,8 @@
 \end{nodelist}
 
 \noindent
-Note: The last device is: letter {\tt X}-digit {\tt 0}-letter {\tt R}.
+Note: The last device is: $<$letter {\tt X}$>$-$<$digit {\tt
+0}$>$-$<$letter {\tt R}$>$.
 
 \subsection{Recommended links}
 
@@ -1128,6 +1160,7 @@
 \begin{nodelist}
 \link{/dev/core}{/proc/kcore}{symbolic}{Backward compatibility}
 \link{/dev/ramdisk}{ram0}{symbolic}{Backward compatibility}
+\link{/dev/ftape}{rft0}{symbolic}{Backward compatibility}
 \link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs}
 %\link{/dev/fd?H*}{fd?D*}{hard}{Compatible floppy formats}
 %\link{/dev/fd?E*}{fd?D*}{hard}{Compatible floppy formats}
diff -u --recursive --new-file v2.0.0/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.0.0/linux/Documentation/devices.txt	Mon May 13 23:02:46 1996
+++ linux/Documentation/devices.txt	Mon Jun 10 08:14:47 1996
@@ -2,7 +2,7 @@
 
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		      Last revised: May 12, 1996
+		      Last revised: June 9, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -35,6 +35,10 @@
 In particular, please don't sent patches for this list to Linus, at
 least not without contacting me first.
 
+I do not have any information about these devices beyond what appears
+on this list.  Any such information requests will be deleted without
+reply.
+
   0 		Unnamed devices (e.g. non-device mounts)
 		  0 = reserved as null device number
 
@@ -461,7 +465,14 @@
 		  3 = /dev/sbpcd7	Panasonic CD-ROM controller 1 unit 3
 
  27 char	QIC-117 tape
-		  0 = /dev/ftape	QIC-117 tape
+		  0 = /dev/rft0		Unit 0, rewind-on-close
+		  1 = /dev/rft1		Unit 1, rewind-on-close
+		  2 = /dev/rft2		Unit 2, rewind-on-close
+		  3 = /dev/rft3		Unit 3, rewind-on-close
+		  4 = /dev/nrft0	Unit 0, no rewind-on-close
+		  5 = /dev/nrft1	Unit 1, no rewind-on-close
+		  6 = /dev/nrft2	Unit 2, no rewind-on-close
+		  7 = /dev/nrft3	Unit 3, no rewind-on-close
     block	Third Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd8	Panasonic CD-ROM controller 2 unit 0
 		  1 = /dev/sbpcd9	Panasonic CD-ROM controller 2 unit 1
@@ -670,8 +681,8 @@
 
  40 char	Matrox Meteor frame grabber
 		  0 = /dev/mmetfgrab	Matrox Meteor frame grabber
-    block	Syquest EZ135 removable drive
-		  0 = /dev/eza		First EZ135 drive, whole disk
+    block	Syquest EZ135 parallel port removable drive
+		  0 = /dev/eza		Parallel EZ135 drive, whole disk
 
 		Partitions are handled in the same way as IDE disks
 		(see major number 3).
@@ -740,7 +751,27 @@
 		  1 = /dev/bc1		Second Baycom radio modem
 		      ...
 
- 52-59		UNALLOCATED
+ 52 char	Spellcaster DataComm/BRI ISDN card
+		  0 = /dev/dcbri0	First DataComm card
+		  1 = /dev/dcbri1	Second DataComm card
+		  2 = /dev/dcbri2	Third DataComm card
+		  3 = /dev/dcbri3	Fourth DataComm card
+
+ 53 char	BDM interface for remote debugging MC683xx microcontrollers
+		  0 = /dev/pd_bdm0	PD BDM interface on lp0
+          	  1 = /dev/pd_bdm1	PD BDM interface on lp1
+          	  2 = /dev/pd_bdm2	PD BDM interface on lp2
+		  4 = /dev/icd_bdm0	ICD BDM interface on lp0
+		  5 = /dev/icd_bdm1	ICD BDM interface on lp1
+		  6 = /dev/icd_bdm2	ICD BDM interface on lp2
+
+		This device is used for the interfacing to the MC683xx
+		microcontrollers via Background Debug Mode by use of a
+		Parallel Port interface. PD is the Motorola Public
+		Domain Interface and ICD is the commercial interface
+		by P&E.
+
+ 54-59		UNALLOCATED
 
  60-63		LOCAL/EXPERIMENTAL USE
 		Allocated for local/experimental use.  For devices not
@@ -780,7 +811,7 @@
 /dev/nfsd	socksys		symbolic	Required by iBCS-2
 /dev/X0R	null		symbolic	Required by iBCS-2
 
-Note: the last device is letter X-digit 0-letter R.
+Note: the last device is <letter X>-<digit 0>-<letter R>.
 
 	Recommended links
 
@@ -788,6 +819,7 @@
 
 /dev/core	/proc/kcore	symbolic	Backward compatibility
 /dev/ramdisk	ram0		symbolic	Backward compatibility
+/dev/ftape	rft0		symbolic	Backward compatibility
 /dev/scd?	sr?		hard		Alternate SCSI CD-ROM name
 
 
diff -u --recursive --new-file v2.0.0/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.0.0/linux/Documentation/ioctl-number.txt	Sat Jun  1 20:11:29 1996
+++ linux/Documentation/ioctl-number.txt	Wed Jun 26 11:05:25 1996
@@ -1,5 +1,5 @@
 Ioctl Numbers
-29 May 1996
+12 Jun 1996
 Michael Chastain
 <mec@duracef.shout.net>
 
@@ -98,6 +98,7 @@
 't'	80-8F	linux/isdn_ppp.h
 'u'	all	linux/smb_fs.h
 'v'	all	linux/ext2_fs.h
+'w'	all	CERN SCI driver (in development)
 0x89	00-0F	asm-i386/sockios.h
 0x89	10-FF	linux/sockios.h
 0x90	00	linux/sbpcd.h
diff -u --recursive --new-file v2.0.0/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE
--- v2.0.0/linux/Documentation/isdn/INTERFACE	Mon May 20 08:20:58 1996
+++ linux/Documentation/isdn/INTERFACE	Sat Jun 29 20:36:22 1996
@@ -1,4 +1,4 @@
-$Id: INTERFACE,v 1.2 1996/05/18 15:58:53 fritz Exp $
+$Id: INTERFACE,v 1.3 1996/06/25 17:52:41 fritz Exp $
 
 Description of the Interface between Linklevel and Hardwarelevel
   of isdn4linux:
@@ -255,7 +255,7 @@
      This command is intended for performing ioctl-calls for configuring
      hardware or similar purposes (setting port-addresses, loading firmware
      etc.) For this purpose, in the LL all ioctl-calls with an argument
-     >= ISDN_IOCTL_DRVIOCTL (0x100) will be handed transparently to this
+     >= IIOCDRVCTL (0x100) will be handed transparently to this
      function after subtracting 0x100 and placing the result in arg.
      Example:
        If a userlevel-program calls ioctl(0x101,...) the function gets
@@ -264,7 +264,7 @@
      Parameter:
        driver  = driver-Id.
        command = ISDN_CMD_IOCTL
-       arg     = Original ioctl-cmd - ISDN_IOCTL_DRVIOCTL
+       arg     = Original ioctl-cmd - IIOCDRVCTL
        num     = first bytes filled with (unsigned long)arg
    
      Returnvalue:
diff -u --recursive --new-file v2.0.0/linux/Documentation/isdn/README.teles linux/Documentation/isdn/README.teles
--- v2.0.0/linux/Documentation/isdn/README.teles	Wed Feb 28 08:32:54 1996
+++ linux/Documentation/isdn/README.teles	Sat Jun 29 20:36:22 1996
@@ -43,8 +43,9 @@
 	4   D channel Q.931 (call control messages)
 	8   D channel Q.921 
 	16  B channel X.75
+	32  Lowlevel (irq and Layer1 stuff)
 
-For example 'teles/telesctrl MyTeles 1 31' enables full 
+For example 'teles/telesctrl MyTeles 1 63' enables full 
 debugging.
 
 Questions
diff -u --recursive --new-file v2.0.0/linux/Documentation/logo.txt linux/Documentation/logo.txt
--- v2.0.0/linux/Documentation/logo.txt	Sun Jun  9 13:28:41 1996
+++ linux/Documentation/logo.txt	Sun Jun  9 18:01:04 1996
@@ -1,4 +1,4 @@
-This is the full-colour version of the currenly unofficial Linux logo
+This is the full-colour version of the currently unofficial Linux logo
 ("currently unofficial" just means that there has been no paperwork and
 that I haven't really announced it yet).  It was created by Larry Ewing,
 and is freely usable as long as you acknowledge Larry as the original
diff -u --recursive --new-file v2.0.0/linux/Documentation/modules.txt linux/Documentation/modules.txt
--- v2.0.0/linux/Documentation/modules.txt	Sun Jun  9 13:28:41 1996
+++ linux/Documentation/modules.txt	Sun Jun  9 18:01:04 1996
@@ -148,7 +148,7 @@
 
 Whenever a program wants the kernel to use a feature that is only
 available as a loadable module, and if the kernel hasn't got the
-module installed yet, the kernel will ask the kerneld deamon to take
+module installed yet, the kernel will ask the kerneld daemon to take
 care of the situation and make the best of it.
 
 This is what happens:
@@ -166,7 +166,7 @@
 	  has decided that the kernel needs.  Every module will be
 	  configured according to the "options" lines in "/etc/conf.modules".
 	- modprobe exits and kerneld tells the kernel that the request
-	  succeded (or failed...)
+	  succeeded (or failed...)
 	- The kernel uses the freshly installed feature just as if it
 	  had been configured into the kernel as a "resident" part.
 
diff -u --recursive --new-file v2.0.0/linux/Makefile linux/Makefile
--- v2.0.0/linux/Makefile	Sun Jun  9 13:28:41 1996
+++ linux/Makefile	Mon Jun 10 08:15:28 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 0
+SUBLEVEL = 1
 
 ARCH = i386
 
diff -u --recursive --new-file v2.0.0/linux/README linux/README
--- v2.0.0/linux/README	Thu Jun  6 22:35:43 1996
+++ linux/README	Wed Jun 26 11:05:26 1996
@@ -76,14 +76,14 @@
    the current directory, but an alternative directory can be specified
    as the second argument.
 
- - make sure your /usr/include/linux and /usr/include/asm directories
-   are just symlinks to the kernel sources:
+ - make sure your /usr/include/asm, /usr/include/linux, and /usr/include/scsi
+   directories are just symlinks to the kernel sources:
 
 		cd /usr/include
-		rm -rf linux
-		rm -rf asm
-		ln -s /usr/src/linux/include/linux linux
+		rm -rf asm linux scsi
 		ln -s /usr/src/linux/include/asm-i386 asm
+		ln -s /usr/src/linux/include/linux linux
+		ln -s /usr/src/linux/include/scsi scsi
 
  - make sure you have no stale .o files and dependencies lying around:
 
@@ -138,6 +138,9 @@
    in your A: drive, and do a "make zdisk".  It is also possible to do
    "make zlilo" if you have lilo installed to suit the kernel makefiles,
    but you may want to check your particular lilo setup first. 
+
+ - if your kernel is too large for "make zImage", use "make bzImage"
+   instead.
 
  - if you configured any of the parts of the kernel as `modules', you
    will have to do "make modules" followed by "make modules_install".
diff -u --recursive --new-file v2.0.0/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.0.0/linux/arch/alpha/defconfig	Sun Jun  9 13:28:41 1996
+++ linux/arch/alpha/defconfig	Tue Jul  2 19:08:29 1996
@@ -24,18 +24,19 @@
 # CONFIG_ALPHA_EB66 is not set
 # CONFIG_ALPHA_EB66P is not set
 # CONFIG_ALPHA_EB64P is not set
-CONFIG_ALPHA_EB164=y
+# CONFIG_ALPHA_EB164 is not set
 # CONFIG_ALPHA_PC164 is not set
 # CONFIG_ALPHA_JENSEN is not set
 # CONFIG_ALPHA_NONAME is not set
 # CONFIG_ALPHA_MIKASA is not set
-# CONFIG_ALPHA_ALCOR is not set
+CONFIG_ALPHA_ALCOR=y
 # CONFIG_ALPHA_P2K is not set
 CONFIG_PCI=y
 CONFIG_ALPHA_EV5=y
 CONFIG_ALPHA_CIA=y
+CONFIG_ALPHA_SRM=y
 # CONFIG_SERIAL_ECHO is not set
-# CONFIG_TGA_CONSOLE is not set
+CONFIG_TGA_CONSOLE=y
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
@@ -126,13 +127,11 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_NCR53C406A is not set
-CONFIG_SCSI_NCR53C7xx=y
-CONFIG_SCSI_NCR53C7xx_sync=y
-CONFIG_SCSI_NCR53C7xx_FAST=y
-# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
+CONFIG_SCSI_QLOGIC_ISP=y
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.0.0/linux/arch/alpha/kernel/head.S	Fri Dec 22 08:22:04 1995
+++ linux/arch/alpha/kernel/head.S	Mon Jul  1 20:06:05 1996
@@ -10,7 +10,7 @@
 #define __ASSEMBLY__
 #include <asm/system.h>
 
-#define halt .long PAL_halt
+#define halt call_pal PAL_halt
 
 .globl swapper_pg_dir
 .globl _stext
@@ -32,7 +32,7 @@
 	.globl	wrent
 	.ent	wrent
 wrent:
-	.long PAL_wrent
+	call_pal PAL_wrent
 	ret	($26)
 	.end wrent
 
@@ -40,7 +40,7 @@
 	.globl	wrkgp
 	.ent	wrkgp
 wrkgp:
-	.long PAL_wrkgp
+	call_pal PAL_wrkgp
 	ret	($26)
 	.end wrkgp
 
@@ -48,7 +48,7 @@
 	.globl	wrusp
 	.ent	wrusp
 wrusp:
-	.long PAL_wrusp
+	call_pal PAL_wrusp
 	ret	($26)
 	.end wrusp
 
@@ -56,7 +56,7 @@
 	.globl	rdusp
 	.ent	rdusp
 rdusp:
-	.long PAL_rdusp
+	call_pal PAL_rdusp
 	ret	($26)
 	.end rdusp
 
@@ -64,7 +64,7 @@
 	.globl	tbi
 	.ent	tbi
 tbi:
-	.long PAL_tbi
+	call_pal PAL_tbi
 	ret	($26)
 	.end tbi
 
@@ -72,7 +72,7 @@
 	.globl	imb
 	.ent	imb
 imb:
-	.long PAL_imb
+	call_pal PAL_imb
 	ret	($26)
 	.end imb
 
diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.0.0/linux/arch/alpha/kernel/irq.c	Sun Jun  9 13:28:41 1996
+++ linux/arch/alpha/kernel/irq.c	Mon Jul  1 20:06:05 1996
@@ -28,109 +28,83 @@
 
 extern void timer_interrupt(struct pt_regs * regs);
 
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
-
-#if NR_IRQS == 48
-  static unsigned int cache_irq_mask = 0x7fffffff; /* enable EISA */
-#elif NR_IRQS == 33
-  static unsigned int  cache_804 = 0x00ffffef;
-#elif NR_IRQS == 32
-#ifdef CONFIG_ALPHA_MIKASA
-  static unsigned short cache_536 = 0xffff;
-#else
-  static unsigned char cache_26 = 0xdf;
-  static unsigned char cache_27 = 0xff;
-#endif
+#if NR_IRQS > 64
+#  error Unable to handle more than 64 irq levels.
 #endif
 
-static void mask_irq(int irq)
-{
-	unsigned long mask;
+/*
+ * Shadow-copy of masked interrupts.
+ *  The bits are used as follows:
+ *	 0.. 7	first ISA PIC (irq level 0..7)
+ *	 8..15	second ISA PIC (irq level 8..15)
+ *   Systems with 32 PCI interrupt lines (e.g., Alcor):
+ *	16..47	PCI interrupts 0..31 (int at GRU_INT_MASK)
+ *   Mikasa:
+ *	16..31	PCI interrupts 0..15 (short at I/O port 536)
+ *   Other systems (not Mikasa) with 16 PCI interrupt lines:
+ *	16..23	PCI interrupts 0.. 7 (char at I/O port 26)
+ *	24..31	PCI interrupts 8..15 (char at I/O port 27)
+ *   Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164):
+ *	16..32	PCI interrupts 0..31 (int at I/O port 804)
+ */
+static unsigned long irq_mask = ~0UL;
 
-	if (irq < 16) {
-		mask = 1 << (irq & 7);
-		if (irq < 8) {
-			cache_21 |= mask;
-			outb(cache_21, 0x21);
-		} else {
-			cache_A1 |= mask;
-			outb(cache_A1, 0xA1);
-		}
+
+/*
+ * Update the hardware with the irq mask passed in MASK.  The function
+ * exploits the fact that it is known that only bit IRQ has changed.
+ */
+static void update_hw(unsigned long irq, unsigned long mask)
+{
+	switch (irq) {
 #if NR_IRQS == 48
-	} else {
-		mask = 1 << (irq - 16);
-		cache_irq_mask |= mask;
-		*(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */
+	      default:
+		/* note inverted sense of mask bits: */
+		*(unsigned int *)GRU_INT_MASK = ~(mask >> 16);
+		mb();
+		break;
+
 #elif NR_IRQS == 33
-	} else {
-		mask = 1 << (irq - 16);
-		cache_804 |= mask;
-		outl(cache_804, 0x804);
+	      default:
+		outl(mask >> 16, 0x804);
+		break;
+
+#elif defined(CONFIG_ALPHA_MIKASA)
+	      default:
+		outw(~(mask >> 16), 0x536); /* note invert */
+		break;
+
 #elif NR_IRQS == 32
-#ifdef CONFIG_ALPHA_MIKASA
-	} else {
-		mask = 1 << (irq & 15);
-		cache_536 |= mask;
-		outw(~cache_536, 0x536); /* note invert */
-#else
-	} else {
-		mask = 1 << (irq & 7);
-		if (irq < 24) {
-			cache_26 |= mask;
-			outb(cache_26, 0x26);
-		} else {
-			cache_27 |= mask;
-			outb(cache_27, 0x27);
-		}
-#endif
+	      case 16 ... 23:
+		outb(mask >> 16, 0x26);
+		break;
+
+	      default:
+		outb(mask >> 24, 0x27);
+		break;
 #endif
+		/* handle ISA irqs last---fast devices belong on PCI... */
+
+	      case  0 ... 7:	/* ISA PIC1 */
+		outb(mask, 0x21);
+		break;
+
+	      case  8 ...15:	/* ISA PIC2 */
+		outb(mask >> 8, 0xA1);
+		break;
 	}
 }
 
-static void unmask_irq(unsigned long irq)
+static inline void mask_irq(unsigned long irq)
 {
-	unsigned long mask;
-
-	if (irq < 16) {
-		mask = ~(1 << (irq & 7));
-		if (irq < 8) {
-			cache_21 &= mask;
-			outb(cache_21, 0x21);
-		} else {
-			cache_A1 &= mask;
-			outb(cache_A1, 0xA1);
-		}
-#if NR_IRQS == 48
-	} else {
-		mask = ~(1 << (irq - 16));
-		cache_irq_mask &= mask;
-		*(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */
-#elif NR_IRQS == 33
-	} else {
-		mask = ~(1 << (irq - 16));
-		cache_804 &= mask;
-		outl(cache_804, 0x804);
-#elif NR_IRQS == 32
-#ifdef CONFIG_ALPHA_MIKASA
-	} else {
-		mask = ~(1 << (irq & 15));
-		cache_536 &= mask;
-		outw(~cache_536, 0x536); /* note invert */
-#else
-	} else {
-		mask = ~(1 << (irq & 7));
+	irq_mask |= (1UL << irq);
+	update_hw(irq, irq_mask);
+}
 
-		if (irq < 24) {
-			cache_26 &= mask;
-			outb(cache_26, 0x26);
-		} else {
-			cache_27 &= mask;
-			outb(cache_27, 0x27);
-		}
-#endif
-#endif
-	}
+static inline void unmask_irq(unsigned long irq)
+{
+	irq_mask &= ~(1UL << irq);
+	update_hw(irq, irq_mask);
 }
 
 void disable_irq(unsigned int irq_nr)
@@ -193,13 +167,16 @@
 		/* .. then the master */
 		outb(0xE0 | irq, 0x20);
 	}
+#if 0
+	/* This is not needed since all interrupt are level-sensitive */
 #if defined(CONFIG_ALPHA_ALCOR)
 	/* on ALCOR, need to dismiss interrupt via GRU */
-	*(int *)GRU_INT_CLEAR = 0x80000000; 
+	*(int *)GRU_INT_CLEAR = 0x80000000;
 	mb();
 	*(int *)GRU_INT_CLEAR = 0x00000000;
 	mb();
 #endif /* CONFIG_ALPHA_ALCOR */
+#endif
 }
 
 int request_irq(unsigned int irq, 
@@ -344,17 +321,6 @@
 
 	kstat.interrupts[irq]++;
 	action = irq_action[irq];
-	if (action) {
-		/* quick interrupts get executed with no extra overhead */
-		if (action->flags & SA_INTERRUPT) {
-			while (action) {
-				action->handler(irq, action->dev_id, regs);
-				action = action->next;
-			}
-			ack_irq(ack);
-			return;
-		}
-	}
 	/*
 	 * For normal interrupts, we mask it out, and then ACK it.
 	 * This way another (more timing-critical) interrupt can
@@ -370,10 +336,10 @@
 		return;
 	if (action->flags & SA_SAMPLE_RANDOM)
 		add_interrupt_randomness(irq);
-	while (action) {
+	do {
 		action->handler(irq, action->dev_id, regs);
 		action = action->next;
-	}
+	} while (action);
 	unmask_irq(ack);
 }
 
@@ -436,8 +402,8 @@
 	 *  write only.  This is not true.
 	 */
 	pic = inb(0x20) | (inb(0xA0) << 8);	/* read isr */
-	pic &= ~((cache_A1 << 8) | cache_21);	/* apply mask */
-	pic &= 0xFFFB;				/* mask out cascade */
+	pic &= ~irq_mask;			/* apply mask */
+	pic &= 0xFFFB;				/* mask out cascade & hibits */
 
 	while (pic) {
 		j = ffz(~pic);
@@ -568,17 +534,13 @@
 	restore_flags(flags) ;
 }
 
-#if NR_IRQS > 64
-#  error Number of irqs limited to 64 due to interrupt-probing.
-#endif
-
 /*
  * Start listening for interrupts..
  */
 unsigned long probe_irq_on(void)
 {
 	struct irqaction * action;
-	unsigned long irqs = 0, irqmask;
+	unsigned long irqs = 0;
 	unsigned long delay;
 	unsigned int i;
 
@@ -589,27 +551,15 @@
 			irqs |= (1 << i);
 		}
 	}
-
-	/* wait for spurious interrupts to mask themselves out again */
+	/*
+	 * Wait about 100ms for spurious interrupts to mask themselves
+	 * out again...
+	 */
 	for (delay = jiffies + HZ/10; delay > jiffies; )
-		/* about 100 ms delay */;
-	
+		barrier();
+
 	/* now filter out any obviously spurious interrupts */
-	irqmask = (((unsigned long)cache_A1)<<8) | (unsigned long) cache_21;
-#if NR_IRQS == 48
-	irqmask |= (unsigned long) cache_irq_mask << 16;
-#elif NR_IRQS == 33
-	irqmask |= (unsigned long) cache_804 << 16;
-#elif NR_IRQS == 32
-#ifdef CONFIG_ALPHA_MIKASA
-	irqmask |= (unsigned long) cache_536 << 16;
-#else
-	irqmask |= ((((unsigned long)cache_26)<<16) |
-		    (((unsigned long)cache_27)<<24));
-#endif
-#endif
-	irqs &= ~irqmask;
-	return irqs;
+	return irqs & ~irq_mask;
 }
 
 /*
@@ -619,23 +569,9 @@
  */
 int probe_irq_off(unsigned long irqs)
 {
-	unsigned long irqmask;
 	int i;
 	
-	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
-#if NR_IRQS == 48
-	irqmask |= (unsigned long) cache_irq_mask << 16;
-#elif NR_IRQS == 33
-	irqmask |= (unsigned long) cache_804 << 16;
-#elif NR_IRQS == 32
-#ifdef CONFIG_ALPHA_MIKASA
-	irqmask |= (unsigned long) cache_536 << 16;
-#else
-	irqmask |= ((((unsigned long)cache_26)<<16) |
-		    (((unsigned long)cache_27)<<24));
-#endif
-#endif
-	irqs &= irqmask & ~1;	/* always mask out irq 0---it's the unused timer */
+	irqs &= irq_mask & ~1;	/* always mask out irq 0---it's the unused timer */
 #ifdef CONFIG_ALPHA_P2K
 	irqs &= ~(1 << 8);	/* mask out irq 8 since that's the unused RTC input to PIC */
 #endif
@@ -687,11 +623,11 @@
 #elif NR_IRQS == 33
 			cabriolet_and_eb66p_device_interrupt(vector, &regs);
 #elif NR_IRQS == 32
-#ifdef CONFIG_ALPHA_MIKASA
+# ifdef CONFIG_ALPHA_MIKASA
 #	error  we got a problem here Charlie MIKASA should be SRM console
-#else
+# else
 			eb66_and_eb64p_device_interrupt(vector, &regs);
-#endif
+# endif
 #elif NR_IRQS == 16
 			isa_device_interrupt(vector, &regs);
 #endif
@@ -715,16 +651,18 @@
 	dma_outb(0, DMA1_CLR_MASK_REG);
 	dma_outb(0, DMA2_CLR_MASK_REG);
 #if NR_IRQS == 48
-	*(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */
+	*(unsigned int *)GRU_INT_MASK = ~(irq_mask >> 16);	/* invert */
+	mb();
+	enable_irq(16 + 31);	/* enable EISA PIC cascade */
 #elif NR_IRQS == 33
-	outl(cache_804, 0x804);
+	outl(irq_mask >> 16, 0x804);
+	enable_irq(16 +  4);	/* enable SIO cascade */
+#elif defined(CONFIG_ALPHA_MIKASA)
+	outw(~(irq_mask >> 16), 0x536); /* note invert */
 #elif NR_IRQS == 32
-#ifdef CONFIG_ALPHA_MIKASA
-	outw(~cache_536, 0x536); /* note invert */
-#else
-	outb(cache_26, 0x26);
-	outb(cache_27, 0x27);
-#endif
+	outb(irq_mask >> 16, 0x26);
+	outb(irq_mask >> 24, 0x27);
+	enable_irq(16 +  5);	/* enable SIO cascade */
 #endif
 	enable_irq(2);		/* enable cascade */
 }
diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.0.0/linux/arch/alpha/kernel/osf_sys.c	Fri Apr 12 15:51:45 1996
+++ linux/arch/alpha/kernel/osf_sys.c	Wed Jun 26 11:05:40 1996
@@ -125,14 +125,22 @@
 	return count - buf.count;
 }
 
-asmlinkage int osf_getpriority(int which, int who)
+/*
+ * Alpha syscall convention has no problem returning negative
+ * values:
+ */
+asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4,
+			       int a5, struct pt_regs regs)
 {
 	extern int sys_getpriority(int, int);
-	/*
-	 * Alpha syscall convention has no problem returning negative
-	 * values:
-	 */
-	return 20 - sys_getpriority(which, who);
+	int prio;
+
+	prio = sys_getpriority(which, who);
+	if (prio < 0)
+		return prio;
+
+	regs.r0 = 0; /* special return: no errors */
+	return 20 - prio;
 }
 
 
@@ -177,6 +185,7 @@
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 			return -EBADF;
 	}
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	return do_mmap(file, addr, len, prot, flags, off);
 }
 
diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.0.0/linux/arch/alpha/kernel/process.c	Wed Feb 28 12:00:49 1996
+++ linux/arch/alpha/kernel/process.c	Tue Jul  2 19:08:34 1996
@@ -8,6 +8,7 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -52,6 +53,11 @@
 
 void hard_reset_now(void)
 {
+#if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR)
+	/* who said DEC engineer's have no sense of humor? ;-)) */
+	*(int *) GRU_RESET = 0x0000dead;
+	mb();
+#endif
 	halt();
 }
 
diff -u --recursive --new-file v2.0.0/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v2.0.0/linux/arch/alpha/kernel/signal.c	Fri Apr 19 10:07:57 1996
+++ linux/arch/alpha/kernel/signal.c	Tue Jul  2 19:08:34 1996
@@ -130,24 +130,28 @@
 /*
  * Set up a signal frame...
  */
-static void setup_frame(struct sigaction * sa, struct sigcontext_struct ** fp,
-			unsigned long pc, struct pt_regs * regs,
+static void setup_frame(struct sigaction * sa,
+			struct pt_regs * regs,
 			struct switch_stack * sw, int signr,
 			unsigned long oldmask)
 {
 	int i;
+	unsigned long oldsp;
 	struct sigcontext_struct * sc;
 
-	sc = *fp;
+	oldsp = rdusp();
+	sc = ((struct sigcontext_struct *) oldsp) - 1;
+
 	/* check here if we would need to switch stacks.. */
-	sc--;
 	if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
 		do_exit(SIGSEGV);
 
+	wrusp((unsigned long) sc);
+
 	put_fs_quad(oldmask, &sc->sc_mask);
 	put_fs_quad(8, &sc->sc_ps);
-	put_fs_quad(pc, &sc->sc_pc);
-	put_fs_quad((unsigned long)*fp, sc->sc_regs+30);
+	put_fs_quad(regs->pc, &sc->sc_pc);
+	put_fs_quad(oldsp, sc->sc_regs+30);
 
 	put_fs_quad(regs->r0 , sc->sc_regs+0);
 	put_fs_quad(regs->r1 , sc->sc_regs+1);
@@ -193,14 +197,51 @@
 	 */
 	put_fs_quad(0x43ecf40047de0410, sc->sc_retcode+0);
 	put_fs_quad(0x0000000000000083, sc->sc_retcode+1);
+	imb();
+
+	/* "return" to the handler */
+	regs->r27 = regs->pc = (unsigned long) sa->sa_handler;
 	regs->r26 = (unsigned long) sc->sc_retcode;
 	regs->r16 = signr;		/* a0: signal number */
 	regs->r17 = 0;			/* a1: exception code; see gentrap.h */
 	regs->r18 = (unsigned long) sc;	/* a2: sigcontext pointer */
-	*fp = sc;
 }
 
 /*
+ * OK, we're invoking a handler
+ */
+static inline void handle_signal(unsigned long signr, struct sigaction *sa,
+	unsigned long oldmask, struct pt_regs * regs, struct switch_stack *sw)
+{
+	setup_frame(sa,regs,sw,signr,oldmask);
+
+	if (sa->sa_flags & SA_ONESHOT)
+		sa->sa_handler = NULL;
+	if (!(sa->sa_flags & SA_NOMASK))
+		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+}
+
+static inline void syscall_restart(unsigned long r0, unsigned long r19,
+	struct pt_regs * regs, struct sigaction * sa)
+{
+	switch (regs->r0) {
+		case ERESTARTNOHAND:
+		no_system_call_restart:
+			regs->r0 = EINTR;
+			break;
+		case ERESTARTSYS:
+			if (!(sa->sa_flags & SA_RESTART))
+				goto no_system_call_restart;
+		/* fallthrough */
+		case ERESTARTNOINTR:
+			regs->r0 = r0;	/* reset v0 and a3 and replay syscall */
+			regs->r19 = r19;
+			regs->pc -= 4;
+	}
+}
+
+
+/*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
@@ -219,9 +260,6 @@
 	unsigned long r0, unsigned long r19)
 {
 	unsigned long mask = ~current->blocked;
-	unsigned long handler_signal = 0;
-	struct sigcontext_struct *frame = NULL;
-	unsigned long pc = 0;
 	unsigned long signr, single_stepping;
 	struct sigaction * sa;
 
@@ -264,7 +302,10 @@
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
 
-			case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+			case SIGSTOP:
 				if (current->flags & PF_PTRACED)
 					continue;
 				current->state = TASK_STOPPED;
@@ -289,16 +330,13 @@
 				do_exit(signr);
 			}
 		}
-		/*
-		 * OK, we're invoking a handler
-		 */
-		if (r0) {
-			if (regs->r0 == ERESTARTNOHAND ||
-			   (regs->r0 == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
-				regs->r0 = EINTR;
+		if (r0)
+			syscall_restart(r0, r19, regs, sa);
+		handle_signal(signr, sa, oldmask, regs, sw);
+		if (single_stepping) {
+			ptrace_set_bpt(current);	/* re-set breakpoint */
 		}
-		handler_signal |= 1 << (signr-1);
-		mask &= ~sa->sa_mask;
+		return 1;
 	}
 	if (r0 &&
 	    (regs->r0 == ERESTARTNOHAND ||
@@ -308,34 +346,8 @@
 		regs->r19 = r19;
 		regs->pc -= 4;
 	}
-	if (!handler_signal) {	/* no handler will be called - return 0 */
-		if (single_stepping) {
-			ptrace_set_bpt(current);	/* re-set breakpoint */
-		}
-		return 0;
-	}
-	pc = regs->pc;
-	frame = (struct sigcontext_struct *) rdusp();
-	signr = 1;
-	sa = current->sig->action;
-	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
-		if (mask > handler_signal)
-			break;
-		if (!(mask & handler_signal))
-			continue;
-		setup_frame(sa,&frame,pc,regs,sw,signr,oldmask);
-		pc = (unsigned long) sa->sa_handler;
-		regs->r27 = pc;
-		if (sa->sa_flags & SA_ONESHOT)
-			sa->sa_handler = NULL;
-		current->blocked |= sa->sa_mask;
-		oldmask |= sa->sa_mask;
-	}
-	imb();
-	wrusp((unsigned long) frame);
-	regs->pc = pc;			/* "return" to the first handler */
 	if (single_stepping) {
 		ptrace_set_bpt(current);	/* re-set breakpoint */
 	}
-	return 1;
+	return 0;
 }
diff -u --recursive --new-file v2.0.0/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c
--- v2.0.0/linux/arch/i386/kernel/ksyms.c	Thu Feb 15 07:13:13 1996
+++ linux/arch/i386/kernel/ksyms.c	Sat Jun 29 12:00:45 1996
@@ -14,6 +14,7 @@
 #ifdef __SMP__
 	X(apic_reg),		/* Needed internally for the I386 inlines */
 	X(cpu_data),
+	X(syscall_count),
 #endif
 #include <linux/symtab_end.h>
 };
diff -u --recursive --new-file v2.0.0/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.0.0/linux/arch/i386/kernel/signal.c	Tue May  7 16:22:17 1996
+++ linux/arch/i386/kernel/signal.c	Tue Jul  2 19:08:34 1996
@@ -248,7 +248,8 @@
 
 	if (sa->sa_flags & SA_ONESHOT)
 		sa->sa_handler = NULL;
-	current->blocked |= sa->sa_mask;
+	if (!(sa->sa_flags & SA_NOMASK))
+		current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
 }
 
 /*
@@ -310,7 +311,10 @@
 			case SIGCONT: case SIGCHLD: case SIGWINCH:
 				continue;
 
-			case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+			case SIGTSTP: case SIGTTIN: case SIGTTOU:
+				if (is_orphaned_pgrp(current->pgrp))
+					continue;
+			case SIGSTOP:
 				if (current->flags & PF_PTRACED)
 					continue;
 				current->state = TASK_STOPPED;
diff -u --recursive --new-file v2.0.0/linux/drivers/block/README.md linux/drivers/block/README.md
--- v2.0.0/linux/drivers/block/README.md	Mon Feb 26 13:51:45 1996
+++ linux/drivers/block/README.md	Tue Jun 11 13:00:11 1996
@@ -1,4 +1,4 @@
 Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr
-in public/Linux/md034.tar.gz.
+in public/Linux/md035.tar.gz.
 
 	Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
diff -u --recursive --new-file v2.0.0/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.0.0/linux/drivers/block/ide.c	Thu Jun  6 17:42:32 1996
+++ linux/drivers/block/ide.c	Tue Jul  2 19:08:34 1996
@@ -1794,7 +1794,7 @@
 	unsigned long flags;
 
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
-		return -ENODEV;
+		return -ENXIO;
 	save_flags(flags);
 	cli();
 	while (drive->busy)
diff -u --recursive --new-file v2.0.0/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.0.0/linux/drivers/block/loop.c	Tue May  7 16:22:22 1996
+++ linux/drivers/block/loop.c	Tue Jul  2 19:08:41 1996
@@ -6,6 +6,7 @@
  * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
  * permitted under the GNU Public License.
  *
+ * more DES encryption plus IDEA encryption by Nicholas J. Leon, June 20, 1996
  * DES encryption plus some minor changes by Werner Almesberger, 30-MAY-1993
  *
  * Modularized and updated for 1.1.16 kernel - Mitch Dsouza 28th May 1994
@@ -15,6 +16,7 @@
 
 #include <linux/module.h>
 
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
@@ -22,9 +24,14 @@
 
 #include <asm/segment.h>
 
-#ifdef DES_AVAILABLE
-#include "des.h"
+#ifdef CONFIG_BLK_DEV_LOOP_DES
+#include <linux/des.h>
+#endif
+
+#ifdef CONFIG_BLK_DEV_LOOP_IDEA
+#include <linux/idea.h>
 #endif
+
 #include <linux/loop.h>		/* must follow des.h */
 
 #define MAJOR_NR LOOP_MAJOR
@@ -113,6 +120,23 @@
 }
 #endif
 
+#ifdef IDEA_AVAILABLE
+
+extern void idea_encrypt_block(idea_key,char *,char *,int);
+
+static int transfer_idea(struct loop_device *lo, int cmd, char *raw_buf,
+		  char *loop_buf, int size)
+{
+  if (cmd==READ) {
+    idea_encrypt_block(lo->lo_idea_en_key,raw_buf,loop_buf,size);
+  }
+  else {
+    idea_encrypt_block(lo->lo_idea_de_key,loop_buf,raw_buf,size);
+  }
+  return 0;
+}
+#endif
+
 static transfer_proc_t xfer_funcs[MAX_LOOP] = {
 	transfer_none,		/* LO_CRYPT_NONE */
 	transfer_xor,		/* LO_CRYPT_XOR */
@@ -121,7 +145,11 @@
 #else
 	NULL,			/* LO_CRYPT_DES */
 #endif
-	0			/* LO_CRYPT_IDEA */
+#ifdef IDEA_AVAILABLE           /* LO_CRYPT_IDEA */
+	transfer_idea
+#else
+	NULL
+#endif
 };
 
 
@@ -225,8 +253,10 @@
 			brelse(bh);
 			goto error_out;
 		}
-		if (CURRENT->cmd == WRITE)
+		if (CURRENT->cmd == WRITE) {
+			mark_buffer_uptodate(bh, 1);
 			mark_buffer_dirty(bh, 1);
+		}
 		brelse(bh);
 		dest_addr += size;
 		len -= size;
@@ -335,6 +365,20 @@
 		memcpy(lo->lo_des_init,info.lo_init,8);
 		break;
 #endif
+#ifdef IDEA_AVAILABLE
+	case LO_CRYPT_IDEA:
+	  {
+	        uint16 tmpkey[8];
+
+	        if (info.lo_encrypt_key_size != IDEAKEYSIZE)
+		        return -EINVAL;
+                /* create key in lo-> from info.lo_encrypt_key */
+		memcpy(tmpkey,info.lo_encrypt_key,sizeof(tmpkey));
+		en_key_idea(tmpkey,lo->lo_idea_en_key);
+		de_key_idea(lo->lo_idea_en_key,lo->lo_idea_de_key);
+		break;
+	  }
+#endif
 	default:
 		return -EINVAL;
 	}
@@ -494,6 +538,12 @@
 	}
 #ifndef MODULE
 	printk("loop: registered device at major %d\n", MAJOR_NR);
+#ifdef DES_AVAILABLE
+	printk("loop: DES encryption available\n");
+#endif
+#ifdef IDEA_AVAILABLE
+	printk("loop: IDEA encryption available\n");
+#endif
 #endif
 
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
diff -u --recursive --new-file v2.0.0/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.0.0/linux/drivers/block/md.c	Tue May 21 19:52:34 1996
+++ linux/drivers/block/md.c	Sun Jun 30 00:04:00 1996
@@ -163,6 +163,7 @@
   {
     md_dev[minor].devices[i].size &= ~(min - 1);
     md_size[minor] += md_dev[minor].devices[i].size;
+    md_dev[minor].devices[i].offset=i ? (md_dev[minor].devices[i-1].offset + md_dev[minor].devices[i-1].size) : 0;
   }
 
   md_dev[minor].pers=pers[pnum];
@@ -218,6 +219,7 @@
     clear_inode (md_dev[minor].devices[i].inode);
   
   md_dev[minor].nb_dev=md_size[minor]=0;
+  md_hd_struct[minor].nr_sects=0;
   md_dev[minor].pers=NULL;
   
   set_ra ();			/* calculate new read_ahead */
@@ -257,14 +259,7 @@
   /* Sizes are now rounded at run time */
   
   md_dev[minor].devices[i].size=gen_real->sizes[MINOR(dev)];
-  md_dev[minor].devices[i].offset=i ?
-    (md_dev[minor].devices[i-1].offset + md_dev[minor].devices[i-1].size) : 0;
-  
-  if (!i)
-    md_size[minor]=0;
-  
-  md_size[minor]+=md_dev[minor].devices[i].size;
-  
+
   printk ("REGISTER_DEV %s to md%x done\n", partition_name(dev), minor);
   return (0);
 }
@@ -372,11 +367,33 @@
 }
 
 
+static int md_read (struct inode *inode, struct file *file,
+		    char *buf, int count)
+{
+  int minor=MINOR(inode->i_rdev);
+
+  if (!md_dev[minor].pers)	/* Check if device is being run */
+    return -ENXIO;
+
+  return block_read (inode, file, buf, count);
+}
+
+static int md_write (struct inode *inode, struct file *file,
+		     const char *buf, int count)
+{
+  int minor=MINOR(inode->i_rdev);
+
+  if (!md_dev[minor].pers)	/* Check if device is being run */
+    return -ENXIO;
+
+  return block_write (inode, file, buf, count);
+}
+
 static struct file_operations md_fops=
 {
   NULL,
-  block_read,
-  block_write,
+  md_read,
+  md_write,
   NULL,
   NULL,
   md_ioctl,
@@ -431,6 +448,7 @@
   {
     md_blocksizes[i] = 1024;
     md_gendisk.part[i].start_sect=-1; /* avoid partition check */
+    md_gendisk.part[i].nr_sects=0;
     md_dev[i].pers=NULL;
   }
 
@@ -448,7 +466,7 @@
 
 int get_md_status (char *page)
 {
-  int sz=0, i, j;
+  int sz=0, i, j, size;
 
   sz+=sprintf( page+sz, "Personalities : ");
   for (i=0; i<MAX_PERSONALITY; i++)
@@ -470,12 +488,16 @@
     if (md_dev[i].pers)
       sz+=sprintf (page+sz, " %s", md_dev[i].pers->name);
 
+    size=0;
     for (j=0; j<md_dev[i].nb_dev; j++)
+    {
       sz+=sprintf (page+sz, " %s",
 		   partition_name(md_dev[i].devices[j].dev));
+      size+=md_dev[i].devices[j].size;
+    }
     
     if (md_dev[i].nb_dev)
-      sz+=sprintf (page+sz, " %d blocks", md_size[i]);
+      sz+=sprintf (page+sz, " %d blocks", size);
 
     if (!md_dev[i].pers)
     {
diff -u --recursive --new-file v2.0.0/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.0.0/linux/drivers/block/rd.c	Mon Apr 29 18:05:16 1996
+++ linux/drivers/block/rd.c	Tue Jul  2 19:08:41 1996
@@ -233,7 +233,7 @@
 #endif
 
 	if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
-		return -ENODEV;
+		return -ENXIO;
 
 	MOD_INC_USE_COUNT;
 
diff -u --recursive --new-file v2.0.0/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.0.0/linux/drivers/block/xd.c	Thu Jun  6 17:42:32 1996
+++ linux/drivers/block/xd.c	Tue Jul  2 19:08:41 1996
@@ -211,7 +211,7 @@
 		return (0);
 	}
 	else
-		return (-ENODEV);
+		return -ENXIO;
 }
 
 /* do_xd_request: handle an incoming request */
diff -u --recursive --new-file v2.0.0/linux/drivers/char/baycom.c linux/drivers/char/baycom.c
--- v2.0.0/linux/drivers/char/baycom.c	Thu Jun  6 17:42:34 1996
+++ linux/drivers/char/baycom.c	Sat Jun 29 12:00:45 1996
@@ -236,7 +236,6 @@
 	unsigned int dcd_shreg;
 	unsigned long descram;
 	unsigned long scram;
-	unsigned char last_rxbit;
 };
 
 struct modem_state {
@@ -581,8 +580,7 @@
 
 /* ---------------------------------------------------------------------- */
 /*
- * The HDLC routines could be more efficient; they could take more than
- * one bit per call
+ * The HDLC routines
  */
 
 static inline int hdlc_rx_add_bytes(struct baycom_state *bc, 
@@ -1212,7 +1210,7 @@
 {
 	register struct baycom_state *bc = (struct baycom_state *)dev_id;
 	int i;
-	unsigned int data, rawdata, mask, mask2;
+	unsigned int data, mask, mask2;
 	
 	if (!bc || bc->magic != BAYCOM_MAGIC)
 		return;
@@ -1270,7 +1268,7 @@
 	/*
 	 * do receiver; differential decode and descramble on the fly
 	 */
-	for(rawdata = data = i = 0; i < PAR96_BURSTBITS; i++) {
+	for(data = i = 0; i < PAR96_BURSTBITS; i++) {
 		unsigned int descx;
 		bc->modem.par96.descram = (bc->modem.par96.descram << 1);
 		if (inb(LPT_STATUS(bc->iobase)) & PAR96_RXBIT)
@@ -1281,14 +1279,9 @@
 		outb(PAR97_POWER | PAR96_PTT, LPT_DATA(bc->iobase));
 		descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^
 			  (descx >> PAR96_DESCRAM_TAPSH2));
-		if (descx & 1)
-			bc->modem.par96.last_rxbit = 
-				!bc->modem.par96.last_rxbit;
 		data >>= 1;
-		if (bc->modem.par96.last_rxbit)
+		if (!(descx & 1))
 			data |= 0x8000;
-		rawdata <<= 1;
-		rawdata |= !(descx & 1);
 		outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, 
 		     LPT_DATA(bc->iobase));
 	}
@@ -1304,16 +1297,16 @@
 	 * do DCD algorithm
 	 */
 	if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
-		bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg << 16)
-			| rawdata;
+		bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16)
+			| (data << 16);
 		/* search for flags and set the dcd counter appropriately */
-		for(mask = 0x7f8000, mask2 = 0x3f0000, i = 0; 
-		    i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1)
+		for(mask = 0x1fe00, mask2 = 0xfc00, i = 0; 
+		    i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)
 			if ((bc->modem.par96.dcd_shreg & mask) == mask2)
 				bc->modem.par96.dcd_count = BAYCOM_MAXFLEN+4;
 		/* check for abort/noise sequences */
-		for(mask = 0x3f8000, mask2 = 0x3f8000, i = 0; 
-		    i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1)
+		for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0; 
+		    i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)
 			if ((bc->modem.par96.dcd_shreg & mask) == mask2)
 				if (bc->modem.par96.dcd_count >= 0)
 					bc->modem.par96.dcd_count -= 
diff -u --recursive --new-file v2.0.0/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.0.0/linux/drivers/char/console.c	Fri May 17 15:32:14 1996
+++ linux/drivers/char/console.c	Tue Jul  2 19:08:41 1996
@@ -306,7 +306,7 @@
 int vc_allocate(unsigned int i)		/* return 0 on success */
 {
 	if (i >= MAX_NR_CONSOLES)
-	  return -ENODEV;
+	  return -ENXIO;
 	if (!vc_cons[i].d) {
 	    long p, q;
 
diff -u --recursive --new-file v2.0.0/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.0.0/linux/drivers/char/lp.c	Tue May  7 16:22:24 1996
+++ linux/drivers/char/lp.c	Tue Jul  2 19:08:41 1996
@@ -322,9 +322,9 @@
 	unsigned int irq;
 
 	if (minor >= LP_NO)
-		return -ENODEV;
+		return -ENXIO;
 	if ((LP_F(minor) & LP_EXIST) == 0)
-		return -ENODEV;
+		return -ENXIO;
 	if (LP_F(minor) & LP_BUSY)
 		return -EBUSY;
 
diff -u --recursive --new-file v2.0.0/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.0.0/linux/drivers/char/mem.c	Sat Apr 27 15:19:51 1996
+++ linux/drivers/char/mem.c	Tue Jul  2 19:08:41 1996
@@ -358,7 +358,7 @@
 			filp->f_op = &urandom_fops;
 			break;
 		default:
-			return -ENODEV;
+			return -ENXIO;
 	}
 	if (filp->f_op && filp->f_op->open)
 		return filp->f_op->open(inode,filp);
diff -u --recursive --new-file v2.0.0/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.0.0/linux/drivers/char/n_tty.c	Wed Apr 24 17:00:38 1996
+++ linux/drivers/char/n_tty.c	Tue Jul  2 19:08:41 1996
@@ -201,7 +201,7 @@
 			tty->read_head = tty->canon_head;
 			return;
 		}
-		if (!L_ECHOK(tty) || !L_ECHOKE(tty)) {
+		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
 			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
 					  (N_TTY_BUF_SIZE - 1));
 			tty->read_head = tty->canon_head;
@@ -236,7 +236,7 @@
 					tty->erasing = 1;
 				}
 				echo_char(c, tty);
-			} else if (!L_ECHOE(tty)) {
+			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
 				echo_char(ERASE_CHAR(tty), tty);
 			} else if (c == '\t') {
 				unsigned int col = tty->canon_column;
@@ -290,11 +290,11 @@
 		finish_erasing(tty);
 }
 
-static void isig(int sig, struct tty_struct *tty)
+static inline void isig(int sig, struct tty_struct *tty, int flush)
 {
 	if (tty->pgrp > 0)
 		kill_pg(tty->pgrp, sig, 1);
-	if (!L_NOFLSH(tty)) {
+	if (flush || !L_NOFLSH(tty)) {
 		n_tty_flush_buffer(tty);
 		if (tty->driver.flush_buffer)
 			tty->driver.flush_buffer(tty);
@@ -306,7 +306,7 @@
 	if (I_IGNBRK(tty))
 		return;
 	if (I_BRKINT(tty)) {
-		isig(SIGINT, tty);
+		isig(SIGINT, tty, 1);
 		return;
 	}
 	if (I_PARMRK(tty)) {
@@ -340,8 +340,10 @@
 		put_tty_queue('\377', tty);
 		put_tty_queue('\0', tty);
 		put_tty_queue(c, tty);
-	} else
+	} else	if (I_INPCK(tty))
 		put_tty_queue('\0', tty);
+	else
+		put_tty_queue(c, tty);
 	wake_up_interruptible(&tty->read_wait);
 }
 
@@ -415,17 +417,17 @@
 		}
 	}
 	if (L_ISIG(tty)) {
-		if (c == INTR_CHAR(tty)) {
-			isig(SIGINT, tty);
-			return;
-		}
-		if (c == QUIT_CHAR(tty)) {
-			isig(SIGQUIT, tty);
-			return;
-		}
+		int signal;
+		signal = SIGINT;
+		if (c == INTR_CHAR(tty))
+			goto send_signal;
+		signal = SIGQUIT;
+		if (c == QUIT_CHAR(tty))
+			goto send_signal;
+		signal = SIGTSTP;
 		if (c == SUSP_CHAR(tty)) {
-			if (!is_orphaned_pgrp(tty->pgrp))
-				isig(SIGTSTP, tty);
+send_signal:
+			isig(signal, tty, 0);
 			return;
 		}
 	}
diff -u --recursive --new-file v2.0.0/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v2.0.0/linux/drivers/char/pty.c	Thu Jun  6 22:35:44 1996
+++ linux/drivers/char/pty.c	Tue Jul  2 19:08:42 1996
@@ -244,6 +244,12 @@
 	return retval;
 }
 
+static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+        tty->termios->c_cflag &= ~(CSIZE | PARENB);
+        tty->termios->c_cflag |= (CS8 | CREAD);
+}
+
 int pty_init(void)
 {
 	memset(&pty_state, 0, sizeof(pty_state));
@@ -274,6 +280,7 @@
 	pty_driver.flush_buffer = pty_flush_buffer;
 	pty_driver.chars_in_buffer = pty_chars_in_buffer;
 	pty_driver.unthrottle = pty_unthrottle;
+	pty_driver.set_termios = pty_set_termios;
 
 	pty_slave_driver = pty_driver;
 	pty_slave_driver.name = "ttyp";
diff -u --recursive --new-file v2.0.0/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.0.0/linux/drivers/char/random.c	Thu Jun  6 22:35:44 1996
+++ linux/drivers/char/random.c	Tue Jul  2 19:08:42 1996
@@ -357,8 +357,6 @@
 #if (!defined (__i386__))
 extern inline __u32 rotate_left(int i, __u32 word)
 {
-	__u32 nbits = 0;
-	
 	return (word << i) | (word >> (32 - i));
 	
 }
diff -u --recursive --new-file v2.0.0/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.0.0/linux/drivers/char/serial.c	Sun Jun  9 13:28:42 1996
+++ linux/drivers/char/serial.c	Tue Jul  2 19:08:42 1996
@@ -2755,9 +2755,8 @@
 	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
 	serial_driver.subtype = SERIAL_TYPE_NORMAL;
 	serial_driver.init_termios = tty_std_termios;
-	serial_driver.init_termios.c_cflag =
-		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.init_termios.c_lflag &=~ (ISIG | ICANON | ECHO);
+	serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
 	serial_driver.refcount = &serial_refcount;
 	serial_driver.table = serial_table;
 	serial_driver.termios = serial_termios;
diff -u --recursive --new-file v2.0.0/linux/drivers/char/softdog.c linux/drivers/char/softdog.c
--- v2.0.0/linux/drivers/char/softdog.c	Mon May 13 23:02:48 1996
+++ linux/drivers/char/softdog.c	Sat Jun 29 12:00:46 1996
@@ -73,6 +73,7 @@
 	/*
 	 *	Activate timer
 	 */
+	del_timer(&watchdog_ticktock);
 	watchdog_ticktock.expires=jiffies + (soft_margin * HZ);
 	add_timer(&watchdog_ticktock);
 	timer_alive++;
diff -u --recursive --new-file v2.0.0/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.0.0/linux/drivers/char/tty_io.c	Thu Jun  6 22:35:44 1996
+++ linux/drivers/char/tty_io.c	Tue Jul  2 19:08:42 1996
@@ -330,7 +330,7 @@
 static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
 			     unsigned int cmd, unsigned long arg)
 {
-	return -EIO;
+	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
 }
 
 static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
@@ -475,8 +475,10 @@
 {
 	struct tty_struct *tty = current->tty;
 	struct task_struct *p;
+	int tty_pgrp = -1;
 
 	if (tty) {
+		tty_pgrp = tty->pgrp;
 		if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)
 			tty_vhangup(tty);
 	} else {
@@ -486,9 +488,10 @@
 		}
 		return;
 	}
-	if (tty->pgrp > 0) {
-		kill_pg(tty->pgrp, SIGHUP, on_exit);
-		kill_pg(tty->pgrp, SIGCONT, on_exit);
+	if (tty_pgrp > 0) {
+		kill_pg(tty_pgrp, SIGHUP, on_exit);
+		if (!on_exit)
+			kill_pg(tty_pgrp, SIGCONT, on_exit);
 	}
 
 	current->tty_old_pgrp = 0;
@@ -1496,6 +1499,8 @@
 			return 0;
 		case TIOCSPGRP:
 			retval = tty_check_change(real_tty);
+			if (retval == -EIO)
+				return -ENOTTY;
 			if (retval)
 				return retval;
 			if (!current->tty ||
@@ -1816,7 +1821,7 @@
 	memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
 	tty_std_termios.c_iflag = ICRNL | IXON;
 	tty_std_termios.c_oflag = OPOST | ONLCR;
-	tty_std_termios.c_cflag = B38400 | CS8 | CREAD;
+	tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;
 	tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
 		ECHOCTL | ECHOKE | IEXTEN;
 
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
--- v2.0.0/linux/drivers/isdn/icn/icn.c	Sun Jun  9 13:28:42 1996
+++ linux/drivers/isdn/icn/icn.c	Sat Jun 29 20:36:22 1996
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.24 1996/06/06 13:58:33 fritz Exp $
+/* $Id: icn.c,v 1.28 1996/06/28 17:02:53 fritz Exp $
  *
  * ISDN low-level module for the ICN active ISDN-Card.
  *
@@ -19,6 +19,23 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: icn.c,v $
+ * Revision 1.28  1996/06/28 17:02:53  fritz
+ * replaced memcpy_fromfs_toio.
+ *
+ * Revision 1.27  1996/06/25 18:38:59  fritz
+ * Fixed function name in error message.
+ *
+ * Revision 1.26  1996/06/24 17:20:35  fritz
+ * Bugfixes in pollbchan_send():
+ *   - Using lock field of skbuff breaks networking.
+ *   - Added channel locking
+ *   - changed dequeuing scheme.
+ * Eliminated misc. compiler warnings.
+ *
+ * Revision 1.25  1996/06/11 22:53:35  tsbogend
+ * fixed problem with large array on stack
+ * made the driver working on Linux/alpha
+ *
  * Revision 1.24  1996/06/06 13:58:33  fritz
  * Changed code to be architecture independent
  *
@@ -119,7 +136,7 @@
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.24 $";
+*revision = "$Revision: 1.28 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -135,10 +152,8 @@
         
         save_flags(flags);
         cli();
-        while ((skb = skb_dequeue(queue))) {
-                skb->free = 1;
-                kfree_skb(skb, FREE_WRITE);
-        }
+        while ((skb = skb_dequeue(queue)))
+                dev_kfree_skb(skb, FREE_WRITE);
         restore_flags(flags);
 }
 
@@ -312,7 +327,7 @@
 
         if (icn_trymaplock_channel(card,mch)) {
                 while (rbavl) {
-                        cnt = rbuf_l;
+                        cnt = readb(&rbuf_l);
                         if ((card->rcvidx[channel] + cnt) > 4000) {
                                 printk(KERN_WARNING 
                                        "icn: (%s) bogus packet on ch%d, dropping.\n",
@@ -322,9 +337,9 @@
                                 eflag = 0;
                         } else {
                                 memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
-                                              rbuf_d, cnt);
+                                              &rbuf_d, cnt);
                                 card->rcvidx[channel] += cnt;
-                                eflag = rbuf_f;
+                                eflag = readb(&rbuf_f);
                         }
                         rbnext;
                         icn_maprelease_channel(card, mch & 2);
@@ -367,36 +382,37 @@
                 while (sbfree && card->sndcount[channel]) {
                         save_flags(flags);
                         cli();
-                        skb = skb_peek(&card->spqueue[channel]);
-                        if (!skb) {
-                                restore_flags(flags);
-                                break;
-                        }
-                        if (skb->lock) {
+                        if (card->xmit_lock[channel]) {
                                 restore_flags(flags);
                                 break;
                         }
-                        skb->lock = 1;
+                        card->xmit_lock[channel]++;
                         restore_flags(flags);
-                        cnt =
-                            (sbuf_l =
-                             (skb->len > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), skb->len));
-                        memcpy(sbuf_d, skb->data, cnt);
+                        skb = skb_dequeue(&card->spqueue[channel]);
+                        if (!skb)
+                                break;
+		        if (skb->len > ICN_FRAGSIZE) {
+			    writeb (0xff, &sbuf_f);
+			    cnt = ICN_FRAGSIZE;
+			} else {
+			    writeb (0x0, &sbuf_f);
+			    cnt = skb->len;
+			}
+		        writeb (cnt, &sbuf_l);		    
+                        memcpy_toio(&sbuf_d, skb->data, cnt);
                         skb_pull(skb, cnt);
                         card->sndcount[channel] -= cnt;
                         sbnext;        /* switch to next buffer        */
                         icn_maprelease_channel(card, mch & 2);
                         if (!skb->len) {
-                                skb = skb_dequeue(&card->spqueue[channel]);
-                                skb->free = 1;
-                                skb->lock = 0;
-                                kfree_skb(skb, FREE_WRITE);
+                                dev_kfree_skb(skb, FREE_WRITE);
                                 cmd.command = ISDN_STAT_BSENT;
                                 cmd.driver = card->myid;
                                 cmd.arg = channel;
                                 card->interface.statcallb(&cmd);
                         } else
-                                skb->lock = 0;
+                                skb_queue_head(&card->spqueue[channel], skb);
+                        card->xmit_lock[channel] = 0;
                         if (!icn_trymaplock_channel(card, mch))
                                 break;
                 }
@@ -426,6 +442,7 @@
                         /* schedule b-channel polling again */
                         save_flags(flags);
                         cli();
+                        del_timer(&card->rb_timer);
                         card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
                         add_timer(&card->rb_timer);
                         card->flags |= ICN_FLAGS_RBTIMER;
@@ -649,6 +666,7 @@
         /* schedule again */
         save_flags(flags);
         cli();
+        del_timer(&card->st_timer);
         card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
         add_timer(&card->st_timer);
         restore_flags(flags);
@@ -671,8 +689,8 @@
         unsigned long flags;
 
         if (len > 4000) {
-                skb->free = 1;
-                kfree_skb(skb, FREE_WRITE);
+                printk(KERN_WARNING
+                       "icn: Send packet too large\n");
                 return -EINVAL;
         }
         if (len) {
@@ -685,7 +703,6 @@
                 card->sndcount[channel] += len;
                 skb_queue_tail(&card->spqueue[channel], skb);
                 restore_flags(flags);
-                icn_pollbchan_send(channel, card);
         }
         return len;
 }
@@ -751,13 +768,17 @@
 {
         int ret;
         ulong flags;
-        unsigned char codebuf[ICN_CODE_STAGE1];
+	u_char *codebuf;
 
 #ifdef BOOT_DEBUG
         printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
 #endif
         if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1)))
                 return ret;
+        if (!(codebuf = kmalloc(ICN_CODE_STAGE1,GFP_KERNEL))) {
+                printk(KERN_WARNING "icn: Could not allocate code buffer\n");
+                return -ENOMEM;
+        }
         save_flags(flags);
         cli();
         if (!card->rvalid) {
@@ -768,6 +789,7 @@
                                card->port,
                                card->port + ICN_PORTLEN);
                         restore_flags(flags);
+                        kfree(codebuf);
                         return -EBUSY;
                 }
                 request_region(card->port, ICN_PORTLEN, card->regname);
@@ -804,8 +826,8 @@
         icn_lock_channel(card,0);                                  /* Lock Bank 0      */
         restore_flags(flags);
         SLEEP(1);
-        memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1);           /* Copy code        */
-        memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);
+        memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1);
+        memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);           /* Copy code        */
 #ifdef BOOT_DEBUG
         printk(KERN_DEBUG "Bootloader transfered\n");
 #endif
@@ -821,12 +843,12 @@
                 icn_lock_channel(card,2);                          /* Lock Bank 8     */
                 restore_flags(flags);
                 SLEEP(1);
-                memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1);   /* Copy code        */
-                memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);
+                memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);           /* Copy code        */
 #ifdef BOOT_DEBUG
                 printk(KERN_DEBUG "Bootloader transfered\n");
 #endif
         }
+        kfree(codebuf);
         SLEEP(1);
         OUTB_P(0xff, ICN_RUN);                                     /* Start Boot-Code */
         if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1)))
@@ -849,6 +871,7 @@
 static int icn_loadproto(u_char * buffer, icn_card * card)
 {
         register u_char *p = buffer;
+        u_char codebuf[256];
         uint left = ICN_CODE_STAGE2;
         uint cnt;
         int timer;
@@ -874,7 +897,8 @@
         while (left) {
                 if (sbfree) {                           /* If there is a free buffer...  */
                         cnt = MIN(256, left);
-                        memcpy_fromfs(&sbuf_l, p, cnt); /* copy data                     */
+                        memcpy_fromfs(codebuf, p, cnt);
+                        memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data                     */ 
                         sbnext;                         /* switch to next buffer         */
                         p += cnt;
                         left -= cnt;
@@ -892,7 +916,7 @@
                         schedule();
                 }
         }
-        sbuf_n = 0x20;
+        writeb (0x20, &sbuf_n);
         timer = 0;
         while (1) {
                 if (readb(&cmd_o) || readb(&cmd_i)) {
@@ -1094,7 +1118,7 @@
                                 }
                                 break;
                         case ICN_IOCTL_GETMMIO:
-                                return (int) dev.shmem;
+                                return (long) dev.shmem;
                         case ICN_IOCTL_SETPORT:
                                 if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
                                     || a == 0x340 || a == 0x350 || a == 0x360 ||
@@ -1391,7 +1415,8 @@
         if (card)
                 return (icn_command(c, card));
         printk(KERN_ERR
-               "icn: if_command called with invalid driverId!\n");
+               "icn: if_command %d called with invalid driverId %d!\n",
+		c->command, c->driver);
         return -ENODEV;
 }
 
@@ -1433,7 +1458,7 @@
                 return (icn_sendbuf(channel, skb, card));
         }
         printk(KERN_ERR
-               "icn: if_readstatus called with invalid driverId!\n");
+               "icn: if_sendbuf called with invalid driverId!\n");
         return -ENODEV;
 }
 
@@ -1455,9 +1480,6 @@
         card->interface.channels = ICN_BCH;
         card->interface.maxbufsize = 4000;
         card->interface.command = if_command;
-	/*
-        card->interface.writebuf = if_sendbuf;
-	*/
 	card->interface.writebuf_skb = if_sendbuf;
         card->interface.writecmd = if_writecmd;
         card->interface.readstat = if_readstatus;
@@ -1558,7 +1580,7 @@
         char rev[10];
 
         memset(&dev, 0, sizeof(icn_dev));
-        dev.shmem = (icn_shmem *) (membase & 0x0ffc000);
+        dev.shmem = (icn_shmem *) ((unsigned long)membase & 0x0ffc000);
         dev.channel = -1;
         dev.mcard   = NULL;
 
@@ -1571,8 +1593,8 @@
                 *p = 0;
         } else
                 strcpy(rev, " ??? ");
-        printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08x\n", rev,
-               (uint) dev.shmem);
+        printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
+               (ulong) dev.shmem);
         return (icn_addcard(portbase,icn_id,icn_id2));
 }
 
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h
--- v2.0.0/linux/drivers/isdn/icn/icn.h	Sun Jun  9 13:28:42 1996
+++ linux/drivers/isdn/icn/icn.h	Sat Jun 29 20:36:22 1996
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.19 1996/06/06 13:58:35 fritz Exp $
+/* $Id: icn.h,v 1.20 1996/06/24 17:20:37 fritz Exp $
  *
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
@@ -19,6 +19,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: icn.h,v $
+ * Revision 1.20  1996/06/24 17:20:37  fritz
+ * Bugfixes in pollbchan_send():
+ *   - Using lock field of skbuff breaks networking.
+ *   - Added channel locking
+ *   - changed dequeuing scheme.
+ * Eliminated misc. compiler warnings.
+ *
  * Revision 1.19  1996/06/06 13:58:35  fritz
  * Changed code to be architecture independent
  *
@@ -155,7 +162,7 @@
 #define ICN_CODE_STAGE1 4096     /* Size of bootcode                        */
 #define ICN_CODE_STAGE2 65536    /* Size of protocol-code                   */
 
-#define ICN_MAX_SQUEUE 65536     /* Max. outstanding send-data              */
+#define ICN_MAX_SQUEUE 8000      /* Max. outstanding send-data (2* hw-buf.) */
 #define ICN_FRAGSIZE (250)       /* Max. size of send-fragments             */
 #define ICN_BCH 2                /* Number of supported channels per card   */
 
@@ -240,6 +247,7 @@
         struct sk_buff_head
                 spqueue[ICN_BCH];     /* Sendqueue                        */
         char regname[35];             /* Name used for request_region     */
+        u_char xmit_lock[ICN_BCH];    /* Semaphore for pollbchan_send()   */
 } icn_card;
 
 /*
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.0.0/linux/drivers/isdn/isdn_common.c	Sun Jun  9 13:28:43 1996
+++ linux/drivers/isdn/isdn_common.c	Sat Jun 29 20:36:22 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.18 1996/06/06 14:51:51 fritz Exp $
+/* $Id: isdn_common.c,v 1.23 1996/06/25 18:35:38 fritz Exp $
  *
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -21,6 +21,25 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_common.c,v $
+ * Revision 1.23  1996/06/25 18:35:38  fritz
+ * Fixed bogus memory access in isdn_set_allcfg().
+ *
+ * Revision 1.22  1996/06/24 17:37:37  fritz
+ * Bugfix: isdn_timer_ctrl() did restart timer, even if it
+ *         was already running.
+ *         lowlevel driver locking did use wrong parameters.
+ *
+ * Revision 1.21  1996/06/15 14:58:20  fritz
+ * Added version signatures for data structures used
+ * by userlevel programs.
+ *
+ * Revision 1.20  1996/06/12 16:01:49  fritz
+ * Bugfix: Remote B-channel hangup sometimes did not result
+ *         in a NO CARRIER on tty.
+ *
+ * Revision 1.19  1996/06/11 14:52:04  hipp
+ * minor bugfix in isdn_writebuf_skb_stub()
+ *
  * Revision 1.18  1996/06/06 14:51:51  fritz
  * Changed to support DTMF decoding on audio playback also.
  *
@@ -115,11 +134,12 @@
 
 /* Debugflags */
 #undef  ISDN_DEBUG_STATCALLB
+#define NEW_ISDN_TIMER_CTRL
 
 isdn_dev *dev = (isdn_dev *) 0;
 
 static int  has_exported = 0;
-static char *isdn_revision      = "$Revision: 1.18 $";
+static char *isdn_revision      = "$Revision: 1.23 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -222,8 +242,10 @@
 
 		save_flags(flags);
 		cli();
-		del_timer(&dev->timer);
-		dev->timer.function = isdn_timer_funct;
+                del_timer(&dev->timer);
+#ifndef NEW_ISDN_TIMER_CTRL
+                dev->timer.function = isdn_timer_funct;
+#endif
 		dev->timer.expires = jiffies + ISDN_TIMER_RES;
 		add_timer(&dev->timer);
 		restore_flags(flags);
@@ -245,12 +267,20 @@
 		dev->tflags |= tf;
 	else
 		dev->tflags &= ~tf;
+#ifdef NEW_ISDN_TIMER_CTRL
+	if (dev->tflags) {
+                if (!del_timer(&dev->timer)) /* del_timer is 1, when active */
+                        dev->timer.expires = jiffies + ISDN_TIMER_RES;
+		add_timer(&dev->timer);
+	}
+#else
 	if (dev->tflags) {
-		del_timer(&dev->timer);
-		dev->timer.function = isdn_timer_funct;
+                del_timer(&dev->timer);
+                dev->timer.function = isdn_timer_funct;
 		dev->timer.expires = jiffies + ISDN_TIMER_RES;
 		add_timer(&dev->timer);
 	}
+#endif
 	restore_flags(flags);
 }
 
@@ -277,6 +307,7 @@
 	if (isdn_net_rcv_skb(i, skb))
 		return;
 	/* No network-device found, deliver to tty or raw-channel */
+        skb->free = 1;
 	if (skb->len) {
                 if ((midx = dev->m_idx[i])<0) {
                         /* if midx is invalid, drop packet */
@@ -599,9 +630,9 @@
                                 info = &dev->mdm.info[mi];
 				if (info->flags &
 				    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
-					info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
-					if (info->online)
+					if (info->msr & UART_MSR_DCD)
 						isdn_tty_modem_result(3, info);
+					info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
 #ifdef ISDN_DEBUG_MODEM_HUP
 					printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
 #endif
@@ -807,6 +838,8 @@
 	return (dev->chanmap[minor]);
 }
 
+#define INF_DV 0x01 /* Data version for /dev/isdninfo */
+
 static char *
  isdn_statstr(void)
 {
@@ -1043,7 +1076,8 @@
 		restore_flags(flags);
 		return ret;
 	}
-	memcpy_tofs((char *) &i, src, sizeof(int));
+	memcpy_fromfs((char *) &i, src, sizeof(int));
+        src += sizeof(int);
 	while (i) {
 		char *c;
 		char *c2;
@@ -1185,6 +1219,10 @@
 
 	if (minor == ISDN_MINOR_STATUS) {
                 switch (cmd) {
+                        case IIOCGETDVR:
+                                return(TTY_DV +
+                                       (NET_DV << 8) +
+                                       (INF_DV << 16));
                         case IIOCGETCPS:
                                 if (arg) {
                                         ulong *p = (ulong *)arg;
@@ -1728,7 +1766,7 @@
 						dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
 						dev->usage[i] |= usage;
 						isdn_info_update();
-                                                cmd.driver = i;
+                                                cmd.driver = d;
                                                 cmd.arg = 0;
                                                 cmd.command = ISDN_CMD_LOCK;
                                                 (void) dev->drv[d]->interface->command(&cmd);
@@ -1739,7 +1777,7 @@
 							dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
 							dev->usage[i] |= usage;
 							isdn_info_update();
-                                                        cmd.driver = i;
+                                                        cmd.driver = d;
                                                         cmd.arg = 0;
                                                         cmd.command = ISDN_CMD_LOCK;
                                                         (void) dev->drv[d]->interface->command(&cmd);
@@ -1878,17 +1916,18 @@
 int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
 {
         int ret;
+	int len = skb->len;	/* skb pointer no longer valid after free */
 
         if (dev->drv[drvidx]->interface->writebuf_skb) 
 		ret = dev->drv[drvidx]->interface->
 			writebuf_skb(drvidx, chan, skb);
 	else {
 		if ((ret = dev->drv[drvidx]->interface->
-                     writebuf(drvidx,chan,skb->data,skb->len,0)) == skb->len)
+                     writebuf(drvidx,chan,skb->data,skb->len,0)) == len)
 		        dev_kfree_skb(skb, FREE_WRITE);
         }
         if (ret > 0)
-                dev->obytes[isdn_dc2minor(drvidx,chan)] += skb->len;
+                dev->obytes[isdn_dc2minor(drvidx,chan)] += len;
         return ret;
 }
 
@@ -2063,6 +2102,10 @@
 		return -EIO;
 	}
 	memset((char *) dev, 0, sizeof(isdn_dev));
+#ifdef NEW_ISDN_TIMER_CTRL
+        init_timer(&dev->timer);
+        dev->timer.function = isdn_timer_funct;
+#endif
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		dev->drvmap[i] = -1;
 		dev->chanmap[i] = -1;
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.0.0/linux/drivers/isdn/isdn_net.c	Sun Jun  9 13:28:43 1996
+++ linux/drivers/isdn/isdn_net.c	Sat Jun 29 20:36:22 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.13 1996/06/06 14:25:44 fritz Exp $
+/* $Id: isdn_net.c,v 1.17 1996/06/25 18:37:37 fritz Exp $
  *
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -21,6 +21,22 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_net.c,v $
+ * Revision 1.17  1996/06/25 18:37:37  fritz
+ * Fixed return count for empty return string in isdn_net_getphones().
+ *
+ * Revision 1.16  1996/06/24 17:48:08  fritz
+ * Bugfixes:
+ *   - Did not free channel on unbinding.
+ *   - ioctl returned wrong callback settings.
+ *
+ * Revision 1.15  1996/06/16 17:42:54  tsbogend
+ * fixed problem with IP addresses on Linux/Alpha (long is 8 byte there)
+ *
+ * Revision 1.14  1996/06/11 14:54:08  hipp
+ * minor bugfix in isdn_net_send_skb
+ * changes in BSENT callback handler for syncPPP
+ * added lp->sav_skb stuff
+ *
  * Revision 1.13  1996/06/06 14:25:44  fritz
  * Changed loglevel of "incoming ... without OAD" message, since
  * with audio support this is quite normal.
@@ -105,7 +121,7 @@
  
 extern void dev_purge_queues(struct device *dev);	/* move this to net/core/dev.c */
 
-char *isdn_net_revision = "$Revision: 1.13 $";
+char *isdn_net_revision = "$Revision: 1.17 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -133,9 +149,9 @@
 	isdn_net_reset(dev);
 	dev->start = 1;
 	/* Fill in the MAC-level header. */
-	for (i = 0; i < ETH_ALEN - sizeof(ulong); i++)
+	for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
 		dev->dev_addr[i] = 0xfc;
-	memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(ulong));
+	memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(u32));
 
         /* If this interface has slaves, start them also */
 
@@ -182,6 +198,10 @@
                 dev_kfree_skb(lp->first_skb,FREE_WRITE);
                 lp->first_skb = NULL;
         }
+	if(lp->sav_skb) {
+                dev_kfree_skb(lp->sav_skb,FREE_WRITE);
+		lp->sav_skb = NULL;
+	}
 	dev_purge_queues(&lp->netdev->dev);
 	lp->dialstate = 0;
 	dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
@@ -263,14 +283,19 @@
 				if ((lp->flags & ISDN_NET_CONNECTED) &&
 				    (!lp->dialstate)) {
 					lp->stats.tx_packets++;
-					if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->first_skb) {
-						if(!isdn_net_send_skb(&lp->netdev->dev,lp,lp->first_skb)) {
-							dev_kfree_skb(lp->first_skb,FREE_WRITE);
-							lp->first_skb = NULL;
+					if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
+						struct device *mdev;
+						if(lp->master)
+							mdev = lp->master;
+						else
+							mdev = &lp->netdev->dev;
+						if(!isdn_net_send_skb(mdev,lp,lp->sav_skb)) {
+							lp->sav_skb = NULL;
 							mark_bh(NET_BH);
 						}
-						else
+						else {
 							return 1;
+						}
 					}
                                         if (clear_bit(0,(void*)&(p->dev.tbusy)))
                                                 mark_bh(NET_BH);
@@ -293,8 +318,14 @@
 				/* Either D-Channel-hangup or error during dialout */
 				if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
 					lp->flags &= ~ISDN_NET_CONNECTED;
-					if(lp->first_skb)
+					if(lp->first_skb) {
 						dev_kfree_skb(lp->first_skb,FREE_WRITE);
+						lp->first_skb = NULL;
+					}
+					if(lp->sav_skb) {
+						dev_kfree_skb(lp->sav_skb,FREE_WRITE);
+						lp->sav_skb = NULL;
+					}
 					isdn_free_channel(lp->isdn_device, lp->isdn_channel,
                                                           ISDN_USAGE_NET);
 #ifdef CONFIG_ISDN_PPP
@@ -596,35 +627,20 @@
 {
 	isdn_net_local *lp = (isdn_net_local *) d->priv;
 	isdn_ctrl cmd;
-	ulong flags;
 
-	save_flags(flags);
-	cli();
-        if (lp->first_skb) {
-                dev_kfree_skb(lp->first_skb,FREE_WRITE);
-                lp->first_skb = NULL;
-        }
-	dev_purge_queues(d);
 	if (lp->flags & ISDN_NET_CONNECTED) {
 		printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
-		lp->dialstate = 0;
-                dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
-                dev->st_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
-		isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
 #ifdef CONFIG_ISDN_PPP
 		isdn_ppp_free(lp);
 #endif
-		lp->flags &= ~ISDN_NET_CONNECTED;
 		cmd.driver = lp->isdn_device;
 		cmd.command = ISDN_CMD_HANGUP;
 		cmd.arg = lp->isdn_channel;
 		(void) dev->drv[cmd.driver]->interface->command(&cmd);
 		printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
 		isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
-		lp->isdn_device = -1;
-		lp->isdn_channel = -1;
 	}
-	restore_flags(flags);
+        isdn_net_unbind_channel(lp);
 }
 
 typedef struct {
@@ -732,13 +748,21 @@
                   struct sk_buff *skb)
 {
 	int ret;
+	int len = skb->len;	/* save len */
 	
-	lp->transcount += skb->len;
         ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb);
-	if (ret == skb->len) {
+	if (ret == len) {
+		lp->transcount += len;
 		clear_bit(0, (void *)&(ndev->tbusy));
 		return 0;
 	}
+        if (ret < 0) {
+                skb->free = 1;
+                dev_kfree_skb(skb, FREE_WRITE);
+                lp->stats.tx_errors++;
+                clear_bit(0, (void *)&(ndev->tbusy));
+                return 0;
+        }
 	return 1;
 }                                      
 	
@@ -762,8 +786,7 @@
 	/* For the other encaps the header has already been built */
 #ifdef CONFIG_ISDN_PPP
 	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
-		ndev->tbusy = ret = isdn_ppp_xmit(skb, ndev);
-		return ret;
+		return isdn_ppp_xmit(skb, ndev);
 	}
 #endif		
 	/* Reset hangup-timeout */
@@ -877,7 +900,7 @@
 				if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
 					/* no 'first_skb' handling for syncPPP */
 					if (isdn_ppp_bind(lp) < 0) {
-						lp->first_skb = skb;	/* net_unbind will free skb */
+                                        	dev_kfree_skb(skb,FREE_WRITE);
 						isdn_net_unbind_channel(lp);
                                                 restore_flags(flags);
 						return 0;	/* STN (skb to nirvana) ;) */
@@ -1241,7 +1264,7 @@
                          * guaranteed to be invalid. Need that to check
                          * for already compressed packets in isdn_ppp_xmit().
                          */
-                        *((unsigned long *)skb_push(skb, len)) = 0;
+                        *((u32 *)skb_push(skb, len)) = 0;
                         break;
 #endif
 	}
@@ -1251,7 +1274,7 @@
 /* We don't need to send arp, because we have point-to-point connections. */
 
 static int
-isdn_net_rebuild_header(void *buff, struct device *dev, ulong dst,
+isdn_net_rebuild_header(void *buff, struct device *dev, unsigned long dst,
                         struct sk_buff *skb)
 {
 	isdn_net_local *lp = dev->priv;
@@ -1266,8 +1289,8 @@
                 
                 if(eth->h_proto != htons(ETH_P_IP)) {
                         printk(KERN_WARNING
-                               "isdn_net_rebuild_header: Don't know how to resolve type %d addresses?\n",
-                               (int)eth->h_proto);
+                               "isdn_net: %s don't know how to resolve type %d addresses?\n",
+                               dev->name, (int)eth->h_proto);
                         memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
                         return 0;
                 }
@@ -1275,7 +1298,7 @@
                  *      Try to get ARP to resolve the header.
                  */
 #ifdef CONFIG_INET       
-                ret = arp_find((unsigned char *)&(eth->h_dest), dst, dev, dev->pa_addr,skb)? 1 : 0;
+                ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;
 #endif  
         }
 	return ret;
@@ -2034,6 +2057,7 @@
 			p->local.exclusive = -1;
 			if ((p->local.pre_device != -1) && (cfg->exclusive == -1)) {
 				isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
+                                isdn_free_channel(p->local.pre_device, p->local.pre_channel,ISDN_USAGE_NET);
 				drvidx = -1;
 				chidx = -1;
 			}
@@ -2059,7 +2083,7 @@
 			p->local.flags &= ~ISDN_NET_CBHUP;
 		switch (cfg->callback) {
                         case 0:
-                                p->local.flags &= ~(ISDN_NET_CALLBACK&ISDN_NET_CBOUT);
+                                p->local.flags &= ~(ISDN_NET_CALLBACK|ISDN_NET_CBOUT);
                                 break;
                         case 1:
                                 p->local.flags |= ISDN_NET_CALLBACK;
@@ -2126,7 +2150,9 @@
 		cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
 		cfg->callback = 0;
                 if (p->local.flags & ISDN_NET_CALLBACK)
-                        cfg->callback = (p->local.flags & ISDN_NET_CBOUT)?2:1;
+                        cfg->callback = 1;
+                if (p->local.flags & ISDN_NET_CBOUT)
+                        cfg->callback = 2;
 		cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0;
 		cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0;
 		cfg->ihup = (p->local.hupflags & 8) ? 1 : 0;
@@ -2186,10 +2212,7 @@
 	save_flags(flags);
 	cli();
 	inout &= 1;
-	n = p->local.phone[inout];
-        if (n)
-                count++;
-	while (n) {
+        for (n = p->local.phone[inout]; n; n = n->next) {
 		if (more) {
 			put_fs_byte(' ', phones++);
 			count++;
@@ -2201,10 +2224,10 @@
 		memcpy_tofs(phones, n->num, strlen(n->num) + 1);
 		phones += strlen(n->num);
 		count += strlen(n->num);
-		n = n->next;
 		more = 1;
 	}
         put_fs_byte(0,phones);
+        count++;
 	restore_flags(flags);
 	return count;
 }
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.0.0/linux/drivers/isdn/isdn_ppp.c	Mon May 20 08:20:59 1996
+++ linux/drivers/isdn/isdn_ppp.c	Sat Jun 29 20:36:22 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.9 1996/05/18 01:37:01 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.12 1996/06/24 17:42:03 fritz Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,16 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.12  1996/06/24 17:42:03  fritz
+ * Minor bugfixes.
+ *
+ * Revision 1.11  1996/06/16 17:46:05  tsbogend
+ * changed unsigned long to u32 to make Alpha people happy
+ *
+ * Revision 1.10  1996/06/11 14:50:29  hipp
+ * Lot of changes and bugfixes.
+ * New scheme to resend packets to busy LL devices.
+ *
  * Revision 1.9  1996/05/18 01:37:01  fritz
  * Added spelling corrections and some minor changes
  * to stay in sync with kernel.
@@ -69,7 +79,7 @@
 #endif
  
 /* Prototypes */
-static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor);
+static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor);
 static int isdn_ppp_closewait(int);
 static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
 			struct sk_buff *skb, int proto);
@@ -83,7 +93,7 @@
 		int BEbyte, int *sqno, int min_sqno);
 #endif
 
-char *isdn_ppp_revision              = "$Revision: 1.9 $";
+char *isdn_ppp_revision              = "$Revision: 1.12 $";
 struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
 extern int isdn_net_force_dial_lp(isdn_net_local *);
@@ -95,10 +105,13 @@
 int isdn_ppp_free(isdn_net_local *lp)
 {
 	isdn_net_local *master_lp=lp;
+	unsigned long flags;
 
 	if (lp->ppp_minor < 0)
 		return 0;
 
+	save_flags(flags);
+	cli();
 #ifdef CONFIG_ISDN_MPP
 	if(lp->master)
 		master_lp = (isdn_net_local *) lp->master->priv;
@@ -123,7 +136,7 @@
 
 	ippp_table[lp->ppp_minor]->lp = NULL;	/* link is down .. set lp to NULL */
 	lp->ppp_minor = -1;			/* is this OK ?? */
-
+	restore_flags(flags);
 	return 0;
 }
 
@@ -286,6 +299,7 @@
 
 #ifdef CONFIG_ISDN_PPP_VJ
 	slhc_free(ippp_table[minor]->slcomp);
+	ippp_table[minor]->slcomp = NULL;
 	kfree(ippp_table[minor]->cbuf);
 #endif
 
@@ -394,7 +408,25 @@
 	case PPPIOCSMAXCID:	/* set the maximum compression slot id */
 		if ((r = get_arg((void *) arg, &val)))
 			return r;
-		ippp_table[minor]->maxcid = val;
+		val++;
+		if(ippp_table[minor]->maxcid != val) {
+#ifdef CONFIG_ISDN_PPP_VJ
+			struct slcompress *sltmp;
+#endif
+			if(ippp_table[minor]->debug & 0x1)
+				printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n",val);
+			ippp_table[minor]->maxcid = val;
+#ifdef CONFIG_ISDN_PPP_VJ
+			sltmp = slhc_init(16,val);
+			if(!sltmp) {
+				printk(KERN_ERR "ippp, can't realloc slhc struct\n");
+				return -ENOMEM;
+			}	
+			if(ippp_table[minor]->slcomp)
+				slhc_free(ippp_table[minor]->slcomp);
+			ippp_table[minor]->slcomp = sltmp;
+#endif
+		}
 		break;
 	case PPPIOCGDEBUG:
 		if ((r = set_arg((void *) arg, ippp_table[minor]->debug)))
@@ -453,10 +485,11 @@
  *  fill up isdn_ppp_read() queue ..
  */
 
-static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor)
+static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor)
 {
 	struct ippp_buf_queue *bf, *bl;
 	unsigned long flags;
+	unsigned char *nbuf;
 
 	if (minor < 0 || minor >= ISDN_MAX_CHANNELS) {
 		printk(KERN_WARNING "ippp: illegal minor.\n");
@@ -466,6 +499,18 @@
 		printk(KERN_DEBUG "ippp: device not activated.\n");
 		return 0;
 	}
+
+	nbuf = (unsigned char *) kmalloc(len+4, GFP_ATOMIC);
+	if(!nbuf) {
+		printk(KERN_WARNING "ippp: Can't alloc buf\n");
+		return 0;
+	}
+	nbuf[0] = PPP_ALLSTATIONS;
+	nbuf[1] = PPP_UI;
+	nbuf[2] = proto >> 8;
+	nbuf[3] = proto & 0xff;
+	memcpy(nbuf+4, buf, len);
+
 	save_flags(flags);
 	cli();
 
@@ -478,20 +523,9 @@
 		kfree(bf->buf);
 		ippp_table[minor]->first = bf;
 	}
-	bl->buf = (char *) kmalloc(len+4, GFP_ATOMIC);
-	if (!bl->buf) {
-		printk(KERN_WARNING "ippp: Can't alloc buf\n");
-		restore_flags(flags);
-		return 0;
-	}
+	bl->buf = (char *) nbuf;
 	bl->len = len+4;
 
-	bl->buf[0] = PPP_ALLSTATIONS;
-	bl->buf[1] = PPP_UI;
-	bl->buf[2] = proto >> 8;
-	bl->buf[3] = proto & 0xff;
-	memcpy(bl->buf+4, buf, len);
-
 	ippp_table[minor]->last = bl->next;
 	restore_flags(flags);
 
@@ -561,9 +595,23 @@
 			return 0;
 
 		if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 &&
-		    (lp->flags & ISDN_NET_CONNECTED))
-			isdn_writebuf_stub(lp->isdn_device,lp->isdn_channel,
-                                           buf, count, 1);
+		    (lp->flags & ISDN_NET_CONNECTED)) {
+			struct sk_buff *skb;
+			skb = dev_alloc_skb(count);
+			if(!skb) {
+				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
+				return count;
+			}
+			skb->free = 1;
+			memcpy_fromfs(skb_put(skb, count), buf, count);
+			if(isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb) != count) {
+				if(lp->sav_skb) {
+					dev_kfree_skb(lp->sav_skb,FREE_WRITE);
+					printk(KERN_INFO "isdn_ppp_write: freeing sav_skb!\n");
+				}
+				lp->sav_skb = skb;
+			}
+		}
 	}
 
 	return count;
@@ -617,6 +665,11 @@
 	if(ippp_table[lp->ppp_minor]->debug & 0x4)
 		printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len);
 
+	if(net_dev->local.master) {
+		printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
+		net_dev = ((isdn_net_local*) net_dev->local.master->priv)->netdev;
+	}
+
 	if(skb->data[0] == 0xff && skb->data[1] == 0x03)
 		skb_pull(skb,2);
 	else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) {
@@ -819,8 +872,13 @@
 			skb->mac.raw = skb->data;
 			pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_minor]->slcomp,
 						  skb->data, skb_old->len);
-			skb_trim(skb, pkt_len);
 			dev_kfree_skb(skb_old,FREE_WRITE);
+			if(pkt_len < 0) {
+				dev_kfree_skb(skb,FREE_WRITE);
+				lp->stats.rx_dropped++;
+				return;
+			}
+			skb_trim(skb, pkt_len);
 			skb->protocol = htons(ETH_P_IP);
 		}
 #else
@@ -848,6 +906,7 @@
  * send ppp frame .. we expect a PIDCOMPressable proto -- 
  *  (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
  */
+
 int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 {
 	struct device *mdev = ((isdn_net_local *) (dev->priv) )->master;	/* get master (for redundancy) */
@@ -861,32 +920,43 @@
 	else
 		mlp = (isdn_net_local *) (dev->priv);
 	nd = mlp->netdev;	/* get master lp */
-	lp = nd->queue;		/* get lp on top of queue */
-	ipt = ippp_table[lp->ppp_minor];
 	ipts = ippp_table[mlp->ppp_minor];
 
-	if (!(ipt->pppcfg & SC_ENABLE_IP)) {    /* PPP connected ? */
-		printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel);
+	if (!(ipts->pppcfg & SC_ENABLE_IP)) {    /* PPP connected ? */
+		printk(KERN_INFO "%s: IP frame delayed.\n",dev->name);
 		return 1;
         }
+
+	lp = nd->queue;		/* get lp on top of queue */
+	if(lp->sav_skb) {	/* find a non-busy device */
+		isdn_net_local *nlp = lp->next;
+		while(lp->sav_skb) {
+			if(lp == nlp)
+				return 1;
+			nlp = nd->queue = nd->queue->next;
+		}
+		lp = nlp;
+	}
+	ipt = ippp_table[lp->ppp_minor];
+
         lp->huptimer = 0;
  
         /* If packet is to be resent, it has already been processed and
          * therefore its first bytes are already initialized. In this case
          * send it immediately ...
          */
-        if (*((unsigned long *)skb->data) != 0)
+        if (*((u32 *)skb->data) != 0) {
+	  printk(KERN_ERR "%s: Whoops .. packet resend should no longer happen!\n",dev->name);
           return (isdn_net_send_skb(dev , lp , skb));
+        }
 
         /* ... else packet needs processing. */
 
-/* future: step to next 'lp' when this lp is 'tbusy' */
-
 	if(ippp_table[lp->ppp_minor]->debug & 0x4)
 		printk(KERN_DEBUG  "xmit skb, len %ld\n",skb->len);
 
 #ifdef CONFIG_ISDN_PPP_VJ
-	if (ipt->pppcfg & SC_COMP_TCP) {	/* ipt or ipts ? -> check this again! */
+	if (ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes .. but check again */
 		u_char *buf = skb->data;
 		int pktlen;
 		int len = 4;
@@ -947,7 +1017,15 @@
 	skb->data[3] = proto & 0xff;
 
         /* tx-stats are now updated via BSENT-callback */
-	return (isdn_net_send_skb(dev , lp , skb));
+	if(isdn_net_send_skb(dev , lp , skb)) {	
+		if(lp->sav_skb) {	/* whole sav_skb processing with disabled IRQs ?? */
+			printk(KERN_ERR "%s: whoops .. there is another stored skb!\n!",dev->name);
+			dev_kfree_skb(skb,FREE_WRITE);
+		}
+		else
+			lp->sav_skb = skb;
+	}
+	return 0;
 }
 
 void isdn_ppp_free_sqqueue(isdn_net_dev * p) 
@@ -1165,6 +1243,9 @@
 
 static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min_sqno)
 {
+#ifdef CONFIG_ISDN_PPP_VJ
+	int toss = 0;
+#endif
 /* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft:
    eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen
    wenn sqno<min_sqno und Luecken vorhanden sind: auch weg (die koennen nicht mehr gefuellt werden)
@@ -1183,6 +1264,9 @@
 					ql = q->last;
 					dev_kfree_skb(q->skb,FREE_WRITE);
 					kfree(q);
+#ifdef CONFIG_ISDN_PPP_VJ
+					toss = 1;
+#endif
 					q = ql;
 				}
 				q = dev->mp_last;
@@ -1191,6 +1275,11 @@
 		} else
 			break;
 	}
+#ifdef CONFIG_ISDN_PPP_VJ
+	/* did we free a stale frame ? */
+	if(toss)
+		slhc_toss(ippp_table[dev->local.ppp_minor]->slcomp);
+#endif
 }
 
 /*
@@ -1207,7 +1296,7 @@
 
 	while (net_dev) {
 		isdn_net_local *lp = &net_dev->local;
-		if (net_dev->ib.modify)	{	/* interface locked? */
+		if (net_dev->ib.modify || lp->master)	{	/* interface locked or slave?*/
                         net_dev = net_dev->next;
 			continue;
                 }
@@ -1215,6 +1304,13 @@
 		q = net_dev->ib.sq;
 		while (q) {
 			if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) {
+
+#ifdef CONFIG_ISDN_PPP_VJ
+				/* did we step over a missing frame ? */
+				if(q->sqno_start != net_dev->ib.next_num)
+					slhc_toss(ippp_table[lp->ppp_minor]->slcomp);
+#endif
+
 				ql = net_dev->ib.sq;
 				net_dev->ib.sq = q->next;
 				net_dev->ib.next_num = q->sqno_end + 1;
@@ -1234,6 +1330,49 @@
 #endif
 }
 
+/*
+ * network device ioctl handlers
+ */
+
+static int isdn_ppp_dev_ioctl_stats(int minor,struct ifreq *ifr,struct device *dev)
+{
+	struct ppp_stats *res, t;
+	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	int err;
+
+        res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+        err = verify_area (VERIFY_WRITE, res,sizeof(struct ppp_stats));
+
+	if(err)
+		return err;
+
+	/* build a temporary stat struct and copy it to user space */
+
+	memset (&t, 0, sizeof(struct ppp_stats));
+	if(dev->flags & IFF_UP) {
+		t.p.ppp_ipackets = lp->stats.rx_packets;
+		t.p.ppp_ierrors = lp->stats.rx_errors;
+		t.p.ppp_opackets = lp->stats.tx_packets;
+		t.p.ppp_oerrors = lp->stats.tx_errors;
+#ifdef CONFIG_ISDN_PPP_VJ
+		if(minor >= 0 && ippp_table[minor]->slcomp) {
+			struct slcompress *slcomp = ippp_table[minor]->slcomp;
+			t.vj.vjs_packets  = slcomp->sls_o_compressed+slcomp->sls_o_uncompressed;
+			t.vj.vjs_compressed = slcomp->sls_o_compressed;
+			t.vj.vjs_searches = slcomp->sls_o_searches;
+			t.vj.vjs_misses   = slcomp->sls_o_misses;
+			t.vj.vjs_errorin  = slcomp->sls_i_error;
+			t.vj.vjs_tossed   = slcomp->sls_i_tossed;
+			t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
+			t.vj.vjs_compressedin = slcomp->sls_i_compressed;
+		}
+#endif
+	}
+	memcpy_tofs (res, &t, sizeof (struct ppp_stats));
+	return 0;
+
+}
+
 int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
 	int error;
@@ -1241,19 +1380,27 @@
 	int len;
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
 
+#if 1
+	printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_minor);
+#endif
+
 	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
 		return -EINVAL;
 
 	switch (cmd) {
-	case SIOCGPPPVER:
-		r = (char *) ifr->ifr_ifru.ifru_data;
-		len = strlen(PPP_VERSION) + 1;
-		error = verify_area(VERIFY_WRITE, r, len);
-		if (!error)
-			memcpy_tofs(r, PPP_VERSION, len);
-		break;
-	default:
-		error = -EINVAL;
+		case SIOCGPPPVER:
+			r = (char *) ifr->ifr_ifru.ifru_data;
+			len = strlen(PPP_VERSION) + 1;
+			error = verify_area(VERIFY_WRITE, r, len);
+			if (!error)
+				memcpy_tofs(r, PPP_VERSION, len);
+			break;
+		case SIOCGPPPSTATS:
+			error = isdn_ppp_dev_ioctl_stats (lp->ppp_minor, ifr, dev);
+			break;
+		default:
+			error = -EINVAL;
+			break;
 	}
 	return error;
 }
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- v2.0.0/linux/drivers/isdn/isdn_tty.c	Sun Jun  9 13:28:43 1996
+++ linux/drivers/isdn/isdn_tty.c	Sat Jun 29 20:36:22 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.18 1996/06/07 11:17:33 tsbogend Exp $
+/* $Id: isdn_tty.c,v 1.21 1996/06/24 17:40:28 fritz Exp $
  *
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -20,6 +20,18 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.21  1996/06/24 17:40:28  fritz
+ * Bugfix: Did not compile without CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.20  1996/06/15 14:59:39  fritz
+ * Fixed isdn_tty_tint() to handle partially sent
+ * sk_buffs.
+ *
+ * Revision 1.19  1996/06/12 15:53:56  fritz
+ * Bugfix: AT+VTX and AT+VRX could be executed without
+ *         having a connection.
+ *         Missing check for NULL tty in isdn_tty_flush_buffer().
+ *
  * Revision 1.18  1996/06/07 11:17:33  tsbogend
  * added missing #ifdef CONFIG_ISDN_AUDIO to make compiling without
  * audio support possible
@@ -127,7 +139,7 @@
 static int bit2si[8] = {1,5,7,7,7,7,7,7};
 static int si2bit[8] = {4,1,4,4,4,4,4,4};
                                 
-char *isdn_tty_revision        = "$Revision: 1.18 $";
+char *isdn_tty_revision        = "$Revision: 1.21 $";
 
 #define DLE 0x10
 #define ETX 0x03
@@ -262,10 +274,13 @@
 static void isdn_tty_tint(modem_info *info)
 {
         struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
+        int len, slen;
 
         if (!skb)
                 return;
-        if (isdn_writebuf_skb_stub(info->isdn_driver, info->isdn_channel, skb) > 0) {
+        len = skb->len;
+        if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
+                                         info->isdn_channel, skb)) == len) {
                 struct tty_struct *tty = info->tty;
                 info->send_outstanding++;
                 info->msr |= UART_MSR_CTS;
@@ -276,6 +291,8 @@
                 wake_up_interruptible(&tty->write_wait);
                 return;
         }
+        if (slen > 0)
+                skb_pull(skb,slen);
         skb_queue_head(&info->xmit_queue, skb);
 }
 
@@ -369,10 +386,11 @@
         }
         return 0;
 }
-#endif        /* CONFIG_ISDN_AUDIO */
 
 static int voice_cf[7] = { 1, 1, 4, 3, 2, 1, 1 };
 
+#endif        /* CONFIG_ISDN_AUDIO */
+
 /* isdn_tty_senddown() is called either directly from within isdn_tty_write()
  * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
  * outgoing data from the tty's xmit-buffer, handles voice-decompression or
@@ -398,8 +416,8 @@
                 return;
         }
         skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
-        if (info->vonline & 2) {
 #ifdef CONFIG_ISDN_AUDIO
+        if (info->vonline & 2) {
                 /* For now, ifmt is fixed to 1 (alaw), since this
                  * is used with ISDN everywhere in the world, except
                  * US, Canada and Japan.
@@ -454,8 +472,8 @@
                         if (!info->vonline)
                                 isdn_tty_at_cout("\r\nVCON\r\n",info);
                 }
-#endif        /* CONFIG_ISDN_AUDIO */
         } else {
+#endif        /* CONFIG_ISDN_AUDIO */
                 skb = dev_alloc_skb(buflen + skb_res);
                 if (!skb) {
                         printk(KERN_WARNING
@@ -467,7 +485,9 @@
                 memcpy(skb_put(skb,buflen),buf,buflen);
                 info->xmit_count = 0;
                 restore_flags(flags);
+#ifdef CONFIG_ISDN_AUDIO
         }
+#endif
         skb->free = 1;
         if (info->emu.mdmreg[13] & 2)
                 /* Add T.70 simplified header */
@@ -591,6 +611,9 @@
 
         if (!info)
                 return;
+#ifdef ISDN_DEBUG_MODEM_HUP
+        printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
+#endif
         info->rcvsched = 0;
         info->online = 0;
         isdn_tty_flush_buffer(info->tty);
@@ -896,13 +919,20 @@
 
 static void isdn_tty_flush_buffer(struct tty_struct *tty)
 {
-	modem_info *info = (modem_info *) tty->driver_data;
+	modem_info *info;
         unsigned long flags;
 
-	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer"))
-		return;
         save_flags(flags);
         cli();
+        if (!tty) {
+                restore_flags(flags);
+                return;
+        }
+        info =  (modem_info *) tty->driver_data;
+	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) {
+                restore_flags(flags);
+		return;
+        }
         isdn_tty_cleanup_xmit(info);
         info->xmit_count = 0;
         restore_flags(flags);
@@ -2324,6 +2354,10 @@
                         /* AT+VRX - Start recording */
                         if (!m->vpar[0])
                                 PARSE_ERROR1;
+                        if (info->online != 1) {
+                                isdn_tty_modem_result(8, info);
+                                return 1;
+                        }
                         info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
                         if (!info->dtmf_state) {
                                 printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
@@ -2430,6 +2464,10 @@
                         /* AT+VTX - Start sending */
                         if (!m->vpar[0])
                                 PARSE_ERROR1;
+                        if (info->online != 1) {
+                                isdn_tty_modem_result(8, info);
+                                return 1;
+                        }
                         info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
                         if (!info->dtmf_state) {
                                 printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/callbacks.c linux/drivers/isdn/pcbit/callbacks.c
--- v2.0.0/linux/drivers/isdn/pcbit/callbacks.c	Wed Apr 24 17:00:39 1996
+++ linux/drivers/isdn/pcbit/callbacks.c	Sat Jun 29 20:36:22 1996
@@ -59,7 +59,8 @@
          *     - kfree   when msg has been sent
          */
 
-        if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb)) < 0)
+        if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb, 
+				 chan->proto)) < 0)
         {
                 printk("capi_conn_req failed\n");
                 return;
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/capi.c linux/drivers/isdn/pcbit/capi.c
--- v2.0.0/linux/drivers/isdn/pcbit/capi.c	Wed Apr 24 17:00:39 1996
+++ linux/drivers/isdn/pcbit/capi.c	Sat Jun 29 20:36:22 1996
@@ -58,7 +58,7 @@
  *
  */
 
-int capi_conn_req(const char * calledPN, struct sk_buff **skb)
+int capi_conn_req(const char * calledPN, struct sk_buff **skb, int proto)
 {
         ushort len;
 
@@ -80,6 +80,9 @@
 
         len = 18 + strlen(calledPN);
 
+	if (proto == ISDN_PROTO_L2_TRANS)
+		len++;
+
 	if ((*skb = dev_alloc_skb(len)) == NULL) {
     
 	        printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n");
@@ -89,11 +92,21 @@
         /* InfoElmMask */
         *((ushort*) skb_put(*skb, 2)) = AppInfoMask; 
 
-
-        /* Bearer Capability - Mandatory*/
-        *(skb_put(*skb, 1)) = 2;        /* BC0.Length                        */
-        *(skb_put(*skb, 1)) = 0x88;     /* BC0.Octect3 - Digital Information */
-        *(skb_put(*skb, 1)) = 0x90;     /* BC0.Octect4 -                     */
+	if (proto == ISDN_PROTO_L2_TRANS)
+	{
+		/* Bearer Capability - Mandatory*/
+		*(skb_put(*skb, 1)) = 3;        /* BC0.Length		*/
+		*(skb_put(*skb, 1)) = 0x80;     /* Speech		*/
+		*(skb_put(*skb, 1)) = 0x10;     /* Circuit Mode		*/
+		*(skb_put(*skb, 1)) = 0x23;     /* A-law		*/
+	}
+	else
+	{
+		/* Bearer Capability - Mandatory*/
+		*(skb_put(*skb, 1)) = 2;        /* BC0.Length		*/
+		*(skb_put(*skb, 1)) = 0x88;     /* Digital Information	*/
+		*(skb_put(*skb, 1)) = 0x90;     /* BC0.Octect4		*/
+	}
 
         /* Bearer Capability - Optional*/
         *(skb_put(*skb, 1)) = 0;        /* BC1.Length = 0                    */
@@ -220,16 +233,19 @@
                 *(skb_put(*skb, 1)) = 0x05;            /* LAPB */
                 break;
         case ISDN_PROTO_L2_HDLC:
-#ifdef DEBUG
-                printk(KERN_DEBUG "HDLC\n");           /* HDLC */
-#endif
                 *(skb_put(*skb, 1)) = 0x02;
                 break;
+	case ISDN_PROTO_L2_TRANS:
+		/* 
+		 *	Voice (a-law)
+		 */
+		*(skb_put(*skb, 1)) = 0x06;
+		break;
         default:
 #ifdef DEBUG 
                 printk(KERN_DEBUG "Transparent\n");
 #endif
-                *(skb_put(*skb, 1)) = 0x03;         
+                *(skb_put(*skb, 1)) = 0x03;
                 break;
         }
 
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/capi.h linux/drivers/isdn/pcbit/capi.h
--- v2.0.0/linux/drivers/isdn/pcbit/capi.h	Wed Apr 24 17:00:39 1996
+++ linux/drivers/isdn/pcbit/capi.h	Sat Jun 29 20:36:22 1996
@@ -22,7 +22,8 @@
 #define AppInfoMask  REQ_CAUSE|REQ_DISPLAY|REQ_USER_TO_USER 
 
 /* Connection Setup */
-extern int capi_conn_req(const char * calledPN, struct sk_buff **buf);
+extern int capi_conn_req(const char * calledPN, struct sk_buff **buf,
+			 int proto);
 extern int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb,
 				 int *complete); 
 
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c
--- v2.0.0/linux/drivers/isdn/pcbit/drv.c	Mon May 20 08:21:00 1996
+++ linux/drivers/isdn/pcbit/drv.c	Sat Jun 29 20:36:22 1996
@@ -11,6 +11,14 @@
  *        PCBIT-D interface with isdn4linux
  */
 
+/*
+ *	Fixes:
+ *
+ *	Nuno Grilo	<l38486@alfa.ist.utl.pt>
+ *      fixed msn_list NULL pointer dereference.
+ *		
+ */
+
 #define __NO_VERSION__
 
 #include <linux/module.h>
@@ -109,7 +117,7 @@
 	dev->b2->id = 1;
 
 
-	dev->qdelivery.next = 0;
+	dev->qdelivery.next = NULL;
 	dev->qdelivery.sync = 0;
 	dev->qdelivery.routine = pcbit_deliver;
 	dev->qdelivery.data = dev;
@@ -152,8 +160,8 @@
 	dev_if->channels = 2;
 
 
-	dev_if->features = ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS | 
-		ISDN_FEATURE_L2_HDLC;
+	dev_if->features = (ISDN_FEATURE_P_EURO  | ISDN_FEATURE_L3_TRANS | 
+			    ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS );
 
 	dev_if->writebuf_skb = pcbit_xmit;
 	dev_if->writebuf  = NULL;
@@ -1051,7 +1059,8 @@
 
 static void pcbit_set_msn(struct pcbit_dev *dev, char *list)
 {
-	struct msn_entry *ptr, *back;
+	struct msn_entry *ptr;
+	struct msn_entry *back = NULL;
 	char *cp, *sp;
 	int len;
 
@@ -1070,7 +1079,8 @@
 		return;
 	}
 
-	for (back=dev->msn_list; back->next; back=back->next);
+	if (dev->msn_list)
+		for (back=dev->msn_list; back->next; back=back->next);
 	
 	sp = list;
 
@@ -1128,10 +1138,3 @@
 
 	return 0;
 }
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/edss1.c linux/drivers/isdn/pcbit/edss1.c
--- v2.0.0/linux/drivers/isdn/pcbit/edss1.c	Wed Apr 24 17:00:39 1996
+++ linux/drivers/isdn/pcbit/edss1.c	Sat Jun 29 20:36:22 1996
@@ -288,15 +288,10 @@
 	save_flags(flags);
 	cli();
 
-        if (chan->fsm_timer.function) {
-                del_timer(&chan->fsm_timer);
-                chan->fsm_timer.function = NULL;
-        }
 
         for (action = fsm_table; action->init != 0xff; action++)
                 if (action->init == chan->fsm_state && action->event == event)
                         break;
-
   
 	if (action->init == 0xff) {
 		
@@ -304,6 +299,11 @@
                        event, chan->fsm_state);
 		return;
 	}
+
+        if (chan->fsm_timer.function) {
+                del_timer(&chan->fsm_timer);
+                chan->fsm_timer.function = NULL;
+        }
 
 	chan->fsm_state = action->final;
   
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/pcbit/layer2.c linux/drivers/isdn/pcbit/layer2.c
--- v2.0.0/linux/drivers/isdn/pcbit/layer2.c	Wed Apr 24 17:00:39 1996
+++ linux/drivers/isdn/pcbit/layer2.c	Sat Jun 29 20:36:22 1996
@@ -58,16 +58,7 @@
 /*
  *  task queue struct
  */ 
-struct tq_struct *tq_delivery=NULL;
 
-static void do_pcbit_bh(task_queue *list)
-{
-	run_task_queue(list);
-}
-
-struct tq_struct run_delivery= {
-        0, 0, (void *)(void *) do_pcbit_bh, &tq_delivery,
-};
 
 
 /*
@@ -87,7 +78,6 @@
 static void pcbit_transmit(struct pcbit_dev * dev);
 
 static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
-static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq);
 
 static void pcbit_l2_error(struct pcbit_dev *dev);
 static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
@@ -95,11 +85,10 @@
 
 static void pcbit_firmware_bug(struct pcbit_dev * dev);
 
-static void pcbit_sched_delivery(struct pcbit_dev *dev)
+static __inline__ void pcbit_sched_delivery(struct pcbit_dev *dev)
 {
-  queue_task_irq_off(&dev->qdelivery, &tq_delivery);
-  queue_task_irq_off(&run_delivery, &tq_immediate);
-  mark_bh(IMMEDIATE_BH);
+	queue_task(&dev->qdelivery, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
 }
 
 
@@ -195,11 +184,10 @@
 
         unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07;
 
-        if (dev->free > 16 && dev->write_queue && unacked < 7) {
-
-                save_flags(flags);
-                cli();
+	save_flags(flags);
+	cli();
 
+        if (dev->free > 16 && dev->write_queue && unacked < 7) {
 
                 if (!dev->w_busy)
                         dev->w_busy = 1;
@@ -209,11 +197,12 @@
                         return;
                 }
 
-                restore_flags(flags);
 
                 frame = dev->write_queue;
                 free = dev->free;
 
+                restore_flags(flags);
+
 		if (frame->copied == 0) {
 
                         /* Type 0 frame */
@@ -311,12 +300,15 @@
 		dev->w_busy = 0;
 		restore_flags(flags);				
         }
-#ifdef DEBUG
         else
+	{
+		restore_flags(flags);
+#ifdef DEBUG		
                 printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
                        unacked, dev->free, dev->write_queue ? "not empty" : 
-		       "empty");
+		       "empty");	
 #endif
+	}
 }
 
 
@@ -334,29 +326,31 @@
 	save_flags(flags);
         cli();
 
-        /* get frame from queue */
-        if (!(frame=dev->read_queue)) {
+	while((frame=dev->read_queue))
+	{
+		dev->read_queue = frame->next;
 		restore_flags(flags);
-                return;
-	}
 
-        dev->read_queue = frame->next;
-        restore_flags(flags);
+		msg.cpu = 0;
+		msg.proc = 0;
+		msg.cmd = frame->skb->data[2];
+		msg.scmd = frame->skb->data[3];
 
-	msg.cpu = 0;
-	msg.proc = 0;
-	msg.cmd = frame->skb->data[2];
-	msg.scmd = frame->skb->data[3];
+		frame->refnum = *((ushort*) frame->skb->data + 4);
+		frame->msg = *((ulong*) &msg);
+		
+		skb_pull(frame->skb, 6);
 
-	frame->refnum = *((ushort*) frame->skb->data + 4);
-	frame->msg = *((ulong*) &msg);
-	
-	skb_pull(frame->skb, 6);
+		pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, 
+				 frame->refnum);
 
-        pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, 
-			 frame->refnum);
+		kfree(frame);
 
-        kfree(frame);
+		save_flags(flags);
+		cli();
+	}
+
+	restore_flags(flags);
 }
 
 /*
@@ -517,8 +511,7 @@
                 }
                 else
                         dev->read_queue = frame;
-
-                pcbit_sched_delivery(dev);
+                
                 restore_flags(flags);
 
         }
@@ -572,7 +565,6 @@
 {
         struct pcbit_dev * dev;
         u_char info, ack_seq, read_seq;
-        u_char ack_int = 1;
 
 	dev = (struct pcbit_dev *) devptr;
 
@@ -618,33 +610,27 @@
         read_seq = (info & 0x07U); 
         
 	dev->interrupt = 0;
-	sti();
-
-	/*
-	 *	Bottom Half
-	 *	Runs with ints enabled
-	 */
 
         if (read_seq != dev->rcv_seq)
         {
-                pcbit_frame_read(dev, read_seq);
-                ack_int = 0;
+		while (read_seq != dev->rcv_seq)
+		{
+			pcbit_receive(dev);
+			dev->rcv_seq = (dev->rcv_seq + 1) % 8;
+		}
+		pcbit_sched_delivery(dev);
         }
 
 	if (ack_seq != dev->unack_seq)
         {
                 pcbit_recv_ack(dev, ack_seq);
-                ack_int = 0;
         }
 
-        if (ack_int) 
-	{
-                info = 0;
-                info |= dev->rcv_seq << 3;
-                info |= dev->send_seq;
+
+	info = dev->rcv_seq << 3;
+	info |= dev->send_seq;
     
-                writeb(info, dev->sh_mem + BANK4);  
-        }	
+	writeb(info, dev->sh_mem + BANK4);  
 }
 
 
@@ -685,17 +671,19 @@
 
         del_timer(&dev->error_recover_timer);
 	if (dev->w_busy || dev->r_busy)
-	  {
-	    init_timer(&dev->error_recover_timer);
-	    dev->error_recover_timer.expires = jiffies + ERRTIME;
-	    add_timer(&dev->error_recover_timer);
-	    return;
-	  }
+	{
+		init_timer(&dev->error_recover_timer);
+		dev->error_recover_timer.expires = jiffies + ERRTIME;
+		add_timer(&dev->error_recover_timer);
+		return;
+	}
 
 	dev->w_busy = dev->r_busy = 1;
 
-        if (dev->read_frame) {
-                if (dev->read_frame->skb) {
+        if (dev->read_frame)
+	{
+                if (dev->read_frame->skb)
+		{
 			dev->read_frame->skb->free = 1; 
                         kfree_skb(dev->read_frame->skb, FREE_READ);
 		}
@@ -704,7 +692,8 @@
         }
 
 
-        if (dev->write_queue) {
+        if (dev->write_queue)
+	{
                 frame = dev->write_queue;
 #ifdef FREE_ON_ERROR
                 dev->write_queue = dev->write_queue->next;
@@ -775,14 +764,20 @@
 	{
 
 		if (dev->send_seq > dev->unack_seq)
-                        if (ack <= dev->unack_seq || ack > dev->send_seq) 
+                        if (ack <= dev->unack_seq || ack > dev->send_seq)
 			{
-                                printk("layer 2 ack unacceptable - dev %d", dev->id);
+                                printk(KERN_DEBUG
+				       "layer 2 ack unacceptable - dev %d",
+				       dev->id);
+
                                 pcbit_l2_error(dev);
                         }
                         else
-                                if (ack > dev->send_seq && ack <= dev->unack_seq) {
-					printk("layer 2 ack unacceptable - dev %d", dev->id);
+                                if (ack > dev->send_seq && ack <= dev->unack_seq)
+				{
+					printk(KERN_DEBUG
+					       "layer 2 ack unacceptable - dev %d",
+					       dev->id);
                                         pcbit_l2_error(dev);
                                 }
 
@@ -805,55 +800,9 @@
 
 			if (dev->send_seq == lsend_seq)
 				break;
-                        count++;			
-                }
-    
-                if (!count) {
-                        u_char info;
-
-                        info = 0;
-                        info |= dev->rcv_seq << 3;
-                        info |= dev->send_seq;
-	
-                        writeb(info, dev->sh_mem + BANK4);  
-                }
+                        count++;
+                }    
         }
         else
                 printk(KERN_DEBUG "recv_ack: unacked = 0\n");
 }
-
-static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq)
-{
-        unsigned long flags;
-        int busy;
-        u_char info;
-
-        save_flags(flags);
-        cli();
-        if (!(busy=dev->r_busy))
-                dev->r_busy = 1;
-        restore_flags(flags);
-
-        if (busy)
-                return;
-        
-
-        while (read_seq != dev->rcv_seq) {
-                pcbit_receive(dev);
-                dev->rcv_seq = (dev->rcv_seq + 1) % 8;  
-        }
-
-        dev->r_busy = 0;
-
-        info = 0;
-        info |= dev->rcv_seq << 3;
-        info |= dev->send_seq;
-  
-        writeb(info, dev->sh_mem + BANK4);  
-}
-
-
-
-
-
-
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c
--- v2.0.0/linux/drivers/isdn/teles/callc.c	Sun Jun  9 13:28:43 1996
+++ linux/drivers/isdn/teles/callc.c	Sat Jun 29 20:36:23 1996
@@ -1,6 +1,12 @@
-/* $Id: callc.c,v 1.11 1996/06/07 12:32:20 fritz Exp $
+/* $Id: callc.c,v 1.13 1996/06/24 17:15:55 fritz Exp $
  *
  * $Log: callc.c,v $
+ * Revision 1.13  1996/06/24 17:15:55  fritz
+ * corrected return code of teles_writebuf()
+ *
+ * Revision 1.12  1996/06/12 16:15:33  fritz
+ * Extended user-configurable debugging flags.
+ *
  * Revision 1.11  1996/06/07 12:32:20  fritz
  * More changes to support suspend/resume.
  *
@@ -1297,8 +1303,10 @@
                 chanlist[i].ds.l2.l2m.debug = debugflags & 16;
         }
         for (i = 0; i < nrcards; i++)
-                if (cards[i].sp)
+                if (cards[i].sp) {
                         cards[i].sp->dlogflag = debugflags & 4;
+                        cards[i].sp->debug = debugflags & 32;
+                }
 }
 
 int
@@ -1419,12 +1427,15 @@
 
 	if (!chanp->data_open) {
 		printk(KERN_DEBUG "teles_writebuf: channel not open\n");
-		return -ENOMEM;
+		return -EIO;
 	}
 	
         err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21);
         if (err)
-                return -ENOMEM;
+                /* Must return 0 here, since this is not an error
+                 * but a temporary lack of resources.
+                 */
+                return 0;
 
         ptr = DATAPTR(ibh);
         if (chanp->lc_b.l2_establish)
diff -u --recursive --new-file v2.0.0/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c
--- v2.0.0/linux/drivers/isdn/teles/card.c	Sun Jun  9 13:28:43 1996
+++ linux/drivers/isdn/teles/card.c	Sat Jun 29 20:36:23 1996
@@ -1,4 +1,4 @@
-/* $Id: card.c,v 1.9 1996/06/06 14:42:09 fritz Exp $
+/* $Id: card.c,v 1.12 1996/06/24 17:16:52 fritz Exp $
  *
  * card.c     low level stuff for the Teles S0 isdn card
  * 
@@ -7,6 +7,16 @@
  * Beat Doebeli         log all D channel traffic
  * 
  * $Log: card.c,v $
+ * Revision 1.12  1996/06/24 17:16:52  fritz
+ * Added check for misconfigured membase.
+ *
+ * Revision 1.11  1996/06/14 03:30:37  fritz
+ * Added recovery from EXIR 40 interrupt.
+ * Some cleanup.
+ *
+ * Revision 1.10  1996/06/11 14:57:20  hipp
+ * minor changes to ensure, that SKBs are sent in the right order
+ *
  * Revision 1.9  1996/06/06 14:42:09  fritz
  * Bugfix: forgot hsp-> in last change.
  *
@@ -52,7 +62,6 @@
 #include <linux/interrupt.h>
 
 #undef DCHAN_VERBOSE
-#define FRITZ_EXPERIMENTAL
 
 extern void     tei_handler(struct PStack *st, byte pr,
 			    struct BufHeader *ibh);
@@ -215,16 +224,9 @@
 static inline void
 waitforXFW_0(byte * base, byte hscx)
 {
-#ifdef FRITZ_EXPERIMENTAL
 	long            to = 20;
 
 	while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
-#else
-	long            to = 10;
-
-	waitforCEC_0(base, hscx);
-	while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x40)) && to) {
-#endif
 		udelay(5);
 		to--;
 	}
@@ -235,16 +237,9 @@
 static inline void
 waitforXFW_3(int iobase, byte hscx)
 {
-#ifdef FRITZ_EXPERIMENTAL
 	long            to = 20;
 
 	while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
-#else
-	long            to = 10;
-
-	waitforCEC_3(iobase, hscx);
-	while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x40)) && to) {
-#endif
 		udelay(5);
 		to--;
 	}
@@ -507,10 +502,10 @@
 			} else {
 				if (hsp->releasebuf)
 					BufPoolRelease(hsp->xmtibh);
-				hsp->xmtibh = NULL;
 				hsp->sendptr = 0;
 				if (hsp->st->l4.l1writewakeup)
 					hsp->st->l4.l1writewakeup(hsp->st);
+				hsp->xmtibh = NULL;
 			}
 		if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
 			hsp->releasebuf = !0;
@@ -709,7 +704,7 @@
 static void
 teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-	byte                 val, val2, r, exval;
+	byte                 val, r, exval;
 	struct IsdnCardState *sp;
 	unsigned int         count;
 	struct HscxState     *hsp;
@@ -725,11 +720,20 @@
 	if (val & 0x01) {
 		hsp = sp->hs + 1;
                 exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR);
-                if ((hsp->mode == 1) || (exval == 0x40))
-                        hscx_fill_fifo(hsp);
-                else
-                        printk(KERN_WARNING "HSCX B EXIR %x xmitbh %lx rcvibh %lx\n",
-                               exval, (long) hsp->xmtibh, (long) hsp->rcvibh);
+                if (exval == 0x40) {
+                        if (hsp->mode == 1)
+                                hscx_fill_fifo(hsp);
+                        else {
+                                /* Here we lost an TX interrupt, so
+                                 * restart transmitting the whole frame.
+                                 */
+                                hsp->sendptr = 0;
+			        WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
+                                               hsp->hscx, 0x01);
+                                printk(KERN_DEBUG "HSCX B EXIR %x\n", exval);
+                        }
+                } else
+                        printk(KERN_WARNING "HSCX B EXIR %x\n", exval);
 	}
 	if (val & 0xf8) {
 		if (sp->debug)
@@ -739,33 +743,28 @@
 	if (val & 0x02) {
 		hsp = sp->hs;
                 exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR);
-                if ((hsp->mode == 1) && (exval == 0x40))
-                        hscx_fill_fifo(hsp);
-                else
-                        printk(KERN_WARNING "HSCX A EXIR %x\n",exval);
+                if (exval == 0x40) {
+                        if (hsp->mode == 1)
+                                hscx_fill_fifo(hsp);
+                        else {
+                                /* Here we lost an TX interrupt, so
+                                 * restart transmitting the whole frame.
+                                 */
+                                hsp->sendptr = 0;
+			        WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
+                                               hsp->hscx, 0x01);
+                                printk(KERN_DEBUG "HSCX A EXIR %x\n", exval);
+                        }
+                } else
+                        printk(KERN_WARNING "HSCX A EXIR %x\n", exval);
 	}
-
-/* ??? Why do that vvvvvvvvvvvvvvvvvvvvv different on Teles 16-3 ??? */
-        if (sp->membase) {
-                if (val & 0x04) {
-                        val = readhscx_0(sp->membase, 0, HSCX_ISTA);
-                        if (sp->debug)
-                                printk(KERN_DEBUG "HSCX A interrupt %x\n",
-                                       val);
-                        hscx_interrupt(sp, val, 0);
-                }
-        } else {
-                val2 = readhscx_3(sp->iobase, 0, HSCX_ISTA);
+        if (val & 0x04) {
+                val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA);
                 if (sp->debug)
-                        printk(KERN_DEBUG "HSCX A ISTA %x\n", val2);
-                if (val & 0x04) {
-                        if (sp->debug)
-                                printk(KERN_DEBUG "HSCX A interrupt %x\n",
-                                       val2);
-                        hscx_interrupt(sp, val2, 0);
-                }
+                        printk(KERN_DEBUG "HSCX A interrupt %x\n",
+                               val);
+                hscx_interrupt(sp, val, 0);
         }
-/* ??? Why do that ^^^^^^^^^^^^^^^^^^^^^ different on Teles 16-3 ??? */
 
 	val = READISAC(sp->membase, sp->iobase, ISAC_ISTA);
 
@@ -1083,6 +1082,13 @@
 	byte            cfval, val;
 	struct IsdnCard *card = cards + cardnr;
 
+        if (card->membase)
+                if ((unsigned long)card->membase < 0x10000) {
+                        (unsigned long)card->membase <<= 4;
+                        printk(KERN_INFO
+                               "Teles membase configured DOSish, assuming 0x%lx\n",
+                               (unsigned long)card->membase);
+                }
         if (!card->iobase) {
                 if (card->membase) {
                         printk(KERN_NOTICE
@@ -1090,7 +1096,7 @@
                                (long) card->membase, card->interrupt,
                                (card->protocol == ISDN_PTYPE_1TR6) ?
                                "1TR6" : "EDSS1");
-                        printk(KERN_INFO "HSCX version A: %x B:%x\n",
+                        printk(KERN_INFO "HSCX version A:%x B:%x\n",
                                readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf,
                                readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf);
                 }
@@ -1736,12 +1742,18 @@
 	struct IsdnCardState *sp = (struct IsdnCardState *)
 	st->l1.hardware;
 	struct HscxState *hsp = sp->hs + st->l1.hscx;
+	long flags;
 
 	switch (pr) {
                 case (PH_DATA):
-                        if (hsp->xmtibh)
+			save_flags(flags);
+			cli();
+                        if (hsp->xmtibh) {
                                 BufQueueLink(&hsp->sq, ibh);
+				restore_flags(flags);
+			}
                         else {
+				restore_flags(flags);
                                 hsp->xmtibh = ibh;
                                 hsp->sendptr = 0;
                                 hsp->releasebuf = !0;
diff -u --recursive --new-file v2.0.0/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.0.0/linux/drivers/net/de4x5.c	Sat Jun  1 20:11:32 1996
+++ linux/drivers/net/de4x5.c	Sat Jun 29 11:12:16 1996
@@ -1,4 +1,4 @@
-/*  de4x5.c: A DIGITAL DE425/DE434/DE435/DE500 ethernet driver for Linux.
+/*  de4x5.c: A DIGITAL DE425/DE434/DE435/DE450/DE500 ethernet driver for Linux.
 
     Copyright 1994, 1995 Digital Equipment Corporation.
 
@@ -191,15 +191,25 @@
                           Fix bug in dc21040 and dc21041 autosense code.
 			  Remove buffer copies on receive for Intels.
 			  Change sk_buff handling during media disconnects to
-			  eliminate DUP packets.
+			   eliminate DUP packets.
 			  Add dynamic TX thresholding.
 			  Change all chips to use perfect multicast filtering.
 			  Fix alloc_device() bug <jari@markkus2.fimr.fi>
+      0.43   21-Jun-96    Fix unconnected media TX retry bug.
+                          Add Accton to the list of broken cards.
+			  Fix TX under-run bug for non DC21140 chips.
+			  Fix boot command probe bug in alloc_device() as
+			   reported by <koen.gadeyne@barco.com> and 
+			   <orava@nether.tky.hut.fi>.
+			  Add cache locks to prevent a race condition as
+			   reported by <csd@microplex.com> and 
+			   <baba@beckman.uiuc.edu>.
+			  Upgraded alloc_device() code.
 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:v0.42 96/4/26 davies@wanton.lkg.dec.com\n";
+static const char *version = "de4x5.c:v0.43 96/6/21 davies@wanton.lkg.dec.com\n";
 
 #include <linux/module.h>
 
@@ -226,6 +236,7 @@
 #include <linux/time.h>
 #include <linux/types.h>
 #include <linux/unistd.h>
+#include <linux/ctype.h>
 
 #include "de4x5.h"
 
@@ -274,10 +285,12 @@
 ** Define special SROM detection cases
 */
 static c_char enet_det[][ETH_ALEN] = {
-    {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00}
+    {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00},
+    {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00}
 };
 
-#define SMC 1
+#define SMC    1
+#define ACCTON 2
 
 
 #ifdef DE4X5_DEBUG
@@ -511,6 +524,7 @@
     struct {
 	void *priv;                         /* Original kmalloc'd mem addr  */
 	void *buf;                          /* Original kmalloc'd mem addr  */
+	int lock;                           /* Lock the cache accesses      */
 	s32 csr0;                           /* Saved Bus Mode Register      */
 	s32 csr6;                           /* Saved Operating Mode Reg.    */
 	s32 csr7;                           /* Saved IRQ Mask Register      */
@@ -633,12 +647,15 @@
 static void    eisa_probe(struct device *dev, u_long iobase);
 static void    pci_probe(struct device *dev, u_long iobase);
 static struct  device *alloc_device(struct device *dev, u_long iobase);
+static struct  device *insert_device(struct device *dev, u_long iobase,
+				     int (*init)(struct device *));
 static char    *build_setup_frame(struct device *dev, int mode);
 static void    disable_ast(struct device *dev);
 static void    enable_ast(struct device *dev, u32 time_out);
 static long    de4x5_switch_to_srl(struct device *dev);
 static long    de4x5_switch_to_mii(struct device *dev);
 static void    timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec);
+static int     de4x5_dev_index(char *s);
 static void    de4x5_dbg_open(struct device *dev);
 static void    de4x5_dbg_mii(struct device *dev, int k);
 static void    de4x5_dbg_media(struct device *dev);
@@ -683,7 +700,7 @@
 {
     int tmp = num_de4x5s, status = -ENODEV;
     u_long iobase = dev->base_addr;
-    
+
     eisa_probe(dev, iobase);
     pci_probe(dev, iobase);
     
@@ -691,7 +708,7 @@
 	printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name, 
 	       iobase);
     }
-    
+
     /*
     ** Walk the device list to check that at least one device
     ** initialised OK
@@ -1076,6 +1093,7 @@
 	return 0;
     }
 
+    set_bit(0, (void*)&dev->tbusy);              /* Stop send re-tries */
     if (lp->tx_enable == NO) {                   /* Cannot send for now */
 	return -1;                                
     }
@@ -1085,11 +1103,13 @@
     ** interrupts are lost by delayed descriptor status updates relative to
     ** the irq assertion, especially with a busy PCI bus.
     */
-    set_bit(0, (void*)&dev->tbusy);
     cli();
     de4x5_tx(dev);
     sti();
-    
+
+    /* Test if cache is already locked - requeue skb if so */
+    if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1;
+
     /* Transmit descriptor ring full or stale skb */
     if (dev->tbusy || lp->tx_skb[lp->tx_new]) {
 	if (dev->interrupt) {
@@ -1130,6 +1150,8 @@
 	}
     }
     
+    lp->cache.lock = 0;
+
     return status;
 }
 
@@ -1195,8 +1217,11 @@
     }
 
     /* Load the TX ring with any locally stored packets */
-    while (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
-	de4x5_queue_pkt(de4x5_get_cache(dev), dev);
+    if (!set_bit(0, (void *)&lp->cache.lock)) {
+	while (lp->cache.skb && !dev->tbusy && lp->tx_enable) {
+	    de4x5_queue_pkt(de4x5_get_cache(dev), dev);
+	}
+	lp->cache.lock = 0;
     }
 
     dev->interrupt = UNMASK_INTERRUPTS;
@@ -1376,7 +1401,7 @@
     int omr;
 
     omr = inl(DE4X5_OMR);
-    if (!(omr & OMR_SF)) {
+    if (!(omr & OMR_SF) || (lp->chipset==DC21041) || (lp->chipset==DC21040)) {
 	omr &= ~(OMR_ST|OMR_SR);
 	outl(omr, DE4X5_OMR);
 	while (inl(DE4X5_STS) & STS_TS);
@@ -1564,6 +1589,7 @@
     u_long iobase;
     struct bus_type *lp = &bus;
     char name[DE4X5_STRLEN];
+    struct device *tmp;
     
     if (!ioaddr && autoprobed) return;     /* Been here before ! */
     
@@ -1589,15 +1615,14 @@
 	    DevicePresent(EISA_APROM);
 	    /* Write the PCI Configuration Registers */
 	    outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
-	    outl(0x00004000, PCI_CFLT);
+	    outl(0x00006000, PCI_CFLT);
 	    outl(iobase, PCI_CBIO);
 	    
 	    if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
-		if ((dev = alloc_device(dev, iobase)) != NULL) {
-		    if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+		if ((tmp = alloc_device(dev, iobase)) != NULL) {
+		    if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
 			num_de4x5s++;
 		    }
-		    num_eth++;
 		}
 	    } else if (autoprobed) {
 		printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase);
@@ -1632,6 +1657,7 @@
     u_int class = DE4X5_CLASS_CODE;
     u_int iobase;
     struct bus_type *lp = &bus;
+    struct device *tmp;
 
     if ((!ioaddr || !loading_module) && autoprobed) return;
     
@@ -1639,14 +1665,14 @@
     
     lp->bus = PCI;
     
-    if (ioaddr < 0x1000) {
+    if ((ioaddr < 0x1000) && loading_module) {
 	pbus = (u_short)(ioaddr >> 8);
 	dnum = (u_short)(ioaddr & 0xff);
     } else {
 	pbus = 0;
 	dnum = 0;
     }
-    
+
     for (index=0; 
 	 (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
 	 index++) {
@@ -1667,7 +1693,7 @@
 	    /* Get the board I/O address */
 	    pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
 	    iobase &= CBIO_MASK;
-	    
+
 	    /* Fetch the IRQ to be used */
 	    pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
 	    if ((irq == 0) || (irq == (u_char) 0xff)) continue;
@@ -1684,12 +1710,11 @@
 
 	    DevicePresent(DE4X5_APROM);
 	    if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
-		if ((dev = alloc_device(dev, iobase)) != NULL) {
-		    dev->irq = irq;
-		    if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+		if ((tmp = alloc_device(dev, iobase)) != NULL) {
+		    tmp->irq = irq;
+		    if ((status = de4x5_hw_init(tmp, iobase)) == 0) {
 			num_de4x5s++;
 		    }
-		    num_eth++;
 		}
 	    } else if (autoprobed) {
 		printk("%s: region already allocated at 0x%04x.\n", dev->name, 
@@ -1702,109 +1727,95 @@
 }
 
 /*
-** Allocate the device by pointing to the next available space in the
-** device structure. Should one not be available, it is created.
+** Search the entire 'eth' device list for a fixed probe. If a match isn't
+** found then check for an autoprobe or unused device location. If they
+** are not available then insert a new device structure at the end of
+** the current list.
 */
 static struct device *
 alloc_device(struct device *dev, u_long iobase)
 {
-    int addAutoProbe = 0;
-    struct device *tmp = NULL, *ret;
-    int (*init)(struct device *) = NULL;
-    
+    struct device *adev = NULL;
+    int fixed = 0, new_dev = 0;
+
+    num_eth = de4x5_dev_index(dev->name);
     if (loading_module) return dev;
     
-    /*
-    ** Check the device structures for an end of list or unused device
-    */
-    while (dev->next != NULL) {
-	if ((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0)) break;
-	dev = dev->next;                   /* walk through eth device list */
-	num_eth++;                         /* increment eth device number */
+    while (1) {
+	if (((dev->base_addr == DE4X5_NDA) || (dev->base_addr==0)) && !adev) {
+	    adev=dev;
+	} else if ((dev->priv == NULL) && (dev->base_addr==iobase)) {
+	    fixed = 1;
+	} else {
+	    if (dev->next == NULL) {
+		new_dev = 1;
+	    } else if (strncmp(dev->next->name, "eth", 3) != 0) {
+		new_dev = 1;
+	    }
+	}
+	if ((dev->next == NULL) || new_dev || fixed) break;
+	dev = dev->next;
+	num_eth++;
     }
-    
-    /*
-    ** If an autoprobe is requested for another device, we must re-insert
-    ** the request later in the list. Remember the current position first.
-    */
-    if ((dev->base_addr == 0) && (num_de4x5s > 0)) {
-	addAutoProbe++;
-	tmp = dev->next;                   /* point to the next device */
-	init = dev->init;                  /* remember the probe function */
+    if (adev && !fixed) {
+	dev = adev;
+	num_eth = de4x5_dev_index(dev->name);
+	new_dev = 0;
+    }
+
+    if (((dev->next == NULL) &&  
+	((dev->base_addr != DE4X5_NDA) && (dev->base_addr != 0)) && !fixed) ||
+	new_dev) {
+	num_eth++;                         /* New device */
+	dev = insert_device(dev, iobase, de4x5_probe);
     }
     
-    /*
-    ** If at end of list and can't use current entry, malloc one up. 
-    ** If memory could not be allocated, print an error message.
-    */
-    if ((dev->next == NULL) &&  
-	!((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0))) {
-	dev->next = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);
-	dev = dev->next;                   /* point to the new device */
-	if (dev == NULL) {
-	    printk("eth%d: Device not initialised, insufficient memory\n", num_eth);
+    return dev;
+}
+
+/*
+** If at end of eth device list and can't use current entry, malloc
+** one up. If memory could not be allocated, print an error message.
+*/
+static struct device *
+insert_device(struct device *dev, u_long iobase, int (*init)(struct device *))
+{
+    struct device *new;
+
+    new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);
+    if (new == NULL) {
+	printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
+	return NULL;
+    } else {
+	new->next = dev->next;
+	dev->next = new;
+	dev = dev->next;               /* point to the new device */
+	dev->name = (char *)(dev + 1);
+	if (num_eth > 9999) {
+	    sprintf(dev->name,"eth????");/* New device name */
 	} else {
-	    /*
-	    ** If the memory was allocated, point to the new memory area
-	    ** and initialize it (name, I/O address, next device (NULL) and
-	    ** initialisation probe routine).
-	    */
-	    dev->name = (char *)(dev + 1);
-	    if (num_eth > 9999) {
-		sprintf(dev->name,"eth????");/* New device name */
-	    } else {
-		sprintf(dev->name,"eth%d", num_eth);/* New device name */
-	    }
-	    dev->base_addr = iobase;       /* assign the io address */
-	    dev->next = NULL;              /* mark the end of list */
-	    dev->init = &de4x5_probe;      /* initialisation routine */
-	    num_de4x5s++;
+	    sprintf(dev->name,"eth%d", num_eth);/* New device name */
 	}
+	dev->base_addr = iobase;       /* assign the io address */
+	dev->init = init;              /* initialisation routine */
     }
-    ret = dev;                             /* return current struct, or NULL */
-     
-    /*
-    ** Now figure out what to do with the autoprobe that has to be inserted.
-    ** Firstly, search the (possibly altered) list for an empty space.
-    */
-    if (ret != NULL) {
-	if (addAutoProbe) {
-	    for (; (tmp->next!=NULL) && (tmp->base_addr!=DE4X5_NDA); tmp=tmp->next);
-	    /*
-	    ** If no more device structures and can't use the current one, 
-	    ** malloc one up. If memory could not be allocated, print an error
-	    **message.
-	    */
-	    if ((tmp->next == NULL) && !(tmp->base_addr == DE4X5_NDA)) {
-		tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8,
-						     GFP_KERNEL);
-		tmp = tmp->next;           /* point to the new device */
-		if (tmp == NULL) {
-		    printk("%s: Insufficient memory to extend the device list.\n", 
-			   dev->name);
-		} else {
-		    /*
-		    ** If the memory was allocated, point to the new memory
-		    ** area and initialize it (name, I/O address, next device
-		    ** (NULL) and initialisation probe routine).
-		    */
-		    tmp->name = (char *)(tmp + 1);
-		    if (num_eth > 9999) {
-			sprintf(tmp->name,"eth????");
-		    } else {               /* New device name */
-			sprintf(tmp->name,"eth%d", num_eth);
-		    }
-		    tmp->base_addr = 0;    /* re-insert the io address */
-		    tmp->next = NULL;      /* mark the end of list */
-		    tmp->init = init;      /* initialisation routine */
-		}
-	    } else {                       /* structure already exists */
-		tmp->base_addr = 0;        /* re-insert the io address */
-	    }
-	}
+
+    return dev;
+}
+
+static int
+de4x5_dev_index(char *s)
+{
+    int i=0, j=0;
+
+    for (;*s; s++) {
+	if (isdigit(*s)) {
+	    j=1;
+	    i = (i * 10) + (*s - '0');
+	} else if (j) break;
     }
-    
-    return ret;
+
+    return i;
 }
 
 /*
@@ -2381,8 +2392,10 @@
     de4x5_setup_intr(dev);
     lp->lostMedia = 0;
     lp->tx_enable = YES;
+    dev->tbusy = 0;
     sti();
     outl(POLL_DEMAND, DE4X5_TPD);
+    mark_bh(NET_BH);
 
     return;
 }
@@ -2643,8 +2656,9 @@
     ret = lp->rx_skb[index];
     lp->rx_skb[index] = p;
 
-    if ((unsigned long) ret > 1)
-	    skb_put(ret, len);
+    if ((u_long) ret > 1) {
+	skb_put(ret, len);
+    }
 
     return ret;
 
@@ -2675,7 +2689,7 @@
     int i;
 
     for (i=0; i<lp->rxRingSize; i++) {
-	if ((unsigned long) lp->rx_skb[i] > 1) {
+	if ((u_long) lp->rx_skb[i] > 1) {
 	    dev_kfree_skb(lp->rx_skb[i], FREE_WRITE);
 	}
 	lp->rx_ring[i].status = 0;
@@ -2728,7 +2742,6 @@
 	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
 	de4x5_sw_reset(dev);
 	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
-	dev->tbusy = 0;
 	lp->cache.save_cnt++;
 	START_DE4X5;
     }
@@ -2748,7 +2761,6 @@
 	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
 	de4x5_sw_reset(dev);
 	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
-	dev->tbusy = 0;
 	lp->cache.save_cnt--;
 	START_DE4X5;
     }
@@ -3074,7 +3086,7 @@
 	    } else if (!broken) {
 		dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
 		dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
-	    } else if (broken == SMC) {           /* Assume SMC9332 for now */
+	    } else if ((broken == SMC) || (broken == ACCTON)) {
 		dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++;
 		dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++;
 	    }
@@ -3118,7 +3130,11 @@
     for (i=0; i<sizeof(enet_det)/ETH_ALEN; i++) {
 	if (!de4x5_strncmp((char *)&lp->srom, (char *)&enet_det[i], 3) &&
 	    !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) {
-	    status = SMC;
+	    if (i == 0) {
+		status = SMC;
+	    } else if (i == 1) {
+		status = ACCTON;
+	    }
 	    break;
 	}
     }
@@ -4123,8 +4139,8 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de4x5.c"
+ *  compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
  *
- *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de4x5.c"
+ *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
  * End:
  */
diff -u --recursive --new-file v2.0.0/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.0.0/linux/drivers/net/net_init.c	Mon Mar 25 08:58:21 1996
+++ linux/drivers/net/net_init.c	Sat Jun 29 12:00:46 1996
@@ -20,6 +20,8 @@
 		Use dev_close cleanly so we always shut things down tidily.
 		
 	Changed 29/10/95, Alan Cox to pass sockaddr's around for mac addresses.
+	
+	14/06/96 - Paul Gortmaker:	Add generic eth_change_mtu() function. 
 */
 
 #include <linux/config.h>
@@ -144,6 +146,14 @@
 	return 0;
 }
 
+static int eth_change_mtu(struct device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > 1500))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
 void ether_setup(struct device *dev)
 {
 	int i;
@@ -165,6 +175,7 @@
 		}
 	}
 
+	dev->change_mtu		= eth_change_mtu;
 	dev->hard_header	= eth_header;
 	dev->rebuild_header 	= eth_rebuild_header;
 	dev->set_mac_address 	= eth_mac_addr;
diff -u --recursive --new-file v2.0.0/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v2.0.0/linux/drivers/net/slhc.c	Mon May 20 08:21:02 1996
+++ linux/drivers/net/slhc.c	Tue Jun 25 12:03:29 1996
@@ -107,29 +107,27 @@
 	memset(comp, 0, sizeof(struct slcompress));
 
 	if ( rslots > 0  &&  rslots < 256 ) {
-		comp->rstate =
-		  (struct cstate *)kmalloc(rslots * sizeof(struct cstate),
-					   GFP_KERNEL);
+		size_t rsize = rslots * sizeof(struct cstate);
+		comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL);
 		if (! comp->rstate)
 		{
 			kfree((unsigned char *)comp);
 			return NULL;
 		}
-		memset(comp->rstate, 0, rslots * sizeof(struct cstate));
+		memset(comp->rstate, 0, rsize);
 		comp->rslot_limit = rslots - 1;
 	}
 
 	if ( tslots > 0  &&  tslots < 256 ) {
-		comp->tstate =
-		  (struct cstate *)kmalloc(tslots * sizeof(struct cstate),
-					   GFP_KERNEL);
+		size_t tsize = tslots * sizeof(struct cstate);
+		comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL);
 		if (! comp->tstate)
 		{
 			kfree((unsigned char *)comp->rstate);
 			kfree((unsigned char *)comp);
 			return NULL;
 		}
-		memset(comp->tstate, 0, tslots * sizeof(struct cstate));
+		memset(comp->tstate, 0, tsize);
 		comp->tslot_limit = tslots - 1;
 	}
 
diff -u --recursive --new-file v2.0.0/linux/drivers/net/wic.c linux/drivers/net/wic.c
--- v2.0.0/linux/drivers/net/wic.c	Fri Apr 19 10:07:59 1996
+++ linux/drivers/net/wic.c	Tue Jul  2 19:08:42 1996
@@ -49,7 +49,7 @@
 #include <asm/bitops.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
-#include <string.h>
+#include <linux/string.h>
 
 #define NET_DEBUG 1
 /* Use 0 for production, 1 for verification, >2 for debug */
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.0.0/linux/drivers/scsi/Config.in	Thu Jun  6 17:42:36 1996
+++ linux/drivers/scsi/Config.in	Tue Jul  2 19:08:42 1996
@@ -48,9 +48,7 @@
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
 dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-     dep_tristate 'Qlogic ISP SCSI support (EXPERIMENTAL)' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
-  fi
+  dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
 fi
 dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
 dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v2.0.0/linux/drivers/scsi/README.st	Tue May  7 16:22:32 1996
+++ linux/drivers/scsi/README.st	Mon Jul  1 07:08:27 1996
@@ -1,5 +1,8 @@
 This file contains brief information about the SCSI tape driver.
-Last modified: Wed May  1 11:51:35 1996 by root@kai.makisara.fi
+The driver is currently maintained by Kai M{kisara (email
+Kai.Makisara@metla.fi)
+
+Last modified: Sun Jun 30 15:47:14 1996 by root@kai.makisara.fi
 
 
 BASICS
@@ -85,13 +88,15 @@
 compile time and/or at run time (via ioctl):
 
 Buffering of data across write calls in fixed block mode (define
-ST_BUFFER_WRITES). This should be disabled if reliable detection of
-end of medium (EOM) for fixed block mode is desired.
+ST_BUFFER_WRITES).
 
 Asynchronous writing. Writing the buffer contents to the tape is
 started and the write call returns immediately. The status is checked
-at the next tape operation. Should not used if reliable EOM detection
-is desired.
+at the next tape operation.
+
+Buffered writes and asynchronous writes may in some rare cases cause
+problems in multivolume operations if there is not enough space after
+the early-warning mark to flush the driver buffer.
 
 Read ahead for fixed block mode (ST_READ_AHEAD). Filling the buffer is
 attempted even if the user does not want to get all of the data at
@@ -187,7 +192,8 @@
 	control of compression. Some drives (like the Exabytes) use
 	density codes for compression control. Some drives use another
 	mode page but this page has not been implemented in the
-	driver.
+	driver. Some drives without compression capability will accept
+	any compression mode without error.
 MTSETPART Moves the tape to the partition given by the argument at the
 	next tape operation. The block at which the tape is positioned
 	is the block where the tape was previously positioned in the
@@ -310,5 +316,3 @@
 time or the MT_ST_CAN_BSR bit is set for the drive with an ioctl.
 (The driver always backs over a filemark crossed by read ahead if the
 user does not request data that far.)
-
-Kai M{kisara
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v2.0.0/linux/drivers/scsi/hosts.h	Mon May 20 08:21:02 1996
+++ linux/drivers/scsi/hosts.h	Mon Jul  1 20:06:05 1996
@@ -244,7 +244,7 @@
     unsigned short extra_bytes;
     volatile unsigned char host_busy;
     char host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
-    int last_reset;
+    unsigned long last_reset;
     struct wait_queue *host_wait;
     Scsi_Cmnd *host_queue;
     Scsi_Host_Template * hostt;
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.0.0/linux/drivers/scsi/qlogicisp.c	Thu Jun  6 17:42:36 1996
+++ linux/drivers/scsi/qlogicisp.c	Mon Jul  1 20:06:05 1996
@@ -63,7 +63,7 @@
    the latest firmware provided by QLogic.  This may be an earlier/later
    revision than supplied by your board. */
 
-#define RELOAD_FIRMWARE		1
+#define RELOAD_FIRMWARE		0
 
 /* Set the following macro to 1 to reload the ISP1020's defaults from nvram.
    If you are not sure of your settings, leave this alone, the driver will
@@ -76,6 +76,7 @@
 #define DEBUG_ISP1020		0
 #define DEBUG_ISP1020_INT	0
 #define DEBUG_ISP1020_SETUP	0
+#define TRACE_ISP		0
 
 #define DEFAULT_LOOP_COUNT	1000000
 
@@ -83,6 +84,38 @@
 
 #include <linux/module.h>
 
+#if TRACE_ISP
+
+# define TRACE_BUF_LEN	(32*1024)
+
+struct {
+	u_long		next;
+	struct {
+		u_long		time;
+		u_int		index;
+		u_int		addr;
+		u_char *	name;
+	} buf[TRACE_BUF_LEN];
+} trace;
+
+#define TRACE(w, i, a)						\
+{								\
+	unsigned long flags;					\
+								\
+	save_flags(flags);					\
+	cli();							\
+	trace.buf[trace.next].name  = (w);			\
+	trace.buf[trace.next].time  = jiffies;			\
+	trace.buf[trace.next].index = (i);			\
+	trace.buf[trace.next].addr  = (long) (a);		\
+	trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1);	\
+	restore_flags(flags);					\
+}
+
+#else
+# define TRACE(w, i, a)
+#endif
+
 #if DEBUG_ISP1020
 #define ENTER(x)	printk("isp1020 : entering %s()\n", x);
 #define LEAVE(x)	printk("isp1020 : leaving %s()\n", x);
@@ -146,10 +179,10 @@
 #define EXECUTION_TIMEOUT_RESET		0x8006
 
 struct Entry_header {
-    u_char    entry_type;
-    u_char    entry_cnt;
-    u_char    sys_def_1;
-    u_char    flags;
+	u_char	entry_type;
+	u_char	entry_cnt;
+	u_char	sys_def_1;
+	u_char	flags;
 };
 
 /* entry header type commands */
@@ -166,25 +199,22 @@
 #define EFLAG_BAD_PAYLOAD	8
 
 struct dataseg {
-    u_int   d_base;
-    u_int   d_count;
+	u_int			d_base;
+	u_int			d_count;
 };
 
 struct Command_Entry {
-    struct    Entry_header    hdr;
-    u_int     handle;
-    u_char    target_lun;
-    u_char    target_id;
-    u_short   cdb_length;
-    u_short   control_flags;
-    u_short   rsvd;
-    u_short   time_out;
-    u_short   segment_cnt;
-    u_char    cdb[12];
-    struct    dataseg    dataseg0;
-    struct    dataseg    dataseg1;
-    struct    dataseg    dataseg2;
-    struct    dataseg    dataseg3;
+	struct Entry_header	hdr;
+	u_int			handle;
+	u_char			target_lun;
+	u_char			target_id;
+	u_short			cdb_length;
+	u_short			control_flags;
+	u_short			rsvd;
+	u_short			time_out;
+	u_short			segment_cnt;
+	u_char			cdb[12];
+	struct dataseg		dataseg[4];
 };
 
 /* command entry control flag definitions */
@@ -197,38 +227,32 @@
 #define CFLAG_WRITE		0x40
 
 struct Ext_Command_Entry {
-    struct    Entry_header    hdr;
-    u_int     handle;
-    u_char    target_lun;
-    u_char    target_id;
-    u_short   cdb_length;
-    u_short   control_flags;
-    u_short   rsvd;
-    u_short   time_out;
-    u_short   segment_cnt;
-    u_char    cdb[44];
+	struct Entry_header	hdr;
+	u_int			handle;
+	u_char			target_lun;
+	u_char			target_id;
+	u_short			cdb_length;
+	u_short			control_flags;
+	u_short			rsvd;
+	u_short			time_out;
+	u_short			segment_cnt;
+	u_char			cdb[44];
 };
 
 struct Continuation_Entry {
-    struct    Entry_header    hdr;
-    u_int     reserved;
-    struct    dataseg    dataseg0;
-    struct    dataseg    dataseg1;
-    struct    dataseg    dataseg2;
-    struct    dataseg    dataseg3;
-    struct    dataseg    dataseg4;
-    struct    dataseg    dataseg5;
-    struct    dataseg    dataseg6;
+	struct Entry_header	hdr;
+	u_int			reserved;
+	struct dataseg		dataseg[7];
 };
 
 struct Marker_Entry {
-    struct    Entry_header    hdr;
-    u_int     reserved;
-    u_char    target_lun;
-    u_char    target_id;
-    u_char    modifier;
-    u_char    rsvd;
-    u_char    rsvds[52];
+	struct Entry_header	hdr;
+	u_int			reserved;
+	u_char			target_lun;
+	u_char			target_id;
+	u_char			modifier;
+	u_char			rsvd;
+	u_char			rsvds[52];
 };
 
 /* marker entry modifier definitions */
@@ -237,17 +261,17 @@
 #define SYNC_ALL	2
 
 struct Status_Entry {
-    struct    Entry_header    hdr;
-    u_int     handle;
-    u_short   scsi_status;
-    u_short   completion_status;
-    u_short   state_flags;
-    u_short   status_flags;
-    u_short   time;
-    u_short   req_sense_len;
-    u_int     residual;
-    u_char    rsvd[8];
-    u_char    req_sense_data[32];
+	struct Entry_header	hdr;
+	u_int			handle;
+	u_short			scsi_status;
+	u_short			completion_status;
+	u_short			state_flags;
+	u_short			status_flags;
+	u_short			time;
+	u_short			req_sense_len;
+	u_int			residual;
+	u_char			rsvd[8];
+	u_char			req_sense_data[32];
 };
 
 /* status entry completion status definitions */
@@ -366,93 +390,93 @@
 
 #define PACKB(a, b)			(((a)<<4)|(b))
 
-u_char mbox_param[] = {
-    PACKB(1, 1),	/* MBOX_NO_OP */
-    PACKB(5, 5),	/* MBOX_LOAD_RAM */
-    PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
-    PACKB(5, 5),	/* MBOX_DUMP_RAM */
-    PACKB(3, 3),	/* MBOX_WRITE_RAM_WORD */
-    PACKB(2, 3),	/* MBOX_READ_RAM_WORD */
-    PACKB(6, 6),	/* MBOX_MAILBOX_REG_TEST */
-    PACKB(2, 3),	/* MBOX_VERIFY_CHECKSUM	*/
-    PACKB(1, 3),	/* MBOX_ABOUT_FIRMWARE */
-    PACKB(0, 0),	/* 0x0009 */
-    PACKB(0, 0),	/* 0x000a */
-    PACKB(0, 0),	/* 0x000b */
-    PACKB(0, 0),	/* 0x000c */
-    PACKB(0, 0),	/* 0x000d */
-    PACKB(1, 2),	/* MBOX_CHECK_FIRMWARE */
-    PACKB(0, 0),	/* 0x000f */
-    PACKB(5, 5),	/* MBOX_INIT_REQ_QUEUE */
-    PACKB(6, 6),	/* MBOX_INIT_RES_QUEUE */
-    PACKB(4, 4),	/* MBOX_EXECUTE_IOCB */
-    PACKB(2, 2),	/* MBOX_WAKE_UP	*/
-    PACKB(1, 6),	/* MBOX_STOP_FIRMWARE */
-    PACKB(4, 4),	/* MBOX_ABORT */
-    PACKB(2, 2),	/* MBOX_ABORT_DEVICE */
-    PACKB(3, 3),	/* MBOX_ABORT_TARGET */
-    PACKB(2, 2),	/* MBOX_BUS_RESET */
-    PACKB(2, 3),	/* MBOX_STOP_QUEUE */
-    PACKB(2, 3),	/* MBOX_START_QUEUE */
-    PACKB(2, 3),	/* MBOX_SINGLE_STEP_QUEUE */
-    PACKB(2, 3),	/* MBOX_ABORT_QUEUE */
-    PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_STATUS */
-    PACKB(0, 0),	/* 0x001e */
-    PACKB(1, 3),	/* MBOX_GET_FIRMWARE_STATUS */
-    PACKB(1, 2),	/* MBOX_GET_INIT_SCSI_ID */
-    PACKB(1, 2),	/* MBOX_GET_SELECT_TIMEOUT */
-    PACKB(1, 3),	/* MBOX_GET_RETRY_COUNT	*/
-    PACKB(1, 2),	/* MBOX_GET_TAG_AGE_LIMIT */
-    PACKB(1, 2),	/* MBOX_GET_CLOCK_RATE */
-    PACKB(1, 2),	/* MBOX_GET_ACT_NEG_STATE */
-    PACKB(1, 2),	/* MBOX_GET_ASYNC_DATA_SETUP_TIME */
-    PACKB(1, 3),	/* MBOX_GET_PCI_PARAMS */
-    PACKB(2, 4),	/* MBOX_GET_TARGET_PARAMS */
-    PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_PARAMS */
-    PACKB(0, 0),	/* 0x002a */
-    PACKB(0, 0),	/* 0x002b */
-    PACKB(0, 0),	/* 0x002c */
-    PACKB(0, 0),	/* 0x002d */
-    PACKB(0, 0),	/* 0x002e */
-    PACKB(0, 0),	/* 0x002f */
-    PACKB(2, 2),	/* MBOX_SET_INIT_SCSI_ID */
-    PACKB(2, 2),	/* MBOX_SET_SELECT_TIMEOUT */
-    PACKB(3, 3),	/* MBOX_SET_RETRY_COUNT	*/
-    PACKB(2, 2),	/* MBOX_SET_TAG_AGE_LIMIT */
-    PACKB(2, 2),	/* MBOX_SET_CLOCK_RATE */
-    PACKB(2, 2),	/* MBOX_SET_ACTIVE_NEG_STATE */
-    PACKB(2, 2),	/* MBOX_SET_ASYNC_DATA_SETUP_TIME */
-    PACKB(3, 3),	/* MBOX_SET_PCI_CONTROL_PARAMS */
-    PACKB(4, 4),	/* MBOX_SET_TARGET_PARAMS */
-    PACKB(4, 4),	/* MBOX_SET_DEV_QUEUE_PARAMS */
-    PACKB(0, 0),	/* 0x003a */
-    PACKB(0, 0),	/* 0x003b */
-    PACKB(0, 0),	/* 0x003c */
-    PACKB(0, 0),	/* 0x003d */
-    PACKB(0, 0),	/* 0x003e */
-    PACKB(0, 0),	/* 0x003f */
-    PACKB(1, 2),	/* MBOX_RETURN_BIOS_BLOCK_ADDR */
-    PACKB(6, 1),	/* MBOX_WRITE_FOUR_RAM_WORDS */
-    PACKB(2, 3)		/* MBOX_EXEC_BIOS_IOCB */
+const u_char mbox_param[] = {
+	PACKB(1, 1),	/* MBOX_NO_OP */
+	PACKB(5, 5),	/* MBOX_LOAD_RAM */
+	PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
+	PACKB(5, 5),	/* MBOX_DUMP_RAM */
+	PACKB(3, 3),	/* MBOX_WRITE_RAM_WORD */
+	PACKB(2, 3),	/* MBOX_READ_RAM_WORD */
+	PACKB(6, 6),	/* MBOX_MAILBOX_REG_TEST */
+	PACKB(2, 3),	/* MBOX_VERIFY_CHECKSUM	*/
+	PACKB(1, 3),	/* MBOX_ABOUT_FIRMWARE */
+	PACKB(0, 0),	/* 0x0009 */
+	PACKB(0, 0),	/* 0x000a */
+	PACKB(0, 0),	/* 0x000b */
+	PACKB(0, 0),	/* 0x000c */
+	PACKB(0, 0),	/* 0x000d */
+	PACKB(1, 2),	/* MBOX_CHECK_FIRMWARE */
+	PACKB(0, 0),	/* 0x000f */
+	PACKB(5, 5),	/* MBOX_INIT_REQ_QUEUE */
+	PACKB(6, 6),	/* MBOX_INIT_RES_QUEUE */
+	PACKB(4, 4),	/* MBOX_EXECUTE_IOCB */
+	PACKB(2, 2),	/* MBOX_WAKE_UP	*/
+	PACKB(1, 6),	/* MBOX_STOP_FIRMWARE */
+	PACKB(4, 4),	/* MBOX_ABORT */
+	PACKB(2, 2),	/* MBOX_ABORT_DEVICE */
+	PACKB(3, 3),	/* MBOX_ABORT_TARGET */
+	PACKB(2, 2),	/* MBOX_BUS_RESET */
+	PACKB(2, 3),	/* MBOX_STOP_QUEUE */
+	PACKB(2, 3),	/* MBOX_START_QUEUE */
+	PACKB(2, 3),	/* MBOX_SINGLE_STEP_QUEUE */
+	PACKB(2, 3),	/* MBOX_ABORT_QUEUE */
+	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_STATUS */
+	PACKB(0, 0),	/* 0x001e */
+	PACKB(1, 3),	/* MBOX_GET_FIRMWARE_STATUS */
+	PACKB(1, 2),	/* MBOX_GET_INIT_SCSI_ID */
+	PACKB(1, 2),	/* MBOX_GET_SELECT_TIMEOUT */
+	PACKB(1, 3),	/* MBOX_GET_RETRY_COUNT	*/
+	PACKB(1, 2),	/* MBOX_GET_TAG_AGE_LIMIT */
+	PACKB(1, 2),	/* MBOX_GET_CLOCK_RATE */
+	PACKB(1, 2),	/* MBOX_GET_ACT_NEG_STATE */
+	PACKB(1, 2),	/* MBOX_GET_ASYNC_DATA_SETUP_TIME */
+	PACKB(1, 3),	/* MBOX_GET_PCI_PARAMS */
+	PACKB(2, 4),	/* MBOX_GET_TARGET_PARAMS */
+	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_PARAMS */
+	PACKB(0, 0),	/* 0x002a */
+	PACKB(0, 0),	/* 0x002b */
+	PACKB(0, 0),	/* 0x002c */
+	PACKB(0, 0),	/* 0x002d */
+	PACKB(0, 0),	/* 0x002e */
+	PACKB(0, 0),	/* 0x002f */
+	PACKB(2, 2),	/* MBOX_SET_INIT_SCSI_ID */
+	PACKB(2, 2),	/* MBOX_SET_SELECT_TIMEOUT */
+	PACKB(3, 3),	/* MBOX_SET_RETRY_COUNT	*/
+	PACKB(2, 2),	/* MBOX_SET_TAG_AGE_LIMIT */
+	PACKB(2, 2),	/* MBOX_SET_CLOCK_RATE */
+	PACKB(2, 2),	/* MBOX_SET_ACTIVE_NEG_STATE */
+	PACKB(2, 2),	/* MBOX_SET_ASYNC_DATA_SETUP_TIME */
+	PACKB(3, 3),	/* MBOX_SET_PCI_CONTROL_PARAMS */
+	PACKB(4, 4),	/* MBOX_SET_TARGET_PARAMS */
+	PACKB(4, 4),	/* MBOX_SET_DEV_QUEUE_PARAMS */
+	PACKB(0, 0),	/* 0x003a */
+	PACKB(0, 0),	/* 0x003b */
+	PACKB(0, 0),	/* 0x003c */
+	PACKB(0, 0),	/* 0x003d */
+	PACKB(0, 0),	/* 0x003e */
+	PACKB(0, 0),	/* 0x003f */
+	PACKB(1, 2),	/* MBOX_RETURN_BIOS_BLOCK_ADDR */
+	PACKB(6, 1),	/* MBOX_WRITE_FOUR_RAM_WORDS */
+	PACKB(2, 3)	/* MBOX_EXEC_BIOS_IOCB */
 };
 
 #define MAX_MBOX_COMMAND	(sizeof(mbox_param)/sizeof(u_short))
 
 struct host_param {
-    u_short    fifo_threshold;
-    u_short    host_adapter_enable;
-    u_short    initiator_scsi_id;
-    u_short    bus_reset_delay;
-    u_short    retry_count;
-    u_short    retry_delay;
-    u_short    async_data_setup_time;
-    u_short    req_ack_active_negation;
-    u_short    data_line_active_negation;
-    u_short    data_dma_burst_enable;
-    u_short    command_dma_burst_enable;
-    u_short    tag_aging;
-    u_short    selection_timeout;
-    u_short    max_queue_depth;
+	u_short		fifo_threshold;
+	u_short		host_adapter_enable;
+	u_short		initiator_scsi_id;
+	u_short		bus_reset_delay;
+	u_short		retry_count;
+	u_short		retry_delay;
+	u_short		async_data_setup_time;
+	u_short		req_ack_active_negation;
+	u_short		data_line_active_negation;
+	u_short		data_dma_burst_enable;
+	u_short		command_dma_burst_enable;
+	u_short		tag_aging;
+	u_short		selection_timeout;
+	u_short		max_queue_depth;
 };
 
 /*
@@ -471,1082 +495,1219 @@
  */
 
 struct dev_param {
-    u_short    device_flags;
-    u_short    execution_throttle;
-    u_short    synchronous_period;
-    u_short    synchronous_offset;
-    u_short    device_enable;
-    u_short    reserved; /* pad */
+	u_short		device_flags;
+	u_short		execution_throttle;
+	u_short		synchronous_period;
+	u_short		synchronous_offset;
+	u_short		device_enable;
+	u_short		reserved; /* pad */
 };
 
-#define REQ_QUEUE_LEN		32
-#define RES_QUEUE_LEN		32
+/*
+ * The result queue can be quite a bit smaller since continuation entries
+ * do not show up there:
+ */
+#define RES_QUEUE_LEN		((QLOGICISP_REQ_QUEUE_LEN + 1) / 8 - 1)
 #define QUEUE_ENTRY_LEN		64
 
 struct isp1020_hostdata {
-    u_int     io_base;
-    u_char    irq;
-    u_char    bus;
-    u_char    revision;
-    u_char    device_fn;
-    u_short   res_queue_in_ptr;
-    u_short   res_queue_out_ptr;
-    u_short   req_queue_in_ptr;
-    u_short   req_queue_out_ptr;
-    struct    host_param host_param;
-    struct    dev_param dev_param[MAX_TARGETS];
-    char      res_queue[RES_QUEUE_LEN][QUEUE_ENTRY_LEN];
-    char      req_queue[REQ_QUEUE_LEN][QUEUE_ENTRY_LEN];
-};
+	u_char	bus;
+	u_char	revision;
+	u_char	device_fn;
+	struct	host_param host_param;
+	struct	dev_param dev_param[MAX_TARGETS];
+	
+	/* result and request queues (shared with isp1020): */
+	u_int	req_in_ptr;		/* index of next request slot */
+	u_int	res_out_ptr;		/* index of next result slot */
 
-struct isp1020_hostdata *irq2host[NR_IRQS];
+	/* this is here so the queues are nicely aligned */
+	long	send_marker;		/* do we need to send a marker? */
 
-void isp1020_enable_irqs(struct isp1020_hostdata *);
-void isp1020_disable_irqs(struct isp1020_hostdata *);
-int isp1020_init(struct Scsi_Host *);
-int isp1020_reset_hardware(struct isp1020_hostdata *);
-int isp1020_get_defaults(struct isp1020_hostdata *);
-int isp1020_set_defaults(struct isp1020_hostdata *);
-int isp1020_load_parameters(struct isp1020_hostdata *);
-int isp1020_mbox_command(struct isp1020_hostdata *, u_short []); 
-u_short isp1020_read_nvram_word(struct isp1020_hostdata *, u_short);
-int isp1020_verify_nvram(struct isp1020_hostdata *);
-void isp1020_print_status_entry(struct Status_Entry *);
-void isp1020_print_scsi_cmd(Scsi_Cmnd *);
-void isp1020_scsi_done(Scsi_Cmnd *);
-int isp1020_return_status(struct Status_Entry *);
-void isp1020_intr_handler(int, void *, struct pt_regs *);
-
-struct proc_dir_entry proc_scsi_isp1020 = {
-    PROC_SCSI_QLOGICISP, 7, "isp1020",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
+	char	res[RES_QUEUE_LEN+1][QUEUE_ENTRY_LEN];
+	char	req[QLOGICISP_REQ_QUEUE_LEN+1][QUEUE_ENTRY_LEN];
 };
 
-int isp1020_detect(Scsi_Host_Template *tmpt)
-{
-    int hosts = 0;
-    u_short index;
-    u_char bus, device_fn;
-    struct Scsi_Host *scsihost;
-    struct isp1020_hostdata *hostdata;
+/* queue length's _must_ be power of two: */
+#define QUEUE_DEPTH(in, out, ql)	((in - out) & (ql))
+#define REQ_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, 		     \
+						    QLOGICISP_REQ_QUEUE_LEN)
+#define RES_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
+
+struct Scsi_Host *irq2host[NR_IRQS];
+
+static void	isp1020_enable_irqs(struct Scsi_Host *);
+static void	isp1020_disable_irqs(struct Scsi_Host *);
+static int	isp1020_init(struct Scsi_Host *);
+static int	isp1020_reset_hardware(struct Scsi_Host *);
+static int	isp1020_set_defaults(struct Scsi_Host *);
+static int	isp1020_load_parameters(struct Scsi_Host *);
+static int	isp1020_mbox_command(struct Scsi_Host *, u_short []); 
+static int	isp1020_return_status(struct Status_Entry *);
+static void	isp1020_intr_handler(int, void *, struct pt_regs *);
+
+#if USE_NVRAM_DEFAULTS
+static int	isp1020_get_defaults(struct Scsi_Host *);
+static int	isp1020_verify_nvram(struct Scsi_Host *);
+static u_short	isp1020_read_nvram_word(struct Scsi_Host *, u_short);
+#endif
+
+#if DEBUG_ISP1020
+static void	isp1020_print_scsi_cmd(Scsi_Cmnd *);
+#endif
+#if DEBUG_ISP1020_INTR
+static void	isp1020_print_status_entry(struct Status_Entry *);
+#endif
 
-    ENTER("isp1020_detect");
+static struct proc_dir_entry proc_scsi_isp1020 = {
+	PROC_SCSI_QLOGICISP, 7, "isp1020",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
 
-    tmpt->proc_dir = &proc_scsi_isp1020;
 
-    if (pcibios_present() == 0) {
-        printk("qlogicisp : PCI bios not present\n");
-        return 0;
-    }
+static inline void isp1020_enable_irqs(struct Scsi_Host *host)
+{
+	outw(ISP_EN_INT|ISP_EN_RISC, host->io_port + PCI_INTF_CTL);
+}
 
-    memset(irq2host, 0, sizeof(irq2host));
 
-    for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC,
-            PCI_DEVICE_ID_QLOGIC_ISP1020, index, &bus, &device_fn) == 0;
-                index++) {
+static inline void isp1020_disable_irqs(struct Scsi_Host *host)
+{
+	outw(0x0, host->io_port + PCI_INTF_CTL);
+}
 
-        scsihost = scsi_register(tmpt, sizeof(struct isp1020_hostdata));
-        hostdata = (struct isp1020_hostdata *) scsihost->hostdata;
 
-        memset(hostdata, 0, sizeof(struct isp1020_hostdata));
-        hostdata->bus = bus;
-        hostdata->device_fn = device_fn;
+int isp1020_detect(Scsi_Host_Template *tmpt)
+{
+	int hosts = 0;
+	u_short index;
+	u_char bus, device_fn;
+	struct Scsi_Host *host;
+	struct isp1020_hostdata *hostdata;
+
+	ENTER("isp1020_detect");
+
+	tmpt->proc_dir = &proc_scsi_isp1020;
+
+	if (pcibios_present() == 0) {
+		printk("qlogicisp : PCI bios not present\n");
+		return 0;
+	}
+
+	memset(irq2host, 0, sizeof(irq2host));
+
+	for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC,
+					    PCI_DEVICE_ID_QLOGIC_ISP1020,
+					    index, &bus, &device_fn) == 0;
+	     index++)
+	{
+		host = scsi_register(tmpt, sizeof(struct isp1020_hostdata));
+		hostdata = (struct isp1020_hostdata *) host->hostdata;
+
+		memset(hostdata, 0, sizeof(struct isp1020_hostdata));
+		hostdata->bus = bus;
+		hostdata->device_fn = device_fn;
 
-        if (isp1020_init(scsihost) || isp1020_reset_hardware(hostdata)
+		if (isp1020_init(host) || isp1020_reset_hardware(host)
 #if USE_NVRAM_DEFAULTS
-                || isp1020_get_defaults(hostdata)
+		    || isp1020_get_defaults(host)
 #else
-                || isp1020_set_defaults(hostdata)
+		    || isp1020_set_defaults(host)
 #endif /* USE_NVRAM_DEFAULTS */
-                || isp1020_load_parameters(hostdata)) {
-            scsi_unregister(scsihost);
-            continue;
-        }
-
-        scsihost->this_id = hostdata->host_param.initiator_scsi_id;
-
-        if (request_irq(hostdata->irq, isp1020_intr_handler, SA_INTERRUPT,
-                "qlogicisp", NULL)) {
-            printk("qlogicisp : interrupt %d already in use\n", hostdata->irq);
-            scsi_unregister(scsihost);
-            continue;
-        }
-
-        if (check_region(hostdata->io_base, 0xff)) {
-            printk("qlogicisp : i/o region 0x%04x-0x%04x already in use\n",
-                hostdata->io_base, hostdata->io_base + 0xff);
-            free_irq(hostdata->irq, NULL);
-            scsi_unregister(scsihost);
-            continue;
-        }
-
-        request_region(hostdata->io_base, 0xff, "qlogicisp");
-        irq2host[hostdata->irq] = hostdata;
-
-        outw(0x0, hostdata->io_base + PCI_SEMAPHORE);
-	outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR);
-        isp1020_enable_irqs(hostdata);
+		    || isp1020_load_parameters(host)) {
+			scsi_unregister(host);
+			continue;
+		}
+
+		host->this_id = hostdata->host_param.initiator_scsi_id;
+
+		if (request_irq(host->irq, isp1020_intr_handler, SA_INTERRUPT,
+				"qlogicisp", NULL))
+		{
+			printk("qlogicisp : interrupt %d already in use\n",
+			       host->irq);
+			scsi_unregister(host);
+			continue;
+		}
+
+		if (check_region(host->io_port, 0xff)) {
+			printk("qlogicisp : i/o region 0x%04x-0x%04x already "
+			       "in use\n",
+			       host->io_port, host->io_port + 0xff);
+			free_irq(host->irq, NULL);
+			scsi_unregister(host);
+			continue;
+		}
+
+		request_region(host->io_port, 0xff, "qlogicisp");
+		irq2host[host->irq] = host;
+
+		outw(0x0, host->io_port + PCI_SEMAPHORE);
+		outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+		isp1020_enable_irqs(host);
 
-        hosts++;
-    }
+		hosts++;
+	}
 
-    LEAVE("isp1020_detect");
+	LEAVE("isp1020_detect");
 
-    return hosts;
+	return hosts;
 }
 
 
 int isp1020_release(struct Scsi_Host *host)
 {
-    struct isp1020_hostdata *hostdata;
+	struct isp1020_hostdata *hostdata;
 
-    ENTER("isp1020_release");
+	ENTER("isp1020_release");
 
-    hostdata = (struct isp1020_hostdata *) host->hostdata;
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
 
-    outw(0x0, hostdata->io_base + PCI_INTF_CTL);
-    free_irq(hostdata->irq, NULL);
+	outw(0x0, host->io_port + PCI_INTF_CTL);
+	free_irq(host->irq, NULL);
 
-    release_region(hostdata->io_base, 0xff);
+	release_region(host->io_port, 0xff);
 
-    LEAVE("isp1020_release");
+	LEAVE("isp1020_release");
 
-    return 0;
+	return 0;
 }
 
 
 const char *isp1020_info(struct Scsi_Host *host)
 {
-    static char buf[80];
-    struct isp1020_hostdata *hostdata;
+	static char buf[80];
+	struct isp1020_hostdata *hostdata;
 
-    ENTER("isp1020_info");
+	ENTER("isp1020_info");
 
-    hostdata = (struct isp1020_hostdata *) host->hostdata;
-    sprintf(buf, "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x",
-	    hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, hostdata->irq,
-	    hostdata->io_base);
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
+	sprintf(buf,
+		"QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x",
+		hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, host->irq,
+		host->io_port);
 
-    LEAVE("isp1020_info");
+	LEAVE("isp1020_info");
 
-    return buf;
+	return buf;
 }
 
 
-#define REQ_QUEUE_DEPTH() \
-    (hostdata->req_queue_in_ptr >= hostdata->req_queue_out_ptr \
-        ? hostdata->req_queue_in_ptr - hostdata->req_queue_out_ptr \
-        : (REQ_QUEUE_LEN - hostdata->req_queue_out_ptr) \
-        + hostdata->req_queue_in_ptr)
-    
-
-int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
+/*
+ * The middle SCSI layer ensures that queuecommand never gets invoked
+ * concurrently with itself or the interrupt handler (though the
+ * interrupt handler may call this routine as part of
+ * request-completion handling).
+ */
+int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
 {
-    int i, *iptr, sg_count;
-    struct scatterlist *sg;
-    struct Command_Entry *cmd;
-    struct isp1020_hostdata *hostdata;
-    unsigned long flags;
-
-    ENTER("isp1020_queuecommand");
+	int i, sg_count, n, num_free;
+	u_int in_ptr, out_ptr;
+	struct dataseg * ds;
+	struct scatterlist *sg;
+	struct Command_Entry *cmd;
+	struct Continuation_Entry *cont;
+	struct Scsi_Host *host;
+	struct isp1020_hostdata *hostdata;
+
+	ENTER("isp1020_queuecommand");
+
+	host = Cmnd->host;
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
+	Cmnd->scsi_done = done;
+
+	DEBUG(isp1020_print_scsi_cmd(Cmnd));
+
+	out_ptr = inw(host->io_port + MBOX4);
+	in_ptr  = hostdata->req_in_ptr;
+
+	DEBUG(printk("qlogicisp : request queue depth %d\n",
+		     REQ_QUEUE_DEPTH(in_ptr, out_ptr)));
+
+	cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0];
+	in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
+	if (in_ptr == out_ptr) {
+		printk("qlogicisp : request queue overflow\n");
+		return 1;
+	}
+
+	if (hostdata->send_marker) {
+		struct Marker_Entry *marker;
+
+		TRACE("queue marker", in_ptr, 0);
+
+		DEBUG(printk("qlogicisp : adding marker entry\n"));
+		marker = (struct Marker_Entry *) cmd;
+		memset(marker, 0, sizeof(struct Marker_Entry));
+
+		marker->hdr.entry_type = ENTRY_MARKER;
+		marker->hdr.entry_cnt = 1;
+		marker->modifier = SYNC_ALL;
+
+		hostdata->send_marker = 0;
+
+		if (((in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN) == out_ptr) {
+			outw(in_ptr, host->io_port + MBOX4);
+			hostdata->req_in_ptr = in_ptr;
+			printk("qlogicisp : request queue overflow\n");
+			return 1;
+		}
+		cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0];
+		in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
+	}
+
+	TRACE("queue command", in_ptr, Cmnd);
+
+	memset(cmd, 0, sizeof(struct Command_Entry));
+
+	cmd->hdr.entry_type = ENTRY_COMMAND;
+	cmd->hdr.entry_cnt = 1;
+
+	cmd->handle = (u_int) virt_to_bus(Cmnd);
+	cmd->target_lun = Cmnd->lun;
+	cmd->target_id = Cmnd->target;
+	cmd->cdb_length = Cmnd->cmd_len;
+	cmd->control_flags = CFLAG_READ | CFLAG_WRITE;
+	cmd->time_out = 30;
+
+	memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
+
+	if (Cmnd->use_sg) {
+		cmd->segment_cnt = sg_count = Cmnd->use_sg;
+		sg = (struct scatterlist *) Cmnd->request_buffer;
+		ds = cmd->dataseg;
+
+		/* fill in first four sg entries: */
+		n = sg_count;
+		if (n > 4)
+			n = 4;
+		for (i = 0; i < n; i++) {
+			ds[i].d_base  = (u_int) virt_to_bus(sg->address);
+			ds[i].d_count = sg->length;
+			++sg;
+		}
+		sg_count -= 4;
+
+		while (sg_count > 0) {
+			++cmd->hdr.entry_cnt;
+			cont = (struct Continuation_Entry *)
+				&hostdata->req[in_ptr][0];
+			in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
+			if (in_ptr == out_ptr) {
+				printk("isp1020: unexpected request queue "
+				       "overflow\n");
+				return 1;
+			}
+			TRACE("queue continuation", in_ptr, 0);
+			cont->hdr.entry_type = ENTRY_CONTINUATION;
+			cont->hdr.entry_cnt  = 0;
+			cont->hdr.sys_def_1  = 0;
+			cont->hdr.flags      = 0;
+			cont->reserved = 0;
+			ds = cont->dataseg;
+			n = sg_count;
+			if (n > 7)
+				n = 7;
+			for (i = 0; i < n; ++i) {
+				ds[i].d_base = (u_int)virt_to_bus(sg->address);
+				ds[i].d_count = sg->length;
+				++sg;
+			}
+			sg_count -= n;
+		}
+	} else {
+		cmd->dataseg[0].d_base =
+			(u_int) virt_to_bus(Cmnd->request_buffer);
+		cmd->dataseg[0].d_count =
+			(u_int) Cmnd->request_bufflen;
+		cmd->segment_cnt = 1;
+	}
+
+	outw(in_ptr, host->io_port + MBOX4);
+	hostdata->req_in_ptr = in_ptr;
+
+	num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
+	host->can_queue = host->host_busy + num_free;
+	host->sg_tablesize = QLOGICISP_MAX_SG(num_free);
 
-    hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata;
-    Cmnd->scsi_done = done;
+	LEAVE("isp1020_queuecommand");
 
-    DEBUG(isp1020_print_scsi_cmd(Cmnd);)
-
-    save_flags(flags);
-    cli();
-
-    hostdata->req_queue_out_ptr = inw(hostdata->io_base + MBOX4);
-
-    if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN ==
-            hostdata->req_queue_out_ptr) {
-        restore_flags(flags);
-        printk("qlogicisp : request queue overflow\n");
-        return 1;
-    }
-
-    DEBUG(printk("qlogicisp : request queue depth %d\n", REQ_QUEUE_DEPTH()));
+	return 0;
+}
 
-    cmd = (struct Command_Entry *)
-        &hostdata->req_queue[hostdata->req_queue_in_ptr][0];
 
-    memset(cmd, 0, sizeof(struct Command_Entry));
+#define ASYNC_EVENT_INTERRUPT	0x01
 
-    cmd->hdr.entry_type = ENTRY_COMMAND;
-    cmd->hdr.entry_cnt = 1;
+void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	Scsi_Cmnd *Cmnd;
+	struct Status_Entry *sts;
+	struct Scsi_Host *host;
+	struct isp1020_hostdata *hostdata;
+	u_int in_ptr, out_ptr;
+	u_short status;
+
+	ENTER_INTR("isp1020_intr_handler");
+
+	host = irq2host[irq];
+	if (!host) {
+		printk("qlogicisp : unexpected interrupt on line %d\n", irq);
+		return;
+	}
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
+
+	DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq));
+
+	if (!(inw(host->io_port + PCI_INTF_STS) & 0x04)) {
+		/* spurious interrupts can happen legally */
+		DEBUG_INTR(printk("qlogicisp: got spurious interrupt\n"));
+		return;
+	}
+	in_ptr = inw(host->io_port + MBOX5);
+	outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+
+	if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) {
+		status = inw(host->io_port + MBOX0);
+
+		DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n",
+				  status));
+
+		switch (status) {
+		      case ASYNC_SCSI_BUS_RESET:
+		      case EXECUTION_TIMEOUT_RESET:
+			hostdata->send_marker = 1;
+			break;
+		      case INVALID_COMMAND:
+		      case HOST_INTERFACE_ERROR:
+		      case COMMAND_ERROR:
+		      case COMMAND_PARAM_ERROR:
+			printk("qlogicisp : bad mailbox return status\n");
+			break;
+		}
+		outw(0x0, host->io_port + PCI_SEMAPHORE);
+	}
+	out_ptr = hostdata->res_out_ptr;
+
+	DEBUG_INTR(printk("qlogicisp : response queue update\n"));
+	DEBUG_INTR(printk("qlogicisp : response queue depth %d\n",
+			  QUEUE_DEPTH(in_ptr, out_ptr)));
+
+	while (out_ptr != in_ptr) {
+		sts = (struct Status_Entry *) &hostdata->res[out_ptr][0];
+		out_ptr = (out_ptr + 1) & RES_QUEUE_LEN;
+
+		Cmnd = (Scsi_Cmnd *) bus_to_virt(sts->handle);
+
+		TRACE("done", out_ptr, Cmnd);
+
+		if (sts->completion_status == CS_RESET_OCCURRED
+		    || sts->completion_status == CS_ABORTED
+		    || (sts->status_flags & STF_BUS_RESET))
+			hostdata->send_marker = 1;
+
+		if (sts->state_flags & SF_GOT_SENSE)
+			memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+			       sizeof(Cmnd->sense_buffer));
+
+		DEBUG_INTR(isp1020_print_status_entry(sts));
+
+		if (sts->hdr.entry_type == ENTRY_STATUS)
+			Cmnd->result = isp1020_return_status(sts);
+		else
+			Cmnd->result = DID_ERROR << 16;
+
+		outw(out_ptr, host->io_port + MBOX5);
+		(*Cmnd->scsi_done)(Cmnd);
+	}
+	hostdata->res_out_ptr = out_ptr;
 
-    cmd->handle = (u_int) virt_to_bus(Cmnd);
-    cmd->target_lun = Cmnd->lun;
-    cmd->target_id = Cmnd->target;
-    cmd->cdb_length = Cmnd->cmd_len;
-    cmd->control_flags = CFLAG_READ | CFLAG_WRITE;
-    cmd->time_out = 30;
+	LEAVE_INTR("isp1020_intr_handler");
+}
 
-    for (i = 0; i < Cmnd->cmd_len; i++)
-        cmd->cdb[i] = Cmnd->cmnd[i];
 
-    if (Cmnd->use_sg) {
-        cmd->segment_cnt = sg_count = Cmnd->use_sg;
-        sg = (struct scatterlist *) Cmnd->request_buffer;
-        iptr = (int *) &cmd->dataseg0.d_base;
+static int isp1020_return_status(struct Status_Entry *sts)
+{
+	int host_status = DID_ERROR;
+#if DEBUG_ISP1020_INTR
+	static char *reason[] = {
+		"DID_OK",
+		"DID_NO_CONNECT",
+		"DID_BUS_BUSY",
+		"DID_TIME_OUT",
+		"DID_BAD_TARGET",
+		"DID_ABORT",
+		"DID_PARITY",
+		"DID_ERROR",
+		"DID_RESET",
+		"DID_BAD_INTR"
+	};
+#endif /* DEBUG_ISP1020_INTR */
 
-        for (i = 0; sg_count > 0; sg_count--, i++) {
-            *iptr++ = (int) virt_to_bus(sg[i].address);
-            *iptr++ = sg[i].length;
-        }
-    }
-    else {
-        cmd->dataseg0.d_base = (u_int) virt_to_bus(Cmnd->request_buffer);
-        cmd->dataseg0.d_count = (u_int) Cmnd->request_bufflen;
-        cmd->segment_cnt = 1;
-    }
+	ENTER("isp1020_return_status");
 
-    hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1)
-        % REQ_QUEUE_LEN;
+	DEBUG(printk("qlogicisp : completion status = 0x%04x\n",
+		     sts->completion_status));
 
-    outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4);
+	switch(sts->completion_status) {
+	      case CS_COMPLETE:
+		host_status = DID_OK;
+		break;
+	      case CS_INCOMPLETE:
+		if (!(sts->state_flags & SF_GOT_BUS))
+			host_status = DID_NO_CONNECT;
+		else if (!(sts->state_flags & SF_GOT_TARGET))
+			host_status = DID_BAD_TARGET;
+		else if (!(sts->state_flags & SF_SENT_CDB))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_TRANSFERRED_DATA))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_GOT_STATUS))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_GOT_SENSE))
+			host_status = DID_ERROR;
+		break;
+	      case CS_DMA_ERROR:
+	      case CS_TRANSPORT_ERROR:
+		host_status = DID_ERROR;
+		break;
+	      case CS_RESET_OCCURRED:
+		host_status = DID_RESET;
+		break;
+	      case CS_ABORTED:
+		host_status = DID_ABORT;
+		break;
+	      case CS_TIMEOUT:
+		host_status = DID_TIME_OUT;
+		break;
+	      case CS_DATA_OVERRUN:
+	      case CS_COMMAND_OVERRUN:
+	      case CS_STATUS_OVERRUN:
+	      case CS_BAD_MESSAGE:
+	      case CS_NO_MESSAGE_OUT:
+	      case CS_EXT_ID_FAILED:
+	      case CS_IDE_MSG_FAILED:
+	      case CS_ABORT_MSG_FAILED:
+	      case CS_NOP_MSG_FAILED:
+	      case CS_PARITY_ERROR_MSG_FAILED:
+	      case CS_DEVICE_RESET_MSG_FAILED:
+	      case CS_ID_MSG_FAILED:
+	      case CS_UNEXP_BUS_FREE:
+		host_status = DID_ERROR;
+		break;
+	      case CS_DATA_UNDERRUN:
+		host_status = DID_OK;
+		break;
+	      default:
+		printk("qlogicisp : unknown completion status 0x%04x\n",
+		       sts->completion_status);
+		host_status = DID_ERROR;
+		break;
+	}
 
-    restore_flags(flags);
+	DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n",
+			  reason[host_status], sts->scsi_status));
 
-    LEAVE("isp1020_queuecommand");
+	LEAVE("isp1020_return_status");
 
-    return 0;
+	return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
 }
 
 
-#define RES_QUEUE_DEPTH() \
-    (hostdata->res_queue_in_ptr >= hostdata->res_queue_out_ptr \
-        ? hostdata->res_queue_in_ptr - hostdata->res_queue_out_ptr \
-        : (RES_QUEUE_LEN - hostdata->res_queue_out_ptr) \
-        + hostdata->res_queue_in_ptr)
- 
-
 int isp1020_abort(Scsi_Cmnd *Cmnd)
 {
-    u_short param[6];
-    struct isp1020_hostdata *hostdata;
-    int return_status = SCSI_ABORT_SUCCESS;
-    u_int cmdaddr = virt_to_bus(Cmnd);
-
-    ENTER("isp1020_abort");
+	u_short param[6];
+	struct Scsi_Host *host;
+	struct isp1020_hostdata *hostdata;
+	int return_status = SCSI_ABORT_SUCCESS;
+	u_int cmdaddr = virt_to_bus(Cmnd);
 
-    hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata;
+	ENTER("isp1020_abort");
 
-    isp1020_disable_irqs(hostdata);
+	host = Cmnd->host;
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
 
-    DEBUG(printk("qlogicisp : response queue depth %d\n", RES_QUEUE_DEPTH()));
+	isp1020_disable_irqs(host);
 
-    param[0] = MBOX_ABORT;
-    param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;
-    param[2] = cmdaddr >> 16;
-    param[3] = cmdaddr & 0xffff;
+	param[0] = MBOX_ABORT;
+	param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;
+	param[2] = cmdaddr >> 16;
+	param[3] = cmdaddr & 0xffff;
 
-    isp1020_mbox_command(hostdata, param);
+	isp1020_mbox_command(host, param);
 
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-        printk("qlogicisp : scsi abort failure: %x\n", param[0]);
-        return_status = SCSI_ABORT_ERROR;
-    }
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : scsi abort failure: %x\n", param[0]);
+		return_status = SCSI_ABORT_ERROR;
+	}
 
-    isp1020_enable_irqs(hostdata);
+	isp1020_enable_irqs(host);
 
-    LEAVE("isp1020_abort");
+	LEAVE("isp1020_abort");
 
-    return return_status;
+	return return_status;
 }
 
 
 int isp1020_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
 {
-    u_short param[6];
-    struct isp1020_hostdata *hostdata;
-    int return_status = SCSI_RESET_SUCCESS;
+	u_short param[6];
+	struct Scsi_Host *host;
+	struct isp1020_hostdata *hostdata;
+	int return_status = SCSI_RESET_SUCCESS;
 
-    ENTER("isp1020_reset");
+	ENTER("isp1020_reset");
 
-    hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata;
+	host = Cmnd->host;
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
 
-    param[0] = MBOX_BUS_RESET;
-    param[1] = hostdata->host_param.bus_reset_delay;
+	param[0] = MBOX_BUS_RESET;
+	param[1] = hostdata->host_param.bus_reset_delay;
 
-    isp1020_disable_irqs(hostdata);
+	isp1020_disable_irqs(host);
 
-    isp1020_mbox_command(hostdata, param);
+	isp1020_mbox_command(host, param);
 
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-        printk("qlogicisp : scsi bus reset failure: %x\n", param[0]);
-        return_status = SCSI_RESET_ERROR;
-    }
-	
-    isp1020_enable_irqs(hostdata);
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : scsi bus reset failure: %x\n", param[0]);
+		return_status = SCSI_RESET_ERROR;
+	}
+
+	isp1020_enable_irqs(host);
 
-    LEAVE("isp1020_reset");
+	LEAVE("isp1020_reset");
 
-    return return_status;;
+	return return_status;;
 }
 
 
 int isp1020_biosparam(Disk *disk, kdev_t n, int ip[])
 {
-    int size = disk->capacity;
+	int size = disk->capacity;
 
-    ENTER("isp1020_biosparam");
+	ENTER("isp1020_biosparam");
 
-    ip[0] = 64;
-    ip[1] = 32;
-    ip[2] = size >> 11;
-    if (ip[2] > 1024) {
-        ip[0] = 255;
-        ip[1] = 63;
-        ip[2] = size / (ip[0] * ip[1]);
-        if (ip[2] > 1023)
-            ip[2] = 1023;
-    }
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+	if (ip[2] > 1024) {
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / (ip[0] * ip[1]);
+		if (ip[2] > 1023)
+			ip[2] = 1023;
+	}
 
-    LEAVE("isp1020_biosparam");
+	LEAVE("isp1020_biosparam");
 
-    return 0;
+	return 0;
 }
 
 
-int isp1020_reset_hardware(struct isp1020_hostdata *hostdata)
+static int isp1020_reset_hardware(struct Scsi_Host *host)
 {
-    u_short param[6];
-    int loop_count;
+	u_short param[6];
+	int loop_count;
 
-    ENTER("isp1020_reset_hardware");
+	ENTER("isp1020_reset_hardware");
 
-    outw(ISP_RESET, hostdata->io_base + PCI_INTF_CTL);
-    outw(HCCR_RESET, hostdata->io_base + HOST_HCCR);
-    outw(HCCR_RELEASE, hostdata->io_base + HOST_HCCR);
-    outw(HCCR_BIOS_DISABLE, hostdata->io_base + HOST_HCCR);
+	outw(ISP_RESET, host->io_port + PCI_INTF_CTL);
+	outw(HCCR_RESET, host->io_port + HOST_HCCR);
+	outw(HCCR_RELEASE, host->io_port + HOST_HCCR);
+	outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR);
 
-    loop_count = DEFAULT_LOOP_COUNT;
-    while (--loop_count && inw(hostdata->io_base + HOST_HCCR) == RISC_BUSY)
-        barrier();
-    if (!loop_count)
-        printk("qlogicisp: reset_hardware loop timeout\n");
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY)
+		barrier();
+	if (!loop_count)
+		printk("qlogicisp: reset_hardware loop timeout\n");
 
-    outw(0, hostdata->io_base + ISP_CFG1);
+	outw(0, host->io_port + ISP_CFG1);
 
 #if DEBUG_ISP1020
-    printk("qlogicisp : mbox 0 0x%04x \n", inw(hostdata->io_base + MBOX0));
-    printk("qlogicisp : mbox 1 0x%04x \n", inw(hostdata->io_base + MBOX1));
-    printk("qlogicisp : mbox 2 0x%04x \n", inw(hostdata->io_base + MBOX2));
-    printk("qlogicisp : mbox 3 0x%04x \n", inw(hostdata->io_base + MBOX3));
-    printk("qlogicisp : mbox 4 0x%04x \n", inw(hostdata->io_base + MBOX4));
-    printk("qlogicisp : mbox 5 0x%04x \n", inw(hostdata->io_base + MBOX5));
+	printk("qlogicisp : mbox 0 0x%04x \n", inw(host->io_port + MBOX0));
+	printk("qlogicisp : mbox 1 0x%04x \n", inw(host->io_port + MBOX1));
+	printk("qlogicisp : mbox 2 0x%04x \n", inw(host->io_port + MBOX2));
+	printk("qlogicisp : mbox 3 0x%04x \n", inw(host->io_port + MBOX3));
+	printk("qlogicisp : mbox 4 0x%04x \n", inw(host->io_port + MBOX4));
+	printk("qlogicisp : mbox 5 0x%04x \n", inw(host->io_port + MBOX5));
 #endif /* DEBUG_ISP1020 */
 
-    DEBUG(printk("qlogicisp : loading risc ram\n");)
+	DEBUG(printk("qlogicisp : loading risc ram\n"));
 
 #if RELOAD_FIRMWARE
-    { int i;
-        for (i = 0; i < risc_code_length01; i++) {
-            param[0] = MBOX_WRITE_RAM_WORD;
-            param[1] = risc_code_addr01 + i;
-            param[2] = risc_code01[i];
-
-            isp1020_mbox_command(hostdata, param);
-
-            if (param[0] != MBOX_COMMAND_COMPLETE) {
-                printk("qlogicisp : firmware load failure\n");
-                return 1;
-            }
-        }
-    }
+	{
+		int i;
+		for (i = 0; i < risc_code_length01; i++) {
+			param[0] = MBOX_WRITE_RAM_WORD;
+			param[1] = risc_code_addr01 + i;
+			param[2] = risc_code01[i];
+
+			isp1020_mbox_command(host, param);
+
+			if (param[0] != MBOX_COMMAND_COMPLETE) {
+				printk("qlogicisp : firmware load failure\n");
+				return 1;
+			}
+		}
+	}
 #endif /* RELOAD_FIRMWARE */
 
-    DEBUG(printk("qlogicisp : verifying checksum\n");)
+	DEBUG(printk("qlogicisp : verifying checksum\n"));
 
-    param[0] = MBOX_VERIFY_CHECKSUM;
-    param[1] = risc_code_addr01;
+	param[0] = MBOX_VERIFY_CHECKSUM;
+	param[1] = risc_code_addr01;
 
-    isp1020_mbox_command(hostdata, param);
+	isp1020_mbox_command(host, param);
 
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-        printk("qlogicisp : ram checksum failure\n");
-        return 1;
-    }
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : ram checksum failure\n");
+		return 1;
+	}
 
-    DEBUG(printk("qlogicisp : executing firmware\n");)
+	DEBUG(printk("qlogicisp : executing firmware\n"));
 
-    param[0] = MBOX_EXEC_FIRMWARE;
-    param[1] = risc_code_addr01;
+	param[0] = MBOX_EXEC_FIRMWARE;
+	param[1] = risc_code_addr01;
 
-    isp1020_mbox_command(hostdata, param);
+	isp1020_mbox_command(host, param);
 
-    param[0] = MBOX_ABOUT_FIRMWARE;
+	param[0] = MBOX_ABOUT_FIRMWARE;
 
-    isp1020_mbox_command(hostdata, param);
+	isp1020_mbox_command(host, param);
 
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-        printk("qlogicisp : about firmware failure\n");
-        return 1;
-    }
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : about firmware failure\n");
+		return 1;
+	}
 
-    DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1]);)
-    DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2]);)
+	DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1]));
+	DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2]));
 
-    LEAVE("isp1020_reset_hardware");
+	LEAVE("isp1020_reset_hardware");
 
-    return 0;
+	return 0;
 }
 
 
-int isp1020_init(struct Scsi_Host *sh)
+static int isp1020_init(struct Scsi_Host *sh)
 {
-    u_int io_base;
-    struct isp1020_hostdata *hostdata;
-    u_char bus, device_fn, revision, irq;
-    u_short vendor_id, device_id, command;
+	u_int io_base;
+	struct isp1020_hostdata *hostdata;
+	u_char bus, device_fn, revision, irq;
+	u_short vendor_id, device_id, command;
 
-    ENTER("isp1020_init");
+	ENTER("isp1020_init");
 
-    hostdata = (struct isp1020_hostdata *) sh->hostdata;
-    bus = hostdata->bus;
-    device_fn = hostdata->device_fn;
+	hostdata = (struct isp1020_hostdata *) sh->hostdata;
+	bus = hostdata->bus;
+	device_fn = hostdata->device_fn;
 
-    if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id)
+	if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id)
             || pcibios_read_config_word(bus, device_fn,
-                PCI_DEVICE_ID, &device_id)
+					PCI_DEVICE_ID, &device_id)
             || pcibios_read_config_word(bus, device_fn,
-                PCI_COMMAND, &command)
+					PCI_COMMAND, &command)
             || pcibios_read_config_dword(bus, device_fn,
-                PCI_BASE_ADDRESS_0, &io_base)
+					 PCI_BASE_ADDRESS_0, &io_base)
 	    || pcibios_read_config_byte(bus, device_fn,
-                PCI_CLASS_REVISION, &revision)
+					PCI_CLASS_REVISION, &revision)
             || pcibios_read_config_byte(bus, device_fn,
-                PCI_INTERRUPT_LINE, &irq)) {
-        printk("qlogicisp : error reading PCI configuration\n");
-        return 1;
-    }
-
-    if (vendor_id != PCI_VENDOR_ID_QLOGIC) {
-        printk("qlogicisp : 0x%04x is not QLogic vendor ID\n", vendor_id);
-        return 1;
-    }
-
-    if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) {
-        printk("qlogicisp : 0x%04x does not match ISP1020 device id\n",
-            device_id);
-        return 1;
-    }
-
-    if (command & PCI_COMMAND_IO && (io_base & 3) == 1)
-        io_base &= PCI_BASE_ADDRESS_IO_MASK;
-    else {
-        printk("qlogicisp : i/o mapping is disabled\n");
-        return 1;
-    }
-
-    if (!(command & PCI_COMMAND_MASTER)) {
-        printk("qlogicisp : bus mastering is disabled\n");
-        return 1;
-    }
-
-    if (revision != ISP1020_REV_ID)
-       printk("qlogicisp : new isp1020 revision ID (%d)\n", revision);
-
-    if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
-            || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) {
-        printk("qlogicisp : can't decode i/o address space\n");
-        return 1;
-    }
-
-    hostdata->io_base = io_base;
-    hostdata->revision = revision;
-    hostdata->irq = irq;
-
-    LEAVE("isp1020_init");
-
-    return 0;
-}
-
-
-int isp1020_get_defaults(struct isp1020_hostdata *hostdata)
-{
-    int i;
-    u_short value;
-
-    ENTER("isp1020_get_defaults");
-
-    if (!isp1020_verify_nvram(hostdata)) {
-        printk("qlogicisp : nvram checksum failure\n");
-        printk("qlogicisp : attempting to use default parameters\n");
-        return isp1020_set_defaults(hostdata);
-    }
-
-    value = isp1020_read_nvram_word(hostdata, 2);
-    hostdata->host_param.fifo_threshold = (value >> 8) & 0x03;
-    hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01;
-    hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f;
-
-    value = isp1020_read_nvram_word(hostdata, 3);
-    hostdata->host_param.bus_reset_delay = value & 0xff;
-    hostdata->host_param.retry_count = value >> 8;
-
-    value = isp1020_read_nvram_word(hostdata, 4);
-    hostdata->host_param.retry_delay = value & 0xff;
-    hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f;
-    hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01;
-    hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01;
-    hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01;
-    hostdata->host_param.command_dma_burst_enable = (value >> 15);
+					PCI_INTERRUPT_LINE, &irq))
+	{
+		printk("qlogicisp : error reading PCI configuration\n");
+		return 1;
+	}
+
+	if (vendor_id != PCI_VENDOR_ID_QLOGIC) {
+		printk("qlogicisp : 0x%04x is not QLogic vendor ID\n",
+		       vendor_id);
+		return 1;
+	}
+
+	if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) {
+		printk("qlogicisp : 0x%04x does not match ISP1020 device id\n",
+		       device_id);
+		return 1;
+	}
+
+	if (command & PCI_COMMAND_IO && (io_base & 3) == 1)
+		io_base &= PCI_BASE_ADDRESS_IO_MASK;
+	else {
+		printk("qlogicisp : i/o mapping is disabled\n");
+		return 1;
+	}
+
+	if (!(command & PCI_COMMAND_MASTER)) {
+		printk("qlogicisp : bus mastering is disabled\n");
+		return 1;
+	}
+
+	if (revision != ISP1020_REV_ID)
+		printk("qlogicisp : new isp1020 revision ID (%d)\n", revision);
+
+	if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
+	    || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020)
+	{
+		printk("qlogicisp : can't decode i/o address space\n");
+		return 1;
+	}
 
-    value = isp1020_read_nvram_word(hostdata, 5);
-    hostdata->host_param.tag_aging = value & 0xff;
+	hostdata->revision = revision;
 
-    value = isp1020_read_nvram_word(hostdata, 6);
-    hostdata->host_param.selection_timeout = value & 0xffff;
+	sh->irq = irq;
+	sh->io_port = io_base;
 
-    value = isp1020_read_nvram_word(hostdata, 7);
-    hostdata->host_param.max_queue_depth = value & 0xffff;
+	LEAVE("isp1020_init");
 
-#if DEBUG_ISP1020_SETUP
-    printk("qlogicisp : fifo threshold=%d\n",
-        hostdata->host_param.fifo_threshold);
-    printk("qlogicisp : initiator scsi id=%d\n",
-        hostdata->host_param.initiator_scsi_id);
-    printk("qlogicisp : bus reset delay=%d\n",
-        hostdata->host_param.bus_reset_delay);
-    printk("qlogicisp : retry count=%d\n",
-	hostdata->host_param.retry_count);
-    printk("qlogicisp : retry delay=%d\n",
-        hostdata->host_param.retry_delay);
-    printk("qlogicisp : async data setup time=%d\n",
-        hostdata->host_param.async_data_setup_time);
-    printk("qlogicisp : req/ack active negation=%d\n",
-        hostdata->host_param.req_ack_active_negation);
-    printk("qlogicisp : data line active negation=%d\n",
-        hostdata->host_param.data_line_active_negation);
-    printk("qlogicisp : data DMA burst enable=%d\n",
-        hostdata->host_param.data_dma_burst_enable);
-    printk("qlogicisp : command DMA burst enable=%d\n",
-        hostdata->host_param.command_dma_burst_enable);
-    printk("qlogicisp : tag age limit=%d\n",
-        hostdata->host_param.tag_aging);
-    printk("qlogicisp : selection timeout limit=%d\n",
-        hostdata->host_param.selection_timeout);
-    printk("qlogicisp : max queue depth=%d\n",
-        hostdata->host_param.max_queue_depth);
-#endif /* DEBUG_ISP1020_SETUP */
-
-    for (i = 0; i < MAX_TARGETS; i++) {
-
-        value = isp1020_read_nvram_word(hostdata, 14 + i * 3);
-        hostdata->dev_param[i].device_flags = value & 0xff;
-        hostdata->dev_param[i].execution_throttle = value >> 8;
-
-        value = isp1020_read_nvram_word(hostdata, 15 + i * 3);
-        hostdata->dev_param[i].synchronous_period = value & 0xff;
-        hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f;
-        hostdata->dev_param[i].device_enable = (value >> 12) & 0x01;
-
-#if DEBUG_ISP1020_SETUP
-        printk("qlogicisp : target 0x%02x\n", i);
-        printk("qlogicisp :     device flags=0x%02x\n",
-            hostdata->dev_param[i].device_flags);
-        printk("qlogicisp :     execution throttle=%d\n",
-            hostdata->dev_param[i].execution_throttle);
-        printk("qlogicisp :     synchronous period=%d\n",
-            hostdata->dev_param[i].synchronous_period);
-        printk("qlogicisp :     synchronous offset=%d\n",
-            hostdata->dev_param[i].synchronous_offset);
-        printk("qlogicisp :     device enable=%d\n",
-            hostdata->dev_param[i].device_enable);
-#endif /* DEBUG_ISP1020_SETUP */
-    }
-
-    LEAVE("isp1020_get_defaults");
-
-    return 0;
+	return 0;
 }
 
 
-int isp1020_set_defaults(struct isp1020_hostdata *hostdata)
-{
-    int i;
-
-    ENTER("isp1020_set_defaults");
-
-    hostdata->host_param.fifo_threshold = 2;
-    hostdata->host_param.host_adapter_enable = 1;
-    hostdata->host_param.initiator_scsi_id = 7;
-    hostdata->host_param.bus_reset_delay = 3;
-    hostdata->host_param.retry_count = 0;
-    hostdata->host_param.retry_delay = 1;
-    hostdata->host_param.async_data_setup_time = 6;
-    hostdata->host_param.req_ack_active_negation = 1;
-    hostdata->host_param.data_line_active_negation = 1;
-    hostdata->host_param.data_dma_burst_enable = 1;
-    hostdata->host_param.command_dma_burst_enable = 1;
-    hostdata->host_param.tag_aging = 8;
-    hostdata->host_param.selection_timeout = 250;
-    hostdata->host_param.max_queue_depth = 256;
-
-    for (i = 0; i < MAX_TARGETS; i++) {
-        hostdata->dev_param[i].device_flags = 0xfd;
-        hostdata->dev_param[i].execution_throttle = 16;
-        hostdata->dev_param[i].synchronous_period = 25;
-        hostdata->dev_param[i].synchronous_offset = 12;
-        hostdata->dev_param[i].device_enable = 1;
-    }
-
-    LEAVE("isp1020_set_defaults");
-
-    return 0;
-}
-
+#if USE_NVRAM_DEFAULTS
 
-int isp1020_load_parameters(struct isp1020_hostdata *hostdata)
+static int isp1020_get_defaults(struct Scsi_Host *host)
 {
-    int i, k;
-    u_int queue_addr;
-    u_short param[6];
-    u_short isp_cfg1;
-    unsigned long flags;
-
-    ENTER("isp1020_load_parameters");
-
-    save_flags(flags);
-    cli();
-
-    outw(hostdata->host_param.fifo_threshold, hostdata->io_base + ISP_CFG1);
-
-    param[0] = MBOX_SET_INIT_SCSI_ID;
-    param[1] = hostdata->host_param.initiator_scsi_id;
+	int i;
+	u_short value;
+	struct isp1020_hostdata *hostdata =
+		(struct isp1020_hostdata *) host->hostdata;
+
+	ENTER("isp1020_get_defaults");
+
+	if (!isp1020_verify_nvram(host)) {
+		printk("qlogicisp : nvram checksum failure\n");
+		printk("qlogicisp : attempting to use default parameters\n");
+		return isp1020_set_defaults(host);
+	}
+
+	value = isp1020_read_nvram_word(host, 2);
+	hostdata->host_param.fifo_threshold = (value >> 8) & 0x03;
+	hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01;
+	hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f;
+
+	value = isp1020_read_nvram_word(host, 3);
+	hostdata->host_param.bus_reset_delay = value & 0xff;
+	hostdata->host_param.retry_count = value >> 8;
+
+	value = isp1020_read_nvram_word(host, 4);
+	hostdata->host_param.retry_delay = value & 0xff;
+	hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f;
+	hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01;
+	hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01;
+	hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01;
+	hostdata->host_param.command_dma_burst_enable = (value >> 15);
 
-    isp1020_mbox_command(hostdata, param);
+	value = isp1020_read_nvram_word(host, 5);
+	hostdata->host_param.tag_aging = value & 0xff;
 
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : set initiator id failure\n");
-        return 1;
-    }
-
-    param[0] = MBOX_SET_RETRY_COUNT;
-    param[1] = hostdata->host_param.retry_count;
-    param[2] = hostdata->host_param.retry_delay;
-
-    isp1020_mbox_command(hostdata, param);
-
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : set retry count failure\n");
-        return 1;
-    }
+	value = isp1020_read_nvram_word(host, 6);
+	hostdata->host_param.selection_timeout = value & 0xffff;
 
-    param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME;
-    param[1] = hostdata->host_param.async_data_setup_time;
+	value = isp1020_read_nvram_word(host, 7);
+	hostdata->host_param.max_queue_depth = value & 0xffff;
 
-    isp1020_mbox_command(hostdata, param);
-
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : async data setup time failure\n");
-        return 1;
-    }
-
-    param[0] = MBOX_SET_ACTIVE_NEG_STATE;
-    param[1] = (hostdata->host_param.req_ack_active_negation << 4)
-        | (hostdata->host_param.data_line_active_negation << 5);
-
-    isp1020_mbox_command(hostdata, param);
-
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : set active negation state failure\n");
-        return 1;
-    }
-
-    param[0] = MBOX_SET_PCI_CONTROL_PARAMS;
-    param[1] = hostdata->host_param.data_dma_burst_enable << 1;
-    param[2] = hostdata->host_param.command_dma_burst_enable << 1;
-
-    isp1020_mbox_command(hostdata, param);
-
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : set pci control parameter failure\n");
-        return 1;
-    }
-
-    isp_cfg1 = inw(hostdata->io_base + ISP_CFG1);
-
-    if (hostdata->host_param.data_dma_burst_enable 
-            || hostdata->host_param.command_dma_burst_enable)
-        isp_cfg1 |= 0x0004;
-    else
-        isp_cfg1 &= 0xfffb;
-
-    outw(isp_cfg1, hostdata->io_base + ISP_CFG1);
-			
-    param[0] = MBOX_SET_TAG_AGE_LIMIT;
-    param[1] = hostdata->host_param.tag_aging;
-
-    isp1020_mbox_command(hostdata, param);
-
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : set tag age limit failure\n");
-        return 1;
-    }
-
-    param[0] = MBOX_SET_SELECT_TIMEOUT;
-    param[1] = hostdata->host_param.selection_timeout;
-
-    isp1020_mbox_command(hostdata, param);
-
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : set selection timeout failure\n");
-        return 1;
-    }
-
-    for (i = 0; i < MAX_TARGETS; i++) {
-
-        if (!hostdata->dev_param[i].device_enable)
-            continue;
-
-        param[0] = MBOX_SET_TARGET_PARAMS;
-        param[1] = i << 8;
-        param[2] = hostdata->dev_param[i].device_flags << 8;
-        param[3] = (hostdata->dev_param[i].synchronous_offset << 8)
-            | hostdata->dev_param[i].synchronous_period;
-
-        isp1020_mbox_command(hostdata, param);
-
-        if (param[0] != MBOX_COMMAND_COMPLETE) {
-	    restore_flags(flags);
-            printk("qlogicisp : set target parameter failure\n");
-            return 1;
-        }
-
-        for (k = 0; k < MAX_LUNS; k++) {
-
-            param[0] = MBOX_SET_DEV_QUEUE_PARAMS;
-            param[1] = (i << 8) | k;
-            param[2] = hostdata->host_param.max_queue_depth;
-            param[3] = hostdata->dev_param[i].execution_throttle;
-
-            isp1020_mbox_command(hostdata, param);
-
-            if (param[0] != MBOX_COMMAND_COMPLETE) {
-	        restore_flags(flags);
-                printk("qlogicisp : set device queue parameter failure\n");
-                return 1;
-            }
-        }
-    }
-
-    queue_addr = (u_int) virt_to_bus(&hostdata->res_queue[0][0]);
-
-    param[0] = MBOX_INIT_RES_QUEUE;
-    param[1] = RES_QUEUE_LEN;
-    param[2] = (u_short) (queue_addr >> 16);
-    param[3] = (u_short) (queue_addr & 0xffff);
-    param[4] = 0;
-    param[5] = 0;
+#if DEBUG_ISP1020_SETUP
+	printk("qlogicisp : fifo threshold=%d\n",
+	       hostdata->host_param.fifo_threshold);
+	printk("qlogicisp : initiator scsi id=%d\n",
+	       hostdata->host_param.initiator_scsi_id);
+	printk("qlogicisp : bus reset delay=%d\n",
+	       hostdata->host_param.bus_reset_delay);
+	printk("qlogicisp : retry count=%d\n",
+	       hostdata->host_param.retry_count);
+	printk("qlogicisp : retry delay=%d\n",
+	       hostdata->host_param.retry_delay);
+	printk("qlogicisp : async data setup time=%d\n",
+	       hostdata->host_param.async_data_setup_time);
+	printk("qlogicisp : req/ack active negation=%d\n",
+	       hostdata->host_param.req_ack_active_negation);
+	printk("qlogicisp : data line active negation=%d\n",
+	       hostdata->host_param.data_line_active_negation);
+	printk("qlogicisp : data DMA burst enable=%d\n",
+	       hostdata->host_param.data_dma_burst_enable);
+	printk("qlogicisp : command DMA burst enable=%d\n",
+	       hostdata->host_param.command_dma_burst_enable);
+	printk("qlogicisp : tag age limit=%d\n",
+	       hostdata->host_param.tag_aging);
+	printk("qlogicisp : selection timeout limit=%d\n",
+	       hostdata->host_param.selection_timeout);
+	printk("qlogicisp : max queue depth=%d\n",
+	       hostdata->host_param.max_queue_depth);
+#endif /* DEBUG_ISP1020_SETUP */
 
-    isp1020_mbox_command(hostdata, param);
+	for (i = 0; i < MAX_TARGETS; i++) {
 
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : set response queue failure\n");
-        return 1;
-    }
+		value = isp1020_read_nvram_word(host, 14 + i * 3);
+		hostdata->dev_param[i].device_flags = value & 0xff;
+		hostdata->dev_param[i].execution_throttle = value >> 8;
+
+		value = isp1020_read_nvram_word(host, 15 + i * 3);
+		hostdata->dev_param[i].synchronous_period = value & 0xff;
+		hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f;
+		hostdata->dev_param[i].device_enable = (value >> 12) & 0x01;
 
-    queue_addr = (u_int) virt_to_bus(&hostdata->req_queue[0][0]);
+#if DEBUG_ISP1020_SETUP
+		printk("qlogicisp : target 0x%02x\n", i);
+		printk("qlogicisp :     device flags=0x%02x\n",
+		       hostdata->dev_param[i].device_flags);
+		printk("qlogicisp :     execution throttle=%d\n",
+		       hostdata->dev_param[i].execution_throttle);
+		printk("qlogicisp :     synchronous period=%d\n",
+		       hostdata->dev_param[i].synchronous_period);
+		printk("qlogicisp :     synchronous offset=%d\n",
+		       hostdata->dev_param[i].synchronous_offset);
+		printk("qlogicisp :     device enable=%d\n",
+		       hostdata->dev_param[i].device_enable);
+#endif /* DEBUG_ISP1020_SETUP */
+	}
 
-    param[0] = MBOX_INIT_REQ_QUEUE;
-    param[1] = REQ_QUEUE_LEN;
-    param[2] = (u_short) (queue_addr >> 16);
-    param[3] = (u_short) (queue_addr & 0xffff);
-    param[4] = 0;
+	LEAVE("isp1020_get_defaults");
 
-    isp1020_mbox_command(hostdata, param);
+	return 0;
+}
 
-    if (param[0] != MBOX_COMMAND_COMPLETE) {
-	restore_flags(flags);
-        printk("qlogicisp : set request queue failure\n");
-        return 1;
-    }
 
-    restore_flags(flags);
+#define ISP1020_NVRAM_LEN	0x40
+#define ISP1020_NVRAM_SIG1	0x5349
+#define ISP1020_NVRAM_SIG2	0x2050
 
-    LEAVE("isp1020_load_parameters");
+static int isp1020_verify_nvram(struct Scsi_Host *host)
+{
+	int	i;
+	u_short value;
+	u_char checksum = 0;
+
+	for (i = 0; i < ISP1020_NVRAM_LEN; i++) {
+		value = isp1020_read_nvram_word(host, i);
+
+		switch (i) {
+		      case 0:
+			if (value != ISP1020_NVRAM_SIG1) return 0;
+			break;
+		      case 1:
+			if (value != ISP1020_NVRAM_SIG2) return 0;
+			break;
+		      case 2:
+			if ((value & 0xff) != 0x02) return 0;
+			break;
+		}
+		checksum += value & 0xff;
+		checksum += value >> 8;
+	}
 
-    return 0;
+	return (checksum == 0);
 }
 
+#define NVRAM_DELAY() udelay(2) /* 2 microsecond delay */
 
-/*
- * currently, this is only called during initialization or abort/reset,
- * at which times interrupts are disabled, so polling is OK, I guess...
- */
-int isp1020_mbox_command(struct isp1020_hostdata *hostdata, u_short param[])
+
+u_short isp1020_read_nvram_word(struct Scsi_Host *host, u_short byte)
 {
-    int loop_count;
+	int i;
+	u_short value, output, input;
 
-    if (mbox_param[param[0]] == 0)
-        return 1;
+	byte &= 0x3f; byte |= 0x0180;
 
-    loop_count = DEFAULT_LOOP_COUNT;
-    while (--loop_count && inw(hostdata->io_base + HOST_HCCR) & 0x0080)
-        barrier();
-    if (!loop_count)
-        printk("qlogicisp: mbox_command loop timeout #1\n");
-
-    switch(mbox_param[param[0]] >> 4) {
-        case 6: outw(param[5], hostdata->io_base + MBOX5);
-        case 5: outw(param[4], hostdata->io_base + MBOX4);
-        case 4: outw(param[3], hostdata->io_base + MBOX3);
-        case 3: outw(param[2], hostdata->io_base + MBOX2);
-        case 2: outw(param[1], hostdata->io_base + MBOX1);
-        case 1: outw(param[0], hostdata->io_base + MBOX0);
-    }
-
-    outw(0x0, hostdata->io_base + PCI_SEMAPHORE);
-    outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR);
-    outw(HCCR_SET_HOST_INTR, hostdata->io_base + HOST_HCCR);
-
-    loop_count = DEFAULT_LOOP_COUNT;
-    while (--loop_count && !(inw(hostdata->io_base + PCI_INTF_STS) & 0x04))
-        barrier();
-    if (!loop_count)
-        printk("qlogicisp: mbox_command loop timeout #2\n");
-
-    loop_count = DEFAULT_LOOP_COUNT;
-    while (--loop_count && inw(hostdata->io_base + MBOX0) == 0x04)
-        barrier();
-    if (!loop_count)
-        printk("qlogicisp: mbox_command loop timeout #3\n");
-
-    switch(mbox_param[param[0]] & 0xf) {
-        case 6: param[5] = inw(hostdata->io_base + MBOX5);
-        case 5: param[4] = inw(hostdata->io_base + MBOX4);
-        case 4: param[3] = inw(hostdata->io_base + MBOX3);
-        case 3: param[2] = inw(hostdata->io_base + MBOX2);
-        case 2: param[1] = inw(hostdata->io_base + MBOX1);
-        case 1: param[0] = inw(hostdata->io_base + MBOX0);
-    }
+	for (i = 8; i >= 0; i--) {
+		output = ((byte >> i) & 0x1) ? 0x4 : 0x0;
+		outw(output | 0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY();
+		outw(output | 0x3, host->io_port + PCI_NVRAM); NVRAM_DELAY();
+		outw(output | 0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY();
+	}
+
+	for (i = 0xf, value = 0; i >= 0; i--) {
+		value <<= 1;
+		outw(0x3, host->io_port + PCI_NVRAM); NVRAM_DELAY();
+		input = inw(host->io_port + PCI_NVRAM); NVRAM_DELAY();
+		outw(0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY();
+		if (input & 0x8) value |= 1;
+	}
 
-    outw(0x0, hostdata->io_base + PCI_SEMAPHORE);
-    outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR);
+	outw(0x0, host->io_port + PCI_NVRAM); NVRAM_DELAY();
 
-    return 0;
+	return value;
 }
 
+#endif /* USE_NVRAM_DEFAULTS */
 
-#define MAILBOX_INTERRUPT	0x01
 
-void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+static int isp1020_set_defaults(struct Scsi_Host *host)
 {
-    Scsi_Cmnd *Cmnd;
-    struct Status_Entry *sts;
-    struct Marker_Entry *marker;
-    u_short status, add_marker = 0;
-    struct isp1020_hostdata *hostdata;
-    int loop_count;
-
-    ENTER_INTR("isp1020_intr_handler");
-
-    if ((hostdata = irq2host[irq]) == NULL) {
-        printk("qlogicisp : unexpected interrupt on line %d\n", irq);
-        return;
-    }
-
-    DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq);)
-
-    loop_count = DEFAULT_LOOP_COUNT;
-    while (--loop_count && !(inw(hostdata->io_base + PCI_INTF_STS) & 0x04))
-        barrier();
-    if (!loop_count)
-        printk("qlogicisp: intr_handler loop timeout\n");
-
-    status = inw(hostdata->io_base + PCI_SEMAPHORE);
-
-    if ((status & MAILBOX_INTERRUPT) == 0) {
+	struct isp1020_hostdata *hostdata =
+		(struct isp1020_hostdata *) host->hostdata;
+	int i;
+
+	ENTER("isp1020_set_defaults");
+
+	hostdata->host_param.fifo_threshold = 2;
+	hostdata->host_param.host_adapter_enable = 1;
+	hostdata->host_param.initiator_scsi_id = 7;
+	hostdata->host_param.bus_reset_delay = 3;
+	hostdata->host_param.retry_count = 0;
+	hostdata->host_param.retry_delay = 1;
+	hostdata->host_param.async_data_setup_time = 6;
+	hostdata->host_param.req_ack_active_negation = 1;
+	hostdata->host_param.data_line_active_negation = 1;
+	hostdata->host_param.data_dma_burst_enable = 1;
+	hostdata->host_param.command_dma_burst_enable = 1;
+	hostdata->host_param.tag_aging = 8;
+	hostdata->host_param.selection_timeout = 250;
+	hostdata->host_param.max_queue_depth = 256;
+
+	for (i = 0; i < MAX_TARGETS; i++) {
+		hostdata->dev_param[i].device_flags = 0xfd;
+		hostdata->dev_param[i].execution_throttle = 16;
+		hostdata->dev_param[i].synchronous_period = 25;
+		hostdata->dev_param[i].synchronous_offset = 12;
+		hostdata->dev_param[i].device_enable = 1;
+	}
+
+	LEAVE("isp1020_set_defaults");
+
+	return 0;
+}
 
-        hostdata->res_queue_in_ptr = inw(hostdata->io_base + MBOX5);
-	outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR);
 
-        DEBUG_INTR(printk("qlogicisp : response queue update\n");)
-        DEBUG_INTR(printk("qlogicisp : response queue depth %d\n",
-            RES_QUEUE_DEPTH());)
+static int isp1020_load_parameters(struct Scsi_Host *host)
+{
+	int i, k;
+	u_int queue_addr;
+	u_short param[6];
+	u_short isp_cfg1;
+	unsigned long flags;
+	struct isp1020_hostdata *hostdata =
+		(struct isp1020_hostdata *) host->hostdata;
 
-        while (hostdata->res_queue_out_ptr != hostdata->res_queue_in_ptr) {
+	ENTER("isp1020_load_parameters");
 
-            sts = (struct Status_Entry *)
-                &hostdata->res_queue[hostdata->res_queue_out_ptr][0];
+	save_flags(flags);
+	cli();
 
-            Cmnd = (Scsi_Cmnd *) bus_to_virt(sts->handle);
+	outw(hostdata->host_param.fifo_threshold, host->io_port + ISP_CFG1);
 
-            if (sts->completion_status == CS_RESET_OCCURRED
-                    || sts->completion_status == CS_ABORTED
-                    || (sts->status_flags & STF_BUS_RESET))
-                add_marker++;
+	param[0] = MBOX_SET_INIT_SCSI_ID;
+	param[1] = hostdata->host_param.initiator_scsi_id;
 
-            if (sts->state_flags & SF_GOT_SENSE)
-                memcpy(Cmnd->sense_buffer, sts->req_sense_data,
-		       sizeof(Cmnd->sense_buffer));
+	isp1020_mbox_command(host, param);
 
-            DEBUG_INTR(isp1020_print_status_entry(sts);)
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : set initiator id failure\n");
+		return 1;
+	}
 
-            if (sts->hdr.entry_type == ENTRY_STATUS)
-                Cmnd->result = isp1020_return_status(sts);
-            else
-                Cmnd->result = DID_ERROR << 16;
+	param[0] = MBOX_SET_RETRY_COUNT;
+	param[1] = hostdata->host_param.retry_count;
+	param[2] = hostdata->host_param.retry_delay;
 
-            hostdata->res_queue_out_ptr = (hostdata->res_queue_out_ptr + 1)
-                % RES_QUEUE_LEN;
+	isp1020_mbox_command(host, param);
 
-            outw(hostdata->res_queue_out_ptr, hostdata->io_base + MBOX5);
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : set retry count failure\n");
+		return 1;
+	}
 
-            (Cmnd->scsi_done)(Cmnd);
-        }
-    }
-    else {
+	param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME;
+	param[1] = hostdata->host_param.async_data_setup_time;
 
-        status = inw(hostdata->io_base + MBOX0);
+	isp1020_mbox_command(host, param);
 
-        DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n", status);)
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : async data setup time failure\n");
+		return 1;
+	}
 
-        switch (status) {
-            case ASYNC_SCSI_BUS_RESET:
-            case EXECUTION_TIMEOUT_RESET:
-                add_marker++;
-                break;
-            case INVALID_COMMAND:
-            case HOST_INTERFACE_ERROR:
-            case COMMAND_ERROR:
-            case COMMAND_PARAM_ERROR:
-                printk("qlogicisp : bad mailbox return status\n");
-                break;
-        }
+	param[0] = MBOX_SET_ACTIVE_NEG_STATE;
+	param[1] = (hostdata->host_param.req_ack_active_negation << 4)
+		| (hostdata->host_param.data_line_active_negation << 5);
 
-        outw(0x0, hostdata->io_base + PCI_SEMAPHORE);
-	outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR);
-    }
+	isp1020_mbox_command(host, param);
 
-    if (add_marker) {
-#if 0
-        unsigned long flags;
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : set active negation state failure\n");
+		return 1;
+	}
 
-	save_flags(flags);
-	cli();
-#endif
+	param[0] = MBOX_SET_PCI_CONTROL_PARAMS;
+	param[1] = hostdata->host_param.data_dma_burst_enable << 1;
+	param[2] = hostdata->host_param.command_dma_burst_enable << 1;
 
-        DEBUG_INTR(printk("qlogicisp : adding marker entry\n");)
+	isp1020_mbox_command(host, param);
 
-        if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN
-                == hostdata->req_queue_out_ptr) {
-#if 0
-	    restore_flags(flags);
-#endif
-            printk("qlogicisp : request queue overflow\n");
-            return;
-        }
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : set pci control parameter failure\n");
+		return 1;
+	}
 
-        marker = (struct Marker_Entry *)
-            &hostdata->req_queue[hostdata->req_queue_in_ptr][0];
+	isp_cfg1 = inw(host->io_port + ISP_CFG1);
 
-        memset(marker, 0, sizeof(struct Marker_Entry));
-
-        marker->hdr.entry_type = ENTRY_MARKER;
-        marker->hdr.entry_cnt = 1;
-        marker->modifier = SYNC_ALL;
-
-        hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1)
-            % REQ_QUEUE_LEN;
-
-        outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4);
+	if (hostdata->host_param.data_dma_burst_enable 
+            || hostdata->host_param.command_dma_burst_enable)
+		isp_cfg1 |= 0x0004;
+	else
+		isp_cfg1 &= 0xfffb;
+
+	outw(isp_cfg1, host->io_port + ISP_CFG1);
+
+	param[0] = MBOX_SET_TAG_AGE_LIMIT;
+	param[1] = hostdata->host_param.tag_aging;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : set tag age limit failure\n");
+		return 1;
+	}
+
+	param[0] = MBOX_SET_SELECT_TIMEOUT;
+	param[1] = hostdata->host_param.selection_timeout;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : set selection timeout failure\n");
+		return 1;
+	}
+
+	for (i = 0; i < MAX_TARGETS; i++) {
+
+		if (!hostdata->dev_param[i].device_enable)
+			continue;
+
+		param[0] = MBOX_SET_TARGET_PARAMS;
+		param[1] = i << 8;
+		param[2] = hostdata->dev_param[i].device_flags << 8;
+		param[3] = (hostdata->dev_param[i].synchronous_offset << 8)
+			| hostdata->dev_param[i].synchronous_period;
+
+		isp1020_mbox_command(host, param);
+
+		if (param[0] != MBOX_COMMAND_COMPLETE) {
+			restore_flags(flags);
+			printk("qlogicisp : set target parameter failure\n");
+			return 1;
+		}
+
+		for (k = 0; k < MAX_LUNS; k++) {
+
+			param[0] = MBOX_SET_DEV_QUEUE_PARAMS;
+			param[1] = (i << 8) | k;
+			param[2] = hostdata->host_param.max_queue_depth;
+			param[3] = hostdata->dev_param[i].execution_throttle;
+
+			isp1020_mbox_command(host, param);
+
+			if (param[0] != MBOX_COMMAND_COMPLETE) {
+				restore_flags(flags);
+				printk("qlogicisp : set device queue "
+				       "parameter failure\n");
+				return 1;
+			}
+		}
+	}
+
+	queue_addr = (u_int) virt_to_bus(&hostdata->res[0][0]);
+
+	param[0] = MBOX_INIT_RES_QUEUE;
+	param[1] = RES_QUEUE_LEN + 1;
+	param[2] = (u_short) (queue_addr >> 16);
+	param[3] = (u_short) (queue_addr & 0xffff);
+	param[4] = 0;
+	param[5] = 0;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : set response queue failure\n");
+		return 1;
+	}
+
+	queue_addr = (u_int) virt_to_bus(&hostdata->req[0][0]);
+
+	param[0] = MBOX_INIT_REQ_QUEUE;
+	param[1] = QLOGICISP_REQ_QUEUE_LEN + 1;
+	param[2] = (u_short) (queue_addr >> 16);
+	param[3] = (u_short) (queue_addr & 0xffff);
+	param[4] = 0;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		restore_flags(flags);
+		printk("qlogicisp : set request queue failure\n");
+		return 1;
+	}
 
-#if 0
 	restore_flags(flags);
-#endif
-    }
 
-    isp1020_enable_irqs(hostdata);
+	LEAVE("isp1020_load_parameters");
 
-    LEAVE_INTR("isp1020_intr_handler");
+	return 0;
 }
 
 
-#define NVRAM_DELAY() udelay(2) /* 2 microsecond delay */
-
-
-u_short isp1020_read_nvram_word(struct isp1020_hostdata *hostdata, u_short byte)
-{
-    int i;
-    u_short value, output, input;
-
-    byte &= 0x3f; byte |= 0x0180;
-
-    for (i = 8; i >= 0; i--) {
-        output = ((byte >> i) & 0x1) ? 0x4 : 0x0;
-        outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
-        outw(output | 0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
-        outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
-    }
-
-    for (i = 0xf, value = 0; i >= 0; i--) {
-        value <<= 1;
-        outw(0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
-        input = inw(hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
-        outw(0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
-        if (input & 0x8) value |= 1;
-    }
-
-    outw(0x0, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY();
-
-    return(value);
-}
-
-#define ISP1020_NVRAM_LEN	0x40
-#define ISP1020_NVRAM_SIG1	0x5349
-#define ISP1020_NVRAM_SIG2	0x2050
-
-int isp1020_verify_nvram(struct isp1020_hostdata *hostdata)
+/*
+ * currently, this is only called during initialization or abort/reset,
+ * at which times interrupts are disabled, so polling is OK, I guess...
+ */
+static int isp1020_mbox_command(struct Scsi_Host *host, u_short param[])
 {
-    int	i;
-    u_short value;
-    u_char checksum = 0;
-
-    for (i = 0; i < ISP1020_NVRAM_LEN; i++) {
-        value = isp1020_read_nvram_word(hostdata, i);
-
-        switch (i) {
-            case 0:
-                if (value != ISP1020_NVRAM_SIG1) return 0;
-                break;
-            case 1:
-                if (value != ISP1020_NVRAM_SIG2) return 0;
-                break;
-            case 2:
-                if ((value & 0xff) != 0x02) return 0;
-                break;
-        }
-        checksum += value & 0xff;
-        checksum += value >> 8;
-    }
-
-    return (checksum == 0);
-}
+	int loop_count;
 
+	if (mbox_param[param[0]] == 0)
+		return 1;
 
-void isp1020_enable_irqs(struct isp1020_hostdata *hostdata)
-{
-    outw(ISP_EN_INT|ISP_EN_RISC, hostdata->io_base + PCI_INTF_CTL);
-}
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080)
+		barrier();
+	if (!loop_count)
+		printk("qlogicisp: mbox_command loop timeout #1\n");
+
+	switch(mbox_param[param[0]] >> 4) {
+	      case 6: outw(param[5], host->io_port + MBOX5);
+	      case 5: outw(param[4], host->io_port + MBOX4);
+	      case 4: outw(param[3], host->io_port + MBOX3);
+	      case 3: outw(param[2], host->io_port + MBOX2);
+	      case 2: outw(param[1], host->io_port + MBOX1);
+	      case 1: outw(param[0], host->io_port + MBOX0);
+	}
+
+	outw(0x0, host->io_port + PCI_SEMAPHORE);
+	outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+	outw(HCCR_SET_HOST_INTR, host->io_port + HOST_HCCR);
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && !(inw(host->io_port + PCI_INTF_STS) & 0x04))
+		barrier();
+	if (!loop_count)
+		printk("qlogicisp: mbox_command loop timeout #2\n");
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && inw(host->io_port + MBOX0) == 0x04)
+		barrier();
+	if (!loop_count)
+		printk("qlogicisp: mbox_command loop timeout #3\n");
+
+	switch(mbox_param[param[0]] & 0xf) {
+	      case 6: param[5] = inw(host->io_port + MBOX5);
+	      case 5: param[4] = inw(host->io_port + MBOX4);
+	      case 4: param[3] = inw(host->io_port + MBOX3);
+	      case 3: param[2] = inw(host->io_port + MBOX2);
+	      case 2: param[1] = inw(host->io_port + MBOX1);
+	      case 1: param[0] = inw(host->io_port + MBOX0);
+	}
 
+	outw(0x0, host->io_port + PCI_SEMAPHORE);
+	outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
 
-void isp1020_disable_irqs(struct isp1020_hostdata *hostdata)
-{
-    outw(0x0, hostdata->io_base + PCI_INTF_CTL);
+	return 0;
 }
 
 
@@ -1554,20 +1715,20 @@
 
 void isp1020_print_status_entry(struct Status_Entry *status)
 {
-    int i;
+	int i;
 
-    printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n",
-        status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
-    printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n",
-        status->scsi_status, status->completion_status);
-    printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n",
-        status->state_flags, status->status_flags);
-    printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n",
-        status->time, status->req_sense_len);
-    printk("qlogicisp : residual transfer length = 0x%08x\n", status->residual);
+	printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n",
+	       status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
+	printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n",
+	       status->scsi_status, status->completion_status);
+	printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n",
+	       status->state_flags, status->status_flags);
+	printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n",
+	       status->time, status->req_sense_len);
+	printk("qlogicisp : residual transfer length = 0x%08x\n", status->residual);
 
-    for (i = 0; i < status->req_sense_len; i++)
-        printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]);
+	for (i = 0; i < status->req_sense_len; i++)
+		printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]);
 }
 
 #endif /* DEBUG_ISP1020_INTR */
@@ -1577,105 +1738,18 @@
 
 void isp1020_print_scsi_cmd(Scsi_Cmnd *cmd)
 {
-    int i;
+	int i;
 
-    printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
-	cmd->target, cmd->lun, cmd->cmd_len);
-    printk("qlogicisp : command = ");
-    for (i = 0; i < cmd->cmd_len; i++)
-        printk("0x%02x ", cmd->cmnd[i]);
-    printk("\n");
+	printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
+	       cmd->target, cmd->lun, cmd->cmd_len);
+	printk("qlogicisp : command = ");
+	for (i = 0; i < cmd->cmd_len; i++)
+		printk("0x%02x ", cmd->cmnd[i]);
+	printk("\n");
 }
 
 #endif /* DEBUG_ISP1020 */
 
-
-int isp1020_return_status(struct Status_Entry *sts)
-{
-    int host_status = DID_ERROR;
-#if DEBUG_ISP1020_INTR
-    static char *reason[] = {
-        "DID_OK",
-        "DID_NO_CONNECT",
-        "DID_BUS_BUSY",
-        "DID_TIME_OUT",
-        "DID_BAD_TARGET",
-        "DID_ABORT",
-        "DID_PARITY",
-        "DID_ERROR",
-        "DID_RESET",
-        "DID_BAD_INTR"
-    };
-#endif /* DEBUG_ISP1020_INTR */
-
-    ENTER("isp1020_return_status");
-
-    DEBUG(printk("qlogicisp : completion status = 0x%04x\n",
-        sts->completion_status);)
-
-    switch(sts->completion_status) {
-        case CS_COMPLETE:
-            host_status = DID_OK;
-            break;
-        case CS_INCOMPLETE:
-            if (!(sts->state_flags & SF_GOT_BUS))
-                host_status = DID_NO_CONNECT;
-            else if (!(sts->state_flags & SF_GOT_TARGET))
-                host_status = DID_BAD_TARGET;
-            else if (!(sts->state_flags & SF_SENT_CDB))
-                host_status = DID_ERROR;
-            else if (!(sts->state_flags & SF_TRANSFERRED_DATA))
-                host_status = DID_ERROR;
-            else if (!(sts->state_flags & SF_GOT_STATUS))
-                host_status = DID_ERROR;
-            else if (!(sts->state_flags & SF_GOT_SENSE))
-                host_status = DID_ERROR;
-                break;
-        case CS_DMA_ERROR:
-        case CS_TRANSPORT_ERROR:
-            host_status = DID_ERROR;
-            break;
-        case CS_RESET_OCCURRED:
-            host_status = DID_RESET;
-            break;
-        case CS_ABORTED:
-            host_status = DID_ABORT;
-            break;
-        case CS_TIMEOUT:
-            host_status = DID_TIME_OUT;
-            break;
-        case CS_DATA_OVERRUN:
-        case CS_COMMAND_OVERRUN:
-        case CS_STATUS_OVERRUN:
-        case CS_BAD_MESSAGE:
-        case CS_NO_MESSAGE_OUT:
-        case CS_EXT_ID_FAILED:
-        case CS_IDE_MSG_FAILED:
-        case CS_ABORT_MSG_FAILED:
-        case CS_NOP_MSG_FAILED:
-        case CS_PARITY_ERROR_MSG_FAILED:
-        case CS_DEVICE_RESET_MSG_FAILED:
-        case CS_ID_MSG_FAILED:
-        case CS_UNEXP_BUS_FREE:
-            host_status = DID_ERROR;
-            break;
-        case CS_DATA_UNDERRUN:
-            host_status = DID_OK;
-            break;
-        default:
-            printk("qlogicisp : unknown completion status 0x%04x\n",
-                sts->completion_status);
-            host_status = DID_ERROR;
-            break;
-    }
-
-    DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n",
-        reason[host_status], sts->scsi_status);)
-
-    LEAVE("isp1020_return_status");
-
-    return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
-}
 
 #ifdef MODULE
 Scsi_Host_Template driver_template = QLOGICISP;
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/qlogicisp.h linux/drivers/scsi/qlogicisp.h
--- v2.0.0/linux/drivers/scsi/qlogicisp.h	Wed Jun  5 10:41:28 1996
+++ linux/drivers/scsi/qlogicisp.h	Mon Jul  1 20:06:05 1996
@@ -43,6 +43,21 @@
 #ifndef _QLOGICISP_H
 #define _QLOGICISP_H
 
+/*
+ * With the qlogic interface, every queue slot can hold a SCSI
+ * command with up to 4 scatter/gather entries.  If we need more
+ * than 4 entries, continuation entries can be used that hold
+ * another 7 entries each.  Unlike for other drivers, this means
+ * that the maximum number of scatter/gather entries we can
+ * support at any given time is a function of the number of queue
+ * slots available.  That is, host->can_queue and host->sg_tablesize
+ * are dynamic and _not_ independent.  This all works fine because
+ * requests are queued serially and the scatter/gather limit is
+ * determined for each queue request anew.
+ */
+#define QLOGICISP_REQ_QUEUE_LEN	63	/* must be power of two - 1 */
+#define QLOGICISP_MAX_SG(ql)	(4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
+
 int isp1020_detect(Scsi_Host_Template *);
 int isp1020_release(struct Scsi_Host *);
 const char * isp1020_info(struct Scsi_Host *);
@@ -57,28 +72,28 @@
 
 extern struct proc_dir_entry proc_scsi_isp1020;
 
-#define QLOGICISP {					\
-	/* next */		NULL,			\
-	/* usage_count */	NULL,			\
-        /* proc dir */          NULL,                   \
-        /* procfs info */       NULL,                   \
-	/* name */		NULL,			\
-	/* detect */		isp1020_detect,		\
-	/* release */		isp1020_release,	\
-	/* info */		isp1020_info,		\
-	/* command */		NULL,		 	\
-	/* queuecommand */	isp1020_queuecommand,	\
-	/* abort */		isp1020_abort,		\
-	/* reset */		isp1020_reset,		\
-	/* slave_attach */	NULL,			\
-	/* bios_param */	isp1020_biosparam,	\
-	/* can_queue */		8,			\
-	/* this_id */		-1,			\
-	/* sg_tablesize */	4,			\
-	/* cmd_per_lun */	1,			\
-	/* present */		0,			\
-	/* unchecked_isa_dma */	0,			\
-	/* use_clustering */	DISABLE_CLUSTERING	\
+#define QLOGICISP {							   \
+	/* next */		NULL,					   \
+	/* usage_count */	NULL,					   \
+	/* proc dir */		NULL,					   \
+	/* procfs info */	NULL,					   \
+	/* name */		NULL,					   \
+	/* detect */		isp1020_detect,				   \
+	/* release */		isp1020_release,			   \
+	/* info */		isp1020_info,				   \
+	/* command */		NULL,					   \
+	/* queuecommand */	isp1020_queuecommand,			   \
+	/* abort */		isp1020_abort,				   \
+	/* reset */		isp1020_reset,				   \
+	/* slave_attach */	NULL,					   \
+	/* bios_param */	isp1020_biosparam,			   \
+	/* can_queue */		QLOGICISP_REQ_QUEUE_LEN,		   \
+	/* this_id */		-1,					   \
+	/* sg_tablesize */	QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
+	/* cmd_per_lun */	1,					   \
+	/* present */		0,					   \
+	/* unchecked_isa_dma */	0,					   \
+	/* use_clustering */	DISABLE_CLUSTERING			   \
 }
 
 #endif /* _QLOGICISP_H */
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.0.0/linux/drivers/scsi/scsi.c	Sun Jun  9 13:28:46 1996
+++ linux/drivers/scsi/scsi.c	Mon Jul  1 20:14:55 1996
@@ -1184,27 +1184,38 @@
 
 inline void internal_cmnd (Scsi_Cmnd * SCpnt)
 {
-    int temp;
+    unsigned long flags, timeout;
     struct Scsi_Host * host;
-    unsigned int flags;
 #ifdef DEBUG_DELAY
-    int clock;
+    unsigned long clock;
 #endif
     
     host = SCpnt->host;
     
-    /*
-     * We will wait MIN_RESET_DELAY clock ticks after the last reset so
-     * we can avoid the drive not being ready.
-     */
     save_flags(flags);
     cli();
     /* Assign a unique nonzero serial_number. */
     if (++serial_number == 0) serial_number = 1;
     SCpnt->serial_number = serial_number;
-    sti();
-    temp = host->last_reset + MIN_RESET_DELAY;
-    while (jiffies < temp);
+
+    /*
+     * We will wait MIN_RESET_DELAY clock ticks after the last reset so
+     * we can avoid the drive not being ready.
+     */
+    timeout = host->last_reset + MIN_RESET_DELAY;
+    if (jiffies < timeout) {
+        /*
+         * NOTE: This may be executed from within an interrupt
+         * handler!  This is bad, but for now, it'll do.  The irq
+         * level of the interrupt handler has been masked out by the
+         * platform dependent interrupt handling code already, so the
+         * sti() here will not cause another call to the SCSI host's
+         * interrupt handler (assuming there is one irq-level per
+         * host).
+         */
+        sti();
+        while (jiffies < timeout) barrier();
+    }
     restore_flags(flags);
     
     update_timeout(SCpnt, SCpnt->timeout_per_command);
@@ -1245,15 +1256,16 @@
     }
     else
     {
-	
+	int temp;
+
 #ifdef DEBUG
 	printk("command() :  routine at %p\n", host->hostt->command);
 #endif
-	temp=host->hostt->command (SCpnt);
+	temp = host->hostt->command (SCpnt);
 	SCpnt->result = temp;
 #ifdef DEBUG_DELAY
 	clock = jiffies + 4 * HZ;
-	while (jiffies < clock);
+	while (jiffies < clock) barrier();
 	printk("done(host = %d, result = %04x) : routine at %p\n", 
 	       host->host_no, temp, host->hostt->command);
 #endif
@@ -2055,10 +2067,11 @@
 	 * Protect against races here.  If the command is done, or we are
 	 * on a different command forget it.
 	 */
-	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+	if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
+	  if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
 	    restore_flags(flags);
 	    return 0;
-	}
+	  }
 
 	if (SCpnt->internal_timeout & IN_RESET)
 	{
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.0.0/linux/drivers/scsi/scsi.h	Thu Jun  6 17:42:36 1996
+++ linux/drivers/scsi/scsi.h	Wed Jun 26 11:05:26 1996
@@ -202,7 +202,7 @@
  *  Use these to separate status msg and our bytes
  */
 
-#define status_byte(result) (((result) >> 1) & 0xf)
+#define status_byte(result) (((result) >> 1) & 0x1f)
 #define msg_byte(result)    (((result) >> 8) & 0xff)
 #define host_byte(result)   (((result) >> 16) & 0xff)
 #define driver_byte(result) (((result) >> 24) & 0xff)
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.0.0/linux/drivers/scsi/sg.c	Sun May  5 08:52:02 1996
+++ linux/drivers/scsi/sg.c	Wed Jul  3 10:12:26 1996
@@ -230,7 +230,7 @@
      * Now copy the result back to the user buffer.
      */
     device->header.pack_len=device->header.reply_len;
-    device->header.result=0;
+
     if (count>=sizeof(struct sg_header))
     {
 	memcpy_tofs(buf,&device->header,sizeof(struct sg_header));
@@ -242,7 +242,7 @@
 	}
     }
     else
-	count=0;
+	count= device->header.result==0 ? 0 : -EIO;
     
     /*
      * Clean up, and release the device so that we can send another
@@ -276,12 +276,7 @@
      * wrong.
      */
     memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
-    if (SCpnt->sense_buffer[0])
-    {
-	device->header.result=EIO;
-    }
-    else
-	device->header.result=SCpnt->result;
+    device->header.result=SCpnt->result;
 
     /*
      * Now wake up the process that is waiting for the
@@ -593,6 +588,11 @@
 	    gpnt->device = NULL;
 	    SDp->attached--;
 	    sg_template.nr_dev--;
+            /* 
+             * avoid associated device /dev/sg? bying incremented 
+             * each time module is inserted/removed , <dan@lectra.fr>
+             */
+            sg_template.dev_noticed--;
 	    return;
 	}
     return;
diff -u --recursive --new-file v2.0.0/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.0.0/linux/drivers/scsi/st.c	Mon May 20 08:21:03 1996
+++ linux/drivers/scsi/st.c	Mon Jul  1 07:08:27 1996
@@ -11,7 +11,7 @@
   Copyright 1992 - 1996 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Tue May 14 17:58:12 1996 by makisara@kai.makisara.fi
+  Last modified: Sun Jun 30 15:26:23 1996 by root@kai.makisara.fi
   Some small formal changes - aeb, 950809
 */
 
@@ -143,6 +143,8 @@
   }
 #endif
   scode = sense[2] & 0x0f;
+
+#if !DEBUG
   if (!(driver_byte(result) & DRIVER_SENSE) ||
       ((sense[0] & 0x70) == 0x70 &&
        scode != NO_SENSE &&
@@ -152,15 +154,14 @@
        scode != VOLUME_OVERFLOW &&
        SCpnt->data_cmnd[0] != MODE_SENSE &&
        SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
-#if !DEBUG
     if (driver_byte(result) & DRIVER_SENSE) {
       printk(KERN_WARNING "st%d: Error with sense data: ", dev);
       print_sense("st", SCpnt);
     }
     else
       printk(KERN_WARNING "st%d: Error %x.\n", dev, result);
-#endif
   }
+#endif
 
   if ((sense[0] & 0x70) == 0x70 &&
       scode == RECOVERED_ERROR
@@ -172,7 +173,7 @@
     scsi_tapes[dev].recover_count++;
     scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT);
 #if DEBUG
-    if (debugging) {  /* This is compiled always on purpose */
+    if (debugging) {
       if (SCpnt->data_cmnd[0] == READ_6)
 	stp = "read";
       else if (SCpnt->data_cmnd[0] == WRITE_6)
@@ -380,16 +381,17 @@
       return (-EBUSY);
 
     if ((STp->buffer)->last_result_fatal != 0) {
-      printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt));
       if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 	  (SCpnt->sense_buffer[2] & 0x40) &&
-	  (SCpnt->sense_buffer[2] & 0x0f) != VOLUME_OVERFLOW) {
+	  (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) {
 	STp->dirty = 0;
 	(STp->buffer)->buffer_bytes = 0;
 	result = (-ENOSPC);
       }
-      else
+      else {
+	printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt));
 	result = (-EIO);
+      }
       STp->drv_block = (-1);
     }
     else {
@@ -455,7 +457,8 @@
       result = st_int_ioctl(inode, MTBSR, backspace);
   }
   else if ((STp->eof == ST_FM) && !STp->eof_hit) {
-    (STp->mt_status)->mt_fileno++;
+    if ((STp->mt_status)->mt_fileno >= 0)
+      (STp->mt_status)->mt_fileno++;
     STp->drv_block = 0;
   }
 
@@ -832,7 +835,13 @@
 
 	SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
 
-	if ((STp->buffer)->last_result_fatal != 0)
+	if ((STp->buffer)->last_result_fatal != 0 &&
+	    ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
+	     (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
+	     ((SCpnt->sense_buffer[0] & 0x80) != 0 &&
+	      (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] |
+	       SCpnt->sense_buffer[5] |
+	       SCpnt->sense_buffer[6]) == 0)))  /* Filter out successful write at EOM */
 	  printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
 	else {
 	  if ((STp->mt_status)->mt_fileno >= 0)
@@ -1266,6 +1275,9 @@
 #endif
 	  if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
 
+	    if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
+		SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
+
 	    if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
 
 	      if ((SCpnt->sense_buffer[0] & 0x80) != 0)
@@ -1309,31 +1321,31 @@
 		  SCpnt = NULL;
 		}
 	      }
-	      else if (SCpnt->sense_buffer[2] & 0x40) {
-		STp->eof = ST_EOM_OK;
+	      else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */
+		STp->eof = ST_FM;
 		if (STp->block_size == 0)
-		  (STp->buffer)->buffer_bytes = bytes - transfer;
+		  (STp->buffer)->buffer_bytes = 0;
 		else
 		  (STp->buffer)->buffer_bytes =
 		    bytes - transfer * STp->block_size;
 #if DEBUG
 		if (debugging)
-		  printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", dev,
-			 (STp->buffer)->buffer_bytes);
+		  printk(ST_DEB_MSG
+		    "st%d: EOF detected (%d bytes read, transferred %d bytes).\n",
+			 dev, (STp->buffer)->buffer_bytes, total);
 #endif
 	      }
-	      else if (SCpnt->sense_buffer[2] & 0x80) {
-		STp->eof = ST_FM;
+	      else if (SCpnt->sense_buffer[2] & 0x40) {
+		STp->eof = ST_EOM_OK;
 		if (STp->block_size == 0)
-		  (STp->buffer)->buffer_bytes = 0;
+		  (STp->buffer)->buffer_bytes = bytes - transfer;
 		else
 		  (STp->buffer)->buffer_bytes =
 		    bytes - transfer * STp->block_size;
 #if DEBUG
 		if (debugging)
-		  printk(ST_DEB_MSG
-		    "st%d: EOF detected (%d bytes read, transferred %d bytes).\n",
-			 dev, (STp->buffer)->buffer_bytes, total);
+		  printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", dev,
+			 (STp->buffer)->buffer_bytes);
 #endif
 	      }
 	    } /* end of EOF, EOM, ILI test */
@@ -1409,7 +1421,7 @@
 	    (STp->mt_status)->mt_fileno++;
 	}
 	if (total == 0 && STp->eof == ST_EOM_OK)
-	  return (-EIO);  /* ST_EOM_ERROR not used in read */
+	  return (-ENOSPC);  /* ST_EOM_ERROR not used in read */
 	return total;
       }
 
@@ -1677,7 +1689,7 @@
 
   SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
   STp->compression_changed = TRUE;
-  return 0;  /* Not implemented yet */
+  return 0;
 }
 
 
@@ -2085,7 +2097,16 @@
 	  (SCpnt->sense_buffer[4] << 16) +
 	  (SCpnt->sense_buffer[5] << 8) +
 	  SCpnt->sense_buffer[6] );
-     if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) {
+     if (cmd_in == MTWEOF &&
+       (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+       (SCpnt->sense_buffer[2] & 0x4f) == 0x40 &&
+       ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) {
+       ioctl_result = 0;  /* EOF written succesfully at EOM */
+       if (fileno >= 0)
+	 fileno++;
+       (STp->mt_status)->mt_fileno = fileno;
+     }
+     else if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) {
        if (fileno >= 0)
 	 (STp->mt_status)->mt_fileno = fileno - undone ;
        else
@@ -2518,11 +2539,13 @@
        if (STp->eof_hit) {
 	 if (mtc.mt_op == MTFSF || mtc.mt_op == MTEOM) {
 	   mtc.mt_count -= 1;
-	   (STp->mt_status)->mt_fileno += 1;
+	   if ((STp->mt_status)->mt_fileno >= 0)
+	     (STp->mt_status)->mt_fileno += 1;
 	 }
 	 else if (mtc.mt_op == MTBSF) {
 	   mtc.mt_count += 1;
-	   (STp->mt_status)->mt_fileno += 1;
+	   if ((STp->mt_status)->mt_fileno >= 0)
+	     (STp->mt_status)->mt_fileno += 1;
 	 }
        }
 
@@ -2670,6 +2693,9 @@
        (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff);
      if (STps->at_sm)
        (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff);
+     if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
+	 STp->drv_buffer != 0)
+       (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff);
 
      memcpy_tofs((char *)arg, (char *)(STp->mt_status),
 		 sizeof(struct mtget));
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/.blurb linux/drivers/sound/.blurb
--- v2.0.0/linux/drivers/sound/.blurb	Sun Mar 24 22:49:48 1996
+++ linux/drivers/sound/.blurb	Sun Jun 30 11:43:44 1996
@@ -1,8 +1,9 @@
 *********************************************************
 * Readme.cards (this directory) contains some card	*
 * specific instructions.				*
-* See http://personal.eunet.fi/pp/voxware for most up   *
+* See http://www.4front-tech.com/usslite for most up    *
 * to date info.                                         *
+* (European mirror http://personal.eunet.fi/pp/voxware) *
 *							*
 * DON'T USE PROGRAMS FROM SND_UTIL PACKAGE EARLIER THAN *
 * snd-util-3.5 WITH THIS SOUND DRIVER VERSION.          *
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/.object_files linux/drivers/sound/.object_files
--- v2.0.0/linux/drivers/sound/.object_files	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/.object_files	Sun Jun 30 11:50:18 1996
@@ -0,0 +1,35 @@
+audio.o
+dmabuf.o
+opl3.o
+sequencer.o
+midibuf.o
+sb_card.o
+pas2_card.o
+adlib_card.o
+pas2_pcm.o
+pas2_mixer.o
+pas2_midi.o
+gus_card.o
+gus_wave.o
+mpu401.o
+gus_midi.o
+gus_vol.o
+patmgr.o
+sb_mixer.o
+sb_common.o
+midi_synth.o
+uart6850.o
+uart401.o
+sound_timer.o
+sb_midi.o
+sb_audio.o
+sys_timer.o
+ics2101.o
+ad1848.o
+pss.o
+sscape.o
+trix.o
+aedsp16.o
+mad16.o
+cs4232.o
+maui.o
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/.objects linux/drivers/sound/.objects
--- v2.0.0/linux/drivers/sound/.objects	Sun Mar 24 22:51:44 1996
+++ linux/drivers/sound/.objects	Sun Jun 30 11:50:25 1996
@@ -29,7 +29,7 @@
 endif
 
 ifdef CONFIG_MAD16
-	OBJS := $(OBJS)  mad16.o mad16_sb_midi.o
+	OBJS := $(OBJS)  mad16.o
 endif
 
 ifdef CONFIG_MAUI
@@ -65,11 +65,11 @@
 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 sb16_dsp.o
-	OBJS := $(OBJS)  sb_midi.o
-	OBJS := $(OBJS)  sb_mixer.o
+	OBJS := $(OBJS) sb_card.o 
+endif
+
+ifdef CONFIG_SBDSP
+	OBJS := $(OBJS) sb_common.o sb_audio.o sb_mixer.o sb_midi.o
 endif
 
 ifdef CONFIG_SEQUENCER
@@ -94,4 +94,8 @@
 
 ifdef CONFIG_UART6850
 	OBJS := $(OBJS)  uart6850.o
+endif
+
+ifdef CONFIG_UART401
+	OBJS := $(OBJS)  uart401.o
 endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/.version linux/drivers/sound/.version
--- v2.0.0/linux/drivers/sound/.version	Sun Mar 31 00:13:17 1996
+++ linux/drivers/sound/.version	Sun Jun 30 11:43:44 1996
@@ -1,2 +1,2 @@
-3.5.2
-0x030500
+3.5.5-beta1
+0x030504
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v2.0.0/linux/drivers/sound/CHANGELOG	Tue May  7 16:22:34 1996
+++ linux/drivers/sound/CHANGELOG	Sun Jun 30 11:43:44 1996
@@ -1,10 +1,63 @@
-Changelog for version 3.5.2
+Changelog for version 3.5.4
 ---------------------------
 
+Since 3.5.4-beta8
+- Fixed a bug in handling of non-fragment sized writes in 16 bit/stereo mode
+  with GUS.
+- Limited minimum fragment size with some audio devices (GUS=512 and
+  SB=32). These devices require more time to "recover" from processing
+  of each fragment. 
+
+Since 3.5.4-beta6/7
+- There seems to be problems in the OPTi 82C930 so cards based on this
+  chip don't necessarily work yet. There are problems in detecting the 
+  MIDI interface. Also mixer volumes may be seriously wrong on some systems.
+  You can safely use this driver version with C930 if it looks to work.
+  However please don't complain if you have problems with it. C930 support
+  should be fixed in future releases.
+- Got initialization of GUS PnP to work. With this version GUS PnP should
+  work in GUS compatible mode after initialization using isapnptools.
+- Fixed a bug in handling of full duplex cards in write only mode. This has
+  been causing "audio device opening" errors with RealAudio player.
+
+Since 3.5.4.beta5
+- Changes to OPTi 82C930 driver.
+- Major changes to the Soundscape driver. The driver requires now just one
+  DMA channel. The extra audio/dsp device (the "Not functional" one) used
+  for code download in the earlier versions has been eliminated. There is now
+  just one /dev/dsp# device which is used both for code download and audio.
+
+Since 3.5.4.beta4
+- Minor changes.
+
+Since 3.5.4-beta2
+- Fixed silent playback with ESS 688/1688.
+- Got SB16 to work without the 16 bit DMA channel (only the 8 bit one
+  is required for 8 and 16 bit modes).
+- Added the "lowlevel" subdirectory for additional low level drivers that
+  are not part of USS core. See lowlevel/README for more info.
+- Included support for ACI mixer (by Markus Kuhn). ACI is a mixer used in
+  miroPCM soundcards. See lowlevel/aci.readme for more info.
+- Support for Aztech Washington chipset (AZT2316 ASIC).
+
+Since 3.5.4-beta1
+- Reduced clicking with AD1848.
+- Support for OPTi 82C930. Only half duplex at this time. 16 bit playback
+  is sometimes just white noise (occurs randomly).
+
+Since 3.5.2
+- Major changes to the SB/Jazz16/ESS driver (most parts rewritten).
+  The most noticeable new feature is support for multiple SB cards at the same
+  time.
+- Renamed sb16_midi.c to uart401.c. Also modified it to work also with
+  other MPU401 UART compatible cards than SB16/ESS/Jazz.
+- Some changes which reduce clicking in audio playback.
+- Copying policy is now GPL.
+
 Since 3.5.1
 - TB Maui initialization support
 Since 3.5
-- Improved handling of playback underrun situations.
+- Improved handling of playback underrunt situations.
 
 Since 3.5-beta10
 - Bug fixing
@@ -82,7 +135,7 @@
 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 synchronizing dsp/audio devices with /dev/sequencer.
+- Added support for syncronizing dsp/audio devices with /dev/sequencer.
 - mmap() support for dsp/audio devices.
 
 Since 3.5-alpha5
@@ -106,13 +159,13 @@
 - Fixed random protection fault in gus_wave.c
 
 Since 3.5-alpha1
-- Modified to work with Linux-1.3.33 and later
+- Modified to work with Linux-1.3.33 and leater
 - Some minor changes
 
 Since 3.0.2
 - Support for CS4232 based PnP cards (AcerMagic S23 etc).
 - Full duplex support for some CS4231, CS4232 and AD1845 based cards
-(GUS MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards
+(GUA MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards
 having a codec mentioned above).
 - Almost fully rewritten loadable modules support.
 - Fixed some bugs.
@@ -255,7 +308,7 @@
 
 Since 2.1
 - Preliminary support for SB16. 
-  - The SB16 mixer is supported in its native mode.
+  - The SB16 mixer is supported in it's native mode.
   - Digitized voice capability up to 44.1 kHz/8 bit/mono
     (16 bit and stereo support coming in the next release).
 - Fixed some bugs in the digitized voice driver for PAS16.
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/COPYING linux/drivers/sound/COPYING
--- v2.0.0/linux/drivers/sound/COPYING	Sun Mar 24 22:49:45 1996
+++ linux/drivers/sound/COPYING	Sun Jun 30 11:43:45 1996
@@ -1,25 +1,339 @@
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <linux/config.h>
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
 
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.0.0/linux/drivers/sound/Config.in	Wed Jun  5 10:41:29 1996
+++ linux/drivers/sound/Config.in	Sun Jun 30 11:46:03 1996
@@ -2,11 +2,16 @@
 # Sound driver configuration
 #
 #--------
-# There is another config script which is compatible with rest of
+# There is another confic script which is compatible with rest of
 # the kernel. It can be activated by running 'make mkscript' in this
 # directory. Please note that this is an _experimental_ feature which
-# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro).
+# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
 #--------
 #
 $MAKE -C drivers/sound config || exit 1
 
+bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
+
+if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
+   bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER
+fi
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Config.std linux/drivers/sound/Config.std
--- v2.0.0/linux/drivers/sound/Config.std	Fri Apr 12 15:52:02 1996
+++ linux/drivers/sound/Config.std	Sun Jun 30 11:46:03 1996
@@ -2,11 +2,16 @@
 # Sound driver configuration
 #
 #--------
-# There is another config script which is compatible with rest of
+# There is another confic script which is compatible with rest of
 # the kernel. It can be activated by running 'make mkscript' in this
 # directory. Please note that this is an _experimental_ feature which
-# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro).
+# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
 #--------
 #
 $MAKE -C drivers/sound config || exit 1
 
+bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
+
+if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
+   bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER
+fi
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.0.0/linux/drivers/sound/Makefile	Sun Jun  9 13:28:46 1996
+++ linux/drivers/sound/Makefile	Sun Jun 30 11:43:41 1996
@@ -5,6 +5,8 @@
 #
 #
 
+.PHONY: dummy
+SUB_DIRS	= lowlevel
 VERSION		= `head -1 .version`
 TARGET_OS	= linux
 USRINCDIR	= /usr/include
@@ -12,17 +14,15 @@
 
 FIXEDOBJS	= soundcard.o dev_table.o sound_switch.o
 
+ifndef NO_LOWLEVEL
+	FIXEDOBJS := $(FIXEDOBJS) lowlevel/lowlevel.o
+endif
+
 ifeq (.defines,$(wildcard .defines))
 include .defines
 include .objects
 else
-OBJS   = audio.o dmabuf.o sb_dsp.o \
-	 opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \
-	 pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \
-	 gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o \
-	 sb16_midi.o midi_synth.o uart6850.o sound_timer.o \
-	 sys_timer.o ics2101.o ad1848.o pss.o sscape.o trix.o aedsp16.o \
-	 mad16.o mad16_sb_midi.o cs4232.o maui.o
+OBJS   = `cat .object_files`
 endif
 
 ifndef TOPDIR
@@ -59,7 +59,7 @@
 #
 CC	= gcc
 HOSTCC	= gcc
-CFLAGS	= -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486
+CFLAGS	= -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -pipe -m486
 USE_DEPEND=y
 else
 include $(TOPDIR)/Rules.make
@@ -72,7 +72,8 @@
 
 clean:
 	rm -f core core.* *.o *.a tmp_make *~ x y z *%
-	rm -f configure sound_stub.c objects/*.o
+	rm -f configure sound_stub.c objects/*.o 
+	cd lowlevel;make clean
 
 indent:
 	for n in *.c;do echo indent $$n;indent $$n;done
@@ -85,9 +86,9 @@
 	@echo
 	@echo
 	@echo
-	@echo "NOTE! Object file dependencies may not be up to date. Run"
-	@echo "make again if kernel/driver doesn't link properly. Restarting"
-	@echo "it now may save some time."
+	@echo NOTE! Object file dependencies may not be up to date. Run
+	@echo make again if kernel/driver doesn''t link properly. Restarting
+	@echo it now may save some time.
 	@echo
 	@echo
 
@@ -108,7 +109,9 @@
 #	@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) configure
+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
@@ -117,13 +120,16 @@
 #	@echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null
 	@echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h
 
-mkscript: setup-$(TARGET_OS) configure
+mkscript: setup-$(TARGET_OS)
+	rm -f configure
+	$(HOSTCC) -o configure configure.c
 	./configure script > Config.in
+	cat lowlevel/Config.tmpl >> 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
+	rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h maui_boot.h .defines
 
 configure: configure.c
 	$(HOSTCC) -o configure configure.c
@@ -142,6 +148,9 @@
 modules: local.h sound.o
 	ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o
 
+
+lowlevel/lowlevel.o: dummy
+		cd lowlevel;make
 
 ifdef USE_DEPEND
 #
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v2.0.0/linux/drivers/sound/Readme	Fri Apr 12 15:52:02 1996
+++ linux/drivers/sound/Readme	Sun Jun 30 11:43:42 1996
@@ -1,9 +1,9 @@
-Version 3.5.2 release notes
---------------------------------
+USS Lite version 3.5.4 release notes
+------------------------------------
 
 Most up to date information about this driver is available from 
-http://personal.eunet.fi/pp/voxware.
-
+http://www.4front-tech.com/usslite or http://personal.eunet.fi/pp/voxware
+(european mirror).
 
 
 
@@ -12,18 +12,20 @@
 date but still very useful. Information about bug fixes and such things
 is available from the web page (see below).
 
-New Programmer's Guide is currently under work (Feb/March 96). Please
-check http://personal.eunet.fi/pp/voxware for more info.
+New Programmer's Guide is currently under work (June/July 96). Please
+check http://www.4front-tech.com/pguide for more info.
 
    ====================================================
 -  THIS VERSION ____REQUIRES____ Linux 1.3.70 OR LATER.
    ====================================================
 
 It's very likely that this driver version is incompatible with
-Linux versions later than 2.x.
+Linux versions later than 2.0.x.
 
 Packages "snd-util-3.5.tar.gz" and "snd-data-0.1.tar.Z"
-contain useful utilities to be used with this driver.
+contain usefull utilities to be used with this driver.
+See http://www.4front-tech.com/usslite/getting.html for
+download instructions.
 
 If you are looking for the installation instructions, please
 look at Readme.linux.
@@ -33,14 +35,14 @@
 
 See Readme.cards.
 
-Please check http://personal.eunet.fi/pp/voxware if you don't find
+Please check http://www.4front-tech.com/usslite if you don't find
 your soundcard there.
 
 Contributors
 ------------
 
 This driver contains code by several contributors. In addition several other
-persons have given useful suggestions. The following is a list of major
+persons have given usefull suggestions. The following is a list of major
 contributors. (I could have forgotten some names.)
 
 	Craig Metz	1/2 of the PAS16 Mixer and PCM support
@@ -53,9 +55,9 @@
 	Jim Lowe,
 	Amancio Hasty Jr	FreeBSD/NetBSD port
 	Anders Baekgaard 	Bughunting and valuable suggestions.
-	Joerg Schubert	SB16 DSP support.
+	Joerg Schubert	SB16 DSP support (initial version).
 	Andrew Robinson Improvements to the GUS driver
-	Megens SA	MIDI recording for SB and SB Pro.
+	Megens SA	MIDI recording for SB and SB Pro (initial version).
 	Mikael Nordqvist  Linear volume support for GUS and
 			  nonblocking /dev/sequencer.
 	Ian Hartas		SVR4.2 port
@@ -63,16 +65,18 @@
 	Risto Kankkunen		Major contributions to the mixer support
 				of GUS v3.7.
 	Hunyue Yau	Mixer support for SG NX Pro.
-	Marc Hoffman	PSS support.
-	Rainer Vranken	Initialization for Jazz16 (ProSonic, MV3D, SM Wave).
+	Marc Hoffman	PSS support (initial version).
+	Rainer Vranken	Initialization for Jazz16 (initial version).
 	Peter Trattler	Initial version of loadable module support for Linux.
-	JRA Gibson	16 bit mode for Jazz16
-	Davor Jadrijevic MAD16 support
-	Gregor Hoffleit	Mozart support
+	JRA Gibson	16 bit mode for Jazz16 (initial version)
+	Davor Jadrijevic MAD16 support (initial version)
+	Gregor Hoffleit	Mozart support (initial version)
 	Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support
 	James Hightower Spotting a tiny but important bug in CS423x support.
+	
+	Please look at lowlevel/README for more contributors.
 
-There are probably many other names missing. If you have sent me some
+There are propably many other names missing. If you have sent me some
 patches and your name is not in the above list, please inform me.
 
 Sponsors etc.
@@ -84,7 +88,7 @@
 Novell, Inc.		UnixWare personal edition + SDK
 The Santa Cruz Operation, Inc. 	A SCO OpenServer + SDK
 Ensoniq Corp,		a SoundScape card and extensive amount of assistance
-MediaTriX Peripherals Inc, a AudioTriX Pro card + SDK
+MediaTrix Peripherals Inc, a AudioTrix Pro card + SDK
 Acer, Inc.		a pair of AcerMagic S23 cards.
 
 In addition the following companies have provided me sufficient amount
@@ -99,6 +103,8 @@
 Integrated Circuit Systems Inc.
 OAK Technology
 OPTi
+Turtle Beach
+miro
 Ad Lib Inc. ($$)
 Music Quest Inc. ($$)
 Creative Labs ($$$)
@@ -107,7 +113,7 @@
 =========================
 
 Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?).
-Also look at the home page (http://personal.eunet.fi/pp/voxware). It may
+Also look at the home page (http://www.4front-tech.com/usslite). It may
 contain info about some recent bug fixes.
 
 It's likely that you have some problems when trying to use the sound driver
@@ -119,7 +125,7 @@
 at /var/adm/messages for more verbose error message.
 
 
-In general the easiest way to diagnose problems is to do "cat /dev/sndstat".
+In general the easiest way to diagnoze problems is to do "cat /dev/sndstat".
 
 If you get an error message, there are some problems with the driver setup:
 
@@ -127,7 +133,7 @@
 	the sound driver are missing. Use the script at the end of
 	linux/drivers/sound/Readme.linux to create them.
 
-	- "No such device" shows that the sound driver is not in the kernel.
+	- "No such device" telss that the sound driver is not in the kernel.
 	You have to reconfigure and recompile the kernel to have the sound
 	driver. Compiling the driver doesn't help alone. You have to boot
 	with the newly compiled one before the driver becomes active.
@@ -142,7 +148,7 @@
 	this particular device. For example /dev/audio and /dev/dsp will not
 	work if "digitized voice support" was not enabled during "make config".
 	
-	- "Device or resource busy". Probably the IRQ (or DMA) channel 
+	- "Device or resource busy". Propably the IRQ (or DMA) channel 
 	required by the soundcard is in use by some other device/driver.
 
 	- "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict.
@@ -161,8 +167,8 @@
 Hannu
 
 Hannu Savolainen
-hannu@voxware.pp.fi	
-(Please check http:/personal.eunet.fi/pp/voxware before mailing me).
+hannu@voxware.pp.fi, hannu@4front-tech.com	
+(Please check http://www.4front-tech.com/usslite before mailing me).
 
 Snail mail:	Hannu Savolainen
 		Hiekkalaiturintie 3 A 8
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v2.0.0/linux/drivers/sound/Readme.cards	Tue May  7 16:22:34 1996
+++ linux/drivers/sound/Readme.cards	Wed Jul  3 10:12:18 1996
@@ -1,40 +1,57 @@
-Configuring version 3.5 (for Linux) with some most common soundcards
-====================================================================
+Configuring version 3.5.4 (for Linux) with some most common soundcards
+======================================================================
 
 IMPORTANT!	This document covers only cards that were "known" when
 		this driver version was released. Please look at
-		http://personal.eunet.fi/pp/voxware for info about
+		http://www.4front-tech.com/usslite for info about
 		cards introduced recently.
 
+		The following covers mainly the "old" configuration
+		method (make config). Most of it is valid for the "new"
+		configuration (make menuconfig/xconfig) too.
+
+		Cards having some kind of loadable "microcode" such as
+		PSS, SM Wave, AudioTrix Pro and Maui/Tropez must be
+		configured using the old method. The new one will not 
+		work with them.
+
+		When using make xconfig and/or make menuconfig, you should
+		carefully check each sound configuration option (particularily
+		"Support for /dev/dsp and /dev/ausio").
+
 Cards that are not (fully) supported by this driver
 ---------------------------------------------------
 
 There are many soundcards which don't work with this driver
 version (v3.5). Support for some of them is expected to be
 available during/after summer 1996 (in version 3.6). Please check
-http://personal.eunet.fi/pp/voxware for latest news. Please don't
+http://www.4front-tech.com/usslite for latest news. Please don't
 mail me and ask about these cards. The unsupported cards are:
 
 	- All PnP soundcards (SB PnP, GUS PnP, Soundscape PnP etc.)
-		(SB PnP in first 3.6-alpha version (Apr 96?), GUS PnP bit later,
-		Soundscape PnP probably much later, others ???). See
-	 	"Configuring PnP soundcards" below for some hints.
+		Schecule for availability of PnP soundcard support in
+		USS/Lite depends on progress made by kernel PnP team
+		(propably in Linux 2.1.xx versions). With Linux 2.0.x
+		versions there are two ways to get PnP soundcards to work:
+	 	- Use isapnptools, DOS, Win95 or PnP aware BIOS to wake up the
+		card before starting the sound driver. See "Configuring PnP 
+		soundcards" below for some hints.
+		- Support for SB PnP and GUS PnP is present in USS/Linux (the
+		commercial version of this driver).
 	- Mwave soundcards and motherboards
-		(Version 3.6 or 3.7. Depends on how fast I get a Mwave
-		card and suitable documents for it).
+		(Version 3.6 or 3.7. Depends on how fast I get
+		suitable documents for Mwave).
 	- Emu8k (SB 32/AWE)
-		(Probably not before Nov/Dec 96. I know the unofficial
+		(Propably not _before_ summer 97. I know the unofficial
 		AWE programmers guide so don't send me more copies of it).
 	- Diamond Edge 3D
 		(ASAP. In practice this may take relatively long time).
 	- Compaq Deskpro
-		(Version 3.6???)
-	- Miro soundcards
-		(Early 3.6-alpha versions)
-	- OPTi 82C930 based soundcards
-		(Early 3.6-alpha versions?)
+		(Version 3.5.4-beta6 (already released))
 	- Sound Galaxy Washington/Waverider
-		(3.6-alpha versions. Can't promise the waverider synth).
+		(Audio features already in USS/Linux (USS/Lite soon). 
+		Can't promise the waverider synth since
+		availability of chip specs is uncertain).
 	- Yamaha OPL4 (on cards having _RAM_ for samples)
 		(Late 96?. Works as OPL3 with current driver versions)
 
@@ -52,7 +69,7 @@
 soft configuring their I/O, IRQ, DMA and shared memory resources.
 Currently at least cards made by Creative Technology (SB32 and SB32AWE
 PnP), Gravis (GUS PnP and GUS PnP Pro), Ensoniq (Soundscape PnP) and
-Aztech (some Sound Galaxy models) use PnP technology. The CS4232 audio
+Aztech (some Sound Galazy models) use PnP technology. The CS4232 audio
 chip by Crystal Semiconductor (Intel Atlantis, HP Pavillon and many other
 motherboards) is also based on PnP technology but there is a "native" driver
 available for it (see information about CS4232 later in this document).
@@ -60,7 +77,7 @@
 PnP soundcards (as well as most other PnP ISA cards) are not supported
 by version 3.5 of this driver (Linux 1.3.xx and Linux 2.0.x). Proper
 support for them should be released during spring 96 
-(see http://personal.eunet.fi/pp/voxware for latest info).
+(see http://www.4front-tech.com/usslite for latest info).
 
 There is a method to get most of the PnP cards to work. The basic method
 is the following:
@@ -76,7 +93,7 @@
 your card for more info.
 
 Windows 95 could work as well as DOS but running loadlin may be somehow 
-difficult. Probably you should "shut down" your machine to MS-DOS mode
+difficult. Propably you should "shut down" your machine to MS-DOS mode
 before running it.
 
 Some machines have BIOS utility for setting PnP resources. This is a good
@@ -87,7 +104,11 @@
 of such tool available from ftp://ftp.demon.co.uk/pub/unix/linux/utils. The
 file is called isapnptools-*. Please note that this tool is just a temporary
 solution which may be incompatible with future kernel versions having proper
-support for PnP cards.
+support for PnP cards. There are bugs in setting DMA channels in earlier
+versions of isapnptools so at least version 1.6 is required with soundcards.
+You can find latest version of isapnptools from
+ftp://ftp.demon.co.uk/pub/unix/linux/utils/
+
 These two methods don't work with GUS PnP which requires some additional
 initialization (cards DOS/Win95 driver does it). 
 
@@ -154,7 +175,7 @@
 	(AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor).
 	Currently most soundcards are based on one of the MSS compatible codec
 	chips. The CS4231 is used in the high quality cards such as GUS MAX,
-	MediaTriX AudioTriX Pro and TB Tropez (GUS MAX is not MSS compatible). 
+	MediaTrix AudioTrix Pro and TB Tropez (GUS MAX is not MSS compatible). 
 
 	Having a AD1848, CS4248 or CS4231 codec chip on the card is a good
 	sign. Even if the card is not MSS compatible, it could be easy to write
@@ -177,7 +198,7 @@
 	voices than the OPL2. The OPL4 is a new chip that has an OPL3 and
 	a wave table synthesizer packed onto the same chip. The driver supports
 	just the OPL3 mode directly. Most cards with an OPL4 (like
-	SM Wave and AudioTriX Pro) support the OPL4 mode using MPU401
+	SM Wave and AudioTrix Pro) support the OPL4 mode using MPU401
 	emulation. Writing a native OPL4 support is difficult
 	since Yamaha doesn't give information about their sample ROM chip.
 
@@ -195,7 +216,7 @@
 
 	The driver supports downloading DSP algorithms to these cards.
 
-MediaTriX AudioTriX Pro
+MediaTrix AudioTrix Pro
 	The ATP card is built around a CS4231 codec and an OPL4 synthesizer
 	chips. The OPL4 mode is supported by a microcontroller running a
 	General MIDI emulator. There is also a SB 1.5 compatible playback mode.
@@ -209,9 +230,10 @@
 	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
+	The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929) 
+	and OPTi 82C930 interface
 	chips are used in many different soundcards, including some
-	cards by Reveal and Turtle Beach (Tropez). The purpose of these
+	cards by Reveal miro and Turtle Beach (Tropez). The purpose of these
 	chips is to connect other audio components to the PC bus. The
 	interface chip performs address decoding for the other chips.
 	NOTE! Tropez Plus is not MAD16 but CS4232 based.
@@ -253,14 +275,14 @@
 Latest cards are fully software configurable or they are PnP ISA
 compatible. There are no jumpers on the board.
 
-The driver handles software configurable cards automatically. Just configure
+The driver handles software configurable cards automaticly. Just configure
 the driver to use I/O, IRQ and DMA settings which are known to work.
 You could usually use the same values than with DOS and/or Windows.
 Using different settings is possible but not recommended since it may cause
 some trouble (for example when warm booting from an OS to another or
 when installing new hardware to the machine).
 
-Sound driver sets the soft configurable parameters of the card automatically
+Sound driver sets the soft configurable parameters of the card automaticly
 during boot. Usually you don't need to run any extra initialization
 programs when booting Linux but there are some exceptions. See the
 card specific instructions (below) for more info.
@@ -357,8 +379,8 @@
 since using the default _doesn't_ guarantee anything.
 
 Note also that all questions may not be asked. The configuration program
-may disable some questions depending on the earlier choices. It may also
-select some options automatically as well.
+may disable some questions dependig on the earlier choices. It may also
+select some options automaticly as well.
 
   "ProAudioSpectrum 16 support",
 	- Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
@@ -426,19 +448,19 @@
 	  conflict.
   "Ensoniq Soundscape support",
 	- Answer 'y' if you have a soundcard based on the Ensoniq SoundScape
-	  chipset. Such cards are being manufactured at least by Ensoniq,
+	  chipset. Suach cards are being manufactured at least by Ensoniq,
 	  Spea and Reveal (note that Reveal makes other cards also).
-  "MediaTriX AudioTriX Pro support",
-	- Answer 'y' if you have the AudioTriX Pro.
+  "MediaTrix AudioTrix Pro support",
+	- Answer 'y' if you have the AudioTrix Pro.
   "Support for MAD16 and/or Mozart based cards",
 	- Answer y if your card has a Mozart (OAK OTI-601) or MAD16
-	  (OPTi 82C928 or 82C929) audio interface chip. These chips are
+	  (OPTi 82C928, 82C929 or 82C930) audio interface chip. These chips are
 	  currently quite common so it's possible that many no-name cards
 	  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 (some recent models).
   "Support for TB Maui"
-	- This enables TB Maui specific initialization. Works with TB Maui
+	- This enables TB Maui spesific initialization. Works with TB Maui
 	and TB Tropez (may not work with Tropez Plus).
 
   "Audio Excel DSP 16 initialization support",
@@ -521,7 +543,7 @@
 was listed in the beginning of this file. In this case you should follow
 instructions for your card later in this file.
 
-For other not fully SB clones you may try initialization using DOS in
+For other not fully SB clones yoy may try initialization using DOS in
 the following way:
 
 	- Boot DOS so that the card specific driver gets run.
@@ -607,7 +629,7 @@
 will fail.
 
 GUS PnP (with RAM) is partially supported but it needs to be initialized using
-DOS before booting Linux. This may fail on machines having PnP BIOS.
+DOS or isapnptools before starting the driver.
 
 MPU401 and Windows Sound System
 -------------------------------
@@ -655,18 +677,18 @@
 It's possible to load your own DSP algorithms and run them with the card.
 Look at the directory pss_test of snd-util-3.0.tar.gz for more info.
 
-AudioTriX Pro
+AudioTrix Pro
 -------------
 
 You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition
-to the native AudioTriX driver. Don't enable MSS or MPU drivers.
+to the native AudioTrix driver. Don't enable MSS or MPU drivers.
 
 Configuring ATP is little bit tricky since it uses so many I/O, IRQ and
 DMA numbers. Using the same values than with DOS/Win is a good idea. Don't
-attempt to use the same IRQ or DMA channels twice.
+attemp to use the same IRQ or DMA channels twice.
 
 The SB mode of ATP is implemented so the the ATP driver just enables SB
-in the proper address. The SB driver handles the rest. You have to configure
+in the proper address. The SB driver handles the rest. Yoy have to configure
 both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O
 settings.
 
@@ -689,22 +711,27 @@
 itself so you don't need to enable other drivers than SoundScape
 (enable also the /dev/dsp, /dev/sequencer and MIDI supports).
 
-SoundScape driver uses the MSS compatible codec of the card. It's important
-to note that /dev/dsp0 (/dev/dsp is linked to /dev/dsp0 by default)
-doesn't work with SoundScape (yet). The 'ssinit' program needs /dev/dsp0 so
-that's the reason why it's there. It's possible that 'primary' pcm channel
-becomes supported later. Currently the card's firmware doesn't contain
-support for it.
-
-With 3.0 of the driver you have to change your system to use /dev/dsp1 by default
-so execute: cd /dev;rm dsp;ln -s dsp1 dsp after you have installed driver
-version 3.0 (or later) first time.
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!                                                                   !!!!
+!!!!! NOTE! Before version 3.5-beta6 there WERE two sets of audio 	!!!!
+!!!!!       device files (/dev/dsp0 and /dev/dsp1). The first one WAS   !!!!
+!!!!!	    used only for card initialization and the second for audio  !!!!
+!!!!!	    purposes. It WAS required to change /dev/dsp (a symlink) to !!!!
+!!!!!	    point to /dev/dsp1.						!!!!
+!!!!!                                                                   !!!!
+!!!!!	    This is not required with USS versions 3.5-beta6 and later	!!!!
+!!!!!	    since there is now just one audio device file. Pleace 	!!!!
+!!!!!	    change /dev/dsp to point back to /dev/dsp0 if you are	!!!!
+!!!!!	    upgrading from an earlier driver version using		!!!!
+!!!!!	    (cd /dev;rm dsp;ln -s dsp0 dsp).				!!!!
+!!!!!                                                                   !!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
-The configuration program asks two DMA channels and two interrupts. One IRQ
+The configuration program asks one DMA channel and two interrupts. One IRQ
 and one DMA is used by the MSS codec. The second IRQ is required for the
 MPU401 mode (you have to use different IRQs for both purposes).
-The second DMA channel is required for initialization of the microcontroller.
-You have to use separate DMA channels.
+There were earlier two DMA channels for soundscape but the current driver
+version requires just one.
 
 The SoundScape card has a Motorola microcontroller which must initialized
 _after_ boot (the driver doesn't initialize it during boot).
@@ -727,7 +754,8 @@
 and locate the sound driver initialization message for the SoundScape
 card. If the driver displays string <Ensoniq Soundscape (old)>, you have
 an old card and you will need to use sndscape.co1. For other cards use
-soundscape.co0.
+soundscape.co0. New Soundscape revisions such as Elite and PnP use
+code files with higher numbers (.co2, .co3, etc.).
 
 Check /var/adm/messages after running ssinit. The driver prints
 the board version after downloading the microcode file. That version
@@ -749,7 +777,8 @@
 
 Mozart and OPTi 82C928 (the original MAD16) chips don't support
 MPU401 mode so enter just 0 when the configuration program asks the
-MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) has MPU401 mode.
+MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) and 82C930 chips have MPU401
+mode.
 
 TB Tropez is based on the 82C929 chip. It has two MIDI ports.
 The one connected to the MAD16 chip is the second one (there is a second
@@ -765,8 +794,8 @@
 this should not be a problem.
 
 If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer
-chip (_not_ an OPL3), you have to append line containing #define MAD16_OPL4
-to the file linux/drivers/sound/local.h (after running make config).
+chip (_not_ an OPL3), you have to append a line containing #define MAD16_OPL4
+to the file linux/dirvers/sound/local.h (after running make config).
 
 MAD16 cards having a CS4231 codec support full duplex mode. This mode
 can be enabled by configuring the card to use two DMA channels. Possible
@@ -785,12 +814,12 @@
 problems if you have another MPU401 compatible card. In this case you must
 give address of the Jazz16 based MPU401 interface when the config
 program prompts for the MPU401 information. Then look at the MPU401
-specific section for instructions about configuring more than one MPU401 cards.
+spesific section for instructions about configuring more than one MPU401 cards.
 
 Logitech Soundman Wave
 ----------------------
 
-Read the above MV Jazz specific instructions first.
+Read the above MV Jazz spesific instructions first.
 
 The Logitech SoundMan Wave (don't confuse with the SM16 or SM Games) is
 a MV Jazz based card which has an additional OPL4 based wave table
@@ -810,7 +839,7 @@
 
 NOTE!	Don't answer 'y' when the driver asks about SM Games support
 	(the next question after the MIDI0001.BIN name). However
-	answering 'y' doesn't cause damage your computer so don't panic. 
+	aneswering 'y' doesn't cause damage your computer so don't panic. 
 
 Sound Galaxies
 --------------
@@ -821,7 +850,7 @@
 
 The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have
 an EEPROM chip for storing the configuration data. There is a microcontroller
-which initializes the card to match the EEPROM settings when the machine
+which initializes the card to match the EEPROM settigs when the machine
 is powered on. These cards actually behave just like they have jumpers
 for all of the settings. Configure driver for MSS, MPU, SB/SB Pro  and OPL3 
 supports with these cards. 
@@ -836,10 +865,10 @@
 ESS ES1688 and ES688 'AudioDrive' based cards
 ---------------------------------------------
 
-Support for these two ESS chips is embedded in the SB Pro driver.
-Configure these cards just like SB Pro. Enable the 'SB MPU401 MIDI port'
+Support for these two ESS chips is embedded in the SB driver.
+Configure these cards just like SB. Enable the 'SB MPU401 MIDI port'
 if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode
-so you don't need to enable it (the driver uses normal SB MIDI automatically
+so you don't need to enable it (the driver uses normal SB MIDI automaticly
 with ES688).
 
 NOTE! ESS cards are not compatible with MSS/WSS.
@@ -879,6 +908,53 @@
 configuring Linux. Having it enabled is likely to cause mysterious problems
 and kernel failures when sound is used.
 
+miroSOUND
+---------
+
+The miroSOUND PCM12 has been used successfully. This card is based on
+the MAD16, OPL4, and CS4231A chips and everything said in the section
+about MAD16 cards applies here, too. The only major difference between
+the PCM12 and other MAD16 cards is that instead of the mixer in the
+CS4231 codec a separate mixer controlled by an on-board 80C32
+microcontroller is used. Control of the mixer takes place via the ACI
+(miro's audio control interface) protocol that is implemented in a
+separate lowlevel driver. Make sure you compile this ACI driver
+together with the normal MAD16 support when you use a miroSOUND PCM12
+card. The ACI mixer is controlled by /dev/mixer and the CS4231 mixer
+by /dev/mixer2. You usually don't want to change anything on the
+CS4231 mixer.
+
+The miroSOUND PCM12 is capable of full duplex operation (simultaneous
+PCM replay and recording), which allows you to implement nice
+real-time signal processing audio effect software and network
+telephones. The ACI mixer has to be configured into a special "solo"
+mode for duplex operation in order to avoid feedback caused by the
+mixer (input hears output signal). See lowlevel/aci.c for details on
+the ioctl() for activating the "solo" mode.
+
+The following configuration parameters have worked fine for the PCM12
+in Markus Kuhn's system, many other configurations might work, too:
+MAD16_BASE=0x530, MAD16_IRQ=11, MAD16_DMA=3, MAD16_DMA2=0,
+MAD16_MPU_BASE=0x330, MAD16_MPU_IRQ=10, DSP_BUFFSIZE=65536,
+SELECTED_SOUND_OPTIONS=0x00281000.
+
+The miroSOUND PCM1 pro and the PCM20 are very similar to the PCM12.
+Perhaps the same ACI driver also works for these cards, however this
+has never actually been tested. The PCM20 contains a radio tuner,
+which is also controlled by ACI. This radio tuner is currently not
+supported by the ACI driver, but documentation for it was provided by
+miro and ACI tuner support could easily be added if someone is really
+interested.
+
+Compaq Deskpro XL
+-----------------
+
+The builtin sound hardware of Compaq Deskpro XL is now supported. 
+You need to configure the driver with MSS and OPL3 supports enabled.
+In addition you need to manually edit linux/drivers/sound/local.h and
+to add a line containing "#define DESKPROXL" if you used 
+make menuconfig/xconfig.
+
 Others?
 -------
 
@@ -893,19 +969,19 @@
 Please check which version of sound driver you are using before 
 complaining that your card is not supported. It's possible that you are 
 using a driver version which was released months before your card was
-introduced. Driver's release date is listed after its version number
+introduced. Driver's release date is listed after it's version number
 in "cat /dev/sndstat" printout and in file linux/drivers/sound/soundvers.h.
 
-First of all, there is an easy way to make most soundcards to work
+First of all. There is an easy way to make most soundcards to work
 with Linux. Just use the DOS based driver to initialize the card
 to a _known_ state. Then use loadlin.exe to boot Linux. If Linux is configured
-to use the same I/O, IRQ and DMA numbers than DOS, the card could work.
+to use the sama I/O, IRQ and DMA numbers than DOS, the card could work.
 (ctrl-alt-del can be used in place of loadlin.exe but it doesn't work with
 new motherboards). This method works also with all/most PnP soundcards.
 
 Don't get fooled with SB compatibility. Most cards are compatible with
 SB but that may require a TSR which is not possible with Linux. If
-the card is compatible with MSS, it's a better choice. Some cards
+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.
 
 Then there are cards which are no longer manufactured and/or which
@@ -914,7 +990,7 @@
 Adding support for a new card requires much work and increases time
 required in maintaining the driver (some changes need to be done
 to all low level drivers and be tested too, maybe with multiple
-operating systems). For this reason I have made a decision to not support
+operating systems). For this reason I have made a desicion to not support
 obsolete cards. It's possible that someone else makes a separately 
 distributed driver (diffs) for the card. Version v3.6 will be much more
 modular so making separately distributed drivers will be easier with it.
@@ -923,17 +999,17 @@
 Writing a driver for a new card is not possible if there are no 
 programming information available about the card. If you don't
 find your new card from this file, look from the home page 
-(http://personal.eunet.fi/pp/voxware). Then please contact
+(http://www.4front-tech.com/usslite). Then please contact
 manufacturer of the card and ask if they have (or are willing to)
 released technical details of the card. Do this before contacting me. I
 can only answer 'no' if there are no programming information available.
 
-I have made decision to not accept code based on reverse engineering
+I have made decicion to not accept code based on reverse engineering
 to the driver. There are three main reasons: First I don't want to break
 relationships to sound card manufacturers. The second reason is that
-maintaining and supporting a driver without any specs will be a pain.
+maintaining and supporting a driver withoun any specs will be a pain.
 The third reason is that companies have freedom to refuse selling their
-products to other than Windows users.
+products to other than Windows useres.
 
 Some companies don't give low level technical information about their
 products to public or at least their require signing a NDA. It's not
@@ -944,7 +1020,7 @@
 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 (http://personal.eunet.fi/pp/voxware/new_cards.html)
+at the home page (http://www.4front-tech.com/usslite/new_cards.html)
 for latest info.
 
 Information about unsupported soundcards and chipsets is welcome as well
@@ -954,6 +1030,11 @@
 
 Hannu Savolainen
 hannu@voxware.pp.fi
-Sound driver's www home page: http://personal.eunet.fi/pp/voxware
-                   US mirror: http://www.4Front-Tech.com/usslite
+
+Personal home page:	   http://personal.eunet.fi/pp/voxware/hannu.html
+www home page of USS/Lite: http://www.4front-tech.com/usslite
+  European/Finnish mirror: http://personal.eunet.fi/pp/voxware
+
+www home page of commercial
+UNIX Sound System drivers: http://www.4front-tech.com/uss.html
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux
--- v2.0.0/linux/drivers/sound/Readme.linux	Tue May 28 08:09:56 1996
+++ linux/drivers/sound/Readme.linux	Sun Jun 30 11:43:41 1996
@@ -19,7 +19,7 @@
   sources). Remove old version of linux/drivers/sound directory before
   installing new files.
 
-- To build the device files you need to run the enclosed shell script 
+- To build the device files you need to run the enclosed shell scrip 
   (see below). You need to do this only when installing sound driver
   first time or when upgrading to much recent version than the earlier
   one.
@@ -27,13 +27,13 @@
 - Configure and compile Linux as normally (remember to include the
   sound support during "make config"). Please refer to kernel documentation
   for instructions about configuring and compiling kernel. File Readme.cards
-  contains card specific instructions for configuring this driver for
+  contains card spesific instructions for configuring this driver for
   use with various soundcards.
 
 Boot time configuration (using lilo and insmod) 
 -----------------------------------------------
 
-This information has been removed. Too many users didn't believe
+This information has been removed. Too many users did't believe
 that it's really not necessary to use this method. Please look at
 Readme of sound driver version 3.0.1 if you still want to use this method.
 
@@ -46,7 +46,7 @@
 
 	cat /dev/sndstat 
 
-and look at the output. It should display some useful info about the
+and look at the output. It should display some usefull info about the
 driver configuration. If there is no /dev/sndstat 
 (/dev/sndstat: No such file or directory), ensure that you have executed the
 soundinstall script (at the end of this file).
@@ -67,7 +67,7 @@
 check for possible boot (insmod) time error messages in /var/adm/messages.
 
 - Other messages or problems
-Please check http://personal.eunet.fi/pp/voxware for more info.
+Please check http://www.4front-tech.com/usslite for more info.
 
 Hannu Savolainen
 hannu@voxware.pp.fi
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme.modules linux/drivers/sound/Readme.modules
--- v2.0.0/linux/drivers/sound/Readme.modules	Mon Apr 29 18:05:18 1996
+++ linux/drivers/sound/Readme.modules	Sun Jun 30 11:43:43 1996
@@ -45,10 +45,10 @@
 
 	insmod sound dma_buffsize=32768
 
-Minimum buffer size is 4096 and the maximum depends on the DMA channel. 
+Minimum buffer size is 4096 and the maximum depends on the DMA channe. 
 For 8 bit channels (0 to 3) the limit is 64k and for 16 bit ones (5 to 7)
-it's 128k. Driver selects a suitable buffer size automatically in case
-you try to specify an invalid size.
+it's 128k. Driver selects a suitable buffer size automaticly in case
+you try to spesify an invalid size.
 
 Q: What is the right DMA buffer size?
 
@@ -58,17 +58,17 @@
 recording to hard disk is likely to require large buffers.
 
 Very small buffers are sufficient when you are just playing 8kHz audio files 
-on an empty P133 system. Using a 128k buffer just wastes 120k (or 250k)
+on an empty P133 system. Using a 128k byffer just wastes 120k (or 250k)
 of valuable physical RAM memory. 
 
-The right buffer size can be easily found by making some experiments
+The right buffer sice can be easily found by making some experiments
 with the dma_buffsize= parameter. I use usually 16k buffers on a DX4/100 system
 and 64k on an old 386 system. 
 
 NOTE!	DMA buffers are used only by /dev/audio# and /dev/dsp# devices.
 	Other device files don't use them but there are two exceptions:
 	GUS driver uses DMA buffers when loading samples to the card.
-	Ensoniq SoundScape driver uses them when downloading the microcode
+	Ensoniq SoundScape driver uses them when doanloading the microcode
 	file (sndscape.co[012]) to the card. Using large buffers doesn't
 	increase performance in these cases.
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/Readme.v30 linux/drivers/sound/Readme.v30
--- v2.0.0/linux/drivers/sound/Readme.v30	Fri Apr 12 15:52:02 1996
+++ linux/drivers/sound/Readme.v30	Sun Jun 30 11:43:43 1996
@@ -18,7 +18,7 @@
 /dev/midi##
 -----------
 
-This interface should be useful for applications like MIDI sysex librarians.
+This interface should be usefull for applications like MIDI sysex librarians.
 There are (currently) no timing features so making music could be impossible.
 
 There are as many /dev/midi## devices as there are MIDI ports in the system. 
@@ -53,7 +53,7 @@
 If this ioctl is called with mode=1, the interface is put to the intelligent
 (coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called.
 It could have some strange effects if not called immediately after open. This
-call returns EINVAL if the midi port doesn't support the MPU-401 intelligent
+vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent
 mode.
 
 ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port
@@ -81,10 +81,10 @@
 	data		Buffer for the command arguments and returned
 			data.
 
-Be extremely careful with the nr_args and nr_returns fields. They
+Be extremely carefull with the nr_args and nr_returns fields. They
 must match the command. An incorrect value will put the card and
 the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further
-details.
+datails.
 
 
 
@@ -99,7 +99,7 @@
 /dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE()
 like macros. The voice number parameters of the API macros have been redefined
 to denote MIDI channels. This means that the driver allocates voices for
-the channels automatically (this is a responsibility/right of an application
+the channels automaticly (this is a responsibility/right of an application
 with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has
 similar effects for a synth channel than on a MIDI port. This kind of
 solution provides better device independence than the /dev/sequencer. The
@@ -116,12 +116,12 @@
 
 - The new interface is used much like the ordinary /dev/sequencer. The
 event format is new so you have to use the API macros defined in the 
-sys/soundcard.h. The interface is will probably change before the final 3.0
+sys/soundcard.h. The interface is will propably change before the final 3.0
 release but using the API macros should ensure compatibility in source level.
 The new event format is not recognized by version 2.X so don't try to 
 distribute binaries compiled with soundcard.h of v3.X.
 
-- The basic API usage is similar to the current one. There are some new
+- The basic API useage is similar to the current one. There are some new
 macros but the older ones should work as earlier. The most important
 incompatibility is that the /dev/sequencer2 driver allocates voices itself.
 The other one is that the application must send SEQ_START_TIMER() as it's
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.0.0/linux/drivers/sound/ad1848.c	Tue May  7 16:22:34 1996
+++ linux/drivers/sound/ad1848.c	Sun Jun 30 11:43:48 1996
@@ -15,27 +15,11 @@
  */
 
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -64,16 +48,18 @@
     unsigned char   format_bits;
 
     int             xfer_count;
-    int             irq_mode;
+    int             audio_mode;
     int             intr_active;
     int             opened;
     char           *chip_name;
-    int             mode;
+    int             model;
 #define MD_1848		1
 #define MD_4231		2
 #define MD_4231A	3
 #define MD_1845		4
 #define MD_4232		5
+#define MD_C930		6
+#define MD_IWAVE	7
 
     /* Mixer parameters */
     int             recmask;
@@ -96,16 +82,15 @@
 
 static int      timer_installed = -1;
 
-static char     mixer2codec[MAX_MIXER_DEV] =
-{0};
-
-static int      ad_format_mask[6 /*devc->mode */ ] =
+static int      ad_format_mask[8 /*devc->model */ ] =
 {
   0,
   AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
   AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
   AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
   AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,	/* AD1845 */
+  AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
+  AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
   AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM
 };
 
@@ -121,6 +106,7 @@
 static int      ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local);
 static void     ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
 static void     ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static int      ad1848_prepare_for_output (int dev, int bsize, int bcount);
 static int      ad1848_prepare_for_IO (int dev, int bsize, int bcount);
 static void     ad1848_reset (int dev);
 static void     ad1848_halt (int dev);
@@ -196,7 +182,8 @@
   while (timeout > 0 && ad_read (devc, 11) & 0x20)
     timeout--;
   if (ad_read (devc, 11) & 0x20)
-    printk ("ad1848: Auto calibration timed out(3).\n");
+    if (devc->model != MD_1845)
+      printk ("ad1848: Auto calibration timed out(3).\n");
 }
 
 static void
@@ -205,8 +192,6 @@
   int             i;
   unsigned char   prev;
 
-  if (devc->mode != MD_1848)
-    return;
   /*
      * Save old register settings and mute output channels
    */
@@ -215,6 +200,12 @@
       prev = devc->saved_regs[i] = ad_read (devc, i);
       ad_write (devc, i, prev | 0x80);
     }
+
+/*
+ * Let's have some delay
+ */
+  for (i = 0; i < 1000; i++)
+    inb (devc->base);
 }
 
 static void
@@ -222,6 +213,12 @@
 {
   int             i;
 
+/*
+ * Let's have some delay
+ */
+  for (i = 0; i < 1000; i++)
+    inb (devc->base);
+
   /*
      * Restore back old volume registers (unmute)
    */
@@ -367,7 +364,7 @@
 ad1848_mixer_get (ad1848_info * devc, int dev)
 {
   if (!((1 << dev) & devc->supported_devices))
-    return -EINVAL;
+    return -(EINVAL);
 
   return devc->levels[dev];
 }
@@ -401,13 +398,13 @@
   right = mix_cvt[right];
 
   if (dev > 31)
-    return -EINVAL;
+    return -(EINVAL);
 
   if (!(devc->supported_devices & (1 << dev)))
-    return -EINVAL;
+    return -(EINVAL);
 
   if (mix_devices[dev][LEFT_CHN].nbits == 0)
-    return -EINVAL;
+    return -(EINVAL);
 
   devc->levels[dev] = retvol;
 
@@ -442,10 +439,12 @@
 {
   int             i;
 
-  switch (devc->mode)
+  switch (devc->model)
     {
     case MD_4231:
     case MD_4231A:
+    case MD_C930:
+    case MD_IWAVE:
     case MD_1845:
       devc->supported_devices = MODE2_MIXER_DEVICES;
       break;
@@ -469,16 +468,7 @@
 static int
 ad1848_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
 {
-  ad1848_info    *devc;
-
-  int             codec_dev = mixer2codec[dev];
-
-  if (!codec_dev)
-    return -ENXIO;
-
-  codec_dev--;
-
-  devc = (ad1848_info *) audio_devs[codec_dev]->devc;
+  ad1848_info    *devc = mixer_devs[dev]->devc;
 
   if (((cmd >> 8) & 0xff) == 'M')
     {
@@ -524,107 +514,16 @@
 	  }
     }
   else
-    return -EINVAL;
+    return -(EINVAL);
 }
 
-static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
-{
-  {
-    "Generic AD1848 codec",
-    DMA_AUTOMODE,
-    AFMT_U8,			/* Will be set later */
-    NULL,
-    ad1848_open,
-    ad1848_close,
-    ad1848_output_block,
-    ad1848_start_input,
-    ad1848_ioctl,
-    ad1848_prepare_for_IO,
-    ad1848_prepare_for_IO,
-    ad1848_reset,
-    ad1848_halt,
-    NULL,
-    NULL,
-    ad1848_halt_input,
-    ad1848_halt_output,
-    ad1848_trigger
-  }};
-
-static struct mixer_operations ad1848_mixer_operations =
-{
-  "AD1848/CS4248/CS4231",
-  ad1848_mixer_ioctl
-};
-
 static int
-ad1848_open (int dev, int mode)
+ad1848_set_speed (int dev, int arg)
 {
-  ad1848_info    *devc = NULL;
-  unsigned long   flags;
-
-  if (dev < 0 || dev >= num_audiodevs)
-    return -ENXIO;
-
-  devc = (ad1848_info *) audio_devs[dev]->devc;
-
-
-  save_flags (flags);
-  cli ();
-  if (devc->opened)
-    {
-      restore_flags (flags);
-      printk ("ad1848: Already opened\n");
-      return -EBUSY;
-    }
-
-
-  devc->dual_dma = 0;
-
-  if (audio_devs[dev]->flags & DMA_DUPLEX)
-    {
-      devc->dual_dma = 1;
-    }
-
-  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 (hope so).
- */
-  ad_mute (devc);
-
-  return 0;
-}
-
-static void
-ad1848_close (int dev)
-{
-  unsigned long   flags;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
-  DEB (printk ("ad1848_close(void)\n"));
-
-  save_flags (flags);
-  cli ();
-
-  devc->intr_active = 0;
-  ad1848_reset (dev);
-
-
-  devc->opened = 0;
-  devc->irq_mode = 0;
-
-  ad_unmute (devc);
-  restore_flags (flags);
-}
-
-static int
-set_speed (ad1848_info * devc, int arg)
-{
   /*
-     * The sampling speed is encoded in the least significant nibble of I8. The
+     * The sampling speed is encoded in the least significant nible of I8. The
      * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
      * three bits select the divisor (indirectly):
      *
@@ -632,10 +531,10 @@
      * the increasing order.
    */
   typedef struct
-  {
-    int             speed;
-    unsigned char   bits;
-  }
+    {
+      int             speed;
+      unsigned char   bits;
+    }
   speed_struct;
 
   static speed_struct speed_table[] =
@@ -661,7 +560,10 @@
 
   n = sizeof (speed_table) / sizeof (speed_struct);
 
-  if (devc->mode == MD_1845)	/* AD1845 has different timer than others */
+  if (arg == 0)
+    return devc->speed;
+
+  if (devc->model == MD_1845)	/* AD1845 has different timer than others */
     {
       if (arg < 4000)
 	arg = 4000;
@@ -705,9 +607,11 @@
   return devc->speed;
 }
 
-static int
-set_channels (ad1848_info * devc, int arg)
+static short
+ad1848_set_channels (int dev, short arg)
 {
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
   if (arg != 1 && arg != 2)
     return devc->channels;
 
@@ -715,15 +619,16 @@
   return arg;
 }
 
-static int
-set_format (ad1848_info * devc, int arg)
+static unsigned int
+ad1848_set_bits (int dev, unsigned int arg)
 {
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
   static struct format_tbl
-  {
-    int             format;
-    unsigned char   bits;
-  }
+    {
+      int             format;
+      unsigned char   bits;
+    }
   format2bits[] =
   {
     {
@@ -768,7 +673,10 @@
   };
   int             i, n = sizeof (format2bits) / sizeof (struct format_tbl);
 
-  if (!(arg & ad_format_mask[devc->mode]))
+  if (arg == 0)
+    return devc->audio_format;
+
+  if (!(arg & ad_format_mask[devc->model]))
     arg = AFMT_U8;
 
   devc->audio_format = arg;
@@ -787,51 +695,100 @@
   return devc->audio_format = AFMT_U8;
 }
 
+static struct audio_driver ad1848_audio_driver =
+{
+  ad1848_open,
+  ad1848_close,
+  ad1848_output_block,
+  ad1848_start_input,
+  ad1848_ioctl,
+  ad1848_prepare_for_IO,
+  ad1848_prepare_for_output,
+  ad1848_reset,
+  ad1848_halt,
+  NULL,
+  NULL,
+  ad1848_halt_input,
+  ad1848_halt_output,
+  ad1848_trigger,
+  ad1848_set_speed,
+  ad1848_set_bits,
+  ad1848_set_channels
+};
+
+static struct mixer_operations ad1848_mixer_operations =
+{
+  "SOUNDPORT",
+  "AD1848/CS4248/CS4231",
+  ad1848_mixer_ioctl
+};
+
 static int
-ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
+ad1848_open (int dev, int mode)
 {
-  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+  ad1848_info    *devc = NULL;
+  unsigned long   flags;
+
+  if (dev < 0 || dev >= num_audiodevs)
+    return -(ENXIO);
+
+  devc = (ad1848_info *) audio_devs[dev]->devc;
+
 
-  switch (cmd)
+  save_flags (flags);
+  cli ();
+  if (devc->opened)
     {
-    case SOUND_PCM_WRITE_RATE:
-      if (local)
-	return set_speed (devc, (int) arg);
-      return snd_ioctl_return ((int *) arg, set_speed (devc, get_fs_long ((long *) arg)));
-
-    case SOUND_PCM_READ_RATE:
-      if (local)
-	return devc->speed;
-      return snd_ioctl_return ((int *) arg, devc->speed);
-
-    case SNDCTL_DSP_STEREO:
-      if (local)
-	return set_channels (devc, (int) arg + 1) - 1;
-      return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg) + 1) - 1);
-
-    case SOUND_PCM_WRITE_CHANNELS:
-      if (local)
-	return set_channels (devc, (int) arg);
-      return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg)));
-
-    case SOUND_PCM_READ_CHANNELS:
-      if (local)
-	return devc->channels;
-      return snd_ioctl_return ((int *) arg, devc->channels);
-
-    case SNDCTL_DSP_SAMPLESIZE:
-      if (local)
-	return set_format (devc, (int) arg);
-      return snd_ioctl_return ((int *) arg, set_format (devc, get_fs_long ((long *) arg)));
-
-    case SOUND_PCM_READ_BITS:
-      if (local)
-	return devc->audio_format;
-      return snd_ioctl_return ((int *) arg, devc->audio_format);
+      restore_flags (flags);
+      return -(EBUSY);
+    }
 
-    default:;
+  devc->dual_dma = 0;
+
+  if (audio_devs[dev]->flags & DMA_DUPLEX)
+    {
+      devc->dual_dma = 1;
     }
-  return -EINVAL;
+
+  devc->intr_active = 0;
+  devc->opened = 1;
+  devc->audio_mode = 0;
+  ad1848_trigger (dev, 0);
+  restore_flags (flags);
+/*
+ * Mute output until the playback really starts. This decreases clicking (hope so).
+ */
+  ad_mute (devc);
+
+  return 0;
+}
+
+static void
+ad1848_close (int dev)
+{
+  unsigned long   flags;
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  DEB (printk ("ad1848_close(void)\n"));
+
+  save_flags (flags);
+  cli ();
+
+  devc->intr_active = 0;
+  ad1848_reset (dev);
+
+
+  devc->opened = 0;
+  devc->audio_mode = 0;
+
+  ad_unmute (devc);
+  restore_flags (flags);
+}
+
+static int
+ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
+{
+  return -(EINVAL);
 }
 
 static void
@@ -840,6 +797,9 @@
   unsigned long   flags, cnt;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
+  if (!dma_restart)
+    return;
+
   cnt = count;
 
   if (devc->audio_format == AFMT_IMA_ADPCM)
@@ -855,11 +815,11 @@
     cnt >>= 1;
   cnt--;
 
-  if (devc->irq_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
+  if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == devc->xfer_count)
     {
-      devc->irq_mode |= PCM_ENABLE_OUTPUT;
+      devc->audio_mode |= PCM_ENABLE_OUTPUT;
       devc->intr_active = 1;
       return;			/*
 				 * Auto DMA mode on. No need to react
@@ -868,20 +828,16 @@
   save_flags (flags);
   cli ();
 
-  if (dma_restart)
-    {
-      ad_write (devc, 9, ad_read (devc, 9) & ~0x01);	/* Playback disable */
-      /* ad1848_halt (dev); */
-      DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
-    }
+  /* ad_write (devc, 9, ad_read (devc, 9) & ~ 0x01); / * Playback disable */
+  ad1848_halt (dev);
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 
   ad_write (devc, 15, (unsigned char) (cnt & 0xff));
   ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
 
-  ad_unmute (devc);
 
   devc->xfer_count = cnt;
-  devc->irq_mode |= PCM_ENABLE_OUTPUT;
+  devc->audio_mode |= PCM_ENABLE_OUTPUT;
   devc->intr_active = 1;
   restore_flags (flags);
 }
@@ -892,6 +848,9 @@
   unsigned long   flags, cnt;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
+  if (!dma_restart)
+    return;
+
   cnt = count;
   if (devc->audio_format == AFMT_IMA_ADPCM)
     {
@@ -906,11 +865,11 @@
     cnt >>= 1;
   cnt--;
 
-  if (devc->irq_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
+  if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == devc->xfer_count)
     {
-      devc->irq_mode |= PCM_ENABLE_INPUT;
+      devc->audio_mode |= PCM_ENABLE_INPUT;
       devc->intr_active = 1;
       return;			/*
 				 * Auto DMA mode on. No need to react
@@ -926,7 +885,7 @@
       DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
     }
 
-  if (devc->mode == MD_1848 || !devc->dual_dma)		/* Single DMA channel mode */
+  if (devc->model == MD_1848 || !devc->dual_dma)	/* Single DMA channel mode */
     {
       ad_write (devc, 15, (unsigned char) (cnt & 0xff));
       ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
@@ -941,12 +900,22 @@
   ad_unmute (devc);
 
   devc->xfer_count = cnt;
-  devc->irq_mode |= PCM_ENABLE_INPUT;
+  devc->audio_mode |= PCM_ENABLE_INPUT;
   devc->intr_active = 1;
   restore_flags (flags);
 }
 
 static int
+ad1848_prepare_for_output (int dev, int bsize, int bcount)
+{
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  ad_mute (devc);
+
+  return ad1848_prepare_for_IO (dev, bsize, bcount);
+}
+
+static int
 ad1848_prepare_for_IO (int dev, int bsize, int bcount)
 {
   int             timeout;
@@ -954,7 +923,7 @@
   unsigned long   flags;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
-  if (devc->irq_mode)
+  if (devc->audio_mode)
     return 0;
 
   save_flags (flags);
@@ -964,7 +933,7 @@
   if (devc->channels > 1)
     fs |= 0x10;
 
-  if (devc->mode == MD_1845)	/* Use alternate speed select registers */
+  if (devc->model == MD_1845)	/* Use alternate speed select registers */
     {
       fs &= 0xf0;		/* Mask off the rate select bits */
 
@@ -974,7 +943,7 @@
 
   old_fs = ad_read (devc, 8);
 
-  if (devc->mode != MD_4232)
+  if (devc->model != MD_4232)
     if (fs == old_fs)		/* No change */
       {
 	restore_flags (flags);
@@ -984,7 +953,7 @@
 
   ad_enter_MCE (devc);		/* Enables changes to the format select reg */
 
-  if (devc->mode == MD_4232)
+  if (devc->model == MD_4232)
     {
       tmp = ad_read (devc, 16);
       ad_write (devc, 16, tmp | 0x30);
@@ -992,21 +961,21 @@
 
   ad_write (devc, 8, fs);
   /*
-   * Write to I8 starts resynchronization. Wait until it completes.
+   * Write to I8 starts resyncronization. Wait until it completes.
    */
   timeout = 10000;
   while (timeout > 0 && inb (devc->base) == 0x80)
     timeout--;
 
   /*
-     * If mode == 2 (CS4231), set I28 also. It's the capture format register.
+     * If mode >= 2 (CS4231), set I28 also. It's the capture format register.
    */
-  if (devc->mode != MD_1848)
+  if (devc->model != MD_1848)
     {
       ad_write (devc, 28, fs);
 
       /*
-         * Write to I28 starts resynchronization. Wait until it completes.
+         * Write to I28 starts resyncronization. Wait until it completes.
        */
       timeout = 10000;
       while (timeout > 0 && inb (devc->base) == 0x80)
@@ -1014,7 +983,7 @@
 
     }
 
-  if (devc->mode == MD_4232)
+  if (devc->model == MD_4232)
     ad_write (devc, 16, tmp & ~0x30);
 
   ad_leave_MCE (devc);		/*
@@ -1064,7 +1033,7 @@
 
   ad_mute (devc);
 
-  if (devc->mode == MD_4232)	/* Use applied black magic */
+  if (devc->model == MD_4232)	/* Use applied black magic */
     {
       int             tmout;
 
@@ -1085,7 +1054,7 @@
   outb (0, io_Status (devc));	/* Clear interrupt status */
   outb (0, io_Status (devc));	/* Clear interrupt status */
 
-  devc->irq_mode &= ~PCM_ENABLE_INPUT;
+  devc->audio_mode &= ~PCM_ENABLE_INPUT;
 
   restore_flags (flags);
 }
@@ -1100,7 +1069,7 @@
   cli ();
 
   ad_mute (devc);
-  if (devc->mode == MD_4232)	/* Use applied black magic */
+  if (devc->model == MD_4232)	/* Use applied black magic */
     {
       int             tmout;
 
@@ -1121,7 +1090,7 @@
   outb (0, io_Status (devc));	/* Clear interrupt status */
   outb (0, io_Status (devc));	/* Clear interrupt status */
 
-  devc->irq_mode &= ~PCM_ENABLE_OUTPUT;
+  devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
 
   restore_flags (flags);
 }
@@ -1131,35 +1100,62 @@
 {
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
   unsigned long   flags;
-  unsigned char   tmp;
+  unsigned char   tmp, old;
 
   save_flags (flags);
   cli ();
-  state &= devc->irq_mode;
+  state &= devc->audio_mode;
 
-  tmp = ad_read (devc, 9) & ~0x03;
+  tmp = (old = ad_read (devc, 9)) & ~0x03;
   if (state & PCM_ENABLE_INPUT)
     tmp |= 0x02;
   if (state & PCM_ENABLE_OUTPUT)
     tmp |= 0x01;
+
+  if (!(state & PCM_ENABLE_OUTPUT) && old & 0x01);
+  ad_mute (devc);
+
   ad_write (devc, 9, tmp);
 
+  if (state & PCM_ENABLE_OUTPUT && !(old & 0x01));
+  ad_unmute (devc);
+
   restore_flags (flags);
 }
 
 int
 ad1848_detect (int io_base, int *ad_flags, int *osp)
 {
+  /*
+   * Initial values for the indirect registers of CS4248/AD1848.
+   */
+  static int      init_values[] =
+  {
+    0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+    0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
+
+  /* Positions 16 to 31 just for CS4231/2 and ad1845 */
+    0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
 
   unsigned char   tmp;
   ad1848_info    *devc = &dev_info[nr_ad1848_devs];
   unsigned char   tmp1 = 0xff, tmp2 = 0xff;
+  int             optiC930 = 0;	/* OPTi 82C930 flag */
+  int             interwave = 0;
+  int             ad1847_flag = 0;
+
   int             i;
 
   DDB (printk ("ad1848_detect(%x)\n", io_base));
 
   if (ad_flags)
-    *ad_flags = 0;
+    {
+      if (*ad_flags == 0x12345678)
+	interwave = 1;
+      *ad_flags = 0;
+    }
 
   if (nr_ad1848_devs >= MAX_AUDIO_DEV)
     {
@@ -1179,7 +1175,7 @@
   devc->irq = 0;
   devc->opened = 0;
   devc->chip_name = "AD1848";
-  devc->mode = MD_1848;		/* AD1848 or CS4248 */
+  devc->model = MD_1848;	/* AD1848 or CS4248 */
   devc->osp = osp;
   devc->debug_flag = 0;
 
@@ -1187,7 +1183,7 @@
      * Check that the I/O address is in use.
      *
      * The bit 0x80 of the base I/O port is known to be 0 after the
-     * chip has performed its power-on initialization. Just assume
+     * chip has performed it's power on initialization. Just assume
      * this has happened before the OS is starting.
      *
      * If the I/O address is unused, it typically returns 0xff.
@@ -1217,23 +1213,29 @@
   ad_write (devc, 1, 0x45);	/* 0x55 with bit 0x10 clear */
 
   if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45)
-    {
-      DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2));
-      return 0;
-    }
+    if (tmp2 == 0x65)		/* AD1847 has couple of bits hardcoded to 1 */
+      ad1847_flag = 1;
+    else
+      {
+	DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2));
+	return 0;
+      }
 
   DDB (printk ("ad1848_detect() - step C\n"));
   ad_write (devc, 0, 0x45);
   ad_write (devc, 1, 0xaa);
 
   if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa)
-    {
-      DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2));
-      return 0;
-    }
+    if (tmp2 == 0x8a)		/* AD1847 has few bits hardcoded to 1 */
+      ad1847_flag = 1;
+    else
+      {
+	DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2));
+	return 0;
+      }
 
   /*
-     * The indirect register I12 has some read only bits. Let's
+     * The indirect register I12 has some read only bits. Lets
      * try to change them.
    */
 
@@ -1259,6 +1261,22 @@
      * with CS4231.
    */
 
+/*
+ * OPTi 82C930 has mode2 control bit in another place. This test will fail
+ * with it. Accept this situation as a possible indication of this chip.
+ */
+
+  DDB (printk ("ad1848_detect() - step F\n"));
+  ad_write (devc, 12, 0);	/* Mode2=disabled */
+
+  for (i = 0; i < 16; i++)
+    if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16)))
+      {
+	DDB (printk ("ad1848 detect step F(%d/%x/%x) - OPTi chip?\n", i, tmp1, tmp2));
+	if (!ad1847_flag)
+	  optiC930 = 1;
+	break;
+      }
 
   /*
      * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
@@ -1277,7 +1295,7 @@
       devc->chip_name = "CS4248";	/* Our best knowledge just now */
     }
 
-  if ((tmp1 & 0xc0) == (0x80 | 0x40))
+  if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40))
     {
       /*
          *      CS4231 detected - is it?
@@ -1314,7 +1332,7 @@
 	       */
 	      devc->chip_name = "CS4231";
 
-	      devc->mode = MD_4231;
+	      devc->model = MD_4231;
 
 	      /*
 	       * It could be an AD1845 or CS4231A as well.
@@ -1330,17 +1348,17 @@
 
 		case 0xa0:
 		  devc->chip_name = "CS4231A";
-		  devc->mode = MD_4231A;
+		  devc->model = MD_4231A;
 		  break;
 
 		case 0xa2:
 		  devc->chip_name = "CS4232";
-		  devc->mode = MD_4232;
+		  devc->model = MD_4232;
 		  break;
 
 		case 0xb2:
 		  devc->chip_name = "CS4232A";
-		  devc->mode = MD_4232;
+		  devc->model = MD_4232;
 		  break;
 
 		case 0x80:
@@ -1358,15 +1376,28 @@
 		    if (ad_read (devc, 23) != tmp)	/* AD1845 ? */
 		      {
 			devc->chip_name = "AD1845";
-			devc->mode = MD_1845;
+			devc->model = MD_1845;
+		      }
+		    else if (interwave)
+		      {
+			devc->model = MD_IWAVE;
+			devc->chip_name = "IWave";
 		      }
 
 		    ad_write (devc, 23, tmp);	/* Restore */
 		  }
 		  break;
 
-		default:	/* Assume CS4231 */
-		  devc->mode = MD_4231;
+		default:	/* Assume CS4231 or OPTi 82C930 */
+		  if (optiC930)
+		    {
+		      devc->chip_name = "82C930";
+		      devc->model = MD_C930;
+		    }
+		  else
+		    {
+		      devc->model = MD_4231;
+		    }
 
 		}
 	    }
@@ -1379,11 +1410,32 @@
   DDB (printk ("ad1848_detect() - step L\n"));
   if (ad_flags)
     {
-      if (devc->mode != MD_1848)
+      if (devc->model != MD_1848)
 	*ad_flags |= AD_F_CS4231;
     }
 
   DDB (printk ("ad1848_detect() - Detected OK\n"));
+
+  if (devc->model == MD_1848 && ad1847_flag)
+    devc->chip_name = "AD1847";
+
+  for (i = 0; i < 16; i++)
+    ad_write (devc, i, init_values[i]);
+
+  ad_mute (devc);		/* Initialize some variables */
+  ad_unmute (devc);		/* Leave it unmuted now */
+
+  if (devc->model > MD_1848)
+    {
+      ad_write (devc, 12, ad_read (devc, 12) | 0x40);	/* Mode2 = enabled */
+
+      if (devc->model == MD_IWAVE)
+	ad_write (devc, 12, 0x6c);	/* Select codec mode 3 */
+
+      for (i = 16; i < 32; i++)
+	ad_write (devc, i, init_values[i]);
+    }
+
   return 1;
 }
 
@@ -1396,24 +1448,14 @@
      *   The actually used IRQ is ABS(irq).
    */
 
-  /*
-     * Initial values for the indirect registers of CS4248/AD1848.
-   */
-  static int      init_values[] =
-  {
-    0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
-    0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
 
-  /* Positions 16 to 31 just for CS4231 */
-    0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-  };
-  int             i, my_dev;
+  int             my_dev;
+  char            dev_name[100];
 
   ad1848_info    *devc = &dev_info[nr_ad1848_devs];
 
-  if (!ad1848_detect (io_base, NULL, osp))
-    return;
+  int             audio_flags = DMA_AUTOMODE;
+
 
   request_region (devc->base, 4, devc->chip_name);
 
@@ -1422,141 +1464,129 @@
   devc->timer_ticks = 0;
   devc->osp = osp;
 
-  if (nr_ad1848_devs != 0)
-    {
-      memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs],
-	      (char *) &ad1848_pcm_operations[0],
-	      sizeof (struct audio_operations));
-    }
-
-  for (i = 0; i < 16; i++)
-    ad_write (devc, i, init_values[i]);
-
-  ad_mute (devc);		/* Initialize some variables */
-  ad_unmute (devc);		/* Leave it unmuted now */
-
-  if (devc->mode > MD_1848)
+  if (devc->model > MD_1848)
     {
       if (dma_capture == dma_playback || dma_capture == -1 || dma_playback == -1)
 	{
 	  ad_write (devc, 9, ad_read (devc, 9) | 0x04);		/* Single DMA mode */
-	  ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+	  audio_flags &= ~DMA_DUPLEX;
 	}
       else
 	{
 	  ad_write (devc, 9, ad_read (devc, 9) & ~0x04);	/* Dual DMA mode */
-	  ad1848_pcm_operations[nr_ad1848_devs].flags |= DMA_DUPLEX;
+	  audio_flags |= DMA_DUPLEX;
 	}
 
-      ad_write (devc, 12, ad_read (devc, 12) | 0x40);	/* Mode2 = enabled */
-      for (i = 16; i < 32; i++)
-	ad_write (devc, i, init_values[i]);
-
-
-      if (devc->mode == MD_1845)
+      if (devc->model == MD_1845)
 	ad_write (devc, 27, ad_read (devc, 27) | 0x08);		/* Alternate freq select enabled */
+
+      if (devc->model == MD_IWAVE)
+	{			/* Some magic Interwave spesific initialization */
+	  ad_write (devc, 12, 0x6c);	/* Select codec mode 3 */
+	  ad_write (devc, 17, 0xc2);	/* Alternate feature enable */
+	}
     }
   else
     {
-      ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+      audio_flags &= ~DMA_DUPLEX;
       ad_write (devc, 9, ad_read (devc, 9) | 0x04);	/* Single DMA mode */
     }
 
   outb (0, io_Status (devc));	/* Clear pending interrupts */
 
   if (name != NULL && name[0] != 0)
-    sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
+    sprintf (dev_name,
 	     "%s (%s)", name, devc->chip_name);
   else
-    sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
+    sprintf (dev_name,
 	     "Generic audio codec (%s)", devc->chip_name);
 
-  conf_printf2 (ad1848_pcm_operations[nr_ad1848_devs].name,
+  conf_printf2 (dev_name,
 		devc->base, devc->irq, dma_playback, dma_capture);
 
-  if (num_audiodevs < MAX_AUDIO_DEV)
+  if (devc->model == MD_1848)
+    audio_flags |= DMA_HARDSTOP;
+
+  if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION,
+					dev_name,
+					&ad1848_audio_driver,
+					sizeof (struct audio_driver),
+					audio_flags,
+					ad_format_mask[devc->model],
+					devc,
+					dma_playback,
+					dma_capture)) < 0)
+    {
+      return;
+    }
+
+  if (irq > 0)
     {
-      audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs];
-      if (irq > 0)
+      irq2dev[irq] = devc->dev_no = my_dev;
+      if (snd_set_irq_handler (devc->irq, ad1848_interrupt,
+			       "SoundPort",
+			       devc->osp) < 0)
 	{
-	  audio_devs[my_dev]->devc = devc;
-	  irq2dev[irq] = devc->dev_no = my_dev;
-	  if (snd_set_irq_handler (devc->irq, ad1848_interrupt,
-				   audio_devs[my_dev]->name,
-				   devc->osp) < 0)
-	    {
-	      printk ("ad1848: IRQ in use\n");
-	    }
+	  printk ("ad1848: IRQ in use\n");
+	}
 
-#ifdef NO_IRQ_TEST
-	  if (devc->mode != MD_1848)
-	    {
-	      int             x;
-	      unsigned char   tmp = ad_read (devc, 16);
+      if (devc->model != MD_1848)
+	{
+	  int             x;
+	  unsigned char   tmp = ad_read (devc, 16);
 
-	      devc->timer_ticks = 0;
+	  devc->timer_ticks = 0;
 
-	      ad_write (devc, 21, 0x00);	/* Timer msb */
-	      ad_write (devc, 20, 0x10);	/* Timer lsb */
+	  ad_write (devc, 21, 0x00);	/* Timer msb */
+	  ad_write (devc, 20, 0x10);	/* Timer lsb */
 
-	      ad_write (devc, 16, tmp | 0x40);	/* Enable timer */
-	      for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
-	      ad_write (devc, 16, tmp & ~0x40);		/* Disable timer */
-
-	      if (devc->timer_ticks == 0)
-		printk ("[IRQ conflict???]");
-	      else
-		devc->irq_ok = 1;
+	  ad_write (devc, 16, tmp | 0x40);	/* Enable timer */
+	  for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
+	  ad_write (devc, 16, tmp & ~0x40);	/* Disable timer */
 
-	    }
+	  if (devc->timer_ticks == 0)
+	    printk ("ad1848: Interrupt test failed (IRQ%d)\n", devc->irq);
 	  else
-	    devc->irq_ok = 1;	/* Couldn't test. assume it's OK */
-#else
-	  devc->irq_ok = 1;
-#endif
+	    devc->irq_ok = 1;
 	}
-      else if (irq < 0)
-	irq2dev[-irq] = devc->dev_no = my_dev;
-
-      audio_devs[my_dev]->dmachan1 = dma_playback;
-      audio_devs[my_dev]->dmachan2 = dma_capture;
-      audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
-      audio_devs[my_dev]->devc = devc;
-      audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
-      nr_ad1848_devs++;
+      else
+	devc->irq_ok = 1;	/* Couldn't test. assume it's OK */
+    }
+  else if (irq < 0)
+    irq2dev[-irq] = devc->dev_no = my_dev;
+  nr_ad1848_devs++;
 
 #ifdef CONFIG_SEQUENCER
-      if (devc->mode != MD_1848 && devc->mode != MD_1845 && devc->irq_ok)
-	ad1848_tmr_install (my_dev);
+  if (devc->model != MD_1848 && devc->model != MD_1845 && devc->irq_ok)
+    ad1848_tmr_install (my_dev);
 #endif
 
-      if (!share_dma)
-	{
-	  if (sound_alloc_dma (dma_playback, "Sound System"))
-	    printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback);
-
-	  if (dma_capture != dma_playback)
-	    if (sound_alloc_dma (dma_capture, "Sound System (capture)"))
-	      printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture);
-	}
+  if (!share_dma)
+    {
+      if (sound_alloc_dma (dma_playback, "Sound System"))
+	printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback);
 
-      /*
-         * Toggle the MCE bit. It completes the initialization phase.
-       */
+      if (dma_capture != dma_playback)
+	if (sound_alloc_dma (dma_capture, "Sound System (capture)"))
+	  printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture);
+    }
 
-      ad_enter_MCE (devc);	/* In case the bit was off */
-      ad_leave_MCE (devc);
+  /*
+     * Toggle the MCE bit. It completes the initialization phase.
+   */
 
-      if (num_mixers < MAX_MIXER_DEV)
-	{
-	  mixer2codec[num_mixers] = my_dev + 1;
-	  audio_devs[my_dev]->mixer_dev = num_mixers;
-	  mixer_devs[num_mixers++] = &ad1848_mixer_operations;
-	  ad1848_mixer_reset (devc);
-	}
+  ad_enter_MCE (devc);		/* In case the bit was off */
+  ad_leave_MCE (devc);
+  ad1848_mixer_reset (devc);
+
+  if (sound_install_mixer (MIXER_DRIVER_VERSION,
+			   dev_name,
+			   &ad1848_mixer_operations,
+			   sizeof (struct mixer_operations),
+			   devc) >= 0)
+    {
+      audio_devs[my_dev]->mixer_dev = num_mixers - 1;
     }
-  else
-    printk ("AD1848: Too many PCM devices available\n");
 }
 
 void
@@ -1588,7 +1618,7 @@
 	}
     }
   else
-    printk ("ad1848: Can't find device to be unloaded. Base=%x\n",
+    printk ("ad1848: Can't find device to be undoaded. Base=%x\n",
 	    io_base);
 }
 
@@ -1633,21 +1663,21 @@
   if (status & 0x01)
     {
 
-      if (devc->mode != MD_1848)
+      if (devc->model != MD_1848)
 	alt_stat = ad_read (devc, 24);
 
-      if (devc->opened && devc->irq_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
+      if (devc->opened && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
 	{
 	  DMAbuf_inputintr (dev);
 	}
 
-      if (devc->opened && devc->irq_mode & PCM_ENABLE_OUTPUT &&
+      if (devc->opened && devc->audio_mode & PCM_ENABLE_OUTPUT &&
 	  alt_stat & 0x10)
 	{
 	  DMAbuf_outputintr (dev, 1);
 	}
 
-      if (devc->mode != MD_1848 && alt_stat & 0x40)	/* Timer interrupt */
+      if (devc->model != MD_1848 && alt_stat & 0x40)	/* Timer interrupt */
 	{
 	  devc->timer_ticks++;
 #ifdef CONFIG_SEQUENCER
@@ -1657,7 +1687,7 @@
 	}
     }
 
-  if (devc->mode != MD_1848)
+  if (devc->model != MD_1848)
     ad_write (devc, 24, ad_read (devc, 24) & ~alt_stat);	/* Selective ack */
   else
     outb (0, io_Status (devc));	/* Clear interrupt status */
@@ -1681,11 +1711,220 @@
   if (!opl3_detect (base, hw_config->osp))
     return;
 
-  opl3_init (0, base, hw_config->osp);
+  opl3_init (base, hw_config->osp);
   request_region (base, 4, "OPL3/OPL2");
 #endif
 }
 
+#ifdef DESKPROXL
+/*
+ * Very experimental initialization sequence for the integrated sound system
+ * of Compaq Deskpro XL. Will be moved somewhere else in future.
+ */
+
+static int
+init_deskpro (struct address_info *hw_config)
+{
+  unsigned char   tmp;
+
+  if ((tmp = inb (0xc44)) == 0xff)
+    {
+      DDB (printk ("init_deskpro: Dead port 0xc44\n"));
+      return 0;
+    }
+
+  outb (tmp | 0x04, 0xc44);	/* Select bank 1 */
+  if (inb (0xc44) != 0x04)
+    {
+      DDB (printk ("init_deskpro: Invalid bank1 signature in port 0xc44\n"));
+      return 0;
+    }
+
+/*
+ * OK. It looks like a Deskpro so let's proceed.
+ */
+
+/*
+ * I/O port 0xc44 Audio configuration register.
+ *
+ * bits 0xc0:   Audio revision bits
+ *              0x00 = Compaq Business Audio
+ *              0x40 = MS Sound System Compatible (reset default)
+ *              0x80 = Reserved
+ *              0xc0 = Reserved
+ * bit 0x20:    No Wait State Enable
+ *              0x00 = Disabled (reset default, DMA mode)
+ *              0x20 = Enabled (programmed I/O mode)
+ * bit 0x10:    MS Sound System Decode Enable
+ *              0x00 = Decoding disabled (reset default)
+ *              0x10 = Decoding enabled
+ * bit 0x08:    FM Synthesis Decode Enable
+ *              0x00 = Decoding Disabled (reset default)
+ *              0x08 = Decoding enabled
+ * bit 0x04     Bank select
+ *              0x00 = Bank 0
+ *              0x04 = Bank 1
+ * bits 0x03    MSS Base address
+ *              0x00 = 0x530 (reset default)
+ *              0x01 = 0x604
+ *              0x02 = 0xf40
+ *              0x03 = 0xe80
+ */
+
+#ifdef DEBUGXL
+  /* Debug printing */
+  printk ("Port 0xc44 (before): ");
+  outb (tmp & ~0x04, 0xc44);
+  printk ("%02x ", inb (0xc44));
+  outb (tmp | 0x04, 0xc44);
+  printk ("%02x\n", inb (0xc44));
+#endif
+
+  /* Set bank 1 of the register */
+  tmp = 0x58;			/* MSS Mode, MSS&FM decode enabled */
+
+  switch (hw_config->io_base)
+    {
+    case 0x530:
+      tmp |= 0x00;
+      break;
+    case 0x604:
+      tmp |= 0x01;
+      break;
+    case 0xf40:
+      tmp |= 0x02;
+      break;
+    case 0xe80:
+      tmp |= 0x03;
+      break;
+    default:
+      DDB (printk ("init_deskpro: Invalid MSS port %x\n",
+		   hw_config->io_base));
+      return 0;
+    }
+  outb (tmp & ~0x04, 0xc44);	/* Write to bank=0 */
+
+#ifdef DEBUGXL
+  /* Debug printing */
+  printk ("Port 0xc44 (after): ");
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  printk ("%02x ", inb (0xc44));
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  printk ("%02x\n", inb (0xc44));
+#endif
+
+/*
+ * I/O port 0xc45 FM Address Decode/MSS ID Register.
+ *
+ * bank=0, bits 0xfe:   FM synthesis Decode Comare bits 7:1 (default=0x88)
+ * bank=0, bit 0x01:    SBIC Power Control Bit
+ *                      0x00 = Powered up
+ *                      0x01 = Powered down
+ * bank=1, bits 0xfc:   MSS ID (default=0x40)
+ */
+
+#ifdef DEBUGXL
+  /* Debug printing */
+  printk ("Port 0xc45 (before): ");
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  printk ("%02x ", inb (0xc45));
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  printk ("%02x\n", inb (0xc45));
+#endif
+
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  outb (0x88, 0xc45);		/* FM base 7:0 = 0x88 */
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  outb (0x10, 0xc45);		/* MSS ID = 0x10 (MSS port returns 0x04) */
+
+#ifdef DEBUGXL
+  /* Debug printing */
+  printk ("Port 0xc45 (after): ");
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  printk ("%02x ", inb (0xc45));
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  printk ("%02x\n", inb (0xc45));
+#endif
+
+
+/*
+ * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register.
+ *
+ * bank=0, bits 0xff:   FM synthesis Decode Compare bits 15:8 (default=0x03)
+ * bank=1, bits 0xff:   Audio addressing ASIC id
+ */
+
+#ifdef DEBUGXL
+  /* Debug printing */
+  printk ("Port 0xc46 (before): ");
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  printk ("%02x ", inb (0xc46));
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  printk ("%02x\n", inb (0xc46));
+#endif
+
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  outb (0x03, 0xc46);		/* FM base 15:8 = 0x03 */
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  outb (0x11, 0xc46);		/* ASIC ID = 0x11 */
+
+#ifdef DEBUGXL
+  /* Debug printing */
+  printk ("Port 0xc46 (after): ");
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  printk ("%02x ", inb (0xc46));
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  printk ("%02x\n", inb (0xc46));
+#endif
+
+/*
+ * I/O port 0xc47 FM Address Decode Register.
+ *
+ * bank=0, bits 0xff:   Decode enble selection for various FM address bits
+ * bank=1, bits 0xff:   Reserved
+ */
+
+#ifdef DEBUGXL
+  /* Debug printing */
+  printk ("Port 0xc47 (before): ");
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  printk ("%02x ", inb (0xc47));
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  printk ("%02x\n", inb (0xc47));
+#endif
+
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  outb (0x7c, 0xc47);		/* FM decode enable bits = 0x7c */
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  outb (0x00, 0xc47);		/* Reserved bank1 = 0x00 */
+
+#ifdef DEBUGXL
+  /* Debug printing */
+  printk ("Port 0xc47 (after): ");
+  outb (tmp & ~0x04, 0xc44);	/* Select bank=0 */
+  printk ("%02x ", inb (0xc47));
+  outb (tmp | 0x04, 0xc44);	/* Select bank=1 */
+  printk ("%02x\n", inb (0xc47));
+#endif
+
+/*
+ * I/O port 0xc6f = Audio Disable Function Register
+ */
+
+#ifdef DEBUGXL
+  printk ("Port 0xc6f (before) = %02x\n", inb (0xc6f));
+#endif
+
+  outb (0x80, 0xc6f);
+
+#ifdef DEBUGXL
+  printk ("Port 0xc6f (after) = %02x\n", inb (0xc6f));
+#endif
+
+  return 1;
+}
+#endif
+
 int
 probe_ms_sound (struct address_info *hw_config)
 {
@@ -1705,9 +1944,17 @@
       return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp);
     }
 
+#ifdef DESKPROXL
+  if (hw_config->card_subtype == 2)	/* Compaq Deskpro XL */
+    {
+      if (!init_deskpro (hw_config))
+	return 0;
+    }
+#endif
+
   /*
      * Check if the IO port returns valid signature. The original MS Sound
-     * system returns 0x04 while some cards (AudioTriX Pro for example)
+     * system returns 0x04 while some cards (AudioTrix Pro for example)
      * return 0x00 or 0x0f.
    */
 
@@ -1720,6 +1967,7 @@
 	return 0;
       return 1;
     }
+  DDB (printk ("MSS signature = %x\n", tmp & 0x3f));
   if ((tmp & 0x3f) != 0x04 &&
       (tmp & 0x3f) != 0x0f &&
       (tmp & 0x3f) != 0x00)
@@ -1766,14 +2014,15 @@
   return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp);
 }
 
-long
-attach_ms_sound (long mem_start, struct address_info *hw_config)
+void
+attach_ms_sound (struct address_info *hw_config)
 {
   static char     interrupt_bits[12] =
   {
     -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
   };
-  char            bits;
+  char            bits, dma2_bit = 0;
+  int             ad_flags = 0;
 
   static char     dma_bits[4] =
   {
@@ -1782,9 +2031,11 @@
 
   int             config_port = hw_config->io_base + 0;
   int             version_port = hw_config->io_base + 3;
+  int             dma = hw_config->dma;
+  int             dma2 = hw_config->dma2;
 
-  if (!ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp))
-    return mem_start;
+  if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, hw_config->osp))
+    return;
 
   if (hw_config->card_subtype == 1)	/* Has no IRQ/DMA registers */
     {
@@ -1793,7 +2044,7 @@
 		   hw_config->dma,
 		   hw_config->dma2, 0, hw_config->osp);
       request_region (hw_config->io_base, 4, "WSS config");
-      return mem_start;
+      return;
     }
 
   /*
@@ -1802,20 +2053,51 @@
 
   bits = interrupt_bits[hw_config->irq];
   if (bits == -1)
-    return mem_start;
+    return;
 
   outb (bits | 0x40, config_port);
   if ((inb (version_port) & 0x40) == 0)
     printk ("[IRQ Conflict?]");
 
-  outb (bits | dma_bits[hw_config->dma], config_port);	/* Write IRQ+DMA setup */
+/*
+ * Handle the capture DMA channel
+ */
+
+  if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
+    {
+      if (!((dma == 0 && dma2 == 1) ||
+	    (dma == 1 && dma2 == 0) ||
+	    (dma == 3 && dma2 == 0)))
+	{			/* Unsupported combination. Try to swap channels */
+	  int             tmp = dma;
+
+	  dma = dma2;
+	  dma2 = tmp;
+	}
+
+      if ((dma == 0 && dma2 == 1) ||
+	  (dma == 1 && dma2 == 0) ||
+	  (dma == 3 && dma2 == 0))
+	{
+	  dma2_bit = 0x04;	/* Enable capture DMA */
+	}
+      else
+	{
+	  printk ("MSS: Invalid capture DMA\n");
+	  dma2 = dma;
+	}
+    }
+  else
+    dma2 = dma;
 
-  ad1848_init ("MS Sound System", hw_config->io_base + 4,
+  outb (bits | dma_bits[dma] | dma2_bit, config_port);	/* Write IRQ+DMA setup */
+
+  ad1848_init ("MSS audio codec", hw_config->io_base + 4,
 	       hw_config->irq,
-	       hw_config->dma,
-	       hw_config->dma, 0, hw_config->osp);
+	       dma,
+	       dma2, 0,
+	       hw_config->osp);
   request_region (hw_config->io_base, 4, "WSS config");
-  return mem_start;
 }
 
 void
@@ -1838,15 +2120,14 @@
   return ad1848_detect (hw_config->io_base, NULL, hw_config->osp);
 }
 
-long
-attach_pnp_ad1848 (long mem_start, struct address_info *hw_config)
+void
+attach_pnp_ad1848 (struct address_info *hw_config)
 {
 
   ad1848_init (hw_config->name, hw_config->io_base,
 	       hw_config->irq,
 	       hw_config->dma,
 	       hw_config->dma2, 0, hw_config->osp);
-  return mem_start;
 }
 
 void
@@ -1871,7 +2152,7 @@
 {
   unsigned long   flags;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
-  unsigned long   xtal_nsecs;	/* nanoseconds per xtal oscillator tick */
+  unsigned long   xtal_nsecs;	/* nanoseconds per xtal oscillaror tick */
   unsigned long   divider;
 
   save_flags (flags);
@@ -1888,7 +2169,7 @@
  * the timer divider.
  */
 
-  if (devc->mode == MD_1845)
+  if (devc->model == MD_1845)
     xtal_nsecs = 10050;
   else if (ad_read (devc, 8) & 0x01)
     xtal_nsecs = 9920;
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h
--- v2.0.0/linux/drivers/sound/ad1848_mixer.h	Sun Mar 24 22:49:40 1996
+++ linux/drivers/sound/ad1848_mixer.h	Sun Jun 30 11:43:36 1996
@@ -5,27 +5,11 @@
  */
 
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c
--- v2.0.0/linux/drivers/sound/adlib_card.c	Sun Mar 24 22:49:51 1996
+++ linux/drivers/sound/adlib_card.c	Sun Jun 30 11:43:48 1996
@@ -5,27 +5,11 @@
  */
 
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -34,14 +18,12 @@
 
 #if defined(CONFIG_YM3812)
 
-long
-attach_adlib_card (long mem_start, struct address_info *hw_config)
+void
+attach_adlib_card (struct address_info *hw_config)
 {
 
-  mem_start = opl3_init (mem_start, hw_config->io_base, hw_config->osp);
+  opl3_init (hw_config->io_base, hw_config->osp);
   request_region (hw_config->io_base, 4, "OPL3/OPL2");
-
-  return mem_start;
 }
 
 int
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c
--- v2.0.0/linux/drivers/sound/aedsp16.c	Fri Apr 12 15:52:02 1996
+++ linux/drivers/sound/aedsp16.c	Sun Jun 30 11:43:49 1996
@@ -170,7 +170,7 @@
    I think the request regions should be done this way:
 
    if (check_region(...))
-   return ERR; // I/O region already reserved
+   return ERR; // I/O region alredy reserved
    device_probe(...);
    device_attach(...);
    request_region(...); // reserve only when we are sure all is okay
@@ -178,12 +178,12 @@
    Request the 2x0h region in any case if we are using this card.
 
    NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region
-   (see code) does not mean necessarily that we are emulating sbpro.
+   (see code) does not mean necessarly that we are emulating sbpro.
    It mean that the region is the sbpro I/O ports region. We use this
    region to access the control registers of the card, and if emulating
    sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro
    registers are not used, in no way, to emulate an sbpro: they are
-   used only for configuration purposes.
+   used only for configuration pourposes.
 
    Someone pointed out that should be possible use both the SBPRO and MSS
    modes because the sound card have all the two chipsets, supposing that
@@ -222,7 +222,7 @@
    one sound card of the emulated type (read the NOTES above)
    - Moved the sb init routine from the attach to the very first
    probe in sb_card.c
-   - Rearrangements and cleanups
+   - Rearrangemens and cleanups
    - Wiped out some unnecessary code and variables: this is kernel
    code so it is better save some TEXT and DATA
    - Fixed the request_region code. We must allocate the aedsp16 (sbpro)
@@ -263,7 +263,7 @@
 #define CMD6 0x8c		/* Enable Microsoft Sound System mode   */
 
 /*
- * Offsets of AEDSP16 DSP I/O ports. The offset is added to portbase
+ * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase
  * to have the actual I/O port.
  * Register permissions are:
  * (wo) == Write Only
@@ -516,7 +516,7 @@
       if ((ret = ReadData (port)) == -1)
 	return -1;
       /*
-         * We already know how many int are stored (2), so we know when the
+         * We alredy know how many int are stored (2), so we know when the
          * string is finished.
        */
       ver[len++] = ret;
@@ -536,7 +536,7 @@
     {
       if ((ret = ReadData (port)) == -1)
 	/*
-	   * If no more data available, return to the caller, no error if len>0.
+	   * If no more data availabe, return to the caller, no error if len>0.
 	   * We have no other way to know when the string is finished.
 	 */
 	return (len ? 0 : -1);
@@ -666,7 +666,7 @@
 InitAEDSP16_SBPRO (struct address_info *hw_config)
 {
   /*
-     * If the card is already init'ed MSS, we can not init it to SBPRO too
+     * If the card is alredy init'ed MSS, we can not init it to SBPRO too
      * because the board can not emulate simultaneously MSS and SBPRO.
    */
   if (ae_init & INIT_MSS)
@@ -683,7 +683,7 @@
     {
       if (check_region (hw_config->io_base, 0x0f))
 	{
-	  printk ("AEDSP16/SBPRO I/O port region is already in use.\n");
+	  printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n");
 	  return -1;
 	}
     }
@@ -721,7 +721,7 @@
 InitAEDSP16_MSS (struct address_info *hw_config)
 {
   /*
-     * If the card is already init'ed SBPRO, we can not init it to MSS too
+     * If the card is alredy init'ed SBPRO, we can not init it to MSS too
      * because the board can not emulate simultaneously MSS and SBPRO.
    */
   if (ae_init & INIT_SBPRO)
@@ -736,7 +736,7 @@
    */
   if (check_region (hw_config->io_base, 0x08))
     {
-      printk ("MSS I/O port region is already in use.\n");
+      printk ("MSS I/O port region is alredy in use.\n");
       return -1;
     }
 
@@ -748,7 +748,7 @@
     {
       if (check_region (AEDSP16_BASE, 0x0f))
 	{
-	  printk ("AEDSP16 I/O port region is already in use.\n");
+	  printk ("AEDSP16 I/O port region is alredy in use.\n");
 	  return -1;
 	}
     }
@@ -801,7 +801,7 @@
    */
   if (check_region (hw_config->io_base, 0x02))
     {
-      printk ("SB I/O port region is already in use.\n");
+      printk ("SB I/O port region is alredy in use.\n");
       return -1;
     }
 
@@ -813,7 +813,7 @@
     {
       if (check_region (AEDSP16_BASE, 0x0f))
 	{
-	  printk ("AEDSP16 I/O port region is already in use.\n");
+	  printk ("AEDSP16 I/O port region is alredy in use.\n");
 	  return -1;
 	}
     }
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v2.0.0/linux/drivers/sound/audio.c	Mon Mar 25 09:25:26 1996
+++ linux/drivers/sound/audio.c	Sun Jun 30 11:43:50 1996
@@ -5,27 +5,11 @@
  */
 
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -51,7 +35,7 @@
 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)
     {
@@ -80,7 +64,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;
 
@@ -108,8 +92,9 @@
 
   if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1) != bits)
     {
+      printk ("audio: Can't set number of bits on device %d\n", dev);
       audio_release (dev, file);
-      return -ENXIO;
+      return -(ENXIO);
     }
 
   if (dev_type == SND_DEV_AUDIO)
@@ -143,7 +128,7 @@
 
   p = dmap->qtail;
 
-  for (i = dmap->qlen; i < dmap->nbufs; i++)
+  for (i = dmap->qlen + 1; i < dmap->nbufs; i++)
     {
       memset (dmap->raw_buf + p * dmap->fragment_size,
 	      dmap->neutral_byte,
@@ -240,7 +225,7 @@
 					    dev_nblock[dev])) < 0)
 	    {
 	      /* Handle nonblocking mode */
-	      if (dev_nblock[dev] && buf_no == -EAGAIN)
+	      if (dev_nblock[dev] && buf_no == -(EAGAIN))
 		return p;	/* No more space. Return # of accepted bytes */
 	      return buf_no;
 	    }
@@ -251,15 +236,15 @@
       if (l > (buf_size - buf_ptr))
 	l = (buf_size - buf_ptr);
 
-      if (!audio_devs[dev]->copy_from_user)
+      if (!audio_devs[dev]->d->copy_from_user)
 	{			/*
 				 * No device specific copy routine
 				 */
-	  memcpy_fromfs (&dma_buf[buf_ptr], &((buf)[p]), l);
+	  memcpy_fromfs (&dma_buf[buf_ptr], &(buf)[p], l);
 	}
       else
-	audio_devs[dev]->copy_from_user (dev,
-					 dma_buf, buf_ptr, buf, p, l);
+	audio_devs[dev]->d->copy_from_user (dev,
+					    dma_buf, buf_ptr, buf, p, l);
 
       if (local_conversion[dev] == AFMT_MU_LAW)
 	{
@@ -318,7 +303,7 @@
 	{
 	  /* Nonblocking mode handling. Return current # of bytes */
 
-	  if (dev_nblock[dev] && buf_no == -EAGAIN)
+	  if (dev_nblock[dev] && buf_no == -(EAGAIN))
 	    return p;
 
 	  return buf_no;
@@ -341,7 +326,7 @@
 	  translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
 	}
 
-      memcpy_tofs (&((buf)[p]), dmabuf, l);
+      memcpy_tofs (&(buf)[p], dmabuf, l);
 
       DMAbuf_rmchars (dev, buf_no, l);
 
@@ -366,17 +351,22 @@
       else
 	printk ("/dev/dsp%d: No coprocessor for this device\n", dev);
 
-      return -ENXIO;
+      return -(ENXIO);
     }
   else
     switch (cmd)
       {
       case SNDCTL_DSP_SYNC:
+	if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+	  return 0;
+
 	sync_output (dev);
 	return DMAbuf_ioctl (dev, cmd, arg, 0);
 	break;
 
       case SNDCTL_DSP_POST:
+	if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+	  return 0;
 	sync_output (dev);
 	return 0;
 	break;
@@ -394,8 +384,10 @@
 	return snd_ioctl_return ((int *) arg, set_format (dev, get_fs_long ((long *) arg)));
 
       case SNDCTL_DSP_GETISPACE:
+	if (!(audio_devs[dev]->open_mode & OPEN_READ))
+	  return 0;
 	if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
-	  return -EBUSY;
+	  return -(EBUSY);
 
 	{
 	  audio_buf_info  info;
@@ -405,13 +397,15 @@
 	  if (err < 0)
 	    return err;
 
-	  memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info));
+	  memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
 	  return 0;
 	}
 
       case SNDCTL_DSP_GETOSPACE:
+	if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+	  return 0;
 	if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
-	  return -EBUSY;
+	  return -(EBUSY);
 
 	{
 	  audio_buf_info  info;
@@ -426,7 +420,7 @@
 	  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));
+	  memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
 	  return 0;
 	}
 
@@ -445,15 +439,15 @@
 	  if (audio_devs[dev]->coproc)
 	    info |= DSP_CAP_COPROC;
 
-	  if (audio_devs[dev]->local_qlen)	/* Device has hidden buffers */
+	  if (audio_devs[dev]->d->local_qlen)	/* Device has hidden buffers */
 	    info |= DSP_CAP_BATCH;
 
-	  if (audio_devs[dev]->trigger)		/* Supports SETTRIGGER */
+	  if (audio_devs[dev]->d->trigger)	/* Supports SETTRIGGER */
 	    info |= DSP_CAP_TRIGGER;
 
 	  info |= DSP_CAP_MMAP;
 
-	  memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info));
+	  memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
 	  return 0;
 	}
 	break;
@@ -463,13 +457,12 @@
       }
 }
 
-long
-audio_init (long mem_start)
+void
+audio_init (void)
 {
   /*
      * NOTE! This routine could be called several times during boot.
    */
-  return mem_start;
 }
 
 int
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v2.0.0/linux/drivers/sound/configure.c	Fri Apr 12 15:52:02 1996
+++ linux/drivers/sound/configure.c	Sun Jun 30 11:43:52 1996
@@ -8,27 +8,11 @@
  * sound/configure.c  - Configuration program for the Linux Sound Driver
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 
 
@@ -83,14 +67,17 @@
 #define AUDIO_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | \
 		B (OPT_MSS) | B (OPT_GUS16) | B (OPT_GUSMAX) | B (OPT_TRIX) | \
 		B (OPT_SSCAPE)| B(OPT_MAD16) | B(OPT_CS4232))
-#define MIDI_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \
+#define MPU_DEVS (B(OPT_PSS)|\
+		  B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI))
+#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_SSCAPE))
+#define MIDI_CARDS (MPU_DEVS | UART401_DEVS | \
+		    B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \
 		    B (OPT_GUS) | B (OPT_TRIX) | B (OPT_SSCAPE)|B(OPT_MAD16) | \
 		    B (OPT_CS4232)|B(OPT_MAUI))
-#define MPU_DEVS (B(OPT_PSS)|B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|\
-		  B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI))
 #define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\
 		     B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_CS4232)|\
 		     B(OPT_SPNP))
+#define SBDSP_DEVS (B(OPT_SB)|B(OPT_SPNP)|B(OPT_MAD16))
 #define SEQUENCER_DEVS (OPT_MIDI|OPT_YM3812|OPT_ADLIB|OPT_GUS|OPT_MAUI|MIDI_CARDS)
 /*
  * Options that have been disabled for some reason (incompletely implemented
@@ -171,7 +158,7 @@
   "GUS MAX support",
   "Microsoft Sound System support",
   "Ensoniq Soundscape support",
-  "MediaTriX AudioTriX Pro support",
+  "MediaTrix AudioTrix Pro support",
   "Support for MAD16 and/or Mozart based cards",
   "Support for Crystal CS4232 based (PnP) cards",
   "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers",
@@ -235,7 +222,7 @@
   "Soundscape chipset. Such cards are being manufactured by Ensoniq,\n"
   "Spea and Reveal (Reveal makes other cards as well).\n",
 
-  "Enable this option if you have the AudioTriX Pro sound card\n"
+  "Enable this option if you have the AudioTrix Pro sound card\n"
   "manufactured by MediaTrix.\n",
 
   "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n"
@@ -294,6 +281,14 @@
   }
   ,
   {
+    "SBDSP", SBDSP_DEVS
+  }
+  ,
+  {
+    "UART401", UART401_DEVS
+  }
+  ,
+  {
     "SEQUENCER", SEQUENCER_DEVS
   }
   ,
@@ -687,11 +682,14 @@
   printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
   fprintf (stderr, "Old configuration copied.\n");
 
+#if defined(linux) || defined(Solaris)
   build_defines ();
+#endif
   old_config_used = 1;
   return 1;
 }
 
+#if defined(linux) || defined(Solaris)
 void
 build_defines (void)
 {
@@ -725,6 +723,7 @@
   fprintf (optf, "\n");
   fclose (optf);
 }
+#endif
 
 void
 ask_parameters (void)
@@ -764,7 +763,7 @@
 		"SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
 		  FMT_INT,
 		  5,
-		  "5, 6 or 7");
+		  "5, 6 or 7 (use 1 for 8 bit cards)");
 
   ask_int_choice (B (OPT_SB), "SB_MPU_BASE",
 		  "MPU401 I/O base of SB16, Jazz16 and ES1688",
@@ -948,7 +947,7 @@
 		  "Soundscape MIDI I/O base",
 		  FMT_HEX,
 		  0x330,
-		  "");
+		  "320, 330, 340 or 350");
 
   ask_int_choice (B (OPT_SSCAPE), "SSCAPE_IRQ",
 		  "Soundscape MIDI IRQ",
@@ -974,11 +973,6 @@
 		  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))
     {
@@ -995,55 +989,55 @@
     }
 
   ask_int_choice (B (OPT_TRIX), "TRIX_BASE",
-		  "AudioTriX audio I/O 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",
+		  "AudioTrix audio IRQ",
 		  FMT_INT,
 		  11,
 		  "7, 9, 10 or 11");
 
   ask_int_choice (B (OPT_TRIX), "TRIX_DMA",
-		  "AudioTriX audio DMA",
+		  "AudioTrix audio DMA",
 		  FMT_INT,
 		  0,
 		  "0, 1 or 3");
 
   ask_int_choice (B (OPT_TRIX), "TRIX_DMA2",
-		  "AudioTriX second (duplex) DMA",
+		  "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",
+		  "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",
+		  "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",
+		  "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",
+		  "AudioTrix SB IRQ",
 		  FMT_INT,
 		  7,
 		  "3, 4, 5 or 7");
 
   ask_int_choice (B (OPT_TRIX), "TRIX_SB_DMA",
-		  "AudioTriX SB DMA",
+		  "AudioTrix SB DMA",
 		  FMT_INT,
 		  1,
 		  "1 or 3");
@@ -1141,7 +1135,6 @@
 /*
  * Some "hardcoded" options
  */
-  printf ("bool 'Support for SM Wave' CONFIG_SMWAVE\n");
 
   dump_only = 1;
   selected_options = 0;
@@ -1437,7 +1430,7 @@
 	{
 	  FILE           *sf = fopen ("synth-ld.h", "w");
 
-	  fprintf (sf, "/* automatically generated by configure */\n");
+	  fprintf (sf, "/* automaticaly generated by configure */\n");
 	  fprintf (sf, "unsigned char pss_synth[1];\n"
 		   "#define pss_synthLen 0\n");
 	  fclose (sf);
@@ -1450,10 +1443,10 @@
 
       if (think_positively ("Do you want to include TRXPRO.HEX in your kernel",
 			    1,
-	"The MediaTriX AudioTrix Pro has an onboard microcontroller which\n"
+	"The MediaTrix AudioTrix Pro has an onboard microcontroller which\n"
 			    "needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
 			    "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
-			    "you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n"
+			    "you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n"
 			    "Pro will not work without this file!\n"))
 	{
 	  char            path[512];
@@ -1467,6 +1460,15 @@
 	    goto hex2hex_again;
 	  printf ("/*build hex2hex %s trix_boot.h trix_boot */\n", path);
 	  printf ("#define INCLUDE_TRIX_BOOT\n");
+	}
+    }
+
+  if (selected_options & B (OPT_MSS))
+    {
+      if (think_positively ("Support for builtin sound of Compaq Deskpro XL", 0,
+			    "Enable this if you have Compaq Deskpro XL.\n"))
+	{
+	  printf ("#define DESKPROXL\n");
 	}
     }
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c
--- v2.0.0/linux/drivers/sound/cs4232.c	Fri Apr 12 15:52:02 1996
+++ linux/drivers/sound/cs4232.c	Sun Jun 30 11:43:52 1996
@@ -5,31 +5,15 @@
  * a PnP compatible chip which contains a CS4231A codec, SB emulation,
  * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM 
  * interfaces. This is just a temporary driver until full PnP support
- * gets implemented. Just the WSS codec, FM synth and the MIDI ports are
+ * gets inplemented. Just the WSS codec, FM synth and the MIDI ports are
  * supported. Other interfaces are left uninitialized.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -67,10 +51,9 @@
   return 0;
 }
 
-long
-attach_cs4232_mpu (long mem_start, struct address_info *hw_config)
+void
+attach_cs4232_mpu (struct address_info *hw_config)
 {
-  return mem_start;
 }
 
 static unsigned char crystal_key[] =	/* A 32 byte magic key sequence */
@@ -122,7 +105,7 @@
 
   for (n = 0; n < 4; n++)
     {
-      cs_sleep_flag.mode = WK_NONE;
+      cs_sleep_flag.flags = WK_NONE;
 /*
  * Wake up the card by sending a 32 byte Crystal key to the key port.
  */
@@ -131,20 +114,20 @@
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (HZ / 10)
-	  current_set_timeout (tl = jiffies + (HZ / 10));
+	  current_set_timeout (tlimit = jiffies + (HZ / 10));
 	else
-	  tl = (unsigned long) -1;
-	cs_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	cs_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&cs_sleeper);
-	if (!(cs_sleep_flag.mode & WK_WAKEUP))
+	if (!(cs_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      cs_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      cs_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	cs_sleep_flag.mode &= ~WK_SLEEP;
+	cs_sleep_flag.flags &= ~WK_SLEEP;
       };			/* Delay */
 
 /*
@@ -179,20 +162,20 @@
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (HZ / 10)
-	  current_set_timeout (tl = jiffies + (HZ / 10));
+	  current_set_timeout (tlimit = jiffies + (HZ / 10));
 	else
-	  tl = (unsigned long) -1;
-	cs_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	cs_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&cs_sleeper);
-	if (!(cs_sleep_flag.mode & WK_WAKEUP))
+	if (!(cs_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      cs_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      cs_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	cs_sleep_flag.mode &= ~WK_SLEEP;
+	cs_sleep_flag.flags &= ~WK_SLEEP;
       };			/* Delay */
 
 /*
@@ -216,20 +199,20 @@
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (HZ / 5)
-	  current_set_timeout (tl = jiffies + (HZ / 5));
+	  current_set_timeout (tlimit = jiffies + (HZ / 5));
 	else
-	  tl = (unsigned long) -1;
-	cs_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	cs_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&cs_sleeper);
-	if (!(cs_sleep_flag.mode & WK_WAKEUP))
+	if (!(cs_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      cs_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      cs_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	cs_sleep_flag.mode &= ~WK_SLEEP;
+	cs_sleep_flag.flags &= ~WK_SLEEP;
       };			/* Delay */
 
 /*
@@ -241,28 +224,28 @@
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (HZ)
-	  current_set_timeout (tl = jiffies + (HZ));
+	  current_set_timeout (tlimit = jiffies + (HZ));
 	else
-	  tl = (unsigned long) -1;
-	cs_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	cs_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&cs_sleeper);
-	if (!(cs_sleep_flag.mode & WK_WAKEUP))
+	if (!(cs_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      cs_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      cs_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	cs_sleep_flag.mode &= ~WK_SLEEP;
+	cs_sleep_flag.flags &= ~WK_SLEEP;
       };			/* Longer delay */
     }
 
   return 0;
 }
 
-long
-attach_cs4232 (long mem_start, struct address_info *hw_config)
+void
+attach_cs4232 (struct address_info *hw_config)
 {
   int             base = hw_config->io_base, irq = hw_config->irq;
   int             dma1 = hw_config->dma, dma2 = hw_config->dma2;
@@ -297,7 +280,7 @@
       if (probe_mpu401 (&hw_config2))
 	{
 	  mpu_detected = 1;
-	  mem_start = attach_mpu401 (mem_start, &hw_config2);
+	  attach_mpu401 (&hw_config2);
 	}
       else
 	{
@@ -305,7 +288,6 @@
 	}
     }
 #endif
-  return mem_start;
 }
 
 void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- v2.0.0/linux/drivers/sound/dev_table.c	Sun Mar 24 22:49:56 1996
+++ linux/drivers/sound/dev_table.c	Sun Jun 30 11:43:53 1996
@@ -4,27 +4,11 @@
  * Device call tables.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -48,36 +32,36 @@
   return -1;
 }
 
-static long
-start_services (long mem_start)
+static void
+start_services (void)
 {
   int             soundcards_installed;
 
   if (!(soundcards_installed = sndtable_get_cardcount ()))
-    return mem_start;		/* No cards detected */
+    return;			/* No cards detected */
 
 #ifdef CONFIG_AUDIO
   if (num_audiodevs)		/* Audio devices present */
     {
-      DMAbuf_init (0);
-      audio_init (0);
+      DMAbuf_init ();
+      audio_init ();
     }
 #endif
 
 #ifdef CONFIG_MIDI
   if (num_midis)
-    MIDIbuf_init (0);
+    MIDIbuf_init ();
 #endif
 
 #ifdef CONFIG_SEQUENCER
   if (num_midis + num_synths)
-    sequencer_init (0);
+    sequencer_init ();
 #endif
-  return mem_start;
+  return;
 }
 
-static long
-start_cards (long mem_start)
+static void
+start_cards (void)
 {
   int             i, n = num_sound_cards;
   int             drv;
@@ -112,7 +96,7 @@
 	if (sound_drivers[drv].probe (&snd_installed_cards[i].config))
 	  {
 
-	    mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config);
+	    sound_drivers[drv].attach (&snd_installed_cards[i].config);
 
 	  }
 	else
@@ -123,13 +107,12 @@
 
   if (trace_init)
     printk ("Sound initialization complete\n");
-  return mem_start;
 }
 
-long
-sndtable_init (long mem_start)
+void
+sndtable_init (void)
 {
-  return start_cards (mem_start);
+  return start_cards ();
 }
 
 void
@@ -173,6 +156,7 @@
 	  {
 	    if ((drv = snd_find_driver (type)) != -1)
 	      {
+		DDB (printk (" card %d", i));
 		if (sound_drivers[drv].unload)
 		  {
 		    sound_drivers[drv].unload (&snd_installed_cards[i].config);
@@ -181,19 +165,19 @@
 	      }
 	  }
       }
+  DDB (printk ("\n"));
 
   save_flags (flags);
   cli ();
 
   restore_flags (flags);
-
 }
 
 
 int
 sndtable_probe (int unit, struct address_info *hw_config)
 {
-  int             i, sel = -1, n = num_sound_cards;
+  int             sel = -1;
 
   DDB (printk ("sndtable_probe(%d)\n", unit));
 
@@ -202,10 +186,6 @@
 
   sound_started = 1;
 
-  for (i = 0; i < n && sel == -1 && snd_installed_cards[i].card_type; i++)
-    if (snd_installed_cards[i].enabled)
-      if (snd_installed_cards[i].card_type == unit)
-	sel = i;
 
   if (sel == -1 && num_sound_cards < max_sound_cards)
     {
@@ -247,8 +227,76 @@
 
       if (sound_drivers[drv].probe (hw_config))
 	{
+	  DDB (printk ("Hardware probed OK\n"));
 	  return TRUE;
+	}
+
+      DDB (printk ("Failed to find hardware\n"));
+      snd_installed_cards[sel].enabled = 0;	/*
+						 * Mark as not detected
+						 */
+      return FALSE;
+    }
+
+  return FALSE;
+}
+
+int
+sndtable_start_card (int unit, struct address_info *hw_config)
+{
+  int             sel = -1;
+
+  DDB (printk ("sndtable_probe(%d)\n", unit));
+
+  if (!unit)
+    return TRUE;
+
+  sound_started = 1;
+
+  if (sel == -1 && num_sound_cards < max_sound_cards)
+    {
+      int             i;
+
+      i = sel = (num_sound_cards++);
+
+      snd_installed_cards[sel].card_type = unit;
+      snd_installed_cards[sel].enabled = 1;
+    }
+
+  if (sel != -1)
+    {
+      int             drv;
+
+      snd_installed_cards[sel].for_driver_use = NULL;
+      snd_installed_cards[sel].config.io_base = hw_config->io_base;
+      snd_installed_cards[sel].config.irq = hw_config->irq;
+      snd_installed_cards[sel].config.dma = hw_config->dma;
+      snd_installed_cards[sel].config.dma2 = hw_config->dma2;
+      snd_installed_cards[sel].config.name = hw_config->name;
+      snd_installed_cards[sel].config.always_detect = hw_config->always_detect;
+      snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1;
+      snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2;
+      snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype;
+      snd_installed_cards[sel].config.osp = hw_config->osp;
+
+      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));
+
+      hw_config->card_subtype =
+	snd_installed_cards[sel].config.card_subtype =
+	sound_drivers[drv].card_subtype;
+
+      if (sound_drivers[drv].probe (hw_config))
+	{
 	  DDB (printk ("Hardware probed OK\n"));
+	  sound_drivers[drv].attach (hw_config);
+	  start_services ();
+	  return TRUE;
 	}
 
       DDB (printk ("Failed to find hardware\n"));
@@ -270,8 +318,7 @@
 
   if (!unit)
     {
-      if (sndtable_init (0) != 0)
-	panic ("sound: Invalid memory allocation\n");
+      sndtable_init ();
       return TRUE;
     }
 
@@ -299,12 +346,11 @@
 	  {
 
 	    DDB (printk ("Located card - calling attach routine\n"));
-	    if (sound_drivers[drv].attach (0, hw_config) != 0)
-	      panic ("sound: Invalid memory allocation\n");
+	    sound_drivers[drv].attach (hw_config);
 
 	    DDB (printk ("attach routine finished\n"));
 	  }
-	start_services (0);
+	start_services ();
 	return TRUE;
       }
 
@@ -361,7 +407,7 @@
 
   for (i = 1; i <= ints[0]; i++)
     {
-      int             card_type, ioaddr, irq, dma, ptr, j;
+      int             card_type, ioaddr, irq, dma, dma2, ptr, j;
       unsigned int    val;
 
       val = (unsigned int) ints[i];
@@ -379,6 +425,7 @@
       ioaddr = (val & 0x000fff00) >> 8;
       irq = (val & 0x000000f0) >> 4;
       dma = (val & 0x0000000f);
+      dma2 = (val & 0xf0000000) >> 28;
 
       ptr = -1;
       for (j = 0; j < n && ptr == -1; j++)
@@ -396,7 +443,7 @@
 	  snd_installed_cards[ptr].config.io_base = ioaddr;
 	  snd_installed_cards[ptr].config.irq = irq;
 	  snd_installed_cards[ptr].config.dma = dma;
-	  snd_installed_cards[ptr].config.dma2 = -1;
+	  snd_installed_cards[ptr].config.dma2 = dma2;
 	  snd_installed_cards[ptr].config.name = NULL;
 	  snd_installed_cards[ptr].config.always_detect = 0;
 	  snd_installed_cards[ptr].config.driver_use_1 = 0;
@@ -424,4 +471,131 @@
     return (struct address_info *) NULL;
 
   return &snd_installed_cards[ptr].config;
+}
+
+
+
+int
+sound_install_audiodrv (int vers,
+			char *name,
+			struct audio_driver *driver,
+			int driver_size,
+			int flags,
+			unsigned int format_mask,
+			void *devc,
+			int dma1,
+			int dma2)
+{
+  struct audio_driver *d;
+  struct audio_operations *op;
+  int             l, num;
+
+  if (num_audiodevs >= MAX_AUDIO_DEV)
+    {
+      printk ("Sound: Too many audio drivers\n");
+      return -(EIO);
+    }
+
+  if (vers != AUDIO_DRIVER_VERSION ||
+      driver_size > sizeof (struct audio_driver))
+    {
+      printk ("Sound: Incompatible audio driver for %s\n", name);
+      return -(EIO);
+    }
+
+
+  d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_driver)));
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+
+  op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_operations)));
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (d == NULL || op == NULL)
+    {
+      printk ("Sound: Can't allocate driver for (%s)\n", name);
+      return -(ENOSPC);
+    }
+
+  memset ((char *) op, 0, sizeof (struct audio_operations));
+  if (driver_size < sizeof (struct audio_driver))
+                    memset ((char *) d, 0, sizeof (struct audio_driver));
+
+  memcpy ((char *) d, (char *) driver, driver_size);
+
+  op->d = d;
+
+  l = strlen (name) + 1;
+  if (l > sizeof (op->name))
+    l = sizeof (op->name);
+  strncpy (op->name, name, l);
+  op->name[l - 1] = 0;
+  op->flags = flags;
+  op->format_mask = format_mask;
+  op->devc = devc;
+  op->dmachan1 = dma1;
+  op->dmachan2 = dma2;
+
+/*
+ *    Hardcoded defaults
+ */
+  op->buffsize = DSP_BUFFSIZE;
+
+  audio_devs[num_audiodevs] = op;
+  num = num_audiodevs++;
+
+  DMAbuf_init ();
+  audio_init ();
+  return num;
+}
+
+int 
+sound_install_mixer (int vers,
+		     char *name,
+		     struct mixer_operations *driver,
+		     int driver_size,
+		     void *devc)
+{
+  struct mixer_operations *op;
+  int             l;
+
+  if (num_mixers >= MAX_MIXER_DEV)
+    {
+      printk ("Sound: Too many mixer drivers\n");
+      return -(EIO);
+    }
+
+  if (vers != MIXER_DRIVER_VERSION ||
+      driver_size > sizeof (struct mixer_operations))
+    {
+      printk ("Sound: Incompatible mixer driver for %s\n", name);
+      return -(EIO);
+    }
+
+
+  op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations)));
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (op == NULL)
+    {
+      printk ("Sound: Can't allocate mixer driver for (%s)\n", name);
+      return -(ENOSPC);
+    }
+
+  memset ((char *) op, 0, sizeof (struct mixer_operations));
+
+  memcpy ((char *) op, (char *) driver, driver_size);
+
+  l = strlen (name) + 1;
+  if (l > sizeof (op->name))
+    l = sizeof (op->name);
+  strncpy (op->name, name, l);
+  op->name[l - 1] = 0;
+  op->devc = devc;
+
+  mixer_devs[num_mixers] = op;
+  return num_mixers++;
 }
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.0.0/linux/drivers/sound/dev_table.h	Fri Apr 12 15:52:02 1996
+++ linux/drivers/sound/dev_table.h	Sun Jun 30 11:43:37 1996
@@ -4,33 +4,24 @@
  *	Global definitions for device call tables
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 
 
 #ifndef _DEV_TABLE_H_
 #define _DEV_TABLE_H_
 
+
+/*
+ * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h)
+ * Numbers 1000 to N are reserved for driver's internal use.
+ */
+#define SNDCARD_DESKPROXL		27	/* Compaq Deskpro XL */
+
 /*
  *	NOTE! 	NOTE!	NOTE!	NOTE!
  *
@@ -43,10 +34,10 @@
 
 struct driver_info {
 	char *driver_id;
-	int card_subtype;	/* Driver specific. Usually 0 */
+	int card_subtype;	/* Driver spesific. Usually 0 */
 	int card_type;		/*	From soundcard.h	*/
 	char *name;
-	long (*attach) (long mem_start, struct address_info *hw_config);
+	void (*attach) (struct address_info *hw_config);
 	int (*probe) (struct address_info *hw_config);
 	void (*unload) (struct address_info *hw_config);
 };
@@ -143,16 +134,7 @@
 		void *devc;		/* Driver specific info */
 	} coproc_operations;
 
-struct audio_operations {
-        char name[32];
-	int flags;
-#define NOTHING_SPECIAL 	0
-#define NEEDS_RESTART		1
-#define DMA_AUTOMODE		2
-#define DMA_DUPLEX		4
-#define DMA_PSEUDO_AUTOMODE	8
-	int  format_mask;	/* Bitmask for supported audio formats */
-	void *devc;		/* Driver specific info */
+struct audio_driver {
 	int (*open) (int dev, int mode);
 	void (*close) (int dev);
 	void (*output_block) (int dev, unsigned long buf, 
@@ -170,6 +152,23 @@
 	void (*halt_input) (int dev);
 	void (*halt_output) (int dev);
 	void (*trigger) (int dev, int bits);
+	int (*set_speed)(int dev, int speed);
+	unsigned int (*set_bits)(int dev, unsigned int bits);
+	short (*set_channels)(int dev, short channels);
+};
+
+struct audio_operations {
+        char name[32];
+	int flags;
+#define NOTHING_SPECIAL 	0x00
+#define NEEDS_RESTART		0x01
+#define DMA_AUTOMODE		0x02
+#define DMA_DUPLEX		0x04
+#define DMA_PSEUDO_AUTOMODE	0x08
+#define DMA_HARDSTOP		0x10
+	int  format_mask;	/* Bitmask for supported audio formats */
+	void *devc;		/* Driver specific info */
+	struct audio_driver *d;
 	long buffsize;
 	int dmachan1, dmachan2;
 	struct dma_buffparms *dmap_in, *dmap_out;
@@ -178,11 +177,15 @@
 	int enable_bits;
  	int open_mode;
 	int go;
+	int min_fragment;	/* 0 == unlimited */
 };
 
 struct mixer_operations {
+	char id[16];
 	char name[32];
 	int (*ioctl) (int dev, unsigned int cmd, caddr_t arg);
+	
+	void *devc;
 };
 
 struct synth_operations {
@@ -246,6 +249,7 @@
 	int (*buffer_status) (int dev);
 	int (*prefix_cmd) (int dev, unsigned char status);
 	struct coproc_operations *coproc;
+	void *devc;
 };
 
 struct sound_lowlev_timer {
@@ -290,7 +294,7 @@
 
 	struct driver_info sound_drivers[] = {
 #ifdef CONFIG_PSS
-	  {"PSSECHO", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss},
+	  {"PSS", 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
@@ -298,6 +302,8 @@
 		{"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 (AXP)",	attach_ms_sound, probe_ms_sound, unload_ms_sound},
+	/* Compaq Deskpro XL */
+		{"DESKPROXL", 2, SNDCARD_DESKPROXL,	"Compaq Deskpro XL",	attach_ms_sound, probe_ms_sound, unload_ms_sound},
 #endif
 #ifdef CONFIG_MAD16
 		{"MAD16", 0, SNDCARD_MAD16,	"MAD16/Mozart (MSS)",		attach_mad16, probe_mad16, unload_mad16},
@@ -324,11 +330,8 @@
 #endif
 #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
 #ifdef CONFIG_MIDI
-		{"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU",	attach_sb16midi, probe_sb16midi, unload_sb16midi},
+		{"UART401", 0, SNDCARD_UART401,"MPU-401 UART",	attach_uart401, probe_uart401, unload_uart401},
 #endif
 #endif
 #ifdef CONFIG_GUS16
@@ -347,9 +350,6 @@
 		{"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
-#ifdef CONFIG_SPNP
-		{"AD1848", 0, 500, "SoundPort",	attach_pnp_ad1848, probe_pnp_ad1848, unload_pnp_ad1848},
-#endif
 		{NULL, 0, 0,		"*?*",			NULL, NULL, NULL}
 	};
 
@@ -390,7 +390,7 @@
 #endif
 #ifdef CONFIG_SSCAPE
 	     {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
-	     {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
+	     {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
 #ifdef CONFIG_MAD16
 #ifndef MAD16_DMA2
@@ -412,13 +412,19 @@
 	     {SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE},
 #endif
 
+
 #ifdef CONFIG_MSS
+#	ifdef DESKPROXL
+		{SNDCARD_DESKPROXL, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
+#	else
 		{SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
+#	endif
 #	ifdef MSS2_BASE
 		{SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, -1}, SND_DEFAULT_ENABLE},
 #	endif
 #endif
 
+
 #ifdef CONFIG_PAS
 		{SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE},
 #endif
@@ -431,6 +437,9 @@
 #		define SB_DMA2		-1
 #	endif
 		{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, SB_DMA2}, SND_DEFAULT_ENABLE},
+# 	ifdef SB2_BASE
+		{SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE},
+#	endif
 #endif
 #if defined(CONFIG_MAUI) 
 		{SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
@@ -508,8 +517,9 @@
 	extern int max_sound_cards;
 
 	extern int trace_init;
+#endif	/* _DEV_TABLE_C_ */
 
-long sndtable_init(long mem_start);
+void sndtable_init(void);
 int sndtable_get_cardcount (void);
 struct address_info *sound_getconf(int card_type);
 void sound_chconf(int card_type, int ioaddr, int irq, int dma);
@@ -521,15 +531,32 @@
 
 int sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan);
 void sound_free_dmap (int dev, struct dma_buffparms *dmap);
-extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
+extern int soud_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
 void install_pnp_sounddrv(struct pnp_sounddev *drv);
 int sndtable_probe (int unit, struct address_info *hw_config);
 int sndtable_init_card (int unit, struct address_info *hw_config);
+int sndtable_start_card (int unit, struct address_info *hw_config);
 void sound_timer_init (struct sound_lowlev_timer *t, char *name);
 int sound_start_dma (	int dev, struct dma_buffparms *dmap, int chan,
 			unsigned long physaddr,
 			int count, int dma_mode, int autoinit);
 void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan);
 
-#endif	/* _DEV_TABLE_C_ */
+#define AUDIO_DRIVER_VERSION	1
+#define MIXER_DRIVER_VERSION	1
+int sound_install_audiodrv(int vers,
+			   char *name,
+			   struct audio_driver *driver,
+			   int driver_size,
+			   int flags,
+      			   unsigned int format_mask,
+			   void *devc,
+			   int dma1, 
+			   int dma2);
+int sound_install_mixer(int vers, 
+			char *name,
+			struct mixer_operations *driver,
+			int driver_size,
+			void *devc);
+
 #endif	/* _DEV_TABLE_H_ */
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v2.0.0/linux/drivers/sound/dmabuf.c	Fri Apr 19 10:08:01 1996
+++ linux/drivers/sound/dmabuf.c	Sun Jun 30 11:43:55 1996
@@ -4,27 +4,11 @@
  * The DMA buffer manager for digitized voice applications
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -59,6 +43,7 @@
 
 static void     dma_reset_output (int dev);
 static void     dma_reset_input (int dev);
+static int      dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact);
 
 static void
 reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording)
@@ -75,9 +60,9 @@
   if (dmap->fragment_size == 0)
     {				/* Compute the fragment size using the default algorithm */
 
-      sr = dsp_dev->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
-      nc = dsp_dev->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
-      sz = dsp_dev->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
+      sr = dsp_dev->d->set_speed (dev, 0);
+      nc = dsp_dev->d->set_channels (dev, 0);
+      sz = dsp_dev->d->set_bits (dev, 0);
 
       if (sz == 8)
 	dmap->neutral_byte = NEUTRAL8;
@@ -98,7 +83,7 @@
       sz /= 8;			/* #bits -> #bytes */
 
       /*
-         * Compute a buffer size for time not exceeding 1 second.
+         * Compute a buffer size for time not exeeding 1 second.
          * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
          * of sound (using the current speed, sample size and #channels).
        */
@@ -135,8 +120,8 @@
   else
     {
       /*
-         * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
-         * the buffer size computation has already been done.
+         * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
+         * the buffer sice computation has already been done.
        */
       if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))
 	dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
@@ -156,9 +141,10 @@
   dmap->nbufs = n;
   dmap->bytes_in_use = n * bsz;
 
-  memset (dmap->raw_buf,
-	  dmap->neutral_byte,
-	  dmap->bytes_in_use);
+  if (dmap->raw_buf)
+    memset (dmap->raw_buf,
+	    dmap->neutral_byte,
+	    dmap->bytes_in_use);
 
   for (i = 0; i < dmap->nbufs; i++)
     {
@@ -173,11 +159,11 @@
 {
   if (dmap == audio_devs[dev]->dmap_out)
     {
-      out_sleep_flag[dev].mode = WK_NONE;
+      out_sleep_flag[dev].flags = WK_NONE;
     }
   else
     {
-      in_sleep_flag[dev].mode = WK_NONE;
+      in_sleep_flag[dev].flags = WK_NONE;
     }
 
   dmap->flags = DMA_BUSY;	/* Other flags off */
@@ -196,7 +182,7 @@
 open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan)
 {
   if (dmap->flags & DMA_BUSY)
-    return -EBUSY;
+    return -(EBUSY);
 
   {
     int             err;
@@ -206,12 +192,12 @@
   }
 
   if (dmap->raw_buf == NULL)
-    return -ENOSPC;		/* Memory allocation failed during boot */
+    return -(ENOSPC);		/* Memory allocation failed during boot */
 
   if (sound_open_dma (chan, audio_devs[dev]->name))
     {
       printk ("Unable to grab(2) DMA%d for the audio driver\n", chan);
-      return -EBUSY;
+      return -(EBUSY);
     }
 
   dmap->open_mode = mode;
@@ -238,6 +224,37 @@
   sound_free_dmap (dev, dmap);
 }
 
+static unsigned int
+default_set_bits (int dev, unsigned int bits)
+{
+  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1);
+}
+
+static int
+default_set_speed (int dev, int speed)
+{
+  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) speed, 1);
+}
+
+static short
+default_set_channels (int dev, short channels)
+{
+  int             c = channels;
+
+  return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) c, 1);
+}
+
+static void
+check_driver (struct audio_driver *d)
+{
+  if (d->set_speed == NULL)
+    d->set_speed = default_set_speed;
+  if (d->set_bits == NULL)
+    d->set_bits = default_set_bits;
+  if (d->set_channels == NULL)
+    d->set_channels = default_set_channels;
+}
+
 int
 DMAbuf_open (int dev, int mode)
 {
@@ -247,14 +264,14 @@
 
   if (dev >= num_audiodevs)
     {
-      printk ("PCM device %d not installed.\n", dev);
-      return -ENXIO;
+      /*  printk ("PCM device %d not installed.\n", dev); */
+      return -(ENXIO);
     }
 
   if (!audio_devs[dev])
     {
-      printk ("PCM device %d not initialized\n", dev);
-      return -ENXIO;
+      /* printk ("PCM device %d not initialized\n", dev); */
+      return -(ENXIO);
     }
 
   if (!(audio_devs[dev]->flags & DMA_DUPLEX))
@@ -263,34 +280,37 @@
       audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
     }
 
-  if ((retval = audio_devs[dev]->open (dev, mode)) < 0)
+  if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0)
     return retval;
 
+  check_driver (audio_devs[dev]->d);
+
   dmap_out = audio_devs[dev]->dmap_out;
   dmap_in = audio_devs[dev]->dmap_in;
 
   if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0)
     {
-      audio_devs[dev]->close (dev);
+      audio_devs[dev]->d->close (dev);
       return retval;
     }
 
   audio_devs[dev]->enable_bits = mode;
-  if (audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in)
+  if (mode & OPEN_READ &&
+      audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in)
     if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0)
       {
-	audio_devs[dev]->close (dev);
+	audio_devs[dev]->d->close (dev);
 	close_dmap (dev, dmap_out, audio_devs[dev]->dmachan1);
 	return retval;
       }
   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;
+  in_sleep_flag[dev].flags = WK_NONE;
+  out_sleep_flag[dev].flags = WK_NONE;
 
-  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, (caddr_t) 8, 1);
-  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, (caddr_t) 1, 1);
-  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, (caddr_t) DSP_DEFAULT_SPEED, 1);
+  audio_devs[dev]->d->set_bits (dev, 8);
+  audio_devs[dev]->d->set_channels (dev, 1);
+  audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED);
 
   return 0;
 }
@@ -302,12 +322,13 @@
 
   save_flags (flags);
   cli ();
-  audio_devs[dev]->reset (dev);
+  audio_devs[dev]->d->reset (dev);
   restore_flags (flags);
 
   dma_reset_output (dev);
 
-  if (audio_devs[dev]->flags & DMA_DUPLEX)
+  if (audio_devs[dev]->flags & DMA_DUPLEX &&
+      audio_devs[dev]->open_mode & OPEN_READ)
     dma_reset_input (dev);
 }
 
@@ -319,10 +340,10 @@
   save_flags (flags);
   cli ();
   if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
-      !audio_devs[dev]->halt_output)
-    audio_devs[dev]->reset (dev);
+      !audio_devs[dev]->d->halt_output)
+    audio_devs[dev]->d->reset (dev);
   else
-    audio_devs[dev]->halt_output (dev);
+    audio_devs[dev]->d->halt_output (dev);
   restore_flags (flags);
 
   dma_init_buffers (dev, audio_devs[dev]->dmap_out);
@@ -337,10 +358,10 @@
   save_flags (flags);
   cli ();
   if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
-      !audio_devs[dev]->halt_input)
-    audio_devs[dev]->reset (dev);
+      !audio_devs[dev]->d->halt_input)
+    audio_devs[dev]->d->reset (dev);
   else
-    audio_devs[dev]->halt_input (dev);
+    audio_devs[dev]->d->halt_input (dev);
   restore_flags (flags);
 
   dma_init_buffers (dev, audio_devs[dev]->dmap_in);
@@ -360,7 +381,7 @@
       save_flags (flags);
       cli ();
 
-      audio_devs[dev]->flags |= DMA_SYNCING;
+      audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
 
       audio_devs[dev]->dmap_out->underrun_count = 0;
       while (!current_got_fatal_signal ()
@@ -369,29 +390,29 @@
 	{
 
 	  {
-	    unsigned long   tl;
+	    unsigned long   tlimit;
 
 	    if (HZ)
-	      current_set_timeout (tl = jiffies + (HZ));
+	      current_set_timeout (tlimit = jiffies + (HZ));
 	    else
-	      tl = (unsigned long) -1;
-	    out_sleep_flag[dev].mode = WK_SLEEP;
+	      tlimit = (unsigned long) -1;
+	    out_sleep_flag[dev].flags = WK_SLEEP;
 	    module_interruptible_sleep_on (&out_sleeper[dev]);
-	    if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
+	    if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
 	      {
-		if (jiffies >= tl)
-		  out_sleep_flag[dev].mode |= WK_TIMEOUT;
+		if (jiffies >= tlimit)
+		  out_sleep_flag[dev].flags |= WK_TIMEOUT;
 	      }
-	    out_sleep_flag[dev].mode &= ~WK_SLEEP;
+	    out_sleep_flag[dev].flags &= ~WK_SLEEP;
 	  };
-	  if ((out_sleep_flag[dev].mode & WK_TIMEOUT))
+	  if ((out_sleep_flag[dev].flags & WK_TIMEOUT))
 	    {
-	      audio_devs[dev]->flags &= ~DMA_SYNCING;
+	      audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
 	      restore_flags (flags);
 	      return audio_devs[dev]->dmap_out->qlen;
 	    }
 	}
-      audio_devs[dev]->flags &= ~DMA_SYNCING;
+      audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
       restore_flags (flags);
 
       /*
@@ -401,27 +422,27 @@
 
       save_flags (flags);
       cli ();
-      if (audio_devs[dev]->local_qlen)	/* Device has hidden buffers */
+      if (audio_devs[dev]->d->local_qlen)	/* Device has hidden buffers */
 	{
 	  while (!(current_got_fatal_signal ())
-		 && audio_devs[dev]->local_qlen (dev))
+		 && audio_devs[dev]->d->local_qlen (dev))
 	    {
 
 	      {
-		unsigned long   tl;
+		unsigned long   tlimit;
 
 		if (HZ)
-		  current_set_timeout (tl = jiffies + (HZ));
+		  current_set_timeout (tlimit = jiffies + (HZ));
 		else
-		  tl = (unsigned long) -1;
-		out_sleep_flag[dev].mode = WK_SLEEP;
+		  tlimit = (unsigned long) -1;
+		out_sleep_flag[dev].flags = WK_SLEEP;
 		module_interruptible_sleep_on (&out_sleeper[dev]);
-		if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
+		if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
 		  {
-		    if (jiffies >= tl)
-		      out_sleep_flag[dev].mode |= WK_TIMEOUT;
+		    if (jiffies >= tlimit)
+		      out_sleep_flag[dev].flags |= WK_TIMEOUT;
 		  }
-		out_sleep_flag[dev].mode &= ~WK_SLEEP;
+		out_sleep_flag[dev].flags &= ~WK_SLEEP;
 	      };
 	    }
 	}
@@ -442,20 +463,23 @@
       && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
     {
       dma_sync (dev);
-
-      memset (audio_devs[dev]->dmap_out->raw_buf,
-	      audio_devs[dev]->dmap_out->neutral_byte,
-	      audio_devs[dev]->dmap_out->bytes_in_use);
     }
 
+  if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
+    memset (audio_devs[dev]->dmap_out->raw_buf,
+	    audio_devs[dev]->dmap_out->neutral_byte,
+	    audio_devs[dev]->dmap_out->bytes_in_use);
+
   save_flags (flags);
   cli ();
 
-  audio_devs[dev]->close (dev);
+  audio_devs[dev]->d->halt_xfer (dev);
+  audio_devs[dev]->d->close (dev);
 
   close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
 
-  if (audio_devs[dev]->flags & DMA_DUPLEX)
+  if (audio_devs[dev]->open_mode & OPEN_READ &&
+      audio_devs[dev]->flags & DMA_DUPLEX)
     close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
   audio_devs[dev]->open_mode = 0;
 
@@ -467,6 +491,8 @@
 static int
 activate_recording (int dev, struct dma_buffparms *dmap)
 {
+  int             prepare = 0;
+
   if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
     return 0;
 
@@ -474,6 +500,7 @@
     {
       dma_reset_input (dev);
       dmap->flags &= ~DMA_RESTART;
+      prepare = 1;
     }
 
   if (dmap->dma_mode == DMODE_OUTPUT)	/* Direction change */
@@ -486,11 +513,11 @@
   if (!(dmap->flags & DMA_ALLOC_DONE))
     reorganize_buffers (dev, dmap, 1);
 
-  if (!dmap->dma_mode)
+  if (prepare || !dmap->dma_mode)
     {
       int             err;
 
-      if ((err = audio_devs[dev]->prepare_for_input (dev,
+      if ((err = audio_devs[dev]->d->prepare_for_input (dev,
 				     dmap->fragment_size, dmap->nbufs)) < 0)
 	{
 	  return err;
@@ -500,14 +527,14 @@
 
   if (!(dmap->flags & DMA_ACTIVE))
     {
-      audio_devs[dev]->start_input (dev, dmap->raw_buf_phys +
-				    dmap->qtail * dmap->fragment_size,
-				    dmap->fragment_size, 0,
+      audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys +
+				       dmap->qtail * dmap->fragment_size,
+				       dmap->fragment_size, 0,
 				 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
-				    !(dmap->flags & DMA_STARTED));
+				       !(dmap->flags & DMA_STARTED));
       dmap->flags |= DMA_ACTIVE | DMA_STARTED;
-      if (audio_devs[dev]->trigger)
-	audio_devs[dev]->trigger (dev,
+      if (audio_devs[dev]->d->trigger)
+	audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
     }
   return 0;
@@ -525,7 +552,7 @@
   if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
     {
       printk ("Sound: Can't read from mmapped device (1)\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
   else if (!dmap->qlen)
     {
@@ -542,14 +569,14 @@
       if (dontblock)
 	{
 	  restore_flags (flags);
-	  return -EAGAIN;
+	  return -(EAGAIN);
 	}
 
       if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &
 	  audio_devs[dev]->go)
 	{
 	  restore_flags (flags);
-	  return -EAGAIN;
+	  return -(EAGAIN);
 	}
 
       if (!audio_devs[dev]->go)
@@ -559,26 +586,26 @@
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (tmout)
-	  current_set_timeout (tl = jiffies + (tmout));
+	  current_set_timeout (tlimit = jiffies + (tmout));
 	else
-	  tl = (unsigned long) -1;
-	in_sleep_flag[dev].mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	in_sleep_flag[dev].flags = WK_SLEEP;
 	module_interruptible_sleep_on (&in_sleeper[dev]);
-	if (!(in_sleep_flag[dev].mode & WK_WAKEUP))
+	if (!(in_sleep_flag[dev].flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      in_sleep_flag[dev].mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      in_sleep_flag[dev].flags |= WK_TIMEOUT;
 	  }
-	in_sleep_flag[dev].mode &= ~WK_SLEEP;
+	in_sleep_flag[dev].flags &= ~WK_SLEEP;
       };
-      if ((in_sleep_flag[dev].mode & WK_TIMEOUT))
+      if ((in_sleep_flag[dev].flags & WK_TIMEOUT))
 	{
 	  printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
 	  err = EIO;
-	  audio_devs[dev]->reset (dev);
+	  audio_devs[dev]->d->reset (dev);
 	  ;
 	}
       else
@@ -587,7 +614,7 @@
   restore_flags (flags);
 
   if (!dmap->qlen)
-    return -err;
+    return -(err);
 
   *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]];
   *len = dmap->fragment_size - dmap->counts[dmap->qhead];
@@ -605,7 +632,7 @@
   if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
     {
       printk ("Sound: Can't read from mmapped device (2)\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
   else if (p >= dmap->fragment_size)
     {				/* This buffer is completely empty */
@@ -634,14 +661,14 @@
     }
 
   if (dmap->subdivision != 0 ||
-      dmap->fragment_size)	/* Too late to change */
-    return -EINVAL;
+      dmap->fragment_size)	/* Loo late to change */
+    return -(EINVAL);
 
   if (fact > MAX_REALTIME_FACTOR)
-    return -EINVAL;
+    return -(EINVAL);
 
   if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
-    return -EINVAL;
+    return -(EINVAL);
 
   dmap->subdivision = fact;
   return snd_ioctl_return ((int *) arg, fact);
@@ -653,23 +680,27 @@
   int             bytes, count;
 
   if (fact == 0)
-    return -EIO;
+    return -(EIO);
 
   if (dmap->subdivision != 0 ||
-      dmap->fragment_size)	/* Too late to change */
-    return -EINVAL;
+      dmap->fragment_size)	/* Loo late to change */
+    return -(EINVAL);
 
   bytes = fact & 0xffff;
-  count = (fact >> 16) & 0xffff;
+  count = (fact >> 16) & 0x7fff;
 
   if (count == 0)
     count = MAX_SUB_BUFFERS;
 
-  if (bytes < 4 || bytes > 17)	/* <16 || > 128k */
-    return -EINVAL;
+  if (bytes < 4 || bytes > 17)	/* <16 || > 512k */
+    return -(EINVAL);
 
   if (count < 2)
-    return -EINVAL;
+    return -(EINVAL);
+
+  if (audio_devs[dev]->min_fragment > 0)
+    if (bytes < audio_devs[dev]->min_fragment)
+      bytes = audio_devs[dev]->min_fragment;
 
 #ifdef OS_DMA_MINBITS
   if (bytes < OS_DMA_MINBITS)
@@ -687,7 +718,10 @@
     dmap->fragment_size /= 2;	/* Needs at least 2 buffers */
 
   dmap->subdivision = 1;	/* Disable SNDCTL_DSP_SUBDIVIDE */
-  return snd_ioctl_return ((int *) arg, bytes | (count << 16));
+  if (arg)
+    return snd_ioctl_return ((int *) arg, bytes | (count << 16));
+  else
+    return 0;
 }
 
 static int
@@ -727,9 +761,45 @@
 {
   struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
   struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
+  int             iarg = (int) arg;
 
   switch (cmd)
     {
+    case SOUND_PCM_WRITE_RATE:
+      if (local)
+	return audio_devs[dev]->d->set_speed (dev, (int) arg);
+      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, get_fs_long ((long *) arg)));
+
+    case SOUND_PCM_READ_RATE:
+      if (local)
+	return audio_devs[dev]->d->set_speed (dev, 0);
+      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, 0));
+
+    case SNDCTL_DSP_STEREO:
+      if (local)
+	return audio_devs[dev]->d->set_channels (dev, (int) arg + 1) - 1;
+      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_fs_long ((long *) arg) + 1) - 1);
+
+    case SOUND_PCM_WRITE_CHANNELS:
+      if (local)
+	return audio_devs[dev]->d->set_channels (dev, (short) iarg);
+      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_fs_long ((long *) arg)));
+
+    case SOUND_PCM_READ_CHANNELS:
+      if (local)
+	return audio_devs[dev]->d->set_channels (dev, 0);
+      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, 0));
+
+    case SNDCTL_DSP_SAMPLESIZE:
+      if (local)
+	return audio_devs[dev]->d->set_bits (dev, (unsigned int) arg);
+      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, get_fs_long ((long *) arg)));
+
+    case SOUND_PCM_READ_BITS:
+      if (local)
+	return audio_devs[dev]->d->set_bits (dev, 0);
+      return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, 0));
+
     case SNDCTL_DSP_RESET:
       dma_reset (dev);
       return 0;
@@ -746,7 +816,8 @@
 	{
 	  reorganize_buffers (dev, dmap_out,
 			      (audio_devs[dev]->open_mode == OPEN_READ));
-	  if (audio_devs[dev]->flags & DMA_DUPLEX)
+	  if (audio_devs[dev]->flags & DMA_DUPLEX &&
+	      audio_devs[dev]->open_mode & OPEN_READ)
 	    reorganize_buffers (dev, dmap_in,
 				(audio_devs[dev]->open_mode == OPEN_READ));
 	}
@@ -763,7 +834,8 @@
 	if (ret < 0)
 	  return ret;
 
-	if (audio_devs[dev]->flags & DMA_DUPLEX)
+	if (audio_devs[dev]->flags & DMA_DUPLEX &&
+	    audio_devs[dev]->open_mode & OPEN_READ)
 	  ret = dma_subdivide (dev, dmap_in, arg, fact);
 
 	return ret;
@@ -772,9 +844,9 @@
 
     case SNDCTL_DSP_SETDUPLEX:
       if (audio_devs[dev]->flags & DMA_DUPLEX)
-	 return 0;
+	return 0;
       else
-         return -EIO;
+	return -(EIO);
       break;
 
     case SNDCTL_DSP_SETFRAGMENT:
@@ -786,7 +858,8 @@
 	if (ret < 0)
 	  return ret;
 
-	if (audio_devs[dev]->flags & DMA_DUPLEX)
+	if (audio_devs[dev]->flags & DMA_DUPLEX &&
+	    audio_devs[dev]->open_mode & OPEN_READ)
 	  ret = dma_set_fragment (dev, dmap_in, arg, fact);
 
 	return ret;
@@ -796,18 +869,22 @@
     case SNDCTL_DSP_GETISPACE:
     case SNDCTL_DSP_GETOSPACE:
       if (!local)
-	return -EINVAL;
+	return -(EINVAL);
       else
 	{
 	  struct dma_buffparms *dmap = dmap_out;
 
 	  audio_buf_info *info = (audio_buf_info *) arg;
 
+	  if (cmd == SNDCTL_DSP_GETISPACE &&
+	      !(audio_devs[dev]->open_mode & OPEN_READ))
+	    return -(EINVAL);
+
 	  if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
 	    dmap = dmap_in;
 
 	  if (dmap->mapping_flags & DMA_MAP_MAPPED)
-	    return -EINVAL;
+	    return -(EINVAL);
 
 	  if (!(dmap->flags & DMA_ALLOC_DONE))
 	    reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
@@ -823,9 +900,9 @@
 	      else
 		{
 		  info->fragments = dmap->nbufs - dmap->qlen;
-		  if (audio_devs[dev]->local_qlen)
+		  if (audio_devs[dev]->d->local_qlen)
 		    {
-		      int             tmp = audio_devs[dev]->local_qlen (dev);
+		      int             tmp = audio_devs[dev]->d->local_qlen (dev);
 
 		      if (tmp && info->fragments)
 			tmp--;	/*
@@ -856,14 +933,14 @@
 	int             bits = get_fs_long ((long *) arg) & audio_devs[dev]->open_mode;
 	int             changed;
 
-	if (audio_devs[dev]->trigger == NULL)
-	  return -EINVAL;
+	if (audio_devs[dev]->d->trigger == NULL)
+	  return -(EINVAL);
 
 	if (!(audio_devs[dev]->flags & DMA_DUPLEX))
 	  if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))
 	    {
 	      printk ("Sound: Device doesn't have full duplex capability\n");
-	      return -EINVAL;
+	      return -(EINVAL);
 	    }
 
 	save_flags (flags);
@@ -879,10 +956,11 @@
 		reorganize_buffers (dev, dmap_in, 1);
 	      }
 
-	    if ((err = audio_devs[dev]->prepare_for_input (dev,
+	    if ((err = audio_devs[dev]->d->prepare_for_input (dev,
 			       dmap_in->fragment_size, dmap_in->nbufs)) < 0)
-	      return -err;
+	      return -(err);
 
+	    audio_devs[dev]->enable_bits = bits;
 	    activate_recording (dev, dmap_in);
 	  }
 
@@ -897,17 +975,19 @@
 		reorganize_buffers (dev, dmap_out, 0);
 	      }
 
-	    if ((err = audio_devs[dev]->prepare_for_output (dev,
+	    if ((err = audio_devs[dev]->d->prepare_for_output (dev,
 			     dmap_out->fragment_size, dmap_out->nbufs)) < 0)
-	      return -err;
+	      return -(err);
 
 	    dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
 	    DMAbuf_start_output (dev, 0, dmap_out->fragment_size);
 	  }
 
 	audio_devs[dev]->enable_bits = bits;
-	if (changed && audio_devs[dev]->trigger)
-	  audio_devs[dev]->trigger (dev, bits * audio_devs[dev]->go);
+	if (changed && audio_devs[dev]->d->trigger)
+	  {
+	    audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go);
+	  }
 	restore_flags (flags);
       }
     case SNDCTL_DSP_GETTRIGGER:
@@ -916,10 +996,10 @@
 
     case SNDCTL_DSP_SETSYNCRO:
 
-      if (!audio_devs[dev]->trigger)
-	return -EINVAL;
+      if (!audio_devs[dev]->d->trigger)
+	return -(EINVAL);
 
-      audio_devs[dev]->trigger (dev, 0);
+      audio_devs[dev]->d->trigger (dev, 0);
       audio_devs[dev]->go = 0;
       return 0;
       break;
@@ -929,13 +1009,16 @@
 	count_info      info;
 	unsigned long   flags;
 
+	if (!(audio_devs[dev]->open_mode & OPEN_READ))
+	  return -(EINVAL);
+
 	save_flags (flags);
 	cli ();
 	info.bytes = audio_devs[dev]->dmap_in->byte_counter;
 	info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in);
 	info.blocks = audio_devs[dev]->dmap_in->qlen;
 	info.bytes += info.ptr;
-	memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info));
+	memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
 
 	if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
 	  audio_devs[dev]->dmap_in->qlen = 0;	/* Acknowledge interrupts */
@@ -949,13 +1032,16 @@
 	count_info      info;
 	unsigned long   flags;
 
+	if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+	  return -(EINVAL);
+
 	save_flags (flags);
 	cli ();
 	info.bytes = audio_devs[dev]->dmap_out->byte_counter;
 	info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out);
 	info.blocks = audio_devs[dev]->dmap_out->qlen;
 	info.bytes += info.ptr;
-	memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info));
+	memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
 
 	if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
 	  audio_devs[dev]->dmap_out->qlen = 0;	/* Acknowledge interrupts */
@@ -966,7 +1052,7 @@
 
 
     default:
-      return audio_devs[dev]->ioctl (dev, cmd, arg, local);
+      return audio_devs[dev]->d->ioctl (dev, cmd, arg, local);
     }
 
 }
@@ -989,8 +1075,8 @@
 	    /* OK to start the device */
 	    audio_devs[dev]->go = 1;
 
-	    if (audio_devs[dev]->trigger)
-	      audio_devs[dev]->trigger (dev,
+	    if (audio_devs[dev]->d->trigger)
+	      audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
 	  }
 }
@@ -1012,9 +1098,9 @@
   max = dmap->max_fragments;
   len = dmap->qlen;
 
-  if (audio_devs[dev]->local_qlen)
+  if (audio_devs[dev]->d->local_qlen)
     {
-      tmp = audio_devs[dev]->local_qlen (dev);
+      tmp = audio_devs[dev]->d->local_qlen (dev);
       if (tmp && len)
 	tmp--;			/*
 				   * This buffer has been counted twice
@@ -1039,7 +1125,7 @@
   if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
     {
       printk ("Sound: Can't write to mmapped device (3)\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   if (dmap->dma_mode == DMODE_INPUT)	/* Direction change */
@@ -1063,7 +1149,7 @@
       int             err;
 
       dmap->dma_mode = DMODE_OUTPUT;
-      if ((err = audio_devs[dev]->prepare_for_output (dev,
+      if ((err = audio_devs[dev]->d->prepare_for_output (dev,
 				     dmap->fragment_size, dmap->nbufs)) < 0)
 	return err;
     }
@@ -1080,14 +1166,14 @@
       if (dontblock)
 	{
 	  restore_flags (flags);
-	  return -EAGAIN;
+	  return -(EAGAIN);
 	}
 
       if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&
 	  audio_devs[dev]->go)
 	{
 	  restore_flags (flags);
-	  return -EAGAIN;
+	  return -(EAGAIN);
 	}
 
       /*
@@ -1100,28 +1186,32 @@
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (tmout)
-	  current_set_timeout (tl = jiffies + (tmout));
+	  current_set_timeout (tlimit = jiffies + (tmout));
 	else
-	  tl = (unsigned long) -1;
-	out_sleep_flag[dev].mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	out_sleep_flag[dev].flags = WK_SLEEP;
 	module_interruptible_sleep_on (&out_sleeper[dev]);
-	if (!(out_sleep_flag[dev].mode & WK_WAKEUP))
+	if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      out_sleep_flag[dev].mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      out_sleep_flag[dev].flags |= WK_TIMEOUT;
 	  }
-	out_sleep_flag[dev].mode &= ~WK_SLEEP;
+	out_sleep_flag[dev].flags &= ~WK_SLEEP;
       };
-      if ((out_sleep_flag[dev].mode & WK_TIMEOUT))
+      if ((out_sleep_flag[dev].flags & WK_TIMEOUT))
 	{
 	  printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
 	  err = EIO;
 	  abort = 1;
 	  ;
-	  audio_devs[dev]->reset (dev);
+	  if (audio_devs[dev]->flags & DMA_AUTOMODE)
+	    dmap->flags |= DMA_RESTART;
+	  else
+	    dmap->flags &= ~DMA_RESTART;
+	  audio_devs[dev]->d->reset (dev);
 	}
       else if (current_got_fatal_signal ())
 	{
@@ -1133,7 +1223,7 @@
 
   if (!space_in_queue (dev))
     {
-      return -err;		/* Caught a signal ? */
+      return -(err);		/* Caught a signal ? */
     }
 
   *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
@@ -1176,11 +1266,14 @@
 DMAbuf_start_output (int dev, int buff_no, int l)
 {
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+  int             restart = 0;
 
   dmap->cfrag = -1;
+  if (dmap->flags & DMA_RESTART)
+    restart = 1;
 
 /*
- * Bypass buffering if using mmapped access
+ * Bypass buffering if using mmaped access
  */
 
   if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
@@ -1193,7 +1286,6 @@
   else
     {
 
-
       dmap->qlen++;
       if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
 	printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
@@ -1204,10 +1296,15 @@
 	{
 	  int             p = dmap->fragment_size * dmap->qtail;
 
+	  dmap->neutral_byte = dmap->raw_buf[p + l - 1];
+
 	  memset (dmap->raw_buf + p + l,
 		  dmap->neutral_byte,
 		  dmap->fragment_size - l);
 	}
+      else
+	dmap->neutral_byte =
+	  dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1];
 
       if ((l != dmap->fragment_size) &&
 	  ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
@@ -1222,14 +1319,19 @@
   if (!(dmap->flags & DMA_ACTIVE))
     {
       dmap->flags |= DMA_ACTIVE;
-      audio_devs[dev]->output_block (dev, dmap->raw_buf_phys +
-				     dmap->qhead * dmap->fragment_size,
-				     dmap->counts[dmap->qhead], 0,
+
+      if (restart)
+	audio_devs[dev]->d->prepare_for_output (dev,
+					  dmap->fragment_size, dmap->nbufs);
+
+      audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
+					dmap->qhead * dmap->fragment_size,
+					dmap->counts[dmap->qhead], 0,
 				 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
-				     !(dmap->flags & DMA_STARTED));
+					!(dmap->flags & DMA_STARTED));
       dmap->flags |= DMA_STARTED;
-      if (audio_devs[dev]->trigger)
-	audio_devs[dev]->trigger (dev,
+      if (audio_devs[dev]->d->trigger)
+	audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
     }
 
@@ -1254,6 +1356,12 @@
       dmap = audio_devs[dev]->dmap_in;
     }
 
+  if (dmap->raw_buf_phys == 0)
+    {
+      printk ("sound: DMA buffer == NULL\n");
+      return 0;
+    }
+
   /*
    * The count must be one less than the actual size. This is handled by
    * set_dma_addr()
@@ -1290,8 +1398,8 @@
   return count;
 }
 
-long
-DMAbuf_init (long mem_start)
+void
+DMAbuf_init (void)
 {
   int             dev;
 
@@ -1311,7 +1419,6 @@
 	  audio_devs[dev]->dmap_in =
 	    &dmaps[ndmaps++];
       }
-  return mem_start;
 }
 
 static void
@@ -1343,12 +1450,12 @@
 force_restart (int dev, struct dma_buffparms *dmap)
 {
   if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
-      audio_devs[dev]->halt_output)
-    audio_devs[dev]->halt_output (dev);
+      audio_devs[dev]->d->halt_output)
+    audio_devs[dev]->d->halt_output (dev);
   else
-    audio_devs[dev]->halt_xfer (dev);
+    audio_devs[dev]->d->halt_xfer (dev);
 
-  dmap->flags &= ~DMA_ACTIVE;
+  dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED);
   if (audio_devs[dev]->flags & DMA_AUTOMODE)
     dmap->flags |= DMA_RESTART;
   else
@@ -1370,6 +1477,7 @@
 
   unsigned long   flags;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+  int             this_fragment;
 
   dmap->byte_counter += dmap->counts[dmap->qhead];
 
@@ -1377,10 +1485,15 @@
   sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
 #endif
 
+  if (dmap->raw_buf == NULL)
+    {
+      printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n");
+      return;
+    }
+
   if (dmap->mapping_flags & DMA_MAP_MAPPED)
     {
       /* mmapped access */
-
       dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
       dmap->qlen++;		/* Yes increment it (don't decrement) */
       dmap->flags &= ~DMA_ACTIVE;
@@ -1388,12 +1501,12 @@
 
       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]->d->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,
+	  if (audio_devs[dev]->d->trigger)
+	    audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
 	}
       dmap->flags |= DMA_ACTIVE;
@@ -1408,6 +1521,7 @@
 	}
 
       dmap->qlen--;
+      this_fragment = dmap->qhead;
       dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
       dmap->flags &= ~DMA_ACTIVE;
 
@@ -1415,8 +1529,11 @@
 	{
 	  dmap->underrun_count++;
 
-	  if (!(dmap->flags & DMA_CLEAN) &&
-	      (audio_devs[dev]->flags & DMA_SYNCING || dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY))
+	  if ((!(dmap->flags & DMA_CLEAN) &&
+	       (audio_devs[dev]->dmap_out->flags & DMA_SYNCING ||
+		dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) ||
+	      audio_devs[dev]->flags & DMA_HARDSTOP)
+
 	    {
 	      dmap->qlen = 0;
 	      force_restart (dev, dmap);
@@ -1426,7 +1543,7 @@
 	  if (dmap->closing)
 	    {
 	      polish_buffers (dmap);
-	      audio_devs[dev]->halt_xfer (dev);
+	      audio_devs[dev]->d->halt_xfer (dev);
 	    }
 	  else
 	    {
@@ -1444,18 +1561,27 @@
 
       if (dmap->qlen)
 	{
+	  if (dmap->flags & DMA_CLEAN)
+	    {
+	      int             p = dmap->fragment_size * this_fragment;
+
+	      memset (dmap->raw_buf + p,
+		      dmap->neutral_byte,
+		      dmap->fragment_size);
+	    }
+
 	  if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
 	    {
 
 	      if (dmap->counts[dmap->qhead] == 0)
 		dmap->counts[dmap->qhead] = dmap->fragment_size;
 
-	      audio_devs[dev]->output_block (dev, dmap->raw_buf_phys +
+	      audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
 					  dmap->qhead * dmap->fragment_size,
-					     dmap->counts[dmap->qhead], 1,
+						dmap->counts[dmap->qhead], 1,
 				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
-	      if (audio_devs[dev]->trigger)
-		audio_devs[dev]->trigger (dev,
+	      if (audio_devs[dev]->d->trigger)
+		audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
 	    }
 	  dmap->flags |= DMA_ACTIVE;
@@ -1464,10 +1590,10 @@
 
   save_flags (flags);
   cli ();
-  if ((out_sleep_flag[dev].mode & WK_SLEEP))
+  if ((out_sleep_flag[dev].flags & WK_SLEEP))
     {
       {
-	out_sleep_flag[dev].mode = WK_WAKEUP;
+	out_sleep_flag[dev].flags = WK_WAKEUP;
 	module_wake_up (&out_sleeper[dev]);
       };
     }
@@ -1486,6 +1612,12 @@
   sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
 #endif
 
+  if (dmap->raw_buf == NULL)
+    {
+      printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n");
+      return;
+    }
+
   if (dmap->mapping_flags & DMA_MAP_MAPPED)
     {
       dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
@@ -1493,12 +1625,12 @@
 
       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]->d->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]->d->trigger)
+	    audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
 	}
 
@@ -1513,10 +1645,10 @@
 	{
 	  /* Force restart on next read */
 	  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
-	      audio_devs[dev]->halt_input)
-	    audio_devs[dev]->halt_input (dev);
+	      audio_devs[dev]->d->halt_input)
+	    audio_devs[dev]->d->halt_input (dev);
 	  else
-	    audio_devs[dev]->halt_xfer (dev);
+	    audio_devs[dev]->d->halt_xfer (dev);
 
 	  dmap->flags &= ~DMA_ACTIVE;
 	  if (audio_devs[dev]->flags & DMA_AUTOMODE)
@@ -1536,12 +1668,12 @@
 
   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]->d->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]->d->trigger)
+	audio_devs[dev]->d->trigger (dev,
 			audio_devs[dev]->enable_bits * audio_devs[dev]->go);
     }
 
@@ -1549,10 +1681,10 @@
 
   save_flags (flags);
   cli ();
-  if ((in_sleep_flag[dev].mode & WK_SLEEP))
+  if ((in_sleep_flag[dev].flags & WK_SLEEP))
     {
       {
-	in_sleep_flag[dev].mode = WK_WAKEUP;
+	in_sleep_flag[dev].flags = WK_WAKEUP;
 	module_wake_up (&in_sleeper[dev]);
       };
     }
@@ -1562,39 +1694,21 @@
 int
 DMAbuf_open_dma (int dev)
 {
+/*
+ *    NOTE!  This routine opens only the primary DMA channel (output).
+ */
+
   int             chan = audio_devs[dev]->dmachan1;
   int             err;
   unsigned long   flags;
 
   if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1)) < 0)
     {
-      return -EBUSY;
+      return -(EBUSY);
     }
   dma_init_buffers (dev, audio_devs[dev]->dmap_out);
   audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE;
   audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize;
-  /* reorganize_buffers (dev, audio_devs[dev]->dmap_out); */
-
-  if (audio_devs[dev]->flags & DMA_DUPLEX)
-    {
-      if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2)) < 0)
-	{
-	  printk ("Unable to grab DMA%d for the audio driver\n",
-		  audio_devs[dev]->dmachan2);
-	  close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
-	  return -EBUSY;
-	}
-      dma_init_buffers (dev, audio_devs[dev]->dmap_in);
-      audio_devs[dev]->dmap_in->flags |= DMA_ALLOC_DONE;
-      audio_devs[dev]->dmap_in->fragment_size = audio_devs[dev]->buffsize;
-      /* reorganize_buffers (dev, audio_devs[dev]->dmap_in); */
-    }
-  else
-    {
-      audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
-      audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
-    }
-
 
   save_flags (flags);
   cli ();
@@ -1610,10 +1724,6 @@
 {
   DMAbuf_reset_dma (dev);
   close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
-
-  if (audio_devs[dev]->flags & DMA_DUPLEX)
-    close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
-
 }
 
 void
@@ -1640,7 +1750,7 @@
 	  save_flags (flags);
 	  cli ();
 
-	  in_sleep_flag[dev].mode = WK_SLEEP;
+	  in_sleep_flag[dev].flags = WK_SLEEP;
 	  module_select_wait (&in_sleeper[dev], wait);
 	  restore_flags (flags);
 	  return 0;
@@ -1667,7 +1777,7 @@
 	  save_flags (flags);
 	  cli ();
 
-	  in_sleep_flag[dev].mode = WK_SLEEP;
+	  in_sleep_flag[dev].flags = WK_SLEEP;
 	  module_select_wait (&in_sleeper[dev], wait);
 	  restore_flags (flags);
 	  return 0;
@@ -1686,7 +1796,7 @@
 	  save_flags (flags);
 	  cli ();
 
-	  out_sleep_flag[dev].mode = WK_SLEEP;
+	  out_sleep_flag[dev].flags = WK_SLEEP;
 	  module_select_wait (&out_sleeper[dev], wait);
 	  restore_flags (flags);
 	  return 0;
@@ -1707,7 +1817,7 @@
 	  save_flags (flags);
 	  cli ();
 
-	  out_sleep_flag[dev].mode = WK_SLEEP;
+	  out_sleep_flag[dev].flags = WK_SLEEP;
 	  module_select_wait (&out_sleeper[dev], wait);
 	  restore_flags (flags);
 	  return 0;
@@ -1731,7 +1841,7 @@
 int
 DMAbuf_open (int dev, int mode)
 {
-  return -ENXIO;
+  return -(ENXIO);
 }
 
 int
@@ -1743,49 +1853,48 @@
 int
 DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
 {
-  return -EIO;
+  return -(EIO);
 }
 
 int
 DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
 {
-  return -EIO;
+  return -(EIO);
 }
 
 int
 DMAbuf_rmchars (int dev, int buff_no, int c)
 {
-  return -EIO;
+  return -(EIO);
 }
 
 int
 DMAbuf_start_output (int dev, int buff_no, int l)
 {
-  return -EIO;
+  return -(EIO);
 }
 
 int
 DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
 {
-  return -EIO;
+  return -(EIO);
 }
 
-long
-DMAbuf_init (long mem_start)
+void
+DMAbuf_init (void)
 {
-  return mem_start;
 }
 
 int
 DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
 {
-  return -EIO;
+  return -(EIO);
 }
 
 int
 DMAbuf_open_dma (int dev)
 {
-  return -ENXIO;
+  return -(ENXIO);
 }
 
 void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/finetune.h linux/drivers/sound/finetune.h
--- v2.0.0/linux/drivers/sound/finetune.h	Sun Mar 24 22:49:41 1996
+++ linux/drivers/sound/finetune.h	Sun Jun 30 11:43:37 1996
@@ -1,26 +1,10 @@
 #ifdef SEQUENCER_C
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v2.0.0/linux/drivers/sound/gus_card.c	Sun Mar 24 22:49:59 1996
+++ linux/drivers/sound/gus_card.c	Sun Jun 30 11:43:56 1996
@@ -4,27 +4,11 @@
  * Detection routine for the Gravis Ultrasound.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -45,8 +29,8 @@
 
 int            *gus_osp;
 
-long
-attach_gus_card (long mem_start, struct address_info *hw_config)
+void
+attach_gus_card (struct address_info *hw_config)
 {
   int             io_addr;
 
@@ -57,7 +41,7 @@
 						 * Try first the default
 						 */
     {
-      mem_start = gus_wave_init (mem_start, hw_config);
+      gus_wave_init (hw_config);
 
       request_region (hw_config->io_base, 16, "GUS");
       request_region (hw_config->io_base + 0x100, 12, "GUS");	/* 0x10c-> is MAX */
@@ -68,9 +52,9 @@
 	if (sound_alloc_dma (hw_config->dma2, "GUS(2)"))
 	  printk ("gus_card.c: Can't allocate DMA channel2\n");
 #ifdef CONFIG_MIDI
-      mem_start = gus_midi_init (mem_start);
+      gus_midi_init ();
 #endif
-      return mem_start;
+      return;
     }
 
 #ifndef EXCLUDE_GUS_IODETECT
@@ -88,7 +72,7 @@
 	  hw_config->io_base = io_addr;
 
 	  printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
-	  mem_start = gus_wave_init (mem_start, hw_config);
+	  gus_wave_init (hw_config);
 	  request_region (io_addr, 16, "GUS");
 	  request_region (io_addr + 0x100, 12, "GUS");	/* 0x10c-> is MAX */
 	  if (sound_alloc_dma (hw_config->dma, "GUS"))
@@ -97,16 +81,13 @@
 	    if (sound_alloc_dma (hw_config->dma2, "GUS"))
 	      printk ("gus_card.c: Can't allocate DMA channel2\n");
 #ifdef CONFIG_MIDI
-	  mem_start = gus_midi_init (mem_start);
+	  gus_midi_init ();
 #endif
-	  return mem_start;
+	  return;
 	}
 
 #endif
 
-  return mem_start;		/*
-				 * Not detected
-				 */
 }
 
 int
@@ -242,8 +223,8 @@
   return ad1848_detect (hw_config->io_base, NULL, hw_config->osp);
 }
 
-long
-attach_gus_db16 (long mem_start, struct address_info *hw_config)
+void
+attach_gus_db16 (struct address_info *hw_config)
 {
 #ifdef CONFIG_GUS
   gus_pcm_volume = 100;
@@ -255,7 +236,6 @@
 	       hw_config->dma,
 	       hw_config->dma, 0,
 	       hw_config->osp);
-  return mem_start;
 }
 
 void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c
--- v2.0.0/linux/drivers/sound/gus_midi.c	Sun Mar 24 22:49:59 1996
+++ linux/drivers/sound/gus_midi.c	Sun Jun 30 11:43:56 1996
@@ -4,27 +4,11 @@
  * The low level driver for the GUS Midi Interface.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -64,7 +48,7 @@
   if (midi_busy)
     {
       printk ("GUS: Midi busy\n");
-      return -EBUSY;
+      return -(EBUSY);
     }
 
   outb (MIDI_RESET, u_MidiControl);
@@ -196,7 +180,7 @@
 static int
 gus_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
 {
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
@@ -249,20 +233,20 @@
   NULL
 };
 
-long
-gus_midi_init (long mem_start)
+void
+gus_midi_init (void)
 {
   if (num_midis >= MAX_MIDI_DEV)
     {
       printk ("Sound: Too many midi devices detected\n");
-      return mem_start;
+      return;
     }
 
   outb (MIDI_RESET, u_MidiControl);
 
   std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &gus_midi_operations;
-  return mem_start;
+  return;
 }
 
 void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c
--- v2.0.0/linux/drivers/sound/gus_vol.c	Sun Mar 24 22:50:00 1996
+++ linux/drivers/sound/gus_vol.c	Sun Jun 30 11:43:56 1996
@@ -2,27 +2,11 @@
  * gus_vol.c - Compute volume for GUS.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.0.0/linux/drivers/sound/gus_wave.c	Tue May  7 16:22:35 1996
+++ linux/drivers/sound/gus_wave.c	Sun Jun 30 11:44:01 1996
@@ -4,31 +4,17 @@
  * Driver for the Gravis UltraSound wave table synth.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
 
+#define GUSPNP_AUTODETECT
+
 #include "sound_config.h"
 #include <linux/ultrasound.h>
 #include "gus_hw.h"
@@ -113,9 +99,9 @@
 #define GUS_DEV_PCM_DONE	2	/* PCM device, transfer done */
 #define GUS_DEV_PCM_CONTINUE	3	/* PCM device, transfer done ch. 1/2 */
 
-static int      gus_sampling_speed;
-static int      gus_sampling_channels;
-static int      gus_sampling_bits;
+static int      gus_audio_speed;
+static int      gus_audio_channels;
+static int      gus_audio_bits;
 
 static wait_handle *dram_sleeper = NULL;
 static volatile struct snd_wait dram_sleep_flag =
@@ -337,8 +323,27 @@
   return ((hi << 8) & 0xff00) | lo;
 }
 
+unsigned short
+gus_look16 (int reg)
+{				/* Reads from an indirect register (16 bit). No additional offset. */
+  unsigned long   flags;
+  unsigned char   hi, lo;
+
+  save_flags (flags);
+  cli ();
+
+  outb (reg, u_Command);
+
+  lo = inb (u_DataLo);
+  hi = inb (u_DataHi);
+
+  restore_flags (flags);
+
+  return ((hi << 8) & 0xff00) | lo;
+}
+
 void
-gus_write_addr (int reg, unsigned long address, int is16bit)
+gus_write_addr (int reg, unsigned long address, int frac, int is16bit)
 {				/* Writes an 24 bit memory address */
   unsigned long   hold_address;
   unsigned long   flags;
@@ -358,11 +363,13 @@
     }
 
   gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
-  gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
-  /* Could writing twice fix problems with GUS_VOICE_POS() ? Let's try... */
+  gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)
+	       + (frac << 5));
+  /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
   gus_delay ();
   gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
-  gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
+  gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)
+	       + (frac << 5));
   restore_flags (flags);
 }
 
@@ -488,7 +495,7 @@
       if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
 	voices[voice].offset_pending = position;
       else
-	gus_write_addr (0x0a, sample_ptrs[sample_no] + position,
+	gus_write_addr (0x0a, sample_ptrs[sample_no] + position, 0,
 			samples[sample_no].mode & WAVE_16_BITS);
 }
 
@@ -502,7 +509,7 @@
   gus_select_voice (voice);
   gus_voice_volume (0);
   gus_voice_off ();
-  gus_write_addr (0x0a, 0, 0);	/* Set current position to 0 */
+  gus_write_addr (0x0a, 0, 0, 0);	/* Set current position to 0 */
   gus_write8 (0x00, 0x03);	/* Voice off */
   gus_write8 (0x0d, 0x03);	/* Ramping off */
   voice_alloc->map[voice] = 0;
@@ -687,14 +694,6 @@
       gus_voice_init (i);	/* Turn voice off */
       gus_voice_init2 (i);
     }
-
-  inb (u_Status);		/* Touch the status register */
-
-  gus_look8 (0x41);		/* Clear any pending DMA IRQs */
-  gus_look8 (0x49);		/* Clear any pending sample IRQs */
-
-  gus_read8 (0x0f);		/* Clear pending IRQs */
-
 }
 
 static void
@@ -838,14 +837,194 @@
 
   gus_select_voice (0);		/* This disables writes to IRQ/DMA reg */
 
-  gusintr (0, NULL, NULL);	/* Serve pending interrupts */
+  gusintr (gus_irq, NULL, NULL);	/* Serve pending interrupts */
+
+  inb (u_Status);		/* Touch the status register */
+
+  gus_look8 (0x41);		/* Clear any pending DMA IRQs */
+  gus_look8 (0x49);		/* Clear any pending sample IRQs */
+
+  gus_read8 (0x0f);		/* Clear pending IRQs */
+
   restore_flags (flags);
 }
 
+static void
+pnp_mem_init (void)
+{
+#include "iwmem.h"
+#define CHUNK_SIZE (256*1024)
+#define BANK_SIZE (4*1024*1024)
+#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE)
+
+  int             bank, chunk, addr, total = 0;
+  int             bank_sizes[4];
+  int             i, j, bits = -1, nbanks = 0;
+
+/*
+ * This routine determines what kind of RAM is installed in each of the four
+ * SIMM banks and configures the DRAM address decode logic accordingly.
+ */
+
+/*
+ *    Place the chip into enhanced mode
+ */
+  gus_write8 (0x19, gus_read8 (0x19) | 0x01);
+  gus_write8 (0x53, gus_look8 (0x53) & ~0x02);	/* Select DRAM I/O access */
+
+/*
+ * Set memory configuration to 4 DRAM banks of 4M in each (16M total).
+ */
+
+  gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | 0x000c);
+
+/*
+ * Perform the DRAM size detection for each bank individually.
+ */
+  for (bank = 0; bank < 4; bank++)
+    {
+      int             size = 0;
+
+      addr = bank * BANK_SIZE;
+
+      /* Clean check points of each chunk */
+      for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
+	{
+	  gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00);
+	  gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00);
+	}
+
+      /* Write a value to each chunk point and verify the result */
+      for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
+	{
+	  gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x55);
+	  gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0xAA);
+
+	  if (gus_peek (addr + chunk * CHUNK_SIZE + 0L) == 0x55 &&
+	      gus_peek (addr + chunk * CHUNK_SIZE + 1L) == 0xAA)
+	    {			/* OK. There is RAM. Now check for possible shadows */
+	      int             ok = 1, chunk2;
+
+	      for (chunk2 = 0; ok && chunk2 < chunk; chunk2++)
+		if (gus_peek (addr + chunk2 * CHUNK_SIZE + 0L) ||
+		    gus_peek (addr + chunk2 * CHUNK_SIZE + 1L))
+		  ok = 0;	/* Addressing wraps */
+
+	      if (ok)
+		size = (chunk + 1) * CHUNK_SIZE;
+	    }
+	  gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00);
+	  gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00);
+	}
+
+      bank_sizes[bank] = size;
+      if (size)
+	nbanks = bank + 1;
+      DDB (printk ("Interwave: Bank %d, size=%dk\n", bank, size / 1024));
+    }
+
+  if (nbanks == 0)		/* No RAM - Give up */
+    {
+      printk ("Sound: An Interwave audio chip detected but no DRAM\n");
+      printk ("Sound: Unable to work with this card.\n");
+      gus_write8 (0x19, gus_read8 (0x19) & ~0x01);
+      return;
+    }
+/*
+ * Now we know how much DRAM there is in each bank. The next step is
+ * to find a DRAM size encoding (0 to 12) which is best for the combination
+ * we have.
+ *
+ * First try if any of the possible alternatives matches exactly the amount
+ * of memory we have.
+ */
+
+  for (i = 0; bits == -1 && i < 13; i++)
+    {
+      bits = i;
+
+      for (j = 0; bits != -1 && j < 4; j++)
+	if (mem_decode[i][j] != bank_sizes[j])
+	  bits = -1;		/* No hit */
+    }
+
+/*
+ * If necessary, try to find a combination where other than the last
+ * bank matches our configuration and the last bank is left oversized.
+ * In this way we don't leave holes in the middle of memory.
+ */
+  if (bits == -1)		/* No luck yet */
+    for (i = 0; bits == -1 && i < 13; i++)
+      {
+	bits = i;
+
+	for (j = 0; bits != -1 && j < nbanks - 1; j++)
+	  if (mem_decode[i][j] != bank_sizes[j])
+	    bits = -1;		/* No hit */
+	if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1])
+	  bits = -1;		/* The last bank is too small */
+      }
+
+/*
+ * The last resort is to search for a combination where the last bank is
+ * smaller than the actual SIMM. This leaves some memory in the last bank
+ * unused but doesn't leave holes in the DRAM address space.
+ */
+  if (bits == -1)		/* No luck yet */
+    {
+      for (i = 0; bits == -1 && i < 13; i++)
+	{
+	  bits = i;
+
+	  for (j = 0; bits != -1 && j < nbanks - 1; j++)
+	    if (mem_decode[i][j] != bank_sizes[j])
+	      bits = -1;	/* No hit */
+	}
+
+      if (bits != -1)
+	{
+	  printk ("Interwave: Can't use all installed RAM.\n");
+	  printk ("Interwave: Try reordering SIMMS.\n");
+	}
+    }
+
+  if (bits == -1)
+    {
+      printk ("Interwave: Can't find working DRAM encoding.\n");
+      printk ("Interwave: Defaulting to 256k. Try reordering SIMMS.\n");
+      bits = 0;
+    }
+
+  DDB (printk ("Interwave: Selecting DRAM addressing mode %d\n", bits));
+
+  for (bank = 0; bank < 4; bank++)
+    {
+      DDB (printk ("  Bank %d, mem=%dk (limit %dk)\n",
+		   bank, bank_sizes[bank] / 1024,
+		   mem_decode[bits][bank] / 1024));
+
+      if (bank_sizes[bank] > mem_decode[bits][bank])
+	total += mem_decode[bits][bank];
+      else
+	total += bank_sizes[bank];
+    }
+
+  DDB (printk ("Total %dk of DRAM (enhanced mode)\n", total / 1024));
+/*
+ *    Set the memory addressing mode.
+ */
+  gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | bits);
+
+/*
+ *    Return the chip back to GUS compatible mode.
+ */
+  gus_write8 (0x19, gus_read8 (0x19) & ~0x01);
+}
+
 int
 gus_wave_detect (int baseaddr)
 {
-  unsigned long   i;
+  unsigned long   i, max_mem = 1024L;
   unsigned long   loc;
 
   gus_base = baseaddr;
@@ -858,6 +1037,9 @@
   gus_delay ();
   gus_delay ();
 
+  if (gus_pnp_flag)
+    pnp_mem_init ();
+
   /* See if there is first block there.... */
   gus_poke (0L, 0xaa);
   if (gus_peek (0L) != 0xaa)
@@ -865,7 +1047,7 @@
 
   /* Now zero it out so that I can check for mirroring .. */
   gus_poke (0L, 0x00);
-  for (i = 1L; i < 1024L; i++)
+  for (i = 1L; i < max_mem; i++)
     {
       int             n, failed;
 
@@ -901,7 +1083,7 @@
     {
     case SNDCTL_SYNTH_INFO:
       gus_info.nr_voices = nr_voices;
-      memcpy_tofs ((&((char *) arg)[0]), &gus_info, sizeof (gus_info));
+      memcpy_tofs (&((char *) arg)[0], &gus_info, sizeof (gus_info));
       return 0;
       break;
 
@@ -918,7 +1100,7 @@
       return gus_mem_size - free_mem_ptr - 32;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 }
 
@@ -928,10 +1110,10 @@
   int             sample_no;
 
   if (instr_no < 0 || instr_no > MAX_PATCH)
-    return -EINVAL;
+    return -(EINVAL);
 
   if (voice < 0 || voice > 31)
-    return -EINVAL;
+    return -(EINVAL);
 
   if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
     {
@@ -945,14 +1127,14 @@
   if (sample_no == NOT_SAMPLE)
     {
       printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
-      return -EINVAL;		/* Patch not defined */
+      return -(EINVAL);		/* Patch not defined */
     }
 
   if (sample_ptrs[sample_no] == -1)	/* Sample not loaded */
     {
       printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n",
 	      sample_no, instr_no, voice);
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   sample_map[voice] = sample_no;
@@ -1206,7 +1388,7 @@
   if (voice < 0 || voice > 31)
     {
       printk ("GUS: Invalid voice\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   if (note_num == 255)
@@ -1224,12 +1406,12 @@
 
   if ((patch = patch_map[voice]) == -1)
     {
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   if ((samplep = patch_table[patch]) == NOT_SAMPLE)
     {
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   note_freq = note_to_freq (note_num);
@@ -1343,10 +1525,10 @@
 
   if (samples[sample].mode & WAVE_LOOP_BACK)
     gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
-		    voices[voice].offset_pending, is16bits);	/* start=end */
+		    voices[voice].offset_pending, 0, is16bits);		/* start=end */
   else
     gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
-		    is16bits);	/* Sample start=begin */
+		    0, is16bits);	/* Sample start=begin */
 
   if (samples[sample].mode & WAVE_LOOPING)
     {
@@ -1359,13 +1541,16 @@
 	{
 	  gus_write_addr (0x0a,
 			  sample_ptrs[sample] + samples[sample].loop_end -
-			  voices[voice].offset_pending, is16bits);
+			  voices[voice].offset_pending,
+			  (samples[sample].fractions >> 4) & 0x0f, is16bits);
 	  mode |= 0x40;
 	}
 
       gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start,
+		      samples[sample].fractions & 0x0f,
 		      is16bits);	/* Loop start location */
-      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end,
+      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len,
+		      (samples[sample].fractions >> 4) & 0x0f,
 		      is16bits);	/* Loop end location */
     }
   else
@@ -1374,8 +1559,9 @@
       voices[voice].loop_irq_mode = LMODE_FINISH;	/* Ramp down at the end */
       voices[voice].loop_irq_parm = 1;
       gus_write_addr (0x02, sample_ptrs[sample],
-		      is16bits);	/* Loop start location */
-      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1,
+		      0, is16bits);	/* Loop start location */
+      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end - 1,
+		      (samples[sample].fractions >> 4) & 0x0f,
 		      is16bits);	/* Loop end location */
     }
   gus_voice_freq (freq);
@@ -1435,7 +1621,7 @@
 	  gus_select_voice (voice);	/* Reselect the voice (just to be sure) */
 	}
 
-      if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065))
+      if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < (unsigned) 2065))
 	{
 	  ret_val = guswave_start_note2 (dev, voice, note_num, volume);
 	}
@@ -1474,24 +1660,26 @@
   int             err;
 
   if (gus_busy)
-    return -EBUSY;
+    return -(EBUSY);
 
-  gus_initialize ();
   voice_alloc->timestamp = 0;
 
   if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
     {
-      printk ("GUS: Loading samples without DMA\n");
+      /* printk ("GUS: Loading saples without DMA\n"); */
       gus_no_dma = 1;		/* Upload samples using PIO */
     }
   else
     gus_no_dma = 0;
 
-  dram_sleep_flag.mode = WK_NONE;
+  dram_sleep_flag.flags = WK_NONE;
   gus_busy = 1;
   active_device = GUS_DEV_WAVE;
 
+  gusintr (gus_irq, NULL, NULL);	/* Serve pending interrupts */
+  gus_initialize ();
   gus_reset ();
+  gusintr (gus_irq, NULL, NULL);	/* Serve pending interrupts */
 
   return 0;
 }
@@ -1522,13 +1710,13 @@
   if (format != GUS_PATCH)
     {
       printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   if (count < sizeof_patch)
     {
       printk ("GUS Error: Patch header too short\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   count -= sizeof_patch;
@@ -1536,7 +1724,7 @@
   if (free_sample >= MAX_SAMPLE)
     {
       printk ("GUS: Sample table full\n");
-      return -ENOSPC;
+      return -(ENOSPC);
     }
 
   /*
@@ -1544,14 +1732,14 @@
    * been transferred already.
    */
 
-  memcpy_fromfs (&((char *) &patch)[offs], &((addr)[offs]), sizeof_patch - offs);
+  memcpy_fromfs (&((char *) &patch)[offs], &(addr)[offs], sizeof_patch - offs);
 
   instr = patch.instr_no;
 
   if (instr < 0 || instr > MAX_PATCH)
     {
       printk ("GUS: Invalid patch number %d\n", instr);
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   if (count < patch.len)
@@ -1564,7 +1752,7 @@
   if (patch.len <= 0 || patch.len > gus_mem_size)
     {
       printk ("GUS: Invalid sample length %d\n", (int) patch.len);
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   if (patch.mode & WAVE_LOOPING)
@@ -1572,13 +1760,13 @@
       if (patch.loop_start < 0 || patch.loop_start >= patch.len)
 	{
 	  printk ("GUS: Invalid loop start\n");
-	  return -EINVAL;
+	  return -(EINVAL);
 	}
 
       if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
 	{
 	  printk ("GUS: Invalid loop end\n");
-	  return -EINVAL;
+	  return -(EINVAL);
 	}
     }
 
@@ -1594,7 +1782,7 @@
       if (patch.len >= GUS_BANK_SIZE)
 	{
 	  printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
-	  return -ENOSPC;
+	  return -(ENOSPC);
 	}
 
       if ((free_mem_ptr / GUS_BANK_SIZE) !=
@@ -1604,14 +1792,14 @@
 	  ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
 
 	  if ((tmp_mem + patch.len) > gus_mem_size)
-	    return -ENOSPC;
+	    return -(ENOSPC);
 
 	  free_mem_ptr = tmp_mem;	/* This leaves unusable memory */
 	}
     }
 
   if ((free_mem_ptr + patch.len) > gus_mem_size)
-    return -ENOSPC;
+    return -(ENOSPC);
 
   sample_ptrs[free_sample] = free_mem_ptr;
 
@@ -1622,6 +1810,11 @@
   if (patch.mode & WAVE_ENVELOPES)
     patch.mode &= ~WAVE_TREMOLO;
 
+  if (!(patch.mode & WAVE_FRACTIONS))
+    {
+      patch.fractions = 0;
+    }
+
   memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
 
   /*
@@ -1641,7 +1834,6 @@
 
   while (left)			/* Not completely transferred yet */
     {
-      /* blk_sz = audio_devs[gus_devnum]->buffsize; */
       blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
       if (blk_sz > left)
 	blk_sz = left;
@@ -1658,7 +1850,7 @@
 	  blk_sz = blk_end - target;
 	}
 
-      if (gus_pnp_flag || gus_no_dma)
+      if (gus_no_dma)
 	{
 	  /*
 	   * For some reason the DMA is not possible. We have to use PIO.
@@ -1683,11 +1875,17 @@
 	  unsigned char   dma_command;
 	  unsigned long   flags;
 
+	  if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL)
+	    {
+	      printk ("GUS: DMA buffer == NULL\n");
+	      return -(EINVAL);
+	    }
+
 	  /*
 	   * OK, move now. First in and then out.
 	   */
 
-	  memcpy_fromfs (audio_devs[gus_devnum]->dmap_out->raw_buf, &((addr)[sizeof_patch + src_offs]), blk_sz);
+	  memcpy_fromfs (audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz);
 
 	  save_flags (flags);
 	  cli ();
@@ -1734,22 +1932,22 @@
 
 
 	  {
-	    unsigned long   tl;
+	    unsigned long   tlimit;
 
 	    if (HZ)
-	      current_set_timeout (tl = jiffies + (HZ));
+	      current_set_timeout (tlimit = jiffies + (HZ));
 	    else
-	      tl = (unsigned long) -1;
-	    dram_sleep_flag.mode = WK_SLEEP;
+	      tlimit = (unsigned long) -1;
+	    dram_sleep_flag.flags = WK_SLEEP;
 	    module_interruptible_sleep_on (&dram_sleeper);
-	    if (!(dram_sleep_flag.mode & WK_WAKEUP))
+	    if (!(dram_sleep_flag.flags & WK_WAKEUP))
 	      {
-		if (jiffies >= tl)
-		  dram_sleep_flag.mode |= WK_TIMEOUT;
+		if (jiffies >= tlimit)
+		  dram_sleep_flag.flags |= WK_TIMEOUT;
 	      }
-	    dram_sleep_flag.mode &= ~WK_SLEEP;
+	    dram_sleep_flag.flags &= ~WK_SLEEP;
 	  };
-	  if ((dram_sleep_flag.mode & WK_TIMEOUT))
+	  if ((dram_sleep_flag.flags & WK_TIMEOUT))
 	    printk ("GUS: DMA Transfer timed out\n");
 	  restore_flags (flags);
 	}
@@ -1935,11 +2133,11 @@
 }
 
 static int
-gus_sampling_set_speed (int speed)
+gus_audio_set_speed (int speed)
 {
 
   if (speed <= 0)
-    speed = gus_sampling_speed;
+    speed = gus_audio_speed;
 
   if (speed < 4000)
     speed = 4000;
@@ -1947,36 +2145,37 @@
   if (speed > 44100)
     speed = 44100;
 
-  gus_sampling_speed = speed;
+  gus_audio_speed = speed;
 
   if (only_read_access)
     {
       /* Compute nearest valid recording speed  and return it */
 
-      speed = (9878400 / (gus_sampling_speed + 2)) / 16;
+      /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */
+      speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
       speed = (9878400 / (speed * 16)) - 2;
     }
   return speed;
 }
 
 static int
-gus_sampling_set_channels (int channels)
+gus_audio_set_channels (int channels)
 {
   if (!channels)
-    return gus_sampling_channels;
+    return gus_audio_channels;
   if (channels > 2)
     channels = 2;
   if (channels < 1)
     channels = 1;
-  gus_sampling_channels = channels;
+  gus_audio_channels = channels;
   return channels;
 }
 
 static int
-gus_sampling_set_bits (int bits)
+gus_audio_set_bits (int bits)
 {
   if (!bits)
-    return gus_sampling_bits;
+    return gus_audio_bits;
 
   if (bits != 8 && bits != 16)
     bits = 8;
@@ -1984,70 +2183,70 @@
   if (only_8_bits)
     bits = 8;
 
-  gus_sampling_bits = bits;
+  gus_audio_bits = bits;
   return bits;
 }
 
 static int
-gus_sampling_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
+gus_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
 {
   switch (cmd)
     {
     case SOUND_PCM_WRITE_RATE:
       if (local)
-	return gus_sampling_set_speed ((int) arg);
-      return snd_ioctl_return ((int *) arg, gus_sampling_set_speed (get_fs_long ((long *) arg)));
+	return gus_audio_set_speed ((int) arg);
+      return snd_ioctl_return ((int *) arg, gus_audio_set_speed (get_fs_long ((long *) arg)));
       break;
 
     case SOUND_PCM_READ_RATE:
       if (local)
-	return gus_sampling_speed;
-      return snd_ioctl_return ((int *) arg, gus_sampling_speed);
+	return gus_audio_speed;
+      return snd_ioctl_return ((int *) arg, gus_audio_speed);
       break;
 
     case SNDCTL_DSP_STEREO:
       if (local)
-	return gus_sampling_set_channels ((int) arg + 1) - 1;
-      return snd_ioctl_return ((int *) arg, gus_sampling_set_channels (get_fs_long ((long *) arg) + 1) - 1);
+	return gus_audio_set_channels ((int) arg + 1) - 1;
+      return snd_ioctl_return ((int *) arg, gus_audio_set_channels (get_fs_long ((long *) arg) + 1) - 1);
       break;
 
     case SOUND_PCM_WRITE_CHANNELS:
       if (local)
-	return gus_sampling_set_channels ((int) arg);
-      return snd_ioctl_return ((int *) arg, gus_sampling_set_channels (get_fs_long ((long *) arg)));
+	return gus_audio_set_channels ((int) arg);
+      return snd_ioctl_return ((int *) arg, gus_audio_set_channels (get_fs_long ((long *) arg)));
       break;
 
     case SOUND_PCM_READ_CHANNELS:
       if (local)
-	return gus_sampling_channels;
-      return snd_ioctl_return ((int *) arg, gus_sampling_channels);
+	return gus_audio_channels;
+      return snd_ioctl_return ((int *) arg, gus_audio_channels);
       break;
 
     case SNDCTL_DSP_SETFMT:
       if (local)
-	return gus_sampling_set_bits ((int) arg);
-      return snd_ioctl_return ((int *) arg, gus_sampling_set_bits (get_fs_long ((long *) arg)));
+	return gus_audio_set_bits ((int) arg);
+      return snd_ioctl_return ((int *) arg, gus_audio_set_bits (get_fs_long ((long *) arg)));
       break;
 
     case SOUND_PCM_READ_BITS:
       if (local)
-	return gus_sampling_bits;
-      return snd_ioctl_return ((int *) arg, gus_sampling_bits);
+	return gus_audio_bits;
+      return snd_ioctl_return ((int *) arg, gus_audio_bits);
 
     case SOUND_PCM_WRITE_FILTER:	/* NOT POSSIBLE */
-      return snd_ioctl_return ((int *) arg, -EINVAL);
+      return snd_ioctl_return ((int *) arg, -(EINVAL));
       break;
 
     case SOUND_PCM_READ_FILTER:
-      return snd_ioctl_return ((int *) arg, -EINVAL);
+      return snd_ioctl_return ((int *) arg, -(EINVAL));
       break;
 
     }
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
-gus_sampling_reset (int dev)
+gus_audio_reset (int dev)
 {
   if (recording_active)
     {
@@ -2057,11 +2256,16 @@
 }
 
 static int
-gus_sampling_open (int dev, int mode)
+gus_audio_open (int dev, int mode)
 {
   if (gus_busy)
-    return -EBUSY;
+    return -(EBUSY);
 
+  if (gus_pnp_flag && mode & OPEN_READ)
+    {
+      printk ("Sound: This audio device doesn't have recording capability\n");
+      return -(EIO);
+    }
   gus_initialize ();
 
   gus_busy = 1;
@@ -2090,7 +2294,7 @@
 }
 
 static void
-gus_sampling_close (int dev)
+gus_audio_close (int dev)
 {
   gus_reset ();
   gus_busy = 0;
@@ -2107,13 +2311,13 @@
 }
 
 static void
-gus_sampling_update_volume (void)
+gus_audio_update_volume (void)
 {
   unsigned long   flags;
   int             voice;
 
   if (pcm_active && pcm_opened)
-    for (voice = 0; voice < gus_sampling_channels; voice++)
+    for (voice = 0; voice < gus_audio_channels; voice++)
       {
 	save_flags (flags);
 	cli ();
@@ -2129,7 +2333,7 @@
 play_next_pcm_block (void)
 {
   unsigned long   flags;
-  int             speed = gus_sampling_speed;
+  int             speed = gus_audio_speed;
   int             this_one, is16bits, chn;
   unsigned long   dram_loc;
   unsigned char   mode[2], ramp_mode[2];
@@ -2139,7 +2343,7 @@
 
   this_one = pcm_head;
 
-  for (chn = 0; chn < gus_sampling_channels; chn++)
+  for (chn = 0; chn < gus_audio_channels; chn++)
     {
       mode[chn] = 0x00;
       ramp_mode[chn] = 0x03;	/* Ramping and rollover off */
@@ -2150,7 +2354,7 @@
 	  voices[chn].loop_irq_mode = LMODE_PCM;
 	}
 
-      if (gus_sampling_bits != 8)
+      if (gus_audio_bits != 8)
 	{
 	  is16bits = 1;
 	  mode[chn] |= 0x04;	/* 16 bit data */
@@ -2177,7 +2381,7 @@
       gus_select_voice (chn);
       gus_voice_freq (speed);
 
-      if (gus_sampling_channels == 1)
+      if (gus_audio_channels == 1)
 	gus_voice_balance (7);	/* mono */
       else if (chn == 0)
 	gus_voice_balance (0);	/* left */
@@ -2198,17 +2402,17 @@
 	  gus_voice_volume (1530 + (25 * gus_pcm_volume));
 	  gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
 
-	  gus_write_addr (0x0a, dram_loc, is16bits);	/* Starting position */
-	  gus_write_addr (0x02, chn * pcm_banksize, is16bits);	/* Loop start */
+	  gus_write_addr (0x0a, dram_loc, 0, is16bits);		/* Starting position */
+	  gus_write_addr (0x02, chn * pcm_banksize, 0, is16bits);	/* Loop start */
 
 	  if (chn != 0)
 	    gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
-			    is16bits);	/* Loop end location */
+			    0, is16bits);	/* Loop end location */
 	}
 
       if (chn == 0)
 	gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1,
-			is16bits);	/* Loop end location */
+			0, is16bits);	/* Loop end location */
       else
 	mode[chn] |= 0x08;	/* Enable looping */
 
@@ -2227,7 +2431,7 @@
 	  else
 	    {
 	      gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
-			      is16bits);	/* Loop end location */
+			      0, is16bits);	/* Loop end location */
 	      mode[chn] &= ~0x08;	/* Disable looping */
 	    }
 	}
@@ -2235,7 +2439,7 @@
       restore_flags (flags);
     }
 
-  for (chn = 0; chn < gus_sampling_channels; chn++)
+  for (chn = 0; chn < gus_audio_channels; chn++)
     {
       save_flags (flags);
       cli ();
@@ -2269,7 +2473,7 @@
   save_flags (flags);
   cli ();
 
-  count = total_count / gus_sampling_channels;
+  count = total_count / gus_audio_channels;
 
   if (chn == 0)
     {
@@ -2302,7 +2506,7 @@
 
   dma_command = 0x21;		/* IRQ enable, DMA start */
 
-  if (gus_sampling_bits != 8)
+  if (gus_audio_bits != 8)
     dma_command |= 0x40;	/* 16 bit _DATA_ */
   else
     dma_command |= 0x80;	/* Invert MSB */
@@ -2312,7 +2516,7 @@
 
   gus_write8 (0x41, dma_command);	/* Kickstart */
 
-  if (chn == (gus_sampling_channels - 1))	/* Last channel */
+  if (chn == (gus_audio_channels - 1))	/* Last channel */
     {
       /*
        * Last (right or mono) channel data
@@ -2337,8 +2541,8 @@
 }
 
 static void
-gus_sampling_output_block (int dev, unsigned long buf, int total_count,
-			   int intrflag, int restart_dma)
+gus_audio_output_block (int dev, unsigned long buf, int total_count,
+			int intrflag, int restart_dma)
 {
   pcm_current_buf = buf;
   pcm_current_count = total_count;
@@ -2348,8 +2552,8 @@
 }
 
 static void
-gus_sampling_start_input (int dev, unsigned long buf, int count,
-			  int intrflag, int restart_dma)
+gus_audio_start_input (int dev, unsigned long buf, int count,
+		       int intrflag, int restart_dma)
 {
   unsigned long   flags;
   unsigned char   mode;
@@ -2363,7 +2567,7 @@
 
   if (audio_devs[dev]->dmachan2 > 3)
     mode |= 0x04;		/* 16 bit DMA channel */
-  if (gus_sampling_channels > 1)
+  if (gus_audio_channels > 1)
     mode |= 0x02;		/* Stereo */
   mode |= 0x01;			/* DMA enable */
 
@@ -2373,37 +2577,37 @@
 }
 
 static int
-gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
+gus_audio_prepare_for_input (int dev, int bsize, int bcount)
 {
   unsigned int    rate;
 
-  rate = (9878400 / (gus_sampling_speed + 2)) / 16;
+  rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
 
   gus_write8 (0x48, rate & 0xff);	/* Set sampling rate */
 
-  if (gus_sampling_bits != 8)
+  if (gus_audio_bits != 8)
     {
       printk ("GUS Error: 16 bit recording not supported\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   return 0;
 }
 
 static int
-gus_sampling_prepare_for_output (int dev, int bsize, int bcount)
+gus_audio_prepare_for_output (int dev, int bsize, int bcount)
 {
   int             i;
 
   long            mem_ptr, mem_size;
 
   mem_ptr = 0;
-  mem_size = gus_mem_size / gus_sampling_channels;
+  mem_size = gus_mem_size / gus_audio_channels;
 
   if (mem_size > (256 * 1024))
     mem_size = 256 * 1024;
 
-  pcm_bsize = bsize / gus_sampling_channels;
+  pcm_bsize = bsize / gus_audio_channels;
   pcm_head = pcm_tail = pcm_qlen = 0;
 
   pcm_nblk = MAX_PCM_BUFFERS;
@@ -2415,7 +2619,7 @@
 
   pcm_banksize = pcm_nblk * pcm_bsize;
 
-  if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
+  if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024))
     pcm_nblk--;
 
   return 0;
@@ -2431,11 +2635,11 @@
 gus_copy_from_user (int dev, char *localbuf, int localoffs,
 		    const char *userbuf, int useroffs, int len)
 {
-  if (gus_sampling_channels == 1)
+  if (gus_audio_channels == 1)
     {
-      memcpy_fromfs (&localbuf[localoffs], &((userbuf)[useroffs]), len);
+      memcpy_fromfs (&localbuf[localoffs], &(userbuf)[useroffs], len);
     }
-  else if (gus_sampling_bits == 8)
+  else if (gus_audio_bits == 8)
     {
       int             in_left = useroffs;
       int             in_right = useroffs + 1;
@@ -2444,7 +2648,7 @@
 
       len /= 2;
       localoffs /= 2;
-      out_left = &localbuf[localoffs];
+      out_left = localbuf + localoffs;
       out_right = out_left + pcm_bsize;
 
       for (i = 0; i < len; i++)
@@ -2465,7 +2669,7 @@
       len /= 4;
       localoffs /= 4;
 
-      out_left = (short *) &localbuf[localoffs];
+      out_left = ((short *) localbuf) + localoffs;
       out_right = out_left + (pcm_bsize / 2);
 
       for (i = 0; i < len; i++)
@@ -2478,23 +2682,28 @@
     }
 }
 
-static struct audio_operations gus_sampling_operations =
+static struct audio_driver gus_audio_driver =
+{
+  gus_audio_open,
+  gus_audio_close,
+  gus_audio_output_block,
+  gus_audio_start_input,
+  gus_audio_ioctl,
+  gus_audio_prepare_for_input,
+  gus_audio_prepare_for_output,
+  gus_audio_reset,
+  gus_audio_reset,
+  gus_local_qlen,
+  gus_copy_from_user
+};
+
+static struct audio_operations gus_audio_operations =
 {
   "Gravis UltraSound",
   NEEDS_RESTART,
   AFMT_U8 | AFMT_S16_LE,
   NULL,
-  gus_sampling_open,
-  gus_sampling_close,
-  gus_sampling_output_block,
-  gus_sampling_start_input,
-  gus_sampling_ioctl,
-  gus_sampling_prepare_for_input,
-  gus_sampling_prepare_for_output,
-  gus_sampling_reset,
-  gus_sampling_reset,
-  gus_local_qlen,
-  gus_copy_from_user
+  &gus_audio_driver
 };
 
 static void
@@ -2508,7 +2717,7 @@
   voices[voice].expression_vol =
     info->controllers[CTL_EXPRESSION];	/* Just msb */
   voices[voice].main_vol =
-    (info->controllers[CTL_MAIN_VOLUME] * 100) / 128;
+    (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
   voices[voice].panning =
     (info->controllers[CTL_PAN] * 2) - 128;
   voices[voice].bender = info->bender_value;
@@ -2589,7 +2798,7 @@
 	struct patch_info *pat;
 
 	if (ptr < 0 || ptr >= free_sample)
-	  return -EINVAL;
+	  return -(EINVAL);
 
 	memcpy (rec->data.data8, (char *) &samples[ptr],
 		sizeof (struct patch_info));
@@ -2609,12 +2818,12 @@
 	struct patch_info *pat;
 
 	if (ptr < 0 || ptr >= free_sample)
-	  return -EINVAL;
+	  return -(EINVAL);
 
 	pat = (struct patch_info *) rec->data.data8;
 
 	if (pat->len > samples[ptr].len)	/* Cannot expand sample */
-	  return -EINVAL;
+	  return -(EINVAL);
 
 	pat->key = samples[ptr].key;	/* Ensure the link is correct */
 
@@ -2634,10 +2843,10 @@
 	int             l = rec->parm3;
 
 	if (sample < 0 || sample >= free_sample)
-	  return -EINVAL;
+	  return -(EINVAL);
 
 	if (offs < 0 || offs >= samples[sample].len)
-	  return -EINVAL;	/* Invalid offset */
+	  return -(EINVAL);	/* Invalid offset */
 
 	n = samples[sample].len - offs;		/* Num of bytes left */
 
@@ -2648,12 +2857,12 @@
 	  l = sizeof (rec->data.data8);
 
 	if (l <= 0)
-	  return -EINVAL;	/*
+	  return -(EINVAL);	/*
 				   * Was there a bug?
 				 */
 
 	offs += sample_ptrs[sample];	/*
-					 * Begin offset + offset to DRAM
+					 * Begin offsess + offset to DRAM
 					 */
 
 	for (n = 0; n < l; n++)
@@ -2675,10 +2884,10 @@
 	int             l = rec->parm3;
 
 	if (sample < 0 || sample >= free_sample)
-	  return -EINVAL;
+	  return -(EINVAL);
 
 	if (offs < 0 || offs >= samples[sample].len)
-	  return -EINVAL;	/*
+	  return -(EINVAL);	/*
 				   * Invalid offset
 				 */
 
@@ -2693,12 +2902,12 @@
 	  l = sizeof (rec->data.data8);
 
 	if (l <= 0)
-	  return -EINVAL;	/*
+	  return -(EINVAL);	/*
 				   * Was there a bug?
 				 */
 
 	offs += sample_ptrs[sample];	/*
-					 * Begin offset + offset to DRAM
+					 * Begin offsess + offset to DRAM
 					 */
 
 	for (n = 0; n < l; n++)
@@ -2711,7 +2920,7 @@
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 }
 
@@ -2878,7 +3087,7 @@
 	      gus_pcm_volume = 0;
 	    if (gus_pcm_volume > 100)
 	      gus_pcm_volume = 100;
-	    gus_sampling_update_volume ();
+	    gus_audio_update_volume ();
 	    return snd_ioctl_return ((int *) arg, gus_pcm_volume | (gus_pcm_volume << 8));
 	    break;
 
@@ -2902,7 +3111,7 @@
 	    break;
 
 	  default:
-	    return -EINVAL;
+	    return -(EINVAL);
 	  }
       else
 	switch (cmd & 0xff)	/*
@@ -2947,21 +3156,22 @@
 	    break;
 
 	  default:
-	    return -EINVAL;
+	    return -(EINVAL);
 	  }
     }
   else
-    return -EINVAL;
+    return -(EINVAL);
 }
 
 static struct mixer_operations gus_mixer_operations =
 {
+  "GUS",
   "Gravis Ultrasound",
   gus_default_mixer_ioctl
 };
 
-static long
-gus_default_mixer_init (long mem_start)
+static void
+gus_default_mixer_init (void)
 {
   if (num_mixers < MAX_MIXER_DEV)	/*
 					 * Don't install if there is another
@@ -2979,11 +3189,10 @@
       mix_image |= 0x04;	/* All channels enabled */
       outb (mix_image, u_Mixer);
     }
-  return mem_start;
 }
 
-long
-gus_wave_init (long mem_start, struct address_info *hw_config)
+void
+gus_wave_init (struct address_info *hw_config)
 {
   unsigned long   flags;
   unsigned char   val;
@@ -2996,13 +3205,13 @@
     if (irq < 0 || irq > 15)
       {
 	printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
-	return mem_start;
+	return;
       }
 
   if (dma < 0 || dma > 7 || dma == 4)
     {
       printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
-      return mem_start;
+      return;
     }
 
   gus_irq = irq;
@@ -3018,18 +3227,36 @@
      *  Versions < 3.6 don't have the digital ASIC. Try to probe it first.
    */
 
+#ifdef GUSPNP_AUTODETECT
+  val = gus_look8 (0x5b);	/* Version number register */
+  gus_write8 (0x5b, ~val);	/* Invert all bits */
+
+  if ((gus_look8 (0x5b) & 0xf0) == (val & 0xf0))	/* No change */
+    if ((gus_look8 (0x5b) & 0x0f) == ((~val) & 0x0f))	/* Change */
+      {
+	DDB (printk ("Interwave chip version %d detected\n", (val & 0xf0) >> 4));
+	gus_pnp_flag = 1;
+      }
+    else
+      {
+	DDB (printk ("Not an Interwave chip\n"));
+	gus_pnp_flag = 0;
+      }
+  gus_write8 (0x5b, val);	/* Restore all bits */
+#endif
+
   save_flags (flags);
   cli ();
   outb (0x20, gus_base + 0x0f);
   val = inb (gus_base + 0x0f);
   restore_flags (flags);
 
-#ifndef GUSPNP_NO_AUTODETECT
-  gus_pnp_flag = (val == 1);
-#endif
-
   if (gus_pnp_flag || (val != 0xff && (val & 0x06)))	/* Should be 0x02?? */
     {
+      int             ad_flags = 0;
+
+      if (gus_pnp_flag)
+	ad_flags = 0x12345678;	/* Interwave "magic" */
       /*
          * It has the digital ASIC so the card is at least v3.4.
          * Next try to detect the true model.
@@ -3082,13 +3309,17 @@
 	    outb (max_config, gus_base + 0x106);	/* UltraMax control */
 	  }
 
-	  if (ad1848_detect (gus_base + 0x10c, NULL, hw_config->osp))
+	  if (ad1848_detect (gus_base + 0x10c, &ad_flags, hw_config->osp))
 	    {
+	      char           *name = "GUS MAX";
 
 	      gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
 	      gus_wave_volume = 90;
 	      have_gus_max = 1;
-	      ad1848_init ("GUS MAX", gus_base + 0x10c,
+	      if (hw_config->name)
+		name = hw_config->name;
+
+	      ad1848_init (name, gus_base + 0x10c,
 			   -irq,
 			   gus_dma2,	/* Playback DMA */
 			   gus_dma,	/* Capture DMA */
@@ -3123,13 +3354,13 @@
     sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
 
 
-  samples = (struct patch_info *) (sound_mem_blocks[sound_num_blocks] = kmalloc ((MAX_SAMPLE + 1) * sizeof (*samples), GFP_KERNEL));
-  if (sound_num_blocks < 1024)
-    sound_num_blocks++;;
+  samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc ((MAX_SAMPLE + 1) * sizeof (*samples)));
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
   if (samples == NULL)
     {
-      printk ("GUS Error: Can't allocate memory for instrument tables\n");
-      return mem_start;
+      printk ("GUS Error: Cant allocate memory for instrument tables\n");
+      return;
     }
 
   conf_printf (gus_info.name, hw_config);
@@ -3151,10 +3382,13 @@
 
   if (num_audiodevs < MAX_AUDIO_DEV)
     {
-      audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations;
+      audio_devs[gus_devnum = num_audiodevs++] = &gus_audio_operations;
       audio_devs[gus_devnum]->dmachan1 = dma;
       audio_devs[gus_devnum]->dmachan2 = dma2;
       audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
+      audio_devs[gus_devnum]->min_fragment = 9;
+      audio_devs[gus_devnum]->mixer_dev = num_mixers;	/* Next mixer# */
+      audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
       if (dma2 != dma && dma2 != -1)
 	audio_devs[gus_devnum]->flags |= DMA_DUPLEX;
     }
@@ -3171,12 +3405,14 @@
       gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
       gus_wave_volume = 90;
       request_region (u_MixSelect, 1, "GUS mixer");
-      return ics2101_mixer_init (mem_start);
+      ics2101_mixer_init ();
+      return;
 
     case CS4231:
       /* Initialized elsewhere (ad1848.c) */
     default:
-      return gus_default_mixer_init (mem_start);
+      gus_default_mixer_init ();
+      return;
     }
 }
 
@@ -3412,9 +3648,9 @@
     switch (active_device)
       {
       case GUS_DEV_WAVE:
-	if ((dram_sleep_flag.mode & WK_SLEEP))
+	if ((dram_sleep_flag.flags & WK_SLEEP))
 	  {
-	    dram_sleep_flag.mode = WK_WAKEUP;
+	    dram_sleep_flag.flags = WK_WAKEUP;
 	    module_wake_up (&dram_sleeper);
 	  };
 	break;
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c
--- v2.0.0/linux/drivers/sound/ics2101.c	Sun Mar 24 22:50:04 1996
+++ linux/drivers/sound/ics2101.c	Sun Jun 30 11:44:01 1996
@@ -4,27 +4,11 @@
  * Driver for the ICS2101 mixer of GUS v3.7.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -164,7 +148,7 @@
 	    break;
 
 	  default:
-	    return -EINVAL;
+	    return -(EINVAL);
 	  }
       else
 	switch (cmd & 0xff)	/*
@@ -213,21 +197,22 @@
 	    break;
 
 	  default:
-	    return -EINVAL;
+	    return -(EINVAL);
 	  }
     }
 
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static struct mixer_operations ics2101_mixer_operations =
 {
+  "ICS2101",
   "ICS2101 Multimedia Mixer",
   ics2101_mixer_ioctl
 };
 
-long
-ics2101_mixer_init (long mem_start)
+void
+ics2101_mixer_init (void)
 {
   int             i;
 
@@ -256,7 +241,6 @@
       set_volumes (DEV_UNUSED, 0x0000);
     }
 
-  return mem_start;
 }
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/iwmem.h linux/drivers/sound/iwmem.h
--- v2.0.0/linux/drivers/sound/iwmem.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/iwmem.h	Sun Jun 30 12:30:15 1996
@@ -0,0 +1,33 @@
+/*
+ * sound/iwmem.c
+ *
+ * DRAM size encoding table for AMD Interwave chip.
+ */
+/*
+ * Copyright (C) by Hannu Savolainen 1993-1996
+ *
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+
+
+#define K 1024
+#define M (1024*K)
+static int mem_decode[][4] =
+{
+/*	Bank0	Bank1	Bank2	Bank3	Encoding bits	*/
+	{256*K,	0,	0,	0},		/*  0 */
+	{256*K,	256*K,	0,	0},		/*  1 */
+	{256*K,	256*K,	256*K,	256*K},		/*  2 */
+	{256*K,	1*M,	0,	0},		/*  3 */
+	{256*K,	1*M,	1*M,	1*M},		/*  4 */
+	{256*K,	256*K,	1*M,	0},		/*  5 */
+	{256*K,	256*K,	1*M,	1*M},		/*  6 */
+	{1*M,	0,	0,	0},		/*  7 */
+	{1*M,	1*M,	0,	0},		/*  8 */
+	{1*M,	1*M,	1*M,	1*M},		/*  9 */
+	{4*M,	0,	0,	0},		/* 10 */
+	{4*M,	4*M,	0,	0},		/* 11 */
+	{4*M,	4*M,	4*M,	4*M}		/* 12 */
+};
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/Config.tmpl linux/drivers/sound/lowlevel/Config.tmpl
--- v2.0.0/linux/drivers/sound/lowlevel/Config.tmpl	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/lowlevel/Config.tmpl	Thu May 16 11:05:56 1996
@@ -0,0 +1,5 @@
+bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND
+
+if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
+   bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER
+fi
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/Makefile linux/drivers/sound/lowlevel/Makefile
--- v2.0.0/linux/drivers/sound/lowlevel/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/lowlevel/Makefile	Thu May 16 11:05:57 1996
@@ -0,0 +1,19 @@
+all:	lowlevel.o
+
+OBJS = init.o
+
+ifdef CONFIG_LOWLEVEL_SOUND
+ifdef CONFIG_ACI_MIXER
+OBJS := $(OBJS) aci.o
+endif
+endif
+
+lowlevel.o:	$(OBJS)
+	ld -r -o lowlevel.o $(OBJS)
+
+clean:
+	rm -f core x y z *~ *.o
+
+ifdef HOSTCC
+include $(TOPDIR)/Rules.make
+endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/README linux/drivers/sound/lowlevel/README
--- v2.0.0/linux/drivers/sound/lowlevel/README	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/lowlevel/README	Thu May 16 11:09:13 1996
@@ -0,0 +1,13 @@
+Additional low level sound drivers for Linux
+--------------------------------------------
+
+This directory contains additional low level sound drivers which
+are not part of USS/Lite (UNIX Sound System). These drivers are
+maintained by their authors.
+
+If you like to write a low level sound driver, please contact
+Hannu Savolainen (hannu@voxware.pp.fi) for more info.
+
+The following low level drivers are included:
+
+- ACI MIXER for miroPCM12 by Markus Kuhn. See aci.readme for more info.
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/aci.c linux/drivers/sound/lowlevel/aci.c
--- v2.0.0/linux/drivers/sound/lowlevel/aci.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/lowlevel/aci.c	Tue May 28 21:48:45 1996
@@ -0,0 +1,590 @@
+/*
+ * Audio Command Interface (ACI) driver (sound/aci.c)
+ *
+ * ACI is a protocol used to communicate with the microcontroller on
+ * some sound cards produced by miro, e.g. the miroSOUND PCM12 and
+ * PCM20. The ACI has been developed for miro by Norberto Pellicci
+ * <pellicci@ix.netcom.com>. Special thanks to both him and miro for
+ * providing the ACI specification.
+ *
+ * The main function of the ACI is to control the mixer and to get a
+ * product identification. On the PCM20, ACI also controls the radio
+ * tuner on this card, however this is not yet supported in this
+ * software.
+ * 
+ * This Voxware ACI driver currently only supports the ACI functions
+ * on the miroSOUND PCM12 card. Support for miro soundcards with
+ * additional ACI functions can easily be added later.
+ *
+ * Revision history:
+ *
+ *   1995-11-10  Markus Kuhn <mskuhn@cip.informatik.uni-erlangen.de>
+ *        First version written.
+ *   1995-12-31  Markus Kuhn
+ *        Second revision, general code cleanup.
+ *   1996-05-16	 Hannu Savolainen
+ *	  Integrated with other parts of the driver.
+ *   1996-05-28  Markus Kuhn
+ *        Initialize CS4231A mixer, make ACI first mixer,
+ *        use new private mixer API for solo mode.
+ */
+
+/*
+ * Some driver specific information and features:
+ *
+ * This mixer driver identifies itself to applications as "ACI" in
+ * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
+ *
+ * Proprietary mixer features that go beyond the standard USS mixer
+ * interface are:
+ * 
+ * Full duplex solo configuration:
+ *
+ *   int solo_mode;
+ *   ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode);
+ *
+ *   solo_mode = 0: deactivate solo mode (default)
+ *   solo_mode > 0: activate solo mode
+ *                  With activated solo mode, the PCM input can not any
+ *                  longer hear the signals produced by the PCM output.
+ *                  Activating solo mode is important in duplex mode in order
+ *                  to avoid feedback distortions.
+ *   solo_mode < 0: do not change solo mode (just retrieve the status)
+ *
+ *   When the ioctl() returns 0, solo_mode contains the previous
+ *   status (0 = deactivated, 1 = activated). If solo mode is not
+ *   implemented on this card, ioctl() returns -1 and sets errno to
+ *   EINVAL.
+ *
+ */
+
+#include "../sound_config.h"
+#ifdef CONFIG_ACI_MIXER
+
+#undef  DEBUG             /* if defined, produce a verbose report via syslog */
+
+int aci_port = 0x354; /* as determined by bit 4 in the Opti 929 MC4 register */
+unsigned char aci_idcode[2] = {0, 0};         /* manufacturer and product ID */
+unsigned char aci_version = 0;                       /* ACI firmware version */
+int aci_solo;                     /* status bit of the card that can't be    *
+                                   * checked with ACI versions prior to 0xb0 */
+
+static int aci_present = 0;
+
+#define COMMAND_REGISTER    (aci_port)
+#define STATUS_REGISTER     (aci_port + 1)
+#define BUSY_REGISTER       (aci_port + 2)
+
+/*
+ * Wait until the ACI microcontroller has set the READYFLAG in the
+ * Busy/IRQ Source Register to 0. This is required to avoid
+ * overrunning the soundcard microcontroller. We do a busy wait here,
+ * because the microcontroller is not supposed to signal a busy
+ * condition for more than a few clock cycles. In case of a time-out,
+ * this function returns -1.
+ *
+ * This busy wait code normally requires less than 15 loops and
+ * practically always less than 100 loops on my i486/DX2 66 MHz.
+ *
+ * Warning: Waiting on the general status flag after reseting the MUTE
+ * function can take a VERY long time, because the PCM12 does some kind
+ * of fade-in effect. For this reason, access to the MUTE function has
+ * not been implemented at all.
+ */
+
+static int busy_wait(void)
+{
+  long timeout;
+
+  for (timeout = 0; timeout < 10000000L; timeout++)
+    if ((inb_p(BUSY_REGISTER) & 1) == 0)
+      return 0;
+
+#ifdef DEBUG
+  printk("ACI: READYFLAG timed out.\n");
+#endif
+
+  return -1;
+}
+
+
+/*
+ * Read the GENERAL STATUS register.
+ */
+
+static int read_general_status(void)
+{
+  unsigned long flags;
+  int status;
+
+  save_flags(flags);
+  cli();
+  if (busy_wait()) { restore_flags(flags); return -1; }
+  status = (unsigned) inb_p(STATUS_REGISTER);
+  restore_flags(flags);
+  return status;
+}
+
+
+/*
+ * The four ACI command types (implied, write, read and indexed) can
+ * be sent to the microcontroller using the following four functions.
+ * If a problem occured, they return -1.
+ */
+
+static int implied_cmd(unsigned char opcode)
+{
+  unsigned long flags;
+
+#ifdef DEBUG
+  printk("ACI: implied_cmd(0x%02x)\n", opcode);
+#endif
+
+  save_flags(flags);
+  cli();
+  
+  if (read_general_status() < 0 || busy_wait()) {
+    restore_flags(flags);
+    return -1;
+  }
+  outb_p(opcode, COMMAND_REGISTER);
+
+  restore_flags(flags);
+  return 0;
+}
+
+
+static int write_cmd(unsigned char opcode, unsigned char parameter)
+{
+  unsigned long flags;
+  int status;
+
+#ifdef DEBUG
+  printk("ACI: write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
+#endif
+
+  save_flags(flags);
+  cli();
+  
+  if (read_general_status() < 0 || busy_wait()) {
+    restore_flags(flags);
+    return -1;
+  }
+  outb_p(opcode, COMMAND_REGISTER);
+  if (busy_wait()) { restore_flags(flags); return -1; }
+  outb_p(parameter, COMMAND_REGISTER);
+
+  if ((status = read_general_status()) < 0) {
+    restore_flags(flags);
+    return -1;
+  }
+  /* polarity of the INVALID flag depends on ACI version */
+  if ((aci_version <  0xb0 && (status & 0x40) != 0) ||
+      (aci_version >= 0xb0 && (status & 0x40) == 0)) {
+    restore_flags(flags);
+    printk("ACI: invalid write command 0x%02x, 0x%02x.\n",
+	   opcode, parameter);
+    return -1;
+  }
+
+  restore_flags(flags);
+  return 0;
+}
+
+
+static int read_cmd(unsigned char opcode, int length, unsigned char *parameter)
+{
+  unsigned long flags;
+  int i = 0;
+
+  save_flags(flags);
+  cli();
+  
+  if (read_general_status() < 0) { restore_flags(flags); return -1; }
+  while (i < length) {
+    if (busy_wait()) { restore_flags(flags); return -1; }
+    outb_p(opcode, COMMAND_REGISTER);
+    if (busy_wait()) { restore_flags(flags); return -1; }
+    parameter[i++] = inb_p(STATUS_REGISTER);
+#ifdef DEBUG
+    if (i == 1)
+      printk("ACI: read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length,
+	     parameter[i-1]);
+    else
+      printk("ACI: read_cmd cont.: 0x%02x\n", parameter[i-1]);
+#endif
+  }
+
+  restore_flags(flags);
+  return 0;
+}
+
+
+static int indexed_cmd(unsigned char opcode, unsigned char index,
+		       unsigned char *parameter)
+{
+  unsigned long flags;
+
+  save_flags(flags);
+  cli();
+  
+  if (read_general_status() < 0 || busy_wait()) {
+    restore_flags(flags);
+    return -1;
+  }
+  outb_p(opcode, COMMAND_REGISTER);
+  if (busy_wait()) { restore_flags(flags); return -1; }
+  outb_p(index, COMMAND_REGISTER);
+  if (busy_wait()) { restore_flags(flags); return -1; }
+  *parameter = inb_p(STATUS_REGISTER);
+#ifdef DEBUG
+  printk("ACI: indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
+	 *parameter);
+#endif
+
+  restore_flags(flags);
+  return 0;
+}
+
+
+/*
+ * The following macro SCALE can be used to scale one integer volume
+ * value into another one using only integer arithmetic. If the input
+ * value x is in the range 0 <= x <= xmax, then the result will be in
+ * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
+ *
+ * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
+ * following nice properties:
+ *
+ * - SCALE(xmax,ymax,xmax) = ymax
+ * - SCALE(xmax,ymax,0) = 0
+ * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
+ *
+ * In addition, the rounding error is minimal and nicely distributed.
+ * The proofs are left as an exercise to the reader.
+ */
+
+#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
+
+
+static int getvolume(caddr_t arg,
+		     unsigned char left_index, unsigned char right_index)
+{
+  int vol;
+  unsigned char buf;
+
+  /* left channel */
+  if (indexed_cmd(0xf0, left_index, &buf)) return -EIO;
+  vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
+  /* right channel */
+  if (indexed_cmd(0xf0, right_index, &buf)) return -EIO;
+  vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
+
+  return snd_ioctl_return((int *) arg, vol);
+}
+
+
+static int setvolume(caddr_t arg, 
+		     unsigned char left_index, unsigned char right_index)
+{
+  int vol, ret;
+  unsigned param;
+
+  param = get_user((int *) arg);
+  /* left channel */
+  vol = param & 0xff;
+  if (vol > 100) vol = 100;
+  vol = SCALE(100, 0x20, vol);
+  if (write_cmd(left_index, 0x20 - vol)) return -EIO;
+  ret = SCALE(0x20, 100, vol);
+  /* right channel */
+  vol = (param >> 8) & 0xff;
+  if (vol > 100) vol = 100;
+  vol = SCALE(100, 0x20, vol);
+  if (write_cmd(right_index, 0x20 - vol)) return -EIO;
+  ret |= SCALE(0x20, 100, vol) << 8;
+ 
+  return snd_ioctl_return((int *) arg, ret);
+}
+
+
+static int
+aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+{
+  int status, vol;
+  unsigned char buf;
+
+  /* handle solo mode control */
+  if (cmd == SOUND_MIXER_PRIVATE1) {
+    if (get_user((int *) arg) >= 0) {
+      aci_solo = !!get_user((int *) arg);
+      if (write_cmd(0xd2, aci_solo)) return -EIO;
+    } else if (aci_version >= 0xb0) {
+      if ((status = read_general_status()) < 0) return -EIO;
+      return snd_ioctl_return ((int *) arg, (status & 0x20) == 0);
+    }
+    return snd_ioctl_return((int *) arg, aci_solo);
+  }
+
+  if (((cmd >> 8) & 0xff) == 'M') {
+    if (cmd & IOC_IN)
+      /* read and write */
+      switch (cmd & 0xff) {
+      case SOUND_MIXER_VOLUME:
+	return setvolume(arg, 0x01, 0x00);
+      case SOUND_MIXER_CD:
+	return setvolume(arg, 0x3c, 0x34);
+      case SOUND_MIXER_MIC:
+	return setvolume(arg, 0x38, 0x30);
+      case SOUND_MIXER_LINE:
+	return setvolume(arg, 0x39, 0x31);
+      case SOUND_MIXER_SYNTH:
+	return setvolume(arg, 0x3b, 0x33);
+      case SOUND_MIXER_PCM:
+	return setvolume(arg, 0x3a, 0x32);
+      case SOUND_MIXER_LINE1:  /* AUX1 */
+	return setvolume(arg, 0x3d, 0x35);
+      case SOUND_MIXER_LINE2:  /* AUX2 */
+	return setvolume(arg, 0x3e, 0x36);
+      case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
+	vol = get_user((int *) arg) & 0xff;
+	if (vol > 100) vol = 100;
+	vol = SCALE(100, 3, vol);
+	if (write_cmd(0x03, vol)) return -EIO;
+	vol = SCALE(3, 100, vol);
+	return snd_ioctl_return((int *) arg, vol | (vol << 8));
+      case SOUND_MIXER_RECSRC:
+	return snd_ioctl_return ((int *) arg, 0);
+	break;
+      default:
+	return -EINVAL;
+      }
+    else
+      /* only read */
+      switch (cmd & 0xff) {
+      case SOUND_MIXER_DEVMASK:
+	return snd_ioctl_return ((int *) arg,
+				 SOUND_MASK_VOLUME | SOUND_MASK_CD    |
+				 SOUND_MASK_MIC    | SOUND_MASK_LINE  |
+				 SOUND_MASK_SYNTH  | SOUND_MASK_PCM   |
+#if 0
+				 SOUND_MASK_IGAIN  |
+#endif
+				 SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
+	break;
+      case SOUND_MIXER_STEREODEVS:
+	return snd_ioctl_return ((int *) arg,
+				 SOUND_MASK_VOLUME | SOUND_MASK_CD   |
+				 SOUND_MASK_MIC    | SOUND_MASK_LINE |
+				 SOUND_MASK_SYNTH  | SOUND_MASK_PCM  |
+				 SOUND_MASK_LINE1  | SOUND_MASK_LINE2);
+	break;
+      case SOUND_MIXER_RECMASK:
+	return snd_ioctl_return ((int *) arg, 0);
+	break;
+      case SOUND_MIXER_RECSRC:
+	return snd_ioctl_return ((int *) arg, 0);
+	break;
+      case SOUND_MIXER_CAPS:
+	return snd_ioctl_return ((int *) arg, 0);
+	break;
+      case SOUND_MIXER_VOLUME:
+	return getvolume(arg, 0x04, 0x03);
+      case SOUND_MIXER_CD:
+	return getvolume(arg, 0x0a, 0x09);
+      case SOUND_MIXER_MIC:
+	return getvolume(arg, 0x06, 0x05);
+      case SOUND_MIXER_LINE:
+	return getvolume(arg, 0x08, 0x07);
+      case SOUND_MIXER_SYNTH:
+	return getvolume(arg, 0x0c, 0x0b);
+      case SOUND_MIXER_PCM:
+	return getvolume(arg, 0x0e, 0x0d);
+      case SOUND_MIXER_LINE1:  /* AUX1 */
+	return getvolume(arg, 0x11, 0x10);
+      case SOUND_MIXER_LINE2:  /* AUX2 */
+	return getvolume(arg, 0x13, 0x12);
+      case SOUND_MIXER_IGAIN:  /* MIC pre-amp */
+	if (indexed_cmd(0xf0, 0x21, &buf)) return -EIO;
+	vol = SCALE(3, 100, buf <= 3 ? buf : 3);
+	vol |= vol << 8;
+	return snd_ioctl_return((int *) arg, vol);
+      default:
+	return -EINVAL;
+      }
+  }
+
+  return -EINVAL;
+}
+
+
+static struct mixer_operations aci_mixer_operations =
+{
+  "ACI",
+  "ACI mixer",
+  aci_mixer_ioctl,
+  NULL
+};
+
+static unsigned char
+mad_read (int port)
+{
+  outb (0xE3, 0xf8f); /* Write MAD16 password */
+  return inb (port);  /* Read from port */
+}
+
+
+/*
+ * Check, whether there actually is any ACI port operational and if
+ * one was found, then initialize the ACI interface, reserve the I/O
+ * addresses and attach the new mixer to the relevant VoxWare data
+ * structures.
+ *
+ * Returns:  1   ACI mixer detected
+ *           0   nothing there
+ *
+ * There is also an internal mixer in the codec (CS4231A or AD1845),
+ * that deserves no purpose in an ACI based system which uses an
+ * external ACI controlled stereo mixer. Make sure that this codec
+ * mixer has the AUX1 input selected as the recording source, that the
+ * input gain is set near maximum and that the other channels going
+ * from the inputs to the codec output are muted.
+ */
+
+int attach_aci(void)
+{
+  char *boardname = "unknown";
+  int volume;
+
+#define MC4_PORT	0xf90
+
+  aci_port =
+      (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;
+
+  if (check_region(aci_port, 3)) {
+#ifdef DEBUG
+    printk("ACI: I/O area 0x%03x-0x%03x already used.\n",
+           aci_port, aci_port+2);
+#endif
+    return 0;
+  }
+
+  if (read_cmd(0xf2, 2, aci_idcode)) {
+#ifdef DEBUG
+    printk("ACI: Failed to read idcode.\n");
+#endif
+    return 0;
+  }
+  if (read_cmd(0xf1, 1, &aci_version)) {
+#ifdef DEBUG
+    printk("ACI: Failed to read version.\n");
+#endif
+    return 0;
+  }
+
+  if (aci_idcode[0] == 0x6d) {
+    /* it looks like a miro soundcard */
+    switch (aci_idcode[1]) {
+    case 0x41:
+      boardname = "PCM1 pro / early PCM12";
+      break;
+    case 0x42:
+      boardname = "PCM12";
+      break;
+    case 0x43:
+      boardname = "PCM20";
+      break;
+    default:
+      boardname = "unknown miro";
+    }
+  } else
+#ifndef DEBUG
+    return 0;
+#endif
+  
+  printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",
+	 aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);
+
+  /* initialize ACI mixer */
+  implied_cmd(0xff);
+  aci_solo = 0;
+
+  /* attach the mixer */
+  request_region(aci_port, 3, "sound mixer (ACI)");
+  if (num_mixers < MAX_MIXER_DEV) {
+    if (num_mixers > 0 &&
+        !strcmp("MAD16 WSS (CS4231A)", mixer_devs[num_mixers-1]->name)) {
+      /*
+       * The previously registered mixer device is the CS4231A which
+       * has no function on an ACI card. Make the ACI mixer the first
+       * of the two mixer devices.
+       */
+      mixer_devs[num_mixers] = mixer_devs[num_mixers-1];
+      mixer_devs[num_mixers-1] = &aci_mixer_operations;
+      /*
+       * Initialize the CS4231A mixer with reasonable values. It is
+       * unlikely that the user ever will want to change these as all
+       * channels can be mixed via ACI.
+       */
+      volume = 0x6464;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_PCM,     (caddr_t) &volume);
+      volume = 0x6464;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_IGAIN,   (caddr_t) &volume);
+      volume = 0;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);
+      volume = 0;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_MIC,     (caddr_t) &volume);
+      volume = 0;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_IMIX,    (caddr_t) &volume);
+      volume = 0;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE1,   (caddr_t) &volume);
+      volume = 0;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE2,   (caddr_t) &volume);
+      volume = 0;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_LINE3,   (caddr_t) &volume);
+      volume = SOUND_MASK_LINE1;
+      mixer_devs[num_mixers]->
+        ioctl(num_mixers, SOUND_MIXER_WRITE_RECSRC,  (caddr_t) &volume);
+      num_mixers++;
+    } else
+      mixer_devs[num_mixers++] = &aci_mixer_operations;
+  }
+
+  /* Initialize ACI mixer with reasonable power-up values */
+  volume = 0x3232;
+  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);
+  volume = 0x3232;
+  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH,  (caddr_t) &volume);
+  volume = 0x3232;
+  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM,    (caddr_t) &volume);
+  volume = 0x3232;
+  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE,   (caddr_t) &volume);
+  volume = 0x3232;
+  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC,    (caddr_t) &volume);
+  volume = 0x3232;
+  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD,     (caddr_t) &volume);
+  volume = 0x3232;
+  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1,  (caddr_t) &volume);
+  volume = 0x3232;
+  aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2,  (caddr_t) &volume);
+  
+  aci_present = 1;
+
+  return 1;
+}
+
+void unload_aci(void)
+{
+  if (aci_present)
+    release_region(aci_port, 3);
+}
+
+#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/aci.readme linux/drivers/sound/lowlevel/aci.readme
--- v2.0.0/linux/drivers/sound/lowlevel/aci.readme	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/lowlevel/aci.readme	Thu May 16 11:08:03 1996
@@ -0,0 +1,40 @@
+
+ACI mixer driver extension (miroSOUND PCM12) for Linux
+------------------------------------------------------
+
+Markus Kuhn -- 1995-12-31
+
+
+This is the ACI mixer driver for the miroSOUND PCM12 soundcard. It
+works probably also for other ACI miroSOUND boards like the PCM1 pro
+or the PCM20, however this has not been tested.
+
+Just copy the file aci.c into the /usr/src/linux/drivers/sound/
+subdirectory, then change to the subdirectory /usr/src/linux/drivers/
+and apply with "patch -p0 <aci.patch" the path file which adds the
+call of the attach_aci() to the MAD16 driver.
+
+With these patches, /dev/mixer will be the ACI mixer, and /dev/mixer1
+will be the (mostly unoperational) mixer in the codec, which is the
+primary mixer of most other MAD16 cards.
+
+Things which still have to be done for full PCM12 support:
+
+  - /dev/mixer1 should be automatically initialized to sensible
+    settings (see the comments in aci.c for details).
+
+  - I still have not been able to record anything with the PCM12
+    in duplex mode. No matter what DMA and IRQ setting I tried,
+    I always get "Sound: DMA (input) timed out - IRQ/DRQ config
+    error?".
+
+Please let me know if you have any problems/suggestions.
+
+*** Happy mixing ***
+
+Markus
+
+-- 
+Markus Kuhn, Computer Science student -- University of Erlangen,
+Internet Mail: <mskuhn@cip.informatik.uni-erlangen.de> - Germany
+WWW Home: <http://wwwcip.informatik.uni-erlangen.de/user/mskuhn>
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/lowlevel/init.c linux/drivers/sound/lowlevel/init.c
--- v2.0.0/linux/drivers/sound/lowlevel/init.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/lowlevel/init.c	Tue May 28 17:45:17 1996
@@ -0,0 +1,26 @@
+/*
+ * lowlevel/init.c - Calls initialization code for configured drivers.
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_LOWLEVEL_SOUND
+extern int attach_aci(void);
+extern void unload_aci(void);
+
+void
+sound_init_lowlevel_drivers(void)
+{
+#ifdef CONFIG_ACI_MIXER
+   attach_aci();
+#endif
+}
+
+void
+sound_unload_lowlevel_drivers(void)
+{
+#ifdef CONFIG_ACI_MIXER
+   unload_aci();
+#endif
+}
+#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v2.0.0/linux/drivers/sound/mad16.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/mad16.c	Sun Jun 30 11:44:02 1996
@@ -1,25 +1,9 @@
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -31,9 +15,9 @@
  *      OPTi 82C928     MAD16           (replaced by C929)
  *      OAK OTI-601D    Mozart
  *      OPTi 82C929     MAD16 Pro
- *      OPTi 82C930     (Not supported yet)
+ *      OPTi 82C930
  *
- * These audio interface chips don't produce sound themselves. They just
+ * These audio interface chips don't prduce sound themselves. They just
  * connect some other components (OPL-[234] and a WSS compatible codec)
  * to the PC bus and perform I/O, DMA and IRQ address decoding. There is
  * also a UART for the MPU-401 mode (not 82C928/Mozart).
@@ -77,6 +61,8 @@
 
 #if defined(CONFIG_MAD16)
 
+#include "sb.h"
+
 static int      already_initialized = 0;
 
 #define C928	1
@@ -91,6 +77,9 @@
  *      All ports are inactive by default. They can be activated by
  *      writing 0xE2 or 0xE3 to the password register. The password is valid
  *      only until the next I/O read or write.
+ *
+ *      82C930 uses 0xE4 as the password and indirect addressing to access
+ *      the config registers.
  */
 
 #define MC0_PORT	0xf8c	/* Dummy port */
@@ -136,9 +125,18 @@
       outb (0xE3, PASSWD_REG);
       break;
 
+    case C930:
+      /* outb( 0xE4,  PASSWD_REG); */
+      break;
     }
 
-  tmp = inb (port);
+  if (board_type == C930)
+    {
+      outb (port - MC0_PORT, 0xe0e);	/* Write to index reg */
+      tmp = inb (0xe0f);	/* Read from data reg */
+    }
+  else
+    tmp = inb (port);
   restore_flags (flags);
 
   return tmp;
@@ -163,13 +161,60 @@
       outb (0xE3, PASSWD_REG);
       break;
 
+    case C930:
+      /* outb( 0xE4,  PASSWD_REG); */
+      break;
     }
 
-  outb ((unsigned char) (value & 0xff), port);
+  if (board_type == C930)
+    {
+      outb (port - MC0_PORT, 0xe0e);	/* Write to index reg */
+      outb ((unsigned char) (value & 0xff), 0xe0f);
+    }
+  else
+    outb ((unsigned char) (value & 0xff), port);
   restore_flags (flags);
 }
 
 static int
+detect_c930 (void)
+{
+  unsigned char   tmp = mad_read (MC1_PORT);
+
+  if ((tmp & 0x06) != 0x06)
+    {
+      DDB (printk ("Wrong C930 signature (%x)\n", tmp));
+      /* return 0; */
+    }
+
+  mad_write (MC1_PORT, 0);
+
+  if (mad_read (MC1_PORT) != 0x06)
+    {
+      DDB (printk ("Wrong C930 signature2 (%x)\n", tmp));
+      /* return 0; */
+    }
+
+  mad_write (MC1_PORT, tmp);	/* Restore bits */
+
+  mad_write (MC7_PORT, 0);
+  if ((tmp = mad_read (MC7_PORT)) != 0)
+    {
+      DDB (printk ("MC7 not writeable (%x)\n", tmp));
+      return 0;
+    }
+
+  mad_write (MC7_PORT, 0xcb);
+  if ((tmp = mad_read (MC7_PORT)) != 0xcb)
+    {
+      DDB (printk ("MC7 not writeable2 (%x)\n", tmp));
+      return 0;
+    }
+
+  return 1;
+}
+
+static int
 detect_mad16 (void)
 {
   unsigned char   tmp, tmp2;
@@ -190,6 +235,8 @@
   for (i = 0xf8d; i <= 0xf98; i++)
     DDB (printk ("Port %0x (init value) = %0x\n", i, mad_read (i)));
 
+  if (board_type == C930)
+    return detect_c930 ();
 /*
  * Now check that the gate is closed on first I/O after writing
  * the password. (This is how a MAD16 compatible card works).
@@ -201,7 +248,7 @@
       return 0;
     }
 
-  mad_write (MC1_PORT, tmp ^ 0x80);	/* Toggle a bit */
+  mad_write (MC1_PORT, tmp ^ 0x80);	/* Togge a bit */
   if ((tmp2 = mad_read (MC1_PORT)) != (tmp ^ 0x80))	/* Compare the bit */
     {
       mad_write (MC1_PORT, tmp);	/* Restore */
@@ -233,7 +280,7 @@
     return 0;
   /*
      * Check if the IO port returns valid signature. The original MS Sound
-     * system returns 0x04 while some cards (AudioTriX Pro for example)
+     * system returns 0x04 while some cards (AudioTrix Pro for example)
      * return 0x00.
    */
 
@@ -275,6 +322,57 @@
   return 1;
 }
 
+static int
+init_c930 (struct address_info *hw_config)
+{
+  unsigned char   cfg;
+
+  cfg = (mad_read (MC1_PORT) & ~0x30);
+  /* mad_write(MC1_PORT, 0); */
+
+  switch (hw_config->io_base)
+    {
+    case 0x530:
+      cfg |= 0x00;
+      break;
+    case 0xe80:
+      cfg |= 0x10;
+      break;
+    case 0xf40:
+      cfg |= 0x20;
+      break;
+    case 0x604:
+      cfg |= 0x30;
+      break;
+
+    default:
+      printk ("MAD16: Invalid codec port %x\n", hw_config->io_base);
+      return 0;
+    }
+  mad_write (MC1_PORT, cfg);
+
+  /* MC2 is CD configuration. Don't touch it. */
+
+  mad_write (MC3_PORT, 0);	/* Disable SB mode IRQ and DMA */
+
+  mad_write (MC4_PORT, 0x52);	/* ??? */
+  mad_write (MC5_PORT, 0x3D);	/* Init it into mode2 */
+  mad_write (MC6_PORT, 0x02);	/* Enable WSS, Disable MPU and SB */
+  mad_write (MC7_PORT, 0xCB);
+  mad_write (MC10_PORT, 0x11);
+
+  if (!wss_init (hw_config))
+    return 0;
+
+/*
+ * A temporarary kludge which drops the device back to mode1.
+ * This removes problems with interrupts but disables full duplex.
+ * A better solution should be introduced later.
+ */
+  mad_write (MC5_PORT, 0x1D);	/* Disable mode2 */
+  return wss_init (hw_config);
+}
+
 int
 probe_mad16 (struct address_info *hw_config)
 {
@@ -313,7 +411,28 @@
 
       if (!detect_mad16 ())
 	{
-	  return 0;
+	  if (inb (PASSWD_REG) != 0xff)
+	    return 0;
+
+/*
+ * First relocate MC# registers to 0xe0e/0xe0f, disable password 
+ */
+
+	  outb (0xE4, PASSWD_REG);
+	  outb (0x80, PASSWD_REG);
+
+	  board_type = C930;
+
+	  DDB (printk ("Detect using password = 0xE4\n"));
+
+	  for (i = 0xf8d; i <= 0xf93; i++)
+	    DDB (printk ("port %03x = %02x\n", i, mad_read (i)));
+
+	  if (!detect_mad16 ())
+	    return 0;
+
+	  DDB (printk ("mad16.c: 82C930 detected\n"));
+	  return init_c930 (hw_config);
 	}
       else
 	{
@@ -408,8 +527,8 @@
   return 1;
 }
 
-long
-attach_mad16 (long mem_start, struct address_info *hw_config)
+void
+attach_mad16 (struct address_info *hw_config)
 {
 
   static char     interrupt_bits[12] =
@@ -430,7 +549,7 @@
   already_initialized = 1;
 
   if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp))
-    return mem_start;
+    return;
 
   /*
      * Set the IRQ and DMA addresses.
@@ -438,7 +557,7 @@
 
   bits = interrupt_bits[hw_config->irq];
   if (bits == -1)
-    return mem_start;
+    return;
 
   outb (bits | 0x40, config_port);
   if ((inb (version_port) & 0x40) == 0)
@@ -450,12 +569,21 @@
 
   if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
     {
+      if (!((dma == 0 && dma2 == 1) ||
+	    (dma == 1 && dma2 == 0) ||
+	    (dma == 3 && dma2 == 0)))
+	{			/* Unsupported combination. Try to swap channels */
+	  int             tmp = dma;
+
+	  dma = dma2;
+	  dma2 = tmp;
+	}
+
       if ((dma == 0 && dma2 == 1) ||
 	  (dma == 1 && dma2 == 0) ||
 	  (dma == 3 && dma2 == 0))
 	{
 	  dma2_bit = 0x04;	/* Enable capture DMA */
-
 	}
       else
 	{
@@ -474,12 +602,10 @@
 	       dma2, 0,
 	       hw_config->osp);
   request_region (hw_config->io_base, 4, "MAD16 WSS config");
-
-  return mem_start;
 }
 
-long
-attach_mad16_mpu (long mem_start, struct address_info *hw_config)
+void
+attach_mad16_mpu (struct address_info *hw_config)
 {
   if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
     {
@@ -490,19 +616,20 @@
       else
 	hw_config->io_base = 0x220;
 
-      return mad16_sb_dsp_init (mem_start, hw_config);
-#else
-      return 0;
+      hw_config->name = "Mad16/Mozart";
+      sb_dsp_init (hw_config);
 #endif
+
+      return;
     }
 
 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   if (!already_initialized)
-    return mem_start;
+    return;
 
-  return attach_mpu401 (mem_start, hw_config);
-#else
-  return mem_start;
+  hw_config->driver_use_1 = SB_MIDI_ONLY;
+  hw_config->name = "Mad16/Mozart";
+  attach_uart401 (hw_config);
 #endif
 }
 
@@ -562,13 +689,15 @@
 	}
 
       mad_write (MC3_PORT, tmp | 0x04);
-      return mad16_sb_dsp_detect (hw_config);
+      hw_config->driver_use_1 = SB_MIDI_ONLY;
+      return sb_dsp_detect (hw_config);
 #else
       return 0;
 #endif
     }
 
-  tmp = 0x83;			/* MPU-401 enable */
+  tmp = mad_read (MC6_PORT) & 0x83;
+  tmp |= 0x80;			/* MPU-401 enable */
 
 /*
  * Set the MPU base bits
@@ -609,7 +738,7 @@
     }
   mad_write (MC6_PORT, tmp);	/* Write MPU401 config */
 
-  return probe_mpu401 (hw_config);
+  return probe_uart401 (hw_config);
 #else
   return 0;
 #endif
@@ -632,13 +761,13 @@
 #ifdef CONFIG_MIDI
   if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
     {
-      mad16_sb_dsp_unload (hw_config);
+      sb_dsp_unload (hw_config);
       return;
     }
 #endif
 
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
-  unload_mpu401 (hw_config);
+#if (defined(CONFIG_UART401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+  unload_uart401 (hw_config);
 #endif
 }
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/mad16_sb_midi.c linux/drivers/sound/mad16_sb_midi.c
--- v2.0.0/linux/drivers/sound/mad16_sb_midi.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/mad16_sb_midi.c	Thu Jan  1 02:00:00 1970
@@ -1,357 +0,0 @@
-/*
- * sound/mad16_sb_midi.c
- *
- * The low level driver for MAD16 SoundBlaster-DS-chip-based MIDI.
- */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <linux/config.h>
-
-/*
- * Modifications by Aaron Ucko 1995
- */
-
-#include "sound_config.h"
-
-#if defined(CONFIG_MAD16) && defined(CONFIG_MIDI)
-
-#define sbc_base mad16_sb_base
-#include "sb.h"
-
-static int      input_opened = 0;
-static int      my_dev;
-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 int     *midi_osp;
-
-int             mad16_sb_midi_mode = NORMAL_MIDI;
-int             mad16_sb_midi_busy = 0;
-
-int             mad16_sb_duplex_midi = 0;
-volatile int    mad16_sb_intr_active = 0;
-
-void            (*midi_input_intr) (int dev, unsigned char data);
-
-static void     mad16_sb_midi_init (int model);
-
-static int
-mad16_sb_dsp_command (unsigned char val)
-{
-  int             i;
-  unsigned long   limit;
-
-  limit = jiffies + HZ / 10;	/*
-				   * The timeout is 0.1 seconds
-				 */
-
-  /*
-   * Note! the i<500000 is an emergency exit. The mad16_sb_dsp_command() is sometimes
-   * called while interrupts are disabled. This means that the timer is
-   * disabled also. However the timeout situation is a abnormal condition.
-   * Normally the DSP should be ready to accept commands after just couple of
-   * loops.
-   */
-
-  for (i = 0; i < 500000 && jiffies < limit; i++)
-    {
-      if ((inb (DSP_STATUS) & 0x80) == 0)
-	{
-	  outb (val, DSP_COMMAND);
-	  return 1;
-	}
-    }
-
-  printk ("MAD16 (SBP mode): DSP Command(%x) Timeout.\n", val);
-  printk ("IRQ conflict???\n");
-  return 0;
-}
-
-void
-mad16_sbintr (int irq, void *dev_id, struct pt_regs *dummy)
-{
-  int             status;
-
-  unsigned long   flags;
-  unsigned char   data;
-
-  status = inb (DSP_DATA_AVAIL);	/*
-					   * Clear interrupt
-					 */
-
-  save_flags (flags);
-  cli ();
-
-  data = inb (DSP_READ);
-  if (input_opened)
-    midi_input_intr (my_dev, data);
-
-  restore_flags (flags);
-}
-
-static int
-mad16_sb_reset_dsp (void)
-{
-  int             loopc;
-
-  outb (1, DSP_RESET);
-  tenmicrosec (midi_osp);
-  outb (0, DSP_RESET);
-  tenmicrosec (midi_osp);
-  tenmicrosec (midi_osp);
-  tenmicrosec (midi_osp);
-
-  for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++);	/*
-										   * Wait
-										   * for
-										   * data
-										   * *
-										   * available
-										   * status
-										 */
-
-  if (inb (DSP_READ) != 0xAA)
-    return 0;			/*
-				 * Sorry
-				 */
-
-  return 1;
-}
-
-int
-mad16_sb_dsp_detect (struct address_info *hw_config)
-{
-  mad16_sb_base = hw_config->io_base;
-  mad16_sb_irq = hw_config->irq;
-  midi_osp = hw_config->osp;
-
-  if (check_region (hw_config->io_base, 16))
-    {
-      printk ("MAD16 SB MIDI: I/O base %x not free\n", hw_config->io_base);
-      return 0;
-    }
-
-  if (mad16_sb_dsp_ok)
-    return 0;			/*
-				 * Already initialized
-				 */
-  if (!mad16_sb_reset_dsp ())
-    return 0;
-
-  return 1;			/*
-				 * Detected
-				 */
-}
-
-long
-mad16_sb_dsp_init (long mem_start, struct address_info *hw_config)
-/* this function now just verifies the reported version and calls
- * 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)
-    {
-      printk ("MAD16 SB MIDI: IRQ not free\n");
-      return mem_start;
-    }
-
-  request_region (hw_config->io_base, 16, "mad16/Mozart MIDI");
-
-  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
-mad16_sb_midi_open (int dev, int mode,
-		    void            (*input) (int dev, unsigned char data),
-		    void            (*output) (int dev)
-)
-{
-
-  if (!mad16_sb_dsp_ok)
-    {
-      printk ("MAD16_SB Error: MIDI hardware not installed\n");
-      return -ENXIO;
-    }
-
-  if (mad16_sb_midi_busy)
-    return -EBUSY;
-
-  if (mode != OPEN_WRITE && !mad16_sb_duplex_midi)
-    {
-      if (num_midis == 1)
-	printk ("MAD16 (SBP mode): Midi input not currently supported\n");
-      return -EPERM;
-    }
-
-  mad16_sb_midi_mode = NORMAL_MIDI;
-  if (mode != OPEN_WRITE)
-    {
-      if (mad16_sb_intr_active)
-	return -EBUSY;
-      mad16_sb_midi_mode = UART_MIDI;
-    }
-
-  if (mad16_sb_midi_mode == UART_MIDI)
-    {
-      mad16_sb_reset_dsp ();
-
-      if (!mad16_sb_dsp_command (0x35))
-	return -EIO;		/*
-				   * Enter the UART mode
-				 */
-      mad16_sb_intr_active = 1;
-
-      input_opened = 1;
-      midi_input_intr = input;
-    }
-
-  mad16_sb_midi_busy = 1;
-
-  return 0;
-}
-
-static void
-mad16_sb_midi_close (int dev)
-{
-  if (mad16_sb_midi_mode == UART_MIDI)
-    {
-      mad16_sb_reset_dsp ();	/*
-				   * The only way to kill the UART mode
-				 */
-    }
-  mad16_sb_intr_active = 0;
-  mad16_sb_midi_busy = 0;
-  input_opened = 0;
-}
-
-static int
-mad16_sb_midi_out (int dev, unsigned char midi_byte)
-{
-  unsigned long   flags;
-
-  if (mad16_sb_midi_mode == NORMAL_MIDI)
-    {
-      save_flags (flags);
-      cli ();
-      if (mad16_sb_dsp_command (0x38))
-	mad16_sb_dsp_command (midi_byte);
-      else
-	printk ("MAD16_SB Error: Unable to send a MIDI byte\n");
-      restore_flags (flags);
-    }
-  else
-    mad16_sb_dsp_command (midi_byte);	/*
-					   * UART write
-					 */
-
-  return 1;
-}
-
-static int
-mad16_sb_midi_start_read (int dev)
-{
-  if (mad16_sb_midi_mode != UART_MIDI)
-    {
-      printk ("MAD16 (SBP mode): MIDI input not implemented.\n");
-      return -EPERM;
-    }
-  return 0;
-}
-
-static int
-mad16_sb_midi_end_read (int dev)
-{
-  if (mad16_sb_midi_mode == UART_MIDI)
-    {
-      mad16_sb_reset_dsp ();
-      mad16_sb_intr_active = 0;
-    }
-  return 0;
-}
-
-static int
-mad16_sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
-{
-  return -EPERM;
-}
-
-#define MIDI_SYNTH_NAME	"pseudo-SoundBlaster Midi"
-#define MIDI_SYNTH_CAPS	0
-#include "midi_synth.h"
-
-static struct midi_operations mad16_sb_midi_operations =
-{
-  {"MAD16 (SBP mode)", 0, 0, SNDCARD_MAD16},
-  &std_midi_synth,
-  {0},
-  mad16_sb_midi_open,
-  mad16_sb_midi_close,
-  mad16_sb_midi_ioctl,
-  mad16_sb_midi_out,
-  mad16_sb_midi_start_read,
-  mad16_sb_midi_end_read,
-  NULL,				/*
-				 * Kick
-				 */
-  NULL,				/*
-				 * command
-				 */
-  NULL,				/*
-				 * buffer_status
-				 */
-  NULL
-};
-
-static void
-mad16_sb_midi_init (int model)
-{
-  if (num_midis >= MAX_MIDI_DEV)
-    {
-      printk ("Sound: Too many midi devices detected\n");
-      return;
-    }
-
-  std_midi_synth.midi_dev = num_midis;
-  my_dev = num_midis;
-  midi_devs[num_midis++] = &mad16_sb_midi_operations;
-}
-
-#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v2.0.0/linux/drivers/sound/maui.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/maui.c	Sun Jun 30 11:44:02 1996
@@ -4,27 +4,11 @@
  * The low level driver for Turtle Beach Maui and Tropez.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -57,6 +41,10 @@
 
 #ifdef HAVE_MAUI_BOOT
 #include "maui_boot.h"
+#else
+static unsigned char *maui_os = NULL;
+static int      maui_osLen = 0;
+
 #endif
 
 static wait_handle *maui_sleeper = NULL;
@@ -93,20 +81,20 @@
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (HZ / 10)
-	  current_set_timeout (tl = jiffies + (HZ / 10));
+	  current_set_timeout (tlimit = jiffies + (HZ / 10));
 	else
-	  tl = (unsigned long) -1;
-	maui_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	maui_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&maui_sleeper);
-	if (!(maui_sleep_flag.mode & WK_WAKEUP))
+	if (!(maui_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      maui_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      maui_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	maui_sleep_flag.mode &= ~WK_SLEEP;
+	maui_sleep_flag.flags &= ~WK_SLEEP;
       };
       if (current_got_fatal_signal ())
 	return 0;
@@ -193,7 +181,7 @@
 
 		if (c != 0x80)
 		  {
-		    printk ("Download not acknowledged\n");
+		    printk ("Doanload not acknowledged\n");
 		    return 0;
 		  }
 		else if (!(lines++ % 10))
@@ -317,7 +305,7 @@
   if (count < hdr_size)
     {
       printk ("Maui error: Patch header too short\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   count -= hdr_size;
@@ -327,7 +315,7 @@
    * been transferred already.
    */
 
-  memcpy_fromfs (&((char *) &header)[offs], &((addr)[offs]), hdr_size - offs);
+  memcpy_fromfs (&((char *) &header)[offs], &(addr)[offs], hdr_size - offs);
 
   if (count < header.len)
     {
@@ -345,10 +333,10 @@
 
       data = get_fs_byte (&((addr)[hdr_size + i]));
       if (i == 0 && !(data & 0x80))
-	return -EINVAL;
+	return -(EINVAL);
 
       if (maui_write (data) == -1)
-	return -EIO;
+	return -(EIO);
     }
 
   if ((i = maui_read ()) != 0x80)
@@ -356,7 +344,7 @@
       if (i != -1)
 	printk ("Maui: Error status %02x\n", i);
 
-      return -EIO;
+      return -(EIO);
     }
 
   return 0;
@@ -377,7 +365,7 @@
   if (snd_set_irq_handler (hw_config->irq, mauiintr, "Maui", maui_osp) < 0)
     return 0;
 
-  maui_sleep_flag.mode = WK_NONE;
+  maui_sleep_flag.flags = WK_NONE;
 /*
  * Initialize the processor if necessary
  */
@@ -448,22 +436,23 @@
   return ret;
 }
 
-long
-attach_maui (long mem_start, struct address_info *hw_config)
+void
+attach_maui (struct address_info *hw_config)
 {
   int             this_dev = num_midis;
 
   conf_printf ("Maui", hw_config);
 
   hw_config->irq *= -1;
-  mem_start = attach_mpu401 (mem_start, hw_config);
+  hw_config->name = "Maui";
+  attach_mpu401 (hw_config);
 
   if (num_midis > this_dev)	/* The MPU401 driver installed itself */
     {
       struct synth_operations *synth;
 
       /*
-       * Intercept patch loading calls so that they can be handled
+       * Intercept patch loading calls so that they canbe handled
        * by the Maui driver.
        */
 
@@ -477,7 +466,6 @@
       else
 	printk ("Maui: Can't install patch loader\n");
     }
-  return mem_start;
 }
 
 void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c
--- v2.0.0/linux/drivers/sound/midi_synth.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/midi_synth.c	Sun Jun 30 11:44:03 1996
@@ -4,27 +4,11 @@
  * High level midi sequencer manager for dumb MIDI interfaces.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -291,7 +275,7 @@
     {
 
     case SNDCTL_SYNTH_INFO:
-      memcpy_tofs ((&((char *) arg)[0]), synth_devs[dev]->info, sizeof (struct synth_info));
+      memcpy_tofs (&((char *) arg)[0], synth_devs[dev]->info, sizeof (struct synth_info));
 
       return 0;
       break;
@@ -301,7 +285,7 @@
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 }
 
@@ -453,7 +437,7 @@
   struct midi_input_info *inc;
 
   if (orig_dev < 0 || orig_dev > num_midis)
-    return -ENXIO;
+    return -(ENXIO);
 
   midi2synth[orig_dev] = dev;
   sysex_state[dev] = 0;
@@ -474,7 +458,7 @@
   inc->m_prev_status = 0x00;
   restore_flags (flags);
 
-  sysex_sleep_flag.mode = WK_NONE;
+  sysex_sleep_flag.flags = WK_NONE;
 
   return 1;
 }
@@ -519,13 +503,13 @@
   if (format != SYSEX_PATCH)
     {
       printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format);
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   if (count < hdr_size)
     {
       printk ("MIDI Error: Patch header too short\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   count -= hdr_size;
@@ -535,7 +519,7 @@
    * been transferred already.
    */
 
-  memcpy_fromfs (&((char *) &sysex)[offs], &((addr)[offs]), hdr_size - offs);
+  memcpy_fromfs (&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs);
 
   if (count < sysex.len)
     {
@@ -547,7 +531,7 @@
   left = sysex.len;
   src_offs = 0;
 
-  sysex_sleep_flag.mode = WK_NONE;
+  sysex_sleep_flag.flags = WK_NONE;
 
   for (i = 0; i < left && !current_got_fatal_signal (); i++)
     {
@@ -565,7 +549,7 @@
 	  if (data != 0xf0)
 	    {
 	      printk ("Error: Sysex start missing\n");
-	      return -EINVAL;
+	      return -(EINVAL);
 	    }
 	}
 
@@ -573,20 +557,20 @@
 	     !current_got_fatal_signal ())
 
 	{
-	  unsigned long   tl;
+	  unsigned long   tlimit;
 
 	  if (1)
-	    current_set_timeout (tl = jiffies + (1));
+	    current_set_timeout (tlimit = jiffies + (1));
 	  else
-	    tl = (unsigned long) -1;
-	  sysex_sleep_flag.mode = WK_SLEEP;
+	    tlimit = (unsigned long) -1;
+	  sysex_sleep_flag.flags = WK_SLEEP;
 	  module_interruptible_sleep_on (&sysex_sleeper);
-	  if (!(sysex_sleep_flag.mode & WK_WAKEUP))
+	  if (!(sysex_sleep_flag.flags & WK_WAKEUP))
 	    {
-	      if (jiffies >= tl)
-		sysex_sleep_flag.mode |= WK_TIMEOUT;
+	      if (jiffies >= tlimit)
+		sysex_sleep_flag.flags |= WK_TIMEOUT;
 	    }
-	  sysex_sleep_flag.mode &= ~WK_SLEEP;
+	  sysex_sleep_flag.flags &= ~WK_SLEEP;
 	};			/* Wait for timeout */
 
       if (!first_byte && data & 0x80)
@@ -668,7 +652,7 @@
 int
 midi_synth_patchmgr (int dev, struct patmgr_info *rec)
 {
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 void
@@ -744,7 +728,7 @@
       if (!midi_devs[orig_dev]->putc (orig_dev, bytes[i]))
 	{
 /*
- * Hardware level buffer is full. Abort the sysex message.
+ * Hardware leve buffer is full. Abort the sysex message.
  */
 
 	  int             timeout = 0;
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v2.0.0/linux/drivers/sound/midibuf.c	Sun Mar 24 22:50:08 1996
+++ linux/drivers/sound/midibuf.c	Sun Jun 30 11:44:04 1996
@@ -4,27 +4,11 @@
  * Device file manager for /dev/midi#
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -112,20 +96,20 @@
 	   midi_devs[dev]->buffer_status (dev))
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (HZ / 10)
-	  current_set_timeout (tl = jiffies + (HZ / 10));
+	  current_set_timeout (tlimit = jiffies + (HZ / 10));
 	else
-	  tl = (unsigned long) -1;
-	midi_sleep_flag[dev].mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	midi_sleep_flag[dev].flags = WK_SLEEP;
 	module_interruptible_sleep_on (&midi_sleeper[dev]);
-	if (!(midi_sleep_flag[dev].mode & WK_WAKEUP))
+	if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      midi_sleep_flag[dev].mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      midi_sleep_flag[dev].flags |= WK_TIMEOUT;
 	  }
-	midi_sleep_flag[dev].mode &= ~WK_SLEEP;
+	midi_sleep_flag[dev].flags &= ~WK_SLEEP;
       };
 }
 
@@ -145,9 +129,9 @@
   if (SPACE_AVAIL (midi_in_buf[dev]))
     {
       QUEUE_BYTE (midi_in_buf[dev], data);
-      if ((input_sleep_flag[dev].mode & WK_SLEEP))
+      if ((input_sleep_flag[dev].flags & WK_SLEEP))
 	{
-	  input_sleep_flag[dev].mode = WK_WAKEUP;
+	  input_sleep_flag[dev].flags = WK_WAKEUP;
 	  module_wake_up (&input_sleeper[dev]);
 	};
     }
@@ -184,9 +168,9 @@
 	      }
 
 	    if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&
-		(midi_sleep_flag[dev].mode & WK_SLEEP))
+		(midi_sleep_flag[dev].flags & WK_SLEEP))
 	      {
-		midi_sleep_flag[dev].mode = WK_WAKEUP;
+		midi_sleep_flag[dev].flags = WK_WAKEUP;
 		module_wake_up (&midi_sleeper[dev]);
 	      };
 	  }
@@ -218,7 +202,7 @@
   if (dev < 0 || dev >= num_midis)
     {
       printk ("Sound: Nonexistent MIDI interface %d\n", dev);
-      return -ENXIO;
+      return -(ENXIO);
     }
 
   /*
@@ -233,31 +217,31 @@
 
   parms[dev].prech_timeout = 0;
 
-  midi_in_buf[dev] = (struct midi_buf *) kmalloc (sizeof (struct midi_buf), GFP_KERNEL);
+  midi_in_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf));
 
   if (midi_in_buf[dev] == NULL)
     {
       printk ("midi: Can't allocate buffer\n");
       midi_devs[dev]->close (dev);
-      return -EIO;
+      return -(EIO);
     }
   midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
 
-  midi_out_buf[dev] = (struct midi_buf *) kmalloc (sizeof (struct midi_buf), GFP_KERNEL);
+  midi_out_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf));
 
   if (midi_out_buf[dev] == NULL)
     {
       printk ("midi: Can't allocate buffer\n");
       midi_devs[dev]->close (dev);
-      kfree (midi_in_buf[dev]);
+      vfree (midi_in_buf[dev]);
       midi_in_buf[dev] = NULL;
-      return -EIO;
+      return -(EIO);
     }
   midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
   open_devs++;
 
-  midi_sleep_flag[dev].mode = WK_NONE;
-  input_sleep_flag[dev].mode = WK_NONE;
+  midi_sleep_flag[dev].flags = WK_NONE;
+  input_sleep_flag[dev].flags = WK_NONE;
 
   if (open_devs < 2)		/* This was first open */
     {
@@ -302,20 +286,20 @@
 	     DATA_AVAIL (midi_out_buf[dev]))
 
 	{
-	  unsigned long   tl;
+	  unsigned long   tlimit;
 
 	  if (0)
-	    current_set_timeout (tl = jiffies + (0));
+	    current_set_timeout (tlimit = jiffies + (0));
 	  else
-	    tl = (unsigned long) -1;
-	  midi_sleep_flag[dev].mode = WK_SLEEP;
+	    tlimit = (unsigned long) -1;
+	  midi_sleep_flag[dev].flags = WK_SLEEP;
 	  module_interruptible_sleep_on (&midi_sleeper[dev]);
-	  if (!(midi_sleep_flag[dev].mode & WK_WAKEUP))
+	  if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
 	    {
-	      if (jiffies >= tl)
-		midi_sleep_flag[dev].mode |= WK_TIMEOUT;
+	      if (jiffies >= tlimit)
+		midi_sleep_flag[dev].flags |= WK_TIMEOUT;
 	    }
-	  midi_sleep_flag[dev].mode &= ~WK_SLEEP;
+	  midi_sleep_flag[dev].flags &= ~WK_SLEEP;
 	};			/*
 				   * Sync
 				 */
@@ -329,8 +313,8 @@
 
   midi_devs[dev]->close (dev);
 
-  kfree (midi_in_buf[dev]);
-  kfree (midi_out_buf[dev]);
+  vfree (midi_in_buf[dev]);
+  vfree (midi_out_buf[dev]);
   midi_in_buf[dev] = NULL;
   midi_out_buf[dev] = NULL;
   if (open_devs < 2)
@@ -365,25 +349,25 @@
 	{
 
 	  {
-	    unsigned long   tl;
+	    unsigned long   tlimit;
 
 	    if (0)
-	      current_set_timeout (tl = jiffies + (0));
+	      current_set_timeout (tlimit = jiffies + (0));
 	    else
-	      tl = (unsigned long) -1;
-	    midi_sleep_flag[dev].mode = WK_SLEEP;
+	      tlimit = (unsigned long) -1;
+	    midi_sleep_flag[dev].flags = WK_SLEEP;
 	    module_interruptible_sleep_on (&midi_sleeper[dev]);
-	    if (!(midi_sleep_flag[dev].mode & WK_WAKEUP))
+	    if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
 	      {
-		if (jiffies >= tl)
-		  midi_sleep_flag[dev].mode |= WK_TIMEOUT;
+		if (jiffies >= tlimit)
+		  midi_sleep_flag[dev].flags |= WK_TIMEOUT;
 	      }
-	    midi_sleep_flag[dev].mode &= ~WK_SLEEP;
+	    midi_sleep_flag[dev].flags &= ~WK_SLEEP;
 	  };
 	  if (current_got_fatal_signal ())
 	    {
 	      restore_flags (flags);
-	      return -EINTR;
+	      return -(EINTR);
 	    }
 
 	  n = SPACE_AVAIL (midi_out_buf[dev]);
@@ -394,7 +378,7 @@
 
       for (i = 0; i < n; i++)
 	{
-	  memcpy_fromfs ((char *) &tmp_data, &((buf)[c]), 1);
+	  memcpy_fromfs ((char *) &tmp_data, &(buf)[c], 1);
 	  QUEUE_BYTE (midi_out_buf[dev], tmp_data);
 	  c++;
 	}
@@ -424,23 +408,23 @@
     {
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (parms[dev].prech_timeout)
-	  current_set_timeout (tl = jiffies + (parms[dev].prech_timeout));
+	  current_set_timeout (tlimit = jiffies + (parms[dev].prech_timeout));
 	else
-	  tl = (unsigned long) -1;
-	input_sleep_flag[dev].mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	input_sleep_flag[dev].flags = WK_SLEEP;
 	module_interruptible_sleep_on (&input_sleeper[dev]);
-	if (!(input_sleep_flag[dev].mode & WK_WAKEUP))
+	if (!(input_sleep_flag[dev].flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      input_sleep_flag[dev].mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      input_sleep_flag[dev].flags |= WK_TIMEOUT;
 	  }
-	input_sleep_flag[dev].mode &= ~WK_SLEEP;
+	input_sleep_flag[dev].flags &= ~WK_SLEEP;
       };
       if (current_got_fatal_signal ())
-	c = -EINTR;		/*
+	c = -(EINTR);		/*
 				   * The user is getting restless
 				 */
     }
@@ -457,7 +441,7 @@
       while (c < n)
 	{
 	  REMOVE_BYTE (midi_in_buf[dev], tmp_data);
-	  memcpy_tofs (&((buf)[c]), (char *) &tmp_data, 1);
+	  memcpy_tofs (&(buf)[c], (char *) &tmp_data, 1);
 	  c++;
 	}
     }
@@ -482,7 +466,7 @@
       else
 	printk ("/dev/midi%d: No coprocessor for this device\n", dev);
 
-      return -ENXIO;
+      return -(ENXIO);
     }
   else
     switch (cmd)
@@ -514,7 +498,7 @@
       if (!DATA_AVAIL (midi_in_buf[dev]))
 	{
 
-	  input_sleep_flag[dev].mode = WK_SLEEP;
+	  input_sleep_flag[dev].flags = WK_SLEEP;
 	  module_select_wait (&input_sleeper[dev], wait);
 	  return 0;
 	}
@@ -525,7 +509,7 @@
       if (SPACE_AVAIL (midi_out_buf[dev]))
 	{
 
-	  midi_sleep_flag[dev].mode = WK_SLEEP;
+	  midi_sleep_flag[dev].flags = WK_SLEEP;
 	  module_select_wait (&midi_sleeper[dev], wait);
 	  return 0;
 	}
@@ -540,10 +524,9 @@
 }
 
 
-long
-MIDIbuf_init (long mem_start)
+void
+MIDIbuf_init (void)
 {
-  return mem_start;
 }
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c
--- v2.0.0/linux/drivers/sound/mpu401.c	Tue May  7 16:22:35 1996
+++ linux/drivers/sound/mpu401.c	Sun Jun 30 11:44:06 1996
@@ -4,27 +4,11 @@
  * The low level driver for Roland MPU-401 compatible Midi cards.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -508,21 +492,21 @@
   struct mpu_config *devc;
 
   if (dev < 0 || dev >= num_midis)
-    return -ENXIO;
+    return -(ENXIO);
 
   devc = &dev_conf[dev];
 
   if (devc->opened)
     {
       printk ("MPU-401: Midi busy\n");
-      return -EBUSY;
+      return -(EBUSY);
     }
 
   /*
      *  Verify that the device is really running.
      *  Some devices (such as Ensoniq SoundScape don't
      *  work before the on board processor (OBP) is initialized
-     *  by downloading its microcode.
+     *  by downloadin it's microcode.
    */
 
   if (!devc->initialized)
@@ -530,7 +514,7 @@
       if (mpu401_status (devc) == 0xff)		/* Bus float */
 	{
 	  printk ("MPU-401: Device not initialized properly\n");
-	  return -EIO;
+	  return -(EIO);
 	}
       reset_mpu401 (devc);
     }
@@ -624,7 +608,7 @@
 				 */
     {
       printk ("MPU-401 commands not possible in the UART mode\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   /*
@@ -643,7 +627,7 @@
   if (timeout-- <= 0)
     {
       printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
-      return -EIO;
+      return -(EIO);
     }
 
   save_flags (flags);
@@ -667,7 +651,7 @@
 	      ok = 1;
 	  }
 	else
-	  {			/* Device is not currently open. Use simpler method */
+	  {			/* Device is not currently open. Use simplier method */
 	    if (read_data (devc) == MPU_ACK)
 	      ok = 1;
 	  }
@@ -677,7 +661,7 @@
     {
       restore_flags (flags);
       /*       printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */
-      return -EIO;
+      return -(EIO);
     }
 
   if (cmd->nr_args)
@@ -689,7 +673,7 @@
 	  {
 	    restore_flags (flags);
 	    printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
-	    return -EIO;
+	    return -(EIO);
 	  }
       }
 
@@ -711,7 +695,7 @@
 	  {
 	    restore_flags (flags);
 	    /* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd);  */
-	    return -EIO;
+	    return -(EIO);
 	  }
       }
 
@@ -796,7 +780,7 @@
   switch (cmd)
     {
     case 1:
-      memcpy_fromfs ((char *) init_sequence, &(((char *) arg)[0]), sizeof (init_sequence));
+      memcpy_fromfs ((char *) init_sequence, &((char *) arg)[0], sizeof (init_sequence));
       return 0;
       break;
 
@@ -804,7 +788,7 @@
       if (!(devc->capabilities & MPU_CAP_INTLG))	/* No intelligent mode */
 	{
 	  printk ("MPU-401: Intelligent mode not supported by the HW\n");
-	  return -EINVAL;
+	  return -(EINVAL);
 	}
       set_uart_mode (dev, devc, !get_fs_long ((long *) arg));
       return 0;
@@ -815,18 +799,18 @@
 	int             ret;
 	mpu_command_rec rec;
 
-	memcpy_fromfs ((char *) &rec, &(((char *) arg)[0]), sizeof (rec));
+	memcpy_fromfs ((char *) &rec, &((char *) arg)[0], sizeof (rec));
 
 	if ((ret = mpu401_command (dev, &rec)) < 0)
 	  return ret;
 
-	memcpy_tofs ((&((char *) arg)[0]), (char *) &rec, sizeof (rec));
+	memcpy_tofs (&((char *) arg)[0], (char *) &rec, sizeof (rec));
 	return 0;
       }
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 }
 
@@ -853,7 +837,7 @@
   midi_dev = synth_devs[dev]->midi_dev;
 
   if (midi_dev < 0 || midi_dev > num_midis)
-    return -ENXIO;
+    return -(ENXIO);
 
   devc = &dev_conf[midi_dev];
 
@@ -861,7 +845,7 @@
     {
 
     case SNDCTL_SYNTH_INFO:
-      memcpy_tofs ((&((char *) arg)[0]), &mpu_synth_info[midi_dev], sizeof (struct synth_info));
+      memcpy_tofs (&((char *) arg)[0], &mpu_synth_info[midi_dev], sizeof (struct synth_info));
 
       return 0;
       break;
@@ -871,7 +855,7 @@
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 }
 
@@ -885,7 +869,7 @@
 
   if (midi_dev < 0 || midi_dev > num_midis)
     {
-      return -ENXIO;
+      return -(ENXIO);
     }
 
   devc = &dev_conf[midi_dev];
@@ -894,7 +878,7 @@
      *  Verify that the device is really running.
      *  Some devices (such as Ensoniq SoundScape don't
      *  work before the on board processor (OBP) is initialized
-     *  by downloading its microcode.
+     *  by downloadin it's microcode.
    */
 
   if (!devc->initialized)
@@ -902,7 +886,7 @@
       if (mpu401_status (devc) == 0xff)		/* Bus float */
 	{
 	  printk ("MPU-401: Device not initialized properly\n");
-	  return -EIO;
+	  return -(EIO);
 	}
       reset_mpu401 (devc);
     }
@@ -910,7 +894,7 @@
   if (devc->opened)
     {
       printk ("MPU-401: Midi busy\n");
-      return -EBUSY;
+      return -(EBUSY);
     }
 
   devc->mode = MODE_SYNTH;
@@ -1047,8 +1031,8 @@
   restore_flags (flags);
 }
 
-long
-attach_mpu401 (long mem_start, struct address_info *hw_config)
+void
+attach_mpu401 (struct address_info *hw_config)
 {
   unsigned long   flags;
   char            revision_char;
@@ -1058,7 +1042,7 @@
   if (num_midis >= MAX_MIDI_DEV)
     {
       printk ("MPU-401: Too many midi devices detected\n");
-      return mem_start;
+      return;
     }
 
   devc = &dev_conf[num_midis];
@@ -1091,14 +1075,14 @@
       if (!reset_mpu401 (devc))
 	{
 	  printk ("MPU401: Device didn't respond\n");
-	  return mem_start;
+	  return;
 	}
 
       if (!devc->shared_irq)
 	if (snd_set_irq_handler (devc->irq, mpuintr, "mpu401", devc->osp) < 0)
 	  {
 	    printk ("MPU401: Failed to allocate IRQ%d\n", devc->irq);
-	    return mem_start;
+	    return;
 	  }
 
       save_flags (flags);
@@ -1117,15 +1101,15 @@
 	devc->capabilities |= MPU_CAP_INTLG;	/* Supports intelligent mode */
 
 
-  mpu401_synth_operations[num_midis] = (struct synth_operations *) (sound_mem_blocks[sound_num_blocks] = kmalloc (sizeof (struct synth_operations), GFP_KERNEL));
+  mpu401_synth_operations[num_midis] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations)));
 
-  if (sound_num_blocks < 1024)
-    sound_num_blocks++;;
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
 
   if (mpu401_synth_operations[num_midis] == NULL)
     {
       printk ("mpu401: Can't allocate memory\n");
-      return mem_start;
+      return;
     }
 
   if (!(devc->capabilities & MPU_CAP_INTLG))	/* No intelligent mode */
@@ -1177,12 +1161,15 @@
 
       devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
 
-      sprintf (mpu_synth_info[num_midis].name,
-	       "MPU-401 %d.%d%c Midi interface #%d",
-	       (int) (devc->version & 0xf0) >> 4,
-	       devc->version & 0x0f,
-	       revision_char,
-	       n_mpu_devs);
+      if (hw_config->name)
+	sprintf (mpu_synth_info[num_midis].name, "%s (MPU401)", hw_config->name);
+      else
+	sprintf (mpu_synth_info[num_midis].name,
+		 "MPU-401 %d.%d%c Midi interface #%d",
+		 (int) (devc->version & 0xf0) >> 4,
+		 devc->version & 0x0f,
+		 revision_char,
+		 n_mpu_devs);
     }
 
   strcpy (mpu401_midi_operations[num_midis].info.name,
@@ -1199,7 +1186,6 @@
 
   irq2dev[devc->irq] = num_midis;
   midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno];
-  return mem_start;
 }
 
 static int
@@ -1348,7 +1334,7 @@
   /*
      * The MPU-401 supports just a limited set of possible timebase values.
      * Since the applications require more choices, the driver has to
-     * program the HW to do its best and to convert between the HW and
+     * program the HW to do it's best and to convert between the HW and
      * actual timebases.
    */
 
@@ -1478,7 +1464,7 @@
   int             midi_dev = sound_timer_devs[dev]->devlink;
 
   if (timer_open)
-    return -EBUSY;
+    return -(EBUSY);
 
   tmr_reset ();
   curr_tempo = 50;
@@ -1677,7 +1663,7 @@
 
     case SNDCTL_SEQ_CTRLRATE:
       if (get_fs_long ((long *) arg) != 0)	/* Can't change */
-	return -EINVAL;
+	return -(EINVAL);
 
       return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60);
       break;
@@ -1691,7 +1677,7 @@
     default:;
     }
 
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v2.0.0/linux/drivers/sound/opl3.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/opl3.c	Sun Jun 30 11:44:07 1996
@@ -4,27 +4,11 @@
  * A low level driver for Yamaha YM3812 and OPL-3 -chips
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -58,6 +42,7 @@
 
 typedef struct opl_devinfo
   {
+    int             base;
     int             left_io, right_io;
     int             nr_voice;
     int             lv_map[MAX_VOICE];
@@ -133,12 +118,12 @@
       {
 	struct sbi_instrument ins;
 
-	memcpy_fromfs ((char *) &ins, &(((char *) arg)[0]), sizeof (ins));
+	memcpy_fromfs ((char *) &ins, &((char *) arg)[0], sizeof (ins));
 
 	if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
 	  {
 	    printk ("FM Error: Invalid instrument number %d\n", ins.channel);
-	    return -EINVAL;
+	    return -(EINVAL);
 	  }
 
 	pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0);
@@ -149,7 +134,7 @@
     case SNDCTL_SYNTH_INFO:
       devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
 
-      memcpy_tofs ((&((char *) arg)[0]), &devc->fm_info, sizeof (devc->fm_info));
+      memcpy_tofs (&((char *) arg)[0], &devc->fm_info, sizeof (devc->fm_info));
       return 0;
       break;
 
@@ -164,7 +149,7 @@
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 
 }
@@ -190,9 +175,9 @@
     return 0;
 
 
-  devc = (struct opl_devinfo *) (sound_mem_blocks[sound_num_blocks] = kmalloc (sizeof (*devc), GFP_KERNEL));
-  if (sound_num_blocks < 1024)
-    sound_num_blocks++;;
+  devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (*devc)));
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
 
   if (devc == NULL)
     {
@@ -201,6 +186,7 @@
     }
 
   devc->osp = osp;
+  devc->base = ioaddr;
 
   /* Reset timers 1 and 2 */
   opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
@@ -266,7 +252,7 @@
       detected_model = 3;
 
       /*
-       * Detect availability of OPL4 (_experimental_). Works probably
+       * Detect availability of OPL4 (_experimental_). Works propably
        * only after a cold boot. In addition the OPL4 port
        * of the chip may not be connected to the PC bus at all.
        */
@@ -319,7 +305,7 @@
 }
 
 static int
-opl3_kill_note (int dev, int voice, int note, int velocity)
+opl3_kill_note (int devno, int voice, int note, int velocity)
 {
   struct physical_voice_info *map;
 
@@ -797,7 +783,7 @@
 }
 
 static void
-opl3_reset (int dev)
+opl3_reset (int devno)
 {
   int             i;
 
@@ -821,7 +807,7 @@
 			KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff);
 	}
 
-      opl3_kill_note (dev, i, 0, 64);
+      opl3_kill_note (devno, i, 0, 64);
     }
 
   if (devc->model == 2)
@@ -841,7 +827,7 @@
   int             i;
 
   if (devc->busy)
-    return -EBUSY;
+    return -(EBUSY);
   devc->busy = 1;
 
   devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9;
@@ -887,15 +873,15 @@
   if (count < sizeof (ins))
     {
       printk ("FM Error: Patch record too short\n");
-      return -EINVAL;
+      return -(EINVAL);
     }
 
-  memcpy_fromfs (&((char *) &ins)[offs], &((addr)[offs]), sizeof (ins) - offs);
+  memcpy_fromfs (&((char *) &ins)[offs], &(addr)[offs], sizeof (ins) - offs);
 
   if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
     {
       printk ("FM Error: Invalid instrument number %d\n", ins.channel);
-      return -EINVAL;
+      return -(EINVAL);
     }
   ins.key = format;
 
@@ -1055,7 +1041,7 @@
 static int
 opl3_patchmgr (int dev, struct patmgr_info *rec)
 {
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
@@ -1173,25 +1159,26 @@
   opl3_setup_voice
 };
 
-long
-opl3_init (long mem_start, int ioaddr, int *osp)
+void
+opl3_init (int ioaddr, int *osp)
 {
   int             i;
 
   if (num_synths >= MAX_SYNTH_DEV)
     {
       printk ("OPL3 Error: Too many synthesizers\n");
-      return mem_start;
+      return;
     }
 
   if (devc == NULL)
     {
       printk ("OPL3: Device control structure not initialized.\n");
-      return mem_start;
+      return;
     }
 
   memset ((char *) devc, 0x00, sizeof (*devc));
   devc->osp = osp;
+  devc->base = ioaddr;
 
   devc->nr_voice = 9;
   strcpy (devc->fm_info.name, "OPL2");
@@ -1257,7 +1244,6 @@
   for (i = 0; i < SBFM_MAXINSTR; i++)
     devc->i_map[i].channel = -1;
 
-  return mem_start;
 }
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/opl3.h linux/drivers/sound/opl3.h
--- v2.0.0/linux/drivers/sound/opl3.h	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/opl3.h	Sun Jun 30 11:43:38 1996
@@ -2,27 +2,11 @@
  *	opl3.h	- Definitions of the OPL-3 registers
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 
 /*
@@ -34,7 +18,7 @@
  *
  *	The percussive mode is implemented in the left side only.
  *
- *	With the above exceptions the both sides can be operated independently.
+ *	With the above exeptions the both sides can be operated independently.
  *	
  *	A 4 OP voice can be created by setting the corresponding
  *	bit at offset 4 of the right side.
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v2.0.0/linux/drivers/sound/os.h	Sun Mar 24 22:49:45 1996
+++ linux/drivers/sound/os.h	Sun Jun 30 11:43:41 1996
@@ -18,14 +18,11 @@
 #include <linux/signal.h>
 #include <linux/fcntl.h>
 #include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/tty.h>
 #include <linux/ctype.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/dma.h>
-#include <sys/kd.h>
 #include <linux/wait.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
@@ -40,7 +37,7 @@
 #define TRUE	1
 
 struct snd_wait {
-	  int mode;
+	  int flags;
 	};
 
 extern int sound_alloc_dma(int chn, char *deviceID);
@@ -51,7 +48,7 @@
 #define RUNTIME_DMA_ALLOC
 
 extern caddr_t sound_mem_blocks[1024];
-extern int sound_num_blocks;
+extern int sound_nblocks;
 
 #undef PSEUDO_DMA_AUTOINIT
 #define ALLOW_BUFFER_MAPPING
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas.h linux/drivers/sound/pas.h
--- v2.0.0/linux/drivers/sound/pas.h	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/pas.h	Thu Jan  1 02:00:00 1970
@@ -1,236 +0,0 @@
-/* 																*/
-/*	Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards.			*/
-/* 																*/
-/* 	Feel free to use this header file in any application you create that has support for the Media Vision			*/
-/*	Pro AudioSpectrum second generation sound cards. Other uses prohibited without prior permission.			*/
-/* 																*/
-/*										- cmetz@thor.tjhsst.edu				*/
-/* 																*/
-/*	Notes:															*/
-/* 																*/
-/*	*	All of these ports go into the MVD101 multimedia controller chip, which	then signals the other chips to do	*/
-/* 		the actual work. Many ports like the FM ones functionally attach directly to the destination chip though 	*/
-/* 		they don't actually have a direct connection.									*/
-/* 																*/
-/* 	*	The PAS2 series cards have an MVD101 multimedia controller chip, the original PAS cards don't. The original	*/
-/* 		PAS cards are pretty defunct now, so no attempt is made here to support them. 					*/
-/*																*/
-/*	*	The PAS2 series cards are all really different at the hardware level, though the MVD101 hides some of the 	*/
-/*		incompatibilities, there still are differences that need to be accounted for.					*/
-/*																*/
-/*		Card		CD-ROM interface	PCM chip		Mixer chip		FM chip			*/
-/* 		PAS Plus	Sony proprietary	(Crystal?) 8-bit DAC	National 		OPL3			*/
-/* 		PAS 16		Zilog SCSI		MVA416 16-bit Codec	MVA508 			OPL3			*/
-/* 		CDPC		Sony proprietary	Sony 16-bit Codec	National		OPL3			*/
-/*		Fusion CD 16	Sony proprietary	MVA416 16-bit Codec	MVA508			OPL3			*/
-/*		Fusion CD	Sony proprietary	(Crystal?) 8-bit DAC	National		OPL3			*/
-/* 																*/
-#define PAS_DEFAULT_BASE		0x388
-
-/*      Symbolic Name			Value 		   R W  Subsystem	Description					*/
-#define SPEAKER_CONTROL			0x61		/*   W	PC speaker 	Control register 				*/
-#define SPEAKER_CONTROL_GHOST		0x738B		/* R W	PC speaker 	Control ghost register				*/
-#define SPEAKER_TIMER_CONTROL		0x43		/*   W  PC speaker 	Timer control register				*/
-#define SPEAKER_TIMER_CONTROL_GHOST	0x778B		/* R W  PC speaker 	Timer control register ghost			*/
-#define SPEAKER_TIMER_DATA		0x42		/*   W  PC speaker 	Timer data register				*/
-#define SPEAKER_TIMER_DATA_GHOST	0x138A		/* R W  PC speaker	Timer data register ghost			*/
-
-#define WARM_BOOT			0x41		/*   W  Control		Used to detect system warm boot	  		*/
-#define WARM_BOOT_GHOST			0x7789		/* ? W  Control		Use to get the card to fake warm boot		*/
-#define MASTER_DECODE			0x9A01		/*   W  Control		Address >> 2 of card base address		*/
-#define PRESCALE_DIVIDER		0xBF8A		/* R W	PCM		Ration between Codec clock and master clock	*/
-#define WAIT_STATE			0xBF88		/* R W	Control		Four-bit bus wait-state count (~140ns ea.)	*/
-#define BOARD_REV_ID			0x2789		/* R	Control		Extended Board Revision ID			*/
-
-#define CHIP_REV			0xFF88		/* R	0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */
-
-#define SYSTEM_CONFIGURATION_1		0x8388		/* R W	Control								*/
-#	define S_C_1_PCS_ENABLE	0x01		/* R W  PC speaker	1=enable, 0=disable PC speaker emulation	*/
-#	define S_C_1_PCM_CLOCK_SELECT	0x02		/* R W  PCM		1=14.31818Mhz/12, 0=28.224Mhz master clock	*/ 
-#	define S_C_1_FM_EMULATE_CLOCK	0x04		/* R W  FM		1=use 28.224Mhz/2, 0=use 14.31818Mhz clock	*/
-#	define S_C_1_PCS_STEREO	0x10 		/* R W  PC speaker	1=enable PC speaker stereo effect, 0=disable	*/
-#	define S_C_1_PCS_REALSOUND	0x20		/* R W  PC speaker	1=enable RealSound enhancement, 0=disable	*/
-#	define S_C_1_FORCE_EXT_RESET	0x40		/* R W  Control		Force external reset				*/
-#	define S_C_1_FORCE_INT_RESET	0x80		/* R W  Control		Force internal reset				*/
-#define SYSTEM_CONFIGURATION_2		0x8389		/* R W  Control								*/
-#	define S_C_2_PCM_OVERSAMPLING	0x03		/* R W  PCM		00=0x, 01=2x, 10=4x, 11=reserved		*/
-#	define S_C_2_PCM_16_BIT	0x04		/* R W	PCM		1=16-bit, 0=8-bit samples			*/
-#define SYSTEM_CONFIGURATION_3		0x838A		/* R W	Control								*/
-#	define S_C_3_PCM_CLOCK_SELECT	0x02		/* R W	PCM		1=use 1.008Mhz clock for PCM, 0=don't		*/
-#define SYSTEM_CONFIGURATION_4		0x838B		/* R W  Control		CD-ROM interface controls			*/
-
-#define IO_CONFIGURATION_1		0xF388		/* R W	Control								*/
-#	define I_C_1_BOOT_RESET_ENABLE	0x80		/* R W  Control		1=reset board on warm boot, 0=don't		*/
-#	define I_C_1_JOYSTICK_ENABLE	0x40		/* R W  Control		1=enable joystick port, 0=don't		        */
-#define IO_CONFIGURATION_2		0xF389		/* R W  Control								*/
-#	define	I_C_2_PCM_DMA_DISABLED	0x00		/* R W  PCM		PCM DMA disabled				*/
-#define IO_CONFIGURATION_3		0xF38A		/* R W	Control								*/
-#	define I_C_3_PCM_IRQ_DISABLED	0x00		/* R W  PCM		PCM IRQ disabled				*/
-
-#define COMPATIBILITY_ENABLE		0xF788		/* R W  Control								*/
-#	define C_E_MPU401_ENABLE	0x01		/* R W	MIDI		1=enable, 0=disable MPU401 MIDI emulation	*/
-#	define C_E_SB_ENABLE		0x02		/* R W  PCM		1=enable, 0=disable Sound Blaster emulation	*/
-#	define C_E_SB_ACTIVE		0x04		/* R    PCM		"Sound Blaster Interrupt active"		*/
-#	define C_E_MPU401_ACTIVE	0x08		/* R	MIDI		"MPU UART mode active"				*/
-#	define C_E_PCM_COMPRESSION	0x10		/* R W  PCM		1=enable, 0=disabled compression		*/
-#define EMULATION_ADDRESS		0xF789		/* R W  Control								*/
-#	define E_A_SB_BASE		0x0f		/* R W  PCM		bits A4-A7 for SB base port			*/
-#	define E_A_MPU401_BASE		0xf0		/* R W	MIDI		bits A4-A7 for MPU401 base port 		*/
-#define EMULATION_CONFIGURATION		0xFB8A		/* R W			***** Only valid on newer PAS2 cards (?) *****	*/
-#	define E_C_MPU401_IRQ		0x07		/* R W	MIDI		MPU401 emulation IRQ				*/
-#	define E_C_SB_IRQ		0x38		/* R W  PCM		SB emulation IRQ				*/
-#	define E_C_SB_DMA		0xC0		/* R W	PCM		SB emulation DMA				*/
-
-#define OPERATION_MODE_1		0xEF8B		/* R	Control								*/
-#	define	O_M_1_CDROM_TYPE	0x03		/* R	CD-ROM		3=SCSI, 2=Sony, 0=no CD-ROM interface		*/
-#	define O_M_1_FM_TYPE		0x04		/* R	FM		1=stereo, 0=mono FM chip			*/
-#	define O_M_1_PCM_TYPE 		0x08		/* R	PCM		1=16-bit Codec, 0=8-bit DAC			*/
-#define OPERATION_MODE_2		0xFF8B		/* R	Control								*/
-#	define O_M_2_PCS_ENABLED	0x02		/* R	PC speaker	PC speaker emulation 1=enabled, 0=disabled	*/
-#	define O_M_2_BUS_TIMING	0x10		/* R	Control		1=AT bus timing, 0=XT bus timing		*/
-#	define O_M_2_BOARD_REVISION	0xe0		/* R	Control		Board revision					*/
-
-#define INTERRUPT_MASK			0x0B8B		/* R W	Control								*/
-#	define I_M_FM_LEFT_IRQ_ENABLE	0x01		/* R W	FM		Enable FM left interrupt			*/
-#	define I_M_FM_RIGHT_IRQ_ENABLE	0x02		/* R W	FM		Enable FM right interrupt			*/
-#	define I_M_PCM_RATE_IRQ_ENABLE	0x04		/* R W	PCM		Enable Sample Rate interrupt			*/
-#	define I_M_PCM_BUFFER_IRQ_ENABLE 0x08		/* R W	PCM		Enable Sample Buffer interrupt			*/
-#	define I_M_MIDI_IRQ_ENABLE	0x10		/* R W	MIDI		Enable MIDI interrupt				*/
-#	define I_M_BOARD_REV		0xE0		/* R	Control		Board revision					*/
-
-#define INTERRUPT_STATUS		0x0B89		/* R W	Control								*/
-#	define I_S_FM_LEFT_IRQ		0x01		/* R W	FM		Left FM Interrupt Pending			*/
-#	define I_S_FM_RIGHT_IRQ	0x02		/* R W	FM		Right FM Interrupt Pending			*/
-#	define I_S_PCM_SAMPLE_RATE_IRQ	0x04		/* R W	PCM		Sample Rate Interrupt Pending			*/
-#	define I_S_PCM_SAMPLE_BUFFER_IRQ 0x08		/* R W	PCM		Sample Buffer Interrupt Pending			*/
-#	define I_S_MIDI_IRQ		0x10		/* R W	MIDI		MIDI Interrupt Pending				*/
-#	define I_S_PCM_CHANNEL		0x20		/* R W	PCM		1=right, 0=left					*/
-#	define I_S_RESET_ACTIVE	0x40		/* R W	Control		Reset is active (Timed pulse not finished)	*/
-#	define I_S_PCM_CLIPPING	0x80		/* R W	PCM		Clipping has occurred				*/
-
-#define FILTER_FREQUENCY		0x0B8A		/* R W	Control								*/
-#	define F_F_FILTER_DISABLED	0x00		/* R W 	Mixer		No filter					*/
-#	define F_F_MIXER_UNMUTE	0x20		/* R W	Mixer		1=disable, 0=enable board mute			*/
-#	define F_F_PCM_RATE_COUNTER	0x40		/* R W	PCM		1=enable, 0=disable sample rate counter		*/
-#	define F_F_PCM_BUFFER_COUNTER	0x80		/* R W 	PCM		1=enable, 0=disable sample buffer counter	*/
-
-#define PAS_NONE	0
-#define PAS_PLUS	1
-#define PAS_CDPC	2
-#define PAS_16		3
-#define PAS_16D		4
-
-#ifdef DEFINE_TRANSLATIONS
-	unsigned char I_C_2_PCM_DMA_translate[] = 		/* R W  PCM		PCM DMA channel value translations		*/
-			{ 4, 1, 2, 3, 0, 5, 6, 7 };
-	unsigned char I_C_3_PCM_IRQ_translate[] = 		/* R W	PCM		PCM IRQ level value translation			*/
-		{ 0,  0,  1,  2,  3,  4,  5,  6, 0,  1,  7,  8,  9,  0, 10, 11 };  
-	unsigned char E_C_MPU401_IRQ_translate[] = 		/* R W	MIDI		MPU401 emulation IRQ value translation		*/
-		{ 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 };
-	unsigned char E_C_SB_IRQ_translate[] = 			/* R W	PCM		SB emulation IRQ translate			*/
-		{ 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 };
-	unsigned char E_C_SB_DMA_translate[] = 			/* R W	PCM		SB emulation DMA translate			*/
-		{ 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
-	unsigned char O_M_1_to_card[] = 				/* R W	Control		Translate (OM1 & 0x0f) to card type		*/
-		{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 };   
-#else
-	extern unsigned char I_C_2_PCM_DMA_translate[];		/* R W  PCM		PCM DMA channel value translations		*/
-	extern unsigned char I_C_3_PCM_IRQ_translate[];		/* R W	PCM		PCM IRQ level value translation			*/
-	extern unsigned char E_C_MPU401_IRQ_translate[];		/* R W	MIDI		MPU401 emulation IRQ value translation		*/
-	extern unsigned char E_C_SB_IRQ_translate[];		/* R W	PCM		SB emulation IRQ translate			*/
-	extern unsigned char E_C_SB_DMA_translate[];		/* R W	PCM		SB emulation DMA translate			*/
-	extern unsigned char O_M_1_to_card[];			/* R W	Control		Translate (OM1 & 0x0f) to card type		*/
-#endif
-
-#define PARALLEL_MIXER			0x078B		/*   W	Mixer		Documented for MVD101 as FM Mono Right decode?? */
-#	define P_M_MV508_ADDRESS	0x80		/*   W	Mixer		MVD508	Address/mixer select			*/
-#	define P_M_MV508_DATA		0x00
-#	define P_M_MV508_LEFT		0x20		/*   W	Mixer		MVD508	Left channel select			*/
-#	define P_M_MV508_RIGHT		0x40		/*   W	Mixer		MVD508	Right channel select			*/
-#	define P_M_MV508_BOTH		0x00		/*   W	Mixer		MVD508	Both channel select			*/
-#	define P_M_MV508_MIXER		0x10		/*   W	Mixer		MVD508	Select a mixer (rather than a volume) 	*/
-#	define P_M_MV508_VOLUME	0x00
-
-#	define P_M_MV508_INPUTMIX	0x20		/*   W  Mixer		MVD508	Select mixer A				*/
-#	define P_M_MV508_OUTPUTMIX	0x00		/*   W  Mixer		MVD508	Select mixer B				*/
-
-#	define P_M_MV508_MASTER_A	0x01		/*   W	Mixer		MVD508	Master volume control A (output)	*/
-#	define P_M_MV508_MASTER_B	0x02		/*   W	Mixer		MVD508	Master volume control B (DSP input)	*/
-#	define P_M_MV508_BASS		0x03		/*   W	Mixer		MVD508	Bass control				*/
-#	define P_M_MV508_TREBLE	0x04		/*   W	Mixer		MVD508	Treble control				*/
-#	define P_M_MV508_MODE		0x05		/*   W	Mixer		MVD508	Master mode control			*/
-
-#	define P_M_MV508_LOUDNESS	0x04		/*   W	Mixer		MVD508	Mode control - Loudness filter 		*/
-#	define P_M_MV508_ENHANCE_BITS	0x03
-#	define P_M_MV508_ENHANCE_NONE	0x00		/*   W	Mixer		MVD508	Mode control - No stereo enhancement	*/
-#	define P_M_MV508_ENHANCE_40	0x01		/*   W	Mixer		MVD508	Mode control - 40% stereo enhancement	*/
-#	define P_M_MV508_ENHANCE_60	0x02		/*   W	Mixer		MVD508	Mode control - 60% stereo enhancement	*/
-#	define P_M_MV508_ENHANCE_80	0x03		/*   W	Mixer		MVD508	Mode control - 80% stereo enhancement	*/
-
-#	define P_M_MV508_FM		0x00		/*   W	Mixer		MVD508	Channel 0 - FM				*/
-#	define P_M_MV508_IMIXER	0x01		/*   W	Mixer		MVD508	Channel 1 - Input mixer (rec monitor)	*/
-#	define P_M_MV508_LINE		0x02		/*   W	Mixer		MVD508	Channel 2 - Line in			*/
-#	define P_M_MV508_CDROM		0x03		/*   W	Mixer		MVD508	Channel 3 - CD-ROM			*/
-#	define P_M_MV508_MIC		0x04		/*   W	Mixer		MVD508	Channel 4 - Microphone			*/
-#	define P_M_MV508_PCM		0x05		/*   W	Mixer		MVD508	Channel 5 - PCM				*/
-#	define P_M_MV508_SPEAKER	0x06		/*   W	Mixer		MVD508	Channel 6 - PC Speaker			*/
-#	define P_M_MV508_SB		0x07		/*   W	Mixer		MVD508	Channel 7 - SB DSP			*/
-
-#define SERIAL_MIXER			0xB88		/* R W	Control		Serial mixer control (used other ways)		*/
-#	define S_M_PCM_RESET		0x01		/* R W	PCM		Codec/DSP reset					*/
-#	define S_M_FM_RESET		0x02		/* R W	FM		FM chip reset					*/
-#	define S_M_SB_RESET		0x04		/* R W	PCM		SB emulation chip reset				*/
-#	define S_M_MIXER_RESET		0x10		/* R W	Mixer		Mixer chip reset				*/
-#	define S_M_INTEGRATOR_ENABLE	0x40		/* R W	Speaker		Enable PC speaker integrator (FORCE RealSound)	*/
-#	define S_M_OPL3_DUAL_MONO	0x80		/* R W  FM		Set the OPL-3 to dual mono mode			*/
-
-#define PCM_CONTROL			0xF8A		/* R W	PCM		PCM Control Register				*/
-#	define P_C_MIXER_CROSS_FIELD	0x0f
-#	define P_C_MIXER_CROSS_R_TO_R	0x01		/* R W	Mixer		Connect Right to Right				*/
-#	define P_C_MIXER_CROSS_L_TO_R	0x02		/* R W	Mixer		Connect Left  to Right				*/
-#	define P_C_MIXER_CROSS_R_TO_L	0x04		/* R W	Mixer		Connect Right to Left				*/
-#	define P_C_MIXER_CROSS_L_TO_L	0x08		/* R W	Mixer		Connect Left  to Left				*/
-#	define P_C_PCM_DAC_MODE	0x10		/* R W	PCM		Playback (DAC) mode				*/
-#	define P_C_PCM_ADC_MODE	0x00		/* R W	PCM		Record (ADC) mode				*/
-#	define P_C_PCM_MONO		0x20		/* R W	PCM		Mono mode					*/
-#	define P_C_PCM_STEREO		0x00		/* R W	PCM		Stereo mode					*/
-#	define P_C_PCM_ENABLE		0x40		/* R W	PCM		Enable PCM engine				*/
-#	define P_C_PCM_DMA_ENABLE	0x80		/* R W	PCM		Enable DRQ					*/
-
-#define SAMPLE_COUNTER_CONTROL		0x138B		/* R W	PCM		Sample counter control register			*/
-#	define S_C_C_SQUARE_WAVE	0x04		/* R W	PCM		Square wave generator (use for sample rate)	*/
-#	define S_C_C_RATE		0x06		/* R W	PCM		Rate generator (use for sample buffer count)	*/
-#	define S_C_C_LSB_THEN_MSB	0x30		/* R W	PCM		Change all 16 bits, LSB first, then MSB		*/
-
-	/* MVD101 and SDK documentations have S_C_C_SAMPLE_RATE and S_C_C_SAMPLE_BUFFER transposed. Only one works :-) */
-#	define S_C_C_SAMPLE_RATE	0x00		/* R W	PCM		Select sample rate timer			*/
-#	define S_C_C_SAMPLE_BUFFER	0x40		/* R W	PCM		Select sample buffer counter			*/
-
-#	define S_C_C_PC_SPEAKER	0x80		/* R W	PCM		Select PC speaker counter			*/
-
-#define SAMPLE_RATE_TIMER		0x1388		/*   W	PCM		Sample rate timer register (PCM wait interval)	*/
-#define SAMPLE_BUFFER_COUNTER		0x1389		/* R W	PCM		Sample buffer counter (DMA buffer size)		*/
-
-#define MIDI_CONTROL			0x178b		/* R W  MIDI		Midi control register				*/
-#	define M_C_ENA_TSTAMP_IRQ	0x01		/* R W	MIDI		Enable Time Stamp Interrupts			*/
-#	define M_C_ENA_TME_COMP_IRQ	0x02		/* R W  MIDI		Enable time compare interrupts			*/
-#	define M_C_ENA_INPUT_IRQ	0x04		/* R W  MIDI		Enable input FIFO interrupts			*/
-#	define M_C_ENA_OUTPUT_IRQ	0x08		/* R W  MIDI		Enable output FIFO interrupts			*/
-#	define M_C_ENA_OUTPUT_HALF_IRQ	0x10		/* R W  MIDI		Enable output FIFO half full interrupts		*/
-#	define M_C_RESET_INPUT_FIFO	0x20		/* R W  MIDI		Reset input FIFO pointer			*/
-#	define M_C_RESET_OUTPUT_FIFO	0x40		/* R W  MIDI		Reset output FIFO pointer			*/
-#	define M_C_ENA_THRU_MODE	0x80		/* R W  MIDI		Echo input to output (THRU)			*/
-
-#define MIDI_STATUS			0x1B88		/* R W  MIDI		Midi (interrupt) status register		*/
-#	define M_S_TIMESTAMP		0x01		/* R W  MIDI		Midi time stamp interrupt occurred		*/
-#	define M_S_COMPARE		0x02		/* R W  MIDI		Midi compare time interrupt occurred		*/
-#	define M_S_INPUT_AVAIL		0x04		/* R W  MIDI		Midi input data available interrupt occurred	*/
-#	define M_S_OUTPUT_EMPTY	0x08		/* R W  MIDI		Midi output FIFO empty interrupt occurred	*/
-#	define M_S_OUTPUT_HALF_EMPTY	0x10		/* R W  MIDI		Midi output FIFO half empty interrupt occurred	*/
-#	define M_S_INPUT_OVERRUN	0x20		/* R W  MIDI		Midi input overrun error occurred		*/
-#	define M_S_OUTPUT_OVERRUN	0x40		/* R W  MIDI 		Midi output overrun error occurred		*/
-#	define M_S_FRAMING_ERROR	0x80		/* R W  MIDI		Midi input framing error occurred		*/
-
-#define MIDI_FIFO_STATUS		0x1B89		/* R W  MIDI		Midi fifo status				*/
-#define MIDI_DATA			0x178A		/* R W  MIDI		Midi data register				*/
-#define MIDI_INPUT_AVAILABLE		0x0f		/* RW   MIDI */ 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v2.0.0/linux/drivers/sound/pas2_card.c	Sun Mar 24 22:50:12 1996
+++ linux/drivers/sound/pas2_card.c	Sun Jun 30 12:31:09 1996
@@ -4,38 +4,21 @@
  *
  * Detection routine for the Pro Audio Spectrum cards.
  */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <linux/config.h>
 
+#include <linux/config.h>
 
 #include "sound_config.h"
 
 #if defined(CONFIG_PAS)
 
-#define DEFINE_TRANSLATIONS
-#include "pas.h"
+static unsigned char dma_bits[] =
+{4, 1, 2, 3, 0, 5, 6, 7};
+static unsigned char irq_bits[] =
+{0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11};
+static unsigned char sb_irq_bits[] =
+{0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0};
+static unsigned char sb_dma_bits[] =
+{0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0};
 
 /*
  * The Address Translation code is used to convert I/O register addresses to
@@ -45,6 +28,7 @@
 int             translat_code;
 static int      pas_intr_mask = 0;
 static int      pas_irq = 0;
+static int      pas_sb_base = 0;
 
 int            *pas_osp;
 
@@ -54,11 +38,7 @@
 
 /*
  * pas_read() and pas_write() are equivalents of inb and outb 
- */
-/*
  * These routines perform the I/O address translation required
- */
-/*
  * to support other than the default base address
  */
 extern void     mix_write (unsigned char data, int ioaddr);
@@ -75,12 +55,6 @@
   outb (data, ioaddr ^ translat_code);
 }
 
-void
-pas2_msg (char *foo)
-{
-  printk ("    PAS2: %s.\n", foo);
-}
-
 /******************* Begin of the Interrupt Handler ********************/
 
 void
@@ -88,26 +62,23 @@
 {
   int             status;
 
-  status = pas_read (INTERRUPT_STATUS);
-  pas_write (status, INTERRUPT_STATUS);		/*
-						   * Clear interrupt
-						 */
+  status = pas_read (0x0B89);
+  pas_write (status, 0x0B89);	/* Clear interrupt */
 
-  if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
+  if (status & 0x08)
     {
 #ifdef CONFIG_AUDIO
       pas_pcm_interrupt (status, 1);
 #endif
-      status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ;
+      status &= ~0x08;
     }
-  if (status & I_S_MIDI_IRQ)
+  if (status & 0x10)
     {
 #ifdef CONFIG_MIDI
       pas_midi_interrupt ();
 #endif
-      status &= ~I_S_MIDI_IRQ;
+      status &= ~0x10;
     }
-
 }
 
 int
@@ -118,7 +89,7 @@
 
   pas_intr_mask |= mask;
 
-  pas_write (pas_intr_mask, INTERRUPT_MASK);
+  pas_write (pas_intr_mask, 0x0B8B);
   return 0;
 }
 
@@ -129,7 +100,7 @@
     return 0;
 
   pas_intr_mask &= ~mask;
-  pas_write (pas_intr_mask, INTERRUPT_MASK);
+  pas_write (pas_intr_mask, 0x0B8B);
 
   return 0;
 }
@@ -146,41 +117,41 @@
 
   pas_irq = hw_config->irq;
 
-  pas_write (0x00, INTERRUPT_MASK);
+  pas_write (0x00, 0x0B8B);
+
+  pas_write (0x36, 0x138B);	/*
+				   * Local timer control *
+				   * register
+				 */
+
+  pas_write (0x36, 0x1388);	/*
+				   * Sample rate timer (16 bit)
+				 */
+  pas_write (0, 0x1388);
+
+  pas_write (0x74, 0x138B);	/*
+				   * Local timer control *
+				   * register
+				 */
+
+  pas_write (0x74, 0x1389);	/*
+				   * Sample count register (16
+				   * * bit)
+				 */
+  pas_write (0, 0x1389);
 
-  pas_write (0x36, SAMPLE_COUNTER_CONTROL);	/*
-						 * Local timer control *
-						 * register
-						 */
-
-  pas_write (0x36, SAMPLE_RATE_TIMER);	/*
-					 * Sample rate timer (16 bit)
-					 */
-  pas_write (0, SAMPLE_RATE_TIMER);
-
-  pas_write (0x74, SAMPLE_COUNTER_CONTROL);	/*
-						 * Local timer control *
-						 * register
-						 */
-
-  pas_write (0x74, SAMPLE_BUFFER_COUNTER);	/*
-						 * Sample count register (16
-						 * * bit)
-						 */
-  pas_write (0, SAMPLE_BUFFER_COUNTER);
-
-  pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY);
-  pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL);
-  pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET	/*
-										 * |
-										 * S_M_OPL3_DUAL_MONO
-										 */ , SERIAL_MIXER);
+  pas_write (0x80 | 0x40 | 0x20 | 1, 0x0B8A);
+  pas_write (0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A);
+  pas_write (0x01 | 0x02 | 0x04 | 0x10	/*
+					   * |
+					   * 0x80
+					 */ , 0xB88);
 
-  pas_write (I_C_1_BOOT_RESET_ENABLE
+  pas_write (0x80
 #ifdef PAS_JOYSTICK_ENABLE
-	     | I_C_1_JOYSTICK_ENABLE
+	     | 0x40
 #endif
-	     ,IO_CONFIGURATION_1);
+	     ,0xF388);
 
   if (pas_irq < 0 || pas_irq > 15)
     {
@@ -189,10 +160,10 @@
     }
   else
     {
-      int_ptrs = pas_read (IO_CONFIGURATION_3);
-      int_ptrs |= I_C_3_PCM_IRQ_translate[pas_irq] & 0xf;
-      pas_write (int_ptrs, IO_CONFIGURATION_3);
-      if (!I_C_3_PCM_IRQ_translate[pas_irq])
+      int_ptrs = pas_read (0xF38A);
+      int_ptrs |= irq_bits[pas_irq] & 0xf;
+      pas_write (int_ptrs, 0xF38A);
+      if (!irq_bits[pas_irq])
 	{
 	  printk ("PAS2: Invalid IRQ %d", pas_irq);
 	  ok = 0;
@@ -211,8 +182,8 @@
     }
   else
     {
-      pas_write (I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2);
-      if (!I_C_2_PCM_DMA_translate[hw_config->dma])
+      pas_write (dma_bits[hw_config->dma], 0xF389);
+      if (!dma_bits[hw_config->dma])
 	{
 	  printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
 	  ok = 0;
@@ -237,29 +208,19 @@
 #endif
 
 #ifdef BROKEN_BUS_CLOCK
-  pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
+  pas_write (0x01 | 0x10 | 0x20 | 0x04, 0x8388);
 #else
   /*
-   * pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);
+   * pas_write(0x01, 0x8388);
    */
-  pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
+  pas_write (0x01 | 0x10 | 0x20, 0x8388);
 #endif
-  pas_write (0x18, SYSTEM_CONFIGURATION_3);	/*
-						 * ???
-						 */
-
-  pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY);	/*
-								 * Sets mute
-								 * off and *
-								 * selects
-								 * filter
-								 * rate * of
-								 * 17.897 kHz
-								 */
-  pas_write (8, PRESCALE_DIVIDER);
+  pas_write (0x18, 0x838A);	/* ??? */
+  pas_write (0x20 | 0x01, 0x0B8A);	/* Mute off, filter = 17.897 kHz */
+  pas_write (8, 0xBF8A);
 
-  mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
-  mix_write (5, PARALLEL_MIXER);
+  mix_write (0x80 | 5, 0x078B);
+  mix_write (5, 0x078B);
 
 #if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB)
 
@@ -272,42 +233,39 @@
 
 	/*
 	 * Turn on Sound Blaster compatibility
-	 */
-	/*
 	 * bit 1 = SB emulation
-	 */
-	/*
 	 * bit 0 = MPU401 emulation (CDPC only :-( )
 	 */
-	pas_write (0x02, COMPATIBILITY_ENABLE);
+	pas_write (0x02, 0xF788);
 
 	/*
 	 * "Emulation address"
 	 */
-	pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
+	pas_write ((sb_config->io_base >> 4) & 0x0f, 0xF789);
+	pas_sb_base = sb_config->io_base;
 
-	if (!E_C_SB_DMA_translate[sb_config->dma])
+	if (!sb_dma_bits[sb_config->dma])
 	  printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
 		  sb_config->dma);
 
-	if (!E_C_SB_IRQ_translate[sb_config->irq])
+	if (!sb_irq_bits[sb_config->irq])
 	  printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
 		  sb_config->irq);
 
-	irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
-	  E_C_SB_IRQ_translate[sb_config->irq];
+	irq_dma = sb_dma_bits[sb_config->dma] |
+	  sb_irq_bits[sb_config->irq];
 
-	pas_write (irq_dma, EMULATION_CONFIGURATION);
+	pas_write (irq_dma, 0xFB8A);
       }
     else
-      pas_write (0x00, COMPATIBILITY_ENABLE);
+      pas_write (0x00, 0xF788);
   }
 #else
-  pas_write (0x00, COMPATIBILITY_ENABLE);
+  pas_write (0x00, 0xF788);
 #endif
 
   if (!ok)
-    pas2_msg ("Driver not enabled");
+    printk ("PAS16: Driver not enabled\n");
 
   return ok;
 }
@@ -324,18 +282,12 @@
    * you have something on base port 0x388. SO be forewarned.
    */
 
-  outb (0xBC, MASTER_DECODE);	/*
-				   * Talk to first board
-				 */
-  outb (hw_config->io_base >> 2, MASTER_DECODE);	/*
-							   * Set base address
-							 */
-  translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base;
-  pas_write (1, WAIT_STATE);	/*
-				 * One wait-state
-				 */
+  outb (0xBC, 0x9A01);		/* Activate first board */
+  outb (hw_config->io_base >> 2, 0x9A01);	/* Set base address */
+  translat_code = 0x388 ^ hw_config->io_base;
+  pas_write (1, 0xBF88);	/* Select one wait states */
 
-  board_id = pas_read (INTERRUPT_MASK);
+  board_id = pas_read (0x0B8B);
 
   if (board_id == 0xff)
     return 0;
@@ -348,22 +300,22 @@
 
   foo = board_id ^ 0xe0;
 
-  pas_write (foo, INTERRUPT_MASK);
-  foo = inb (INTERRUPT_MASK);
-  pas_write (board_id, INTERRUPT_MASK);
+  pas_write (foo, 0x0B8B);
+  foo = inb (0x0B8B);
+  pas_write (board_id, 0x0B8B);
 
   if (board_id != foo)		/*
 				 * Not a PAS2
 				 */
     return 0;
 
-  pas_model = pas_read (CHIP_REV);
+  pas_model = pas_read (0xFF88);
 
   return pas_model;
 }
 
-long
-attach_pas_card (long mem_start, struct address_info *hw_config)
+void
+attach_pas_card (struct address_info *hw_config)
 {
   pas_irq = hw_config->irq;
   pas_osp = hw_config->osp;
@@ -371,13 +323,13 @@
   if (detect_pas_hw (hw_config))
     {
 
-      if ((pas_model = pas_read (CHIP_REV)))
+      if ((pas_model = pas_read (0xFF88)))
 	{
 	  char            temp[100];
 
 	  sprintf (temp,
 		   "%s rev %d", pas_model_names[(int) pas_model],
-		   pas_read (BOARD_REV_ID));
+		   pas_read (0x2789));
 	  conf_printf (temp, hw_config);
 	}
 
@@ -385,27 +337,23 @@
 	{
 
 #ifdef CONFIG_AUDIO
-	  mem_start = pas_pcm_init (mem_start, hw_config);
+	  pas_pcm_init (hw_config);
 #endif
 
 #if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB)
 
-	  sb_dsp_disable_midi ();	/*
-					 * The SB emulation don't support *
-					 * midi
-					 */
+	  sb_dsp_disable_midi (pas_sb_base);	/* No MIDI capability */
 #endif
 
 
 #ifdef CONFIG_MIDI
-	  mem_start = pas_midi_init (mem_start);
+	  pas_midi_init ();
 #endif
 
 	  pas_init_mixer ();
 	}
     }
 
-  return mem_start;
 }
 
 int
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c
--- v2.0.0/linux/drivers/sound/pas2_midi.c	Sun Mar 24 22:50:12 1996
+++ linux/drivers/sound/pas2_midi.c	Sun Jun 30 12:31:09 1996
@@ -3,36 +3,11 @@
  *
  * The low level driver for the PAS Midi Interface.
  */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <linux/config.h>
 
+#include <linux/config.h>
 
 #include "sound_config.h"
 
-#include "pas.h"
-
 #if defined(CONFIG_PAS) && defined(CONFIG_MIDI)
 
 static int      midi_busy = 0, input_opened = 0;
@@ -59,19 +34,19 @@
   if (midi_busy)
     {
       printk ("PAS2: Midi busy\n");
-      return -EBUSY;
+      return -(EBUSY);
     }
 
   /*
    * Reset input and output FIFO pointers
    */
-  pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO,
-	     MIDI_CONTROL);
+  pas_write (0x20 | 0x40,
+	     0x178b);
 
   save_flags (flags);
   cli ();
 
-  if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0)
+  if ((err = pas_set_intr (0x10)) < 0)
     return err;
 
   /*
@@ -84,28 +59,28 @@
 
   if (mode == OPEN_READ || mode == OPEN_READWRITE)
     {
-      ctrl |= M_C_ENA_INPUT_IRQ;	/*
-					   * Enable input
-					 */
+      ctrl |= 0x04;		/*
+				   * Enable input
+				 */
       input_opened = 1;
     }
 
   if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
     {
-      ctrl |= M_C_ENA_OUTPUT_IRQ |	/*
-					 * Enable output
-					 */
-	M_C_ENA_OUTPUT_HALF_IRQ;
+      ctrl |= 0x08 |		/*
+				   * Enable output
+				 */
+	0x10;
     }
 
   pas_write (ctrl,
-	     MIDI_CONTROL);
+	     0x178b);
 
   /*
    * Acknowledge any pending interrupts
    */
 
-  pas_write (0xff, MIDI_STATUS);
+  pas_write (0xff, 0x1B88);
   ofifo_bytes = 0;
 
   restore_flags (flags);
@@ -122,9 +97,9 @@
   /*
    * Reset FIFO pointers, disable intrs
    */
-  pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL);
+  pas_write (0x20 | 0x40, 0x178b);
 
-  pas_remove_intr (I_M_MIDI_IRQ_ENABLE);
+  pas_remove_intr (0x10);
   midi_busy = 0;
 }
 
@@ -133,7 +108,7 @@
 {
   int             fifo_space, x;
 
-  fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
+  fifo_space = ((x = pas_read (0x1B89)) >> 4) & 0x0f;
 
   if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13))		/*
 									   * Fifo
@@ -147,7 +122,7 @@
 
   ofifo_bytes++;
 
-  pas_write (midi_byte, MIDI_DATA);
+  pas_write (midi_byte, 0x178A);
 
   return 1;
 }
@@ -219,7 +194,7 @@
 static int
 pas_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
 {
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
@@ -257,18 +232,17 @@
   NULL
 };
 
-long
-pas_midi_init (long mem_start)
+void
+pas_midi_init (void)
 {
   if (num_midis >= MAX_MIDI_DEV)
     {
       printk ("Sound: Too many midi devices detected\n");
-      return mem_start;
+      return;
     }
 
   std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &pas_midi_operations;
-  return mem_start;
 }
 
 void
@@ -278,32 +252,32 @@
   int             i, incount;
   unsigned long   flags;
 
-  stat = pas_read (MIDI_STATUS);
+  stat = pas_read (0x1B88);
 
-  if (stat & M_S_INPUT_AVAIL)	/*
-				 * Input byte available
+  if (stat & 0x04)		/*
+				   * Input byte available
 				 */
     {
-      incount = pas_read (MIDI_FIFO_STATUS) & 0x0f;	/*
-							 * Input FIFO count
-							 */
+      incount = pas_read (0x1B89) & 0x0f;	/*
+						   * Input FIFO count
+						 */
       if (!incount)
 	incount = 16;
 
       for (i = 0; i < incount; i++)
 	if (input_opened)
 	  {
-	    midi_input_intr (my_dev, pas_read (MIDI_DATA));
+	    midi_input_intr (my_dev, pas_read (0x178A));
 	  }
 	else
-	  pas_read (MIDI_DATA);	/*
+	  pas_read (0x178A);	/*
 				 * Flush
 				 */
     }
 
-  if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY))
+  if (stat & (0x08 | 0x10))
     {
-      if (!(stat & M_S_OUTPUT_EMPTY))
+      if (!(stat & 0x08))
 	{
 	  ofifo_bytes = 8;
 	}
@@ -325,15 +299,15 @@
     }
 
 
-  if (stat & M_S_OUTPUT_OVERRUN)
+  if (stat & 0x40)
     {
-      printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
+      printk ("MIDI output overrun %x,%x,%d \n", pas_read (0x1B89), stat, ofifo_bytes);
       ofifo_bytes = 100;
     }
 
-  pas_write (stat, MIDI_STATUS);	/*
-					   * Acknowledge interrupts
-					 */
+  pas_write (stat, 0x1B88);	/*
+				   * Acknowledge interrupts
+				 */
 }
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c
--- v2.0.0/linux/drivers/sound/pas2_mixer.c	Sun Mar 24 22:50:13 1996
+++ linux/drivers/sound/pas2_mixer.c	Sun Jun 30 12:31:09 1996
@@ -5,43 +5,21 @@
  *
  * Mixer routines for the Pro Audio Spectrum cards.
  */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+   
 #include <linux/config.h>
 
-
 #include "sound_config.h"
 
 #if defined(CONFIG_PAS)
 
-#include "pas.h"
-
-#define TRACE(what)		/* (what) */
+#ifndef DEB
+#define DEB(what)		/* (what) */
+#endif
 
 extern int      translat_code;
 extern char     pas_model;
 extern int     *pas_osp;
+extern int      pas_audiodev;
 
 static int      rec_devices = (SOUND_MASK_MIC);		/* Default recording source */
 static int      mode_control = 0;
@@ -51,8 +29,8 @@
 
 #define SUPPORTED_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
 					 SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
-					 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
-					 SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
+					 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV)
+
 
 static unsigned short levels[SOUND_MIXER_NRDEVICES] =
 {
@@ -81,7 +59,7 @@
    * sequence problem.
    */
 
-  if (pas_model == PAS_16D)
+  if (pas_model == 4)
     {
       outw (data | (data << 8), (ioaddr ^ translat_code) - 1);
       outb (0x80, 0);
@@ -98,7 +76,7 @@
   int             right = right_vol * div / 100;
 
 
-  if (bits & P_M_MV508_MIXER)
+  if (bits & 0x10)
     {				/*
 				 * Select input or output mixer
 				 */
@@ -106,20 +84,20 @@
       right |= mixer;
     }
 
-  if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
+  if (bits == 0x03 || bits == 0x04)
     {				/*
 				 * Bass and treble are mono devices
 				 */
-      mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
-      mix_write (left, PARALLEL_MIXER);
+      mix_write (0x80 | bits, 0x078B);
+      mix_write (left, 0x078B);
       right_vol = left_vol;
     }
   else
     {
-      mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
-      mix_write (left, PARALLEL_MIXER);
-      mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
-      mix_write (right, PARALLEL_MIXER);
+      mix_write (0x80 | 0x20 | bits, 0x078B);
+      mix_write (left, 0x078B);
+      mix_write (0x80 | 0x40 | bits, 0x078B);
+      mix_write (right, 0x078B);
     }
 
   return (left_vol | (right_vol << 8));
@@ -128,8 +106,8 @@
 void
 set_mode (int new_mode)
 {
-  mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
-  mix_write (new_mode, PARALLEL_MIXER);
+  mix_write (0x80 | 0x05, 0x078B);
+  mix_write (new_mode, 0x078B);
 
   mode_control = new_mode;
 }
@@ -139,21 +117,21 @@
 {
   int             left, right, devmask, changed, i, mixer = 0;
 
-  TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
+  DEB (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
 
   left = level & 0x7f;
   right = (level & 0x7f00) >> 8;
 
   if (whichDev < SOUND_MIXER_NRDEVICES)
     if ((1 << whichDev) & rec_devices)
-      mixer = P_M_MV508_INPUTMIX;
+      mixer = 0x20;
     else
-      mixer = P_M_MV508_OUTPUTMIX;
+      mixer = 0x00;
 
   switch (whichDev)
     {
     case SOUND_MIXER_VOLUME:	/* Master volume (0-63) */
-      levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
+      levels[whichDev] = mixer_output (right, left, 63, 0x01, 0);
       break;
 
       /*
@@ -161,67 +139,41 @@
        * channel.
        */
     case SOUND_MIXER_BASS:	/* Bass (0-12) */
-      levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
+      levels[whichDev] = mixer_output (right, left, 12, 0x03, 0);
       break;
     case SOUND_MIXER_TREBLE:	/* Treble (0-12) */
-      levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
+      levels[whichDev] = mixer_output (right, left, 12, 0x04, 0);
       break;
 
     case SOUND_MIXER_SYNTH:	/* Internal synthesizer (0-31) */
-      levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
+      levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x00, mixer);
       break;
     case SOUND_MIXER_PCM:	/* PAS PCM (0-31) */
-      levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
+      levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x05, mixer);
       break;
     case SOUND_MIXER_ALTPCM:	/* SB PCM (0-31) */
-      levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
+      levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x07, mixer);
       break;
     case SOUND_MIXER_SPEAKER:	/* PC speaker (0-31) */
-      levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
+      levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x06, mixer);
       break;
     case SOUND_MIXER_LINE:	/* External line (0-31) */
-      levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
+      levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x02, mixer);
       break;
     case SOUND_MIXER_CD:	/* CD (0-31) */
-      levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
+      levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x03, mixer);
       break;
     case SOUND_MIXER_MIC:	/* External microphone (0-31) */
-      levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
+      levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x04, mixer);
       break;
     case SOUND_MIXER_IMIX:	/* Recording monitor (0-31) (Output mixer only) */
-      levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
-				       P_M_MV508_OUTPUTMIX);
+      levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x01,
+				       0x00);
       break;
     case SOUND_MIXER_RECLEV:	/* Recording level (0-15) */
-      levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
+      levels[whichDev] = mixer_output (right, left, 15, 0x02, 0);
       break;
 
-    case SOUND_MIXER_MUTE:
-      return 0;
-      break;
-
-    case SOUND_MIXER_ENHANCE:
-      i = 0;
-      level &= 0x7f;
-      if (level)
-	i = (level / 20) - 1;
-
-      mode_control &= ~P_M_MV508_ENHANCE_BITS;
-      mode_control |= P_M_MV508_ENHANCE_BITS;
-      set_mode (mode_control);
-
-      if (i)
-	i = (i + 1) * 20;
-      return i;
-      break;
-
-    case SOUND_MIXER_LOUD:
-      mode_control &= ~P_M_MV508_LOUDNESS;
-      if (level)
-	mode_control |= P_M_MV508_LOUDNESS;
-      set_mode (mode_control);
-      return !!level;		/* 0 or 1 */
-      break;
 
     case SOUND_MIXER_RECSRC:
       devmask = level & POSSIBLE_RECORDING_DEVICES;
@@ -238,7 +190,7 @@
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   return (levels[whichDev]);
@@ -251,18 +203,92 @@
 {
   int             foo;
 
-  TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
+  DEB (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
 
   for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
     pas_mixer_set (foo, levels[foo]);
 
-  set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
+  set_mode (0x04 | 0x01);
 }
 
 int
 pas_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
 {
-  TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
+  DEB (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
+
+  if (cmd == SOUND_MIXER_PRIVATE1)	/* Set loudness bit */
+    {
+      int             level = get_fs_long ((long *) arg);
+
+      if (level == -1)		/* Return current settings */
+	{
+	  if (mode_control & 0x04)
+	    return snd_ioctl_return ((int *) arg, 1);
+	  else
+	    return snd_ioctl_return ((int *) arg, 0);
+	}
+      else
+	{
+	  mode_control &= ~0x04;
+	  if (level)
+	    mode_control |= 0x04;
+	  set_mode (mode_control);
+	  return snd_ioctl_return ((int *) arg, !!level);	/* 0 or 1 */
+	}
+    }
+
+
+  if (cmd == SOUND_MIXER_PRIVATE2)	/* Set enhance bit */
+    {
+      int             level = get_fs_long ((long *) arg);
+
+      if (level == -1)		/* Return current settings */
+	{
+	  if (!(mode_control & 0x03))
+	    return snd_ioctl_return ((int *) arg, 0);
+	  return snd_ioctl_return ((int *) arg, ((mode_control & 0x03) + 1) * 20);
+	}
+      else
+	{
+	  int             i = 0;
+
+	  level &= 0x7f;
+	  if (level)
+	    i = (level / 20) - 1;
+
+	  mode_control &= ~0x03;
+	  mode_control |= i & 0x03;
+	  set_mode (mode_control);
+
+	  if (i)
+	    i = (i + 1) * 20;
+
+	  return i;
+	}
+    }
+
+  if (cmd == SOUND_MIXER_PRIVATE3)	/* Set mute bit */
+    {
+      int             level = get_fs_long ((long *) arg);
+
+      if (level == -1)		/* Return current settings */
+	{
+	  return snd_ioctl_return ((int *) arg,
+				   !(pas_read (0x0B8A) &
+				     0x20));
+	}
+      else
+	{
+	  if (level)
+	    pas_write (pas_read (0x0B8A) & (~0x20),
+		       0x0B8A);
+	  else
+	    pas_write (pas_read (0x0B8A) | 0x20,
+		       0x0B8A);
+
+	  return !(pas_read (0x0B8A) & 0x20);
+	}
+    }
 
   if (((cmd >> 8) & 0xff) == 'M')
     {
@@ -270,7 +296,7 @@
 	return snd_ioctl_return ((int *) arg, pas_mixer_set (cmd & 0xff, get_fs_long ((long *) arg)));
       else
 	{			/*
-				   * Read parameters
+				 * Read parameters
 				 */
 
 	  switch (cmd & 0xff)
@@ -296,32 +322,18 @@
 	      return snd_ioctl_return ((int *) arg, 0);		/* No special capabilities */
 	      break;
 
-	    case SOUND_MIXER_MUTE:
-	      return snd_ioctl_return ((int *) arg, 0);		/* No mute yet */
-	      break;
-
-	    case SOUND_MIXER_ENHANCE:
-	      if (!(mode_control & P_M_MV508_ENHANCE_BITS))
-		return snd_ioctl_return ((int *) arg, 0);
-	      return snd_ioctl_return ((int *) arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
-	      break;
-
-	    case SOUND_MIXER_LOUD:
-	      if (mode_control & P_M_MV508_LOUDNESS)
-		return snd_ioctl_return ((int *) arg, 1);
-	      return snd_ioctl_return ((int *) arg, 0);
-	      break;
 
 	    default:
 	      return snd_ioctl_return ((int *) arg, levels[cmd & 0xff]);
 	    }
 	}
     }
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static struct mixer_operations pas_mixer_operations =
 {
+  "PAS16",
   "Pro Audio Spectrum 16",
   pas_mixer_ioctl
 };
@@ -332,7 +344,10 @@
   pas_mixer_reset ();
 
   if (num_mixers < MAX_MIXER_DEV)
-    mixer_devs[num_mixers++] = &pas_mixer_operations;
+    {
+      audio_devs[pas_audiodev]->mixer_dev = num_mixers;
+      mixer_devs[num_mixers++] = &pas_mixer_operations;
+    }
   return 1;
 }
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c
--- v2.0.0/linux/drivers/sound/pas2_pcm.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/pas2_pcm.c	Sun Jun 30 12:31:09 1996
@@ -4,40 +4,16 @@
  *
  * The low level driver for the Pro Audio Spectrum ADC/DAC.
  */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+   
 #include <linux/config.h>
 
-
 #include "sound_config.h"
 
-#include "pas.h"
-
 #if defined(CONFIG_PAS) && defined(CONFIG_AUDIO)
 
-#define TRACE(WHAT)		/*
-				   * * * (WHAT)   */
+#ifndef DEB
+#define DEB(WHAT)
+#endif
 
 #define PAS_PCM_INTRBITS (0x08)
 /*
@@ -56,7 +32,7 @@
 static unsigned long pcm_count = 0;
 static unsigned short pcm_bitsok = 8;	/* mask of OK bits */
 static int      pcm_busy = 0;
-static int      my_devnum = 0;
+int             pas_audiodev = 0;
 static int      open_mode = 0;
 
 int
@@ -83,41 +59,45 @@
 
   pcm_speed = arg;
 
-  tmp = pas_read (FILTER_FREQUENCY);
+  tmp = pas_read (0x0B8A);
 
   /*
-     * Set anti-aliasing filters according to sample rate. You really *NEED*
+     * Set anti-aliasing filters according to sample rate. You reall *NEED*
      * to enable this feature for all normal recording unless you want to
      * experiment with aliasing effects.
      * These filters apply to the selected "recording" source.
      * I (pfw) don't know the encoding of these 5 bits. The values shown
      * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
+     *
+     * I cleared bit 5 of these values, since that bit controls the master
+     * mute flag. (Olav Wölfelschneider)
+     *
    */
 #if !defined NO_AUTO_FILTER_SET
   tmp &= 0xe0;
   if (pcm_speed >= 2 * 17897)
-    tmp |= 0x21;
+    tmp |= 0x01;
   else if (pcm_speed >= 2 * 15909)
-    tmp |= 0x22;
+    tmp |= 0x02;
   else if (pcm_speed >= 2 * 11931)
-    tmp |= 0x29;
+    tmp |= 0x09;
   else if (pcm_speed >= 2 * 8948)
-    tmp |= 0x31;
+    tmp |= 0x11;
   else if (pcm_speed >= 2 * 5965)
-    tmp |= 0x39;
+    tmp |= 0x19;
   else if (pcm_speed >= 2 * 2982)
-    tmp |= 0x24;
+    tmp |= 0x04;
   pcm_filter = tmp;
 #endif
 
   save_flags (flags);
   cli ();
 
-  pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
-  pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
-  pas_write (foo & 0xff, SAMPLE_RATE_TIMER);
-  pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);
-  pas_write (tmp, FILTER_FREQUENCY);
+  pas_write (tmp & ~(0x40 | 0x80), 0x0B8A);
+  pas_write (0x00 | 0x30 | 0x04, 0x138B);
+  pas_write (foo & 0xff, 0x1388);
+  pas_write ((foo >> 8) & 0xff, 0x1388);
+  pas_write (tmp, 0x0B8A);
 
   restore_flags (flags);
 
@@ -133,7 +113,7 @@
 
   if (arg != pcm_channels)
     {
-      pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
+      pas_write (pas_read (0xF8A) ^ 0x20, 0xF8A);
 
       pcm_channels = arg;
       pcm_set_speed (pcm_speed);	/*
@@ -152,7 +132,7 @@
 
   if (arg != pcm_bits)
     {
-      pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);
+      pas_write (pas_read (0x8389) ^ 0x04, 0x8389);
 
       pcm_bits = arg;
     }
@@ -161,9 +141,9 @@
 }
 
 static int
-pas_pcm_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
+pas_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
 {
-  TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
+  DEB (printk ("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
 
   switch (cmd)
     {
@@ -212,7 +192,7 @@
 					 * NOT YET IMPLEMENTED
 					 */
       if (get_fs_long ((long *) arg) > 1)
-	return -EINVAL;
+	return -(EINVAL);
       pcm_filter = get_fs_long ((long *) arg);
       break;
 
@@ -221,34 +201,34 @@
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
-pas_pcm_reset (int dev)
+pas_audio_reset (int dev)
 {
-  TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
+  DEB (printk ("pas2_pcm.c: static void pas_audio_reset(void)\n"));
 
-  pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
+  pas_write (pas_read (0xF8A) & ~0x40, 0xF8A);
 }
 
 static int
-pas_pcm_open (int dev, int mode)
+pas_audio_open (int dev, int mode)
 {
   int             err;
   unsigned long   flags;
 
-  TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
+  DEB (printk ("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode));
 
   save_flags (flags);
   cli ();
   if (pcm_busy)
     {
       restore_flags (flags);
-      return -EBUSY;
+      return -(EBUSY);
     }
 
   pcm_busy = 1;
@@ -265,16 +245,16 @@
 }
 
 static void
-pas_pcm_close (int dev)
+pas_audio_close (int dev)
 {
   unsigned long   flags;
 
-  TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n"));
+  DEB (printk ("pas2_pcm.c: static void pas_audio_close(void)\n"));
 
   save_flags (flags);
   cli ();
 
-  pas_pcm_reset (dev);
+  pas_audio_reset (dev);
   pas_remove_intr (PAS_PCM_INTRBITS);
   pcm_mode = PCM_NON;
 
@@ -283,12 +263,12 @@
 }
 
 static void
-pas_pcm_output_block (int dev, unsigned long buf, int count,
-		      int intrflag, int restart_dma)
+pas_audio_output_block (int dev, unsigned long buf, int count,
+			int intrflag, int restart_dma)
 {
   unsigned long   flags, cnt;
 
-  TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
+  DEB (printk ("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count));
 
   cnt = count;
   if (audio_devs[dev]->dmachan1 > 3)
@@ -304,8 +284,8 @@
   save_flags (flags);
   cli ();
 
-  pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
-	     PCM_CONTROL);
+  pas_write (pas_read (0xF8A) & ~0x40,
+	     0xF8A);
 
   if (restart_dma)
     DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
@@ -315,17 +295,17 @@
 
   if (count != pcm_count)
     {
-      pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
-      pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
-      pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
-      pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
-      pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+      pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A);
+      pas_write (0x40 | 0x30 | 0x04, 0x138B);
+      pas_write (count & 0xff, 0x1389);
+      pas_write ((count >> 8) & 0xff, 0x1389);
+      pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A);
 
       pcm_count = count;
     }
-  pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+  pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A);
 #ifdef NO_TRIGGER
-  pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
+  pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A);
 #endif
 
   pcm_mode = PCM_DAC;
@@ -334,19 +314,19 @@
 }
 
 static void
-pas_pcm_start_input (int dev, unsigned long buf, int count,
-		     int intrflag, int restart_dma)
+pas_audio_start_input (int dev, unsigned long buf, int count,
+		       int intrflag, int restart_dma)
 {
   unsigned long   flags;
   int             cnt;
 
-  TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
+  DEB (printk ("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count));
 
   cnt = count;
   if (audio_devs[dev]->dmachan1 > 3)
     cnt >>= 1;
 
-  if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&
+  if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == pcm_count)
     return;			/*
@@ -364,17 +344,17 @@
 
   if (count != pcm_count)
     {
-      pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
-      pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
-      pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
-      pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
-      pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+      pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A);
+      pas_write (0x40 | 0x30 | 0x04, 0x138B);
+      pas_write (count & 0xff, 0x1389);
+      pas_write ((count >> 8) & 0xff, 0x1389);
+      pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A);
 
       pcm_count = count;
     }
-  pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+  pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A);
 #ifdef NO_TRIGGER
-  pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
+  pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A);
 #endif
 
   pcm_mode = PCM_ADC;
@@ -384,7 +364,7 @@
 
 #ifndef NO_TRIGGER
 static void
-pas_pcm_trigger (int dev, int state)
+pas_audio_trigger (int dev, int state)
 {
   unsigned long   flags;
 
@@ -393,75 +373,74 @@
   state &= open_mode;
 
   if (state & PCM_ENABLE_OUTPUT)
-    pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
+    pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A);
   else if (state & PCM_ENABLE_INPUT)
-    pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
+    pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A);
   else
-    pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
+    pas_write (pas_read (0xF8A) & ~0x40, 0xF8A);
 
   restore_flags (flags);
 }
 #endif
 
 static int
-pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
+pas_audio_prepare_for_input (int dev, int bsize, int bcount)
 {
   return 0;
 }
 
 static int
-pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
+pas_audio_prepare_for_output (int dev, int bsize, int bcount)
 {
   return 0;
 }
 
-static struct audio_operations pas_pcm_operations =
+static struct audio_driver pas_audio_driver =
 {
-  "Pro Audio Spectrum",
-  DMA_AUTOMODE,
-  AFMT_U8 | AFMT_S16_LE,
+  pas_audio_open,
+  pas_audio_close,
+  pas_audio_output_block,
+  pas_audio_start_input,
+  pas_audio_ioctl,
+  pas_audio_prepare_for_input,
+  pas_audio_prepare_for_output,
+  pas_audio_reset,
+  pas_audio_reset,
   NULL,
-  pas_pcm_open,
-  pas_pcm_close,
-  pas_pcm_output_block,
-  pas_pcm_start_input,
-  pas_pcm_ioctl,
-  pas_pcm_prepare_for_input,
-  pas_pcm_prepare_for_output,
-  pas_pcm_reset,
-  pas_pcm_reset,
   NULL,
   NULL,
   NULL,
+  pas_audio_trigger
+};
+
+static struct audio_operations pas_audio_operations =
+{
+  "Pro Audio Spectrum",
+  DMA_AUTOMODE,
+  AFMT_U8 | AFMT_S16_LE,
   NULL,
-#ifndef NO_TRIGGER
-  pas_pcm_trigger
-#else
-  NULL
-#endif
+  &pas_audio_driver
 };
 
-long
-pas_pcm_init (long mem_start, struct address_info *hw_config)
+void
+pas_pcm_init (struct address_info *hw_config)
 {
-  TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));
+  DEB (printk ("pas2_pcm.c: long pas_pcm_init()\n"));
 
   pcm_bitsok = 8;
-  if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)
+  if (pas_read (0xEF8B) & 0x08)
     pcm_bitsok |= 16;
 
   pcm_set_speed (DSP_DEFAULT_SPEED);
 
   if (num_audiodevs < MAX_AUDIO_DEV)
     {
-      audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;
-      audio_devs[my_devnum]->dmachan1 = hw_config->dma;
-      audio_devs[my_devnum]->buffsize = DSP_BUFFSIZE;
+      audio_devs[pas_audiodev = num_audiodevs++] = &pas_audio_operations;
+      audio_devs[pas_audiodev]->dmachan1 = hw_config->dma;
+      audio_devs[pas_audiodev]->buffsize = DSP_BUFFSIZE;
     }
   else
     printk ("PAS2: Too many PCM devices available\n");
-
-  return mem_start;
 }
 
 void
@@ -476,21 +455,21 @@
        * block before the PCM chip proceeds to the next sample
        */
 
-      if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE))
+      if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE))
 	{
-	  pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
-		     PCM_CONTROL);
+	  pas_write (pas_read (0xF8A) & ~0x40,
+		     0xF8A);
 	}
 
       switch (pcm_mode)
 	{
 
 	case PCM_DAC:
-	  DMAbuf_outputintr (my_devnum, 1);
+	  DMAbuf_outputintr (pas_audiodev, 1);
 	  break;
 
 	case PCM_ADC:
-	  DMAbuf_inputintr (my_devnum);
+	  DMAbuf_inputintr (pas_audiodev);
 	  break;
 
 	default:
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c
--- v2.0.0/linux/drivers/sound/patmgr.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/patmgr.c	Sun Jun 30 11:44:10 1996
@@ -1,30 +1,14 @@
 /*
  * sound/patmgr.c
  *
- * The patch manager interface for the /dev/sequencer
+ * The patch maneger interface for the /dev/sequencer
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -59,13 +43,13 @@
 pmgr_open (int dev)
 {
   if (dev < 0 || dev >= num_synths)
-    return -ENXIO;
+    return -(ENXIO);
 
   if (pmgr_opened[dev])
-    return -EBUSY;
+    return -(EBUSY);
   pmgr_opened[dev] = 1;
 
-  server_wait_flag[dev].mode = WK_NONE;
+  server_wait_flag[dev].flags = WK_NONE;
 
   return 0;
 }
@@ -80,11 +64,11 @@
     {
 
       mbox[dev]->key = PM_ERROR;
-      mbox[dev]->parm1 = -EIO;
+      mbox[dev]->parm1 = -(EIO);
 
-      if ((appl_wait_flag.mode & WK_SLEEP))
+      if ((appl_wait_flag.flags & WK_SLEEP))
 	{
-	  appl_wait_flag.mode = WK_WAKEUP;
+	  appl_wait_flag.flags = WK_WAKEUP;
 	  module_wake_up (&appl_proc);
 	};
     }
@@ -101,7 +85,7 @@
   if (count != sizeof (struct patmgr_info))
     {
       printk ("PATMGR%d: Invalid read count\n", dev);
-      return -EIO;
+      return -(EIO);
     }
 
   while (!ok && !current_got_fatal_signal ())
@@ -113,14 +97,14 @@
 	     !current_got_fatal_signal ())
 	{
 
-	  server_wait_flag[dev].mode = WK_SLEEP;
+	  server_wait_flag[dev].flags = WK_SLEEP;
 	  module_interruptible_sleep_on (&server_procs[dev]);
-	  server_wait_flag[dev].mode &= ~WK_SLEEP;;
+	  server_wait_flag[dev].flags &= ~WK_SLEEP;;
 	}
 
       if (mbox[dev] && msg_direction[dev] == A_TO_S)
 	{
-	  memcpy_tofs (&((buf)[0]), (char *) mbox[dev], count);
+	  memcpy_tofs (&(buf)[0], (char *) mbox[dev], count);
 	  msg_direction[dev] = 0;
 	  ok = 1;
 	}
@@ -130,7 +114,7 @@
     }
 
   if (!ok)
-    return -EINTR;
+    return -(EINTR);
   return count;
 }
 
@@ -142,10 +126,10 @@
   if (count < 4)
     {
       printk ("PATMGR%d: Write count < 4\n", dev);
-      return -EIO;
+      return -(EIO);
     }
 
-  memcpy_fromfs ((char *) mbox[dev], &((buf)[0]), 4);
+  memcpy_fromfs ((char *) mbox[dev], &(buf)[0], 4);
 
   if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE)
     {
@@ -153,7 +137,7 @@
 
       tmp_dev = ((unsigned short *) mbox[dev])[2];
       if (tmp_dev != dev)
-	return -ENXIO;
+	return -(ENXIO);
 
       return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev],
 					  buf, 4, count, 1);
@@ -162,7 +146,7 @@
   if (count != sizeof (struct patmgr_info))
     {
       printk ("PATMGR%d: Invalid write count\n", dev);
-      return -EIO;
+      return -(EIO);
     }
 
   /*
@@ -175,13 +159,13 @@
 
   if (mbox[dev] && !msg_direction[dev])
     {
-      memcpy_fromfs (&((char *) mbox[dev])[4], &((buf)[4]), count - 4);
+      memcpy_fromfs (&((char *) mbox[dev])[4], &(buf)[4], count - 4);
       msg_direction[dev] = S_TO_A;
 
-      if ((appl_wait_flag.mode & WK_SLEEP))
+      if ((appl_wait_flag.flags & WK_SLEEP))
 	{
 	  {
-	    appl_wait_flag.mode = WK_WAKEUP;
+	    appl_wait_flag.flags = WK_WAKEUP;
 	    module_wake_up (&appl_proc);
 	  };
 	}
@@ -209,23 +193,23 @@
       mbox[dev] = rec;
       msg_direction[dev] = A_TO_S;
 
-      if ((server_wait_flag[dev].mode & WK_SLEEP))
+      if ((server_wait_flag[dev].flags & WK_SLEEP))
 	{
 	  {
-	    server_wait_flag[dev].mode = WK_WAKEUP;
+	    server_wait_flag[dev].flags = WK_WAKEUP;
 	    module_wake_up (&server_procs[dev]);
 	  };
 	}
 
 
-      appl_wait_flag.mode = WK_SLEEP;
+      appl_wait_flag.flags = WK_SLEEP;
       module_interruptible_sleep_on (&appl_proc);
-      appl_wait_flag.mode &= ~WK_SLEEP;;
+      appl_wait_flag.flags &= ~WK_SLEEP;;
 
       if (msg_direction[dev] != S_TO_A)
 	{
 	  rec->key = PM_ERROR;
-	  rec->parm1 = -EIO;
+	  rec->parm1 = -(EIO);
 	}
       else if (rec->key == PM_ERROR)
 	{
@@ -255,7 +239,7 @@
   if (!pmgr_opened[dev])
     return 0;
 
-  tmp_mbox = (struct patmgr_info *) kmalloc (sizeof (struct patmgr_info), GFP_KERNEL);
+  tmp_mbox = (struct patmgr_info *) vmalloc (sizeof (struct patmgr_info));
 
   if (tmp_mbox == NULL)
     {
@@ -279,24 +263,24 @@
       mbox[dev]->parm3 = p3;
       msg_direction[dev] = A_TO_S;
 
-      if ((server_wait_flag[dev].mode & WK_SLEEP))
+      if ((server_wait_flag[dev].flags & WK_SLEEP))
 	{
 	  {
-	    server_wait_flag[dev].mode = WK_WAKEUP;
+	    server_wait_flag[dev].flags = WK_WAKEUP;
 	    module_wake_up (&server_procs[dev]);
 	  };
 	}
 
 
-      appl_wait_flag.mode = WK_SLEEP;
+      appl_wait_flag.flags = WK_SLEEP;
       module_interruptible_sleep_on (&appl_proc);
-      appl_wait_flag.mode &= ~WK_SLEEP;;
+      appl_wait_flag.flags &= ~WK_SLEEP;;
       mbox[dev] = NULL;
       msg_direction[dev] = 0;
     }
 
   restore_flags (flags);
-  kfree (tmp_mbox);
+  vfree (tmp_mbox);
 
   return err;
 }
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v2.0.0/linux/drivers/sound/pss.c	Sat Jun  1 20:11:32 1996
+++ linux/drivers/sound/pss.c	Sun Jun 30 11:44:11 1996
@@ -4,27 +4,11 @@
  * The low level driver for the Personal Sound System (ECHO ESC614).
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -69,12 +53,12 @@
 #include "synth-ld.h"
 #else
 static int      pss_synthLen = 0;
-static unsigned char pss_synth[1] =
-{0};
+static unsigned char *pss_synth =
+NULL;
 
 #endif
 
-typedef struct pss_config
+typedef struct pss_confdata
   {
     int             base;
     int             irq;
@@ -82,10 +66,10 @@
     int            *osp;
   }
 
-pss_config;
+pss_confdata;
 
-static pss_config pss_data;
-static pss_config *devc = &pss_data;
+static pss_confdata pss_data;
+static pss_confdata *devc = &pss_data;
 
 static int      pss_initialized = 0;
 static int      nonstandard_microcode = 0;
@@ -122,7 +106,7 @@
 }
 
 static int
-set_irq (pss_config * devc, int dev, int irq)
+set_irq (pss_confdata * devc, int dev, int irq)
 {
   static unsigned short irq_bits[16] =
   {
@@ -150,7 +134,7 @@
 }
 
 static int
-set_io_base (pss_config * devc, int dev, int base)
+set_io_base (pss_confdata * devc, int dev, int base)
 {
   unsigned short  tmp = inw (REG (dev)) & 0x003f;
   unsigned short  bits = (base & 0x0ffc) << 4;
@@ -161,7 +145,7 @@
 }
 
 static int
-set_dma (pss_config * devc, int dev, int dma)
+set_dma (pss_confdata * devc, int dev, int dma)
 {
   static unsigned short dma_bits[8] =
   {
@@ -187,7 +171,7 @@
 }
 
 static int
-pss_reset_dsp (pss_config * devc)
+pss_reset_dsp (pss_confdata * devc)
 {
   unsigned long   i, limit = jiffies + 10;
 
@@ -202,7 +186,7 @@
 }
 
 static int
-pss_put_dspword (pss_config * devc, unsigned short word)
+pss_put_dspword (pss_confdata * devc, unsigned short word)
 {
   int             i, val;
 
@@ -219,7 +203,7 @@
 }
 
 static int
-pss_get_dspword (pss_config * devc, unsigned short *word)
+pss_get_dspword (pss_confdata * devc, unsigned short *word)
 {
   int             i, val;
 
@@ -237,7 +221,7 @@
 }
 
 static int
-pss_download_boot (pss_config * devc, unsigned char *block, int size, int flags)
+pss_download_boot (pss_confdata * devc, unsigned char *block, int size, int flags)
 {
   int             i, limit, val, count;
 
@@ -320,8 +304,8 @@
   return 1;
 }
 
-long
-attach_pss (long mem_start, struct address_info *hw_config)
+void
+attach_pss (struct address_info *hw_config)
 {
   unsigned short  id;
   char            tmp[100];
@@ -332,7 +316,7 @@
   devc->osp = hw_config->osp;
 
   if (!probe_pss (hw_config))
-    return mem_start;
+    return;
 
   id = inw (REG (PSS_ID)) & 0x00ff;
 
@@ -349,27 +333,25 @@
   if (sound_alloc_dma (hw_config->dma, "PSS"))
     {
       printk ("pss.c: Can't allocate DMA channel\n");
-      return mem_start;
+      return;
     }
 
   if (!set_irq (devc, CONF_PSS, devc->irq))
     {
       printk ("PSS: IRQ error\n");
-      return mem_start;
+      return;
     }
 
   if (!set_dma (devc, CONF_PSS, devc->dma))
     {
       printk ("PSS: DRQ error\n");
-      return mem_start;
+      return;
     }
 #endif
 
   pss_initialized = 1;
   sprintf (tmp, "ECHO-PSS  Rev. %d", id);
   conf_printf (tmp, hw_config);
-
-  return mem_start;
 }
 
 int
@@ -440,14 +422,14 @@
       if (pss_synthLen == 0)
 	{
 	  printk ("PSS: MIDI synth microcode not available.\n");
-	  return -EIO;
+	  return -(EIO);
 	}
 
       if (nonstandard_microcode)
 	if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
 	  {
 	    printk ("PSS: Unable to load MIDI synth microcode to DSP.\n");
-	    return -EIO;
+	    return -(EIO);
 	  }
       nonstandard_microcode = 0;
       break;
@@ -478,12 +460,12 @@
 download_boot_block (void *dev_info, copr_buffer * buf)
 {
   if (buf->len <= 0 || buf->len > sizeof (buf->data))
-    return -EINVAL;
+    return -(EINVAL);
 
   if (!pss_download_boot (devc, buf->data, buf->len, buf->flags))
     {
       printk ("PSS: Unable to load microcode block to DSP.\n");
-      return -EIO;
+      return -(EIO);
     }
   nonstandard_microcode = 1;	/* The MIDI microcode has been overwritten */
 
@@ -507,31 +489,29 @@
 	copr_buffer    *buf;
 	int             err;
 
-	buf = (copr_buffer *) kmalloc (sizeof (copr_buffer), GFP_KERNEL);
+	buf = (copr_buffer *) vmalloc (sizeof (copr_buffer));
 	if (buf == NULL)
-	  return -ENOSPC;
+	  return -(ENOSPC);
 
-	memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf));
+	memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf));
 	err = download_boot_block (dev_info, buf);
-	kfree (buf);
+	vfree (buf);
 	return err;
       }
       break;
 
     case SNDCTL_COPR_SENDMSG:
       {
-	/* send buf->len words from buf->data to DSP */
-
 	copr_msg       *buf;
 	unsigned long   flags;
 	unsigned short *data;
 	int             i;
 
-	buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL);
+	buf = (copr_msg *) vmalloc (sizeof (copr_msg));
 	if (buf == NULL)
-	  return -ENOSPC;
+	  return -(ENOSPC);
 
-	memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf));
+	memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf));
 
 	data = (unsigned short *) (buf->data);
 
@@ -543,16 +523,15 @@
 	    if (!pss_put_dspword (devc, *data++))
 	      {
 		restore_flags (flags);
-		/* feed back number of WORDs sent */
-		memcpy_tofs( (char *)(&(((copr_msg *)arg)->len)),
-				(char *)(&i), sizeof(buf->len));
-		kfree (buf);
-		return -EIO;
+		buf->len = i;	/* feed back number of WORDs sent */
+		memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf));
+		vfree (buf);
+		return -(EIO);
 	      }
 	  }
 
 	restore_flags (flags);
-	kfree (buf);
+	vfree (buf);
 
 	return 0;
       }
@@ -561,42 +540,37 @@
 
     case SNDCTL_COPR_RCVMSG:
       {
-	/* try to read as much words as possible from DSP into buf */
 	copr_msg       *buf;
 	unsigned long   flags;
 	unsigned short *data;
 	unsigned int    i;
 	int             err = 0;
 
-	buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL);
+	buf = (copr_msg *) vmalloc (sizeof (copr_msg));
 	if (buf == NULL)
-	  return -ENOSPC;
-#if 0
-	memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf));
-#endif
+	  return -(ENOSPC);
+
 
 	data = (unsigned short *) buf->data;
 
 	save_flags (flags);
 	cli ();
 
-	for (i = 0; i < sizeof(buf->data); i++)
+	for (i = 0; i < buf->len; i++)
 	  {
+	    buf->len = i;	/* feed back number of WORDs read */
 	    if (!pss_get_dspword (devc, data++))
 	      {
-		buf->len = i;	/* feed back number of WORDs read */
-		err = (i==0)? -EIO : 0;	   /* EIO only if no word read */
+		if (i == 0)
+		  err = -(EIO);
 		break;
 	      }
 	  }
 
-	if( i==sizeof(buf->data) )
-		buf->len = i;
-
 	restore_flags (flags);
 
-	memcpy_tofs ((&((char *) arg)[0]), buf, sizeof (*buf));
-	kfree (buf);
+	memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf));
+	vfree (buf);
 
 	return err;
       }
@@ -609,32 +583,32 @@
 	unsigned long   flags;
 	unsigned short  tmp;
 
-	memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf));
+	memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf));
 
 	save_flags (flags);
 	cli ();
 	if (!pss_put_dspword (devc, 0x00d0))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	if (!pss_get_dspword (devc, &tmp))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	buf.parm1 = tmp;
 	restore_flags (flags);
 
-	memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf));
+	memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf));
 	return 0;
       }
       break;
@@ -645,27 +619,27 @@
 	unsigned long   flags;
 	unsigned short  tmp;
 
-	memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf));
+	memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf));
 
 	save_flags (flags);
 	cli ();
 	if (!pss_put_dspword (devc, 0x00d1))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	tmp = (unsigned int) buf.parm2 & 0xffff;
 	if (!pss_put_dspword (devc, tmp))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	restore_flags (flags);
@@ -679,34 +653,34 @@
 	unsigned long   flags;
 	unsigned short  tmp;
 
-	memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf));
+	memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf));
 
 	save_flags (flags);
 	cli ();
 	if (!pss_put_dspword (devc, 0x00d3))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	tmp = (unsigned int) buf.parm2 & 0x00ff;
 	if (!pss_put_dspword (devc, tmp))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff;
 	if (!pss_put_dspword (devc, tmp))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	restore_flags (flags);
@@ -720,26 +694,26 @@
 	unsigned long   flags;
 	unsigned short  tmp;
 
-	memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf));
+	memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf));
 
 	save_flags (flags);
 	cli ();
 	if (!pss_put_dspword (devc, 0x00d2))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	if (!pss_get_dspword (devc, &tmp))	/* Read msb */
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	buf.parm1 = tmp << 8;
@@ -747,23 +721,23 @@
 	if (!pss_get_dspword (devc, &tmp))	/* Read lsb */
 	  {
 	    restore_flags (flags);
-	    return -EIO;
+	    return -(EIO);
 	  }
 
 	buf.parm1 |= tmp & 0x00ff;
 
 	restore_flags (flags);
 
-	memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf));
+	memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf));
 	return 0;
       }
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static coproc_operations pss_coproc_operations =
@@ -776,23 +750,19 @@
   &pss_data
 };
 
-long
-attach_pss_mpu (long mem_start, struct address_info *hw_config)
+void
+attach_pss_mpu (struct address_info *hw_config)
 {
 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
-  long            ret;
-
   {
     int             prev_devs;
+
     prev_devs = num_midis;
-    ret = attach_mpu401 (mem_start, hw_config);
+    attach_mpu401 (hw_config);
 
     if (num_midis == (prev_devs + 1))	/* The MPU driver installed itself */
       midi_devs[prev_devs]->coproc = &pss_coproc_operations;
   }
-  return ret;
-#else
-  return mem_start;
 #endif
 }
 
@@ -830,7 +800,7 @@
 
   /*
      * For some reason the card returns 0xff in the WSS status register
-     * immediately after boot. Probably MIDI+SB emulation algorithm
+     * immediately after boot. Propably MIDI+SB emulation algorithm
      * downloaded to the ADSP2115 spends some time initializing the card.
      * Let's try to wait until it finishes this task.
    */
@@ -842,19 +812,16 @@
   return probe_ms_sound (hw_config);
 }
 
-long
-attach_pss_mss (long mem_start, struct address_info *hw_config)
+void
+attach_pss_mss (struct address_info *hw_config)
 {
   int             prev_devs;
-  long            ret;
 
   prev_devs = num_audiodevs;
-  ret = attach_ms_sound (mem_start, hw_config);
+  attach_ms_sound (hw_config);
 
   if (num_audiodevs == (prev_devs + 1))		/* The MSS driver installed itself */
     audio_devs[prev_devs]->coproc = &pss_coproc_operations;
-
-  return ret;
 }
 
 void
@@ -865,9 +832,7 @@
 void
 unload_pss_mpu (struct address_info *hw_config)
 {
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   unload_mpu401 (hw_config);
-#endif
 }
 
 void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb.h linux/drivers/sound/sb.h
--- v2.0.0/linux/drivers/sound/sb.h	Sun Mar 24 22:49:43 1996
+++ linux/drivers/sound/sb.h	Sun Jun 30 11:43:38 1996
@@ -1,15 +1,15 @@
-#define DSP_RESET	(sbc_base + 0x6)
-#define DSP_READ	(sbc_base + 0xA)
-#define DSP_WRITE	(sbc_base + 0xC)
-#define DSP_COMMAND	(sbc_base + 0xC)
-#define DSP_STATUS	(sbc_base + 0xC)
-#define DSP_DATA_AVAIL	(sbc_base + 0xE)
-#define DSP_DATA_AVL16	(sbc_base + 0xF)
-#define MIXER_ADDR	(sbc_base + 0x4)
-#define MIXER_DATA	(sbc_base + 0x5)
-#define OPL3_LEFT	(sbc_base + 0x0)
-#define OPL3_RIGHT	(sbc_base + 0x2)
-#define OPL3_BOTH	(sbc_base + 0x8)
+#define DSP_RESET	(devc->base + 0x6)
+#define DSP_READ	(devc->base + 0xA)
+#define DSP_WRITE	(devc->base + 0xC)
+#define DSP_COMMAND	(devc->base + 0xC)
+#define DSP_STATUS	(devc->base + 0xC)
+#define DSP_DATA_AVAIL	(devc->base + 0xE)
+#define DSP_DATA_AVL16	(devc->base + 0xF)
+#define MIXER_ADDR	(devc->base + 0x4)
+#define MIXER_DATA	(devc->base + 0x5)
+#define OPL3_LEFT	(devc->base + 0x0)
+#define OPL3_RIGHT	(devc->base + 0x2)
+#define OPL3_BOTH	(devc->base + 0x8)
 /* DSP Commands */
 
 #define DSP_CMD_SPKON		0xD1
@@ -26,3 +26,96 @@
 #define NORMAL_MIDI	0
 #define UART_MIDI	1
 
+
+/*
+ * Device models
+ */
+#define MDL_NONE	0
+#define MDL_SB1		1	/* SB1.0 or 1.5 */
+#define MDL_SB2		2	/* SB2.0 */
+#define MDL_SB201	3	/* SB2.01 */
+#define MDL_SBPRO	4	/* SB Pro */
+#define MDL_SB16	5	/* SB16/32/AWE */
+#define MDL_JAZZ	10	/* Media Vision Jazz16 */
+#define MDL_SMW		11	/* Logitech Soundman Wave (Jazz16) */
+#define MDL_ESS		12	/* ESS ES688 and ES1688 */
+#define MDL_AZTECH	13	/* Aztech Sound Galaxy family */
+
+/*
+ * Config flags
+ */
+#define SB_NO_MIDI	0x00000001
+#define SB_NO_MIXER	0x00000002
+#define SB_NO_AUDIO	0x00000004
+#define SB_NO_RECORDING	0x00000008 /* No audio recording */
+#define SB_MIDI_ONLY	(SB_NO_AUDIO|SB_NO_MIXER)
+
+struct mixer_def {
+	unsigned int regno: 8;
+	unsigned int bitoffs:4;
+	unsigned int nbits:4;
+};
+
+typedef struct mixer_def mixer_tab[32][2];
+typedef struct mixer_def mixer_ent;
+
+typedef struct sb_devc {
+	   int dev;
+
+	/* Hardware parameters */
+	   int *osp;
+	   int minor, major;
+	   int type;
+	   int model, submodel;
+	   int caps;
+#	define SBCAP_STEREO	0x00000001
+#	define SBCAP_16BITS	0x00000002
+
+	/* Hardware resources */
+	   int base;
+	   int irq;
+	   int dma8, dma16;
+
+	/* State variables */
+ 	   int opened;
+	   int speed, bits, channels;
+	   volatile int irq_ok;
+	   volatile int intr_active, irq_mode;
+
+	/* Mixer fields */
+	   int levels[SOUND_MIXER_NRDEVICES];
+	   mixer_tab *iomap;
+	   int mixer_caps, recmask, supported_devices;
+	   int supported_rec_devices;
+	   int my_mixerdev;
+
+	/* Audio fields */
+	   unsigned long trg_buf;
+	   int      trigger_bits;
+	   int      trg_bytes;
+	   int      trg_intrflag;
+	   int      trg_restart;
+	   unsigned char tconst;
+	   int my_dev;
+	
+	/* MIDI fields */
+	   int my_mididev;
+	   int input_opened;
+	   void (*midi_input_intr) (int dev, unsigned char data);
+	} sb_devc;
+
+int sb_dsp_command (sb_devc *devc, unsigned char val);
+int sb_dsp_get_byte (sb_devc *devc);
+int sb_dsp_reset (sb_devc *devc);
+void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value);
+unsigned int sb_getmixer (sb_devc *devc, unsigned int port);
+int sb_dsp_detect (struct address_info *hw_config);
+void sb_dsp_init (struct address_info *hw_config);
+void sb_dsp_unload(struct address_info *hw_config);
+int sb_mixer_init(sb_devc *devc);
+void smw_mixer_init(sb_devc *devc);
+void sb_dsp_midi_init (sb_devc *devc);
+void sb_audio_init (sb_devc *devc, char *name);
+void sb_midi_interrupt (sb_devc *devc);
+int ess_write (sb_devc *devc, unsigned char reg, unsigned char data);
+int ess_read (sb_devc *devc, unsigned char reg);
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c
--- v2.0.0/linux/drivers/sound/sb16_dsp.c	Mon Mar 25 09:25:26 1996
+++ linux/drivers/sound/sb16_dsp.c	Thu Jan  1 02:00:00 1970
@@ -1,643 +0,0 @@
-/*
- * sound/sb16_dsp.c
- *
- * The low level driver for the SoundBlaster DSP chip.
- */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <linux/config.h>
-
-
-#define DEB(x)
-#define DEB1(x)
-/*
- * #define DEB_DMARES
- */
-#include "sound_config.h"
-#include "sb.h"
-#include "sb_mixer.h"
-
-#if defined(CONFIG_SB) && defined(CONFIG_AUDIO)
-
-extern int      sbc_base;
-extern int     *sb_osp;
-
-static int      sb16_dsp_ok = 0;
-static int      dsp_16bit = 0;
-static int      dsp_stereo = 0;
-static int      dsp_current_speed = 8000;
-static int      dsp_busy = 0;
-static int      dma16 = -1, dma8 = -1;
-static int      trigger_bits = 0;
-static unsigned long dsp_count = 0;
-
-static int      irq_mode = IMODE_NONE;
-static int      my_dev = 0;
-
-static volatile int intr_active = 0;
-
-static int      sb16_dsp_open (int dev, int mode);
-static void     sb16_dsp_close (int dev);
-static void     sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
-static void     sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
-static int      sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local);
-static int      sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
-static int      sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
-static void     sb16_dsp_reset (int dev);
-static void     sb16_dsp_halt (int dev);
-static void     sb16_dsp_trigger (int dev, int bits);
-static int      dsp_set_speed (int);
-static int      dsp_set_stereo (int);
-static void     dsp_cleanup (void);
-int             sb_reset_dsp (void);
-
-static struct audio_operations sb16_dsp_operations =
-{
-  "SoundBlaster 16",
-  DMA_AUTOMODE,
-  AFMT_U8 | AFMT_S16_LE,
-  NULL,
-  sb16_dsp_open,
-  sb16_dsp_close,
-  sb16_dsp_output_block,
-  sb16_dsp_start_input,
-  sb16_dsp_ioctl,
-  sb16_dsp_prepare_for_input,
-  sb16_dsp_prepare_for_output,
-  sb16_dsp_reset,
-  sb16_dsp_halt,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
-  sb16_dsp_trigger
-};
-
-static int
-sb_dsp_command01 (unsigned char val)
-{
-  int             i = 1 << 16;
-
-  while (--i & (!inb (DSP_STATUS) & 0x80));
-  if (!i)
-    printk ("SB16 sb_dsp_command01 Timeout\n");
-  return sb_dsp_command (val);
-}
-
-static int
-dsp_set_speed (int mode)
-{
-  DEB (printk ("dsp_set_speed(%d)\n", mode));
-  if (mode)
-    {
-      if (mode < 5000)
-	mode = 5000;
-      if (mode > 44100)
-	mode = 44100;
-      dsp_current_speed = mode;
-    }
-  return mode;
-}
-
-static int
-dsp_set_stereo (int mode)
-{
-  DEB (printk ("dsp_set_stereo(%d)\n", mode));
-
-  dsp_stereo = mode;
-
-  return mode;
-}
-
-static int
-dsp_set_bits (int arg)
-{
-  DEB (printk ("dsp_set_bits(%d)\n", arg));
-
-  if (arg)
-    switch (arg)
-      {
-      case 8:
-	dsp_16bit = 0;
-	break;
-      case 16:
-	dsp_16bit = 1;
-	break;
-      default:
-	dsp_16bit = 0;
-      }
-  return dsp_16bit ? 16 : 8;
-}
-
-static int
-sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
-{
-  switch (cmd)
-    {
-    case SOUND_PCM_WRITE_RATE:
-      if (local)
-	return dsp_set_speed ((long) arg);
-      return snd_ioctl_return ((int *) arg, dsp_set_speed (get_fs_long ((long *) arg)));
-
-    case SOUND_PCM_READ_RATE:
-      if (local)
-	return dsp_current_speed;
-      return snd_ioctl_return ((int *) arg, dsp_current_speed);
-
-    case SNDCTL_DSP_STEREO:
-      if (local)
-	return dsp_set_stereo ((long) 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 snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1);
-
-    case SOUND_PCM_READ_CHANNELS:
-      if (local)
-	return dsp_stereo + 1;
-      return snd_ioctl_return ((int *) arg, dsp_stereo + 1);
-
-    case SNDCTL_DSP_SETFMT:
-      if (local)
-	return dsp_set_bits ((long) arg);
-      return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg)));
-
-    case SOUND_PCM_READ_BITS:
-      if (local)
-	return dsp_16bit ? 16 : 8;
-      return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8);
-
-    case SOUND_PCM_WRITE_FILTER:	/*
-					 * NOT YET IMPLEMENTED
-					 */
-      if (get_fs_long ((long *) arg) > 1)
-	return snd_ioctl_return ((int *) arg, -EINVAL);
-    default:
-      return -EINVAL;
-    }
-
-  return -EINVAL;
-}
-
-static int
-sb16_dsp_open (int dev, int mode)
-{
-  int             retval;
-
-  DEB (printk ("sb16_dsp_open()\n"));
-  if (!sb16_dsp_ok)
-    {
-      printk ("SB16 Error: SoundBlaster board not installed\n");
-      return -ENXIO;
-    }
-
-  if (intr_active)
-    return -EBUSY;
-
-  retval = sb_get_irq ();
-  if (retval < 0)
-    return retval;
-
-  sb_reset_dsp ();
-
-  if (dma16 != dma8)
-    if (sound_open_dma (dma16, "SB16 (16bit)"))
-      {
-	printk ("SB16: Unable to grab DMA%d\n", dma16);
-	sb_free_irq ();
-	return -EBUSY;
-      }
-
-  irq_mode = IMODE_NONE;
-  dsp_busy = 1;
-  trigger_bits = 0;
-
-  return 0;
-}
-
-static void
-sb16_dsp_close (int dev)
-{
-  unsigned long   flags;
-
-  DEB (printk ("sb16_dsp_close()\n"));
-  sb_dsp_command01 (0xd9);
-  sb_dsp_command01 (0xd5);
-  sb_reset_dsp ();
-
-  save_flags (flags);
-  cli ();
-
-  audio_devs[dev]->dmachan1 = audio_devs[dev]->dmachan2 = dma8;
-
-  if (dma16 != dma8)
-    sound_close_dma (dma16);
-  sb_free_irq ();
-  dsp_cleanup ();
-  dsp_busy = 0;
-  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;
-  if (dsp_16bit)
-    cnt >>= 1;
-  cnt--;
-
-  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
-      intrflag &&
-      cnt == dsp_count)
-    {
-      irq_mode = IMODE_OUTPUT;
-      intr_active = 1;
-      return;			/*
-				 * Auto mode on. No need to react
-				 */
-    }
-  save_flags (flags);
-  cli ();
-
-  if (dma_restart)
-    {
-      sb16_dsp_halt (dev);
-      DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
-    }
-  sb_dsp_command (0x41);
-  sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
-  sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
-  sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6));
-  dsp_count = cnt;
-  sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
-				   (dsp_16bit ? 0x10 : 0)));
-  sb_dsp_command01 ((unsigned char) (cnt & 0xff));
-  sb_dsp_command ((unsigned char) (cnt >> 8));
-
-  irq_mode = IMODE_OUTPUT;
-  intr_active = 1;
-  restore_flags (flags);
-}
-
-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;
-  if (dsp_16bit)
-    cnt >>= 1;
-  cnt--;
-
-  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
-      intrflag &&
-      cnt == dsp_count)
-    {
-      irq_mode = IMODE_INPUT;
-      intr_active = 1;
-      return;			/*
-				 * Auto mode on. No need to react
-				 */
-    }
-  save_flags (flags);
-  cli ();
-
-  if (dma_restart)
-    {
-      sb16_dsp_halt (dev);
-      DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
-    }
-
-  sb_dsp_command (0x42);
-  sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
-  sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
-
-  sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce));
-  dsp_count = cnt;
-  sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
-				   (dsp_16bit ? 0x10 : 0)));
-  sb_dsp_command01 ((unsigned char) (cnt & 0xff));
-  sb_dsp_command ((unsigned char) (cnt >> 8));
-
-  irq_mode = IMODE_INPUT;
-  intr_active = 1;
-  restore_flags (flags);
-}
-
-static int
-sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
-{
-  audio_devs[my_dev]->dmachan1 =
-    audio_devs[my_dev]->dmachan2 =
-    dsp_16bit ? dma16 : dma8;
-  dsp_count = 0;
-  dsp_cleanup ();
-  trigger_bits = 0;
-  return 0;
-}
-
-static int
-sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
-{
-  audio_devs[my_dev]->dmachan1 =
-    audio_devs[my_dev]->dmachan2 =
-    dsp_16bit ? dma16 : dma8;
-  dsp_count = 0;
-  dsp_cleanup ();
-  trigger_bits = 0;
-  return 0;
-}
-
-static void
-sb16_dsp_trigger (int dev, int bits)
-{
-  trigger_bits = bits;
-
-  if (!bits)
-    {
-      sb_dsp_command (0xd0);	/* Halt DMA */
-    }
-  else if (bits & irq_mode)
-    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
-dsp_cleanup (void)
-{
-  irq_mode = IMODE_NONE;
-  intr_active = 0;
-}
-
-static void
-sb16_dsp_reset (int dev)
-{
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-
-  sb_reset_dsp ();
-  dsp_cleanup ();
-
-  restore_flags (flags);
-}
-
-static void
-sb16_dsp_halt (int dev)
-{
-  if (dsp_16bit)
-    {
-      sb_dsp_command01 (0xd9);
-      sb_dsp_command01 (0xd5);
-    }
-  else
-    {
-      sb_dsp_command01 (0xda);
-      sb_dsp_command01 (0xd0);
-    }
-  /* DMAbuf_reset_dma (dev); */
-}
-
-static void
-set_irq_hw (int level)
-{
-  int             ival;
-
-  switch (level)
-    {
-    case 5:
-      ival = 2;
-      break;
-    case 7:
-      ival = 4;
-      break;
-    case 9:
-      ival = 1;
-      break;
-    case 10:
-      ival = 8;
-      break;
-    default:
-      printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
-      return;
-    }
-  sb_setmixer (IRQ_NR, ival);
-}
-
-long
-sb16_dsp_init (long mem_start, struct address_info *hw_config)
-{
-  extern int      sbc_major, sbc_minor;
-
-  if (sbc_major < 4)
-    return mem_start;		/* Not a SB16 */
-
-  sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
-
-  conf_printf (sb16_dsp_operations.name, hw_config);
-
-  if (num_audiodevs < MAX_AUDIO_DEV)
-    {
-      audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations;
-      audio_devs[my_dev]->dmachan1 = audio_devs[my_dev]->dmachan2 = dma8;
-      audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
-
-      if (sound_alloc_dma (dma8, "SB16 (8bit)"))
-	{
-	  printk ("SB16: Unable to grab DMA%d\n", dma8);
-	}
-
-      if (dma16 != dma8)
-	if (sound_alloc_dma (dma16, "SB16 (16bit)"))
-	  {
-	    printk ("SB16: Unable to grab DMA%d\n", dma16);
-	  }
-    }
-  else
-    printk ("SB: Too many DSP devices available\n");
-  sb16_dsp_ok = 1;
-  return mem_start;
-}
-
-static void
-set_dma (int dma)
-{
-  if (dma >= 0 && dma < 4)
-    dma8 = dma;
-  if (dma >= 5 && dma <= 7)
-    dma16 = dma;
-}
-
-int
-sb16_dsp_detect (struct address_info *hw_config)
-{
-  struct address_info *sb_config;
-  extern int      sbc_major, Jazz16_detected;
-
-  extern void     Jazz16_set_dma16 (int dma);
-  int             irq;
-
-  if (sb16_dsp_ok)
-    {
-      return 1;			/* Can't drive two cards */
-    }
-
-  irq = hw_config->irq;
-  set_dma (hw_config->dma);
-  set_dma (hw_config->dma2);
-
-  if (Jazz16_detected)
-    {
-      Jazz16_set_dma16 (dma16);
-      sb16_dsp_ok = 1;
-      return 1;
-    }
-
-  if (dma8 == -1)
-    if (!(sb_config = sound_getconf (SNDCARD_SB)))
-      {
-	printk ("SB16 Error: Plain SB not configured\n");
-	return 0;
-      }
-    else
-      {
-	dma8 = sb_config->dma;
-	irq = sb_config->irq;
-      }
-
-  if (dma16 == -1)
-    dma16 = dma8;
-
-  /*
-   * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0;
-   */
-
-  if (!sb_reset_dsp ())
-    return 0;
-
-  if (sbc_major < 4)		/* Set by the plain SB driver */
-    return 0;			/* Not a SB16 */
-
-  if (dma16 < 4)
-    if (dma16 != dma8)
-      {
-	printk ("SB16 Error: Invalid DMA channel %d/%d\n",
-		dma8, dma16);
-	return 0;
-      }
-
-  set_irq_hw (irq);
-  sb_setmixer (DMA_NR, (1 << dma16) | (1 << dma8));
-
-  DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, dma16));
-
-  /*
-     * dsp_showmessage(0xe3,99);
-   */
-  sb16_dsp_ok = 1;
-  return 1;
-}
-
-void
-unload_sb16 (struct address_info *hw_config)
-{
-  extern int      Jazz16_detected;
-
-  if (Jazz16_detected)
-    return;
-
-  sound_free_dma (dma8);
-
-  if (dma16 != dma8)
-    sound_free_dma (dma16);
-}
-
-void
-sb16_dsp_interrupt (int unused)
-{
-  int             data;
-
-  data = inb (DSP_DATA_AVL16);	/*
-				   * Interrupt acknowledge
-				 */
-
-  if (intr_active)
-    switch (irq_mode)
-      {
-      case IMODE_OUTPUT:
-	DMAbuf_outputintr (my_dev, 1);
-	break;
-
-      case IMODE_INPUT:
-	DMAbuf_inputintr (my_dev);
-	break;
-
-      default:
-	printk ("SoundBlaster: Unexpected interrupt\n");
-      }
-}
-
-#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c
--- v2.0.0/linux/drivers/sound/sb16_midi.c	Sun Mar 24 22:50:18 1996
+++ linux/drivers/sound/sb16_midi.c	Thu Jan  1 02:00:00 1970
@@ -1,364 +0,0 @@
-/*
- * sound/sb16_midi.c
- *
- * The low level driver for the MPU-401 UART emulation of the SB16.
- */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <linux/config.h>
-
-
-#include "sound_config.h"
-
-#if defined(CONFIG_SB) && defined(CONFIG_MIDI)
-
-#include "sb.h"
-
-#define	DATAPORT   (sb16midi_base)
-#define	COMDPORT   (sb16midi_base+1)
-#define	STATPORT   (sb16midi_base+1)
-
-extern int     *sb_osp;
-static int      sb16midi_base = 0;
-
-static int 
-sb16midi_status (void)
-{
-  return inb (STATPORT);
-}
-#define input_avail()		(!(sb16midi_status()&INPUT_AVAIL))
-#define output_ready()		(!(sb16midi_status()&OUTPUT_READY))
-static void 
-sb16midi_cmd (unsigned char cmd)
-{
-  outb (cmd, COMDPORT);
-}
-static int 
-sb16midi_read (void)
-{
-  return inb (DATAPORT);
-}
-static void 
-sb16midi_write (unsigned char byte)
-{
-  outb (byte, DATAPORT);
-}
-
-#define	OUTPUT_READY	0x40
-#define	INPUT_AVAIL	0x80
-#define	MPU_ACK		0xFE
-#define	MPU_RESET	0xFF
-#define	UART_MODE_ON	0x3F
-
-static int      sb16midi_opened = 0;
-static int      sb16midi_detected = 0;
-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)
-{
-  while (input_avail ())
-    {
-      unsigned char   c = sb16midi_read ();
-
-      if (c == MPU_ACK)
-	input_byte = c;
-      else if (sb16midi_opened & OPEN_READ && midi_input_intr)
-	midi_input_intr (my_dev, c);
-    }
-}
-
-void
-sb16midiintr (int unit)
-{
-  if (sb16midi_base == 0)
-    return;
-
-  if (input_avail ())
-    sb16midi_input_loop ();
-}
-
-void
-sbmidiintr (int irq, void *dev_id, 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),
-	       void            (*output) (int dev)
-)
-{
-  if (sb16midi_opened)
-    {
-      return -EBUSY;
-    }
-
-  while (input_avail ())
-    sb16midi_read ();
-
-  midi_input_intr = input;
-  sb16midi_opened = mode;
-
-  return 0;
-}
-
-static void
-sb16midi_close (int dev)
-{
-  sb16midi_opened = 0;
-}
-
-static int
-sb16midi_out (int dev, unsigned char midi_byte)
-{
-  int             timeout;
-  unsigned long   flags;
-
-  /*
-   * Test for input since pending input seems to block the output.
-   */
-
-  save_flags (flags);
-  cli ();
-
-  if (input_avail ())
-    sb16midi_input_loop ();
-
-  restore_flags (flags);
-
-  /*
-   * Sometimes it takes about 13000 loops before the output becomes ready
-   * (After reset). Normally it takes just about 10 loops.
-   */
-
-  for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);	/*
-									 * Wait
-									 */
-
-  if (!output_ready ())
-    {
-      printk ("MPU-401: Timeout\n");
-      return 0;
-    }
-
-  sb16midi_write (midi_byte);
-  return 1;
-}
-
-static int
-sb16midi_start_read (int dev)
-{
-  return 0;
-}
-
-static int
-sb16midi_end_read (int dev)
-{
-  return 0;
-}
-
-static int
-sb16midi_ioctl (int dev, unsigned cmd, caddr_t arg)
-{
-  return -EINVAL;
-}
-
-static void
-sb16midi_kick (int dev)
-{
-}
-
-static int
-sb16midi_buffer_status (int dev)
-{
-  return 0;			/*
-				 * No data in buffers
-				 */
-}
-
-#define MIDI_SYNTH_NAME	"SoundBlaster MPU"
-#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-static struct midi_operations sb16midi_operations =
-{
-  {"SoundBlaster MPU", 0, 0, SNDCARD_SB16MIDI},
-  &std_midi_synth,
-  {0},
-  sb16midi_open,
-  sb16midi_close,
-  sb16midi_ioctl,
-  sb16midi_out,
-  sb16midi_start_read,
-  sb16midi_end_read,
-  sb16midi_kick,
-  NULL,
-  sb16midi_buffer_status,
-  NULL
-};
-
-static void
-enter_uart_mode (void)
-{
-  int             ok, timeout;
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);
-
-  input_byte = 0;
-  sb16midi_cmd (UART_MODE_ON);
-
-  ok = 0;
-  for (timeout = 50000; timeout > 0 && !ok; timeout--)
-    if (input_byte == MPU_ACK)
-      ok = 1;
-    else if (input_avail ())
-      if (sb16midi_read () == MPU_ACK)
-	ok = 1;
-
-  restore_flags (flags);
-}
-
-long
-attach_sb16midi (long mem_start, struct address_info *hw_config)
-{
-  sb16midi_base = hw_config->io_base;
-
-  if (!sb16midi_detected)
-    return mem_start;
-
-  request_region (hw_config->io_base, 4, "SB MIDI");
-  enter_uart_mode ();
-
-  if (num_midis >= MAX_MIDI_DEV)
-    {
-      printk ("Sound: Too many midi devices detected\n");
-      return mem_start;
-    }
-
-  conf_printf ("SoundBlaster MPU-401", hw_config);
-
-  std_midi_synth.midi_dev = my_dev = num_midis;
-  midi_devs[num_midis++] = &sb16midi_operations;
-  return mem_start;
-}
-
-static int
-reset_sb16midi (void)
-{
-  int             ok, timeout, n;
-
-  /*
-   * Send the RESET command. Try again if no success at the first time.
-   */
-
-  ok = 0;
-
-  /*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
-				 */
-
-      /*
-       * Wait at least 25 msec. This method is not accurate so let's make the
-       * loop bit longer. Cannot sleep since this is called during boot.
-       */
-
-      for (timeout = 50000; timeout > 0 && !ok; timeout--)
-	if (input_byte == MPU_ACK)	/* Interrupt */
-	  ok = 1;
-	else if (input_avail ())
-	  if (sb16midi_read () == MPU_ACK)
-	    ok = 1;
-
-    }
-
-  sb16midi_opened = 0;
-  if (ok)
-    sb16midi_input_loop ();	/*
-				 * Flush input before enabling interrupts
-				 */
-
-  /* restore_flags(flags); */
-
-  return ok;
-}
-
-int
-probe_sb16midi (struct address_info *hw_config)
-{
-  int             ok = 0;
-  extern int      sbc_major;
-
-  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;
-
-  if (sb_get_irq () < 0)
-    return 0;
-
-  ok = reset_sb16midi ();
-
-  sb16midi_detected = ok;
-  return ok;
-}
-
-void
-unload_sb16midi (struct address_info *hw_config)
-{
-  release_region (hw_config->io_base, 4);
-}
-
-#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c
--- v2.0.0/linux/drivers/sound/sb_audio.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/sb_audio.c	Sun Jun 30 11:44:12 1996
@@ -0,0 +1,1202 @@
+/*
+ * sound/sb_audio.c
+ *
+ * Audio routines for SoundBlaster compatible cards.
+ */
+/*
+ * Copyright (C) by Hannu Savolainen 1993-1996
+ *
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+#include <linux/config.h>
+
+
+#include "sound_config.h"
+
+#if defined(CONFIG_SBDSP)
+
+#include "sb_mixer.h"
+#include "sb.h"
+
+static int
+sb_audio_open (int dev, int mode)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned long   flags;
+
+  if (devc == NULL)
+    {
+      printk ("SB: Incomplete initialization\n");
+      return -(ENXIO);
+    }
+
+  if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ)
+    {
+      printk ("SB: Recording is not possible with this device\n");
+      return -(EPERM);
+    }
+
+  save_flags (flags);
+  cli ();
+  if (devc->opened)
+    {
+      restore_flags (flags);
+      return -(EBUSY);
+    }
+
+  if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
+    {
+      if (sound_open_dma (devc->dma16, "Sound Blaster 16 bit"))
+	{
+	  return -(EBUSY);
+	}
+    }
+  devc->opened = mode;
+  restore_flags (flags);
+
+  devc->irq_mode = IMODE_NONE;
+  sb_dsp_reset (devc);
+
+  return 0;
+}
+
+static void
+sb_audio_close (int dev)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  audio_devs[dev]->dmachan1 =
+    audio_devs[dev]->dmachan2 =
+    devc->dma8;
+
+  if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
+    sound_close_dma (devc->dma16);
+
+  devc->opened = 0;
+}
+
+static void
+sb_set_output_parms (int dev, unsigned long buf, int nr_bytes,
+		     int intrflag, int restart_dma)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  devc->trg_buf = buf;
+  devc->trg_bytes = nr_bytes;
+  devc->trg_intrflag = intrflag;
+  devc->trg_restart = restart_dma;
+  devc->irq_mode = IMODE_OUTPUT;
+}
+
+static void
+sb_set_input_parms (int dev, unsigned long buf, int count, int intrflag,
+		    int restart_dma)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  devc->trg_buf = buf;
+  devc->trg_bytes = count;
+  devc->trg_intrflag = intrflag;
+  devc->trg_restart = restart_dma;
+  devc->irq_mode = IMODE_INPUT;
+}
+
+/*
+ * SB1.x compatible routines 
+ */
+
+static void
+sb1_audio_output_block (int dev, unsigned long buf, int nr_bytes,
+			int intrflag, int restart_dma)
+{
+  unsigned long   flags;
+  int             count = nr_bytes;
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+
+  if (audio_devs[dev]->dmachan1 > 3)
+    count >>= 1;
+  count--;
+
+  devc->irq_mode = IMODE_OUTPUT;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x14))	/* 8 bit DAC using DMA */
+    {
+      sb_dsp_command (devc, (unsigned char) (count & 0xff));
+      sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff));
+    }
+  else
+    printk ("SB: Unable to start DAC\n");
+  restore_flags (flags);
+  devc->intr_active = 1;
+}
+
+static void
+sb1_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag,
+		       int restart_dma)
+{
+  unsigned long   flags;
+  int             count = nr_bytes;
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  /*
+   * Start a DMA input to the buffer pointed by dmaqtail
+   */
+
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+
+  if (audio_devs[dev]->dmachan1 > 3)
+    count >>= 1;
+  count--;
+
+  devc->irq_mode = IMODE_INPUT;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x24))	/* 8 bit ADC using DMA */
+    {
+      sb_dsp_command (devc, (unsigned char) (count & 0xff));
+      sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff));
+    }
+  else
+    printk ("SB Error: Unable to start ADC\n");
+  restore_flags (flags);
+
+  devc->intr_active = 1;
+}
+
+static void
+sb1_audio_trigger (int dev, int bits)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  bits &= devc->irq_mode;
+
+  if (!bits)
+    sb_dsp_command (devc, 0xd0);	/* Halt DMA */
+  else
+    {
+      switch (devc->irq_mode)
+	{
+	case IMODE_INPUT:
+	  sb1_audio_start_input (dev, devc->trg_buf, devc->trg_bytes,
+				 devc->trg_intrflag, devc->trg_restart);
+	  break;
+
+	case IMODE_OUTPUT:
+	  sb1_audio_output_block (dev, devc->trg_buf, devc->trg_bytes,
+				  devc->trg_intrflag, devc->trg_restart);
+	  break;
+	}
+    }
+
+  devc->trigger_bits = bits;
+}
+
+static int
+sb1_audio_prepare_for_input (int dev, int bsize, int bcount)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned long   flags;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x40))
+    sb_dsp_command (devc, devc->tconst);
+  sb_dsp_command (devc, DSP_CMD_SPKOFF);
+  restore_flags (flags);
+
+  devc->trigger_bits = 0;
+  return 0;
+}
+
+static int
+sb1_audio_prepare_for_output (int dev, int bsize, int bcount)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned long   flags;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x40))
+    sb_dsp_command (devc, devc->tconst);
+  sb_dsp_command (devc, DSP_CMD_SPKON);
+  restore_flags (flags);
+  devc->trigger_bits = 0;
+  return 0;
+}
+
+static int
+sb1_audio_set_speed (int dev, int speed)
+{
+  int             max_speed = 23000;
+  sb_devc        *devc = audio_devs[dev]->devc;
+  int             tmp;
+
+  if (devc->opened & OPEN_READ)
+    max_speed = 13000;
+
+  if (speed > 0)
+    {
+      if (speed < 4000)
+	speed = 4000;
+
+      if (speed > max_speed)
+	speed = max_speed;
+
+      devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
+
+      tmp = 256 - devc->tconst;
+      speed = (1000000 + tmp / 2) / tmp;
+
+      devc->speed = speed;
+    }
+
+  return devc->speed;
+}
+
+static short
+sb1_audio_set_channels (int dev, short channels)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  return devc->channels = 1;
+}
+
+static unsigned int
+sb1_audio_set_bits (int dev, unsigned int bits)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  return devc->bits = 8;
+}
+
+static void
+sb1_audio_halt_xfer (int dev)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  sb_dsp_reset (devc);
+}
+
+/*
+ * SB 2.0 and SB 2.01 compatible routines
+ */
+
+static void
+sb20_audio_output_block (int dev, unsigned long buf, int nr_bytes,
+			 int intrflag, int restart_dma)
+{
+  unsigned long   flags;
+  int             count = nr_bytes;
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned char   cmd;
+
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+
+  if (audio_devs[dev]->dmachan1 > 3)
+    count >>= 1;
+  count--;
+
+  devc->irq_mode = IMODE_OUTPUT;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x48))	/* DSP Block size */
+    {
+      sb_dsp_command (devc, (unsigned char) (count & 0xff));
+      sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff));
+
+      if (devc->speed * devc->channels <= 23000)
+	cmd = 0x1c;		/* 8 bit PCM output */
+      else
+	cmd = 0x90;		/* 8 bit high speed PCM output (SB2.01/Pro) */
+
+      if (!sb_dsp_command (devc, cmd))
+	printk ("SB: Unable to start DAC\n");
+
+    }
+  else
+    printk ("SB: Unable to start DAC\n");
+  restore_flags (flags);
+  devc->intr_active = 1;
+}
+
+static void
+sb20_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag,
+			int restart_dma)
+{
+  unsigned long   flags;
+  int             count = nr_bytes;
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned char   cmd;
+
+  /*
+   * Start a DMA input to the buffer pointed by dmaqtail
+   */
+
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+
+  if (audio_devs[dev]->dmachan1 > 3)
+    count >>= 1;
+  count--;
+
+  devc->irq_mode = IMODE_INPUT;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x48))	/* DSP Block size */
+    {
+      sb_dsp_command (devc, (unsigned char) (count & 0xff));
+      sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff));
+
+      if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000))
+	cmd = 0x2c;		/* 8 bit PCM input */
+      else
+	cmd = 0x98;		/* 8 bit high speed PCM input (SB2.01/Pro) */
+
+      if (!sb_dsp_command (devc, cmd))
+	printk ("SB: Unable to start ADC\n");
+    }
+  else
+    printk ("SB Error: Unable to start ADC\n");
+  restore_flags (flags);
+
+  devc->intr_active = 1;
+}
+
+static void
+sb20_audio_trigger (int dev, int bits)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  bits &= devc->irq_mode;
+
+  if (!bits)
+    sb_dsp_command (devc, 0xd0);	/* Halt DMA */
+  else
+    {
+      switch (devc->irq_mode)
+	{
+	case IMODE_INPUT:
+	  sb20_audio_start_input (dev, devc->trg_buf, devc->trg_bytes,
+				  devc->trg_intrflag, devc->trg_restart);
+	  break;
+
+	case IMODE_OUTPUT:
+	  sb20_audio_output_block (dev, devc->trg_buf, devc->trg_bytes,
+				   devc->trg_intrflag, devc->trg_restart);
+	  break;
+	}
+    }
+
+  devc->trigger_bits = bits;
+}
+
+/*
+ * SB2.01 spesific speed setup
+ */
+
+static int
+sb201_audio_set_speed (int dev, int speed)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+  int             tmp;
+  int             s = speed * devc->channels;
+
+  if (speed > 0)
+    {
+      if (speed < 4000)
+	speed = 4000;
+
+      if (speed > 44100)
+	speed = 44100;
+
+      if (devc->opened & OPEN_READ && speed > 15000)
+	speed = 15000;
+
+      devc->tconst = ((65536 - ((256000000 + s / 2) /
+				s)) >> 8) & 0xff;
+
+      tmp = 256 - devc->tconst;
+      speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
+
+      devc->speed = speed;
+    }
+
+  return devc->speed;
+}
+
+/*
+ * SB Pro spesific routines
+ */
+
+static int
+sbpro_audio_prepare_for_input (int dev, int bsize, int bcount)
+{				/* For SB Pro and Jazz16 */
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned long   flags;
+  unsigned char   bits = 0;
+
+  if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
+    audio_devs[dev]->dmachan1 =
+      audio_devs[dev]->dmachan2 =
+      devc->bits == 16 ? devc->dma16 : devc->dma8;
+
+  if (devc->model == MDL_JAZZ || devc->model == MDL_SMW)
+    if (devc->bits == AFMT_S16_LE)
+      bits = 0x04;		/* 16 bit mode */
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x40))
+    sb_dsp_command (devc, devc->tconst);
+  sb_dsp_command (devc, DSP_CMD_SPKOFF);
+  if (devc->channels == 1)
+    sb_dsp_command (devc, 0xa0 | bits);		/* Mono input */
+  else
+    sb_dsp_command (devc, 0xa8 | bits);		/* Stereo input */
+  restore_flags (flags);
+
+  devc->trigger_bits = 0;
+  return 0;
+}
+
+static int
+sbpro_audio_prepare_for_output (int dev, int bsize, int bcount)
+{				/* For SB Pro and Jazz16 */
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned long   flags;
+  unsigned char   tmp;
+  unsigned char   bits = 0;
+
+  if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
+    audio_devs[dev]->dmachan1 =
+      audio_devs[dev]->dmachan2 =
+      devc->bits == 16 ? devc->dma16 : devc->dma8;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x40))
+    sb_dsp_command (devc, devc->tconst);
+  sb_dsp_command (devc, DSP_CMD_SPKON);
+
+  if (devc->model == MDL_JAZZ || devc->model == MDL_SMW)
+    {
+      if (devc->bits == AFMT_S16_LE)
+	bits = 0x04;		/* 16 bit mode */
+
+      if (devc->channels == 1)
+	sb_dsp_command (devc, 0xa0 | bits);	/* Mono output */
+      else
+	sb_dsp_command (devc, 0xa8 | bits);	/* Stereo output */
+    }
+  else
+    {
+      tmp = sb_getmixer (devc, 0x0e);
+      if (devc->channels == 1)
+	tmp &= ~0x20;
+      else
+	tmp |= 0x20;
+      sb_setmixer (devc, 0x0e, tmp);
+    }
+  restore_flags (flags);
+  devc->trigger_bits = 0;
+  return 0;
+}
+
+static int
+sbpro_audio_set_speed (int dev, int speed)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  if (speed > 0)
+    {
+      if (speed < 4000)
+	speed = 4000;
+
+      if (speed > 44100)
+	speed = 44100;
+
+      if (devc->channels > 1 && speed > 22050)
+	speed = 22050;
+
+      sb201_audio_set_speed (dev, speed);
+    }
+
+  return devc->speed;
+}
+
+static short
+sbpro_audio_set_channels (int dev, short channels)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  if (channels == 1 || channels == 2)
+    if (channels != devc->channels)
+      {
+	devc->channels = channels;
+	sbpro_audio_set_speed (dev, devc->speed);
+      }
+  return devc->channels;
+}
+
+static int
+jazz16_audio_set_speed (int dev, int speed)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  if (speed > 0)
+    {
+      int             tmp;
+      int             s = speed * devc->channels;
+
+      if (speed < 5000)
+	speed = 4000;
+
+      if (speed > 44100)
+	speed = 44100;
+
+      devc->tconst = ((65536 - ((256000000 + s / 2) /
+				s)) >> 8) & 0xff;
+
+      tmp = 256 - devc->tconst;
+      speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
+
+      devc->speed = speed;
+    }
+
+  return devc->speed;
+}
+
+/*
+ * ESS spesific routines
+ */
+
+static void
+ess_speed (sb_devc * devc)
+{
+  int             divider;
+  unsigned char   bits = 0;
+  int             speed = devc->speed;
+
+  if (speed < 4000)
+    speed = 4000;
+  else if (speed > 48000)
+    speed = 48000;
+
+  if (speed > 22000)
+    {
+      bits = 0x80;
+      divider = 256 - (795500 + speed / 2) / speed;
+    }
+  else
+    {
+      divider = 128 - (397700 + speed / 2) / speed;
+    }
+
+  bits |= (unsigned char) divider;
+  ess_write (devc, 0xa1, bits);
+
+/*
+ * Set filter divider register
+ */
+
+  speed = (speed * 9) / 20;	/* Set filter rolloff to 90% of speed/2 */
+  divider = 256 - 7160000 / (speed * 82);
+  ess_write (devc, 0xa2, divider);
+
+  return;
+}
+
+static int
+ess_audio_prepare_for_input (int dev, int bsize, int bcount)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  ess_speed (devc);
+  sb_dsp_command (devc, DSP_CMD_SPKOFF);
+
+  ess_write (devc, 0xb8, 0x0e);	/* Auto init DMA mode */
+  ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) |
+	     (3 - devc->channels));	/* Mono/stereo */
+  ess_write (devc, 0xb9, 2);	/* Demand mode (4 bytes/DMA request) */
+
+  if (devc->channels == 1)
+    {
+      if (devc->bits == AFMT_U8 == 0)
+	{			/* 8 bit mono */
+	  ess_write (devc, 0xb7, 0x51);
+	  ess_write (devc, 0xb7, 0xd0);
+	}
+      else
+	{			/* 16 bit mono */
+	  ess_write (devc, 0xb7, 0x71);
+	  ess_write (devc, 0xb7, 0xf4);
+	}
+    }
+  else
+    {				/* Stereo */
+      if (devc->bits == AFMT_U8)
+	{			/* 8 bit stereo */
+	  ess_write (devc, 0xb7, 0x51);
+	  ess_write (devc, 0xb7, 0x98);
+	}
+      else
+	{			/* 16 bit stereo */
+	  ess_write (devc, 0xb7, 0x71);
+	  ess_write (devc, 0xb7, 0xbc);
+	}
+    }
+
+  ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50);
+  ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50);
+
+  devc->trigger_bits = 0;
+  return 0;
+}
+
+static int
+ess_audio_prepare_for_output (int dev, int bsize, int bcount)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  sb_dsp_reset (devc);
+  ess_speed (devc);
+
+  ess_write (devc, 0xb8, 4);	/* Auto init DMA mode */
+  ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) |
+	     (3 - devc->channels));	/* Mono/stereo */
+  ess_write (devc, 0xb9, 2);	/* Demand mode (4 bytes/request) */
+
+  if (devc->channels == 1)
+    {
+      if (devc->bits == AFMT_U8)
+	{			/* 8 bit mono */
+	  ess_write (devc, 0xb6, 0x80);
+	  ess_write (devc, 0xb7, 0x51);
+	  ess_write (devc, 0xb7, 0xd0);
+	}
+      else
+	{			/* 16 bit mono */
+	  ess_write (devc, 0xb6, 0x00);
+	  ess_write (devc, 0xb7, 0x71);
+	  ess_write (devc, 0xb7, 0xf4);
+	}
+    }
+  else
+    {				/* Stereo */
+      if (devc->bits == AFMT_U8)
+	{			/* 8 bit stereo */
+	  ess_write (devc, 0xb6, 0x80);
+	  ess_write (devc, 0xb7, 0x51);
+	  ess_write (devc, 0xb7, 0x98);
+	}
+      else
+	{			/* 16 bit stereo */
+	  ess_write (devc, 0xb6, 0x00);
+	  ess_write (devc, 0xb7, 0x71);
+	  ess_write (devc, 0xb7, 0xbc);
+	}
+    }
+
+  ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50);
+  ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50);
+  sb_dsp_command (devc, DSP_CMD_SPKON);
+
+  devc->trigger_bits = 0;
+  return 0;
+}
+
+static void
+ess_audio_output_block (int dev, unsigned long buf, int nr_bytes,
+			int intrflag, int restart_dma)
+{
+  int             count = nr_bytes;
+  sb_devc        *devc = audio_devs[dev]->devc;
+  short           c = -nr_bytes;
+
+  if (!restart_dma)
+    return;
+
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+
+  if (audio_devs[dev]->dmachan1 > 3)
+    count >>= 1;
+  count--;
+
+  devc->irq_mode = IMODE_OUTPUT;
+
+  ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
+  ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+
+  ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x05);		/* Go */
+  devc->intr_active = 1;
+}
+
+static void
+ess_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag,
+		       int restart_dma)
+{
+  int             count = nr_bytes;
+  sb_devc        *devc = audio_devs[dev]->devc;
+  short           c = -nr_bytes;
+
+  if (!restart_dma)
+    return;
+
+  /*
+   * Start a DMA input to the buffer pointed by dmaqtail
+   */
+
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+
+  if (audio_devs[dev]->dmachan1 > 3)
+    count >>= 1;
+  count--;
+
+  devc->irq_mode = IMODE_INPUT;
+
+  ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff));
+  ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
+
+  ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x0f);		/* Go */
+  devc->intr_active = 1;
+}
+
+static void
+ess_audio_trigger (int dev, int bits)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  bits &= devc->irq_mode;
+
+  if (!bits)
+    sb_dsp_command (devc, 0xd0);	/* Halt DMA */
+  else
+    {
+      switch (devc->irq_mode)
+	{
+	case IMODE_INPUT:
+	  ess_audio_start_input (dev, devc->trg_buf, devc->trg_bytes,
+				 devc->trg_intrflag, devc->trg_restart);
+	  break;
+
+	case IMODE_OUTPUT:
+	  ess_audio_output_block (dev, devc->trg_buf, devc->trg_bytes,
+				  devc->trg_intrflag, devc->trg_restart);
+	  break;
+	}
+    }
+
+  devc->trigger_bits = bits;
+}
+
+/*
+ * SB16 spesific routines
+ */
+
+static int
+sb16_audio_set_speed (int dev, int speed)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  if (speed > 0)
+    {
+      if (speed < 5000)
+	speed = 4000;
+
+      if (speed > 44100)
+	speed = 44100;
+
+      devc->speed = speed;
+    }
+
+  return devc->speed;
+}
+
+static unsigned int
+sb16_audio_set_bits (int dev, unsigned int bits)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  if (bits != 0)
+    if (devc->bits == AFMT_U8 || bits == AFMT_S16_LE)
+      devc->bits = bits;
+    else
+      devc->bits = AFMT_U8;
+
+  return devc->bits;
+}
+
+static int
+sb16_audio_prepare_for_input (int dev, int bsize, int bcount)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  audio_devs[dev]->dmachan1 =
+    audio_devs[dev]->dmachan2 =
+    devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
+
+  devc->trigger_bits = 0;
+  return 0;
+}
+
+static int
+sb16_audio_prepare_for_output (int dev, int bsize, int bcount)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  audio_devs[dev]->dmachan1 =
+    audio_devs[dev]->dmachan2 =
+    devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
+
+  devc->trigger_bits = 0;
+  return 0;
+}
+
+static void
+sb16_audio_output_block (int dev, unsigned long buf, int count,
+			 int intrflag, int restart_dma)
+{
+  unsigned long   flags, cnt;
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  devc->irq_mode = IMODE_OUTPUT;
+  devc->intr_active = 1;
+
+  if (!restart_dma)
+    return;
+
+  cnt = count;
+  if (devc->bits == AFMT_S16_LE)
+    cnt >>= 1;
+  cnt--;
+
+  save_flags (flags);
+  cli ();
+
+  if (restart_dma)
+    DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+
+  sb_dsp_command (devc, 0x41);
+  sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff));
+  sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff));
+
+  sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6));
+  sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) +
+			 (devc->bits == AFMT_S16_LE ? 0x10 : 0)));
+  sb_dsp_command (devc, (unsigned char) (cnt & 0xff));
+  sb_dsp_command (devc, (unsigned char) (cnt >> 8));
+
+  restore_flags (flags);
+}
+
+static void
+sb16_audio_start_input (int dev, unsigned long buf, int count, int intrflag,
+			int restart_dma)
+{
+  unsigned long   flags, cnt;
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  devc->irq_mode = IMODE_INPUT;
+  devc->intr_active = 1;
+
+  if (!restart_dma)
+    return;
+
+  cnt = count;
+  if (devc->bits == AFMT_S16_LE)
+    cnt >>= 1;
+  cnt--;
+
+  save_flags (flags);
+  cli ();
+
+  if (restart_dma)
+    DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+
+  sb_dsp_command (devc, 0x42);
+  sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff));
+  sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff));
+
+  sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce));
+  sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) +
+			 (devc->bits == AFMT_S16_LE ? 0x10 : 0)));
+  sb_dsp_command (devc, (unsigned char) (cnt & 0xff));
+  sb_dsp_command (devc, (unsigned char) (cnt >> 8));
+
+  restore_flags (flags);
+}
+
+static void
+sb16_audio_trigger (int dev, int bits)
+{
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  bits &= devc->irq_mode;
+
+  if (!bits)
+    sb_dsp_command (devc, 0xd0);	/* Halt DMA */
+  else
+    {
+      switch (devc->irq_mode)
+	{
+	case IMODE_INPUT:
+	  sb16_audio_start_input (dev, devc->trg_buf, devc->trg_bytes,
+				  devc->trg_intrflag, devc->trg_restart);
+	  break;
+
+	case IMODE_OUTPUT:
+	  sb16_audio_output_block (dev, devc->trg_buf, devc->trg_bytes,
+				   devc->trg_intrflag, devc->trg_restart);
+	  break;
+	}
+    }
+
+  devc->trigger_bits = bits;
+}
+
+static int
+sb_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
+{
+  return -(EINVAL);
+}
+
+static void
+sb_audio_reset (int dev)
+{
+  unsigned long   flags;
+  sb_devc        *devc = audio_devs[dev]->devc;
+
+  save_flags (flags);
+  cli ();
+  sb_dsp_reset (devc);
+  restore_flags (flags);
+}
+
+static struct audio_driver sb1_audio_driver =	/* SB1.x */
+{
+  sb_audio_open,
+  sb_audio_close,
+  sb_set_output_parms,
+  sb_set_input_parms,
+  sb_audio_ioctl,
+  sb1_audio_prepare_for_input,
+  sb1_audio_prepare_for_output,
+  sb_audio_reset,
+  sb1_audio_halt_xfer,
+  NULL,				/* local_qlen */
+  NULL,				/* copy_from_user */
+  NULL,
+  NULL,
+  sb1_audio_trigger,
+  sb1_audio_set_speed,
+  sb1_audio_set_bits,
+  sb1_audio_set_channels
+};
+
+static struct audio_driver sb20_audio_driver =	/* SB2.0 */
+{
+  sb_audio_open,
+  sb_audio_close,
+  sb_set_output_parms,
+  sb_set_input_parms,
+  sb_audio_ioctl,
+  sb1_audio_prepare_for_input,
+  sb1_audio_prepare_for_output,
+  sb_audio_reset,
+  sb1_audio_halt_xfer,
+  NULL,				/* local_qlen */
+  NULL,				/* copy_from_user */
+  NULL,
+  NULL,
+  sb20_audio_trigger,
+  sb1_audio_set_speed,
+  sb1_audio_set_bits,
+  sb1_audio_set_channels
+};
+
+static struct audio_driver sb201_audio_driver =		/* SB2.01 */
+{
+  sb_audio_open,
+  sb_audio_close,
+  sb_set_output_parms,
+  sb_set_input_parms,
+  sb_audio_ioctl,
+  sb1_audio_prepare_for_input,
+  sb1_audio_prepare_for_output,
+  sb_audio_reset,
+  sb1_audio_halt_xfer,
+  NULL,				/* local_qlen */
+  NULL,				/* copy_from_user */
+  NULL,
+  NULL,
+  sb20_audio_trigger,
+  sb201_audio_set_speed,
+  sb1_audio_set_bits,
+  sb1_audio_set_channels
+};
+
+static struct audio_driver sbpro_audio_driver =		/* SB Pro */
+{
+  sb_audio_open,
+  sb_audio_close,
+  sb_set_output_parms,
+  sb_set_input_parms,
+  sb_audio_ioctl,
+  sbpro_audio_prepare_for_input,
+  sbpro_audio_prepare_for_output,
+  sb_audio_reset,
+  sb1_audio_halt_xfer,
+  NULL,				/* local_qlen */
+  NULL,				/* copy_from_user */
+  NULL,
+  NULL,
+  sb20_audio_trigger,
+  sbpro_audio_set_speed,
+  sb1_audio_set_bits,
+  sbpro_audio_set_channels
+};
+
+static struct audio_driver jazz16_audio_driver =	/* Jazz16 and SM Wave */
+{
+  sb_audio_open,
+  sb_audio_close,
+  sb_set_output_parms,
+  sb_set_input_parms,
+  sb_audio_ioctl,
+  sbpro_audio_prepare_for_input,
+  sbpro_audio_prepare_for_output,
+  sb_audio_reset,
+  sb1_audio_halt_xfer,
+  NULL,				/* local_qlen */
+  NULL,				/* copy_from_user */
+  NULL,
+  NULL,
+  sb20_audio_trigger,
+  jazz16_audio_set_speed,
+  sb16_audio_set_bits,
+  sbpro_audio_set_channels
+};
+
+static struct audio_driver sb16_audio_driver =	/* SB16 */
+{
+  sb_audio_open,
+  sb_audio_close,
+  sb_set_output_parms,
+  sb_set_input_parms,
+  sb_audio_ioctl,
+  sb16_audio_prepare_for_input,
+  sb16_audio_prepare_for_output,
+  sb_audio_reset,
+  sb1_audio_halt_xfer,
+  NULL,				/* local_qlen */
+  NULL,				/* copy_from_user */
+  NULL,
+  NULL,
+  sb16_audio_trigger,
+  sb16_audio_set_speed,
+  sb16_audio_set_bits,
+  sbpro_audio_set_channels
+};
+
+static struct audio_driver ess_audio_driver =	/* ESS ES688/1688 */
+{
+  sb_audio_open,
+  sb_audio_close,
+  sb_set_output_parms,
+  sb_set_input_parms,
+  sb_audio_ioctl,
+  ess_audio_prepare_for_input,
+  ess_audio_prepare_for_output,
+  sb_audio_reset,
+  sb1_audio_halt_xfer,
+  NULL,				/* local_qlen */
+  NULL,				/* copy_from_user */
+  NULL,
+  NULL,
+  ess_audio_trigger,
+  sb16_audio_set_speed,
+  sb16_audio_set_bits,
+  sbpro_audio_set_channels
+};
+
+void
+sb_audio_init (sb_devc * devc, char *name)
+{
+  int             audio_flags = 0;
+  int             format_mask = AFMT_U8;
+
+  struct audio_driver *driver = &sb1_audio_driver;
+
+  switch (devc->model)
+    {
+    case MDL_SB1:		/* SB1.0 or SB 1.5 */
+      DDB (printk ("Will use standard SB1.x driver\n"));
+      audio_flags = DMA_HARDSTOP;
+      break;
+
+    case MDL_SB2:
+      DDB (printk ("Will use SB2.0 driver\n"));
+      audio_flags = DMA_AUTOMODE;
+      driver = &sb20_audio_driver;
+      break;
+
+    case MDL_SB201:
+      DDB (printk ("Will use SB2.01 (high speed) driver\n"));
+      audio_flags = DMA_AUTOMODE;
+      driver = &sb201_audio_driver;
+      break;
+
+    case MDL_JAZZ:
+    case MDL_SMW:
+      DDB (printk ("Will use Jazz16 driver\n"));
+      audio_flags = DMA_AUTOMODE;
+      format_mask |= AFMT_S16_LE;
+      driver = &jazz16_audio_driver;
+      break;
+
+    case MDL_ESS:
+      DDB (printk ("Will use ESS ES688/1688 driver\n"));
+      audio_flags = DMA_AUTOMODE;
+      format_mask |= AFMT_S16_LE;
+      driver = &ess_audio_driver;
+      break;
+
+    case MDL_SB16:
+      DDB (printk ("Will use SB16 driver\n"));
+      audio_flags = DMA_AUTOMODE;
+      format_mask |= AFMT_S16_LE;
+      driver = &sb16_audio_driver;
+      break;
+
+    default:
+      DDB (printk ("Will use SB Pro driver\n"));
+      audio_flags = DMA_AUTOMODE;
+      driver = &sbpro_audio_driver;
+    }
+
+  if ((devc->my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION,
+					      name,
+					      driver,
+					      sizeof (struct audio_driver),
+					      audio_flags,
+					      format_mask,
+					      devc,
+					      devc->dma8,
+					      devc->dma8)) < 0)
+    {
+      return;
+    }
+
+  audio_devs[devc->my_dev]->mixer_dev = devc->my_mixerdev;
+  audio_devs[devc->my_dev]->min_fragment = 5;
+}
+
+#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.0.0/linux/drivers/sound/sb_card.c	Sun Mar 24 22:50:18 1996
+++ linux/drivers/sound/sb_card.c	Sun Jun 30 11:44:12 1996
@@ -4,27 +4,11 @@
  * Detection routine for the SoundBlaster cards.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -33,19 +17,15 @@
 
 #if defined(CONFIG_SB)
 
+#include "sb_mixer.h"
 #include "sb.h"
 
-long
-attach_sb_card (long mem_start, struct address_info *hw_config)
+void
+attach_sb_card (struct address_info *hw_config)
 {
 #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, "SoundBlaster");
+  sb_dsp_init (hw_config);
 #endif
-
-  return mem_start;
 }
 
 int
@@ -64,7 +44,6 @@
 void
 unload_sb (struct address_info *hw_config)
 {
-  release_region (hw_config->io_base, 16);
   sb_dsp_unload (hw_config);
 }
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.0.0/linux/drivers/sound/sb_common.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/sb_common.c	Sun Jun 30 11:44:13 1996
@@ -0,0 +1,1207 @@
+/*
+ * sound/sb_common.c
+ *
+ * Common routines for SoundBlaster compatible cards.
+ */
+/*
+ * Copyright (C) by Hannu Savolainen 1993-1996
+ *
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+#include <linux/config.h>
+
+
+#include "sound_config.h"
+
+#if defined(CONFIG_SBDSP)
+
+#ifndef CONFIG_AUDIO
+#error You will need to configure the sound driver with CONFIG_AUDIO option.
+#endif
+
+#include "sb_mixer.h"
+#include "sb.h"
+
+static sb_devc *detected_devc = NULL;	/* For communication from probe to init */
+static sb_devc *last_devc = NULL;	/* For MPU401 initalization */
+static sb_devc *irq2devc[16] =
+{NULL};
+static unsigned char jazz_irq_bits[] =
+{0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6};
+static unsigned char jazz_dma_bits[] =
+{0, 1, 0, 2, 0, 3, 0, 4};
+
+/*
+ * Jazz16 chipset spesific control variables
+ */
+
+static int      jazz16_base = 0;	/* Not detected */
+static unsigned char jazz16_bits = 0;	/* I/O relocation bits */
+
+/*
+ * Logitech Soundman Wave spesific initialization code
+ */
+
+#ifdef SMW_MIDI0001_INCLUDED
+#include "smw-midi0001.h"
+#else
+unsigned char  *smw_ucode = NULL;
+int             smw_ucodeLen = 0;
+
+#endif
+
+int
+sb_dsp_command (sb_devc * devc, unsigned char val)
+{
+  int             i;
+  unsigned long   limit;
+
+  limit = jiffies + HZ / 10;	/*
+				   * The timeout is 0.1 secods
+				 */
+
+  /*
+   * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
+   * called while interrupts are disabled. This means that the timer is
+   * disabled also. However the timeout situation is a abnormal condition.
+   * Normally the DSP should be ready to accept commands after just couple of
+   * loops.
+   */
+
+  for (i = 0; i < 500000 && jiffies < limit; i++)
+    {
+      if ((inb (DSP_STATUS) & 0x80) == 0)
+	{
+	  outb (val, DSP_COMMAND);
+	  return 1;
+	}
+    }
+
+  printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val);
+  return 0;
+}
+
+int
+sb_dsp_get_byte (sb_devc * devc)
+{
+  int             i;
+
+  for (i = 1000; i; i--)
+    if (inb (DSP_DATA_AVAIL) & 0x80)
+      {
+	return inb (DSP_READ);
+      }
+
+  return 0xffff;
+}
+
+int
+ess_write (sb_devc * devc, unsigned char reg, unsigned char data)
+{
+  /* Write a byte to an extended mode register of ES1688 */
+
+  if (!sb_dsp_command (devc, reg))
+    return 0;
+
+  return sb_dsp_command (devc, data);
+}
+
+int
+ess_read (sb_devc * devc, unsigned char reg)
+{
+/* Read a byte from an extended mode register of ES1688 */
+
+  if (!sb_dsp_command (devc, 0xc0))	/* Read register command */
+    return -1;
+
+  if (!sb_dsp_command (devc, reg))
+    return -1;
+
+  return sb_dsp_get_byte (devc);
+}
+
+void
+sbintr (int irq, void *dev_id, struct pt_regs *dummy)
+{
+  int             status;
+  unsigned char   src = 0xff;
+
+  sb_devc        *devc = irq2devc[irq];
+
+  devc->irq_ok = 1;
+
+  if (devc == NULL || devc->irq != irq)
+    {
+      DEB (printk ("sbintr: Bogus interrupt IRQ%d\n", irq));
+      return;
+    }
+
+  if (devc->model == MDL_SB16)
+    {
+
+      src = sb_getmixer (devc, IRQ_STAT);	/* Interrupt source register */
+
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
+      if (src & 4)
+	uart401intr (devc->irq, NULL, NULL);	/* MPU401 interrupt */
+#endif
+
+      if (!(src & 3))
+	return;			/* Not a DSP interrupt */
+    }
+
+  if (devc->intr_active)
+    switch (devc->irq_mode)
+      {
+      case IMODE_OUTPUT:
+	DMAbuf_outputintr (devc->dev, 1);
+	break;
+
+      case IMODE_INPUT:
+	DMAbuf_inputintr (devc->dev);
+	break;
+
+      case IMODE_INIT:
+	break;
+
+      case IMODE_MIDI:
+#ifdef CONFIG_MIDI
+	sb_midi_interrupt (devc);
+#endif
+	break;
+
+      default:
+	printk ("SoundBlaster: Unexpected interrupt\n");
+      }
+/*
+ * Acknowledge interrupts 
+ */
+
+  if (src & 0x01)
+    status = inb (DSP_DATA_AVAIL);
+
+  if (devc->model == MDL_SB16 && src & 0x02)
+    status = inb (DSP_DATA_AVL16);
+}
+
+int
+sb_dsp_reset (sb_devc * devc)
+{
+  int             loopc;
+
+  if (devc->model == MDL_ESS)
+    outb (3, DSP_RESET);	/* Reset FIFO too */
+  else
+    outb (1, DSP_RESET);
+
+  tenmicrosec (devc->osp);
+  outb (0, DSP_RESET);
+  tenmicrosec (devc->osp);
+  tenmicrosec (devc->osp);
+  tenmicrosec (devc->osp);
+
+  for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++);
+
+  if (inb (DSP_READ) != 0xAA)
+    return 0;			/* Sorry */
+
+  if (devc->model == MDL_ESS)
+    sb_dsp_command (devc, 0xc6);	/* Enable extended mode */
+
+  return 1;
+}
+
+static void
+dsp_get_vers (sb_devc * devc)
+{
+  int             i;
+
+  unsigned long   flags;
+
+  save_flags (flags);
+  cli ();
+  devc->major = devc->minor = 0;
+  sb_dsp_command (devc, 0xe1);	/* Get version */
+
+  for (i = 100000; i; i--)
+    {
+      if (inb (DSP_DATA_AVAIL) & 0x80)
+	{
+	  if (devc->major == 0)
+	    devc->major = inb (DSP_READ);
+	  else
+	    {
+	      devc->minor = inb (DSP_READ);
+	      break;
+	    }
+	}
+    }
+  restore_flags (flags);
+}
+
+static int
+sb16_set_dma_hw (sb_devc * devc)
+{
+  int             bits;
+
+  if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3)
+    {
+      printk ("SB16: Invalid 8 bit DMA (%d)\n", devc->dma8);
+      return 0;
+    }
+
+  bits = (1 << devc->dma8);
+
+  if (devc->dma16 >= 5 && devc->dma16 <= 7)
+    bits |= (1 << devc->dma16);
+
+  sb_setmixer (devc, DMA_NR, bits);
+  return 1;
+}
+
+static int
+sb16_set_irq_hw (sb_devc * devc, int level)
+{
+  int             ival;
+
+  switch (level)
+    {
+    case 5:
+      ival = 2;
+      break;
+    case 7:
+      ival = 4;
+      break;
+    case 9:
+      ival = 1;
+      break;
+    case 10:
+      ival = 8;
+      break;
+    default:
+      printk ("SB16 IRQ%d is not possible\n", level);
+      return 0;
+    }
+  sb_setmixer (devc, IRQ_NR, ival);
+  return 1;
+}
+
+static void
+relocate_Jazz16 (sb_devc * devc, struct address_info *hw_config)
+{
+  unsigned char   bits = 0;
+  unsigned long   flags;
+
+  if (jazz16_base != 0 && jazz16_base != hw_config->io_base)
+    return;
+
+  switch (hw_config->io_base)
+    {
+    case 0x220:
+      bits = 1;
+      break;
+    case 0x240:
+      bits = 2;
+      break;
+    case 0x260:
+      bits = 3;
+      break;
+
+    default:
+      return;
+    }
+
+  bits = jazz16_bits = bits << 5;
+
+  jazz16_base = hw_config->io_base;
+
+/*
+ * Magic wake up sequence by writing to 0x201 (aka Joystick port)
+ */
+  save_flags (flags);
+  cli ();
+  outb (0xAF, 0x201);
+  outb (0x50, 0x201);
+  outb (bits, 0x201);
+  restore_flags (flags);
+}
+
+static int
+init_Jazz16 (sb_devc * devc, struct address_info *hw_config)
+{
+  char            name[100];
+
+/*
+ * First try to check that the card has Jazz16 chip. It identifies itself
+ * by returning 0x12 as response to DSP command 0xfa.
+ */
+
+  if (!sb_dsp_command (devc, 0xfa))
+    return 0;
+
+  if (sb_dsp_get_byte (devc) != 0x12)
+    return 0;
+
+/*
+ * OK so far. Now configure the IRQ and DMA channel used by the acrd.
+ */
+  if (hw_config->irq < 1 || hw_config->irq > 15 ||
+      jazz_irq_bits[hw_config->irq] == 0)
+    {
+      printk ("Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq);
+      return 0;
+    }
+
+  if (hw_config->dma < 0 || hw_config->dma > 3 ||
+      jazz_dma_bits[hw_config->dma] == 0)
+    {
+      printk ("Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma);
+      return 0;
+    }
+
+  if (hw_config->dma2 < 0)
+    {
+      printk ("Jazz16: No 16 bit DMA channel defined\n");
+      return 0;
+    }
+
+  if (hw_config->dma2 < 5 || hw_config->dma2 > 7 ||
+      jazz_dma_bits[hw_config->dma2] == 0)
+    {
+      printk ("Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2);
+      return 0;
+    }
+
+  devc->dma16 = hw_config->dma2;
+
+  if (!sb_dsp_command (devc, 0xfb))
+    return 0;
+
+  if (!sb_dsp_command (devc, jazz_dma_bits[hw_config->dma] |
+		       (jazz_dma_bits[hw_config->dma2] << 4)))
+    return 0;
+
+  if (!sb_dsp_command (devc, jazz_irq_bits[hw_config->irq]))
+    return 0;
+
+/*
+ * Now we have configured a standard Jazz16 device. 
+ */
+  devc->model = MDL_JAZZ;
+  strcpy (name, "Jazz16");
+
+
+  hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1)));
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (hw_config->name != NULL)
+    strcpy (hw_config->name, name);
+  devc->caps |= SB_NO_MIDI;
+  return 1;
+}
+
+static int
+ess_init (sb_devc * devc, struct address_info *hw_config)
+{
+  unsigned char   cfg, irq_bits = 0, dma_bits = 0;
+  int             ess_major = 0, ess_minor = 0;
+  int             i;
+  char            name[100];
+
+/*
+ * Try to detect ESS chips.
+ */
+
+  sb_dsp_command (devc, 0xe7);	/* Return identification */
+
+  for (i = 1000; i; i--)
+    {
+      if (inb (DSP_DATA_AVAIL) & 0x80)
+	{
+	  if (ess_major == 0)
+	    ess_major = inb (DSP_READ);
+	  else
+	    {
+	      ess_minor = inb (DSP_READ);
+	      break;
+	    }
+	}
+    }
+
+  if (ess_major == 0)
+    return 0;
+
+  if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
+    {
+      sprintf (name, "ESS ES488 AudioDrive (rev %d)",
+	       ess_minor & 0x0f);
+      hw_config->name = name;
+      devc->model = MDL_SBPRO;
+      return 1;
+    }
+  else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
+    {
+      sprintf (name,
+	       "ESS ES1688 AudioDrive (rev %d)",
+	       ess_minor & 0x0f);
+    }
+  else
+    strcpy (name, "Jazz16");
+
+  devc->model = MDL_ESS;
+  devc->submodel = ess_minor & 0x0f;
+
+  hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1)));
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (hw_config->name != NULL)
+    strcpy (hw_config->name, name);
+
+
+  sb_dsp_reset (devc);		/* Turn on extended mode */
+
+/*
+ *    Set IRQ configuration register
+ */
+
+  cfg = 0x50;			/* Enable only DMA counter interrupt */
+
+  switch (devc->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", devc->irq);
+      return 0;
+    }
+
+  if (!ess_write (devc, 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 (devc->dma8 > 3 || devc->dma8 < 0 || devc->dma8 == 2)
+    {
+      dma_bits = 0;
+      cfg = 0x00;		/* Disable all DMA */
+      printk ("\nESS1688: Invalid DMA %d\n", devc->dma8);
+    }
+  else
+    {
+      if (devc->dma8 == 3)
+	dma_bits = 3;
+      else
+	dma_bits = devc->dma8 + 1;
+    }
+
+  if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2)))
+    printk ("\nESS1688: Failed to write to DMA config register\n");
+
+/*
+ * Enable joystick and OPL3
+ */
+
+  cfg = sb_getmixer (devc, 0x40);
+  sb_setmixer (devc, 0x40, cfg | 0x03);
+  if (devc->submodel >= 8)	/* ES1688 */
+    devc->caps |= SB_NO_MIDI;	/* ES1688 uses MPU401 MIDI mode */
+  sb_dsp_reset (devc);
+  return 1;
+}
+
+int
+sb_dsp_detect (struct address_info *hw_config)
+{
+  sb_devc         sb_info;
+  sb_devc        *devc = &sb_info;
+
+/*
+ * Initialize variables 
+ */
+  DDB (printk ("sb_dsp_detect(%x) entered\n", hw_config->io_base));
+  if (check_region (hw_config->io_base, 16))
+    return 0;
+
+  memset ((char *) &sb_info, 0, sizeof (sb_info));	/* Zero everything */
+
+  devc->osp = hw_config->osp;
+  devc->type = hw_config->card_subtype;
+
+  devc->base = hw_config->io_base;
+  devc->irq = hw_config->irq;
+  devc->dma8 = hw_config->dma;
+
+  devc->dma16 = -1;
+
+/*
+ * Detect the device
+ */
+
+  if (sb_dsp_reset (devc))
+    dsp_get_vers (devc);
+  else
+    devc->major = 0;
+
+  if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW)
+    if (devc->major == 0 || (devc->major == 3 && devc->minor == 1))
+      relocate_Jazz16 (devc, hw_config);
+
+  if (!sb_dsp_reset (devc))
+    {
+      DDB (printk ("SB reset failed\n"));
+      return 0;
+    }
+
+  if (devc->major == 0)
+    dsp_get_vers (devc);
+
+  if (devc->major == 3 && devc->minor == 1)
+    if (devc->type == MDL_AZTECH)	/* SG Washington? */
+      {
+	if (sb_dsp_command (devc, 0x09))
+	  if (sb_dsp_command (devc, 0x00))	/* Enter WSS mode */
+	    {
+	      int             i;
+
+	      /* Have some delay */
+	      for (i = 0; i < 10000; i++)
+		inb (DSP_DATA_AVAIL);
+	      devc->caps = SB_NO_AUDIO | SB_NO_MIDI;	/* Mixer only */
+	    }
+      }
+
+/*
+ * Save device information for sb_dsp_init()
+ */
+
+
+  detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (sb_devc)));
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+
+  if (detected_devc == NULL)
+    {
+      printk ("sb: Can't allocate memory for device information\n");
+      return 0;
+    }
+
+  memcpy ((char *) detected_devc, (char *) devc, sizeof (sb_devc));
+
+  DDB (printk ("SB %d.%d detected OK (%x)\n", devc->major, devc->minor,
+	       hw_config->io_base));
+  return 1;
+}
+
+void
+sb_dsp_init (struct address_info *hw_config)
+{
+  sb_devc        *devc;
+  int             n;
+  char            name[100];
+
+/*
+ * Check if we had detected a SB device earlier
+ */
+  DDB (printk ("sb_dsp_init(%x) entered\n", hw_config->io_base));
+
+  if (detected_devc == NULL)
+    {
+      DDB (printk ("No detected device\n"));
+      return;
+    }
+
+  devc = detected_devc;
+  detected_devc = NULL;
+
+  if (devc->base != hw_config->io_base)
+    {
+      DDB (printk ("I/O port mismatch\n"));
+      return;
+    }
+
+/*
+ * Now continue initialization of the device
+ */
+  devc->dev = num_audiodevs;
+  devc->caps = hw_config->driver_use_1;
+
+  if (snd_set_irq_handler (hw_config->irq,
+			   sbintr, "soundblaster", devc->osp) < 0)
+    {
+      printk ("SB: Can't allocate IRQ%d\n", hw_config->irq);
+      return;
+    }
+
+  if (devc->major == 4)
+    if (!sb16_set_irq_hw (devc, devc->irq))	/* Unsupported IRQ */
+      {
+	snd_release_irq (devc->irq);
+	return;
+      }
+
+  if ((devc->type == 0 || devc->type == MDL_ESS) &&
+      devc->major == 3 && devc->minor == 1)
+    {				/* Handle various chipsets which claim they are SB Pro compatible */
+      if ((devc->type != 0 && devc->type != MDL_ESS) ||
+	  !ess_init (devc, hw_config))
+	if ((devc->type != 0 && devc->type != MDL_JAZZ &&
+	     devc->type != MDL_SMW) || !init_Jazz16 (devc, hw_config))
+	  {
+	    DDB (printk ("This is a genuine SB Pro\n"));
+	  }
+    }
+
+  irq2devc[hw_config->irq] = devc;
+  devc->irq_ok = 0;
+
+  for (n = 0; n < 3 && devc->irq_ok == 0; n++)
+    if (sb_dsp_command (devc, 0xf2))	/* Cause interrupt immediately */
+      {
+	int             i;
+
+	for (i = 0; !devc->irq_ok && i < 10000000; i++);
+      }
+
+  if (!devc->irq_ok)
+    {
+      printk ("sb: Interrupt test on IRQ%d failed - device disabled\n", devc->irq);
+      snd_release_irq (devc->irq);
+      return;
+    }
+  else
+    {
+      DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq));
+    }
+
+  request_region (hw_config->io_base, 16, "soundblaster");
+
+  switch (devc->major)
+    {
+    case 1:			/* SB 1.0 or 1.5 */
+      devc->model = hw_config->card_subtype = MDL_SB1;
+      break;
+
+    case 2:			/* SB 2.x */
+      if (devc->minor == 0)
+	devc->model = hw_config->card_subtype = MDL_SB2;
+      else
+	devc->model = hw_config->card_subtype = MDL_SB201;
+      break;
+
+    case 3:			/* SB Pro and most clones */
+      if (devc->model == 0)
+	{
+	  devc->model = hw_config->card_subtype = MDL_SBPRO;
+	  if (hw_config->name == NULL)
+	    hw_config->name = "Sound Blaster Pro";
+	}
+      break;
+
+    case 4:
+      devc->model = hw_config->card_subtype = MDL_SB16;
+      if (hw_config->name == NULL)
+	hw_config->name = "Sound Blaster 16";
+
+      if (hw_config->dma2 == -1)
+	devc->dma16 = devc->dma8;
+      else if (hw_config->dma2 < 5 || hw_config->dma2 > 7)
+	{
+	  printk ("SB16: Bad or missing 16 bit DMA channel\n");
+	  devc->dma16 = devc->dma8;
+	}
+      else
+	devc->dma16 = hw_config->dma2;
+
+      sb16_set_dma_hw (devc);
+      devc->caps |= SB_NO_MIDI;
+    }
+
+  if (!(devc->caps & SB_NO_MIXER))
+    if (devc->major == 3 || devc->major == 4)
+      sb_mixer_init (devc);
+
+#ifdef CONFIG_MIDI
+  if (!(devc->caps & SB_NO_MIDI))
+    sb_dsp_midi_init (devc);
+#endif
+
+  if (hw_config->name == NULL)
+    hw_config->name = "Sound Blaster";
+
+  sprintf (name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor);
+  conf_printf (name, hw_config);
+  hw_config->card_subtype = devc->model;
+  last_devc = devc;		/* For SB MPU detection */
+
+  if (!(devc->caps & SB_NO_AUDIO))
+    {
+      if (sound_alloc_dma (devc->dma8, "SoundBlaster8"))
+	{
+	  printk ("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8);
+	}
+      if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
+	if (sound_alloc_dma (devc->dma16, "SoundBlaster16"))
+	  {
+	    printk ("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16);
+	  }
+      sb_audio_init (devc, name);
+    }
+}
+
+void
+sb_dsp_disable_midi (int io_base)
+{
+}
+
+void
+sb_dsp_disable_recording (int io_base)
+{
+}
+
+void
+sb_dsp_unload (struct address_info *hw_config)
+{
+  sb_devc        *devc;
+  int             irq = hw_config->irq;
+
+  if (irq < 0)
+    irq *= -1;
+
+  devc = irq2devc[irq];
+
+  if (devc && devc->base == hw_config->io_base)
+    {
+      release_region (devc->base, 16);
+      if (!(devc->caps & SB_NO_AUDIO))
+	{
+	  sound_free_dma (devc->dma8);
+
+	  if (devc->dma16 >= 0)
+	    sound_free_dma (devc->dma16);
+	}
+
+      snd_release_irq (devc->irq);
+      irq2devc[devc->irq] = NULL;
+    }
+}
+
+/*
+ * Mixer access routines
+ */
+
+void
+sb_setmixer (sb_devc * devc, unsigned int port, unsigned int value)
+{
+  unsigned long   flags;
+
+  save_flags (flags);
+  cli ();
+  outb ((unsigned char) (port & 0xff), MIXER_ADDR);
+
+  tenmicrosec (devc->osp);
+  outb ((unsigned char) (value & 0xff), MIXER_DATA);
+  tenmicrosec (devc->osp);
+  restore_flags (flags);
+}
+
+unsigned int
+sb_getmixer (sb_devc * devc, unsigned int port)
+{
+  unsigned int    val;
+  unsigned long   flags;
+
+  save_flags (flags);
+  cli ();
+  outb ((unsigned char) (port & 0xff), MIXER_ADDR);
+
+  tenmicrosec (devc->osp);
+  val = inb (MIXER_DATA);
+  tenmicrosec (devc->osp);
+  restore_flags (flags);
+
+  return val;
+}
+
+#ifdef CONFIG_MIDI
+/*
+ * MPU401 MIDI initialization.
+ */
+
+static void
+smw_putmem (sb_devc * devc, int base, int addr, unsigned char val)
+{
+  unsigned long   flags;
+
+  save_flags (flags);
+  cli ();
+
+  outb (addr & 0xff, base + 1);	/* Low address bits */
+  outb (addr >> 8, base + 2);	/* High address bits */
+  outb (val, base);		/* Data */
+
+  restore_flags (flags);
+}
+
+static unsigned char
+smw_getmem (sb_devc * devc, int base, int addr)
+{
+  unsigned long   flags;
+  unsigned char   val;
+
+  save_flags (flags);
+  cli ();
+
+  outb (addr & 0xff, base + 1);	/* Low address bits */
+  outb (addr >> 8, base + 2);	/* High address bits */
+  val = inb (base);		/* Data */
+
+  restore_flags (flags);
+  return val;
+}
+
+static int
+smw_midi_init (sb_devc * devc, struct address_info *hw_config)
+{
+  int             mpu_base = hw_config->io_base;
+  int             mp_base = mpu_base + 4;	/* Microcontroller base */
+  int             i;
+  unsigned char   control;
+
+
+  /*
+     *  Reset the microcontroller so that the RAM can be accessed
+   */
+
+  control = inb (mpu_base + 7);
+  outb (control | 3, mpu_base + 7);	/* Set last two bits to 1 (?) */
+  outb ((control & 0xfe) | 2, mpu_base + 7);	/* xxxxxxx0 resets the mc */
+
+  for (i = 0; i < 300; i++)	/* Wait at least 1ms */
+    tenmicrosec (devc->osp);
+
+  outb (control & 0xfc, mpu_base + 7);	/* xxxxxx00 enables RAM */
+
+  /*
+     *  Detect microcontroller by probing the 8k RAM area
+   */
+  smw_putmem (devc, mp_base, 0, 0x00);
+  smw_putmem (devc, mp_base, 1, 0xff);
+  tenmicrosec (devc->osp);
+
+  if (smw_getmem (devc, mp_base, 0) != 0x00 || smw_getmem (devc, mp_base, 1) != 0xff)
+    {
+      DDB (printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n",
+	     smw_getmem (devc, mp_base, 0), smw_getmem (devc, mp_base, 1)));
+      return 0;			/* No RAM */
+    }
+
+  /*
+     *  There is RAM so assume it's really a SM Wave
+   */
+
+  devc->model = MDL_SMW;
+  smw_mixer_init (devc);
+
+  if (smw_ucodeLen > 0)
+    {
+      if (smw_ucodeLen != 8192)
+	{
+	  printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n");
+	  return 1;
+	}
+
+      /*
+       *  Download microcode
+       */
+
+      for (i = 0; i < 8192; i++)
+	smw_putmem (devc, mp_base, i, smw_ucode[i]);
+
+      /*
+       *  Verify microcode
+       */
+
+      for (i = 0; i < 8192; i++)
+	if (smw_getmem (devc, mp_base, i) != smw_ucode[i])
+	  {
+	    printk ("SM Wave: Microcode verification failed\n");
+	    return 0;
+	  }
+    }
+
+  control = 0;
+#ifdef SMW_SCSI_IRQ
+  /*
+     * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt
+     * is disabled by default.
+     *
+     * Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10.
+   */
+  {
+    static unsigned char scsi_irq_bits[] =
+    {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0};
+
+    control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6;
+  }
+#endif
+
+#ifdef SMW_OPL4_ENABLE
+  /*
+     *  Make the OPL4 chip visible on the PC bus at 0x380.
+     *
+     *  There is no need to enable this feature since this driver
+     *  doesn't support OPL4 yet. Also there is no RAM in SM Wave so
+     *  enabling OPL4 is pretty useless.
+   */
+  control |= 0x10;		/* Uses IRQ12 if bit 0x20 == 0 */
+  /* control |= 0x20;      Uncomment this if you want to use IRQ7 */
+#endif
+
+  outb (control | 0x03, mpu_base + 7);	/* xxxxxx11 restarts */
+  hw_config->name = "SoundMan Wave";
+  return 1;
+}
+
+static int
+ess_midi_init (sb_devc * devc, struct address_info *hw_config)
+{
+  unsigned char   cfg, tmp;
+
+  cfg = sb_getmixer (devc, 0x40) & 0x03;
+
+  if (devc->submodel < 8)
+    {
+      sb_setmixer (devc, 0x40, cfg | 0x03);	/* Enable OPL3 & joystick */
+      return 0;			/* ES688 doesn't support MPU401 mode */
+    }
+
+  tmp = (hw_config->io_base & 0x0f0) >> 4;
+
+  if (tmp > 3)
+    {
+      sb_setmixer (devc, 0x40, cfg);
+      return 0;
+    }
+
+  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;
+    default:
+      return 0;
+    }
+
+  cfg |= tmp << 5;
+
+  sb_setmixer (devc, 0x40, cfg | 0x03);
+  return 1;
+}
+
+static int
+init_Jazz16_midi (sb_devc * devc, struct address_info *hw_config)
+{
+  int             mpu_base = hw_config->io_base;
+  int             sb_base = devc->base;
+  int             irq = hw_config->irq;
+
+  unsigned char   bits = 0;
+  unsigned long   flags;
+
+  if (irq < 0)
+    irq *= -1;
+
+  if (irq < 1 || irq > 15 ||
+      jazz_irq_bits[irq] == 0)
+    {
+      printk ("Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq);
+      return 0;
+    }
+
+  switch (sb_base)
+    {
+    case 0x220:
+      bits = 1;
+      break;
+    case 0x240:
+      bits = 2;
+      break;
+    case 0x260:
+      bits = 3;
+      break;
+
+    default:
+      return 0;
+    }
+
+  bits = jazz16_bits = bits << 5;
+
+  switch (mpu_base)
+    {
+    case 0x310:
+      bits |= 1;
+      break;
+    case 0x320:
+      bits |= 2;
+      break;
+    case 0x330:
+      bits |= 3;
+      break;
+
+    default:
+      printk ("Jazz16: Invalid MIDI I/O port %x\n", mpu_base);
+      return 0;
+    }
+/*
+ * Magic wake up sequence by writing to 0x201 (aka Joystick port)
+ */
+  save_flags (flags);
+  cli ();
+  outb (0xAF, 0x201);
+  outb (0x50, 0x201);
+  outb (bits, 0x201);
+  restore_flags (flags);
+
+  hw_config->name = "Jazz16";
+  smw_midi_init (devc, hw_config);
+
+  if (!sb_dsp_command (devc, 0xfb))
+    return 0;
+
+  if (!sb_dsp_command (devc, jazz_dma_bits[devc->dma8] |
+		       (jazz_dma_bits[devc->dma16] << 4)))
+    return 0;
+
+  if (!sb_dsp_command (devc, jazz_irq_bits[devc->irq] |
+		       (jazz_irq_bits[irq] << 4)))
+    return 0;
+
+  return 1;
+}
+
+void
+attach_sbmpu (struct address_info *hw_config)
+{
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
+  attach_uart401 (hw_config);
+#endif
+}
+
+int
+probe_sbmpu (struct address_info *hw_config)
+{
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
+  sb_devc        *devc = last_devc;
+
+  if (last_devc == NULL)
+    return 0;
+
+  last_devc = 0;
+
+  if (check_region (hw_config->io_base, 4))
+    {
+      printk ("sbmpu: I/O port conflict (%x)\n", hw_config->io_base);
+      return 0;
+    }
+
+  switch (devc->model)
+    {
+    case MDL_SB16:
+      if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330)
+	{
+	  printk ("SB16: Invalid MIDI port %x\n", hw_config->irq);
+	  return 0;
+	}
+      hw_config->name = "Sound Blaster 16";
+      hw_config->irq = -devc->irq;
+      break;
+
+    case MDL_ESS:
+      if (hw_config->irq < 3 || hw_config->irq == devc->irq)
+	hw_config->irq = -devc->irq;
+      if (!ess_midi_init (devc, hw_config))
+	return 0;
+      hw_config->name = "ESS ES1688";
+      break;
+
+    case MDL_JAZZ:
+      if (hw_config->irq < 3 || hw_config->irq == devc->irq)
+	hw_config->irq = -devc->irq;
+      if (!init_Jazz16_midi (devc, hw_config))
+	return 0;
+      break;
+
+    default:
+      return 0;
+    }
+
+  return probe_uart401 (hw_config);
+#else
+  return 0;
+#endif
+}
+
+void 
+unload_sbmpu (struct address_info *hw_config)
+{
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
+  unload_uart401 (hw_config);
+#endif
+}
+#else /* !CONFIG_MIDI */
+
+void 
+unload_sbmpu (struct address_info *hw_config)
+{
+}
+
+int
+probe_sbmpu (struct address_info *hw_config)
+{
+  return 0;
+}
+
+void
+attach_sbmpu (struct address_info *hw_config)
+{
+}
+#endif
+
+
+#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
--- v2.0.0/linux/drivers/sound/sb_dsp.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/sb_dsp.c	Thu Jan  1 02:00:00 1970
@@ -1,1661 +0,0 @@
-/*
- * sound/sb_dsp.c
- *
- * The low level driver for the SoundBlaster DSP chip (SB1.0 to 2.1, SB Pro).
- */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <linux/config.h>
-
-/*
- * Modified:
- *      Hunyue Yau      Jan 6 1994
- *      Added code to support Sound Galaxy NX Pro
- *
- *      JRA Gibson      April 1995
- *      Code added for MV ProSonic/Jazz 16 in 16 bit mode
- */
-
-#include "sound_config.h"
-
-#if defined(CONFIG_SB)
-
-#include "sb.h"
-#include "sb_mixer.h"
-#undef SB_TEST_IRQ
-
-int             sbc_base = 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;
-static int      sb16_inited = 0;
-
-/*
- * The DSP channel can be used either for input or output. Variable
- * 'sb_irq_mode' will be set when the program calls read or write first time
- * after open. Current version doesn't support mode changes without closing
- * and reopening the device. Support for this feature may be implemented in a
- * future version of this driver.
- */
-
-int             sb_dsp_ok = 0;	/*
-
-
-				 * *  * * Set to 1 after successful
-				 * initialization  *  */
-static int      midi_disabled = 0;
-int             sb_dsp_highspeed = 0;
-int             sbc_major = 0, sbc_minor = 0;
-static int      dsp_stereo = 0;
-static int      dsp_current_speed = DSP_DEFAULT_SPEED;
-static int      dsp_requested_speed = DSP_DEFAULT_SPEED;
-static int      sb16 = 0;
-static int      irq_verified = 0;
-
-int             sb_midi_mode = NORMAL_MIDI;
-int             sb_midi_busy = 0;
-int             sb_dsp_busy = 0;
-
-volatile int    sb_irq_mode = IMODE_NONE;
-static volatile int irq_ok = 0;
-
-static int      dma8 = 1;
-static int      dsp_16bit = 0;
-
-/* 16 bit support
- */
-
-static int      dma16 = 1;
-
-static int      dsp_set_bits (int arg);
-static int      initialize_ProSonic16 (void);
-
-/* end of 16 bit support
- */
-
-int             sb_duplex_midi = 0;
-static int      my_dev = 0;
-
-volatile int    sb_intr_active = 0;
-
-static int      dsp_speed (int);
-static int      dsp_set_stereo (int mode);
-static void     sb_dsp_reset (int dev);
-static void     dsp_get_vers (struct address_info *hw_config);
-int            *sb_osp = NULL;
-
-#if defined(CONFIG_MIDI) || defined(CONFIG_AUDIO)
-
-/*
- * Common code for the midi and pcm functions
- */
-
-int
-sb_dsp_command (unsigned char val)
-{
-  int             i;
-  unsigned long   limit;
-
-  limit = jiffies + HZ / 10;	/*
-				   * The timeout is 0.1 seconds
-				 */
-
-  /*
-   * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
-   * called while interrupts are disabled. This means that the timer is
-   * disabled also. However the timeout situation is a abnormal condition.
-   * Normally the DSP should be ready to accept commands after just couple of
-   * loops.
-   */
-
-  for (i = 0; i < 500000 && jiffies < limit; i++)
-    {
-      if ((inb (DSP_STATUS) & 0x80) == 0)
-	{
-	  outb (val, DSP_COMMAND);
-	  return 1;
-	}
-    }
-
-  printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val);
-  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, void *dev_id, struct pt_regs *dummy)
-{
-  int             status;
-
-  if (sb16 && !AudioDrive)
-    {
-      unsigned char   src = sb_getmixer (IRQ_STAT);	/* Interrupt source register */
-
-      if (src & 3)
-	sb16_dsp_interrupt (irq);
-
-#ifdef CONFIG_MIDI
-      if (src & 4)
-	sb16midiintr (irq);	/*
-				 * SB MPU401 interrupt
-				 */
-#endif
-
-      if (!(src & 1))
-	return;			/*
-				 * Not a DSP interrupt
-				 */
-    }
-
-  status = inb (DSP_DATA_AVAIL);	/*
-					   * Clear interrupt
-					 */
-  if (sb_intr_active)
-    switch (sb_irq_mode)
-      {
-      case IMODE_OUTPUT:
-	if (!AudioDrive)
-	  sb_intr_active = 0;
-	DMAbuf_outputintr (my_dev, 1);
-	break;
-
-      case IMODE_INPUT:
-	if (!AudioDrive)
-	  sb_intr_active = 0;
-	DMAbuf_inputintr (my_dev);
-	break;
-
-      case IMODE_INIT:
-	sb_intr_active = 0;
-	irq_ok = 1;
-	break;
-
-      case IMODE_MIDI:
-#ifdef CONFIG_MIDI
-	sb_midi_interrupt (irq);
-#endif
-	break;
-
-      default:
-	printk ("SoundBlaster: Unexpected interrupt\n");
-      }
-}
-
-int
-sb_get_irq (void)
-{
-  return 0;
-}
-
-void
-sb_free_irq (void)
-{
-}
-
-int
-sb_reset_dsp (void)
-{
-  int             loopc;
-
-  if (AudioDrive)
-    outb (3, DSP_RESET);	/* Reset FIFO too */
-  else
-    outb (1, DSP_RESET);
-
-  tenmicrosec (sb_osp);
-  outb (0, DSP_RESET);
-  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
-
-#ifdef CONFIG_AUDIO
-
-static void
-dsp_speaker (char state)
-{
-  if (state)
-    sb_dsp_command (DSP_CMD_SPKON);
-  else
-    sb_dsp_command (DSP_CMD_SPKOFF);
-}
-
-static int
-ess_speed (int speed)
-{
-  int             divider;
-  unsigned char   bits = 0;
-
-  if (speed < 4000)
-    speed = 4000;
-  else if (speed > 48000)
-    speed = 48000;
-
-  if (speed > 22000)
-    {
-      bits = 0x80;
-      divider = 256 - (795500 + speed / 2) / speed;
-      dsp_current_speed = 795500 / (256 - divider);
-    }
-  else
-    {
-      divider = 128 - (397700 + speed / 2) / speed;
-      dsp_current_speed = 397700 / (128 - divider);
-    }
-
-  bits |= (unsigned char) divider;
-  ess_write (0xa1, bits);
-
-/*
- * Set filter divider register
- */
-
-  speed = (speed * 9) / 20;	/* Set filter rolloff to 90% of speed/2 */
-  divider = 256 - 7160000 / (speed * 82);
-  ess_write (0xa2, divider);
-
-  return dsp_current_speed;
-}
-
-static int
-dsp_speed (int speed)
-{
-  unsigned char   tconst;
-  unsigned long   flags;
-  int             max_speed = 44100;
-
-  dsp_requested_speed = speed;
-
-  if (AudioDrive)
-    return ess_speed (speed);
-
-  if (speed < 4000)
-    speed = 4000;
-
-  /*
-     * Older SB models don't support higher speeds than 22050.
-   */
-
-  if (sbc_major < 2 ||
-      (sbc_major == 2 && sbc_minor == 0))
-    max_speed = 22050;
-
-  /*
-     * SB models earlier than SB Pro have low limit for the input speed.
-   */
-  if (open_mode != OPEN_WRITE)	/* Recording is possible */
-    if (sbc_major < 3)		/* Limited input speed with these cards */
-      if (sbc_major == 2 && sbc_minor > 0)
-	max_speed = 15000;
-      else
-	max_speed = 13000;
-
-  if (speed > max_speed)
-    speed = max_speed;		/*
-				 * Invalid speed
-				 */
-
-  /* Logitech SoundMan Games and Jazz16 cards can support 44.1kHz stereo */
-#if !defined (SM_GAMES)
-  /*
-   * Max. stereo speed is 22050
-   */
-  if (dsp_stereo && speed > 22050 && Jazz16_detected == 0 && AudioDrive == 0)
-    speed = 22050;
-#endif
-
-  if ((speed > 22050) && sb_midi_busy)
-    {
-      printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n");
-      speed = 22050;
-    }
-
-  if (dsp_stereo)
-    speed *= 2;
-
-  /*
-   * Now the speed should be valid
-   */
-
-  if (speed > 22050)
-    {				/*
-				 * High speed mode
-				 */
-      int             tmp;
-
-      tconst = (unsigned char) ((65536 -
-				 ((256000000 + speed / 2) / speed)) >> 8);
-      sb_dsp_highspeed = 1;
-
-      save_flags (flags);
-      cli ();
-      if (sb_dsp_command (0x40))
-	sb_dsp_command (tconst);
-      restore_flags (flags);
-
-      tmp = 65536 - (tconst << 8);
-      speed = (256000000 + tmp / 2) / tmp;
-    }
-  else
-    {
-      int             tmp;
-
-      sb_dsp_highspeed = 0;
-      tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
-
-      save_flags (flags);
-      cli ();
-      if (sb_dsp_command (0x40))	/*
-					 * Set time constant
-					 */
-	sb_dsp_command (tconst);
-      restore_flags (flags);
-
-      tmp = 256 - tconst;
-      speed = (1000000 + tmp / 2) / tmp;
-    }
-
-  if (dsp_stereo)
-    speed /= 2;
-
-  dsp_current_speed = speed;
-  return speed;
-}
-
-static int
-dsp_set_stereo (int mode)
-{
-  dsp_stereo = 0;
-
-  if (sbc_major < 3 || sb16)
-    return 0;			/*
-				 * Sorry no stereo
-				 */
-
-  if (mode && sb_midi_busy)
-    {
-      printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n");
-      return 0;
-    }
-
-  dsp_stereo = !!mode;
-  dsp_speed (dsp_requested_speed);
-  return dsp_stereo;
-}
-
-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 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;
-
-  DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
-
-  sb_irq_mode = 0;
-
-  if (audio_devs[dev]->dmachan1 > 3)
-    count >>= 1;
-  count--;
-  dsp_count = count;
-
-  sb_irq_mode = IMODE_OUTPUT;
-
-  if (AudioDrive)
-    {
-      short           c = -nr_bytes;
-
-      ess_write (0xa4, (unsigned char) ((unsigned short) c & 0xff));
-      ess_write (0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
-
-      ess_write (0xb8, ess_read (0xb8) | 0x01);		/* Go */
-    }
-  else if (sb_dsp_highspeed)
-    {
-      save_flags (flags);
-      cli ();
-      if (sb_dsp_command (0x48))	/*
-					   * High speed size
-					 */
-	{
-	  sb_dsp_command ((unsigned char) (dsp_count & 0xff));
-	  sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff));
-	  sb_dsp_command (0x91);	/*
-					   * High speed 8 bit DAC
-					 */
-	}
-      else
-	printk ("SB Error: Unable to start (high speed) DAC\n");
-      restore_flags (flags);
-    }
-  else
-    {
-      save_flags (flags);
-      cli ();
-      if (sb_dsp_command (0x14))	/*
-					   * 8-bit DAC (DMA)
-					 */
-	{
-	  sb_dsp_command ((unsigned char) (dsp_count & 0xff));
-	  sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff));
-	}
-      else
-	printk ("SB Error: Unable to start DAC\n");
-      restore_flags (flags);
-    }
-  sb_intr_active = 1;
-}
-
-static void
-sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
-		    int restart_dma)
-{
-  if (sb_no_recording)
-    {
-      return;
-    }
-
-  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 nr_bytes, int intrflag,
-		      int restart_dma)
-{
-  unsigned long   flags;
-  int             count = nr_bytes;
-
-  if (sb_no_recording)
-    {
-      return;
-    }
-
-  /*
-   * Start a DMA input to the buffer pointed by dmaqtail
-   */
-
-  DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
-  sb_irq_mode = 0;
-
-  if (audio_devs[dev]->dmachan1 > 3)
-    count >>= 1;
-  count--;
-  dsp_count = count;
-
-  sb_irq_mode = IMODE_INPUT;
-
-  if (AudioDrive)
-    {
-      short           c = -nr_bytes;
-
-      ess_write (0xa4, (unsigned char) ((unsigned short) c & 0xff));
-      ess_write (0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff));
-
-      ess_write (0xb8, ess_read (0xb8) | 0x01);		/* Go */
-    }
-  else if (sb_dsp_highspeed)
-    {
-      save_flags (flags);
-      cli ();
-      if (sb_dsp_command (0x48))	/*
-					   * High speed size
-					 */
-	{
-	  sb_dsp_command ((unsigned char) (dsp_count & 0xff));
-	  sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff));
-	  sb_dsp_command (0x99);	/*
-					   * High speed 8 bit ADC
-					 */
-	}
-      else
-	printk ("SB Error: Unable to start (high speed) ADC\n");
-      restore_flags (flags);
-    }
-  else
-    {
-      save_flags (flags);
-      cli ();
-      if (sb_dsp_command (0x24))	/*
-					   * 8-bit ADC (DMA)
-					 */
-	{
-	  sb_dsp_command ((unsigned char) (dsp_count & 0xff));
-	  sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff));
-	}
-      else
-	printk ("SB Error: Unable to start ADC\n");
-      restore_flags (flags);
-    }
-
-  sb_intr_active = 1;
-}
-
-static void
-sb_dsp_trigger (int dev, int bits)
-{
-
-  if (!bits)
-    sb_dsp_command (0xd0);	/* Halt DMA */
-  else if (bits & sb_irq_mode)
-    {
-      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;
-}
-
-static void
-dsp_cleanup (void)
-{
-  sb_intr_active = 0;
-}
-
-static int
-sb_dsp_prepare_for_input (int dev, int bsize, int bcount)
-{
-  if (sb_no_recording)
-    {
-      printk ("SB Error: This device doesn't support recording\n");
-      return 0;
-    }
-
-  dsp_cleanup ();
-  dsp_speaker (OFF);
-  dsp_speed (dsp_requested_speed);
-
-  if (sbc_major == 3)		/*
-				 * SB Pro
-				 */
-    {
-      if (AudioDrive)
-	{
-
-	  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
-	{			/* !AudioDrive */
-
-	  /* Select correct dma channel
-	     * for 16/8 bit access
-	   */
-	  audio_devs[my_dev]->dmachan1 =
-	    audio_devs[my_dev]->dmachan2 =
-	    dsp_16bit ? dma16 : dma8;
-	  if (dsp_stereo)
-	    sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
-	  else
-	    sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
-
-	}			/* !AudioDrive */
-    }
-  trigger_bits = 0;
-  return 0;
-}
-
-static int
-sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
-{
-  dsp_cleanup ();
-  dsp_speaker (OFF);
-  dsp_speed (dsp_requested_speed);
-
-  if (sbc_major == 3)		/* SB Pro (at least ) */
-    {
-
-      if (AudioDrive)
-	{
-
-	  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
-	{			/* !AudioDrive */
-
-	  /* 16 bit specific instructions (Jazz16)
-	   */
-	  audio_devs[my_dev]->dmachan1 =
-	    audio_devs[my_dev]->dmachan2 =
-	    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 */
-
-    }
-
-  trigger_bits = 0;
-  dsp_speaker (ON);
-  return 0;
-}
-
-static void
-sb_dsp_halt_xfer (int dev)
-{
-  if (AudioDrive)
-    sb_reset_dsp ();
-}
-
-static int
-verify_irq (void)
-{
-  irq_ok = 1;
-  return irq_ok;
-}
-
-static int
-sb_dsp_open (int dev, int mode)
-{
-  int             retval;
-
-  if (!sb_dsp_ok)
-    {
-      printk ("SB Error: SoundBlaster board not installed\n");
-      return -ENXIO;
-    }
-
-  if (sb_no_recording && mode & OPEN_READ)
-    {
-      printk ("SB Warning: Recording not supported by this device\n");
-    }
-
-  if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI))
-    {
-      printk ("SB: Audio device or MIDI already in use.\n");
-      return -EBUSY;
-    }
-
-  if (!sb_midi_busy)
-    sb_reset_dsp ();
-
-  if (!irq_verified)
-    {
-      verify_irq ();
-      irq_verified = 1;
-    }
-  else if (!irq_ok)
-    printk ("SB Warning: Incorrect IRQ setting %d\n",
-	    sbc_irq);
-
-  retval = sb_get_irq ();
-  if (retval)
-    return retval;
-
-  /* Allocate 8 bit dma
-   */
-  audio_devs[my_dev]->dmachan1 =
-    audio_devs[my_dev]->dmachan2 =
-    dma8;
-
-  /* Allocate 16 bit dma (jazz16)
-   */
-  if (Jazz16_detected != 0)
-    if (dma16 != dma8)
-      {
-	if (sound_open_dma (dma16, "Jazz16 16 bit"))
-	  {
-	    sb_free_irq ();
-	    /* DMAbuf_close_dma (dev); */
-	    return -EBUSY;
-	  }
-      }
-
-  sb_irq_mode = IMODE_NONE;
-
-  sb_dsp_busy = 1;
-  open_mode = mode;
-
-  return 0;
-}
-
-static void
-sb_dsp_close (int dev)
-{
-  /* Release 16 bit dma channel
-   */
-  if (Jazz16_detected)
-    {
-      audio_devs[my_dev]->dmachan1 =
-	audio_devs[my_dev]->dmachan2 =
-	dma8;
-
-      if (dma16 != dma8)
-	sound_close_dma (dma16);
-    }
-
-  if (AudioDrive)
-    sb_reset_dsp ();
-
-  /* DMAbuf_close_dma (dev); */
-  sb_free_irq ();
-  /* sb_dsp_command (0xd4); */
-  dsp_cleanup ();
-  dsp_speaker (OFF);
-  sb_dsp_busy = 0;
-  sb_dsp_highspeed = 0;
-  open_mode = 0;
-}
-
-static int
-dsp_set_bits (int arg)
-{
-  if (arg)
-    if (Jazz16_detected == 0 && AudioDrive == 0)
-      dsp_16bit = 0;
-    else
-      switch (arg)
-	{
-	case 8:
-	  dsp_16bit = 0;
-	  break;
-	case 16:
-	  dsp_16bit = 1;
-	  break;
-	default:
-	  dsp_16bit = 0;
-	}
-
-  return dsp_16bit ? 16 : 8;
-}
-
-static int
-sb_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
-{
-  switch (cmd)
-    {
-    case SOUND_PCM_WRITE_RATE:
-      if (local)
-	return dsp_speed ((long) arg);
-      return snd_ioctl_return ((int *) arg, dsp_speed (get_fs_long ((long *) arg)));
-      break;
-
-    case SOUND_PCM_READ_RATE:
-      if (local)
-	return dsp_current_speed;
-      return snd_ioctl_return ((int *) arg, dsp_current_speed);
-      break;
-
-    case SOUND_PCM_WRITE_CHANNELS:
-      if (local)
-	return dsp_set_stereo ((long) arg - 1) + 1;
-      return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1);
-      break;
-
-    case SOUND_PCM_READ_CHANNELS:
-      if (local)
-	return dsp_stereo + 1;
-      return snd_ioctl_return ((int *) arg, dsp_stereo + 1);
-      break;
-
-    case SNDCTL_DSP_STEREO:
-      if (local)
-	return dsp_set_stereo ((long) arg);
-      return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg)));
-      break;
-
-      /* Word size specific cases here.
-         * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS
-       */
-    case SNDCTL_DSP_SETFMT:
-      if (local)
-	return dsp_set_bits ((long) arg);
-      return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg)));
-      break;
-
-    case SOUND_PCM_READ_BITS:
-      if (local)
-	return dsp_16bit ? 16 : 8;
-      return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8);
-      break;
-
-    case SOUND_PCM_WRITE_FILTER:
-    case SOUND_PCM_READ_FILTER:
-      return -EINVAL;
-      break;
-
-    default:;
-    }
-
-  return -EINVAL;
-}
-
-static void
-sb_dsp_reset (int dev)
-{
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-
-  sb_reset_dsp ();
-  dsp_speed (dsp_current_speed);
-  dsp_cleanup ();
-
-  restore_flags (flags);
-}
-
-#endif
-
-
-/*
- * Initialization of a Media Vision ProSonic 16 Soundcard.
- * The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets
- * the base address, the DMA-channels, interrupts and enables the joystickport.
- *
- * Also used by Jazz 16 (same card, different name)
- *
- * written 1994 by Rainer Vranken
- * E-Mail: rvranken@polaris.informatik.uni-essen.de
- */
-
-unsigned int
-get_sb_byte (void)
-{
-  int             i;
-
-  for (i = 1000; i; i--)
-    if (inb (DSP_DATA_AVAIL) & 0x80)
-      {
-	return inb (DSP_READ);
-      }
-
-  return 0xffff;
-}
-
-/*
- * Logitech Soundman Wave detection and initialization by Hannu Savolainen.
- *
- * There is a microcontroller (8031) in the SM Wave card for MIDI emulation.
- * it's located at address MPU_BASE+4.  MPU_BASE+7 is a SM Wave specific
- * control register for MC reset, SCSI, OPL4 and DSP (future expansion)
- * address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16
- * based soundcard.
- */
-
-static void
-smw_putmem (int base, int addr, unsigned char val)
-{
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-
-  outb (addr & 0xff, base + 1);	/* Low address bits */
-  outb (addr >> 8, base + 2);	/* High address bits */
-  outb (val, base);		/* Data */
-
-  restore_flags (flags);
-}
-
-static unsigned char
-smw_getmem (int base, int addr)
-{
-  unsigned long   flags;
-  unsigned char   val;
-
-  save_flags (flags);
-  cli ();
-
-  outb (addr & 0xff, base + 1);	/* Low address bits */
-  outb (addr >> 8, base + 2);	/* High address bits */
-  val = inb (base);		/* Data */
-
-  restore_flags (flags);
-  return val;
-}
-
-#ifdef SMW_MIDI0001_INCLUDED
-#include "smw-midi0001.h"
-#else
-unsigned char  *smw_ucode = NULL;
-int             smw_ucodeLen = 0;
-
-#endif
-
-static int
-initialize_smw (int mpu_base)
-{
-
-  int             mp_base = mpu_base + 4;	/* Microcontroller base */
-  int             i;
-  unsigned char   control;
-
-
-  /*
-     *  Reset the microcontroller so that the RAM can be accessed
-   */
-
-  control = inb (mpu_base + 7);
-  outb (control | 3, mpu_base + 7);	/* Set last two bits to 1 (?) */
-  outb ((control & 0xfe) | 2, mpu_base + 7);	/* xxxxxxx0 resets the mc */
-
-  for (i = 0; i < 300; i++)	/* Wait at least 1ms */
-    tenmicrosec (sb_osp);
-
-  outb (control & 0xfc, mpu_base + 7);	/* xxxxxx00 enables RAM */
-
-  /*
-     *  Detect microcontroller by probing the 8k RAM area
-   */
-  smw_putmem (mp_base, 0, 0x00);
-  smw_putmem (mp_base, 1, 0xff);
-  tenmicrosec (sb_osp);
-
-  if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff)
-    {
-      printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n",
-	      smw_getmem (mp_base, 0), smw_getmem (mp_base, 1));
-      return 0;			/* No RAM */
-    }
-
-  /*
-     *  There is RAM so assume it's really a SM Wave
-   */
-
-  if (smw_ucodeLen > 0)
-    {
-      if (smw_ucodeLen != 8192)
-	{
-	  printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n");
-	  return 1;
-	}
-
-      /*
-         *  Download microcode
-       */
-
-      for (i = 0; i < 8192; i++)
-	smw_putmem (mp_base, i, smw_ucode[i]);
-
-      /*
-         *  Verify microcode
-       */
-
-      for (i = 0; i < 8192; i++)
-	if (smw_getmem (mp_base, i) != smw_ucode[i])
-	  {
-	    printk ("SM Wave: Microcode verification failed\n");
-	    return 0;
-	  }
-    }
-
-  control = 0;
-#ifdef SMW_SCSI_IRQ
-  /*
-     * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt
-     * is disabled by default.
-     *
-     * Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10.
-   */
-  {
-    static unsigned char scsi_irq_bits[] =
-    {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0};
-
-    control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6;
-  }
-#endif
-
-#ifdef SMW_OPL4_ENABLE
-  /*
-     *  Make the OPL4 chip visible on the PC bus at 0x380.
-     *
-     *  There is no need to enable this feature since this driver
-     *  doesn't support OPL4 yet. Also there is no RAM in SM Wave so
-     *  enabling OPL4 is pretty useless.
-   */
-  control |= 0x10;		/* Uses IRQ12 if bit 0x20 == 0 */
-  /* control |= 0x20;      Uncomment this if you want to use IRQ7 */
-#endif
-
-  outb (control | 0x03, mpu_base + 7);	/* xxxxxx11 restarts */
-  return 1;
-}
-
-static int
-initialize_ProSonic16 (void)
-{
-  int             x;
-  static unsigned char int_translat[16] =
-  {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};
-
-  outb (0xAF, 0x201);		/* ProSonic/Jazz16 wakeup */
-  for (x = 0; x < 1000; ++x)	/* wait 10 milliseconds */
-    tenmicrosec (sb_osp);
-  outb (0x50, 0x201);
-  outb ((sbc_base & 0x70) | ((mpu_base & 0x30) >> 4), 0x201);
-
-  if (sb_reset_dsp ())
-    {				/* OK. We have at least a SB */
-
-      /* Check the version number of ProSonic (I guess) */
-
-      if (!sb_dsp_command (0xFA))
-	return 1;
-      if (get_sb_byte () != 0x12)
-	return 1;
-
-      if (sb_dsp_command (0xFB) &&	/* set DMA-channels and Interrupts */
-	  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)
-	    if (initialize_smw (mpu_base))
-	      Jazz16_detected = 2;
-
-	  sb_dsp_disable_midi ();
-	}
-
-      return 1;			/* There was at least a SB */
-    }
-  return 0;			/* No SB or ProSonic16 detected */
-}
-
-int
-sb_dsp_detect (struct address_info *hw_config)
-{
-  if (sb_dsp_ok)
-    return 0;			/*
-				 * Already initialized
-				 */
-
-  sbc_base = hw_config->io_base;
-  sbc_irq = hw_config->irq;
-  sbc_dma = hw_config->dma;
-  sb_osp = hw_config->osp;
-  dma8 = dma16 = hw_config->dma;
-
-  if (sb_reset_dsp ())
-    dsp_get_vers (hw_config);
-  else
-    sbc_major = 0;
-
-  if (sbc_major == 3 || sbc_major == 0)
-    if (initialize_ProSonic16 ())
-      return 1;
-
-  if (!sb_reset_dsp ())
-    return 0;
-
-  return 1;			/*
-				 * Detected
-				 */
-}
-
-#ifdef CONFIG_AUDIO
-static struct audio_operations sb_dsp_operations =
-{
-  "SoundBlaster",
-  NOTHING_SPECIAL,
-  AFMT_U8,			/* Just 8 bits. Poor old SB */
-  NULL,
-  sb_dsp_open,
-  sb_dsp_close,
-  sb_dsp_output_block,
-  sb_dsp_start_input,
-  sb_dsp_ioctl,
-  sb_dsp_prepare_for_input,
-  sb_dsp_prepare_for_output,
-  sb_dsp_reset,
-  sb_dsp_halt_xfer,
-  NULL,				/* local_qlen */
-  NULL,				/* copy_from_user */
-  NULL,
-  NULL,
-  sb_dsp_trigger
-};
-
-#endif
-
-static void
-ess_init (int ess_minor)	/* ESS1688 Initialization */
-{
-  unsigned char   cfg, irq_bits = 0, dma_bits = 0;
-
-  AudioDrive = 1;
-
-  if (ess_minor >= 8)		/* ESS1688 doesn't support SB MIDI */
-    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 enable */
-
-  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);
-}
-
-#ifdef CONFIG_MIDI
-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);
-}
-#endif
-
-void
-Jazz16_midi_init (struct address_info *hw_config)
-{
-  extern void     smw_mixer_init (void);
-  extern void     sb_mixer_reset (void);
-
-  mpu_base = hw_config->io_base;
-  mpu_irq = hw_config->irq;
-
-  initialize_ProSonic16 ();
-
-  smw_mixer_init ();
-  sb_mixer_reset ();
-}
-
-void
-Jazz16_set_dma16 (int dma)
-{
-  dma16 = dma;
-
-/* Allocate 16 bit dma (Jazz16)
- */
-  if (dma16 != dma8)
-    {
-      if (sound_alloc_dma (dma16, "Jazz16 16 bit"))
-	{
-	  printk ("Jazz16: Can't allocate 16 bit DMA channel\n");
-	  Jazz16_detected = 0;
-	  return;
-	}
-    }
-  initialize_ProSonic16 ();
-}
-
-static void
-dsp_get_vers (struct address_info *hw_config)
-{
-  int             i;
-
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-  sb_osp = hw_config->osp;
-  sbc_major = sbc_minor = 0;
-  sb_dsp_command (0xe1);	/* Get version */
-
-  for (i = 100000; i; i--)
-    {
-      if (inb (DSP_DATA_AVAIL) & 0x80)
-	{
-	  if (sbc_major == 0)
-	    sbc_major = inb (DSP_READ);
-	  else
-	    {
-	      sbc_minor = inb (DSP_READ);
-	      break;
-	    }
-	}
-    }
-  restore_flags (flags);
-}
-
-long
-sb_dsp_init (long mem_start, struct address_info *hw_config)
-{
-  int             i;
-  int             ess_major = 0, ess_minor = 0;
-
-  int             mixer_type = 0;
-
-  if (sbc_major == 0)
-    dsp_get_vers (hw_config);
-
-  if (sbc_major == 0)
-    {
-      sb_reset_dsp ();
-      dsp_get_vers (hw_config);
-    }
-
-  if (sbc_major == 0)
-    {
-      printk ("\n\nFailed to get SB version (%x) - possible I/O conflict?\n\n",
-	      inb (DSP_DATA_AVAIL));
-      sbc_major = 1;
-    }
-
-  if (sbc_major == 2 || sbc_major == 3)
-    sb_duplex_midi = 1;
-
-  if (sbc_major == 4)
-    sb16 = 1;
-
-  if (sbc_major == 3 && sbc_minor == 1)
-    {
-
-/*
- * Try to detect ESS chips.
- */
-
-      sb_dsp_command (0xe7);	/*
-				 * Return identification bytes.
-				 */
-
-      for (i = 1000; i; i--)
-	{
-	  if (inb (DSP_DATA_AVAIL) & 0x80)
-	    {			/*
-				 * wait for Data Ready
-				 */
-	      if (ess_major == 0)
-		ess_major = inb (DSP_READ);
-	      else
-		{
-		  ess_minor = inb (DSP_READ);
-		  break;
-		}
-	    }
-	}
-    }
-
-  if (snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster", sb_osp) < 0)
-    printk ("sb_dsp: Can't allocate IRQ\n");;
-
-#ifdef CONFIG_AUDIO
-  if (sbc_major >= 3)
-    {
-      if (Jazz16_detected)
-	{
-	  if (Jazz16_detected == 2)
-	    sprintf (sb_dsp_operations.name, "SoundMan Wave %d.%d", sbc_major, sbc_minor);
-	  else
-	    sprintf (sb_dsp_operations.name, "MV Jazz16 %d.%d", sbc_major, sbc_minor);
-	  sb_dsp_operations.format_mask |= AFMT_S16_LE;		/* Hurrah, 16 bits          */
-	}
-      else
-#ifdef __SGNXPRO__
-      if (mixer_type == 2)
-	{
-	  sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
-	}
-      else
-#endif
-
-      if (sbc_major == 4)
-	{
-	  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 (ess_minor);
-	    }
-	}
-      else
-	{
-	  sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
-	}
-    }
-  else
-    {
-      sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
-    }
-
-  conf_printf (sb_dsp_operations.name, hw_config);
-
-  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;
-	dma16 = audio_devs[my_dev]->dmachan2 = hw_config->dma;
-	if (sound_alloc_dma (hw_config->dma, "SoundBlaster"))
-	  printk ("sb_dsp.c: Can't allocate DMA channel\n");
-      }
-    else
-      printk ("SB: Too many DSP devices available\n");
-#else
-  conf_printf ("SoundBlaster (configured without audio support)", hw_config);
-#endif
-
-#ifdef CONFIG_MIDI
-  if (!midi_disabled && !sb16)	/*
-				 * Midi don't work in the SB emulation mode *
-				 * of PAS, SB16 has better midi interface
-				 */
-    sb_midi_init (sbc_major);
-#endif
-
-  sb_dsp_ok = 1;
-  sb_reset_dsp ();
-
-  if (sb16 || hw_config->dma2 >= 0)
-    {
-      if (sb16_dsp_detect (hw_config))
-	{
-	  sb16_inited = 1;
-	  return sb16_dsp_init (mem_start, hw_config);
-	}
-    }
-  return mem_start;
-}
-
-void
-sb_dsp_unload (struct address_info *hw_config)
-{
-  sound_free_dma (dma8);
-
-  /* Free 16 bit dma (Jazz16)
-   */
-  if (Jazz16_detected != 0)
-    if (dma16 != dma8)
-      {
-	sound_free_dma (dma16);
-      }
-  snd_release_irq (sbc_irq);
-
-  if (AudioDrive && ess_mpu_irq)
-    {
-      snd_release_irq (ess_mpu_irq);
-    }
-
-  if (sb16_inited)
-    unload_sb16 (hw_config);
-}
-
-void
-sb_dsp_disable_midi (void)
-{
-  midi_disabled = 1;
-}
-
-
-#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c
--- v2.0.0/linux/drivers/sound/sb_midi.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/sb_midi.c	Sun Jun 30 11:44:14 1996
@@ -4,34 +4,18 @@
  * The low level driver for the SoundBlaster DS chips.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
 
 #include "sound_config.h"
 
-#if defined(CONFIG_SB) && defined(CONFIG_MIDI)
+#if defined(CONFIG_SBDSP) && defined(CONFIG_MIDI)
 
 #include "sb.h"
 #undef SB_TEST_IRQ
@@ -44,27 +28,6 @@
  * future version of this driver.
  */
 
-extern int      sb_dsp_ok;	/* Set to 1 after successful initialization */
-extern int      sbc_base;
-
-extern int      sb_midi_mode;
-extern int      sb_midi_busy;	/*
-
-
-				 * *  * * 1 if the process has output to MIDI
-				 *
-				 */
-extern int      sb_dsp_busy;
-extern int      sb_dsp_highspeed;
-
-extern volatile int sb_irq_mode;
-extern int      sb_duplex_midi;
-extern int      sb_intr_active;
-int             input_opened = 0;
-static int      my_dev;
-
-extern int     *sb_osp;
-
 void            (*midi_input_intr) (int dev, unsigned char data);
 
 static int
@@ -73,100 +36,69 @@
 	      void            (*output) (int dev)
 )
 {
-  int             ret;
+  sb_devc        *devc = midi_devs[dev]->devc;
+  unsigned long   flags;
+
+  if (devc == NULL)
+    return -(ENXIO);
 
-  if (!sb_dsp_ok)
+  save_flags (flags);
+  cli ();
+  if (devc->opened)
     {
-      printk ("SB Error: MIDI hardware not installed\n");
-      return -ENXIO;
+      restore_flags (flags);
+      return -(EBUSY);
     }
+  devc->opened = 1;
+  restore_flags (flags);
 
-  if (sb_midi_busy)
-    return -EBUSY;
+  devc->irq_mode = IMODE_MIDI;
 
-  if (mode != OPEN_WRITE && !sb_duplex_midi)
-    {
-      if (num_midis == 1)
-	printk ("SoundBlaster: Midi input not currently supported\n");
-      return -EPERM;
-    }
+  sb_dsp_reset (devc);
 
-  sb_midi_mode = NORMAL_MIDI;
-  if (mode != OPEN_WRITE)
+  if (!sb_dsp_command (devc, 0x35))	/* Start MIDI UART mode */
     {
-      if (sb_dsp_busy || sb_intr_active)
-	return -EBUSY;
-      sb_midi_mode = UART_MIDI;
+      devc->opened = 0;
+      return -(EIO);
     }
 
-  if (sb_dsp_highspeed)
-    {
-      printk ("SB Error: Midi output not possible during stereo or high speed audio\n");
-      return -EBUSY;
-    }
+  devc->intr_active = 1;
 
-  if (sb_midi_mode == UART_MIDI)
+  if (mode & OPEN_READ)
     {
-      sb_irq_mode = IMODE_MIDI;
-
-      sb_reset_dsp ();
-
-      if (!sb_dsp_command (0x35))
-	return -EIO;		/*
-				   * Enter the UART mode
-				 */
-      sb_intr_active = 1;
-
-      if ((ret = sb_get_irq ()) < 0)
-	{
-	  sb_reset_dsp ();
-	  return 0;		/*
-				 * IRQ not free
-				 */
-	}
-      input_opened = 1;
-      midi_input_intr = input;
+      devc->input_opened = 1;
+      devc->midi_input_intr = input;
     }
 
-  sb_midi_busy = 1;
-
   return 0;
 }
 
 static void
 sb_midi_close (int dev)
 {
-  if (sb_midi_mode == UART_MIDI)
-    {
-      sb_reset_dsp ();		/*
-				 * The only way to kill the UART mode
-				 */
-      sb_free_irq ();
-    }
-  sb_intr_active = 0;
-  sb_midi_busy = 0;
-  input_opened = 0;
+  sb_devc        *devc = midi_devs[dev]->devc;
+  unsigned long   flags;
+
+  if (devc == NULL)
+    return;
+
+  save_flags (flags);
+  cli ();
+  sb_dsp_reset (devc);
+  devc->intr_active = 0;
+  devc->input_opened = 0;
+  restore_flags (flags);
 }
 
 static int
 sb_midi_out (int dev, unsigned char midi_byte)
 {
-  unsigned long   flags;
+  sb_devc        *devc = midi_devs[dev]->devc;
 
-  if (sb_midi_mode == NORMAL_MIDI)
-    {
-      save_flags (flags);
-      cli ();
-      if (sb_dsp_command (0x38))
-	sb_dsp_command (midi_byte);
-      else
-	printk ("SB Error: Unable to send a MIDI byte\n");
-      restore_flags (flags);
-    }
-  else
-    sb_dsp_command (midi_byte);	/*
-				 * UART write
-				 */
+  if (devc == NULL)
+    return -(ENXIO);
+
+  sb_dsp_command (devc, midi_byte);
 
   return 1;
 }
@@ -174,43 +106,43 @@
 static int
 sb_midi_start_read (int dev)
 {
-  if (sb_midi_mode != UART_MIDI)
-    {
-      printk ("SoundBlaster: MIDI input not implemented.\n");
-      return -EPERM;
-    }
   return 0;
 }
 
 static int
 sb_midi_end_read (int dev)
 {
-  if (sb_midi_mode == UART_MIDI)
-    {
-      sb_reset_dsp ();
-      sb_intr_active = 0;
-    }
+  sb_devc        *devc = midi_devs[dev]->devc;
+
+  if (devc == NULL)
+    return -(ENXIO);
+
+  sb_dsp_reset (devc);
+  devc->intr_active = 0;
   return 0;
 }
 
 static int
 sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
 {
-  return -EPERM;
+  return -(EPERM);
 }
 
 void
-sb_midi_interrupt (int dummy)
+sb_midi_interrupt (sb_devc * devc)
 {
   unsigned long   flags;
   unsigned char   data;
 
+  if (devc == NULL)
+    return;
+
   save_flags (flags);
   cli ();
 
   data = inb (DSP_READ);
-  if (input_opened)
-    midi_input_intr (my_dev, data);
+  if (devc->input_opened)
+    devc->midi_input_intr (devc->my_mididev, data);
 
   restore_flags (flags);
 }
@@ -230,21 +162,18 @@
   sb_midi_out,
   sb_midi_start_read,
   sb_midi_end_read,
-  NULL,				/*
-				 * Kick
-				 */
-  NULL,				/*
-				 * command
-				 */
-  NULL,				/*
-				 * buffer_status
-				 */
+  NULL,
+  NULL,
+  NULL,
   NULL
 };
 
 void
-sb_midi_init (int model)
+sb_dsp_midi_init (sb_devc * devc)
 {
+  if (devc->model < 2)		/* No MIDI support for SB 1.x */
+    return;
+
   if (num_midis >= MAX_MIDI_DEV)
     {
       printk ("Sound: Too many midi devices detected\n");
@@ -252,8 +181,42 @@
     }
 
   std_midi_synth.midi_dev = num_midis;
-  my_dev = num_midis;
-  midi_devs[num_midis++] = &sb_midi_operations;
+  devc->my_mididev = num_midis;
+
+  std_midi_synth.midi_dev = devc->my_mididev = num_midis;
+
+
+  midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations)));
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (midi_devs[num_midis] == NULL)
+    {
+      printk ("sb MIDI: Failed to allocate memory\n");
+      return;
+    }
+
+  memcpy ((char *) midi_devs[num_midis], (char *) &sb_midi_operations,
+	  sizeof (struct midi_operations));
+
+  midi_devs[num_midis]->devc = devc;
+
+
+  midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations)));
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+
+  if (midi_devs[num_midis]->converter == NULL)
+    {
+      printk ("sb MIDI: Failed to allocate memory\n");
+      return;
+    }
+
+  memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth,
+	  sizeof (struct synth_operations));
+
+  num_midis++;
 }
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v2.0.0/linux/drivers/sound/sb_mixer.c	Sun Mar 24 22:50:21 1996
+++ linux/drivers/sound/sb_mixer.c	Sun Jun 30 11:44:14 1996
@@ -2,251 +2,100 @@
 /*
  * sound/sb_mixer.c
  *
- * The low level mixer driver for the SoundBlaster Pro and SB16 cards.
+ * The low level mixer driver for the SoundBlaster compatible cards.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
-/*
- * Modified:
- *      Hunyue Yau      Jan 6 1994
- *      Added code to support the Sound Galaxy NX Pro mixer.
- *
- */
 
 #include "sound_config.h"
 
-#if defined(CONFIG_SB)
+#if defined(CONFIG_SBDSP)
 #define __SB_MIXER_C__
 
 #include "sb.h"
 #include "sb_mixer.h"
-#undef SB_TEST_IRQ
-
-extern int      sbc_base;
-extern int      Jazz16_detected;
-extern int     *sb_osp;
-extern int      AudioDrive;
-
-static int      mixer_initialized = 0;
-
-static int      supported_rec_devices;
-static int      supported_devices;
-static int      recmask = 0;
-static int      mixer_model;
-static int      mixer_caps;
-static mixer_tab *iomap;
-
-void
-sb_setmixer (unsigned int port, unsigned int value)
-{
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-  outb ((unsigned char) (port & 0xff), MIXER_ADDR);	/*
-							   * Select register
-							 */
-  tenmicrosec (sb_osp);
-  outb ((unsigned char) (value & 0xff), MIXER_DATA);
-  tenmicrosec (sb_osp);
-  restore_flags (flags);
-}
-
-int
-sb_getmixer (unsigned int port)
-{
-  int             val;
-  unsigned long   flags;
-
-  save_flags (flags);
-  cli ();
-  outb ((unsigned char) (port & 0xff), MIXER_ADDR);	/*
-							   * Select register
-							 */
-  tenmicrosec (sb_osp);
-  val = inb (MIXER_DATA);
-  tenmicrosec (sb_osp);
-  restore_flags (flags);
 
-  return val;
-}
+void            sb_mixer_reset (sb_devc * devc);
 
 void
-sb_mixer_set_stereo (int mode)
+sb_mixer_set_stereo (sb_devc * devc, int mode)
 {
-  if (!mixer_initialized)
-    return;
-
-  sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
-			    | (mode ? STEREO_DAC : MONO_DAC)));
+  sb_setmixer (devc, OUT_FILTER, ((sb_getmixer (devc, OUT_FILTER) & ~STEREO_DAC)
+				  | (mode ? STEREO_DAC : MONO_DAC)));
 }
 
-/*
- * Returns:
- *      0       No mixer detected.
- *      1       Only a plain Sound Blaster Pro style mixer detected.
- *      2       The Sound Galaxy NX Pro mixer detected.
- */
 static int
-detect_mixer (void)
+detect_mixer (sb_devc * devc)
 {
-#ifdef __SGNXPRO__
-  int             oldbass, oldtreble;
-  extern int      sbc_major;
-
-#endif
-  int             retcode = 1;
-
   /*
    * Detect the mixer by changing parameters of two volume channels. If the
    * values read back match with the values written, the mixer is there (is
    * it?)
    */
-  sb_setmixer (FM_VOL, 0xff);
-  sb_setmixer (VOC_VOL, 0x33);
+  sb_setmixer (devc, FM_VOL, 0xff);
+  sb_setmixer (devc, VOC_VOL, 0x33);
 
-  if (sb_getmixer (FM_VOL) != 0xff)
-    return 0;			/*
-				 * No match
-				 */
-  if (sb_getmixer (VOC_VOL) != 0x33)
+  if (sb_getmixer (devc, FM_VOL) != 0xff)
+    return 0;
+  if (sb_getmixer (devc, VOC_VOL) != 0x33)
     return 0;
 
-#ifdef __SGNXPRO__
-  /* Attempt to detect the SG NX Pro by check for valid bass/treble
-     * registers.
-   */
-  oldbass = sb_getmixer (BASS_LVL);
-  oldtreble = sb_getmixer (TREBLE_LVL);
-
-  sb_setmixer (BASS_LVL, 0xaa);
-  sb_setmixer (TREBLE_LVL, 0x55);
-
-  if ((sb_getmixer (BASS_LVL) != 0xaa) ||
-      (sb_getmixer (TREBLE_LVL) != 0x55))
-    {
-      retcode = 1;		/* 1 == Only SB Pro detected */
-    }
-  else
-    retcode = 2;		/* 2 == SG NX Pro detected */
-  /* Restore register in either case since SG NX Pro has EEPROM with
-   * 'preferred' values stored.
-   */
-  sb_setmixer (BASS_LVL, oldbass);
-  sb_setmixer (TREBLE_LVL, oldtreble);
-
-  /*
-     * If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16.
-     * In this case it's good idea to disable the Disney Sound Source
-     * compatibility mode. It's useless and just causes noise every time the
-     * LPT-port is accessed.
-     *
-     * Also place the card into WSS mode.
-   */
-  if (sbc_major == 3)
-    {
-      outb (0x01, sbc_base + 0x1c);
-      outb (0x00, sbc_base + 0x1a);
-    }
-
-#endif
-  return retcode;
+  return 1;
 }
 
 static void
-change_bits (unsigned char *regval, int dev, int chn, int newval)
+change_bits (sb_devc * devc, unsigned char *regval, int dev, int chn, int newval)
 {
   unsigned char   mask;
   int             shift;
 
-  mask = (1 << (*iomap)[dev][chn].nbits) - 1;
-  newval = (int) ((newval * mask) + 50) / 100;	/*
-						 * Scale it
-						 */
+  mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1;
+  newval = (int) ((newval * mask) + 50) / 100;	/* Scale */
 
-  shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
+  shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1;
 
-  *regval &= ~(mask << shift);	/*
-				 * Filter out the previous value
-				 */
-  *regval |= (newval & mask) << shift;	/*
-					 * Set the new value
-					 */
+  *regval &= ~(mask << shift);	/* Mask out previous value */
+  *regval |= (newval & mask) << shift;	/* Set the new value */
 }
 
 static int
-sb_mixer_get (int dev)
+sb_mixer_get (sb_devc * devc, int dev)
 {
-  if (!((1 << dev) & supported_devices))
-    return -EINVAL;
+  if (!((1 << dev) & devc->supported_devices))
+    return -(EINVAL);
 
-  return levels[dev];
+  return devc->levels[dev];
 }
 
-static char     smw_mix_regs[] =	/* Left mixer registers */
-{
-  0x0b,				/* SOUND_MIXER_VOLUME */
-  0x0d,				/* SOUND_MIXER_BASS */
-  0x0d,				/* SOUND_MIXER_TREBLE */
-  0x05,				/* SOUND_MIXER_SYNTH */
-  0x09,				/* SOUND_MIXER_PCM */
-  0x00,				/* SOUND_MIXER_SPEAKER */
-  0x03,				/* SOUND_MIXER_LINE */
-  0x01,				/* SOUND_MIXER_MIC */
-  0x07,				/* SOUND_MIXER_CD */
-  0x00,				/* SOUND_MIXER_IMIX */
-  0x00,				/* SOUND_MIXER_ALTPCM */
-  0x00,				/* SOUND_MIXER_RECLEV */
-  0x00,				/* SOUND_MIXER_IGAIN */
-  0x00,				/* SOUND_MIXER_OGAIN */
-  0x00,				/* SOUND_MIXER_LINE1 */
-  0x00,				/* SOUND_MIXER_LINE2 */
-  0x00				/* SOUND_MIXER_LINE3 */
-};
-
 void
-smw_mixer_init (void)
+smw_mixer_init (sb_devc * devc)
 {
   int             i;
 
-  sb_setmixer (0x00, 0x18);	/* Mute unused (Telephone) line */
-  sb_setmixer (0x10, 0x38);	/* Config register 2 */
+  sb_setmixer (devc, 0x00, 0x18);	/* Mute unused (Telephone) line */
+  sb_setmixer (devc, 0x10, 0x38);	/* Config register 2 */
 
-  supported_devices = 0;
+  devc->supported_devices = 0;
   for (i = 0; i < sizeof (smw_mix_regs); i++)
     if (smw_mix_regs[i] != 0)
-      supported_devices |= (1 << i);
+      devc->supported_devices |= (1 << i);
 
-  supported_rec_devices = supported_devices &
+  devc->supported_rec_devices = devc->supported_devices &
     ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM |
       SOUND_MASK_VOLUME);
+
+  sb_mixer_reset (devc);
 }
 
 static int
-smw_mixer_set (int dev, int value)
+smw_mixer_set (sb_devc * devc, int dev, int value)
 {
   int             left = value & 0x000000ff;
   int             right = (value & 0x0000ff00) >> 8;
@@ -258,47 +107,47 @@
     right = 100;
 
   if (dev > 31)
-    return -EINVAL;
+    return -(EINVAL);
 
-  if (!(supported_devices & (1 << dev)))	/* Not supported */
-    return -EINVAL;
+  if (!(devc->supported_devices & (1 << dev)))	/* Not supported */
+    return -(EINVAL);
 
   switch (dev)
     {
     case SOUND_MIXER_VOLUME:
-      sb_setmixer (0x0b, 96 - (96 * left / 100));	/* 96=mute, 0=max */
-      sb_setmixer (0x0c, 96 - (96 * right / 100));
+      sb_setmixer (devc, 0x0b, 96 - (96 * left / 100));		/* 96=mute, 0=max */
+      sb_setmixer (devc, 0x0c, 96 - (96 * right / 100));
       break;
 
     case SOUND_MIXER_BASS:
     case SOUND_MIXER_TREBLE:
-      levels[dev] = left | (right << 8);
+      devc->levels[dev] = left | (right << 8);
 
       /* Set left bass and treble values */
-      val = ((levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4;
-      val |= ((levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f;
-      sb_setmixer (0x0d, val);
+      val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4;
+      val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f;
+      sb_setmixer (devc, 0x0d, val);
 
       /* Set right bass and treble values */
-      val = (((levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4;
-      val |= (((levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f;
-      sb_setmixer (0x0e, val);
+      val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4;
+      val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f;
+      sb_setmixer (devc, 0x0e, val);
       break;
 
     default:
       reg = smw_mix_regs[dev];
       if (reg == 0)
-	return -EINVAL;
-      sb_setmixer (reg, (24 - (24 * left / 100)) | 0x20);	/* 24=mute, 0=max */
-      sb_setmixer (reg + 1, (24 - (24 * right / 100)) | 0x40);
+	return -(EINVAL);
+      sb_setmixer (devc, reg, (24 - (24 * left / 100)) | 0x20);		/* 24=mute, 0=max */
+      sb_setmixer (devc, reg + 1, (24 - (24 * right / 100)) | 0x40);
     }
 
-  levels[dev] = left | (right << 8);
+  devc->levels[dev] = left | (right << 8);
   return left | (right << 8);
 }
 
 static int
-sb_mixer_set (int dev, int value)
+sb_mixer_set (sb_devc * devc, int dev, int value)
 {
   int             left = value & 0x000000ff;
   int             right = (value & 0x0000ff00) >> 8;
@@ -306,8 +155,8 @@
   int             regoffs;
   unsigned char   val;
 
-  if (Jazz16_detected == 2)
-    return smw_mixer_set (dev, value);
+  if (devc->model == MDL_SMW)
+    return smw_mixer_set (devc, dev, value);
 
   if (left > 100)
     left = 100;
@@ -315,67 +164,70 @@
     right = 100;
 
   if (dev > 31)
-    return -EINVAL;
+    return -(EINVAL);
 
-  if (!(supported_devices & (1 << dev)))	/*
+  if (!(devc->supported_devices & (1 << dev)))	/*
 						 * Not supported
 						 */
-    return -EINVAL;
+    return -(EINVAL);
 
-  regoffs = (*iomap)[dev][LEFT_CHN].regno;
+  regoffs = (*devc->iomap)[dev][LEFT_CHN].regno;
 
   if (regoffs == 0)
-    return -EINVAL;
+    return -(EINVAL);
 
-  val = sb_getmixer (regoffs);
-  change_bits (&val, dev, LEFT_CHN, left);
+  val = sb_getmixer (devc, regoffs);
+  change_bits (devc, &val, dev, LEFT_CHN, left);
 
-  levels[dev] = left | (left << 8);
+  devc->levels[dev] = left | (left << 8);
 
-  if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)	/*
+  if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs)	/*
 							 * Change register
 							 */
     {
-      sb_setmixer (regoffs, val);	/*
-					 * Save the old one
-					 */
-      regoffs = (*iomap)[dev][RIGHT_CHN].regno;
+      sb_setmixer (devc, regoffs, val);		/*
+						 * Save the old one
+						 */
+      regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno;
 
       if (regoffs == 0)
 	return left | (left << 8);	/*
 					 * Just left channel present
 					 */
 
-      val = sb_getmixer (regoffs);	/*
-					 * Read the new one
-					 */
+      val = sb_getmixer (devc, regoffs);	/*
+						   * Read the new one
+						 */
     }
 
-  change_bits (&val, dev, RIGHT_CHN, right);
+  change_bits (devc, &val, dev, RIGHT_CHN, right);
 
-  sb_setmixer (regoffs, val);
+  sb_setmixer (devc, regoffs, val);
 
-  levels[dev] = left | (right << 8);
+  devc->levels[dev] = left | (right << 8);
   return left | (right << 8);
 }
 
 static void
-set_recsrc (int src)
+set_recsrc (sb_devc * devc, int src)
 {
-  sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
+  sb_setmixer (devc, RECORD_SRC, (sb_getmixer (devc, RECORD_SRC) & ~7) | (src & 0x7));
 }
 
 static int
-set_recmask (int mask)
+set_recmask (sb_devc * devc, int mask)
 {
   int             devmask, i;
   unsigned char   regimageL, regimageR;
 
-  devmask = mask & supported_rec_devices;
+  devmask = mask & devc->supported_rec_devices;
 
-  switch (mixer_model)
+  switch (devc->model)
     {
-    case 3:
+    case MDL_SBPRO:
+    case MDL_ESS:
+    case MDL_JAZZ:
+    case MDL_SMW:
 
       if (devmask != SOUND_MASK_MIC &&
 	  devmask != SOUND_MASK_LINE &&
@@ -384,7 +236,7 @@
 				 * More than one devices selected. Drop the *
 				 * previous selection
 				 */
-	  devmask &= ~recmask;
+	  devmask &= ~devc->recmask;
 	}
 
       if (devmask != SOUND_MASK_MIC &&
@@ -398,33 +250,33 @@
 	}
 
 
-      if (devmask ^ recmask)	/*
-				 * Input source changed
-				 */
+      if (devmask ^ devc->recmask)	/*
+					   * Input source changed
+					 */
 	{
 	  switch (devmask)
 	    {
 
 	    case SOUND_MASK_MIC:
-	      set_recsrc (SRC_MIC);
+	      set_recsrc (devc, SRC__MIC);
 	      break;
 
 	    case SOUND_MASK_LINE:
-	      set_recsrc (SRC_LINE);
+	      set_recsrc (devc, SRC__LINE);
 	      break;
 
 	    case SOUND_MASK_CD:
-	      set_recsrc (SRC_CD);
+	      set_recsrc (devc, SRC__CD);
 	      break;
 
 	    default:
-	      set_recsrc (SRC_MIC);
+	      set_recsrc (devc, SRC__MIC);
 	    }
 	}
 
       break;
 
-    case 4:
+    case MDL_SB16:
       if (!devmask)
 	devmask = SOUND_MASK_MIC;
 
@@ -435,159 +287,155 @@
 	    regimageL |= sb16_recmasks_L[i];
 	    regimageR |= sb16_recmasks_R[i];
 	  }
-      sb_setmixer (SB16_IMASK_L, regimageL);
-      sb_setmixer (SB16_IMASK_R, regimageR);
+      sb_setmixer (devc, SB16_IMASK_L, regimageL);
+      sb_setmixer (devc, SB16_IMASK_R, regimageR);
       break;
     }
 
-  recmask = devmask;
-  return recmask;
+  devc->recmask = devmask;
+  return devc->recmask;
 }
 
 static int
 sb_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
 {
+  sb_devc        *devc = mixer_devs[dev]->devc;
+
   if (((cmd >> 8) & 0xff) == 'M')
     {
       if (_IOC_DIR (cmd) & _IOC_WRITE)
 	switch (cmd & 0xff)
 	  {
 	  case SOUND_MIXER_RECSRC:
-	    return snd_ioctl_return ((int *) arg, set_recmask (get_fs_long ((long *) arg)));
+	    return snd_ioctl_return ((int *) arg, set_recmask (devc, get_fs_long ((long *) arg)));
 	    break;
 
 	  default:
 
-	    return snd_ioctl_return ((int *) arg, sb_mixer_set (cmd & 0xff, get_fs_long ((long *) arg)));
+	    return snd_ioctl_return ((int *) arg, sb_mixer_set (devc, cmd & 0xff, get_fs_long ((long *) arg)));
 	  }
       else
-	switch (cmd & 0xff)	/*
-				 * Return parameters
-				 */
+	switch (cmd & 0xff)
 	  {
 
 	  case SOUND_MIXER_RECSRC:
-	    return snd_ioctl_return ((int *) arg, recmask);
+	    return snd_ioctl_return ((int *) arg, devc->recmask);
 	    break;
 
 	  case SOUND_MIXER_DEVMASK:
-	    return snd_ioctl_return ((int *) arg, supported_devices);
+	    return snd_ioctl_return ((int *) arg, devc->supported_devices);
 	    break;
 
 	  case SOUND_MIXER_STEREODEVS:
-	    if (Jazz16_detected)
-	      return snd_ioctl_return ((int *) arg, supported_devices);
+	    if (devc->model == MDL_JAZZ || devc->model == MDL_SMW)
+	      return snd_ioctl_return ((int *) arg, devc->supported_devices);
 	    else
-	      return snd_ioctl_return ((int *) arg, supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+	      return snd_ioctl_return ((int *) arg, devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
 	    break;
 
 	  case SOUND_MIXER_RECMASK:
-	    return snd_ioctl_return ((int *) arg, supported_rec_devices);
+	    return snd_ioctl_return ((int *) arg, devc->supported_rec_devices);
 	    break;
 
 	  case SOUND_MIXER_CAPS:
-	    return snd_ioctl_return ((int *) arg, mixer_caps);
+	    return snd_ioctl_return ((int *) arg, devc->mixer_caps);
 	    break;
 
 	  default:
-	    return snd_ioctl_return ((int *) arg, sb_mixer_get (cmd & 0xff));
+	    return snd_ioctl_return ((int *) arg, sb_mixer_get (devc, cmd & 0xff));
 	  }
     }
   else
-    return -EINVAL;
+    return -(EINVAL);
 }
 
 static struct mixer_operations sb_mixer_operations =
 {
+  "SB",
   "SoundBlaster",
   sb_mixer_ioctl
 };
 
 void
-sb_mixer_reset (void)
+sb_mixer_reset (sb_devc * devc)
 {
   int             i;
 
   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-    sb_mixer_set (i, levels[i]);
-  set_recmask (SOUND_MASK_MIC);
+    sb_mixer_set (devc, i, devc->levels[i]);
+  set_recmask (devc, SOUND_MASK_MIC);
 }
 
-/*
- * Returns a code depending on whether a SG NX Pro was detected.
- * 1 == Plain SB Pro
- * 2 == SG NX Pro detected.
- * 3 == SB16
- *
- * Used to update message.
- */
 int
-sb_mixer_init (int major_model)
+sb_mixer_init (sb_devc * devc)
 {
   int             mixer_type = 0;
 
-  sb_setmixer (0x00, 0);	/* Reset mixer */
+  sb_setmixer (devc, 0x00, 0);	/* Reset mixer */
 
-  if (!(mixer_type = detect_mixer ()))
+  if (!(mixer_type = detect_mixer (devc)))
     return 0;			/* No mixer. Why? */
 
-  mixer_initialized = 1;
-  mixer_model = major_model;
-
-  switch (major_model)
+  switch (devc->model)
     {
-    case 3:
-      mixer_caps = SOUND_CAP_EXCL_INPUT;
+    case MDL_SBPRO:
+    case MDL_JAZZ:
+      devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
+      devc->supported_devices = SBPRO_MIXER_DEVICES;
+      devc->supported_rec_devices = SBPRO_RECORDING_DEVICES;
+      devc->iomap = &sbpro_mix;
+      break;
 
-      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;
-	  iomap = &sbpro_mix;
-	  smw_mixer_init ();
-	  mixer_type = 1;
-	}
-      else
-#ifdef __SGNXPRO__
-      if (mixer_type == 2)	/* A SGNXPRO was detected */
-	{
-	  supported_devices = SGNXPRO_MIXER_DEVICES;
-	  supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
-	  iomap = &sgnxpro_mix;
-	}
-      else
-#endif
-	{
-	  supported_devices = SBPRO_MIXER_DEVICES;
-	  supported_rec_devices = SBPRO_RECORDING_DEVICES;
-	  iomap = &sbpro_mix;
-	  mixer_type = 1;
-	}
+    case MDL_ESS:
+      devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
+      devc->supported_devices = ES688_MIXER_DEVICES;
+      devc->supported_rec_devices = ES688_RECORDING_DEVICES;
+      devc->iomap = &es688_mix;
       break;
 
-    case 4:
-      mixer_caps = 0;
-      supported_devices = SB16_MIXER_DEVICES;
-      supported_rec_devices = SB16_RECORDING_DEVICES;
-      iomap = &sb16_mix;
-      mixer_type = 3;
+    case MDL_SMW:
+      devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
+      devc->supported_devices = 0;
+      devc->supported_rec_devices = 0;
+      devc->iomap = &sbpro_mix;
+      smw_mixer_init (devc);
+      break;
+
+    case MDL_SB16:
+      devc->mixer_caps = 0;
+      devc->supported_devices = SB16_MIXER_DEVICES;
+      devc->supported_rec_devices = SB16_RECORDING_DEVICES;
+      devc->iomap = &sb16_mix;
       break;
 
     default:
-      printk ("SB Warning: Unsupported mixer type\n");
+      printk ("SB Warning: Unsupported mixer type %d\n", devc->model);
       return 0;
     }
 
-  if (num_mixers < MAX_MIXER_DEV)
-    mixer_devs[num_mixers++] = &sb_mixer_operations;
-  sb_mixer_reset ();
-  return mixer_type;
+  if (num_mixers >= MAX_MIXER_DEV)
+    return 0;
+
+
+  mixer_devs[num_mixers] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations)));
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (mixer_devs[num_mixers] == NULL)
+    {
+      printk ("sb_mixer: Can't allocate memory\n");
+      return 0;
+    }
+
+  memcpy ((char *) mixer_devs[num_mixers], (char *) &sb_mixer_operations,
+	  sizeof (struct mixer_operations));
+
+  mixer_devs[num_mixers]->devc = devc;
+  memcpy ((char *) devc->levels, (char *) &default_levels, sizeof (default_levels));
+
+  sb_mixer_reset (devc);
+  devc->my_mixerdev = num_mixers++;
+  return 1;
 }
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h
--- v2.0.0/linux/drivers/sound/sb_mixer.h	Sun Mar 24 22:49:43 1996
+++ linux/drivers/sound/sb_mixer.h	Sun Jun 30 11:43:39 1996
@@ -4,27 +4,11 @@
  * Definitions for the SB Pro and SB16 mixers
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 
 /*
@@ -109,16 +93,6 @@
 #define LEFT_CHN	0
 #define RIGHT_CHN	1
 
-struct mixer_def {
-	unsigned int regno: 8;
-	unsigned int bitoffs:4;
-	unsigned int nbits:4;
-};
-
-
-typedef struct mixer_def mixer_tab[32][2];
-typedef struct mixer_def mixer_ent;
-
 #define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r)	\
 	{{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}}
 
@@ -197,7 +171,7 @@
 			     higher than with SB Pro. This improves the
 			     sound quality */
 
-static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+static unsigned short default_levels[SOUND_MIXER_NRDEVICES] =
 {
   0x2020,			/* Master Volume */
   0x4b4b,			/* Bass */
@@ -220,7 +194,7 @@
 
 #else  /* If the user selected just plain SB Pro */
 
-static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+static unsigned short default_levels[SOUND_MIXER_NRDEVICES] =
 {
   0x5a5a,			/* Master Volume */
   0x4b4b,			/* Bass */
@@ -278,12 +252,33 @@
 	0x00	/* SOUND_MIXER_OGAIN	*/
 };
 
+static char     smw_mix_regs[] =	/* Left mixer registers */
+{
+  0x0b,				/* SOUND_MIXER_VOLUME */
+  0x0d,				/* SOUND_MIXER_BASS */
+  0x0d,				/* SOUND_MIXER_TREBLE */
+  0x05,				/* SOUND_MIXER_SYNTH */
+  0x09,				/* SOUND_MIXER_PCM */
+  0x00,				/* SOUND_MIXER_SPEAKER */
+  0x03,				/* SOUND_MIXER_LINE */
+  0x01,				/* SOUND_MIXER_MIC */
+  0x07,				/* SOUND_MIXER_CD */
+  0x00,				/* SOUND_MIXER_IMIX */
+  0x00,				/* SOUND_MIXER_ALTPCM */
+  0x00,				/* SOUND_MIXER_RECLEV */
+  0x00,				/* SOUND_MIXER_IGAIN */
+  0x00,				/* SOUND_MIXER_OGAIN */
+  0x00,				/* SOUND_MIXER_LINE1 */
+  0x00,				/* SOUND_MIXER_LINE2 */
+  0x00				/* SOUND_MIXER_LINE3 */
+};
+
 /*
  *	Recording sources (SB Pro)
  */
 
-#define SRC_MIC         1	/* Select Microphone recording source */
-#define SRC_CD          3	/* Select CD recording source */
-#define SRC_LINE        7	/* Use Line-in for recording source */
+#define SRC__MIC         1	/* Select Microphone recording source */
+#define SRC__CD          3	/* Select CD recording source */
+#define SRC__LINE        7	/* Use Line-in for recording source */
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v2.0.0/linux/drivers/sound/sequencer.c	Mon Jun  3 16:46:56 1996
+++ linux/drivers/sound/sequencer.c	Sun Jun 30 11:44:16 1996
@@ -4,27 +4,11 @@
  * The sequencer personality manager.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -51,7 +35,7 @@
 /*
  * The seq_mode gives the operating mode of the sequencer:
  *      1 = level1 (the default)
- *      2 = level2 (extended capabilities)
+ *      2 = level2 (extended capabilites)
  */
 
 #define SEQ_1	1
@@ -124,25 +108,25 @@
 	   1 : 0))
 	{
 	  restore_flags (flags);
-	  return -EAGAIN;
+	  return -(EAGAIN);
 	}
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (pre_event_timeout)
-	  current_set_timeout (tl = jiffies + (pre_event_timeout));
+	  current_set_timeout (tlimit = jiffies + (pre_event_timeout));
 	else
-	  tl = (unsigned long) -1;
-	midi_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	midi_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&midi_sleeper);
-	if (!(midi_sleep_flag.mode & WK_WAKEUP))
+	if (!(midi_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      midi_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      midi_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	midi_sleep_flag.mode &= ~WK_SLEEP;
+	midi_sleep_flag.flags &= ~WK_SLEEP;
       };
 
       if (!iqlen)
@@ -155,7 +139,7 @@
   while (iqlen && c >= ev_len)
     {
 
-      memcpy_tofs (&((buf)[p]), (char *) &iqueue[iqhead * IEV_SZ], ev_len);
+      memcpy_tofs (&(buf)[p], (char *) &iqueue[iqhead * IEV_SZ], ev_len);
       p += ev_len;
       c -= ev_len;
 
@@ -198,10 +182,10 @@
   iqlen++;
   iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
 
-  if ((midi_sleep_flag.mode & WK_SLEEP))
+  if ((midi_sleep_flag.flags & WK_SLEEP))
     {
       {
-	midi_sleep_flag.mode = WK_WAKEUP;
+	midi_sleep_flag.flags = WK_WAKEUP;
 	module_wake_up (&midi_sleeper);
       };
     }
@@ -274,7 +258,7 @@
   DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count));
 
   if (mode == OPEN_READ)
-    return -EIO;
+    return -(EIO);
 
   if (dev)
     return pmgr_write (dev - 1, file, buf, count);
@@ -283,7 +267,7 @@
 
   while (c >= 4)
     {
-      memcpy_fromfs ((char *) event_rec, &((buf)[p]), 4);
+      memcpy_fromfs ((char *) event_rec, &(buf)[p], 4);
       ev_code = event_rec[0];
 
       if (ev_code == SEQ_FULLSIZE)
@@ -292,10 +276,10 @@
 
 	  dev = *(unsigned short *) &event_rec[2];
 	  if (dev < 0 || dev >= max_synthdev)
-	    return -ENXIO;
+	    return -(ENXIO);
 
 	  if (!(synth_open_mask & (1 << dev)))
-	    return -ENXIO;
+	    return -(ENXIO);
 
 	  err = synth_devs[dev]->load_patch (dev, *(short *) &event_rec[0], buf, p + 4, c, 0);
 	  if (err < 0)
@@ -309,7 +293,7 @@
 	  if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED)
 	    {
 	      printk ("Sequencer: Invalid level 2 event %x\n", ev_code);
-	      return -EINVAL;
+	      return -(EINVAL);
 	    }
 
 	  ev_size = 8;
@@ -321,7 +305,7 @@
 	      return count - c;
 	    }
 
-	  memcpy_fromfs ((char *) &event_rec[4], &((buf)[p + 4]), 4);
+	  memcpy_fromfs ((char *) &event_rec[4], &(buf)[p + 4], 4);
 
 	}
       else
@@ -329,7 +313,7 @@
 	  if (seq_mode == SEQ_2)
 	    {
 	      printk ("Sequencer: 4 byte event in level 2 mode\n");
-	      return -EINVAL;
+	      return -(EINVAL);
 	    }
 	  ev_size = 4;
 	}
@@ -345,7 +329,7 @@
 	      if (dev >= max_mididev)
 		{
 		  printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev);
-		  return -ENXIO;
+		  return -(ENXIO);
 		}
 
 	      mode = file->mode & O_ACCMODE;
@@ -373,7 +357,7 @@
 
 	  if (!processed && (file->flags & (O_NONBLOCK) ?
 			     1 : 0))
-	    return -EAGAIN;
+	    return -(EAGAIN);
 	  else
 	    return processed;
 	}
@@ -404,15 +388,15 @@
 				 * Give chance to drain the queue
 				 */
 
-  if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.mode & WK_SLEEP))
+  if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.flags & WK_SLEEP))
     {
       /*
        * Sleep until there is enough space on the queue
        */
 
-      seq_sleep_flag.mode = WK_SLEEP;
+      seq_sleep_flag.flags = WK_SLEEP;
       module_interruptible_sleep_on (&seq_sleeper);
-      seq_sleep_flag.mode &= ~WK_SLEEP;;
+      seq_sleep_flag.flags &= ~WK_SLEEP;;
     }
 
   if (qlen >= SEQ_MAX_QUEUE)
@@ -435,10 +419,10 @@
   int             dev = q[2];
 
   if (dev < 0 || dev >= max_synthdev)
-    return -ENXIO;
+    return -(ENXIO);
 
   if (!(synth_open_mask & (1 << dev)))
-    return -ENXIO;
+    return -(ENXIO);
 
   switch (q[1])
     {
@@ -475,7 +459,7 @@
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 
   return 0;
@@ -710,10 +694,10 @@
 
 	      save_flags (flags);
 	      cli ();
-	      if ((seq_sleep_flag.mode & WK_SLEEP))
+	      if ((seq_sleep_flag.flags & WK_SLEEP))
 		{
 		  {
-		    seq_sleep_flag.mode = WK_WAKEUP;
+		    seq_sleep_flag.flags = WK_WAKEUP;
 		    module_wake_up (&seq_sleeper);
 		  };
 		}
@@ -750,10 +734,10 @@
 
 	      save_flags (flags);
 	      cli ();
-	      if ((seq_sleep_flag.mode & WK_SLEEP))
+	      if ((seq_sleep_flag.flags & WK_SLEEP))
 		{
 		  {
-		    seq_sleep_flag.mode = WK_WAKEUP;
+		    seq_sleep_flag.flags = WK_WAKEUP;
 		    module_wake_up (&seq_sleeper);
 		  };
 		}
@@ -886,10 +870,10 @@
 
 	      save_flags (flags);
 	      cli ();
-	      if ((seq_sleep_flag.mode & WK_SLEEP))
+	      if ((seq_sleep_flag.flags & WK_SLEEP))
 		{
 		  {
-		    seq_sleep_flag.mode = WK_WAKEUP;
+		    seq_sleep_flag.flags = WK_WAKEUP;
 		    module_wake_up (&seq_sleeper);
 		  };
 		}
@@ -927,7 +911,7 @@
 	  dev = q[2];
 
 	  if (dev < 0 || dev >= num_midis)
-	     break;
+	    break;
 
 	  if (!midi_devs[dev]->putc (dev, q[1]))
 	    {
@@ -946,7 +930,7 @@
 
     case SEQ_ECHO:
       seq_copy_to_input (q, 4);	/*
-				   * Echo back to the process
+				 * Echo back to the process
 				 */
       break;
 
@@ -1025,10 +1009,10 @@
 
       save_flags (flags);
       cli ();
-      if ((seq_sleep_flag.mode & WK_SLEEP))
+      if ((seq_sleep_flag.flags & WK_SLEEP))
 	{
 	  {
-	    seq_sleep_flag.mode = WK_WAKEUP;
+	    seq_sleep_flag.flags = WK_WAKEUP;
 	    module_wake_up (&seq_sleeper);
 	  };
 	}
@@ -1095,13 +1079,13 @@
   if (!sequencer_ok)
     {
       printk ("Soundcard: Sequencer not initialized\n");
-      return -ENXIO;
+      return -(ENXIO);
     }
 
   if (dev)			/* Patch manager device */
     {
       printk ("Patch manager interface is currently broken. Sorry\n");
-      return -ENXIO;
+      return -(ENXIO);
     }
 
   save_flags (flags);
@@ -1110,7 +1094,7 @@
     {
       printk ("Sequencer busy\n");
       restore_flags (flags);
-      return -EBUSY;
+      return -(EBUSY);
     }
   sequencer_busy = 1;
   restore_flags (flags);
@@ -1150,7 +1134,7 @@
 	{
 	  printk ("sequencer: No timer for level 2\n");
 	  sequencer_busy = 0;
-	  return -ENXIO;
+	  return -(ENXIO);
 	}
       setup_mode2 ();
     }
@@ -1160,11 +1144,11 @@
       {
 	printk ("Sequencer: No Midi devices. Input not possible\n");
 	sequencer_busy = 0;
-	return -ENXIO;
+	return -(ENXIO);
       }
 
   if (!max_synthdev && !max_mididev)
-    return -ENXIO;
+    return -(ENXIO);
 
   synth_open_mask = 0;
 
@@ -1217,8 +1201,8 @@
       tmr->open (tmr_no, seq_mode);
     }
 
-  seq_sleep_flag.mode = WK_NONE;
-  midi_sleep_flag.mode = WK_NONE;
+  seq_sleep_flag.flags = WK_NONE;
+  midi_sleep_flag.flags = WK_NONE;
   output_treshold = SEQ_MAX_QUEUE / 2;
 
   for (i = 0; i < num_synths; i++)
@@ -1256,20 +1240,20 @@
 	{
 
 	  {
-	    unsigned long   tl;
+	    unsigned long   tlimit;
 
 	    if (HZ / 10)
-	      current_set_timeout (tl = jiffies + (HZ / 10));
+	      current_set_timeout (tlimit = jiffies + (HZ / 10));
 	    else
-	      tl = (unsigned long) -1;
-	    seq_sleep_flag.mode = WK_SLEEP;
+	      tlimit = (unsigned long) -1;
+	    seq_sleep_flag.flags = WK_SLEEP;
 	    module_interruptible_sleep_on (&seq_sleeper);
-	    if (!(seq_sleep_flag.mode & WK_WAKEUP))
+	    if (!(seq_sleep_flag.flags & WK_WAKEUP))
 	      {
-		if (jiffies >= tl)
-		  seq_sleep_flag.mode |= WK_TIMEOUT;
+		if (jiffies >= tlimit)
+		  seq_sleep_flag.flags |= WK_TIMEOUT;
 	      }
-	    seq_sleep_flag.mode &= ~WK_SLEEP;
+	    seq_sleep_flag.flags &= ~WK_SLEEP;
 	  };
 	}
     }
@@ -1352,24 +1336,24 @@
 
   save_flags (flags);
   cli ();
-  if (qlen && !(seq_sleep_flag.mode & WK_SLEEP))
+  if (qlen && !(seq_sleep_flag.flags & WK_SLEEP))
     {
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (HZ)
-	  current_set_timeout (tl = jiffies + (HZ));
+	  current_set_timeout (tlimit = jiffies + (HZ));
 	else
-	  tl = (unsigned long) -1;
-	seq_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	seq_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&seq_sleeper);
-	if (!(seq_sleep_flag.mode & WK_WAKEUP))
+	if (!(seq_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      seq_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      seq_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	seq_sleep_flag.mode &= ~WK_SLEEP;
+	seq_sleep_flag.flags &= ~WK_SLEEP;
       };
     }
   restore_flags (flags);
@@ -1401,20 +1385,20 @@
     {
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (4)
-	  current_set_timeout (tl = jiffies + (4));
+	  current_set_timeout (tlimit = jiffies + (4));
 	else
-	  tl = (unsigned long) -1;
-	seq_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	seq_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&seq_sleeper);
-	if (!(seq_sleep_flag.mode & WK_WAKEUP))
+	if (!(seq_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      seq_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      seq_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	seq_sleep_flag.mode &= ~WK_SLEEP;
+	seq_sleep_flag.flags &= ~WK_SLEEP;
       };
       n--;
     }
@@ -1493,11 +1477,11 @@
 
   save_flags (flags);
   cli ();
-  if ((seq_sleep_flag.mode & WK_SLEEP))
+  if ((seq_sleep_flag.flags & WK_SLEEP))
     {
       /*      printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */
       {
-	seq_sleep_flag.mode = WK_WAKEUP;
+	seq_sleep_flag.flags = WK_WAKEUP;
 	module_wake_up (&seq_sleeper);
       };
     }
@@ -1546,25 +1530,25 @@
     case SNDCTL_TMR_METRONOME:
     case SNDCTL_TMR_SOURCE:
       if (dev)			/* Patch manager */
-	return -EIO;
+	return -(EIO);
 
       if (seq_mode != SEQ_2)
-	return -EINVAL;
+	return -(EINVAL);
       return tmr->ioctl (tmr_no, cmd, arg);
       break;
 
     case SNDCTL_TMR_SELECT:
       if (dev)			/* Patch manager */
-	return -EIO;
+	return -(EIO);
 
       if (seq_mode != SEQ_2)
-	return -EINVAL;
+	return -(EINVAL);
       pending_timer = get_fs_long ((long *) arg);
 
       if (pending_timer < 0 || pending_timer >= num_sound_timers)
 	{
 	  pending_timer = -1;
-	  return -EINVAL;
+	  return -(EINVAL);
 	}
 
       return snd_ioctl_return ((int *) arg, pending_timer);
@@ -1578,14 +1562,14 @@
       if (dev)			/*
 				 * Patch manager
 				 */
-	return -EIO;
+	return -(EIO);
 
       if (mode == OPEN_READ)
 	return 0;
       while (qlen && !current_got_fatal_signal ())
 	seq_sync ();
       if (qlen)
-	return -EINTR;
+	return -(EINTR);
       else
 	return 0;
       break;
@@ -1594,7 +1578,7 @@
       if (dev)			/*
 				 * Patch manager
 				 */
-	return -EIO;
+	return -(EIO);
 
       seq_reset ();
       return 0;
@@ -1604,11 +1588,11 @@
       if (dev)			/*
 				 * Patch manager
 				 */
-	return -EIO;
+	return -(EIO);
 
       midi_dev = get_fs_long ((long *) arg);
       if (midi_dev >= max_mididev)
-	return -ENXIO;
+	return -(ENXIO);
 
       if (!midi_opened[midi_dev])
 	{
@@ -1630,7 +1614,7 @@
       if (dev)			/*
 				 * Patch manager
 				 */
-	return -EIO;
+	return -(EIO);
 
       if (mode == OPEN_WRITE)
 	return 0;
@@ -1646,7 +1630,7 @@
 
     case SNDCTL_SEQ_CTRLRATE:
       if (dev)			/* Patch manager */
-	return -EIO;
+	return -(EIO);
 
       /*
        * If *arg == 0, just return the current rate
@@ -1655,7 +1639,7 @@
 	return tmr->ioctl (tmr_no, cmd, arg);
 
       if (get_fs_long ((long *) arg) != 0)
-	return -EINVAL;
+	return -(EINVAL);
 
       return snd_ioctl_return ((int *) arg, HZ);
       break;
@@ -1667,12 +1651,12 @@
 	dev = get_fs_long ((long *) arg);
 	if (dev < 0 || dev >= num_synths)
 	  {
-	    return -ENXIO;
+	    return -(ENXIO);
 	  }
 
 	if (!(synth_open_mask & (1 << dev)) && !orig_dev)
 	  {
-	    return -EBUSY;
+	    return -(EBUSY);
 	  }
 
 	if (!orig_dev && pmgr_present[dev])
@@ -1696,10 +1680,10 @@
 	int             dev = get_fs_long ((long *) arg);
 
 	if (dev < 0 || dev >= num_synths)
-	  return -ENXIO;
+	  return -(ENXIO);
 
 	if (!(synth_open_mask & (1 << dev)) && !orig_dev)
-	  return -EBUSY;
+	  return -(EBUSY);
 
 	return snd_ioctl_return ((int *) arg, synth_devs[dev]->ioctl (dev, cmd, arg));
       }
@@ -1710,10 +1694,10 @@
 	int             dev = get_fs_long ((long *) arg);
 
 	if (dev < 0 || dev >= num_synths)
-	  return -ENXIO;
+	  return -(ENXIO);
 
 	if (!(synth_open_mask & (1 << dev)))
-	  return -ENXIO;
+	  return -(ENXIO);
 
 	synth_devs[dev]->ioctl (dev, cmd, arg);
 	return 0;
@@ -1725,14 +1709,14 @@
 	struct synth_info inf;
 	int             dev;
 
-	memcpy_fromfs ((char *) &inf, &(((char *) arg)[0]), sizeof (inf));
+	memcpy_fromfs ((char *) &inf, &((char *) arg)[0], sizeof (inf));
 	dev = inf.device;
 
 	if (dev < 0 || dev >= max_synthdev)
-	  return -ENXIO;
+	  return -(ENXIO);
 
 	if (!(synth_open_mask & (1 << dev)) && !orig_dev)
-	  return -EBUSY;
+	  return -(EBUSY);
 
 	return synth_devs[dev]->ioctl (dev, cmd, arg);
       }
@@ -1743,7 +1727,7 @@
 	struct seq_event_rec event_rec;
 	unsigned long   flags;
 
-	memcpy_fromfs ((char *) &event_rec, &(((char *) arg)[0]), sizeof (event_rec));
+	memcpy_fromfs ((char *) &event_rec, &((char *) arg)[0], sizeof (event_rec));
 
 	save_flags (flags);
 	cli ();
@@ -1759,13 +1743,13 @@
 	struct midi_info inf;
 	int             dev;
 
-	memcpy_fromfs ((char *) &inf, &(((char *) arg)[0]), sizeof (inf));
+	memcpy_fromfs ((char *) &inf, &((char *) arg)[0], sizeof (inf));
 	dev = inf.device;
 
 	if (dev < 0 || dev >= max_mididev)
-	  return -ENXIO;
+	  return -(ENXIO);
 
-	memcpy_tofs ((&((char *) arg)[0]), (char *) &(midi_devs[dev]->info), sizeof (inf));
+	memcpy_tofs (&((char *) arg)[0], (char *) &(midi_devs[dev]->info), sizeof (inf));
 	return 0;
       }
       break;
@@ -1775,35 +1759,35 @@
 	struct patmgr_info *inf;
 	int             dev, err;
 
-	if ((inf = (struct patmgr_info *) kmalloc (sizeof (*inf), GFP_KERNEL)) == NULL)
+	if ((inf = (struct patmgr_info *) vmalloc (sizeof (*inf))) == NULL)
 	  {
 	    printk ("patmgr: Can't allocate memory for a message\n");
-	    return -EIO;
+	    return -(EIO);
 	  }
 
-	memcpy_fromfs ((char *) inf, &(((char *) arg)[0]), sizeof (*inf));
+	memcpy_fromfs ((char *) inf, &((char *) arg)[0], sizeof (*inf));
 	dev = inf->device;
 
 	if (dev < 0 || dev >= num_synths)
 	  {
-	    kfree (inf);
-	    return -ENXIO;
+	    vfree (inf);
+	    return -(ENXIO);
 	  }
 
 	if (!synth_devs[dev]->pmgr_interface)
 	  {
-	    kfree (inf);
-	    return -ENXIO;
+	    vfree (inf);
+	    return -(ENXIO);
 	  }
 
 	if ((err = synth_devs[dev]->pmgr_interface (dev, inf)) == -1)
 	  {
-	    kfree (inf);
+	    vfree (inf);
 	    return err;
 	  }
 
-	memcpy_tofs ((&((char *) arg)[0]), (char *) inf, sizeof (*inf));
-	kfree (inf);
+	memcpy_tofs (&((char *) arg)[0], (char *) inf, sizeof (*inf));
+	vfree (inf);
 	return 0;
       }
       break;
@@ -1813,35 +1797,35 @@
 	struct patmgr_info *inf;
 	int             dev, err;
 
-	if ((inf = (struct patmgr_info *) kmalloc (sizeof (*inf), GFP_KERNEL)) == NULL)
+	if ((inf = (struct patmgr_info *) vmalloc (sizeof (*inf))) == NULL)
 	  {
 	    printk ("patmgr: Can't allocate memory for a message\n");
-	    return -EIO;
+	    return -(EIO);
 	  }
 
-	memcpy_fromfs ((char *) inf, &(((char *) arg)[0]), sizeof (*inf));
+	memcpy_fromfs ((char *) inf, &((char *) arg)[0], sizeof (*inf));
 	dev = inf->device;
 
 	if (dev < 0 || dev >= num_synths)
 	  {
-	    kfree (inf);
-	    return -ENXIO;
+	    vfree (inf);
+	    return -(ENXIO);
 	  }
 
 	if (!pmgr_present[dev])
 	  {
-	    kfree (inf);
-	    return -ESRCH;
+	    vfree (inf);
+	    return -(ESRCH);
 	  }
 
 	if ((err = pmgr_access (dev, inf)) < 0)
 	  {
-	    kfree (inf);
+	    vfree (inf);
 	    return err;
 	  }
 
-	memcpy_tofs ((&((char *) arg)[0]), (char *) inf, sizeof (*inf));
-	kfree (inf);
+	memcpy_tofs (&((char *) arg)[0], (char *) inf, sizeof (*inf));
+	vfree (inf);
 	return 0;
       }
       break;
@@ -1853,7 +1837,7 @@
 	if (dev)		/*
 				 * Patch manager
 				 */
-	  return -EIO;
+	  return -(EIO);
 
 	if (tmp < 1)
 	  tmp = 1;
@@ -1881,20 +1865,20 @@
       if (dev)			/*
 				 * Patch manager
 				 */
-	return -EIO;
+	return -(EIO);
 
       if (mode == OPEN_READ)
-	return -EIO;
+	return -(EIO);
 
       if (!synth_devs[0])
-	return -ENXIO;
+	return -(ENXIO);
       if (!(synth_open_mask & (1 << 0)))
-	return -ENXIO;
+	return -(ENXIO);
       return synth_devs[0]->ioctl (0, cmd, arg);
       break;
     }
 
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 int
@@ -1912,7 +1896,7 @@
       if (!iqlen)
 	{
 
-	  midi_sleep_flag.mode = WK_SLEEP;
+	  midi_sleep_flag.flags = WK_SLEEP;
 	  module_select_wait (&midi_sleeper, wait);
 	  restore_flags (flags);
 	  return 0;
@@ -1927,7 +1911,7 @@
       if ((SEQ_MAX_QUEUE - qlen) < output_treshold)
 	{
 
-	  seq_sleep_flag.mode = WK_SLEEP;
+	  seq_sleep_flag.flags = WK_SLEEP;
 	  module_select_wait (&seq_sleeper, wait);
 	  restore_flags (flags);
 	  return 0;
@@ -2035,33 +2019,31 @@
 }
 
 
-long
-sequencer_init (long mem_start)
+void
+sequencer_init (void)
 {
 
 
-  queue = (unsigned char *) (sound_mem_blocks[sound_num_blocks] = kmalloc (SEQ_MAX_QUEUE * EV_SZ, GFP_KERNEL));
-  if (sound_num_blocks < 1024)
-    sound_num_blocks++;;
+  queue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * EV_SZ));
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
   if (queue == NULL)
     {
       printk ("Sound: Can't allocate memory for sequencer output queue\n");
-      return mem_start;
+      return;
     }
 
 
-  iqueue = (unsigned char *) (sound_mem_blocks[sound_num_blocks] = kmalloc (SEQ_MAX_QUEUE * IEV_SZ, GFP_KERNEL));
-  if (sound_num_blocks < 1024)
-    sound_num_blocks++;;
+  iqueue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * IEV_SZ));
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
   if (queue == NULL)
     {
       printk ("Sound: Can't allocate memory for sequencer input queue\n");
-      return mem_start;
+      return;
     }
 
   sequencer_ok = 1;
-
-  return mem_start;
 }
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v2.0.0/linux/drivers/sound/sound_calls.h	Sun Mar 24 22:49:43 1996
+++ linux/drivers/sound/sound_calls.h	Sun Jun 30 11:43:39 1996
@@ -11,7 +11,7 @@
 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, caddr_t arg, int local);
-long DMAbuf_init(long mem_start);
+void DMAbuf_init(void);
 int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
 int DMAbuf_open_dma (int dev);
 void DMAbuf_close_dma (int dev);
@@ -32,7 +32,7 @@
 int audio_ioctl (int dev, struct fileinfo *file,
 	   unsigned int cmd, caddr_t arg);
 int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
-long audio_init (long mem_start);
+void audio_init (void);
 
 int audio_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
 
@@ -47,7 +47,7 @@
 int sequencer_ioctl (int dev, struct fileinfo *file,
 	   unsigned int cmd, caddr_t arg);
 int sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
-long sequencer_init (long mem_start);
+void sequencer_init (void);
 void sequencer_timer(unsigned long dummy);
 int note_to_freq(int note_num);
 unsigned long compute_finetune(unsigned long base_freq, int bend, int range);
@@ -68,7 +68,7 @@
 	   unsigned int cmd, caddr_t arg);
 int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
 void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
-long MIDIbuf_init(long mem_start);
+void MIDIbuf_init(void);
 
 int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
 
@@ -83,7 +83,7 @@
 void request_sound_timer (int count);
 void sound_stop_timer(void);
 int snd_ioctl_return(int *addr, int value);
-int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, void*, struct pt_regs *), char *name, int *osp);
+int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp);
 void snd_release_irq(int vect);
 void sound_dma_malloc(int dev);
 void sound_dma_free(int dev);
@@ -98,51 +98,33 @@
 int sound_ioctl_sw (int dev, struct fileinfo *file,
 	     unsigned int cmd, caddr_t arg);
 
-/*	From sb_dsp.c	*/
-int sb_dsp_detect (struct address_info *hw_config);
-long sb_dsp_init (long mem_start, struct address_info *hw_config);
-void sb_dsp_disable_midi(void);
-int sb_get_irq(void);
-void sb_free_irq(void);
-int sb_dsp_command (unsigned char val);
-int sb_reset_dsp (void);
-void sb_dsp_unload(struct address_info *);
-
-/*	From sb16_dsp.c	*/
-void sb16_dsp_interrupt (int irq);
-long sb16_dsp_init(long mem_start, struct address_info *hw_config);
-int sb16_dsp_detect(struct address_info *hw_config);
-
-/*	From sb16_midi.c	*/
-void sb16midiintr (int unit);
-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, void *dev_id, struct pt_regs * dummy);
-
-/*	From sb_midi.c	*/
-void sb_midi_init(int model);
-
-/*	From sb_mixer.c	*/
-void sb_setmixer (unsigned int port, unsigned int value);
-int sb_getmixer (unsigned int port);
-void sb_mixer_set_stereo(int mode);
-int sb_mixer_init(int major_model);
-
 /*	From opl3.c	*/
 int opl3_detect (int ioaddr, int *osp);
-long opl3_init(long mem_start, int ioaddr, int *osp);
+void opl3_init(int ioaddr, int *osp);
 
 /*	From sb_card.c	*/
-long attach_sb_card(long mem_start, struct address_info *hw_config);
+void attach_sb_card(struct address_info *hw_config);
 int probe_sb(struct address_info *hw_config);
 
+/*	From sb_common.c */
+void sb_dsp_disable_midi(int port);
+void sb_dsp_disable_recording(int port);
+void attach_sbmpu (struct address_info *hw_config);
+int probe_sbmpu (struct address_info *hw_config);
+void unload_sbmpu (struct address_info *hw_config);
+
+/*	From uart401.c */
+void attach_uart401 (struct address_info *hw_config);
+int probe_uart401 (struct address_info *hw_config);
+void unload_uart401 (struct address_info *hw_config);
+void uart401intr (int irq, void *dev_id, struct pt_regs * dummy);
+
 /*	From adlib_card.c	*/
-long attach_adlib_card(long mem_start, struct address_info *hw_config);
+void attach_adlib_card(struct address_info *hw_config);
 int probe_adlib(struct address_info *hw_config);
 
 /*	From pas_card.c	*/
-long attach_pas_card(long mem_start, struct address_info *hw_config);
+void attach_pas_card(struct address_info *hw_config);
 int probe_pas(struct address_info *hw_config);
 int pas_set_intr(int mask);
 int pas_remove_intr(int mask);
@@ -151,26 +133,26 @@
 
 /*	From pas_audio.c */
 void pas_pcm_interrupt(unsigned char status, int cause);
-long pas_pcm_init(long mem_start, struct address_info *hw_config);
+void pas_pcm_init(struct address_info *hw_config);
 
 /*	From pas_mixer.c */
 int pas_init_mixer(void);
 
 /*	From pas_midi.c */
-long pas_midi_init(long mem_start);
+void pas_midi_init(void);
 void pas_midi_interrupt(void);
 
 /*	From gus_card.c */
-long attach_gus_card(long mem_start, struct address_info * hw_config);
+void attach_gus_card(struct address_info * hw_config);
 int probe_gus(struct address_info *hw_config);
 int gus_set_midi_irq(int num);
 void gusintr(int irq, void *dev_id, struct pt_regs * dummy);
-long attach_gus_db16(long mem_start, struct address_info * hw_config);
+void attach_gus_db16(struct address_info * hw_config);
 int probe_gus_db16(struct address_info *hw_config);
 
 /*	From gus_wave.c */
 int gus_wave_detect(int baseaddr);
-long gus_wave_init(long mem_start, struct address_info *hw_config);
+void gus_wave_init(struct address_info *hw_config);
 void gus_wave_unload (void);
 void gus_voice_irq(void);
 unsigned char gus_read8 (int reg);
@@ -181,16 +163,16 @@
 void gus_timer_command (unsigned int addr, unsigned int val);
 
 /*	From gus_midi.c */
-long gus_midi_init(long mem_start);
+void gus_midi_init(void);
 void gus_midi_interrupt(int dummy);
 
 /*	From mpu401.c */
-long attach_mpu401(long mem_start, struct address_info * hw_config);
+void attach_mpu401(struct address_info * hw_config);
 int probe_mpu401(struct address_info *hw_config);
 void mpuintr(int irq, void *dev_id, struct pt_regs * dummy);
 
 /*	From uart6850.c */
-long attach_uart6850(long mem_start, struct address_info * hw_config);
+void attach_uart6850(struct address_info * hw_config);
 int probe_uart6850(struct address_info *hw_config);
 
 /*	From opl3.c */
@@ -206,7 +188,7 @@
 				    unsigned long parm3, unsigned long parm4);
 
 /* 	From ics2101.c */
-long ics2101_mixer_init(long mem_start);
+void ics2101_mixer_init(void);
 
 /*	From sound_timer.c */
 void sound_timer_interrupt(void);
@@ -221,25 +203,25 @@
 #define AD_F_CS4248	0x0001	/* Returned if a CS4248 (or compatible) detected */
 
 void     ad1848_interrupt (int irq, void *dev_id, struct pt_regs * dummy);
-long attach_ms_sound(long mem_start, struct address_info * hw_config);
+void attach_ms_sound(struct address_info * hw_config);
 int probe_ms_sound(struct address_info *hw_config);
-long attach_pnp_ad1848(long mem_start, struct address_info * hw_config);
+void attach_pnp_ad1848(struct address_info * hw_config);
 int probe_pnp_ad1848(struct address_info *hw_config);
 void unload_pnp_ad1848(struct address_info *hw_info);
 
 /* 	From pss.c */
 int probe_pss (struct address_info *hw_config);
-long attach_pss (long mem_start, struct address_info *hw_config);
+void attach_pss (struct address_info *hw_config);
 int probe_pss_mpu (struct address_info *hw_config);
-long attach_pss_mpu (long mem_start, struct address_info *hw_config);
+void attach_pss_mpu (struct address_info *hw_config);
 int probe_pss_mss (struct address_info *hw_config);
-long attach_pss_mss (long mem_start, struct address_info *hw_config);
+void attach_pss_mss (struct address_info *hw_config);
 
 /* 	From sscape.c */
 int probe_sscape (struct address_info *hw_config);
-long attach_sscape (long mem_start, struct address_info *hw_config);
+void attach_sscape (struct address_info *hw_config);
 int probe_ss_ms_sound (struct address_info *hw_config);
-long attach_ss_ms_sound(long mem_start, struct address_info * hw_config);
+void attach_ss_ms_sound(struct address_info * hw_config);
 
 int pss_read (int dev, struct fileinfo *file, char *buf, int count);
 int pss_write (int dev, struct fileinfo *file, char *buf, int count);
@@ -248,7 +230,7 @@
 int pss_ioctl (int dev, struct fileinfo *file,
 	   unsigned int cmd, caddr_t arg);
 int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
-long pss_init(long mem_start);
+void pss_init(void);
 
 /* From aedsp16.c */
 int InitAEDSP16_SBPRO(struct address_info *hw_config);
@@ -259,21 +241,19 @@
 void do_midi_msg (int synthno, unsigned char *msg, int mlen);
 
 /*	From trix.c	*/
-long attach_trix_wss (long mem_start, struct address_info *hw_config);
+void attach_trix_wss (struct address_info *hw_config);
 int probe_trix_wss (struct address_info *hw_config);
-long attach_trix_sb (long mem_start, struct address_info *hw_config);
+void attach_trix_sb (struct address_info *hw_config);
 int probe_trix_sb (struct address_info *hw_config);
-long attach_trix_mpu (long mem_start, struct address_info *hw_config);
+void attach_trix_mpu (struct address_info *hw_config);
 int probe_trix_mpu (struct address_info *hw_config);
 
 /*	From mad16.c	*/
-long attach_mad16 (long mem_start, struct address_info *hw_config);
+void attach_mad16 (struct address_info *hw_config);
 int probe_mad16 (struct address_info *hw_config);
-long attach_mad16_mpu (long mem_start, struct address_info *hw_config);
+void attach_mad16_mpu (struct address_info *hw_config);
 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);
@@ -303,14 +283,14 @@
 /* From cs4232.c */
 
 int probe_cs4232 (struct address_info *hw_config);
-long attach_cs4232 (long mem_start, struct address_info *hw_config);
+void attach_cs4232 (struct address_info *hw_config);
 int probe_cs4232_mpu (struct address_info *hw_config);
-long attach_cs4232_mpu (long mem_start, struct address_info *hw_config);
+void attach_cs4232_mpu (struct address_info *hw_config);
 
 /*	From maui.c */
-long attach_maui(long mem_start, struct address_info * hw_config);
+void attach_maui(struct address_info * hw_config);
 int probe_maui(struct address_info *hw_config);
 
 /*	From sound_pnp.c */
-void sound_pnp_init(void);
+void sound_pnp_init(int *osp);
 void sound_pnp_disconnect(void);
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h
--- v2.0.0/linux/drivers/sound/sound_config.h	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/sound_config.h	Sun Jun 30 11:43:39 1996
@@ -3,27 +3,11 @@
  * A driver for Soundcards, misc configuration parameters.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 
 
@@ -112,8 +96,8 @@
 #define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
 #define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
 #define SND_DEV_STATUS	6	/* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
+#define SND_DEV_AWFM	7	/* Reserved */
+#define SND_DEV_SEQ2	8	/* /dev/sequecer, level 2 interface */
 #define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
 #define SND_DEV_PSS	SND_DEV_SNDPROC
 
@@ -143,8 +127,8 @@
 	char *name;
 	int driver_use_1;	/* Driver defined field 1 */
 	int driver_use_2;	/* Driver defined field 2 */
-	int *osp;	/* OS specific info */
-	int card_subtype;	/* Driver specific. Usually 0 */
+	int *osp;	/* OS spesific info */
+	int card_subtype;	/* Driver spesific. Usually 0 */
 };
 
 #define SYNTH_MAX_VOICES	32
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c
--- v2.0.0/linux/drivers/sound/sound_switch.c	Tue May  7 16:22:35 1996
+++ linux/drivers/sound/sound_switch.c	Sun Jun 30 11:44:18 1996
@@ -4,27 +4,11 @@
  * The system call switch handler
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -48,7 +32,7 @@
 static int
 put_status (char *s)
 {
-  int             l = strnlen (s, 256);
+  int             l = strlen (s);
 
   if (status_len + l >= 4000)
     return 0;
@@ -172,18 +156,24 @@
 	  if (!put_status (sound_drivers[drv].name))
 	    return;
 
-	if (!put_status (" at 0x"))
-	  return;
-	if (!put_status_int (snd_installed_cards[i].config.io_base, 16))
-	  return;
+	if (snd_installed_cards[i].config.io_base)
+	  {
+	    if (!put_status (" at 0x"))
+	      return;
+	    if (!put_status_int (snd_installed_cards[i].config.io_base, 16))
+	      return;
+	  }
 
-	if (!put_status (" irq "))
-	  return;
 	tmp = snd_installed_cards[i].config.irq;
-	if (tmp < 0)
-	  tmp = -tmp;
-	if (!put_status_int (tmp, 10))
-	  return;
+	if (tmp != 0)
+	  {
+	    if (!put_status (" irq "))
+	      return;
+	    if (tmp < 0)
+	      tmp = -tmp;
+	    if (!put_status_int (tmp, 10))
+	      return;
+	  }
 
 	if (snd_installed_cards[i].config.dma != -1)
 	  {
@@ -326,7 +316,7 @@
   if (l <= 0)
     return 0;
 
-  memcpy_tofs (&((buf)[0]), &status_buf[status_ptr], l);
+  memcpy_tofs (&(buf)[0], &status_buf[status_ptr], l);
   status_ptr += l;
 
   return l;
@@ -367,7 +357,7 @@
       printk ("Sound: Undefined minor device %d\n", dev);
     }
 
-  return -EPERM;
+  return -(EPERM);
 }
 
 int
@@ -401,77 +391,67 @@
 
     }
 
-  return -EPERM;
+  return -(EPERM);
 }
 
 int
 sound_open_sw (int dev, struct fileinfo *file)
 {
+  int             retval;
+
   DEB (printk ("sound_open_sw(dev=%d)\n", dev));
 
   if ((dev >= SND_NDEVS) || (dev < 0))
     {
       printk ("Invalid minor device %d\n", dev);
-      return -ENXIO;
+      return -(ENXIO);
     }
 
   switch (dev & 0x0f)
     {
     case SND_DEV_STATUS:
       if (status_busy)
-	return -EBUSY;
+	return -(EBUSY);
       status_busy = 1;
-      if ((status_buf = (char *) kmalloc (4000, GFP_KERNEL)) == NULL)
-	return -EIO;
+      if ((status_buf = (char *) vmalloc (4000)) == NULL)
+	return -(EIO);
       status_len = status_ptr = 0;
       init_status ();
       break;
 
     case SND_DEV_CTL:
       if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers)
-	return -ENXIO;
+	return -(ENXIO);
       return 0;
       break;
 
 #ifdef CONFIG_SEQUENCER
     case SND_DEV_SEQ:
     case SND_DEV_SEQ2:
-    {
-      int retval;
-
       if ((retval = sequencer_open (dev, file)) < 0)
 	return retval;
       break;
-    }
 #endif
 
 #ifdef CONFIG_MIDI
     case SND_DEV_MIDIN:
-    {
-      int retval;
-
       if ((retval = MIDIbuf_open (dev, file)) < 0)
 	return retval;
       break;
-    }
 #endif
 
 #ifdef CONFIG_AUDIO
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
-    {
-      int retval;
-
       if ((retval = audio_open (dev, file)) < 0)
 	return retval;
       break;
-    }
 #endif
 
     default:
       printk ("Invalid minor device %d\n", dev);
-      return -ENXIO;
+      return -(ENXIO);
     }
 
   in_use++;
@@ -489,7 +469,7 @@
     {
     case SND_DEV_STATUS:
       if (status_buf)
-	kfree (status_buf);
+	vfree (status_buf);
       status_buf = NULL;
       status_busy = 0;
       break;
@@ -524,6 +504,21 @@
   in_use--;
 }
 
+static int
+get_mixer_info (int dev, caddr_t arg)
+{
+  mixer_info      info;
+
+  if (dev < 0 || dev >= num_mixers)
+    return -(ENXIO);
+
+  strcpy (info.id, mixer_devs[dev]->id);
+  strcpy (info.name, mixer_devs[dev]->name);
+
+  memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info));
+  return 0;
+}
+
 int
 sound_ioctl_sw (int dev, struct fileinfo *file,
 		unsigned int cmd, caddr_t arg)
@@ -533,22 +528,29 @@
   if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0)	/* Mixer ioctl */
     if ((dev & 0x0f) != SND_DEV_CTL)
       {
-#ifdef CONFIG_AUDIO
 	int             dtype = dev & 0x0f;
 	int             mixdev;
 
 	switch (dtype)
 	  {
+#ifdef CONFIG_AUDIO
 	  case SND_DEV_DSP:
 	  case SND_DEV_DSP16:
 	  case SND_DEV_AUDIO:
 	    mixdev = audio_devs[dev >> 4]->mixer_dev;
 	    if (mixdev < 0 || mixdev >= num_mixers)
-	      return -ENXIO;
+	      return -(ENXIO);
+	    if (cmd == SOUND_MIXER_INFO)
+	      return get_mixer_info (mixdev, arg);
 	    return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg);
-	  }
+	    break;
 #endif
-	  return mixer_devs[0]->ioctl (0, cmd, arg);
+
+	  default:
+	    if (cmd == SOUND_MIXER_INFO)
+	      return get_mixer_info (0, arg);
+	    return mixer_devs[0]->ioctl (0, cmd, arg);
+	  }
       }
 
   switch (dev & 0x0f)
@@ -557,13 +559,15 @@
     case SND_DEV_CTL:
 
       if (!num_mixers)
-	return -ENXIO;
+	return -(ENXIO);
 
       dev = dev >> 4;
 
       if (dev >= num_mixers)
-	return -ENXIO;
+	return -(ENXIO);
 
+      if (cmd == SOUND_MIXER_INFO)
+	return get_mixer_info (dev, arg);
       return mixer_devs[dev]->ioctl (dev, cmd, arg);
       break;
 
@@ -590,5 +594,5 @@
 
     }
 
-  return -EPERM;
+  return -(EPERM);
 }
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c
--- v2.0.0/linux/drivers/sound/sound_timer.c	Sun Mar 24 22:50:24 1996
+++ linux/drivers/sound/sound_timer.c	Sun Jun 30 11:44:18 1996
@@ -2,27 +2,11 @@
  * sound/sound_timer.c
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -110,7 +94,7 @@
 timer_open (int dev, int mode)
 {
   if (opened)
-    return -EBUSY;
+    return -(EBUSY);
 
   tmr_reset ();
   curr_tempo = 60;
@@ -268,7 +252,7 @@
 
     case SNDCTL_SEQ_CTRLRATE:
       if (get_fs_long ((long *) arg) != 0)	/* Can't change */
-	return -EINVAL;
+	return -(EINVAL);
 
       return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60);
       break;
@@ -280,7 +264,7 @@
     default:;
     }
 
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.0.0/linux/drivers/sound/soundcard.c	Fri May 17 15:32:17 1996
+++ linux/drivers/sound/soundcard.c	Sun Jun 30 11:44:19 1996
@@ -4,27 +4,11 @@
  * Soundcard driver for Linux
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -33,6 +17,8 @@
 
 #include <linux/major.h>
 
+
+int            *sound_global_osp = NULL;
 static int      chrdev_registered = 0;
 static int      sound_major = SOUND_MAJOR;
 
@@ -42,7 +28,7 @@
  * Table for permanently allocated memory (used when unloading the module)
  */
 caddr_t         sound_mem_blocks[1024];
-int             sound_num_blocks = 0;
+int             sound_nblocks = 0;
 
 static int      soundcard_configured = 0;
 
@@ -55,6 +41,7 @@
 #define DMA_MAP_FREE		1
 #define DMA_MAP_BUSY		2
 
+
 int
 snd_ioctl_return (int *addr, int value)
 {
@@ -92,7 +79,7 @@
 static int
 sound_lseek (inode_handle * inode, file_handle * file, off_t offset, int orig)
 {
-  return -EPERM;
+  return -(EPERM);
 }
 
 static int
@@ -104,7 +91,7 @@
   if (is_unloading)
     {
       printk ("Sound: Driver partially removed. Can't open device\n");
-      return -EBUSY;
+      return -(EBUSY);
     }
 
   dev = MINOR (inode_get_rdev (inode));
@@ -112,7 +99,7 @@
   if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
     {
       printk ("SoundCard Error: The soundcard system has not been configured\n");
-      return -ENXIO;
+      return -(ENXIO);
     }
 
   tmp_file.mode = 0;
@@ -302,7 +289,6 @@
 	      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)))
@@ -342,8 +328,17 @@
 
   soundcard_configured = 1;
 
-  sndtable_init (0);		/* Initialize call tables and
-				   * detect cards */
+  sndtable_init ();		/* Initialize call tables and detect cards */
+
+
+
+#ifdef CONFIG_LOWLEVEL_SOUND
+  {
+    extern void     sound_init_lowlevel_drivers (void);
+
+    sound_init_lowlevel_drivers ();
+  }
+#endif
 
   if (sndtable_get_cardcount () == 0)
     return;			/* No cards detected */
@@ -351,19 +346,19 @@
 #ifdef CONFIG_AUDIO
   if (num_audiodevs)		/* Audio devices present */
     {
-      DMAbuf_init (0);
-      audio_init (0);
+      DMAbuf_init ();
+      audio_init ();
     }
 #endif
 
 #ifdef CONFIG_MIDI
   if (num_midis)
-    MIDIbuf_init (0);
+    MIDIbuf_init ();
 #endif
 
 #ifdef CONFIG_SEQUENCER
   if (num_midis + num_synths)
-    sequencer_init (0);
+    sequencer_init ();
 #endif
 
 }
@@ -389,6 +384,8 @@
 
 #endif
 
+static int      debugmem = 0;	/* switched off by default */
+
 static int      sound[20] =
 {0};
 
@@ -426,7 +423,7 @@
   chrdev_registered = 1;
   soundcard_init ();
 
-  if (sound_num_blocks >= 1024)
+  if (sound_nblocks >= 1024)
     printk ("Sound warning: Deallocation table was too small.\n");
 
   return 0;
@@ -440,16 +437,29 @@
 {
   int             i;
 
+  if (MOD_IN_USE)
+    {
+      return;
+    }
+
   if (chrdev_registered)
     module_unregister_chrdev (sound_major, "sound");
 
 #ifdef CONFIG_SEQUENCER
   sound_stop_timer ();
 #endif
+
+#ifdef CONFIG_LOWLEVEL_SOUND
+  {
+    extern void     sound_unload_lowlevel_drivers (void);
+
+    sound_unload_lowlevel_drivers ();
+  }
+#endif
   sound_unload_drivers ();
 
-  for (i = 0; i < sound_num_blocks; i++)
-    kfree (sound_mem_blocks[i]);
+  for (i = 0; i < sound_nblocks; i++)
+    vfree (sound_mem_blocks[i]);
 
   free_all_irqs ();		/* If something was left allocated by accident */
 
@@ -460,6 +470,7 @@
 	sound_free_dma (i);
       }
 
+
 }
 #endif
 
@@ -473,11 +484,11 @@
 }
 
 int
-snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, void *, struct pt_regs *), char *name, int *osp)
+snd_set_irq_handler (int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp)
 {
   int             retcode;
 
-  retcode = request_irq (interrupt_level, hndlr, 0 /* SA_INTERRUPT */ , name, NULL);
+  retcode = request_irq (interrupt_level, iproc, 0 /* SA_INTERRUPT */ , name, NULL);
   if (retcode < 0)
     {
       printk ("Sound: IRQ%d already in use\n", interrupt_level);
@@ -516,6 +527,12 @@
 {
   unsigned long   flags;
 
+  if (chn < 0 || chn > 7 || chn == 4)
+    {
+      printk ("sound_open_dma: Invalid DMA channel %d\n", chn);
+      return 1;
+    }
+
   save_flags (flags);
   cli ();
 
@@ -598,8 +615,6 @@
 fatal_error__This_version_is_not_compatible_with_this_kernel;
 #endif
 
-static int      debugmem = 0;	/* switched off by default */
-
 static int      dma_buffsize = DSP_BUFFSIZE;
 
 int
@@ -655,7 +670,7 @@
   if (start_addr == NULL)
     {
       printk ("Sound error: Couldn't allocate DMA buffer\n");
-      return -ENOMEM;
+      return -(ENOMEM);
     }
   else
     {
@@ -673,10 +688,10 @@
 	  || end_addr >= (char *) (MAX_DMA_ADDRESS))
 	{
 	  printk (
-		   "sound: kmalloc returned invalid address 0x%lx for %ld Bytes DMA-buffer\n",
+		   "sound: Got invalid address 0x%lx for %ldb DMA-buffer\n",
 		   (long) start_addr,
 		   audio_devs[dev]->buffsize);
-	  return -EFAULT;
+	  return -(EFAULT);
 	}
     }
   dmap->raw_buf = start_addr;
@@ -693,39 +708,37 @@
 void
 sound_free_dmap (int dev, struct dma_buffparms *dmap)
 {
+  int             sz, size, i;
+  unsigned long   start_addr, end_addr;
+
   if (dmap->raw_buf == NULL)
     return;
 
   if (dmap->mapping_flags & DMA_MAP_MAPPED)
     return;			/* Don't free mmapped buffer. Will use it next time */
 
-  {
-    int             sz, size, i;
-    unsigned long   start_addr, end_addr;
-
-    for (sz = 0, size = PAGE_SIZE;
-	 size < audio_devs[dev]->buffsize;
-	 sz++, size <<= 1);
+  for (sz = 0, size = PAGE_SIZE;
+       size < audio_devs[dev]->buffsize;
+       sz++, size <<= 1);
 
-    start_addr = (unsigned long) dmap->raw_buf;
-    end_addr = start_addr + audio_devs[dev]->buffsize;
+  start_addr = (unsigned long) dmap->raw_buf;
+  end_addr = start_addr + audio_devs[dev]->buffsize;
 
-    for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
-      {
-	mem_map_unreserve (i);
-      }
+  for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
+    {
+      mem_map_unreserve (i);
+    }
 
-    free_pages ((unsigned long) dmap->raw_buf, sz);
-  }
+  free_pages ((unsigned long) dmap->raw_buf, sz);
   dmap->raw_buf = NULL;
 }
 
 int
-sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info)
+soud_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info)
 {
   printk ("Entered sound_map_buffer()\n");
   printk ("Exited sound_map_buffer()\n");
-  return -EINVAL;
+  return -(EINVAL);
 }
 #endif
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h
--- v2.0.0/linux/drivers/sound/soundvers.h	Sun Mar 31 00:13:18 1996
+++ linux/drivers/sound/soundvers.h	Mon Jul  1 06:30:35 1996
@@ -1,2 +1,2 @@
-#define SOUND_VERSION_STRING "3.5.2-960330"
-#define SOUND_INTERNAL_VERSION 0x030500
+#define SOUND_VERSION_STRING "3.5.4-960630"
+#define SOUND_INTERNAL_VERSION 0x030504
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v2.0.0/linux/drivers/sound/sscape.c	Sat Apr 13 18:22:07 1996
+++ linux/drivers/sound/sscape.c	Sun Jun 30 11:44:20 1996
@@ -4,27 +4,11 @@
  * Low level driver for Ensoniq Soundscape
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -281,7 +265,7 @@
   host_command3 (devc, CMD_SET_CONTROL, ctrl, value);
   if (host_read (devc) != CMD_ACK)
     {
-      printk ("SNDSCAPE: Setting control (%d) failed\n", ctrl);
+      /* printk ("SNDSCAPE: Setting control (%d) failed\n", ctrl); */
     }
   host_close (devc);
 }
@@ -307,10 +291,10 @@
   static int      debug = 0;
 
   bits = sscape_read (devc, GA_INTSTAT_REG);
-  if ((sscape_sleep_flag.mode & WK_SLEEP))
+  if ((sscape_sleep_flag.flags & WK_SLEEP))
     {
       {
-	sscape_sleep_flag.mode = WK_WAKEUP;
+	sscape_sleep_flag.flags = WK_WAKEUP;
 	module_wake_up (&sscape_sleeper);
       };
     }
@@ -320,10 +304,10 @@
       printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc));
     }
 
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
   if (bits & 0x01)
     {
-      mpuintr (irq, NULL, NULL);
+      uart401intr (irq, NULL, NULL);
       if (debug++ > 10)		/* Temporary debugging hack */
 	{
 	  sscape_write (devc, GA_INTENA_REG, 0x00);	/* Disable all interrupts */
@@ -352,9 +336,11 @@
       return;
     }
 
+  audio_devs[devc->my_audiodev]->flags &= ~DMA_AUTOMODE;
   DMAbuf_start_dma (devc->my_audiodev,
 		    buf,
 		    blk_size, mode);
+  audio_devs[devc->my_audiodev]->flags |= DMA_AUTOMODE;
 
   temp = devc->dma << 4;	/* Setup DMA channel select bits */
   if (devc->dma <= 3)
@@ -401,10 +387,10 @@
     {
       set_mt32 (devc, 0);
       if (!verify_mpu (devc))
-	return -EIO;
+	return -(EIO);
     }
 
-  sscape_sleep_flag.mode = WK_NONE;
+  sscape_sleep_flag.flags = WK_NONE;
   return 0;
 }
 
@@ -419,11 +405,9 @@
   if (devc->dma_allocated)
     {
       sscape_write (devc, GA_DMAA_REG, 0x20);	/* DMA channel disabled */
-#ifdef CONFIG_NATIVE_PCM
-#endif
       devc->dma_allocated = 0;
     }
-  sscape_sleep_flag.mode = WK_NONE;
+  sscape_sleep_flag.flags = WK_NONE;
   restore_flags (flags);
 
   return;
@@ -440,7 +424,7 @@
   unsigned long   flags;
   unsigned char   temp;
   int             done, timeout_val;
-  static int      already_done = 0;
+  static unsigned char codec_dma_bits = 0;
 
   if (flag & CPF_FIRST)
     {
@@ -449,20 +433,14 @@
          * before continuing.
        */
 
-      if (already_done)
-	{
-	  printk ("Can't run 'ssinit' twice\n");
-	  return 0;
-	}
-      already_done = 1;
-
       save_flags (flags);
       cli ();
+      codec_dma_bits = sscape_read (devc, GA_CDCFG_REG);
+      sscape_write (devc, GA_CDCFG_REG,
+		    codec_dma_bits & ~0x08);	/* Disable codec DMA */
+
       if (devc->dma_allocated == 0)
 	{
-#ifdef CONFIG_NATIVE_PCM
-#endif
-
 	  devc->dma_allocated = 1;
 	}
       restore_flags (flags);
@@ -479,7 +457,7 @@
     }
 
   /*
-     * Transfer one code block using DMA
+   * Transfer one code block using DMA
    */
   memcpy (audio_devs[devc->my_audiodev]->dmap_out->raw_buf, block, size);
 
@@ -493,7 +471,7 @@
   /*
    * Wait until transfer completes.
    */
-  sscape_sleep_flag.mode = WK_NONE;
+  sscape_sleep_flag.flags = WK_NONE;
   done = 0;
   timeout_val = 100;
   while (!done && timeout_val-- > 0)
@@ -502,24 +480,26 @@
 
 
       {
-	unsigned long   tl;
+	unsigned long   tlimit;
 
 	if (1)
-	  current_set_timeout (tl = jiffies + (1));
+	  current_set_timeout (tlimit = jiffies + (1));
 	else
-	  tl = (unsigned long) -1;
-	sscape_sleep_flag.mode = WK_SLEEP;
+	  tlimit = (unsigned long) -1;
+	sscape_sleep_flag.flags = WK_SLEEP;
 	module_interruptible_sleep_on (&sscape_sleeper);
-	if (!(sscape_sleep_flag.mode & WK_WAKEUP))
+	if (!(sscape_sleep_flag.flags & WK_WAKEUP))
 	  {
-	    if (jiffies >= tl)
-	      sscape_sleep_flag.mode |= WK_TIMEOUT;
+	    if (jiffies >= tlimit)
+	      sscape_sleep_flag.flags |= WK_TIMEOUT;
 	  }
-	sscape_sleep_flag.mode &= ~WK_SLEEP;
+	sscape_sleep_flag.flags &= ~WK_SLEEP;
       };
       clear_dma_ff (devc->dma);
       if ((resid = get_dma_residue (devc->dma)) == 0)
-	done = 1;
+	{
+	  done = 1;
+	}
     }
 
   restore_flags (flags);
@@ -550,24 +530,26 @@
 	{
 
 	  {
-	    unsigned long   tl;
+	    unsigned long   tlimit;
 
 	    if (1)
-	      current_set_timeout (tl = jiffies + (1));
+	      current_set_timeout (tlimit = jiffies + (1));
 	    else
-	      tl = (unsigned long) -1;
-	    sscape_sleep_flag.mode = WK_SLEEP;
+	      tlimit = (unsigned long) -1;
+	    sscape_sleep_flag.flags = WK_SLEEP;
 	    module_interruptible_sleep_on (&sscape_sleeper);
-	    if (!(sscape_sleep_flag.mode & WK_WAKEUP))
+	    if (!(sscape_sleep_flag.flags & WK_WAKEUP))
 	      {
-		if (jiffies >= tl)
-		  sscape_sleep_flag.mode |= WK_TIMEOUT;
+		if (jiffies >= tlimit)
+		  sscape_sleep_flag.flags |= WK_TIMEOUT;
 	      }
-	    sscape_sleep_flag.mode &= ~WK_SLEEP;
+	    sscape_sleep_flag.flags &= ~WK_SLEEP;
 	  };
 	  if (inb (PORT (HOST_DATA)) == 0xff)	/* OBP startup acknowledge */
 	    done = 1;
 	}
+      sscape_write (devc, GA_CDCFG_REG, codec_dma_bits);
+
       restore_flags (flags);
       if (!done)
 	{
@@ -583,20 +565,20 @@
 	{
 
 	  {
-	    unsigned long   tl;
+	    unsigned long   tlimit;
 
 	    if (1)
-	      current_set_timeout (tl = jiffies + (1));
+	      current_set_timeout (tlimit = jiffies + (1));
 	    else
-	      tl = (unsigned long) -1;
-	    sscape_sleep_flag.mode = WK_SLEEP;
+	      tlimit = (unsigned long) -1;
+	    sscape_sleep_flag.flags = WK_SLEEP;
 	    module_interruptible_sleep_on (&sscape_sleeper);
-	    if (!(sscape_sleep_flag.mode & WK_WAKEUP))
+	    if (!(sscape_sleep_flag.flags & WK_WAKEUP))
 	      {
-		if (jiffies >= tl)
-		  sscape_sleep_flag.mode |= WK_TIMEOUT;
+		if (jiffies >= tlimit)
+		  sscape_sleep_flag.flags |= WK_TIMEOUT;
 	      }
-	    sscape_sleep_flag.mode &= ~WK_SLEEP;
+	    sscape_sleep_flag.flags &= ~WK_SLEEP;
 	  };
 	  if (inb (PORT (HOST_DATA)) == 0xfe)	/* Host startup acknowledge */
 	    done = 1;
@@ -636,12 +618,12 @@
 download_boot_block (void *dev_info, copr_buffer * buf)
 {
   if (buf->len <= 0 || buf->len > sizeof (buf->data))
-    return -EINVAL;
+    return -(EINVAL);
 
   if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags))
     {
       printk ("SSCAPE: Unable to load microcode block to the OBP.\n");
-      return -EIO;
+      return -(EIO);
     }
 
   return 0;
@@ -663,18 +645,18 @@
 	copr_buffer    *buf;
 	int             err;
 
-	buf = (copr_buffer *) kmalloc (sizeof (copr_buffer), GFP_KERNEL);
+	buf = (copr_buffer *) vmalloc (sizeof (copr_buffer));
 	if (buf == NULL)
-	  return -ENOSPC;
-	memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf));
+	  return -(ENOSPC);
+	memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf));
 	err = download_boot_block (dev_info, buf);
-	kfree (buf);
+	vfree (buf);
 	return err;
       }
       break;
 
     default:
-      return -EINVAL;
+      return -(EINVAL);
     }
 
 }
@@ -689,176 +671,11 @@
   &dev_info
 };
 
-static int
-sscape_audio_open (int dev, int mode)
-{
-  unsigned long   flags;
-  sscape_info    *devc = (sscape_info *) audio_devs[dev]->devc;
-
-  save_flags (flags);
-  cli ();
-  if (devc->opened)
-    {
-      restore_flags (flags);
-      return -EBUSY;
-    }
-  devc->opened = 1;
-  restore_flags (flags);
-#ifdef SSCAPE_DEBUG4
-  /*
-     * Temporary debugging aid. Print contents of the registers
-     * when the device is opened.
-   */
-  {
-    int             i;
-
-    for (i = 0; i < 13; i++)
-      printk ("I%d = %02x\n", i, sscape_read (devc, i));
-  }
-#endif
-
-  return 0;
-}
-
-static void
-sscape_audio_close (int dev)
-{
-  unsigned long   flags;
-  sscape_info    *devc = (sscape_info *) audio_devs[dev]->devc;
-
-  DEB (printk ("sscape_audio_close(void)\n"));
-
-  save_flags (flags);
-  cli ();
-
-  devc->opened = 0;
-
-  restore_flags (flags);
-}
-
-static int
-set_speed (sscape_info * devc, int arg)
-{
-  return 8000;
-}
-
-static int
-set_channels (sscape_info * devc, int arg)
-{
-  return 1;
-}
-
-static int
-set_format (sscape_info * devc, int arg)
-{
-  return AFMT_U8;
-}
-
-static int
-sscape_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
-{
-  sscape_info    *devc = (sscape_info *) audio_devs[dev]->devc;
-
-  switch (cmd)
-    {
-    case SOUND_PCM_WRITE_RATE:
-      if (local)
-	return set_speed (devc, (int) arg);
-      return snd_ioctl_return ((int *) arg, set_speed (devc, get_fs_long ((long *) arg)));
-
-    case SOUND_PCM_READ_RATE:
-      if (local)
-	return 8000;
-      return snd_ioctl_return ((int *) arg, 8000);
-
-    case SNDCTL_DSP_STEREO:
-      if (local)
-	return set_channels (devc, (int) arg + 1) - 1;
-      return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg) + 1) - 1);
-
-    case SOUND_PCM_WRITE_CHANNELS:
-      if (local)
-	return set_channels (devc, (int) arg);
-      return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg)));
-
-    case SOUND_PCM_READ_CHANNELS:
-      if (local)
-	return 1;
-      return snd_ioctl_return ((int *) arg, 1);
-
-    case SNDCTL_DSP_SAMPLESIZE:
-      if (local)
-	return set_format (devc, (int) arg);
-      return snd_ioctl_return ((int *) arg, set_format (devc, get_fs_long ((long *) arg)));
-
-    case SOUND_PCM_READ_BITS:
-      if (local)
-	return 8;
-      return snd_ioctl_return ((int *) arg, 8);
-
-    default:;
-    }
-  return -EINVAL;
-}
-
-static void
-sscape_audio_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
-{
-}
-
-static void
-sscape_audio_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
-{
-}
-
-static int
-sscape_audio_prepare_for_input (int dev, int bsize, int bcount)
-{
-  return 0;
-}
-
-static int
-sscape_audio_prepare_for_output (int dev, int bsize, int bcount)
-{
-  return 0;
-}
-
-static void
-sscape_audio_halt (int dev)
-{
-}
-
-static void
-sscape_audio_reset (int dev)
-{
-  sscape_audio_halt (dev);
-}
-
-static struct audio_operations sscape_audio_operations =
-{
-  "Not functional",
-  0,
-  AFMT_U8 | AFMT_S16_LE,
-  NULL,
-  sscape_audio_open,
-  sscape_audio_close,
-  sscape_audio_output_block,
-  sscape_audio_start_input,
-  sscape_audio_ioctl,
-  sscape_audio_prepare_for_input,
-  sscape_audio_prepare_for_output,
-  sscape_audio_reset,
-  sscape_audio_halt,
-  NULL,
-  NULL
-};
-
 static int      sscape_detected = 0;
 
-long
-attach_sscape (long mem_start, struct address_info *hw_config)
+void
+attach_sscape (struct address_info *hw_config)
 {
-  int             my_dev;
 
 #ifndef SSCAPE_REGS
   /*
@@ -894,7 +711,7 @@
   int             i, irq_bits = 0xff;
 
   if (sscape_detected != hw_config->io_base)
-    return mem_start;
+    return;
 
   if (old_hardware)
     {
@@ -914,7 +731,7 @@
   if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff))
     {
       printk ("Invalid IRQ%d\n", hw_config->irq);
-      return mem_start;
+      return;
     }
 
   save_flags (flags);
@@ -968,45 +785,27 @@
   }
 #endif
 
-#if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU)
-  if (probe_mpu401 (hw_config))
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
+  if (probe_uart401 (hw_config))
     hw_config->always_detect = 1;
   {
     int             prev_devs;
 
     prev_devs = num_midis;
-    mem_start = attach_mpu401 (mem_start, hw_config);
+    hw_config->name = "Soundscape";
+
+    hw_config->irq *= -1;	/* Negative value signals IRQ sharing */
+    attach_uart401 (hw_config);
+    hw_config->irq *= -1;	/* Restore it */
 
     if (num_midis == (prev_devs + 1))	/* The MPU driver installed itself */
       midi_devs[prev_devs]->coproc = &sscape_coproc_operations;
   }
 #endif
 
-#ifndef EXCLUDE_NATIVE_PCM
-  /* Not supported yet */
-
-#ifdef CONFIG_AUDIO
-  if (num_audiodevs < MAX_AUDIO_DEV)
-    {
-      audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations;
-      audio_devs[my_dev]->dmachan1 = hw_config->dma;
-      audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
-      audio_devs[my_dev]->devc = devc;
-      devc->my_audiodev = my_dev;
-      devc->opened = 0;
-      audio_devs[my_dev]->coproc = &sscape_coproc_operations;
-      if (snd_set_irq_handler (hw_config->irq, sscapeintr, "SoundScape", devc->osp) < 0)
-	printk ("Error: Can't allocate IRQ for SoundScape\n");
-
-      sscape_write (devc, GA_INTENA_REG, 0x80);		/* Master IRQ enable */
-    }
-  else
-    printk ("SoundScape: More than enough audio devices detected\n");
-#endif
-#endif
+  sscape_write (devc, GA_INTENA_REG, 0x80);	/* Master IRQ enable */
   devc->ok = 1;
   devc->failed = 0;
-  return mem_start;
 }
 
 int
@@ -1083,11 +882,6 @@
 	old_hardware = 0;
     }
 
-  if (sound_alloc_dma (hw_config->dma, "soundscape"))
-    {
-      printk ("sscape.c: Can't allocate DMA channel\n");
-      return 0;
-    }
 
   sscape_detected = hw_config->io_base;
 
@@ -1123,8 +917,8 @@
   return ad1848_detect (hw_config->io_base, NULL, hw_config->osp);
 }
 
-long
-attach_ss_ms_sound (long mem_start, struct address_info *hw_config)
+void
+attach_ss_ms_sound (struct address_info *hw_config)
 {
   /*
      * This routine configures the SoundScape card for use with the
@@ -1134,18 +928,17 @@
 
   int             i, irq_bits = 0xff;
 
-#ifndef CONFIG_NATIVE_PCM
   int             prev_devs = num_audiodevs;
 
-#endif
+  hw_config->dma = devc->dma;	/* Share the DMA with the ODIE/OPUS chip */
 
   /*
-     * Setup the DMA polarity.
+   * Setup the DMA polarity.
    */
   sscape_write (devc, GA_DMACFG_REG, 0x50);
 
   /*
-     * Take the gate-array off of the DMA channel.
+     * Take the gate-arry off of the DMA channel.
    */
   sscape_write (devc, GA_DMAB_REG, 0x20);
 
@@ -1173,10 +966,10 @@
 	       0,
 	       devc->osp);
 
-#ifndef CONFIG_NATIVE_PCM
   if (num_audiodevs == (prev_devs + 1))		/* The AD1848 driver installed itself */
     audio_devs[prev_devs]->coproc = &sscape_coproc_operations;
-#endif
+  devc->my_audiodev = prev_devs;
+
 #ifdef SSCAPE_DEBUG5
   /*
      * Temporary debugging aid. Print contents of the registers
@@ -1190,17 +983,15 @@
   }
 #endif
 
-  return mem_start;
 }
 
 void
 unload_sscape (struct address_info *hw_config)
 {
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
-  unload_mpu401 (hw_config);
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
+  unload_uart401 (hw_config);
 #endif
   snd_release_irq (hw_config->irq);
-  sound_free_dma (hw_config->dma);
 }
 
 void
@@ -1208,9 +999,10 @@
 {
   ad1848_unload (hw_config->io_base,
 		 hw_config->irq,
-		 hw_config->dma,
-		 hw_config->dma,
+		 devc->dma,
+		 devc->dma,
 		 0);
 }
+
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c
--- v2.0.0/linux/drivers/sound/sys_timer.c	Sun Mar 24 22:50:27 1996
+++ linux/drivers/sound/sys_timer.c	Sun Jun 30 11:44:21 1996
@@ -5,27 +5,11 @@
  * Uses the (1/HZ sec) timer of kernel.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -106,7 +90,7 @@
 def_tmr_open (int dev, int mode)
 {
   if (opened)
-    return -EBUSY;
+    return -(EBUSY);
 
   tmr_reset ();
   curr_tempo = 60;
@@ -266,7 +250,7 @@
 
     case SNDCTL_SEQ_CTRLRATE:
       if (get_fs_long ((long *) arg) != 0)	/* Can't change */
-	return -EINVAL;
+	return -(EINVAL);
 
       return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60);
       break;
@@ -278,7 +262,7 @@
     default:;
     }
 
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.0.0/linux/drivers/sound/trix.c	Sun Mar 24 22:50:28 1996
+++ linux/drivers/sound/trix.c	Sun Jun 30 11:44:21 1996
@@ -1,36 +1,21 @@
 /*
  * sound/trix.c
  *
- * Low level driver for the MediaTriX AudioTriX Pro
+ * Low level driver for the MediaTrix AudioTrix Pro
  * (MT-0002-PC Control Chip)
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
 
 #include "sound_config.h"
+#include "sb.h"
 
 #if defined(CONFIG_TRIX)
 
@@ -98,7 +83,7 @@
 
   if (check_region (0x390, 2))
     {
-      printk ("AudioTriX: Config port I/O conflict\n");
+      printk ("AudioTrix: Config port I/O conflict\n");
       return 0;
     }
 
@@ -107,7 +92,7 @@
 
   if (trix_read (0x15) != 0x71)	/* No asic signature */
     {
-      DDB (printk ("No AudioTriX ASIC signature found\n"));
+      DDB (printk ("No AudioTrix ASIC signature found\n"));
       return 0;
     }
 
@@ -148,7 +133,7 @@
 
 /*
  *    Probe and attach routines for the Windows Sound System mode of
- *      AudioTriX Pro
+ *      AudioTrix Pro
  */
 
 int
@@ -158,12 +143,12 @@
 
   /*
      * Check if the IO port returns valid signature. The original MS Sound
-     * system returns 0x04 while some cards (AudioTriX Pro for example)
+     * system returns 0x04 while some cards (AudioTrix Pro for example)
      * return 0x00.
    */
   if (check_region (hw_config->io_base, 8))
     {
-      printk ("AudioTriX: MSS I/O port conflict (%x)\n", hw_config->io_base);
+      printk ("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base);
       return 0;
     }
 
@@ -180,20 +165,20 @@
 
   if (hw_config->irq > 11)
     {
-      printk ("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq);
+      printk ("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq);
       return 0;
     }
 
   if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
     {
-      printk ("AudioTriX: Bad WSS DMA %d\n", hw_config->dma);
+      printk ("AudioTrix: Bad WSS DMA %d\n", hw_config->dma);
       return 0;
     }
 
   if (hw_config->dma2 != -1)
     if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3)
       {
-	printk ("AudioTriX: Bad capture DMA %d\n", hw_config->dma2);
+	printk ("AudioTrix: Bad capture DMA %d\n", hw_config->dma2);
 	return 0;
       }
 
@@ -203,43 +188,43 @@
 
   if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80)
     {
-      printk ("AudioTriX: Can't use DMA0 with a 8 bit card\n");
+      printk ("AudioTrix: Can't use DMA0 with a 8 bit card\n");
       return 0;
     }
 
   if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80)
     {
-      printk ("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq);
+      printk ("AudioTrix: Can't use IRQ%d with a 8 bit card\n", hw_config->irq);
       return 0;
     }
 
   ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp);
 
   if (ret)
-    request_region (0x390, 2, "AudioTriX");
+    request_region (0x390, 2, "AudioTrix");
 
   return ret;
 }
 
-long
-attach_trix_wss (long mem_start, struct address_info *hw_config)
+void
+attach_trix_wss (struct address_info *hw_config)
 {
   static unsigned char interrupt_bits[12] =
-  {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
+  {0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20};
   char            bits;
 
   static unsigned char dma_bits[4] =
   {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             dma1 = hw_config->dma, dma2 = hw_config->dma2;
 
   trix_osp = hw_config->osp;
 
   if (!kilroy_was_here)
     {
-      DDB (printk ("AudioTriX: Attach called but not probed yet???\n"));
-      return mem_start;
+      DDB (printk ("AudioTrix: Attach called but not probed yet???\n"));
+      return;
     }
 
   /*
@@ -247,17 +232,15 @@
    */
 
   bits = interrupt_bits[hw_config->irq];
-  if (bits == -1)
+  if (bits == 0)
     {
-      printk ("AudioTriX: Bad IRQ (%d)\n", hw_config->irq);
-      return mem_start;
+      printk ("AudioTrix: Bad IRQ (%d)\n", hw_config->irq);
+      return;
     }
 
   outb (bits | 0x40, config_port);
-  if ((inb (version_port) & 0x40) == 0)
-    printk ("[IRQ Conflict?]");
 
-  if (hw_config->dma2 == -1)	/* Single DMA mode */
+  if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma)
     {
       bits |= dma_bits[dma1];
       dma2 = dma1;
@@ -275,14 +258,13 @@
 
   outb (bits, config_port);	/* Write IRQ+DMA setup */
 
-  ad1848_init ("AudioTriX Pro", hw_config->io_base + 4,
+  ad1848_init ("AudioTrix Pro", hw_config->io_base + 4,
 	       hw_config->irq,
 	       dma1,
 	       dma2,
 	       0,
 	       hw_config->osp);
   request_region (hw_config->io_base, 4, "MSS config");
-  return mem_start;
 }
 
 int
@@ -298,18 +280,18 @@
     return 0;			/* No boot code -> no fun */
 
   if (!kilroy_was_here)
-    return 0;			/* AudioTriX Pro has not been detected earlier */
+    return 0;			/* AudioTrix Pro has not been detected earlier */
 
   if (sb_initialized)
     return 0;
 
   if (check_region (hw_config->io_base, 16))
     {
-      printk ("AudioTriX: SB I/O port conflict (%x)\n", hw_config->io_base);
+      printk ("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base);
       return 0;
     }
 
-  if (hw_config->io_base & 0xffffff8f != 0x200)
+  if ((hw_config->io_base & 0xffffff8f) != 0x200)
     return 0;
 
   tmp = hw_config->irq;
@@ -332,36 +314,36 @@
   download_boot (hw_config->io_base);
   sb_initialized = 1;
 
-  return 1;
+  hw_config->name = "AudioTrix SB";
+#ifdef CONFIG_SBDSP
+  return probe_sb (hw_config);
+#else
+  return 0;
+#endif
 }
 
-long
-attach_trix_sb (long mem_start, struct address_info *hw_config)
+void
+attach_trix_sb (struct address_info *hw_config)
 {
-#ifdef CONFIG_SB
-  extern int      sb_no_recording;
-
-  sb_dsp_disable_midi ();
-  sb_no_recording = 1;
+#ifdef CONFIG_SBDSP
+  hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING;
+  attach_sb_card (hw_config);
 #endif
-  conf_printf ("AudioTriX (SB)", hw_config);
-  return mem_start;
 }
 
-long
-attach_trix_mpu (long mem_start, struct address_info *hw_config)
+void
+attach_trix_mpu (struct address_info *hw_config)
 {
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
-  return attach_mpu401 (mem_start, hw_config);
-#else
-  return mem_start;
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
+  hw_config->name = "AudioTrix Pro";
+  attach_uart401 (hw_config);
 #endif
 }
 
 int
 probe_trix_mpu (struct address_info *hw_config)
 {
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
   unsigned char   conf;
   static char     irq_bits[] =
   {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5};
@@ -369,7 +351,7 @@
   if (!kilroy_was_here)
     {
       DDB (printk ("Trix: WSS and SB modes must be initialized before MPU\n"));
-      return 0;			/* AudioTriX Pro has not been detected earlier */
+      return 0;			/* AudioTrix Pro has not been detected earlier */
     }
 
   if (!sb_initialized)
@@ -386,19 +368,19 @@
 
   if (check_region (hw_config->io_base, 4))
     {
-      printk ("AudioTriX: MPU I/O port conflict (%x)\n", hw_config->io_base);
+      printk ("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base);
       return 0;
     }
 
   if (hw_config->irq > 9)
     {
-      printk ("AudioTriX: Bad MPU IRQ %d\n", hw_config->irq);
+      printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq);
       return 0;
     }
 
   if (irq_bits[hw_config->irq] == -1)
     {
-      printk ("AudioTriX: Bad MPU IRQ %d\n", hw_config->irq);
+      printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq);
       return 0;
     }
 
@@ -426,7 +408,7 @@
 
   mpu_initialized = 1;
 
-  return probe_mpu401 (hw_config);
+  return probe_uart401 (hw_config);
 #else
   return 0;
 #endif
@@ -453,13 +435,14 @@
 void
 unload_trix_mpu (struct address_info *hw_config)
 {
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
-  unload_mpu401 (hw_config);
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
+  unload_uart401 (hw_config);
 #endif
 }
 void
 unload_trix_sb (struct address_info *hw_config)
 {
+  unload_sb (hw_config);
 }
 
 
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c
--- v2.0.0/linux/drivers/sound/uart401.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/uart401.c	Sun Jun 30 11:44:22 1996
@@ -0,0 +1,437 @@
+/*
+ * sound/uart401.c
+ *
+ * MPU-401 UART driver (formerly uart401_midi.c)
+ */
+/*
+ * Copyright (C) by Hannu Savolainen 1993-1996
+ *
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
+ */
+#include <linux/config.h>
+
+
+#include "sound_config.h"
+
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
+
+typedef struct uart401_devc
+  {
+    int             base;
+    int             irq;
+    int            *osp;
+    void            (*midi_input_intr) (int dev, unsigned char data);
+    int             opened;
+    volatile unsigned char input_byte;
+    int             my_dev;
+    int             share_irq;
+  }
+uart401_devc;
+
+static uart401_devc *detected_devc = NULL;
+static uart401_devc *irq2devc[16] =
+{NULL};
+
+#define	DATAPORT   (devc->base)
+#define	COMDPORT   (devc->base+1)
+#define	STATPORT   (devc->base+1)
+
+static int 
+uart401_status (uart401_devc * devc)
+{
+  return inb (STATPORT);
+}
+#define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL))
+#define output_ready(devc)	(!(uart401_status(devc)&OUTPUT_READY))
+static void 
+uart401_cmd (uart401_devc * devc, unsigned char cmd)
+{
+  outb (cmd, COMDPORT);
+}
+static int 
+uart401_read (uart401_devc * devc)
+{
+  return inb (DATAPORT);
+}
+static void 
+uart401_write (uart401_devc * devc, unsigned char byte)
+{
+  outb (byte, DATAPORT);
+}
+
+#define	OUTPUT_READY	0x40
+#define	INPUT_AVAIL	0x80
+#define	MPU_ACK		0xFE
+#define	MPU_RESET	0xFF
+#define	UART_MODE_ON	0x3F
+
+static int      reset_uart401 (uart401_devc * devc);
+
+static void
+uart401_input_loop (uart401_devc * devc)
+{
+  while (input_avail (devc))
+    {
+      unsigned char   c = uart401_read (devc);
+
+      if (c == MPU_ACK)
+	devc->input_byte = c;
+      else if (devc->opened & OPEN_READ && devc->midi_input_intr)
+	devc->midi_input_intr (devc->my_dev, c);
+    }
+}
+
+void
+uart401intr (int irq, void *dev_id, struct pt_regs *dummy)
+{
+  uart401_devc   *devc;
+
+  if (irq < 1 || irq > 15)
+    return;
+
+  devc = irq2devc[irq];
+
+  if (devc == NULL)
+    return;
+
+  if (input_avail (devc))
+    uart401_input_loop (devc);
+}
+
+static int
+uart401_open (int dev, int mode,
+	      void            (*input) (int dev, unsigned char data),
+	      void            (*output) (int dev)
+)
+{
+  uart401_devc   *devc = (uart401_devc *) midi_devs[dev]->devc;
+
+  if (devc->opened)
+    {
+      return -(EBUSY);
+    }
+
+  while (input_avail (devc))
+    uart401_read (devc);
+
+  devc->midi_input_intr = input;
+  devc->opened = mode;
+
+  return 0;
+}
+
+static void
+uart401_close (int dev)
+{
+  uart401_devc   *devc = (uart401_devc *) midi_devs[dev]->devc;
+
+  devc->opened = 0;
+}
+
+static int
+uart401_out (int dev, unsigned char midi_byte)
+{
+  int             timeout;
+  unsigned long   flags;
+  uart401_devc   *devc = (uart401_devc *) midi_devs[dev]->devc;
+
+  /*
+   * Test for input since pending input seems to block the output.
+   */
+
+  save_flags (flags);
+  cli ();
+
+  if (input_avail (devc))
+    uart401_input_loop (devc);
+
+  restore_flags (flags);
+
+  /*
+   * Sometimes it takes about 13000 loops before the output becomes ready
+   * (After reset). Normally it takes just about 10 loops.
+   */
+
+  for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--);
+
+  if (!output_ready (devc))
+    {
+      printk ("MPU-401: Timeout\n");
+      return 0;
+    }
+
+  uart401_write (devc, midi_byte);
+  return 1;
+}
+
+static int
+uart401_start_read (int dev)
+{
+  return 0;
+}
+
+static int
+uart401_end_read (int dev)
+{
+  return 0;
+}
+
+static int
+uart401_ioctl (int dev, unsigned cmd, caddr_t arg)
+{
+  return -(EINVAL);
+}
+
+static void
+uart401_kick (int dev)
+{
+}
+
+static int
+uart401_buffer_status (int dev)
+{
+  return 0;
+}
+
+#define MIDI_SYNTH_NAME	"MPU-401 UART"
+#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
+static struct midi_operations uart401_operations =
+{
+  {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401},
+  &std_midi_synth,
+  {0},
+  uart401_open,
+  uart401_close,
+  uart401_ioctl,
+  uart401_out,
+  uart401_start_read,
+  uart401_end_read,
+  uart401_kick,
+  NULL,
+  uart401_buffer_status,
+  NULL
+};
+
+static void
+enter_uart_mode (uart401_devc * devc)
+{
+  int             ok, timeout;
+  unsigned long   flags;
+
+  save_flags (flags);
+  cli ();
+  for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--);
+
+  devc->input_byte = 0;
+  uart401_cmd (devc, UART_MODE_ON);
+
+  ok = 0;
+  for (timeout = 50000; timeout > 0 && !ok; timeout--)
+    if (devc->input_byte == MPU_ACK)
+      ok = 1;
+    else if (input_avail (devc))
+      if (uart401_read (devc) == MPU_ACK)
+	ok = 1;
+
+  restore_flags (flags);
+}
+
+void
+attach_uart401 (struct address_info *hw_config)
+{
+  uart401_devc   *devc;
+  char           *name = "MPU-401 (UART) MIDI";
+
+  if (hw_config->name)
+    name = hw_config->name;
+
+  if (detected_devc == NULL)
+    return;
+
+
+  devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (uart401_devc)));
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (devc == NULL)
+    {
+      printk ("uart401: Can't allocate memory\n");
+      return;
+    }
+
+  memcpy ((char *) devc, (char *) detected_devc, sizeof (uart401_devc));
+  detected_devc = NULL;
+
+  devc->irq = hw_config->irq;
+  if (devc->irq < 0)
+    {
+      devc->share_irq = 1;
+      devc->irq *= -1;
+    }
+  else
+    devc->share_irq = 0;
+
+  if (devc->irq < 1 || devc->irq > 15)
+    return;
+
+  if (!devc->share_irq)
+    if (snd_set_irq_handler (devc->irq, uart401intr, "uart401", devc->osp) < 0)
+      {
+	printk ("uart401: Failed to allocate IRQ%d\n", devc->irq);
+	return;
+      }
+
+  irq2devc[devc->irq] = devc;
+  devc->my_dev = num_midis;
+
+  request_region (hw_config->io_base, 4, "SB MIDI");
+  enter_uart_mode (devc);
+
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return;
+    }
+
+  conf_printf (name, hw_config);
+
+  std_midi_synth.midi_dev = devc->my_dev = num_midis;
+
+
+  midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations)));
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+  if (midi_devs[num_midis] == NULL)
+    {
+      printk ("uart401: Failed to allocate memory\n");
+      return;
+    }
+
+  memcpy ((char *) midi_devs[num_midis], (char *) &uart401_operations,
+	  sizeof (struct midi_operations));
+
+  midi_devs[num_midis]->devc = devc;
+
+
+  midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations)));
+
+  if (sound_nblocks < 1024)
+    sound_nblocks++;;
+
+  if (midi_devs[num_midis]->converter == NULL)
+    {
+      printk ("uart401: Failed to allocate memory\n");
+      return;
+    }
+
+  memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth,
+	  sizeof (struct synth_operations));
+
+  strcpy (midi_devs[num_midis]->info.name, name);
+  num_midis++;
+  devc->opened = 0;
+}
+
+static int
+reset_uart401 (uart401_devc * devc)
+{
+  int             ok, timeout, n;
+
+  /*
+   * Send the RESET command. Try again if no success at the first time.
+   */
+
+  ok = 0;
+
+  /* save_flags(flags);cli(); */
+
+  for (n = 0; n < 2 && !ok; n++)
+    {
+      for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--);
+
+      devc->input_byte = 0;
+      uart401_cmd (devc, MPU_RESET);
+
+      /*
+       * Wait at least 25 msec. This method is not accurate so let's make the
+       * loop bit longer. Cannot sleep since this is called during boot.
+       */
+
+      for (timeout = 50000; timeout > 0 && !ok; timeout--)
+	if (devc->input_byte == MPU_ACK)	/* Interrupt */
+	  ok = 1;
+	else if (input_avail (devc))
+	  if (uart401_read (devc) == MPU_ACK)
+	    ok = 1;
+
+    }
+
+  if (ok)
+    uart401_input_loop (devc);	/*
+				 * Flush input before enabling interrupts
+				 */
+
+  /* restore_flags(flags); */
+
+  return ok;
+}
+
+int
+probe_uart401 (struct address_info *hw_config)
+{
+  int             ok = 0;
+
+  static uart401_devc hw_info;
+  uart401_devc   *devc = &hw_info;
+
+  detected_devc = NULL;
+
+  if (check_region (hw_config->io_base, 4))
+    return 0;
+
+  devc->base = hw_config->io_base;
+  devc->irq = hw_config->irq;
+  devc->osp = hw_config->osp;
+  devc->midi_input_intr = NULL;
+  devc->opened = 0;
+  devc->input_byte = 0;
+  devc->my_dev = 0;
+  devc->share_irq = 0;
+
+  ok = reset_uart401 (devc);
+
+  if (ok)
+    detected_devc = devc;
+
+  return ok;
+}
+
+void
+unload_uart401 (struct address_info *hw_config)
+{
+  uart401_devc   *devc;
+
+  int             irq = hw_config->irq;
+
+  if (irq < 0)
+    irq *= -1;
+
+  if (irq < 1 || irq > 15)
+    return;
+
+  devc = irq2devc[irq];
+  if (devc == NULL)
+    return;
+
+  release_region (hw_config->io_base, 4);
+
+  if (!devc->share_irq)
+    snd_release_irq (devc->irq);
+}
+
+
+#endif
diff -u --recursive --new-file v2.0.0/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c
--- v2.0.0/linux/drivers/sound/uart6850.c	Sun Mar 24 22:50:28 1996
+++ linux/drivers/sound/uart6850.c	Sun Jun 30 11:44:22 1996
@@ -2,27 +2,11 @@
  * sound/uart6850.c
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 #include <linux/config.h>
 
@@ -154,7 +138,7 @@
   if (uart6850_opened)
     {
       printk ("Midi6850: Midi busy\n");
-      return -EBUSY;
+      return -(EBUSY);
     }
 
   ;
@@ -238,7 +222,7 @@
 static int
 uart6850_ioctl (int dev, unsigned cmd, caddr_t arg)
 {
-  return -EINVAL;
+  return -(EINVAL);
 }
 
 static void
@@ -275,8 +259,8 @@
 };
 
 
-long
-attach_uart6850 (long mem_start, struct address_info *hw_config)
+void
+attach_uart6850 (struct address_info *hw_config)
 {
   int             ok, timeout;
   unsigned long   flags;
@@ -284,7 +268,7 @@
   if (num_midis >= MAX_MIDI_DEV)
     {
       printk ("Sound: Too many midi devices detected\n");
-      return mem_start;
+      return;
     }
 
   uart6850_base = hw_config->io_base;
@@ -292,7 +276,7 @@
   uart6850_irq = hw_config->irq;
 
   if (!uart6850_detected)
-    return -EIO;
+    return;
 
   save_flags (flags);
   cli ();
@@ -310,7 +294,6 @@
 
   std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &uart6850_operations;
-  return mem_start;
 }
 
 static int
diff -u --recursive --new-file v2.0.0/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.0.0/linux/fs/affs/namei.c	Mon May 20 08:21:04 1996
+++ linux/fs/affs/namei.c	Wed Jul  3 12:03:47 1996
@@ -535,7 +535,8 @@
 
 int
 affs_rename(struct inode *old_dir, const char *old_name, int old_len,
-	    struct inode *new_dir, const char *new_name, int new_len)
+	    struct inode *new_dir, const char *new_name, int new_len,
+	    int must_be_dir)
 {
 	struct inode		*old_inode;
 	struct inode		*new_inode;
@@ -568,6 +569,8 @@
 		goto end_rename;
 	old_inode = __iget(old_dir->i_sb,old_ino,0);
 	if (!old_inode)
+		goto end_rename;
+	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
 		goto end_rename;
 	new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
 	if (new_bh) {
diff -u --recursive --new-file v2.0.0/linux/fs/exec.c linux/fs/exec.c
--- v2.0.0/linux/fs/exec.c	Sat May 11 10:42:06 1996
+++ linux/fs/exec.c	Tue Jul  2 19:08:42 1996
@@ -429,7 +429,6 @@
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
 	    permission(bprm->inode,MAY_READ))
 		current->dumpable = 0;
-	current->signal = 0;
 	for (i=0 ; i<32 ; i++) {
 		current->sig->action[i].sa_mask = 0;
 		current->sig->action[i].sa_flags = 0;
diff -u --recursive --new-file v2.0.0/linux/fs/ext/namei.c linux/fs/ext/namei.c
--- v2.0.0/linux/fs/ext/namei.c	Mon Sep 18 08:54:10 1995
+++ linux/fs/ext/namei.c	Wed Jul  3 16:19:00 1996
@@ -885,7 +885,8 @@
  * as they are on different partitions.
  */
 int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len)
+	struct inode * new_dir, const char * new_name, int new_len,
+	int must_be_dir)
 {
 	static struct wait_queue * wait = NULL;
 	static int lock = 0;
diff -u --recursive --new-file v2.0.0/linux/fs/ext2/acl.c linux/fs/ext2/acl.c
--- v2.0.0/linux/fs/ext2/acl.c	Wed Mar 22 10:33:59 1995
+++ linux/fs/ext2/acl.c	Tue Jul  2 19:08:42 1996
@@ -28,6 +28,13 @@
 	unsigned short mode = inode->i_mode;
 
 	/*
+	 * Nobody gets write access to a file on a readonly-fs
+	 */
+	if ((mask & S_IWOTH) && 
+            (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) &&
+            IS_RDONLY(inode))
+		return -EROFS;
+	/*
 	 * Nobody gets write access to an immutable file
 	 */
 	if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
diff -u --recursive --new-file v2.0.0/linux/fs/ext2/ioctl.c linux/fs/ext2/ioctl.c
--- v2.0.0/linux/fs/ext2/ioctl.c	Mon Jun  3 16:46:56 1996
+++ linux/fs/ext2/ioctl.c	Tue Jul  2 19:08:42 1996
@@ -82,6 +82,6 @@
 		inode->i_dirt = 1;
 		return 0;
 	default:
-		return -EINVAL;
+		return -ENOTTY;
 	}
 }
diff -u --recursive --new-file v2.0.0/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.0.0/linux/fs/ext2/namei.c	Mon Dec 11 06:56:35 1995
+++ linux/fs/ext2/namei.c	Wed Jul  3 11:46:41 1996
@@ -25,12 +25,6 @@
 #include <linux/locks.h>
 
 /*
- * comment out this line if you want names > EXT2_NAME_LEN chars to be
- * truncated. Else they will be disallowed.
- */
-/* #define NO_TRUNCATE */
-
-/*
  * define how far ahead to read directories while searching them.
  */
 #define NAMEI_RA_CHUNKS  2
@@ -80,13 +74,8 @@
 		return NULL;
 	sb = dir->i_sb;
 
-#ifdef NO_TRUNCATE
 	if (namelen > EXT2_NAME_LEN)
 		return NULL;
-#else
-	if (namelen > EXT2_NAME_LEN)
-		namelen = EXT2_NAME_LEN;
-#endif
 
 	memset (bh_use, 0, sizeof (bh_use));
 	toread = 0;
@@ -176,6 +165,8 @@
 		iput (dir);
 		return -ENOENT;
 	}
+	if (len > EXT2_NAME_LEN)
+		return -ENAMETOOLONG;
 	if (dcache_lookup(dir, name, len, &ino)) {
 		if (!ino) {
 			iput(dir);
@@ -232,13 +223,13 @@
 	if (!dir)
 		return NULL;
 	sb = dir->i_sb;
-#ifdef NO_TRUNCATE
+
 	if (namelen > EXT2_NAME_LEN)
+	{
+		*err = -ENAMETOOLONG;
 		return NULL;
-#else
-	if (namelen > EXT2_NAME_LEN)
-		namelen = EXT2_NAME_LEN;
-#endif
+	}
+
 	if (!namelen)
 		return NULL;
 	/*
@@ -415,6 +406,9 @@
 
 	if (!dir)
 		return -ENOENT;
+
+	if (len > EXT2_NAME_LEN)
+		return -ENAMETOOLONG;
 	bh = ext2_find_entry (dir, name, len, &de);
 	if (bh) {
 		brelse (bh);
@@ -478,6 +472,8 @@
 
 	if (!dir)
 		return -ENOENT;
+	if (len > EXT2_NAME_LEN)
+		return -ENAMETOOLONG;
 	bh = ext2_find_entry (dir, name, len, &de);
 	if (bh) {
 		brelse (bh);
@@ -615,6 +611,8 @@
 	if (!dir)
 		return -ENOENT;
 	inode = NULL;
+	if (len > EXT2_NAME_LEN)
+		return -ENAMETOOLONG;
 	bh = ext2_find_entry (dir, name, len, &de);
 	retval = -ENOENT;
 	if (!bh)
@@ -624,8 +622,10 @@
 		goto end_rmdir;
 	if (inode->i_sb->dq_op)
 		inode->i_sb->dq_op->initialize (inode, -1);
-	if (inode->i_dev != dir->i_dev)
+	if (inode->i_dev != dir->i_dev) {
+		retval = -EBUSY;
 		goto end_rmdir;
+	}
 	if (de->inode != inode->i_ino) {
 		iput(inode);
 		brelse(bh);
@@ -699,6 +699,8 @@
 		return -ENOENT;
 	retval = -ENOENT;
 	inode = NULL;
+	if (len > EXT2_NAME_LEN)
+		return -ENAMETOOLONG;
 	bh = ext2_find_entry (dir, name, len, &de);
 	if (!bh)
 		goto end_unlink;
@@ -928,7 +930,8 @@
  */
 static int do_ext2_rename (struct inode * old_dir, const char * old_name,
 			   int old_len, struct inode * new_dir,
-			   const char * new_name, int new_len)
+			   const char * new_name, int new_len,
+			   int must_be_dir)
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -952,6 +955,10 @@
 	old_inode = new_inode = NULL;
 	old_bh = new_bh = dir_bh = NULL;
 	new_de = NULL;
+	retval = -ENAMETOOLONG;
+	if (old_len > EXT2_NAME_LEN)
+		goto end_rename;
+
 	old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de);
 	retval = -ENOENT;
 	if (!old_bh)
@@ -959,6 +966,8 @@
 	old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
+	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
+		goto end_rename;
 	retval = -EPERM;
 	if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
@@ -1099,7 +1108,8 @@
  * on the same file system
  */
 int ext2_rename (struct inode * old_dir, const char * old_name, int old_len,
-		 struct inode * new_dir, const char * new_name, int new_len)
+		 struct inode * new_dir, const char * new_name, int new_len,
+		 int must_be_dir)
 {
 	int result;
 
@@ -1107,7 +1117,7 @@
 		sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
 	old_dir->i_sb->u.ext2_sb.s_rename_lock = 1;
 	result = do_ext2_rename (old_dir, old_name, old_len, new_dir,
-				 new_name, new_len);
+				 new_name, new_len, must_be_dir);
 	old_dir->i_sb->u.ext2_sb.s_rename_lock = 0;
 	wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
 	return result;
diff -u --recursive --new-file v2.0.0/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.0.0/linux/fs/ioctl.c	Sun Mar 10 09:28:56 1996
+++ linux/fs/ioctl.c	Tue Jul  2 19:08:42 1996
@@ -51,7 +51,7 @@
 	}
 	if (filp->f_op && filp->f_op->ioctl)
 		return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
-	return -EINVAL;
+	return -ENOTTY;
 }
 
 
@@ -103,6 +103,6 @@
 			if (filp->f_op && filp->f_op->ioctl)
 				return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg);
 
-			return -EINVAL;
+			return -ENOTTY;
 	}
 }
diff -u --recursive --new-file v2.0.0/linux/fs/locks.c linux/fs/locks.c
--- v2.0.0/linux/fs/locks.c	Sun Jun  9 13:28:46 1996
+++ linux/fs/locks.c	Tue Jul  2 19:08:42 1996
@@ -317,6 +317,8 @@
 		break;
 	case F_UNLCK :
 		break;
+	default:
+		return -EINVAL;
 	}
 	
 	return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
@@ -448,7 +450,7 @@
 			if (current->signal & ~current->blocked)
 				return (-ERESTARTSYS);
 			if (posix_locks_deadlock(current, fl->fl_owner))
-				return (-EDEADLOCK);
+				return (-EDEADLK);
 			interruptible_sleep_on(&fl->fl_wait);
 			if (current->signal & ~current->blocked)
 				return (-ERESTARTSYS);
@@ -762,7 +764,7 @@
 				if (current->signal & ~current->blocked)
 					return (-ERESTARTSYS);
 				if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner))
-					return (-EDEADLOCK);
+					return (-EDEADLK);
 				interruptible_sleep_on(&fl->fl_wait);
 				if (current->signal & ~current->blocked)
 					return (-ERESTARTSYS);
diff -u --recursive --new-file v2.0.0/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.0.0/linux/fs/minix/namei.c	Wed Nov  8 12:22:48 1995
+++ linux/fs/minix/namei.c	Wed Jul  3 13:13:21 1996
@@ -672,7 +672,7 @@
  * higher-level routines.
  */
 static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len)
+	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir)
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -700,6 +700,8 @@
 	old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
+	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
+		goto end_rename;
 	retval = -EPERM;
 	if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
@@ -816,7 +818,8 @@
  * as they are on different partitions.
  */
 int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len)
+	struct inode * new_dir, const char * new_name, int new_len,
+	int must_be_dir)
 {
 	static struct wait_queue * wait = NULL;
 	static int lock = 0;
@@ -826,7 +829,7 @@
 		sleep_on(&wait);
 	lock = 1;
 	result = do_minix_rename(old_dir, old_name, old_len,
-		new_dir, new_name, new_len);
+		new_dir, new_name, new_len, must_be_dir);
 	lock = 0;
 	wake_up(&wait);
 	return result;
diff -u --recursive --new-file v2.0.0/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.0.0/linux/fs/msdos/namei.c	Sat May 11 10:42:06 1996
+++ linux/fs/msdos/namei.c	Wed Jul  3 12:08:03 1996
@@ -738,7 +738,8 @@
 
 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
-	struct inode *new_dir,const char *new_name,int new_len)
+	struct inode *new_dir,const char *new_name,int new_len,
+	int must_be_dir)
 {
 	struct super_block *sb = old_dir->i_sb;
 	char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
diff -u --recursive --new-file v2.0.0/linux/fs/namei.c linux/fs/namei.c
--- v2.0.0/linux/fs/namei.c	Wed Apr 17 09:06:32 1996
+++ linux/fs/namei.c	Wed Jul  3 11:38:01 1996
@@ -515,6 +515,43 @@
 	return error;
 }
 
+/*
+ * Some operations need to remove trailing slashes for POSIX.1
+ * conformance. For rename we also need to change the behaviour
+ * depending on whether we had a trailing slash or not.. (we
+ * cannot rename normal files with trailing slashes, only dirs)
+ *
+ * "dummy" is used to make sure we don't do "/" -> "".
+ */
+static int remove_trailing_slashes(char * name)
+{
+	int result;
+	char dummy[1];
+	char *remove = dummy+1;
+
+	for (;;) {
+		char c = *name;
+		name++;
+		if (!c)
+			break;
+		if (c != '/') {
+			remove = NULL;
+			continue;
+		}
+		if (remove)
+			continue;
+		remove = name;
+	}
+
+	result = 0;
+	if (remove) {
+		remove[-1] = 0;
+		result = 1;
+	}
+
+	return result;
+}
+
 static int do_mkdir(const char * pathname, int mode)
 {
 	const char * basename;
@@ -557,6 +594,7 @@
 
 	error = getname(pathname,&tmp);
 	if (!error) {
+		remove_trailing_slashes(tmp);
 		error = do_mkdir(tmp,mode);
 		putname(tmp);
 	}
@@ -607,6 +645,7 @@
 
 	error = getname(pathname,&tmp);
 	if (!error) {
+		remove_trailing_slashes(tmp);
 		error = do_rmdir(tmp);
 		putname(tmp);
 	}
@@ -788,7 +827,7 @@
 	return error;
 }
 
-static int do_rename(const char * oldname, const char * newname)
+static int do_rename(const char * oldname, const char * newname, int must_be_dir)
 {
 	struct inode * old_dir, * new_dir;
 	const char * old_base, * new_base;
@@ -852,7 +891,7 @@
 		new_dir->i_sb->dq_op->initialize(new_dir, -1);
 	down(&new_dir->i_sem);
 	error = old_dir->i_op->rename(old_dir, old_base, old_len, 
-		new_dir, new_base, new_len);
+		new_dir, new_base, new_len, must_be_dir);
 	up(&new_dir->i_sem);
 	iput(new_dir);
 	return error;
@@ -867,7 +906,9 @@
 	if (!error) {
 		error = getname(newname,&to);
 		if (!error) {
-			error = do_rename(from,to);
+			error = do_rename(from,to,
+				remove_trailing_slashes(from) |
+				remove_trailing_slashes(to));
 			putname(to);
 		}
 		putname(from);
diff -u --recursive --new-file v2.0.0/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.0.0/linux/fs/ncpfs/dir.c	Mon Jun  3 16:46:57 1996
+++ linux/fs/ncpfs/dir.c	Wed Jul  3 12:10:59 1996
@@ -63,7 +63,8 @@
 
 static int
 ncp_rename(struct inode *old_dir, const char *old_name, int old_len, 
-           struct inode *new_dir, const char *new_name, int new_len);
+           struct inode *new_dir, const char *new_name, int new_len,
+           int must_be_dir);
 
 static inline void
 str_upper(char *name)
@@ -1099,7 +1100,8 @@
 
 static int
 ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
-           struct inode *new_dir, const char *new_name, int new_len)
+           struct inode *new_dir, const char *new_name, int new_len,
+           int must_be_dir)
 {
 	int res;
 	char _old_name[old_len+1];
diff -u --recursive --new-file v2.0.0/linux/fs/nfs/bio.c linux/fs/nfs/bio.c
--- v2.0.0/linux/fs/nfs/bio.c	Sun Jun  9 13:28:46 1996
+++ linux/fs/nfs/bio.c	Sat Jun 29 12:00:46 1996
@@ -16,6 +16,9 @@
  * Another possible solution to this problem may be to have a cache of recent
  * RPC call results indexed by page pointer, or even a result code field
  * in struct page.
+ *
+ * June 96: Added retries of RPCs that seem to have failed for a transient
+ * reason.
  */
 
 #include <linux/sched.h>
@@ -90,64 +93,114 @@
 }
 
 /*
+ * This is the function to (re-) transmit an NFS readahead request
+ */
+static int
+nfsiod_read_setup(struct nfsiod_req *req)
+{
+	struct inode	*inode = req->rq_inode;
+	struct page	*page = req->rq_page;
+
+	return nfs_proc_read_request(&req->rq_rpcreq,
+			NFS_SERVER(inode), NFS_FH(inode),
+			page->offset, PAGE_SIZE, 
+			(__u32 *) page_address(page));
+}
+
+/*
  * This is the callback from nfsiod telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
  */
-static void
-nfs_read_cb(int result, struct nfsiod_req *req)
+static int
+nfsiod_read_result(int result, struct nfsiod_req *req)
 {
-	struct page	*page = (struct page *) req->rq_cdata;
+	struct nfs_server *server = NFS_SERVER(req->rq_inode);
+	struct page	*page = req->rq_page;
 	static int	succ = 0, fail = 0;
+	int		i;
 
 	dprintk("BIO: received callback for page %p, result %d\n",
 			page, result);
 
-	if (result >= 0
-	 && (result = nfs_proc_read_reply(&req->rq_rpcreq)) >= 0) {
-		succ++;
+	if (result >= 0) {
+		struct nfs_fattr	fattr;
+
+		result = nfs_proc_read_reply(&req->rq_rpcreq, &fattr);
+		if (result >= 0) {
+			nfs_refresh_inode(req->rq_inode, &fattr);
+			if (result < PAGE_SIZE)
+				memset((u8 *) page_address(page)+result,
+						0, PAGE_SIZE-result);
+		}
+	} else
+	if (result == -ETIMEDOUT && !(server->flags & NFS_MOUNT_SOFT)) {
+		/* XXX: Theoretically, we'd have to increment the initial
+		 * timeo here; but I'm not going to bother with this now
+		 * because this old nfsiod stuff will soon die anyway.
+		 */
+		result = -EAGAIN;
+	}
+
+	if (result == -EAGAIN && req->rq_retries--) {
+		dprintk("BIO: retransmitting request.\n");
+		memset(&req->rq_rpcreq, 0, sizeof(struct rpc_ioreq));
+		while (rpc_reserve(server->rsock, &req->rq_rpcreq, 1) < 0)
+			schedule();
+		current->fsuid = req->rq_fsuid;
+		current->fsgid = req->rq_fsgid;
+		for (i = 0; i < NGROUPS; i++)
+			current->groups[i] = req->rq_groups[i];
+		nfsiod_read_setup(req);
+		return 0;
+	}
+	if (result >= 0) {
 		set_bit(PG_uptodate, &page->flags);
+		succ++;
 	} else {
-		fail++;
 		dprintk("BIO: %d successful reads, %d failures\n", succ, fail);
 		set_bit(PG_error, &page->flags);
+		fail++;
 	}
 	clear_bit(PG_locked, &page->flags);
 	wake_up(&page->wait);
 	free_page(page_address(page));
+	return 1;
 }
 
 static inline int
 do_read_nfs_async(struct inode *inode, struct page *page)
 {
 	struct nfsiod_req *req;
-	int		result = -1;	/* totally arbitrary */
+	int		result, i;
 
 	dprintk("NFS: do_read_nfs_async(%p)\n", page);
 
 	set_bit(PG_locked, &page->flags);
 	clear_bit(PG_error, &page->flags);
 
-	if (!(req = nfsiod_reserve(NFS_SERVER(inode), nfs_read_cb)))
-		goto done;
-	result = nfs_proc_read_request(&req->rq_rpcreq,
-			NFS_SERVER(inode), NFS_FH(inode),
-			page->offset, PAGE_SIZE, 
-			(__u32 *) page_address(page));
-	if (result >= 0) {
-		req->rq_cdata = page;
+	if (!(req = nfsiod_reserve(NFS_SERVER(inode))))
+		return -EAGAIN;
+
+	req->rq_retries = 5;
+	req->rq_callback = nfsiod_read_result;
+	req->rq_inode = inode;
+	req->rq_page = page;
+
+	req->rq_fsuid = current->fsuid;
+	req->rq_fsgid = current->fsgid;
+	for (i = 0; i < NGROUPS; i++)
+		req->rq_groups[i] = current->groups[i];
+
+	if ((result = nfsiod_read_setup(req)) >= 0) {
 		page->count++;
-		result = nfsiod_enqueue(req);
-		if (result >= 0)
-			dprintk("NFS: enqueued async READ request.\n");
-	}
-	if (result < 0) {
+		nfsiod_enqueue(req);
+	} else {
 		dprintk("NFS: deferring async READ request.\n");
 		nfsiod_release(req);
 		clear_bit(PG_locked, &page->flags);
 		wake_up(&page->wait);
 	}
 
-done:
 	return result < 0? result : 0;
 }
 
diff -u --recursive --new-file v2.0.0/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.0.0/linux/fs/nfs/dir.c	Sat Jun  1 20:11:34 1996
+++ linux/fs/nfs/dir.c	Wed Jul  3 13:54:26 1996
@@ -32,7 +32,7 @@
 static int nfs_link(struct inode *, struct inode *, const char *, int);
 static int nfs_mknod(struct inode *, const char *, int, int, int);
 static int nfs_rename(struct inode *, const char *, int,
-		      struct inode *, const char *, int);
+		      struct inode *, const char *, int, int);
 
 static struct file_operations nfs_dir_operations = {
 	NULL,			/* lseek - default */
@@ -505,8 +505,7 @@
 		return -ENAMETOOLONG;
 	}
 	error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), name);
-	if (!error)
-		nfs_lookup_cache_remove(dir, NULL, name);
+	nfs_lookup_cache_remove(dir, NULL, name);
 	iput(dir);
 	return error;
 }
@@ -531,7 +530,7 @@
 		return -EIO;		/* DWIM */
 	}
 	ret = nfs_proc_rename(NFS_SERVER(dir), NFS_FH(dir), name,
-					       NFS_FH(dir), silly);
+					       NFS_FH(dir), silly, 0);
 	if (ret >= 0) {
 		nfs_lookup_cache_remove(dir, NULL, name);
 		nfs_lookup_cache_remove(dir, NULL, silly);
@@ -571,8 +570,7 @@
 	}
 	if ((error = nfs_sillyrename(dir, name, len)) < 0) {
 		error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), name);
-		if (!error)
-			nfs_lookup_cache_remove(dir, NULL, name);
+		nfs_lookup_cache_remove(dir, NULL, name);
 	}
 	iput(dir);
 	return error;
@@ -630,15 +628,16 @@
 	}
 	error = nfs_proc_link(NFS_SERVER(oldinode), NFS_FH(oldinode),
 		NFS_FH(dir), name);
-	if (!error)
-		nfs_lookup_cache_remove(dir, oldinode, NULL);
+
+	nfs_lookup_cache_remove(dir, oldinode, NULL);
 	iput(oldinode);
 	iput(dir);
 	return error;
 }
 
 static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
-		      struct inode *new_dir, const char *new_name, int new_len)
+		      struct inode *new_dir, const char *new_name, int new_len,
+		      int must_be_dir)
 {
 	int error;
 
@@ -661,11 +660,11 @@
 	}
 	error = nfs_proc_rename(NFS_SERVER(old_dir),
 		NFS_FH(old_dir), old_name,
-		NFS_FH(new_dir), new_name);
-	if (!error) {
-		nfs_lookup_cache_remove(old_dir, NULL, old_name);
-		nfs_lookup_cache_remove(new_dir, NULL, new_name);
-	}
+		NFS_FH(new_dir), new_name,
+		must_be_dir);
+
+	nfs_lookup_cache_remove(old_dir, NULL, old_name);
+	nfs_lookup_cache_remove(new_dir, NULL, new_name);
 	iput(old_dir);
 	iput(new_dir);
 	return error;
diff -u --recursive --new-file v2.0.0/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.0.0/linux/fs/nfs/file.c	Tue Apr  2 13:32:22 1996
+++ linux/fs/nfs/file.c	Sat Jun 29 12:00:46 1996
@@ -146,7 +146,9 @@
 	file->f_pos = pos;
 	if (pos > inode->i_size)
 		inode->i_size = pos;
-	nfs_refresh_inode(inode, &fattr);
+	/* Avoid possible Solaris 2.5 nfsd bug */
+	if (inode->i_ino == fattr.fileid)
+		nfs_refresh_inode(inode, &fattr);
 	return written;
 }
 
diff -u --recursive --new-file v2.0.0/linux/fs/nfs/nfsiod.c linux/fs/nfs/nfsiod.c
--- v2.0.0/linux/fs/nfs/nfsiod.c	Mon Apr  8 19:01:45 1996
+++ linux/fs/nfs/nfsiod.c	Sat Jun 29 12:00:46 1996
@@ -37,7 +37,7 @@
  * Reserve an nfsiod slot and initialize the request struct
  */
 struct nfsiod_req *
-nfsiod_reserve(struct nfs_server *server, nfsiod_done_fn_t callback)
+nfsiod_reserve(struct nfs_server *server)
 {
 	struct nfsiod_req	*req;
 
@@ -56,8 +56,6 @@
 	}
 
 	req->rq_server = server;
-	req->rq_callback = callback;
-
 	return req;
 }
 
@@ -74,21 +72,12 @@
 /*
  * Transmit a request and put it on nfsiod's list of pending requests.
  */
-int
+void
 nfsiod_enqueue(struct nfsiod_req *req)
 {
-	int	result;
-
 	dprintk("BIO: enqueuing request %p\n", &req->rq_rpcreq);
-	result = rpc_transmit(req->rq_server->rsock, &req->rq_rpcreq);
-	if (result < 0) {
-		dprintk("BIO: rpc_transmit returned %d\n", result);
-	} else {
-		dprintk("BIO: waking up nfsiod (%p)\n", req->rq_wait);
-		wake_up(&req->rq_wait);
-		schedule();
-	}
-	return result;
+	wake_up(&req->rq_wait);
+	schedule();
 }
 
 /*
@@ -120,8 +109,10 @@
 				current->pid);
 		active++;
 		dprintk("BIO: before: now %d nfsiod's active\n", active);
-		result = nfs_rpc_doio(req->rq_server, &req->rq_rpcreq, 1);
-		req->rq_callback(result, req);
+		do {
+			result = nfs_rpc_doio(req->rq_server,
+						&req->rq_rpcreq, 1);
+		} while (!req->rq_callback(result, req));
 		active--;
 	}
 
diff -u --recursive --new-file v2.0.0/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
--- v2.0.0/linux/fs/nfs/proc.c	Sun Apr 21 19:22:11 1996
+++ linux/fs/nfs/proc.c	Wed Jul  3 13:52:09 1996
@@ -451,13 +451,12 @@
 	req->rq_addr = &server->toaddr;
 	req->rq_alen = sizeof(server->toaddr);
 
-	return 0;
+	return rpc_transmit(server->rsock, req);
 }
 
 int
-nfs_proc_read_reply(struct rpc_ioreq *req)
+nfs_proc_read_reply(struct rpc_ioreq *req, struct nfs_fattr *fattr)
 {
-	struct nfs_fattr fattr;
 	int		status;
 	__u32		*p0, *p;
 	int		count;
@@ -465,9 +464,11 @@
 	p0 = (__u32 *) req->rq_rvec[0].iov_base;
 
 	if (!(p = nfs_rpc_verify(p0))) {
-		status = -errno_NFSERR_IO;
+		/* Tell the upper layers to retry */
+		status = -EAGAIN;
+		/* status = -errno_NFSERR_IO; */
 	} else if ((status = ntohl(*p++)) == NFS_OK) {
-		p = xdr_decode_fattr(p, &fattr);
+		p = xdr_decode_fattr(p, fattr);
 		count = ntohl(*p++);
 		if (p != req->rq_rvec[2].iov_base) {
 			/* unexpected RPC reply header size. punt.
@@ -612,12 +613,19 @@
 
 int nfs_proc_rename(struct nfs_server *server,
 		    struct nfs_fh *old_dir, const char *old_name,
-		    struct nfs_fh *new_dir, const char *new_name)
+		    struct nfs_fh *new_dir, const char *new_name,
+		    int must_be_dir)
 {
 	int *p, *p0;
 	int status;
 	int ruid = 0;
 
+	/*
+	 * Disallow "rename()" with trailing slashes over NFS: getting
+	 * POSIX.1 behaviour is just too unlikely.
+	 */
+	if (must_be_dir)
+		return -EINVAL;
 	PRINTK("NFS call  rename %s -> %s\n", old_name, new_name);
 	if (!(p0 = nfs_rpc_alloc(server->wsize)))
 		return -EIO;
diff -u --recursive --new-file v2.0.0/linux/fs/open.c linux/fs/open.c
--- v2.0.0/linux/fs/open.c	Tue May 28 08:09:56 1996
+++ linux/fs/open.c	Tue Jul  2 19:08:42 1996
@@ -53,6 +53,8 @@
 		return -EBADF;
 	if (!(inode = file->f_inode))
 		return -ENOENT;
+	if (!inode->i_sb)
+	        return -ENODEV;
 	if (!inode->i_sb->s_op->statfs)
 		return -ENOSYS;
 	inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
@@ -397,7 +399,7 @@
 	/*
 	 * If the owner has been changed, remove the setuid bit
 	 */
-	if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
+	if (inode->i_mode & S_ISUID) {
 		newattrs.ia_mode &= ~S_ISUID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
@@ -407,8 +409,7 @@
 	 * Don't remove the setgid bit if no group execute bit.
 	 * This is a file marked for mandatory locking.
 	 */
-	if (group != inode->i_gid &&
-	    ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
+	if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
 		newattrs.ia_mode &= ~S_ISGID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
@@ -453,7 +454,7 @@
 	/*
 	 * If the owner has been changed, remove the setuid bit
 	 */
-	if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
+	if (inode->i_mode & S_ISUID) {
 		newattrs.ia_mode &= ~S_ISUID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
@@ -463,8 +464,7 @@
 	 * Don't remove the setgid bit if no group execute bit.
 	 * This is a file marked for mandatory locking.
 	 */
-	if (group != inode->i_gid &&
-	    ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
+	if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
 		newattrs.ia_mode &= ~S_ISGID;
 		newattrs.ia_valid |= ATTR_MODE;
 	}
@@ -509,7 +509,7 @@
 	f->f_mode = (flag+1) & O_ACCMODE;
 	if (f->f_mode)
 		flag++;
-	if (flag & (O_TRUNC | O_CREAT))
+	if (flag & O_TRUNC)
 		flag |= 2;
 	error = open_namei(filename,flag,mode,&inode,NULL);
 	if (error)
diff -u --recursive --new-file v2.0.0/linux/fs/pipe.c linux/fs/pipe.c
--- v2.0.0/linux/fs/pipe.c	Sun May  5 08:52:03 1996
+++ linux/fs/pipe.c	Tue Jul  2 19:08:42 1996
@@ -67,8 +67,10 @@
 	}
 	PIPE_LOCK(*inode)--;
 	wake_up_interruptible(&PIPE_WAIT(*inode));
-	if (read)
+	if (read) {
+	        inode->i_atime = CURRENT_TIME;
 		return read;
+	}
 	if (PIPE_WRITERS(*inode))
 		return -EAGAIN;
 	return 0;
@@ -118,6 +120,7 @@
 		wake_up_interruptible(&PIPE_WAIT(*inode));
 		free = 1;
 	}
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	return written;
 }
 
diff -u --recursive --new-file v2.0.0/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.0.0/linux/fs/proc/array.c	Sun May  5 08:52:03 1996
+++ linux/fs/proc/array.c	Mon Jun 10 08:14:28 1996
@@ -861,8 +861,13 @@
  * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH
  *         + (index into the line)
  */
+#ifdef __alpha__
+#define MAPS_LINE_FORMAT	  "%016lx-%016lx %s %016lx %s %lu\n"
+#define MAPS_LINE_MAX	73 /* sum of 16  1  16  1 4 1 16 1 5 1 10 1 */
+#else
 #define MAPS_LINE_FORMAT	  "%08lx-%08lx %s %08lx %s %lu\n"
 #define MAPS_LINE_MAX	49 /* sum of 8  1  8  1 4 1 8 1 5 1 10 1 */
+#endif
 
 static int read_maps (int pid, struct file * file, char * buf, int count)
 {
diff -u --recursive --new-file v2.0.0/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.0.0/linux/fs/smbfs/dir.c	Thu Jun  6 17:42:36 1996
+++ linux/fs/smbfs/dir.c	Wed Jul  3 12:09:32 1996
@@ -61,7 +61,8 @@
 
 static int
 smb_rename(struct inode *old_dir, const char *old_name, int old_len, 
-           struct inode *new_dir, const char *new_name, int new_len);
+           struct inode *new_dir, const char *new_name, int new_len,
+           int must_be_dir);
 
 static inline void str_upper(char *name)
 {
@@ -882,7 +883,8 @@
 
 static int
 smb_rename(struct inode *old_dir, const char *old_name, int old_len,
-           struct inode *new_dir, const char *new_name, int new_len)
+           struct inode *new_dir, const char *new_name, int new_len,
+           int must_be_dir)
 {
 	int res;
 	char old_path[SMB_MAXPATHLEN], new_path[SMB_MAXPATHLEN];
diff -u --recursive --new-file v2.0.0/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.0.0/linux/fs/smbfs/proc.c	Thu Jun  6 17:42:37 1996
+++ linux/fs/smbfs/proc.c	Tue Jul  2 19:08:43 1996
@@ -305,7 +305,7 @@
 			case ERRdiffdevice: return EXDEV;
 			case ERRnofiles:    return 0;
 			case ERRbadshare:   return ETXTBSY;
-			case ERRlock:       return EDEADLOCK;
+			case ERRlock:       return EDEADLK;
 			case ERRfilexists:  return EEXIST;
 			case 87:            return 0; /* Unknown error!! */
 			/* This next error seems to occur on an mv when
@@ -330,7 +330,7 @@
 			case ERRdata: return EIO;
 			case ERRbadreq: return ERANGE;
 			case ERRbadshare: return ETXTBSY;
-			case ERRlock: return EDEADLOCK;
+			case ERRlock: return EDEADLK;
 			default: return EIO;
 		}
 	else if (errcls == ERRCMD) 
diff -u --recursive --new-file v2.0.0/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.0.0/linux/fs/sysv/namei.c	Wed Nov  8 12:36:10 1995
+++ linux/fs/sysv/namei.c	Wed Jul  3 12:06:03 1996
@@ -668,7 +668,7 @@
  * higher-level routines.
  */
 static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len)
+	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir)
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -694,6 +694,8 @@
 	old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
+	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
+		goto end_rename;
 	retval = -EPERM;
 	if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
@@ -808,7 +810,8 @@
  * as they are on different partitions.
  */
 int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len)
+	struct inode * new_dir, const char * new_name, int new_len,
+	int must_be_dir)
 {
 	static struct wait_queue * wait = NULL;
 	static int lock = 0;
@@ -818,7 +821,7 @@
 		sleep_on(&wait);
 	lock = 1;
 	result = do_sysv_rename(old_dir, old_name, old_len,
-		new_dir, new_name, new_len);
+		new_dir, new_name, new_len, must_be_dir);
 	lock = 0;
 	wake_up(&wait);
 	return result;
diff -u --recursive --new-file v2.0.0/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v2.0.0/linux/fs/umsdos/ioctl.c	Sun Mar 24 20:07:00 1996
+++ linux/fs/umsdos/ioctl.c	Wed Jul  3 16:39:48 1996
@@ -219,7 +219,7 @@
 				ret = msdos_rename (dir
 					,data.dos_dirent.d_name,data.dos_dirent.d_reclen
 					,dir
-					,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
+					,data.umsdos_dirent.name,data.umsdos_dirent.name_len,0);
 			}else if (cmd == UMSDOS_UNLINK_EMD){
 				/* #Specification: ioctl / UMSDOS_UNLINK_EMD
 					The umsdos_dirent field of the struct umsdos_ioctl is used
diff -u --recursive --new-file v2.0.0/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.0.0/linux/fs/umsdos/namei.c	Tue May  7 16:22:37 1996
+++ linux/fs/umsdos/namei.c	Wed Jul  3 16:41:31 1996
@@ -353,7 +353,8 @@
 						ret = msdos_rename (old_dir
 								    ,old_info.fake.fname,old_info.fake.len
 								    ,new_dir
-								    ,new_info.fake.fname,new_info.fake.len);
+								    ,new_info.fake.fname,new_info.fake.len
+								    ,0);
 chkstk();
 						PRINTK (("after m_rename ret %d ",ret));
 						if (ret != 0){
@@ -1014,7 +1015,8 @@
 	int old_len,
 	struct inode * new_dir,
 	const char * new_name,
-	int new_len)
+	int new_len,
+	int must_be_dir)
 {
 	/* #Specification: weakness / rename
 		There is a case where UMSDOS rename has a different behavior
diff -u --recursive --new-file v2.0.0/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.0.0/linux/fs/vfat/namei.c	Sat May 11 10:42:06 1996
+++ linux/fs/vfat/namei.c	Wed Jul  3 11:58:01 1996
@@ -1352,7 +1352,7 @@
 
 
 int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
-	struct inode *new_dir,const char *new_name,int new_len)
+	struct inode *new_dir,const char *new_name,int new_len,int must_be_dir)
 {
 	struct super_block *sb = old_dir->i_sb;
 	struct buffer_head *old_bh,*new_bh,*dotdot_bh;
@@ -1383,8 +1383,12 @@
 	PRINTK(("vfat_rename 3\n"));
 	if (res < 0) goto rename_done;
 
-	if (!(old_inode = iget(old_dir->i_sb,old_ino))) goto rename_done;
+	res = -ENOENT;
+	if (!(old_inode = iget(old_dir->i_sb,old_ino)))
+		goto rename_done;
 	is_dir = S_ISDIR(old_inode->i_mode);
+	if (must_be_dir && !is_dir)
+		goto rename_done;
 	if (is_dir) {
 		if ((old_dir->i_dev != new_dir->i_dev) ||
 		    (old_ino == new_dir->i_ino)) {
diff -u --recursive --new-file v2.0.0/linux/fs/xiafs/namei.c linux/fs/xiafs/namei.c
--- v2.0.0/linux/fs/xiafs/namei.c	Wed Nov  8 12:32:32 1995
+++ linux/fs/xiafs/namei.c	Wed Jul  3 16:28:55 1996
@@ -713,7 +713,8 @@
  */
 static int do_xiafs_rename(struct inode * old_dir, const char * old_name, 
 			 int old_len, struct inode * new_dir, 
-			 const char * new_name, int new_len)
+			 const char * new_name, int new_len,
+			 int must_be_dir)
 {
     struct inode * old_inode, * new_inode;
     struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -730,6 +731,8 @@
     old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */
     if (!old_inode)
         goto end_rename;
+    if (must_be_dir && !S_ISDIR(old_inode->i_mode))
+	goto end_rename;
     retval = -EPERM;
     if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
@@ -832,7 +835,8 @@
  * as they are on different partitions.
  */
 int xiafs_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len)
+	struct inode * new_dir, const char * new_name, int new_len,
+	int must_be_dir)
 {
     static struct wait_queue * wait = NULL;
     static int lock = 0;
@@ -842,7 +846,8 @@
         sleep_on(&wait);
     lock = 1;
     result = do_xiafs_rename(old_dir, old_name, old_len,
-			   new_dir, new_name, new_len);
+			   new_dir, new_name, new_len,
+			   must_be_dir);
     lock = 0;
     wake_up(&wait);
     return result;
diff -u --recursive --new-file v2.0.0/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h
--- v2.0.0/linux/include/asm-alpha/byteorder.h	Thu Feb 15 09:20:41 1996
+++ linux/include/asm-alpha/byteorder.h	Mon Jul  1 20:06:05 1996
@@ -21,6 +21,9 @@
 
 extern unsigned long int	__ntohl(unsigned long int);
 extern unsigned short int	__ntohs(unsigned short int);
+
+#ifdef __GNUC__
+
 extern unsigned long int	__constant_ntohl(unsigned long int);
 extern unsigned short int	__constant_ntohs(unsigned short int);
 
@@ -100,6 +103,8 @@
 (__builtin_constant_p((short)(x)) ? \
  __constant_htons((x)) : \
  __htons((x)))
-#endif
+#endif /* __OPTIMIZE__ */
+
+#endif /* __GNUC__ */
 
-#endif
+#endif /* _ALPHA_BYTEORDER_H */
diff -u --recursive --new-file v2.0.0/linux/include/asm-alpha/errno.h linux/include/asm-alpha/errno.h
--- v2.0.0/linux/include/asm-alpha/errno.h	Tue Nov  7 09:18:35 1995
+++ linux/include/asm-alpha/errno.h	Tue Jul  2 19:08:43 1996
@@ -106,7 +106,9 @@
 #define	ENOANO		100	/* No anode */
 #define	EBADRQC		101	/* Invalid request code */
 #define	EBADSLT		102	/* Invalid slot */
+#if 0
 #define	EDEADLOCK	103	/* File locking deadlock error */
+#endif
 #define	EBFONT		104	/* Bad font file format */
 #define	ENONET		105	/* Machine is not on the network */
 #define	ENOLINK		106	/* Link has been severed */
diff -u --recursive --new-file v2.0.0/linux/include/asm-i386/errno.h linux/include/asm-i386/errno.h
--- v2.0.0/linux/include/asm-i386/errno.h	Sat Jun 10 18:36:48 1995
+++ linux/include/asm-i386/errno.h	Tue Jul  2 19:08:43 1996
@@ -58,7 +58,9 @@
 #define	ENOANO		55	/* No anode */
 #define	EBADRQC		56	/* Invalid request code */
 #define	EBADSLT		57	/* Invalid slot */
+#if 0
 #define	EDEADLOCK	58	/* File locking deadlock error */
+#endif
 #define	EBFONT		59	/* Bad font file format */
 #define	ENOSTR		60	/* Device not a stream */
 #define	ENODATA		61	/* No data available */
diff -u --recursive --new-file v2.0.0/linux/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h
--- v2.0.0/linux/include/asm-i386/posix_types.h	Mon Jun  3 16:46:58 1996
+++ linux/include/asm-i386/posix_types.h	Tue Jul  2 19:08:43 1996
@@ -28,32 +28,36 @@
 #endif
 
 typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
 	int	val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+	int	__val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
 } __kernel_fsid_t;
 
 #undef	__FD_SET
 #define __FD_SET(fd,fdsetp) \
 		__asm__ __volatile__("btsl %1,%0": \
-			"=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd)))
+			"=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd)))
 
 #undef	__FD_CLR
 #define __FD_CLR(fd,fdsetp) \
 		__asm__ __volatile__("btrl %1,%0": \
-			"=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd)))
+			"=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd)))
 
 #undef	__FD_ISSET
 #define __FD_ISSET(fd,fdsetp) (__extension__ ({ \
 		unsigned char __result; \
 		__asm__ __volatile__("btl %1,%2 ; setb %0" \
 			:"=q" (__result) :"r" ((int) (fd)), \
-			"m" (*(fd_set *) (fdsetp))); \
+			"m" (*(__kernel_fd_set *) (fdsetp))); \
 		__result; }))
 
 #undef	__FD_ZERO
 #define __FD_ZERO(fdsetp) \
 		__asm__ __volatile__("cld ; rep ; stosl" \
-			:"=m" (*(fd_set *) (fdsetp)) \
+			:"=m" (*(__kernel_fd_set *) (fdsetp)) \
 			:"a" (0), "c" (__FDSET_INTS), \
-			"D" ((fd_set *) (fdsetp)) :"cx","di")
+			"D" ((__kernel_fd_set *) (fdsetp)) :"cx","di")
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- v2.0.0/linux/include/linux/affs_fs.h	Mon May 20 08:21:04 1996
+++ linux/include/linux/affs_fs.h	Wed Jul  3 11:53:06 1996
@@ -69,7 +69,8 @@
 				        const char *symname);
 extern int		   affs_fixup(struct buffer_head *bh, struct inode *inode);
 extern int		   affs_rename(struct inode *old_dir, const char *old_name, int old_len,
-				       struct inode *new_dir, const char *new_name, int new_len);
+				       struct inode *new_dir, const char *new_name, int new_len,
+				       int must_be_dir);
 
 /* inode.c */
 
diff -u --recursive --new-file v2.0.0/linux/include/linux/dirent.h linux/include/linux/dirent.h
--- v2.0.0/linux/include/linux/dirent.h	Tue Aug 15 18:31:52 1995
+++ linux/include/linux/dirent.h	Tue Jul  2 19:08:43 1996
@@ -1,13 +1,11 @@
 #ifndef _LINUX_DIRENT_H
 #define _LINUX_DIRENT_H
 
-#include <linux/limits.h>
-
 struct dirent {
 	long		d_ino;
 	off_t		d_off;
 	unsigned short	d_reclen;
-	char		d_name[NAME_MAX+1];
+	char		d_name[256]; /* We must not include limits.h! */
 };
 
 #endif
diff -u --recursive --new-file v2.0.0/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.0.0/linux/include/linux/ext2_fs.h	Sun Jun  9 13:28:47 1996
+++ linux/include/linux/ext2_fs.h	Wed Jul  3 11:48:37 1996
@@ -495,7 +495,7 @@
 extern int ext2_link (struct inode *, struct inode *, const char *, int);
 extern int ext2_mknod (struct inode *, const char *, int, int, int);
 extern int ext2_rename (struct inode *, const char *, int,
-			struct inode *, const char *, int);
+			struct inode *, const char *, int, int);
 
 /* super.c */
 extern void ext2_error (struct super_block *, const char *, const char *, ...)
diff -u --recursive --new-file v2.0.0/linux/include/linux/ext_fs.h linux/include/linux/ext_fs.h
--- v2.0.0/linux/include/linux/ext_fs.h	Mon Jan 15 07:59:13 1996
+++ linux/include/linux/ext_fs.h	Wed Jul  3 11:53:06 1996
@@ -74,7 +74,7 @@
 extern int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
 extern int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
 extern int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len);
+	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir);
 extern struct inode * ext_new_inode(const struct inode * dir);
 extern void ext_free_inode(struct inode * inode);
 extern unsigned long ext_count_free_inodes(struct super_block *sb);
diff -u --recursive --new-file v2.0.0/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.0.0/linux/include/linux/fs.h	Tue May 28 08:10:01 1996
+++ linux/include/linux/fs.h	Wed Jul  3 17:53:14 1996
@@ -478,7 +478,7 @@
 	int (*mkdir) (struct inode *,const char *,int,int);
 	int (*rmdir) (struct inode *,const char *,int);
 	int (*mknod) (struct inode *,const char *,int,int,int);
-	int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int);
+	int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int);
 	int (*readlink) (struct inode *,char *,int);
 	int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
 	int (*readpage) (struct inode *, struct page *);
diff -u --recursive --new-file v2.0.0/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v2.0.0/linux/include/linux/if_arp.h	Sat Jun  1 20:11:35 1996
+++ linux/include/linux/if_arp.h	Wed Jul  3 17:55:18 1996
@@ -22,6 +22,7 @@
 #ifndef _LINUX_IF_ARP_H
 #define _LINUX_IF_ARP_H
 
+#include <linux/netdevice.h>
 
 /* ARP protocol HARDWARE identifiers. */
 #define ARPHRD_NETROM	0		/* from KA9Q: NET/ROM pseudo	*/
diff -u --recursive --new-file v2.0.0/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- v2.0.0/linux/include/linux/isdn.h	Sun Jun  9 13:28:47 1996
+++ linux/include/linux/isdn.h	Sat Jun 29 20:36:23 1996
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.14 1996/06/06 21:24:23 fritz Exp $
+/* $Id: isdn.h,v 1.15 1996/06/15 14:56:57 fritz Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -21,6 +21,10 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdn.h,v $
+ * Revision 1.15  1996/06/15 14:56:57  fritz
+ * Added version signatures for data structures used
+ * by userlevel programs.
+ *
  * Revision 1.14  1996/06/06 21:24:23  fritz
  * Started adding support for suspend/resume.
  *
@@ -118,6 +122,7 @@
 #define IIOCNETASL  _IO('I',19)
 #define IIOCNETDIL  _IO('I',20)
 #define IIOCGETCPS  _IO('I',21)
+#define IIOCGETDVR  _IO('I',22)
 
 #define IIOCNETALN  _IO('I',32)
 #define IIOCNETDLN  _IO('I',33)
@@ -164,6 +169,9 @@
   char phone[20];
   int  outgoing;
 } isdn_net_ioctl_phone;
+
+#define NET_DV 0x01 /* Data version for net_cfg     */
+#define TTY_DV 0x01 /* Data version for iprofd etc. */
 
 typedef struct {
   char name[10];     /* Name of interface                     */
diff -u --recursive --new-file v2.0.0/linux/include/linux/loop.h linux/include/linux/loop.h
--- v2.0.0/linux/include/linux/loop.h	Sun Mar 24 20:07:01 1996
+++ linux/include/linux/loop.h	Mon Jul  1 20:06:05 1996
@@ -32,6 +32,10 @@
 	des_key_schedule lo_des_key;
 	unsigned long	lo_des_init[2];
 #endif
+#ifdef IDEA_AVAILABLE
+        idea_key        lo_idea_en_key;
+        idea_key        lo_idea_de_key;
+#endif
 };
 
 typedef	int (* transfer_proc_t)(struct loop_device *, int cmd,
diff -u --recursive --new-file v2.0.0/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v2.0.0/linux/include/linux/minix_fs.h	Mon Jan 15 07:59:14 1996
+++ linux/include/linux/minix_fs.h	Wed Jul  3 11:53:06 1996
@@ -100,7 +100,7 @@
 extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
 extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
 extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len);
+	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir);
 extern struct inode * minix_new_inode(const struct inode * dir);
 extern void minix_free_inode(struct inode * inode);
 extern unsigned long minix_count_free_inodes(struct super_block *sb);
diff -u --recursive --new-file v2.0.0/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.0.0/linux/include/linux/mm.h	Sat Apr 27 15:20:07 1996
+++ linux/include/linux/mm.h	Wed Jul  3 17:53:14 1996
@@ -318,7 +318,8 @@
 	unsigned long grow;
 
 	address &= PAGE_MASK;
-	if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
+	if (vma->vm_end - address
+	    > (unsigned long) current->rlim[RLIMIT_STACK].rlim_cur)
 		return -ENOMEM;
 	grow = vma->vm_start - address;
 	vma->vm_start = address;
diff -u --recursive --new-file v2.0.0/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.0.0/linux/include/linux/msdos_fs.h	Tue May  7 16:22:38 1996
+++ linux/include/linux/msdos_fs.h	Wed Jul  3 17:56:37 1996
@@ -251,7 +251,8 @@
 extern int msdos_unlink(struct inode *dir,const char *name,int len);
 extern int msdos_unlink_umsdos(struct inode *dir,const char *name,int len);
 extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
-			struct inode *new_dir,const char *new_name,int new_len);
+			struct inode *new_dir,const char *new_name,int new_len,
+			int must_be_dir);
 
 /* fatfs_syms.c */
 extern int init_fat_fs(void);
@@ -263,7 +264,8 @@
 extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode);
 extern int vfat_rmdir(struct inode *dir,const char *name,int len);
 extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
-		       struct inode *new_dir,const char *new_name,int new_len);
+		       struct inode *new_dir,const char *new_name,int new_len,
+		       int must_be_dir);
 extern void vfat_put_super(struct super_block *sb);
 extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
 					   int silent);
diff -u --recursive --new-file v2.0.0/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.0.0/linux/include/linux/nfs_fs.h	Fri Apr 12 15:52:08 1996
+++ linux/include/linux/nfs_fs.h	Wed Jul  3 11:53:06 1996
@@ -79,7 +79,8 @@
 			   const char *name);
 extern int nfs_proc_rename(struct nfs_server *server,
 			   struct nfs_fh *old_dir, const char *old_name,
-			   struct nfs_fh *new_dir, const char *new_name);
+			   struct nfs_fh *new_dir, const char *new_name,
+			   int must_be_dir);
 extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
 			 struct nfs_fh *dir, const char *name);
 extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
@@ -96,7 +97,7 @@
 extern int nfs_proc_read_request(struct rpc_ioreq *, struct nfs_server *,
 				 struct nfs_fh *, unsigned long offset,
 				 unsigned long count, __u32 *buf);
-extern int nfs_proc_read_reply(struct rpc_ioreq *);
+extern int nfs_proc_read_reply(struct rpc_ioreq *, struct nfs_fattr *);
 extern int *rpc_header(int *p, int procedure, int program, int version,
 				int uid, int gid, int *groups);
 extern int *rpc_verify(int *p);
diff -u --recursive --new-file v2.0.0/linux/include/linux/nfsiod.h linux/include/linux/nfsiod.h
--- v2.0.0/linux/include/linux/nfsiod.h	Tue Apr  2 13:32:22 1996
+++ linux/include/linux/nfsiod.h	Wed Jul  3 13:52:36 1996
@@ -9,6 +9,7 @@
 #define _LINUX_NFSIOD_H
 
 #include <linux/rpcsock.h>
+#include <linux/nfs_fs.h>
 
 #ifdef __KERNEL__
 
@@ -17,7 +18,7 @@
  * Note that the callback procedure must NOT sleep.
  */
 struct nfsiod_req;
-typedef void	(*nfsiod_done_fn_t)(int result, struct nfsiod_req *);
+typedef int	(*nfsiod_callback_t)(int result, struct nfsiod_req *);
 
 /*
  * This is the nfsiod request struct.
@@ -25,16 +26,25 @@
 struct nfsiod_req {
 	struct nfsiod_req *	rq_next;
 	struct nfsiod_req *	rq_prev;
-	struct nfs_server *	rq_server;
 	struct wait_queue *	rq_wait;
 	struct rpc_ioreq	rq_rpcreq;
-	nfsiod_done_fn_t	rq_callback;
-	void *			rq_cdata;
+	nfsiod_callback_t	rq_callback;
+	struct nfs_server *	rq_server;
+	struct inode *		rq_inode;
+	struct page *		rq_page;
+
+	/* user creds */
+	uid_t			rq_fsuid;
+	gid_t			rq_fsgid;
+	int			rq_groups[NGROUPS];
+
+	/* retry handling */
+	int			rq_retries;
 };
 
-struct nfsiod_req *	nfsiod_reserve(struct nfs_server *, nfsiod_done_fn_t);
+struct nfsiod_req *	nfsiod_reserve(struct nfs_server *);
 void			nfsiod_release(struct nfsiod_req *);
-int			nfsiod_enqueue(struct nfsiod_req *);
+void			nfsiod_enqueue(struct nfsiod_req *);
 int			nfsiod(void);
 
 
diff -u --recursive --new-file v2.0.0/linux/include/linux/posix_types.h linux/include/linux/posix_types.h
--- v2.0.0/linux/include/linux/posix_types.h	Wed Mar 27 08:19:29 1996
+++ linux/include/linux/posix_types.h	Tue Jul  2 19:08:43 1996
@@ -12,10 +12,10 @@
 #endif
 
 /*
- * This allows for 256 file descriptors: if NR_OPEN is ever grown
- * beyond that you'll have to change this too. But 256 fd's seem to be
- * enough even for such "real" unices like SunOS, so hopefully this is
- * one limit that doesn't have to be changed.
+ * This allows for 1024 file descriptors: if NR_OPEN is ever grown
+ * beyond that you'll have to change this too. But 1024 fd's seem to be
+ * enough even for such "real" unices like OSF/1, so hopefully this is
+ * one limit that doesn't have to be changed [again].
  *
  * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in
  * <sys/time.h> (and thus <linux/time.h>) - but this is a more logical
@@ -30,7 +30,7 @@
 #define __NFDBITS	(8 * sizeof(unsigned int))
 
 #undef __FD_SETSIZE
-#define __FD_SETSIZE	256
+#define __FD_SETSIZE	1024
 
 #undef __FDSET_INTS
 #define __FDSET_INTS	(__FD_SETSIZE/__NFDBITS)
@@ -41,7 +41,7 @@
 #undef __FDMASK
 #define	__FDMASK(d)	(1 << ((d) % __NFDBITS))
 
-typedef struct fd_set {
+typedef struct {
 	unsigned int fds_bits [__FDSET_INTS];
 } __kernel_fd_set;
 
diff -u --recursive --new-file v2.0.0/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v2.0.0/linux/include/linux/soundcard.h	Sun Apr 21 12:39:03 1996
+++ linux/include/linux/soundcard.h	Sun Jun 30 12:25:28 1996
@@ -58,6 +58,8 @@
 #define SNDCARD_MAUI		23
 #define SNDCARD_PSEUDO_MSS	24
 #define SNDCARD_GUSPNP		25
+#define SNDCARD_UART401		26
+/* Soundcard numbers 27 to N are reserved. Don't add more numbers here */
 
 /***********************************
  * IOCTL Commands for /dev/sequencer
@@ -140,7 +142,7 @@
  *	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
- *	sample based patches but is probably too limited.
+ *	sample based patches but is propably too limited.
  */
 
 struct patch_info {
@@ -168,6 +170,7 @@
 #define WAVE_VIBRATO	0x00010000	/* The vibrato info is valid */
 #define WAVE_TREMOLO	0x00020000	/* The tremolo info is valid */
 #define WAVE_SCALE	0x00040000	/* The scaling info is valid */
+#define WAVE_FRACTIONS	0x00080000	/* Fraction information is valid */
 /* Other bits must be zeroed */
 
 		int len;	/* Size of the wave data in bytes */
@@ -220,7 +223,8 @@
 		unsigned int	scale_factor;		/* from 0 to 2048 or 0 to 2 */
 	
 	        int		volume;
-	        int		spare[4];
+		int		fractions;
+	        int		spare[3];
 		char data[1];	/* The waveform data starts here */
 	};
 
@@ -259,7 +263,7 @@
  * may confuse the patch manager daemon.
  */
 
-struct patmgr_info {	/* Note! size must be < 4k since kmalloc() is used */
+struct patmgr_info {
 	  unsigned int key;	/* Don't worry. Reserved for communication
 	  			   between the patch manager and the driver. */
 #define PM_K_EVENT		1 /* Event from the /dev/sequencer driver */
@@ -550,7 +554,8 @@
 #define SNDCTL_DSP_STEREO		_IOWR('P', 3, int)
 #define SNDCTL_DSP_GETBLKSIZE		_IOWR('P', 4, int)
 #define SNDCTL_DSP_SAMPLESIZE		SNDCTL_DSP_SETFMT
-#define SOUND_PCM_WRITE_CHANNELS	_IOWR('P', 6, int)
+#define SNDCTL_DSP_CHANNELS		_IOWR('P', 6, int)
+#define SOUND_PCM_WRITE_CHANNELS	SNDCTL_DSP_CHANNELS
 #define SOUND_PCM_WRITE_FILTER		_IOWR('P', 7, int)
 #define SNDCTL_DSP_POST			_IO  ('P', 8)
 #define SNDCTL_DSP_SUBDIVIDE		_IOWR('P', 9, int)
@@ -575,7 +580,7 @@
  * Buffer status queries.
  */
 typedef struct audio_buf_info {
-			int fragments;	/* # of available fragments (partially used ones not counted) */
+			int fragments;	/* # of available fragments (partially usend ones not counted) */
 			int fragstotal;	/* Total # of fragments allocated */
 			int fragsize;	/* Size of a fragment in bytes */
 
@@ -688,7 +693,7 @@
 #define SNDCTL_COPR_WCODE	      _IOW ('C',  5, copr_debug_buf)
 #define SNDCTL_COPR_RUN		      _IOWR('C',  6, copr_debug_buf)
 #define SNDCTL_COPR_HALT	      _IOWR('C',  7, copr_debug_buf)
-#define SNDCTL_COPR_SENDMSG	      _IOW ('C',  8, copr_msg)
+#define SNDCTL_COPR_SENDMSG	      _IOWR('C',  8, copr_msg)
 #define SNDCTL_COPR_RCVMSG	      _IOR ('C',  9, copr_msg)
 
 /*********************************************
@@ -722,7 +727,7 @@
 /* 
  * The AD1848 codec and compatibles have three line level inputs
  * (line, aux1 and aux2). Since each card manufacturer have assigned
- * different meanings to these inputs, it's impractical to assign
+ * different meanings to these inputs, it's inpractical to assign
  * specific meanings (line, cd, synth etc.) to them.
  */
 #define SOUND_MIXER_LINE1	14	/* Input source 1  (aux1) */
@@ -737,6 +742,7 @@
 /* Note!	Number 31 cannot be used since the sign bit is reserved */
 
 
+#ifdef NO_LONGER_AVAILABLE
 /*
  * The following unsupported macros will be removed from the API in near
  * future.
@@ -744,7 +750,7 @@
 #define SOUND_MIXER_ENHANCE	29	/* Enhanced stereo (0, 40, 60 or 80) */
 #define SOUND_MIXER_MUTE	28	/* 0 or 1 */
 #define SOUND_MIXER_LOUD	30	/* 0 or 1 */
-
+#endif
 
 
 #define SOUND_DEVICE_LABELS	{"Vol  ", "Bass ", "Trebl", "Synth", "Pcm  ", "Spkr ", "Line ", \
@@ -784,9 +790,11 @@
 #define SOUND_MASK_LINE2	(1 << SOUND_MIXER_LINE2)
 #define SOUND_MASK_LINE3	(1 << SOUND_MIXER_LINE3)
 
+#ifdef NO_LONGER_AVAILABLE
 #define SOUND_MASK_MUTE		(1 << SOUND_MIXER_MUTE)
 #define SOUND_MASK_ENHANCE	(1 << SOUND_MIXER_ENHANCE)
 #define SOUND_MASK_LOUD		(1 << SOUND_MIXER_LOUD)
+#endif
 
 #define MIXER_READ(dev)		_IOR('M', dev, int)
 #define SOUND_MIXER_READ_VOLUME		MIXER_READ(SOUND_MIXER_VOLUME)
@@ -806,9 +814,11 @@
 #define SOUND_MIXER_READ_LINE1		MIXER_READ(SOUND_MIXER_LINE1)
 #define SOUND_MIXER_READ_LINE2		MIXER_READ(SOUND_MIXER_LINE2)
 #define SOUND_MIXER_READ_LINE3		MIXER_READ(SOUND_MIXER_LINE3)
+#ifdef NO_LONGER_AVAILABLE
 #define SOUND_MIXER_READ_MUTE		MIXER_READ(SOUND_MIXER_MUTE)
 #define SOUND_MIXER_READ_ENHANCE	MIXER_READ(SOUND_MIXER_ENHANCE)
 #define SOUND_MIXER_READ_LOUD		MIXER_READ(SOUND_MIXER_LOUD)
+#endif
 
 #define SOUND_MIXER_READ_RECSRC		MIXER_READ(SOUND_MIXER_RECSRC)
 #define SOUND_MIXER_READ_DEVMASK	MIXER_READ(SOUND_MIXER_DEVMASK)
@@ -834,12 +844,42 @@
 #define SOUND_MIXER_WRITE_LINE1		MIXER_WRITE(SOUND_MIXER_LINE1)
 #define SOUND_MIXER_WRITE_LINE2		MIXER_WRITE(SOUND_MIXER_LINE2)
 #define SOUND_MIXER_WRITE_LINE3		MIXER_WRITE(SOUND_MIXER_LINE3)
+#ifdef NO_LONGER_AVAILABLE
 #define SOUND_MIXER_WRITE_MUTE		MIXER_WRITE(SOUND_MIXER_MUTE)
 #define SOUND_MIXER_WRITE_ENHANCE	MIXER_WRITE(SOUND_MIXER_ENHANCE)
 #define SOUND_MIXER_WRITE_LOUD		MIXER_WRITE(SOUND_MIXER_LOUD)
+#endif
 
 #define SOUND_MIXER_WRITE_RECSRC	MIXER_WRITE(SOUND_MIXER_RECSRC)
 
+typedef struct mixer_info
+{
+  char id[16];
+  char name[32];
+} mixer_info;
+
+#define SOUND_MIXER_INFO		_IOR ('M', 101, mixer_info)
+
+/*
+ * A mechanism for accessing "proprietary" mixer features. This method
+ * permits passing 128 bytes of arbitrary data between a mixer application
+ * and the mixer driver. Interpretation of the record is defined by
+ * the particular mixer driver.
+ */
+typedef unsigned char mixer_record[128];
+
+#define SOUND_MIXER_ACCESS		_IOWR('M', 102, mixer_record)
+
+/*
+ * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers.
+ * These features can be used when accessing device specific features.
+ */
+#define SOUND_MIXER_PRIVATE1		_IOWR('M', 111, int)
+#define SOUND_MIXER_PRIVATE2		_IOWR('M', 112, int)
+#define SOUND_MIXER_PRIVATE3		_IOWR('M', 113, int)
+#define SOUND_MIXER_PRIVATE4		_IOWR('M', 114, int)
+#define SOUND_MIXER_PRIVATE5		_IOWR('M', 115, int)
+
 /*
  * Level 2 event types for /dev/sequencer
  */
@@ -1077,7 +1117,7 @@
 #define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
 
 /*
- * Timing and synchronization macros
+ * Timing and syncronization macros
  */
 
 #define _TIMER_EVENT(ev, parm)		{_SEQ_NEEDBUF(8);\
diff -u --recursive --new-file v2.0.0/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v2.0.0/linux/include/linux/sysv_fs.h	Mon Mar 25 10:26:15 1996
+++ linux/include/linux/sysv_fs.h	Wed Jul  3 17:58:15 1996
@@ -373,7 +373,7 @@
 extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
 extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
 extern int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len);
+	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir);
 extern struct inode * sysv_new_inode(const struct inode * dir);
 extern void sysv_free_inode(struct inode * inode);
 extern unsigned long sysv_count_free_inodes(struct super_block *sb);
diff -u --recursive --new-file v2.0.0/linux/include/linux/time.h linux/include/linux/time.h
--- v2.0.0/linux/include/linux/time.h	Tue Feb 13 19:55:59 1996
+++ linux/include/linux/time.h	Tue Jul  2 19:08:43 1996
@@ -1,10 +1,13 @@
 #ifndef _LINUX_TIME_H
 #define _LINUX_TIME_H
 
+#ifndef _STRUCT_TIMESPEC
+#define _STRUCT_TIMESPEC
 struct timespec {
 	long	tv_sec;		/* seconds */
 	long	tv_nsec;	/* nanoseconds */
 };
+#endif /* _STRUCT_TIMESPEC */
 
 struct timeval {
 	int	tv_sec;		/* seconds */
diff -u --recursive --new-file v2.0.0/linux/include/linux/ultrasound.h linux/include/linux/ultrasound.h
--- v2.0.0/linux/include/linux/ultrasound.h	Fri Apr 12 15:52:08 1996
+++ linux/include/linux/ultrasound.h	Sun Jun 30 11:43:41 1996
@@ -6,27 +6,11 @@
  *			and not portable.
  */
 /*
- * Copyright by Hannu Savolainen 1993-1996
+ * Copyright (C) by Hannu Savolainen 1993-1996
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * Version 2 (June 1991). See the "COPYING" file distributed with this software
+ * for more info.
  */
 
 
@@ -50,7 +34,7 @@
  *		_GUS_VOICEOFF	- Stops voice (no parameters)
  *		_GUS_VOICEFADE	- Stops the voice smoothly.
  *		_GUS_VOICEMODE	- Alters the voice mode, don't start or stop voice (P1=voice mode)
- *		_GUS_VOICEBALA	- Sets voice balance (P1, 0=left, 7=middle and 15=right, default 7)
+ *		_GUS_VOICEBALA	- Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7)
  *		_GUS_VOICEFREQ	- Sets voice (sample) playback frequency (P1=Hz)
  *		_GUS_VOICEVOL	- Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
  *		_GUS_VOICEVOL2	- Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
diff -u --recursive --new-file v2.0.0/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- v2.0.0/linux/include/linux/umsdos_fs.p	Tue Aug  1 10:02:47 1995
+++ linux/include/linux/umsdos_fs.p	Wed Jul  3 16:39:14 1996
@@ -122,7 +122,8 @@
 	 int old_len,
 	 struct inode *new_dir,
 	 const char *new_name,
-	 int new_len);
+	 int new_len,
+	 int must_be_dir);
 /* rdir.c 22/03/95 03.31.42 */
 int umsdos_rlookup_x (struct inode *dir,
 	 const char *name,
diff -u --recursive --new-file v2.0.0/linux/include/linux/xia_fs.h linux/include/linux/xia_fs.h
--- v2.0.0/linux/include/linux/xia_fs.h	Mon Jan 15 07:59:14 1996
+++ linux/include/linux/xia_fs.h	Wed Jul  3 11:53:06 1996
@@ -79,7 +79,8 @@
 		     	int mode, int rdev);
 extern int xiafs_rename(struct inode * old_dir, const char * old_name, 
 		      	int old_len, struct inode * new_dir, 
-		      	const char * new_name, int new_len);
+		      	const char * new_name, int new_len,
+		      	int must_be_dir);
 extern struct inode * xiafs_new_inode(struct inode * dir);
 extern void xiafs_free_inode(struct inode * inode);
 extern unsigned long xiafs_count_free_inodes(struct super_block *sb);
diff -u --recursive --new-file v2.0.0/linux/include/scsi/scsi.h linux/include/scsi/scsi.h
--- v2.0.0/linux/include/scsi/scsi.h	Wed Jun  5 10:41:29 1996
+++ linux/include/scsi/scsi.h	Wed Jun 26 11:05:26 1996
@@ -96,7 +96,7 @@
 #define RESERVATION_CONFLICT 0x0c
 #define QUEUE_FULL           0x1a
 
-#define STATUS_MASK          0x1e
+#define STATUS_MASK          0x3e
 
 /*
  *  SENSE KEYS
diff -u --recursive --new-file v2.0.0/linux/kernel/exit.c linux/kernel/exit.c
--- v2.0.0/linux/kernel/exit.c	Mon Jun  3 16:46:59 1996
+++ linux/kernel/exit.c	Tue Jul  2 19:08:43 1996
@@ -75,8 +75,8 @@
 	if (!p || sig > 32)
 		return -EINVAL;
 	if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
-	    (current->euid ^ p->euid) && (current->euid ^ p->uid) &&
-	    (current->uid ^ p->euid) && (current->uid ^ p->uid) &&
+	    (current->euid ^ p->suid) && (current->euid ^ p->uid) &&
+	    (current->uid ^ p->suid) && (current->uid ^ p->uid) &&
 	    !suser())
 		return -EPERM;
 	if (!sig)
@@ -346,12 +346,12 @@
  * 
  * "I ask you, have you ever known what it is to be an orphan?"
  */
-int is_orphaned_pgrp(int pgrp)
+static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task)
 {
 	struct task_struct *p;
 
 	for_each_task(p) {
-		if ((p->pgrp != pgrp) || 
+		if ((p == ignored_task) || (p->pgrp != pgrp) || 
 		    (p->state == TASK_ZOMBIE) ||
 		    (p->p_pptr->pid == 1))
 			continue;
@@ -362,6 +362,11 @@
 	return(1);	/* (sighing) "Often!" */
 }
 
+int is_orphaned_pgrp(int pgrp)
+{
+	return will_become_orphaned_pgrp(pgrp, 0);
+}
+
 static inline int has_stopped_jobs(int pgrp)
 {
 	struct task_struct * p;
@@ -495,7 +500,7 @@
 	 */
 	if ((current->p_pptr->pgrp != current->pgrp) &&
 	    (current->p_pptr->session == current->session) &&
-	    is_orphaned_pgrp(current->pgrp) &&
+	    will_become_orphaned_pgrp(current->pgrp, current) &&
 	    has_stopped_jobs(current->pgrp)) {
 		kill_pg(current->pgrp,SIGHUP,1);
 		kill_pg(current->pgrp,SIGCONT,1);
@@ -607,6 +612,9 @@
 		if (flag)
 			return flag;
 	}
+	if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
+	    return -EINVAL;
+
 	add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
 	flag=0;
@@ -666,12 +674,11 @@
 		retval = 0;
 		if (options & WNOHANG)
 			goto end_wait4;
-		current->state=TASK_INTERRUPTIBLE;
-		schedule();
-		current->signal &= ~(1<<(SIGCHLD-1));
 		retval = -ERESTARTSYS;
 		if (current->signal & ~current->blocked)
 			goto end_wait4;
+		current->state=TASK_INTERRUPTIBLE;
+		schedule();
 		goto repeat;
 	}
 	retval = -ECHILD;
diff -u --recursive --new-file v2.0.0/linux/kernel/fork.c linux/kernel/fork.c
--- v2.0.0/linux/kernel/fork.c	Tue Apr 23 13:57:14 1996
+++ linux/kernel/fork.c	Tue Jul  2 19:08:43 1996
@@ -34,7 +34,6 @@
 static inline int find_empty_process(void)
 {
 	int i;
-	struct task_struct *p;
 
 	if (nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) {
 		if (current->uid)
@@ -43,7 +42,9 @@
 	if (current->uid) {
 		long max_tasks = current->rlim[RLIMIT_NPROC].rlim_cur;
 
+		max_tasks--;	/* count the new process.. */
 		if (max_tasks < nr_tasks) {
+			struct task_struct *p;
 			for_each_task (p) {
 				if (p->uid == current->uid)
 					if (--max_tasks < 0)
diff -u --recursive --new-file v2.0.0/linux/kernel/sched.c linux/kernel/sched.c
--- v2.0.0/linux/kernel/sched.c	Tue May  7 16:22:40 1996
+++ linux/kernel/sched.c	Sat Jun 29 12:00:48 1996
@@ -573,6 +573,7 @@
 {
 	struct timer_list * timer;
 
+	cli();
 	while ((timer = timer_head.next) != &timer_head && timer->expires <= jiffies) {
 		void (*fn)(unsigned long) = timer->function;
 		unsigned long data = timer->data;
@@ -583,6 +584,7 @@
 		fn(data);
 		cli();
 	}
+	sti();
 }
 
 static inline void run_old_timers(void)
@@ -942,6 +944,12 @@
 			}
 			update_one_process(p, ticks, utime, stime);
 
+			if (p->priority < DEF_PRIORITY)
+				kstat.cpu_nice += utime;
+			else
+				kstat.cpu_user += utime;
+			kstat.cpu_system += stime;
+
 			p->counter -= ticks;
 			if (p->counter >= 0)
 				continue;
@@ -966,25 +974,27 @@
 static unsigned long lost_ticks = 0;
 static unsigned long lost_ticks_system = 0;
 
-static void timer_bh(void)
+static inline void update_times(void)
 {
-	unsigned long ticks, system;
+	unsigned long ticks;
 
-	run_old_timers();
-
-	cli();
-	run_timer_list();
-	ticks = lost_ticks;
-	lost_ticks = 0;
-	system = lost_ticks_system;
-	lost_ticks_system = 0;
-	sti();
+	ticks = xchg(&lost_ticks, 0);
 
 	if (ticks) {
+		unsigned long system;
+
+		system = xchg(&lost_ticks_system, 0);
 		calc_load(ticks);
 		update_wall_time(ticks);
 		update_process_times(ticks, system);
 	}
+}
+
+static void timer_bh(void)
+{
+	update_times();
+	run_old_timers();
+	run_timer_list();
 }
 
 /*
diff -u --recursive --new-file v2.0.0/linux/kernel/signal.c linux/kernel/signal.c
--- v2.0.0/linux/kernel/signal.c	Sat Feb 17 09:19:43 1996
+++ linux/kernel/signal.c	Tue Jul  2 19:08:43 1996
@@ -91,7 +91,7 @@
  * POSIX 3.3.1.3:
  *  "Setting a signal action to SIG_IGN for a signal that is pending
  *   shall cause the pending signal to be discarded, whether or not
- *   it is blocked" (but SIGCHLD is unspecified: linux leaves it alone).
+ *   it is blocked."
  *
  *  "Setting a signal action to SIG_DFL for a signal that is pending
  *   and whose default action is to ignore the signal (for example,
@@ -108,8 +108,6 @@
 
 	p = signum - 1 + current->sig->action;
 	if (p->sa_handler == SIG_IGN) {
-		if (signum == SIGCHLD)
-			return;
 		current->signal &= ~_S(signum);
 		return;
 	}
@@ -156,18 +154,14 @@
 
 	if (signum<1 || signum>32)
 		return -EINVAL;
-	if (signum==SIGKILL || signum==SIGSTOP)
-		return -EINVAL;
 	p = signum - 1 + current->sig->action;
 	if (action) {
 		int err = verify_area(VERIFY_READ, action, sizeof(*action));
 		if (err)
 			return err;
+		if (signum==SIGKILL || signum==SIGSTOP)
+			return -EINVAL;
 		memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
-		new_sa.sa_mask |= _S(signum);
-		if (new_sa.sa_flags & SA_NOMASK)
-			new_sa.sa_mask &= ~_S(signum);
-		new_sa.sa_mask &= _BLOCKABLE;
 		if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
 			err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
 			if (err)
diff -u --recursive --new-file v2.0.0/linux/kernel/sys.c linux/kernel/sys.c
--- v2.0.0/linux/kernel/sys.c	Thu Jun  6 17:42:38 1996
+++ linux/kernel/sys.c	Tue Jul  2 19:08:43 1996
@@ -634,8 +634,13 @@
 
 asmlinkage int sys_setsid(void)
 {
-	if (current->leader)
-		return -EPERM;
+	struct task_struct * p;
+
+	for_each_task(p) {
+		if (p->pgrp == current->pid)
+		        return -EPERM;
+	}
+
 	current->leader = 1;
 	current->session = current->pgrp = current->pid;
 	current->tty = NULL;
@@ -651,21 +656,29 @@
 	int i;
 	int * groups;
 
-	if (gidsetsize) {
-		i = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize);
-		if (i)
-			return i;
-	}
+	if (gidsetsize < 0)
+		return -EINVAL;
 	groups = current->groups;
-	for (i = 0 ; (i < NGROUPS) && (*groups != NOGROUP) ; i++, groups++) {
-		if (!gidsetsize)
-			continue;
-		if (i >= gidsetsize)
+	for (i = 0 ; i < NGROUPS ; i++) {
+		if (groups[i] == NOGROUP)
 			break;
-		put_user(*groups, grouplist);
-		grouplist++;
 	}
-	return(i);
+	if (gidsetsize) {
+		int error;
+		error = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize);
+		if (error)
+			return error;
+		if (i > gidsetsize)
+		        return -EINVAL;
+
+		for (i = 0 ; i < NGROUPS ; i++) {
+			if (groups[i] == NOGROUP)
+				break;
+			put_user(groups[i], grouplist);
+			grouplist++;
+		}
+	}
+	return i;
 }
 
 asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
diff -u --recursive --new-file v2.0.0/linux/lib/ctype.c linux/lib/ctype.c
--- v2.0.0/linux/lib/ctype.c	Mon Nov 27 15:53:48 1995
+++ linux/lib/ctype.c	Tue Jul  2 19:08:43 1996
@@ -26,10 +26,11 @@
 _L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 160-175 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 176-191 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 192-207 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 208-223 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 224-239 */
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};		/* 240-255 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
+
 
diff -u --recursive --new-file v2.0.0/linux/mm/mremap.c linux/mm/mremap.c
--- v2.0.0/linux/mm/mremap.c	Fri Apr 12 15:52:10 1996
+++ linux/mm/mremap.c	Wed Jun 26 09:44:52 1996
@@ -167,8 +167,6 @@
 		return -EINVAL;
 	old_len = PAGE_ALIGN(old_len);
 	new_len = PAGE_ALIGN(new_len);
-	if (old_len == new_len)
-		return addr;
 
 	/*
 	 * Always allow a shrinking remap: that just unmaps
@@ -196,7 +194,8 @@
 	}
 
 	/* old_len exactly to the end of the area.. */
-	if (old_len == vma->vm_end - addr) {
+	if (old_len == vma->vm_end - addr &&
+	    (old_len != new_len || !(flags & MREMAP_MAYMOVE))) {
 		unsigned long max_addr = TASK_SIZE;
 		if (vma->vm_next)
 			max_addr = vma->vm_next->vm_start;
diff -u --recursive --new-file v2.0.0/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.0.0/linux/mm/swapfile.c	Fri May 31 08:02:20 1996
+++ linux/mm/swapfile.c	Tue Jun 11 13:00:11 1996
@@ -16,6 +16,7 @@
 #include <linux/swap.h>
 #include <linux/fs.h>
 #include <linux/swapctl.h>
+#include <linux/blkdev.h> /* for blk_size */
 
 #include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
@@ -457,7 +458,9 @@
 		if(error)
 			goto bad_swap_2;
 		error = -ENODEV;
-		if (!p->swap_device)
+		if (!p->swap_device ||
+		    (blk_size[MAJOR(p->swap_device)] &&
+		     !blk_size[MAJOR(p->swap_device)][MINOR(p->swap_device)]))
 			goto bad_swap;
 		error = -EBUSY;
 		for (i = 0 ; i < nr_swapfiles ; i++) {
diff -u --recursive --new-file v2.0.0/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.0.0/linux/mm/vmscan.c	Thu Jun  6 17:42:38 1996
+++ linux/mm/vmscan.c	Fri Jun 28 18:49:55 1996
@@ -404,6 +404,7 @@
 	while (1) {
 		kswapd_awake = 0;
 		current->signal = 0;
+		run_task_queue(&tq_disk);
 		interruptible_sleep_on(&kswapd_wait);
 		kswapd_awake = 1;
 		swapstats.wakeups++;
diff -u --recursive --new-file v2.0.0/linux/net/core/sock.c linux/net/core/sock.c
--- v2.0.0/linux/net/core/sock.c	Sun Jun  9 13:28:47 1996
+++ linux/net/core/sock.c	Wed Jun 26 11:05:26 1996
@@ -185,6 +185,8 @@
 			 	val = SK_RMEM_MAX*2;
 			if(val < 256)
 				val = 256;
+			if(val > 65535)
+				val = 65535;
 			sk->rcvbuf = val;
 			return(0);
 
diff -u --recursive --new-file v2.0.0/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.0.0/linux/net/ipv4/af_inet.c	Sun Jun  9 13:28:47 1996
+++ linux/net/ipv4/af_inet.c	Tue Jul  2 19:08:43 1996
@@ -926,7 +926,7 @@
 			 *	Reuse ?
 			 */
 			 
-			if (!sk2->reuse || sk2->state==TCP_LISTEN) 
+			if (!sk2->dead)
 			{
 				sti();
 				return(-EADDRINUSE);
diff -u --recursive --new-file v2.0.0/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.0.0/linux/net/ipv4/ip_forward.c	Thu Jun  6 17:42:39 1996
+++ linux/net/ipv4/ip_forward.c	Tue Jul  2 12:14:08 1996
@@ -326,7 +326,7 @@
 #ifdef CONFIG_IP_MROUTE
 			if(is_frag&IPFWD_MULTITUNNEL)
 			{
-				skb_reserve(skb,(encap+dev->hard_header_len+15)&~15);	/* 16 byte aligned IP headers are good */
+				skb_reserve(skb2,(encap+dev2->hard_header_len+15)&~15);	/* 16 byte aligned IP headers are good */
 				ip_encap(skb2,skb->len, dev2, raddr);
 			}
 			else
diff -u --recursive --new-file v2.0.0/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v2.0.0/linux/net/ipv4/ip_fw.c	Sun Jun  9 13:28:47 1996
+++ linux/net/ipv4/ip_fw.c	Sat Jun 29 12:00:48 1996
@@ -264,9 +264,11 @@
 	
 	/*
 	 *	Too short.
+	 *
+	 *	But only too short for a packet with ports...
 	 */
 	 
-	else if(ntohs(ip->tot_len)<8+(ip->ihl<<2))
+	else if((ntohs(ip->tot_len)<8+(ip->ihl<<2))&&(ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP))
 		return FW_BLOCK;
 		
 	src = ip->saddr;
diff -u --recursive --new-file v2.0.0/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c
--- v2.0.0/linux/net/ipv4/ip_masq_app.c	Sat Jun  1 20:11:37 1996
+++ linux/net/ipv4/ip_masq_app.c	Fri Jun 28 18:49:55 1996
@@ -2,7 +2,7 @@
  *		IP_MASQ_APP application masquerading module
  *
  *
- * Version:	@(#)ip_masq_app.c  0.03      03/96
+ * Version:	@(#)ip_masq_app.c  0.04      96/06/17
  *
  * Author:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
  *
@@ -13,7 +13,8 @@
  *	2 of the License, or (at your option) any later version.
  *
  * Fixes:
- *	JJC		: Implemented also input pkt hook
+ *	JJC			: Implemented also input pkt hook
+ *	Miquel van Smoorenburg	: Copy more stuff when resizing skb
  *
  *
  * FIXME:
@@ -502,6 +503,7 @@
 {
         int maxsize, diff, o_offset;
         struct sk_buff *n_skb;
+	int offset;
 
 	maxsize = skb->truesize - sizeof(struct sk_buff);
 
@@ -521,7 +523,9 @@
 	    skb->end = skb->head+n_len;
 	} else {
                 /*
-                 * 	Sizes differ, make a copy
+                 * 	Sizes differ, make a copy.
+                 *
+                 *	FIXME: move this to core/sbuff.c:skb_grow()
                  */
         
                 n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri);
@@ -534,8 +538,22 @@
                 n_skb->free = skb->free;
                 skb_reserve(n_skb, MAX_HEADER);
                 skb_put(n_skb, skb->len + diff);
-                n_skb->h.raw = n_skb->data + (skb->h.raw - skb->data);
-                
+
+                /*
+                 *	Copy as much data from the old skb as possible. Even
+                 *	though we're only forwarding packets, we need stuff
+                 *	like skb->protocol (PPP driver wants it).
+                 */
+                offset = n_skb->data - skb->data;
+                n_skb->h.raw = skb->h.raw + offset;
+                n_skb->when = skb->when;
+                n_skb->dev = skb->dev;
+                n_skb->mac.raw = skb->mac.raw + offset;
+                n_skb->ip_hdr = (struct iphdr *)(((char *)skb->ip_hdr)+offset);
+                n_skb->pkt_type = skb->pkt_type;
+                n_skb->protocol = skb->protocol;
+                n_skb->ip_summed = skb->ip_summed;
+
                 /*
                  * Copy pkt in new buffer
                  */
diff -u --recursive --new-file v2.0.0/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.0.0/linux/net/ipv4/ip_output.c	Thu Jun  6 17:42:39 1996
+++ linux/net/ipv4/ip_output.c	Sat Jun 29 20:47:09 1996
@@ -107,7 +107,7 @@
 	/* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */
 		
 	/*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/
-	ip_queue_xmit(NULL, dev, newskb, 1);
+	ip_queue_xmit(NULL, dev, newskb, 2);
 }
 
 
@@ -160,9 +160,9 @@
 	skb->dev = dev;
 	skb->arp = 1;
 	skb->protocol = htons(ETH_P_IP);
+	skb_reserve(skb,MAX_HEADER);
 	if (dev->hard_header)
 	{
-		skb_reserve(skb,MAX_HEADER);
 		if (rt && dev == rt->rt_dev && rt->rt_hh)
 		{
 			memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len);
@@ -574,7 +574,7 @@
 	ip_statistics.IpOutRequests++;
 
 #ifdef CONFIG_IP_MULTICAST	
-	if(sk && MULTICAST(daddr) && *sk->ip_mc_name)
+	if(MULTICAST(daddr) && *sk->ip_mc_name)
 	{
 		dev=dev_get(sk->ip_mc_name);
 		if(!dev)
@@ -710,8 +710,10 @@
 		}
 		return 0;
 	}
-	length -= sizeof(struct iphdr);
-	if (sk && !sk->ip_hdrincl && opt) 
+	if (!sk->ip_hdrincl)
+		length -= sizeof(struct iphdr);
+		
+	if(opt) 
 	{
 		length -= opt->optlen;
 		fragheaderlen = dev->hard_header_len + sizeof(struct iphdr) + opt->optlen;
@@ -810,6 +812,7 @@
 		skb->sk = sk;
 		skb->arp = 0;
 		skb->saddr = saddr;
+		skb->daddr = daddr;
 		skb->raddr = raddr;
 		skb_reserve(skb,(dev->hard_header_len+15)&~15);
 		data = skb_put(skb, fraglen-dev->hard_header_len);
@@ -927,7 +930,7 @@
 			 
 			if(sk==NULL || sk->ip_mc_loop)
 			{
-				if(skb->daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI))
+				if(daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI))
 					ip_loopback(dev,skb);
 				else 
 				{
@@ -950,7 +953,11 @@
 			 */
 
 			if(skb->ip_hdr->ttl==0)
-				kfree_skb(skb, FREE_READ);
+			{
+				kfree_skb(skb, FREE_WRITE);
+				nfrags++;
+				continue;
+			}
 		}
 #endif
 
diff -u --recursive --new-file v2.0.0/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.0.0/linux/net/ipv4/tcp.c	Sun Jun  9 13:28:47 1996
+++ linux/net/ipv4/tcp.c	Tue Jul  2 19:08:44 1996
@@ -551,8 +551,15 @@
 			if (rt->rt_mtu > new_mtu)
 				rt->rt_mtu = new_mtu;
 
+		/*
+		 *	FIXME::
+		 *	Not the nicest of fixes: Lose a MTU update if the socket is
+		 *	locked this instant. Not the right answer but will be best
+		 *	for the production fix. Make 2.1 work right!
+		 */
+		 
 		if (sk->mtu > new_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr)
-			&& new_mtu > sizeof(struct iphdr)+sizeof(struct tcphdr))
+			&& new_mtu > sizeof(struct iphdr)+sizeof(struct tcphdr) && !sk->users)
 			sk->mtu = new_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr);
 
 		return;
@@ -943,40 +950,44 @@
 				return -EPIPE;
 			}
 
-		/*
-		 * The following code can result in copy <= if sk->mss is ever
-		 * decreased.  It shouldn't be.  sk->mss is min(sk->mtu, sk->max_window).
-		 * sk->mtu is constant once SYN processing is finished.  I.e. we
-		 * had better not get here until we've seen his SYN and at least one
-		 * valid ack.  (The SYN sets sk->mtu and the ack sets sk->max_window.)
-		 * But ESTABLISHED should guarantee that.  sk->max_window is by definition
-		 * non-decreasing.  Note that any ioctl to set user_mss must be done
-		 * before the exchange of SYN's.  If the initial ack from the other
-		 * end has a window of 0, max_window and thus mss will both be 0.
-		 */
+			/*
+			 * The following code can result in copy <= if sk->mss is ever
+			 * decreased.  It shouldn't be.  sk->mss is min(sk->mtu, sk->max_window).
+			 * sk->mtu is constant once SYN processing is finished.  I.e. we
+			 * had better not get here until we've seen his SYN and at least one
+			 * valid ack.  (The SYN sets sk->mtu and the ack sets sk->max_window.)
+			 * But ESTABLISHED should guarantee that.  sk->max_window is by definition
+			 * non-decreasing.  Note that any ioctl to set user_mss must be done
+			 * before the exchange of SYN's.  If the initial ack from the other
+			 * end has a window of 0, max_window and thus mss will both be 0.
+			 */
 
-		/*
-		 *	Now we need to check if we have a half built packet.
-		 */
+			/*
+			 *	Now we need to check if we have a half built packet.
+			 */
 #ifndef CONFIG_NO_PATH_MTU_DISCOVERY
-		/*
-		 *	FIXME:  I'm almost sure that this fragment is BUG,
-		 *		but it works... I do not know why 8) --ANK
-		 *
-		 *	Really, we should rebuild all the queues...
-		 *	It's difficult. Temporary hack is to send all
-		 *	queued segments with allowed fragmentation.
-		 */
-		{
-			int new_mss = min(sk->mtu, sk->max_window);
-			if (new_mss < sk->mss)
+			/*
+			 *	FIXME:  I'm almost sure that this fragment is BUG,
+			 *		but it works... I do not know why 8) --ANK
+			 *
+			 *	Really, we should rebuild all the queues...
+			 *	It's difficult. Temporary hack is to send all
+			 *	queued segments with allowed fragmentation.
+			 */
 			{
-				tcp_send_partial(sk);
-				sk->mss = new_mss;
+				int new_mss = min(sk->mtu, sk->max_window);
+				if (new_mss < sk->mss)
+				{
+					tcp_send_partial(sk);
+					sk->mss = new_mss;
+				}
 			}
-		}
 #endif
 
+			/*
+			 *	If there is a partly filled frame we can fill
+			 *	out.
+			 */
 			if ((skb = tcp_dequeue_partial(sk)) != NULL)
 			{
 				int tcp_size;
@@ -987,11 +998,33 @@
 				if (!(flags & MSG_OOB))
 				{
 					copy = min(sk->mss - tcp_size, seglen);
+					
+					/*
+					 *	Now we may find the frame is as big, or too
+					 *	big for our MSS. Thats all fine. It means the
+					 *	MSS shrank (from an ICMP) after we allocated 
+					 *	this frame.
+					 */
+					 
 					if (copy <= 0)
 					{
-						printk(KERN_CRIT "TCP: **bug**: \"copy\" <= 0\n");
-				  		return -EFAULT;
+						/*
+						 *	Send the now forced complete frame out. 
+						 *
+						 *	Note for 2.1: The MSS reduce code ought to
+						 *	flush any frames in partial that are now
+						 *	full sized. Not serious, potential tiny
+						 *	performance hit.
+						 */
+						tcp_send_skb(sk,skb);
+						/*
+						 *	Get a new buffer and try again.
+						 */
+						continue;
 					}
+					/*
+					 *	Otherwise continue to fill the buffer.
+					 */
 					tcp_size += copy;
 					memcpy_fromfs(skb_put(skb,copy), from, copy);
 					skb->csum = csum_partial(skb->tail - tcp_size, tcp_size, 0);
@@ -1378,11 +1411,9 @@
 
 		current->state = TASK_INTERRUPTIBLE;
 
-		skb = skb_peek(&sk->receive_queue);
-		do
+		skb = sk->receive_queue.next;
+		while (skb != (struct sk_buff *)&sk->receive_queue)
 		{
-			if (!skb)
-				break;
 			if (before(*seq, skb->seq))
 				break;
 			offset = *seq - skb->seq;
@@ -1396,7 +1427,6 @@
 				skb->used = 1;
 			skb = skb->next;
 		}
-		while (skb != (struct sk_buff *)&sk->receive_queue);
 
 		if (copied)
 			break;
diff -u --recursive --new-file v2.0.0/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.0.0/linux/net/ipv4/tcp_input.c	Sun Jun  9 13:28:48 1996
+++ linux/net/ipv4/tcp_input.c	Sun Jun  9 18:01:04 1996
@@ -66,7 +66,7 @@
 
 		/* This used to test against sk->rtt.
 		 * On a purely receiving link, there is no rtt measure.
-		 * The result is that we loose delayed ACKs on one way links.
+		 * The result is that we lose delayed ACKs on one-way links.
 		 * Therefore we test against sk->rto, which will always
 		 * at least have a default value.
 		 */
@@ -860,11 +860,11 @@
 	 		 * sensitive to minor changes in the round trip time.
 			 * We add in two compensating factors.
 			 * First we multiply by 5/4. For large congestion
-			 * windows this allows us to tollerate burst traffic
+			 * windows this allows us to tolerate burst traffic
 			 * delaying up to 1/4 of our packets.
 			 * We also add in a rtt / cong_window term.
 			 * For small congestion windows this allows
-			 * a single packet delay, but has neglibible effect
+			 * a single packet delay, but has negligible effect
 			 * on the compensation for large windows.
 	 		 */
 			sk->rto = (sk->rtt >> 3) + sk->mdev;
@@ -1902,7 +1902,7 @@
 			{
 				/* We got an ack, but it's not a good ack.
 				 * We used to test this with a call to tcp_ack,
-				 * but this looses, because it takes the SYN
+				 * but this loses, because it takes the SYN
 				 * packet out of the send queue, even if
 				 * the ACK doesn't have the SYN bit sent, and
 				 * therefore isn't the one we are waiting for.
@@ -1932,7 +1932,7 @@
 
 				/* process the ACK, get the SYN packet out
 				 * of the send queue, do other initial
-				 * processing stuff. [We know its good, and
+				 * processing stuff. [We know it's good, and
 				 * we know it's the SYN,ACK we want.]
 				 */
 				tcp_ack(sk,th,skb->ack_seq,len);
diff -u --recursive --new-file v2.0.0/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.0.0/linux/net/ipv4/tcp_output.c	Sun Jun  9 13:28:48 1996
+++ linux/net/ipv4/tcp_output.c	Sat Jun 29 12:00:48 1996
@@ -879,15 +879,22 @@
 void tcp_send_delayed_ack(struct sock * sk, int max_timeout, unsigned long timeout)
 {
 	unsigned long now;
+	static int delack_guard=0;
 
+	if(delack_guard)
+		return;
+	
+	delack_guard++;
+	
 	/* Calculate new timeout */
 	now = jiffies;
 	if (timeout > max_timeout)
 		timeout = max_timeout;
 	timeout += now;
 	if (sk->bytes_rcv >= sk->max_unacked) {
-		timeout = now;
-		mark_bh(TIMER_BH);
+		tcp_send_ack(sk);
+		delack_guard--;
+		return;
 	}
 
 	/* Use new timeout only if there wasn't a older one earlier  */
@@ -896,6 +903,7 @@
 
 	sk->ack_backlog++;
 	add_timer(&sk->delack_timer);
+	delack_guard--;
 }
 
 
diff -u --recursive --new-file v2.0.0/linux/net/socket.c linux/net/socket.c
--- v2.0.0/linux/net/socket.c	Thu Jun  6 17:42:39 1996
+++ linux/net/socket.c	Sat Jun 29 12:00:48 1996
@@ -778,7 +778,7 @@
 		sock_release(newsock);
 		return(-EINVAL);
 	}
-	sock->file=current->files->fd[fd];
+	newsock->file=current->files->fd[fd];
 	
 	if (upeer_sockaddr)
 	{
