diff -u --new-file --recursive v1.1.9/linux/Makefile linux/Makefile
--- v1.1.9/linux/Makefile	Wed Apr 27 09:46:04 1994
+++ linux/Makefile	Wed Apr 27 09:47:03 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 9
+SUBLEVEL = 10
 
 all:	Version zImage
 
diff -u --new-file --recursive v1.1.9/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v1.1.9/linux/drivers/net/3c509.c	Tue Apr 19 10:53:41 1994
+++ linux/drivers/net/3c509.c	Wed Apr 27 09:16:14 1994
@@ -91,17 +91,20 @@
 	/* First check for a board on the EISA bus. */
 	if (EISA_bus) {
 		for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-			if (inw(ioaddr) != 0x6d50)
+			/* Check the standard EISA ID register for an encoded '3Com'. */
+			if (inw(ioaddr + 0xC80) != 0x6d50)
 				continue;
 
+			/* Change the register set to the configuration window 0. */
+			outw(0x0800, ioaddr + 0xC80 + EL3_CMD);
+
 			irq = inw(ioaddr + 8) >> 12;
 			if_port = inw(ioaddr + 6)>>14;
 			for (i = 0; i < 3; i++)
 				phys_addr[i] = htons(read_eeprom(ioaddr, i));
 
-			/* Restore the "Manufacturer ID" to the EEPROM read register. */
-			/* The manual says to restore "Product ID" (reg. 3). !???! */
-			read_eeprom(ioaddr, 7);
+			/* Restore the "Product ID" to the EEPROM read register. */
+			read_eeprom(ioaddr, 3);
 
 			/* Was the EISA code an add-on hack?  Nahhhhh... */
 			goto found;
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/.blurb linux/drivers/sound/.blurb
--- v1.1.9/linux/drivers/sound/.blurb	Sun Dec 12 21:33:48 1993
+++ linux/drivers/sound/.blurb	Tue Apr 26 09:32:05 1994
@@ -4,9 +4,3 @@
 	other programs using ioctl calls of the driver, they must be
 	recompiled. Most of them will not work without some source
 	modifications.
-
-	******** LINUX VERSION 0.99.14 OR LATER IS REQUIRED *******
-
-	See sound/Readme for more details
-
-		Hannu
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v1.1.9/linux/drivers/sound/CHANGELOG	Fri Jan 21 15:59:46 1994
+++ linux/drivers/sound/CHANGELOG	Tue Apr 26 09:16:43 1994
@@ -1,5 +1,28 @@
-Changelog for version 2.4
--------------------------
+Changelog for version 2.5a
+--------------------------
+
+Since 2.5
+- Minor fix to read from /dev/sequencer
+
+Since 2.5-beta2
+- Some fine tuning to the GUS v3.7 mixer code.
+- Fixed speed limits for the plain SB (1.0 to 2.0).
+
+Since 2.5-beta
+- Fixed OPL-3 detection with SB. Caused problems with PAS16.
+- GUS v3.7 mixer support.
+
+Since 2.4
+- Mixer support for Sound Galaxy NX Pro (define __SGNXPRO__ on your local.h).
+- Fixed truncated sound on /dev/dsp when the device is closed.
+- Linear volume mode for GUS
+- Pitch bends larger than +/- 2 octaves.
+- MIDI recording for SB and SB Pro. (Untested).
+- Some other fixes.
+- SB16 MIDI and DSP drivers only initialized if SB16 actually installed.
+- Implemented better detection for OPL-3. This should be usefull if you
+  have an old SB Pro (the non-OPL-3 one) or a SB 2.0 clone which has a OPL-3.
+- SVR4.2 support by Ian Hartas. Initial ALPHA TEST version (untested).
 
 Since 2.3b
 - Fixed bug which made it impossible to make long recordings to disk.
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v1.1.9/linux/drivers/sound/Makefile	Fri Jan 21 15:59:46 1994
+++ linux/drivers/sound/Makefile	Tue Apr 26 09:37:46 1994
@@ -5,7 +5,7 @@
 #
 #
 
-VERSION		= 2.4
+VERSION		= 2.5a
 TARGET_OS	= linux
 
 .c.s:
@@ -19,7 +19,7 @@
 	 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
+	 sb16_midi.o sound_switch.o ics2101.o
 
 all:	local.h sound.a
 
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v1.1.9/linux/drivers/sound/Readme	Fri Jan 21 15:59:47 1994
+++ linux/drivers/sound/Readme	Tue Apr 26 09:31:48 1994
@@ -1,5 +1,13 @@
-Release notes for the Linux Sound Driver 2.4
---------------------------------------------
+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
@@ -17,17 +25,13 @@
 No support for the ASP chip yet (the ASP chip can be installed but it's
 not used by the driver).
 
-You will need the snd-util-2.4.tar.gz and snd-data-0.1.tar.Z
+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/*.
 
-There is a new version of the tracker program available (tracker-3_19.lzh) but
-I don't know where it is available. The tracker 3.10 has bugs and it don't work
-without some fixes. Look at the README of the snd-util-2.3.
-
 If you are looking for the installation instructions, please
-look at linux/Readme.
+look at $OS/Readme.
 
 This version supports the following soundcards:
 GUS, SoundBlaster, SB Pro, SB16, Pro Audio Spectrum 16 and AdLib.
@@ -36,19 +40,6 @@
 Most of the features of the /dev/sequencer device file are
 available just for GUS owners. 
 
-NOTE!	There are separate driver for CD-ROMS supported by
-	some soundcards. The driver for CDU31A (Fusion 16) is
-	called cdu31a-0.6.diff.z. It will be contained in the
-	Linux version 0.99.12. The driver for the CD-ROM of SB Pro
-	is sbpcd0.4.tar.gz (these were the latest versions when I wrote
-	this). These files should be at least at sunsite.unc.edu.
-	Also the SCSI interface of the PAS16 should be supported by
-	Linux 0.99.13k and later.
-
-	There is also a driver for joystick. Look for file joystick-0.5.tar.gz
-	(sunsite).
-
-
 Compatibility with the earlier versions
 ---------------------------------------
 
@@ -104,58 +95,6 @@
 there is some new fields which must be initialized. Look at the sbiset.c in
 the snd-util-2.0 package for further info.
 
-This version is almost 100% compatible with the alpha test version (1.99.9). The
-difference is in the installation procedure.
-
-Using this driver with other operating systems than Linux
----------------------------------------------------------
-
-This package contains just the Linux version. The version 2.3
-for SCO is available at nic.funet.fi:pub/OS/Linux/ALPHA/sound.
-The version 2.3 doesn't work well with xxxxxBSD. Use the version
-2.3 for them.
-
-/dev/sndstat
-------------
-
-The /dev/sndstat is now available in the SCO and BSD versions also.
-
-This is a new devicefile for debugging purposes. A better place for
-it is in the /proc -directory but I was just too lazy to implement it
-properly. The /dev/sndstat (major 14, minor 6) is a file which returns
-info about the current configuration (see the example below). If you
-send me a error/problem report, please include a printout from this 
-device to your message (cat /dev/sndstat).
-
-Note!	This device file is currently present only in the Linux version
-	of this driver.
-
------- cut here --- cat /dev/sndstat example --------
-Sound Driver:1.99.7 (Fri Jul 9 17:01:47 GMT 1993 root@lucifer.savolai.fi)
-Config options: 0x00000d4b
-
-HW config: 
-Type 4: Gravis Ultrasound  at 0x210 irq 15 drq 6
-Type 3: ProAudioSpectrum  at 0x388 irq 10 drq 3
-Type 2: SoundBlaster  at 0x220 irq 7 drq 1
-Type 1: AdLib  at 0x388 irq 0 drq 0
-
-PCM devices:
-00: Gravis UltraSound
-01: Pro Audio Spectrum
-02: SoundBlaster 2.0
-
-Synth devices:
-00: Gravis UltraSound
-01: Yamaha OPL-3
-
-Midi devices:
-00: Gravis UltraSound
-01: Pro Audio Spectrum
-
-Mixer(s) installed
------- cut here ---- End of Example -----------
-
 Known bugs/limitations
 ----------------------
 
@@ -164,7 +103,6 @@
   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.
-- Midi input doesn't work with SB and SB Pro (SB16 works).
 - 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
@@ -173,9 +111,6 @@
 - 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.
-- There are some problems in midi input with MPU-401 and the SB16 midi
-  (MPU-401 emulation). This makes it impossible to read long sysex dumps
-  using these devices.
 - 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). 
@@ -220,21 +155,28 @@
 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	ISC port
-	Jim Lowe	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		Initial ISC port
+	Jim Lowe		Initial FreeBSD port
 	Anders Baekgaard 	Bughunting and valuable suggestions.
-	Joerg Schubert	SB16 DSP support.
-	Andrew Robinson Improvements to the GUS driver
+	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.
+	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.
 
 Regards,
 
 Hannu Savolainen
-hsavolai@cs.helsinki.fi
+hannu@voxware.pp.fi, Hannu.Savolainen@Helsinki.fi
 
 Snail mail:	Hannu Savolainen
 		Pallaksentie 4 A 2
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux
--- v1.1.9/linux/drivers/sound/Readme.linux	Fri Jan 21 15:59:47 1994
+++ linux/drivers/sound/Readme.linux	Wed Mar 30 14:29:23 1994
@@ -1,4 +1,4 @@
-Sound Driver version 2.4 for Linux
+Sound Driver version 2.5 for Linux
 ----------------------------------
 
 NOTE!	The sound driver is now a part of the Linux kernel distribution.
@@ -174,7 +174,8 @@
 It runs without burning your CPU.
 
 Hannu Savolainen
-hsavolai@cs.helsinki.fi
+Hannu.Savolainen@Helsinki.fi
+(hannu@voxware.pp.fi (april 94 ->))
 
 ----------------- cut here ------------------------------
 #!/bin/sh
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c
--- v1.1.9/linux/drivers/sound/adlib_card.c	Fri Dec 10 00:22:20 1993
+++ linux/drivers/sound/adlib_card.c	Fri Apr 15 11:03:06 1994
@@ -1,10 +1,10 @@
 /*
  * sound/adlib_card.c
- * 
+ *
  * Detection routine for the AdLib card.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v1.1.9/linux/drivers/sound/audio.c	Fri Dec 10 00:22:30 1993
+++ linux/drivers/sound/audio.c	Fri Apr 15 11:03:07 1994
@@ -1,10 +1,10 @@
 /*
  * sound/audio.c
- * 
+ *
  * Device file manager for /dev/audio
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
@@ -38,10 +38,12 @@
 #define OFF		0
 
 static int      wr_buff_no[MAX_DSP_DEV];	/* != -1, if there is a
+
 						 * incomplete output block */
 static int      wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
 
-static int	audio_mode[MAX_DSP_DEV];
+static int      audio_mode[MAX_DSP_DEV];
+
 #define		AM_NONE		0
 #define		AM_WRITE	1
 #define 	AM_READ		2
@@ -52,16 +54,16 @@
 audio_open (int dev, struct fileinfo *file)
 {
   int             ret;
-  int		  bits;
-  int		  dev_type = dev & 0x0f;
-  int		  mode = file->mode & O_ACCMODE;
+  int             bits;
+  int             dev_type = dev & 0x0f;
+  int             mode = file->mode & O_ACCMODE;
 
   dev = dev >> 4;
 
   if (dev_type == SND_DEV_DSP16)
-     bits = 16;
+    bits = 16;
   else
-     bits = 8;
+    bits = 8;
 
   if ((ret = DMAbuf_open (dev, mode)) < 0)
     return ret;
@@ -126,7 +128,7 @@
 {
   int             c, p, l;
   int             err;
-  int		  dev_type = dev & 0x0f;
+  int             dev_type = dev & 0x0f;
 
   dev = dev >> 4;
 
@@ -134,9 +136,9 @@
   c = count;
 
   if (audio_mode[dev] == AM_READ)	/* Direction changed */
-  {
+    {
       wr_buff_no[dev] = -1;
-  }
+    }
 
   audio_mode[dev] = AM_WRITE;
 
@@ -170,19 +172,19 @@
 	}
       else
 	dsp_devs[dev]->copy_from_user (dev,
-			       wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
+			      wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
 
 
       /* Insert local processing here */
 
       if (dev_type == SND_DEV_AUDIO)
-      {
+	{
 #ifdef linux
-      /* This just allows interrupts while the conversion is running */
-         __asm__ ("sti");
+	  /* This just allows interrupts while the conversion is running */
+	  __asm__ ("sti");
 #endif
-         translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
-      }
+	  translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+	}
 
       c -= l;
       p += l;
@@ -207,21 +209,21 @@
   int             c, p, l;
   char           *dmabuf;
   int             buff_no;
-  int		  dev_type = dev & 0x0f;
+  int             dev_type = dev & 0x0f;
 
   dev = dev >> 4;
   p = 0;
   c = count;
 
   if (audio_mode[dev] == AM_WRITE)
-  {
+    {
       if (wr_buff_no[dev] >= 0)
 	{
 	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
 
 	  wr_buff_no[dev] = -1;
 	}
-  }
+    }
 
   audio_mode[dev] = AM_READ;
 
@@ -236,14 +238,14 @@
       /* Insert any local processing here. */
 
       if (dev_type == SND_DEV_AUDIO)
-      {
+	{
 #ifdef linux
-        /* This just allows interrupts while the conversion is running */
-        __asm__ ("sti");
+	  /* This just allows interrupts while the conversion is running */
+	  __asm__ ("sti");
 #endif
 
-        translate_bytes (dsp_ulaw, dmabuf, l);
-      }
+	  translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
+	}
 
       COPY_TO_USER (buf, p, dmabuf, l);
 
@@ -260,7 +262,8 @@
 audio_ioctl (int dev, struct fileinfo *file,
 	     unsigned int cmd, unsigned int arg)
 {
-  int		  dev_type = dev & 0x0f;
+  int             dev_type = dev & 0x0f;
+
   dev = dev >> 4;
 
   switch (cmd)
@@ -292,7 +295,7 @@
 
     default:
       if (dev_type == SND_DEV_AUDIO)
-         return RET_ERROR (EIO);
+	return RET_ERROR (EIO);
 
       return DMAbuf_ioctl (dev, cmd, arg, 0);
     }
@@ -321,14 +324,14 @@
 
 int
 audio_open (int dev, struct fileinfo *file)
-  {
-    return RET_ERROR (ENXIO);
-  }
+{
+  return RET_ERROR (ENXIO);
+}
 
 void
 audio_release (int dev, struct fileinfo *file)
-  {
-  };
+{
+};
 int
 audio_ioctl (int dev, struct fileinfo *file,
 	     unsigned int cmd, unsigned int arg)
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v1.1.9/linux/drivers/sound/configure.c	Tue Dec 14 14:16:48 1993
+++ linux/drivers/sound/configure.c	Wed Apr 20 11:49:11 1994
@@ -1,8 +1,8 @@
 /*
- * sound/configure.c	- Configuration program for the Linux Sound Driver
- * 
+ * sound/configure.c  - Configuration program for the Linux Sound Driver
+ *
  * 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
@@ -10,7 +10,7 @@
  * 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
@@ -22,7 +22,7 @@
  * 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 <stdio.h>
@@ -48,12 +48,12 @@
 #define OPT_MIDI_AUTO	8
 #define OPT_MIDI	9
 #define OPT_YM3812_AUTO	10	/* Select this automaticly if user selects
-				 * MIDI or AdLib driver */
+				   * MIDI or AdLib driver */
 #define OPT_YM3812	11	/* Select this if the previous one was not
-				 * selected */
+				   * selected */
 #define OPT_SEQUENCER	12
 #define OPT_CHIP_MIDI   13	/* New support added at UW - Milwauklee UW -
-				 * Milwauklee */
+				   * Milwauklee */
 #define OPT_LAST	12
 
 #define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)|B(OPT_MPU401))
@@ -65,7 +65,7 @@
     char            macro[20];
     int             verify;
     int             alias;
-    int		    default_answ;
+    int             default_answ;
   }
 
 hw_entry;
@@ -77,11 +77,11 @@
  * second field is a set of options which are not allowed with this one. If
  * the fourth field is zero, the option is selected without asking
  * confirmation from the user.
- * 
+ *
  * With this version of the rule table it is possible to select just one type of
  * hardware.
- * 
- * NOTE!	Keep the following table and the questions array in sync with the
+ *
+ * NOTE!        Keep the following table and the questions array in sync with the
  * option numbering!
  */
 
@@ -127,7 +127,7 @@
 };
 
 unsigned long   selected_options = 0;
-int sb_dma = 0;
+int             sb_dma = 0;
 
 int
 can_select_option (int nr)
@@ -272,11 +272,11 @@
 		}
 	      else
 		{
-		  int def_answ = hw_table[i].default_answ;
+		  int             def_answ = hw_table[i].default_answ;
 
-		  fprintf (stderr, 
-		     def_answ ? "  %s (y/n) ? " : "  %s (n/y) ? ", 
-		     questions[i]);
+		  fprintf (stderr,
+			   def_answ ? "  %s (y/n) ? " : "  %s (n/y) ? ",
+			   questions[i]);
 		  if (think_positively (def_answ))
 		    if (hw_table[i].alias)
 		      selected_options |= B (hw_table[i].alias);
@@ -286,8 +286,8 @@
 	  }
     }
 
-  if (selected_options & B(OPT_SB16))
-     selected_options |= B(OPT_SBPRO);
+  if (selected_options & B (OPT_SB16))
+    selected_options |= B (OPT_SBPRO);
 
   if (!(selected_options & ANY_DEVS))
     {
@@ -319,8 +319,9 @@
   if (selected_options & B (OPT_SB) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
     {
       fprintf (stderr, "\nIRQ number for SoundBlaster?\n"
-	       "The IRQ adress is defined by the jumpers on your card and\n"
-	       "7 is the factory default. Valid values are 9, 5, 7 and 10.\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"
 	       "Enter the value: ");
 
       num = ask_value ("%d", 7);
@@ -331,9 +332,10 @@
 	  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))
+      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS)))
 	{
 
 	  fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
@@ -359,7 +361,7 @@
 	{
 
 	  fprintf (stderr, "\n16 bit DMA channel for SoundBlaster 16?\n"
-	  	   "Possible values are 5, 6 or 7\n"
+		   "Possible values are 5, 6 or 7\n"
 		   "The default value is 6\n"
 		   "Enter the value: ");
 
@@ -373,14 +375,14 @@
 	  fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
 	  printf ("#define SB16_DMA %d\n", num);
 
-          fprintf (stderr, "\nI/O base for SB16 Midi?\n"
-	       "Possible values are 300 and 330\n"
-	       "The factory default is 330\n"
-	       "Enter the SB16 Midi I/O base: ");
-
-          num = ask_value ("%x", 0x330);
-          fprintf (stderr, "SB16 Midi I/O base set to %03x\n", num);
-          printf ("#define SB16MIDI_BASE 0x%03x\n", num);
+	  fprintf (stderr, "\nI/O base for SB16 Midi?\n"
+		   "Possible values are 300 and 330\n"
+		   "The factory default is 330\n"
+		   "Enter the SB16 Midi I/O base: ");
+
+	  num = ask_value ("%x", 0x330);
+	  fprintf (stderr, "SB16 Midi I/O base set to %03x\n", num);
+	  printf ("#define SB16MIDI_BASE 0x%03x\n", num);
 	}
     }
 
@@ -428,7 +430,7 @@
   if (selected_options & B (OPT_GUS))
     {
       fprintf (stderr, "\nI/O base for Gravis Ultrasound?\n"
-	       "Valid choises are 210, 220, 230, 240, 250 or 260\n"
+	       "Valid choices are 210, 220, 230, 240, 250 or 260\n"
 	       "The factory default is 220\n"
 	       "Enter the GUS I/O base: ");
 
@@ -515,12 +517,12 @@
     {
       def_size = 16384;
 
-      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B(OPT_SB16)))
+      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_SB16)))
 	def_size = 32768;
 
 #ifndef __386BSD__
-      if (((selected_options & B (OPT_PAS)) || (selected_options & B (OPT_SB16))) && 
-          !full_driver)
+      if (((selected_options & B (OPT_PAS)) || (selected_options & B (OPT_SB16))) &&
+	  !full_driver)
 	def_size = 65536;	/* PAS16 or SB16 */
 #endif
 
@@ -543,7 +545,7 @@
   fprintf (stderr, "The sound driver is now configured.\n");
 
 #if defined(SCO) || defined(ISC) || defined(SYSV)
-	fprintf(stderr, "Rember to update the System file\n");
+  fprintf (stderr, "Remember to update the System file\n");
 #endif
 
   exit (0);
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- v1.1.9/linux/drivers/sound/dev_table.c	Tue Dec 14 18:41:32 1993
+++ linux/drivers/sound/dev_table.c	Fri Apr 15 11:03:09 1994
@@ -1,10 +1,10 @@
 /*
  * sound/dev_table.c
- * 
+ *
  * Device call tables.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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 _DEV_TABLE_C_
@@ -39,23 +39,23 @@
 
   for (i = 0; i < (n - 1); i++)
     if (supported_drivers[i].enabled)
-    if (supported_drivers[i].probe (&supported_drivers[i].config))
-      {
+      if (supported_drivers[i].probe (&supported_drivers[i].config))
+	{
 #ifndef SHORT_BANNERS
-	printk ("snd%d",
-		supported_drivers[i].card_type);
+	  printk ("snd%d",
+		  supported_drivers[i].card_type);
 #endif
 
-	mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
+	  mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[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);
+	  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);
 #endif
-      }
-    else
-      supported_drivers[i].enabled=0;	/* Mark as not detected */
+	}
+      else
+	supported_drivers[i].enabled = 0;	/* Mark as not detected */
   return mem_start;
 }
 
@@ -69,14 +69,15 @@
 
   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;
-    }
+	if (supported_drivers[i].probe (hw_config))
+	  return 1;
+	supported_drivers[i].enabled = 0;	/* Mark as not detected */
+	return 0;
+      }
 
   return FALSE;
 }
@@ -115,91 +116,102 @@
 }
 
 #ifdef linux
-void sound_setup(char *str, int *ints)
+void
+sound_setup (char *str, int *ints)
 {
   int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
 
-/*
+  /*
  * First disable all drivers
  */
 
-	for (i=0;i<n;i++)
-		supported_drivers[i].enabled = 0;
+  for (i = 0; i < n; i++)
+    supported_drivers[i].enabled = 0;
 
-	if (ints[0] == 0 || ints[1] == 0) return;
-/*
+  if (ints[0] == 0 || ints[1] == 0)
+    return;
+  /*
  * Then enable them one by time
  */
 
- 	for (i=1;i<=ints[0];i++)
- 	{
- 		int card_type, ioaddr, irq, dma, ptr, j;
- 		unsigned int val;
-
-		val = (unsigned int)ints[i];
-
-		card_type = (val & 0x0ff00000) >> 20;
-
-		if (card_type > 127)
-		{
-			/* Add any future extensions here*/
-			return;
-		}
-
-		ioaddr	  = (val & 0x000fff00) >> 8;
-		irq	  = (val & 0x000000f0) >> 4;
-		dma 	  = (val & 0x0000000f);
-
-		ptr = -1;
-		for (j=0;j<n && ptr == -1;j++)
-		if (supported_drivers[j].card_type == card_type)
-			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;
-	 	}
- 	}
+  for (i = 1; i <= ints[0]; i++)
+    {
+      int             card_type, ioaddr, irq, dma, ptr, j;
+      unsigned int    val;
+
+      val = (unsigned int) ints[i];
+
+      card_type = (val & 0x0ff00000) >> 20;
+
+      if (card_type > 127)
+	{
+	  /* Add any future extensions here */
+	  return;
+	}
+
+      ioaddr = (val & 0x000fff00) >> 8;
+      irq = (val & 0x000000f0) >> 4;
+      dma = (val & 0x0000000f);
+
+      ptr = -1;
+      for (j = 0; j < n && ptr == -1; j++)
+	if (supported_drivers[j].card_type == card_type)
+	  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;
+	}
+    }
 }
+
 #else
-void sound_chconf(int card_type, int ioaddr, int irq, int dma)
+void
+sound_chconf (int card_type, int ioaddr, int irq, int dma)
 {
   int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
 
- 		int ptr, j;
+  int             ptr, j;
+
+  ptr = -1;
+  for (j = 0; j < n && ptr == -1; j++)
+    if (supported_drivers[j].card_type == card_type)
+      ptr = j;
 
-		ptr = -1;
-		for (j=0;j<n && ptr == -1;j++)
-		if (supported_drivers[j].card_type == card_type)
-			ptr = j;
-
-	 	if (ptr != -1)
-	 	{
-	 		supported_drivers[ptr].enabled = 1;
-	 		if (ioaddr) supported_drivers[ptr].config.io_base = ioaddr;
-	 		if (irq) supported_drivers[ptr].config.irq = irq;
-	 		if (dma) supported_drivers[ptr].config.dma = dma;
-	 	}
+  if (ptr != -1)
+    {
+      supported_drivers[ptr].enabled = 1;
+      if (ioaddr)
+	supported_drivers[ptr].config.io_base = ioaddr;
+      if (irq)
+	supported_drivers[ptr].config.irq = irq;
+      if (dma)
+	supported_drivers[ptr].config.dma = dma;
+    }
 }
+
 #endif
 
-struct address_info *sound_getconf(int card_type)
+struct address_info *
+sound_getconf (int card_type)
 {
-	int j, ptr;
-        int n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             j, ptr;
+  int             n = sizeof (supported_drivers) / sizeof (struct card_info);
 
-	ptr = -1;
-	for (j=0;j<n && ptr == -1;j++)
-	if (supported_drivers[j].card_type == card_type)
-		ptr = j;
+  ptr = -1;
+  for (j = 0; j < n && ptr == -1; j++)
+    if (supported_drivers[j].card_type == card_type)
+      ptr = j;
 
- 	if (ptr == -1) return (struct address_info *)NULL;
+  if (ptr == -1)
+    return (struct address_info *) NULL;
 
-	return &supported_drivers[ptr].config;
+  return &supported_drivers[ptr].config;
 }
+
 #endif
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v1.1.9/linux/drivers/sound/dev_table.h	Fri Jan 21 15:59:47 1994
+++ linux/drivers/sound/dev_table.h	Wed Apr  6 13:13:39 1994
@@ -58,6 +58,9 @@
 
 struct audio_operations {
         char name[32];
+	int flags;
+#define NOTHING_SPECIAL 	0
+#define NEEDS_RESTART		1
 	int (*open) (int dev, int mode);
 	void (*close) (int dev);
 	void (*output_block) (int dev, unsigned long buf, 
@@ -96,6 +99,7 @@
 	void (*aftertouch) (int dev, int voice, int pressure);
 	void (*controller) (int dev, int voice, int ctrl_num, int value);
 	void (*panning) (int dev, int voice, int value);
+	void (*volume_method) (int dev, int mode);
 	int (*pmgr_interface) (int dev, struct patmgr_info *info);
 };
 
@@ -177,7 +181,7 @@
 			{SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
 #ifndef EXCLUDE_AUDIO
 		{SNDCARD_SB16,	"SoundBlaster16",	sb16_dsp_init, sb16_dsp_detect,
 			{SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v1.1.9/linux/drivers/sound/dmabuf.c	Fri Jan 21 15:59:47 1994
+++ linux/drivers/sound/dmabuf.c	Fri Apr 15 11:03:10 1994
@@ -1,10 +1,10 @@
 /*
  * sound/dmabuf.c
- * 
+ *
  * The DMA buffer manager for digitized voice applications
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
@@ -88,12 +88,14 @@
  */
 
 static int      dev_nbufs[MAX_DSP_DEV];	/* # of logical buffers ( >=
-					 * sound_buffcounts[dev] */
+
+						   * 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}};
+{
+  {NULL}};
 static int      dev_buffsize[MAX_DSP_DEV];
 
 static void
@@ -103,8 +105,8 @@
    * This routine breaks the physical device buffers to logical ones.
    */
 
-  unsigned i, p, n;
-  unsigned sr, nc, sz, bsz;
+  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);
@@ -135,14 +137,15 @@
     bsz >>= 1;			/* Need at least 2 buffers */
 
   if (dev_subdivision[dev] == 0)
-     dev_subdivision[dev] = 1;	/* Default value */
+    dev_subdivision[dev] = 1;	/* Default value */
 
   bsz /= dev_subdivision[dev];	/* Use smaller buffers */
 
-  if (bsz == 0) bsz = 4096;	/* Just a sanity check */
+  if (bsz == 0)
+    bsz = 4096;			/* Just a sanity check */
 
-  while ((sound_buffsizes[dev]*sound_buffcounts[dev])/bsz > MAX_SUB_BUFFERS)
-  	bsz <<= 1;	/* Too much buffers */
+  while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS)
+    bsz <<= 1;			/* Too much buffers */
 
   dev_buffsize[dev] = bsz;
   n = 0;
