diff -u --recursive --new-file v1.1.30/linux/Makefile linux/Makefile
--- v1.1.30/linux/Makefile	Mon Jul 18 14:48:27 1994
+++ linux/Makefile	Mon Jul 18 09:51:22 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 30
+SUBLEVEL = 31
 
 all:	Version zImage
 
diff -u --recursive --new-file v1.1.30/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.30/linux/drivers/block/floppy.c	Mon Jul 18 14:48:28 1994
+++ linux/drivers/block/floppy.c	Mon Jul 18 22:51:13 1994
@@ -97,7 +97,7 @@
 #define MAJOR_NR FLOPPY_MAJOR
 #include "blk.h"
 
-static unsigned int changed_floppies = 0, fake_change = 0;
+static unsigned int changed_floppies = 0, fake_change = 0, read_only = 0;
 
 static int initial_reset_flag = 0;
 static int need_configure = 1;		/* for 82077 */
@@ -150,7 +150,7 @@
 #define ST0 (reply_buffer[0])
 #define ST1 (reply_buffer[1])
 #define ST2 (reply_buffer[2])
-#define ST3 (reply_buffer[3])
+#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
 
 /*
  * This struct defines the different floppy types.
@@ -1037,8 +1037,20 @@
 	output_byte(1);
 }
 
+static void check_readonly(void)
+{
+	unsigned long mask = 1 << current_drive;
+
+	read_only &= ~mask;
+	output_byte(FD_GETSTATUS);
+	output_byte(current_drive);
+	if ((result() == 1) && (ST3 & ST3_RY) && !(ST3 & ST3_FT) && (ST3 & ST3_WP))
+		read_only |= mask;
+}
+
 static void floppy_ready(void)
 {
+	check_readonly();
 	if (inb(FD_DIR) & 0x80) {
 		changed_floppies |= 1<<current_drive;
 		buffer_track = -1;
@@ -1368,6 +1380,16 @@
 	printk("\n");
 }
 
+static void floppy_release(struct inode * inode, struct file * filp)
+{
+	fsync_dev(inode->i_rdev);
+	if (!fd_ref[inode->i_rdev & 3]--) {
+		printk("floppy_release with fd_ref == 0");
+		fd_ref[inode->i_rdev & 3] = 0;
+	}
+	floppy_release_irq_and_dma();
+}
+
 /*
  * floppy_open check for aliasing (/dev/fd0 can be the same as
  * /dev/PS0 etc), and disallows simultaneous access to the same
@@ -1390,19 +1412,16 @@
 	buffer_drive = buffer_track = -1;
 	if (old_dev && old_dev != inode->i_rdev)
 		invalidate_buffers(old_dev);
-	if (filp && filp->f_mode)
+	if (filp && filp->f_mode) {
 		check_disk_change(inode->i_rdev);
-	return 0;
-}
-
-static void floppy_release(struct inode * inode, struct file * filp)
-{
-	fsync_dev(inode->i_rdev);
-	if (!fd_ref[inode->i_rdev & 3]--) {
-		printk("floppy_release with fd_ref == 0");
-		fd_ref[inode->i_rdev & 3] = 0;
+		if (filp->f_mode & 2) {
+			if (1 & (read_only >> drive)) {
+				floppy_release(inode, filp);
+				return -EACCES;
+			}
+		}
 	}
-        floppy_release_irq_and_dma();
+	return 0;
 }
 
 static int check_floppy_change(dev_t dev)
diff -u --recursive --new-file v1.1.30/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.1.30/linux/drivers/scsi/sd.c	Mon Jul 18 14:48:29 1994
+++ linux/drivers/scsi/sd.c	Mon Jul 18 11:28:10 1994
@@ -38,7 +38,7 @@
  *	Time out in seconds for disks and Magneto-opticals (which are slower).
  */
 
-#define SD_TIMEOUT 300
+#define SD_TIMEOUT 600
 #define SD_MOD_TIMEOUT 750
 
 #define CLUSTERABLE_DEVICE(SC) (SC->host->hostt->use_clustering && \
diff -u --recursive --new-file v1.1.30/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.1.30/linux/drivers/scsi/sr.c	Mon Jul 18 14:48:30 1994
+++ linux/drivers/scsi/sr.c	Mon Jul 18 11:22:03 1994
@@ -636,7 +636,6 @@
 static void sr_init_done (Scsi_Cmnd * SCpnt)
 {
   struct request * req;
-  struct task_struct * p;
   
   req = &SCpnt->request;
   req->dev = 0xfffe; /* Busy, but indicate request done */
diff -u --recursive --new-file v1.1.30/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v1.1.30/linux/drivers/scsi/sr_ioctl.c	Mon Jul 18 14:48:30 1994
+++ linux/drivers/scsi/sr_ioctl.c	Mon Jul 18 11:21:50 1994
@@ -21,13 +21,12 @@
 static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
 {
   struct request * req;
-  struct task_struct * p;
   
   req = &SCpnt->request;
   req->dev = 0xfffe; /* Busy, but indicate request done */
   
   if (req->sem != NULL) {
-    up(&req->sem);
+    up(req->sem);
   }
 }
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/.blurb linux/drivers/sound/.blurb
--- v1.1.30/linux/drivers/sound/.blurb	Sun May  1 12:12:22 1994
+++ linux/drivers/sound/.blurb	Fri Apr 15 13:36:01 1994
@@ -1,6 +1,27 @@
-NOTE!	This driver version is not compatible with the version 1.0c.
-	This means you have to use the latest version of the snd-util
-	package (2.0). The earlier ones (from 1.0) will not work. If you have
-	other programs using ioctl calls of the driver, they must be
-	recompiled. Most of them will not work without some source
-	modifications.
+NOTE!
+
+	This is an ALPHA TEST VERSION (pre 3.0). The latest
+	released version of this driver is now part of
+	Linux kernel distribution. For other operating systems
+	use the snd-driv-2.5.tar.gz package.
+
+	This particular version contains lots of new features
+	BUT THERE ARE NO APPLICATIONS WHICH USE THEM. So there
+	is no need to install this version as long as you are
+	not developing the driver or applications which use it.
+	All new features are in the /dev/sequencer and /dev/midi
+	parts of the driver.
+
+	
+	This version is little bit incomplete. Some features have
+	not been implemented for each soundcards yet. All features
+	of v2.4 should work OK.
+
+CAUTION!
+	This version of driver works with applications written and
+	compiled for v2.*. The problem is that APPLICATIONS COMPILED
+	WITH soundcard.h OF THIS VERSION WILL NOT WORK WITH OLDER DRIVER.
+	Be carefull when distributing applications compiled with this
+	version (just the apps using /dev/sequencer are incompatible).
+
+Hannu
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v1.1.30/linux/drivers/sound/CHANGELOG	Sun May  1 12:12:23 1994
+++ linux/drivers/sound/CHANGELOG	Mon Jul 18 09:50:55 1994
@@ -1,8 +1,40 @@
-Changelog for version 2.5a
---------------------------
+Changelog for version 2.90
+------------------------------------
 
-Since 2.5
-- Minor fix to read from /dev/sequencer
+This is an intermediate release (v3.0 prototype with some experimental
+features disabled). See experimental.txt for more info.
+
+Since pre-3.0-949712
+- GUS MAX support
+- Partially working MSS/WSS support (could work with some cards).
+- Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs
+  (GUS MAX, GUS16, WSS etc). Hardware ADPCM is possible with GUS16 and
+  GUS MAX, but it doesn't work yet.
+Since pre-3.0-940426
+- AD1848/CS4248/CS4231 codec support (MSS, GUS MAX, Aztec, Orchid etc).
+This codec chip is used in various soundcards. This version is developed
+for the 16 bit daughtercard of GUS. It should work with other cards also
+if the following requirements are met:
+	- The I/O, IRQ and DMA settings are jumper selectable or
+	the card is initialized by booting DOS before booting Linux (etc.).
+	- You add the IO, IRQ and DMA settings manually to the local.h.
+	  (Just define GUS16_BASE, GUS16_IRQ and GUS16_DMA). Note that
+	the base address bust be the base address of the codec chip not the
+	card itself. For the GUS16 these are the same but most MSS compatible
+	cards have the codec located at card_base+4.
+- Some minor changes
+
+Since 2.5 (******* MAJOR REWRITE ***********)
+
+This version is based on v2.3. I have tried to maintain two versions
+together so that this one should have the same features than v2.5.
+Something may still be missing. If you notice such things, please let me
+know.
+
+The Readme.v30 contains more details.
+
+- /dev/midi## devices.
+- /dev/sequencer2
 
 Since 2.5-beta2
 - Some fine tuning to the GUS v3.7 mixer code.
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v1.1.30/linux/drivers/sound/Makefile	Sun May  1 12:12:23 1994
+++ linux/drivers/sound/Makefile	Mon Jul 18 09:50:55 1994
@@ -5,7 +5,7 @@
 #
 #
 
-VERSION		= 2.5a
+VERSION		= 2.90
 TARGET_OS	= linux
 
 .c.s:
@@ -19,7 +19,8 @@
 	 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 sound_switch.o ics2101.o
+	 sb16_midi.o sound_switch.o midi_synth.o uart6850.o sound_timer.o \
+	 sys_timer.o ics2101.o ad1848.o pss.o
 
 all:	local.h sound.a
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v1.1.30/linux/drivers/sound/Readme	Sun May  1 12:12:23 1994
+++ linux/drivers/sound/Readme	Mon Jul 18 09:50:55 1994
@@ -1,152 +1,45 @@
-Release notes for the Linux Sound Driver 2.5a
----------------------------------------------
-This directory contains just the Linux version. The portable version
-(SCO/ISC, FreeBSD/NetBSD and SVR4.2) is available from sunsite.unc.edu:
-pub/Linux/kernel/sound.
-
-This is mainly a bug fix release. There are couple of new things such as
-linear volume mode for GUS and MIDI recording for SB 2.0 and SB Pro.
-Also this version supports the mixer of GUS v3.7. (Support for GUS MAX and
-the 16-bit daughtercard is coming sooner or later).
-
-NOTE!	The sound driver is a part of the Linux kernel distribution also.
-	Check that your kernel doesn't have more recent version than this
-	when installing a separately distributed sound driver. The
-	version number of this driver is defined in the makefile.
-
-This version contains a driver for the SB16 also.
-The SB16 driver requires separate DMA channels for the 8 and 16 bit
-modes. There should be a way to share the 8 bit DMA channels between
-these modes but this feature is not supported yet.
-The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de).
-
-The SB16 driver has also the Midi input capability even at the same
-time with the /dev/dsp. Also the WaveBlaster daughter board is supported.
-No support for the ASP chip yet (the ASP chip can be installed but it's
-not used by the driver).
+VoxWare v2.90 release notes
+--------------------------
 
+
+		This version includes some hidden features which
+		are described in the file experimental.txt
+		Some of these features are not enabled by default. Look at
+		experimental.txt for more info.
+
+		I just decided to release this version with some
+		incompletely implemented features disabled since
+		there are some new features required by a popular 
+		application. In addition there is also support
+		for the GUS MAX and the 16 bit sampling option of GUS.
+		Also the Windows Sound System stuff is there but may not
+		work yet (may work with some WSS compatible cards).
+
+********* IMPORTANT *****************************************
+Linux 1.0 or later is required to by this driver version.
+
+Don't distribute binaries which use /dev/sequencer and are
+compiled with the soundcard.h of this version. They will
+not work with version 2.x of the driver.
+*************************************************************
+
+
 You will need the snd-util-2.5.tar.gz and snd-data-0.1.tar.Z
 packages to use this driver. They should be in the same
 ftp site or BBS from where you got this driver. For
 example at nic.funet.fi:pub/OS/Linux/*.
 
 If you are looking for the installation instructions, please
-look at $OS/Readme.
+look at linux/Readme.
 
-This version supports the following soundcards:
-GUS, SoundBlaster, SB Pro, SB16, Pro Audio Spectrum 16 and AdLib.
-In addition there is rather limited support for MPU-401.
-(and compatible) midi cards. Also the OPL-3 synthesizer
-Most of the features of the /dev/sequencer device file are
-available just for GUS owners. 
-
 Compatibility with the earlier versions
 ---------------------------------------
 
-In this version the ultrasound.h no longer includes the sys/soundcard.h
-You have to change the gmod.c of the snd-util-2.0 package and to add an
-include for it.
-
-IMPORTANT!!!!!!!!!!!!!!!!!!!!!!
-
-This version is not binary or source compatible with the version 1.0c.
-
-The ioctl() interface has changed completely since version 1.0c. All
-programs using this driver must be at least recompiled. 
-The snd-util-2.0 package contains some utilities for this version.
-
-The version 1.0c and earlier used a 'nonportable' ioctl calling scheme
-where the input argument was passed by value and the output value was
-returned as the functional return. For example setting the speed of
-/dev/dsp were done as the following:
-
-	int actual_speed;
-	actual_speed = ioctl(fd, SOUND_PCM_WRITE_RATE, 44100);
-
-After version 1.99.0 this must be done as the following:
-
-	int actual_speed = 44100;
-	ioctl(fd, SOUND_PCM_WRITE_RATE, &actual_speed);
-
-If you have an application written for the version 1.0, you should search
-for the strings SNDCTL_ and SOUND_ and to check the parameters. 
-The following ioctl calls have changed:
-
-	SNDCTL_SEQ_GETOUTCOUNT
-	SNDCTL_SEQ_GETINCOUNT
-	SNDCTL_SEQ_TESTMIDI
-	SNDCTL_DSP_SPEED
-	SNDCTL_DSP_STEREO
-	SNDCTL_DSP_GETBLKSIZE
-	SNDCTL_DSP_SAMPLESIZE
-	SOUND_PCM_WRITE_CHANNELS
-	SOUND_PCM_WRITE_FILTER
-	SOUND_PCM_READ_RATE
-	SOUND_PCM_READ_CHANNELS
-	SOUND_PCM_READ_BITS
-	SOUND_PCM_READ_FILTER
-	SOUND_PCM_WRITE_BITS
-	SOUND_PCM_WRITE_RATE
-	SOUND_MIXER_READ_*	(several ones)
-	SOUND_MIXER_WRITE_*	(several ones)
-
-Since the this version will support more than one synthesizer devices
-at the same time, the ioctl(SNDCTL_FM_LOAD_INSTR) is obsolete. In addition
-there is some new fields which must be initialized. Look at the sbiset.c in
-the snd-util-2.0 package for further info.
-
-Known bugs/limitations
-----------------------
-
-- High speed recording of long audio samples (>20 second) to disk
-  is not possible. Everything works until next sync() which delays the
-  recording process too much. A delay longer than 0.1 to 0.3 seconds is
-  too much.
-- The SB16 driver sometimes swaps the left and right channels together.
-- It's not possible to open /dev/dsp (or /dev/audio) while the 
-  /dev/sequencer is open for output and GUS is the only soundcard
-  installed. It's possible if /dev/dsp is opened before /dev/sequencer
-  but at this time the GUS is not available for access via /dev/sequencer.
-  This is a limitation of the driver.
-- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed.
-  It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI
-  adapter.
-- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting
-  ^C and playing again should solve this problem. This is propably caused by
-  incompatibilities between GUS and certain VLB motherboards (like mine). 
-  Try to avoid
-  switching between VTs while patches are being loaded to the GUS.
-  This problem disappears completely if you define GUS_PATCH_NO_DMA in the
-  local.h (after make config in linux). The drawback is that patch loading
-  without DMA takes several times longer than with DMA.
-- There is a skeleton of the patch manager support. It don't work in
-  this version. 
-
-
-Future development
-------------------
-
-- Since this driver is no longer just the Linux Sound Driver, it's time
-  to give it a new name. I have planned to use name VoxWare.
-- I'm writing a Hacker's guide to the VoxWare sound driver. Should
-  be ready within this(/next) year (alpha version).
-- Completion of the ISC, SCO and BSD ports. Port to SVR4.2.
-- I'm interested to implement/include support for new soundcards and 
-  operating systems. 
-
-  Hint for the soundcard and OS manufacturers:
-  I'm collecting soundcards (high end ones) and SDKs for them. In
-  addition I'm collecting PC operating systems. I will be happy if
-  somebody sends me such items. In addition such kind of donation
-  makes it easier to change the VoxWare driver to support your
-  soundcard or operating system. However, please contact me before
-  sending anything.
-
-I will propably release some fix versions within this and next year. At
-least when the non-Linux versions get ready. The next major release (3.0)
-will be quite complete rewrite and released after about a year (end of 94 or
-beginning of 95).
-
+This version is backward compatible with the version 2.X. All programs
+compiled with sys/soundcard.h of v2.X should work without problems.
+PROGRAMS COMPILED WITH THE sys/soundcard.h OF THIS VERSION WILL NOT
+WORK WITH v2.X DRIVER. BE CAREFULL WHEN DISTRIBUTING BINARIES COMPILED 
+FOR THIS VERSION.
 
 Contributors
 ------------
@@ -155,30 +48,32 @@
 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
-	Rob Hooft		Volume computation algorithm for the FM synth.
-	Mika Liljeberg		uLaw encoding and decoding routines
-	Greg Lee		Volume computation algorithm for the GUS and
-				lot's of valuable suggestions.
-	Andy Warner		Initial ISC port
-	Jim Lowe		Initial FreeBSD port
+	Craig Metz	1/2 of the PAS16 Mixer and PCM support
+	Rob Hooft	Volume computation algorithm for the FM synth.
+	Mika Liljeberg	uLaw encoding and decoding routines
+	Greg Lee	Volume computation algorithm for the GUS and
+			lot's of valuable suggestions.
+	Andy Warner	ISC port
+	Jim Lowe	FreeBSD port
 	Anders Baekgaard 	Bughunting and valuable suggestions.
-	Joerg Schubert		SB16 DSP support.
-	Andrew Robinson 	Improvements to the GUS driver
-	Megens SA		MIDI recording for SB and SB Pro.
+	Joerg Schubert	SB16 DSP support.
+	Andrew Robinson Improvements to the GUS driver
+	Megens SA	MIDI recording for SB and SB Pro.
+	Mikael Nordqvist  Linear volume support for GUS.
 	Mikael Nordqvist  	Linear volume support for GUS.
 	Ian Hartas		SVR4.2 port
 	Markus Aroharju	and
 	Risto Kankkunen		Major contributions to the mixer support
 				of GUS v3.7.
-	Hunyue Yau		Sound Galaxy NX Pro mixer support.
+	Marc Hoffman	PSS support.
 
 Regards,
 
 Hannu Savolainen
-hannu@voxware.pp.fi, Hannu.Savolainen@Helsinki.fi
+hannu@voxware.pp.fi
 
 Snail mail:	Hannu Savolainen
 		Pallaksentie 4 A 2
 		00970 Helsinki
 		Finland
+FAX:		+358 0 395 1968 (usually not connected)
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux
--- v1.1.30/linux/drivers/sound/Readme.linux	Sun May  1 12:12:23 1994
+++ linux/drivers/sound/Readme.linux	Mon Jul 18 09:50:55 1994
@@ -1,35 +1,25 @@
-Sound Driver version 2.5 for Linux
-----------------------------------
-
-NOTE!	The sound driver is now a part of the Linux kernel distribution.
-	Check that your kernel doesn't have more recent version than this
-	when installing a separately distributed sound driver. The
-	version number of this driver is defined in the makefile.
-
 Installation
 ------------
 
-- Since this driver is a part of the Linux kernel distribution, no
-  special steps are required to build the driver itself.
+- Since you are reading this, you have already installed the files so
+  let's skip this step. To be serious, the sound driver belongs
+  to linux/drivers/sound. 
 
-- In case you are installing a separately distributed sound driver,
-  you have to do some additional steps.
-  - Remove all files from the linux/drivers/sound. Old files could
-    sometimes cause trouble.
-  - cd linux/drivers.
-  - gunzip -c snd-driv-X.Y.tar.gz|tar xvf -
-  - cd ./sound
-  - cp soundcard.h ultrasound.h /usr/include/linux
+- To build the device files you need to run the enclosed shell scrip 
+  (see below).
 
-- To build the device files for this driver, you need to run the enclosed 
-  shell script (at the end of this file).
+- If you are installing a separately distributed version, copy the
+  soundcard.h to /usr/include/linux. It may contain some new stuff.
 
-- Create /usr/include/sys/soundcard.h whic contains just a line:
-#include <linux/soundcard.h>
+- Copy the sound/ultrasound.h  to /usr/include/sys
+  (Remove the old one from /usr/include/sys /usr/include/linux first).
 
-- Create /usr/include/sys/ultrasound.h whic contains just a line:
-#include <linux/ultrasound.h>
+- Ensure you have the following symlink:
+  ln -s /usr/include/linux/soundcard.h /usr/include/sys/soundcard.h
 
+- Configure and compile Linux as normally (remember to include the
+  sound support during "make config").
+
 Boot time configuration (using lilo)
 ------------------------------------
 
@@ -61,6 +51,8 @@
 					5=MPU-401 UART midi
 					6=SB16 (16 bit DMA number)
 					7=SB16 Midi (MPU-401 emulation)
+			(There are some new ones also but they are currently
+			not documented).
 
 These are the configuration templates for various soundcards:
 
@@ -174,43 +166,76 @@
 It runs without burning your CPU.
 
 Hannu Savolainen
-Hannu.Savolainen@Helsinki.fi
-(hannu@voxware.pp.fi (april 94 ->))
+hannu@voxware.pp.fi
 
 ----------------- cut here ------------------------------
 #!/bin/sh
 #
 #	soudinstall		
 #
-#		by Craig Metz - cmetz@thor.tjhsst.edu
 #
 # Create the devices
 #
-#	Mixer 		(14, 0)
+#	Mixer devices
 #
 if [ -e /dev/mixer ]; then 
 	rm -f /dev/mixer 
 fi
+ 
 mknod -m 666 /dev/mixer c 14 0
-
 if [ -e /dev/mixer1 ]; then 
 	rm -f /dev/mixer1 
 fi
 mknod -m 666 /dev/mixer1 c 14 16
-#
+
+
 #	Sequencer	(14, 1)
 #
 if [ -e /dev/sequencer ]; then
 	rm -f /dev/sequencer
 fi
 mknod -m 666 /dev/sequencer c 14 1
-#
-#	MIDI		(14, 2)	[ Not implemented ]
+
+if [ -e /dev/patmgr0 ]; then
+	rm -f /dev/patmgr0
+fi
+mknod -m 666 /dev/patmgr0 c 14 17
+if [ -e /dev/patmgr1 ]; then
+	rm -f /dev/patmgr1
+fi
+mknod -m 666 /dev/patmgr1 c 14 33
+
+###	#	Sequencer2	(14, 8)
+###	#
+###	if [ -e /dev/sequencer2 ]; then
+###		rm -f /dev/sequencer2
+###	fi
+###	mknod -m 666 /dev/sequencer2 c 14 8
+
+#	Midi devices
 #
 if [ -e /dev/midi ]; then
-	rm -f /dev/midi
+	rm -f /dev/midi		# Old name. Don't use it
 fi
-mknod -m 666 /dev/midi c 14 2
+###	if [ -e /dev/midi00 ]; then
+###		rm -f /dev/midi00
+###	fi
+###	mknod -m 666 /dev/midi00 c 14 2
+###	
+###	if [ -e /dev/midi01 ]; then
+###		rm -f /dev/midi01
+###	fi
+###	mknod -m 666 /dev/midi01 c 14 18
+###	
+###	if [ -e /dev/midi02 ]; then
+###		rm -f /dev/midi02
+###	fi
+###	mknod -m 666 /dev/midi02 c 14 34
+###	
+###	if [ -e /dev/midi03 ]; then
+###		rm -f /dev/midi03
+###	fi
+###	mknod -m 666 /dev/midi03 c 14 50
 #
 #	DSP		(14, 3)
 #
@@ -219,14 +244,14 @@
 fi
 mknod -m 666 /dev/dsp c 14 3
 #
-#	SPARC audio	(14, 4)	[ Not fully implemented ]
+#	SPARC compatible /dev/audio	(14, 4)	
 #
 if [ -e /dev/audio ]; then
 	rm -f /dev/audio
 fi
 mknod -m 666 /dev/audio c 14 4
 #
-#	DSP2		(14, 19) /dev/dsp for the second soundcard.
+#	DSP1		(14, 19) /dev/dsp for the second soundcard.
 #				Also the SB emulation part of the
 #				PAS16 card.
 #
@@ -235,7 +260,7 @@
 fi
 mknod -m 666 /dev/dsp1 c 14 19
 #
-#	SPARC audio1	(14, 20) [ Not fully implemented ]
+#	SPARC audio1	(14, 20) 
 #				/dev/audio for the second soundcard.
 #				Also the SB emulation part of the
 #				PAS16 card.
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/Readme.v30 linux/drivers/sound/Readme.v30
--- v1.1.30/linux/drivers/sound/Readme.v30	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/Readme.v30	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,154 @@
+VoxWare v3.0
+------------
+
+This is a PROTOTYPE of the VoxWare v3.0 to be relased late 94.
+
+All features of v2.5 should work as earlier. There could be some
+omissions but they are unintentional. I started this version thread
+after v2.3 so all features implemented before it are there.
+
+Even this is a prototype, there should not be any fatal bugs. The
+prototype just means that I don't have implemented all features
+completely. Mainly in the /dev/sequener2 driver.
+For example recording from /dev/sequencer2 won't work
+with other cards than a full features MPU-401 or clones. As well the
+way how the MIDI controllers are handled will change.
+
+IMPORTANT!!!!!!!!!!!!!!!!!
+
+Don't distribute any binaries compiled with the soundcard.h of this version. 
+They will not work together with older drivers.
+
+New features
+============
+
+There are now two new device interfaces. The /dev/midi## is a raw
+tty like interface to MIDI ports. There is a device file for each MIDI
+port on your system. They are named (/dev/midi00 to /dev/midiNN).
+The second addition is the /dev/sequencer2 which is higher level interface 
+than the old /dev/sequencer. It's intended for writing device independent
+applications like sequencers.
+
+/dev/midi##
+-----------
+
+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. 
+The /dev/midi00 is connected to the first one, /dev/midi01 to the second etc.
+
+These devices work like tty devices in raw mode. Everything written to them is
+sent out to the MIDI port. There is currently an extra delay of at most 
+1/100th of sec but it will be removed later.
+
+The reading algorithm is little bit more complicated. There are two different
+cases:
+
+1)	There is at least one byte in the input buffer.
+
+The read returns as many bytes as it can without waiting for more bytes.
+For example when a process reads 100 bytes and there are 10 bytes in the 
+buffer, the read returns just 10 bytes.
+
+2)	The input buffer is empty when the process calls read.
+
+The read waits for the first byte and then continues as in case 1. By
+default it waits infinitely but there is an ioctl for setting a timeout
+for this. The ioctl(fd, SNDCTL_MIDI_PRETIME, &time) changes the timeout.
+The time is given in 1/10th of seconds (10 means one second).
+
+Other ioctl calls:
+
+ioctl(fd, SNDCTL_MIDI_MPUMODE, &mode) is available for full MPU-401
+compatible devices such as MPU-IPC-T, MQ PC Midi Card or MQX-32.
+It's not available for the so called MPU UART ports of some soundcards
+(PAS16, SB16 etc). By default the MIDI port is in UART mode after open. 
+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
+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
+is put to the coprocessor mode using ioctl(SNDCTL_MIDI_MPUMODE). It's used to
+send commands to a MPU-401 compatible MIDI cards. Please refer to the
+MPU-401 Technical Reference Manual (or Music Quest Technical Reference
+Manual) for descriptions of the commands.
+
+The argument of SNDCTL_MIDI_MPUCOMMAND is of type mpu_command_rec. It
+has the following fields:
+
+typedef struct {
+		unsigned char cmd;
+
+		char nr_args, nr_returns;
+		unsigned char data[30];
+	} mpu_command_rec;
+
+where:
+	cmd		Contains the command number.
+	nr_args		Number of arguments of the command.
+			MUST BE INITIALIZED BEFORE CALL
+	nr_returns	Number of bytes returned by the command.
+			MUST BE INITIALIZED BEFORE CALL
+	data		Buffer for the command arguments and returned
+			data.
+
+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
+datails.
+
+
+
+/dev/sequencer2 (if you find a better name, please let me know).
+---------------
+
+This device file works much like the /dev/sequencer which has been present
+since the beginning. The main differences are the following:
+
+- /dev/sequencer makes the MIDI ports to look like the synth devices. In fact
+the result is somewhere between the MIDI specification and the synth devices of
+/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 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
+drawback is that the new interface doesn't permit so low level access to the
+device as the /dev/sequencer does. An application developer must choose between
+these two interfaces. I think the old /dev/sequencer is better for applications
+like module players while the new one is better for making generic sequencer
+programs.
+
+- There are no separate MIDI devices with the /dev/sequencer2. The
+ioctl(SNDCTL_SEQ_NRMIDIS) returns always zero. Instead the MIDI ports are
+shown as synth devices. ioctl(SNDCTL_SEQ_NRSYNTHS) on /dev/sequencer2 will 
+return sum of internal synthesizers (GUS, OPL3) and MIDI ports in the systems.
+
+- 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 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 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
+first event. Otherwise the timer is not started and the application waits
+infinitely.
+
+
+There are several new features but I don't document them here. There are
+some info in the soundcard.h (near the end). I have also included some
+sample code in the directory v30. Full documentation will
+appear in the Hacker's Guide later.
+
+Don't hesitate to contact me in case you have questions or comments.
+
+Hannu Savolainen
+hannu@voxware.pp.fi
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v1.1.30/linux/drivers/sound/ad1848.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/ad1848.c	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,953 @@
+/*
+ * sound/ad1848.c
+ *
+ * The low level driver for the AD1848/CS4248 codec chip which
+ * is used for example in the MS Sound System.
+ *
+ * The CS4231 which is used in the GUS MAX and some other cards is
+ * upwards compatible with AD1848 and this driver is able to drive it.
+ *
+ * Copyright by Hannu Savolainen 1994
+ *
+ * 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.
+ *
+ */
+
+#define DEB(x)
+#define DEB1(x)
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)
+
+#define IMODE_NONE		0
+#define IMODE_OUTPUT		1
+#define IMODE_INPUT		2
+#define IMODE_INIT		3
+#define IMODE_MIDI		4
+
+typedef struct
+{
+  int             base;
+  int             irq;
+  int             dma_capture, dma_playback;
+  unsigned char   MCE_bit;
+
+  int             speed;
+  unsigned char   speed_bits;
+  int             channels;
+  int             audio_format;
+  unsigned char   format_bits;
+
+  int             xfer_count;
+  int             irq_mode;
+  int             intr_active;
+  int             opened;
+  char           *chip_name;
+  int             mode;
+}
+
+ad1848_info;
+
+static int      nr_ad1848_devs = 0;
+static char     irq2dev[16] =
+{-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1};
+
+static int      ad_format_mask[2 /*devc->mode*/ ] =
+{
+  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
+};
+
+static ad1848_info dev_info[MAX_AUDIO_DEV];
+
+#define io_Index_Addr(d)	((d)->base)
+#define io_Indexed_Data(d)	((d)->base+1)
+#define io_Status(d)		((d)->base+2)
+#define io_Polled_IO(d)		((d)->base+3)
+
+static int      ad1848_open (int dev, int mode);
+static void     ad1848_close (int dev);
+static int      ad1848_ioctl (int dev, unsigned int cmd, unsigned int 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_IO (int dev, int bsize, int bcount);
+static void     ad1848_reset (int dev);
+static void     ad1848_halt (int dev);
+void            ad1848_interrupt (int dev);
+
+static int
+ad_read (ad1848_info * devc, int reg)
+{
+  unsigned long   flags;
+  int             x;
+
+  DISABLE_INTR (flags);
+  OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
+  x = INB (io_Indexed_Data (devc));
+  /*  printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
+  RESTORE_INTR (flags);
+
+  return x;
+}
+
+static void
+ad_write (ad1848_info * devc, int reg, int data)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
+  OUTB ((unsigned char) (data & 0xff), io_Indexed_Data (devc));
+  /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
+  RESTORE_INTR (flags);
+}
+
+static void
+ad_set_MCE (ad1848_info * devc, int state)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  if (state)
+    devc->MCE_bit = 0x40;
+  else
+    devc->MCE_bit = 0x00;
+  OUTB (devc->MCE_bit, io_Index_Addr (devc));
+  RESTORE_INTR (flags);
+}
+
+static void
+wait_for_calibration (ad1848_info * devc)
+{
+  int             timeout = 0;
+
+  /*
+ * Wait until the auto calibration process has finished.
+ *
+ * 1)	Wait until the chip becomes ready (reads don't return 0x80).
+ * 2)	Wait until the ACI bit of I11 gets on and then off.
+ */
+
+  timeout = 100000;
+  while (timeout > 0 && INB (devc->base) == 0x80)
+    timeout--;
+  if (INB (devc->base) == 0x80)
+    printk ("ad1848: Auto calibration timed out(1).\n");
+
+  timeout = 100000;
+  while (timeout > 0 && !(ad_read (devc, 11) & 0x20))
+    timeout--;
+  if (!(ad_read (devc, 11) & 0x20))
+    printk ("ad1848: Auto calibration timed out(2).\n");
+
+  timeout = 100000;
+  while (timeout > 0 && ad_read (devc, 11) & 0x20)
+    timeout--;
+  if (ad_read (devc, 11) & 0x20)
+    printk ("ad1848: Auto calibration timed out(3).\n");
+}
+
+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
+  }};
+
+static int
+ad1848_open (int dev, int mode)
+{
+  int             err;
+  ad1848_info    *devc = NULL;
+  unsigned long   flags;
+
+  DEB (printk ("ad1848_open(int mode = %X)\n", mode));
+
+  if (dev < 0 || dev >= num_audiodevs)
+    return RET_ERROR (ENXIO);
+
+  devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  DISABLE_INTR (flags);
+  if (devc->opened)
+    {
+      RESTORE_INTR (flags);
+      printk ("ad1848: Already opened\n");
+      return RET_ERROR (EBUSY);
+    }
+
+  if (devc->irq)		/* Not managed by another driver */
+    if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt)) < 0)
+      {
+	printk ("ad1848: IRQ in use\n");
+	RESTORE_INTR (flags);
+	return err;
+      }
+
+  if (DMAbuf_open_dma (dev) < 0)
+    {
+      RESTORE_INTR (flags);
+      printk ("ad1848: DMA in use\n");
+      return RET_ERROR (EBUSY);
+    }
+
+  devc->intr_active = 0;
+  devc->opened = 1;
+  RESTORE_INTR (flags);
+
+  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"));
+
+  DISABLE_INTR (flags);
+
+  devc->intr_active = 0;
+  if (devc->irq)		/* Not managed by another driver */
+    snd_release_irq (devc->irq);
+  ad1848_reset (dev);
+  DMAbuf_close_dma (dev);
+  devc->opened = 0;
+
+  RESTORE_INTR (flags);
+}
+
+static int
+set_speed (ad1848_info * devc, int arg)
+{
+  /*
+ * 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):
+ *
+ * The available speeds are in the following table. Keep the speeds in
+ * the increasing order.
+ */
+  typedef struct
+    {
+      int             speed;
+      unsigned char   bits;
+    }
+  speed_struct;
+
+  static speed_struct speed_table[] =
+  {
+    {5510, (0 << 1) | 1},
+    {5510, (0 << 1) | 1},
+    {6620, (7 << 1) | 1},
+    {8000, (0 << 1) | 0},
+    {9600, (7 << 1) | 0},
+    {11025, (1 << 1) | 1},
+    {16000, (1 << 1) | 0},
+    {18900, (2 << 1) | 1},
+    {22050, (3 << 1) | 1},
+    {27420, (2 << 1) | 0},
+    {32000, (3 << 1) | 0},
+    {33075, (6 << 1) | 1},
+    {37800, (4 << 1) | 1},
+    {44100, (5 << 1) | 1},
+    {48000, (6 << 1) | 0}
+  };
+
+  int             i, n, selected = -1;
+
+  n = sizeof (speed_table) / sizeof (speed_struct);
+
+  if (arg < speed_table[0].speed)
+    selected = 0;
+  if (arg > speed_table[n - 1].speed)
+    selected = n - 1;
+
+  for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
+    if (speed_table[i].speed == arg)
+      selected = i;
+    else if (speed_table[i].speed > arg)
+      {
+	int             diff1, diff2;
+
+	diff1 = arg - speed_table[i - 1].speed;
+	diff2 = speed_table[i].speed - arg;
+
+	if (diff1 < diff2)
+	  selected = i - 1;
+	else
+	  selected = i;
+      }
+
+  if (selected == -1)
+    {
+      printk ("ad1848: Can't find speed???\n");
+      selected = 3;
+    }
+
+  devc->speed = speed_table[selected].speed;
+  devc->speed_bits = speed_table[selected].bits;
+  return devc->speed;
+}
+
+static int
+set_channels (ad1848_info * devc, int arg)
+{
+  if (arg != 1 && arg != 2)
+    return devc->channels;
+
+  devc->channels = arg;
+  return arg;
+}
+
+static int
+set_format (ad1848_info * devc, int arg)
+{
+
+  static struct format_tbl
+    {
+      int             format;
+      unsigned char   bits;
+    }
+  format2bits     [] =
+  {
+    {
+      0, 0
+    }
+    ,
+    {
+      AFMT_MU_LAW, 1
+    }
+    ,
+    {
+      AFMT_A_LAW, 3
+    }
+    ,
+    {
+      AFMT_IMA_ADPCM, 5
+    }
+    ,
+    {
+      AFMT_U8, 0
+    }
+    ,
+    {
+      AFMT_S16_LE, 2
+    }
+    ,
+    {
+      AFMT_S16_BE, 6
+    }
+    ,
+    {
+      AFMT_S8, 0
+    }
+    ,
+    {
+      AFMT_U16_LE, 0
+    }
+    ,
+    {
+      AFMT_U16_BE, 0
+    }
+  };
+  int             i, n = sizeof (format2bits) / sizeof (struct format_tbl);
+
+  if (!(arg & ad_format_mask[devc->mode]))
+    arg = AFMT_U8;
+
+  devc->audio_format = arg;
+
+  for (i = 0; i < n; i++)
+    if (format2bits[i].format == arg)
+      {
+	if ((devc->format_bits = format2bits[i].bits) == 0)
+	  return devc->audio_format = AFMT_U8;	/* Was not supported */
+
+	return arg;
+      }
+
+  /* Still hanging here. Something must be terribly wrong */
+  devc->format_bits = 0;
+  return devc->audio_format = AFMT_U8;
+}
+
+static int
+ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  switch (cmd)
+    {
+    case SOUND_PCM_WRITE_RATE:
+      if (local)
+	return set_speed (devc, arg);
+      return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_RATE:
+      if (local)
+	return devc->speed;
+      return IOCTL_OUT (arg, devc->speed);
+
+    case SNDCTL_DSP_STEREO:
+      if (local)
+	return set_channels (devc, arg + 1) - 1;
+      return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1);
+
+    case SOUND_PCM_WRITE_CHANNELS:
+      if (local)
+	return set_channels (devc, arg);
+      return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_CHANNELS:
+      if (local)
+	return devc->channels;
+      return IOCTL_OUT (arg, devc->channels);
+
+    case SNDCTL_DSP_SAMPLESIZE:
+      if (local)
+	return set_format (devc, arg);
+      return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_BITS:
+      if (local)
+	return devc->audio_format;
+      return IOCTL_OUT (arg, devc->audio_format);
+
+    default:;
+    }
+  return RET_ERROR (EINVAL);
+}
+
+static void
+ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+  unsigned long   flags, cnt;
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  cnt = count;
+
+  if (devc->audio_format == AFMT_IMA_ADPCM)
+    {
+      cnt /= 4;
+    }
+  else
+    {
+      if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))	/* 16 bit data */
+	cnt >>= 1;
+    }
+  if (devc->channels > 1)
+    cnt >>= 1;
+  cnt--;
+
+  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
+      intrflag &&
+      cnt == devc->xfer_count)
+    {
+      devc->irq_mode = IMODE_OUTPUT;
+      devc->intr_active = 1;
+      return;			/*
+				 * Auto DMA mode on. No need to react
+				 */
+    }
+  DISABLE_INTR (flags);
+
+  if (dma_restart)
+    {
+      ad1848_halt (dev);
+      DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+    }
+
+  ad_set_MCE (devc, 1);
+
+  ad_write (devc, 15, (unsigned char) (cnt & 0xff));
+  ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
+
+
+  ad_write (devc, 9, 0x0d);	/*
+				 * Playback enable, single DMA channel mode,
+				 * auto calibration on.
+				 */
+
+  ad_set_MCE (devc, 0);		/*
+				 * Starts the calibration process and
+				 * enters playback mode after it.
+				 */
+  wait_for_calibration (devc);
+
+  devc->xfer_count = cnt;
+  devc->irq_mode = IMODE_OUTPUT;
+  devc->intr_active = 1;
+  RESTORE_INTR (flags);
+}
+
+static void
+ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+  unsigned long   flags, cnt;
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  /* int             count_reg = (devc->mode == 1) ? 14 : 30; */
+
+  cnt = count;
+  if (devc->audio_format == AFMT_IMA_ADPCM)
+    {
+      cnt /= 4;
+    }
+  else
+    {
+      if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))	/* 16 bit data */
+	cnt >>= 1;
+    }
+  if (devc->channels > 1)
+    cnt >>= 1;
+  cnt--;
+
+  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
+      intrflag &&
+      cnt == devc->xfer_count)
+    {
+      devc->irq_mode = IMODE_INPUT;
+      devc->intr_active = 1;
+      return;			/*
+				 * Auto DMA mode on. No need to react
+				 */
+    }
+  DISABLE_INTR (flags);
+
+  if (dma_restart)
+    {
+      ad1848_halt (dev);
+      DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+    }
+
+  ad_set_MCE (devc, 1);
+#if 0
+  ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff));
+  ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff));
+#else
+  ad_write (devc, 15, (unsigned char) (cnt & 0xff));
+  ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
+  if (devc->mode == 2)
+    {
+      ad_write (devc, 31, (unsigned char) (cnt & 0xff));
+      ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff));
+    }
+#endif
+
+  ad_write (devc, 9, 0x0e);	/*
+				 * Capture enable, single DMA channel mode,
+				 * auto calibration on.
+				 */
+
+  ad_set_MCE (devc, 0);		/*
+				 * Starts the calibration process and
+				 * enters playback mode after it.
+				 */
+  wait_for_calibration (devc);
+
+  devc->xfer_count = cnt;
+  devc->irq_mode = IMODE_INPUT;
+  devc->intr_active = 1;
+  RESTORE_INTR (flags);
+}
+
+static int
+ad1848_prepare_for_IO (int dev, int bsize, int bcount)
+{
+  int             timeout;
+  unsigned char   fs;
+  unsigned long   flags;
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  DISABLE_INTR (flags);
+  ad_set_MCE (devc, 1);		/* Enables changes to the format select reg */
+  fs = devc->speed_bits | (devc->format_bits << 5);
+
+  if (devc->channels > 1)
+    fs |= 0x10;
+
+  ad_write (devc, 8, fs);
+  /*
+   * Write to I8 starts resyncronization. Wait until it completes.
+   */
+  timeout = 10000;
+  while (timeout > 0 && INB (devc->base) == 0x80)
+    timeout--;
+
+  ad_set_MCE (devc, 0);		/*
+				 * Starts the calibration process and
+				 * enters playback mode after it.
+				 */
+  wait_for_calibration (devc);
+  RESTORE_INTR (flags);
+
+  /*
+ * If mode == 2 (CS4231), set I28 also. It's the capture format register.
+ */
+  if (devc->mode == 2)
+    {
+      ad_set_MCE (devc, 1);
+      ad_write (devc, 28, fs);
+
+      /*
+   * Write to I28 starts resyncronization. Wait until it completes.
+   */
+      timeout = 10000;
+      while (timeout > 0 && INB (devc->base) == 0x80)
+	timeout--;
+
+      ad_set_MCE (devc, 0);	/*
+				 * Starts the calibration process and
+				 * enters playback mode after it.
+				 */
+      wait_for_calibration (devc);
+      RESTORE_INTR (flags);
+    }
+  devc->xfer_count = 0;
+  return 0;
+}
+
+static void
+ad1848_reset (int dev)
+{
+  ad1848_halt (dev);
+}
+
+static void
+ad1848_halt (int dev)
+{
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  ad_write (devc, 9, 0);	/* Clear the PEN and CEN bits (among others) */
+  OUTB (0, io_Status (devc));	/* Clear interrupt status */
+}
+
+int
+ad1848_detect (int io_base)
+{
+
+#define DDB(x)	x
+
+  unsigned char   tmp;
+  int             i;
+  ad1848_info    *devc = &dev_info[nr_ad1848_devs];
+  unsigned char   tmp1 = 0xff, tmp2 = 0xff;
+
+  if (nr_ad1848_devs >= MAX_AUDIO_DEV)
+    return 0;
+
+  devc->base = io_base;
+  devc->MCE_bit = 0x40;
+  devc->irq = 0;
+  devc->dma_capture = 0;
+  devc->dma_playback = 0;
+  devc->opened = 0;
+  devc->chip_name = "AD1848";
+  devc->mode = 1;		/* MODE1 = original AD1848 */
+
+  /*
+ * 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 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.
+ */
+
+  if ((INB (devc->base) & 0x80) != 0x00)	/* Not a AD1884 */
+    {
+      DDB (printk ("ad_detect_A\n"));
+      return 0;
+    }
+
+  /*
+ * Test if it's possible to change contents of the indirect registers.
+ * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
+ * so try to avoid using it.
+*/
+
+  ad_write (devc, 0, 0xaa);
+  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 ("ad_detect_B (%x/%x)\n", tmp1, tmp2));
+      return 0;
+    }
+
+  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 ("ad_detect_C (%x/%x)\n", tmp1, tmp2));
+      return 0;
+    }
+
+  /*
+ * The indirect register I12 has some read only bits. Lets
+ * try to change them.
+ */
+
+  tmp = ad_read (devc, 12);
+  ad_write (devc, 12, (~tmp) & 0x0f);
+
+  if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f))
+    {
+      DDB (printk ("ad_detect_D (%x)\n", tmp1));
+      return 0;
+    }
+
+  /*
+ * NOTE! Last 4 bits of the reg I12 tell the chip revision.
+ *	 0x01=RevB and 0x0A=RevC.
+ */
+
+  /*
+ * The original AD1848/CS4248 has just 15 indirect registers. This means
+ * that I0 and I16 should return the same value (etc.).
+ * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
+ * with CS4231.
+ */
+
+  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 ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2));
+	return 0;
+      }
+
+  /*
+ * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
+ * The bit 0x80 is always 1 in CS4248 and CS4231.
+ */
+
+  ad_write (devc, 12, 0x40);	/* Set mode2, clear 0x80 */
+
+  tmp1 = ad_read (devc, 12);
+  if (tmp1 & 0x80)
+    devc->chip_name = "CS4248";
+
+  if ((tmp1 & 0xc0) == (0x80 | 0x40))
+    {
+      /*
+	 *	CS4231 detected - is it?
+	 *
+	 *	Verify that setting I0 doesn't change I16.
+	 */
+      ad_write (devc, 16, 0);	/* Set I16 to known value */
+
+      ad_write (devc, 0, 0x45);
+      if ((tmp1 = ad_read (devc, 16)) != 0x45)	/* No change -> CS4231? */
+	{
+
+	  ad_write (devc, 0, 0xaa);
+	  if ((tmp1 = ad_read (devc, 16)) == 0xaa)	/* Rotten bits? */
+	    {
+	      DDB (printk ("ad_detect_H(%x)\n", tmp1));
+	      return 0;
+	    }
+
+	  /*
+	 *	It's a CS4231 - So what!
+	 *	(Mode2 will be supported later)
+	 */
+	  devc->chip_name = "CS4231";
+	  devc->mode = 2;
+	}
+    }
+
+  return 1;
+}
+
+void
+ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture)
+{
+  /*
+ * NOTE! If irq < 0, there is another driver which has allocated the IRQ
+ *	 so that this driver doesn't need to allocate/deallocate it.
+ *	 The actually used IRQ is ABS(irq).
+ */
+
+  /*
+ * Initial values for the indirect registers of CS4248/AD1848.
+ */
+  static int      init_values[] =
+  {
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+    0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00
+  };
+  int             i, my_dev;
+  ad1848_info    *devc = &dev_info[nr_ad1848_devs];
+
+  if (!ad1848_detect (io_base))
+    return;
+
+  devc->irq = (irq > 0) ? irq : 0;
+  devc->dma_capture = dma_playback;
+  devc->dma_playback = dma_capture;
+  devc->opened = 0;
+
+  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]);
+
+  OUTB (0, io_Status (devc));	/* Clear pending interrupts */
+
+#ifndef SCO
+  sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
+	   "%s (%s)", name, devc->chip_name);
+#endif
+
+  if (irq > 0)
+    printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
+
+  if (num_audiodevs < MAX_AUDIO_DEV)
+    {
+      audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs];
+      if (irq > 0)
+	irq2dev[irq] = my_dev;
+      else if (irq < 0)
+	irq2dev[-irq] = my_dev;
+
+      audio_devs[my_dev]->dmachan = dma_playback;
+      audio_devs[my_dev]->buffcount = 1;
+      audio_devs[my_dev]->buffsize = DSP_BUFFSIZE * 2;
+      audio_devs[my_dev]->devc = devc;
+      audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
+      nr_ad1848_devs++;
+    }
+  else
+    printk ("AD1848: Too many PCM devices available\n");
+}
+
+void
+ad1848_interrupt (int irq)
+{
+  unsigned char   status;
+  ad1848_info    *devc;
+  int             dev;
+
+  if (irq < 0 || irq > 15)
+    return;			/* Bogus irq */
+  dev = irq2dev[irq];
+  if (dev < 0 || dev >= num_audiodevs)
+    return;			/* Bogus dev */
+
+  devc = (ad1848_info *) audio_devs[dev]->devc;
+  status = INB (io_Status (devc));
+
+  if (status & 0x01)
+    {
+      if (devc->opened && devc->irq_mode == IMODE_OUTPUT)
+	{
+	  DMAbuf_outputintr (dev, 1);
+	}
+
+      if (devc->opened && devc->irq_mode == IMODE_INPUT)
+	DMAbuf_inputintr (dev);
+    }
+
+  OUTB (0, io_Status (devc));	/* Clear interrupt status */
+}
+
+#endif
+/*
+ * Some extra code for the MS Sound System
+ */
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS)
+
+int
+probe_ms_sound (struct address_info *hw_config)
+{
+  int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+
+  if ((INB (hw_config->io_base + 3) & 0x04) == 0)
+    return 0;			/* WSS ID test failed */
+
+  if (hw_config->irq > 11)
+    return;
+
+  if (hw_config->dma > 3 || hw_config->dma == 2)
+    return;
+
+  return ad1848_detect (hw_config->io_base + 4);
+}
+
+long
+attach_ms_sound (long mem_start, struct address_info *hw_config)
+{
+  static unsigned char interrupt_bits[11] =
+  {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
+  char            bits;
+
+  int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+
+  if (!ad1848_detect (hw_config->io_base + 4))
+    return mem_start;
+
+  /*
+ * Set the IRQ and DMA addresses.
+ */
+
+  bits = interrupt_bits[hw_config->irq];
+  if (bits == -1)
+    return mem_start;
+
+  OUTB (bits | 0x40, config_port);	/* Verify IRQ (I guess) */
+  if ((INB (version_port) & 0x40) == 0)
+    printk ("[IRQ?]");
+
+  OUTB (bits | hw_config->dma, config_port);	/* Write IRQ+DMA setup */
+
+  ad1848_init ("MS Sound System", hw_config->io_base + 4,
+	       hw_config->irq,
+	       hw_config->dma,
+	       hw_config->dma);
+  return mem_start;
+}
+
+#endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v1.1.30/linux/drivers/sound/audio.c	Sun May  1 12:12:24 1994
+++ linux/drivers/sound/audio.c	Mon Jul 18 09:50:55 1994
@@ -37,19 +37,49 @@
 #define ON		1
 #define OFF		0
 
-static int      wr_buff_no[MAX_DSP_DEV];	/* != -1, if there is a
+static int      wr_buff_no[MAX_AUDIO_DEV];	/*
+						 * != -1, if there is
+						 * a incomplete output
+						 * block in the queue.
+						 */
+static int      wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
 
-						 * incomplete output block */
-static int      wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
+static int      audio_mode[MAX_AUDIO_DEV];
 
-static int      audio_mode[MAX_DSP_DEV];
-
 #define		AM_NONE		0
 #define		AM_WRITE	1
 #define 	AM_READ		2
 
-static char    *wr_dma_buf[MAX_DSP_DEV];
+static char    *wr_dma_buf[MAX_AUDIO_DEV];
+static int      audio_format[MAX_AUDIO_DEV];
+static int      local_conversion[MAX_AUDIO_DEV];
+
+static int
+set_format (int dev, int fmt)
+{
+  if (fmt != AFMT_QUERY)
+    {
+
+      local_conversion[dev] = 0;
+
+      if (!(audio_devs[dev]->format_mask & fmt))	/* Not supported */
+	if (fmt == AFMT_MU_LAW)
+	  {
+	    fmt = AFMT_U8;
+	    local_conversion[dev] = AFMT_MU_LAW;
+	  }
+	else
+	  fmt = AFMT_U8;	/* This is always supported */
 
+      audio_format[dev] = DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, fmt, 1);
+    }
+
+  if (local_conversion[dev])	/* This shadows the HW format */
+    return local_conversion[dev];
+
+  return audio_format[dev];
+}
+
 int
 audio_open (int dev, struct fileinfo *file)
 {
@@ -68,12 +98,21 @@
   if ((ret = DMAbuf_open (dev, mode)) < 0)
     return ret;
 
-  if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
+  local_conversion[dev] = 0;
+
+  if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
     {
       audio_release (dev, file);
       return RET_ERROR (ENXIO);
     }
 
+  if (dev_type == SND_DEV_AUDIO)
+    {
+      set_format (dev, AFMT_MU_LAW);
+    }
+  else
+    set_format (dev, bits);
+
   wr_buff_no[dev] = -1;
   audio_mode[dev] = AM_NONE;
 
@@ -128,21 +167,24 @@
 {
   int             c, p, l;
   int             err;
-  int             dev_type = dev & 0x0f;
 
   dev = dev >> 4;
 
   p = 0;
   c = count;
 
-  if (audio_mode[dev] == AM_READ)	/* Direction changed */
+  if (audio_mode[dev] == AM_READ)	/*
+					 * Direction changed
+					 */
     {
       wr_buff_no[dev] = -1;
     }
 
   audio_mode[dev] = AM_WRITE;
 
-  if (!count)			/* Flush output */
+  if (!count)			/*
+				 * Flush output
+				 */
     {
       if (wr_buff_no[dev] >= 0)
 	{
@@ -154,11 +196,17 @@
     }
 
   while (c)
-    {				/* Perform output blocking */
-      if (wr_buff_no[dev] < 0)	/* There is no incomplete buffers */
+    {				/*
+				 * Perform output blocking
+				 */
+      if (wr_buff_no[dev] < 0)	/*
+				 * There is no incomplete buffers
+				 */
 	{
 	  if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
-	    return wr_buff_no[dev];
+	    {
+	      return wr_buff_no[dev];
+	    }
 	  wr_buff_ptr[dev] = 0;
 	}
 
@@ -166,21 +214,27 @@
       if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
 	l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
 
-      if (!dsp_devs[dev]->copy_from_user)
-	{			/* No device specific copy routine */
+      if (!audio_devs[dev]->copy_from_user)
+	{			/*
+				 * No device specific copy routine
+				 */
 	  COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
 	}
       else
-	dsp_devs[dev]->copy_from_user (dev,
+	audio_devs[dev]->copy_from_user (dev,
 			      wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
 
 
-      /* Insert local processing here */
+      /*
+       * Insert local processing here
+       */
 
-      if (dev_type == SND_DEV_AUDIO)
+      if (local_conversion[dev] == AFMT_MU_LAW)
 	{
 #ifdef linux
-	  /* This just allows interrupts while the conversion is running */
+	  /*
+	   * This just allows interrupts while the conversion is running
+	   */
 	  __asm__ ("sti");
 #endif
 	  translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
@@ -193,7 +247,9 @@
       if (wr_buff_ptr[dev] >= wr_buff_size[dev])
 	{
 	  if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
-	    return err;
+	    {
+	      return err;
+	    }
 
 	  wr_buff_no[dev] = -1;
 	}
@@ -209,7 +265,6 @@
   int             c, p, l;
   char           *dmabuf;
   int             buff_no;
-  int             dev_type = dev & 0x0f;
 
   dev = dev >> 4;
   p = 0;
@@ -235,12 +290,16 @@
       if (l > c)
 	l = c;
 
-      /* Insert any local processing here. */
+      /*
+       * Insert any local processing here.
+       */
 
-      if (dev_type == SND_DEV_AUDIO)
+      if (local_conversion[dev] == AFMT_MU_LAW)
 	{
 #ifdef linux
-	  /* This just allows interrupts while the conversion is running */
+	  /*
+	   * This just allows interrupts while the conversion is running
+	   */
 	  __asm__ ("sti");
 #endif
 
@@ -262,7 +321,6 @@
 audio_ioctl (int dev, struct fileinfo *file,
 	     unsigned int cmd, unsigned int arg)
 {
-  int             dev_type = dev & 0x0f;
 
   dev = dev >> 4;
 
@@ -293,22 +351,32 @@
       return DMAbuf_ioctl (dev, cmd, arg, 0);
       break;
 
-    default:
-      if (dev_type == SND_DEV_AUDIO)
-	return RET_ERROR (EIO);
+    case SNDCTL_DSP_GETFMTS:
+      return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
+      break;
 
+    case SNDCTL_DSP_SETFMT:
+      return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
+
+    default:
       return DMAbuf_ioctl (dev, cmd, arg, 0);
+      break;
     }
 }
 
 long
 audio_init (long mem_start)
 {
+  /*
+ * NOTE! This routine could be called several times during boot.
+ */
   return mem_start;
 }
 
 #else
-/* Stub versions */
+/*
+ * Stub versions
+ */
 
 int
 audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v1.1.30/linux/drivers/sound/configure.c	Sun May  1 12:12:25 1994
+++ linux/drivers/sound/configure.c	Mon Jul 18 09:50:55 1994
@@ -40,23 +40,31 @@
 
 #define OPT_GUS		3
 #define OPT_MPU401	4
+#define OPT_UART6850	5
+#define OPT_PSS		6
+#define OPT_GUS16	7
+#define OPT_GUSMAX	8
+#define OPT_MSS		9
+
+#define OPT_HIGHLEVEL   10	/* This must be same than the next one */
+#define OPT_SBPRO	10
+#define OPT_SB16	11
+#define OPT_AUDIO	12
+#define OPT_MIDI_AUTO	13
+#define OPT_MIDI	14
+#define OPT_YM3812_AUTO	15
+#define OPT_YM3812	16
+#define OPT_SEQUENCER	17
+#define OPT_LAST	17	/* Must be the same than the defined OPT */
 
-#define OPT_HIGHLEVEL   5
-#define OPT_SBPRO	5
-#define OPT_SB16	6
-#define OPT_AUDIO	7
-#define OPT_MIDI_AUTO	8
-#define OPT_MIDI	9
-#define OPT_YM3812_AUTO	10	/* Select this automaticly if user selects
-				   * MIDI or AdLib driver */
-#define OPT_YM3812	11	/* Select this if the previous one was not
-				   * selected */
-#define OPT_SEQUENCER	12
-#define OPT_CHIP_MIDI   13	/* New support added at UW - Milwauklee UW -
-				   * Milwauklee */
-#define OPT_LAST	12
-
-#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)|B(OPT_MPU401))
+#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \
+		  B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)|B(OPT_MSS))
+/*
+ * Options that have been disabled for some reason (incompletely implemented
+ * and/or tested). Don't remove from this list before looking at file
+ * experimental.txt for further info.
+ */
+#define DISABLED_OPTIONS (B(OPT_PSS))
 
 typedef struct
   {
@@ -87,24 +95,29 @@
 
 hw_entry        hw_table[] =
 {
-/* 0 */
+/*
+ * 0
+ */
   {0, 0, "PAS", 1, 0, 0},
   {0, 0, "SB", 1, 0, 0},
   {0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0, 0},
 
-/* 3 */
   {0, 0, "GUS", 1, 0, 0},
   {0, 0, "MPU401", 1, 0, 0},
+  {0, 0, "UART6850", 1, 0, 0},
+  {0, 0, "PSS", 1, 0, 0},
+  {B (OPT_GUS), 0, "GUS16", 1, 0, 0},
+  {B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0},
+  {0, 0, "MSS", 1, 0, 0},
+
   {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1},
   {B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1},
-  {B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1},
+{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1},
   {B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
-  {B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1},
+  {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1},
   {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
-  {B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
-/* 10 */
-  {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1},
-  {0, 0, "CHIP_MIDI", 1, 0, 0}
+  {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
+  {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}
 };
 
 char           *questions[] =
@@ -114,6 +127,11 @@
   "AdLib support",
   "Gravis Ultrasound support",
   "MPU-401 support (NOT for SB16)",
+  "6850 UART Midi support",
+  "PSS (ECHO-ADI2111) support",
+  "16 bit sampling option of GUS (_NOT_ GUS MAX)",
+  "GUS MAX support",
+  "Microsoft Sound System support",
 
   "SoundBlaster Pro support",
   "SoundBlaster 16 support",
@@ -123,7 +141,7 @@
   "This should not be asked",
   "FM synthesizer (YM3812/OPL-3) support",
   "/dev/sequencer support",
-  "MIDI on CHIP support"
+  "Should I die"
 };
 
 unsigned long   selected_options = 0;
@@ -136,12 +154,12 @@
     {
     case 0:
       fprintf (stderr, "The SoundBlaster, AdLib and ProAudioSpectrum\n"
-	       "cards cannot be installed at the same time\n");
-      fprintf (stderr, "\nSelect at most one of them:\n");
+	       "CARDS cannot be installed at the same time.\n\n"
+	       "However the PAS16 has a SB emulator so you could select"
+	       "the SoundBlaster DRIVER with it.\n");
       fprintf (stderr, "	- ProAudioSpectrum 16\n");
       fprintf (stderr, "	- SoundBlaster / SB Pro\n");
-      fprintf (stderr, "          (Could be selected with PAS16 also\n"
-	       "	  since there is a SB emulation on it)\n");
+      fprintf (stderr, "          (Could be selected with a PAS16 also)\n");
       fprintf (stderr, "	- AdLib\n");
       fprintf (stderr, "\nDon't enable SoundBlaster if you have GUS at 0x220!\n\n");
       break;
@@ -166,6 +184,9 @@
     if (hw_table[nr].exclusive_options & selected_options)
       return 0;
 
+  if (DISABLED_OPTIONS & B (nr))
+    return 0;
+
   return 1;
 }
 
@@ -185,7 +206,9 @@
       exit (-1);
     }
 
-  if (len < 2)			/* There is an additional LF at the end */
+  if (len < 2)			/*
+				 * There is an additional LF at the end
+				 */
     return def_answ;
 
   answ[len - 1] = 0;
@@ -214,7 +237,9 @@
       exit (-1);
     }
 
-  if (len < 2)			/* There is an additional LF at the end */
+  if (len < 2)			/*
+				 * There is an additional LF at the end
+				 */
     return default_answer;
 
   answ[len - 1] = 0;
@@ -242,8 +267,15 @@
 
   if (think_positively (0))
     {
-      selected_options = 0xffffffff & ~B (OPT_MPU401);
-      fprintf (stderr, "Note! MPU-401 driver was not enabled\n");
+      /*
+ * Select all but some most dangerous cards. These cards are difficult to
+ * detect reliably or conflict with some other cards (SCSI, Mitsumi)
+ */
+      selected_options = 0xffffffff &
+	~(B (OPT_MPU401) | B (OPT_UART6850) | B (OPT_PSS)) &
+	~DISABLED_OPTIONS;
+
+      fprintf (stderr, "Note! MPU-401, PSS and 6850 UART drivers not enabled\n");
       full_driver = 1;
     }
   else
@@ -255,14 +287,18 @@
 	  printf ("#undef KERNEL_SOUNDCARD\n");
 	  exit (0);
 	}
-      /* Partial driver */
+      /*
+       * Partial driver
+       */
 
       full_driver = 0;
 
       for (i = 0; i <= OPT_LAST; i++)
 	if (can_select_option (i))
 	  {
-	    if (!(selected_options & B (i)))	/* Not selected yet */
+	    if (!(selected_options & B (i)))	/*
+						 * Not selected yet
+						 */
 	      if (!hw_table[i].verify)
 		{
 		  if (hw_table[i].alias)
@@ -289,6 +325,73 @@
   if (selected_options & B (OPT_SB16))
     selected_options |= B (OPT_SBPRO);
 
+  if (selected_options & B (OPT_PSS))
+    {
+    genld_again:
+      fprintf
+	(stderr,
+       "if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n"
+	 "then you must include the LD in the kernel.\n"
+	 "(do you wish to include a LD) ? ");
+      if (think_positively (1))
+	{
+	  char            path[512];
+
+	  fprintf (stderr,
+		   "Enter the path to your LD file (pwd is sound): ");
+	  scanf ("%s", path);
+	  fprintf (stderr, "including LD file %s\n", path);
+	  selected_options |= B (OPT_SB) | B (OPT_MPU401) | B (OPT_ADLIB);
+
+	  /* Gen LD header */
+	  {
+	    int             fd;
+	    int             count;
+	    char            c;
+	    int             i = 0;
+
+	    if ((fd = open (path, 0)) > 0)
+	      {
+		FILE           *sf = fopen ("synth-ld.h", "w");
+
+		fprintf (sf, "/* automaticaly generated by configure */\n");
+		fprintf (sf, "unsigned char pss_synth[] = {\n");
+		while (1)
+		  {
+		    count = read (fd, &c, 1);
+		    if (count == 0)
+		      break;
+		    if (i != 0 && (i % 10) == 0)
+		      fprintf (sf, "\n");
+		    fprintf (sf, "0x%02x,", c & 0xFFL);
+		    i++;
+		  }
+		fprintf (sf, "};\n"
+			 "#define pss_synthLen %d\n", i);
+		fclose (sf);
+		close (fd);
+	      }
+	    else
+	      {
+		fprintf (stderr, "couldn't open %s as the ld file\n",
+			 path);
+		fprintf (stderr, "try again with correct path? ");
+		if (think_positively (1))
+		  goto genld_again;
+	      }
+	  }
+	}
+      else
+	{
+	  FILE           *sf = fopen ("synth-ld.h", "w");
+
+	  fprintf (sf, "/* automaticaly generated by configure */\n");
+	  fprintf (sf, "unsigned char pss_synth[1];\n"
+		   "#define pss_synthLen 0\n");
+	  fclose (sf);
+	}
+    }
+
   if (!(selected_options & ANY_DEVS))
     {
       printf ("#undef CONFIGURE_SOUNDCARD\n");
@@ -307,21 +410,26 @@
 	printf ("#define EXCLUDE_%s\n", hw_table[i].macro);
 
 
-  printf ("#define EXCLUDE_PRO_MIDI\n");
-  printf ("#define EXCLUDE_CHIP_MIDI\n");
-
   /*
    * IRQ and DMA settings
    */
   printf ("\n");
 
 #if defined(linux)
-  if (selected_options & B (OPT_SB) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
+  if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
     {
+      fprintf (stderr, "\nI/O base for SB?\n"
+	       "The factory default is 220\n"
+	       "Enter the SB I/O base: ");
+
+      num = ask_value ("%x", 0x220);
+      fprintf (stderr, "SB I/O base set to %03x\n", num);
+      printf ("#define SBC_BASE 0x%03x\n", num);
+
       fprintf (stderr, "\nIRQ number for SoundBlaster?\n"
 	       "The IRQ address is defined by the jumpers on your card.\n"
 	  "The factory default is either 5 or 7 (depending on the model).\n"
-	       "Valid values are 9, 5, 7 and 10.\n"
+	       "Valid values are 9(=2), 5, 7 and 10.\n"
 	       "Enter the value: ");
 
       num = ask_value ("%d", 7);
@@ -332,12 +440,11 @@
 	  num = 7;
 	}
       fprintf (stderr, "SoundBlaster IRQ set to %d\n", num);
-      printf ("#define SBC_BASE 0x220\n");
+
       printf ("#define SBC_IRQ %d\n", num);
 
-      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS)))
+      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_PSS)))
 	{
-
 	  fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
 		   "For SB 1.0, 1.5 and 2.0 this MUST be 1\n"
 		   "SB Pro supports DMA channels 0, 1 and 3 (jumper)\n"
@@ -397,7 +504,9 @@
 		   "Enter the value: ");
 
 	  num = ask_value ("%d", 10);
-	  if (num == 6 || num < 3 || num > 15 || num == 2)	/* Illegal */
+	  if (num == 6 || num < 3 || num > 15 || num == 2)	/*
+								 * Illegal
+								 */
 	    {
 
 	      fprintf (stderr, "*** Illegal input! ***\n");
@@ -461,7 +570,9 @@
 	       "Enter the value: ");
 
       num = ask_value ("%d", 15);
-      if (num == 6 || num < 3 || num > 15 || num == 2)	/* Invalid */
+      if (num == 6 || num < 3 || num > 15 || num == 2)	/*
+							 * Invalid
+							 */
 	{
 
 	  fprintf (stderr, "*** Illegal input! ***\n");
@@ -498,11 +609,13 @@
 
       fprintf (stderr, "\nIRQ number for MPU-401?\n"
 	       "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
-	       "The default value is 5.\n"
+	       "The default value is 9.\n"
 	       "Enter the value: ");
 
-      num = ask_value ("%d", 5);
-      if (num == 6 || num < 3 || num > 15)	/* Used for floppy */
+      num = ask_value ("%d", 9);
+      if (num == 6 || num < 3 || num > 15)	/*
+						 * Used for floppy
+						 */
 	{
 
 	  fprintf (stderr, "*** Illegal input! ***\n");
@@ -511,6 +624,161 @@
       fprintf (stderr, "MPU-401 IRQ set to %d\n", num);
       printf ("#define MPU_IRQ %d\n", num);
     }
+
+  if (selected_options & B (OPT_UART6850))
+    {
+      fprintf (stderr, "\nI/O base for 6850 UART Midi?\n"
+	       "Be carefull. No defaults.\n"
+	       "Enter the 6850 UART I/O base: ");
+
+      num = ask_value ("%x", 0);
+      if (num == 0)
+	{
+	  /*
+ * Invalid value entered
+ */
+	  printf ("#define EXCLUDE_UART6850\n");
+	}
+      else
+	{
+	  fprintf (stderr, "6850 UART I/O base set to %03x\n", num);
+	  printf ("#define U6850_BASE 0x%03x\n", num);
+
+	  fprintf (stderr, "\nIRQ number for 6850 UART?\n"
+		   "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
+		   "The default value is 5.\n"
+		   "Enter the value: ");
+
+	  num = ask_value ("%d", 5);
+	  if (num == 6 || num < 3 || num > 15)	/*
+						 * Used for floppy
+						 */
+	    {
+
+	      fprintf (stderr, "*** Illegal input! ***\n");
+	      num = 5;
+	    }
+	  fprintf (stderr, "6850 UART IRQ set to %d\n", num);
+	  printf ("#define U6850_IRQ %d\n", num);
+	}
+    }
+
+  if (selected_options & B (OPT_PSS))
+    {
+      fprintf (stderr, "\nI/O base for PSS?\n"
+	       "The factory default is 220\n"
+	       "Enter the PSS I/O base: ");
+
+      num = ask_value ("%x", 0x220);
+      fprintf (stderr, "PSS I/O base set to %03x\n", num);
+      printf ("#define PSS_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for PSS?\n"
+	       "Valid numbers are: 3, 4, 5, 7, 9(=2) or 10.\n"
+	       "The default value is 10.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 10);
+      if (num == 6 || num < 3 || num > 15)	/* Used for floppy */
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 7;
+	}
+      fprintf (stderr, "PSS IRQ set to %d\n", num);
+      printf ("#define PSS_IRQ %d\n", num);
+
+      fprintf (stderr, "\nDMA number for ECHO-PSS?\n"
+	       "The default value is 3\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num == 4 || num < 0 || num > 7)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 3;
+	}
+      fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num);
+      printf ("#define PSS_DMA %d\n", num);
+    }
+
+  if (selected_options & B (OPT_MSS))
+    {
+      fprintf (stderr, "\nI/O base for MSS (MS Sound System)?\n"
+	       "The factory default is 530\n"
+	       "Other possible values are  604, E80 or F40\n"
+	       "Enter the MSS I/O base: ");
+
+      num = ask_value ("%x", 0x530);
+      fprintf (stderr, "MSS I/O base set to %03x\n", num);
+      printf ("#define MSS_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for MSS?\n"
+	       "Valid numbers are: 7, 9(=2), 10 and 11.\n"
+	       "The default value is 10.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 10);
+      if (num == 6 || num < 3 || num > 15)	/* Used for floppy */
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 7;
+	}
+      fprintf (stderr, "MSS IRQ set to %d\n", num);
+      printf ("#define MSS_IRQ %d\n", num);
+
+      fprintf (stderr, "\nDMA number for MSS?\n"
+	       "Valid values are 1 and 3 (sometimes 0)"
+	       "The default value is 3\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num == 4 || num < 0 || num > 7)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 3;
+	}
+      fprintf (stderr, "\nMSS DMA set to %d\n", num);
+      printf ("#define MSS_DMA %d\n", num);
+    }
+
+  if (selected_options & B (OPT_GUS16))
+    {
+      fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n"
+	       "The factory default is 530\n"
+	       "Other possible values are  604, E80 or F40\n"
+	       "Enter the GUS16 I/O base: ");
+
+      num = ask_value ("%x", 0x530);
+      fprintf (stderr, "GUS16 I/O base set to %03x\n", num);
+      printf ("#define GUS16_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for GUS16?\n"
+	       "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n"
+	       "The default value is 7.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 7);
+      if (num == 6 || num < 3 || num > 15)	/* Used for floppy */
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 7;
+	}
+      fprintf (stderr, "GUS16 IRQ set to %d\n", num);
+      printf ("#define GUS16_IRQ %d\n", num);
+
+      fprintf (stderr, "\nDMA number for GUS16?\n"
+	       "The default value is 3\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num < 0 || num > 3)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 3;
+	}
+      fprintf (stderr, "\nGUS16 DMA set to %d\n", num);
+      printf ("#define GUS16_DMA %d\n", num);
+    }
 #endif
 
   if (selected_options & B (OPT_AUDIO))
@@ -521,9 +789,12 @@
 	def_size = 32768;
 
 #ifndef __386BSD__
-      if (((selected_options & B (OPT_PAS)) || (selected_options & B (OPT_SB16))) &&
+      if ((selected_options & (B (OPT_PAS) | B (OPT_PAS) | B (OPT_GUS16) | B (OPT_GUSMAX) |
+			       B (OPT_MSS) | B (OPT_PSS))) &&
 	  !full_driver)
-	def_size = 65536;	/* PAS16 or SB16 */
+	def_size = 65536;	/*
+				 * PAS16 or SB16
+				 */
 #endif
 
       fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n"
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- v1.1.30/linux/drivers/sound/dev_table.c	Sun May  1 12:12:25 1994
+++ linux/drivers/sound/dev_table.c	Mon Jul 18 09:50:55 1994
@@ -32,101 +32,138 @@
 
 #ifdef CONFIGURE_SOUNDCARD
 
+int
+snd_find_driver (int type)
+{
+  int             i, n = sizeof (sound_drivers) / sizeof (struct driver_info);
+
+  for (i = 0; i < (n - 1); i++)
+    if (sound_drivers[i].card_type == type)
+      return i;
+
+  return -1;			/*
+				 * Not found
+				 */
+}
+
 long
 sndtable_init (long mem_start)
 {
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+  int             drv;
 
   for (i = 0; i < (n - 1); i++)
-    if (supported_drivers[i].enabled)
-      if (supported_drivers[i].probe (&supported_drivers[i].config))
+    if (snd_installed_cards[i].enabled)
+      if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
+	snd_installed_cards[i].enabled = 0;	/*
+						 * Mark as not detected
+						 */
+      else if (sound_drivers[drv].probe (&snd_installed_cards[i].config))
 	{
 #ifndef SHORT_BANNERS
 	  printk ("snd%d",
-		  supported_drivers[i].card_type);
+		  snd_installed_cards[i].card_type);
 #endif
 
-	  mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
+	  mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config);
 #ifndef SHORT_BANNERS
 	  printk (" at 0x%x irq %d drq %d\n",
-		  supported_drivers[i].config.io_base,
-		  supported_drivers[i].config.irq,
-		  supported_drivers[i].config.dma);
+		  snd_installed_cards[i].config.io_base,
+		  snd_installed_cards[i].config.irq,
+		  snd_installed_cards[i].config.dma);
 #endif
 	}
       else
-	supported_drivers[i].enabled = 0;	/* Mark as not detected */
+	snd_installed_cards[i].enabled = 0;	/*
+						 * Mark as not detected
+						 */
   return mem_start;
 }
 
 int
 sndtable_probe (int unit, struct address_info *hw_config)
-{
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+  {
+    int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
-  if (!unit)
-    return TRUE;
+    if (!unit)
+      return TRUE;
 
-  for (i = 0; i < (n - 1); i++)
-    if (supported_drivers[i].card_type == unit)
-      {
-	supported_drivers[i].config.io_base = hw_config->io_base;
-	supported_drivers[i].config.irq = hw_config->irq;
-	supported_drivers[i].config.dma = hw_config->dma;
-	if (supported_drivers[i].probe (hw_config))
-	  return 1;
-	supported_drivers[i].enabled = 0;	/* Mark as not detected */
-	return 0;
-      }
+    for (i = 0; i < (n - 1); i++)
+      if (snd_installed_cards[i].enabled)
+	if (snd_installed_cards[i].card_type == unit)
+	  {
+	    int             drv;
+
+	    snd_installed_cards[i].config.io_base = hw_config->io_base;
+	    snd_installed_cards[i].config.irq = hw_config->irq;
+	    snd_installed_cards[i].config.dma = hw_config->dma;
+	    if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
+	      snd_installed_cards[i].enabled = 0;	/*
+							 * Mark as not
+							 * detected
+							 */
+	    else if (sound_drivers[drv].probe (hw_config))
+	      return 1;
+	    snd_installed_cards[i].enabled = 0;	/*
+						 * Mark as not detected
+						 */
+	    return 0;
+	  }
 
-  return FALSE;
-}
+    return FALSE;
+  }
 
 int
 sndtable_init_card (int unit, struct address_info *hw_config)
-{
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
-
-  if (!unit)
-    {
-      if (sndtable_init (0) != 0)
-	panic ("snd: Invalid memory allocation\n");
-      return TRUE;
-    }
+  {
+    int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
-  for (i = 0; i < (n - 1); i++)
-    if (supported_drivers[i].card_type == unit)
+    if (!unit)
       {
-	supported_drivers[i].config.io_base = hw_config->io_base;
-	supported_drivers[i].config.irq = hw_config->irq;
-	supported_drivers[i].config.dma = hw_config->dma;
-
-	if (supported_drivers[i].attach (0, hw_config) != 0)
-	  panic ("snd#: Invalid memory allocation\n");
+	if (sndtable_init (0) != 0)
+	  panic ("snd: Invalid memory allocation\n");
 	return TRUE;
       }
 
-  return FALSE;
-}
+    for (i = 0; i < (n - 1); i++)
+      if (snd_installed_cards[i].card_type == unit)
+	{
+	  int             drv;
+
+	  snd_installed_cards[i].config.io_base = hw_config->io_base;
+	  snd_installed_cards[i].config.irq = hw_config->irq;
+	  snd_installed_cards[i].config.dma = hw_config->dma;
+
+	  if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
+	    snd_installed_cards[i].enabled = 0;	/*
+						 * Mark as not detected
+						 */
+	  else if (sound_drivers[drv].attach (0, hw_config) != 0)
+	    panic ("snd#: Invalid memory allocation\n");
+	  return TRUE;
+	}
 
+    return FALSE;
+  }
+
 int
 sndtable_get_cardcount (void)
 {
-  return num_dspdevs + num_mixers + num_synths + num_midis;
+  return num_audiodevs + num_mixers + num_synths + num_midis;
 }
 
 #ifdef linux
 void
 sound_setup (char *str, int *ints)
 {
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
   /*
  * First disable all drivers
  */
 
   for (i = 0; i < n; i++)
-    supported_drivers[i].enabled = 0;
+    snd_installed_cards[i].enabled = 0;
 
   if (ints[0] == 0 || ints[1] == 0)
     return;
@@ -145,7 +182,9 @@
 
       if (card_type > 127)
 	{
-	  /* Add any future extensions here */
+	  /*
+	   * Add any future extensions here
+	   */
 	  return;
 	}
 
@@ -155,17 +194,20 @@
 
       ptr = -1;
       for (j = 0; j < n && ptr == -1; j++)
-	if (supported_drivers[j].card_type == card_type)
+	if (snd_installed_cards[j].card_type == card_type &&
+	    !snd_installed_cards[j].enabled)	/*
+						 * Not already found
+						 */
 	  ptr = j;
 
       if (ptr == -1)
 	printk ("Sound: Invalid setup parameter 0x%08x\n", val);
       else
 	{
-	  supported_drivers[ptr].enabled = 1;
-	  supported_drivers[ptr].config.io_base = ioaddr;
-	  supported_drivers[ptr].config.irq = irq;
-	  supported_drivers[ptr].config.dma = dma;
+	  snd_installed_cards[ptr].enabled = 1;
+	  snd_installed_cards[ptr].config.io_base = ioaddr;
+	  snd_installed_cards[ptr].config.irq = irq;
+	  snd_installed_cards[ptr].config.dma = dma;
 	}
     }
 }
@@ -174,24 +216,27 @@
 void
 sound_chconf (int card_type, int ioaddr, int irq, int dma)
 {
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
   int             ptr, j;
 
   ptr = -1;
   for (j = 0; j < n && ptr == -1; j++)
-    if (supported_drivers[j].card_type == card_type)
+    if (snd_installed_cards[j].card_type == card_type &&
+	!snd_installed_cards[j].enabled)	/*
+						 * Not already found
+						 */
       ptr = j;
 
   if (ptr != -1)
     {
-      supported_drivers[ptr].enabled = 1;
+      snd_installed_cards[ptr].enabled = 1;
       if (ioaddr)
-	supported_drivers[ptr].config.io_base = ioaddr;
+	snd_installed_cards[ptr].config.io_base = ioaddr;
       if (irq)
-	supported_drivers[ptr].config.irq = irq;
+	snd_installed_cards[ptr].config.irq = irq;
       if (dma)
-	supported_drivers[ptr].config.dma = dma;
+	snd_installed_cards[ptr].config.dma = dma;
     }
 }
 
@@ -201,17 +246,24 @@
 sound_getconf (int card_type)
 {
   int             j, ptr;
-  int             n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
   ptr = -1;
   for (j = 0; j < n && ptr == -1; j++)
-    if (supported_drivers[j].card_type == card_type)
+    if (snd_installed_cards[j].card_type == card_type)
       ptr = j;
 
   if (ptr == -1)
     return (struct address_info *) NULL;
 
-  return &supported_drivers[ptr].config;
+  return &snd_installed_cards[ptr].config;
+}
+
+#else
+
+void
+sound_setup (char *str, int *ints)
+{
 }
 
 #endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v1.1.30/linux/drivers/sound/dev_table.h	Sun May  1 12:12:25 1994
+++ linux/drivers/sound/dev_table.h	Mon Jul 18 09:50:55 1994
@@ -40,20 +40,71 @@
  *	NOTE! 	NOTE!	NOTE!	NOTE!
  */
 
-struct card_info {
-	int card_type;	/*	From soundcard.c	*/
+struct driver_info {
+	int card_type;	/*	From soundcard.h	*/
 	char *name;
 	long (*attach) (long mem_start, struct address_info *hw_config);
 	int (*probe) (struct address_info *hw_config);
+};
+
+struct card_info {
+	int card_type;	/* Link (search key) to the driver list */
 	struct address_info config;
 	int enabled;
 };
 
-/** UWM -- new  MIDI structure here.. **/
+/*
+ * Device specific parameters (used only by dmabuf.c)
+ */
+#define MAX_SUB_BUFFERS		(32*MAX_REALTIME_FACTOR)
+
+#define DMODE_NONE		0
+#define DMODE_OUTPUT		1
+#define DMODE_INPUT		2
+
+struct dma_buffparms {
+	int      dma_mode;	/* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
+
+	/*
+ 	 * Pointers to raw buffers
+ 	 */
+
+  	char     *raw_buf[DSP_BUFFCOUNT];
+    	unsigned long   raw_buf_phys[DSP_BUFFCOUNT];
+    	int             raw_count;
+
+     	/*
+         * Device state tables
+         */
+
+	unsigned long flags;
+#define DMA_BUSY	0x00000001
+#define DMA_RESTART	0x00000002
+#define DMA_ACTIVE	0x00000004
+#define DMA_STARTED	0x00000008
+#define DMA_ALLOC_DONE	0x00000020
+
+	int      open_mode;
+
+	/*
+	 * Queue parameters.
+	 */
+       	int      qlen;
+       	int      qhead;
+       	int      qtail;
+
+	int      nbufs;
+	int      counts[MAX_SUB_BUFFERS];
+	int      subdivision;
+	char    *buf[MAX_SUB_BUFFERS];
+	unsigned long buf_phys[MAX_SUB_BUFFERS];
+
+	int      fragment_size;
+	int	 max_fragments;
+
+	int	 bytes_in_use;
 
-struct generic_midi_info{
-        char *name;	/* Name of the MIDI device.. */
-        long (*attach) (long mem_start);
+	int	 underrun_count;
 };
 
 struct audio_operations {
@@ -61,6 +112,9 @@
 	int flags;
 #define NOTHING_SPECIAL 	0
 #define NEEDS_RESTART		1
+#define DMA_AUTOMODE		2
+	int  format_mask;	/* Bitmask for supported audio formats */
+	void *devc;		/* Driver specific info */
 	int (*open) (int dev, int mode);
 	void (*close) (int dev);
 	void (*output_block) (int dev, unsigned long buf, 
@@ -72,9 +126,13 @@
 	int (*prepare_for_output) (int dev, int bufsize, int nbufs);
 	void (*reset) (int dev);
 	void (*halt_xfer) (int dev);
-	int (*has_output_drained)(int dev);
+	int (*local_qlen)(int dev);
         void (*copy_from_user)(int dev, char *localbuf, int localoffs,
                                snd_rw_buf *userbuf, int useroffs, int len);
+	int buffcount;
+	long buffsize;
+	int dmachan;
+	struct dma_buffparms *dmap;
 };
 
 struct mixer_operations {
@@ -83,13 +141,14 @@
 
 struct synth_operations {
 	struct synth_info *info;
+	int midi_dev;
 	int synth_type;
 	int synth_subtype;
 
 	int (*open) (int dev, int mode);
 	void (*close) (int dev);
 	int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
-	int (*kill_note) (int dev, int voice, int velocity);
+	int (*kill_note) (int dev, int voice, int note, int velocity);
 	int (*start_note) (int dev, int voice, int note, int velocity);
 	int (*set_instr) (int dev, int voice, int instr);
 	void (*reset) (int dev);
@@ -101,10 +160,16 @@
 	void (*panning) (int dev, int voice, int value);
 	void (*volume_method) (int dev, int mode);
 	int (*pmgr_interface) (int dev, struct patmgr_info *info);
+	void (*bender) (int dev, int chn, int value);
+	int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc);
+
+ 	struct voice_alloc_info alloc;
+ 	struct channel_info chn_info[16];
 };
 
 struct midi_operations {
 	struct midi_info info;
+	struct synth_operations *converter;
 	int (*open) (int dev, int mode,
 		void (*inputintr)(int dev, unsigned char data),
 		void (*outputintr)(int dev)
@@ -115,159 +180,163 @@
 	int (*start_read) (int dev);
 	int (*end_read) (int dev);
 	void (*kick)(int dev);
-	int (*command) (int dev, unsigned char data);
+	int (*command) (int dev, unsigned char *data);
 	int (*buffer_status) (int dev);
+	int (*prefix_cmd) (int dev, unsigned char status);
 };
 
-/** UWM -- new structure for MIDI  **/
-
-struct generic_midi_operations {
-	struct midi_info info;
-	int (*open) (int dev, int mode);
-	void (*close) (int dev);
-	int (*write) (int dev, snd_rw_buf *data);
-	int (*read)  (int dev, snd_rw_buf *data);
-};	
-
-#ifndef ALL_EXTERNAL_TO_ME
-
-#ifdef _MIDI_TABLE_C_
-
-/** UWM **/
-       struct generic_midi_operations * generic_midi_devs[MAX_MIDI_DEV] = {NULL}; 
-       int num_generic_midis = 0, pro_midi_dev = 0; 
-
-      struct generic_midi_info midi_supported[] = {
+struct sound_timer_operations {
+	struct sound_timer_info info;
+	int priority;
+	int devlink;
+	int (*open)(int dev, int mode);
+	void (*close)(int dev);
+	int (*event)(int dev, unsigned char *ev);
+	unsigned long (*get_time)(int dev);
+	int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+	void (*arm_timer)(int dev, long time);
+};
 
-#ifndef EXCLUDE_PRO_MIDI
-        {"ProAudioSpectrum MV101",pro_midi_attach}
+#ifdef _DEV_TABLE_C_   
+	struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0;
+	struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
+	struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0;
+	struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
+
+#ifndef EXCLUDE_SEQUENCER
+	extern struct sound_timer_operations default_sound_timer;
+	struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = 
+		{&default_sound_timer, NULL}; 
+	int num_sound_timers = 1;
+#else
+	struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = 
+		{NULL}; 
+	int num_sound_timers = 0;
 #endif
-        }; 
 
-        int num_midi_drivers = 
-            sizeof (midi_supported) / sizeof(struct generic_midi_info);
+/*
+ * List of low level drivers compiled into the kernel.
+ */
 
+	struct driver_info sound_drivers[] = {
+#ifndef EXCLUDE_PSS
+	  {SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss},
 #endif
-
-
-#ifdef _DEV_TABLE_C_   
-	struct audio_operations * dsp_devs[MAX_DSP_DEV] = {NULL}; int num_dspdevs = 0;
-	struct mixer_operations * mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
-	struct synth_operations * synth_devs[MAX_SYNTH_DEV] = {NULL}; int num_synths = 0;
-	struct midi_operations * midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
-
-
-#   ifndef EXCLUDE_MPU401
-        int mpu401_dev = 0;
-#   endif
+#ifndef EXCLUDE_YM3812
+		{SNDCARD_ADLIB,	"OPL-2/OPL-3 FM",		attach_adlib_card, probe_adlib},
+#endif
+#ifndef EXCLUDE_PAS
+		{SNDCARD_PAS,	"ProAudioSpectrum",	attach_pas_card, probe_pas},
+#endif
+#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+		{SNDCARD_MPU401,"Roland MPU-401",	attach_mpu401, probe_mpu401},
+#endif
+#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+		{SNDCARD_UART6850,"6860 UART Midi",	attach_uart6850, probe_uart6850},
+#endif
+#ifndef EXCLUDE_SB
+		{SNDCARD_SB,	"SoundBlaster",		attach_sb_card, probe_sb},
+#endif
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
+#ifndef EXCLUDE_AUDIO
+		{SNDCARD_SB16,	"SoundBlaster16",	sb16_dsp_init, sb16_dsp_detect},
+#endif
+#ifndef EXCLUDE_MIDI
+		{SNDCARD_SB16MIDI,"SB16 MIDI",	attach_sb16midi, probe_sb16midi},
+#endif
+#endif
+#ifndef EXCLUDE_GUS16
+		{SNDCARD_GUS16,	"Ultrasound 16-bit opt.",	attach_gus_db16, probe_gus_db16},
+#endif
+#ifndef EXCLUDE_MSS
+		{SNDCARD_MSS,	"MS Sound System",	attach_ms_sound, probe_ms_sound},
+#endif
+#ifndef EXCLUDE_GUS
+		{SNDCARD_GUS,	"Gravis Ultrasound",	attach_gus_card, probe_gus},
+#endif
+		{0,			"*?*",			NULL, NULL}
+	};
 
 /*
+ *	List of devices actually configured in the system.
+ *
  *	Note! The detection order is significant. Don't change it.
  */
 
-	struct card_info supported_drivers[] = {
+	struct card_info snd_installed_cards[] = {
+#ifndef EXCLUDE_PSS
+	     {SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE},
+#endif
 #if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
-		{SNDCARD_MPU401,"Roland MPU-401",	attach_mpu401, probe_mpu401,
-			{MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+		{SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+#ifdef MPU2_BASE
+		{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef MPU3_BASE
+		{SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
 #endif
+#ifndef EXCLUDE_MSS
+		{SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE},
+#endif
+
+#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+		{SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
 
 #ifndef EXCLUDE_PAS
-		{SNDCARD_PAS,	"ProAudioSpectrum",	attach_pas_card, probe_pas,
-			{PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
+		{SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifndef EXCLUDE_SB
-		{SNDCARD_SB,	"SoundBlaster",		attach_sb_card, probe_sb,
-			{SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
+		{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
 #ifndef EXCLUDE_AUDIO
-		{SNDCARD_SB16,	"SoundBlaster16",	sb16_dsp_init, sb16_dsp_detect,
-			{SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
+		{SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
 #endif
 #ifndef EXCLUDE_MIDI
-		{SNDCARD_SB16MIDI,"SB16 MPU-401",	attach_sb16midi, probe_sb16midi,
-			{SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
+		{SNDCARD_SB16MIDI,{SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 
 #ifndef EXCLUDE_GUS
-		{SNDCARD_GUS,	"Gravis Ultrasound",	attach_gus_card, probe_gus,
-			{GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
+#ifndef EXCLUDE_GUS16
+		{SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA}, SND_DEFAULT_ENABLE},
+#endif
+		{SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifndef EXCLUDE_YM3812
-		{SNDCARD_ADLIB,	"AdLib",		attach_adlib_card, probe_adlib,
-			{FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
+		{SNDCARD_ADLIB, {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
 #endif
-		{0,			"*?*",			NULL, 0}
+		{0, {0}, 0}
 	};
 
 	int num_sound_drivers =
-	    sizeof(supported_drivers) / sizeof (struct card_info);
+	    sizeof(sound_drivers) / sizeof (struct driver_info);
+	int num_sound_cards =
+	    sizeof(snd_installed_cards) / sizeof (struct card_info);
 
 
-# ifndef EXCLUDE_AUDIO 
-	int sound_buffcounts[MAX_DSP_DEV] = {0};
-	long sound_buffsizes[MAX_DSP_DEV] = {0};
-	int sound_dsp_dmachan[MAX_DSP_DEV] = {0};
-	int sound_dma_automode[MAX_DSP_DEV] = {0};
-# endif
 #else
-	extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs;
+	extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs;
 	extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
-	extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths;
+	extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths;
 	extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
-#   ifndef EXCLUDE_MPU401
-        extern int mpu401_dev;
-#   endif
+	extern struct sound_timer_operations * sound_timer_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_sound_timers;
 
-	extern struct card_info supported_drivers[];
+	extern struct driver_info sound_drivers[];
 	extern int num_sound_drivers;
+	extern struct card_info snd_installed_cards[];
+	extern int num_sound_cards;
 
-# ifndef EXCLUDE_AUDIO
-	extern int sound_buffcounts[MAX_DSP_DEV];
-	extern long sound_buffsizes[MAX_DSP_DEV];
-	extern int sound_dsp_dmachan[MAX_DSP_DEV];
-	extern int sound_dma_automode[MAX_DSP_DEV];
-# endif
-
-#endif
-
 long sndtable_init(long mem_start);
 int sndtable_get_cardcount (void);
-long CMIDI_init(long mem_start); /* */
 struct address_info *sound_getconf(int card_type);
 void sound_chconf(int card_type, int ioaddr, int irq, int dma);
-#endif
+int snd_find_driver(int type);
 
-#endif
-
-/* If external to me.... :) */
-
-#ifdef ALL_EXTERNAL_TO_ME
-
-	extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs;
-        extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
-        extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths;
-        extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
-	extern struct generic_midi_operations *generic_midi_devs[]; 
-	extern int num_generic_midis, pro_midi_dev;
- 
-#ifndef EXCLUDE_MPU401
-        extern int mpu401_dev;
-#endif
-
-	extern struct generic_midi_info midi_supported[];
-	extern struct card_info supported_drivers[];
-        extern int num_sound_drivers;
-	extern int num_midi_drivers;	
-#ifndef EXCLUDE_AUDIO
-        extern int sound_buffcounts[MAX_DSP_DEV];
-        extern long sound_buffsizes[MAX_DSP_DEV];
-        extern int sound_dsp_dmachan[MAX_DSP_DEV];
-        extern int sound_dma_automode[MAX_DSP_DEV];
-#endif
-
-#endif
+#endif	/* _DEV_TABLE_C_ */
+#endif	/* _DEV_TABLE_H_ */
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v1.1.30/linux/drivers/sound/dmabuf.c	Sun May  1 12:12:26 1994
+++ linux/drivers/sound/dmabuf.c	Mon Jul 18 09:50:55 1994
@@ -3,7 +3,7 @@
  *
  * The DMA buffer manager for digitized voice applications
  *
- * Copyright by Hannu Savolainen 1993
+ * Copyright by Hannu Savolainen 1993, 1994
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -35,68 +35,14 @@
 
 #if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
 
-#define MAX_SUB_BUFFERS		(32*MAX_REALTIME_FACTOR)
+DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
 
-/*
- * The DSP channel can be used either for input or output. Variable
- * 'dma_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.
- */
-
-#define DMODE_NONE		0
-#define DMODE_OUTPUT		1
-#define DMODE_INPUT		2
-
-DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]);
-
-static int      dma_mode[MAX_DSP_DEV] =
-{0};				/* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
-
-static volatile int dmabuf_interrupted[MAX_DSP_DEV] =
-{0};
-
-/*
- * Pointers to raw buffers
- */
-
-char           *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT] =
-{
-  {NULL}};
-unsigned long   snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
-int             snd_raw_count[MAX_DSP_DEV];
-
-/*
- * Device state tables
- */
-
-static int      dev_busy[MAX_DSP_DEV];
-static int      dev_needs_restart[MAX_DSP_DEV];
-static int      dev_modes[MAX_DSP_DEV];
-static int      dev_active[MAX_DSP_DEV];
-static int      dev_started[MAX_DSP_DEV];
-static int      dev_qlen[MAX_DSP_DEV];
-static int      dev_qhead[MAX_DSP_DEV];
-static int      dev_qtail[MAX_DSP_DEV];
-static int      dev_underrun[MAX_DSP_DEV];
-static int      bufferalloc_done[MAX_DSP_DEV] =
-{0};
-
-/*
- * Logical buffers for each devices
- */
-
-static int      dev_nbufs[MAX_DSP_DEV];	/* # of logical buffers ( >=
-
-						   * sound_buffcounts[dev] */
-static int      dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS];
-static int      dev_subdivision[MAX_DSP_DEV];
-static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS];
-static char    *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] =
-{
-  {NULL}};
-static int      dev_buffsize[MAX_DSP_DEV];
+static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
+{0};				/*
+		 * Primitive way to allocate
+		 * such a large array.
+		 * Needs dynamic run-time alloction.
+		 */
 
 static void
 reorganize_buffers (int dev)
@@ -105,130 +51,159 @@
    * This routine breaks the physical device buffers to logical ones.
    */
 
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+  struct audio_operations *dsp_dev = audio_devs[dev];
+
   unsigned        i, p, n;
   unsigned        sr, nc, sz, bsz;
 
-  sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
-  nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
-  sz = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
+  if (dmap->fragment_size == 0)
+    {				/* Compute the fragment size using the default algorithm */
 
-  if (sr < 1 || nc < 1 || sz < 1)
-    {
-      printk ("SOUND: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);
-      sr = DSP_DEFAULT_SPEED;
-      nc = 1;
-      sz = 8;
-    }
+      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);
+
+      if (sr < 1 || nc < 1 || sz < 1)
+	{
+	  printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
+		  dev, sr, nc, sz);
+	  sr = DSP_DEFAULT_SPEED;
+	  nc = 1;
+	  sz = 8;
+	}
 
-  sz /= 8;			/* Convert # of bits -> # of bytes */
+      sz /= 8;			/* #bits -> #bytes */
 
-  sz = sr * nc * sz;
+      sz = sr * nc * sz;
 
-  /*
-   * Compute a buffer size not exeeding 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).
    */
 
-  bsz = sound_buffsizes[dev];
+      bsz = dsp_dev->buffsize;
+      while (bsz > sz)
+	bsz /= 2;
 
-  while (bsz > sz)
-    bsz >>= 1;			/* Divide by 2 */
+      if (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize)
+	bsz /= 2;		/* Needs at least 2 buffers */
 
-  if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev])
-    bsz >>= 1;			/* Need at least 2 buffers */
+      if (dmap->subdivision == 0)	/* Not already set */
+	dmap->subdivision = 1;	/* Init to default value */
 
-  if (dev_subdivision[dev] == 0)
-    dev_subdivision[dev] = 1;	/* Default value */
+      bsz /= dmap->subdivision;
 
-  bsz /= dev_subdivision[dev];	/* Use smaller buffers */
+      if (bsz < 64)
+	bsz = 4096;		/* Just a sanity check */
 
-  if (bsz == 0)
-    bsz = 4096;			/* Just a sanity check */
+      while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS)
+	bsz *= 2;
 
-  while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS)
-    bsz <<= 1;			/* Too much buffers */
-
-  dev_buffsize[dev] = bsz;
-  n = 0;
+      dmap->fragment_size = bsz;
+    }
+  else
+    {
+      /*
+ * 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)
+	dmap->fragment_size = audio_devs[dev]->buffsize;
+      bsz = dmap->fragment_size;
+    }
 
   /*
    * Now computing addresses for the logical buffers
    */
 
-  for (i = 0; i < snd_raw_count[dev]; i++)
+  n = 0;
+  for (i = 0; i < dmap->raw_count &&
+       n < dmap->max_fragments &&
+       n < MAX_SUB_BUFFERS; i++)
     {
       p = 0;
 
-      while ((p + bsz) <= sound_buffsizes[dev])
+      while ((p + bsz) <= dsp_dev->buffsize &&
+	     n < dmap->max_fragments &&
+	     n < MAX_SUB_BUFFERS)
 	{
-	  dev_buf[dev][n] = snd_raw_buf[dev][i] + p;
-	  dev_buf_phys[dev][n] = snd_raw_buf_phys[dev][i] + p;
+	  dmap->buf[n] = dmap->raw_buf[i] + p;
+	  dmap->buf_phys[n] = dmap->raw_buf_phys[i] + p;
 	  p += bsz;
 	  n++;
 	}
     }
 
-  dev_nbufs[dev] = n;
+  dmap->nbufs = n;
+  dmap->bytes_in_use = n * bsz;
 
-  for (i = 0; i < dev_nbufs[dev]; i++)
+  for (i = 0; i < dmap->nbufs; i++)
     {
-      dev_counts[dev][i] = 0;
+      dmap->counts[i] = 0;
     }
 
-  bufferalloc_done[dev] = 1;
+  dmap->flags |= DMA_ALLOC_DONE;
 }
 
 static void
 dma_init_buffers (int dev)
 {
-  RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
-  dev_underrun[dev] = 0;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev];
 
-  dev_busy[dev] = 1;
+  RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
 
-  bufferalloc_done[dev] = 0;
+  dmap->flags = DMA_BUSY;	/* Other flags off */
+  dmap->qlen = dmap->qhead = dmap->qtail = 0;
 
-  dev_active[dev] = dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
-  dev_needs_restart[dev] = dev_started[dev] = 0;
-  dma_mode[dev] = DMODE_NONE;
+  dmap->qlen = dmap->qtail = dmap->qhead = 0;
+  dmap->dma_mode = DMODE_NONE;
 }
 
 int
 DMAbuf_open (int dev, int mode)
 {
   int             retval;
+  struct dma_buffparms *dmap = NULL;
 
-  if (dev >= num_dspdevs)
+  if (dev >= num_audiodevs)
     {
       printk ("PCM device %d not installed.\n", dev);
       return RET_ERROR (ENXIO);
     }
 
-  if (dev_busy[dev])
-    return RET_ERROR (EBUSY);
-
-  if (!dsp_devs[dev])
+  if (!audio_devs[dev])
     {
-      printk ("DSP device %d not initialized\n", dev);
+      printk ("PCM device %d not initialized\n", dev);
       return RET_ERROR (ENXIO);
     }
 
+  dmap = audio_devs[dev]->dmap = &dmaps[dev];
+
+  if (dmap->flags & DMA_BUSY)
+    return RET_ERROR (EBUSY);
+
 #ifdef USE_RUNTIME_DMAMEM
+  dmap->raw_buf[0] = NULL;
   sound_dma_malloc (dev);
 #endif
 
-  if (snd_raw_buf[dev][0] == NULL)
+  if (dmap->raw_buf[0] == NULL)
     return RET_ERROR (ENOSPC);	/* Memory allocation failed during boot */
 
-  if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)
+  if ((retval = audio_devs[dev]->open (dev, mode)) < 0)
     return retval;
 
-  dev_modes[dev] = mode;
-  dev_subdivision[dev] = 0;
+  dmap->open_mode = mode;
+  dmap->subdivision = dmap->underrun_count = 0;
+  dmap->fragment_size = 0;
+  dmap->max_fragments = 65536;	/* Just a large value */
 
   dma_init_buffers (dev);
-  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
-  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
-  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
+  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
+  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
+  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
 
   return 0;
 }
@@ -240,10 +215,11 @@
   unsigned long   flags;
 
   DISABLE_INTR (flags);
-  dsp_devs[dev]->reset (dev);
-  dsp_devs[dev]->close (dev);
+
+  audio_devs[dev]->reset (dev);
+  audio_devs[dev]->close (dev);
 
-  if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0)
+  if ((retval = audio_devs[dev]->open (dev, audio_devs[dev]->dmap->open_mode)) < 0)
     printk ("Sound: Reset failed - Can't reopen device\n");
   RESTORE_INTR (flags);
 
@@ -256,17 +232,19 @@
 {
   unsigned long   flags;
 
-  if (dma_mode[dev] == DMODE_OUTPUT)
+  if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)
     {
       DISABLE_INTR (flags);
 
-      while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
-		dmabuf_interrupted[dev]))
-	     && dev_qlen[dev])
+      while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])
+	     && audio_devs[dev]->dmap->qlen)
 	{
 	  DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
 	  if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
-	    return dev_qlen[dev];
+	    {
+	      RESTORE_INTR (flags);
+	      return audio_devs[dev]->dmap->qlen;
+	    }
 	}
       RESTORE_INTR (flags);
 
@@ -276,27 +254,26 @@
        */
 
       DISABLE_INTR (flags);
-      if (dsp_devs[dev]->has_output_drained)	/* Device has hidden buffers */
+      if (audio_devs[dev]->local_qlen)	/* Device has hidden buffers */
 	{
-	  while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
-		   dmabuf_interrupted[dev])
-		 && !dsp_devs[dev]->has_output_drained (dev))
+	  while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+		 && audio_devs[dev]->local_qlen (dev))
 	    {
-	      DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4);
+	      DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ);
 	    }
 	}
       RESTORE_INTR (flags);
     }
-  return dev_qlen[dev];
+  return audio_devs[dev]->dmap->qlen;
 }
 
 int
 DMAbuf_release (int dev, int mode)
 {
+  unsigned long   flags;
 
-  if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
-	dmabuf_interrupted[dev])
-      && (dma_mode[dev] == DMODE_OUTPUT))
+  if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+      && (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT))
     {
       dma_sync (dev);
     }
@@ -305,12 +282,14 @@
   sound_dma_free (dev);
 #endif
 
-  dsp_devs[dev]->reset (dev);
+  DISABLE_INTR (flags);
+  audio_devs[dev]->reset (dev);
 
-  dsp_devs[dev]->close (dev);
+  audio_devs[dev]->close (dev);
 
-  dma_mode[dev] = DMODE_NONE;
-  dev_busy[dev] = 0;
+  audio_devs[dev]->dmap->dma_mode = DMODE_NONE;
+  audio_devs[dev]->dmap->flags &= ~DMA_BUSY;
+  RESTORE_INTR (flags);
 
   return 0;
 }
@@ -320,50 +299,51 @@
 {
   unsigned long   flags;
   int             err = EIO;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
   DISABLE_INTR (flags);
-  if (!dev_qlen[dev])
+  if (!dmap->qlen)
     {
-      if (dev_needs_restart[dev])
+      if (dmap->flags & DMA_RESTART)
 	{
 	  dma_reset (dev);
-	  dev_needs_restart[dev] = 0;
+	  dmap->flags &= ~DMA_RESTART;
 	}
 
-      if (dma_mode[dev] == DMODE_OUTPUT)	/* Was output -> direction change */
+      if (dmap->dma_mode == DMODE_OUTPUT)	/* Direction change */
 	{
 	  dma_sync (dev);
 	  dma_reset (dev);
-	  dma_mode[dev] = DMODE_NONE;
+	  dmap->dma_mode = DMODE_NONE;
 	}
 
-      if (!bufferalloc_done[dev])
+      if (!(dmap->flags & DMA_ALLOC_DONE))
 	reorganize_buffers (dev);
 
-      if (!dma_mode[dev])
+      if (dmap->dma_mode)
 	{
 	  int             err;
 
-	  if ((err = dsp_devs[dev]->prepare_for_input (dev,
-				    dev_buffsize[dev], dev_nbufs[dev])) < 0)
+	  if ((err = audio_devs[dev]->prepare_for_input (dev,
+				     dmap->fragment_size, dmap->nbufs)) < 0)
 	    {
 	      RESTORE_INTR (flags);
 	      return err;
 	    }
-	  dma_mode[dev] = DMODE_INPUT;
+	  dmap->dma_mode = DMODE_INPUT;
 	}
 
-      if (!dev_active[dev])
+      if (!(dmap->flags & DMA_ACTIVE))
 	{
-	  dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
-				      dev_buffsize[dev], 0,
-				      !sound_dma_automode[dev] ||
-				      !dev_started[dev]);
-	  dev_active[dev] = 1;
-	  dev_started[dev] = 1;
+	  audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
+					dmap->fragment_size, 0,
+				 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+					!(dmap->flags & DMA_STARTED));
+	  dmap->flags |= DMA_ACTIVE | DMA_STARTED;
 	}
 
       /* Wait for the next block */
+
       DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
       if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
 	{
@@ -376,60 +356,42 @@
     }
   RESTORE_INTR (flags);
 
-  if (!dev_qlen[dev])
+  if (!dmap->qlen)
     return RET_ERROR (err);
 
-  *buf = &dev_buf[dev][dev_qhead[dev]][dev_counts[dev][dev_qhead[dev]]];
-  *len = dev_buffsize[dev] - dev_counts[dev][dev_qhead[dev]];
+  *buf = &dmap->buf[dmap->qhead][dmap->counts[dmap->qhead]];
+  *len = dmap->fragment_size - dmap->counts[dmap->qhead];
 
-  return dev_qhead[dev];
+  return dmap->qhead;
 }
 
 int
 DMAbuf_rmchars (int dev, int buff_no, int c)
 {
-  int             p = dev_counts[dev][dev_qhead[dev]] + c;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+
+  int             p = dmap->counts[dmap->qhead] + c;
 
-  if (p >= dev_buffsize[dev])
-    {				/* This buffer is now empty */
-      dev_counts[dev][dev_qhead[dev]] = 0;
-      dev_qlen[dev]--;
-      dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
+  if (p >= dmap->fragment_size)
+    {				/* This buffer is completely empty */
+      dmap->counts[dmap->qhead] = 0;
+      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+	printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
+		dev, dmap->qlen, dmap->nbufs);
+      dmap->qlen--;
+      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
     }
   else
-    dev_counts[dev][dev_qhead[dev]] = p;
+    dmap->counts[dmap->qhead] = p;
 
   return 0;
 }
 
 int
-DMAbuf_read (int dev, snd_rw_buf * user_buf, int count)
-{
-  char           *dmabuf;
-  int             buff_no, c, err;
-
-  /*
-   * This routine returns at most 'count' bytes from the dsp input buffers.
-   * Returns negative value if there is an error.
-   */
-
-  if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &c)) < 0)
-    return buff_no;
-
-  if (c > count)
-    c = count;
-
-  COPY_TO_USER (user_buf, 0, dmabuf, c);
-
-  if ((err = DMAbuf_rmchars (dev, buff_no, c)) < 0)
-    return err;
-  return c;
-
-}
-
-int
 DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
 {
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+
   switch (cmd)
     {
     case SNDCTL_DSP_RESET:
@@ -444,10 +406,10 @@
       break;
 
     case SNDCTL_DSP_GETBLKSIZE:
-      if (!bufferalloc_done[dev])
+      if (!(dmap->flags & DMA_ALLOC_DONE))
 	reorganize_buffers (dev);
 
-      return IOCTL_OUT (arg, dev_buffsize[dev]);
+      return IOCTL_OUT (arg, dmap->fragment_size);
       break;
 
     case SNDCTL_DSP_SUBDIVIDE:
@@ -456,13 +418,14 @@
 
 	if (fact == 0)
 	  {
-	    fact = dev_subdivision[dev];
+	    fact = dmap->subdivision;
 	    if (fact == 0)
 	      fact = 1;
 	    return IOCTL_OUT (arg, fact);
 	  }
 
-	if (dev_subdivision[dev] != 0)	/* Too late to change */
+	if (dmap->subdivision != 0 ||
+	    dmap->fragment_size)/* Loo late to change */
 	  return RET_ERROR (EINVAL);
 
 	if (fact > MAX_REALTIME_FACTOR)
@@ -471,110 +434,192 @@
 	if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
 	  return RET_ERROR (EINVAL);
 
-	dev_subdivision[dev] = fact;
+	dmap->subdivision = fact;
 	return IOCTL_OUT (arg, fact);
       }
       break;
 
+    case SNDCTL_DSP_SETFRAGMENT:
+      {
+	int             fact = IOCTL_IN (arg);
+	int             bytes, count;
+
+	if (fact == 0)
+	  return RET_ERROR (EIO);
+
+	if (dmap->subdivision != 0 ||
+	    dmap->fragment_size)/* Loo late to change */
+	  return RET_ERROR (EINVAL);
+
+	bytes = fact & 0xffff;
+	count = (fact >> 16) & 0xffff;
+
+	if (count == 0)
+	  count = MAX_SUB_BUFFERS;
+
+	if (bytes < 7 || bytes > 17)	/* <64 || > 128k */
+	  return RET_ERROR (EINVAL);
+
+	if (count < 2)
+	  return RET_ERROR (EINVAL);
+
+	dmap->fragment_size = (1 << bytes);
+	dmap->max_fragments = count;
+
+	if (dmap->fragment_size > audio_devs[dev]->buffsize)
+	  dmap->fragment_size = audio_devs[dev]->buffsize;
+
+	if (dmap->fragment_size == audio_devs[dev]->buffsize &&
+	    audio_devs[dev]->flags & DMA_AUTOMODE)
+	  dmap->fragment_size /= 2;	/* Needs at least 2 buffers */
+
+	dmap->subdivision = 1;	/* Disable SNDCTL_DSP_SUBDIVIDE */
+	return IOCTL_OUT (arg, bytes | (count << 16));
+      }
+      break;
+
     default:
-      return dsp_devs[dev]->ioctl (dev, cmd, arg, local);
+      return audio_devs[dev]->ioctl (dev, cmd, arg, local);
     }
 
-  /* NOTREACHED */
   return RET_ERROR (EIO);
 }
 
+static int
+space_in_queue (int dev)
+{
+  int             len, max, tmp;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+
+  if (dmap->qlen == dmap->nbufs)/* No space at all */
+    return 0;
+
+  /*
+  * Verify that there are no more pending buffers than the limit
+  * defined by the process.
+  */
+
+  max = dmap->max_fragments;
+  len = dmap->qlen;
+
+  if (audio_devs[dev]->local_qlen)
+    {
+      tmp = audio_devs[dev]->local_qlen (dev);
+      if (tmp & len)
+	tmp--;			/*
+			 * This buffer has been counted twice
+			 */
+      len += tmp;
+    }
+
+  if (len >= max)
+    return 0;
+  return 1;
+}
+
 int
 DMAbuf_getwrbuffer (int dev, char **buf, int *size)
 {
   unsigned long   flags;
-  int             err = EIO;
+  int             abort, err = EIO;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  if (dma_mode[dev] == DMODE_INPUT)	/* Was input -> Direction change */
+  if (dmap->dma_mode == DMODE_INPUT)	/* Direction change */
     {
       dma_reset (dev);
-      dma_mode[dev] = DMODE_NONE;
+      dmap->dma_mode = DMODE_NONE;
     }
-  else if (dev_needs_restart[dev])	/* Restart buffering */
+  else if (dmap->flags & DMA_RESTART)	/* Restart buffering */
     {
       dma_sync (dev);
       dma_reset (dev);
     }
 
-  dev_needs_restart[dev] = 0;
+  dmap->flags &= ~DMA_RESTART;
 
-  if (!bufferalloc_done[dev])
+  if (!(dmap->flags & DMA_ALLOC_DONE))
     reorganize_buffers (dev);
 
-  if (!dma_mode[dev])
+  if (!dmap->dma_mode)
     {
       int             err;
 
-      dma_mode[dev] = DMODE_OUTPUT;
-      if ((err = dsp_devs[dev]->prepare_for_output (dev,
-				    dev_buffsize[dev], dev_nbufs[dev])) < 0)
+      dmap->dma_mode = DMODE_OUTPUT;
+      if ((err = audio_devs[dev]->prepare_for_output (dev,
+				     dmap->fragment_size, dmap->nbufs)) < 0)
 	return err;
     }
 
 
   DISABLE_INTR (flags);
 
-  RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
-
-  if (dev_qlen[dev] == dev_nbufs[dev])
+  abort = 0;
+  while (!space_in_queue (dev) &&
+	 !abort)
     {
-      if (!dev_active[dev])
-	{
-	  printk ("Soundcard warning: DMA not activated %d/%d\n",
-		  dev_qlen[dev], dev_nbufs[dev]);
-	  return RET_ERROR (EIO);
-	}
-
-      /* Wait for free space */
+      /*
+       * Wait for free space
+       */
       DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
       if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
 	{
 	  printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
 	  err = EIO;
+	  abort = 1;
 	  SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
 	}
       else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
-	err = EINTR;
+	{
+	  err = EINTR;
+	  abort = 1;
+	}
     }
   RESTORE_INTR (flags);
 
-  if (dev_qlen[dev] == dev_nbufs[dev])
-    return RET_ERROR (err);	/* We have got signal (?) */
+  if (!space_in_queue (dev))
+    {
+      return RET_ERROR (err);	/* Caught a signal ? */
+    }
 
-  *buf = dev_buf[dev][dev_qtail[dev]];
-  *size = dev_buffsize[dev];
-  dev_counts[dev][dev_qtail[dev]] = 0;
+  *buf = dmap->buf[dmap->qtail];
+  *size = dmap->fragment_size;
+  dmap->counts[dmap->qtail] = 0;
 
-  return dev_qtail[dev];
+  return dmap->qtail;
 }
 
 int
 DMAbuf_start_output (int dev, int buff_no, int l)
 {
-  if (buff_no != dev_qtail[dev])
-    printk ("Soundcard warning: DMA buffers out of sync %d != %d\n", buff_no, dev_qtail[dev]);
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  dev_qlen[dev]++;
+  if (buff_no != dmap->qtail)
+    printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
 
-  dev_counts[dev][dev_qtail[dev]] = l;
-
-  dev_needs_restart[dev] = (l != dev_buffsize[dev]) &&
-    (sound_dma_automode[dev] || dsp_devs[dev]->flags & NEEDS_RESTART);
+  dmap->qlen++;
+  if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+    printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
+	    dev, dmap->qlen, dmap->nbufs);
+
+  dmap->counts[dmap->qtail] = l;
+
+  if ((l != dmap->fragment_size) &&
+      ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
+       audio_devs[dev]->flags & NEEDS_RESTART))
+    dmap->flags |= DMA_RESTART;
+  else
+    dmap->flags &= ~DMA_RESTART;
 
-  dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
+  dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
 
-  if (!dev_active[dev])
+  if (!(dmap->flags & DMA_ACTIVE))
     {
-      dev_active[dev] = 1;
-      dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
-				   dev_counts[dev][dev_qhead[dev]], 0,
-			     !sound_dma_automode[dev] || !dev_started[dev]);
-      dev_started[dev] = 1;
+      dmap->flags |= DMA_ACTIVE;
+      audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
+				     dmap->counts[dmap->qhead], 0,
+				 !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+				     !(dmap->flags & DMA_STARTED));
+      dmap->flags |= DMA_STARTED;
     }
 
   return 0;
@@ -583,7 +628,8 @@
 int
 DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
 {
-  int             chan = sound_dsp_dmachan[dev];
+  int             chan = audio_devs[dev]->dmachan;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
   unsigned long   flags;
 
   /*
@@ -595,45 +641,47 @@
    * set_dma_addr()
    */
 
-  if (sound_dma_automode[dev])
-    {				/* Auto restart mode. Transfer the whole
-				 * buffer */
+  if (audio_devs[dev]->flags & DMA_AUTOMODE)
+    {				/*
+				 * Auto restart mode. Transfer the whole *
+				 * buffer
+				 */
 #ifdef linux
       DISABLE_INTR (flags);
       disable_dma (chan);
       clear_dma_ff (chan);
       set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
-      set_dma_addr (chan, snd_raw_buf_phys[dev][0]);
-      set_dma_count (chan, sound_buffsizes[dev]);
+      set_dma_addr (chan, dmap->raw_buf_phys[0]);
+      set_dma_count (chan, dmap->bytes_in_use);
       enable_dma (chan);
       RESTORE_INTR (flags);
-#else /* linux */
+#else
 
 #ifdef __386BSD__
       printk ("sound: Invalid DMA mode for device %d\n", dev);
 
       isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
-		    snd_raw_buf_phys[dev][0],
-		    sound_buffsizes[dev],
+		    dmap->raw_buf_phys[0],
+		    dmap->bytes_in_use,
 		    chan);
-#else /* __386BSD__ */
-#if defined(ISC) || defined(SCO) || defined(SVR42)
+#else
+#if defined(GENERIC_SYSV)
 #ifndef DMAMODE_AUTO
       printk ("sound: Invalid DMA mode for device %d\n", dev);
-#endif /* DMAMODE_AUTO */
+#endif
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
 #ifdef DMAMODE_AUTO
 		 | DMAMODE_AUTO
-#endif /* DMAMODE_AUTO */
+#endif
 		 ,
-		 snd_raw_buf_phys[dev][0], count);
+		 dmap->raw_buf_phys[0], dmap->bytes_in_use);
       dma_enable (chan);
-#else /* SYSV */
+#else
 #error This routine is not valid for this OS.
-#endif /* SYSV */
-#endif /* __386BSD__ */
+#endif
+#endif
 
-#endif /* linux */
+#endif
     }
   else
     {
@@ -646,24 +694,24 @@
       set_dma_count (chan, count);
       enable_dma (chan);
       RESTORE_INTR (flags);
-#else /* linux */
+#else
 #ifdef __386BSD__
       isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
 		    physaddr,
 		    count,
 		    chan);
-#else /* __386BSD__ */
+#else
 
-#if defined(ISC) || defined(SCO) || defined(SVR42)
+#if defined(GENERIC_SYSV)
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
 		 physaddr, count);
       dma_enable (chan);
-#else /* SYSV */
+#else
 #error This routine is not valid for this OS.
-#endif /* SYSV */
-#endif /* __386BSD__ */
+#endif /* GENERIC_SYSV */
+#endif
 
-#endif /* linux */
+#endif
     }
 
   return count;
@@ -672,50 +720,65 @@
 long
 DMAbuf_init (long mem_start)
 {
-  int             i;
+  int             dev;
 
   /*
-   * In this version the DMA buffer allocation is done by sound_mem_init()
-   * which is called by init/main.c
-   */
-
-  for (i = 0; i < MAX_DSP_DEV; i++)
-    {
-      dev_qlen[i] = 0;
-      dev_qhead[i] = 0;
-      dev_qtail[i] = 0;
-      dev_active[i] = 0;
-      dev_busy[i] = 0;
-      bufferalloc_done[i] = 0;
-    }
+ * NOTE! This routine could be called several times.
+ */
 
+  for (dev = 0; dev < num_audiodevs; dev++)
+    audio_devs[dev]->dmap = &dmaps[dev];
   return mem_start;
 }
 
 void
-DMAbuf_outputintr (int dev, int underrun_flag)
+DMAbuf_outputintr (int dev, int event_type)
 {
+  /*
+ * Event types:
+ *	0 = DMA transfer done. Device still has more data in the local
+ *	    buffer.
+ *	1 = DMA transfer done. Device doesn't have local buffer or it's
+ *	    empty now.
+ *	2 = No DMA transfer but the device has now more space in it's local
+ *	    buffer.
+ */
+
   unsigned long   flags;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  dev_qlen[dev]--;
-  dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
-  dev_active[dev] = 0;
-
-  if (dev_qlen[dev])
-    {
-      dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
-				   dev_counts[dev][dev_qhead[dev]], 1,
-				   !sound_dma_automode[dev]);
-      dev_active[dev] = 1;
-    }
-  else if (underrun_flag)
-    {
-      dev_underrun[dev]++;
-      dsp_devs[dev]->halt_xfer (dev);
-      dev_needs_restart[dev] = (sound_dma_automode[dev] ||
-				dsp_devs[dev]->flags & NEEDS_RESTART);
-    }
+  if (event_type != 2)
+    {
+      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+	{
+	  printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
+		  dev, dmap->qlen, dmap->nbufs);
+	  return;
+	}
 
+      dmap->qlen--;
+      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+      dmap->flags &= ~DMA_ACTIVE;
+
+      if (dmap->qlen)
+	{
+	  audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
+					 dmap->counts[dmap->qhead], 1,
+				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
+	  dmap->flags |= DMA_ACTIVE;
+	}
+      else if (event_type == 1)
+	{
+	  dmap->underrun_count++;
+	  audio_devs[dev]->halt_xfer (dev);
+	  if ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
+	      audio_devs[dev]->flags & NEEDS_RESTART)
+	    dmap->flags |= DMA_RESTART;
+	  else
+	    dmap->flags &= ~DMA_RESTART;
+	}
+    }				/* event_type != 2 */
+
   DISABLE_INTR (flags);
   if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
     {
@@ -728,28 +791,31 @@
 DMAbuf_inputintr (int dev)
 {
   unsigned long   flags;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  if (!dev_busy[dev])
-    {
-      dsp_devs[dev]->close (dev);
-    }
-  else if (dev_qlen[dev] == (dev_nbufs[dev] - 1))
+  if (dmap->qlen == (dmap->nbufs - 1))
     {
       printk ("Sound: Recording overrun\n");
-      dev_underrun[dev]++;
-      dsp_devs[dev]->halt_xfer (dev);
-      dev_active[dev] = 0;
-      dev_needs_restart[dev] = sound_dma_automode[dev];
+      dmap->underrun_count++;
+      audio_devs[dev]->halt_xfer (dev);
+      dmap->flags &= ~DMA_ACTIVE;
+      if (audio_devs[dev]->flags & DMA_AUTOMODE)
+	dmap->flags |= DMA_RESTART;
+      else
+	dmap->flags &= ~DMA_RESTART;
     }
   else
     {
-      dev_qlen[dev]++;
-      dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
-
-      dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
-				  dev_buffsize[dev], 1,
-				  !sound_dma_automode[dev]);
-      dev_active[dev] = 1;
+      dmap->qlen++;
+      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+	printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
+		dev, dmap->qlen, dmap->nbufs);
+      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+
+      audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
+				    dmap->fragment_size, 1,
+				  !(audio_devs[dev]->flags & DMA_AUTOMODE));
+      dmap->flags |= DMA_ACTIVE;
     }
 
   DISABLE_INTR (flags);
@@ -764,12 +830,12 @@
 DMAbuf_open_dma (int dev)
 {
   unsigned long   flags;
-  int             chan = sound_dsp_dmachan[dev];
+  int             chan = audio_devs[dev]->dmachan;
 
   if (ALLOC_DMA_CHN (chan))
     {
       printk ("Unable to grab DMA%d for the audio driver\n", chan);
-      return 0;
+      return RET_ERROR (EBUSY);
     }
 
   DISABLE_INTR (flags);
@@ -779,13 +845,13 @@
 #endif
   RESTORE_INTR (flags);
 
-  return 1;
+  return 0;
 }
 
 void
 DMAbuf_close_dma (int dev)
 {
-  int             chan = sound_dsp_dmachan[dev];
+  int             chan = audio_devs[dev]->dmachan;
 
   DMAbuf_reset_dma (chan);
   RELEASE_DMA_CHN (chan);
@@ -805,7 +871,9 @@
  */
 
 #else
-/* Stub versions if audio services not included  */
+/*
+ * Stub versions if audio services not included
+ */
 
 int
 DMAbuf_open (int dev, int mode)
@@ -817,12 +885,6 @@
 DMAbuf_release (int dev, int mode)
 {
   return 0;
-}
-
-int
-DMAbuf_read (int dev, snd_rw_buf * user_buf, int count)
-{
-  return RET_ERROR (EIO);
 }
 
 int
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/experimental.txt linux/drivers/sound/experimental.txt
--- v1.1.30/linux/drivers/sound/experimental.txt	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/experimental.txt	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,160 @@
+This version contains some features which is are NOT enabled by default. 
+I'm trying to release an official/reliable version soon so that the
+Linux version of Doom (and other games) becomes possible. For that reason
+I have disabled some features which are not reliable enough to be
+released for wide public. If you are interested to try them, please
+read this file carefully.
+
+There are currently following goodies which I have disabled:
+
+1) ECHO PSS (Personal Sound System support)
+
+This version contains support for soundcards based on the AD20msp614
+chipset made by Analog Devices. This chipset consist of the
+AD1848 codec, ADSP-21xx DSP chip and a ESC614 ASIC and is used in some
+soundcards made by Orchid, Cardinal, Echo Speech Corporation, Western
+Digital and Wearnes Technology. The PSS support is by Marc M. Hoffman
+(marc.hoffman@analog.com). I received this stuff about a week ago and
+have not been able to test it yet.
+If you are interested, remove the B(OPT_PSS) from the DISABLED_OPTIONS
+(see above).
+You have also to enable the MSS support since I have not integrated
+the AD1848 driver with the PSS one yet.
+
+2) WSS/MSS (Microsoft Sound System) support
+
+The MSS standard is based on the AD1848 codec by Analog Devices.
+Since I don't know how the software configuration of the MSS works
+so it's not supported yet. This driver should work if your card
+has jumpers for the I/O base, IRQ and DMA or there is a way to configure
+them using DOS. You could try this if you have a soundcard with
+AD1848 codec. I have tried to use this with Aztech SG NX Pro 16 without
+success. 
+If you are interested, remove the B(OPT_MSS) from the DISABLED_OPTIONS
+(see above).
+
+3) /dev/sequencer2
+
+This version has a new device file called /dev/sequence2. I have not
+implemented all parts of it but it's there. It's only interesting if
+you are writing a sequencer program yourself. Enable by creating
+the device file /dev/sequencer (minor 8).
+
+4) /dev/midi##
+
+These are tty like raw devices for MIDI ports. Since there is a minor
+incompatibility between different versions of Linux, I have disabled
+this feature by default. You just need to create the device files yourself.
+IMPORTANT!	If you get warning at line 64 of midibuf.c,
+		don't try to use /dev/midi## files. Otherwise your
+		system halts. You may also try to fix the
+		DEFINE_TIMER() macro in os.h (just remove the 2nd NULL).
+		This could happen with some earlier versions of Linux
+		(before 1.1.0???).
+
+5) Support for hardware based u-Law/A-Law and ADPCM formats.
+
+The AD1848 (and compatibles) are able to do compression and
+decompression by hardware. This version has experimental support
+for some of them. Currently they are implemented just in the
+AD1848 driver. The GUS MAX (and the 16 bit daughtercard) support
+also 16->4 bit ADPCM (the IMA one) but it don't work yet.
+The argument ioctl(SNDCTL_DSP_SAMPLESIZE) can have some new values
+in addition to the 8 and 16 supported earlier. Look at soundcard.h
+for more info.
+(In case somebody dares to ask: The ASP chip of SB16 is not supported
+so the hardware compression/decompression doesn't work with it. Also
+the ADPCM format is different than the standard (IMA) one (I guess).
+This feature is enabled by default.
+
+5) Real time fix to /dev/dsp and /dev/audio drivers
+
+The following feature should help game writers. This stuff is enabled
+by default.
+---------------- cut here ---------------------
+There is a new ioctl called SNDCTL_DSP_SETFRAGMENT. It accepts a
+int parameter which has format 0x00nn00ss where the nn is max number of 
+buffer fragments (between 0x02 and 0xff) and the ss gives indirectly the 
+size of a buffer fragment (fragment_size = (1 << ss)). Valid sizes are 
+between (ss=0x07 -> 128 bytes and ss=0x11 (17 dec) -> 128k).
+
+This ioctl must be used ONCE between open() and first call to 
+read()/write() or ioctl(SNDCTL_DSP_GETBLKSIZE). 
+
+You need just to force the fragment size to a value which is sufficiently 
+short (gives the 1/20th of sec with the speed/#channels/#bits you are using).
+
+Using a small number of fragments offers (I guess) a significant advantage.
+For example with 2 fragments the driver works as the following (at least 
+I hope so). Assuming that the process writes exactly 'fragment_size' of 
+bytes each time (this is really important).
+
+	1) When the process writes the first fragment, it will be copied to
+	the DMA buffer area and the playback begins. The write() returns
+	immediately and the process is free to continue.
+
+
+	2a) If the fragment gets played before the application writes a new
+	one, the device will be stoppen and restarted which causes a click.
+	When the process calls write next time, it will be processes as 
+	in step 1.
+
+	2b) If the process calls write before the buffer underflows, the
+	data will be queued and the process is free to continue. (There
+	is now one full and one partially played fragment in the kernel
+	buffers. This gives average delay of 1.5*fragment_time (for 
+	example 1/20th sec) before the last byte in the buffer gets played.
+
+
+	3a) If the device gets both fragments played before the next write
+	(underflow), there will be a click. The write will be processed as
+	in step 1.
+
+	3b) If the 1st fragment gets played before next write (the process
+	calls write during playback of the second fragment), it will be
+	processed as step 2b.
+
+	3c) If the process writes 3rd fragment when there is already 2
+	fragments in the queue (1 playing and 1 waiting), the process
+	will block until the 1st fragment gets played. It will then be
+	woken up and it continues as in step 2b. This means that
+	the process blocks for at most the time required to play a
+	buffer fragment.
+
+This method syncronizes the process and the audio device together 
+automaticly. The process will block at most the 'fragment_time'. Usually 
+less, depending on how much it needs time to do other things. The maximum
+delay between writing a byte and the time when it finally plays is
+at most 3 times the 'fragment_time'. 
+
+The delay depends on how much time the program needs to do it's 
+computations for the next sample (updating screen etc). If it's about
+80% of the 'fragment_time' the game will run almost without delays. If it 
+uses more time, there is a risk that the audio buffer gets empty.
+	
+The application code should be something like the following:
+
+int frag = 0x00020008;	/* 2 fragments of 2^8=256 bytes */
+int frag_size;
+
+int fd=open("/dev/dsp");
+ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+ioctl(NDCTL_DSP_SPEED); /* And #channels & #bits if required */
+
+/*
+ * Query the actual fragment sice since the driver may refuse
+ * the requested one (unlikely but possible?)
+ */
+
+ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size);
+
+while(True)
+{
+	do_computations();
+	write(fd, buf, frag_size);	/* Always the same size!!!!!!! */
+}
+
+I have tested this with a modified version of str.c. The algorithm works 
+as long as the playing program gets enough time to run. Hitting ENTER on 
+another virtual console causes a pause/click (with 2 frags of 64 bytes).
+------------------- cut here ---------------------
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v1.1.30/linux/drivers/sound/gus_card.c	Sun May  1 12:12:27 1994
+++ linux/drivers/sound/gus_card.c	Mon Jul 18 09:50:55 1994
@@ -36,6 +36,9 @@
 void            gusintr (int);
 
 int             gus_base, gus_irq, gus_dma;
+extern int      gus_wave_volume;
+extern int      gus_pcm_volume;
+extern int      have_gus_max;
 
 long
 attach_gus_card (long mem_start, struct address_info *hw_config)
@@ -44,12 +47,17 @@
 
   snd_set_irq_handler (hw_config->irq, gusintr);
 
-  if (gus_wave_detect (hw_config->io_base))	/* Try first the default */
+  if (gus_wave_detect (hw_config->io_base))	/*
+						 * Try first the default
+						 */
     {
       mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
 #ifndef EXCLUDE_MIDI
       mem_start = gus_midi_init (mem_start);
 #endif
+#ifndef EXCLUDE_SEQUENCER
+      sound_timer_init (hw_config->io_base + 8);
+#endif
       return mem_start;
     }
 
@@ -60,7 +68,9 @@
    */
 
   for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
-    if (io_addr != hw_config->io_base)	/* Already tested */
+    if (io_addr != hw_config->io_base)	/*
+					 * Already tested
+					 */
       if (gus_wave_detect (io_addr))
 	{
 	  printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
@@ -68,12 +78,17 @@
 #ifndef EXCLUDE_MIDI
 	  mem_start = gus_midi_init (mem_start);
 #endif
+#ifndef EXCLUDE_SEQUENCER
+	  sound_timer_init (io_addr + 8);
+#endif
 	  return mem_start;
 	}
 
 #endif
 
-  return mem_start;		/* Not detected */
+  return mem_start;		/*
+				 * Not detected
+				 */
 }
 
 int
@@ -91,7 +106,9 @@
    */
 
   for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
-    if (io_addr != hw_config->io_base)	/* Already tested */
+    if (io_addr != hw_config->io_base)	/*
+					 * Already tested
+					 */
       if (gus_wave_detect (io_addr))
 	return 1;
 
@@ -101,7 +118,7 @@
 }
 
 void
-gusintr (int unit)
+gusintr (int irq)
 {
   unsigned char   src;
 
@@ -109,6 +126,11 @@
   sti ();
 #endif
 
+#ifndef EXCLUDE_GUSMAX
+  if (have_gus_max)
+    ad1848_interrupt (irq);
+#endif
+
   while (1)
     {
       if (!(src = INB (u_IrqStatus)))
@@ -128,8 +150,11 @@
 
       if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
 	{
-	  printk ("T");
-	  gus_write8 (0x45, 0);	/* Timer control */
+#ifndef EXCLUDE_SEQUENCER
+	  sound_timer_interrupt ();
+#else
+	  gus_write8 (0x45, 0);	/* Stop timers */
+#endif
 	}
 
       if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
@@ -137,6 +162,32 @@
 	  gus_voice_irq ();
 	}
     }
+}
+
+#endif
+
+/*
+ * Some extra code for the 16 bit sampling option
+ */
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16)
+
+int
+probe_gus_db16 (struct address_info *hw_config)
+{
+  return ad1848_detect (hw_config->io_base);
+}
+
+long
+attach_gus_db16 (long mem_start, struct address_info *hw_config)
+{
+  gus_pcm_volume = 100;
+  gus_wave_volume = 90;
+
+  ad1848_init ("GUS 16 bit sampling", hw_config->io_base,
+	       hw_config->irq,
+	       hw_config->dma,
+	       hw_config->dma);
+  return mem_start;
 }
 
 #endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c
--- v1.1.30/linux/drivers/sound/gus_midi.c	Sun May  1 12:12:27 1994
+++ linux/drivers/sound/gus_midi.c	Mon Jul 18 09:50:55 1994
@@ -79,7 +79,9 @@
       gus_midi_control |= MIDI_ENABLE_XMIT;
     }
 
-  OUTB (gus_midi_control, u_MidiControl);	/* Enable */
+  OUTB (gus_midi_control, u_MidiControl);	/*
+						 * Enable
+						 */
 
   midi_busy = 1;
   qlen = qhead = qtail = output_used = 0;
@@ -105,7 +107,9 @@
     }
   else
     {
-      /* Enable Midi xmit interrupts (again) */
+      /*
+       * Enable Midi xmit interrupts (again)
+       */
       gus_midi_control |= MIDI_ENABLE_XMIT;
       OUTB (gus_midi_control, u_MidiControl);
     }
@@ -117,7 +121,9 @@
 static void
 gus_midi_close (int dev)
 {
-  /* Reset FIFO pointers, disable intrs */
+  /*
+   * Reset FIFO pointers, disable intrs
+   */
 
   OUTB (MIDI_RESET, u_MidiControl);
   midi_busy = 0;
@@ -149,14 +155,18 @@
 
   if (!qlen)
     if (dump_to_midi (midi_byte))
-      return 1;			/* OK */
+      return 1;			/*
+				 * OK
+				 */
 
   /*
    * Put to the local queue
    */
 
   if (qlen >= 256)
-    return 0;			/* Local queue full */
+    return 0;			/*
+				 * Local queue full
+				 */
 
   DISABLE_INTR (flags);
 
@@ -213,9 +223,14 @@
   return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY);
 }
 
+#define MIDI_SYNTH_NAME	"Gravis Ultrasound Midi"
+#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
 static struct midi_operations gus_midi_operations =
 {
-  {"Gravis UltraSound", 0, 0, SNDCARD_GUS},
+  {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
+  &std_midi_synth,
   gus_midi_open,
   gus_midi_close,
   gus_midi_ioctl,
@@ -223,16 +238,25 @@
   gus_midi_start_read,
   gus_midi_end_read,
   gus_midi_kick,
-  NULL,				/* command */
-  gus_midi_buffer_status
+  NULL,				/*
+				 * command
+				 */
+  gus_midi_buffer_status,
+  NULL
 };
 
 long
 gus_midi_init (long mem_start)
 {
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return mem_start;
+    }
+
   OUTB (MIDI_RESET, u_MidiControl);
 
-  my_dev = num_midis;
+  std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &gus_midi_operations;
   return mem_start;
 }
@@ -264,7 +288,9 @@
 
       if (!qlen)
 	{
-	  /* Disable Midi output interrupts, since no data in the buffer */
+	  /*
+	   * Disable Midi output interrupts, since no data in the buffer
+	   */
 	  gus_midi_control &= ~MIDI_ENABLE_XMIT;
 	  OUTB (gus_midi_control, u_MidiControl);
 	}
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v1.1.30/linux/drivers/sound/gus_wave.c	Sun May  1 12:12:33 1994
+++ linux/drivers/sound/gus_wave.c	Mon Jul 18 09:50:55 1994
@@ -3,7 +3,7 @@
  *
  * Driver for the Gravis UltraSound wave table synth.
  *
- * Copyright by Hannu Savolainen 1993
+ * Copyright by Hannu Savolainen 1993, 1994
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -72,23 +72,23 @@
 
   };
 
+static struct voice_alloc_info *voice_alloc;
+
 extern int      gus_base;
 extern int      gus_irq, gus_dma;
-extern char    *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
-extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
-extern int      snd_raw_count[MAX_DSP_DEV];
 static long     gus_mem_size = 0;
 static long     free_mem_ptr = 0;
 static int      gus_busy = 0;
 static int      nr_voices = 0;
 static int      gus_devnum = 0;
 static int      volume_base, volume_scale, volume_method;
-static int      gus_line_vol = 100, gus_mic_vol = 0;
 static int      gus_recmask = SOUND_MASK_MIC;
 static int      recording_active = 0;
 
 int             gus_wave_volume = 60;
 int             gus_pcm_volume = 80;
+int             have_gus_max = 0;
+static int      gus_line_vol = 100, gus_mic_vol = 0;
 static unsigned char mix_image = 0x00;
 
 /*
@@ -97,13 +97,9 @@
  */
 static int      active_device = 0;
 
-#define GUS_DEV_WAVE		1	/*
-					   * * * Wave table synth   */
-#define GUS_DEV_PCM_DONE	2	/*
-					   * * * PCM device, transfer done   */
-#define GUS_DEV_PCM_CONTINUE	3	/*
-					   * * * PCM device, transfer the
-					   * second * * * chn   */
+#define GUS_DEV_WAVE		1	/* Wave table synth */
+#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;
@@ -114,33 +110,13 @@
 /*
  * Variables and buffers for PCM output
  */
-#define MAX_PCM_BUFFERS		(32*MAX_REALTIME_FACTOR)	/*
-								   * * * Don't
-								   * * * change
-								   *
-								 */
-
-static int      pcm_bsize,	/*
-				 * Current blocksize
-				 */
-                pcm_nblk,	/*
-				 * Current # of blocks
-				 */
-                pcm_banksize;	/*
-
-
-				 * *  * * # bytes allocated for channels   */
-static int      pcm_datasize[MAX_PCM_BUFFERS];	/*
+#define MAX_PCM_BUFFERS		(32*MAX_REALTIME_FACTOR)	/* Don't change */
 
-
-						 * *  * * Actual # of bytes
-						 * in blk  *  */
-static volatile int pcm_head, pcm_tail, pcm_qlen;	/*
-
-
-							 * *  * * DRAM queue
-							 *  */
+static int      pcm_bsize, pcm_nblk, pcm_banksize;
+static int      pcm_datasize[MAX_PCM_BUFFERS];
+static volatile int pcm_head, pcm_tail, pcm_qlen;
 static volatile int pcm_active;
+static volatile int dma_active;
 static int      pcm_opened = 0;
 static int      pcm_current_dev;
 static int      pcm_current_block;
@@ -152,63 +128,25 @@
 
 static int      freq_div_table[] =
 {
-  44100,			/*
-				 * 14
-				 */
-  41160,			/*
-				 * 15
-				 */
-  38587,			/*
-				 * 16
-				 */
-  36317,			/*
-				 * 17
-				 */
-  34300,			/*
-				 * 18
-				 */
-  32494,			/*
-				 * 19
-				 */
-  30870,			/*
-				 * 20
-				 */
-  29400,			/*
-				 * 21
-				 */
-  28063,			/*
-				 * 22
-				 */
-  26843,			/*
-				 * 23
-				 */
-  25725,			/*
-				 * 24
-				 */
-  24696,			/*
-				 * 25
-				 */
-  23746,			/*
-				 * 26
-				 */
-  22866,			/*
-				 * 27
-				 */
-  22050,			/*
-				 * 28
-				 */
-  21289,			/*
-				 * 29
-				 */
-  20580,			/*
-				 * 30
-				 */
-  19916,			/*
-				 * 31
-				 */
-  19293				/*
-				 * 32
-				 */
+  44100,			/* 14 */
+  41160,			/* 15 */
+  38587,			/* 16 */
+  36317,			/* 17 */
+  34300,			/* 18 */
+  32494,			/* 19 */
+  30870,			/* 20 */
+  29400,			/* 21 */
+  28063,			/* 22 */
+  26843,			/* 23 */
+  25725,			/* 24 */
+  24696,			/* 25 */
+  23746,			/* 26 */
+  22866,			/* 27 */
+  22050,			/* 28 */
+  21289,			/* 29 */
+  20580,			/* 30 */
+  19916,			/* 31 */
+  19293				/* 32 */
 };
 
 static struct patch_info *samples;
@@ -231,10 +169,8 @@
 static void     do_volume_irq (int voice);
 static void     set_input_volumes (void);
 
-#define	INSTANT_RAMP		-1	/*
-					   * * * Dont use ramping   */
-#define FAST_RAMP		0	/*
-					   * * * Fastest possible ramp   */
+#define	INSTANT_RAMP		-1	/* Instant change. No ramping */
+#define FAST_RAMP		0	/* Fastest possible ramp */
 
 static void
 reset_sample_memory (void)
@@ -248,12 +184,10 @@
   for (i = 0; i < 32; i++)
     patch_map[i] = -1;
 
-  gus_poke (0, 0);		/*
-				 * Put silence here
-				 */
+  gus_poke (0, 0);		/* Put a silent sample to the beginning */
   gus_poke (1, 0);
-
   free_mem_ptr = 2;
+
   free_sample = 0;
 
   for (i = 0; i < MAX_PATCH; i++)
@@ -271,7 +205,7 @@
 
 static void
 gus_poke (long addr, unsigned char data)
-{
+{				/* Writes a byte to the DRAM */
   unsigned long   flags;
 
   DISABLE_INTR (flags);
@@ -287,7 +221,7 @@
 
 static unsigned char
 gus_peek (long addr)
-{
+{				/* Reads a byte from the DRAM */
   unsigned long   flags;
   unsigned char   tmp;
 
@@ -306,7 +240,7 @@
 
 void
 gus_write8 (int reg, unsigned int data)
-{
+{				/* Writes to an indirect register (8 bit) */
   unsigned long   flags;
 
   DISABLE_INTR (flags);
@@ -319,7 +253,7 @@
 
 unsigned char
 gus_read8 (int reg)
-{
+{				/* Reads from an indirect register (8 bit). Offset 0x80. */
   unsigned long   flags;
   unsigned char   val;
 
@@ -333,7 +267,7 @@
 
 unsigned char
 gus_look8 (int reg)
-{
+{				/* Reads from an indirect register (8 bit). No additional offset. */
   unsigned long   flags;
   unsigned char   val;
 
@@ -347,7 +281,7 @@
 
 void
 gus_write16 (int reg, unsigned int data)
-{
+{				/* Writes to an indirect register (16 bit) */
   unsigned long   flags;
 
   DISABLE_INTR (flags);
@@ -362,7 +296,7 @@
 
 unsigned short
 gus_read16 (int reg)
-{
+{				/* Reads from an indirect register (16 bit). Offset 0x80. */
   unsigned long   flags;
   unsigned char   hi, lo;
 
@@ -380,9 +314,11 @@
 
 void
 gus_write_addr (int reg, unsigned long address, int is16bit)
-{
+{				/* Writes an 24 bit memory address */
   unsigned long   hold_address;
+  unsigned long   flags;
 
+  DISABLE_INTR (flags);
   if (is16bit)
     {
       /*
@@ -401,6 +337,7 @@
   gus_delay ();
   gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
   gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
+  RESTORE_INTR (flags);
 }
 
 static void
@@ -420,7 +357,7 @@
   if (nvoices > 32)
     nvoices = 32;
 
-  nr_voices = nvoices;
+  voice_alloc->max_voice = nr_voices = nvoices;
 
   gus_write8 (0x0e, (nvoices - 1) | 0xc0);
 }
@@ -444,14 +381,8 @@
 {
   unsigned char   mode = (unsigned char) (m & 0xff);
 
-  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));	/*
-									 * Don't
-									 * start
-									 * or
-									 * stop
-									 * *
-									 * voice
-									 */
+  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) |
+	      (mode & 0xfc));	/* Don't touch last two bits */
   gus_delay ();
   gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
 }
@@ -471,9 +402,7 @@
 static void
 gus_voice_volume (unsigned int vol)
 {
-  gus_write8 (0x0d, 0x03);	/*
-				 * Stop ramp before setting volume
-				 */
+  gus_write8 (0x0d, 0x03);	/* Stop ramp before setting volume */
   gus_write16 (0x09, (unsigned short) (vol << 4));
 }
 
@@ -511,14 +440,8 @@
 {
   unsigned char   mode = (unsigned char) (m & 0xff);
 
-  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));	/*
-									 * Don't
-									 * start
-									 * or
-									 * stop
-									 * *
-									 * ramping
-									 */
+  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) |
+	      (mode & 0xfc));	/* Leave the last 2 bits alone */
   gus_delay ();
   gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
 }
@@ -551,15 +474,10 @@
   DISABLE_INTR (flags);
   gus_select_voice (voice);
   gus_voice_volume (0);
-  gus_write_addr (0x0a, 0, 0);	/*
-				 * Set current position to 0
-				 */
-  gus_write8 (0x00, 0x03);	/*
-				 * Voice off
-				 */
-  gus_write8 (0x0d, 0x03);	/*
-				 * Ramping off
-				 */
+  gus_write_addr (0x0a, 0, 0);	/* Set current position to 0 */
+  gus_write8 (0x00, 0x03);	/* Voice off */
+  gus_write8 (0x0d, 0x03);	/* Ramping off */
+  voice_alloc->map[voice] = 0;
   RESTORE_INTR (flags);
 
 }
@@ -599,17 +517,14 @@
       gus_select_voice (voice);
       gus_rampoff ();
       RESTORE_INTR (flags);
-      return;			/*
-				 * Sustain
-				 */
-    }
-
-  if (voices[voice].env_phase >= 5)
-    {
+      return;
       /*
-       * Shoot the voice off
+       * Sustain phase begins. Continue envelope after receiving note off.
        */
+    }
 
+  if (voices[voice].env_phase >= 5)
+    {				/* Envelope finished. Shoot the voice down */
       gus_voice_init (voice);
       return;
     }
@@ -626,20 +541,14 @@
   gus_voice_volume (prev_vol);
 
 
-  gus_write8 (0x06, rate);	/*
-				 * Ramping rate
-				 */
+  gus_write8 (0x06, rate);	/* Ramping rate */
 
   voices[voice].volume_irq_mode = VMODE_ENVELOPE;
 
-  if (((vol - prev_vol) / 64) == 0)	/*
-					 * No significant volume change
-					 */
+  if (((vol - prev_vol) / 64) == 0)	/* No significant volume change */
     {
       RESTORE_INTR (flags);
-      step_envelope (voice);	/*
-				 * Continue with the next phase
-				 */
+      step_envelope (voice);	/* Continue the envelope on the next step */
       return;
     }
 
@@ -648,18 +557,14 @@
       if (vol >= (4096 - 64))
 	vol = 4096 - 65;
       gus_ramp_range (0, vol);
-      gus_rampon (0x20);	/*
-				 * Increasing, irq
-				 */
+      gus_rampon (0x20);	/* Increasing volume, with IRQ */
     }
   else
     {
       if (vol <= 64)
 	vol = 65;
       gus_ramp_range (vol, 4030);
-      gus_rampon (0x60);	/*
-				 * Decreasing, irq
-				 */
+      gus_rampon (0x60);	/* Decreasing volume, with IRQ */
     }
   voices[voice].current_volume = vol;
   RESTORE_INTR (flags);
@@ -678,19 +583,13 @@
 start_release (int voice, long int flags)
 {
   if (gus_read8 (0x00) & 0x03)
-    return;			/*
-				 * Voice already stopped
-				 */
+    return;			/* Voice already stopped */
 
-  voices[voice].env_phase = 2;	/*
-				 * Will be incremented by step_envelope
-				 */
+  voices[voice].env_phase = 2;	/* Will be incremented by step_envelope */
 
   voices[voice].current_volume =
     voices[voice].initial_volume =
-    gus_read16 (0x09) >> 4;	/*
-				 * Get current volume
-				 */
+    gus_read16 (0x09) >> 4;	/* Get current volume */
 
   voices[voice].mode &= ~WAVE_SUSTAIN_ON;
   gus_rampoff ();
@@ -709,18 +608,13 @@
 
   if (instr_no < 0 || instr_no > MAX_SAMPLE)
     {
-      gus_write8 (0x00, 0x03);	/*
-				 * Hard stop
-				 */
+      gus_write8 (0x00, 0x03);	/* Hard stop */
+      voice_alloc->map[voice] = 0;
       RESTORE_INTR (flags);
       return;
     }
 
-  is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/*
-								 * 8 or 16
-								 * bit
-								 * samples
-								 */
+  is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/* 8 or 16 bits */
 
   if (voices[voice].mode & WAVE_ENVELOPES)
     {
@@ -731,9 +625,7 @@
   /*
    * Ramp the volume down but not too quickly.
    */
-  if ((gus_read16 (0x09) >> 4) < 100)	/*
-					 * Get current volume
-					 */
+  if ((int) (gus_read16 (0x09) >> 4) < 100)	/* Get current volume */
     {
       gus_voice_off ();
       gus_rampoff ();
@@ -743,9 +635,7 @@
 
   gus_ramp_range (65, 4030);
   gus_ramp_rate (2, 4);
-  gus_rampon (0x40 | 0x20);	/*
-				 * Down, once, irq
-				 */
+  gus_rampon (0x40 | 0x20);	/* Down, once, with IRQ */
   voices[voice].volume_irq_mode = VMODE_HALT;
   RESTORE_INTR (flags);
 }
@@ -762,33 +652,24 @@
 
   for (i = 0; i < 32; i++)
     {
-      gus_voice_init (i);	/*
-				 * Turn voice off
-				 */
+      gus_voice_init (i);	/* Turn voice off */
       gus_voice_init2 (i);
     }
 
-  INB (u_Status);		/*
-				 * Touch the status register
-				 */
+  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
-				 */
+  gus_look8 (0x41);		/* Clear any pending DMA IRQs */
+  gus_look8 (0x49);		/* Clear any pending sample IRQs */
 
+  gus_read8 (0x0f);		/* Clear pending IRQs */
+
 }
 
 static void
 gus_initialize (void)
 {
   unsigned long   flags;
-  register unsigned char dma_image, irq_image, tmp;
+  unsigned char   dma_image, irq_image, tmp;
 
   static unsigned char gus_irq_map[16] =
   {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
@@ -797,16 +678,11 @@
   {0, 1, 0, 2, 0, 3, 4, 5};
 
   DISABLE_INTR (flags);
-
-  gus_write8 (0x4c, 0);		/*
-				 * Reset GF1
-				 */
+  gus_write8 (0x4c, 0);		/* Reset GF1 */
   gus_delay ();
   gus_delay ();
 
-  gus_write8 (0x4c, 1);		/*
-				 * Release Reset
-				 */
+  gus_write8 (0x4c, 1);		/* Release Reset */
   gus_delay ();
   gus_delay ();
 
@@ -814,49 +690,25 @@
    * Clear all interrupts
    */
 
-  gus_write8 (0x41, 0);		/*
-				 * DMA control
-				 */
-  gus_write8 (0x45, 0);		/*
-				 * Timer control
-				 */
-  gus_write8 (0x49, 0);		/*
-				 * Sample control
-				 */
+  gus_write8 (0x41, 0);		/* DMA control */
+  gus_write8 (0x45, 0);		/* Timer control */
+  gus_write8 (0x49, 0);		/* Sample control */
 
   gus_select_max_voices (24);
 
-  INB (u_Status);		/*
-				 * Touch the status register
-				 */
+  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
-				 */
+  gus_look8 (0x41);		/* Clear any pending DMA IRQs */
+  gus_look8 (0x49);		/* Clear any pending sample IRQs */
+  gus_read8 (0x0f);		/* Clear pending IRQs */
 
-  gus_reset ();			/*
-				 * Resets all voices
-				 */
+  gus_reset ();			/* Resets all voices */
 
-  gus_look8 (0x41);		/*
-				 * Clear any pending DMA IRQs
-				 */
-  gus_look8 (0x49);		/*
-				 * Clear any pending sample IRQs
-				 */
-  gus_read8 (0x0f);		/*
-				 * Clear pending IRQs
-				 */
+  gus_look8 (0x41);		/* Clear any pending DMA IRQs */
+  gus_look8 (0x49);		/* Clear any pending sample IRQs */
+  gus_read8 (0x0f);		/* Clear pending IRQs */
 
-  gus_write8 (0x4c, 7);		/*
-				 * Master reset | DAC enable | IRQ enable
-				 */
+  gus_write8 (0x4c, 7);		/* Master reset | DAC enable | IRQ enable */
 
   /*
    * Set up for Digital ASIC
@@ -864,9 +716,7 @@
 
   OUTB (0x05, gus_base + 0x0f);
 
-  mix_image |= 0x02;		/*
-				 * Disable line out
-				 */
+  mix_image |= 0x02;		/* Disable line out */
   OUTB (mix_image, u_Mixer);
 
   OUTB (0x00, u_IRQDMAControl);
@@ -888,13 +738,9 @@
   if (!tmp)
     printk ("Warning! GUS IRQ not selected\n");
   irq_image |= tmp;
-  irq_image |= 0x40;		/*
-				 * Combine IRQ1 (GF1) and IRQ2 (Midi)
-				 */
+  irq_image |= 0x40;		/* Combine IRQ1 (GF1) and IRQ2 (Midi) */
 
-  dma_image = 0x40;		/*
-				 * Combine DMA1 (DRAM) and IRQ2 (ADC)
-				 */
+  dma_image = 0x40;		/* Combine DMA1 (DRAM) and IRQ2 (ADC) */
   tmp = gus_dma_map[gus_dma];
   if (!tmp)
     printk ("Warning! GUS DMA not selected\n");
@@ -908,60 +754,34 @@
    * Doing it first time
    */
 
-  OUTB (mix_image, u_Mixer);	/*
-				 * Select DMA control
-				 */
-  OUTB (dma_image | 0x80, u_IRQDMAControl);	/*
-						 * Set DMA address
-						 */
+  OUTB (mix_image, u_Mixer);	/* Select DMA control */
+  OUTB (dma_image | 0x80, u_IRQDMAControl);	/* Set DMA address */
 
-  OUTB (mix_image | 0x40, u_Mixer);	/*
-					 * Select IRQ control
-					 */
-  OUTB (irq_image, u_IRQDMAControl);	/*
-					 * Set IRQ address
-					 */
+  OUTB (mix_image | 0x40, u_Mixer);	/* Select IRQ control */
+  OUTB (irq_image, u_IRQDMAControl);	/* Set IRQ address */
 
   /*
    * Doing it second time
    */
 
-  OUTB (mix_image, u_Mixer);	/*
-				 * Select DMA control
-				 */
-  OUTB (dma_image, u_IRQDMAControl);	/*
-					 * Set DMA address
-					 */
+  OUTB (mix_image, u_Mixer);	/* Select DMA control */
+  OUTB (dma_image, u_IRQDMAControl);	/* Set DMA address */
 
-  OUTB (mix_image | 0x40, u_Mixer);	/*
-					 * Select IRQ control
-					 */
-  OUTB (irq_image, u_IRQDMAControl);	/*
-					 * Set IRQ address
-					 */
+  OUTB (mix_image | 0x40, u_Mixer);	/* Select IRQ control */
+  OUTB (irq_image, u_IRQDMAControl);	/* Set IRQ address */
 
-  gus_select_voice (0);		/*
-				 * This disables writes to IRQ/DMA reg
-				 */
+  gus_select_voice (0);		/* This disables writes to IRQ/DMA reg */
 
-  mix_image &= ~0x02;		/*
-				 * Enable line out
-				 */
-  mix_image |= 0x08;		/*
-				 * Enable IRQ
-				 */
+  mix_image &= ~0x02;		/* Enable line out */
+  mix_image |= 0x08;		/* Enable IRQ */
   OUTB (mix_image, u_Mixer);	/*
 				 * Turn mixer channels on
 				 * Note! Mic in is left off.
 				 */
 
-  gus_select_voice (0);		/*
-				 * This disables writes to IRQ/DMA reg
-				 */
+  gus_select_voice (0);		/* This disables writes to IRQ/DMA reg */
 
-  gusintr (0);			/*
-				 * Serve pending interrupts
-				 */
+  gusintr (0);			/* Serve pending interrupts */
   RESTORE_INTR (flags);
 }
 
@@ -1068,16 +888,13 @@
   if (sample_no < 0)
     {
       printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
-      return RET_ERROR (EINVAL);/*
-					 * Patch not defined
-					 */
+      return RET_ERROR (EINVAL);/* Patch not defined */
     }
 
-  if (sample_ptrs[sample_no] == -1)	/*
-					 * Sample not loaded
-					 */
+  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);
+      printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n",
+	      sample_no, instr_no, voice);
       return RET_ERROR (EINVAL);
     }
 
@@ -1087,15 +904,12 @@
 }
 
 static int
-#ifdef FUTURE_VERSION
 guswave_kill_note (int dev, int voice, int note, int velocity)
-#else
-guswave_kill_note (int dev, int voice, int velocity)
-#endif
 {
   unsigned long   flags;
 
   DISABLE_INTR (flags);
+  voice_alloc->map[voice] = 0xffff;
   if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
     {
       voices[voice].kill_pending = 1;
@@ -1116,26 +930,20 @@
   short           lo_limit, hi_limit;
   unsigned long   flags;
 
-  return;			/*
-				 * Currently disabled
-				 */
+  return;			/* Procedure currently disabled */
 
   if (voice < 0 || voice > 31)
     return;
 
   if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
-    return;			/*
-				 * Don't mix with envelopes
-				 */
+    return;			/* Don't mix with envelopes */
 
   if (pressure < 32)
     {
       DISABLE_INTR (flags);
       gus_select_voice (voice);
       gus_rampoff ();
-      compute_and_set_volume (voice, 255, 0);	/*
-						 * Back to original volume
-						 */
+      compute_and_set_volume (voice, 255, 0);	/* Back to original volume */
       RESTORE_INTR (flags);
       return;
     }
@@ -1154,9 +962,7 @@
     }
   gus_ramp_range (lo_limit, hi_limit);
   gus_ramp_rate (3, 8);
-  gus_rampon (0x58);		/*
-				 * Bidirectional, Down, Loop
-				 */
+  gus_rampon (0x58);		/* Bidirectional, dow, loop */
   RESTORE_INTR (flags);
 }
 
@@ -1236,9 +1042,7 @@
     rate = 16;
   gus_ramp_rate (0, rate);
 
-  if ((target - current) / 64 == 0)	/*
-					 * Too close
-					 */
+  if ((target - current) / 64 == 0)	/* Close enough to target. */
     {
       gus_rampoff ();
       gus_voice_volume (target);
@@ -1251,9 +1055,7 @@
       if (target > (4095 - 65))
 	target = 4095 - 65;
       gus_ramp_range (current, target);
-      gus_rampon (0x00);	/*
-				 * Ramp up, once, no irq
-				 */
+      gus_rampon (0x00);	/* Ramp up, once, no IRQ */
     }
   else
     {
@@ -1261,9 +1063,7 @@
 	target = 65;
 
       gus_ramp_range (target, current);
-      gus_rampon (0x40);	/*
-				 * Ramp down, once, no irq
-				 */
+      gus_rampon (0x40);	/* Ramp down, once, no irq */
     }
   RESTORE_INTR (flags);
 }
@@ -1276,15 +1076,11 @@
 
   DISABLE_INTR (flags);
   gus_select_voice (voice);
-  status = gus_read8 (0x00);	/*
-				 * Voice status
-				 */
+  status = gus_read8 (0x00);	/* Get voice status */
   RESTORE_INTR (flags);
 
   if (status & 0x03)
-    return;			/*
-				 * Voice not started
-				 */
+    return;			/* Voice was not running */
 
   if (!(voices[voice].mode & WAVE_ENVELOPES))
     {
@@ -1298,14 +1094,10 @@
 
   DISABLE_INTR (flags);
   gus_select_voice (voice);
-  status = gus_read8 (0x0d);	/*
-				 * Ramping status
-				 */
+  status = gus_read8 (0x0d);	/* Ramping status */
   RESTORE_INTR (flags);
 
-  if (status & 0x03)		/*
-				 * Sustain phase?
-				 */
+  if (status & 0x03)		/* Sustain phase? */
     {
       compute_and_set_volume (voice, voices[voice].midi_volume, 1);
       return;
@@ -1316,16 +1108,6 @@
 
   compute_volume (voice, voices[voice].midi_volume);
 
-#if 0				/*
-				   * * * Is this really required   */
-  voices[voice].current_volume =
-    gus_read16 (0x09) >> 4;	/*
-				 * Get current volume
-				 */
-
-  voices[voice].env_phase--;
-  step_envelope (voice);
-#endif
 }
 
 static void
@@ -1344,7 +1126,8 @@
 
       if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
 	{
-	  freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+	  freq = compute_finetune (voices[voice].orig_freq, value,
+				   voices[voice].bender_range);
 	  voices[voice].current_freq = freq;
 
 	  DISABLE_INTR (flags);
@@ -1357,10 +1140,8 @@
     case CTRL_PITCH_BENDER_RANGE:
       voices[voice].bender_range = value;
       break;
-#ifdef FUTURE_VERSION
     case CTL_EXPRESSION:
       value /= 128;
-#endif
     case CTRL_EXPRESSION:
       if (volume_method == VOL_METHOD_ADAGIO)
 	{
@@ -1370,14 +1151,12 @@
 	}
       break;
 
-#ifdef FUTURE_VERSION
     case CTL_PAN:
       voices[voice].panning = (value * 2) - 128;
       break;
 
     case CTL_MAIN_VOLUME:
       value = (value * 100) / 16383;
-#endif
 
     case CTRL_MAIN_VOLUME:
       voices[voice].main_vol = value;
@@ -1385,9 +1164,7 @@
 	dynamic_volume_change (voice);
       break;
 
-    default:			/*
-				 * Ignore
-				 */
+    default:
       break;
     }
 }
@@ -1449,7 +1226,8 @@
 	  best_sample = samplep;
 	  best_delta = delta_freq;
 	}
-      if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
+      if (samples[samplep].low_note <= note_freq &&
+	  note_freq <= samples[samplep].high_note)
 	sample = samplep;
       else
 	samplep = samples[samplep].key;	/*
@@ -1462,16 +1240,10 @@
   if (sample == -1)
     {
       printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
-      return 0;			/*
-				 * Should play default patch ???
-				 */
+      return 0;			/* Should play default patch ??? */
     }
 
-  is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;	/*
-								 * 8 or 16
-								 * bit
-								 * samples
-								 */
+  is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
   voices[voice].mode = samples[sample].mode;
   voices[voice].patch_vol = samples[sample].volume;
 
@@ -1488,9 +1260,7 @@
 
   sample_map[voice] = sample;
 
-  base_note = samples[sample].base_note / 100;	/*
-						 * To avoid overflows
-						 */
+  base_note = samples[sample].base_note / 100;	/* Try to avoid overflows */
   note_freq /= 100;
 
   freq = samples[sample].base_freq * note_freq / base_note;
@@ -1502,7 +1272,8 @@
    * have to calculate the bending now.
    */
 
-  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
+  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender,
+			   voices[voice].bender_range);
   voices[voice].current_freq = freq;
 
   pan = (samples[sample].panning + voices[voice].panning) / 32;
@@ -1514,9 +1285,7 @@
 
   if (samples[sample].mode & WAVE_16_BITS)
     {
-      mode |= 0x04;		/*
-				 * 16 bits
-				 */
+      mode |= 0x04;		/* 16 bits */
       if ((sample_ptrs[sample] >> 18) !=
 	  ((sample_ptrs[sample] + samples[sample].len) >> 18))
 	printk ("GUS: Sample address error\n");
@@ -1528,9 +1297,7 @@
 
   DISABLE_INTR (flags);
   gus_select_voice (voice);
-  gus_voice_off ();		/*
-				 * It may still be running
-				 */
+  gus_voice_off ();
   gus_rampoff ();
 
   RESTORE_INTR (flags);
@@ -1548,22 +1315,17 @@
 
   if (samples[sample].mode & WAVE_LOOP_BACK)
     gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
-		    voices[voice].offset_pending, is16bits);	/* Sample
-								 * start=end */
+		    voices[voice].offset_pending, is16bits);	/* start=end */
   else
     gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
 		    is16bits);	/* Sample start=begin */
 
   if (samples[sample].mode & WAVE_LOOPING)
     {
-      mode |= 0x08;		/*
-				 * Looping on
-				 */
+      mode |= 0x08;
 
       if (samples[sample].mode & WAVE_BIDIR_LOOP)
-	mode |= 0x10;		/*
-				 * Bidirectional looping on
-				 */
+	mode |= 0x10;
 
       if (samples[sample].mode & WAVE_LOOP_BACK)
 	{
@@ -1573,36 +1335,20 @@
 	  mode |= 0x40;
 	}
 
-      gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits);	/*
-												 * Loop
-												 * start
-												 * location
-												 */
-      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits);	/*
-											 * Loop
-											 * end
-											 * location
-											 */
+      gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start,
+		      is16bits);/* Loop start location */
+      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end,
+		      is16bits);/* Loop end location */
     }
   else
     {
-      mode |= 0x20;		/*
-				 * Loop irq at the end
-				 */
-      voices[voice].loop_irq_mode = LMODE_FINISH;	/*
-							 * Ramp it down at
-							 * the * end
-							 */
+      mode |= 0x20;		/* Loop IRQ at the end */
+      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, is16bits);	/*
-											 * Loop
-											 * end
-											 * location
-											 */
+      gus_write_addr (0x02, sample_ptrs[sample],
+		      is16bits);/* Loop start location */
+      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1,
+		      is16bits);/* Loop end location */
     }
   gus_voice_freq (freq);
   gus_voice_balance (pan);
@@ -1613,9 +1359,10 @@
 }
 
 /*
- * * New guswave_start_note by Andrew J. Robinson attempts to minimize
- * clicking  * when the note playing on the voice is changed.  It uses volume
- * ramping. */
+ * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking
+ * when the note playing on the voice is changed.  It uses volume
+ * ramping.
+ */
 
 static int
 guswave_start_note (int dev, int voice, int note_num, int volume)
@@ -1656,7 +1403,7 @@
 	  DISABLE_INTR (flags);
 	}
 
-      if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
+      if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065))
 	{
 	  ret_val = guswave_start_note2 (dev, voice, note_num, volume);
 	}
@@ -1699,7 +1446,7 @@
 
   gus_initialize ();
 
-  if ((err = DMAbuf_open_dma (gus_devnum)))
+  if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
     return err;
 
   RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
@@ -1731,11 +1478,7 @@
 
   unsigned long   blk_size, blk_end, left, src_offs, target;
 
-  sizeof_patch = (long) &patch.data[0] - (long) &patch;	/*
-								 * Size of
-								 * the header
-								 * * info
-								 */
+  sizeof_patch = (long) &patch.data[0] - (long) &patch;	/* Header size */
 
   if (format != GUS_PATCH)
     {
@@ -1800,9 +1543,7 @@
 	}
     }
 
-  free_mem_ptr = (free_mem_ptr + 31) & ~31;	/*
-						 * Alignment 32 bytes
-						 */
+  free_mem_ptr = (free_mem_ptr + 31) & ~31;	/* 32 byte alignment */
 
 #define GUS_BANK_SIZE (256*1024)
 
@@ -1820,17 +1561,13 @@
       if ((free_mem_ptr / GUS_BANK_SIZE) !=
 	  ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
 	{
-	  unsigned long   tmp_mem =	/*
-					 * Align to 256K*N
-					 */
+	  unsigned long   tmp_mem =	/* Aling to 256K */
 	  ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
 
 	  if ((tmp_mem + patch.len) > gus_mem_size)
 	    return RET_ERROR (ENOSPC);
 
-	  free_mem_ptr = tmp_mem;	/*
-					 * This leaves unusable memory
-					 */
+	  free_mem_ptr = tmp_mem;	/* This leaves unusable memory */
 	}
     }
 
@@ -1863,11 +1600,9 @@
   src_offs = 0;
   target = free_mem_ptr;
 
-  while (left)			/*
-				 * Not all moved
-				 */
+  while (left)			/* Not completely transferred yet */
     {
-      blk_size = sound_buffsizes[gus_devnum];
+      blk_size = audio_devs[gus_devnum]->buffsize;
       if (blk_size > left)
 	blk_size = left;
 
@@ -1877,9 +1612,7 @@
       blk_end = target + blk_size;
 
       if ((target >> 18) != (blk_end >> 18))
-	{			/*
-				 * Have to split the block
-				 */
+	{			/* Split the block */
 
 	  blk_end &= ~(256 * 1024 - 1);
 	  blk_size = blk_end - target;
@@ -1899,14 +1632,11 @@
 	    if (patch.mode & WAVE_UNSIGNED)
 
 	      if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
-		data ^= 0x80;	/*
-				 * Convert to signed
-				 */
+		data ^= 0x80;	/* Convert to signed */
 	    gus_poke (target + i, data);
 	  }
       }
-#else /*
-         * * * GUS_NO_DMA   */
+#else /* GUS_NO_DMA */
       {
 	unsigned long   address, hold_address;
 	unsigned char   dma_command;
@@ -1916,15 +1646,14 @@
 	 * OK, move now. First in and then out.
 	 */
 
-	COPY_FROM_USER (snd_raw_buf[gus_devnum][0],
+	COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0],
 			addr, sizeof_patch + src_offs,
 			blk_size);
 
 	DISABLE_INTR (flags);	/******** INTERRUPTS DISABLED NOW ********/
-	gus_write8 (0x41, 0);	/*
-				 * Disable GF1 DMA
-				 */
-	DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0],
+	gus_write8 (0x41, 0);	/* Disable GF1 DMA */
+	DMAbuf_start_dma (gus_devnum,
+			  audio_devs[gus_devnum]->dmap->raw_buf_phys[0],
 			  blk_size, DMA_MODE_WRITE);
 
 	/*
@@ -1933,7 +1662,7 @@
 
 	address = target;
 
-	if (sound_dsp_dmachan[gus_devnum] > 3)
+	if (audio_devs[gus_devnum]->dmachan > 3)
 	  {
 	    hold_address = address;
 	    address = address >> 1;
@@ -1941,33 +1670,21 @@
 	    address |= (hold_address & 0x000c0000L);
 	  }
 
-	gus_write16 (0x42, (address >> 4) & 0xffff);	/*
-							 * DRAM DMA address
-							 */
+	gus_write16 (0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
 
 	/*
 	 * Start the DMA transfer
 	 */
 
-	dma_command = 0x21;	/*
-				 * IRQ enable, DMA start
-				 */
+	dma_command = 0x21;	/* IRQ enable, DMA start */
 	if (patch.mode & WAVE_UNSIGNED)
-	  dma_command |= 0x80;	/*
-				 * Invert MSB
-				 */
+	  dma_command |= 0x80;	/* Invert MSB */
 	if (patch.mode & WAVE_16_BITS)
-	  dma_command |= 0x40;	/*
-				 * 16 bit _DATA_
-				 */
-	if (sound_dsp_dmachan[gus_devnum] > 3)
-	  dma_command |= 0x04;	/*
-				 * 16 bit DMA channel
-				 */
+	  dma_command |= 0x40;	/* 16 bit _DATA_ */
+	if (audio_devs[gus_devnum]->dmachan > 3)
+	  dma_command |= 0x04;	/* 16 bit DMA _channel_ */
 
-	gus_write8 (0x41, dma_command);	/*
-						 * Let's go luteet (=bugs)
-						 */
+	gus_write8 (0x41, dma_command);	/* Lets bo luteet (=bugs) */
 
 	/*
 	 * Sleep here until the DRAM DMA done interrupt is served
@@ -1979,8 +1696,7 @@
 	  printk ("GUS: DMA Transfer timed out\n");
 	RESTORE_INTR (flags);
       }
-#endif /*
-          * * * GUS_NO_DMA   */
+#endif /* GUS_NO_DMA */
 
       /*
        * Now the next part
@@ -1990,9 +1706,7 @@
       src_offs += blk_size;
       target += blk_size;
 
-      gus_write8 (0x41, 0);	/*
-				 * Stop DMA
-				 */
+      gus_write8 (0x41, 0);	/* Stop DMA */
     }
 
   free_mem_ptr += patch.len;
@@ -2037,9 +1751,7 @@
     case _GUS_VOICEON:
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;		/*
-				 * Disable intr
-				 */
+      p1 &= ~0x20;		/* Don't allow interrupts */
       gus_voice_on (p1);
       RESTORE_INTR (flags);
       break;
@@ -2058,9 +1770,7 @@
     case _GUS_VOICEMODE:
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;		/*
-				 * Disable intr
-				 */
+      p1 &= ~0x20;		/* Don't allow interrupts */
       gus_voice_mode (p1);
       RESTORE_INTR (flags);
       break;
@@ -2086,18 +1796,14 @@
       RESTORE_INTR (flags);
       break;
 
-    case _GUS_VOICEVOL2:	/*
-				 * Just update the voice value
-				 */
+    case _GUS_VOICEVOL2:	/* Just update the software voice level */
       voices[voice].initial_volume =
 	voices[voice].current_volume = p1;
       break;
 
     case _GUS_RAMPRANGE:
       if (voices[voice].mode & WAVE_ENVELOPES)
-	break;			/*
-				 * NO-NO
-				 */
+	break;			/* NO-NO */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
       gus_ramp_range (p1, p2);
@@ -2106,9 +1812,7 @@
 
     case _GUS_RAMPRATE:
       if (voices[voice].mode & WAVE_ENVELOPES)
-	break;			/*
-				 * NO-NO
-				 */
+	break;			/* NJET-NJET */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
       gus_ramp_rate (p1, p2);
@@ -2117,37 +1821,27 @@
 
     case _GUS_RAMPMODE:
       if (voices[voice].mode & WAVE_ENVELOPES)
-	break;			/*
-				 * NO-NO
-				 */
+	break;			/* NO-NO */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;		/*
-				 * Disable intr
-				 */
+      p1 &= ~0x20;		/* Don't allow interrupts */
       gus_ramp_mode (p1);
       RESTORE_INTR (flags);
       break;
 
     case _GUS_RAMPON:
       if (voices[voice].mode & WAVE_ENVELOPES)
-	break;			/*
-				 * NO-NO
-				 */
+	break;			/* EI-EI */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;		/*
-				 * Disable intr
-				 */
+      p1 &= ~0x20;		/* Don't allow interrupts */
       gus_rampon (p1);
       RESTORE_INTR (flags);
       break;
 
     case _GUS_RAMPOFF:
       if (voices[voice].mode & WAVE_ENVELOPES)
-	break;			/*
-				 * NO-NO
-				 */
+	break;			/* NEJ-NEJ */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
       gus_rampoff ();
@@ -2244,7 +1938,7 @@
       return IOCTL_OUT (arg, gus_sampling_channels);
       break;
 
-    case SNDCTL_DSP_SAMPLESIZE:
+    case SNDCTL_DSP_SETFMT:
       if (local)
 	return gus_sampling_set_bits (arg);
       return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg)));
@@ -2255,9 +1949,7 @@
 	return gus_sampling_bits;
       return IOCTL_OUT (arg, gus_sampling_bits);
 
-    case SOUND_PCM_WRITE_FILTER:	/*
-					 * NOT YET IMPLEMENTED
-					 */
+    case SOUND_PCM_WRITE_FILTER:	/* NOT POSSIBLE */
       return IOCTL_OUT (arg, RET_ERROR (EINVAL));
       break;
 
@@ -2297,6 +1989,7 @@
   gus_select_max_voices (14);
 
   pcm_active = 0;
+  dma_active = 0;
   pcm_opened = 1;
   if (mode & OPEN_READ)
     {
@@ -2356,24 +2049,18 @@
   for (chn = 0; chn < gus_sampling_channels; chn++)
     {
       mode[chn] = 0x00;
-      ramp_mode[chn] = 0x03;	/*
-				 * Ramping and rollover off
-				 */
+      ramp_mode[chn] = 0x03;	/* Ramping and rollover off */
 
       if (chn == 0)
 	{
-	  mode[chn] |= 0x20;	/*
-				 * Loop irq
-				 */
+	  mode[chn] |= 0x20;	/* Loop IRQ */
 	  voices[chn].loop_irq_mode = LMODE_PCM;
 	}
 
       if (gus_sampling_bits != 8)
 	{
 	  is16bits = 1;
-	  mode[chn] |= 0x04;	/*
-				 * 16 bit data
-				 */
+	  mode[chn] |= 0x04;	/* 16 bit data */
 	}
       else
 	is16bits = 0;
@@ -2381,23 +2068,15 @@
       dram_loc = this_one * pcm_bsize;
       dram_loc += chn * pcm_banksize;
 
-      if (this_one == (pcm_nblk - 1))	/*
-					 * Last of the DRAM buffers
-					 */
+      if (this_one == (pcm_nblk - 1))	/* Last fragment of the DRAM buffer */
 	{
-	  mode[chn] |= 0x08;	/*
-				 * Enable loop
-				 */
-	  ramp_mode[chn] = 0x03;/*
-					 * Disable rollover
-					 */
+	  mode[chn] |= 0x08;	/* Enable loop */
+	  ramp_mode[chn] = 0x03;/* Disable rollover bit */
 	}
       else
 	{
 	  if (chn == 0)
-	    ramp_mode[chn] = 0x04;	/*
-					 * Enable rollover bit
-					 */
+	    ramp_mode[chn] = 0x04;	/* Enable rollover bit */
 	}
 
       DISABLE_INTR (flags);
@@ -2405,21 +2084,13 @@
       gus_voice_freq (speed);
 
       if (gus_sampling_channels == 1)
-	gus_voice_balance (7);	/*
-				 * mono
-				 */
+	gus_voice_balance (7);	/* mono */
       else if (chn == 0)
-	gus_voice_balance (0);	/*
-				 * left
-				 */
+	gus_voice_balance (0);	/* left */
       else
-	gus_voice_balance (15);	/*
-				 * right
-				 */
+	gus_voice_balance (15);	/* right */
 
-      if (!pcm_active)		/*
-				 * Voice not started yet
-				 */
+      if (!pcm_active)		/* Playback not already active */
 	{
 	  /*
 	   * The playback was not started yet (or there has been a pause).
@@ -2428,67 +2099,42 @@
 	   * the normal loop with irq.
 	   */
 
-	  gus_voice_off ();	/*
-				 * It could already be running
-				 */
+	  gus_voice_off ();
 	  gus_rampoff ();
 	  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
-								 * location
-								 */
+	  gus_write_addr (0x0a, dram_loc, is16bits);	/* Starting position */
+	  gus_write_addr (0x02, chn * pcm_banksize, is16bits);	/* Loop start */
 
 	  if (chn != 0)
 	    gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
-			    is16bits);	/*
-					 * Loop end location
-					 */
+			    is16bits);	/* Loop end location */
 	}
 
       if (chn == 0)
-	gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits);	/*
-										 * Loop
-										 * end
-										 * location
-										 */
+	gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
+			is16bits);	/* Loop end location */
       else
-	mode[chn] |= 0x08;	/*
-				 * Enable loop
-				 */
+	mode[chn] |= 0x08;	/* Enable looping */
 
       if (pcm_datasize[this_one] != pcm_bsize)
 	{
 	  /*
-	   * Incomplete block. Possibly the last one.
+	   * Incompletely filled block. Possibly the last one.
 	   */
 	  if (chn == 0)
 	    {
-	      mode[chn] &= ~0x08;	/*
-					 * Disable loop
-					 */
-	      mode[chn] |= 0x20;/*
-					 * Enable loop IRQ
-					 */
+	      mode[chn] &= ~0x08;	/* Disable looping */
+	      mode[chn] |= 0x20;/* Enable IRQ at the end */
 	      voices[0].loop_irq_mode = LMODE_PCM_STOP;
-	      ramp_mode[chn] = 0x03;	/*
-					 * No rollover bit
-					 */
+	      ramp_mode[chn] = 0x03;	/* No rollover bit */
 	    }
 	  else
 	    {
-	      gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits);	/*
-											 * Loop
-											 * end
-											 * location
-											 */
-	      mode[chn] &= ~0x08;	/*
-					 * Disable loop
-					 */
+	      gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
+			      is16bits);	/* Loop end location */
+	      mode[chn] &= ~0x08;	/* Disable looping */
 	    }
 	}
 
@@ -2542,15 +2188,13 @@
   else
     this_one = pcm_current_block;
 
-  gus_write8 (0x41, 0);		/*
-				 * Disable GF1 DMA
-				 */
+  gus_write8 (0x41, 0);		/* Disable GF1 DMA */
   DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
 
   address = this_one * pcm_bsize;
   address += chn * pcm_banksize;
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     {
       hold_address = address;
       address = address >> 1;
@@ -2558,49 +2202,40 @@
       address |= (hold_address & 0x000c0000L);
     }
 
-  gus_write16 (0x42, (address >> 4) & 0xffff);	/*
-						 * DRAM DMA address
-						 */
+  gus_write16 (0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
 
-  dma_command = 0x21;		/*
-				 * IRQ enable, DMA start
-				 */
+  dma_command = 0x21;		/* IRQ enable, DMA start */
 
   if (gus_sampling_bits != 8)
-    dma_command |= 0x40;	/*
-				 * 16 bit _DATA_
-				 */
+    dma_command |= 0x40;	/* 16 bit _DATA_ */
   else
-    dma_command |= 0x80;	/*
-				 * Invert MSB
-				 */
+    dma_command |= 0x80;	/* Invert MSB */
 
-  if (sound_dsp_dmachan[dev] > 3)
-    dma_command |= 0x04;	/*
-				 * 16 bit DMA channel
-				 */
+  if (audio_devs[dev]->dmachan > 3)
+    dma_command |= 0x04;	/* 16 bit DMA channel */
 
-  gus_write8 (0x41, dma_command);	/*
-					 * Kick on
-					 */
+  gus_write8 (0x41, dma_command);	/* Kickstart */
 
-  if (chn == (gus_sampling_channels - 1))	/*
-						 * Last channel
-						 */
+  if (chn == (gus_sampling_channels - 1))	/* Last channel */
     {
       /*
        * Last (right or mono) channel data
        */
+      dma_active = 1;		/* DMA started. There is a unacknowledged buffer */
       active_device = GUS_DEV_PCM_DONE;
-      if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))
+      if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize))
 	{
 	  play_next_pcm_block ();
 	}
     }
-  else				/*
-				   * * * Left channel data. The right channel
-				   * is * * * transferred after DMA interrupt   */
-    active_device = GUS_DEV_PCM_CONTINUE;
+  else
+    {
+      /*
+	 * Left channel data. The right channel
+	 * is transferred after DMA interrupt
+	 */
+      active_device = GUS_DEV_PCM_CONTINUE;
+    }
 
   RESTORE_INTR (flags);
 }
@@ -2627,21 +2262,13 @@
 
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 
-  mode = 0xa0;			/*
-				 * DMA IRQ enable, invert MSB
-				 */
+  mode = 0xa0;			/* DMA IRQ enabled, invert MSB */
 
-  if (sound_dsp_dmachan[dev] > 3)
-    mode |= 0x04;		/*
-				 * 16 bit DMA channel
-				 */
+  if (audio_devs[dev]->dmachan > 3)
+    mode |= 0x04;		/* 16 bit DMA channel */
   if (gus_sampling_channels > 1)
-    mode |= 0x02;		/*
-				 * Stereo
-				 */
-  mode |= 0x01;			/*
-				 * DMA enable
-				 */
+    mode |= 0x02;		/* Stereo */
+  mode |= 0x01;			/* DMA enable */
 
   gus_write8 (0x49, mode);
 
@@ -2655,9 +2282,7 @@
 
   rate = (9878400 / (gus_sampling_speed + 2)) / 16;
 
-  gus_write8 (0x48, rate & 0xff);	/*
-					 * Set sampling frequency
-					 */
+  gus_write8 (0x48, rate & 0xff);	/* Set sampling rate */
 
   if (gus_sampling_bits != 8)
     {
@@ -2700,9 +2325,9 @@
 }
 
 static int
-gus_has_output_drained (int dev)
+gus_local_qlen (int dev)
 {
-  return !pcm_qlen;
+  return pcm_qlen;
 }
 
 static void
@@ -2760,6 +2385,8 @@
 {
   "Gravis UltraSound",
   NEEDS_RESTART,
+  AFMT_U8 | AFMT_S16_LE,
+  NULL,
   gus_sampling_open,
   gus_sampling_close,
   gus_sampling_output_block,
@@ -2769,11 +2396,10 @@
   gus_sampling_prepare_for_output,
   gus_sampling_reset,
   gus_sampling_reset,
-  gus_has_output_drained,
+  gus_local_qlen,
   gus_copy_from_user
 };
 
-#ifdef FUTURE_VERSION
 static void
 guswave_bender (int dev, int voice, int value)
 {
@@ -2781,7 +2407,8 @@
   unsigned long   flags;
 
   voices[voice].bender = value - 8192;
-  freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+  freq = compute_finetune (voices[voice].orig_freq, value,
+			   voices[voice].bender_range);
   voices[voice].current_freq = freq;
 
   DISABLE_INTR (flags);
@@ -2790,8 +2417,6 @@
   RESTORE_INTR (flags);
 }
 
-#endif
-
 static int
 guswave_patchmgr (int dev, struct patmgr_info *rec)
 {
@@ -2821,9 +2446,7 @@
 	  while (ptr >= 0 && ptr < free_sample)
 	    {
 	      rec->data.data8[i]++;
-	      ptr = samples[ptr].key;	/*
-					 * Follow link
-					 */
+	      ptr = samples[ptr].key;	/* Follow link */
 	    }
 	}
       return 0;
@@ -2838,9 +2461,7 @@
 	while (ptr >= 0 && ptr < free_sample)
 	  {
 	    rec->data.data32[n++] = ptr;
-	    ptr = samples[ptr].key;	/*
-					 * Follow link
-					 */
+	    ptr = samples[ptr].key;	/* Follow link */
 	  }
       }
       rec->parm1 = n;
@@ -2860,12 +2481,8 @@
 
 	pat = (struct patch_info *) rec->data.data8;
 
-	pat->key = GUS_PATCH;	/*
-				 * Restore patch type
-				 */
-	rec->parm1 = sample_ptrs[ptr];	/*
-					 * DRAM address
-					 */
+	pat->key = GUS_PATCH;	/* Restore patch type */
+	rec->parm1 = sample_ptrs[ptr];	/* DRAM location */
 	rec->parm2 = sizeof (struct patch_info);
       }
       return 0;
@@ -2881,14 +2498,10 @@
 
 	pat = (struct patch_info *) rec->data.data8;
 
-	if (pat->len > samples[ptr].len)	/*
-						 * Cannot expand sample
-						 */
+	if (pat->len > samples[ptr].len)	/* Cannot expand sample */
 	  return RET_ERROR (EINVAL);
 
-	pat->key = samples[ptr].key;	/*
-					 * Ensure the link is correct
-					 */
+	pat->key = samples[ptr].key;	/* Ensure the link is correct */
 
 	memcpy ((char *) &samples[ptr], rec->data.data8,
 		sizeof (struct patch_info));
@@ -2898,9 +2511,7 @@
       return 0;
       break;
 
-    case PM_READ_PATCH:	/*
-				 * Returns a block of wave data from the DRAM
-				 */
+    case PM_READ_PATCH:	/* Returns a block of wave data from the DRAM */
       {
 	int             sample = rec->parm1;
 	int             n;
@@ -2911,13 +2522,9 @@
 	  return RET_ERROR (EINVAL);
 
 	if (offs < 0 || offs >= samples[sample].len)
-	  return RET_ERROR (EINVAL);	/*
-					 * Invalid offset
-					 */
+	  return RET_ERROR (EINVAL);	/* Invalid offset */
 
-	n = samples[sample].len - offs;	/*
-						 * Nr of bytes left
-						 */
+	n = samples[sample].len - offs;	/* Num of bytes left */
 
 	if (l > n)
 	  l = n;
@@ -2993,12 +2600,49 @@
     }
 }
 
+static int
+guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
+{
+  int             i, p;
+
+  p = alloc->ptr;
+  /*
+ * First look for a completely stopped voice
+ */
+
+  for (i = 0; i < alloc->max_voice; i++)
+    {
+      if (alloc->map[p] == 0)
+	{
+	  alloc->ptr = p;
+	  return p;
+	}
+      p = (p + 1) % alloc->max_voice;
+    }
+
+  /*
+ * Then look for a releasing voice
+ */
+
+  for (i = 0; i < alloc->max_voice; i++)
+    {
+      if (alloc->map[p] == 0xffff)
+	{
+	  alloc->ptr = p;
+	  return p;
+	}
+      p = (p + 1) % alloc->max_voice;
+    }
+  printk ("GUS: Out of free voices\n");
+
+  alloc->ptr = p;
+  return p;
+}
+
 static struct synth_operations guswave_operations =
 {
   &gus_info,
-#ifdef FUTURE_VERSION
   0,
-#endif
   SYNTH_TYPE_SAMPLE,
   SAMPLE_TYPE_GUS,
   guswave_open,
@@ -3015,9 +2659,8 @@
   guswave_panning,
   guswave_volume_method,
   guswave_patchmgr,
-#ifdef FUTURE_VERSION
-  guswave_bender
-#endif
+  guswave_bender,
+  guswave_alloc
 };
 
 static void
@@ -3125,10 +2768,7 @@
 
 	      if (active_device == GUS_DEV_WAVE)
 		for (voice = 0; voice < nr_voices; voice++)
-		  dynamic_volume_change (voice);	/*
-							 * Apply the new
-							 * volume
-							 */
+		  dynamic_volume_change (voice);	/* Apply the new vol */
 
 	      return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
 	    }
@@ -3224,7 +2864,7 @@
   val = INB (gus_base + 0x0f);
   RESTORE_INTR (flags);
 
-  if (val != 0xff && (val & 0x06))	/* Should be 0x02? */
+  if (val != 0xff && (val & 0x06))	/* Should be 0x02?? */
     {
       /*
 	 * It has the digital ASIC so the card is at least v3.4.
@@ -3258,6 +2898,31 @@
 	  model_num = "MAX";
 	  gus_type = 0x40;
 	  mixer_type = CS4231;
+#ifndef EXCLUDE_GUSMAX
+	  {
+	    unsigned char   max_config = 0x40;	/* Codec enable */
+
+	    if (dma > 3)
+	      max_config |= 0x30;	/* 16 bit playback and capture DMAs */
+
+	    max_config |= (gus_base >> 4) & 0x0f;	/* Extract the X from 2X0 */
+
+	    OUTB (max_config, gus_base + 0x106);	/* UltraMax control */
+	  }
+
+	  if (ad1848_detect (gus_base + 0x10c))
+	    {
+	      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,
+			   -irq,
+			   dma,
+			   dma);
+	    }
+	  else
+	    printk ("[Where's the CS4231?]");
+#endif
 	}
     }
   else
@@ -3295,7 +2960,10 @@
   if (num_synths >= MAX_SYNTH_DEV)
     printk ("GUS Error: Too many synthesizers\n");
   else
-    synth_devs[num_synths++] = &guswave_operations;
+    {
+      voice_alloc = &guswave_operations.alloc;
+      synth_devs[num_synths++] = &guswave_operations;
+    }
 
   PERMANENT_MALLOC (struct patch_info *, samples,
 	                   (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
@@ -3304,13 +2972,12 @@
 
   gus_initialize ();
 
-  if (num_dspdevs < MAX_DSP_DEV)
+  if (num_audiodevs < MAX_AUDIO_DEV)
     {
-      dsp_devs[gus_devnum = num_dspdevs++] = &gus_sampling_operations;
-      sound_dsp_dmachan[gus_devnum] = dma;
-      sound_buffcounts[gus_devnum] = 1;
-      sound_buffsizes[gus_devnum] = DSP_BUFFSIZE;
-      sound_dma_automode[gus_devnum] = 0;
+      audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations;
+      audio_devs[gus_devnum]->dmachan = dma;
+      audio_devs[gus_devnum]->buffcount = 1;
+      audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
     }
   else
     printk ("GUS: Too many PCM devices available\n");
@@ -3322,11 +2989,12 @@
   switch (mixer_type)
     {
     case ICS2101:
-      gus_line_vol=gus_mic_vol=gus_wave_volume = gus_pcm_volume = 100;
+      gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+      gus_wave_volume = 90;
       return ics2101_mixer_init (mem_start);
 
     case CS4231:
-      /* Available soon */
+      /* Initialized elsewhere (ad1848.c) */
     default:
       return gus_default_mixer_init (mem_start);
     }
@@ -3361,7 +3029,7 @@
 				 * Final loop finished, shoot volume down
 				 */
 
-      if ((gus_read16 (0x09) >> 4) < 100)	/*
+      if ((int) (gus_read16 (0x09) >> 4) < 100)	/*
 						 * Get current volume
 						 */
 	{
@@ -3381,12 +3049,11 @@
       break;
 
     case LMODE_PCM_STOP:
-      pcm_active = 0;		/*
-				 * Requires extensive processing
-				 */
+      pcm_active = 0;		/* Signal to the play_next_pcm_block routine */
     case LMODE_PCM:
       {
 	int             orig_qlen = pcm_qlen;
+	int             flag;	/* 0 or 2 */
 
 	pcm_qlen--;
 	pcm_head = (pcm_head + 1) % pcm_nblk;
@@ -3395,18 +3062,27 @@
 	    play_next_pcm_block ();
 	  }
 	else
-	  {			/*
-				 * Out of data. Just stop the voice
-				 */
+	  {			/* Underrun. Just stop the voice */
 	    gus_voice_off ();
 	    gus_rampoff ();
 	    pcm_active = 0;
 	  }
 
-	if (orig_qlen == pcm_nblk)
+	/*
+ * If the queue was full before this interrupt, the DMA transfer was
+ * suspended. Let it continue now.
+ */
+	if (dma_active)
 	  {
-	    DMAbuf_outputintr (gus_devnum, 0);
+	    if (pcm_qlen == 0)
+	      flag = 1;		/* Underflow */
+	    else
+	      flag = 0;
+	    dma_active = 0;
 	  }
+	else
+	  flag = 2;		/* Just notify the dmabuf.c */
+	DMAbuf_outputintr (gus_devnum, flag);
       }
       break;
 
@@ -3456,7 +3132,9 @@
       guswave_start_note2 (voices[voice].dev_pending, voice,
 		  voices[voice].note_pending, voices[voice].volume_pending);
       if (voices[voice].kill_pending)
-	guswave_kill_note (voices[voice].dev_pending, voice, 0);
+	guswave_kill_note (voices[voice].dev_pending, voice,
+			   voices[voice].note_pending, 0);
+
       if (voices[voice].sample_pending >= 0)
 	{
 	  guswave_set_instr (voices[voice].dev_pending, voice,
@@ -3495,7 +3173,7 @@
       if (!(src & 0x80))	/*
 				 * Wave IRQ pending
 				 */
-	if (!(wave_ignore & voice_bit) && voice < nr_voices)	/*
+	if (!(wave_ignore & voice_bit) && (int) voice < nr_voices)	/*
 								 * Not done
 								 * yet
 								 */
@@ -3507,7 +3185,7 @@
       if (!(src & 0x40))	/*
 				 * Volume IRQ pending
 				 */
-	if (!(volume_ignore & voice_bit) && voice < nr_voices)	/*
+	if (!(volume_ignore & voice_bit) && (int) voice < nr_voices)	/*
 								 * Not done
 								 * yet
 								 */
@@ -3523,12 +3201,8 @@
 {
   unsigned char   status;
 
-  status = gus_look8 (0x41);	/*
-				 * Get DMA IRQ Status
-				 */
-  if (status & 0x40)		/*
-				 * DMA Irq pending
-				 */
+  status = gus_look8 (0x41);	/* Get DMA IRQ Status */
+  if (status & 0x40)		/* DMA interrupt pending */
     switch (active_device)
       {
       case GUS_DEV_WAVE:
@@ -3536,16 +3210,21 @@
 	  WAKE_UP (dram_sleeper, dram_sleep_flag);
 	break;
 
-      case GUS_DEV_PCM_CONTINUE:
+      case GUS_DEV_PCM_CONTINUE:	/* Left channel data transferred */
 	gus_transfer_output_block (pcm_current_dev, pcm_current_buf,
 				   pcm_current_count,
 				   pcm_current_intrflag, 1);
 	break;
 
-      case GUS_DEV_PCM_DONE:
+      case GUS_DEV_PCM_DONE:	/* Right or mono channel data transferred */
 	if (pcm_qlen < pcm_nblk)
 	  {
-	    DMAbuf_outputintr (gus_devnum, pcm_qlen == 0);
+	    int             flag = (1 - dma_active) * 2;	/* 0 or 2 */
+
+	    if (pcm_qlen == 0)
+	      flag = 1;		/* Underrun */
+	    dma_active = 0;
+	    DMAbuf_outputintr (gus_devnum, flag);
 	  }
 	break;
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c
--- v1.1.30/linux/drivers/sound/ics2101.c	Sun May  1 12:12:33 1994
+++ linux/drivers/sound/ics2101.c	Mon Jul 18 09:50:55 1994
@@ -44,34 +44,36 @@
 static int      right_fix[ICS_MIXDEVS] =
 {2, 2, 2, 1, 2, 1};
 
-static int 
-scale_vol(int vol)
+static int
+scale_vol (int vol)
 {
 #if 1
-/*
+  /*
  *	Experimental volume scaling by Risto Kankkunen.
  *	This should give smoother volume response than just
  *	a plain multiplication.
  */
-        int e;
+  int             e;
 
-        if (vol < 0)
-                vol = 0;
-        if (vol > 100)
-                vol = 100;
-        vol = (31 * vol + 50) / 100;
-        e = 0;
-        if (vol) {
-                while (vol < 16) {
-                        vol <<= 1;
-                        e--;
-                }
-                vol -= 16;
-                e += 7;
-        }
-        return ((e << 4) + vol);
+  if (vol < 0)
+    vol = 0;
+  if (vol > 100)
+    vol = 100;
+  vol = (31 * vol + 50) / 100;
+  e = 0;
+  if (vol)
+    {
+      while (vol < 16)
+	{
+	  vol <<= 1;
+	  e--;
+	}
+      vol -= 16;
+      e += 7;
+    }
+  return ((e << 4) + vol);
 #else
-  return ((vol*127)+50)/100;
+  return ((vol * 127) + 50) / 100;
 #endif
 }
 
@@ -83,7 +85,7 @@
   int             ctrl_addr = dev << 3;
   int             attn_addr = dev << 3;
 
-  vol=scale_vol(vol);
+  vol = scale_vol (vol);
 
   if (chn == CHN_LEFT)
     {
@@ -180,7 +182,7 @@
 
 	  case SOUND_MIXER_STEREODEVS:
 	    return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
-			      SOUND_MASK_SYNTH | SOUND_MASK_VOLUME|
+			      SOUND_MASK_SYNTH | SOUND_MASK_VOLUME |
 			      SOUND_MASK_MIC);
 	    break;
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/midi_ctrl.h linux/drivers/sound/midi_ctrl.h
--- v1.1.30/linux/drivers/sound/midi_ctrl.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/midi_ctrl.h	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,22 @@
+static unsigned char ctrl_def_values[128] =
+{
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*   0 to   7 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*   8 to  15 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  16 to  23 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  24 to  31 */
+
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  32 to  39 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  40 to  47 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  48 to  55 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  56 to  63 */
+	
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  64 to  71 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  72 to  79 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  80 to  87 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  88 to  95 */
+
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  96 to 103 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/* 104 to 111 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/* 112 to 119 */
+	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/* 120 to 127 */
+};
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c
--- v1.1.30/linux/drivers/sound/midi_synth.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/midi_synth.c	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,474 @@
+/*
+ * sound/midi_synth.c
+ *
+ * High level midi sequencer manager for dumb MIDI interfaces.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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 "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+
+#define _MIDI_SYNTH_C_
+
+DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
+
+#include "midi_synth.h"
+
+static int      midi2synth[MAX_MIDI_DEV];
+static unsigned char prev_out_status[MAX_MIDI_DEV];
+
+static void
+midi_outc (int midi_dev, int data)
+{
+  int             timeout;
+
+  for (timeout = 0; timeout < 32000; timeout++)
+    if (midi_devs[midi_dev]->putc (midi_dev, (unsigned char) (data & 0xff)))
+      {
+	if (data & 0x80)	/*
+				 * Status byte
+				 */
+	  prev_out_status[midi_dev] =
+	    (unsigned char) (data & 0xff);	/*
+						 * Store for running status
+						 */
+	return;			/*
+				 * Mission complete
+				 */
+      }
+
+  /*
+   * Sorry! No space on buffers.
+   */
+  printk ("Midi send timed out\n");
+}
+
+static int
+prefix_cmd (int midi_dev, unsigned char status)
+{
+  if (midi_devs[midi_dev]->prefix_cmd == NULL)
+    return 1;
+
+  return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
+}
+
+static void
+midi_synth_input (int dev, unsigned char data)
+{
+  int             orig_dev;
+
+  if (dev < 0 || dev > num_synths)
+    return;
+
+  if (data == 0xfe)		/* Ignore active sensing */
+    return;
+
+  orig_dev = midi2synth[dev];
+
+}
+
+static void
+midi_synth_output (int dev)
+{
+  /*
+   * Currently NOP
+   */
+}
+
+int
+midi_synth_ioctl (int dev,
+		  unsigned int cmd, unsigned int arg)
+{
+  /*
+   * int orig_dev = synth_devs[dev]->midi_dev;
+   */
+
+  switch (cmd)
+    {
+
+    case SNDCTL_SYNTH_INFO:
+      IOCTL_TO_USER ((char *) arg, 0, synth_devs[dev]->info,
+		     sizeof (struct synth_info));
+
+      return 0;
+      break;
+
+    case SNDCTL_SYNTH_MEMAVL:
+      return 0x7fffffff;
+      break;
+
+    default:
+      return RET_ERROR (EINVAL);
+    }
+}
+
+int
+midi_synth_kill_note (int dev, int channel, int note, int velocity)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             msg, chn;
+
+  if (note < 0 || note > 127)
+    return 0;
+  if (channel < 0 || channel > 15)
+    return 0;
+  if (velocity < 0)
+    velocity = 0;
+  if (velocity > 127)
+    velocity = 127;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80))
+    {				/*
+				 * Use running status
+				 */
+      if (!prefix_cmd (orig_dev, note))
+	return 0;
+
+      midi_outc (orig_dev, note);
+
+      if (msg == 0x90)		/*
+				 * Running status = Note on
+				 */
+	midi_outc (orig_dev, 0);/*
+					 * Note on with velocity 0 == note
+					 * off
+					 */
+      else
+	midi_outc (orig_dev, velocity);
+    }
+  else
+    {
+      if (velocity == 64)
+	{
+	  if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
+	    return 0;
+	  midi_outc (orig_dev, 0x90 | (channel & 0x0f));	/*
+								 * Note on
+								 */
+	  midi_outc (orig_dev, note);
+	  midi_outc (orig_dev, 0);	/*
+					 * Zero G
+					 */
+	}
+      else
+	{
+	  if (!prefix_cmd (orig_dev, 0x80 | (channel & 0x0f)))
+	    return 0;
+	  midi_outc (orig_dev, 0x80 | (channel & 0x0f));	/*
+								 * Note off
+								 */
+	  midi_outc (orig_dev, note);
+	  midi_outc (orig_dev, velocity);
+	}
+    }
+
+  return 0;
+}
+
+int
+midi_synth_set_instr (int dev, int channel, int instr_no)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+
+  if (instr_no < 0 || instr_no > 127)
+    return 0;
+  if (channel < 0 || channel > 15)
+    return 0;
+
+  if (!prefix_cmd (orig_dev, 0xc0 | (channel & 0x0f)))
+    return 0;
+  midi_outc (orig_dev, 0xc0 | (channel & 0x0f));	/*
+							 * Program change
+							 */
+  midi_outc (orig_dev, instr_no);
+
+  return 0;
+}
+
+int
+midi_synth_start_note (int dev, int channel, int note, int velocity)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             msg, chn;
+
+  if (note < 0 || note > 127)
+    return 0;
+  if (channel < 0 || channel > 15)
+    return 0;
+  if (velocity < 0)
+    velocity = 0;
+  if (velocity > 127)
+    velocity = 127;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (chn == channel && msg == 0x90)
+    {				/*
+				 * Use running status
+				 */
+      if (!prefix_cmd (orig_dev, note))
+	return 0;
+      midi_outc (orig_dev, note);
+      midi_outc (orig_dev, velocity);
+    }
+  else
+    {
+      if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
+	return 0;
+      midi_outc (orig_dev, 0x90 | (channel & 0x0f));	/*
+							 * Note on
+							 */
+      midi_outc (orig_dev, note);
+      midi_outc (orig_dev, velocity);
+    }
+  return 0;
+}
+
+void
+midi_synth_reset (int dev)
+{
+}
+
+int
+midi_synth_open (int dev, int mode)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             err;
+
+  if (orig_dev < 0 || orig_dev > num_midis)
+    return RET_ERROR (ENXIO);
+
+  midi2synth[orig_dev] = dev;
+  prev_out_status[orig_dev] = 0;
+
+  if ((err = midi_devs[orig_dev]->open (orig_dev, mode,
+				  midi_synth_input, midi_synth_output)) < 0)
+    return err;
+
+  return 1;
+}
+
+void
+midi_synth_close (int dev)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+
+  /*
+ * Shut up the synths by sending just single active sensing message.
+ */
+  midi_devs[orig_dev]->putc (orig_dev, 0xfe);
+
+  midi_devs[orig_dev]->close (orig_dev);
+}
+
+void
+midi_synth_hw_control (int dev, unsigned char *event)
+{
+}
+
+int
+midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
+		       int offs, int count, int pmgr_flag)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+
+  struct sysex_info sysex;
+  int             i;
+  unsigned long   left, src_offs, eox_seen = 0;
+  int             first_byte = 1;
+
+  if (!prefix_cmd (orig_dev, 0xf0))
+    return 0;
+
+  if (format != SYSEX_PATCH)
+    {
+      printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format);
+      return RET_ERROR (EINVAL);
+    }
+
+  if (count < sizeof (struct sysex_info))
+    {
+      printk ("MIDI Error: Patch header too short\n");
+      return RET_ERROR (EINVAL);
+    }
+
+  count -= sizeof (struct sysex_info);
+
+  /*
+   * Copy the header from user space but ignore the first bytes which have
+   * been transferred already.
+   */
+
+  COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs);
+
+  if (count < sysex.len)
+    {
+      printk ("MIDI Warning: Sysex record too short (%d<%d)\n",
+	      count, (int) sysex.len);
+      sysex.len = count;
+    }
+
+  left = sysex.len;
+  src_offs = 0;
+
+  RESET_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
+
+  for (i = 0; i < left && !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag); i++)
+    {
+      unsigned char   data;
+
+      GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i);
+
+      if (first_byte && data != 0xf0)
+	midi_outc (orig_dev, 0xf0);	/* Sysex start */
+
+      eox_seen = (data == 0xf7);/*
+					 * Last byte was end of sysex
+					 */
+
+      if (i == 0)
+	{
+	  if (data != 0xf0)	/*
+				 * Sysex start
+				 */
+	    return RET_ERROR (EINVAL);
+	}
+
+      while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
+	     !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag))
+	DO_SLEEP (sysex_sleeper, sysex_sleep_flag, 1);	/* Wait for timeout */
+
+      if (!first_byte && data & 0x80)
+	return 0;
+      first_byte = 0;
+    }
+
+  if (!eox_seen)
+    midi_outc (orig_dev, 0xf7);
+  return 0;
+}
+
+void
+midi_synth_panning (int dev, int channel, int pressure)
+{
+}
+
+void
+midi_synth_aftertouch (int dev, int channel, int pressure)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             msg, chn;
+
+  if (pressure < 0 || pressure > 127)
+    return;
+  if (channel < 0 || channel > 15)
+    return;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (msg != 0xd0 || chn != channel)	/*
+					 * Test for running status
+					 */
+    {
+      if (!prefix_cmd (orig_dev, 0xd0 | (channel & 0x0f)))
+	return;
+      midi_outc (orig_dev, 0xd0 | (channel & 0x0f));	/*
+							 * Channel pressure
+							 */
+    }
+  else if (!prefix_cmd (orig_dev, pressure))
+    return;
+  midi_outc (orig_dev, pressure);
+}
+
+void
+midi_synth_controller (int dev, int channel, int ctrl_num, int value)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             chn, msg;
+
+  if (ctrl_num < 1 || ctrl_num > 127)
+    return;			/* NOTE! Controller # 0 ignored */
+  if (channel < 0 || channel > 15)
+    return;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (msg != 0xb0 || chn != channel)
+    {
+      if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f)))
+	return;
+      midi_outc (orig_dev, 0xb0 | (channel & 0x0f));
+    }
+  else if (!prefix_cmd (orig_dev, ctrl_num))
+    return;
+
+  midi_outc (orig_dev, ctrl_num);
+  midi_outc (orig_dev, value & 0x7f);
+}
+
+int
+midi_synth_patchmgr (int dev, struct patmgr_info *rec)
+{
+  return RET_ERROR (EINVAL);
+}
+
+void
+midi_synth_bender (int dev, int channel, int value)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             msg, prev_chn;
+
+  if (channel < 0 || channel > 15)
+    return;
+
+  if (value < 0 || value > 16383)
+    return;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  prev_chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (msg != 0xd0 || prev_chn != channel)	/*
+						 * * Test for running status  */
+    {
+      if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f)))
+	return;
+      midi_outc (orig_dev, 0xe0 | (channel & 0x0f));
+    }
+  else if (!prefix_cmd (orig_dev, value & 0x7f))
+    return;
+
+  midi_outc (orig_dev, value & 0x7f);
+  midi_outc (orig_dev, (value >> 7) & 0x7f);
+}
+
+#endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/midi_synth.h linux/drivers/sound/midi_synth.h
--- v1.1.30/linux/drivers/sound/midi_synth.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/midi_synth.h	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,45 @@
+int midi_synth_ioctl (int dev,
+	    unsigned int cmd, unsigned int arg);
+int midi_synth_kill_note (int dev, int channel, int note, int velocity);
+int midi_synth_set_instr (int dev, int channel, int instr_no);
+int midi_synth_start_note (int dev, int channel, int note, int volume);
+void midi_synth_reset (int dev);
+int midi_synth_open (int dev, int mode);
+void midi_synth_close (int dev);
+void midi_synth_hw_control (int dev, unsigned char *event);
+int midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
+		 int offs, int count, int pmgr_flag);
+void midi_synth_panning (int dev, int channel, int pressure);
+void midi_synth_aftertouch (int dev, int channel, int pressure);
+void midi_synth_controller (int dev, int channel, int ctrl_num, int value);
+int midi_synth_patchmgr (int dev, struct patmgr_info *rec);
+void midi_synth_bender (int dev, int chn, int value);
+
+
+#ifndef _MIDI_SYNTH_C_
+static struct synth_info std_synth_info =
+{MIDI_SYNTH_NAME, 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, MIDI_SYNTH_CAPS};
+
+static struct synth_operations std_midi_synth =
+{
+  &std_synth_info,
+  0,
+  SYNTH_TYPE_MIDI,
+  0,
+  midi_synth_open,
+  midi_synth_close,
+  midi_synth_ioctl,
+  midi_synth_kill_note,
+  midi_synth_start_note,
+  midi_synth_set_instr,
+  midi_synth_reset,
+  midi_synth_hw_control,
+  midi_synth_load_patch,
+  midi_synth_aftertouch,
+  midi_synth_controller,
+  midi_synth_panning,
+  NULL,
+  midi_synth_patchmgr,
+  midi_synth_bender
+};
+#endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v1.1.30/linux/drivers/sound/midibuf.c	Sun May  1 12:12:34 1994
+++ linux/drivers/sound/midibuf.c	Mon Jul 18 09:50:55 1994
@@ -1,10 +1,8 @@
 /*
  * sound/midibuf.c
  *
- * Device file manager for /dev/midi
+ * Device file manager for /dev/midi#
  *
- * NOTE! This part of the driver is currently just a stub.
- *
  * Copyright by Hannu Savolainen 1993
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,88 +29,410 @@
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MPU401)
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+
+/*
+ * Don't make MAX_QUEUE_SIZE larger than 4000
+ */
+
+#define MAX_QUEUE_SIZE	4000
+
+DEFINE_WAIT_QUEUES (midi_sleeper[MAX_MIDI_DEV], midi_sleep_flag[MAX_MIDI_DEV]);
+DEFINE_WAIT_QUEUES (input_sleeper[MAX_MIDI_DEV], input_sleep_flag[MAX_MIDI_DEV]);
+
+struct midi_buf
+  {
+    int             len, head, tail;
+    unsigned char   queue[MAX_QUEUE_SIZE];
+  };
+
+struct midi_parms
+  {
+    int             prech_timeout;	/*
+					 * Timeout before the first ch
+					 */
+  };
+
+static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] =
+{NULL};
+static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] =
+{NULL};
+static struct midi_parms parms[MAX_MIDI_DEV];
+
+static void     midi_poll (unsigned long dummy);
+
+DEFINE_TIMER (poll_timer, midi_poll);
+static volatile int open_devs = 0;
+
+#define DATA_AVAIL(q) (q->len)
+#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
+
+#define QUEUE_BYTE(q, data) \
+	if (SPACE_AVAIL(q)) \
+	{ \
+	  unsigned long flags; \
+	  DISABLE_INTR(flags); \
+	  q->queue[q->tail] = (data); \
+	  q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
+	  RESTORE_INTR(flags); \
+	}
+
+#define REMOVE_BYTE(q, data) \
+	if (DATA_AVAIL(q)) \
+	{ \
+	  unsigned long flags; \
+	  DISABLE_INTR(flags); \
+	  data = q->queue[q->head]; \
+	  q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
+	  RESTORE_INTR(flags); \
+	}
+
+void
+drain_midi_queue (int dev)
+{
+
+  /*
+   * Give the Midi driver time to drain its output queues
+   */
+
+  if (midi_devs[dev]->buffer_status != NULL)
+    while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
+	   midi_devs[dev]->buffer_status (dev))
+      DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], HZ / 10);
+}
+
+static void
+midi_input_intr (int dev, unsigned char data)
+{
+  if (midi_in_buf[dev] == NULL)
+    return;
+
+  if (data == 0xfe)		/*
+				 * Active sensing
+				 */
+    return;			/*
+				 * Ignore
+				 */
+
+  if (SPACE_AVAIL (midi_in_buf[dev]))
+    {
+      QUEUE_BYTE (midi_in_buf[dev], data);
+      if (SOMEONE_WAITING (input_sleeper[dev], input_sleep_flag[dev]))
+	WAKE_UP (input_sleeper[dev], input_sleep_flag[dev]);
+    }
+
+}
+
+static void
+midi_output_intr (int dev)
+{
+  /*
+   * Currently NOP
+   */
+}
 
-#if 0
-#include "midiioctl.h"
-#include "midivar.h"
-#endif
+static void
+midi_poll (unsigned long dummy)
+{
+  unsigned long   flags;
+  int             dev;
 
-static int      midibuf_busy = 0;
+  DISABLE_INTR (flags);
+  if (open_devs)
+    {
+      for (dev = 0; dev < num_midis; dev++)
+	if (midi_out_buf[dev] != NULL)
+	  {
+	    while (DATA_AVAIL (midi_out_buf[dev]) &&
+		   midi_devs[dev]->putc (dev,
+			 midi_out_buf[dev]->queue[midi_out_buf[dev]->head]))
+	      {
+		midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
+		midi_out_buf[dev]->len--;
+	      }
+
+	    if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&
+		SOMEONE_WAITING (midi_sleeper[dev], midi_sleep_flag[dev]))
+	      WAKE_UP (midi_sleeper[dev], midi_sleep_flag[dev]);
+	  }
+      ACTIVATE_TIMER (poll_timer, midi_poll, 1);	/*
+							 * Come back later
+							 */
+    }
+  RESTORE_INTR (flags);
+}
 
 int
 MIDIbuf_open (int dev, struct fileinfo *file)
 {
   int             mode, err;
+  unsigned long   flags;
 
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
 
-  if (midibuf_busy)
-    return RET_ERROR (EBUSY);
+  if (num_midis > MAX_MIDI_DEV)
+    {
+      printk ("Sound: FATAL ERROR: Too many midi interfaces\n");
+      num_midis = MAX_MIDI_DEV;
+    }
 
-  if (!mpu401_dev)
+  if (dev < 0 || dev >= num_midis)
     {
-      printk ("Midi: MPU-401 compatible Midi interface not present\n");
+      printk ("Sound: Nonexistent MIDI interface %d\n", dev);
       return RET_ERROR (ENXIO);
     }
 
-  if ((err = midi_devs[mpu401_dev]->open (mpu401_dev, mode, NULL, NULL)) < 0)
-    return err;
+  /*
+ *    Interrupts disabled. Be careful
+ */
+
+  DISABLE_INTR (flags);
+  if ((err = midi_devs[dev]->open (dev, mode,
+				   midi_input_intr, midi_output_intr)) < 0)
+    {
+      RESTORE_INTR (flags);
+      return err;
+    }
+
+  parms[dev].prech_timeout = 0;
+
+  RESET_WAIT_QUEUE (midi_sleeper[dev], midi_sleep_flag[dev]);
+  RESET_WAIT_QUEUE (input_sleeper[dev], input_sleep_flag[dev]);
+
+  midi_in_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));
+
+  if (midi_in_buf[dev] == NULL)
+    {
+      printk ("midi: Can't allocate buffer\n");
+      midi_devs[dev]->close (dev);
+      RESTORE_INTR (flags);
+      return RET_ERROR (EIO);
+    }
+  midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
+
+  midi_out_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));
 
-  midibuf_busy = 1;
+  if (midi_out_buf[dev] == NULL)
+    {
+      printk ("midi: Can't allocate buffer\n");
+      midi_devs[dev]->close (dev);
+      KERNEL_FREE (midi_in_buf[dev]);
+      midi_in_buf[dev] = NULL;
+      RESTORE_INTR (flags);
+      return RET_ERROR (EIO);
+    }
+  midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
+  if (!open_devs)
+    ACTIVATE_TIMER (poll_timer, midi_poll, 1);	/*
+						 * Come back later
+						 */
+  open_devs++;
+  RESTORE_INTR (flags);
 
-  return RET_ERROR (ENXIO);
+  return err;
 }
 
 void
 MIDIbuf_release (int dev, struct fileinfo *file)
 {
   int             mode;
+  unsigned long   flags;
 
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
 
-  midi_devs[mpu401_dev]->close (mpu401_dev);
-  midibuf_busy = 0;
+  DISABLE_INTR (flags);
+
+  /*
+ * Wait until the queue is empty
+ */
+
+  if (mode != OPEN_READ)
+    {
+      midi_devs[dev]->putc (dev, 0xfe);	/*
+						 * Active sensing to shut the
+						 * devices
+						 */
+
+      while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
+	     DATA_AVAIL (midi_out_buf[dev]))
+	DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0);	/*
+								 * Sync
+								 */
+
+      drain_midi_queue (dev);	/*
+				 * Ensure the output queues are empty
+				 */
+    }
+
+  midi_devs[dev]->close (dev);
+  KERNEL_FREE (midi_in_buf[dev]);
+  KERNEL_FREE (midi_out_buf[dev]);
+  midi_in_buf[dev] = NULL;
+  midi_out_buf[dev] = NULL;
+  open_devs--;
+  RESTORE_INTR (flags);
 }
 
 int
 MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
+  unsigned long   flags;
+  int             c, n, i;
+  unsigned char   tmp_data;
 
   dev = dev >> 4;
 
-  return count;
+  if (!count)
+    return 0;
+
+  DISABLE_INTR (flags);
+
+  c = 0;
+
+  while (c < count)
+    {
+      n = SPACE_AVAIL (midi_out_buf[dev]);
+
+      if (n == 0)		/*
+				 * No space just now. We have to sleep
+				 */
+	{
+	  DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0);
+	  if (PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]))
+	    {
+	      RESTORE_INTR (flags);
+	      return RET_ERROR (EINTR);
+	    }
+
+	  n = SPACE_AVAIL (midi_out_buf[dev]);
+	}
+
+      if (n > (count - c))
+	n = count - c;
+
+      for (i = 0; i < n; i++)
+	{
+	  COPY_FROM_USER (&tmp_data, buf, c, 1);
+	  QUEUE_BYTE (midi_out_buf[dev], tmp_data);
+	  c++;
+	}
+    }
+
+  RESTORE_INTR (flags);
+
+  return c;
 }
 
 
 int
 MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
+  int             n, c = 0;
+  unsigned long   flags;
+  unsigned char   tmp_data;
+
   dev = dev >> 4;
 
-  return RET_ERROR (EIO);
+  DISABLE_INTR (flags);
+
+  if (!DATA_AVAIL (midi_in_buf[dev]))	/*
+					 * No data yet, wait
+					 */
+    {
+      DO_SLEEP (input_sleeper[dev], input_sleep_flag[dev],
+		parms[dev].prech_timeout);
+      if (PROCESS_ABORTING (input_sleeper[dev], input_sleep_flag[dev]))
+	c = RET_ERROR (EINTR);	/*
+				 * The user is getting restless
+				 */
+    }
+
+  if (c == 0 && DATA_AVAIL (midi_in_buf[dev]))	/*
+						 * Got some bytes
+						 */
+    {
+      n = DATA_AVAIL (midi_in_buf[dev]);
+      if (n > count)
+	n = count;
+      c = 0;
+
+      while (c < n)
+	{
+	  REMOVE_BYTE (midi_in_buf[dev], tmp_data);
+	  COPY_TO_USER (buf, c, &tmp_data, 1);
+	  c++;
+	}
+    }
+
+  RESTORE_INTR (flags);
+
+  return c;
 }
 
 int
 MIDIbuf_ioctl (int dev, struct fileinfo *file,
 	       unsigned int cmd, unsigned int arg)
 {
+  int             val;
+
   dev = dev >> 4;
 
   switch (cmd)
     {
 
+    case SNDCTL_MIDI_PRETIME:
+      val = IOCTL_IN (arg);
+      if (val < 0)
+	val = 0;
+
+      val = (HZ * val) / 10;
+      parms[dev].prech_timeout = val;
+      return IOCTL_OUT (arg, val);
+      break;
+
     default:
-      return midi_devs[0]->ioctl (dev, cmd, arg);
+      return midi_devs[dev]->ioctl (dev, cmd, arg);
     }
 }
 
-void
-MIDIbuf_bytes_received (int dev, unsigned char *buf, int count)
+#ifdef ALLOW_SELECT
+int
+MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
 {
+  dev = dev >> 4;
+
+  switch (sel_type)
+    {
+    case SEL_IN:
+      if (!DATA_AVAIL (midi_in_buf[dev]))
+	{
+	  input_sleep_flag[dev].mode = WK_SLEEP;
+	  select_wait (&input_sleeper[dev], wait);
+	  return 0;
+	}
+      return 1;
+      break;
+
+    case SEL_OUT:
+      if (SPACE_AVAIL (midi_out_buf[dev]))
+	{
+	  midi_sleep_flag[dev].mode = WK_SLEEP;
+	  select_wait (&midi_sleeper[dev], wait);
+	  return 0;
+	}
+      return 1;
+      break;
+
+    case SEL_EX:
+      return 0;
+    }
+
+  return 0;
 }
+
+#endif /* ALLOW_SELECT */
 
 long
 MIDIbuf_init (long mem_start)
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c
--- v1.1.30/linux/drivers/sound/mpu401.c	Sun May  1 12:12:34 1994
+++ linux/drivers/sound/mpu401.c	Mon Jul 18 09:50:55 1994
@@ -3,8 +3,6 @@
  *
  * The low level driver for Roland MPU-401 compatible Midi cards.
  *
- * This version supports just the DUMB UART mode.
- *
  * Copyright by Hannu Savolainen 1993
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,48 +27,486 @@
  *
  */
 
+#define USE_SEQ_MACROS
+#define USE_SIMPLE_MACROS
+
 #include "sound_config.h"
 
 #ifdef CONFIGURE_SOUNDCARD
 
 #if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
 
-#define	DATAPORT   (mpu401_base)/* MPU-401 Data I/O Port on IBM */
-#define	COMDPORT   (mpu401_base+1)	/* MPU-401 Command Port on IBM */
-#define	STATPORT   (mpu401_base+1)	/* MPU-401 Status Port on IBM */
-
-#define mpu401_status()		INB(STATPORT)
-#define input_avail()		(!(mpu401_status()&INPUT_AVAIL))
-#define output_ready()		(!(mpu401_status()&OUTPUT_READY))
-#define mpu401_cmd(cmd)		OUTB(cmd, COMDPORT)
-#define mpu401_read()		INB(DATAPORT)
-#define mpu401_write(byte)	OUTB(byte, DATAPORT)
-
-#define	OUTPUT_READY	0x40	/* Mask for Data Read Redy Bit */
-#define	INPUT_AVAIL	0x80	/* Mask for Data Send Ready Bit */
-#define	MPU_ACK		0xFE	/* MPU-401 Acknowledge Response */
-#define	MPU_RESET	0xFF	/* MPU-401 Total Reset Command */
-#define	UART_MODE_ON	0x3F	/* MPU-401 "Dumb UART Mode" */
-
-static int      mpu401_opened = 0;
-static int      mpu401_base = 0x330;
-static int      mpu401_irq;
-static int      mpu401_detected = 0;
-static int      my_dev;
+static int      init_sequence[20];	/* NOTE! pos 0 = len, start pos 1. */
+static int      timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
+
+struct mpu_config
+  {
+    int             base;	/*
+				 * I/O base
+				 */
+    int             irq;
+    int             opened;	/*
+				 * Open mode
+				 */
+    int             devno;
+    int             synthno;
+    int             uart_mode;
+    int             initialized;
+    int             mode;
+#define MODE_MIDI	1
+#define MODE_SYNTH	2
+    unsigned char   version, revision;
+    unsigned int    capabilities;
+#define MPU_CAP_INTLG	0x10000000
+#define MPU_CAP_SYNC	0x00000010
+#define MPU_CAP_FSK	0x00000020
+#define MPU_CAP_CLS	0x00000040
+#define MPU_CAP_SMPTE 	0x00000080
+#define MPU_CAP_2PORT	0x00000001
+    int             timer_flag;
+
+#define MBUF_MAX	10
+#define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \
+	{printk("MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;}
+    int             m_busy;
+    unsigned char   m_buf[MBUF_MAX];
+    int             m_ptr;
+    int             m_state;
+    int             m_left;
+    unsigned char   last_status;
+    void            (*inputintr) (int dev, unsigned char data);
+    unsigned short  controls[32];
+  };
+
+#define	DATAPORT(base)   (base)
+#define	COMDPORT(base)   (base+1)
+#define	STATPORT(base)   (base+1)
+
+#define mpu401_status(base)		INB(STATPORT(base))
+#define input_avail(base)		(!(mpu401_status(base)&INPUT_AVAIL))
+#define output_ready(base)		(!(mpu401_status(base)&OUTPUT_READY))
+#define write_command(base, cmd)		OUTB(cmd, COMDPORT(base))
+#define read_data(base)		INB(DATAPORT(base))
+
+#define write_data(base, byte)	OUTB(byte, DATAPORT(base))
+
+#define	OUTPUT_READY	0x40
+#define	INPUT_AVAIL	0x80
+#define	MPU_ACK		0xF7
+#define	MPU_RESET	0xFF
+#define	UART_MODE_ON	0x3F
+
+static struct mpu_config dev_conf[MAX_MIDI_DEV] =
+{
+  {0}};
+
+static int      n_mpu_devs = 0;
+static int      irq2dev[16];
+
+static int      reset_mpu401 (struct mpu_config *devc);
+static void     set_uart_mode (int dev, struct mpu_config *devc, int arg);
+static void     mpu_timer_init (int midi_dev);
+static void     mpu_timer_interrupt (void);
+static void     timer_ext_event (struct mpu_config *devc, int event, int parm);
+
+static struct synth_info mpu_synth_info_proto =
+{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+
+static struct synth_info mpu_synth_info[MAX_MIDI_DEV];
+
+/*
+ * States for the input scanner
+ */
+
+#define ST_INIT			0	/* Ready for timing byte or msg */
+#define ST_TIMED		1	/* Leading timing byte rcvd */
+#define ST_DATABYTE		2	/* Waiting for (nr_left) data bytes */
+
+#define ST_SYSMSG		100	/* System message (sysx etc). */
+#define ST_SYSEX		101	/* System exclusive msg */
+#define ST_MTC			102	/* Midi Time Code (MTC) qframe msg */
+#define ST_SONGSEL		103	/* Song select */
+#define ST_SONGPOS		104	/* Song position pointer */
+
+static unsigned char len_tab[] =/* # of data bytes following a status
+					 */
+{
+  2,				/* 8x */
+  2,				/* 9x */
+  2,				/* Ax */
+  2,				/* Bx */
+  1,				/* Cx */
+  1,				/* Dx */
+  2,				/* Ex */
+  0				/* Fx */
+};
+
+#define STORE(cmd) \
+if (devc->opened & OPEN_READ) \
+{ \
+  int len; \
+  unsigned char obuf[8]; \
+  cmd; \
+  seq_input_event(obuf, len); \
+}
+#define _seqbuf obuf
+#define _seqbufptr 0
+#define _SEQ_ADVBUF(x) len=x
+
+static void
+do_midi_msg (struct mpu_config *devc, unsigned char *msg, int mlen)
+{
+  switch (msg[0] & 0xf0)
+    {
+    case 0x90:
+      if (msg[2] != 0)
+	{
+	  STORE (SEQ_START_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
+	  break;
+	}
+      msg[2] = 64;
+
+    case 0x80:
+      STORE (SEQ_STOP_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xA0:
+      STORE (SEQ_KEY_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xB0:
+      /*
+ * Fix the controller value (combine MSB and LSB)
+ */
+      if (msg[1] < 64)
+	{
+	  int             ctrl = msg[1];
+
+	  if (ctrl < 32)
+	    {
+	      devc->controls[ctrl] = (msg[2] & 0x7f) << 7;
+	    }
+	  else
+	    {
+	      ctrl -= 32;
+	      devc->controls[ctrl] =
+		(devc->controls[ctrl] & ~0x7f) | (msg[2] & 0x7f);
+	    }
+	  STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f,
+			      msg[1], devc->controls[ctrl]));
+	}
+      else
+	STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xC0:
+      STORE (SEQ_SET_PATCH (devc->synthno, msg[0] & 0x0f, msg[1]));
+      break;
+
+    case 0xD0:
+      STORE (SEQ_CHN_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1]));
+      break;
+
+    case 0xE0:
+      STORE (SEQ_BENDER (devc->synthno, msg[0] & 0x0f,
+			 (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
+      break;
+
+    default:
+      printk ("MPU: Unknown midi channel message %02x\n", msg[0]);
+    }
+}
+
+static int
+mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
+{
+  switch (devc->m_state)
+    {
+    case ST_INIT:
+      switch (midic)
+	{
+	case 0xf8:
+	  /* Timer overflow */
+	  break;
+
+	case 0xfc:
+	  printk ("<all end>");
+	  break;
+
+	case 0xfd:
+	  if (devc->timer_flag)
+	    mpu_timer_interrupt ();
+	  break;
+
+	case 0xfe:
+	  return MPU_ACK;
+	  break;
+
+	case 0xf0:
+	case 0xf1:
+	case 0xf2:
+	case 0xf3:
+	case 0xf4:
+	case 0xf5:
+	case 0xf6:
+	case 0xf7:
+	  printk ("<Trk data rq #%d>", midic & 0x0f);
+	  break;
+
+	case 0xf9:
+	  printk ("<conductor rq>");
+	  break;
+
+	case 0xff:
+	  devc->m_state = ST_SYSMSG;
+	  break;
+
+	default:
+	  if (midic <= 0xef)
+	    {
+	      /* printk("mpu time: %d ", midic); */
+	      devc->m_state = ST_TIMED;
+	    }
+	  else
+	    printk ("<MPU: Unknown event %02x> ", midic);
+	}
+      break;
+
+    case ST_TIMED:
+      {
+	int             msg = (midic & 0xf0) >> 4;
+
+	devc->m_state = ST_DATABYTE;
+	if (msg < 8)		/* Data byte */
+	  {
+	    /* printk("midi msg (running status) "); */
+	    msg = (devc->last_status & 0xf0) >> 4;
+	    msg -= 8;
+	    devc->m_left = len_tab[msg] - 1;
+
+	    devc->m_ptr = 2;
+	    devc->m_buf[0] = devc->last_status;
+	    devc->m_buf[1] = midic;
+
+	    if (devc->m_left <= 0)
+	      {
+		devc->m_state = ST_INIT;
+		do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+		devc->m_ptr = 0;
+	      }
+	  }
+	else if (msg == 0xf)	/* MPU MARK */
+	  {
+	    devc->m_state = ST_INIT;
+
+	    switch (midic)
+	      {
+	      case 0xf8:
+		/* printk("NOP "); */
+		break;
+
+	      case 0xf9:
+		/* printk("meas end "); */
+		break;
+
+	      case 0xfc:
+		/* printk("data end "); */
+		break;
+
+	      default:
+		printk ("Unknown MPU mark %02x\n", midic);
+	      }
+	  }
+	else
+	  {
+	    devc->last_status = midic;
+	    /* printk("midi msg "); */
+	    msg -= 8;
+	    devc->m_left = len_tab[msg];
+
+	    devc->m_ptr = 1;
+	    devc->m_buf[0] = midic;
+
+	    if (devc->m_left <= 0)
+	      {
+		devc->m_state = ST_INIT;
+		do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+		devc->m_ptr = 0;
+	      }
+	  }
+      }
+      break;
+
+    case ST_SYSMSG:
+      switch (midic)
+	{
+	case 0xf0:
+	  printk ("<SYX>");
+	  devc->m_state = ST_SYSEX;
+	  break;
+
+	case 0xf1:
+	  devc->m_state = ST_MTC;
+	  break;
+
+	case 0xf2:
+	  devc->m_state = ST_SONGPOS;
+	  devc->m_ptr = 0;
+	  break;
+
+	case 0xf3:
+	  devc->m_state = ST_SONGSEL;
+	  break;
+
+	case 0xf6:
+	  /* printk("tune_request\n"); */
+	  devc->m_state = ST_INIT;
+
+	  /*
+ *    Real time messages
+ */
+	case 0xf8:
+	  /* midi clock */
+	  devc->m_state = ST_INIT;
+	  timer_ext_event (devc, TMR_CLOCK, 0);
+	  break;
+
+	case 0xfA:
+	  devc->m_state = ST_INIT;
+	  timer_ext_event (devc, TMR_START, 0);
+	  break;
+
+	case 0xFB:
+	  devc->m_state = ST_INIT;
+	  timer_ext_event (devc, TMR_CONTINUE, 0);
+	  break;
+
+	case 0xFC:
+	  devc->m_state = ST_INIT;
+	  timer_ext_event (devc, TMR_STOP, 0);
+	  break;
+
+	case 0xFE:
+	  /* active sensing */
+	  devc->m_state = ST_INIT;
+	  break;
+
+	case 0xff:
+	  /* printk("midi hard reset"); */
+	  devc->m_state = ST_INIT;
+	  break;
+
+	default:
+	  printk ("unknown MIDI sysmsg %0x\n", midic);
+	  devc->m_state = ST_INIT;
+	}
+      break;
+
+    case ST_MTC:
+      devc->m_state = ST_INIT;
+      printk ("MTC frame %x02\n", midic);
+      break;
+
+    case ST_SYSEX:
+      if (midic == 0xf7)
+	{
+	  printk ("<EOX>");
+	  devc->m_state = ST_INIT;
+	}
+      else
+	printk ("%02x ", midic);
+      break;
+
+    case ST_SONGPOS:
+      BUFTEST (devc);
+      devc->m_buf[devc->m_ptr++] = midic;
+      if (devc->m_ptr == 2)
+	{
+	  devc->m_state = ST_INIT;
+	  devc->m_ptr = 0;
+	  timer_ext_event (devc, TMR_SPP,
+			   ((devc->m_buf[1] & 0x7f) << 7) |
+			   (devc->m_buf[0] & 0x7f));
+	}
+      break;
+
+    case ST_DATABYTE:
+      BUFTEST (devc);
+      devc->m_buf[devc->m_ptr++] = midic;
+      if ((--devc->m_left) <= 0)
+	{
+	  devc->m_state = ST_INIT;
+	  do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+	  devc->m_ptr = 0;
+	}
+      break;
+
+    default:
+      printk ("Bad state %d ", devc->m_state);
+      devc->m_state = ST_INIT;
+    }
+
+  return 1;
+}
+
+static void
+mpu401_input_loop (struct mpu_config *devc)
+{
+  unsigned long   flags;
+  int             busy;
+
+  DISABLE_INTR (flags);
+  busy = devc->m_busy;
+  devc->m_busy = 1;
+  RESTORE_INTR (flags);
+
+  if (busy)
+    return;
+
+  while (input_avail (devc->base))
+    {
+      unsigned char   c = read_data (devc->base);
+
+      if (devc->mode == MODE_SYNTH)
+	{
+	  mpu_input_scanner (devc, c);
+	}
+      else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
+	devc->inputintr (devc->devno, c);
+    }
 
-static int      reset_mpu401 (void);
-static void     (*midi_input_intr) (int dev, unsigned char data);
+  devc->m_busy = 0;
+}
 
 void
-mpuintr (int unit)
+mpuintr (int irq)
 {
-  while (input_avail ())
+  struct mpu_config *devc;
+  int             dev;
+
+#ifdef linux
+  sti ();
+#endif
+
+  if (irq < 1 || irq > 15)
     {
-      unsigned char   c = mpu401_read ();
+      printk ("MPU-401: Interrupt #%d?\n", irq);
+      return;
+    }
 
-      if (mpu401_opened & OPEN_READ)
-	midi_input_intr (my_dev, c);
+  dev = irq2dev[irq];
+  if (dev == -1)
+    {
+      printk ("MPU-401: Interrupt #%d?\n", irq);
+      return;
     }
+
+  devc = &dev_conf[dev];
+
+  if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
+    if (input_avail (devc->base))
+      mpu401_input_loop (devc);
+
 }
 
 static int
@@ -79,16 +515,32 @@
 	     void            (*output) (int dev)
 )
 {
-  if (mpu401_opened)
+  int             err;
+  struct mpu_config *devc;
+
+  if (dev < 0 || dev >= num_midis)
+    return RET_ERROR (ENXIO);
+
+  devc = &dev_conf[dev];
+
+  if (devc->opened)
     {
       printk ("MPU-401: Midi busy\n");
       return RET_ERROR (EBUSY);
     }
 
-  mpuintr (0);
+  irq2dev[devc->irq] = dev;
+  if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
+    return err;
+
+  set_uart_mode (dev, devc, 1);
+  devc->mode = MODE_MIDI;
+  devc->synthno = 0;
+
+  mpu401_input_loop (devc);
 
-  midi_input_intr = input;
-  mpu401_opened = mode;
+  devc->inputintr = input;
+  devc->opened = mode;
 
   return 0;
 }
@@ -96,7 +548,20 @@
 static void
 mpu401_close (int dev)
 {
-  mpu401_opened = 0;
+  struct mpu_config *devc;
+
+  devc = &dev_conf[dev];
+
+  if (devc->uart_mode)
+    reset_mpu401 (devc);	/*
+				 * This disables the UART mode
+				 */
+  devc->mode = 0;
+
+  snd_release_irq (devc->irq);
+  devc->inputintr = NULL;
+  irq2dev[devc->irq] = -1;
+  devc->opened = 0;
 }
 
 static int
@@ -105,38 +570,180 @@
   int             timeout;
   unsigned long   flags;
 
+  struct mpu_config *devc;
+
+  devc = &dev_conf[dev];
+
+#if 0
   /*
    * Test for input since pending input seems to block the output.
    */
 
-  DISABLE_INTR (flags);
+  if (input_avail (devc->base))
+    mpu401_input_loop (devc);
+#endif
+  /*
+   * Sometimes it takes about 13000 loops before the output becomes ready
+   * (After reset). Normally it takes just about 10 loops.
+   */
 
-  if (input_avail ())
-    mpuintr (0);
+  for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--);	/*
+										 * Wait
+										 */
 
+  DISABLE_INTR (flags);
+  if (!output_ready (devc->base))
+    {
+      printk ("MPU-401: Send data timeout\n");
+      RESTORE_INTR (flags);
+      return 0;
+    }
+
+  write_data (devc->base, midi_byte);
   RESTORE_INTR (flags);
+  return 1;
+}
+
+static int
+mpu401_command (int dev, mpu_command_rec * cmd)
+{
+  int             i, timeout, ok;
+  int             ret = 0;
+  unsigned long   flags;
+  struct mpu_config *devc;
+
+  devc = &dev_conf[dev];
 
+  if (devc->uart_mode)		/*
+				 * Not possible in UART mode
+				 */
+    {
+      printk ("MPU-401 commands not possible in the UART mode\n");
+      return RET_ERROR (EINVAL);
+    }
+
   /*
-   * Sometimes it takes about 13000 loops before the output becomes ready
+   * Test for input since pending input seems to block the output.
+   */
+  if (input_avail (devc->base))
+    mpu401_input_loop (devc);
+
+  /*
+   * Sometimes it takes about 30000 loops before the output becomes ready
    * (After reset). Normally it takes just about 10 loops.
    */
 
-  for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);	/* Wait */
+  for (timeout = 500000; timeout > 0 && !output_ready (devc->base); timeout--);
 
-  if (!output_ready ())
+  DISABLE_INTR (flags);
+  if (!output_ready (devc->base))
     {
-      printk ("MPU-401: Timeout\n");
-      return 0;
+      printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
+      RESTORE_INTR (flags);
+      return RET_ERROR (EIO);
     }
 
-  mpu401_write (midi_byte);
-  return 1;
+  write_command (devc->base, cmd->cmd);
+  ok = 0;
+  for (timeout = 500000; timeout > 0 && !ok; timeout--)
+    if (input_avail (devc->base))
+      if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK)
+	ok = 1;
+
+  if (!ok)
+    {
+      RESTORE_INTR (flags);
+      printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd);
+      return RET_ERROR (EIO);
+    }
+
+  if (cmd->nr_args)
+    for (i = 0; i < cmd->nr_args; i++)
+      {
+	for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--);
+
+	if (!mpu401_out (dev, cmd->data[i]))
+	  {
+	    RESTORE_INTR (flags);
+	    printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
+	    return RET_ERROR (EIO);
+	  }
+      }
+
+  ret = 0;
+  cmd->data[0] = 0;
+
+  if (cmd->nr_returns)
+    for (i = 0; i < cmd->nr_returns; i++)
+      {
+	ok = 0;
+	for (timeout = 5000; timeout > 0 && !ok; timeout--)
+	  if (input_avail (devc->base))
+	    {
+	      cmd->data[i] = read_data (devc->base);
+	      ok = 1;
+	    }
+
+	if (!ok)
+	  {
+	    RESTORE_INTR (flags);
+	    printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd);
+	    return RET_ERROR (EIO);
+	  }
+      }
+
+  RESTORE_INTR (flags);
+
+  return ret;
 }
 
 static int
-mpu401_command (int dev, unsigned char midi_byte)
+exec_cmd (int dev, int cmd, int data)
 {
-  return 1;
+  int             ret;
+
+  static mpu_command_rec rec;
+
+  rec.cmd = cmd & 0xff;
+  rec.nr_args = ((cmd & 0xf0) == 0xE0);
+  rec.nr_returns = ((cmd & 0xf0) == 0xA0);
+  rec.data[0] = data & 0xff;
+
+  if ((ret = mpu401_command (dev, &rec)) < 0)
+    return ret;
+  return (unsigned char) rec.data[0];
+}
+
+static int
+mpu401_prefix_cmd (int dev, unsigned char status)
+{
+  struct mpu_config *devc = &dev_conf[dev];
+
+  if (devc->uart_mode)
+    return 1;
+
+  if (status < 0xf0)
+    {
+      if (exec_cmd (dev, 0xD0, 0) < 0)
+	return 0;
+
+      return 1;
+    }
+
+  switch (status)
+    {
+    case 0xF0:
+      if (exec_cmd (dev, 0xDF, 0) < 0)
+	return 0;
+
+      return 1;
+      break;
+
+    default:
+      return 0;
+    }
+
+  return 0;
 }
 
 static int
@@ -154,7 +761,45 @@
 static int
 mpu401_ioctl (int dev, unsigned cmd, unsigned arg)
 {
-  return RET_ERROR (EINVAL);
+  struct mpu_config *devc;
+
+  devc = &dev_conf[dev];
+
+  switch (cmd)
+    {
+    case 1:
+      IOCTL_FROM_USER ((char *) &init_sequence, (char *) arg, 0, sizeof (init_sequence));
+      return 0;
+      break;
+
+    case SNDCTL_MIDI_MPUMODE:
+      if (devc->version == 0)
+	{
+	  printk ("MPU-401: Intelligent mode not supported by the HW\n");
+	  return RET_ERROR (EINVAL);
+	}
+      set_uart_mode (dev, devc, !IOCTL_IN (arg));
+      return 0;
+      break;
+
+    case SNDCTL_MIDI_MPUCMD:
+      {
+	int             ret;
+	mpu_command_rec rec;
+
+	IOCTL_FROM_USER ((char *) &rec, (char *) arg, 0, sizeof (rec));
+
+	if ((ret = mpu401_command (dev, &rec)) < 0)
+	  return ret;
+
+	IOCTL_TO_USER ((char *) arg, 0, (char *) &rec, sizeof (rec));
+	return 0;
+      }
+      break;
+
+    default:
+      return RET_ERROR (EINVAL);
+    }
 }
 
 static void
@@ -165,12 +810,135 @@
 static int
 mpu401_buffer_status (int dev)
 {
-  return 0;			/* No data in buffers */
+  return 0;			/*
+				 * No data in buffers
+				 */
+}
+
+static int
+mpu_synth_ioctl (int dev,
+		 unsigned int cmd, unsigned int arg)
+{
+  int             midi_dev;
+  struct mpu_config *devc;
+
+  midi_dev = synth_devs[dev]->midi_dev;
+
+  if (midi_dev < 0 || midi_dev > num_midis)
+    return RET_ERROR (ENXIO);
+
+  devc = &dev_conf[midi_dev];
+
+  switch (cmd)
+    {
+
+    case SNDCTL_SYNTH_INFO:
+      IOCTL_TO_USER ((char *) arg, 0, &mpu_synth_info[midi_dev],
+		     sizeof (struct synth_info));
+
+      return 0;
+      break;
+
+    case SNDCTL_SYNTH_MEMAVL:
+      return 0x7fffffff;
+      break;
+
+    default:
+      return RET_ERROR (EINVAL);
+    }
+}
+
+static int
+mpu_synth_open (int dev, int mode)
+{
+  int             midi_dev, err;
+  struct mpu_config *devc;
+
+  midi_dev = synth_devs[dev]->midi_dev;
+
+  if (midi_dev < 0 || midi_dev > num_midis)
+    return RET_ERROR (ENXIO);
+
+  devc = &dev_conf[midi_dev];
+
+  if (devc->opened)
+    {
+      printk ("MPU-401: Midi busy\n");
+      return RET_ERROR (EBUSY);
+    }
+
+  devc->opened = mode;
+  devc->mode = MODE_SYNTH;
+  devc->synthno = dev;
+
+  devc->inputintr = NULL;
+  irq2dev[devc->irq] = midi_dev;
+  if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
+    return err;
+
+  reset_mpu401 (devc);
+
+  if (mode & OPEN_READ)
+    {
+      exec_cmd (midi_dev, 0x34, 0);	/* Return timing bytes in stop mode */
+      exec_cmd (midi_dev, 0x8B, 0);	/* Enable data in stop mode */
+    }
+
+  return 0;
+}
+
+static void
+mpu_synth_close (int dev)
+{
+  int             midi_dev;
+  struct mpu_config *devc;
+
+  midi_dev = synth_devs[dev]->midi_dev;
+
+  devc = &dev_conf[midi_dev];
+  exec_cmd (midi_dev, 0x15, 0);	/* Stop recording, playback and MIDI */
+  exec_cmd (midi_dev, 0x8a, 0);	/* Disable data in stopped mode */
+
+  devc->opened = 0;
+  devc->mode = 0;
+  snd_release_irq (devc->irq);
+  devc->inputintr = NULL;
+  irq2dev[devc->irq] = -1;
 }
 
-static struct midi_operations mpu401_operations =
+#define MIDI_SYNTH_NAME	"MPU-401 UART Midi"
+#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
+static struct synth_operations mpu401_synth_proto =
+{
+  NULL,
+  0,
+  SYNTH_TYPE_MIDI,
+  0,
+  mpu_synth_open,
+  mpu_synth_close,
+  mpu_synth_ioctl,
+  midi_synth_kill_note,
+  midi_synth_start_note,
+  midi_synth_set_instr,
+  midi_synth_reset,
+  midi_synth_hw_control,
+  midi_synth_load_patch,
+  midi_synth_aftertouch,
+  midi_synth_controller,
+  midi_synth_panning,
+  NULL,
+  midi_synth_patchmgr,
+  midi_synth_bender
+};
+
+static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV];
+
+static struct midi_operations mpu401_midi_proto =
 {
-  {"MPU-401", 0, 0, SNDCARD_MPU401},
+  {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
+  NULL,
   mpu401_open,
   mpu401_close,
   mpu401_ioctl,
@@ -178,100 +946,776 @@
   mpu401_start_read,
   mpu401_end_read,
   mpu401_kick,
-  mpu401_command,
-  mpu401_buffer_status
+  NULL,
+  mpu401_buffer_status,
+  mpu401_prefix_cmd
 };
 
+static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
+
+static void
+mpu401_chk_version (struct mpu_config *devc)
+{
+  int             tmp;
+
+  devc->version = devc->revision = 0;
+
+  if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0)
+    return;
+  devc->version = tmp;
+
+  if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0)
+    return;
+  devc->revision = tmp;
+}
 
 long
 attach_mpu401 (long mem_start, struct address_info *hw_config)
 {
-  int             ok, timeout;
+  int             i;
   unsigned long   flags;
+  char            revision_char;
 
-  mpu401_base = hw_config->io_base;
-  mpu401_irq = hw_config->irq;
+  struct mpu_config *devc;
 
-  if (!mpu401_detected)
-    return RET_ERROR (EIO);
+  for (i = 0; i < 16; i++)
+    irq2dev[i] = -1;
 
-  DISABLE_INTR (flags);
-  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/* Wait */
-  mpu401_cmd (UART_MODE_ON);
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("MPU-401: Too many midi devices detected\n");
+      return mem_start;
+    }
 
-  ok = 0;
-  for (timeout = 50000; timeout > 0 && !ok; timeout--)
-    if (input_avail ())
-      if (mpu401_read () == MPU_ACK)
-	ok = 1;
+  devc = &dev_conf[num_midis];
 
+  devc->base = hw_config->io_base;
+  devc->irq = hw_config->irq;
+  devc->opened = 0;
+  devc->uart_mode = 0;
+  devc->initialized = 0;
+  devc->version = 0;
+  devc->revision = 0;
+  devc->capabilities = 0;
+  devc->timer_flag = 0;
+  devc->m_busy = 0;
+  devc->m_state = ST_INIT;
+
+  for (i = 0; i < 32; i++)
+    devc->controls[i] = 0x2000;
+
+  if (!reset_mpu401 (devc))
+    return mem_start;
+
+  DISABLE_INTR (flags);
+  mpu401_chk_version (devc);
+  if (devc->version == 0)
+    mpu401_chk_version (devc);
   RESTORE_INTR (flags);
 
-  printk (" <Roland MPU-401>");
+  if (devc->version == 0)
+    {
+      memcpy ((char *) &mpu401_synth_operations[num_midis],
+	      (char *) &std_midi_synth,
+	      sizeof (struct synth_operations));
+    }
+  else
+    {
+      devc->capabilities |= MPU_CAP_INTLG;	/* Supports intelligent mode */
+      memcpy ((char *) &mpu401_synth_operations[num_midis],
+	      (char *) &mpu401_synth_proto,
+	      sizeof (struct synth_operations));
+    }
+
+  memcpy ((char *) &mpu401_midi_operations[num_midis],
+	  (char *) &mpu401_midi_proto,
+	  sizeof (struct midi_operations));
+
+  mpu401_midi_operations[num_midis].converter =
+    &mpu401_synth_operations[num_midis];
+
+  memcpy ((char *) &mpu_synth_info[num_midis],
+	  (char *) &mpu_synth_info_proto,
+	  sizeof (struct synth_info));
+
+  n_mpu_devs++;
+
+  if (devc->version == 0x20 && devc->revision >= 0x07)	/* MusicQuest interface */
+    {
+      int             ports = (devc->revision & 0x08) ? 32 : 16;
+
+      devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE |
+	MPU_CAP_CLS | MPU_CAP_2PORT;
+
+      revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
+      printk (" <MQX-%d%c MIDI Interface>",
+	      ports,
+	      revision_char);
+#ifndef SCO
+      sprintf (mpu_synth_info[num_midis].name,
+	       "MQX-%d%c MIDI Interface #%d",
+	       ports,
+	       revision_char,
+	       n_mpu_devs);
+#endif
+    }
+  else
+    {
+
+      revision_char = devc->revision ? devc->revision + '@' : ' ';
+      if (devc->revision > ('Z' - '@'))
+	revision_char = '+';
+
+      devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
+
+      printk (" <MPU-401 MIDI Interface %d.%d%c>",
+	      (devc->version & 0xf0) >> 4,
+	      devc->version & 0x0f,
+	      revision_char);
+#ifndef SCO
+      sprintf (mpu_synth_info[num_midis].name,
+	       "MPU-401 %d.%d%c Midi interface #%d",
+	       (devc->version & 0xf0) >> 4,
+	       devc->version & 0x0f,
+	       revision_char,
+	       n_mpu_devs);
+#endif
+    }
+
+#ifndef SCO
+  strcpy (mpu401_midi_operations[num_midis].info.name,
+	  mpu_synth_info[num_midis].name);
+#endif
+
+  mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis;
+  mpu401_synth_operations[devc->devno].info =
+    &mpu_synth_info[devc->devno];
 
-  my_dev = num_midis;
-  mpu401_dev = num_midis;
-  midi_devs[num_midis++] = &mpu401_operations;
+  if (devc->capabilities & MPU_CAP_INTLG)	/* Has timer */
+    mpu_timer_init (num_midis);
+
+  midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno];
   return mem_start;
 }
 
 static int
-reset_mpu401 (void)
+reset_mpu401 (struct mpu_config *devc)
 {
   unsigned long   flags;
   int             ok, timeout, n;
+  int             timeout_limit;
 
   /*
    * Send the RESET command. Try again if no success at the first time.
+   * (If the device is in the UART mode, it will not ack the reset cmd).
    */
 
   ok = 0;
 
-  DISABLE_INTR (flags);
+  timeout_limit = devc->initialized ? 30000 : 100000;
+  devc->initialized = 1;
 
   for (n = 0; n < 2 && !ok; n++)
     {
-      for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/* Wait */
-      mpu401_cmd (MPU_RESET);	/* Send MPU-401 RESET Command */
+      for (timeout = timeout_limit; timeout > 0 && !ok; timeout--)
+	ok = output_ready (devc->base);
+
+      write_command (devc->base, 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_avail ())
-	  if (mpu401_read () == MPU_ACK)
-	    ok = 1;
+      for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--)
+	{
+	  DISABLE_INTR (flags);
+	  if (input_avail (devc->base))
+	    if (read_data (devc->base) == MPU_ACK)
+	      ok = 1;
+	  RESTORE_INTR (flags);
+	}
 
     }
 
-  mpu401_opened = 0;
-  if (ok)
-    mpuintr (0);		/* Flush input before enabling interrupts */
+  devc->m_state = ST_INIT;
+  devc->m_ptr = 0;
+  devc->m_left = 0;
+  devc->last_status = 0;
+  devc->uart_mode = 0;
 
-  RESTORE_INTR (flags);
-
   return ok;
 }
 
+static void
+set_uart_mode (int dev, struct mpu_config *devc, int arg)
+{
+
+  if (!arg && devc->version == 0)
+    return;
+
+  if ((devc->uart_mode == 0) == (arg == 0))
+    return;			/* Already set */
 
+  reset_mpu401 (devc);		/* This exits the uart mode */
+
+  if (arg)
+    {
+      if (exec_cmd (dev, UART_MODE_ON, 0) < 0)
+	{
+	  printk ("MPU%d: Can't enter UART mode\n", devc->devno);
+	  devc->uart_mode = 0;
+	  return;
+	}
+    }
+  devc->uart_mode = arg;
+
+}
+
 int
 probe_mpu401 (struct address_info *hw_config)
 {
   int             ok = 0;
+  struct mpu_config tmp_devc;
+
+  tmp_devc.base = hw_config->io_base;
+  tmp_devc.irq = hw_config->irq;
+  tmp_devc.initialized = 0;
+
+  ok = reset_mpu401 (&tmp_devc);
+
+  return ok;
+}
+
+/*****************************************************
+ *      Timer stuff
+ ****************************************************/
+
+#if !defined(EXCLUDE_SEQUENCER)
+
+static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0;
+static volatile int curr_tempo, curr_timebase, hw_timebase;
+static int      max_timebase = 8;	/* 8*24=192 ppqn */
+static volatile unsigned long next_event_time;
+static volatile unsigned long curr_ticks, curr_clocks;
+static unsigned long prev_event_time;
+static int      metronome_mode;
+
+static unsigned long
+clocks2ticks (unsigned long clocks)
+{
+  /*
+ * 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 it's best and to convert between the HW and
+ * actual timebases.
+ */
+
+  return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase;
+}
+
+static void
+set_timebase (int midi_dev, int val)
+{
+  int             hw_val;
+
+  if (val < 48)
+    val = 48;
+  if (val > 1000)
+    val = 1000;
+
+  hw_val = val;
+  hw_val = (hw_val + 23) / 24;
+  if (hw_val > max_timebase)
+    hw_val = max_timebase;
+
+  if (exec_cmd (midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0)
+    {
+      printk ("MPU: Can't set HW timebase to %d\n", hw_val * 24);
+      return;
+    }
+  hw_timebase = hw_val * 24;
+  curr_timebase = val;
+
+}
+
+static void
+tmr_reset (void)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  next_event_time = 0xffffffff;
+  prev_event_time = 0;
+  curr_ticks = curr_clocks = 0;
+  RESTORE_INTR (flags);
+}
+
+static void
+set_timer_mode (int midi_dev)
+{
+  if (timer_mode & TMR_MODE_CLS)
+    exec_cmd (midi_dev, 0x3c, 0);	/* Use CLS sync */
+  else if (timer_mode & TMR_MODE_SMPTE)
+    exec_cmd (midi_dev, 0x3d, 0);	/* Use SMPTE sync */
+
+  if (timer_mode & TMR_INTERNAL)
+    {
+      exec_cmd (midi_dev, 0x80, 0);	/* Use MIDI sync */
+    }
+  else
+    {
+      if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))
+	{
+	  exec_cmd (midi_dev, 0x82, 0);	/* Use MIDI sync */
+	  exec_cmd (midi_dev, 0x91, 0);	/* Enable ext MIDI ctrl */
+	}
+      else if (timer_mode & TMR_MODE_FSK)
+	exec_cmd (midi_dev, 0x81, 0);	/* Use FSK sync */
+    }
+}
+
+static void
+stop_metronome (int midi_dev)
+{
+  exec_cmd (midi_dev, 0x84, 0);	/* Disable metronome */
+}
+
+static void
+setup_metronome (int midi_dev)
+{
+  int             numerator, denominator;
+  int             clks_per_click, num_32nds_per_beat;
+  int             beats_per_measure;
+
+  numerator = ((unsigned) metronome_mode >> 24) & 0xff;
+  denominator = ((unsigned) metronome_mode >> 16) & 0xff;
+  clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff;
+  num_32nds_per_beat = (unsigned) metronome_mode & 0xff;
+  beats_per_measure = (numerator * 4) >> denominator;
+
+  if (!metronome_mode)
+    exec_cmd (midi_dev, 0x84, 0);	/* Disable metronome */
+  else
+    {
+      exec_cmd (midi_dev, 0xE4, clks_per_click);
+      exec_cmd (midi_dev, 0xE6, beats_per_measure);
+      exec_cmd (midi_dev, 0x83, 0);	/* Enable metronome without accents */
+    }
+}
+
+static int
+start_timer (int midi_dev)
+{
+  tmr_reset ();
+  set_timer_mode (midi_dev);
 
-  mpu401_base = hw_config->io_base;
-  mpu401_irq = hw_config->irq;
+  if (tmr_running)
+    return TIMER_NOT_ARMED;	/* Already running */
 
-  if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0)
+  if (timer_mode & TMR_INTERNAL)
+    {
+      exec_cmd (midi_dev, 0x02, 0);	/* Send MIDI start */
+      tmr_running = 1;
+      return TIMER_NOT_ARMED;
+    }
+  else
+    {
+      exec_cmd (midi_dev, 0x35, 0);	/* Enable mode messages to PC */
+      exec_cmd (midi_dev, 0x38, 0);	/* Enable sys common messages to PC */
+      exec_cmd (midi_dev, 0x39, 0);	/* Enable real time messages to PC */
+      exec_cmd (midi_dev, 0x97, 0);	/* Enable system exclusive messages to PC */
+    }
+
+  return TIMER_ARMED;
+}
+
+static int
+mpu_timer_open (int dev, int mode)
+{
+  int             midi_dev = sound_timer_devs[dev]->devlink;
+
+  if (timer_open)
+    return RET_ERROR (EBUSY);
+
+  tmr_reset ();
+  curr_tempo = 50;
+  exec_cmd (midi_dev, 0xE0, 50);
+  curr_timebase = hw_timebase = 120;
+  set_timebase (midi_dev, 120);
+  timer_open = 1;
+  metronome_mode = 0;
+  set_timer_mode (midi_dev);
+
+  exec_cmd (midi_dev, 0xe7, 0x04);	/* Send all clocks to host */
+  exec_cmd (midi_dev, 0x95, 0);	/* Enable clock to host */
+
+  return 0;
+}
+
+static void
+mpu_timer_close (int dev)
+{
+  int             midi_dev = sound_timer_devs[dev]->devlink;
+
+  timer_open = tmr_running = 0;
+  exec_cmd (midi_dev, 0x15, 0);	/* Stop all */
+  exec_cmd (midi_dev, 0x94, 0);	/* Disable clock to host */
+  exec_cmd (midi_dev, 0x8c, 0);	/* Disable measure end messages to host */
+  stop_metronome (midi_dev);
+}
+
+static int
+mpu_timer_event (int dev, unsigned char *event)
+{
+  unsigned char   command = event[1];
+  unsigned long   parm = *(unsigned int *) &event[4];
+  int             midi_dev = sound_timer_devs[dev]->devlink;
+
+  switch (command)
+    {
+    case TMR_WAIT_REL:
+      parm += prev_event_time;
+    case TMR_WAIT_ABS:
+      if (parm > 0)
+	{
+	  long            time;
+
+	  if (parm <= curr_ticks)	/* It's the time */
+	    return TIMER_NOT_ARMED;
+
+	  time = parm;
+	  next_event_time = prev_event_time = time;
+
+	  return TIMER_ARMED;
+	}
+      break;
+
+    case TMR_START:
+      if (tmr_running)
+	break;
+      return start_timer (midi_dev);
+      break;
+
+    case TMR_STOP:
+      exec_cmd (midi_dev, 0x01, 0);	/* Send MIDI stop */
+      stop_metronome (midi_dev);
+      tmr_running = 0;
+      break;
+
+    case TMR_CONTINUE:
+      if (tmr_running)
+	break;
+      exec_cmd (midi_dev, 0x03, 0);	/* Send MIDI continue */
+      setup_metronome (midi_dev);
+      tmr_running = 1;
+      break;
+
+    case TMR_TEMPO:
+      if (parm)
+	{
+	  if (parm < 8)
+	    parm = 8;
+	  if (parm > 250)
+	    parm = 250;
+
+	  if (exec_cmd (midi_dev, 0xE0, parm) < 0)
+	    printk ("MPU: Can't set tempo to %d\n", (int) parm);
+	  curr_tempo = parm;
+	}
+      break;
+
+    case TMR_ECHO:
+      seq_copy_to_input (event, 8);
+      break;
+
+    case TMR_TIMESIG:
+      if (metronome_mode)	/* Metronome enabled */
+	{
+	  metronome_mode = parm;
+	  setup_metronome (midi_dev);
+	}
+      break;
+
+    default:;
+    }
+
+  return TIMER_NOT_ARMED;
+}
+
+static unsigned long
+mpu_timer_get_time (int dev)
+{
+  if (!timer_open)
     return 0;
 
-  ok = reset_mpu401 ();
+  return curr_ticks;
+}
 
-  mpu401_detected = ok;
-  return ok;
+static int
+mpu_timer_ioctl (int dev,
+		 unsigned int command, unsigned int arg)
+{
+  int             midi_dev = sound_timer_devs[dev]->devlink;
+
+  switch (command)
+    {
+    case SNDCTL_TMR_SOURCE:
+      {
+	int             parm = IOCTL_IN (arg) & timer_caps;
+
+	if (parm != 0)
+	  {
+	    timer_mode = parm;
+
+	    if (timer_mode & TMR_MODE_CLS)
+	      exec_cmd (midi_dev, 0x3c, 0);	/* Use CLS sync */
+	    else if (timer_mode & TMR_MODE_SMPTE)
+	      exec_cmd (midi_dev, 0x3d, 0);	/* Use SMPTE sync */
+	  }
+
+	return IOCTL_OUT (arg, timer_mode);
+      }
+      break;
+
+    case SNDCTL_TMR_START:
+      if (tmr_running)
+	return 0;
+      start_timer (midi_dev);
+      return 0;
+      break;
+
+    case SNDCTL_TMR_STOP:
+      tmr_running = 0;
+      exec_cmd (midi_dev, 0x01, 0);	/* Send MIDI stop */
+      stop_metronome (midi_dev);
+      return 0;
+      break;
+
+    case SNDCTL_TMR_CONTINUE:
+      if (tmr_running)
+	return 0;
+      tmr_running = 1;
+      exec_cmd (midi_dev, 0x03, 0);	/* Send MIDI continue */
+      return 0;
+      break;
+
+    case SNDCTL_TMR_TIMEBASE:
+      {
+	int             val = IOCTL_IN (arg);
+
+	if (val)
+	  set_timebase (midi_dev, val);
+
+	return IOCTL_OUT (arg, curr_timebase);
+      }
+      break;
+
+    case SNDCTL_TMR_TEMPO:
+      {
+	int             val = IOCTL_IN (arg);
+	int             ret;
+
+	if (val)
+	  {
+	    if (val < 8)
+	      val = 8;
+	    if (val > 250)
+	      val = 250;
+	    if ((ret = exec_cmd (midi_dev, 0xE0, val)) < 0)
+	      {
+		printk ("MPU: Can't set tempo to %d\n", (int) val);
+		return ret;
+	      }
+
+	    curr_tempo = val;
+	  }
+
+	return IOCTL_OUT (arg, curr_tempo);
+      }
+      break;
+
+    case SNDCTL_SEQ_CTRLRATE:
+      if (IOCTL_IN (arg) != 0)	/* Can't change */
+	return RET_ERROR (EINVAL);
+
+      return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+      break;
+
+    case SNDCTL_TMR_METRONOME:
+      metronome_mode = IOCTL_IN (arg);
+      setup_metronome (midi_dev);
+      return 0;
+      break;
+
+    default:
+    }
+
+  return RET_ERROR (EINVAL);
+}
+
+static void
+mpu_timer_arm (int dev, long time)
+{
+  if (time < 0)
+    time = curr_ticks + 1;
+  else if (time <= curr_ticks)	/* It's the time */
+    return;
+
+  next_event_time = prev_event_time = time;
+
+  return;
+}
+
+static struct sound_timer_operations mpu_timer =
+{
+  {"MPU-401 Timer", 0},
+  10,				/* Priority */
+  0,				/* Local device link */
+  mpu_timer_open,
+  mpu_timer_close,
+  mpu_timer_event,
+  mpu_timer_get_time,
+  mpu_timer_ioctl,
+  mpu_timer_arm
+};
+
+static void
+mpu_timer_interrupt (void)
+{
+
+  if (!timer_open)
+    return;
+
+  if (!tmr_running)
+    return;
+
+  curr_clocks++;
+  curr_ticks = clocks2ticks (curr_clocks);
+
+  if (curr_ticks >= next_event_time)
+    {
+      next_event_time = 0xffffffff;
+      sequencer_timer ();
+    }
+}
+
+static void
+timer_ext_event (struct mpu_config *devc, int event, int parm)
+{
+  int             midi_dev = devc->devno;
+
+  if (!devc->timer_flag)
+    return;
+
+  switch (event)
+    {
+    case TMR_CLOCK:
+      printk ("<MIDI clk>");
+      break;
+
+    case TMR_START:
+      printk ("Ext MIDI start\n");
+      if (!tmr_running)
+	if (timer_mode & TMR_EXTERNAL)
+	  {
+	    tmr_running = 1;
+	    setup_metronome (midi_dev);
+	    next_event_time = 0;
+	    STORE (SEQ_START_TIMER ());
+	  }
+      break;
+
+    case TMR_STOP:
+      printk ("Ext MIDI stop\n");
+      if (timer_mode & TMR_EXTERNAL)
+	{
+	  tmr_running = 0;
+	  stop_metronome (midi_dev);
+	  STORE (SEQ_STOP_TIMER ());
+	}
+      break;
+
+    case TMR_CONTINUE:
+      printk ("Ext MIDI continue\n");
+      if (timer_mode & TMR_EXTERNAL)
+	{
+	  tmr_running = 1;
+	  setup_metronome (midi_dev);
+	  STORE (SEQ_CONTINUE_TIMER ());
+	}
+      break;
+
+    case TMR_SPP:
+      printk ("Songpos: %d\n", parm);
+      if (timer_mode & TMR_EXTERNAL)
+	{
+	  STORE (SEQ_SONGPOS (parm));
+	}
+      break;
+    }
+}
+
+static void
+mpu_timer_init (int midi_dev)
+{
+  struct mpu_config *devc;
+  int             n;
+
+  devc = &dev_conf[midi_dev];
+
+  if (timer_initialized)
+    return;			/* There is already a similar timer */
+
+  timer_initialized = 1;
+
+  mpu_timer.devlink = midi_dev;
+  dev_conf[midi_dev].timer_flag = 1;
+
+#if 1
+  if (num_sound_timers >= MAX_TIMER_DEV)
+    n = 0;			/* Overwrite the system timer */
+  else
+    n = num_sound_timers++;
+#else
+  n = 0;
+#endif
+  sound_timer_devs[n] = &mpu_timer;
+
+  if (devc->version < 0x20)	/* Original MPU-401 */
+    timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI;
+  else
+    {
+      /*
+         * The version number 2.0 is used (at least) by the
+         * MusicQuest cards and the Roland Super-MPU.
+         *
+         * MusicQuest has given a special meaning to the bits of the
+         * revision number. The Super-MPU returns 0.
+       */
+
+      if (devc->revision)
+	timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI;
+
+      if (devc->revision & 0x02)
+	timer_caps |= TMR_MODE_CLS;
+
+#if 0
+      if (devc->revision & 0x04)
+	timer_caps |= TMR_MODE_SMPTE;
+#endif
+
+      if (devc->revision & 0x40)
+	max_timebase = 10;	/* Has the 216 and 240 ppqn modes */
+    }
+
+  timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps;
+
 }
+
+#endif
 
 #endif
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v1.1.30/linux/drivers/sound/opl3.c	Sun May  1 12:12:35 1994
+++ linux/drivers/sound/opl3.c	Mon Jul 18 09:50:55 1994
@@ -27,8 +27,12 @@
  *
  */
 
-/* Major improvements to the FM handling 30AUG92 by Rob Hooft, */
-/* hooft@chem.ruu.nl */
+/*
+ * Major improvements to the FM handling 30AUG92 by Rob Hooft,
+ */
+/*
+ * hooft@chem.ruu.nl
+ */
 
 #include "sound_config.h"
 
@@ -37,8 +41,9 @@
 #include "opl3.h"
 
 #define MAX_VOICE	18
-#define OFFS_4OP	11	/* Definitions for the operators OP3 and OP4
-				   * begin here */
+#define OFFS_4OP	11	/*
+				   * * * Definitions for the operators OP3 and
+				   * * OP4 * * begin here   */
 
 static int      opl3_enabled = 0;
 static int      left_address = 0x388, right_address = 0x388, both_address = 0;
@@ -58,24 +63,30 @@
   };
 
 static struct voice_info voices[MAX_VOICE];
+static struct voice_alloc_info *voice_alloc;
+static struct channel_info *chn_info;
 
 static struct sbi_instrument *instrmap;
 static struct sbi_instrument *active_instrument[MAX_VOICE] =
 {NULL};
 
 static struct synth_info fm_info =
-{"AdLib", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0};
+{"OPL-2", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0};
 
 static int      already_initialized = 0;
 
 static int      opl3_ok = 0;
 static int      opl3_busy = 0;
-static int      fm_model = 0;	/* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2       */
+static int      fm_model = 0;	/*
 
+
+				 * *  * * 0=no fm, 1=mono, 2=SB Pro 1, 3=SB
+				 * Pro 2 * *    */
+
 static int      store_instr (int instr_no, struct sbi_instrument *instr);
 static void     freq_to_fnum (int freq, int *block, int *fnum);
 static void     opl3_command (int io_addr, unsigned int addr, unsigned int val);
-static int      opl3_kill_note (int dev, int voice, int velocity);
+static int      opl3_kill_note (int dev, int voice, int note, int velocity);
 static unsigned char connection_mask = 0x00;
 
 void
@@ -99,9 +110,9 @@
   static int      voices_4op[MAX_VOICE] =
   {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17};
 
-  connection_mask = 0x3f;
-  opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f);	/* Select all 4-OP
-									 * voices */
+  connection_mask = 0x3f;	/* Connect all possible 4 OP voices */
+  opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f);
+
   for (i = 0; i < 3; i++)
     physical_voices[i].voice_mode = 4;
   for (i = 3; i < 6; i++)
@@ -114,7 +125,7 @@
 
   for (i = 0; i < 12; i++)
     logical_voices[i] = voices_4op[i];
-  nr_voices = 12;
+  voice_alloc->max_voice = nr_voices = 12;
 }
 
 static int
@@ -183,66 +194,111 @@
 
   if (already_initialized)
     {
-      return 0;			/* Do avoid duplicate initializations */
+      return 0;			/*
+				 * Do avoid duplicate initializations
+				 */
     }
 
   if (opl3_enabled)
     ioaddr = left_address;
 
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);	/* Reset timers 1 and 2 */
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);	/* Reset the IRQ of FM
-								 * chicp */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);	/*
+										 * Reset
+										 * timers
+										 * 1
+										 * and
+										 * 2
+										 */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);	/*
+								 * Reset the
+								 * IRQ of FM
+								 * * chicp
+								 */
+
+  stat1 = INB (ioaddr);		/*
+				 * Read status register
+				 */
 
-  stat1 = INB (ioaddr);		/* Read status register */
-
   if ((stat1 & 0xE0) != 0x00)
     {
-      return 0;			/* Should be 0x00        */
+      return 0;			/*
+				 * Should be 0x00
+				 */
     }
 
-  opl3_command (ioaddr, TIMER1_REGISTER, 0xff);	/* Set timer 1 to 0xff */
+  opl3_command (ioaddr, TIMER1_REGISTER, 0xff);	/*
+							 * Set timer 1 to
+							 * 0xff
+							 */
   opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
-		TIMER2_MASK | TIMER1_START);	/* Unmask and start timer 1 */
+		TIMER2_MASK | TIMER1_START);	/*
+						 * Unmask and start timer 1
+						 */
 
   /*
    * Now we have to delay at least 80 msec
    */
 
   for (i = 0; i < 50; i++)
-    tenmicrosec ();		/* To be sure */
-
-  stat2 = INB (ioaddr);		/* Read status after timers have expired */
+    tenmicrosec ();		/*
+				 * To be sure
+				 */
+
+  stat2 = INB (ioaddr);		/*
+				 * Read status after timers have expired
+				 */
 
-  /* Stop the timers */
+  /*
+   * Stop the timers
+   */
 
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);	/* Reset timers 1 and 2 */
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);	/* Reset the IRQ of FM
-								 * chicp */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);	/*
+										 * Reset
+										 * timers
+										 * 1
+										 * and
+										 * 2
+										 */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);	/*
+								 * Reset the
+								 * IRQ of FM
+								 * * chicp
+								 */
 
   if ((stat2 & 0xE0) != 0xc0)
     {
-      return 0;			/* There is no YM3812 */
+      return 0;			/*
+				 * There is no YM3812
+				 */
     }
 
-  /* There is a FM chicp in this address. Now set some default values. */
+  /*
+   * There is a FM chicp in this address. Now set some default values.
+   */
 
   for (i = 0; i < 9; i++)
-    opl3_command (ioaddr, KEYON_BLOCK + i, 0);	/* Note off */
+    opl3_command (ioaddr, KEYON_BLOCK + i, 0);	/*
+						 * Note off
+						 */
 
   opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT);
-  opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00);	/* Melodic mode. */
+  opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00);	/*
+							 * Melodic mode.
+							 */
 
   return 1;
 }
 
 static int
-opl3_kill_note (int dev, int voice, int velocity)
+opl3_kill_note (int dev, int voice, int note, int velocity)
 {
   struct physical_voice_info *map;
 
   if (voice < 0 || voice >= nr_voices)
     return 0;
 
+  voice_alloc->map[voice] = 0;
+
   map = &physical_voices[logical_voices[voice]];
 
   DEB (printk ("Kill note %d\n", voice));
@@ -254,7 +310,9 @@
 
   voices[voice].keyon_byte = 0;
   voices[voice].bender = 0;
-  voices[voice].bender_range = 200;	/* 200 cents = 2 semitones */
+  voices[voice].bender_range = 200;	/*
+					 * 200 cents = 2 semitones
+					 */
   voices[voice].orig_freq = 0;
   voices[voice].current_freq = 0;
   voices[voice].mode = 0;
@@ -304,23 +362,56 @@
  * it saves a lot of log() calculations. (RH)
  */
 char            fm_volume_table[128] =
-{-64, -48, -40, -35, -32, -29, -27, -26,	/* 0 -   7 */
- -24, -23, -21, -20, -19, -18, -18, -17,	/* 8 -  15 */
- -16, -15, -15, -14, -13, -13, -12, -12,	/* 16 -  23 */
- -11, -11, -10, -10, -10, -9, -9, -8,	/* 24 -  31 */
- -8, -8, -7, -7, -7, -6, -6, -6,/* 32 -  39 */
- -5, -5, -5, -5, -4, -4, -4, -4,/* 40 -  47 */
- -3, -3, -3, -3, -2, -2, -2, -2,/* 48 -  55 */
- -2, -1, -1, -1, -1, 0, 0, 0,	/* 56 -  63 */
- 0, 0, 0, 1, 1, 1, 1, 1,	/* 64 -  71 */
- 1, 2, 2, 2, 2, 2, 2, 2,	/* 72 -  79 */
- 3, 3, 3, 3, 3, 3, 3, 4,	/* 80 -  87 */
- 4, 4, 4, 4, 4, 4, 4, 5,	/* 88 -  95 */
- 5, 5, 5, 5, 5, 5, 5, 5,	/* 96 - 103 */
- 6, 6, 6, 6, 6, 6, 6, 6,	/* 104 - 111 */
- 6, 7, 7, 7, 7, 7, 7, 7,	/* 112 - 119 */
- 7, 7, 7, 8, 8, 8, 8, 8};	/* 120 - 127 */
+{-64, -48, -40, -35, -32, -29, -27, -26,	/*
+						 * 0 -   7
+						 */
+ -24, -23, -21, -20, -19, -18, -18, -17,	/*
+						 * 8 -  15
+						 */
+ -16, -15, -15, -14, -13, -13, -12, -12,	/*
+						 * 16 -  23
+						 */
+ -11, -11, -10, -10, -10, -9, -9, -8,	/*
+					 * 24 -  31
+					 */
+ -8, -8, -7, -7, -7, -6, -6, -6,/*
+					 * 32 -  39
+					 */
+ -5, -5, -5, -5, -4, -4, -4, -4,/*
+					 * 40 -  47
+					 */
+ -3, -3, -3, -3, -2, -2, -2, -2,/*
+					 * 48 -  55
+					 */
+ -2, -1, -1, -1, -1, 0, 0, 0,	/*
+				 * 56 -  63
+				 */
+ 0, 0, 0, 1, 1, 1, 1, 1,	/*
+				 * 64 -  71
+				 */
+ 1, 2, 2, 2, 2, 2, 2, 2,	/*
+				 * 72 -  79
+				 */
+ 3, 3, 3, 3, 3, 3, 3, 4,	/*
+				 * 80 -  87
+				 */
+ 4, 4, 4, 4, 4, 4, 4, 5,	/*
+				 * 88 -  95
+				 */
+ 5, 5, 5, 5, 5, 5, 5, 5,	/*
+				 * 96 - 103
+				 */
+ 6, 6, 6, 6, 6, 6, 6, 6,	/*
+				 * 104 - 111
+				 */
+ 6, 7, 7, 7, 7, 7, 7, 7,	/*
+				 * 112 - 119
+				 */
+ 7, 7, 7, 8, 8, 8, 8, 8};	/*
 
+
+				 * *  * * 120 - 127   */
+
 static void
 calc_vol (unsigned char *regbyte, int volume)
 {
@@ -361,26 +452,40 @@
     return;
 
   if (voices[voice].mode == 2)
-    {				/* 2 OP voice */
+    {				/*
+				 * 2 OP voice
+				 */
 
       vol1 = instr->operators[2];
       vol2 = instr->operators[3];
 
       if ((instr->operators[10] & 0x01))
-	{			/* Additive synthesis    */
+	{			/*
+				 * Additive synthesis
+				 */
 	  calc_vol (&vol1, volume);
 	  calc_vol (&vol2, volume);
 	}
       else
-	{			/* FM synthesis */
+	{			/*
+				 * FM synthesis
+				 */
 	  calc_vol (&vol2, volume);
 	}
 
-      opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);	/* Modulator volume */
-      opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);	/* Carrier volume */
+      opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);	/*
+									 * Modulator
+									 * volume
+									 */
+      opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);	/*
+									 * Carrier
+									 * volume
+									 */
     }
   else
-    {				/* 4 OP voice */
+    {				/*
+				 * 4 OP voice
+				 */
       int             connection;
 
       vol1 = instr->operators[2];
@@ -398,7 +503,9 @@
       switch (connection)
 	{
 	case 0:
-	  calc_vol (&vol4, volume);	/* Just the OP 4 is carrier */
+	  calc_vol (&vol4, volume);	/*
+					 * Just the OP 4 is carrier
+					 */
 	  break;
 
 	case 1:
@@ -417,7 +524,9 @@
 	  calc_vol (&vol4, volume);
 	  break;
 
-	default:/* Why ?? */ ;
+	default:		/*
+				 * Why ??
+	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  				 */ ;
 	}
 
       opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
@@ -443,15 +552,26 @@
   if (map->voice_mode == 0)
     return 0;
 
-  if (note == 255)		/* Just change the volume */
+  if (note == 255)		/*
+				 * Just change the volume
+				 */
     {
       set_voice_volume (voice, volume);
       return 0;
     }
 
-  /* Kill previous note before playing */
-  opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff);	/* Carrier volume to min */
-  opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff);	/* Modulator volume to */
+  /*
+   * Kill previous note before playing
+   */
+  opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff);	/*
+								 * Carrier
+								 * volume to
+								 * min
+								 */
+  opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff);	/*
+								 * Modulator
+								 * volume to
+								 */
 
   if (map->voice_mode == 4)
     {
@@ -459,7 +579,10 @@
       opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff);
     }
 
-  opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00);	/* Note off */
+  opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00);	/*
+									 * Note
+									 * off
+									 */
 
   instr = active_instrument[voice];
 
@@ -475,7 +598,9 @@
     }
 
   if (map->voice_mode == 2 && instr->key == OPL3_PATCH)
-    return 0;			/* Cannot play */
+    return 0;			/*
+				 * Cannot play
+				 */
 
   voice_mode = map->voice_mode;
 
@@ -486,7 +611,9 @@
       voice_shift = (map->ioaddr == left_address) ? 0 : 3;
       voice_shift += map->voice_num;
 
-      if (instr->key != OPL3_PATCH)	/* Just 2 OP patch */
+      if (instr->key != OPL3_PATCH)	/*
+					 * Just 2 OP patch
+					 */
 	{
 	  voice_mode = 2;
 	  connection_mask &= ~(1 << voice_shift);
@@ -499,26 +626,38 @@
       opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
     }
 
-  /* Set Sound Characteristics */
+  /*
+   * Set Sound Characteristics
+   */
   opl3_command (map->ioaddr, AM_VIB + map->op[0], instr->operators[0]);
   opl3_command (map->ioaddr, AM_VIB + map->op[1], instr->operators[1]);
 
-  /* Set Attack/Decay */
+  /*
+   * Set Attack/Decay
+   */
   opl3_command (map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]);
   opl3_command (map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]);
 
-  /* Set Sustain/Release */
+  /*
+   * Set Sustain/Release
+   */
   opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]);
   opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]);
 
-  /* Set Wave Select */
+  /*
+   * Set Wave Select
+   */
   opl3_command (map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]);
   opl3_command (map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]);
 
-  /* Set Feedback/Connection */
+  /*
+   * Set Feedback/Connection
+   */
   fpc = instr->operators[10];
   if (!(fpc & 0x30))
-    fpc |= 0x30;		/* Ensure that at least one chn is enabled */
+    fpc |= 0x30;		/*
+				 * Ensure that at least one chn is enabled
+				 */
   opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num,
 		fpc);
 
@@ -529,26 +668,38 @@
   if (voice_mode == 4)
     {
 
-      /* Set Sound Characteristics */
+      /*
+       * Set Sound Characteristics
+       */
       opl3_command (map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]);
       opl3_command (map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]);
 
-      /* Set Attack/Decay */
+      /*
+       * Set Attack/Decay
+       */
       opl3_command (map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]);
       opl3_command (map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]);
 
-      /* Set Sustain/Release */
+      /*
+       * Set Sustain/Release
+       */
       opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]);
       opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]);
 
-      /* Set Wave Select */
+      /*
+       * Set Wave Select
+       */
       opl3_command (map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]);
       opl3_command (map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]);
 
-      /* Set Feedback/Connection */
+      /*
+       * Set Feedback/Connection
+       */
       fpc = instr->operators[OFFS_4OP + 10];
       if (!(fpc & 0x30))
-	fpc |= 0x30;		/* Ensure that at least one chn is enabled */
+	fpc |= 0x30;		/*
+				 * Ensure that at least one chn is enabled
+				 */
       opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc);
     }
 
@@ -568,9 +719,13 @@
 
   freq_to_fnum (freq, &block, &fnum);
 
-  /* Play note */
+  /*
+   * Play note
+   */
 
-  data = fnum & 0xff;		/* Least significant bits of fnumber */
+  data = fnum & 0xff;		/*
+				 * Least significant bits of fnumber
+				 */
   opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
 
   data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
@@ -587,8 +742,12 @@
 {
   int             f, octave;
 
-  /* Converts the note frequency to block and fnum values for the FM chip */
-  /* First try to compute the block -value (octave) where the note belongs */
+  /*
+   * Converts the note frequency to block and fnum values for the FM chip
+   */
+  /*
+   * First try to compute the block -value (octave) where the note belongs
+   */
 
   f = freq;
 
@@ -630,7 +789,10 @@
    * register. The OPL-3 survives with just two INBs
    */
 
-  OUTB ((unsigned char) (addr & 0xff), io_addr);	/* Select register       */
+  OUTB ((unsigned char) (addr & 0xff), io_addr);	/*
+							 * Select register
+							 *
+							 */
 
   if (!opl3_enabled)
     tenmicrosec ();
@@ -638,7 +800,10 @@
     for (i = 0; i < 2; i++)
       INB (io_addr);
 
-  OUTB ((unsigned char) (val & 0xff), io_addr + 1);	/* Write to register  */
+  OUTB ((unsigned char) (val & 0xff), io_addr + 1);	/*
+							 * Write to register
+							 *
+							 */
 
   if (!opl3_enabled)
     {
@@ -659,26 +824,26 @@
   for (i = 0; i < nr_voices; i++)
     {
       opl3_command (physical_voices[logical_voices[i]].ioaddr,
-		KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff);	/* OP1 volume to min */
+		KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff);
 
       opl3_command (physical_voices[logical_voices[i]].ioaddr,
-		KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff);	/* OP2 volume to min */
+		KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff);
 
-      if (physical_voices[logical_voices[i]].voice_mode == 4)	/* 4 OP voice */
+      if (physical_voices[logical_voices[i]].voice_mode == 4)
 	{
 	  opl3_command (physical_voices[logical_voices[i]].ioaddr,
-		KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff);	/* OP3 volume to min */
+		KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff);
 
 	  opl3_command (physical_voices[logical_voices[i]].ioaddr,
-		KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff);	/* OP4 volume to min */
+		KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff);
 	}
 
-      opl3_kill_note (dev, i, 64);
+      opl3_kill_note (dev, i, 0, 64);
     }
 
   if (opl3_enabled)
     {
-      nr_voices = 18;
+      voice_alloc->max_voice = nr_voices = 18;
 
       for (i = 0; i < 18; i++)
 	logical_voices[i] = i;
@@ -699,7 +864,9 @@
     return RET_ERROR (EBUSY);
   opl3_busy = 1;
 
-  connection_mask = 0x00;	/* Just 2 OP voices */
+  connection_mask = 0x00;	/*
+				 * Just 2 OP voices
+				 */
   if (opl3_enabled)
     opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
   return 0;
@@ -709,7 +876,7 @@
 opl3_close (int dev)
 {
   opl3_busy = 0;
-  nr_voices = opl3_enabled ? 18 : 9;
+  voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
   fm_info.nr_drums = 0;
   fm_info.perc_mode = 0;
 
@@ -814,13 +981,17 @@
 	  break;
 
 	}
-      /* Not implemented yet */
+      /*
+       * Not implemented yet
+       */
     }
   else
     {
       SET_VIBRATO (1);
 
-      if ((instr->operators[10] & 0x01))	/* Additive synthesis */
+      if ((instr->operators[10] & 0x01))	/*
+						 * Additive synthesis
+						 */
 	SET_VIBRATO (2);
     }
 }
@@ -828,41 +999,57 @@
 #undef SET_VIBRATO
 
 static void
-opl3_controller (int dev, int voice, int ctrl_num, int value)
+bend_pitch (int dev, int voice, int value)
 {
   unsigned char   data;
   int             block, fnum, freq;
   struct physical_voice_info *map;
 
-  if (voice < 0 || voice >= nr_voices)
-    return;
-
   map = &physical_voices[logical_voices[voice]];
 
   if (map->voice_mode == 0)
     return;
 
+  voices[voice].bender = value;
+  if (!value)
+    return;
+  if (!(voices[voice].keyon_byte & 0x20))
+    return;			/*
+				 * Not keyed on
+				 */
+
+  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
+  voices[voice].current_freq = freq;
+
+  freq_to_fnum (freq, &block, &fnum);
+
+  data = fnum & 0xff;		/*
+				 * Least significant bits of fnumber
+				 */
+  opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
+
+  data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);	/*
+								 * *
+								 * KEYON|OCTAVE|MS
+								 *
+								 * * bits * *
+								 * of * f-num
+								 *
+								 */
+  voices[voice].keyon_byte = data;
+  opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
+}
+
+static void
+opl3_controller (int dev, int voice, int ctrl_num, int value)
+{
+  if (voice < 0 || voice >= nr_voices)
+    return;
+
   switch (ctrl_num)
     {
     case CTRL_PITCH_BENDER:
-      voices[voice].bender = value;
-      if (!value)
-	return;
-      if (!(voices[voice].keyon_byte & 0x20))
-	return;			/* Not keyed on */
-
-      freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
-      voices[voice].current_freq = freq;
-
-      freq_to_fnum (freq, &block, &fnum);
-
-      data = fnum & 0xff;	/* Least significant bits of fnumber */
-      opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
-
-      data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);	/* KEYON|OCTAVE|MS bits
-									   * of f-num */
-      voices[voice].keyon_byte = data;
-      opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
+      bend_pitch (dev, voice, value);
       break;
 
     case CTRL_PITCH_BENDER_RANGE:
@@ -877,9 +1064,76 @@
   return RET_ERROR (EINVAL);
 }
 
+static void
+opl3_bender (int dev, int voice, int value)
+{
+  if (voice < 0 || voice >= nr_voices)
+    return;
+
+  bend_pitch (dev, voice, value);
+}
+
+static int
+opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
+{
+  int             i, p, avail_voices;
+  struct sbi_instrument *instr;
+  int             is4op;
+  int             instr_no;
+
+  if (chn < 0 || chn > 15)
+    instr_no = 0;
+  else
+    instr_no = chn_info[chn].pgm_num;
+
+  instr = &instrmap[instr_no];
+  if (instr->channel < 0 ||	/* Instrument not loaded */
+      nr_voices != 12)		/* Not in 4 OP mode */
+    is4op = 0;
+  else if (nr_voices == 12)	/* 4 OP mode */
+    is4op = (instr->key == OPL3_PATCH);
+  else
+    is4op = 0;
+
+  if (is4op)
+    {
+      p = 0;
+      avail_voices = 6;
+    }
+  else
+    {
+      if (nr_voices == 12)	/* 4 OP mode. Use the '2 OP only' voices first */
+	p = 6;
+      else
+	p = 0;
+      avail_voices = nr_voices;
+    }
+
+  /*
+ *    Now try to find a free voice
+ */
+
+  for (i = 0; i < avail_voices; i++)
+    {
+      if (alloc->map[p] == 0)
+	{
+	  return p;
+	}
+      p = (p + 1) % nr_voices;
+    }
+
+  /*
+ *    Insert some kind of priority mechanism here.
+ */
+
+  printk ("OPL3: Out of free voices\n");
+  return 0;			/* All voices in use. Select the first one. */
+}
+
 static struct synth_operations opl3_operations =
 {
   &fm_info,
+  0,
   SYNTH_TYPE_FM,
   FM_TYPE_ADLIB,
   opl3_open,
@@ -895,7 +1149,9 @@
   opl3_controller,
   opl3_panning,
   opl3_volume_method,
-  opl3_patchmgr
+  opl3_patchmgr,
+  opl3_bender,
+  opl3_alloc_voice
 };
 
 long
@@ -906,14 +1162,22 @@
   PERMANENT_MALLOC (struct sbi_instrument *, instrmap,
 		    SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
 
-  synth_devs[num_synths++] = &opl3_operations;
+  if (num_synths >= MAX_SYNTH_DEV)
+    printk ("OPL3 Error: Too many synthesizers\n");
+  else
+    {
+      synth_devs[num_synths++] = &opl3_operations;
+      voice_alloc = &opl3_operations.alloc;
+      chn_info = &opl3_operations.chn_info[0];
+    }
+
   fm_model = 0;
   opl3_ok = 1;
   if (opl3_enabled)
     {
       printk (" <Yamaha OPL-3 FM>");
       fm_model = 2;
-      nr_voices = 18;
+      voice_alloc->max_voice = nr_voices = 18;
       fm_info.nr_drums = 0;
       fm_info.capabilities |= SYNTH_CAP_OPL3;
 #ifndef SCO
@@ -927,15 +1191,24 @@
 	  physical_voices[i].ioaddr = right_address;
 
 
-      opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE);	/* Enable OPL-3 mode */
-      opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00);	/* Select all 2-OP
-									 * voices */
+      opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE);	/*
+									 * Enable
+									 * OPL-3
+									 * mode
+									 */
+      opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00);	/*
+									 * Select
+									 * all
+									 * 2-OP
+									 * *
+									 * voices
+									 */
     }
   else
     {
       printk (" <Yamaha 2-OP FM>");
       fm_model = 1;
-      nr_voices = 9;
+      voice_alloc->max_voice = nr_voices = 9;
       fm_info.nr_drums = 0;
 
       for (i = 0; i < 18; i++)
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v1.1.30/linux/drivers/sound/os.h	Sun May  1 12:12:35 1994
+++ linux/drivers/sound/os.h	Mon Jul 18 09:50:55 1994
@@ -44,8 +44,8 @@
 #include <sys/kd.h>
 #include <linux/wait.h>
 #include <linux/malloc.h>
-#include <linux/soundcard.h>
 #include <linux/string.h>
+#include <linux/soundcard.h>
 
 typedef char snd_rw_buf;
 
@@ -73,7 +73,7 @@
 #define DEFINE_WAIT_QUEUES(name, flag) static struct wait_queue *name = {NULL}; \
 	static volatile struct snd_wait flag = {{0}}
 #define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;}
-#define PROCESS_ABORTING(q, f) (f.aborting | (current->signal & ~current->blocked))
+#define PROCESS_ABORTING(q, f) (/*f.aborting | */(current->signal & ~current->blocked))
 #define SET_ABORT_FLAG(q, f) f.aborting = 1
 #define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT)
 #define DO_SLEEP(q, f, time_limit)	\
@@ -141,7 +141,7 @@
 
 #define DEFINE_TIMER(name, proc) \
   static struct timer_list name = \
-  {NULL, 0, 0, 0, proc}
+  {NULL, NULL, 0, 0, proc}
 
 /*
  * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
@@ -153,3 +153,9 @@
 
 #define INB	inb
 #define OUTB	outb
+
+/*
+ * SND_SA_INTERRUPT is required. Otherwise the IRQ number is not passed 
+ * the handler.
+ */
+#define SND_SA_INTERRUPT
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas.h linux/drivers/sound/pas.h
--- v1.1.30/linux/drivers/sound/pas.h	Sun May  1 12:12:36 1994
+++ linux/drivers/sound/pas.h	Mon Jul 18 09:50:55 1994
@@ -135,25 +135,25 @@
 #define PAS_16D		4
 
 #ifdef DEFINE_TRANSLATIONS
-	char I_C_2_PCM_DMA_translate[] = 		/* R W  PCM		PCM DMA channel value 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 };
-	char I_C_3_PCM_IRQ_translate[] = 		/* R W	PCM		PCM IRQ level value translation			*/
+	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 };  
-	char E_C_MPU401_IRQ_translate[] = 		/* R W	MIDI		MPU401 emulation IRQ value translation		*/
+	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 };
-	char E_C_SB_IRQ_translate[] = 			/* R W	PCM		SB emulation IRQ translate			*/
+	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 };
-	char E_C_SB_DMA_translate[] = 			/* R W	PCM		SB emulation DMA translate			*/
+	unsigned char E_C_SB_DMA_translate[] = 			/* R W	PCM		SB emulation DMA translate			*/
 		{ 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
-	char O_M_1_to_card[] = 				/* R W	Control		Translate (OM1 & 0x0f) to card type		*/
+	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 char I_C_2_PCM_DMA_translate[];		/* R W  PCM		PCM DMA channel value translations		*/
-	extern char I_C_3_PCM_IRQ_translate[];		/* R W	PCM		PCM IRQ level value translation			*/
-	extern char E_C_MPU401_IRQ_translate[];		/* R W	MIDI		MPU401 emulation IRQ value translation		*/
-	extern char E_C_SB_IRQ_translate[];		/* R W	PCM		SB emulation IRQ translate			*/
-	extern char E_C_SB_DMA_translate[];		/* R W	PCM		SB emulation DMA translate			*/
-	extern char O_M_1_to_card[];			/* R W	Control		Translate (OM1 & 0x0f) to card type		*/
+	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?? */
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v1.1.30/linux/drivers/sound/pas2_card.c	Sun May  1 12:12:36 1994
+++ linux/drivers/sound/pas2_card.c	Mon Jul 18 09:50:55 1994
@@ -1,5 +1,4 @@
 #define _PAS2_CARD_C_
-#define SND_SA_INTERRUPT
 /*
  * sound/pas2_card.c
  *
@@ -49,9 +48,15 @@
 static char    *pas_model_names[] =
 {"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
 
-/* 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 */
+/*
+ * 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
+ */
 
 unsigned char
 pas_read (int ioaddr)
@@ -79,7 +84,9 @@
   int             status;
 
   status = pas_read (INTERRUPT_STATUS);
-  pas_write (status, INTERRUPT_STATUS);	/* Clear interrupt */
+  pas_write (status, INTERRUPT_STATUS);	/*
+						 * Clear interrupt
+						 */
 
   if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
     {
@@ -143,27 +150,39 @@
 config_pas_hw (struct address_info *hw_config)
 {
   char            ok = 1;
+  unsigned        int_ptrs;	/* scsi/sound interrupt pointers */
 
   pas_irq = hw_config->irq;
 
   pas_write (0x00, INTERRUPT_MASK);
 
-  pas_write (0x36, SAMPLE_COUNTER_CONTROL);	/* Local timer control
-						 * register */
-
-  pas_write (0x36, SAMPLE_RATE_TIMER);	/* Sample rate timer (16 bit) */
+  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 (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 (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 (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1);
 
@@ -174,7 +193,9 @@
     }
   else
     {
-      pas_write (I_C_3_PCM_IRQ_translate[pas_irq], IO_CONFIGURATION_3);
+      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])
 	{
 	  printk ("PAS2: Invalid IRQ %d", pas_irq);
@@ -209,14 +230,23 @@
 #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);
 #else
-  /* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);     */
+  /*
+   * pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);
+   */
   pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
 #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 (0x18, SYSTEM_CONFIGURATION_3);	/*
+						 * ???
+						 */
+
+  pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY);	/*
+								 * Sets mute
+								 * off and *
+								 * selects
+								 * filter
+								 * rate * of
+								 * 17.897 kHz
+								 */
 
   if (pas_model == PAS_16 || pas_model == PAS_16D)
     pas_write (8, PRESCALE_DIVIDER);
@@ -235,12 +265,20 @@
       {
 	unsigned char   irq_dma;
 
-	/* Turn on Sound Blaster compatibility */
-	/* bit 1 = SB emulation */
-	/* bit 0 = MPU401 emulation (CDPC only :-( ) */
+	/*
+	 * Turn on Sound Blaster compatibility
+	 */
+	/*
+	 * bit 1 = SB emulation
+	 */
+	/*
+	 * bit 0 = MPU401 emulation (CDPC only :-( )
+	 */
 	pas_write (0x02, COMPATIBILITY_ENABLE);
 
-	/* "Emulation address"         */
+	/*
+	 * "Emulation address"
+	 */
 	pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
 
 	if (!E_C_SB_DMA_translate[sb_config->dma])
@@ -277,10 +315,16 @@
    * 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 */
+  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 */
+  pas_write (1, WAIT_STATE);	/*
+				 * One wait-state
+				 */
 
   board_id = pas_read (INTERRUPT_MASK);
 
@@ -299,7 +343,9 @@
   foo = INB (INTERRUPT_MASK);
   pas_write (board_id, INTERRUPT_MASK);
 
-  if (board_id != foo)		/* Not a PAS2 */
+  if (board_id != foo)		/*
+				 * Not a PAS2
+				 */
     return 0;
 
   pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f];
@@ -329,8 +375,10 @@
 
 #if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
 
-	  sb_dsp_disable_midi ();	/* The SB emulation don't support
-					 * midi */
+	  sb_dsp_disable_midi ();	/*
+					 * The SB emulation don't support *
+					 * midi
+					 */
 #endif
 
 #ifndef EXCLUDE_YM3812
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c
--- v1.1.30/linux/drivers/sound/pas2_midi.c	Sun May  1 12:12:36 1994
+++ linux/drivers/sound/pas2_midi.c	Mon Jul 18 09:50:55 1994
@@ -62,7 +62,9 @@
       return RET_ERROR (EBUSY);
     }
 
-  /* Reset input and output FIFO pointers */
+  /*
+   * Reset input and output FIFO pointers
+   */
   pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO,
 	     MIDI_CONTROL);
 
@@ -71,7 +73,9 @@
   if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0)
     return err;
 
-  /* Enable input available and output FIFO empty interrupts */
+  /*
+   * Enable input available and output FIFO empty interrupts
+   */
 
   ctrl = 0;
   input_opened = 0;
@@ -79,20 +83,26 @@
 
   if (mode == OPEN_READ || mode == OPEN_READWRITE)
     {
-      ctrl |= M_C_ENA_INPUT_IRQ;/* Enable input */
+      ctrl |= M_C_ENA_INPUT_IRQ;/*
+					 * Enable input
+					 */
       input_opened = 1;
     }
 
   if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
     {
-      ctrl |= M_C_ENA_OUTPUT_IRQ |	/* Enable output */
+      ctrl |= M_C_ENA_OUTPUT_IRQ |	/*
+					 * Enable output
+					 */
 	M_C_ENA_OUTPUT_HALF_IRQ;
     }
 
   pas_write (ctrl,
 	     MIDI_CONTROL);
 
-  /* Acknowledge any pending interrupts */
+  /*
+   * Acknowledge any pending interrupts
+   */
 
   pas_write (0xff, MIDI_STATUS);
   ofifo_bytes = 0;
@@ -108,7 +118,9 @@
 pas_midi_close (int dev)
 {
 
-  /* Reset FIFO pointers, disable intrs */
+  /*
+   * Reset FIFO pointers, disable intrs
+   */
   pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL);
 
   pas_remove_intr (I_M_MIDI_IRQ_ENABLE);
@@ -122,9 +134,14 @@
 
   fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
 
-  if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13))	/* Fifo full */
+  if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13))	/*
+									 * Fifo
+									 * full
+									 */
     {
-      return 0;			/* Upper layer will call again */
+      return 0;			/*
+				 * Upper layer will call again
+				 */
     }
 
   ofifo_bytes++;
@@ -160,14 +177,18 @@
 
   if (!qlen)
     if (dump_to_midi (midi_byte))
-      return 1;			/* OK */
+      return 1;			/*
+				 * OK
+				 */
 
   /*
    * Put to the local queue
    */
 
   if (qlen >= 256)
-    return 0;			/* Local queue full */
+    return 0;			/*
+				 * Local queue full
+				 */
 
   DISABLE_INTR (flags);
 
@@ -210,9 +231,14 @@
   return !qlen;
 }
 
+#define MIDI_SYNTH_NAME	"Pro Audio Spectrum Midi"
+#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
 static struct midi_operations pas_midi_operations =
 {
   {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
+  &std_midi_synth,
   pas_midi_open,
   pas_midi_close,
   pas_midi_ioctl,
@@ -220,14 +246,23 @@
   pas_midi_start_read,
   pas_midi_end_read,
   pas_midi_kick,
-  NULL,				/* command */
-  pas_buffer_status
+  NULL,				/*
+				 * command
+				 */
+  pas_buffer_status,
+  NULL
 };
 
 long
 pas_midi_init (long mem_start)
 {
-  my_dev = num_midis;
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return mem_start;
+    }
+
+  std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &pas_midi_operations;
   return mem_start;
 }
@@ -241,9 +276,13 @@
 
   stat = pas_read (MIDI_STATUS);
 
-  if (stat & M_S_INPUT_AVAIL)	/* Input byte available */
+  if (stat & M_S_INPUT_AVAIL)	/*
+				 * Input byte available
+				 */
     {
-      incount = pas_read (MIDI_FIFO_STATUS) & 0x0f;	/* Input FIFO count */
+      incount = pas_read (MIDI_FIFO_STATUS) & 0x0f;	/*
+							 * Input FIFO count
+							 */
       if (!incount)
 	incount = 16;
 
@@ -253,7 +292,9 @@
 	    midi_input_intr (my_dev, pas_read (MIDI_DATA));
 	  }
 	else
-	  pas_read (MIDI_DATA);	/* Flush */
+	  pas_read (MIDI_DATA);	/*
+				 * Flush
+				 */
     }
 
   if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY))
@@ -287,7 +328,9 @@
       ofifo_bytes = 100;
     }
 
-  pas_write (stat, MIDI_STATUS);/* Acknowledge interrupts */
+  pas_write (stat, MIDI_STATUS);/*
+					 * Acknowledge interrupts
+					 */
 }
 
 #endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c
--- v1.1.30/linux/drivers/sound/pas2_mixer.c	Sun May  1 12:12:37 1994
+++ linux/drivers/sound/pas2_mixer.c	Mon Jul 18 09:50:55 1994
@@ -35,11 +35,18 @@
 
 #include "pas.h"
 
-#define TRACE(what)		/* (what) */
+#define TRACE(what)		/*
+				   * * * (what)   */
 
 extern int      translat_code;
 
-static int      rec_devices = (SOUND_MASK_MIC);	/* Default recording source */
+static int      rec_devices = (SOUND_MASK_MIC);	/*
+
+
+							 * *  * * Default *
+							 * recording * source
+							 *
+							 * *  */
 static int      mode_control = 0;
 
 #define POSSIBLE_RECORDING_DEVICES	(SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
@@ -52,22 +59,49 @@
 
 static unsigned short levels[SOUND_MIXER_NRDEVICES] =
 {
-  0x3232,			/* Master Volume */
-  0x3232,			/* Bass */
-  0x3232,			/* Treble */
-  0x5050,			/* FM */
-  0x4b4b,			/* PCM */
-  0x3232,			/* PC Speaker */
-  0x4b4b,			/* Ext Line */
-  0x4b4b,			/* Mic */
-  0x4b4b,			/* CD */
-  0x6464,			/* Recording monitor */
-  0x4b4b,			/* SB PCM */
-  0x6464};			/* Recording level */
+  0x3232,			/*
+				 * Master Volume
+				 */
+  0x3232,			/*
+				 * Bass
+				 */
+  0x3232,			/*
+				 * Treble
+				 */
+  0x5050,			/*
+				 * FM
+				 */
+  0x4b4b,			/*
+				 * PCM
+				 */
+  0x3232,			/*
+				 * PC Speaker
+				 */
+  0x4b4b,			/*
+				 * Ext Line
+				 */
+  0x4b4b,			/*
+				 * Mic
+				 */
+  0x4b4b,			/*
+				 * CD
+				 */
+  0x6464,			/*
+				 * Recording monitor
+				 */
+  0x4b4b,			/*
+				 * SB PCM
+				 */
+  0x6464};			/*
+
 
+				 * *  * * Recording level   */
+
 static int
 mixer_output (int right_vol, int left_vol, int div, int bits,
-	      int mixer /* Input or output mixer */ )
+	      int mixer		/*
+				 * Input or output mixer
+     	      	      	      	      	      				 */ )
 {
   int             left = left_vol * div / 100;
   int             right = right_vol * div / 100;
@@ -81,13 +115,17 @@
    */
 
   if (bits & P_M_MV508_MIXER)
-    {				/* Select input or output mixer */
+    {				/*
+				 * Select input or output mixer
+				 */
       left |= mixer;
       right |= mixer;
     }
 
   if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
-    {				/* Bass and trebble are mono devices     */
+    {				/*
+				 * Bass and trebble are mono devices
+				 */
       pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
       pas_write (left, PARALLEL_MIXER);
       right_vol = left_vol;
@@ -130,7 +168,9 @@
 
   switch (whichDev)
     {
-    case SOUND_MIXER_VOLUME:	/* Master volume (0-63) */
+    case SOUND_MIXER_VOLUME:	/*
+				 * Master volume (0-63)
+				 */
       levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
       break;
 
@@ -138,40 +178,62 @@
        * Note! Bass and Treble are mono devices. Will use just the left
        * channel.
        */
-    case SOUND_MIXER_BASS:	/* Bass (0-12) */
+    case SOUND_MIXER_BASS:	/*
+				 * Bass (0-12)
+				 */
       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
       break;
-    case SOUND_MIXER_TREBLE:	/* Treble (0-12) */
+    case SOUND_MIXER_TREBLE:	/*
+				 * Treble (0-12)
+				 */
       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
       break;
 
-    case SOUND_MIXER_SYNTH:	/* Internal synthesizer (0-31) */
+    case SOUND_MIXER_SYNTH:	/*
+				 * Internal synthesizer (0-31)
+				 */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
       break;
-    case SOUND_MIXER_PCM:	/* PAS PCM (0-31) */
+    case SOUND_MIXER_PCM:	/*
+				 * PAS PCM (0-31)
+				 */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
       break;
-    case SOUND_MIXER_ALTPCM:	/* SB PCM (0-31) */
+    case SOUND_MIXER_ALTPCM:	/*
+				 * SB PCM (0-31)
+				 */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
       break;
-    case SOUND_MIXER_SPEAKER:	/* PC speaker (0-31) */
+    case SOUND_MIXER_SPEAKER:	/*
+				 * PC speaker (0-31)
+				 */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
       break;
-    case SOUND_MIXER_LINE:	/* External line (0-31) */
+    case SOUND_MIXER_LINE:	/*
+				 * External line (0-31)
+				 */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
       break;
-    case SOUND_MIXER_CD:	/* CD (0-31) */
+    case SOUND_MIXER_CD:	/*
+				 * CD (0-31)
+				 */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
       break;
-    case SOUND_MIXER_MIC:	/* External microphone (0-31) */
+    case SOUND_MIXER_MIC:	/*
+				 * External microphone (0-31)
+				 */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
       break;
-    case SOUND_MIXER_IMIX:	/* Recording monitor (0-31) (Only available
-				 * on the Output Mixer) */
+    case SOUND_MIXER_IMIX:	/*
+				 * Recording monitor (0-31) (Only available *
+				 * on the Output Mixer)
+				 */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
 				       P_M_MV508_OUTPUTMIX);
       break;
-    case SOUND_MIXER_RECLEV:	/* Recording level (0-15) */
+    case SOUND_MIXER_RECLEV:	/*
+				 * Recording level (0-15)
+				 */
       levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
       break;
 
@@ -199,7 +261,9 @@
       if (level)
 	mode_control |= P_M_MV508_LOUDNESS;
       set_mode (mode_control);
-      return !!level;		/* 0 or 1 */
+      return !!level;		/*
+				 * 0 or 1
+				 */
       break;
 
     case SOUND_MIXER_RECSRC:
@@ -226,91 +290,6 @@
 /*****/
 
 static int
-mixer_set_levels (struct sb_mixer_levels *user_l)
-{
-#define cmix(v) ((((v.r*100+7)/15)<<8)| ((v.l*100+7)/15))
-
-  struct sb_mixer_levels l;
-
-  IOCTL_FROM_USER ((char *) &l, (char *) user_l, 0, sizeof (l));
-
-  if (l.master.l & ~0xF || l.master.r & ~0xF
-      || l.line.l & ~0xF || l.line.r & ~0xF
-      || l.voc.l & ~0xF || l.voc.r & ~0xF
-      || l.fm.l & ~0xF || l.fm.r & ~0xF
-      || l.cd.l & ~0xF || l.cd.r & ~0xF
-      || l.mic & ~0x7)
-    return (RET_ERROR (EINVAL));
-
-  pas_mixer_set (SOUND_MIXER_VOLUME, cmix (l.master));
-  pas_mixer_set (SOUND_MIXER_LINE, cmix (l.line));
-  pas_mixer_set (SOUND_MIXER_PCM, cmix (l.voc));
-  pas_mixer_set (SOUND_MIXER_ALTPCM, cmix (l.voc));
-  pas_mixer_set (SOUND_MIXER_SYNTH, cmix (l.fm));
-  pas_mixer_set (SOUND_MIXER_CD, cmix (l.cd));
-  pas_mixer_set (SOUND_MIXER_MIC, ((l.mic * 100 + 3) / 7) | (((l.mic * 100 + 3) / 7) << 8));
-  return (0);
-}
-
-/*
- * This sets aspects of the Mixer that are not volume levels. (Recording
- * source, filter level, I/O filtering, and stereo.)
- */
-static int
-mixer_set_params (struct sb_mixer_params *user_p)
-{
-  struct sb_mixer_params p;
-  S_BYTE          val;
-  int             src;
-  unsigned long   flags;
-
-  IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p));
-
-  if (p.record_source != SRC_MIC
-      && p.record_source != SRC_CD
-      && p.record_source != SRC_LINE)
-    return (RET_ERROR (EINVAL));
-
-  /*
-   * I'm not sure if this is The Right Thing.  Should stereo be entirely
-   * under control of DSP?  I like being able to toggle it while a sound is
-   * playing, so I do this... because I can.
-   */
-
-  DISABLE_INTR (flags);
-
-  val = (pas_read (PCM_CONTROL) & ~P_C_MIXER_CROSS_FIELD) | P_C_MIXER_CROSS_R_TO_R | P_C_MIXER_CROSS_L_TO_L;
-  if (!p.dsp_stereo)
-    val |= (P_C_MIXER_CROSS_R_TO_L | P_C_MIXER_CROSS_L_TO_R);	/* Mono */
-  pas_write (val, PCM_CONTROL);
-
-  RESTORE_INTR (flags);
-
-  switch (p.record_source)
-    {
-    case SRC_CD:
-      src = SOUND_MASK_CD;
-      break;
-
-    case SRC_LINE:
-      src = SOUND_MASK_LINE;
-      break;
-
-    default:
-      src = SOUND_MASK_MIC;
-      break;
-    }
-
-  pas_mixer_set (SOUND_MIXER_RECSRC, src);
-
-  /*
-   * setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC) |
-   * (p.filter_output ? FILT_ON : FILT_OFF)));
-   */
-  return (0);
-}
-
-static int
 getmixer (int dev, int chn)
 {
   if (chn == P_M_MV508_RIGHT)
@@ -323,73 +302,6 @@
     }
 }
 
-/* Read the current mixer level settings into the user's struct. */
-static int
-mixer_get_levels (struct sb_mixer_levels *user_l)
-{
-
-  struct sb_mixer_levels l;
-
-  l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100;	/* Master */
-  l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100;	/* Master */
-
-  l.line.r = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_RIGHT) * 15) + 50) / 100;	/* Line */
-  l.line.l = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_LEFT) * 15) + 50) / 100;
-
-  l.voc.r = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_RIGHT) * 15) + 50) / 100;	/* DAC */
-  l.voc.l = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_LEFT) * 15) + 50) / 100;
-
-  l.fm.r = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_RIGHT) * 15) + 50) / 100;	/* FM */
-  l.fm.l = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_LEFT) * 15) + 50) / 100;
-
-  l.cd.r = ((getmixer (SOUND_MIXER_CD, P_M_MV508_RIGHT) * 15) + 50) / 100;	/* CD */
-  l.cd.l = ((getmixer (SOUND_MIXER_CD, P_M_MV508_LEFT) * 15) + 50) / 100;
-
-  l.mic = ((getmixer (SOUND_MIXER_MIC, P_M_MV508_LEFT) * 7) + 50) / 100;	/* Microphone */
-
-  IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l));
-  return (0);
-}
-
-/* Read the current mixer parameters into the user's struct. */
-static int
-mixer_get_params (struct sb_mixer_params *user_params)
-{
-  S_BYTE          val;
-  struct sb_mixer_params params;
-
-  switch (rec_devices)
-    {
-    case SOUND_MASK_CD:
-      params.record_source = SRC_CD;
-      break;
-
-    case SOUND_MASK_LINE:
-      params.record_source = SRC_LINE;
-      break;
-
-    case SOUND_MASK_MIC:
-      params.record_source = SRC_MIC;
-      break;
-
-    default:
-      params.record_source = SRC_MIC;
-      pas_mixer_set (SOUND_MIXER_RECSRC, SOUND_MASK_MIC);	/* Adjust */
-    }
-
-  params.hifreq_filter = OFF;
-  params.filter_input = OFF;
-  params.filter_output = OFF;
-
-  val = INB (PCM_CONTROL);
-  params.dsp_stereo = ((val & P_C_MIXER_CROSS_FIELD) == (P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R));
-
-  IOCTL_TO_USER ((char *) user_params, 0, (char *) &params, sizeof (params));
-  return (0);
-}
-
-/*****/
-
 static void
 pas_mixer_reset (void)
 {
@@ -413,7 +325,9 @@
       if (cmd & IOC_IN)
 	return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
       else
-	{			/* Read parameters */
+	{			/*
+				 * Read parameters
+				 */
 
 	  switch (cmd & 0xff)
 	    {
@@ -435,11 +349,15 @@
 	      break;
 
 	    case SOUND_MIXER_CAPS:
-	      return IOCTL_OUT (arg, 0);	/* No special capabilities */
+	      return IOCTL_OUT (arg, 0);	/*
+						 * No special capabilities
+						 */
 	      break;
 
 	    case SOUND_MIXER_MUTE:
-	      return IOCTL_OUT (arg, 0);	/* No mute yet */
+	      return IOCTL_OUT (arg, 0);	/*
+						 * No mute yet
+						 */
 	      break;
 
 	    case SOUND_MIXER_ENHANCE:
@@ -459,27 +377,6 @@
 	    }
 	}
     }
-  else
-    {
-      switch (cmd)
-	{
-	case MIXER_IOCTL_SET_LEVELS:
-	  mixer_set_levels ((struct sb_mixer_levels *) arg);
-	  return mixer_get_levels ((struct sb_mixer_levels *) arg);
-	case MIXER_IOCTL_SET_PARAMS:
-	  mixer_set_params ((struct sb_mixer_params *) arg);
-	  return mixer_get_params ((struct sb_mixer_params *) arg);
-	case MIXER_IOCTL_READ_LEVELS:
-	  return mixer_get_levels ((struct sb_mixer_levels *) arg);
-	case MIXER_IOCTL_READ_PARAMS:
-	  return mixer_get_params ((struct sb_mixer_params *) arg);
-	case MIXER_IOCTL_RESET:
-	  pas_mixer_reset ();
-	  return (0);
-	default:
-	  return RET_ERROR (EINVAL);
-	}
-    }
   return RET_ERROR (EINVAL);
 }
 
@@ -493,7 +390,8 @@
 {
   pas_mixer_reset ();
 
-  mixer_devs[num_mixers++] = &pas_mixer_operations;
+  if (num_mixers < MAX_MIXER_DEV)
+    mixer_devs[num_mixers++] = &pas_mixer_operations;
   return 1;
 }
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c
--- v1.1.30/linux/drivers/sound/pas2_pcm.c	Sun May  1 12:12:37 1994
+++ linux/drivers/sound/pas2_pcm.c	Mon Jul 18 09:50:55 1994
@@ -36,17 +36,20 @@
 
 #if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO)
 
-#define TRACE(WHAT)		/* (WHAT) */
+#define TRACE(WHAT)		/*
+				   * * * (WHAT)   */
 
 #define PAS_PCM_INTRBITS (0x08)
-/* Sample buffer timer interrupt enable */
+/*
+ * Sample buffer timer interrupt enable
+ */
 
 #define PCM_NON	0
 #define PCM_DAC	1
 #define PCM_ADC	2
 
 static unsigned long pcm_speed = 0;	/* sampling rate */
-static unsigned char pcm_channels = 1;	/* channels/sample (1 or 2) */
+static unsigned char pcm_channels = 1;	/* channels (1 or 2) */
 static unsigned char pcm_bits = 8;	/* bits/sample (8 or 16) */
 static unsigned char pcm_filter = 0;	/* filter FLAG */
 static unsigned char pcm_mode = PCM_NON;
@@ -65,7 +68,7 @@
   if (arg < 5000)
     arg = 5000;
 
-  foo = 1193180 / arg;
+  foo = (1193180 + (arg / 2)) / arg;
   arg = 1193180 / foo;
 
   if (pcm_channels & 2)
@@ -75,6 +78,31 @@
 
   tmp = pas_read (FILTER_FREQUENCY);
 
+  /*
+ * 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/.
+*/
+#if !defined NO_AUTO_FILTER_SET
+  tmp &= 0xe0;
+  if (pcm_speed >= 2 * 17897)
+    tmp |= 0x21;
+  else if (pcm_speed >= 2 * 15909)
+    tmp |= 0x22;
+  else if (pcm_speed >= 2 * 11931)
+    tmp |= 0x29;
+  else if (pcm_speed >= 2 * 8948)
+    tmp |= 0x31;
+  else if (pcm_speed >= 2 * 5965)
+    tmp |= 0x39;
+  else if (pcm_speed >= 2 * 2982)
+    tmp |= 0x24;
+  pcm_filter = tmp;
+#endif
+
   DISABLE_INTR (flags);
 
   pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
@@ -100,7 +128,9 @@
       pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
 
       pcm_channels = arg;
-      pcm_set_speed (pcm_speed);/* The speed must be reinitialized */
+      pcm_set_speed (pcm_speed);/*
+					 * The speed must be reinitialized
+					 */
     }
 
   return pcm_channels;
@@ -159,7 +189,7 @@
       return IOCTL_OUT (arg, pcm_channels);
       break;
 
-    case SNDCTL_DSP_SAMPLESIZE:
+    case SNDCTL_DSP_SETFMT:
       if (local)
 	return pcm_set_bits (arg);
       return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));
@@ -170,7 +200,9 @@
 	return pcm_bits;
       return IOCTL_OUT (arg, pcm_bits);
 
-    case SOUND_PCM_WRITE_FILTER:	/* NOT YET IMPLEMENTED */
+    case SOUND_PCM_WRITE_FILTER:	/*
+					 * NOT YET IMPLEMENTED
+					 */
       if (IOCTL_IN (arg) > 1)
 	return IOCTL_OUT (arg, RET_ERROR (EINVAL));
       break;
@@ -205,7 +237,7 @@
   if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
     return err;
 
-  if (!DMAbuf_open_dma (dev))
+  if (DMAbuf_open_dma (dev) < 0)
     {
       pas_remove_intr (PAS_PCM_INTRBITS);
       return RET_ERROR (EBUSY);
@@ -242,13 +274,15 @@
   TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
 
   cnt = count;
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     cnt >>= 1;
 
-  if (sound_dma_automode[dev] &&
+  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == pcm_count)
-    return;			/* Auto mode on. No need to react */
+    return;			/*
+				 * Auto mode on. No need to react
+				 */
 
   DISABLE_INTR (flags);
 
@@ -258,7 +292,7 @@
   if (restart_dma)
     DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     count >>= 1;
 
   if (count != pcm_count)
@@ -289,20 +323,22 @@
   TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
 
   cnt = count;
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     cnt >>= 1;
 
-  if (sound_dma_automode[my_devnum] &&
+  if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == pcm_count)
-    return;			/* Auto mode on. No need to react */
+    return;			/*
+				 * Auto mode on. No need to react
+				 */
 
   DISABLE_INTR (flags);
 
   if (restart_dma)
     DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     count >>= 1;
 
   if (count != pcm_count)
@@ -337,7 +373,9 @@
 static struct audio_operations pas_pcm_operations =
 {
   "Pro Audio Spectrum",
-  NOTHING_SPECIAL,
+  DMA_AUTOMODE,
+  AFMT_U8 | AFMT_S16_LE,
+  NULL,
   pas_pcm_open,
   pas_pcm_close,
   pas_pcm_output_block,
@@ -346,9 +384,9 @@
   pas_pcm_prepare_for_input,
   pas_pcm_prepare_for_output,
   pas_pcm_reset,
-  pas_pcm_reset,		/* halt_xfer */
-  NULL,				/* has_output_drained */
-  NULL				/* copy_from_user */
+  pas_pcm_reset,
+  NULL,
+  NULL
 };
 
 long
@@ -362,28 +400,12 @@
 
   pcm_set_speed (DSP_DEFAULT_SPEED);
 
-  if (num_dspdevs < MAX_DSP_DEV)
+  if (num_audiodevs < MAX_AUDIO_DEV)
     {
-      dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
-      sound_dsp_dmachan[my_devnum] = hw_config->dma;
-#ifndef PAS_NO_AUTODMA
-      if (hw_config->dma > 3)
-	{
-	  sound_buffcounts[my_devnum] = 1;
-	  sound_buffsizes[my_devnum] = 2 * 65536;
-	  sound_dma_automode[my_devnum] = 1;
-	}
-      else
-	{
-	  sound_buffcounts[my_devnum] = 1;
-	  sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
-	  sound_dma_automode[my_devnum] = 1;
-	}
-#else
-      sound_buffcounts[my_devnum] = 2;
-      sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
-      sound_dma_automode[my_devnum] = 0;
-#endif
+      audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;
+      audio_devs[my_devnum]->dmachan = hw_config->dma;
+      audio_devs[my_devnum]->buffcount = 1;
+      audio_devs[my_devnum]->buffsize = 2 * DSP_BUFFSIZE;
     }
   else
     printk ("PAS2: Too many PCM devices available\n");
@@ -394,14 +416,16 @@
 void
 pas_pcm_interrupt (unsigned char status, int cause)
 {
-  if (cause == 1)		/* PCM buffer done */
+  if (cause == 1)		/*
+				 * PCM buffer done
+				 */
     {
       /*
        * Halt the PCM first. Otherwise we don't have time to start a new
        * block before the PCM chip proceeds to the next sample
        */
 
-      if (!sound_dma_automode[my_devnum])
+      if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE))
 	{
 	  pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
 		     PCM_CONTROL);
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c
--- v1.1.30/linux/drivers/sound/patmgr.c	Sun May  1 12:12:38 1994
+++ linux/drivers/sound/patmgr.c	Mon Jul 18 09:50:55 1994
@@ -67,7 +67,9 @@
 pmgr_release (int dev)
 {
 
-  if (mbox[dev])		/* Killed in action. Inform the client */
+  if (mbox[dev])		/*
+				 * Killed in action. Inform the client
+				 */
     {
 
       mbox[dev]->key = PM_ERROR;
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v1.1.30/linux/drivers/sound/pss.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/pss.c	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,924 @@
+/* Marc.Hoffman@analog.com
+
+   This is a pss driver.
+
+   it is based on Greg.Yukna@analog.com @file{host} for DOG
+
+   Unfortunately I can't distribute the ld file needed to
+   make the pss card to emulate the SB stuff.
+
+   I have provided a simple interface to the PSS unlike the
+   DOG version.  to download a new algorithim just cat it to
+   /dev/pss 14,9.
+
+   You really need to rebuild this with the synth.ld file
+
+   get the <synth>.ld from your dos directory maybe
+   voyetra\dsp001.ld
+
+   ld2inc < synth.ld > synth-ld.h
+   (make config does the same).
+
+   rebuild
+
+   Okay if you blow things away no problem just
+
+   main(){ioctl(open("/dev/pss"),SNDCTL_PSS_RESET)};
+
+   and everything will be okay.
+
+   At first I was going to wory about applications that were using
+   the sound stuff and disallow the use of /dev/pss.  But for
+   now I figured it doesn't matter.
+
+   And if you change algos all the other applications running die off
+   due to DMA problems.  Yeah just pull the plug and watch em die.
+
+   If the registers get hosed
+   main(){ioctl(open("/dev/pss"),SNDCTL_PSS_SETUP_REGISTERS)};
+
+   Probably everything else can be done via mmap
+
+   Oh if you want to develope code for the ADSP-21xx or Program the
+   1848 just send me mail and I will hook you up.
+
+               marc.hoffman@analog.com
+
+   */
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS)
+
+#ifndef PSS_MSS_BASE
+#define PSS_MSS_BASE 0
+#endif
+
+#ifndef PSS_MPU_BASE
+#define PSS_MPU_BASE 0
+#endif
+
+#ifndef PSS_MPU_IRQ
+#define PSS_MPU_IRQ 0
+#endif
+
+#undef DEB
+#define DEB(x) x
+
+#include "pss.h"
+
+static int      pss_ok = 0;
+static int      sb_ok = 0;
+
+static int      pss_base;
+static int      pss_irq;
+static int      pss_dma;
+
+static int      gamePort = 0;
+
+static int      sbInt;
+static int      cdPol;
+static int      cdAddr = 0;	/* 0x340;	*/
+static int      cdInt = 10;
+
+/* Define these by hand in local.h */
+static int      wssAddr = PSS_MSS_BASE;
+static int      midiAddr = PSS_MPU_BASE;
+static int      midiInt = PSS_MPU_IRQ;
+
+static int      SoundPortAddress;
+static int      SoundPortData;
+static int      speaker = 1;
+
+
+static struct pss_speaker default_speaker =
+{0, 0, 0, PSS_STEREO};
+
+DEFINE_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
+
+#include "synth-ld.h"
+
+static int      pss_download_boot (unsigned char *block, int size);
+static int      pss_reset_dsp (void);
+
+static inline void
+pss_outpw (unsigned short port, unsigned short value)
+{
+  __asm__         __volatile__ ("outw %w0, %w1"
+				:	/* no outputs */
+				:"a"            (value), "d" (port));
+}
+
+static inline unsigned int
+pss_inpw (unsigned short port)
+{
+  unsigned int    _v;
+  __asm__         __volatile__ ("inw %w1,%w0"
+				:"=a"           (_v):"d" (port), "0" (0));
+
+  return _v;
+}
+
+static void
+PSS_write (int data)
+{
+  int             i, limit;
+
+  limit = GET_TIME () + 10;	/* The timeout is 0.1 secods */
+  /*
+   * Note! the i<5000000 is an emergency exit. The 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 < 5000000 && GET_TIME () < limit; i++)
+    {
+      if (pss_inpw (pss_base + PSS_STATUS) & PSS_WRITE_EMPTY)
+	{
+	  pss_outpw (pss_base + PSS_DATA, data);
+	  return;
+	}
+    }
+  printk ("PSS: DSP Command (%04x) Timeout.\n", data);
+  printk ("IRQ conflict???\n");
+}
+
+
+static void
+pss_setaddr (int addr, int configAddr)
+{
+  int             val;
+
+  val = pss_inpw (configAddr);
+  val &= ADDR_MASK;
+  val |= (addr << 4);
+  pss_outpw (configAddr, val);
+}
+
+/*_____ pss_checkint
+         This function tests an interrupt number to see if
+	 it is availible. It takes the interrupt button
+	 as it's argument and returns TRUE if the interrupt
+	 is ok.
+*/
+static int
+pss_checkint (int intNum)
+{
+  int             val;
+  int             ret;
+  int             i;
+
+  /*_____ Set the interrupt bits */
+  switch (intNum)
+    {
+    case 3:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_3_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 5:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_5_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 7:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_7_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 9:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_9_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 10:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_10_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 11:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_11_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 12:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_12_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    default:
+      printk ("unknown interupt selected. %d\n", intNum);
+      return 0;
+    }
+
+  /*_____ Set the interrupt test bit */
+  val = pss_inpw (pss_base + PSS_CONFIG);
+  val |= INT_TEST_BIT;
+  pss_outpw (pss_base + PSS_CONFIG, val);
+
+  /*_____ Check if the interrupt is in use */
+  /*_____ Do it a few times in case there is a delay */
+  ret = 0;
+  for (i = 0; i < 5; i++)
+    {
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      if (val & INT_TEST_PASS)
+	{
+	  ret = 1;
+	  break;
+	}
+    }
+  /*_____ Clear the Test bit and the interrupt bits */
+  val = pss_inpw (pss_base + PSS_CONFIG);
+  val &= INT_TEST_BIT_MASK;
+  val &= INT_MASK;
+  pss_outpw (pss_base + PSS_CONFIG, val);
+  return (ret);
+}
+
+/*____ pss_setint
+        This function sets the correct bits in the
+	configuration register to
+	enable the chosen interrupt.
+*/
+static void
+pss_setint (int intNum, int configAddress)
+{
+  int             val;
+
+  switch (intNum)
+    {
+    case 0:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      pss_outpw (configAddress, val);
+      break;
+    case 3:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_3_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 5:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_5_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 7:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_7_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 9:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_9_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 10:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_10_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 11:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_11_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 12:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_12_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    default:
+      printk ("pss_setint unkown int\n");
+    }
+}
+
+
+/*____ pss_setsbint
+        This function sets the correct bits in the
+	SoundBlaster configuration PSS register to
+	enable the chosen interrupt.
+	It takes a interrupt button as its argument.
+*/
+static void
+pss_setsbint (int intNum)
+{
+  int             val;
+  int             sbConfigAddress;
+
+  sbConfigAddress = pss_base + SB_CONFIG;
+  switch (intNum)
+    {
+    case 3:
+      val = pss_inpw (sbConfigAddress);
+      val &= INT_MASK;
+      val |= INT_3_BITS;
+      pss_outpw (sbConfigAddress, val);
+      break;
+    case 5:
+      val = pss_inpw (sbConfigAddress);
+      val &= INT_MASK;
+      val |= INT_5_BITS;
+      pss_outpw (sbConfigAddress, val);
+      break;
+    case 7:
+      val = pss_inpw (sbConfigAddress);
+      val &= INT_MASK;
+      val |= INT_7_BITS;
+      pss_outpw (sbConfigAddress, val);
+      break;
+    default:
+      printk ("pss_setsbint: unknown_int\n");
+    }
+}
+
+/*____ pss_setsbdma
+        This function sets the correct bits in the
+	SoundBlaster configuration PSS register to
+	enable the chosen DMA channel.
+	It takes a DMA button as its argument.
+*/
+static void
+pss_setsbdma (int dmaNum)
+{
+  int             val;
+  int             sbConfigAddress;
+
+  sbConfigAddress = pss_base + SB_CONFIG;
+
+  switch (dmaNum)
+    {
+    case 1:
+      val = pss_inpw (sbConfigAddress);
+      val &= DMA_MASK;
+      val |= DMA_1_BITS;
+      pss_outpw (sbConfigAddress, val);
+      break;
+    default:
+      printk ("Personal Sound System ERROR! pss_setsbdma: unknown_dma\n");
+    }
+}
+
+/*____ pss_setwssdma
+        This function sets the correct bits in the
+	WSS configuration PSS register to
+	enable the chosen DMA channel.
+	It takes a DMA button as its argument.
+*/
+static void
+pss_setwssdma (int dmaNum)
+{
+  int             val;
+  int             wssConfigAddress;
+
+  wssConfigAddress = pss_base + PSS_WSS_CONFIG;
+
+  switch (dmaNum)
+    {
+    case 0:
+      val = pss_inpw (wssConfigAddress);
+      val &= DMA_MASK;
+      val |= DMA_0_BITS;
+      pss_outpw (wssConfigAddress, val);
+      break;
+    case 1:
+      val = pss_inpw (wssConfigAddress);
+      val &= DMA_MASK;
+      val |= DMA_1_BITS;
+      pss_outpw (wssConfigAddress, val);
+      break;
+    case 3:
+      val = pss_inpw (wssConfigAddress);
+      val &= DMA_MASK;
+      val |= DMA_3_BITS;
+      pss_outpw (wssConfigAddress, val);
+      break;
+    default:
+      printk ("Personal Sound System ERROR! pss_setwssdma: unknown_dma\n");
+    }
+}
+
+
+/*_____ SetSpeakerOut
+         This function sets the Volume, Bass, Treble and Mode of
+	 the speaker out channel.
+	 */
+void
+pss_setspeaker (struct pss_speaker *spk)
+{
+  PSS_write (SET_MASTER_COMMAND);
+  if (spk->volume > PHILLIPS_VOL_MAX)
+    spk->volume = PHILLIPS_VOL_MAX;
+  if (spk->volume < PHILLIPS_VOL_MIN)
+    spk->volume = PHILLIPS_VOL_MIN;
+
+  PSS_write (MASTER_VOLUME_LEFT
+	     | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
+  PSS_write (SET_MASTER_COMMAND);
+  PSS_write (MASTER_VOLUME_RIGHT
+	     | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
+
+  if (spk->bass > PHILLIPS_BASS_MAX)
+    spk->bass = PHILLIPS_BASS_MAX;
+  if (spk->bass < PHILLIPS_BASS_MIN)
+    spk->bass = PHILLIPS_BASS_MIN;
+  PSS_write (SET_MASTER_COMMAND);
+  PSS_write (MASTER_BASS
+	     | (PHILLIPS_BASS_CONSTANT + spk->bass / PHILLIPS_BASS_STEP));
+
+  if (spk->treb > PHILLIPS_TREBLE_MAX)
+    spk->treb = PHILLIPS_TREBLE_MAX;
+  if (spk->treb < PHILLIPS_TREBLE_MIN)
+    spk->treb = PHILLIPS_TREBLE_MIN;
+  PSS_write (SET_MASTER_COMMAND);
+  PSS_write (MASTER_TREBLE
+	   | (PHILLIPS_TREBLE_CONSTANT + spk->treb / PHILLIPS_TREBLE_STEP));
+
+  PSS_write (SET_MASTER_COMMAND);
+  PSS_write (MASTER_SWITCH | spk->mode);
+}
+
+static void
+pss_init1848 (void)
+{
+  /*_____ Wait for 1848 to init */
+  while (INB (SoundPortAddress) & SP_IN_INIT);
+
+  /*_____ Wait for 1848 to autocal */
+  OUTB (SoundPortAddress, SP_TEST_AND_INIT);
+  while (INB (SoundPortData) & AUTO_CAL_IN_PROG);
+}
+
+static int
+pss_configure_registers_to_look_like_sb (void)
+{
+  pss_setaddr (wssAddr, pss_base + PSS_WSS_CONFIG);
+
+  SoundPortAddress = wssAddr + 4;
+  SoundPortData = wssAddr + 5;
+
+  DEB (printk ("Turning Game Port %s.\n",
+	       gamePort ? "On" : "Off"));
+
+  /*_____ Turn on the Game port */
+  if (gamePort)
+    pss_outpw (pss_base + PSS_STATUS,
+	       pss_inpw (pss_base + PSS_STATUS) | GAME_BIT);
+  else
+    pss_outpw (pss_base + PSS_STATUS,
+	       pss_inpw (pss_base + PSS_STATUS) & GAME_BIT_MASK);
+
+
+  DEB (printk ("PSS attaching base %x irq %d dma %d\n",
+	       pss_base, pss_irq, pss_dma));
+
+  /* Check if sb is enabled if it is check the interrupt */
+  pss_outpw (pss_base + SB_CONFIG, 0);
+
+  if (pss_irq != 0)
+    {
+      DEB (printk ("PSS Emulating Sound Blaster ADDR %04x\n", pss_base));
+      DEB (printk ("PSS SBC: attaching base %x irq %d dma %d\n",
+		   SBC_BASE, SBC_IRQ, SBC_DMA));
+
+      if (pss_checkint (SBC_IRQ) == 0)
+	{
+	  printk ("PSS! attach: int_error\n");
+	  return 0;
+	}
+
+      pss_setsbint (SBC_IRQ);
+      pss_setsbdma (SBC_DMA);
+      sb_ok = 1;
+    }
+  else
+    {
+      sb_ok = 0;
+      printk ("PSS: sound blaster error init\n");
+    }
+
+  /* Check if cd is enabled if it is check the interrupt */
+  pss_outpw (pss_base + CD_CONFIG, 0);
+
+  if (cdAddr != 0)
+    {
+      DEB (printk ("PSS:CD drive %x irq: %d", cdAddr, cdInt));
+      if (cdInt != 0)
+	{
+	  if (pss_checkint (cdInt) == 0)
+	    {
+	      printk ("Can't allocate cdInt %d\n", cdInt);
+	    }
+	  else
+	    {
+	      int             val;
+
+	      printk ("CD poll ");
+	      pss_setaddr (cdAddr, pss_base + CD_CONFIG);
+	      pss_setint (cdInt, pss_base + CD_CONFIG);
+
+	      /* set the correct bit in the
+		 configuration register to
+		 set the irq polarity for the CD-Rom.
+		 NOTE: This bit is in the address config
+		 field, It must be configured after setting
+		 the CD-ROM ADDRESS!!! */
+	      val = pss_inpw (pss_base + CD_CONFIG);
+	      pss_outpw (pss_base + CD_CONFIG, 0);
+	      val &= CD_POL_MASK;
+	      if (cdPol)
+		val |= CD_POL_BIT;
+	      pss_outpw (pss_base + CD_CONFIG, val);
+	    }
+	}
+    }
+
+  /* Check if midi is enabled if it is check the interrupt */
+  pss_outpw (pss_base + MIDI_CONFIG, 0);
+  if (midiAddr != 0)
+    {
+      printk ("midi init %x %d\n", midiAddr, midiInt);
+      if (pss_checkint (midiInt) == 0)
+	{
+	  printk ("midi init int error %x %d\n", midiAddr, midiInt);
+	}
+      else
+	{
+	  pss_setaddr (midiAddr, pss_base + MIDI_CONFIG);
+	  pss_setint (midiInt, pss_base + MIDI_CONFIG);
+	}
+    }
+  return 1;
+}
+
+long
+attach_pss (long mem_start, struct address_info *hw_config)
+{
+  if (pss_ok)
+    {
+      if (hw_config)
+	{
+	  printk (" <PSS-ESC614>");
+	}
+
+      return mem_start;
+    }
+
+  pss_ok = 1;
+
+  if (pss_configure_registers_to_look_like_sb () == 0)
+    return mem_start;
+
+  if (sb_ok)
+    if (pss_synthLen
+	&& pss_download_boot (pss_synth, pss_synthLen))
+      {
+	if (speaker)
+	  pss_setspeaker (&default_speaker);
+	pss_ok = 1;
+      }
+    else
+      pss_reset_dsp ();
+
+  return mem_start;
+}
+
+int
+probe_pss (struct address_info *hw_config)
+{
+  pss_base = hw_config->io_base;
+  pss_irq = hw_config->irq;
+  pss_dma = hw_config->dma;
+
+  if ((pss_inpw (pss_base + 4) & 0xff00) == 0x4500)
+    {
+      attach_pss (0, hw_config);
+      return 1;
+    }
+  printk (" fail base %x irq %d dma %d\n", pss_base, pss_irq, pss_dma);
+  return 0;
+}
+
+
+static int
+pss_reattach (void)
+{
+  pss_ok = 0;
+  attach_pss (0, 0);
+  return 1;
+}
+
+static int
+pss_reset_dsp ()
+{
+  unsigned long   i, limit = GET_TIME () + 10;
+
+  pss_outpw (pss_base + PSS_CONTROL, 0x2000);
+
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    pss_inpw (pss_base + PSS_CONTROL);
+
+  pss_outpw (pss_base + PSS_CONTROL, 0x0000);
+
+  return 1;
+}
+
+
+static int
+pss_download_boot (unsigned char *block, int size)
+{
+  int             i, limit, val, count;
+
+  printk ("PSS: downloading boot code synth.ld... ");
+
+  /*_____ Warn DSP software that a boot is coming */
+  pss_outpw (pss_base + PSS_DATA, 0x00fe);
+
+  limit = GET_TIME () + 10;
+
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    if (pss_inpw (pss_base + PSS_DATA) == 0x5500)
+      break;
+
+  pss_outpw (pss_base + PSS_DATA, *block++);
+
+  pss_reset_dsp ();
+  printk ("start ");
+
+  count = 1;
+  while (1)
+    {
+      int             j;
+
+      for (j = 0; j < 327670; j++)
+	{
+	  /*_____ Wait for BG to appear */
+	  if (pss_inpw (pss_base + PSS_STATUS) & PSS_FLAG3)
+	    break;
+	}
+
+      if (j == 327670)
+	{
+	  /* It's ok we timed out when the file was empty */
+	  if (count >= size)
+	    break;
+	  else
+	    {
+	      printk ("\nPSS: DownLoad timeout problems, byte %d=%d\n",
+		      count, size);
+	      return 0;
+	    }
+	}
+      /*_____ Send the next byte */
+      pss_outpw (pss_base + PSS_DATA, *block++);
+      count++;
+    }
+
+  /*_____ Why */
+  pss_outpw (pss_base + PSS_DATA, 0);
+
+  limit = GET_TIME () + 10;
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    val = pss_inpw (pss_base + PSS_STATUS);
+
+  printk ("downloaded\n");
+
+  limit = GET_TIME () + 10;
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    {
+      val = pss_inpw (pss_base + PSS_STATUS);
+      if (val & 0x4000)
+	break;
+    }
+
+  /* now read the version */
+  for (i = 0; i < 32000; i++)
+    {
+      val = pss_inpw (pss_base + PSS_STATUS_REG);
+      if (val & PSS_READ_FULL)
+	break;
+    }
+  if (i == 32000)
+    return 0;
+
+  val = pss_inpw (pss_base + PSS_DATA_REG);
+
+  return 1;
+}
+
+
+/* The following is a simple device driver for the pss.
+   All I really care about is comunication to and from the pss.
+
+   The ability to reinitialize the <synth.ld>  This will be
+   default when release is choosen.
+
+   SNDCTL_PSS_DOWNLOAD:
+
+   Okay we need to creat new minor numbers for the
+   DOWNLOAD functionality.
+
+   14,0x19 -- /dev/pssld where a read operation would output the
+                         current ld to user space
+                         where a write operation would effectively
+			 download a new ld.
+
+   14,0x09 -- /dev/psecho  would open up a comunication path to the
+                         esc614 asic.  Given the ability to send
+			 messages to the asic and recive messages too.
+
+			 All messages would get read and written in the
+			 same manner.  It would be up to the application
+			 and the ld to maintain a relationship
+			 of what the messages mean.
+			
+			 for this device we need to implement select. */
+#define CODE_BUFFER_LEN (64*1024)
+static char    *code_buffer;
+static int      code_length;
+
+static int      lock_pss = 0;
+
+int
+pss_open (int dev, struct fileinfo *file)
+{
+  int             mode;
+
+  DEB (printk ("pss_open\n"));
+
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  if (lock_pss)
+    return 0;
+
+  lock_pss = 1;
+
+  dev = dev >> 4;
+  mode = file->mode & O_ACCMODE;
+  if (mode == O_WRONLY)
+    {
+      printk ("pss-open for WRONLY\n");
+      code_length = 0;
+    }
+
+  RESET_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
+  return 1;
+}
+
+void
+pss_release (int dev, struct fileinfo *file)
+{
+  int             mode;
+
+  DEB (printk ("pss_release\n"));
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  dev = dev >> 4;
+  mode = file->mode & O_ACCMODE;
+  if (mode == O_WRONLY && code_length > 0)
+    {
+#ifdef linux
+      /* This just allows interrupts while the conversion is running */
+      __asm__ ("sti");
+#endif
+      if (!pss_download_boot (code_buffer, code_length))
+	{
+	  pss_reattach ();
+	}
+    }
+  lock_pss = 0;
+}
+
+int
+pss_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+  int             c, p;
+
+  DEB (printk ("pss_read\n"));
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  dev = dev >> 4;
+  p = 0;
+  c = count;
+
+  return count - c;
+}
+
+int
+pss_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+  DEB (printk ("pss_write\n"));
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+  dev = dev >> 4;
+
+  if (count)			/* Flush output */
+    {
+      COPY_FROM_USER (&code_buffer[code_length], buf, 0, count);
+      code_length += count;
+    }
+  return count;
+}
+
+
+int
+pss_ioctl (int dev, struct fileinfo *file,
+	   unsigned int cmd, unsigned int arg)
+{
+  DEB (printk ("pss_ioctl dev=%d cmd=%x\n", dev, cmd));
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  dev = dev >> 4;
+
+  switch (cmd)
+    {
+    case SNDCTL_PSS_RESET:
+      pss_reattach ();
+      return 1;
+
+    case SNDCTL_PSS_SETUP_REGISTERS:
+      pss_configure_registers_to_look_like_sb ();
+      return 1;
+
+    case SNDCTL_PSS_SPEAKER:
+      {
+	struct pss_speaker params;
+	COPY_FROM_USER (&params, (char *) arg, 0, sizeof (struct pss_speaker));
+
+	pss_setspeaker (&params);
+	return 0;
+      }
+    default:
+      return RET_ERROR (EIO);
+    }
+}
+
+/* This is going to be used to implement
+   waiting on messages sent from the DSP and to the
+   DSP when comunication is used via the pss directly.
+
+   We need to find out if the pss can generate a diffrent
+   interupt other than the one it has been setup for.
+
+   This way we can carry on a conversation with the pss
+   on a seprate chanel.  This would be usefull for debugging. */
+
+pss_select (int dev, struct fileinfo * file, int sel_type, select_table * wait)
+{
+  return 0;
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  dev = dev >> 4;
+
+  switch (sel_type)
+    {
+    case SEL_IN:
+      select_wait (&pss_sleeper, wait);
+      return 0;
+      break;
+
+    case SEL_OUT:
+      select_wait (&pss_sleeper, wait);
+      return 0;
+      break;
+
+    case SEL_EX:
+      return 0;
+    }
+
+  return 0;
+}
+
+long
+pss_init (long mem_start)
+{
+  DEB (printk ("pss_init\n"));
+  if (pss_ok)
+    {
+      code_buffer = mem_start;
+      mem_start += CODE_BUFFER_LEN;
+    }
+  return mem_start;
+}
+
+#endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pss.h linux/drivers/sound/pss.h
--- v1.1.30/linux/drivers/sound/pss.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/pss.h	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,371 @@
+/******************************************************************************
+
+	def.h
+
+	Version 1.3	11/2/93
+
+	Copyright (c) 1993 Analog Devices Inc. All rights reserved
+
+******************************************************************************/
+/* Port offsets from base port for Sound Blaster DSP */
+#define DSP_PORT_CMSD0      0x00  /* C/MS music voice 1-6 data port, write only */
+#define DSP_PORT_CMSR0      0x01  /* C/MS music voice 1-6 register port, write only */
+#define DSP_PORT_CMSD1      0x02  /* C/MS music voice 7-12 data port, write only */
+#define DSP_PORT_CMSR1      0x03  /* C/MS music voice 7-12 register port, write only */
+
+#define DSP_PORT_STATUS     0x04  /* DSP Status bits, read only */
+#define DSP_PORT_CONTROL    0x04  /* DSP Control bits, write only */
+#define DSP_PORT_DATA_LSB   0x05  /* Read or write LSB of 16 bit data */
+
+
+#define DSP_PORT_RESET      0x06  /* DSP Reset, write only */
+#define DSP_PORT_07h        0x07  /* reserved port */
+
+#define DSP_PORT_FMD0       0x08  /* FM music data/status port, read/write  */
+#define DSP_PORT_FMR0       0x09  /* FM music data/status port, write only */
+
+#define DSP_PORT_RDDATA     0x0A  /* DSP Read data, read only reading signals DSP */
+#define DSP_PORT_0Bh        0x0B  /* reserved port */
+#define DSP_PORT_WRDATA     0x0C  /* DSP Write data or command, write */
+#define DSP_PORT_WRBUSY     0x0C  /* DSP Write buffer status (bit 7), read */
+#define DSP_PORT_0Dh        0x0D  /* reserved port */
+#define DSP_PORT_DATAAVAIL  0x0E  /* DSP Data available status (bit 7), read only */
+#define DSP_PORT_INTERFACE  0x0E  /* Sets DMA Channel and Interrupt, write only */
+#define DSP_PORT_0Fh        0x0F  /* reserved port (used on Pro cards) */
+
+#define ADDR_MASK   0x003f
+
+#define INT_MASK    0xffc7
+#define INT_3_BITS  0x0008
+#define INT_5_BITS  0x0010
+#define INT_7_BITS  0x0018
+#define INT_9_BITS  0x0020
+#define INT_10_BITS 0x0028
+#define INT_11_BITS 0x0030
+#define INT_12_BITS 0x0038
+
+#define GAME_BIT      0x0400
+#define GAME_BIT_MASK 0xfbff
+
+#define INT_TEST_BIT 0x0200
+#define INT_TEST_PASS 0x0100
+#define INT_TEST_BIT_MASK 0xFDFF
+
+#define DMA_MASK    0xfff8
+#define DMA_0_BITS  0x0001
+#define DMA_1_BITS  0x0002
+#define DMA_3_BITS  0x0003
+#define DMA_5_BITS  0x0004
+#define DMA_6_BITS  0x0005
+#define DMA_7_BITS  0x0006
+
+#define DMA_TEST_BIT  0x0080
+#define DMA_TEST_PASS 0x0040
+#define DMA_TEST_BIT_MASK 0xFF7F
+
+
+/* Echo DSP Flags */
+
+#define DSP_FLAG3     0x10
+#define DSP_FLAG2     0x08
+#define DSP_FLAG1     0x80
+#define DSP_FLAG0     0x40
+
+#define PSS_CONFIG    0x10
+#define PSS_WSS_CONFIG    0x12
+#define SB_CONFIG     0x14
+#define MIDI_CONFIG   0x18
+#define CD_CONFIG     0x16
+#define UART_CONFIG   0x1a
+
+#define PSS_DATA      0x00
+#define PSS_STATUS    0x02
+#define PSS_CONTROL   0x02
+#define PSS_ID_VERS   0x04
+
+#define PSS_FLAG3     0x0800
+#define PSS_FLAG2     0x0400
+#define PSS_FLAG1     0x1000
+#define PSS_FLAG0     0x0800
+
+/*_____ WSS defines */
+#define WSS_BASE_ADDRESS 0x530
+#define WSS_CONFIG       0x0
+#define WSS_VERSION      0x03
+#define WSS_SP0          0x04
+#define WSS_SP1          0x05
+#define WSS_SP2          0x06
+#define WSS_SP3          0x07
+
+/*_____ SoundPort register addresses */
+
+#define SP_LIN_SOURCE_CTRL   0x00
+#define SP_RIN_SOURCE_CTRL   0x01
+#define SP_LIN_GAIN_CTRL   0x10
+#define SP_RIN_GAIN_CTRL   0x11
+#define SP_LAUX1_CTRL      0x02
+#define SP_RAUX1_CTRL      0x03
+#define SP_LAUX2_CTRL      0x04
+#define SP_RAUX2_CTRL      0x05
+#define SP_LOUT_CTRL       0x06
+#define SP_ROUT_CTRL       0x07
+#define SP_CLK_FORMAT      0x48
+#define SP_INT_CONF        0x09
+#define SP_INT_CONF_MCE    0x49
+#define SP_PIN_CTRL        0x0a
+#define SP_TEST_INIT       0x0b
+#define SP_MISC_CTRL       0x0c
+#define SP_MIX_CTRL        0x0d
+#define SP_DMA_UCNT        0x0e
+#define SP_DMA_LCNT        0x0f
+
+/*_____ Gain constants  */
+
+#define GAIN_0      0x00
+#define GAIN_1_5    0x01
+#define GAIN_3      0x02
+#define GAIN_4_5    0x03
+#define GAIN_6      0x04
+#define GAIN_7_5    0x05
+#define GAIN_9      0x06
+#define GAIN_10_5   0x07
+#define GAIN_12     0x08
+#define GAIN_13_5   0x09
+#define GAIN_15     0x0a
+#define GAIN_16_5   0x0b
+#define GAIN_18     0x0c
+#define GAIN_19_5   0x0d
+#define GAIN_21     0x0e
+#define GAIN_22_5   0x0f
+#define MUTE       0XFFFF
+
+/*_____ Attenuation constants  */
+
+#define ATTEN_0      0x00
+#define ATTEN_1_5    0x01
+#define ATTEN_3      0x02
+#define ATTEN_4_5    0x03
+#define ATTEN_6      0x04
+#define ATTEN_7_5    0x05
+#define ATTEN_9      0x06
+#define ATTEN_10_5   0x07
+#define ATTEN_12     0x08
+#define ATTEN_13_5   0x09
+#define ATTEN_15     0x0a
+#define ATTEN_16_5   0x0b
+#define ATTEN_18     0x0c
+#define ATTEN_19_5   0x0d
+#define ATTEN_21     0x0e
+#define ATTEN_22_5   0x0f
+
+
+#define PSS_WRITE_EMPTY 0x8000
+
+#define CD_POL_MASK 0xFFBF
+#define CD_POL_BIT  0x0040
+
+
+
+/******************************************************************************
+
+	host.h
+
+	Version 1.2	9/27/93
+
+	Copyright (c) 1993 Analog Devices Inc. All rights reserved
+
+******************************************************************************/
+#define SB_WRITE_FULL    0x80
+#define SB_READ_FULL     0x80
+#define SB_WRITE_STATUS  0x0C
+#define SB_READ_STATUS   0x0E
+#define SB_READ_DATA     0x0A
+#define SB_WRITE_DATA    0x0C
+
+#define PSS_DATA_REG     0x00
+#define PSS_STATUS_REG   0x02
+#define PSS_WRITE_EMPTY  0x8000
+#define PSS_READ_FULL    0x4000
+
+/*_____ 1848 Sound Port bit defines */
+
+#define SP_IN_INIT            0x80
+#define MODE_CHANGE_ENABLE    0x40
+#define MODE_CHANGE_MASK      0xbf
+#define TRANSFER_DISABLE      0x20
+#define TRANSFER_DISABLE_MASK 0xdf
+#define ADDRESS_MASK          0xf0
+
+/*_____ Status bits */
+#define INTERRUPT_STATUS      0x01
+#define PLAYBACK_READY        0x02
+#define PLAYBACK_LEFT         0x04
+/*_____ pbright is not left */
+#define PLAYBACK_UPPER        0x08
+/*_____ bplower is not upper */
+
+#define SAMPLE_OVERRUN        0x10
+#define SAMPLE_UNDERRUN       0x10
+#define CAPTURE_READY         0x20
+#define CAPTURE_LEFT          0x40
+/*_____ cpright is not left */
+#define CAPTURE_UPPER         0x08
+/*_____ cplower is not upper */
+
+/*_____ Input & Output regs bits */
+#define LINE_INPUT            0x80
+#define AUX_INPUT             0x40
+#define MIC_INPUT             0x80
+#define MIXED_DAC_INPUT       0xC0
+#define INPUT_GAIN_MASK       0xf0
+#define INPUT_MIC_GAIN_ENABLE 0x20
+#define INPUT_MIC_GAIN_MASK   0xdf
+#define INPUT_SOURCE_MASK     0x3f
+#define AUX_INPUT_ATTEN_MASK  0xf0
+#define AUX_INPUT_MUTE        0x80
+#define AUX_INPUT_MUTE_MASK   0x7f
+#define OUTPUT_MUTE           0x80
+#define OUTPUT_MUTE_MASK      0x7f
+#define OUTPUT_ATTEN_MASK     0xc0
+
+/*_____ Clock and Data format reg bits */
+#define CLOCK_SELECT_MASK     0xfe
+#define CLOCK_XTAL2           0x01
+#define CLOCK_XTAL1           0x00
+#define CLOCK_FREQ_MASK       0xf1
+#define STEREO_MONO_MASK      0xef
+#define STEREO                0x10
+#define AUDIO_MONO            0x00
+#define LINEAR_COMP_MASK      0xdf
+#define LINEAR                0x00
+#define COMPANDED             0x20
+#define FORMAT_MASK           0xbf
+#define PCM                   0x00
+#define ULAW                  0x00
+#define TWOS_COMP             0x40
+#define ALAW                  0x40
+
+/*_____ Interface Configuration reg bits */
+#define PLAYBACK_ENABLE       0x01
+#define PLAYBACK_ENABLE_MASK  0xfe
+#define CAPTURE_ENABLE        0x02
+#define CAPTURE_ENABLE_MASK   0xfd
+#define SINGLE_DMA            0x04
+#define SINGLE_DMA_MASK       0xfb
+#define DUAL_DMA              0x00
+#define AUTO_CAL_ENABLE       0x08
+#define AUTO_CAL_DISABLE_MASK 0xf7
+#define PLAYBACK_PIO_ENABLE   0x40
+#define PLAYBACK_DMA_MASK     0xbf
+#define CAPTURE_PIO_ENABLE    0x80
+#define CAPTURE_DMA_MASK      0x7f
+
+/*_____ Pin control bits */
+#define INTERRUPT_ENABLE      0x02
+#define INTERRUPT_MASK        0xfd
+
+/*_____ Test and init reg bits */
+#define OVERRANGE_LEFT_MASK   0xfc
+#define OVERRANGE_RIGHT_MASK  0xf3
+#define DATA_REQUEST_STATUS   0x10
+#define AUTO_CAL_IN_PROG      0x20
+#define PLAYBACK_UNDERRUN     0x40
+#define CAPTURE_UNDERRUN      0x80
+
+/*_____ Miscellaneous Control reg bits */
+#define ID_MASK               0xf0
+
+/*_____ Digital Mix Control reg bits */
+#define DIGITAL_MIX1_MUTE_MASK 0xfe
+#define MIX_ATTEN_MASK         0x03
+
+/*_____ 1848 Sound Port reg defines */
+
+#define SP_LEFT_INPUT_CONTROL    0x0
+#define SP_RIGHT_INPUT_CONTROL   0x1
+#define SP_LEFT_AUX1_CONTROL     0x2
+#define SP_RIGHT_AUX1_CONTROL    0x3
+#define SP_LEFT_AUX2_CONTROL     0x4
+#define SP_RIGHT_AUX2_CONTROL    0x5
+#define SP_LEFT_OUTPUT_CONTROL   0x6
+#define SP_RIGHT_OUTPUT_CONTROL  0x7
+#define SP_CLOCK_DATA_FORMAT     0x8
+#define SP_INTERFACE_CONFIG      0x9
+#define SP_PIN_CONTROL           0xA
+#define SP_TEST_AND_INIT         0xB
+#define SP_MISC_INFO             0xC
+#define SP_DIGITAL_MIX           0xD
+#define SP_UPPER_BASE_COUNT      0xE
+#define SP_LOWER_BASE_COUNT      0xF
+
+#define HOST_SP_ADDR (0x534)
+#define HOST_SP_DATA (0x535)
+
+
+/******************************************************************************
+
+	phillips.h
+
+	Version 1.2	9/27/93
+
+	Copyright (c) 1993 Analog Devices Inc. All rights reserved
+
+******************************************************************************/
+/*_____ Phillips control SW defines */
+
+/*_____ Settings and ranges */
+#define VOLUME_MAX   6
+#define VOLUME_MIN (-64)
+#define VOLUME_RANGE 70
+#define VOLUME_STEP  2
+#define BASS_MAX    15
+#define BASS_MIN   (-12)
+#define BASS_STEP    2
+#define BASS_RANGE 27
+#define TREBLE_MAX  12
+#define TREBLE_MIN (-12)
+#define TREBLE_STEP  2
+#define TREBLE_RANGE 24
+
+#define VOLUME_CONSTANT 252
+#define BASS_CONSTANT   246
+#define TREBLE_CONSTANT 246
+
+/*_____ Software commands */
+#define SET_MASTER_COMMAND  0x0010
+#define MASTER_VOLUME_LEFT  0x0000
+#define MASTER_VOLUME_RIGHT 0x0100
+#define MASTER_BASS         0x0200
+#define MASTER_TREBLE       0x0300
+#define MASTER_SWITCH       0x0800
+
+#define STEREO_MODE  0x00ce
+#define PSEUDO_MODE  0x00d6
+#define SPATIAL_MODE 0x00de
+#define MONO_MODE    0x00c6
+
+
+#define PSS_STEREO           0x00ce
+#define PSS_PSEUDO           0x00d6
+#define PSS_SPATIAL          0x00de
+#define PSS_MONO             0x00c6
+
+#define PHILLIPS_VOL_MIN          -64
+#define PHILLIPS_VOL_MAX            6
+#define PHILLIPS_VOL_DELTA         70
+#define PHILLIPS_VOL_INITIAL      -20
+#define PHILLIPS_VOL_CONSTANT     252
+#define PHILLIPS_VOL_STEP           2
+#define PHILLIPS_BASS_MIN         -12
+#define PHILLIPS_BASS_MAX          15
+#define PHILLIPS_BASS_DELTA        27
+#define PHILLIPS_BASS_INITIAL       0
+#define PHILLIPS_BASS_CONSTANT    246
+#define PHILLIPS_BASS_STEP          2
+#define PHILLIPS_TREBLE_MIN       -12
+#define PHILLIPS_TREBLE_MAX        12
+#define PHILLIPS_TREBLE_DELTA      24
+#define PHILLIPS_TREBLE_INITIAL     0
+#define PHILLIPS_TREBLE_CONSTANT  246
+#define PHILLIPS_TREBLE_STEP        2
+
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c
--- v1.1.30/linux/drivers/sound/sb16_dsp.c	Sun May  1 12:12:39 1994
+++ linux/drivers/sound/sb16_dsp.c	Mon Jul 18 09:50:55 1994
@@ -32,7 +32,7 @@
 #define DEB(x)
 #define DEB1(x)
 /*
-   #define DEB_DMARES
+ * #define DEB_DMARES
  */
 #include "sound_config.h"
 #include "sb.h"
@@ -40,19 +40,28 @@
 
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
 
-extern int      sbc_base, sbc_minor, sbc_major;
+extern int      sbc_base;
 
-static int      sb16_dsp_ok = 0;/* Set to 1 after successful initialization */
+static int      sb16_dsp_ok = 0;/*
+
+
+					 * *  * * Set to 1 after successful *
+					 * * initialization   */
 static int      dsp_16bit = 0;
 static int      dsp_stereo = 0;
-static int      dsp_current_speed = 8000;	/*DSP_DEFAULT_SPEED; */
+static int      dsp_current_speed = 8000;	/*
+
+
+						 * *  * * DSP_DEFAULT_SPEED;  */
 static int      dsp_busy = 0;
 static int      dma16, dma8;
 static unsigned long dsp_count = 0;
 
-static int      irq_mode = IMODE_NONE;	/* IMODE_INPUT, IMODE_OUTPUT or
+static int      irq_mode = IMODE_NONE;	/*
+
 
-					   IMODE_NONE */
+					 * *  * * IMODE_INPUT, IMODE_OUTPUT
+					 * or * * IMODE_NONE   */
 static int      my_dev = 0;
 
 static volatile int intr_active = 0;
@@ -74,7 +83,9 @@
 static struct audio_operations sb16_dsp_operations =
 {
   "SoundBlaster 16",
-  NOTHING_SPECIAL,
+  DMA_AUTOMODE,
+  AFMT_U8 | AFMT_S16_LE,
+  NULL,
   sb16_dsp_open,
   sb16_dsp_close,
   sb16_dsp_output_block,
@@ -100,79 +111,6 @@
 }
 
 static int
-wait_data_avail (unsigned long t)
-{
-  int             loopc = 5000000;
-
-  t += GET_TIME ();
-  do
-    {
-      if (INB (DSP_DATA_AVAIL) & 0x80)
-	return 1;
-    }
-  while (--loopc && GET_TIME () < t);
-  printk ("!data_avail l=%d\n", loopc);
-  return 0;
-}
-
-static int
-read_dsp (int t)
-{
-  if (!wait_data_avail ((unsigned long) t))
-    return -1;
-  else
-    return INB (DSP_READ);
-}
-
-static int
-dsp_ini2 (void)
-{
-#if 0
-  /* sb_setmixer(0x83, sb_getmixer(0x83) | 0x03);       */
-  sb_dsp_command (0xe2);
-  sb_dsp_command (0x76);	/* E0 ??? */
-  sb_dsp_command (0xe2);
-  sb_dsp_command (0x30);	/* A0 ??? */
-  sb_dsp_command (0xe4);
-  sb_dsp_command (0xaa);
-  sb_dsp_command (0xe8);
-  if (read_dsp (100) != 0xaa)
-    printk ("Error dsp_ini2\n");
-#endif
-  return 0;
-}
-
-/*
-   static char *dsp_getmessage(unsigned char command,int maxn)
-   {
-   static char buff[100];
-   int n=0;
-
-   sb_dsp_command(command);
-   while(n<maxn && wait_data_avail(2L)) {
-   buff[++n]=INB(DSP_READ);
-   if(!buff[n])
-   break;
-   }
-   buff[0]=n;
-   return buff;
-   }
-
-   static void dsp_showmessage(unsigned char command,int len)
-   {
-   int n;
-   unsigned char *c;
-   c=dsp_getmessage(command,len);
-   printk("DSP C=%x l=%d,lr=%d b=",command,len,c[0]);
-   for(n=1;n<=c[0];n++)
-   if(c[n]>=' ' & c[n]<='z')
-   printk("%c",c[n]);
-   else
-   printk("|%x|",c[n]);
-   printk("\n");
-   }
- */
-static int
 dsp_set_speed (int mode)
 {
   DEB (printk ("dsp_set_speed(%d)\n", mode));
@@ -212,7 +150,7 @@
 	dsp_16bit = 1;
 	break;
       default:
-	return RET_ERROR (EINVAL);
+	dsp_16bit = 0;
       }
   return dsp_16bit ? 16 : 8;
 }
@@ -247,7 +185,7 @@
 	return dsp_stereo + 1;
       return IOCTL_OUT (arg, dsp_stereo + 1);
 
-    case SNDCTL_DSP_SAMPLESIZE:
+    case SNDCTL_DSP_SETFMT:
       if (local)
 	return dsp_set_bits (arg);
       return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
@@ -257,7 +195,9 @@
 	return dsp_16bit ? 16 : 8;
       return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
 
-    case SOUND_PCM_WRITE_FILTER:	/* NOT YET IMPLEMENTED */
+    case SOUND_PCM_WRITE_FILTER:	/*
+					 * NOT YET IMPLEMENTED
+					 */
       if (IOCTL_IN (arg) > 1)
 	return IOCTL_OUT (arg, RET_ERROR (EINVAL));
     default:
@@ -286,6 +226,8 @@
   if (retval < 0)
     return retval;
 
+  sb_reset_dsp ();
+
   if (ALLOC_DMA_CHN (dma8))
     {
       printk ("SB16: Unable to grab DMA%d\n", dma8);
@@ -302,8 +244,6 @@
 	return RET_ERROR (EBUSY);
       }
 
-  dsp_ini2 ();
-
   irq_mode = IMODE_NONE;
   dsp_busy = 1;
 
@@ -344,7 +284,7 @@
   printk ("output_block: %x %d %d\n", buf, count, intrflag);
   if (intrflag)
     {
-      int             pos, chan = sound_dsp_dmachan[dev];
+      int             pos, chan = audio_devs[dev]->dmachan;
 
       DISABLE_INTR (flags);
       clear_dma_ff (chan);
@@ -355,13 +295,15 @@
       printk ("dmapos=%d %x\n", pos, pos);
     }
 #endif
-  if (sound_dma_automode[dev] &&
+  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 */
+      return;			/*
+				 * Auto mode on. No need to react
+				 */
     }
   DISABLE_INTR (flags);
 
@@ -378,13 +320,11 @@
 				   (dsp_16bit ? 0x10 : 0)));
   sb_dsp_command01 ((unsigned char) (cnt & 0xff));
   sb_dsp_command ((unsigned char) (cnt >> 8));
-  /* sb_dsp_command (0);
-     sb_dsp_command (0); */
 
-  RESTORE_INTR (flags);
   dsp_count = cnt;
   irq_mode = IMODE_OUTPUT;
   intr_active = 1;
+  RESTORE_INTR (flags);
 }
 
 static void
@@ -401,7 +341,7 @@
   printk ("start_input: %x %d %d\n", buf, count, intrflag);
   if (intrflag)
     {
-      int             pos, chan = sound_dsp_dmachan[dev];
+      int             pos, chan = audio_devs[dev]->dmachan;
 
       DISABLE_INTR (flags);
       clear_dma_ff (chan);
@@ -412,19 +352,21 @@
       printk ("dmapos=%d %x\n", pos, pos);
     }
 #endif
-  if (sound_dma_automode[dev] &&
+  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 */
+      return;			/*
+				 * Auto mode on. No need to react
+				 */
     }
   DISABLE_INTR (flags);
 
   if (dma_restart)
     {
-      sb16_dsp_halt (dev);
+      sb_reset_dsp ();
       DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
     }
 
@@ -437,18 +379,16 @@
   sb_dsp_command01 ((unsigned char) (cnt & 0xff));
   sb_dsp_command ((unsigned char) (cnt >> 8));
 
-  /* sb_dsp_command (0);
-     sb_dsp_command (0); */
-  RESTORE_INTR (flags);
   dsp_count = cnt;
   irq_mode = IMODE_INPUT;
   intr_active = 1;
+  RESTORE_INTR (flags);
 }
 
 static int
 sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
 {
-  sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+  audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
   dsp_count = 0;
   dsp_cleanup ();
   return 0;
@@ -457,7 +397,7 @@
 static int
 sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
 {
-  sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+  audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
   dsp_count = 0;
   dsp_cleanup ();
   return 0;
@@ -511,6 +451,9 @@
     case 7:
       ival = 4;
       break;
+    case 9:
+      ival = 1;
+      break;
     case 10:
       ival = 8;
       break;
@@ -524,8 +467,10 @@
 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;
+    return mem_start;		/* Not a SB16 */
 
 #ifndef SCO
   sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
@@ -533,13 +478,12 @@
 
   printk (" <%s>", sb16_dsp_operations.name);
 
-  if (num_dspdevs < MAX_DSP_DEV)
+  if (num_audiodevs < MAX_AUDIO_DEV)
     {
-      dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations;
-      sound_dsp_dmachan[my_dev] = hw_config->dma;
-      sound_buffcounts[my_dev] = 1;
-      sound_buffsizes[my_dev] = DSP_BUFFSIZE;
-      sound_dma_automode[my_dev] = 1;
+      audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations;
+      audio_devs[my_dev]->dmachan = hw_config->dma;
+      audio_devs[my_dev]->buffcount = 1;
+      audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
     }
   else
     printk ("SB: Too many DSP devices available\n");
@@ -551,9 +495,10 @@
 sb16_dsp_detect (struct address_info *hw_config)
 {
   struct address_info *sb_config;
+  extern int      sbc_major;
 
   if (sb16_dsp_ok)
-    return 1;			/* Already initialized */
+    return 1;			/* Can't drive two cards */
 
   if (!(sb_config = sound_getconf (SNDCARD_SB)))
     {
@@ -561,13 +506,16 @@
       return 0;
     }
 
-  /* sb_setmixer(OPSW,0xf);
-     if(sb_getmixer(OPSW)!=0xf)
-     return 0; */
+  /*
+   * 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 (hw_config->dma < 4)
     if (hw_config->dma != sb_config->dma)
       {
@@ -584,7 +532,7 @@
   DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
 
   /*
-   dsp_showmessage(0xe3,99);
+ * dsp_showmessage(0xe3,99);
  */
   sb16_dsp_ok = 1;
   return 1;
@@ -595,7 +543,9 @@
 {
   int             data;
 
-  data = INB (DSP_DATA_AVL16);	/* Interrupt acknowledge */
+  data = INB (DSP_DATA_AVL16);	/*
+				 * Interrupt acknowledge
+				 */
 
   if (intr_active)
     switch (irq_mode)
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c
--- v1.1.30/linux/drivers/sound/sb16_midi.c	Sun May  1 12:12:39 1994
+++ linux/drivers/sound/sb16_midi.c	Mon Jul 18 09:50:55 1994
@@ -33,10 +33,12 @@
 
 #if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
 
-#define	DATAPORT   (sb16midi_base)	/* MPU-401 Data I/O Port on IBM */
-#define	COMDPORT   (sb16midi_base+1)	/* MPU-401 Command Port on IBM */
-#define	STATPORT   (sb16midi_base+1)	/* MPU-401 Status Port on IBM */
+#include "sb.h"
 
+#define	DATAPORT   (sb16midi_base)
+#define	COMDPORT   (sb16midi_base+1)
+#define	STATPORT   (sb16midi_base+1)
+
 #define sb16midi_status()		INB(STATPORT)
 #define input_avail()		(!(sb16midi_status()&INPUT_AVAIL))
 #define output_ready()		(!(sb16midi_status()&OUTPUT_READY))
@@ -44,26 +46,24 @@
 #define sb16midi_read()		INB(DATAPORT)
 #define sb16midi_write(byte)	OUTB(byte, DATAPORT)
 
-#define	OUTPUT_READY	0x40	/* Mask for Data Read Redy Bit */
-#define	INPUT_AVAIL	0x80	/* Mask for Data Send Ready Bit */
-#define	MPU_ACK		0xFE	/* MPU-401 Acknowledge Response */
-#define	MPU_RESET	0xFF	/* MPU-401 Total Reset Command */
-#define	UART_MODE_ON	0x3F	/* MPU-401 "Dumb UART Mode" */
+#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_base = 0x330;
 static int      sb16midi_detected = 0;
 static int      my_dev;
+extern int      sbc_base;
 
 static int      reset_sb16midi (void);
 static void     (*midi_input_intr) (int dev, unsigned char data);
 
-extern int      sbc_major;
-
 static void
 sb16midi_input_loop (void)
 {
-
   while (input_avail ())
     {
       unsigned char   c = sb16midi_read ();
@@ -127,7 +127,9 @@
    * (After reset). Normally it takes just about 10 loops.
    */
 
-  for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);	/* Wait */
+  for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);	/*
+									 * Wait
+									 */
 
   if (!output_ready ())
     {
@@ -140,12 +142,6 @@
 }
 
 static int
-sb16midi_command (int dev, unsigned char midi_byte)
-{
-  return 1;
-}
-
-static int
 sb16midi_start_read (int dev)
 {
   return 0;
@@ -171,12 +167,19 @@
 static int
 sb16midi_buffer_status (int dev)
 {
-  return 0;			/* No data in buffers */
+  return 0;			/*
+				 * No data in buffers
+				 */
 }
 
+#define MIDI_SYNTH_NAME	"SoundBlaster 16 Midi"
+#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
 static struct midi_operations sb16midi_operations =
 {
-  {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI},
+  {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI},
+  &std_midi_synth,
   sb16midi_open,
   sb16midi_close,
   sb16midi_ioctl,
@@ -184,8 +187,9 @@
   sb16midi_start_read,
   sb16midi_end_read,
   sb16midi_kick,
-  sb16midi_command,
-  sb16midi_buffer_status
+  NULL,
+  sb16midi_buffer_status,
+  NULL
 };
 
 
@@ -201,7 +205,9 @@
     return RET_ERROR (EIO);
 
   DISABLE_INTR (flags);
-  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/* Wait */
+  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/*
+									 * Wait
+									 */
   sb16midi_cmd (UART_MODE_ON);
 
   ok = 0;
@@ -212,9 +218,15 @@
 
   RESTORE_INTR (flags);
 
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return mem_start;
+    }
+
   printk (" <SoundBlaster MPU-401>");
 
-  my_dev = num_midis;
+  std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &sb16midi_operations;
   return mem_start;
 }
@@ -235,8 +247,12 @@
 
   for (n = 0; n < 2 && !ok; n++)
     {
-      for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/* Wait */
-      sb16midi_cmd (MPU_RESET);	/* Send MPU-401 RESET Command */
+      for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/*
+										 * Wait
+										 */
+      sb16midi_cmd (MPU_RESET);	/*
+				 * Send MPU-401 RESET Command
+				 */
 
       /*
        * Wait at least 25 msec. This method is not accurate so let's make the
@@ -252,7 +268,9 @@
 
   sb16midi_opened = 0;
   if (ok)
-    sb16midi_input_loop ();	/* Flush input before enabling interrupts */
+    sb16midi_input_loop ();	/*
+				 * Flush input before enabling interrupts
+				 */
 
   RESTORE_INTR (flags);
 
@@ -264,10 +282,13 @@
 probe_sb16midi (struct address_info *hw_config)
 {
   int             ok = 0;
+  int             i;
+  extern int      sbc_major;
 
-  sb16midi_base = hw_config->io_base;
   if (sbc_major < 4)
-    return 0;			/* SB16 not detected */
+    return 0;			/* Not a SB16 */
+
+  sb16midi_base = hw_config->io_base;
 
   if (sb_get_irq () < 0)
     return 0;
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
--- v1.1.30/linux/drivers/sound/sb_dsp.c	Sat May  7 14:54:03 1994
+++ linux/drivers/sound/sb_dsp.c	Mon Jul 18 09:50:55 1994
@@ -25,10 +25,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * Modified:
- *	Hunyue Yau	Jan 6 1994
- *	Added code to support Sound Galaxy NX Pro
- *
  */
 
 #include "sound_config.h"
@@ -41,7 +37,7 @@
 
 int             sbc_base = 0;
 static int      sbc_irq = 0;
-static int	open_mode=0;
+static int      open_mode = 0;	/* Read, write or both */
 
 /*
  * The DSP channel can be used either for input or output. Variable
@@ -51,23 +47,36 @@
  * future version of this driver.
  */
 
-int             sb_dsp_ok = 0;	/* Set to 1 after successful initialization */
+int             sb_dsp_ok = 0;	/*
+
+
+				 * *  * * Set to 1 after successful
+				 * initialization  *  */
 static int      midi_disabled = 0;
 int             sb_dsp_highspeed = 0;
-int             sbc_major = 1;
-int             sbc_minor = 0;	/* DSP version */
+int             sbc_major = 1, sbc_minor = 0;	/*
+
+
+						   * *  * * DSP version   */
 static int      dsp_stereo = 0;
 static int      dsp_current_speed = DSP_DEFAULT_SPEED;
 static int      sb16 = 0;
 static int      irq_verified = 0;
 
 int             sb_midi_mode = NORMAL_MIDI;
-int             sb_midi_busy = 0;	/* 1 if the process has output to MIDI */
+int             sb_midi_busy = 0;	/*
+
+
+					 * *  * * 1 if the process has output
+					 * to *  * MIDI   */
 int             sb_dsp_busy = 0;
 
-volatile int    sb_irq_mode = IMODE_NONE;	/* IMODE_INPUT, IMODE_OUTPUT
+volatile int    sb_irq_mode = IMODE_NONE;	/*
 
-						 * or IMODE_NONE */
+
+						 * *  * * IMODE_INPUT, *
+						 * IMODE_OUTPUT * * or *
+						 * IMODE_NONE   */
 static volatile int irq_ok = 0;
 
 int             sb_duplex_midi = 0;
@@ -81,7 +90,9 @@
 
 #if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
 
-/* Common code for the midi and pcm functions */
+/*
+ * Common code for the midi and pcm functions
+ */
 
 int
 sb_dsp_command (unsigned char val)
@@ -89,7 +100,9 @@
   int             i;
   unsigned long   limit;
 
-  limit = GET_TIME () + HZ / 10;/* The timeout is 0.1 secods */
+  limit = GET_TIME () + HZ / 10;/*
+					   * The timeout is 0.1 secods
+					 */
 
   /*
    * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
@@ -121,25 +134,36 @@
 #ifndef EXCLUDE_SBPRO
   if (sb16)
     {
-      unsigned char   src = sb_getmixer (IRQ_STAT);	/* Interrupt source register */
+      unsigned char   src = sb_getmixer (IRQ_STAT);	/*
+
 
+							 * *  * * Interrupt
+							 * source * *
+							 * register   */
+
 #ifndef EXCLUDE_SB16
       if (src & 3)
 	sb16_dsp_interrupt (unit);
 
 #ifndef EXCLUDE_MIDI
       if (src & 4)
-	sb16midiintr (unit);	/* MPU401 interrupt */
+	sb16midiintr (unit);	/*
+				 * SB MPU401 interrupt
+				 */
 #endif
 
 #endif
 
       if (!(src & 1))
-	return;			/* Not a DSP interupt */
+	return;			/*
+				 * Not a DSP interupt
+				 */
     }
 #endif
 
-  status = INB (DSP_DATA_AVAIL);/* Clear interrupt */
+  status = INB (DSP_DATA_AVAIL);/*
+					 * Clear interrupt
+					 */
 
   if (sb_intr_active)
     switch (sb_irq_mode)
@@ -152,7 +176,9 @@
       case IMODE_INPUT:
 	sb_intr_active = 0;
 	DMAbuf_inputintr (my_dev);
-	/* A complete buffer has been input. Let's start new one */
+	/*
+	 * A complete buffer has been input. Let's start new one
+	 */
 	break;
 
       case IMODE_INIT:
@@ -160,13 +186,11 @@
 	irq_ok = 1;
 	break;
 
-#ifndef EXCLUDE_MIDI
-
       case IMODE_MIDI:
+#ifndef EXCLUDE_MIDI
 	sb_midi_interrupt (unit);
-	break;
-
 #endif
+	break;
 
       default:
 	printk ("SoundBlaster: Unexpected interrupt\n");
@@ -213,11 +237,19 @@
   tenmicrosec ();
   tenmicrosec ();
 
-  for (loopc = 0; loopc < 1000 && !(INB (DSP_DATA_AVAIL) & 0x80); loopc++);	/* Wait for data
-										 * available status */
+  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 0;			/*
+				 * Sorry
+				 */
 
   return 1;
 }
@@ -264,11 +296,15 @@
 	max_speed = 13000;
 
   if (speed > max_speed)
-    speed = max_speed;		/* Invalid speed */
+    speed = max_speed;		/*
+				 * Invalid speed
+				 */
 
   if (dsp_stereo && speed > 22050)
     speed = 22050;
-  /* Max. stereo speed is 22050 */
+  /*
+   * Max. stereo speed is 22050
+   */
 
   if ((speed > 22050) && sb_midi_busy)
     {
@@ -279,10 +315,14 @@
   if (dsp_stereo)
     speed *= 2;
 
-  /* Now the speed should be valid */
+  /*
+   * Now the speed should be valid
+   */
 
   if (speed > 22050)
-    {				/* High speed mode */
+    {				/*
+				 * High speed mode
+				 */
       int             tmp;
 
       tconst = (unsigned char) ((65536 -
@@ -305,7 +345,9 @@
       tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
 
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x40))/* Set time constant */
+      if (sb_dsp_command (0x40))/*
+					 * Set time constant
+					 */
 	sb_dsp_command (tconst);
       RESTORE_INTR (flags);
 
@@ -329,7 +371,9 @@
   return 0;
 #else
   if (sbc_major < 3 || sb16)
-    return 0;			/* Sorry no stereo */
+    return 0;			/*
+				 * Sorry no stereo
+				 */
 
   if (mode && sb_midi_busy)
     {
@@ -354,18 +398,22 @@
   sb_irq_mode = IMODE_OUTPUT;
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     count >>= 1;
   count--;
 
   if (sb_dsp_highspeed)
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x48))/* High speed size */
+      if (sb_dsp_command (0x48))/*
+					 * High speed size
+					 */
 	{
 	  sb_dsp_command ((unsigned char) (count & 0xff));
 	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
-	  sb_dsp_command (0x91);/* High speed 8 bit DAC */
+	  sb_dsp_command (0x91);/*
+					 * High speed 8 bit DAC
+					 */
 	}
       else
 	printk ("SB Error: Unable to start (high speed) DAC\n");
@@ -374,7 +422,9 @@
   else
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x14))/* 8-bit DAC (DMA) */
+      if (sb_dsp_command (0x14))/*
+					 * 8-bit DAC (DMA)
+					 */
 	{
 	  sb_dsp_command ((unsigned char) (count & 0xff));
 	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
@@ -390,7 +440,9 @@
 sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
 		    int restart_dma)
 {
-  /* Start a DMA input to the buffer pointed by dmaqtail */
+  /*
+   * Start a DMA input to the buffer pointed by dmaqtail
+   */
 
   unsigned long   flags;
 
@@ -400,18 +452,22 @@
   sb_irq_mode = IMODE_INPUT;
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     count >>= 1;
   count--;
 
   if (sb_dsp_highspeed)
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x48))/* High speed size */
+      if (sb_dsp_command (0x48))/*
+					 * High speed size
+					 */
 	{
 	  sb_dsp_command ((unsigned char) (count & 0xff));
 	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
-	  sb_dsp_command (0x99);/* High speed 8 bit ADC */
+	  sb_dsp_command (0x99);/*
+					 * High speed 8 bit ADC
+					 */
 	}
       else
 	printk ("SB Error: Unable to start (high speed) ADC\n");
@@ -420,7 +476,9 @@
   else
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x24))/* 8-bit ADC (DMA) */
+      if (sb_dsp_command (0x24))/*
+					 * 8-bit ADC (DMA)
+					 */
 	{
 	  sb_dsp_command ((unsigned char) (count & 0xff));
 	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
@@ -445,15 +503,19 @@
   dsp_cleanup ();
   dsp_speaker (OFF);
 
-  if (sbc_major == 3)		/* SB Pro */
+  if (sbc_major == 3)		/*
+				 * SB Pro
+				 */
     {
       if (dsp_stereo)
 	sb_dsp_command (0xa8);
       else
 	sb_dsp_command (0xa0);
 
-      dsp_speed (dsp_current_speed);	/* Speed must be recalculated if #channels
-					   * changes */
+      dsp_speed (dsp_current_speed);	/*
+					 * Speed must be recalculated if
+					 * #channels * changes
+					 */
     }
   return 0;
 }
@@ -465,11 +527,15 @@
   dsp_speaker (ON);
 
 #ifndef EXCLUDE_SBPRO
-  if (sbc_major == 3)		/* SB Pro */
+  if (sbc_major == 3)		/*
+				 * SB Pro
+				 */
     {
       sb_mixer_set_stereo (dsp_stereo);
-      dsp_speed (dsp_current_speed);	/* Speed must be recalculated if #channels
-					   * changes */
+      dsp_speed (dsp_current_speed);	/*
+					 * Speed must be recalculated if
+					 * #channels * changes
+					 */
     }
 #endif
   return 0;
@@ -497,7 +563,9 @@
 
   sb_irq_mode = IMODE_INIT;
 
-  sb_dsp_command (0xf2);	/* This should cause immediate interrupt */
+  sb_dsp_command (0xf2);	/*
+				 * This should cause immediate interrupt
+				 */
 
   DO_SLEEP (testq, testf, HZ / 5);
 
@@ -544,7 +612,7 @@
   if (retval)
     return retval;
 
-  if (!DMAbuf_open_dma (dev))
+  if (DMAbuf_open_dma (dev) < 0)
     {
       sb_free_irq ();
       printk ("SB: DMA Busy\n");
@@ -610,7 +678,9 @@
     case SOUND_PCM_READ_BITS:
       if (local)
 	return 8;
-      return IOCTL_OUT (arg, 8);/* Only 8 bits/sample supported */
+      return IOCTL_OUT (arg, 8);/*
+					 * Only 8 bits/sample supported
+					 */
       break;
 
     case SOUND_PCM_WRITE_FILTER:
@@ -648,12 +718,16 @@
   sbc_irq = hw_config->irq;
 
   if (sb_dsp_ok)
-    return 0;			/* Already initialized */
+    return 0;			/*
+				 * Already initialized
+				 */
 
   if (!sb_reset_dsp ())
     return 0;
 
-  return 1;			/* Detected */
+  return 1;			/*
+				 * Detected
+				 */
 }
 
 #ifndef EXCLUDE_AUDIO
@@ -661,6 +735,8 @@
 {
   "SoundBlaster",
   NOTHING_SPECIAL,
+  AFMT_U8,			/* Just 8 bits. Poor old SB */
+  NULL,
   sb_dsp_open,
   sb_dsp_close,
   sb_dsp_output_block,
@@ -670,7 +746,7 @@
   sb_dsp_prepare_for_output,
   sb_dsp_reset,
   sb_dsp_halt_xfer,
-  NULL,				/* has_output_drained */
+  NULL,				/* local_qlen */
   NULL				/* copy_from_user */
 };
 
@@ -680,15 +756,18 @@
 sb_dsp_init (long mem_start, struct address_info *hw_config)
 {
   int             i;
-  int             prostat = 0;
 
   sbc_major = sbc_minor = 0;
-  sb_dsp_command (0xe1);	/* Get version */
+  sb_dsp_command (0xe1);	/*
+				 * Get version
+				 */
 
   for (i = 1000; i; i--)
     {
       if (INB (DSP_DATA_AVAIL) & 0x80)
-	{			/* wait for Data Ready */
+	{			/*
+				 * wait for Data Ready
+				 */
 	  if (sbc_major == 0)
 	    sbc_major = INB (DSP_READ);
 	  else
@@ -699,35 +778,28 @@
 	}
     }
 
-  if (sbc_major == 2 || sbc_major == 3)	/* SB 2.0 or SB Pro */
+  if (sbc_major == 2 || sbc_major == 3)
     sb_duplex_midi = 1;
 
   if (sbc_major == 4)
     sb16 = 1;
 
 #ifndef EXCLUDE_SBPRO
-  if (sbc_major >= 3 ||
-      (sbc_major == 2 && sbc_minor == 1))	/* Sound Galaxy ??? */
-    prostat = sb_mixer_init (sbc_major);
+  if (sbc_major >= 3)
+    sb_mixer_init (sbc_major);
 #endif
 
-#ifndef EXCLUDE_YM3812
+#ifndef EXCLUDE_YM8312
+
   if (sbc_major > 3 ||
-      (sbc_major == 3 && INB (0x388) == 0x00))	/* Non OPL-3 should return 0x06 */
+      (sbc_major == 3 && INB (0x388) == 0x00))	/* Should be 0x06 if not OPL-3 */
     enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
 #endif
 
   if (sbc_major >= 3)
     {
 #ifndef SCO
-      if (prostat)
-	{
-	  sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
-	}
-      else
-	{
-	  sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
-	}
+      sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
 #endif
     }
   else
@@ -741,23 +813,26 @@
 
 #ifndef EXCLUDE_AUDIO
 #if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
-  if (!sb16)			/* There is a better driver for SB16    */
+  if (!sb16)			/*
+				 * There is a better driver for SB16
+				 */
 #endif
-    if (num_dspdevs < MAX_DSP_DEV)
+    if (num_audiodevs < MAX_AUDIO_DEV)
       {
-	dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations;
-	sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
-	sound_buffsizes[my_dev] = DSP_BUFFSIZE;
-	sound_dsp_dmachan[my_dev] = hw_config->dma;
-	sound_dma_automode[my_dev] = 0;
+	audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations;
+	audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT;
+	audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
+	audio_devs[my_dev]->dmachan = hw_config->dma;
       }
     else
       printk ("SB: Too many DSP devices available\n");
 #endif
 
 #ifndef EXCLUDE_MIDI
-  if (!midi_disabled && !sb16)	/* Midi don't work in the SB emulation mode
-				 * of PAS, SB16 has better midi interface */
+  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
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c
--- v1.1.30/linux/drivers/sound/sb_midi.c	Sun May  1 12:12:41 1994
+++ linux/drivers/sound/sb_midi.c	Mon Jul 18 09:50:55 1994
@@ -42,23 +42,26 @@
  * future version of this driver.
  */
 
-extern int      sb_dsp_ok;	/* Set to 1 after successful initialization */
+extern int      sb_dsp_ok;	/* Set to 1 atfer 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_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;/* IMODE_INPUT, IMODE_OUTPUT
-
-					 * or IMODE_NONE */
+extern volatile int sb_irq_mode;
 extern int      sb_duplex_midi;
 extern int      sb_intr_active;
-extern int      sbc_base;
+int             input_opened = 0;
+static int      my_dev;
 
-static int      input_opened = 0;
-static void     (*midi_input_intr) (int dev, unsigned char data);
-static int      my_dev = 0;
+void            (*midi_input_intr) (int dev, unsigned char data);
 
 static int
 sb_midi_open (int dev, int mode,
@@ -74,10 +77,13 @@
       return RET_ERROR (ENXIO);
     }
 
+  if (sb_midi_busy)
+    return RET_ERROR (EBUSY);
+
   if (mode != OPEN_WRITE && !sb_duplex_midi)
     {
       if (num_midis == 1)
-	printk ("SoundBlaster: MIDI input not supported with plain SB\n");
+	printk ("SoundBlaster: Midi input not currently supported\n");
       return RET_ERROR (EPERM);
     }
 
@@ -101,20 +107,20 @@
 
       sb_reset_dsp ();
 
-      if (!sb_dsp_command (0xf2))	/* This is undodumented, isn't it */
-	return RET_ERROR (EIO);	/* be nice to DSP */
-
       if (!sb_dsp_command (0x35))
-	return RET_ERROR (EIO);	/* Enter the UART mode */
+	return RET_ERROR (EIO);	/*
+				 * Enter the UART mode
+				 */
       sb_intr_active = 1;
 
       if ((ret = sb_get_irq ()) < 0)
 	{
 	  sb_reset_dsp ();
-	  return 0;		/* IRQ not free */
+	  return 0;		/*
+				 * IRQ not free
+				 */
 	}
       input_opened = 1;
-      my_dev = dev;
       midi_input_intr = input;
     }
 
@@ -128,7 +134,9 @@
 {
   if (sb_midi_mode == UART_MIDI)
     {
-      sb_reset_dsp ();		/* The only way to kill the UART mode */
+      sb_reset_dsp ();		/*
+				 * The only way to kill the UART mode
+				 */
       sb_free_irq ();
     }
   sb_intr_active = 0;
@@ -141,8 +149,6 @@
 {
   unsigned long   flags;
 
-  sb_midi_busy = 1;		/* Kill all notes after close */
-
   if (sb_midi_mode == NORMAL_MIDI)
     {
       DISABLE_INTR (flags);
@@ -153,7 +159,9 @@
       RESTORE_INTR (flags);
     }
   else
-    sb_dsp_command (midi_byte);	/* UART write */
+    sb_dsp_command (midi_byte);	/*
+				 * UART write
+				 */
 
   return 1;
 }
@@ -201,23 +209,43 @@
   RESTORE_INTR (flags);
 }
 
+#define MIDI_SYNTH_NAME	"SoundBlaster Midi"
+#define MIDI_SYNTH_CAPS	0
+#include "midi_synth.h"
+
 static struct midi_operations sb_midi_operations =
 {
   {"SoundBlaster", 0, 0, SNDCARD_SB},
+  &std_midi_synth,
   sb_midi_open,
   sb_midi_close,
   sb_midi_ioctl,
   sb_midi_out,
   sb_midi_start_read,
   sb_midi_end_read,
-  NULL,				/* Kick */
-  NULL,				/* command */
-  NULL				/* buffer_status */
+  NULL,				/*
+				 * Kick
+				 */
+  NULL,				/*
+				 * command
+				 */
+  NULL,				/*
+				 * buffer_status
+				 */
+  NULL
 };
 
 void
 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++] = &sb_midi_operations;
 }
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v1.1.30/linux/drivers/sound/sb_mixer.c	Sun May  1 12:12:42 1994
+++ linux/drivers/sound/sb_mixer.c	Mon Jul 18 09:50:55 1994
@@ -26,10 +26,6 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * Modified:
- *	Hunyue Yau	Jan 6 1994
- *	Added code to support the Sound Galaxy NX Pro mixer.
- *
  */
 
 #include "sound_config.h"
@@ -58,7 +54,9 @@
   unsigned long   flags;
 
   DISABLE_INTR (flags);
-  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);	/* Select register */
+  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);	/*
+							 * Select register
+							 */
   tenmicrosec ();
   OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
   tenmicrosec ();
@@ -72,7 +70,9 @@
   unsigned long   flags;
 
   DISABLE_INTR (flags);
-  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);	/* Select register */
+  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);	/*
+							 * Select register
+							 */
   tenmicrosec ();
   val = INB (MIXER_DATA);
   tenmicrosec ();
@@ -91,21 +91,9 @@
 			    | (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)
 {
-#ifdef __SGNXPRO__
-  int             oldbass, oldtreble;
-
-#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
@@ -115,34 +103,13 @@
   sb_setmixer (VOC_VOL, 0x33);
 
   if (sb_getmixer (FM_VOL) != 0xff)
-    return 0;			/* No match */
+    return 0;			/*
+				 * No match
+				 */
   if (sb_getmixer (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);
-#endif
-  return retcode;
+  return 1;
 }
 
 static void
@@ -152,12 +119,18 @@
   int             shift;
 
   mask = (1 << (*iomap)[dev][chn].nbits) - 1;
-  newval = ((newval * mask) + 50) / 100;	/* Scale it */
+  newval = (int) ((newval * mask) + 50) / 100;	/*
+						 * Scale it
+						 */
 
   shift = (*iomap)[dev][chn].bitoffs - (*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);	/*
+				 * Filter out the previous value
+				 */
+  *regval |= (newval & mask) << shift;	/*
+					 * Set the new value
+					 */
 }
 
 static int
@@ -186,7 +159,9 @@
   if (dev > 31)
     return RET_ERROR (EINVAL);
 
-  if (!(supported_devices & (1 << dev)))	/* Not supported */
+  if (!(supported_devices & (1 << dev)))	/*
+						 * Not supported
+						 */
     return RET_ERROR (EINVAL);
 
   regoffs = (*iomap)[dev][LEFT_CHN].regno;
@@ -199,15 +174,23 @@
 
   levels[dev] = left | (left << 8);
 
-  if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)	/* Change register */
+  if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)	/*
+							 * Change register
+							 */
     {
-      sb_setmixer (regoffs, val);	/* Save the old one */
+      sb_setmixer (regoffs, val);	/*
+					 * Save the old one
+					 */
       regoffs = (*iomap)[dev][RIGHT_CHN].regno;
 
       if (regoffs == 0)
-	return left | (left << 8);	/* Just left channel present */
-
-      val = sb_getmixer (regoffs);	/* Read the new one */
+	return left | (left << 8);	/*
+					 * Just left channel present
+					 */
+
+      val = sb_getmixer (regoffs);	/*
+					 * Read the new one
+					 */
     }
 
   change_bits (&val, dev, RIGHT_CHN, right);
@@ -238,21 +221,27 @@
       if (devmask != SOUND_MASK_MIC &&
 	  devmask != SOUND_MASK_LINE &&
 	  devmask != SOUND_MASK_CD)
-	{			/* More than one devices selected. Drop the
-				 * previous selection */
+	{			/*
+				 * More than one devices selected. Drop the *
+				 * previous selection
+				 */
 	  devmask &= ~recmask;
 	}
 
       if (devmask != SOUND_MASK_MIC &&
 	  devmask != SOUND_MASK_LINE &&
 	  devmask != SOUND_MASK_CD)
-	{			/* More than one devices selected. Default to
-				 * mic */
+	{			/*
+				 * More than one devices selected. Default to
+				 * * mic
+				 */
 	  devmask = SOUND_MASK_MIC;
 	}
 
 
-      if (devmask ^ recmask)	/* Input source changed */
+      if (devmask ^ recmask)	/*
+				 * Input source changed
+				 */
 	{
 	  switch (devmask)
 	    {
@@ -312,7 +301,9 @@
 	    return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
 	  }
       else
-	switch (cmd & 0xff)	/* Return parameters */
+	switch (cmd & 0xff)	/*
+				 * Return parameters
+				 */
 	  {
 
 	  case SOUND_MIXER_RECSRC:
@@ -359,25 +350,18 @@
   set_recmask (SOUND_MASK_MIC);
 }
 
-/*
- * Returns a code depending on whether a SG NX Pro was detected.
- * 0 == Plain SB 16 or SB Pro
- * 1 == SG NX Pro detected.
- *
- * Used to update message.
- */
-int
+void
 sb_mixer_init (int major_model)
 {
-  int             mixerstat;
-
-  sb_setmixer (0x00, 0);	/* Reset mixer */
-
-  mixerstat = detect_mixer ();
+  sb_setmixer (0x00, 0);	/*
+				 * Reset mixer
+				 */
+
+  if (!detect_mixer ())
+    return;			/*
+				 * No mixer. Why?
+				 */
 
-  if (!mixerstat)
-    return 0;			/* No mixer. Why? */
-
   mixer_initialized = 1;
   mixer_model = major_model;
 
@@ -385,21 +369,9 @@
     {
     case 3:
       mixer_caps = SOUND_CAP_EXCL_INPUT;
-#ifdef __SGNXPRO__
-      if (mixerstat == 2)
-	{			/* A SGNXPRO was detected */
-	  supported_devices = SGNXPRO_MIXER_DEVICES;
-	  supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
-	  iomap = &sgnxpro_mix;
-	}
-      else
-#endif
-	{			/* Otherwise plain SB Pro */
-	  supported_devices = SBPRO_MIXER_DEVICES;
-	  supported_rec_devices = SBPRO_RECORDING_DEVICES;
-	  iomap = &sbpro_mix;
-	}
-
+      supported_devices = SBPRO_MIXER_DEVICES;
+      supported_rec_devices = SBPRO_RECORDING_DEVICES;
+      iomap = &sbpro_mix;
       break;
 
     case 4:
@@ -411,12 +383,12 @@
 
     default:
       printk ("SB Warning: Unsupported mixer type\n");
-      return 0;
+      return;
     }
 
-  mixer_devs[num_mixers++] = &sb_mixer_operations;
+  if (num_mixers < MAX_MIXER_DEV)
+    mixer_devs[num_mixers++] = &sb_mixer_operations;
   sb_mixer_reset ();
-  return (mixerstat == 2);
 }
 
 #endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h
--- v1.1.30/linux/drivers/sound/sb_mixer.h	Sun May  1 12:12:42 1994
+++ linux/drivers/sound/sb_mixer.h	Mon Jul 18 09:50:55 1994
@@ -24,29 +24,13 @@
  * 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.
- *
- * Modified:
- *	Hunyue Yau	Jan 6 1994
- *	Added defines for the Sound Galaxy NX Pro mixer.
  * 
  */
-
 #define SBPRO_RECORDING_DEVICES	(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
 
-/* Same as SB Pro, unless I find otherwise */
-#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
-
 #define SBPRO_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
 					 SOUND_MASK_CD | SOUND_MASK_VOLUME)
 
-/* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
- * channel is the COVOX/DisneySoundSource emulation volume control
- * on the mixer. It does NOT control speaker volume. Should have own
- * mask eventually?
- */
-#define SGNXPRO_MIXER_DEVICES	(SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
-				 SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
-
 #define SB16_RECORDING_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
 					 SOUND_MASK_CD)
 
@@ -78,13 +62,6 @@
 #define IRQ_STAT	0x82
 #define OPSW		0x3c
 
-/*
- * Additional registers on the SG NX Pro 
- */
-#define COVOX_VOL	0x42
-#define TREBLE_LVL	0x44
-#define BASS_LVL	0x46
-
 #define FREQ_HI         (1 << 3)/* Use High-frequency ANFI filters */
 #define FREQ_LOW        0	/* Use Low-frequency ANFI filters */
 #define FILT_ON         0	/* Yes, 0 to turn it on, 1 for off */
@@ -131,23 +108,6 @@
 MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0)
 };
 
-#ifdef	__SGNXPRO__
-mixer_tab sgnxpro_mix = {
-MIX_ENT(SOUND_MIXER_VOLUME,	0x22, 7, 4, 0x22, 3, 4),
-MIX_ENT(SOUND_MIXER_BASS,	0x46, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_TREBLE,	0x44, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_SYNTH,	0x26, 7, 4, 0x26, 3, 4),
-MIX_ENT(SOUND_MIXER_PCM,	0x04, 7, 4, 0x04, 3, 4),
-MIX_ENT(SOUND_MIXER_SPEAKER,	0x42, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE,	0x2e, 7, 4, 0x2e, 3, 4),
-MIX_ENT(SOUND_MIXER_MIC,	0x0a, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_CD,		0x28, 7, 4, 0x28, 3, 4),
-MIX_ENT(SOUND_MIXER_IMIX,	0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0)
-};
-#endif
-
 mixer_tab sb16_mix = {
 MIX_ENT(SOUND_MIXER_VOLUME,	0x30, 7, 5, 0x31, 7, 5),
 MIX_ENT(SOUND_MIXER_BASS,	0x46, 7, 4, 0x47, 7, 4),
@@ -209,4 +169,13 @@
 	0x00,	/* SOUND_MIXER_ALTPCM	*/
 	0x00	/* SOUND_MIXER_RECLEV	*/
 };
+
+/*
+ *	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 */
+
 #endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v1.1.30/linux/drivers/sound/sequencer.c	Sun May  1 12:12:43 1994
+++ linux/drivers/sound/sequencer.c	Mon Jul 18 09:50:55 1994
@@ -35,31 +35,52 @@
 #ifndef EXCLUDE_SEQUENCER
 
 static int      sequencer_ok = 0;
+static struct sound_timer_operations *tmr;
+static int      tmr_no = -1;	/* Currently selected timer */
+static int      pending_timer = -1;	/* For timer change operation */
+
+/*
+ * Local counts for number of synth and MIDI devices. These are initialized
+ * by the sequencer_open.
+ */
+static int      max_mididev = 0;
+static int      max_synthdev = 0;
+
+/*
+ * The seq_mode gives the operating mode of the sequencer:
+ *      1 = level1 (the default)
+ *      2 = level2 (extended capabilites)
+ */
+
+#define SEQ_1	1
+#define SEQ_2	2
+static int      seq_mode = SEQ_1;
 
 DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
-/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */
-#define midi_sleeper seq_sleeper
-#define midi_sleep_flag seq_sleep_flag
+DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
 
 static int      midi_opened[MAX_MIDI_DEV] =
-{0};				/* 1 if the process has opened MIDI */
+{0};
 static int      midi_written[MAX_MIDI_DEV] =
 {0};
 
-unsigned long   seq_time = 0;	/* Reference point for the timer */
+unsigned long   prev_input_time = 0;
+int             prev_event_time;
+unsigned long   seq_time = 0;
 
 #include "tuning.h"
 
 #define EV_SZ	8
-#define IEV_SZ	4
-static unsigned char *queue = NULL;	/* SEQ_MAX_QUEUE * EV_SZ bytes */
-static unsigned char *iqueue = NULL;	/* SEQ_MAX_QUEUE * IEV_SZ bytes */
+#define IEV_SZ	8
+static unsigned char *queue = NULL;
+static unsigned char *iqueue = NULL;
 
 static volatile int qhead = 0, qtail = 0, qlen = 0;
 static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
 static volatile int seq_playing = 0;
 static int      sequencer_busy = 0;
 static int      output_treshold;
+static int      pre_event_timeout;
 static unsigned synth_open_mask;
 
 static int      seq_queue (unsigned char *note);
@@ -70,48 +91,48 @@
 {0};
 
 #if MAX_SYNTH_DEV > 15
-#error Too many synthesizer devices
+#error Too many synthesizer devices enabled.
 #endif
 
 int
 sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
   int             c = count, p = 0;
+  int             ev_len;
   unsigned long   flags;
 
   dev = dev >> 4;
 
-  if (dev)			/* Patch manager device */
+  ev_len = seq_mode == SEQ_1 ? 4 : 8;
+
+  if (dev)			/*
+				 * Patch manager device
+				 */
     return pmgr_read (dev - 1, file, buf, count);
 
-  while (c > 3)
+  DISABLE_INTR (flags);
+  if (!iqlen)
     {
-      DISABLE_INTR (flags);
+      DO_SLEEP (midi_sleeper, midi_sleep_flag, pre_event_timeout);
+
       if (!iqlen)
 	{
-	  if (c != count)	/* Some data has been received */
-	    {
-	      RESTORE_INTR (flags);
-	      return count - c;	/* Return what we have */
-	    }
-
-	  DO_SLEEP (midi_sleeper, midi_sleep_flag, 0);
-
-	  if (!iqlen)
-	    {
-	      RESTORE_INTR (flags);
-	      return count - c;
-	    }
+	  RESTORE_INTR (flags);
+	  return 0;
 	}
+    }
+
+  while (iqlen && c >= ev_len)
+    {
 
-      COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ);
-      p += 4;
-      c -= 4;
+      COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], ev_len);
+      p += ev_len;
+      c -= ev_len;
 
       iqhead = (iqhead + 1) % SEQ_MAX_QUEUE;
       iqlen--;
-      RESTORE_INTR (flags);
     }
+  RESTORE_INTR (flags);
 
   return count - c;
 }
@@ -119,19 +140,30 @@
 static void
 sequencer_midi_output (int dev)
 {
-  /* Currently NOP */
+  /*
+   * Currently NOP
+   */
 }
 
-static void
-copy_to_input (unsigned char *event)
+void
+seq_copy_to_input (unsigned char *event, int len)
 {
   unsigned long   flags;
 
+  /*
+ * Verify that the len is valid for the current mode.
+ */
+
+  if (len != 4 && len != 8)
+    return;
+  if ((seq_mode == SEQ_1) != (len == 4))
+    return;
+
   if (iqlen >= (SEQ_MAX_QUEUE - 1))
     return;			/* Overflow */
 
   DISABLE_INTR (flags);
-  memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ);
+  memcpy (&iqueue[iqtail * IEV_SZ], event, len);
   iqlen++;
   iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
 
@@ -145,23 +177,54 @@
 static void
 sequencer_midi_input (int dev, unsigned char data)
 {
-  int             tstamp;
+  unsigned int    tstamp;
   unsigned char   event[4];
 
-  if (data == 0xfe)		/* Active sensing */
-    return;			/* Ignore */
+  if (data == 0xfe)		/* Ignore active sensing */
+    return;
 
-  tstamp = GET_TIME () - seq_time;	/* Time since open() */
-  tstamp = (tstamp << 8) | SEQ_WAIT;
+  tstamp = GET_TIME () - seq_time;
+  if (tstamp != prev_input_time)
+    {
+      tstamp = (tstamp << 8) | SEQ_WAIT;
 
-  copy_to_input ((unsigned char *) &tstamp);
+      seq_copy_to_input ((unsigned char *) &tstamp, 4);
+      prev_input_time = tstamp;
+    }
 
   event[0] = SEQ_MIDIPUTC;
   event[1] = data;
   event[2] = dev;
   event[3] = 0;
 
-  copy_to_input (event);
+  seq_copy_to_input (event, 4);
+}
+
+void
+seq_input_event (unsigned char *event, int len)
+{
+  unsigned long   this_time;
+
+  if (seq_mode == SEQ_2)
+    this_time = tmr->get_time (tmr_no);
+  else
+    this_time = GET_TIME () - seq_time;
+
+  if (this_time != prev_input_time)
+    {
+      unsigned char   tmp_event[8];
+
+      tmp_event[0] = EV_TIMING;
+      tmp_event[1] = TMR_WAIT_ABS;
+      tmp_event[2] = 0;
+      tmp_event[3] = 0;
+      *(unsigned long *) &tmp_event[4] = this_time;
+
+      seq_copy_to_input (tmp_event, 8);
+      prev_input_time = this_time;
+    }
+
+  seq_copy_to_input (event, len);
 }
 
 int
@@ -179,7 +242,9 @@
   if (mode == OPEN_READ)
     return RET_ERROR (EIO);
 
-  if (dev)			/* Patch manager device */
+  if (dev)			/*
+				 * Patch manager device
+				 */
     return pmgr_write (dev - 1, file, buf, count);
 
   c = count;
@@ -194,7 +259,7 @@
 	  int             err;
 
 	  dev = *(unsigned short *) &event[2];
-	  if (dev < 0 || dev >= num_synths)
+	  if (dev < 0 || dev >= max_synthdev)
 	    return RET_ERROR (ENXIO);
 
 	  if (!(synth_open_mask & (1 << dev)))
@@ -207,8 +272,13 @@
 	  return err;
 	}
 
-      if (ev_code == SEQ_EXTENDED || ev_code == SEQ_PRIVATE)
+      if (ev_code >= 128)
 	{
+	  if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED)
+	    {
+	      printk ("Sequencer: Invalid level 2 event %x\n", ev_code);
+	      return RET_ERROR (EINVAL);
+	    }
 
 	  ev_size = 8;
 
@@ -223,7 +293,14 @@
 
 	}
       else
-	ev_size = 4;
+	{
+	  if (seq_mode == SEQ_2)
+	    {
+	      printk ("Sequencer: 4 byte event in level 2 mode\n");
+	      return RET_ERROR (EINVAL);
+	    }
+	  ev_size = 4;
+	}
 
       if (event[0] == SEQ_MIDIPUTC)
 	{
@@ -233,7 +310,7 @@
 	      int             mode;
 	      int             dev = event[2];
 
-	      if (dev >= num_midis)
+	      if (dev >= max_mididev)
 		{
 		  printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev);
 		  return RET_ERROR (ENXIO);
@@ -276,20 +353,28 @@
 seq_queue (unsigned char *note)
 {
 
-  /* Test if there is space in the queue */
+  /*
+   * Test if there is space in the queue
+   */
 
   if (qlen >= SEQ_MAX_QUEUE)
     if (!seq_playing)
-      seq_startplay ();		/* Give chance to drain the queue */
+      seq_startplay ();		/*
+				 * Give chance to drain the queue
+				 */
 
   if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
     {
-      /* Sleep until there is enough space on the queue */
+      /*
+       * Sleep until there is enough space on the queue
+       */
       DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
     }
 
   if (qlen >= SEQ_MAX_QUEUE)
-    return 0;			/* To be sure */
+    return 0;			/*
+				 * To be sure
+				 */
 
   memcpy (&queue[qtail * EV_SZ], note, EV_SZ);
 
@@ -304,7 +389,7 @@
 {
   int             dev = q[2];
 
-  if (dev < 0 || dev >= num_synths)
+  if (dev < 0 || dev >= max_synthdev)
     return RET_ERROR (ENXIO);
 
   if (!(synth_open_mask & (1 << dev)))
@@ -313,7 +398,7 @@
   switch (q[1])
     {
     case SEQ_NOTEOFF:
-      synth_devs[dev]->kill_note (dev, q[3], q[5]);
+      synth_devs[dev]->kill_note (dev, q[3], q[4], q[5]);
       break;
 
     case SEQ_NOTEON:
@@ -340,7 +425,8 @@
       break;
 
     case SEQ_VOLMODE:
-      synth_devs[dev]->volume_method (dev, q[3]);
+      if (synth_devs[dev]->volume_method != NULL)
+	synth_devs[dev]->volume_method (dev, q[3]);
       break;
 
     default:
@@ -350,6 +436,282 @@
   return 0;
 }
 
+static int
+find_voice (int dev, int chn, int note)
+{
+  unsigned short  key;
+  int             i;
+
+  key = (chn << 8) | (note + 1);
+
+  for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++)
+    if (synth_devs[dev]->alloc.map[i] == key)
+      return i;
+
+  return -1;
+}
+
+static int
+alloc_voice (int dev, int chn, int note)
+{
+  unsigned short  key;
+  int             voice;
+
+  key = (chn << 8) | (note + 1);
+
+  voice = synth_devs[dev]->alloc_voice (dev, chn, note,
+					&synth_devs[dev]->alloc);
+  synth_devs[dev]->alloc.map[voice] = key;
+  return voice;
+}
+
+static void
+seq_chn_voice_event (unsigned char *event)
+{
+  unsigned char   dev = event[1];
+  unsigned char   cmd = event[2];
+  unsigned char   chn = event[3];
+  unsigned char   note = event[4];
+  unsigned char   parm = event[5];
+  int             voice = -1;
+
+  if ((int) dev > max_synthdev)
+    return;
+  if (!(synth_open_mask & (1 << dev)))
+    return;
+  if (!synth_devs[dev])
+    return;
+
+  if (seq_mode == SEQ_2)
+    if (synth_devs[dev]->alloc_voice)
+      voice = find_voice (dev, chn, note);
+
+  if (cmd == MIDI_NOTEON && parm == 0)
+    {
+      cmd = MIDI_NOTEOFF;
+      parm = 64;
+    }
+
+  switch (cmd)
+    {
+    case MIDI_NOTEON:
+      if (note > 127)
+	return;
+
+      if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice)
+	{
+	  voice = alloc_voice (dev, chn, note);
+	}
+
+      if (voice == -1)
+	voice = chn;
+
+      if (seq_mode == SEQ_2)
+	{
+	  synth_devs[dev]->set_instr (dev, voice,
+				    synth_devs[dev]->chn_info[chn].pgm_num);
+	}
+
+      synth_devs[dev]->start_note (dev, voice, note, parm);
+      break;
+
+    case MIDI_NOTEOFF:
+      if (voice == -1)
+	voice = chn;
+      synth_devs[dev]->kill_note (dev, voice, note, parm);
+      break;
+
+    case MIDI_KEY_PRESSURE:
+      /* To be implemented */
+      break;
+
+    default:;
+    }
+}
+
+static void
+seq_chn_common_event (unsigned char *event)
+{
+  unsigned char   dev = event[1];
+  unsigned char   cmd = event[2];
+  unsigned char   chn = event[3];
+  unsigned char   p1 = event[4];
+
+  /* unsigned char   p2 = event[5]; */
+  unsigned short  w14 = *(short *) &event[6];
+
+  if ((int) dev > max_synthdev)
+    return;
+  if (!(synth_open_mask & (1 << dev)))
+    return;
+  if (!synth_devs[dev])
+    return;
+
+  switch (cmd)
+    {
+    case MIDI_PGM_CHANGE:
+      if (seq_mode == SEQ_2)
+	{
+	  synth_devs[dev]->chn_info[chn].pgm_num = p1;
+	}
+      else
+	synth_devs[dev]->set_instr (dev, chn, p1);
+      break;
+
+    case MIDI_CTL_CHANGE:
+      if (p1 == CTRL_MAIN_VOLUME)
+	{
+	  w14 = (unsigned short) (((int) w14 * 16383) / 100);
+	  p1 = CTL_MAIN_VOLUME;
+	}
+      if (p1 == CTRL_EXPRESSION)
+	{
+	  w14 *= 128;
+	  p1 = CTL_EXPRESSION;
+	}
+
+      if (seq_mode == SEQ_2)
+	{
+	  if (chn > 15 || p1 > 127)
+	    break;
+
+	  synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0xff;
+
+	  if (dev < num_synths)
+	    {
+	      int             val = w14 & 0xff;
+
+	      if (p1 < 64)	/* Combine MSB and LSB */
+		{
+		  val = ((synth_devs[dev]->
+			  chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7)
+		    | (synth_devs[dev]->
+		       chn_info[chn].controllers[p1 | 32] & 0x7f);
+		  p1 &= ~32;
+		}
+	      else
+		val = synth_devs[dev]->chn_info[chn].controllers[p1];
+
+	      synth_devs[dev]->controller (dev, chn, p1, val);
+	    }
+	  else
+	    synth_devs[dev]->controller (dev, chn, p1, w14);
+	}
+      else
+	synth_devs[dev]->controller (dev, chn, p1, w14);
+      break;
+
+    case MIDI_PITCH_BEND:
+      synth_devs[dev]->bender (dev, chn, w14);
+      break;
+
+    default:;
+    }
+}
+
+static int
+seq_timing_event (unsigned char *event)
+{
+  unsigned char   cmd = event[1];
+  unsigned int    parm = *(int *) &event[4];
+
+  if (seq_mode == SEQ_2)
+    {
+      int             ret;
+
+      if ((ret = tmr->event (tmr_no, event)) == TIMER_ARMED)
+	{
+	  if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+	    {
+	      unsigned long   flags;
+
+	      DISABLE_INTR (flags);
+	      if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+		{
+		  WAKE_UP (seq_sleeper, seq_sleep_flag);
+		}
+	      RESTORE_INTR (flags);
+	    }
+	}
+      return ret;
+    }
+
+  switch (cmd)
+    {
+    case TMR_WAIT_REL:
+      parm += prev_event_time;
+
+      /*
+ * NOTE!  No break here. Execution of TMR_WAIT_REL continues in the
+ * next case (TMR_WAIT_ABS)
+ */
+
+    case TMR_WAIT_ABS:
+      if (parm > 0)
+	{
+	  long            time;
+
+	  seq_playing = 1;
+	  time = parm;
+	  prev_event_time = time;
+
+	  request_sound_timer (time);
+
+	  if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+	    {
+	      unsigned long   flags;
+
+	      DISABLE_INTR (flags);
+	      if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+		{
+		  WAKE_UP (seq_sleeper, seq_sleep_flag);
+		}
+	      RESTORE_INTR (flags);
+	    }
+
+	  return TIMER_ARMED;
+	}
+      break;
+
+    case TMR_START:
+      seq_time = GET_TIME ();
+      prev_input_time = 0;
+      prev_event_time = 0;
+      break;
+
+    case TMR_STOP:
+      break;
+
+    case TMR_CONTINUE:
+      break;
+
+    case TMR_TEMPO:
+      break;
+
+    case TMR_ECHO:
+      if (seq_mode == SEQ_2)
+	seq_copy_to_input (event, 8);
+      else
+	{
+	  parm = (parm << 8 | SEQ_ECHO);
+	  seq_copy_to_input ((unsigned char *) &parm, 4);
+	}
+      break;
+
+    default:;
+    }
+
+  return TIMER_NOT_ARMED;
+}
+
+static void
+seq_local_event (unsigned char *event)
+{
+  /* unsigned char   cmd = event[1]; */
+
+  printk ("seq_local_event() called. WHY????????\n");
+}
+
 static void
 seq_startplay (void)
 {
@@ -359,6 +721,9 @@
 
   while (qlen > 0)
     {
+
+      seq_playing = 1;
+
       qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
       qlen--;
 
@@ -369,7 +734,7 @@
 	case SEQ_NOTEOFF:
 	  if (synth_open_mask & (1 << 0))
 	    if (synth_devs[0])
-	      synth_devs[0]->kill_note (0, q[1], q[3]);
+	      synth_devs[0]->kill_note (0, q[1], 255, q[3]);
 	  break;
 
 	case SEQ_NOTEON:
@@ -380,8 +745,10 @@
 	  break;
 
 	case SEQ_WAIT:
-	  delay = (unsigned long *) q;	/* Bytes 1 to 3 are containing the
-					 * delay in GET_TIME() */
+	  delay = (unsigned long *) q;	/*
+					 * Bytes 1 to 3 are containing the *
+					 * delay in GET_TIME()
+					 */
 	  *delay = (*delay >> 8) & 0xffffff;
 
 	  if (*delay > 0)
@@ -390,6 +757,7 @@
 
 	      seq_playing = 1;
 	      time = *delay;
+	      prev_event_time = time;
 
 	      request_sound_timer (time);
 
@@ -404,8 +772,11 @@
 		    }
 		  RESTORE_INTR (flags);
 		}
-	      return;		/* Stop here. Timer routine will continue
-				 * playing after the delay */
+	      /*
+ * The timer is now active and will reinvoke this function
+ * after the timer expires. Return to the caller now.
+ */
+	      return;
 	    }
 	  break;
 
@@ -415,11 +786,17 @@
 	      synth_devs[0]->set_instr (0, q[1], q[2]);
 	  break;
 
-	case SEQ_SYNCTIMER:	/* Reset timer */
+	case SEQ_SYNCTIMER:	/*
+				 * Reset timer
+				 */
 	  seq_time = GET_TIME ();
+	  prev_input_time = 0;
+	  prev_event_time = 0;
 	  break;
 
-	case SEQ_MIDIPUTC:	/* Put a midi character */
+	case SEQ_MIDIPUTC:	/*
+				 * Put a midi character
+				 */
 	  if (midi_opened[q[2]])
 	    {
 	      int             dev;
@@ -433,7 +810,9 @@
 		   */
 
 		  qlen++;
-		  qhead = this_one;	/* Restore queue */
+		  qhead = this_one;	/*
+					 * Restore queue
+					 */
 		  seq_playing = 1;
 		  request_sound_timer (-1);
 		  return;
@@ -444,11 +823,13 @@
 	  break;
 
 	case SEQ_ECHO:
-	  copy_to_input (q);	/* Echo back to the process */
+	  seq_copy_to_input (q, 4);	/*
+					   * Echo back to the process
+					 */
 	  break;
 
 	case SEQ_PRIVATE:
-	  if (q[1] < num_synths)
+	  if ((int) q[1] < max_synthdev)
 	    synth_devs[q[1]]->hw_control (q[1], q);
 	  break;
 
@@ -456,6 +837,25 @@
 	  extended_event (q);
 	  break;
 
+	case EV_CHN_VOICE:
+	  seq_chn_voice_event (q);
+	  break;
+
+	case EV_CHN_COMMON:
+	  seq_chn_common_event (q);
+	  break;
+
+	case EV_TIMING:
+	  if (seq_timing_event (q) == TIMER_ARMED)
+	    {
+	      return;
+	    }
+	  break;
+
+	case EV_SEQ_LOCAL:
+	  seq_local_event (q);
+	  break;
+
 	default:;
 	}
 
@@ -477,10 +877,55 @@
 
 }
 
+static void
+reset_controllers (int dev, unsigned char *controller, int update_dev)
+{
+#include "midi_ctrl.h"
+
+  int             i;
+
+  for (i = 0; i < 128; i++)
+    controller[i] = ctrl_def_values[i];
+}
+
+static void
+setup_mode2 (void)
+{
+  int             dev;
+
+  max_synthdev = num_synths;
+
+  for (dev = 0; dev < num_midis; dev++)
+    if (midi_devs[dev]->converter != NULL)
+      {
+	synth_devs[max_synthdev++] =
+	  midi_devs[dev]->converter;
+      }
+
+  for (dev = 0; dev < max_synthdev; dev++)
+    {
+      int             chn;
+
+      for (chn = 0; chn < 16; chn++)
+	{
+	  synth_devs[dev]->chn_info[chn].pgm_num = 0;
+	  reset_controllers (dev,
+			     synth_devs[dev]->chn_info[chn].controllers,
+			     0);
+	}
+    }
+
+  max_mididev = 0;
+  seq_mode = SEQ_2;
+}
+
 int
 sequencer_open (int dev, struct fileinfo *file)
 {
   int             retval, mode, i;
+  int             level, tmp;
+
+  level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1;
 
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
@@ -493,15 +938,22 @@
       return RET_ERROR (ENXIO);
     }
 
-  if (dev)			/* Patch manager device */
+  if (dev)			/*
+				 * Patch manager device
+				 */
     {
       int             err;
 
       dev--;
+
+      if (dev >= MAX_SYNTH_DEV)
+	return RET_ERROR (ENXIO);
       if (pmgr_present[dev])
 	return RET_ERROR (EBUSY);
       if ((err = pmgr_open (dev)) < 0)
-	return err;		/* Failed */
+	return err;		/*
+				 * Failed
+				 */
 
       pmgr_present[dev] = 1;
       return err;
@@ -513,40 +965,105 @@
       return RET_ERROR (EBUSY);
     }
 
-  if (!(num_synths + num_midis))
-    return RET_ERROR (ENXIO);
+  max_mididev = num_midis;
+  max_synthdev = num_synths;
+  pre_event_timeout = 0;
+  seq_mode = SEQ_1;
 
-  synth_open_mask = 0;
+  if (pending_timer != -1)
+    {
+      tmr_no = pending_timer;
+      pending_timer = -1;
+    }
 
-  if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
-    for (i = 0; i < num_synths; i++)	/* Open synth devices */
-      if (synth_devs[i]->open (i, mode) < 0)
-	printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
-      else
-	synth_open_mask |= (1 << i);
+  if (tmr_no == -1)		/* Not selected yet */
+    {
+      int             i, best;
 
-  seq_time = GET_TIME ();
+      best = -1;
+      for (i = 0; i < num_sound_timers; i++)
+	if (sound_timer_devs[i]->priority > best)
+	  {
+	    tmr_no = i;
+	    best = sound_timer_devs[i]->priority;
+	  }
 
-  for (i = 0; i < num_midis; i++)
-    {
-      midi_opened[i] = 0;
-      midi_written[i] = 0;
+      if (tmr_no == -1)		/* Should not be */
+	tmr_no = 0;
     }
 
-  if (mode == OPEN_READ || mode == OPEN_READWRITE)
-    {				/* Initialize midi input devices */
-      if (!num_midis)
+  tmr = sound_timer_devs[tmr_no];
+
+  if (level == 2)
+    {
+      printk ("Using timer #%d\n", tmr_no);
+      if (tmr == NULL)
 	{
-	  printk ("Sequencer: No Midi devices. Input not possible\n");
+	  printk ("sequencer: No timer for level 2\n");
 	  return RET_ERROR (ENXIO);
 	}
+      setup_mode2 ();
+    }
 
-      for (i = 0; i < num_midis; i++)
-	{
-	  if ((retval = midi_devs[i]->open (i, mode,
+  if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE))
+    if (!max_mididev)
+      {
+	printk ("Sequencer: No Midi devices. Input not possible\n");
+	return RET_ERROR (ENXIO);
+      }
+
+  if (!max_synthdev && !max_mididev)
+    return RET_ERROR (ENXIO);
+
+  synth_open_mask = 0;
+
+  for (i = 0; i < max_mididev; i++)
+    {
+      midi_opened[i] = 0;
+      midi_written[i] = 0;
+    }
+
+  /*
+   * if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+   */
+  for (i = 0; i < max_synthdev; i++)	/*
+					 * Open synth devices
+					 */
+    if ((tmp = synth_devs[i]->open (i, mode)) < 0)
+      {
+	printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp);
+	if (synth_devs[i]->midi_dev)
+	  printk ("(Maps to midi dev #%d\n", synth_devs[i]->midi_dev);
+      }
+    else
+      {
+	synth_open_mask |= (1 << i);
+	if (synth_devs[i]->midi_dev)	/*
+					 * Is a midi interface
+					 */
+	  midi_opened[synth_devs[i]->midi_dev] = 1;
+      }
+
+  seq_time = GET_TIME ();
+  prev_input_time = 0;
+  prev_event_time = 0;
+
+  if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE))
+    {				/*
+				 * Initialize midi input devices
+				 */
+      for (i = 0; i < max_mididev; i++)
+	if (!midi_opened[i])
+	  {
+	    if ((retval = midi_devs[i]->open (i, mode,
 			 sequencer_midi_input, sequencer_midi_output)) >= 0)
-	    midi_opened[i] = 1;
-	}
+	      midi_opened[i] = 1;
+	  }
+    }
+
+  if (seq_mode == SEQ_2)
+    {
+      tmr->open (tmr_no, seq_mode);
     }
 
   sequencer_busy = 1;
@@ -576,7 +1093,7 @@
     {
       n = 0;
 
-      for (i = 0; i < num_midis; i++)
+      for (i = 0; i < max_mididev; i++)
 	if (midi_opened[i] && midi_written[i])
 	  if (midi_devs[i]->buffer_status != NULL)
 	    if (midi_devs[i]->buffer_status (i))
@@ -602,7 +1119,9 @@
 
   DEB (printk ("sequencer_release(dev=%d)\n", dev));
 
-  if (dev)			/* Patch manager device */
+  if (dev)			/*
+				 * Patch manager device
+				 */
     {
       dev--;
       pmgr_release (dev);
@@ -611,34 +1130,48 @@
     }
 
   /*
-     * Wait until the queue is empty
+   * * Wait until the queue is empty
    */
 
-  while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
-    {
-      seq_sync ();
-    }
+  if (mode != OPEN_READ)
+    while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
+      {
+	seq_sync ();
+      }
 
   if (mode != OPEN_READ)
-    seq_drain_midi_queues ();	/* Ensure the output queues are empty */
+    seq_drain_midi_queues ();	/*
+				 * Ensure the output queues are empty
+				 */
   seq_reset ();
   if (mode != OPEN_READ)
-    seq_drain_midi_queues ();	/* Flush the all notes off messages */
-
-  for (i = 0; i < num_midis; i++)
-    if (midi_opened[i])
-      midi_devs[i]->close (i);
-
-  if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
-    for (i = 0; i < num_synths; i++)
-      if (synth_open_mask & (1 << i))	/* Actually opened */
-	if (synth_devs[i])
+    seq_drain_midi_queues ();	/*
+				 * Flush the all notes off messages
+				 */
+
+  for (i = 0; i < max_synthdev; i++)
+    if (synth_open_mask & (1 << i))	/*
+					 * Actually opened
+					 */
+      if (synth_devs[i])
+	{
 	  synth_devs[i]->close (i);
 
+	  if (synth_devs[i]->midi_dev)
+	    midi_opened[synth_devs[i]->midi_dev] = 0;
+	}
+
   for (i = 0; i < num_synths; i++)
     if (pmgr_present[i])
       pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
 
+  for (i = 0; i < max_mididev; i++)
+    if (midi_opened[i])
+      midi_devs[i]->close (i);
+
+  if (seq_mode == SEQ_2)
+    tmr->close (tmr_no);
+
   sequencer_busy = 0;
 }
 
@@ -648,7 +1181,10 @@
   if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
     seq_startplay ();
 
-  if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))	/* Queue not empty */
+  if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))	/*
+								 * Queue not
+								 * empty
+								 */
     {
       DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
     }
@@ -665,11 +1201,19 @@
 
   int             n;
 
-  /* This routine sends one byte to the Midi channel. */
-  /* If the output Fifo is full, it waits until there */
-  /* is space in the queue */
+  /*
+   * This routine sends one byte to the Midi channel.
+   */
+  /*
+   * If the output Fifo is full, it waits until there
+   */
+  /*
+   * is space in the queue
+   */
 
-  n = 300;			/* Timeout in jiffies */
+  n = 300;			/*
+				 * Timeout in jiffies
+				 */
 
   while (n && !midi_devs[dev]->putc (dev, data))
     {
@@ -685,34 +1229,66 @@
    * NOTE! Calls sleep(). Don't call this from interrupt.
    */
 
-  int             i, chn;
+  int             i;
+
+  int             chn;
 
   sound_stop_timer ();
+  seq_time = GET_TIME ();
+  prev_input_time = 0;
+  prev_event_time = 0;
 
   qlen = qhead = qtail = 0;
   iqlen = iqhead = iqtail = 0;
 
-  for (i = 0; i < num_synths; i++)
+  for (i = 0; i < max_synthdev; i++)
     if (synth_open_mask & (1 << i))
       if (synth_devs[i])
 	synth_devs[i]->reset (i);
 
-  for (i = 0; i < num_midis; i++)
-    if (midi_written[i])	/* Midi used. Some notes may still be playing */
-      {
-	for (chn = 0; chn < 16; chn++)
+  if (seq_mode == SEQ_2)
+    {
+      for (i = 0; i < max_synthdev; i++)
+	if (synth_open_mask & (1 << i))
+	  if (synth_devs[i])
+	    for (chn = 0; chn < 16; chn++)
+	      synth_devs[i]->controller (i, chn, 0xfe, 0);	/* All notes off */
+    }
+  else
+    {
+      for (i = 0; i < max_mididev; i++)
+	if (midi_written[i])	/*
+				 * Midi used. Some notes may still be playing
+				 */
 	  {
-	    midi_outc (i,
-		       (unsigned char) (0xb0 + (chn & 0xff)));	/* Channel msg */
-	    midi_outc (i, 0x7b);/* All notes off */
-	    midi_outc (i, 0);	/* Dummy parameter */
-	  }
+	    /*
+ *    Sending just a ACTIVE SENSING message should be enough to stop all
+ *      playing notes. Since there are devices not recognizing the
+ *      active sensing, we have to send some all notes off messages also.
+ */
+	    midi_outc (i, 0xfe);
+
+	    for (chn = 0; chn < 16; chn++)
+	      {
+		midi_outc (i,
+			   (unsigned char) (0xb0 + (chn & 0xff)));	/*
+								 * Channel
+								 * msg
+								 */
+		midi_outc (i, 0x7b);	/*
+					 * All notes off
+					 */
+		midi_outc (i, 0);	/*
+				 * Dummy parameter
+				 */
+	      }
 
-	midi_devs[i]->close (i);
+	    midi_devs[i]->close (i);
 
-	midi_written[i] = 0;
-	midi_opened[i] = 0;
-      }
+	    midi_written[i] = 0;
+	    midi_opened[i] = 0;
+	  }
+    }
 
   seq_playing = 0;
 
@@ -721,6 +1297,28 @@
 
 }
 
+static void
+seq_panic (void)
+{
+  /*
+ * This routine is called by the application in case the user
+ * wants to reset the system to the default state.
+ */
+
+  seq_reset ();
+
+  /*
+ * Since some of the devices don't recognize the active sensing and
+ * all notes off messages, we have to shut all notes manually.
+ *
+ *      TO BE IMPLEMENTED LATER
+ */
+
+  /*
+ * Also return the controllers to their default states
+ */
+}
+
 int
 sequencer_ioctl (int dev, struct fileinfo *file,
 		 unsigned int cmd, unsigned int arg)
@@ -732,20 +1330,62 @@
 
   switch (cmd)
     {
+    case SNDCTL_TMR_TIMEBASE:
+    case SNDCTL_TMR_TEMPO:
+    case SNDCTL_TMR_START:
+    case SNDCTL_TMR_STOP:
+    case SNDCTL_TMR_CONTINUE:
+    case SNDCTL_TMR_METRONOME:
+    case SNDCTL_TMR_SOURCE:
+      if (dev)			/* Patch manager */
+	return RET_ERROR (EIO);
 
-    case SNDCTL_SEQ_SYNC:
+      if (seq_mode != SEQ_2)
+	return RET_ERROR (EINVAL);
+      return tmr->ioctl (tmr_no, cmd, arg);
+      break;
+
+    case SNDCTL_TMR_SELECT:
       if (dev)			/* Patch manager */
 	return RET_ERROR (EIO);
 
+      if (seq_mode != SEQ_2)
+	return RET_ERROR (EINVAL);
+      pending_timer = IOCTL_IN (arg);
+
+      if (pending_timer < 0 || pending_timer >= num_sound_timers)
+	{
+	  pending_timer = -1;
+	  return RET_ERROR (EINVAL);
+	}
+
+      return IOCTL_OUT (arg, pending_timer);
+      break;
+
+    case SNDCTL_SEQ_PANIC:
+      seq_panic ();
+      break;
+
+    case SNDCTL_SEQ_SYNC:
+      if (dev)			/*
+				 * Patch manager
+				 */
+	return RET_ERROR (EIO);
+
       if (mode == OPEN_READ)
 	return 0;
       while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
 	seq_sync ();
-      return 0;
+      if (qlen)
+	return RET_ERROR (EINTR);
+      else
+	return 0;
       break;
 
     case SNDCTL_SEQ_RESET:
-      if (dev)			/* Patch manager */
+      if (dev)			/*
+				 * Patch manager
+				 */
 	return RET_ERROR (EIO);
 
       seq_reset ();
@@ -753,11 +1393,13 @@
       break;
 
     case SNDCTL_SEQ_TESTMIDI:
-      if (dev)			/* Patch manager */
+      if (dev)			/*
+				 * Patch manager
+				 */
 	return RET_ERROR (EIO);
 
       midi_dev = IOCTL_IN (arg);
-      if (midi_dev >= num_midis)
+      if (midi_dev >= max_mididev)
 	return RET_ERROR (ENXIO);
 
       if (!midi_opened[midi_dev])
@@ -777,7 +1419,9 @@
       break;
 
     case SNDCTL_SEQ_GETINCOUNT:
-      if (dev)			/* Patch manager */
+      if (dev)			/*
+				 * Patch manager
+				 */
 	return RET_ERROR (EIO);
 
       if (mode == OPEN_WRITE)
@@ -796,7 +1440,15 @@
       if (dev)			/* Patch manager */
 	return RET_ERROR (EIO);
 
-      /* If *arg == 0, just return the current rate */
+      /*
+       * If *arg == 0, just return the current rate
+       */
+      if (seq_mode == SEQ_2)
+	return tmr->ioctl (tmr_no, cmd, arg);
+
+      if (IOCTL_IN (arg) != 0)
+	return RET_ERROR (EINVAL);
+
       return IOCTL_OUT (arg, HZ);
       break;
 
@@ -815,11 +1467,11 @@
       break;
 
     case SNDCTL_SEQ_NRSYNTHS:
-      return IOCTL_OUT (arg, num_synths);
+      return IOCTL_OUT (arg, max_synthdev);
       break;
 
     case SNDCTL_SEQ_NRMIDIS:
-      return IOCTL_OUT (arg, num_midis);
+      return IOCTL_OUT (arg, max_mididev);
       break;
 
     case SNDCTL_SYNTH_MEMAVL:
@@ -859,7 +1511,7 @@
 	IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf));
 	dev = inf.device;
 
-	if (dev < 0 || dev >= num_synths)
+	if (dev < 0 || dev >= max_synthdev)
 	  return RET_ERROR (ENXIO);
 
 	if (!(synth_open_mask & (1 << dev)) && !orig_dev)
@@ -877,7 +1529,7 @@
 	IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf));
 	dev = inf.device;
 
-	if (dev < 0 || dev >= num_midis)
+	if (dev < 0 || dev >= max_mididev)
 	  return RET_ERROR (ENXIO);
 
 	IOCTL_TO_USER ((char *) arg, 0, (char *) &(midi_devs[dev]->info), sizeof (inf));
@@ -957,7 +1609,9 @@
       {
 	int             tmp = IOCTL_IN (arg);
 
-	if (dev)		/* Patch manager */
+	if (dev)		/*
+				 * Patch manager
+				 */
 	  return RET_ERROR (EIO);
 
 	if (tmp < 1)
@@ -969,8 +1623,23 @@
       }
       break;
 
+    case SNDCTL_MIDI_PRETIME:
+      {
+	int             val = IOCTL_IN (arg);
+
+	if (val < 0)
+	  val = 0;
+
+	val = (HZ * val) / 10;
+	pre_event_timeout = val;
+	return IOCTL_OUT (arg, val);
+      }
+      break;
+
     default:
-      if (dev)			/* Patch manager */
+      if (dev)			/*
+				 * Patch manager
+				 */
 	return RET_ERROR (EIO);
 
       if (mode == OPEN_READ)
@@ -991,6 +1660,8 @@
 int
 sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
 {
+  unsigned long   flags;
+
   dev = dev >> 4;
 
   switch (sel_type)
@@ -998,17 +1669,22 @@
     case SEL_IN:
       if (!iqlen)
 	{
+	  DISABLE_INTR (flags);
+	  midi_sleep_flag.mode = WK_SLEEP;
 	  select_wait (&midi_sleeper, wait);
+	  RESTORE_INTR (flags);
 	  return 0;
 	}
       return 1;
-
       break;
 
     case SEL_OUT:
       if (qlen >= SEQ_MAX_QUEUE)
 	{
+	  DISABLE_INTR (flags);
+	  seq_sleep_flag.mode = WK_SLEEP;
 	  select_wait (&seq_sleeper, wait);
+	  RESTORE_INTR (flags);
 	  return 0;
 	}
       return 1;
@@ -1042,7 +1718,7 @@
   {
     261632, 277189, 293671, 311132, 329632, 349232,
     369998, 391998, 415306, 440000, 466162, 493880
-  };				/* Note freq*1000 for octave 5 */
+  };
 
 #define BASE_OCTAVE	5
 
@@ -1056,7 +1732,9 @@
   else if (octave > BASE_OCTAVE)
     note_freq <<= (octave - BASE_OCTAVE);
 
-  /* note_freq >>= 1;    */
+  /*
+   * note_freq >>= 1;
+   */
 
   return note_freq;
 }
@@ -1102,12 +1780,17 @@
   semitones = bend / 100;
   cents = bend % 100;
 
-  amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents] / 10000;
+  amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents])
+    / 10000;
 
   if (negative)
-    return (base_freq * 10000) / amount;	/* Bend down */
+    return (base_freq * 10000) / amount;	/*
+						 * Bend down
+						 */
   else
-    return (base_freq * amount) / 10000;	/* Bend up */
+    return (base_freq * amount) / 10000;	/*
+						 * Bend up
+						 */
 }
 
 
@@ -1123,7 +1806,9 @@
 }
 
 #else
-/* Stub version */
+/*
+ * Stub version
+ */
 int
 sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v1.1.30/linux/drivers/sound/sound_calls.h	Sun May  1 12:12:43 1994
+++ linux/drivers/sound/sound_calls.h	Mon Jul 18 09:50:55 1994
@@ -4,7 +4,6 @@
 
 int DMAbuf_open(int dev, int mode);
 int DMAbuf_release(int dev, int mode);
-int DMAbuf_read (int dev, snd_rw_buf *user_buf, int count);
 int DMAbuf_getwrbuffer(int dev, char **buf, int *size);
 int DMAbuf_getrdbuffer(int dev, char **buf, int *len);
 int DMAbuf_rmchars(int dev, int buff_no, int c);
@@ -46,6 +45,8 @@
 void sequencer_timer(void);
 int note_to_freq(int note_num);
 unsigned long compute_finetune(unsigned long base_freq, int bend, int range);
+void seq_input_event(unsigned char *event, int len);
+void seq_copy_to_input (unsigned char *event, int len);
 
 #ifdef ALLOW_SELECT
 int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
@@ -65,6 +66,10 @@
 void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
 long MIDIbuf_init(long mem_start);
 
+#ifdef ALLOW_SELECT
+int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+#endif
+
 /*
  *	System calls for the generic midi interface.
  *
@@ -126,16 +131,16 @@
 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);
 
 /*	From sb_midi.c	*/
 void sb_midi_init(int model);
-void sb_midi_interrupt(int dummy);
 
 /*	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);
+void sb_mixer_init(int major_model);
 
 /*	From opl3.c	*/
 int opl3_detect (int ioaddr);
@@ -173,6 +178,8 @@
 int probe_gus(struct address_info *hw_config);
 int gus_set_midi_irq(int num);
 void gusintr(int);
+long attach_gus_db16(long mem_start, struct address_info * hw_config);
+int probe_gus_db16(struct address_info *hw_config);
 
 /*	From gus_wave.c */
 int gus_wave_detect(int baseaddr);
@@ -192,6 +199,10 @@
 long attach_mpu401(long mem_start, struct address_info * hw_config);
 int probe_mpu401(struct address_info *hw_config);
 
+/*	From uart6850.c */
+long attach_uart6850(long mem_start, struct address_info * hw_config);
+int probe_uart6850(struct address_info *hw_config);
+
 /*	From opl3.c */
 void enable_opl3_mode(int left, int right, int both);
 
@@ -206,3 +217,27 @@
 
 /* 	From ics2101.c */
 long ics2101_mixer_init(long mem_start);
+
+/*	From sound_timer.c */
+void sound_timer_init(int io_base);
+void sound_timer_interrupt(void);
+
+/*	From ad1848.c */
+void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture);
+int ad1848_detect (int io_base);
+void     ad1848_interrupt (int dev);
+long attach_ms_sound(long mem_start, struct address_info * hw_config);
+int probe_ms_sound(struct address_info *hw_config);
+
+/* 	From pss.c */
+int probe_pss (struct address_info *hw_config);
+long attach_pss (long mem_start, struct address_info *hw_config);
+
+int pss_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int pss_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int pss_open (int dev, struct fileinfo *file);
+void pss_release (int dev, struct fileinfo *file);
+int pss_ioctl (int dev, struct fileinfo *file,
+	   unsigned int cmd, unsigned int arg);
+int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
+long pss_init(long mem_start);
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h
--- v1.1.30/linux/drivers/sound/sound_config.h	Fri Jan 21 15:59:51 1994
+++ linux/drivers/sound/sound_config.h	Mon Jul 18 09:50:55 1994
@@ -30,7 +30,18 @@
 
 #include "local.h"
 
+#if defined(ISC) || defined(SCO) || defined(SVR42)
+#define GENERIC_SYSV
+#endif
+
+/*
+ * Disable the AD1848 driver if there are no other drivers requiring it.
+ */
 
+#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX)
+#define EXCLUDE_AD1848
+#endif
+
 #undef CONFIGURE_SOUNDCARD
 #undef DYNAMIC_BUFFER
 
@@ -50,18 +61,6 @@
 #define SND_DEFAULT_ENABLE	1
 #endif
 
-/** UWM - new MIDI stuff **/
-
-#ifdef EXCLUDE_CHIP_MIDI
-#define EXCLUDE_PRO_MIDI
-#endif
-
-/** UWM - stuff **/
- 
-#if defined(EXCLUDE_SEQUENCER) && defined(EXCLUDE_AUDIO)
-#undef CONFIGURE_SOUNDCARD
-#endif
-
 #ifdef CONFIGURE_SOUNDCARD
 
 /* ****** IO-address, DMA and IRQ settings ****
@@ -125,6 +124,19 @@
 #define MPU_IRQ		6
 #endif
 
+/* Echo Personal Sound System */
+#ifndef PSS_BASE
+#define PSS_BASE        0x220   /* 0x240 or */
+#endif
+
+#ifndef PSS_IRQ
+#define PSS_IRQ         7
+#endif
+
+#ifndef PSS_DMA
+#define PSS_DMA         1
+#endif
+
 #ifndef MAX_REALTIME_FACTOR
 #define MAX_REALTIME_FACTOR	4
 #endif
@@ -156,48 +168,42 @@
    driver. (There is no need to alter this) */
 #define SEQ_MAX_QUEUE	1024
 
-#define SBFM_MAXINSTR		(256)	/* Size of the FM Instrument
-						   bank				 */
+#define SBFM_MAXINSTR		(256)	/* Size of the FM Instrument bank */
 /* 128 instruments for general MIDI setup and 16 unassigned	 */
 
-#define SND_NDEVS	50	/* Number of supported devices */
+/*
+ * Minor numbers for the sound driver.
+ *
+ * Unfortunately Creative called the codec chip of SB as a DSP. For this
+ * reason the /dev/dsp is reserved for digitized audio use. There is a
+ * device for true DSP processors but it will be called something else.
+ * In v3.0 it's /dev/sndproc but this could be a temporary solution.
+ */
+
+#define SND_NDEVS	64	/* Number of supported devices */
 #define SND_DEV_CTL	0	/* Control port /dev/mixer */
 #define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
 				   synthesizer and MIDI output) */
-#define SND_DEV_MIDIN	2	/* MIDI input /dev/midin (not implemented
-				   yet) */
+#define SND_DEV_MIDIN	2	/* Raw midi access */
 #define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
 #define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
 #define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS	6	/* /dev/sndstatus */
-
-/* UWM ... note add new MIDI devices here..  
- *  Also do not forget to add table midi_supported[]
- *  Minor numbers for on-chip midi devices start from 15.. and 
- *  should be contiguous.. viz. 15,16,17....
- * ERROR!!!!!!!!! NO NO. Minor numbers above 15 are reserved!!!!!! Hannu
- *  Also note the max # of midi devices as MAX_MIDI_DEV
- */ 
-
-#define CMIDI_DEV_PRO  15  	/* Chip midi device == /dev/pro_midi */
+#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/sequecer, level 2 interface */
+#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
+#define SND_DEV_PSS	SND_DEV_SNDPROC
 
-/*
- *  Add other midis here...
-		.
-		.
-		.
-		.
- */
-
 #define DSP_DEFAULT_SPEED	8000
 
 #define ON		1
 #define OFF		0
 
-#define MAX_DSP_DEV	4
+#define MAX_AUDIO_DEV	4
 #define MAX_MIXER_DEV	2
 #define MAX_SYNTH_DEV	3
-#define MAX_MIDI_DEV	4
+#define MAX_MIDI_DEV	6
+#define MAX_TIMER_DEV	3
 
 struct fileinfo {
        	  int mode;	/* Open mode */
@@ -209,6 +215,20 @@
 	int dma;
 };
 
+#define SYNTH_MAX_VOICES	32
+
+struct voice_alloc_info {
+		int max_voice;
+		int used_voices;
+		int ptr;		/* For device specific use */
+		unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */
+	};
+
+struct channel_info {
+		int pgm_num;
+		unsigned char controllers[128];
+	};
+
 /*
  * Process wakeup reasons
  */
@@ -228,6 +248,11 @@
 
 #ifndef DEB
 #define DEB(x)
+
+#define TIMER_ARMED	121234
+#define TIMER_NOT_ARMED	1
+
+#define FUTURE_VERSION
 #endif
 
 #endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c
--- v1.1.30/linux/drivers/sound/sound_switch.c	Sun May  1 12:12:44 1994
+++ linux/drivers/sound/sound_switch.c	Mon Jul 18 09:50:55 1994
@@ -40,10 +40,12 @@
 {
   {0}};
 
-static int      in_use = 0;	/* Total # of open device files (excluding
+static int      in_use = 0;	/*
 
-				 * minor 0) */
 
+				 * *  * * Total # of open device files
+				 * (excluding * * * minor 0)   */
+
 /*
  * /dev/sndstatus -device
  */
@@ -56,7 +58,9 @@
 {
   int             l;
 
-  for (l = 0; l < 256, s[l]; l++);	/* l=strlen(s); */
+  for (l = 0; l < 256, s[l]; l++);	/*
+					 * l=strlen(s);
+					 */
 
   if (status_len + l >= 4000)
     return 0;
@@ -121,37 +125,58 @@
   if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
     return;
 
-  if (!put_status ("\n\nHW config: \n"))
+  if (!put_status ("\n\nInstalled drivers: \n"))
     return;
 
   for (i = 0; i < (num_sound_drivers - 1); i++)
     {
-      if (!supported_drivers[i].enabled)
-	if (!put_status ("("))
-	  return;
-
       if (!put_status ("Type "))
 	return;
-      if (!put_status_int (supported_drivers[i].card_type, 10))
+      if (!put_status_int (sound_drivers[i].card_type, 10))
 	return;
       if (!put_status (": "))
 	return;
-      if (!put_status (supported_drivers[i].name))
+      if (!put_status (sound_drivers[i].name))
+	return;
+
+      if (!put_status ("\n"))
 	return;
+    }
+
+  if (!put_status ("\n\nCard config: \n"))
+    return;
+
+  for (i = 0; i < (num_sound_cards - 1); i++)
+    {
+      int             drv;
+
+      if (!snd_installed_cards[i].enabled)
+	if (!put_status ("("))
+	  return;
+
+      /*
+       * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return;
+       * if (!put_status (": ")) return;
+       */
+
+      if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1)
+	if (!put_status (sound_drivers[drv].name))
+	  return;
+
       if (!put_status (" at 0x"))
 	return;
-      if (!put_status_int (supported_drivers[i].config.io_base, 16))
+      if (!put_status_int (snd_installed_cards[i].config.io_base, 16))
 	return;
       if (!put_status (" irq "))
 	return;
-      if (!put_status_int (supported_drivers[i].config.irq, 10))
+      if (!put_status_int (snd_installed_cards[i].config.irq, 10))
 	return;
       if (!put_status (" drq "))
 	return;
-      if (!put_status_int (supported_drivers[i].config.dma, 10))
+      if (!put_status_int (snd_installed_cards[i].config.dma, 10))
 	return;
 
-      if (!supported_drivers[i].enabled)
+      if (!snd_installed_cards[i].enabled)
 	if (!put_status (")"))
 	  return;
 
@@ -162,13 +187,13 @@
   if (!put_status ("\nPCM devices:\n"))
     return;
 
-  for (i = 0; i < num_dspdevs; i++)
+  for (i = 0; i < num_audiodevs; i++)
     {
       if (!put_status_int (i, 10))
 	return;
       if (!put_status (": "))
 	return;
-      if (!put_status (dsp_devs[i]->name))
+      if (!put_status (audio_devs[i]->name))
 	return;
       if (!put_status ("\n"))
 	return;
@@ -204,16 +229,27 @@
 	return;
     }
 
-  if (num_mixers)
+  if (!put_status ("\nMIDI Timers:\n"))
+    return;
+
+  for (i = 0; i < num_sound_timers; i++)
     {
-      if (!put_status ("\nMixer(s) installed\n"))
+      if (!put_status_int (i, 10))
 	return;
-    }
-  else
-    {
-      if (!put_status ("\nNo mixers installed\n"))
+      if (!put_status (": "))
+	return;
+      if (!put_status (sound_timer_devs[i]->info.name))
 	return;
+      if (!put_status ("\n"))
+	return;
     }
+
+  if (!put_status ("\n"))
+    return;
+  if (!put_status_int (num_mixers, 10))
+    return;
+  if (!put_status (" mixer(s) installed\n"))
+    return;
 }
 
 static int
@@ -256,14 +292,20 @@
       break;
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       return sequencer_read (dev, file, buf, count);
       break;
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_read (dev, file, buf, count);
 #endif
 
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      return pss_read (dev, file, buf, count);
+#endif
+
     default:
       printk ("Sound: Undefined minor device %d\n", dev);
     }
@@ -281,6 +323,7 @@
     {
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       return sequencer_write (dev, file, buf, count);
       break;
 
@@ -290,6 +333,16 @@
       return audio_write (dev, file, buf, count);
       break;
 
+#ifndef EXCLUDE_MIDI
+    case SND_DEV_MIDIN:
+      return MIDIbuf_write (dev, file, buf, count);
+#endif
+
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      return pss_write (dev, file, buf, count);
+#endif
+
     default:
       return RET_ERROR (EPERM);
     }
@@ -327,17 +380,25 @@
       break;
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       if ((retval = sequencer_open (dev, file)) < 0)
 	return retval;
       break;
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       if ((retval = MIDIbuf_open (dev, file)) < 0)
 	return retval;
       break;
 #endif
 
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      if ((retval = pss_open (dev, file)) < 0)
+	return retval;
+      break;
+#endif
+
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -375,15 +436,22 @@
       break;
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       sequencer_release (dev, file);
       break;
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       MIDIbuf_release (dev, file);
       break;
 #endif
 
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      pss_release (dev, file);
+      break;
+#endif
+
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -404,6 +472,12 @@
 {
   DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
 
+  if ((dev & 0x0f) != SND_DEV_CTL && num_mixers > 0)
+    if ((cmd >> 8) & 0xff == 'M')	/*
+					 * Mixer ioctl
+					 */
+      return mixer_devs[0]->ioctl (0, cmd, arg);
+
   switch (dev & 0x0f)
     {
 
@@ -412,13 +486,16 @@
       if (!num_mixers)
 	return RET_ERROR (ENXIO);
 
-      if ((dev >> 4) >= num_mixers)
+      dev = dev >> 4;
+
+      if (dev >= num_mixers)
 	return RET_ERROR (ENXIO);
 
-      return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg);
+      return mixer_devs[dev]->ioctl (dev, cmd, arg);
       break;
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       return sequencer_ioctl (dev, file, cmd, arg);
       break;
 
@@ -428,9 +505,15 @@
       return audio_ioctl (dev, file, cmd, arg);
       break;
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_ioctl (dev, file, cmd, arg);
+      break;
+#endif
+
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      return pss_ioctl (dev, file, cmd, arg);
       break;
 #endif
 
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c
--- v1.1.30/linux/drivers/sound/sound_timer.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/sound_timer.c	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,406 @@
+/*
+ * sound/sound_timer.c
+ *
+ * Timer for the level 2 interface of the /dev/sequencer. Uses the
+ * 80 and 320 usec timers of OPL-3 (PAS16 only) and GUS.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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.
+ *
+ */
+
+#define SEQUENCER_C
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#if !defined(EXCLUDE_SEQUENCER) && (!defined(EXCLUDE_GUS) || (!defined(EXCLUDE_PAS) && !defined(EXCLUDE_YM3812)))
+
+static volatile int initialized = 0, opened = 0, tmr_running = 0;
+static volatile time_t tmr_offs, tmr_ctr;
+static volatile unsigned long ticks_offs;
+static volatile int curr_tempo, curr_timebase;
+static volatile unsigned long curr_ticks;
+static volatile unsigned long next_event_time;
+static unsigned long prev_event_time;
+static volatile int select_addr, data_addr;
+static volatile int curr_timer = 0;
+static volatile unsigned long usecs_per_tmr;	/* Length of the current interval */
+
+
+static void
+timer_command (unsigned int addr, unsigned int val)
+{
+  int             i;
+
+  OUTB ((unsigned char) (addr & 0xff), select_addr);
+
+  for (i = 0; i < 2; i++)
+    INB (select_addr);
+
+  OUTB ((unsigned char) (val & 0xff), data_addr);
+
+  for (i = 0; i < 2; i++)
+    INB (select_addr);
+}
+
+static void
+arm_timer (int timer, unsigned int interval)
+{
+
+  curr_timer = timer;
+
+  if (timer == 1)
+    {
+      gus_write8 (0x46, 256 - interval);	/* Set counter for timer 1 */
+      gus_write8 (0x45, 0x04);	/* Enable timer 1 IRQ */
+      timer_command (0x04, 0x01);	/* Start timer 1 */
+    }
+  else
+    {
+      gus_write8 (0x47, 256 - interval);	/* Set counter for timer 2 */
+      gus_write8 (0x45, 0x08);	/* Enable timer 2 IRQ */
+      timer_command (0x04, 0x02);	/* Start timer 2 */
+    }
+}
+
+static unsigned long
+tmr2ticks (int tmr_value)
+{
+  /*
+ *    Convert timer ticks to MIDI ticks
+ */
+
+  unsigned long   tmp;
+  unsigned long   scale;
+
+  tmp = tmr_value * usecs_per_tmr;	/* Convert to usecs */
+
+  scale = (60 * 1000000) / (curr_tempo * curr_timebase);	/* usecs per MIDI tick */
+
+  return (tmp + (scale / 2)) / scale;
+}
+
+static void
+reprogram_timer (void)
+{
+  unsigned long   usecs_per_tick;
+  int             timer_no, resolution;
+  int             divisor;
+
+  usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
+
+  /*
+ * Don't kill the system by setting too high timer rate
+ */
+  if (usecs_per_tick < 2000)
+    usecs_per_tick = 2000;
+
+  if (usecs_per_tick > (256 * 80))
+    {
+      timer_no = 2;
+      resolution = 320;		/* usec */
+    }
+  else
+    {
+      timer_no = 1;
+      resolution = 80;		/* usec */
+    }
+
+  divisor = (usecs_per_tick + (resolution / 2)) / resolution;
+  usecs_per_tmr = divisor * resolution;
+
+  arm_timer (timer_no, divisor);
+}
+
+static void
+tmr_reset (void)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  tmr_offs = 0;
+  ticks_offs = 0;
+  tmr_ctr = 0;
+  next_event_time = 0xffffffff;
+  prev_event_time = 0;
+  curr_ticks = 0;
+  RESTORE_INTR (flags);
+}
+
+static int
+timer_open (int dev, int mode)
+{
+  if (opened)
+    return RET_ERROR (EBUSY);
+
+  tmr_reset ();
+  curr_tempo = 60;
+  curr_timebase = HZ;
+  opened = 1;
+  reprogram_timer ();
+
+  return 0;
+}
+
+static void
+timer_close (int dev)
+{
+  opened = tmr_running = 0;
+  gus_write8 (0x45, 0);		/* Disable both timers */
+}
+
+static int
+timer_event (int dev, unsigned char *event)
+{
+  unsigned char   cmd = event[1];
+  unsigned long   parm = *(int *) &event[4];
+
+  switch (cmd)
+    {
+    case TMR_WAIT_REL:
+      parm += prev_event_time;
+    case TMR_WAIT_ABS:
+      if (parm > 0)
+	{
+	  long            time;
+
+	  if (parm <= curr_ticks)	/* It's the time */
+	    return TIMER_NOT_ARMED;
+
+	  time = parm;
+	  next_event_time = prev_event_time = time;
+
+	  return TIMER_ARMED;
+	}
+      break;
+
+    case TMR_START:
+      tmr_reset ();
+      tmr_running = 1;
+      reprogram_timer ();
+      break;
+
+    case TMR_STOP:
+      tmr_running = 0;
+      break;
+
+    case TMR_CONTINUE:
+      tmr_running = 1;
+      reprogram_timer ();
+      break;
+
+    case TMR_TEMPO:
+      if (parm)
+	{
+	  if (parm < 8)
+	    parm = 8;
+	  if (parm > 250)
+	    parm = 250;
+	  tmr_offs = tmr_ctr;
+	  ticks_offs += tmr2ticks (tmr_ctr);
+	  tmr_ctr = 0;
+	  curr_tempo = parm;
+	  reprogram_timer ();
+	}
+      break;
+
+    case TMR_ECHO:
+      seq_copy_to_input (event, 8);
+      break;
+
+    default:;
+    }
+
+  return TIMER_NOT_ARMED;
+}
+
+static unsigned long
+timer_get_time (int dev)
+{
+  if (!opened)
+    return 0;
+
+  return curr_ticks;
+}
+
+static int
+timer_ioctl (int dev,
+	     unsigned int cmd, unsigned int arg)
+{
+  switch (cmd)
+    {
+    case SNDCTL_TMR_SOURCE:
+      return IOCTL_OUT (arg, TMR_INTERNAL);
+      break;
+
+    case SNDCTL_TMR_START:
+      tmr_reset ();
+      tmr_running = 1;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_STOP:
+      tmr_running = 0;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_CONTINUE:
+      tmr_running = 1;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_TIMEBASE:
+      {
+	int             val = IOCTL_IN (arg);
+
+	if (val)
+	  {
+	    if (val < 1)
+	      val = 1;
+	    if (val > 1000)
+	      val = 1000;
+	    curr_timebase = val;
+	  }
+
+	return IOCTL_OUT (arg, curr_timebase);
+      }
+      break;
+
+    case SNDCTL_TMR_TEMPO:
+      {
+	int             val = IOCTL_IN (arg);
+
+	if (val)
+	  {
+	    if (val < 8)
+	      val = 8;
+	    if (val > 250)
+	      val = 250;
+	    tmr_offs = tmr_ctr;
+	    ticks_offs += tmr2ticks (tmr_ctr);
+	    tmr_ctr = 0;
+	    curr_tempo = val;
+	    reprogram_timer ();
+	  }
+
+	return IOCTL_OUT (arg, curr_tempo);
+      }
+      break;
+
+    case SNDCTL_SEQ_CTRLRATE:
+      if (IOCTL_IN (arg) != 0)	/* Can't change */
+	return RET_ERROR (EINVAL);
+
+      return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+      break;
+
+    case SNDCTL_TMR_METRONOME:
+      /* NOP */
+      break;
+
+    default:
+    }
+
+  return RET_ERROR (EINVAL);
+}
+
+static void
+timer_arm (int dev, long time)
+{
+  if (time < 0)
+    time = curr_ticks + 1;
+  else if (time <= curr_ticks)	/* It's the time */
+    return;
+
+  next_event_time = prev_event_time = time;
+
+  return;
+}
+
+static struct sound_timer_operations sound_timer =
+{
+  {"OPL-3/GUS Timer", 0},
+  1,				/* Priority */
+  0,				/* Local device link */
+  timer_open,
+  timer_close,
+  timer_event,
+  timer_get_time,
+  timer_ioctl,
+  timer_arm
+};
+
+void
+sound_timer_interrupt (void)
+{
+  gus_write8 (0x45, 0);		/* Ack IRQ */
+  timer_command (4, 0x80);	/* Reset IRQ flags */
+
+  if (!opened)
+    return;
+
+  if (curr_timer == 1)
+    gus_write8 (0x45, 0x04);	/* Start timer 1 again */
+  else
+    gus_write8 (0x45, 0x08);	/* Start timer 2 again */
+
+  if (!tmr_running)
+    return;
+
+  tmr_ctr++;
+  curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
+
+  if (curr_ticks >= next_event_time)
+    {
+      next_event_time = 0xffffffff;
+      sequencer_timer ();
+    }
+}
+
+void
+sound_timer_init (int io_base)
+{
+  int             n;
+
+  if (initialized)
+    return;			/* There is already a similar timer */
+
+  select_addr = io_base;
+  data_addr = io_base + 1;
+
+  initialized = 1;
+
+#if 1
+  if (num_sound_timers >= MAX_TIMER_DEV)
+    n = 0;			/* Overwrite the system timer */
+  else
+    n = num_sound_timers++;
+#else
+  n = 0;
+#endif
+
+  sound_timer_devs[n] = &sound_timer;
+}
+
+#endif
+#endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v1.1.30/linux/drivers/sound/soundcard.c	Sun May  1 12:12:45 1994
+++ linux/drivers/sound/soundcard.c	Mon Jul 18 09:50:55 1994
@@ -1,4 +1,3 @@
-
 /*
  * linux/kernel/chr_drv/sound/soundcard.c
  *
@@ -34,8 +33,6 @@
 
 #include <linux/major.h>
 
-extern long     seq_time;
-
 static int      soundcards_installed = 0;	/* Number of installed
 
 						 * soundcards */
@@ -43,10 +40,6 @@
 
 static struct fileinfo files[SND_NDEVS];
 
-extern char    *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
-extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
-extern int      snd_raw_count[MAX_DSP_DEV];
-
 int
 snd_ioctl_return (int *addr, int value)
 {
@@ -146,9 +139,17 @@
 
   switch (dev & 0x0f)
     {
+#ifndef EXCLUDE_SEQUENCER
     case SND_DEV_SEQ:
       return sequencer_select (dev, &files[dev], sel_type, wait);
       break;
+#endif
+
+#ifndef EXCLUDE_MIDI
+    case SND_DEV_MIDIN:
+      return MIDIbuf_select (dev, &files[dev], sel_type, wait);
+      break;
+#endif
 
     default:
       return 0;
@@ -183,19 +184,23 @@
   if (!(soundcards_installed = sndtable_get_cardcount ()))
     return mem_start;		/* No cards detected */
 
-  if (num_dspdevs)		/* Audio devices present */
+#ifndef EXCLUDE_AUDIO
+  if (num_audiodevs)		/* Audio devices present */
     {
       mem_start = DMAbuf_init (mem_start);
       mem_start = audio_init (mem_start);
     }
+#endif
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
   if (num_midis)
     mem_start = MIDIbuf_init (mem_start);
 #endif
 
+#ifndef EXCLUDE_SEQUENCER
   if (num_midis + num_synths)
     mem_start = sequencer_init (mem_start);
+#endif
 
   return mem_start;
 }
@@ -243,10 +248,13 @@
   free_irq (vect);
 }
 
+#ifndef EXCLUDE_SEQUENCER
 void
 request_sound_timer (int count)
 {
-#ifndef EXCLUDE_SEQUENCER
+  extern unsigned long seq_time;
+
+#if 1
   if (count < 0)
     count = jiffies + (-count);
   else
@@ -257,10 +265,12 @@
 #endif
 }
 
+#endif
+
 void
 sound_stop_timer (void)
 {
-#ifndef EXCLUDE_SEQUENCER
+#if 1
   timer_table[SOUND_TIMER].expires = 0;
   timer_active &= ~(1 << SOUND_TIMER);
 #endif
@@ -281,6 +291,7 @@
 {
   int             i, dev;
   unsigned long   start_addr, end_addr, mem_ptr, dma_pagesize;
+  struct dma_buffparms *dmap;
 
   mem_ptr = high_memory;
 
@@ -289,38 +300,40 @@
   if (mem_ptr > (16 * 1024 * 1024))
     mem_ptr = 16 * 1024 * 1024;	/* Limit to 16M */
 
-  for (dev = 0; dev < num_dspdevs; dev++)	/* Enumerate devices */
-    if (sound_buffcounts[dev] > 0 && sound_dsp_dmachan[dev] > 0)
+  for (dev = 0; dev < num_audiodevs; dev++)	/* Enumerate devices */
+    if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
       {
-	if (sound_dma_automode[dev])
-	  sound_buffcounts[dev] = 1;
+	dmap = audio_devs[dev]->dmap;
+
+	if (audio_devs[dev]->flags & DMA_AUTOMODE)
+	  audio_devs[dev]->buffcount = 1;
 
-	if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536)
+	if (audio_devs[dev]->dmachan > 3 && audio_devs[dev]->buffsize > 65536)
 	  dma_pagesize = 131072;/* 128k */
 	else
 	  dma_pagesize = 65536;
 
 	/* More sanity checks */
 
-	if (sound_buffsizes[dev] > dma_pagesize)
-	  sound_buffsizes[dev] = dma_pagesize;
-	sound_buffsizes[dev] &= 0xfffff000;	/* Truncate to n*4k */
-	if (sound_buffsizes[dev] < 4096)
-	  sound_buffsizes[dev] = 4096;
+	if (audio_devs[dev]->buffsize > dma_pagesize)
+	  audio_devs[dev]->buffsize = dma_pagesize;
+	audio_devs[dev]->buffsize &= 0xfffff000;	/* Truncate to n*4k */
+	if (audio_devs[dev]->buffsize < 4096)
+	  audio_devs[dev]->buffsize = 4096;
 
 	/* Now allocate the buffers */
 
-	for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++)
+	for (dmap->raw_count = 0; dmap->raw_count < audio_devs[dev]->buffcount; dmap->raw_count++)
 	  {
-	    start_addr = mem_ptr - sound_buffsizes[dev];
-	    if (!valid_dma_page (start_addr, sound_buffsizes[dev], dma_pagesize))
+	    start_addr = mem_ptr - audio_devs[dev]->buffsize;
+	    if (!valid_dma_page (start_addr, audio_devs[dev]->buffsize, dma_pagesize))
 	      start_addr &= ~(dma_pagesize - 1);	/* Align address to
 							 * dma_pagesize */
 
-	    end_addr = start_addr + sound_buffsizes[dev] - 1;
+	    end_addr = start_addr + audio_devs[dev]->buffsize - 1;
 
-	    snd_raw_buf[dev][snd_raw_count[dev]] = (char *) start_addr;
-	    snd_raw_buf_phys[dev][snd_raw_count[dev]] = start_addr;
+	    dmap->raw_buf[dmap->raw_count] = (char *) start_addr;
+	    dmap->raw_buf_phys[dmap->raw_count] = start_addr;
 	    mem_ptr = start_addr;
 
 	    for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c
--- v1.1.30/linux/drivers/sound/sys_timer.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/sys_timer.c	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,304 @@
+/*
+ * sound/sys_timer.c
+ *
+ * The default timer for the Level 2 sequencer interface
+ * Uses the (100HZ) timer of kernel.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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.
+ *
+ */
+
+#define SEQUENCER_C
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#ifndef EXCLUDE_SEQUENCER
+
+static volatile int opened = 0, tmr_running = 0;
+static volatile time_t tmr_offs, tmr_ctr;
+static volatile unsigned long ticks_offs;
+static volatile int curr_tempo, curr_timebase;
+static volatile unsigned long curr_ticks;
+static volatile unsigned long next_event_time;
+static unsigned long prev_event_time;
+
+static void     poll_def_tmr (unsigned long dummy);
+
+DEFINE_TIMER (def_tmr, poll_def_tmr);
+
+static unsigned long
+tmr2ticks (int tmr_value)
+{
+  /*
+ *    Convert system timer ticks (HZ) to MIDI ticks
+ */
+
+  unsigned long   tmp;
+  unsigned long   scale;
+
+  tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */
+
+  scale = (60 * 1000) / (curr_tempo * curr_timebase);	/* msecs per MIDI tick */
+
+  return (tmp + (scale / 2)) / scale;
+}
+
+static void
+poll_def_tmr (unsigned long dummy)
+{
+
+  if (opened)
+    {
+      ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);
+
+      if (tmr_running)
+	{
+	  tmr_ctr++;
+	  curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
+
+	  if (curr_ticks >= next_event_time)
+	    {
+	      next_event_time = 0xffffffff;
+	      sequencer_timer ();
+	    }
+	}
+    }
+}
+
+static void
+tmr_reset (void)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  tmr_offs = 0;
+  ticks_offs = 0;
+  tmr_ctr = 0;
+  next_event_time = 0xffffffff;
+  prev_event_time = 0;
+  curr_ticks = 0;
+  RESTORE_INTR (flags);
+}
+
+static int
+def_tmr_open (int dev, int mode)
+{
+  if (opened)
+    return RET_ERROR (EBUSY);
+
+  tmr_reset ();
+  curr_tempo = 60;
+  curr_timebase = HZ;
+  opened = 1;
+
+  ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);
+
+  return 0;
+}
+
+static void
+def_tmr_close (int dev)
+{
+  opened = tmr_running = 0;
+}
+
+static int
+def_tmr_event (int dev, unsigned char *event)
+{
+  unsigned char   cmd = event[1];
+  unsigned long   parm = *(int *) &event[4];
+
+  switch (cmd)
+    {
+    case TMR_WAIT_REL:
+      parm += prev_event_time;
+    case TMR_WAIT_ABS:
+      if (parm > 0)
+	{
+	  long            time;
+
+	  if (parm <= curr_ticks)	/* It's the time */
+	    return TIMER_NOT_ARMED;
+
+	  time = parm;
+	  next_event_time = prev_event_time = time;
+
+	  return TIMER_ARMED;
+	}
+      break;
+
+    case TMR_START:
+      tmr_reset ();
+      tmr_running = 1;
+      break;
+
+    case TMR_STOP:
+      tmr_running = 0;
+      break;
+
+    case TMR_CONTINUE:
+      tmr_running = 1;
+      break;
+
+    case TMR_TEMPO:
+      if (parm)
+	{
+	  if (parm < 8)
+	    parm = 8;
+	  if (parm > 250)
+	    parm = 250;
+	  tmr_offs = tmr_ctr;
+	  ticks_offs += tmr2ticks (tmr_ctr);
+	  tmr_ctr = 0;
+	  curr_tempo = parm;
+	}
+      break;
+
+    case TMR_ECHO:
+      seq_copy_to_input (event, 8);
+      break;
+
+    default:;
+    }
+
+  return TIMER_NOT_ARMED;
+}
+
+static unsigned long
+def_tmr_get_time (int dev)
+{
+  if (!opened)
+    return 0;
+
+  return curr_ticks;
+}
+
+static int
+def_tmr_ioctl (int dev,
+	       unsigned int cmd, unsigned int arg)
+{
+  switch (cmd)
+    {
+    case SNDCTL_TMR_SOURCE:
+      return IOCTL_OUT (arg, TMR_INTERNAL);
+      break;
+
+    case SNDCTL_TMR_START:
+      tmr_reset ();
+      tmr_running = 1;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_STOP:
+      tmr_running = 0;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_CONTINUE:
+      tmr_running = 1;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_TIMEBASE:
+      {
+	int             val = IOCTL_IN (arg);
+
+	if (val)
+	  {
+	    if (val < 1)
+	      val = 1;
+	    if (val > 1000)
+	      val = 1000;
+	    curr_timebase = val;
+	  }
+
+	return IOCTL_OUT (arg, curr_timebase);
+      }
+      break;
+
+    case SNDCTL_TMR_TEMPO:
+      {
+	int             val = IOCTL_IN (arg);
+
+	if (val)
+	  {
+	    if (val < 8)
+	      val = 8;
+	    if (val > 250)
+	      val = 250;
+	    tmr_offs = tmr_ctr;
+	    ticks_offs += tmr2ticks (tmr_ctr);
+	    tmr_ctr = 0;
+	    curr_tempo = val;
+	  }
+
+	return IOCTL_OUT (arg, curr_tempo);
+      }
+      break;
+
+    case SNDCTL_SEQ_CTRLRATE:
+      if (IOCTL_IN (arg) != 0)	/* Can't change */
+	return RET_ERROR (EINVAL);
+
+      return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+      break;
+
+    case SNDCTL_TMR_METRONOME:
+      /* NOP */
+      break;
+
+    default:;
+    }
+
+  return RET_ERROR (EINVAL);
+}
+
+static void
+def_tmr_arm (int dev, long time)
+{
+  if (time < 0)
+    time = curr_ticks + 1;
+  else if (time <= curr_ticks)	/* It's the time */
+    return;
+
+  next_event_time = prev_event_time = time;
+
+  return;
+}
+
+struct sound_timer_operations default_sound_timer =
+{
+  {"System Timer", 0},
+  0,				/* Priority */
+  0,				/* Local device link */
+  def_tmr_open,
+  def_tmr_close,
+  def_tmr_event,
+  def_tmr_get_time,
+  def_tmr_ioctl,
+  def_tmr_arm
+};
+
+#endif
+#endif
diff -u --recursive --new-file v1.1.30/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c
--- v1.1.30/linux/drivers/sound/uart6850.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/uart6850.c	Mon Jul 18 09:50:55 1994
@@ -0,0 +1,323 @@
+/*
+ * sound/uart6850.c
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl:
+ *      added 6850 support, used with COVOX SoundMaster II and custom cards.
+ *
+ * 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 "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+
+#define	DATAPORT   (uart6850_base)	/*
+					   * * * Midi6850 Data I/O Port on IBM
+					   *  */
+#define	COMDPORT   (uart6850_base+1)	/*
+					   * * * Midi6850 Command Port on IBM   */
+#define	STATPORT   (uart6850_base+1)	/*
+					   * * * Midi6850 Status Port on IBM   */
+
+#define uart6850_status()		INB(STATPORT)
+#define input_avail()		((uart6850_status()&INPUT_AVAIL))
+#define output_ready()		((uart6850_status()&OUTPUT_READY))
+#define uart6850_cmd(cmd)	OUTB(cmd, COMDPORT)
+#define uart6850_read()		INB(DATAPORT)
+#define uart6850_write(byte)	OUTB(byte, DATAPORT)
+
+#define	OUTPUT_READY	0x02	/*
+				   * * * Mask for Data Read Ready Bit   */
+#define	INPUT_AVAIL	0x01	/*
+				   * * * Mask for Data Send Ready Bit   */
+
+#define	UART_RESET	0x95	/*
+				   * * * 6850 Total Reset Command   */
+#define	UART_MODE_ON	0x03	/*
+				   * * * 6850 Send/Receive UART Mode   */
+
+static int      uart6850_opened = 0;
+static int      uart6850_base = 0x330;
+static int      uart6850_irq;
+static int      uart6850_detected = 0;
+static int      my_dev;
+
+static int      reset_uart6850 (void);
+static void     (*midi_input_intr) (int dev, unsigned char data);
+
+static void
+uart6850_input_loop (void)
+{
+  int             count;
+
+  count = 10;
+
+  while (count)			/*
+				 * Not timed out
+				 */
+    if (input_avail ())
+      {
+	unsigned char   c = uart6850_read ();
+
+	count = 100;
+
+	if (uart6850_opened & OPEN_READ)
+	  midi_input_intr (my_dev, c);
+      }
+    else
+      while (!input_avail () && count)
+	count--;
+}
+
+void
+m6850intr (int unit)
+{
+  printk ("M");
+  if (input_avail ())
+    uart6850_input_loop ();
+}
+
+/*
+ * It looks like there is no input interrupts in the UART mode. Let's try
+ * polling.
+ */
+
+static void
+poll_uart6850 (unsigned long dummy)
+{
+  unsigned long   flags;
+
+  DEFINE_TIMER (uart6850_timer, poll_uart6850);
+
+  if (!(uart6850_opened & OPEN_READ))
+    return;			/*
+				 * No longer required
+				 */
+
+  DISABLE_INTR (flags);
+
+  if (input_avail ())
+    uart6850_input_loop ();
+
+  ACTIVATE_TIMER (uart6850_timer, poll_uart6850, 1);	/*
+							 * Come back later
+							 */
+
+  RESTORE_INTR (flags);
+}
+
+static int
+uart6850_open (int dev, int mode,
+	       void            (*input) (int dev, unsigned char data),
+	       void            (*output) (int dev)
+)
+{
+  if (uart6850_opened)
+    {
+      printk ("Midi6850: Midi busy\n");
+      return RET_ERROR (EBUSY);
+    }
+
+  uart6850_cmd (UART_RESET);
+
+  uart6850_input_loop ();
+
+  midi_input_intr = input;
+  uart6850_opened = mode;
+  poll_uart6850 (0);		/*
+				 * Enable input polling
+				 */
+
+  return 0;
+}
+
+static void
+uart6850_close (int dev)
+{
+  uart6850_cmd (UART_MODE_ON);
+
+  uart6850_opened = 0;
+}
+
+static int
+uart6850_out (int dev, unsigned char midi_byte)
+{
+  int             timeout;
+  unsigned long   flags;
+
+  /*
+   * Test for input since pending input seems to block the output.
+   */
+
+  DISABLE_INTR (flags);
+
+  if (input_avail ())
+    uart6850_input_loop ();
+
+  RESTORE_INTR (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 ("Midi6850: Timeout\n");
+      return 0;
+    }
+
+  uart6850_write (midi_byte);
+  return 1;
+}
+
+static int
+uart6850_command (int dev, unsigned char *midi_byte)
+{
+  return 1;
+}
+
+static int
+uart6850_start_read (int dev)
+{
+  return 0;
+}
+
+static int
+uart6850_end_read (int dev)
+{
+  return 0;
+}
+
+static int
+uart6850_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+  return RET_ERROR (EINVAL);
+}
+
+static void
+uart6850_kick (int dev)
+{
+}
+
+static int
+uart6850_buffer_status (int dev)
+{
+  return 0;			/*
+				 * No data in buffers
+				 */
+}
+
+#define MIDI_SYNTH_NAME	"6850 UART Midi"
+#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
+static struct midi_operations uart6850_operations =
+{
+  {"6850 UART", 0, 0, SNDCARD_UART6850},
+  &std_midi_synth,
+  uart6850_open,
+  uart6850_close,
+  uart6850_ioctl,
+  uart6850_out,
+  uart6850_start_read,
+  uart6850_end_read,
+  uart6850_kick,
+  uart6850_command,
+  uart6850_buffer_status
+};
+
+
+long
+attach_uart6850 (long mem_start, struct address_info *hw_config)
+{
+  int             ok, timeout;
+  unsigned long   flags;
+
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return mem_start;
+    }
+
+  uart6850_base = hw_config->io_base;
+  uart6850_irq = hw_config->irq;
+
+  if (!uart6850_detected)
+    return RET_ERROR (EIO);
+
+  DISABLE_INTR (flags);
+
+  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);	/*
+									 * Wait
+									 */
+  uart6850_cmd (UART_MODE_ON);
+
+  ok = 1;
+
+  RESTORE_INTR (flags);
+
+  printk (" <6850 Midi Interface>");
+
+  std_midi_synth.midi_dev = my_dev = num_midis;
+  midi_devs[num_midis++] = &uart6850_operations;
+  return mem_start;
+}
+
+static int
+reset_uart6850 (void)
+{
+  uart6850_read ();
+  return 1;			/*
+				 * OK
+				 */
+}
+
+
+int
+probe_uart6850 (struct address_info *hw_config)
+{
+  int             ok = 0;
+
+  uart6850_base = hw_config->io_base;
+  uart6850_irq = hw_config->irq;
+
+  if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0)
+    return 0;
+
+  ok = reset_uart6850 ();
+
+  uart6850_detected = ok;
+  return ok;
+}
+
+#endif
+
+#endif
diff -u --recursive --new-file v1.1.30/linux/fs/buffer.c linux/fs/buffer.c
--- v1.1.30/linux/fs/buffer.c	Fri Jul  8 13:26:40 1994
+++ linux/fs/buffer.c	Mon Jul 18 13:08:22 1994
@@ -1113,13 +1113,13 @@
  * etc. This also allows us to optimize memory usage by sharing code pages
  * and filesystem buffers..
  */
-unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int prot)
+unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int share)
 {
 	struct buffer_head * bh[8];
 	unsigned long where;
 	int i, j;
 
-	if (!(prot & PAGE_RW)) {
+	if (share) {
 		where = try_to_share_buffers(address,dev,b,size);
 		if (where)
 			return where;
diff -u --recursive --new-file v1.1.30/linux/fs/ext/namei.c linux/fs/ext/namei.c
--- v1.1.30/linux/fs/ext/namei.c	Fri May 27 10:49:12 1994
+++ linux/fs/ext/namei.c	Mon Jul 18 11:29:02 1994
@@ -55,7 +55,7 @@
  */
 static int ext_match(int len,const char * name,struct ext_dir_entry * de)
 {
-	register int same __asm__("ax");
+	register int same;
 
 	if (!de || !de->inode || len > EXT_NAME_LEN)
 		return 0;
@@ -64,7 +64,8 @@
 		return 1;
 	if (len < EXT_NAME_LEN && len != de->name_len)
 		return 0;
-	__asm__("cld\n\t"
+	__asm__ __volatile__(
+		"cld\n\t"
 		"repe ; cmpsb\n\t"
 		"setz %%al"
 		:"=a" (same)
diff -u --recursive --new-file v1.1.30/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v1.1.30/linux/fs/ext2/namei.c	Fri May 27 10:49:13 1994
+++ linux/fs/ext2/namei.c	Mon Jul 18 09:15:15 1994
@@ -390,6 +390,7 @@
 		return err;
 	}
 	de->inode = inode->i_ino;
+	dir->i_version++;
 #ifndef DONT_USE_DCACHE
 	ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 			 de->inode);
@@ -456,6 +457,7 @@
 		return err;
 	}
 	de->inode = inode->i_ino;
+	dir->i_version++;
 #ifndef DONT_USE_DCACHE
 	ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 			 de->inode);
@@ -532,6 +534,7 @@
 		return err;
 	}
 	de->inode = inode->i_ino;
+	dir->i_version++;
 #ifndef DONT_USE_DCACHE
 	ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 			 de->inode);
@@ -657,6 +660,7 @@
 			inode->i_size = 0;
 		}
 		retval = ext2_delete_entry (de, bh);
+		dir->i_version++;
 	}
 	up(&inode->i_sem);
 	if (retval)
@@ -729,6 +733,7 @@
 	retval = ext2_delete_entry (de, bh);
 	if (retval)
 		goto end_unlink;
+	dir->i_version++;
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -817,6 +822,7 @@
 		return err;
 	}
 	de->inode = inode->i_ino;
+	dir->i_version++;
 #ifndef DONT_USE_DCACHE
 	ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 			 de->inode);
@@ -863,6 +869,7 @@
 		return err;
 	}
 	de->inode = oldinode->i_ino;
+	dir->i_version++;
 #ifndef DONT_USE_DCACHE
 	ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
 			 de->inode);
@@ -1036,6 +1043,8 @@
 		goto try_again;
 	if (retval)
 		goto end_rename;
+	new_dir->i_version++;
+	old_dir->i_version++;
 	if (new_inode) {
 		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME;
@@ -1043,16 +1052,6 @@
 	}
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	old_dir->i_dirt = 1;
-	mark_buffer_dirty(old_bh,  1);
-	if (IS_SYNC(old_dir)) {
-		ll_rw_block (WRITE, 1, &old_bh);
-		wait_on_buffer (old_bh);
-	}
-	mark_buffer_dirty(new_bh, 1);
-	if (IS_SYNC(new_dir)) {
-		ll_rw_block (WRITE, 1, &new_bh);
-		wait_on_buffer (new_bh);
-	}
 	if (dir_bh) {
 		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
 		mark_buffer_dirty(dir_bh, 1);
@@ -1065,6 +1064,16 @@
 			new_dir->i_nlink++;
 			new_dir->i_dirt = 1;
 		}
+	}
+	mark_buffer_dirty(old_bh,  1);
+	if (IS_SYNC(old_dir)) {
+		ll_rw_block (WRITE, 1, &old_bh);
+		wait_on_buffer (old_bh);
+	}
+	mark_buffer_dirty(new_bh, 1);
+	if (IS_SYNC(new_dir)) {
+		ll_rw_block (WRITE, 1, &new_bh);
+		wait_on_buffer (new_bh);
 	}
 	retval = 0;
 end_rename:
diff -u --recursive --new-file v1.1.30/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v1.1.30/linux/fs/isofs/namei.c	Sun Dec 12 12:26:43 1993
+++ linux/fs/isofs/namei.c	Mon Jul 18 11:24:50 1994
@@ -26,7 +26,7 @@
  */
 static int isofs_match(int len,const char * name, char * compare, int dlen)
 {
-	register int same __asm__("ax");
+	register int same;
 	
 	if (!compare) return 0;
 	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
@@ -45,7 +45,8 @@
 	
 	if (dlen != len)
 		return 0;
-	__asm__("cld\n\t"
+	__asm__ __volatile__(
+		"cld\n\t"
 		"repe ; cmpsb\n\t"
 		"setz %%al"
 		:"=a" (same)
diff -u --recursive --new-file v1.1.30/linux/fs/nfs/mmap.c linux/fs/nfs/mmap.c
--- v1.1.30/linux/fs/nfs/mmap.c	Tue Jun 21 14:16:23 1994
+++ linux/fs/nfs/mmap.c	Mon Jul 18 13:00:26 1994
@@ -23,16 +23,9 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 
-extern int share_page(struct vm_area_struct * area, struct task_struct * tsk,
-	struct inode * inode, unsigned long address, unsigned long error_code,
-	unsigned long newpage);
+static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area,
+	unsigned long address, unsigned long page, int error_code);
 
-extern unsigned long put_page(struct task_struct * tsk,unsigned long page,
-	unsigned long address,int prot);
-
-static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
-				unsigned long address);
-
 extern void file_mmap_free(struct vm_area_struct * area);
 extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to,
 				unsigned long address);
@@ -85,12 +78,11 @@
 }
 
 
-static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
-				unsigned long address)
+static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
+	unsigned long page, int error_code)
 {
 	struct inode * inode = area->vm_inode;
 	unsigned int clear;
-	unsigned long page;
 	unsigned long tmp;
 	int n;
 	int i;
@@ -100,19 +92,6 @@
 	address &= PAGE_MASK;
 	pos = address - area->vm_start + area->vm_offset;
 
-	page = get_free_page(GFP_KERNEL);
-	if (share_page(area, area->vm_task, inode, address, error_code, page)) {
-		++area->vm_task->mm->min_flt;
-		return;
-	}
-
-	++area->vm_task->mm->maj_flt;
-	if (!page) {
-		oom(current);
-		put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
-		return;
-	}
-
 	clear = 0;
 	if (address + PAGE_SIZE > area->vm_end) {
 		clear = address + PAGE_SIZE - area->vm_end;
@@ -141,17 +120,9 @@
 	nfs_refresh_inode(inode, &fattr);
 #endif
 
-	if (!(error_code & PAGE_RW)) {
-		if (share_page(area, area->vm_task, inode, address, error_code, page))
-			return;
-	}
-
 	tmp = page + PAGE_SIZE;
 	while (clear--) {
 		*(char *)--tmp = 0;
 	}
-	if (put_page(area->vm_task,page,address,area->vm_page_prot))
-		return;
-	free_page(page);
-	oom(current);
+	return page;
 }
diff -u --recursive --new-file v1.1.30/linux/fs/super.c linux/fs/super.c
--- v1.1.30/linux/fs/super.c	Tue May 31 12:48:18 1994
+++ linux/fs/super.c	Mon Jul 18 22:51:13 1994
@@ -610,7 +610,11 @@
 	}
 	fops = get_blkfops(MAJOR(dev));
 	if (fops && fops->open) {
-		retval = fops->open(inode,NULL);
+		struct file dummy;	/* allows read-write or read-only flag */
+		memset(&dummy, 0, sizeof(dummy));
+		dummy.f_inode = inode;
+		dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
+		retval = fops->open(inode, &dummy);
 		if (retval) {
 			iput(inode);
 			return retval;
@@ -628,7 +632,7 @@
 	retval = do_mount(dev,dir_name,t,flags,(void *) page);
 	free_page(page);
 	if (retval && fops && fops->release)
-		fops->release(inode,NULL);
+		fops->release(inode, NULL);
 	iput(inode);
 	return retval;
 }
diff -u --recursive --new-file v1.1.30/linux/include/linux/fdreg.h linux/include/linux/fdreg.h
--- v1.1.30/linux/include/linux/fdreg.h	Tue Mar  1 08:27:32 1994
+++ linux/include/linux/fdreg.h	Mon Jul 18 22:51:14 1994
@@ -47,8 +47,11 @@
 
 /* Bits of FD_ST3 */
 #define ST3_HA		0x04		/* Head (Address) */
+#define ST3_DS		0x08		/* drive is double-sided */
 #define ST3_TZ		0x10		/* Track Zero signal (1=track 0) */
+#define ST3_RY		0x20		/* drive is ready */
 #define ST3_WP		0x40		/* Write Protect */
+#define ST3_FT		0x80		/* Drive Fault */
 
 /* Values for FD_COMMAND */
 #define FD_RECALIBRATE		0x07	/* move to track 0 */
@@ -61,6 +64,7 @@
 #define FD_VERSION		0x10	/* get version code */
 #define FD_CONFIGURE		0x13	/* configure FIFO operation */
 #define FD_PERPENDICULAR	0x12	/* perpendicular r/w mode */
+#define FD_GETSTATUS		0x04	/* read ST3 */
 
 /* DMA commands */
 #define DMA_READ	0x46
diff -u --recursive --new-file v1.1.30/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.1.30/linux/include/linux/fs.h	Mon Jul 18 14:48:30 1994
+++ linux/include/linux/fs.h	Mon Jul 18 13:08:40 1994
@@ -444,7 +444,7 @@
 extern void brelse(struct buffer_head * buf);
 extern void set_blocksize(dev_t dev, int size);
 extern struct buffer_head * bread(dev_t dev, int block, int size);
-extern unsigned long bread_page(unsigned long addr,dev_t dev,int b[],int size,int prot);
+extern unsigned long bread_page(unsigned long addr,dev_t dev,int b[],int size,int share);
 extern struct buffer_head * breada(dev_t dev,int block, int size, 
 				   unsigned int pos, unsigned int filesize);
 extern void put_super(dev_t dev);
diff -u --recursive --new-file v1.1.30/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.1.30/linux/include/linux/mm.h	Sat Jul  9 16:30:47 1994
+++ linux/include/linux/mm.h	Mon Jul 18 12:33:53 1994
@@ -55,9 +55,10 @@
 struct vm_operations_struct {
 	void (*open)(struct vm_area_struct * area);
 	void (*close)(struct vm_area_struct * area);
-	void (*nopage)(int error_code,
-		       struct vm_area_struct * area, unsigned long address);
-	void (*wppage)(struct vm_area_struct * area, unsigned long address);
+	unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address,
+		unsigned long page, int error_code);
+	unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
+		unsigned long page);
 	int (*share)(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address);
 	int (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
 };
@@ -135,6 +136,7 @@
 extern void show_free_areas(void);
 extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
 	unsigned long address);
+
 extern void free_page_tables(struct task_struct * tsk);
 extern void clear_page_tables(struct task_struct * tsk);
 extern int copy_page_tables(struct task_struct * to);
@@ -144,9 +146,9 @@
 extern int zeromap_page_range(unsigned long from, unsigned long size, int mask);
 
 extern void do_wp_page(unsigned long error_code, unsigned long address,
-	struct task_struct *tsk, unsigned long user_esp);
+	struct task_struct *tsk);
 extern void do_no_page(unsigned long error_code, unsigned long address,
-	struct task_struct *tsk, unsigned long user_esp);
+	struct task_struct *tsk);
 
 extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
 extern void mem_init(unsigned long low_start_mem,
diff -u --recursive --new-file v1.1.30/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v1.1.30/linux/include/linux/soundcard.h	Sun May  1 12:12:47 1994
+++ linux/include/linux/soundcard.h	Mon Jul 18 09:38:23 1994
@@ -34,7 +34,7 @@
   *
   * Regards,
   * Hannu Savolainen
-  * hannu@voxware.pp.fi, Hannu.Savolainen@helsinki.fi
+  * hannu@voxware.pp.fi
   */
 
 #define SOUND_VERSION	203
@@ -46,13 +46,17 @@
  *	Supported card ID numbers (Should be somewhere else?)
  */
 
-#define SNDCARD_ADLIB	1
-#define SNDCARD_SB	2
-#define SNDCARD_PAS	3
-#define SNDCARD_GUS	4
-#define SNDCARD_MPU401	5
-#define SNDCARD_SB16	6
-#define SNDCARD_SB16MIDI 7
+#define SNDCARD_ADLIB		1
+#define SNDCARD_SB		2
+#define SNDCARD_PAS		3
+#define SNDCARD_GUS		4
+#define SNDCARD_MPU401		5
+#define SNDCARD_SB16		6
+#define SNDCARD_SB16MIDI	7
+#define SNDCARD_UART6850	8
+#define SNDCARD_GUS16		9
+#define SNDCARD_MSS		10
+#define SNDCARD_PSS     	11
 
 /***********************************
  * IOCTL Commands for /dev/sequencer
@@ -98,7 +102,23 @@
 #define SNDCTL_SYNTH_MEMAVL		_IOWR('Q',14, int)	/* in=dev#, out=memsize */
 #define SNDCTL_FM_4OP_ENABLE		_IOW ('Q',15, int)	/* in=dev# */
 #define SNDCTL_PMGR_ACCESS		_IOWR('Q',16, struct patmgr_info)
+#define SNDCTL_SEQ_PANIC		_IO  ('Q',17)
 
+#define SNDCTL_TMR_TIMEBASE		_IOWR('T', 1, int)
+#define SNDCTL_TMR_START		_IO  ('T', 2)
+#define SNDCTL_TMR_STOP			_IO  ('T', 3)
+#define SNDCTL_TMR_CONTINUE		_IO  ('T', 4)
+#define SNDCTL_TMR_TEMPO		_IOWR('T', 5, int)
+#define SNDCTL_TMR_SOURCE		_IOWR('T', 6, int)
+#	define TMR_INTERNAL		0x00000001
+#	define TMR_EXTERNAL		0x00000002
+#		define TMR_MODE_MIDI	0x00000010
+#		define TMR_MODE_FSK	0x00000020
+#		define TMR_MODE_CLS	0x00000040
+#		define TMR_MODE_SMPTE	0x00000080
+#define SNDCTL_TMR_METRONOME		_IOW ('T', 7, int)
+#define SNDCTL_TMR_SELECT		_IOW ('T', 8, int)
+
 /*
  *	Sample loading mechanism for internal synthesizers (/dev/sequencer)
  *	The following patch_info structure has been designed to support
@@ -187,6 +207,14 @@
 	};
 
 
+struct sysex_info {
+		short key;		/* Use GUS_PATCH here */
+#define SYSEX_PATCH	0x05fd
+		short device_no;	/* Synthesizer number */
+		long len;	/* Size of the sysex data in bytes */
+		unsigned char data[1];	/* Sysex data starts here */
+	};
+
 /*
  * Patch management interface (/dev/sequencer, /dev/patmgr#)
  * Don't use these calls if you want to maintain compatibility with
@@ -282,7 +310,7 @@
  *
  * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events.
  * (All input events are currently 4 bytes long. Be prepared to support
- * 8 byte events also. If you receive any event having first byte >= 0xf0,
+ * 8 byte events also. If you receive any event having first byte >= 128,
  * it's a 8 byte event.
  *
  * The events are documented at the end of this file.
@@ -295,20 +323,99 @@
 #define SEQ_FMNOTEOFF		SEQ_NOTEOFF	/* Just old name */
 #define SEQ_NOTEON		1
 #define	SEQ_FMNOTEON		SEQ_NOTEON
-#define SEQ_WAIT		2
+#define SEQ_WAIT		TMR_WAIT_ABS
 #define SEQ_PGMCHANGE		3
 #define SEQ_FMPGMCHANGE		SEQ_PGMCHANGE
-#define SEQ_SYNCTIMER		4
+#define SEQ_SYNCTIMER		TMR_START
 #define SEQ_MIDIPUTC		5
 #define SEQ_DRUMON		6	/*** OBSOLETE ***/
 #define SEQ_DRUMOFF		7	/*** OBSOLETE ***/
-#define SEQ_ECHO		8	/* For synching programs with output */
+#define SEQ_ECHO		TMR_ECHO	/* For synching programs with output */
 #define SEQ_AFTERTOUCH		9
 #define SEQ_CONTROLLER		10
+
+/*******************************************
+ *	Midi controller numbers
+ *******************************************
+ * Controllers 0 to 31 (0x00 to 0x1f) and
+ * 32 to 63 (0x20 to 0x3f) are continuous
+ * controllers.
+ * In the MIDI 1.0 these controllers are sent using
+ * two messages. Controller numbers 0 to 31 are used
+ * to send the LSB and the controller numbers 32 to 63
+ * are for the LSB.
+ *
+ * This driver uses just the numbers 0 to 31 to store both
+ * the LSB and MSB. The controller value is a unsigned short
+ * and it's valid range is between 0 and 16383 (0x0000 to 0x3fff).
+ * The driver sends the controller value using two messages when
+ * necessary.
+ */
+
+#define	   CTL_BANK_SELECT		0x00
+#define	   CTL_MODWHEEL			0x01
+#define    CTL_BREATH			0x02
+/*		undefined		0x03 */
+#define    CTL_FOOT			0x04
+#define    CTL_PORTAMENTO_TIME		0x05
+#define    CTL_DATA_ENTRY		0x06
+#define    CTL_MAIN_VOLUME		0x07
+#define    CTL_BALANCE			0x08
+/*		undefined		0x09 */
+#define    CTL_PAN			0x0a
+#define    CTL_EXPRESSION		0x0b
+/*		undefined		0x0c */
+/*		undefined		0x0d */
+/*		undefined		0x0e */
+/*		undefined		0x0f */
+#define    CTL_GENERAL_PURPOSE1	0x10
+#define    CTL_GENERAL_PURPOSE2	0x11
+#define    CTL_GENERAL_PURPOSE3	0x12
+#define    CTL_GENERAL_PURPOSE4	0x13
+/*		undefined		0x14 - 0x1f */
+
+/*		undefined		0x20 */
+/* The controller numbers 0x21 to 0x3f are reserved for the */
+/* least significant bytes of the controllers 0x00 to 0x1f. */
+/* These controllers are not recognised by the driver. */
+
+/* Controllers 64 to 69 (0x40 to 0x45) are on/off switches. */
+/* 0=OFF and 127=ON (intermediate values are possible) */
+#define    CTL_DAMPER_PEDAL		0x40
+#define    CTL_SUSTAIN			0x40	/* Alias */
+#define    CTL_HOLD			0x40	/* Alias */
+#define    CTL_PORTAMENTO		0x41
+#define    CTL_SOSTENUTO		0x42
+#define    CTL_SOFT_PEDAL		0x43
+/*		undefined		0x44 */
+#define    CTL_HOLD2			0x45
+/*		undefined		0x46 - 0x4f */
+
+#define    CTL_GENERAL_PURPOSE5	0x50
+#define    CTL_GENERAL_PURPOSE6	0x51
+#define    CTL_GENERAL_PURPOSE7	0x52
+#define    CTL_GENERAL_PURPOSE8	0x53
+/*		undefined		0x54 - 0x5a */
+#define    CTL_EXT_EFF_DEPTH		0x5b
+#define    CTL_TREMOLO_DEPTH		0x5c
+#define    CTL_CHORUS_DEPTH		0x5d
+#define    CTL_DETUNE_DEPTH		0x5e
+#define    CTL_CELESTE_DEPTH		0x5e	/* Alias for the above one */
+#define    CTL_PHASER_DEPTH		0x5f
+#define    CTL_DATA_INCREMENT		0x60
+#define    CTL_DATA_DECREMENT		0x61
+#define    CTL_NONREG_PARM_NUM_LSB	0x62
+#define    CTL_NONREG_PARM_NUM_MSB	0x63
+#define    CTL_REGIST_PARM_NUM_LSB	0x64
+#define    CTL_REGIST_PARM_NUM_MSB	0x65
+/*		undefined		0x66 - 0x78 */
+/*		reserved		0x79 - 0x7f */
+
+/* Pseudo controllers (not midi compatible) */
 #define    CTRL_PITCH_BENDER		255
 #define    CTRL_PITCH_BENDER_RANGE	254
-#define    CTRL_EXPRESSION		253
-#define    CTRL_MAIN_VOLUME		252
+#define    CTRL_EXPRESSION		253	/* Obsolete */
+#define    CTRL_MAIN_VOLUME		252	/* Obsolete */
 #define SEQ_BALANCE		11
 #define SEQ_VOLMODE             12
 
@@ -350,26 +457,7 @@
  *      to GUS_PATCH.
  */
 #define SEQ_PRIVATE		0xfe	/* Low level HW dependent events (8 bytes) */
-#define SEQ_EXTENDED		0xff	/* Extended events (8 bytes) */
-
-/*
- *	Extended events for synthesizers (8 bytes)
- *
- *	Format:
- *
- *		b0	= SEQ_EXTENDED
- *		b1	= command
- *		b2	= device
- *		b3-b7	= parameters
- *
- *	Command				b3	b4	b5	b6	b7
- *	----------------------------------------------------------------------------
- *	SEQ_NOTEON			voice	note	volume	0	0
- *	SEQ_NOTEOFF			voice	note	volume	0	0
- *	SEQ_PGMCHANGE			voice	pgm	0	0	0
- *	SEQ_DRUMON			(voice)	drum#	volume	0	0
- *	SEQ_DRUMOFF			(voice)	drum#	volume	0	0
- */
+#define SEQ_EXTENDED		0xff	/* Extended events (8 bytes) OBSOLETE */
 
 /*
  * Record for FM patches
@@ -392,6 +480,7 @@
 		int	synth_type;
 #define SYNTH_TYPE_FM			0
 #define SYNTH_TYPE_SAMPLE		1
+#define SYNTH_TYPE_MIDI			2	/* Midi interface */
 
 		int	synth_subtype;
 #define FM_TYPE_ADLIB			0x00
@@ -406,9 +495,17 @@
 		unsigned long	capabilities;	
 #define SYNTH_CAP_PERCMODE		0x00000001 /* No longer used */
 #define SYNTH_CAP_OPL3			0x00000002 /* Set if OPL3 supported */
+#define SYNTH_CAP_INPUT			0x00000004 /* Input (MIDI) device */
 		int	dummies[19];	/* Reserve space */
 	};
 
+struct sound_timer_info {
+		char name[30];
+		int caps;
+	};
+
+#define MIDI_CAP_MPU401		1		/* MPU-401 intelligent mode */
+
 struct midi_info {
 		char		name[30];
 		int		device;		/* 0-N. INITIALIZE BEFORE CALLING */
@@ -418,6 +515,19 @@
 	};
 
 /********************************************
+ * ioctl commands for the /dev/midi##
+ */
+typedef struct {
+		unsigned char cmd;
+		char nr_args, nr_returns;
+		unsigned char data[30];
+	} mpu_command_rec;
+
+#define SNDCTL_MIDI_PRETIME		_IOWR('m', 0, int)
+#define SNDCTL_MIDI_MPUMODE		_IOWR('m', 1, int)
+#define SNDCTL_MIDI_MPUCMD		_IOWR('m', 2, mpu_command_rec)
+
+/********************************************
  * IOCTL commands for /dev/dsp and /dev/audio
  */
 
@@ -426,24 +536,57 @@
 #define SNDCTL_DSP_SPEED		_IOWR('P', 2, int)
 #define SNDCTL_DSP_STEREO		_IOWR('P', 3, int)
 #define SNDCTL_DSP_GETBLKSIZE		_IOWR('P', 4, int)
-#define SNDCTL_DSP_SAMPLESIZE		_IOWR('P', 5, int)	/* 8, 12 or 16 */
+#define SNDCTL_DSP_SAMPLESIZE		SNDCTL_DSP_SETFMT
 #define SOUND_PCM_WRITE_CHANNELS	_IOWR('P', 6, int)
 #define SOUND_PCM_WRITE_FILTER		_IOWR('P', 7, int)
 #define SNDCTL_DSP_POST			_IO  ('P', 8)
 #define SNDCTL_DSP_SUBDIVIDE		_IOWR('P', 9, int)
+#define SNDCTL_DSP_SETFRAGMENT		_IOWR('P',10, int)
 
+/*	Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */
+#define SNDCTL_DSP_GETFMTS		_IOR ('P',11, int) /* Returns a mask */
+#define SNDCTL_DSP_SETFMT		_IOWR('P',5, int) /* Selects ONE fmt*/
+#	define AFMT_QUERY		0x00000000	/* Return current fmt */
+#	define AFMT_MU_LAW		0x00000001
+#	define AFMT_A_LAW		0x00000002
+#	define AFMT_IMA_ADPCM		0x00000004
+#	define AFMT_U8			0x00000008
+#	define AFMT_S16_LE		0x00000010	/* Little endian signed 16*/
+#	define AFMT_S16_BE		0x00000020	/* Big endian signed 16 */
+#	define AFMT_S8			0x00000040
+#	define AFMT_U16_LE		0x00000080	/* Little endian U16 */
+#	define AFMT_U16_BE		0x00000100	/* Big endian U16 */
+
 #define SOUND_PCM_READ_RATE		_IOR ('P', 2, int)
 #define SOUND_PCM_READ_CHANNELS		_IOR ('P', 6, int)
 #define SOUND_PCM_READ_BITS		_IOR ('P', 5, int)
 #define SOUND_PCM_READ_FILTER		_IOR ('P', 7, int)
 
 /* Some alias names */
-#define SOUND_PCM_WRITE_BITS		SNDCTL_DSP_SAMPLESIZE
+#define SOUND_PCM_WRITE_BITS		SNDCTL_DSP_SETFMT
 #define SOUND_PCM_WRITE_RATE		SNDCTL_DSP_SPEED
 #define SOUND_PCM_POST			SNDCTL_DSP_POST
 #define SOUND_PCM_RESET			SNDCTL_DSP_RESET
 #define SOUND_PCM_SYNC			SNDCTL_DSP_SYNC
 #define SOUND_PCM_SUBDIVIDE		SNDCTL_DSP_SUBDIVIDE
+#define SOUND_PCM_SETFRAGMENT		SNDCTL_DSP_SETFRAGMENT
+#define SOUND_PCM_GETFMTS		SNDCTL_DSP_GETFMTS
+#define SOUND_PCM_SETFMT		SNDCTL_DSP_SETFMT
+
+/*********************************************
+ * IOCTL /dev/pss (experimental PSS API by marc.hoffman@analog.com.
+ *		likely to change in near future.
+ */
+#define SNDCTL_PSS_RESET             _IO  ('C',  0)
+#define SNDCTL_PSS_SETUP_REGISTERS   _IO  ('C',  1)
+#define SNDCTL_PSS_SPEAKER           _IOW ('C',  2, struct pss_speaker)
+
+struct pss_speaker {
+  int volume;
+  int bass;
+  int treb;
+  int mode;
+};
 
 /*********************************************
  * IOCTL commands for /dev/mixer
@@ -559,57 +702,66 @@
 #define SOUND_MIXER_WRITE_RECSRC	MIXER_WRITE(SOUND_MIXER_RECSRC)
 
 /*
- *	The following mixer ioctl calls are compatible with the BSD driver by
- *	  Steve Haehnichen <shaehnic@ucsd.edu>
+ * Level 2 event types for /dev/sequencer
+ */
+
+/*
+ * The 4 most significant bits of byte 0 specify the class of
+ * the event: 
  *
- * Since this interface is entirely SB specific, it will be dropped in the
- * near future.
+ *	0x8X = system level events,
+ *	0x9X = device/port specific events, event[1] = device/port,
+ *		The last 4 bits give the subtype:
+ *			0x02	= Channel event (event[3] = chn).
+ *			0x01	= note event (event[4] = note).
+ *			(0x01 is not used alone but always with bit 0x02).
+ *	       event[2] = MIDI message code (0x80=note off etc.)
+ *
  */
 
-typedef unsigned char S_BYTE;
-typedef unsigned char S_FLAG;
-struct stereo_vol
-{
-  S_BYTE l;			/* Left volume */
-  S_BYTE r;			/* Right volume */
-};
+#define EV_SEQ_LOCAL		0x80
+#define EV_TIMING		0x81
+#define EV_CHN_COMMON		0x92
+#define EV_CHN_VOICE		0x93
+/*
+ * Event types 200 to 220 are reserved for application use.
+ * These numbers will not be used by the driver.
+ */
 
-#define MIXER_IOCTL_SET_LEVELS 		_IOW ('s', 20, struct sb_mixer_levels)
-#define MIXER_IOCTL_SET_PARAMS 		_IOW ('s', 21, struct sb_mixer_params)
-#define MIXER_IOCTL_READ_LEVELS 	_IOR ('s', 22, struct sb_mixer_levels)
-#define MIXER_IOCTL_READ_PARAMS 	_IOR ('s', 23, struct sb_mixer_params)
-#define MIXER_IOCTL_RESET		_IO  ('s', 24)
-
-/*
- * Mixer volume levels for MIXER_IOCTL_SET_VOL & MIXER_IOCTL_READ_VOL
- */
-struct sb_mixer_levels
-{
-  struct stereo_vol master;	/* Master volume */
-  struct stereo_vol voc;	/* DSP Voice volume */
-  struct stereo_vol fm;		/* FM volume */
-  struct stereo_vol line;	/* Line-in volume */
-  struct stereo_vol cd;		/* CD audio */
-  S_BYTE mic;			/* Microphone level */
-};
+/*
+ * Events for event type EV_CHN_VOICE
+ */
+
+#define MIDI_NOTEOFF		0x80
+#define MIDI_NOTEON		0x90
+#define MIDI_KEY_PRESSURE	0xA0
 
 /*
- * Mixer parameters for MIXER_IOCTL_SET_PARAMS & MIXER_IOCTL_READ_PARAMS
+ * Events for event type EV_CHN_COMMON
  */
-struct sb_mixer_params
-{
-  S_BYTE record_source;		/* Recording source (See SRC_xxx below) */
-  S_FLAG hifreq_filter;		/* Filter frequency (hi/low) */
-  S_FLAG filter_input;		/* ANFI input filter */
-  S_FLAG filter_output;		/* DNFI output filter */
-  S_FLAG dsp_stereo;		/* 1 if DSP is in Stereo mode */
-};
+
+#define MIDI_CTL_CHANGE		0xB0
+#define MIDI_PGM_CHANGE		0xC0
+#define MIDI_CHN_PRESSURE	0xD0
+#define MIDI_PITCH_BEND		0xE0
+
+#define MIDI_SYSTEM_PREFIX	0xF0
 
-#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 */
+/*
+ * Timer event types
+ */
+#define TMR_WAIT_REL		1	/* Time relative to the prev time */
+#define TMR_WAIT_ABS		2	/* Absolute time since TMR_START */
+#define TMR_STOP		3
+#define TMR_START		4
+#define TMR_CONTINUE		5
+#define TMR_TEMPO		6
+#define TMR_ECHO		8
+#define TMR_CLOCK		9	/* MIDI clock */
+#define TMR_SPP			10	/* Song position pointer */
+#define TMR_TIMESIG		11	/* Time signature */
 
-#if !defined(KERNEL) && !defined(INKERNEL)
+#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS) 
 /*
  *	Some convenience macros to simplify programming of the
  *	/dev/sequencer interface
@@ -617,6 +769,7 @@
  *	These macros define the API which should be used when possible.
  */
 
+#ifndef USE_SIMPLE_MACROS
 void seqbuf_dump(void);	/* This function must be provided by programs */
 
 /* Sample seqbuf_dump() implementation:
@@ -638,12 +791,31 @@
  *	}
  */
 
-#define SEQ_DEFINEBUF(len)		unsigned char _seqbuf[len]; int _seqbuflen = len; int _seqbufptr = 0
-#define SEQ_DECLAREBUF()		extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr
+#define SEQ_DEFINEBUF(len)		unsigned char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0
+#define SEQ_USE_EXTBUF()		extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr
+#define SEQ_DECLAREBUF()		SEQ_USE_EXTBUF()
 #define SEQ_PM_DEFINES			struct patmgr_info _pm_info
 #define _SEQ_NEEDBUF(len)		if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
 #define _SEQ_ADVBUF(len)		_seqbufptr += len
 #define SEQ_DUMPBUF			seqbuf_dump
+#else
+/*
+ * This variation of the sequencer macros is used just to format one event
+ * using fixed buffer.
+ * 
+ * The program using the macro library must define the following macros before
+ * using this library.
+ *
+ * #define _seqbuf 		 name of the buffer (unsigned char[]) 
+ * #define _SEQ_ADVBUF(len)	 If the applic needs to know the exact
+ *				 size of the event, this macro can be used.
+ *				 Otherwise this must be defined as empty.
+ * #define _seqbufptr		 Define the name of index variable or 0 if
+ *				 not required. 
+ */
+#define _SEQ_NEEDBUF(len)	/* empty */
+#endif
+
 #define PM_LOAD_PATCH(dev, bank, pgm)	(SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
 					_pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
 					_pm_info.parm1 = bank, _pm_info.parm2 = 1, \
@@ -664,39 +836,68 @@
 					_seqbuf[_seqbufptr+7] = 0;\
 					_SEQ_ADVBUF(8);}
 
-#define SEQ_START_NOTE(dev, voice, note, vol)	{_SEQ_NEEDBUF(8);\
-					_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-					_seqbuf[_seqbufptr+1] = SEQ_NOTEON;\
-					_seqbuf[_seqbufptr+2] = (dev);\
-					_seqbuf[_seqbufptr+3] = (voice);\
-					_seqbuf[_seqbufptr+4] = (note);\
-					_seqbuf[_seqbufptr+5] = (vol);\
-					_seqbuf[_seqbufptr+6] = 0;\
-					_seqbuf[_seqbufptr+7] = 0;\
-					_SEQ_ADVBUF(8);}
+/*
+ * Midi voice messages
+ */
 
-#define SEQ_STOP_NOTE(dev, voice, note, vol)	{_SEQ_NEEDBUF(8);\
-					_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-					_seqbuf[_seqbufptr+1] = SEQ_NOTEOFF;\
-					_seqbuf[_seqbufptr+2] = (dev);\
-					_seqbuf[_seqbufptr+3] = (voice);\
+#define _CHN_VOICE(dev, event, chn, note, parm) \
+					{_SEQ_NEEDBUF(8);\
+					_seqbuf[_seqbufptr] = EV_CHN_VOICE;\
+					_seqbuf[_seqbufptr+1] = (dev);\
+					_seqbuf[_seqbufptr+2] = (event);\
+					_seqbuf[_seqbufptr+3] = (chn);\
 					_seqbuf[_seqbufptr+4] = (note);\
-					_seqbuf[_seqbufptr+5] = (vol);\
-					_seqbuf[_seqbufptr+6] = 0;\
+					_seqbuf[_seqbufptr+5] = (parm);\
+					_seqbuf[_seqbufptr+6] = (0);\
 					_seqbuf[_seqbufptr+7] = 0;\
 					_SEQ_ADVBUF(8);}
 
-#define SEQ_CHN_PRESSURE(dev, voice, pressure)	{_SEQ_NEEDBUF(8);\
-					_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-					_seqbuf[_seqbufptr+1] = SEQ_AFTERTOUCH;\
-					_seqbuf[_seqbufptr+2] = (dev);\
-					_seqbuf[_seqbufptr+3] = (voice);\
-					_seqbuf[_seqbufptr+4] = (pressure);\
-					_seqbuf[_seqbufptr+5] = 0;\
-					_seqbuf[_seqbufptr+6] = 0;\
-					_seqbuf[_seqbufptr+7] = 0;\
+#define SEQ_START_NOTE(dev, chn, note, vol) \
+		_CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol)
+
+#define SEQ_STOP_NOTE(dev, chn, note, vol) \
+		_CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol)
+
+#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \
+		_CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure)
+
+/*
+ * Midi channel messages
+ */
+
+#define _CHN_COMMON(dev, event, chn, p1, p2, w14) \
+					{_SEQ_NEEDBUF(8);\
+					_seqbuf[_seqbufptr] = EV_CHN_COMMON;\
+					_seqbuf[_seqbufptr+1] = (dev);\
+					_seqbuf[_seqbufptr+2] = (event);\
+					_seqbuf[_seqbufptr+3] = (chn);\
+					_seqbuf[_seqbufptr+4] = (p1);\
+					_seqbuf[_seqbufptr+5] = (p2);\
+					*(short *)&_seqbuf[_seqbufptr+6] = (w14);\
 					_SEQ_ADVBUF(8);}
 
+#define SEQ_CHN_PRESSURE(dev, chn, pressure) \
+		_CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0)
+
+#define SEQ_SET_PATCH(dev, chn, patch) \
+		_CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0)
+
+#define SEQ_CONTROL(dev, chn, controller, value) \
+		_CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value)
+
+#define SEQ_BENDER(dev, chn, value) \
+		_CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
+
+/*
+ * The following 5 macros are incorrectly implemented and obsolete.
+ * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead.
+ */
+#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
+#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
+#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
+#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
+#define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
+#if 0
 #define SEQ_PANNING(dev, voice, pos)	{_SEQ_NEEDBUF(8);\
 					_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
 					_seqbuf[_seqbufptr+1] = SEQ_BALANCE;\
@@ -705,58 +906,50 @@
 					(char)_seqbuf[_seqbufptr+4] = (pos);\
 					_seqbuf[_seqbufptr+5] = 0;\
 					_seqbuf[_seqbufptr+6] = 0;\
-					_seqbuf[_seqbufptr+7] = 0;\
-					_SEQ_ADVBUF(8);}
-
-#define SEQ_CONTROL(dev, voice, controller, value)	{_SEQ_NEEDBUF(8);\
-					_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-					_seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
-					_seqbuf[_seqbufptr+2] = (dev);\
-					_seqbuf[_seqbufptr+3] = (voice);\
-					_seqbuf[_seqbufptr+4] = (controller);\
-					*(short *)&_seqbuf[_seqbufptr+5] = (value);\
-					_seqbuf[_seqbufptr+7] = 0;\
+					_seqbuf[_seqbufptr+7] = 1;\
 					_SEQ_ADVBUF(8);}
+#endif
 
-#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
-#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
-#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_EXPRESSION, value)
-#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_MAIN_VOLUME, value)
+/*
+ * Timing and syncronization macros
+ */
 
-#define SEQ_START_TIMER()		{_SEQ_NEEDBUF(4);\
-					_seqbuf[_seqbufptr] = SEQ_SYNCTIMER;\
-					_seqbuf[_seqbufptr+1] = 0;\
+#define _TIMER_EVENT(ev, parm)		{_SEQ_NEEDBUF(8);\
+				 	_seqbuf[_seqbufptr+0] = EV_TIMING; \
+				 	_seqbuf[_seqbufptr+1] = (ev); \
 					_seqbuf[_seqbufptr+2] = 0;\
 					_seqbuf[_seqbufptr+3] = 0;\
-					_SEQ_ADVBUF(4);}
-#define SEQ_SET_PATCH(dev, voice, patch)	{_SEQ_NEEDBUF(8);\
-					_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-					_seqbuf[_seqbufptr+1] = SEQ_PGMCHANGE;\
-					_seqbuf[_seqbufptr+2] = (dev);\
-					_seqbuf[_seqbufptr+3] = (voice);\
-					_seqbuf[_seqbufptr+4] = (patch);\
-					_seqbuf[_seqbufptr+5] = 0;\
-					_seqbuf[_seqbufptr+6] = 0;\
-					_seqbuf[_seqbufptr+7] = 0;\
+				 	*(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
 					_SEQ_ADVBUF(8);}
 
-#define SEQ_WAIT_TIME(ticks)		{_SEQ_NEEDBUF(4);\
-				 	*(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_WAIT | ((ticks) << 8);\
-				 	_SEQ_ADVBUF(4);}
-
-#define SEQ_ECHO_BACK(key)		{_SEQ_NEEDBUF(4);\
-				 	*(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_ECHO | ((key) << 8);\
-				 	_SEQ_ADVBUF(4);}
+#define SEQ_START_TIMER()		_TIMER_EVENT(TMR_START, 0)
+#define SEQ_STOP_TIMER()		_TIMER_EVENT(TMR_STOP, 0)
+#define SEQ_CONTINUE_TIMER()		_TIMER_EVENT(TMR_CONTINUE, 0)
+#define SEQ_WAIT_TIME(ticks)		_TIMER_EVENT(TMR_WAIT_ABS, ticks)
+#define SEQ_DELTA_TIME(ticks)		_TIMER_EVENT(TMR_WAIT_REL, ticks)
+#define SEQ_ECHO_BACK(key)		_TIMER_EVENT(TMR_ECHO, key)
+#define SEQ_SET_TEMPO(value)		_TIMER_EVENT(TMR_TEMPO, value)
+#define SEQ_SONGPOS(pos)		_TIMER_EVENT(TMR_SPP, pos)
+#define SEQ_TIME_SIGNATURE(sig)		_TIMER_EVENT(TMR_TIMESIG, sig)
 
+/*
+ * Events for the level 1 interface only 
+ */
+
 #define SEQ_MIDIOUT(device, byte)	{_SEQ_NEEDBUF(4);\
 					_seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
 					_seqbuf[_seqbufptr+1] = (byte);\
 					_seqbuf[_seqbufptr+2] = (device);\
 					_seqbuf[_seqbufptr+3] = 0;\
 					_SEQ_ADVBUF(4);}
-#define SEQ_WRPATCH(patchx, len)	{if (_seqbufptr) seqbuf_dump();\
+
+/*
+ * Patch loading.
+ */
+#define SEQ_WRPATCH(patchx, len)		{if (_seqbufptr) seqbuf_dump();\
 					if (write(seqfd, (char*)(patchx), len)==-1) \
 					   perror("Write patch: /dev/sequencer");}
+#define SEQ_WRPATCH2(patchx, len)	(seqbuf_dump(), write(seqfd, (char*)(patchx), len))
 
 #endif
 long soundcard_init(long mem_start);
diff -u --recursive --new-file v1.1.30/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v1.1.30/linux/kernel/ptrace.c	Mon Dec 27 08:54:52 1993
+++ linux/kernel/ptrace.c	Mon Jul 18 12:45:50 1994
@@ -98,7 +98,7 @@
 		page = *((unsigned long *) page);
 	}
 	if (!(page & PAGE_PRESENT)) {
-		do_no_page(0,addr,tsk,0);
+		do_no_page(0,addr,tsk);
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -133,13 +133,13 @@
 		page = *((unsigned long *) page);
 	}
 	if (!(page & PAGE_PRESENT)) {
-		do_no_page(0 /* PAGE_RW */ ,addr,tsk,0);
+		do_no_page(0 /* PAGE_RW */ ,addr,tsk);
 		goto repeat;
 	}
 	if (!(page & PAGE_RW)) {
 		if(!(page & PAGE_COW))
 			readonly = 1;
-		do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0);
+		do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk);
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
diff -u --recursive --new-file v1.1.30/linux/mm/memory.c linux/mm/memory.c
--- v1.1.30/linux/mm/memory.c	Mon Jun 27 16:47:02 1994
+++ linux/mm/memory.c	Mon Jul 18 15:53:55 1994
@@ -561,7 +561,7 @@
  * in better assembly code.. The "default" path will see no jumps at all.
  */
 static void __do_wp_page(unsigned long error_code, unsigned long address,
-	struct task_struct * tsk, unsigned long user_esp)
+	struct task_struct * tsk)
 {
 	unsigned long *pde, pte, old_page, prot;
 	unsigned long new_page;
@@ -626,7 +626,7 @@
  * the low-level function only in that case..
  */
 void do_wp_page(unsigned long error_code, unsigned long address,
-	struct task_struct * tsk, unsigned long user_esp)
+	struct task_struct * tsk)
 {
 	unsigned long page;
 	unsigned long * pg_table;
@@ -643,7 +643,7 @@
 		if (page & PAGE_RW)
 			return;
 		if (!(page & PAGE_COW)) {
-			if (user_esp && tsk == current) {
+			if ((error_code & PAGE_USER) && tsk == current) {
 				current->tss.cr2 = address;
 				current->tss.error_code = error_code;
 				current->tss.trap_no = 14;
@@ -656,7 +656,7 @@
 			invalidate();
 			return;
 		}
-		__do_wp_page(error_code, address, tsk, user_esp);
+		__do_wp_page(error_code, address, tsk);
 		return;
 	}
 	printk("bad page directory entry %08lx\n",page);
@@ -670,7 +670,7 @@
 	size >>= PAGE_SHIFT;
 	start &= PAGE_MASK;
 	do {
-		do_wp_page(1,start,current,0);
+		do_wp_page(1,start,current);
 		start += PAGE_SIZE;
 	} while (size--);
 	return 0;
@@ -733,30 +733,25 @@
  * task.
  *
  * NOTE! This assumes we have checked that p != current, and that they
- * share the same executable or library.
- *
- * We may want to fix this to allow page sharing for PIC pages at different
- * addresses so that ELF will really perform properly. As long as the vast
- * majority of sharable libraries load at fixed addresses this is not a
- * big concern. Any sharing of pages between the buffer cache and the
- * code space reduces the need for this as well.  - ERY
+ * share the same inode and can generally otherwise be shared.
  */
-static int try_to_share(unsigned long address, struct task_struct * tsk,
-	struct task_struct * p, unsigned long error_code, unsigned long newpage)
+static int try_to_share(unsigned long to_address, struct vm_area_struct * to_area,
+	unsigned long from_address, struct vm_area_struct * from_area,
+	unsigned long newpage)
 {
 	unsigned long from;
 	unsigned long to;
 	unsigned long from_page;
 	unsigned long to_page;
 
-	from_page = (unsigned long)PAGE_DIR_OFFSET(p->tss.cr3,address);
-	to_page = (unsigned long)PAGE_DIR_OFFSET(tsk->tss.cr3,address);
+	from_page = (unsigned long)PAGE_DIR_OFFSET(from_area->vm_task->tss.cr3,from_address);
+	to_page = (unsigned long)PAGE_DIR_OFFSET(to_area->vm_task->tss.cr3,to_address);
 /* is there a page-directory at from? */
 	from = *(unsigned long *) from_page;
 	if (!(from & PAGE_PRESENT))
 		return 0;
 	from &= PAGE_MASK;
-	from_page = from + PAGE_PTR(address);
+	from_page = from + PAGE_PTR(from_address);
 	from = *(unsigned long *) from_page;
 /* is the page clean and present? */
 	if ((from & (PAGE_PRESENT | PAGE_DIRTY)) != PAGE_PRESENT)
@@ -770,68 +765,88 @@
 	if (!(to & PAGE_PRESENT))
 		return 0;
 	to &= PAGE_MASK;
-	to_page = to + PAGE_PTR(address);
+	to_page = to + PAGE_PTR(to_address);
 	if (*(unsigned long *) to_page)
 		return 0;
-/* share them if read - do COW immediately otherwise */
-	if (error_code & PAGE_RW) {
-		if(!newpage)	/* did the page exist?  SRB. */
-			return 0;
-		copy_page((from & PAGE_MASK),newpage);
-		to = newpage | PAGE_PRIVATE;
-	} else {
-		mem_map[MAP_NR(from)]++;
-		from &= ~PAGE_RW;
-		to = from;
-		if(newpage)	/* only if it existed. SRB. */
-			free_page(newpage);
-	}
-	*(unsigned long *) from_page = from;
+/* do we copy? */
+	if (newpage) {
+		copy_page((from & PAGE_MASK), newpage);
+		*(unsigned long *) to_page = newpage | to_area->vm_page_prot;
+		return 1;
+	}
+/* just share them.. */
+	mem_map[MAP_NR(from)]++;
+/* fill in the 'to' field, checking for COW-stuff */
+	to = (from & PAGE_MASK) | to_area->vm_page_prot;
+	if (to & PAGE_COW)
+		to &= ~PAGE_RW;
 	*(unsigned long *) to_page = to;
+/* Check if we need to do anything at all to the 'from' field */
+	if (!(from & PAGE_RW))
+		return 1;
+	if (!(from_area->vm_page_prot & PAGE_COW))
+		return 1;
+/* ok, need to mark it read-only, so invalidate aany possible old TB entry */
+	from &= ~PAGE_RW;
+	*(unsigned long *) from_page = from;
 	invalidate();
 	return 1;
 }
 
 /*
  * share_page() tries to find a process that could share a page with
- * the current one. Address is the address of the wanted page relative
- * to the current data space.
+ * the current one.
  *
- * We first check if it is at all feasible by checking executable->i_count.
+ * We first check if it is at all feasible by checking inode->i_count.
  * It should be >1 if there are other tasks sharing this inode.
  */
-int share_page(struct vm_area_struct * area, struct task_struct * tsk,
-	struct inode * inode,
-	unsigned long address, unsigned long error_code, unsigned long newpage)
+static int share_page(struct vm_area_struct * area, unsigned long address,
+	unsigned long error_code, unsigned long newpage)
 {
+	struct inode * inode;
 	struct task_struct ** p;
-
-	if (!inode || inode->i_count < 2 || !area->vm_ops)
-		return 0;
+	unsigned long offset;
+	unsigned long from_address;
+	unsigned long give_page;
+
+	if (!area || !(inode = area->vm_inode) || inode->i_count < 2)
+		return 0;
+	/* do we need to copy or can we just share? */
+	give_page = 0;
+	if ((area->vm_page_prot & PAGE_COW) && (error_code & PAGE_RW)) {
+		if (!newpage)
+			return 0;
+		give_page = newpage;
+	}
+	offset = address - area->vm_start + area->vm_offset;
 	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+		struct vm_area_struct * mpnt;
 		if (!*p)
 			continue;
-		if (tsk == *p)
+		if (area->vm_task == *p)
 			continue;
-		if (inode != (*p)->executable) {
-			  if(!area) continue;
-			/* Now see if there is something in the VMM that
-			   we can share pages with */
-			if(area){
-			  struct vm_area_struct * mpnt;
-			  for (mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
-			    if (mpnt->vm_ops == area->vm_ops &&
-			       mpnt->vm_inode->i_ino == area->vm_inode->i_ino&&
-			       mpnt->vm_inode->i_dev == area->vm_inode->i_dev){
-			      if (mpnt->vm_ops->share(mpnt, area, address))
-				break;
-			    };
-			  };
-			  if (!mpnt) continue;  /* Nope.  Nuthin here */
-			};
-		}
-		if (try_to_share(address,tsk,*p,error_code,newpage))
+		/* Now see if there is something in the VMM that
+		   we can share pages with */
+		for (mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
+			/* must be same inode */
+			if (mpnt->vm_inode != inode)
+				continue;
+			/* offsets must be mutually page-aligned */
+			if ((mpnt->vm_offset ^ area->vm_offset) & ~PAGE_MASK)
+				continue;
+			/* the other area must actually cover the wanted page.. */
+			from_address = offset + mpnt->vm_start - mpnt->vm_offset;
+			if (from_address < mpnt->vm_start || from_address >= mpnt->vm_end)
+				continue;
+			/* .. NOW we can actually try to use the same physical page */
+			if (!try_to_share(address, area, from_address, mpnt, give_page))
+				continue;
+			/* free newpage if we never used it.. */
+			if (give_page || !newpage)
+				return 1;
+			free_page(newpage);
 			return 1;
+		}
 	}
 	return 0;
 }
@@ -870,13 +885,42 @@
 	return 0;
 }
 
-void do_no_page(unsigned long error_code, unsigned long address,
-	struct task_struct *tsk, unsigned long user_esp)
+static void handle_no_page(struct vm_area_struct * vma,
+	unsigned long address, unsigned long error_code)
 {
-	unsigned long tmp;
 	unsigned long page;
-	struct vm_area_struct * mpnt;
+	int prot;
+
+	page = get_free_page(GFP_KERNEL);
+	if (share_page(vma, address, error_code, page)) {
+		++vma->vm_task->mm->min_flt;
+		return;
+	}
+	if (!page) {
+		oom(current);
+		put_page(vma->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
+		return;
+	}
+	++vma->vm_task->mm->maj_flt;
+	++vma->vm_task->mm->rss;
+	page = vma->vm_ops->nopage(vma, address, page, error_code);
+	if (share_page(vma, address, error_code, 0))
+		return;
+	prot = vma->vm_page_prot;
+	if ((prot & PAGE_COW) && mem_map[MAP_NR(page)] > 1)
+		prot &= ~PAGE_RW;
+	if (put_page(vma->vm_task, page, address, prot))
+		return;
+	free_page(page);
+	oom(current);
+}
 
+void do_no_page(unsigned long error_code, unsigned long address,
+	struct task_struct *tsk)
+{
+	unsigned long page, tmp;
+	struct vm_area_struct * vma;
+
 	page = get_empty_pgtable(tsk,address);
 	if (!page)
 		return;
@@ -891,42 +935,43 @@
 		swap_in((unsigned long *) page);
 		return;
 	}
-	address &= 0xfffff000;
-	tmp = 0;
-	for (mpnt = tsk->mm->mmap; mpnt != NULL; mpnt = mpnt->vm_next) {
-		if (address < mpnt->vm_start)
+	address &= PAGE_MASK;
+	for (vma = tsk->mm->mmap ; ; vma = vma->vm_next) {
+		if (!vma)
+			goto bad_area;
+		if (vma->vm_end > address)
 			break;
-		if (address >= mpnt->vm_end) {
-			tmp = mpnt->vm_end;
-			continue;
-		}
-		if (!mpnt->vm_ops || !mpnt->vm_ops->nopage) {
-			++tsk->mm->rss;
-			++tsk->mm->min_flt;
-			get_empty_page(tsk,address);
-			return;
-		}
+	}
+	if (vma->vm_start <= address)
+		goto good_area;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		goto bad_area;
+	if (vma->vm_end - address > tsk->rlim[RLIMIT_STACK].rlim_cur)
+		goto bad_area;
+	vma->vm_offset -= vma->vm_start - address;
+	vma->vm_start = address;
+
+good_area:
+	if (!vma->vm_ops || !vma->vm_ops->nopage) {
 		++tsk->mm->rss;
-		mpnt->vm_ops->nopage(error_code, mpnt, address);
+		++tsk->mm->min_flt;
+		get_empty_page(tsk,address);
 		return;
 	}
+	handle_no_page(vma, address, error_code);
+	return;
+
+bad_area:
 	if (tsk != current)
-		goto ok_no_page;
-	if (address >= tsk->mm->end_data && address < tsk->mm->brk)
-		goto ok_no_page;
-	if (mpnt && (mpnt->vm_flags & VM_GROWSDOWN) &&
-	    address - tmp > mpnt->vm_start - address &&
-	    tsk->rlim[RLIMIT_STACK].rlim_cur > mpnt->vm_end - address) {
-		mpnt->vm_start = address;
-		goto ok_no_page;
-	}
+		goto kernel_needs_bad_page;
 	tsk->tss.cr2 = address;
-	current->tss.error_code = error_code;
-	current->tss.trap_no = 14;
+	tsk->tss.error_code = error_code;
+	tsk->tss.trap_no = 14;
 	send_sig(SIGSEGV,tsk,1);
 	if (error_code & 4)	/* user level access? */
 		return;
-ok_no_page:
+
+kernel_needs_bad_page:
 	++tsk->mm->rss;
 	++tsk->mm->min_flt;
 	get_empty_page(tsk,address);
@@ -940,28 +985,25 @@
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
 	unsigned long address;
-	unsigned long user_esp = 0;
+	unsigned long page;
 	unsigned int bit;
 
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 	if (address < TASK_SIZE) {
-		if (error_code & 4) {	/* user mode access? */
-			if (regs->eflags & VM_MASK) {
-				bit = (address - 0xA0000) >> PAGE_SHIFT;
-				if (bit < 32)
-					current->screen_bitmap |= 1 << bit;
-			} else 
-				user_esp = regs->esp;
+		if (regs->eflags & VM_MASK) {
+			bit = (address - 0xA0000) >> PAGE_SHIFT;
+			if (bit < 32)
+				current->screen_bitmap |= 1 << bit;
 		}
 		if (error_code & PAGE_PRESENT) {
 #ifdef CONFIG_TEST_VERIFY_AREA
 			if (regs->cs == KERNEL_CS)
 				printk("WP fault at %08x\n", regs->eip);
 #endif
-			do_wp_page(error_code, address, current, user_esp);
+			do_wp_page(error_code, address, current);
 		} else {
-			do_no_page(error_code, address, current, user_esp);
+			do_no_page(error_code, address, current);
 		}
 		return;
 	}
@@ -979,16 +1021,16 @@
 		printk(KERN_ALERT "Unable to handle kernel paging request");
 	printk(" at kernel address %08lx\n",address);
 	address += TASK_SIZE;
-	__asm__("movl %%cr3,%0" : "=r" (user_esp));
+	__asm__("movl %%cr3,%0" : "=r" (page));
 	printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
-		current->tss.cr3, user_esp);
-	user_esp = ((unsigned long *) user_esp)[address >> 22];
-	printk(KERN_ALERT "*pde = %08lx\n", user_esp);
-	if (user_esp & PAGE_PRESENT) {
-		user_esp &= PAGE_MASK;
+		current->tss.cr3, page);
+	page = ((unsigned long *) page)[address >> 22];
+	printk(KERN_ALERT "*pde = %08lx\n", page);
+	if (page & PAGE_PRESENT) {
+		page &= PAGE_MASK;
 		address &= 0x003ff000;
-		user_esp = ((unsigned long *) user_esp)[address >> PAGE_SHIFT];
-		printk(KERN_ALERT "*pte = %08lx\n", user_esp);
+		page = ((unsigned long *) page)[address >> PAGE_SHIFT];
+		printk(KERN_ALERT "*pte = %08lx\n", page);
 	}
 	die_if_kernel("Oops", regs, error_code);
 	do_exit(SIGKILL);
@@ -1214,11 +1256,11 @@
 
 
 /* This handles a generic mmap of a disk file */
-void file_mmap_nopage(int error_code, struct vm_area_struct * area, unsigned long address)
+unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
+	unsigned long page, int error_code)
 {
 	struct inode * inode = area->vm_inode;
 	unsigned int block;
-	unsigned long page;
 	int nr[8];
 	int i, j;
 	int prot = area->vm_page_prot;
@@ -1227,32 +1269,11 @@
 	block = address - area->vm_start + area->vm_offset;
 	block >>= inode->i_sb->s_blocksize_bits;
 
-	page = get_free_page(GFP_KERNEL);
-	if (share_page(area, area->vm_task, inode, address, error_code, page)) {
-		++area->vm_task->mm->min_flt;
-		return;
-	}
-
-	++area->vm_task->mm->maj_flt;
-	if (!page) {
-		oom(current);
-		put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
-		return;
-	}
 	for (i=0, j=0; i< PAGE_SIZE ; j++, block++, i += inode->i_sb->s_blocksize)
 		nr[j] = bmap(inode,block);
 	if (error_code & PAGE_RW)
 		prot |= PAGE_RW | PAGE_DIRTY;
-	page = bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, prot);
-
-	if (!(prot & PAGE_RW)) {
-		if (share_page(area, area->vm_task, inode, address, error_code, page))
-			return;
-	}
-	if (put_page(area->vm_task,page,address,prot))
-		return;
-	free_page(page);
-	oom(current);
+	return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, !(error_code & PAGE_RW));
 }
 
 void file_mmap_free(struct vm_area_struct * area)
@@ -1274,16 +1295,6 @@
 		    struct vm_area_struct * area2, 
 		    unsigned long address)
 {
-	if (area1->vm_inode != area2->vm_inode)
-		return 0;
-	if (area1->vm_start != area2->vm_start)
-		return 0;
-	if (area1->vm_end != area2->vm_end)
-		return 0;
-	if (area1->vm_offset != area2->vm_offset)
-		return 0;
-	if (area1->vm_page_prot != area2->vm_page_prot)
-		return 0;
 	return 1;
 }
 
diff -u --recursive --new-file v1.1.30/linux/mm/swap.c linux/mm/swap.c
--- v1.1.30/linux/mm/swap.c	Sat May  7 14:54:17 1994
+++ linux/mm/swap.c	Mon Jul 18 11:37:07 1994
@@ -869,7 +869,7 @@
 
 	val->freeswap = val->totalswap = 0;
 	for (i = 0; i < nr_swapfiles; i++) {
-		if (!(swap_info[i].flags & SWP_USED))
+		if ((swap_info[i].flags & SWP_WRITEOK) != SWP_WRITEOK)
 			continue;
 		for (j = 0; j < swap_info[i].max; ++j)
 			switch (swap_info[i].swap_map[j]) {
