aboutsummaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sys/i386/isa/sound')
-rw-r--r--sys/i386/isa/sound/CHANGELOG75
-rw-r--r--sys/i386/isa/sound/RELNOTES.Linux256
-rw-r--r--sys/i386/isa/sound/adlib_card.c13
-rw-r--r--sys/i386/isa/sound/audio.c106
-rw-r--r--sys/i386/isa/sound/debug.h29
-rw-r--r--sys/i386/isa/sound/dev_table.c148
-rw-r--r--sys/i386/isa/sound/dev_table.h46
-rw-r--r--sys/i386/isa/sound/dmabuf.c360
-rw-r--r--sys/i386/isa/sound/dsp.c270
-rw-r--r--sys/i386/isa/sound/gus_card.c87
-rw-r--r--sys/i386/isa/sound/gus_hw.h15
-rw-r--r--sys/i386/isa/sound/gus_linearvol.h18
-rw-r--r--sys/i386/isa/sound/gus_midi.c14
-rw-r--r--sys/i386/isa/sound/gus_vol.c70
-rw-r--r--sys/i386/isa/sound/gus_wave.c1834
-rw-r--r--sys/i386/isa/sound/ics2101.c265
-rw-r--r--sys/i386/isa/sound/local.h13
-rw-r--r--sys/i386/isa/sound/midi.c220
-rw-r--r--sys/i386/isa/sound/midibuf.c14
-rw-r--r--sys/i386/isa/sound/mpu401.c129
-rw-r--r--sys/i386/isa/sound/opl3.c68
-rw-r--r--sys/i386/isa/sound/os.h94
-rw-r--r--sys/i386/isa/sound/pas.h12
-rw-r--r--sys/i386/isa/sound/pas2_card.c135
-rw-r--r--sys/i386/isa/sound/pas2_midi.c16
-rw-r--r--sys/i386/isa/sound/pas2_mixer.c40
-rw-r--r--sys/i386/isa/sound/pas2_pcm.c91
-rw-r--r--sys/i386/isa/sound/patmgr.c41
-rw-r--r--sys/i386/isa/sound/pro_midi.c140
-rw-r--r--sys/i386/isa/sound/sb.h28
-rw-r--r--sys/i386/isa/sound/sb16_dsp.c627
-rw-r--r--sys/i386/isa/sound/sb16_midi.c287
-rw-r--r--sys/i386/isa/sound/sb_card.c13
-rw-r--r--sys/i386/isa/sound/sb_dsp.c1140
-rw-r--r--sys/i386/isa/sound/sb_midi.c224
-rw-r--r--sys/i386/isa/sound/sb_mixer.c422
-rw-r--r--sys/i386/isa/sound/sb_mixer.h212
-rw-r--r--sys/i386/isa/sound/sequencer.c311
-rw-r--r--sys/i386/isa/sound/sound_calls.h59
-rw-r--r--sys/i386/isa/sound/sound_config.h43
-rw-r--r--sys/i386/isa/sound/sound_switch.c445
-rw-r--r--sys/i386/isa/sound/soundcard.c307
42 files changed, 5891 insertions, 2846 deletions
diff --git a/sys/i386/isa/sound/CHANGELOG b/sys/i386/isa/sound/CHANGELOG
new file mode 100644
index 000000000000..6a9bef153ce3
--- /dev/null
+++ b/sys/i386/isa/sound/CHANGELOG
@@ -0,0 +1,75 @@
+Changelog for version 2.5
+-------------------------
+
+Since 2.5-beta2
+- Some fine tuning to the GUS v3.7 mixer code.
+- Fixed speed limits for the plain SB (1.0 to 2.0).
+
+Since 2.5-beta
+- Fixed OPL-3 detection with SB. Caused problems with PAS16.
+- GUS v3.7 mixer support.
+
+Since 2.4
+- Mixer support for Sound Galaxy NX Pro (define __SGNXPRO__ on your local.h).
+- Fixed truncated sound on /dev/dsp when the device is closed.
+- Linear volume mode for GUS
+- Pitch bends larger than +/- 2 octaves.
+- MIDI recording for SB and SB Pro. (Untested).
+- Some other fixes.
+- SB16 MIDI and DSP drivers only initialized if SB16 actually installed.
+- Implemented better detection for OPL-3. This should be usefull if you
+ have an old SB Pro (the non-OPL-3 one) or a SB 2.0 clone which has a OPL-3.
+- SVR4.2 support by Ian Hartas. Initial ALPHA TEST version (untested).
+
+Since 2.3b
+- Fixed bug which made it impossible to make long recordings to disk.
+ Recording was not restarted after a buffer overflow situation.
+- Limited mixer support for GUS.
+- Numerous improvements to the GUS driver by Andrew Robinson. Including
+ some click removal etc.
+
+Since 2.3
+- Fixed some minor bugs in the SB16 driver.
+
+Since 2.2b
+- Full SB16 DSP support. 8/16 bit, mono/stereo
+- The SCO and FreeBSD versions should be in sync now. There are some
+ problems with SB16 and GUS in the freebsd versions.
+ The DMA buffer allocation of the SCO version has been polished but
+ there could still be some problems. At least it hogs memory.
+ The DMA channel
+ configuration method used in the sco/System is a hack.
+- Support for the MPU emulation of the SB16.
+- Some big arrays are now allocated boot time. This makes the bss segment
+ smaller which makes it possible to use the full driver with
+ NetBSD. These arrays are not allocated if no suitable soundcard is available.
+- Fixed a bug in the compute_and_set_volume in gus_wave.c
+- Fixed the too fast mono playback problem of SB Pro and PAS16.
+
+Since 2.2
+- Stereo recording for SB Pro. Somehow it was missing and nobody
+ had noticed it earlier.
+- Minor polishing.
+- Interpreting of boot time arguments (sound=) for Linux.
+- Breakup of sb_dsp.c. Parts of the code has been moved to
+ sb_mixer.c and sb_midi.c
+
+Since 2.1
+- Preliminary support for SB16.
+ - The SB16 mixer is supported in it's native mode.
+ - Digitized voice capability up to 44.1 kHz/8 bit/mono
+ (16 bit and stereo support coming in the next release).
+- Fixed some bugs in the digitized voice driver for PAS16.
+- Proper initialization of the SB emulation of latest PAS16 models.
+
+- Significantly improved /dev/dsp and /dev/audio support.
+ - Now supports half duplex mode. It's now possible to record and
+ playback without closing and reopening the device.
+ - It's possible to use smaller buffers than earlier. There is a new
+ ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &n) where n should be 1, 2 or 4.
+ This call instructs the driver to use smaller buffers. The default
+ buffer size (0.5 to 1.0 seconds) is divided by n. Should be called
+ immediately after opening the device.
+
+Since 2.0
+Just cosmetic changes.
diff --git a/sys/i386/isa/sound/RELNOTES.Linux b/sys/i386/isa/sound/RELNOTES.Linux
index 4082f4e255b0..ea57d0a950c4 100644
--- a/sys/i386/isa/sound/RELNOTES.Linux
+++ b/sys/i386/isa/sound/RELNOTES.Linux
@@ -1,67 +1,74 @@
-Release notes for the Linux Sound Driver 1.99.9
------------------------------------------------
-
-******** THIS IS A BETA TEST RELEASE ********
-which means that there can be some untested things. In theory
-there is a risk that this driver causes some trouble to your system.
-You should not use this driver before backing up your disks.
-
-
-
-
-Welcome to use the Gravis UltraSound driver for Linux. This
-driver still supports the same cards than version 1.0c
-(SoundBlaster, SB Pro, Pro Audio Spectrum 16 and AdLib).
-In addition there is rather limited support for MPU-401
+Release notes for the Linux Sound Driver 2.5
+--------------------------------------------
+There is also a version called 2.5-beta floating around the net. This
+version contains some fixes after it. Mainly to the SB and GUS code.
+
+CAUTION! The SVR4.2 port has not been tested much. Backup your system
+ carefully before trying it.
+
+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).
+
+You will need the snd-util-2.5.tar.gz and snd-data-0.1.tar.Z
+packages to use this driver. They should be in the same
+ftp site or BBS from where you got this driver. For
+example at nic.funet.fi:pub/OS/Linux/*.
+
+If you are looking for the installation instructions, please
+look at $OS/Readme.
+
+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
-of the SB Pro and PAS16 cards is now supported in the 4 OP
-modes.
Most of the features of the /dev/sequencer device file are
available just for GUS owners.
-The SoundBlaster 16 and SB 16 ASP cards are not supported.
-They could work in mono mode with speeds < 22 kHz.
-The OPL-3 chicp of the SB 16 should work (without problems?).
-Is there anybody willing to implement the SB 16 support
-(have the SB 16 and the SDK for it)?
-
-
-This is the first version of the driver which has almost
-all of the features which I have planned to include into
-version 2.0. Some features are still missing and some ones
-doesn't work.
-
NOTE! There are separate driver for CD-ROMS supported by
some soundcards. The driver for CDU31A (Fusion 16) is
called cdu31a-0.6.diff.z. It will be contained in the
Linux version 0.99.12. The driver for the CD-ROM of SB Pro
is sbpcd0.4.tar.gz (these were the latest versions when I wrote
this). These files should be at least at sunsite.unc.edu.
- As far as I know, there is no driver for the SCSI interface of PAS16
- (yet).
+ Also the SCSI interface of the PAS16 should be supported by
+ Linux 0.99.13k and later.
There is also a driver for joystick. Look for file joystick-0.5.tar.gz
(sunsite).
- Since this driver is a sound driver, it will not contain support
- for SCSI/CD-ROM/Joystick -devices.
Compatibility with the earlier versions
---------------------------------------
-This is just like the version 1.99.7/1.99.8. There is just some minor
-enhancements. Most of them are portability fixes. If you are porting
-this driver to any OS, please look at the 386bsd/os.h. There is some
-new macros and some macros have more parameters. In addition this file
-contains some usefull comments.
+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.
-**** There is some ISC and 386bsd stuff in this driver. Please stay away ****
-This stuff is here just because I want to be in sync with the porters. These
-ports don't work yet.
+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-1.99.6 package contains some utilities for this version.
+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
@@ -78,59 +85,46 @@ After version 1.99.0 this must be done as the following:
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-1.99.6 package for further info.
-
-The GUS patch format has changed since the version 1.99.3. You have to
-use latest versions of the programs in the sound/gustest directory. In
-addition the version 0.4g of the Adagio package supports this format.
-
-New features
-------------
-
-There is also some changes which make this version more usable than
-the version 1.0c.
-
-- /dev/dsp and /dev/audio
-
-The DMA buffering is now little bit more intelligent than earlier. The
-buffer size is selected run-time so that a buffer holds data for 0.5 to
-1.0 seconds of recording or playback. This makes recording more comfortable
-than with version 1.0. With the previous version there was sometimes more
-than 10 seconds of delay before the driver returned the first input byte.
-
-There is also support for more than one digitized voice devices. The device
-files /dev/dsp1 and /dev/audio1 (minor 19 and 20) are available with PAS16.
-The /dev/dsp (/dev/audio) is connected to the PCM circuit of the PAS16 itself
-and the /dev/dsp1 (/dev/audio1) to the SB emulation of PAS16 card. Two
-dsp/audio devices are available also if you have combination of SB and GUS.
-With GUS and PAS16 you will have even three dsp/audio devices. These devices
-can be used independently and can be active at the same time (3 channels
-at the same time propably don't work).
+the snd-util-2.0 package for further info.
-The dsp/audio support of PAS16 should be much cleaner now since the
-constant clicking sound between the DMA blocks (about once per second) has
-been eliminated.
+This version is almost 100% compatible with the alpha test version (1.99.9). The
+difference is in the installation procedure.
-The stereo playback of GUS doesn't work perfectly. There is lot of
-clicking in the output.
+Using this driver with other operating systems than Linux
+---------------------------------------------------------
-- /dev/mixer
+This package contains just the Linux version. The version 2.3
+for SCO is available at nic.funet.fi:pub/OS/Linux/ALPHA/sound.
+The version 2.3 doesn't work well with xxxxxBSD. Use the version
+2.3 for them.
-No changes.
-
-There is no mixer for the GUS yet.
-
-- /dev/sequencer
-
-This part has the most changes. Mostly to support the rich
-features of the Gravis UltraSound. There is also the support
-for the OPL-3 synthesizer chip.
+/dev/sndstat
+------------
-- /dev/sndstat
+The /dev/sndstat is now available in the SCO and BSD versions also.
This is a new devicefile for debugging purposes. A better place for
it is in the /proc -directory but I was just too lazy to implement it
@@ -139,11 +133,13 @@ info about the current configuration (see the example below). If you
send me a error/problem report, please include a printout from this
device to your message (cat /dev/sndstat).
+Note! This device file is currently present only in the Linux version
+ of this driver.
+
------ cut here --- cat /dev/sndstat example --------
Sound Driver:1.99.7 (Fri Jul 9 17:01:47 GMT 1993 root@lucifer.savolai.fi)
Config options: 0x00000d4b
-Major number: 14
HW config:
Type 4: Gravis Ultrasound at 0x210 irq 15 drq 6
Type 3: ProAudioSpectrum at 0x388 irq 10 drq 3
@@ -166,12 +162,15 @@ Midi devices:
Mixer(s) installed
------ cut here ---- End of Example -----------
+Known bugs/limitations
+----------------------
-Known bugs
-----------
-
-- There was clicking during stereo playback to /dev/dsp with GUS.
- * Fixed in 1.99.9 *
+- 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.
+- Midi input doesn't work with SB and SB Pro (SB16 works).
- It's not possible to open /dev/dsp (or /dev/audio) while the
/dev/sequencer is open for output and GUS is the only soundcard
installed. It's possible if /dev/dsp is opened before /dev/sequencer
@@ -180,12 +179,77 @@ Known bugs
- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed.
It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI
adapter.
+- There are some problems in midi input with MPU-401 and the SB16 midi
+ (MPU-401 emulation). This makes it impossible to read long sysex dumps
+ using these devices.
- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting
^C and playing again should solve this problem. This is propably caused by
- incompatibilities between GUS and certain VLB motherboards. Try to avoid
+ incompatibilities between GUS and certain VLB motherboards (like mine).
+ Try to avoid
switching between VTs while patches are being loaded to the GUS.
-- There was some problems with GUS and Mitsumi CD in version 1.99.8. Fixed
- in 1.99.9.
-- /dev/audio sounded like stereo with GUS. Fixed in 1.99.9.
+ 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).
+
+
+Contributors
+------------
+
+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
+ 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.
+ Mikael Nordqvist Linear volume support for GUS.
+ Ian Hartas SVR4.2 port
+ Markus Aroharju and
+ Risto Kankkunen Major contributions to the mixer support
+ of GUS v3.7.
+ Hunyue Yau Sound Galaxy NX Pro mixer support.
+
+Regards,
+
+Hannu Savolainen
+hannu@voxware.pp.fi, Hannu.Savolainen@Helsinki.fi
+
+Snail mail: Hannu Savolainen
+ Pallaksentie 4 A 2
+ 00970 Helsinki
+ Finland
diff --git a/sys/i386/isa/sound/adlib_card.c b/sys/i386/isa/sound/adlib_card.c
index 29e521e914d9..6365069384a5 100644
--- a/sys/i386/isa/sound/adlib_card.c
+++ b/sys/i386/isa/sound/adlib_card.c
@@ -1,11 +1,10 @@
-
/*
- * linux/kernel/chr_drv/sound/adlib_card.c
- *
+ * sound/adlib_card.c
+ *
* Detection routine for the AdLib card.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -13,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -25,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
diff --git a/sys/i386/isa/sound/audio.c b/sys/i386/isa/sound/audio.c
index 775e6abeb021..f27f9d5fa09f 100644
--- a/sys/i386/isa/sound/audio.c
+++ b/sys/i386/isa/sound/audio.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/audio.c
- *
+ * sound/audio.c
+ *
* Device file manager for /dev/audio
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -38,23 +38,45 @@
#define OFF 0
static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a
+
* incomplete output block */
static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
+
+static int audio_mode[MAX_DSP_DEV];
+
+#define AM_NONE 0
+#define AM_WRITE 1
+#define AM_READ 2
+
static char *wr_dma_buf[MAX_DSP_DEV];
int
audio_open (int dev, struct fileinfo *file)
{
- int mode;
int ret;
+ int bits;
+ int dev_type = dev & 0x0f;
+ int mode = file->mode & O_ACCMODE;
dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+
+ if (dev_type == SND_DEV_DSP16)
+ bits = 16;
+ else
+ bits = 8;
if ((ret = DMAbuf_open (dev, mode)) < 0)
return ret;
+ if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
+ {
+ audio_release (dev, file);
+ return RET_ERROR (ENXIO);
+ }
+
wr_buff_no[dev] = -1;
+ audio_mode[dev] = AM_NONE;
+
return ret;
}
@@ -106,12 +128,20 @@ 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 */
+ {
+ wr_buff_no[dev] = -1;
+ }
+
+ audio_mode[dev] = AM_WRITE;
+
if (!count) /* Flush output */
{
if (wr_buff_no[dev] >= 0)
@@ -136,15 +166,25 @@ 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]);
- COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
+ if (!dsp_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,
+ wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
+
/* Insert local processing here */
+ if (dev_type == SND_DEV_AUDIO)
+ {
#ifdef linux
- /* This just allows interrupts while the conversion is running */
- __asm__ ("sti");
+ /* This just allows interrupts while the conversion is running */
+ __asm__ ("sti");
#endif
- translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ }
c -= l;
p += l;
@@ -169,11 +209,24 @@ 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;
c = count;
+ if (audio_mode[dev] == AM_WRITE)
+ {
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ }
+
+ audio_mode[dev] = AM_READ;
+
while (c)
{
if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
@@ -183,12 +236,16 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
l = c;
/* Insert any local processing here. */
+
+ if (dev_type == SND_DEV_AUDIO)
+ {
#ifdef linux
- /* This just allows interrupts while the conversion is running */
- __asm__ ("sti");
+ /* This just allows interrupts while the conversion is running */
+ __asm__ ("sti");
#endif
- translate_bytes (dsp_ulaw, dmabuf, l);
+ translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
+ }
COPY_TO_USER (buf, p, dmabuf, l);
@@ -205,6 +262,8 @@ int
audio_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, unsigned int arg)
{
+ int dev_type = dev & 0x0f;
+
dev = dev >> 4;
switch (cmd)
@@ -235,11 +294,10 @@ audio_ioctl (int dev, struct fileinfo *file,
break;
default:
-#if 1
- return RET_ERROR (EIO);
-#else
+ if (dev_type == SND_DEV_AUDIO)
+ return RET_ERROR (EIO);
+
return DMAbuf_ioctl (dev, cmd, arg, 0);
-#endif
}
}
@@ -266,14 +324,14 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
int
audio_open (int dev, struct fileinfo *file)
- {
- return RET_ERROR (ENXIO);
- }
+{
+ return RET_ERROR (ENXIO);
+}
void
audio_release (int dev, struct fileinfo *file)
- {
- };
+{
+};
int
audio_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, unsigned int arg)
diff --git a/sys/i386/isa/sound/debug.h b/sys/i386/isa/sound/debug.h
deleted file mode 100644
index 79b4acdeba8f..000000000000
--- a/sys/i386/isa/sound/debug.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Kernel driver debugging stuff - cmetz@thor.tjhsst.edu */
-
-#ifndef _DEBUG_H_
-#define _DEBUG_H_
-
-#if defined (DEBUG_ME) && !defined(HALT_DEBUGGING)
-
-#define DEB(X) printk("%s %s: ", __FILE__, __FUNCTION__); X
-#define DEB1(X) printk("%s %s: ", __FILE__, __FUNCTION__); X
-#define RETURN_HEX(X, Y) { Y _foo; _foo = X; printk("%s %s: 0x%x\n", __FILE__, __FUNCTION__, ((int)_foo)); return(_foo); }
-#define RETURN_DEC(X, Y) { Y _foo; _foo = X; printk("%s %s: %d\n", __FILE__, __FUNCTION__, ((int)_foo)); return(_foo); }
-#define RETURN_PTR(X, Y) { Y _foo; _foo = X; printk("%s %s: 0x%08x\n", __FILE__, __FUNCTION__, ((void *)_foo)); return(_foo); }
-#define RETURN_ERR(X) { int _foo; _foo = X; printk("%s %s: ", __FILE__, __FUNCTION__); switch(_foo) { case 0: printk("No error"); break; case -ENODEV: printk("ENODEV"); break; case -EBUSY: printk("EBUSY"); break; default: printk("Error %d", _foo); } printk(".\n"); return(_foo); }
-#define DEB_OUTB OUTB
-#define DEB_INB INB
-
-#else
-
-#define DEB(X)
-#define DEB1(X)
-#define RETURN_HEX(X, Y) return(X)
-#define RETURN_DEC(X, Y) return(X)
-#define RETURN_PTR(X, Y) return(X)
-#define RETURN_ERR(X) return(X)
-#define DEB_OUTB OUTB
-#define DEB_INB INB
-
-#endif
-#endif
diff --git a/sys/i386/isa/sound/dev_table.c b/sys/i386/isa/sound/dev_table.c
index 7eabad4ab8a0..7f7cae11d02e 100644
--- a/sys/i386/isa/sound/dev_table.c
+++ b/sys/i386/isa/sound/dev_table.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/dev_table.c
- *
+ * sound/dev_table.c
+ *
* Device call tables.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#define _DEV_TABLE_C_
@@ -38,21 +38,24 @@ sndtable_init (long mem_start)
int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
for (i = 0; i < (n - 1); i++)
- if (supported_drivers[i].probe (&supported_drivers[i].config))
- {
+ if (supported_drivers[i].enabled)
+ if (supported_drivers[i].probe (&supported_drivers[i].config))
+ {
#ifndef SHORT_BANNERS
- printk ("snd%d",
- supported_drivers[i].card_type);
+ printk ("snd%d",
+ supported_drivers[i].card_type);
#endif
- mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
+ mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
#ifndef SHORT_BANNERS
- printk (" at 0x%03x irq %d drq %d\n",
- supported_drivers[i].config.io_base,
- supported_drivers[i].config.irq,
- supported_drivers[i].config.dma);
+ printk (" at 0x%x irq %d drq %d\n",
+ supported_drivers[i].config.io_base,
+ supported_drivers[i].config.irq,
+ supported_drivers[i].config.dma);
#endif
- }
+ }
+ else
+ supported_drivers[i].enabled = 0; /* Mark as not detected */
return mem_start;
}
@@ -66,7 +69,15 @@ sndtable_probe (int unit, struct address_info *hw_config)
for (i = 0; i < (n - 1); i++)
if (supported_drivers[i].card_type == unit)
- return supported_drivers[i].probe (hw_config);
+ {
+ 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;
+ }
return FALSE;
}
@@ -86,6 +97,10 @@ sndtable_init_card (int unit, struct address_info *hw_config)
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].attach (0, hw_config) != 0)
panic ("snd#: Invalid memory allocation\n");
return TRUE;
@@ -100,4 +115,103 @@ sndtable_get_cardcount (void)
return num_dspdevs + 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);
+
+ /*
+ * First disable all drivers
+ */
+
+ for (i = 0; i < n; i++)
+ supported_drivers[i].enabled = 0;
+
+ if (ints[0] == 0 || ints[1] == 0)
+ return;
+ /*
+ * Then enable them one by time
+ */
+
+ for (i = 1; i <= ints[0]; i++)
+ {
+ int card_type, ioaddr, irq, dma, ptr, j;
+ unsigned int val;
+
+ val = (unsigned int) ints[i];
+
+ card_type = (val & 0x0ff00000) >> 20;
+
+ if (card_type > 127)
+ {
+ /* Add any future extensions here */
+ return;
+ }
+
+ ioaddr = (val & 0x000fff00) >> 8;
+ irq = (val & 0x000000f0) >> 4;
+ dma = (val & 0x0000000f);
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr == -1)
+ printk ("Sound: Invalid setup parameter 0x%08x\n", val);
+ else
+ {
+ supported_drivers[ptr].enabled = 1;
+ supported_drivers[ptr].config.io_base = ioaddr;
+ supported_drivers[ptr].config.irq = irq;
+ supported_drivers[ptr].config.dma = dma;
+ }
+ }
+}
+
+#else
+void
+sound_chconf (int card_type, int ioaddr, int irq, int dma)
+{
+ int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ int ptr, j;
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr != -1)
+ {
+ supported_drivers[ptr].enabled = 1;
+ if (ioaddr)
+ supported_drivers[ptr].config.io_base = ioaddr;
+ if (irq)
+ supported_drivers[ptr].config.irq = irq;
+ if (dma)
+ supported_drivers[ptr].config.dma = dma;
+ }
+}
+
+#endif
+
+struct address_info *
+sound_getconf (int card_type)
+{
+ int j, ptr;
+ int n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr == -1)
+ return (struct address_info *) NULL;
+
+ return &supported_drivers[ptr].config;
+}
+
#endif
diff --git a/sys/i386/isa/sound/dev_table.h b/sys/i386/isa/sound/dev_table.h
index 9bfd7847ecd2..4b656ba39c2b 100644
--- a/sys/i386/isa/sound/dev_table.h
+++ b/sys/i386/isa/sound/dev_table.h
@@ -46,6 +46,7 @@ struct card_info {
long (*attach) (long mem_start, struct address_info *hw_config);
int (*probe) (struct address_info *hw_config);
struct address_info config;
+ int enabled;
};
/** UWM -- new MIDI structure here.. **/
@@ -57,10 +58,15 @@ struct generic_midi_info{
struct audio_operations {
char name[32];
+ int flags;
+#define NOTHING_SPECIAL 0
+#define NEEDS_RESTART 1
int (*open) (int dev, int mode);
void (*close) (int dev);
- void (*output_block) (int dev, unsigned long buf, int count, int intrflag);
- void (*start_input) (int dev, unsigned long buf, int count, int intrflag);
+ void (*output_block) (int dev, unsigned long buf,
+ int count, int intrflag, int dma_restart);
+ void (*start_input) (int dev, unsigned long buf,
+ int count, int intrflag, int dma_restart);
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local);
int (*prepare_for_input) (int dev, int bufsize, int nbufs);
int (*prepare_for_output) (int dev, int bufsize, int nbufs);
@@ -93,6 +99,7 @@ struct synth_operations {
void (*aftertouch) (int dev, int voice, int pressure);
void (*controller) (int dev, int voice, int ctrl_num, int value);
void (*panning) (int dev, int voice, int value);
+ void (*volume_method) (int dev, int mode);
int (*pmgr_interface) (int dev, struct patmgr_info *info);
};
@@ -159,31 +166,42 @@ struct generic_midi_operations {
*/
struct card_info supported_drivers[] = {
-#ifndef EXCLUDE_MPU401
+#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
{SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401,
- {MPU_BASE, MPU_IRQ, 0}},
-#endif
-
-#ifndef EXCLUDE_GUS
- {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus,
- {GUS_BASE, GUS_IRQ, GUS_DMA}},
+ {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_PAS
{SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas,
- {PAS_BASE, PAS_IRQ, PAS_DMA}},
+ {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}},
+ {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
+#endif
+
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+#ifndef EXCLUDE_AUDIO
+ {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect,
+ {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
+#endif
+#ifndef EXCLUDE_MIDI
+ {SNDCARD_SB16MIDI,"SB16 MPU-401", attach_sb16midi, probe_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},
#endif
#ifndef EXCLUDE_YM3812
{SNDCARD_ADLIB, "AdLib", attach_adlib_card, probe_adlib,
- {FM_MONO, 0, 0}},
+ {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
#endif
- {0, "*?*", NULL}
+ {0, "*?*", NULL, 0}
};
int num_sound_drivers =
@@ -220,6 +238,8 @@ struct generic_midi_operations {
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
#endif
diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c
index ace02d149a41..851a70a16b1b 100644
--- a/sys/i386/isa/sound/dmabuf.c
+++ b/sys/i386/isa/sound/dmabuf.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/dmabuf.c
- *
+ * sound/dmabuf.c
+ *
* The DMA buffer manager for digitized voice applications
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -35,7 +35,7 @@
#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
-#define MAX_SUB_BUFFERS 16
+#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR)
/*
* The DSP channel can be used either for input or output. Variable
@@ -48,7 +48,6 @@
#define DMODE_NONE 0
#define DMODE_OUTPUT 1
#define DMODE_INPUT 2
-#define DMODE_INIT 3
DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]);
@@ -58,22 +57,6 @@ static int dma_mode[MAX_DSP_DEV] =
static volatile int dmabuf_interrupted[MAX_DSP_DEV] =
{0};
-#ifdef ISC
-/* I don't like this. */
-#undef INTERRUPTIBLE_SLEEP_ON
-#define INTERRUPTIBLE_SLEEP_ON(A,F) { \
- A = F = 1; \
- if (sleep(&(A), (PZERO + 5) | PCATCH)) { \
- A = F = 0; \
- dmabuf_interrupted[dev] = 1; \
- dev_busy[dev] = 0; \
- dma_reset(dev); \
- dmabuf_interrupted[dev] = 0; \
- /* longjmp(u.u_qsav, 1); Where it goes??? */ \
- } \
- }
-#endif
-
/*
* Pointers to raw buffers
*/
@@ -89,7 +72,10 @@ int snd_raw_count[MAX_DSP_DEV];
*/
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];
@@ -102,8 +88,10 @@ static int bufferalloc_done[MAX_DSP_DEV] =
*/
static int dev_nbufs[MAX_DSP_DEV]; /* # of logical buffers ( >=
- * sound_buffcounts[dev] */
+
+ * sound_buffcounts[dev] */
static int dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS];
+static int dev_subdivision[MAX_DSP_DEV];
static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS];
static char *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] =
{
@@ -117,8 +105,8 @@ reorganize_buffers (int dev)
* This routine breaks the physical device buffers to logical ones.
*/
- unsigned long i, p, n;
- unsigned long sr, nc, sz, bsz;
+ unsigned i, p, n;
+ unsigned sr, nc, sz, bsz;
sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
@@ -148,6 +136,17 @@ reorganize_buffers (int dev)
if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev])
bsz >>= 1; /* Need at least 2 buffers */
+ if (dev_subdivision[dev] == 0)
+ dev_subdivision[dev] = 1; /* Default value */
+
+ bsz /= dev_subdivision[dev]; /* Use smaller buffers */
+
+ if (bsz == 0)
+ bsz = 4096; /* Just a sanity check */
+
+ while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS)
+ bsz <<= 1; /* Too much buffers */
+
dev_buffsize[dev] = bsz;
n = 0;
@@ -178,6 +177,21 @@ reorganize_buffers (int dev)
bufferalloc_done[dev] = 1;
}
+static void
+dma_init_buffers (int dev)
+{
+ RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
+ dev_underrun[dev] = 0;
+
+ dev_busy[dev] = 1;
+
+ bufferalloc_done[dev] = 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;
+}
+
int
DMAbuf_open (int dev, int mode)
{
@@ -198,20 +212,23 @@ DMAbuf_open (int dev, int mode)
return RET_ERROR (ENXIO);
}
+#ifdef USE_RUNTIME_DMAMEM
+ sound_dma_malloc (dev);
+#endif
+
if (snd_raw_buf[dev][0] == NULL)
return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)
return retval;
- dev_underrun[dev] = 0;
-
- dev_busy[dev] = 1;
+ dev_modes[dev] = mode;
+ dev_subdivision[dev] = 0;
- reorganize_buffers (dev);
- bufferalloc_done[dev] = 0;
-
- dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
+ 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);
return 0;
}
@@ -219,35 +236,37 @@ DMAbuf_open (int dev, int mode)
static void
dma_reset (int dev)
{
+ int retval;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
dsp_devs[dev]->reset (dev);
+ dsp_devs[dev]->close (dev);
- dev_qlen[dev] = 0;
- dev_qhead[dev] = 0;
- dev_qtail[dev] = 0;
- dev_active[dev] = 0;
+ if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0)
+ printk ("Sound: Reset failed - Can't reopen device\n");
+ RESTORE_INTR (flags);
+
+ dma_init_buffers (dev);
+ reorganize_buffers (dev);
}
static int
dma_sync (int dev)
{
unsigned long flags;
- unsigned long time;
- int timed_out;
if (dma_mode[dev] == DMODE_OUTPUT)
{
DISABLE_INTR (flags);
- timed_out = 0;
- time = GET_TIME ();
-
- while ((!(PROCESS_ABORTING || dmabuf_interrupted[dev]) && !timed_out)
+ while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev]))
&& dev_qlen[dev])
{
- REQUEST_TIMEOUT (10 * HZ, dev_sleeper[dev]);
- INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
- if ((GET_TIME () - time) > (10 * HZ))
- timed_out = 1;
+ 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);
@@ -259,11 +278,11 @@ dma_sync (int dev)
DISABLE_INTR (flags);
if (dsp_devs[dev]->has_output_drained) /* Device has hidden buffers */
{
- while (!(PROCESS_ABORTING || dmabuf_interrupted[dev])
+ while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev])
&& !dsp_devs[dev]->has_output_drained (dev))
{
- REQUEST_TIMEOUT (HZ / 4, dev_sleeper[dev]);
- INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4);
}
}
RESTORE_INTR (flags);
@@ -275,16 +294,20 @@ int
DMAbuf_release (int dev, int mode)
{
- if (!(PROCESS_ABORTING || dmabuf_interrupted[dev])
+ if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev])
&& (dma_mode[dev] == DMODE_OUTPUT))
{
dma_sync (dev);
}
- dma_reset (dev);
+#ifdef USE_RUNTIME_DMAMEM
+ sound_dma_free (dev);
+#endif
- if (!dev_active[dev])
- dsp_devs[dev]->close (dev);
+ dsp_devs[dev]->reset (dev);
+
+ dsp_devs[dev]->close (dev);
dma_mode[dev] = DMODE_NONE;
dev_busy[dev] = 0;
@@ -296,40 +319,65 @@ int
DMAbuf_getrdbuffer (int dev, char **buf, int *len)
{
unsigned long flags;
+ int err = EIO;
- if (!bufferalloc_done[dev])
- reorganize_buffers (dev);
-
- if (!dma_mode[dev])
+ DISABLE_INTR (flags);
+ if (!dev_qlen[dev])
{
- int err;
+ if (dev_needs_restart[dev])
+ {
+ dma_reset (dev);
+ dev_needs_restart[dev] = 0;
+ }
- if ((err = dsp_devs[dev]->prepare_for_input (dev,
- dev_buffsize[dev], dev_nbufs[dev])) < 0)
- return err;
- dma_mode[dev] = DMODE_INPUT;
- }
+ if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */
+ {
+ dma_sync (dev);
+ dma_reset (dev);
+ dma_mode[dev] = DMODE_NONE;
+ }
- if (dma_mode[dev] != DMODE_INPUT)
- return RET_ERROR (EBUSY); /* Can't change mode on fly */
+ if (!bufferalloc_done[dev])
+ reorganize_buffers (dev);
+
+ if (!dma_mode[dev])
+ {
+ int err;
+
+ if ((err = dsp_devs[dev]->prepare_for_input (dev,
+ dev_buffsize[dev], dev_nbufs[dev])) < 0)
+ {
+ RESTORE_INTR (flags);
+ return err;
+ }
+ dma_mode[dev] = DMODE_INPUT;
+ }
- DISABLE_INTR (flags);
- if (!dev_qlen[dev])
- {
if (!dev_active[dev])
{
- dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], dev_buffsize[dev], 0);
+ 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;
}
/* Wait for the next block */
- REQUEST_TIMEOUT (10 * HZ, dev_sleeper[dev]);
- INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
+ 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;
+ SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ }
+ else
+ err = EINTR;
}
RESTORE_INTR (flags);
if (!dev_qlen[dev])
- return RET_ERROR (EINTR);
+ 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]];
@@ -391,6 +439,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
case SNDCTL_DSP_SYNC:
dma_sync (dev);
+ dma_reset (dev);
return 0;
break;
@@ -401,10 +450,37 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
return IOCTL_OUT (arg, dev_buffsize[dev]);
break;
+ case SNDCTL_DSP_SUBDIVIDE:
+ {
+ int fact = IOCTL_IN (arg);
+
+ if (fact == 0)
+ {
+ fact = dev_subdivision[dev];
+ if (fact == 0)
+ fact = 1;
+ return IOCTL_OUT (arg, fact);
+ }
+
+ if (dev_subdivision[dev] != 0) /* Too late to change */
+ return RET_ERROR (EINVAL);
+
+ if (fact > MAX_REALTIME_FACTOR)
+ return RET_ERROR (EINVAL);
+
+ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+ return RET_ERROR (EINVAL);
+
+ dev_subdivision[dev] = fact;
+ return IOCTL_OUT (arg, fact);
+ }
+ break;
+
default:
return dsp_devs[dev]->ioctl (dev, cmd, arg, local);
}
+ /* NOTREACHED */
return RET_ERROR (EIO);
}
@@ -412,6 +488,20 @@ int
DMAbuf_getwrbuffer (int dev, char **buf, int *size)
{
unsigned long flags;
+ int err = EIO;
+
+ if (dma_mode[dev] == DMODE_INPUT) /* Was input -> Direction change */
+ {
+ dma_reset (dev);
+ dma_mode[dev] = DMODE_NONE;
+ }
+ else if (dev_needs_restart[dev]) /* Restart buffering */
+ {
+ dma_sync (dev);
+ dma_reset (dev);
+ }
+
+ dev_needs_restart[dev] = 0;
if (!bufferalloc_done[dev])
reorganize_buffers (dev);
@@ -426,10 +516,11 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size)
return err;
}
- if (dma_mode[dev] != DMODE_OUTPUT)
- return RET_ERROR (EBUSY); /* Can't change mode on fly */
DISABLE_INTR (flags);
+
+ RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
+
if (dev_qlen[dev] == dev_nbufs[dev])
{
if (!dev_active[dev])
@@ -440,14 +531,20 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size)
}
/* Wait for free space */
- REQUEST_TIMEOUT (60 * HZ, dev_sleeper[dev]); /* GUS requires up to 60
- * sec */
- INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
+ 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;
+ SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ }
+ else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ err = EINTR;
}
RESTORE_INTR (flags);
if (dev_qlen[dev] == dev_nbufs[dev])
- return RET_ERROR (EIO); /* We have got signal (?) */
+ return RET_ERROR (err); /* We have got signal (?) */
*buf = dev_buf[dev][dev_qtail[dev]];
*size = dev_buffsize[dev];
@@ -466,12 +563,18 @@ DMAbuf_start_output (int dev, int buff_no, int l)
dev_counts[dev][dev_qtail[dev]] = l;
+ dev_needs_restart[dev] = (l != dev_buffsize[dev]) &&
+ (sound_dma_automode[dev] || dsp_devs[dev]->flags & NEEDS_RESTART);
+
dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
if (!dev_active[dev])
{
dev_active[dev] = 1;
- dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], dev_counts[dev][dev_qhead[dev]], 0);
+ dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
+ dev_counts[dev][dev_qhead[dev]], 0,
+ !sound_dma_automode[dev] || !dev_started[dev]);
+ dev_started[dev] = 1;
}
return 0;
@@ -504,27 +607,33 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
set_dma_count (chan, sound_buffsizes[dev]);
enable_dma (chan);
RESTORE_INTR (flags);
-#else
+#else /* linux */
#ifdef __386BSD__
printk ("sound: Invalid DMA mode for device %d\n", dev);
isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
(caddr_t)snd_raw_buf_phys[dev][0],
- (unsigned)sound_buffsizes[dev],
- (unsigned)chan);
-#else
-#ifdef ISC
+ sound_buffsizes[dev],
+ chan);
+#else /* __386BSD__ */
+#if defined(ISC) || defined(SCO) || defined(SVR42)
+#ifndef DMAMODE_AUTO
printk ("sound: Invalid DMA mode for device %d\n", dev);
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) | DMAMODE_AUTO,
- snd_raw_buf_phys[dev][0], count - 1);
+#endif /* DMAMODE_AUTO */
+ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
+#ifdef DMAMODE_AUTO
+ | DMAMODE_AUTO
+#endif /* DMAMODE_AUTO */
+ ,
+ snd_raw_buf_phys[dev][0], count);
dma_enable (chan);
-#else
-# error This routine is not valid for this OS.
-#endif
-#endif
+#else /* SYSV */
+#error This routine is not valid for this OS.
+#endif /* SYSV */
+#endif /* __386BSD__ */
-#endif
+#endif /* linux */
}
else
{
@@ -537,24 +646,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
+#else /* linux */
#ifdef __386BSD__
isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
(caddr_t)physaddr,
count,
chan);
-#else
+#else /* __386BSD__ */
-#ifdef ISC
+#if defined(ISC) || defined(SCO) || defined(SVR42)
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
- physaddr, count - 1);
+ physaddr, count);
dma_enable (chan);
-#else
-# error This routine is not valid for this OS.
-#endif /* !ISC */
-#endif
+#else /* SYSV */
+#error This routine is not valid for this OS.
+#endif /* SYSV */
+#endif /* __386BSD__ */
-#endif
+#endif /* linux */
}
return count;
@@ -584,37 +693,33 @@ DMAbuf_init (long mem_start)
}
void
-DMAbuf_outputintr (int dev)
+DMAbuf_outputintr (int dev, int underrun_flag)
{
unsigned long flags;
- dev_active[dev] = 0;
dev_qlen[dev]--;
dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
+ dev_active[dev] = 0;
if (dev_qlen[dev])
{
- dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], dev_counts[dev][dev_qhead[dev]], 1);
+ 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
+ else if (underrun_flag)
{
- if (dev_busy[dev])
- {
- dev_underrun[dev]++;
- dsp_devs[dev]->halt_xfer (dev);
- }
- else
- { /* Device has been closed */
- dsp_devs[dev]->close (dev);
- }
+ dev_underrun[dev]++;
+ dsp_devs[dev]->halt_xfer (dev);
+ dev_needs_restart[dev] = (sound_dma_automode[dev] ||
+ dsp_devs[dev]->flags & NEEDS_RESTART);
}
DISABLE_INTR (flags);
- if (dev_sleep_flag[dev])
+ if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
{
- dev_sleep_flag[dev] = 0;
- WAKE_UP (dev_sleeper[dev]);
+ WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
}
RESTORE_INTR (flags);
}
@@ -624,30 +729,33 @@ DMAbuf_inputintr (int dev)
{
unsigned long flags;
- dev_active[dev] = 0;
if (!dev_busy[dev])
{
dsp_devs[dev]->close (dev);
}
else if (dev_qlen[dev] == (dev_nbufs[dev] - 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];
}
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);
+ 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;
}
DISABLE_INTR (flags);
- if (dev_sleep_flag[dev])
+ if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
{
- dev_sleep_flag[dev] = 0;
- WAKE_UP (dev_sleeper[dev]);
+ WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
}
RESTORE_INTR (flags);
}
@@ -691,13 +799,13 @@ DMAbuf_reset_dma (int chan)
/*
* The sound_mem_init() is called by mem_init() immediately after mem_map is
* initialized and before free_page_list is created.
- *
+ *
* This routine allocates DMA buffers at the end of available physical memory (
* <16M) and marks pages reserved at mem_map.
*/
#else
-/* Stub versions if audio services not included */
+/* Stub versions if audio services not included */
int
DMAbuf_open (int dev, int mode)
@@ -784,7 +892,7 @@ DMAbuf_inputintr (int dev)
}
void
-DMAbuf_outputintr (int dev)
+DMAbuf_outputintr (int dev, int underrun_flag)
{
return;
}
diff --git a/sys/i386/isa/sound/dsp.c b/sys/i386/isa/sound/dsp.c
deleted file mode 100644
index fca931afab3e..000000000000
--- a/sys/i386/isa/sound/dsp.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * linux/kernel/chr_drv/sound/dsp.c
- *
- * Device file manager for /dev/dsp
- *
- * 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"
-
-#ifdef CONFIGURE_SOUNDCARD
-
-#ifndef EXCLUDE_AUDIO
-
-#define ON 1
-#define OFF 0
-
-static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a
- * incomplete output block */
-static int wr_buff_size[MAX_DSP_DEV], wr_buf_ptr[MAX_DSP_DEV];
-static char *wr_dma_buf[MAX_DSP_DEV];
-
-int
-dsp_open (int dev, struct fileinfo *file, int bits)
-{
- int mode;
- int ret;
-
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
-
- if ((ret = DMAbuf_open (dev, mode)) < 0)
- return ret;
-
- if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
- {
- dsp_release (dev, file);
- return RET_ERROR (ENXIO);
- }
-
- wr_buff_no[dev] = -1;
-
- return ret;
-}
-
-void
-dsp_release (int dev, struct fileinfo *file)
-{
- int mode;
-
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
-
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
-
- DMAbuf_release (dev, mode);
-}
-
-
-int
-dsp_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- int c, p, l;
- int err;
-
- dev = dev >> 4;
-
- p = 0;
- c = count;
-
- if (!count) /* Flush output */
- {
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return 0;
- }
-
- while (c)
- { /* 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];
- wr_buf_ptr[dev] = 0;
- }
-
- l = c;
- if (l > (wr_buff_size[dev] - wr_buf_ptr[dev]))
- l = (wr_buff_size[dev] - wr_buf_ptr[dev]);
-
- if (!dsp_devs[dev]->copy_from_user)
- { /* No device specific copy routine */
- COPY_FROM_USER (&wr_dma_buf[dev][wr_buf_ptr[dev]], buf, p, l);
- }
- else
- dsp_devs[dev]->copy_from_user (dev,
- wr_dma_buf[dev], wr_buf_ptr[dev], buf, p, l);
-
- c -= l;
- p += l;
- wr_buf_ptr[dev] += l;
-
- if (wr_buf_ptr[dev] >= wr_buff_size[dev])
- {
- if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev])) < 0)
- return err;
-
- wr_buff_no[dev] = -1;
- }
-
- }
-
- return count;
-}
-
-
-int
-dsp_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- int c, p, l;
- char *dmabuf;
- int buff_no;
-
- dev = dev >> 4;
- p = 0;
- c = count;
-
- while (c)
- {
- if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
- return buff_no;
-
- if (l > c)
- l = c;
-
- /* Insert any local processing here. */
-
- COPY_TO_USER (buf, 0, dmabuf, l);
-
- DMAbuf_rmchars (dev, buff_no, l);
-
- p += l;
- c -= l;
- }
-
- return count - c;
-}
-
-int
-dsp_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
-{
-
- dev = dev >> 4;
-
- switch (cmd)
- {
- case SNDCTL_DSP_SYNC:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
-
- case SNDCTL_DSP_POST:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return 0;
- break;
-
- case SNDCTL_DSP_RESET:
- wr_buff_no[dev] = -1;
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
-
- default:
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- }
-}
-
-long
-dsp_init (long mem_start)
-{
- return mem_start;
-}
-
-#else
-/* Stub version */
-int
-dsp_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- return RET_ERROR (EIO);
-}
-
-int
-dsp_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- return RET_ERROR (EIO);
-}
-
-int
-dsp_open (int dev, struct fileinfo *file, int bits)
-{
- return RET_ERROR (ENXIO);
-}
-
-void
-dsp_release (int dev, struct fileinfo *file)
- {
- };
-int
-dsp_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
-{
- return RET_ERROR (EIO);
-}
-
-int
-dsp_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
-{
- return RET_ERROR (EIO);
-}
-
-long
-dsp_init (long mem_start)
-{
- return mem_start;
-}
-
-#endif
-
-#endif
diff --git a/sys/i386/isa/sound/gus_card.c b/sys/i386/isa/sound/gus_card.c
index 414034deef6f..c7cfc0a7ab6c 100644
--- a/sys/i386/isa/sound/gus_card.c
+++ b/sys/i386/isa/sound/gus_card.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/gus_card.c
- *
+ * sound/gus_card.c
+ *
* Detection routine for the Gravis Ultrasound.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -37,76 +37,12 @@ void gusintr (int);
int gus_base, gus_irq, gus_dma;
-static int
-set_gus_irq (int interrupt_level)
-{
- int retcode = EINVAL;
-
-#ifdef linux
- struct sigaction sa;
-
- sa.sa_handler = gusintr;
-
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
-
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
-
- retcode = irqaction (interrupt_level, &sa);
-
- if (retcode < 0)
- {
- printk ("GUS: IRQ%d already in use\n", interrupt_level);
- }
-
-#else
- /* # error Unimplemented for this OS */
-#endif
- return retcode;
-}
-
-int
-gus_set_midi_irq (int interrupt_level)
-{
- int retcode = EINVAL;
-
-#ifdef linux
- struct sigaction sa;
-
- sa.sa_handler = gus_midi_interrupt;
-
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
-
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
-
- retcode = irqaction (interrupt_level, &sa);
-
- if (retcode < 0)
- {
- printk ("GUS: IRQ%d already in use\n", interrupt_level);
- }
-
-#else
- /* # error Unimplemented for this OS */
-#endif
- return retcode;
-}
-
long
attach_gus_card (long mem_start, struct address_info *hw_config)
{
int io_addr;
- set_gus_irq (hw_config->irq);
+ snd_set_irq_handler (hw_config->irq, gusintr);
if (gus_wave_detect (hw_config->io_base)) /* Try first the default */
{
@@ -127,7 +63,7 @@ attach_gus_card (long mem_start, struct address_info *hw_config)
if (io_addr != hw_config->io_base) /* Already tested */
if (gus_wave_detect (io_addr))
{
- printk (" WARNING! GUS found at %03x, config was %03x ", io_addr, hw_config->io_base);
+ 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);
@@ -168,7 +104,10 @@ void
gusintr (int unit)
{
unsigned char src;
- unsigned long flags;
+
+#ifdef linux
+ sti ();
+#endif
while (1)
{
@@ -195,9 +134,7 @@ gusintr (int unit)
if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
{
- DISABLE_INTR (flags);
gus_voice_irq ();
- RESTORE_INTR (flags);
}
}
}
diff --git a/sys/i386/isa/sound/gus_hw.h b/sys/i386/isa/sound/gus_hw.h
index 48233e7e1e32..f97a0b8670e3 100644
--- a/sys/i386/isa/sound/gus_hw.h
+++ b/sys/i386/isa/sound/gus_hw.h
@@ -24,6 +24,8 @@
#define u_Command (gus_base + 0x103)
#define u_DataLo (gus_base + 0x104)
#define u_DataHi (gus_base + 0x105)
+#define u_MixData (gus_base + 0x106) /* Rev. 3.7+ mixing */
+#define u_MixSelect (gus_base + 0x506) /* registers. */
#define u_IrqStatus u_Status
# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */
# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */
@@ -32,4 +34,17 @@
# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */
# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */
# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */
+
+#define ICS2101 1
+# define ICS_MIXDEVS 6
+# define DEV_MIC 0
+# define DEV_LINE 1
+# define DEV_CD 2
+# define DEV_GF1 3
+# define DEV_UNUSED 4
+# define DEV_VOL 5
+
+# define CHN_LEFT 0
+# define CHN_RIGHT 1
+#define CS4231 2
#define u_DRAMIO (gus_base + 0x107)
diff --git a/sys/i386/isa/sound/gus_linearvol.h b/sys/i386/isa/sound/gus_linearvol.h
new file mode 100644
index 000000000000..7ad0c30d4fd9
--- /dev/null
+++ b/sys/i386/isa/sound/gus_linearvol.h
@@ -0,0 +1,18 @@
+static unsigned short gus_linearvol[128] = {
+ 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
+ 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
+ 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
+ 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
+ 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
+ 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
+ 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
+ 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
+ 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
+ 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
+ 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
+ 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
+ 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
+ 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
+ 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
+ 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
+};
diff --git a/sys/i386/isa/sound/gus_midi.c b/sys/i386/isa/sound/gus_midi.c
index b5cd6844cd1d..935c5c90b324 100644
--- a/sys/i386/isa/sound/gus_midi.c
+++ b/sys/i386/isa/sound/gus_midi.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/gus2_midi.c
- *
+ * sound/gus2_midi.c
+ *
* The low level driver for the GUS Midi Interface.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -215,7 +215,7 @@ gus_midi_buffer_status (int dev)
static struct midi_operations gus_midi_operations =
{
- {"Gravis UltraSound", 0},
+ {"Gravis UltraSound", 0, 0, SNDCARD_GUS},
gus_midi_open,
gus_midi_close,
gus_midi_ioctl,
diff --git a/sys/i386/isa/sound/gus_vol.c b/sys/i386/isa/sound/gus_vol.c
index b3f1e84060ad..055a1170e9fb 100644
--- a/sys/i386/isa/sound/gus_vol.c
+++ b/sys/i386/isa/sound/gus_vol.c
@@ -1,10 +1,11 @@
/*
* gus_vol.c - Compute volume for GUS.
- *
+ *
* Greg Lee 1993.
*/
#include "sound_config.h"
#ifndef EXCLUDE_GUS
+#include "gus_linearvol.h"
#define GUS_VOLUME gus_wave_volume
@@ -20,7 +21,7 @@ extern int gus_wave_volume;
* to expression controller messages, if they were found to be used for
* dynamic volume adjustments, so here, main volume can be assumed to be
* constant throughout a song.)
- *
+ *
* Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
* we can give a big boost to very weak voices like nylon guitar and the
* basses. The normal value is 64. Strings are assigned lower values.
@@ -38,24 +39,37 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
*/
x = 256 + 6 * (voicev - 64);
- /* Boost expression by voice volume above neutral. */
+ /*
+ * Boost expression by voice volume above neutral.
+ */
if (voicev > 65)
xpn += voicev - 64;
xpn += (voicev - 64) / 2;
- /* Combine multiplicative and level components. */
+ /*
+ * Combine multiplicative and level components.
+ */
x = vel * xpn * 6 + (voicev / 4) * x;
#ifdef GUS_VOLUME
/*
* Further adjustment by installation-specific master volume control
- * (default 50).
+ * (default 60).
*/
x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
#endif
- if (x < (1 << 11))
- return (11 << 8);
+#ifdef GUS_USE_CHN_MAIN_VOLUME
+ /*
+ * Experimental support for the channel main volume
+ */
+
+ mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
+ x = (x * mainv * mainv) / 16384;
+#endif
+
+ if (x < 2)
+ return (0);
else if (x >= 65535)
return ((15 << 8) | 255);
@@ -82,7 +96,9 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
*/
m = x - (1 << i);
- /* Adjust mantissa to 8 bits. */
+ /*
+ * Adjust mantissa to 8 bits.
+ */
if (m > 0)
{
if (i > 8)
@@ -91,11 +107,41 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
m <<= 8 - i;
}
- /* low volumes give occasional sour notes */
- if (i < 11)
- return (11 << 8);
-
return ((i << 8) + m);
}
+/*
+ * Volume-values are interpreted as linear values. Volume is based on the
+ * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
+ * and the volume set by the mixer-device (default 60%).
+ */
+
+unsigned short
+gus_linear_vol (int vol, int mainvol)
+{
+ int mixer_mainvol;
+
+ if (vol <= 0)
+ vol = 0;
+ else if (vol >= 127)
+ vol = 127;
+
+#ifdef GUS_VOLUME
+ mixer_mainvol = GUS_VOLUME;
+#else
+ mixer_mainvol = 100;
+#endif
+
+#ifdef GUS_USE_CHN_MAIN_VOLUME
+ if (mainvol <= 0)
+ mainvol = 0;
+ else if (mainvol >= 127)
+ mainvol = 127;
+#else
+ mainvol = 128;
+#endif
+
+ return gus_linearvol[(((vol * mainvol) / 128) * mixer_mainvol) / 100];
+}
+
#endif
diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c
index deb3a1525991..9f6442e0fcff 100644
--- a/sys/i386/isa/sound/gus_wave.c
+++ b/sys/i386/isa/sound/gus_wave.c
@@ -1,11 +1,10 @@
-
/*
- * linux/kernel/chr_drv/sound/gus_wave.c
- *
+ * sound/gus_wave.c
+ *
* Driver for the Gravis UltraSound wave table synth.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -13,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -25,18 +24,20 @@
* 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 GUS_LINEAR_VOLUME */
-
#include "sound_config.h"
+#ifdef __FreeBSD__
#include <machine/ultrasound.h>
+#else
+#include "ultrasound.h"
+#endif
#include "gus_hw.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
-#define MAX_SAMPLE 256
+#define MAX_SAMPLE 128
#define MAX_PATCH 256
struct voice_info
@@ -57,6 +58,7 @@ struct voice_info
int volume_irq_mode, volume_irq_parm;
#define VMODE_HALT 1
#define VMODE_ENVELOPE 2
+#define VMODE_START_NOTE 3
int env_phase;
unsigned char env_rate[6];
@@ -67,6 +69,11 @@ struct voice_info
*/
int main_vol, expression_vol, patch_vol;
+ /* Variables for "Ultraclick" removal */
+ int dev_pending, note_pending, volume_pending, sample_pending;
+ char kill_pending;
+ long offset_pending;
+
};
extern int gus_base;
@@ -77,24 +84,30 @@ 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; /* Number of currently allowed voices */
+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;
-#define VOL_METHOD_ADAGIO 1
-int gus_wave_volume = 60; /* Master wolume for wave (0 to 100) */
+int gus_wave_volume = 60;
+int gus_pcm_volume = 80;
static unsigned char mix_image = 0x00;
/*
- * Current version of this_one driver doesn't allow synth and PCM functions
+ * Current version of this driver doesn't allow synth and PCM functions
* at the same time. The active_device specifies the active driver
*/
static int active_device = 0;
-#define GUS_DEV_WAVE 1 /* Wave table synth */
-#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */
-#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer the second
- * chn */
+#define GUS_DEV_WAVE 1 /*
+ * * * Wave table synth */
+#define GUS_DEV_PCM_DONE 2 /*
+ * * * PCM device, transfer done */
+#define GUS_DEV_PCM_CONTINUE 3 /*
+ * * * PCM device, transfer the
+ * second * * * chn */
static int gus_sampling_speed;
static int gus_sampling_channels;
@@ -105,13 +118,34 @@ DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
/*
* Variables and buffers for PCM output
*/
-#define MAX_PCM_BUFFERS 32 /* 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]; /* Actual # of bytes in blk */
-static volatile int pcm_head, pcm_tail, pcm_qlen; /* DRAM queue */
+#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]; /*
+
+
+ * * * * Actual # of bytes
+ * in blk * */
+static volatile int pcm_head, pcm_tail, pcm_qlen; /*
+
+
+ * * * * DRAM queue
+ * */
static volatile int pcm_active;
+static int pcm_opened = 0;
static int pcm_current_dev;
static int pcm_current_block;
static unsigned long pcm_current_buf;
@@ -122,28 +156,66 @@ 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[MAX_SAMPLE + 1];
+static struct patch_info *samples;
static long sample_ptrs[MAX_SAMPLE + 1];
static int sample_map[32];
static int free_sample;
@@ -158,10 +230,15 @@ static struct synth_info gus_info =
static void gus_poke (long addr, unsigned char data);
static void compute_and_set_volume (int voice, int volume, int ramp_time);
extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
+extern unsigned short gus_linear_vol (int vol, int mainvol);
static void compute_volume (int voice, int volume);
+static void do_volume_irq (int voice);
+static void set_input_volumes (void);
-#define INSTANT_RAMP -1 /* Dont use ramping */
-#define FAST_RAMP 0 /* Fastest possible ramp */
+#define INSTANT_RAMP -1 /*
+ * * * Dont use ramping */
+#define FAST_RAMP 0 /*
+ * * * Fastest possible ramp */
static void
reset_sample_memory (void)
@@ -175,7 +252,9 @@ 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 silence here
+ */
gus_poke (1, 0);
free_mem_ptr = 2;
@@ -230,14 +309,14 @@ gus_peek (long addr)
}
void
-gus_write8 (int reg, unsigned char data)
+gus_write8 (int reg, unsigned int data)
{
unsigned long flags;
DISABLE_INTR (flags);
OUTB (reg, u_Command);
- OUTB (data, u_DataHi);
+ OUTB ((unsigned char) (data & 0xff), u_DataHi);
RESTORE_INTR (flags);
}
@@ -271,7 +350,7 @@ gus_look8 (int reg)
}
void
-gus_write16 (int reg, unsigned short data)
+gus_write16 (int reg, unsigned int data)
{
unsigned long flags;
@@ -279,8 +358,8 @@ gus_write16 (int reg, unsigned short data)
OUTB (reg, u_Command);
- OUTB (data & 0xff, u_DataLo);
- OUTB ((data >> 8) & 0xff, u_DataHi);
+ OUTB ((unsigned char) (data & 0xff), u_DataLo);
+ OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
RESTORE_INTR (flags);
}
@@ -322,6 +401,10 @@ gus_write_addr (int reg, unsigned long address, int is16bit)
gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
+ /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
+ gus_delay ();
+ gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
+ gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
}
static void
@@ -347,11 +430,11 @@ gus_select_max_voices (int nvoices)
}
static void
-gus_voice_on (unsigned char mode)
+gus_voice_on (unsigned int mode)
{
- gus_write8 (0x00, mode & 0xfc);
+ gus_write8 (0x00, (unsigned char) (mode & 0xfc));
gus_delay ();
- gus_write8 (0x00, mode & 0xfc);
+ gus_write8 (0x00, (unsigned char) (mode & 0xfc));
}
static void
@@ -361,10 +444,18 @@ gus_voice_off (void)
}
static void
-gus_voice_mode (unsigned char mode)
-{
- gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* Don't start or stop
- * voice */
+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_delay ();
gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
}
@@ -382,44 +473,56 @@ gus_voice_freq (unsigned long freq)
}
static void
-gus_voice_volume (unsigned short vol)
+gus_voice_volume (unsigned int vol)
{
- gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */
- gus_write16 (0x09, vol << 4);
+ gus_write8 (0x0d, 0x03); /*
+ * Stop ramp before setting volume
+ */
+ gus_write16 (0x09, (unsigned short) (vol << 4));
}
static void
-gus_voice_balance (unsigned char balance)
+gus_voice_balance (unsigned int balance)
{
- gus_write8 (0x0c, balance);
+ gus_write8 (0x0c, (unsigned char) (balance & 0xff));
}
static void
-gus_ramp_range (unsigned short low, unsigned short high)
+gus_ramp_range (unsigned int low, unsigned int high)
{
- gus_write8 (0x07, (low >> 4) & 0xff);
- gus_write8 (0x08, (high >> 4) & 0xff);
+ gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff));
+ gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff));
}
static void
-gus_ramp_rate (unsigned char scale, unsigned char rate)
+gus_ramp_rate (unsigned int scale, unsigned int rate)
{
- gus_write8 (0x06, ((scale & 0x03) << 6) | (rate & 0x3f));
+ gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
}
static void
-gus_rampon (unsigned char mode)
+gus_rampon (unsigned int m)
{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
gus_write8 (0x0d, mode & 0xfc);
gus_delay ();
gus_write8 (0x0d, mode & 0xfc);
}
static void
-gus_ramp_mode (unsigned char mode)
-{
- gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* Don't start or stop
- * ramping */
+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_delay ();
gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
}
@@ -431,6 +534,20 @@ gus_rampoff (void)
}
static void
+gus_set_voice_pos (int voice, long position)
+{
+ int sample_no;
+
+ if ((sample_no = sample_map[voice]) != -1)
+ if (position < samples[sample_no].len)
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].offset_pending = position;
+ else
+ gus_write_addr (0x0a, sample_ptrs[sample_no] + position,
+ samples[sample_no].mode & WAVE_16_BITS);
+}
+
+static void
gus_voice_init (int voice)
{
unsigned long flags;
@@ -438,11 +555,22 @@ 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
+ */
RESTORE_INTR (flags);
+}
+
+static void
+gus_voice_init2 (int voice)
+{
voices[voice].panning = 0;
voices[voice].mode = 0;
voices[voice].orig_freq = 20000;
@@ -459,6 +587,7 @@ gus_voice_init (int voice)
voices[voice].main_vol = 127;
voices[voice].patch_vol = 127;
voices[voice].expression_vol = 127;
+ voices[voice].sample_pending = -1;
}
static void
@@ -466,11 +595,17 @@ step_envelope (int voice)
{
unsigned vol, prev_vol, phase;
unsigned char rate;
+ long int flags;
if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
{
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
gus_rampoff ();
- return; /* Sustain */
+ RESTORE_INTR (flags);
+ return; /*
+ * Sustain
+ */
}
if (voices[voice].env_phase >= 5)
@@ -484,20 +619,31 @@ step_envelope (int voice)
}
prev_vol = voices[voice].current_volume;
- gus_voice_volume (prev_vol);
phase = ++voices[voice].env_phase;
-
compute_volume (voice, voices[voice].midi_volume);
-
vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
rate = voices[voice].env_rate[phase];
- gus_write8 (0x06, rate); /* Ramping rate */
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+
+ gus_voice_volume (prev_vol);
+
+
+ gus_write8 (0x06, rate); /*
+ * Ramping rate
+ */
voices[voice].volume_irq_mode = VMODE_ENVELOPE;
- if (((vol - prev_vol) / 64) == 0) /* No significant volume change */
+ if (((vol - prev_vol) / 64) == 0) /*
+ * No significant volume change
+ */
{
- step_envelope (voice); /* Continue with the next phase */
+ RESTORE_INTR (flags);
+ step_envelope (voice); /*
+ * Continue with the next phase
+ */
return;
}
@@ -506,16 +652,21 @@ 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, irq
+ */
}
else
{
if (vol <= 64)
vol = 65;
- gus_ramp_range (vol, 4095);
- gus_rampon (0x60); /* Decreasing, irq */
+ gus_ramp_range (vol, 4030);
+ gus_rampon (0x60); /*
+ * Decreasing, irq
+ */
}
voices[voice].current_volume = vol;
+ RESTORE_INTR (flags);
}
static void
@@ -528,19 +679,26 @@ init_envelope (int voice)
}
static void
-start_release (int voice)
+start_release (int voice, long int flags)
{
if (gus_read8 (0x00) & 0x03)
- return; /* Voice already stopped */
+ return; /*
+ * Voice already stopped
+ */
- voices[voice].env_phase = 2; /* Will be incremented by step_envelope */
+ voices[voice].env_phase = 2; /*
+ * Will be incremented by step_envelope
+ */
voices[voice].current_volume =
voices[voice].initial_volume =
- gus_read16 (0x09) >> 4; /* Get current volume */
+ gus_read16 (0x09) >> 4; /*
+ * Get current volume
+ */
voices[voice].mode &= ~WAVE_SUSTAIN_ON;
gus_rampoff ();
+ RESTORE_INTR (flags);
step_envelope (voice);
}
@@ -548,25 +706,38 @@ static void
gus_voice_fade (int voice)
{
int instr_no = sample_map[voice], is16bits;
+ long int flags;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
if (instr_no < 0 || instr_no > MAX_SAMPLE)
{
- gus_write8 (0x00, 0x03); /* Hard stop */
+ gus_write8 (0x00, 0x03); /*
+ * Hard stop
+ */
+ RESTORE_INTR (flags);
return;
}
- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */
+ is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /*
+ * 8 or 16
+ * bit
+ * samples
+ */
if (voices[voice].mode & WAVE_ENVELOPES)
{
- start_release (voice);
+ start_release (voice, flags);
return;
}
/*
* Ramp the volume down but not too quickly.
*/
- if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */
+ if ((gus_read16 (0x09) >> 4) < 100) /*
+ * Get current volume
+ */
{
gus_voice_off ();
gus_rampoff ();
@@ -574,10 +745,13 @@ gus_voice_fade (int voice)
return;
}
- gus_ramp_range (65, 4095);
+ gus_ramp_range (65, 4030);
gus_ramp_rate (2, 4);
- gus_rampon (0x40 | 0x20); /* Down, once, irq */
+ gus_rampon (0x40 | 0x20); /*
+ * Down, once, irq
+ */
voices[voice].volume_irq_mode = VMODE_HALT;
+ RESTORE_INTR (flags);
}
static void
@@ -592,14 +766,25 @@ 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
+ */
}
@@ -607,7 +792,7 @@ static void
gus_initialize (void)
{
unsigned long flags;
- unsigned char dma_image, irq_image, tmp;
+ register unsigned char dma_image, irq_image, tmp;
static unsigned char gus_irq_map[16] =
{0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
@@ -617,11 +802,15 @@ gus_initialize (void)
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 ();
@@ -629,25 +818,49 @@ 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 */
-
- 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_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 */
+ 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_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_write8 (0x4c, 7); /*
+ * Master reset | DAC enable | IRQ enable
+ */
/*
* Set up for Digital ASIC
@@ -655,7 +868,9 @@ 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);
@@ -664,12 +879,9 @@ gus_initialize (void)
/*
* Now set up the DMA and IRQ interface
- *
+ *
* The GUS supports two IRQs and two DMAs.
- *
- * If GUS_MIDI_IRQ is defined and if it's != GUS_IRQ, separate Midi IRQ is set
- * up. Otherwise the same IRQ is shared by the both devices.
- *
+ *
* Just one DMA channel is used. This prevents simultaneous ADC and DAC.
* Adding this support requires significant changes to the dmabuf.c, dsp.c
* and audio.c also.
@@ -680,23 +892,13 @@ gus_initialize (void)
if (!tmp)
printk ("Warning! GUS IRQ not selected\n");
irq_image |= tmp;
+ irq_image |= 0x40; /*
+ * Combine IRQ1 (GF1) and IRQ2 (Midi)
+ */
- if (GUS_MIDI_IRQ != gus_irq)
- { /* The midi irq was defined and != wave irq */
- tmp = gus_irq_map[GUS_MIDI_IRQ];
- tmp <<= 3;
-
- if (!tmp)
- printk ("Warning! GUS Midi IRQ not selected\n");
- else
- gus_set_midi_irq (GUS_MIDI_IRQ);
-
- irq_image |= tmp;
- }
- else
- 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");
@@ -706,37 +908,73 @@ gus_initialize (void)
* For some reason the IRQ and DMA addresses must be written twice
*/
- /* Doing it first time */
-
- 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 */
-
- /* Doing it second time */
-
- 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 */
+ /*
+ * Doing it first time
+ */
- gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
+ OUTB (mix_image, u_Mixer); /*
+ * Select DMA control
+ */
+ OUTB (dma_image | 0x80, u_IRQDMAControl); /*
+ * Set DMA address
+ */
- mix_image &= ~0x02; /* Enable line out */
- mix_image |= 0x08; /* Enable IRQ */
- OUTB (mix_image, u_Mixer); /* Turn mixer channels on */
+ 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 */
+ /*
+ * Doing it second time
+ */
- gusintr (0); /* Serve pending interrupts */
+ 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
+ */
+
+ gus_select_voice (0); /*
+ * This disables writes to IRQ/DMA reg
+ */
+
+ 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
+ */
+
+ gusintr (0); /*
+ * Serve pending interrupts
+ */
RESTORE_INTR (flags);
}
int
gus_wave_detect (int baseaddr)
{
+ unsigned long i;
+ unsigned long loc;
+
gus_base = baseaddr;
gus_write8 (0x4c, 0); /* Reset GF1 */
@@ -747,31 +985,37 @@ gus_wave_detect (int baseaddr)
gus_delay ();
gus_delay ();
- gus_poke (0x000, 0xaa);
- gus_poke (0x100, 0x55);
+ /* See if there is first block there.... */
+ gus_poke (0L, 0xaa);
+ if (gus_peek (0L) != 0xaa)
+ return (0);
- if (gus_peek (0x000) != 0xaa)
- return 0;
- if (gus_peek (0x100) != 0x55)
- return 0;
-
- gus_mem_size = 0x40000; /* 256k */
- gus_poke (0x40000, 0xaa);
- if (gus_peek (0x40000) != 0xaa)
- return 1;
+ /* Now zero it out so that I can check for mirroring .. */
+ gus_poke (0L, 0x00);
+ for (i = 1L; i < 1024L; i++)
+ {
+ int n, failed;
- gus_mem_size = 0x80000; /* 512k */
- gus_poke (0x80000, 0xaa);
- if (gus_peek (0x80000) != 0xaa)
- return 1;
+ /* check for mirroring ... */
+ if (gus_peek (0L) != 0)
+ break;
+ loc = i << 10;
- gus_mem_size = 0xc0000; /* 768k */
- gus_poke (0xc0000, 0xaa);
- if (gus_peek (0xc0000) != 0xaa)
- return 1;
+ for (n = loc - 1, failed = 0; n <= loc; n++)
+ {
+ gus_poke (loc, 0xaa);
+ if (gus_peek (loc) != 0xaa)
+ failed = 1;
- gus_mem_size = 0x100000; /* 1M */
+ gus_poke (loc, 0x55);
+ if (gus_peek (loc) != 0x55)
+ failed = 1;
+ }
+ if (failed)
+ break;
+ }
+ gus_mem_size = i << 10;
return 1;
}
@@ -816,16 +1060,26 @@ guswave_set_instr (int dev, int voice, int instr_no)
if (voice < 0 || voice > 31)
return RET_ERROR (EINVAL);
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ {
+ voices[voice].sample_pending = instr_no;
+ return 0;
+ }
+
sample_no = patch_table[instr_no];
patch_map[voice] = -1;
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);
return RET_ERROR (EINVAL);
@@ -837,14 +1091,25 @@ 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);
- gus_select_voice (voice);
- gus_voice_fade (voice);
- RESTORE_INTR (flags);
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ {
+ voices[voice].kill_pending = 1;
+ RESTORE_INTR (flags);
+ }
+ else
+ {
+ RESTORE_INTR (flags);
+ gus_voice_fade (voice);
+ }
return 0;
}
@@ -855,20 +1120,26 @@ guswave_aftertouch (int dev, int voice, int pressure)
short lo_limit, hi_limit;
unsigned long flags;
- return; /* Currently disabled */
+ return; /*
+ * Currently disabled
+ */
if (voice < 0 || voice > 31)
return;
if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
- return; /* Don't mix with envelopes */
+ return; /*
+ * Don't mix with envelopes
+ */
if (pressure < 32)
{
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;
}
@@ -887,7 +1158,9 @@ 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, Down, Loop
+ */
RESTORE_INTR (flags);
}
@@ -899,38 +1172,57 @@ guswave_panning (int dev, int voice, int value)
}
static void
+guswave_volume_method (int dev, int mode)
+{
+ if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
+ volume_method = mode;
+}
+
+static void
compute_volume (int voice, int volume)
{
if (volume < 128)
+ voices[voice].midi_volume = volume;
+
+ switch (volume_method)
{
- voices[voice].midi_volume = volume;
+ case VOL_METHOD_ADAGIO:
+ voices[voice].initial_volume =
+ gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
+ voices[voice].expression_vol,
+ voices[voice].patch_vol);
+ break;
- switch (volume_method)
- {
- case VOL_METHOD_ADAGIO:
- voices[voice].initial_volume =
- gus_adagio_vol (volume, voices[voice].main_vol,
- voices[voice].expression_vol,
- voices[voice].patch_vol);
- break;
+ case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */
+ voices[voice].initial_volume =
+ gus_linear_vol (volume, voices[voice].main_vol);
+ break;
- default:
- voices[voice].initial_volume = volume_base + (volume * volume_scale);
- }
+ default:
+ voices[voice].initial_volume = volume_base +
+ (voices[voice].midi_volume * volume_scale);
}
- if (voices[voice].initial_volume > 4095)
- voices[voice].initial_volume = 4095;
+ if (voices[voice].initial_volume > 4030)
+ voices[voice].initial_volume = 4030;
}
static void
compute_and_set_volume (int voice, int volume, int ramp_time)
{
int current, target, rate;
+ unsigned long flags;
compute_volume (voice, volume);
voices[voice].current_volume = voices[voice].initial_volume;
+ DISABLE_INTR (flags);
+ /*
+ * CAUTION! Interrupts disabled. Enable them before returning
+ */
+
+ gus_select_voice (voice);
+
current = gus_read16 (0x09) >> 4;
target = voices[voice].initial_volume;
@@ -938,6 +1230,7 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
{
gus_rampoff ();
gus_voice_volume (target);
+ RESTORE_INTR (flags);
return;
}
@@ -947,10 +1240,13 @@ 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) /*
+ * Too close
+ */
{
gus_rampoff ();
gus_voice_volume (target);
+ RESTORE_INTR (flags);
return;
}
@@ -959,7 +1255,9 @@ 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
{
@@ -967,8 +1265,11 @@ 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);
}
static void
@@ -979,11 +1280,15 @@ dynamic_volume_change (int voice)
DISABLE_INTR (flags);
gus_select_voice (voice);
- status = gus_read8 (0x00); /* Voice status */
+ status = gus_read8 (0x00); /*
+ * Voice status
+ */
RESTORE_INTR (flags);
if (status & 0x03)
- return; /* Voice not started */
+ return; /*
+ * Voice not started
+ */
if (!(voices[voice].mode & WAVE_ENVELOPES))
{
@@ -997,10 +1302,14 @@ 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;
@@ -1011,9 +1320,12 @@ dynamic_volume_change (int voice)
compute_volume (voice, voices[voice].midi_volume);
-#if 0 /* Is this really required */
+#if 0 /*
+ * * * Is this really required */
voices[voice].current_volume =
- gus_read16 (0x09) >> 4; /* Get current volume */
+ gus_read16 (0x09) >> 4; /*
+ * Get current volume
+ */
voices[voice].env_phase--;
step_envelope (voice);
@@ -1033,38 +1345,59 @@ guswave_controller (int dev, int voice, int ctrl_num, int value)
{
case CTRL_PITCH_BENDER:
voices[voice].bender = value;
- freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
- voices[voice].current_freq = freq;
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (freq);
- RESTORE_INTR (flags);
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ {
+ freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_freq (freq);
+ RESTORE_INTR (flags);
+ }
break;
case CTRL_PITCH_BENDER_RANGE:
voices[voice].bender_range = value;
break;
-
+#ifdef FUTURE_VERSION
+ case CTL_EXPRESSION:
+ value /= 128;
+#endif
case CTRL_EXPRESSION:
- volume_method = VOL_METHOD_ADAGIO;
- voices[voice].expression_vol = value;
- dynamic_volume_change (voice);
+ if (volume_method == VOL_METHOD_ADAGIO)
+ {
+ voices[voice].expression_vol = value;
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change (voice);
+ }
break;
+#ifdef FUTURE_VERSION
+ case CTL_PAN:
+ voices[voice].panning = (value * 2) - 128;
+ break;
+
+ case CTL_MAIN_VOLUME:
+ value = (value * 100) / 16383;
+#endif
+
case CTRL_MAIN_VOLUME:
- volume_method = VOL_METHOD_ADAGIO;
voices[voice].main_vol = value;
- dynamic_volume_change (voice);
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change (voice);
break;
- default: /* Ignore */
+ default: /*
+ * Ignore
+ */
break;
}
}
static int
-guswave_start_note (int dev, int voice, int note_num, int volume)
+guswave_start_note2 (int dev, int voice, int note_num, int volume)
{
int sample, best_sample, best_delta, delta_freq;
int is16bits, samplep, patch, pan;
@@ -1123,7 +1456,9 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
sample = samplep;
else
- samplep = samples[samplep].key; /* Follow link */
+ samplep = samples[samplep].key; /*
+ * Follow link
+ */
}
if (sample == -1)
sample = best_sample;
@@ -1131,10 +1466,16 @@ guswave_start_note (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; /*
+ * 8 or 16
+ * bit
+ * samples
+ */
voices[voice].mode = samples[sample].mode;
voices[voice].patch_vol = samples[sample].volume;
@@ -1151,7 +1492,9 @@ guswave_start_note (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; /*
+ * To avoid overflows
+ */
note_freq /= 100;
freq = samples[sample].base_freq * note_freq / base_note;
@@ -1175,20 +1518,27 @@ guswave_start_note (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");
}
/*************************************************************************
- * CAUTION! Interrupts disabled. Don't return before enabling
- *************************************************************************/
+ * CAUTION! Interrupts disabled. Don't return before enabling
+ *************************************************************************/
DISABLE_INTR (flags);
gus_select_voice (voice);
- gus_voice_off (); /* It may still be running */
+ gus_voice_off (); /*
+ * It may still be running
+ */
gus_rampoff ();
+
+ RESTORE_INTR (flags);
+
if (voices[voice].mode & WAVE_ENVELOPES)
{
compute_volume (voice, volume);
@@ -1197,36 +1547,66 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
else
compute_and_set_volume (voice, volume, 0);
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+
if (samples[sample].mode & WAVE_LOOP_BACK)
- gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len, is16bits); /* Sample start=end */
+ gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
+ voices[voice].offset_pending, is16bits); /* Sample
+ * start=end */
else
- gus_write_addr (0x0a, sample_ptrs[sample], is16bits); /* Sample start=begin */
+ 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; /*
+ * Looping on
+ */
if (samples[sample].mode & WAVE_BIDIR_LOOP)
- mode |= 0x10; /* Bidirectional looping on */
+ mode |= 0x10; /*
+ * Bidirectional looping on
+ */
if (samples[sample].mode & WAVE_LOOP_BACK)
{
- gus_write_addr (0x0a, /* Put the current location = loop_end */
- sample_ptrs[sample] + samples[sample].loop_end, is16bits);
- mode |= 0x40; /* Loop backwards */
+ gus_write_addr (0x0a,
+ sample_ptrs[sample] + samples[sample].loop_end -
+ voices[voice].offset_pending, is16bits);
+ 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 it 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, 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);
@@ -1236,13 +1616,81 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
return 0;
}
+/*
+ * * New guswave_start_note by Andrew J. Robinson attempts to minimize
+ * clicking * when the note playing on the voice is changed. It uses volume
+ * ramping. */
+
+static int
+guswave_start_note (int dev, int voice, int note_num, int volume)
+{
+ long int flags;
+ int mode;
+ int ret_val = 0;
+
+ DISABLE_INTR (flags);
+ if (note_num == 255)
+ {
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].volume_pending = volume;
+ else
+ {
+ RESTORE_INTR (flags);
+ ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+ }
+ }
+ else
+ {
+ gus_select_voice (voice);
+ mode = gus_read8 (0x00);
+ if (mode & 0x20)
+ gus_write8 (0x00, mode & 0xdf); /* No interrupt! */
+
+ voices[voice].offset_pending = 0;
+ voices[voice].kill_pending = 0;
+ voices[voice].volume_irq_mode = 0;
+ voices[voice].loop_irq_mode = 0;
+
+ if (voices[voice].sample_pending >= 0)
+ {
+ RESTORE_INTR (flags);
+ guswave_set_instr (voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ DISABLE_INTR (flags);
+ }
+
+ if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
+ {
+ ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+ }
+ else
+ {
+ voices[voice].dev_pending = dev;
+ voices[voice].note_pending = note_num;
+ voices[voice].volume_pending = volume;
+ voices[voice].volume_irq_mode = VMODE_START_NOTE;
+
+ gus_rampoff ();
+ gus_ramp_range (2000, 4065);
+ gus_ramp_rate (0, 63);/* Fastest possible rate */
+ gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
+ RESTORE_INTR (flags);
+ }
+ }
+ return ret_val;
+}
+
static void
guswave_reset (int dev)
{
int i;
for (i = 0; i < 32; i++)
- gus_voice_init (i);
+ {
+ gus_voice_init (i);
+ gus_voice_init2 (i);
+ }
}
static int
@@ -1253,9 +1701,12 @@ guswave_open (int dev, int mode)
if (gus_busy)
return RET_ERROR (EBUSY);
+ gus_initialize ();
+
if ((err = DMAbuf_open_dma (gus_devnum)))
return err;
+ RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
gus_busy = 1;
active_device = GUS_DEV_WAVE;
@@ -1280,22 +1731,29 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
{
struct patch_info patch;
int instr;
+ long sizeof_patch;
unsigned long blk_size, blk_end, left, src_offs, target;
+ sizeof_patch = (long) &patch.data[0] - (long) &patch; /*
+ * Size of
+ * the header
+ * * info
+ */
+
if (format != GUS_PATCH)
{
- printk ("GUS Error: Invalid patch format (key) 0x%04x\n", format);
+ printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
return RET_ERROR (EINVAL);
}
- if (count < sizeof (patch))
+ if (count < sizeof_patch)
{
printk ("GUS Error: Patch header too short\n");
return RET_ERROR (EINVAL);
}
- count -= sizeof (patch);
+ count -= sizeof_patch;
if (free_sample >= MAX_SAMPLE)
{
@@ -1308,7 +1766,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
* been transferred already.
*/
- COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof (patch) - offs);
+ COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs);
instr = patch.instr_no;
@@ -1321,13 +1779,13 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
if (count < patch.len)
{
printk ("GUS Warning: Patch record too short (%d<%d)\n",
- count, patch.len);
+ count, (int) patch.len);
patch.len = count;
}
if (patch.len <= 0 || patch.len > gus_mem_size)
{
- printk ("GUS: Invalid sample length %d\n", patch.len);
+ printk ("GUS: Invalid sample length %d\n", (int) patch.len);
return RET_ERROR (EINVAL);
}
@@ -1346,7 +1804,9 @@ 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; /*
+ * Alignment 32 bytes
+ */
#define GUS_BANK_SIZE (256*1024)
@@ -1357,20 +1817,24 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
*/
if (patch.len >= GUS_BANK_SIZE)
{
- printk ("GUS: Sample (16 bit) too long %d\n", patch.len);
+ printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
return RET_ERROR (ENOSPC);
}
if ((free_mem_ptr / GUS_BANK_SIZE) !=
((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
{
- unsigned long tmp_mem = /* Align to 256K*N */
+ unsigned long tmp_mem = /*
+ * Align to 256K*N
+ */
((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
if ((tmp_mem + patch.len) > gus_mem_size)
return RET_ERROR (ENOSPC);
- free_mem_ptr = tmp_mem; /* This leaves unusable memory */
+ free_mem_ptr = tmp_mem; /*
+ * This leaves unusable memory
+ */
}
}
@@ -1379,12 +1843,14 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
sample_ptrs[free_sample] = free_mem_ptr;
- /* Tremolo is not possible with envelopes */
+ /*
+ * Tremolo is not possible with envelopes
+ */
if (patch.mode & WAVE_ENVELOPES)
patch.mode &= ~WAVE_TREMOLO;
- memcpy ((char *) &samples[free_sample], &patch, sizeof (patch));
+ memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
/*
* Link this_one sample to the list of samples for patch 'instr'.
@@ -1401,7 +1867,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 all moved
+ */
{
blk_size = sound_buffsizes[gus_devnum];
if (blk_size > left)
@@ -1413,13 +1881,15 @@ 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 */
+ { /*
+ * Have to split the block
+ */
blk_end &= ~(256 * 1024 - 1);
blk_size = blk_end - target;
}
-#ifdef GUS_NO_DMA
+#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
/*
* For some reason the DMA is not possible. We have to use PIO.
*/
@@ -1429,24 +1899,35 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
for (i = 0; i < blk_size; i++)
{
- GET_BYTE_FROM_USER (data, addr, sizeof (patch) + i);
+ GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
+ if (patch.mode & WAVE_UNSIGNED)
+
+ if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
+ data ^= 0x80; /*
+ * Convert to signed
+ */
gus_poke (target + i, data);
}
}
-#else /* GUS_NO_DMA */
+#else /*
+ * * * GUS_NO_DMA */
{
unsigned long address, hold_address;
unsigned char dma_command;
+ unsigned long flags;
/*
* OK, move now. First in and then out.
*/
COPY_FROM_USER (snd_raw_buf[gus_devnum][0],
- addr, sizeof (patch) + src_offs,
+ addr, sizeof_patch + src_offs,
blk_size);
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
+ 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],
blk_size, DMA_MODE_WRITE);
@@ -1464,30 +1945,46 @@ 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_ */
+ dma_command |= 0x40; /*
+ * 16 bit _DATA_
+ */
if (sound_dsp_dmachan[gus_devnum] > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
+ dma_command |= 0x04; /*
+ * 16 bit DMA channel
+ */
- gus_write8 (0x41, dma_command); /* Let's go luteet (=bugs) */
+ gus_write8 (0x41, dma_command); /*
+ * Let's go luteet (=bugs)
+ */
/*
* Sleep here until the DRAM DMA done interrupt is served
*/
active_device = GUS_DEV_WAVE;
- INTERRUPTIBLE_SLEEP_ON (dram_sleeper, dram_sleep_flag);
+ DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
+ if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
+ printk ("GUS: DMA Transfer timed out\n");
+ RESTORE_INTR (flags);
}
-#endif /* GUS_NO_DMA */
+#endif /*
+ * * * GUS_NO_DMA */
/*
* Now the next part
@@ -1497,7 +1994,9 @@ 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;
@@ -1521,6 +2020,10 @@ guswave_hw_control (int dev, unsigned char *event)
p2 = *(unsigned short *) &event[6];
plong = *(unsigned long *) &event[4];
+ if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
+ (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
+ do_volume_irq (voice);
+
switch (cmd)
{
@@ -1538,7 +2041,9 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_VOICEON:
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_voice_on (p1);
RESTORE_INTR (flags);
break;
@@ -1551,16 +2056,15 @@ guswave_hw_control (int dev, unsigned char *event)
break;
case _GUS_VOICEFADE:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
gus_voice_fade (voice);
- RESTORE_INTR (flags);
break;
case _GUS_VOICEMODE:
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_voice_mode (p1);
RESTORE_INTR (flags);
break;
@@ -1586,14 +2090,18 @@ 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 voice value
+ */
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);
@@ -1602,7 +2110,9 @@ guswave_hw_control (int dev, unsigned char *event)
case _GUS_RAMPRATE:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_ramp_rate (p1, p2);
@@ -1611,27 +2121,37 @@ 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; /*
+ * Disable intr
+ */
gus_ramp_mode (p1);
RESTORE_INTR (flags);
break;
case _GUS_RAMPON:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
- p1 &= ~0x20; /* Disable intr */
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
gus_rampon (p1);
RESTORE_INTR (flags);
break;
case _GUS_RAMPOFF:
if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
+ break; /*
+ * NO-NO
+ */
DISABLE_INTR (flags);
gus_select_voice (voice);
gus_rampoff ();
@@ -1643,6 +2163,13 @@ guswave_hw_control (int dev, unsigned char *event)
volume_scale = p2;
break;
+ case _GUS_VOICE_POS:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_set_voice_pos (voice, plong);
+ RESTORE_INTR (flags);
+ break;
+
default:;
}
}
@@ -1710,6 +2237,8 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
break;
case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return gus_sampling_set_channels (arg);
return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg)));
break;
@@ -1730,7 +2259,9 @@ 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 YET IMPLEMENTED
+ */
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
break;
@@ -1760,6 +2291,8 @@ gus_sampling_open (int dev, int mode)
if (gus_busy)
return RET_ERROR (EBUSY);
+ gus_initialize ();
+
gus_busy = 1;
active_device = 0;
@@ -1767,10 +2300,13 @@ gus_sampling_open (int dev, int mode)
reset_sample_memory ();
gus_select_max_voices (14);
- gus_sampling_set_bits (8);
- gus_sampling_set_channels (1);
- gus_sampling_set_speed (DSP_DEFAULT_SPEED);
pcm_active = 0;
+ pcm_opened = 1;
+ if (mode & OPEN_READ)
+ {
+ recording_active = 1;
+ set_input_volumes ();
+ }
return 0;
}
@@ -1780,7 +2316,31 @@ gus_sampling_close (int dev)
{
gus_reset ();
gus_busy = 0;
+ pcm_opened = 0;
active_device = 0;
+
+ if (recording_active)
+ set_input_volumes ();
+
+ recording_active = 0;
+}
+
+static void
+gus_sampling_update_volume (void)
+{
+ unsigned long flags;
+ int voice;
+
+ DISABLE_INTR (flags);
+ if (pcm_active && pcm_opened)
+ for (voice = 0; voice < gus_sampling_channels; voice++)
+ {
+ gus_select_voice (voice);
+ gus_rampoff ();
+ gus_voice_volume (1530 + (25 * gus_pcm_volume));
+ gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
+ }
+ RESTORE_INTR (flags);
}
static void
@@ -1800,18 +2360,24 @@ 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;
@@ -1819,15 +2385,23 @@ 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 of the DRAM buffers
+ */
{
- mode[chn] |= 0x08; /* Enable loop */
- ramp_mode[chn] = 0x03;/* Disable rollover */
+ mode[chn] |= 0x08; /*
+ * Enable loop
+ */
+ ramp_mode[chn] = 0x03;/*
+ * Disable rollover
+ */
}
else
{
if (chn == 0)
- ramp_mode[chn] = 0x04; /* Enable rollover bit */
+ ramp_mode[chn] = 0x04; /*
+ * Enable rollover bit
+ */
}
DISABLE_INTR (flags);
@@ -1835,13 +2409,21 @@ 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) /*
+ * Voice not started yet
+ */
{
/*
* The playback was not started yet (or there has been a pause).
@@ -1850,38 +2432,67 @@ play_next_pcm_block (void)
* the normal loop with irq.
*/
- gus_voice_off (); /* It could already be running */
+ gus_voice_off (); /*
+ * It could already be running
+ */
gus_rampoff ();
- gus_voice_volume (4000);
- gus_ramp_range (65, 4030);
+ 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
+ * location
+ */
if (chn != 0)
gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
- is16bits); /* Loop end location */
+ is16bits); /*
+ * Loop end location
+ */
}
if (chn == 0)
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */
+ gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
+ * Loop
+ * end
+ * location
+ */
else
- mode[chn] |= 0x08; /* Enable loop */
+ mode[chn] |= 0x08; /*
+ * Enable loop
+ */
if (pcm_datasize[this_one] != pcm_bsize)
{
- /* Incomplete block. Possibly the last one. */
+ /*
+ * Incomplete block. Possibly the last one.
+ */
if (chn == 0)
{
- mode[chn] &= ~0x08; /* Disable loop */
- mode[chn] |= 0x20;/* Enable loop IRQ */
+ mode[chn] &= ~0x08; /*
+ * Disable loop
+ */
+ mode[chn] |= 0x20;/*
+ * Enable loop IRQ
+ */
voices[0].loop_irq_mode = LMODE_PCM_STOP;
- ramp_mode[chn] = 0x03; /* No rollover bit */
+ ramp_mode[chn] = 0x03; /*
+ * No rollover bit
+ */
}
else
{
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */
- mode[chn] &= ~0x08; /* Disable loop */
+ gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
+ * Loop
+ * end
+ * location
+ */
+ mode[chn] &= ~0x08; /*
+ * Disable loop
+ */
}
}
@@ -1908,7 +2519,7 @@ gus_transfer_output_block (int dev, unsigned long buf,
* This routine transfers one block of audio data to the DRAM. In mono mode
* it's called just once. When in stereo mode, this_one routine is called
* once for both channels.
- *
+ *
* The left/mono channel data is transferred to the beginning of dram and the
* right data to the area pointed by gus_page_size.
*/
@@ -1935,7 +2546,9 @@ 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;
@@ -1949,38 +2562,56 @@ 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 */
+ dma_command |= 0x04; /*
+ * 16 bit DMA channel
+ */
- gus_write8 (0x41, dma_command); /* Kick on */
+ gus_write8 (0x41, dma_command); /*
+ * Kick on
+ */
- if (chn == (gus_sampling_channels - 1)) /* Last channel */
+ if (chn == (gus_sampling_channels - 1)) /*
+ * Last channel
+ */
{
- /* Last (right or mono) channel data */
+ /*
+ * Last (right or mono) channel data
+ */
active_device = GUS_DEV_PCM_DONE;
if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))
{
play_next_pcm_block ();
}
}
- else /* Left channel data. The right channel is
- * transferred after DMA interrupt */
+ else /*
+ * * * Left channel data. The right channel
+ * is * * * transferred after DMA interrupt */
active_device = GUS_DEV_PCM_CONTINUE;
RESTORE_INTR (flags);
}
static void
-gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intrflag)
+gus_sampling_output_block (int dev, unsigned long buf, int total_count,
+ int intrflag, int restart_dma)
{
pcm_current_buf = buf;
pcm_current_count = total_count;
@@ -1990,7 +2621,8 @@ gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intr
}
static void
-gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag)
+gus_sampling_start_input (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags;
unsigned char mode;
@@ -1999,13 +2631,21 @@ gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag)
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
- mode = 0xa0; /* DMA IRQ enable, invert MSB */
+ mode = 0xa0; /*
+ * DMA IRQ enable, invert MSB
+ */
if (sound_dsp_dmachan[dev] > 3)
- mode |= 0x04; /* 16 bit DMA channel */
+ mode |= 0x04; /*
+ * 16 bit DMA channel
+ */
if (gus_sampling_channels > 1)
- mode |= 0x02; /* Stereo */
- mode |= 0x01; /* DMA enable */
+ mode |= 0x02; /*
+ * Stereo
+ */
+ mode |= 0x01; /*
+ * DMA enable
+ */
gus_write8 (0x49, mode);
@@ -2019,7 +2659,9 @@ 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 frequency
+ */
if (gus_sampling_bits != 8)
{
@@ -2072,7 +2714,9 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs,
snd_rw_buf * userbuf, int useroffs, int len)
{
if (gus_sampling_channels == 1)
- COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
+ {
+ COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
+ }
else if (gus_sampling_bits == 8)
{
int in_left = useroffs;
@@ -2119,19 +2763,39 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs,
static struct audio_operations gus_sampling_operations =
{
"Gravis UltraSound",
- gus_sampling_open, /* */
- gus_sampling_close, /* */
- gus_sampling_output_block, /* */
- gus_sampling_start_input, /* */
- gus_sampling_ioctl, /* */
- gus_sampling_prepare_for_input, /* */
- gus_sampling_prepare_for_output, /* */
- gus_sampling_reset, /* */
- gus_sampling_reset, /* halt_xfer */
+ NEEDS_RESTART,
+ gus_sampling_open,
+ gus_sampling_close,
+ gus_sampling_output_block,
+ gus_sampling_start_input,
+ gus_sampling_ioctl,
+ gus_sampling_prepare_for_input,
+ gus_sampling_prepare_for_output,
+ gus_sampling_reset,
+ gus_sampling_reset,
gus_has_output_drained,
gus_copy_from_user
};
+#ifdef FUTURE_VERSION
+static void
+guswave_bender (int dev, int voice, int value)
+{
+ int freq;
+ unsigned long flags;
+
+ voices[voice].bender = value - 8192;
+ freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_freq (freq);
+ RESTORE_INTR (flags);
+}
+
+#endif
+
static int
guswave_patchmgr (int dev, struct patmgr_info *rec)
{
@@ -2161,7 +2825,9 @@ 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;
@@ -2176,7 +2842,9 @@ 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;
@@ -2196,8 +2864,12 @@ 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 address
+ */
rec->parm2 = sizeof (struct patch_info);
}
return 0;
@@ -2213,10 +2885,14 @@ 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));
@@ -2226,7 +2902,9 @@ 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;
@@ -2237,9 +2915,13 @@ 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; /*
+ * Nr of bytes left
+ */
if (l > n)
l = n;
@@ -2248,18 +2930,26 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
l = sizeof (rec->data.data8);
if (l <= 0)
- return RET_ERROR (EINVAL); /* Was there a bug? */
+ return RET_ERROR (EINVAL); /*
+ * Was there a bug?
+ */
- offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */
+ offs += sample_ptrs[sample]; /*
+ * Begin offsess + offset to DRAM
+ */
for (n = 0; n < l; n++)
rec->data.data8[n] = gus_peek (offs++);
- rec->parm1 = n; /* Nr of bytes copied */
+ rec->parm1 = n; /*
+ * Nr of bytes copied
+ */
}
return 0;
break;
- case PM_WRITE_PATCH: /* Writes a block of wave data to the DRAM */
+ case PM_WRITE_PATCH: /*
+ * Writes a block of wave data to the DRAM
+ */
{
int sample = rec->parm1;
int n;
@@ -2270,9 +2960,13 @@ 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; /*
+ * Nr of bytes left
+ */
if (l > n)
l = n;
@@ -2281,13 +2975,19 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
l = sizeof (rec->data.data8);
if (l <= 0)
- return RET_ERROR (EINVAL); /* Was there a bug? */
+ return RET_ERROR (EINVAL); /*
+ * Was there a bug?
+ */
- offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */
+ offs += sample_ptrs[sample]; /*
+ * Begin offsess + offset to DRAM
+ */
for (n = 0; n < l; n++)
gus_poke (offs++, rec->data.data8[n]);
- rec->parm1 = n; /* Nr of bytes copied */
+ rec->parm1 = n; /*
+ * Nr of bytes copied
+ */
}
return 0;
break;
@@ -2300,6 +3000,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
static struct synth_operations guswave_operations =
{
&gus_info,
+#ifdef FUTURE_VERSION
+ 0,
+#endif
SYNTH_TYPE_SAMPLE,
SAMPLE_TYPE_GUS,
guswave_open,
@@ -2314,13 +3017,273 @@ static struct synth_operations guswave_operations =
guswave_aftertouch,
guswave_controller,
guswave_panning,
- guswave_patchmgr
+ guswave_volume_method,
+ guswave_patchmgr,
+#ifdef FUTURE_VERSION
+ guswave_bender
+#endif
+};
+
+static void
+set_input_volumes (void)
+{
+ unsigned long flags;
+ unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
+
+ DISABLE_INTR (flags);
+
+ /*
+ * Enable channels having vol > 10%
+ * Note! bit 0x01 means line in DISABLED while 0x04 means
+ * mic in ENABLED.
+ */
+ if (gus_line_vol > 10)
+ mask &= ~0x01;
+ if (gus_mic_vol > 10)
+ mask |= 0x04;
+
+ if (recording_active)
+ {
+ /*
+ * Disable channel, if not selected for recording
+ */
+ if (!(gus_recmask & SOUND_MASK_LINE))
+ mask |= 0x01;
+ if (!(gus_recmask & SOUND_MASK_MIC))
+ mask &= ~0x04;
+ }
+
+ mix_image &= ~0x07;
+ mix_image |= mask & 0x07;
+ OUTB (mix_image, u_Mixer);
+
+ RESTORE_INTR (flags);
+}
+
+int
+gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+ SOUND_MASK_SYNTH|SOUND_MASK_PCM)
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ gus_recmask = IOCTL_IN (arg) & MIX_DEVS;
+ if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
+ gus_recmask = SOUND_MASK_MIC;
+ /* Note! Input volumes are updated during next open for recording */
+ return IOCTL_OUT (arg, gus_recmask);
+ break;
+
+ case SOUND_MIXER_MIC:
+ {
+ int vol = IOCTL_IN (arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_mic_vol = vol;
+ set_input_volumes ();
+ return IOCTL_OUT (arg, vol | (vol << 8));
+ }
+ break;
+
+ case SOUND_MIXER_LINE:
+ {
+ int vol = IOCTL_IN (arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_line_vol = vol;
+ set_input_volumes ();
+ return IOCTL_OUT (arg, vol | (vol << 8));
+ }
+ break;
+
+ case SOUND_MIXER_PCM:
+ gus_pcm_volume = IOCTL_IN (arg) & 0xff;
+ if (gus_pcm_volume < 0)
+ gus_pcm_volume = 0;
+ if (gus_pcm_volume > 100)
+ gus_pcm_volume = 100;
+ gus_sampling_update_volume ();
+ return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ {
+ int voice;
+
+ gus_wave_volume = IOCTL_IN (arg) & 0xff;
+
+ if (gus_wave_volume < 0)
+ gus_wave_volume = 0;
+ if (gus_wave_volume > 100)
+ gus_wave_volume = 100;
+
+ if (active_device == GUS_DEV_WAVE)
+ for (voice = 0; voice < nr_voices; voice++)
+ dynamic_volume_change (voice); /*
+ * Apply the new
+ * volume
+ */
+
+ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ }
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ else
+ switch (cmd & 0xff) /*
+ * Return parameters
+ */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, gus_recmask);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, MIX_DEVS);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, gus_mic_vol | (gus_mic_vol << 8));
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, gus_line_vol | (gus_line_vol << 8));
+ break;
+
+ case SOUND_MIXER_PCM:
+ return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ }
+ else
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations gus_mixer_operations =
+{
+ gus_default_mixer_ioctl
};
+static long
+gus_default_mixer_init (long mem_start)
+{
+ if (num_mixers < MAX_MIXER_DEV) /*
+ * Don't install if there is another
+ * mixer
+ */
+ mixer_devs[num_mixers++] = &gus_mixer_operations;
+
+ return mem_start;
+}
+
long
gus_wave_init (long mem_start, int irq, int dma)
{
- printk ("snd4: <Gravis UltraSound %dk>", gus_mem_size / 1024);
+ unsigned long flags;
+ unsigned char val;
+ char *model_num = "2.4";
+ int gus_type = 0x24; /* 2.4 */
+ int mixer_type = 0;
+
+ /*
+ * Try to identify the GUS model.
+ *
+ * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+ */
+
+ DISABLE_INTR (flags);
+ OUTB (0x20, gus_base + 0x0f);
+ val = INB (gus_base + 0x0f);
+ RESTORE_INTR (flags);
+
+ if (val != 0xff && (val & 0x06)) /* Should be 0x02? */
+ {
+ /*
+ * It has the digital ASIC so the card is at least v3.4.
+ * Next try to detect the true model.
+ */
+
+ val = INB (u_MixSelect);
+
+ /*
+ * Value 255 means pre-3.7 which don't have mixer.
+ * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
+ * 10 and above is GUS MAX which has the CS4231 codec/mixer.
+ *
+ * Sorry. No GUS max support yet but it should be available
+ * soon after the SDK for GUS MAX is available.
+ */
+
+ if (val == 255 || val < 5)
+ {
+ model_num = "3.4";
+ gus_type = 0x34;
+ }
+ else if (val < 10)
+ {
+ model_num = "3.7";
+ gus_type = 0x37;
+ mixer_type = ICS2101;
+ }
+ else
+ {
+ model_num = "MAX";
+ gus_type = 0x40;
+ mixer_type = CS4231;
+ }
+ }
+ else
+ {
+ /*
+ * ASIC not detected so the card must be 2.2 or 2.4.
+ * There could still be the 16-bit/mixer daughter card.
+ * It has the same codec/mixer than MAX.
+ * At this time there is no support for it but it will appear soon.
+ */
+ }
+
+
+#ifdef __FreeBSD__
+ printk ("snd4: <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+#else
+ printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+#endif
+
+#ifndef SCO
+ sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+#endif
if (irq < 0 || irq > 15)
{
@@ -2342,6 +3305,9 @@ gus_wave_init (long mem_start, int irq, int dma)
else
synth_devs[num_synths++] = &guswave_operations;
+ PERMANENT_MALLOC (struct patch_info *, samples,
+ (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
+
reset_sample_memory ();
gus_initialize ();
@@ -2350,13 +3316,29 @@ gus_wave_init (long mem_start, int irq, int dma)
{
dsp_devs[gus_devnum = num_dspdevs++] = &gus_sampling_operations;
sound_dsp_dmachan[gus_devnum] = dma;
- sound_buffcounts[gus_devnum] = 1;
+ sound_buffcounts[gus_devnum] = DSP_BUFFCOUNT;
sound_buffsizes[gus_devnum] = DSP_BUFFSIZE;
sound_dma_automode[gus_devnum] = 0;
}
else
printk ("GUS: Too many PCM devices available\n");
+ /*
+ * Mixer dependent initialization.
+ */
+
+ switch (mixer_type)
+ {
+ case ICS2101:
+ gus_line_vol=gus_mic_vol=gus_wave_volume = gus_pcm_volume = 100;
+ return ics2101_mixer_init (mem_start);
+
+ case CS4231:
+ /* Available soon */
+ default:
+ return gus_default_mixer_init (mem_start);
+ }
+
return mem_start;
}
@@ -2371,7 +3353,9 @@ do_loop_irq (int voice)
gus_select_voice (voice);
tmp = gus_read8 (0x00);
- tmp &= ~0x20; /* Disable wave IRQ for this_one voice */
+ tmp &= ~0x20; /*
+ * Disable wave IRQ for this_one voice
+ */
gus_write8 (0x00, tmp);
mode = voices[voice].loop_irq_mode;
@@ -2381,23 +3365,33 @@ do_loop_irq (int voice)
switch (mode)
{
- case LMODE_FINISH: /* Final loop finished, shoot volume down */
+ case LMODE_FINISH: /*
+ * Final loop finished, shoot volume down
+ */
- if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */
+ if ((gus_read16 (0x09) >> 4) < 100) /*
+ * Get current volume
+ */
{
gus_voice_off ();
gus_rampoff ();
gus_voice_init (voice);
- return;
+ break;
}
gus_ramp_range (65, 4065);
- gus_ramp_rate (0, 63); /* Fastest possible rate */
- gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
+ gus_ramp_rate (0, 63); /*
+ * Fastest possible rate
+ */
+ gus_rampon (0x20 | 0x40); /*
+ * Ramp down, once, irq
+ */
voices[voice].volume_irq_mode = VMODE_HALT;
break;
case LMODE_PCM_STOP:
- pcm_active = 0; /* Requires extensive processing */
+ pcm_active = 0; /*
+ * Requires extensive processing
+ */
case LMODE_PCM:
{
int orig_qlen = pcm_qlen;
@@ -2409,7 +3403,9 @@ do_loop_irq (int voice)
play_next_pcm_block ();
}
else
- { /* Out of data. Just stop the voice */
+ { /*
+ * Out of data. Just stop the voice
+ */
gus_voice_off ();
gus_rampoff ();
pcm_active = 0;
@@ -2417,7 +3413,7 @@ do_loop_irq (int voice)
if (orig_qlen == pcm_nblk)
{
- DMAbuf_outputintr (gus_devnum);
+ DMAbuf_outputintr (gus_devnum, 0);
}
}
break;
@@ -2439,7 +3435,9 @@ do_volume_irq (int voice)
gus_select_voice (voice);
tmp = gus_read8 (0x0d);
- tmp &= ~0x20; /* Disable volume ramp IRQ */
+ tmp &= ~0x20; /*
+ * Disable volume ramp IRQ
+ */
gus_write8 (0x0d, tmp);
mode = voices[voice].volume_irq_mode;
@@ -2448,19 +3446,35 @@ do_volume_irq (int voice)
switch (mode)
{
- case VMODE_HALT: /* Decay phase finished */
+ case VMODE_HALT: /*
+ * Decay phase finished
+ */
+ RESTORE_INTR (flags);
gus_voice_init (voice);
break;
case VMODE_ENVELOPE:
gus_rampoff ();
+ RESTORE_INTR (flags);
step_envelope (voice);
break;
+ case VMODE_START_NOTE:
+ RESTORE_INTR (flags);
+ guswave_start_note2 (voices[voice].dev_pending, voice,
+ voices[voice].note_pending, voices[voice].volume_pending);
+ if (voices[voice].kill_pending)
+ guswave_kill_note (voices[voice].dev_pending, voice, 0);
+ if (voices[voice].sample_pending >= 0)
+ {
+ guswave_set_instr (voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ }
+ break;
+
default:;
}
-
- RESTORE_INTR (flags);
}
void
@@ -2473,24 +3487,38 @@ gus_voice_irq (void)
while (1)
{
- src = gus_read8 (0x0f); /* Get source info */
+ src = gus_read8 (0x0f); /*
+ * Get source info
+ */
voice = src & 0x1f;
src &= 0xc0;
if (src == (0x80 | 0x40))
- return; /* No interrupt */
+ return; /*
+ * No interrupt
+ */
voice_bit = 1 << voice;
- if (!(src & 0x80)) /* Wave IRQ pending */
- if (!(wave_ignore & voice_bit) && voice < nr_voices) /* Not done yet */
+ if (!(src & 0x80)) /*
+ * Wave IRQ pending
+ */
+ if (!(wave_ignore & voice_bit) && voice < nr_voices) /*
+ * Not done
+ * yet
+ */
{
wave_ignore |= voice_bit;
do_loop_irq (voice);
}
- if (!(src & 0x40)) /* Volume IRQ pending */
- if (!(volume_ignore & voice_bit) && voice < nr_voices) /* Not done yet */
+ if (!(src & 0x40)) /*
+ * Volume IRQ pending
+ */
+ if (!(volume_ignore & voice_bit) && voice < nr_voices) /*
+ * Not done
+ * yet
+ */
{
volume_ignore |= voice_bit;
do_volume_irq (voice);
@@ -2503,13 +3531,17 @@ 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 Irq pending
+ */
switch (active_device)
{
case GUS_DEV_WAVE:
- if (dram_sleep_flag)
- WAKE_UP (dram_sleeper);
+ if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag))
+ WAKE_UP (dram_sleeper, dram_sleep_flag);
break;
case GUS_DEV_PCM_CONTINUE:
@@ -2521,15 +3553,19 @@ guswave_dma_irq (void)
case GUS_DEV_PCM_DONE:
if (pcm_qlen < pcm_nblk)
{
- DMAbuf_outputintr (gus_devnum);
+ DMAbuf_outputintr (gus_devnum, pcm_qlen == 0);
}
break;
default:;
}
- status = gus_look8 (0x49); /* Get Sampling IRQ Status */
- if (status & 0x40) /* Sampling Irq pending */
+ status = gus_look8 (0x49); /*
+ * Get Sampling IRQ Status
+ */
+ if (status & 0x40) /*
+ * Sampling Irq pending
+ */
{
DMAbuf_inputintr (gus_devnum);
}
diff --git a/sys/i386/isa/sound/ics2101.c b/sys/i386/isa/sound/ics2101.c
new file mode 100644
index 000000000000..0e54c608de36
--- /dev/null
+++ b/sys/i386/isa/sound/ics2101.c
@@ -0,0 +1,265 @@
+/*
+ * sound/ics2101.c
+ *
+ * Driver for the ICS2101 mixer of GUS v3.7.
+ *
+ * Copyright by Hannu Savolainen 1994
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+
+#ifdef __FreeBSD__
+#include <machine/ultrasound.h>
+#else
+#include "ultrasound.h"
+#endif
+#include "gus_hw.h"
+
+#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+ SOUND_MASK_SYNTH| \
+ SOUND_MASK_CD | SOUND_MASK_VOLUME)
+
+extern int gus_base;
+static int volumes[ICS_MIXDEVS];
+static int left_fix[ICS_MIXDEVS] =
+{1, 1, 1, 2, 1, 2};
+static int right_fix[ICS_MIXDEVS] =
+{2, 2, 2, 1, 2, 1};
+
+static int
+scale_vol(int vol)
+{
+#if 1
+/*
+ * Experimental volume scaling by Risto Kankkunen.
+ * This should give smoother volume response than just
+ * a plain multiplication.
+ */
+ int e;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ vol = (31 * vol + 50) / 100;
+ e = 0;
+ if (vol) {
+ while (vol < 16) {
+ vol <<= 1;
+ e--;
+ }
+ vol -= 16;
+ e += 7;
+ }
+ return ((e << 4) + vol);
+#else
+ return ((vol*127)+50)/100;
+#endif
+}
+
+static void
+write_mix (int dev, int chn, int vol)
+{
+ int *selector;
+ unsigned long flags;
+ int ctrl_addr = dev << 3;
+ int attn_addr = dev << 3;
+
+ vol=scale_vol(vol);
+
+ if (chn == CHN_LEFT)
+ {
+ selector = left_fix;
+ ctrl_addr |= 0x00;
+ attn_addr |= 0x02;
+ }
+ else
+ {
+ selector = right_fix;
+ ctrl_addr |= 0x01;
+ attn_addr |= 0x03;
+ }
+
+ DISABLE_INTR (flags);
+ OUTB (ctrl_addr, u_MixSelect);
+ OUTB (selector[dev], u_MixData);
+ OUTB (attn_addr, u_MixSelect);
+ OUTB ((unsigned char) vol, u_MixData);
+ RESTORE_INTR (flags);
+}
+
+static int
+set_volumes (int dev, int vol)
+{
+ int left = vol & 0x00ff;
+ int right = (vol >> 8) & 0x00ff;
+
+ if (left < 0)
+ left = 0;
+ if (left > 100)
+ left = 100;
+ if (right < 0)
+ right = 0;
+ if (right > 100)
+ right = 100;
+
+ write_mix (dev, CHN_LEFT, left);
+ write_mix (dev, CHN_RIGHT, right);
+
+ vol = left + (right << 8);
+ volumes[dev] = vol;
+ return vol;
+}
+
+static int
+ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ return gus_default_mixer_ioctl (dev, cmd, arg);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, set_volumes (DEV_MIC, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_CD:
+ return IOCTL_OUT (arg, set_volumes (DEV_CD, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, set_volumes (DEV_LINE, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, set_volumes (DEV_GF1, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return IOCTL_OUT (arg, set_volumes (DEV_VOL, IOCTL_IN (arg)));
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ else
+ switch (cmd & 0xff) /*
+ * Return parameters
+ */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return gus_default_mixer_ioctl (dev, cmd, arg);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, MIX_DEVS);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_SYNTH | SOUND_MASK_VOLUME|
+ SOUND_MASK_MIC);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, volumes[DEV_MIC]);
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, volumes[DEV_LINE]);
+ break;
+
+ case SOUND_MIXER_CD:
+ return IOCTL_OUT (arg, volumes[DEV_CD]);
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return IOCTL_OUT (arg, volumes[DEV_VOL]);
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, volumes[DEV_GF1]);
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations ics2101_mixer_operations =
+{
+ ics2101_mixer_ioctl
+};
+
+long
+ics2101_mixer_init (long mem_start)
+{
+ int i;
+
+ if (num_mixers < MAX_MIXER_DEV)
+ {
+ mixer_devs[num_mixers++] = &ics2101_mixer_operations;
+
+ /*
+ * Some GUS v3.7 cards had some channels flipped. Disable
+ * the flipping feature if the model id is other than 5.
+ */
+
+ if (INB (u_MixSelect) != 5)
+ {
+ for (i = 0; i < ICS_MIXDEVS; i++)
+ left_fix[i] = 1;
+ for (i = 0; i < ICS_MIXDEVS; i++)
+ right_fix[i] = 2;
+ }
+
+ set_volumes (DEV_GF1, 0x5a5a);
+ set_volumes (DEV_CD, 0x5a5a);
+ set_volumes (DEV_MIC, 0x0000);
+ set_volumes (DEV_LINE, 0x5a5a);
+ set_volumes (DEV_VOL, 0x5a5a);
+ set_volumes (DEV_UNUSED, 0x0000);
+ }
+
+ return mem_start;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/local.h b/sys/i386/isa/sound/local.h
index f81bd7821673..36092e37d978 100644
--- a/sys/i386/isa/sound/local.h
+++ b/sys/i386/isa/sound/local.h
@@ -1,10 +1,15 @@
-/* These few lines are used by FreeBSD (only??). */
-
+/* for FreeBSD */
#include "snd.h"
#if NSND > 0
-#define CONFIGURE_SOUNDCARD
+#define KERNEL_SOUNDCARD
#endif
-#define DSP_BUFFSIZE 32768
+#define DSP_BUFFSIZE 65536
+#define NO_AUTODMA /* still */
#define SELECTED_SOUND_OPTIONS 0xffffffff
+#define SOUND_VERSION_STRING "2.5"
+#define SOUND_CONFIG_DATE "Sat Apr 23 07:45:17 MSD 1994"
+#define SOUND_CONFIG_BY "ache"
+#define SOUND_CONFIG_HOST "dream.demos.su"
+#define SOUND_CONFIG_DOMAIN ""
diff --git a/sys/i386/isa/sound/midi.c b/sys/i386/isa/sound/midi.c
index 8d604a80abc2..6ea51b061b9c 100644
--- a/sys/i386/isa/sound/midi.c
+++ b/sys/i386/isa/sound/midi.c
@@ -31,24 +31,27 @@
#ifndef EXCLUDE_CHIP_MIDI
-static int generic_midi_busy[MAX_MIDI_DEV];
+static int generic_midi_busy[MAX_MIDI_DEV];
-long CMIDI_init (long mem_start)
+long
+CMIDI_init (long mem_start)
{
-
- int i;
- int n = num_midi_drivers;
- /* int n = sizeof (midi_supported) / sizeof( struct generic_midi_info );
- */
- for (i = 0; i < n; i++)
- {
- if ( midi_supported[i].attach (mem_start) )
+
+ int i;
+ int n = num_midi_drivers;
+
+ /*
+ * int n = sizeof (midi_supported) / sizeof( struct generic_midi_info );
+ */
+ for (i = 0; i < n; i++)
{
- printk("MIDI: Successfully attached %s\n",midi_supported[i].name);
- }
+ if (midi_supported[i].attach (mem_start))
+ {
+ printk ("MIDI: Successfully attached %s\n", midi_supported[i].name);
+ }
- }
- return (mem_start);
+ }
+ return (mem_start);
}
@@ -56,142 +59,143 @@ int
CMIDI_open (int dev, struct fileinfo *file)
{
- int mode, err, retval;
+ int mode, err, retval;
- dev = dev >> 4;
+ dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ mode = file->mode & O_ACCMODE;
- if (generic_midi_busy[dev])
- return (RET_ERROR(EBUSY));
+ if (generic_midi_busy[dev])
+ return (RET_ERROR (EBUSY));
-
- if (dev >= num_generic_midis)
- {
- printk(" MIDI device %d not installed.\n", dev);
- return (ENXIO);
- }
- if (!generic_midi_devs[dev])
- {
- printk(" MIDI device %d not initialized\n",dev);
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
return (ENXIO);
- }
+ }
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
+ return (ENXIO);
+ }
+
+ /* If all good and healthy, go ahead and issue call! */
- /* If all good and healthy, go ahead and issue call! */
-
- retval = generic_midi_devs[dev]->open (dev, mode) ;
+ retval = generic_midi_devs[dev]->open (dev, mode);
- /* If everything ok, set device as busy */
+ /* If everything ok, set device as busy */
- if ( retval >= 0 )
- generic_midi_busy[dev] = 1;
-
- return ( retval );
+ if (retval >= 0)
+ generic_midi_busy[dev] = 1;
+
+ return (retval);
}
-int
-CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+int
+CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
- int retval;
-
- dev = dev >> 4;
+ int retval;
+
+ dev = dev >> 4;
- if (dev >= num_generic_midis)
- {
- printk(" MIDI device %d not installed.\n", dev);
- return (ENXIO);
- }
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
+ return (ENXIO);
+ }
- /* Make double sure of healthiness -- doubt
- * Need we check this again??
- *
- */
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
- if (!generic_midi_devs[dev])
- {
- printk(" MIDI device %d not initialized\n",dev);
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
return (ENXIO);
- }
+ }
- /* If all good and healthy, go ahead and issue call! */
+ /* If all good and healthy, go ahead and issue call! */
-
- retval = generic_midi_devs[dev]->write (dev, buf);
- return ( retval );
+ retval = generic_midi_devs[dev]->write (dev, buf);
-}
+ return (retval);
+
+}
int
-CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count)
+CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
- int retval;
-
- dev = dev >> 4;
-
- if (dev >= num_generic_midis)
- {
- printk(" MIDI device %d not installed.\n", dev);
- return (ENXIO);
- }
-
- /* Make double sure of healthiness -- doubt
- * Need we check this again??
- *
- */
-
- if (!generic_midi_devs[dev])
- {
- printk(" MIDI device %d not initialized\n",dev);
+ int retval;
+
+ dev = dev >> 4;
+
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
return (ENXIO);
- }
+ }
- /* If all good and healthy, go ahead and issue call! */
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
+ return (ENXIO);
+ }
+
+ /* If all good and healthy, go ahead and issue call! */
-
- retval = generic_midi_devs[dev]->read(dev,buf);
- return (retval);
+ retval = generic_midi_devs[dev]->read (dev, buf);
+
+ return (retval);
+
+}
-}
-
int
CMIDI_close (int dev, struct fileinfo *file)
{
- int retval;
- dev = dev >> 4;
-
- if (dev >= num_generic_midis)
- {
- printk(" MIDI device %d not installed.\n", dev);
- return (ENXIO);
- }
-
- /* Make double sure of healthiness -- doubt
- * Need we check this again??
- *
- */
-
- if (!generic_midi_devs[dev])
- {
- printk(" MIDI device %d not initialized\n",dev);
+ int retval;
+
+ dev = dev >> 4;
+
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
+ return (ENXIO);
+ }
+
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
return (ENXIO);
- }
+ }
- /* If all good and healthy, go ahead and issue call! */
+ /* If all good and healthy, go ahead and issue call! */
- generic_midi_devs[dev]->close(dev);
+ generic_midi_devs[dev]->close (dev);
- generic_midi_busy[dev] = 0; /* Free the device */
+ generic_midi_busy[dev] = 0; /* Free the device */
- return (0) ;
+ return (0);
}
diff --git a/sys/i386/isa/sound/midibuf.c b/sys/i386/isa/sound/midibuf.c
index 0196f84876bf..7dadb3f8fa74 100644
--- a/sys/i386/isa/sound/midibuf.c
+++ b/sys/i386/isa/sound/midibuf.c
@@ -1,12 +1,12 @@
/*
- * linux/kernel/chr_drv/sound/midibuf.c
- *
+ * sound/midibuf.c
+ *
* Device file manager for /dev/midi
- *
+ *
* NOTE! This part of the driver is currently just a stub.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -14,7 +14,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -26,7 +26,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
diff --git a/sys/i386/isa/sound/mpu401.c b/sys/i386/isa/sound/mpu401.c
index e8c011bc7940..38ba486b142b 100644
--- a/sys/i386/isa/sound/mpu401.c
+++ b/sys/i386/isa/sound/mpu401.c
@@ -1,12 +1,12 @@
/*
- * linux/kernel/chr_drv/sound/mpu401.c
- *
+ * sound/mpu401.c
+ *
* The low level driver for Roland MPU-401 compatible Midi cards.
- *
+ *
* This version supports just the DUMB UART mode.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -14,7 +14,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -26,7 +26,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -61,102 +61,16 @@ static int my_dev;
static int reset_mpu401 (void);
static void (*midi_input_intr) (int dev, unsigned char data);
-static void
-mpu401_input_loop (void)
-{
- int count;
-
- count = 10;
-
- while (count) /* Not timed out */
- if (input_avail ())
- {
- unsigned char c = mpu401_read ();
-
- count = 100;
-
- if (mpu401_opened & OPEN_READ)
- midi_input_intr (my_dev, c);
- }
- else
- while (!input_avail () && count)
- count--;
-}
-
void
mpuintr (int unit)
{
- if (input_avail ())
- mpu401_input_loop ();
-}
-
-/*
- * It looks like there is no input interrupts in the UART mode. Let's try
- * polling.
- */
-
-/* XXX WARNING: FreeBSD doesn't seem to have timer_lists like this,
- * so until I figure out how to do the analogous thing in FreeBSD, I'm
- * not all that sure WHAT this driver will do! It might work, depending
- * on the condition taken, but then again it might not! -jkh
- * XXX WARNING
- */
-static void
-poll_mpu401 (unsigned long dummy)
-{
- unsigned long flags;
-
-#ifdef linux
- static struct timer_list mpu401_timer =
- {NULL, 0, 0, poll_mpu401};
-#endif
-
- if (!(mpu401_opened & OPEN_READ))
- return; /* No longer required */
-
- DISABLE_INTR (flags);
-
- if (input_avail ())
- mpu401_input_loop ();
-
-#ifdef linux
- mpu401_timer.expires = 1;
- add_timer (&mpu401_timer); /* Come back later */
-#endif
-
- RESTORE_INTR (flags);
-}
-
-static int
-set_mpu401_irq (int interrupt_level)
-{
- int retcode = EINVAL;
-
-#ifdef linux
- struct sigaction sa;
-
- sa.sa_handler = mpuintr;
-
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
-
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
-
- retcode = irqaction (interrupt_level, &sa);
-
- if (retcode < 0)
+ while (input_avail ())
{
- printk ("MPU-401: IRQ%d already in use\n", interrupt_level);
- }
+ unsigned char c = mpu401_read ();
-#else
- /* # error Unimplemented for this OS */
-#endif
- return retcode;
+ if (mpu401_opened & OPEN_READ)
+ midi_input_intr (my_dev, c);
+ }
}
static int
@@ -171,11 +85,10 @@ mpu401_open (int dev, int mode,
return RET_ERROR (EBUSY);
}
- mpu401_input_loop ();
+ mpuintr (0);
midi_input_intr = input;
mpu401_opened = mode;
- poll_mpu401 (0); /* Enable input polling */
return 0;
}
@@ -199,7 +112,7 @@ mpu401_out (int dev, unsigned char midi_byte)
DISABLE_INTR (flags);
if (input_avail ())
- mpu401_input_loop ();
+ mpuintr (0);
RESTORE_INTR (flags);
@@ -257,7 +170,7 @@ mpu401_buffer_status (int dev)
static struct midi_operations mpu401_operations =
{
- {"MPU-401", 0},
+ {"MPU-401", 0, 0, SNDCARD_MPU401},
mpu401_open,
mpu401_close,
mpu401_ioctl,
@@ -294,12 +207,14 @@ attach_mpu401 (long mem_start, struct address_info *hw_config)
RESTORE_INTR (flags);
+#ifdef __FreeBSD__
printk ("snd5: <Roland MPU-401>");
+#else
+ printk (" <Roland MPU-401>");
+#endif
my_dev = num_midis;
-#ifdef linux
mpu401_dev = num_midis;
-#endif
midi_devs[num_midis++] = &mpu401_operations;
return mem_start;
}
@@ -311,7 +226,7 @@ reset_mpu401 (void)
int ok, timeout, n;
/*
- * Send the RESET command. Try twice if no success at the first time.
+ * Send the RESET command. Try again if no success at the first time.
*/
ok = 0;
@@ -337,7 +252,7 @@ reset_mpu401 (void)
mpu401_opened = 0;
if (ok)
- mpu401_input_loop (); /* Flush input before enabling interrupts */
+ mpuintr (0); /* Flush input before enabling interrupts */
RESTORE_INTR (flags);
@@ -353,7 +268,7 @@ probe_mpu401 (struct address_info *hw_config)
mpu401_base = hw_config->io_base;
mpu401_irq = hw_config->irq;
- if (set_mpu401_irq (mpu401_irq) < 0)
+ if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0)
return 0;
ok = reset_mpu401 ();
diff --git a/sys/i386/isa/sound/opl3.c b/sys/i386/isa/sound/opl3.c
index 2dbed1f96e00..6e3dccab8c43 100644
--- a/sys/i386/isa/sound/opl3.c
+++ b/sys/i386/isa/sound/opl3.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/opl3.c
- *
+ * sound/opl3.c
+ *
* A low level driver for Yamaha YM3812 and OPL-3 -chips
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
/* Major improvements to the FM handling 30AUG92 by Rob Hooft, */
@@ -38,7 +38,7 @@
#define MAX_VOICE 18
#define OFFS_4OP 11 /* Definitions for the operators OP3 and OP4
- * begin here */
+ * begin here */
static int opl3_enabled = 0;
static int left_address = 0x388, right_address = 0x388, both_address = 0;
@@ -59,8 +59,7 @@ struct voice_info
static struct voice_info voices[MAX_VOICE];
-typedef struct sbi_instrument instr_array[SBFM_MAXINSTR];
-static instr_array instrmap;
+static struct sbi_instrument *instrmap;
static struct sbi_instrument *active_instrument[MAX_VOICE] =
{NULL};
@@ -71,17 +70,20 @@ 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, const unsigned char addr, const unsigned char val);
+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 unsigned char connection_mask = 0x00;
void
enable_opl3_mode (int left, int right, int both)
{
+ if (opl3_enabled)
+ return;
+
opl3_enabled = 1;
left_address = left;
right_address = right;
@@ -112,7 +114,7 @@ enter_4op_mode (void)
for (i = 0; i < 12; i++)
logical_voices[i] = voices_4op[i];
- nr_voices = 6;
+ nr_voices = 12;
}
static int
@@ -140,7 +142,7 @@ opl3_ioctl (int dev,
break;
case SNDCTL_SYNTH_INFO:
- fm_info.nr_voices = nr_voices;
+ fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices;
IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info));
return 0;
@@ -169,10 +171,10 @@ opl3_detect (int ioaddr)
* This function returns 1 if the FM chicp is present at the given I/O port
* The detection algorithm plays with the timer built in the FM chip and
* looks for a change in the status register.
- *
+ *
* Note! The timers of the FM chip are not connected to AdLib (and compatible)
* boards.
- *
+ *
* Note2! The chip is initialized if detected.
*/
@@ -184,6 +186,9 @@ opl3_detect (int ioaddr)
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 */
@@ -192,7 +197,7 @@ opl3_detect (int ioaddr)
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 */
@@ -270,7 +275,7 @@ store_instr (int instr_no, struct sbi_instrument *instr)
{
if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled))
- printk ("FM warning: Invalid patch format field (key) 0x%04x\n", instr->key);
+ printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key);
memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr));
return 0;
@@ -362,7 +367,7 @@ set_voice_volume (int voice, int volume)
vol2 = instr->operators[3];
if ((instr->operators[10] & 0x01))
- { /* Additive synthesis */
+ { /* Additive synthesis */
calc_vol (&vol1, volume);
calc_vol (&vol2, volume);
}
@@ -616,7 +621,7 @@ freq_to_fnum (int freq, int *block, int *fnum)
}
static void
-opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
+opl3_command (int io_addr, unsigned int addr, unsigned int val)
{
int i;
@@ -625,7 +630,7 @@ opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
* register. The OPL-3 survives with just two INBs
*/
- OUTB (addr, io_addr); /* Select register */
+ OUTB ((unsigned char) (addr & 0xff), io_addr); /* Select register */
if (!opl3_enabled)
tenmicrosec ();
@@ -633,7 +638,7 @@ opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
for (i = 0; i < 2; i++)
INB (io_addr);
- OUTB (val, io_addr + 1); /* Write to register */
+ OUTB ((unsigned char) (val & 0xff), io_addr + 1); /* Write to register */
if (!opl3_enabled)
{
@@ -745,6 +750,11 @@ opl3_panning (int dev, int voice, int pressure)
{
}
+static void
+opl3_volume_method (int dev, int mode)
+{
+}
+
#define SET_VIBRATO(cell) { \
tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \
if (pressure > 110) \
@@ -850,7 +860,7 @@ opl3_controller (int dev, int voice, int ctrl_num, int value)
opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); /* KEYON|OCTAVE|MS bits
- * of f-num */
+ * of f-num */
voices[voice].keyon_byte = data;
opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
break;
@@ -884,6 +894,7 @@ static struct synth_operations opl3_operations =
opl3_aftertouch,
opl3_controller,
opl3_panning,
+ opl3_volume_method,
opl3_patchmgr
};
@@ -892,17 +903,26 @@ opl3_init (long mem_start)
{
int i;
+ PERMANENT_MALLOC (struct sbi_instrument *, instrmap,
+ SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
+
synth_devs[num_synths++] = &opl3_operations;
fm_model = 0;
opl3_ok = 1;
if (opl3_enabled)
{
+#ifdef __FreeBSD__
printk ("snd1: <Yamaha OPL-3 FM>");
+#else
+ printk (" <Yamaha OPL-3 FM>");
+#endif
fm_model = 2;
nr_voices = 18;
fm_info.nr_drums = 0;
fm_info.capabilities |= SYNTH_CAP_OPL3;
+#ifndef SCO
strcpy (fm_info.name, "Yamaha OPL-3");
+#endif
for (i = 0; i < 18; i++)
if (physical_voices[i].ioaddr == USE_LEFT)
@@ -917,7 +937,11 @@ opl3_init (long mem_start)
}
else
{
+#ifdef __FreeBSD__
printk ("snd1: <Yamaha 2-OP FM>");
+#else
+ printk (" <Yamaha 2-OP FM>");
+#endif
fm_model = 1;
nr_voices = 9;
fm_info.nr_drums = 0;
diff --git a/sys/i386/isa/sound/os.h b/sys/i386/isa/sound/os.h
index fba20980c3f0..c6b688ac6aa9 100644
--- a/sys/i386/isa/sound/os.h
+++ b/sys/i386/isa/sound/os.h
@@ -3,7 +3,7 @@
/*
* OS specific settings for FreeBSD
*
- * Copyright by Hannu Savolainen 1993
+ * Copyright by UWM - comments to soft-eng@cs.uwm.edu
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * This should be used as an example when porting the driver to a new
+ * This chould be used as an example when porting the driver to a new
* operating systems.
*
* What you should do is to rewrite the soundcard.c and os.h (this file).
@@ -44,7 +44,6 @@
#include "param.h"
#include "systm.h"
-#include "kernel.h"
#include "ioctl.h"
#include "tty.h"
#include "proc.h"
@@ -52,6 +51,7 @@
#include "conf.h"
#include "file.h"
#include "uio.h"
+#include "kernel.h"
#include "syslog.h"
#include "errno.h"
#include "malloc.h"
@@ -63,10 +63,6 @@
*/
#ifdef CONFIGURE_SOUNDCARD
-/* lbolt is required by the FreeBSD version (only???) */
-extern int __timeout_val;
-extern int __process_aborting;
-
/*
* select() is currently implemented in Linux specific way. Don't enable.
* I don't remember what the SHORT_BANNERS means so forget it.
@@ -163,14 +159,25 @@ typedef struct uio snd_rw_buf;
* The following macros define an interface to the process management.
*/
+struct snd_wait {
+ int mode; int aborting;
+ };
+
/*
* DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define
* a structure which can be passed as a parameter to a sleep(). The second
* parameter is name of a flag variable (must be defined as int).
*/
-#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; static int flag = 0
+#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; \
+ static volatile struct snd_wait flag = {0}
/* Like the above but defines an array of wait queues and flags */
-#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; static int flag = {0}
+#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; \
+ static volatile struct snd_wait flag = {{0}}
+
+#define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;}
+#define SET_ABORT_FLAG(q, f) f.aborting = 1
+#define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT)
+#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
/*
* This driver handles interrupts little bit nonstandard way. The following
* macro is used to test if the current process has received a signal which
@@ -179,34 +186,28 @@ typedef struct uio snd_rw_buf;
* 1 or 0 could be returned (1 should be better than 0).
* I'm not sure if the following is correct for FreeBSD.
*/
-#define PROCESS_ABORTING (__process_aborting | curproc->p_sig)
-/*
- * REQUEST_TIMEOUT is called before sleep. It shoud ensure that the
- * process is woken up after given number of ticks (1/HZ secs.).
- * The wqueue gives the wait queue.
- */
-#define REQUEST_TIMEOUT(nticks, wqueue) __timeout_val = nticks;
+#define PROCESS_ABORTING(q, f) (f.aborting | curproc->p_sig)
/*
* The following macro calls sleep. It should be implemented such that
* the process is resumed if it receives a signal. The following is propably
* not the way how it should be done on 386bsd.
- * The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE()
- * The second parameter is a flag. It must be initialized to 1 before sleep
- * and to zero after proces continues.
+ * The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE(),
+ * and the second is a workarea parameter. The third is a timeout
+ * in ticks. Zero means no timeout.
*/
-#define INTERRUPTIBLE_SLEEP_ON(on_what, flag) \
+#define DO_SLEEP(q, f, time_limit) \
{ \
- flag = 1; \
- flag=tsleep((caddr_t)&(on_what), (PRIBIO-5)|PCATCH, "sndint", __timeout_val); \
- if(flag == ERESTART) __process_aborting = 1;\
- else __process_aborting = 0;\
- __timeout_val = 0; \
- flag = 0; \
+ int flag, chn; \
+ f.mode = WK_SLEEP; \
+ q = &chn; \
+ flag=tsleep((caddr_t)&(chn), (PRIBIO-5)|PCATCH, "sndint", time_limit); \
+ if(flag == ERESTART) f.aborting = 1;\
+ else f.aborting = 0;\
+ f.mode &= ~WK_SLEEP; \
}
-
/* An the following wakes up a process */
-#define WAKE_UP(who) wakeup((caddr_t)&(who))
+#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wakeup((caddr_t)q);}
/*
* Timing macros. This driver assumes that there is a timer running in the
@@ -215,6 +216,7 @@ typedef struct uio snd_rw_buf;
*/
#ifndef HZ
+extern int hz;
#define HZ hz
#endif
@@ -223,9 +225,9 @@ typedef struct uio snd_rw_buf;
* ticks. This can overflow, so the timeout might be real big...
*
*/
+extern unsigned long get_time(void);
#define GET_TIME() get_time()
-extern long get_time(void);
-/*#define GET_TIME() (lbolt)*/ /* Returns current time (1/HZ secs since boot) */
+/*#define GET_TIME() (lbolt) */ /* Returns current time (1/HZ secs since boot) */
/*
* The following three macros are called before and after atomic
@@ -248,7 +250,11 @@ extern long get_time(void);
*/
#define INB inb
-#define OUTB(addr, data) outb(data, addr)
+/*
+ * The outb(0, 0x80) is just for slowdown. It's bit unsafe since
+ * this address could be used for something usefull.
+ */
+#define OUTB(addr, data) {outb(data, addr);outb(0, 0x80);}
/* memcpy() was not defined og 386bsd. Lets define it here */
#define memcpy(d, s, c) bcopy(s, d, c)
@@ -274,6 +280,32 @@ extern long get_time(void);
#define KERNEL_FREE(addr) free(addr, M_TEMP)
/*
+ * The macro PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr)
+ * returns size bytes of
+ * (kernel virtual) memory which will never get freed by the driver.
+ * This macro is called only during boot. The linux_ptr is a linux specific
+ * parameter which should be ignored in other operating systems.
+ * The mem_ptr is a pointer variable where the macro assigns pointer to the
+ * memory area. The type is the type of the mem_ptr.
+ */
+#define PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) \
+ (mem_ptr) = (typecast)malloc((size), M_TEMP, M_WAITOK)
+
+/*
+ * The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if
+ * required. The name is the variable/name to be used and the proc is
+ * the procedure to be called when the timer expires.
+ */
+
+#define DEFINE_TIMER(name, proc)
+
+/*
+ * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
+ */
+
+#define ACTIVATE_TIMER(name, proc, time) \
+ timeout((timeout_func_t)proc, 0, time);
+/*
* The rest of this file is not complete yet. The functions using these
* macros will not work
*/
diff --git a/sys/i386/isa/sound/pas.h b/sys/i386/isa/sound/pas.h
index 4dadea3713b8..55d83737b609 100644
--- a/sys/i386/isa/sound/pas.h
+++ b/sys/i386/isa/sound/pas.h
@@ -128,24 +128,26 @@
#define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */
#define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */
+#define CHIP_REV 0xFF88 /* R 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */
#define PAS_NONE 0
#define PAS_PLUS 1
#define PAS_CDPC 2
#define PAS_16 3
+#define PAS_16D 4
#ifdef DEFINE_TRANSLATIONS
char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */
{ 4, 1, 2, 3, 0, 5, 6, 7 };
char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */
- { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 };
+ { 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 };
char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */
- { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x05, 0x06, 0x07 };
+ { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 };
char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */
- { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x00, 0x28, 0x30, 0x38 };
+ { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 };
char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */
- { 0x00, 0x40, 0x80, 0xC0 };
+ { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
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, 3, 0, 2, 3 };
+ { 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 */
diff --git a/sys/i386/isa/sound/pas2_card.c b/sys/i386/isa/sound/pas2_card.c
index 96fe651fbaac..a8b79df2c8cd 100644
--- a/sys/i386/isa/sound/pas2_card.c
+++ b/sys/i386/isa/sound/pas2_card.c
@@ -1,12 +1,12 @@
#define _PAS2_CARD_C_
#define SND_SA_INTERRUPT
/*
- * linux/kernel/chr_drv/sound/pas2_card.c
- *
+ * sound/pas2_card.c
+ *
* Detection routine for the Pro Audio Spectrum cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -14,7 +14,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -26,7 +26,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -46,8 +46,9 @@ static int pas_intr_mask = 0;
static int pas_irq = 0;
static char pas_model;
+static unsigned char board_rev_id;
static char *pas_model_names[] =
-{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16"};
+{"", "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 */
@@ -65,6 +66,23 @@ pas_write (unsigned char data, int ioaddr)
OUTB (data, ioaddr ^ translat_code);
}
+/*
+ * The Revision D cards have a problem with their MVA508 interface. The
+ * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
+ * MSBs out of the output byte and to do a 16-bit out to the mixer port -
+ * 1.
+ */
+
+void
+mix_write (unsigned char data, int ioaddr)
+{
+ if (pas_model == PAS_16D) {
+ outw ((ioaddr ^ translat_code) - 1, data | (data << 8));
+ outb (0, 0x80);
+ } else
+ OUTB (data, ioaddr ^ translat_code);
+}
+
void
pas2_msg (char *foo)
{
@@ -100,39 +118,6 @@ pasintr (int unused)
}
-static int
-set_pas_irq (int interrupt_level)
-{
-#ifdef linux
- int retcode;
- struct sigaction sa;
-
- pas_write (0xff, INTERRUPT_STATUS); /* Reset pending interrupts */
-
- sa.sa_handler = pasintr;
-
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
-
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
-
- retcode = irqaction (interrupt_level, &sa);
-
- if (retcode < 0)
- {
- printk ("ProAudioSpectrum: IRQ%d already in use\n", interrupt_level);
- }
- return retcode;
-#else
- /* # error This routine does not work with this OS */
- return EINVAL;
-#endif
-}
-
int
pas_set_intr (int mask)
{
@@ -143,7 +128,7 @@ pas_set_intr (int mask)
if (!pas_intr_mask)
{
- if ((err = set_pas_irq (pas_irq)) < 0)
+ if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0)
return err;
}
pas_intr_mask |= mask;
@@ -163,7 +148,7 @@ pas_remove_intr (int mask)
if (!pas_intr_mask)
{
- RELEASE_IRQ (pas_irq);
+ snd_release_irq (pas_irq);
}
return 0;
}
@@ -230,36 +215,66 @@ config_pas_hw (struct address_info *hw_config)
}
}
+ /*
+ * This fixes the timing problems of the PAS due to the Symphony chipset
+ * as per Media Vision. Only define this if your PAS doesn't work correctly.
+ */
+#ifdef SYMPHONY_PAS
+ OUTB (0x05, 0xa8);
+ OUTB (0x60, 0xa9);
+#endif
+
#ifdef BROKEN_BUS_CLOCK
pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
#else
/* 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(S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2); Don't do this */
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)
+ if (pas_model == PAS_16 || pas_model == PAS_16D)
pas_write (8, PRESCALE_DIVIDER);
else
pas_write (0, PRESCALE_DIVIDER);
- pas_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
- pas_write (5, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
+ mix_write (5, PARALLEL_MIXER);
#if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
- /* Turn on Sound Blaster compatibility */
- /* bit 1 = SB emulation */
- /* bit 0 = MPU401 emulation (CDPC only :-( ) */
- pas_write (0x02, COMPATIBILITY_ENABLE);
+ {
+ struct address_info *sb_config;
+
+ if ((sb_config = sound_getconf (SNDCARD_SB)))
+ {
+ unsigned char irq_dma;
- /* "Emulation address" */
- pas_write ((SBC_BASE >> 4) & 0x0f, EMULATION_ADDRESS);
+ /* Turn on Sound Blaster compatibility */
+ /* bit 1 = SB emulation */
+ /* bit 0 = MPU401 emulation (CDPC only :-( ) */
+ pas_write (0x02, COMPATIBILITY_ENABLE);
+
+ /* "Emulation address" */
+ pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
+
+ if (!E_C_SB_DMA_translate[sb_config->dma])
+ printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
+ sb_config->dma);
+
+ if (!E_C_SB_IRQ_translate[sb_config->irq])
+ printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
+ sb_config->irq);
+
+ irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
+ E_C_SB_IRQ_translate[sb_config->irq];
+
+ pas_write (irq_dma, EMULATION_CONFIGURATION);
+ }
+ }
#endif
if (!ok)
@@ -305,7 +320,7 @@ detect_pas_hw (struct address_info *hw_config)
if (board_id != foo) /* Not a PAS2 */
return 0;
- if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]));
+ pas_model = pas_read (CHIP_REV);
return pas_model;
}
@@ -318,9 +333,14 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
if (detect_pas_hw (hw_config))
{
- if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]))
+ board_rev_id = pas_read (BOARD_REV_ID);
+ if (pas_model = pas_read (CHIP_REV))
{
- printk ("snd3: <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
+#ifdef __FreeBSD__
+ printk ("snd3: <%s rev %d>", pas_model_names[(int) pas_model], board_rev_id);
+#else
+ printk (" <%s rev %d>", pas_model_names[(int) pas_model], board_rev_id);
+#endif
}
if (config_pas_hw (hw_config))
@@ -330,11 +350,11 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
mem_start = pas_pcm_init (mem_start, hw_config);
#endif
-# if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
+#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
sb_dsp_disable_midi (); /* The SB emulation don't support
* midi */
-# endif
+#endif
#ifndef EXCLUDE_YM3812
enable_opl3_mode (0x388, 0x38a, 0);
@@ -350,7 +370,6 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
}
}
- printk ("\n");
return mem_start;
}
diff --git a/sys/i386/isa/sound/pas2_midi.c b/sys/i386/isa/sound/pas2_midi.c
index 1a605905420f..4a07b0b59bf8 100644
--- a/sys/i386/isa/sound/pas2_midi.c
+++ b/sys/i386/isa/sound/pas2_midi.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/pas2_midi.c
- *
+ * sound/pas2_midi.c
+ *
* The low level driver for the PAS Midi Interface.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -212,7 +212,7 @@ pas_buffer_status (int dev)
static struct midi_operations pas_midi_operations =
{
- {"Pro Audio Spectrum", 0},
+ {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
pas_midi_open,
pas_midi_close,
pas_midi_ioctl,
@@ -283,7 +283,7 @@ pas_midi_interrupt (void)
if (stat & M_S_OUTPUT_OVERRUN)
{
- printk ("MIDI output overrun %02x,%02x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
+ printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
ofifo_bytes = 100;
}
diff --git a/sys/i386/isa/sound/pas2_mixer.c b/sys/i386/isa/sound/pas2_mixer.c
index 33135d24e859..b3868773d64c 100644
--- a/sys/i386/isa/sound/pas2_mixer.c
+++ b/sys/i386/isa/sound/pas2_mixer.c
@@ -1,12 +1,12 @@
#define _PAS2_MIXER_C_
/*
- * linux/kernel/chr_drv/sound/pas2_mixer.c
- *
+ * sound/pas2_mixer.c
+ *
* Mixer routines for the Pro Audio Spectrum cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -14,7 +14,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -26,7 +26,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -46,7 +46,7 @@ static int mode_control = 0;
SOUND_MASK_CD | SOUND_MASK_ALTPCM)
#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
- SOUND_MASK_CD /*|SOUND_MASK_ALTPCM*/ | SOUND_MASK_IMIX | \
+ SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
@@ -72,14 +72,6 @@ mixer_output (int right_vol, int left_vol, int div, int bits,
int left = left_vol * div / 100;
int right = right_vol * div / 100;
- /*
- * The Revision D cards have a problem with their MVA508 interface. The
- * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
- * MSBs out of the output byte and to do a 16-bit out to the mixer port -
- * 1. We don't need to do this because the call to pas_write more than
- * compensates for the timing problems.
- */
-
if (bits & P_M_MV508_MIXER)
{ /* Select input or output mixer */
left |= mixer;
@@ -87,17 +79,17 @@ mixer_output (int right_vol, int left_vol, int div, int bits,
}
if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
- { /* Bass and trebble are mono devices */
- pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
- pas_write (left, PARALLEL_MIXER);
+ { /* Bass and trebble are mono devices */
+ mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
+ mix_write (left, PARALLEL_MIXER);
right_vol = left_vol;
}
else
{
- pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
- pas_write (left, PARALLEL_MIXER);
- pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
- pas_write (right, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
+ mix_write (left, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
+ mix_write (right, PARALLEL_MIXER);
}
return (left_vol | (right_vol << 8));
@@ -106,8 +98,8 @@ mixer_output (int right_vol, int left_vol, int div, int bits,
void
set_mode (int new_mode)
{
- pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
- pas_write (new_mode, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
+ mix_write (new_mode, PARALLEL_MIXER);
mode_control = new_mode;
}
diff --git a/sys/i386/isa/sound/pas2_pcm.c b/sys/i386/isa/sound/pas2_pcm.c
index 878de5aaca94..b6d53fbccd01 100644
--- a/sys/i386/isa/sound/pas2_pcm.c
+++ b/sys/i386/isa/sound/pas2_pcm.c
@@ -1,11 +1,11 @@
#define _PAS2_PCM_C_
/*
- * linux/kernel/chr_drv/sound/pas2_pcm.c
- *
+ * sound/pas2_pcm.c
+ *
* The low level driver for the Pro Audio Spectrum ADC/DAC.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -13,7 +13,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -25,7 +25,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
@@ -75,6 +75,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);
@@ -148,6 +173,8 @@ pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
break;
case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return pcm_set_channels (arg);
return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
break;
@@ -200,12 +227,6 @@ pas_pcm_open (int dev, int mode)
TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
- if (mode != OPEN_READ && mode != OPEN_WRITE)
- {
- printk ("PAS2: Attempt to open PCM device for simultaneous read and write");
- return RET_ERROR (EINVAL);
- }
-
if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
return err;
@@ -217,10 +238,6 @@ pas_pcm_open (int dev, int mode)
pcm_count = 0;
- pcm_set_bits (8);
- pcm_set_channels (1);
- pcm_set_speed (DSP_DEFAULT_SPEED);
-
return 0;
}
@@ -242,7 +259,8 @@ pas_pcm_close (int dev)
}
static void
-pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
+pas_pcm_output_block (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags, cnt;
@@ -251,7 +269,6 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
cnt = count;
if (sound_dsp_dmachan[dev] > 3)
cnt >>= 1;
- cnt--;
if (sound_dma_automode[dev] &&
intrflag &&
@@ -263,11 +280,11 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
PCM_CONTROL);
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+ if (restart_dma)
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
- count--;
if (count != pcm_count)
{
@@ -288,7 +305,8 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
}
static void
-pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
+pas_pcm_start_input (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags;
int cnt;
@@ -298,7 +316,6 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
cnt = count;
if (sound_dsp_dmachan[dev] > 3)
cnt >>= 1;
- cnt--;
if (sound_dma_automode[my_devnum] &&
intrflag &&
@@ -307,13 +324,12 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
DISABLE_INTR (flags);
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+ if (restart_dma)
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
- count--;
-
if (count != pcm_count)
{
pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
@@ -346,14 +362,15 @@ pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
static struct audio_operations pas_pcm_operations =
{
"Pro Audio Spectrum",
- pas_pcm_open, /* */
- pas_pcm_close, /* */
- pas_pcm_output_block, /* */
- pas_pcm_start_input, /* */
- pas_pcm_ioctl, /* */
- pas_pcm_prepare_for_input, /* */
- pas_pcm_prepare_for_output, /* */
- pas_pcm_reset, /* */
+ NOTHING_SPECIAL,
+ pas_pcm_open,
+ pas_pcm_close,
+ pas_pcm_output_block,
+ pas_pcm_start_input,
+ pas_pcm_ioctl,
+ pas_pcm_prepare_for_input,
+ pas_pcm_prepare_for_output,
+ pas_pcm_reset,
pas_pcm_reset, /* halt_xfer */
NULL, /* has_output_drained */
NULL /* copy_from_user */
@@ -374,6 +391,7 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
{
dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
sound_dsp_dmachan[my_devnum] = hw_config->dma;
+#ifndef NO_AUTODMA
if (hw_config->dma > 3)
{
sound_buffcounts[my_devnum] = 1;
@@ -386,6 +404,11 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
sound_dma_automode[my_devnum] = 1;
}
+#else
+ sound_buffcounts[my_devnum] = DSP_BUFFCOUNT;
+ sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
+ sound_dma_automode[my_devnum] = 0;
+#endif
}
else
printk ("PAS2: Too many PCM devices available\n");
@@ -413,7 +436,7 @@ pas_pcm_interrupt (unsigned char status, int cause)
{
case PCM_DAC:
- DMAbuf_outputintr (my_devnum);
+ DMAbuf_outputintr (my_devnum, 1);
break;
case PCM_ADC:
diff --git a/sys/i386/isa/sound/patmgr.c b/sys/i386/isa/sound/patmgr.c
index 140a42845e5b..042d42d4067c 100644
--- a/sys/i386/isa/sound/patmgr.c
+++ b/sys/i386/isa/sound/patmgr.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/patmgr.c
- *
+ * sound/patmgr.c
+ *
* The patch maneger interface for the /dev/sequencer
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#define PATMGR_C
@@ -58,6 +58,8 @@ pmgr_open (int dev)
return RET_ERROR (EBUSY);
pmgr_opened[dev] = 1;
+ RESET_WAIT_QUEUE (server_procs[dev], server_wait_flag[dev]);
+
return 0;
}
@@ -71,8 +73,8 @@ pmgr_release (int dev)
mbox[dev]->key = PM_ERROR;
mbox[dev]->parm1 = RET_ERROR (EIO);
- if (appl_wait_flag)
- WAKE_UP (appl_proc);
+ if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
+ WAKE_UP (appl_proc, appl_wait_flag);
}
pmgr_opened[dev] = 0;
@@ -90,13 +92,14 @@ pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
return RET_ERROR (EIO);
}
- while (!ok && !PROCESS_ABORTING)
+ while (!ok && !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
{
DISABLE_INTR (flags);
- while (!(mbox[dev] && msg_direction[dev] == A_TO_S) && !PROCESS_ABORTING)
+ while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
+ !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
{
- INTERRUPTIBLE_SLEEP_ON (server_procs[dev], server_wait_flag[dev]);
+ DO_SLEEP (server_procs[dev], server_wait_flag[dev], 0);
}
if (mbox[dev] && msg_direction[dev] == A_TO_S)
@@ -158,9 +161,9 @@ pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
COPY_FROM_USER (&((char *) mbox[dev])[4], buf, 4, count - 4);
msg_direction[dev] = S_TO_A;
- if (appl_wait_flag)
+ if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
{
- WAKE_UP (appl_proc);
+ WAKE_UP (appl_proc, appl_wait_flag);
}
}
@@ -185,12 +188,12 @@ pmgr_access (int dev, struct patmgr_info *rec)
mbox[dev] = rec;
msg_direction[dev] = A_TO_S;
- if (server_wait_flag[dev])
+ if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
{
- WAKE_UP (server_procs[dev]);
+ WAKE_UP (server_procs[dev], server_wait_flag[dev]);
}
- INTERRUPTIBLE_SLEEP_ON (appl_proc, appl_wait_flag);
+ DO_SLEEP (appl_proc, appl_wait_flag, 0);
if (msg_direction[dev] != S_TO_A)
{
@@ -239,12 +242,12 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2,
mbox[dev]->parm3 = p3;
msg_direction[dev] = A_TO_S;
- if (server_wait_flag[dev])
+ if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
{
- WAKE_UP (server_procs[dev]);
+ WAKE_UP (server_procs[dev], server_wait_flag[dev]);
}
- INTERRUPTIBLE_SLEEP_ON (appl_proc, appl_wait_flag);
+ DO_SLEEP (appl_proc, appl_wait_flag, 0);
if (mbox[dev])
KERNEL_FREE (mbox[dev]);
mbox[dev] = NULL;
diff --git a/sys/i386/isa/sound/pro_midi.c b/sys/i386/isa/sound/pro_midi.c
index 606657d403da..b9ffa26a9ab2 100644
--- a/sys/i386/isa/sound/pro_midi.c
+++ b/sys/i386/isa/sound/pro_midi.c
@@ -1,5 +1,5 @@
/*
- * Copyright by UWM -- comments to soft-eng@cs.uwm.edu
+ * Copyright by UWM - comments to soft-eng@cs.uwm.edu
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,140 +37,148 @@
/** Structure for handling operations **/
-static struct generic_midi_operations pro_midi_operations = {
+static struct generic_midi_operations pro_midi_operations =
+{
- {"Pro_Audio_Spectrum 16 MV101", 0},
- pro_midi_open,
- pro_midi_close,
- pro_midi_write,
- pro_midi_read
+ {"Pro_Audio_Spectrum 16 MV101", 0},
+ pro_midi_open,
+ pro_midi_close,
+ pro_midi_write,
+ pro_midi_read
};
/*
- * Note! Note! Note!
- * Follow the same model for any other attach function you
+ * Note! Note! Note! Follow the same model for any other attach function you
* may write
*/
-long pro_midi_attach( long mem_start)
+long
+pro_midi_attach (long mem_start)
{
pro_midi_dev = num_generic_midis;
generic_midi_devs[num_generic_midis++] = &pro_midi_operations;
return mem_start;
-}
+}
-int pro_midi_open(int dev, int mode)
+int
+pro_midi_open (int dev, int mode)
{
- int intr_mask, s;
+ int intr_mask, s;
- s = splhigh();
+ s = splhigh ();
- /* Reset the input and output FIFO pointers */
+ /* Reset the input and output FIFO pointers */
- outb(MIDI_CONTROL,M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
+ outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
- /* Get the interrupt status */
+ /* Get the interrupt status */
- intr_mask = inb(INTERRUPT_MASK);
+ intr_mask = inb (INTERRUPT_MASK);
- /* Enable MIDI IRQ */
+ /* Enable MIDI IRQ */
- intr_mask |= I_M_MIDI_IRQ_ENABLE;
- outb(INTERRUPT_MASK, intr_mask);
+ intr_mask |= I_M_MIDI_IRQ_ENABLE;
+ outb (INTERRUPT_MASK, intr_mask);
/* Enable READ/WRITE on MIDI port. This part is quite unsure though */
- outb(MIDI_CONTROL,M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ);
+ outb (MIDI_CONTROL, M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ);
/* Acknowledge pending interrupts */
- outb(MIDI_STATUS,0xff);
+ outb (MIDI_STATUS, 0xff);
- splx(s);
+ splx (s);
- return(ESUCCESS);
+ return (ESUCCESS);
}
-void pro_midi_close(int dev)
+void
+pro_midi_close (int dev)
{
- int intr_mask;
+ int intr_mask;
- /* Clean up */
+ /* Clean up */
- outb(MIDI_CONTROL,M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
- intr_mask = inb(INTERRUPT_MASK);
- intr_mask &= ~I_M_MIDI_IRQ_ENABLE;
- outb(INTERRUPT_MASK,intr_mask);
+ outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
+ intr_mask = inb (INTERRUPT_MASK);
+ intr_mask &= ~I_M_MIDI_IRQ_ENABLE;
+ outb (INTERRUPT_MASK, intr_mask);
- return;
+ return;
}
-int pro_midi_write(int dev, struct uio *uio)
+int
+pro_midi_write (int dev, struct uio *uio)
{
- int s;
- unsigned char data;
+ int s;
+ unsigned char data;
- /* printf("midi: Going to do write routine..\n"); */
- while(uio->uio_resid) {
+ /* printf("midi: Going to do write routine..\n"); */
+ while (uio->uio_resid)
+ {
- if ( uiomove(&data,1,uio) ) return(ENOTTY);
+ if (uiomove (&data, 1, uio))
+ return (ENOTTY);
- s = splhigh();
+ s = splhigh ();
- DELAY(30);
- outb(MIDI_DATA,data);
- DELAY(70); /* Ze best pause.. find a better one if
- * you can :)
- */
- splx(s);
- }
+ DELAY (30);
+ outb (MIDI_DATA, data);
+ DELAY (70); /* Ze best pause.. find a better one if you
+ * can :) */
+ splx (s);
+ }
- return(ESUCCESS);
+ return (ESUCCESS);
}
-int pro_midi_read(int dev, struct uio *uio)
+int
+pro_midi_read (int dev, struct uio *uio)
{
- int s;
- unsigned char data;
+ int s;
+ unsigned char data;
- s = splhigh();
+ s = splhigh ();
- /* For each uio_iov[] entry .... */
+ /* For each uio_iov[] entry .... */
- while (uio->uio_resid) {
+ while (uio->uio_resid)
+ {
- if((( inb(MIDI_STATUS) & M_S_INPUT_AVAIL) == 0 ) &&
- ((inb(MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0 ) )
+ if (((inb (MIDI_STATUS) & M_S_INPUT_AVAIL) == 0) &&
+ ((inb (MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0))
- data = 0xfe;
- else
- data = inb(MIDI_DATA);
+ data = 0xfe;
+ else
+ data = inb (MIDI_DATA);
- if ( uiomove(&data, 1 , uio)) {
+ if (uiomove (&data, 1, uio))
+ {
- printf("midi: Bad copyout()!\n");
- return(ENOTTY);
+ printf ("midi: Bad copyout()!\n");
+ return (ENOTTY);
- }
+ }
- }
- splx(s);
- return(ESUCCESS);
+ }
+ splx (s);
+ return (ESUCCESS);
}
diff --git a/sys/i386/isa/sound/sb.h b/sys/i386/isa/sound/sb.h
new file mode 100644
index 000000000000..bb8ae12d7e60
--- /dev/null
+++ b/sys/i386/isa/sound/sb.h
@@ -0,0 +1,28 @@
+#define DSP_RESET (sbc_base + 0x6)
+#define DSP_READ (sbc_base + 0xA)
+#define DSP_WRITE (sbc_base + 0xC)
+#define DSP_COMMAND (sbc_base + 0xC)
+#define DSP_STATUS (sbc_base + 0xC)
+#define DSP_DATA_AVAIL (sbc_base + 0xE)
+#define DSP_DATA_AVL16 (sbc_base + 0xF)
+#define MIXER_ADDR (sbc_base + 0x4)
+#define MIXER_DATA (sbc_base + 0x5)
+#define OPL3_LEFT (sbc_base + 0x0)
+#define OPL3_RIGHT (sbc_base + 0x2)
+#define OPL3_BOTH (sbc_base + 0x8)
+/* DSP Commands */
+
+#define DSP_CMD_SPKON 0xD1
+#define DSP_CMD_SPKOFF 0xD3
+#define DSP_CMD_DMAON 0xD0
+#define DSP_CMD_DMAOFF 0xD4
+
+#define IMODE_NONE 0
+#define IMODE_OUTPUT 1
+#define IMODE_INPUT 2
+#define IMODE_INIT 3
+#define IMODE_MIDI 4
+
+#define NORMAL_MIDI 0
+#define UART_MIDI 1
+
diff --git a/sys/i386/isa/sound/sb16_dsp.c b/sys/i386/isa/sound/sb16_dsp.c
new file mode 100644
index 000000000000..b545f8cac222
--- /dev/null
+++ b/sys/i386/isa/sound/sb16_dsp.c
@@ -0,0 +1,627 @@
+/*
+ * sound/sb16_dsp.c
+ *
+ * The low level driver for the SoundBlaster DSP chip.
+ *
+ * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de)
+ *
+ * based on SB-driver by (C) Hannu Savolainen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * 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)
+/*
+ #define DEB_DMARES
+ */
+#include "sound_config.h"
+#include "sb.h"
+#include "sb_mixer.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
+
+extern int sbc_base, sbc_minor, sbc_major;
+
+static int sb16_dsp_ok = 0;/* Set to 1 after successful initialization */
+static int dsp_16bit = 0;
+static int dsp_stereo = 0;
+static int dsp_current_speed = 8000; /*DSP_DEFAULT_SPEED; */
+static int dsp_busy = 0;
+static int dma16, dma8;
+static unsigned long dsp_count = 0;
+
+static int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT or
+
+ IMODE_NONE */
+static int my_dev = 0;
+
+static volatile int intr_active = 0;
+
+static int sb16_dsp_open (int dev, int mode);
+static void sb16_dsp_close (int dev);
+static void sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static void sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static int sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
+static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
+static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
+static void sb16_dsp_reset (int dev);
+static void sb16_dsp_halt (int dev);
+static int dsp_set_speed (int);
+static int dsp_set_stereo (int);
+static void dsp_cleanup (void);
+int sb_reset_dsp (void);
+
+static struct audio_operations sb16_dsp_operations =
+{
+ "SoundBlaster 16",
+ NOTHING_SPECIAL,
+ sb16_dsp_open,
+ sb16_dsp_close,
+ sb16_dsp_output_block,
+ sb16_dsp_start_input,
+ sb16_dsp_ioctl,
+ sb16_dsp_prepare_for_input,
+ sb16_dsp_prepare_for_output,
+ sb16_dsp_reset,
+ sb16_dsp_halt,
+ NULL,
+ NULL
+};
+
+static int
+sb_dsp_command01 (unsigned char val)
+{
+ int i = 1 << 16;
+
+ while (--i & (!INB (DSP_STATUS) & 0x80));
+ if (!i)
+ printk ("SB16 sb_dsp_command01 Timeout\n");
+ return sb_dsp_command (val);
+}
+
+static int
+wait_data_avail (unsigned long t)
+{
+ int loopc = 5000000;
+
+ t += GET_TIME ();
+ do
+ {
+ if (INB (DSP_DATA_AVAIL) & 0x80)
+ return 1;
+ }
+ while (--loopc && GET_TIME () < t);
+ printk ("!data_avail l=%d\n", loopc);
+ return 0;
+}
+
+static int
+read_dsp (int t)
+{
+ if (!wait_data_avail ((unsigned long) t))
+ return -1;
+ else
+ return INB (DSP_READ);
+}
+
+static int
+dsp_ini2 (void)
+{
+#if 0
+ /* sb_setmixer(0x83, sb_getmixer(0x83) | 0x03); */
+ sb_dsp_command (0xe2);
+ sb_dsp_command (0x76); /* E0 ??? */
+ sb_dsp_command (0xe2);
+ sb_dsp_command (0x30); /* A0 ??? */
+ sb_dsp_command (0xe4);
+ sb_dsp_command (0xaa);
+ sb_dsp_command (0xe8);
+ if (read_dsp (100) != 0xaa)
+ printk ("Error dsp_ini2\n");
+#endif
+ return 0;
+}
+
+/*
+ static char *dsp_getmessage(unsigned char command,int maxn)
+ {
+ static char buff[100];
+ int n=0;
+
+ sb_dsp_command(command);
+ while(n<maxn && wait_data_avail(2L)) {
+ buff[++n]=INB(DSP_READ);
+ if(!buff[n])
+ break;
+ }
+ buff[0]=n;
+ return buff;
+ }
+
+ static void dsp_showmessage(unsigned char command,int len)
+ {
+ int n;
+ unsigned char *c;
+ c=dsp_getmessage(command,len);
+ printk("DSP C=%x l=%d,lr=%d b=",command,len,c[0]);
+ for(n=1;n<=c[0];n++)
+ if(c[n]>=' ' & c[n]<='z')
+ printk("%c",c[n]);
+ else
+ printk("|%x|",c[n]);
+ printk("\n");
+ }
+ */
+static int
+dsp_set_speed (int mode)
+{
+ DEB (printk ("dsp_set_speed(%d)\n", mode));
+ if (mode)
+ {
+ if (mode < 5000)
+ mode = 5000;
+ if (mode > 44100)
+ mode = 44100;
+ dsp_current_speed = mode;
+ }
+ return mode;
+}
+
+static int
+dsp_set_stereo (int mode)
+{
+ DEB (printk ("dsp_set_stereo(%d)\n", mode));
+
+ dsp_stereo = mode;
+
+ return mode;
+}
+
+static int
+dsp_set_bits (int arg)
+{
+ DEB (printk ("dsp_set_bits(%d)\n", arg));
+
+ if (arg)
+ switch (arg)
+ {
+ case 8:
+ dsp_16bit = 0;
+ break;
+ case 16:
+ dsp_16bit = 1;
+ break;
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ return dsp_16bit ? 16 : 8;
+}
+
+static int
+sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ switch (cmd)
+ {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return dsp_set_speed (arg);
+ return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg)));
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return dsp_current_speed;
+ return IOCTL_OUT (arg, dsp_current_speed);
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return dsp_set_stereo (arg);
+ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return dsp_set_stereo (arg - 1) + 1;
+ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return dsp_stereo + 1;
+ return IOCTL_OUT (arg, dsp_stereo + 1);
+
+ case SNDCTL_DSP_SAMPLESIZE:
+ if (local)
+ return dsp_set_bits (arg);
+ return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return dsp_16bit ? 16 : 8;
+ return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
+
+ case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
+ if (IOCTL_IN (arg) > 1)
+ return IOCTL_OUT (arg, RET_ERROR (EINVAL));
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+static int
+sb16_dsp_open (int dev, int mode)
+{
+ int retval;
+
+ DEB (printk ("sb16_dsp_open()\n"));
+ if (!sb16_dsp_ok)
+ {
+ printk ("SB16 Error: SoundBlaster board not installed\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (intr_active)
+ return RET_ERROR (EBUSY);
+
+ retval = sb_get_irq ();
+ if (retval < 0)
+ return retval;
+
+ if (ALLOC_DMA_CHN (dma8))
+ {
+ printk ("SB16: Unable to grab DMA%d\n", dma8);
+ sb_free_irq ();
+ return RET_ERROR (EBUSY);
+ }
+
+ if (dma16 != dma8)
+ if (ALLOC_DMA_CHN (dma16))
+ {
+ printk ("SB16: Unable to grab DMA%d\n", dma16);
+ sb_free_irq ();
+ RELEASE_DMA_CHN (dma8);
+ return RET_ERROR (EBUSY);
+ }
+
+ dsp_ini2 ();
+
+ irq_mode = IMODE_NONE;
+ dsp_busy = 1;
+
+ return 0;
+}
+
+static void
+sb16_dsp_close (int dev)
+{
+ unsigned long flags;
+
+ DEB (printk ("sb16_dsp_close()\n"));
+ sb_dsp_command01 (0xd9);
+ sb_dsp_command01 (0xd5);
+
+ DISABLE_INTR (flags);
+ RELEASE_DMA_CHN (dma8);
+
+ if (dma16 != dma8)
+ RELEASE_DMA_CHN (dma16);
+ sb_free_irq ();
+ dsp_cleanup ();
+ dsp_busy = 0;
+ RESTORE_INTR (flags);
+}
+
+static void
+sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+ unsigned long flags, cnt;
+
+ cnt = count;
+ if (dsp_16bit)
+ cnt >>= 1;
+ cnt--;
+
+#ifdef DEB_DMARES
+ printk ("output_block: %x %d %d\n", buf, count, intrflag);
+ if (intrflag)
+ {
+ int pos, chan = sound_dsp_dmachan[dev];
+
+ DISABLE_INTR (flags);
+ clear_dma_ff (chan);
+ disable_dma (chan);
+ pos = get_dma_residue (chan);
+ enable_dma (chan);
+ RESTORE_INTR (flags);
+ printk ("dmapos=%d %x\n", pos, pos);
+ }
+#endif
+ if (sound_dma_automode[dev] &&
+ intrflag &&
+ cnt == dsp_count)
+ {
+ irq_mode = IMODE_OUTPUT;
+ intr_active = 1;
+ return; /* Auto mode on. No need to react */
+ }
+ DISABLE_INTR (flags);
+
+ if (dma_restart)
+ {
+ sb16_dsp_halt (dev);
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+ }
+ sb_dsp_command (0x41);
+ sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6));
+ sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
+ (dsp_16bit ? 0x10 : 0)));
+ sb_dsp_command01 ((unsigned char) (cnt & 0xff));
+ sb_dsp_command ((unsigned char) (cnt >> 8));
+ /* sb_dsp_command (0);
+ sb_dsp_command (0); */
+
+ RESTORE_INTR (flags);
+ dsp_count = cnt;
+ irq_mode = IMODE_OUTPUT;
+ intr_active = 1;
+}
+
+static void
+sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+ unsigned long flags, cnt;
+
+ cnt = count;
+ if (dsp_16bit)
+ cnt >>= 1;
+ cnt--;
+
+#ifdef DEB_DMARES
+ printk ("start_input: %x %d %d\n", buf, count, intrflag);
+ if (intrflag)
+ {
+ int pos, chan = sound_dsp_dmachan[dev];
+
+ DISABLE_INTR (flags);
+ clear_dma_ff (chan);
+ disable_dma (chan);
+ pos = get_dma_residue (chan);
+ enable_dma (chan);
+ RESTORE_INTR (flags);
+ printk ("dmapos=%d %x\n", pos, pos);
+ }
+#endif
+ if (sound_dma_automode[dev] &&
+ intrflag &&
+ cnt == dsp_count)
+ {
+ irq_mode = IMODE_INPUT;
+ intr_active = 1;
+ return; /* Auto mode on. No need to react */
+ }
+ DISABLE_INTR (flags);
+
+ if (dma_restart)
+ {
+ sb16_dsp_halt (dev);
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+ }
+
+ sb_dsp_command (0x42);
+ sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce));
+ sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
+ (dsp_16bit ? 0x10 : 0)));
+ sb_dsp_command01 ((unsigned char) (cnt & 0xff));
+ sb_dsp_command ((unsigned char) (cnt >> 8));
+
+ /* sb_dsp_command (0);
+ sb_dsp_command (0); */
+ RESTORE_INTR (flags);
+ dsp_count = cnt;
+ irq_mode = IMODE_INPUT;
+ intr_active = 1;
+}
+
+static int
+sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
+{
+ sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+ dsp_count = 0;
+ dsp_cleanup ();
+ return 0;
+}
+
+static int
+sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
+{
+ sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+ dsp_count = 0;
+ dsp_cleanup ();
+ return 0;
+}
+
+static void
+dsp_cleanup (void)
+{
+ irq_mode = IMODE_NONE;
+ intr_active = 0;
+}
+
+static void
+sb16_dsp_reset (int dev)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ sb_reset_dsp ();
+ dsp_cleanup ();
+
+ RESTORE_INTR (flags);
+}
+
+static void
+sb16_dsp_halt (int dev)
+{
+ if (dsp_16bit)
+ {
+ sb_dsp_command01 (0xd9);
+ sb_dsp_command01 (0xd5);
+ }
+ else
+ {
+ sb_dsp_command01 (0xda);
+ sb_dsp_command01 (0xd0);
+ }
+}
+
+static void
+set_irq_hw (int level)
+{
+ int ival;
+
+ switch (level)
+ {
+ case 5:
+ ival = 2;
+ break;
+ case 7:
+ ival = 4;
+ break;
+ case 10:
+ ival = 8;
+ break;
+ default:
+ printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
+ return;
+ }
+ sb_setmixer (IRQ_NR, ival);
+}
+
+long
+sb16_dsp_init (long mem_start, struct address_info *hw_config)
+{
+ if (sbc_major < 4)
+ return mem_start;
+
+#ifndef SCO
+ sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
+#endif
+
+#ifdef __FreeBSD__
+ printk ("snd6: <%s>", sb16_dsp_operations.name);
+#else
+ printk (" <%s>", sb16_dsp_operations.name);
+#endif
+
+ if (num_dspdevs < MAX_DSP_DEV)
+ {
+ dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations;
+ sound_dsp_dmachan[my_dev] = hw_config->dma;
+#ifndef NO_AUTODMA
+ sound_buffcounts[my_dev] = 1;
+ sound_dma_automode[my_dev] = 1;
+#else
+ sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
+ sound_dma_automode[my_dev] = 0;
+#endif
+ sound_buffsizes[my_dev] = DSP_BUFFSIZE;
+ }
+ else
+ printk ("SB: Too many DSP devices available\n");
+ sb16_dsp_ok = 1;
+ return mem_start;
+}
+
+int
+sb16_dsp_detect (struct address_info *hw_config)
+{
+ struct address_info *sb_config;
+
+ if (sb16_dsp_ok)
+ return 1; /* Already initialized */
+
+ if (!(sb_config = sound_getconf (SNDCARD_SB)))
+ {
+ printk ("SB16 Error: Plain SB not configured\n");
+ return 0;
+ }
+
+ /* sb_setmixer(OPSW,0xf);
+ if(sb_getmixer(OPSW)!=0xf)
+ return 0; */
+
+ if (!sb_reset_dsp ())
+ return 0;
+
+ if (hw_config->dma < 4)
+ if (hw_config->dma != sb_config->dma)
+ {
+ printk ("SB16 Error: Invalid DMA channel %d/%d\n",
+ sb_config->dma, hw_config->dma);
+ return 0;
+ }
+
+ dma16 = hw_config->dma;
+ dma8 = sb_config->dma;
+ set_irq_hw (sb_config->irq);
+ sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
+
+ DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
+
+ /*
+ dsp_showmessage(0xe3,99);
+ */
+ sb16_dsp_ok = 1;
+ return 1;
+}
+
+void
+sb16_dsp_interrupt (int unused)
+{
+ int data;
+
+ data = INB (DSP_DATA_AVL16); /* Interrupt acknowledge */
+
+ if (intr_active)
+ switch (irq_mode)
+ {
+ case IMODE_OUTPUT:
+ intr_active = 0;
+ DMAbuf_outputintr (my_dev, 1);
+ break;
+
+ case IMODE_INPUT:
+ intr_active = 0;
+ DMAbuf_inputintr (my_dev);
+ break;
+
+ default:
+ printk ("SoundBlaster: Unexpected interrupt\n");
+ }
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb16_midi.c b/sys/i386/isa/sound/sb16_midi.c
new file mode 100644
index 000000000000..39808c80fe0d
--- /dev/null
+++ b/sys/i386/isa/sound/sb16_midi.c
@@ -0,0 +1,287 @@
+/*
+ * sound/sb16_midi.c
+ *
+ * The low level driver for the MPU-401 UART emulation of the SB16.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * 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_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 */
+
+#define sb16midi_status() INB(STATPORT)
+#define input_avail() (!(sb16midi_status()&INPUT_AVAIL))
+#define output_ready() (!(sb16midi_status()&OUTPUT_READY))
+#define sb16midi_cmd(cmd) OUTB(cmd, COMDPORT)
+#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" */
+
+static int sb16midi_opened = 0;
+static int sb16midi_base = 0x330;
+static int sb16midi_detected = 0;
+static int my_dev;
+
+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 ();
+
+ if (sb16midi_opened & OPEN_READ)
+ midi_input_intr (my_dev, c);
+ }
+}
+
+void
+sb16midiintr (int unit)
+{
+ if (input_avail ())
+ sb16midi_input_loop ();
+}
+
+static int
+sb16midi_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+ if (sb16midi_opened)
+ {
+ return RET_ERROR (EBUSY);
+ }
+
+ sb16midi_input_loop ();
+
+ midi_input_intr = input;
+ sb16midi_opened = mode;
+
+ return 0;
+}
+
+static void
+sb16midi_close (int dev)
+{
+ sb16midi_opened = 0;
+}
+
+static int
+sb16midi_out (int dev, unsigned char midi_byte)
+{
+ int timeout;
+ unsigned long flags;
+
+ /*
+ * Test for input since pending input seems to block the output.
+ */
+
+ DISABLE_INTR (flags);
+
+ if (input_avail ())
+ sb16midi_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 ("MPU-401: Timeout\n");
+ return 0;
+ }
+
+ sb16midi_write (midi_byte);
+ return 1;
+}
+
+static int
+sb16midi_command (int dev, unsigned char midi_byte)
+{
+ return 1;
+}
+
+static int
+sb16midi_start_read (int dev)
+{
+ return 0;
+}
+
+static int
+sb16midi_end_read (int dev)
+{
+ return 0;
+}
+
+static int
+sb16midi_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EINVAL);
+}
+
+static void
+sb16midi_kick (int dev)
+{
+}
+
+static int
+sb16midi_buffer_status (int dev)
+{
+ return 0; /* No data in buffers */
+}
+
+static struct midi_operations sb16midi_operations =
+{
+ {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI},
+ sb16midi_open,
+ sb16midi_close,
+ sb16midi_ioctl,
+ sb16midi_out,
+ sb16midi_start_read,
+ sb16midi_end_read,
+ sb16midi_kick,
+ sb16midi_command,
+ sb16midi_buffer_status
+};
+
+
+long
+attach_sb16midi (long mem_start, struct address_info *hw_config)
+{
+ int ok, timeout;
+ unsigned long flags;
+
+ sb16midi_base = hw_config->io_base;
+
+ if (!sb16midi_detected)
+ return RET_ERROR (EIO);
+
+ DISABLE_INTR (flags);
+ for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
+ sb16midi_cmd (UART_MODE_ON);
+
+ ok = 0;
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ if (input_avail ())
+ if (sb16midi_read () == MPU_ACK)
+ ok = 1;
+
+ RESTORE_INTR (flags);
+
+#ifdef __FreeBSD__
+ printk ("snd7: <SoundBlaster MPU-401>");
+#else
+ printk (" <SoundBlaster MPU-401>");
+#endif
+
+ my_dev = num_midis;
+ midi_devs[num_midis++] = &sb16midi_operations;
+ return mem_start;
+}
+
+static int
+reset_sb16midi (void)
+{
+ unsigned long flags;
+ int ok, timeout, n;
+
+ /*
+ * Send the RESET command. Try again if no success at the first time.
+ */
+
+ ok = 0;
+
+ DISABLE_INTR (flags);
+
+ 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 */
+
+ /*
+ * 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 (sb16midi_read () == MPU_ACK)
+ ok = 1;
+
+ }
+
+ sb16midi_opened = 0;
+ if (ok)
+ sb16midi_input_loop (); /* Flush input before enabling interrupts */
+
+ RESTORE_INTR (flags);
+
+ return ok;
+}
+
+
+int
+probe_sb16midi (struct address_info *hw_config)
+{
+ int ok = 0;
+
+ sb16midi_base = hw_config->io_base;
+ if (sbc_major < 4)
+ return 0; /* SB16 not detected */
+
+ if (sb_get_irq () < 0)
+ return 0;
+
+ ok = reset_sb16midi ();
+
+ sb16midi_detected = ok;
+ return ok;
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/sb_card.c b/sys/i386/isa/sound/sb_card.c
index e2527c51a35e..f7588e1ca172 100644
--- a/sys/i386/isa/sound/sb_card.c
+++ b/sys/i386/isa/sound/sb_card.c
@@ -1,11 +1,10 @@
-
/*
- * linux/kernel/chr_drv/sound/sb_card.c
- *
+ * sound/sb_card.c
+ *
* Detection routine for the SoundBlaster cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -13,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -25,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#include "sound_config.h"
diff --git a/sys/i386/isa/sound/sb_dsp.c b/sys/i386/isa/sound/sb_dsp.c
index 4c273646bdd3..17fb4b70dc6a 100644
--- a/sys/i386/isa/sound/sb_dsp.c
+++ b/sys/i386/isa/sound/sb_dsp.c
@@ -1,7 +1,7 @@
/*
- * linux/kernel/chr_drv/sound/sb_dsp.c
+ * sound/sb_dsp.c
*
- * The low level driver for the SoundBlaster DS chips.
+ * The low level driver for the SoundBlaster DSP chip.
*
* Copyright by Hannu Savolainen 1993
*
@@ -25,152 +25,81 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * The mixer support is based on the SB-BSD 1.5 driver by (C) Steve Haehnichen
- * <shaehnic@ucsd.edu>
+ * Modified:
+ * Hunyue Yau Jan 6 1994
+ * Added code to support Sound Galaxy NX Pro
+ *
*/
#include "sound_config.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
+#include "sb.h"
+#include "sb_mixer.h"
#undef SB_TEST_IRQ
-#define DSP_RESET (sbc_base + 0x6)
-#define DSP_READ (sbc_base + 0xA)
-#define DSP_WRITE (sbc_base + 0xC)
-#define DSP_COMMAND (sbc_base + 0xC)
-#define DSP_STATUS (sbc_base + 0xC)
-#define DSP_DATA_AVAIL (sbc_base + 0xE)
-#define MIXER_ADDR (sbc_base + 0x4)
-#define MIXER_DATA (sbc_base + 0x5)
-#define OPL3_LEFT (sbc_base + 0x0)
-#define OPL3_RIGHT (sbc_base + 0x2)
-#define OPL3_BOTH (sbc_base + 0x8)
-
-static int sbc_base = 0;
+int sbc_base = 0;
static int sbc_irq = 0;
-
-#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
-
-#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
- SOUND_MASK_CD | SOUND_MASK_VOLUME)
-
-/*
- * Mixer registers
- *
- * NOTE! RECORD_SRC == IN_FILTER
- */
-
-#define VOC_VOL 0x04
-#define MIC_VOL 0x0A
-#define MIC_MIX 0x0A
-#define RECORD_SRC 0x0C
-#define IN_FILTER 0x0C
-#define OUT_FILTER 0x0E
-#define MASTER_VOL 0x22
-#define FM_VOL 0x26
-#define CD_VOL 0x28
-#define LINE_VOL 0x2E
-
-#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 */
-#define FILT_OFF (1 << 5)
-
-/* Convenient byte masks */
-#define B1(x) ((x) & 0x01)
-#define B2(x) ((x) & 0x03)
-#define B3(x) ((x) & 0x07)
-#define B4(x) ((x) & 0x0f)
-#define B5(x) ((x) & 0x1f)
-#define B6(x) ((x) & 0x3f)
-#define B7(x) ((x) & 0x7f)
-#define B8(x) ((x) & 0xff)
-#define F(x) (!!(x)) /* 0 or 1 only */
-
-#define MONO_DAC 0x00
-#define STEREO_DAC 0x02
-
-/* DSP Commands */
-
-#define DSP_CMD_SPKON 0xD1
-#define DSP_CMD_SPKOFF 0xD3
+static int open_mode=0;
/*
* The DSP channel can be used either for input or output. Variable
- * 'irq_mode' will be set when the program calls read or write first time
+ * 'sb_irq_mode' will be set when the program calls read or write first time
* after open. Current version doesn't support mode changes without closing
* and reopening the device. Support for this feature may be implemented in a
* future version of this driver.
*/
-#define IMODE_NONE 0
-#define IMODE_OUTPUT 1
-#define IMODE_INPUT 2
-#define IMODE_INIT 3
-#define IMODE_MIDI 4
-
-#define NORMAL_MIDI 0
-#define UART_MIDI 1
-
-static 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;
-static int dsp_highspeed = 0, dsp_stereo = 0;
+int sb_dsp_highspeed = 0;
+int sbc_major = 1;
+int sbc_minor = 0; /* DSP version */
+static int dsp_stereo = 0;
static int dsp_current_speed = DSP_DEFAULT_SPEED;
+static int sb16 = 0;
+static int irq_verified = 0;
-#ifndef EXCLUDE_SBPRO
-static int rec_devices = SOUND_MASK_MIC;
-static int hi_filter = 0, filter_in = 0, filter_out = 0;
+int sb_midi_mode = NORMAL_MIDI;
+int sb_midi_busy = 0; /* 1 if the process has output to MIDI */
+int sb_dsp_busy = 0;
-#endif
+volatile int sb_irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT
-static int midi_mode = NORMAL_MIDI;
-static int midi_busy = 0; /* 1 if the process has output to MIDI */
-static int dsp_busy = 0;
-
-static volatile int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT
* or IMODE_NONE */
static volatile int irq_ok = 0;
-static int dsp_model = 1; /* DSP version */
-static int dsp_mono = 1; /* 1 SB, 0 SB Pro */
-static int duplex_midi = 0;
+int sb_duplex_midi = 0;
static int my_dev = 0;
-static volatile int intr_active = 0;
+volatile int sb_intr_active = 0;
static int dsp_speed (int);
static int dsp_set_stereo (int mode);
-static int dsp_command (unsigned char val);
-
-#ifndef EXCLUDE_SBPRO
-static void setmixer (unsigned char port, unsigned char value);
-static int getmixer (unsigned char port);
-static void init_mixer (void);
-static int detect_mixer (void);
-
-#endif
+int sb_dsp_command (unsigned char val);
#if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
/* Common code for the midi and pcm functions */
-static int
-dsp_command (unsigned char val)
+int
+sb_dsp_command (unsigned char val)
{
- int i, limit;
+ int i;
+ unsigned long limit;
- limit = GET_TIME () + 10; /* The timeout is 0.1 secods */
+ limit = GET_TIME () + HZ / 10;/* The timeout is 0.1 secods */
/*
- * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
+ * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
* called while interrupts are disabled. This means that the timer is
* disabled also. However the timeout situation is a abnormal condition.
* Normally the DSP should be ready to accept commands after just couple of
* loops.
*/
- for (i = 0; i < 5000000 && GET_TIME () < limit; i++)
+ for (i = 0; i < 500000 && GET_TIME () < limit; i++)
{
if ((INB (DSP_STATUS) & 0x80) == 0)
{
@@ -179,42 +108,60 @@ dsp_command (unsigned char val)
}
}
- printk ("SoundBlaster: DSP Command(%02x) Timeout.\n", val);
+ printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val);
printk ("IRQ conflict???\n");
return 0;
}
void
-sbintr (int unused)
+sbintr (int unit)
{
- int status, data;
+ int status;
+
+#ifndef EXCLUDE_SBPRO
+ if (sb16)
+ {
+ unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */
+
+#ifndef EXCLUDE_SB16
+ if (src & 3)
+ sb16_dsp_interrupt (unit);
+
+#ifndef EXCLUDE_MIDI
+ if (src & 4)
+ sb16midiintr (unit); /* MPU401 interrupt */
+#endif
+
+#endif
+
+ if (!(src & 1))
+ return; /* Not a DSP interupt */
+ }
+#endif
status = INB (DSP_DATA_AVAIL);/* Clear interrupt */
- if (intr_active)
- switch (irq_mode)
+ if (sb_intr_active)
+ switch (sb_irq_mode)
{
case IMODE_OUTPUT:
- intr_active = 0;
- DMAbuf_outputintr (my_dev);
+ sb_intr_active = 0;
+ DMAbuf_outputintr (my_dev, 1);
break;
case IMODE_INPUT:
- intr_active = 0;
+ sb_intr_active = 0;
DMAbuf_inputintr (my_dev);
/* A complete buffer has been input. Let's start new one */
break;
case IMODE_INIT:
- intr_active = 0;
+ sb_intr_active = 0;
irq_ok = 1;
break;
case IMODE_MIDI:
- printk ("+");
- data = INB (DSP_READ);
- printk ("%02x", data);
-
+ sb_midi_interrupt (unit);
break;
default:
@@ -222,40 +169,36 @@ sbintr (int unused)
}
}
-static int
-set_dsp_irq (int interrupt_level)
-{
- int retcode = EINVAL;
+static int sb_irq_usecount = 0;
-#ifdef linux
- struct sigaction sa;
+int
+sb_get_irq (void)
+{
+ int ok;
- sa.sa_handler = sbintr;
+ if (!sb_irq_usecount)
+ if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0)
+ return ok;
-#ifdef SND_SA_INTERRUPT
- sa.sa_flags = SA_INTERRUPT;
-#else
- sa.sa_flags = 0;
-#endif
+ sb_irq_usecount++;
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
+ return 0;
+}
- retcode = irqaction (interrupt_level, &sa);
+void
+sb_free_irq (void)
+{
+ if (!sb_irq_usecount)
+ return;
- if (retcode < 0)
- {
- printk ("SoundBlaster: IRQ%d already in use\n", interrupt_level);
- }
+ sb_irq_usecount--;
-#else
- /* # error Unimplemented for this OS */
-#endif
- return retcode;
+ if (!sb_irq_usecount)
+ snd_release_irq (sbc_irq);
}
-static int
-reset_dsp (void)
+int
+sb_reset_dsp (void)
{
int loopc;
@@ -283,9 +226,9 @@ static void
dsp_speaker (char state)
{
if (state)
- dsp_command (DSP_CMD_SPKON);
+ sb_dsp_command (DSP_CMD_SPKON);
else
- dsp_command (DSP_CMD_SPKOFF);
+ sb_dsp_command (DSP_CMD_SPKOFF);
}
static int
@@ -293,61 +236,81 @@ dsp_speed (int speed)
{
unsigned char tconst;
unsigned long flags;
-
+ int max_speed = 44100;
if (speed < 4000)
speed = 4000;
- if (speed > 44100)
- speed = 44100; /* Invalid speed */
+ /*
+ * Older SB models don't support higher speeds than 22050.
+ */
+
+ if (sbc_major < 2 ||
+ (sbc_major == 2 && sbc_minor == 0))
+ max_speed = 22050;
- if (dsp_model == 1 && speed > 22050)
- speed = 22050;
- /* SB Classic doesn't support higher speed */
+ /*
+ * SB models earlier than SB Pro have low limit for the input speed.
+ */
+ if (open_mode != OPEN_WRITE) /* Recording is possible */
+ if (sbc_major < 3) /* Limited input speed with these cards */
+ if (sbc_major == 2 && sbc_minor > 0)
+ max_speed = 15000;
+ else
+ max_speed = 13000;
+ if (speed > max_speed)
+ speed = max_speed; /* Invalid speed */
if (dsp_stereo && speed > 22050)
speed = 22050;
/* Max. stereo speed is 22050 */
- if ((speed > 22050) && midi_busy)
+ if ((speed > 22050) && sb_midi_busy)
{
printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n");
speed = 22050;
}
if (dsp_stereo)
- speed <<= 1;
+ speed *= 2;
/* Now the speed should be valid */
if (speed > 22050)
{ /* High speed mode */
- tconst = (unsigned char) ((65536 - (256000000 / speed)) >> 8);
- dsp_highspeed = 1;
+ int tmp;
+
+ tconst = (unsigned char) ((65536 -
+ ((256000000 + speed / 2) / speed)) >> 8);
+ sb_dsp_highspeed = 1;
DISABLE_INTR (flags);
- if (dsp_command (0x40))
- dsp_command (tconst);
+ if (sb_dsp_command (0x40))
+ sb_dsp_command (tconst);
RESTORE_INTR (flags);
- speed = (256000000 / (65536 - (tconst << 8)));
+ tmp = 65536 - (tconst << 8);
+ speed = (256000000 + tmp / 2) / tmp;
}
else
{
- dsp_highspeed = 0;
- tconst = (256 - (1000000 / speed)) & 0xff;
+ int tmp;
+
+ sb_dsp_highspeed = 0;
+ tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
DISABLE_INTR (flags);
- if (dsp_command (0x40)) /* Set time constant */
- dsp_command (tconst);
+ if (sb_dsp_command (0x40))/* Set time constant */
+ sb_dsp_command (tconst);
RESTORE_INTR (flags);
- speed = 1000000 / (256 - tconst);
+ tmp = 256 - tconst;
+ speed = (1000000 + tmp / 2) / tmp;
}
if (dsp_stereo)
- speed >>= 1;
+ speed /= 2;
dsp_current_speed = speed;
return speed;
@@ -358,49 +321,47 @@ dsp_set_stereo (int mode)
{
dsp_stereo = 0;
- if (dsp_mono == 1)
+#ifdef EXCLUDE_SBPRO
+ return 0;
+#else
+ if (sbc_major < 3 || sb16)
return 0; /* Sorry no stereo */
- if (mode && midi_busy)
+ if (mode && sb_midi_busy)
{
printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n");
return 0;
}
dsp_stereo = !!mode;
-
-#ifndef EXCLUDE_SBPRO
- setmixer (OUT_FILTER, ((getmixer (OUT_FILTER) & ~STEREO_DAC)
- | (mode ? STEREO_DAC : MONO_DAC)));
+ return dsp_stereo;
#endif
- dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels
- * changes */
- return mode;
}
static void
-sb_dsp_output_block (int dev, unsigned long buf, int count, int intrflag)
+sb_dsp_output_block (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
{
unsigned long flags;
- if (!irq_mode)
+ if (!sb_irq_mode)
dsp_speaker (ON);
- irq_mode = IMODE_OUTPUT;
+ sb_irq_mode = IMODE_OUTPUT;
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
count--;
- if (dsp_highspeed)
+ if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
- if (dsp_command (0x48)) /* High speed size */
+ if (sb_dsp_command (0x48))/* High speed size */
{
- dsp_command (count & 0xff);
- dsp_command ((count >> 8) & 0xff);
- dsp_command (0x91); /* High speed 8 bit DAC */
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+ sb_dsp_command (0x91);/* High speed 8 bit DAC */
}
else
printk ("SB Error: Unable to start (high speed) DAC\n");
@@ -409,43 +370,44 @@ sb_dsp_output_block (int dev, unsigned long buf, int count, int intrflag)
else
{
DISABLE_INTR (flags);
- if (dsp_command (0x14)) /* 8-bit DAC (DMA) */
+ if (sb_dsp_command (0x14))/* 8-bit DAC (DMA) */
{
- dsp_command (count & 0xff);
- dsp_command ((count >> 8) & 0xff);
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
}
else
printk ("SB Error: Unable to start DAC\n");
RESTORE_INTR (flags);
}
- intr_active = 1;
+ sb_intr_active = 1;
}
static void
-sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag)
+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 */
unsigned long flags;
- if (!irq_mode)
+ if (!sb_irq_mode)
dsp_speaker (OFF);
- irq_mode = IMODE_INPUT;
+ sb_irq_mode = IMODE_INPUT;
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
count--;
- if (dsp_highspeed)
+ if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
- if (dsp_command (0x48)) /* High speed size */
+ if (sb_dsp_command (0x48))/* High speed size */
{
- dsp_command (count & 0xff);
- dsp_command ((count >> 8) & 0xff);
- dsp_command (0x99); /* High speed 8 bit ADC */
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+ sb_dsp_command (0x99);/* High speed 8 bit ADC */
}
else
printk ("SB Error: Unable to start (high speed) ADC\n");
@@ -454,23 +416,23 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag)
else
{
DISABLE_INTR (flags);
- if (dsp_command (0x24)) /* 8-bit ADC (DMA) */
+ if (sb_dsp_command (0x24))/* 8-bit ADC (DMA) */
{
- dsp_command (count & 0xff);
- dsp_command ((count >> 8) & 0xff);
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
}
else
printk ("SB Error: Unable to start ADC\n");
RESTORE_INTR (flags);
}
- intr_active = 1;
+ sb_intr_active = 1;
}
static void
dsp_cleanup (void)
{
- intr_active = 0;
+ sb_intr_active = 0;
}
static int
@@ -478,6 +440,17 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount)
{
dsp_cleanup ();
dsp_speaker (OFF);
+
+ 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 */
+ }
return 0;
}
@@ -486,6 +459,15 @@ sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
{
dsp_cleanup ();
dsp_speaker (ON);
+
+#ifndef EXCLUDE_SBPRO
+ if (sbc_major == 3) /* SB Pro */
+ {
+ sb_mixer_set_stereo (dsp_stereo);
+ dsp_speed (dsp_current_speed); /* Speed must be recalculated if #channels
+ * changes */
+ }
+#endif
return 0;
}
@@ -495,50 +477,80 @@ sb_dsp_halt_xfer (int dev)
}
static int
-sb_dsp_open (int dev, int mode)
+verify_irq (void)
{
- int retval;
+#if 0
+ DEFINE_WAIT_QUEUE (testq, testf);
- if (!sb_dsp_ok)
+ irq_ok = 0;
+
+ if (sb_get_irq () == -1)
{
- printk ("SB Error: SoundBlaster board not installed\n");
- return RET_ERROR (ENXIO);
+ printk ("*** SB Error: Irq %d already in use\n", sbc_irq);
+ return 0;
}
+
+ sb_irq_mode = IMODE_INIT;
+
+ sb_dsp_command (0xf2); /* This should cause immediate interrupt */
+
+ DO_SLEEP (testq, testf, HZ / 5);
+
+ sb_free_irq ();
+
if (!irq_ok)
{
- printk ("SB Error: Incorrect IRQ setting (%d)\n", sbc_irq);
+ printk ("SB Warning: IRQ%d test not passed!", sbc_irq);
+ irq_ok = 1;
+ }
+#else
+ irq_ok = 1;
+#endif
+ return irq_ok;
+}
+
+static int
+sb_dsp_open (int dev, int mode)
+{
+ int retval;
+
+ if (!sb_dsp_ok)
+ {
+ printk ("SB Error: SoundBlaster board not installed\n");
return RET_ERROR (ENXIO);
}
- if (intr_active || (midi_busy && midi_mode == UART_MIDI))
+ if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI))
{
printk ("SB: PCM not possible during MIDI input\n");
return RET_ERROR (EBUSY);
}
- if (mode != OPEN_READ && mode != OPEN_WRITE)
+ if (!irq_verified)
{
- printk ("SoundBlaster error: DAC and ACD not possible simultaneously\n");
- return RET_ERROR (EINVAL);
+ verify_irq ();
+ irq_verified = 1;
}
+ else if (!irq_ok)
+ printk ("SB Warning: Incorrect IRQ setting %d\n",
+ sbc_irq);
- retval = set_dsp_irq (sbc_irq);
+ retval = sb_get_irq ();
if (retval)
return retval;
if (!DMAbuf_open_dma (dev))
{
- RELEASE_IRQ (sbc_irq);
+ sb_free_irq ();
printk ("SB: DMA Busy\n");
return RET_ERROR (EBUSY);
}
- dsp_set_stereo (OFF);
- dsp_speed (DSP_DEFAULT_SPEED);
- irq_mode = IMODE_NONE;
+ sb_irq_mode = IMODE_NONE;
- dsp_busy = 1;
+ sb_dsp_busy = 1;
+ open_mode = mode;
return 0;
}
@@ -547,12 +559,12 @@ static void
sb_dsp_close (int dev)
{
DMAbuf_close_dma (dev);
- RELEASE_IRQ (sbc_irq);
+ sb_free_irq ();
dsp_cleanup ();
- dsp_speed (DSP_DEFAULT_SPEED);
- dsp_set_stereo (OFF);
dsp_speaker (OFF);
- dsp_busy = 0;
+ sb_dsp_busy = 0;
+ sb_dsp_highspeed = 0;
+ open_mode = 0;
}
static int
@@ -573,6 +585,8 @@ sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
break;
case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return dsp_set_stereo (arg - 1) + 1;
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
break;
@@ -614,7 +628,8 @@ sb_dsp_reset (int dev)
DISABLE_INTR (flags);
- reset_dsp ();
+ sb_reset_dsp ();
+ dsp_speed (dsp_current_speed);
dsp_cleanup ();
RESTORE_INTR (flags);
@@ -631,542 +646,19 @@ sb_dsp_detect (struct address_info *hw_config)
if (sb_dsp_ok)
return 0; /* Already initialized */
- if (!reset_dsp ())
+ if (!sb_reset_dsp ())
return 0;
return 1; /* Detected */
}
-#ifndef EXCLUDE_SBPRO
-
-static void
-setmixer (unsigned char port, unsigned char value)
-{
- OUTB (port, MIXER_ADDR); /* Select register */
- tenmicrosec ();
- OUTB (value, MIXER_DATA);
- tenmicrosec ();
-}
-
-static int
-getmixer (unsigned char port)
-{
- int val;
-
- OUTB (port, MIXER_ADDR); /* Select register */
- tenmicrosec ();
- val = INB (MIXER_DATA);
- tenmicrosec ();
-
- return val;
-}
-
-static int
-detect_mixer (void)
-{
- /*
- * Detect the mixer by changing parameters of two volume channels. If the
- * values read back match with the values written, the mixer is there (is
- * it?)
- */
- setmixer (FM_VOL, 0xff);
- setmixer (VOC_VOL, 0x33);
-
- if (getmixer (FM_VOL) != 0xff)
- return 0; /* No match */
- if (getmixer (VOC_VOL) != 0x33)
- return 0;
-
- return 1;
-}
-
-static void
-init_mixer (void)
-{
- setmixer (MASTER_VOL, 0xbb);
- setmixer (VOC_VOL, 0x99);
- setmixer (LINE_VOL, 0xbb);
- setmixer (FM_VOL, 0x99);
- setmixer (CD_VOL, 0x11);
- setmixer (MIC_MIX, 0x11);
- setmixer (RECORD_SRC, 0x31);
- setmixer (OUT_FILTER, 0x31);
-}
-
-static void
-set_filter (int record_source, int hifreq_filter, int filter_input, int filter_output)
-{
- setmixer (RECORD_SRC, (record_source
- | (hifreq_filter ? FREQ_HI : FREQ_LOW)
- | (filter_input ? FILT_ON : FILT_OFF)));
-
- setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC)
- | (filter_output ? FILT_ON : FILT_OFF)));
-
- hi_filter = hifreq_filter;
- filter_in = filter_input;
- filter_out = filter_output;
-}
-
-static int
-mixer_output (int right_vol, int left_vol, int div, int device)
-{
- int left = ((left_vol * div) + 50) / 100;
- int right = ((right_vol * div) + 50) / 100;
-
- setmixer (device, ((left & 0xf) << 4) | (right & 0xf));
-
- return (left_vol | (right_vol << 8));
-}
-
-static int
-sbp_mixer_set (int whichDev, unsigned int level)
-{
- int left, right, devmask;
-
- left = level & 0x7f;
- right = (level & 0x7f00) >> 8;
-
- switch (whichDev)
- {
- case SOUND_MIXER_VOLUME: /* Master volume (0-15) */
- return mixer_output (right, left, 15, MASTER_VOL);
- break;
- case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-15) */
- return mixer_output (right, left, 15, FM_VOL);
- break;
- case SOUND_MIXER_PCM: /* PAS PCM (0-15) */
- return mixer_output (right, left, 15, VOC_VOL);
- break;
- case SOUND_MIXER_LINE: /* External line (0-15) */
- return mixer_output (right, left, 15, LINE_VOL);
- break;
- case SOUND_MIXER_CD: /* CD (0-15) */
- return mixer_output (right, left, 15, CD_VOL);
- break;
- case SOUND_MIXER_MIC: /* External microphone (0-7) */
- return mixer_output (right, left, 7, MIC_VOL);
- break;
-
- case SOUND_MIXER_RECSRC:
- devmask = level & POSSIBLE_RECORDING_DEVICES;
-
- if (devmask != SOUND_MASK_MIC &&
- devmask != SOUND_MASK_LINE &&
- devmask != SOUND_MASK_CD)
- { /* More than one devices selected. Drop the
- * previous selection */
- devmask &= ~rec_devices;
- }
-
- if (devmask != SOUND_MASK_MIC &&
- devmask != SOUND_MASK_LINE &&
- devmask != SOUND_MASK_CD)
- { /* More than one devices selected. Default to
- * mic */
- devmask = SOUND_MASK_MIC;
- }
-
- if (devmask ^ rec_devices)/* Input source changed */
- {
- switch (devmask)
- {
-
- case SOUND_MASK_MIC:
- set_filter (SRC_MIC, hi_filter, filter_in, filter_out);
- break;
-
- case SOUND_MASK_LINE:
- set_filter (SRC_LINE, hi_filter, filter_in, filter_out);
- break;
-
- case SOUND_MASK_CD:
- set_filter (SRC_CD, hi_filter, filter_in, filter_out);
- break;
-
- default:
- set_filter (SRC_MIC, hi_filter, filter_in, filter_out);
- }
- }
-
- rec_devices = devmask;
-
- return rec_devices;
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
-
-}
-
-static int
-mixer_input (int div, int device)
-{
- int level, left, right, half;
-
- level = getmixer (device);
- half = div / 2;
-
- left = ((((level & 0xf0) >> 4) * 100) + half) / div;
- right = (((level & 0x0f) * 100) + half) / div;
-
- return (right << 8) | left;
-}
-
-static int
-sbp_mixer_get (int whichDev)
-{
-
- switch (whichDev)
- {
- case SOUND_MIXER_VOLUME: /* Master volume (0-15) */
- return mixer_input (15, MASTER_VOL);
- break;
- case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-15) */
- return mixer_input (15, FM_VOL);
- break;
- case SOUND_MIXER_PCM: /* PAS PCM (0-15) */
- return mixer_input (15, VOC_VOL);
- break;
- case SOUND_MIXER_LINE: /* External line (0-15) */
- return mixer_input (15, LINE_VOL);
- break;
- case SOUND_MIXER_CD: /* CD (0-15) */
- return mixer_input (15, CD_VOL);
- break;
- case SOUND_MIXER_MIC: /* External microphone (0-7) */
- return mixer_input (7, MIC_VOL);
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
-
-}
-
-/*
- * Sets mixer volume levels. All levels except mic are 0 to 15, mic is 7. See
- * sbinfo.doc for details on granularity and such. Basically, the mixer
- * forces the lowest bit high, effectively reducing the possible settings by
- * one half. Yes, that's right, volume levels have 8 settings, and
- * microphone has four. Sucks.
- */
-static int
-mixer_set_levels (struct sb_mixer_levels *user_l)
-{
- 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));
-
- setmixer (MASTER_VOL, (l.master.l << 4) | l.master.r);
- setmixer (LINE_VOL, (l.line.l << 4) | l.line.r);
- setmixer (VOC_VOL, (l.voc.l << 4) | l.voc.r);
- setmixer (FM_VOL, (l.fm.l << 4) | l.fm.r);
- setmixer (CD_VOL, (l.cd.l << 4) | l.cd.r);
- setmixer (MIC_VOL, l.mic);
- 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;
-
- 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 (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.
- */
-
- dsp_stereo = !!p.dsp_stereo;
-
- set_filter (p.record_source, p.hifreq_filter, p.filter_input, p.filter_output);
-
- switch (p.record_source)
- {
-
- case SRC_MIC:
- rec_devices = SOUND_MASK_MIC;
- break;
-
- case SRC_LINE:
- rec_devices = SOUND_MASK_LINE;
- break;
-
- case SRC_CD:
- rec_devices = SOUND_MASK_CD;
- }
-
- return (0);
-}
-
-/* Read the current mixer level settings into the user's struct. */
-static int
-mixer_get_levels (struct sb_mixer_levels *user_l)
-{
- S_BYTE val;
- struct sb_mixer_levels l;
-
- val = getmixer (MASTER_VOL); /* Master */
- l.master.l = B4 (val >> 4);
- l.master.r = B4 (val);
-
- val = getmixer (LINE_VOL); /* FM */
- l.line.l = B4 (val >> 4);
- l.line.r = B4 (val);
-
- val = getmixer (VOC_VOL); /* DAC */
- l.voc.l = B4 (val >> 4);
- l.voc.r = B4 (val);
-
- val = getmixer (FM_VOL); /* FM */
- l.fm.l = B4 (val >> 4);
- l.fm.r = B4 (val);
-
- val = getmixer (CD_VOL); /* CD */
- l.cd.l = B4 (val >> 4);
- l.cd.r = B4 (val);
-
- val = getmixer (MIC_VOL); /* Microphone */
- l.mic = B3 (val);
-
- 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;
-
- val = getmixer (RECORD_SRC);
- params.record_source = val & 0x07;
- params.hifreq_filter = !!(val & FREQ_HI);
- params.filter_input = (val & FILT_OFF) ? OFF : ON;
- params.filter_output = (getmixer (OUT_FILTER) & FILT_OFF) ? OFF : ON;
- params.dsp_stereo = dsp_stereo;
-
- IOCTL_TO_USER ((char *) user_params, 0, (char *) &params, sizeof (params));
- return (0);
-}
-
-static int
-sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
-{
- if (((cmd >> 8) & 0xff) == 'M')
- {
- if (cmd & IOC_IN)
- return IOCTL_OUT (arg, sbp_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
- else
- { /* Read parameters */
-
- switch (cmd & 0xff)
- {
-
- case SOUND_MIXER_RECSRC:
- return IOCTL_OUT (arg, rec_devices);
- break;
-
- case SOUND_MIXER_DEVMASK:
- return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~SOUND_MASK_MIC);
- break;
-
- case SOUND_MIXER_RECMASK:
- return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES);
- break;
-
- case SOUND_MIXER_CAPS:
- return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT);
- break;
-
- default:
- return IOCTL_OUT (arg, sbp_mixer_get (cmd & 0xff));
- }
- }
- }
- else
- {
- switch (cmd)
- {
- case MIXER_IOCTL_SET_LEVELS:
- return (mixer_set_levels ((struct sb_mixer_levels *) arg));
- case MIXER_IOCTL_SET_PARAMS:
- return (mixer_set_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:
- init_mixer ();
- return (0);
- default:
- return RET_ERROR (EINVAL);
- }
- }
-}
-
-/* End of mixer code */
-#endif
-
-#ifndef EXCLUDE_MIDI
-
-/* Midi code */
-
-static int
-sb_midi_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
-)
-{
- int ret;
-
- if (!sb_dsp_ok)
- {
- printk ("SB Error: MIDI hardware not installed\n");
- return RET_ERROR (ENXIO);
- }
-
- if (mode != OPEN_WRITE && !duplex_midi)
- {
- if (num_midis == 1)
- printk ("SoundBlaster: Midi input not currently supported\n");
- return RET_ERROR (EPERM);
- }
-
- midi_mode = NORMAL_MIDI;
- if (mode != OPEN_WRITE)
- {
- if (dsp_busy || intr_active)
- return RET_ERROR (EBUSY);
- midi_mode = UART_MIDI;
- }
-
- if (dsp_highspeed || dsp_stereo)
- {
- printk ("SB Error: Midi output not possible during stereo or high speed audio\n");
- return RET_ERROR (EBUSY);
- }
-
- if (midi_mode == UART_MIDI)
- {
- irq_mode = IMODE_MIDI;
-
- reset_dsp ();
- dsp_speaker (OFF);
-
- if (!dsp_command (0x35))
- return RET_ERROR (EIO); /* Enter the UART mode */
- intr_active = 1;
-
- if ((ret = set_dsp_irq (sbc_irq)) < 0)
- {
- reset_dsp ();
- return 0; /* IRQ not free */
- }
- }
-
- midi_busy = 1;
-
- return 0;
-}
-
-static void
-sb_midi_close (int dev)
-{
- if (midi_mode == UART_MIDI)
- {
- reset_dsp (); /* The only way to kill the UART mode */
- RELEASE_IRQ (sbc_irq);
- }
- intr_active = 0;
- midi_busy = 0;
-}
-
-static int
-sb_midi_out (int dev, unsigned char midi_byte)
-{
- unsigned long flags;
-
- midi_busy = 1; /* Kill all notes after close */
-
- if (midi_mode == NORMAL_MIDI)
- {
- DISABLE_INTR (flags);
- if (dsp_command (0x38))
- dsp_command (midi_byte);
- else
- printk ("SB Error: Unable to send a MIDI byte\n");
- RESTORE_INTR (flags);
- }
- else
- dsp_command (midi_byte); /* UART write */
-
- return 1;
-}
-
-static int
-sb_midi_start_read (int dev)
-{
- if (midi_mode != UART_MIDI)
- {
- printk ("SoundBlaster: MIDI input not implemented.\n");
- return RET_ERROR (EPERM);
- }
- return 0;
-}
-
-static int
-sb_midi_end_read (int dev)
-{
- if (midi_mode == UART_MIDI)
- {
- reset_dsp ();
- intr_active = 0;
- }
- return 0;
-}
-
-static int
-sb_midi_ioctl (int dev, unsigned cmd, unsigned arg)
-{
- return RET_ERROR (EPERM);
-}
-
-/* End of midi code */
-#endif
+static char card_name[32] = "SoundBlaster";
#ifndef EXCLUDE_AUDIO
static struct audio_operations sb_dsp_operations =
{
"SoundBlaster",
+ NOTHING_SPECIAL,
sb_dsp_open,
sb_dsp_close,
sb_dsp_output_block,
@@ -1182,132 +674,102 @@ static struct audio_operations sb_dsp_operations =
#endif
-#ifndef EXCLUDE_SBPRO
-static struct mixer_operations sb_mixer_operations =
-{
- sb_mixer_ioctl
-};
-
-#endif
-
-#ifndef EXCLUDE_MIDI
-static struct midi_operations sb_midi_operations =
-{
- {"SoundBlaster", 0},
- 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 */
-};
-
-#endif
-
-static int
-verify_irq (void)
-{
-#if 0
- unsigned long loop;
-
- irq_ok = 0;
-
- if (set_dsp_irq (sbc_irq) == -1)
- {
- printk ("*** SB Error: Irq %d already in use\n", sbc_irq);
- return 0;
- }
-
-
- irq_mode = IMODE_INIT;
-
- dsp_command (0xf2); /* This should cause immediate interrupt */
-
- for (loop = 100000; loop > 0 && !irq_ok; loop--);
-
- RELEASE_IRQ (sbc_irq);
-
- if (!irq_ok)
- {
- printk ("SB Warning: IRQ test not passed!");
- irq_ok = 1;
- }
-#else
- irq_ok = 1;
-#endif
- return irq_ok;
-}
-
long
sb_dsp_init (long mem_start, struct address_info *hw_config)
{
- int i, major, minor;
+ int i;
+ int prostat = 0;
- major = minor = 0;
- dsp_command (0xe1); /* Get version */
+ sbc_major = sbc_minor = 0;
+ sb_dsp_command (0xe1); /* Get version */
for (i = 1000; i; i--)
{
- if (inb (DSP_DATA_AVAIL) & 0x80)
+ if (INB (DSP_DATA_AVAIL) & 0x80)
{ /* wait for Data Ready */
- if (major == 0)
- major = inb (DSP_READ);
+ if (sbc_major == 0)
+ sbc_major = INB (DSP_READ);
else
{
- minor = inb (DSP_READ);
+ sbc_minor = INB (DSP_READ);
break;
}
}
}
- dsp_model = major;
+
+ if (sbc_major == 2 || sbc_major == 3) /* SB 2.0 or SB Pro */
+ sb_duplex_midi = 1;
+
+ if (sbc_major == 4)
+ sb16 = 1;
#ifndef EXCLUDE_SBPRO
- if (detect_mixer ())
- {
- dsp_mono = 0;
- sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", major, minor);
- init_mixer ();
- mixer_devs[num_mixers++] = &sb_mixer_operations;
+ if (sbc_major >= 3 ||
+ (sbc_major == 2 && sbc_minor == 1)) /* Sound Galaxy ??? */
+ prostat = sb_mixer_init (sbc_major);
+#endif
- if (major >= 2)
- duplex_midi = 1;
+#ifndef EXCLUDE_YM3812
+ if (sbc_major > 3 ||
+ (sbc_major == 3 && INB (0x388) == 0x00)) /* Non OPL-3 should return 0x06 */
+ enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
+#endif
-#ifndef EXCLUDE_YM8312
- if (major > 3 || (major == 3 && minor > 0)) /* SB Pro2 or later */
+ if (sbc_major >= 3)
+ {
+#ifndef SCO
+ if (prostat)
{
- enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
+#endif
+ sprintf (card_name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
+ }
+ else
+ {
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
+#endif
+ sprintf (card_name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
}
#endif
}
else
+ {
+#ifndef SCO
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
#endif
- sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", major, minor);
-
- printk ("snd2: <%s>", sb_dsp_operations.name);
+ sprintf (card_name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
+#endif
+ }
- if (!verify_irq ())
- return mem_start;
+#ifdef __FreeBSD__
+ printk ("snd2: <%s>", card_name);
+#else
+ printk (" <%s>", card_name);
+#endif
#ifndef EXCLUDE_AUDIO
- if (num_dspdevs < MAX_DSP_DEV)
- {
- dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations;
- sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
- sound_buffsizes[my_dev] = DSP_BUFFSIZE;
- sound_dsp_dmachan[my_dev] = hw_config->dma;
- sound_dma_automode[my_dev] = 0;
- }
- else
- printk ("SB: Too many DSP devices available\n");
+#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+ if (!sb16) /* There is a better driver for SB16 */
+#endif
+ if (num_dspdevs < MAX_DSP_DEV)
+ {
+ dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations;
+ sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
+ sound_buffsizes[my_dev] = DSP_BUFFSIZE;
+ sound_dsp_dmachan[my_dev] = hw_config->dma;
+ sound_dma_automode[my_dev] = 0;
+ }
+ else
+ printk ("SB: Too many DSP devices available\n");
#endif
#ifndef EXCLUDE_MIDI
- if (!midi_disabled) /* Midi don't work in the SB emulation mode
- * of PAS */
- midi_devs[num_midis++] = &sb_midi_operations;
+ if (!midi_disabled && !sb16) /* Midi don't work in the SB emulation mode
+ * of PAS, SB16 has better midi interface */
+ sb_midi_init (sbc_major);
#endif
sb_dsp_ok = 1;
diff --git a/sys/i386/isa/sound/sb_midi.c b/sys/i386/isa/sound/sb_midi.c
new file mode 100644
index 000000000000..fed19aba3a08
--- /dev/null
+++ b/sys/i386/isa/sound/sb_midi.c
@@ -0,0 +1,224 @@
+/*
+ * sound/sb_dsp.c
+ *
+ * The low level driver for the SoundBlaster DS chips.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * 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_SB) && !defined(EXCLUDE_MIDI)
+
+#include "sb.h"
+#undef SB_TEST_IRQ
+
+/*
+ * The DSP channel can be used either for input or output. Variable
+ * 'sb_irq_mode' will be set when the program calls read or write first time
+ * after open. Current version doesn't support mode changes without closing
+ * and reopening the device. Support for this feature may be implemented in a
+ * future version of this driver.
+ */
+
+extern int sb_dsp_ok; /* Set to 1 after successful initialization */
+
+extern int sb_midi_mode;
+extern int sb_midi_busy; /* 1 if the process has output to MIDI */
+extern int sb_dsp_busy;
+extern int sb_dsp_highspeed;
+
+extern volatile int sb_irq_mode;/* IMODE_INPUT, IMODE_OUTPUT
+
+ * or IMODE_NONE */
+extern int sb_duplex_midi;
+extern int sb_intr_active;
+extern int sbc_base;
+
+static int input_opened = 0;
+static void (*midi_input_intr) (int dev, unsigned char data);
+static int my_dev = 0;
+
+static int
+sb_midi_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+ int ret;
+
+ if (!sb_dsp_ok)
+ {
+ printk ("SB Error: MIDI hardware not installed\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (mode != OPEN_WRITE && !sb_duplex_midi)
+ {
+ if (num_midis == 1)
+ printk ("SoundBlaster: MIDI input not supported with plain SB\n");
+ return RET_ERROR (EPERM);
+ }
+
+ sb_midi_mode = NORMAL_MIDI;
+ if (mode != OPEN_WRITE)
+ {
+ if (sb_dsp_busy || sb_intr_active)
+ return RET_ERROR (EBUSY);
+ sb_midi_mode = UART_MIDI;
+ }
+
+ if (sb_dsp_highspeed)
+ {
+ printk ("SB Error: Midi output not possible during stereo or high speed audio\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_irq_mode = IMODE_MIDI;
+
+ sb_reset_dsp ();
+
+ if (!sb_dsp_command (0xf2)) /* This is undodumented, isn't it */
+ return RET_ERROR (EIO); /* be nice to DSP */
+
+ if (!sb_dsp_command (0x35))
+ return RET_ERROR (EIO); /* Enter the UART mode */
+ sb_intr_active = 1;
+
+ if ((ret = sb_get_irq ()) < 0)
+ {
+ sb_reset_dsp ();
+ return 0; /* IRQ not free */
+ }
+ input_opened = 1;
+ my_dev = dev;
+ midi_input_intr = input;
+ }
+
+ sb_midi_busy = 1;
+
+ return 0;
+}
+
+static void
+sb_midi_close (int dev)
+{
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_reset_dsp (); /* The only way to kill the UART mode */
+ sb_free_irq ();
+ }
+ sb_intr_active = 0;
+ sb_midi_busy = 0;
+ input_opened = 0;
+}
+
+static int
+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);
+ if (sb_dsp_command (0x38))
+ sb_dsp_command (midi_byte);
+ else
+ printk ("SB Error: Unable to send a MIDI byte\n");
+ RESTORE_INTR (flags);
+ }
+ else
+ sb_dsp_command (midi_byte); /* UART write */
+
+ return 1;
+}
+
+static int
+sb_midi_start_read (int dev)
+{
+ if (sb_midi_mode != UART_MIDI)
+ {
+ printk ("SoundBlaster: MIDI input not implemented.\n");
+ return RET_ERROR (EPERM);
+ }
+ return 0;
+}
+
+static int
+sb_midi_end_read (int dev)
+{
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_reset_dsp ();
+ sb_intr_active = 0;
+ }
+ return 0;
+}
+
+static int
+sb_midi_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EPERM);
+}
+
+void
+sb_midi_interrupt (int dummy)
+{
+ unsigned long flags;
+ unsigned char data;
+
+ DISABLE_INTR (flags);
+
+ data = INB (DSP_READ);
+ if (input_opened)
+ midi_input_intr (my_dev, data);
+
+ RESTORE_INTR (flags);
+}
+
+static struct midi_operations sb_midi_operations =
+{
+ {"SoundBlaster", 0, 0, SNDCARD_SB},
+ 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 */
+};
+
+void
+sb_midi_init (int model)
+{
+ midi_devs[num_midis++] = &sb_midi_operations;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb_mixer.c b/sys/i386/isa/sound/sb_mixer.c
new file mode 100644
index 000000000000..39b97caf8cd7
--- /dev/null
+++ b/sys/i386/isa/sound/sb_mixer.c
@@ -0,0 +1,422 @@
+
+/*
+ * sound/sb_mixer.c
+ *
+ * The low level mixer driver for the SoundBlaster Pro and SB16 cards.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * 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.
+ *
+ * Modified:
+ * Hunyue Yau Jan 6 1994
+ * Added code to support the Sound Galaxy NX Pro mixer.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO)
+#define __SB_MIXER_C__
+
+#include "sb.h"
+#include "sb_mixer.h"
+#undef SB_TEST_IRQ
+
+extern int sbc_base;
+
+static int mixer_initialized = 0;
+
+static int supported_rec_devices;
+static int supported_devices;
+static int recmask = 0;
+static int mixer_model;
+static int mixer_caps;
+static mixer_tab *iomap;
+
+void
+sb_setmixer (unsigned int port, unsigned int value)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */
+ tenmicrosec ();
+ OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
+ tenmicrosec ();
+ RESTORE_INTR (flags);
+}
+
+int
+sb_getmixer (unsigned int port)
+{
+ int val;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */
+ tenmicrosec ();
+ val = INB (MIXER_DATA);
+ tenmicrosec ();
+ RESTORE_INTR (flags);
+
+ return val;
+}
+
+void
+sb_mixer_set_stereo (int mode)
+{
+ if (!mixer_initialized)
+ return;
+
+ sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
+ | (mode ? STEREO_DAC : MONO_DAC)));
+}
+
+/*
+ * Returns:
+ * 0 No mixer detected.
+ * 1 Only a plain Sound Blaster Pro style mixer detected.
+ * 2 The Sound Galaxy NX Pro mixer detected.
+ */
+static int
+detect_mixer (void)
+{
+#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
+ * it?)
+ */
+ sb_setmixer (FM_VOL, 0xff);
+ sb_setmixer (VOC_VOL, 0x33);
+
+ if (sb_getmixer (FM_VOL) != 0xff)
+ 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;
+}
+
+static void
+change_bits (unsigned char *regval, int dev, int chn, int newval)
+{
+ unsigned char mask;
+ int shift;
+
+ mask = (1 << (*iomap)[dev][chn].nbits) - 1;
+ newval = ((newval * mask) + 50) / 100; /* Scale it */
+
+ shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
+
+ *regval &= ~(mask << shift); /* Filter out the previous value */
+ *regval |= (newval & mask) << shift; /* Set the new value */
+}
+
+static int
+sb_mixer_get (int dev)
+{
+ if (!((1 << dev) & supported_devices))
+ return RET_ERROR (EINVAL);
+
+ return levels[dev];
+}
+
+static int
+sb_mixer_set (int dev, int value)
+{
+ int left = value & 0x000000ff;
+ int right = (value & 0x0000ff00) >> 8;
+
+ int regoffs;
+ unsigned char val;
+
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+
+ if (dev > 31)
+ return RET_ERROR (EINVAL);
+
+ if (!(supported_devices & (1 << dev))) /* Not supported */
+ return RET_ERROR (EINVAL);
+
+ regoffs = (*iomap)[dev][LEFT_CHN].regno;
+
+ if (regoffs == 0)
+ return RET_ERROR (EINVAL);
+
+ val = sb_getmixer (regoffs);
+ change_bits (&val, dev, LEFT_CHN, left);
+
+ levels[dev] = left | (left << 8);
+
+ if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */
+ {
+ sb_setmixer (regoffs, val); /* Save the old one */
+ regoffs = (*iomap)[dev][RIGHT_CHN].regno;
+
+ if (regoffs == 0)
+ return left | (left << 8); /* Just left channel present */
+
+ val = sb_getmixer (regoffs); /* Read the new one */
+ }
+
+ change_bits (&val, dev, RIGHT_CHN, right);
+ sb_setmixer (regoffs, val);
+
+ levels[dev] = left | (right << 8);
+ return left | (right << 8);
+}
+
+static void
+set_recsrc (int src)
+{
+ sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
+}
+
+static int
+set_recmask (int mask)
+{
+ int devmask, i;
+ unsigned char regimageL, regimageR;
+
+ devmask = mask & supported_rec_devices;
+
+ switch (mixer_model)
+ {
+ case 3:
+
+ if (devmask != SOUND_MASK_MIC &&
+ devmask != SOUND_MASK_LINE &&
+ devmask != SOUND_MASK_CD)
+ { /* 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 */
+ devmask = SOUND_MASK_MIC;
+ }
+
+
+ if (devmask ^ recmask) /* Input source changed */
+ {
+ switch (devmask)
+ {
+
+ case SOUND_MASK_MIC:
+ set_recsrc (SRC_MIC);
+ break;
+
+ case SOUND_MASK_LINE:
+ set_recsrc (SRC_LINE);
+ break;
+
+ case SOUND_MASK_CD:
+ set_recsrc (SRC_CD);
+ break;
+
+ default:
+ set_recsrc (SRC_MIC);
+ }
+ }
+
+ break;
+
+ case 4:
+ if (!devmask)
+ devmask = SOUND_MASK_MIC;
+
+ regimageL = regimageR = 0;
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if ((1 << i) & devmask)
+ {
+ regimageL |= sb16_recmasks_L[i];
+ regimageR |= sb16_recmasks_R[i];
+ }
+ sb_setmixer (SB16_IMASK_L, regimageL);
+ sb_setmixer (SB16_IMASK_R, regimageR);
+ break;
+ }
+
+ recmask = devmask;
+ return recmask;
+}
+
+static int
+sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg)));
+ break;
+
+ default:
+ return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
+ }
+ else
+ switch (cmd & 0xff) /* Return parameters */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, recmask);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, supported_devices);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, supported_devices &
+ ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, supported_rec_devices);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, mixer_caps);
+ break;
+
+ default:
+ return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
+ }
+ }
+ else
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations sb_mixer_operations =
+{
+ sb_mixer_ioctl
+};
+
+static void
+sb_mixer_reset (void)
+{
+ int i;
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ sb_mixer_set (i, levels[i]);
+ 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
+sb_mixer_init (int major_model)
+{
+ int mixerstat;
+
+ sb_setmixer (0x00, 0); /* Reset mixer */
+
+ mixerstat = detect_mixer ();
+
+ if (!mixerstat)
+ return 0; /* No mixer. Why? */
+
+ mixer_initialized = 1;
+ mixer_model = major_model;
+
+ switch (major_model)
+ {
+ case 3:
+ mixer_caps = SOUND_CAP_EXCL_INPUT;
+#ifdef __SGNXPRO__
+ if (mixerstat == 2)
+ { /* A SGNXPRO was detected */
+ supported_devices = SGNXPRO_MIXER_DEVICES;
+ supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
+ iomap = &sgnxpro_mix;
+ }
+ else
+#endif
+ { /* Otherwise plain SB Pro */
+ supported_devices = SBPRO_MIXER_DEVICES;
+ supported_rec_devices = SBPRO_RECORDING_DEVICES;
+ iomap = &sbpro_mix;
+ }
+
+ break;
+
+ case 4:
+ mixer_caps = 0;
+ supported_devices = SB16_MIXER_DEVICES;
+ supported_rec_devices = SB16_RECORDING_DEVICES;
+ iomap = &sb16_mix;
+ break;
+
+ default:
+ printk ("SB Warning: Unsupported mixer type\n");
+ return 0;
+ }
+
+ mixer_devs[num_mixers++] = &sb_mixer_operations;
+ sb_mixer_reset ();
+ return (mixerstat == 2);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb_mixer.h b/sys/i386/isa/sound/sb_mixer.h
new file mode 100644
index 000000000000..4caf7730226f
--- /dev/null
+++ b/sys/i386/isa/sound/sb_mixer.h
@@ -0,0 +1,212 @@
+/*
+ * sound/sb_mixer.h
+ *
+ * Definitions for the SB Pro and SB16 mixers
+ *
+ * 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.
+ *
+ * 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 SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD | SOUND_MASK_RECLEV | \
+ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
+
+/*
+ * Mixer registers
+ *
+ * NOTE! RECORD_SRC == IN_FILTER
+ */
+
+/*
+ * Mixer registers of SB Pro
+ */
+#define VOC_VOL 0x04
+#define MIC_VOL 0x0A
+#define MIC_MIX 0x0A
+#define RECORD_SRC 0x0C
+#define IN_FILTER 0x0C
+#define OUT_FILTER 0x0E
+#define MASTER_VOL 0x22
+#define FM_VOL 0x26
+#define CD_VOL 0x28
+#define LINE_VOL 0x2E
+#define IRQ_NR 0x80
+#define DMA_NR 0x81
+#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 */
+#define FILT_OFF (1 << 5)
+
+#define MONO_DAC 0x00
+#define STEREO_DAC 0x02
+
+/*
+ * Mixer registers of SB16
+ */
+#define SB16_IMASK_L 0x3d
+#define SB16_IMASK_R 0x3e
+
+#define LEFT_CHN 0
+#define RIGHT_CHN 1
+
+struct mixer_def {
+ unsigned int regno: 8;
+ unsigned int bitoffs:4;
+ unsigned int nbits:4;
+};
+
+
+typedef struct mixer_def mixer_tab[32][2];
+typedef struct mixer_def mixer_ent;
+
+#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \
+ {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}}
+
+#ifdef __SB_MIXER_C__
+mixer_tab sbpro_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 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)
+};
+
+#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),
+MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4),
+MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5),
+MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5),
+MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5),
+MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5),
+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, 0x3f, 7, 2, 0x40, 7, 2)
+};
+
+static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+{
+ 0x5a5a, /* Master Volume */
+ 0x3232, /* Bass */
+ 0x3232, /* Treble */
+ 0x4b4b, /* FM */
+ 0x4b4b, /* PCM */
+ 0x4b4b, /* PC Speaker */
+ 0x4b4b, /* Ext Line */
+ 0x0000, /* Mic */
+ 0x4b4b, /* CD */
+ 0x4b4b, /* Recording monitor */
+ 0x4b4b, /* SB PCM */
+ 0x4b4b}; /* Recording level */
+
+static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
+{
+ 0x00, /* SOUND_MIXER_VOLUME */
+ 0x00, /* SOUND_MIXER_BASS */
+ 0x00, /* SOUND_MIXER_TREBLE */
+ 0x40, /* SOUND_MIXER_SYNTH */
+ 0x00, /* SOUND_MIXER_PCM */
+ 0x00, /* SOUND_MIXER_SPEAKER */
+ 0x10, /* SOUND_MIXER_LINE */
+ 0x01, /* SOUND_MIXER_MIC */
+ 0x04, /* SOUND_MIXER_CD */
+ 0x00, /* SOUND_MIXER_IMIX */
+ 0x00, /* SOUND_MIXER_ALTPCM */
+ 0x00 /* SOUND_MIXER_RECLEV */
+};
+
+static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
+{
+ 0x00, /* SOUND_MIXER_VOLUME */
+ 0x00, /* SOUND_MIXER_BASS */
+ 0x00, /* SOUND_MIXER_TREBLE */
+ 0x20, /* SOUND_MIXER_SYNTH */
+ 0x00, /* SOUND_MIXER_PCM */
+ 0x00, /* SOUND_MIXER_SPEAKER */
+ 0x08, /* SOUND_MIXER_LINE */
+ 0x01, /* SOUND_MIXER_MIC */
+ 0x02, /* SOUND_MIXER_CD */
+ 0x00, /* SOUND_MIXER_IMIX */
+ 0x00, /* SOUND_MIXER_ALTPCM */
+ 0x00 /* SOUND_MIXER_RECLEV */
+};
+#endif
diff --git a/sys/i386/isa/sound/sequencer.c b/sys/i386/isa/sound/sequencer.c
index 7df08120ebcc..1a3943289958 100644
--- a/sys/i386/isa/sound/sequencer.c
+++ b/sys/i386/isa/sound/sequencer.c
@@ -1,10 +1,10 @@
/*
- * linux/kernel/chr_drv/sound/sequencer.c
- *
+ * sound/sequencer.c
+ *
* The sequencer personality manager.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
#define SEQUENCER_C
@@ -37,20 +37,24 @@
static int sequencer_ok = 0;
DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
-DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
+/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */
+#define midi_sleeper seq_sleeper
+#define midi_sleep_flag seq_sleep_flag
static int midi_opened[MAX_MIDI_DEV] =
{0}; /* 1 if the process has opened MIDI */
static int midi_written[MAX_MIDI_DEV] =
{0};
-long seq_time = 0; /* Reference point for the timer */
+unsigned long seq_time = 0; /* Reference point for the timer */
#include "tuning.h"
#define EV_SZ 8
-static unsigned char queue[SEQ_MAX_QUEUE][EV_SZ];
-static unsigned char iqueue[SEQ_MAX_QUEUE][4];
+#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 */
+
static volatile int qhead = 0, qtail = 0, qlen = 0;
static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
static volatile int seq_playing = 0;
@@ -83,13 +87,16 @@ sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
if (!iqlen)
{
- INTERRUPTIBLE_SLEEP_ON (midi_sleeper, midi_sleep_flag);
+ if (c != count) /* Some data has been received */
+ return count - c; /* Return what we have */
+
+ DO_SLEEP (midi_sleeper, midi_sleep_flag, 0);
if (!iqlen)
return count - c;
}
- COPY_TO_USER (buf, p, &iqueue[iqhead][0], 4);
+ COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ);
p += 4;
c -= 4;
@@ -114,14 +121,14 @@ copy_to_input (unsigned char *event)
if (iqlen >= (SEQ_MAX_QUEUE - 1))
return; /* Overflow */
- memcpy (iqueue[iqtail], event, 4);
+ memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ);
iqlen++;
iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
DISABLE_INTR (flags);
- if (midi_sleep_flag)
+ if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag))
{
- WAKE_UP (midi_sleeper);
+ WAKE_UP (midi_sleeper, midi_sleep_flag);
}
RESTORE_INTR (flags);
}
@@ -266,16 +273,16 @@ seq_queue (unsigned char *note)
if (!seq_playing)
seq_startplay (); /* Give chance to drain the queue */
- if (qlen >= SEQ_MAX_QUEUE && !seq_sleep_flag)
+ if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
/* Sleep until there is enough space on the queue */
- INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
}
if (qlen >= SEQ_MAX_QUEUE)
return 0; /* To be sure */
- memcpy (&queue[qtail][0], note, EV_SZ);
+ memcpy (&queue[qtail * EV_SZ], note, EV_SZ);
qtail = (qtail + 1) % SEQ_MAX_QUEUE;
qlen++;
@@ -323,6 +330,10 @@ extended_event (unsigned char *q)
synth_devs[dev]->controller (dev, q[3], q[4], *(short *) &q[5]);
break;
+ case SEQ_VOLMODE:
+ synth_devs[dev]->volume_method (dev, q[3]);
+ break;
+
default:
return RET_ERROR (EINVAL);
}
@@ -342,7 +353,7 @@ seq_startplay (void)
qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
qlen--;
- q = &queue[this_one][0];
+ q = &queue[this_one * EV_SZ];
switch (q[0])
{
@@ -378,10 +389,9 @@ seq_startplay (void)
unsigned long flags;
DISABLE_INTR (flags);
- if (seq_sleep_flag)
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
- seq_sleep_flag = 0;
- WAKE_UP (seq_sleeper);
+ WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
}
@@ -449,10 +459,9 @@ seq_startplay (void)
unsigned long flags;
DISABLE_INTR (flags);
- if (seq_sleep_flag)
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
- seq_sleep_flag = 0;
- WAKE_UP (seq_sleeper);
+ WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
}
@@ -461,86 +470,87 @@ seq_startplay (void)
int
sequencer_open (int dev, struct fileinfo *file)
- {
- int retval, mode, i;
+{
+ int retval, mode, i;
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
- DEB (printk ("sequencer_open(dev=%d)\n", dev));
+ DEB (printk ("sequencer_open(dev=%d)\n", dev));
- if (!sequencer_ok)
- {
- printk ("Soundcard: Sequencer not initialized\n");
- return RET_ERROR (ENXIO);
- }
+ if (!sequencer_ok)
+ {
+ printk ("Soundcard: Sequencer not initialized\n");
+ return RET_ERROR (ENXIO);
+ }
- if (dev) /* Patch manager device */
- {
- int err;
+ if (dev) /* Patch manager device */
+ {
+ int err;
- dev--;
- if (pmgr_present[dev])
- return RET_ERROR (EBUSY);
- if ((err = pmgr_open (dev)) < 0)
- return err; /* Failed */
+ dev--;
+ if (pmgr_present[dev])
+ return RET_ERROR (EBUSY);
+ if ((err = pmgr_open (dev)) < 0)
+ return err; /* Failed */
- pmgr_present[dev] = 1;
- return err;
- }
+ pmgr_present[dev] = 1;
+ return err;
+ }
- if (sequencer_busy)
- {
- printk ("Sequencer busy\n");
- return RET_ERROR (EBUSY);
- }
+ if (sequencer_busy)
+ {
+ printk ("Sequencer busy\n");
+ return RET_ERROR (EBUSY);
+ }
- if (!(num_synths + num_midis))
- return RET_ERROR (ENXIO);
+ if (!(num_synths + num_midis))
+ return RET_ERROR (ENXIO);
- synth_open_mask = 0;
+ synth_open_mask = 0;
- if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
- for (i = 0; i < num_synths; i++) /* Open synth devices */
- if (synth_devs[i]->open (i, mode) < 0)
- printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
- else
- synth_open_mask |= (1 << i);
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+ for (i = 0; i < num_synths; i++) /* Open synth devices */
+ if (synth_devs[i]->open (i, mode) < 0)
+ printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
+ else
+ synth_open_mask |= (1 << i);
- seq_time = GET_TIME ();
+ seq_time = GET_TIME ();
- for (i = 0; i < num_midis; i++)
- {
- midi_opened[i] = 0;
- midi_written[i] = 0;
- }
+ for (i = 0; i < num_midis; i++)
+ {
+ midi_opened[i] = 0;
+ midi_written[i] = 0;
+ }
- if (mode == OPEN_READ || mode == OPEN_READWRITE)
- { /* Initialize midi input devices */
- if (!num_midis)
- {
- printk ("Sequencer: No Midi devices. Input not possible\n");
- return RET_ERROR (ENXIO);
- }
+ if (mode == OPEN_READ || mode == OPEN_READWRITE)
+ { /* Initialize midi input devices */
+ if (!num_midis)
+ {
+ printk ("Sequencer: No Midi devices. Input not possible\n");
+ return RET_ERROR (ENXIO);
+ }
- for (i = 0; i < num_midis; i++)
- {
- if ((retval = midi_devs[i]->open (i, mode,
+ for (i = 0; i < num_midis; i++)
+ {
+ if ((retval = midi_devs[i]->open (i, mode,
sequencer_midi_input, sequencer_midi_output)) >= 0)
- midi_opened[i] = 1;
- }
- }
+ midi_opened[i] = 1;
+ }
+ }
- sequencer_busy = 1;
- seq_sleep_flag = midi_sleep_flag = 0;
- output_treshold = SEQ_MAX_QUEUE / 2;
+ sequencer_busy = 1;
+ RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
+ RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
+ output_treshold = SEQ_MAX_QUEUE / 2;
- for (i = 0; i < num_synths; i++)
- if (pmgr_present[i])
- pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
+ for (i = 0; i < num_synths; i++)
+ if (pmgr_present[i])
+ pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
- return 0;
- }
+ return 0;
+}
void
seq_drain_midi_queues (void)
@@ -553,7 +563,7 @@ seq_drain_midi_queues (void)
n = 1;
- while (!PROCESS_ABORTING && n)
+ while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n)
{
n = 0;
@@ -568,70 +578,70 @@ seq_drain_midi_queues (void)
*/
if (n)
{
- REQUEST_TIMEOUT (HZ / 10, seq_sleeper);
- INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, HZ / 10);
}
}
}
void
sequencer_release (int dev, struct fileinfo *file)
- {
- int i;
- int mode = file->mode & O_ACCMODE;
+{
+ int i;
+ int mode = file->mode & O_ACCMODE;
- dev = dev >> 4;
+ dev = dev >> 4;
- DEB (printk ("sequencer_release(dev=%d)\n", dev));
+ DEB (printk ("sequencer_release(dev=%d)\n", dev));
- if (dev) /* Patch manager device */
- {
- dev--;
- pmgr_release (dev);
- pmgr_present[dev] = 0;
- return;
- }
+ if (dev) /* Patch manager device */
+ {
+ dev--;
+ pmgr_release (dev);
+ pmgr_present[dev] = 0;
+ return;
+ }
- /*
+ /*
* Wait until the queue is empty
- */
- while (!PROCESS_ABORTING && qlen)
- {
- seq_sync ();
- }
+ */
- if (mode != OPEN_READ)
- seq_drain_midi_queues (); /* Ensure the output queues are empty */
- seq_reset ();
- if (mode != OPEN_READ)
- seq_drain_midi_queues (); /* Flush the all notes off messages */
+ while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
+ {
+ seq_sync ();
+ }
- for (i = 0; i < num_midis; i++)
- if (midi_opened[i])
- midi_devs[i]->close (i);
+ if (mode != OPEN_READ)
+ seq_drain_midi_queues (); /* Ensure the output queues are empty */
+ seq_reset ();
+ if (mode != OPEN_READ)
+ seq_drain_midi_queues (); /* Flush the all notes off messages */
- if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
- for (i = 0; i < num_synths; i++)
- if (synth_open_mask & (1 << i)) /* Actually opened */
- if (synth_devs[i])
- synth_devs[i]->close (i);
+ for (i = 0; i < num_midis; i++)
+ if (midi_opened[i])
+ midi_devs[i]->close (i);
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
for (i = 0; i < num_synths; i++)
- if (pmgr_present[i])
- pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
+ if (synth_open_mask & (1 << i)) /* Actually opened */
+ if (synth_devs[i])
+ synth_devs[i]->close (i);
- sequencer_busy = 0;
- }
+ for (i = 0; i < num_synths; i++)
+ if (pmgr_present[i])
+ pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
+
+ sequencer_busy = 0;
+}
static int
seq_sync (void)
{
- if (qlen && !seq_playing && !PROCESS_ABORTING)
+ if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
seq_startplay ();
- if (qlen && !seq_sleep_flag) /* Queue not empty */
+ if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* Queue not empty */
{
- INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
}
return qlen;
@@ -654,8 +664,7 @@ midi_outc (int dev, unsigned char data)
while (n && !midi_devs[dev]->putc (dev, data))
{
- REQUEST_TIMEOUT (1, seq_sleeper);
- INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 4);
n--;
}
}
@@ -684,7 +693,8 @@ seq_reset (void)
{
for (chn = 0; chn < 16; chn++)
{
- midi_outc (i, 0xb0 + chn); /* Channel message */
+ midi_outc (i,
+ (unsigned char) (0xb0 + (chn & 0xff))); /* Channel msg */
midi_outc (i, 0x7b);/* All notes off */
midi_outc (i, 0); /* Dummy parameter */
}
@@ -697,7 +707,7 @@ seq_reset (void)
seq_playing = 0;
- if (seq_sleep_flag)
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
printk ("Sequencer Warning: Unexpected sleeping process\n");
}
@@ -720,7 +730,7 @@ sequencer_ioctl (int dev, struct fileinfo *file,
if (mode == OPEN_READ)
return 0;
- while (qlen && !PROCESS_ABORTING)
+ while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
seq_sync ();
return 0;
break;
@@ -979,7 +989,6 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w
case SEL_IN:
if (!iqlen)
{
- midi_sleep_flag = 1;
select_wait (&midi_sleeper, wait);
return 0;
}
@@ -990,7 +999,6 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w
case SEL_OUT:
if (qlen >= SEQ_MAX_QUEUE)
{
- seq_sleep_flag = 1;
select_wait (&seq_sleeper, wait);
return 0;
}
@@ -1039,7 +1047,7 @@ 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;
}
@@ -1048,7 +1056,7 @@ unsigned long
compute_finetune (unsigned long base_freq, int bend, int range)
{
unsigned long amount;
- int negative, semitones, cents;
+ int negative, semitones, cents, multiplier = 1;
if (!bend)
return base_freq;
@@ -1072,13 +1080,20 @@ compute_finetune (unsigned long base_freq, int bend, int range)
if (bend > range)
bend = range;
- if (bend > 2399)
- bend = 2399;
+ /*
+ if (bend > 2399)
+ bend = 2399;
+ */
+ while (bend > 2399)
+ {
+ multiplier *= 4;
+ bend -= 2400;
+ }
semitones = bend / 100;
cents = bend % 100;
- amount = semitone_tuning[semitones] * cent_tuning[cents] / 10000;
+ amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents] / 10000;
if (negative)
return (base_freq * 10000) / amount; /* Bend down */
@@ -1092,6 +1107,9 @@ sequencer_init (long mem_start)
{
sequencer_ok = 1;
+ PERMANENT_MALLOC (unsigned char *, queue, SEQ_MAX_QUEUE * EV_SZ, mem_start);
+ PERMANENT_MALLOC (unsigned char *, iqueue, SEQ_MAX_QUEUE * IEV_SZ, mem_start);
+
return mem_start;
}
@@ -1111,14 +1129,14 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
int
sequencer_open (int dev, struct fileinfo *file)
- {
- return RET_ERROR (ENXIO);
- }
+{
+ return RET_ERROR (ENXIO);
+}
void
sequencer_release (int dev, struct fileinfo *file)
- {
- }
+{
+}
int
sequencer_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, unsigned int arg)
@@ -1138,11 +1156,14 @@ sequencer_init (long mem_start)
return mem_start;
}
+#ifdef ALLOW_SELECT
+
int
sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
return RET_ERROR (EIO);
}
+#endif /* ALLOW_SELECT */
#endif
diff --git a/sys/i386/isa/sound/sound_calls.h b/sys/i386/isa/sound/sound_calls.h
index 89bd79604359..abc82001b776 100644
--- a/sys/i386/isa/sound/sound_calls.h
+++ b/sys/i386/isa/sound/sound_calls.h
@@ -16,23 +16,10 @@ int DMAbuf_open_dma (int chan);
void DMAbuf_close_dma (int chan);
void DMAbuf_reset_dma (int chan);
void DMAbuf_inputintr(int dev);
-void DMAbuf_outputintr(int dev);
+void DMAbuf_outputintr(int dev, int underflow_flag);
/*
- * System calls for the /dev/dsp
- */
-
-int dsp_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
-int dsp_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
-int dsp_open (int dev, struct fileinfo *file, int bits);
-void dsp_release (int dev, struct fileinfo *file);
-int dsp_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg);
-int dsp_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
-long dsp_init (long mem_start);
-
-/*
- * System calls for the /dev/audio
+ * System calls for /dev/dsp and /dev/audio
*/
int audio_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
@@ -108,11 +95,47 @@ void tenmicrosec(void);
void request_sound_timer (int count);
void sound_stop_timer(void);
int snd_ioctl_return(int *addr, int value);
+int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int));
+void snd_release_irq(int vect);
+void sound_dma_malloc(int dev);
+void sound_dma_free(int dev);
+
+/* From sound_switch.c */
+int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int sound_open_sw (int dev, struct fileinfo *file);
+void sound_release_sw (int dev, struct fileinfo *file);
+int sound_ioctl_sw (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned long arg);
/* From sb_dsp.c */
int sb_dsp_detect (struct address_info *hw_config);
long sb_dsp_init (long mem_start, struct address_info *hw_config);
void sb_dsp_disable_midi(void);
+int sb_get_irq(void);
+void sb_free_irq(void);
+int sb_dsp_command (unsigned char val);
+int sb_reset_dsp (void);
+
+/* From sb16_dsp.c */
+void sb16_dsp_interrupt (int unused);
+long sb16_dsp_init(long mem_start, struct address_info *hw_config);
+int sb16_dsp_detect(struct address_info *hw_config);
+
+/* From sb16_midi.c */
+void sb16midiintr (int unit);
+long attach_sb16midi(long mem_start, struct address_info * hw_config);
+int probe_sb16midi(struct address_info *hw_config);
+
+/* 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);
/* From opl3.c */
int opl3_detect (int ioaddr);
@@ -156,9 +179,10 @@ int gus_wave_detect(int baseaddr);
long gus_wave_init(long mem_start, int irq, int dma);
void gus_voice_irq(void);
unsigned char gus_read8 (int reg);
-void gus_write8(int reg, unsigned char data);
+void gus_write8(int reg, unsigned int data);
void guswave_dma_irq(void);
void gus_delay(void);
+int gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg);
/* From gus_midi.c */
long gus_midi_init(long mem_start);
@@ -179,3 +203,6 @@ int pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count);
int pmgr_access(int dev, struct patmgr_info *rec);
int pmgr_inform(int dev, int event, unsigned long parm1, unsigned long parm2,
unsigned long parm3, unsigned long parm4);
+
+/* From ics2101.c */
+long ics2101_mixer_init(long mem_start);
diff --git a/sys/i386/isa/sound/sound_config.h b/sys/i386/isa/sound/sound_config.h
index 9cbd8103b8f5..0d30c12aadc4 100644
--- a/sys/i386/isa/sound/sound_config.h
+++ b/sys/i386/isa/sound/sound_config.h
@@ -30,6 +30,16 @@
#include "local.h"
+
+#undef CONFIGURE_SOUNDCARD
+#undef DYNAMIC_BUFFER
+
+#ifdef KERNEL_SOUNDCARD
+#define CONFIGURE_SOUNDCARD
+#define DYNAMIC_BUFFER
+#undef LOADABLE_SOUNDCARD
+#endif
+
#ifdef EXCLUDE_SEQUENCER
#ifndef EXCLUDE_MIDI
#define EXCLUDE_MIDI
@@ -42,6 +52,10 @@
#endif
#endif
+#ifndef SND_DEFAULT_ENABLE
+#define SND_DEFAULT_ENABLE 1
+#endif
+
/** UWM - new MIDI stuff **/
#ifdef EXCLUDE_CHIP_MIDI
@@ -75,6 +89,14 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define SBC_DMA 1
#endif
+#ifndef SB16_DMA
+#define SB16_DMA 6
+#endif
+
+#ifndef SB16MIDI_BASE
+#define SB16MIDI_BASE 0x300
+#endif
+
#ifndef PAS_BASE
#define PAS_BASE 0x388
#endif
@@ -111,6 +133,10 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define MPU_IRQ 6
#endif
+#ifndef MAX_REALTIME_FACTOR
+#define MAX_REALTIME_FACTOR 4
+#endif
+
/************* PCM DMA buffer sizes *******************/
/* If you are using high playback or recording speeds, the default buffersize
@@ -132,8 +158,6 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define DMA_AUTOINIT 0x10
-#define SND_MAJOR 14
-
#define FM_MONO 0x388 /* This is the I/O address used by AdLib */
/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
@@ -178,10 +202,10 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define ON 1
#define OFF 0
-#define MAX_DSP_DEV 3
-#define MAX_MIXER_DEV 1
+#define MAX_DSP_DEV 4
+#define MAX_MIXER_DEV 2
#define MAX_SYNTH_DEV 3
-#define MAX_MIDI_DEV 3
+#define MAX_MIDI_DEV 4
struct fileinfo {
int mode; /* Open mode */
@@ -193,6 +217,15 @@ struct address_info {
int dma;
};
+/*
+ * Process wakeup reasons
+ */
+#define WK_NONE 0x00
+#define WK_WAKEUP 0x01
+#define WK_TIMEOUT 0x02
+#define WK_SIGNAL 0x04
+#define WK_SLEEP 0x08
+
#define OPEN_READ 1
#define OPEN_WRITE 2
#define OPEN_READWRITE 3
diff --git a/sys/i386/isa/sound/sound_switch.c b/sys/i386/isa/sound/sound_switch.c
new file mode 100644
index 000000000000..68c757586083
--- /dev/null
+++ b/sys/i386/isa/sound/sound_switch.c
@@ -0,0 +1,445 @@
+/*
+ * sound/sound_switch.c
+ *
+ * The system call switch
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * 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
+
+struct sbc_device
+ {
+ int usecount;
+ };
+
+static struct sbc_device sbc_devices[SND_NDEVS] =
+{
+ {0}};
+
+static int in_use = 0; /* Total # of open device files (excluding
+
+ * minor 0) */
+
+/*
+ * /dev/sndstatus -device
+ */
+static char *status_buf = NULL;
+static int status_len, status_ptr;
+static int status_busy = 0;
+
+static int
+put_status (char *s)
+{
+ int l;
+
+ for (l = 0; l < 256, s[l]; l++); /* l=strlen(s); */
+
+ if (status_len + l >= 4000)
+ return 0;
+
+ memcpy (&status_buf[status_len], s, l);
+ status_len += l;
+
+ return 1;
+}
+
+static int
+put_status_int (unsigned int val, int radix)
+{
+ int l, v;
+
+ static char hx[] = "0123456789abcdef";
+ char buf[11];
+
+ if (!val)
+ return put_status ("0");
+
+ l = 0;
+ buf[10] = 0;
+
+ while (val)
+ {
+ v = val % radix;
+ val = val / radix;
+
+ buf[9 - l] = hx[v];
+ l++;
+ }
+
+ if (status_len + l >= 4000)
+ return 0;
+
+ memcpy (&status_buf[status_len], &buf[10 - l], l);
+ status_len += l;
+
+ return 1;
+}
+
+static void
+init_status (void)
+{
+ /*
+ * Write the status information to the status_buf and update status_len.
+ * There is a limit of 4000 bytes for the data.
+ */
+
+ int i;
+
+ status_ptr = 0;
+
+ put_status ("Sound Driver:" SOUND_VERSION_STRING
+ " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
+ SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")"
+ "\n");
+
+ if (!put_status ("Config options: "))
+ return;
+ if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
+ return;
+
+ if (!put_status ("\n\nHW config: \n"))
+ return;
+
+ for (i = 0; i < (num_sound_drivers - 1); i++)
+ {
+ if (!supported_drivers[i].enabled)
+ if (!put_status ("("))
+ return;
+
+ if (!put_status ("Type "))
+ return;
+ if (!put_status_int (supported_drivers[i].card_type, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (supported_drivers[i].name))
+ return;
+ if (!put_status (" at 0x"))
+ return;
+ if (!put_status_int (supported_drivers[i].config.io_base, 16))
+ return;
+ if (!put_status (" irq "))
+ return;
+ if (!put_status_int (supported_drivers[i].config.irq, 10))
+ return;
+ if (!put_status (" drq "))
+ return;
+ if (!put_status_int (supported_drivers[i].config.dma, 10))
+ return;
+
+ if (!supported_drivers[i].enabled)
+ if (!put_status (")"))
+ return;
+
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nPCM devices:\n"))
+ return;
+
+ for (i = 0; i < num_dspdevs; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (dsp_devs[i]->name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nSynth devices:\n"))
+ return;
+
+ for (i = 0; i < num_synths; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (synth_devs[i]->info->name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nMidi devices:\n"))
+ return;
+
+ for (i = 0; i < num_midis; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (midi_devs[i]->info.name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (num_mixers)
+ {
+ if (!put_status ("\nMixer(s) installed\n"))
+ return;
+ }
+ else
+ {
+ if (!put_status ("\nNo mixers installed\n"))
+ return;
+ }
+}
+
+static int
+read_status (snd_rw_buf * buf, int count)
+{
+ /*
+ * Return at most 'count' bytes from the status_buf.
+ */
+ int l, c;
+
+ l = count;
+ c = status_len - status_ptr;
+
+ if (l > c)
+ l = c;
+ if (l <= 0)
+ return 0;
+
+ COPY_TO_USER (buf, 0, &status_buf[status_ptr], l);
+ status_ptr += l;
+
+ return l;
+}
+
+int
+sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count));
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ return read_status (buf, count);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_read (dev, file, buf, count);
+ break;
+
+ case SND_DEV_SEQ:
+ return sequencer_read (dev, file, buf, count);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ return MIDIbuf_read (dev, file, buf, count);
+#endif
+
+ default:
+ printk ("Sound: Undefined minor device %d\n", dev);
+ }
+
+ return RET_ERROR (EPERM);
+}
+
+int
+sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+
+ DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count));
+
+ switch (dev & 0x0f)
+ {
+
+ case SND_DEV_SEQ:
+ return sequencer_write (dev, file, buf, count);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_write (dev, file, buf, count);
+ break;
+
+ default:
+ return RET_ERROR (EPERM);
+ }
+
+ return count;
+}
+
+int
+sound_open_sw (int dev, struct fileinfo *file)
+{
+ int retval;
+
+ DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
+
+ if ((dev >= SND_NDEVS) || (dev < 0))
+ {
+ printk ("Invalid minor device %d\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ if (status_busy)
+ return RET_ERROR (EBUSY);
+ status_busy = 1;
+ if ((status_buf = (char *) KERNEL_MALLOC (4000)) == NULL)
+ return RET_ERROR (EIO);
+ status_len = status_ptr = 0;
+ init_status ();
+ break;
+
+ case SND_DEV_CTL:
+ return 0;
+ break;
+
+ case SND_DEV_SEQ:
+ if ((retval = sequencer_open (dev, file)) < 0)
+ return retval;
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ if ((retval = MIDIbuf_open (dev, file)) < 0)
+ return retval;
+ break;
+#endif
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ if ((retval = audio_open (dev, file)) < 0)
+ return retval;
+ break;
+
+ default:
+ printk ("Invalid minor device %d\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ sbc_devices[dev].usecount++;
+ in_use++;
+
+ return 0;
+}
+
+void
+sound_release_sw (int dev, struct fileinfo *file)
+{
+
+ DEB (printk ("sound_release_sw(dev=%d)\n", dev));
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ if (status_buf)
+ KERNEL_FREE (status_buf);
+ status_buf = NULL;
+ status_busy = 0;
+ break;
+
+ case SND_DEV_CTL:
+ break;
+
+ case SND_DEV_SEQ:
+ sequencer_release (dev, file);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ MIDIbuf_release (dev, file);
+ break;
+#endif
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ audio_release (dev, file);
+ break;
+
+ default:
+ printk ("Sound error: Releasing unknown device 0x%02x\n", dev);
+ }
+
+ sbc_devices[dev].usecount--;
+ in_use--;
+}
+
+int
+sound_ioctl_sw (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned long arg)
+{
+ DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
+
+ switch (dev & 0x0f)
+ {
+
+ case SND_DEV_CTL:
+
+ if (!num_mixers)
+ return RET_ERROR (ENXIO);
+
+ if ((dev >> 4) >= num_mixers)
+ return RET_ERROR (ENXIO);
+
+ return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg);
+ break;
+
+ case SND_DEV_SEQ:
+ return sequencer_ioctl (dev, file, cmd, arg);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_ioctl (dev, file, cmd, arg);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ return MIDIbuf_ioctl (dev, file, cmd, arg);
+ break;
+#endif
+
+ default:
+ return RET_ERROR (EPERM);
+ break;
+ }
+
+ return RET_ERROR (EPERM);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/soundcard.c b/sys/i386/isa/sound/soundcard.c
index 79c9b09298d1..9691e4f07bec 100644
--- a/sys/i386/isa/sound/soundcard.c
+++ b/sys/i386/isa/sound/soundcard.c
@@ -34,28 +34,20 @@
#include "dev_table.h"
-int __timeout_val = 0;
-int __process_aborting = 0;
-
-u_int snd1mask;
-u_int snd2mask;
-u_int snd3mask;
-u_int snd4mask;
-u_int snd5mask;
-
-struct sbc_device
-{
- int usecount;
-};
+u_int snd1_imask;
+u_int snd2_imask;
+u_int snd3_imask;
+u_int snd4_imask;
+u_int snd5_imask;
+u_int snd6_imask;
+u_int snd7_imask;
+u_int snd8_imask;
+u_int snd9_imask;
#define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
-static struct sbc_device sbc_devices[SND_NDEVS];
static int timer_running = 0;
-static int in_use = 0; /* Total # of open device files (excluding
- * minor 0) */
-
static int soundcards_installed = 0; /* Number of installed
* soundcards */
static int soundcard_configured = 0;
@@ -75,12 +67,19 @@ int sndwrite (int dev, struct uio *uio);
int sndselect (int dev, int rw);
static void sound_mem_init(void);
+unsigned
long
-get_time()
+get_time(void)
{
extern struct timeval time;
-
- return(time.tv_usec + (time.tv_sec*1000000));
+struct timeval timecopy;
+int x;
+
+ x = splclock();
+ timecopy = time;
+ splx(x);
+ return timecopy.tv_usec/(1000000/HZ) +
+ (unsigned long)timecopy.tv_sec*HZ;
}
@@ -91,41 +90,7 @@ sndread (int dev, struct uio *buf)
dev = minor (dev);
- DEB (printk ("sound_read(dev=%d, count=%d)\n", dev, count));
-
- switch (dev & 0x0f) /* It really has to be 0x0f */
- {
- case SND_DEV_AUDIO:
- FIX_RETURN (audio_read (dev, &files[dev], buf, count));
- break;
-
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- FIX_RETURN (dsp_read (dev, &files[dev], buf, count));
- break;
-
- case SND_DEV_SEQ:
- FIX_RETURN (sequencer_read (dev, &files[dev], buf, count));
- break;
-
-#ifndef EXCLUDE_CHIP_MIDI
- case CMIDI_DEV_PRO:
- FIX_RETURN (CMIDI_read (dev, &files[dev], buf, count));
-
- break;
-#endif
-
-
-#ifndef EXCLUDE_MPU401
- case SND_DEV_MIDIN:
- FIX_RETURN (MIDIbuf_read (dev, &files[dev], buf, count));
-#endif
-
- default:
- ;
- }
-
- FIX_RETURN (-EPERM);
+ FIX_RETURN (sound_read_sw (dev, &files[dev], buf, count));
}
int
@@ -133,37 +98,9 @@ sndwrite (int dev, struct uio *buf)
{
int count = buf->uio_resid;
- DEB (printk ("sound_write(dev=%d, count=%d)\n", dev, count));
-
dev = minor (dev);
- switch (dev & 0x0f) /* It really has to be 0x0f */
- {
-
- case SND_DEV_SEQ:
- FIX_RETURN (sequencer_write (dev, &files[dev], buf, count));
- break;
-
- case SND_DEV_AUDIO:
- FIX_RETURN (audio_write (dev, &files[dev], buf, count));
- break;
-
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- FIX_RETURN (dsp_write (dev, &files[dev], buf, count));
- break;
-
-#ifndef EXCLUDE_CHIP_MIDI
- case CMIDI_DEV_PRO:
- FIX_RETURN (CMIDI_write (dev, &files[dev], buf, count));
- break;
-#endif
-
- default:
- FIX_RETURN (-EPERM);
- }
-
- FIX_RETURN (count);
+ FIX_RETURN (sound_write_sw (dev, &files[dev], buf, count));
}
int
@@ -173,16 +110,6 @@ sndopen (dev_t dev, int flags)
dev = minor (dev);
- /* printf("SND: Minor number is now : %ld\n",dev); */
-
- DEB (printk ("sound_open(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
-
- if ((dev >= SND_NDEVS) || (dev < 0))
- {
- printk ("Invalid minor device %d\n", dev);
- FIX_RETURN (-ENODEV);
- }
-
if (!soundcard_configured && dev)
{
printk ("SoundCard Error: The soundcard system has not been configured\n");
@@ -198,62 +125,7 @@ sndopen (dev_t dev, int flags)
else if (flags & FWRITE)
files[dev].mode = OPEN_WRITE;
- switch (dev & 0x0f) /* It has to be 0x0f. Trust me */
- {
- case SND_DEV_CTL:
- if (!soundcards_installed)
- if (soundcard_configured)
- {
- printk ("Soundcard not installed\n");
- FIX_RETURN (-ENODEV);
- }
- break;
-
- case SND_DEV_SEQ:
- if ((retval = sequencer_open (dev, &files[dev])) < 0)
- FIX_RETURN (retval);
- break;
-
-/** UWM stuff **/
-
-#ifndef EXCLUDE_CHIP_MIDI
- case CMIDI_DEV_PRO:
- FIX_RETURN ( CMIDI_open (dev, &files[dev]) );
- break;
-#endif
-
-
-#ifndef EXCLUDE_MPU401
- case SND_DEV_MIDIN:
- if ((retval = MIDIbuf_open (dev, &files[dev])) < 0)
- FIX_RETURN (retval);
- break;
-#endif
-
- case SND_DEV_AUDIO:
- if ((retval = audio_open (dev, &files[dev])) < 0)
- FIX_RETURN (retval);
- break;
-
- case SND_DEV_DSP:
- if ((retval = dsp_open (dev, &files[dev], 8)) < 0)
- FIX_RETURN (retval);
- break;
-
- case SND_DEV_DSP16:
- if ((retval = dsp_open (dev, &files[dev], 16)) < 0)
- FIX_RETURN (retval);
- break;
-
- default:
- printk ("Invalid minor device %d\n", dev);
- FIX_RETURN (-ENODEV);
- }
-
- sbc_devices[dev].usecount++;
- in_use++;
-
- FIX_RETURN (0);
+ FIX_RETURN(sound_open_sw (dev, &files[dev]));
}
int
@@ -262,41 +134,7 @@ sndclose (dev_t dev, int flags)
dev = minor (dev);
- DEB (printk ("sound_release(dev=%d)\n", dev));
-
- switch (dev & 0x0f) /* Has to be 0x0f */
- {
- case SND_DEV_SEQ:
- sequencer_release (dev, &files[dev]);
- break;
-
-#ifndef EXCLUDE_CHIP_MIDI
- case CMIDI_DEV_PRO:
- CMIDI_close (dev, &files[dev]);
- break;
-#endif
-
-#ifndef EXCLUDE_MPU401
- case SND_DEV_MIDIN:
- MIDIbuf_release (dev, &files[dev]);
- break;
-#endif
-
- case SND_DEV_AUDIO:
- audio_release (dev, &files[dev]);
- break;
-
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- dsp_release (dev, &files[dev]);
- break;
-
- default:;
- }
-
- sbc_devices[dev].usecount--;
- in_use--; /* If not control port */
-
+ sound_release_sw(dev, &files[dev]);
FIX_RETURN (0);
}
@@ -305,46 +143,7 @@ sndioctl (dev_t dev, int cmd, caddr_t arg, int mode)
{
dev = minor (dev);
- DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
-
- switch (dev & 0x0f)
- {
-
- case SND_DEV_CTL:
- if (!num_mixers)
- FIX_RETURN (-ENODEV);
-
- if (dev >= num_mixers)
- FIX_RETURN (-ENODEV);
-
- FIX_RETURN (mixer_devs[dev]->ioctl (dev, cmd, (unsigned int) arg));
- break;
-
- case SND_DEV_SEQ:
- FIX_RETURN (sequencer_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
- break;
-
- case SND_DEV_AUDIO:
- FIX_RETURN (audio_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
- break;
-
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- FIX_RETURN (dsp_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
- break;
-
-#ifndef EXCLUDE_MPU401
- case SND_DEV_MIDIN:
- FIX_RETURN (MIDIbuf_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
- break;
-#endif
-
- default:
- FIX_RETURN (-EPERM);
- break;
- }
-
- FIX_RETURN (-EPERM);
+ FIX_RETURN (sound_ioctl_sw (dev, &files[dev], cmd, (unsigned int) arg));
}
int
@@ -380,7 +179,6 @@ sndprobe (struct isa_device *dev)
hw_config.io_base = dev->id_iobase;
hw_config.irq = ipri_to_irq (dev->id_irq);
hw_config.dma = dev->id_drq;
-
return sndtable_probe (dev->id_unit, &hw_config);
}
@@ -430,7 +228,6 @@ sndattach (struct isa_device *dev)
dsp_initialized = 1;
mem_start = DMAbuf_init (mem_start);
mem_start = audio_init (mem_start);
- mem_start = dsp_init (mem_start);
}
/** UWM stuff **/
@@ -459,11 +256,6 @@ sndattach (struct isa_device *dev)
mem_start = sequencer_init (mem_start);
}
- for (i = 0; i < SND_NDEVS; i++)
- {
- sbc_devices[i].usecount = 0;
- }
-
return TRUE;
}
@@ -514,7 +306,7 @@ void
sound_stop_timer (void)
{
if (timer_running)
- untimeout ((timeout_func_t)sequencer_timer, 0); /* XXX should fix */
+ untimeout ((timeout_func_t)sequencer_timer, 0);
timer_running = 0;
}
@@ -533,26 +325,12 @@ sound_mem_init (void)
dsp_init_mask |= (1 << dev);
if (sound_dma_automode[dev])
- {
- sound_dma_automode[dev] = 0; /* Not possible with FreeBSD */
- }
-
- if (sound_buffcounts[dev] == 1)
- {
- sound_buffcounts[dev] = 2;
- sound_buffsizes[dev] /= 2;
- }
-
- if (sound_buffsizes[dev] > 65536) /* Larger is not possible (yet) */
- sound_buffsizes[dev] = 65536;
+ sound_buffcounts[dev] = 1;
-#if 0
if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536)
dma_pagesize = 131072; /* 128k */
else
dma_pagesize = 65536;
-#endif
- dma_pagesize = 4096; /* use bounce buffer */
/* More sanity checks */
@@ -566,31 +344,17 @@ sound_mem_init (void)
for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++)
{
- /*
- * The DMA buffer allocation algorithm hogs memory. We allocate
- * a memory area which is two times the requires size. This
- * guarantees that it contains at least one valid DMA buffer.
- *
- * This really needs some kind of finetuning.
- */
- char *tmpbuf = malloc (2*sound_buffsizes[dev], M_DEVBUF, M_NOWAIT);
- unsigned long addr, rounded;
+ char *tmpbuf = contigmalloc (sound_buffsizes[dev], M_DEVBUF, M_NOWAIT,
+ 0xFFFFFFul, 0ul, dma_pagesize - 1);
if (tmpbuf == NULL)
{
printk ("snd: Unable to allocate %d bytes of buffer\n",
- 2 * sound_buffsizes[dev]);
+ sound_buffsizes[dev]);
return;
}
- addr = kvtop (tmpbuf);
- /*
- * Align the start address
- */
- rounded = (addr & ~(dma_pagesize - 1)) + dma_pagesize;
-
- snd_raw_buf[dev][snd_raw_count[dev]] =
- &tmpbuf[rounded - addr]; /* Compute offset */
+ snd_raw_buf[dev][snd_raw_count[dev]] = tmpbuf;
/*
* Use virtual address as the physical address, since
* isa_dmastart performs the phys address computation.
@@ -616,4 +380,15 @@ snd_ioctl_return (int *addr, int value)
return 0;
}
+int
+snd_set_irq_handler (int interrupt_level, void(*hndlr)(int))
+{
+ return 1;
+}
+
+void
+snd_release_irq(int vect)
+{
+}
+
#endif