@@ -175,7 +178,7 @@
 }
 
 static void
-dma_init_buffers(int dev)
+dma_init_buffers (int dev)
 {
   RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
   dev_underrun[dev] = 0;
@@ -210,7 +213,7 @@
     }
 
 #ifdef USE_RUNTIME_DMAMEM
-  sound_dma_malloc(dev);
+  sound_dma_malloc (dev);
 #endif
 
   if (snd_raw_buf[dev][0] == NULL)
@@ -222,7 +225,7 @@
   dev_modes[dev] = mode;
   dev_subdivision[dev] = 0;
 
-  dma_init_buffers(dev);
+  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);
@@ -233,42 +236,37 @@
 static void
 dma_reset (int dev)
 {
-  int retval;
-  unsigned long flags;
+  int             retval;
+  unsigned long   flags;
 
-  DISABLE_INTR(flags);
+  DISABLE_INTR (flags);
   dsp_devs[dev]->reset (dev);
   dsp_devs[dev]->close (dev);
 
   if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0)
-    printk("Sound: Reset failed - Can't reopen device\n");
-  RESTORE_INTR(flags);
+    printk ("Sound: Reset failed - Can't reopen device\n");
+  RESTORE_INTR (flags);
 
-  dma_init_buffers(dev);
-  reorganize_buffers(dev);
+  dma_init_buffers (dev);
+  reorganize_buffers (dev);
 }
 
 static int
 dma_sync (int dev)
 {
   unsigned long   flags;
-  unsigned long   time;
-  int             timed_out;
 
   if (dma_mode[dev] == DMODE_OUTPUT)
     {
       DISABLE_INTR (flags);
 
-      timed_out = 0;
-      time = GET_TIME ();
-
       while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
-		dmabuf_interrupted[dev]) && !timed_out)
+		dmabuf_interrupted[dev]))
 	     && dev_qlen[dev])
 	{
 	  DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
-	  if ((GET_TIME () - time) > (10 * HZ))
-	    timed_out = 1;
+	  if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
+	    return dev_qlen[dev];
 	}
       RESTORE_INTR (flags);
 
@@ -304,7 +302,7 @@
     }
 
 #ifdef USE_RUNTIME_DMAMEM
-  sound_dma_free(dev);
+  sound_dma_free (dev);
 #endif
 
   dsp_devs[dev]->reset (dev);
@@ -321,45 +319,45 @@
 DMAbuf_getrdbuffer (int dev, char **buf, int *len)
 {
   unsigned long   flags;
-  int err = EIO;
+  int             err = EIO;
 
   DISABLE_INTR (flags);
   if (!dev_qlen[dev])
     {
       if (dev_needs_restart[dev])
-      {
-	dma_reset(dev);
-	dev_needs_restart[dev] = 0;
-      }
+	{
+	  dma_reset (dev);
+	  dev_needs_restart[dev] = 0;
+	}
 
-  if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */
-  {
-	dma_sync(dev);
-	dma_reset(dev);
-	dma_mode[dev] = DMODE_NONE;
-  }
+      if (dma_mode[dev] == DMODE_OUTPUT)	/* Was output -> direction change */
+	{
+	  dma_sync (dev);
+	  dma_reset (dev);
+	  dma_mode[dev] = DMODE_NONE;
+	}
 
-  if (!bufferalloc_done[dev])
-    reorganize_buffers (dev);
+      if (!bufferalloc_done[dev])
+	reorganize_buffers (dev);
 
-  if (!dma_mode[dev])
-    {
-      int             err;
+      if (!dma_mode[dev])
+	{
+	  int             err;
 
-      if ((err = dsp_devs[dev]->prepare_for_input (dev,
+	  if ((err = dsp_devs[dev]->prepare_for_input (dev,
 				    dev_buffsize[dev], dev_nbufs[dev])) < 0)
-	{
-          RESTORE_INTR (flags);
-	  return err;
- 	}
-      dma_mode[dev] = DMODE_INPUT;
-    }
+	    {
+	      RESTORE_INTR (flags);
+	      return err;
+	    }
+	  dma_mode[dev] = DMODE_INPUT;
+	}
 
       if (!dev_active[dev])
 	{
-	  dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], 
+	  dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
 				      dev_buffsize[dev], 0,
-				      !sound_dma_automode[dev] || 
+				      !sound_dma_automode[dev] ||
 				      !dev_started[dev]);
 	  dev_active[dev] = 1;
 	  dev_started[dev] = 1;
@@ -454,25 +452,27 @@
 
     case SNDCTL_DSP_SUBDIVIDE:
       {
-      	int fact = IOCTL_IN(arg);
-
-      	if (fact == 0)
-      	{
-      	  fact = dev_subdivision[dev];
-      	  if (fact == 0) fact = 1;
-	  return IOCTL_OUT(arg, fact);
-      	}
+	int             fact = IOCTL_IN (arg);
 
-      	if (dev_subdivision[dev] != 0) /* Too late to change */
-      	   return RET_ERROR(EINVAL);
+	if (fact == 0)
+	  {
+	    fact = dev_subdivision[dev];
+	    if (fact == 0)
+	      fact = 1;
+	    return IOCTL_OUT (arg, fact);
+	  }
+
+	if (dev_subdivision[dev] != 0)	/* Too late to change */
+	  return RET_ERROR (EINVAL);
 
-      	if (fact > MAX_REALTIME_FACTOR) return RET_ERROR(EINVAL);
+	if (fact > MAX_REALTIME_FACTOR)
+	  return RET_ERROR (EINVAL);
 
-      	if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact !=16)
-      	   return RET_ERROR(EINVAL);
+	if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+	  return RET_ERROR (EINVAL);
 
-      	dev_subdivision[dev] = fact;
-      	return IOCTL_OUT(arg, fact);
+	dev_subdivision[dev] = fact;
+	return IOCTL_OUT (arg, fact);
       }
       break;
 
@@ -480,6 +480,7 @@
       return dsp_devs[dev]->ioctl (dev, cmd, arg, local);
     }
 
+  /* NOTREACHED */
   return RET_ERROR (EIO);
 }
 
@@ -491,16 +492,15 @@
 
   if (dma_mode[dev] == DMODE_INPUT)	/* Was input -> Direction change */
     {
-	dma_reset(dev);
-	dma_mode[dev] = DMODE_NONE;
+      dma_reset (dev);
+      dma_mode[dev] = DMODE_NONE;
     }
-  else
-   if (dev_needs_restart[dev])	/* Restart buffering */
+  else if (dev_needs_restart[dev])	/* Restart buffering */
     {
-	dma_sync(dev);
-	dma_reset(dev);
+      dma_sync (dev);
+      dma_reset (dev);
     }
-  
+
   dev_needs_restart[dev] = 0;
 
   if (!bufferalloc_done[dev])
@@ -563,17 +563,18 @@
 
   dev_counts[dev][dev_qtail[dev]] = l;
 
-  dev_needs_restart[dev] = (l != dev_buffsize[dev]);
+  dev_needs_restart[dev] = (l != dev_buffsize[dev]) &&
+    (sound_dma_automode[dev] || dsp_devs[dev]->flags & NEEDS_RESTART);
 
   dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
 
   if (!dev_active[dev])
     {
       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; 
+      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;
     }
 
   return 0;
@@ -606,7 +607,7 @@
       set_dma_count (chan, sound_buffsizes[dev]);
       enable_dma (chan);
       RESTORE_INTR (flags);
-#else
+#else /* linux */
 
 #ifdef __386BSD__
       printk ("sound: Invalid DMA mode for device %d\n", dev);
@@ -615,24 +616,24 @@
 		    snd_raw_buf_phys[dev][0],
 		    sound_buffsizes[dev],
 		    chan);
-#else
-#if defined(ISC) || defined(SCO)
+#else /* __386BSD__ */
+#if defined(ISC) || defined(SCO) || defined(SVR42)
 #ifndef DMAMODE_AUTO
       printk ("sound: Invalid DMA mode for device %d\n", dev);
-#endif
+#endif /* DMAMODE_AUTO */
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
 #ifdef DMAMODE_AUTO
 		 | DMAMODE_AUTO
-#endif
+#endif /* DMAMODE_AUTO */
 		 ,
 		 snd_raw_buf_phys[dev][0], count);
       dma_enable (chan);
-#else
-#  error This routine is not valid for this OS.
-#endif
-#endif
+#else /* SYSV */
+#error This routine is not valid for this OS.
+#endif /* SYSV */
+#endif /* __386BSD__ */
 
-#endif
+#endif /* linux */
     }
   else
     {
@@ -645,24 +646,24 @@
       set_dma_count (chan, count);
       enable_dma (chan);
       RESTORE_INTR (flags);
-#else
+#else /* linux */
 #ifdef __386BSD__
       isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
 		    physaddr,
 		    count,
 		    chan);
-#else
+#else /* __386BSD__ */
 
-#if defined(ISC) || defined(SCO)
+#if defined(ISC) || defined(SCO) || defined(SVR42)
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
 		 physaddr, count);
       dma_enable (chan);
-#else
-#  error This routine is not valid for this OS.
-#endif /* !ISC */
-#endif
+#else /* SYSV */
+#error This routine is not valid for this OS.
+#endif /* SYSV */
+#endif /* __386BSD__ */
 
-#endif
+#endif /* linux */
     }
 
   return count;
@@ -702,17 +703,17 @@
 
   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]);
+      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)
+  else if (underrun_flag)
     {
       dev_underrun[dev]++;
       dsp_devs[dev]->halt_xfer (dev);
-      dev_needs_restart[dev] = 1;
+      dev_needs_restart[dev] = (sound_dma_automode[dev] ||
+				dsp_devs[dev]->flags & NEEDS_RESTART);
     }
 
   DISABLE_INTR (flags);
@@ -734,20 +735,20 @@
     }
   else if (dev_qlen[dev] == (dev_nbufs[dev] - 1))
     {
-      printk("Sound: Recording overrun\n");
+      printk ("Sound: Recording overrun\n");
       dev_underrun[dev]++;
       dsp_devs[dev]->halt_xfer (dev);
       dev_active[dev] = 0;
-      dev_needs_restart[dev] = 1;
+      dev_needs_restart[dev] = sound_dma_automode[dev];
     }
   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]], 
+      dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
 				  dev_buffsize[dev], 1,
-	  			  !sound_dma_automode[dev]);
+				  !sound_dma_automode[dev]);
       dev_active[dev] = 1;
     }
 
@@ -798,13 +799,13 @@
 /*
  * The sound_mem_init() is called by mem_init() immediately after mem_map is
  * initialized and before free_page_list is created.
- * 
+ *
  * This routine allocates DMA buffers at the end of available physical memory (
  * <16M) and marks pages reserved at mem_map.
  */
 
 #else
-/* Stub versions if audio services not included	 */
+/* Stub versions if audio services not included  */
 
 int
 DMAbuf_open (int dev, int mode)
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v1.1.9/linux/drivers/sound/gus_card.c	Fri Jan 21 15:59:47 1994
+++ linux/drivers/sound/gus_card.c	Fri Apr 15 11:03:11 1994
@@ -1,10 +1,10 @@
 /*
  * sound/gus_card.c
- * 
+ *
  * Detection routine for the Gravis Ultrasound.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
@@ -106,7 +106,7 @@
   unsigned char   src;
 
 #ifdef linux
-  sti();
+  sti ();
 #endif
 
   while (1)
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/gus_hw.h linux/drivers/sound/gus_hw.h
--- v1.1.9/linux/drivers/sound/gus_hw.h	Mon Jun 21 15:19:09 1993
+++ linux/drivers/sound/gus_hw.h	Fri Apr 15 10:23:47 1994
@@ -24,6 +24,8 @@
 #define u_Command		(gus_base + 0x103)
 #define u_DataLo		(gus_base + 0x104)
 #define u_DataHi		(gus_base + 0x105)
+#define u_MixData               (gus_base + 0x106)   /* Rev. 3.7+ mixing */
+#define u_MixSelect             (gus_base + 0x506)   /* registers.       */
 #define u_IrqStatus		u_Status
 #	define MIDI_TX_IRQ		0x01	/* pending MIDI xmit IRQ */
 #	define MIDI_RX_IRQ		0x02	/* pending MIDI recv IRQ */
@@ -32,4 +34,17 @@
 #	define WAVETABLE_IRQ		0x20	/* pending wavetable IRQ */
 #	define ENVELOPE_IRQ		0x40	/* pending volume envelope IRQ */
 #	define DMA_TC_IRQ		0x80	/* pending dma tc IRQ */
+
+#define ICS2101		1
+#	define ICS_MIXDEVS	6
+#	define DEV_MIC		0
+#	define DEV_LINE		1
+#	define DEV_CD		2
+#	define DEV_GF1		3
+#	define DEV_UNUSED	4
+#	define DEV_VOL		5
+
+#	define CHN_LEFT		0
+#	define CHN_RIGHT	1
+#define CS4231		2
 #define u_DRAMIO		(gus_base + 0x107)
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/gus_linearvol.h linux/drivers/sound/gus_linearvol.h
--- v1.1.9/linux/drivers/sound/gus_linearvol.h
+++ linux/drivers/sound/gus_linearvol.h	Wed Mar 23 13:12:19 1994
@@ -0,0 +1,18 @@
+static unsigned short gus_linearvol[128] = {
+ 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
+ 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
+ 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
+ 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
+ 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
+ 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
+ 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
+ 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
+ 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
+ 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
+ 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
+ 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
+ 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
+ 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
+ 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
+ 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
+};
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c
--- v1.1.9/linux/drivers/sound/gus_midi.c	Fri Dec 10 00:23:12 1993
+++ linux/drivers/sound/gus_midi.c	Fri Apr 15 11:03:11 1994
@@ -1,10 +1,10 @@
 /*
  * sound/gus2_midi.c
- * 
+ *
  * The low level driver for the GUS Midi Interface.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c
--- v1.1.9/linux/drivers/sound/gus_vol.c	Fri Jan 21 15:59:48 1994
+++ linux/drivers/sound/gus_vol.c	Tue Apr 19 12:08:33 1994
@@ -1,17 +1,18 @@
-/* 
+/*
  * gus_vol.c - Compute volume for GUS.
- * 
+ *
  * Greg Lee 1993.
  */
 #include "sound_config.h"
 #ifndef EXCLUDE_GUS
+#include "gus_linearvol.h"
 
 #define GUS_VOLUME	gus_wave_volume
 
 
 extern int      gus_wave_volume;
 
-/* 
+/*
  * Calculate gus volume from note velocity, main volume, expression, and
  * intrinsic patch volume given in patch library.  Expression is multiplied
  * in, so it emphasizes differences in note velocity, while main volume is
@@ -20,7 +21,7 @@
  * to expression controller messages, if they were found to be used for
  * dynamic volume adjustments, so here, main volume can be assumed to be
  * constant throughout a song.)
- * 
+ *
  * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
  * we can give a big boost to very weak voices like nylon guitar and the
  * basses.  The normal value is 64.  Strings are assigned lower values.
@@ -31,27 +32,27 @@
   int             i, m, n, x;
 
 
-  /* 
+  /*
    * A voice volume of 64 is considered neutral, so adjust the main volume if
    * something other than this neutral value was assigned in the patch
    * library.
    */
   x = 256 + 6 * (voicev - 64);
 
-  /* 
-   * Boost expression by voice volume above neutral. 
+  /*
+   * Boost expression by voice volume above neutral.
    */
   if (voicev > 65)
     xpn += voicev - 64;
   xpn += (voicev - 64) / 2;
 
-  /* 
-   * Combine multiplicative and level components. 
+  /*
+   * Combine multiplicative and level components.
    */
   x = vel * xpn * 6 + (voicev / 4) * x;
 
 #ifdef GUS_VOLUME
-  /* 
+  /*
    * Further adjustment by installation-specific master volume control
    * (default 60).
    */
@@ -63,8 +64,8 @@
    * Experimental support for the channel main volume
    */
 
-   mainv = (mainv / 2) + 64;  /* Scale to 64 to 127 */
-   x = (x * mainv * mainv) / 16384;
+  mainv = (mainv / 2) + 64;	/* Scale to 64 to 127 */
+  x = (x * mainv * mainv) / 16384;
 #endif
 
   if (x < 2)
@@ -72,7 +73,7 @@
   else if (x >= 65535)
     return ((15 << 8) | 255);
 
-  /* 
+  /*
    * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
    * mantissa m.
    */
@@ -89,14 +90,14 @@
 	n >>= 1;
 	i++;
       }
-  /* 
+  /*
    * Mantissa is part of linear volume not expressed in exponent.  (This is
    * not quite like real logs -- I wonder if it's right.)
    */
   m = x - (1 << i);
 
-  /* 
-   * Adjust mantissa to 8 bits. 
+  /*
+   * Adjust mantissa to 8 bits.
    */
   if (m > 0)
     {
@@ -107,6 +108,40 @@
     }
 
   return ((i << 8) + m);
+}
+
+/*
+ * Volume-values are interpreted as linear values. Volume is based on the
+ * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
+ * and the volume set by the mixer-device (default 60%).
+ */
+
+unsigned short
+gus_linear_vol (int vol, int mainvol)
+{
+  int             mixer_mainvol;
+
+  if (vol <= 0)
+    vol = 0;
+  else if (vol >= 127)
+    vol = 127;
+
+#ifdef GUS_VOLUME
+  mixer_mainvol = GUS_VOLUME;
+#else
+  mixer_mainvol = 100;
+#endif
+
+#ifdef GUS_USE_CHN_MAIN_VOLUME
+  if (mainvol <= 0)
+    mainvol = 0;
+  else if (mainvol >= 127)
+    mainvol = 127;
+#else
+  mainvol = 128;
+#endif
+
+  return gus_linearvol[(((vol * mainvol) / 128) * mixer_mainvol) / 100];
 }
 
 #endif
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v1.1.9/linux/drivers/sound/gus_wave.c	Fri Jan 21 15:59:50 1994
+++ linux/drivers/sound/gus_wave.c	Tue Apr 26 09:35:59 1994
@@ -1,11 +1,10 @@
-
-/* 
+/*
  * sound/gus_wave.c
- * 
+ *
  * Driver for the Gravis UltraSound wave table synth.
- * 
+ *
  * 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
@@ -13,7 +12,7 @@
  * 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
@@ -25,7 +24,7 @@
  * 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"
@@ -61,7 +60,7 @@
     unsigned char   env_rate[6];
     unsigned char   env_offset[6];
 
-    /* 
+    /*
      * Volume computation parameters for gus_adagio_vol()
      */
     int             main_vol, expression_vol, patch_vol;
@@ -84,28 +83,27 @@
 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;
+static int      gus_line_vol = 100, gus_mic_vol = 0;
+static int      gus_recmask = SOUND_MASK_MIC;
+static int      recording_active = 0;
 
-#define VOL_METHOD_ADAGIO	1
 int             gus_wave_volume = 60;
 int             gus_pcm_volume = 80;
 static unsigned char mix_image = 0x00;
 
-/* 
+/*
  * Current version of this driver doesn't allow synth and PCM functions
  * at the same time. The active_device specifies the active driver
  */
 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 the
+					   * second * * * chn   */
 
 static int      gus_sampling_speed;
 static int      gus_sampling_channels;
@@ -113,33 +111,33 @@
 
 DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
 
-/* 
+/*
  * Variables and buffers for PCM output
  */
-#define MAX_PCM_BUFFERS		(32*MAX_REALTIME_FACTOR)	/* 
-								 * * * Don't
-								 * * * change 
-								 * 
+#define MAX_PCM_BUFFERS		(32*MAX_REALTIME_FACTOR)	/*
+								   * * * Don't
+								   * * * change
+								   *
 								 */
 
-static int      pcm_bsize,	/* 
-				 * Current blocksize 
+static int      pcm_bsize,	/*
+				 * Current blocksize
 				 */
-                pcm_nblk,	/* 
-				 * Current # of blocks 
+                pcm_nblk,	/*
+				 * Current # of blocks
 				 */
-                pcm_banksize;	/* 
+                pcm_banksize;	/*
+
 
-				 * 
 				 * *  * * # bytes allocated for channels   */
-static int      pcm_datasize[MAX_PCM_BUFFERS];	/* 
+static int      pcm_datasize[MAX_PCM_BUFFERS];	/*
 
-						 * 
+
 						 * *  * * Actual # of bytes
 						 * in blk  *  */
-static volatile int pcm_head, pcm_tail, pcm_qlen;	/* 
+static volatile int pcm_head, pcm_tail, pcm_qlen;	/*
+
 
-							 * 
 							 * *  * * DRAM queue
 							 *  */
 static volatile int pcm_active;
@@ -154,62 +152,62 @@
 
 static int      freq_div_table[] =
 {
-  44100,			/* 
-				 * 14 
+  44100,			/*
+				 * 14
 				 */
-  41160,			/* 
-				 * 15 
+  41160,			/*
+				 * 15
 				 */
-  38587,			/* 
-				 * 16 
+  38587,			/*
+				 * 16
 				 */
-  36317,			/* 
-				 * 17 
+  36317,			/*
+				 * 17
 				 */
-  34300,			/* 
-				 * 18 
+  34300,			/*
+				 * 18
 				 */
-  32494,			/* 
-				 * 19 
+  32494,			/*
+				 * 19
 				 */
-  30870,			/* 
-				 * 20 
+  30870,			/*
+				 * 20
 				 */
-  29400,			/* 
-				 * 21 
+  29400,			/*
+				 * 21
 				 */
-  28063,			/* 
-				 * 22 
+  28063,			/*
+				 * 22
 				 */
-  26843,			/* 
-				 * 23 
+  26843,			/*
+				 * 23
 				 */
-  25725,			/* 
-				 * 24 
+  25725,			/*
+				 * 24
 				 */
-  24696,			/* 
-				 * 25 
+  24696,			/*
+				 * 25
 				 */
-  23746,			/* 
-				 * 26 
+  23746,			/*
+				 * 26
 				 */
-  22866,			/* 
-				 * 27 
+  22866,			/*
+				 * 27
 				 */
-  22050,			/* 
-				 * 28 
+  22050,			/*
+				 * 28
 				 */
-  21289,			/* 
-				 * 29 
+  21289,			/*
+				 * 29
 				 */
-  20580,			/* 
-				 * 30 
+  20580,			/*
+				 * 30
 				 */
-  19916,			/* 
-				 * 31 
+  19916,			/*
+				 * 31
 				 */
-  19293				/* 
-				 * 32 
+  19293				/*
+				 * 32
 				 */
 };
 
@@ -228,14 +226,15 @@
 static void     gus_poke (long addr, unsigned char data);
 static void     compute_and_set_volume (int voice, int volume, int ramp_time);
 extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
+extern unsigned short gus_linear_vol (int vol, int mainvol);
 static void     compute_volume (int voice, int volume);
 static void     do_volume_irq (int voice);
-static void	set_input_volumes(void);
+static void     set_input_volumes (void);
 
-#define	INSTANT_RAMP		-1	/* 
-					 * * * Dont use ramping   */
-#define FAST_RAMP		0	/* 
-					 * * * Fastest possible ramp   */
+#define	INSTANT_RAMP		-1	/*
+					   * * * Dont use ramping   */
+#define FAST_RAMP		0	/*
+					   * * * Fastest possible ramp   */
 
 static void
 reset_sample_memory (void)
@@ -249,8 +248,8 @@
   for (i = 0; i < 32; i++)
     patch_map[i] = -1;
 
-  gus_poke (0, 0);		/* 
-				 * Put silence here 
+  gus_poke (0, 0);		/*
+				 * Put silence here
 				 */
   gus_poke (1, 0);
 
@@ -386,7 +385,7 @@
 
   if (is16bit)
     {
-      /* 
+      /*
        * Special processing required for 16 bit patches
        */
 
@@ -398,6 +397,10 @@
 
   gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
   gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
+  /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
+  gus_delay ();
+  gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
+  gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
 }
 
 static void
@@ -441,13 +444,13 @@
 {
   unsigned char   mode = (unsigned char) (m & 0xff);
 
-  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));		/* 
-									 * Don't 
-									 * start 
-									 * or 
+  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));	/*
+									 * Don't
+									 * start
+									 * or
 									 * stop
 									 * *
-									 * voice 
+									 * voice
 									 */
   gus_delay ();
   gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
@@ -468,8 +471,8 @@
 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));
 }
@@ -508,13 +511,13 @@
 {
   unsigned char   mode = (unsigned char) (m & 0xff);
 
-  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));		/* 
-									 * Don't 
-									 * start 
-									 * or 
+  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));	/*
+									 * Don't
+									 * start
+									 * or
 									 * stop
 									 * *
-									 * ramping 
+									 * ramping
 									 */
   gus_delay ();
   gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
@@ -548,14 +551,14 @@
   DISABLE_INTR (flags);
   gus_select_voice (voice);
   gus_voice_volume (0);
-  gus_write_addr (0x0a, 0, 0);	/* 
-				 * Set current position to 0 
+  gus_write_addr (0x0a, 0, 0);	/*
+				 * Set current position to 0
 				 */
-  gus_write8 (0x00, 0x03);	/* 
-				 * Voice off 
+  gus_write8 (0x00, 0x03);	/*
+				 * Voice off
 				 */
-  gus_write8 (0x0d, 0x03);	/* 
-				 * Ramping off 
+  gus_write8 (0x0d, 0x03);	/*
+				 * Ramping off
 				 */
   RESTORE_INTR (flags);
 
@@ -588,18 +591,22 @@
 {
   unsigned        vol, prev_vol, phase;
   unsigned char   rate;
+  long int        flags;
 
   if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
     {
+      DISABLE_INTR (flags);
+      gus_select_voice (voice);
       gus_rampoff ();
-      return;			/* 
-				 * Sustain 
+      RESTORE_INTR (flags);
+      return;			/*
+				 * Sustain
 				 */
     }
 
   if (voices[voice].env_phase >= 5)
     {
-      /* 
+      /*
        * Shoot the voice off
        */
 
@@ -608,25 +615,30 @@
     }
 
   prev_vol = voices[voice].current_volume;
-  gus_voice_volume (prev_vol);
   phase = ++voices[voice].env_phase;
-
   compute_volume (voice, voices[voice].midi_volume);
-
   vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
   rate = voices[voice].env_rate[phase];
-  gus_write8 (0x06, rate);	/* 
-				 * Ramping rate 
+
+  DISABLE_INTR (flags);
+  gus_select_voice (voice);
+
+  gus_voice_volume (prev_vol);
+
+
+  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
 					 */
     {
-      step_envelope (voice);	/* 
-				 * Continue with the next phase 
+      RESTORE_INTR (flags);
+      step_envelope (voice);	/*
+				 * Continue with the next phase
 				 */
       return;
     }
@@ -636,8 +648,8 @@
       if (vol >= (4096 - 64))
 	vol = 4096 - 65;
       gus_ramp_range (0, vol);
-      gus_rampon (0x20);	/* 
-				 * Increasing, irq 
+      gus_rampon (0x20);	/*
+				 * Increasing, irq
 				 */
     }
   else
@@ -645,11 +657,12 @@
       if (vol <= 64)
 	vol = 65;
       gus_ramp_range (vol, 4030);
-      gus_rampon (0x60);	/* 
-				 * Decreasing, irq 
+      gus_rampon (0x60);	/*
+				 * Decreasing, irq
 				 */
     }
   voices[voice].current_volume = vol;
+  RESTORE_INTR (flags);
 }
 
 static void
@@ -662,25 +675,26 @@
 }
 
 static void
-start_release (int voice)
+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 ();
+  RESTORE_INTR (flags);
   step_envelope (voice);
 }
 
