]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.31 1.1.31
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:34 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:34 +0000 (15:09 -0500)
64 files changed:
Makefile
drivers/block/floppy.c
drivers/scsi/sd.c
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/sound/.blurb
drivers/sound/CHANGELOG
drivers/sound/Makefile
drivers/sound/Readme
drivers/sound/Readme.linux
drivers/sound/Readme.v30 [new file with mode: 0644]
drivers/sound/ad1848.c [new file with mode: 0644]
drivers/sound/audio.c
drivers/sound/configure.c
drivers/sound/dev_table.c
drivers/sound/dev_table.h
drivers/sound/dmabuf.c
drivers/sound/experimental.txt [new file with mode: 0644]
drivers/sound/gus_card.c
drivers/sound/gus_midi.c
drivers/sound/gus_wave.c
drivers/sound/ics2101.c
drivers/sound/midi_ctrl.h [new file with mode: 0644]
drivers/sound/midi_synth.c [new file with mode: 0644]
drivers/sound/midi_synth.h [new file with mode: 0644]
drivers/sound/midibuf.c
drivers/sound/mpu401.c
drivers/sound/opl3.c
drivers/sound/os.h
drivers/sound/pas.h
drivers/sound/pas2_card.c
drivers/sound/pas2_midi.c
drivers/sound/pas2_mixer.c
drivers/sound/pas2_pcm.c
drivers/sound/patmgr.c
drivers/sound/pss.c [new file with mode: 0644]
drivers/sound/pss.h [new file with mode: 0644]
drivers/sound/sb16_dsp.c
drivers/sound/sb16_midi.c
drivers/sound/sb_dsp.c
drivers/sound/sb_midi.c
drivers/sound/sb_mixer.c
drivers/sound/sb_mixer.h
drivers/sound/sequencer.c
drivers/sound/sound_calls.h
drivers/sound/sound_config.h
drivers/sound/sound_switch.c
drivers/sound/sound_timer.c [new file with mode: 0644]
drivers/sound/soundcard.c
drivers/sound/sys_timer.c [new file with mode: 0644]
drivers/sound/uart6850.c [new file with mode: 0644]
fs/buffer.c
fs/ext/namei.c
fs/ext2/namei.c
fs/isofs/namei.c
fs/nfs/mmap.c
fs/super.c
include/linux/fdreg.h
include/linux/fs.h
include/linux/mm.h
include/linux/soundcard.h
kernel/ptrace.c
mm/memory.c
mm/swap.c

index 9c58e53f478f115dfb5dafb6796c98a82576426a..e5b07536ee4c5a7293d373acfdafaa9e01d17e77 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 30
+SUBLEVEL = 31
 
 all:   Version zImage
 
index 5758ceffd64b17e33150f6e8c7f455092ab0b18e..382d0bd164ee12b6748905bec84b9e60d2fb596b 100644 (file)
@@ -97,7 +97,7 @@
 #define MAJOR_NR FLOPPY_MAJOR
 #include "blk.h"
 
-static unsigned int changed_floppies = 0, fake_change = 0;
+static unsigned int changed_floppies = 0, fake_change = 0, read_only = 0;
 
 static int initial_reset_flag = 0;
 static int need_configure = 1;         /* for 82077 */
@@ -150,7 +150,7 @@ static unsigned char reply_buffer[MAX_REPLIES];
 #define ST0 (reply_buffer[0])
 #define ST1 (reply_buffer[1])
 #define ST2 (reply_buffer[2])
-#define ST3 (reply_buffer[3])
+#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
 
 /*
  * This struct defines the different floppy types.
@@ -1037,8 +1037,20 @@ static void shake_one(void)
        output_byte(1);
 }
 
+static void check_readonly(void)
+{
+       unsigned long mask = 1 << current_drive;
+
+       read_only &= ~mask;
+       output_byte(FD_GETSTATUS);
+       output_byte(current_drive);
+       if ((result() == 1) && (ST3 & ST3_RY) && !(ST3 & ST3_FT) && (ST3 & ST3_WP))
+               read_only |= mask;
+}
+
 static void floppy_ready(void)
 {
+       check_readonly();
        if (inb(FD_DIR) & 0x80) {
                changed_floppies |= 1<<current_drive;
                buffer_track = -1;
@@ -1368,6 +1380,16 @@ static void config_types(void)
        printk("\n");
 }
 
+static void floppy_release(struct inode * inode, struct file * filp)
+{
+       fsync_dev(inode->i_rdev);
+       if (!fd_ref[inode->i_rdev & 3]--) {
+               printk("floppy_release with fd_ref == 0");
+               fd_ref[inode->i_rdev & 3] = 0;
+       }
+       floppy_release_irq_and_dma();
+}
+
 /*
  * floppy_open check for aliasing (/dev/fd0 can be the same as
  * /dev/PS0 etc), and disallows simultaneous access to the same
@@ -1390,19 +1412,16 @@ static int floppy_open(struct inode * inode, struct file * filp)
        buffer_drive = buffer_track = -1;
        if (old_dev && old_dev != inode->i_rdev)
                invalidate_buffers(old_dev);
-       if (filp && filp->f_mode)
+       if (filp && filp->f_mode) {
                check_disk_change(inode->i_rdev);
-       return 0;
-}
-
-static void floppy_release(struct inode * inode, struct file * filp)
-{
-       fsync_dev(inode->i_rdev);
-       if (!fd_ref[inode->i_rdev & 3]--) {
-               printk("floppy_release with fd_ref == 0");
-               fd_ref[inode->i_rdev & 3] = 0;
+               if (filp->f_mode & 2) {
+                       if (1 & (read_only >> drive)) {
+                               floppy_release(inode, filp);
+                               return -EACCES;
+                       }
+               }
        }
-        floppy_release_irq_and_dma();
+       return 0;
 }
 
 static int check_floppy_change(dev_t dev)
index c04a8b2b5505250214a95d2468408c7440ef712e..198cd33601cf03a950d27bd5130d411fe446be0b 100644 (file)
@@ -38,7 +38,7 @@ static const char RCSid[] = "$Header:";
  *     Time out in seconds for disks and Magneto-opticals (which are slower).
  */
 
-#define SD_TIMEOUT 300
+#define SD_TIMEOUT 600
 #define SD_MOD_TIMEOUT 750
 
 #define CLUSTERABLE_DEVICE(SC) (SC->host->hostt->use_clustering && \
index 6af2df39da133447dd350ef512193071b37b1352..8ff304a86c0e59f5b504efb920fe38674ace782e 100644 (file)
@@ -636,7 +636,6 @@ void sr_attach(Scsi_Device * SDp){
 static void sr_init_done (Scsi_Cmnd * SCpnt)
 {
   struct request * req;
-  struct task_struct * p;
   
   req = &SCpnt->request;
   req->dev = 0xfffe; /* Busy, but indicate request done */
index e1761839b8c71222c421dae0a0f5eadb4cf19212..84789c550fc1e51dac36f257b486423b987b9d94 100644 (file)
@@ -21,13 +21,12 @@ extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
 static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
 {
   struct request * req;
-  struct task_struct * p;
   
   req = &SCpnt->request;
   req->dev = 0xfffe; /* Busy, but indicate request done */
   
   if (req->sem != NULL) {
-    up(&req->sem);
+    up(req->sem);
   }
 }
 
index 5a74edfdaecb12bde8e3633ad0c701f7ee706eb4..165e01ac8b9a6cd23b2bec20d0d67131a6030aa8 100644 (file)
@@ -1,6 +1,27 @@
-NOTE!  This driver version is not compatible with the version 1.0c.
-       This means you have to use the latest version of the snd-util
-       package (2.0). The earlier ones (from 1.0) will not work. If you have
-       other programs using ioctl calls of the driver, they must be
-       recompiled. Most of them will not work without some source
-       modifications.
+NOTE!
+
+       This is an ALPHA TEST VERSION (pre 3.0). The latest
+       released version of this driver is now part of
+       Linux kernel distribution. For other operating systems
+       use the snd-driv-2.5.tar.gz package.
+
+       This particular version contains lots of new features
+       BUT THERE ARE NO APPLICATIONS WHICH USE THEM. So there
+       is no need to install this version as long as you are
+       not developing the driver or applications which use it.
+       All new features are in the /dev/sequencer and /dev/midi
+       parts of the driver.
+
+       
+       This version is little bit incomplete. Some features have
+       not been implemented for each soundcards yet. All features
+       of v2.4 should work OK.
+
+CAUTION!
+       This version of driver works with applications written and
+       compiled for v2.*. The problem is that APPLICATIONS COMPILED
+       WITH soundcard.h OF THIS VERSION WILL NOT WORK WITH OLDER DRIVER.
+       Be carefull when distributing applications compiled with this
+       version (just the apps using /dev/sequencer are incompatible).
+
+Hannu
index f274c834bc9a38d646dcf53883a429dc3187101d..fcdbb8e3eae6ea6bf552d48979a219d9745abe77 100644 (file)
@@ -1,8 +1,40 @@
-Changelog for version 2.5a
---------------------------
+Changelog for version 2.90
+------------------------------------
 
-Since 2.5
-- Minor fix to read from /dev/sequencer
+This is an intermediate release (v3.0 prototype with some experimental
+features disabled). See experimental.txt for more info.
+
+Since pre-3.0-949712
+- GUS MAX support
+- Partially working MSS/WSS support (could work with some cards).
+- Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs
+  (GUS MAX, GUS16, WSS etc). Hardware ADPCM is possible with GUS16 and
+  GUS MAX, but it doesn't work yet.
+Since pre-3.0-940426
+- AD1848/CS4248/CS4231 codec support (MSS, GUS MAX, Aztec, Orchid etc).
+This codec chip is used in various soundcards. This version is developed
+for the 16 bit daughtercard of GUS. It should work with other cards also
+if the following requirements are met:
+       - The I/O, IRQ and DMA settings are jumper selectable or
+       the card is initialized by booting DOS before booting Linux (etc.).
+       - You add the IO, IRQ and DMA settings manually to the local.h.
+         (Just define GUS16_BASE, GUS16_IRQ and GUS16_DMA). Note that
+       the base address bust be the base address of the codec chip not the
+       card itself. For the GUS16 these are the same but most MSS compatible
+       cards have the codec located at card_base+4.
+- Some minor changes
+
+Since 2.5 (******* MAJOR REWRITE ***********)
+
+This version is based on v2.3. I have tried to maintain two versions
+together so that this one should have the same features than v2.5.
+Something may still be missing. If you notice such things, please let me
+know.
+
+The Readme.v30 contains more details.
+
+- /dev/midi## devices.
+- /dev/sequencer2
 
 Since 2.5-beta2
 - Some fine tuning to the GUS v3.7 mixer code.
index 6200fa91482e51487e72548c91f400ae690d9c6a..e6fc09ba2bb2e47bcdf69dbf1f1cbee90cb2db36 100644 (file)
@@ -5,7 +5,7 @@
 #
 #
 
-VERSION                = 2.5a
+VERSION                = 2.90
 TARGET_OS      = linux
 
 .c.s:
@@ -19,7 +19,8 @@ OBJS   = soundcard.o audio.o dmabuf.o sb_dsp.o dev_table.o \
         opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \
         pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \
         gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o \
-        sb16_midi.o sound_switch.o ics2101.o
+        sb16_midi.o sound_switch.o midi_synth.o uart6850.o sound_timer.o \
+        sys_timer.o ics2101.o ad1848.o pss.o
 
 all:   local.h sound.a
 
index 4438b3ee468c738f74c0a89bfc8442713374ee30..a7653246322edee9b6b3d48a78d2972cd8600b0d 100644 (file)
@@ -1,29 +1,28 @@
-Release notes for the Linux Sound Driver 2.5a
----------------------------------------------
-This directory contains just the Linux version. The portable version
-(SCO/ISC, FreeBSD/NetBSD and SVR4.2) is available from sunsite.unc.edu:
-pub/Linux/kernel/sound.
-
-This is mainly a bug fix release. There are couple of new things such as
-linear volume mode for GUS and MIDI recording for SB 2.0 and SB Pro.
-Also this version supports the mixer of GUS v3.7. (Support for GUS MAX and
-the 16-bit daughtercard is coming sooner or later).
-
-NOTE!  The sound driver is a part of the Linux kernel distribution also.
-       Check that your kernel doesn't have more recent version than this
-       when installing a separately distributed sound driver. The
-       version number of this driver is defined in the makefile.
-
-This version contains a driver for the SB16 also.
-The SB16 driver requires separate DMA channels for the 8 and 16 bit
-modes. There should be a way to share the 8 bit DMA channels between
-these modes but this feature is not supported yet.
-The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de).
-
-The SB16 driver has also the Midi input capability even at the same
-time with the /dev/dsp. Also the WaveBlaster daughter board is supported.
-No support for the ASP chip yet (the ASP chip can be installed but it's
-not used by the driver).
+VoxWare v2.90 release notes
+--------------------------
+
+
+               This version includes some hidden features which
+               are described in the file experimental.txt
+               Some of these features are not enabled by default. Look at
+               experimental.txt for more info.
+
+               I just decided to release this version with some
+               incompletely implemented features disabled since
+               there are some new features required by a popular 
+               application. In addition there is also support
+               for the GUS MAX and the 16 bit sampling option of GUS.
+               Also the Windows Sound System stuff is there but may not
+               work yet (may work with some WSS compatible cards).
+
+********* IMPORTANT *****************************************
+Linux 1.0 or later is required to by this driver version.
+
+Don't distribute binaries which use /dev/sequencer and are
+compiled with the soundcard.h of this version. They will
+not work with version 2.x of the driver.
+*************************************************************
+
 
 You will need the snd-util-2.5.tar.gz and snd-data-0.1.tar.Z
 packages to use this driver. They should be in the same
@@ -31,122 +30,16 @@ ftp site or BBS from where you got this driver. For
 example at nic.funet.fi:pub/OS/Linux/*.
 
 If you are looking for the installation instructions, please
-look at $OS/Readme.
-
-This version supports the following soundcards:
-GUS, SoundBlaster, SB Pro, SB16, Pro Audio Spectrum 16 and AdLib.
-In addition there is rather limited support for MPU-401.
-(and compatible) midi cards. Also the OPL-3 synthesizer
-Most of the features of the /dev/sequencer device file are
-available just for GUS owners. 
+look at linux/Readme.
 
 Compatibility with the earlier versions
 ---------------------------------------
 
-In this version the ultrasound.h no longer includes the sys/soundcard.h
-You have to change the gmod.c of the snd-util-2.0 package and to add an
-include for it.
-
-IMPORTANT!!!!!!!!!!!!!!!!!!!!!!
-
-This version is not binary or source compatible with the version 1.0c.
-
-The ioctl() interface has changed completely since version 1.0c. All
-programs using this driver must be at least recompiled. 
-The snd-util-2.0 package contains some utilities for this version.
-
-The version 1.0c and earlier used a 'nonportable' ioctl calling scheme
-where the input argument was passed by value and the output value was
-returned as the functional return. For example setting the speed of
-/dev/dsp were done as the following:
-
-       int actual_speed;
-       actual_speed = ioctl(fd, SOUND_PCM_WRITE_RATE, 44100);
-
-After version 1.99.0 this must be done as the following:
-
-       int actual_speed = 44100;
-       ioctl(fd, SOUND_PCM_WRITE_RATE, &actual_speed);
-
-If you have an application written for the version 1.0, you should search
-for the strings SNDCTL_ and SOUND_ and to check the parameters. 
-The following ioctl calls have changed:
-
-       SNDCTL_SEQ_GETOUTCOUNT
-       SNDCTL_SEQ_GETINCOUNT
-       SNDCTL_SEQ_TESTMIDI
-       SNDCTL_DSP_SPEED
-       SNDCTL_DSP_STEREO
-       SNDCTL_DSP_GETBLKSIZE
-       SNDCTL_DSP_SAMPLESIZE
-       SOUND_PCM_WRITE_CHANNELS
-       SOUND_PCM_WRITE_FILTER
-       SOUND_PCM_READ_RATE
-       SOUND_PCM_READ_CHANNELS
-       SOUND_PCM_READ_BITS
-       SOUND_PCM_READ_FILTER
-       SOUND_PCM_WRITE_BITS
-       SOUND_PCM_WRITE_RATE
-       SOUND_MIXER_READ_*      (several ones)
-       SOUND_MIXER_WRITE_*     (several ones)
-
-Since the this version will support more than one synthesizer devices
-at the same time, the ioctl(SNDCTL_FM_LOAD_INSTR) is obsolete. In addition
-there is some new fields which must be initialized. Look at the sbiset.c in
-the snd-util-2.0 package for further info.
-
-Known bugs/limitations
-----------------------
-
-- High speed recording of long audio samples (>20 second) to disk
-  is not possible. Everything works until next sync() which delays the
-  recording process too much. A delay longer than 0.1 to 0.3 seconds is
-  too much.
-- The SB16 driver sometimes swaps the left and right channels together.
-- It's not possible to open /dev/dsp (or /dev/audio) while the 
-  /dev/sequencer is open for output and GUS is the only soundcard
-  installed. It's possible if /dev/dsp is opened before /dev/sequencer
-  but at this time the GUS is not available for access via /dev/sequencer.
-  This is a limitation of the driver.
-- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed.
-  It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI
-  adapter.
-- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting
-  ^C and playing again should solve this problem. This is propably caused by
-  incompatibilities between GUS and certain VLB motherboards (like mine). 
-  Try to avoid
-  switching between VTs while patches are being loaded to the GUS.
-  This problem disappears completely if you define GUS_PATCH_NO_DMA in the
-  local.h (after make config in linux). The drawback is that patch loading
-  without DMA takes several times longer than with DMA.
-- There is a skeleton of the patch manager support. It don't work in
-  this version. 
-
-
-Future development
-------------------
-
-- Since this driver is no longer just the Linux Sound Driver, it's time
-  to give it a new name. I have planned to use name VoxWare.
-- I'm writing a Hacker's guide to the VoxWare sound driver. Should
-  be ready within this(/next) year (alpha version).
-- Completion of the ISC, SCO and BSD ports. Port to SVR4.2.
-- I'm interested to implement/include support for new soundcards and 
-  operating systems. 
-
-  Hint for the soundcard and OS manufacturers:
-  I'm collecting soundcards (high end ones) and SDKs for them. In
-  addition I'm collecting PC operating systems. I will be happy if
-  somebody sends me such items. In addition such kind of donation
-  makes it easier to change the VoxWare driver to support your
-  soundcard or operating system. However, please contact me before
-  sending anything.
-
-I will propably release some fix versions within this and next year. At
-least when the non-Linux versions get ready. The next major release (3.0)
-will be quite complete rewrite and released after about a year (end of 94 or
-beginning of 95).
-
+This version is backward compatible with the version 2.X. All programs
+compiled with sys/soundcard.h of v2.X should work without problems.
+PROGRAMS COMPILED WITH THE sys/soundcard.h OF THIS VERSION WILL NOT
+WORK WITH v2.X DRIVER. BE CAREFULL WHEN DISTRIBUTING BINARIES COMPILED 
+FOR THIS VERSION.
 
 Contributors
 ------------
@@ -155,30 +48,32 @@ This driver contains code by several contributors. In addition several other
 persons have given usefull suggestions. The following is a list of major
 contributors. (I could have forgotten some names.)
 
-       Craig Metz              1/2 of the PAS16 Mixer and PCM support
-       Rob Hooft               Volume computation algorithm for the FM synth.
-       Mika Liljeberg          uLaw encoding and decoding routines
-       Greg Lee                Volume computation algorithm for the GUS and
-                               lot's of valuable suggestions.
-       Andy Warner             Initial ISC port
-       Jim Lowe                Initial FreeBSD port
+       Craig Metz      1/2 of the PAS16 Mixer and PCM support
+       Rob Hooft       Volume computation algorithm for the FM synth.
+       Mika Liljeberg  uLaw encoding and decoding routines
+       Greg Lee        Volume computation algorithm for the GUS and
+                       lot's of valuable suggestions.
+       Andy Warner     ISC port
+       Jim Lowe        FreeBSD port
        Anders Baekgaard        Bughunting and valuable suggestions.
-       Joerg Schubert          SB16 DSP support.
-       Andrew Robinson         Improvements to the GUS driver
-       Megens SA               MIDI recording for SB and SB Pro.
+       Joerg Schubert  SB16 DSP support.
+       Andrew Robinson Improvements to the GUS driver
+       Megens SA       MIDI recording for SB and SB Pro.
+       Mikael Nordqvist  Linear volume support for GUS.
        Mikael Nordqvist        Linear volume support for GUS.
        Ian Hartas              SVR4.2 port
        Markus Aroharju and
        Risto Kankkunen         Major contributions to the mixer support
                                of GUS v3.7.
-       Hunyue Yau              Sound Galaxy NX Pro mixer support.
+       Marc Hoffman    PSS support.
 
 Regards,
 
 Hannu Savolainen
-hannu@voxware.pp.fi, Hannu.Savolainen@Helsinki.fi
+hannu@voxware.pp.fi
 
 Snail mail:    Hannu Savolainen
                Pallaksentie 4 A 2
                00970 Helsinki
                Finland
+FAX:           +358 0 395 1968 (usually not connected)
index 080a23d54c89209866c14c1fe9ad56f1aec440de..ab3740700119c64e420ccefdf9352f4cc506603d 100644 (file)
@@ -1,34 +1,24 @@
-Sound Driver version 2.5 for Linux
-----------------------------------
-
-NOTE!  The sound driver is now a part of the Linux kernel distribution.
-       Check that your kernel doesn't have more recent version than this
-       when installing a separately distributed sound driver. The
-       version number of this driver is defined in the makefile.
-
 Installation
 ------------
 
-- Since this driver is a part of the Linux kernel distribution, no
-  special steps are required to build the driver itself.
+- Since you are reading this, you have already installed the files so
+  let's skip this step. To be serious, the sound driver belongs
+  to linux/drivers/sound. 
 
-- In case you are installing a separately distributed sound driver,
-  you have to do some additional steps.
-  - Remove all files from the linux/drivers/sound. Old files could
-    sometimes cause trouble.
-  - cd linux/drivers.
-  - gunzip -c snd-driv-X.Y.tar.gz|tar xvf -
-  - cd ./sound
-  - cp soundcard.h ultrasound.h /usr/include/linux
+- To build the device files you need to run the enclosed shell scrip 
+  (see below).
 
-- To build the device files for this driver, you need to run the enclosed 
-  shell script (at the end of this file).
+- If you are installing a separately distributed version, copy the
+  soundcard.h to /usr/include/linux. It may contain some new stuff.
 
-- Create /usr/include/sys/soundcard.h whic contains just a line:
-#include <linux/soundcard.h>
+- Copy the sound/ultrasound.h  to /usr/include/sys
+  (Remove the old one from /usr/include/sys /usr/include/linux first).
 
-- Create /usr/include/sys/ultrasound.h whic contains just a line:
-#include <linux/ultrasound.h>
+- Ensure you have the following symlink:
+  ln -s /usr/include/linux/soundcard.h /usr/include/sys/soundcard.h
+
+- Configure and compile Linux as normally (remember to include the
+  sound support during "make config").
 
 Boot time configuration (using lilo)
 ------------------------------------
@@ -61,6 +51,8 @@ Each option is encoded as the following:
                                        5=MPU-401 UART midi
                                        6=SB16 (16 bit DMA number)
                                        7=SB16 Midi (MPU-401 emulation)
+                       (There are some new ones also but they are currently
+                       not documented).
 
 These are the configuration templates for various soundcards:
 
@@ -174,43 +166,76 @@ If you want to play modules on a 386sx while recompiling the world, buy a GUS.
 It runs without burning your CPU.
 
 Hannu Savolainen
-Hannu.Savolainen@Helsinki.fi
-(hannu@voxware.pp.fi (april 94 ->))
+hannu@voxware.pp.fi
 
 ----------------- cut here ------------------------------
 #!/bin/sh
 #
 #      soudinstall             
 #
-#              by Craig Metz - cmetz@thor.tjhsst.edu
 #
 # Create the devices
 #
-#      Mixer           (14, 0)
+#      Mixer devices
 #
 if [ -e /dev/mixer ]; then 
        rm -f /dev/mixer 
 fi
 mknod -m 666 /dev/mixer c 14 0
-
 if [ -e /dev/mixer1 ]; then 
        rm -f /dev/mixer1 
 fi
 mknod -m 666 /dev/mixer1 c 14 16
-#
+
+
 #      Sequencer       (14, 1)
 #
 if [ -e /dev/sequencer ]; then
        rm -f /dev/sequencer
 fi
 mknod -m 666 /dev/sequencer c 14 1
-#
-#      MIDI            (14, 2) [ Not implemented ]
+
+if [ -e /dev/patmgr0 ]; then
+       rm -f /dev/patmgr0
+fi
+mknod -m 666 /dev/patmgr0 c 14 17
+if [ -e /dev/patmgr1 ]; then
+       rm -f /dev/patmgr1
+fi
+mknod -m 666 /dev/patmgr1 c 14 33
+
+###    #       Sequencer2      (14, 8)
+###    #
+###    if [ -e /dev/sequencer2 ]; then
+###            rm -f /dev/sequencer2
+###    fi
+###    mknod -m 666 /dev/sequencer2 c 14 8
+
+#      Midi devices
 #
 if [ -e /dev/midi ]; then
-       rm -f /dev/midi
+       rm -f /dev/midi         # Old name. Don't use it
 fi
-mknod -m 666 /dev/midi c 14 2
+###    if [ -e /dev/midi00 ]; then
+###            rm -f /dev/midi00
+###    fi
+###    mknod -m 666 /dev/midi00 c 14 2
+###    
+###    if [ -e /dev/midi01 ]; then
+###            rm -f /dev/midi01
+###    fi
+###    mknod -m 666 /dev/midi01 c 14 18
+###    
+###    if [ -e /dev/midi02 ]; then
+###            rm -f /dev/midi02
+###    fi
+###    mknod -m 666 /dev/midi02 c 14 34
+###    
+###    if [ -e /dev/midi03 ]; then
+###            rm -f /dev/midi03
+###    fi
+###    mknod -m 666 /dev/midi03 c 14 50
 #
 #      DSP             (14, 3)
 #
@@ -219,14 +244,14 @@ if [ -e /dev/dsp ]; then
 fi
 mknod -m 666 /dev/dsp c 14 3
 #
-#      SPARC audio     (14, 4) [ Not fully implemented ]
+#      SPARC compatible /dev/audio     (14, 4) 
 #
 if [ -e /dev/audio ]; then
        rm -f /dev/audio
 fi
 mknod -m 666 /dev/audio c 14 4
 #
-#      DSP2            (14, 19) /dev/dsp for the second soundcard.
+#      DSP1            (14, 19) /dev/dsp for the second soundcard.
 #                              Also the SB emulation part of the
 #                              PAS16 card.
 #
@@ -235,7 +260,7 @@ if [ -e /dev/dsp1 ]; then
 fi
 mknod -m 666 /dev/dsp1 c 14 19
 #
-#      SPARC audio1    (14, 20) [ Not fully implemented ]
+#      SPARC audio1    (14, 20) 
 #                              /dev/audio for the second soundcard.
 #                              Also the SB emulation part of the
 #                              PAS16 card.
diff --git a/drivers/sound/Readme.v30 b/drivers/sound/Readme.v30
new file mode 100644 (file)
index 0000000..45e7ef8
--- /dev/null
@@ -0,0 +1,154 @@
+VoxWare v3.0
+------------
+
+This is a PROTOTYPE of the VoxWare v3.0 to be relased late 94.
+
+All features of v2.5 should work as earlier. There could be some
+omissions but they are unintentional. I started this version thread
+after v2.3 so all features implemented before it are there.
+
+Even this is a prototype, there should not be any fatal bugs. The
+prototype just means that I don't have implemented all features
+completely. Mainly in the /dev/sequener2 driver.
+For example recording from /dev/sequencer2 won't work
+with other cards than a full features MPU-401 or clones. As well the
+way how the MIDI controllers are handled will change.
+
+IMPORTANT!!!!!!!!!!!!!!!!!
+
+Don't distribute any binaries compiled with the soundcard.h of this version. 
+They will not work together with older drivers.
+
+New features
+============
+
+There are now two new device interfaces. The /dev/midi## is a raw
+tty like interface to MIDI ports. There is a device file for each MIDI
+port on your system. They are named (/dev/midi00 to /dev/midiNN).
+The second addition is the /dev/sequencer2 which is higher level interface 
+than the old /dev/sequencer. It's intended for writing device independent
+applications like sequencers.
+
+/dev/midi##
+-----------
+
+This interface should be usefull for applications like MIDI sysex librarians.
+There are (currently) no timing features so making music could be impossible.
+
+There are as many /dev/midi## devices as there are MIDI ports in the system. 
+The /dev/midi00 is connected to the first one, /dev/midi01 to the second etc.
+
+These devices work like tty devices in raw mode. Everything written to them is
+sent out to the MIDI port. There is currently an extra delay of at most 
+1/100th of sec but it will be removed later.
+
+The reading algorithm is little bit more complicated. There are two different
+cases:
+
+1)     There is at least one byte in the input buffer.
+
+The read returns as many bytes as it can without waiting for more bytes.
+For example when a process reads 100 bytes and there are 10 bytes in the 
+buffer, the read returns just 10 bytes.
+
+2)     The input buffer is empty when the process calls read.
+
+The read waits for the first byte and then continues as in case 1. By
+default it waits infinitely but there is an ioctl for setting a timeout
+for this. The ioctl(fd, SNDCTL_MIDI_PRETIME, &time) changes the timeout.
+The time is given in 1/10th of seconds (10 means one second).
+
+Other ioctl calls:
+
+ioctl(fd, SNDCTL_MIDI_MPUMODE, &mode) is available for full MPU-401
+compatible devices such as MPU-IPC-T, MQ PC Midi Card or MQX-32.
+It's not available for the so called MPU UART ports of some soundcards
+(PAS16, SB16 etc). By default the MIDI port is in UART mode after open. 
+If this ioctl is called with mode=1, the interface is put to the intelligent
+(coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called.
+It could have some strange effects if not called immediately after open. This
+vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent
+mode.
+
+ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port
+is put to the coprocessor mode using ioctl(SNDCTL_MIDI_MPUMODE). It's used to
+send commands to a MPU-401 compatible MIDI cards. Please refer to the
+MPU-401 Technical Reference Manual (or Music Quest Technical Reference
+Manual) for descriptions of the commands.
+
+The argument of SNDCTL_MIDI_MPUCOMMAND is of type mpu_command_rec. It
+has the following fields:
+
+typedef struct {
+               unsigned char cmd;
+
+               char nr_args, nr_returns;
+               unsigned char data[30];
+       } mpu_command_rec;
+
+where:
+       cmd             Contains the command number.
+       nr_args         Number of arguments of the command.
+                       MUST BE INITIALIZED BEFORE CALL
+       nr_returns      Number of bytes returned by the command.
+                       MUST BE INITIALIZED BEFORE CALL
+       data            Buffer for the command arguments and returned
+                       data.
+
+Be extremely carefull with the nr_args and nr_returns fields. They
+must match the command. An incorrect value will put the card and
+the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further
+datails.
+
+
+
+/dev/sequencer2 (if you find a better name, please let me know).
+---------------
+
+This device file works much like the /dev/sequencer which has been present
+since the beginning. The main differences are the following:
+
+- /dev/sequencer makes the MIDI ports to look like the synth devices. In fact
+the result is somewhere between the MIDI specification and the synth devices of
+/dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE()
+like macros. The voice number parameters of the API macros have been redefined
+to denote MIDI channels. This means that the driver allocates voices for
+the channels automaticly (this is a responsibility/right of an application
+with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has
+similar effects for a synth channel than on a MIDI port. This kind of
+solution provides better device independence than the /dev/sequencer. The
+drawback is that the new interface doesn't permit so low level access to the
+device as the /dev/sequencer does. An application developer must choose between
+these two interfaces. I think the old /dev/sequencer is better for applications
+like module players while the new one is better for making generic sequencer
+programs.
+
+- There are no separate MIDI devices with the /dev/sequencer2. The
+ioctl(SNDCTL_SEQ_NRMIDIS) returns always zero. Instead the MIDI ports are
+shown as synth devices. ioctl(SNDCTL_SEQ_NRSYNTHS) on /dev/sequencer2 will 
+return sum of internal synthesizers (GUS, OPL3) and MIDI ports in the systems.
+
+- The new interface is used much like the ordinary /dev/sequencer. The
+event format is new so you have to use the API macros defined in the 
+sys/soundcard.h. The interface is will propably change before the final 3.0
+release but using the API macros should ensure compatibility in source level.
+The new event format is not recognized by version 2.X so don't try to 
+distribute binaries compiled with soundcard.h of v3.X.
+
+- The basic API useage is similar to the current one. There are some new
+macros but the older ones should work as earlier. The most important
+incompatibility is that the /dev/sequencer2 driver allocates voices itself.
+The other one is that the application must send SEQ_START_TIMER() as it's
+first event. Otherwise the timer is not started and the application waits
+infinitely.
+
+
+There are several new features but I don't document them here. There are
+some info in the soundcard.h (near the end). I have also included some
+sample code in the directory v30. Full documentation will
+appear in the Hacker's Guide later.
+
+Don't hesitate to contact me in case you have questions or comments.
+
+Hannu Savolainen
+hannu@voxware.pp.fi
diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c
new file mode 100644 (file)
index 0000000..c42e11c
--- /dev/null
@@ -0,0 +1,953 @@
+/*
+ * sound/ad1848.c
+ *
+ * The low level driver for the AD1848/CS4248 codec chip which
+ * is used for example in the MS Sound System.
+ *
+ * The CS4231 which is used in the GUS MAX and some other cards is
+ * upwards compatible with AD1848 and this driver is able to drive it.
+ *
+ * Copyright by Hannu Savolainen 1994
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define DEB(x)
+#define DEB1(x)
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)
+
+#define IMODE_NONE             0
+#define IMODE_OUTPUT           1
+#define IMODE_INPUT            2
+#define IMODE_INIT             3
+#define IMODE_MIDI             4
+
+typedef struct
+{
+  int             base;
+  int             irq;
+  int             dma_capture, dma_playback;
+  unsigned char   MCE_bit;
+
+  int             speed;
+  unsigned char   speed_bits;
+  int             channels;
+  int             audio_format;
+  unsigned char   format_bits;
+
+  int             xfer_count;
+  int             irq_mode;
+  int             intr_active;
+  int             opened;
+  char           *chip_name;
+  int             mode;
+}
+
+ad1848_info;
+
+static int      nr_ad1848_devs = 0;
+static char     irq2dev[16] =
+{-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1};
+
+static int      ad_format_mask[2 /*devc->mode*/ ] =
+{
+  AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
+  AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM
+};
+
+static ad1848_info dev_info[MAX_AUDIO_DEV];
+
+#define io_Index_Addr(d)       ((d)->base)
+#define io_Indexed_Data(d)     ((d)->base+1)
+#define io_Status(d)           ((d)->base+2)
+#define io_Polled_IO(d)                ((d)->base+3)
+
+static int      ad1848_open (int dev, int mode);
+static void     ad1848_close (int dev);
+static int      ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
+static void     ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static void     ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static int      ad1848_prepare_for_IO (int dev, int bsize, int bcount);
+static void     ad1848_reset (int dev);
+static void     ad1848_halt (int dev);
+void            ad1848_interrupt (int dev);
+
+static int
+ad_read (ad1848_info * devc, int reg)
+{
+  unsigned long   flags;
+  int             x;
+
+  DISABLE_INTR (flags);
+  OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
+  x = INB (io_Indexed_Data (devc));
+  /*  printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
+  RESTORE_INTR (flags);
+
+  return x;
+}
+
+static void
+ad_write (ad1848_info * devc, int reg, int data)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
+  OUTB ((unsigned char) (data & 0xff), io_Indexed_Data (devc));
+  /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
+  RESTORE_INTR (flags);
+}
+
+static void
+ad_set_MCE (ad1848_info * devc, int state)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  if (state)
+    devc->MCE_bit = 0x40;
+  else
+    devc->MCE_bit = 0x00;
+  OUTB (devc->MCE_bit, io_Index_Addr (devc));
+  RESTORE_INTR (flags);
+}
+
+static void
+wait_for_calibration (ad1848_info * devc)
+{
+  int             timeout = 0;
+
+  /*
+ * Wait until the auto calibration process has finished.
+ *
+ * 1)  Wait until the chip becomes ready (reads don't return 0x80).
+ * 2)  Wait until the ACI bit of I11 gets on and then off.
+ */
+
+  timeout = 100000;
+  while (timeout > 0 && INB (devc->base) == 0x80)
+    timeout--;
+  if (INB (devc->base) == 0x80)
+    printk ("ad1848: Auto calibration timed out(1).\n");
+
+  timeout = 100000;
+  while (timeout > 0 && !(ad_read (devc, 11) & 0x20))
+    timeout--;
+  if (!(ad_read (devc, 11) & 0x20))
+    printk ("ad1848: Auto calibration timed out(2).\n");
+
+  timeout = 100000;
+  while (timeout > 0 && ad_read (devc, 11) & 0x20)
+    timeout--;
+  if (ad_read (devc, 11) & 0x20)
+    printk ("ad1848: Auto calibration timed out(3).\n");
+}
+
+static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
+{
+  {
+    "Generic AD1848 codec",
+    DMA_AUTOMODE,
+    AFMT_U8,                   /* Will be set later */
+    NULL,
+    ad1848_open,
+    ad1848_close,
+    ad1848_output_block,
+    ad1848_start_input,
+    ad1848_ioctl,
+    ad1848_prepare_for_IO,
+    ad1848_prepare_for_IO,
+    ad1848_reset,
+    ad1848_halt,
+    NULL,
+    NULL
+  }};
+
+static int
+ad1848_open (int dev, int mode)
+{
+  int             err;
+  ad1848_info    *devc = NULL;
+  unsigned long   flags;
+
+  DEB (printk ("ad1848_open(int mode = %X)\n", mode));
+
+  if (dev < 0 || dev >= num_audiodevs)
+    return RET_ERROR (ENXIO);
+
+  devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  DISABLE_INTR (flags);
+  if (devc->opened)
+    {
+      RESTORE_INTR (flags);
+      printk ("ad1848: Already opened\n");
+      return RET_ERROR (EBUSY);
+    }
+
+  if (devc->irq)               /* Not managed by another driver */
+    if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt)) < 0)
+      {
+       printk ("ad1848: IRQ in use\n");
+       RESTORE_INTR (flags);
+       return err;
+      }
+
+  if (DMAbuf_open_dma (dev) < 0)
+    {
+      RESTORE_INTR (flags);
+      printk ("ad1848: DMA in use\n");
+      return RET_ERROR (EBUSY);
+    }
+
+  devc->intr_active = 0;
+  devc->opened = 1;
+  RESTORE_INTR (flags);
+
+  return 0;
+}
+
+static void
+ad1848_close (int dev)
+{
+  unsigned long   flags;
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  DEB (printk ("ad1848_close(void)\n"));
+
+  DISABLE_INTR (flags);
+
+  devc->intr_active = 0;
+  if (devc->irq)               /* Not managed by another driver */
+    snd_release_irq (devc->irq);
+  ad1848_reset (dev);
+  DMAbuf_close_dma (dev);
+  devc->opened = 0;
+
+  RESTORE_INTR (flags);
+}
+
+static int
+set_speed (ad1848_info * devc, int arg)
+{
+  /*
+ * The sampling speed is encoded in the least significant nible of I8. The
+ * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
+ * three bits select the divisor (indirectly):
+ *
+ * The available speeds are in the following table. Keep the speeds in
+ * the increasing order.
+ */
+  typedef struct
+    {
+      int             speed;
+      unsigned char   bits;
+    }
+  speed_struct;
+
+  static speed_struct speed_table[] =
+  {
+    {5510, (0 << 1) | 1},
+    {5510, (0 << 1) | 1},
+    {6620, (7 << 1) | 1},
+    {8000, (0 << 1) | 0},
+    {9600, (7 << 1) | 0},
+    {11025, (1 << 1) | 1},
+    {16000, (1 << 1) | 0},
+    {18900, (2 << 1) | 1},
+    {22050, (3 << 1) | 1},
+    {27420, (2 << 1) | 0},
+    {32000, (3 << 1) | 0},
+    {33075, (6 << 1) | 1},
+    {37800, (4 << 1) | 1},
+    {44100, (5 << 1) | 1},
+    {48000, (6 << 1) | 0}
+  };
+
+  int             i, n, selected = -1;
+
+  n = sizeof (speed_table) / sizeof (speed_struct);
+
+  if (arg < speed_table[0].speed)
+    selected = 0;
+  if (arg > speed_table[n - 1].speed)
+    selected = n - 1;
+
+  for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
+    if (speed_table[i].speed == arg)
+      selected = i;
+    else if (speed_table[i].speed > arg)
+      {
+       int             diff1, diff2;
+
+       diff1 = arg - speed_table[i - 1].speed;
+       diff2 = speed_table[i].speed - arg;
+
+       if (diff1 < diff2)
+         selected = i - 1;
+       else
+         selected = i;
+      }
+
+  if (selected == -1)
+    {
+      printk ("ad1848: Can't find speed???\n");
+      selected = 3;
+    }
+
+  devc->speed = speed_table[selected].speed;
+  devc->speed_bits = speed_table[selected].bits;
+  return devc->speed;
+}
+
+static int
+set_channels (ad1848_info * devc, int arg)
+{
+  if (arg != 1 && arg != 2)
+    return devc->channels;
+
+  devc->channels = arg;
+  return arg;
+}
+
+static int
+set_format (ad1848_info * devc, int arg)
+{
+
+  static struct format_tbl
+    {
+      int             format;
+      unsigned char   bits;
+    }
+  format2bits     [] =
+  {
+    {
+      0, 0
+    }
+    ,
+    {
+      AFMT_MU_LAW, 1
+    }
+    ,
+    {
+      AFMT_A_LAW, 3
+    }
+    ,
+    {
+      AFMT_IMA_ADPCM, 5
+    }
+    ,
+    {
+      AFMT_U8, 0
+    }
+    ,
+    {
+      AFMT_S16_LE, 2
+    }
+    ,
+    {
+      AFMT_S16_BE, 6
+    }
+    ,
+    {
+      AFMT_S8, 0
+    }
+    ,
+    {
+      AFMT_U16_LE, 0
+    }
+    ,
+    {
+      AFMT_U16_BE, 0
+    }
+  };
+  int             i, n = sizeof (format2bits) / sizeof (struct format_tbl);
+
+  if (!(arg & ad_format_mask[devc->mode]))
+    arg = AFMT_U8;
+
+  devc->audio_format = arg;
+
+  for (i = 0; i < n; i++)
+    if (format2bits[i].format == arg)
+      {
+       if ((devc->format_bits = format2bits[i].bits) == 0)
+         return devc->audio_format = AFMT_U8;  /* Was not supported */
+
+       return arg;
+      }
+
+  /* Still hanging here. Something must be terribly wrong */
+  devc->format_bits = 0;
+  return devc->audio_format = AFMT_U8;
+}
+
+static int
+ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  switch (cmd)
+    {
+    case SOUND_PCM_WRITE_RATE:
+      if (local)
+       return set_speed (devc, arg);
+      return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_RATE:
+      if (local)
+       return devc->speed;
+      return IOCTL_OUT (arg, devc->speed);
+
+    case SNDCTL_DSP_STEREO:
+      if (local)
+       return set_channels (devc, arg + 1) - 1;
+      return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1);
+
+    case SOUND_PCM_WRITE_CHANNELS:
+      if (local)
+       return set_channels (devc, arg);
+      return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_CHANNELS:
+      if (local)
+       return devc->channels;
+      return IOCTL_OUT (arg, devc->channels);
+
+    case SNDCTL_DSP_SAMPLESIZE:
+      if (local)
+       return set_format (devc, arg);
+      return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_BITS:
+      if (local)
+       return devc->audio_format;
+      return IOCTL_OUT (arg, devc->audio_format);
+
+    default:;
+    }
+  return RET_ERROR (EINVAL);
+}
+
+static void
+ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+  unsigned long   flags, cnt;
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  cnt = count;
+
+  if (devc->audio_format == AFMT_IMA_ADPCM)
+    {
+      cnt /= 4;
+    }
+  else
+    {
+      if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))    /* 16 bit data */
+       cnt >>= 1;
+    }
+  if (devc->channels > 1)
+    cnt >>= 1;
+  cnt--;
+
+  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
+      intrflag &&
+      cnt == devc->xfer_count)
+    {
+      devc->irq_mode = IMODE_OUTPUT;
+      devc->intr_active = 1;
+      return;                  /*
+                                * Auto DMA mode on. No need to react
+                                */
+    }
+  DISABLE_INTR (flags);
+
+  if (dma_restart)
+    {
+      ad1848_halt (dev);
+      DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+    }
+
+  ad_set_MCE (devc, 1);
+
+  ad_write (devc, 15, (unsigned char) (cnt & 0xff));
+  ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
+
+
+  ad_write (devc, 9, 0x0d);    /*
+                                * Playback enable, single DMA channel mode,
+                                * auto calibration on.
+                                */
+
+  ad_set_MCE (devc, 0);                /*
+                                * Starts the calibration process and
+                                * enters playback mode after it.
+                                */
+  wait_for_calibration (devc);
+
+  devc->xfer_count = cnt;
+  devc->irq_mode = IMODE_OUTPUT;
+  devc->intr_active = 1;
+  RESTORE_INTR (flags);
+}
+
+static void
+ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+  unsigned long   flags, cnt;
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  /* int             count_reg = (devc->mode == 1) ? 14 : 30; */
+
+  cnt = count;
+  if (devc->audio_format == AFMT_IMA_ADPCM)
+    {
+      cnt /= 4;
+    }
+  else
+    {
+      if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))    /* 16 bit data */
+       cnt >>= 1;
+    }
+  if (devc->channels > 1)
+    cnt >>= 1;
+  cnt--;
+
+  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
+      intrflag &&
+      cnt == devc->xfer_count)
+    {
+      devc->irq_mode = IMODE_INPUT;
+      devc->intr_active = 1;
+      return;                  /*
+                                * Auto DMA mode on. No need to react
+                                */
+    }
+  DISABLE_INTR (flags);
+
+  if (dma_restart)
+    {
+      ad1848_halt (dev);
+      DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+    }
+
+  ad_set_MCE (devc, 1);
+#if 0
+  ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff));
+  ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff));
+#else
+  ad_write (devc, 15, (unsigned char) (cnt & 0xff));
+  ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
+  if (devc->mode == 2)
+    {
+      ad_write (devc, 31, (unsigned char) (cnt & 0xff));
+      ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff));
+    }
+#endif
+
+  ad_write (devc, 9, 0x0e);    /*
+                                * Capture enable, single DMA channel mode,
+                                * auto calibration on.
+                                */
+
+  ad_set_MCE (devc, 0);                /*
+                                * Starts the calibration process and
+                                * enters playback mode after it.
+                                */
+  wait_for_calibration (devc);
+
+  devc->xfer_count = cnt;
+  devc->irq_mode = IMODE_INPUT;
+  devc->intr_active = 1;
+  RESTORE_INTR (flags);
+}
+
+static int
+ad1848_prepare_for_IO (int dev, int bsize, int bcount)
+{
+  int             timeout;
+  unsigned char   fs;
+  unsigned long   flags;
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  DISABLE_INTR (flags);
+  ad_set_MCE (devc, 1);                /* Enables changes to the format select reg */
+  fs = devc->speed_bits | (devc->format_bits << 5);
+
+  if (devc->channels > 1)
+    fs |= 0x10;
+
+  ad_write (devc, 8, fs);
+  /*
+   * Write to I8 starts resyncronization. Wait until it completes.
+   */
+  timeout = 10000;
+  while (timeout > 0 && INB (devc->base) == 0x80)
+    timeout--;
+
+  ad_set_MCE (devc, 0);                /*
+                                * Starts the calibration process and
+                                * enters playback mode after it.
+                                */
+  wait_for_calibration (devc);
+  RESTORE_INTR (flags);
+
+  /*
+ * If mode == 2 (CS4231), set I28 also. It's the capture format register.
+ */
+  if (devc->mode == 2)
+    {
+      ad_set_MCE (devc, 1);
+      ad_write (devc, 28, fs);
+
+      /*
+   * Write to I28 starts resyncronization. Wait until it completes.
+   */
+      timeout = 10000;
+      while (timeout > 0 && INB (devc->base) == 0x80)
+       timeout--;
+
+      ad_set_MCE (devc, 0);    /*
+                                * Starts the calibration process and
+                                * enters playback mode after it.
+                                */
+      wait_for_calibration (devc);
+      RESTORE_INTR (flags);
+    }
+  devc->xfer_count = 0;
+  return 0;
+}
+
+static void
+ad1848_reset (int dev)
+{
+  ad1848_halt (dev);
+}
+
+static void
+ad1848_halt (int dev)
+{
+  ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+  ad_write (devc, 9, 0);       /* Clear the PEN and CEN bits (among others) */
+  OUTB (0, io_Status (devc));  /* Clear interrupt status */
+}
+
+int
+ad1848_detect (int io_base)
+{
+
+#define DDB(x) x
+
+  unsigned char   tmp;
+  int             i;
+  ad1848_info    *devc = &dev_info[nr_ad1848_devs];
+  unsigned char   tmp1 = 0xff, tmp2 = 0xff;
+
+  if (nr_ad1848_devs >= MAX_AUDIO_DEV)
+    return 0;
+
+  devc->base = io_base;
+  devc->MCE_bit = 0x40;
+  devc->irq = 0;
+  devc->dma_capture = 0;
+  devc->dma_playback = 0;
+  devc->opened = 0;
+  devc->chip_name = "AD1848";
+  devc->mode = 1;              /* MODE1 = original AD1848 */
+
+  /*
+ * Check that the I/O address is in use.
+ *
+ * The bit 0x80 of the base I/O port is known to be 0 after the
+ * chip has performed it's power on initialization. Just assume
+ * this has happened before the OS is starting.
+ *
+ * If the I/O address is unused, it typically returns 0xff.
+ */
+
+  if ((INB (devc->base) & 0x80) != 0x00)       /* Not a AD1884 */
+    {
+      DDB (printk ("ad_detect_A\n"));
+      return 0;
+    }
+
+  /*
+ * Test if it's possible to change contents of the indirect registers.
+ * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
+ * so try to avoid using it.
+*/
+
+  ad_write (devc, 0, 0xaa);
+  ad_write (devc, 1, 0x45);    /* 0x55 with bit 0x10 clear */
+
+  if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45)
+    {
+      DDB (printk ("ad_detect_B (%x/%x)\n", tmp1, tmp2));
+      return 0;
+    }
+
+  ad_write (devc, 0, 0x45);
+  ad_write (devc, 1, 0xaa);
+
+  if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa)
+    {
+      DDB (printk ("ad_detect_C (%x/%x)\n", tmp1, tmp2));
+      return 0;
+    }
+
+  /*
+ * The indirect register I12 has some read only bits. Lets
+ * try to change them.
+ */
+
+  tmp = ad_read (devc, 12);
+  ad_write (devc, 12, (~tmp) & 0x0f);
+
+  if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f))
+    {
+      DDB (printk ("ad_detect_D (%x)\n", tmp1));
+      return 0;
+    }
+
+  /*
+ * NOTE! Last 4 bits of the reg I12 tell the chip revision.
+ *      0x01=RevB and 0x0A=RevC.
+ */
+
+  /*
+ * The original AD1848/CS4248 has just 15 indirect registers. This means
+ * that I0 and I16 should return the same value (etc.).
+ * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
+ * with CS4231.
+ */
+
+  ad_write (devc, 12, 0);      /* Mode2=disabled */
+
+  for (i = 0; i < 16; i++)
+    if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16)))
+      {
+       DDB (printk ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2));
+       return 0;
+      }
+
+  /*
+ * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
+ * The bit 0x80 is always 1 in CS4248 and CS4231.
+ */
+
+  ad_write (devc, 12, 0x40);   /* Set mode2, clear 0x80 */
+
+  tmp1 = ad_read (devc, 12);
+  if (tmp1 & 0x80)
+    devc->chip_name = "CS4248";
+
+  if ((tmp1 & 0xc0) == (0x80 | 0x40))
+    {
+      /*
+        *      CS4231 detected - is it?
+        *
+        *      Verify that setting I0 doesn't change I16.
+        */
+      ad_write (devc, 16, 0);  /* Set I16 to known value */
+
+      ad_write (devc, 0, 0x45);
+      if ((tmp1 = ad_read (devc, 16)) != 0x45) /* No change -> CS4231? */
+       {
+
+         ad_write (devc, 0, 0xaa);
+         if ((tmp1 = ad_read (devc, 16)) == 0xaa)      /* Rotten bits? */
+           {
+             DDB (printk ("ad_detect_H(%x)\n", tmp1));
+             return 0;
+           }
+
+         /*
+        *      It's a CS4231 - So what!
+        *      (Mode2 will be supported later)
+        */
+         devc->chip_name = "CS4231";
+         devc->mode = 2;
+       }
+    }
+
+  return 1;
+}
+
+void
+ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture)
+{
+  /*
+ * NOTE! If irq < 0, there is another driver which has allocated the IRQ
+ *      so that this driver doesn't need to allocate/deallocate it.
+ *      The actually used IRQ is ABS(irq).
+ */
+
+  /*
+ * Initial values for the indirect registers of CS4248/AD1848.
+ */
+  static int      init_values[] =
+  {
+    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+    0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00
+  };
+  int             i, my_dev;
+  ad1848_info    *devc = &dev_info[nr_ad1848_devs];
+
+  if (!ad1848_detect (io_base))
+    return;
+
+  devc->irq = (irq > 0) ? irq : 0;
+  devc->dma_capture = dma_playback;
+  devc->dma_playback = dma_capture;
+  devc->opened = 0;
+
+  if (nr_ad1848_devs != 0)
+    {
+      memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs],
+             (char *) &ad1848_pcm_operations[0],
+             sizeof (struct audio_operations));
+    }
+
+  for (i = 0; i < 16; i++)
+    ad_write (devc, i, init_values[i]);
+
+  OUTB (0, io_Status (devc));  /* Clear pending interrupts */
+
+#ifndef SCO
+  sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
+          "%s (%s)", name, devc->chip_name);
+#endif
+
+  if (irq > 0)
+    printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
+
+  if (num_audiodevs < MAX_AUDIO_DEV)
+    {
+      audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs];
+      if (irq > 0)
+       irq2dev[irq] = my_dev;
+      else if (irq < 0)
+       irq2dev[-irq] = my_dev;
+
+      audio_devs[my_dev]->dmachan = dma_playback;
+      audio_devs[my_dev]->buffcount = 1;
+      audio_devs[my_dev]->buffsize = DSP_BUFFSIZE * 2;
+      audio_devs[my_dev]->devc = devc;
+      audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
+      nr_ad1848_devs++;
+    }
+  else
+    printk ("AD1848: Too many PCM devices available\n");
+}
+
+void
+ad1848_interrupt (int irq)
+{
+  unsigned char   status;
+  ad1848_info    *devc;
+  int             dev;
+
+  if (irq < 0 || irq > 15)
+    return;                    /* Bogus irq */
+  dev = irq2dev[irq];
+  if (dev < 0 || dev >= num_audiodevs)
+    return;                    /* Bogus dev */
+
+  devc = (ad1848_info *) audio_devs[dev]->devc;
+  status = INB (io_Status (devc));
+
+  if (status & 0x01)
+    {
+      if (devc->opened && devc->irq_mode == IMODE_OUTPUT)
+       {
+         DMAbuf_outputintr (dev, 1);
+       }
+
+      if (devc->opened && devc->irq_mode == IMODE_INPUT)
+       DMAbuf_inputintr (dev);
+    }
+
+  OUTB (0, io_Status (devc));  /* Clear interrupt status */
+}
+
+#endif
+/*
+ * Some extra code for the MS Sound System
+ */
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS)
+
+int
+probe_ms_sound (struct address_info *hw_config)
+{
+  int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+
+  if ((INB (hw_config->io_base + 3) & 0x04) == 0)
+    return 0;                  /* WSS ID test failed */
+
+  if (hw_config->irq > 11)
+    return;
+
+  if (hw_config->dma > 3 || hw_config->dma == 2)
+    return;
+
+  return ad1848_detect (hw_config->io_base + 4);
+}
+
+long
+attach_ms_sound (long mem_start, struct address_info *hw_config)
+{
+  static unsigned char interrupt_bits[11] =
+  {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
+  char            bits;
+
+  int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+
+  if (!ad1848_detect (hw_config->io_base + 4))
+    return mem_start;
+
+  /*
+ * Set the IRQ and DMA addresses.
+ */
+
+  bits = interrupt_bits[hw_config->irq];
+  if (bits == -1)
+    return mem_start;
+
+  OUTB (bits | 0x40, config_port);     /* Verify IRQ (I guess) */
+  if ((INB (version_port) & 0x40) == 0)
+    printk ("[IRQ?]");
+
+  OUTB (bits | hw_config->dma, config_port);   /* Write IRQ+DMA setup */
+
+  ad1848_init ("MS Sound System", hw_config->io_base + 4,
+              hw_config->irq,
+              hw_config->dma,
+              hw_config->dma);
+  return mem_start;
+}
+
+#endif
index f27f9d5fa09fd0ed00280bcee871c03576e5790a..d5a4acce44e3b7f72d824d71dfcfdb5314498086 100644 (file)
 #define ON             1
 #define OFF            0
 
-static int      wr_buff_no[MAX_DSP_DEV];       /* != -1, if there is a
+static int      wr_buff_no[MAX_AUDIO_DEV];     /*
+                                                * != -1, if there is
+                                                * a incomplete output
+                                                * block in the queue.
+                                                */
+static int      wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
 
-                                                * incomplete output block */
-static int      wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
-
-static int      audio_mode[MAX_DSP_DEV];
+static int      audio_mode[MAX_AUDIO_DEV];
 
 #define                AM_NONE         0
 #define                AM_WRITE        1
 #define        AM_READ         2
 
-static char    *wr_dma_buf[MAX_DSP_DEV];
+static char    *wr_dma_buf[MAX_AUDIO_DEV];
+static int      audio_format[MAX_AUDIO_DEV];
+static int      local_conversion[MAX_AUDIO_DEV];
+
+static int
+set_format (int dev, int fmt)
+{
+  if (fmt != AFMT_QUERY)
+    {
+
+      local_conversion[dev] = 0;
+
+      if (!(audio_devs[dev]->format_mask & fmt))       /* Not supported */
+       if (fmt == AFMT_MU_LAW)
+         {
+           fmt = AFMT_U8;
+           local_conversion[dev] = AFMT_MU_LAW;
+         }
+       else
+         fmt = AFMT_U8;        /* This is always supported */
+
+      audio_format[dev] = DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, fmt, 1);
+    }
+
+  if (local_conversion[dev])   /* This shadows the HW format */
+    return local_conversion[dev];
+
+  return audio_format[dev];
+}
 
 int
 audio_open (int dev, struct fileinfo *file)
@@ -68,12 +98,21 @@ audio_open (int dev, struct fileinfo *file)
   if ((ret = DMAbuf_open (dev, mode)) < 0)
     return ret;
 
-  if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
+  local_conversion[dev] = 0;
+
+  if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
     {
       audio_release (dev, file);
       return RET_ERROR (ENXIO);
     }
 
+  if (dev_type == SND_DEV_AUDIO)
+    {
+      set_format (dev, AFMT_MU_LAW);
+    }
+  else
+    set_format (dev, bits);
+
   wr_buff_no[dev] = -1;
   audio_mode[dev] = AM_NONE;
 
@@ -128,21 +167,24 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
   int             c, p, l;
   int             err;
-  int             dev_type = dev & 0x0f;
 
   dev = dev >> 4;
 
   p = 0;
   c = count;
 
-  if (audio_mode[dev] == AM_READ)      /* Direction changed */
+  if (audio_mode[dev] == AM_READ)      /*
+                                        * Direction changed
+                                        */
     {
       wr_buff_no[dev] = -1;
     }
 
   audio_mode[dev] = AM_WRITE;
 
-  if (!count)                  /* Flush output */
+  if (!count)                  /*
+                                * Flush output
+                                */
     {
       if (wr_buff_no[dev] >= 0)
        {
@@ -154,11 +196,17 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
     }
 
   while (c)
-    {                          /* Perform output blocking */
-      if (wr_buff_no[dev] < 0) /* There is no incomplete buffers */
+    {                          /*
+                                * Perform output blocking
+                                */
+      if (wr_buff_no[dev] < 0) /*
+                                * There is no incomplete buffers
+                                */
        {
          if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
-           return wr_buff_no[dev];
+           {
+             return wr_buff_no[dev];
+           }
          wr_buff_ptr[dev] = 0;
        }
 
@@ -166,21 +214,27 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
       if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
        l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
 
-      if (!dsp_devs[dev]->copy_from_user)
-       {                       /* No device specific copy routine */
+      if (!audio_devs[dev]->copy_from_user)
+       {                       /*
+                                * No device specific copy routine
+                                */
          COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
        }
       else
-       dsp_devs[dev]->copy_from_user (dev,
+       audio_devs[dev]->copy_from_user (dev,
                              wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
 
 
-      /* Insert local processing here */
+      /*
+       * Insert local processing here
+       */
 
-      if (dev_type == SND_DEV_AUDIO)
+      if (local_conversion[dev] == AFMT_MU_LAW)
        {
 #ifdef linux
-         /* This just allows interrupts while the conversion is running */
+         /*
+          * This just allows interrupts while the conversion is running
+          */
          __asm__ ("sti");
 #endif
          translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
@@ -193,7 +247,9 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
       if (wr_buff_ptr[dev] >= wr_buff_size[dev])
        {
          if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
-           return err;
+           {
+             return err;
+           }
 
          wr_buff_no[dev] = -1;
        }
@@ -209,7 +265,6 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
   int             c, p, l;
   char           *dmabuf;
   int             buff_no;
-  int             dev_type = dev & 0x0f;
 
   dev = dev >> 4;
   p = 0;
@@ -235,12 +290,16 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
       if (l > c)
        l = c;
 
-      /* Insert any local processing here. */
+      /*
+       * Insert any local processing here.
+       */
 
-      if (dev_type == SND_DEV_AUDIO)
+      if (local_conversion[dev] == AFMT_MU_LAW)
        {
 #ifdef linux
-         /* This just allows interrupts while the conversion is running */
+         /*
+          * This just allows interrupts while the conversion is running
+          */
          __asm__ ("sti");
 #endif
 
@@ -262,7 +321,6 @@ int
 audio_ioctl (int dev, struct fileinfo *file,
             unsigned int cmd, unsigned int arg)
 {
-  int             dev_type = dev & 0x0f;
 
   dev = dev >> 4;
 
@@ -293,22 +351,32 @@ audio_ioctl (int dev, struct fileinfo *file,
       return DMAbuf_ioctl (dev, cmd, arg, 0);
       break;
 
-    default:
-      if (dev_type == SND_DEV_AUDIO)
-       return RET_ERROR (EIO);
+    case SNDCTL_DSP_GETFMTS:
+      return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
+      break;
 
+    case SNDCTL_DSP_SETFMT:
+      return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
+
+    default:
       return DMAbuf_ioctl (dev, cmd, arg, 0);
+      break;
     }
 }
 
 long
 audio_init (long mem_start)
 {
+  /*
+ * NOTE! This routine could be called several times during boot.
+ */
   return mem_start;
 }
 
 #else
-/* Stub versions */
+/*
+ * Stub versions
+ */
 
 int
 audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
index dd9a81609c7437549ba8623067ecbd95c547e198..e1cbc7b3021bcb64b778c2e65b86a675e7ccdaa8 100644 (file)
 
 #define OPT_GUS                3
 #define OPT_MPU401     4
-
-#define OPT_HIGHLEVEL   5
-#define OPT_SBPRO      5
-#define OPT_SB16       6
-#define OPT_AUDIO      7
-#define OPT_MIDI_AUTO  8
-#define OPT_MIDI       9
-#define OPT_YM3812_AUTO        10      /* Select this automaticly if user selects
-                                  * MIDI or AdLib driver */
-#define OPT_YM3812     11      /* Select this if the previous one was not
-                                  * selected */
-#define OPT_SEQUENCER  12
-#define OPT_CHIP_MIDI   13     /* New support added at UW - Milwauklee UW -
-                                  * Milwauklee */
-#define OPT_LAST       12
-
-#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)|B(OPT_MPU401))
+#define OPT_UART6850   5
+#define OPT_PSS                6
+#define OPT_GUS16      7
+#define OPT_GUSMAX     8
+#define OPT_MSS                9
+
+#define OPT_HIGHLEVEL   10     /* This must be same than the next one */
+#define OPT_SBPRO      10
+#define OPT_SB16       11
+#define OPT_AUDIO      12
+#define OPT_MIDI_AUTO  13
+#define OPT_MIDI       14
+#define OPT_YM3812_AUTO        15
+#define OPT_YM3812     16
+#define OPT_SEQUENCER  17
+#define OPT_LAST       17      /* Must be the same than the defined OPT */
+
+#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \
+                 B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)|B(OPT_MSS))
+/*
+ * Options that have been disabled for some reason (incompletely implemented
+ * and/or tested). Don't remove from this list before looking at file
+ * experimental.txt for further info.
+ */
+#define DISABLED_OPTIONS (B(OPT_PSS))
 
 typedef struct
   {
@@ -87,24 +95,29 @@ hw_entry;
 
 hw_entry        hw_table[] =
 {
-/* 0 */
+/*
+ * 0
+ */
   {0, 0, "PAS", 1, 0, 0},
   {0, 0, "SB", 1, 0, 0},
   {0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0, 0},
 
-/* 3 */
   {0, 0, "GUS", 1, 0, 0},
   {0, 0, "MPU401", 1, 0, 0},
+  {0, 0, "UART6850", 1, 0, 0},
+  {0, 0, "PSS", 1, 0, 0},
+  {B (OPT_GUS), 0, "GUS16", 1, 0, 0},
+  {B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0},
+  {0, 0, "MSS", 1, 0, 0},
+
   {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1},
   {B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1},
-  {B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1},
+{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1},
   {B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
-  {B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1},
+  {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1},
   {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
-  {B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
-/* 10 */
-  {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1},
-  {0, 0, "CHIP_MIDI", 1, 0, 0}
+  {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
+  {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}
 };
 
 char           *questions[] =
@@ -114,6 +127,11 @@ char           *questions[] =
   "AdLib support",
   "Gravis Ultrasound support",
   "MPU-401 support (NOT for SB16)",
+  "6850 UART Midi support",
+  "PSS (ECHO-ADI2111) support",
+  "16 bit sampling option of GUS (_NOT_ GUS MAX)",
+  "GUS MAX support",
+  "Microsoft Sound System support",
 
   "SoundBlaster Pro support",
   "SoundBlaster 16 support",
@@ -123,7 +141,7 @@ char           *questions[] =
   "This should not be asked",
   "FM synthesizer (YM3812/OPL-3) support",
   "/dev/sequencer support",
-  "MIDI on CHIP support"
+  "Should I die"
 };
 
 unsigned long   selected_options = 0;
@@ -136,12 +154,12 @@ can_select_option (int nr)
     {
     case 0:
       fprintf (stderr, "The SoundBlaster, AdLib and ProAudioSpectrum\n"
-              "cards cannot be installed at the same time\n");
-      fprintf (stderr, "\nSelect at most one of them:\n");
+              "CARDS cannot be installed at the same time.\n\n"
+              "However the PAS16 has a SB emulator so you could select"
+              "the SoundBlaster DRIVER with it.\n");
       fprintf (stderr, "       - ProAudioSpectrum 16\n");
       fprintf (stderr, "       - SoundBlaster / SB Pro\n");
-      fprintf (stderr, "          (Could be selected with PAS16 also\n"
-              "          since there is a SB emulation on it)\n");
+      fprintf (stderr, "          (Could be selected with a PAS16 also)\n");
       fprintf (stderr, "       - AdLib\n");
       fprintf (stderr, "\nDon't enable SoundBlaster if you have GUS at 0x220!\n\n");
       break;
@@ -166,6 +184,9 @@ can_select_option (int nr)
     if (hw_table[nr].exclusive_options & selected_options)
       return 0;
 
+  if (DISABLED_OPTIONS & B (nr))
+    return 0;
+
   return 1;
 }
 
@@ -185,7 +206,9 @@ think_positively (int def_answ)
       exit (-1);
     }
 
-  if (len < 2)                 /* There is an additional LF at the end */
+  if (len < 2)                 /*
+                                * There is an additional LF at the end
+                                */
     return def_answ;
 
   answ[len - 1] = 0;
@@ -214,7 +237,9 @@ play_it_again_Sam:
       exit (-1);
     }
 
-  if (len < 2)                 /* There is an additional LF at the end */
+  if (len < 2)                 /*
+                                * There is an additional LF at the end
+                                */
     return default_answer;
 
   answ[len - 1] = 0;
@@ -242,8 +267,15 @@ main (int argc, char *argv[])
 
   if (think_positively (0))
     {
-      selected_options = 0xffffffff & ~B (OPT_MPU401);
-      fprintf (stderr, "Note! MPU-401 driver was not enabled\n");
+      /*
+ * Select all but some most dangerous cards. These cards are difficult to
+ * detect reliably or conflict with some other cards (SCSI, Mitsumi)
+ */
+      selected_options = 0xffffffff &
+       ~(B (OPT_MPU401) | B (OPT_UART6850) | B (OPT_PSS)) &
+       ~DISABLED_OPTIONS;
+
+      fprintf (stderr, "Note! MPU-401, PSS and 6850 UART drivers not enabled\n");
       full_driver = 1;
     }
   else
@@ -255,14 +287,18 @@ main (int argc, char *argv[])
          printf ("#undef KERNEL_SOUNDCARD\n");
          exit (0);
        }
-      /* Partial driver */
+      /*
+       * Partial driver
+       */
 
       full_driver = 0;
 
       for (i = 0; i <= OPT_LAST; i++)
        if (can_select_option (i))
          {
-           if (!(selected_options & B (i)))    /* Not selected yet */
+           if (!(selected_options & B (i)))    /*
+                                                * Not selected yet
+                                                */
              if (!hw_table[i].verify)
                {
                  if (hw_table[i].alias)
@@ -289,6 +325,73 @@ main (int argc, char *argv[])
   if (selected_options & B (OPT_SB16))
     selected_options |= B (OPT_SBPRO);
 
+  if (selected_options & B (OPT_PSS))
+    {
+    genld_again:
+      fprintf
+       (stderr,
+       "if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n"
+        "then you must include the LD in the kernel.\n"
+        "(do you wish to include a LD) ? ");
+      if (think_positively (1))
+       {
+         char            path[512];
+
+         fprintf (stderr,
+                  "Enter the path to your LD file (pwd is sound): ");
+         scanf ("%s", path);
+         fprintf (stderr, "including LD file %s\n", path);
+         selected_options |= B (OPT_SB) | B (OPT_MPU401) | B (OPT_ADLIB);
+
+         /* Gen LD header */
+         {
+           int             fd;
+           int             count;
+           char            c;
+           int             i = 0;
+
+           if ((fd = open (path, 0)) > 0)
+             {
+               FILE           *sf = fopen ("synth-ld.h", "w");
+
+               fprintf (sf, "/* automaticaly generated by configure */\n");
+               fprintf (sf, "unsigned char pss_synth[] = {\n");
+               while (1)
+                 {
+                   count = read (fd, &c, 1);
+                   if (count == 0)
+                     break;
+                   if (i != 0 && (i % 10) == 0)
+                     fprintf (sf, "\n");
+                   fprintf (sf, "0x%02x,", c & 0xFFL);
+                   i++;
+                 }
+               fprintf (sf, "};\n"
+                        "#define pss_synthLen %d\n", i);
+               fclose (sf);
+               close (fd);
+             }
+           else
+             {
+               fprintf (stderr, "couldn't open %s as the ld file\n",
+                        path);
+               fprintf (stderr, "try again with correct path? ");
+               if (think_positively (1))
+                 goto genld_again;
+             }
+         }
+       }
+      else
+       {
+         FILE           *sf = fopen ("synth-ld.h", "w");
+
+         fprintf (sf, "/* automaticaly generated by configure */\n");
+         fprintf (sf, "unsigned char pss_synth[1];\n"
+                  "#define pss_synthLen 0\n");
+         fclose (sf);
+       }
+    }
+
   if (!(selected_options & ANY_DEVS))
     {
       printf ("#undef CONFIGURE_SOUNDCARD\n");
@@ -307,21 +410,26 @@ main (int argc, char *argv[])
        printf ("#define EXCLUDE_%s\n", hw_table[i].macro);
 
 
-  printf ("#define EXCLUDE_PRO_MIDI\n");
-  printf ("#define EXCLUDE_CHIP_MIDI\n");
-
   /*
    * IRQ and DMA settings
    */
   printf ("\n");
 
 #if defined(linux)
-  if (selected_options & B (OPT_SB) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
+  if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
     {
+      fprintf (stderr, "\nI/O base for SB?\n"
+              "The factory default is 220\n"
+              "Enter the SB I/O base: ");
+
+      num = ask_value ("%x", 0x220);
+      fprintf (stderr, "SB I/O base set to %03x\n", num);
+      printf ("#define SBC_BASE 0x%03x\n", num);
+
       fprintf (stderr, "\nIRQ number for SoundBlaster?\n"
               "The IRQ address is defined by the jumpers on your card.\n"
          "The factory default is either 5 or 7 (depending on the model).\n"
-              "Valid values are 9, 5, 7 and 10.\n"
+              "Valid values are 9(=2), 5, 7 and 10.\n"
               "Enter the value: ");
 
       num = ask_value ("%d", 7);
@@ -332,12 +440,11 @@ main (int argc, char *argv[])
          num = 7;
        }
       fprintf (stderr, "SoundBlaster IRQ set to %d\n", num);
-      printf ("#define SBC_BASE 0x220\n");
+
       printf ("#define SBC_IRQ %d\n", num);
 
-      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS)))
+      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_PSS)))
        {
-
          fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
                   "For SB 1.0, 1.5 and 2.0 this MUST be 1\n"
                   "SB Pro supports DMA channels 0, 1 and 3 (jumper)\n"
@@ -397,7 +504,9 @@ main (int argc, char *argv[])
                   "Enter the value: ");
 
          num = ask_value ("%d", 10);
-         if (num == 6 || num < 3 || num > 15 || num == 2)      /* Illegal */
+         if (num == 6 || num < 3 || num > 15 || num == 2)      /*
+                                                                * Illegal
+                                                                */
            {
 
              fprintf (stderr, "*** Illegal input! ***\n");
@@ -461,7 +570,9 @@ main (int argc, char *argv[])
               "Enter the value: ");
 
       num = ask_value ("%d", 15);
-      if (num == 6 || num < 3 || num > 15 || num == 2) /* Invalid */
+      if (num == 6 || num < 3 || num > 15 || num == 2) /*
+                                                        * Invalid
+                                                        */
        {
 
          fprintf (stderr, "*** Illegal input! ***\n");
@@ -498,11 +609,13 @@ main (int argc, char *argv[])
 
       fprintf (stderr, "\nIRQ number for MPU-401?\n"
               "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
-              "The default value is 5.\n"
+              "The default value is 9.\n"
               "Enter the value: ");
 
-      num = ask_value ("%d", 5);
-      if (num == 6 || num < 3 || num > 15)     /* Used for floppy */
+      num = ask_value ("%d", 9);
+      if (num == 6 || num < 3 || num > 15)     /*
+                                                * Used for floppy
+                                                */
        {
 
          fprintf (stderr, "*** Illegal input! ***\n");
@@ -511,6 +624,161 @@ main (int argc, char *argv[])
       fprintf (stderr, "MPU-401 IRQ set to %d\n", num);
       printf ("#define MPU_IRQ %d\n", num);
     }
+
+  if (selected_options & B (OPT_UART6850))
+    {
+      fprintf (stderr, "\nI/O base for 6850 UART Midi?\n"
+              "Be carefull. No defaults.\n"
+              "Enter the 6850 UART I/O base: ");
+
+      num = ask_value ("%x", 0);
+      if (num == 0)
+       {
+         /*
+ * Invalid value entered
+ */
+         printf ("#define EXCLUDE_UART6850\n");
+       }
+      else
+       {
+         fprintf (stderr, "6850 UART I/O base set to %03x\n", num);
+         printf ("#define U6850_BASE 0x%03x\n", num);
+
+         fprintf (stderr, "\nIRQ number for 6850 UART?\n"
+                  "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
+                  "The default value is 5.\n"
+                  "Enter the value: ");
+
+         num = ask_value ("%d", 5);
+         if (num == 6 || num < 3 || num > 15)  /*
+                                                * Used for floppy
+                                                */
+           {
+
+             fprintf (stderr, "*** Illegal input! ***\n");
+             num = 5;
+           }
+         fprintf (stderr, "6850 UART IRQ set to %d\n", num);
+         printf ("#define U6850_IRQ %d\n", num);
+       }
+    }
+
+  if (selected_options & B (OPT_PSS))
+    {
+      fprintf (stderr, "\nI/O base for PSS?\n"
+              "The factory default is 220\n"
+              "Enter the PSS I/O base: ");
+
+      num = ask_value ("%x", 0x220);
+      fprintf (stderr, "PSS I/O base set to %03x\n", num);
+      printf ("#define PSS_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for PSS?\n"
+              "Valid numbers are: 3, 4, 5, 7, 9(=2) or 10.\n"
+              "The default value is 10.\n"
+              "Enter the value: ");
+
+      num = ask_value ("%d", 10);
+      if (num == 6 || num < 3 || num > 15)     /* Used for floppy */
+       {
+         fprintf (stderr, "*** Illegal input! ***\n");
+         num = 7;
+       }
+      fprintf (stderr, "PSS IRQ set to %d\n", num);
+      printf ("#define PSS_IRQ %d\n", num);
+
+      fprintf (stderr, "\nDMA number for ECHO-PSS?\n"
+              "The default value is 3\n"
+              "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num == 4 || num < 0 || num > 7)
+       {
+         fprintf (stderr, "*** Illegal input! ***\n");
+         num = 3;
+       }
+      fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num);
+      printf ("#define PSS_DMA %d\n", num);
+    }
+
+  if (selected_options & B (OPT_MSS))
+    {
+      fprintf (stderr, "\nI/O base for MSS (MS Sound System)?\n"
+              "The factory default is 530\n"
+              "Other possible values are  604, E80 or F40\n"
+              "Enter the MSS I/O base: ");
+
+      num = ask_value ("%x", 0x530);
+      fprintf (stderr, "MSS I/O base set to %03x\n", num);
+      printf ("#define MSS_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for MSS?\n"
+              "Valid numbers are: 7, 9(=2), 10 and 11.\n"
+              "The default value is 10.\n"
+              "Enter the value: ");
+
+      num = ask_value ("%d", 10);
+      if (num == 6 || num < 3 || num > 15)     /* Used for floppy */
+       {
+         fprintf (stderr, "*** Illegal input! ***\n");
+         num = 7;
+       }
+      fprintf (stderr, "MSS IRQ set to %d\n", num);
+      printf ("#define MSS_IRQ %d\n", num);
+
+      fprintf (stderr, "\nDMA number for MSS?\n"
+              "Valid values are 1 and 3 (sometimes 0)"
+              "The default value is 3\n"
+              "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num == 4 || num < 0 || num > 7)
+       {
+         fprintf (stderr, "*** Illegal input! ***\n");
+         num = 3;
+       }
+      fprintf (stderr, "\nMSS DMA set to %d\n", num);
+      printf ("#define MSS_DMA %d\n", num);
+    }
+
+  if (selected_options & B (OPT_GUS16))
+    {
+      fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n"
+              "The factory default is 530\n"
+              "Other possible values are  604, E80 or F40\n"
+              "Enter the GUS16 I/O base: ");
+
+      num = ask_value ("%x", 0x530);
+      fprintf (stderr, "GUS16 I/O base set to %03x\n", num);
+      printf ("#define GUS16_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for GUS16?\n"
+              "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n"
+              "The default value is 7.\n"
+              "Enter the value: ");
+
+      num = ask_value ("%d", 7);
+      if (num == 6 || num < 3 || num > 15)     /* Used for floppy */
+       {
+         fprintf (stderr, "*** Illegal input! ***\n");
+         num = 7;
+       }
+      fprintf (stderr, "GUS16 IRQ set to %d\n", num);
+      printf ("#define GUS16_IRQ %d\n", num);
+
+      fprintf (stderr, "\nDMA number for GUS16?\n"
+              "The default value is 3\n"
+              "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num < 0 || num > 3)
+       {
+         fprintf (stderr, "*** Illegal input! ***\n");
+         num = 3;
+       }
+      fprintf (stderr, "\nGUS16 DMA set to %d\n", num);
+      printf ("#define GUS16_DMA %d\n", num);
+    }
 #endif
 
   if (selected_options & B (OPT_AUDIO))
@@ -521,9 +789,12 @@ main (int argc, char *argv[])
        def_size = 32768;
 
 #ifndef __386BSD__
-      if (((selected_options & B (OPT_PAS)) || (selected_options & B (OPT_SB16))) &&
+      if ((selected_options & (B (OPT_PAS) | B (OPT_PAS) | B (OPT_GUS16) | B (OPT_GUSMAX) |
+                              B (OPT_MSS) | B (OPT_PSS))) &&
          !full_driver)
-       def_size = 65536;       /* PAS16 or SB16 */
+       def_size = 65536;       /*
+                                * PAS16 or SB16
+                                */
 #endif
 
       fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n"
index 7f7cae11d02e77ab9ab6441de95cf4114b742dfe..1eb57bbb08c12de62e83d8c59f2b1d83dd91f0df 100644 (file)
 
 #ifdef CONFIGURE_SOUNDCARD
 
+int
+snd_find_driver (int type)
+{
+  int             i, n = sizeof (sound_drivers) / sizeof (struct driver_info);
+
+  for (i = 0; i < (n - 1); i++)
+    if (sound_drivers[i].card_type == type)
+      return i;
+
+  return -1;                   /*
+                                * Not found
+                                */
+}
+
 long
 sndtable_init (long mem_start)
 {
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+  int             drv;
 
   for (i = 0; i < (n - 1); i++)
-    if (supported_drivers[i].enabled)
-      if (supported_drivers[i].probe (&supported_drivers[i].config))
+    if (snd_installed_cards[i].enabled)
+      if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
+       snd_installed_cards[i].enabled = 0;     /*
+                                                * Mark as not detected
+                                                */
+      else if (sound_drivers[drv].probe (&snd_installed_cards[i].config))
        {
 #ifndef SHORT_BANNERS
          printk ("snd%d",
-                 supported_drivers[i].card_type);
+                 snd_installed_cards[i].card_type);
 #endif
 
-         mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
+         mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config);
 #ifndef SHORT_BANNERS
          printk (" at 0x%x irq %d drq %d\n",
-                 supported_drivers[i].config.io_base,
-                 supported_drivers[i].config.irq,
-                 supported_drivers[i].config.dma);
+                 snd_installed_cards[i].config.io_base,
+                 snd_installed_cards[i].config.irq,
+                 snd_installed_cards[i].config.dma);
 #endif
        }
       else
-       supported_drivers[i].enabled = 0;       /* Mark as not detected */
+       snd_installed_cards[i].enabled = 0;     /*
+                                                * Mark as not detected
+                                                */
   return mem_start;
 }
 
 int
 sndtable_probe (int unit, struct address_info *hw_config)
-{
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+  {
+    int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
-  if (!unit)
-    return TRUE;
-
-  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 (!unit)
+      return TRUE;
 
-  return FALSE;
-}
+    for (i = 0; i < (n - 1); i++)
+      if (snd_installed_cards[i].enabled)
+       if (snd_installed_cards[i].card_type == unit)
+         {
+           int             drv;
+
+           snd_installed_cards[i].config.io_base = hw_config->io_base;
+           snd_installed_cards[i].config.irq = hw_config->irq;
+           snd_installed_cards[i].config.dma = hw_config->dma;
+           if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
+             snd_installed_cards[i].enabled = 0;       /*
+                                                        * Mark as not
+                                                        * detected
+                                                        */
+           else if (sound_drivers[drv].probe (hw_config))
+             return 1;
+           snd_installed_cards[i].enabled = 0; /*
+                                                * Mark as not detected
+                                                */
+           return 0;
+         }
+
+    return FALSE;
+  }
 
 int
 sndtable_init_card (int unit, struct address_info *hw_config)
-{
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
-
-  if (!unit)
-    {
-      if (sndtable_init (0) != 0)
-       panic ("snd: Invalid memory allocation\n");
-      return TRUE;
-    }
+  {
+    int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
-  for (i = 0; i < (n - 1); i++)
-    if (supported_drivers[i].card_type == unit)
+    if (!unit)
       {
-       supported_drivers[i].config.io_base = hw_config->io_base;
-       supported_drivers[i].config.irq = hw_config->irq;
-       supported_drivers[i].config.dma = hw_config->dma;
-
-       if (supported_drivers[i].attach (0, hw_config) != 0)
-         panic ("snd#: Invalid memory allocation\n");
+       if (sndtable_init (0) != 0)
+         panic ("snd: Invalid memory allocation\n");
        return TRUE;
       }
 
-  return FALSE;
-}
+    for (i = 0; i < (n - 1); i++)
+      if (snd_installed_cards[i].card_type == unit)
+       {
+         int             drv;
+
+         snd_installed_cards[i].config.io_base = hw_config->io_base;
+         snd_installed_cards[i].config.irq = hw_config->irq;
+         snd_installed_cards[i].config.dma = hw_config->dma;
+
+         if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
+           snd_installed_cards[i].enabled = 0; /*
+                                                * Mark as not detected
+                                                */
+         else if (sound_drivers[drv].attach (0, hw_config) != 0)
+           panic ("snd#: Invalid memory allocation\n");
+         return TRUE;
+       }
+
+    return FALSE;
+  }
 
 int
 sndtable_get_cardcount (void)
 {
-  return num_dspdevs + num_mixers + num_synths + num_midis;
+  return num_audiodevs + num_mixers + num_synths + num_midis;
 }
 
 #ifdef linux
 void
 sound_setup (char *str, int *ints)
 {
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
   /*
  * First disable all drivers
  */
 
   for (i = 0; i < n; i++)
-    supported_drivers[i].enabled = 0;
+    snd_installed_cards[i].enabled = 0;
 
   if (ints[0] == 0 || ints[1] == 0)
     return;
@@ -145,7 +182,9 @@ sound_setup (char *str, int *ints)
 
       if (card_type > 127)
        {
-         /* Add any future extensions here */
+         /*
+          * Add any future extensions here
+          */
          return;
        }
 
@@ -155,17 +194,20 @@ sound_setup (char *str, int *ints)
 
       ptr = -1;
       for (j = 0; j < n && ptr == -1; j++)
-       if (supported_drivers[j].card_type == card_type)
+       if (snd_installed_cards[j].card_type == card_type &&
+           !snd_installed_cards[j].enabled)    /*
+                                                * Not already found
+                                                */
          ptr = j;
 
       if (ptr == -1)
        printk ("Sound: Invalid setup parameter 0x%08x\n", val);
       else
        {
-         supported_drivers[ptr].enabled = 1;
-         supported_drivers[ptr].config.io_base = ioaddr;
-         supported_drivers[ptr].config.irq = irq;
-         supported_drivers[ptr].config.dma = dma;
+         snd_installed_cards[ptr].enabled = 1;
+         snd_installed_cards[ptr].config.io_base = ioaddr;
+         snd_installed_cards[ptr].config.irq = irq;
+         snd_installed_cards[ptr].config.dma = dma;
        }
     }
 }
@@ -174,24 +216,27 @@ sound_setup (char *str, int *ints)
 void
 sound_chconf (int card_type, int ioaddr, int irq, int dma)
 {
-  int             i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
   int             ptr, j;
 
   ptr = -1;
   for (j = 0; j < n && ptr == -1; j++)
-    if (supported_drivers[j].card_type == card_type)
+    if (snd_installed_cards[j].card_type == card_type &&
+       !snd_installed_cards[j].enabled)        /*
+                                                * Not already found
+                                                */
       ptr = j;
 
   if (ptr != -1)
     {
-      supported_drivers[ptr].enabled = 1;
+      snd_installed_cards[ptr].enabled = 1;
       if (ioaddr)
-       supported_drivers[ptr].config.io_base = ioaddr;
+       snd_installed_cards[ptr].config.io_base = ioaddr;
       if (irq)
-       supported_drivers[ptr].config.irq = irq;
+       snd_installed_cards[ptr].config.irq = irq;
       if (dma)
-       supported_drivers[ptr].config.dma = dma;
+       snd_installed_cards[ptr].config.dma = dma;
     }
 }
 
@@ -201,17 +246,24 @@ struct address_info *
 sound_getconf (int card_type)
 {
   int             j, ptr;
-  int             n = sizeof (supported_drivers) / sizeof (struct card_info);
+  int             n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
   ptr = -1;
   for (j = 0; j < n && ptr == -1; j++)
-    if (supported_drivers[j].card_type == card_type)
+    if (snd_installed_cards[j].card_type == card_type)
       ptr = j;
 
   if (ptr == -1)
     return (struct address_info *) NULL;
 
-  return &supported_drivers[ptr].config;
+  return &snd_installed_cards[ptr].config;
+}
+
+#else
+
+void
+sound_setup (char *str, int *ints)
+{
 }
 
 #endif
index 4b656ba39c2b8a98241f8567b645cc626fb0b794..a2bf8e68931e4bf7cb6df4ad30987d7d2adefe51 100644 (file)
  *     NOTE!   NOTE!   NOTE!   NOTE!
  */
 
-struct card_info {
-       int card_type;  /*      From soundcard.c        */
+struct driver_info {
+       int card_type;  /*      From soundcard.h        */
        char *name;
        long (*attach) (long mem_start, struct address_info *hw_config);
        int (*probe) (struct address_info *hw_config);
+};
+
+struct card_info {
+       int card_type;  /* Link (search key) to the driver list */
        struct address_info config;
        int enabled;
 };
 
-/** UWM -- new  MIDI structure here.. **/
+/*
+ * Device specific parameters (used only by dmabuf.c)
+ */
+#define MAX_SUB_BUFFERS                (32*MAX_REALTIME_FACTOR)
+
+#define DMODE_NONE             0
+#define DMODE_OUTPUT           1
+#define DMODE_INPUT            2
+
+struct dma_buffparms {
+       int      dma_mode;      /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
+
+       /*
+        * Pointers to raw buffers
+        */
+
+       char     *raw_buf[DSP_BUFFCOUNT];
+       unsigned long   raw_buf_phys[DSP_BUFFCOUNT];
+       int             raw_count;
 
-struct generic_midi_info{
-        char *name;    /* Name of the MIDI device.. */
-        long (*attach) (long mem_start);
+       /*
+         * Device state tables
+         */
+
+       unsigned long flags;
+#define DMA_BUSY       0x00000001
+#define DMA_RESTART    0x00000002
+#define DMA_ACTIVE     0x00000004
+#define DMA_STARTED    0x00000008
+#define DMA_ALLOC_DONE 0x00000020
+
+       int      open_mode;
+
+       /*
+        * Queue parameters.
+        */
+               int      qlen;
+               int      qhead;
+               int      qtail;
+
+       int      nbufs;
+       int      counts[MAX_SUB_BUFFERS];
+       int      subdivision;
+       char    *buf[MAX_SUB_BUFFERS];
+       unsigned long buf_phys[MAX_SUB_BUFFERS];
+
+       int      fragment_size;
+       int      max_fragments;
+
+       int      bytes_in_use;
+
+       int      underrun_count;
 };
 
 struct audio_operations {
@@ -61,6 +112,9 @@ struct audio_operations {
        int flags;
 #define NOTHING_SPECIAL        0
 #define NEEDS_RESTART          1
+#define DMA_AUTOMODE           2
+       int  format_mask;       /* Bitmask for supported audio formats */
+       void *devc;             /* Driver specific info */
        int (*open) (int dev, int mode);
        void (*close) (int dev);
        void (*output_block) (int dev, unsigned long buf, 
@@ -72,9 +126,13 @@ struct audio_operations {
        int (*prepare_for_output) (int dev, int bufsize, int nbufs);
        void (*reset) (int dev);
        void (*halt_xfer) (int dev);
-       int (*has_output_drained)(int dev);
+       int (*local_qlen)(int dev);
         void (*copy_from_user)(int dev, char *localbuf, int localoffs,
                                snd_rw_buf *userbuf, int useroffs, int len);
+       int buffcount;
+       long buffsize;
+       int dmachan;
+       struct dma_buffparms *dmap;
 };
 
 struct mixer_operations {
@@ -83,13 +141,14 @@ struct mixer_operations {
 
 struct synth_operations {
        struct synth_info *info;
+       int midi_dev;
        int synth_type;
        int synth_subtype;
 
        int (*open) (int dev, int mode);
        void (*close) (int dev);
        int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
-       int (*kill_note) (int dev, int voice, int velocity);
+       int (*kill_note) (int dev, int voice, int note, int velocity);
        int (*start_note) (int dev, int voice, int note, int velocity);
        int (*set_instr) (int dev, int voice, int instr);
        void (*reset) (int dev);
@@ -101,10 +160,16 @@ struct synth_operations {
        void (*panning) (int dev, int voice, int value);
        void (*volume_method) (int dev, int mode);
        int (*pmgr_interface) (int dev, struct patmgr_info *info);
+       void (*bender) (int dev, int chn, int value);
+       int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc);
+
+       struct voice_alloc_info alloc;
+       struct channel_info chn_info[16];
 };
 
 struct midi_operations {
        struct midi_info info;
+       struct synth_operations *converter;
        int (*open) (int dev, int mode,
                void (*inputintr)(int dev, unsigned char data),
                void (*outputintr)(int dev)
@@ -115,159 +180,163 @@ struct midi_operations {
        int (*start_read) (int dev);
        int (*end_read) (int dev);
        void (*kick)(int dev);
-       int (*command) (int dev, unsigned char data);
+       int (*command) (int dev, unsigned char *data);
        int (*buffer_status) (int dev);
+       int (*prefix_cmd) (int dev, unsigned char status);
 };
 
-/** UWM -- new structure for MIDI  **/
-
-struct generic_midi_operations {
-       struct midi_info info;
-       int (*open) (int dev, int mode);
-       void (*close) (int dev);
-       int (*write) (int dev, snd_rw_buf *data);
-       int (*read)  (int dev, snd_rw_buf *data);
-};     
-
-#ifndef ALL_EXTERNAL_TO_ME
-
-#ifdef _MIDI_TABLE_C_
-
-/** UWM **/
-       struct generic_midi_operations * generic_midi_devs[MAX_MIDI_DEV] = {NULL}; 
-       int num_generic_midis = 0, pro_midi_dev = 0; 
-
-      struct generic_midi_info midi_supported[] = {
+struct sound_timer_operations {
+       struct sound_timer_info info;
+       int priority;
+       int devlink;
+       int (*open)(int dev, int mode);
+       void (*close)(int dev);
+       int (*event)(int dev, unsigned char *ev);
+       unsigned long (*get_time)(int dev);
+       int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+       void (*arm_timer)(int dev, long time);
+};
 
-#ifndef EXCLUDE_PRO_MIDI
-        {"ProAudioSpectrum MV101",pro_midi_attach}
+#ifdef _DEV_TABLE_C_   
+       struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0;
+       struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
+       struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0;
+       struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
+
+#ifndef EXCLUDE_SEQUENCER
+       extern struct sound_timer_operations default_sound_timer;
+       struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = 
+               {&default_sound_timer, NULL}; 
+       int num_sound_timers = 1;
+#else
+       struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = 
+               {NULL}; 
+       int num_sound_timers = 0;
 #endif
-        }; 
 
-        int num_midi_drivers = 
-            sizeof (midi_supported) / sizeof(struct generic_midi_info);
+/*
+ * List of low level drivers compiled into the kernel.
+ */
 
+       struct driver_info sound_drivers[] = {
+#ifndef EXCLUDE_PSS
+         {SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss},
 #endif
-
-
-#ifdef _DEV_TABLE_C_   
-       struct audio_operations * dsp_devs[MAX_DSP_DEV] = {NULL}; int num_dspdevs = 0;
-       struct mixer_operations * mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
-       struct synth_operations * synth_devs[MAX_SYNTH_DEV] = {NULL}; int num_synths = 0;
-       struct midi_operations * midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
-
-
-#   ifndef EXCLUDE_MPU401
-        int mpu401_dev = 0;
-#   endif
+#ifndef EXCLUDE_YM3812
+               {SNDCARD_ADLIB, "OPL-2/OPL-3 FM",               attach_adlib_card, probe_adlib},
+#endif
+#ifndef EXCLUDE_PAS
+               {SNDCARD_PAS,   "ProAudioSpectrum",     attach_pas_card, probe_pas},
+#endif
+#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+               {SNDCARD_MPU401,"Roland MPU-401",       attach_mpu401, probe_mpu401},
+#endif
+#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+               {SNDCARD_UART6850,"6860 UART Midi",     attach_uart6850, probe_uart6850},
+#endif
+#ifndef EXCLUDE_SB
+               {SNDCARD_SB,    "SoundBlaster",         attach_sb_card, probe_sb},
+#endif
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
+#ifndef EXCLUDE_AUDIO
+               {SNDCARD_SB16,  "SoundBlaster16",       sb16_dsp_init, sb16_dsp_detect},
+#endif
+#ifndef EXCLUDE_MIDI
+               {SNDCARD_SB16MIDI,"SB16 MIDI",  attach_sb16midi, probe_sb16midi},
+#endif
+#endif
+#ifndef EXCLUDE_GUS16
+               {SNDCARD_GUS16, "Ultrasound 16-bit opt.",       attach_gus_db16, probe_gus_db16},
+#endif
+#ifndef EXCLUDE_MSS
+               {SNDCARD_MSS,   "MS Sound System",      attach_ms_sound, probe_ms_sound},
+#endif
+#ifndef EXCLUDE_GUS
+               {SNDCARD_GUS,   "Gravis Ultrasound",    attach_gus_card, probe_gus},
+#endif
+               {0,                     "*?*",                  NULL, NULL}
+       };
 
 /*
+ *     List of devices actually configured in the system.
+ *
  *     Note! The detection order is significant. Don't change it.
  */
 
-       struct card_info supported_drivers[] = {
+       struct card_info snd_installed_cards[] = {
+#ifndef EXCLUDE_PSS
+            {SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE},
+#endif
 #if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
-               {SNDCARD_MPU401,"Roland MPU-401",       attach_mpu401, probe_mpu401,
-                       {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+               {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+#ifdef MPU2_BASE
+               {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef MPU3_BASE
+               {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+#endif
+#ifndef EXCLUDE_MSS
+               {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE},
+#endif
+
+#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+               {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifndef EXCLUDE_PAS
-               {SNDCARD_PAS,   "ProAudioSpectrum",     attach_pas_card, probe_pas,
-                       {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
+               {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifndef EXCLUDE_SB
-               {SNDCARD_SB,    "SoundBlaster",         attach_sb_card, probe_sb,
-                       {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
+               {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
 #ifndef EXCLUDE_AUDIO
-               {SNDCARD_SB16,  "SoundBlaster16",       sb16_dsp_init, sb16_dsp_detect,
-                       {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
+               {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
 #endif
 #ifndef EXCLUDE_MIDI
-               {SNDCARD_SB16MIDI,"SB16 MPU-401",       attach_sb16midi, probe_sb16midi,
-                       {SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
+               {SNDCARD_SB16MIDI,{SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
 #endif
 #endif
 
 #ifndef EXCLUDE_GUS
-               {SNDCARD_GUS,   "Gravis Ultrasound",    attach_gus_card, probe_gus,
-                       {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
+#ifndef EXCLUDE_GUS16
+               {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA}, SND_DEFAULT_ENABLE},
+#endif
+               {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifndef EXCLUDE_YM3812
-               {SNDCARD_ADLIB, "AdLib",                attach_adlib_card, probe_adlib,
-                       {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
+               {SNDCARD_ADLIB, {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
 #endif
-               {0,                     "*?*",                  NULL, 0}
+               {0, {0}, 0}
        };
 
        int num_sound_drivers =
-           sizeof(supported_drivers) / sizeof (struct card_info);
+           sizeof(sound_drivers) / sizeof (struct driver_info);
+       int num_sound_cards =
+           sizeof(snd_installed_cards) / sizeof (struct card_info);
 
 
-# ifndef EXCLUDE_AUDIO 
-       int sound_buffcounts[MAX_DSP_DEV] = {0};
-       long sound_buffsizes[MAX_DSP_DEV] = {0};
-       int sound_dsp_dmachan[MAX_DSP_DEV] = {0};
-       int sound_dma_automode[MAX_DSP_DEV] = {0};
-# endif
 #else
-       extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs;
+       extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs;
        extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
-       extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths;
+       extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths;
        extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
-#   ifndef EXCLUDE_MPU401
-        extern int mpu401_dev;
-#   endif
+       extern struct sound_timer_operations * sound_timer_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_sound_timers;
 
-       extern struct card_info supported_drivers[];
+       extern struct driver_info sound_drivers[];
        extern int num_sound_drivers;
-
-# ifndef EXCLUDE_AUDIO
-       extern int sound_buffcounts[MAX_DSP_DEV];
-       extern long sound_buffsizes[MAX_DSP_DEV];
-       extern int sound_dsp_dmachan[MAX_DSP_DEV];
-       extern int sound_dma_automode[MAX_DSP_DEV];
-# endif
-
-#endif
+       extern struct card_info snd_installed_cards[];
+       extern int num_sound_cards;
 
 long sndtable_init(long mem_start);
 int sndtable_get_cardcount (void);
-long CMIDI_init(long mem_start); /* */
 struct address_info *sound_getconf(int card_type);
 void sound_chconf(int card_type, int ioaddr, int irq, int dma);
-#endif
+int snd_find_driver(int type);
 
-#endif
-
-/* If external to me.... :) */
-
-#ifdef ALL_EXTERNAL_TO_ME
-
-       extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs;
-        extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
-        extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths;
-        extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
-       extern struct generic_midi_operations *generic_midi_devs[]; 
-       extern int num_generic_midis, pro_midi_dev;
-#ifndef EXCLUDE_MPU401
-        extern int mpu401_dev;
-#endif
-
-       extern struct generic_midi_info midi_supported[];
-       extern struct card_info supported_drivers[];
-        extern int num_sound_drivers;
-       extern int num_midi_drivers;    
-#ifndef EXCLUDE_AUDIO
-        extern int sound_buffcounts[MAX_DSP_DEV];
-        extern long sound_buffsizes[MAX_DSP_DEV];
-        extern int sound_dsp_dmachan[MAX_DSP_DEV];
-        extern int sound_dma_automode[MAX_DSP_DEV];
-#endif
-
-#endif
+#endif /* _DEV_TABLE_C_ */
+#endif /* _DEV_TABLE_H_ */
index 7ffa146979ae5b69824036e8524ed764059260c2..0e275b6a3aea1cef99e1a04cf8043dae35ad87dc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * The DMA buffer manager for digitized voice applications
  *
- * Copyright by Hannu Savolainen 1993
+ * Copyright by Hannu Savolainen 1993, 1994
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
 
 #if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
 
-#define MAX_SUB_BUFFERS                (32*MAX_REALTIME_FACTOR)
+DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
 
-/*
- * The DSP channel can be used either for input or output. Variable
- * 'dma_mode' will be set when the program calls read or write first time
- * after open. Current version doesn't support mode changes without closing
- * and reopening the device. Support for this feature may be implemented in a
- * future version of this driver.
- */
-
-#define DMODE_NONE             0
-#define DMODE_OUTPUT           1
-#define DMODE_INPUT            2
-
-DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]);
-
-static int      dma_mode[MAX_DSP_DEV] =
-{0};                           /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
-
-static volatile int dmabuf_interrupted[MAX_DSP_DEV] =
-{0};
-
-/*
- * Pointers to raw buffers
- */
-
-char           *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT] =
-{
-  {NULL}};
-unsigned long   snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
-int             snd_raw_count[MAX_DSP_DEV];
-
-/*
- * Device state tables
- */
-
-static int      dev_busy[MAX_DSP_DEV];
-static int      dev_needs_restart[MAX_DSP_DEV];
-static int      dev_modes[MAX_DSP_DEV];
-static int      dev_active[MAX_DSP_DEV];
-static int      dev_started[MAX_DSP_DEV];
-static int      dev_qlen[MAX_DSP_DEV];
-static int      dev_qhead[MAX_DSP_DEV];
-static int      dev_qtail[MAX_DSP_DEV];
-static int      dev_underrun[MAX_DSP_DEV];
-static int      bufferalloc_done[MAX_DSP_DEV] =
-{0};
-
-/*
- * Logical buffers for each devices
- */
-
-static int      dev_nbufs[MAX_DSP_DEV];        /* # of logical buffers ( >=
-
-                                                  * sound_buffcounts[dev] */
-static int      dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS];
-static int      dev_subdivision[MAX_DSP_DEV];
-static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS];
-static char    *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] =
-{
-  {NULL}};
-static int      dev_buffsize[MAX_DSP_DEV];
+static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
+{0};                           /*
+                * Primitive way to allocate
+                * such a large array.
+                * Needs dynamic run-time alloction.
+                */
 
 static void
 reorganize_buffers (int dev)
@@ -105,130 +51,159 @@ reorganize_buffers (int dev)
    * This routine breaks the physical device buffers to logical ones.
    */
 
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+  struct audio_operations *dsp_dev = audio_devs[dev];
+
   unsigned        i, p, n;
   unsigned        sr, nc, sz, bsz;
 
-  sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
-  nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
-  sz = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
+  if (dmap->fragment_size == 0)
+    {                          /* Compute the fragment size using the default algorithm */
 
-  if (sr < 1 || nc < 1 || sz < 1)
-    {
-      printk ("SOUND: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);
-      sr = DSP_DEFAULT_SPEED;
-      nc = 1;
-      sz = 8;
-    }
+      sr = dsp_dev->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
+      nc = dsp_dev->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
+      sz = dsp_dev->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
+
+      if (sr < 1 || nc < 1 || sz < 1)
+       {
+         printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
+                 dev, sr, nc, sz);
+         sr = DSP_DEFAULT_SPEED;
+         nc = 1;
+         sz = 8;
+       }
 
-  sz /= 8;                     /* Convert # of bits -> # of bytes */
+      sz /= 8;                 /* #bits -> #bytes */
 
-  sz = sr * nc * sz;
+      sz = sr * nc * sz;
 
-  /*
-   * Compute a buffer size not exeeding 1 second.
+      /*
+   * Compute a buffer size for time not exeeding 1 second.
+   * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
+   * of sound (using the current speed, sample size and #channels).
    */
 
-  bsz = sound_buffsizes[dev];
+      bsz = dsp_dev->buffsize;
+      while (bsz > sz)
+       bsz /= 2;
 
-  while (bsz > sz)
-    bsz >>= 1;                 /* Divide by 2 */
+      if (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize)
+       bsz /= 2;               /* Needs at least 2 buffers */
 
-  if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev])
-    bsz >>= 1;                 /* Need at least 2 buffers */
+      if (dmap->subdivision == 0)      /* Not already set */
+       dmap->subdivision = 1;  /* Init to default value */
 
-  if (dev_subdivision[dev] == 0)
-    dev_subdivision[dev] = 1;  /* Default value */
+      bsz /= dmap->subdivision;
 
-  bsz /= dev_subdivision[dev]; /* Use smaller buffers */
+      if (bsz < 64)
+       bsz = 4096;             /* Just a sanity check */
 
-  if (bsz == 0)
-    bsz = 4096;                        /* Just a sanity check */
+      while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS)
+       bsz *= 2;
 
-  while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS)
-    bsz <<= 1;                 /* Too much buffers */
-
-  dev_buffsize[dev] = bsz;
-  n = 0;
+      dmap->fragment_size = bsz;
+    }
+  else
+    {
+      /*
+ * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
+ * the buffer sice computation has already been done.
+ */
+      if (dmap->fragment_size > audio_devs[dev]->buffsize)
+       dmap->fragment_size = audio_devs[dev]->buffsize;
+      bsz = dmap->fragment_size;
+    }
 
   /*
    * Now computing addresses for the logical buffers
    */
 
-  for (i = 0; i < snd_raw_count[dev]; i++)
+  n = 0;
+  for (i = 0; i < dmap->raw_count &&
+       n < dmap->max_fragments &&
+       n < MAX_SUB_BUFFERS; i++)
     {
       p = 0;
 
-      while ((p + bsz) <= sound_buffsizes[dev])
+      while ((p + bsz) <= dsp_dev->buffsize &&
+            n < dmap->max_fragments &&
+            n < MAX_SUB_BUFFERS)
        {
-         dev_buf[dev][n] = snd_raw_buf[dev][i] + p;
-         dev_buf_phys[dev][n] = snd_raw_buf_phys[dev][i] + p;
+         dmap->buf[n] = dmap->raw_buf[i] + p;
+         dmap->buf_phys[n] = dmap->raw_buf_phys[i] + p;
          p += bsz;
          n++;
        }
     }
 
-  dev_nbufs[dev] = n;
+  dmap->nbufs = n;
+  dmap->bytes_in_use = n * bsz;
 
-  for (i = 0; i < dev_nbufs[dev]; i++)
+  for (i = 0; i < dmap->nbufs; i++)
     {
-      dev_counts[dev][i] = 0;
+      dmap->counts[i] = 0;
     }
 
-  bufferalloc_done[dev] = 1;
+  dmap->flags |= DMA_ALLOC_DONE;
 }
 
 static void
 dma_init_buffers (int dev)
 {
-  RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
-  dev_underrun[dev] = 0;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev];
 
-  dev_busy[dev] = 1;
+  RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
 
-  bufferalloc_done[dev] = 0;
+  dmap->flags = DMA_BUSY;      /* Other flags off */
+  dmap->qlen = dmap->qhead = dmap->qtail = 0;
 
-  dev_active[dev] = dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
-  dev_needs_restart[dev] = dev_started[dev] = 0;
-  dma_mode[dev] = DMODE_NONE;
+  dmap->qlen = dmap->qtail = dmap->qhead = 0;
+  dmap->dma_mode = DMODE_NONE;
 }
 
 int
 DMAbuf_open (int dev, int mode)
 {
   int             retval;
+  struct dma_buffparms *dmap = NULL;
 
-  if (dev >= num_dspdevs)
+  if (dev >= num_audiodevs)
     {
       printk ("PCM device %d not installed.\n", dev);
       return RET_ERROR (ENXIO);
     }
 
-  if (dev_busy[dev])
-    return RET_ERROR (EBUSY);
-
-  if (!dsp_devs[dev])
+  if (!audio_devs[dev])
     {
-      printk ("DSP device %d not initialized\n", dev);
+      printk ("PCM device %d not initialized\n", dev);
       return RET_ERROR (ENXIO);
     }
 
+  dmap = audio_devs[dev]->dmap = &dmaps[dev];
+
+  if (dmap->flags & DMA_BUSY)
+    return RET_ERROR (EBUSY);
+
 #ifdef USE_RUNTIME_DMAMEM
+  dmap->raw_buf[0] = NULL;
   sound_dma_malloc (dev);
 #endif
 
-  if (snd_raw_buf[dev][0] == NULL)
+  if (dmap->raw_buf[0] == NULL)
     return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
 
-  if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)
+  if ((retval = audio_devs[dev]->open (dev, mode)) < 0)
     return retval;
 
-  dev_modes[dev] = mode;
-  dev_subdivision[dev] = 0;
+  dmap->open_mode = mode;
+  dmap->subdivision = dmap->underrun_count = 0;
+  dmap->fragment_size = 0;
+  dmap->max_fragments = 65536; /* Just a large value */
 
   dma_init_buffers (dev);
-  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
-  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
-  dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
+  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
+  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
+  audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
 
   return 0;
 }
@@ -240,10 +215,11 @@ dma_reset (int dev)
   unsigned long   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)
+  audio_devs[dev]->reset (dev);
+  audio_devs[dev]->close (dev);
+
+  if ((retval = audio_devs[dev]->open (dev, audio_devs[dev]->dmap->open_mode)) < 0)
     printk ("Sound: Reset failed - Can't reopen device\n");
   RESTORE_INTR (flags);
 
@@ -256,17 +232,19 @@ dma_sync (int dev)
 {
   unsigned long   flags;
 
-  if (dma_mode[dev] == DMODE_OUTPUT)
+  if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)
     {
       DISABLE_INTR (flags);
 
-      while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
-               dmabuf_interrupted[dev]))
-            && dev_qlen[dev])
+      while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])
+            && audio_devs[dev]->dmap->qlen)
        {
          DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
          if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
-           return dev_qlen[dev];
+           {
+             RESTORE_INTR (flags);
+             return audio_devs[dev]->dmap->qlen;
+           }
        }
       RESTORE_INTR (flags);
 
@@ -276,27 +254,26 @@ dma_sync (int dev)
        */
 
       DISABLE_INTR (flags);
-      if (dsp_devs[dev]->has_output_drained)   /* Device has hidden buffers */
+      if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */
        {
-         while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
-                  dmabuf_interrupted[dev])
-                && !dsp_devs[dev]->has_output_drained (dev))
+         while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+                && audio_devs[dev]->local_qlen (dev))
            {
-             DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4);
+             DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ);
            }
        }
       RESTORE_INTR (flags);
     }
-  return dev_qlen[dev];
+  return audio_devs[dev]->dmap->qlen;
 }
 
 int
 DMAbuf_release (int dev, int mode)
 {
+  unsigned long   flags;
 
-  if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
-       dmabuf_interrupted[dev])
-      && (dma_mode[dev] == DMODE_OUTPUT))
+  if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+      && (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT))
     {
       dma_sync (dev);
     }
@@ -305,12 +282,14 @@ DMAbuf_release (int dev, int mode)
   sound_dma_free (dev);
 #endif
 
-  dsp_devs[dev]->reset (dev);
+  DISABLE_INTR (flags);
+  audio_devs[dev]->reset (dev);
 
-  dsp_devs[dev]->close (dev);
+  audio_devs[dev]->close (dev);
 
-  dma_mode[dev] = DMODE_NONE;
-  dev_busy[dev] = 0;
+  audio_devs[dev]->dmap->dma_mode = DMODE_NONE;
+  audio_devs[dev]->dmap->flags &= ~DMA_BUSY;
+  RESTORE_INTR (flags);
 
   return 0;
 }
@@ -320,50 +299,51 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len)
 {
   unsigned long   flags;
   int             err = EIO;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
   DISABLE_INTR (flags);
-  if (!dev_qlen[dev])
+  if (!dmap->qlen)
     {
-      if (dev_needs_restart[dev])
+      if (dmap->flags & DMA_RESTART)
        {
          dma_reset (dev);
-         dev_needs_restart[dev] = 0;
+         dmap->flags &= ~DMA_RESTART;
        }
 
-      if (dma_mode[dev] == DMODE_OUTPUT)       /* Was output -> direction change */
+      if (dmap->dma_mode == DMODE_OUTPUT)      /* Direction change */
        {
          dma_sync (dev);
          dma_reset (dev);
-         dma_mode[dev] = DMODE_NONE;
+         dmap->dma_mode = DMODE_NONE;
        }
 
-      if (!bufferalloc_done[dev])
+      if (!(dmap->flags & DMA_ALLOC_DONE))
        reorganize_buffers (dev);
 
-      if (!dma_mode[dev])
+      if (dmap->dma_mode)
        {
          int             err;
 
-         if ((err = dsp_devs[dev]->prepare_for_input (dev,
-                                   dev_buffsize[dev], dev_nbufs[dev])) < 0)
+         if ((err = audio_devs[dev]->prepare_for_input (dev,
+                                    dmap->fragment_size, dmap->nbufs)) < 0)
            {
              RESTORE_INTR (flags);
              return err;
            }
-         dma_mode[dev] = DMODE_INPUT;
+         dmap->dma_mode = DMODE_INPUT;
        }
 
-      if (!dev_active[dev])
+      if (!(dmap->flags & DMA_ACTIVE))
        {
-         dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
-                                     dev_buffsize[dev], 0,
-                                     !sound_dma_automode[dev] ||
-                                     !dev_started[dev]);
-         dev_active[dev] = 1;
-         dev_started[dev] = 1;
+         audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
+                                       dmap->fragment_size, 0,
+                                !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+                                       !(dmap->flags & DMA_STARTED));
+         dmap->flags |= DMA_ACTIVE | DMA_STARTED;
        }
 
       /* Wait for the next block */
+
       DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
       if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
        {
@@ -376,60 +356,42 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len)
     }
   RESTORE_INTR (flags);
 
-  if (!dev_qlen[dev])
+  if (!dmap->qlen)
     return RET_ERROR (err);
 
-  *buf = &dev_buf[dev][dev_qhead[dev]][dev_counts[dev][dev_qhead[dev]]];
-  *len = dev_buffsize[dev] - dev_counts[dev][dev_qhead[dev]];
+  *buf = &dmap->buf[dmap->qhead][dmap->counts[dmap->qhead]];
+  *len = dmap->fragment_size - dmap->counts[dmap->qhead];
 
-  return dev_qhead[dev];
+  return dmap->qhead;
 }
 
 int
 DMAbuf_rmchars (int dev, int buff_no, int c)
 {
-  int             p = dev_counts[dev][dev_qhead[dev]] + c;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+
+  int             p = dmap->counts[dmap->qhead] + c;
 
-  if (p >= dev_buffsize[dev])
-    {                          /* This buffer is now empty */
-      dev_counts[dev][dev_qhead[dev]] = 0;
-      dev_qlen[dev]--;
-      dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
+  if (p >= dmap->fragment_size)
+    {                          /* This buffer is completely empty */
+      dmap->counts[dmap->qhead] = 0;
+      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+       printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
+               dev, dmap->qlen, dmap->nbufs);
+      dmap->qlen--;
+      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
     }
   else
-    dev_counts[dev][dev_qhead[dev]] = p;
+    dmap->counts[dmap->qhead] = p;
 
   return 0;
 }
 
-int
-DMAbuf_read (int dev, snd_rw_buf * user_buf, int count)
-{
-  char           *dmabuf;
-  int             buff_no, c, err;
-
-  /*
-   * This routine returns at most 'count' bytes from the dsp input buffers.
-   * Returns negative value if there is an error.
-   */
-
-  if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &c)) < 0)
-    return buff_no;
-
-  if (c > count)
-    c = count;
-
-  COPY_TO_USER (user_buf, 0, dmabuf, c);
-
-  if ((err = DMAbuf_rmchars (dev, buff_no, c)) < 0)
-    return err;
-  return c;
-
-}
-
 int
 DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
 {
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+
   switch (cmd)
     {
     case SNDCTL_DSP_RESET:
@@ -444,10 +406,10 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
       break;
 
     case SNDCTL_DSP_GETBLKSIZE:
-      if (!bufferalloc_done[dev])
+      if (!(dmap->flags & DMA_ALLOC_DONE))
        reorganize_buffers (dev);
 
-      return IOCTL_OUT (arg, dev_buffsize[dev]);
+      return IOCTL_OUT (arg, dmap->fragment_size);
       break;
 
     case SNDCTL_DSP_SUBDIVIDE:
@@ -456,13 +418,14 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
 
        if (fact == 0)
          {
-           fact = dev_subdivision[dev];
+           fact = dmap->subdivision;
            if (fact == 0)
              fact = 1;
            return IOCTL_OUT (arg, fact);
          }
 
-       if (dev_subdivision[dev] != 0)  /* Too late to change */
+       if (dmap->subdivision != 0 ||
+           dmap->fragment_size)/* Loo late to change */
          return RET_ERROR (EINVAL);
 
        if (fact > MAX_REALTIME_FACTOR)
@@ -471,110 +434,192 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
        if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
          return RET_ERROR (EINVAL);
 
-       dev_subdivision[dev] = fact;
+       dmap->subdivision = fact;
        return IOCTL_OUT (arg, fact);
       }
       break;
 
+    case SNDCTL_DSP_SETFRAGMENT:
+      {
+       int             fact = IOCTL_IN (arg);
+       int             bytes, count;
+
+       if (fact == 0)
+         return RET_ERROR (EIO);
+
+       if (dmap->subdivision != 0 ||
+           dmap->fragment_size)/* Loo late to change */
+         return RET_ERROR (EINVAL);
+
+       bytes = fact & 0xffff;
+       count = (fact >> 16) & 0xffff;
+
+       if (count == 0)
+         count = MAX_SUB_BUFFERS;
+
+       if (bytes < 7 || bytes > 17)    /* <64 || > 128k */
+         return RET_ERROR (EINVAL);
+
+       if (count < 2)
+         return RET_ERROR (EINVAL);
+
+       dmap->fragment_size = (1 << bytes);
+       dmap->max_fragments = count;
+
+       if (dmap->fragment_size > audio_devs[dev]->buffsize)
+         dmap->fragment_size = audio_devs[dev]->buffsize;
+
+       if (dmap->fragment_size == audio_devs[dev]->buffsize &&
+           audio_devs[dev]->flags & DMA_AUTOMODE)
+         dmap->fragment_size /= 2;     /* Needs at least 2 buffers */
+
+       dmap->subdivision = 1;  /* Disable SNDCTL_DSP_SUBDIVIDE */
+       return IOCTL_OUT (arg, bytes | (count << 16));
+      }
+      break;
+
     default:
-      return dsp_devs[dev]->ioctl (dev, cmd, arg, local);
+      return audio_devs[dev]->ioctl (dev, cmd, arg, local);
     }
 
-  /* NOTREACHED */
   return RET_ERROR (EIO);
 }
 
+static int
+space_in_queue (int dev)
+{
+  int             len, max, tmp;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+
+  if (dmap->qlen == dmap->nbufs)/* No space at all */
+    return 0;
+
+  /*
+  * Verify that there are no more pending buffers than the limit
+  * defined by the process.
+  */
+
+  max = dmap->max_fragments;
+  len = dmap->qlen;
+
+  if (audio_devs[dev]->local_qlen)
+    {
+      tmp = audio_devs[dev]->local_qlen (dev);
+      if (tmp & len)
+       tmp--;                  /*
+                        * This buffer has been counted twice
+                        */
+      len += tmp;
+    }
+
+  if (len >= max)
+    return 0;
+  return 1;
+}
+
 int
 DMAbuf_getwrbuffer (int dev, char **buf, int *size)
 {
   unsigned long   flags;
-  int             err = EIO;
+  int             abort, err = EIO;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  if (dma_mode[dev] == DMODE_INPUT)    /* Was input -> Direction change */
+  if (dmap->dma_mode == DMODE_INPUT)   /* Direction change */
     {
       dma_reset (dev);
-      dma_mode[dev] = DMODE_NONE;
+      dmap->dma_mode = DMODE_NONE;
     }
-  else if (dev_needs_restart[dev])     /* Restart buffering */
+  else if (dmap->flags & DMA_RESTART)  /* Restart buffering */
     {
       dma_sync (dev);
       dma_reset (dev);
     }
 
-  dev_needs_restart[dev] = 0;
+  dmap->flags &= ~DMA_RESTART;
 
-  if (!bufferalloc_done[dev])
+  if (!(dmap->flags & DMA_ALLOC_DONE))
     reorganize_buffers (dev);
 
-  if (!dma_mode[dev])
+  if (!dmap->dma_mode)
     {
       int             err;
 
-      dma_mode[dev] = DMODE_OUTPUT;
-      if ((err = dsp_devs[dev]->prepare_for_output (dev,
-                                   dev_buffsize[dev], dev_nbufs[dev])) < 0)
+      dmap->dma_mode = DMODE_OUTPUT;
+      if ((err = audio_devs[dev]->prepare_for_output (dev,
+                                    dmap->fragment_size, dmap->nbufs)) < 0)
        return err;
     }
 
 
   DISABLE_INTR (flags);
 
-  RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
-
-  if (dev_qlen[dev] == dev_nbufs[dev])
+  abort = 0;
+  while (!space_in_queue (dev) &&
+        !abort)
     {
-      if (!dev_active[dev])
-       {
-         printk ("Soundcard warning: DMA not activated %d/%d\n",
-                 dev_qlen[dev], dev_nbufs[dev]);
-         return RET_ERROR (EIO);
-       }
-
-      /* Wait for free space */
+      /*
+       * Wait for free space
+       */
       DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
       if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
        {
          printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
          err = EIO;
+         abort = 1;
          SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
        }
       else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
-       err = EINTR;
+       {
+         err = EINTR;
+         abort = 1;
+       }
     }
   RESTORE_INTR (flags);
 
-  if (dev_qlen[dev] == dev_nbufs[dev])
-    return RET_ERROR (err);    /* We have got signal (?) */
+  if (!space_in_queue (dev))
+    {
+      return RET_ERROR (err);  /* Caught a signal ? */
+    }
 
-  *buf = dev_buf[dev][dev_qtail[dev]];
-  *size = dev_buffsize[dev];
-  dev_counts[dev][dev_qtail[dev]] = 0;
+  *buf = dmap->buf[dmap->qtail];
+  *size = dmap->fragment_size;
+  dmap->counts[dmap->qtail] = 0;
 
-  return dev_qtail[dev];
+  return dmap->qtail;
 }
 
 int
 DMAbuf_start_output (int dev, int buff_no, int l)
 {
-  if (buff_no != dev_qtail[dev])
-    printk ("Soundcard warning: DMA buffers out of sync %d != %d\n", buff_no, dev_qtail[dev]);
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+
+  if (buff_no != dmap->qtail)
+    printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
 
-  dev_qlen[dev]++;
+  dmap->qlen++;
+  if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+    printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
+           dev, dmap->qlen, dmap->nbufs);
 
-  dev_counts[dev][dev_qtail[dev]] = l;
+  dmap->counts[dmap->qtail] = l;
 
-  dev_needs_restart[dev] = (l != dev_buffsize[dev]) &&
-    (sound_dma_automode[dev] || dsp_devs[dev]->flags & NEEDS_RESTART);
+  if ((l != dmap->fragment_size) &&
+      ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
+       audio_devs[dev]->flags & NEEDS_RESTART))
+    dmap->flags |= DMA_RESTART;
+  else
+    dmap->flags &= ~DMA_RESTART;
 
-  dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
+  dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
 
-  if (!dev_active[dev])
+  if (!(dmap->flags & DMA_ACTIVE))
     {
-      dev_active[dev] = 1;
-      dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
-                                  dev_counts[dev][dev_qhead[dev]], 0,
-                            !sound_dma_automode[dev] || !dev_started[dev]);
-      dev_started[dev] = 1;
+      dmap->flags |= DMA_ACTIVE;
+      audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
+                                    dmap->counts[dmap->qhead], 0,
+                                !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+                                    !(dmap->flags & DMA_STARTED));
+      dmap->flags |= DMA_STARTED;
     }
 
   return 0;
@@ -583,7 +628,8 @@ DMAbuf_start_output (int dev, int buff_no, int l)
 int
 DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
 {
-  int             chan = sound_dsp_dmachan[dev];
+  int             chan = audio_devs[dev]->dmachan;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
   unsigned long   flags;
 
   /*
@@ -595,45 +641,47 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
    * set_dma_addr()
    */
 
-  if (sound_dma_automode[dev])
-    {                          /* Auto restart mode. Transfer the whole
-                                * buffer */
+  if (audio_devs[dev]->flags & DMA_AUTOMODE)
+    {                          /*
+                                * Auto restart mode. Transfer the whole *
+                                * buffer
+                                */
 #ifdef linux
       DISABLE_INTR (flags);
       disable_dma (chan);
       clear_dma_ff (chan);
       set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
-      set_dma_addr (chan, snd_raw_buf_phys[dev][0]);
-      set_dma_count (chan, sound_buffsizes[dev]);
+      set_dma_addr (chan, dmap->raw_buf_phys[0]);
+      set_dma_count (chan, dmap->bytes_in_use);
       enable_dma (chan);
       RESTORE_INTR (flags);
-#else /* linux */
+#else
 
 #ifdef __386BSD__
       printk ("sound: Invalid DMA mode for device %d\n", dev);
 
       isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
-                   snd_raw_buf_phys[dev][0],
-                   sound_buffsizes[dev],
+                   dmap->raw_buf_phys[0],
+                   dmap->bytes_in_use,
                    chan);
-#else /* __386BSD__ */
-#if defined(ISC) || defined(SCO) || defined(SVR42)
+#else
+#if defined(GENERIC_SYSV)
 #ifndef DMAMODE_AUTO
       printk ("sound: Invalid DMA mode for device %d\n", dev);
-#endif /* DMAMODE_AUTO */
+#endif
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
 #ifdef DMAMODE_AUTO
                 | DMAMODE_AUTO
-#endif /* DMAMODE_AUTO */
+#endif
                 ,
-                snd_raw_buf_phys[dev][0], count);
+                dmap->raw_buf_phys[0], dmap->bytes_in_use);
       dma_enable (chan);
-#else /* SYSV */
+#else
 #error This routine is not valid for this OS.
-#endif /* SYSV */
-#endif /* __386BSD__ */
+#endif
+#endif
 
-#endif /* linux */
+#endif
     }
   else
     {
@@ -646,24 +694,24 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
       set_dma_count (chan, count);
       enable_dma (chan);
       RESTORE_INTR (flags);
-#else /* linux */
+#else
 #ifdef __386BSD__
       isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
                    physaddr,
                    count,
                    chan);
-#else /* __386BSD__ */
+#else
 
-#if defined(ISC) || defined(SCO) || defined(SVR42)
+#if defined(GENERIC_SYSV)
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
                 physaddr, count);
       dma_enable (chan);
-#else /* SYSV */
+#else
 #error This routine is not valid for this OS.
-#endif /* SYSV */
-#endif /* __386BSD__ */
+#endif /* GENERIC_SYSV */
+#endif
 
-#endif /* linux */
+#endif
     }
 
   return count;
@@ -672,49 +720,64 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
 long
 DMAbuf_init (long mem_start)
 {
-  int             i;
+  int             dev;
 
   /*
-   * In this version the DMA buffer allocation is done by sound_mem_init()
-   * which is called by init/main.c
-   */
-
-  for (i = 0; i < MAX_DSP_DEV; i++)
-    {
-      dev_qlen[i] = 0;
-      dev_qhead[i] = 0;
-      dev_qtail[i] = 0;
-      dev_active[i] = 0;
-      dev_busy[i] = 0;
-      bufferalloc_done[i] = 0;
-    }
+ * NOTE! This routine could be called several times.
+ */
 
+  for (dev = 0; dev < num_audiodevs; dev++)
+    audio_devs[dev]->dmap = &dmaps[dev];
   return mem_start;
 }
 
 void
-DMAbuf_outputintr (int dev, int underrun_flag)
+DMAbuf_outputintr (int dev, int event_type)
 {
-  unsigned long   flags;
+  /*
+ * Event types:
+ *     0 = DMA transfer done. Device still has more data in the local
+ *         buffer.
+ *     1 = DMA transfer done. Device doesn't have local buffer or it's
+ *         empty now.
+ *     2 = No DMA transfer but the device has now more space in it's local
+ *         buffer.
+ */
 
-  dev_qlen[dev]--;
-  dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
-  dev_active[dev] = 0;
+  unsigned long   flags;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  if (dev_qlen[dev])
+  if (event_type != 2)
     {
-      dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
-                                  dev_counts[dev][dev_qhead[dev]], 1,
-                                  !sound_dma_automode[dev]);
-      dev_active[dev] = 1;
-    }
-  else if (underrun_flag)
-    {
-      dev_underrun[dev]++;
-      dsp_devs[dev]->halt_xfer (dev);
-      dev_needs_restart[dev] = (sound_dma_automode[dev] ||
-                               dsp_devs[dev]->flags & NEEDS_RESTART);
-    }
+      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+       {
+         printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
+                 dev, dmap->qlen, dmap->nbufs);
+         return;
+       }
+
+      dmap->qlen--;
+      dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+      dmap->flags &= ~DMA_ACTIVE;
+
+      if (dmap->qlen)
+       {
+         audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
+                                        dmap->counts[dmap->qhead], 1,
+                                 !(audio_devs[dev]->flags & DMA_AUTOMODE));
+         dmap->flags |= DMA_ACTIVE;
+       }
+      else if (event_type == 1)
+       {
+         dmap->underrun_count++;
+         audio_devs[dev]->halt_xfer (dev);
+         if ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
+             audio_devs[dev]->flags & NEEDS_RESTART)
+           dmap->flags |= DMA_RESTART;
+         else
+           dmap->flags &= ~DMA_RESTART;
+       }
+    }                          /* event_type != 2 */
 
   DISABLE_INTR (flags);
   if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
@@ -728,28 +791,31 @@ void
 DMAbuf_inputintr (int dev)
 {
   unsigned long   flags;
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  if (!dev_busy[dev])
-    {
-      dsp_devs[dev]->close (dev);
-    }
-  else if (dev_qlen[dev] == (dev_nbufs[dev] - 1))
+  if (dmap->qlen == (dmap->nbufs - 1))
     {
       printk ("Sound: Recording overrun\n");
-      dev_underrun[dev]++;
-      dsp_devs[dev]->halt_xfer (dev);
-      dev_active[dev] = 0;
-      dev_needs_restart[dev] = sound_dma_automode[dev];
+      dmap->underrun_count++;
+      audio_devs[dev]->halt_xfer (dev);
+      dmap->flags &= ~DMA_ACTIVE;
+      if (audio_devs[dev]->flags & DMA_AUTOMODE)
+       dmap->flags |= DMA_RESTART;
+      else
+       dmap->flags &= ~DMA_RESTART;
     }
   else
     {
-      dev_qlen[dev]++;
-      dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
-
-      dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
-                                 dev_buffsize[dev], 1,
-                                 !sound_dma_automode[dev]);
-      dev_active[dev] = 1;
+      dmap->qlen++;
+      if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+       printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
+               dev, dmap->qlen, dmap->nbufs);
+      dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+
+      audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
+                                   dmap->fragment_size, 1,
+                                 !(audio_devs[dev]->flags & DMA_AUTOMODE));
+      dmap->flags |= DMA_ACTIVE;
     }
 
   DISABLE_INTR (flags);
@@ -764,12 +830,12 @@ int
 DMAbuf_open_dma (int dev)
 {
   unsigned long   flags;
-  int             chan = sound_dsp_dmachan[dev];
+  int             chan = audio_devs[dev]->dmachan;
 
   if (ALLOC_DMA_CHN (chan))
     {
       printk ("Unable to grab DMA%d for the audio driver\n", chan);
-      return 0;
+      return RET_ERROR (EBUSY);
     }
 
   DISABLE_INTR (flags);
@@ -779,13 +845,13 @@ DMAbuf_open_dma (int dev)
 #endif
   RESTORE_INTR (flags);
 
-  return 1;
+  return 0;
 }
 
 void
 DMAbuf_close_dma (int dev)
 {
-  int             chan = sound_dsp_dmachan[dev];
+  int             chan = audio_devs[dev]->dmachan;
 
   DMAbuf_reset_dma (chan);
   RELEASE_DMA_CHN (chan);
@@ -805,7 +871,9 @@ DMAbuf_reset_dma (int chan)
  */
 
 #else
-/* Stub versions if audio services not included  */
+/*
+ * Stub versions if audio services not included
+ */
 
 int
 DMAbuf_open (int dev, int mode)
@@ -819,12 +887,6 @@ DMAbuf_release (int dev, int mode)
   return 0;
 }
 
-int
-DMAbuf_read (int dev, snd_rw_buf * user_buf, int count)
-{
-  return RET_ERROR (EIO);
-}
-
 int
 DMAbuf_getwrbuffer (int dev, char **buf, int *size)
 {
diff --git a/drivers/sound/experimental.txt b/drivers/sound/experimental.txt
new file mode 100644 (file)
index 0000000..0046230
--- /dev/null
@@ -0,0 +1,160 @@
+This version contains some features which is are NOT enabled by default. 
+I'm trying to release an official/reliable version soon so that the
+Linux version of Doom (and other games) becomes possible. For that reason
+I have disabled some features which are not reliable enough to be
+released for wide public. If you are interested to try them, please
+read this file carefully.
+
+There are currently following goodies which I have disabled:
+
+1) ECHO PSS (Personal Sound System support)
+
+This version contains support for soundcards based on the AD20msp614
+chipset made by Analog Devices. This chipset consist of the
+AD1848 codec, ADSP-21xx DSP chip and a ESC614 ASIC and is used in some
+soundcards made by Orchid, Cardinal, Echo Speech Corporation, Western
+Digital and Wearnes Technology. The PSS support is by Marc M. Hoffman
+(marc.hoffman@analog.com). I received this stuff about a week ago and
+have not been able to test it yet.
+If you are interested, remove the B(OPT_PSS) from the DISABLED_OPTIONS
+(see above).
+You have also to enable the MSS support since I have not integrated
+the AD1848 driver with the PSS one yet.
+
+2) WSS/MSS (Microsoft Sound System) support
+
+The MSS standard is based on the AD1848 codec by Analog Devices.
+Since I don't know how the software configuration of the MSS works
+so it's not supported yet. This driver should work if your card
+has jumpers for the I/O base, IRQ and DMA or there is a way to configure
+them using DOS. You could try this if you have a soundcard with
+AD1848 codec. I have tried to use this with Aztech SG NX Pro 16 without
+success. 
+If you are interested, remove the B(OPT_MSS) from the DISABLED_OPTIONS
+(see above).
+
+3) /dev/sequencer2
+
+This version has a new device file called /dev/sequence2. I have not
+implemented all parts of it but it's there. It's only interesting if
+you are writing a sequencer program yourself. Enable by creating
+the device file /dev/sequencer (minor 8).
+
+4) /dev/midi##
+
+These are tty like raw devices for MIDI ports. Since there is a minor
+incompatibility between different versions of Linux, I have disabled
+this feature by default. You just need to create the device files yourself.
+IMPORTANT!     If you get warning at line 64 of midibuf.c,
+               don't try to use /dev/midi## files. Otherwise your
+               system halts. You may also try to fix the
+               DEFINE_TIMER() macro in os.h (just remove the 2nd NULL).
+               This could happen with some earlier versions of Linux
+               (before 1.1.0???).
+
+5) Support for hardware based u-Law/A-Law and ADPCM formats.
+
+The AD1848 (and compatibles) are able to do compression and
+decompression by hardware. This version has experimental support
+for some of them. Currently they are implemented just in the
+AD1848 driver. The GUS MAX (and the 16 bit daughtercard) support
+also 16->4 bit ADPCM (the IMA one) but it don't work yet.
+The argument ioctl(SNDCTL_DSP_SAMPLESIZE) can have some new values
+in addition to the 8 and 16 supported earlier. Look at soundcard.h
+for more info.
+(In case somebody dares to ask: The ASP chip of SB16 is not supported
+so the hardware compression/decompression doesn't work with it. Also
+the ADPCM format is different than the standard (IMA) one (I guess).
+This feature is enabled by default.
+
+5) Real time fix to /dev/dsp and /dev/audio drivers
+
+The following feature should help game writers. This stuff is enabled
+by default.
+---------------- cut here ---------------------
+There is a new ioctl called SNDCTL_DSP_SETFRAGMENT. It accepts a
+int parameter which has format 0x00nn00ss where the nn is max number of 
+buffer fragments (between 0x02 and 0xff) and the ss gives indirectly the 
+size of a buffer fragment (fragment_size = (1 << ss)). Valid sizes are 
+between (ss=0x07 -> 128 bytes and ss=0x11 (17 dec) -> 128k).
+
+This ioctl must be used ONCE between open() and first call to 
+read()/write() or ioctl(SNDCTL_DSP_GETBLKSIZE). 
+
+You need just to force the fragment size to a value which is sufficiently 
+short (gives the 1/20th of sec with the speed/#channels/#bits you are using).
+
+Using a small number of fragments offers (I guess) a significant advantage.
+For example with 2 fragments the driver works as the following (at least 
+I hope so). Assuming that the process writes exactly 'fragment_size' of 
+bytes each time (this is really important).
+
+       1) When the process writes the first fragment, it will be copied to
+       the DMA buffer area and the playback begins. The write() returns
+       immediately and the process is free to continue.
+
+
+       2a) If the fragment gets played before the application writes a new
+       one, the device will be stoppen and restarted which causes a click.
+       When the process calls write next time, it will be processes as 
+       in step 1.
+
+       2b) If the process calls write before the buffer underflows, the
+       data will be queued and the process is free to continue. (There
+       is now one full and one partially played fragment in the kernel
+       buffers. This gives average delay of 1.5*fragment_time (for 
+       example 1/20th sec) before the last byte in the buffer gets played.
+
+
+       3a) If the device gets both fragments played before the next write
+       (underflow), there will be a click. The write will be processed as
+       in step 1.
+
+       3b) If the 1st fragment gets played before next write (the process
+       calls write during playback of the second fragment), it will be
+       processed as step 2b.
+
+       3c) If the process writes 3rd fragment when there is already 2
+       fragments in the queue (1 playing and 1 waiting), the process
+       will block until the 1st fragment gets played. It will then be
+       woken up and it continues as in step 2b. This means that
+       the process blocks for at most the time required to play a
+       buffer fragment.
+
+This method syncronizes the process and the audio device together 
+automaticly. The process will block at most the 'fragment_time'. Usually 
+less, depending on how much it needs time to do other things. The maximum
+delay between writing a byte and the time when it finally plays is
+at most 3 times the 'fragment_time'. 
+
+The delay depends on how much time the program needs to do it's 
+computations for the next sample (updating screen etc). If it's about
+80% of the 'fragment_time' the game will run almost without delays. If it 
+uses more time, there is a risk that the audio buffer gets empty.
+       
+The application code should be something like the following:
+
+int frag = 0x00020008; /* 2 fragments of 2^8=256 bytes */
+int frag_size;
+
+int fd=open("/dev/dsp");
+ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+ioctl(NDCTL_DSP_SPEED); /* And #channels & #bits if required */
+
+/*
+ * Query the actual fragment sice since the driver may refuse
+ * the requested one (unlikely but possible?)
+ */
+
+ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size);
+
+while(True)
+{
+       do_computations();
+       write(fd, buf, frag_size);      /* Always the same size!!!!!!! */
+}
+
+I have tested this with a modified version of str.c. The algorithm works 
+as long as the playing program gets enough time to run. Hitting ENTER on 
+another virtual console causes a pause/click (with 2 frags of 64 bytes).
+------------------- cut here ---------------------
index c7cfc0a7ab6c8aa63b351d7bb0db216b028514a9..614532c7d1145ca0d5a57748ecfbe25e0a0c413b 100644 (file)
@@ -36,6 +36,9 @@
 void            gusintr (int);
 
 int             gus_base, gus_irq, gus_dma;
+extern int      gus_wave_volume;
+extern int      gus_pcm_volume;
+extern int      have_gus_max;
 
 long
 attach_gus_card (long mem_start, struct address_info *hw_config)
@@ -44,11 +47,16 @@ attach_gus_card (long mem_start, struct address_info *hw_config)
 
   snd_set_irq_handler (hw_config->irq, gusintr);
 
-  if (gus_wave_detect (hw_config->io_base))    /* Try first the default */
+  if (gus_wave_detect (hw_config->io_base))    /*
+                                                * Try first the default
+                                                */
     {
       mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
 #ifndef EXCLUDE_MIDI
       mem_start = gus_midi_init (mem_start);
+#endif
+#ifndef EXCLUDE_SEQUENCER
+      sound_timer_init (hw_config->io_base + 8);
 #endif
       return mem_start;
     }
@@ -60,20 +68,27 @@ attach_gus_card (long mem_start, struct address_info *hw_config)
    */
 
   for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
-    if (io_addr != hw_config->io_base) /* Already tested */
+    if (io_addr != hw_config->io_base) /*
+                                        * Already tested
+                                        */
       if (gus_wave_detect (io_addr))
        {
          printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
          mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
 #ifndef EXCLUDE_MIDI
          mem_start = gus_midi_init (mem_start);
+#endif
+#ifndef EXCLUDE_SEQUENCER
+         sound_timer_init (io_addr + 8);
 #endif
          return mem_start;
        }
 
 #endif
 
-  return mem_start;            /* Not detected */
+  return mem_start;            /*
+                                * Not detected
+                                */
 }
 
 int
@@ -91,7 +106,9 @@ probe_gus (struct address_info *hw_config)
    */
 
   for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
-    if (io_addr != hw_config->io_base) /* Already tested */
+    if (io_addr != hw_config->io_base) /*
+                                        * Already tested
+                                        */
       if (gus_wave_detect (io_addr))
        return 1;
 
@@ -101,7 +118,7 @@ probe_gus (struct address_info *hw_config)
 }
 
 void
-gusintr (int unit)
+gusintr (int irq)
 {
   unsigned char   src;
 
@@ -109,6 +126,11 @@ gusintr (int unit)
   sti ();
 #endif
 
+#ifndef EXCLUDE_GUSMAX
+  if (have_gus_max)
+    ad1848_interrupt (irq);
+#endif
+
   while (1)
     {
       if (!(src = INB (u_IrqStatus)))
@@ -128,8 +150,11 @@ gusintr (int unit)
 
       if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
        {
-         printk ("T");
-         gus_write8 (0x45, 0); /* Timer control */
+#ifndef EXCLUDE_SEQUENCER
+         sound_timer_interrupt ();
+#else
+         gus_write8 (0x45, 0); /* Stop timers */
+#endif
        }
 
       if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
@@ -140,3 +165,29 @@ gusintr (int unit)
 }
 
 #endif
+
+/*
+ * Some extra code for the 16 bit sampling option
+ */
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16)
+
+int
+probe_gus_db16 (struct address_info *hw_config)
+{
+  return ad1848_detect (hw_config->io_base);
+}
+
+long
+attach_gus_db16 (long mem_start, struct address_info *hw_config)
+{
+  gus_pcm_volume = 100;
+  gus_wave_volume = 90;
+
+  ad1848_init ("GUS 16 bit sampling", hw_config->io_base,
+              hw_config->irq,
+              hw_config->dma,
+              hw_config->dma);
+  return mem_start;
+}
+
+#endif
index 935c5c90b3248f2cad6a1a0013d0225a8ad5f559..87aea6251daff99f56597a5d8898807444773c6c 100644 (file)
@@ -79,7 +79,9 @@ gus_midi_open (int dev, int mode,
       gus_midi_control |= MIDI_ENABLE_XMIT;
     }
 
-  OUTB (gus_midi_control, u_MidiControl);      /* Enable */
+  OUTB (gus_midi_control, u_MidiControl);      /*
+                                                * Enable
+                                                */
 
   midi_busy = 1;
   qlen = qhead = qtail = output_used = 0;
@@ -105,7 +107,9 @@ dump_to_midi (unsigned char midi_byte)
     }
   else
     {
-      /* Enable Midi xmit interrupts (again) */
+      /*
+       * Enable Midi xmit interrupts (again)
+       */
       gus_midi_control |= MIDI_ENABLE_XMIT;
       OUTB (gus_midi_control, u_MidiControl);
     }
@@ -117,7 +121,9 @@ dump_to_midi (unsigned char midi_byte)
 static void
 gus_midi_close (int dev)
 {
-  /* Reset FIFO pointers, disable intrs */
+  /*
+   * Reset FIFO pointers, disable intrs
+   */
 
   OUTB (MIDI_RESET, u_MidiControl);
   midi_busy = 0;
@@ -149,14 +155,18 @@ gus_midi_out (int dev, unsigned char midi_byte)
 
   if (!qlen)
     if (dump_to_midi (midi_byte))
-      return 1;                        /* OK */
+      return 1;                        /*
+                                * OK
+                                */
 
   /*
    * Put to the local queue
    */
 
   if (qlen >= 256)
-    return 0;                  /* Local queue full */
+    return 0;                  /*
+                                * Local queue full
+                                */
 
   DISABLE_INTR (flags);
 
@@ -213,9 +223,14 @@ gus_midi_buffer_status (int dev)
   return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY);
 }
 
+#define MIDI_SYNTH_NAME        "Gravis Ultrasound Midi"
+#define MIDI_SYNTH_CAPS        SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
 static struct midi_operations gus_midi_operations =
 {
-  {"Gravis UltraSound", 0, 0, SNDCARD_GUS},
+  {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
+  &std_midi_synth,
   gus_midi_open,
   gus_midi_close,
   gus_midi_ioctl,
@@ -223,16 +238,25 @@ static struct midi_operations gus_midi_operations =
   gus_midi_start_read,
   gus_midi_end_read,
   gus_midi_kick,
-  NULL,                                /* command */
-  gus_midi_buffer_status
+  NULL,                                /*
+                                * command
+                                */
+  gus_midi_buffer_status,
+  NULL
 };
 
 long
 gus_midi_init (long mem_start)
 {
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return mem_start;
+    }
+
   OUTB (MIDI_RESET, u_MidiControl);
 
-  my_dev = num_midis;
+  std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &gus_midi_operations;
   return mem_start;
 }
@@ -264,7 +288,9 @@ gus_midi_interrupt (int dummy)
 
       if (!qlen)
        {
-         /* Disable Midi output interrupts, since no data in the buffer */
+         /*
+          * Disable Midi output interrupts, since no data in the buffer
+          */
          gus_midi_control &= ~MIDI_ENABLE_XMIT;
          OUTB (gus_midi_control, u_MidiControl);
        }
index 924cd9375a6ee9fbdd0f67aef4a8f2a083a437dd..1066bd7c4efd1924d9e2a536679887dda800bf25 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Driver for the Gravis UltraSound wave table synth.
  *
- * Copyright by Hannu Savolainen 1993
+ * Copyright by Hannu Savolainen 1993, 1994
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -72,23 +72,23 @@ struct voice_info
 
   };
 
+static struct voice_alloc_info *voice_alloc;
+
 extern int      gus_base;
 extern int      gus_irq, gus_dma;
-extern char    *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
-extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
-extern int      snd_raw_count[MAX_DSP_DEV];
 static long     gus_mem_size = 0;
 static long     free_mem_ptr = 0;
 static int      gus_busy = 0;
 static int      nr_voices = 0;
 static int      gus_devnum = 0;
 static int      volume_base, volume_scale, volume_method;
-static int      gus_line_vol = 100, gus_mic_vol = 0;
 static int      gus_recmask = SOUND_MASK_MIC;
 static int      recording_active = 0;
 
 int             gus_wave_volume = 60;
 int             gus_pcm_volume = 80;
+int             have_gus_max = 0;
+static int      gus_line_vol = 100, gus_mic_vol = 0;
 static unsigned char mix_image = 0x00;
 
 /*
@@ -97,13 +97,9 @@ static unsigned char mix_image = 0x00;
  */
 static int      active_device = 0;
 
-#define GUS_DEV_WAVE           1       /*
-                                          * * * Wave table synth   */
-#define GUS_DEV_PCM_DONE       2       /*
-                                          * * * PCM device, transfer done   */
-#define GUS_DEV_PCM_CONTINUE   3       /*
-                                          * * * PCM device, transfer the
-                                          * second * * * chn   */
+#define GUS_DEV_WAVE           1       /* Wave table synth */
+#define GUS_DEV_PCM_DONE       2       /* PCM device, transfer done */
+#define GUS_DEV_PCM_CONTINUE   3       /* PCM device, transfer done ch. 1/2 */
 
 static int      gus_sampling_speed;
 static int      gus_sampling_channels;
@@ -114,33 +110,13 @@ 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
-                                                                  *
-                                                                */
-
-static int      pcm_bsize,     /*
-                                * Current blocksize
-                                */
-                pcm_nblk,      /*
-                                * Current # of blocks
-                                */
-                pcm_banksize;  /*
-
-
-                                * *  * * # bytes allocated for channels   */
-static int      pcm_datasize[MAX_PCM_BUFFERS]; /*
+#define MAX_PCM_BUFFERS                (32*MAX_REALTIME_FACTOR)        /* Don't change */
 
-
-                                                * *  * * Actual # of bytes
-                                                * in blk  *  */
-static volatile int pcm_head, pcm_tail, pcm_qlen;      /*
-
-
-                                                        * *  * * DRAM queue
-                                                        *  */
+static int      pcm_bsize, pcm_nblk, pcm_banksize;
+static int      pcm_datasize[MAX_PCM_BUFFERS];
+static volatile int pcm_head, pcm_tail, pcm_qlen;
 static volatile int pcm_active;
+static volatile int dma_active;
 static int      pcm_opened = 0;
 static int      pcm_current_dev;
 static int      pcm_current_block;
@@ -152,63 +128,25 @@ struct voice_info voices[32];
 
 static int      freq_div_table[] =
 {
-  44100,                       /*
-                                * 14
-                                */
-  41160,                       /*
-                                * 15
-                                */
-  38587,                       /*
-                                * 16
-                                */
-  36317,                       /*
-                                * 17
-                                */
-  34300,                       /*
-                                * 18
-                                */
-  32494,                       /*
-                                * 19
-                                */
-  30870,                       /*
-                                * 20
-                                */
-  29400,                       /*
-                                * 21
-                                */
-  28063,                       /*
-                                * 22
-                                */
-  26843,                       /*
-                                * 23
-                                */
-  25725,                       /*
-                                * 24
-                                */
-  24696,                       /*
-                                * 25
-                                */
-  23746,                       /*
-                                * 26
-                                */
-  22866,                       /*
-                                * 27
-                                */
-  22050,                       /*
-                                * 28
-                                */
-  21289,                       /*
-                                * 29
-                                */
-  20580,                       /*
-                                * 30
-                                */
-  19916,                       /*
-                                * 31
-                                */
-  19293                                /*
-                                * 32
-                                */
+  44100,                       /* 14 */
+  41160,                       /* 15 */
+  38587,                       /* 16 */
+  36317,                       /* 17 */
+  34300,                       /* 18 */
+  32494,                       /* 19 */
+  30870,                       /* 20 */
+  29400,                       /* 21 */
+  28063,                       /* 22 */
+  26843,                       /* 23 */
+  25725,                       /* 24 */
+  24696,                       /* 25 */
+  23746,                       /* 26 */
+  22866,                       /* 27 */
+  22050,                       /* 28 */
+  21289,                       /* 29 */
+  20580,                       /* 30 */
+  19916,                       /* 31 */
+  19293                                /* 32 */
 };
 
 static struct patch_info *samples;
@@ -231,10 +169,8 @@ static void     compute_volume (int voice, int volume);
 static void     do_volume_irq (int voice);
 static void     set_input_volumes (void);
 
-#define        INSTANT_RAMP            -1      /*
-                                          * * * Dont use ramping   */
-#define FAST_RAMP              0       /*
-                                          * * * Fastest possible ramp   */
+#define        INSTANT_RAMP            -1      /* Instant change. No ramping */
+#define FAST_RAMP              0       /* Fastest possible ramp */
 
 static void
 reset_sample_memory (void)
@@ -248,12 +184,10 @@ reset_sample_memory (void)
   for (i = 0; i < 32; i++)
     patch_map[i] = -1;
 
-  gus_poke (0, 0);             /*
-                                * Put silence here
-                                */
+  gus_poke (0, 0);             /* Put a silent sample to the beginning */
   gus_poke (1, 0);
-
   free_mem_ptr = 2;
+
   free_sample = 0;
 
   for (i = 0; i < MAX_PATCH; i++)
@@ -271,7 +205,7 @@ gus_delay (void)
 
 static void
 gus_poke (long addr, unsigned char data)
-{
+{                              /* Writes a byte to the DRAM */
   unsigned long   flags;
 
   DISABLE_INTR (flags);
@@ -287,7 +221,7 @@ gus_poke (long addr, unsigned char data)
 
 static unsigned char
 gus_peek (long addr)
-{
+{                              /* Reads a byte from the DRAM */
   unsigned long   flags;
   unsigned char   tmp;
 
@@ -306,7 +240,7 @@ gus_peek (long addr)
 
 void
 gus_write8 (int reg, unsigned int data)
-{
+{                              /* Writes to an indirect register (8 bit) */
   unsigned long   flags;
 
   DISABLE_INTR (flags);
@@ -319,7 +253,7 @@ gus_write8 (int reg, unsigned int data)
 
 unsigned char
 gus_read8 (int reg)
-{
+{                              /* Reads from an indirect register (8 bit). Offset 0x80. */
   unsigned long   flags;
   unsigned char   val;
 
@@ -333,7 +267,7 @@ gus_read8 (int reg)
 
 unsigned char
 gus_look8 (int reg)
-{
+{                              /* Reads from an indirect register (8 bit). No additional offset. */
   unsigned long   flags;
   unsigned char   val;
 
@@ -347,7 +281,7 @@ gus_look8 (int reg)
 
 void
 gus_write16 (int reg, unsigned int data)
-{
+{                              /* Writes to an indirect register (16 bit) */
   unsigned long   flags;
 
   DISABLE_INTR (flags);
@@ -362,7 +296,7 @@ gus_write16 (int reg, unsigned int data)
 
 unsigned short
 gus_read16 (int reg)
-{
+{                              /* Reads from an indirect register (16 bit). Offset 0x80. */
   unsigned long   flags;
   unsigned char   hi, lo;
 
@@ -380,9 +314,11 @@ gus_read16 (int reg)
 
 void
 gus_write_addr (int reg, unsigned long address, int is16bit)
-{
+{                              /* Writes an 24 bit memory address */
   unsigned long   hold_address;
+  unsigned long   flags;
 
+  DISABLE_INTR (flags);
   if (is16bit)
     {
       /*
@@ -401,6 +337,7 @@ gus_write_addr (int reg, unsigned long address, int is16bit)
   gus_delay ();
   gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
   gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
+  RESTORE_INTR (flags);
 }
 
 static void
@@ -420,7 +357,7 @@ gus_select_max_voices (int nvoices)
   if (nvoices > 32)
     nvoices = 32;
 
-  nr_voices = nvoices;
+  voice_alloc->max_voice = nr_voices = nvoices;
 
   gus_write8 (0x0e, (nvoices - 1) | 0xc0);
 }
@@ -444,14 +381,8 @@ gus_voice_mode (unsigned int m)
 {
   unsigned char   mode = (unsigned char) (m & 0xff);
 
-  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));        /*
-                                                                        * Don't
-                                                                        * start
-                                                                        * or
-                                                                        * stop
-                                                                        * *
-                                                                        * voice
-                                                                        */
+  gus_write8 (0x00, (gus_read8 (0x00) & 0x03) |
+             (mode & 0xfc));   /* Don't touch last two bits */
   gus_delay ();
   gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
 }
@@ -471,9 +402,7 @@ gus_voice_freq (unsigned long freq)
 static void
 gus_voice_volume (unsigned int vol)
 {
-  gus_write8 (0x0d, 0x03);     /*
-                                * Stop ramp before setting volume
-                                */
+  gus_write8 (0x0d, 0x03);     /* Stop ramp before setting volume */
   gus_write16 (0x09, (unsigned short) (vol << 4));
 }
 
@@ -511,14 +440,8 @@ gus_ramp_mode (unsigned int m)
 {
   unsigned char   mode = (unsigned char) (m & 0xff);
 
-  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));        /*
-                                                                        * Don't
-                                                                        * start
-                                                                        * or
-                                                                        * stop
-                                                                        * *
-                                                                        * ramping
-                                                                        */
+  gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) |
+             (mode & 0xfc));   /* Leave the last 2 bits alone */
   gus_delay ();
   gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
 }
@@ -551,15 +474,10 @@ gus_voice_init (int voice)
   DISABLE_INTR (flags);
   gus_select_voice (voice);
   gus_voice_volume (0);
-  gus_write_addr (0x0a, 0, 0); /*
-                                * Set current position to 0
-                                */
-  gus_write8 (0x00, 0x03);     /*
-                                * Voice off
-                                */
-  gus_write8 (0x0d, 0x03);     /*
-                                * Ramping off
-                                */
+  gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */
+  gus_write8 (0x00, 0x03);     /* Voice off */
+  gus_write8 (0x0d, 0x03);     /* Ramping off */
+  voice_alloc->map[voice] = 0;
   RESTORE_INTR (flags);
 
 }
@@ -599,17 +517,14 @@ step_envelope (int voice)
       gus_select_voice (voice);
       gus_rampoff ();
       RESTORE_INTR (flags);
-      return;                  /*
-                                * Sustain
-                                */
-    }
-
-  if (voices[voice].env_phase >= 5)
-    {
+      return;
       /*
-       * Shoot the voice off
+       * Sustain phase begins. Continue envelope after receiving note off.
        */
+    }
 
+  if (voices[voice].env_phase >= 5)
+    {                          /* Envelope finished. Shoot the voice down */
       gus_voice_init (voice);
       return;
     }
@@ -626,20 +541,14 @@ step_envelope (int voice)
   gus_voice_volume (prev_vol);
 
 
-  gus_write8 (0x06, rate);     /*
-                                * Ramping rate
-                                */
+  gus_write8 (0x06, rate);     /* Ramping rate */
 
   voices[voice].volume_irq_mode = VMODE_ENVELOPE;
 
-  if (((vol - prev_vol) / 64) == 0)    /*
-                                        * No significant volume change
-                                        */
+  if (((vol - prev_vol) / 64) == 0)    /* No significant volume change */
     {
       RESTORE_INTR (flags);
-      step_envelope (voice);   /*
-                                * Continue with the next phase
-                                */
+      step_envelope (voice);   /* Continue the envelope on the next step */
       return;
     }
 
@@ -648,18 +557,14 @@ step_envelope (int voice)
       if (vol >= (4096 - 64))
        vol = 4096 - 65;
       gus_ramp_range (0, vol);
-      gus_rampon (0x20);       /*
-                                * Increasing, irq
-                                */
+      gus_rampon (0x20);       /* Increasing volume, with IRQ */
     }
   else
     {
       if (vol <= 64)
        vol = 65;
       gus_ramp_range (vol, 4030);
-      gus_rampon (0x60);       /*
-                                * Decreasing, irq
-                                */
+      gus_rampon (0x60);       /* Decreasing volume, with IRQ */
     }
   voices[voice].current_volume = vol;
   RESTORE_INTR (flags);
@@ -678,19 +583,13 @@ static void
 start_release (int voice, long int flags)
 {
   if (gus_read8 (0x00) & 0x03)
-    return;                    /*
-                                * Voice already stopped
-                                */
+    return;                    /* Voice already stopped */
 
-  voices[voice].env_phase = 2; /*
-                                * Will be incremented by step_envelope
-                                */
+  voices[voice].env_phase = 2; /* Will be incremented by step_envelope */
 
   voices[voice].current_volume =
     voices[voice].initial_volume =
-    gus_read16 (0x09) >> 4;    /*
-                                * Get current volume
-                                */
+    gus_read16 (0x09) >> 4;    /* Get current volume */
 
   voices[voice].mode &= ~WAVE_SUSTAIN_ON;
   gus_rampoff ();
@@ -709,18 +608,13 @@ gus_voice_fade (int voice)
 
   if (instr_no < 0 || instr_no > MAX_SAMPLE)
     {
-      gus_write8 (0x00, 0x03); /*
-                                * Hard stop
-                                */
+      gus_write8 (0x00, 0x03); /* Hard stop */
+      voice_alloc->map[voice] = 0;
       RESTORE_INTR (flags);
       return;
     }
 
-  is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;  /*
-                                                                * 8 or 16
-                                                                * bit
-                                                                * samples
-                                                                */
+  is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;  /* 8 or 16 bits */
 
   if (voices[voice].mode & WAVE_ENVELOPES)
     {
@@ -731,9 +625,7 @@ gus_voice_fade (int voice)
   /*
    * Ramp the volume down but not too quickly.
    */
-  if ((gus_read16 (0x09) >> 4) < 100)  /*
-                                        * Get current volume
-                                        */
+  if ((int) (gus_read16 (0x09) >> 4) < 100)    /* Get current volume */
     {
       gus_voice_off ();
       gus_rampoff ();
@@ -743,9 +635,7 @@ gus_voice_fade (int voice)
 
   gus_ramp_range (65, 4030);
   gus_ramp_rate (2, 4);
-  gus_rampon (0x40 | 0x20);    /*
-                                * Down, once, irq
-                                */
+  gus_rampon (0x40 | 0x20);    /* Down, once, with IRQ */
   voices[voice].volume_irq_mode = VMODE_HALT;
   RESTORE_INTR (flags);
 }
@@ -762,25 +652,16 @@ gus_reset (void)
 
   for (i = 0; i < 32; i++)
     {
-      gus_voice_init (i);      /*
-                                * Turn voice off
-                                */
+      gus_voice_init (i);      /* Turn voice off */
       gus_voice_init2 (i);
     }
 
-  INB (u_Status);              /*
-                                * Touch the status register
-                                */
+  INB (u_Status);              /* Touch the status register */
 
-  gus_look8 (0x41);            /*
-                                * Clear any pending DMA IRQs
-                                */
-  gus_look8 (0x49);            /*
-                                * Clear any pending sample IRQs
-                                */
-  gus_read8 (0x0f);            /*
-                                * Clear pending IRQs
-                                */
+  gus_look8 (0x41);            /* Clear any pending DMA IRQs */
+  gus_look8 (0x49);            /* Clear any pending sample IRQs */
+
+  gus_read8 (0x0f);            /* Clear pending IRQs */
 
 }
 
@@ -788,7 +669,7 @@ static void
 gus_initialize (void)
 {
   unsigned long   flags;
-  register unsigned char dma_image, irq_image, tmp;
+  unsigned char   dma_image, irq_image, tmp;
 
   static unsigned char gus_irq_map[16] =
   {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
@@ -797,16 +678,11 @@ gus_initialize (void)
   {0, 1, 0, 2, 0, 3, 4, 5};
 
   DISABLE_INTR (flags);
-
-  gus_write8 (0x4c, 0);                /*
-                                * Reset GF1
-                                */
+  gus_write8 (0x4c, 0);                /* Reset GF1 */
   gus_delay ();
   gus_delay ();
 
-  gus_write8 (0x4c, 1);                /*
-                                * Release Reset
-                                */
+  gus_write8 (0x4c, 1);                /* Release Reset */
   gus_delay ();
   gus_delay ();
 
@@ -814,49 +690,25 @@ gus_initialize (void)
    * Clear all interrupts
    */
 
-  gus_write8 (0x41, 0);                /*
-                                * DMA control
-                                */
-  gus_write8 (0x45, 0);                /*
-                                * Timer control
-                                */
-  gus_write8 (0x49, 0);                /*
-                                * Sample control
-                                */
+  gus_write8 (0x41, 0);                /* DMA control */
+  gus_write8 (0x45, 0);                /* Timer control */
+  gus_write8 (0x49, 0);                /* Sample control */
 
   gus_select_max_voices (24);
 
-  INB (u_Status);              /*
-                                * Touch the status register
-                                */
+  INB (u_Status);              /* Touch the status register */
 
-  gus_look8 (0x41);            /*
-                                * Clear any pending DMA IRQs
-                                */
-  gus_look8 (0x49);            /*
-                                * Clear any pending sample IRQs
-                                */
-  gus_read8 (0x0f);            /*
-                                * Clear pending IRQs
-                                */
+  gus_look8 (0x41);            /* Clear any pending DMA IRQs */
+  gus_look8 (0x49);            /* Clear any pending sample IRQs */
+  gus_read8 (0x0f);            /* Clear pending IRQs */
 
-  gus_reset ();                        /*
-                                * Resets all voices
-                                */
+  gus_reset ();                        /* Resets all voices */
 
-  gus_look8 (0x41);            /*
-                                * Clear any pending DMA IRQs
-                                */
-  gus_look8 (0x49);            /*
-                                * Clear any pending sample IRQs
-                                */
-  gus_read8 (0x0f);            /*
-                                * Clear pending IRQs
-                                */
+  gus_look8 (0x41);            /* Clear any pending DMA IRQs */
+  gus_look8 (0x49);            /* Clear any pending sample IRQs */
+  gus_read8 (0x0f);            /* Clear pending IRQs */
 
-  gus_write8 (0x4c, 7);                /*
-                                * Master reset | DAC enable | IRQ enable
-                                */
+  gus_write8 (0x4c, 7);                /* Master reset | DAC enable | IRQ enable */
 
   /*
    * Set up for Digital ASIC
@@ -864,9 +716,7 @@ gus_initialize (void)
 
   OUTB (0x05, gus_base + 0x0f);
 
-  mix_image |= 0x02;           /*
-                                * Disable line out
-                                */
+  mix_image |= 0x02;           /* Disable line out */
   OUTB (mix_image, u_Mixer);
 
   OUTB (0x00, u_IRQDMAControl);
@@ -888,13 +738,9 @@ gus_initialize (void)
   if (!tmp)
     printk ("Warning! GUS IRQ not selected\n");
   irq_image |= tmp;
-  irq_image |= 0x40;           /*
-                                * Combine IRQ1 (GF1) and IRQ2 (Midi)
-                                */
+  irq_image |= 0x40;           /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
 
-  dma_image = 0x40;            /*
-                                * Combine DMA1 (DRAM) and IRQ2 (ADC)
-                                */
+  dma_image = 0x40;            /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
   tmp = gus_dma_map[gus_dma];
   if (!tmp)
     printk ("Warning! GUS DMA not selected\n");
@@ -908,60 +754,34 @@ gus_initialize (void)
    * Doing it first time
    */
 
-  OUTB (mix_image, u_Mixer);   /*
-                                * Select DMA control
-                                */
-  OUTB (dma_image | 0x80, u_IRQDMAControl);    /*
-                                                * Set DMA address
-                                                */
+  OUTB (mix_image, u_Mixer);   /* Select DMA control */
+  OUTB (dma_image | 0x80, u_IRQDMAControl);    /* Set DMA address */
 
-  OUTB (mix_image | 0x40, u_Mixer);    /*
-                                        * Select IRQ control
-                                        */
-  OUTB (irq_image, u_IRQDMAControl);   /*
-                                        * Set IRQ address
-                                        */
+  OUTB (mix_image | 0x40, u_Mixer);    /* Select IRQ control */
+  OUTB (irq_image, u_IRQDMAControl);   /* Set IRQ address */
 
   /*
    * Doing it second time
    */
 
-  OUTB (mix_image, u_Mixer);   /*
-                                * Select DMA control
-                                */
-  OUTB (dma_image, u_IRQDMAControl);   /*
-                                        * Set DMA address
-                                        */
+  OUTB (mix_image, u_Mixer);   /* Select DMA control */
+  OUTB (dma_image, u_IRQDMAControl);   /* Set DMA address */
 
-  OUTB (mix_image | 0x40, u_Mixer);    /*
-                                        * Select IRQ control
-                                        */
-  OUTB (irq_image, u_IRQDMAControl);   /*
-                                        * Set IRQ address
-                                        */
+  OUTB (mix_image | 0x40, u_Mixer);    /* Select IRQ control */
+  OUTB (irq_image, u_IRQDMAControl);   /* Set IRQ address */
 
-  gus_select_voice (0);                /*
-                                * This disables writes to IRQ/DMA reg
-                                */
+  gus_select_voice (0);                /* This disables writes to IRQ/DMA reg */
 
-  mix_image &= ~0x02;          /*
-                                * Enable line out
-                                */
-  mix_image |= 0x08;           /*
-                                * Enable IRQ
-                                */
+  mix_image &= ~0x02;          /* Enable line out */
+  mix_image |= 0x08;           /* Enable IRQ */
   OUTB (mix_image, u_Mixer);   /*
                                 * Turn mixer channels on
                                 * Note! Mic in is left off.
                                 */
 
-  gus_select_voice (0);                /*
-                                * This disables writes to IRQ/DMA reg
-                                */
+  gus_select_voice (0);                /* This disables writes to IRQ/DMA reg */
 
-  gusintr (0);                 /*
-                                * Serve pending interrupts
-                                */
+  gusintr (0);                 /* Serve pending interrupts */
   RESTORE_INTR (flags);
 }
 
@@ -1068,16 +888,13 @@ guswave_set_instr (int dev, int voice, int instr_no)
   if (sample_no < 0)
     {
       printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
-      return RET_ERROR (EINVAL);/*
-                                        * Patch not defined
-                                        */
+      return RET_ERROR (EINVAL);/* Patch not defined */
     }
 
-  if (sample_ptrs[sample_no] == -1)    /*
-                                        * Sample not loaded
-                                        */
+  if (sample_ptrs[sample_no] == -1)    /* Sample not loaded */
     {
-      printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);
+      printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n",
+             sample_no, instr_no, voice);
       return RET_ERROR (EINVAL);
     }
 
@@ -1087,15 +904,12 @@ guswave_set_instr (int dev, int voice, int instr_no)
 }
 
 static int
-#ifdef FUTURE_VERSION
 guswave_kill_note (int dev, int voice, int note, int velocity)
-#else
-guswave_kill_note (int dev, int voice, int velocity)
-#endif
 {
   unsigned long   flags;
 
   DISABLE_INTR (flags);
+  voice_alloc->map[voice] = 0xffff;
   if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
     {
       voices[voice].kill_pending = 1;
@@ -1116,26 +930,20 @@ guswave_aftertouch (int dev, int voice, int pressure)
   short           lo_limit, hi_limit;
   unsigned long   flags;
 
-  return;                      /*
-                                * Currently disabled
-                                */
+  return;                      /* Procedure currently disabled */
 
   if (voice < 0 || voice > 31)
     return;
 
   if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
-    return;                    /*
-                                * Don't mix with envelopes
-                                */
+    return;                    /* Don't mix with envelopes */
 
   if (pressure < 32)
     {
       DISABLE_INTR (flags);
       gus_select_voice (voice);
       gus_rampoff ();
-      compute_and_set_volume (voice, 255, 0);  /*
-                                                * Back to original volume
-                                                */
+      compute_and_set_volume (voice, 255, 0);  /* Back to original volume */
       RESTORE_INTR (flags);
       return;
     }
@@ -1154,9 +962,7 @@ guswave_aftertouch (int dev, int voice, int pressure)
     }
   gus_ramp_range (lo_limit, hi_limit);
   gus_ramp_rate (3, 8);
-  gus_rampon (0x58);           /*
-                                * Bidirectional, Down, Loop
-                                */
+  gus_rampon (0x58);           /* Bidirectional, dow, loop */
   RESTORE_INTR (flags);
 }
 
@@ -1236,9 +1042,7 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
     rate = 16;
   gus_ramp_rate (0, rate);
 
-  if ((target - current) / 64 == 0)    /*
-                                        * Too close
-                                        */
+  if ((target - current) / 64 == 0)    /* Close enough to target. */
     {
       gus_rampoff ();
       gus_voice_volume (target);
@@ -1251,9 +1055,7 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
       if (target > (4095 - 65))
        target = 4095 - 65;
       gus_ramp_range (current, target);
-      gus_rampon (0x00);       /*
-                                * Ramp up, once, no irq
-                                */
+      gus_rampon (0x00);       /* Ramp up, once, no IRQ */
     }
   else
     {
@@ -1261,9 +1063,7 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
        target = 65;
 
       gus_ramp_range (target, current);
-      gus_rampon (0x40);       /*
-                                * Ramp down, once, no irq
-                                */
+      gus_rampon (0x40);       /* Ramp down, once, no irq */
     }
   RESTORE_INTR (flags);
 }
@@ -1276,15 +1076,11 @@ dynamic_volume_change (int voice)
 
   DISABLE_INTR (flags);
   gus_select_voice (voice);
-  status = gus_read8 (0x00);   /*
-                                * Voice status
-                                */
+  status = gus_read8 (0x00);   /* Get voice status */
   RESTORE_INTR (flags);
 
   if (status & 0x03)
-    return;                    /*
-                                * Voice not started
-                                */
+    return;                    /* Voice was not running */
 
   if (!(voices[voice].mode & WAVE_ENVELOPES))
     {
@@ -1298,14 +1094,10 @@ dynamic_volume_change (int voice)
 
   DISABLE_INTR (flags);
   gus_select_voice (voice);
-  status = gus_read8 (0x0d);   /*
-                                * Ramping status
-                                */
+  status = gus_read8 (0x0d);   /* Ramping status */
   RESTORE_INTR (flags);
 
-  if (status & 0x03)           /*
-                                * Sustain phase?
-                                */
+  if (status & 0x03)           /* Sustain phase? */
     {
       compute_and_set_volume (voice, voices[voice].midi_volume, 1);
       return;
@@ -1316,16 +1108,6 @@ dynamic_volume_change (int voice)
 
   compute_volume (voice, voices[voice].midi_volume);
 
-#if 0                          /*
-                                  * * * Is this really required   */
-  voices[voice].current_volume =
-    gus_read16 (0x09) >> 4;    /*
-                                * Get current volume
-                                */
-
-  voices[voice].env_phase--;
-  step_envelope (voice);
-#endif
 }
 
 static void
@@ -1344,7 +1126,8 @@ guswave_controller (int dev, int voice, int ctrl_num, int value)
 
       if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
        {
-         freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+         freq = compute_finetune (voices[voice].orig_freq, value,
+                                  voices[voice].bender_range);
          voices[voice].current_freq = freq;
 
          DISABLE_INTR (flags);
@@ -1357,10 +1140,8 @@ guswave_controller (int dev, int voice, int ctrl_num, int value)
     case CTRL_PITCH_BENDER_RANGE:
       voices[voice].bender_range = value;
       break;
-#ifdef FUTURE_VERSION
     case CTL_EXPRESSION:
       value /= 128;
-#endif
     case CTRL_EXPRESSION:
       if (volume_method == VOL_METHOD_ADAGIO)
        {
@@ -1370,14 +1151,12 @@ guswave_controller (int dev, int voice, int ctrl_num, int value)
        }
       break;
 
-#ifdef FUTURE_VERSION
     case CTL_PAN:
       voices[voice].panning = (value * 2) - 128;
       break;
 
     case CTL_MAIN_VOLUME:
       value = (value * 100) / 16383;
-#endif
 
     case CTRL_MAIN_VOLUME:
       voices[voice].main_vol = value;
@@ -1385,9 +1164,7 @@ guswave_controller (int dev, int voice, int ctrl_num, int value)
        dynamic_volume_change (voice);
       break;
 
-    default:                   /*
-                                * Ignore
-                                */
+    default:
       break;
     }
 }
@@ -1449,7 +1226,8 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
          best_sample = samplep;
          best_delta = delta_freq;
        }
-      if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
+      if (samples[samplep].low_note <= note_freq &&
+         note_freq <= samples[samplep].high_note)
        sample = samplep;
       else
        samplep = samples[samplep].key; /*
@@ -1462,16 +1240,10 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
   if (sample == -1)
     {
       printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
-      return 0;                        /*
-                                * Should play default patch ???
-                                */
+      return 0;                        /* Should play default patch ??? */
     }
 
-  is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;    /*
-                                                                * 8 or 16
-                                                                * bit
-                                                                * samples
-                                                                */
+  is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
   voices[voice].mode = samples[sample].mode;
   voices[voice].patch_vol = samples[sample].volume;
 
@@ -1488,9 +1260,7 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
 
   sample_map[voice] = sample;
 
-  base_note = samples[sample].base_note / 100; /*
-                                                * To avoid overflows
-                                                */
+  base_note = samples[sample].base_note / 100; /* Try to avoid overflows */
   note_freq /= 100;
 
   freq = samples[sample].base_freq * note_freq / base_note;
@@ -1502,7 +1272,8 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
    * have to calculate the bending now.
    */
 
-  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
+  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender,
+                          voices[voice].bender_range);
   voices[voice].current_freq = freq;
 
   pan = (samples[sample].panning + voices[voice].panning) / 32;
@@ -1514,9 +1285,7 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
 
   if (samples[sample].mode & WAVE_16_BITS)
     {
-      mode |= 0x04;            /*
-                                * 16 bits
-                                */
+      mode |= 0x04;            /* 16 bits */
       if ((sample_ptrs[sample] >> 18) !=
          ((sample_ptrs[sample] + samples[sample].len) >> 18))
        printk ("GUS: Sample address error\n");
@@ -1528,9 +1297,7 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
 
   DISABLE_INTR (flags);
   gus_select_voice (voice);
-  gus_voice_off ();            /*
-                                * It may still be running
-                                */
+  gus_voice_off ();
   gus_rampoff ();
 
   RESTORE_INTR (flags);
@@ -1548,22 +1315,17 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
 
   if (samples[sample].mode & WAVE_LOOP_BACK)
     gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
-                   voices[voice].offset_pending, is16bits);    /* Sample
-                                                                * start=end */
+                   voices[voice].offset_pending, is16bits);    /* start=end */
   else
     gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
                    is16bits);  /* Sample start=begin */
 
   if (samples[sample].mode & WAVE_LOOPING)
     {
-      mode |= 0x08;            /*
-                                * Looping on
-                                */
+      mode |= 0x08;
 
       if (samples[sample].mode & WAVE_BIDIR_LOOP)
-       mode |= 0x10;           /*
-                                * Bidirectional looping on
-                                */
+       mode |= 0x10;
 
       if (samples[sample].mode & WAVE_LOOP_BACK)
        {
@@ -1573,36 +1335,20 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
          mode |= 0x40;
        }
 
-      gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits);       /*
-                                                                                                * Loop
-                                                                                                * start
-                                                                                                * location
-                                                                                                */
-      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /*
-                                                                                        * Loop
-                                                                                        * end
-                                                                                        * location
-                                                                                        */
+      gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start,
+                     is16bits);/* Loop start location */
+      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end,
+                     is16bits);/* Loop end location */
     }
   else
     {
-      mode |= 0x20;            /*
-                                * Loop irq at the end
-                                */
-      voices[voice].loop_irq_mode = LMODE_FINISH;      /*
-                                                        * Ramp it down at
-                                                        * the * end
-                                                        */
+      mode |= 0x20;            /* Loop IRQ at the end */
+      voices[voice].loop_irq_mode = LMODE_FINISH;      /* Ramp down at the end */
       voices[voice].loop_irq_parm = 1;
-      gus_write_addr (0x02, sample_ptrs[sample], is16bits);    /*
-                                                                * Loop start
-                                                                * location
-                                                                */
-      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, is16bits);  /*
-                                                                                        * Loop
-                                                                                        * end
-                                                                                        * location
-                                                                                        */
+      gus_write_addr (0x02, sample_ptrs[sample],
+                     is16bits);/* Loop start location */
+      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1,
+                     is16bits);/* Loop end location */
     }
   gus_voice_freq (freq);
   gus_voice_balance (pan);
@@ -1613,9 +1359,10 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
 }
 
 /*
- * * New guswave_start_note by Andrew J. Robinson attempts to minimize
- * clicking  * when the note playing on the voice is changed.  It uses volume
- * ramping. */
+ * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking
+ * when the note playing on the voice is changed.  It uses volume
+ * ramping.
+ */
 
 static int
 guswave_start_note (int dev, int voice, int note_num, int volume)
@@ -1656,7 +1403,7 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
          DISABLE_INTR (flags);
        }
 
-      if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
+      if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065))
        {
          ret_val = guswave_start_note2 (dev, voice, note_num, volume);
        }
@@ -1699,7 +1446,7 @@ guswave_open (int dev, int mode)
 
   gus_initialize ();
 
-  if ((err = DMAbuf_open_dma (gus_devnum)))
+  if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
     return err;
 
   RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
@@ -1731,11 +1478,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
 
   unsigned long   blk_size, blk_end, left, src_offs, target;
 
-  sizeof_patch = (long) &patch.data[0] - (long) &patch;        /*
-                                                                * Size of
-                                                                * the header
-                                                                * * info
-                                                                */
+  sizeof_patch = (long) &patch.data[0] - (long) &patch;        /* Header size */
 
   if (format != GUS_PATCH)
     {
@@ -1800,9 +1543,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
        }
     }
 
-  free_mem_ptr = (free_mem_ptr + 31) & ~31;    /*
-                                                * Alignment 32 bytes
-                                                */
+  free_mem_ptr = (free_mem_ptr + 31) & ~31;    /* 32 byte alignment */
 
 #define GUS_BANK_SIZE (256*1024)
 
@@ -1820,17 +1561,13 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
       if ((free_mem_ptr / GUS_BANK_SIZE) !=
          ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
        {
-         unsigned long   tmp_mem =     /*
-                                        * Align to 256K*N
-                                        */
+         unsigned long   tmp_mem =     /* Aling to 256K */
          ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
 
          if ((tmp_mem + patch.len) > gus_mem_size)
            return RET_ERROR (ENOSPC);
 
-         free_mem_ptr = tmp_mem;       /*
-                                        * This leaves unusable memory
-                                        */
+         free_mem_ptr = tmp_mem;       /* This leaves unusable memory */
        }
     }
 
@@ -1863,11 +1600,9 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
   src_offs = 0;
   target = free_mem_ptr;
 
-  while (left)                 /*
-                                * Not all moved
-                                */
+  while (left)                 /* Not completely transferred yet */
     {
-      blk_size = sound_buffsizes[gus_devnum];
+      blk_size = audio_devs[gus_devnum]->buffsize;
       if (blk_size > left)
        blk_size = left;
 
@@ -1877,9 +1612,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
       blk_end = target + blk_size;
 
       if ((target >> 18) != (blk_end >> 18))
-       {                       /*
-                                * Have to split the block
-                                */
+       {                       /* Split the block */
 
          blk_end &= ~(256 * 1024 - 1);
          blk_size = blk_end - target;
@@ -1899,14 +1632,11 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
            if (patch.mode & WAVE_UNSIGNED)
 
              if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
-               data ^= 0x80;   /*
-                                * Convert to signed
-                                */
+               data ^= 0x80;   /* Convert to signed */
            gus_poke (target + i, data);
          }
       }
-#else /*
-         * * * GUS_NO_DMA   */
+#else /* GUS_NO_DMA */
       {
        unsigned long   address, hold_address;
        unsigned char   dma_command;
@@ -1916,15 +1646,14 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
         * OK, move now. First in and then out.
         */
 
-       COPY_FROM_USER (snd_raw_buf[gus_devnum][0],
+       COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0],
                        addr, sizeof_patch + src_offs,
                        blk_size);
 
        DISABLE_INTR (flags);   /******** INTERRUPTS DISABLED NOW ********/
-       gus_write8 (0x41, 0);   /*
-                                * Disable GF1 DMA
-                                */
-       DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0],
+       gus_write8 (0x41, 0);   /* Disable GF1 DMA */
+       DMAbuf_start_dma (gus_devnum,
+                         audio_devs[gus_devnum]->dmap->raw_buf_phys[0],
                          blk_size, DMA_MODE_WRITE);
 
        /*
@@ -1933,7 +1662,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
 
        address = target;
 
-       if (sound_dsp_dmachan[gus_devnum] > 3)
+       if (audio_devs[gus_devnum]->dmachan > 3)
          {
            hold_address = address;
            address = address >> 1;
@@ -1941,33 +1670,21 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
            address |= (hold_address & 0x000c0000L);
          }
 
-       gus_write16 (0x42, (address >> 4) & 0xffff);    /*
-                                                        * DRAM DMA address
-                                                        */
+       gus_write16 (0x42, (address >> 4) & 0xffff);    /* DRAM DMA address */
 
        /*
         * Start the DMA transfer
         */
 
-       dma_command = 0x21;     /*
-                                * IRQ enable, DMA start
-                                */
+       dma_command = 0x21;     /* IRQ enable, DMA start */
        if (patch.mode & WAVE_UNSIGNED)
-         dma_command |= 0x80;  /*
-                                * Invert MSB
-                                */
+         dma_command |= 0x80;  /* Invert MSB */
        if (patch.mode & WAVE_16_BITS)
-         dma_command |= 0x40;  /*
-                                * 16 bit _DATA_
-                                */
-       if (sound_dsp_dmachan[gus_devnum] > 3)
-         dma_command |= 0x04;  /*
-                                * 16 bit DMA channel
-                                */
+         dma_command |= 0x40;  /* 16 bit _DATA_ */
+       if (audio_devs[gus_devnum]->dmachan > 3)
+         dma_command |= 0x04;  /* 16 bit DMA _channel_ */
 
-       gus_write8 (0x41, dma_command); /*
-                                                * Let's go luteet (=bugs)
-                                                */
+       gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */
 
        /*
         * Sleep here until the DRAM DMA done interrupt is served
@@ -1979,8 +1696,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
          printk ("GUS: DMA Transfer timed out\n");
        RESTORE_INTR (flags);
       }
-#endif /*
-          * * * GUS_NO_DMA   */
+#endif /* GUS_NO_DMA */
 
       /*
        * Now the next part
@@ -1990,9 +1706,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
       src_offs += blk_size;
       target += blk_size;
 
-      gus_write8 (0x41, 0);    /*
-                                * Stop DMA
-                                */
+      gus_write8 (0x41, 0);    /* Stop DMA */
     }
 
   free_mem_ptr += patch.len;
@@ -2037,9 +1751,7 @@ guswave_hw_control (int dev, unsigned char *event)
     case _GUS_VOICEON:
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;             /*
-                                * Disable intr
-                                */
+      p1 &= ~0x20;             /* Don't allow interrupts */
       gus_voice_on (p1);
       RESTORE_INTR (flags);
       break;
@@ -2058,9 +1770,7 @@ guswave_hw_control (int dev, unsigned char *event)
     case _GUS_VOICEMODE:
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;             /*
-                                * Disable intr
-                                */
+      p1 &= ~0x20;             /* Don't allow interrupts */
       gus_voice_mode (p1);
       RESTORE_INTR (flags);
       break;
@@ -2086,18 +1796,14 @@ guswave_hw_control (int dev, unsigned char *event)
       RESTORE_INTR (flags);
       break;
 
-    case _GUS_VOICEVOL2:       /*
-                                * Just update the voice value
-                                */
+    case _GUS_VOICEVOL2:       /* Just update the software voice level */
       voices[voice].initial_volume =
        voices[voice].current_volume = p1;
       break;
 
     case _GUS_RAMPRANGE:
       if (voices[voice].mode & WAVE_ENVELOPES)
-       break;                  /*
-                                * NO-NO
-                                */
+       break;                  /* NO-NO */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
       gus_ramp_range (p1, p2);
@@ -2106,9 +1812,7 @@ guswave_hw_control (int dev, unsigned char *event)
 
     case _GUS_RAMPRATE:
       if (voices[voice].mode & WAVE_ENVELOPES)
-       break;                  /*
-                                * NO-NO
-                                */
+       break;                  /* NJET-NJET */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
       gus_ramp_rate (p1, p2);
@@ -2117,37 +1821,27 @@ guswave_hw_control (int dev, unsigned char *event)
 
     case _GUS_RAMPMODE:
       if (voices[voice].mode & WAVE_ENVELOPES)
-       break;                  /*
-                                * NO-NO
-                                */
+       break;                  /* NO-NO */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;             /*
-                                * Disable intr
-                                */
+      p1 &= ~0x20;             /* Don't allow interrupts */
       gus_ramp_mode (p1);
       RESTORE_INTR (flags);
       break;
 
     case _GUS_RAMPON:
       if (voices[voice].mode & WAVE_ENVELOPES)
-       break;                  /*
-                                * NO-NO
-                                */
+       break;                  /* EI-EI */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
-      p1 &= ~0x20;             /*
-                                * Disable intr
-                                */
+      p1 &= ~0x20;             /* Don't allow interrupts */
       gus_rampon (p1);
       RESTORE_INTR (flags);
       break;
 
     case _GUS_RAMPOFF:
       if (voices[voice].mode & WAVE_ENVELOPES)
-       break;                  /*
-                                * NO-NO
-                                */
+       break;                  /* NEJ-NEJ */
       DISABLE_INTR (flags);
       gus_select_voice (voice);
       gus_rampoff ();
@@ -2244,7 +1938,7 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
       return IOCTL_OUT (arg, gus_sampling_channels);
       break;
 
-    case SNDCTL_DSP_SAMPLESIZE:
+    case SNDCTL_DSP_SETFMT:
       if (local)
        return gus_sampling_set_bits (arg);
       return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg)));
@@ -2255,9 +1949,7 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
        return gus_sampling_bits;
       return IOCTL_OUT (arg, gus_sampling_bits);
 
-    case SOUND_PCM_WRITE_FILTER:       /*
-                                        * NOT YET IMPLEMENTED
-                                        */
+    case SOUND_PCM_WRITE_FILTER:       /* NOT POSSIBLE */
       return IOCTL_OUT (arg, RET_ERROR (EINVAL));
       break;
 
@@ -2297,6 +1989,7 @@ gus_sampling_open (int dev, int mode)
   gus_select_max_voices (14);
 
   pcm_active = 0;
+  dma_active = 0;
   pcm_opened = 1;
   if (mode & OPEN_READ)
     {
@@ -2356,24 +2049,18 @@ play_next_pcm_block (void)
   for (chn = 0; chn < gus_sampling_channels; chn++)
     {
       mode[chn] = 0x00;
-      ramp_mode[chn] = 0x03;   /*
-                                * Ramping and rollover off
-                                */
+      ramp_mode[chn] = 0x03;   /* Ramping and rollover off */
 
       if (chn == 0)
        {
-         mode[chn] |= 0x20;    /*
-                                * Loop irq
-                                */
+         mode[chn] |= 0x20;    /* Loop IRQ */
          voices[chn].loop_irq_mode = LMODE_PCM;
        }
 
       if (gus_sampling_bits != 8)
        {
          is16bits = 1;
-         mode[chn] |= 0x04;    /*
-                                * 16 bit data
-                                */
+         mode[chn] |= 0x04;    /* 16 bit data */
        }
       else
        is16bits = 0;
@@ -2381,23 +2068,15 @@ play_next_pcm_block (void)
       dram_loc = this_one * pcm_bsize;
       dram_loc += chn * pcm_banksize;
 
-      if (this_one == (pcm_nblk - 1))  /*
-                                        * Last of the DRAM buffers
-                                        */
+      if (this_one == (pcm_nblk - 1))  /* Last fragment of the DRAM buffer */
        {
-         mode[chn] |= 0x08;    /*
-                                * Enable loop
-                                */
-         ramp_mode[chn] = 0x03;/*
-                                        * Disable rollover
-                                        */
+         mode[chn] |= 0x08;    /* Enable loop */
+         ramp_mode[chn] = 0x03;/* Disable rollover bit */
        }
       else
        {
          if (chn == 0)
-           ramp_mode[chn] = 0x04;      /*
-                                        * Enable rollover bit
-                                        */
+           ramp_mode[chn] = 0x04;      /* Enable rollover bit */
        }
 
       DISABLE_INTR (flags);
@@ -2405,21 +2084,13 @@ play_next_pcm_block (void)
       gus_voice_freq (speed);
 
       if (gus_sampling_channels == 1)
-       gus_voice_balance (7);  /*
-                                * mono
-                                */
+       gus_voice_balance (7);  /* mono */
       else if (chn == 0)
-       gus_voice_balance (0);  /*
-                                * left
-                                */
+       gus_voice_balance (0);  /* left */
       else
-       gus_voice_balance (15); /*
-                                * right
-                                */
+       gus_voice_balance (15); /* right */
 
-      if (!pcm_active)         /*
-                                * Voice not started yet
-                                */
+      if (!pcm_active)         /* Playback not already active */
        {
          /*
           * The playback was not started yet (or there has been a pause).
@@ -2428,67 +2099,42 @@ play_next_pcm_block (void)
           * the normal loop with irq.
           */
 
-         gus_voice_off ();     /*
-                                * It could already be running
-                                */
+         gus_voice_off ();
          gus_rampoff ();
          gus_voice_volume (1530 + (25 * gus_pcm_volume));
          gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
 
-         gus_write_addr (0x0a, dram_loc, is16bits);    /*
-                                                        * Starting position
-                                                        */
-         gus_write_addr (0x02, chn * pcm_banksize, is16bits);  /*
-                                                                * Loop start
-                                                                * location
-                                                                */
+         gus_write_addr (0x0a, dram_loc, is16bits);    /* Starting position */
+         gus_write_addr (0x02, chn * pcm_banksize, is16bits);  /* Loop start */
 
          if (chn != 0)
            gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
-                           is16bits);  /*
-                                        * Loop end location
-                                        */
+                           is16bits);  /* Loop end location */
        }
 
       if (chn == 0)
-       gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits);     /*
-                                                                                * Loop
-                                                                                * end
-                                                                                * location
-                                                                                */
+       gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
+                       is16bits);      /* Loop end location */
       else
-       mode[chn] |= 0x08;      /*
-                                * Enable loop
-                                */
+       mode[chn] |= 0x08;      /* Enable looping */
 
       if (pcm_datasize[this_one] != pcm_bsize)
        {
          /*
-          * Incomplete block. Possibly the last one.
+          * Incompletely filled block. Possibly the last one.
           */
          if (chn == 0)
            {
-             mode[chn] &= ~0x08;       /*
-                                        * Disable loop
-                                        */
-             mode[chn] |= 0x20;/*
-                                        * Enable loop IRQ
-                                        */
+             mode[chn] &= ~0x08;       /* Disable looping */
+             mode[chn] |= 0x20;/* Enable IRQ at the end */
              voices[0].loop_irq_mode = LMODE_PCM_STOP;
-             ramp_mode[chn] = 0x03;    /*
-                                        * No rollover bit
-                                        */
+             ramp_mode[chn] = 0x03;    /* No rollover bit */
            }
          else
            {
-             gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits);       /*
-                                                                                        * Loop
-                                                                                        * end
-                                                                                        * location
-                                                                                        */
-             mode[chn] &= ~0x08;       /*
-                                        * Disable loop
-                                        */
+             gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
+                             is16bits);        /* Loop end location */
+             mode[chn] &= ~0x08;       /* Disable looping */
            }
        }
 
@@ -2542,15 +2188,13 @@ gus_transfer_output_block (int dev, unsigned long buf,
   else
     this_one = pcm_current_block;
 
-  gus_write8 (0x41, 0);                /*
-                                * Disable GF1 DMA
-                                */
+  gus_write8 (0x41, 0);                /* Disable GF1 DMA */
   DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
 
   address = this_one * pcm_bsize;
   address += chn * pcm_banksize;
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     {
       hold_address = address;
       address = address >> 1;
@@ -2558,49 +2202,40 @@ gus_transfer_output_block (int dev, unsigned long buf,
       address |= (hold_address & 0x000c0000L);
     }
 
-  gus_write16 (0x42, (address >> 4) & 0xffff); /*
-                                                * DRAM DMA address
-                                                */
+  gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
 
-  dma_command = 0x21;          /*
-                                * IRQ enable, DMA start
-                                */
+  dma_command = 0x21;          /* IRQ enable, DMA start */
 
   if (gus_sampling_bits != 8)
-    dma_command |= 0x40;       /*
-                                * 16 bit _DATA_
-                                */
+    dma_command |= 0x40;       /* 16 bit _DATA_ */
   else
-    dma_command |= 0x80;       /*
-                                * Invert MSB
-                                */
+    dma_command |= 0x80;       /* Invert MSB */
 
-  if (sound_dsp_dmachan[dev] > 3)
-    dma_command |= 0x04;       /*
-                                * 16 bit DMA channel
-                                */
+  if (audio_devs[dev]->dmachan > 3)
+    dma_command |= 0x04;       /* 16 bit DMA channel */
 
-  gus_write8 (0x41, dma_command);      /*
-                                        * Kick on
-                                        */
+  gus_write8 (0x41, dma_command);      /* Kickstart */
 
-  if (chn == (gus_sampling_channels - 1))      /*
-                                                * Last channel
-                                                */
+  if (chn == (gus_sampling_channels - 1))      /* Last channel */
     {
       /*
        * Last (right or mono) channel data
        */
+      dma_active = 1;          /* DMA started. There is a unacknowledged buffer */
       active_device = GUS_DEV_PCM_DONE;
-      if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))
+      if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize))
        {
          play_next_pcm_block ();
        }
     }
-  else                         /*
-                                  * * * Left channel data. The right channel
-                                  * is * * * transferred after DMA interrupt   */
-    active_device = GUS_DEV_PCM_CONTINUE;
+  else
+    {
+      /*
+        * Left channel data. The right channel
+        * is transferred after DMA interrupt
+        */
+      active_device = GUS_DEV_PCM_CONTINUE;
+    }
 
   RESTORE_INTR (flags);
 }
@@ -2627,21 +2262,13 @@ gus_sampling_start_input (int dev, unsigned long buf, int count,
 
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 
-  mode = 0xa0;                 /*
-                                * DMA IRQ enable, invert MSB
-                                */
+  mode = 0xa0;                 /* DMA IRQ enabled, invert MSB */
 
-  if (sound_dsp_dmachan[dev] > 3)
-    mode |= 0x04;              /*
-                                * 16 bit DMA channel
-                                */
+  if (audio_devs[dev]->dmachan > 3)
+    mode |= 0x04;              /* 16 bit DMA channel */
   if (gus_sampling_channels > 1)
-    mode |= 0x02;              /*
-                                * Stereo
-                                */
-  mode |= 0x01;                        /*
-                                * DMA enable
-                                */
+    mode |= 0x02;              /* Stereo */
+  mode |= 0x01;                        /* DMA enable */
 
   gus_write8 (0x49, mode);
 
@@ -2655,9 +2282,7 @@ gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
 
   rate = (9878400 / (gus_sampling_speed + 2)) / 16;
 
-  gus_write8 (0x48, rate & 0xff);      /*
-                                        * Set sampling frequency
-                                        */
+  gus_write8 (0x48, rate & 0xff);      /* Set sampling rate */
 
   if (gus_sampling_bits != 8)
     {
@@ -2700,9 +2325,9 @@ gus_sampling_prepare_for_output (int dev, int bsize, int bcount)
 }
 
 static int
-gus_has_output_drained (int dev)
+gus_local_qlen (int dev)
 {
-  return !pcm_qlen;
+  return pcm_qlen;
 }
 
 static void
@@ -2760,6 +2385,8 @@ static struct audio_operations gus_sampling_operations =
 {
   "Gravis UltraSound",
   NEEDS_RESTART,
+  AFMT_U8 | AFMT_S16_LE,
+  NULL,
   gus_sampling_open,
   gus_sampling_close,
   gus_sampling_output_block,
@@ -2769,11 +2396,10 @@ static struct audio_operations gus_sampling_operations =
   gus_sampling_prepare_for_output,
   gus_sampling_reset,
   gus_sampling_reset,
-  gus_has_output_drained,
+  gus_local_qlen,
   gus_copy_from_user
 };
 
-#ifdef FUTURE_VERSION
 static void
 guswave_bender (int dev, int voice, int value)
 {
@@ -2781,7 +2407,8 @@ guswave_bender (int dev, int voice, int value)
   unsigned long   flags;
 
   voices[voice].bender = value - 8192;
-  freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+  freq = compute_finetune (voices[voice].orig_freq, value,
+                          voices[voice].bender_range);
   voices[voice].current_freq = freq;
 
   DISABLE_INTR (flags);
@@ -2790,8 +2417,6 @@ guswave_bender (int dev, int voice, int value)
   RESTORE_INTR (flags);
 }
 
-#endif
-
 static int
 guswave_patchmgr (int dev, struct patmgr_info *rec)
 {
@@ -2821,9 +2446,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
          while (ptr >= 0 && ptr < free_sample)
            {
              rec->data.data8[i]++;
-             ptr = samples[ptr].key;   /*
-                                        * Follow link
-                                        */
+             ptr = samples[ptr].key;   /* Follow link */
            }
        }
       return 0;
@@ -2838,9 +2461,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
        while (ptr >= 0 && ptr < free_sample)
          {
            rec->data.data32[n++] = ptr;
-           ptr = samples[ptr].key;     /*
-                                        * Follow link
-                                        */
+           ptr = samples[ptr].key;     /* Follow link */
          }
       }
       rec->parm1 = n;
@@ -2860,12 +2481,8 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
 
        pat = (struct patch_info *) rec->data.data8;
 
-       pat->key = GUS_PATCH;   /*
-                                * Restore patch type
-                                */
-       rec->parm1 = sample_ptrs[ptr];  /*
-                                        * DRAM address
-                                        */
+       pat->key = GUS_PATCH;   /* Restore patch type */
+       rec->parm1 = sample_ptrs[ptr];  /* DRAM location */
        rec->parm2 = sizeof (struct patch_info);
       }
       return 0;
@@ -2881,14 +2498,10 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
 
        pat = (struct patch_info *) rec->data.data8;
 
-       if (pat->len > samples[ptr].len)        /*
-                                                * Cannot expand sample
-                                                */
+       if (pat->len > samples[ptr].len)        /* Cannot expand sample */
          return RET_ERROR (EINVAL);
 
-       pat->key = samples[ptr].key;    /*
-                                        * Ensure the link is correct
-                                        */
+       pat->key = samples[ptr].key;    /* Ensure the link is correct */
 
        memcpy ((char *) &samples[ptr], rec->data.data8,
                sizeof (struct patch_info));
@@ -2898,9 +2511,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
       return 0;
       break;
 
-    case PM_READ_PATCH:        /*
-                                * Returns a block of wave data from the DRAM
-                                */
+    case PM_READ_PATCH:        /* Returns a block of wave data from the DRAM */
       {
        int             sample = rec->parm1;
        int             n;
@@ -2911,13 +2522,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
          return RET_ERROR (EINVAL);
 
        if (offs < 0 || offs >= samples[sample].len)
-         return RET_ERROR (EINVAL);    /*
-                                        * Invalid offset
-                                        */
+         return RET_ERROR (EINVAL);    /* Invalid offset */
 
-       n = samples[sample].len - offs; /*
-                                                * Nr of bytes left
-                                                */
+       n = samples[sample].len - offs; /* Num of bytes left */
 
        if (l > n)
          l = n;
@@ -2993,12 +2600,49 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
     }
 }
 
+static int
+guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
+{
+  int             i, p;
+
+  p = alloc->ptr;
+  /*
+ * First look for a completely stopped voice
+ */
+
+  for (i = 0; i < alloc->max_voice; i++)
+    {
+      if (alloc->map[p] == 0)
+       {
+         alloc->ptr = p;
+         return p;
+       }
+      p = (p + 1) % alloc->max_voice;
+    }
+
+  /*
+ * Then look for a releasing voice
+ */
+
+  for (i = 0; i < alloc->max_voice; i++)
+    {
+      if (alloc->map[p] == 0xffff)
+       {
+         alloc->ptr = p;
+         return p;
+       }
+      p = (p + 1) % alloc->max_voice;
+    }
+  printk ("GUS: Out of free voices\n");
+
+  alloc->ptr = p;
+  return p;
+}
+
 static struct synth_operations guswave_operations =
 {
   &gus_info,
-#ifdef FUTURE_VERSION
   0,
-#endif
   SYNTH_TYPE_SAMPLE,
   SAMPLE_TYPE_GUS,
   guswave_open,
@@ -3015,9 +2659,8 @@ static struct synth_operations guswave_operations =
   guswave_panning,
   guswave_volume_method,
   guswave_patchmgr,
-#ifdef FUTURE_VERSION
-  guswave_bender
-#endif
+  guswave_bender,
+  guswave_alloc
 };
 
 static void
@@ -3125,10 +2768,7 @@ gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
 
              if (active_device == GUS_DEV_WAVE)
                for (voice = 0; voice < nr_voices; voice++)
-                 dynamic_volume_change (voice);        /*
-                                                        * Apply the new
-                                                        * volume
-                                                        */
+                 dynamic_volume_change (voice);        /* Apply the new vol */
 
              return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
            }
@@ -3224,7 +2864,7 @@ gus_wave_init (long mem_start, int irq, int dma)
   val = INB (gus_base + 0x0f);
   RESTORE_INTR (flags);
 
-  if (val != 0xff && (val & 0x06))     /* Should be 0x02? */
+  if (val != 0xff && (val & 0x06))     /* Should be 0x02?? */
     {
       /*
         * It has the digital ASIC so the card is at least v3.4.
@@ -3258,6 +2898,31 @@ gus_wave_init (long mem_start, int irq, int dma)
          model_num = "MAX";
          gus_type = 0x40;
          mixer_type = CS4231;
+#ifndef EXCLUDE_GUSMAX
+         {
+           unsigned char   max_config = 0x40;  /* Codec enable */
+
+           if (dma > 3)
+             max_config |= 0x30;       /* 16 bit playback and capture DMAs */
+
+           max_config |= (gus_base >> 4) & 0x0f;       /* Extract the X from 2X0 */
+
+           OUTB (max_config, gus_base + 0x106);        /* UltraMax control */
+         }
+
+         if (ad1848_detect (gus_base + 0x10c))
+           {
+             gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+             gus_wave_volume = 90;
+             have_gus_max = 1;
+             ad1848_init ("GUS MAX", gus_base + 0x10c,
+                          -irq,
+                          dma,
+                          dma);
+           }
+         else
+           printk ("[Where's the CS4231?]");
+#endif
        }
     }
   else
@@ -3295,7 +2960,10 @@ gus_wave_init (long mem_start, int irq, int dma)
   if (num_synths >= MAX_SYNTH_DEV)
     printk ("GUS Error: Too many synthesizers\n");
   else
-    synth_devs[num_synths++] = &guswave_operations;
+    {
+      voice_alloc = &guswave_operations.alloc;
+      synth_devs[num_synths++] = &guswave_operations;
+    }
 
   PERMANENT_MALLOC (struct patch_info *, samples,
                           (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
@@ -3304,13 +2972,12 @@ gus_wave_init (long mem_start, int irq, int dma)
 
   gus_initialize ();
 
-  if (num_dspdevs < MAX_DSP_DEV)
+  if (num_audiodevs < MAX_AUDIO_DEV)
     {
-      dsp_devs[gus_devnum = num_dspdevs++] = &gus_sampling_operations;
-      sound_dsp_dmachan[gus_devnum] = dma;
-      sound_buffcounts[gus_devnum] = 1;
-      sound_buffsizes[gus_devnum] = DSP_BUFFSIZE;
-      sound_dma_automode[gus_devnum] = 0;
+      audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations;
+      audio_devs[gus_devnum]->dmachan = dma;
+      audio_devs[gus_devnum]->buffcount = 1;
+      audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
     }
   else
     printk ("GUS: Too many PCM devices available\n");
@@ -3322,11 +2989,12 @@ gus_wave_init (long mem_start, int irq, int dma)
   switch (mixer_type)
     {
     case ICS2101:
-      gus_line_vol=gus_mic_vol=gus_wave_volume = gus_pcm_volume = 100;
+      gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+      gus_wave_volume = 90;
       return ics2101_mixer_init (mem_start);
 
     case CS4231:
-      /* Available soon */
+      /* Initialized elsewhere (ad1848.c) */
     default:
       return gus_default_mixer_init (mem_start);
     }
@@ -3361,7 +3029,7 @@ do_loop_irq (int voice)
                                 * Final loop finished, shoot volume down
                                 */
 
-      if ((gus_read16 (0x09) >> 4) < 100)      /*
+      if ((int) (gus_read16 (0x09) >> 4) < 100)        /*
                                                 * Get current volume
                                                 */
        {
@@ -3381,12 +3049,11 @@ do_loop_irq (int voice)
       break;
 
     case LMODE_PCM_STOP:
-      pcm_active = 0;          /*
-                                * Requires extensive processing
-                                */
+      pcm_active = 0;          /* Signal to the play_next_pcm_block routine */
     case LMODE_PCM:
       {
        int             orig_qlen = pcm_qlen;
+       int             flag;   /* 0 or 2 */
 
        pcm_qlen--;
        pcm_head = (pcm_head + 1) % pcm_nblk;
@@ -3395,18 +3062,27 @@ do_loop_irq (int voice)
            play_next_pcm_block ();
          }
        else
-         {                     /*
-                                * Out of data. Just stop the voice
-                                */
+         {                     /* Underrun. Just stop the voice */
            gus_voice_off ();
            gus_rampoff ();
            pcm_active = 0;
          }
 
-       if (orig_qlen == pcm_nblk)
+       /*
+ * If the queue was full before this interrupt, the DMA transfer was
+ * suspended. Let it continue now.
+ */
+       if (dma_active)
          {
-           DMAbuf_outputintr (gus_devnum, 0);
+           if (pcm_qlen == 0)
+             flag = 1;         /* Underflow */
+           else
+             flag = 0;
+           dma_active = 0;
          }
+       else
+         flag = 2;             /* Just notify the dmabuf.c */
+       DMAbuf_outputintr (gus_devnum, flag);
       }
       break;
 
@@ -3456,7 +3132,9 @@ do_volume_irq (int voice)
       guswave_start_note2 (voices[voice].dev_pending, voice,
                  voices[voice].note_pending, voices[voice].volume_pending);
       if (voices[voice].kill_pending)
-       guswave_kill_note (voices[voice].dev_pending, voice, 0);
+       guswave_kill_note (voices[voice].dev_pending, voice,
+                          voices[voice].note_pending, 0);
+
       if (voices[voice].sample_pending >= 0)
        {
          guswave_set_instr (voices[voice].dev_pending, voice,
@@ -3495,7 +3173,7 @@ gus_voice_irq (void)
       if (!(src & 0x80))       /*
                                 * Wave IRQ pending
                                 */
-       if (!(wave_ignore & voice_bit) && voice < nr_voices)    /*
+       if (!(wave_ignore & voice_bit) && (int) voice < nr_voices)      /*
                                                                 * Not done
                                                                 * yet
                                                                 */
@@ -3507,7 +3185,7 @@ gus_voice_irq (void)
       if (!(src & 0x40))       /*
                                 * Volume IRQ pending
                                 */
-       if (!(volume_ignore & voice_bit) && voice < nr_voices)  /*
+       if (!(volume_ignore & voice_bit) && (int) voice < nr_voices)    /*
                                                                 * Not done
                                                                 * yet
                                                                 */
@@ -3523,12 +3201,8 @@ guswave_dma_irq (void)
 {
   unsigned char   status;
 
-  status = gus_look8 (0x41);   /*
-                                * Get DMA IRQ Status
-                                */
-  if (status & 0x40)           /*
-                                * DMA Irq pending
-                                */
+  status = gus_look8 (0x41);   /* Get DMA IRQ Status */
+  if (status & 0x40)           /* DMA interrupt pending */
     switch (active_device)
       {
       case GUS_DEV_WAVE:
@@ -3536,16 +3210,21 @@ guswave_dma_irq (void)
          WAKE_UP (dram_sleeper, dram_sleep_flag);
        break;
 
-      case GUS_DEV_PCM_CONTINUE:
+      case GUS_DEV_PCM_CONTINUE:       /* Left channel data transferred */
        gus_transfer_output_block (pcm_current_dev, pcm_current_buf,
                                   pcm_current_count,
                                   pcm_current_intrflag, 1);
        break;
 
-      case GUS_DEV_PCM_DONE:
+      case GUS_DEV_PCM_DONE:   /* Right or mono channel data transferred */
        if (pcm_qlen < pcm_nblk)
          {
-           DMAbuf_outputintr (gus_devnum, pcm_qlen == 0);
+           int             flag = (1 - dma_active) * 2;        /* 0 or 2 */
+
+           if (pcm_qlen == 0)
+             flag = 1;         /* Underrun */
+           dma_active = 0;
+           DMAbuf_outputintr (gus_devnum, flag);
          }
        break;
 
index df65b5d067ab3bd09a1dddf8b8dda1ce19e8e58a..c2522a32ce4618ce16a07d62acce7ff25875ef20 100644 (file)
@@ -44,34 +44,36 @@ static int      left_fix[ICS_MIXDEVS] =
 static int      right_fix[ICS_MIXDEVS] =
 {2, 2, 2, 1, 2, 1};
 
-static int 
-scale_vol(int vol)
+static int
+scale_vol (int vol)
 {
 #if 1
-/*
+  /*
  *     Experimental volume scaling by Risto Kankkunen.
  *     This should give smoother volume response than just
  *     a plain multiplication.
  */
-        int e;
-
-        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);
+  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;
+  return ((vol * 127) + 50) / 100;
 #endif
 }
 
@@ -83,7 +85,7 @@ write_mix (int dev, int chn, int vol)
   int             ctrl_addr = dev << 3;
   int             attn_addr = dev << 3;
 
-  vol=scale_vol(vol);
+  vol = scale_vol (vol);
 
   if (chn == CHN_LEFT)
     {
@@ -180,7 +182,7 @@ ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
 
          case SOUND_MIXER_STEREODEVS:
            return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
-                             SOUND_MASK_SYNTH | SOUND_MASK_VOLUME|
+                             SOUND_MASK_SYNTH | SOUND_MASK_VOLUME |
                              SOUND_MASK_MIC);
            break;
 
diff --git a/drivers/sound/midi_ctrl.h b/drivers/sound/midi_ctrl.h
new file mode 100644 (file)
index 0000000..616b591
--- /dev/null
@@ -0,0 +1,22 @@
+static unsigned char ctrl_def_values[128] =
+{
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*   0 to   7 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*   8 to  15 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  16 to  23 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  24 to  31 */
+
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  32 to  39 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  40 to  47 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  48 to  55 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  56 to  63 */
+       
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  64 to  71 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  72 to  79 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  80 to  87 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  88 to  95 */
+
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /*  96 to 103 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /* 104 to 111 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /* 112 to 119 */
+       0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,      /* 120 to 127 */
+};
diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c
new file mode 100644 (file)
index 0000000..fd6d8bd
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * sound/midi_synth.c
+ *
+ * High level midi sequencer manager for dumb MIDI interfaces.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+
+#define _MIDI_SYNTH_C_
+
+DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
+
+#include "midi_synth.h"
+
+static int      midi2synth[MAX_MIDI_DEV];
+static unsigned char prev_out_status[MAX_MIDI_DEV];
+
+static void
+midi_outc (int midi_dev, int data)
+{
+  int             timeout;
+
+  for (timeout = 0; timeout < 32000; timeout++)
+    if (midi_devs[midi_dev]->putc (midi_dev, (unsigned char) (data & 0xff)))
+      {
+       if (data & 0x80)        /*
+                                * Status byte
+                                */
+         prev_out_status[midi_dev] =
+           (unsigned char) (data & 0xff);      /*
+                                                * Store for running status
+                                                */
+       return;                 /*
+                                * Mission complete
+                                */
+      }
+
+  /*
+   * Sorry! No space on buffers.
+   */
+  printk ("Midi send timed out\n");
+}
+
+static int
+prefix_cmd (int midi_dev, unsigned char status)
+{
+  if (midi_devs[midi_dev]->prefix_cmd == NULL)
+    return 1;
+
+  return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
+}
+
+static void
+midi_synth_input (int dev, unsigned char data)
+{
+  int             orig_dev;
+
+  if (dev < 0 || dev > num_synths)
+    return;
+
+  if (data == 0xfe)            /* Ignore active sensing */
+    return;
+
+  orig_dev = midi2synth[dev];
+
+}
+
+static void
+midi_synth_output (int dev)
+{
+  /*
+   * Currently NOP
+   */
+}
+
+int
+midi_synth_ioctl (int dev,
+                 unsigned int cmd, unsigned int arg)
+{
+  /*
+   * int orig_dev = synth_devs[dev]->midi_dev;
+   */
+
+  switch (cmd)
+    {
+
+    case SNDCTL_SYNTH_INFO:
+      IOCTL_TO_USER ((char *) arg, 0, synth_devs[dev]->info,
+                    sizeof (struct synth_info));
+
+      return 0;
+      break;
+
+    case SNDCTL_SYNTH_MEMAVL:
+      return 0x7fffffff;
+      break;
+
+    default:
+      return RET_ERROR (EINVAL);
+    }
+}
+
+int
+midi_synth_kill_note (int dev, int channel, int note, int velocity)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             msg, chn;
+
+  if (note < 0 || note > 127)
+    return 0;
+  if (channel < 0 || channel > 15)
+    return 0;
+  if (velocity < 0)
+    velocity = 0;
+  if (velocity > 127)
+    velocity = 127;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80))
+    {                          /*
+                                * Use running status
+                                */
+      if (!prefix_cmd (orig_dev, note))
+       return 0;
+
+      midi_outc (orig_dev, note);
+
+      if (msg == 0x90)         /*
+                                * Running status = Note on
+                                */
+       midi_outc (orig_dev, 0);/*
+                                        * Note on with velocity 0 == note
+                                        * off
+                                        */
+      else
+       midi_outc (orig_dev, velocity);
+    }
+  else
+    {
+      if (velocity == 64)
+       {
+         if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
+           return 0;
+         midi_outc (orig_dev, 0x90 | (channel & 0x0f));        /*
+                                                                * Note on
+                                                                */
+         midi_outc (orig_dev, note);
+         midi_outc (orig_dev, 0);      /*
+                                        * Zero G
+                                        */
+       }
+      else
+       {
+         if (!prefix_cmd (orig_dev, 0x80 | (channel & 0x0f)))
+           return 0;
+         midi_outc (orig_dev, 0x80 | (channel & 0x0f));        /*
+                                                                * Note off
+                                                                */
+         midi_outc (orig_dev, note);
+         midi_outc (orig_dev, velocity);
+       }
+    }
+
+  return 0;
+}
+
+int
+midi_synth_set_instr (int dev, int channel, int instr_no)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+
+  if (instr_no < 0 || instr_no > 127)
+    return 0;
+  if (channel < 0 || channel > 15)
+    return 0;
+
+  if (!prefix_cmd (orig_dev, 0xc0 | (channel & 0x0f)))
+    return 0;
+  midi_outc (orig_dev, 0xc0 | (channel & 0x0f));       /*
+                                                        * Program change
+                                                        */
+  midi_outc (orig_dev, instr_no);
+
+  return 0;
+}
+
+int
+midi_synth_start_note (int dev, int channel, int note, int velocity)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             msg, chn;
+
+  if (note < 0 || note > 127)
+    return 0;
+  if (channel < 0 || channel > 15)
+    return 0;
+  if (velocity < 0)
+    velocity = 0;
+  if (velocity > 127)
+    velocity = 127;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (chn == channel && msg == 0x90)
+    {                          /*
+                                * Use running status
+                                */
+      if (!prefix_cmd (orig_dev, note))
+       return 0;
+      midi_outc (orig_dev, note);
+      midi_outc (orig_dev, velocity);
+    }
+  else
+    {
+      if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
+       return 0;
+      midi_outc (orig_dev, 0x90 | (channel & 0x0f));   /*
+                                                        * Note on
+                                                        */
+      midi_outc (orig_dev, note);
+      midi_outc (orig_dev, velocity);
+    }
+  return 0;
+}
+
+void
+midi_synth_reset (int dev)
+{
+}
+
+int
+midi_synth_open (int dev, int mode)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             err;
+
+  if (orig_dev < 0 || orig_dev > num_midis)
+    return RET_ERROR (ENXIO);
+
+  midi2synth[orig_dev] = dev;
+  prev_out_status[orig_dev] = 0;
+
+  if ((err = midi_devs[orig_dev]->open (orig_dev, mode,
+                                 midi_synth_input, midi_synth_output)) < 0)
+    return err;
+
+  return 1;
+}
+
+void
+midi_synth_close (int dev)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+
+  /*
+ * Shut up the synths by sending just single active sensing message.
+ */
+  midi_devs[orig_dev]->putc (orig_dev, 0xfe);
+
+  midi_devs[orig_dev]->close (orig_dev);
+}
+
+void
+midi_synth_hw_control (int dev, unsigned char *event)
+{
+}
+
+int
+midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
+                      int offs, int count, int pmgr_flag)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+
+  struct sysex_info sysex;
+  int             i;
+  unsigned long   left, src_offs, eox_seen = 0;
+  int             first_byte = 1;
+
+  if (!prefix_cmd (orig_dev, 0xf0))
+    return 0;
+
+  if (format != SYSEX_PATCH)
+    {
+      printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format);
+      return RET_ERROR (EINVAL);
+    }
+
+  if (count < sizeof (struct sysex_info))
+    {
+      printk ("MIDI Error: Patch header too short\n");
+      return RET_ERROR (EINVAL);
+    }
+
+  count -= sizeof (struct sysex_info);
+
+  /*
+   * Copy the header from user space but ignore the first bytes which have
+   * been transferred already.
+   */
+
+  COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs);
+
+  if (count < sysex.len)
+    {
+      printk ("MIDI Warning: Sysex record too short (%d<%d)\n",
+             count, (int) sysex.len);
+      sysex.len = count;
+    }
+
+  left = sysex.len;
+  src_offs = 0;
+
+  RESET_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
+
+  for (i = 0; i < left && !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag); i++)
+    {
+      unsigned char   data;
+
+      GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i);
+
+      if (first_byte && data != 0xf0)
+       midi_outc (orig_dev, 0xf0);     /* Sysex start */
+
+      eox_seen = (data == 0xf7);/*
+                                        * Last byte was end of sysex
+                                        */
+
+      if (i == 0)
+       {
+         if (data != 0xf0)     /*
+                                * Sysex start
+                                */
+           return RET_ERROR (EINVAL);
+       }
+
+      while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
+            !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag))
+       DO_SLEEP (sysex_sleeper, sysex_sleep_flag, 1);  /* Wait for timeout */
+
+      if (!first_byte && data & 0x80)
+       return 0;
+      first_byte = 0;
+    }
+
+  if (!eox_seen)
+    midi_outc (orig_dev, 0xf7);
+  return 0;
+}
+
+void
+midi_synth_panning (int dev, int channel, int pressure)
+{
+}
+
+void
+midi_synth_aftertouch (int dev, int channel, int pressure)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             msg, chn;
+
+  if (pressure < 0 || pressure > 127)
+    return;
+  if (channel < 0 || channel > 15)
+    return;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (msg != 0xd0 || chn != channel)   /*
+                                        * Test for running status
+                                        */
+    {
+      if (!prefix_cmd (orig_dev, 0xd0 | (channel & 0x0f)))
+       return;
+      midi_outc (orig_dev, 0xd0 | (channel & 0x0f));   /*
+                                                        * Channel pressure
+                                                        */
+    }
+  else if (!prefix_cmd (orig_dev, pressure))
+    return;
+  midi_outc (orig_dev, pressure);
+}
+
+void
+midi_synth_controller (int dev, int channel, int ctrl_num, int value)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             chn, msg;
+
+  if (ctrl_num < 1 || ctrl_num > 127)
+    return;                    /* NOTE! Controller # 0 ignored */
+  if (channel < 0 || channel > 15)
+    return;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (msg != 0xb0 || chn != channel)
+    {
+      if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f)))
+       return;
+      midi_outc (orig_dev, 0xb0 | (channel & 0x0f));
+    }
+  else if (!prefix_cmd (orig_dev, ctrl_num))
+    return;
+
+  midi_outc (orig_dev, ctrl_num);
+  midi_outc (orig_dev, value & 0x7f);
+}
+
+int
+midi_synth_patchmgr (int dev, struct patmgr_info *rec)
+{
+  return RET_ERROR (EINVAL);
+}
+
+void
+midi_synth_bender (int dev, int channel, int value)
+{
+  int             orig_dev = synth_devs[dev]->midi_dev;
+  int             msg, prev_chn;
+
+  if (channel < 0 || channel > 15)
+    return;
+
+  if (value < 0 || value > 16383)
+    return;
+
+  msg = prev_out_status[orig_dev] & 0xf0;
+  prev_chn = prev_out_status[orig_dev] & 0x0f;
+
+  if (msg != 0xd0 || prev_chn != channel)      /*
+                                                * * Test for running status  */
+    {
+      if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f)))
+       return;
+      midi_outc (orig_dev, 0xe0 | (channel & 0x0f));
+    }
+  else if (!prefix_cmd (orig_dev, value & 0x7f))
+    return;
+
+  midi_outc (orig_dev, value & 0x7f);
+  midi_outc (orig_dev, (value >> 7) & 0x7f);
+}
+
+#endif
diff --git a/drivers/sound/midi_synth.h b/drivers/sound/midi_synth.h
new file mode 100644 (file)
index 0000000..04075e2
--- /dev/null
@@ -0,0 +1,45 @@
+int midi_synth_ioctl (int dev,
+           unsigned int cmd, unsigned int arg);
+int midi_synth_kill_note (int dev, int channel, int note, int velocity);
+int midi_synth_set_instr (int dev, int channel, int instr_no);
+int midi_synth_start_note (int dev, int channel, int note, int volume);
+void midi_synth_reset (int dev);
+int midi_synth_open (int dev, int mode);
+void midi_synth_close (int dev);
+void midi_synth_hw_control (int dev, unsigned char *event);
+int midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
+                int offs, int count, int pmgr_flag);
+void midi_synth_panning (int dev, int channel, int pressure);
+void midi_synth_aftertouch (int dev, int channel, int pressure);
+void midi_synth_controller (int dev, int channel, int ctrl_num, int value);
+int midi_synth_patchmgr (int dev, struct patmgr_info *rec);
+void midi_synth_bender (int dev, int chn, int value);
+
+
+#ifndef _MIDI_SYNTH_C_
+static struct synth_info std_synth_info =
+{MIDI_SYNTH_NAME, 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, MIDI_SYNTH_CAPS};
+
+static struct synth_operations std_midi_synth =
+{
+  &std_synth_info,
+  0,
+  SYNTH_TYPE_MIDI,
+  0,
+  midi_synth_open,
+  midi_synth_close,
+  midi_synth_ioctl,
+  midi_synth_kill_note,
+  midi_synth_start_note,
+  midi_synth_set_instr,
+  midi_synth_reset,
+  midi_synth_hw_control,
+  midi_synth_load_patch,
+  midi_synth_aftertouch,
+  midi_synth_controller,
+  midi_synth_panning,
+  NULL,
+  midi_synth_patchmgr,
+  midi_synth_bender
+};
+#endif
index 7dadb3f8fa7420815680f599d45fbde260a2a98f..ae0ddc3ea54ba022e6e38028aa77bd1b7c355a63 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * sound/midibuf.c
  *
- * Device file manager for /dev/midi
- *
- * NOTE! This part of the driver is currently just a stub.
+ * Device file manager for /dev/midi#
  *
  * Copyright by Hannu Savolainen 1993
  *
 
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MPU401)
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
 
-#if 0
-#include "midiioctl.h"
-#include "midivar.h"
-#endif
+/*
+ * Don't make MAX_QUEUE_SIZE larger than 4000
+ */
+
+#define MAX_QUEUE_SIZE 4000
+
+DEFINE_WAIT_QUEUES (midi_sleeper[MAX_MIDI_DEV], midi_sleep_flag[MAX_MIDI_DEV]);
+DEFINE_WAIT_QUEUES (input_sleeper[MAX_MIDI_DEV], input_sleep_flag[MAX_MIDI_DEV]);
+
+struct midi_buf
+  {
+    int             len, head, tail;
+    unsigned char   queue[MAX_QUEUE_SIZE];
+  };
+
+struct midi_parms
+  {
+    int             prech_timeout;     /*
+                                        * Timeout before the first ch
+                                        */
+  };
+
+static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] =
+{NULL};
+static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] =
+{NULL};
+static struct midi_parms parms[MAX_MIDI_DEV];
+
+static void     midi_poll (unsigned long dummy);
+
+DEFINE_TIMER (poll_timer, midi_poll);
+static volatile int open_devs = 0;
+
+#define DATA_AVAIL(q) (q->len)
+#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
 
-static int      midibuf_busy = 0;
+#define QUEUE_BYTE(q, data) \
+       if (SPACE_AVAIL(q)) \
+       { \
+         unsigned long flags; \
+         DISABLE_INTR(flags); \
+         q->queue[q->tail] = (data); \
+         q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
+         RESTORE_INTR(flags); \
+       }
+
+#define REMOVE_BYTE(q, data) \
+       if (DATA_AVAIL(q)) \
+       { \
+         unsigned long flags; \
+         DISABLE_INTR(flags); \
+         data = q->queue[q->head]; \
+         q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
+         RESTORE_INTR(flags); \
+       }
+
+void
+drain_midi_queue (int dev)
+{
+
+  /*
+   * Give the Midi driver time to drain its output queues
+   */
+
+  if (midi_devs[dev]->buffer_status != NULL)
+    while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
+          midi_devs[dev]->buffer_status (dev))
+      DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], HZ / 10);
+}
+
+static void
+midi_input_intr (int dev, unsigned char data)
+{
+  if (midi_in_buf[dev] == NULL)
+    return;
+
+  if (data == 0xfe)            /*
+                                * Active sensing
+                                */
+    return;                    /*
+                                * Ignore
+                                */
+
+  if (SPACE_AVAIL (midi_in_buf[dev]))
+    {
+      QUEUE_BYTE (midi_in_buf[dev], data);
+      if (SOMEONE_WAITING (input_sleeper[dev], input_sleep_flag[dev]))
+       WAKE_UP (input_sleeper[dev], input_sleep_flag[dev]);
+    }
+
+}
+
+static void
+midi_output_intr (int dev)
+{
+  /*
+   * Currently NOP
+   */
+}
+
+static void
+midi_poll (unsigned long dummy)
+{
+  unsigned long   flags;
+  int             dev;
+
+  DISABLE_INTR (flags);
+  if (open_devs)
+    {
+      for (dev = 0; dev < num_midis; dev++)
+       if (midi_out_buf[dev] != NULL)
+         {
+           while (DATA_AVAIL (midi_out_buf[dev]) &&
+                  midi_devs[dev]->putc (dev,
+                        midi_out_buf[dev]->queue[midi_out_buf[dev]->head]))
+             {
+               midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
+               midi_out_buf[dev]->len--;
+             }
+
+           if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&
+               SOMEONE_WAITING (midi_sleeper[dev], midi_sleep_flag[dev]))
+             WAKE_UP (midi_sleeper[dev], midi_sleep_flag[dev]);
+         }
+      ACTIVATE_TIMER (poll_timer, midi_poll, 1);       /*
+                                                        * Come back later
+                                                        */
+    }
+  RESTORE_INTR (flags);
+}
 
 int
 MIDIbuf_open (int dev, struct fileinfo *file)
 {
   int             mode, err;
+  unsigned long   flags;
 
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
 
-  if (midibuf_busy)
-    return RET_ERROR (EBUSY);
+  if (num_midis > MAX_MIDI_DEV)
+    {
+      printk ("Sound: FATAL ERROR: Too many midi interfaces\n");
+      num_midis = MAX_MIDI_DEV;
+    }
 
-  if (!mpu401_dev)
+  if (dev < 0 || dev >= num_midis)
     {
-      printk ("Midi: MPU-401 compatible Midi interface not present\n");
+      printk ("Sound: Nonexistent MIDI interface %d\n", dev);
       return RET_ERROR (ENXIO);
     }
 
-  if ((err = midi_devs[mpu401_dev]->open (mpu401_dev, mode, NULL, NULL)) < 0)
-    return err;
+  /*
+ *    Interrupts disabled. Be careful
+ */
+
+  DISABLE_INTR (flags);
+  if ((err = midi_devs[dev]->open (dev, mode,
+                                  midi_input_intr, midi_output_intr)) < 0)
+    {
+      RESTORE_INTR (flags);
+      return err;
+    }
+
+  parms[dev].prech_timeout = 0;
+
+  RESET_WAIT_QUEUE (midi_sleeper[dev], midi_sleep_flag[dev]);
+  RESET_WAIT_QUEUE (input_sleeper[dev], input_sleep_flag[dev]);
+
+  midi_in_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));
+
+  if (midi_in_buf[dev] == NULL)
+    {
+      printk ("midi: Can't allocate buffer\n");
+      midi_devs[dev]->close (dev);
+      RESTORE_INTR (flags);
+      return RET_ERROR (EIO);
+    }
+  midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
+
+  midi_out_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));
 
-  midibuf_busy = 1;
+  if (midi_out_buf[dev] == NULL)
+    {
+      printk ("midi: Can't allocate buffer\n");
+      midi_devs[dev]->close (dev);
+      KERNEL_FREE (midi_in_buf[dev]);
+      midi_in_buf[dev] = NULL;
+      RESTORE_INTR (flags);
+      return RET_ERROR (EIO);
+    }
+  midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
+  if (!open_devs)
+    ACTIVATE_TIMER (poll_timer, midi_poll, 1); /*
+                                                * Come back later
+                                                */
+  open_devs++;
+  RESTORE_INTR (flags);
 
-  return RET_ERROR (ENXIO);
+  return err;
 }
 
 void
 MIDIbuf_release (int dev, struct fileinfo *file)
 {
   int             mode;
+  unsigned long   flags;
 
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
 
-  midi_devs[mpu401_dev]->close (mpu401_dev);
-  midibuf_busy = 0;
+  DISABLE_INTR (flags);
+
+  /*
+ * Wait until the queue is empty
+ */
+
+  if (mode != OPEN_READ)
+    {
+      midi_devs[dev]->putc (dev, 0xfe);        /*
+                                                * Active sensing to shut the
+                                                * devices
+                                                */
+
+      while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
+            DATA_AVAIL (midi_out_buf[dev]))
+       DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0);  /*
+                                                                * Sync
+                                                                */
+
+      drain_midi_queue (dev);  /*
+                                * Ensure the output queues are empty
+                                */
+    }
+
+  midi_devs[dev]->close (dev);
+  KERNEL_FREE (midi_in_buf[dev]);
+  KERNEL_FREE (midi_out_buf[dev]);
+  midi_in_buf[dev] = NULL;
+  midi_out_buf[dev] = NULL;
+  open_devs--;
+  RESTORE_INTR (flags);
 }
 
 int
 MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
+  unsigned long   flags;
+  int             c, n, i;
+  unsigned char   tmp_data;
 
   dev = dev >> 4;
 
-  return count;
+  if (!count)
+    return 0;
+
+  DISABLE_INTR (flags);
+
+  c = 0;
+
+  while (c < count)
+    {
+      n = SPACE_AVAIL (midi_out_buf[dev]);
+
+      if (n == 0)              /*
+                                * No space just now. We have to sleep
+                                */
+       {
+         DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0);
+         if (PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]))
+           {
+             RESTORE_INTR (flags);
+             return RET_ERROR (EINTR);
+           }
+
+         n = SPACE_AVAIL (midi_out_buf[dev]);
+       }
+
+      if (n > (count - c))
+       n = count - c;
+
+      for (i = 0; i < n; i++)
+       {
+         COPY_FROM_USER (&tmp_data, buf, c, 1);
+         QUEUE_BYTE (midi_out_buf[dev], tmp_data);
+         c++;
+       }
+    }
+
+  RESTORE_INTR (flags);
+
+  return c;
 }
 
 
 int
 MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
+  int             n, c = 0;
+  unsigned long   flags;
+  unsigned char   tmp_data;
+
   dev = dev >> 4;
 
-  return RET_ERROR (EIO);
+  DISABLE_INTR (flags);
+
+  if (!DATA_AVAIL (midi_in_buf[dev]))  /*
+                                        * No data yet, wait
+                                        */
+    {
+      DO_SLEEP (input_sleeper[dev], input_sleep_flag[dev],
+               parms[dev].prech_timeout);
+      if (PROCESS_ABORTING (input_sleeper[dev], input_sleep_flag[dev]))
+       c = RET_ERROR (EINTR);  /*
+                                * The user is getting restless
+                                */
+    }
+
+  if (c == 0 && DATA_AVAIL (midi_in_buf[dev])) /*
+                                                * Got some bytes
+                                                */
+    {
+      n = DATA_AVAIL (midi_in_buf[dev]);
+      if (n > count)
+       n = count;
+      c = 0;
+
+      while (c < n)
+       {
+         REMOVE_BYTE (midi_in_buf[dev], tmp_data);
+         COPY_TO_USER (buf, c, &tmp_data, 1);
+         c++;
+       }
+    }
+
+  RESTORE_INTR (flags);
+
+  return c;
 }
 
 int
 MIDIbuf_ioctl (int dev, struct fileinfo *file,
               unsigned int cmd, unsigned int arg)
 {
+  int             val;
+
   dev = dev >> 4;
 
   switch (cmd)
     {
 
+    case SNDCTL_MIDI_PRETIME:
+      val = IOCTL_IN (arg);
+      if (val < 0)
+       val = 0;
+
+      val = (HZ * val) / 10;
+      parms[dev].prech_timeout = val;
+      return IOCTL_OUT (arg, val);
+      break;
+
     default:
-      return midi_devs[0]->ioctl (dev, cmd, arg);
+      return midi_devs[dev]->ioctl (dev, cmd, arg);
     }
 }
 
-void
-MIDIbuf_bytes_received (int dev, unsigned char *buf, int count)
+#ifdef ALLOW_SELECT
+int
+MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
 {
+  dev = dev >> 4;
+
+  switch (sel_type)
+    {
+    case SEL_IN:
+      if (!DATA_AVAIL (midi_in_buf[dev]))
+       {
+         input_sleep_flag[dev].mode = WK_SLEEP;
+         select_wait (&input_sleeper[dev], wait);
+         return 0;
+       }
+      return 1;
+      break;
+
+    case SEL_OUT:
+      if (SPACE_AVAIL (midi_out_buf[dev]))
+       {
+         midi_sleep_flag[dev].mode = WK_SLEEP;
+         select_wait (&midi_sleeper[dev], wait);
+         return 0;
+       }
+      return 1;
+      break;
+
+    case SEL_EX:
+      return 0;
+    }
+
+  return 0;
 }
 
+#endif /* ALLOW_SELECT */
+
 long
 MIDIbuf_init (long mem_start)
 {
index 68b461bb3c443f9305975d0e193d0cfe4959a659..40be06638ac56ca851c168ad260680f4f9532271 100644 (file)
@@ -3,8 +3,6 @@
  *
  * The low level driver for Roland MPU-401 compatible Midi cards.
  *
- * This version supports just the DUMB UART mode.
- *
  * Copyright by Hannu Savolainen 1993
  *
  * Redistribution and use in source and binary forms, with or without
  *
  */
 
+#define USE_SEQ_MACROS
+#define USE_SIMPLE_MACROS
+
 #include "sound_config.h"
 
 #ifdef CONFIGURE_SOUNDCARD
 
 #if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
 
-#define        DATAPORT   (mpu401_base)/* MPU-401 Data I/O Port on IBM */
-#define        COMDPORT   (mpu401_base+1)      /* MPU-401 Command Port on IBM */
-#define        STATPORT   (mpu401_base+1)      /* MPU-401 Status Port on IBM */
+static int      init_sequence[20];     /* NOTE! pos 0 = len, start pos 1. */
+static int      timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
+
+struct mpu_config
+  {
+    int             base;      /*
+                                * I/O base
+                                */
+    int             irq;
+    int             opened;    /*
+                                * Open mode
+                                */
+    int             devno;
+    int             synthno;
+    int             uart_mode;
+    int             initialized;
+    int             mode;
+#define MODE_MIDI      1
+#define MODE_SYNTH     2
+    unsigned char   version, revision;
+    unsigned int    capabilities;
+#define MPU_CAP_INTLG  0x10000000
+#define MPU_CAP_SYNC   0x00000010
+#define MPU_CAP_FSK    0x00000020
+#define MPU_CAP_CLS    0x00000040
+#define MPU_CAP_SMPTE  0x00000080
+#define MPU_CAP_2PORT  0x00000001
+    int             timer_flag;
+
+#define MBUF_MAX       10
+#define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \
+       {printk("MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;}
+    int             m_busy;
+    unsigned char   m_buf[MBUF_MAX];
+    int             m_ptr;
+    int             m_state;
+    int             m_left;
+    unsigned char   last_status;
+    void            (*inputintr) (int dev, unsigned char data);
+    unsigned short  controls[32];
+  };
+
+#define        DATAPORT(base)   (base)
+#define        COMDPORT(base)   (base+1)
+#define        STATPORT(base)   (base+1)
+
+#define mpu401_status(base)            INB(STATPORT(base))
+#define input_avail(base)              (!(mpu401_status(base)&INPUT_AVAIL))
+#define output_ready(base)             (!(mpu401_status(base)&OUTPUT_READY))
+#define write_command(base, cmd)               OUTB(cmd, COMDPORT(base))
+#define read_data(base)                INB(DATAPORT(base))
+
+#define write_data(base, byte) OUTB(byte, DATAPORT(base))
+
+#define        OUTPUT_READY    0x40
+#define        INPUT_AVAIL     0x80
+#define        MPU_ACK         0xF7
+#define        MPU_RESET       0xFF
+#define        UART_MODE_ON    0x3F
+
+static struct mpu_config dev_conf[MAX_MIDI_DEV] =
+{
+  {0}};
+
+static int      n_mpu_devs = 0;
+static int      irq2dev[16];
+
+static int      reset_mpu401 (struct mpu_config *devc);
+static void     set_uart_mode (int dev, struct mpu_config *devc, int arg);
+static void     mpu_timer_init (int midi_dev);
+static void     mpu_timer_interrupt (void);
+static void     timer_ext_event (struct mpu_config *devc, int event, int parm);
+
+static struct synth_info mpu_synth_info_proto =
+{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+
+static struct synth_info mpu_synth_info[MAX_MIDI_DEV];
+
+/*
+ * States for the input scanner
+ */
+
+#define ST_INIT                        0       /* Ready for timing byte or msg */
+#define ST_TIMED               1       /* Leading timing byte rcvd */
+#define ST_DATABYTE            2       /* Waiting for (nr_left) data bytes */
+
+#define ST_SYSMSG              100     /* System message (sysx etc). */
+#define ST_SYSEX               101     /* System exclusive msg */
+#define ST_MTC                 102     /* Midi Time Code (MTC) qframe msg */
+#define ST_SONGSEL             103     /* Song select */
+#define ST_SONGPOS             104     /* Song position pointer */
+
+static unsigned char len_tab[] =/* # of data bytes following a status
+                                        */
+{
+  2,                           /* 8x */
+  2,                           /* 9x */
+  2,                           /* Ax */
+  2,                           /* Bx */
+  1,                           /* Cx */
+  1,                           /* Dx */
+  2,                           /* Ex */
+  0                            /* Fx */
+};
+
+#define STORE(cmd) \
+if (devc->opened & OPEN_READ) \
+{ \
+  int len; \
+  unsigned char obuf[8]; \
+  cmd; \
+  seq_input_event(obuf, len); \
+}
+#define _seqbuf obuf
+#define _seqbufptr 0
+#define _SEQ_ADVBUF(x) len=x
+
+static void
+do_midi_msg (struct mpu_config *devc, unsigned char *msg, int mlen)
+{
+  switch (msg[0] & 0xf0)
+    {
+    case 0x90:
+      if (msg[2] != 0)
+       {
+         STORE (SEQ_START_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
+         break;
+       }
+      msg[2] = 64;
+
+    case 0x80:
+      STORE (SEQ_STOP_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xA0:
+      STORE (SEQ_KEY_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xB0:
+      /*
+ * Fix the controller value (combine MSB and LSB)
+ */
+      if (msg[1] < 64)
+       {
+         int             ctrl = msg[1];
+
+         if (ctrl < 32)
+           {
+             devc->controls[ctrl] = (msg[2] & 0x7f) << 7;
+           }
+         else
+           {
+             ctrl -= 32;
+             devc->controls[ctrl] =
+               (devc->controls[ctrl] & ~0x7f) | (msg[2] & 0x7f);
+           }
+         STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f,
+                             msg[1], devc->controls[ctrl]));
+       }
+      else
+       STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xC0:
+      STORE (SEQ_SET_PATCH (devc->synthno, msg[0] & 0x0f, msg[1]));
+      break;
+
+    case 0xD0:
+      STORE (SEQ_CHN_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1]));
+      break;
+
+    case 0xE0:
+      STORE (SEQ_BENDER (devc->synthno, msg[0] & 0x0f,
+                        (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
+      break;
+
+    default:
+      printk ("MPU: Unknown midi channel message %02x\n", msg[0]);
+    }
+}
+
+static int
+mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
+{
+  switch (devc->m_state)
+    {
+    case ST_INIT:
+      switch (midic)
+       {
+       case 0xf8:
+         /* Timer overflow */
+         break;
+
+       case 0xfc:
+         printk ("<all end>");
+         break;
+
+       case 0xfd:
+         if (devc->timer_flag)
+           mpu_timer_interrupt ();
+         break;
+
+       case 0xfe:
+         return MPU_ACK;
+         break;
+
+       case 0xf0:
+       case 0xf1:
+       case 0xf2:
+       case 0xf3:
+       case 0xf4:
+       case 0xf5:
+       case 0xf6:
+       case 0xf7:
+         printk ("<Trk data rq #%d>", midic & 0x0f);
+         break;
+
+       case 0xf9:
+         printk ("<conductor rq>");
+         break;
+
+       case 0xff:
+         devc->m_state = ST_SYSMSG;
+         break;
+
+       default:
+         if (midic <= 0xef)
+           {
+             /* printk("mpu time: %d ", midic); */
+             devc->m_state = ST_TIMED;
+           }
+         else
+           printk ("<MPU: Unknown event %02x> ", midic);
+       }
+      break;
+
+    case ST_TIMED:
+      {
+       int             msg = (midic & 0xf0) >> 4;
+
+       devc->m_state = ST_DATABYTE;
+       if (msg < 8)            /* Data byte */
+         {
+           /* printk("midi msg (running status) "); */
+           msg = (devc->last_status & 0xf0) >> 4;
+           msg -= 8;
+           devc->m_left = len_tab[msg] - 1;
+
+           devc->m_ptr = 2;
+           devc->m_buf[0] = devc->last_status;
+           devc->m_buf[1] = midic;
+
+           if (devc->m_left <= 0)
+             {
+               devc->m_state = ST_INIT;
+               do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+               devc->m_ptr = 0;
+             }
+         }
+       else if (msg == 0xf)    /* MPU MARK */
+         {
+           devc->m_state = ST_INIT;
+
+           switch (midic)
+             {
+             case 0xf8:
+               /* printk("NOP "); */
+               break;
+
+             case 0xf9:
+               /* printk("meas end "); */
+               break;
+
+             case 0xfc:
+               /* printk("data end "); */
+               break;
+
+             default:
+               printk ("Unknown MPU mark %02x\n", midic);
+             }
+         }
+       else
+         {
+           devc->last_status = midic;
+           /* printk("midi msg "); */
+           msg -= 8;
+           devc->m_left = len_tab[msg];
 
-#define mpu401_status()                INB(STATPORT)
-#define input_avail()          (!(mpu401_status()&INPUT_AVAIL))
-#define output_ready()         (!(mpu401_status()&OUTPUT_READY))
-#define mpu401_cmd(cmd)                OUTB(cmd, COMDPORT)
-#define mpu401_read()          INB(DATAPORT)
-#define mpu401_write(byte)     OUTB(byte, DATAPORT)
+           devc->m_ptr = 1;
+           devc->m_buf[0] = midic;
 
-#define        OUTPUT_READY    0x40    /* Mask for Data Read Redy Bit */
-#define        INPUT_AVAIL     0x80    /* Mask for Data Send Ready Bit */
-#define        MPU_ACK         0xFE    /* MPU-401 Acknowledge Response */
-#define        MPU_RESET       0xFF    /* MPU-401 Total Reset Command */
-#define        UART_MODE_ON    0x3F    /* MPU-401 "Dumb UART Mode" */
+           if (devc->m_left <= 0)
+             {
+               devc->m_state = ST_INIT;
+               do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+               devc->m_ptr = 0;
+             }
+         }
+      }
+      break;
 
-static int      mpu401_opened = 0;
-static int      mpu401_base = 0x330;
-static int      mpu401_irq;
-static int      mpu401_detected = 0;
-static int      my_dev;
+    case ST_SYSMSG:
+      switch (midic)
+       {
+       case 0xf0:
+         printk ("<SYX>");
+         devc->m_state = ST_SYSEX;
+         break;
 
-static int      reset_mpu401 (void);
-static void     (*midi_input_intr) (int dev, unsigned char data);
+       case 0xf1:
+         devc->m_state = ST_MTC;
+         break;
+
+       case 0xf2:
+         devc->m_state = ST_SONGPOS;
+         devc->m_ptr = 0;
+         break;
+
+       case 0xf3:
+         devc->m_state = ST_SONGSEL;
+         break;
+
+       case 0xf6:
+         /* printk("tune_request\n"); */
+         devc->m_state = ST_INIT;
+
+         /*
+ *    Real time messages
+ */
+       case 0xf8:
+         /* midi clock */
+         devc->m_state = ST_INIT;
+         timer_ext_event (devc, TMR_CLOCK, 0);
+         break;
+
+       case 0xfA:
+         devc->m_state = ST_INIT;
+         timer_ext_event (devc, TMR_START, 0);
+         break;
+
+       case 0xFB:
+         devc->m_state = ST_INIT;
+         timer_ext_event (devc, TMR_CONTINUE, 0);
+         break;
+
+       case 0xFC:
+         devc->m_state = ST_INIT;
+         timer_ext_event (devc, TMR_STOP, 0);
+         break;
+
+       case 0xFE:
+         /* active sensing */
+         devc->m_state = ST_INIT;
+         break;
+
+       case 0xff:
+         /* printk("midi hard reset"); */
+         devc->m_state = ST_INIT;
+         break;
+
+       default:
+         printk ("unknown MIDI sysmsg %0x\n", midic);
+         devc->m_state = ST_INIT;
+       }
+      break;
+
+    case ST_MTC:
+      devc->m_state = ST_INIT;
+      printk ("MTC frame %x02\n", midic);
+      break;
+
+    case ST_SYSEX:
+      if (midic == 0xf7)
+       {
+         printk ("<EOX>");
+         devc->m_state = ST_INIT;
+       }
+      else
+       printk ("%02x ", midic);
+      break;
+
+    case ST_SONGPOS:
+      BUFTEST (devc);
+      devc->m_buf[devc->m_ptr++] = midic;
+      if (devc->m_ptr == 2)
+       {
+         devc->m_state = ST_INIT;
+         devc->m_ptr = 0;
+         timer_ext_event (devc, TMR_SPP,
+                          ((devc->m_buf[1] & 0x7f) << 7) |
+                          (devc->m_buf[0] & 0x7f));
+       }
+      break;
+
+    case ST_DATABYTE:
+      BUFTEST (devc);
+      devc->m_buf[devc->m_ptr++] = midic;
+      if ((--devc->m_left) <= 0)
+       {
+         devc->m_state = ST_INIT;
+         do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+         devc->m_ptr = 0;
+       }
+      break;
+
+    default:
+      printk ("Bad state %d ", devc->m_state);
+      devc->m_state = ST_INIT;
+    }
+
+  return 1;
+}
+
+static void
+mpu401_input_loop (struct mpu_config *devc)
+{
+  unsigned long   flags;
+  int             busy;
+
+  DISABLE_INTR (flags);
+  busy = devc->m_busy;
+  devc->m_busy = 1;
+  RESTORE_INTR (flags);
+
+  if (busy)
+    return;
+
+  while (input_avail (devc->base))
+    {
+      unsigned char   c = read_data (devc->base);
+
+      if (devc->mode == MODE_SYNTH)
+       {
+         mpu_input_scanner (devc, c);
+       }
+      else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
+       devc->inputintr (devc->devno, c);
+    }
+
+  devc->m_busy = 0;
+}
 
 void
-mpuintr (int unit)
+mpuintr (int irq)
 {
-  while (input_avail ())
+  struct mpu_config *devc;
+  int             dev;
+
+#ifdef linux
+  sti ();
+#endif
+
+  if (irq < 1 || irq > 15)
     {
-      unsigned char   c = mpu401_read ();
+      printk ("MPU-401: Interrupt #%d?\n", irq);
+      return;
+    }
 
-      if (mpu401_opened & OPEN_READ)
-       midi_input_intr (my_dev, c);
+  dev = irq2dev[irq];
+  if (dev == -1)
+    {
+      printk ("MPU-401: Interrupt #%d?\n", irq);
+      return;
     }
+
+  devc = &dev_conf[dev];
+
+  if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
+    if (input_avail (devc->base))
+      mpu401_input_loop (devc);
+
 }
 
 static int
@@ -79,16 +515,32 @@ mpu401_open (int dev, int mode,
             void            (*output) (int dev)
 )
 {
-  if (mpu401_opened)
+  int             err;
+  struct mpu_config *devc;
+
+  if (dev < 0 || dev >= num_midis)
+    return RET_ERROR (ENXIO);
+
+  devc = &dev_conf[dev];
+
+  if (devc->opened)
     {
       printk ("MPU-401: Midi busy\n");
       return RET_ERROR (EBUSY);
     }
 
-  mpuintr (0);
+  irq2dev[devc->irq] = dev;
+  if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
+    return err;
 
-  midi_input_intr = input;
-  mpu401_opened = mode;
+  set_uart_mode (dev, devc, 1);
+  devc->mode = MODE_MIDI;
+  devc->synthno = 0;
+
+  mpu401_input_loop (devc);
+
+  devc->inputintr = input;
+  devc->opened = mode;
 
   return 0;
 }
@@ -96,7 +548,20 @@ mpu401_open (int dev, int mode,
 static void
 mpu401_close (int dev)
 {
-  mpu401_opened = 0;
+  struct mpu_config *devc;
+
+  devc = &dev_conf[dev];
+
+  if (devc->uart_mode)
+    reset_mpu401 (devc);       /*
+                                * This disables the UART mode
+                                */
+  devc->mode = 0;
+
+  snd_release_irq (devc->irq);
+  devc->inputintr = NULL;
+  irq2dev[devc->irq] = -1;
+  devc->opened = 0;
 }
 
 static int
@@ -105,38 +570,180 @@ mpu401_out (int dev, unsigned char midi_byte)
   int             timeout;
   unsigned long   flags;
 
+  struct mpu_config *devc;
+
+  devc = &dev_conf[dev];
+
+#if 0
   /*
    * Test for input since pending input seems to block the output.
    */
 
-  DISABLE_INTR (flags);
+  if (input_avail (devc->base))
+    mpu401_input_loop (devc);
+#endif
+  /*
+   * Sometimes it takes about 13000 loops before the output becomes ready
+   * (After reset). Normally it takes just about 10 loops.
+   */
 
-  if (input_avail ())
-    mpuintr (0);
+  for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--); /*
+                                                                                * Wait
+                                                                                */
 
+  DISABLE_INTR (flags);
+  if (!output_ready (devc->base))
+    {
+      printk ("MPU-401: Send data timeout\n");
+      RESTORE_INTR (flags);
+      return 0;
+    }
+
+  write_data (devc->base, midi_byte);
   RESTORE_INTR (flags);
+  return 1;
+}
+
+static int
+mpu401_command (int dev, mpu_command_rec * cmd)
+{
+  int             i, timeout, ok;
+  int             ret = 0;
+  unsigned long   flags;
+  struct mpu_config *devc;
+
+  devc = &dev_conf[dev];
+
+  if (devc->uart_mode)         /*
+                                * Not possible in UART mode
+                                */
+    {
+      printk ("MPU-401 commands not possible in the UART mode\n");
+      return RET_ERROR (EINVAL);
+    }
 
   /*
-   * Sometimes it takes about 13000 loops before the output becomes ready
+   * Test for input since pending input seems to block the output.
+   */
+  if (input_avail (devc->base))
+    mpu401_input_loop (devc);
+
+  /*
+   * Sometimes it takes about 30000 loops before the output becomes ready
    * (After reset). Normally it takes just about 10 loops.
    */
 
-  for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);   /* Wait */
+  for (timeout = 500000; timeout > 0 && !output_ready (devc->base); timeout--);
 
-  if (!output_ready ())
+  DISABLE_INTR (flags);
+  if (!output_ready (devc->base))
     {
-      printk ("MPU-401: Timeout\n");
-      return 0;
+      printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
+      RESTORE_INTR (flags);
+      return RET_ERROR (EIO);
     }
 
-  mpu401_write (midi_byte);
-  return 1;
+  write_command (devc->base, cmd->cmd);
+  ok = 0;
+  for (timeout = 500000; timeout > 0 && !ok; timeout--)
+    if (input_avail (devc->base))
+      if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK)
+       ok = 1;
+
+  if (!ok)
+    {
+      RESTORE_INTR (flags);
+      printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd);
+      return RET_ERROR (EIO);
+    }
+
+  if (cmd->nr_args)
+    for (i = 0; i < cmd->nr_args; i++)
+      {
+       for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--);
+
+       if (!mpu401_out (dev, cmd->data[i]))
+         {
+           RESTORE_INTR (flags);
+           printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
+           return RET_ERROR (EIO);
+         }
+      }
+
+  ret = 0;
+  cmd->data[0] = 0;
+
+  if (cmd->nr_returns)
+    for (i = 0; i < cmd->nr_returns; i++)
+      {
+       ok = 0;
+       for (timeout = 5000; timeout > 0 && !ok; timeout--)
+         if (input_avail (devc->base))
+           {
+             cmd->data[i] = read_data (devc->base);
+             ok = 1;
+           }
+
+       if (!ok)
+         {
+           RESTORE_INTR (flags);
+           printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd);
+           return RET_ERROR (EIO);
+         }
+      }
+
+  RESTORE_INTR (flags);
+
+  return ret;
 }
 
 static int
-mpu401_command (int dev, unsigned char midi_byte)
+exec_cmd (int dev, int cmd, int data)
 {
-  return 1;
+  int             ret;
+
+  static mpu_command_rec rec;
+
+  rec.cmd = cmd & 0xff;
+  rec.nr_args = ((cmd & 0xf0) == 0xE0);
+  rec.nr_returns = ((cmd & 0xf0) == 0xA0);
+  rec.data[0] = data & 0xff;
+
+  if ((ret = mpu401_command (dev, &rec)) < 0)
+    return ret;
+  return (unsigned char) rec.data[0];
+}
+
+static int
+mpu401_prefix_cmd (int dev, unsigned char status)
+{
+  struct mpu_config *devc = &dev_conf[dev];
+
+  if (devc->uart_mode)
+    return 1;
+
+  if (status < 0xf0)
+    {
+      if (exec_cmd (dev, 0xD0, 0) < 0)
+       return 0;
+
+      return 1;
+    }
+
+  switch (status)
+    {
+    case 0xF0:
+      if (exec_cmd (dev, 0xDF, 0) < 0)
+       return 0;
+
+      return 1;
+      break;
+
+    default:
+      return 0;
+    }
+
+  return 0;
 }
 
 static int
@@ -154,7 +761,45 @@ mpu401_end_read (int dev)
 static int
 mpu401_ioctl (int dev, unsigned cmd, unsigned arg)
 {
-  return RET_ERROR (EINVAL);
+  struct mpu_config *devc;
+
+  devc = &dev_conf[dev];
+
+  switch (cmd)
+    {
+    case 1:
+      IOCTL_FROM_USER ((char *) &init_sequence, (char *) arg, 0, sizeof (init_sequence));
+      return 0;
+      break;
+
+    case SNDCTL_MIDI_MPUMODE:
+      if (devc->version == 0)
+       {
+         printk ("MPU-401: Intelligent mode not supported by the HW\n");
+         return RET_ERROR (EINVAL);
+       }
+      set_uart_mode (dev, devc, !IOCTL_IN (arg));
+      return 0;
+      break;
+
+    case SNDCTL_MIDI_MPUCMD:
+      {
+       int             ret;
+       mpu_command_rec rec;
+
+       IOCTL_FROM_USER ((char *) &rec, (char *) arg, 0, sizeof (rec));
+
+       if ((ret = mpu401_command (dev, &rec)) < 0)
+         return ret;
+
+       IOCTL_TO_USER ((char *) arg, 0, (char *) &rec, sizeof (rec));
+       return 0;
+      }
+      break;
+
+    default:
+      return RET_ERROR (EINVAL);
+    }
 }
 
 static void
@@ -165,12 +810,135 @@ mpu401_kick (int dev)
 static int
 mpu401_buffer_status (int dev)
 {
-  return 0;                    /* No data in buffers */
+  return 0;                    /*
+                                * No data in buffers
+                                */
+}
+
+static int
+mpu_synth_ioctl (int dev,
+                unsigned int cmd, unsigned int arg)
+{
+  int             midi_dev;
+  struct mpu_config *devc;
+
+  midi_dev = synth_devs[dev]->midi_dev;
+
+  if (midi_dev < 0 || midi_dev > num_midis)
+    return RET_ERROR (ENXIO);
+
+  devc = &dev_conf[midi_dev];
+
+  switch (cmd)
+    {
+
+    case SNDCTL_SYNTH_INFO:
+      IOCTL_TO_USER ((char *) arg, 0, &mpu_synth_info[midi_dev],
+                    sizeof (struct synth_info));
+
+      return 0;
+      break;
+
+    case SNDCTL_SYNTH_MEMAVL:
+      return 0x7fffffff;
+      break;
+
+    default:
+      return RET_ERROR (EINVAL);
+    }
+}
+
+static int
+mpu_synth_open (int dev, int mode)
+{
+  int             midi_dev, err;
+  struct mpu_config *devc;
+
+  midi_dev = synth_devs[dev]->midi_dev;
+
+  if (midi_dev < 0 || midi_dev > num_midis)
+    return RET_ERROR (ENXIO);
+
+  devc = &dev_conf[midi_dev];
+
+  if (devc->opened)
+    {
+      printk ("MPU-401: Midi busy\n");
+      return RET_ERROR (EBUSY);
+    }
+
+  devc->opened = mode;
+  devc->mode = MODE_SYNTH;
+  devc->synthno = dev;
+
+  devc->inputintr = NULL;
+  irq2dev[devc->irq] = midi_dev;
+  if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
+    return err;
+
+  reset_mpu401 (devc);
+
+  if (mode & OPEN_READ)
+    {
+      exec_cmd (midi_dev, 0x34, 0);    /* Return timing bytes in stop mode */
+      exec_cmd (midi_dev, 0x8B, 0);    /* Enable data in stop mode */
+    }
+
+  return 0;
+}
+
+static void
+mpu_synth_close (int dev)
+{
+  int             midi_dev;
+  struct mpu_config *devc;
+
+  midi_dev = synth_devs[dev]->midi_dev;
+
+  devc = &dev_conf[midi_dev];
+  exec_cmd (midi_dev, 0x15, 0);        /* Stop recording, playback and MIDI */
+  exec_cmd (midi_dev, 0x8a, 0);        /* Disable data in stopped mode */
+
+  devc->opened = 0;
+  devc->mode = 0;
+  snd_release_irq (devc->irq);
+  devc->inputintr = NULL;
+  irq2dev[devc->irq] = -1;
 }
 
-static struct midi_operations mpu401_operations =
+#define MIDI_SYNTH_NAME        "MPU-401 UART Midi"
+#define MIDI_SYNTH_CAPS        SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
+static struct synth_operations mpu401_synth_proto =
 {
-  {"MPU-401", 0, 0, SNDCARD_MPU401},
+  NULL,
+  0,
+  SYNTH_TYPE_MIDI,
+  0,
+  mpu_synth_open,
+  mpu_synth_close,
+  mpu_synth_ioctl,
+  midi_synth_kill_note,
+  midi_synth_start_note,
+  midi_synth_set_instr,
+  midi_synth_reset,
+  midi_synth_hw_control,
+  midi_synth_load_patch,
+  midi_synth_aftertouch,
+  midi_synth_controller,
+  midi_synth_panning,
+  NULL,
+  midi_synth_patchmgr,
+  midi_synth_bender
+};
+
+static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV];
+
+static struct midi_operations mpu401_midi_proto =
+{
+  {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
+  NULL,
   mpu401_open,
   mpu401_close,
   mpu401_ioctl,
@@ -178,101 +946,777 @@ static struct midi_operations mpu401_operations =
   mpu401_start_read,
   mpu401_end_read,
   mpu401_kick,
-  mpu401_command,
-  mpu401_buffer_status
+  NULL,
+  mpu401_buffer_status,
+  mpu401_prefix_cmd
 };
 
+static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
+
+static void
+mpu401_chk_version (struct mpu_config *devc)
+{
+  int             tmp;
+
+  devc->version = devc->revision = 0;
+
+  if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0)
+    return;
+  devc->version = tmp;
+
+  if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0)
+    return;
+  devc->revision = tmp;
+}
 
 long
 attach_mpu401 (long mem_start, struct address_info *hw_config)
 {
-  int             ok, timeout;
+  int             i;
   unsigned long   flags;
+  char            revision_char;
 
-  mpu401_base = hw_config->io_base;
-  mpu401_irq = hw_config->irq;
+  struct mpu_config *devc;
 
-  if (!mpu401_detected)
-    return RET_ERROR (EIO);
+  for (i = 0; i < 16; i++)
+    irq2dev[i] = -1;
 
-  DISABLE_INTR (flags);
-  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);   /* Wait */
-  mpu401_cmd (UART_MODE_ON);
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("MPU-401: Too many midi devices detected\n");
+      return mem_start;
+    }
 
-  ok = 0;
-  for (timeout = 50000; timeout > 0 && !ok; timeout--)
-    if (input_avail ())
-      if (mpu401_read () == MPU_ACK)
-       ok = 1;
+  devc = &dev_conf[num_midis];
+
+  devc->base = hw_config->io_base;
+  devc->irq = hw_config->irq;
+  devc->opened = 0;
+  devc->uart_mode = 0;
+  devc->initialized = 0;
+  devc->version = 0;
+  devc->revision = 0;
+  devc->capabilities = 0;
+  devc->timer_flag = 0;
+  devc->m_busy = 0;
+  devc->m_state = ST_INIT;
 
+  for (i = 0; i < 32; i++)
+    devc->controls[i] = 0x2000;
+
+  if (!reset_mpu401 (devc))
+    return mem_start;
+
+  DISABLE_INTR (flags);
+  mpu401_chk_version (devc);
+  if (devc->version == 0)
+    mpu401_chk_version (devc);
   RESTORE_INTR (flags);
 
-  printk (" <Roland MPU-401>");
+  if (devc->version == 0)
+    {
+      memcpy ((char *) &mpu401_synth_operations[num_midis],
+             (char *) &std_midi_synth,
+             sizeof (struct synth_operations));
+    }
+  else
+    {
+      devc->capabilities |= MPU_CAP_INTLG;     /* Supports intelligent mode */
+      memcpy ((char *) &mpu401_synth_operations[num_midis],
+             (char *) &mpu401_synth_proto,
+             sizeof (struct synth_operations));
+    }
+
+  memcpy ((char *) &mpu401_midi_operations[num_midis],
+         (char *) &mpu401_midi_proto,
+         sizeof (struct midi_operations));
+
+  mpu401_midi_operations[num_midis].converter =
+    &mpu401_synth_operations[num_midis];
+
+  memcpy ((char *) &mpu_synth_info[num_midis],
+         (char *) &mpu_synth_info_proto,
+         sizeof (struct synth_info));
+
+  n_mpu_devs++;
+
+  if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */
+    {
+      int             ports = (devc->revision & 0x08) ? 32 : 16;
+
+      devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE |
+       MPU_CAP_CLS | MPU_CAP_2PORT;
+
+      revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
+      printk (" <MQX-%d%c MIDI Interface>",
+             ports,
+             revision_char);
+#ifndef SCO
+      sprintf (mpu_synth_info[num_midis].name,
+              "MQX-%d%c MIDI Interface #%d",
+              ports,
+              revision_char,
+              n_mpu_devs);
+#endif
+    }
+  else
+    {
 
-  my_dev = num_midis;
-  mpu401_dev = num_midis;
-  midi_devs[num_midis++] = &mpu401_operations;
+      revision_char = devc->revision ? devc->revision + '@' : ' ';
+      if (devc->revision > ('Z' - '@'))
+       revision_char = '+';
+
+      devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
+
+      printk (" <MPU-401 MIDI Interface %d.%d%c>",
+             (devc->version & 0xf0) >> 4,
+             devc->version & 0x0f,
+             revision_char);
+#ifndef SCO
+      sprintf (mpu_synth_info[num_midis].name,
+              "MPU-401 %d.%d%c Midi interface #%d",
+              (devc->version & 0xf0) >> 4,
+              devc->version & 0x0f,
+              revision_char,
+              n_mpu_devs);
+#endif
+    }
+
+#ifndef SCO
+  strcpy (mpu401_midi_operations[num_midis].info.name,
+         mpu_synth_info[num_midis].name);
+#endif
+
+  mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis;
+  mpu401_synth_operations[devc->devno].info =
+    &mpu_synth_info[devc->devno];
+
+  if (devc->capabilities & MPU_CAP_INTLG)      /* Has timer */
+    mpu_timer_init (num_midis);
+
+  midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno];
   return mem_start;
 }
 
 static int
-reset_mpu401 (void)
+reset_mpu401 (struct mpu_config *devc)
 {
   unsigned long   flags;
   int             ok, timeout, n;
+  int             timeout_limit;
 
   /*
    * Send the RESET command. Try again if no success at the first time.
+   * (If the device is in the UART mode, it will not ack the reset cmd).
    */
 
   ok = 0;
 
-  DISABLE_INTR (flags);
+  timeout_limit = devc->initialized ? 30000 : 100000;
+  devc->initialized = 1;
 
   for (n = 0; n < 2 && !ok; n++)
     {
-      for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);       /* Wait */
-      mpu401_cmd (MPU_RESET);  /* Send MPU-401 RESET Command */
+      for (timeout = timeout_limit; timeout > 0 && !ok; timeout--)
+       ok = output_ready (devc->base);
+
+      write_command (devc->base, MPU_RESET);   /*
+                                                * Send MPU-401 RESET Command
+                                                */
 
       /*
        * Wait at least 25 msec. This method is not accurate so let's make the
        * loop bit longer. Cannot sleep since this is called during boot.
        */
 
-      for (timeout = 50000; timeout > 0 && !ok; timeout--)
-       if (input_avail ())
-         if (mpu401_read () == MPU_ACK)
-           ok = 1;
+      for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--)
+       {
+         DISABLE_INTR (flags);
+         if (input_avail (devc->base))
+           if (read_data (devc->base) == MPU_ACK)
+             ok = 1;
+         RESTORE_INTR (flags);
+       }
 
     }
 
-  mpu401_opened = 0;
-  if (ok)
-    mpuintr (0);               /* Flush input before enabling interrupts */
-
-  RESTORE_INTR (flags);
+  devc->m_state = ST_INIT;
+  devc->m_ptr = 0;
+  devc->m_left = 0;
+  devc->last_status = 0;
+  devc->uart_mode = 0;
 
   return ok;
 }
 
+static void
+set_uart_mode (int dev, struct mpu_config *devc, int arg)
+{
+
+  if (!arg && devc->version == 0)
+    return;
+
+  if ((devc->uart_mode == 0) == (arg == 0))
+    return;                    /* Already set */
+
+  reset_mpu401 (devc);         /* This exits the uart mode */
+
+  if (arg)
+    {
+      if (exec_cmd (dev, UART_MODE_ON, 0) < 0)
+       {
+         printk ("MPU%d: Can't enter UART mode\n", devc->devno);
+         devc->uart_mode = 0;
+         return;
+       }
+    }
+  devc->uart_mode = arg;
+
+}
 
 int
 probe_mpu401 (struct address_info *hw_config)
 {
   int             ok = 0;
+  struct mpu_config tmp_devc;
+
+  tmp_devc.base = hw_config->io_base;
+  tmp_devc.irq = hw_config->irq;
+  tmp_devc.initialized = 0;
+
+  ok = reset_mpu401 (&tmp_devc);
+
+  return ok;
+}
+
+/*****************************************************
+ *      Timer stuff
+ ****************************************************/
 
-  mpu401_base = hw_config->io_base;
-  mpu401_irq = hw_config->irq;
+#if !defined(EXCLUDE_SEQUENCER)
 
-  if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0)
+static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0;
+static volatile int curr_tempo, curr_timebase, hw_timebase;
+static int      max_timebase = 8;      /* 8*24=192 ppqn */
+static volatile unsigned long next_event_time;
+static volatile unsigned long curr_ticks, curr_clocks;
+static unsigned long prev_event_time;
+static int      metronome_mode;
+
+static unsigned long
+clocks2ticks (unsigned long clocks)
+{
+  /*
+ * The MPU-401 supports just a limited set of possible timebase values.
+ * Since the applications require more choices, the driver has to
+ * program the HW to do it's best and to convert between the HW and
+ * actual timebases.
+ */
+
+  return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase;
+}
+
+static void
+set_timebase (int midi_dev, int val)
+{
+  int             hw_val;
+
+  if (val < 48)
+    val = 48;
+  if (val > 1000)
+    val = 1000;
+
+  hw_val = val;
+  hw_val = (hw_val + 23) / 24;
+  if (hw_val > max_timebase)
+    hw_val = max_timebase;
+
+  if (exec_cmd (midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0)
+    {
+      printk ("MPU: Can't set HW timebase to %d\n", hw_val * 24);
+      return;
+    }
+  hw_timebase = hw_val * 24;
+  curr_timebase = val;
+
+}
+
+static void
+tmr_reset (void)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  next_event_time = 0xffffffff;
+  prev_event_time = 0;
+  curr_ticks = curr_clocks = 0;
+  RESTORE_INTR (flags);
+}
+
+static void
+set_timer_mode (int midi_dev)
+{
+  if (timer_mode & TMR_MODE_CLS)
+    exec_cmd (midi_dev, 0x3c, 0);      /* Use CLS sync */
+  else if (timer_mode & TMR_MODE_SMPTE)
+    exec_cmd (midi_dev, 0x3d, 0);      /* Use SMPTE sync */
+
+  if (timer_mode & TMR_INTERNAL)
+    {
+      exec_cmd (midi_dev, 0x80, 0);    /* Use MIDI sync */
+    }
+  else
+    {
+      if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))
+       {
+         exec_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */
+         exec_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */
+       }
+      else if (timer_mode & TMR_MODE_FSK)
+       exec_cmd (midi_dev, 0x81, 0);   /* Use FSK sync */
+    }
+}
+
+static void
+stop_metronome (int midi_dev)
+{
+  exec_cmd (midi_dev, 0x84, 0);        /* Disable metronome */
+}
+
+static void
+setup_metronome (int midi_dev)
+{
+  int             numerator, denominator;
+  int             clks_per_click, num_32nds_per_beat;
+  int             beats_per_measure;
+
+  numerator = ((unsigned) metronome_mode >> 24) & 0xff;
+  denominator = ((unsigned) metronome_mode >> 16) & 0xff;
+  clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff;
+  num_32nds_per_beat = (unsigned) metronome_mode & 0xff;
+  beats_per_measure = (numerator * 4) >> denominator;
+
+  if (!metronome_mode)
+    exec_cmd (midi_dev, 0x84, 0);      /* Disable metronome */
+  else
+    {
+      exec_cmd (midi_dev, 0xE4, clks_per_click);
+      exec_cmd (midi_dev, 0xE6, beats_per_measure);
+      exec_cmd (midi_dev, 0x83, 0);    /* Enable metronome without accents */
+    }
+}
+
+static int
+start_timer (int midi_dev)
+{
+  tmr_reset ();
+  set_timer_mode (midi_dev);
+
+  if (tmr_running)
+    return TIMER_NOT_ARMED;    /* Already running */
+
+  if (timer_mode & TMR_INTERNAL)
+    {
+      exec_cmd (midi_dev, 0x02, 0);    /* Send MIDI start */
+      tmr_running = 1;
+      return TIMER_NOT_ARMED;
+    }
+  else
+    {
+      exec_cmd (midi_dev, 0x35, 0);    /* Enable mode messages to PC */
+      exec_cmd (midi_dev, 0x38, 0);    /* Enable sys common messages to PC */
+      exec_cmd (midi_dev, 0x39, 0);    /* Enable real time messages to PC */
+      exec_cmd (midi_dev, 0x97, 0);    /* Enable system exclusive messages to PC */
+    }
+
+  return TIMER_ARMED;
+}
+
+static int
+mpu_timer_open (int dev, int mode)
+{
+  int             midi_dev = sound_timer_devs[dev]->devlink;
+
+  if (timer_open)
+    return RET_ERROR (EBUSY);
+
+  tmr_reset ();
+  curr_tempo = 50;
+  exec_cmd (midi_dev, 0xE0, 50);
+  curr_timebase = hw_timebase = 120;
+  set_timebase (midi_dev, 120);
+  timer_open = 1;
+  metronome_mode = 0;
+  set_timer_mode (midi_dev);
+
+  exec_cmd (midi_dev, 0xe7, 0x04);     /* Send all clocks to host */
+  exec_cmd (midi_dev, 0x95, 0);        /* Enable clock to host */
+
+  return 0;
+}
+
+static void
+mpu_timer_close (int dev)
+{
+  int             midi_dev = sound_timer_devs[dev]->devlink;
+
+  timer_open = tmr_running = 0;
+  exec_cmd (midi_dev, 0x15, 0);        /* Stop all */
+  exec_cmd (midi_dev, 0x94, 0);        /* Disable clock to host */
+  exec_cmd (midi_dev, 0x8c, 0);        /* Disable measure end messages to host */
+  stop_metronome (midi_dev);
+}
+
+static int
+mpu_timer_event (int dev, unsigned char *event)
+{
+  unsigned char   command = event[1];
+  unsigned long   parm = *(unsigned int *) &event[4];
+  int             midi_dev = sound_timer_devs[dev]->devlink;
+
+  switch (command)
+    {
+    case TMR_WAIT_REL:
+      parm += prev_event_time;
+    case TMR_WAIT_ABS:
+      if (parm > 0)
+       {
+         long            time;
+
+         if (parm <= curr_ticks)       /* It's the time */
+           return TIMER_NOT_ARMED;
+
+         time = parm;
+         next_event_time = prev_event_time = time;
+
+         return TIMER_ARMED;
+       }
+      break;
+
+    case TMR_START:
+      if (tmr_running)
+       break;
+      return start_timer (midi_dev);
+      break;
+
+    case TMR_STOP:
+      exec_cmd (midi_dev, 0x01, 0);    /* Send MIDI stop */
+      stop_metronome (midi_dev);
+      tmr_running = 0;
+      break;
+
+    case TMR_CONTINUE:
+      if (tmr_running)
+       break;
+      exec_cmd (midi_dev, 0x03, 0);    /* Send MIDI continue */
+      setup_metronome (midi_dev);
+      tmr_running = 1;
+      break;
+
+    case TMR_TEMPO:
+      if (parm)
+       {
+         if (parm < 8)
+           parm = 8;
+         if (parm > 250)
+           parm = 250;
+
+         if (exec_cmd (midi_dev, 0xE0, parm) < 0)
+           printk ("MPU: Can't set tempo to %d\n", (int) parm);
+         curr_tempo = parm;
+       }
+      break;
+
+    case TMR_ECHO:
+      seq_copy_to_input (event, 8);
+      break;
+
+    case TMR_TIMESIG:
+      if (metronome_mode)      /* Metronome enabled */
+       {
+         metronome_mode = parm;
+         setup_metronome (midi_dev);
+       }
+      break;
+
+    default:;
+    }
+
+  return TIMER_NOT_ARMED;
+}
+
+static unsigned long
+mpu_timer_get_time (int dev)
+{
+  if (!timer_open)
     return 0;
 
-  ok = reset_mpu401 ();
+  return curr_ticks;
+}
 
-  mpu401_detected = ok;
-  return ok;
+static int
+mpu_timer_ioctl (int dev,
+                unsigned int command, unsigned int arg)
+{
+  int             midi_dev = sound_timer_devs[dev]->devlink;
+
+  switch (command)
+    {
+    case SNDCTL_TMR_SOURCE:
+      {
+       int             parm = IOCTL_IN (arg) & timer_caps;
+
+       if (parm != 0)
+         {
+           timer_mode = parm;
+
+           if (timer_mode & TMR_MODE_CLS)
+             exec_cmd (midi_dev, 0x3c, 0);     /* Use CLS sync */
+           else if (timer_mode & TMR_MODE_SMPTE)
+             exec_cmd (midi_dev, 0x3d, 0);     /* Use SMPTE sync */
+         }
+
+       return IOCTL_OUT (arg, timer_mode);
+      }
+      break;
+
+    case SNDCTL_TMR_START:
+      if (tmr_running)
+       return 0;
+      start_timer (midi_dev);
+      return 0;
+      break;
+
+    case SNDCTL_TMR_STOP:
+      tmr_running = 0;
+      exec_cmd (midi_dev, 0x01, 0);    /* Send MIDI stop */
+      stop_metronome (midi_dev);
+      return 0;
+      break;
+
+    case SNDCTL_TMR_CONTINUE:
+      if (tmr_running)
+       return 0;
+      tmr_running = 1;
+      exec_cmd (midi_dev, 0x03, 0);    /* Send MIDI continue */
+      return 0;
+      break;
+
+    case SNDCTL_TMR_TIMEBASE:
+      {
+       int             val = IOCTL_IN (arg);
+
+       if (val)
+         set_timebase (midi_dev, val);
+
+       return IOCTL_OUT (arg, curr_timebase);
+      }
+      break;
+
+    case SNDCTL_TMR_TEMPO:
+      {
+       int             val = IOCTL_IN (arg);
+       int             ret;
+
+       if (val)
+         {
+           if (val < 8)
+             val = 8;
+           if (val > 250)
+             val = 250;
+           if ((ret = exec_cmd (midi_dev, 0xE0, val)) < 0)
+             {
+               printk ("MPU: Can't set tempo to %d\n", (int) val);
+               return ret;
+             }
+
+           curr_tempo = val;
+         }
+
+       return IOCTL_OUT (arg, curr_tempo);
+      }
+      break;
+
+    case SNDCTL_SEQ_CTRLRATE:
+      if (IOCTL_IN (arg) != 0) /* Can't change */
+       return RET_ERROR (EINVAL);
+
+      return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+      break;
+
+    case SNDCTL_TMR_METRONOME:
+      metronome_mode = IOCTL_IN (arg);
+      setup_metronome (midi_dev);
+      return 0;
+      break;
+
+    default:
+    }
+
+  return RET_ERROR (EINVAL);
+}
+
+static void
+mpu_timer_arm (int dev, long time)
+{
+  if (time < 0)
+    time = curr_ticks + 1;
+  else if (time <= curr_ticks) /* It's the time */
+    return;
+
+  next_event_time = prev_event_time = time;
+
+  return;
+}
+
+static struct sound_timer_operations mpu_timer =
+{
+  {"MPU-401 Timer", 0},
+  10,                          /* Priority */
+  0,                           /* Local device link */
+  mpu_timer_open,
+  mpu_timer_close,
+  mpu_timer_event,
+  mpu_timer_get_time,
+  mpu_timer_ioctl,
+  mpu_timer_arm
+};
+
+static void
+mpu_timer_interrupt (void)
+{
+
+  if (!timer_open)
+    return;
+
+  if (!tmr_running)
+    return;
+
+  curr_clocks++;
+  curr_ticks = clocks2ticks (curr_clocks);
+
+  if (curr_ticks >= next_event_time)
+    {
+      next_event_time = 0xffffffff;
+      sequencer_timer ();
+    }
+}
+
+static void
+timer_ext_event (struct mpu_config *devc, int event, int parm)
+{
+  int             midi_dev = devc->devno;
+
+  if (!devc->timer_flag)
+    return;
+
+  switch (event)
+    {
+    case TMR_CLOCK:
+      printk ("<MIDI clk>");
+      break;
+
+    case TMR_START:
+      printk ("Ext MIDI start\n");
+      if (!tmr_running)
+       if (timer_mode & TMR_EXTERNAL)
+         {
+           tmr_running = 1;
+           setup_metronome (midi_dev);
+           next_event_time = 0;
+           STORE (SEQ_START_TIMER ());
+         }
+      break;
+
+    case TMR_STOP:
+      printk ("Ext MIDI stop\n");
+      if (timer_mode & TMR_EXTERNAL)
+       {
+         tmr_running = 0;
+         stop_metronome (midi_dev);
+         STORE (SEQ_STOP_TIMER ());
+       }
+      break;
+
+    case TMR_CONTINUE:
+      printk ("Ext MIDI continue\n");
+      if (timer_mode & TMR_EXTERNAL)
+       {
+         tmr_running = 1;
+         setup_metronome (midi_dev);
+         STORE (SEQ_CONTINUE_TIMER ());
+       }
+      break;
+
+    case TMR_SPP:
+      printk ("Songpos: %d\n", parm);
+      if (timer_mode & TMR_EXTERNAL)
+       {
+         STORE (SEQ_SONGPOS (parm));
+       }
+      break;
+    }
 }
 
+static void
+mpu_timer_init (int midi_dev)
+{
+  struct mpu_config *devc;
+  int             n;
+
+  devc = &dev_conf[midi_dev];
+
+  if (timer_initialized)
+    return;                    /* There is already a similar timer */
+
+  timer_initialized = 1;
+
+  mpu_timer.devlink = midi_dev;
+  dev_conf[midi_dev].timer_flag = 1;
+
+#if 1
+  if (num_sound_timers >= MAX_TIMER_DEV)
+    n = 0;                     /* Overwrite the system timer */
+  else
+    n = num_sound_timers++;
+#else
+  n = 0;
+#endif
+  sound_timer_devs[n] = &mpu_timer;
+
+  if (devc->version < 0x20)    /* Original MPU-401 */
+    timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI;
+  else
+    {
+      /*
+         * The version number 2.0 is used (at least) by the
+         * MusicQuest cards and the Roland Super-MPU.
+         *
+         * MusicQuest has given a special meaning to the bits of the
+         * revision number. The Super-MPU returns 0.
+       */
+
+      if (devc->revision)
+       timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI;
+
+      if (devc->revision & 0x02)
+       timer_caps |= TMR_MODE_CLS;
+
+#if 0
+      if (devc->revision & 0x04)
+       timer_caps |= TMR_MODE_SMPTE;
+#endif
+
+      if (devc->revision & 0x40)
+       max_timebase = 10;      /* Has the 216 and 240 ppqn modes */
+    }
+
+  timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps;
+
+}
+
+#endif
+
 #endif
 
 #endif
index 65e783432c4c6d2d5b82750cb22de8ddc2316b3b..0acd0c6203a0e8cd3773faf37bd0b4bdd3a90ed3 100644 (file)
  *
  */
 
-/* Major improvements to the FM handling 30AUG92 by Rob Hooft, */
-/* hooft@chem.ruu.nl */
+/*
+ * Major improvements to the FM handling 30AUG92 by Rob Hooft,
+ */
+/*
+ * hooft@chem.ruu.nl
+ */
 
 #include "sound_config.h"
 
@@ -37,8 +41,9 @@
 #include "opl3.h"
 
 #define MAX_VOICE      18
-#define OFFS_4OP       11      /* Definitions for the operators OP3 and OP4
-                                  * begin here */
+#define OFFS_4OP       11      /*
+                                  * * * Definitions for the operators OP3 and
+                                  * * OP4 * * begin here   */
 
 static int      opl3_enabled = 0;
 static int      left_address = 0x388, right_address = 0x388, both_address = 0;
@@ -58,24 +63,30 @@ struct voice_info
   };
 
 static struct voice_info voices[MAX_VOICE];
+static struct voice_alloc_info *voice_alloc;
+static struct channel_info *chn_info;
 
 static struct sbi_instrument *instrmap;
 static struct sbi_instrument *active_instrument[MAX_VOICE] =
 {NULL};
 
 static struct synth_info fm_info =
-{"AdLib", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0};
+{"OPL-2", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0};
 
 static int      already_initialized = 0;
 
 static int      opl3_ok = 0;
 static int      opl3_busy = 0;
-static int      fm_model = 0;  /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2       */
+static int      fm_model = 0;  /*
+
+
+                                * *  * * 0=no fm, 1=mono, 2=SB Pro 1, 3=SB
+                                * Pro 2 * *    */
 
 static int      store_instr (int instr_no, struct sbi_instrument *instr);
 static void     freq_to_fnum (int freq, int *block, int *fnum);
 static void     opl3_command (int io_addr, unsigned int addr, unsigned int val);
-static int      opl3_kill_note (int dev, int voice, int velocity);
+static int      opl3_kill_note (int dev, int voice, int note, int velocity);
 static unsigned char connection_mask = 0x00;
 
 void
@@ -99,9 +110,9 @@ enter_4op_mode (void)
   static int      voices_4op[MAX_VOICE] =
   {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17};
 
-  connection_mask = 0x3f;
-  opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f);      /* Select all 4-OP
-                                                                        * voices */
+  connection_mask = 0x3f;      /* Connect all possible 4 OP voices */
+  opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f);
+
   for (i = 0; i < 3; i++)
     physical_voices[i].voice_mode = 4;
   for (i = 3; i < 6; i++)
@@ -114,7 +125,7 @@ enter_4op_mode (void)
 
   for (i = 0; i < 12; i++)
     logical_voices[i] = voices_4op[i];
-  nr_voices = 12;
+  voice_alloc->max_voice = nr_voices = 12;
 }
 
 static int
@@ -183,66 +194,111 @@ opl3_detect (int ioaddr)
 
   if (already_initialized)
     {
-      return 0;                        /* Do avoid duplicate initializations */
+      return 0;                        /*
+                                * Do avoid duplicate initializations
+                                */
     }
 
   if (opl3_enabled)
     ioaddr = left_address;
 
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);    /* Reset timers 1 and 2 */
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);    /* Reset the IRQ of FM
-                                                                * chicp */
-
-  stat1 = INB (ioaddr);                /* Read status register */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);    /*
+                                                                                * Reset
+                                                                                * timers
+                                                                                * 1
+                                                                                * and
+                                                                                * 2
+                                                                                */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);    /*
+                                                                * Reset the
+                                                                * IRQ of FM
+                                                                * * chicp
+                                                                */
+
+  stat1 = INB (ioaddr);                /*
+                                * Read status register
+                                */
 
   if ((stat1 & 0xE0) != 0x00)
     {
-      return 0;                        /* Should be 0x00        */
+      return 0;                        /*
+                                * Should be 0x00
+                                */
     }
 
-  opl3_command (ioaddr, TIMER1_REGISTER, 0xff);        /* Set timer 1 to 0xff */
+  opl3_command (ioaddr, TIMER1_REGISTER, 0xff);        /*
+                                                        * Set timer 1 to
+                                                        * 0xff
+                                                        */
   opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
-               TIMER2_MASK | TIMER1_START);    /* Unmask and start timer 1 */
+               TIMER2_MASK | TIMER1_START);    /*
+                                                * Unmask and start timer 1
+                                                */
 
   /*
    * Now we have to delay at least 80 msec
    */
 
   for (i = 0; i < 50; i++)
-    tenmicrosec ();            /* To be sure */
+    tenmicrosec ();            /*
+                                * To be sure
+                                */
 
-  stat2 = INB (ioaddr);                /* Read status after timers have expired */
+  stat2 = INB (ioaddr);                /*
+                                * Read status after timers have expired
+                                */
 
-  /* Stop the timers */
+  /*
+   * Stop the timers
+   */
 
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);    /* Reset timers 1 and 2 */
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);    /* Reset the IRQ of FM
-                                                                * chicp */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);    /*
+                                                                                * Reset
+                                                                                * timers
+                                                                                * 1
+                                                                                * and
+                                                                                * 2
+                                                                                */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);    /*
+                                                                * Reset the
+                                                                * IRQ of FM
+                                                                * * chicp
+                                                                */
 
   if ((stat2 & 0xE0) != 0xc0)
     {
-      return 0;                        /* There is no YM3812 */
+      return 0;                        /*
+                                * There is no YM3812
+                                */
     }
 
-  /* There is a FM chicp in this address. Now set some default values. */
+  /*
+   * There is a FM chicp in this address. Now set some default values.
+   */
 
   for (i = 0; i < 9; i++)
-    opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* Note off */
+    opl3_command (ioaddr, KEYON_BLOCK + i, 0); /*
+                                                * Note off
+                                                */
 
   opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT);
-  opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00);    /* Melodic mode. */
+  opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00);    /*
+                                                        * Melodic mode.
+                                                        */
 
   return 1;
 }
 
 static int
-opl3_kill_note (int dev, int voice, int velocity)
+opl3_kill_note (int dev, int voice, int note, int velocity)
 {
   struct physical_voice_info *map;
 
   if (voice < 0 || voice >= nr_voices)
     return 0;
 
+  voice_alloc->map[voice] = 0;
+
   map = &physical_voices[logical_voices[voice]];
 
   DEB (printk ("Kill note %d\n", voice));
@@ -254,7 +310,9 @@ opl3_kill_note (int dev, int voice, int velocity)
 
   voices[voice].keyon_byte = 0;
   voices[voice].bender = 0;
-  voices[voice].bender_range = 200;    /* 200 cents = 2 semitones */
+  voices[voice].bender_range = 200;    /*
+                                        * 200 cents = 2 semitones
+                                        */
   voices[voice].orig_freq = 0;
   voices[voice].current_freq = 0;
   voices[voice].mode = 0;
@@ -304,22 +362,55 @@ opl3_set_instr (int dev, int voice, int instr_no)
  * it saves a lot of log() calculations. (RH)
  */
 char            fm_volume_table[128] =
-{-64, -48, -40, -35, -32, -29, -27, -26,       /* 0 -   7 */
- -24, -23, -21, -20, -19, -18, -18, -17,       /* 8 -  15 */
- -16, -15, -15, -14, -13, -13, -12, -12,       /* 16 -  23 */
- -11, -11, -10, -10, -10, -9, -9, -8,  /* 24 -  31 */
- -8, -8, -7, -7, -7, -6, -6, -6,/* 32 -  39 */
- -5, -5, -5, -5, -4, -4, -4, -4,/* 40 -  47 */
- -3, -3, -3, -3, -2, -2, -2, -2,/* 48 -  55 */
- -2, -1, -1, -1, -1, 0, 0, 0,  /* 56 -  63 */
- 0, 0, 0, 1, 1, 1, 1, 1,       /* 64 -  71 */
- 1, 2, 2, 2, 2, 2, 2, 2,       /* 72 -  79 */
- 3, 3, 3, 3, 3, 3, 3, 4,       /* 80 -  87 */
- 4, 4, 4, 4, 4, 4, 4, 5,       /* 88 -  95 */
- 5, 5, 5, 5, 5, 5, 5, 5,       /* 96 - 103 */
- 6, 6, 6, 6, 6, 6, 6, 6,       /* 104 - 111 */
- 6, 7, 7, 7, 7, 7, 7, 7,       /* 112 - 119 */
- 7, 7, 7, 8, 8, 8, 8, 8};      /* 120 - 127 */
+{-64, -48, -40, -35, -32, -29, -27, -26,       /*
+                                                * 0 -   7
+                                                */
+ -24, -23, -21, -20, -19, -18, -18, -17,       /*
+                                                * 8 -  15
+                                                */
+ -16, -15, -15, -14, -13, -13, -12, -12,       /*
+                                                * 16 -  23
+                                                */
+ -11, -11, -10, -10, -10, -9, -9, -8,  /*
+                                        * 24 -  31
+                                        */
+ -8, -8, -7, -7, -7, -6, -6, -6,/*
+                                        * 32 -  39
+                                        */
+ -5, -5, -5, -5, -4, -4, -4, -4,/*
+                                        * 40 -  47
+                                        */
+ -3, -3, -3, -3, -2, -2, -2, -2,/*
+                                        * 48 -  55
+                                        */
+ -2, -1, -1, -1, -1, 0, 0, 0,  /*
+                                * 56 -  63
+                                */
+ 0, 0, 0, 1, 1, 1, 1, 1,       /*
+                                * 64 -  71
+                                */
+ 1, 2, 2, 2, 2, 2, 2, 2,       /*
+                                * 72 -  79
+                                */
+ 3, 3, 3, 3, 3, 3, 3, 4,       /*
+                                * 80 -  87
+                                */
+ 4, 4, 4, 4, 4, 4, 4, 5,       /*
+                                * 88 -  95
+                                */
+ 5, 5, 5, 5, 5, 5, 5, 5,       /*
+                                * 96 - 103
+                                */
+ 6, 6, 6, 6, 6, 6, 6, 6,       /*
+                                * 104 - 111
+                                */
+ 6, 7, 7, 7, 7, 7, 7, 7,       /*
+                                * 112 - 119
+                                */
+ 7, 7, 7, 8, 8, 8, 8, 8};      /*
+
+
+                                * *  * * 120 - 127   */
 
 static void
 calc_vol (unsigned char *regbyte, int volume)
@@ -361,26 +452,40 @@ set_voice_volume (int voice, int volume)
     return;
 
   if (voices[voice].mode == 2)
-    {                          /* 2 OP voice */
+    {                          /*
+                                * 2 OP voice
+                                */
 
       vol1 = instr->operators[2];
       vol2 = instr->operators[3];
 
       if ((instr->operators[10] & 0x01))
-       {                       /* Additive synthesis    */
+       {                       /*
+                                * Additive synthesis
+                                */
          calc_vol (&vol1, volume);
          calc_vol (&vol2, volume);
        }
       else
-       {                       /* FM synthesis */
+       {                       /*
+                                * FM synthesis
+                                */
          calc_vol (&vol2, volume);
        }
 
-      opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);        /* Modulator volume */
-      opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);        /* Carrier volume */
+      opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);        /*
+                                                                        * Modulator
+                                                                        * volume
+                                                                        */
+      opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);        /*
+                                                                        * Carrier
+                                                                        * volume
+                                                                        */
     }
   else
-    {                          /* 4 OP voice */
+    {                          /*
+                                * 4 OP voice
+                                */
       int             connection;
 
       vol1 = instr->operators[2];
@@ -398,7 +503,9 @@ set_voice_volume (int voice, int volume)
       switch (connection)
        {
        case 0:
-         calc_vol (&vol4, volume);     /* Just the OP 4 is carrier */
+         calc_vol (&vol4, volume);     /*
+                                        * Just the OP 4 is carrier
+                                        */
          break;
 
        case 1:
@@ -417,7 +524,9 @@ set_voice_volume (int voice, int volume)
          calc_vol (&vol4, volume);
          break;
 
-       default:/* Why ?? */ ;
+       default:                /*
+                                * Why ??
+                                                                                                                                                                */ ;
        }
 
       opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
@@ -443,15 +552,26 @@ opl3_start_note (int dev, int voice, int note, int volume)
   if (map->voice_mode == 0)
     return 0;
 
-  if (note == 255)             /* Just change the volume */
+  if (note == 255)             /*
+                                * Just change the volume
+                                */
     {
       set_voice_volume (voice, volume);
       return 0;
     }
 
-  /* Kill previous note before playing */
-  opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff);    /* Carrier volume to min */
-  opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff);    /* Modulator volume to */
+  /*
+   * Kill previous note before playing
+   */
+  opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff);    /*
+                                                                * Carrier
+                                                                * volume to
+                                                                * min
+                                                                */
+  opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff);    /*
+                                                                * Modulator
+                                                                * volume to
+                                                                */
 
   if (map->voice_mode == 4)
     {
@@ -459,7 +579,10 @@ opl3_start_note (int dev, int voice, int note, int volume)
       opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff);
     }
 
-  opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00);      /* Note off */
+  opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00);      /*
+                                                                        * Note
+                                                                        * off
+                                                                        */
 
   instr = active_instrument[voice];
 
@@ -475,7 +598,9 @@ opl3_start_note (int dev, int voice, int note, int volume)
     }
 
   if (map->voice_mode == 2 && instr->key == OPL3_PATCH)
-    return 0;                  /* Cannot play */
+    return 0;                  /*
+                                * Cannot play
+                                */
 
   voice_mode = map->voice_mode;
 
@@ -486,7 +611,9 @@ opl3_start_note (int dev, int voice, int note, int volume)
       voice_shift = (map->ioaddr == left_address) ? 0 : 3;
       voice_shift += map->voice_num;
 
-      if (instr->key != OPL3_PATCH)    /* Just 2 OP patch */
+      if (instr->key != OPL3_PATCH)    /*
+                                        * Just 2 OP patch
+                                        */
        {
          voice_mode = 2;
          connection_mask &= ~(1 << voice_shift);
@@ -499,26 +626,38 @@ opl3_start_note (int dev, int voice, int note, int volume)
       opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
     }
 
-  /* Set Sound Characteristics */
+  /*
+   * Set Sound Characteristics
+   */
   opl3_command (map->ioaddr, AM_VIB + map->op[0], instr->operators[0]);
   opl3_command (map->ioaddr, AM_VIB + map->op[1], instr->operators[1]);
 
-  /* Set Attack/Decay */
+  /*
+   * Set Attack/Decay
+   */
   opl3_command (map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]);
   opl3_command (map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]);
 
-  /* Set Sustain/Release */
+  /*
+   * Set Sustain/Release
+   */
   opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]);
   opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]);
 
-  /* Set Wave Select */
+  /*
+   * Set Wave Select
+   */
   opl3_command (map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]);
   opl3_command (map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]);
 
-  /* Set Feedback/Connection */
+  /*
+   * Set Feedback/Connection
+   */
   fpc = instr->operators[10];
   if (!(fpc & 0x30))
-    fpc |= 0x30;               /* Ensure that at least one chn is enabled */
+    fpc |= 0x30;               /*
+                                * Ensure that at least one chn is enabled
+                                */
   opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num,
                fpc);
 
@@ -529,26 +668,38 @@ opl3_start_note (int dev, int voice, int note, int volume)
   if (voice_mode == 4)
     {
 
-      /* Set Sound Characteristics */
+      /*
+       * Set Sound Characteristics
+       */
       opl3_command (map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]);
       opl3_command (map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]);
 
-      /* Set Attack/Decay */
+      /*
+       * Set Attack/Decay
+       */
       opl3_command (map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]);
       opl3_command (map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]);
 
-      /* Set Sustain/Release */
+      /*
+       * Set Sustain/Release
+       */
       opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]);
       opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]);
 
-      /* Set Wave Select */
+      /*
+       * Set Wave Select
+       */
       opl3_command (map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]);
       opl3_command (map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]);
 
-      /* Set Feedback/Connection */
+      /*
+       * Set Feedback/Connection
+       */
       fpc = instr->operators[OFFS_4OP + 10];
       if (!(fpc & 0x30))
-       fpc |= 0x30;            /* Ensure that at least one chn is enabled */
+       fpc |= 0x30;            /*
+                                * Ensure that at least one chn is enabled
+                                */
       opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc);
     }
 
@@ -568,9 +719,13 @@ opl3_start_note (int dev, int voice, int note, int volume)
 
   freq_to_fnum (freq, &block, &fnum);
 
-  /* Play note */
+  /*
+   * Play note
+   */
 
-  data = fnum & 0xff;          /* Least significant bits of fnumber */
+  data = fnum & 0xff;          /*
+                                * Least significant bits of fnumber
+                                */
   opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
 
   data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
@@ -587,8 +742,12 @@ freq_to_fnum (int freq, int *block, int *fnum)
 {
   int             f, octave;
 
-  /* Converts the note frequency to block and fnum values for the FM chip */
-  /* First try to compute the block -value (octave) where the note belongs */
+  /*
+   * Converts the note frequency to block and fnum values for the FM chip
+   */
+  /*
+   * First try to compute the block -value (octave) where the note belongs
+   */
 
   f = freq;
 
@@ -630,7 +789,10 @@ opl3_command (int io_addr, unsigned int addr, unsigned int val)
    * register. The OPL-3 survives with just two INBs
    */
 
-  OUTB ((unsigned char) (addr & 0xff), io_addr);       /* Select register       */
+  OUTB ((unsigned char) (addr & 0xff), io_addr);       /*
+                                                        * Select register
+                                                        *
+                                                        */
 
   if (!opl3_enabled)
     tenmicrosec ();
@@ -638,7 +800,10 @@ opl3_command (int io_addr, unsigned int addr, unsigned int val)
     for (i = 0; i < 2; i++)
       INB (io_addr);
 
-  OUTB ((unsigned char) (val & 0xff), io_addr + 1);    /* Write to register  */
+  OUTB ((unsigned char) (val & 0xff), io_addr + 1);    /*
+                                                        * Write to register
+                                                        *
+                                                        */
 
   if (!opl3_enabled)
     {
@@ -659,26 +824,26 @@ opl3_reset (int dev)
   for (i = 0; i < nr_voices; i++)
     {
       opl3_command (physical_voices[logical_voices[i]].ioaddr,
-               KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff);    /* OP1 volume to min */
+               KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff);
 
       opl3_command (physical_voices[logical_voices[i]].ioaddr,
-               KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff);    /* OP2 volume to min */
+               KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff);
 
-      if (physical_voices[logical_voices[i]].voice_mode == 4)  /* 4 OP voice */
+      if (physical_voices[logical_voices[i]].voice_mode == 4)
        {
          opl3_command (physical_voices[logical_voices[i]].ioaddr,
-               KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff);    /* OP3 volume to min */
+               KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff);
 
          opl3_command (physical_voices[logical_voices[i]].ioaddr,
-               KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff);    /* OP4 volume to min */
+               KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff);
        }
 
-      opl3_kill_note (dev, i, 64);
+      opl3_kill_note (dev, i, 0, 64);
     }
 
   if (opl3_enabled)
     {
-      nr_voices = 18;
+      voice_alloc->max_voice = nr_voices = 18;
 
       for (i = 0; i < 18; i++)
        logical_voices[i] = i;
@@ -699,7 +864,9 @@ opl3_open (int dev, int mode)
     return RET_ERROR (EBUSY);
   opl3_busy = 1;
 
-  connection_mask = 0x00;      /* Just 2 OP voices */
+  connection_mask = 0x00;      /*
+                                * Just 2 OP voices
+                                */
   if (opl3_enabled)
     opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
   return 0;
@@ -709,7 +876,7 @@ static void
 opl3_close (int dev)
 {
   opl3_busy = 0;
-  nr_voices = opl3_enabled ? 18 : 9;
+  voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
   fm_info.nr_drums = 0;
   fm_info.perc_mode = 0;
 
@@ -814,13 +981,17 @@ opl3_aftertouch (int dev, int voice, int pressure)
          break;
 
        }
-      /* Not implemented yet */
+      /*
+       * Not implemented yet
+       */
     }
   else
     {
       SET_VIBRATO (1);
 
-      if ((instr->operators[10] & 0x01))       /* Additive synthesis */
+      if ((instr->operators[10] & 0x01))       /*
+                                                * Additive synthesis
+                                                */
        SET_VIBRATO (2);
     }
 }
@@ -828,41 +999,57 @@ opl3_aftertouch (int dev, int voice, int pressure)
 #undef SET_VIBRATO
 
 static void
-opl3_controller (int dev, int voice, int ctrl_num, int value)
+bend_pitch (int dev, int voice, int value)
 {
   unsigned char   data;
   int             block, fnum, freq;
   struct physical_voice_info *map;
 
-  if (voice < 0 || voice >= nr_voices)
-    return;
-
   map = &physical_voices[logical_voices[voice]];
 
   if (map->voice_mode == 0)
     return;
 
-  switch (ctrl_num)
-    {
-    case CTRL_PITCH_BENDER:
-      voices[voice].bender = value;
-      if (!value)
-       return;
-      if (!(voices[voice].keyon_byte & 0x20))
-       return;                 /* Not keyed on */
+  voices[voice].bender = value;
+  if (!value)
+    return;
+  if (!(voices[voice].keyon_byte & 0x20))
+    return;                    /*
+                                * Not keyed on
+                                */
+
+  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
+  voices[voice].current_freq = freq;
+
+  freq_to_fnum (freq, &block, &fnum);
 
-      freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
-      voices[voice].current_freq = freq;
+  data = fnum & 0xff;          /*
+                                * Least significant bits of fnumber
+                                */
+  opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
 
-      freq_to_fnum (freq, &block, &fnum);
+  data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);    /*
+                                                                * *
+                                                                * KEYON|OCTAVE|MS
+                                                                *
+                                                                * * bits * *
+                                                                * of * f-num
+                                                                *
+                                                                */
+  voices[voice].keyon_byte = data;
+  opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
+}
 
-      data = fnum & 0xff;      /* Least significant bits of fnumber */
-      opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
+static void
+opl3_controller (int dev, int voice, int ctrl_num, int value)
+{
+  if (voice < 0 || voice >= nr_voices)
+    return;
 
-      data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);        /* KEYON|OCTAVE|MS bits
-                                                                          * of f-num */
-      voices[voice].keyon_byte = data;
-      opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
+  switch (ctrl_num)
+    {
+    case CTRL_PITCH_BENDER:
+      bend_pitch (dev, voice, value);
       break;
 
     case CTRL_PITCH_BENDER_RANGE:
@@ -877,9 +1064,76 @@ opl3_patchmgr (int dev, struct patmgr_info *rec)
   return RET_ERROR (EINVAL);
 }
 
+static void
+opl3_bender (int dev, int voice, int value)
+{
+  if (voice < 0 || voice >= nr_voices)
+    return;
+
+  bend_pitch (dev, voice, value);
+}
+
+static int
+opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
+{
+  int             i, p, avail_voices;
+  struct sbi_instrument *instr;
+  int             is4op;
+  int             instr_no;
+
+  if (chn < 0 || chn > 15)
+    instr_no = 0;
+  else
+    instr_no = chn_info[chn].pgm_num;
+
+  instr = &instrmap[instr_no];
+  if (instr->channel < 0 ||    /* Instrument not loaded */
+      nr_voices != 12)         /* Not in 4 OP mode */
+    is4op = 0;
+  else if (nr_voices == 12)    /* 4 OP mode */
+    is4op = (instr->key == OPL3_PATCH);
+  else
+    is4op = 0;
+
+  if (is4op)
+    {
+      p = 0;
+      avail_voices = 6;
+    }
+  else
+    {
+      if (nr_voices == 12)     /* 4 OP mode. Use the '2 OP only' voices first */
+       p = 6;
+      else
+       p = 0;
+      avail_voices = nr_voices;
+    }
+
+  /*
+ *    Now try to find a free voice
+ */
+
+  for (i = 0; i < avail_voices; i++)
+    {
+      if (alloc->map[p] == 0)
+       {
+         return p;
+       }
+      p = (p + 1) % nr_voices;
+    }
+
+  /*
+ *    Insert some kind of priority mechanism here.
+ */
+
+  printk ("OPL3: Out of free voices\n");
+  return 0;                    /* All voices in use. Select the first one. */
+}
+
 static struct synth_operations opl3_operations =
 {
   &fm_info,
+  0,
   SYNTH_TYPE_FM,
   FM_TYPE_ADLIB,
   opl3_open,
@@ -895,7 +1149,9 @@ static struct synth_operations opl3_operations =
   opl3_controller,
   opl3_panning,
   opl3_volume_method,
-  opl3_patchmgr
+  opl3_patchmgr,
+  opl3_bender,
+  opl3_alloc_voice
 };
 
 long
@@ -906,14 +1162,22 @@ opl3_init (long mem_start)
   PERMANENT_MALLOC (struct sbi_instrument *, instrmap,
                    SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
 
-  synth_devs[num_synths++] = &opl3_operations;
+  if (num_synths >= MAX_SYNTH_DEV)
+    printk ("OPL3 Error: Too many synthesizers\n");
+  else
+    {
+      synth_devs[num_synths++] = &opl3_operations;
+      voice_alloc = &opl3_operations.alloc;
+      chn_info = &opl3_operations.chn_info[0];
+    }
+
   fm_model = 0;
   opl3_ok = 1;
   if (opl3_enabled)
     {
       printk (" <Yamaha OPL-3 FM>");
       fm_model = 2;
-      nr_voices = 18;
+      voice_alloc->max_voice = nr_voices = 18;
       fm_info.nr_drums = 0;
       fm_info.capabilities |= SYNTH_CAP_OPL3;
 #ifndef SCO
@@ -927,15 +1191,24 @@ opl3_init (long mem_start)
          physical_voices[i].ioaddr = right_address;
 
 
-      opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE);   /* Enable OPL-3 mode */
-      opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00);  /* Select all 2-OP
-                                                                        * voices */
+      opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE);   /*
+                                                                        * Enable
+                                                                        * OPL-3
+                                                                        * mode
+                                                                        */
+      opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00);  /*
+                                                                        * Select
+                                                                        * all
+                                                                        * 2-OP
+                                                                        * *
+                                                                        * voices
+                                                                        */
     }
   else
     {
       printk (" <Yamaha 2-OP FM>");
       fm_model = 1;
-      nr_voices = 9;
+      voice_alloc->max_voice = nr_voices = 9;
       fm_info.nr_drums = 0;
 
       for (i = 0; i < 18; i++)
index fc1b0f5cae7ded59cf5126f32fe9c687f3d67c6e..bdd734e7559455e3061c9f43f5a3ce9376e34721 100644 (file)
@@ -44,8 +44,8 @@
 #include <sys/kd.h>
 #include <linux/wait.h>
 #include <linux/malloc.h>
-#include <linux/soundcard.h>
 #include <linux/string.h>
+#include <linux/soundcard.h>
 
 typedef char snd_rw_buf;
 
@@ -73,7 +73,7 @@ struct snd_wait {
 #define DEFINE_WAIT_QUEUES(name, flag) static struct wait_queue *name = {NULL}; \
        static volatile struct snd_wait flag = {{0}}
 #define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;}
-#define PROCESS_ABORTING(q, f) (f.aborting | (current->signal & ~current->blocked))
+#define PROCESS_ABORTING(q, f) (/*f.aborting | */(current->signal & ~current->blocked))
 #define SET_ABORT_FLAG(q, f) f.aborting = 1
 #define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT)
 #define DO_SLEEP(q, f, time_limit)     \
@@ -141,7 +141,7 @@ struct snd_wait {
 
 #define DEFINE_TIMER(name, proc) \
   static struct timer_list name = \
-  {NULL, 0, 0, 0, proc}
+  {NULL, NULL, 0, 0, proc}
 
 /*
  * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
@@ -153,3 +153,9 @@ struct snd_wait {
 
 #define INB    inb
 #define OUTB   outb
+
+/*
+ * SND_SA_INTERRUPT is required. Otherwise the IRQ number is not passed 
+ * the handler.
+ */
+#define SND_SA_INTERRUPT
index 9902e03e4bfeb9a43c44bf3352b97658dc72a616..70c61dc57f5c3811385c6fe9eb875b517ec20b24 100644 (file)
 #define PAS_16D                4
 
 #ifdef DEFINE_TRANSLATIONS
-       char I_C_2_PCM_DMA_translate[] =                /* R W  PCM             PCM DMA channel value translations              */
+       unsigned char I_C_2_PCM_DMA_translate[] =               /* R W  PCM             PCM DMA channel value translations              */
                        { 4, 1, 2, 3, 0, 5, 6, 7 };
-       char I_C_3_PCM_IRQ_translate[] =                /* R W  PCM             PCM IRQ level value translation                 */
+       unsigned char I_C_3_PCM_IRQ_translate[] =               /* R W  PCM             PCM IRQ level value translation                 */
                { 0,  0,  1,  2,  3,  4,  5,  6, 0,  1,  7,  8,  9,  0, 10, 11 };  
-       char E_C_MPU401_IRQ_translate[] =               /* R W  MIDI            MPU401 emulation IRQ value translation          */
+       unsigned char E_C_MPU401_IRQ_translate[] =              /* R W  MIDI            MPU401 emulation IRQ value translation          */
                { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 };
-       char E_C_SB_IRQ_translate[] =                   /* R W  PCM             SB emulation IRQ translate                      */
+       unsigned char E_C_SB_IRQ_translate[] =                  /* R W  PCM             SB emulation IRQ translate                      */
                { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 };
-       char E_C_SB_DMA_translate[] =                   /* R W  PCM             SB emulation DMA translate                      */
+       unsigned char E_C_SB_DMA_translate[] =                  /* R W  PCM             SB emulation DMA translate                      */
                { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
-       char O_M_1_to_card[] =                          /* R W  Control         Translate (OM1 & 0x0f) to card type             */
+       unsigned char O_M_1_to_card[] =                                 /* R W  Control         Translate (OM1 & 0x0f) to card type             */
                { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 };   
 #else
-       extern char I_C_2_PCM_DMA_translate[];          /* R W  PCM             PCM DMA channel value translations              */
-       extern char I_C_3_PCM_IRQ_translate[];          /* R W  PCM             PCM IRQ level value translation                 */
-       extern char E_C_MPU401_IRQ_translate[];         /* R W  MIDI            MPU401 emulation IRQ value translation          */
-       extern char E_C_SB_IRQ_translate[];             /* R W  PCM             SB emulation IRQ translate                      */
-       extern char E_C_SB_DMA_translate[];             /* R W  PCM             SB emulation DMA translate                      */
-       extern char O_M_1_to_card[];                    /* R W  Control         Translate (OM1 & 0x0f) to card type             */
+       extern unsigned char I_C_2_PCM_DMA_translate[];         /* R W  PCM             PCM DMA channel value translations              */
+       extern unsigned char I_C_3_PCM_IRQ_translate[];         /* R W  PCM             PCM IRQ level value translation                 */
+       extern unsigned char E_C_MPU401_IRQ_translate[];                /* R W  MIDI            MPU401 emulation IRQ value translation          */
+       extern unsigned char E_C_SB_IRQ_translate[];            /* R W  PCM             SB emulation IRQ translate                      */
+       extern unsigned char E_C_SB_DMA_translate[];            /* R W  PCM             SB emulation DMA translate                      */
+       extern unsigned char O_M_1_to_card[];                   /* R W  Control         Translate (OM1 & 0x0f) to card type             */
 #endif
 
 #define PARALLEL_MIXER                 0x078B          /*   W  Mixer           Documented for MVD101 as FM Mono Right decode?? */
index a3030a44af758077ebc8bbaecb5c95aa003647b4..1bfd73fcc40413e2a3b1df8667f934f7c8f194e8 100644 (file)
@@ -1,5 +1,4 @@
 #define _PAS2_CARD_C_
-#define SND_SA_INTERRUPT
 /*
  * sound/pas2_card.c
  *
@@ -49,9 +48,15 @@ static char     pas_model;
 static char    *pas_model_names[] =
 {"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
 
-/* pas_read() and pas_write() are equivalents of INB() and OUTB() */
-/* These routines perform the I/O address translation required */
-/* to support other than the default base address */
+/*
+ * pas_read() and pas_write() are equivalents of INB() and OUTB()
+ */
+/*
+ * These routines perform the I/O address translation required
+ */
+/*
+ * to support other than the default base address
+ */
 
 unsigned char
 pas_read (int ioaddr)
@@ -79,7 +84,9 @@ pasintr (int unused)
   int             status;
 
   status = pas_read (INTERRUPT_STATUS);
-  pas_write (status, INTERRUPT_STATUS);        /* Clear interrupt */
+  pas_write (status, INTERRUPT_STATUS);        /*
+                                                * Clear interrupt
+                                                */
 
   if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
     {
@@ -143,27 +150,39 @@ int
 config_pas_hw (struct address_info *hw_config)
 {
   char            ok = 1;
+  unsigned        int_ptrs;    /* scsi/sound interrupt pointers */
 
   pas_irq = hw_config->irq;
 
   pas_write (0x00, INTERRUPT_MASK);
 
-  pas_write (0x36, SAMPLE_COUNTER_CONTROL);    /* Local timer control
-                                                * register */
+  pas_write (0x36, SAMPLE_COUNTER_CONTROL);    /*
+                                                * Local timer control *
+                                                * register
+                                                */
 
-  pas_write (0x36, SAMPLE_RATE_TIMER); /* Sample rate timer (16 bit) */
+  pas_write (0x36, SAMPLE_RATE_TIMER); /*
+                                        * Sample rate timer (16 bit)
+                                        */
   pas_write (0, SAMPLE_RATE_TIMER);
 
-  pas_write (0x74, SAMPLE_COUNTER_CONTROL);    /* Local timer control
-                                                * register */
+  pas_write (0x74, SAMPLE_COUNTER_CONTROL);    /*
+                                                * Local timer control *
+                                                * register
+                                                */
 
-  pas_write (0x74, SAMPLE_BUFFER_COUNTER);     /* Sample count register (16
-                                                * bit) */
+  pas_write (0x74, SAMPLE_BUFFER_COUNTER);     /*
+                                                * Sample count register (16
+                                                * * bit)
+                                                */
   pas_write (0, SAMPLE_BUFFER_COUNTER);
 
   pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY);
   pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL);
-  pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* | S_M_OPL3_DUAL_MONO */ , SERIAL_MIXER);
+  pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET     /*
+                                                                                * |
+                                                                                * S_M_OPL3_DUAL_MONO
+                                                                                                                                                                                                                */ , SERIAL_MIXER);
 
   pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1);
 
@@ -174,7 +193,9 @@ config_pas_hw (struct address_info *hw_config)
     }
   else
     {
-      pas_write (I_C_3_PCM_IRQ_translate[pas_irq], IO_CONFIGURATION_3);
+      int_ptrs = pas_read (IO_CONFIGURATION_3);
+      int_ptrs |= I_C_3_PCM_IRQ_translate[pas_irq] & 0xf;
+      pas_write (int_ptrs, IO_CONFIGURATION_3);
       if (!I_C_3_PCM_IRQ_translate[pas_irq])
        {
          printk ("PAS2: Invalid IRQ %d", pas_irq);
@@ -209,14 +230,23 @@ config_pas_hw (struct address_info *hw_config)
 #ifdef BROKEN_BUS_CLOCK
   pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
 #else
-  /* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);     */
+  /*
+   * pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);
+   */
   pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
 #endif
-  pas_write (0x18, SYSTEM_CONFIGURATION_3);    /* ??? */
-
-  pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY);       /* Sets mute off and
-                                                                * selects filter rate
-                                                                * of 17.897 kHz */
+  pas_write (0x18, SYSTEM_CONFIGURATION_3);    /*
+                                                * ???
+                                                */
+
+  pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY);       /*
+                                                                * Sets mute
+                                                                * off and *
+                                                                * selects
+                                                                * filter
+                                                                * rate * of
+                                                                * 17.897 kHz
+                                                                */
 
   if (pas_model == PAS_16 || pas_model == PAS_16D)
     pas_write (8, PRESCALE_DIVIDER);
@@ -235,12 +265,20 @@ config_pas_hw (struct address_info *hw_config)
       {
        unsigned char   irq_dma;
 
-       /* Turn on Sound Blaster compatibility */
-       /* bit 1 = SB emulation */
-       /* bit 0 = MPU401 emulation (CDPC only :-( ) */
+       /*
+        * Turn on Sound Blaster compatibility
+        */
+       /*
+        * bit 1 = SB emulation
+        */
+       /*
+        * bit 0 = MPU401 emulation (CDPC only :-( )
+        */
        pas_write (0x02, COMPATIBILITY_ENABLE);
 
-       /* "Emulation address"         */
+       /*
+        * "Emulation address"
+        */
        pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
 
        if (!E_C_SB_DMA_translate[sb_config->dma])
@@ -277,10 +315,16 @@ detect_pas_hw (struct address_info *hw_config)
    * you have something on base port 0x388. SO be forewarned.
    */
 
-  OUTB (0xBC, MASTER_DECODE);  /* Talk to first board */
-  OUTB (hw_config->io_base >> 2, MASTER_DECODE);       /* Set base address */
+  OUTB (0xBC, MASTER_DECODE);  /*
+                                * Talk to first board
+                                */
+  OUTB (hw_config->io_base >> 2, MASTER_DECODE);       /*
+                                                        * Set base address
+                                                        */
   translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base;
-  pas_write (1, WAIT_STATE);   /* One wait-state */
+  pas_write (1, WAIT_STATE);   /*
+                                * One wait-state
+                                */
 
   board_id = pas_read (INTERRUPT_MASK);
 
@@ -299,7 +343,9 @@ detect_pas_hw (struct address_info *hw_config)
   foo = INB (INTERRUPT_MASK);
   pas_write (board_id, INTERRUPT_MASK);
 
-  if (board_id != foo)         /* Not a PAS2 */
+  if (board_id != foo)         /*
+                                * Not a PAS2
+                                */
     return 0;
 
   pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f];
@@ -329,8 +375,10 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
 
 #if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
 
-         sb_dsp_disable_midi ();       /* The SB emulation don't support
-                                        * midi */
+         sb_dsp_disable_midi ();       /*
+                                        * The SB emulation don't support *
+                                        * midi
+                                        */
 #endif
 
 #ifndef EXCLUDE_YM3812
index 4a07b0b59bf8537cab63bf286e26e71e2517a760..1c6bf5937a037eaceb725a2160d45d8e9b30708d 100644 (file)
@@ -62,7 +62,9 @@ pas_midi_open (int dev, int mode,
       return RET_ERROR (EBUSY);
     }
 
-  /* Reset input and output FIFO pointers */
+  /*
+   * Reset input and output FIFO pointers
+   */
   pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO,
             MIDI_CONTROL);
 
@@ -71,7 +73,9 @@ pas_midi_open (int dev, int mode,
   if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0)
     return err;
 
-  /* Enable input available and output FIFO empty interrupts */
+  /*
+   * Enable input available and output FIFO empty interrupts
+   */
 
   ctrl = 0;
   input_opened = 0;
@@ -79,20 +83,26 @@ pas_midi_open (int dev, int mode,
 
   if (mode == OPEN_READ || mode == OPEN_READWRITE)
     {
-      ctrl |= M_C_ENA_INPUT_IRQ;/* Enable input */
+      ctrl |= M_C_ENA_INPUT_IRQ;/*
+                                        * Enable input
+                                        */
       input_opened = 1;
     }
 
   if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
     {
-      ctrl |= M_C_ENA_OUTPUT_IRQ |     /* Enable output */
+      ctrl |= M_C_ENA_OUTPUT_IRQ |     /*
+                                        * Enable output
+                                        */
        M_C_ENA_OUTPUT_HALF_IRQ;
     }
 
   pas_write (ctrl,
             MIDI_CONTROL);
 
-  /* Acknowledge any pending interrupts */
+  /*
+   * Acknowledge any pending interrupts
+   */
 
   pas_write (0xff, MIDI_STATUS);
   ofifo_bytes = 0;
@@ -108,7 +118,9 @@ static void
 pas_midi_close (int dev)
 {
 
-  /* Reset FIFO pointers, disable intrs */
+  /*
+   * Reset FIFO pointers, disable intrs
+   */
   pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL);
 
   pas_remove_intr (I_M_MIDI_IRQ_ENABLE);
@@ -122,9 +134,14 @@ dump_to_midi (unsigned char midi_byte)
 
   fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
 
-  if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13))        /* Fifo full */
+  if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13))        /*
+                                                                        * Fifo
+                                                                        * full
+                                                                        */
     {
-      return 0;                        /* Upper layer will call again */
+      return 0;                        /*
+                                * Upper layer will call again
+                                */
     }
 
   ofifo_bytes++;
@@ -160,14 +177,18 @@ pas_midi_out (int dev, unsigned char midi_byte)
 
   if (!qlen)
     if (dump_to_midi (midi_byte))
-      return 1;                        /* OK */
+      return 1;                        /*
+                                * OK
+                                */
 
   /*
    * Put to the local queue
    */
 
   if (qlen >= 256)
-    return 0;                  /* Local queue full */
+    return 0;                  /*
+                                * Local queue full
+                                */
 
   DISABLE_INTR (flags);
 
@@ -210,9 +231,14 @@ pas_buffer_status (int dev)
   return !qlen;
 }
 
+#define MIDI_SYNTH_NAME        "Pro Audio Spectrum Midi"
+#define MIDI_SYNTH_CAPS        SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
 static struct midi_operations pas_midi_operations =
 {
   {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
+  &std_midi_synth,
   pas_midi_open,
   pas_midi_close,
   pas_midi_ioctl,
@@ -220,14 +246,23 @@ static struct midi_operations pas_midi_operations =
   pas_midi_start_read,
   pas_midi_end_read,
   pas_midi_kick,
-  NULL,                                /* command */
-  pas_buffer_status
+  NULL,                                /*
+                                * command
+                                */
+  pas_buffer_status,
+  NULL
 };
 
 long
 pas_midi_init (long mem_start)
 {
-  my_dev = num_midis;
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return mem_start;
+    }
+
+  std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &pas_midi_operations;
   return mem_start;
 }
@@ -241,9 +276,13 @@ pas_midi_interrupt (void)
 
   stat = pas_read (MIDI_STATUS);
 
-  if (stat & M_S_INPUT_AVAIL)  /* Input byte available */
+  if (stat & M_S_INPUT_AVAIL)  /*
+                                * Input byte available
+                                */
     {
-      incount = pas_read (MIDI_FIFO_STATUS) & 0x0f;    /* Input FIFO count */
+      incount = pas_read (MIDI_FIFO_STATUS) & 0x0f;    /*
+                                                        * Input FIFO count
+                                                        */
       if (!incount)
        incount = 16;
 
@@ -253,7 +292,9 @@ pas_midi_interrupt (void)
            midi_input_intr (my_dev, pas_read (MIDI_DATA));
          }
        else
-         pas_read (MIDI_DATA); /* Flush */
+         pas_read (MIDI_DATA); /*
+                                * Flush
+                                */
     }
 
   if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY))
@@ -287,7 +328,9 @@ pas_midi_interrupt (void)
       ofifo_bytes = 100;
     }
 
-  pas_write (stat, MIDI_STATUS);/* Acknowledge interrupts */
+  pas_write (stat, MIDI_STATUS);/*
+                                        * Acknowledge interrupts
+                                        */
 }
 
 #endif
index fd3e1065a2442cf6b083071648a57e3831907821..c125b47c181a27c088ba1152b52241ab31d290a8 100644 (file)
 
 #include "pas.h"
 
-#define TRACE(what)            /* (what) */
+#define TRACE(what)            /*
+                                  * * * (what)   */
 
 extern int      translat_code;
 
-static int      rec_devices = (SOUND_MASK_MIC);        /* Default recording source */
+static int      rec_devices = (SOUND_MASK_MIC);        /*
+
+
+                                                        * *  * * Default *
+                                                        * recording * source
+                                                        *
+                                                        * *  */
 static int      mode_control = 0;
 
 #define POSSIBLE_RECORDING_DEVICES     (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
@@ -52,22 +59,49 @@ static int      mode_control = 0;
 
 static unsigned short levels[SOUND_MIXER_NRDEVICES] =
 {
-  0x3232,                      /* Master Volume */
-  0x3232,                      /* Bass */
-  0x3232,                      /* Treble */
-  0x5050,                      /* FM */
-  0x4b4b,                      /* PCM */
-  0x3232,                      /* PC Speaker */
-  0x4b4b,                      /* Ext Line */
-  0x4b4b,                      /* Mic */
-  0x4b4b,                      /* CD */
-  0x6464,                      /* Recording monitor */
-  0x4b4b,                      /* SB PCM */
-  0x6464};                     /* Recording level */
+  0x3232,                      /*
+                                * Master Volume
+                                */
+  0x3232,                      /*
+                                * Bass
+                                */
+  0x3232,                      /*
+                                * Treble
+                                */
+  0x5050,                      /*
+                                * FM
+                                */
+  0x4b4b,                      /*
+                                * PCM
+                                */
+  0x3232,                      /*
+                                * PC Speaker
+                                */
+  0x4b4b,                      /*
+                                * Ext Line
+                                */
+  0x4b4b,                      /*
+                                * Mic
+                                */
+  0x4b4b,                      /*
+                                * CD
+                                */
+  0x6464,                      /*
+                                * Recording monitor
+                                */
+  0x4b4b,                      /*
+                                * SB PCM
+                                */
+  0x6464};                     /*
+
+
+                                * *  * * Recording level   */
 
 static int
 mixer_output (int right_vol, int left_vol, int div, int bits,
-             int mixer /* Input or output mixer */ )
+             int mixer         /*
+                                * Input or output mixer
+                                                                        */ )
 {
   int             left = left_vol * div / 100;
   int             right = right_vol * div / 100;
@@ -81,13 +115,17 @@ mixer_output (int right_vol, int left_vol, int div, int bits,
    */
 
   if (bits & P_M_MV508_MIXER)
-    {                          /* Select input or output mixer */
+    {                          /*
+                                * Select input or output mixer
+                                */
       left |= mixer;
       right |= mixer;
     }
 
   if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
-    {                          /* Bass and trebble are mono devices     */
+    {                          /*
+                                * Bass and trebble are mono devices
+                                */
       pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
       pas_write (left, PARALLEL_MIXER);
       right_vol = left_vol;
@@ -130,7 +168,9 @@ pas_mixer_set (int whichDev, unsigned int level)
 
   switch (whichDev)
     {
-    case SOUND_MIXER_VOLUME:   /* Master volume (0-63) */
+    case SOUND_MIXER_VOLUME:   /*
+                                * Master volume (0-63)
+                                */
       levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
       break;
 
@@ -138,40 +178,62 @@ pas_mixer_set (int whichDev, unsigned int level)
        * Note! Bass and Treble are mono devices. Will use just the left
        * channel.
        */
-    case SOUND_MIXER_BASS:     /* Bass (0-12) */
+    case SOUND_MIXER_BASS:     /*
+                                * Bass (0-12)
+                                */
       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
       break;
-    case SOUND_MIXER_TREBLE:   /* Treble (0-12) */
+    case SOUND_MIXER_TREBLE:   /*
+                                * Treble (0-12)
+                                */
       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
       break;
 
-    case SOUND_MIXER_SYNTH:    /* Internal synthesizer (0-31) */
+    case SOUND_MIXER_SYNTH:    /*
+                                * Internal synthesizer (0-31)
+                                */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
       break;
-    case SOUND_MIXER_PCM:      /* PAS PCM (0-31) */
+    case SOUND_MIXER_PCM:      /*
+                                * PAS PCM (0-31)
+                                */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
       break;
-    case SOUND_MIXER_ALTPCM:   /* SB PCM (0-31) */
+    case SOUND_MIXER_ALTPCM:   /*
+                                * SB PCM (0-31)
+                                */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
       break;
-    case SOUND_MIXER_SPEAKER:  /* PC speaker (0-31) */
+    case SOUND_MIXER_SPEAKER:  /*
+                                * PC speaker (0-31)
+                                */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
       break;
-    case SOUND_MIXER_LINE:     /* External line (0-31) */
+    case SOUND_MIXER_LINE:     /*
+                                * External line (0-31)
+                                */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
       break;
-    case SOUND_MIXER_CD:       /* CD (0-31) */
+    case SOUND_MIXER_CD:       /*
+                                * CD (0-31)
+                                */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
       break;
-    case SOUND_MIXER_MIC:      /* External microphone (0-31) */
+    case SOUND_MIXER_MIC:      /*
+                                * External microphone (0-31)
+                                */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
       break;
-    case SOUND_MIXER_IMIX:     /* Recording monitor (0-31) (Only available
-                                * on the Output Mixer) */
+    case SOUND_MIXER_IMIX:     /*
+                                * Recording monitor (0-31) (Only available *
+                                * on the Output Mixer)
+                                */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
                                       P_M_MV508_OUTPUTMIX);
       break;
-    case SOUND_MIXER_RECLEV:   /* Recording level (0-15) */
+    case SOUND_MIXER_RECLEV:   /*
+                                * Recording level (0-15)
+                                */
       levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
       break;
 
@@ -199,7 +261,9 @@ pas_mixer_set (int whichDev, unsigned int level)
       if (level)
        mode_control |= P_M_MV508_LOUDNESS;
       set_mode (mode_control);
-      return !!level;          /* 0 or 1 */
+      return !!level;          /*
+                                * 0 or 1
+                                */
       break;
 
     case SOUND_MIXER_RECSRC:
@@ -225,91 +289,6 @@ pas_mixer_set (int whichDev, unsigned int level)
 
 /*****/
 
-static int
-mixer_set_levels (struct sb_mixer_levels *user_l)
-{
-#define cmix(v) ((((v.r*100+7)/15)<<8)| ((v.l*100+7)/15))
-
-  struct sb_mixer_levels l;
-
-  IOCTL_FROM_USER ((char *) &l, (char *) user_l, 0, sizeof (l));
-
-  if (l.master.l & ~0xF || l.master.r & ~0xF
-      || l.line.l & ~0xF || l.line.r & ~0xF
-      || l.voc.l & ~0xF || l.voc.r & ~0xF
-      || l.fm.l & ~0xF || l.fm.r & ~0xF
-      || l.cd.l & ~0xF || l.cd.r & ~0xF
-      || l.mic & ~0x7)
-    return (RET_ERROR (EINVAL));
-
-  pas_mixer_set (SOUND_MIXER_VOLUME, cmix (l.master));
-  pas_mixer_set (SOUND_MIXER_LINE, cmix (l.line));
-  pas_mixer_set (SOUND_MIXER_PCM, cmix (l.voc));
-  pas_mixer_set (SOUND_MIXER_ALTPCM, cmix (l.voc));
-  pas_mixer_set (SOUND_MIXER_SYNTH, cmix (l.fm));
-  pas_mixer_set (SOUND_MIXER_CD, cmix (l.cd));
-  pas_mixer_set (SOUND_MIXER_MIC, ((l.mic * 100 + 3) / 7) | (((l.mic * 100 + 3) / 7) << 8));
-  return (0);
-}
-
-/*
- * This sets aspects of the Mixer that are not volume levels. (Recording
- * source, filter level, I/O filtering, and stereo.)
- */
-static int
-mixer_set_params (struct sb_mixer_params *user_p)
-{
-  struct sb_mixer_params p;
-  S_BYTE          val;
-  int             src;
-  unsigned long   flags;
-
-  IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p));
-
-  if (p.record_source != SRC_MIC
-      && p.record_source != SRC_CD
-      && p.record_source != SRC_LINE)
-    return (RET_ERROR (EINVAL));
-
-  /*
-   * I'm not sure if this is The Right Thing.  Should stereo be entirely
-   * under control of DSP?  I like being able to toggle it while a sound is
-   * playing, so I do this... because I can.
-   */
-
-  DISABLE_INTR (flags);
-
-  val = (pas_read (PCM_CONTROL) & ~P_C_MIXER_CROSS_FIELD) | P_C_MIXER_CROSS_R_TO_R | P_C_MIXER_CROSS_L_TO_L;
-  if (!p.dsp_stereo)
-    val |= (P_C_MIXER_CROSS_R_TO_L | P_C_MIXER_CROSS_L_TO_R);  /* Mono */
-  pas_write (val, PCM_CONTROL);
-
-  RESTORE_INTR (flags);
-
-  switch (p.record_source)
-    {
-    case SRC_CD:
-      src = SOUND_MASK_CD;
-      break;
-
-    case SRC_LINE:
-      src = SOUND_MASK_LINE;
-      break;
-
-    default:
-      src = SOUND_MASK_MIC;
-      break;
-    }
-
-  pas_mixer_set (SOUND_MIXER_RECSRC, src);
-
-  /*
-   * setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC) |
-   * (p.filter_output ? FILT_ON : FILT_OFF)));
-   */
-  return (0);
-}
-
 static int
 getmixer (int dev, int chn)
 {
@@ -323,73 +302,6 @@ getmixer (int dev, int chn)
     }
 }
 
-/* Read the current mixer level settings into the user's struct. */
-static int
-mixer_get_levels (struct sb_mixer_levels *user_l)
-{
-
-  struct sb_mixer_levels l;
-
-  l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100; /* Master */
-  l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100;        /* Master */
-
-  l.line.r = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_RIGHT) * 15) + 50) / 100; /* Line */
-  l.line.l = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_LEFT) * 15) + 50) / 100;
-
-  l.voc.r = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_RIGHT) * 15) + 50) / 100;   /* DAC */
-  l.voc.l = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_LEFT) * 15) + 50) / 100;
-
-  l.fm.r = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_RIGHT) * 15) + 50) / 100;  /* FM */
-  l.fm.l = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_LEFT) * 15) + 50) / 100;
-
-  l.cd.r = ((getmixer (SOUND_MIXER_CD, P_M_MV508_RIGHT) * 15) + 50) / 100;     /* CD */
-  l.cd.l = ((getmixer (SOUND_MIXER_CD, P_M_MV508_LEFT) * 15) + 50) / 100;
-
-  l.mic = ((getmixer (SOUND_MIXER_MIC, P_M_MV508_LEFT) * 7) + 50) / 100;       /* Microphone */
-
-  IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l));
-  return (0);
-}
-
-/* Read the current mixer parameters into the user's struct. */
-static int
-mixer_get_params (struct sb_mixer_params *user_params)
-{
-  S_BYTE          val;
-  struct sb_mixer_params params;
-
-  switch (rec_devices)
-    {
-    case SOUND_MASK_CD:
-      params.record_source = SRC_CD;
-      break;
-
-    case SOUND_MASK_LINE:
-      params.record_source = SRC_LINE;
-      break;
-
-    case SOUND_MASK_MIC:
-      params.record_source = SRC_MIC;
-      break;
-
-    default:
-      params.record_source = SRC_MIC;
-      pas_mixer_set (SOUND_MIXER_RECSRC, SOUND_MASK_MIC);      /* Adjust */
-    }
-
-  params.hifreq_filter = OFF;
-  params.filter_input = OFF;
-  params.filter_output = OFF;
-
-  val = INB (PCM_CONTROL);
-  params.dsp_stereo = ((val & P_C_MIXER_CROSS_FIELD) == (P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R));
-
-  IOCTL_TO_USER ((char *) user_params, 0, (char *) &params, sizeof (params));
-  return (0);
-}
-
-/*****/
-
 static void
 pas_mixer_reset (void)
 {
@@ -413,7 +325,9 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
       if (cmd & IOC_IN)
        return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
       else
-       {                       /* Read parameters */
+       {                       /*
+                                * Read parameters
+                                */
 
          switch (cmd & 0xff)
            {
@@ -435,11 +349,15 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
              break;
 
            case SOUND_MIXER_CAPS:
-             return IOCTL_OUT (arg, 0);        /* No special capabilities */
+             return IOCTL_OUT (arg, 0);        /*
+                                                * No special capabilities
+                                                */
              break;
 
            case SOUND_MIXER_MUTE:
-             return IOCTL_OUT (arg, 0);        /* No mute yet */
+             return IOCTL_OUT (arg, 0);        /*
+                                                * No mute yet
+                                                */
              break;
 
            case SOUND_MIXER_ENHANCE:
@@ -459,27 +377,6 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
            }
        }
     }
-  else
-    {
-      switch (cmd)
-       {
-       case MIXER_IOCTL_SET_LEVELS:
-         mixer_set_levels ((struct sb_mixer_levels *) arg);
-         return mixer_get_levels ((struct sb_mixer_levels *) arg);
-       case MIXER_IOCTL_SET_PARAMS:
-         mixer_set_params ((struct sb_mixer_params *) arg);
-         return mixer_get_params ((struct sb_mixer_params *) arg);
-       case MIXER_IOCTL_READ_LEVELS:
-         return mixer_get_levels ((struct sb_mixer_levels *) arg);
-       case MIXER_IOCTL_READ_PARAMS:
-         return mixer_get_params ((struct sb_mixer_params *) arg);
-       case MIXER_IOCTL_RESET:
-         pas_mixer_reset ();
-         return (0);
-       default:
-         return RET_ERROR (EINVAL);
-       }
-    }
   return RET_ERROR (EINVAL);
 }
 
@@ -493,7 +390,8 @@ pas_init_mixer (void)
 {
   pas_mixer_reset ();
 
-  mixer_devs[num_mixers++] = &pas_mixer_operations;
+  if (num_mixers < MAX_MIXER_DEV)
+    mixer_devs[num_mixers++] = &pas_mixer_operations;
   return 1;
 }
 
index 06742d5589fa0e303b0b554c4363443c01040544..e4c9a63c384c66b59d03996b54ba1e1f94696330 100644 (file)
 
 #if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO)
 
-#define TRACE(WHAT)            /* (WHAT) */
+#define TRACE(WHAT)            /*
+                                  * * * (WHAT)   */
 
 #define PAS_PCM_INTRBITS (0x08)
-/* Sample buffer timer interrupt enable */
+/*
+ * Sample buffer timer interrupt enable
+ */
 
 #define PCM_NON        0
 #define PCM_DAC        1
 #define PCM_ADC        2
 
 static unsigned long pcm_speed = 0;    /* sampling rate */
-static unsigned char pcm_channels = 1; /* channels/sample (1 or 2) */
+static unsigned char pcm_channels = 1; /* channels (1 or 2) */
 static unsigned char pcm_bits = 8;     /* bits/sample (8 or 16) */
 static unsigned char pcm_filter = 0;   /* filter FLAG */
 static unsigned char pcm_mode = PCM_NON;
@@ -65,7 +68,7 @@ pcm_set_speed (int arg)
   if (arg < 5000)
     arg = 5000;
 
-  foo = 1193180 / arg;
+  foo = (1193180 + (arg / 2)) / arg;
   arg = 1193180 / foo;
 
   if (pcm_channels & 2)
@@ -75,6 +78,31 @@ pcm_set_speed (int arg)
 
   tmp = pas_read (FILTER_FREQUENCY);
 
+  /*
+ * Set anti-aliasing filters according to sample rate. You reall *NEED*
+ * to enable this feature for all normal recording unless you want to
+ * experiment with aliasing effects.
+ * These filters apply to the selected "recording" source.
+ * I (pfw) don't know the encoding of these 5 bits. The values shown
+ * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
+*/
+#if !defined NO_AUTO_FILTER_SET
+  tmp &= 0xe0;
+  if (pcm_speed >= 2 * 17897)
+    tmp |= 0x21;
+  else if (pcm_speed >= 2 * 15909)
+    tmp |= 0x22;
+  else if (pcm_speed >= 2 * 11931)
+    tmp |= 0x29;
+  else if (pcm_speed >= 2 * 8948)
+    tmp |= 0x31;
+  else if (pcm_speed >= 2 * 5965)
+    tmp |= 0x39;
+  else if (pcm_speed >= 2 * 2982)
+    tmp |= 0x24;
+  pcm_filter = tmp;
+#endif
+
   DISABLE_INTR (flags);
 
   pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
@@ -100,7 +128,9 @@ pcm_set_channels (int arg)
       pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
 
       pcm_channels = arg;
-      pcm_set_speed (pcm_speed);/* The speed must be reinitialized */
+      pcm_set_speed (pcm_speed);/*
+                                        * The speed must be reinitialized
+                                        */
     }
 
   return pcm_channels;
@@ -159,7 +189,7 @@ pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
       return IOCTL_OUT (arg, pcm_channels);
       break;
 
-    case SNDCTL_DSP_SAMPLESIZE:
+    case SNDCTL_DSP_SETFMT:
       if (local)
        return pcm_set_bits (arg);
       return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));
@@ -170,7 +200,9 @@ pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
        return pcm_bits;
       return IOCTL_OUT (arg, pcm_bits);
 
-    case SOUND_PCM_WRITE_FILTER:       /* NOT YET IMPLEMENTED */
+    case SOUND_PCM_WRITE_FILTER:       /*
+                                        * NOT YET IMPLEMENTED
+                                        */
       if (IOCTL_IN (arg) > 1)
        return IOCTL_OUT (arg, RET_ERROR (EINVAL));
       break;
@@ -205,7 +237,7 @@ pas_pcm_open (int dev, int mode)
   if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
     return err;
 
-  if (!DMAbuf_open_dma (dev))
+  if (DMAbuf_open_dma (dev) < 0)
     {
       pas_remove_intr (PAS_PCM_INTRBITS);
       return RET_ERROR (EBUSY);
@@ -242,13 +274,15 @@ pas_pcm_output_block (int dev, unsigned long buf, int count,
   TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
 
   cnt = count;
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     cnt >>= 1;
 
-  if (sound_dma_automode[dev] &&
+  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == pcm_count)
-    return;                    /* Auto mode on. No need to react */
+    return;                    /*
+                                * Auto mode on. No need to react
+                                */
 
   DISABLE_INTR (flags);
 
@@ -258,7 +292,7 @@ pas_pcm_output_block (int dev, unsigned long buf, int count,
   if (restart_dma)
     DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     count >>= 1;
 
   if (count != pcm_count)
@@ -289,20 +323,22 @@ pas_pcm_start_input (int dev, unsigned long buf, int count,
   TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
 
   cnt = count;
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     cnt >>= 1;
 
-  if (sound_dma_automode[my_devnum] &&
+  if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == pcm_count)
-    return;                    /* Auto mode on. No need to react */
+    return;                    /*
+                                * Auto mode on. No need to react
+                                */
 
   DISABLE_INTR (flags);
 
   if (restart_dma)
     DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     count >>= 1;
 
   if (count != pcm_count)
@@ -337,7 +373,9 @@ pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
 static struct audio_operations pas_pcm_operations =
 {
   "Pro Audio Spectrum",
-  NOTHING_SPECIAL,
+  DMA_AUTOMODE,
+  AFMT_U8 | AFMT_S16_LE,
+  NULL,
   pas_pcm_open,
   pas_pcm_close,
   pas_pcm_output_block,
@@ -346,9 +384,9 @@ static struct audio_operations pas_pcm_operations =
   pas_pcm_prepare_for_input,
   pas_pcm_prepare_for_output,
   pas_pcm_reset,
-  pas_pcm_reset,               /* halt_xfer */
-  NULL,                                /* has_output_drained */
-  NULL                         /* copy_from_user */
+  pas_pcm_reset,
+  NULL,
+  NULL
 };
 
 long
@@ -362,28 +400,12 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
 
   pcm_set_speed (DSP_DEFAULT_SPEED);
 
-  if (num_dspdevs < MAX_DSP_DEV)
+  if (num_audiodevs < MAX_AUDIO_DEV)
     {
-      dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
-      sound_dsp_dmachan[my_devnum] = hw_config->dma;
-#ifndef PAS_NO_AUTODMA
-      if (hw_config->dma > 3)
-       {
-         sound_buffcounts[my_devnum] = 1;
-         sound_buffsizes[my_devnum] = 2 * 65536;
-         sound_dma_automode[my_devnum] = 1;
-       }
-      else
-       {
-         sound_buffcounts[my_devnum] = 1;
-         sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
-         sound_dma_automode[my_devnum] = 1;
-       }
-#else
-      sound_buffcounts[my_devnum] = 2;
-      sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
-      sound_dma_automode[my_devnum] = 0;
-#endif
+      audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;
+      audio_devs[my_devnum]->dmachan = hw_config->dma;
+      audio_devs[my_devnum]->buffcount = 1;
+      audio_devs[my_devnum]->buffsize = 2 * DSP_BUFFSIZE;
     }
   else
     printk ("PAS2: Too many PCM devices available\n");
@@ -394,14 +416,16 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
 void
 pas_pcm_interrupt (unsigned char status, int cause)
 {
-  if (cause == 1)              /* PCM buffer done */
+  if (cause == 1)              /*
+                                * PCM buffer done
+                                */
     {
       /*
        * Halt the PCM first. Otherwise we don't have time to start a new
        * block before the PCM chip proceeds to the next sample
        */
 
-      if (!sound_dma_automode[my_devnum])
+      if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE))
        {
          pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
                     PCM_CONTROL);
index 042d42d4067cd42b57f2567ec0adfed11d832854..a77626609106a7144da657fab03a54bf68669ca6 100644 (file)
@@ -67,7 +67,9 @@ void
 pmgr_release (int dev)
 {
 
-  if (mbox[dev])               /* Killed in action. Inform the client */
+  if (mbox[dev])               /*
+                                * Killed in action. Inform the client
+                                */
     {
 
       mbox[dev]->key = PM_ERROR;
diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c
new file mode 100644 (file)
index 0000000..6a0e7a8
--- /dev/null
@@ -0,0 +1,924 @@
+/* Marc.Hoffman@analog.com
+
+   This is a pss driver.
+
+   it is based on Greg.Yukna@analog.com @file{host} for DOG
+
+   Unfortunately I can't distribute the ld file needed to
+   make the pss card to emulate the SB stuff.
+
+   I have provided a simple interface to the PSS unlike the
+   DOG version.  to download a new algorithim just cat it to
+   /dev/pss 14,9.
+
+   You really need to rebuild this with the synth.ld file
+
+   get the <synth>.ld from your dos directory maybe
+   voyetra\dsp001.ld
+
+   ld2inc < synth.ld > synth-ld.h
+   (make config does the same).
+
+   rebuild
+
+   Okay if you blow things away no problem just
+
+   main(){ioctl(open("/dev/pss"),SNDCTL_PSS_RESET)};
+
+   and everything will be okay.
+
+   At first I was going to wory about applications that were using
+   the sound stuff and disallow the use of /dev/pss.  But for
+   now I figured it doesn't matter.
+
+   And if you change algos all the other applications running die off
+   due to DMA problems.  Yeah just pull the plug and watch em die.
+
+   If the registers get hosed
+   main(){ioctl(open("/dev/pss"),SNDCTL_PSS_SETUP_REGISTERS)};
+
+   Probably everything else can be done via mmap
+
+   Oh if you want to develope code for the ADSP-21xx or Program the
+   1848 just send me mail and I will hook you up.
+
+               marc.hoffman@analog.com
+
+   */
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS)
+
+#ifndef PSS_MSS_BASE
+#define PSS_MSS_BASE 0
+#endif
+
+#ifndef PSS_MPU_BASE
+#define PSS_MPU_BASE 0
+#endif
+
+#ifndef PSS_MPU_IRQ
+#define PSS_MPU_IRQ 0
+#endif
+
+#undef DEB
+#define DEB(x) x
+
+#include "pss.h"
+
+static int      pss_ok = 0;
+static int      sb_ok = 0;
+
+static int      pss_base;
+static int      pss_irq;
+static int      pss_dma;
+
+static int      gamePort = 0;
+
+static int      sbInt;
+static int      cdPol;
+static int      cdAddr = 0;    /* 0x340;       */
+static int      cdInt = 10;
+
+/* Define these by hand in local.h */
+static int      wssAddr = PSS_MSS_BASE;
+static int      midiAddr = PSS_MPU_BASE;
+static int      midiInt = PSS_MPU_IRQ;
+
+static int      SoundPortAddress;
+static int      SoundPortData;
+static int      speaker = 1;
+
+
+static struct pss_speaker default_speaker =
+{0, 0, 0, PSS_STEREO};
+
+DEFINE_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
+
+#include "synth-ld.h"
+
+static int      pss_download_boot (unsigned char *block, int size);
+static int      pss_reset_dsp (void);
+
+static inline void
+pss_outpw (unsigned short port, unsigned short value)
+{
+  __asm__         __volatile__ ("outw %w0, %w1"
+                               :       /* no outputs */
+                               :"a"            (value), "d" (port));
+}
+
+static inline unsigned int
+pss_inpw (unsigned short port)
+{
+  unsigned int    _v;
+  __asm__         __volatile__ ("inw %w1,%w0"
+                               :"=a"           (_v):"d" (port), "0" (0));
+
+  return _v;
+}
+
+static void
+PSS_write (int data)
+{
+  int             i, limit;
+
+  limit = GET_TIME () + 10;    /* The timeout is 0.1 secods */
+  /*
+   * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
+   * called while interrupts are disabled. This means that the timer is
+   * disabled also. However the timeout situation is a abnormal condition.
+   * Normally the DSP should be ready to accept commands after just couple of
+   * loops.
+   */
+
+  for (i = 0; i < 5000000 && GET_TIME () < limit; i++)
+    {
+      if (pss_inpw (pss_base + PSS_STATUS) & PSS_WRITE_EMPTY)
+       {
+         pss_outpw (pss_base + PSS_DATA, data);
+         return;
+       }
+    }
+  printk ("PSS: DSP Command (%04x) Timeout.\n", data);
+  printk ("IRQ conflict???\n");
+}
+
+
+static void
+pss_setaddr (int addr, int configAddr)
+{
+  int             val;
+
+  val = pss_inpw (configAddr);
+  val &= ADDR_MASK;
+  val |= (addr << 4);
+  pss_outpw (configAddr, val);
+}
+
+/*_____ pss_checkint
+         This function tests an interrupt number to see if
+        it is availible. It takes the interrupt button
+        as it's argument and returns TRUE if the interrupt
+        is ok.
+*/
+static int
+pss_checkint (int intNum)
+{
+  int             val;
+  int             ret;
+  int             i;
+
+  /*_____ Set the interrupt bits */
+  switch (intNum)
+    {
+    case 3:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_3_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 5:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_5_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 7:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_7_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 9:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_9_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 10:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_10_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 11:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_11_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    case 12:
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      val &= INT_MASK;
+      val |= INT_12_BITS;
+      pss_outpw (pss_base + PSS_CONFIG, val);
+      break;
+    default:
+      printk ("unknown interupt selected. %d\n", intNum);
+      return 0;
+    }
+
+  /*_____ Set the interrupt test bit */
+  val = pss_inpw (pss_base + PSS_CONFIG);
+  val |= INT_TEST_BIT;
+  pss_outpw (pss_base + PSS_CONFIG, val);
+
+  /*_____ Check if the interrupt is in use */
+  /*_____ Do it a few times in case there is a delay */
+  ret = 0;
+  for (i = 0; i < 5; i++)
+    {
+      val = pss_inpw (pss_base + PSS_CONFIG);
+      if (val & INT_TEST_PASS)
+       {
+         ret = 1;
+         break;
+       }
+    }
+  /*_____ Clear the Test bit and the interrupt bits */
+  val = pss_inpw (pss_base + PSS_CONFIG);
+  val &= INT_TEST_BIT_MASK;
+  val &= INT_MASK;
+  pss_outpw (pss_base + PSS_CONFIG, val);
+  return (ret);
+}
+
+/*____ pss_setint
+        This function sets the correct bits in the
+       configuration register to
+       enable the chosen interrupt.
+*/
+static void
+pss_setint (int intNum, int configAddress)
+{
+  int             val;
+
+  switch (intNum)
+    {
+    case 0:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      pss_outpw (configAddress, val);
+      break;
+    case 3:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_3_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 5:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_5_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 7:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_7_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 9:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_9_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 10:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_10_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 11:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_11_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    case 12:
+      val = pss_inpw (configAddress);
+      val &= INT_MASK;
+      val |= INT_12_BITS;
+      pss_outpw (configAddress, val);
+      break;
+    default:
+      printk ("pss_setint unkown int\n");
+    }
+}
+
+
+/*____ pss_setsbint
+        This function sets the correct bits in the
+       SoundBlaster configuration PSS register to
+       enable the chosen interrupt.
+       It takes a interrupt button as its argument.
+*/
+static void
+pss_setsbint (int intNum)
+{
+  int             val;
+  int             sbConfigAddress;
+
+  sbConfigAddress = pss_base + SB_CONFIG;
+  switch (intNum)
+    {
+    case 3:
+      val = pss_inpw (sbConfigAddress);
+      val &= INT_MASK;
+      val |= INT_3_BITS;
+      pss_outpw (sbConfigAddress, val);
+      break;
+    case 5:
+      val = pss_inpw (sbConfigAddress);
+      val &= INT_MASK;
+      val |= INT_5_BITS;
+      pss_outpw (sbConfigAddress, val);
+      break;
+    case 7:
+      val = pss_inpw (sbConfigAddress);
+      val &= INT_MASK;
+      val |= INT_7_BITS;
+      pss_outpw (sbConfigAddress, val);
+      break;
+    default:
+      printk ("pss_setsbint: unknown_int\n");
+    }
+}
+
+/*____ pss_setsbdma
+        This function sets the correct bits in the
+       SoundBlaster configuration PSS register to
+       enable the chosen DMA channel.
+       It takes a DMA button as its argument.
+*/
+static void
+pss_setsbdma (int dmaNum)
+{
+  int             val;
+  int             sbConfigAddress;
+
+  sbConfigAddress = pss_base + SB_CONFIG;
+
+  switch (dmaNum)
+    {
+    case 1:
+      val = pss_inpw (sbConfigAddress);
+      val &= DMA_MASK;
+      val |= DMA_1_BITS;
+      pss_outpw (sbConfigAddress, val);
+      break;
+    default:
+      printk ("Personal Sound System ERROR! pss_setsbdma: unknown_dma\n");
+    }
+}
+
+/*____ pss_setwssdma
+        This function sets the correct bits in the
+       WSS configuration PSS register to
+       enable the chosen DMA channel.
+       It takes a DMA button as its argument.
+*/
+static void
+pss_setwssdma (int dmaNum)
+{
+  int             val;
+  int             wssConfigAddress;
+
+  wssConfigAddress = pss_base + PSS_WSS_CONFIG;
+
+  switch (dmaNum)
+    {
+    case 0:
+      val = pss_inpw (wssConfigAddress);
+      val &= DMA_MASK;
+      val |= DMA_0_BITS;
+      pss_outpw (wssConfigAddress, val);
+      break;
+    case 1:
+      val = pss_inpw (wssConfigAddress);
+      val &= DMA_MASK;
+      val |= DMA_1_BITS;
+      pss_outpw (wssConfigAddress, val);
+      break;
+    case 3:
+      val = pss_inpw (wssConfigAddress);
+      val &= DMA_MASK;
+      val |= DMA_3_BITS;
+      pss_outpw (wssConfigAddress, val);
+      break;
+    default:
+      printk ("Personal Sound System ERROR! pss_setwssdma: unknown_dma\n");
+    }
+}
+
+
+/*_____ SetSpeakerOut
+         This function sets the Volume, Bass, Treble and Mode of
+        the speaker out channel.
+        */
+void
+pss_setspeaker (struct pss_speaker *spk)
+{
+  PSS_write (SET_MASTER_COMMAND);
+  if (spk->volume > PHILLIPS_VOL_MAX)
+    spk->volume = PHILLIPS_VOL_MAX;
+  if (spk->volume < PHILLIPS_VOL_MIN)
+    spk->volume = PHILLIPS_VOL_MIN;
+
+  PSS_write (MASTER_VOLUME_LEFT
+            | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
+  PSS_write (SET_MASTER_COMMAND);
+  PSS_write (MASTER_VOLUME_RIGHT
+            | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
+
+  if (spk->bass > PHILLIPS_BASS_MAX)
+    spk->bass = PHILLIPS_BASS_MAX;
+  if (spk->bass < PHILLIPS_BASS_MIN)
+    spk->bass = PHILLIPS_BASS_MIN;
+  PSS_write (SET_MASTER_COMMAND);
+  PSS_write (MASTER_BASS
+            | (PHILLIPS_BASS_CONSTANT + spk->bass / PHILLIPS_BASS_STEP));
+
+  if (spk->treb > PHILLIPS_TREBLE_MAX)
+    spk->treb = PHILLIPS_TREBLE_MAX;
+  if (spk->treb < PHILLIPS_TREBLE_MIN)
+    spk->treb = PHILLIPS_TREBLE_MIN;
+  PSS_write (SET_MASTER_COMMAND);
+  PSS_write (MASTER_TREBLE
+          | (PHILLIPS_TREBLE_CONSTANT + spk->treb / PHILLIPS_TREBLE_STEP));
+
+  PSS_write (SET_MASTER_COMMAND);
+  PSS_write (MASTER_SWITCH | spk->mode);
+}
+
+static void
+pss_init1848 (void)
+{
+  /*_____ Wait for 1848 to init */
+  while (INB (SoundPortAddress) & SP_IN_INIT);
+
+  /*_____ Wait for 1848 to autocal */
+  OUTB (SoundPortAddress, SP_TEST_AND_INIT);
+  while (INB (SoundPortData) & AUTO_CAL_IN_PROG);
+}
+
+static int
+pss_configure_registers_to_look_like_sb (void)
+{
+  pss_setaddr (wssAddr, pss_base + PSS_WSS_CONFIG);
+
+  SoundPortAddress = wssAddr + 4;
+  SoundPortData = wssAddr + 5;
+
+  DEB (printk ("Turning Game Port %s.\n",
+              gamePort ? "On" : "Off"));
+
+  /*_____ Turn on the Game port */
+  if (gamePort)
+    pss_outpw (pss_base + PSS_STATUS,
+              pss_inpw (pss_base + PSS_STATUS) | GAME_BIT);
+  else
+    pss_outpw (pss_base + PSS_STATUS,
+              pss_inpw (pss_base + PSS_STATUS) & GAME_BIT_MASK);
+
+
+  DEB (printk ("PSS attaching base %x irq %d dma %d\n",
+              pss_base, pss_irq, pss_dma));
+
+  /* Check if sb is enabled if it is check the interrupt */
+  pss_outpw (pss_base + SB_CONFIG, 0);
+
+  if (pss_irq != 0)
+    {
+      DEB (printk ("PSS Emulating Sound Blaster ADDR %04x\n", pss_base));
+      DEB (printk ("PSS SBC: attaching base %x irq %d dma %d\n",
+                  SBC_BASE, SBC_IRQ, SBC_DMA));
+
+      if (pss_checkint (SBC_IRQ) == 0)
+       {
+         printk ("PSS! attach: int_error\n");
+         return 0;
+       }
+
+      pss_setsbint (SBC_IRQ);
+      pss_setsbdma (SBC_DMA);
+      sb_ok = 1;
+    }
+  else
+    {
+      sb_ok = 0;
+      printk ("PSS: sound blaster error init\n");
+    }
+
+  /* Check if cd is enabled if it is check the interrupt */
+  pss_outpw (pss_base + CD_CONFIG, 0);
+
+  if (cdAddr != 0)
+    {
+      DEB (printk ("PSS:CD drive %x irq: %d", cdAddr, cdInt));
+      if (cdInt != 0)
+       {
+         if (pss_checkint (cdInt) == 0)
+           {
+             printk ("Can't allocate cdInt %d\n", cdInt);
+           }
+         else
+           {
+             int             val;
+
+             printk ("CD poll ");
+             pss_setaddr (cdAddr, pss_base + CD_CONFIG);
+             pss_setint (cdInt, pss_base + CD_CONFIG);
+
+             /* set the correct bit in the
+                configuration register to
+                set the irq polarity for the CD-Rom.
+                NOTE: This bit is in the address config
+                field, It must be configured after setting
+                the CD-ROM ADDRESS!!! */
+             val = pss_inpw (pss_base + CD_CONFIG);
+             pss_outpw (pss_base + CD_CONFIG, 0);
+             val &= CD_POL_MASK;
+             if (cdPol)
+               val |= CD_POL_BIT;
+             pss_outpw (pss_base + CD_CONFIG, val);
+           }
+       }
+    }
+
+  /* Check if midi is enabled if it is check the interrupt */
+  pss_outpw (pss_base + MIDI_CONFIG, 0);
+  if (midiAddr != 0)
+    {
+      printk ("midi init %x %d\n", midiAddr, midiInt);
+      if (pss_checkint (midiInt) == 0)
+       {
+         printk ("midi init int error %x %d\n", midiAddr, midiInt);
+       }
+      else
+       {
+         pss_setaddr (midiAddr, pss_base + MIDI_CONFIG);
+         pss_setint (midiInt, pss_base + MIDI_CONFIG);
+       }
+    }
+  return 1;
+}
+
+long
+attach_pss (long mem_start, struct address_info *hw_config)
+{
+  if (pss_ok)
+    {
+      if (hw_config)
+       {
+         printk (" <PSS-ESC614>");
+       }
+
+      return mem_start;
+    }
+
+  pss_ok = 1;
+
+  if (pss_configure_registers_to_look_like_sb () == 0)
+    return mem_start;
+
+  if (sb_ok)
+    if (pss_synthLen
+       && pss_download_boot (pss_synth, pss_synthLen))
+      {
+       if (speaker)
+         pss_setspeaker (&default_speaker);
+       pss_ok = 1;
+      }
+    else
+      pss_reset_dsp ();
+
+  return mem_start;
+}
+
+int
+probe_pss (struct address_info *hw_config)
+{
+  pss_base = hw_config->io_base;
+  pss_irq = hw_config->irq;
+  pss_dma = hw_config->dma;
+
+  if ((pss_inpw (pss_base + 4) & 0xff00) == 0x4500)
+    {
+      attach_pss (0, hw_config);
+      return 1;
+    }
+  printk (" fail base %x irq %d dma %d\n", pss_base, pss_irq, pss_dma);
+  return 0;
+}
+
+
+static int
+pss_reattach (void)
+{
+  pss_ok = 0;
+  attach_pss (0, 0);
+  return 1;
+}
+
+static int
+pss_reset_dsp ()
+{
+  unsigned long   i, limit = GET_TIME () + 10;
+
+  pss_outpw (pss_base + PSS_CONTROL, 0x2000);
+
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    pss_inpw (pss_base + PSS_CONTROL);
+
+  pss_outpw (pss_base + PSS_CONTROL, 0x0000);
+
+  return 1;
+}
+
+
+static int
+pss_download_boot (unsigned char *block, int size)
+{
+  int             i, limit, val, count;
+
+  printk ("PSS: downloading boot code synth.ld... ");
+
+  /*_____ Warn DSP software that a boot is coming */
+  pss_outpw (pss_base + PSS_DATA, 0x00fe);
+
+  limit = GET_TIME () + 10;
+
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    if (pss_inpw (pss_base + PSS_DATA) == 0x5500)
+      break;
+
+  pss_outpw (pss_base + PSS_DATA, *block++);
+
+  pss_reset_dsp ();
+  printk ("start ");
+
+  count = 1;
+  while (1)
+    {
+      int             j;
+
+      for (j = 0; j < 327670; j++)
+       {
+         /*_____ Wait for BG to appear */
+         if (pss_inpw (pss_base + PSS_STATUS) & PSS_FLAG3)
+           break;
+       }
+
+      if (j == 327670)
+       {
+         /* It's ok we timed out when the file was empty */
+         if (count >= size)
+           break;
+         else
+           {
+             printk ("\nPSS: DownLoad timeout problems, byte %d=%d\n",
+                     count, size);
+             return 0;
+           }
+       }
+      /*_____ Send the next byte */
+      pss_outpw (pss_base + PSS_DATA, *block++);
+      count++;
+    }
+
+  /*_____ Why */
+  pss_outpw (pss_base + PSS_DATA, 0);
+
+  limit = GET_TIME () + 10;
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    val = pss_inpw (pss_base + PSS_STATUS);
+
+  printk ("downloaded\n");
+
+  limit = GET_TIME () + 10;
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    {
+      val = pss_inpw (pss_base + PSS_STATUS);
+      if (val & 0x4000)
+       break;
+    }
+
+  /* now read the version */
+  for (i = 0; i < 32000; i++)
+    {
+      val = pss_inpw (pss_base + PSS_STATUS_REG);
+      if (val & PSS_READ_FULL)
+       break;
+    }
+  if (i == 32000)
+    return 0;
+
+  val = pss_inpw (pss_base + PSS_DATA_REG);
+
+  return 1;
+}
+
+
+/* The following is a simple device driver for the pss.
+   All I really care about is comunication to and from the pss.
+
+   The ability to reinitialize the <synth.ld>  This will be
+   default when release is choosen.
+
+   SNDCTL_PSS_DOWNLOAD:
+
+   Okay we need to creat new minor numbers for the
+   DOWNLOAD functionality.
+
+   14,0x19 -- /dev/pssld where a read operation would output the
+                         current ld to user space
+                         where a write operation would effectively
+                        download a new ld.
+
+   14,0x09 -- /dev/psecho  would open up a comunication path to the
+                         esc614 asic.  Given the ability to send
+                        messages to the asic and recive messages too.
+
+                        All messages would get read and written in the
+                        same manner.  It would be up to the application
+                        and the ld to maintain a relationship
+                        of what the messages mean.
+                       
+                        for this device we need to implement select. */
+#define CODE_BUFFER_LEN (64*1024)
+static char    *code_buffer;
+static int      code_length;
+
+static int      lock_pss = 0;
+
+int
+pss_open (int dev, struct fileinfo *file)
+{
+  int             mode;
+
+  DEB (printk ("pss_open\n"));
+
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  if (lock_pss)
+    return 0;
+
+  lock_pss = 1;
+
+  dev = dev >> 4;
+  mode = file->mode & O_ACCMODE;
+  if (mode == O_WRONLY)
+    {
+      printk ("pss-open for WRONLY\n");
+      code_length = 0;
+    }
+
+  RESET_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
+  return 1;
+}
+
+void
+pss_release (int dev, struct fileinfo *file)
+{
+  int             mode;
+
+  DEB (printk ("pss_release\n"));
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  dev = dev >> 4;
+  mode = file->mode & O_ACCMODE;
+  if (mode == O_WRONLY && code_length > 0)
+    {
+#ifdef linux
+      /* This just allows interrupts while the conversion is running */
+      __asm__ ("sti");
+#endif
+      if (!pss_download_boot (code_buffer, code_length))
+       {
+         pss_reattach ();
+       }
+    }
+  lock_pss = 0;
+}
+
+int
+pss_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+  int             c, p;
+
+  DEB (printk ("pss_read\n"));
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  dev = dev >> 4;
+  p = 0;
+  c = count;
+
+  return count - c;
+}
+
+int
+pss_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+  DEB (printk ("pss_write\n"));
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+  dev = dev >> 4;
+
+  if (count)                   /* Flush output */
+    {
+      COPY_FROM_USER (&code_buffer[code_length], buf, 0, count);
+      code_length += count;
+    }
+  return count;
+}
+
+
+int
+pss_ioctl (int dev, struct fileinfo *file,
+          unsigned int cmd, unsigned int arg)
+{
+  DEB (printk ("pss_ioctl dev=%d cmd=%x\n", dev, cmd));
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  dev = dev >> 4;
+
+  switch (cmd)
+    {
+    case SNDCTL_PSS_RESET:
+      pss_reattach ();
+      return 1;
+
+    case SNDCTL_PSS_SETUP_REGISTERS:
+      pss_configure_registers_to_look_like_sb ();
+      return 1;
+
+    case SNDCTL_PSS_SPEAKER:
+      {
+       struct pss_speaker params;
+       COPY_FROM_USER (&params, (char *) arg, 0, sizeof (struct pss_speaker));
+
+       pss_setspeaker (&params);
+       return 0;
+      }
+    default:
+      return RET_ERROR (EIO);
+    }
+}
+
+/* This is going to be used to implement
+   waiting on messages sent from the DSP and to the
+   DSP when comunication is used via the pss directly.
+
+   We need to find out if the pss can generate a diffrent
+   interupt other than the one it has been setup for.
+
+   This way we can carry on a conversation with the pss
+   on a seprate chanel.  This would be usefull for debugging. */
+
+pss_select (int dev, struct fileinfo * file, int sel_type, select_table * wait)
+{
+  return 0;
+  if (pss_ok == 0)
+    return RET_ERROR (EIO);
+
+  dev = dev >> 4;
+
+  switch (sel_type)
+    {
+    case SEL_IN:
+      select_wait (&pss_sleeper, wait);
+      return 0;
+      break;
+
+    case SEL_OUT:
+      select_wait (&pss_sleeper, wait);
+      return 0;
+      break;
+
+    case SEL_EX:
+      return 0;
+    }
+
+  return 0;
+}
+
+long
+pss_init (long mem_start)
+{
+  DEB (printk ("pss_init\n"));
+  if (pss_ok)
+    {
+      code_buffer = mem_start;
+      mem_start += CODE_BUFFER_LEN;
+    }
+  return mem_start;
+}
+
+#endif
diff --git a/drivers/sound/pss.h b/drivers/sound/pss.h
new file mode 100644 (file)
index 0000000..e020af6
--- /dev/null
@@ -0,0 +1,371 @@
+/******************************************************************************
+
+       def.h
+
+       Version 1.3     11/2/93
+
+       Copyright (c) 1993 Analog Devices Inc. All rights reserved
+
+******************************************************************************/
+/* Port offsets from base port for Sound Blaster DSP */
+#define DSP_PORT_CMSD0      0x00  /* C/MS music voice 1-6 data port, write only */
+#define DSP_PORT_CMSR0      0x01  /* C/MS music voice 1-6 register port, write only */
+#define DSP_PORT_CMSD1      0x02  /* C/MS music voice 7-12 data port, write only */
+#define DSP_PORT_CMSR1      0x03  /* C/MS music voice 7-12 register port, write only */
+
+#define DSP_PORT_STATUS     0x04  /* DSP Status bits, read only */
+#define DSP_PORT_CONTROL    0x04  /* DSP Control bits, write only */
+#define DSP_PORT_DATA_LSB   0x05  /* Read or write LSB of 16 bit data */
+
+
+#define DSP_PORT_RESET      0x06  /* DSP Reset, write only */
+#define DSP_PORT_07h        0x07  /* reserved port */
+
+#define DSP_PORT_FMD0       0x08  /* FM music data/status port, read/write  */
+#define DSP_PORT_FMR0       0x09  /* FM music data/status port, write only */
+
+#define DSP_PORT_RDDATA     0x0A  /* DSP Read data, read only reading signals DSP */
+#define DSP_PORT_0Bh        0x0B  /* reserved port */
+#define DSP_PORT_WRDATA     0x0C  /* DSP Write data or command, write */
+#define DSP_PORT_WRBUSY     0x0C  /* DSP Write buffer status (bit 7), read */
+#define DSP_PORT_0Dh        0x0D  /* reserved port */
+#define DSP_PORT_DATAAVAIL  0x0E  /* DSP Data available status (bit 7), read only */
+#define DSP_PORT_INTERFACE  0x0E  /* Sets DMA Channel and Interrupt, write only */
+#define DSP_PORT_0Fh        0x0F  /* reserved port (used on Pro cards) */
+
+#define ADDR_MASK   0x003f
+
+#define INT_MASK    0xffc7
+#define INT_3_BITS  0x0008
+#define INT_5_BITS  0x0010
+#define INT_7_BITS  0x0018
+#define INT_9_BITS  0x0020
+#define INT_10_BITS 0x0028
+#define INT_11_BITS 0x0030
+#define INT_12_BITS 0x0038
+
+#define GAME_BIT      0x0400
+#define GAME_BIT_MASK 0xfbff
+
+#define INT_TEST_BIT 0x0200
+#define INT_TEST_PASS 0x0100
+#define INT_TEST_BIT_MASK 0xFDFF
+
+#define DMA_MASK    0xfff8
+#define DMA_0_BITS  0x0001
+#define DMA_1_BITS  0x0002
+#define DMA_3_BITS  0x0003
+#define DMA_5_BITS  0x0004
+#define DMA_6_BITS  0x0005
+#define DMA_7_BITS  0x0006
+
+#define DMA_TEST_BIT  0x0080
+#define DMA_TEST_PASS 0x0040
+#define DMA_TEST_BIT_MASK 0xFF7F
+
+
+/* Echo DSP Flags */
+
+#define DSP_FLAG3     0x10
+#define DSP_FLAG2     0x08
+#define DSP_FLAG1     0x80
+#define DSP_FLAG0     0x40
+
+#define PSS_CONFIG    0x10
+#define PSS_WSS_CONFIG    0x12
+#define SB_CONFIG     0x14
+#define MIDI_CONFIG   0x18
+#define CD_CONFIG     0x16
+#define UART_CONFIG   0x1a
+
+#define PSS_DATA      0x00
+#define PSS_STATUS    0x02
+#define PSS_CONTROL   0x02
+#define PSS_ID_VERS   0x04
+
+#define PSS_FLAG3     0x0800
+#define PSS_FLAG2     0x0400
+#define PSS_FLAG1     0x1000
+#define PSS_FLAG0     0x0800
+
+/*_____ WSS defines */
+#define WSS_BASE_ADDRESS 0x530
+#define WSS_CONFIG       0x0
+#define WSS_VERSION      0x03
+#define WSS_SP0          0x04
+#define WSS_SP1          0x05
+#define WSS_SP2          0x06
+#define WSS_SP3          0x07
+
+/*_____ SoundPort register addresses */
+
+#define SP_LIN_SOURCE_CTRL   0x00
+#define SP_RIN_SOURCE_CTRL   0x01
+#define SP_LIN_GAIN_CTRL   0x10
+#define SP_RIN_GAIN_CTRL   0x11
+#define SP_LAUX1_CTRL      0x02
+#define SP_RAUX1_CTRL      0x03
+#define SP_LAUX2_CTRL      0x04
+#define SP_RAUX2_CTRL      0x05
+#define SP_LOUT_CTRL       0x06
+#define SP_ROUT_CTRL       0x07
+#define SP_CLK_FORMAT      0x48
+#define SP_INT_CONF        0x09
+#define SP_INT_CONF_MCE    0x49
+#define SP_PIN_CTRL        0x0a
+#define SP_TEST_INIT       0x0b
+#define SP_MISC_CTRL       0x0c
+#define SP_MIX_CTRL        0x0d
+#define SP_DMA_UCNT        0x0e
+#define SP_DMA_LCNT        0x0f
+
+/*_____ Gain constants  */
+
+#define GAIN_0      0x00
+#define GAIN_1_5    0x01
+#define GAIN_3      0x02
+#define GAIN_4_5    0x03
+#define GAIN_6      0x04
+#define GAIN_7_5    0x05
+#define GAIN_9      0x06
+#define GAIN_10_5   0x07
+#define GAIN_12     0x08
+#define GAIN_13_5   0x09
+#define GAIN_15     0x0a
+#define GAIN_16_5   0x0b
+#define GAIN_18     0x0c
+#define GAIN_19_5   0x0d
+#define GAIN_21     0x0e
+#define GAIN_22_5   0x0f
+#define MUTE       0XFFFF
+
+/*_____ Attenuation constants  */
+
+#define ATTEN_0      0x00
+#define ATTEN_1_5    0x01
+#define ATTEN_3      0x02
+#define ATTEN_4_5    0x03
+#define ATTEN_6      0x04
+#define ATTEN_7_5    0x05
+#define ATTEN_9      0x06
+#define ATTEN_10_5   0x07
+#define ATTEN_12     0x08
+#define ATTEN_13_5   0x09
+#define ATTEN_15     0x0a
+#define ATTEN_16_5   0x0b
+#define ATTEN_18     0x0c
+#define ATTEN_19_5   0x0d
+#define ATTEN_21     0x0e
+#define ATTEN_22_5   0x0f
+
+
+#define PSS_WRITE_EMPTY 0x8000
+
+#define CD_POL_MASK 0xFFBF
+#define CD_POL_BIT  0x0040
+
+
+
+/******************************************************************************
+
+       host.h
+
+       Version 1.2     9/27/93
+
+       Copyright (c) 1993 Analog Devices Inc. All rights reserved
+
+******************************************************************************/
+#define SB_WRITE_FULL    0x80
+#define SB_READ_FULL     0x80
+#define SB_WRITE_STATUS  0x0C
+#define SB_READ_STATUS   0x0E
+#define SB_READ_DATA     0x0A
+#define SB_WRITE_DATA    0x0C
+
+#define PSS_DATA_REG     0x00
+#define PSS_STATUS_REG   0x02
+#define PSS_WRITE_EMPTY  0x8000
+#define PSS_READ_FULL    0x4000
+
+/*_____ 1848 Sound Port bit defines */
+
+#define SP_IN_INIT            0x80
+#define MODE_CHANGE_ENABLE    0x40
+#define MODE_CHANGE_MASK      0xbf
+#define TRANSFER_DISABLE      0x20
+#define TRANSFER_DISABLE_MASK 0xdf
+#define ADDRESS_MASK          0xf0
+
+/*_____ Status bits */
+#define INTERRUPT_STATUS      0x01
+#define PLAYBACK_READY        0x02
+#define PLAYBACK_LEFT         0x04
+/*_____ pbright is not left */
+#define PLAYBACK_UPPER        0x08
+/*_____ bplower is not upper */
+
+#define SAMPLE_OVERRUN        0x10
+#define SAMPLE_UNDERRUN       0x10
+#define CAPTURE_READY         0x20
+#define CAPTURE_LEFT          0x40
+/*_____ cpright is not left */
+#define CAPTURE_UPPER         0x08
+/*_____ cplower is not upper */
+
+/*_____ Input & Output regs bits */
+#define LINE_INPUT            0x80
+#define AUX_INPUT             0x40
+#define MIC_INPUT             0x80
+#define MIXED_DAC_INPUT       0xC0
+#define INPUT_GAIN_MASK       0xf0
+#define INPUT_MIC_GAIN_ENABLE 0x20
+#define INPUT_MIC_GAIN_MASK   0xdf
+#define INPUT_SOURCE_MASK     0x3f
+#define AUX_INPUT_ATTEN_MASK  0xf0
+#define AUX_INPUT_MUTE        0x80
+#define AUX_INPUT_MUTE_MASK   0x7f
+#define OUTPUT_MUTE           0x80
+#define OUTPUT_MUTE_MASK      0x7f
+#define OUTPUT_ATTEN_MASK     0xc0
+
+/*_____ Clock and Data format reg bits */
+#define CLOCK_SELECT_MASK     0xfe
+#define CLOCK_XTAL2           0x01
+#define CLOCK_XTAL1           0x00
+#define CLOCK_FREQ_MASK       0xf1
+#define STEREO_MONO_MASK      0xef
+#define STEREO                0x10
+#define AUDIO_MONO            0x00
+#define LINEAR_COMP_MASK      0xdf
+#define LINEAR                0x00
+#define COMPANDED             0x20
+#define FORMAT_MASK           0xbf
+#define PCM                   0x00
+#define ULAW                  0x00
+#define TWOS_COMP             0x40
+#define ALAW                  0x40
+
+/*_____ Interface Configuration reg bits */
+#define PLAYBACK_ENABLE       0x01
+#define PLAYBACK_ENABLE_MASK  0xfe
+#define CAPTURE_ENABLE        0x02
+#define CAPTURE_ENABLE_MASK   0xfd
+#define SINGLE_DMA            0x04
+#define SINGLE_DMA_MASK       0xfb
+#define DUAL_DMA              0x00
+#define AUTO_CAL_ENABLE       0x08
+#define AUTO_CAL_DISABLE_MASK 0xf7
+#define PLAYBACK_PIO_ENABLE   0x40
+#define PLAYBACK_DMA_MASK     0xbf
+#define CAPTURE_PIO_ENABLE    0x80
+#define CAPTURE_DMA_MASK      0x7f
+
+/*_____ Pin control bits */
+#define INTERRUPT_ENABLE      0x02
+#define INTERRUPT_MASK        0xfd
+
+/*_____ Test and init reg bits */
+#define OVERRANGE_LEFT_MASK   0xfc
+#define OVERRANGE_RIGHT_MASK  0xf3
+#define DATA_REQUEST_STATUS   0x10
+#define AUTO_CAL_IN_PROG      0x20
+#define PLAYBACK_UNDERRUN     0x40
+#define CAPTURE_UNDERRUN      0x80
+
+/*_____ Miscellaneous Control reg bits */
+#define ID_MASK               0xf0
+
+/*_____ Digital Mix Control reg bits */
+#define DIGITAL_MIX1_MUTE_MASK 0xfe
+#define MIX_ATTEN_MASK         0x03
+
+/*_____ 1848 Sound Port reg defines */
+
+#define SP_LEFT_INPUT_CONTROL    0x0
+#define SP_RIGHT_INPUT_CONTROL   0x1
+#define SP_LEFT_AUX1_CONTROL     0x2
+#define SP_RIGHT_AUX1_CONTROL    0x3
+#define SP_LEFT_AUX2_CONTROL     0x4
+#define SP_RIGHT_AUX2_CONTROL    0x5
+#define SP_LEFT_OUTPUT_CONTROL   0x6
+#define SP_RIGHT_OUTPUT_CONTROL  0x7
+#define SP_CLOCK_DATA_FORMAT     0x8
+#define SP_INTERFACE_CONFIG      0x9
+#define SP_PIN_CONTROL           0xA
+#define SP_TEST_AND_INIT         0xB
+#define SP_MISC_INFO             0xC
+#define SP_DIGITAL_MIX           0xD
+#define SP_UPPER_BASE_COUNT      0xE
+#define SP_LOWER_BASE_COUNT      0xF
+
+#define HOST_SP_ADDR (0x534)
+#define HOST_SP_DATA (0x535)
+
+
+/******************************************************************************
+
+       phillips.h
+
+       Version 1.2     9/27/93
+
+       Copyright (c) 1993 Analog Devices Inc. All rights reserved
+
+******************************************************************************/
+/*_____ Phillips control SW defines */
+
+/*_____ Settings and ranges */
+#define VOLUME_MAX   6
+#define VOLUME_MIN (-64)
+#define VOLUME_RANGE 70
+#define VOLUME_STEP  2
+#define BASS_MAX    15
+#define BASS_MIN   (-12)
+#define BASS_STEP    2
+#define BASS_RANGE 27
+#define TREBLE_MAX  12
+#define TREBLE_MIN (-12)
+#define TREBLE_STEP  2
+#define TREBLE_RANGE 24
+
+#define VOLUME_CONSTANT 252
+#define BASS_CONSTANT   246
+#define TREBLE_CONSTANT 246
+
+/*_____ Software commands */
+#define SET_MASTER_COMMAND  0x0010
+#define MASTER_VOLUME_LEFT  0x0000
+#define MASTER_VOLUME_RIGHT 0x0100
+#define MASTER_BASS         0x0200
+#define MASTER_TREBLE       0x0300
+#define MASTER_SWITCH       0x0800
+
+#define STEREO_MODE  0x00ce
+#define PSEUDO_MODE  0x00d6
+#define SPATIAL_MODE 0x00de
+#define MONO_MODE    0x00c6
+
+
+#define PSS_STEREO           0x00ce
+#define PSS_PSEUDO           0x00d6
+#define PSS_SPATIAL          0x00de
+#define PSS_MONO             0x00c6
+
+#define PHILLIPS_VOL_MIN          -64
+#define PHILLIPS_VOL_MAX            6
+#define PHILLIPS_VOL_DELTA         70
+#define PHILLIPS_VOL_INITIAL      -20
+#define PHILLIPS_VOL_CONSTANT     252
+#define PHILLIPS_VOL_STEP           2
+#define PHILLIPS_BASS_MIN         -12
+#define PHILLIPS_BASS_MAX          15
+#define PHILLIPS_BASS_DELTA        27
+#define PHILLIPS_BASS_INITIAL       0
+#define PHILLIPS_BASS_CONSTANT    246
+#define PHILLIPS_BASS_STEP          2
+#define PHILLIPS_TREBLE_MIN       -12
+#define PHILLIPS_TREBLE_MAX        12
+#define PHILLIPS_TREBLE_DELTA      24
+#define PHILLIPS_TREBLE_INITIAL     0
+#define PHILLIPS_TREBLE_CONSTANT  246
+#define PHILLIPS_TREBLE_STEP        2
+
index f9297bca4d7cf01cb1045a8619ca9ccdebe5b154..e3078bca7bf7ee281f3b1435cf2edc70091accc0 100644 (file)
@@ -32,7 +32,7 @@
 #define DEB(x)
 #define DEB1(x)
 /*
  #define DEB_DMARES
* #define DEB_DMARES
  */
 #include "sound_config.h"
 #include "sb.h"
 
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
 
-extern int      sbc_base, sbc_minor, sbc_major;
+extern int      sbc_base;
 
-static int      sb16_dsp_ok = 0;/* Set to 1 after successful initialization */
+static int      sb16_dsp_ok = 0;/*
+
+
+                                        * *  * * Set to 1 after successful *
+                                        * * initialization   */
 static int      dsp_16bit = 0;
 static int      dsp_stereo = 0;
-static int      dsp_current_speed = 8000;      /*DSP_DEFAULT_SPEED; */
+static int      dsp_current_speed = 8000;      /*
+
+
+                                                * *  * * DSP_DEFAULT_SPEED;  */
 static int      dsp_busy = 0;
 static int      dma16, dma8;
 static unsigned long dsp_count = 0;
 
-static int      irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT or
+static int      irq_mode = IMODE_NONE; /*
+
 
-                                          IMODE_NONE */
+                                        * *  * * IMODE_INPUT, IMODE_OUTPUT
+                                        * or * * IMODE_NONE   */
 static int      my_dev = 0;
 
 static volatile int intr_active = 0;
@@ -74,7 +83,9 @@ int             sb_reset_dsp (void);
 static struct audio_operations sb16_dsp_operations =
 {
   "SoundBlaster 16",
-  NOTHING_SPECIAL,
+  DMA_AUTOMODE,
+  AFMT_U8 | AFMT_S16_LE,
+  NULL,
   sb16_dsp_open,
   sb16_dsp_close,
   sb16_dsp_output_block,
@@ -99,79 +110,6 @@ sb_dsp_command01 (unsigned char val)
   return sb_dsp_command (val);
 }
 
-static int
-wait_data_avail (unsigned long t)
-{
-  int             loopc = 5000000;
-
-  t += GET_TIME ();
-  do
-    {
-      if (INB (DSP_DATA_AVAIL) & 0x80)
-       return 1;
-    }
-  while (--loopc && GET_TIME () < t);
-  printk ("!data_avail l=%d\n", loopc);
-  return 0;
-}
-
-static int
-read_dsp (int t)
-{
-  if (!wait_data_avail ((unsigned long) t))
-    return -1;
-  else
-    return INB (DSP_READ);
-}
-
-static int
-dsp_ini2 (void)
-{
-#if 0
-  /* sb_setmixer(0x83, sb_getmixer(0x83) | 0x03);       */
-  sb_dsp_command (0xe2);
-  sb_dsp_command (0x76);       /* E0 ??? */
-  sb_dsp_command (0xe2);
-  sb_dsp_command (0x30);       /* A0 ??? */
-  sb_dsp_command (0xe4);
-  sb_dsp_command (0xaa);
-  sb_dsp_command (0xe8);
-  if (read_dsp (100) != 0xaa)
-    printk ("Error dsp_ini2\n");
-#endif
-  return 0;
-}
-
-/*
-   static char *dsp_getmessage(unsigned char command,int maxn)
-   {
-   static char buff[100];
-   int n=0;
-
-   sb_dsp_command(command);
-   while(n<maxn && wait_data_avail(2L)) {
-   buff[++n]=INB(DSP_READ);
-   if(!buff[n])
-   break;
-   }
-   buff[0]=n;
-   return buff;
-   }
-
-   static void dsp_showmessage(unsigned char command,int len)
-   {
-   int n;
-   unsigned char *c;
-   c=dsp_getmessage(command,len);
-   printk("DSP C=%x l=%d,lr=%d b=",command,len,c[0]);
-   for(n=1;n<=c[0];n++)
-   if(c[n]>=' ' & c[n]<='z')
-   printk("%c",c[n]);
-   else
-   printk("|%x|",c[n]);
-   printk("\n");
-   }
- */
 static int
 dsp_set_speed (int mode)
 {
@@ -212,7 +150,7 @@ dsp_set_bits (int arg)
        dsp_16bit = 1;
        break;
       default:
-       return RET_ERROR (EINVAL);
+       dsp_16bit = 0;
       }
   return dsp_16bit ? 16 : 8;
 }
@@ -247,7 +185,7 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
        return dsp_stereo + 1;
       return IOCTL_OUT (arg, dsp_stereo + 1);
 
-    case SNDCTL_DSP_SAMPLESIZE:
+    case SNDCTL_DSP_SETFMT:
       if (local)
        return dsp_set_bits (arg);
       return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
@@ -257,7 +195,9 @@ sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
        return dsp_16bit ? 16 : 8;
       return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
 
-    case SOUND_PCM_WRITE_FILTER:       /* NOT YET IMPLEMENTED */
+    case SOUND_PCM_WRITE_FILTER:       /*
+                                        * NOT YET IMPLEMENTED
+                                        */
       if (IOCTL_IN (arg) > 1)
        return IOCTL_OUT (arg, RET_ERROR (EINVAL));
     default:
@@ -286,6 +226,8 @@ sb16_dsp_open (int dev, int mode)
   if (retval < 0)
     return retval;
 
+  sb_reset_dsp ();
+
   if (ALLOC_DMA_CHN (dma8))
     {
       printk ("SB16: Unable to grab DMA%d\n", dma8);
@@ -302,8 +244,6 @@ sb16_dsp_open (int dev, int mode)
        return RET_ERROR (EBUSY);
       }
 
-  dsp_ini2 ();
-
   irq_mode = IMODE_NONE;
   dsp_busy = 1;
 
@@ -344,7 +284,7 @@ sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int
   printk ("output_block: %x %d %d\n", buf, count, intrflag);
   if (intrflag)
     {
-      int             pos, chan = sound_dsp_dmachan[dev];
+      int             pos, chan = audio_devs[dev]->dmachan;
 
       DISABLE_INTR (flags);
       clear_dma_ff (chan);
@@ -355,13 +295,15 @@ sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int
       printk ("dmapos=%d %x\n", pos, pos);
     }
 #endif
-  if (sound_dma_automode[dev] &&
+  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == dsp_count)
     {
       irq_mode = IMODE_OUTPUT;
       intr_active = 1;
-      return;                  /* Auto mode on. No need to react */
+      return;                  /*
+                                * Auto mode on. No need to react
+                                */
     }
   DISABLE_INTR (flags);
 
@@ -378,13 +320,11 @@ sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int
                                   (dsp_16bit ? 0x10 : 0)));
   sb_dsp_command01 ((unsigned char) (cnt & 0xff));
   sb_dsp_command ((unsigned char) (cnt >> 8));
-  /* sb_dsp_command (0);
-     sb_dsp_command (0); */
 
-  RESTORE_INTR (flags);
   dsp_count = cnt;
   irq_mode = IMODE_OUTPUT;
   intr_active = 1;
+  RESTORE_INTR (flags);
 }
 
 static void
@@ -401,7 +341,7 @@ sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int d
   printk ("start_input: %x %d %d\n", buf, count, intrflag);
   if (intrflag)
     {
-      int             pos, chan = sound_dsp_dmachan[dev];
+      int             pos, chan = audio_devs[dev]->dmachan;
 
       DISABLE_INTR (flags);
       clear_dma_ff (chan);
@@ -412,19 +352,21 @@ sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int d
       printk ("dmapos=%d %x\n", pos, pos);
     }
 #endif
-  if (sound_dma_automode[dev] &&
+  if (audio_devs[dev]->flags & DMA_AUTOMODE &&
       intrflag &&
       cnt == dsp_count)
     {
       irq_mode = IMODE_INPUT;
       intr_active = 1;
-      return;                  /* Auto mode on. No need to react */
+      return;                  /*
+                                * Auto mode on. No need to react
+                                */
     }
   DISABLE_INTR (flags);
 
   if (dma_restart)
     {
-      sb16_dsp_halt (dev);
+      sb_reset_dsp ();
       DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
     }
 
@@ -437,18 +379,16 @@ sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int d
   sb_dsp_command01 ((unsigned char) (cnt & 0xff));
   sb_dsp_command ((unsigned char) (cnt >> 8));
 
-  /* sb_dsp_command (0);
-     sb_dsp_command (0); */
-  RESTORE_INTR (flags);
   dsp_count = cnt;
   irq_mode = IMODE_INPUT;
   intr_active = 1;
+  RESTORE_INTR (flags);
 }
 
 static int
 sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
 {
-  sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+  audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
   dsp_count = 0;
   dsp_cleanup ();
   return 0;
@@ -457,7 +397,7 @@ sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
 static int
 sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
 {
-  sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+  audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
   dsp_count = 0;
   dsp_cleanup ();
   return 0;
@@ -511,6 +451,9 @@ set_irq_hw (int level)
     case 7:
       ival = 4;
       break;
+    case 9:
+      ival = 1;
+      break;
     case 10:
       ival = 8;
       break;
@@ -524,8 +467,10 @@ set_irq_hw (int level)
 long
 sb16_dsp_init (long mem_start, struct address_info *hw_config)
 {
+  extern int      sbc_major, sbc_minor;
+
   if (sbc_major < 4)
-    return mem_start;
+    return mem_start;          /* Not a SB16 */
 
 #ifndef SCO
   sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
@@ -533,13 +478,12 @@ sb16_dsp_init (long mem_start, struct address_info *hw_config)
 
   printk (" <%s>", sb16_dsp_operations.name);
 
-  if (num_dspdevs < MAX_DSP_DEV)
+  if (num_audiodevs < MAX_AUDIO_DEV)
     {
-      dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations;
-      sound_dsp_dmachan[my_dev] = hw_config->dma;
-      sound_buffcounts[my_dev] = 1;
-      sound_buffsizes[my_dev] = DSP_BUFFSIZE;
-      sound_dma_automode[my_dev] = 1;
+      audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations;
+      audio_devs[my_dev]->dmachan = hw_config->dma;
+      audio_devs[my_dev]->buffcount = 1;
+      audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
     }
   else
     printk ("SB: Too many DSP devices available\n");
@@ -551,9 +495,10 @@ int
 sb16_dsp_detect (struct address_info *hw_config)
 {
   struct address_info *sb_config;
+  extern int      sbc_major;
 
   if (sb16_dsp_ok)
-    return 1;                  /* Already initialized */
+    return 1;                  /* Can't drive two cards */
 
   if (!(sb_config = sound_getconf (SNDCARD_SB)))
     {
@@ -561,13 +506,16 @@ sb16_dsp_detect (struct address_info *hw_config)
       return 0;
     }
 
-  /* sb_setmixer(OPSW,0xf);
-     if(sb_getmixer(OPSW)!=0xf)
-     return 0; */
+  /*
+   * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0;
+   */
 
   if (!sb_reset_dsp ())
     return 0;
 
+  if (sbc_major < 4)           /* Set by the plain SB driver */
+    return 0;                  /* Not a SB16 */
+
   if (hw_config->dma < 4)
     if (hw_config->dma != sb_config->dma)
       {
@@ -584,7 +532,7 @@ sb16_dsp_detect (struct address_info *hw_config)
   DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
 
   /*
  dsp_showmessage(0xe3,99);
* dsp_showmessage(0xe3,99);
  */
   sb16_dsp_ok = 1;
   return 1;
@@ -595,7 +543,9 @@ sb16_dsp_interrupt (int unused)
 {
   int             data;
 
-  data = INB (DSP_DATA_AVL16); /* Interrupt acknowledge */
+  data = INB (DSP_DATA_AVL16); /*
+                                * Interrupt acknowledge
+                                */
 
   if (intr_active)
     switch (irq_mode)
index 0ce274047c796a7af0d1d590e56b87dc4f9de5e5..7a3fdb1a3be6500497b1634046dba84a82b9583d 100644 (file)
 
 #if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
 
-#define        DATAPORT   (sb16midi_base)      /* MPU-401 Data I/O Port on IBM */
-#define        COMDPORT   (sb16midi_base+1)    /* MPU-401 Command Port on IBM */
-#define        STATPORT   (sb16midi_base+1)    /* MPU-401 Status Port on IBM */
+#include "sb.h"
+
+#define        DATAPORT   (sb16midi_base)
+#define        COMDPORT   (sb16midi_base+1)
+#define        STATPORT   (sb16midi_base+1)
 
 #define sb16midi_status()              INB(STATPORT)
 #define input_avail()          (!(sb16midi_status()&INPUT_AVAIL))
 #define sb16midi_read()                INB(DATAPORT)
 #define sb16midi_write(byte)   OUTB(byte, DATAPORT)
 
-#define        OUTPUT_READY    0x40    /* Mask for Data Read Redy Bit */
-#define        INPUT_AVAIL     0x80    /* Mask for Data Send Ready Bit */
-#define        MPU_ACK         0xFE    /* MPU-401 Acknowledge Response */
-#define        MPU_RESET       0xFF    /* MPU-401 Total Reset Command */
-#define        UART_MODE_ON    0x3F    /* MPU-401 "Dumb UART Mode" */
+#define        OUTPUT_READY    0x40
+#define        INPUT_AVAIL     0x80
+#define        MPU_ACK         0xFE
+#define        MPU_RESET       0xFF
+#define        UART_MODE_ON    0x3F
 
 static int      sb16midi_opened = 0;
 static int      sb16midi_base = 0x330;
 static int      sb16midi_detected = 0;
 static int      my_dev;
+extern int      sbc_base;
 
 static int      reset_sb16midi (void);
 static void     (*midi_input_intr) (int dev, unsigned char data);
 
-extern int      sbc_major;
-
 static void
 sb16midi_input_loop (void)
 {
-
   while (input_avail ())
     {
       unsigned char   c = sb16midi_read ();
@@ -127,7 +127,9 @@ sb16midi_out (int dev, unsigned char midi_byte)
    * (After reset). Normally it takes just about 10 loops.
    */
 
-  for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);   /* Wait */
+  for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);   /*
+                                                                        * Wait
+                                                                        */
 
   if (!output_ready ())
     {
@@ -139,12 +141,6 @@ sb16midi_out (int dev, unsigned char midi_byte)
   return 1;
 }
 
-static int
-sb16midi_command (int dev, unsigned char midi_byte)
-{
-  return 1;
-}
-
 static int
 sb16midi_start_read (int dev)
 {
@@ -171,12 +167,19 @@ sb16midi_kick (int dev)
 static int
 sb16midi_buffer_status (int dev)
 {
-  return 0;                    /* No data in buffers */
+  return 0;                    /*
+                                * No data in buffers
+                                */
 }
 
+#define MIDI_SYNTH_NAME        "SoundBlaster 16 Midi"
+#define MIDI_SYNTH_CAPS        SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
 static struct midi_operations sb16midi_operations =
 {
-  {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI},
+  {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI},
+  &std_midi_synth,
   sb16midi_open,
   sb16midi_close,
   sb16midi_ioctl,
@@ -184,8 +187,9 @@ static struct midi_operations sb16midi_operations =
   sb16midi_start_read,
   sb16midi_end_read,
   sb16midi_kick,
-  sb16midi_command,
-  sb16midi_buffer_status
+  NULL,
+  sb16midi_buffer_status,
+  NULL
 };
 
 
@@ -201,7 +205,9 @@ attach_sb16midi (long mem_start, struct address_info *hw_config)
     return RET_ERROR (EIO);
 
   DISABLE_INTR (flags);
-  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);   /* Wait */
+  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);   /*
+                                                                        * Wait
+                                                                        */
   sb16midi_cmd (UART_MODE_ON);
 
   ok = 0;
@@ -212,9 +218,15 @@ attach_sb16midi (long mem_start, struct address_info *hw_config)
 
   RESTORE_INTR (flags);
 
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return mem_start;
+    }
+
   printk (" <SoundBlaster MPU-401>");
 
-  my_dev = num_midis;
+  std_midi_synth.midi_dev = my_dev = num_midis;
   midi_devs[num_midis++] = &sb16midi_operations;
   return mem_start;
 }
@@ -235,8 +247,12 @@ reset_sb16midi (void)
 
   for (n = 0; n < 2 && !ok; n++)
     {
-      for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);       /* Wait */
-      sb16midi_cmd (MPU_RESET);        /* Send MPU-401 RESET Command */
+      for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);       /*
+                                                                                * Wait
+                                                                                */
+      sb16midi_cmd (MPU_RESET);        /*
+                                * Send MPU-401 RESET Command
+                                */
 
       /*
        * Wait at least 25 msec. This method is not accurate so let's make the
@@ -252,7 +268,9 @@ reset_sb16midi (void)
 
   sb16midi_opened = 0;
   if (ok)
-    sb16midi_input_loop ();    /* Flush input before enabling interrupts */
+    sb16midi_input_loop ();    /*
+                                * Flush input before enabling interrupts
+                                */
 
   RESTORE_INTR (flags);
 
@@ -264,10 +282,13 @@ int
 probe_sb16midi (struct address_info *hw_config)
 {
   int             ok = 0;
+  int             i;
+  extern int      sbc_major;
 
-  sb16midi_base = hw_config->io_base;
   if (sbc_major < 4)
-    return 0;                  /* SB16 not detected */
+    return 0;                  /* Not a SB16 */
+
+  sb16midi_base = hw_config->io_base;
 
   if (sb_get_irq () < 0)
     return 0;
index 5c6c0626e5bcd0daca9487f2b0eb1c19bf13c377..0e3936b1fb1be6a93171c744d169aa9c2f95f077 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * Modified:
- *     Hunyue Yau      Jan 6 1994
- *     Added code to support Sound Galaxy NX Pro
- *
  */
 
 #include "sound_config.h"
@@ -41,7 +37,7 @@
 
 int             sbc_base = 0;
 static int      sbc_irq = 0;
-static int     open_mode=0;
+static int      open_mode = 0; /* Read, write or both */
 
 /*
  * The DSP channel can be used either for input or output. Variable
@@ -51,23 +47,36 @@ static int  open_mode=0;
  * future version of this driver.
  */
 
-int             sb_dsp_ok = 0; /* Set to 1 after successful initialization */
+int             sb_dsp_ok = 0; /*
+
+
+                                * *  * * Set to 1 after successful
+                                * initialization  *  */
 static int      midi_disabled = 0;
 int             sb_dsp_highspeed = 0;
-int             sbc_major = 1;
-int             sbc_minor = 0; /* DSP version */
+int             sbc_major = 1, sbc_minor = 0;  /*
+
+
+                                                  * *  * * DSP version   */
 static int      dsp_stereo = 0;
 static int      dsp_current_speed = DSP_DEFAULT_SPEED;
 static int      sb16 = 0;
 static int      irq_verified = 0;
 
 int             sb_midi_mode = NORMAL_MIDI;
-int             sb_midi_busy = 0;      /* 1 if the process has output to MIDI */
+int             sb_midi_busy = 0;      /*
+
+
+                                        * *  * * 1 if the process has output
+                                        * to *  * MIDI   */
 int             sb_dsp_busy = 0;
 
-volatile int    sb_irq_mode = IMODE_NONE;      /* IMODE_INPUT, IMODE_OUTPUT
+volatile int    sb_irq_mode = IMODE_NONE;      /*
+
 
-                                                * or IMODE_NONE */
+                                                * *  * * IMODE_INPUT, *
+                                                * IMODE_OUTPUT * * or *
+                                                * IMODE_NONE   */
 static volatile int irq_ok = 0;
 
 int             sb_duplex_midi = 0;
@@ -81,7 +90,9 @@ int             sb_dsp_command (unsigned char val);
 
 #if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
 
-/* Common code for the midi and pcm functions */
+/*
+ * Common code for the midi and pcm functions
+ */
 
 int
 sb_dsp_command (unsigned char val)
@@ -89,7 +100,9 @@ sb_dsp_command (unsigned char val)
   int             i;
   unsigned long   limit;
 
-  limit = GET_TIME () + HZ / 10;/* The timeout is 0.1 secods */
+  limit = GET_TIME () + HZ / 10;/*
+                                          * The timeout is 0.1 secods
+                                        */
 
   /*
    * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
@@ -121,7 +134,12 @@ sbintr (int unit)
 #ifndef EXCLUDE_SBPRO
   if (sb16)
     {
-      unsigned char   src = sb_getmixer (IRQ_STAT);    /* Interrupt source register */
+      unsigned char   src = sb_getmixer (IRQ_STAT);    /*
+
+
+                                                        * *  * * Interrupt
+                                                        * source * *
+                                                        * register   */
 
 #ifndef EXCLUDE_SB16
       if (src & 3)
@@ -129,17 +147,23 @@ sbintr (int unit)
 
 #ifndef EXCLUDE_MIDI
       if (src & 4)
-       sb16midiintr (unit);    /* MPU401 interrupt */
+       sb16midiintr (unit);    /*
+                                * SB MPU401 interrupt
+                                */
 #endif
 
 #endif
 
       if (!(src & 1))
-       return;                 /* Not a DSP interupt */
+       return;                 /*
+                                * Not a DSP interupt
+                                */
     }
 #endif
 
-  status = INB (DSP_DATA_AVAIL);/* Clear interrupt */
+  status = INB (DSP_DATA_AVAIL);/*
+                                        * Clear interrupt
+                                        */
 
   if (sb_intr_active)
     switch (sb_irq_mode)
@@ -152,7 +176,9 @@ sbintr (int unit)
       case IMODE_INPUT:
        sb_intr_active = 0;
        DMAbuf_inputintr (my_dev);
-       /* A complete buffer has been input. Let's start new one */
+       /*
+        * A complete buffer has been input. Let's start new one
+        */
        break;
 
       case IMODE_INIT:
@@ -160,13 +186,11 @@ sbintr (int unit)
        irq_ok = 1;
        break;
 
-#ifndef EXCLUDE_MIDI
-
       case IMODE_MIDI:
+#ifndef EXCLUDE_MIDI
        sb_midi_interrupt (unit);
-       break;
-
 #endif
+       break;
 
       default:
        printk ("SoundBlaster: Unexpected interrupt\n");
@@ -213,11 +237,19 @@ sb_reset_dsp (void)
   tenmicrosec ();
   tenmicrosec ();
 
-  for (loopc = 0; loopc < 1000 && !(INB (DSP_DATA_AVAIL) & 0x80); loopc++);    /* Wait for data
-                                                                                * available status */
+  for (loopc = 0; loopc < 1000 && !(INB (DSP_DATA_AVAIL) & 0x80); loopc++);    /*
+                                                                                * Wait
+                                                                                * for
+                                                                                * data
+                                                                                * *
+                                                                                * available
+                                                                                * status
+                                                                                */
 
   if (INB (DSP_READ) != 0xAA)
-    return 0;                  /* Sorry */
+    return 0;                  /*
+                                * Sorry
+                                */
 
   return 1;
 }
@@ -264,11 +296,15 @@ dsp_speed (int speed)
        max_speed = 13000;
 
   if (speed > max_speed)
-    speed = max_speed;         /* Invalid speed */
+    speed = max_speed;         /*
+                                * Invalid speed
+                                */
 
   if (dsp_stereo && speed > 22050)
     speed = 22050;
-  /* Max. stereo speed is 22050 */
+  /*
+   * Max. stereo speed is 22050
+   */
 
   if ((speed > 22050) && sb_midi_busy)
     {
@@ -279,10 +315,14 @@ dsp_speed (int speed)
   if (dsp_stereo)
     speed *= 2;
 
-  /* Now the speed should be valid */
+  /*
+   * Now the speed should be valid
+   */
 
   if (speed > 22050)
-    {                          /* High speed mode */
+    {                          /*
+                                * High speed mode
+                                */
       int             tmp;
 
       tconst = (unsigned char) ((65536 -
@@ -305,7 +345,9 @@ dsp_speed (int speed)
       tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
 
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x40))/* Set time constant */
+      if (sb_dsp_command (0x40))/*
+                                        * Set time constant
+                                        */
        sb_dsp_command (tconst);
       RESTORE_INTR (flags);
 
@@ -329,7 +371,9 @@ dsp_set_stereo (int mode)
   return 0;
 #else
   if (sbc_major < 3 || sb16)
-    return 0;                  /* Sorry no stereo */
+    return 0;                  /*
+                                * Sorry no stereo
+                                */
 
   if (mode && sb_midi_busy)
     {
@@ -354,18 +398,22 @@ sb_dsp_output_block (int dev, unsigned long buf, int count,
   sb_irq_mode = IMODE_OUTPUT;
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     count >>= 1;
   count--;
 
   if (sb_dsp_highspeed)
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x48))/* High speed size */
+      if (sb_dsp_command (0x48))/*
+                                        * High speed size
+                                        */
        {
          sb_dsp_command ((unsigned char) (count & 0xff));
          sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
-         sb_dsp_command (0x91);/* High speed 8 bit DAC */
+         sb_dsp_command (0x91);/*
+                                        * High speed 8 bit DAC
+                                        */
        }
       else
        printk ("SB Error: Unable to start (high speed) DAC\n");
@@ -374,7 +422,9 @@ sb_dsp_output_block (int dev, unsigned long buf, int count,
   else
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x14))/* 8-bit DAC (DMA) */
+      if (sb_dsp_command (0x14))/*
+                                        * 8-bit DAC (DMA)
+                                        */
        {
          sb_dsp_command ((unsigned char) (count & 0xff));
          sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
@@ -390,7 +440,9 @@ static void
 sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
                    int restart_dma)
 {
-  /* Start a DMA input to the buffer pointed by dmaqtail */
+  /*
+   * Start a DMA input to the buffer pointed by dmaqtail
+   */
 
   unsigned long   flags;
 
@@ -400,18 +452,22 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
   sb_irq_mode = IMODE_INPUT;
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
 
-  if (sound_dsp_dmachan[dev] > 3)
+  if (audio_devs[dev]->dmachan > 3)
     count >>= 1;
   count--;
 
   if (sb_dsp_highspeed)
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x48))/* High speed size */
+      if (sb_dsp_command (0x48))/*
+                                        * High speed size
+                                        */
        {
          sb_dsp_command ((unsigned char) (count & 0xff));
          sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
-         sb_dsp_command (0x99);/* High speed 8 bit ADC */
+         sb_dsp_command (0x99);/*
+                                        * High speed 8 bit ADC
+                                        */
        }
       else
        printk ("SB Error: Unable to start (high speed) ADC\n");
@@ -420,7 +476,9 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
   else
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x24))/* 8-bit ADC (DMA) */
+      if (sb_dsp_command (0x24))/*
+                                        * 8-bit ADC (DMA)
+                                        */
        {
          sb_dsp_command ((unsigned char) (count & 0xff));
          sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
@@ -445,15 +503,19 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount)
   dsp_cleanup ();
   dsp_speaker (OFF);
 
-  if (sbc_major == 3)          /* SB Pro */
+  if (sbc_major == 3)          /*
+                                * SB Pro
+                                */
     {
       if (dsp_stereo)
        sb_dsp_command (0xa8);
       else
        sb_dsp_command (0xa0);
 
-      dsp_speed (dsp_current_speed);   /* Speed must be recalculated if #channels
-                                          * changes */
+      dsp_speed (dsp_current_speed);   /*
+                                        * Speed must be recalculated if
+                                        * #channels * changes
+                                        */
     }
   return 0;
 }
@@ -465,11 +527,15 @@ sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
   dsp_speaker (ON);
 
 #ifndef EXCLUDE_SBPRO
-  if (sbc_major == 3)          /* SB Pro */
+  if (sbc_major == 3)          /*
+                                * SB Pro
+                                */
     {
       sb_mixer_set_stereo (dsp_stereo);
-      dsp_speed (dsp_current_speed);   /* Speed must be recalculated if #channels
-                                          * changes */
+      dsp_speed (dsp_current_speed);   /*
+                                        * Speed must be recalculated if
+                                        * #channels * changes
+                                        */
     }
 #endif
   return 0;
@@ -497,7 +563,9 @@ verify_irq (void)
 
   sb_irq_mode = IMODE_INIT;
 
-  sb_dsp_command (0xf2);       /* This should cause immediate interrupt */
+  sb_dsp_command (0xf2);       /*
+                                * This should cause immediate interrupt
+                                */
 
   DO_SLEEP (testq, testf, HZ / 5);
 
@@ -544,7 +612,7 @@ sb_dsp_open (int dev, int mode)
   if (retval)
     return retval;
 
-  if (!DMAbuf_open_dma (dev))
+  if (DMAbuf_open_dma (dev) < 0)
     {
       sb_free_irq ();
       printk ("SB: DMA Busy\n");
@@ -610,7 +678,9 @@ sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
     case SOUND_PCM_READ_BITS:
       if (local)
        return 8;
-      return IOCTL_OUT (arg, 8);/* Only 8 bits/sample supported */
+      return IOCTL_OUT (arg, 8);/*
+                                        * Only 8 bits/sample supported
+                                        */
       break;
 
     case SOUND_PCM_WRITE_FILTER:
@@ -648,12 +718,16 @@ sb_dsp_detect (struct address_info *hw_config)
   sbc_irq = hw_config->irq;
 
   if (sb_dsp_ok)
-    return 0;                  /* Already initialized */
+    return 0;                  /*
+                                * Already initialized
+                                */
 
   if (!sb_reset_dsp ())
     return 0;
 
-  return 1;                    /* Detected */
+  return 1;                    /*
+                                * Detected
+                                */
 }
 
 #ifndef EXCLUDE_AUDIO
@@ -661,6 +735,8 @@ static struct audio_operations sb_dsp_operations =
 {
   "SoundBlaster",
   NOTHING_SPECIAL,
+  AFMT_U8,                     /* Just 8 bits. Poor old SB */
+  NULL,
   sb_dsp_open,
   sb_dsp_close,
   sb_dsp_output_block,
@@ -670,7 +746,7 @@ static struct audio_operations sb_dsp_operations =
   sb_dsp_prepare_for_output,
   sb_dsp_reset,
   sb_dsp_halt_xfer,
-  NULL,                                /* has_output_drained */
+  NULL,                                /* local_qlen */
   NULL                         /* copy_from_user */
 };
 
@@ -680,15 +756,18 @@ long
 sb_dsp_init (long mem_start, struct address_info *hw_config)
 {
   int             i;
-  int             prostat = 0;
 
   sbc_major = sbc_minor = 0;
-  sb_dsp_command (0xe1);       /* Get version */
+  sb_dsp_command (0xe1);       /*
+                                * Get version
+                                */
 
   for (i = 1000; i; i--)
     {
       if (INB (DSP_DATA_AVAIL) & 0x80)
-       {                       /* wait for Data Ready */
+       {                       /*
+                                * wait for Data Ready
+                                */
          if (sbc_major == 0)
            sbc_major = INB (DSP_READ);
          else
@@ -699,35 +778,28 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
        }
     }
 
-  if (sbc_major == 2 || sbc_major == 3)        /* SB 2.0 or SB Pro */
+  if (sbc_major == 2 || sbc_major == 3)
     sb_duplex_midi = 1;
 
   if (sbc_major == 4)
     sb16 = 1;
 
 #ifndef EXCLUDE_SBPRO
-  if (sbc_major >= 3 ||
-      (sbc_major == 2 && sbc_minor == 1))      /* Sound Galaxy ??? */
-    prostat = sb_mixer_init (sbc_major);
+  if (sbc_major >= 3)
+    sb_mixer_init (sbc_major);
 #endif
 
-#ifndef EXCLUDE_YM3812
+#ifndef EXCLUDE_YM8312
+
   if (sbc_major > 3 ||
-      (sbc_major == 3 && INB (0x388) == 0x00)) /* Non OPL-3 should return 0x06 */
+      (sbc_major == 3 && INB (0x388) == 0x00)) /* Should be 0x06 if not OPL-3 */
     enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
 #endif
 
   if (sbc_major >= 3)
     {
 #ifndef SCO
-      if (prostat)
-       {
-         sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
-       }
-      else
-       {
-         sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
-       }
+      sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
 #endif
     }
   else
@@ -741,23 +813,26 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
 
 #ifndef EXCLUDE_AUDIO
 #if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
-  if (!sb16)                   /* There is a better driver for SB16    */
+  if (!sb16)                   /*
+                                * There is a better driver for SB16
+                                */
 #endif
-    if (num_dspdevs < MAX_DSP_DEV)
+    if (num_audiodevs < MAX_AUDIO_DEV)
       {
-       dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations;
-       sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
-       sound_buffsizes[my_dev] = DSP_BUFFSIZE;
-       sound_dsp_dmachan[my_dev] = hw_config->dma;
-       sound_dma_automode[my_dev] = 0;
+       audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations;
+       audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT;
+       audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
+       audio_devs[my_dev]->dmachan = hw_config->dma;
       }
     else
       printk ("SB: Too many DSP devices available\n");
 #endif
 
 #ifndef EXCLUDE_MIDI
-  if (!midi_disabled && !sb16) /* Midi don't work in the SB emulation mode
-                                * of PAS, SB16 has better midi interface */
+  if (!midi_disabled && !sb16) /*
+                                * Midi don't work in the SB emulation mode *
+                                * of PAS, SB16 has better midi interface
+                                */
     sb_midi_init (sbc_major);
 #endif
 
index fed19aba3a0810804ff78bccc08071fb50ad7bae..a78225ed2732a5ed527546e2a29c12010d6d85c8 100644 (file)
  * future version of this driver.
  */
 
-extern int      sb_dsp_ok;     /* Set to 1 after successful initialization */
+extern int      sb_dsp_ok;     /* Set to 1 atfer successful initialization */
+extern int      sbc_base;
 
 extern int      sb_midi_mode;
-extern int      sb_midi_busy;  /* 1 if the process has output to MIDI */
+extern int      sb_midi_busy;  /*
+
+
+                                * *  * * 1 if the process has output to MIDI
+                                *
+                                */
 extern int      sb_dsp_busy;
 extern int      sb_dsp_highspeed;
 
-extern volatile int sb_irq_mode;/* IMODE_INPUT, IMODE_OUTPUT
-
-                                        * or IMODE_NONE */
+extern volatile int sb_irq_mode;
 extern int      sb_duplex_midi;
 extern int      sb_intr_active;
-extern int      sbc_base;
+int             input_opened = 0;
+static int      my_dev;
 
-static int      input_opened = 0;
-static void     (*midi_input_intr) (int dev, unsigned char data);
-static int      my_dev = 0;
+void            (*midi_input_intr) (int dev, unsigned char data);
 
 static int
 sb_midi_open (int dev, int mode,
@@ -74,10 +77,13 @@ sb_midi_open (int dev, int mode,
       return RET_ERROR (ENXIO);
     }
 
+  if (sb_midi_busy)
+    return RET_ERROR (EBUSY);
+
   if (mode != OPEN_WRITE && !sb_duplex_midi)
     {
       if (num_midis == 1)
-       printk ("SoundBlaster: MIDI input not supported with plain SB\n");
+       printk ("SoundBlaster: Midi input not currently supported\n");
       return RET_ERROR (EPERM);
     }
 
@@ -101,20 +107,20 @@ sb_midi_open (int dev, int mode,
 
       sb_reset_dsp ();
 
-      if (!sb_dsp_command (0xf2))      /* This is undodumented, isn't it */
-       return RET_ERROR (EIO); /* be nice to DSP */
-
       if (!sb_dsp_command (0x35))
-       return RET_ERROR (EIO); /* Enter the UART mode */
+       return RET_ERROR (EIO); /*
+                                * Enter the UART mode
+                                */
       sb_intr_active = 1;
 
       if ((ret = sb_get_irq ()) < 0)
        {
          sb_reset_dsp ();
-         return 0;             /* IRQ not free */
+         return 0;             /*
+                                * IRQ not free
+                                */
        }
       input_opened = 1;
-      my_dev = dev;
       midi_input_intr = input;
     }
 
@@ -128,7 +134,9 @@ sb_midi_close (int dev)
 {
   if (sb_midi_mode == UART_MIDI)
     {
-      sb_reset_dsp ();         /* The only way to kill the UART mode */
+      sb_reset_dsp ();         /*
+                                * The only way to kill the UART mode
+                                */
       sb_free_irq ();
     }
   sb_intr_active = 0;
@@ -141,8 +149,6 @@ sb_midi_out (int dev, unsigned char midi_byte)
 {
   unsigned long   flags;
 
-  sb_midi_busy = 1;            /* Kill all notes after close */
-
   if (sb_midi_mode == NORMAL_MIDI)
     {
       DISABLE_INTR (flags);
@@ -153,7 +159,9 @@ sb_midi_out (int dev, unsigned char midi_byte)
       RESTORE_INTR (flags);
     }
   else
-    sb_dsp_command (midi_byte);        /* UART write */
+    sb_dsp_command (midi_byte);        /*
+                                * UART write
+                                */
 
   return 1;
 }
@@ -201,23 +209,43 @@ sb_midi_interrupt (int dummy)
   RESTORE_INTR (flags);
 }
 
+#define MIDI_SYNTH_NAME        "SoundBlaster Midi"
+#define MIDI_SYNTH_CAPS        0
+#include "midi_synth.h"
+
 static struct midi_operations sb_midi_operations =
 {
   {"SoundBlaster", 0, 0, SNDCARD_SB},
+  &std_midi_synth,
   sb_midi_open,
   sb_midi_close,
   sb_midi_ioctl,
   sb_midi_out,
   sb_midi_start_read,
   sb_midi_end_read,
-  NULL,                                /* Kick */
-  NULL,                                /* command */
-  NULL                         /* buffer_status */
+  NULL,                                /*
+                                * Kick
+                                */
+  NULL,                                /*
+                                * command
+                                */
+  NULL,                                /*
+                                * buffer_status
+                                */
+  NULL
 };
 
 void
 sb_midi_init (int model)
 {
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return;
+    }
+
+  std_midi_synth.midi_dev = num_midis;
+  my_dev = num_midis;
   midi_devs[num_midis++] = &sb_midi_operations;
 }
 
index 39b97caf8cd73fa6d8c1c3e022d8cfe7faf16f66..92d3c64368a5bce10ea6e53a9a3eadc7af51c9dd 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * Modified:
- *     Hunyue Yau      Jan 6 1994
- *     Added code to support the Sound Galaxy NX Pro mixer.
- *
  */
 
 #include "sound_config.h"
@@ -58,7 +54,9 @@ sb_setmixer (unsigned int port, unsigned int value)
   unsigned long   flags;
 
   DISABLE_INTR (flags);
-  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);    /* Select register */
+  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);    /*
+                                                        * Select register
+                                                        */
   tenmicrosec ();
   OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
   tenmicrosec ();
@@ -72,7 +70,9 @@ sb_getmixer (unsigned int port)
   unsigned long   flags;
 
   DISABLE_INTR (flags);
-  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);    /* Select register */
+  OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);    /*
+                                                        * Select register
+                                                        */
   tenmicrosec ();
   val = INB (MIXER_DATA);
   tenmicrosec ();
@@ -91,21 +91,9 @@ sb_mixer_set_stereo (int mode)
                            | (mode ? STEREO_DAC : MONO_DAC)));
 }
 
-/*
- * Returns:
- *     0       No mixer detected.
- *     1       Only a plain Sound Blaster Pro style mixer detected.
- *     2       The Sound Galaxy NX Pro mixer detected.
- */
 static int
 detect_mixer (void)
 {
-#ifdef __SGNXPRO__
-  int             oldbass, oldtreble;
-
-#endif
-  int             retcode = 1;
-
   /*
    * Detect the mixer by changing parameters of two volume channels. If the
    * values read back match with the values written, the mixer is there (is
@@ -115,34 +103,13 @@ detect_mixer (void)
   sb_setmixer (VOC_VOL, 0x33);
 
   if (sb_getmixer (FM_VOL) != 0xff)
-    return 0;                  /* No match */
+    return 0;                  /*
+                                * No match
+                                */
   if (sb_getmixer (VOC_VOL) != 0x33)
     return 0;
 
-#ifdef __SGNXPRO__
-  /* Attempt to detect the SG NX Pro by check for valid bass/treble
- * registers.
- */
-  oldbass = sb_getmixer (BASS_LVL);
-  oldtreble = sb_getmixer (TREBLE_LVL);
-
-  sb_setmixer (BASS_LVL, 0xaa);
-  sb_setmixer (TREBLE_LVL, 0x55);
-
-  if ((sb_getmixer (BASS_LVL) != 0xaa) ||
-      (sb_getmixer (TREBLE_LVL) != 0x55))
-    {
-      retcode = 1;             /* 1 == Only SB Pro detected */
-    }
-  else
-    retcode = 2;               /* 2 == SG NX Pro detected */
-  /* Restore register in either case since SG NX Pro has EEPROM with
-   * 'preferred' values stored.
-   */
-  sb_setmixer (BASS_LVL, oldbass);
-  sb_setmixer (TREBLE_LVL, oldtreble);
-#endif
-  return retcode;
+  return 1;
 }
 
 static void
@@ -152,12 +119,18 @@ change_bits (unsigned char *regval, int dev, int chn, int newval)
   int             shift;
 
   mask = (1 << (*iomap)[dev][chn].nbits) - 1;
-  newval = ((newval * mask) + 50) / 100;       /* Scale it */
+  newval = (int) ((newval * mask) + 50) / 100; /*
+                                                * Scale it
+                                                */
 
   shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
 
-  *regval &= ~(mask << shift); /* Filter out the previous value */
-  *regval |= (newval & mask) << shift; /* Set the new value */
+  *regval &= ~(mask << shift); /*
+                                * Filter out the previous value
+                                */
+  *regval |= (newval & mask) << shift; /*
+                                        * Set the new value
+                                        */
 }
 
 static int
@@ -186,7 +159,9 @@ sb_mixer_set (int dev, int value)
   if (dev > 31)
     return RET_ERROR (EINVAL);
 
-  if (!(supported_devices & (1 << dev)))       /* Not supported */
+  if (!(supported_devices & (1 << dev)))       /*
+                                                * Not supported
+                                                */
     return RET_ERROR (EINVAL);
 
   regoffs = (*iomap)[dev][LEFT_CHN].regno;
@@ -199,15 +174,23 @@ sb_mixer_set (int dev, int value)
 
   levels[dev] = left | (left << 8);
 
-  if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)       /* Change register */
+  if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)       /*
+                                                        * Change register
+                                                        */
     {
-      sb_setmixer (regoffs, val);      /* Save the old one */
+      sb_setmixer (regoffs, val);      /*
+                                        * Save the old one
+                                        */
       regoffs = (*iomap)[dev][RIGHT_CHN].regno;
 
       if (regoffs == 0)
-       return left | (left << 8);      /* Just left channel present */
+       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);
@@ -238,21 +221,27 @@ set_recmask (int mask)
       if (devmask != SOUND_MASK_MIC &&
          devmask != SOUND_MASK_LINE &&
          devmask != SOUND_MASK_CD)
-       {                       /* More than one devices selected. Drop the
-                                * previous selection */
+       {                       /*
+                                * More than one devices selected. Drop the *
+                                * previous selection
+                                */
          devmask &= ~recmask;
        }
 
       if (devmask != SOUND_MASK_MIC &&
          devmask != SOUND_MASK_LINE &&
          devmask != SOUND_MASK_CD)
-       {                       /* More than one devices selected. Default to
-                                * mic */
+       {                       /*
+                                * More than one devices selected. Default to
+                                * * mic
+                                */
          devmask = SOUND_MASK_MIC;
        }
 
 
-      if (devmask ^ recmask)   /* Input source changed */
+      if (devmask ^ recmask)   /*
+                                * Input source changed
+                                */
        {
          switch (devmask)
            {
@@ -312,7 +301,9 @@ sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
            return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
          }
       else
-       switch (cmd & 0xff)     /* Return parameters */
+       switch (cmd & 0xff)     /*
+                                * Return parameters
+                                */
          {
 
          case SOUND_MIXER_RECSRC:
@@ -359,24 +350,17 @@ sb_mixer_reset (void)
   set_recmask (SOUND_MASK_MIC);
 }
 
-/*
- * Returns a code depending on whether a SG NX Pro was detected.
- * 0 == Plain SB 16 or SB Pro
- * 1 == SG NX Pro detected.
- *
- * Used to update message.
- */
-int
+void
 sb_mixer_init (int major_model)
 {
-  int             mixerstat;
-
-  sb_setmixer (0x00, 0);       /* Reset mixer */
+  sb_setmixer (0x00, 0);       /*
+                                * Reset mixer
+                                */
 
-  mixerstat = detect_mixer ();
-
-  if (!mixerstat)
-    return 0;                  /* No mixer. Why? */
+  if (!detect_mixer ())
+    return;                    /*
+                                * No mixer. Why?
+                                */
 
   mixer_initialized = 1;
   mixer_model = major_model;
@@ -385,21 +369,9 @@ sb_mixer_init (int 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;
-       }
-
+      supported_devices = SBPRO_MIXER_DEVICES;
+      supported_rec_devices = SBPRO_RECORDING_DEVICES;
+      iomap = &sbpro_mix;
       break;
 
     case 4:
@@ -411,12 +383,12 @@ sb_mixer_init (int major_model)
 
     default:
       printk ("SB Warning: Unsupported mixer type\n");
-      return 0;
+      return;
     }
 
-  mixer_devs[num_mixers++] = &sb_mixer_operations;
+  if (num_mixers < MAX_MIXER_DEV)
+    mixer_devs[num_mixers++] = &sb_mixer_operations;
   sb_mixer_reset ();
-  return (mixerstat == 2);
 }
 
 #endif
index 4caf7730226fa3b7c0d0dc626f756ee46a02211a..b0b5f58a1f6ffb0957b56c45ba0d48587aa7d65f 100644 (file)
  * 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)
 
 #define IRQ_STAT       0x82
 #define OPSW           0x3c
 
-/*
- * Additional registers on the SG NX Pro 
- */
-#define COVOX_VOL      0x42
-#define TREBLE_LVL     0x44
-#define BASS_LVL       0x46
-
 #define FREQ_HI         (1 << 3)/* Use High-frequency ANFI filters */
 #define FREQ_LOW        0      /* Use Low-frequency ANFI filters */
 #define FILT_ON         0      /* Yes, 0 to turn it on, 1 for off */
@@ -131,23 +108,6 @@ MIX_ENT(SOUND_MIXER_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),
 MIX_ENT(SOUND_MIXER_BASS,      0x46, 7, 4, 0x47, 7, 4),
@@ -209,4 +169,13 @@ static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
        0x00,   /* SOUND_MIXER_ALTPCM   */
        0x00    /* SOUND_MIXER_RECLEV   */
 };
+
+/*
+ *     Recording sources (SB Pro)
+ */
+
+#define SRC_MIC         1      /* Select Microphone recording source */
+#define SRC_CD          3      /* Select CD recording source */
+#define SRC_LINE        7      /* Use Line-in for recording source */
+
 #endif
index fc02464a9f8fb8c63a2592ac86c933fca3ab800a..45f06c1edfbfb49e27aa1c6f3287ee5ea977865a 100644 (file)
 #ifndef EXCLUDE_SEQUENCER
 
 static int      sequencer_ok = 0;
+static struct sound_timer_operations *tmr;
+static int      tmr_no = -1;   /* Currently selected timer */
+static int      pending_timer = -1;    /* For timer change operation */
+
+/*
+ * Local counts for number of synth and MIDI devices. These are initialized
+ * by the sequencer_open.
+ */
+static int      max_mididev = 0;
+static int      max_synthdev = 0;
+
+/*
+ * The seq_mode gives the operating mode of the sequencer:
+ *      1 = level1 (the default)
+ *      2 = level2 (extended capabilites)
+ */
+
+#define SEQ_1  1
+#define SEQ_2  2
+static int      seq_mode = SEQ_1;
 
 DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
-/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */
-#define midi_sleeper seq_sleeper
-#define midi_sleep_flag seq_sleep_flag
+DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
 
 static int      midi_opened[MAX_MIDI_DEV] =
-{0};                           /* 1 if the process has opened MIDI */
+{0};
 static int      midi_written[MAX_MIDI_DEV] =
 {0};
 
-unsigned long   seq_time = 0;  /* Reference point for the timer */
+unsigned long   prev_input_time = 0;
+int             prev_event_time;
+unsigned long   seq_time = 0;
 
 #include "tuning.h"
 
 #define EV_SZ  8
-#define IEV_SZ 4
-static unsigned char *queue = NULL;    /* SEQ_MAX_QUEUE * EV_SZ bytes */
-static unsigned char *iqueue = NULL;   /* SEQ_MAX_QUEUE * IEV_SZ bytes */
+#define IEV_SZ 8
+static unsigned char *queue = NULL;
+static unsigned char *iqueue = NULL;
 
 static volatile int qhead = 0, qtail = 0, qlen = 0;
 static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
 static volatile int seq_playing = 0;
 static int      sequencer_busy = 0;
 static int      output_treshold;
+static int      pre_event_timeout;
 static unsigned synth_open_mask;
 
 static int      seq_queue (unsigned char *note);
@@ -70,48 +91,48 @@ static int      pmgr_present[MAX_SYNTH_DEV] =
 {0};
 
 #if MAX_SYNTH_DEV > 15
-#error Too many synthesizer devices
+#error Too many synthesizer devices enabled.
 #endif
 
 int
 sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
   int             c = count, p = 0;
+  int             ev_len;
   unsigned long   flags;
 
   dev = dev >> 4;
 
-  if (dev)                     /* Patch manager device */
+  ev_len = seq_mode == SEQ_1 ? 4 : 8;
+
+  if (dev)                     /*
+                                * Patch manager device
+                                */
     return pmgr_read (dev - 1, file, buf, count);
 
-  while (c > 3)
+  DISABLE_INTR (flags);
+  if (!iqlen)
     {
-      DISABLE_INTR (flags);
+      DO_SLEEP (midi_sleeper, midi_sleep_flag, pre_event_timeout);
+
       if (!iqlen)
        {
-         if (c != count)       /* Some data has been received */
-           {
-             RESTORE_INTR (flags);
-             return count - c; /* Return what we have */
-           }
-
-         DO_SLEEP (midi_sleeper, midi_sleep_flag, 0);
-
-         if (!iqlen)
-           {
-             RESTORE_INTR (flags);
-             return count - c;
-           }
+         RESTORE_INTR (flags);
+         return 0;
        }
+    }
 
-      COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ);
-      p += 4;
-      c -= 4;
+  while (iqlen && c >= ev_len)
+    {
+
+      COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], ev_len);
+      p += ev_len;
+      c -= ev_len;
 
       iqhead = (iqhead + 1) % SEQ_MAX_QUEUE;
       iqlen--;
-      RESTORE_INTR (flags);
     }
+  RESTORE_INTR (flags);
 
   return count - c;
 }
@@ -119,19 +140,30 @@ sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 static void
 sequencer_midi_output (int dev)
 {
-  /* Currently NOP */
+  /*
+   * Currently NOP
+   */
 }
 
-static void
-copy_to_input (unsigned char *event)
+void
+seq_copy_to_input (unsigned char *event, int len)
 {
   unsigned long   flags;
 
+  /*
+ * Verify that the len is valid for the current mode.
+ */
+
+  if (len != 4 && len != 8)
+    return;
+  if ((seq_mode == SEQ_1) != (len == 4))
+    return;
+
   if (iqlen >= (SEQ_MAX_QUEUE - 1))
     return;                    /* Overflow */
 
   DISABLE_INTR (flags);
-  memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ);
+  memcpy (&iqueue[iqtail * IEV_SZ], event, len);
   iqlen++;
   iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
 
@@ -145,23 +177,54 @@ copy_to_input (unsigned char *event)
 static void
 sequencer_midi_input (int dev, unsigned char data)
 {
-  int             tstamp;
+  unsigned int    tstamp;
   unsigned char   event[4];
 
-  if (data == 0xfe)            /* Active sensing */
-    return;                    /* Ignore */
+  if (data == 0xfe)            /* Ignore active sensing */
+    return;
 
-  tstamp = GET_TIME () - seq_time;     /* Time since open() */
-  tstamp = (tstamp << 8) | SEQ_WAIT;
+  tstamp = GET_TIME () - seq_time;
+  if (tstamp != prev_input_time)
+    {
+      tstamp = (tstamp << 8) | SEQ_WAIT;
 
-  copy_to_input ((unsigned char *) &tstamp);
+      seq_copy_to_input ((unsigned char *) &tstamp, 4);
+      prev_input_time = tstamp;
+    }
 
   event[0] = SEQ_MIDIPUTC;
   event[1] = data;
   event[2] = dev;
   event[3] = 0;
 
-  copy_to_input (event);
+  seq_copy_to_input (event, 4);
+}
+
+void
+seq_input_event (unsigned char *event, int len)
+{
+  unsigned long   this_time;
+
+  if (seq_mode == SEQ_2)
+    this_time = tmr->get_time (tmr_no);
+  else
+    this_time = GET_TIME () - seq_time;
+
+  if (this_time != prev_input_time)
+    {
+      unsigned char   tmp_event[8];
+
+      tmp_event[0] = EV_TIMING;
+      tmp_event[1] = TMR_WAIT_ABS;
+      tmp_event[2] = 0;
+      tmp_event[3] = 0;
+      *(unsigned long *) &tmp_event[4] = this_time;
+
+      seq_copy_to_input (tmp_event, 8);
+      prev_input_time = this_time;
+    }
+
+  seq_copy_to_input (event, len);
 }
 
 int
@@ -179,7 +242,9 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
   if (mode == OPEN_READ)
     return RET_ERROR (EIO);
 
-  if (dev)                     /* Patch manager device */
+  if (dev)                     /*
+                                * Patch manager device
+                                */
     return pmgr_write (dev - 1, file, buf, count);
 
   c = count;
@@ -194,7 +259,7 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
          int             err;
 
          dev = *(unsigned short *) &event[2];
-         if (dev < 0 || dev >= num_synths)
+         if (dev < 0 || dev >= max_synthdev)
            return RET_ERROR (ENXIO);
 
          if (!(synth_open_mask & (1 << dev)))
@@ -207,8 +272,13 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
          return err;
        }
 
-      if (ev_code == SEQ_EXTENDED || ev_code == SEQ_PRIVATE)
+      if (ev_code >= 128)
        {
+         if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED)
+           {
+             printk ("Sequencer: Invalid level 2 event %x\n", ev_code);
+             return RET_ERROR (EINVAL);
+           }
 
          ev_size = 8;
 
@@ -223,7 +293,14 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 
        }
       else
-       ev_size = 4;
+       {
+         if (seq_mode == SEQ_2)
+           {
+             printk ("Sequencer: 4 byte event in level 2 mode\n");
+             return RET_ERROR (EINVAL);
+           }
+         ev_size = 4;
+       }
 
       if (event[0] == SEQ_MIDIPUTC)
        {
@@ -233,7 +310,7 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
              int             mode;
              int             dev = event[2];
 
-             if (dev >= num_midis)
+             if (dev >= max_mididev)
                {
                  printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev);
                  return RET_ERROR (ENXIO);
@@ -276,20 +353,28 @@ static int
 seq_queue (unsigned char *note)
 {
 
-  /* Test if there is space in the queue */
+  /*
+   * Test if there is space in the queue
+   */
 
   if (qlen >= SEQ_MAX_QUEUE)
     if (!seq_playing)
-      seq_startplay ();                /* Give chance to drain the queue */
+      seq_startplay ();                /*
+                                * Give chance to drain the queue
+                                */
 
   if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
     {
-      /* Sleep until there is enough space on the queue */
+      /*
+       * Sleep until there is enough space on the queue
+       */
       DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
     }
 
   if (qlen >= SEQ_MAX_QUEUE)
-    return 0;                  /* To be sure */
+    return 0;                  /*
+                                * To be sure
+                                */
 
   memcpy (&queue[qtail * EV_SZ], note, EV_SZ);
 
@@ -304,7 +389,7 @@ extended_event (unsigned char *q)
 {
   int             dev = q[2];
 
-  if (dev < 0 || dev >= num_synths)
+  if (dev < 0 || dev >= max_synthdev)
     return RET_ERROR (ENXIO);
 
   if (!(synth_open_mask & (1 << dev)))
@@ -313,7 +398,7 @@ extended_event (unsigned char *q)
   switch (q[1])
     {
     case SEQ_NOTEOFF:
-      synth_devs[dev]->kill_note (dev, q[3], q[5]);
+      synth_devs[dev]->kill_note (dev, q[3], q[4], q[5]);
       break;
 
     case SEQ_NOTEON:
@@ -340,7 +425,8 @@ extended_event (unsigned char *q)
       break;
 
     case SEQ_VOLMODE:
-      synth_devs[dev]->volume_method (dev, q[3]);
+      if (synth_devs[dev]->volume_method != NULL)
+       synth_devs[dev]->volume_method (dev, q[3]);
       break;
 
     default:
@@ -350,6 +436,282 @@ extended_event (unsigned char *q)
   return 0;
 }
 
+static int
+find_voice (int dev, int chn, int note)
+{
+  unsigned short  key;
+  int             i;
+
+  key = (chn << 8) | (note + 1);
+
+  for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++)
+    if (synth_devs[dev]->alloc.map[i] == key)
+      return i;
+
+  return -1;
+}
+
+static int
+alloc_voice (int dev, int chn, int note)
+{
+  unsigned short  key;
+  int             voice;
+
+  key = (chn << 8) | (note + 1);
+
+  voice = synth_devs[dev]->alloc_voice (dev, chn, note,
+                                       &synth_devs[dev]->alloc);
+  synth_devs[dev]->alloc.map[voice] = key;
+  return voice;
+}
+
+static void
+seq_chn_voice_event (unsigned char *event)
+{
+  unsigned char   dev = event[1];
+  unsigned char   cmd = event[2];
+  unsigned char   chn = event[3];
+  unsigned char   note = event[4];
+  unsigned char   parm = event[5];
+  int             voice = -1;
+
+  if ((int) dev > max_synthdev)
+    return;
+  if (!(synth_open_mask & (1 << dev)))
+    return;
+  if (!synth_devs[dev])
+    return;
+
+  if (seq_mode == SEQ_2)
+    if (synth_devs[dev]->alloc_voice)
+      voice = find_voice (dev, chn, note);
+
+  if (cmd == MIDI_NOTEON && parm == 0)
+    {
+      cmd = MIDI_NOTEOFF;
+      parm = 64;
+    }
+
+  switch (cmd)
+    {
+    case MIDI_NOTEON:
+      if (note > 127)
+       return;
+
+      if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice)
+       {
+         voice = alloc_voice (dev, chn, note);
+       }
+
+      if (voice == -1)
+       voice = chn;
+
+      if (seq_mode == SEQ_2)
+       {
+         synth_devs[dev]->set_instr (dev, voice,
+                                   synth_devs[dev]->chn_info[chn].pgm_num);
+       }
+
+      synth_devs[dev]->start_note (dev, voice, note, parm);
+      break;
+
+    case MIDI_NOTEOFF:
+      if (voice == -1)
+       voice = chn;
+      synth_devs[dev]->kill_note (dev, voice, note, parm);
+      break;
+
+    case MIDI_KEY_PRESSURE:
+      /* To be implemented */
+      break;
+
+    default:;
+    }
+}
+
+static void
+seq_chn_common_event (unsigned char *event)
+{
+  unsigned char   dev = event[1];
+  unsigned char   cmd = event[2];
+  unsigned char   chn = event[3];
+  unsigned char   p1 = event[4];
+
+  /* unsigned char   p2 = event[5]; */
+  unsigned short  w14 = *(short *) &event[6];
+
+  if ((int) dev > max_synthdev)
+    return;
+  if (!(synth_open_mask & (1 << dev)))
+    return;
+  if (!synth_devs[dev])
+    return;
+
+  switch (cmd)
+    {
+    case MIDI_PGM_CHANGE:
+      if (seq_mode == SEQ_2)
+       {
+         synth_devs[dev]->chn_info[chn].pgm_num = p1;
+       }
+      else
+       synth_devs[dev]->set_instr (dev, chn, p1);
+      break;
+
+    case MIDI_CTL_CHANGE:
+      if (p1 == CTRL_MAIN_VOLUME)
+       {
+         w14 = (unsigned short) (((int) w14 * 16383) / 100);
+         p1 = CTL_MAIN_VOLUME;
+       }
+      if (p1 == CTRL_EXPRESSION)
+       {
+         w14 *= 128;
+         p1 = CTL_EXPRESSION;
+       }
+
+      if (seq_mode == SEQ_2)
+       {
+         if (chn > 15 || p1 > 127)
+           break;
+
+         synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0xff;
+
+         if (dev < num_synths)
+           {
+             int             val = w14 & 0xff;
+
+             if (p1 < 64)      /* Combine MSB and LSB */
+               {
+                 val = ((synth_devs[dev]->
+                         chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7)
+                   | (synth_devs[dev]->
+                      chn_info[chn].controllers[p1 | 32] & 0x7f);
+                 p1 &= ~32;
+               }
+             else
+               val = synth_devs[dev]->chn_info[chn].controllers[p1];
+
+             synth_devs[dev]->controller (dev, chn, p1, val);
+           }
+         else
+           synth_devs[dev]->controller (dev, chn, p1, w14);
+       }
+      else
+       synth_devs[dev]->controller (dev, chn, p1, w14);
+      break;
+
+    case MIDI_PITCH_BEND:
+      synth_devs[dev]->bender (dev, chn, w14);
+      break;
+
+    default:;
+    }
+}
+
+static int
+seq_timing_event (unsigned char *event)
+{
+  unsigned char   cmd = event[1];
+  unsigned int    parm = *(int *) &event[4];
+
+  if (seq_mode == SEQ_2)
+    {
+      int             ret;
+
+      if ((ret = tmr->event (tmr_no, event)) == TIMER_ARMED)
+       {
+         if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+           {
+             unsigned long   flags;
+
+             DISABLE_INTR (flags);
+             if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+               {
+                 WAKE_UP (seq_sleeper, seq_sleep_flag);
+               }
+             RESTORE_INTR (flags);
+           }
+       }
+      return ret;
+    }
+
+  switch (cmd)
+    {
+    case TMR_WAIT_REL:
+      parm += prev_event_time;
+
+      /*
+ * NOTE!  No break here. Execution of TMR_WAIT_REL continues in the
+ * next case (TMR_WAIT_ABS)
+ */
+
+    case TMR_WAIT_ABS:
+      if (parm > 0)
+       {
+         long            time;
+
+         seq_playing = 1;
+         time = parm;
+         prev_event_time = time;
+
+         request_sound_timer (time);
+
+         if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+           {
+             unsigned long   flags;
+
+             DISABLE_INTR (flags);
+             if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+               {
+                 WAKE_UP (seq_sleeper, seq_sleep_flag);
+               }
+             RESTORE_INTR (flags);
+           }
+
+         return TIMER_ARMED;
+       }
+      break;
+
+    case TMR_START:
+      seq_time = GET_TIME ();
+      prev_input_time = 0;
+      prev_event_time = 0;
+      break;
+
+    case TMR_STOP:
+      break;
+
+    case TMR_CONTINUE:
+      break;
+
+    case TMR_TEMPO:
+      break;
+
+    case TMR_ECHO:
+      if (seq_mode == SEQ_2)
+       seq_copy_to_input (event, 8);
+      else
+       {
+         parm = (parm << 8 | SEQ_ECHO);
+         seq_copy_to_input ((unsigned char *) &parm, 4);
+       }
+      break;
+
+    default:;
+    }
+
+  return TIMER_NOT_ARMED;
+}
+
+static void
+seq_local_event (unsigned char *event)
+{
+  /* unsigned char   cmd = event[1]; */
+
+  printk ("seq_local_event() called. WHY????????\n");
+}
+
 static void
 seq_startplay (void)
 {
@@ -359,6 +721,9 @@ seq_startplay (void)
 
   while (qlen > 0)
     {
+
+      seq_playing = 1;
+
       qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
       qlen--;
 
@@ -369,7 +734,7 @@ seq_startplay (void)
        case SEQ_NOTEOFF:
          if (synth_open_mask & (1 << 0))
            if (synth_devs[0])
-             synth_devs[0]->kill_note (0, q[1], q[3]);
+             synth_devs[0]->kill_note (0, q[1], 255, q[3]);
          break;
 
        case SEQ_NOTEON:
@@ -380,8 +745,10 @@ seq_startplay (void)
          break;
 
        case SEQ_WAIT:
-         delay = (unsigned long *) q;  /* Bytes 1 to 3 are containing the
-                                        * delay in GET_TIME() */
+         delay = (unsigned long *) q;  /*
+                                        * Bytes 1 to 3 are containing the *
+                                        * delay in GET_TIME()
+                                        */
          *delay = (*delay >> 8) & 0xffffff;
 
          if (*delay > 0)
@@ -390,6 +757,7 @@ seq_startplay (void)
 
              seq_playing = 1;
              time = *delay;
+             prev_event_time = time;
 
              request_sound_timer (time);
 
@@ -404,8 +772,11 @@ seq_startplay (void)
                    }
                  RESTORE_INTR (flags);
                }
-             return;           /* Stop here. Timer routine will continue
-                                * playing after the delay */
+             /*
+ * The timer is now active and will reinvoke this function
+ * after the timer expires. Return to the caller now.
+ */
+             return;
            }
          break;
 
@@ -415,11 +786,17 @@ seq_startplay (void)
              synth_devs[0]->set_instr (0, q[1], q[2]);
          break;
 
-       case SEQ_SYNCTIMER:     /* Reset timer */
+       case SEQ_SYNCTIMER:     /*
+                                * Reset timer
+                                */
          seq_time = GET_TIME ();
+         prev_input_time = 0;
+         prev_event_time = 0;
          break;
 
-       case SEQ_MIDIPUTC:      /* Put a midi character */
+       case SEQ_MIDIPUTC:      /*
+                                * Put a midi character
+                                */
          if (midi_opened[q[2]])
            {
              int             dev;
@@ -433,7 +810,9 @@ seq_startplay (void)
                   */
 
                  qlen++;
-                 qhead = this_one;     /* Restore queue */
+                 qhead = this_one;     /*
+                                        * Restore queue
+                                        */
                  seq_playing = 1;
                  request_sound_timer (-1);
                  return;
@@ -444,11 +823,13 @@ seq_startplay (void)
          break;
 
        case SEQ_ECHO:
-         copy_to_input (q);    /* Echo back to the process */
+         seq_copy_to_input (q, 4);     /*
+                                          * Echo back to the process
+                                        */
          break;
 
        case SEQ_PRIVATE:
-         if (q[1] < num_synths)
+         if ((int) q[1] < max_synthdev)
            synth_devs[q[1]]->hw_control (q[1], q);
          break;
 
@@ -456,6 +837,25 @@ seq_startplay (void)
          extended_event (q);
          break;
 
+       case EV_CHN_VOICE:
+         seq_chn_voice_event (q);
+         break;
+
+       case EV_CHN_COMMON:
+         seq_chn_common_event (q);
+         break;
+
+       case EV_TIMING:
+         if (seq_timing_event (q) == TIMER_ARMED)
+           {
+             return;
+           }
+         break;
+
+       case EV_SEQ_LOCAL:
+         seq_local_event (q);
+         break;
+
        default:;
        }
 
@@ -477,10 +877,55 @@ seq_startplay (void)
 
 }
 
+static void
+reset_controllers (int dev, unsigned char *controller, int update_dev)
+{
+#include "midi_ctrl.h"
+
+  int             i;
+
+  for (i = 0; i < 128; i++)
+    controller[i] = ctrl_def_values[i];
+}
+
+static void
+setup_mode2 (void)
+{
+  int             dev;
+
+  max_synthdev = num_synths;
+
+  for (dev = 0; dev < num_midis; dev++)
+    if (midi_devs[dev]->converter != NULL)
+      {
+       synth_devs[max_synthdev++] =
+         midi_devs[dev]->converter;
+      }
+
+  for (dev = 0; dev < max_synthdev; dev++)
+    {
+      int             chn;
+
+      for (chn = 0; chn < 16; chn++)
+       {
+         synth_devs[dev]->chn_info[chn].pgm_num = 0;
+         reset_controllers (dev,
+                            synth_devs[dev]->chn_info[chn].controllers,
+                            0);
+       }
+    }
+
+  max_mididev = 0;
+  seq_mode = SEQ_2;
+}
+
 int
 sequencer_open (int dev, struct fileinfo *file)
 {
   int             retval, mode, i;
+  int             level, tmp;
+
+  level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1;
 
   dev = dev >> 4;
   mode = file->mode & O_ACCMODE;
@@ -493,15 +938,22 @@ sequencer_open (int dev, struct fileinfo *file)
       return RET_ERROR (ENXIO);
     }
 
-  if (dev)                     /* Patch manager device */
+  if (dev)                     /*
+                                * Patch manager device
+                                */
     {
       int             err;
 
       dev--;
+
+      if (dev >= MAX_SYNTH_DEV)
+       return RET_ERROR (ENXIO);
       if (pmgr_present[dev])
        return RET_ERROR (EBUSY);
       if ((err = pmgr_open (dev)) < 0)
-       return err;             /* Failed */
+       return err;             /*
+                                * Failed
+                                */
 
       pmgr_present[dev] = 1;
       return err;
@@ -513,40 +965,105 @@ sequencer_open (int dev, struct fileinfo *file)
       return RET_ERROR (EBUSY);
     }
 
-  if (!(num_synths + num_midis))
-    return RET_ERROR (ENXIO);
+  max_mididev = num_midis;
+  max_synthdev = num_synths;
+  pre_event_timeout = 0;
+  seq_mode = SEQ_1;
 
-  synth_open_mask = 0;
+  if (pending_timer != -1)
+    {
+      tmr_no = pending_timer;
+      pending_timer = -1;
+    }
 
-  if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
-    for (i = 0; i < num_synths; i++)   /* Open synth devices */
-      if (synth_devs[i]->open (i, mode) < 0)
-       printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
-      else
-       synth_open_mask |= (1 << i);
+  if (tmr_no == -1)            /* Not selected yet */
+    {
+      int             i, best;
 
-  seq_time = GET_TIME ();
+      best = -1;
+      for (i = 0; i < num_sound_timers; i++)
+       if (sound_timer_devs[i]->priority > best)
+         {
+           tmr_no = i;
+           best = sound_timer_devs[i]->priority;
+         }
 
-  for (i = 0; i < num_midis; i++)
-    {
-      midi_opened[i] = 0;
-      midi_written[i] = 0;
+      if (tmr_no == -1)                /* Should not be */
+       tmr_no = 0;
     }
 
-  if (mode == OPEN_READ || mode == OPEN_READWRITE)
-    {                          /* Initialize midi input devices */
-      if (!num_midis)
+  tmr = sound_timer_devs[tmr_no];
+
+  if (level == 2)
+    {
+      printk ("Using timer #%d\n", tmr_no);
+      if (tmr == NULL)
        {
-         printk ("Sequencer: No Midi devices. Input not possible\n");
+         printk ("sequencer: No timer for level 2\n");
          return RET_ERROR (ENXIO);
        }
+      setup_mode2 ();
+    }
 
-      for (i = 0; i < num_midis; i++)
-       {
-         if ((retval = midi_devs[i]->open (i, mode,
+  if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE))
+    if (!max_mididev)
+      {
+       printk ("Sequencer: No Midi devices. Input not possible\n");
+       return RET_ERROR (ENXIO);
+      }
+
+  if (!max_synthdev && !max_mididev)
+    return RET_ERROR (ENXIO);
+
+  synth_open_mask = 0;
+
+  for (i = 0; i < max_mididev; i++)
+    {
+      midi_opened[i] = 0;
+      midi_written[i] = 0;
+    }
+
+  /*
+   * if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+   */
+  for (i = 0; i < max_synthdev; i++)   /*
+                                        * Open synth devices
+                                        */
+    if ((tmp = synth_devs[i]->open (i, mode)) < 0)
+      {
+       printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp);
+       if (synth_devs[i]->midi_dev)
+         printk ("(Maps to midi dev #%d\n", synth_devs[i]->midi_dev);
+      }
+    else
+      {
+       synth_open_mask |= (1 << i);
+       if (synth_devs[i]->midi_dev)    /*
+                                        * Is a midi interface
+                                        */
+         midi_opened[synth_devs[i]->midi_dev] = 1;
+      }
+
+  seq_time = GET_TIME ();
+  prev_input_time = 0;
+  prev_event_time = 0;
+
+  if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE))
+    {                          /*
+                                * Initialize midi input devices
+                                */
+      for (i = 0; i < max_mididev; i++)
+       if (!midi_opened[i])
+         {
+           if ((retval = midi_devs[i]->open (i, mode,
                         sequencer_midi_input, sequencer_midi_output)) >= 0)
-           midi_opened[i] = 1;
-       }
+             midi_opened[i] = 1;
+         }
+    }
+
+  if (seq_mode == SEQ_2)
+    {
+      tmr->open (tmr_no, seq_mode);
     }
 
   sequencer_busy = 1;
@@ -576,7 +1093,7 @@ seq_drain_midi_queues (void)
     {
       n = 0;
 
-      for (i = 0; i < num_midis; i++)
+      for (i = 0; i < max_mididev; i++)
        if (midi_opened[i] && midi_written[i])
          if (midi_devs[i]->buffer_status != NULL)
            if (midi_devs[i]->buffer_status (i))
@@ -602,7 +1119,9 @@ sequencer_release (int dev, struct fileinfo *file)
 
   DEB (printk ("sequencer_release(dev=%d)\n", dev));
 
-  if (dev)                     /* Patch manager device */
+  if (dev)                     /*
+                                * Patch manager device
+                                */
     {
       dev--;
       pmgr_release (dev);
@@ -611,34 +1130,48 @@ sequencer_release (int dev, struct fileinfo *file)
     }
 
   /*
-     * Wait until the queue is empty
+   * * Wait until the queue is empty
    */
 
-  while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
-    {
-      seq_sync ();
-    }
+  if (mode != OPEN_READ)
+    while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
+      {
+       seq_sync ();
+      }
 
   if (mode != OPEN_READ)
-    seq_drain_midi_queues ();  /* Ensure the output queues are empty */
+    seq_drain_midi_queues ();  /*
+                                * Ensure the output queues are empty
+                                */
   seq_reset ();
   if (mode != OPEN_READ)
-    seq_drain_midi_queues ();  /* Flush the all notes off messages */
-
-  for (i = 0; i < num_midis; i++)
-    if (midi_opened[i])
-      midi_devs[i]->close (i);
-
-  if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
-    for (i = 0; i < num_synths; i++)
-      if (synth_open_mask & (1 << i))  /* Actually opened */
-       if (synth_devs[i])
+    seq_drain_midi_queues ();  /*
+                                * Flush the all notes off messages
+                                */
+
+  for (i = 0; i < max_synthdev; i++)
+    if (synth_open_mask & (1 << i))    /*
+                                        * Actually opened
+                                        */
+      if (synth_devs[i])
+       {
          synth_devs[i]->close (i);
 
+         if (synth_devs[i]->midi_dev)
+           midi_opened[synth_devs[i]->midi_dev] = 0;
+       }
+
   for (i = 0; i < num_synths; i++)
     if (pmgr_present[i])
       pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
 
+  for (i = 0; i < max_mididev; i++)
+    if (midi_opened[i])
+      midi_devs[i]->close (i);
+
+  if (seq_mode == SEQ_2)
+    tmr->close (tmr_no);
+
   sequencer_busy = 0;
 }
 
@@ -648,7 +1181,10 @@ seq_sync (void)
   if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
     seq_startplay ();
 
-  if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))  /* Queue not empty */
+  if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))  /*
+                                                                * Queue not
+                                                                * empty
+                                                                */
     {
       DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
     }
@@ -665,11 +1201,19 @@ midi_outc (int dev, unsigned char data)
 
   int             n;
 
-  /* This routine sends one byte to the Midi channel. */
-  /* If the output Fifo is full, it waits until there */
-  /* is space in the queue */
+  /*
+   * This routine sends one byte to the Midi channel.
+   */
+  /*
+   * If the output Fifo is full, it waits until there
+   */
+  /*
+   * is space in the queue
+   */
 
-  n = 300;                     /* Timeout in jiffies */
+  n = 300;                     /*
+                                * Timeout in jiffies
+                                */
 
   while (n && !midi_devs[dev]->putc (dev, data))
     {
@@ -685,34 +1229,66 @@ seq_reset (void)
    * NOTE! Calls sleep(). Don't call this from interrupt.
    */
 
-  int             i, chn;
+  int             i;
+
+  int             chn;
 
   sound_stop_timer ();
+  seq_time = GET_TIME ();
+  prev_input_time = 0;
+  prev_event_time = 0;
 
   qlen = qhead = qtail = 0;
   iqlen = iqhead = iqtail = 0;
 
-  for (i = 0; i < num_synths; i++)
+  for (i = 0; i < max_synthdev; i++)
     if (synth_open_mask & (1 << i))
       if (synth_devs[i])
        synth_devs[i]->reset (i);
 
-  for (i = 0; i < num_midis; i++)
-    if (midi_written[i])       /* Midi used. Some notes may still be playing */
-      {
-       for (chn = 0; chn < 16; chn++)
+  if (seq_mode == SEQ_2)
+    {
+      for (i = 0; i < max_synthdev; i++)
+       if (synth_open_mask & (1 << i))
+         if (synth_devs[i])
+           for (chn = 0; chn < 16; chn++)
+             synth_devs[i]->controller (i, chn, 0xfe, 0);      /* All notes off */
+    }
+  else
+    {
+      for (i = 0; i < max_mididev; i++)
+       if (midi_written[i])    /*
+                                * Midi used. Some notes may still be playing
+                                */
          {
-           midi_outc (i,
-                      (unsigned char) (0xb0 + (chn & 0xff)));  /* Channel msg */
-           midi_outc (i, 0x7b);/* All notes off */
-           midi_outc (i, 0);   /* Dummy parameter */
+           /*
+ *    Sending just a ACTIVE SENSING message should be enough to stop all
+ *      playing notes. Since there are devices not recognizing the
+ *      active sensing, we have to send some all notes off messages also.
+ */
+           midi_outc (i, 0xfe);
+
+           for (chn = 0; chn < 16; chn++)
+             {
+               midi_outc (i,
+                          (unsigned char) (0xb0 + (chn & 0xff)));      /*
+                                                                * Channel
+                                                                * msg
+                                                                */
+               midi_outc (i, 0x7b);    /*
+                                        * All notes off
+                                        */
+               midi_outc (i, 0);       /*
+                                * Dummy parameter
+                                */
+             }
+
+           midi_devs[i]->close (i);
+
+           midi_written[i] = 0;
+           midi_opened[i] = 0;
          }
-
-       midi_devs[i]->close (i);
-
-       midi_written[i] = 0;
-       midi_opened[i] = 0;
-      }
+    }
 
   seq_playing = 0;
 
@@ -721,6 +1297,28 @@ seq_reset (void)
 
 }
 
+static void
+seq_panic (void)
+{
+  /*
+ * This routine is called by the application in case the user
+ * wants to reset the system to the default state.
+ */
+
+  seq_reset ();
+
+  /*
+ * Since some of the devices don't recognize the active sensing and
+ * all notes off messages, we have to shut all notes manually.
+ *
+ *      TO BE IMPLEMENTED LATER
+ */
+
+  /*
+ * Also return the controllers to their default states
+ */
+}
+
 int
 sequencer_ioctl (int dev, struct fileinfo *file,
                 unsigned int cmd, unsigned int arg)
@@ -732,20 +1330,62 @@ sequencer_ioctl (int dev, struct fileinfo *file,
 
   switch (cmd)
     {
+    case SNDCTL_TMR_TIMEBASE:
+    case SNDCTL_TMR_TEMPO:
+    case SNDCTL_TMR_START:
+    case SNDCTL_TMR_STOP:
+    case SNDCTL_TMR_CONTINUE:
+    case SNDCTL_TMR_METRONOME:
+    case SNDCTL_TMR_SOURCE:
+      if (dev)                 /* Patch manager */
+       return RET_ERROR (EIO);
 
-    case SNDCTL_SEQ_SYNC:
+      if (seq_mode != SEQ_2)
+       return RET_ERROR (EINVAL);
+      return tmr->ioctl (tmr_no, cmd, arg);
+      break;
+
+    case SNDCTL_TMR_SELECT:
       if (dev)                 /* Patch manager */
        return RET_ERROR (EIO);
 
+      if (seq_mode != SEQ_2)
+       return RET_ERROR (EINVAL);
+      pending_timer = IOCTL_IN (arg);
+
+      if (pending_timer < 0 || pending_timer >= num_sound_timers)
+       {
+         pending_timer = -1;
+         return RET_ERROR (EINVAL);
+       }
+
+      return IOCTL_OUT (arg, pending_timer);
+      break;
+
+    case SNDCTL_SEQ_PANIC:
+      seq_panic ();
+      break;
+
+    case SNDCTL_SEQ_SYNC:
+      if (dev)                 /*
+                                * Patch manager
+                                */
+       return RET_ERROR (EIO);
+
       if (mode == OPEN_READ)
        return 0;
       while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
        seq_sync ();
-      return 0;
+      if (qlen)
+       return RET_ERROR (EINTR);
+      else
+       return 0;
       break;
 
     case SNDCTL_SEQ_RESET:
-      if (dev)                 /* Patch manager */
+      if (dev)                 /*
+                                * Patch manager
+                                */
        return RET_ERROR (EIO);
 
       seq_reset ();
@@ -753,11 +1393,13 @@ sequencer_ioctl (int dev, struct fileinfo *file,
       break;
 
     case SNDCTL_SEQ_TESTMIDI:
-      if (dev)                 /* Patch manager */
+      if (dev)                 /*
+                                * Patch manager
+                                */
        return RET_ERROR (EIO);
 
       midi_dev = IOCTL_IN (arg);
-      if (midi_dev >= num_midis)
+      if (midi_dev >= max_mididev)
        return RET_ERROR (ENXIO);
 
       if (!midi_opened[midi_dev])
@@ -777,7 +1419,9 @@ sequencer_ioctl (int dev, struct fileinfo *file,
       break;
 
     case SNDCTL_SEQ_GETINCOUNT:
-      if (dev)                 /* Patch manager */
+      if (dev)                 /*
+                                * Patch manager
+                                */
        return RET_ERROR (EIO);
 
       if (mode == OPEN_WRITE)
@@ -796,7 +1440,15 @@ sequencer_ioctl (int dev, struct fileinfo *file,
       if (dev)                 /* Patch manager */
        return RET_ERROR (EIO);
 
-      /* If *arg == 0, just return the current rate */
+      /*
+       * If *arg == 0, just return the current rate
+       */
+      if (seq_mode == SEQ_2)
+       return tmr->ioctl (tmr_no, cmd, arg);
+
+      if (IOCTL_IN (arg) != 0)
+       return RET_ERROR (EINVAL);
+
       return IOCTL_OUT (arg, HZ);
       break;
 
@@ -815,11 +1467,11 @@ sequencer_ioctl (int dev, struct fileinfo *file,
       break;
 
     case SNDCTL_SEQ_NRSYNTHS:
-      return IOCTL_OUT (arg, num_synths);
+      return IOCTL_OUT (arg, max_synthdev);
       break;
 
     case SNDCTL_SEQ_NRMIDIS:
-      return IOCTL_OUT (arg, num_midis);
+      return IOCTL_OUT (arg, max_mididev);
       break;
 
     case SNDCTL_SYNTH_MEMAVL:
@@ -859,7 +1511,7 @@ sequencer_ioctl (int dev, struct fileinfo *file,
        IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf));
        dev = inf.device;
 
-       if (dev < 0 || dev >= num_synths)
+       if (dev < 0 || dev >= max_synthdev)
          return RET_ERROR (ENXIO);
 
        if (!(synth_open_mask & (1 << dev)) && !orig_dev)
@@ -877,7 +1529,7 @@ sequencer_ioctl (int dev, struct fileinfo *file,
        IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf));
        dev = inf.device;
 
-       if (dev < 0 || dev >= num_midis)
+       if (dev < 0 || dev >= max_mididev)
          return RET_ERROR (ENXIO);
 
        IOCTL_TO_USER ((char *) arg, 0, (char *) &(midi_devs[dev]->info), sizeof (inf));
@@ -957,7 +1609,9 @@ sequencer_ioctl (int dev, struct fileinfo *file,
       {
        int             tmp = IOCTL_IN (arg);
 
-       if (dev)                /* Patch manager */
+       if (dev)                /*
+                                * Patch manager
+                                */
          return RET_ERROR (EIO);
 
        if (tmp < 1)
@@ -969,8 +1623,23 @@ sequencer_ioctl (int dev, struct fileinfo *file,
       }
       break;
 
+    case SNDCTL_MIDI_PRETIME:
+      {
+       int             val = IOCTL_IN (arg);
+
+       if (val < 0)
+         val = 0;
+
+       val = (HZ * val) / 10;
+       pre_event_timeout = val;
+       return IOCTL_OUT (arg, val);
+      }
+      break;
+
     default:
-      if (dev)                 /* Patch manager */
+      if (dev)                 /*
+                                * Patch manager
+                                */
        return RET_ERROR (EIO);
 
       if (mode == OPEN_READ)
@@ -991,6 +1660,8 @@ sequencer_ioctl (int dev, struct fileinfo *file,
 int
 sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
 {
+  unsigned long   flags;
+
   dev = dev >> 4;
 
   switch (sel_type)
@@ -998,17 +1669,22 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w
     case SEL_IN:
       if (!iqlen)
        {
+         DISABLE_INTR (flags);
+         midi_sleep_flag.mode = WK_SLEEP;
          select_wait (&midi_sleeper, wait);
+         RESTORE_INTR (flags);
          return 0;
        }
       return 1;
-
       break;
 
     case SEL_OUT:
       if (qlen >= SEQ_MAX_QUEUE)
        {
+         DISABLE_INTR (flags);
+         seq_sleep_flag.mode = WK_SLEEP;
          select_wait (&seq_sleeper, wait);
+         RESTORE_INTR (flags);
          return 0;
        }
       return 1;
@@ -1042,7 +1718,7 @@ note_to_freq (int note_num)
   {
     261632, 277189, 293671, 311132, 329632, 349232,
     369998, 391998, 415306, 440000, 466162, 493880
-  };                           /* Note freq*1000 for octave 5 */
+  };
 
 #define BASE_OCTAVE    5
 
@@ -1056,7 +1732,9 @@ note_to_freq (int note_num)
   else if (octave > BASE_OCTAVE)
     note_freq <<= (octave - BASE_OCTAVE);
 
-  /* note_freq >>= 1;    */
+  /*
+   * note_freq >>= 1;
+   */
 
   return note_freq;
 }
@@ -1102,12 +1780,17 @@ compute_finetune (unsigned long base_freq, int bend, int range)
   semitones = bend / 100;
   cents = bend % 100;
 
-  amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents] / 10000;
+  amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents])
+    / 10000;
 
   if (negative)
-    return (base_freq * 10000) / amount;       /* Bend down */
+    return (base_freq * 10000) / amount;       /*
+                                                * Bend down
+                                                */
   else
-    return (base_freq * amount) / 10000;       /* Bend up */
+    return (base_freq * amount) / 10000;       /*
+                                                * Bend up
+                                                */
 }
 
 
@@ -1123,7 +1806,9 @@ sequencer_init (long mem_start)
 }
 
 #else
-/* Stub version */
+/*
+ * Stub version
+ */
 int
 sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
 {
index abc82001b77698b5f3267e3eee61eaa05bdd4a43..cbef1a4baf95e57dc3f32e531aac8cbb0d13573f 100644 (file)
@@ -4,7 +4,6 @@
 
 int DMAbuf_open(int dev, int mode);
 int DMAbuf_release(int dev, int mode);
-int DMAbuf_read (int dev, snd_rw_buf *user_buf, int count);
 int DMAbuf_getwrbuffer(int dev, char **buf, int *size);
 int DMAbuf_getrdbuffer(int dev, char **buf, int *len);
 int DMAbuf_rmchars(int dev, int buff_no, int c);
@@ -46,6 +45,8 @@ long sequencer_init (long mem_start);
 void sequencer_timer(void);
 int note_to_freq(int note_num);
 unsigned long compute_finetune(unsigned long base_freq, int bend, int range);
+void seq_input_event(unsigned char *event, int len);
+void seq_copy_to_input (unsigned char *event, int len);
 
 #ifdef ALLOW_SELECT
 int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
@@ -65,6 +66,10 @@ int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
 void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
 long MIDIbuf_init(long mem_start);
 
+#ifdef ALLOW_SELECT
+int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+#endif
+
 /*
  *     System calls for the generic midi interface.
  *
@@ -126,16 +131,16 @@ int sb16_dsp_detect(struct address_info *hw_config);
 void sb16midiintr (int unit);
 long attach_sb16midi(long mem_start, struct address_info * hw_config);
 int probe_sb16midi(struct address_info *hw_config);
+void sb_midi_interrupt(int dummy);
 
 /*     From sb_midi.c  */
 void sb_midi_init(int model);
-void sb_midi_interrupt(int dummy);
 
 /*     From sb_mixer.c */
 void sb_setmixer (unsigned int port, unsigned int value);
 int sb_getmixer (unsigned int port);
 void sb_mixer_set_stereo(int mode);
-int sb_mixer_init(int major_model);
+void sb_mixer_init(int major_model);
 
 /*     From opl3.c     */
 int opl3_detect (int ioaddr);
@@ -173,6 +178,8 @@ long attach_gus_card(long mem_start, struct address_info * hw_config);
 int probe_gus(struct address_info *hw_config);
 int gus_set_midi_irq(int num);
 void gusintr(int);
+long attach_gus_db16(long mem_start, struct address_info * hw_config);
+int probe_gus_db16(struct address_info *hw_config);
 
 /*     From gus_wave.c */
 int gus_wave_detect(int baseaddr);
@@ -192,6 +199,10 @@ void gus_midi_interrupt(int dummy);
 long attach_mpu401(long mem_start, struct address_info * hw_config);
 int probe_mpu401(struct address_info *hw_config);
 
+/*     From uart6850.c */
+long attach_uart6850(long mem_start, struct address_info * hw_config);
+int probe_uart6850(struct address_info *hw_config);
+
 /*     From opl3.c */
 void enable_opl3_mode(int left, int right, int both);
 
@@ -206,3 +217,27 @@ int pmgr_inform(int dev, int event, unsigned long parm1, unsigned long parm2,
 
 /*     From ics2101.c */
 long ics2101_mixer_init(long mem_start);
+
+/*     From sound_timer.c */
+void sound_timer_init(int io_base);
+void sound_timer_interrupt(void);
+
+/*     From ad1848.c */
+void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture);
+int ad1848_detect (int io_base);
+void     ad1848_interrupt (int dev);
+long attach_ms_sound(long mem_start, struct address_info * hw_config);
+int probe_ms_sound(struct address_info *hw_config);
+
+/*     From pss.c */
+int probe_pss (struct address_info *hw_config);
+long attach_pss (long mem_start, struct address_info *hw_config);
+
+int pss_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int pss_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int pss_open (int dev, struct fileinfo *file);
+void pss_release (int dev, struct fileinfo *file);
+int pss_ioctl (int dev, struct fileinfo *file,
+          unsigned int cmd, unsigned int arg);
+int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
+long pss_init(long mem_start);
index 1cad333c92c9ae631ecba3ef1a4b98467bb96c45..68e61632b9163c2db904fcc69a68472aa3a1f142 100644 (file)
 
 #include "local.h"
 
+#if defined(ISC) || defined(SCO) || defined(SVR42)
+#define GENERIC_SYSV
+#endif
+
+/*
+ * Disable the AD1848 driver if there are no other drivers requiring it.
+ */
+
+#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX)
+#define EXCLUDE_AD1848
+#endif
 
 #undef CONFIGURE_SOUNDCARD
 #undef DYNAMIC_BUFFER
 #define SND_DEFAULT_ENABLE     1
 #endif
 
-/** UWM - new MIDI stuff **/
-
-#ifdef EXCLUDE_CHIP_MIDI
-#define EXCLUDE_PRO_MIDI
-#endif
-
-/** UWM - stuff **/
-#if defined(EXCLUDE_SEQUENCER) && defined(EXCLUDE_AUDIO)
-#undef CONFIGURE_SOUNDCARD
-#endif
-
 #ifdef CONFIGURE_SOUNDCARD
 
 /* ****** IO-address, DMA and IRQ settings ****
@@ -125,6 +124,19 @@ If your card has nonstandard I/O address or IRQ number, change defines
 #define MPU_IRQ                6
 #endif
 
+/* Echo Personal Sound System */
+#ifndef PSS_BASE
+#define PSS_BASE        0x220   /* 0x240 or */
+#endif
+
+#ifndef PSS_IRQ
+#define PSS_IRQ         7
+#endif
+
+#ifndef PSS_DMA
+#define PSS_DMA         1
+#endif
+
 #ifndef MAX_REALTIME_FACTOR
 #define MAX_REALTIME_FACTOR    4
 #endif
@@ -156,48 +168,42 @@ If your card has nonstandard I/O address or IRQ number, change defines
    driver. (There is no need to alter this) */
 #define SEQ_MAX_QUEUE  1024
 
-#define SBFM_MAXINSTR          (256)   /* Size of the FM Instrument
-                                                  bank                          */
+#define SBFM_MAXINSTR          (256)   /* Size of the FM Instrument bank */
 /* 128 instruments for general MIDI setup and 16 unassigned     */
 
-#define SND_NDEVS      50      /* Number of supported devices */
+/*
+ * Minor numbers for the sound driver.
+ *
+ * Unfortunately Creative called the codec chip of SB as a DSP. For this
+ * reason the /dev/dsp is reserved for digitized audio use. There is a
+ * device for true DSP processors but it will be called something else.
+ * In v3.0 it's /dev/sndproc but this could be a temporary solution.
+ */
+
+#define SND_NDEVS      64      /* Number of supported devices */
 #define SND_DEV_CTL    0       /* Control port /dev/mixer */
 #define SND_DEV_SEQ    1       /* Sequencer output /dev/sequencer (FM
                                   synthesizer and MIDI output) */
-#define SND_DEV_MIDIN  2       /* MIDI input /dev/midin (not implemented
-                                  yet) */
+#define SND_DEV_MIDIN  2       /* Raw midi access */
 #define SND_DEV_DSP    3       /* Digitized voice /dev/dsp */
 #define SND_DEV_AUDIO  4       /* Sparc compatible /dev/audio */
 #define SND_DEV_DSP16  5       /* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS 6       /* /dev/sndstatus */
-
-/* UWM ... note add new MIDI devices here..  
- *  Also do not forget to add table midi_supported[]
- *  Minor numbers for on-chip midi devices start from 15.. and 
- *  should be contiguous.. viz. 15,16,17....
- * ERROR!!!!!!!!! NO NO. Minor numbers above 15 are reserved!!!!!! Hannu
- *  Also note the max # of midi devices as MAX_MIDI_DEV
- */ 
-
-#define CMIDI_DEV_PRO  15      /* Chip midi device == /dev/pro_midi */
-
-/*
- *  Add other midis here...
-               .
-               .
-               .
-               .
- */
+#define SND_DEV_STATUS 6       /* /dev/sndstat */
+/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
+#define SND_DEV_SEQ2   8       /* /dev/sequecer, level 2 interface */
+#define SND_DEV_SNDPROC 9      /* /dev/sndproc for programmable devices */
+#define SND_DEV_PSS    SND_DEV_SNDPROC
 
 #define DSP_DEFAULT_SPEED      8000
 
 #define ON             1
 #define OFF            0
 
-#define MAX_DSP_DEV    4
+#define MAX_AUDIO_DEV  4
 #define MAX_MIXER_DEV  2
 #define MAX_SYNTH_DEV  3
-#define MAX_MIDI_DEV   4
+#define MAX_MIDI_DEV   6
+#define MAX_TIMER_DEV  3
 
 struct fileinfo {
                  int mode;     /* Open mode */
@@ -209,6 +215,20 @@ struct address_info {
        int dma;
 };
 
+#define SYNTH_MAX_VOICES       32
+
+struct voice_alloc_info {
+               int max_voice;
+               int used_voices;
+               int ptr;                /* For device specific use */
+               unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */
+       };
+
+struct channel_info {
+               int pgm_num;
+               unsigned char controllers[128];
+       };
+
 /*
  * Process wakeup reasons
  */
@@ -228,6 +248,11 @@ struct address_info {
 
 #ifndef DEB
 #define DEB(x)
+
+#define TIMER_ARMED    121234
+#define TIMER_NOT_ARMED        1
+
+#define FUTURE_VERSION
 #endif
 
 #endif
index 68c757586083e696c3a7df67a9974e3284f61178..fe73aea93e070976ab636a8c5a588d953223c2c6 100644 (file)
@@ -40,9 +40,11 @@ static struct sbc_device sbc_devices[SND_NDEVS] =
 {
   {0}};
 
-static int      in_use = 0;    /* Total # of open device files (excluding
+static int      in_use = 0;    /*
 
-                                * minor 0) */
+
+                                * *  * * Total # of open device files
+                                * (excluding * * * minor 0)   */
 
 /*
  * /dev/sndstatus -device
@@ -56,7 +58,9 @@ put_status (char *s)
 {
   int             l;
 
-  for (l = 0; l < 256, s[l]; l++);     /* l=strlen(s); */
+  for (l = 0; l < 256, s[l]; l++);     /*
+                                        * l=strlen(s);
+                                        */
 
   if (status_len + l >= 4000)
     return 0;
@@ -121,37 +125,58 @@ init_status (void)
   if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
     return;
 
-  if (!put_status ("\n\nHW config: \n"))
+  if (!put_status ("\n\nInstalled drivers: \n"))
     return;
 
   for (i = 0; i < (num_sound_drivers - 1); i++)
     {
-      if (!supported_drivers[i].enabled)
-       if (!put_status ("("))
-         return;
-
       if (!put_status ("Type "))
        return;
-      if (!put_status_int (supported_drivers[i].card_type, 10))
+      if (!put_status_int (sound_drivers[i].card_type, 10))
        return;
       if (!put_status (": "))
        return;
-      if (!put_status (supported_drivers[i].name))
+      if (!put_status (sound_drivers[i].name))
+       return;
+
+      if (!put_status ("\n"))
        return;
+    }
+
+  if (!put_status ("\n\nCard config: \n"))
+    return;
+
+  for (i = 0; i < (num_sound_cards - 1); i++)
+    {
+      int             drv;
+
+      if (!snd_installed_cards[i].enabled)
+       if (!put_status ("("))
+         return;
+
+      /*
+       * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return;
+       * if (!put_status (": ")) return;
+       */
+
+      if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1)
+       if (!put_status (sound_drivers[drv].name))
+         return;
+
       if (!put_status (" at 0x"))
        return;
-      if (!put_status_int (supported_drivers[i].config.io_base, 16))
+      if (!put_status_int (snd_installed_cards[i].config.io_base, 16))
        return;
       if (!put_status (" irq "))
        return;
-      if (!put_status_int (supported_drivers[i].config.irq, 10))
+      if (!put_status_int (snd_installed_cards[i].config.irq, 10))
        return;
       if (!put_status (" drq "))
        return;
-      if (!put_status_int (supported_drivers[i].config.dma, 10))
+      if (!put_status_int (snd_installed_cards[i].config.dma, 10))
        return;
 
-      if (!supported_drivers[i].enabled)
+      if (!snd_installed_cards[i].enabled)
        if (!put_status (")"))
          return;
 
@@ -162,13 +187,13 @@ init_status (void)
   if (!put_status ("\nPCM devices:\n"))
     return;
 
-  for (i = 0; i < num_dspdevs; i++)
+  for (i = 0; i < num_audiodevs; i++)
     {
       if (!put_status_int (i, 10))
        return;
       if (!put_status (": "))
        return;
-      if (!put_status (dsp_devs[i]->name))
+      if (!put_status (audio_devs[i]->name))
        return;
       if (!put_status ("\n"))
        return;
@@ -204,16 +229,27 @@ init_status (void)
        return;
     }
 
-  if (num_mixers)
+  if (!put_status ("\nMIDI Timers:\n"))
+    return;
+
+  for (i = 0; i < num_sound_timers; i++)
     {
-      if (!put_status ("\nMixer(s) installed\n"))
+      if (!put_status_int (i, 10))
        return;
-    }
-  else
-    {
-      if (!put_status ("\nNo mixers installed\n"))
+      if (!put_status (": "))
+       return;
+      if (!put_status (sound_timer_devs[i]->info.name))
+       return;
+      if (!put_status ("\n"))
        return;
     }
+
+  if (!put_status ("\n"))
+    return;
+  if (!put_status_int (num_mixers, 10))
+    return;
+  if (!put_status (" mixer(s) installed\n"))
+    return;
 }
 
 static int
@@ -256,14 +292,20 @@ sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
       break;
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       return sequencer_read (dev, file, buf, count);
       break;
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_read (dev, file, buf, count);
 #endif
 
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      return pss_read (dev, file, buf, count);
+#endif
+
     default:
       printk ("Sound: Undefined minor device %d\n", dev);
     }
@@ -281,6 +323,7 @@ sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
     {
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       return sequencer_write (dev, file, buf, count);
       break;
 
@@ -290,6 +333,16 @@ sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
       return audio_write (dev, file, buf, count);
       break;
 
+#ifndef EXCLUDE_MIDI
+    case SND_DEV_MIDIN:
+      return MIDIbuf_write (dev, file, buf, count);
+#endif
+
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      return pss_write (dev, file, buf, count);
+#endif
+
     default:
       return RET_ERROR (EPERM);
     }
@@ -327,17 +380,25 @@ sound_open_sw (int dev, struct fileinfo *file)
       break;
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       if ((retval = sequencer_open (dev, file)) < 0)
        return retval;
       break;
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       if ((retval = MIDIbuf_open (dev, file)) < 0)
        return retval;
       break;
 #endif
 
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      if ((retval = pss_open (dev, file)) < 0)
+       return retval;
+      break;
+#endif
+
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -375,15 +436,22 @@ sound_release_sw (int dev, struct fileinfo *file)
       break;
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       sequencer_release (dev, file);
       break;
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       MIDIbuf_release (dev, file);
       break;
 #endif
 
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      pss_release (dev, file);
+      break;
+#endif
+
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -404,6 +472,12 @@ sound_ioctl_sw (int dev, struct fileinfo *file,
 {
   DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
 
+  if ((dev & 0x0f) != SND_DEV_CTL && num_mixers > 0)
+    if ((cmd >> 8) & 0xff == 'M')      /*
+                                        * Mixer ioctl
+                                        */
+      return mixer_devs[0]->ioctl (0, cmd, arg);
+
   switch (dev & 0x0f)
     {
 
@@ -412,13 +486,16 @@ sound_ioctl_sw (int dev, struct fileinfo *file,
       if (!num_mixers)
        return RET_ERROR (ENXIO);
 
-      if ((dev >> 4) >= num_mixers)
+      dev = dev >> 4;
+
+      if (dev >= num_mixers)
        return RET_ERROR (ENXIO);
 
-      return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg);
+      return mixer_devs[dev]->ioctl (dev, cmd, arg);
       break;
 
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       return sequencer_ioctl (dev, file, cmd, arg);
       break;
 
@@ -428,12 +505,18 @@ sound_ioctl_sw (int dev, struct fileinfo *file,
       return audio_ioctl (dev, file, cmd, arg);
       break;
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_ioctl (dev, file, cmd, arg);
       break;
 #endif
 
+#ifndef EXCLUDE_PSS
+    case SND_DEV_PSS:
+      return pss_ioctl (dev, file, cmd, arg);
+      break;
+#endif
+
     default:
       return RET_ERROR (EPERM);
       break;
diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c
new file mode 100644 (file)
index 0000000..c6544c8
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * sound/sound_timer.c
+ *
+ * Timer for the level 2 interface of the /dev/sequencer. Uses the
+ * 80 and 320 usec timers of OPL-3 (PAS16 only) and GUS.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define SEQUENCER_C
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#if !defined(EXCLUDE_SEQUENCER) && (!defined(EXCLUDE_GUS) || (!defined(EXCLUDE_PAS) && !defined(EXCLUDE_YM3812)))
+
+static volatile int initialized = 0, opened = 0, tmr_running = 0;
+static volatile time_t tmr_offs, tmr_ctr;
+static volatile unsigned long ticks_offs;
+static volatile int curr_tempo, curr_timebase;
+static volatile unsigned long curr_ticks;
+static volatile unsigned long next_event_time;
+static unsigned long prev_event_time;
+static volatile int select_addr, data_addr;
+static volatile int curr_timer = 0;
+static volatile unsigned long usecs_per_tmr;   /* Length of the current interval */
+
+
+static void
+timer_command (unsigned int addr, unsigned int val)
+{
+  int             i;
+
+  OUTB ((unsigned char) (addr & 0xff), select_addr);
+
+  for (i = 0; i < 2; i++)
+    INB (select_addr);
+
+  OUTB ((unsigned char) (val & 0xff), data_addr);
+
+  for (i = 0; i < 2; i++)
+    INB (select_addr);
+}
+
+static void
+arm_timer (int timer, unsigned int interval)
+{
+
+  curr_timer = timer;
+
+  if (timer == 1)
+    {
+      gus_write8 (0x46, 256 - interval);       /* Set counter for timer 1 */
+      gus_write8 (0x45, 0x04); /* Enable timer 1 IRQ */
+      timer_command (0x04, 0x01);      /* Start timer 1 */
+    }
+  else
+    {
+      gus_write8 (0x47, 256 - interval);       /* Set counter for timer 2 */
+      gus_write8 (0x45, 0x08); /* Enable timer 2 IRQ */
+      timer_command (0x04, 0x02);      /* Start timer 2 */
+    }
+}
+
+static unsigned long
+tmr2ticks (int tmr_value)
+{
+  /*
+ *    Convert timer ticks to MIDI ticks
+ */
+
+  unsigned long   tmp;
+  unsigned long   scale;
+
+  tmp = tmr_value * usecs_per_tmr;     /* Convert to usecs */
+
+  scale = (60 * 1000000) / (curr_tempo * curr_timebase);       /* usecs per MIDI tick */
+
+  return (tmp + (scale / 2)) / scale;
+}
+
+static void
+reprogram_timer (void)
+{
+  unsigned long   usecs_per_tick;
+  int             timer_no, resolution;
+  int             divisor;
+
+  usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
+
+  /*
+ * Don't kill the system by setting too high timer rate
+ */
+  if (usecs_per_tick < 2000)
+    usecs_per_tick = 2000;
+
+  if (usecs_per_tick > (256 * 80))
+    {
+      timer_no = 2;
+      resolution = 320;                /* usec */
+    }
+  else
+    {
+      timer_no = 1;
+      resolution = 80;         /* usec */
+    }
+
+  divisor = (usecs_per_tick + (resolution / 2)) / resolution;
+  usecs_per_tmr = divisor * resolution;
+
+  arm_timer (timer_no, divisor);
+}
+
+static void
+tmr_reset (void)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  tmr_offs = 0;
+  ticks_offs = 0;
+  tmr_ctr = 0;
+  next_event_time = 0xffffffff;
+  prev_event_time = 0;
+  curr_ticks = 0;
+  RESTORE_INTR (flags);
+}
+
+static int
+timer_open (int dev, int mode)
+{
+  if (opened)
+    return RET_ERROR (EBUSY);
+
+  tmr_reset ();
+  curr_tempo = 60;
+  curr_timebase = HZ;
+  opened = 1;
+  reprogram_timer ();
+
+  return 0;
+}
+
+static void
+timer_close (int dev)
+{
+  opened = tmr_running = 0;
+  gus_write8 (0x45, 0);                /* Disable both timers */
+}
+
+static int
+timer_event (int dev, unsigned char *event)
+{
+  unsigned char   cmd = event[1];
+  unsigned long   parm = *(int *) &event[4];
+
+  switch (cmd)
+    {
+    case TMR_WAIT_REL:
+      parm += prev_event_time;
+    case TMR_WAIT_ABS:
+      if (parm > 0)
+       {
+         long            time;
+
+         if (parm <= curr_ticks)       /* It's the time */
+           return TIMER_NOT_ARMED;
+
+         time = parm;
+         next_event_time = prev_event_time = time;
+
+         return TIMER_ARMED;
+       }
+      break;
+
+    case TMR_START:
+      tmr_reset ();
+      tmr_running = 1;
+      reprogram_timer ();
+      break;
+
+    case TMR_STOP:
+      tmr_running = 0;
+      break;
+
+    case TMR_CONTINUE:
+      tmr_running = 1;
+      reprogram_timer ();
+      break;
+
+    case TMR_TEMPO:
+      if (parm)
+       {
+         if (parm < 8)
+           parm = 8;
+         if (parm > 250)
+           parm = 250;
+         tmr_offs = tmr_ctr;
+         ticks_offs += tmr2ticks (tmr_ctr);
+         tmr_ctr = 0;
+         curr_tempo = parm;
+         reprogram_timer ();
+       }
+      break;
+
+    case TMR_ECHO:
+      seq_copy_to_input (event, 8);
+      break;
+
+    default:;
+    }
+
+  return TIMER_NOT_ARMED;
+}
+
+static unsigned long
+timer_get_time (int dev)
+{
+  if (!opened)
+    return 0;
+
+  return curr_ticks;
+}
+
+static int
+timer_ioctl (int dev,
+            unsigned int cmd, unsigned int arg)
+{
+  switch (cmd)
+    {
+    case SNDCTL_TMR_SOURCE:
+      return IOCTL_OUT (arg, TMR_INTERNAL);
+      break;
+
+    case SNDCTL_TMR_START:
+      tmr_reset ();
+      tmr_running = 1;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_STOP:
+      tmr_running = 0;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_CONTINUE:
+      tmr_running = 1;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_TIMEBASE:
+      {
+       int             val = IOCTL_IN (arg);
+
+       if (val)
+         {
+           if (val < 1)
+             val = 1;
+           if (val > 1000)
+             val = 1000;
+           curr_timebase = val;
+         }
+
+       return IOCTL_OUT (arg, curr_timebase);
+      }
+      break;
+
+    case SNDCTL_TMR_TEMPO:
+      {
+       int             val = IOCTL_IN (arg);
+
+       if (val)
+         {
+           if (val < 8)
+             val = 8;
+           if (val > 250)
+             val = 250;
+           tmr_offs = tmr_ctr;
+           ticks_offs += tmr2ticks (tmr_ctr);
+           tmr_ctr = 0;
+           curr_tempo = val;
+           reprogram_timer ();
+         }
+
+       return IOCTL_OUT (arg, curr_tempo);
+      }
+      break;
+
+    case SNDCTL_SEQ_CTRLRATE:
+      if (IOCTL_IN (arg) != 0) /* Can't change */
+       return RET_ERROR (EINVAL);
+
+      return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+      break;
+
+    case SNDCTL_TMR_METRONOME:
+      /* NOP */
+      break;
+
+    default:
+    }
+
+  return RET_ERROR (EINVAL);
+}
+
+static void
+timer_arm (int dev, long time)
+{
+  if (time < 0)
+    time = curr_ticks + 1;
+  else if (time <= curr_ticks) /* It's the time */
+    return;
+
+  next_event_time = prev_event_time = time;
+
+  return;
+}
+
+static struct sound_timer_operations sound_timer =
+{
+  {"OPL-3/GUS Timer", 0},
+  1,                           /* Priority */
+  0,                           /* Local device link */
+  timer_open,
+  timer_close,
+  timer_event,
+  timer_get_time,
+  timer_ioctl,
+  timer_arm
+};
+
+void
+sound_timer_interrupt (void)
+{
+  gus_write8 (0x45, 0);                /* Ack IRQ */
+  timer_command (4, 0x80);     /* Reset IRQ flags */
+
+  if (!opened)
+    return;
+
+  if (curr_timer == 1)
+    gus_write8 (0x45, 0x04);   /* Start timer 1 again */
+  else
+    gus_write8 (0x45, 0x08);   /* Start timer 2 again */
+
+  if (!tmr_running)
+    return;
+
+  tmr_ctr++;
+  curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
+
+  if (curr_ticks >= next_event_time)
+    {
+      next_event_time = 0xffffffff;
+      sequencer_timer ();
+    }
+}
+
+void
+sound_timer_init (int io_base)
+{
+  int             n;
+
+  if (initialized)
+    return;                    /* There is already a similar timer */
+
+  select_addr = io_base;
+  data_addr = io_base + 1;
+
+  initialized = 1;
+
+#if 1
+  if (num_sound_timers >= MAX_TIMER_DEV)
+    n = 0;                     /* Overwrite the system timer */
+  else
+    n = num_sound_timers++;
+#else
+  n = 0;
+#endif
+
+  sound_timer_devs[n] = &sound_timer;
+}
+
+#endif
+#endif
index 9708994c7d92bb71fb9b5661bb1fa6a580465c01..bdacb5235e7e817ae0c784b04c3141f2a335eebe 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * linux/kernel/chr_drv/sound/soundcard.c
  *
@@ -34,8 +33,6 @@
 
 #include <linux/major.h>
 
-extern long     seq_time;
-
 static int      soundcards_installed = 0;      /* Number of installed
 
                                                 * soundcards */
@@ -43,10 +40,6 @@ static int      soundcard_configured = 0;
 
 static struct fileinfo files[SND_NDEVS];
 
-extern char    *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
-extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
-extern int      snd_raw_count[MAX_DSP_DEV];
-
 int
 snd_ioctl_return (int *addr, int value)
 {
@@ -146,9 +139,17 @@ sound_select (struct inode *inode, struct file *file, int sel_type, select_table
 
   switch (dev & 0x0f)
     {
+#ifndef EXCLUDE_SEQUENCER
     case SND_DEV_SEQ:
       return sequencer_select (dev, &files[dev], sel_type, wait);
       break;
+#endif
+
+#ifndef EXCLUDE_MIDI
+    case SND_DEV_MIDIN:
+      return MIDIbuf_select (dev, &files[dev], sel_type, wait);
+      break;
+#endif
 
     default:
       return 0;
@@ -183,19 +184,23 @@ soundcard_init (long mem_start)
   if (!(soundcards_installed = sndtable_get_cardcount ()))
     return mem_start;          /* No cards detected */
 
-  if (num_dspdevs)             /* Audio devices present */
+#ifndef EXCLUDE_AUDIO
+  if (num_audiodevs)           /* Audio devices present */
     {
       mem_start = DMAbuf_init (mem_start);
       mem_start = audio_init (mem_start);
     }
+#endif
 
-#ifndef EXCLUDE_MPU401
+#ifndef EXCLUDE_MIDI
   if (num_midis)
     mem_start = MIDIbuf_init (mem_start);
 #endif
 
+#ifndef EXCLUDE_SEQUENCER
   if (num_midis + num_synths)
     mem_start = sequencer_init (mem_start);
+#endif
 
   return mem_start;
 }
@@ -243,10 +248,13 @@ snd_release_irq (int vect)
   free_irq (vect);
 }
 
+#ifndef EXCLUDE_SEQUENCER
 void
 request_sound_timer (int count)
 {
-#ifndef EXCLUDE_SEQUENCER
+  extern unsigned long seq_time;
+
+#if 1
   if (count < 0)
     count = jiffies + (-count);
   else
@@ -257,10 +265,12 @@ request_sound_timer (int count)
 #endif
 }
 
+#endif
+
 void
 sound_stop_timer (void)
 {
-#ifndef EXCLUDE_SEQUENCER
+#if 1
   timer_table[SOUND_TIMER].expires = 0;
   timer_active &= ~(1 << SOUND_TIMER);
 #endif
@@ -281,6 +291,7 @@ sound_mem_init (void)
 {
   int             i, dev;
   unsigned long   start_addr, end_addr, mem_ptr, dma_pagesize;
+  struct dma_buffparms *dmap;
 
   mem_ptr = high_memory;
 
@@ -289,38 +300,40 @@ sound_mem_init (void)
   if (mem_ptr > (16 * 1024 * 1024))
     mem_ptr = 16 * 1024 * 1024;        /* Limit to 16M */
 
-  for (dev = 0; dev < num_dspdevs; dev++)      /* Enumerate devices */
-    if (sound_buffcounts[dev] > 0 && sound_dsp_dmachan[dev] > 0)
+  for (dev = 0; dev < num_audiodevs; dev++)    /* Enumerate devices */
+    if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
       {
-       if (sound_dma_automode[dev])
-         sound_buffcounts[dev] = 1;
+       dmap = audio_devs[dev]->dmap;
+
+       if (audio_devs[dev]->flags & DMA_AUTOMODE)
+         audio_devs[dev]->buffcount = 1;
 
-       if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536)
+       if (audio_devs[dev]->dmachan > 3 && audio_devs[dev]->buffsize > 65536)
          dma_pagesize = 131072;/* 128k */
        else
          dma_pagesize = 65536;
 
        /* More sanity checks */
 
-       if (sound_buffsizes[dev] > dma_pagesize)
-         sound_buffsizes[dev] = dma_pagesize;
-       sound_buffsizes[dev] &= 0xfffff000;     /* Truncate to n*4k */
-       if (sound_buffsizes[dev] < 4096)
-         sound_buffsizes[dev] = 4096;
+       if (audio_devs[dev]->buffsize > dma_pagesize)
+         audio_devs[dev]->buffsize = dma_pagesize;
+       audio_devs[dev]->buffsize &= 0xfffff000;        /* Truncate to n*4k */
+       if (audio_devs[dev]->buffsize < 4096)
+         audio_devs[dev]->buffsize = 4096;
 
        /* Now allocate the buffers */
 
-       for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++)
+       for (dmap->raw_count = 0; dmap->raw_count < audio_devs[dev]->buffcount; dmap->raw_count++)
          {
-           start_addr = mem_ptr - sound_buffsizes[dev];
-           if (!valid_dma_page (start_addr, sound_buffsizes[dev], dma_pagesize))
+           start_addr = mem_ptr - audio_devs[dev]->buffsize;
+           if (!valid_dma_page (start_addr, audio_devs[dev]->buffsize, dma_pagesize))
              start_addr &= ~(dma_pagesize - 1);        /* Align address to
                                                         * dma_pagesize */
 
-           end_addr = start_addr + sound_buffsizes[dev] - 1;
+           end_addr = start_addr + audio_devs[dev]->buffsize - 1;
 
-           snd_raw_buf[dev][snd_raw_count[dev]] = (char *) start_addr;
-           snd_raw_buf_phys[dev][snd_raw_count[dev]] = start_addr;
+           dmap->raw_buf[dmap->raw_count] = (char *) start_addr;
+           dmap->raw_buf_phys[dmap->raw_count] = start_addr;
            mem_ptr = start_addr;
 
            for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
diff --git a/drivers/sound/sys_timer.c b/drivers/sound/sys_timer.c
new file mode 100644 (file)
index 0000000..1000045
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * sound/sys_timer.c
+ *
+ * The default timer for the Level 2 sequencer interface
+ * Uses the (100HZ) timer of kernel.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define SEQUENCER_C
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#ifndef EXCLUDE_SEQUENCER
+
+static volatile int opened = 0, tmr_running = 0;
+static volatile time_t tmr_offs, tmr_ctr;
+static volatile unsigned long ticks_offs;
+static volatile int curr_tempo, curr_timebase;
+static volatile unsigned long curr_ticks;
+static volatile unsigned long next_event_time;
+static unsigned long prev_event_time;
+
+static void     poll_def_tmr (unsigned long dummy);
+
+DEFINE_TIMER (def_tmr, poll_def_tmr);
+
+static unsigned long
+tmr2ticks (int tmr_value)
+{
+  /*
+ *    Convert system timer ticks (HZ) to MIDI ticks
+ */
+
+  unsigned long   tmp;
+  unsigned long   scale;
+
+  tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */
+
+  scale = (60 * 1000) / (curr_tempo * curr_timebase);  /* msecs per MIDI tick */
+
+  return (tmp + (scale / 2)) / scale;
+}
+
+static void
+poll_def_tmr (unsigned long dummy)
+{
+
+  if (opened)
+    {
+      ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);
+
+      if (tmr_running)
+       {
+         tmr_ctr++;
+         curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
+
+         if (curr_ticks >= next_event_time)
+           {
+             next_event_time = 0xffffffff;
+             sequencer_timer ();
+           }
+       }
+    }
+}
+
+static void
+tmr_reset (void)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  tmr_offs = 0;
+  ticks_offs = 0;
+  tmr_ctr = 0;
+  next_event_time = 0xffffffff;
+  prev_event_time = 0;
+  curr_ticks = 0;
+  RESTORE_INTR (flags);
+}
+
+static int
+def_tmr_open (int dev, int mode)
+{
+  if (opened)
+    return RET_ERROR (EBUSY);
+
+  tmr_reset ();
+  curr_tempo = 60;
+  curr_timebase = HZ;
+  opened = 1;
+
+  ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);
+
+  return 0;
+}
+
+static void
+def_tmr_close (int dev)
+{
+  opened = tmr_running = 0;
+}
+
+static int
+def_tmr_event (int dev, unsigned char *event)
+{
+  unsigned char   cmd = event[1];
+  unsigned long   parm = *(int *) &event[4];
+
+  switch (cmd)
+    {
+    case TMR_WAIT_REL:
+      parm += prev_event_time;
+    case TMR_WAIT_ABS:
+      if (parm > 0)
+       {
+         long            time;
+
+         if (parm <= curr_ticks)       /* It's the time */
+           return TIMER_NOT_ARMED;
+
+         time = parm;
+         next_event_time = prev_event_time = time;
+
+         return TIMER_ARMED;
+       }
+      break;
+
+    case TMR_START:
+      tmr_reset ();
+      tmr_running = 1;
+      break;
+
+    case TMR_STOP:
+      tmr_running = 0;
+      break;
+
+    case TMR_CONTINUE:
+      tmr_running = 1;
+      break;
+
+    case TMR_TEMPO:
+      if (parm)
+       {
+         if (parm < 8)
+           parm = 8;
+         if (parm > 250)
+           parm = 250;
+         tmr_offs = tmr_ctr;
+         ticks_offs += tmr2ticks (tmr_ctr);
+         tmr_ctr = 0;
+         curr_tempo = parm;
+       }
+      break;
+
+    case TMR_ECHO:
+      seq_copy_to_input (event, 8);
+      break;
+
+    default:;
+    }
+
+  return TIMER_NOT_ARMED;
+}
+
+static unsigned long
+def_tmr_get_time (int dev)
+{
+  if (!opened)
+    return 0;
+
+  return curr_ticks;
+}
+
+static int
+def_tmr_ioctl (int dev,
+              unsigned int cmd, unsigned int arg)
+{
+  switch (cmd)
+    {
+    case SNDCTL_TMR_SOURCE:
+      return IOCTL_OUT (arg, TMR_INTERNAL);
+      break;
+
+    case SNDCTL_TMR_START:
+      tmr_reset ();
+      tmr_running = 1;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_STOP:
+      tmr_running = 0;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_CONTINUE:
+      tmr_running = 1;
+      return 0;
+      break;
+
+    case SNDCTL_TMR_TIMEBASE:
+      {
+       int             val = IOCTL_IN (arg);
+
+       if (val)
+         {
+           if (val < 1)
+             val = 1;
+           if (val > 1000)
+             val = 1000;
+           curr_timebase = val;
+         }
+
+       return IOCTL_OUT (arg, curr_timebase);
+      }
+      break;
+
+    case SNDCTL_TMR_TEMPO:
+      {
+       int             val = IOCTL_IN (arg);
+
+       if (val)
+         {
+           if (val < 8)
+             val = 8;
+           if (val > 250)
+             val = 250;
+           tmr_offs = tmr_ctr;
+           ticks_offs += tmr2ticks (tmr_ctr);
+           tmr_ctr = 0;
+           curr_tempo = val;
+         }
+
+       return IOCTL_OUT (arg, curr_tempo);
+      }
+      break;
+
+    case SNDCTL_SEQ_CTRLRATE:
+      if (IOCTL_IN (arg) != 0) /* Can't change */
+       return RET_ERROR (EINVAL);
+
+      return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+      break;
+
+    case SNDCTL_TMR_METRONOME:
+      /* NOP */
+      break;
+
+    default:;
+    }
+
+  return RET_ERROR (EINVAL);
+}
+
+static void
+def_tmr_arm (int dev, long time)
+{
+  if (time < 0)
+    time = curr_ticks + 1;
+  else if (time <= curr_ticks) /* It's the time */
+    return;
+
+  next_event_time = prev_event_time = time;
+
+  return;
+}
+
+struct sound_timer_operations default_sound_timer =
+{
+  {"System Timer", 0},
+  0,                           /* Priority */
+  0,                           /* Local device link */
+  def_tmr_open,
+  def_tmr_close,
+  def_tmr_event,
+  def_tmr_get_time,
+  def_tmr_ioctl,
+  def_tmr_arm
+};
+
+#endif
+#endif
diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c
new file mode 100644 (file)
index 0000000..ca63135
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * sound/uart6850.c
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl:
+ *      added 6850 support, used with COVOX SoundMaster II and custom cards.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+
+#define        DATAPORT   (uart6850_base)      /*
+                                          * * * Midi6850 Data I/O Port on IBM
+                                          *  */
+#define        COMDPORT   (uart6850_base+1)    /*
+                                          * * * Midi6850 Command Port on IBM   */
+#define        STATPORT   (uart6850_base+1)    /*
+                                          * * * Midi6850 Status Port on IBM   */
+
+#define uart6850_status()              INB(STATPORT)
+#define input_avail()          ((uart6850_status()&INPUT_AVAIL))
+#define output_ready()         ((uart6850_status()&OUTPUT_READY))
+#define uart6850_cmd(cmd)      OUTB(cmd, COMDPORT)
+#define uart6850_read()                INB(DATAPORT)
+#define uart6850_write(byte)   OUTB(byte, DATAPORT)
+
+#define        OUTPUT_READY    0x02    /*
+                                  * * * Mask for Data Read Ready Bit   */
+#define        INPUT_AVAIL     0x01    /*
+                                  * * * Mask for Data Send Ready Bit   */
+
+#define        UART_RESET      0x95    /*
+                                  * * * 6850 Total Reset Command   */
+#define        UART_MODE_ON    0x03    /*
+                                  * * * 6850 Send/Receive UART Mode   */
+
+static int      uart6850_opened = 0;
+static int      uart6850_base = 0x330;
+static int      uart6850_irq;
+static int      uart6850_detected = 0;
+static int      my_dev;
+
+static int      reset_uart6850 (void);
+static void     (*midi_input_intr) (int dev, unsigned char data);
+
+static void
+uart6850_input_loop (void)
+{
+  int             count;
+
+  count = 10;
+
+  while (count)                        /*
+                                * Not timed out
+                                */
+    if (input_avail ())
+      {
+       unsigned char   c = uart6850_read ();
+
+       count = 100;
+
+       if (uart6850_opened & OPEN_READ)
+         midi_input_intr (my_dev, c);
+      }
+    else
+      while (!input_avail () && count)
+       count--;
+}
+
+void
+m6850intr (int unit)
+{
+  printk ("M");
+  if (input_avail ())
+    uart6850_input_loop ();
+}
+
+/*
+ * It looks like there is no input interrupts in the UART mode. Let's try
+ * polling.
+ */
+
+static void
+poll_uart6850 (unsigned long dummy)
+{
+  unsigned long   flags;
+
+  DEFINE_TIMER (uart6850_timer, poll_uart6850);
+
+  if (!(uart6850_opened & OPEN_READ))
+    return;                    /*
+                                * No longer required
+                                */
+
+  DISABLE_INTR (flags);
+
+  if (input_avail ())
+    uart6850_input_loop ();
+
+  ACTIVATE_TIMER (uart6850_timer, poll_uart6850, 1);   /*
+                                                        * Come back later
+                                                        */
+
+  RESTORE_INTR (flags);
+}
+
+static int
+uart6850_open (int dev, int mode,
+              void            (*input) (int dev, unsigned char data),
+              void            (*output) (int dev)
+)
+{
+  if (uart6850_opened)
+    {
+      printk ("Midi6850: Midi busy\n");
+      return RET_ERROR (EBUSY);
+    }
+
+  uart6850_cmd (UART_RESET);
+
+  uart6850_input_loop ();
+
+  midi_input_intr = input;
+  uart6850_opened = mode;
+  poll_uart6850 (0);           /*
+                                * Enable input polling
+                                */
+
+  return 0;
+}
+
+static void
+uart6850_close (int dev)
+{
+  uart6850_cmd (UART_MODE_ON);
+
+  uart6850_opened = 0;
+}
+
+static int
+uart6850_out (int dev, unsigned char midi_byte)
+{
+  int             timeout;
+  unsigned long   flags;
+
+  /*
+   * Test for input since pending input seems to block the output.
+   */
+
+  DISABLE_INTR (flags);
+
+  if (input_avail ())
+    uart6850_input_loop ();
+
+  RESTORE_INTR (flags);
+
+  /*
+   * Sometimes it takes about 13000 loops before the output becomes ready
+   * (After reset). Normally it takes just about 10 loops.
+   */
+
+  for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);   /*
+                                                                        * Wait
+                                                                        */
+
+  if (!output_ready ())
+    {
+      printk ("Midi6850: Timeout\n");
+      return 0;
+    }
+
+  uart6850_write (midi_byte);
+  return 1;
+}
+
+static int
+uart6850_command (int dev, unsigned char *midi_byte)
+{
+  return 1;
+}
+
+static int
+uart6850_start_read (int dev)
+{
+  return 0;
+}
+
+static int
+uart6850_end_read (int dev)
+{
+  return 0;
+}
+
+static int
+uart6850_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+  return RET_ERROR (EINVAL);
+}
+
+static void
+uart6850_kick (int dev)
+{
+}
+
+static int
+uart6850_buffer_status (int dev)
+{
+  return 0;                    /*
+                                * No data in buffers
+                                */
+}
+
+#define MIDI_SYNTH_NAME        "6850 UART Midi"
+#define MIDI_SYNTH_CAPS        SYNTH_CAP_INPUT
+#include "midi_synth.h"
+
+static struct midi_operations uart6850_operations =
+{
+  {"6850 UART", 0, 0, SNDCARD_UART6850},
+  &std_midi_synth,
+  uart6850_open,
+  uart6850_close,
+  uart6850_ioctl,
+  uart6850_out,
+  uart6850_start_read,
+  uart6850_end_read,
+  uart6850_kick,
+  uart6850_command,
+  uart6850_buffer_status
+};
+
+
+long
+attach_uart6850 (long mem_start, struct address_info *hw_config)
+{
+  int             ok, timeout;
+  unsigned long   flags;
+
+  if (num_midis >= MAX_MIDI_DEV)
+    {
+      printk ("Sound: Too many midi devices detected\n");
+      return mem_start;
+    }
+
+  uart6850_base = hw_config->io_base;
+  uart6850_irq = hw_config->irq;
+
+  if (!uart6850_detected)
+    return RET_ERROR (EIO);
+
+  DISABLE_INTR (flags);
+
+  for (timeout = 30000; timeout < 0 && !output_ready (); timeout--);   /*
+                                                                        * Wait
+                                                                        */
+  uart6850_cmd (UART_MODE_ON);
+
+  ok = 1;
+
+  RESTORE_INTR (flags);
+
+  printk (" <6850 Midi Interface>");
+
+  std_midi_synth.midi_dev = my_dev = num_midis;
+  midi_devs[num_midis++] = &uart6850_operations;
+  return mem_start;
+}
+
+static int
+reset_uart6850 (void)
+{
+  uart6850_read ();
+  return 1;                    /*
+                                * OK
+                                */
+}
+
+
+int
+probe_uart6850 (struct address_info *hw_config)
+{
+  int             ok = 0;
+
+  uart6850_base = hw_config->io_base;
+  uart6850_irq = hw_config->irq;
+
+  if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0)
+    return 0;
+
+  ok = reset_uart6850 ();
+
+  uart6850_detected = ok;
+  return ok;
+}
+
+#endif
+
+#endif
index e2f9884a1e676d15265ce6043e5ff3e6246f972e..5e43d42c5e6d60f20c40737043589832864bcb35 100644 (file)
@@ -1113,13 +1113,13 @@ __asm__ __volatile__("rep ; movsl": \
  * etc. This also allows us to optimize memory usage by sharing code pages
  * and filesystem buffers..
  */
-unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int prot)
+unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int share)
 {
        struct buffer_head * bh[8];
        unsigned long where;
        int i, j;
 
-       if (!(prot & PAGE_RW)) {
+       if (share) {
                where = try_to_share_buffers(address,dev,b,size);
                if (where)
                        return where;
index dd61df085502c11490e3210e9538617294fdd7fc..2b54034de0c315ae56fecfec21d6d5ce6600fbdb 100644 (file)
@@ -55,7 +55,7 @@
  */
 static int ext_match(int len,const char * name,struct ext_dir_entry * de)
 {
-       register int same __asm__("ax");
+       register int same;
 
        if (!de || !de->inode || len > EXT_NAME_LEN)
                return 0;
@@ -64,7 +64,8 @@ static int ext_match(int len,const char * name,struct ext_dir_entry * de)
                return 1;
        if (len < EXT_NAME_LEN && len != de->name_len)
                return 0;
-       __asm__("cld\n\t"
+       __asm__ __volatile__(
+               "cld\n\t"
                "repe ; cmpsb\n\t"
                "setz %%al"
                :"=a" (same)
index e063ab46d70afacd4453640c50d677f40bb22a44..1a3a9fb557b2474baf816fc68fed0ce651d48307 100644 (file)
@@ -390,6 +390,7 @@ int ext2_create (struct inode * dir,const char * name, int len, int mode,
                return err;
        }
        de->inode = inode->i_ino;
+       dir->i_version++;
 #ifndef DONT_USE_DCACHE
        ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
                         de->inode);
@@ -456,6 +457,7 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode,
                return err;
        }
        de->inode = inode->i_ino;
+       dir->i_version++;
 #ifndef DONT_USE_DCACHE
        ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
                         de->inode);
@@ -532,6 +534,7 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode)
                return err;
        }
        de->inode = inode->i_ino;
+       dir->i_version++;
 #ifndef DONT_USE_DCACHE
        ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
                         de->inode);
@@ -657,6 +660,7 @@ repeat:
                        inode->i_size = 0;
                }
                retval = ext2_delete_entry (de, bh);
+               dir->i_version++;
        }
        up(&inode->i_sem);
        if (retval)
@@ -729,6 +733,7 @@ repeat:
        retval = ext2_delete_entry (de, bh);
        if (retval)
                goto end_unlink;
+       dir->i_version++;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -817,6 +822,7 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
                return err;
        }
        de->inode = inode->i_ino;
+       dir->i_version++;
 #ifndef DONT_USE_DCACHE
        ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
                         de->inode);
@@ -863,6 +869,7 @@ int ext2_link (struct inode * oldinode, struct inode * dir,
                return err;
        }
        de->inode = oldinode->i_ino;
+       dir->i_version++;
 #ifndef DONT_USE_DCACHE
        ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len,
                         de->inode);
@@ -1036,6 +1043,8 @@ start_up:
                goto try_again;
        if (retval)
                goto end_rename;
+       new_dir->i_version++;
+       old_dir->i_version++;
        if (new_inode) {
                new_inode->i_nlink--;
                new_inode->i_ctime = CURRENT_TIME;
@@ -1043,16 +1052,6 @@ start_up:
        }
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        old_dir->i_dirt = 1;
-       mark_buffer_dirty(old_bh,  1);
-       if (IS_SYNC(old_dir)) {
-               ll_rw_block (WRITE, 1, &old_bh);
-               wait_on_buffer (old_bh);
-       }
-       mark_buffer_dirty(new_bh, 1);
-       if (IS_SYNC(new_dir)) {
-               ll_rw_block (WRITE, 1, &new_bh);
-               wait_on_buffer (new_bh);
-       }
        if (dir_bh) {
                PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
                mark_buffer_dirty(dir_bh, 1);
@@ -1066,6 +1065,16 @@ start_up:
                        new_dir->i_dirt = 1;
                }
        }
+       mark_buffer_dirty(old_bh,  1);
+       if (IS_SYNC(old_dir)) {
+               ll_rw_block (WRITE, 1, &old_bh);
+               wait_on_buffer (old_bh);
+       }
+       mark_buffer_dirty(new_bh, 1);
+       if (IS_SYNC(new_dir)) {
+               ll_rw_block (WRITE, 1, &new_bh);
+               wait_on_buffer (new_bh);
+       }
        retval = 0;
 end_rename:
        brelse (dir_bh);
index a2713779bd096dcd421d9a6604ed89127d08c714..8061e1c94110c30e4efa29d2fea2b82753c82bc4 100644 (file)
@@ -26,7 +26,7 @@
  */
 static int isofs_match(int len,const char * name, char * compare, int dlen)
 {
-       register int same __asm__("ax");
+       register int same;
        
        if (!compare) return 0;
        /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
@@ -45,7 +45,8 @@ static int isofs_match(int len,const char * name, char * compare, int dlen)
        
        if (dlen != len)
                return 0;
-       __asm__("cld\n\t"
+       __asm__ __volatile__(
+               "cld\n\t"
                "repe ; cmpsb\n\t"
                "setz %%al"
                :"=a" (same)
index 5547c339ddf6a697876343df3e249cfe1561bb7e..a13778ed6a2c9ddb9d530df32fed9961e13153b8 100644 (file)
 #include <asm/segment.h>
 #include <asm/system.h>
 
-extern int share_page(struct vm_area_struct * area, struct task_struct * tsk,
-       struct inode * inode, unsigned long address, unsigned long error_code,
-       unsigned long newpage);
-
-extern unsigned long put_page(struct task_struct * tsk,unsigned long page,
-       unsigned long address,int prot);
-
-static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
-                               unsigned long address);
+static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area,
+       unsigned long address, unsigned long page, int error_code);
 
 extern void file_mmap_free(struct vm_area_struct * area);
 extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to,
@@ -85,12 +78,11 @@ int nfs_mmap(struct inode * inode, struct file * file,
 }
 
 
-static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
-                               unsigned long address)
+static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
+       unsigned long page, int error_code)
 {
        struct inode * inode = area->vm_inode;
        unsigned int clear;
-       unsigned long page;
        unsigned long tmp;
        int n;
        int i;
@@ -100,19 +92,6 @@ static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
        address &= PAGE_MASK;
        pos = address - area->vm_start + area->vm_offset;
 
-       page = get_free_page(GFP_KERNEL);
-       if (share_page(area, area->vm_task, inode, address, error_code, page)) {
-               ++area->vm_task->mm->min_flt;
-               return;
-       }
-
-       ++area->vm_task->mm->maj_flt;
-       if (!page) {
-               oom(current);
-               put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
-               return;
-       }
-
        clear = 0;
        if (address + PAGE_SIZE > area->vm_end) {
                clear = address + PAGE_SIZE - area->vm_end;
@@ -141,17 +120,9 @@ static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
        nfs_refresh_inode(inode, &fattr);
 #endif
 
-       if (!(error_code & PAGE_RW)) {
-               if (share_page(area, area->vm_task, inode, address, error_code, page))
-                       return;
-       }
-
        tmp = page + PAGE_SIZE;
        while (clear--) {
                *(char *)--tmp = 0;
        }
-       if (put_page(area->vm_task,page,address,area->vm_page_prot))
-               return;
-       free_page(page);
-       oom(current);
+       return page;
 }
index 4b93762f5721bd054ae986f18a9ebe726f784fba..a016a75840e4a23a23d3b180f50d92c6a7ede25e 100644 (file)
@@ -610,7 +610,11 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
        }
        fops = get_blkfops(MAJOR(dev));
        if (fops && fops->open) {
-               retval = fops->open(inode,NULL);
+               struct file dummy;      /* allows read-write or read-only flag */
+               memset(&dummy, 0, sizeof(dummy));
+               dummy.f_inode = inode;
+               dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
+               retval = fops->open(inode, &dummy);
                if (retval) {
                        iput(inode);
                        return retval;
@@ -628,7 +632,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
        retval = do_mount(dev,dir_name,t,flags,(void *) page);
        free_page(page);
        if (retval && fops && fops->release)
-               fops->release(inode,NULL);
+               fops->release(inode, NULL);
        iput(inode);
        return retval;
 }
index de1e9f6fecdd62a2a6ba13b1c3629bff499c0b7e..ef1123afca1207d2ac26fd130aa640bc82be4192 100644 (file)
 
 /* Bits of FD_ST3 */
 #define ST3_HA         0x04            /* Head (Address) */
+#define ST3_DS         0x08            /* drive is double-sided */
 #define ST3_TZ         0x10            /* Track Zero signal (1=track 0) */
+#define ST3_RY         0x20            /* drive is ready */
 #define ST3_WP         0x40            /* Write Protect */
+#define ST3_FT         0x80            /* Drive Fault */
 
 /* Values for FD_COMMAND */
 #define FD_RECALIBRATE         0x07    /* move to track 0 */
@@ -61,6 +64,7 @@
 #define FD_VERSION             0x10    /* get version code */
 #define FD_CONFIGURE           0x13    /* configure FIFO operation */
 #define FD_PERPENDICULAR       0x12    /* perpendicular r/w mode */
+#define FD_GETSTATUS           0x04    /* read ST3 */
 
 /* DMA commands */
 #define DMA_READ       0x46
index 44b10ac1e3facfe631ca378c98ced779399e09ad..25a68a38181decffd893fa9863c6444cfc8762e3 100644 (file)
@@ -444,7 +444,7 @@ extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buff
 extern void brelse(struct buffer_head * buf);
 extern void set_blocksize(dev_t dev, int size);
 extern struct buffer_head * bread(dev_t dev, int block, int size);
-extern unsigned long bread_page(unsigned long addr,dev_t dev,int b[],int size,int prot);
+extern unsigned long bread_page(unsigned long addr,dev_t dev,int b[],int size,int share);
 extern struct buffer_head * breada(dev_t dev,int block, int size, 
                                   unsigned int pos, unsigned int filesize);
 extern void put_super(dev_t dev);
index d29152b1ad18463a9615a19d3d91d16f26d38152..b249c4a37a2880a8a747e5ae773ef9eeeb6f8740 100644 (file)
@@ -55,9 +55,10 @@ struct vm_area_struct {
 struct vm_operations_struct {
        void (*open)(struct vm_area_struct * area);
        void (*close)(struct vm_area_struct * area);
-       void (*nopage)(int error_code,
-                      struct vm_area_struct * area, unsigned long address);
-       void (*wppage)(struct vm_area_struct * area, unsigned long address);
+       unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address,
+               unsigned long page, int error_code);
+       unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
+               unsigned long page);
        int (*share)(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address);
        int (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
 };
@@ -135,6 +136,7 @@ extern void free_pages(unsigned long addr, unsigned long order);
 extern void show_free_areas(void);
 extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page,
        unsigned long address);
+
 extern void free_page_tables(struct task_struct * tsk);
 extern void clear_page_tables(struct task_struct * tsk);
 extern int copy_page_tables(struct task_struct * to);
@@ -144,9 +146,9 @@ extern int remap_page_range(unsigned long from, unsigned long to, unsigned long
 extern int zeromap_page_range(unsigned long from, unsigned long size, int mask);
 
 extern void do_wp_page(unsigned long error_code, unsigned long address,
-       struct task_struct *tsk, unsigned long user_esp);
+       struct task_struct *tsk);
 extern void do_no_page(unsigned long error_code, unsigned long address,
-       struct task_struct *tsk, unsigned long user_esp);
+       struct task_struct *tsk);
 
 extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
 extern void mem_init(unsigned long low_start_mem,
index 60d6d99f8f9f9cfcb8ebc3520a0cddea031469c2..0916bb925ead7253e2e695f9c54c99cc99b0af1b 100644 (file)
@@ -34,7 +34,7 @@
   *
   * Regards,
   * Hannu Savolainen
-  * hannu@voxware.pp.fi, Hannu.Savolainen@helsinki.fi
+  * hannu@voxware.pp.fi
   */
 
 #define SOUND_VERSION  203
  *     Supported card ID numbers (Should be somewhere else?)
  */
 
-#define SNDCARD_ADLIB  1
-#define SNDCARD_SB     2
-#define SNDCARD_PAS    3
-#define SNDCARD_GUS    4
-#define SNDCARD_MPU401 5
-#define SNDCARD_SB16   6
-#define SNDCARD_SB16MIDI 7
+#define SNDCARD_ADLIB          1
+#define SNDCARD_SB             2
+#define SNDCARD_PAS            3
+#define SNDCARD_GUS            4
+#define SNDCARD_MPU401         5
+#define SNDCARD_SB16           6
+#define SNDCARD_SB16MIDI       7
+#define SNDCARD_UART6850       8
+#define SNDCARD_GUS16          9
+#define SNDCARD_MSS            10
+#define SNDCARD_PSS            11
 
 /***********************************
  * IOCTL Commands for /dev/sequencer
 #define SNDCTL_SYNTH_MEMAVL            _IOWR('Q',14, int)      /* in=dev#, out=memsize */
 #define SNDCTL_FM_4OP_ENABLE           _IOW ('Q',15, int)      /* in=dev# */
 #define SNDCTL_PMGR_ACCESS             _IOWR('Q',16, struct patmgr_info)
+#define SNDCTL_SEQ_PANIC               _IO  ('Q',17)
+
+#define SNDCTL_TMR_TIMEBASE            _IOWR('T', 1, int)
+#define SNDCTL_TMR_START               _IO  ('T', 2)
+#define SNDCTL_TMR_STOP                        _IO  ('T', 3)
+#define SNDCTL_TMR_CONTINUE            _IO  ('T', 4)
+#define SNDCTL_TMR_TEMPO               _IOWR('T', 5, int)
+#define SNDCTL_TMR_SOURCE              _IOWR('T', 6, int)
+#      define TMR_INTERNAL             0x00000001
+#      define TMR_EXTERNAL             0x00000002
+#              define TMR_MODE_MIDI    0x00000010
+#              define TMR_MODE_FSK     0x00000020
+#              define TMR_MODE_CLS     0x00000040
+#              define TMR_MODE_SMPTE   0x00000080
+#define SNDCTL_TMR_METRONOME           _IOW ('T', 7, int)
+#define SNDCTL_TMR_SELECT              _IOW ('T', 8, int)
 
 /*
  *     Sample loading mechanism for internal synthesizers (/dev/sequencer)
@@ -187,6 +207,14 @@ struct patch_info {
        };
 
 
+struct sysex_info {
+               short key;              /* Use GUS_PATCH here */
+#define SYSEX_PATCH    0x05fd
+               short device_no;        /* Synthesizer number */
+               long len;       /* Size of the sysex data in bytes */
+               unsigned char data[1];  /* Sysex data starts here */
+       };
+
 /*
  * Patch management interface (/dev/sequencer, /dev/patmgr#)
  * Don't use these calls if you want to maintain compatibility with
@@ -282,7 +310,7 @@ struct patmgr_info {        /* Note! size must be < 4k since kmalloc() is used */
  *
  * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events.
  * (All input events are currently 4 bytes long. Be prepared to support
- * 8 byte events also. If you receive any event having first byte >= 0xf0,
+ * 8 byte events also. If you receive any event having first byte >= 128,
  * it's a 8 byte event.
  *
  * The events are documented at the end of this file.
@@ -295,20 +323,99 @@ struct patmgr_info {      /* Note! size must be < 4k since kmalloc() is used */
 #define SEQ_FMNOTEOFF          SEQ_NOTEOFF     /* Just old name */
 #define SEQ_NOTEON             1
 #define        SEQ_FMNOTEON            SEQ_NOTEON
-#define SEQ_WAIT               2
+#define SEQ_WAIT               TMR_WAIT_ABS
 #define SEQ_PGMCHANGE          3
 #define SEQ_FMPGMCHANGE                SEQ_PGMCHANGE
-#define SEQ_SYNCTIMER          4
+#define SEQ_SYNCTIMER          TMR_START
 #define SEQ_MIDIPUTC           5
 #define SEQ_DRUMON             6       /*** OBSOLETE ***/
 #define SEQ_DRUMOFF            7       /*** OBSOLETE ***/
-#define SEQ_ECHO               8       /* For synching programs with output */
+#define SEQ_ECHO               TMR_ECHO        /* For synching programs with output */
 #define SEQ_AFTERTOUCH         9
 #define SEQ_CONTROLLER         10
+
+/*******************************************
+ *     Midi controller numbers
+ *******************************************
+ * Controllers 0 to 31 (0x00 to 0x1f) and
+ * 32 to 63 (0x20 to 0x3f) are continuous
+ * controllers.
+ * In the MIDI 1.0 these controllers are sent using
+ * two messages. Controller numbers 0 to 31 are used
+ * to send the LSB and the controller numbers 32 to 63
+ * are for the LSB.
+ *
+ * This driver uses just the numbers 0 to 31 to store both
+ * the LSB and MSB. The controller value is a unsigned short
+ * and it's valid range is between 0 and 16383 (0x0000 to 0x3fff).
+ * The driver sends the controller value using two messages when
+ * necessary.
+ */
+
+#define           CTL_BANK_SELECT              0x00
+#define           CTL_MODWHEEL                 0x01
+#define    CTL_BREATH                  0x02
+/*             undefined               0x03 */
+#define    CTL_FOOT                    0x04
+#define    CTL_PORTAMENTO_TIME         0x05
+#define    CTL_DATA_ENTRY              0x06
+#define    CTL_MAIN_VOLUME             0x07
+#define    CTL_BALANCE                 0x08
+/*             undefined               0x09 */
+#define    CTL_PAN                     0x0a
+#define    CTL_EXPRESSION              0x0b
+/*             undefined               0x0c */
+/*             undefined               0x0d */
+/*             undefined               0x0e */
+/*             undefined               0x0f */
+#define    CTL_GENERAL_PURPOSE1        0x10
+#define    CTL_GENERAL_PURPOSE2        0x11
+#define    CTL_GENERAL_PURPOSE3        0x12
+#define    CTL_GENERAL_PURPOSE4        0x13
+/*             undefined               0x14 - 0x1f */
+
+/*             undefined               0x20 */
+/* The controller numbers 0x21 to 0x3f are reserved for the */
+/* least significant bytes of the controllers 0x00 to 0x1f. */
+/* These controllers are not recognised by the driver. */
+
+/* Controllers 64 to 69 (0x40 to 0x45) are on/off switches. */
+/* 0=OFF and 127=ON (intermediate values are possible) */
+#define    CTL_DAMPER_PEDAL            0x40
+#define    CTL_SUSTAIN                 0x40    /* Alias */
+#define    CTL_HOLD                    0x40    /* Alias */
+#define    CTL_PORTAMENTO              0x41
+#define    CTL_SOSTENUTO               0x42
+#define    CTL_SOFT_PEDAL              0x43
+/*             undefined               0x44 */
+#define    CTL_HOLD2                   0x45
+/*             undefined               0x46 - 0x4f */
+
+#define    CTL_GENERAL_PURPOSE5        0x50
+#define    CTL_GENERAL_PURPOSE6        0x51
+#define    CTL_GENERAL_PURPOSE7        0x52
+#define    CTL_GENERAL_PURPOSE8        0x53
+/*             undefined               0x54 - 0x5a */
+#define    CTL_EXT_EFF_DEPTH           0x5b
+#define    CTL_TREMOLO_DEPTH           0x5c
+#define    CTL_CHORUS_DEPTH            0x5d
+#define    CTL_DETUNE_DEPTH            0x5e
+#define    CTL_CELESTE_DEPTH           0x5e    /* Alias for the above one */
+#define    CTL_PHASER_DEPTH            0x5f
+#define    CTL_DATA_INCREMENT          0x60
+#define    CTL_DATA_DECREMENT          0x61
+#define    CTL_NONREG_PARM_NUM_LSB     0x62
+#define    CTL_NONREG_PARM_NUM_MSB     0x63
+#define    CTL_REGIST_PARM_NUM_LSB     0x64
+#define    CTL_REGIST_PARM_NUM_MSB     0x65
+/*             undefined               0x66 - 0x78 */
+/*             reserved                0x79 - 0x7f */
+
+/* Pseudo controllers (not midi compatible) */
 #define    CTRL_PITCH_BENDER           255
 #define    CTRL_PITCH_BENDER_RANGE     254
-#define    CTRL_EXPRESSION             253
-#define    CTRL_MAIN_VOLUME            252
+#define    CTRL_EXPRESSION             253     /* Obsolete */
+#define    CTRL_MAIN_VOLUME            252     /* Obsolete */
 #define SEQ_BALANCE            11
 #define SEQ_VOLMODE             12
 
@@ -350,26 +457,7 @@ struct patmgr_info {       /* Note! size must be < 4k since kmalloc() is used */
  *      to GUS_PATCH.
  */
 #define SEQ_PRIVATE            0xfe    /* Low level HW dependent events (8 bytes) */
-#define SEQ_EXTENDED           0xff    /* Extended events (8 bytes) */
-
-/*
- *     Extended events for synthesizers (8 bytes)
- *
- *     Format:
- *
- *             b0      = SEQ_EXTENDED
- *             b1      = command
- *             b2      = device
- *             b3-b7   = parameters
- *
- *     Command                         b3      b4      b5      b6      b7
- *     ----------------------------------------------------------------------------
- *     SEQ_NOTEON                      voice   note    volume  0       0
- *     SEQ_NOTEOFF                     voice   note    volume  0       0
- *     SEQ_PGMCHANGE                   voice   pgm     0       0       0
- *     SEQ_DRUMON                      (voice) drum#   volume  0       0
- *     SEQ_DRUMOFF                     (voice) drum#   volume  0       0
- */
+#define SEQ_EXTENDED           0xff    /* Extended events (8 bytes) OBSOLETE */
 
 /*
  * Record for FM patches
@@ -392,6 +480,7 @@ struct synth_info { /* Read only */
                int     synth_type;
 #define SYNTH_TYPE_FM                  0
 #define SYNTH_TYPE_SAMPLE              1
+#define SYNTH_TYPE_MIDI                        2       /* Midi interface */
 
                int     synth_subtype;
 #define FM_TYPE_ADLIB                  0x00
@@ -406,9 +495,17 @@ struct synth_info {        /* Read only */
                unsigned long   capabilities;   
 #define SYNTH_CAP_PERCMODE             0x00000001 /* No longer used */
 #define SYNTH_CAP_OPL3                 0x00000002 /* Set if OPL3 supported */
+#define SYNTH_CAP_INPUT                        0x00000004 /* Input (MIDI) device */
                int     dummies[19];    /* Reserve space */
        };
 
+struct sound_timer_info {
+               char name[30];
+               int caps;
+       };
+
+#define MIDI_CAP_MPU401                1               /* MPU-401 intelligent mode */
+
 struct midi_info {
                char            name[30];
                int             device;         /* 0-N. INITIALIZE BEFORE CALLING */
@@ -417,6 +514,19 @@ struct midi_info {
                int             dummies[18];    /* Reserve space */
        };
 
+/********************************************
+ * ioctl commands for the /dev/midi##
+ */
+typedef struct {
+               unsigned char cmd;
+               char nr_args, nr_returns;
+               unsigned char data[30];
+       } mpu_command_rec;
+
+#define SNDCTL_MIDI_PRETIME            _IOWR('m', 0, int)
+#define SNDCTL_MIDI_MPUMODE            _IOWR('m', 1, int)
+#define SNDCTL_MIDI_MPUCMD             _IOWR('m', 2, mpu_command_rec)
+
 /********************************************
  * IOCTL commands for /dev/dsp and /dev/audio
  */
@@ -426,11 +536,26 @@ struct midi_info {
 #define SNDCTL_DSP_SPEED               _IOWR('P', 2, int)
 #define SNDCTL_DSP_STEREO              _IOWR('P', 3, int)
 #define SNDCTL_DSP_GETBLKSIZE          _IOWR('P', 4, int)
-#define SNDCTL_DSP_SAMPLESIZE          _IOWR('P', 5, int)      /* 8, 12 or 16 */
+#define SNDCTL_DSP_SAMPLESIZE          SNDCTL_DSP_SETFMT
 #define SOUND_PCM_WRITE_CHANNELS       _IOWR('P', 6, int)
 #define SOUND_PCM_WRITE_FILTER         _IOWR('P', 7, int)
 #define SNDCTL_DSP_POST                        _IO  ('P', 8)
 #define SNDCTL_DSP_SUBDIVIDE           _IOWR('P', 9, int)
+#define SNDCTL_DSP_SETFRAGMENT         _IOWR('P',10, int)
+
+/*     Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */
+#define SNDCTL_DSP_GETFMTS             _IOR ('P',11, int) /* Returns a mask */
+#define SNDCTL_DSP_SETFMT              _IOWR('P',5, int) /* Selects ONE fmt*/
+#      define AFMT_QUERY               0x00000000      /* Return current fmt */
+#      define AFMT_MU_LAW              0x00000001
+#      define AFMT_A_LAW               0x00000002
+#      define AFMT_IMA_ADPCM           0x00000004
+#      define AFMT_U8                  0x00000008
+#      define AFMT_S16_LE              0x00000010      /* Little endian signed 16*/
+#      define AFMT_S16_BE              0x00000020      /* Big endian signed 16 */
+#      define AFMT_S8                  0x00000040
+#      define AFMT_U16_LE              0x00000080      /* Little endian U16 */
+#      define AFMT_U16_BE              0x00000100      /* Big endian U16 */
 
 #define SOUND_PCM_READ_RATE            _IOR ('P', 2, int)
 #define SOUND_PCM_READ_CHANNELS                _IOR ('P', 6, int)
@@ -438,12 +563,30 @@ struct midi_info {
 #define SOUND_PCM_READ_FILTER          _IOR ('P', 7, int)
 
 /* Some alias names */
-#define SOUND_PCM_WRITE_BITS           SNDCTL_DSP_SAMPLESIZE
+#define SOUND_PCM_WRITE_BITS           SNDCTL_DSP_SETFMT
 #define SOUND_PCM_WRITE_RATE           SNDCTL_DSP_SPEED
 #define SOUND_PCM_POST                 SNDCTL_DSP_POST
 #define SOUND_PCM_RESET                        SNDCTL_DSP_RESET
 #define SOUND_PCM_SYNC                 SNDCTL_DSP_SYNC
 #define SOUND_PCM_SUBDIVIDE            SNDCTL_DSP_SUBDIVIDE
+#define SOUND_PCM_SETFRAGMENT          SNDCTL_DSP_SETFRAGMENT
+#define SOUND_PCM_GETFMTS              SNDCTL_DSP_GETFMTS
+#define SOUND_PCM_SETFMT               SNDCTL_DSP_SETFMT
+
+/*********************************************
+ * IOCTL /dev/pss (experimental PSS API by marc.hoffman@analog.com.
+ *             likely to change in near future.
+ */
+#define SNDCTL_PSS_RESET             _IO  ('C',  0)
+#define SNDCTL_PSS_SETUP_REGISTERS   _IO  ('C',  1)
+#define SNDCTL_PSS_SPEAKER           _IOW ('C',  2, struct pss_speaker)
+
+struct pss_speaker {
+  int volume;
+  int bass;
+  int treb;
+  int mode;
+};
 
 /*********************************************
  * IOCTL commands for /dev/mixer
@@ -559,57 +702,66 @@ struct midi_info {
 #define SOUND_MIXER_WRITE_RECSRC       MIXER_WRITE(SOUND_MIXER_RECSRC)
 
 /*
- *     The following mixer ioctl calls are compatible with the BSD driver by
- *       Steve Haehnichen <shaehnic@ucsd.edu>
- *
- * Since this interface is entirely SB specific, it will be dropped in the
- * near future.
+ * Level 2 event types for /dev/sequencer
  */
 
-typedef unsigned char S_BYTE;
-typedef unsigned char S_FLAG;
-struct stereo_vol
-{
-  S_BYTE l;                    /* Left volume */
-  S_BYTE r;                    /* Right volume */
-};
+/*
+ * The 4 most significant bits of byte 0 specify the class of
+ * the event: 
+ *
+ *     0x8X = system level events,
+ *     0x9X = device/port specific events, event[1] = device/port,
+ *             The last 4 bits give the subtype:
+ *                     0x02    = Channel event (event[3] = chn).
+ *                     0x01    = note event (event[4] = note).
+ *                     (0x01 is not used alone but always with bit 0x02).
+ *            event[2] = MIDI message code (0x80=note off etc.)
+ *
+ */
 
-#define MIXER_IOCTL_SET_LEVELS                 _IOW ('s', 20, struct sb_mixer_levels)
-#define MIXER_IOCTL_SET_PARAMS                 _IOW ('s', 21, struct sb_mixer_params)
-#define MIXER_IOCTL_READ_LEVELS        _IOR ('s', 22, struct sb_mixer_levels)
-#define MIXER_IOCTL_READ_PARAMS        _IOR ('s', 23, struct sb_mixer_params)
-#define MIXER_IOCTL_RESET              _IO  ('s', 24)
+#define EV_SEQ_LOCAL           0x80
+#define EV_TIMING              0x81
+#define EV_CHN_COMMON          0x92
+#define EV_CHN_VOICE           0x93
+/*
+ * Event types 200 to 220 are reserved for application use.
+ * These numbers will not be used by the driver.
+ */
 
 /*
- * Mixer volume levels for MIXER_IOCTL_SET_VOL & MIXER_IOCTL_READ_VOL
- */
-struct sb_mixer_levels
-{
-  struct stereo_vol master;    /* Master volume */
-  struct stereo_vol voc;       /* DSP Voice volume */
-  struct stereo_vol fm;                /* FM volume */
-  struct stereo_vol line;      /* Line-in volume */
-  struct stereo_vol cd;                /* CD audio */
-  S_BYTE mic;                  /* Microphone level */
-};
+ * Events for event type EV_CHN_VOICE
+ */
+
+#define MIDI_NOTEOFF           0x80
+#define MIDI_NOTEON            0x90
+#define MIDI_KEY_PRESSURE      0xA0
 
 /*
- * Mixer parameters for MIXER_IOCTL_SET_PARAMS & MIXER_IOCTL_READ_PARAMS
- */
-struct sb_mixer_params
-{
-  S_BYTE record_source;                /* Recording source (See SRC_xxx below) */
-  S_FLAG hifreq_filter;                /* Filter frequency (hi/low) */
-  S_FLAG filter_input;         /* ANFI input filter */
-  S_FLAG filter_output;                /* DNFI output filter */
-  S_FLAG dsp_stereo;           /* 1 if DSP is in Stereo mode */
-};
+ * Events for event type EV_CHN_COMMON
+ */
+
+#define MIDI_CTL_CHANGE                0xB0
+#define MIDI_PGM_CHANGE                0xC0
+#define MIDI_CHN_PRESSURE      0xD0
+#define MIDI_PITCH_BEND                0xE0
 
-#define SRC_MIC         1      /* Select Microphone recording source */
-#define SRC_CD          3      /* Select CD recording source */
-#define SRC_LINE        7      /* Use Line-in for recording source */
+#define MIDI_SYSTEM_PREFIX     0xF0
 
-#if !defined(KERNEL) && !defined(INKERNEL)
+/*
+ * Timer event types
+ */
+#define TMR_WAIT_REL           1       /* Time relative to the prev time */
+#define TMR_WAIT_ABS           2       /* Absolute time since TMR_START */
+#define TMR_STOP               3
+#define TMR_START              4
+#define TMR_CONTINUE           5
+#define TMR_TEMPO              6
+#define TMR_ECHO               8
+#define TMR_CLOCK              9       /* MIDI clock */
+#define TMR_SPP                        10      /* Song position pointer */
+#define TMR_TIMESIG            11      /* Time signature */
+
+#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS) 
 /*
  *     Some convenience macros to simplify programming of the
  *     /dev/sequencer interface
@@ -617,6 +769,7 @@ struct sb_mixer_params
  *     These macros define the API which should be used when possible.
  */
 
+#ifndef USE_SIMPLE_MACROS
 void seqbuf_dump(void);        /* This function must be provided by programs */
 
 /* Sample seqbuf_dump() implementation:
@@ -638,12 +791,31 @@ void seqbuf_dump(void);   /* This function must be provided by programs */
  *     }
  */
 
-#define SEQ_DEFINEBUF(len)             unsigned char _seqbuf[len]; int _seqbuflen = len; int _seqbufptr = 0
-#define SEQ_DECLAREBUF()               extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr
+#define SEQ_DEFINEBUF(len)             unsigned char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0
+#define SEQ_USE_EXTBUF()               extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr
+#define SEQ_DECLAREBUF()               SEQ_USE_EXTBUF()
 #define SEQ_PM_DEFINES                 struct patmgr_info _pm_info
 #define _SEQ_NEEDBUF(len)              if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
 #define _SEQ_ADVBUF(len)               _seqbufptr += len
 #define SEQ_DUMPBUF                    seqbuf_dump
+#else
+/*
+ * This variation of the sequencer macros is used just to format one event
+ * using fixed buffer.
+ * 
+ * The program using the macro library must define the following macros before
+ * using this library.
+ *
+ * #define _seqbuf              name of the buffer (unsigned char[]) 
+ * #define _SEQ_ADVBUF(len)     If the applic needs to know the exact
+ *                              size of the event, this macro can be used.
+ *                              Otherwise this must be defined as empty.
+ * #define _seqbufptr           Define the name of index variable or 0 if
+ *                              not required. 
+ */
+#define _SEQ_NEEDBUF(len)      /* empty */
+#endif
+
 #define PM_LOAD_PATCH(dev, bank, pgm)  (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
                                        _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
                                        _pm_info.parm1 = bank, _pm_info.parm2 = 1, \
@@ -664,39 +836,68 @@ void seqbuf_dump(void);   /* This function must be provided by programs */
                                        _seqbuf[_seqbufptr+7] = 0;\
                                        _SEQ_ADVBUF(8);}
 
-#define SEQ_START_NOTE(dev, voice, note, vol)  {_SEQ_NEEDBUF(8);\
-                                       _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-                                       _seqbuf[_seqbufptr+1] = SEQ_NOTEON;\
-                                       _seqbuf[_seqbufptr+2] = (dev);\
-                                       _seqbuf[_seqbufptr+3] = (voice);\
-                                       _seqbuf[_seqbufptr+4] = (note);\
-                                       _seqbuf[_seqbufptr+5] = (vol);\
-                                       _seqbuf[_seqbufptr+6] = 0;\
-                                       _seqbuf[_seqbufptr+7] = 0;\
-                                       _SEQ_ADVBUF(8);}
+/*
+ * Midi voice messages
+ */
 
-#define SEQ_STOP_NOTE(dev, voice, note, vol)   {_SEQ_NEEDBUF(8);\
-                                       _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-                                       _seqbuf[_seqbufptr+1] = SEQ_NOTEOFF;\
-                                       _seqbuf[_seqbufptr+2] = (dev);\
-                                       _seqbuf[_seqbufptr+3] = (voice);\
+#define _CHN_VOICE(dev, event, chn, note, parm) \
+                                       {_SEQ_NEEDBUF(8);\
+                                       _seqbuf[_seqbufptr] = EV_CHN_VOICE;\
+                                       _seqbuf[_seqbufptr+1] = (dev);\
+                                       _seqbuf[_seqbufptr+2] = (event);\
+                                       _seqbuf[_seqbufptr+3] = (chn);\
                                        _seqbuf[_seqbufptr+4] = (note);\
-                                       _seqbuf[_seqbufptr+5] = (vol);\
-                                       _seqbuf[_seqbufptr+6] = 0;\
+                                       _seqbuf[_seqbufptr+5] = (parm);\
+                                       _seqbuf[_seqbufptr+6] = (0);\
                                        _seqbuf[_seqbufptr+7] = 0;\
                                        _SEQ_ADVBUF(8);}
 
-#define SEQ_CHN_PRESSURE(dev, voice, pressure) {_SEQ_NEEDBUF(8);\
-                                       _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-                                       _seqbuf[_seqbufptr+1] = SEQ_AFTERTOUCH;\
-                                       _seqbuf[_seqbufptr+2] = (dev);\
-                                       _seqbuf[_seqbufptr+3] = (voice);\
-                                       _seqbuf[_seqbufptr+4] = (pressure);\
-                                       _seqbuf[_seqbufptr+5] = 0;\
-                                       _seqbuf[_seqbufptr+6] = 0;\
-                                       _seqbuf[_seqbufptr+7] = 0;\
+#define SEQ_START_NOTE(dev, chn, note, vol) \
+               _CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol)
+
+#define SEQ_STOP_NOTE(dev, chn, note, vol) \
+               _CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol)
+
+#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \
+               _CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure)
+
+/*
+ * Midi channel messages
+ */
+
+#define _CHN_COMMON(dev, event, chn, p1, p2, w14) \
+                                       {_SEQ_NEEDBUF(8);\
+                                       _seqbuf[_seqbufptr] = EV_CHN_COMMON;\
+                                       _seqbuf[_seqbufptr+1] = (dev);\
+                                       _seqbuf[_seqbufptr+2] = (event);\
+                                       _seqbuf[_seqbufptr+3] = (chn);\
+                                       _seqbuf[_seqbufptr+4] = (p1);\
+                                       _seqbuf[_seqbufptr+5] = (p2);\
+                                       *(short *)&_seqbuf[_seqbufptr+6] = (w14);\
                                        _SEQ_ADVBUF(8);}
 
+#define SEQ_CHN_PRESSURE(dev, chn, pressure) \
+               _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0)
+
+#define SEQ_SET_PATCH(dev, chn, patch) \
+               _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0)
+
+#define SEQ_CONTROL(dev, chn, controller, value) \
+               _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value)
+
+#define SEQ_BENDER(dev, chn, value) \
+               _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
+
+/*
+ * The following 5 macros are incorrectly implemented and obsolete.
+ * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead.
+ */
+#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
+#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
+#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
+#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
+#define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
+#if 0
 #define SEQ_PANNING(dev, voice, pos)   {_SEQ_NEEDBUF(8);\
                                        _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
                                        _seqbuf[_seqbufptr+1] = SEQ_BALANCE;\
@@ -705,48 +906,35 @@ void seqbuf_dump(void);   /* This function must be provided by programs */
                                        (char)_seqbuf[_seqbufptr+4] = (pos);\
                                        _seqbuf[_seqbufptr+5] = 0;\
                                        _seqbuf[_seqbufptr+6] = 0;\
-                                       _seqbuf[_seqbufptr+7] = 0;\
-                                       _SEQ_ADVBUF(8);}
-
-#define SEQ_CONTROL(dev, voice, controller, value)     {_SEQ_NEEDBUF(8);\
-                                       _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-                                       _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
-                                       _seqbuf[_seqbufptr+2] = (dev);\
-                                       _seqbuf[_seqbufptr+3] = (voice);\
-                                       _seqbuf[_seqbufptr+4] = (controller);\
-                                       *(short *)&_seqbuf[_seqbufptr+5] = (value);\
-                                       _seqbuf[_seqbufptr+7] = 0;\
+                                       _seqbuf[_seqbufptr+7] = 1;\
                                        _SEQ_ADVBUF(8);}
+#endif
 
-#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
-#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
-#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_EXPRESSION, value)
-#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_MAIN_VOLUME, value)
+/*
+ * Timing and syncronization macros
+ */
 
-#define SEQ_START_TIMER()              {_SEQ_NEEDBUF(4);\
-                                       _seqbuf[_seqbufptr] = SEQ_SYNCTIMER;\
-                                       _seqbuf[_seqbufptr+1] = 0;\
+#define _TIMER_EVENT(ev, parm)         {_SEQ_NEEDBUF(8);\
+                                       _seqbuf[_seqbufptr+0] = EV_TIMING; \
+                                       _seqbuf[_seqbufptr+1] = (ev); \
                                        _seqbuf[_seqbufptr+2] = 0;\
                                        _seqbuf[_seqbufptr+3] = 0;\
-                                       _SEQ_ADVBUF(4);}
-#define SEQ_SET_PATCH(dev, voice, patch)       {_SEQ_NEEDBUF(8);\
-                                       _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
-                                       _seqbuf[_seqbufptr+1] = SEQ_PGMCHANGE;\
-                                       _seqbuf[_seqbufptr+2] = (dev);\
-                                       _seqbuf[_seqbufptr+3] = (voice);\
-                                       _seqbuf[_seqbufptr+4] = (patch);\
-                                       _seqbuf[_seqbufptr+5] = 0;\
-                                       _seqbuf[_seqbufptr+6] = 0;\
-                                       _seqbuf[_seqbufptr+7] = 0;\
+                                       *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
                                        _SEQ_ADVBUF(8);}
 
-#define SEQ_WAIT_TIME(ticks)           {_SEQ_NEEDBUF(4);\
-                                       *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_WAIT | ((ticks) << 8);\
-                                       _SEQ_ADVBUF(4);}
+#define SEQ_START_TIMER()              _TIMER_EVENT(TMR_START, 0)
+#define SEQ_STOP_TIMER()               _TIMER_EVENT(TMR_STOP, 0)
+#define SEQ_CONTINUE_TIMER()           _TIMER_EVENT(TMR_CONTINUE, 0)
+#define SEQ_WAIT_TIME(ticks)           _TIMER_EVENT(TMR_WAIT_ABS, ticks)
+#define SEQ_DELTA_TIME(ticks)          _TIMER_EVENT(TMR_WAIT_REL, ticks)
+#define SEQ_ECHO_BACK(key)             _TIMER_EVENT(TMR_ECHO, key)
+#define SEQ_SET_TEMPO(value)           _TIMER_EVENT(TMR_TEMPO, value)
+#define SEQ_SONGPOS(pos)               _TIMER_EVENT(TMR_SPP, pos)
+#define SEQ_TIME_SIGNATURE(sig)                _TIMER_EVENT(TMR_TIMESIG, sig)
 
-#define SEQ_ECHO_BACK(key)             {_SEQ_NEEDBUF(4);\
-                                       *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_ECHO | ((key) << 8);\
-                                       _SEQ_ADVBUF(4);}
+/*
+ * Events for the level 1 interface only 
+ */
 
 #define SEQ_MIDIOUT(device, byte)      {_SEQ_NEEDBUF(4);\
                                        _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
@@ -754,9 +942,14 @@ void seqbuf_dump(void);    /* This function must be provided by programs */
                                        _seqbuf[_seqbufptr+2] = (device);\
                                        _seqbuf[_seqbufptr+3] = 0;\
                                        _SEQ_ADVBUF(4);}
-#define SEQ_WRPATCH(patchx, len)       {if (_seqbufptr) seqbuf_dump();\
+
+/*
+ * Patch loading.
+ */
+#define SEQ_WRPATCH(patchx, len)               {if (_seqbufptr) seqbuf_dump();\
                                        if (write(seqfd, (char*)(patchx), len)==-1) \
                                           perror("Write patch: /dev/sequencer");}
+#define SEQ_WRPATCH2(patchx, len)      (seqbuf_dump(), write(seqfd, (char*)(patchx), len))
 
 #endif
 long soundcard_init(long mem_start);
index d40dc7d574d35d2d8969edc3e53abfd34d0080ab..c622764412b3f382b71a82ad21f012b1ff447779 100644 (file)
@@ -98,7 +98,7 @@ repeat:
                page = *((unsigned long *) page);
        }
        if (!(page & PAGE_PRESENT)) {
-               do_no_page(0,addr,tsk,0);
+               do_no_page(0,addr,tsk);
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -133,13 +133,13 @@ repeat:
                page = *((unsigned long *) page);
        }
        if (!(page & PAGE_PRESENT)) {
-               do_no_page(0 /* PAGE_RW */ ,addr,tsk,0);
+               do_no_page(0 /* PAGE_RW */ ,addr,tsk);
                goto repeat;
        }
        if (!(page & PAGE_RW)) {
                if(!(page & PAGE_COW))
                        readonly = 1;
-               do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0);
+               do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk);
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
index ab511b9610f0e480369af5805ea3b6dbffe9a748..4b423f28776a8edc8bbd421c533bb89046925c6d 100644 (file)
@@ -561,7 +561,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
  * in better assembly code.. The "default" path will see no jumps at all.
  */
 static void __do_wp_page(unsigned long error_code, unsigned long address,
-       struct task_struct * tsk, unsigned long user_esp)
+       struct task_struct * tsk)
 {
        unsigned long *pde, pte, old_page, prot;
        unsigned long new_page;
@@ -626,7 +626,7 @@ end_wp_page:
  * the low-level function only in that case..
  */
 void do_wp_page(unsigned long error_code, unsigned long address,
-       struct task_struct * tsk, unsigned long user_esp)
+       struct task_struct * tsk)
 {
        unsigned long page;
        unsigned long * pg_table;
@@ -643,7 +643,7 @@ void do_wp_page(unsigned long error_code, unsigned long address,
                if (page & PAGE_RW)
                        return;
                if (!(page & PAGE_COW)) {
-                       if (user_esp && tsk == current) {
+                       if ((error_code & PAGE_USER) && tsk == current) {
                                current->tss.cr2 = address;
                                current->tss.error_code = error_code;
                                current->tss.trap_no = 14;
@@ -656,7 +656,7 @@ void do_wp_page(unsigned long error_code, unsigned long address,
                        invalidate();
                        return;
                }
-               __do_wp_page(error_code, address, tsk, user_esp);
+               __do_wp_page(error_code, address, tsk);
                return;
        }
        printk("bad page directory entry %08lx\n",page);
@@ -670,7 +670,7 @@ static int __verify_write(unsigned long start, unsigned long size)
        size >>= PAGE_SHIFT;
        start &= PAGE_MASK;
        do {
-               do_wp_page(1,start,current,0);
+               do_wp_page(1,start,current);
                start += PAGE_SIZE;
        } while (size--);
        return 0;
@@ -733,30 +733,25 @@ static inline void get_empty_page(struct task_struct * tsk, unsigned long addres
  * task.
  *
  * NOTE! This assumes we have checked that p != current, and that they
- * share the same executable or library.
- *
- * We may want to fix this to allow page sharing for PIC pages at different
- * addresses so that ELF will really perform properly. As long as the vast
- * majority of sharable libraries load at fixed addresses this is not a
- * big concern. Any sharing of pages between the buffer cache and the
- * code space reduces the need for this as well.  - ERY
+ * share the same inode and can generally otherwise be shared.
  */
-static int try_to_share(unsigned long address, struct task_struct * tsk,
-       struct task_struct * p, unsigned long error_code, unsigned long newpage)
+static int try_to_share(unsigned long to_address, struct vm_area_struct * to_area,
+       unsigned long from_address, struct vm_area_struct * from_area,
+       unsigned long newpage)
 {
        unsigned long from;
        unsigned long to;
        unsigned long from_page;
        unsigned long to_page;
 
-       from_page = (unsigned long)PAGE_DIR_OFFSET(p->tss.cr3,address);
-       to_page = (unsigned long)PAGE_DIR_OFFSET(tsk->tss.cr3,address);
+       from_page = (unsigned long)PAGE_DIR_OFFSET(from_area->vm_task->tss.cr3,from_address);
+       to_page = (unsigned long)PAGE_DIR_OFFSET(to_area->vm_task->tss.cr3,to_address);
 /* is there a page-directory at from? */
        from = *(unsigned long *) from_page;
        if (!(from & PAGE_PRESENT))
                return 0;
        from &= PAGE_MASK;
-       from_page = from + PAGE_PTR(address);
+       from_page = from + PAGE_PTR(from_address);
        from = *(unsigned long *) from_page;
 /* is the page clean and present? */
        if ((from & (PAGE_PRESENT | PAGE_DIRTY)) != PAGE_PRESENT)
@@ -770,68 +765,88 @@ static int try_to_share(unsigned long address, struct task_struct * tsk,
        if (!(to & PAGE_PRESENT))
                return 0;
        to &= PAGE_MASK;
-       to_page = to + PAGE_PTR(address);
+       to_page = to + PAGE_PTR(to_address);
        if (*(unsigned long *) to_page)
                return 0;
-/* share them if read - do COW immediately otherwise */
-       if (error_code & PAGE_RW) {
-               if(!newpage)    /* did the page exist?  SRB. */
-                       return 0;
-               copy_page((from & PAGE_MASK),newpage);
-               to = newpage | PAGE_PRIVATE;
-       } else {
-               mem_map[MAP_NR(from)]++;
-               from &= ~PAGE_RW;
-               to = from;
-               if(newpage)     /* only if it existed. SRB. */
-                       free_page(newpage);
+/* do we copy? */
+       if (newpage) {
+               copy_page((from & PAGE_MASK), newpage);
+               *(unsigned long *) to_page = newpage | to_area->vm_page_prot;
+               return 1;
        }
-       *(unsigned long *) from_page = from;
+/* just share them.. */
+       mem_map[MAP_NR(from)]++;
+/* fill in the 'to' field, checking for COW-stuff */
+       to = (from & PAGE_MASK) | to_area->vm_page_prot;
+       if (to & PAGE_COW)
+               to &= ~PAGE_RW;
        *(unsigned long *) to_page = to;
+/* Check if we need to do anything at all to the 'from' field */
+       if (!(from & PAGE_RW))
+               return 1;
+       if (!(from_area->vm_page_prot & PAGE_COW))
+               return 1;
+/* ok, need to mark it read-only, so invalidate aany possible old TB entry */
+       from &= ~PAGE_RW;
+       *(unsigned long *) from_page = from;
        invalidate();
        return 1;
 }
 
 /*
  * share_page() tries to find a process that could share a page with
- * the current one. Address is the address of the wanted page relative
- * to the current data space.
+ * the current one.
  *
- * We first check if it is at all feasible by checking executable->i_count.
+ * We first check if it is at all feasible by checking inode->i_count.
  * It should be >1 if there are other tasks sharing this inode.
  */
-int share_page(struct vm_area_struct * area, struct task_struct * tsk,
-       struct inode * inode,
-       unsigned long address, unsigned long error_code, unsigned long newpage)
+static int share_page(struct vm_area_struct * area, unsigned long address,
+       unsigned long error_code, unsigned long newpage)
 {
+       struct inode * inode;
        struct task_struct ** p;
+       unsigned long offset;
+       unsigned long from_address;
+       unsigned long give_page;
 
-       if (!inode || inode->i_count < 2 || !area->vm_ops)
+       if (!area || !(inode = area->vm_inode) || inode->i_count < 2)
                return 0;
+       /* do we need to copy or can we just share? */
+       give_page = 0;
+       if ((area->vm_page_prot & PAGE_COW) && (error_code & PAGE_RW)) {
+               if (!newpage)
+                       return 0;
+               give_page = newpage;
+       }
+       offset = address - area->vm_start + area->vm_offset;
        for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+               struct vm_area_struct * mpnt;
                if (!*p)
                        continue;
-               if (tsk == *p)
+               if (area->vm_task == *p)
                        continue;
-               if (inode != (*p)->executable) {
-                         if(!area) continue;
-                       /* Now see if there is something in the VMM that
-                          we can share pages with */
-                       if(area){
-                         struct vm_area_struct * mpnt;
-                         for (mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
-                           if (mpnt->vm_ops == area->vm_ops &&
-                              mpnt->vm_inode->i_ino == area->vm_inode->i_ino&&
-                              mpnt->vm_inode->i_dev == area->vm_inode->i_dev){
-                             if (mpnt->vm_ops->share(mpnt, area, address))
-                               break;
-                           };
-                         };
-                         if (!mpnt) continue;  /* Nope.  Nuthin here */
-                       };
-               }
-               if (try_to_share(address,tsk,*p,error_code,newpage))
+               /* Now see if there is something in the VMM that
+                  we can share pages with */
+               for (mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
+                       /* must be same inode */
+                       if (mpnt->vm_inode != inode)
+                               continue;
+                       /* offsets must be mutually page-aligned */
+                       if ((mpnt->vm_offset ^ area->vm_offset) & ~PAGE_MASK)
+                               continue;
+                       /* the other area must actually cover the wanted page.. */
+                       from_address = offset + mpnt->vm_start - mpnt->vm_offset;
+                       if (from_address < mpnt->vm_start || from_address >= mpnt->vm_end)
+                               continue;
+                       /* .. NOW we can actually try to use the same physical page */
+                       if (!try_to_share(address, area, from_address, mpnt, give_page))
+                               continue;
+                       /* free newpage if we never used it.. */
+                       if (give_page || !newpage)
+                               return 1;
+                       free_page(newpage);
                        return 1;
+               }
        }
        return 0;
 }
@@ -870,12 +885,41 @@ static inline unsigned long get_empty_pgtable(struct task_struct * tsk,unsigned
        return 0;
 }
 
-void do_no_page(unsigned long error_code, unsigned long address,
-       struct task_struct *tsk, unsigned long user_esp)
+static void handle_no_page(struct vm_area_struct * vma,
+       unsigned long address, unsigned long error_code)
 {
-       unsigned long tmp;
        unsigned long page;
-       struct vm_area_struct * mpnt;
+       int prot;
+
+       page = get_free_page(GFP_KERNEL);
+       if (share_page(vma, address, error_code, page)) {
+               ++vma->vm_task->mm->min_flt;
+               return;
+       }
+       if (!page) {
+               oom(current);
+               put_page(vma->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
+               return;
+       }
+       ++vma->vm_task->mm->maj_flt;
+       ++vma->vm_task->mm->rss;
+       page = vma->vm_ops->nopage(vma, address, page, error_code);
+       if (share_page(vma, address, error_code, 0))
+               return;
+       prot = vma->vm_page_prot;
+       if ((prot & PAGE_COW) && mem_map[MAP_NR(page)] > 1)
+               prot &= ~PAGE_RW;
+       if (put_page(vma->vm_task, page, address, prot))
+               return;
+       free_page(page);
+       oom(current);
+}
+
+void do_no_page(unsigned long error_code, unsigned long address,
+       struct task_struct *tsk)
+{
+       unsigned long page, tmp;
+       struct vm_area_struct * vma;
 
        page = get_empty_pgtable(tsk,address);
        if (!page)
@@ -891,42 +935,43 @@ void do_no_page(unsigned long error_code, unsigned long address,
                swap_in((unsigned long *) page);
                return;
        }
-       address &= 0xfffff000;
-       tmp = 0;
-       for (mpnt = tsk->mm->mmap; mpnt != NULL; mpnt = mpnt->vm_next) {
-               if (address < mpnt->vm_start)
+       address &= PAGE_MASK;
+       for (vma = tsk->mm->mmap ; ; vma = vma->vm_next) {
+               if (!vma)
+                       goto bad_area;
+               if (vma->vm_end > address)
                        break;
-               if (address >= mpnt->vm_end) {
-                       tmp = mpnt->vm_end;
-                       continue;
-               }
-               if (!mpnt->vm_ops || !mpnt->vm_ops->nopage) {
-                       ++tsk->mm->rss;
-                       ++tsk->mm->min_flt;
-                       get_empty_page(tsk,address);
-                       return;
-               }
+       }
+       if (vma->vm_start <= address)
+               goto good_area;
+       if (!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+       if (vma->vm_end - address > tsk->rlim[RLIMIT_STACK].rlim_cur)
+               goto bad_area;
+       vma->vm_offset -= vma->vm_start - address;
+       vma->vm_start = address;
+
+good_area:
+       if (!vma->vm_ops || !vma->vm_ops->nopage) {
                ++tsk->mm->rss;
-               mpnt->vm_ops->nopage(error_code, mpnt, address);
+               ++tsk->mm->min_flt;
+               get_empty_page(tsk,address);
                return;
        }
+       handle_no_page(vma, address, error_code);
+       return;
+
+bad_area:
        if (tsk != current)
-               goto ok_no_page;
-       if (address >= tsk->mm->end_data && address < tsk->mm->brk)
-               goto ok_no_page;
-       if (mpnt && (mpnt->vm_flags & VM_GROWSDOWN) &&
-           address - tmp > mpnt->vm_start - address &&
-           tsk->rlim[RLIMIT_STACK].rlim_cur > mpnt->vm_end - address) {
-               mpnt->vm_start = address;
-               goto ok_no_page;
-       }
+               goto kernel_needs_bad_page;
        tsk->tss.cr2 = address;
-       current->tss.error_code = error_code;
-       current->tss.trap_no = 14;
+       tsk->tss.error_code = error_code;
+       tsk->tss.trap_no = 14;
        send_sig(SIGSEGV,tsk,1);
        if (error_code & 4)     /* user level access? */
                return;
-ok_no_page:
+
+kernel_needs_bad_page:
        ++tsk->mm->rss;
        ++tsk->mm->min_flt;
        get_empty_page(tsk,address);
@@ -940,28 +985,25 @@ ok_no_page:
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
        unsigned long address;
-       unsigned long user_esp = 0;
+       unsigned long page;
        unsigned int bit;
 
        /* get the address */
        __asm__("movl %%cr2,%0":"=r" (address));
        if (address < TASK_SIZE) {
-               if (error_code & 4) {   /* user mode access? */
-                       if (regs->eflags & VM_MASK) {
-                               bit = (address - 0xA0000) >> PAGE_SHIFT;
-                               if (bit < 32)
-                                       current->screen_bitmap |= 1 << bit;
-                       } else 
-                               user_esp = regs->esp;
+               if (regs->eflags & VM_MASK) {
+                       bit = (address - 0xA0000) >> PAGE_SHIFT;
+                       if (bit < 32)
+                               current->screen_bitmap |= 1 << bit;
                }
                if (error_code & PAGE_PRESENT) {
 #ifdef CONFIG_TEST_VERIFY_AREA
                        if (regs->cs == KERNEL_CS)
                                printk("WP fault at %08x\n", regs->eip);
 #endif
-                       do_wp_page(error_code, address, current, user_esp);
+                       do_wp_page(error_code, address, current);
                } else {
-                       do_no_page(error_code, address, current, user_esp);
+                       do_no_page(error_code, address, current);
                }
                return;
        }
@@ -979,16 +1021,16 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
                printk(KERN_ALERT "Unable to handle kernel paging request");
        printk(" at kernel address %08lx\n",address);
        address += TASK_SIZE;
-       __asm__("movl %%cr3,%0" : "=r" (user_esp));
+       __asm__("movl %%cr3,%0" : "=r" (page));
        printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
-               current->tss.cr3, user_esp);
-       user_esp = ((unsigned long *) user_esp)[address >> 22];
-       printk(KERN_ALERT "*pde = %08lx\n", user_esp);
-       if (user_esp & PAGE_PRESENT) {
-               user_esp &= PAGE_MASK;
+               current->tss.cr3, page);
+       page = ((unsigned long *) page)[address >> 22];
+       printk(KERN_ALERT "*pde = %08lx\n", page);
+       if (page & PAGE_PRESENT) {
+               page &= PAGE_MASK;
                address &= 0x003ff000;
-               user_esp = ((unsigned long *) user_esp)[address >> PAGE_SHIFT];
-               printk(KERN_ALERT "*pte = %08lx\n", user_esp);
+               page = ((unsigned long *) page)[address >> PAGE_SHIFT];
+               printk(KERN_ALERT "*pte = %08lx\n", page);
        }
        die_if_kernel("Oops", regs, error_code);
        do_exit(SIGKILL);
@@ -1214,11 +1256,11 @@ void si_meminfo(struct sysinfo *val)
 
 
 /* This handles a generic mmap of a disk file */
-void file_mmap_nopage(int error_code, struct vm_area_struct * area, unsigned long address)
+unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
+       unsigned long page, int error_code)
 {
        struct inode * inode = area->vm_inode;
        unsigned int block;
-       unsigned long page;
        int nr[8];
        int i, j;
        int prot = area->vm_page_prot;
@@ -1227,32 +1269,11 @@ void file_mmap_nopage(int error_code, struct vm_area_struct * area, unsigned lon
        block = address - area->vm_start + area->vm_offset;
        block >>= inode->i_sb->s_blocksize_bits;
 
-       page = get_free_page(GFP_KERNEL);
-       if (share_page(area, area->vm_task, inode, address, error_code, page)) {
-               ++area->vm_task->mm->min_flt;
-               return;
-       }
-
-       ++area->vm_task->mm->maj_flt;
-       if (!page) {
-               oom(current);
-               put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
-               return;
-       }
        for (i=0, j=0; i< PAGE_SIZE ; j++, block++, i += inode->i_sb->s_blocksize)
                nr[j] = bmap(inode,block);
        if (error_code & PAGE_RW)
                prot |= PAGE_RW | PAGE_DIRTY;
-       page = bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, prot);
-
-       if (!(prot & PAGE_RW)) {
-               if (share_page(area, area->vm_task, inode, address, error_code, page))
-                       return;
-       }
-       if (put_page(area->vm_task,page,address,prot))
-               return;
-       free_page(page);
-       oom(current);
+       return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, !(error_code & PAGE_RW));
 }
 
 void file_mmap_free(struct vm_area_struct * area)
@@ -1274,16 +1295,6 @@ int file_mmap_share(struct vm_area_struct * area1,
                    struct vm_area_struct * area2, 
                    unsigned long address)
 {
-       if (area1->vm_inode != area2->vm_inode)
-               return 0;
-       if (area1->vm_start != area2->vm_start)
-               return 0;
-       if (area1->vm_end != area2->vm_end)
-               return 0;
-       if (area1->vm_offset != area2->vm_offset)
-               return 0;
-       if (area1->vm_page_prot != area2->vm_page_prot)
-               return 0;
        return 1;
 }
 
index ffc2a195d493e1f6323aa46062d6491c645a8f0e..2e6f93d4499d3dbd519495137698294025cc1070 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -869,7 +869,7 @@ void si_swapinfo(struct sysinfo *val)
 
        val->freeswap = val->totalswap = 0;
        for (i = 0; i < nr_swapfiles; i++) {
-               if (!(swap_info[i].flags & SWP_USED))
+               if ((swap_info[i].flags & SWP_WRITEOK) != SWP_WRITEOK)
                        continue;
                for (j = 0; j < swap_info[i].max; ++j)
                        switch (swap_info[i].swap_map[j]) {