@@ -688,32 +702,37 @@
 gus_voice_fade (int voice)
 {
   int             instr_no = sample_map[voice], is16bits;
+  long int        flags;
+
+  DISABLE_INTR (flags);
+  gus_select_voice (voice);
 
   if (instr_no < 0 || instr_no > MAX_SAMPLE)
     {
-      gus_write8 (0x00, 0x03);	/* 
-				 * Hard stop 
+      gus_write8 (0x00, 0x03);	/*
+				 * Hard stop
 				 */
+      RESTORE_INTR (flags);
       return;
     }
 
-  is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/* 
+  is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/*
 								 * 8 or 16
 								 * bit
-								 * samples 
+								 * samples
 								 */
 
   if (voices[voice].mode & WAVE_ENVELOPES)
     {
-      start_release (voice);
+      start_release (voice, flags);
       return;
     }
 
-  /* 
+  /*
    * Ramp the volume down but not too quickly.
    */
-  if ((gus_read16 (0x09) >> 4) < 100)	/* 
-					 * Get current volume 
+  if ((gus_read16 (0x09) >> 4) < 100)	/*
+					 * Get current volume
 					 */
     {
       gus_voice_off ();
@@ -724,10 +743,11 @@
 
   gus_ramp_range (65, 4030);
   gus_ramp_rate (2, 4);
-  gus_rampon (0x40 | 0x20);	/* 
-				 * Down, once, irq 
+  gus_rampon (0x40 | 0x20);	/*
+				 * Down, once, irq
 				 */
   voices[voice].volume_irq_mode = VMODE_HALT;
+  RESTORE_INTR (flags);
 }
 
 static void
@@ -742,24 +762,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 (0x41);		/*
+				 * Clear any pending DMA IRQs
 				 */
-  gus_look8 (0x49);		/* 
-				 * Clear any pending sample IRQs 
+  gus_look8 (0x49);		/*
+				 * Clear any pending sample IRQs
 				 */
-  gus_read8 (0x0f);		/* 
-				 * Clear pending IRQs 
+  gus_read8 (0x0f);		/*
+				 * Clear pending IRQs
 				 */
 
 }
@@ -768,7 +788,7 @@
 gus_initialize (void)
 {
   unsigned long   flags;
-  unsigned char   dma_image, irq_image, tmp;
+  register 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};
@@ -778,74 +798,74 @@
 
   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 ();
 
-  /* 
+  /*
    * Clear all interrupts
    */
 
-  gus_write8 (0x41, 0);		/* 
-				 * DMA control 
+  gus_write8 (0x41, 0);		/*
+				 * DMA control
 				 */
-  gus_write8 (0x45, 0);		/* 
-				 * Timer control 
+  gus_write8 (0x45, 0);		/*
+				 * Timer control
 				 */
-  gus_write8 (0x49, 0);		/* 
-				 * Sample 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 (0x41);		/*
+				 * Clear any pending DMA IRQs
 				 */
-  gus_look8 (0x49);		/* 
-				 * Clear any pending sample IRQs 
+  gus_look8 (0x49);		/*
+				 * Clear any pending sample IRQs
 				 */
-  gus_read8 (0x0f);		/* 
-				 * Clear pending 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 (0x41);		/*
+				 * Clear any pending DMA IRQs
 				 */
-  gus_look8 (0x49);		/* 
-				 * Clear any pending sample IRQs 
+  gus_look8 (0x49);		/*
+				 * Clear any pending sample IRQs
 				 */
-  gus_read8 (0x0f);		/* 
-				 * Clear pending 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
    */
 
   OUTB (0x05, gus_base + 0x0f);
 
-  mix_image |= 0x02;		/* 
-				 * Disable line out 
+  mix_image |= 0x02;		/*
+				 * Disable line out
 				 */
   OUTB (mix_image, u_Mixer);
 
@@ -853,11 +873,11 @@
 
   OUTB (0x00, gus_base + 0x0f);
 
-  /* 
+  /*
    * Now set up the DMA and IRQ interface
-   * 
+   *
    * The GUS supports two IRQs and two DMAs.
-   * 
+   *
    * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
    * Adding this support requires significant changes to the dmabuf.c, dsp.c
    * and audio.c also.
@@ -868,79 +888,79 @@
   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");
   dma_image |= tmp;
 
-  /* 
+  /*
    * For some reason the IRQ and DMA addresses must be written twice
    */
 
-  /* 
-   * Doing it first time 
+  /*
+   * Doing it first time
    */
 
-  OUTB (mix_image, u_Mixer);	/* 
-				 * Select DMA control 
+  OUTB (mix_image, u_Mixer);	/*
+				 * Select DMA control
 				 */
-  OUTB (dma_image | 0x80, u_IRQDMAControl);	/* 
-						 * Set DMA address 
+  OUTB (dma_image | 0x80, u_IRQDMAControl);	/*
+						 * Set DMA address
 						 */
 
-  OUTB (mix_image | 0x40, u_Mixer);	/* 
-					 * Select IRQ control 
+  OUTB (mix_image | 0x40, u_Mixer);	/*
+					 * Select IRQ control
 					 */
-  OUTB (irq_image, u_IRQDMAControl);	/* 
-					 * Set IRQ address 
+  OUTB (irq_image, u_IRQDMAControl);	/*
+					 * Set IRQ address
 					 */
 
-  /* 
-   * Doing it second time 
+  /*
+   * Doing it second time
    */
 
-  OUTB (mix_image, u_Mixer);	/* 
-				 * Select DMA control 
+  OUTB (mix_image, u_Mixer);	/*
+				 * Select DMA control
 				 */
-  OUTB (dma_image, u_IRQDMAControl);	/* 
-					 * Set DMA address 
+  OUTB (dma_image, u_IRQDMAControl);	/*
+					 * Set DMA address
 					 */
 
-  OUTB (mix_image | 0x40, u_Mixer);	/* 
-					 * Select IRQ control 
+  OUTB (mix_image | 0x40, u_Mixer);	/*
+					 * Select IRQ control
 					 */
-  OUTB (irq_image, u_IRQDMAControl);	/* 
-					 * Set IRQ address 
+  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 &= ~0x02;		/*
+				 * Enable line out
 				 */
-  mix_image |= 0x08;		/* 
-				 * Enable IRQ 
+  mix_image |= 0x08;		/*
+				 * Enable IRQ
 				 */
-  OUTB (mix_image, u_Mixer);	/* 
-				 * Turn mixer channels on 
+  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);
 }
@@ -1048,13 +1068,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);
@@ -1077,13 +1097,15 @@
 
   DISABLE_INTR (flags);
   if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
-    voices[voice].kill_pending = 1;
+    {
+      voices[voice].kill_pending = 1;
+      RESTORE_INTR (flags);
+    }
   else
     {
-      gus_select_voice (voice);
+      RESTORE_INTR (flags);
       gus_voice_fade (voice);
     }
-  RESTORE_INTR (flags);
 
   return 0;
 }
@@ -1094,16 +1116,16 @@
   short           lo_limit, hi_limit;
   unsigned long   flags;
 
-  return;			/* 
-				 * Currently disabled 
+  return;			/*
+				 * 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)
@@ -1111,8 +1133,8 @@
       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;
@@ -1132,8 +1154,8 @@
     }
   gus_ramp_range (lo_limit, hi_limit);
   gus_ramp_rate (3, 8);
-  gus_rampon (0x58);		/* 
-				 * Bidirectional, Down, Loop 
+  gus_rampon (0x58);		/*
+				 * Bidirectional, Down, Loop
 				 */
   RESTORE_INTR (flags);
 }
@@ -1146,24 +1168,36 @@
 }
 
 static void
+guswave_volume_method (int dev, int mode)
+{
+  if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
+    volume_method = mode;
+}
+
+static void
 compute_volume (int voice, int volume)
 {
   if (volume < 128)
     voices[voice].midi_volume = volume;
 
-    switch (volume_method)
-      {
-      case VOL_METHOD_ADAGIO:
-	voices[voice].initial_volume =
-	  gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
-			  voices[voice].expression_vol,
-			  voices[voice].patch_vol);
-	break;
+  switch (volume_method)
+    {
+    case VOL_METHOD_ADAGIO:
+      voices[voice].initial_volume =
+	gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
+			voices[voice].expression_vol,
+			voices[voice].patch_vol);
+      break;
 
-      default:
-	voices[voice].initial_volume = volume_base +
-	  (voices[voice].midi_volume * volume_scale);
-      }
+    case VOL_METHOD_LINEAR:	/* Totally ignores patch-volume and expression */
+      voices[voice].initial_volume =
+	gus_linear_vol (volume, voices[voice].main_vol);
+      break;
+
+    default:
+      voices[voice].initial_volume = volume_base +
+	(voices[voice].midi_volume * volume_scale);
+    }
 
   if (voices[voice].initial_volume > 4030)
     voices[voice].initial_volume = 4030;
@@ -1175,16 +1209,16 @@
   int             current, target, rate;
   unsigned long   flags;
 
+  compute_volume (voice, volume);
+  voices[voice].current_volume = voices[voice].initial_volume;
+
   DISABLE_INTR (flags);
-/* 
+  /*
  * CAUTION! Interrupts disabled. Enable them before returning
  */
 
   gus_select_voice (voice);
 
-  compute_volume (voice, volume);
-  voices[voice].current_volume = voices[voice].initial_volume;
-
   current = gus_read16 (0x09) >> 4;
   target = voices[voice].initial_volume;
 
@@ -1202,8 +1236,8 @@
     rate = 16;
   gus_ramp_rate (0, rate);
 
-  if ((target - current) / 64 == 0)	/* 
-					 * Too close 
+  if ((target - current) / 64 == 0)	/*
+					 * Too close
 					 */
     {
       gus_rampoff ();
@@ -1217,8 +1251,8 @@
       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
@@ -1227,8 +1261,8 @@
 	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);
@@ -1242,14 +1276,14 @@
 
   DISABLE_INTR (flags);
   gus_select_voice (voice);
-  status = gus_read8 (0x00);	/* 
-				 * Voice status 
+  status = gus_read8 (0x00);	/*
+				 * Voice status
 				 */
   RESTORE_INTR (flags);
 
   if (status & 0x03)
-    return;			/* 
-				 * Voice not started 
+    return;			/*
+				 * Voice not started
 				 */
 
   if (!(voices[voice].mode & WAVE_ENVELOPES))
@@ -1258,19 +1292,19 @@
       return;
     }
 
-  /* 
+  /*
    * Voice is running and has envelopes.
    */
 
   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);
@@ -1282,11 +1316,11 @@
 
   compute_volume (voice, voices[voice].midi_volume);
 
-#if 0				/* 
-				 * * * Is this really required   */
+#if 0				/*
+				   * * * Is this really required   */
   voices[voice].current_volume =
-    gus_read16 (0x09) >> 4;	/* 
-				 * Get current volume 
+    gus_read16 (0x09) >> 4;	/*
+				 * Get current volume
 				 */
 
   voices[voice].env_phase--;
@@ -1309,15 +1343,15 @@
       voices[voice].bender = value;
 
       if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
-        {
-          freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
-          voices[voice].current_freq = freq;
-
-          DISABLE_INTR (flags);
-          gus_select_voice (voice);
-          gus_voice_freq (freq);
-          RESTORE_INTR (flags);
-        }
+	{
+	  freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+	  voices[voice].current_freq = freq;
+
+	  DISABLE_INTR (flags);
+	  gus_select_voice (voice);
+	  gus_voice_freq (freq);
+	  RESTORE_INTR (flags);
+	}
       break;
 
     case CTRL_PITCH_BENDER_RANGE:
@@ -1328,10 +1362,12 @@
       value /= 128;
 #endif
     case CTRL_EXPRESSION:
-      volume_method = VOL_METHOD_ADAGIO;
-      voices[voice].expression_vol = value;
-      if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
-         dynamic_volume_change (voice);
+      if (volume_method == VOL_METHOD_ADAGIO)
+	{
+	  voices[voice].expression_vol = value;
+	  if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+	    dynamic_volume_change (voice);
+	}
       break;
 
 #ifdef FUTURE_VERSION
@@ -1344,14 +1380,13 @@
 #endif
 
     case CTRL_MAIN_VOLUME:
-      volume_method = VOL_METHOD_ADAGIO;
       voices[voice].main_vol = value;
       if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
-         dynamic_volume_change (voice);
+	dynamic_volume_change (voice);
       break;
 
-    default:			/* 
-				 * Ignore 
+    default:			/*
+				 * Ignore
 				 */
       break;
     }
@@ -1396,7 +1431,7 @@
 
   note_freq = note_to_freq (note_num);
 
-  /* 
+  /*
    * Find a sample within a patch so that the note_freq is between low_note
    * and high_note.
    */
@@ -1417,8 +1452,8 @@
       if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
 	sample = samplep;
       else
-	samplep = samples[samplep].key;		/* 
-						 * Follow link 
+	samplep = samples[samplep].key;	/*
+						 * Follow link
 						 */
     }
   if (sample == -1)
@@ -1427,15 +1462,15 @@
   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;	/* 
+  is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;	/*
 								 * 8 or 16
 								 * bit
-								 * samples 
+								 * samples
 								 */
   voices[voice].mode = samples[sample].mode;
   voices[voice].patch_vol = samples[sample].volume;
@@ -1453,8 +1488,8 @@
 
   sample_map[voice] = sample;
 
-  base_note = samples[sample].base_note / 100;	/* 
-						 * To avoid overflows 
+  base_note = samples[sample].base_note / 100;	/*
+						 * To avoid overflows
 						 */
   note_freq /= 100;
 
@@ -1462,7 +1497,7 @@
 
   voices[voice].orig_freq = freq;
 
-  /* 
+  /*
    * Since the pitch bender may have been set before playing the note, we
    * have to calculate the bending now.
    */
@@ -1479,8 +1514,8 @@
 
   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))
@@ -1493,10 +1528,13 @@
 
   DISABLE_INTR (flags);
   gus_select_voice (voice);
-  gus_voice_off ();		/* 
-				 * It may still be running 
+  gus_voice_off ();		/*
+				 * It may still be running
 				 */
   gus_rampoff ();
+
+  RESTORE_INTR (flags);
+
   if (voices[voice].mode & WAVE_ENVELOPES)
     {
       compute_volume (voice, volume);
@@ -1505,6 +1543,9 @@
   else
     compute_and_set_volume (voice, volume, 0);
 
+  DISABLE_INTR (flags);
+  gus_select_voice (voice);
+
   if (samples[sample].mode & WAVE_LOOP_BACK)
     gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
 		    voices[voice].offset_pending, is16bits);	/* Sample
@@ -1515,13 +1556,13 @@
 
   if (samples[sample].mode & WAVE_LOOPING)
     {
-      mode |= 0x08;		/* 
-				 * Looping on 
+      mode |= 0x08;		/*
+				 * Looping on
 				 */
 
       if (samples[sample].mode & WAVE_BIDIR_LOOP)
-	mode |= 0x10;		/* 
-				 * Bidirectional looping on 
+	mode |= 0x10;		/*
+				 * Bidirectional looping on
 				 */
 
       if (samples[sample].mode & WAVE_LOOP_BACK)
@@ -1532,35 +1573,35 @@
 	  mode |= 0x40;
 	}
 
-      gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits);	/* 
-												 * Loop 
-												 * start 
-												 * 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 
+      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits);	/*
+											 * Loop
+											 * end
+											 * location
 											 */
     }
   else
     {
-      mode |= 0x20;		/* 
-				 * Loop irq at the end 
+      mode |= 0x20;		/*
+				 * Loop irq at the end
 				 */
-      voices[voice].loop_irq_mode = LMODE_FINISH;	/* 
+      voices[voice].loop_irq_mode = LMODE_FINISH;	/*
 							 * Ramp it down at
-							 * the * end 
+							 * the * end
 							 */
       voices[voice].loop_irq_parm = 1;
-      gus_write_addr (0x02, sample_ptrs[sample], is16bits);	/* 
-								 * Loop start 
-								 * 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_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, is16bits);	/*
+											 * Loop
+											 * end
+											 * location
 											 */
     }
   gus_voice_freq (freq);
@@ -1571,9 +1612,9 @@
   return 0;
 }
 
-/* 
+/*
  * * New guswave_start_note by Andrew J. Robinson attempts to minimize
- * clicking  * when the note playing on the voice is changed.  It uses volume 
+ * clicking  * when the note playing on the voice is changed.  It uses volume
  * ramping. */
 
 static int
@@ -1589,26 +1630,31 @@
       if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
 	voices[voice].volume_pending = volume;
       else
-	ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+	{
+	  RESTORE_INTR (flags);
+	  ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+	}
     }
   else
     {
-       gus_select_voice (voice);
-       mode = gus_read8 (0x00);
-       if (mode & 0x20)
-         gus_write8 (0x00, mode & 0xdf);    /* No interrupt! */
-
-       voices[voice].offset_pending = 0;
-       voices[voice].kill_pending = 0;
-       voices[voice].volume_irq_mode = 0;
-       voices[voice].loop_irq_mode = 0;
-
-       if (voices[voice].sample_pending >= 0)
-       {
-         guswave_set_instr (voices[voice].dev_pending, voice,
-         voices[voice].sample_pending);
-         voices[voice].sample_pending = -1;
-       }
+      gus_select_voice (voice);
+      mode = gus_read8 (0x00);
+      if (mode & 0x20)
+	gus_write8 (0x00, mode & 0xdf);	/* No interrupt! */
+
+      voices[voice].offset_pending = 0;
+      voices[voice].kill_pending = 0;
+      voices[voice].volume_irq_mode = 0;
+      voices[voice].loop_irq_mode = 0;
+
+      if (voices[voice].sample_pending >= 0)
+	{
+	  RESTORE_INTR (flags);
+	  guswave_set_instr (voices[voice].dev_pending, voice,
+			     voices[voice].sample_pending);
+	  voices[voice].sample_pending = -1;
+	  DISABLE_INTR (flags);
+	}
 
       if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
 	{
@@ -1623,11 +1669,11 @@
 
 	  gus_rampoff ();
 	  gus_ramp_range (2000, 4065);
-	  gus_ramp_rate (0, 63);	/* Fastest possible rate */
+	  gus_ramp_rate (0, 63);/* Fastest possible rate */
 	  gus_rampon (0x20 | 0x40);	/* Ramp down, once, irq */
+	  RESTORE_INTR (flags);
 	}
     }
-  RESTORE_INTR (flags);
   return ret_val;
 }
 
@@ -1685,10 +1731,10 @@
 
   unsigned long   blk_size, blk_end, left, src_offs, target;
 
-  sizeof_patch = (long) &patch.data[0] - (long) &patch;		/* 
+  sizeof_patch = (long) &patch.data[0] - (long) &patch;	/*
 								 * Size of
 								 * the header
-								 * * info 
+								 * * info
 								 */
 
   if (format != GUS_PATCH)
@@ -1711,7 +1757,7 @@
       return RET_ERROR (ENOSPC);
     }
 
-  /* 
+  /*
    * Copy the header from user space but ignore the first bytes which have
    * been transferred already.
    */
@@ -1754,15 +1800,15 @@
 	}
     }
 
-  free_mem_ptr = (free_mem_ptr + 31) & ~31;	/* 
-						 * Alignment 32 bytes 
+  free_mem_ptr = (free_mem_ptr + 31) & ~31;	/*
+						 * Alignment 32 bytes
 						 */
 
 #define GUS_BANK_SIZE (256*1024)
 
   if (patch.mode & WAVE_16_BITS)
     {
-      /* 
+      /*
        * 16 bit samples must fit one 256k bank.
        */
       if (patch.len >= GUS_BANK_SIZE)
@@ -1774,16 +1820,16 @@
       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 =	/*
+					 * Align to 256K*N
 					 */
 	  ((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
 					 */
 	}
     }
@@ -1793,8 +1839,8 @@
 
   sample_ptrs[free_sample] = free_mem_ptr;
 
-  /* 
-   * Tremolo is not possible with envelopes 
+  /*
+   * Tremolo is not possible with envelopes
    */
 
   if (patch.mode & WAVE_ENVELOPES)
@@ -1802,14 +1848,14 @@
 
   memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
 
-  /* 
+  /*
    * Link this_one sample to the list of samples for patch 'instr'.
    */
 
   samples[free_sample].key = patch_table[instr];
   patch_table[instr] = free_sample;
 
-  /* 
+  /*
    * Use DMA to transfer the wave data to the DRAM
    */
 
@@ -1817,22 +1863,22 @@
   src_offs = 0;
   target = free_mem_ptr;
 
-  while (left)			/* 
-				 * Not all moved 
+  while (left)			/*
+				 * Not all moved
 				 */
     {
       blk_size = sound_buffsizes[gus_devnum];
       if (blk_size > left)
 	blk_size = left;
 
-      /* 
+      /*
        * DMA cannot cross 256k bank boundaries. Check for that.
        */
       blk_end = target + blk_size;
 
       if ((target >> 18) != (blk_end >> 18))
-	{			/* 
-				 * Have to split the block 
+	{			/*
+				 * Have to split the block
 				 */
 
 	  blk_end &= ~(256 * 1024 - 1);
@@ -1840,7 +1886,7 @@
 	}
 
 #if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
-      /* 
+      /*
        * For some reason the DMA is not possible. We have to use PIO.
        */
       {
@@ -1853,20 +1899,20 @@
 	    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;
 	unsigned long   flags;
 
-	/* 
+	/*
 	 * OK, move now. First in and then out.
 	 */
 
@@ -1875,13 +1921,13 @@
 			blk_size);
 
 	DISABLE_INTR (flags);	/******** INTERRUPTS DISABLED NOW ********/
-	gus_write8 (0x41, 0);	/* 
-				 * Disable GF1 DMA 
+	gus_write8 (0x41, 0);	/*
+				 * Disable GF1 DMA
 				 */
 	DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0],
 			  blk_size, DMA_MODE_WRITE);
 
-	/* 
+	/*
 	 * Set the DRAM address for the wave data
 	 */
 
@@ -1895,35 +1941,35 @@
 	    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_ 
+	  dma_command |= 0x40;	/*
+				 * 16 bit _DATA_
 				 */
 	if (sound_dsp_dmachan[gus_devnum] > 3)
-	  dma_command |= 0x04;	/* 
-				 * 16 bit DMA channel 
+	  dma_command |= 0x04;	/*
+				 * 16 bit DMA channel
 				 */
 
-	gus_write8 (0x41, dma_command);		/* 
-						 * Let's go luteet (=bugs) 
+	gus_write8 (0x41, dma_command);	/*
+						 * Let's go luteet (=bugs)
 						 */
 
-	/* 
+	/*
 	 * Sleep here until the DRAM DMA done interrupt is served
 	 */
 	active_device = GUS_DEV_WAVE;
@@ -1933,10 +1979,10 @@
 	  printk ("GUS: DMA Transfer timed out\n");
 	RESTORE_INTR (flags);
       }
-#endif /* 
-        * * * GUS_NO_DMA   */
+#endif /*
+          * * * GUS_NO_DMA   */
 
-      /* 
+      /*
        * Now the next part
        */
 
@@ -1944,8 +1990,8 @@
       src_offs += blk_size;
       target += blk_size;
 
-      gus_write8 (0x41, 0);	/* 
-				 * Stop DMA 
+      gus_write8 (0x41, 0);	/*
+				 * Stop DMA
 				 */
     }
 
@@ -1991,8 +2037,8 @@
     case _GUS_VOICEON:
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;		/* 
-				 * Disable intr 
+      p1 &= ~0x20;		/*
+				 * Disable intr
 				 */
       gus_voice_on (p1);
       RESTORE_INTR (flags);
@@ -2006,17 +2052,14 @@
       break;
 
     case _GUS_VOICEFADE:
-      DISABLE_INTR (flags);
-      gus_select_voice (voice);
       gus_voice_fade (voice);
-      RESTORE_INTR (flags);
       break;
 
     case _GUS_VOICEMODE:
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;		/* 
-				 * Disable intr 
+      p1 &= ~0x20;		/*
+				 * Disable intr
 				 */
       gus_voice_mode (p1);
       RESTORE_INTR (flags);
@@ -2043,8 +2086,8 @@
       RESTORE_INTR (flags);
       break;
 
-    case _GUS_VOICEVOL2:	/* 
-				 * Just update the voice value 
+    case _GUS_VOICEVOL2:	/*
+				 * Just update the voice value
 				 */
       voices[voice].initial_volume =
 	voices[voice].current_volume = p1;
@@ -2052,8 +2095,8 @@
 
     case _GUS_RAMPRANGE:
       if (voices[voice].mode & WAVE_ENVELOPES)
-	break;			/* 
-				 * NO-NO 
+	break;			/*
+				 * NO-NO
 				 */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
@@ -2063,8 +2106,8 @@
 
     case _GUS_RAMPRATE:
       if (voices[voice].mode & WAVE_ENVELOPES)
-	break;			/* 
-				 * NO-NO 
+	break;			/*
+				 * NO-NO
 				 */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
@@ -2074,13 +2117,13 @@
 
     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;		/*
+				 * Disable intr
 				 */
       gus_ramp_mode (p1);
       RESTORE_INTR (flags);
@@ -2088,13 +2131,13 @@
 
     case _GUS_RAMPON:
       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;		/*
+				 * Disable intr
 				 */
       gus_rampon (p1);
       RESTORE_INTR (flags);
@@ -2102,8 +2145,8 @@
 
     case _GUS_RAMPOFF:
       if (voices[voice].mode & WAVE_ENVELOPES)
-	break;			/* 
-				 * NO-NO 
+	break;			/*
+				 * NO-NO
 				 */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
@@ -2212,8 +2255,8 @@
 	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 YET IMPLEMENTED
 					 */
       return IOCTL_OUT (arg, RET_ERROR (EINVAL));
       break;
@@ -2255,11 +2298,11 @@
 
   pcm_active = 0;
   pcm_opened = 1;
-  if (mode & OPEN_READ) 
-  {
-     recording_active = 1;
-     set_input_volumes();
-  }
+  if (mode & OPEN_READ)
+    {
+      recording_active = 1;
+      set_input_volumes ();
+    }
 
   return 0;
 }
@@ -2273,7 +2316,7 @@
   active_device = 0;
 
   if (recording_active)
-     set_input_volumes();
+    set_input_volumes ();
 
   recording_active = 0;
 }
@@ -2313,14 +2356,14 @@
   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;
 	}
@@ -2328,8 +2371,8 @@
       if (gus_sampling_bits != 8)
 	{
 	  is16bits = 1;
-	  mode[chn] |= 0x04;	/* 
-				 * 16 bit data 
+	  mode[chn] |= 0x04;	/*
+				 * 16 bit data
 				 */
 	}
       else
@@ -2338,22 +2381,22 @@
       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 of the DRAM buffers
 					 */
 	{
-	  mode[chn] |= 0x08;	/* 
-				 * Enable loop 
+	  mode[chn] |= 0x08;	/*
+				 * Enable loop
 				 */
-	  ramp_mode[chn] = 0x03;	/* 
-					 * Disable rollover 
+	  ramp_mode[chn] = 0x03;/*
+					 * Disable rollover
 					 */
 	}
       else
 	{
 	  if (chn == 0)
-	    ramp_mode[chn] = 0x04;	/* 
-					 * Enable rollover bit 
+	    ramp_mode[chn] = 0x04;	/*
+					 * Enable rollover bit
 					 */
 	}
 
@@ -2362,89 +2405,89 @@
       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)		/*
+				 * Voice not started yet
 				 */
 	{
-	  /* 
+	  /*
 	   * The playback was not started yet (or there has been a pause).
 	   * Start the voice (again) and ask for a rollover irq at the end of
 	   * this_one block. If this_one one is last of the buffers, use just
 	   * the normal loop with irq.
 	   */
 
-	  gus_voice_off ();	/* 
-				 * It could already be running 
+	  gus_voice_off ();	/*
+				 * It could already be running
 				 */
 	  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 (0x0a, dram_loc, is16bits);	/*
+							 * Starting position
 							 */
-	  gus_write_addr (0x02, chn * pcm_banksize, is16bits);	/* 
-								 * Loop start 
-								 * location 
+	  gus_write_addr (0x02, chn * pcm_banksize, is16bits);	/*
+								 * Loop start
+								 * location
 								 */
 
 	  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 loop
 				 */
 
       if (pcm_datasize[this_one] != pcm_bsize)
 	{
-	  /* 
-	   * Incomplete block. Possibly the last one. 
+	  /*
+	   * Incomplete block. Possibly the last one.
 	   */
 	  if (chn == 0)
 	    {
-	      mode[chn] &= ~0x08;	/* 
-					 * Disable loop 
+	      mode[chn] &= ~0x08;	/*
+					 * Disable loop
 					 */
-	      mode[chn] |= 0x20;	/* 
-					 * Enable loop IRQ 
+	      mode[chn] |= 0x20;/*
+					 * Enable loop IRQ
 					 */
 	      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 
+	      gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits);	/*
+											 * Loop
+											 * end
+											 * location
 											 */
-	      mode[chn] &= ~0x08;	/* 
-					 * Disable loop 
+	      mode[chn] &= ~0x08;	/*
+					 * Disable loop
 					 */
 	    }
 	}
@@ -2468,11 +2511,11 @@
 gus_transfer_output_block (int dev, unsigned long buf,
 			   int total_count, int intrflag, int chn)
 {
-  /* 
+  /*
    * This routine transfers one block of audio data to the DRAM. In mono mode
    * it's called just once. When in stereo mode, this_one routine is called
    * once for both channels.
-   * 
+   *
    * The left/mono channel data is transferred to the beginning of dram and the
    * right data to the area pointed by gus_page_size.
    */
@@ -2499,8 +2542,8 @@
   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);
 
@@ -2515,38 +2558,38 @@
       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 
+    dma_command |= 0x04;	/*
+				 * 16 bit DMA channel
 				 */
 
-  gus_write8 (0x41, dma_command);	/* 
-					 * Kick on 
+  gus_write8 (0x41, dma_command);	/*
+					 * Kick on
 					 */
 
-  if (chn == (gus_sampling_channels - 1))	/* 
-						 * Last channel 
+  if (chn == (gus_sampling_channels - 1))	/*
+						 * Last channel
 						 */
     {
-      /* 
-       * Last (right or mono) channel data 
+      /*
+       * Last (right or mono) channel data
        */
       active_device = GUS_DEV_PCM_DONE;
       if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))
@@ -2554,9 +2597,9 @@
 	  play_next_pcm_block ();
 	}
     }
-  else				/* 
-				 * * * Left channel data. The right channel
-				 * is * * * transferred after DMA interrupt   */
+  else				/*
+				   * * * Left channel data. The right channel
+				   * is * * * transferred after DMA interrupt   */
     active_device = GUS_DEV_PCM_CONTINUE;
 
   RESTORE_INTR (flags);
@@ -2584,20 +2627,20 @@
 
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 
-  mode = 0xa0;			/* 
-				 * DMA IRQ enable, invert MSB 
+  mode = 0xa0;			/*
+				 * DMA IRQ enable, invert MSB
 				 */
 
   if (sound_dsp_dmachan[dev] > 3)
-    mode |= 0x04;		/* 
-				 * 16 bit DMA channel 
+    mode |= 0x04;		/*
+				 * 16 bit DMA channel
 				 */
   if (gus_sampling_channels > 1)
-    mode |= 0x02;		/* 
-				 * Stereo 
+    mode |= 0x02;		/*
+				 * Stereo
 				 */
-  mode |= 0x01;			/* 
-				 * DMA enable 
+  mode |= 0x01;			/*
+				 * DMA enable
 				 */
 
   gus_write8 (0x49, mode);
@@ -2612,8 +2655,8 @@
 
   rate = (9878400 / (gus_sampling_speed + 2)) / 16;
 
-  gus_write8 (0x48, rate & 0xff);	/* 
-					 * Set sampling frequency 
+  gus_write8 (0x48, rate & 0xff);	/*
+					 * Set sampling frequency
 					 */
 
   if (gus_sampling_bits != 8)
@@ -2716,6 +2759,7 @@
 static struct audio_operations gus_sampling_operations =
 {
   "Gravis UltraSound",
+  NEEDS_RESTART,
   gus_sampling_open,
   gus_sampling_close,
   gus_sampling_output_block,
@@ -2745,6 +2789,7 @@
   gus_voice_freq (freq);
   RESTORE_INTR (flags);
 }
+
 #endif
 
 static int
@@ -2776,8 +2821,8 @@
 	  while (ptr >= 0 && ptr < free_sample)
 	    {
 	      rec->data.data8[i]++;
-	      ptr = samples[ptr].key;	/* 
-					 * Follow link 
+	      ptr = samples[ptr].key;	/*
+					 * Follow link
 					 */
 	    }
 	}
@@ -2793,8 +2838,8 @@
 	while (ptr >= 0 && ptr < free_sample)
 	  {
 	    rec->data.data32[n++] = ptr;
-	    ptr = samples[ptr].key;	/* 
-					 * Follow link 
+	    ptr = samples[ptr].key;	/*
+					 * Follow link
 					 */
 	  }
       }
@@ -2815,11 +2860,11 @@
 
 	pat = (struct patch_info *) rec->data.data8;
 
-	pat->key = GUS_PATCH;	/* 
-				 * Restore patch type 
+	pat->key = GUS_PATCH;	/*
+				 * Restore patch type
 				 */
-	rec->parm1 = sample_ptrs[ptr];	/* 
-					 * DRAM address 
+	rec->parm1 = sample_ptrs[ptr];	/*
+					 * DRAM address
 					 */
 	rec->parm2 = sizeof (struct patch_info);
       }
@@ -2836,13 +2881,13 @@
 
 	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,
@@ -2853,8 +2898,8 @@
       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;
@@ -2866,12 +2911,12 @@
 	  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;	/*
+						 * Nr of bytes left
 						 */
 
 	if (l > n)
@@ -2881,25 +2926,25 @@
 	  l = sizeof (rec->data.data8);
 
 	if (l <= 0)
-	  return RET_ERROR (EINVAL);	/* 
-					 * Was there a bug? 
+	  return RET_ERROR (EINVAL);	/*
+					 * Was there a bug?
 					 */
 
-	offs += sample_ptrs[sample];	/* 
-					 * Begin offsess + offset to DRAM 
+	offs += sample_ptrs[sample];	/*
+					 * Begin offsess + offset to DRAM
 					 */
 
 	for (n = 0; n < l; n++)
 	  rec->data.data8[n] = gus_peek (offs++);
-	rec->parm1 = n;		/* 
-				 * Nr of bytes copied 
+	rec->parm1 = n;		/*
+				 * Nr of bytes copied
 				 */
       }
       return 0;
       break;
 
-    case PM_WRITE_PATCH:	/* 
-				 * Writes a block of wave data to the DRAM 
+    case PM_WRITE_PATCH:	/*
+				 * Writes a block of wave data to the DRAM
 				 */
       {
 	int             sample = rec->parm1;
@@ -2911,12 +2956,12 @@
 	  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;	/*
+						 * Nr of bytes left
 						 */
 
 	if (l > n)
@@ -2926,18 +2971,18 @@
 	  l = sizeof (rec->data.data8);
 
 	if (l <= 0)
-	  return RET_ERROR (EINVAL);	/* 
-					 * Was there a bug? 
+	  return RET_ERROR (EINVAL);	/*
+					 * Was there a bug?
 					 */
 
-	offs += sample_ptrs[sample];	/* 
-					 * Begin offsess + offset to DRAM 
+	offs += sample_ptrs[sample];	/*
+					 * Begin offsess + offset to DRAM
 					 */
 
 	for (n = 0; n < l; n++)
 	  gus_poke (offs++, rec->data.data8[n]);
-	rec->parm1 = n;		/* 
-				 * Nr of bytes copied 
+	rec->parm1 = n;		/*
+				 * Nr of bytes copied
 				 */
       }
       return 0;
@@ -2968,6 +3013,7 @@
   guswave_aftertouch,
   guswave_controller,
   guswave_panning,
+  guswave_volume_method,
   guswave_patchmgr,
 #ifdef FUTURE_VERSION
   guswave_bender
@@ -2975,39 +3021,43 @@
 };
 
 static void
-set_input_volumes(void)
+set_input_volumes (void)
 {
-	unsigned long flags;
-	unsigned char mask = 0xff & ~0x06;	/* Just line out enabled */
+  unsigned long   flags;
+  unsigned char   mask = 0xff & ~0x06;	/* Just line out enabled */
 
-	DISABLE_INTR(flags);
+  DISABLE_INTR (flags);
 
-/*
- *	Enable channels having vol > 10%
- *	Note! bit 0x01 means line in DISABLED while 0x04 means
- *	      mic in ENABLED.
+  /*
+ *    Enable channels having vol > 10%
+ *      Note! bit 0x01 means line in DISABLED while 0x04 means
+ *            mic in ENABLED.
  */
- 	if (gus_line_vol > 10) mask &= ~0x01;
- 	if (gus_mic_vol > 10) mask |= 0x04;
+  if (gus_line_vol > 10)
+    mask &= ~0x01;
+  if (gus_mic_vol > 10)
+    mask |= 0x04;
 
-	if (recording_active)
-	  {
-/*
- *	Disable channel, if not selected for recording
+  if (recording_active)
+    {
+      /*
+ *    Disable channel, if not selected for recording
  */
-	  	if (!(gus_recmask & SOUND_MASK_LINE)) mask |= 0x01;
-	  	if (!(gus_recmask & SOUND_MASK_MIC)) mask &= ~0x04;
-	  }
+      if (!(gus_recmask & SOUND_MASK_LINE))
+	mask |= 0x01;
+      if (!(gus_recmask & SOUND_MASK_MIC))
+	mask &= ~0x04;
+    }
 
-	mix_image &= ~0x07;
-	mix_image |= mask & 0x07;
-  	OUTB (mix_image, u_Mixer);
+  mix_image &= ~0x07;
+  mix_image |= mask & 0x07;
+  OUTB (mix_image, u_Mixer);
 
-	RESTORE_INTR(flags);
+  RESTORE_INTR (flags);
 }
 
-static int
-gus_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+int
+gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
 {
 #define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
 			 SOUND_MASK_SYNTH|SOUND_MASK_PCM)
@@ -3017,9 +3067,9 @@
 	switch (cmd & 0xff)
 	  {
 	  case SOUND_MIXER_RECSRC:
-	    gus_recmask = IOCTL_IN(arg) & MIX_DEVS;
-	    if (!(gus_recmask & (SOUND_MASK_MIC|SOUND_MASK_LINE)))
-	       gus_recmask = SOUND_MASK_MIC;
+	    gus_recmask = IOCTL_IN (arg) & MIX_DEVS;
+	    if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
+	      gus_recmask = SOUND_MASK_MIC;
 	    /* Note! Input volumes are updated during next open for recording */
 	    return IOCTL_OUT (arg, gus_recmask);
 	    break;
@@ -3027,10 +3077,13 @@
 	  case SOUND_MIXER_MIC:
 	    {
 	      int             vol = IOCTL_IN (arg) & 0xff;
-	      if (vol < 0) vol = 0;
-	      if (vol > 100) vol = 100;
+
+	      if (vol < 0)
+		vol = 0;
+	      if (vol > 100)
+		vol = 100;
 	      gus_mic_vol = vol;
-	      set_input_volumes();
+	      set_input_volumes ();
 	      return IOCTL_OUT (arg, vol | (vol << 8));
 	    }
 	    break;
@@ -3038,27 +3091,30 @@
 	  case SOUND_MIXER_LINE:
 	    {
 	      int             vol = IOCTL_IN (arg) & 0xff;
-	      if (vol < 0) vol = 0;
-	      if (vol > 100) vol = 100;
+
+	      if (vol < 0)
+		vol = 0;
+	      if (vol > 100)
+		vol = 100;
 	      gus_line_vol = vol;
-	      set_input_volumes();
+	      set_input_volumes ();
 	      return IOCTL_OUT (arg, vol | (vol << 8));
 	    }
 	    break;
 
 	  case SOUND_MIXER_PCM:
-	      gus_pcm_volume = IOCTL_IN (arg) & 0xff;
-	      if (gus_pcm_volume < 0)
-		gus_pcm_volume = 0;
-	      if (gus_pcm_volume > 100)
-		gus_pcm_volume = 100;
-	      gus_sampling_update_volume ();
-	      return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
+	    gus_pcm_volume = IOCTL_IN (arg) & 0xff;
+	    if (gus_pcm_volume < 0)
+	      gus_pcm_volume = 0;
+	    if (gus_pcm_volume > 100)
+	      gus_pcm_volume = 100;
+	    gus_sampling_update_volume ();
+	    return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
 	    break;
 
 	  case SOUND_MIXER_SYNTH:
 	    {
-	      int             voice; 
+	      int             voice;
 
 	      gus_wave_volume = IOCTL_IN (arg) & 0xff;
 
@@ -3069,9 +3125,9 @@
 
 	      if (active_device == GUS_DEV_WAVE)
 		for (voice = 0; voice < nr_voices; voice++)
-		  dynamic_volume_change (voice);	/* 
+		  dynamic_volume_change (voice);	/*
 							 * Apply the new
-							 * volume 
+							 * volume
 							 */
 
 	      return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
@@ -3082,8 +3138,8 @@
 	    return RET_ERROR (EINVAL);
 	  }
       else
-	switch (cmd & 0xff)	/* 
-				 * Return parameters 
+	switch (cmd & 0xff)	/*
+				 * Return parameters
 				 */
 	  {
 
@@ -3100,7 +3156,7 @@
 	    break;
 
 	  case SOUND_MIXER_RECMASK:
-	    return IOCTL_OUT (arg, SOUND_MASK_MIC|SOUND_MASK_LINE);
+	    return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
 	    break;
 
 	  case SOUND_MIXER_CAPS:
@@ -3133,14 +3189,94 @@
 
 static struct mixer_operations gus_mixer_operations =
 {
-  gus_mixer_ioctl
+  gus_default_mixer_ioctl
 };
 
+static long
+gus_default_mixer_init (long mem_start)
+{
+  if (num_mixers < MAX_MIXER_DEV)	/*
+					 * Don't install if there is another
+					 * mixer
+					 */
+    mixer_devs[num_mixers++] = &gus_mixer_operations;
+
+  return mem_start;
+}
+
 long
 gus_wave_init (long mem_start, int irq, int dma)
 {
-  printk (" <Gravis UltraSound %dk>", (int) gus_mem_size / 1024);
+  unsigned long   flags;
+  unsigned char   val;
+  char           *model_num = "2.4";
+  int             gus_type = 0x24;	/* 2.4 */
+  int             mixer_type = 0;
+
+  /*
+ * Try to identify the GUS model.
+ *
+ *	Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+ */
+
+  DISABLE_INTR (flags);
+  OUTB (0x20, gus_base + 0x0f);
+  val = INB (gus_base + 0x0f);
+  RESTORE_INTR (flags);
 
+  if (val != 0xff && (val & 0x06))	/* Should be 0x02? */
+    {
+      /*
+	 * It has the digital ASIC so the card is at least v3.4.
+	 * Next try to detect the true model.
+	 */
+
+      val = INB (u_MixSelect);
+
+      /*
+         * Value 255 means pre-3.7 which don't have mixer.
+         * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
+         * 10 and above is GUS MAX which has the CS4231 codec/mixer.
+         *
+         * Sorry. No GUS max support yet but it should be available
+	 * soon after the SDK for GUS MAX is available.
+	 */
+
+      if (val == 255 || val < 5)
+	{
+	  model_num = "3.4";
+	  gus_type = 0x34;
+	}
+      else if (val < 10)
+	{
+	  model_num = "3.7";
+	  gus_type = 0x37;
+	  mixer_type = ICS2101;
+	}
+      else
+	{
+	  model_num = "MAX";
+	  gus_type = 0x40;
+	  mixer_type = CS4231;
+	}
+    }
+  else
+    {
+      /*
+	 * ASIC not detected so the card must be 2.2 or 2.4.
+	 * There could still be the 16-bit/mixer daughter card.
+	 * It has the same codec/mixer than MAX.
+	 * At this time there is no support for it but it will appear soon.
+	 */
+    }
+
+
+  printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+
+#ifndef SCO
+  sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+#endif
+
   if (irq < 0 || irq > 15)
     {
       printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
@@ -3179,11 +3315,21 @@
   else
     printk ("GUS: Too many PCM devices available\n");
 
-  if (num_mixers < MAX_MIXER_DEV)	/* 
-					 * Don't install if there is another
-					 * mixer 
-					 */
-    mixer_devs[num_mixers++] = &gus_mixer_operations;
+  /*
+ *  Mixer dependent initialization.
+ */
+
+  switch (mixer_type)
+    {
+    case ICS2101:
+      gus_line_vol=gus_mic_vol=gus_wave_volume = gus_pcm_volume = 100;
+      return ics2101_mixer_init (mem_start);
+
+    case CS4231:
+      /* Available soon */
+    default:
+      return gus_default_mixer_init (mem_start);
+    }
 
   return mem_start;
 }
@@ -3199,8 +3345,8 @@
   gus_select_voice (voice);
 
   tmp = gus_read8 (0x00);
-  tmp &= ~0x20;			/* 
-				 * Disable wave IRQ for this_one voice 
+  tmp &= ~0x20;			/*
+				 * Disable wave IRQ for this_one voice
 				 */
   gus_write8 (0x00, tmp);
 
@@ -3211,12 +3357,12 @@
   switch (mode)
     {
 
-    case LMODE_FINISH:		/* 
-				 * Final loop finished, shoot volume down 
+    case LMODE_FINISH:		/*
+				 * Final loop finished, shoot volume down
 				 */
 
-      if ((gus_read16 (0x09) >> 4) < 100)	/* 
-						 * Get current volume 
+      if ((gus_read16 (0x09) >> 4) < 100)	/*
+						 * Get current volume
 						 */
 	{
 	  gus_voice_off ();
@@ -3225,18 +3371,18 @@
 	  break;
 	}
       gus_ramp_range (65, 4065);
-      gus_ramp_rate (0, 63);	/* 
-				 * Fastest possible rate 
+      gus_ramp_rate (0, 63);	/*
+				 * Fastest possible rate
 				 */
-      gus_rampon (0x20 | 0x40);	/* 
-				 * Ramp down, once, irq 
+      gus_rampon (0x20 | 0x40);	/*
+				 * Ramp down, once, irq
 				 */
       voices[voice].volume_irq_mode = VMODE_HALT;
       break;
 
     case LMODE_PCM_STOP:
-      pcm_active = 0;		/* 
-				 * Requires extensive processing 
+      pcm_active = 0;		/*
+				 * Requires extensive processing
 				 */
     case LMODE_PCM:
       {
@@ -3249,8 +3395,8 @@
 	    play_next_pcm_block ();
 	  }
 	else
-	  {			/* 
-				 * Out of data. Just stop the voice 
+	  {			/*
+				 * Out of data. Just stop the voice
 				 */
 	    gus_voice_off ();
 	    gus_rampoff ();
@@ -3281,8 +3427,8 @@
   gus_select_voice (voice);
 
   tmp = gus_read8 (0x0d);
-  tmp &= ~0x20;			/* 
-				 * Disable volume ramp IRQ 
+  tmp &= ~0x20;			/*
+				 * Disable volume ramp IRQ
 				 */
   gus_write8 (0x0d, tmp);
 
@@ -3292,34 +3438,35 @@
 
   switch (mode)
     {
-    case VMODE_HALT:		/* 
-				 * Decay phase finished 
+    case VMODE_HALT:		/*
+				 * Decay phase finished
 				 */
+      RESTORE_INTR (flags);
       gus_voice_init (voice);
       break;
 
     case VMODE_ENVELOPE:
       gus_rampoff ();
+      RESTORE_INTR (flags);
       step_envelope (voice);
       break;
 
     case VMODE_START_NOTE:
+      RESTORE_INTR (flags);
       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, 0);
       if (voices[voice].sample_pending >= 0)
-        {
-          guswave_set_instr (voices[voice].dev_pending, voice,
-            voices[voice].sample_pending);
-          voices[voice].sample_pending = -1;
-        }
+	{
+	  guswave_set_instr (voices[voice].dev_pending, voice,
+			     voices[voice].sample_pending);
+	  voices[voice].sample_pending = -1;
+	}
       break;
 
     default:;
     }
-
-  RESTORE_INTR (flags);
 }
 
 void
@@ -3332,37 +3479,37 @@
 
   while (1)
     {
-      src = gus_read8 (0x0f);	/* 
-				 * Get source info 
+      src = gus_read8 (0x0f);	/*
+				 * Get source info
 				 */
       voice = src & 0x1f;
       src &= 0xc0;
 
       if (src == (0x80 | 0x40))
-	return;			/* 
-				 * No interrupt 
+	return;			/*
+				 * No interrupt
 				 */
 
       voice_bit = 1 << voice;
 
-      if (!(src & 0x80))	/* 
-				 * Wave IRQ pending 
+      if (!(src & 0x80))	/*
+				 * Wave IRQ pending
 				 */
-	if (!(wave_ignore & voice_bit) && voice < nr_voices)	/* 
+	if (!(wave_ignore & voice_bit) && voice < nr_voices)	/*
 								 * Not done
-								 * yet 
+								 * yet
 								 */
 	  {
 	    wave_ignore |= voice_bit;
 	    do_loop_irq (voice);
 	  }
 
-      if (!(src & 0x40))	/* 
-				 * Volume IRQ pending 
+      if (!(src & 0x40))	/*
+				 * Volume IRQ pending
 				 */
-	if (!(volume_ignore & voice_bit) && voice < nr_voices)	/* 
+	if (!(volume_ignore & voice_bit) && voice < nr_voices)	/*
 								 * Not done
-								 * yet 
+								 * yet
 								 */
 	  {
 	    volume_ignore |= voice_bit;
@@ -3376,11 +3523,11 @@
 {
   unsigned char   status;
 
-  status = gus_look8 (0x41);	/* 
-				 * Get DMA IRQ Status 
+  status = gus_look8 (0x41);	/*
+				 * Get DMA IRQ Status
 				 */
-  if (status & 0x40)		/* 
-				 * DMA Irq pending 
+  if (status & 0x40)		/*
+				 * DMA Irq pending
 				 */
     switch (active_device)
       {
@@ -3405,11 +3552,11 @@
       default:;
       }
 
-  status = gus_look8 (0x49);	/* 
-				 * Get Sampling IRQ Status 
+  status = gus_look8 (0x49);	/*
+				 * Get Sampling IRQ Status
 				 */
-  if (status & 0x40)		/* 
-				 * Sampling Irq pending 
+  if (status & 0x40)		/*
+				 * Sampling Irq pending
 				 */
     {
       DMAbuf_inputintr (gus_devnum);
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c
--- v1.1.9/linux/drivers/sound/ics2101.c
+++ linux/drivers/sound/ics2101.c	Tue Apr 26 09:36:11 1994
@@ -0,0 +1,261 @@
+/*
+ * sound/ics2101.c
+ *
+ * Driver for the ICS2101 mixer of GUS v3.7.
+ *
+ * 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.
+ *
+ */
+
+#include "sound_config.h"
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+
+#include <linux/ultrasound.h>
+#include "gus_hw.h"
+
+#define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
+			 SOUND_MASK_SYNTH| \
+  			 SOUND_MASK_CD | SOUND_MASK_VOLUME)
+
+extern int      gus_base;
+static int      volumes[ICS_MIXDEVS];
+static int      left_fix[ICS_MIXDEVS] =
+{1, 1, 1, 2, 1, 2};
+static int      right_fix[ICS_MIXDEVS] =
+{2, 2, 2, 1, 2, 1};
+
+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;
+
+        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;
+#endif
+}
+
+static void
+write_mix (int dev, int chn, int vol)
+{
+  int            *selector;
+  unsigned long   flags;
+  int             ctrl_addr = dev << 3;
+  int             attn_addr = dev << 3;
+
+  vol=scale_vol(vol);
+
+  if (chn == CHN_LEFT)
+    {
+      selector = left_fix;
+      ctrl_addr |= 0x00;
+      attn_addr |= 0x02;
+    }
+  else
+    {
+      selector = right_fix;
+      ctrl_addr |= 0x01;
+      attn_addr |= 0x03;
+    }
+
+  DISABLE_INTR (flags);
+  OUTB (ctrl_addr, u_MixSelect);
+  OUTB (selector[dev], u_MixData);
+  OUTB (attn_addr, u_MixSelect);
+  OUTB ((unsigned char) vol, u_MixData);
+  RESTORE_INTR (flags);
+}
+
+static int
+set_volumes (int dev, int vol)
+{
+  int             left = vol & 0x00ff;
+  int             right = (vol >> 8) & 0x00ff;
+
+  if (left < 0)
+    left = 0;
+  if (left > 100)
+    left = 100;
+  if (right < 0)
+    right = 0;
+  if (right > 100)
+    right = 100;
+
+  write_mix (dev, CHN_LEFT, left);
+  write_mix (dev, CHN_RIGHT, right);
+
+  vol = left + (right << 8);
+  volumes[dev] = vol;
+  return vol;
+}
+
+static int
+ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+  if (((cmd >> 8) & 0xff) == 'M')
+    {
+      if (cmd & IOC_IN)
+	switch (cmd & 0xff)
+	  {
+	  case SOUND_MIXER_RECSRC:
+	    return gus_default_mixer_ioctl (dev, cmd, arg);
+	    break;
+
+	  case SOUND_MIXER_MIC:
+	    return IOCTL_OUT (arg, set_volumes (DEV_MIC, IOCTL_IN (arg)));
+	    break;
+
+	  case SOUND_MIXER_CD:
+	    return IOCTL_OUT (arg, set_volumes (DEV_CD, IOCTL_IN (arg)));
+	    break;
+
+	  case SOUND_MIXER_LINE:
+	    return IOCTL_OUT (arg, set_volumes (DEV_LINE, IOCTL_IN (arg)));
+	    break;
+
+	  case SOUND_MIXER_SYNTH:
+	    return IOCTL_OUT (arg, set_volumes (DEV_GF1, IOCTL_IN (arg)));
+	    break;
+
+	  case SOUND_MIXER_VOLUME:
+	    return IOCTL_OUT (arg, set_volumes (DEV_VOL, IOCTL_IN (arg)));
+	    break;
+
+	  default:
+	    return RET_ERROR (EINVAL);
+	  }
+      else
+	switch (cmd & 0xff)	/*
+				 * Return parameters
+				 */
+	  {
+
+	  case SOUND_MIXER_RECSRC:
+	    return gus_default_mixer_ioctl (dev, cmd, arg);
+	    break;
+
+	  case SOUND_MIXER_DEVMASK:
+	    return IOCTL_OUT (arg, MIX_DEVS);
+	    break;
+
+	  case SOUND_MIXER_STEREODEVS:
+	    return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
+			      SOUND_MASK_SYNTH | SOUND_MASK_VOLUME|
+			      SOUND_MASK_MIC);
+	    break;
+
+	  case SOUND_MIXER_RECMASK:
+	    return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+	    break;
+
+	  case SOUND_MIXER_CAPS:
+	    return IOCTL_OUT (arg, 0);
+	    break;
+
+	  case SOUND_MIXER_MIC:
+	    return IOCTL_OUT (arg, volumes[DEV_MIC]);
+	    break;
+
+	  case SOUND_MIXER_LINE:
+	    return IOCTL_OUT (arg, volumes[DEV_LINE]);
+	    break;
+
+	  case SOUND_MIXER_CD:
+	    return IOCTL_OUT (arg, volumes[DEV_CD]);
+	    break;
+
+	  case SOUND_MIXER_VOLUME:
+	    return IOCTL_OUT (arg, volumes[DEV_VOL]);
+	    break;
+
+	  case SOUND_MIXER_SYNTH:
+	    return IOCTL_OUT (arg, volumes[DEV_GF1]);
+	    break;
+
+	  default:
+	    return RET_ERROR (EINVAL);
+	  }
+    }
+
+  return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations ics2101_mixer_operations =
+{
+  ics2101_mixer_ioctl
+};
+
+long
+ics2101_mixer_init (long mem_start)
+{
+  int             i;
+
+  if (num_mixers < MAX_MIXER_DEV)
+    {
+      mixer_devs[num_mixers++] = &ics2101_mixer_operations;
+
+      /*
+ * Some GUS v3.7 cards had some channels flipped. Disable
+ * the flipping feature if the model id is other than 5.
+ */
+
+      if (INB (u_MixSelect) != 5)
+	{
+	  for (i = 0; i < ICS_MIXDEVS; i++)
+	    left_fix[i] = 1;
+	  for (i = 0; i < ICS_MIXDEVS; i++)
+	    right_fix[i] = 2;
+	}
+
+      set_volumes (DEV_GF1, 0x5a5a);
+      set_volumes (DEV_CD, 0x5a5a);
+      set_volumes (DEV_MIC, 0x0000);
+      set_volumes (DEV_LINE, 0x5a5a);
+      set_volumes (DEV_VOL, 0x5a5a);
+      set_volumes (DEV_UNUSED, 0x0000);
+    }
+
+  return mem_start;
+}
+
+#endif
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v1.1.9/linux/drivers/sound/midibuf.c	Fri Dec 10 00:23:26 1993
+++ linux/drivers/sound/midibuf.c	Fri Apr 15 11:03:17 1994
@@ -1,12 +1,12 @@
 /*
  * sound/midibuf.c
- * 
+ *
  * 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
  * modification, are permitted provided that the following conditions are
  * met: 1. Redistributions of source code must retain the above copyright
@@ -14,7 +14,7 @@
  * 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
@@ -26,7 +26,7 @@
  * 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"
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c
--- v1.1.9/linux/drivers/sound/mpu401.c	Fri Dec 10 00:23:39 1993
+++ linux/drivers/sound/mpu401.c	Fri Apr 15 11:03:18 1994
@@ -1,12 +1,12 @@
 /*
  * sound/mpu401.c
- * 
+ *
  * 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
  * modification, are permitted provided that the following conditions are
  * met: 1. Redistributions of source code must retain the above copyright
@@ -14,7 +14,7 @@
  * 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
@@ -26,7 +26,7 @@
  * 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"
@@ -35,7 +35,7 @@
 
 #if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
 
-#define	DATAPORT   (mpu401_base)	/* MPU-401 Data I/O Port on IBM */
+#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 */
 
@@ -61,58 +61,16 @@
 static int      reset_mpu401 (void);
 static void     (*midi_input_intr) (int dev, unsigned char data);
 
-static void
-mpu401_input_loop (void)
-{
-  int             count;
-
-  count = 10;
-
-  while (count)			/* Not timed out */
-    if (input_avail ())
-      {
-	unsigned char   c = mpu401_read ();
-
-	count = 100;
-
-	if (mpu401_opened & OPEN_READ)
-	  midi_input_intr (my_dev, c);
-      }
-    else
-      while (!input_avail () && count)
-	count--;
-}
-
 void
 mpuintr (int unit)
 {
-  if (input_avail ())
-    mpu401_input_loop ();
-}
-
-/*
- * It looks like there is no input interrupts in the UART mode. Let's try
- * polling.
- */
-
-static void
-poll_mpu401 (unsigned long dummy)
-{
-  unsigned long   flags;
-
-  DEFINE_TIMER(mpu401_timer, poll_mpu401);
-
-  if (!(mpu401_opened & OPEN_READ))
-    return;			/* No longer required */
-
-  DISABLE_INTR (flags);
-
-  if (input_avail ())
-    mpu401_input_loop ();
-
-  ACTIVATE_TIMER(mpu401_timer, poll_mpu401, 1); /* Come back later */
+  while (input_avail ())
+    {
+      unsigned char   c = mpu401_read ();
 
-  RESTORE_INTR (flags);
+      if (mpu401_opened & OPEN_READ)
+	midi_input_intr (my_dev, c);
+    }
 }
 
 static int
@@ -127,11 +85,10 @@
       return RET_ERROR (EBUSY);
     }
 
-  mpu401_input_loop ();
+  mpuintr (0);
 
   midi_input_intr = input;
   mpu401_opened = mode;
-  poll_mpu401 (0);		/* Enable input polling */
 
   return 0;
 }
@@ -155,7 +112,7 @@
   DISABLE_INTR (flags);
 
   if (input_avail ())
-    mpu401_input_loop ();
+    mpuintr (0);
 
   RESTORE_INTR (flags);
 
@@ -291,7 +248,7 @@
 
   mpu401_opened = 0;
   if (ok)
-    mpu401_input_loop ();	/* Flush input before enabling interrupts */
+    mpuintr (0);		/* Flush input before enabling interrupts */
 
   RESTORE_INTR (flags);
 
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v1.1.9/linux/drivers/sound/opl3.c	Tue Dec 14 02:41:13 1993
+++ linux/drivers/sound/opl3.c	Fri Apr 15 11:03:20 1994
@@ -1,10 +1,10 @@
 /*
  * sound/opl3.c
- * 
+ *
  * A low level driver for Yamaha YM3812 and OPL-3 -chips
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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.
- * 
+ *
  */
 
 /* Major improvements to the FM handling 30AUG92 by Rob Hooft, */
@@ -38,7 +38,7 @@
 
 #define MAX_VOICE	18
 #define OFFS_4OP	11	/* Definitions for the operators OP3 and OP4
-				 * begin here */
+				   * begin here */
 
 static int      opl3_enabled = 0;
 static int      left_address = 0x388, right_address = 0x388, both_address = 0;
@@ -70,7 +70,7 @@
 
 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);
@@ -81,6 +81,9 @@
 void
 enable_opl3_mode (int left, int right, int both)
 {
+  if (opl3_enabled)
+    return;
+
   opl3_enabled = 1;
   left_address = left;
   right_address = right;
@@ -168,10 +171,10 @@
    * This function returns 1 if the FM chicp is present at the given I/O port
    * The detection algorithm plays with the timer built in the FM chip and
    * looks for a change in the status register.
-   * 
+   *
    * Note! The timers of the FM chip are not connected to AdLib (and compatible)
    * boards.
-   * 
+   *
    * Note2! The chip is initialized if detected.
    */
 
@@ -194,7 +197,7 @@
 
   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 */
@@ -364,7 +367,7 @@
       vol2 = instr->operators[3];
 
       if ((instr->operators[10] & 0x01))
-	{			/* Additive synthesis	 */
+	{			/* Additive synthesis    */
 	  calc_vol (&vol1, volume);
 	  calc_vol (&vol2, volume);
 	}
@@ -627,7 +630,7 @@
    * 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 ();
@@ -635,7 +638,7 @@
     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)
     {
@@ -747,6 +750,11 @@
 {
 }
 
+static void
+opl3_volume_method (int dev, int mode)
+{
+}
+
 #define SET_VIBRATO(cell) { \
       tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \
       if (pressure > 110) \
@@ -852,7 +860,7 @@
       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 */
+									   * of f-num */
       voices[voice].keyon_byte = data;
       opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
       break;
@@ -886,6 +894,7 @@
   opl3_aftertouch,
   opl3_controller,
   opl3_panning,
+  opl3_volume_method,
   opl3_patchmgr
 };
 
@@ -894,8 +903,8 @@
 {
   int             i;
 
-  PERMANENT_MALLOC(struct sbi_instrument*, instrmap, 
-  		   SBFM_MAXINSTR*sizeof(*instrmap), mem_start);
+  PERMANENT_MALLOC (struct sbi_instrument *, instrmap,
+		    SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
 
   synth_devs[num_synths++] = &opl3_operations;
   fm_model = 0;
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v1.1.9/linux/drivers/sound/os.h	Tue Apr 19 10:52:50 1994
+++ linux/drivers/sound/os.h	Sun Apr 24 12:28:37 1994
@@ -37,7 +37,6 @@
 #include <linux/timer.h>
 #include <linux/tty.h>
 #include <linux/ctype.h>
-#include <linux/string.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -46,6 +45,7 @@
 #include <linux/wait.h>
 #include <linux/malloc.h>
 #include <linux/soundcard.h>
+#include <linux/string.h>
 
 typedef char snd_rw_buf;
 
@@ -141,7 +141,7 @@
 
 #define DEFINE_TIMER(name, proc) \
   static struct timer_list name = \
-  {NULL, NULL, 0, 0, proc}
+  {NULL, 0, 0, 0, proc}
 
 /*
  * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/pas.h linux/drivers/sound/pas.h
--- v1.1.9/linux/drivers/sound/pas.h	Wed Dec 15 02:10:21 1993
+++ linux/drivers/sound/pas.h	Thu Mar  3 23:32:05 1994
@@ -138,11 +138,11 @@
 	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			*/
-		{ 0,  0,  1,  2,  3,  4,  5,  6, 0,  0,  7,  8,  9,  0, 10, 11 };  
+		{ 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		*/
-		{ 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x05, 0x06, 0x07 };
+		{ 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			*/
-		{ 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x00, 0x28, 0x30, 0x38, 0, 0 };
+		{ 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			*/
 		{ 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
 	char O_M_1_to_card[] = 				/* R W	Control		Translate (OM1 & 0x0f) to card type		*/
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v1.1.9/linux/drivers/sound/pas2_card.c	Wed Dec 15 02:21:11 1993
+++ linux/drivers/sound/pas2_card.c	Fri Apr 15 11:03:20 1994
@@ -2,11 +2,11 @@
 #define SND_SA_INTERRUPT
 /*
  * sound/pas2_card.c
- * 
+ *
  * Detection routine for the Pro Audio Spectrum cards.
- * 
+ *
  * 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
@@ -14,7 +14,7 @@
  * 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
@@ -26,7 +26,7 @@
  * 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"
@@ -196,14 +196,14 @@
 	  ok = 0;
 	}
     }
-  
-/*
+
+  /*
  * This fixes the timing problems of the PAS due to the Symphony chipset
  * as per Media Vision.  Only define this if your PAS doesn't work correctly.
  */
 #ifdef SYMPHONY_PAS
-	OUTB(0x05,0xa8);
-	OUTB(0x60,0xa9);
+  OUTB (0x05, 0xa8);
+  OUTB (0x60, 0xa9);
 #endif
 
 #ifdef BROKEN_BUS_CLOCK
@@ -228,35 +228,35 @@
 
 #if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
 
-    {
-	struct address_info *sb_config;
+  {
+    struct address_info *sb_config;
 
-	if ((sb_config=sound_getconf(SNDCARD_SB)))
-        {
-		unsigned char irq_dma;
-
-  /* Turn on Sound Blaster compatibility */
-  /* bit 1 = SB emulation */
-  /* bit 0 = MPU401 emulation (CDPC only :-( ) */
-  pas_write (0x02, COMPATIBILITY_ENABLE);
-
-  /* "Emulation address"	 */
-            pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
-
-	    if (!E_C_SB_DMA_translate[sb_config->dma]) 
-               printk("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
-			sb_config->dma);
-
-	    if (!E_C_SB_IRQ_translate[sb_config->irq]) 
-               printk("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
-			sb_config->irq);
-
-	    irq_dma = E_C_SB_DMA_translate[sb_config->dma] | 
-		      E_C_SB_IRQ_translate[sb_config->irq];
-
-	    pas_write(irq_dma, EMULATION_CONFIGURATION);
-        }
-   }
+    if ((sb_config = sound_getconf (SNDCARD_SB)))
+      {
+	unsigned char   irq_dma;
+
+	/* Turn on Sound Blaster compatibility */
+	/* bit 1 = SB emulation */
+	/* bit 0 = MPU401 emulation (CDPC only :-( ) */
+	pas_write (0x02, COMPATIBILITY_ENABLE);
+
+	/* "Emulation address"         */
+	pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
+
+	if (!E_C_SB_DMA_translate[sb_config->dma])
+	  printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
+		  sb_config->dma);
+
+	if (!E_C_SB_IRQ_translate[sb_config->irq])
+	  printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
+		  sb_config->irq);
+
+	irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
+	  E_C_SB_IRQ_translate[sb_config->irq];
+
+	pas_write (irq_dma, EMULATION_CONFIGURATION);
+      }
+  }
 #endif
 
   if (!ok)
@@ -327,11 +327,11 @@
 	  mem_start = pas_pcm_init (mem_start, hw_config);
 #endif
 
-# if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
+#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
 
 	  sb_dsp_disable_midi ();	/* The SB emulation don't support
 					 * midi */
-# endif
+#endif
 
 #ifndef EXCLUDE_YM3812
 	  enable_opl3_mode (0x388, 0x38a, 0);
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c
--- v1.1.9/linux/drivers/sound/pas2_midi.c	Fri Dec 10 00:24:01 1993
+++ linux/drivers/sound/pas2_midi.c	Fri Apr 15 11:03:21 1994
@@ -1,10 +1,10 @@
 /*
  * sound/pas2_midi.c
- * 
+ *
  * The low level driver for the PAS Midi Interface.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c
--- v1.1.9/linux/drivers/sound/pas2_mixer.c	Fri Dec 10 00:24:14 1993
+++ linux/drivers/sound/pas2_mixer.c	Fri Apr 15 11:03:22 1994
@@ -2,11 +2,11 @@
 
 /*
  * sound/pas2_mixer.c
- * 
+ *
  * Mixer routines for the Pro Audio Spectrum cards.
- * 
+ *
  * 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
@@ -14,7 +14,7 @@
  * 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
@@ -26,7 +26,7 @@
  * 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"
@@ -87,7 +87,7 @@
     }
 
   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;
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c
--- v1.1.9/linux/drivers/sound/pas2_pcm.c	Tue Dec 14 18:22:50 1993
+++ linux/drivers/sound/pas2_pcm.c	Fri Apr 15 11:03:23 1994
@@ -1,11 +1,11 @@
 #define _PAS2_PCM_C_
 /*
  * sound/pas2_pcm.c
- * 
+ *
  * The low level driver for the Pro Audio Spectrum ADC/DAC.
- * 
+ *
  * 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
@@ -13,7 +13,7 @@
  * 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
@@ -25,7 +25,7 @@
  * 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"
@@ -149,7 +149,7 @@
 
     case SOUND_PCM_WRITE_CHANNELS:
       if (local)
-         return pcm_set_channels (arg);
+	return pcm_set_channels (arg);
       return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
       break;
 
@@ -234,7 +234,7 @@
 }
 
 static void
-pas_pcm_output_block (int dev, unsigned long buf, int count, 
+pas_pcm_output_block (int dev, unsigned long buf, int count,
 		      int intrflag, int restart_dma)
 {
   unsigned long   flags, cnt;
@@ -255,8 +255,8 @@
   pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
 	     PCM_CONTROL);
 
-  if (restart_dma) 
-     DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+  if (restart_dma)
+    DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 
   if (sound_dsp_dmachan[dev] > 3)
     count >>= 1;
@@ -280,7 +280,7 @@
 }
 
 static void
-pas_pcm_start_input (int dev, unsigned long buf, int count, 
+pas_pcm_start_input (int dev, unsigned long buf, int count,
 		     int intrflag, int restart_dma)
 {
   unsigned long   flags;
@@ -300,7 +300,7 @@
   DISABLE_INTR (flags);
 
   if (restart_dma)
-     DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+    DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 
   if (sound_dsp_dmachan[dev] > 3)
     count >>= 1;
@@ -337,14 +337,15 @@
 static struct audio_operations pas_pcm_operations =
 {
   "Pro Audio Spectrum",
-  pas_pcm_open,			/* */
-  pas_pcm_close,		/* */
-  pas_pcm_output_block,		/* */
-  pas_pcm_start_input,		/* */
-  pas_pcm_ioctl,		/* */
-  pas_pcm_prepare_for_input,	/* */
-  pas_pcm_prepare_for_output,	/* */
-  pas_pcm_reset,		/* */
+  NOTHING_SPECIAL,
+  pas_pcm_open,
+  pas_pcm_close,
+  pas_pcm_output_block,
+  pas_pcm_start_input,
+  pas_pcm_ioctl,
+  pas_pcm_prepare_for_input,
+  pas_pcm_prepare_for_output,
+  pas_pcm_reset,
   pas_pcm_reset,		/* halt_xfer */
   NULL,				/* has_output_drained */
   NULL				/* copy_from_user */
@@ -379,9 +380,9 @@
 	  sound_dma_automode[my_devnum] = 1;
 	}
 #else
-	  sound_buffcounts[my_devnum] = 2;
-	  sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
-	  sound_dma_automode[my_devnum] = 0;
+      sound_buffcounts[my_devnum] = 2;
+      sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
+      sound_dma_automode[my_devnum] = 0;
 #endif
     }
   else
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c
--- v1.1.9/linux/drivers/sound/patmgr.c	Fri Dec 10 00:24:34 1993
+++ linux/drivers/sound/patmgr.c	Fri Apr 15 11:03:24 1994
@@ -1,10 +1,10 @@
 /*
  * sound/patmgr.c
- * 
+ *
  * The patch maneger interface for the /dev/sequencer
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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 PATMGR_C
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c
--- v1.1.9/linux/drivers/sound/sb16_dsp.c	Fri Jan 21 15:59:50 1994
+++ linux/drivers/sound/sb16_dsp.c	Fri Apr 15 11:03:25 1994
@@ -1,12 +1,12 @@
 /*
  * sound/sb16_dsp.c
- * 
+ *
  * The low level driver for the SoundBlaster DSP chip.
- * 
+ *
  * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de)
  *
  * based on SB-driver by (C) Hannu Savolainen
- * 
+ *
  * 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
@@ -14,7 +14,7 @@
  * 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
@@ -26,53 +26,55 @@
  * 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)
 /*
-#define DEB_DMARES
-*/
+   #define DEB_DMARES
+ */
 #include "sound_config.h"
 #include "sb.h"
 #include "sb_mixer.h"
 
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
 
-extern int sbc_base;
+extern int      sbc_base, sbc_minor, sbc_major;
 
-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_busy  = 0;
-static int dma16, dma8;
+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_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_INPUT, IMODE_OUTPUT or
+
 					   IMODE_NONE */
-static int my_dev = 0;
+static int      my_dev = 0;
 
 static volatile int intr_active = 0;
 
-static int sb16_dsp_open (int dev, int mode);
-static void sb16_dsp_close (int dev);
-static void sb16_dsp_output_block (int dev, unsigned long buf, int count,int intrflag, int dma_restart);
-static void sb16_dsp_start_input (int dev, unsigned long buf, int count,int intrflag, int dma_restart);
-static int sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg,int local);
-static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
-static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
-static void sb16_dsp_reset (int dev);
-static void sb16_dsp_halt (int dev);
-static int dsp_set_speed (int);
-static int dsp_set_stereo (int);
-static void dsp_cleanup (void);
-int sb_reset_dsp (void);
+static int      sb16_dsp_open (int dev, int mode);
+static void     sb16_dsp_close (int dev);
+static void     sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static void     sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static int      sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
+static int      sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
+static int      sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
+static void     sb16_dsp_reset (int dev);
+static void     sb16_dsp_halt (int dev);
+static int      dsp_set_speed (int);
+static int      dsp_set_stereo (int);
+static void     dsp_cleanup (void);
+int             sb_reset_dsp (void);
 
 static struct audio_operations sb16_dsp_operations =
 {
   "SoundBlaster 16",
+  NOTHING_SPECIAL,
   sb16_dsp_open,
   sb16_dsp_close,
   sb16_dsp_output_block,
@@ -86,203 +88,221 @@
   NULL
 };
 
-static int sb_dsp_command01 (unsigned char val)
+static int
+sb_dsp_command01 (unsigned char val)
 {
-  int i=1<<16;
+  int             i = 1 << 16;
 
-  while(--i & (!INB (DSP_STATUS) & 0x80));
-  if(!i)
-    printk("SB16 sb_dsp_command01 Timeout\n");
-  return sb_dsp_command(val);
+  while (--i & (!INB (DSP_STATUS) & 0x80));
+  if (!i)
+    printk ("SB16 sb_dsp_command01 Timeout\n");
+  return sb_dsp_command (val);
 }
 
-static int wait_data_avail(int t)
+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);
+  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)
+static int
+read_dsp (int t)
 {
-  if(!wait_data_avail(t))
+  if (!wait_data_avail ((unsigned long) t))
     return -1;
   else
-    return INB(DSP_READ);
-}									
+    return INB (DSP_READ);
+}
 
-static int dsp_ini2(void)
+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");
+  /* 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;
+   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(2)) {
-    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)
+   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));
+  DEB (printk ("dsp_set_speed(%d)\n", mode));
   if (mode)
-  {
-    if (mode < 5000) mode = 5000;
-    if (mode > 44100) mode = 44100;
-    dsp_current_speed=mode;
-  }
+    {
+      if (mode < 5000)
+	mode = 5000;
+      if (mode > 44100)
+	mode = 44100;
+      dsp_current_speed = mode;
+    }
   return mode;
 }
 
-static int dsp_set_stereo(int mode)
+static int
+dsp_set_stereo (int mode)
 {
-DEB(printk("dsp_set_stereo(%d)\n",mode));
+  DEB (printk ("dsp_set_stereo(%d)\n", mode));
 
-  dsp_stereo=mode;
+  dsp_stereo = mode;
 
   return mode;
 }
 
-static int dsp_set_bits(int arg) {
-DEB(printk("dsp_set_bits(%d)\n",arg));
+static int
+dsp_set_bits (int arg)
+{
+  DEB (printk ("dsp_set_bits(%d)\n", arg));
 
   if (arg)
-  switch(arg) {
-  case 8:
-    dsp_16bit=0; break;
-  case 16:
-    dsp_16bit=1; break;
-  default:
-    return RET_ERROR(EINVAL);
-  }
-  return dsp_16bit? 16:8;
+    switch (arg)
+      {
+      case 8:
+	dsp_16bit = 0;
+	break;
+      case 16:
+	dsp_16bit = 1;
+	break;
+      default:
+	return RET_ERROR (EINVAL);
+      }
+  return dsp_16bit ? 16 : 8;
 }
 
 static int
-sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg,int local)
-{
-  switch (cmd) {
-  case SOUND_PCM_WRITE_RATE:
-    if(local)
-      return dsp_set_speed(arg);
-    return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg)));
-    
-  case SOUND_PCM_READ_RATE:
-    if(local)
-      return dsp_current_speed;
-    return IOCTL_OUT (arg, dsp_current_speed);
-    
-  case SNDCTL_DSP_STEREO:
-    if (local)
-      return dsp_set_stereo(arg);
-    return IOCTL_OUT (arg, dsp_set_stereo(IOCTL_IN(arg)));
-    
-  case SOUND_PCM_WRITE_CHANNELS:
-    if (local)
-      return dsp_set_stereo(arg-1)+1;
-    return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
-    
-  case SOUND_PCM_READ_CHANNELS:
-    if (local)
-      return dsp_stereo+1;
-    return IOCTL_OUT (arg, dsp_stereo+1);
-    
-  case SNDCTL_DSP_SAMPLESIZE:
-    if (local)
-      return dsp_set_bits (arg);
-    return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
-    
-  case SOUND_PCM_READ_BITS:
-    if (local)
-      return dsp_16bit?16:8;
-    return IOCTL_OUT (arg, dsp_16bit?16:8);
-    
-  case SOUND_PCM_WRITE_FILTER:	/* NOT YET IMPLEMENTED */
-    if (IOCTL_IN (arg) > 1)
-      return IOCTL_OUT (arg, RET_ERROR (EINVAL));
-  default:
-    return RET_ERROR (EINVAL);
-  }
-  
+sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+  switch (cmd)
+    {
+    case SOUND_PCM_WRITE_RATE:
+      if (local)
+	return dsp_set_speed (arg);
+      return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_RATE:
+      if (local)
+	return dsp_current_speed;
+      return IOCTL_OUT (arg, dsp_current_speed);
+
+    case SNDCTL_DSP_STEREO:
+      if (local)
+	return dsp_set_stereo (arg);
+      return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
+
+    case SOUND_PCM_WRITE_CHANNELS:
+      if (local)
+	return dsp_set_stereo (arg - 1) + 1;
+      return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
+
+    case SOUND_PCM_READ_CHANNELS:
+      if (local)
+	return dsp_stereo + 1;
+      return IOCTL_OUT (arg, dsp_stereo + 1);
+
+    case SNDCTL_DSP_SAMPLESIZE:
+      if (local)
+	return dsp_set_bits (arg);
+      return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_BITS:
+      if (local)
+	return dsp_16bit ? 16 : 8;
+      return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
+
+    case SOUND_PCM_WRITE_FILTER:	/* NOT YET IMPLEMENTED */
+      if (IOCTL_IN (arg) > 1)
+	return IOCTL_OUT (arg, RET_ERROR (EINVAL));
+    default:
+      return RET_ERROR (EINVAL);
+    }
+
   return RET_ERROR (EINVAL);
 }
 
 static int
 sb16_dsp_open (int dev, int mode)
 {
-  int retval;
+  int             retval;
 
-DEB(printk("sb16_dsp_open()\n"));
+  DEB (printk ("sb16_dsp_open()\n"));
   if (!sb16_dsp_ok)
     {
       printk ("SB16 Error: SoundBlaster board not installed\n");
-      return RET_ERROR(ENXIO);
+      return RET_ERROR (ENXIO);
     }
 
   if (intr_active)
-    return RET_ERROR(EBUSY);
+    return RET_ERROR (EBUSY);
 
   retval = sb_get_irq ();
-  if (retval<0)
+  if (retval < 0)
     return retval;
 
   if (ALLOC_DMA_CHN (dma8))
     {
       printk ("SB16: Unable to grab DMA%d\n", dma8);
-      sb_free_irq();
-      return RET_ERROR(EBUSY);
+      sb_free_irq ();
+      return RET_ERROR (EBUSY);
     }
 
   if (dma16 != dma8)
-  if (ALLOC_DMA_CHN (dma16))
-    {
-      printk ("SB16: Unable to grab DMA%d\n", dma16);
-      sb_free_irq();
-      RELEASE_DMA_CHN (dma8);
-      return RET_ERROR(EBUSY);
-    }
+    if (ALLOC_DMA_CHN (dma16))
+      {
+	printk ("SB16: Unable to grab DMA%d\n", dma16);
+	sb_free_irq ();
+	RELEASE_DMA_CHN (dma8);
+	return RET_ERROR (EBUSY);
+      }
 
-  dsp_ini2();
+  dsp_ini2 ();
 
   irq_mode = IMODE_NONE;
   dsp_busy = 1;
@@ -294,15 +314,16 @@
 sb16_dsp_close (int dev)
 {
   unsigned long   flags;
-DEB(printk("sb16_dsp_close()\n"));
-  sb_dsp_command01(0xd9);
-  sb_dsp_command01(0xd5);
+
+  DEB (printk ("sb16_dsp_close()\n"));
+  sb_dsp_command01 (0xd9);
+  sb_dsp_command01 (0xd5);
 
   DISABLE_INTR (flags);
   RELEASE_DMA_CHN (dma8);
 
   if (dma16 != dma8)
-     RELEASE_DMA_CHN (dma16);
+    RELEASE_DMA_CHN (dma16);
   sb_free_irq ();
   dsp_cleanup ();
   dsp_busy = 0;
@@ -310,7 +331,7 @@
 }
 
 static void
-sb16_dsp_output_block (int dev, unsigned long buf, int count,int intrflag, int dma_restart)
+sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
 {
   unsigned long   flags, cnt;
 
@@ -320,51 +341,54 @@
   cnt--;
 
 #ifdef DEB_DMARES
-  printk("output_block: %x %d %d\n",buf,count,intrflag);
-  if(intrflag) {
-    int pos,chan=sound_dsp_dmachan[dev];
-    DISABLE_INTR (flags);
-    clear_dma_ff(chan);
-    disable_dma(chan);
-    pos=get_dma_residue(chan);
-    enable_dma(chan);
-    RESTORE_INTR (flags);
-    printk("dmapos=%d %x\n",pos,pos);
-  }
+  printk ("output_block: %x %d %d\n", buf, count, intrflag);
+  if (intrflag)
+    {
+      int             pos, chan = sound_dsp_dmachan[dev];
+
+      DISABLE_INTR (flags);
+      clear_dma_ff (chan);
+      disable_dma (chan);
+      pos = get_dma_residue (chan);
+      enable_dma (chan);
+      RESTORE_INTR (flags);
+      printk ("dmapos=%d %x\n", pos, pos);
+    }
 #endif
   if (sound_dma_automode[dev] &&
       intrflag &&
-      cnt == dsp_count) {
-    irq_mode = IMODE_OUTPUT;
-    intr_active = 1;
-    return;			/* Auto mode on. No need to react */
-  }
+      cnt == dsp_count)
+    {
+      irq_mode = IMODE_OUTPUT;
+      intr_active = 1;
+      return;			/* Auto mode on. No need to react */
+    }
   DISABLE_INTR (flags);
-  
+
   if (dma_restart)
-  {
-     sb16_dsp_halt(dev);
-     DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
-  }
+    {
+      sb16_dsp_halt (dev);
+      DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+    }
   sb_dsp_command (0x41);
-  sb_dsp_command ((unsigned char)((dsp_current_speed >> 8) & 0xff));
-  sb_dsp_command ((unsigned char)(dsp_current_speed & 0xff));
-  sb_dsp_command ((unsigned char)(dsp_16bit ? 0xb6 : 0xc6));
-  sb_dsp_command ((unsigned char)((dsp_stereo ? 0x20 : 0) + 
-				  (dsp_16bit ? 0x10:0)));
-  sb_dsp_command01 ((unsigned char)(cnt&0xff));
-  sb_dsp_command ((unsigned char)(cnt>>8));
+  sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
+  sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
+  sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6));
+  sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
+				   (dsp_16bit ? 0x10 : 0)));
+  sb_dsp_command01 ((unsigned char) (cnt & 0xff));
+  sb_dsp_command ((unsigned char) (cnt >> 8));
   /* sb_dsp_command (0);
-  sb_dsp_command (0); */
-  
+     sb_dsp_command (0); */
+
   RESTORE_INTR (flags);
-  dsp_count=cnt;
+  dsp_count = cnt;
   irq_mode = IMODE_OUTPUT;
   intr_active = 1;
 }
 
 static void
-sb16_dsp_start_input (int dev, unsigned long buf, int count,int intrflag, int dma_restart)
+sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
 {
   unsigned long   flags, cnt;
 
@@ -374,46 +398,49 @@
   cnt--;
 
 #ifdef DEB_DMARES
-printk("start_input: %x %d %d\n",buf,count,intrflag);
-  if(intrflag) {
-    int pos,chan=sound_dsp_dmachan[dev];
-    DISABLE_INTR (flags);
-    clear_dma_ff(chan);
-    disable_dma(chan);
-    pos=get_dma_residue(chan);
-    enable_dma(chan);
-    RESTORE_INTR (flags);
-    printk("dmapos=%d %x\n",pos,pos);
-  }
+  printk ("start_input: %x %d %d\n", buf, count, intrflag);
+  if (intrflag)
+    {
+      int             pos, chan = sound_dsp_dmachan[dev];
+
+      DISABLE_INTR (flags);
+      clear_dma_ff (chan);
+      disable_dma (chan);
+      pos = get_dma_residue (chan);
+      enable_dma (chan);
+      RESTORE_INTR (flags);
+      printk ("dmapos=%d %x\n", pos, pos);
+    }
 #endif
   if (sound_dma_automode[dev] &&
       intrflag &&
-      cnt == dsp_count) {
-    irq_mode = IMODE_INPUT;
-    intr_active = 1;
-    return;			/* Auto mode on. No need to react */
-  }
+      cnt == dsp_count)
+    {
+      irq_mode = IMODE_INPUT;
+      intr_active = 1;
+      return;			/* Auto mode on. No need to react */
+    }
   DISABLE_INTR (flags);
-  
-  if (dma_restart) 
-  {
-      sb16_dsp_halt(dev);
+
+  if (dma_restart)
+    {
+      sb16_dsp_halt (dev);
       DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
-  }
+    }
 
   sb_dsp_command (0x42);
-  sb_dsp_command ((unsigned char)((dsp_current_speed >> 8) & 0xff));
-  sb_dsp_command ((unsigned char)(dsp_current_speed & 0xff));
-  sb_dsp_command ((unsigned char)(dsp_16bit ? 0xbe : 0xce));
-  sb_dsp_command ((unsigned char)((dsp_stereo ? 0x20 : 0) + 
-			(dsp_16bit ? 0x10:0)));
-  sb_dsp_command01 ((unsigned char)(cnt&0xff));
-  sb_dsp_command ((unsigned char)(cnt>>8));
-  
+  sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
+  sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
+  sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce));
+  sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
+				   (dsp_16bit ? 0x10 : 0)));
+  sb_dsp_command01 ((unsigned char) (cnt & 0xff));
+  sb_dsp_command ((unsigned char) (cnt >> 8));
+
   /* sb_dsp_command (0);
-  sb_dsp_command (0); */
+     sb_dsp_command (0); */
   RESTORE_INTR (flags);
-  dsp_count=cnt;
+  dsp_count = cnt;
   irq_mode = IMODE_INPUT;
   intr_active = 1;
 }
@@ -421,7 +448,7 @@
 static int
 sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
 {
-  sound_dsp_dmachan[my_dev] = dsp_16bit? dma16:dma8;
+  sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
   dsp_count = 0;
   dsp_cleanup ();
   return 0;
@@ -430,7 +457,7 @@
 static int
 sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
 {
-  sound_dsp_dmachan[my_dev] = dsp_16bit? dma16:dma8;
+  sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
   dsp_count = 0;
   dsp_cleanup ();
   return 0;
@@ -446,7 +473,7 @@
 static void
 sb16_dsp_reset (int dev)
 {
-  unsigned long flags;
+  unsigned long   flags;
 
   DISABLE_INTR (flags);
 
@@ -460,61 +487,52 @@
 sb16_dsp_halt (int dev)
 {
   if (dsp_16bit)
-   {
-     sb_dsp_command01(0xd9);
-     sb_dsp_command01(0xd5);
-   }
+    {
+      sb_dsp_command01 (0xd9);
+      sb_dsp_command01 (0xd5);
+    }
   else
-   {
-     sb_dsp_command01(0xda);
-     sb_dsp_command01(0xd0);
-   }
+    {
+      sb_dsp_command01 (0xda);
+      sb_dsp_command01 (0xd0);
+    }
 }
 
 static void
-set_irq_hw(int level) {
-  int ival;
-  switch(level) {
-  case 5:
-    ival=2; break;
-  case 7:
-    ival=4; break;
-  case 10:
-    ival=8; break;
-  default:
-    printk("SB16_IRQ_LEVEL %d does not exist\n",level);
-    return;
-  }
-  sb_setmixer(IRQ_NR,ival);
+set_irq_hw (int level)
+{
+  int             ival;
+
+  switch (level)
+    {
+    case 5:
+      ival = 2;
+      break;
+    case 7:
+      ival = 4;
+      break;
+    case 10:
+      ival = 8;
+      break;
+    default:
+      printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
+      return;
+    }
+  sb_setmixer (IRQ_NR, ival);
 }
 
 long
 sb16_dsp_init (long mem_start, struct address_info *hw_config)
 {
-  int             i, major, minor;
-
-  major = minor = 0;
-  sb_dsp_command (0xe1);		/* Get version */
-  
-  for (i = 1000; i; i--) {
-    if (INB (DSP_DATA_AVAIL) & 0x80)
-      {			/* wait for Data Ready */
-	if (major == 0)
-	  major = INB (DSP_READ);
-	else
-	  {
-	    minor = INB (DSP_READ);
-	    break;
-	  }
-      }
-  }
+  if (sbc_major < 4)
+    return mem_start;
 
-#ifndef SCO 
-  sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", major, minor);
+#ifndef SCO
+  sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
 #endif
-  
+
   printk (" <%s>", sb16_dsp_operations.name);
-  
+
   if (num_dspdevs < MAX_DSP_DEV)
     {
       dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations;
@@ -537,47 +555,37 @@
   if (sb16_dsp_ok)
     return 1;			/* Already initialized */
 
-  if (!(sb_config=sound_getconf(SNDCARD_SB)))
-  {
-  	printk("SB16 Error: Plain SB not configured\n");
-  	return 0;
-  }
-
-  if (sbc_base != hw_config->io_base)
-     printk("Warning! SB16 I/O != SB I/O\n");
+  if (!(sb_config = sound_getconf (SNDCARD_SB)))
+    {
+      printk ("SB16 Error: Plain SB not configured\n");
+      return 0;
+    }
 
   /* sb_setmixer(OPSW,0xf);
-  if(sb_getmixer(OPSW)!=0xf)
-    return 0; */
-  
+     if(sb_getmixer(OPSW)!=0xf)
+     return 0; */
+
   if (!sb_reset_dsp ())
     return 0;
 
-  if (hw_config->irq != sb_config->irq)
-  {
-     printk("SB16 Error: Invalid IRQ number %d/%d\n",
-     	     sb_config->irq, hw_config->irq);
-     return 0;
-  }
-
   if (hw_config->dma < 4)
-     if (hw_config->dma != sb_config->dma)
-     {
-     	printk("SB16 Error: Invalid DMA channel %d/%d\n",
-     		sb_config->dma, hw_config->dma);
-     	return 0;
-     }
+    if (hw_config->dma != sb_config->dma)
+      {
+	printk ("SB16 Error: Invalid DMA channel %d/%d\n",
+		sb_config->dma, hw_config->dma);
+	return 0;
+      }
 
   dma16 = hw_config->dma;
   dma8 = sb_config->dma;
-  set_irq_hw(hw_config->irq);
-  sb_setmixer(DMA_NR, (1<<hw_config->dma) | (1<<sb_config->dma));
+  set_irq_hw (sb_config->irq);
+  sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
 
-  DEB(printk ("SoundBlaster 16: IRQ %d DMA %d OK\n",hw_config->irq,hw_config->dma));
-  
-/*
-  dsp_showmessage(0xe3,99);
-*/
+  DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
+
+  /*
+   dsp_showmessage(0xe3,99);
+ */
   sb16_dsp_ok = 1;
   return 1;
 }
@@ -585,24 +593,26 @@
 void
 sb16_dsp_interrupt (int unused)
 {
-    int data;
-    data = INB (DSP_DATA_AVL16);	/* Interrupt acknowledge */
+  int             data;
 
-    if (intr_active)
-      switch (irq_mode)
-	{
-	case IMODE_OUTPUT:
-	  intr_active = 0;
-	  DMAbuf_outputintr (my_dev, 1);
-	  break;
-	  
-	case IMODE_INPUT:
-	  intr_active = 0;
-	  DMAbuf_inputintr (my_dev);
-	  break;
-	  
-	default:
-	  printk ("SoundBlaster: Unexpected interrupt\n");
-	}
+  data = INB (DSP_DATA_AVL16);	/* Interrupt acknowledge */
+
+  if (intr_active)
+    switch (irq_mode)
+      {
+      case IMODE_OUTPUT:
+	intr_active = 0;
+	DMAbuf_outputintr (my_dev, 1);
+	break;
+
+      case IMODE_INPUT:
+	intr_active = 0;
+	DMAbuf_inputintr (my_dev);
+	break;
+
+      default:
+	printk ("SoundBlaster: Unexpected interrupt\n");
+      }
 }
+
 #endif
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c
--- v1.1.9/linux/drivers/sound/sb16_midi.c	Fri Dec  3 04:10:08 1993
+++ linux/drivers/sound/sb16_midi.c	Fri Apr 15 11:03:26 1994
@@ -1,10 +1,10 @@
 /*
  * sound/sb16_midi.c
- * 
+ *
  * The low level driver for the MPU-401 UART emulation of the SB16.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
@@ -58,26 +58,19 @@
 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)
 {
-  int             count;
-
-  count = 10;
-
-  while (count)			/* Not timed out */
-    if (input_avail ())
-      {
-	unsigned char   c = sb16midi_read ();
 
-	count = 100;
+  while (input_avail ())
+    {
+      unsigned char   c = sb16midi_read ();
 
-	if (sb16midi_opened & OPEN_READ)
-	  midi_input_intr (my_dev, c);
-      }
-    else
-      while (!input_avail () && count)
-	count--;
+      if (sb16midi_opened & OPEN_READ)
+	midi_input_intr (my_dev, c);
+    }
 }
 
 void
@@ -87,35 +80,10 @@
     sb16midi_input_loop ();
 }
 
-/*
- * It looks like there is no input interrupts in the UART mode. Let's try
- * polling.
- */
-
-static void
-poll_sb16midi (unsigned long dummy)
-{
-  unsigned long   flags;
-
-  DEFINE_TIMER(sb16midi_timer, poll_sb16midi);
-
-  if (!(sb16midi_opened & OPEN_READ))
-    return;			/* No longer required */
-
-  DISABLE_INTR (flags);
-
-  if (input_avail ())
-    sb16midi_input_loop ();
-
-  ACTIVATE_TIMER(sb16midi_timer, poll_sb16midi, 1); /* Come back later */
-
-  RESTORE_INTR (flags);
-}
-
 static int
 sb16midi_open (int dev, int mode,
-	     void            (*input) (int dev, unsigned char data),
-	     void            (*output) (int dev)
+	       void            (*input) (int dev, unsigned char data),
+	       void            (*output) (int dev)
 )
 {
   if (sb16midi_opened)
@@ -127,7 +95,6 @@
 
   midi_input_intr = input;
   sb16midi_opened = mode;
-  poll_sb16midi (0);		/* Enable input polling */
 
   return 0;
 }
@@ -299,6 +266,8 @@
   int             ok = 0;
 
   sb16midi_base = hw_config->io_base;
+  if (sbc_major < 4)
+    return 0;			/* SB16 not detected */
 
   if (sb_get_irq () < 0)
     return 0;
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v1.1.9/linux/drivers/sound/sb_card.c	Fri Dec 10 00:24:43 1993
+++ linux/drivers/sound/sb_card.c	Fri Apr 15 11:03:26 1994
@@ -1,10 +1,10 @@
 /*
  * sound/sb_card.c
- * 
+ *
  * Detection routine for the SoundBlaster cards.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
--- v1.1.9/linux/drivers/sound/sb_dsp.c	Sat Jan  8 14:35:09 1994
+++ linux/drivers/sound/sb_dsp.c	Tue Apr 19 12:07:17 1994
@@ -1,10 +1,10 @@
 /*
  * sound/sb_dsp.c
- * 
+ *
  * The low level driver for the SoundBlaster DSP chip.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,11 @@
  * 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 code to support Sound Galaxy NX Pro
+ *
  */
 
 #include "sound_config.h"
@@ -35,8 +39,9 @@
 #include "sb_mixer.h"
 #undef SB_TEST_IRQ
 
-int      sbc_base = 0;
+int             sbc_base = 0;
 static int      sbc_irq = 0;
+static int	open_mode=0;
 
 /*
  * The DSP channel can be used either for input or output. Variable
@@ -46,32 +51,33 @@
  * 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;
-static int	major=1, minor=0;	/* DSP version */
-static int	dsp_stereo = 0;
+int             sb_dsp_highspeed = 0;
+int             sbc_major = 1;
+int             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;
+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_dsp_busy = 0;
+int             sb_midi_mode = NORMAL_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;	/* IMODE_INPUT, IMODE_OUTPUT
+
 						 * or IMODE_NONE */
 static volatile int irq_ok = 0;
 
-int      sb_dsp_model = 1;	/* 1=SB, 2=SB Pro */
-int      sb_duplex_midi = 0;
+int             sb_duplex_midi = 0;
 static int      my_dev = 0;
 
-volatile int sb_intr_active = 0;
+volatile int    sb_intr_active = 0;
 
 static int      dsp_speed (int);
 static int      dsp_set_stereo (int mode);
-int      sb_dsp_command (unsigned char val);
+int             sb_dsp_command (unsigned char val);
 
 #if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
 
@@ -80,9 +86,10 @@
 int
 sb_dsp_command (unsigned char val)
 {
-  int             i, limit;
+  int             i;
+  unsigned long   limit;
 
-  limit = GET_TIME () + 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
@@ -109,7 +116,7 @@
 void
 sbintr (int unit)
 {
-  int             status, data;
+  int             status;
 
 #ifndef EXCLUDE_SBPRO
   if (sb16)
@@ -117,10 +124,12 @@
       unsigned char   src = sb_getmixer (IRQ_STAT);	/* Interrupt source register */
 
 #ifndef EXCLUDE_SB16
-      if (src & 3) sb16_dsp_interrupt(unit);
+      if (src & 3)
+	sb16_dsp_interrupt (unit);
 
 #ifndef EXCLUDE_MIDI
-      if (src & 4) sb16midiintr (unit);			/* MPU401 interrupt */
+      if (src & 4)
+	sb16midiintr (unit);	/* MPU401 interrupt */
 #endif
 
 #endif
@@ -152,10 +161,7 @@
 	break;
 
       case IMODE_MIDI:
-	printk ("+");
-	data = INB (DSP_READ);
-	printk ("%x", data);
-
+	sb_midi_interrupt (unit);
 	break;
 
       default:
@@ -163,29 +169,32 @@
       }
 }
 
-static int sb_irq_usecount = 0;
+static int      sb_irq_usecount = 0;
 
 int
-sb_get_irq(void)
+sb_get_irq (void)
 {
-	int ok;
+  int             ok;
 
-	if (!sb_irq_usecount)
-	  if ((ok=snd_set_irq_handler(sbc_irq, sbintr))<0) return ok;
+  if (!sb_irq_usecount)
+    if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0)
+      return ok;
 
-	sb_irq_usecount++;
+  sb_irq_usecount++;
 
-	return 0; 
+  return 0;
 }
 
-void 
-sb_free_irq(void)
+void
+sb_free_irq (void)
 {
-	if (!sb_irq_usecount) return;
+  if (!sb_irq_usecount)
+    return;
 
-	sb_irq_usecount--;
+  sb_irq_usecount--;
 
-	if (!sb_irq_usecount) snd_release_irq(sbc_irq);
+  if (!sb_irq_usecount)
+    snd_release_irq (sbc_irq);
 }
 
 int
@@ -227,17 +236,31 @@
 {
   unsigned char   tconst;
   unsigned long   flags;
+  int             max_speed = 44100;
 
   if (speed < 4000)
     speed = 4000;
 
-  if (speed > 44100)
-    speed = 44100;		/* Invalid speed */
+  /*
+ * Older SB models don't support higher speeds than 22050.
+ */
+
+  if (sbc_major < 2 ||
+      (sbc_major == 2 && sbc_minor == 0))
+    max_speed = 22050;
 
-  if (sb_dsp_model == 1 && speed > 22050)
-    speed = 22050;
-  /* SB Classic doesn't support higher speed */
+  /*
+ * SB models earlier than SB Pro have low limit for the input speed.
+ */
+  if (open_mode != OPEN_WRITE)	/* Recording is possible */
+    if (sbc_major < 3)		/* Limited input speed with these cards */
+      if (sbc_major == 2 && sbc_minor > 0)
+	max_speed = 15000;
+      else
+	max_speed = 13000;
 
+  if (speed > max_speed)
+    speed = max_speed;		/* Invalid speed */
 
   if (dsp_stereo && speed > 22050)
     speed = 22050;
@@ -256,10 +279,10 @@
 
   if (speed > 22050)
     {				/* High speed mode */
-      int tmp;
+      int             tmp;
 
-      tconst = (unsigned char) ((65536 - 
-      				((256000000+speed/2) / speed)) >> 8);
+      tconst = (unsigned char) ((65536 -
+				 ((256000000 + speed / 2) / speed)) >> 8);
       sb_dsp_highspeed = 1;
 
       DISABLE_INTR (flags);
@@ -268,22 +291,22 @@
       RESTORE_INTR (flags);
 
       tmp = 65536 - (tconst << 8);
-      speed = (256000000+tmp/2) / tmp;
+      speed = (256000000 + tmp / 2) / tmp;
     }
   else
     {
-      int tmp;
+      int             tmp;
 
       sb_dsp_highspeed = 0;
-      tconst = (256 - ((1000000+speed/2) / speed)) & 0xff;
+      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);
 
       tmp = 256 - tconst;
-      speed = (1000000+tmp/2) / tmp;
+      speed = (1000000 + tmp / 2) / tmp;
     }
 
   if (dsp_stereo)
@@ -301,7 +324,7 @@
 #ifdef EXCLUDE_SBPRO
   return 0;
 #else
-  if (sb_dsp_model == 1 || sb16)
+  if (sbc_major < 3 || sb16)
     return 0;			/* Sorry no stereo */
 
   if (mode && sb_midi_busy)
@@ -316,7 +339,7 @@
 }
 
 static void
-sb_dsp_output_block (int dev, unsigned long buf, int count, 
+sb_dsp_output_block (int dev, unsigned long buf, int count,
 		     int intrflag, int restart_dma)
 {
   unsigned long   flags;
@@ -334,11 +357,11 @@
   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 ((unsigned char) (count & 0xff));
+	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+	  sb_dsp_command (0x91);/* High speed 8 bit DAC */
 	}
       else
 	printk ("SB Error: Unable to start (high speed) DAC\n");
@@ -347,10 +370,10 @@
   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));
+	  sb_dsp_command ((unsigned char) (count & 0xff));
+	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
 	}
       else
 	printk ("SB Error: Unable to start DAC\n");
@@ -380,11 +403,11 @@
   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 ((unsigned char) (count & 0xff));
+	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+	  sb_dsp_command (0x99);/* High speed 8 bit ADC */
 	}
       else
 	printk ("SB Error: Unable to start (high speed) ADC\n");
@@ -393,10 +416,10 @@
   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));
+	  sb_dsp_command ((unsigned char) (count & 0xff));
+	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
 	}
       else
 	printk ("SB Error: Unable to start ADC\n");
@@ -418,16 +441,16 @@
   dsp_cleanup ();
   dsp_speaker (OFF);
 
-  if (major == 3)	/* SB Pro */
-  {
-    if (dsp_stereo)
-       sb_dsp_command(0xa8);
-    else
-       sb_dsp_command(0xa0);
+  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;
 }
 
@@ -438,12 +461,12 @@
   dsp_speaker (ON);
 
 #ifndef EXCLUDE_SBPRO
-  if (major == 3)	/* SB Pro */
-  {
-    sb_mixer_set_stereo(dsp_stereo);
-    dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels
-				   * changes */
-  }
+  if (sbc_major == 3)		/* SB Pro */
+    {
+      sb_mixer_set_stereo (dsp_stereo);
+      dsp_speed (dsp_current_speed);	/* Speed must be recalculated if #channels
+					   * changes */
+    }
 #endif
   return 0;
 }
@@ -457,7 +480,7 @@
 verify_irq (void)
 {
 #if 0
-  DEFINE_WAIT_QUEUE(testq, testf);
+  DEFINE_WAIT_QUEUE (testq, testf);
 
   irq_ok = 0;
 
@@ -470,11 +493,11 @@
 
   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);
+  DO_SLEEP (testq, testf, HZ / 5);
 
-  sb_free_irq();
+  sb_free_irq ();
 
   if (!irq_ok)
     {
@@ -506,13 +529,12 @@
 
   if (!irq_verified)
     {
-  	verify_irq();
-  	irq_verified = 1;
+      verify_irq ();
+      irq_verified = 1;
     }
-  else
-    if (!irq_ok)
-       printk("SB Warning: Incorrect IRQ setting %d\n",
-  	      sbc_irq);
+  else if (!irq_ok)
+    printk ("SB Warning: Incorrect IRQ setting %d\n",
+	    sbc_irq);
 
   retval = sb_get_irq ();
   if (retval)
@@ -528,6 +550,7 @@
   sb_irq_mode = IMODE_NONE;
 
   sb_dsp_busy = 1;
+  open_mode = mode;
 
   return 0;
 }
@@ -541,6 +564,7 @@
   dsp_speaker (OFF);
   sb_dsp_busy = 0;
   sb_dsp_highspeed = 0;
+  open_mode = 0;
 }
 
 static int
@@ -562,7 +586,7 @@
 
     case SOUND_PCM_WRITE_CHANNELS:
       if (local)
-         return dsp_set_stereo (arg - 1) + 1;
+	return dsp_set_stereo (arg - 1) + 1;
       return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
       break;
 
@@ -605,6 +629,7 @@
   DISABLE_INTR (flags);
 
   sb_reset_dsp ();
+  dsp_speed (dsp_current_speed);
   dsp_cleanup ();
 
   RESTORE_INTR (flags);
@@ -631,6 +656,7 @@
 static struct audio_operations sb_dsp_operations =
 {
   "SoundBlaster",
+  NOTHING_SPECIAL,
   sb_dsp_open,
   sb_dsp_close,
   sb_dsp_output_block,
@@ -650,80 +676,85 @@
 sb_dsp_init (long mem_start, struct address_info *hw_config)
 {
   int             i;
+  int             prostat = 0;
 
-  major = minor = 0;
-  sb_dsp_command (0xe1);		/* Get version */
+  sbc_major = sbc_minor = 0;
+  sb_dsp_command (0xe1);	/* Get version */
 
   for (i = 1000; i; i--)
     {
       if (INB (DSP_DATA_AVAIL) & 0x80)
 	{			/* wait for Data Ready */
-	  if (major == 0)
-	    major = INB (DSP_READ);
+	  if (sbc_major == 0)
+	    sbc_major = INB (DSP_READ);
 	  else
 	    {
-	      minor = INB (DSP_READ);
+	      sbc_minor = INB (DSP_READ);
 	      break;
 	    }
 	}
     }
 
-      if (major == 2 || major == 3)
-	sb_duplex_midi = 1;
+  if (sbc_major == 2 || sbc_major == 3)	/* SB 2.0 or SB Pro */
+    sb_duplex_midi = 1;
 
-      if (major == 4)
-	sb16 = 1;
+  if (sbc_major == 4)
+    sb16 = 1;
 
-      if (major >= 3)
-	sb_dsp_model = 2;
-
 #ifndef EXCLUDE_SBPRO
-      if (major >= 3)
-         sb_mixer_init(major);
+  if (sbc_major >= 3 ||
+      (sbc_major == 2 && sbc_minor == 1))	/* Sound Galaxy ??? */
+    prostat = sb_mixer_init (sbc_major);
 #endif
 
 #ifndef EXCLUDE_YM3812
-      if (major > 3 || (major == 3 && minor > 0))	/* SB Pro2 or later */
-	{
-	  enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
-	}
+  if (sbc_major > 3 ||
+      (sbc_major == 3 && INB (0x388) == 0x00))	/* Non OPL-3 should return 0x06 */
+    enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
 #endif
 
-    if (major >= 3)
-      {
+  if (sbc_major >= 3)
+    {
 #ifndef SCO
-      	sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", major, minor);
+      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);
+	}
 #endif
-      }
-    else
-      {
+    }
+  else
+    {
 #ifndef SCO
-    	sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", major, minor);
+      sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
 #endif
-      }
+    }
 
   printk (" <%s>", sb_dsp_operations.name);
 
 #ifndef EXCLUDE_AUDIO
-#  if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
-  if (!sb16)	/* There is a better driver for SB16	*/
-#  endif
-  if (num_dspdevs < MAX_DSP_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;
-    }
-  else
-    printk ("SB: Too many DSP devices available\n");
+#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+  if (!sb16)			/* There is a better driver for SB16    */
+#endif
+    if (num_dspdevs < MAX_DSP_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;
+      }
+    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 */
-	sb_midi_init(major);
+    sb_midi_init (sbc_major);
 #endif
 
   sb_dsp_ok = 1;
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c
--- v1.1.9/linux/drivers/sound/sb_midi.c	Thu Dec  2 11:56:16 1993
+++ linux/drivers/sound/sb_midi.c	Fri Apr 15 11:03:28 1994
@@ -1,10 +1,10 @@
 /*
  * sound/sb_dsp.c
- * 
+ *
  * The low level driver for the SoundBlaster DS chips.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
@@ -49,11 +49,16 @@
 extern int      sb_dsp_busy;
 extern int      sb_dsp_highspeed;
 
-extern volatile int sb_irq_mode;	/* IMODE_INPUT, IMODE_OUTPUT
+extern volatile int sb_irq_mode;/* IMODE_INPUT, IMODE_OUTPUT
+
 					 * or IMODE_NONE */
-extern int      sb_dsp_model;	/* 1=SB, 2=SB Pro */
 extern int      sb_duplex_midi;
 extern int      sb_intr_active;
+extern int      sbc_base;
+
+static int      input_opened = 0;
+static void     (*midi_input_intr) (int dev, unsigned char data);
+static int      my_dev = 0;
 
 static int
 sb_midi_open (int dev, int mode,
@@ -72,7 +77,7 @@
   if (mode != OPEN_WRITE && !sb_duplex_midi)
     {
       if (num_midis == 1)
-	printk ("SoundBlaster: Midi input not currently supported\n");
+	printk ("SoundBlaster: MIDI input not supported with plain SB\n");
       return RET_ERROR (EPERM);
     }
 
@@ -96,6 +101,9 @@
 
       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 */
       sb_intr_active = 1;
@@ -105,6 +113,9 @@
 	  sb_reset_dsp ();
 	  return 0;		/* IRQ not free */
 	}
+      input_opened = 1;
+      my_dev = dev;
+      midi_input_intr = input;
     }
 
   sb_midi_busy = 1;
@@ -122,6 +133,7 @@
     }
   sb_intr_active = 0;
   sb_midi_busy = 0;
+  input_opened = 0;
 }
 
 static int
@@ -174,6 +186,21 @@
   return RET_ERROR (EPERM);
 }
 
+void
+sb_midi_interrupt (int dummy)
+{
+  unsigned long   flags;
+  unsigned char   data;
+
+  DISABLE_INTR (flags);
+
+  data = INB (DSP_READ);
+  if (input_opened)
+    midi_input_intr (my_dev, data);
+
+  RESTORE_INTR (flags);
+}
+
 static struct midi_operations sb_midi_operations =
 {
   {"SoundBlaster", 0, 0, SNDCARD_SB},
@@ -189,7 +216,7 @@
 };
 
 void
-sb_midi_init(int model)
+sb_midi_init (int model)
 {
   midi_devs[num_midis++] = &sb_midi_operations;
 }
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v1.1.9/linux/drivers/sound/sb_mixer.c	Fri Dec 10 01:19:23 1993
+++ linux/drivers/sound/sb_mixer.c	Fri Apr 15 11:03:29 1994
@@ -1,11 +1,11 @@
 
 /*
  * sound/sb_mixer.c
- * 
+ *
  * The low level mixer driver for the SoundBlaster Pro and SB16 cards.
- * 
+ *
  * 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
@@ -13,7 +13,7 @@
  * 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
@@ -25,7 +25,11 @@
  * 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 code to support the Sound Galaxy NX Pro mixer.
+ *
  */
 
 #include "sound_config.h"
@@ -39,56 +43,69 @@
 
 extern int      sbc_base;
 
-static int mixer_initialized = 0;
+static int      mixer_initialized = 0;
 
-static int supported_rec_devices;
-static int supported_devices;
-static int recmask = 0;
-static int mixer_model;
-static int mixer_caps;
+static int      supported_rec_devices;
+static int      supported_devices;
+static int      recmask = 0;
+static int      mixer_model;
+static int      mixer_caps;
 static mixer_tab *iomap;
 
 void
 sb_setmixer (unsigned int port, unsigned int value)
 {
-  unsigned long flags;
+  unsigned long   flags;
 
-  DISABLE_INTR(flags);
-  OUTB ((unsigned char)(port & 0xff), MIXER_ADDR);	/* Select register */
+  DISABLE_INTR (flags);
+  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);	/* Select register */
   tenmicrosec ();
-  OUTB ((unsigned char)(value & 0xff), MIXER_DATA);
+  OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
   tenmicrosec ();
-  RESTORE_INTR(flags);
+  RESTORE_INTR (flags);
 }
 
 int
 sb_getmixer (unsigned int port)
 {
   int             val;
-  unsigned long flags;
+  unsigned long   flags;
 
-  DISABLE_INTR(flags);
-  OUTB ((unsigned char)(port & 0xff), MIXER_ADDR);	/* Select register */
+  DISABLE_INTR (flags);
+  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);	/* Select register */
   tenmicrosec ();
   val = INB (MIXER_DATA);
   tenmicrosec ();
-  RESTORE_INTR(flags);
+  RESTORE_INTR (flags);
 
   return val;
 }
 
 void
-sb_mixer_set_stereo(int mode)
+sb_mixer_set_stereo (int mode)
 {
-  if (!mixer_initialized) return;
+  if (!mixer_initialized)
+    return;
 
   sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
-			 | (mode ? STEREO_DAC : MONO_DAC)));
+			    | (mode ? STEREO_DAC : MONO_DAC)));
 }
 
+/*
+ * Returns:
+ *	0	No mixer detected.
+ *	1	Only a plain Sound Blaster Pro style mixer detected.
+ *	2	The Sound Galaxy NX Pro mixer detected.
+ */
 static int
 detect_mixer (void)
 {
+#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
@@ -102,95 +119,121 @@
   if (sb_getmixer (VOC_VOL) != 0x33)
     return 0;
 
-  return 1;
+#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;
 }
 
 static void
-change_bits(unsigned char *regval, int dev, int chn, int newval)
+change_bits (unsigned char *regval, int dev, int chn, int newval)
 {
-	unsigned char mask;
-	int shift;
+  unsigned char   mask;
+  int             shift;
 
-	mask = (1 << (*iomap)[dev][chn].nbits)-1;
-	newval = ((newval * mask) + 50) / 100;	/* Scale it */
+  mask = (1 << (*iomap)[dev][chn].nbits) - 1;
+  newval = ((newval * mask) + 50) / 100;	/* Scale it */
 
-	shift = (*iomap)[dev][chn].bitoffs-(*iomap)[dev][LEFT_CHN].nbits+1;
+  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
-sb_mixer_get(int dev)
+sb_mixer_get (int dev)
 {
-	if (!((1<<dev) & supported_devices)) 
-	   return RET_ERROR(EINVAL);
+  if (!((1 << dev) & supported_devices))
+    return RET_ERROR (EINVAL);
 
-	return levels[dev];
+  return levels[dev];
 }
 
 static int
 sb_mixer_set (int dev, int value)
 {
-	int left = value & 0x000000ff;
-	int right = (value & 0x0000ff00) >> 8;
+  int             left = value & 0x000000ff;
+  int             right = (value & 0x0000ff00) >> 8;
 
-	int regoffs;
-	unsigned char val;
+  int             regoffs;
+  unsigned char   val;
 
-	if (left > 100) left = 100;
-	if (right > 100) right = 100;
+  if (left > 100)
+    left = 100;
+  if (right > 100)
+    right = 100;
 
-	if (dev > 31) return RET_ERROR(EINVAL);
+  if (dev > 31)
+    return RET_ERROR (EINVAL);
 
-	if (!(supported_devices & (1 << dev)))	/* Not supported */
-	   return RET_ERROR(EINVAL);
+  if (!(supported_devices & (1 << dev)))	/* Not supported */
+    return RET_ERROR (EINVAL);
 
-	regoffs = (*iomap)[dev][LEFT_CHN].regno;
+  regoffs = (*iomap)[dev][LEFT_CHN].regno;
 
-	if (regoffs == 0)
-	   return RET_ERROR(EINVAL);
+  if (regoffs == 0)
+    return RET_ERROR (EINVAL);
 
-	val = sb_getmixer(regoffs);
-	change_bits(&val, dev, LEFT_CHN, left);
+  val = sb_getmixer (regoffs);
+  change_bits (&val, dev, LEFT_CHN, left);
 
-	levels[dev] = left|(left << 8);
+  levels[dev] = left | (left << 8);
 
-	if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */
-	{
-		sb_setmixer(regoffs, val);	/* Save the old one */
-		regoffs = (*iomap)[dev][RIGHT_CHN].regno;
+  if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)	/* Change register */
+    {
+      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 */
+      if (regoffs == 0)
+	return left | (left << 8);	/* Just left channel present */
 
-		val = sb_getmixer(regoffs);	/* Read the new one */
-	}
+      val = sb_getmixer (regoffs);	/* Read the new one */
+    }
 
-	change_bits(&val, dev, RIGHT_CHN, right);
-	sb_setmixer(regoffs, val);
+  change_bits (&val, dev, RIGHT_CHN, right);
+  sb_setmixer (regoffs, val);
 
-	levels[dev] = left | (right << 8);
-	return left | (right << 8);
+  levels[dev] = left | (right << 8);
+  return left | (right << 8);
 }
 
 static void
-set_recsrc(int src)
+set_recsrc (int src)
 {
-	sb_setmixer(RECORD_SRC, (sb_getmixer(RECORD_SRC)&~7) | (src&0x7));
+  sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
 }
 
 static int
-set_recmask(int mask)
+set_recmask (int mask)
 {
-      int devmask, i;
-      unsigned char regimageL, regimageR;
+  int             devmask, i;
+  unsigned char   regimageL, regimageR;
 
-      devmask = mask & supported_rec_devices;
+  devmask = mask & supported_rec_devices;
 
-      switch (mixer_model)
-      {
-      case 3:
+  switch (mixer_model)
+    {
+    case 3:
 
       if (devmask != SOUND_MASK_MIC &&
 	  devmask != SOUND_MASK_LINE &&
@@ -209,7 +252,7 @@
 	}
 
 
-      if (devmask ^ recmask)/* Input source changed */
+      if (devmask ^ recmask)	/* Input source changed */
 	{
 	  switch (devmask)
 	    {
@@ -233,23 +276,24 @@
 
       break;
 
-      case 4:
-	if (!devmask) devmask = SOUND_MASK_MIC;
-
-        regimageL = regimageR = 0;
-	for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
-	  if ((1<<i) & devmask)
+    case 4:
+      if (!devmask)
+	devmask = SOUND_MASK_MIC;
+
+      regimageL = regimageR = 0;
+      for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+	if ((1 << i) & devmask)
 	  {
 	    regimageL |= sb16_recmasks_L[i];
 	    regimageR |= sb16_recmasks_R[i];
 	  }
-	sb_setmixer(SB16_IMASK_L, regimageL);
-	sb_setmixer(SB16_IMASK_R, regimageR);
+      sb_setmixer (SB16_IMASK_L, regimageL);
+      sb_setmixer (SB16_IMASK_R, regimageR);
       break;
-      }
+    }
 
-      recmask = devmask;
-      return recmask;
+  recmask = devmask;
+  return recmask;
 }
 
 static int
@@ -258,43 +302,43 @@
   if (((cmd >> 8) & 0xff) == 'M')
     {
       if (cmd & IOC_IN)
-        switch (cmd & 0xff)
-        {
-        case SOUND_MIXER_RECSRC:
-           return IOCTL_OUT(arg, set_recmask(IOCTL_IN(arg)));
-           break;
-
-	default:
-	   return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
-        }
-      else
-	  switch (cmd & 0xff)	/* Return parameters */
-	    {
-
-	    case SOUND_MIXER_RECSRC:
-	      return IOCTL_OUT (arg, recmask);
-	      break;
-
-	    case SOUND_MIXER_DEVMASK:
-	      return IOCTL_OUT (arg, supported_devices);
-	      break;
-
-	    case SOUND_MIXER_STEREODEVS:
-	      return IOCTL_OUT (arg, supported_devices & 
-	                              ~(SOUND_MASK_MIC|SOUND_MASK_SPEAKER));
-	      break;
+	switch (cmd & 0xff)
+	  {
+	  case SOUND_MIXER_RECSRC:
+	    return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg)));
+	    break;
 
-	    case SOUND_MIXER_RECMASK:
-	      return IOCTL_OUT (arg, supported_rec_devices);
-	      break;
+	  default:
+	    return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
+	  }
+      else
+	switch (cmd & 0xff)	/* Return parameters */
+	  {
 
-	    case SOUND_MIXER_CAPS:
-	      return IOCTL_OUT (arg, mixer_caps);
-	      break;
+	  case SOUND_MIXER_RECSRC:
+	    return IOCTL_OUT (arg, recmask);
+	    break;
+
+	  case SOUND_MIXER_DEVMASK:
+	    return IOCTL_OUT (arg, supported_devices);
+	    break;
+
+	  case SOUND_MIXER_STEREODEVS:
+	    return IOCTL_OUT (arg, supported_devices &
+			      ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+	    break;
+
+	  case SOUND_MIXER_RECMASK:
+	    return IOCTL_OUT (arg, supported_rec_devices);
+	    break;
+
+	  case SOUND_MIXER_CAPS:
+	    return IOCTL_OUT (arg, mixer_caps);
+	    break;
 
-	    default:
-	      return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
-	    }
+	  default:
+	    return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
+	  }
     }
   else
     return RET_ERROR (EINVAL);
@@ -306,48 +350,73 @@
 };
 
 static void
-sb_mixer_reset(void)
+sb_mixer_reset (void)
 {
-  int i;
+  int             i;
 
   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
     sb_mixer_set (i, levels[i]);
-  set_recmask(SOUND_MASK_MIC);
+  set_recmask (SOUND_MASK_MIC);
 }
 
-void
-sb_mixer_init(int major_model)
+/*
+ * 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
+sb_mixer_init (int major_model)
 {
-	sb_setmixer(0x00, 0);	/* Reset mixer */
+  int             mixerstat;
+
+  sb_setmixer (0x00, 0);	/* Reset mixer */
 
-	if (!detect_mixer()) return;	/* No mixer. Why? */
+  mixerstat = detect_mixer ();
 
-	mixer_initialized = 1;
-	mixer_model = major_model;
+  if (!mixerstat)
+    return 0;			/* No mixer. Why? */
 
-        switch (major_model)
-        {
-        case 3:
-	  mixer_caps = SOUND_CAP_EXCL_INPUT;
+  mixer_initialized = 1;
+  mixer_model = major_model;
+
+  switch (major_model)
+    {
+    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;
-	  break;
-
-	case 4:
-	  mixer_caps = 0;
-	  supported_devices = SB16_MIXER_DEVICES;
-	  supported_rec_devices = SB16_RECORDING_DEVICES;
-	  iomap = &sb16_mix;
-	  break;
-
-	default:
-	  printk("SB Warning: Unsupported mixer type\n");
-	  return;
 	}
 
-        mixer_devs[num_mixers++] = &sb_mixer_operations;
-        sb_mixer_reset();
+      break;
+
+    case 4:
+      mixer_caps = 0;
+      supported_devices = SB16_MIXER_DEVICES;
+      supported_rec_devices = SB16_RECORDING_DEVICES;
+      iomap = &sb16_mix;
+      break;
+
+    default:
+      printk ("SB Warning: Unsupported mixer type\n");
+      return 0;
+    }
+
+  mixer_devs[num_mixers++] = &sb_mixer_operations;
+  sb_mixer_reset ();
+  return (mixerstat == 2);
 }
 
 #endif
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h
--- v1.1.9/linux/drivers/sound/sb_mixer.h	Tue Dec 14 03:04:54 1993
+++ linux/drivers/sound/sb_mixer.h	Wed Apr  6 11:30:20 1994
@@ -24,13 +24,29 @@
  * 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)
 
@@ -62,6 +78,13 @@
 #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 */
@@ -107,6 +130,23 @@
 MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
 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),
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v1.1.9/linux/drivers/sound/sequencer.c	Tue Dec 14 02:19:51 1993
+++ linux/drivers/sound/sequencer.c	Tue Apr 26 09:15:43 1994
@@ -1,10 +1,10 @@
 /*
  * sound/sequencer.c
- * 
+ *
  * The sequencer personality manager.
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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
@@ -46,7 +46,7 @@
 static int      midi_written[MAX_MIDI_DEV] =
 {0};
 
-long            seq_time = 0;	/* Reference point for the timer */
+unsigned long   seq_time = 0;	/* Reference point for the timer */
 
 #include "tuning.h"
 
@@ -77,6 +77,7 @@
 sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
   int             c = count, p = 0;
+  unsigned long   flags;
 
   dev = dev >> 4;
 
@@ -85,12 +86,22 @@
 
   while (c > 3)
     {
+      DISABLE_INTR (flags);
       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)
-	    return count - c;
+	    {
+	      RESTORE_INTR (flags);
+	      return count - c;
+	    }
 	}
 
       COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ);
@@ -99,6 +110,7 @@
 
       iqhead = (iqhead + 1) % SEQ_MAX_QUEUE;
       iqlen--;
+      RESTORE_INTR (flags);
     }
 
   return count - c;
@@ -118,11 +130,11 @@
   if (iqlen >= (SEQ_MAX_QUEUE - 1))
     return;			/* Overflow */
 
+  DISABLE_INTR (flags);
   memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ);
   iqlen++;
   iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
 
-  DISABLE_INTR (flags);
   if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag))
     {
       WAKE_UP (midi_sleeper, midi_sleep_flag);
@@ -327,6 +339,10 @@
       synth_devs[dev]->controller (dev, q[3], q[4], *(short *) &q[5]);
       break;
 
+    case SEQ_VOLMODE:
+      synth_devs[dev]->volume_method (dev, q[3]);
+      break;
+
     default:
       return RET_ERROR (EINVAL);
     }
@@ -346,7 +362,7 @@
       qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
       qlen--;
 
-      q = &queue[this_one*EV_SZ];
+      q = &queue[this_one * EV_SZ];
 
       switch (q[0])
 	{
@@ -463,87 +479,87 @@
 
 int
 sequencer_open (int dev, struct fileinfo *file)
-  {
-    int             retval, mode, i;
+{
+  int             retval, mode, i;
 
-    dev = dev >> 4;
-    mode = file->mode & O_ACCMODE;
+  dev = dev >> 4;
+  mode = file->mode & O_ACCMODE;
 
-    DEB (printk ("sequencer_open(dev=%d)\n", dev));
+  DEB (printk ("sequencer_open(dev=%d)\n", dev));
 
-    if (!sequencer_ok)
-      {
-	printk ("Soundcard: Sequencer not initialized\n");
-	return RET_ERROR (ENXIO);
-      }
+  if (!sequencer_ok)
+    {
+      printk ("Soundcard: Sequencer not initialized\n");
+      return RET_ERROR (ENXIO);
+    }
 
-    if (dev)			/* Patch manager device */
-      {
-	int             err;
+  if (dev)			/* Patch manager device */
+    {
+      int             err;
 
-	dev--;
-	if (pmgr_present[dev])
-	  return RET_ERROR (EBUSY);
-	if ((err = pmgr_open (dev)) < 0)
-	  return err;		/* Failed */
+      dev--;
+      if (pmgr_present[dev])
+	return RET_ERROR (EBUSY);
+      if ((err = pmgr_open (dev)) < 0)
+	return err;		/* Failed */
 
-	pmgr_present[dev] = 1;
-	return err;
-      }
+      pmgr_present[dev] = 1;
+      return err;
+    }
 
-    if (sequencer_busy)
-      {
-	printk ("Sequencer busy\n");
-	return RET_ERROR (EBUSY);
-      }
+  if (sequencer_busy)
+    {
+      printk ("Sequencer busy\n");
+      return RET_ERROR (EBUSY);
+    }
 
-    if (!(num_synths + num_midis))
-      return RET_ERROR (ENXIO);
+  if (!(num_synths + num_midis))
+    return RET_ERROR (ENXIO);
 
-    synth_open_mask = 0;
+  synth_open_mask = 0;
 
-    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 (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);
 
-    seq_time = GET_TIME ();
+  seq_time = GET_TIME ();
 
-    for (i = 0; i < num_midis; i++)
-      {
-	midi_opened[i] = 0;
-	midi_written[i] = 0;
-      }
+  for (i = 0; i < num_midis; i++)
+    {
+      midi_opened[i] = 0;
+      midi_written[i] = 0;
+    }
 
-    if (mode == OPEN_READ || mode == OPEN_READWRITE)
-      {				/* Initialize midi input devices */
-	if (!num_midis)
-	  {
-	    printk ("Sequencer: No Midi devices. Input not possible\n");
-	    return RET_ERROR (ENXIO);
-	  }
+  if (mode == OPEN_READ || mode == OPEN_READWRITE)
+    {				/* Initialize midi input devices */
+      if (!num_midis)
+	{
+	  printk ("Sequencer: No Midi devices. Input not possible\n");
+	  return RET_ERROR (ENXIO);
+	}
 
-	for (i = 0; i < num_midis; i++)
-	  {
-	    if ((retval = midi_devs[i]->open (i, mode,
+      for (i = 0; i < num_midis; i++)
+	{
+	  if ((retval = midi_devs[i]->open (i, mode,
 			 sequencer_midi_input, sequencer_midi_output)) >= 0)
-	      midi_opened[i] = 1;
-	  }
-      }
+	    midi_opened[i] = 1;
+	}
+    }
 
-    sequencer_busy = 1;
-    RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
-    RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
-    output_treshold = SEQ_MAX_QUEUE / 2;
+  sequencer_busy = 1;
+  RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
+  RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
+  output_treshold = SEQ_MAX_QUEUE / 2;
 
-    for (i = 0; i < num_synths; i++)
-      if (pmgr_present[i])
-	pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
+  for (i = 0; i < num_synths; i++)
+    if (pmgr_present[i])
+      pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
 
-    return 0;
-  }
+  return 0;
+}
 
 void
 seq_drain_midi_queues (void)
@@ -578,53 +594,53 @@
 
 void
 sequencer_release (int dev, struct fileinfo *file)
-  {
-    int             i;
-    int             mode = file->mode & O_ACCMODE;
+{
+  int             i;
+  int             mode = file->mode & O_ACCMODE;
 
-    dev = dev >> 4;
+  dev = dev >> 4;
 
-    DEB (printk ("sequencer_release(dev=%d)\n", dev));
+  DEB (printk ("sequencer_release(dev=%d)\n", dev));
 
-    if (dev)			/* Patch manager device */
-      {
-	dev--;
-	pmgr_release (dev);
-	pmgr_present[dev] = 0;
-	return;
-      }
+  if (dev)			/* Patch manager device */
+    {
+      dev--;
+      pmgr_release (dev);
+      pmgr_present[dev] = 0;
+      return;
+    }
 
-    /*
+  /*
      * Wait until the queue is empty
-     */
-
-    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_reset ();
-    if (mode != OPEN_READ)
-      seq_drain_midi_queues ();	/* Flush the all notes off messages */
+  while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
+    {
+      seq_sync ();
+    }
 
-    for (i = 0; i < num_midis; i++)
-      if (midi_opened[i])
-	midi_devs[i]->close (i);
+  if (mode != OPEN_READ)
+    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 */
 
-    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])
-	    synth_devs[i]->close (i);
+  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 (pmgr_present[i])
-	pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
+      if (synth_open_mask & (1 << i))	/* Actually opened */
+	if (synth_devs[i])
+	  synth_devs[i]->close (i);
+
+  for (i = 0; i < num_synths; i++)
+    if (pmgr_present[i])
+      pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
 
-    sequencer_busy = 0;
-  }
+  sequencer_busy = 0;
+}
 
 static int
 seq_sync (void)
@@ -686,8 +702,8 @@
       {
 	for (chn = 0; chn < 16; chn++)
 	  {
-	    midi_outc (i, 
-		(unsigned char)(0xb0 + (chn & 0xff))); /* Channel msg */
+	    midi_outc (i,
+		       (unsigned char) (0xb0 + (chn & 0xff)));	/* Channel msg */
 	    midi_outc (i, 0x7b);/* All notes off */
 	    midi_outc (i, 0);	/* Dummy parameter */
 	  }
@@ -1040,7 +1056,7 @@
   else if (octave > BASE_OCTAVE)
     note_freq <<= (octave - BASE_OCTAVE);
 
-  /* note_freq >>= 1;	 */
+  /* note_freq >>= 1;    */
 
   return note_freq;
 }
@@ -1049,7 +1065,7 @@
 compute_finetune (unsigned long base_freq, int bend, int range)
 {
   unsigned long   amount;
-  int             negative, semitones, cents;
+  int             negative, semitones, cents, multiplier = 1;
 
   if (!bend)
     return base_freq;
@@ -1073,13 +1089,20 @@
   if (bend > range)
     bend = range;
 
-  if (bend > 2399)
-    bend = 2399;
+  /*
+     if (bend > 2399)
+     bend = 2399;
+   */
+  while (bend > 2399)
+    {
+      multiplier *= 4;
+      bend -= 2400;
+    }
 
   semitones = bend / 100;
   cents = bend % 100;
 
-  amount = semitone_tuning[semitones] * cent_tuning[cents] / 10000;
+  amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents] / 10000;
 
   if (negative)
     return (base_freq * 10000) / amount;	/* Bend down */
@@ -1093,8 +1116,9 @@
 {
 
   sequencer_ok = 1;
-  PERMANENT_MALLOC(unsigned char*, queue, SEQ_MAX_QUEUE*EV_SZ, mem_start);
-  PERMANENT_MALLOC(unsigned char*, iqueue, SEQ_MAX_QUEUE*IEV_SZ, mem_start);
+  PERMANENT_MALLOC (unsigned char *, queue, SEQ_MAX_QUEUE * EV_SZ, mem_start);
+  PERMANENT_MALLOC (unsigned char *, iqueue, SEQ_MAX_QUEUE * IEV_SZ, mem_start);
+
   return mem_start;
 }
 
@@ -1114,14 +1138,14 @@
 
 int
 sequencer_open (int dev, struct fileinfo *file)
-  {
-    return RET_ERROR (ENXIO);
-  }
+{
+  return RET_ERROR (ENXIO);
+}
 
 void
 sequencer_release (int dev, struct fileinfo *file)
-  {
-  }
+{
+}
 int
 sequencer_ioctl (int dev, struct fileinfo *file,
 		 unsigned int cmd, unsigned int arg)
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v1.1.9/linux/drivers/sound/sound_calls.h	Tue Dec 14 13:20:36 1993
+++ linux/drivers/sound/sound_calls.h	Fri Apr 15 10:10:46 1994
@@ -129,12 +129,13 @@
 
 /*	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);
-void sb_mixer_init(int major_model);
+int sb_mixer_init(int major_model);
 
 /*	From opl3.c	*/
 int opl3_detect (int ioaddr);
@@ -181,6 +182,7 @@
 void gus_write8(int reg, unsigned int data);
 void guswave_dma_irq(void);
 void gus_delay(void);
+int gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg);
 
 /*	From gus_midi.c */
 long gus_midi_init(long mem_start);
@@ -201,3 +203,6 @@
 int pmgr_access(int dev, struct patmgr_info *rec);
 int pmgr_inform(int dev, int event, unsigned long parm1, unsigned long parm2,
 				    unsigned long parm3, unsigned long parm4);
+
+/* 	From ics2101.c */
+long ics2101_mixer_init(long mem_start);
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c
--- v1.1.9/linux/drivers/sound/sound_switch.c	Fri Jan 21 15:59:51 1994
+++ linux/drivers/sound/sound_switch.c	Fri Apr 15 11:03:33 1994
@@ -1,10 +1,10 @@
 /*
  * sound/sound_switch.c
- * 
+ *
  * The system call switch
- * 
+ *
  * 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
@@ -12,7 +12,7 @@
  * 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
@@ -24,7 +24,7 @@
  * 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"
@@ -32,13 +32,16 @@
 #ifdef CONFIGURE_SOUNDCARD
 
 struct sbc_device
-{
-  int             usecount;
-};
+  {
+    int             usecount;
+  };
 
-static struct sbc_device sbc_devices[SND_NDEVS] = {{0}};
+static struct sbc_device sbc_devices[SND_NDEVS] =
+{
+  {0}};
 
 static int      in_use = 0;	/* Total # of open device files (excluding
+
 				 * minor 0) */
 
 /*
@@ -53,7 +56,7 @@
 {
   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;
@@ -69,27 +72,28 @@
 {
   int             l, v;
 
-  static char hx[] = "0123456789abcdef";
-  char buf[11];
+  static char     hx[] = "0123456789abcdef";
+  char            buf[11];
 
-  if (!val) return put_status("0");
+  if (!val)
+    return put_status ("0");
 
   l = 0;
-  buf[10]=0;
+  buf[10] = 0;
 
   while (val)
-  {
-  	v = val % radix;
-  	val = val / radix;
+    {
+      v = val % radix;
+      val = val / radix;
 
-  	buf[9-l] = hx[v];
-  	l++;
-  }
+      buf[9 - l] = hx[v];
+      l++;
+    }
 
   if (status_len + l >= 4000)
     return 0;
 
-  memcpy (&status_buf[status_len], &buf[10-l], l);
+  memcpy (&status_buf[status_len], &buf[10 - l], l);
   status_len += l;
 
   return 1;
@@ -114,33 +118,43 @@
 
   if (!put_status ("Config options: "))
     return;
-  if (!put_status_int(SELECTED_SOUND_OPTIONS, 16))
-     return;
+  if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
+    return;
 
   if (!put_status ("\n\nHW config: \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)) return;
-      if (!put_status (": ")) return;
-      if (!put_status (supported_drivers[i].name)) return;
-      if (!put_status (" at 0x")) return;
-      if (!put_status_int(supported_drivers[i].config.io_base, 16)) return;
-      if (!put_status (" irq ")) return;
-      if (!put_status_int(supported_drivers[i].config.irq, 10)) return;
-      if (!put_status (" drq ")) return;
-      if (!put_status_int(supported_drivers[i].config.dma, 10)) return;
+      if (!supported_drivers[i].enabled)
+	if (!put_status ("("))
+	  return;
 
-      if (!supported_drivers[i].enabled) 
-      if (!put_status (")"))
+      if (!put_status ("Type "))
+	return;
+      if (!put_status_int (supported_drivers[i].card_type, 10))
+	return;
+      if (!put_status (": "))
+	return;
+      if (!put_status (supported_drivers[i].name))
+	return;
+      if (!put_status (" at 0x"))
+	return;
+      if (!put_status_int (supported_drivers[i].config.io_base, 16))
+	return;
+      if (!put_status (" irq "))
+	return;
+      if (!put_status_int (supported_drivers[i].config.irq, 10))
+	return;
+      if (!put_status (" drq "))
+	return;
+      if (!put_status_int (supported_drivers[i].config.dma, 10))
 	return;
 
+      if (!supported_drivers[i].enabled)
+	if (!put_status (")"))
+	  return;
+
       if (!put_status ("\n"))
 	return;
     }
@@ -150,10 +164,14 @@
 
   for (i = 0; i < num_dspdevs; i++)
     {
-      if (!put_status_int(i, 10)) return;
-      if (!put_status(": "))return;
-      if (!put_status(dsp_devs[i]->name))return;
-      if (!put_status("\n"))return;
+      if (!put_status_int (i, 10))
+	return;
+      if (!put_status (": "))
+	return;
+      if (!put_status (dsp_devs[i]->name))
+	return;
+      if (!put_status ("\n"))
+	return;
     }
 
   if (!put_status ("\nSynth devices:\n"))
@@ -161,10 +179,14 @@
 
   for (i = 0; i < num_synths; i++)
     {
-      if (!put_status_int(i, 10)) return;
-      if (!put_status(": "))return;
-      if (!put_status(synth_devs[i]->info->name))return;
-      if (!put_status("\n"))return;
+      if (!put_status_int (i, 10))
+	return;
+      if (!put_status (": "))
+	return;
+      if (!put_status (synth_devs[i]->info->name))
+	return;
+      if (!put_status ("\n"))
+	return;
     }
 
   if (!put_status ("\nMidi devices:\n"))
@@ -172,10 +194,14 @@
 
   for (i = 0; i < num_midis; i++)
     {
-      if (!put_status_int(i, 10)) return;
-      if (!put_status(": "))return;
-      if (!put_status(midi_devs[i]->info.name))return;
-      if (!put_status("\n"))return;
+      if (!put_status_int (i, 10))
+	return;
+      if (!put_status (": "))
+	return;
+      if (!put_status (midi_devs[i]->info.name))
+	return;
+      if (!put_status ("\n"))
+	return;
     }
 
   if (num_mixers)
@@ -191,7 +217,7 @@
 }
 
 static int
-read_status (snd_rw_buf *buf, int count)
+read_status (snd_rw_buf * buf, int count)
 {
   /*
    * Return at most 'count' bytes from the status_buf.
@@ -206,14 +232,14 @@
   if (l <= 0)
     return 0;
 
-  COPY_TO_USER(buf, 0, &status_buf[status_ptr], l);
+  COPY_TO_USER (buf, 0, &status_buf[status_ptr], l);
   status_ptr += l;
 
   return l;
 }
 
 int
-sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count)
+sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
   DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count));
 
@@ -246,7 +272,7 @@
 }
 
 int
-sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count)
+sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
 
   DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count));
@@ -275,6 +301,7 @@
 sound_open_sw (int dev, struct fileinfo *file)
 {
   int             retval;
+
   DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
 
   if ((dev >= SND_NDEVS) || (dev < 0))
@@ -373,7 +400,7 @@
 
 int
 sound_ioctl_sw (int dev, struct fileinfo *file,
-	     unsigned int cmd, unsigned long arg)
+		unsigned int cmd, unsigned long arg)
 {
   DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
 
@@ -414,4 +441,5 @@
 
   return RET_ERROR (EPERM);
 }
+
 #endif
diff -u --new-file --recursive v1.1.9/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v1.1.9/linux/drivers/sound/soundcard.c	Fri Jan 21 15:59:51 1994
+++ linux/drivers/sound/soundcard.c	Fri Apr 15 11:01:14 1994
@@ -1,11 +1,11 @@
 
 /*
  * linux/kernel/chr_drv/sound/soundcard.c
- * 
+ *
  * Soundcard driver for Linux
- * 
+ *
  * 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
@@ -13,7 +13,7 @@
  * 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
@@ -25,7 +25,7 @@
  * 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"
@@ -37,6 +37,7 @@
 extern long     seq_time;
 
 static int      soundcards_installed = 0;	/* Number of installed
+
 						 * soundcards */
 static int      soundcard_configured = 0;
 
@@ -209,7 +210,7 @@
 }
 
 int
-snd_set_irq_handler (int interrupt_level, void(*hndlr)(int))
+snd_set_irq_handler (int interrupt_level, void (*hndlr) (int))
 {
   int             retcode;
 
@@ -237,9 +238,9 @@
 }
 
 void
-snd_release_irq(int vect)
+snd_release_irq (int vect)
 {
-	free_irq(vect);
+  free_irq (vect);
 }
 
 void
diff -u --new-file --recursive v1.1.9/linux/fs/namei.c linux/fs/namei.c
--- v1.1.9/linux/fs/namei.c	Sun Feb 13 14:01:51 1994
+++ linux/fs/namei.c	Tue Apr 26 08:24:11 1994
@@ -407,9 +407,11 @@
 		iput(dir);
 		return -EPERM;
 	}
+	dir->i_count++;
 	down(&dir->i_sem);
 	error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
 	up(&dir->i_sem);
+	iput(dir);
 	return error;
 }
 
@@ -462,9 +464,11 @@
 		iput(dir);
 		return -EPERM;
 	}
+	dir->i_count++;
 	down(&dir->i_sem);
 	error = dir->i_op->mkdir(dir,basename,namelen,mode);
 	up(&dir->i_sem);
+	iput(dir);
 	return error;
 }
 
@@ -588,9 +592,11 @@
 		iput(dir);
 		return -EPERM;
 	}
+	dir->i_count++;
 	down(&dir->i_sem);
 	error = dir->i_op->symlink(dir,basename,namelen,oldname);
 	up(&dir->i_sem);
+	iput(dir);
 	return error;
 }
 
@@ -647,9 +653,11 @@
 		iput(oldinode);
 		return -EPERM;
 	}
+	dir->i_count++;
 	down(&dir->i_sem);
 	error = dir->i_op->link(oldinode, dir, basename, namelen);
 	up(&dir->i_sem);
+	iput(dir);
 	return error;
 }
 
@@ -723,10 +731,12 @@
 		iput(new_dir);
 		return -EPERM;
 	}
+	new_dir->i_count++;
 	down(&new_dir->i_sem);
 	error = old_dir->i_op->rename(old_dir, old_base, old_len, 
 		new_dir, new_base, new_len);
 	up(&new_dir->i_sem);
+	iput(new_dir);
 	return error;
 }
 
diff -u --new-file --recursive v1.1.9/linux/include/asm/segment.h linux/include/asm/segment.h
--- v1.1.9/linux/include/asm/segment.h	Mon Apr 25 10:04:34 1994
+++ linux/include/asm/segment.h	Thu Apr 28 08:04:56 1994
@@ -52,20 +52,6 @@
 
 #define put_fs_long(x,addr) put_user_long((x),(int *)(addr))
 
-static inline void and_user_long(unsigned long val,int * addr)
-{
-__asm__ ("andl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
-}
-
-#define and_fs_long(x,addr) and_user_long((x),(int *)(addr))
-
-static inline void or_user_long(unsigned long val,int * addr)
-{
-__asm__ ("orl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
-}
-
-#define or_fs_long(x,addr) or_user_long((x),(int *)(addr))
-
 static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned long n)
 {
 __asm__("cld\n\t"
diff -u --new-file --recursive v1.1.9/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.1.9/linux/include/linux/sched.h	Wed Apr 27 09:46:10 1994
+++ linux/include/linux/sched.h	Thu Apr 28 10:36:32 1994
@@ -365,9 +365,7 @@
  * tha math co-processor latest.
  */
 #define switch_to(tsk) \
-__asm__("cmpl %%ecx,_current\n\t" \
-	"je 1f\n\t" \
-	"cli\n\t" \
+__asm__("cli\n\t" \
 	"xchgl %%ecx,_current\n\t" \
 	"ljmp %0\n\t" \
 	"sti\n\t" \
diff -u --new-file --recursive v1.1.9/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v1.1.9/linux/include/linux/soundcard.h	Sun Dec 12 22:34:07 1993
+++ linux/include/linux/soundcard.h	Wed Mar 30 14:28:39 1994
@@ -34,7 +34,7 @@
   *
   * Regards,
   * Hannu Savolainen
-  * hsavolai@cs.helsinki.fi
+  * hannu@voxware.pp.fi, Hannu.Savolainen@helsinki.fi
   */
 
 #define SOUND_VERSION	203
@@ -310,8 +310,16 @@
 #define    CTRL_EXPRESSION		253
 #define    CTRL_MAIN_VOLUME		252
 #define SEQ_BALANCE		11
+#define SEQ_VOLMODE             12
 
 /*
+ * Volume mode decides how volumes are used
+ */
+
+#define VOL_METHOD_ADAGIO	1
+#define VOL_METHOD_LINEAR	2
+
+/*
  * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as
  *	 input events.
  */
@@ -630,7 +638,8 @@
  *	}
  */
 
-#define SEQ_DEFINEBUF(len)		unsigned char _seqbuf[len]; int _seqbuflen = len, _seqbufptr = 0
+#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_PM_DEFINES			struct patmgr_info _pm_info
 #define _SEQ_NEEDBUF(len)		if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
 #define _SEQ_ADVBUF(len)		_seqbufptr += len
@@ -644,6 +653,17 @@
 					_pm_info.parm1 = bank, _pm_info.parm2 = 128, \
 					ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
 
+#define SEQ_VOLUME_MODE(dev, mode)	{_SEQ_NEEDBUF(8);\
+					_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+					_seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
+					_seqbuf[_seqbufptr+2] = (dev);\
+					_seqbuf[_seqbufptr+3] = (mode);\
+					_seqbuf[_seqbufptr+4] = 0;\
+					_seqbuf[_seqbufptr+5] = 0;\
+					_seqbuf[_seqbufptr+6] = 0;\
+					_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;\
@@ -734,8 +754,8 @@
 					_seqbuf[_seqbufptr+2] = (device);\
 					_seqbuf[_seqbufptr+3] = 0;\
 					_SEQ_ADVBUF(4);}
-#define SEQ_WRPATCH(patch, len)		{if (_seqbufptr) seqbuf_dump();\
-					if (write(seqfd, (char*)(patch), len)==-1) \
+#define SEQ_WRPATCH(patchx, len)	{if (_seqbufptr) seqbuf_dump();\
+					if (write(seqfd, (char*)(patchx), len)==-1) \
 					   perror("Write patch: /dev/sequencer");}
 
 #endif
diff -u --new-file --recursive v1.1.9/linux/include/linux/vm86.h linux/include/linux/vm86.h
--- v1.1.9/linux/include/linux/vm86.h	Wed Apr 27 09:46:10 1994
+++ linux/include/linux/vm86.h	Thu Apr 28 08:16:53 1994
@@ -40,7 +40,7 @@
 #define VM86_SIGNAL	0	/* return due to signal */
 #define VM86_UNKNOWN	1	/* unhandled GP fault - IO-instruction or similar */
 #define VM86_INTx	2	/* int3/int x instruction (ARG = x) */
-#define VM86_STI	3	/* sti/popfl instruction enabled virtual interrupts */
+#define VM86_STI	3	/* sti/popf/iret instruction enabled virtual interrupts */
 
 /*
  * This is the stack-layout when we have done a "SAVE_ALL" from vm86
@@ -102,14 +102,6 @@
 #ifdef __KERNEL__
 
 void handle_vm86_fault(struct vm86_regs *, long);
-
-extern inline int is_revectored(int nr, struct revectored_struct * bitmap)
-{
-	__asm__ __volatile__("btl %2,%%fs:%1\n\tsbbl %0,%0"
-		:"=r" (nr)
-		:"m" (*bitmap),"r" (nr));
-	return nr;
-}
 
 #endif
 
diff -u --new-file --recursive v1.1.9/linux/ipc/msg.c linux/ipc/msg.c
--- v1.1.9/linux/ipc/msg.c	Mon Dec 27 16:21:51 1993
+++ linux/ipc/msg.c	Wed Apr 27 08:05:16 1994
@@ -84,7 +84,7 @@
 	
 	if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
 		|| ipcp->seq != msqid / MSGMNI) {
-		kfree_s (msgh, sizeof(*msgh) + msgsz);
+		kfree(msgh);
 		return -EIDRM;
 	}
 
@@ -194,7 +194,7 @@
 				wake_up (&msq->wwait);
 			put_fs_long (nmsg->msg_type, &msgp->mtype);
 			memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
-			kfree_s (nmsg, sizeof(*nmsg) + msgsz); 
+			kfree(nmsg);
 			return msgsz;
 		} else {  /* did not find a message */
 			if (msgflg & IPC_NOWAIT)
@@ -311,9 +311,9 @@
 	for (msgp = msq->msg_first; msgp; msgp = msgh ) {
 		msgh = msgp->msg_next;
 		msghdrs--;
-		kfree_s (msgp, sizeof(*msgp) + msgp->msg_ts);
+		kfree(msgp);
 	}
-	kfree_s (msq, sizeof (*msq));
+	kfree(msq);
 }
 
 int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
diff -u --new-file --recursive v1.1.9/linux/ipc/sem.c linux/ipc/sem.c
--- v1.1.9/linux/ipc/sem.c	Mon Mar 21 16:16:11 1994
+++ linux/ipc/sem.c	Wed Apr 27 08:06:06 1994
@@ -144,7 +144,7 @@
 			wake_up (&sma->eventn);
 		schedule();
 	}
-	kfree_s (sma, sizeof (*sma) + sma->sem_nsems * sizeof (struct sem));
+	kfree(sma);
 	return;
 }
 
diff -u --new-file --recursive v1.1.9/linux/ipc/shm.c linux/ipc/shm.c
--- v1.1.9/linux/ipc/shm.c	Wed Mar  2 19:35:20 1994
+++ linux/ipc/shm.c	Wed Apr 27 08:08:04 1994
@@ -95,7 +95,7 @@
 		shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
 		if (shm_lock)
 			wake_up (&shm_lock);
-		kfree_s (shp, sizeof (*shp));
+		kfree(shp);
 		return -ENOMEM;
 	}
 
@@ -186,9 +186,9 @@
 			shm_swp--;
 		}
 	}
-	kfree_s (shp->shm_pages, numpages * sizeof (ulong));
+	kfree(shp->shm_pages);
 	shm_tot -= numpages;
-	kfree_s (shp, sizeof (*shp));
+	kfree(shp);
 	return;
 }
 
@@ -439,7 +439,7 @@
 	if (!shmd)
 		return -ENOMEM;
 	if ((shp != shm_segs[id]) || (shp->shm_perm.seq != shmid / SHMMNI)) {
-		kfree_s (shmd, sizeof (*shmd));
+		kfree(shmd);
 		return -EIDRM;
 	}
 	shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) |
@@ -458,7 +458,7 @@
 	if ((err = shm_map (shmd, shmflg & SHM_REMAP))) {
 		if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
 			killseg(id);
-		kfree_s (shmd, sizeof (*shmd));
+		kfree(shmd);
 		return err;
 	}
 		
@@ -497,7 +497,7 @@
 	
  found:
 	unmap_page_range (shmd->start, shp->shm_segsz); /* sleeps */
-	kfree_s (shmd, sizeof (*shmd));
+	kfree(shmd);
   	shp->shm_lpid = current->pid;
 	shp->shm_dtime = CURRENT_TIME;
 	if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
@@ -550,7 +550,7 @@
 		if (!tmp) {
 			while (new_desc) { 
 				tmp = new_desc->task_next; 
-				kfree_s (new_desc, sizeof (*new_desc)); 
+				kfree(new_desc);
 				new_desc = tmp; 
 			}
 			free_page_tables (p2);
diff -u --new-file --recursive v1.1.9/linux/kernel/sched.c linux/kernel/sched.c
--- v1.1.9/linux/kernel/sched.c	Tue Apr  5 08:49:45 1994
+++ linux/kernel/sched.c	Thu Apr 28 10:33:52 1994
@@ -222,7 +222,7 @@
 		++current->counter;
 	}
 #endif
-	c = -1;
+	c = -1000;
 	next = p = &init_task;
 	for (;;) {
 		if ((p = p->next_task) == &init_task)
@@ -235,8 +235,9 @@
 		for_each_task(p)
 			p->counter = (p->counter >> 1) + p->priority;
 	}
-	if(current != next)
-		kstat.context_swtch++;
+	if (current == next)
+		return;
+	kstat.context_swtch++;
 	switch_to(next);
 	/* Now maybe reload the debug registers */
 	if(current->debugreg[7]){
@@ -634,8 +635,8 @@
 		}
 #endif
 	}
-	if (current == task[0] || (--current->counter)<=0) {
-		current->counter=0;
+	if (current != task[0] && 0 > --current->counter) {
+		current->counter = 0;
 		need_resched = 1;
 	}
 	/* Update ITIMER_PROF for the current task */
diff -u --new-file --recursive v1.1.9/linux/kernel/sys.c linux/kernel/sys.c
--- v1.1.9/linux/kernel/sys.c	Mon Apr 25 10:04:37 1994
+++ linux/kernel/sys.c	Thu Apr 28 10:32:01 1994
@@ -35,6 +35,23 @@
 	return -EINVAL;
 }
 
+asmlinkage int sys_idle(void)
+{
+	int i;
+
+	/* Map out the low memory: it's no longer needed */
+	for (i = 0 ; i < 768 ; i++)
+		swapper_pg_dir[i] = 0;
+
+	/* endless idle loop with no priority at all */
+	current->counter = -100;
+	for (;;) {
+		if (!need_resched)
+			__asm__("hlt");
+		schedule();
+	}
+}
+
 static int proc_sel(struct task_struct *p, int which, int who)
 {
 	switch (which) {
diff -u --new-file --recursive v1.1.9/linux/kernel/vm86.c linux/kernel/vm86.c
--- v1.1.9/linux/kernel/vm86.c	Wed Apr 27 09:46:10 1994
+++ linux/kernel/vm86.c	Thu Apr 28 08:16:53 1994
@@ -22,13 +22,14 @@
 /*
  * virtual flags (16 and 32-bit versions)
  */
-#define VFLAGS(regs)	(*(unsigned short *)&(current->v86flags))
-#define VEFLAGS(regs)	(current->v86flags)
+#define VFLAGS	(*(unsigned short *)&(current->v86flags))
+#define VEFLAGS	(current->v86flags)
 
 #define set_flags(X,new,mask) \
 ((X) = ((X) & ~(mask)) | ((new) & (mask)))
 
 #define SAFE_MASK	(0xDD5)
+#define RETURN_MASK	(0xDFF)
 
 asmlinkage struct pt_regs * save_v86_state(struct vm86_regs * regs)
 {
@@ -38,6 +39,7 @@
 		printk("no vm86_info: BAD\n");
 		do_exit(SIGSEGV);
 	}
+	set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->v86mask);
 	memcpy_tofs(&current->vm86_info->regs,regs,sizeof(*regs));
 	put_fs_long(current->screen_bitmap,&current->vm86_info->screen_bitmap);
 	tmp = current->tss.esp0;
@@ -91,9 +93,9 @@
  * has set it up safely, so this makes sure interrupt etc flags are
  * inherited from protected mode.
  */
- 	current->v86flags = info.regs.eflags;
+ 	VEFLAGS = info.regs.eflags;
 	info.regs.eflags &= SAFE_MASK;
-	info.regs.eflags |= ~SAFE_MASK & pt_regs->eflags;
+	info.regs.eflags |= pt_regs->eflags & ~SAFE_MASK;
 	info.regs.eflags |= VM_MASK;
 
 	switch (info.cpu_type) {
@@ -142,14 +144,14 @@
 
 static inline void set_IF(struct vm86_regs * regs)
 {
-	current->v86flags |= VIF_MASK;
-	if (current->v86flags & VIP_MASK)
+	VEFLAGS |= VIF_MASK;
+	if (VEFLAGS & VIP_MASK)
 		return_to_32bit(regs, VM86_STI);
 }
 
 static inline void clear_IF(struct vm86_regs * regs)
 {
-	current->v86flags &= ~VIF_MASK;
+	VEFLAGS &= ~VIF_MASK;
 }
 
 static inline void clear_TF(struct vm86_regs * regs)
@@ -159,7 +161,7 @@
 
 static inline void set_vflags_long(unsigned long eflags, struct vm86_regs * regs)
 {
-	set_flags(VEFLAGS(regs), eflags, current->v86mask);
+	set_flags(VEFLAGS, eflags, current->v86mask);
 	set_flags(regs->eflags, eflags, SAFE_MASK);
 	if (eflags & IF_MASK)
 		set_IF(regs);
@@ -167,7 +169,7 @@
 
 static inline void set_vflags_short(unsigned short flags, struct vm86_regs * regs)
 {
-	set_flags(VFLAGS(regs), flags, current->v86mask);
+	set_flags(VFLAGS, flags, current->v86mask);
 	set_flags(regs->eflags, flags, SAFE_MASK);
 	if (flags & IF_MASK)
 		set_IF(regs);
@@ -175,11 +177,19 @@
 
 static inline unsigned long get_vflags(struct vm86_regs * regs)
 {
-	unsigned long flags = regs->eflags & SAFE_MASK;
+	unsigned long flags = regs->eflags & RETURN_MASK;
 
-	if (current->v86flags & VIF_MASK)
+	if (VEFLAGS & VIF_MASK)
 		flags |= IF_MASK;
-	return flags | (VEFLAGS(regs) & current->v86mask);
+	return flags | (VEFLAGS & current->v86mask);
+}
+
+static inline int is_revectored(int nr, struct revectored_struct * bitmap)
+{
+	__asm__ __volatile__("btl %2,%%fs:%1\n\tsbbl %0,%0"
+		:"=r" (nr)
+		:"m" (*bitmap),"r" (nr));
+	return nr;
 }
 
 /*
diff -u --new-file --recursive v1.1.9/linux/mm/memory.c linux/mm/memory.c
--- v1.1.9/linux/mm/memory.c	Thu Apr 21 09:46:35 1994
+++ linux/mm/memory.c	Wed Apr 27 09:43:05 1994
@@ -1011,6 +1011,8 @@
 	show_buffers();
 }
 
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
 /*
  * paging_init() sets up the page tables - note that the first 4MB are
  * already mapped by head.S.
@@ -1056,7 +1058,7 @@
 		}
 	}
 	invalidate();
-	return start_mem;
+	return free_area_init(start_mem, end_mem);
 }
 
 void mem_init(unsigned long start_low_mem,
@@ -1065,33 +1067,12 @@
 	int codepages = 0;
 	int reservedpages = 0;
 	int datapages = 0;
-	unsigned long tmp, mask;
-	unsigned short * p;
+	unsigned long tmp;
 	extern int etext;
 
 	cli();
 	end_mem &= PAGE_MASK;
 	high_memory = end_mem;
-	start_mem +=  0x0000000f;
-	start_mem &= ~0x0000000f;
-	tmp = MAP_NR(end_mem);
-	mem_map = (unsigned short *) start_mem;
-	p = mem_map + tmp;
-	start_mem = (unsigned long) p;
-	while (p > mem_map)
-		*--p = MAP_PAGE_RESERVED;
-
-	/* set up the free-area data structures */
-	for (mask = PAGE_MASK, tmp = 0 ; tmp < NR_MEM_LISTS ; tmp++, mask <<= 1) {
-		unsigned long bitmap_size;
-		free_area_list[tmp].prev = free_area_list[tmp].next = &free_area_list[tmp];
-		end_mem = (end_mem + ~mask) & mask;
-		bitmap_size = end_mem >> (PAGE_SHIFT + tmp);
-		bitmap_size = (bitmap_size + 7) >> 3;
-		free_area_map[tmp] = (unsigned char *) start_mem;
-		memset((void *) start_mem, 0, bitmap_size);
-		start_mem += bitmap_size;
-	}
 
 	/* mark usable pages in the mem_map[] */
 	start_low_mem = PAGE_ALIGN(start_low_mem);
diff -u --new-file --recursive v1.1.9/linux/mm/swap.c linux/mm/swap.c
--- v1.1.9/linux/mm/swap.c	Mon Apr 25 10:04:38 1994
+++ linux/mm/swap.c	Thu Apr 28 08:43:25 1994
@@ -264,17 +264,6 @@
 }
 
 /*
- * sys_idle() does nothing much: it just searches for likely candidates for
- * swapping out or forgetting about. This speeds up the search when we
- * actually have to swap.
- */
-asmlinkage int sys_idle(void)
-{
-	need_resched = 1;
-	return 0;
-}
-
-/*
  * A new implementation of swap_out().  We do not swap complete processes,
  * but only a small number of blocks, before we continue with the next
  * process.  The number of blocks actually swapped is determined on the
@@ -895,4 +884,35 @@
 	val->freeswap <<= PAGE_SHIFT;
 	val->totalswap <<= PAGE_SHIFT;
 	return;
+}
+
+/*
+ * set up the free-area data structures:
+ *   - mark all pages MAP_PAGE_RESERVED
+ *   - mark all memory queues empty
+ *   - clear the memory bitmaps
+ */
+unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)
+{
+	unsigned short * p;
+	unsigned long mask = PAGE_MASK;
+	int i;
+
+	mem_map = (unsigned short *) start_mem;
+	p = mem_map + MAP_NR(end_mem);
+	start_mem = (unsigned long) p;
+	while (p > mem_map)
+		*--p = MAP_PAGE_RESERVED;
+
+	for (i = 0 ; i < NR_MEM_LISTS ; i++, mask <<= 1) {
+		unsigned long bitmap_size;
+		free_area_list[i].prev = free_area_list[i].next = &free_area_list[i];
+		end_mem = (end_mem + ~mask) & mask;
+		bitmap_size = end_mem >> (PAGE_SHIFT + i);
+		bitmap_size = (bitmap_size + 7) >> 3;
+		free_area_map[i] = (unsigned char *) start_mem;
+		memset((void *) start_mem, 0, bitmap_size);
+		start_mem += bitmap_size;
+	}
+	return start_mem;
 }
diff -u --new-file --recursive v1.1.9/linux/net/inet/icmp.c linux/net/inet/icmp.c
--- v1.1.9/linux/net/inet/icmp.c	Tue Apr 19 10:54:18 1994
+++ linux/net/inet/icmp.c	Thu Apr 28 23:39:19 1994
@@ -186,6 +186,7 @@
 		icmp_statistics.IcmpOutErrors++;
 		return;
 	}
+	skb->free = 1;
 
 	/*
 	 *	Build Layer 2-3 headers for message back to source. 
diff -u --new-file --recursive v1.1.9/linux/net/inet/skbuff.c linux/net/inet/skbuff.c
--- v1.1.9/linux/net/inet/skbuff.c	Tue Apr 19 10:54:03 1994
+++ linux/net/inet/skbuff.c	Wed Apr 27 08:58:32 1994
@@ -387,7 +387,8 @@
 {
 	if (skb == NULL) 
 	{
-		printk("kfree_skb: skb = NULL\n");
+		printk("kfree_skb: skb = NULL (from %08lx)\n",
+			((unsigned long *) &skb)[-1]);
 		return;
   	}
 	IS_SKB(skb);
@@ -397,9 +398,11 @@
 		return;
   	}
   	if (skb->free == 2)
-		printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
+		printk("Warning: kfree_skb passed an skb that nobody set the free flag on! (from %08lx)\n",
+			((unsigned long *) &skb)[-1]);
 	if (skb->next)
-	 	printk("Warning: kfree_skb passed an skb still on a list.\n");
+	 	printk("Warning: kfree_skb passed an skb still on a list (from %08lx).\n",
+			((unsigned long *) &skb)[-1]);
 	if (skb->sk) 
 	{
 	        if(skb->sk->prot!=NULL)
