aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Murray <markm@FreeBSD.org>1997-11-10 18:10:41 +0000
committerMark Murray <markm@FreeBSD.org>1997-11-10 18:10:41 +0000
commit8bfc1067c3b493685418300fea866d851ab98a63 (patch)
treecb233efdc05a92c1e2283040d95ca68fefed6548
parent915f1f5d0871c790bcb1a126ef69a6b88e2d14f2 (diff)
downloadsrc-vendor/voxware.tar.gz
src-vendor/voxware.zip
Import of guspnp23.vendor/voxware
Notes
Notes: svn path=/cvs2svn/branches/AMANCIO/; revision=31106
-rw-r--r--sys/i386/isa/sound/CHANGELOG104
-rw-r--r--sys/i386/isa/sound/README16
-rw-r--r--sys/i386/isa/sound/Readme.modules186
-rw-r--r--sys/i386/isa/sound/Readme.v3036
-rw-r--r--sys/i386/isa/sound/ad1848.c2272
-rw-r--r--sys/i386/isa/sound/ad1848_mixer.h36
-rw-r--r--sys/i386/isa/sound/adlib_card.c29
-rw-r--r--sys/i386/isa/sound/aedsp16.c838
-rw-r--r--sys/i386/isa/sound/audio.c599
-rw-r--r--sys/i386/isa/sound/awe_wave.c51
-rw-r--r--sys/i386/isa/sound/dev_table.c414
-rw-r--r--sys/i386/isa/sound/dev_table.h696
-rw-r--r--sys/i386/isa/sound/dmabuf.c1944
-rw-r--r--sys/i386/isa/sound/gus_card.c221
-rw-r--r--sys/i386/isa/sound/gus_midi.c347
-rw-r--r--sys/i386/isa/sound/gus_vol.c171
-rw-r--r--sys/i386/isa/sound/gus_wave.c6536
-rw-r--r--sys/i386/isa/sound/hex2hex.h2
-rw-r--r--sys/i386/isa/sound/ics2101.c362
-rw-r--r--sys/i386/isa/sound/local.h201
-rw-r--r--sys/i386/isa/sound/midi_ctrl.h8
-rw-r--r--sys/i386/isa/sound/midi_synth.c797
-rw-r--r--sys/i386/isa/sound/midi_synth.h10
-rw-r--r--sys/i386/isa/sound/midibuf.c618
-rw-r--r--sys/i386/isa/sound/mpu401.c2271
-rw-r--r--sys/i386/isa/sound/opl3.c1697
-rw-r--r--sys/i386/isa/sound/opl3.h15
-rw-r--r--sys/i386/isa/sound/os.h343
-rw-r--r--sys/i386/isa/sound/pas2_card.c498
-rw-r--r--sys/i386/isa/sound/pas2_midi.c407
-rw-r--r--sys/i386/isa/sound/pas2_mixer.c566
-rw-r--r--sys/i386/isa/sound/pas2_pcm.c604
-rw-r--r--sys/i386/isa/sound/patmgr.c323
-rw-r--r--sys/i386/isa/sound/pcm86.c6
-rw-r--r--sys/i386/isa/sound/pss.c1403
-rw-r--r--sys/i386/isa/sound/sb16_dsp.c733
-rw-r--r--sys/i386/isa/sound/sb16_midi.c333
-rw-r--r--sys/i386/isa/sound/sb_card.c47
-rw-r--r--sys/i386/isa/sound/sb_dsp.c1481
-rw-r--r--sys/i386/isa/sound/sb_midi.c251
-rw-r--r--sys/i386/isa/sound/sb_mixer.c668
-rw-r--r--sys/i386/isa/sound/sb_mixer.h214
-rw-r--r--sys/i386/isa/sound/sequencer.c2597
-rw-r--r--sys/i386/isa/sound/sound.doc155
-rw-r--r--sys/i386/isa/sound/sound_calls.h224
-rw-r--r--sys/i386/isa/sound/sound_config.h183
-rw-r--r--sys/i386/isa/sound/sound_switch.c633
-rw-r--r--sys/i386/isa/sound/sound_timer.c458
-rw-r--r--sys/i386/isa/sound/soundcard.c773
-rw-r--r--sys/i386/isa/sound/soundvers.h3
-rw-r--r--sys/i386/isa/sound/sscape.c1340
-rw-r--r--sys/i386/isa/sound/sys_timer.c328
-rw-r--r--sys/i386/isa/sound/trix.c443
-rw-r--r--sys/i386/isa/sound/uart6850.c320
-rw-r--r--sys/i386/isa/sound/ulaw.h130
-rw-r--r--sys/i386/isa/sound/ultrasound.h72
56 files changed, 19258 insertions, 16755 deletions
diff --git a/sys/i386/isa/sound/CHANGELOG b/sys/i386/isa/sound/CHANGELOG
index fcdbb8e3eae6..878e2b75874a 100644
--- a/sys/i386/isa/sound/CHANGELOG
+++ b/sys/i386/isa/sound/CHANGELOG
@@ -1,10 +1,100 @@
-Changelog for version 2.90
-------------------------------------
-
-This is an intermediate release (v3.0 prototype with some experimental
-features disabled). See experimental.txt for more info.
+Changelog for version 3.5-alpha7
+--------------------------------
+
+Since 3.5-alpha6
+- Changed all #ifndef EXCLUDE_xx stuff to #ifdef CONFIG_xx. Modified
+configure to handle this.
+- Removed initialization messages from the
+modularized version. They can be enabled by using init_trace=1 in
+the insmod command line (insmod sound init_trace=1).
+- More AIX stuff.
+- Added support for syncronizing dsp/audio devices with /dev/sequencer.
+- mmap() support for dsp/audio devices.
+
+Since 3.5-alpha5
+- AIX port.
+- Changed some xxx_PATCH macros in soundcard.h to work with
+ big endian machines.
+
+Since 3.5-alpha4
+- Removed the 'setfx' stuff from the version distributed with kernel
+ sources.
+
+Since 3.5-alpha3
+- Moved stuff from the 'setfx' program to the AudioTriX Pro driver.
+
+Since 3.5-alpha2
+- Modifications to makefile and configure.c. Unnecessary sources
+ are no longer compiled. Newly created local.h is also copied to
+ /etc/soundconf. "make oldconfig" reads /etc/soundconf and produces
+ new local.h which is compatible with current version of the driver.
+- Some fixes to the SB16 support.
+- Fixed random protection fault in gus_wave.c
+
+Since 3.5-alpha1
+- Modified to work with Linux-1.3.33 and leater
+- Some minor changes
-Since pre-3.0-949712
+Since 3.0.2
+- Support for CS4232 based PnP cards (AcerMagic S23 etc).
+- Full duplex support for some CS4231, CS4232 and AD1845 based cards
+(GUA MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards
+having a codec mentioned above).
+- Almost fully rewritten loadable modules support.
+- Fixed some bugs.
+- Huge amount of testing (more testing is still required).
+- mmap() support (works with some cards). Requires much more testing.
+- Sample/patch/program loading for TB Maui/Tropez. No initialization
+since TB doesn't allow me to release that code.
+- Using CS4231 compatible codecs as timer for /dev/music.
+
+Since 3.0.1
+- Added allocation of I/O ports, DMA channels and interrupts
+to the initialization code. This may break modules support since
+the driver may not free some resources on unload. Should be fixed soon.
+
+Since 3.0
+- Some important bug fixes.
+- select() for /dev/dsp and /dev/audio (Linux only).
+(To use select() with read, you have to call read() to start
+the recording. Calling write() kills recording immediately so
+use select() carefully when you are writing a half duplex app.
+Full duplex mode is not implemented yet.) Select works also with
+/dev/sequencer and /dev/music. Maybe with /dev/midi## too.
+
+Since 3.0-beta2
+- Minor fixes.
+- Added Readme.cards
+
+Since 3.0-beta1
+- Minor fixes to the modules support.
+- Eliminated call to sb_free_irq() in ad1848.c
+- Rewritten MAD16&Mozart support (not tested with MAD16 Pro).
+- Fix to DMA initialization of PSS cards.
+- Some fixes to ad1848/cs42xx mixer support (GUS MAX, MSS, etc.)
+- Fixed some bugs in the PSS driver which caused I/O errors with
+ the MSS mode (/dev/dsp).
+
+Since 3.0-950506
+- Recording with GUS MAX fixed. It works when the driver is configured
+ to use two DMA channels with GUS MAX (16 bit ones recommended).
+
+Since 3.0-94xxxx
+- Too many changes
+
+Since 3.0-940818
+- Fixes for Linux 1.1.4x.
+- Disables Disney Sound System with SG NX Pro 16 (less noise).
+
+Since 2.90-2
+- Fixes to soundcard.h
+- Non blocking mode to /dev/sequencer
+- Experimental detection code for Ensoniq Soundscape.
+
+Since 2.90
+- Minor and major bug fixes
+
+Since pre-3.0-940712
- GUS MAX support
- Partially working MSS/WSS support (could work with some cards).
- Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs
@@ -52,7 +142,7 @@ Since 2.4
- 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
+- Implemented better detection for OPL-3. This should be useful 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).
diff --git a/sys/i386/isa/sound/README b/sys/i386/isa/sound/README
index a4a084706e5b..1c31ac66c2a7 100644
--- a/sys/i386/isa/sound/README
+++ b/sys/i386/isa/sound/README
@@ -38,14 +38,14 @@ Compatibility with the earlier versions
This version is backward compatible with the version 2.X. All programs
compiled with sys/soundcard.h of v2.X should work without problems.
PROGRAMS COMPILED WITH THE sys/soundcard.h OF THIS VERSION WILL NOT
-WORK WITH v2.X DRIVER. BE CAREFULL WHEN DISTRIBUTING BINARIES COMPILED
+WORK WITH v2.X DRIVER. BE CAREFUL WHEN DISTRIBUTING BINARIES COMPILED
FOR THIS VERSION.
Contributors
------------
This driver contains code by several contributors. In addition several other
-persons have given usefull suggestions. The following is a list of major
+persons have given useful 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
@@ -74,7 +74,13 @@ Hannu Savolainen
hannu@voxware.pp.fi
Snail mail: Hannu Savolainen
- Pallaksentie 4 A 2
- 00970 Helsinki
+ Hiekkalaiturintie 3 A 8
+ 00980 Helsinki
Finland
-FAX: +358 0 395 1968 (usually not connected)
+FAX: +358 0 341 6272 (answers if I have my machine (mgetty) on).
+
+NOTE! I probably don't answer to Snail mail or FAX messages. Sending answer
+ to each of them is simply too expensive and time consuming. However I
+ try to reply every email message I get (within a week). If you don't
+ get response, please check how your address is written in the message
+ header. I can't answer if I don't have a valid reply address.
diff --git a/sys/i386/isa/sound/Readme.modules b/sys/i386/isa/sound/Readme.modules
index 315540f510c1..2dab12552d1b 100644
--- a/sys/i386/isa/sound/Readme.modules
+++ b/sys/i386/isa/sound/Readme.modules
@@ -1,87 +1,99 @@
- Linux sound-driver module
- (c) Peter Trattler
- License: GPL (Gnu Public License)
-
-
-Idea:
-
-I've modified the sources for the sound driver to allow simply insert and
-remove the sound driver from the kernel by calling (only available for Linux)
-
- insmod /usr/src/linux/modules/sound.o
-
-and
-
- rmmod sound
-
-This may be useful if you are doing one of the following things:
-
-1) Debugging the sound driver
-2) Creating a new device within the sound-driver
-3) You do not the sound driver all the time (as it wastes quite a lot of
-memory for its buffers)
-
-
-Compilation:
-
-Go to /usr/src/linux and make the following steps:
-
-a) configure the sound driver: To do that call "make config" and enable the
-sound-driver -- you will be asked different questions about your
-sound-hardware (remember not to use a too big DMA-Buffer size; you
-should use 16kB, if you have 16Bit devices, otherwise you can use 32kB)
-
-b) disable the sound driver in the kernel: call make config again but answer
-'N' to "Sound card support"
-
-c) run "make modules"; the sound-driver sound.o should end up in
-/usr/src/linux/modules
-
-
-If memory is tight:
-
-I've allocated at about 70kB for the sound-drivers internal tables. If this
-is too much, 'insmod sound.o' will generate the following warning
-...
-use 'insmod memsize=xxxx'
-...
-You can only use this command, if you have (I think) at least
-modules-1.1.87 or up. You can also switch debugging on by running the command
-
-insmod sound.o debugmem=1
-
-
-Files I changed:
-
-I've only changed the files soundcard.c(most changes) and some changes within
-the Makefile, sound_config.h and the Makefile in /usr/src/linux/drivers
-
-
-Bugs:
-
-a) As the kmalloc (..., GFP_DMA) caused some unexpected errors (I don't know if
-it is my fault), I created some code, which is (by default) enabled by
-
-#define KMALLOC_DMA_BROKEN 1 (within soundcard.c).
-
-It trys to allocate a large enough region, so that the complete dma-buffer
-can be occupied in this space. If it does not fit within this region it
-doubles the size of it. But this can cause problems, if the sound-buffer is
-too big (as kmalloc can only handle regions at up to circa 100kB).
-
-So take care to use for 8Bit devices a sound-DMA-buffer of 32kB (maximum)
-and for 16Bit devices a maximum of 16kB. Otherwise the allocation scheme
-might fail.
-
-b) Buffers allocated by the different sound devices via calls to kmalloc are
-not freed, if the sound driver is removed again (these buffers tend to be
-quite small -- so it does not harm a lot)
-
-c) If there is not enough (kernel-) memory available, the installation of
-the sound-driver fails. (This happens quite often, if you did not install the
-driver right after booting -- [PS: I've only got 5MB of Ram, so this might
-be the source for this problem])
-
-
-Author:
- Peter Trattler (peter@sbox.tu-graz.ac.at)
+Building a loadable sound driver
+================================
+
+Loadable module support in version 3.5 of VoxWare is mostly rewritten since
+the previous version (3.0.1). This means that some things have changed.
+
+To compile the sound driver as a loadable module you have to perform
+the following steps:
+
+1) Install modules-1.2.8.tar.gz package (or later if available).
+2a) Check that symbol remap_page_range is defined in linux/init/ksyms.c.
+Insert a line containing "X(remap_page_range)," if required. The driver will
+not load if this line is missing.
+2b) Recompile kernel with soundcard support disabled.
+3) Boot the new kernel.
+4) cd to the sound driver source directory (this directory). It's no
+longer required that the sound driver sources are installed in the
+kernel source tree (linux/drivers/sound). When installing a separately
+distributed sound driver you may install the sources for example to
+/usr/src/sound.
+5) Execute make in the sound driver source directory. Enter
+configuration parameters as described in Readme.cards. Then just wait until
+the driver is compiled OK.
+6) Copy sound.o to the directory where insmod expects to find it.
+("make install" copies it to /lib/modules/misc).
+7) Use command "insmod sound" to load the driver.
+
+8) The sound driver can be removed using command "rmmod sound".
+
+
+Parameters accepted by the loadable sound driver
+================================================
+
+Setting DMA buffer size
+-----------------------
+
+The driver allocates a DMA buffer (or two for full duplex devices)
+every time the audio device (/dev/dsp or /dev/audio) is opened
+and frees it when the device is closed. Size of this buffer is defined
+when the driver is configured (the last question). The buffer size
+can be redefined when loading the driver if required (note that this is
+an optional feature which is not normally required). The buffer size
+is redefined by adding dma_pagesize= parameter to the insmod command line.
+For example:
+
+ insmod sound dma_buffsize=32768
+
+Minimum buffer size is 4096 and the maximum depends on the DMA channe.
+For 8 bit channels (0 to 3) the limit is 64k and for 16 bit ones (5 to 7)
+it's 128k. Driver selects a suitable buffer size automaticly in case
+you try to spesify an invalid size.
+
+Q: What is the right DMA buffer size?
+
+A: It depends on the sampling rate, machine speed and the load of the system.
+Large buffers are required on slow machines, when recording/playing CD-quality
+audio or when there are other processes running on the same system. Also
+recording to hard disk is likely to require large buffers.
+
+Very small buffers are sufficient when you are just playing 8kHz audio files
+on an empty P133 system. Using a 128k byffer just wastes 120k (or 250k)
+of valuable physical RAM memory.
+
+The right buffer sice can be easily found by making some experiments
+with the dma_buffsize= parameter. I use usually 16k buffers on a DX4/100 system
+and 64k on an old 386 system.
+
+NOTE! DMA buffers are used only by /dev/audio# and /dev/dsp# devices.
+ Other device files don't use them but there are two exceptions:
+ GUS driver uses DMA buffers when loading samples to the card.
+ Ensoniq SoundScape driver uses them when doanloading the microcode
+ file (sndscape.co[012]) to the card. Using large buffers doesn't
+ increase performance in these cases.
+
+Configuring device parameters when loading the driver
+-----------------------------------------------------
+
+The loadable version of the sound driver accepts now the same
+sound= parameter that has been available in the LILO command line.
+In this way it's possible to change I/O port, IRQ and DMA addresses
+and to enable/disable various cards at load time. Normally
+the driver uses the configuration parameters entered when compiling
+and configuring the driver.
+Look at Readme.linux for more info.
+
+NOTE! This method is not normally required. You should use it only when
+ you have to use different configuration than normally. The sound=
+ command line parameter is error phrone and not recommended.
+
+Debugging and tracing
+---------------------
+
+Modularized sound driver doesn't display messages during initialization as
+the kernel compiled one does. This feature can be turned on by adding
+init_trace=1 to the insmod command line.
+
+For example:
+
+ insmod sound init_trace=1
diff --git a/sys/i386/isa/sound/Readme.v30 b/sys/i386/isa/sound/Readme.v30
index cade461d2a6d..826710ea09cf 100644
--- a/sys/i386/isa/sound/Readme.v30
+++ b/sys/i386/isa/sound/Readme.v30
@@ -1,38 +1,24 @@
VoxWare v3.0
------------
-This is a PROTOTYPE of the VoxWare v3.0 to be released late 94.
-
-All features of v2.5 should work as earlier. There could be some
+All features of v2.90-2 should work as earlier. There could be some
omissions but they are unintentional. I started this version thread
after v2.3 so all features implemented before it are there.
-Even this is a prototype, there should not be any fatal bugs. The
-prototype just means that I don't have implemented all features
-completely. Mainly in the /dev/sequencer2 driver.
-For example recording from /dev/sequencer2 won't work
-with other cards than a full features MPU-401 or clones. As well the
-way how the MIDI controllers are handled will change.
-
-IMPORTANT!!!!!!!!!!!!!!!!!
-
-Don't distribute any binaries compiled with the soundcard.h of this version.
-They will not work together with older drivers.
-
New features
============
There are now two new device interfaces. The /dev/midi## is a raw
tty like interface to MIDI ports. There is a device file for each MIDI
port on your system. They are named (/dev/midi00 to /dev/midiNN).
-The second addition is the /dev/sequencer2 which is higher level interface
+The second addition is the /dev/music which is higher level interface
than the old /dev/sequencer. It's intended for writing device independent
applications like sequencers.
/dev/midi##
-----------
-This interface should be useful for applications like MIDI sysex librarians.
+This interface should be usefull for applications like MIDI sysex librarians.
There are (currently) no timing features so making music could be impossible.
There are as many /dev/midi## devices as there are MIDI ports in the system.
@@ -67,7 +53,7 @@ It's not available for the so called MPU UART ports of some soundcards
If this ioctl is called with mode=1, the interface is put to the intelligent
(coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called.
It could have some strange effects if not called immediately after open. This
-call returns EINVAL if the midi port doesn't support the MPU-401 intelligent
+vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent
mode.
ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port
@@ -95,15 +81,15 @@ where:
data Buffer for the command arguments and returned
data.
-Be extremely careful with the nr_args and nr_returns fields. They
+Be extremely carefull with the nr_args and nr_returns fields. They
must match the command. An incorrect value will put the card and
the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further
-details.
+datails.
-/dev/sequencer2 (if you find a better name, please let me know).
----------------
+/dev/music (/dev/sequencer2)
+----------------------------
This device file works much like the /dev/sequencer which has been present
since the beginning. The main differences are the following:
@@ -113,7 +99,7 @@ the result is somewhere between the MIDI specification and the synth devices of
/dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE()
like macros. The voice number parameters of the API macros have been redefined
to denote MIDI channels. This means that the driver allocates voices for
-the channels automatically (this is a responsibility/right of an application
+the channels automaticly (this is a responsibility/right of an application
with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has
similar effects for a synth channel than on a MIDI port. This kind of
solution provides better device independence than the /dev/sequencer. The
@@ -130,12 +116,12 @@ return sum of internal synthesizers (GUS, OPL3) and MIDI ports in the systems.
- The new interface is used much like the ordinary /dev/sequencer. The
event format is new so you have to use the API macros defined in the
-sys/soundcard.h. The interface will probably change before the final 3.0
+sys/soundcard.h. The interface is will propably change before the final 3.0
release but using the API macros should ensure compatibility in source level.
The new event format is not recognized by version 2.X so don't try to
distribute binaries compiled with soundcard.h of v3.X.
-- The basic API usage is similar to the current one. There are some new
+- The basic API useage is similar to the current one. There are some new
macros but the older ones should work as earlier. The most important
incompatibility is that the /dev/sequencer2 driver allocates voices itself.
The other one is that the application must send SEQ_START_TIMER() as it's
diff --git a/sys/i386/isa/sound/ad1848.c b/sys/i386/isa/sound/ad1848.c
index b08f5f76cc68..05d77fa36172 100644
--- a/sys/i386/isa/sound/ad1848.c
+++ b/sys/i386/isa/sound/ad1848.c
@@ -1,14 +1,29 @@
/*
* sound/ad1848.c
+ *
+ * Modified by Luigi Rizzo (luigi@iet.unipi.it)
*
- * The low level driver for the AD1848/CS4248 codec chip which
- * is used for example in the MS Sound System.
- *
- * The CS4231 which is used in the GUS MAX and some other cards is
- * upwards compatible with AD1848 and this driver is able to drive it.
- *
- * Copyright by Hannu Savolainen 1994
+ * The low level driver for the AD1848/CS4248 codec chip which is used for
+ * example in the MS Sound System.
+ *
+ * The CS4231 which is used in the GUS MAX and some other cards is upwards
+ * compatible with AD1848 and this driver is able to drive it.
+ *
+ * CS4231A and AD1845 are upward compatible with CS4231. However the new
+ * features of these chips are different.
+ *
+ * CS4232 is a PnP audio chip which contains a CS4231A (and SB, MPU). CS4232A is
+ * an improved version of CS4232.
+ *
+ * CS4236 is also a PnP audio chip similar to the 4232
*
+ * OPTi931 is another high-end 1848-type chip. It differs in the use
+ * of the high 16 registers and configuration stuff. Luckily, being a
+ * PnP device, we can avoid black magic to identify the chip and be
+ * sure of its identity.
+ *
+ * Copyright by Hannu Savolainen 1994, 1995
+ *
* 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
@@ -16,7 +31,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
@@ -28,53 +43,88 @@
* 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: Riccardo Facchetti 24 Mar 1995 - Added the Audio Excel DSP 16
+ * initialization routine.
*/
#define DEB(x)
#define DEB1(x)
-#include "sound_config.h"
+#include <i386/isa/sound/sound_config.h>
+
+#if defined(CONFIG_AD1848)
+
+#include <i386/isa/sound/ad1848_mixer.h>
+#include <i386/isa/sound/iwdefs.h>
+
+extern struct isa_driver mssdriver;
+
+extern void IwaveStopDma(BYTE path);
+
+typedef struct {
+ int base;
+ int irq;
+ int dual_dma; /* 1, when two DMA channels allocated */
+ u_char MCE_bit;
+ u_char saved_regs[16];
+
+ int speed;
+ u_char speed_bits;
+ int channels;
+ int audio_format;
+ u_char format_bits;
+
+ u_long xfer_count;
+ int irq_mode;
+ int intr_active;
+ int opened;
+ char *chip_name;
+ int mode;
+#define MD_1848 1
+#define MD_4231 2
+#define MD_4231A 3
+#define MD_1845 4
+#define MD_MAXMODE 5
+
+ /* Mixer parameters */
+ int recmask;
+ int supported_devices;
+ int supported_rec_devices;
+ u_short levels[32];
+ int dev_no;
+ volatile u_long timer_ticks;
+ int timer_running;
+ int irq_ok;
+ sound_os_info *osp;
+} ad1848_info;
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)
+static int nr_ad1848_devs = 0;
+static volatile char irq2dev[17] =
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
-#define IMODE_NONE 0
-#define IMODE_OUTPUT 1
-#define IMODE_INPUT 2
-#define IMODE_INIT 3
-#define IMODE_MIDI 4
+static int timer_installed = -1;
+static int mute_flag = 0;
+static char mixer2codec[MAX_MIXER_DEV] = {0};
-typedef struct
+static int ad_format_mask[MD_MAXMODE /* devc->mode */ ] =
{
- int base;
- int irq;
- int dma_capture, dma_playback;
- unsigned char MCE_bit;
-
- int speed;
- unsigned char speed_bits;
- int channels;
- int audio_format;
- unsigned char format_bits;
+ /* 0 - none */ 0,
+ /* 1 - AD1848 */ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
- int xfer_count;
- int irq_mode;
- int intr_active;
- int opened;
- char *chip_name;
- int mode;
-}
+ /*
+ * AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE |
+ * AFMT_IMA_ADPCM,
+ */
-ad1848_info;
+ /* 2 - CS4231 */ AFMT_U8 | AFMT_S16_LE | AFMT_U16_LE,
-static int nr_ad1848_devs = 0;
-static char irq2dev[16] =
-{-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1};
+ /*
+ * AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE |
+ * AFMT_IMA_ADPCM,
+ */
-static int ad_format_mask[2 /*devc->mode*/ ] =
-{
- AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
- AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM
+ /* 3 - CS4231A */ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
+ /* 4 - AD1845 */ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW
};
static ad1848_info dev_info[MAX_AUDIO_DEV];
@@ -84,870 +134,1704 @@ static ad1848_info dev_info[MAX_AUDIO_DEV];
#define io_Status(d) ((d)->base+2)
#define io_Polled_IO(d) ((d)->base+3)
-static int ad1848_open (int dev, int mode);
-static void ad1848_close (int dev);
-static int ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
-static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
-static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
-static int ad1848_prepare_for_IO (int dev, int bsize, int bcount);
-static void ad1848_reset (int dev);
-static void ad1848_halt (int dev);
-void ad1848_interrupt (int dev);
+static int ad1848_open(int dev, int mode);
+static void ad1848_close(int dev);
+static int ad1848_ioctl(int dev, u_int cmd, ioctl_arg arg, int local);
+static void ad1848_output_block(int dev, u_long buf, int count, int intrflag, int dma_restart);
+static void ad1848_start_input(int dev, u_long buf, int count, int intrflag, int dma_restart);
+static int ad1848_prepare_for_IO(int dev, int bsize, int bcount);
+static void ad1848_reset(int dev);
+static void ad1848_halt(int dev);
+static void ad1848_halt_input(int dev);
+static void ad1848_halt_output(int dev);
+static void ad1848_trigger(int dev, int bits);
+static int ad1848_tmr_install(int dev);
+static void ad1848_tmr_reprogram(int dev);
+void adintr(int);
+
+/*
+ * AD_WAIT_INIT waits if we are initializing the board and we cannot modify
+ * its settings
+ */
+#define AD_WAIT_INIT(x) {int t=x; while(t>0 && inb(devc->base) == 0x80) t-- ; }
+
+short ipri_to_irq(u_short ipri);
+
+void
+adintr(unit)
+{
+ static short unit_to_irq[4] = {9, -1, -1, -1};
+ struct isa_device *dev;
+
+ if (unit_to_irq[unit] > 0)
+ ad1848_interrupt(unit_to_irq[unit]);
+ else {
+ dev = find_isadev(isa_devtab_null, &mssdriver, unit);
+ if (!dev)
+ printf("ad1848: Couldn't determine unit\n");
+ else {
+ unit_to_irq[unit] = ipri_to_irq(dev->id_irq);
+ ad1848_interrupt(unit_to_irq[unit]);
+ }
+ }
+}
static int
-ad_read (ad1848_info * devc, int reg)
+ad_read(ad1848_info * devc, int reg)
{
- unsigned long flags;
- int x;
+ u_long flags;
+ int x;
- DISABLE_INTR (flags);
- OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
- x = INB (io_Indexed_Data (devc));
- /* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
- RESTORE_INTR (flags);
+ AD_WAIT_INIT(900000);
+ flags = splhigh();
+ outb(io_Index_Addr(devc), (u_char) (reg & 0xff) | devc->MCE_bit);
+ x = inb(io_Indexed_Data(devc));
+ splx(flags);
- return x;
+ return x;
}
static void
-ad_write (ad1848_info * devc, int reg, int data)
+ad_write(ad1848_info * devc, int reg, u_char data)
{
- unsigned long flags;
+ u_long flags;
+
+ AD_WAIT_INIT(90000);
- DISABLE_INTR (flags);
- OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
- OUTB ((unsigned char) (data & 0xff), io_Indexed_Data (devc));
- /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
- RESTORE_INTR (flags);
+ flags = splhigh();
+ outb(io_Index_Addr(devc), (u_char) (reg & 0xff) | devc->MCE_bit);
+ outb(io_Indexed_Data(devc), (u_char) (data & 0xff));
+ splx(flags);
}
static void
-ad_set_MCE (ad1848_info * devc, int state)
+wait_for_calibration(ad1848_info * devc)
{
- unsigned long flags;
+ int timeout = 0;
- DISABLE_INTR (flags);
- if (state)
- devc->MCE_bit = 0x40;
- else
- devc->MCE_bit = 0x00;
- OUTB (devc->MCE_bit, io_Index_Addr (devc));
- RESTORE_INTR (flags);
+ /*
+ * Wait until the auto calibration process has finished.
+ *
+ * 1) Wait until the chip becomes ready (reads don't return 0x80).
+ * 2) Wait until the ACI bit of I11 gets on and then off.
+ */
+
+ AD_WAIT_INIT(100000);
+ if (inb(devc->base) & 0x80)
+ printf("ad1848: Auto calibration timed out(1).\n");
+
+ timeout = 100;
+ while (timeout > 0 && !(ad_read(devc, 11) & 0x20))
+ timeout--;
+ if (!(ad_read(devc, 11) & 0x20))
+ return;
+
+ timeout = 20000;
+ while (timeout > 0 && ad_read(devc, 11) & 0x20)
+ timeout--;
+ if (ad_read(devc, 11) & 0x20)
+ printf("ad1848: Auto calibration timed out(3).\n");
}
static void
-wait_for_calibration (ad1848_info * devc)
+ad_mute(ad1848_info * devc)
{
- int timeout = 0;
+ int i;
+ u_char prev;
- /*
- * Wait until the auto calibration process has finished.
- *
- * 1) Wait until the chip becomes ready (reads don't return 0x80).
- * 2) Wait until the ACI bit of I11 gets on and then off.
- */
+ mute_flag = 1;
- timeout = 100000;
- while (timeout > 0 && INB (devc->base) == 0x80)
- timeout--;
- if (INB (devc->base) == 0x80)
- printk ("ad1848: Auto calibration timed out(1).\n");
+ /*
+ * Save old register settings and mute output channels
+ */
+ for (i = 6; i < 8; i++) {
+ prev = devc->saved_regs[i] = ad_read(devc, i);
+ ad_write(devc, i, prev | 0x80);
+ }
+}
- timeout = 100000;
- while (timeout > 0 && !(ad_read (devc, 11) & 0x20))
- timeout--;
- if (!(ad_read (devc, 11) & 0x20))
- printk ("ad1848: Auto calibration timed out(2).\n");
+static void
+ad_unmute(ad1848_info * devc)
+{
+ int i;
+
+ mute_flag = 0;
+ /*
+ * Restore back old volume registers (unmute)
+ */
+ for (i = 6; i < 8; i++)
+ ad_write(devc, i, devc->saved_regs[i] & ~0x80);
+ }
- timeout = 100000;
- while (timeout > 0 && ad_read (devc, 11) & 0x20)
- timeout--;
- if (ad_read (devc, 11) & 0x20)
- printk ("ad1848: Auto calibration timed out(3).\n");
+static void
+ad_enter_MCE(ad1848_info * devc)
+{
+ u_long flags;
+
+ AD_WAIT_INIT(1000);
+ devc->MCE_bit = 0x40;
+ flags = splhigh();
+ if ( ( inb(io_Index_Addr(devc)) & 0x40) == 0 )
+ outb(io_Index_Addr(devc), devc->MCE_bit);
+ splx(flags);
}
-static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
+static void
+ad_leave_MCE(ad1848_info * devc)
{
- {
- "Generic AD1848 codec",
- DMA_AUTOMODE,
- AFMT_U8, /* Will be set later */
- NULL,
- ad1848_open,
- ad1848_close,
- ad1848_output_block,
- ad1848_start_input,
- ad1848_ioctl,
- ad1848_prepare_for_IO,
- ad1848_prepare_for_IO,
- ad1848_reset,
- ad1848_halt,
- NULL,
- NULL
- }};
+ u_long flags;
+ u_char prev;
+
+ AD_WAIT_INIT(1000);
+
+ flags = splhigh();
+
+ devc->MCE_bit = 0x00;
+ prev = inb(io_Index_Addr(devc));
+ /* XXX the next call is redundant ? */
+ outb(io_Index_Addr(devc), 0x00); /* Clear the MCE bit */
+
+ if ((prev & 0x40) == 0) { /* Not in MCE mode */
+ splx(flags);
+ return;
+ }
+ outb(io_Index_Addr(devc), 0x00); /* Clear the MCE bit */
+ wait_for_calibration(devc);
+ splx(flags);
+}
+
static int
-ad1848_open (int dev, int mode)
+ad1848_set_recmask(ad1848_info * devc, int mask)
{
- int err;
- ad1848_info *devc = NULL;
- unsigned long flags;
-
- DEB (printk ("ad1848_open(int mode = %X)\n", mode));
+ u_char recdev;
+ int i, n;
- if (dev < 0 || dev >= num_audiodevs)
- return RET_ERROR (ENXIO);
+ mask &= devc->supported_rec_devices;
- devc = (ad1848_info *) audio_devs[dev]->devc;
+ n = 0;
+ for (i = 0; i < 32; i++)/* Count selected device bits */
+ if (mask & (1 << i))
+ n++;
- DISABLE_INTR (flags);
- if (devc->opened)
- {
- RESTORE_INTR (flags);
- printk ("ad1848: Already opened\n");
- return RET_ERROR (EBUSY);
- }
+ if (n == 0)
+ mask = SOUND_MASK_MIC;
+ else if (n != 1) { /* Too many devices selected */
+ mask &= ~devc->recmask; /* Filter out active settings */
- if (devc->irq) /* Not managed by another driver */
- if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt)) < 0)
- {
- printk ("ad1848: IRQ in use\n");
- RESTORE_INTR (flags);
- return err;
- }
+ n = 0;
+ for (i = 0; i < 32; i++) /* Count selected device bits */
+ if (mask & (1 << i))
+ n++;
- if (DMAbuf_open_dma (dev) < 0)
- {
- RESTORE_INTR (flags);
- printk ("ad1848: DMA in use\n");
- return RET_ERROR (EBUSY);
+ if (n != 1)
+ mask = SOUND_MASK_MIC;
+ }
+ switch (mask) {
+ case SOUND_MASK_MIC:
+ recdev = 2;
+ break;
+
+ case SOUND_MASK_LINE:
+ case SOUND_MASK_LINE3:
+ recdev = 0;
+ break;
+
+ case SOUND_MASK_CD:
+ case SOUND_MASK_LINE1:
+ recdev = 1;
+ break;
+
+ case SOUND_MASK_IMIX:
+ recdev = 3;
+ break;
+
+ default:
+ mask = SOUND_MASK_MIC;
+ recdev = 2;
}
- devc->intr_active = 0;
- devc->opened = 1;
- RESTORE_INTR (flags);
+ recdev <<= 6;
+ ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev);
+ ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev);
- return 0;
+ devc->recmask = mask;
+ return mask;
}
static void
-ad1848_close (int dev)
+change_bits(u_char *regval, int dev, int chn, int newval)
{
- unsigned long flags;
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_char mask;
+ int shift;
+
+ if (mix_devices[dev][chn].polarity == 1) /* Reverse */
+ newval = 100 - newval;
- DEB (printk ("ad1848_close(void)\n"));
+ mask = (1 << mix_devices[dev][chn].nbits) - 1;
+ shift = mix_devices[dev][chn].bitpos;
+ newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
- DISABLE_INTR (flags);
+ *regval &= ~(mask << shift); /* Clear bits */
+ *regval |= (newval & mask) << shift; /* Set new value */
+}
- devc->intr_active = 0;
- if (devc->irq) /* Not managed by another driver */
- snd_release_irq (devc->irq);
- ad1848_reset (dev);
- DMAbuf_close_dma (dev);
- devc->opened = 0;
+static int
+ad1848_mixer_get(ad1848_info * devc, int dev)
+{
+ if (!((1 << dev) & devc->supported_devices))
+ return -(EINVAL);
- RESTORE_INTR (flags);
+ return devc->levels[dev];
}
+#define CLMICI 0x00781601
+#define CRMICI 0x00791701
+
static int
-set_speed (ad1848_info * devc, int arg)
+ad1848_mixer_set(ad1848_info * devc, int dev, int value)
{
- /*
- * The sampling speed is encoded in the least significant nible of I8. The
- * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
- * three bits select the divisor (indirectly):
- *
- * The available speeds are in the following table. Keep the speeds in
- * the increasing order.
- */
- typedef struct
- {
- int speed;
- unsigned char bits;
- }
- speed_struct;
-
- static speed_struct speed_table[] =
- {
- {5510, (0 << 1) | 1},
- {5510, (0 << 1) | 1},
- {6620, (7 << 1) | 1},
- {8000, (0 << 1) | 0},
- {9600, (7 << 1) | 0},
- {11025, (1 << 1) | 1},
- {16000, (1 << 1) | 0},
- {18900, (2 << 1) | 1},
- {22050, (3 << 1) | 1},
- {27420, (2 << 1) | 0},
- {32000, (3 << 1) | 0},
- {33075, (6 << 1) | 1},
- {37800, (4 << 1) | 1},
- {44100, (5 << 1) | 1},
- {48000, (6 << 1) | 0}
- };
-
- int i, n, selected = -1;
-
- n = sizeof (speed_table) / sizeof (speed_struct);
-
- if (arg < speed_table[0].speed)
- selected = 0;
- if (arg > speed_table[n - 1].speed)
- selected = n - 1;
-
- for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
- if (speed_table[i].speed == arg)
- selected = i;
- else if (speed_table[i].speed > arg)
- {
- int diff1, diff2;
-
- diff1 = arg - speed_table[i - 1].speed;
- diff2 = speed_table[i].speed - arg;
-
- if (diff1 < diff2)
- selected = i - 1;
- else
- selected = i;
- }
+ int left = value & 0x000000ff;
+ int right = (value & 0x0000ff00) >> 8;
+ int retvol;
- if (selected == -1)
- {
- printk ("ad1848: Can't find speed???\n");
- selected = 3;
- }
+ int regoffs;
+ u_char val;
+ /* u_char clci, crmici, clmici, clici, crici; */
+
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+
+ if (mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */
+ right = left;
+
+ retvol = left | (right << 8);
+
+ /* Scale volumes */
+ left = mix_cvt[left];
+ right = mix_cvt[right];
+
+ /* Scale it again */
+ left = mix_cvt[left];
+ right = mix_cvt[right];
- devc->speed = speed_table[selected].speed;
- devc->speed_bits = speed_table[selected].bits;
- return devc->speed;
+ if (dev > 31)
+ return -(EINVAL);
+
+ if (!(devc->supported_devices & (1 << dev)))
+ return -(EINVAL);
+
+ if (mix_devices[dev][LEFT_CHN].nbits == 0)
+ return -(EINVAL);
+
+ devc->levels[dev] = retvol;
+
+ /*
+ * Set the left channel
+ */
+ /* IwaveCodecMode(CODEC_MODE3); Default codec mode */
+
+ regoffs = mix_devices[dev][LEFT_CHN].regno;
+ val = ad_read(devc, regoffs);
+
+ change_bits(&val, dev, LEFT_CHN, left);
+ ad_write(devc, regoffs, val);
+ devc->saved_regs[regoffs] = val;
+
+ /*
+ * Set the right channel
+ */
+
+ if (mix_devices[dev][RIGHT_CHN].nbits == 0)
+ return retvol; /* Was just a mono channel */
+
+ regoffs = mix_devices[dev][RIGHT_CHN].regno;
+ val = ad_read(devc, regoffs);
+ change_bits(&val, dev, RIGHT_CHN, right);
+ ad_write(devc, regoffs, val);
+ devc->saved_regs[regoffs] = val;
+
+ return retvol;
}
-static int
-set_channels (ad1848_info * devc, int arg)
+static void
+ad1848_mixer_reset(ad1848_info * devc)
{
- if (arg != 1 && arg != 2)
- return devc->channels;
+ int i;
+
+ devc->recmask = 0;
+ if (devc->mode != MD_1848)
+ devc->supported_devices = MODE2_MIXER_DEVICES;
+ else
+ devc->supported_devices = MODE1_MIXER_DEVICES;
+
+ devc->supported_rec_devices = MODE1_REC_DEVICES;
- devc->channels = arg;
- return arg;
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if (devc->supported_devices & (1 << i))
+ ad1848_mixer_set(devc, i, default_mixer_levels[i]);
+ ad1848_set_recmask(devc, SOUND_MASK_MIC);
}
static int
-set_format (ad1848_info * devc, int arg)
+ad1848_mixer_ioctl(int dev, u_int cmd, ioctl_arg arg)
{
+ ad1848_info *devc;
+ int codec_dev = mixer2codec[dev];
- static struct format_tbl
- {
- int format;
- unsigned char bits;
- }
- format2bits [] =
- {
- {
- 0, 0
- }
- ,
- {
- AFMT_MU_LAW, 1
- }
- ,
- {
- AFMT_A_LAW, 3
- }
- ,
- {
- AFMT_IMA_ADPCM, 5
- }
- ,
- {
- AFMT_U8, 0
- }
- ,
+ if (!codec_dev)
+ return -(ENXIO);
+
+ codec_dev--;
+
+ devc = (ad1848_info *) audio_devs[codec_dev]->devc;
+
+ if (((cmd >> 8) & 0xff) == 'M') {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ return *(int *) arg = ad1848_set_recmask(devc, (*(int *) arg));
+ break;
+
+ default:
+ return *(int *) arg = ad1848_mixer_set(devc, cmd & 0xff, (*(int *) arg));
+ }
+ else
+ switch (cmd & 0xff) { /* Return parameters */
+
+ case SOUND_MIXER_RECSRC:
+ return *(int *) arg = devc->recmask;
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return *(int *) arg = devc->supported_devices;
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return *(int *) arg = devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return *(int *) arg = devc->supported_rec_devices;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return *(int *) arg = SOUND_CAP_EXCL_INPUT;
+ break;
+
+ default:
+ return *(int *) arg = ad1848_mixer_get(devc, cmd & 0xff);
+ }
+ } else
+ return -(EINVAL);
+}
+
+static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
+{
{
- AFMT_S16_LE, 2
+ "Generic AD1848 codec",
+ /* DMA_AUTOMODE | DMA_DUPLEX, */
+ DMA_AUTOMODE,
+ AFMT_U8, /* Will be set later */
+ NULL,
+ ad1848_open,
+ ad1848_close,
+ ad1848_output_block,
+ ad1848_start_input,
+ ad1848_ioctl,
+ ad1848_prepare_for_IO,
+ ad1848_prepare_for_IO,
+ ad1848_reset,
+ ad1848_halt,
+ NULL,
+ NULL,
+ ad1848_halt_input,
+ ad1848_halt_output,
+ ad1848_trigger
}
- ,
- {
- AFMT_S16_BE, 6
+};
+
+static struct mixer_operations ad1848_mixer_operations =
+{
+ "AD1848/CS4248/CS4231",
+ ad1848_mixer_ioctl
+};
+
+static int
+ad1848_open(int dev, int mode)
+{
+ ad1848_info *devc = NULL;
+ u_long flags;
+ int otherside = audio_devs[dev]->otherside;
+
+ if (dev < 0 || dev >= num_audiodevs)
+ return -(ENXIO);
+
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return -(EBUSY);
}
- ,
- {
- AFMT_S8, 0
+ if (audio_devs[dev]->busy)
+ return -(EBUSY);
+
+ devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ flags = splhigh();
+ if (audio_devs[dev]->busy) {
+ splx(flags);
+ return -(EBUSY);
}
- ,
- {
- AFMT_U16_LE, 0
+ devc->dual_dma = 0;
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX) {
+ devc->dual_dma = 1;
}
- ,
- {
- AFMT_U16_BE, 0
+ devc->intr_active = 0;
+ audio_devs[dev]->busy = 1;
+ devc->irq_mode = 0;
+ ad1848_trigger(dev, 0);
+ splx(flags);
+ /*
+ * Mute output until the playback really starts. This decreases
+ * clicking.
+ */
+ ad_mute(devc);
+
+ return 0;
+}
+
+static void
+ad1848_close(int dev)
+{
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ int otherside = audio_devs[dev]->otherside;
+
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return;
}
- };
- int i, n = sizeof (format2bits) / sizeof (struct format_tbl);
+ DEB(printf("ad1848_close(void)\n"));
- if (!(arg & ad_format_mask[devc->mode]))
- arg = AFMT_U8;
+ flags = splhigh();
- devc->audio_format = arg;
+ ad_mute(devc);
- for (i = 0; i < n; i++)
- if (format2bits[i].format == arg)
- {
- if ((devc->format_bits = format2bits[i].bits) == 0)
- return devc->audio_format = AFMT_U8; /* Was not supported */
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x1);
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+ /*
+ * ad_write (devc, 15,0); ad_write (devc, 14,0);
+ */
+ devc->irq_mode &= ~PCM_ENABLE_OUTPUT;
- return arg;
- }
+ devc->intr_active = 0;
+ ad1848_reset(dev);
- /* Still hanging here. Something must be terribly wrong */
- devc->format_bits = 0;
- return devc->audio_format = AFMT_U8;
+ devc->opened = 0;
+ devc->irq_mode = 0;
+ audio_devs[dev]->busy = 0;
+ ad_unmute(devc);
+ splx(flags);
}
static int
-ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+set_speed(ad1848_info * devc, int arg)
{
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ /*
+ * The sampling speed is encoded in the least significant nible of
+ * I8. The LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz)
+ * and other three bits select the divisor (indirectly):
+ *
+ * The available speeds are in the following table. Keep the speeds in
+ * the increasing order.
+ */
+ typedef struct {
+ int speed;
+ u_char bits;
+ } speed_struct;
+
+ static speed_struct speed_table[] = {
+ {5510, (0 << 1) | 1},
+ {5510, (0 << 1) | 1},
+ {6620, (7 << 1) | 1},
+ {8000, (0 << 1) | 0},
+ {9600, (7 << 1) | 0},
+ {11025, (1 << 1) | 1},
+ {16000, (1 << 1) | 0},
+ {18900, (2 << 1) | 1},
+ {22050, (3 << 1) | 1},
+ {27420, (2 << 1) | 0},
+ {32000, (3 << 1) | 0},
+ {33075, (6 << 1) | 1},
+ {37800, (4 << 1) | 1},
+ {44100, (5 << 1) | 1},
+ {48000, (6 << 1) | 0}
+ };
+
+ int i, n, selected = -1;
+
+ n = sizeof(speed_table) / sizeof(speed_struct);
+
+ if (devc->mode == MD_1845) { /* AD1845 has different timer than others */
+ RANGE (arg, 4000, 50000) ;
+
+ devc->speed = arg;
+ devc->speed_bits = speed_table[selected].bits;
+ return devc->speed;
+ }
+ if (arg < speed_table[0].speed)
+ selected = 0;
+ if (arg > speed_table[n - 1].speed)
+ selected = n - 1;
+
+ for (i = 1 /* really */ ; selected == -1 && i < n; i++)
+ if (speed_table[i].speed == arg)
+ selected = i;
+ else if (speed_table[i].speed > arg) {
+ int diff1, diff2;
+
+ diff1 = arg - speed_table[i - 1].speed;
+ diff2 = speed_table[i].speed - arg;
+
+ if (diff1 < diff2)
+ selected = i - 1;
+ else
+ selected = i;
+ }
+ if (selected == -1) {
+ printf("ad1848: Can't find speed???\n");
+ selected = 3;
+ }
+ devc->speed = speed_table[selected].speed;
+ devc->speed_bits = speed_table[selected].bits;
+ return devc->speed;
+}
- switch (cmd)
- {
+static int
+set_channels(ad1848_info * devc, int arg)
+{
+ if (arg != 1 && arg != 2)
+ return devc->channels;
+
+ devc->channels = arg;
+ return arg;
+}
+
+static int
+set_format(ad1848_info * devc, int arg)
+{
+ static struct format_tbl {
+ int format;
+ u_char bits;
+ } format2bits[] = {
+ { 0, 0 } ,
+ { AFMT_MU_LAW, 1 } ,
+ { AFMT_A_LAW, 3 } ,
+ { AFMT_IMA_ADPCM, 5 } ,
+ { AFMT_U8, 0 } ,
+ { AFMT_S16_LE, 2 } ,
+ { AFMT_S16_BE, 6 } ,
+ { AFMT_S8, 0 } ,
+ { AFMT_U16_LE, 0 } ,
+ { AFMT_U16_BE, 0 }
+ };
+ int i, n = sizeof(format2bits) / sizeof(struct format_tbl);
+
+
+ if (!(arg & ad_format_mask[devc->mode]))
+ arg = AFMT_U8;
+
+ devc->audio_format = arg;
+
+ for (i = 0; i < n; i++)
+ if (format2bits[i].format == arg) {
+ if ((devc->format_bits = format2bits[i].bits) == 0)
+ return devc->audio_format = AFMT_U8; /* Was not supported */
+ return arg;
+ }
+ /* Still hanging here. Something must be terribly wrong */
+ devc->format_bits = 0;
+ return devc->audio_format = AFMT_U8;
+}
+
+/* XXX check what is arg, (int) or *(int *) lr970705 */
+static int
+ad1848_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
+{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ switch (cmd) {
case SOUND_PCM_WRITE_RATE:
- if (local)
- return set_speed (devc, arg);
- return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg)));
+ if (local)
+ return set_speed(devc, (int) arg);
+ return *(int *) arg = set_speed(devc, (*(int *) arg));
case SOUND_PCM_READ_RATE:
- if (local)
- return devc->speed;
- return IOCTL_OUT (arg, devc->speed);
+ if (local)
+ return devc->speed;
+ return *(int *) arg = devc->speed;
case SNDCTL_DSP_STEREO:
- if (local)
- return set_channels (devc, arg + 1) - 1;
- return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1);
+ if (local)
+ return set_channels(devc, (int) arg + 1) - 1;
+ return *(int *) arg = set_channels(devc, (*(int *) arg) + 1) - 1;
case SOUND_PCM_WRITE_CHANNELS:
- if (local)
- return set_channels (devc, arg);
- return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg)));
+ if (local)
+ return set_channels(devc, (int) arg);
+ return *(int *) arg = set_channels(devc, (*(int *) arg));
case SOUND_PCM_READ_CHANNELS:
- if (local)
- return devc->channels;
- return IOCTL_OUT (arg, devc->channels);
+ if (local)
+ return devc->channels;
+ return *(int *) arg = devc->channels;
case SNDCTL_DSP_SAMPLESIZE:
- if (local)
- return set_format (devc, arg);
- return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg)));
+ if (local)
+ return set_format(devc, (int) arg);
+ return *(int *) arg = set_format(devc, (*(int *) arg));
case SOUND_PCM_READ_BITS:
- if (local)
- return devc->audio_format;
- return IOCTL_OUT (arg, devc->audio_format);
+ if (local)
+ return devc->audio_format;
+ return *(int *) arg = devc->audio_format;
+
+
+ case FIOASYNC:
+ if (local)
+ return 1;
+ return *(int *) arg = 1;
+
+ case FIONBIO:
+ if (local)
+ return 1;
+ return *(int *) arg = 1;
+
default:;
}
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static void
-ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+ad1848_output_block(int dev, u_long buf, int count, int intrflag, int dma_restart)
{
- unsigned long flags, cnt;
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags, cnt;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ cnt = count;
+ if (devc->audio_format == AFMT_IMA_ADPCM) {
+ cnt /= 4;
+ } else {
+ if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
+ cnt >>= 1;
+ }
+ if (devc->channels > 1)
+ cnt >>= 1;
+ cnt--;
+ if (mute_flag)
+ ad_unmute(devc);
- cnt = count;
+ if ( devc->irq_mode & PCM_ENABLE_OUTPUT &&
+ audio_devs[dev]->flags & DMA_AUTOMODE && intrflag &&
+ cnt == devc->xfer_count) {
+ devc->irq_mode |= PCM_ENABLE_OUTPUT;
+ devc->intr_active = 1;
- if (devc->audio_format == AFMT_IMA_ADPCM)
- {
- cnt /= 4;
}
- else
- {
- if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
+ flags = splhigh();
+
+ if (dma_restart) {
+
+ DMAbuf_start_dma(dev, buf, count, 1);
+ }
+ ad_write(devc, 15, (u_char) (cnt & 0xff));
+ ad_write(devc, 14, (u_char) ((cnt >> 8) & 0xff));
+
+ devc->xfer_count = cnt;
+ devc->irq_mode |= PCM_ENABLE_OUTPUT;
+ devc->intr_active = 1;
+ splx(flags);
+}
+
+static void
+ad1848_start_input(int dev, u_long buf, int count,
+ int intrflag, int dma_restart)
+{
+ u_long flags, cnt;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ cnt = count;
+ if (devc->audio_format == AFMT_IMA_ADPCM)
+ cnt /= 4;
+ else if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
cnt >>= 1;
+ if (devc->channels > 1)
+ cnt >>= 1;
+ cnt--;
+
+ if ( devc->irq_mode & PCM_ENABLE_INPUT &&
+ audio_devs[dev]->flags & DMA_AUTOMODE && intrflag &&
+ cnt == devc->xfer_count) {
+ devc->irq_mode |= PCM_ENABLE_INPUT;
+ devc->intr_active = 1;
+ return; /* Auto DMA mode on. No need to react */
}
- if (devc->channels > 1)
- cnt >>= 1;
- cnt--;
+ flags = splhigh();
- if (audio_devs[dev]->flags & DMA_AUTOMODE &&
- intrflag &&
- cnt == devc->xfer_count)
- {
- devc->irq_mode = IMODE_OUTPUT;
- devc->intr_active = 1;
- return; /*
- * Auto DMA mode on. No need to react
- */
+ if (dma_restart) {
+ /* ad1848_halt (dev); */
+ DMAbuf_start_dma(dev, buf, count, 0);
+ }
+ if (devc->mode == MD_1848 || !devc->dual_dma) {/* Single DMA chan. mode */
+ ad_write(devc, 15, (u_char) (cnt & 0xff));
+ ad_write(devc, 14, (u_char) ((cnt >> 8) & 0xff));
+ } else { /* Dual DMA channel mode */
+ ad_write(devc, 31, (u_char) (cnt & 0xff));
+ ad_write(devc, 30, (u_char) ((cnt >> 8) & 0xff));
}
- DISABLE_INTR (flags);
- if (dma_restart)
- {
- ad1848_halt (dev);
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+ /* ad_write (devc, 9, ad_read (devc, 9) | 0x02); *//* Capture enable */
+ ad_unmute(devc);
+
+ devc->xfer_count = cnt;
+ devc->irq_mode |= PCM_ENABLE_INPUT;
+ devc->intr_active = 1;
+ splx(flags);
+}
+
+static int
+ad1848_prepare_for_IO(int dev, int bsize, int bcount)
+{
+ int timeout;
+ u_char fs, old_fs;
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ if (devc->irq_mode)
+ return 0;
+
+ fs = devc->speed_bits | (devc->format_bits << 5);
+
+ if (devc->channels > 1)
+ fs |= 0x10;
+ old_fs = fs;
+
+ flags = splhigh();
+
+ if (devc->mode == MD_1845) { /* Use alternate speed select regs */
+ fs &= 0xf0; /* Mask off the rate select bits */
+
+ ad_write(devc, 22, (devc->speed >> 8) & 0xff); /* Speed MSB */
+ ad_write(devc, 23, devc->speed & 0xff); /* Speed LSB */
}
- ad_set_MCE (devc, 1);
+ ad_enter_MCE(devc); /* Enables changes to the format select reg */
+
+ ad_write(devc, 8, fs);
- ad_write (devc, 15, (unsigned char) (cnt & 0xff));
- ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
+ /*
+ * Write to I8 starts resyncronization. Wait until it completes.
+ */
+ AD_WAIT_INIT(10000);
+ /*
+ * If mode == 2 (CS4231), set I28 also. It's the capture format
+ * register.
+ */
+ if (devc->mode != MD_1848) {
+ ad_write(devc, 28, fs);
+
+ /*
+ * Write to I28 starts resyncronization. Wait until it completes.
+ */
+ AD_WAIT_INIT(10000);
+ }
- ad_write (devc, 9, 0x0d); /*
- * Playback enable, single DMA channel mode,
- * auto calibration on.
- */
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x08);
- ad_set_MCE (devc, 0); /*
- * Starts the calibration process and
- * enters playback mode after it.
- */
- wait_for_calibration (devc);
+ ad_leave_MCE(devc);
- devc->xfer_count = cnt;
- devc->irq_mode = IMODE_OUTPUT;
- devc->intr_active = 1;
- RESTORE_INTR (flags);
+ splx(flags);
+
+ devc->xfer_count = 0;
+#ifdef CONFIG_SEQUENCER
+ if (dev == timer_installed && devc->timer_running)
+ if ((fs & 0x01) != (old_fs & 0x01)) {
+ ad1848_tmr_reprogram(dev);
+ }
+#endif
+ return 0;
}
static void
-ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+ad1848_reset(int dev)
{
- unsigned long flags, cnt;
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ ad1848_halt(dev);
+}
- /* int count_reg = (devc->mode == 1) ? 14 : 30; */
+static void
+ad1848_halt(int dev)
+{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ int timeout;
- cnt = count;
- if (devc->audio_format == AFMT_IMA_ADPCM)
- {
- cnt /= 4;
- }
- else
- {
- if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
- cnt >>= 1;
- }
- if (devc->channels > 1)
- cnt >>= 1;
- cnt--;
+ flags = splhigh();
- if (audio_devs[dev]->flags & DMA_AUTOMODE &&
- intrflag &&
- cnt == devc->xfer_count)
- {
- devc->irq_mode = IMODE_INPUT;
- devc->intr_active = 1;
- return; /*
- * Auto DMA mode on. No need to react
- */
- }
- DISABLE_INTR (flags);
+ ad_mute(devc);
- if (dma_restart)
- {
- ad1848_halt (dev);
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
- }
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x03); /* Stop DMA */
- ad_set_MCE (devc, 1);
-#if 0
- ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff));
- ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff));
-#else
- ad_write (devc, 15, (unsigned char) (cnt & 0xff));
- ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
- if (devc->mode == 2)
- {
- ad_write (devc, 31, (unsigned char) (cnt & 0xff));
- ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff));
+ ad_write(devc, 14, 0); /* Clear DMA counter */
+ ad_write(devc, 15, 0); /* Clear DMA counter */
+
+ if (devc->mode != MD_1848) {
+ ad_write(devc, 30, 0); /* Clear DMA counter */
+ ad_write(devc, 31, 0); /* Clear DMA counter */
}
-#endif
- ad_write (devc, 9, 0x0e); /*
- * Capture enable, single DMA channel mode,
- * auto calibration on.
- */
+ for (timeout = 0; timeout < 1000 && !(inb(io_Status(devc)) & 0x01);
+ timeout++); /* Wait for interrupt */
- ad_set_MCE (devc, 0); /*
- * Starts the calibration process and
- * enters playback mode after it.
- */
- wait_for_calibration (devc);
+ outb(io_Status(devc), 0); /* Clear interrupt status */
- devc->xfer_count = cnt;
- devc->irq_mode = IMODE_INPUT;
- devc->intr_active = 1;
- RESTORE_INTR (flags);
-}
+ devc->irq_mode = 0;
-static int
-ad1848_prepare_for_IO (int dev, int bsize, int bcount)
-{
- int timeout;
- unsigned char fs;
- unsigned long flags;
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
-
- DISABLE_INTR (flags);
- ad_set_MCE (devc, 1); /* Enables changes to the format select reg */
- fs = devc->speed_bits | (devc->format_bits << 5);
-
- if (devc->channels > 1)
- fs |= 0x10;
-
- ad_write (devc, 8, fs);
- /*
- * Write to I8 starts resyncronization. Wait until it completes.
- */
- timeout = 10000;
- while (timeout > 0 && INB (devc->base) == 0x80)
- timeout--;
-
- ad_set_MCE (devc, 0); /*
- * Starts the calibration process and
- * enters playback mode after it.
- */
- wait_for_calibration (devc);
- RESTORE_INTR (flags);
-
- /*
- * If mode == 2 (CS4231), set I28 also. It's the capture format register.
- */
- if (devc->mode == 2)
- {
- ad_set_MCE (devc, 1);
- ad_write (devc, 28, fs);
-
- /*
- * Write to I28 starts resyncronization. Wait until it completes.
- */
- timeout = 10000;
- while (timeout > 0 && INB (devc->base) == 0x80)
- timeout--;
+ /* DMAbuf_reset_dma (dev); */
+ splx(flags);
+}
- ad_set_MCE (devc, 0); /*
- * Starts the calibration process and
- * enters playback mode after it.
- */
- wait_for_calibration (devc);
- RESTORE_INTR (flags);
+static void
+ad1848_halt_input(int dev)
+{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ u_char playing;
+ if (devc->mode == MD_1848) {
+ ad1848_halt(dev);
+ return;
}
- devc->xfer_count = 0;
- return 0;
+ playing = ad_read(devc, 9);
+ if (!(playing & 0x2))
+ return;
+
+ flags = splhigh();
+
+ ad_mute(devc);
+ ad_write(devc, 9, playing & ~0x02); /* Stop capture */
+
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+
+ devc->irq_mode &= ~PCM_ENABLE_INPUT;
+
+ splx(flags);
}
static void
-ad1848_reset (int dev)
+ad1848_halt_output(int dev)
{
- ad1848_halt (dev);
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ u_char playing;
+
+ playing = ad_read(devc, 9);
+ if (!(playing & 0x1)) {
+ devc->irq_mode &= ~PCM_ENABLE_OUTPUT;
+ return;
+ }
+ /* IwaveStopDma(PLAYBACK); */
+ if (devc->mode == MD_1848) {
+ ad1848_halt(dev);
+ return;
+ }
+ flags = splhigh();
+ /* ad_mute (devc); */
+
+ ad_write(devc, 9, playing & ~0x1);
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+ /*
+ * ad_write (devc, 15,0); ad_write (devc, 14,0);
+ */
+ devc->irq_mode &= ~PCM_ENABLE_OUTPUT;
+
+ splx(flags);
}
static void
-ad1848_halt (int dev)
+ad1848_trigger(int dev, int state)
{
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ u_char tmp;
+
+ flags = splhigh();
+ state &= devc->irq_mode;
+
+ tmp = ad_read(devc, 9) & ~0x03;
+ if (state & PCM_ENABLE_INPUT)
+ tmp |= 0x02;
+ if (state & PCM_ENABLE_OUTPUT) {
+ tmp |= 0x01;
+ }
+ ad_write(devc, 9, tmp);
- ad_write (devc, 9, 0); /* Clear the PEN and CEN bits (among others) */
- OUTB (0, io_Status (devc)); /* Clear interrupt status */
+ splx(flags);
}
+
int
-ad1848_detect (int io_base)
+ad1848_detect(int io_base, int *ad_flags, sound_os_info * osp)
{
+ static int last_probe_addr=0, last_result=0; /* to avoid multiple probes*/
+ int i;
+ ad1848_info *devc = &dev_info[nr_ad1848_devs];
+ u_char tmp, tmp1, tmp2 ;
+
+ DDB(printf("ad1848_detect(%x)\n", io_base));
+ if (io_base == last_probe_addr)
+ return last_result;
+ else {
+ last_result = 0; /* default value for detect */
+ last_probe_addr = io_base ;
+ }
-#define DDB(x) x
+ if (ad_flags)
+ *ad_flags = 0;
- unsigned char tmp;
- int i;
- ad1848_info *devc = &dev_info[nr_ad1848_devs];
- unsigned char tmp1 = 0xff, tmp2 = 0xff;
+ if (nr_ad1848_devs >= MAX_AUDIO_DEV) {
+ DDB(printf("ad1848 detect error - step 0\n"));
+ return 0 ;
+ }
+ devc->base = io_base;
+ devc->irq_ok = 0;
+ devc->timer_running = 0;
+ devc->MCE_bit = 0x40;
+ devc->irq = 0;
+ devc->opened = 0;
+ devc->chip_name = "AD1848";
+ devc->mode = MD_1848; /* AD1848 or CS4248 */
+ devc->osp = osp;
+
+ /*
+ * Check that the I/O address is in use.
+ *
+ * The bit 0x80 of the base I/O port is known to be 0 after the chip has
+ * performed it's power on initialization. Just assume this has
+ * happened before the OS is starting.
+ *
+ * If the I/O address is unused, it typically returns 0xff.
+ */
+
+ DDB(printf("ad1848_detect() - step A\n"));
+
+ if ((inb(devc->base) & 0x80) != 0x00) { /* Not a AD1848 */
+ DDB(printf("ad1848 detect error - step A,"
+ " inb(base) = 0x%02x, want 0XXX.XXXX\n",
+ inb(devc->base)));
+ return 0;
+ }
+ /*
+ * Test if it's possible to change contents of the indirect
+ * registers. Registers 0 and 1 are ADC volume registers. The bit
+ * 0x10 is read only so try to avoid using it.
+ */
+
+ DDB(printf("ad1848_detect() - step B, test indirect register\n"));
+
+ ad_write(devc, 0, 0xaa);
+ ad_write(devc, 1, 0x45);/* 0x55 with bit 0x10 clear */
+ tmp1 = ad_read(devc, 0) ;
+ tmp2 = ad_read(devc, 1) ;
+ if ( tmp1 != 0xaa || tmp2 != 0x45) {
+ DDB(printf("ad1848 detect error - step B (0x%02x/0x%02x) want 0xaa/0x45\n", tmp1, tmp2));
+ return 0;
+ }
+ DDB(printf("ad1848_detect() - step C\n"));
+ ad_write(devc, 0, 0x45);
+ ad_write(devc, 1, 0xaa);
+ tmp1 = ad_read(devc, 0) ;
+ tmp2 = ad_read(devc, 1) ;
- if (nr_ad1848_devs >= MAX_AUDIO_DEV)
- return 0;
+ if (tmp1 != 0x45 || tmp2 != 0xaa) {
+ DDB(printf("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2));
- devc->base = io_base;
- devc->MCE_bit = 0x40;
- devc->irq = 0;
- devc->dma_capture = 0;
- devc->dma_playback = 0;
- devc->opened = 0;
- devc->chip_name = "AD1848";
- devc->mode = 1; /* MODE1 = original AD1848 */
-
- /*
- * Check that the I/O address is in use.
- *
- * The bit 0x80 of the base I/O port is known to be 0 after the
- * chip has performed it's power on initialization. Just assume
- * this has happened before the OS is starting.
- *
- * If the I/O address is unused, it typically returns 0xff.
- */
+ return 0;
+ }
+ /*
+ * The indirect register I12 has some read only bits. Lets try to
+ * change them.
+ */
+
+ DDB(printf("ad1848_detect() - step D, last 4 bits of I12 readonly\n"));
+ tmp = ad_read(devc, 12);
+ ad_write(devc, 12, (~tmp) & 0x0f);
+ tmp1 = ad_read(devc, 12);
+
+ if ((tmp & 0x0f) != (tmp1 & 0x0f)) {
+ DDB(printf("ad1848 detect error - step D, I12 (0x%02x was 0x%02x)\n",
+ tmp1, tmp));
+ return 0;
+ }
- if ((INB (devc->base) & 0x80) != 0x00) /* Not a AD1884 */
- {
- DDB (printk ("ad_detect_A\n"));
- return 0;
+ /*
+ * NOTE! Last 4 bits of the reg I12 tell the chip revision.
+ * 0x01=RevB
+ * 0x0A=RevC. also CS4231/CS4231A and OPTi931
+ */
+
+
+ /*
+ * The original AD1848/CS4248 has just 15 indirect registers. This
+ * means that I0 and I16 should return the same value (etc.). Ensure
+ * that the Mode2 enable bit of I12 is 0. Otherwise this test fails
+ * with CS4231.
+ */
+
+ DDB(printf("ad1848_detect() - step F\n"));
+ ad_write(devc, 12, 0); /* Mode2=disabled */
+
+ for (i = 0; i < 16; i++)
+ if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) {
+ DDB(printf("ad1848 detect warning - step F(I%d/0x%02x/0x%02x)\n",
+ i, tmp1, tmp2));
+ /*
+ * note - this seems to fail on the 4232 on I11. So we just break
+ * rather than fail.
+ */
+ break ; /* return 0; */
+ }
+ /*
+ * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit
+ * (0x40). The bit 0x80 is always 1 in CS4248 and CS4231.
+ *
+ * On the OPTi931, however, I12 is readonly and only contains the
+ * chip revision ID (as in the CS4231A). The upper bits return 0.
+ */
+
+ DDB(printf("ad1848_detect() - step G\n"));
+ ad_write(devc, 12, 0x40); /* Set mode2, clear 0x80 */
+
+ tmp1 = ad_read(devc, 12);
+ if (tmp1 & 0x80) {
+ if (ad_flags)
+ *ad_flags |= AD_F_CS4248;
+
+ devc->chip_name = "CS4248"; /* Our best knowledge just now */
}
+ if ((tmp1 & 0xf0) == 0x00) {
+ printf("this should be an OPTi931\n");
+ } else if ((tmp1 & 0xc0) == 0xC0) {
+ /*
+ * The 4231 has bit7=1 always, and bit6 we just set to 1.
+ * We want to check that this is really a CS4231
+ * Verify that setting I0 doesn't change I16.
+ */
+ DDB(printf("ad1848_detect() - step H\n"));
+ ad_write(devc, 16, 0); /* Set I16 to known value */
- /*
- * Test if it's possible to change contents of the indirect registers.
- * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
- * so try to avoid using it.
-*/
+ ad_write(devc, 0, 0x45);
+ if ((tmp1 = ad_read(devc, 16)) != 0x45) { /* No change -> CS4231? */
- ad_write (devc, 0, 0xaa);
- ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */
+ ad_write(devc, 0, 0xaa);
+ if ((tmp1 = ad_read(devc, 16)) == 0xaa) { /* Rotten bits? */
+ DDB(printf("ad1848 detect error - step H(%x)\n", tmp1));
+ return 0;
+ }
+ /*
+ * Verify that some bits of I25 are read only.
+ */
+
+ DDB(printf("ad1848_detect() - step I\n"));
+ tmp1 = ad_read(devc, 25); /* Original bits */
+ ad_write(devc, 25, ~tmp1); /* Invert all bits */
+ if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7)) {
+ int id;
+
+ /*
+ * It's at least CS4231
+ */
+ devc->chip_name = "CS4231";
+ devc->mode = MD_4231;
+
+ /*
+ * It could be an AD1845 or CS4231A as well.
+ * CS4231 and AD1845 report the same revision info in I25
+ * while the CS4231A reports different.
+ */
+
+ DDB(printf("ad1848_detect() - step I\n"));
+ id = ad_read(devc, 25) & 0xe7;
+ /*
+ * b7-b5 = version number;
+ * 100 : all CS4231
+ * 101 : CS4231A
+ *
+ * b2-b0 = chip id;
+ */
+ switch (id) {
+
+ case 0xa0:
+ devc->chip_name = "CS4231A";
+ devc->mode = MD_4231A;
+ break;
+
+ case 0xa2:
+ devc->chip_name = "CS4232";
+ devc->mode = MD_4231A;
+ break;
+
+ case 0xb2:
+ /* strange: the 4231 data sheet says b4-b3 are XX
+ * so this should be the same as 0xa2
+ */
+ devc->chip_name = "CS4232A";
+ devc->mode = MD_4231A;
+ break;
+
+ case 0x80:
+ /*
+ * It must be a CS4231 or AD1845. The register I23
+ * of CS4231 is undefined and it appears to be read
+ * only. AD1845 uses I23 for setting sample rate.
+ * Assume the chip is AD1845 if I23 is changeable.
+ */
+
+ tmp = ad_read(devc, 23);
+
+ ad_write(devc, 23, ~tmp);
+ if (ad_read(devc, 23) != tmp) { /* AD1845 ? */
+ devc->chip_name = "AD1845";
+ devc->mode = MD_1845;
+ }
+ ad_write(devc, 23, tmp); /* Restore */
+ break;
+
+ case 0x83: /* CS4236 */
+ default: /* Assume CS4231 */
+ printf("unknown id 0x%02x, assuming CS4231\n", id);
+ devc->mode = MD_4231;
+
+ }
+ }
+ ad_write(devc, 25, tmp1); /* Restore bits */
- if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45)
- {
- DDB (printk ("ad_detect_B (%x/%x)\n", tmp1, tmp2));
- return 0;
+ DDB(printf("ad1848_detect() - step K\n"));
+ }
}
+ DDB(printf("ad1848_detect() - step L\n"));
- ad_write (devc, 0, 0x45);
- ad_write (devc, 1, 0xaa);
+ if (ad_flags) {
+ if (devc->mode != MD_1848)
+ *ad_flags |= AD_F_CS4231;
+ }
+ DDB(printf("ad1848_detect() - Detected OK\n"));
+ return (last_result = 1);
+}
- if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa)
- {
- DDB (printk ("ad_detect_C (%x/%x)\n", tmp1, tmp2));
- return 0;
+void
+ad1848_init(char *name, int io_base, int irq,
+ int dma_playback, int dma_capture, int share_dma, sound_os_info * osp)
+{
+
+ /*
+ * NOTE! If irq < 0, there is another driver which has allocated the
+ * IRQ so that this driver doesn't need to allocate/deallocate it.
+ * The actually used IRQ is ABS(irq).
+ */
+
+ /*
+ * Initial values for the indirect registers of CS4248/AD1848.
+ */
+ static int init_values[] = {
+ 0xa8, /* MIXOUTL: src:mic, +20dB, gain +12dB */
+ 0xa8, /* MIXOUTR: src:mic, +20dB, gain +12dB */
+ 0x08, /* CDL Input: mute, +6dB */
+ 0x08, /* CDR Input: mute, +6dB */
+ 0x08, /* FML Input: mute, +6dB */
+ 0x08, /* FMR Input: mute, +6dB */
+ 0x80, /* DAC-L Input: enable, 0dB */
+ 0x80, /* DAC-R Input: enable, 0dB */
+ /* 0xa8, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, */
+ 0x00, /* 8bit, lin, uns, mono, 8KHz */
+ 0x0c, /* dma-cap, dma-pb, autocal, single dma, disable cap/pb */
+ 0x02, /* int enable */
+ 0x00, /* clear error status */
+ 0x8a, /* rev. id (low bytes readonly) */
+ 0x00,
+ 0x00, /* playback upper base count */
+ 0x00, /* playback lower base count */
+
+ /* Positions 16 to 31 just for CS4231 and newer devices */
+ /* I16-I17: alt. feature enable on the 4231, but AUXL Input
+ * on the OPTi931 (where the features are set elsewhere
+ */
+ 0x81, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ int i, my_dev;
+
+ ad1848_info *devc = &dev_info[nr_ad1848_devs];
+
+ if (!ad1848_detect(io_base, NULL, osp))
+ return;
+
+ devc->irq = (irq > 0) ? irq : 0;
+ devc->opened = 0;
+ devc->timer_ticks = 0;
+ devc->osp = osp;
+
+ if (nr_ad1848_devs != 0) {
+ bcopy((char *) &ad1848_pcm_operations[0],
+ (char *) &ad1848_pcm_operations[nr_ad1848_devs],
+ sizeof(struct audio_operations));
}
+ for (i = 0; i < 16; i++)
+ ad_write(devc, i, init_values[i]);
+
+ ad_mute(devc); /* Initialize some variables */
+ ad_unmute(devc); /* Leave it unmuted now */
+
+ if (devc->mode > MD_1848) {
+ if (dma_capture == dma_playback ||
+ dma_capture == -1 || dma_playback == -1) {
+ ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */
+ ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+ } else {
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x04); /* Dual DMA mode */
+ ad1848_pcm_operations[nr_ad1848_devs].flags |= DMA_DUPLEX;
+ }
- /*
- * The indirect register I12 has some read only bits. Lets
- * try to change them.
- */
+ ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */
+ for (i = 16; i < 32; i++)
+ ad_write(devc, i, init_values[i]);
- tmp = ad_read (devc, 12);
- ad_write (devc, 12, (~tmp) & 0x0f);
+ if (devc->mode == MD_4231A) {
+ /* Enable full * calibration */
+ ad_write(devc, 9, init_values[9] | 0x18);
+ }
- if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f))
- {
- DDB (printk ("ad_detect_D (%x)\n", tmp1));
- return 0;
+ if (devc->mode == MD_1845) {
+ /* Alternate freq select enabled */
+ ad_write(devc, 27, init_values[27] | 0x08);
+ }
+ } else {
+ ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+ ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */
}
- /*
- * NOTE! Last 4 bits of the reg I12 tell the chip revision.
- * 0x01=RevB and 0x0A=RevC.
- */
+ outb(io_Status(devc), 0); /* Clear pending interrupts */
- /*
- * The original AD1848/CS4248 has just 15 indirect registers. This means
- * that I0 and I16 should return the same value (etc.).
- * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
- * with CS4231.
- */
+ if (name != NULL && name[0] != 0)
+ sprintf(ad1848_pcm_operations[nr_ad1848_devs].name,
+ "%s (%s)", name, devc->chip_name);
+ else
+ sprintf(ad1848_pcm_operations[nr_ad1848_devs].name,
+ "Generic audio codec (%s)", devc->chip_name);
- ad_write (devc, 12, 0); /* Mode2=disabled */
+ conf_printf2(ad1848_pcm_operations[nr_ad1848_devs].name,
+ devc->base, devc->irq, dma_playback, dma_capture);
- for (i = 0; i < 16; i++)
- if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16)))
- {
- DDB (printk ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2));
- return 0;
- }
- /*
- * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
- * The bit 0x80 is always 1 in CS4248 and CS4231.
- */
+ /* ad1848_pcm_operations[nr_ad1848_devs].flags |= DMA_AUTOMODE ; */
- ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
+ if (num_audiodevs < MAX_AUDIO_DEV) {
+ audio_devs[my_dev = num_audiodevs++] =
+ &ad1848_pcm_operations[nr_ad1848_devs];
+ if (irq > 0) {
+ audio_devs[my_dev]->devc = devc;
+ irq2dev[irq] = my_dev;
+ if (snd_set_irq_handler(devc->irq, ad1848_interrupt, devc->osp)<0) {
+ printf("ad1848: IRQ in use\n");
+ }
+#ifdef NO_IRQ_TEST
+ if (devc->mode != MD_1848) {
+ int x;
+ u_char tmp = ad_read(devc, 16);
- tmp1 = ad_read (devc, 12);
- if (tmp1 & 0x80)
- devc->chip_name = "CS4248";
+ devc->timer_ticks = 0;
- if ((tmp1 & 0xc0) == (0x80 | 0x40))
- {
- /*
- * CS4231 detected - is it?
- *
- * Verify that setting I0 doesn't change I16.
- */
- ad_write (devc, 16, 0); /* Set I16 to known value */
+ ad_write(devc, 21, 0x00); /* Timer msb */
+ ad_write(devc, 20, 0x10); /* Timer lsb */
- ad_write (devc, 0, 0x45);
- if ((tmp1 = ad_read (devc, 16)) != 0x45) /* No change -> CS4231? */
- {
+ ad_write(devc, 16, tmp | 0x40); /* Enable timer */
+ for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
+ ad_write(devc, 16, tmp & ~0x40); /* Disable timer */
- ad_write (devc, 0, 0xaa);
- if ((tmp1 = ad_read (devc, 16)) == 0xaa) /* Rotten bits? */
- {
- DDB (printk ("ad_detect_H(%x)\n", tmp1));
- return 0;
- }
+ if (devc->timer_ticks == 0)
+ printf("[IRQ conflict???]");
+ else
+ devc->irq_ok = 1;
- /*
- * It's a CS4231 - So what!
- * (Mode2 will be supported later)
+ } else
+ devc->irq_ok = 1; /* Couldn't test. assume it's OK */
+#else
+ devc->irq_ok = 1;
+#endif
+ } else if (irq < 0)
+ irq2dev[-irq] = devc->dev_no = my_dev;
+
+ audio_devs[my_dev]->otherside = -1 ;
+ audio_devs[my_dev]->flags |= DMA_AUTOMODE | DMA_DUPLEX;
+ audio_devs[my_dev]->dmachan1 = dma_playback;
+ audio_devs[my_dev]->dmachan2 = dma_capture;
+ audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
+ audio_devs[my_dev]->devc = devc;
+ audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
+ nr_ad1848_devs++;
+
+#ifdef CONFIG_SEQUENCER
+ if (devc->mode != MD_1848 && devc->irq_ok)
+ ad1848_tmr_install(my_dev);
+#endif
+
+ /*
+ * Toggle the MCE bit. It completes the initialization phase.
*/
- devc->chip_name = "CS4231";
- devc->mode = 2;
+
+ ad_enter_MCE(devc); /* In case the bit was off */
+ ad_leave_MCE(devc);
+
+ if (num_mixers < MAX_MIXER_DEV) {
+ mixer2codec[num_mixers] = my_dev + 1;
+ audio_devs[my_dev]->mixer_dev = num_mixers;
+ mixer_devs[num_mixers++] = &ad1848_mixer_operations;
+ ad1848_mixer_reset(devc);
}
+ } else
+ printf("AD1848: Too many PCM devices available\n");
+}
+
+void
+ad1848_interrupt(int irq)
+{
+ u_char status;
+ ad1848_info *devc;
+ int dev;
+
+ if (irq < 0 || irq > 15)
+ dev = -1;
+ else
+ dev = irq2dev[irq];
+
+ if (dev < 0 || dev >= num_audiodevs) {
+ for (irq = 0; irq < 17; irq++)
+ if (irq2dev[irq] != -1)
+ break;
+
+ if (irq > 15) {
+ printf("ad1848.c: Bogus interrupt %d\n", irq);
+ return;
+ }
+ dev = irq2dev[irq];
}
+ devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ status = inb(io_Status(devc));
+
+ if (status & 0x01) { /* we have an interrupt */
+ int alt_stat = 0xff ;
+
+ if (devc->mode != MD_1848) {
+ /*
+ * high-end devices have full-duplex dma and timer.
+ * the exact reason for the interrupt is in reg. I24.
+ * For old devices, we fake the interrupt bits, and
+ * determine the real reason basing on the device mode.
+ */
+ alt_stat = ad_read(devc, 24);
+ if (alt_stat & 0x40) { /* Timer interrupt */
+ devc->timer_ticks++;
+#ifdef CONFIG_SEQUENCER
+ if (timer_installed == dev && devc->timer_running)
+ sound_timer_interrupt();
+#endif
+ }
+ }
+
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+
+ if (audio_devs[dev]->busy) {
+
+ if (devc->irq_mode & PCM_ENABLE_OUTPUT && alt_stat & 0x10)
+ DMAbuf_outputintr(dev, 1);
- return 1;
+ if (devc->irq_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
+ DMAbuf_inputintr(dev);
+ }
+ }
}
+/*
+ * Some extra code for the MS Sound System
+ */
+
+#ifdef amancio
void
-ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture)
+check_opl3(int base, struct address_info * hw_config)
{
- /*
- * NOTE! If irq < 0, there is another driver which has allocated the IRQ
- * so that this driver doesn't need to allocate/deallocate it.
- * The actually used IRQ is ABS(irq).
- */
- /*
- * Initial values for the indirect registers of CS4248/AD1848.
+ if (!opl3_detect(base, hw_config->osp))
+ return;
+
+ opl3_init(0, base, hw_config->osp);
+}
+#endif
+
+/*
+ * this is the probe routine. Note, it is not necessary to
+ * go through this for PnP devices, since they are already
+ * indentified precisely using their PnP id.
+ *
*/
- static int init_values[] =
- {
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
- 0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00
- };
- int i, my_dev;
- ad1848_info *devc = &dev_info[nr_ad1848_devs];
-
- if (!ad1848_detect (io_base))
- return;
-
- devc->irq = (irq > 0) ? irq : 0;
- devc->dma_capture = dma_playback;
- devc->dma_playback = dma_capture;
- devc->opened = 0;
-
- if (nr_ad1848_devs != 0)
- {
- memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs],
- (char *) &ad1848_pcm_operations[0],
- sizeof (struct audio_operations));
- }
- for (i = 0; i < 16; i++)
- ad_write (devc, i, init_values[i]);
+int
+probe_mss(struct address_info * hw_config)
+{
+ u_char tmp;
- OUTB (0, io_Status (devc)); /* Clear pending interrupts */
+ DDB(printf("Entered probe_mss(io 0x%x, type %d)\n",
+ hw_config->io_base, hw_config->card_subtype));
-#ifndef SCO
- sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
- "%s (%s)", name, devc->chip_name);
+ if (hw_config->card_subtype == 1) { /* Has no IRQ/DMA registers */
+ /* check_opl3(0x388, hw_config); */
+ goto probe_ms_end;
+ }
+
+#if defined(CONFIG_AEDSP16) && defined(AEDSP16_MSS)
+ /*
+ * Initialize Audio Excel DSP 16 to MSS: before any operation we must
+ * enable MSS I/O ports.
+ */
+ InitAEDSP16_MSS(hw_config);
#endif
- if (irq > 0)
- printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
+ /*
+ * Check if the IO port returns valid signature. The original MS
+ * Sound system returns 0x04 while some cards (AudioTriX Pro for
+ * example) return 0x00 or 0x0f.
+ */
- if (num_audiodevs < MAX_AUDIO_DEV)
- {
- audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs];
- if (irq > 0)
- irq2dev[irq] = my_dev;
- else if (irq < 0)
- irq2dev[-irq] = my_dev;
+ if ((tmp = inb(hw_config->io_base + 3)) == 0xff) { /* Bus float */
+ DDB(printf("I/O address inactive (%x), force type 1\n", tmp));
+ hw_config->card_subtype = 1 ;
+ goto probe_ms_end;
+ }
- audio_devs[my_dev]->dmachan = dma_playback;
- audio_devs[my_dev]->buffcount = 1;
- audio_devs[my_dev]->buffsize = DSP_BUFFSIZE * 2;
- audio_devs[my_dev]->devc = devc;
- audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
- nr_ad1848_devs++;
+ if ((tmp & 0x3f) != 0x04 &&
+ (tmp & 0x3f) != 0x0f &&
+ (tmp & 0x3f) != 0x00) {
+ DDB(printf("No MSS signature detected on port 0x%x (0x%x)\n",
+ hw_config->io_base, inb(hw_config->io_base + 3)));
+ return 0;
}
- else
- printk ("AD1848: Too many PCM devices available\n");
+ if (hw_config->irq > 11) {
+ printf("MSS: Bad IRQ %d\n", hw_config->irq);
+ return 0;
+ }
+ if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) {
+ printf("MSS: Bad DMA %d\n", hw_config->dma);
+ return 0;
+ }
+ /*
+ * Check that DMA0 is not in use with a 8 bit board.
+ */
+
+ if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) {
+ printf("MSS: Can't use DMA0 with a 8 bit card/slot\n");
+ return 0;
+ }
+ if (hw_config->irq > 7 && hw_config->irq != 9 &&
+ inb(hw_config->io_base + 3) & 0x80) {
+ printf("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
+ return 0;
+ }
+probe_ms_end:
+ return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);
}
void
-ad1848_interrupt (int irq)
+attach_mss(struct address_info * hw_config)
{
- unsigned char status;
- ad1848_info *devc;
- int dev;
-
- if (irq < 0 || irq > 15)
- return; /* Bogus irq */
- dev = irq2dev[irq];
- if (dev < 0 || dev >= num_audiodevs)
- return; /* Bogus dev */
- devc = (ad1848_info *) audio_devs[dev]->devc;
- status = INB (io_Status (devc));
-
- if (status & 0x01)
- {
- if (devc->opened && devc->irq_mode == IMODE_OUTPUT)
- {
- DMAbuf_outputintr (dev, 1);
- }
+#if 0
+ /*
+ * XXX do we really need to detect it again ? - lr970712
+ */
+ if (!ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))
+ return ;
+#endif
- if (devc->opened && devc->irq_mode == IMODE_INPUT)
- DMAbuf_inputintr (dev);
+ if (hw_config->card_subtype == 1) { /* Has no IRQ/DMA registers */
+ ad1848_init("MS Sound System1", hw_config->io_base + 4,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma2, 0, hw_config->osp);
+ } else {
+ /*
+ * Set the IRQ and DMA addresses.
+ */
+ static char interrupt_bits[12] = {
+ -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
+ };
+ static char dma_bits[4] = {
+ 1, 2, 0, 3
+ };
+
+ int config_port = hw_config->io_base + 0;
+ int version_port = hw_config->io_base + 3;
+ char bits = interrupt_bits[hw_config->irq];
+
+ if (bits == -1)
+ return ;
+
+ outb(config_port, bits | 0x40);
+ if ((inb(version_port) & 0x40) == 0)
+ printf("[IRQ Conflict?]");
+
+ /* Write IRQ+DMA setup */
+ outb(config_port, bits | dma_bits[hw_config->dma]);
+
+ ad1848_init("MS Sound System0", hw_config->io_base + 4,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma, 0, hw_config->osp);
}
-
- OUTB (0, io_Status (devc)); /* Clear interrupt status */
+ return ;
}
-#endif
/*
- * Some extra code for the MS Sound System
+ * WSS compatible PnP codec support.
+ * XXX I doubt it works now - lr970712
*/
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS)
int
-probe_ms_sound (struct address_info *hw_config)
+probe_pnp_ad1848(struct address_info * hw_config)
{
- if ((INB (hw_config->io_base + 3) & 0x04) == 0)
- return 0; /* WSS ID test failed */
+ return ad1848_detect(hw_config->io_base, NULL, hw_config->osp);
+}
- if (hw_config->irq > 11)
- return 0;
+void
+attach_pnp_ad1848(struct address_info * hw_config)
+{
- if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
- return 0;
+ ad1848_init(hw_config->name, hw_config->io_base,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma2, 0, hw_config->osp);
+}
+
+#ifdef CONFIG_SEQUENCER
+/*
+ * Timer stuff (for /dev/music).
+ */
+
+static u_int current_interval = 0;
+
+static u_int
+ad1848_tmr_start(int dev, u_int usecs)
+{
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long xtal_nsecs; /* nanoseconds per xtal oscillaror tick */
+ u_long divider;
+
+ flags = splhigh();
+
+ /*
+ * Length of the timer interval (in nanoseconds) depends on the
+ * selected crystal oscillator. Check this from bit 0x01 of I8.
+ *
+ * AD1845 has just one oscillator which has cycle time of 10.050 us
+ * (when a 24.576 MHz xtal oscillator is used).
+ *
+ * Convert requested interval to nanoseconds before computing the timer
+ * divider.
+ */
+
+ if (devc->mode == MD_1845)
+ xtal_nsecs = 10050;
+ else if (ad_read(devc, 8) & 0x01)
+ xtal_nsecs = 9920;
+ else
+ xtal_nsecs = 9969;
+
+ divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs;
+
+ if (divider < 100) /* Don't allow shorter intervals than about 1ms */
+ divider = 100;
+
+ if (divider > 65535) /* Overflow check */
+ divider = 65535;
+
+ ad_write(devc, 21, (divider >> 8) & 0xff); /* Set upper bits */
+ ad_write(devc, 20, divider & 0xff); /* Set lower bits */
+ ad_write(devc, 16, ad_read(devc, 16) | 0x40); /* Start the timer */
+ devc->timer_running = 1;
+ splx(flags);
+
+ return current_interval = (divider * xtal_nsecs + 500) / 1000;
+}
+
+static void
+ad1848_tmr_reprogram(int dev)
+{
+ /*
+ * Audio driver has changed sampling rate so that a different xtal
+ * oscillator was selected. We have to reprogram the timer rate.
+ */
- return ad1848_detect (hw_config->io_base + 4);
+ ad1848_tmr_start(dev, current_interval);
+ sound_timer_syncinterval(current_interval);
}
-long
-attach_ms_sound (long mem_start, struct address_info *hw_config)
+static void
+ad1848_tmr_disable(int dev)
{
- static unsigned char interrupt_bits[12] =
- {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
- char bits;
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- static unsigned char dma_bits[4] = {1, 2, 0, 3};
+ flags = splhigh();
+ ad_write(devc, 16, ad_read(devc, 16) & ~0x40);
+ devc->timer_running = 0;
+ splx(flags);
+}
- int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+static void
+ad1848_tmr_restart(int dev)
+{
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- if (!ad1848_detect (hw_config->io_base + 4))
- return mem_start;
+ if (current_interval == 0)
+ return;
- /*
- * Set the IRQ and DMA addresses.
- */
+ flags = splhigh();
+ ad_write(devc, 16, ad_read(devc, 16) | 0x40);
+ devc->timer_running = 1;
+ splx(flags);
+}
- bits = interrupt_bits[hw_config->irq];
- if (bits == -1)
- return mem_start;
+static struct sound_lowlev_timer ad1848_tmr = {
+ 0,
+ ad1848_tmr_start,
+ ad1848_tmr_disable,
+ ad1848_tmr_restart
+};
- OUTB (bits | 0x40, config_port); /* Verify IRQ (I guess) */
- if ((INB (version_port) & 0x40) == 0)
- printk ("[IRQ?]");
+static int
+ad1848_tmr_install(int dev)
+{
+ if (timer_installed != -1)
+ return 0; /* Don't install another timer */
- OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */
+ timer_installed = ad1848_tmr.dev = dev;
+ sound_timer_init(&ad1848_tmr, audio_devs[dev]->name);
- ad1848_init ("MS Sound System", hw_config->io_base + 4,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma);
- return mem_start;
+ return 1;
}
-
+#endif
#endif
diff --git a/sys/i386/isa/sound/ad1848_mixer.h b/sys/i386/isa/sound/ad1848_mixer.h
index 9404047ce77d..7a1d3230ece7 100644
--- a/sys/i386/isa/sound/ad1848_mixer.h
+++ b/sys/i386/isa/sound/ad1848_mixer.h
@@ -35,9 +35,10 @@
* (Actually this is not a mapping but rather some kind of interleaving
* solution).
*/
+#define GUSMAX_MIXER
#ifdef GUSMAX_MIXER
#define MODE1_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \
- SOUND_MASK_CD)
+ SOUND_MASK_CD|SOUND_MASK_IMIX)
#define MODE1_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_MIC | \
SOUND_MASK_CD | \
@@ -50,7 +51,7 @@
SOUND_MASK_PCM | SOUND_MASK_IMIX)
#else /* Generic mapping */
#define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \
- SOUND_MASK_LINE1)
+ SOUND_MASK_LINE1|SOUND_MASK_IMIX)
#define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \
SOUND_MASK_LINE2 | \
@@ -70,6 +71,14 @@ struct mixer_def {
unsigned int nbits:4;
};
+static char mix_cvt[101] = {
+ 0, 0,3,7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
+ 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,
+ 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,
+ 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,
+ 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99,
+ 100
+};
typedef struct mixer_def mixer_ent;
@@ -83,7 +92,7 @@ typedef struct mixer_def mixer_ent;
*/
#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \
- {{reg_l, pola_l, pos_r, len_l}, {reg_r, pola_r, pos_r, len_r}}
+ {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}
mixer_ent mix_devices[32][2] = { /* As used in GUS MAX */
MIX_ENT(SOUND_MIXER_VOLUME, 0, 0, 0, 0, 0, 0, 0, 0),
@@ -93,7 +102,7 @@ MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5),
MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6),
MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5),
-MIX_ENT(SOUND_MIXER_MIC, 0, 1, 5, 1, 1, 1, 5, 1),
+MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1),
MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5),
MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0),
@@ -111,20 +120,23 @@ static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] =
0x3232, /* Bass */
0x3232, /* Treble */
0x4b4b, /* FM */
- 0x6464, /* PCM */
+ 0x4040, /* PCM */
0x4b4b, /* PC Speaker */
- 0x4b4b, /* Ext Line */
- 0x1010, /* Mic */
+ /* 0x2020, Ext Line */
+ 0x0000, /* Ext Line */
+ 0x4040, /* Mic */
0x4b4b, /* CD */
0x0000, /* Recording monitor */
0x4b4b, /* SB PCM */
0x4b4b, /* Recording level */
- 0x4b4b, /* Input gain */
- 0x4b4b, /* Output gain */
- 0x4b4b, /* Line1 */
- 0x4b4b, /* Line2 */
- 0x4b4b /* Line3 */
+ 0x2525, /* Input gain */
+ 0x0000, /* Output gain */
+ /* 0x4040, Line1 */
+ 0x0000, /* Line1 */
+ 0x0000, /* Line2 */
+ 0x1515, /* Line3 (usually line in)*/
};
#define LEFT_CHN 0
#define RIGHT_CHN 1
+
diff --git a/sys/i386/isa/sound/adlib_card.c b/sys/i386/isa/sound/adlib_card.c
index 6365069384a5..41039b934d0a 100644
--- a/sys/i386/isa/sound/adlib_card.c
+++ b/sys/i386/isa/sound/adlib_card.c
@@ -1,10 +1,10 @@
/*
* sound/adlib_card.c
- *
+ *
* Detection routine for the AdLib card.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,28 +24,23 @@
* 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"
+#include <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812)
+#if defined(CONFIG_YM3812)
-long
-attach_adlib_card (long mem_start, struct address_info *hw_config)
+void
+attach_adlib_card(struct address_info * hw_config)
{
-
- if (opl3_detect (FM_MONO))
- {
- mem_start = opl3_init (mem_start);
- }
- return mem_start;
+ opl3_init(hw_config->io_base, hw_config->osp);
}
int
-probe_adlib (struct address_info *hw_config)
+probe_adlib(struct address_info * hw_config)
{
- return opl3_detect (FM_MONO);
+ return opl3_detect(hw_config->io_base, hw_config->osp);
}
#endif
diff --git a/sys/i386/isa/sound/aedsp16.c b/sys/i386/isa/sound/aedsp16.c
index b14a24618f0c..e69de29bb2d1 100644
--- a/sys/i386/isa/sound/aedsp16.c
+++ b/sys/i386/isa/sound/aedsp16.c
@@ -1,838 +0,0 @@
-/*
- sound/aedsp16.c
-
- Audio Excel DSP 16 software configuration routines
-
- Copyright (C) 1995 Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it)
-
- 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.
-
- READ THIS
-
- This module is intended for Audio Excel DSP 16 Sound Card.
-
- Audio Excel DSP 16 is an SB pro II, Microsoft Sound System
- and MPU-401 compatible card.
- It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq),
- so before this module, the only way to configure the DSP under linux was
- boot the MS-BAU loading the sound.sys device driver (this driver soft-
- configure the sound board hardware by massaging someone of its registers),
- and then ctrl-alt-del to boot linux with the DSP configured by the DOG
- driver.
-
- This module works configuring your Audio Excel DSP 16's
- irq, dma and mpu-401-irq. The voxware probe routines rely on the
- fact that if the hardware is there, they can detect it. The problem
- with AEDSP16 is that no hardware can be found by the probe routines
- if the sound card is not well configured. Sometimes the kernel probe
- routines can find an SBPRO even when the card is not configured (this
- is the standard setup of the card), but the SBPRO emulation don't work
- well if the card is not properly initialized. For this reason
-
- InitAEDSP16_...()
-
- routines are called before the voxware probe routines try to detect the
- hardware.
-
- NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS)
-
- The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS;
- the voxware sound driver can be configured for SBPRO and MSS cards
- at the same time, but the aedsp16 can't be two cards!!
- When we configure it, we have to choose the SBPRO or the MSS emulation
- for AEDSP16. We also can install a *REAL* card of the other type
- (see [1], not tested but I can't see any reason for it to fail).
-
- NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO
- please let me know if it works.
-
- The MPU-401 support can be compiled in together with one of the other
- two operating modes.
-
- The board configuration calls, are in the probe_...() routines because
- we have to configure the board before probing it for a particular
- hardware. After card configuration, we can probe the hardware.
-
- NOTE: This is something like plug-and-play: we have only to plug
- the AEDSP16 board in the socket, and then configure and compile
- a kernel that uses the AEDSP16 software configuration capability.
- No jumper setting is needed!
-
- For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3
- you have just to make config the voxware package, configuring
- the SBPro sound card with that parameters, then when configure
- asks if you have an AEDSP16, answer yes. That's it.
- Compile the kernel and run it.
-
- NOTE: This means that you can choose irq and dma, but not the
- I/O addresses. To change I/O addresses you have to set them
- with jumpers.
-
- NOTE: InitAEDSP16_...() routines get as parameter the hw_config,
- the hardware configuration of the - to be configured - board.
- The InitAEDSP16() routine, configure the board following our
- wishes, that are in the hw_config structure.
-
- You can change the irq/dma/mirq settings WITHOUT THE NEED to open
- your computer and massage the jumpers (there are no irq/dma/mirq
- jumpers to be configured anyway, only I/O port ones have to be
- configured with jumpers)
-
- For some ununderstandable reason, the card default of irq 7, dma 1,
- don't work for me. Seems to be an IRQ or DMA conflict. Under heavy
- HDD work, the kernel start to erupt out a lot of messages like:
-
- 'Sound: DMA timed out - IRQ/DRQ config error?'
-
- For what I can say, I have NOT any conflict at irq 7 (under linux I'm
- using the lp polling driver), and dma line 1 is unused as stated by
- /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so
- I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows!
- Anyway a setting of irq 10, dma 3 works really fine.
-
- NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know
- the emulation mode, all the installed hardware and the hardware
- configuration (irq and dma settings of all the hardware).
-
- This init module should work with SBPRO+MSS, when one of the two is
- the AEDSP16 emulation and the other the real card. (see [1])
- For example:
-
- AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other
- AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other
-
- MPU401 should work. (see [1])
-
- [1] Not tested by me for lack of hardware.
-
- TODO, WISHES AND TECH
-
- May be there's lot of redundant delays, but for now I want to leave it
- this way.
-
- Should be interesting eventually write down a new ioctl for the
- aedsp16, to let the suser() change the irq/dma/mirq on the fly.
- The thing is not trivial.
- In the real world, there's no need to have such an ioctl because
- when we configure the kernel for compile, we can choose the config
- parameters. If we change our mind, we can easily re-config the kernel
- and re-compile.
- Why let the suser() change the config parameters on the fly ?
- If anyone have a reasonable answer to this question, I will write down
- the code to do it.
-
- More integration with voxware, using voxware low level routines to
- read-write dsp is not possible because you may want to have MSS
- support and in that case we can not rely on the functions included
- in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my
- own I/O functions.
-
- - About I/O ports allocation -
-
- The request_region should be done at device probe in every sound card
- module. This module is not the best site for requesting regions.
- When the request_region code will be added to the main modules such as
- sb, adlib, gus, ad1848, etc, the requesting code in this module should
- go away.
-
- I think the request regions should be done this way:
-
- if (check_region(...))
- return ERR; // I/O region alredy reserved
- device_probe(...);
- device_attach(...);
- request_region(...); // reserve only when we are sure all is okay
-
- Request the 2x0h region in any case if we are using this card.
-
- NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region
- (see code) does not mean necessarly that we are emulating sbpro.
- It mean that the region is the sbpro I/O ports region. We use this
- region to access the control registers of the card, and if emulating
- sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro
- registers are not used, in no way, to emulate an sbpro: they are
- used only for configuration pourposes.
-
- Someone pointed out that should be possible use both the SBPRO and MSS
- modes because the sound card have all the two chipsets, supposing that
- the card is really two cards. I have tried something to have the two
- modes work together, but, for some reason unknown to me, without success.
-
- I think all the soft-config only cards have an init sequence similar to
- this. If you have a card that is not an aedsp16, you can try to start
- with this module changing it (mainly in the CMD? I think) to fit your
- needs.
-
- Started Fri Mar 17 16:13:18 MET 1995
-
- v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c)
- - Initial code.
- v0.2 (ALPHA)
- - Cleanups.
- - Integrated with Linux voxware v 2.90-2 kernel sound driver.
- - SoundBlaster Pro mode configuration.
- - Microsoft Sound System mode configuration.
- - MPU-401 mode configuration.
- v0.3 (ALPHA)
- - Cleanups.
- - Rearranged the code to let InitAEDSP16 be more general.
- - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h
- inclusion too. We rely on os.h
- - Used the INB and OUTB #defined in os.h instead of inb and outb.
- - Corrected the code for GetCardName (DSP Copyright) to get a variable
- len string (we are not sure about the len of Copyright string).
- This works with any SB and compatible.
- - Added the code to request_region at device init (should go in
- the main body of voxware).
- v0.4 (BETA)
- - Better configure.c patch for aedsp16 configuration (better
- logic of inclusion of AEDSP16 support)
- - Modified the conditional compilation to better support more than
- one sound card of the emulated type (read the NOTES above)
- - Moved the sb init routine from the attach to the very first
- probe in sb_card.c
- - Rearrangemens and cleanups
- - Wiped out some unnecessary code and variables: this is kernel
- code so it is better save some TEXT and DATA
- - Fixed the request_region code. We must allocate the aedsp16 (sbpro)
- I/O ports in any case because they are used to access the DSP
- configuration registers and we can not allow anyone to get them.
- v0.5
- - cleanups on comments
- - prep for diffs against v3.0-proto-950402
-
- */
-
-/*
- * Include the main voxware header file. It include all the os/voxware/etc
- * headers needed by this source.
- */
-#include "sound_config.h"
-/*
- * all but ioport.h :)
- */
-#include <linux/ioport.h>
-
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AEDSP16)
-
-#define VERSION "0.5" /* Version of Audio Excel DSP 16 driver */
-
-#undef AEDSP16_DEBUG /* Define this to enable debug code */
-/* Actually no debug code is activated */
-
-/*
- * Hardware related defaults
- */
-#define IRQ 7 /* 5 7(default) 9 10 11 */
-#define MIRQ 0 /* 5 7 9 10 0(default), 0 means disable */
-#define DMA 1 /* 0 1(default) 3 */
-
-/*
- * Commands of AEDSP16's DSP (SBPRO+special).
- * For now they are CMDn, in the future they may change.
- */
-#define CMD1 0xe3 /* Get DSP Copyright */
-#define CMD2 0xe1 /* Get DSP Version */
-#define CMD3 0x88 /* */
-#define CMD4 0x5c /* */
-#define CMD5 0x50 /* Set M&I&DRQ mask (the real config) */
-#define CMD6 0x8c /* Enable Microsoft Sound System mode */
-
-/*
- * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase
- * to have the actual I/O port.
- * Register permissions are:
- * (wo) == Write Only
- * (ro) == Read Only
- * (w-) == Write
- * (r-) == Read
- */
-#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */
-#define DSP_READ 0x0a /* offset of DSP READ (ro) */
-#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */
-#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */
-#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */
-#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */
-
-
-#define RETRY 10 /* Various retry values on I/O opera- */
-#define STATUSRETRY 1000 /* tions. Sometimes we have to */
-#define HARDRETRY 500000 /* wait for previous cmd to complete */
-
-/*
- * Size of character arrays that store name and version of sound card
- */
-#define CARDNAMELEN 15 /* Size of the card's name in chars */
-#define CARDVERLEN 2 /* Size of the card's version in chars */
-
-/*
- * Bit mapped flags for calling InitAEDSP16(), and saving the current
- * emulation mode.
- */
-#define INIT_NONE (0 )
-#define INIT_SBPRO (1<<0)
-#define INIT_MSS (1<<1)
-#define INIT_MPU401 (1<<2)
-#define RESET_DSP16 (1<<3)
-
-/* Base HW Port for Audio Card */
-static int portbase = AEDSP16_BASE;
-static int irq = IRQ; /* irq for DSP I/O */
-static int mirq = MIRQ; /* irq for MPU-401 I/O */
-static int dma = DMA; /* dma for DSP I/O */
-
-/* Init status of the card */
-static int ae_init = INIT_NONE; /* (bitmapped variable) */
-static int oredparams = 0; /* Will contain or'ed values of params */
-static int gc = 0; /* generic counter (utility counter) */
-struct orVals
- { /* Contain the values to be or'ed */
- int val; /* irq|mirq|dma */
- int or; /* oredparams |= TheStruct.or */
- };
-
-/*
- * Magic values that the DSP will eat when configuring irq/mirq/dma
- */
-/* DSP IRQ conversion array */
-static struct orVals orIRQ[] =
-{
- {0x05, 0x28},
- {0x07, 0x08},
- {0x09, 0x10},
- {0x0a, 0x18},
- {0x0b, 0x20},
- {0x00, 0x00}
-};
-
-/* MPU-401 IRQ conversion array */
-static struct orVals orMIRQ[] =
-{
- {0x05, 0x04},
- {0x07, 0x44},
- {0x09, 0x84},
- {0x0a, 0xc4},
- {0x00, 0x00}
-};
-
-/* DMA Channels conversion array */
-static struct orVals orDMA[] =
-{
- {0x00, 0x01},
- {0x01, 0x02},
- {0x03, 0x03},
- {0x00, 0x00}
-};
-
-/*
- * Buffers to store audio card informations
- */
-static char AudioExcelName[CARDNAMELEN + 1];
-static char AudioExcelVersion[CARDVERLEN + 1];
-
-static void
-tenmillisec (void)
-{
-
- for (gc = 0; gc < 1000; gc++)
- tenmicrosec ();
-}
-
-static int
-WaitForDataAvail (int port)
-{
- int loop = STATUSRETRY;
- unsigned char ret = 0;
-
- do
- {
- ret = INB (port + DSP_DATAVAIL);
- /*
- * Wait for data available (bit 7 of ret == 1)
- */
- }
- while (!(ret & 0x80) && loop--);
-
- if (ret & 0x80)
- return 0;
-
- return -1;
-}
-
-static int
-ReadData (int port)
-{
- if (WaitForDataAvail (port))
- return -1;
- return INB (port + DSP_READ);
-}
-
-static int
-CheckDSPOkay (int port)
-{
- return ((ReadData (port) == 0xaa) ? 0 : -1);
-}
-
-static int
-ResetBoard (int port)
-{
- /*
- * Reset DSP
- */
- OUTB (1, (port + DSP_RESET));
- tenmicrosec ();
- OUTB (0, (port + DSP_RESET));
- tenmicrosec ();
- tenmicrosec ();
- return CheckDSPOkay (port);
-}
-
-static int
-WriteDSPCommand (int port, int cmd)
-{
- unsigned char ret;
- int loop = HARDRETRY;
-
- do
- {
- ret = INB (port + DSP_STATUS);
- /*
- * DSP ready to receive data if bit 7 of ret == 0
- */
- if (!(ret & 0x80))
- {
- OUTB (cmd, port + DSP_COMMAND);
- return 0;
- }
- }
- while (loop--);
-
- printk ("[aedsp16] DSP Command (0x%x) timeout.\n", cmd);
- return -1;
-}
-
-int
-InitMSS (int port)
-{
-
- tenmillisec ();
-
- if (WriteDSPCommand (port, CMD6))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD6);
- return -1;
- }
-
- tenmillisec ();
-
- return 0;
-}
-
-static int
-SetUpBoard (int port)
-{
- int loop = RETRY;
-
- do
- {
- if (WriteDSPCommand (portbase, CMD3))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD3);
- return -1;
- }
-
- tenmillisec ();
-
- }
- while (WaitForDataAvail (port) && loop--);
-
-#if defined(THIS_SHOULD_GO_AWAY)
- if (CheckDSPOkay (port))
- {
- printk ("[aedsp16] CheckDSPOkay: failed\n");
- return -1;
- }
-#else
- if (ReadData (port) == -1)
- {
- printk ("[aedsp16] ReadData after CMD 0x%x: failed\n", CMD3);
- return -1;
- }
-#endif
-
- if (WriteDSPCommand (portbase, CMD4))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD4);
- return -1;
- }
-
- if (WriteDSPCommand (portbase, CMD5))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD5);
- return -1;
- }
-
- if (WriteDSPCommand (portbase, oredparams))
- {
- printk ("[aedsp16] Initialization of (M)IRQ and DMA: failed!\n");
- return -1;
- }
- return 0;
-}
-
-static int
-GetCardVersion (int port)
-{
- int len = 0;
- int ret;
- int ver[3];
-
- do
- {
- if ((ret = ReadData (port)) == -1)
- return -1;
- /*
- * We alredy know how many int are stored (2), so we know when the
- * string is finished.
- */
- ver[len++] = ret;
- }
- while (len < CARDVERLEN);
- sprintf (AudioExcelVersion, "%d.%d", ver[0], ver[1]);
- return 0;
-}
-
-static int
-GetCardName (int port)
-{
- int len = 0;
- int ret;
-
- do
- {
- if ((ret = ReadData (port)) == -1)
- /*
- * If no more data availabe, return to the caller, no error if len>0.
- * We have no other way to know when the string is finished.
- */
- return (len ? 0 : -1);
-
- AudioExcelName[len++] = ret;
-
- }
- while (len < CARDNAMELEN);
- return 0;
-}
-
-static void
-InitializeHardParams (void)
-{
-
- memset (AudioExcelName, 0, CARDNAMELEN + 1);
- memset (AudioExcelVersion, 0, CARDVERLEN + 1);
-
- for (gc = 0; orIRQ[gc].or; gc++)
- if (orIRQ[gc].val == irq)
- oredparams |= orIRQ[gc].or;
-
- for (gc = 0; orMIRQ[gc].or; gc++)
- if (orMIRQ[gc].or == mirq)
- oredparams |= orMIRQ[gc].or;
-
- for (gc = 0; orDMA[gc].or; gc++)
- if (orDMA[gc].val == dma)
- oredparams |= orDMA[gc].or;
-}
-
-static int
-InitAEDSP16 (int which)
-{
- static char *InitName = NULL;
-
- InitializeHardParams ();
-
- if (ResetBoard (portbase))
- {
- printk ("[aedsp16] ResetBoard: failed!\n");
- return -1;
- }
-
-#if defined(THIS_SHOULD_GO_AWAY)
- if (CheckDSPOkay (portbase))
- {
- printk ("[aedsp16] CheckDSPOkay: failed!\n");
- return -1;
- }
-#endif
-
- if (WriteDSPCommand (portbase, CMD1))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD1);
- return -1;
- }
-
- if (GetCardName (portbase))
- {
- printk ("[aedsp16] GetCardName: failed!\n");
- return -1;
- }
-
- /*
- * My AEDSP16 card return SC-6000 in AudioExcelName, so
- * if we have something different, we have to be warned.
- */
- if (strcmp ("SC-6000", AudioExcelName))
- printk ("[aedsp16] Warning: non SC-6000 audio card!\n");
-
- if (WriteDSPCommand (portbase, CMD2))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD2);
- return -1;
- }
-
- if (GetCardVersion (portbase))
- {
- printk ("[aedsp16] GetCardVersion: failed!\n");
- return -1;
- }
-
- if (SetUpBoard (portbase))
- {
- printk ("[aedsp16] SetUpBoard: failed!\n");
- return -1;
- }
-
- if (which == INIT_MSS)
- {
- if (InitMSS (portbase))
- {
- printk ("[aedsp16] Can't initialize Microsoft Sound System mode.\n");
- return -1;
- }
- }
-
- /*
- * If we are resetting, do not print any message because we may be
- * in playing and we do not want lost too much time.
- */
- if (!(which & RESET_DSP16))
- {
- if (which & INIT_MPU401)
- InitName = "MPU401";
- else if (which & INIT_SBPRO)
- InitName = "SBPro";
- else if (which & INIT_MSS)
- InitName = "MSS";
- else
- InitName = "None";
-
- printk ("Audio Excel DSP 16 init v%s (%s %s) [%s]\n",
- VERSION, AudioExcelName,
- AudioExcelVersion, InitName);
- }
-
- tenmillisec ();
-
- return 0;
-}
-
-#if defined(AEDSP16_SBPRO)
-
-int
-InitAEDSP16_SBPRO (struct address_info *hw_config)
-{
- /*
- * If the card is alredy init'ed MSS, we can not init it to SBPRO too
- * because the board can not emulate simultaneously MSS and SBPRO.
- */
- if (ae_init & INIT_MSS)
- return -1;
- if (ae_init & INIT_SBPRO)
- return 0;
-
- /*
- * For now we will leave this
- * code included only when INCLUDE_AEDSP16 is configured in, but it should
- * be better include it every time.
- */
- if (!(ae_init & INIT_MPU401))
- {
- if (check_region (hw_config->io_base, 0x0f))
- {
- printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n");
- return -1;
- }
- }
-
- /*
- * Set up the internal hardware parameters, to let the driver reach
- * the Sound Card.
- */
- portbase = hw_config->io_base;
- irq = hw_config->irq;
- dma = hw_config->dma;
- if (InitAEDSP16 (INIT_SBPRO))
- return -1;
-
- if (!(ae_init & INIT_MPU401))
- request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)");
-
- ae_init |= INIT_SBPRO;
- return 0;
-}
-
-#endif /* AEDSP16_SBPRO */
-
-#if defined(AEDSP16_MSS)
-
-int
-InitAEDSP16_MSS (struct address_info *hw_config)
-{
- /*
- * If the card is alredy init'ed SBPRO, we can not init it to MSS too
- * because the board can not emulate simultaneously MSS and SBPRO.
- */
- if (ae_init & INIT_SBPRO)
- return -1;
- if (ae_init & INIT_MSS)
- return 0;
-
- /*
- * For now we will leave this
- * code included only when INCLUDE_AEDSP16 is configured in, but it should
- * be better include it every time.
- */
- if (check_region (hw_config->io_base, 0x08))
- {
- printk ("MSS I/O port region is alredy in use.\n");
- return -1;
- }
-
- /*
- * We must allocate the AEDSP16 region too because these are the I/O ports
- * to access card's control registers.
- */
- if (!(ae_init & INIT_MPU401))
- {
- if (check_region (AEDSP16_BASE, 0x0f))
- {
- printk ("AEDSP16 I/O port region is alredy in use.\n");
- return -1;
- }
- }
-
-
- /*
- * If we are configuring the card for MSS, the portbase for card configuration
- * is the default one (0x220 unless you have changed the factory default
- * with board switches), so no need to modify the portbase variable.
- * The default is AEDSP16_BASE, that is the right value.
- */
- irq = hw_config->irq;
- dma = hw_config->dma;
- if (InitAEDSP16 (INIT_MSS))
- return -1;
-
- request_region (hw_config->io_base, 0x08, "aedsp16 (mss)");
-
- if (!(ae_init & INIT_MPU401))
- request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
-
- ae_init |= INIT_MSS;
- return 0;
-}
-
-#endif /* AEDSP16_MSS */
-
-#if defined(AEDSP16_MPU401)
-
-int
-InitAEDSP16_MPU401 (struct address_info *hw_config)
-{
- if (ae_init & INIT_MPU401)
- return 0;
-
- /*
- * For now we will leave this
- * code included only when INCLUDE_AEDSP16 is configured in, but it should
- * be better include it every time.
- */
- if (check_region (hw_config->io_base, 0x02))
- {
- printk ("SB I/O port region is alredy in use.\n");
- return -1;
- }
-
- /*
- * We must allocate the AEDSP16 region too because these are the I/O ports
- * to access card's control registers.
- */
- if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
- {
- if (check_region (AEDSP16_BASE, 0x0f))
- {
- printk ("AEDSP16 I/O port region is alredy in use.\n");
- return -1;
- }
- }
-
- /*
- * If mpu401, the irq and dma are not important, do not touch it
- * because we may use the default if sbpro is not yet configured,
- * we may use the sbpro ones if configured, and nothing wrong
- * should happen.
- *
- * The mirq default is 0, but once set it to non-0 value, we should
- * not touch it anymore (unless I write an ioctl to do it, of course).
- */
- mirq = hw_config->irq;
- if (InitAEDSP16 (INIT_MPU401))
- return -1;
-
- request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)");
-
- if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
- request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
-
- ae_init |= INIT_MPU401;
- return 0;
-}
-
-#endif /* AEDSP16_MPU401 */
-
-#if 0 /* Leave it out for now. We are not using this portion of code. */
-
-/*
- * Entry point for a reset function.
- * May be I will write the infamous ioctl :)
- */
-int
-ResetAEDSP16 (void)
-{
-#if defined(AEDSP16_DEBUG)
- printk ("[aedsp16] ResetAEDSP16 called.\n");
-#endif
- return InitAEDSP16 (RESET_DSP16);
-}
-
-#endif /* 0 */
-
-#endif /* !EXCLUDE_AEDSP16 */
diff --git a/sys/i386/isa/sound/audio.c b/sys/i386/isa/sound/audio.c
index d5a4acce44e3..a48524800d40 100644
--- a/sys/i386/isa/sound/audio.c
+++ b/sys/i386/isa/sound/audio.c
@@ -1,10 +1,10 @@
/*
* sound/audio.c
- *
+ *
* Device file manager for /dev/audio
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,27 +24,30 @@
* 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"
+#include <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
-#include "ulaw.h"
+#include <i386/isa/sound/ulaw.h>
+#include <i386/isa/sound/coproc.h>
#define ON 1
#define OFF 0
+int
+DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait);
-static int wr_buff_no[MAX_AUDIO_DEV]; /*
- * != -1, if there is
- * a incomplete output
- * block in the queue.
- */
+int
+audio_poll(int dev, struct fileinfo * file, int events, select_table * wait);
+
+static int wr_buff_no[MAX_AUDIO_DEV];
+ /* != -1, if there is a incomplete output block in the queue. */
static int wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
static int audio_mode[MAX_AUDIO_DEV];
+static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in noblocking mode */
#define AM_NONE 0
#define AM_WRITE 1
@@ -54,371 +57,413 @@ static char *wr_dma_buf[MAX_AUDIO_DEV];
static int audio_format[MAX_AUDIO_DEV];
static int local_conversion[MAX_AUDIO_DEV];
+#if defined(NO_INLINE_ASM) || !defined(i386)
+static void
+translate_bytes(const u_char *table, u_char *buff, int n);
+
+#else
+extern inline void
+translate_bytes(const void *table, void *buff, int n);
+#endif
+
static int
-set_format (int dev, int fmt)
+set_format(int dev, int fmt)
{
- if (fmt != AFMT_QUERY)
- {
+ if (fmt != AFMT_QUERY) {
- local_conversion[dev] = 0;
+ local_conversion[dev] = 0;
- if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */
- if (fmt == AFMT_MU_LAW)
- {
- fmt = AFMT_U8;
- local_conversion[dev] = AFMT_MU_LAW;
- }
- else
- fmt = AFMT_U8; /* This is always supported */
+ if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */
+ if (fmt == AFMT_MU_LAW) {
+ fmt = AFMT_U8;
+ local_conversion[dev] = AFMT_MU_LAW;
+ } else
+ fmt = AFMT_U8; /* This is always supported */
- audio_format[dev] = DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, fmt, 1);
+ audio_format[dev] = DMAbuf_ioctl(dev, SNDCTL_DSP_SETFMT,
+ (ioctl_arg) fmt, 1);
}
+ if (local_conversion[dev]) /* This shadows the HW format */
+ return local_conversion[dev];
- if (local_conversion[dev]) /* This shadows the HW format */
- return local_conversion[dev];
-
- return audio_format[dev];
+ return audio_format[dev];
}
int
-audio_open (int dev, struct fileinfo *file)
+audio_open(int dev, struct fileinfo * file)
{
- int ret;
- int bits;
- int dev_type = dev & 0x0f;
- int mode = file->mode & O_ACCMODE;
+ int ret;
+ int bits;
+ int dev_type = dev & 0x0f;
+ int mode = file->mode & O_ACCMODE;
- dev = dev >> 4;
+ dev = dev >> 4;
- if (dev_type == SND_DEV_DSP16)
- bits = 16;
- else
- bits = 8;
+ bits = (dev_type == SND_DEV_DSP16) ? 16 : 8 ;
- if ((ret = DMAbuf_open (dev, mode)) < 0)
- return ret;
+ if ((ret = DMAbuf_open(dev, mode)) < 0)
+ return ret;
- local_conversion[dev] = 0;
+ if (audio_devs[dev]->coproc)
+ if ((ret = audio_devs[dev]->coproc->
+ open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) {
+ audio_release(dev, file);
+ printf("Sound: Can't access coprocessor device\n");
- if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
- {
- audio_release (dev, file);
- return RET_ERROR (ENXIO);
- }
+ return ret;
+ }
+ local_conversion[dev] = 0;
- if (dev_type == SND_DEV_AUDIO)
- {
- set_format (dev, AFMT_MU_LAW);
+ if (DMAbuf_ioctl(dev, SNDCTL_DSP_SETFMT, (ioctl_arg) bits, 1) != bits) {
+ audio_release(dev, file);
+ return -(ENXIO);
}
- else
- set_format (dev, bits);
- wr_buff_no[dev] = -1;
- audio_mode[dev] = AM_NONE;
+ set_format(dev, (dev_type == SND_DEV_AUDIO) ? AFMT_MU_LAW : bits ) ;
+
+ wr_buff_no[dev] = -1;
+ audio_mode[dev] = AM_NONE;
+ wr_buff_size[dev] = wr_buff_ptr[dev] = 0;
+ dev_nblock[dev] = 0;
- return ret;
+ return ret;
}
void
-audio_release (int dev, struct fileinfo *file)
+audio_release(int dev, struct fileinfo * file)
{
- int mode;
+ int mode;
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ wr_buff_no[dev] = -1;
}
+ if (audio_devs[dev]->coproc)
+ audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc,COPR_PCM);
+ DMAbuf_release(dev, mode);
+ audio_devs[dev]->dmap_out->mapping_flags &= ~DMA_MAP_MAPPED ;
- DMAbuf_release (dev, mode);
}
-#ifdef NO_INLINE_ASM
+#if defined(NO_INLINE_ASM) || !defined(i386)
static void
-translate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n)
+translate_bytes(const u_char *table, u_char *buff, int n)
{
- unsigned long i;
+ u_long i;
+
+ if (n <= 0)
+ return;
- for (i = 0; i < n; ++i)
- buff[i] = table[buff[i]];
+ for (i = 0; i < n; ++i)
+ buff[i] = table[buff[i]];
}
#else
extern inline void
-translate_bytes (const void *table, void *buff, unsigned long n)
+translate_bytes(const void *table, void *buff, int n)
{
- __asm__ ("cld\n"
- "1:\tlodsb\n\t"
- "xlatb\n\t"
- "stosb\n\t"
- "loop 1b\n\t":
- :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
- :"bx", "cx", "di", "si", "ax");
+ if (n > 0) {
+ __asm__("cld\n"
+ "1:\tlodsb\n\t"
+ "xlatb\n\t"
+ "stosb\n\t"
+ "loop 1b\n\t":
+ :"b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
+ :"bx", "cx", "di", "si", "ax");
+ }
}
#endif
int
-audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+audio_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
{
- int c, p, l;
- int err;
+ int c, p, l;
+ int err;
- dev = dev >> 4;
+ dev = dev >> 4;
- p = 0;
- c = count;
+ p = 0;
+ c = count;
- if (audio_mode[dev] == AM_READ) /*
- * Direction changed
- */
- {
- wr_buff_no[dev] = -1;
+ if ((audio_mode[dev] & AM_READ) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX)) { /* Direction change */
+ wr_buff_no[dev] = -1;
+ }
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_mode[dev] |= AM_WRITE;
+ else
+ audio_mode[dev] = AM_WRITE;
+
+ if (!count) { /* Flush output */
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_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],
+ dev_nblock[dev])) < 0) {
+ /* Handle nonblocking mode */
+ if (dev_nblock[dev] && wr_buff_no[dev] == -(EAGAIN))
+ return p; /* No more space. Return # of accepted bytes */
+ return wr_buff_no[dev];
+ }
+ wr_buff_ptr[dev] = 0;
+ }
+ l = c;
+ if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
+ l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
- audio_mode[dev] = AM_WRITE;
+ if (!audio_devs[dev]->copy_from_user) { /* No device specific
+ * copy routine */
- if (!count) /*
- * Flush output
- */
- {
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ if (uiomove(&wr_dma_buf[dev][wr_buff_ptr[dev]], l, buf)) {
+ printf("sb: Bad copyin()!\n");
+ };
+ } else
+ audio_devs[dev]->copy_from_user(dev,
+ wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
- 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];
+ /*
+ * Insert local processing here
+ */
+
+ if (local_conversion[dev] == AFMT_MU_LAW) {
+ translate_bytes(ulaw_dsp,
+ (u_char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ }
+ c -= l;
+ p += l;
+ wr_buff_ptr[dev] += l;
+
+ if (wr_buff_ptr[dev] >= wr_buff_size[dev]) {
+ if ((err = DMAbuf_start_output(dev, wr_buff_no[dev],
+ wr_buff_ptr[dev])) < 0) {
+ return err;
}
- wr_buff_ptr[dev] = 0;
+ wr_buff_no[dev] = -1;
}
+ }
- l = c;
- if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
- l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
+ return count;
+}
- if (!audio_devs[dev]->copy_from_user)
- { /*
- * No device specific copy routine
- */
- COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
+int
+audio_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;
+ if ((audio_mode[dev] & AM_WRITE) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX)) {
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX))
+ wr_buff_no[dev] = -1;
}
- else
- audio_devs[dev]->copy_from_user (dev,
- wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
-
-
- /*
- * Insert local processing here
- */
-
- if (local_conversion[dev] == AFMT_MU_LAW)
- {
-#ifdef linux
- /*
- * This just allows interrupts while the conversion is running
- */
- __asm__ ("sti");
-#endif
- translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ }
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_mode[dev] |= AM_READ;
+ else
+ audio_mode[dev] = AM_READ;
+
+ while (c) {
+ if ((buff_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
+ dev_nblock[dev])) < 0) {
+ /*
+ * Nonblocking mode handling. Return current # of bytes
+ */
+
+ if (dev_nblock[dev] && buff_no == -(EAGAIN))
+ return p;
+
+ return buff_no;
}
+ if (l > c)
+ l = c;
- c -= l;
- p += l;
- wr_buff_ptr[dev] += l;
+ /*
+ * Insert any local processing here.
+ */
- if (wr_buff_ptr[dev] >= wr_buff_size[dev])
- {
- if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
- {
- return err;
- }
-
- wr_buff_no[dev] = -1;
+ if (local_conversion[dev] == AFMT_MU_LAW) {
+ translate_bytes(dsp_ulaw, (u_char *) dmabuf, l);
}
+ if (uiomove(dmabuf, l, buf)) {
+ printf("sb: Bad copyout()!\n");
+ };
- }
+ DMAbuf_rmchars(dev, buff_no, l);
- return count;
+ p += l;
+ c -= l;
+ }
+ return count - c;
}
int
-audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+audio_ioctl(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg)
{
- int c, p, l;
- char *dmabuf;
- int buff_no;
+ dev = dev >> 4;
+ if (((cmd >> 8) & 0xff) == 'C') {
+ if (audio_devs[dev]->coproc) /* Coprocessor ioctl */
+ return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
+ else
+ printf("/dev/dsp%d: No coprocessor for this device\n", dev);
- dev = dev >> 4;
- p = 0;
- c = count;
+ return -(ENXIO);
+ } else
+ switch (cmd) {
- if (audio_mode[dev] == AM_WRITE)
- {
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ case SNDCTL_DSP_SYNC:
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ wr_buff_no[dev] = -1;
+ }
+ return DMAbuf_ioctl(dev, cmd, arg, 0);
+ break;
- wr_buff_no[dev] = -1;
- }
- }
+ case SNDCTL_DSP_POST:
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ wr_buff_no[dev] = -1;
+ }
+ return 0;
+ break;
- audio_mode[dev] = AM_READ;
+ case SNDCTL_DSP_RESET:
+ wr_buff_no[dev] = -1;
+ audio_mode[dev] = AM_NONE;
+ return DMAbuf_ioctl(dev, cmd, arg, 0);
+ break;
- while (c)
- {
- if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
- return buff_no;
+ case SNDCTL_DSP_GETFMTS:
+ return *(int *) arg = audio_devs[dev]->format_mask;
+ break;
- if (l > c)
- l = c;
+ case SNDCTL_DSP_SETFMT:
+ return *(int *) arg = set_format(dev, (*(int *) arg));
- /*
- * Insert any local processing here.
- */
-
- if (local_conversion[dev] == AFMT_MU_LAW)
- {
-#ifdef linux
- /*
- * This just allows interrupts while the conversion is running
- */
- __asm__ ("sti");
-#endif
+ case SNDCTL_DSP_GETISPACE:
+ if ((audio_mode[dev] & AM_WRITE) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return -(EBUSY);
- translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
- }
+ else {
+ audio_buf_info info;
+ int err = DMAbuf_ioctl(dev, cmd, (ioctl_arg) & info, 1);
- COPY_TO_USER (buf, p, dmabuf, l);
+ if (err < 0)
+ return err;
- DMAbuf_rmchars (dev, buff_no, l);
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+ return 0;
+ }
- p += l;
- c -= l;
- }
+ case SNDCTL_DSP_GETOSPACE:
+ if ((audio_mode[dev] & AM_READ) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return -(EBUSY);
+ else {
+ audio_buf_info info;
+ int err = DMAbuf_ioctl(dev, cmd, (ioctl_arg) & info, 1);
- return count - c;
-}
+ if (err < 0)
+ return err;
-int
-audio_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
-{
+ if (wr_buff_no[dev] != -1)
+ info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev];
- dev = dev >> 4;
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+ return 0;
+ }
- switch (cmd)
- {
- case SNDCTL_DSP_SYNC:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ case SNDCTL_DSP_NONBLOCK:
+ dev_nblock[dev] = 1;
+ return 0;
+ break;
- wr_buff_no[dev] = -1;
- }
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
+ case SNDCTL_DSP_GETCAPS:
+ {
+ int info = 1; /* Revision level of this ioctl() */
- case SNDCTL_DSP_POST:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ info |= DSP_CAP_DUPLEX;
- wr_buff_no[dev] = -1;
- }
- return 0;
- break;
+ if (audio_devs[dev]->coproc)
+ info |= DSP_CAP_COPROC;
- case SNDCTL_DSP_RESET:
- wr_buff_no[dev] = -1;
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
+ if (audio_devs[dev]->local_qlen) /* Dev. has hidden buffs */
+ info |= DSP_CAP_BATCH;
- case SNDCTL_DSP_GETFMTS:
- return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
- break;
+ if (audio_devs[dev]->trigger) /* Supports SETTRIGGER */
+ info |= DSP_CAP_TRIGGER;
- case SNDCTL_DSP_SETFMT:
- return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
+ info |= DSP_CAP_MMAP;
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+ return 0;
+ }
+ break;
- default:
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
- }
-}
-long
-audio_init (long mem_start)
-{
- /*
- * NOTE! This routine could be called several times during boot.
- */
- return mem_start;
+ case FIOASYNC:
+ return *(int *) arg = 1;
+
+ case FIONBIO:
+ return *(int *) arg = 1;
+
+ default:
+ return DMAbuf_ioctl(dev, cmd, arg, 0);
+ }
}
-#else
+#ifdef ALLOW_POLL
/*
- * Stub versions
+ * XXX should we use spltty() in the select calls ? - lr970714
+ *
*/
int
-audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+audio_poll(int dev, struct fileinfo * file, int events, select_table * wait)
{
- return RET_ERROR (EIO);
-}
+ dev = dev >> 4;
-int
-audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- return RET_ERROR (EIO);
-}
+ if (events & (POLLOUT | POLLWRNORM)) {
+ if ((audio_mode[dev] & AM_WRITE) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return 0; /* Not recording */
-int
-audio_open (int dev, struct fileinfo *file)
-{
- 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)
-{
- return RET_ERROR (EIO);
-}
+ return (DMAbuf_poll(dev, file, events, wait));
+ }
-int
-audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
-{
- return RET_ERROR (EIO);
-}
+ if (events & (POLLIN | POLLRDNORM)) {
+ if ((audio_mode[dev] & AM_READ) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return 0; /* Wrong direction */
-long
-audio_init (long mem_start)
-{
- return mem_start;
-}
+ if (wr_buff_no[dev] != -1)
+ return 1; /* There is space in the current buffer */
-#endif
+ return ( DMAbuf_poll(dev, file, events, wait) );
+
+ }
+ return 0;
+}
+#endif /* ALLOW_POLL */
#endif
diff --git a/sys/i386/isa/sound/awe_wave.c b/sys/i386/isa/sound/awe_wave.c
index 47818165a9e4..dec20b2e41bc 100644
--- a/sys/i386/isa/sound/awe_wave.c
+++ b/sys/i386/isa/sound/awe_wave.c
@@ -31,8 +31,8 @@
/* if you're using obsolete VoxWare 3.0.x on Linux 1.2.x (or FreeBSD),
* uncomment the following line
*/
-#define AWE_OBSOLETE_VOXWARE
+#define AWE_OBSOLETE_VOXWARE
#ifdef AWE_OBSOLETE_VOXWARE
@@ -88,9 +88,6 @@
#include <i386/isa/sound/awe_voice.h>
#ifdef AWE_OBSOLETE_VOXWARE
-#ifdef __FreeBSD__
-#define SEQUENCER_C
-#endif
#include <i386/isa/sound/tuning.h>
#else
#include "../tuning.h"
@@ -333,11 +330,25 @@ static void awe_set_reverb_mode(int mode);
#define awe_request_region() /* nothing */
#define awe_release_region() /* nothing */
+#ifdef __FreeBSD__
+# ifndef PERMANENT_MALLOC
+# define PERMANENT_MALLOC(typecast, mem_ptr, size) \
+ {mem_ptr = (typecast)malloc(size, M_DEVBUF, M_NOWAIT); \
+ if (!mem_ptr)panic("SOUND: Cannot allocate memory\n");}
+# endif
+# ifndef printk
+# define printk printf
+# endif
+# ifndef RET_ERROR
+# define RET_ERROR(err) -(err)
+# endif
+#endif
+
#else /* AWE_OBSOLETE_VOXWARE */
/* the following macros are osbolete */
-#define PERMANENT_MALLOC(type,var,size,memptr) \
+#define PERMANENT_MALLOC(type,var,size) \
var = (type)(sound_mem_blocks[sound_nblocks++] = vmalloc(size))
#define RET_ERROR(err) -err
@@ -431,8 +442,8 @@ static struct synth_operations awe_operations =
* attach / unload interface
*================================================================*/
-#ifdef AWE_OBSOLETE_VOXWARE
-long attach_awe_obsolete(long mem_start, struct address_info *hw_config)
+#if defined(AWE_OBSOLETE_VOXWARE) || defined(__FreeBSD__)
+void attach_awe_obsolete(struct address_info *hw_config)
#else
int attach_awe(void)
#endif
@@ -440,23 +451,23 @@ int attach_awe(void)
/* check presence of AWE32 card */
if (! awe_detect()) {
printk("AWE32: not detected\n");
- return 0;
+ return ;
}
/* check AWE32 ports are available */
if (awe_check_port()) {
printk("AWE32: I/O area already used.\n");
- return 0;
+ return ;
}
/* allocate sample tables */
PERMANENT_MALLOC(awe_sample_info *, samples,
- AWE_MAX_SAMPLES * sizeof(awe_sample_info), mem_start);
+ AWE_MAX_SAMPLES * sizeof(awe_sample_info) );
PERMANENT_MALLOC(awe_voice_list *, infos,
- AWE_MAX_INFOS * sizeof(awe_voice_list), mem_start);
+ AWE_MAX_INFOS * sizeof(awe_voice_list) );
if (samples == NULL || infos == NULL) {
printk("AWE32: can't allocate sample tables\n");
- return 0;
+ return ;
}
if (num_synths >= MAX_SYNTH_DEV)
@@ -488,29 +499,19 @@ int attach_awe(void)
awe_present = 1;
#ifdef AWE_OBSOLETE_VOXWARE
- return mem_start;
+ return ;
#else
return 1;
#endif
}
-
-void unload_awe(void)
-{
- if (awe_present) {
- awe_reset_samples();
- awe_release_region();
- }
-}
-
-
#ifdef AWE_OBSOLETE_VOXWARE
-int probe_awe_obsolete(struct address_info *hw_config)
+int
+probe_awe_obsolete(struct address_info *hw_config)
{
return 1;
/*return awe_detect();*/
}
-
#endif
/*================================================================
diff --git a/sys/i386/isa/sound/dev_table.c b/sys/i386/isa/sound/dev_table.c
index 1eb57bbb08c1..42e5197b2c46 100644
--- a/sys/i386/isa/sound/dev_table.c
+++ b/sys/i386/isa/sound/dev_table.c
@@ -1,10 +1,10 @@
/*
* sound/dev_table.c
- *
+ *
* Device call tables.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,246 +24,280 @@
* 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_
-#include "sound_config.h"
+#include <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
+#if NSND > 0
+
+int sound_started = 0;
+
+int sndtable_get_cardcount(void);
+int snd_find_driver(int type);
+void sndtable_init(void);
+int sndtable_probe(int unit, struct address_info * hw_config);
+int sndtable_init_card(int unit, struct address_info * hw_config);
+int sndtable_identify_card(char *name);
+void sound_chconf(int card_type, int ioaddr, int irq, int dma);
+static void start_services(void);
+static void start_cards(void);
+struct address_info *sound_getconf(int card_type);
int
-snd_find_driver (int type)
+snd_find_driver(int type)
{
- int i, n = sizeof (sound_drivers) / sizeof (struct driver_info);
+ int i, n = num_sound_drivers;
- for (i = 0; i < (n - 1); i++)
- if (sound_drivers[i].card_type == type)
- return i;
+ for (i = 0; i < n; i++)
+ if (sound_drivers[i].card_type == type)
+ return i;
- return -1; /*
- * Not found
- */
+ return -1;
}
-long
-sndtable_init (long mem_start)
+static void
+start_services()
{
- int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
- int drv;
-
- for (i = 0; i < (n - 1); i++)
- if (snd_installed_cards[i].enabled)
- if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
- snd_installed_cards[i].enabled = 0; /*
- * Mark as not detected
- */
- else if (sound_drivers[drv].probe (&snd_installed_cards[i].config))
- {
-#ifndef SHORT_BANNERS
- printk ("snd%d",
- snd_installed_cards[i].card_type);
+ int soundcards_installed;
+
+ if (!(soundcards_installed = sndtable_get_cardcount()))
+ return ; /* No cards detected */
+
+#ifdef CONFIG_AUDIO
+ if (num_audiodevs) /* Audio devices present */
+ DMAbuf_init();
#endif
- mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config);
-#ifndef SHORT_BANNERS
- printk (" at 0x%x irq %d drq %d\n",
- snd_installed_cards[i].config.io_base,
- snd_installed_cards[i].config.irq,
- snd_installed_cards[i].config.dma);
+#ifdef CONFIG_MIDI
+ if (num_midis)
+ /* MIDIbuf_init(0) */;
#endif
+
+#ifdef CONFIG_SEQUENCER
+ if (num_midis + num_synths)
+ sequencer_init();
+#endif
+}
+
+static void
+start_cards()
+{
+ int drv, i, n = num_sound_cards;
+ struct card_info *ci = snd_installed_cards ;
+
+ sound_started = 1;
+ if (trace_init)
+ printf("Sound initialization started\n");
+
+ /*
+ * Check the number of cards actually defined in the table
+ */
+
+ for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
+ num_sound_cards = i + 1;
+
+ for (i = 0; i < n && ci->card_type; ci++, i++)
+ if (ci->enabled) {
+ if ((drv = snd_find_driver(ci->card_type)) == -1) {
+ ci->enabled = 0; /* Mark as not detected */
+ continue;
+ }
+ ci->config.card_subtype = sound_drivers[drv].card_subtype;
+
+ if (sound_drivers[drv].probe(&(ci->config)))
+ sound_drivers[drv].attach(&(ci->config));
+ else
+ ci->enabled = 0; /* Mark as not detected */
}
- else
- snd_installed_cards[i].enabled = 0; /*
- * Mark as not detected
- */
- return mem_start;
+ if (trace_init)
+ printf("Sound initialization complete\n");
}
+void
+sndtable_init()
+{
+ start_cards();
+}
+
+/*
+ * sndtable_probe probes a specific device. unit is the voxware unit number.
+ */
+
int
-sndtable_probe (int unit, struct address_info *hw_config)
- {
- int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+sndtable_probe(int unit, struct address_info * hw_config)
+{
+ int i, sel = -1, n = num_sound_cards;
+ struct card_info *ci = snd_installed_cards ;
+
+ DDB(printf("-- sndtable_probe(%d)\n", unit));
+
+ /*
+ * for some reason unit 0 always succeeds ?
+ */
if (!unit)
- return TRUE;
+ return TRUE;
- for (i = 0; i < (n - 1); i++)
- if (snd_installed_cards[i].enabled)
- if (snd_installed_cards[i].card_type == unit)
- {
- int drv;
+ sound_started = 1;
- snd_installed_cards[i].config.io_base = hw_config->io_base;
- snd_installed_cards[i].config.irq = hw_config->irq;
- snd_installed_cards[i].config.dma = hw_config->dma;
- if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
- snd_installed_cards[i].enabled = 0; /*
- * Mark as not
- * detected
- */
- else if (sound_drivers[drv].probe (hw_config))
- return 1;
- snd_installed_cards[i].enabled = 0; /*
- * Mark as not detected
- */
- return 0;
- }
+ for (i=0; i<n && sel== -1 && ci->card_type; ci++, i++)
+ if ( (ci->enabled) && (ci->card_type == unit) ) {
+ /* DDB(printf("-- found card %d\n", i) ); */
+ sel = i; /* and break */
+ }
- return FALSE;
- }
+ /*
+ * not found. Creates a new entry in the table for this unit.
+ */
+ if (sel == -1 && num_sound_cards < max_sound_cards) {
+ int i;
-int
-sndtable_init_card (int unit, struct address_info *hw_config)
- {
- int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+ i = sel = (num_sound_cards++);
+ DDB(printf("-- installing card %d\n", i) );
- if (!unit)
- {
- if (sndtable_init (0) != 0)
- panic ("snd: Invalid memory allocation\n");
- return TRUE;
- }
-
- for (i = 0; i < (n - 1); i++)
- if (snd_installed_cards[i].card_type == unit)
- {
- int drv;
-
- snd_installed_cards[i].config.io_base = hw_config->io_base;
- snd_installed_cards[i].config.irq = hw_config->irq;
- snd_installed_cards[i].config.dma = hw_config->dma;
-
- if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
- snd_installed_cards[i].enabled = 0; /*
- * Mark as not detected
- */
- else if (sound_drivers[drv].attach (0, hw_config) != 0)
- panic ("snd#: Invalid memory allocation\n");
- return TRUE;
+ ci = &snd_installed_cards[sel] ;
+ ci->card_type = unit;
+ ci->enabled = 1;
+ }
+ /* DDB(printf("-- installed card %d\n", sel) ); */
+ if (sel != -1) {
+ int drv;
+
+ ci->config.io_base = hw_config->io_base;
+ ci->config.irq = hw_config->irq;
+ ci->config.dma = hw_config->dma;
+ ci->config.dma2 = hw_config->dma2;
+ ci->config.name = hw_config->name;
+ ci->config.always_detect = hw_config->always_detect;
+ ci->config.card_subtype = hw_config->card_subtype;
+ ci->config.osp = hw_config->osp;
+
+ if ((drv = snd_find_driver(ci->card_type)) == -1) {
+ ci->enabled = 0;
+ DDB(printf("Failed to find driver\n"));
+ return FALSE;
}
+ DDB(printf("-- Driver name '%s' probe 0x%08x\n",
+ sound_drivers[drv].name, sound_drivers[drv].probe));
- return FALSE;
- }
+ hw_config->card_subtype =
+ ci->config.card_subtype = sound_drivers[drv].card_subtype;
-int
-sndtable_get_cardcount (void)
-{
- return num_audiodevs + num_mixers + num_synths + num_midis;
+ if (sound_drivers[drv].probe(hw_config)) {
+ DDB(printf("-- Hardware probed OK\n"));
+ return TRUE;
+ }
+ DDB(printf("-- Failed to find hardware\n"));
+ ci->enabled = 0; /* mark as not detected */
+ return FALSE;
+ }
+ return FALSE;
}
-#ifdef linux
-void
-sound_setup (char *str, int *ints)
+int
+sndtable_init_card(int unit, struct address_info * hw_config)
{
- int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
-
- /*
- * First disable all drivers
- */
+ int i, n = num_sound_cards;
+ struct card_info *ci = snd_installed_cards ;
- for (i = 0; i < n; i++)
- snd_installed_cards[i].enabled = 0;
+ DDB(printf("sndtable_init_card(%d) entered\n", unit));
- if (ints[0] == 0 || ints[1] == 0)
- return;
- /*
- * Then enable them one by time
- */
+ if (!unit) {
+ sndtable_init() ;
+ return TRUE;
+ }
+ for (i = 0; i < n && ci->card_type; ci++, i++)
+ if (ci->card_type == unit) {
+ int drv;
- for (i = 1; i <= ints[0]; i++)
- {
- int card_type, ioaddr, irq, dma, ptr, j;
- unsigned int val;
+ ci->config.io_base = hw_config->io_base;
+ ci->config.irq = hw_config->irq;
+ ci->config.dma = hw_config->dma;
+ ci->config.dma2 = hw_config->dma2;
+ ci->config.name = hw_config->name;
+ ci->config.always_detect = hw_config->always_detect;
+ ci->config.card_subtype = hw_config->card_subtype;
+ ci->config.osp = hw_config->osp;
+
+ if ((drv = snd_find_driver(ci->card_type)) == -1)
+ ci->enabled = 0; /* Mark not fnd */
+ else {
+ DDB(printf("Located card - calling attach routine\n"));
+ sound_drivers[drv].attach(hw_config) ;
+ DDB(printf("attach routine finished\n"));
+ }
+ start_services();
+ return TRUE;
+ }
+ DDB(printf("sndtable_init_card: No card defined with type=%d, num cards: %d\n",
+ unit, num_sound_cards));
+ return FALSE;
+}
- val = (unsigned int) ints[i];
+int
+sndtable_get_cardcount(void)
+{
+ return num_audiodevs + num_mixers + num_synths + num_midis;
+}
- card_type = (val & 0x0ff00000) >> 20;
+int
+sndtable_identify_card(char *name)
+{
+ int i, n = num_sound_drivers;
- if (card_type > 127)
- {
- /*
- * Add any future extensions here
- */
- return;
- }
+ if (name == NULL)
+ return 0;
- ioaddr = (val & 0x000fff00) >> 8;
- irq = (val & 0x000000f0) >> 4;
- dma = (val & 0x0000000f);
+ for (i = 0; i < n; i++)
+ if (sound_drivers[i].driver_id != NULL) {
+ char *id = sound_drivers[i].driver_id;
+ int j;
- ptr = -1;
- for (j = 0; j < n && ptr == -1; j++)
- if (snd_installed_cards[j].card_type == card_type &&
- !snd_installed_cards[j].enabled) /*
- * Not already found
- */
- ptr = j;
-
- if (ptr == -1)
- printk ("Sound: Invalid setup parameter 0x%08x\n", val);
- else
- {
- snd_installed_cards[ptr].enabled = 1;
- snd_installed_cards[ptr].config.io_base = ioaddr;
- snd_installed_cards[ptr].config.irq = irq;
- snd_installed_cards[ptr].config.dma = dma;
+ for (j = 0; j < 80 && name[j] == id[j]; j++)
+ if (id[j] == 0 && name[j] == 0) /* Match */
+ return sound_drivers[i].card_type;
}
- }
+ return 0;
}
-#else
void
-sound_chconf (int card_type, int ioaddr, int irq, int dma)
+sound_chconf(int card_type, int ioaddr, int irq, int dma)
{
- int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
-
- int ptr, j;
-
- ptr = -1;
- for (j = 0; j < n && ptr == -1; j++)
- if (snd_installed_cards[j].card_type == card_type &&
- !snd_installed_cards[j].enabled) /*
- * Not already found
- */
- ptr = j;
-
- if (ptr != -1)
- {
- snd_installed_cards[ptr].enabled = 1;
- if (ioaddr)
- snd_installed_cards[ptr].config.io_base = ioaddr;
- if (irq)
- snd_installed_cards[ptr].config.irq = irq;
- if (dma)
- snd_installed_cards[ptr].config.dma = dma;
+ int j, ptr = -1, n = num_sound_cards;
+
+ for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++)
+ if (snd_installed_cards[j].card_type == card_type &&
+ !snd_installed_cards[j].enabled) /* Not already found */
+ ptr = j;
+
+ if (ptr != -1) {
+ snd_installed_cards[ptr].enabled = 1;
+ if (ioaddr)
+ snd_installed_cards[ptr].config.io_base = ioaddr;
+ if (irq)
+ snd_installed_cards[ptr].config.irq = irq;
+ if (dma)
+ snd_installed_cards[ptr].config.dma = dma;
+ snd_installed_cards[ptr].config.dma2 = -1;
}
}
-#endif
struct address_info *
-sound_getconf (int card_type)
+sound_getconf(int card_type)
{
- int j, ptr;
- int n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+ int j, ptr = -1, n = num_sound_cards;
- ptr = -1;
- for (j = 0; j < n && ptr == -1; j++)
- if (snd_installed_cards[j].card_type == card_type)
- ptr = j;
+ for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++)
+ if (snd_installed_cards[j].card_type == card_type)
+ ptr = j;
- if (ptr == -1)
- return (struct address_info *) NULL;
-
- return &snd_installed_cards[ptr].config;
-}
+ if (ptr == -1)
+ return (struct address_info *) NULL;
-#else
-
-void
-sound_setup (char *str, int *ints)
-{
+ return &snd_installed_cards[ptr].config;
}
#endif
diff --git a/sys/i386/isa/sound/dev_table.h b/sys/i386/isa/sound/dev_table.h
index 12b20baf7d82..63067a4b7714 100644
--- a/sys/i386/isa/sound/dev_table.h
+++ b/sys/i386/isa/sound/dev_table.h
@@ -1,58 +1,66 @@
/*
- * dev_table.h
- *
- * Global definitions for device call tables
+ * dev_table.h
+ *
+ * Global definitions for 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
- * 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
+ * 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.
- *
-
-*/
+ *
+ */
#ifndef _DEV_TABLE_H_
#define _DEV_TABLE_H_
/*
- * NOTE! NOTE! NOTE! NOTE!
- *
- * If you modify this file, please check the dev_table.c also.
- *
- * NOTE! NOTE! NOTE! NOTE!
+ * NOTE! NOTE! NOTE! NOTE!
+ *
+ * If you modify this file, please check the dev_table.c also.
+ *
+ * NOTE! NOTE! NOTE! NOTE!
*/
+extern int sound_started;
+
struct driver_info {
- int card_type; /* From soundcard.h */
- char *name;
- long (*attach) (long mem_start, struct address_info *hw_config);
- int (*probe) (struct address_info *hw_config);
+ char *driver_id;
+ int card_subtype; /* Driver specific. Usually 0 */
+ int card_type; /* From soundcard.h */
+ char *name;
+ void (*attach) (struct address_info * hw_config);
+ int (*probe) (struct address_info * hw_config);
};
struct card_info {
- int card_type; /* Link (search key) to the driver list */
+ int card_type; /* Link (search key) to the driver list */
struct address_info config;
- int enabled;
+ int enabled;
};
+typedef struct pnp_sounddev {
+ int id;
+ void (*setup) (void *dev);
+ char *driver_name;
+} pnp_sounddev;
+
/*
* Device specific parameters (used only by dmabuf.c)
*/
@@ -63,283 +71,523 @@ struct card_info {
#define DMODE_INPUT 2
struct dma_buffparms {
- int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
-
- /*
- * Pointers to raw buffers
- */
+ int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
- char *raw_buf[DSP_BUFFCOUNT];
- unsigned long raw_buf_phys[DSP_BUFFCOUNT];
- int raw_count;
+ char *raw_buf; /* Pointers to raw buffers */
+ u_long raw_buf_phys;
- /*
- * Device state tables
- */
+ /*
+ * Device state tables
+ */
- unsigned long flags;
+ u_long flags;
#define DMA_BUSY 0x00000001
#define DMA_RESTART 0x00000002
#define DMA_ACTIVE 0x00000004
#define DMA_STARTED 0x00000008
#define DMA_ALLOC_DONE 0x00000020
- int open_mode;
+ int open_mode;
/*
* Queue parameters.
*/
- int qlen;
- int qhead;
- int qtail;
+ int qlen;
+ int qhead;
+ int qtail;
+
+ int nbufs;
+ int counts[MAX_SUB_BUFFERS];
+ int subdivision;
- int nbufs;
- int counts[MAX_SUB_BUFFERS];
- int subdivision;
- char *buf[MAX_SUB_BUFFERS];
- unsigned long buf_phys[MAX_SUB_BUFFERS];
+ int fragment_size;
+ int max_fragments;
- int fragment_size;
- int max_fragments;
+ int bytes_in_use;
- int bytes_in_use;
+ int underrun_count;
+ int byte_counter;
- int underrun_count;
+ int mapping_flags;
+#define DMA_MAP_MAPPED 0x00000001
+ char neutral_byte;
};
+/*
+ * Structure for use with various microcontrollers and DSP processors in the
+ * recent soundcards.
+ */
+typedef struct coproc_operations {
+ char name[32];
+ int (*open) (void *devc, int sub_device);
+ void (*close) (void *devc, int sub_device);
+ int (*ioctl) (void *devc, u_int cmd, ioctl_arg arg, int local);
+ void (*reset) (void *devc);
+
+ void *devc; /* Driver specific info */
+} coproc_operations;
+
struct audio_operations {
- char name[32];
- int flags;
+ char name[32];
+ int flags;
#define NOTHING_SPECIAL 0
#define NEEDS_RESTART 1
#define DMA_AUTOMODE 2
- int format_mask; /* Bitmask for supported audio formats */
- void *devc; /* Driver specific info */
- int (*open) (int dev, int mode);
- void (*close) (int dev);
- void (*output_block) (int dev, unsigned long buf,
- 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);
- void (*reset) (int dev);
- void (*halt_xfer) (int dev);
- int (*local_qlen)(int dev);
- void (*copy_from_user)(int dev, char *localbuf, int localoffs,
- snd_rw_buf *userbuf, int useroffs, int len);
- int buffcount;
- long buffsize;
- int dmachan;
- struct dma_buffparms *dmap;
+#define DMA_DUPLEX 4
+ int format_mask; /* Bitmask for supported audio formats */
+ void *devc; /* Driver specific info */
+ int (*open) (int dev, int mode);
+ void (*close) (int dev);
+ void (*output_block) (int dev, unsigned long buf,
+ 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, u_int cmd, ioctl_arg arg, int local);
+ int (*prepare_for_input) (int dev, int bufsize, int nbufs);
+ int (*prepare_for_output) (int dev, int bufsize, int nbufs);
+ void (*reset) (int dev);
+ void (*halt_xfer) (int dev);
+ int (*local_qlen) (int dev);
+ void (*copy_from_user) (int dev, char *localbuf, int localoffs,
+ snd_rw_buf * userbuf, int useroffs, int len);
+ void (*halt_input) (int dev);
+ void (*halt_output) (int dev);
+ void (*trigger) (int dev, int bits);
+ long buffsize;
+ int dmachan1, dmachan2;
+ struct dma_buffparms *dmap_in, *dmap_out;
+ struct coproc_operations *coproc;
+ int mixer_dev;
+ int enable_bits;
+ int open_mode;
+ int go;
+ int otherside;
+ int busy;
};
struct mixer_operations {
- int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+ char name[32];
+ int (*ioctl) (int dev, unsigned int cmd, ioctl_arg arg);
};
struct synth_operations {
struct synth_info *info;
- int midi_dev;
- int synth_type;
- int synth_subtype;
-
- int (*open) (int dev, int mode);
- void (*close) (int dev);
- int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
- int (*kill_note) (int dev, int voice, int note, int velocity);
- int (*start_note) (int dev, int voice, int note, int velocity);
- int (*set_instr) (int dev, int voice, int instr);
- void (*reset) (int dev);
- void (*hw_control) (int dev, unsigned char *event);
- int (*load_patch) (int dev, int format, snd_rw_buf *addr,
- int offs, int count, int pmgr_flag);
- 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);
- void (*bender) (int dev, int chn, int value);
- int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc);
-
- struct voice_alloc_info alloc;
- struct channel_info chn_info[16];
+ int midi_dev;
+ int synth_type;
+ int synth_subtype;
+
+ int (*open) (int dev, int mode);
+ void (*close) (int dev);
+ int (*ioctl) (int dev, unsigned int cmd, ioctl_arg arg);
+ int (*kill_note) (int dev, int voice, int note, int velocity);
+ int (*start_note) (int dev, int voice, int note, int velocity);
+ int (*set_instr) (int dev, int voice, int instr);
+ void (*reset) (int dev);
+ void (*hw_control) (int dev, unsigned char *event);
+ int (*load_patch) (int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag);
+ 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);
+ void (*bender) (int dev, int chn, int value);
+ int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info * alloc);
+ void (*setup_voice) (int dev, int voice, int chn);
+ int (*send_sysex) (int dev, unsigned char *bytes, int len);
+
+ struct voice_alloc_info alloc;
+ struct channel_info chn_info[16];
+};
+
+struct midi_input_info { /* MIDI input scanner variables */
+#define MI_MAX 10
+ int m_busy;
+ unsigned char m_buf[MI_MAX];
+ unsigned char m_prev_status; /* For running status */
+ int m_ptr;
+#define MST_INIT 0
+#define MST_DATA 1
+#define MST_SYSEX 2
+ int m_state;
+ int m_left;
};
struct midi_operations {
struct midi_info info;
struct synth_operations *converter;
- int (*open) (int dev, int mode,
- void (*inputintr)(int dev, unsigned char data),
- void (*outputintr)(int dev)
- );
- void (*close) (int dev);
- int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
- int (*putc) (int dev, unsigned char data);
- int (*start_read) (int dev);
- int (*end_read) (int dev);
- void (*kick)(int dev);
- int (*command) (int dev, unsigned char *data);
- int (*buffer_status) (int dev);
- int (*prefix_cmd) (int dev, unsigned char status);
+ struct midi_input_info in_info;
+ int (*open) (int dev, int mode,
+ void (*inputintr) (int dev, unsigned char data),
+ void (*outputintr) (int dev) );
+ void (*close) (int dev);
+ int (*ioctl) (int dev, unsigned int cmd, ioctl_arg arg);
+ int (*putc) (int dev, unsigned char data);
+ int (*start_read) (int dev);
+ int (*end_read) (int dev);
+ void (*kick) (int dev);
+ int (*command) (int dev, unsigned char *data);
+ int (*buffer_status) (int dev);
+ int (*prefix_cmd) (int dev, unsigned char status);
+ struct coproc_operations *coproc;
+};
+
+struct sound_lowlev_timer {
+ int dev;
+ u_int (*tmr_start) (int dev, unsigned int usecs);
+ void (*tmr_disable) (int dev);
+ void (*tmr_restart) (int dev);
};
struct sound_timer_operations {
struct sound_timer_info info;
- int priority;
- int devlink;
- int (*open)(int dev, int mode);
- void (*close)(int dev);
- int (*event)(int dev, unsigned char *ev);
- unsigned long (*get_time)(int dev);
- int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
- void (*arm_timer)(int dev, long time);
+ int priority;
+ int devlink;
+ int (*open) (int dev, int mode);
+ void (*close) (int dev);
+ int (*event) (int dev, unsigned char *ev);
+ u_long (*get_time) (int dev);
+ int (*ioctl) (int dev, unsigned int cmd, ioctl_arg arg);
+ void (*arm_timer) (int dev, long time);
};
-#ifdef _DEV_TABLE_C_
- struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0;
- struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
- struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0;
- struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
-
-#ifndef EXCLUDE_SEQUENCER
- extern struct sound_timer_operations default_sound_timer;
- struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] =
- {&default_sound_timer, NULL};
- int num_sound_timers = 1;
+#ifdef _DEV_TABLE_C_
+struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL};
+int num_audiodevs = 0;
+struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL};
+int num_mixers = 0;
+struct synth_operations *synth_devs[MAX_SYNTH_DEV + MAX_MIDI_DEV] = {NULL};
+int num_synths = 0;
+struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL};
+int num_midis = 0;
+
+#ifdef CONFIG_SEQUENCER
+extern struct sound_timer_operations default_sound_timer;
+struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] =
+ {&default_sound_timer, NULL};
+int num_sound_timers = 1;
#else
- struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] =
- {NULL};
- int num_sound_timers = 0;
+struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {NULL};
+int num_sound_timers = 0;
#endif
/*
* List of low level drivers compiled into the kernel.
+ *
+ * remember, each entry contains:
+
+ char *driver_id;
+ int card_subtype; (Driver specific. Usually 0)
+ int card_type; (From soundcard.h)
+ char *name;
+ void (*attach) (struct address_info * hw_config);
+ int (*probe) (struct address_info * hw_config);
+ *
*/
- struct driver_info sound_drivers[] = {
-#ifndef EXCLUDE_PSS
- {SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss},
+struct driver_info sound_drivers[] = {
+
+#ifdef CONFIG_PSS
+ {"PSSECHO", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)",
+ attach_pss, probe_pss},
+ {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU",
+ attach_pss_mpu, probe_pss_mpu},
+ {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS",
+ attach_pss_mss, probe_pss_mss},
#endif
-#ifndef EXCLUDE_YM3812
- {SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib},
+
+#ifdef CONFIG_MSS
+ /* XXX changed type from 0 to 1 -lr 970705 */
+ {"MSS", 1, SNDCARD_MSS, "MS Sound System",
+ attach_mss, probe_mss},
+ /* MSS without IRQ/DMA config registers (for DEC Alphas) */
+ {"PCXBJ", 1, SNDCARD_PSEUDO_MSS, "MS Sound System (AXP)",
+ attach_mss, probe_mss},
#endif
-#ifndef EXCLUDE_PAS
- {SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas},
+
+#ifdef CONFIG_MAD16
+ {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)",
+ attach_mad16, probe_mad16},
+ {"MAD16MPU", 0, SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)",
+ attach_mad16_mpu, probe_mad16_mpu},
#endif
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
- {SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401},
+
+#ifdef CONFIG_CS4232
+ {"CS4232", 0, SNDCARD_CS4232, "CS4232",
+ attach_cs4232, probe_cs4232},
+ {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI",
+ attach_cs4232_mpu, probe_cs4232_mpu},
#endif
-#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
- {SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850},
+
+#ifdef CONFIG_YM3812
+ {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM",
+ attach_adlib_card, probe_adlib},
#endif
-#ifndef EXCLUDE_SB
- {SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb},
+
+#ifdef CONFIG_PAS
+ {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum",
+ attach_pas_card, probe_pas},
#endif
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
-#ifndef EXCLUDE_AUDIO
- {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect},
+
+#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
+ {"MPU401", 0, SNDCARD_MPU401, "Roland MPU-401",
+ attach_mpu401, probe_mpu401},
#endif
-#ifndef EXCLUDE_MIDI
- {SNDCARD_SB16MIDI,"SB16 MIDI", attach_sb16midi, probe_sb16midi},
+
+#if defined(CONFIG_MAUI)
+ {"MAUI", 0, SNDCARD_MAUI, "TB Maui",
+ attach_maui, probe_maui},
#endif
+
+#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
+ {"MIDI6850", 0, SNDCARD_UART6850, "6860 UART Midi",
+ attach_uart6850, probe_uart6850},
#endif
-#ifndef EXCLUDE_GUS16
- {SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16},
+
+#ifdef CONFIG_SB
+ {"SBLAST", 0, SNDCARD_SB, "SoundBlaster",
+ attach_sb_card, probe_sb},
#endif
-#ifndef EXCLUDE_MSS
- {SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound},
+
+#if defined(CONFIG_SB) && defined(CONFIG_SB16)
+#ifdef CONFIG_AUDIO
+ {"SB16", 0, SNDCARD_SB16, "SoundBlaster16",
+ sb16_dsp_init, sb16_dsp_detect},
+#endif
+#ifdef CONFIG_AWE32
+ {"AWE32", 0, SNDCARD_AWE32, "AWE32 Synth",
+ attach_awe_obsolete, probe_awe_obsolete},
+#endif
+#ifdef CONFIG_MIDI
+ {"SB16MIDI", 0, SNDCARD_SB16MIDI, "SB16 MIDI",
+ attach_sb16midi, probe_sb16midi},
#endif
-#ifndef EXCLUDE_GUS
- {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus},
#endif
- {0, "*?*", NULL, NULL}
- };
+#ifdef CONFIG_GUS16
+ {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.",
+ attach_gus_db16, probe_gus_db16},
+#endif
+
+#ifdef CONFIG_GUS
+ {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound",
+ attach_gus_card, probe_gus},
+#endif
+
+#ifdef CONFIG_SSCAPE
+ {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq Soundscape",
+ attach_sscape, probe_sscape},
+ {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)",
+ attach_ss_mss, probe_ss_mss},
+#endif
+
+#if NTRIX > 0
+ {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro",
+ attach_trix_wss, probe_trix_wss},
+ {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)",
+ attach_trix_sb, probe_trix_sb},
+ {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTriX MIDI",
+ attach_trix_mpu, probe_trix_mpu},
+#endif
+
+#ifdef CONFIG_PNP
+ {"AD1848", 0, 500, "PnP MSS",
+ attach_pnp_ad1848, probe_pnp_ad1848},
+#endif
+
+ {NULL, 0, 0, "*?*", NULL, NULL}
+};
+
+int num_sound_drivers =
+sizeof(sound_drivers) / sizeof(struct driver_info);
+int max_sound_drivers =
+sizeof(sound_drivers) / sizeof(struct driver_info);
+
+#define FULL_SOUND
+
+#ifndef FULL_SOUND
/*
- * List of devices actually configured in the system.
+ * List of devices actually configured in the system.
+ *
+ * Note! The detection order is significant. Don't change it.
+ *
+ * remember, the list contains
+ *
+ * int card_type; (Link (search key) to the driver list)
+ * struct address_info config;
+ * io_base, irq, dma, dma2,
+ * always_detect, char *name, struct... *osp
+ * int enabled;
+ * void *for_driver_use;
*
- * Note! The detection order is significant. Don't change it.
*/
- struct card_info snd_installed_cards[] = {
-#ifndef EXCLUDE_PSS
- {SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE},
+struct card_info snd_installed_cards[] = {
+#ifdef CONFIG_PSS
+ {SNDCARD_PSS, {PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE},
+#ifdef PSS_MPU_BASE
+ {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
- {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
-#ifdef MPU2_BASE
- {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#ifdef PSS_MSS_BASE
+ {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifdef MPU3_BASE
- {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif /* config PSS */
+
+#if NTRIX > 0
+ {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA, TRIX_DMA2}, SND_DEFAULT_ENABLE},
+#ifdef TRIX_SB_BASE
+ {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
+#ifdef TRIX_MPU_BASE
+ {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_MSS
- {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE},
-# ifdef MSS2_BASE
- {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA}, SND_DEFAULT_ENABLE},
-# endif
+#endif /* NTRIX > 0 */
+
+#ifdef CONFIG_SSCAPE
+ {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
+ {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
- {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_MAD16
+ {SNDCARD_MAD16, {MAD16_BASE, MAD16_IRQ, MAD16_DMA, MAD16_DMA2}, SND_DEFAULT_ENABLE},
+#ifdef MAD16_MPU_BASE
+ {SNDCARD_MAD16_MPU, {MAD16_MPU_BASE, MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
+#endif /* CONFIG_MAD16 */
-#ifndef EXCLUDE_PAS
- {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_CS4232
+#ifdef CS4232_MPU_BASE
+ {SNDCARD_CS4232_MPU, {CS4232_MPU_BASE, CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+ {SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_SB
- {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_MSS
+#ifdef PSEUDO_MSS
+ {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
+#else
+ {SNDCARD_PSEUDO_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
+#ifdef MSS2_BASE
+ {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, -1}, SND_DEFAULT_ENABLE},
+#endif
+#endif /* CONFIG_MSS */
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
-#ifndef EXCLUDE_AUDIO
- {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_PAS
+ {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_MIDI
- {SNDCARD_SB16MIDI,{SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
+
+#ifdef CONFIG_SB
+#ifndef SBC_DMA
+#define SBC_DMA 1
#endif
+ {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_GUS
-#ifndef EXCLUDE_GUS16
- {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA}, SND_DEFAULT_ENABLE},
+#if defined(CONFIG_MAUI)
+ {SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+
+#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
+ {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#ifdef MPU2_BASE
+ {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef MPU3_BASE
+ {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+#endif
+
+#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
+ {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+
+#if defined(CONFIG_SB) && defined(CONFIG_SB16)
+#ifdef CONFIG_AUDIO
+ {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA, -1}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef CONFIG_MIDI
+ {SNDCARD_SB16MIDI, {SB16MIDI_BASE, SBC_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef CONFIG_AWE32
+ {SNDCARD_AWE32,{AWE32_BASE, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
- {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_YM3812
- {SNDCARD_ADLIB, {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_GUS
+#ifdef CONFIG_GUS16
+ {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, -1}, SND_DEFAULT_ENABLE},
+#endif
+ {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA2}, SND_DEFAULT_ENABLE},
#endif
- {0, {0}, 0}
- };
- int num_sound_drivers =
- sizeof(sound_drivers) / sizeof (struct driver_info);
- int num_sound_cards =
- sizeof(snd_installed_cards) / sizeof (struct card_info);
+#ifdef CONFIG_YM3812
+ {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+ /* Define some expansion space */
+ {0, {0}, 0},
+ {0, {0}, 0},
+ {0, {0}, 0},
+ {0, {0}, 0},
+ {0, {0}, 0}
+};
+int num_sound_cards = sizeof(snd_installed_cards) / sizeof(struct card_info);
+int max_sound_cards = sizeof(snd_installed_cards) / sizeof(struct card_info);
#else
- extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs;
- extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
- extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths;
- extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
- extern struct sound_timer_operations * sound_timer_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_sound_timers;
-
- extern struct driver_info sound_drivers[];
- extern int num_sound_drivers;
- extern struct card_info snd_installed_cards[];
- extern int num_sound_cards;
-
-long sndtable_init(long mem_start);
-int sndtable_get_cardcount (void);
-struct address_info *sound_getconf(int card_type);
-void sound_chconf(int card_type, int ioaddr, int irq, int dma);
-int snd_find_driver(int type);
+int num_sound_cards = 0;
+struct card_info snd_installed_cards[20] = {{0}};
+int max_sound_cards = 20;
+#endif
-#endif /* _DEV_TABLE_C_ */
-#endif /* _DEV_TABLE_H_ */
+#ifdef MODULE
+int trace_init = 0;
+#else
+int trace_init = 1;
+#endif
+
+#else
+extern struct audio_operations *audio_devs[MAX_AUDIO_DEV];
+int num_audiodevs;
+extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
+extern int num_mixers;
+extern struct synth_operations *synth_devs[MAX_SYNTH_DEV + MAX_MIDI_DEV];
+extern int num_synths;
+extern struct midi_operations *midi_devs[MAX_MIDI_DEV];
+extern int num_midis;
+extern struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV];
+extern int num_sound_timers;
+
+extern struct driver_info sound_drivers[];
+extern int num_sound_drivers;
+extern int max_sound_drivers;
+extern struct card_info snd_installed_cards[];
+extern int num_sound_cards;
+extern int max_sound_cards;
+
+extern int trace_init;
+
+void sndtable_init(void);
+int sndtable_get_cardcount(void);
+struct address_info *sound_getconf(int card_type);
+void sound_chconf(int card_type, int ioaddr, int irq, int dma);
+int snd_find_driver(int type);
+int sndtable_identify_card(char *name);
+void sound_setup(char *str, int *ints);
+
+int sound_alloc_dmap(int dev, struct dma_buffparms * dmap, int chan);
+void sound_free_dmap(int dev, struct dma_buffparms * dmap);
+extern int soud_map_buffer(int dev, struct dma_buffparms * dmap, buffmem_desc * info);
+void install_pnp_sounddrv(struct pnp_sounddev * drv);
+int sndtable_probe(int unit, struct address_info * hw_config);
+int sndtable_init_card(int unit, struct address_info * hw_config);
+void sound_timer_init(struct sound_lowlev_timer * t, char *name);
+int
+sound_start_dma(int dev, struct dma_buffparms * dmap, int chan,
+ unsigned long physaddr,
+ int count, int dma_mode, int autoinit);
+void sound_dma_intr(int dev, struct dma_buffparms * dmap, int chan);
+
+#endif /* _DEV_TABLE_C_ */
+#endif /* _DEV_TABLE_H_ */
diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c
index 0e275b6a3aea..db1824efab15 100644
--- a/sys/i386/isa/sound/dmabuf.c
+++ b/sys/i386/isa/sound/dmabuf.c
@@ -1,10 +1,10 @@
/*
* sound/dmabuf.c
- *
+ *
* The DMA buffer manager for digitized voice applications
- *
- * Copyright by Hannu Savolainen 1993, 1994
- *
+ *
+ * Copyright by Hannu Savolainen 1993, 1994, 1995
+ *
* 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,941 +24,1579 @@
* 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"
+#include <i386/isa/sound/sound_config.h>
+#include <i386/include/md_var.h>
-#ifdef CONFIGURE_SOUNDCARD
+#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
+#ifdef ALLOW_POLL
-#include "sound_calls.h"
-
-#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
+int
+DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait);
+#endif;
-DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
+static void
+reorganize_buffers(int dev, struct dma_buffparms * dmap);
-static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
-{0}; /*
- * Primitive way to allocate
- * such a large array.
- * Needs dynamic run-time alloction.
- */
+static int *in_sleeper[MAX_AUDIO_DEV] = {NULL};
+static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = {{0}};
+static int *out_sleeper[MAX_AUDIO_DEV] = {NULL};
+static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = {{0}};
-static void
-reorganize_buffers (int dev)
-{
- /*
- * This routine breaks the physical device buffers to logical ones.
- */
+static int ndmaps = 0;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
- struct audio_operations *dsp_dev = audio_devs[dev];
+#define MAX_DMAP (MAX_AUDIO_DEV*2)
- unsigned i, p, n;
- unsigned sr, nc, sz, bsz;
+static struct dma_buffparms dmaps[MAX_DMAP] = {{0}};
+/*
+ * Primitive way to allocate such a large array. Needs dynamic run-time
+ * alloction.
+ */
- if (dmap->fragment_size == 0)
- { /* Compute the fragment size using the default algorithm */
+static int space_in_queue(int dev);
- sr = dsp_dev->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
- nc = dsp_dev->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
- sz = dsp_dev->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
+static void dma_reset_output(int dev);
+static void dma_reset_input(int dev);
- if (sr < 1 || nc < 1 || sz < 1)
- {
- printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
- dev, sr, nc, sz);
- sr = DSP_DEFAULT_SPEED;
- nc = 1;
- sz = 8;
+static void
+reorganize_buffers(int dev, struct dma_buffparms * dmap)
+{
+ /*
+ * This routine breaks the physical device buffers to logical ones.
+ */
+
+ struct audio_operations *dsp_dev = audio_devs[dev];
+ u_int sr, nc;
+ int bsz, sz, n, i;
+
+ if (dmap->fragment_size == 0) {
+ /* Compute the fragment size using the default algorithm */
+
+ sr = dsp_dev->ioctl(dev, SOUND_PCM_READ_RATE, 0, 1);
+ nc = dsp_dev->ioctl(dev, SOUND_PCM_READ_CHANNELS, 0, 1);
+ sz = dsp_dev->ioctl(dev, SOUND_PCM_READ_BITS, 0, 1);
+
+ if (sz == 8)
+ dmap->neutral_byte = 254;
+ else
+ dmap->neutral_byte = 0x00;
+
+ if (sr < 1 || nc < 1 || sz < 1) {
+ printf("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
+ dev, sr, nc, sz);
+ sr = DSP_DEFAULT_SPEED;
+ nc = 1;
+ sz = 8;
}
+ sz = sr * nc * sz;
+
+ sz /= 8; /* #bits -> #bytes */
+
+ /*
+ * Compute a buffer size for time not exeeding 1 second.
+ * Usually this algorithm gives a buffer size for 0.5 to 1.0
+ * seconds of sound (using the current speed, sample size and
+ * #channels).
+ */
+
+ bsz = dsp_dev->buffsize;
+ while (bsz > sz)
+ bsz /= 2;
+
+ if (bsz == dsp_dev->buffsize)
+ bsz /= 2; /* Needs at least 2 buffers */
+
+ if (dmap->subdivision == 0) /* Not already set */
+ dmap->subdivision = 1; /* Init to default value */
+ else
+ bsz /= dmap->subdivision;
+
+ if (bsz < 16)
+ bsz = 16; /* Just a sanity check */
+
+ dmap->fragment_size = bsz;
+ } else {
+ /*
+ * The process has specified the buffer sice with
+ * SNDCTL_DSP_SETFRAGMENT or the buffer sice computation has
+ * already been done.
+ */
+
+ if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))
+ dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
+ bsz = dmap->fragment_size;
+ }
- sz /= 8; /* #bits -> #bytes */
-
- sz = sr * nc * sz;
+ bsz &= ~0x03; /* Force size which is multiple of 4 bytes */
+#ifdef OS_DMA_ALIGN_CHECK
+ OS_DMA_ALIGN_CHECK(bsz);
+#endif
- /*
- * Compute a buffer size for time not exeeding 1 second.
- * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
- * of sound (using the current speed, sample size and #channels).
- */
+ n = dsp_dev->buffsize / bsz;
- bsz = dsp_dev->buffsize;
- while (bsz > sz)
- bsz /= 2;
+ if (n > MAX_SUB_BUFFERS)
+ n = MAX_SUB_BUFFERS;
- if (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize)
- bsz /= 2; /* Needs at least 2 buffers */
+ if (n > dmap->max_fragments)
+ n = dmap->max_fragments;
+ dmap->nbufs = n;
+ dmap->bytes_in_use = n * bsz;
- if (dmap->subdivision == 0) /* Not already set */
- dmap->subdivision = 1; /* Init to default value */
+ for (i = 0; i < dmap->nbufs; i++) {
+ dmap->counts[i] = 0;
+ }
- bsz /= dmap->subdivision;
+ if (dmap->raw_buf)
+ fillw (dmap->neutral_byte, dmap->raw_buf,
+ dmap->bytes_in_use/2);
- if (bsz < 64)
- bsz = 4096; /* Just a sanity check */
+ dmap->flags |= DMA_ALLOC_DONE;
- while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS)
- bsz *= 2;
+}
- dmap->fragment_size = bsz;
- }
- else
- {
- /*
- * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
- * the buffer sice computation has already been done.
- */
- if (dmap->fragment_size > audio_devs[dev]->buffsize)
- dmap->fragment_size = audio_devs[dev]->buffsize;
- bsz = dmap->fragment_size;
+static void
+dma_init_buffers(int dev, struct dma_buffparms * dmap)
+{
+ if (dmap == audio_devs[dev]->dmap_out) {
+ out_sleep_flag[dev].aborting = 0;
+ out_sleep_flag[dev].mode = WK_NONE;
+ } else {
+ in_sleep_flag[dev].aborting = 0;
+ in_sleep_flag[dev].mode = WK_NONE;
}
- /*
- * Now computing addresses for the logical buffers
- */
+ dmap->flags = DMA_BUSY; /* Other flags off */
+ dmap->qlen = dmap->qhead = dmap->qtail = 0;
+ dmap->nbufs = 1;
+ dmap->bytes_in_use = audio_devs[dev]->buffsize;
- n = 0;
- for (i = 0; i < dmap->raw_count &&
- n < dmap->max_fragments &&
- n < MAX_SUB_BUFFERS; i++)
+ dmap->dma_mode = DMODE_NONE;
+ dmap->mapping_flags = 0;
+ dmap->neutral_byte = 0x00;
+}
+
+static int
+open_dmap(int dev, int mode, struct dma_buffparms * dmap, int chan)
+{
+ if (dmap->flags & DMA_BUSY)
+ return -(EBUSY);
+
+#ifdef RUNTIME_DMA_ALLOC
{
- p = 0;
+ int err;
- while ((p + bsz) <= dsp_dev->buffsize &&
- n < dmap->max_fragments &&
- n < MAX_SUB_BUFFERS)
- {
- dmap->buf[n] = dmap->raw_buf[i] + p;
- dmap->buf_phys[n] = dmap->raw_buf_phys[i] + p;
- p += bsz;
- n++;
- }
+ if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0)
+ return err;
}
+#endif
- dmap->nbufs = n;
- dmap->bytes_in_use = n * bsz;
+ if (dmap->raw_buf == NULL)
+ return -(ENOSPC); /* Memory allocation failed during boot */
- for (i = 0; i < dmap->nbufs; i++)
- {
- dmap->counts[i] = 0;
+ if (0) {
+ printf("Unable to grab(2) DMA%d for the audio driver\n", chan);
+ return -(EBUSY);
}
+ dmap->open_mode = mode;
+ dmap->subdivision = dmap->underrun_count = 0;
+ dmap->fragment_size = 0;
+ dmap->max_fragments = 65536; /* Just a large value */
+ dmap->byte_counter = 0;
+ isa_dma_acquire(chan);
- dmap->flags |= DMA_ALLOC_DONE;
+ dma_init_buffers(dev, dmap);
+
+ return 0;
}
static void
-dma_init_buffers (int dev)
+close_dmap(int dev, struct dma_buffparms * dmap, int chan)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
-
- dmap->flags = DMA_BUSY; /* Other flags off */
- dmap->qlen = dmap->qhead = dmap->qtail = 0;
-
- dmap->qlen = dmap->qtail = dmap->qhead = 0;
- dmap->dma_mode = DMODE_NONE;
+ if (dmap->flags & DMA_BUSY)
+ dmap->dma_mode = DMODE_NONE;
+ dmap->flags &= ~DMA_BUSY;
+ isa_dma_release(chan);
+#ifdef RUNTIME_DMA_ALLOC
+ sound_free_dmap(dev, dmap);
+#endif
}
int
-DMAbuf_open (int dev, int mode)
+DMAbuf_open(int dev, int mode)
{
- int retval;
- struct dma_buffparms *dmap = NULL;
+ int retval;
+ struct dma_buffparms *dmap_in = NULL;
+ struct dma_buffparms *dmap_out = NULL;
- if (dev >= num_audiodevs)
- {
- printk ("PCM device %d not installed.\n", dev);
- return RET_ERROR (ENXIO);
+ if (dev >= num_audiodevs) {
+ printf("PCM device %d not installed.\n", dev);
+ return -(ENXIO);
}
-
- if (!audio_devs[dev])
- {
- printk ("PCM device %d not initialized\n", dev);
- return RET_ERROR (ENXIO);
+ if (!audio_devs[dev]) {
+ printf("PCM device %d not initialized\n", dev);
+ return -(ENXIO);
}
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX)) {
+ audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
+ audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
+ }
+ if ((retval = audio_devs[dev]->open(dev, mode)) < 0)
+ return retval;
- dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- if (dmap->flags & DMA_BUSY)
- return RET_ERROR (EBUSY);
+ dmap_out = audio_devs[dev]->dmap_out;
+ dmap_in = audio_devs[dev]->dmap_in;
-#ifdef USE_RUNTIME_DMAMEM
- dmap->raw_buf[0] = NULL;
- sound_dma_malloc (dev);
-#endif
+ if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0) {
+ audio_devs[dev]->close(dev);
+ return retval;
+ }
+ audio_devs[dev]->enable_bits = mode;
- if (dmap->raw_buf[0] == NULL)
- return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
+ if (audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in) {
+ if ((retval = open_dmap(dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0) {
+ audio_devs[dev]->close(dev);
+ close_dmap(dev, dmap_out, audio_devs[dev]->dmachan1);
+ return retval;
+ }
+ }
+ audio_devs[dev]->open_mode = mode;
+ audio_devs[dev]->go = 1;
- if ((retval = audio_devs[dev]->open (dev, mode)) < 0)
- return retval;
+ in_sleep_flag[dev].aborting = 0;
+ in_sleep_flag[dev].mode = WK_NONE;
- dmap->open_mode = mode;
- dmap->subdivision = dmap->underrun_count = 0;
- dmap->fragment_size = 0;
- dmap->max_fragments = 65536; /* Just a large value */
+ out_sleep_flag[dev].aborting = 0;
+ out_sleep_flag[dev].mode = WK_NONE;
- dma_init_buffers (dev);
- audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
- audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
- audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_BITS, (ioctl_arg) 8, 1);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_CHANNELS, (ioctl_arg) 1, 1);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_RATE, (ioctl_arg) DSP_DEFAULT_SPEED, 1);
- return 0;
+ return 0;
}
static void
-dma_reset (int dev)
+dma_reset(int dev)
{
- int retval;
- unsigned long flags;
+ u_long flags;
- DISABLE_INTR (flags);
+ flags = splhigh();
+ audio_devs[dev]->reset(dev);
+ splx(flags);
- audio_devs[dev]->reset (dev);
- audio_devs[dev]->close (dev);
+ dma_reset_output(dev);
- if ((retval = audio_devs[dev]->open (dev, audio_devs[dev]->dmap->open_mode)) < 0)
- printk ("Sound: Reset failed - Can't reopen device\n");
- RESTORE_INTR (flags);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ dma_reset_input(dev);
+}
- dma_init_buffers (dev);
- reorganize_buffers (dev);
+static void
+dma_reset_output(int dev)
+{
+ u_long flags;
+
+ flags = splhigh();
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
+ !audio_devs[dev]->halt_output)
+ audio_devs[dev]->reset(dev);
+ else
+ audio_devs[dev]->halt_output(dev);
+ splx(flags);
+
+ dma_init_buffers(dev, audio_devs[dev]->dmap_out);
+ reorganize_buffers(dev, audio_devs[dev]->dmap_out);
+}
+
+static void
+dma_reset_input(int dev)
+{
+ u_long flags;
+
+ flags = splhigh();
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
+ !audio_devs[dev]->halt_input)
+ audio_devs[dev]->reset(dev);
+ else
+ audio_devs[dev]->halt_input(dev);
+ splx(flags);
+
+ dma_init_buffers(dev, audio_devs[dev]->dmap_in);
+ reorganize_buffers(dev, audio_devs[dev]->dmap_in);
}
static int
-dma_sync (int dev)
+dma_sync(int dev)
{
- unsigned long flags;
+ u_long flags;
+ int i = 0;
+
+ if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
+ return 0;
+
+ if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) {
+ flags = splhigh();
+
+ out_sleep_flag[dev].aborting = 0;
+#ifdef ALLOW_BUFFER_MAPPING
+ if(audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED &&
+ audio_devs[dev]->dmap_out->qlen) {
+ splx(flags);
+
+ return audio_devs[dev]->dmap_out->qlen;
+ }
- if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)
- {
- DISABLE_INTR (flags);
+#endif
+ while (!PROCESS_ABORTING (out_sleep_flag[dev])
+ && audio_devs[dev]->dmap_out->qlen){
+ int chn;
+
+ out_sleeper[dev] = &chn;
+ DO_SLEEP1(chn, out_sleep_flag[dev], 10 * hz);
+ if (TIMED_OUT (out_sleep_flag[dev]) ) {
+
+ splx(flags);
+
+ return audio_devs[dev]->dmap_out->qlen;
- while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])
- && audio_devs[dev]->dmap->qlen)
- {
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
- if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- RESTORE_INTR (flags);
- return audio_devs[dev]->dmap->qlen;
- }
+ }
}
- RESTORE_INTR (flags);
- /*
- * Some devices such as GUS have huge amount of on board RAM for the
- * audio data. We have to wait util the device has finished playing.
- */
- DISABLE_INTR (flags);
- if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */
- {
- while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- && audio_devs[dev]->local_qlen (dev))
- {
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ);
+ splx(flags);
+
+ /*
+ * Some devices such as GUS have huge amount of on board RAM
+ * for the audio data. We have to wait until the device has
+ * finished playing.
+ */
+
+ flags = splhigh();
+ if (audio_devs[dev]->local_qlen) { /* Device has hidden buffers */
+ while (!(PROCESS_ABORTING (out_sleep_flag[dev]))
+ && audio_devs[dev]->local_qlen(dev)) {
+ int chn;
+ out_sleeper[dev] = &chn;
+ DO_SLEEP(chn, out_sleep_flag[dev], 10 * hz);
+
}
}
- RESTORE_INTR (flags);
+ splx(flags);
}
- return audio_devs[dev]->dmap->qlen;
+ return audio_devs[dev]->dmap_out->qlen;
}
int
-DMAbuf_release (int dev, int mode)
+DMAbuf_release(int dev, int mode)
{
- unsigned long flags;
+ u_long flags;
- if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- && (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT))
- {
- dma_sync (dev);
+ if (!((out_sleep_flag[dev].aborting))
+ && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) {
+ dma_sync(dev);
}
+ flags = splhigh();
-#ifdef USE_RUNTIME_DMAMEM
- sound_dma_free (dev);
-#endif
+ audio_devs[dev]->close(dev);
- DISABLE_INTR (flags);
- audio_devs[dev]->reset (dev);
+ close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
- audio_devs[dev]->close (dev);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+ audio_devs[dev]->open_mode = 0;
- audio_devs[dev]->dmap->dma_mode = DMODE_NONE;
- audio_devs[dev]->dmap->flags &= ~DMA_BUSY;
- RESTORE_INTR (flags);
+ splx(flags);
- return 0;
+ return 0;
}
-int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+static int
+activate_recording(int dev, struct dma_buffparms * dmap)
{
- unsigned long flags;
- int err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
+ return 0;
- DISABLE_INTR (flags);
- if (!dmap->qlen)
- {
- if (dmap->flags & DMA_RESTART)
- {
- dma_reset (dev);
- dmap->flags &= ~DMA_RESTART;
- }
+ if (dmap->flags & DMA_RESTART) {
+ dma_reset_input(dev);
+ dmap->flags &= ~DMA_RESTART;
+ }
+ if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */
+ dma_sync(dev);
+ dma_reset(dev);
+ dmap->dma_mode = DMODE_NONE;
+ }
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
- if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */
- {
- dma_sync (dev);
- dma_reset (dev);
- dmap->dma_mode = DMODE_NONE;
- }
+ if (!dmap->dma_mode) {
+ int err;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if ((err = audio_devs[dev]->prepare_for_input(dev,
+ dmap->fragment_size, dmap->nbufs)) < 0) {
+ return err;
+ }
+ dmap->dma_mode = DMODE_INPUT;
+ }
+ if (!(dmap->flags & DMA_ACTIVE)) {
+ audio_devs[dev]->start_input(dev,
+ dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 0,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+ !(dmap->flags & DMA_STARTED));
+ dmap->flags |= DMA_ACTIVE | DMA_STARTED;
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+ return 0;
+}
- if (dmap->dma_mode)
- {
- int err;
+int
+DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
+{
+ u_long flags;
+ int err = EIO;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+
+ flags = splhigh();
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't read from mmapped device (1)\n");
+ return -(EINVAL);
+ } else
+#endif
+ if (!dmap->qlen) {
+ int timeout;
- if ((err = audio_devs[dev]->prepare_for_input (dev,
- dmap->fragment_size, dmap->nbufs)) < 0)
- {
- RESTORE_INTR (flags);
- return err;
- }
- dmap->dma_mode = DMODE_INPUT;
+ if ((err = activate_recording(dev, dmap)) < 0) {
+ splx(flags);
+ return err;
}
+ /* Wait for the next block */
- if (!(dmap->flags & DMA_ACTIVE))
- {
- audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
- dmap->fragment_size, 0,
- !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
- !(dmap->flags & DMA_STARTED));
- dmap->flags |= DMA_ACTIVE | DMA_STARTED;
+ if (dontblock) {
+ splx(flags);
+ return -(EAGAIN);
}
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &
+ audio_devs[dev]->go) {
+ splx(flags);
+ return -(EAGAIN);
+ }
+ if (!audio_devs[dev]->go)
+ timeout = 0;
+ else
+ timeout = 2 * hz;
- /* Wait for the next block */
-
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
- if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
{
- 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;
+ int chn;
+
+ in_sleeper[dev] = &chn;
+ DO_SLEEP(chn, in_sleep_flag[dev], timeout);
+
+ };
+ /* XXX note -- nobody seems to set the mode to WK_TIMEOUT - lr */
+ if ((in_sleep_flag[dev].mode & WK_TIMEOUT)) {
+ /* XXX hey, we are in splhigh here ? lr 970705 */
+ printf("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ audio_devs[dev]->reset(dev);
+ in_sleep_flag[dev].aborting = 1;
+ } else
+ err = EINTR;
}
- RESTORE_INTR (flags);
+ splx(flags);
- if (!dmap->qlen)
- return RET_ERROR (err);
+ if (!dmap->qlen)
+ return -(err);
- *buf = &dmap->buf[dmap->qhead][dmap->counts[dmap->qhead]];
- *len = dmap->fragment_size - dmap->counts[dmap->qhead];
+ *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]];
+ *len = dmap->fragment_size - dmap->counts[dmap->qhead];
- return dmap->qhead;
+ return dmap->qhead;
}
int
-DMAbuf_rmchars (int dev, int buff_no, int c)
+DMAbuf_rmchars(int dev, int buff_no, int c)
+{
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+
+ int p = dmap->counts[dmap->qhead] + c;
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't read from mmapped device (2)\n");
+ return -(EINVAL);
+ } else
+#endif
+ if (p >= dmap->fragment_size) { /* This buffer is completely empty */
+ dmap->counts[dmap->qhead] = 0;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
+ dmap->qlen--;
+ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ } else
+ dmap->counts[dmap->qhead] = p;
+
+ return 0;
+}
+
+static int
+dma_subdivide(int dev, struct dma_buffparms * dmap, ioctl_arg arg, int fact)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ if (fact == 0) {
+ fact = dmap->subdivision;
+ if (fact == 0)
+ fact = 1;
+ return *(int *) arg = fact;
+ }
+ if (dmap->subdivision != 0 || dmap->fragment_size)/* Loo late to change */
+ return -(EINVAL);
- int p = dmap->counts[dmap->qhead] + c;
+ if (fact > MAX_REALTIME_FACTOR)
+ return -(EINVAL);
+
+ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+ return -(EINVAL);
+
+ dmap->subdivision = fact;
+ return *(int *) arg = fact;
+}
+
+static int
+dma_set_fragment(int dev, struct dma_buffparms * dmap, ioctl_arg arg, int fact)
+{
+ int bytes, count;
+
+ if (fact == 0)
+ return -(EIO);
+
+ if (dmap->subdivision != 0 || dmap->fragment_size)/* Loo late to change */
+ return -(EINVAL);
+
+ bytes = fact & 0xffff;
+ count = (fact >> 16) & 0xffff;
+
+ if (count == 0)
+ count = MAX_SUB_BUFFERS;
+
+#if amancio
+ if (bytes < 4 || bytes > 17) /* <16 || > 128k */
+ return -(EINVAL);
+#endif
+
+ if (count < 2)
+ return -(EINVAL);
+
+#ifdef OS_DMA_MINBITS
+ if (bytes < OS_DMA_MINBITS)
+ bytes = OS_DMA_MINBITS;
+#endif
+
+ dmap->fragment_size = (1 << bytes);
+
+ dmap->max_fragments = count;
+
+ if (dmap->fragment_size > audio_devs[dev]->buffsize)
+ dmap->fragment_size = audio_devs[dev]->buffsize;
+
+ if (dmap->fragment_size == audio_devs[dev]->buffsize &&
+ audio_devs[dev]->flags & DMA_AUTOMODE)
+ dmap->fragment_size /= 2; /* Needs at least 2 buffers */
+
+ dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */
+ return *(int *) arg = bytes | (count << 16);
+}
+
+static int
+get_buffer_pointer(int dev, int chan, struct dma_buffparms * dmap)
+{
+ int pos;
+ u_long flags;
+
+ flags = splhigh();
- if (p >= dmap->fragment_size)
- { /* This buffer is completely empty */
- dmap->counts[dmap->qhead] = 0;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
- dmap->qlen--;
- dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ if (!(dmap->flags & DMA_ACTIVE))
+ pos = 0;
+ else
+ {
+ pos = isa_dmastatus(chan);
}
+
+ splx(flags);
+
+ pos = dmap->bytes_in_use - pos ;
+ if (audio_devs[dev]->flags & DMA_AUTOMODE)
+ return pos;
else
- dmap->counts[dmap->qhead] = p;
+ {
+ pos = dmap->fragment_size - pos;
+ if (pos < 0)
+ return 0;
+ return pos;
+ }
+
- return 0;
}
int
-DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+DMAbuf_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
+ struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
+
+ switch (cmd) {
+
- switch (cmd)
- {
case SNDCTL_DSP_RESET:
- dma_reset (dev);
- return 0;
- break;
+ dma_reset(dev);
+ return 0;
+ break;
case SNDCTL_DSP_SYNC:
- dma_sync (dev);
- dma_reset (dev);
- return 0;
- break;
+ dma_sync(dev);
+ dma_reset(dev);
+ return 0;
+ break;
case SNDCTL_DSP_GETBLKSIZE:
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_out);
- return IOCTL_OUT (arg, dmap->fragment_size);
- break;
+ return *(int *) arg = dmap_out->fragment_size;
+ break;
- case SNDCTL_DSP_SUBDIVIDE:
- {
- int fact = IOCTL_IN (arg);
+ case SNDCTL_DSP_SETBLKSIZE:
+ {
+ int size = (*(int *) arg);
- if (fact == 0)
- {
- fact = dmap->subdivision;
- if (fact == 0)
- fact = 1;
- return IOCTL_OUT (arg, fact);
- }
+ if (!(dmap_out->flags & DMA_ALLOC_DONE) && size) {
+ if ((size >> 16) > 0 )
+ dmap_out->fragment_size = size >> 16;
+ else {
+ dmap_out->fragment_size = size;
+ }
+ dmap_out->max_fragments = 8888;
+
+ size &= 0xffff;
- if (dmap->subdivision != 0 ||
- dmap->fragment_size)/* Loo late to change */
- return RET_ERROR (EINVAL);
+ if (audio_devs[dev]->flags & DMA_DUPLEX) {
+ dmap_in->fragment_size = size;
+ dmap_in->max_fragments = 8888;
+ }
+ return 0;
- if (fact > MAX_REALTIME_FACTOR)
- return RET_ERROR (EINVAL);
+ } else
+ return -(EINVAL); /* Too late to change */
+
+ }
+ break;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ {
+ int fact = (*(int *) arg);
+ int ret;
- if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
- return RET_ERROR (EINVAL);
+ ret = dma_subdivide(dev, dmap_out, arg, fact);
+ if (ret < 0)
+ return ret;
- dmap->subdivision = fact;
- return IOCTL_OUT (arg, fact);
- }
- break;
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ ret = dma_subdivide(dev, dmap_in, arg, fact);
+
+ return ret;
+ }
+ break;
case SNDCTL_DSP_SETFRAGMENT:
- {
- int fact = IOCTL_IN (arg);
- int bytes, count;
+ {
+ int fact = (*(int *) arg);
+ int ret;
- if (fact == 0)
- return RET_ERROR (EIO);
+ ret = dma_set_fragment(dev, dmap_out, arg, fact);
+ if (ret < 0)
+ return ret;
- if (dmap->subdivision != 0 ||
- dmap->fragment_size)/* Loo late to change */
- return RET_ERROR (EINVAL);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ ret = dma_set_fragment(dev, dmap_in, arg, fact);
- bytes = fact & 0xffff;
- count = (fact >> 16) & 0xffff;
+ return ret;
+ }
+ break;
- if (count == 0)
- count = MAX_SUB_BUFFERS;
+ case SNDCTL_DSP_GETISPACE:
+ case SNDCTL_DSP_GETOSPACE:
+ if (!local)
+ return -(EINVAL);
+ else {
+ struct dma_buffparms *dmap = dmap_out;
- if (bytes < 7 || bytes > 17) /* <64 || > 128k */
- return RET_ERROR (EINVAL);
+ audio_buf_info *info = (audio_buf_info *) arg;
- if (count < 2)
- return RET_ERROR (EINVAL);
+ if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
+ dmap = dmap_in;
- dmap->fragment_size = (1 << bytes);
- dmap->max_fragments = count;
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ return -(EINVAL);
+#endif
- if (dmap->fragment_size > audio_devs[dev]->buffsize)
- dmap->fragment_size = audio_devs[dev]->buffsize;
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
+
+ info->fragstotal = dmap->nbufs;
+
+ if (cmd == SNDCTL_DSP_GETISPACE)
+ info->fragments = dmap->qlen;
+ else {
+ if (!space_in_queue(dev))
+ info->fragments = 0;
+ else {
+ info->fragments = dmap->nbufs - dmap->qlen;
+ if (audio_devs[dev]->local_qlen) {
+ int tmp = audio_devs[dev]->local_qlen(dev);
+
+ if (tmp & info->fragments)
+ tmp--; /* This buffer has been counted twice */
+ info->fragments -= tmp;
+ }
+ }
+ }
- if (dmap->fragment_size == audio_devs[dev]->buffsize &&
- audio_devs[dev]->flags & DMA_AUTOMODE)
- dmap->fragment_size /= 2; /* Needs at least 2 buffers */
+ if (info->fragments < 0)
+ info->fragments = 0;
+ else if (info->fragments > dmap->nbufs)
+ info->fragments = dmap->nbufs;
- dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */
- return IOCTL_OUT (arg, bytes | (count << 16));
- }
- break;
+ info->fragsize = dmap->fragment_size;
+ info->bytes = info->fragments * dmap->fragment_size;
+
+ if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
+ info->bytes -= dmap->counts[dmap->qhead];
+ }
+ return 0;
+
+ case SNDCTL_DSP_SETTRIGGER:
+ {
+ u_long flags;
+
+ int bits = (*(int *) arg) & audio_devs[dev]->open_mode;
+ int changed;
+
+ if (audio_devs[dev]->trigger == NULL)
+ return -(EINVAL);
+
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX))
+ if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) {
+ printf("Sound: Device doesn't have full duplex capability\n");
+ return -(EINVAL);
+ }
+ flags = splhigh();
+ changed = audio_devs[dev]->enable_bits ^ bits;
+
+ if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) {
+ if (!(dmap_in->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_in);
+ activate_recording(dev, dmap_in);
+ }
+#ifdef ALLOW_BUFFER_MAPPING
+ if ((changed & bits) & PCM_ENABLE_OUTPUT &&
+ dmap_out->mapping_flags & DMA_MAP_MAPPED &&
+ audio_devs[dev]->go) {
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_out);
+
+ audio_devs[dev]->prepare_for_output (dev,
+ dmap_out->fragment_size, dmap_out->nbufs);
+
+ dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+ DMAbuf_start_output(dev, 0, dmap_out->fragment_size);
+ dmap_out->dma_mode = DMODE_OUTPUT;
+ }
+#endif
+
+ audio_devs[dev]->enable_bits = bits;
+ if (changed && audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev, bits * audio_devs[dev]->go);
+ splx(flags);
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ return *(int *) arg = audio_devs[dev]->enable_bits;
+ break;
+
+ case SNDCTL_DSP_SETSYNCRO:
+
+ if (!audio_devs[dev]->trigger)
+ return -(EINVAL);
+
+ audio_devs[dev]->trigger(dev, 0);
+ audio_devs[dev]->go = 0;
+ return 0;
+ break;
+
+ case SNDCTL_DSP_GETIPTR:
+ {
+ count_info info;
+ u_long flags;
+
+ flags = splhigh();
+ info.bytes = audio_devs[dev]->dmap_in->byte_counter;
+ info.ptr = get_buffer_pointer(dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in);
+ info.blocks = audio_devs[dev]->dmap_in->qlen;
+ info.bytes += info.ptr;
+
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
+ audio_devs[dev]->dmap_in->qlen = 0; /* Ack interrupts */
+#endif
+ splx(flags);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_DSP_GETOPTR:
+ {
+ count_info info;
+ u_long flags;
+
+ flags = splhigh();
+ info.bytes = audio_devs[dev]->dmap_out->byte_counter;
+ info.ptr = get_buffer_pointer(dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out);
+ info.blocks = audio_devs[dev]->dmap_out->qlen;
+ info.bytes += info.ptr;
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+ audio_devs[dev]->dmap_out->qlen = 0; /* Ack interrupts */
+#endif
+ splx(flags);
+ return 0;
+ }
+ break;
default:
- return audio_devs[dev]->ioctl (dev, cmd, arg, local);
+ return audio_devs[dev]->ioctl(dev, cmd, arg, local);
}
+}
- return RET_ERROR (EIO);
+/*
+ * DMAbuf_start_devices() is called by the /dev/music driver to start one or
+ * more audio devices at desired moment.
+ */
+
+void
+DMAbuf_start_devices(u_int devmask)
+{
+ int dev;
+
+ for (dev = 0; dev < num_audiodevs; dev++)
+ if (devmask & (1 << dev))
+ if (audio_devs[dev]->open_mode != 0)
+ if (!audio_devs[dev]->go) {
+ /* OK to start the device */
+ audio_devs[dev]->go = 1;
+
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
}
static int
-space_in_queue (int dev)
+space_in_queue(int dev)
{
- int len, max, tmp;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- if (dmap->qlen == dmap->nbufs)/* No space at all */
- return 0;
-
- /*
- * Verify that there are no more pending buffers than the limit
- * defined by the process.
- */
-
- max = dmap->max_fragments;
- len = dmap->qlen;
-
- if (audio_devs[dev]->local_qlen)
- {
- tmp = audio_devs[dev]->local_qlen (dev);
- if (tmp & len)
- tmp--; /*
- * This buffer has been counted twice
- */
- len += tmp;
+ int len, max, tmp;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ if (dmap->qlen >= dmap->nbufs) /* No space at all */
+ return 0;
+
+ /*
+ * Verify that there are no more pending buffers than the limit
+ * defined by the process.
+ */
+
+ max = dmap->max_fragments;
+ len = dmap->qlen;
+
+ if (audio_devs[dev]->local_qlen) {
+ tmp = audio_devs[dev]->local_qlen(dev);
+ if (tmp & len)
+ tmp--; /* This buffer has been counted twice */
+ len += tmp;
}
- if (len >= max)
- return 0;
- return 1;
+ if (len >= max)
+ return 0;
+ return 1;
}
int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock)
{
- unsigned long flags;
- int abort, err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- if (dmap->dma_mode == DMODE_INPUT) /* Direction change */
- {
- dma_reset (dev);
- dmap->dma_mode = DMODE_NONE;
- }
- else if (dmap->flags & DMA_RESTART) /* Restart buffering */
- {
- dma_sync (dev);
- dma_reset (dev);
+ u_long flags;
+ int abort, err = EIO;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't write to mmapped device (3)\n");
+ return -(EINVAL);
}
+#endif
- dmap->flags &= ~DMA_RESTART;
+ if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */
+ dma_reset(dev);
+ dmap->dma_mode = DMODE_NONE;
+ } else if (dmap->flags & DMA_RESTART) { /* Restart buffering */
+ dma_sync(dev);
+ dma_reset_output(dev);
+ }
+ dmap->flags &= ~DMA_RESTART;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
- if (!dmap->dma_mode)
- {
- int err;
+ if (!dmap->dma_mode) {
+ int err;
- dmap->dma_mode = DMODE_OUTPUT;
- if ((err = audio_devs[dev]->prepare_for_output (dev,
- dmap->fragment_size, dmap->nbufs)) < 0)
- return err;
+ dmap->dma_mode = DMODE_OUTPUT;
+ if ((err = audio_devs[dev]->prepare_for_output(dev,
+ dmap->fragment_size, dmap->nbufs)) < 0)
+ return err;
}
+ flags = splhigh();
+ abort = 0;
+ while (!space_in_queue(dev) && !abort) {
+ int timeout;
- DISABLE_INTR (flags);
+ if (dontblock) {
+ splx(flags);
+ return -(EAGAIN);
+ }
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&
+ audio_devs[dev]->go) {
+ splx(flags);
+ return -(EAGAIN);
+ }
+ /*
+ * Wait for free space
+ */
+ if (!audio_devs[dev]->go)
+ timeout = 0;
+ else
+ timeout = 2 * hz;
- abort = 0;
- while (!space_in_queue (dev) &&
- !abort)
- {
- /*
- * Wait for free space
- */
- DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
- if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
{
- printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
- err = EIO;
- abort = 1;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ int chn;
+
+ out_sleep_flag[dev].mode = WK_SLEEP;
+ out_sleeper[dev] = &chn;
+ DO_SLEEP2(chn, out_sleep_flag[dev], timeout);
+
+ if ((out_sleep_flag[dev].mode & WK_TIMEOUT)) {
+ printf("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ abort = 1;
+ out_sleep_flag[dev].aborting = 1;
+ audio_devs[dev]->reset(dev);
+ } else if ((out_sleep_flag[dev].aborting) ||
+ CURSIG(curproc)) {
+ err = EINTR;
+ abort = 1;
}
- else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- err = EINTR;
- abort = 1;
}
}
- RESTORE_INTR (flags);
+ splx(flags);
- if (!space_in_queue (dev))
- {
- return RET_ERROR (err); /* Caught a signal ? */
+ if (!space_in_queue(dev)) {
+ return -(err); /* Caught a signal ? */
}
-
- *buf = dmap->buf[dmap->qtail];
- *size = dmap->fragment_size;
- dmap->counts[dmap->qtail] = 0;
-
- return dmap->qtail;
+ *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
+ *size = dmap->fragment_size;
+ dmap->counts[dmap->qtail] = 0;
+ return dmap->qtail;
}
int
-DMAbuf_start_output (int dev, int buff_no, int l)
+DMAbuf_start_output(int dev, int buff_no, int l)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
- if (buff_no != dmap->qtail)
- printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
+ /*
+ * Bypass buffering if using mmaped access
+ */
- dmap->qlen++;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) {
+ l = dmap->fragment_size;
+ dmap->counts[dmap->qtail] = l;
+ dmap->flags &= ~DMA_RESTART;
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ } else
+#else
+ if (dmap != NULL)
+#endif
+ {
- dmap->counts[dmap->qtail] = l;
+ if (buff_no != dmap->qtail)
+ printf("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
- if ((l != dmap->fragment_size) &&
- ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
- audio_devs[dev]->flags & NEEDS_RESTART))
- dmap->flags |= DMA_RESTART;
- else
- dmap->flags &= ~DMA_RESTART;
+ dmap->qlen++;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ dmap->counts[dmap->qtail] = l;
- if (!(dmap->flags & DMA_ACTIVE))
- {
- dmap->flags |= DMA_ACTIVE;
- audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
- dmap->counts[dmap->qhead], 0,
- !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
- !(dmap->flags & DMA_STARTED));
- dmap->flags |= DMA_STARTED;
- }
+ if ((l != dmap->fragment_size) &&
+ ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
+ audio_devs[dev]->flags & NEEDS_RESTART))
+ dmap->flags |= DMA_RESTART;
+ else
+ dmap->flags &= ~DMA_RESTART;
- return 0;
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ }
+ if (!(dmap->flags & DMA_ACTIVE)) {
+ dmap->flags |= DMA_ACTIVE;
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 0,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+ !(dmap->flags & DMA_STARTED));
+ dmap->flags |= DMA_STARTED;
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+ return 0;
}
int
-DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+DMAbuf_start_dma(int dev, u_long physaddr, int count, int dma_mode)
{
- int chan = audio_devs[dev]->dmachan;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
- unsigned long flags;
+ int chan;
+ struct dma_buffparms *dmap;
- /*
- * This function is not as portable as it should be.
- */
+ if (dma_mode == 1) {
+ chan = audio_devs[dev]->dmachan1;
+ dmap = audio_devs[dev]->dmap_out;
- /*
- * The count must be one less than the actual size. This is handled by
- * set_dma_addr()
- */
+ } else {
+ chan = audio_devs[dev]->dmachan2;
+ dmap = audio_devs[dev]->dmap_in;
+ }
- if (audio_devs[dev]->flags & DMA_AUTOMODE)
- { /*
- * Auto restart mode. Transfer the whole *
- * buffer
- */
-#ifdef linux
- DISABLE_INTR (flags);
- disable_dma (chan);
- clear_dma_ff (chan);
- set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
- set_dma_addr (chan, dmap->raw_buf_phys[0]);
- set_dma_count (chan, dmap->bytes_in_use);
- enable_dma (chan);
- RESTORE_INTR (flags);
-#else
+ /*
+ * The count must be one less than the actual size. This is handled
+ * by set_dma_addr()
+ */
-#ifdef __386BSD__
- printk ("sound: Invalid DMA mode for device %d\n", dev);
+#ifndef PSEUDO_DMA_AUTOINIT
+ if (audio_devs[dev]->flags & DMA_AUTOMODE) {
+ /* Auto restart mode. Transfer the whole buffer */
+ isa_dmastart(B_RAW | ((dma_mode == 0) ? B_READ : B_WRITE),
+ (caddr_t) dmap->raw_buf_phys, dmap->bytes_in_use, chan);
- isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
- dmap->raw_buf_phys[0],
- dmap->bytes_in_use,
- chan);
-#else
-#if defined(GENERIC_SYSV)
-#ifndef DMAMODE_AUTO
- printk ("sound: Invalid DMA mode for device %d\n", dev);
-#endif
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
-#ifdef DMAMODE_AUTO
- | DMAMODE_AUTO
+ } else
#endif
- ,
- dmap->raw_buf_phys[0], dmap->bytes_in_use);
- dma_enable (chan);
-#else
-#error This routine is not valid for this OS.
+ {
+ isa_dmastart((dma_mode == 0) ? B_READ : B_WRITE,
+ (caddr_t) physaddr, count, chan);
+ }
+ return count;
+}
+
+void
+DMAbuf_init()
+{
+ int dev;
+
+ /*
+ * NOTE! This routine could be called several times.
+ * XXX is it ok to make it run only the first time ? -- lr970710
+ */
+
+ for (dev = 0; dev < num_audiodevs; dev++)
+ if (audio_devs[dev]->dmap_out == NULL) {
+ audio_devs[dev]->dmap_out =
+ audio_devs[dev]->dmap_in = &dmaps[ndmaps++];
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_devs[dev]->dmap_in = &dmaps[ndmaps++];
+ }
+}
+
+void
+DMAbuf_outputintr(int dev, int event_type)
+{
+ /*
+ * Event types: 0 = DMA transfer done. Device still has more data in
+ * the local buffer. 1 = DMA transfer done. Device doesn't have local
+ * buffer or it's empty now. 2 = No DMA transfer but the device has
+ * now more space in it's local buffer.
+ */
+
+ u_long flags;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ dmap->byte_counter += dmap->counts[dmap->qhead];
+#ifdef OS_DMA_INTR
+ sound_dma_intr(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
#endif
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+ /* mmapped access */
+
+ int p = dmap->fragment_size * dmap->qhead;
+
+ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ dmap->qlen++; /* Yes increment it (don't decrement) */
+ dmap->flags &= ~DMA_ACTIVE;
+ dmap->counts[dmap->qhead] = dmap->fragment_size;
+
+ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) {
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+#ifdef PSEUDO_DMA_AUTOINIT
+ else {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1);
+ }
#endif
+ dmap->flags |= DMA_ACTIVE;
+ } else
#endif
- }
- else
- {
-#ifdef linux
- DISABLE_INTR (flags);
- disable_dma (chan);
- clear_dma_ff (chan);
- set_dma_mode (chan, dma_mode);
- set_dma_addr (chan, physaddr);
- set_dma_count (chan, count);
- enable_dma (chan);
- RESTORE_INTR (flags);
-#else
-#ifdef __386BSD__
- isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
- physaddr,
- count,
- chan);
-#else
+ if (event_type != 2) {
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) {
+ printf("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
+ return;
+ }
+ isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan1);
-#if defined(GENERIC_SYSV)
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
- physaddr, count);
- dma_enable (chan);
-#else
-#error This routine is not valid for this OS.
-#endif /* GENERIC_SYSV */
-#endif
+ dmap->qlen--;
+ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ dmap->flags &= ~DMA_ACTIVE;
+ if (dmap->qlen) {
+ /* if (!(audio_devs[dev]->flags & NEEDS_RESTART)) */
+ {
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+#ifdef PSEUDO_DMA_AUTOINIT
+ /* else */
+ {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1);
+ }
#endif
- }
-
- return count;
-}
+ dmap->flags |= DMA_ACTIVE;
+ } else if (event_type == 1) {
+ dmap->underrun_count++;
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+ audio_devs[dev]->halt_output)
+ audio_devs[dev]->halt_output(dev);
+ else
+ audio_devs[dev]->halt_xfer(dev);
+
+ if ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
+ audio_devs[dev]->flags & NEEDS_RESTART)
+ dmap->flags |= DMA_RESTART;
+ else
+ dmap->flags &= ~DMA_RESTART;
+ }
+ } /* event_type != 2 */
+ flags = splhigh();
-long
-DMAbuf_init (long mem_start)
-{
- int dev;
+ if ((out_sleep_flag[dev].mode & WK_SLEEP)) {
+ out_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(out_sleeper[dev]);
+ }
- /*
- * NOTE! This routine could be called several times.
- */
+ if(selinfo[dev].si_pid) {
+ selwakeup(&selinfo[dev]);
+ }
- for (dev = 0; dev < num_audiodevs; dev++)
- audio_devs[dev]->dmap = &dmaps[dev];
- return mem_start;
+ splx(flags);
}
void
-DMAbuf_outputintr (int dev, int event_type)
-{
- /*
- * Event types:
- * 0 = DMA transfer done. Device still has more data in the local
- * buffer.
- * 1 = DMA transfer done. Device doesn't have local buffer or it's
- * empty now.
- * 2 = No DMA transfer but the device has now more space in it's local
- * buffer.
- */
+DMAbuf_inputintr(int dev)
+{
+ u_long flags;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
- unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ dmap->byte_counter += dmap->fragment_size;
- if (event_type != 2)
- {
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- {
- printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
- return;
+#ifdef OS_DMA_INTR
+ sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+#endif
+ isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan2);
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ dmap->qlen++;
+
+ if (!(audio_devs[dev]->flags & NEEDS_RESTART)) {
+ audio_devs[dev]->start_input(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
}
+#ifdef PSEUDO_DMA_AUTOINIT
+ else {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->counts[dmap->qtail], 0);
+ }
+#endif
- dmap->qlen--;
- dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
- dmap->flags &= ~DMA_ACTIVE;
-
- if (dmap->qlen)
+ dmap->flags |= DMA_ACTIVE;
+ } else
+#endif
+ if (dmap->qlen == (dmap->nbufs - 1)) {
+ /* printf ("Sound: Recording overrun\n"); */
+ dmap->underrun_count++;
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+ audio_devs[dev]->halt_input)
+ audio_devs[dev]->halt_input(dev);
+ else
+ audio_devs[dev]->halt_xfer(dev);
+
+ dmap->flags &= ~DMA_ACTIVE;
+ if (audio_devs[dev]->flags & DMA_AUTOMODE)
+ dmap->flags |= DMA_RESTART;
+ else
+ dmap->flags &= ~DMA_RESTART;
+ } else {
+ dmap->qlen++;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+
+ /* if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) */
{
- audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
- dmap->counts[dmap->qhead], 1,
- !(audio_devs[dev]->flags & DMA_AUTOMODE));
- dmap->flags |= DMA_ACTIVE;
+ audio_devs[dev]->start_input(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
}
- else if (event_type == 1)
+#ifdef PSEUDO_DMA_AUTOINIT
+ /* else */
{
- dmap->underrun_count++;
- audio_devs[dev]->halt_xfer (dev);
- if ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
- audio_devs[dev]->flags & NEEDS_RESTART)
- dmap->flags |= DMA_RESTART;
- else
- dmap->flags &= ~DMA_RESTART;
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->counts[dmap->qtail], 0);
}
- } /* event_type != 2 */
+#endif
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
+ dmap->flags |= DMA_ACTIVE;
+ }
+
+ flags = splhigh();
+ if ((in_sleep_flag[dev].mode & WK_SLEEP)) {
+ in_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(in_sleeper[dev]);
}
- RESTORE_INTR (flags);
+ if (selinfo[dev].si_pid)
+ selwakeup(&selinfo[dev]);
+ splx(flags);
+}
+
+int
+DMAbuf_open_dma(int dev)
+{
+ int err;
+ u_long flags;
+ flags = splhigh();
+
+ if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out,
+ audio_devs[dev]->dmachan1)) < 0) {
+ splx(flags);
+ return -(EBUSY);
+ }
+ dma_init_buffers(dev, audio_devs[dev]->dmap_out);
+ /* audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; */
+ audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize;
+ /* reorganize_buffers (dev, audio_devs[dev]->dmap_out); */
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX) {
+ if ((err = open_dmap(dev, OPEN_READWRITE,
+ audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2)) < 0) {
+ printf("Unable to grab DMA%d for the audio driver\n",
+ audio_devs[dev]->dmachan2);
+ close_dmap(dev, audio_devs[dev]->dmap_out,
+ audio_devs[dev]->dmachan1);
+ splx(flags);
+ return -(EBUSY);
+ }
+ dma_init_buffers(dev, audio_devs[dev]->dmap_in);
+ /* audio_devs[dev]->dmap_in->flags |= DMA_ALLOC_DONE; */
+ audio_devs[dev]->dmap_in->fragment_size = audio_devs[dev]->buffsize;
+ /* reorganize_buffers (dev, audio_devs[dev]->dmap_in); */
+ } else {
+ audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
+ audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
+ }
+
+ splx(flags);
+ return 0;
}
void
-DMAbuf_inputintr (int dev)
+DMAbuf_close_dma(int dev)
{
- unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ DMAbuf_reset_dma(dev);
+ close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
- if (dmap->qlen == (dmap->nbufs - 1))
- {
- printk ("Sound: Recording overrun\n");
- dmap->underrun_count++;
- audio_devs[dev]->halt_xfer (dev);
- dmap->flags &= ~DMA_ACTIVE;
- if (audio_devs[dev]->flags & DMA_AUTOMODE)
- dmap->flags |= DMA_RESTART;
- else
- dmap->flags &= ~DMA_RESTART;
- }
- else
- {
- dmap->qlen++;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
- audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
- dmap->fragment_size, 1,
- !(audio_devs[dev]->flags & DMA_AUTOMODE));
- dmap->flags |= DMA_ACTIVE;
- }
+}
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
- }
- RESTORE_INTR (flags);
+void
+DMAbuf_reset_dma(int dev)
+{
}
+#ifdef ALLOW_POLL
+
int
-DMAbuf_open_dma (int dev)
+DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait)
{
- unsigned long flags;
- int chan = audio_devs[dev]->dmachan;
+ struct dma_buffparms *dmap;
+ u_long flags;
+ int revents = 0;
+
+ dmap = audio_devs[dev]->dmap_in;
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (dmap->dma_mode != DMODE_INPUT) {
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen &&
+ audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
+ audio_devs[dev]->go) {
+ u_long flags;
+
+ flags = splhigh();
+
+ activate_recording(dev, dmap);
+ splx(flags);
+
+ }
+ return 0;
+ }
+ if (!dmap->qlen) {
+ flags = splhigh();
+
+ selrecord(wait, &selinfo[dev]);
+
+ splx(flags);
+
+ return 0;
+ } else
+ revents |= events & (POLLIN | POLLRDNORM);
- if (ALLOC_DMA_CHN (chan))
- {
- printk ("Unable to grab DMA%d for the audio driver\n", chan);
- return RET_ERROR (EBUSY);
}
- DISABLE_INTR (flags);
-#ifdef linux
- disable_dma (chan);
- clear_dma_ff (chan);
-#endif
- RESTORE_INTR (flags);
+ if (events & (POLLOUT | POLLWRNORM)) {
+
+ dmap = audio_devs[dev]->dmap_out;
+ if (dmap->dma_mode == DMODE_INPUT)
+ return 0;
+
+ if (dmap->dma_mode == DMODE_NONE)
+ return ( events & (POLLOUT | POLLWRNORM));
+
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+
+ if(dmap->qlen)
+ return 1;
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+
+ splx(flags);
+
+ return 0;
+
+ }
+ if (!space_in_queue(dev)) {
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
- return 0;
-}
+ } else
+ revents |= events & (POLLOUT | POLLWRNORM);
-void
-DMAbuf_close_dma (int dev)
-{
- int chan = audio_devs[dev]->dmachan;
- DMAbuf_reset_dma (chan);
- RELEASE_DMA_CHN (chan);
+ }
+
+ return (revents);
}
-void
-DMAbuf_reset_dma (int chan)
+
+#ifdef amancio
+int
+DMAbuf_select(int dev, struct fileinfo * file, int sel_type, select_table * wait)
{
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ struct dma_buffparms *dmapin = audio_devs[dev]->dmap_in;
+ u_long flags;
+
+ switch (sel_type) {
+ case FREAD:
+ if (dmapin->dma_mode != DMODE_INPUT)
+ return 0;
+
+ if (!dmap->qlen) {
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
+
+ return 0;
+ }
+ return 1;
+ break;
+
+ case FWRITE:
+ if (dmap->dma_mode == DMODE_INPUT)
+ return 0;
+
+ if (dmap->dma_mode == DMODE_NONE)
+ return 1;
+
+ if (!space_in_queue(dev)) {
+ flags = splhigh();
+
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
+
+ return 0;
+ }
+ return 1;
+ break;
+
+ }
+
+ return 0;
}
-/*
- * 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.
- */
+#endif /* ALLOW_POLL */
+#endif
-#else
+#else /* CONFIG_AUDIO */
/*
* Stub versions if audio services not included
*/
int
-DMAbuf_open (int dev, int mode)
+DMAbuf_open(int dev, int mode)
{
- return RET_ERROR (ENXIO);
+ return -(ENXIO);
}
int
-DMAbuf_release (int dev, int mode)
+DMAbuf_release(int dev, int mode)
{
- return 0;
+ return 0;
}
int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_rmchars (int dev, int buff_no, int c)
+DMAbuf_rmchars(int dev, int buff_no, int c)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_start_output (int dev, int buff_no, int l)
+DMAbuf_start_output(int dev, int buff_no, int l)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+DMAbuf_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
-long
-DMAbuf_init (long mem_start)
+void
+DMAbuf_init()
{
- return mem_start;
}
int
-DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+DMAbuf_start_dma(int dev, u_long physaddr, int count, int dma_mode)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_open_dma (int chan)
+DMAbuf_open_dma(int dev)
{
- return RET_ERROR (ENXIO);
+ return -(ENXIO);
}
void
-DMAbuf_close_dma (int chan)
+DMAbuf_close_dma(int dev)
{
- return;
+ return;
}
void
-DMAbuf_reset_dma (int chan)
+DMAbuf_reset_dma(int dev)
{
- return;
+ return;
}
void
-DMAbuf_inputintr (int dev)
+DMAbuf_inputintr(int dev)
{
- return;
+ return;
}
void
-DMAbuf_outputintr (int dev, int underrun_flag)
+DMAbuf_outputintr(int dev, int underrun_flag)
{
- return;
+ return;
}
-
-#endif
-
-#endif
+#endif /* CONFIG_AUDIO */
diff --git a/sys/i386/isa/sound/gus_card.c b/sys/i386/isa/sound/gus_card.c
index 614532c7d114..2f73ce61c72c 100644
--- a/sys/i386/isa/sound/gus_card.c
+++ b/sys/i386/isa/sound/gus_card.c
@@ -1,10 +1,10 @@
/*
* sound/gus_card.c
- *
+ *
* Detection routine for the Gravis Ultrasound.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,143 +24,138 @@
* 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"
+#include <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+#if defined(CONFIG_GUS)
-#include "gus_hw.h"
-
-void gusintr (int);
+#include <i386/isa/sound/gus_hw.h>
+#include <i386/isa/sound/iwdefs.h>
int gus_base, gus_irq, gus_dma;
extern int gus_wave_volume;
extern int gus_pcm_volume;
extern int have_gus_max;
+extern int gus_timer_enabled;
+
+sound_os_info *gus_osp;
+
+#ifndef NOGUSPNP
+int IwaveOpen(char voices, char mode, struct address_info * hw);
+#endif
-long
-attach_gus_card (long mem_start, struct address_info *hw_config)
+void
+attach_gus_card(struct address_info * hw_config)
{
- int io_addr;
+ int io_addr;
- snd_set_irq_handler (hw_config->irq, gusintr);
+ gus_osp = hw_config->osp;
- if (gus_wave_detect (hw_config->io_base)) /*
- * Try first the default
- */
- {
- mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
-#ifndef EXCLUDE_MIDI
- mem_start = gus_midi_init (mem_start);
-#endif
-#ifndef EXCLUDE_SEQUENCER
- sound_timer_init (hw_config->io_base + 8);
+ snd_set_irq_handler(hw_config->irq, gusintr, hw_config->osp);
+
+ if (gus_wave_detect(hw_config->io_base)) {
+ /* Try first the default */
+ gus_wave_init(hw_config);
+
+ /* 0x10c-> is MAX */
+
+ if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
+ if (0)
+ printf("gus_card.c: Can't allocate DMA channel2\n");
+#ifdef CONFIG_MIDI
+ gus_midi_init();
#endif
- return mem_start;
+ return ;
}
-
#ifndef EXCLUDE_GUS_IODETECT
- /*
- * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
- */
-
- for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
- if (io_addr != hw_config->io_base) /*
- * Already tested
- */
- if (gus_wave_detect (io_addr))
- {
- printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
- mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
-#ifndef EXCLUDE_MIDI
- mem_start = gus_midi_init (mem_start);
+ /*
+ * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
+ */
+
+ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
+ if ( (io_addr != hw_config->io_base) /* Already tested */
+ && (gus_wave_detect(io_addr)) ) {
+ hw_config->io_base = io_addr;
+
+ printf(" WARNING! GUS found at %x, config was %x ",
+ io_addr, hw_config->io_base);
+ gus_wave_init(hw_config);
+ /* 0x10c-> is MAX */
+ if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
+ if (0)
+ printf("gus_card.c: Can't allocate DMA channel2\n");
+#ifdef CONFIG_MIDI
+ gus_midi_init();
#endif
-#ifndef EXCLUDE_SEQUENCER
- sound_timer_init (io_addr + 8);
-#endif
- return mem_start;
+ return ;
}
-
#endif
-
- return mem_start; /*
- * Not detected
- */
}
int
-probe_gus (struct address_info *hw_config)
+probe_gus(struct address_info * hw_config)
{
- int io_addr;
-
- if (gus_wave_detect (hw_config->io_base))
- return 1;
+ int io_addr;
-#ifndef EXCLUDE_GUS_IODETECT
-
- /*
- * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
- */
-
- for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
- if (io_addr != hw_config->io_base) /*
- * Already tested
- */
- if (gus_wave_detect (io_addr))
+ gus_osp = hw_config->osp;
+#ifndef NOGUSPNP
+ IwaveOpen((char) 32, (char) GUS_MODE, hw_config);
+#endif
+ if (gus_wave_detect(hw_config->io_base))
return 1;
+ printf("oops I didnt find gus \n");
+#undef EXCLUDE_GUS_IODETECT
+#ifndef EXCLUDE_GUS_IODETECT
+ /*
+ * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
+ */
+ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
+ if ( (io_addr != hw_config->io_base) /* Already tested */
+ && (gus_wave_detect(io_addr)) ) {
+ hw_config->io_base = io_addr;
+ return 1;
+ }
#endif
- return 0;
+ return 0;
}
void
-gusintr (int irq)
+gusintr(int irq)
{
- unsigned char src;
-
-#ifdef linux
- sti ();
-#endif
+ u_char src;
-#ifndef EXCLUDE_GUSMAX
- if (have_gus_max)
- ad1848_interrupt (irq);
+#ifdef CONFIG_GUSMAX
+ if (have_gus_max)
+ ad1848_interrupt(irq);
#endif
- while (1)
- {
- if (!(src = INB (u_IrqStatus)))
- return;
+ for (;;) {
+ if (!(src = inb(u_IrqStatus)))
+ return;
- if (src & DMA_TC_IRQ)
- {
- guswave_dma_irq ();
- }
-
- if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
- {
-#ifndef EXCLUDE_MIDI
- gus_midi_interrupt (0);
+ if (src & DMA_TC_IRQ)
+ guswave_dma_irq();
+#ifdef CONFIG_MIDI
+ if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
+ gus_midi_interrupt(0);
#endif
- }
-
- if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
- {
-#ifndef EXCLUDE_SEQUENCER
- sound_timer_interrupt ();
+ if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) {
+#ifdef CONFIG_SEQUENCER
+ if (gus_timer_enabled)
+ sound_timer_interrupt();
+ gus_write8(0x45, 0); /* Ack IRQ */
+ gus_timer_command(4, 0x80); /* Reset IRQ flags */
#else
- gus_write8 (0x45, 0); /* Stop timers */
+ gus_write8(0x45, 0); /* Stop timers */
#endif
}
-
- if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
- {
- gus_voice_irq ();
- }
+ if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
+ gus_voice_irq();
}
}
@@ -169,25 +164,25 @@ gusintr (int irq)
/*
* Some extra code for the 16 bit sampling option
*/
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16)
+#if defined(CONFIG_GUS16)
int
-probe_gus_db16 (struct address_info *hw_config)
+probe_gus_db16(struct address_info * hw_config)
{
- return ad1848_detect (hw_config->io_base);
+ return ad1848_detect(hw_config->io_base, NULL, hw_config->osp);
}
-long
-attach_gus_db16 (long mem_start, struct address_info *hw_config)
+void
+attach_gus_db16(struct address_info * hw_config)
{
- gus_pcm_volume = 100;
- gus_wave_volume = 90;
-
- ad1848_init ("GUS 16 bit sampling", hw_config->io_base,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma);
- return mem_start;
+ gus_pcm_volume = 100;
+ gus_wave_volume = 90;
+
+ ad1848_init("GUS 16 bit sampling", hw_config->io_base,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma, 0,
+ hw_config->osp);
}
#endif
diff --git a/sys/i386/isa/sound/gus_midi.c b/sys/i386/isa/sound/gus_midi.c
index 87aea6251daf..0dfc7c502a33 100644
--- a/sys/i386/isa/sound/gus_midi.c
+++ b/sys/i386/isa/sound/gus_midi.c
@@ -1,10 +1,10 @@
/*
* sound/gus2_midi.c
- *
+ *
* The low level driver for the GUS Midi Interface.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,16 +24,13 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
-#include "sound_config.h"
+#include <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
-
-#include "gus_hw.h"
-
-#if !defined(EXCLUDE_GUS) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_GUS) && defined(CONFIG_MIDI)
+#include <i386/isa/sound/gus_hw.h>
static int midi_busy = 0, input_opened = 0;
static int my_dev;
@@ -46,264 +43,232 @@ static unsigned char tmp_queue[256];
static volatile int qlen;
static volatile unsigned char qhead, qtail;
extern int gus_base, gus_irq, gus_dma;
+extern sound_os_info *gus_osp;
-#define GUS_MIDI_STATUS() INB(u_MidiStatus)
+#define GUS_MIDI_STATUS() inb( u_MidiStatus)
static int
-gus_midi_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
+gus_midi_open(int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
)
{
- if (midi_busy)
- {
- printk ("GUS: Midi busy\n");
- return RET_ERROR (EBUSY);
- }
-
- OUTB (MIDI_RESET, u_MidiControl);
- gus_delay ();
-
- gus_midi_control = 0;
- input_opened = 0;
-
- if (mode == OPEN_READ || mode == OPEN_READWRITE)
- {
- gus_midi_control |= MIDI_ENABLE_RCV;
- input_opened = 1;
- }
+ if (midi_busy) {
+ printf("GUS: Midi busy\n");
+ return -(EBUSY);
+ }
+ outb(u_MidiControl, MIDI_RESET);
+ gus_delay();
- if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
- {
- gus_midi_control |= MIDI_ENABLE_XMIT;
- }
+ gus_midi_control = 0;
+ input_opened = 0;
- OUTB (gus_midi_control, u_MidiControl); /*
- * Enable
- */
+ if (mode == OPEN_READ || mode == OPEN_READWRITE) {
+ gus_midi_control |= MIDI_ENABLE_RCV;
+ input_opened = 1;
+ }
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE) {
+ gus_midi_control |= MIDI_ENABLE_XMIT;
+ }
+ outb(u_MidiControl, gus_midi_control); /* Enable */
- midi_busy = 1;
- qlen = qhead = qtail = output_used = 0;
- midi_input_intr = input;
+ midi_busy = 1;
+ qlen = qhead = qtail = output_used = 0;
+ midi_input_intr = input;
- return 0;
+ return 0;
}
static int
-dump_to_midi (unsigned char midi_byte)
+dump_to_midi(unsigned char midi_byte)
{
- unsigned long flags;
- int ok = 0;
-
- output_used = 1;
-
- DISABLE_INTR (flags);
-
- if (GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY)
- {
- ok = 1;
- OUTB (midi_byte, u_MidiData);
- }
- else
- {
- /*
- * Enable Midi xmit interrupts (again)
- */
- gus_midi_control |= MIDI_ENABLE_XMIT;
- OUTB (gus_midi_control, u_MidiControl);
- }
-
- RESTORE_INTR (flags);
- return ok;
+ unsigned long flags;
+ int ok = 0;
+
+ output_used = 1;
+
+ flags = splhigh();
+
+ if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY) {
+ ok = 1;
+ outb(u_MidiData, midi_byte);
+ } else {
+ /*
+ * Enable Midi xmit interrupts (again)
+ */
+ gus_midi_control |= MIDI_ENABLE_XMIT;
+ outb(u_MidiControl, gus_midi_control);
+ }
+
+ splx(flags);
+ return ok;
}
static void
-gus_midi_close (int dev)
+gus_midi_close(int dev)
{
- /*
- * Reset FIFO pointers, disable intrs
- */
+ /*
+ * Reset FIFO pointers, disable intrs
+ */
- OUTB (MIDI_RESET, u_MidiControl);
- midi_busy = 0;
+ outb(u_MidiControl, MIDI_RESET);
+ midi_busy = 0;
}
static int
-gus_midi_out (int dev, unsigned char midi_byte)
+gus_midi_out(int dev, unsigned char midi_byte)
{
- unsigned long flags;
+ unsigned long flags;
- /*
- * Drain the local queue first
- */
+ /*
+ * Drain the local queue first
+ */
- DISABLE_INTR (flags);
+ flags = splhigh();
- while (qlen && dump_to_midi (tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
+ while (qlen && dump_to_midi(tmp_queue[qhead])) {
+ qlen--;
+ qhead++;
+ }
- RESTORE_INTR (flags);
+ splx(flags);
- /*
- * Output the byte if the local queue is empty.
- */
+ /*
+ * Output the byte if the local queue is empty.
+ */
- if (!qlen)
- if (dump_to_midi (midi_byte))
- return 1; /*
- * OK
- */
+ if (!qlen)
+ if (dump_to_midi(midi_byte))
+ return 1; /* OK */
- /*
- * Put to the local queue
- */
+ /*
+ * Put to the local queue
+ */
- if (qlen >= 256)
- return 0; /*
- * Local queue full
- */
+ if (qlen >= 256)
+ return 0; /* Local queue full */
- DISABLE_INTR (flags);
+ flags = splhigh();
- tmp_queue[qtail] = midi_byte;
- qlen++;
- qtail++;
+ tmp_queue[qtail] = midi_byte;
+ qlen++;
+ qtail++;
- RESTORE_INTR (flags);
+ splx(flags);
- return 1;
+ return 1;
}
static int
-gus_midi_start_read (int dev)
+gus_midi_start_read(int dev)
{
- return 0;
+ return 0;
}
static int
-gus_midi_end_read (int dev)
+gus_midi_end_read(int dev)
{
- return 0;
+ return 0;
}
static int
-gus_midi_ioctl (int dev, unsigned cmd, unsigned arg)
+gus_midi_ioctl(int dev, unsigned cmd, ioctl_arg arg)
{
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static void
-gus_midi_kick (int dev)
+gus_midi_kick(int dev)
{
}
static int
-gus_midi_buffer_status (int dev)
+gus_midi_buffer_status(int dev)
{
- unsigned long flags;
+ unsigned long flags;
- if (!output_used)
- return 0;
+ if (!output_used)
+ return 0;
- DISABLE_INTR (flags);
+ flags = splhigh();
- if (qlen && dump_to_midi (tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
-
- RESTORE_INTR (flags);
+ if (qlen && dump_to_midi(tmp_queue[qhead])) {
+ qlen--;
+ qhead++;
+ }
+ splx(flags);
- return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY);
+ return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
}
#define MIDI_SYNTH_NAME "Gravis Ultrasound Midi"
#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
-#include "midi_synth.h"
+#include <i386/isa/sound/midi_synth.h>
static struct midi_operations gus_midi_operations =
{
- {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
- &std_midi_synth,
- gus_midi_open,
- gus_midi_close,
- gus_midi_ioctl,
- gus_midi_out,
- gus_midi_start_read,
- gus_midi_end_read,
- gus_midi_kick,
- NULL, /*
- * command
- */
- gus_midi_buffer_status,
- NULL
+ {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
+ &std_midi_synth,
+ {0},
+ gus_midi_open,
+ gus_midi_close,
+ gus_midi_ioctl,
+ gus_midi_out,
+ gus_midi_start_read,
+ gus_midi_end_read,
+ gus_midi_kick,
+ NULL, /* command */
+ gus_midi_buffer_status,
+ NULL
};
-long
-gus_midi_init (long mem_start)
+void
+gus_midi_init()
{
- if (num_midis >= MAX_MIDI_DEV)
- {
- printk ("Sound: Too many midi devices detected\n");
- return mem_start;
- }
-
- OUTB (MIDI_RESET, u_MidiControl);
+ if (num_midis >= MAX_MIDI_DEV) {
+ printf("Sound: Too many midi devices detected\n");
+ return;
+ }
+ outb(u_MidiControl, MIDI_RESET);
- std_midi_synth.midi_dev = my_dev = num_midis;
- midi_devs[num_midis++] = &gus_midi_operations;
- return mem_start;
+ std_midi_synth.midi_dev = my_dev = num_midis;
+ midi_devs[num_midis++] = &gus_midi_operations;
+ return;
}
void
-gus_midi_interrupt (int dummy)
+gus_midi_interrupt(int dummy)
{
- unsigned char stat, data;
- unsigned long flags;
-
- DISABLE_INTR (flags);
-
- stat = GUS_MIDI_STATUS ();
-
- if (stat & MIDI_RCV_FULL)
- {
- data = INB (u_MidiData);
- if (input_opened)
- midi_input_intr (my_dev, data);
- }
-
- if (stat & MIDI_XMIT_EMPTY)
- {
- while (qlen && dump_to_midi (tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
+ unsigned char stat, data;
+ unsigned long flags;
- if (!qlen)
- {
- /*
- * Disable Midi output interrupts, since no data in the buffer
- */
- gus_midi_control &= ~MIDI_ENABLE_XMIT;
- OUTB (gus_midi_control, u_MidiControl);
- }
- }
+ flags = splhigh();
- if (stat & MIDI_FRAME_ERR)
- printk ("Midi framing error\n");
- if (stat & MIDI_OVERRUN && input_opened)
- printk ("GUS: Midi input overrun\n");
+ stat = GUS_MIDI_STATUS();
- RESTORE_INTR (flags);
+ if (stat & MIDI_RCV_FULL) {
+ data = inb(u_MidiData);
+ if (input_opened)
+ midi_input_intr(my_dev, data);
+ }
+ if (stat & MIDI_XMIT_EMPTY) {
+ while (qlen && dump_to_midi(tmp_queue[qhead])) {
+ qlen--;
+ qhead++;
+ }
+
+ if (!qlen) {
+ /*
+ * Disable Midi output interrupts, since no data in
+ * the buffer
+ */
+ gus_midi_control &= ~MIDI_ENABLE_XMIT;
+ outb(u_MidiControl, gus_midi_control);
+ }
+ }
+ splx(flags);
}
#endif
-
-#endif
diff --git a/sys/i386/isa/sound/gus_vol.c b/sys/i386/isa/sound/gus_vol.c
index 055a1170e9fb..fc66618f3b9c 100644
--- a/sys/i386/isa/sound/gus_vol.c
+++ b/sys/i386/isa/sound/gus_vol.c
@@ -1,16 +1,19 @@
/*
* gus_vol.c - Compute volume for GUS.
- *
+ *
* Greg Lee 1993.
*/
-#include "sound_config.h"
-#ifndef EXCLUDE_GUS
-#include "gus_linearvol.h"
+#include <i386/isa/sound/sound_config.h>
+
+#ifdef CONFIG_GUS
+#include <i386/isa/sound/gus_linearvol.h>
#define GUS_VOLUME gus_wave_volume
extern int gus_wave_volume;
+unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
+unsigned short gus_linear_vol(int vol, int mainvol);
/*
* Calculate gus volume from note velocity, main volume, expression, and
@@ -21,93 +24,87 @@ 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.
*/
unsigned short
-gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
+gus_adagio_vol(int vel, int mainv, int xpn, int voicev)
{
- int i, m, n, x;
-
-
- /*
- * A voice volume of 64 is considered neutral, so adjust the main volume if
- * something other than this neutral value was assigned in the patch
- * library.
- */
- x = 256 + 6 * (voicev - 64);
-
- /*
- * Boost expression by voice volume above neutral.
- */
- if (voicev > 65)
- xpn += voicev - 64;
- xpn += (voicev - 64) / 2;
-
- /*
- * Combine multiplicative and level components.
- */
- x = vel * xpn * 6 + (voicev / 4) * x;
+ int i, m, n, x;
+
+ /*
+ * A voice volume of 64 is considered neutral, so adjust the main
+ * volume if something other than this neutral value was assigned in
+ * the patch library.
+ */
+ x = 256 + 6 * (voicev - 64);
+
+ /*
+ * Boost expression by voice volume above neutral.
+ */
+ if (voicev > 65)
+ xpn += voicev - 64;
+ xpn += (voicev - 64) / 2;
+
+ /*
+ * Combine multiplicative and level components.
+ */
+ x = vel * xpn * 6 + (voicev / 4) * x;
#ifdef GUS_VOLUME
- /*
- * Further adjustment by installation-specific master volume control
- * (default 60).
- */
- x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
+ /*
+ * Further adjustment by installation-specific master volume control
+ * (default 60).
+ */
+ x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
#endif
#ifdef GUS_USE_CHN_MAIN_VOLUME
- /*
- * Experimental support for the channel main volume
- */
+ /*
+ * Experimental support for the channel main volume
+ */
- mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
- x = (x * mainv * mainv) / 16384;
+ mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
+ x = (x * mainv * mainv) / 16384;
#endif
- if (x < 2)
- return (0);
- else if (x >= 65535)
- return ((15 << 8) | 255);
-
- /*
- * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
- * mantissa m.
- */
- n = x;
- i = 7;
- if (n < 128)
- {
- while (i > 0 && n < (1 << i))
- i--;
+ if (x < 2)
+ return (0);
+ else if (x >= 65535)
+ return ((15 << 8) | 255);
+
+ /*
+ * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
+ * mantissa m.
+ */
+ n = x;
+ i = 7;
+ if (n < 128) {
+ while (i > 0 && n < (1 << i))
+ i--;
+ } else
+ while (n > 255) {
+ n >>= 1;
+ i++;
+ }
+ /*
+ * Mantissa is part of linear volume not expressed in exponent.
+ * (This is not quite like real logs -- I wonder if it's right.)
+ */
+ m = x - (1 << i);
+
+ /*
+ * Adjust mantissa to 8 bits.
+ */
+ if (m > 0) {
+ if (i > 8)
+ m >>= i - 8;
+ else if (i < 8)
+ m <<= 8 - i;
}
- else
- while (n > 255)
- {
- n >>= 1;
- i++;
- }
- /*
- * Mantissa is part of linear volume not expressed in exponent. (This is
- * not quite like real logs -- I wonder if it's right.)
- */
- m = x - (1 << i);
-
- /*
- * Adjust mantissa to 8 bits.
- */
- if (m > 0)
- {
- if (i > 8)
- m >>= i - 8;
- else if (i < 8)
- m <<= 8 - i;
- }
-
- return ((i << 8) + m);
+ return ((i << 8) + m);
}
/*
@@ -117,31 +114,25 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
*/
unsigned short
-gus_linear_vol (int vol, int mainvol)
+gus_linear_vol(int vol, int mainvol)
{
- int mixer_mainvol;
+ int mixer_mainvol;
- if (vol <= 0)
- vol = 0;
- else if (vol >= 127)
- vol = 127;
+ RANGE (vol, 0, 127) ;
#ifdef GUS_VOLUME
- mixer_mainvol = GUS_VOLUME;
+ mixer_mainvol = GUS_VOLUME;
#else
- mixer_mainvol = 100;
+ mixer_mainvol = 100;
#endif
#ifdef GUS_USE_CHN_MAIN_VOLUME
- if (mainvol <= 0)
- mainvol = 0;
- else if (mainvol >= 127)
- mainvol = 127;
+ RANGE (mainvol, 0, 127);
#else
- mainvol = 128;
+ mainvol = 127;
#endif
- return gus_linearvol[(((vol * mainvol) / 128) * mixer_mainvol) / 100];
+ return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100];
}
#endif
diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c
index 5f8e39c8ae5b..8cb3419dffa8 100644
--- a/sys/i386/isa/sound/gus_wave.c
+++ b/sys/i386/isa/sound/gus_wave.c
@@ -1,10 +1,10 @@
/*
* sound/gus_wave.c
- *
+ *
* Driver for the Gravis UltraSound wave table synth.
- *
+ *
* Copyright by Hannu Savolainen 1993, 1994
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* 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,76 +24,109 @@
* 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"
-#include "ultrasound.h"
-#include "gus_hw.h"
+#include <i386/isa/sound/sound_config.h>
+#include <i386/isa/sound/ultrasound.h>
+#include <i386/isa/sound/gus_hw.h>
+#include <i386/isa/sound/iwdefs.h>
+#include <machine/clock.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+/* PnP stuff */
+#define GUS_PNP_ID 0x100561e
-#define MAX_SAMPLE 128
+#define MAX_CARDS 8
+#define MAX_GUS_PNP 12
+
+
+/* Static ports */
+#define PADDRESS 0x279
+#define PWRITE_DATA 0xa79
+#define SET_CSN 0x06
+#define PSTATUS 0x05
+
+/* PnP Registers. Write to ADDRESS and then use WRITE/READ_DATA */
+#define SET_RD_DATA 0x00
+#define SERIAL_ISOLATION 0x01
+#define WAKE 0x03
+
+#if defined(CONFIG_GUS)
+
+IWAVE iw;
+#define ENTER_CRITICAL
+
+#define LEAVE_CRITICAL
+
+#define MAX_SAMPLE 150
#define MAX_PATCH 256
-struct voice_info
- {
- unsigned long orig_freq;
- unsigned long current_freq;
- unsigned long mode;
- int bender;
- int bender_range;
- int panning;
- int midi_volume;
- unsigned int initial_volume;
- unsigned int current_volume;
- int loop_irq_mode, loop_irq_parm;
+
+u_int gus_pnp_found[MAX_GUS_PNP] =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+struct voice_info {
+ u_long orig_freq;
+ u_long current_freq;
+ u_long mode;
+ int bender;
+ int bender_range;
+ int panning;
+ int midi_volume;
+ u_int initial_volume;
+ u_int current_volume;
+ int loop_irq_mode, loop_irq_parm;
#define LMODE_FINISH 1
#define LMODE_PCM 2
#define LMODE_PCM_STOP 3
- int volume_irq_mode, volume_irq_parm;
+ 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];
- unsigned char env_offset[6];
+ int env_phase;
+ u_char env_rate[6];
+ u_char env_offset[6];
- /*
- * Volume computation parameters for gus_adagio_vol()
- */
- int main_vol, expression_vol, patch_vol;
+ /*
+ * Volume computation parameters for gus_adagio_vol()
+ */
+ 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;
+ /* Variables for "Ultraclick" removal */
+ int dev_pending, note_pending, volume_pending, sample_pending;
+ char kill_pending;
+ long offset_pending;
- };
+};
static struct voice_alloc_info *voice_alloc;
extern int gus_base;
extern int gus_irq, gus_dma;
+static int gus_dma2 = -1;
+static int dual_dma_mode = 0;
static long gus_mem_size = 0;
static long free_mem_ptr = 0;
-static int gus_busy = 0;
+static int gus_no_dma = 0;
static int nr_voices = 0;
static int gus_devnum = 0;
static int volume_base, volume_scale, volume_method;
static int gus_recmask = SOUND_MASK_MIC;
static int recording_active = 0;
+static int only_read_access = 0;
+static int only_8_bits = 0;
int gus_wave_volume = 60;
int gus_pcm_volume = 80;
int have_gus_max = 0;
static int gus_line_vol = 100, gus_mic_vol = 0;
-static unsigned char mix_image = 0x00;
+static u_char mix_image = 0x00;
+int gus_timer_enabled = 0;
/*
- * Current version of this driver doesn't allow synth and PCM functions
- * at the same time. The active_device specifies the active driver
+ * 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;
@@ -105,7 +138,9 @@ static int gus_sampling_speed;
static int gus_sampling_channels;
static int gus_sampling_bits;
-DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
+static int *dram_sleeper = NULL;
+static volatile struct snd_wait dram_sleep_flag =
+{0};
/*
* Variables and buffers for PCM output
@@ -120,39 +155,45 @@ static volatile int dma_active;
static int pcm_opened = 0;
static int pcm_current_dev;
static int pcm_current_block;
-static unsigned long pcm_current_buf;
+static u_long pcm_current_buf;
static int pcm_current_count;
static int pcm_current_intrflag;
+extern sound_os_info *gus_osp;
+
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;
+struct patch_info *dbg_samples;
+int dbg_samplep;
+
static long sample_ptrs[MAX_SAMPLE + 1];
static int sample_map[32];
static int free_sample;
+static int mixer_type = 0;
static int patch_table[MAX_PATCH];
@@ -161,3086 +202,4673 @@ static int patch_map[32];
static struct synth_info gus_info =
{"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH};
-static void gus_poke (long addr, unsigned char data);
-static void compute_and_set_volume (int voice, int volume, int ramp_time);
-extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
-extern unsigned short gus_linear_vol (int vol, int mainvol);
-static void compute_volume (int voice, int volume);
-static void do_volume_irq (int voice);
-static void set_input_volumes (void);
+static void gus_default_mixer_init(void);
+
+int guswave_start_note2(int dev, int voice, int note_num, int volume);
+static void gus_poke(long addr, u_char data);
+void compute_and_set_volume(int voice, int volume, int ramp_time);
+extern u_short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
+extern u_short gus_linear_vol(int vol, int mainvol);
+void compute_volume(int voice, int volume);
+void do_volume_irq(int voice);
+static void set_input_volumes(void);
+static void gus_tmr_install(int io_base);
+
+void SEND(int d, int r);
+int get_serial(int rd_port, u_char *data);
+void send_Initiation_LFSR(void);
+int isolation_protocol(int rd_port);
+
#define INSTANT_RAMP -1 /* Instant change. No ramping */
#define FAST_RAMP 0 /* Fastest possible ramp */
+
+/* Crystal Select */
+#define CODEC_XTAL2 0x01 /* 16.9344 crystal */
+#define CODEC_XTAL1 0x00 /* 24.576 crystal */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for CONFIG_1 register */
+#define CODEC_CFIG1I_DEFAULT 0x03 | 0x8
+#define CODEC_CAPTURE_PIO 0x80 /* Capture PIO enable */
+#define CODEC_PLAYBACK_PIO 0x40 /* Playback PIO enable */
+#define CODEC_AUTOCALIB 0x08 /* auto calibrate */
+#define CODEC_SINGLE_DMA 0x04 /* Use single DMA channel */
+#define CODEC_RE 0x02 /* Capture enable */
+#define CODEC_PE 0x01 /* playback enable */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for CONFIG_2 register */
+#define CODEC_CFIG2I_DEFAULT 0x81
+#define CODEC_OFVS 0x80 /* Output Full Scale Voltage */
+#define CODEC_TE 0x40 /* Timer Enable */
+#define CODEC_RSCD 0x20 /* Recors Sample Counter Disable */
+#define CODEC_PSCD 0x10 /* Playback Sample Counter Disable */
+#define CODEC_DAOF 0x01 /* D/A Ouput Force Enable */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for CONFIG_3 register */
+/* #define CODEC_CFIG3I_DEFAULT 0xe0 0x02 when synth DACs are working */
+
+#define CODEC_CFIG3I_DEFAULT 0xc0 /* 0x02 when synth DACs are working */
+#define CODEC_RPIE 0x80 /* Record FIFO IRQ Enable */
+#define CODEC_PPIE 0x40 /* Playback FIFO IRQ Enable */
+#define CODEC_FT_MASK 0x30 /* FIFO Threshold Select */
+#define CODEC_PVFM 0x04 /* Playback Variable Frequency Mode */
+#define CODEC_SYNA 0x02 /* AUX1/Synth Signal Select */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for EXTERNAL_CONTROL register */
+#define CODEC_CEXTI_DEFAULT 0x00
+#define CODEC_IRQ_ENABLE 0x02 /* interrupt enable */
+#define CODEC_GPOUT1 0x80 /* external control #1 */
+#define CODEC_GPOUT0 0x40 /* external control #0 */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for MODE_SELECT_ID register */
+#define CODEC_MODE_DEFAULT 0x40
+#define CODEC_MODE_MASK 0x60
+#define CODEC_ID_BIT4 0x80
+#define CODEC_ID_BIT3_0 0x0F
+/************************************************************************/
+#define CONFIG_1 0x09
+#define EXTERNAL_CONTROL 0x0a/* Pin control */
+#define STATUS_2 0x0b/* Test and initialization */
+#define MODE_SELECT_ID 0x0c/* Miscellaneaous information */
+#define LOOPBACK 0x0d/* Digital Mix */
+#define UPPER_PLAY_COUNT 0x0e/* Playback Upper Base Count */
+#define LOWER_PLAY_COUNT 0x0f/* Playback Lower Base Count */
+#define CONFIG_2 0x10
+#define CONFIG_3 0x11
+
+
+#define IWL_CODEC_OUT(reg, val) \
+ { outb(iwl_codec_base, reg); outb(iwl_codec_data, val); }
+
+#define IWL_CODEC_IN(reg, val) \
+ { outb(iwl_codec_base, reg); val = inb(iwl_codec_data); }
+
+
+u_char gus_look8(int reg);
+
+void gus_write16(int reg, u_int data);
+
+u_short gus_read16(int reg);
+
+void gus_write_addr(int reg, u_long address, int is16bit);
+void IwaveLineLevel(char level, char index);
+void IwaveInputSource(BYTE index, BYTE source);
+void IwaveDelay(WORD count);
+void IwaveStopDma(BYTE path);
+void IwavePnpGetCfg(void);
+void IwavePnpDevice(BYTE dev);
+void IwavePnpSetCfg(void);
+void IwavePnpKey(void);
+BYTE IwavePnpIsol(PORT * pnpread);
+void IwaveCfgIOSpace(void);
+
+void IwavePnpSerial(PORT pnprdp, BYTE csn, BYTE * vendor, DWORD * serial);
+
+
+void IwavePnpPeek(PORT pnprdp, WORD bytes, BYTE * data);
+void IwavePnpEeprom(BYTE ctrl);
+void IwavePnpActivate(BYTE dev, BYTE bool);
+
+void IwavePnpPower(BYTE mode);
+void IwavePnpWake(BYTE csn);
+PORT IwavePnpIOcheck(PORT base, BYTE no_ports);
+
+BYTE IwavePnpGetCSN(DWORD VendorID, BYTE csn_max);
+BYTE IwavePnpPing(DWORD VendorID);
+WORD IwaveMemSize(void);
+BYTE IwaveMemPeek(ADDRESS addr);
+void IwaveMemPoke(ADDRESS addr, BYTE datum);
+void IwaveMemCfg(DWORD * lpbanks);
+void IwaveCodecIrq(BYTE mode);
+WORD IwaveRegPeek(DWORD reg_mnem);
+
+void IwaveRegPoke(DWORD reg_mnem, WORD datum);
+void IwaveCodecMode(char mode);
+void IwaveLineMute(BYTE mute, BYTE inx);
+void Iwaveinitcodec(void);
+int IwaveOpen(char voices, char mode, struct address_info * hw);
+
+
static void
-reset_sample_memory (void)
+reset_sample_memory(void)
{
- int i;
+ int i;
- for (i = 0; i <= MAX_SAMPLE; i++)
- sample_ptrs[i] = -1;
- for (i = 0; i < 32; i++)
- sample_map[i] = -1;
- for (i = 0; i < 32; i++)
- patch_map[i] = -1;
+ for (i = 0; i <= MAX_SAMPLE; i++)
+ sample_ptrs[i] = -1;
+ for (i = 0; i < 32; i++)
+ sample_map[i] = -1;
+ for (i = 0; i < 32; i++)
+ patch_map[i] = -1;
- gus_poke (0, 0); /* Put a silent sample to the beginning */
- gus_poke (1, 0);
- free_mem_ptr = 2;
+ gus_poke(0, 0); /* Put a silent sample to the beginning */
+ gus_poke(1, 0);
+ free_mem_ptr = 2;
- free_sample = 0;
+ free_sample = 0;
- for (i = 0; i < MAX_PATCH; i++)
- patch_table[i] = -1;
+ for (i = 0; i < MAX_PATCH; i++)
+ patch_table[i] = -1;
}
void
-gus_delay (void)
+gus_delay(void)
{
- int i;
+ int i;
- for (i = 0; i < 7; i++)
- INB (u_DRAMIO);
+ for (i = 0; i < 7; i++)
+ inb(u_DRAMIO);
}
static void
-gus_poke (long addr, unsigned char data)
+gus_poke(long addr, u_char data)
{ /* Writes a byte to the DRAM */
- unsigned long flags;
+ u_long flags;
- DISABLE_INTR (flags);
- OUTB (0x43, u_Command);
- OUTB (addr & 0xff, u_DataLo);
- OUTB ((addr >> 8) & 0xff, u_DataHi);
+ flags = splhigh();
+ outb(u_Command, 0x43);
+ outb(u_DataLo, addr & 0xff);
+ outb(u_DataHi, (addr >> 8) & 0xff);
- OUTB (0x44, u_Command);
- OUTB ((addr >> 16) & 0xff, u_DataHi);
- OUTB (data, u_DRAMIO);
- RESTORE_INTR (flags);
+ outb(u_Command, 0x44);
+ outb(u_DataHi, (addr >> 16) & 0xff);
+ outb(u_DRAMIO, data);
+ splx(flags);
}
-static unsigned char
-gus_peek (long addr)
+static u_char
+gus_peek(long addr)
{ /* Reads a byte from the DRAM */
- unsigned long flags;
- unsigned char tmp;
+ u_long flags;
+ u_char tmp;
- DISABLE_INTR (flags);
- OUTB (0x43, u_Command);
- OUTB (addr & 0xff, u_DataLo);
- OUTB ((addr >> 8) & 0xff, u_DataHi);
+ flags = splhigh();
+ outb(u_Command, 0x43);
+ outb(u_DataLo, addr & 0xff);
+ outb(u_DataHi, (addr >> 8) & 0xff);
- OUTB (0x44, u_Command);
- OUTB ((addr >> 16) & 0xff, u_DataHi);
- tmp = INB (u_DRAMIO);
- RESTORE_INTR (flags);
+ outb(u_Command, 0x44);
+ outb(u_DataHi, (addr >> 16) & 0xff);
+ tmp = inb(u_DRAMIO);
+ splx(flags);
- return tmp;
+ return tmp;
}
void
-gus_write8 (int reg, unsigned int data)
+gus_write8(int reg, u_int data)
{ /* Writes to an indirect register (8 bit) */
- unsigned long flags;
+ u_long flags;
- DISABLE_INTR (flags);
-
- OUTB (reg, u_Command);
- OUTB ((unsigned char) (data & 0xff), u_DataHi);
-
- RESTORE_INTR (flags);
+ flags = splhigh();
+ outb(u_Command, reg);
+ outb(u_DataHi, (u_char) (data & 0xff));
+ splx(flags);
}
-unsigned char
-gus_read8 (int reg)
-{ /* Reads from an indirect register (8 bit). Offset 0x80. */
- unsigned long flags;
- unsigned char val;
+u_char
+gus_read8(int reg)
+{ /* Reads from an indirect register (8 bit). Offset 0x80. */
+ u_long flags;
+ u_char val;
- DISABLE_INTR (flags);
- OUTB (reg | 0x80, u_Command);
- val = INB (u_DataHi);
- RESTORE_INTR (flags);
+ flags = splhigh();
+ outb(u_Command, reg | 0x80);
+ val = inb(u_DataHi);
+ splx(flags);
- return val;
+ return val;
}
-unsigned char
-gus_look8 (int reg)
-{ /* Reads from an indirect register (8 bit). No additional offset. */
- unsigned long flags;
- unsigned char val;
+u_char
+gus_look8(int reg)
+{ /* Reads from an indirect register (8 bit). No additional offset. */
+ u_long flags;
+ u_char val;
- DISABLE_INTR (flags);
- OUTB (reg, u_Command);
- val = INB (u_DataHi);
- RESTORE_INTR (flags);
+ flags = splhigh();
+ outb(u_Command, reg);
+ val = inb(u_DataHi);
+ splx(flags);
- return val;
+ return val;
}
void
-gus_write16 (int reg, unsigned int data)
-{ /* Writes to an indirect register (16 bit) */
- unsigned long flags;
+gus_write16(int reg, u_int data)
+{ /* Writes to an indirect register (16 bit) */
+ u_long flags;
- DISABLE_INTR (flags);
+ flags = splhigh();
- OUTB (reg, u_Command);
+ outb(u_Command, reg);
- OUTB ((unsigned char) (data & 0xff), u_DataLo);
- OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
+ outb(u_DataLo, (u_char) (data & 0xff));
+ outb(u_DataHi, (u_char) ((data >> 8) & 0xff));
- RESTORE_INTR (flags);
+ splx(flags);
}
-unsigned short
-gus_read16 (int reg)
-{ /* Reads from an indirect register (16 bit). Offset 0x80. */
- unsigned long flags;
- unsigned char hi, lo;
+u_short
+gus_read16(int reg)
+{ /* Reads from an indirect register (16 bit). Offset 0x80. */
+ u_long flags;
+ u_char hi, lo;
- DISABLE_INTR (flags);
+ flags = splhigh();
- OUTB (reg | 0x80, u_Command);
+ outb(u_Command, reg | 0x80);
- lo = INB (u_DataLo);
- hi = INB (u_DataHi);
+ lo = inb(u_DataLo);
+ hi = inb(u_DataHi);
- RESTORE_INTR (flags);
+ splx(flags);
- return ((hi << 8) & 0xff00) | lo;
+ return ((hi << 8) & 0xff00) | lo;
}
void
-gus_write_addr (int reg, unsigned long address, int is16bit)
+gus_write_addr(int reg, u_long address, int is16bit)
{ /* Writes an 24 bit memory address */
- unsigned long hold_address;
- unsigned long flags;
+ u_long hold_address;
+ u_long flags;
- DISABLE_INTR (flags);
- if (is16bit)
- {
- /*
- * Special processing required for 16 bit patches
- */
-
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
+ flags = splhigh();
+ if (is16bit) {
+ /*
+ * Special processing required for 16 bit patches
+ */
- 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));
- RESTORE_INTR (flags);
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+ gus_write16(reg, (u_short) ((address >> 7) & 0xffff));
+ gus_write16(reg + 1, (u_short) ((address << 9) & 0xffff));
+ /*
+ * Could writing twice fix problems with GUS_VOICE_POS() ? Lets try...
+ */
+ gus_delay();
+ gus_write16(reg, (u_short) ((address >> 7) & 0xffff));
+ gus_write16(reg + 1, (u_short) ((address << 9) & 0xffff));
+ splx(flags);
}
static void
-gus_select_voice (int voice)
+gus_select_voice(int voice)
{
- if (voice < 0 || voice > 31)
- return;
+ if (voice < 0 || voice > 31)
+ return;
- OUTB (voice, u_Voice);
+ outb(u_Voice, voice);
}
static void
-gus_select_max_voices (int nvoices)
+gus_select_max_voices(int nvoices)
{
- if (nvoices < 14)
- nvoices = 14;
- if (nvoices > 32)
- nvoices = 32;
+ if (nvoices < 14)
+ nvoices = 14;
+ if (nvoices > 32)
+ nvoices = 32;
- voice_alloc->max_voice = nr_voices = nvoices;
+ voice_alloc->max_voice = nr_voices = nvoices;
- gus_write8 (0x0e, (nvoices - 1) | 0xc0);
+ gus_write8(0x0e, (nvoices - 1) | 0xc0);
}
static void
-gus_voice_on (unsigned int mode)
+gus_voice_on(u_int mode)
{
- gus_write8 (0x00, (unsigned char) (mode & 0xfc));
- gus_delay ();
- gus_write8 (0x00, (unsigned char) (mode & 0xfc));
+ gus_write8(0x00, (u_char) (mode & 0xfc));
+ gus_delay();
+ gus_write8(0x00, (u_char) (mode & 0xfc));
}
static void
-gus_voice_off (void)
+gus_voice_off(void)
{
- gus_write8 (0x00, gus_read8 (0x00) | 0x03);
+ gus_write8(0x00, gus_read8(0x00) | 0x03);
}
static void
-gus_voice_mode (unsigned int m)
+gus_voice_mode(u_int m)
{
- unsigned char mode = (unsigned char) (m & 0xff);
+ u_char mode = (u_char) (m & 0xff);
- gus_write8 (0x00, (gus_read8 (0x00) & 0x03) |
- (mode & 0xfc)); /* Don't touch last two bits */
- gus_delay ();
- gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
+ gus_write8(0x00, (gus_read8(0x00) & 0x03) |
+ (mode & 0xfc)); /* Don't touch last two bits */
+ gus_delay();
+ gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc));
}
static void
-gus_voice_freq (unsigned long freq)
+gus_voice_freq(u_long freq)
{
- unsigned long divisor = freq_div_table[nr_voices - 14];
- unsigned short fc;
+ u_long divisor = freq_div_table[nr_voices - 14];
+ u_short fc;
- fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
- fc = fc << 1;
+ fc = (u_short) (((freq << 9) + (divisor >> 1)) / divisor);
+ fc = fc << 1;
- gus_write16 (0x01, fc);
+ gus_write16(0x01, fc);
}
static void
-gus_voice_volume (unsigned int vol)
+gus_voice_volume(u_int vol)
{
- gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */
- gus_write16 (0x09, (unsigned short) (vol << 4));
+ gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */
+ gus_write16(0x09, (u_short) (vol << 4));
}
static void
-gus_voice_balance (unsigned int balance)
+gus_voice_balance(u_int balance)
{
- gus_write8 (0x0c, (unsigned char) (balance & 0xff));
+ gus_write8(0x0c, (u_char) (balance & 0xff));
}
static void
-gus_ramp_range (unsigned int low, unsigned int high)
+gus_ramp_range(u_int low, u_int high)
{
- gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff));
- gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff));
+ gus_write8(0x07, (u_char) ((low >> 4) & 0xff));
+ gus_write8(0x08, (u_char) ((high >> 4) & 0xff));
}
static void
-gus_ramp_rate (unsigned int scale, unsigned int rate)
+gus_ramp_rate(u_int scale, u_int rate)
{
- gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
+ gus_write8(0x06, (u_char) (((scale & 0x03) << 6) | (rate & 0x3f)));
}
static void
-gus_rampon (unsigned int m)
+gus_rampon(u_int m)
{
- unsigned char mode = (unsigned char) (m & 0xff);
+ u_char mode = (u_char) (m & 0xff);
- gus_write8 (0x0d, mode & 0xfc);
- gus_delay ();
- gus_write8 (0x0d, mode & 0xfc);
+ gus_write8(0x0d, mode & 0xfc);
+ gus_delay();
+ gus_write8(0x0d, mode & 0xfc);
}
static void
-gus_ramp_mode (unsigned int m)
+gus_ramp_mode(u_int m)
{
- unsigned char mode = (unsigned char) (m & 0xff);
+ u_char mode = (u_char) (m & 0xff);
- gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) |
- (mode & 0xfc)); /* Leave the last 2 bits alone */
- gus_delay ();
- gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
+ gus_write8(0x0d, (gus_read8(0x0d) & 0x03) |
+ (mode & 0xfc)); /* Leave the last 2 bits alone */
+ gus_delay();
+ gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc));
}
static void
-gus_rampoff (void)
+gus_rampoff(void)
{
- gus_write8 (0x0d, 0x03);
+ gus_write8(0x0d, 0x03);
}
static void
-gus_set_voice_pos (int voice, long position)
+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);
+ 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)
+gus_voice_init(int voice)
{
- unsigned long flags;
-
- 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 */
- voice_alloc->map[voice] = 0;
- RESTORE_INTR (flags);
+ u_long flags;
+
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_volume(0);
+ gus_voice_off();
+ gus_write_addr(0x0a, 0, 0); /* Set current position to 0 */
+ gus_write8(0x00, 0x03); /* Voice off */
+ gus_write8(0x0d, 0x03); /* Ramping off */
+ voice_alloc->map[voice] = 0;
+ voice_alloc->alloc_times[voice] = 0;
+ splx(flags);
}
static void
-gus_voice_init2 (int voice)
-{
- voices[voice].panning = 0;
- voices[voice].mode = 0;
- voices[voice].orig_freq = 20000;
- voices[voice].current_freq = 20000;
- voices[voice].bender = 0;
- voices[voice].bender_range = 200;
- voices[voice].initial_volume = 0;
- voices[voice].current_volume = 0;
- voices[voice].loop_irq_mode = 0;
- voices[voice].loop_irq_parm = 0;
- voices[voice].volume_irq_mode = 0;
- voices[voice].volume_irq_parm = 0;
- voices[voice].env_phase = 0;
- voices[voice].main_vol = 127;
- voices[voice].patch_vol = 127;
- voices[voice].expression_vol = 127;
- voices[voice].sample_pending = -1;
+gus_voice_init2(int voice)
+{
+ voices[voice].panning = 0;
+ voices[voice].mode = 0;
+ voices[voice].orig_freq = 20000;
+ voices[voice].current_freq = 20000;
+ voices[voice].bender = 0;
+ voices[voice].bender_range = 200;
+ voices[voice].initial_volume = 0;
+ voices[voice].current_volume = 0;
+ voices[voice].loop_irq_mode = 0;
+ voices[voice].loop_irq_parm = 0;
+ voices[voice].volume_irq_mode = 0;
+ voices[voice].volume_irq_parm = 0;
+ voices[voice].env_phase = 0;
+ voices[voice].main_vol = 127;
+ voices[voice].patch_vol = 127;
+ voices[voice].expression_vol = 127;
+ voices[voice].sample_pending = -1;
}
static void
-step_envelope (int voice)
+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 ();
- RESTORE_INTR (flags);
- return;
- /*
- * Sustain phase begins. Continue envelope after receiving note off.
- */
+ u_int vol, prev_vol, phase;
+ u_char rate;
+ long int flags;
+
+ if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) {
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_rampoff();
+ splx(flags);
+ return;
+ /*
+ * Sustain phase begins. Continue envelope after receiving
+ * note off.
+ */
}
-
- if (voices[voice].env_phase >= 5)
- { /* Envelope finished. Shoot the voice down */
- gus_voice_init (voice);
- return;
+ if (voices[voice].env_phase >= 5) { /* Envelope finished. Shoot
+ * the voice down */
+ gus_voice_init(voice);
+ return;
}
-
- prev_vol = voices[voice].current_volume;
- 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];
-
- 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 */
- {
- RESTORE_INTR (flags);
- step_envelope (voice); /* Continue the envelope on the next step */
- return;
+ prev_vol = voices[voice].current_volume;
+ 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];
+
+ flags = splhigh();
+ 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 */
+ splx(flags);
+ step_envelope(voice); /* Continue the envelope on the next
+ * step */
+ return;
}
-
- if (vol > prev_vol)
- {
- if (vol >= (4096 - 64))
- vol = 4096 - 65;
- gus_ramp_range (0, vol);
- gus_rampon (0x20); /* Increasing volume, with IRQ */
- }
- else
- {
- if (vol <= 64)
- vol = 65;
- gus_ramp_range (vol, 4030);
- gus_rampon (0x60); /* Decreasing volume, with IRQ */
+ if (vol > prev_vol) {
+ if (vol >= (4096 - 64))
+ vol = 4096 - 65;
+ gus_ramp_range(0, vol);
+ gus_rampon(0x20); /* Increasing volume, with IRQ */
+ } else {
+ if (vol <= 64)
+ vol = 65;
+ gus_ramp_range(vol, 4030);
+ gus_rampon(0x60); /* Decreasing volume, with IRQ */
}
- voices[voice].current_volume = vol;
- RESTORE_INTR (flags);
+ voices[voice].current_volume = vol;
+ splx(flags);
}
static void
-init_envelope (int voice)
+init_envelope(int voice)
{
- voices[voice].env_phase = -1;
- voices[voice].current_volume = 64;
+ voices[voice].env_phase = -1;
+ voices[voice].current_volume = 64;
- step_envelope (voice);
+ step_envelope(voice);
}
static void
-start_release (int voice, long int flags)
+start_release(int voice, long int flags)
{
- if (gus_read8 (0x00) & 0x03)
- return; /* Voice already stopped */
+ if (gus_read8(0x00) & 0x03)
+ 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].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);
+ voices[voice].mode &= ~WAVE_SUSTAIN_ON;
+ gus_rampoff();
+ splx(flags);
+ step_envelope(voice);
}
static void
-gus_voice_fade (int voice)
+gus_voice_fade(int voice)
{
- int instr_no = sample_map[voice], is16bits;
- long int flags;
+ int instr_no = sample_map[voice], is16bits;
+ long int flags;
- DISABLE_INTR (flags);
- gus_select_voice (voice);
+ flags = splhigh();
+ gus_select_voice(voice);
- if (instr_no < 0 || instr_no > MAX_SAMPLE)
- {
- gus_write8 (0x00, 0x03); /* Hard stop */
- voice_alloc->map[voice] = 0;
- RESTORE_INTR (flags);
- return;
+ if (instr_no < 0 || instr_no > MAX_SAMPLE) {
+ gus_write8(0x00, 0x03); /* Hard stop */
+ voice_alloc->map[voice] = 0;
+ splx(flags);
+ return;
}
+ is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */
- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- start_release (voice, flags);
- return;
+ if (voices[voice].mode & WAVE_ENVELOPES) {
+ start_release(voice, flags);
+ return;
}
-
- /*
- * Ramp the volume down but not too quickly.
- */
- if ((int) (gus_read16 (0x09) >> 4) < 100) /* Get current volume */
- {
- gus_voice_off ();
- gus_rampoff ();
- gus_voice_init (voice);
- return;
+ /*
+ * Ramp the volume down but not too quickly.
+ */
+ if ((int) (gus_read16(0x09) >> 4) < 100) { /* Get current volume */
+ gus_voice_off();
+ gus_rampoff();
+ gus_voice_init(voice);
+ return;
}
-
- gus_ramp_range (65, 4030);
- gus_ramp_rate (2, 4);
- gus_rampon (0x40 | 0x20); /* Down, once, with IRQ */
- voices[voice].volume_irq_mode = VMODE_HALT;
- RESTORE_INTR (flags);
+ gus_ramp_range(65, 4030);
+ gus_ramp_rate(2, 4);
+ gus_rampon(0x40 | 0x20);/* Down, once, with IRQ */
+ voices[voice].volume_irq_mode = VMODE_HALT;
+ splx(flags);
}
static void
-gus_reset (void)
+gus_reset(void)
{
- int i;
+ int i;
- gus_select_max_voices (24);
- volume_base = 3071;
- volume_scale = 4;
- volume_method = VOL_METHOD_ADAGIO;
+ gus_select_max_voices(24);
+ volume_base = 3071;
+ volume_scale = 4;
+ volume_method = VOL_METHOD_ADAGIO;
- for (i = 0; i < 32; i++)
- {
- gus_voice_init (i); /* Turn voice off */
- gus_voice_init2 (i);
+ for (i = 0; i < 32; i++) {
+ 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_look8(0x41); /* Clear any pending DMA IRQs */
+ gus_look8(0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
+ gus_read8(0x0f); /* Clear pending IRQs */
}
static void
-gus_initialize (void)
+gus_initialize(void)
{
- unsigned long flags;
- unsigned char dma_image, irq_image, tmp;
+ u_long flags;
+ u_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};
+ static u_char gus_irq_map[16] =
+ {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
- static unsigned char gus_dma_map[8] =
- {0, 1, 0, 2, 0, 3, 4, 5};
+ static u_char gus_dma_map[8] =
+ {0, 1, 0, 2, 0, 3, 4, 5};
- DISABLE_INTR (flags);
- gus_write8 (0x4c, 0); /* Reset GF1 */
- gus_delay ();
- gus_delay ();
+ flags = splhigh();
+ gus_write8(0x4c, 0); /* Reset GF1 */
+ gus_delay();
+ gus_delay();
- gus_write8 (0x4c, 1); /* Release Reset */
- gus_delay ();
- gus_delay ();
+ gus_write8(0x4c, 1); /* Release Reset */
+ gus_delay();
+ gus_delay();
- /*
- * Clear all interrupts
- */
-
- gus_write8 (0x41, 0); /* DMA control */
- gus_write8 (0x45, 0); /* Timer control */
- gus_write8 (0x49, 0); /* Sample control */
+ /*
+ * Clear all interrupts
+ */
- gus_select_max_voices (24);
+ gus_write8(0x41, 0); /* DMA control */
+ gus_write8(0x45, 0); /* Timer control */
+ gus_write8(0x49, 0); /* Sample control */
- INB (u_Status); /* Touch the status register */
+ gus_select_max_voices(24);
- gus_look8 (0x41); /* Clear any pending DMA IRQs */
- gus_look8 (0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
+ inb(u_Status); /* Touch the status register */
- gus_reset (); /* Resets all voices */
+ gus_look8(0x41); /* Clear any pending DMA IRQs */
+ gus_look8(0x49); /* Clear any pending sample IRQs */
+ gus_read8(0x0f); /* Clear pending IRQs */
- gus_look8 (0x41); /* Clear any pending DMA IRQs */
- gus_look8 (0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
+ gus_reset(); /* Resets all voices */
- gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */
+ gus_look8(0x41); /* Clear any pending DMA IRQs */
+ gus_look8(0x49); /* Clear any pending sample IRQs */
+ gus_read8(0x0f); /* Clear pending IRQs */
- /*
- * Set up for Digital ASIC
- */
+ gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */
- OUTB (0x05, gus_base + 0x0f);
+ /*
+ * Set up for Digital ASIC
+ */
- mix_image |= 0x02; /* Disable line out */
- OUTB (mix_image, u_Mixer);
+ outb(gus_base + 0x0f, 0x05);
- OUTB (0x00, u_IRQDMAControl);
+ mix_image |= 0x02; /* Disable line out (for a moment) */
+ outb(u_Mixer, mix_image);
- OUTB (0x00, gus_base + 0x0f);
+ outb(u_IRQDMAControl, 0x00);
- /*
- * Now set up the DMA and IRQ interface
- *
- * The GUS supports two IRQs and two DMAs.
- *
- * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
- * Adding this support requires significant changes to the dmabuf.c, dsp.c
- * and audio.c also.
- */
+ outb(gus_base + 0x0f, 0x00);
- irq_image = 0;
- tmp = gus_irq_map[gus_irq];
- if (!tmp)
- printk ("Warning! GUS IRQ not selected\n");
- irq_image |= tmp;
- irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
+ /*
+ * Now set up the DMA and IRQ interface
+ *
+ * The GUS supports two IRQs and two DMAs.
+ *
+ * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
+ * Adding this support requires significant changes to the dmabuf.c,
+ * dsp.c and audio.c also.
+ */
- dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
- tmp = gus_dma_map[gus_dma];
- if (!tmp)
- printk ("Warning! GUS DMA not selected\n");
- dma_image |= tmp;
+ irq_image = 0;
+ tmp = gus_irq_map[gus_irq];
+ if (!tmp)
+ printf("Warning! GUS IRQ not selected\n");
+ irq_image |= tmp;
+ irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
+
+ dual_dma_mode = 1;
+ if (gus_dma2 == gus_dma || gus_dma2 == -1) {
+ dual_dma_mode = 0;
+ dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
+
+ tmp = gus_dma_map[gus_dma];
+ if (!tmp)
+ printf("Warning! GUS DMA not selected\n");
+
+ dma_image |= tmp;
+ } else
+ /* Setup dual DMA channel mode for GUS MAX */
+ {
+ dma_image = gus_dma_map[gus_dma];
+ if (!dma_image)
+ printf("Warning! GUS DMA not selected\n");
+
+ tmp = gus_dma_map[gus_dma2] << 3;
+ if (!tmp) {
+ printf("Warning! Invalid GUS MAX DMA\n");
+ tmp = 0x40; /* Combine DMA channels */
+ dual_dma_mode = 0;
+ }
+ dma_image |= tmp;
+ }
- /*
- * For some reason the IRQ and DMA addresses must be written twice
- */
+ /*
+ * For some reason the IRQ and DMA addresses must be written twice
+ */
- /*
- * Doing it first time
- */
+ /*
+ * Doing it first time
+ */
- OUTB (mix_image, u_Mixer); /* Select DMA control */
- OUTB (dma_image | 0x80, u_IRQDMAControl); /* Set DMA address */
+ outb(u_Mixer, mix_image); /* Select DMA control */
+ outb(u_IRQDMAControl, dma_image | 0x80); /* Set DMA address */
- OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */
+ outb(u_Mixer, mix_image | 0x40); /* Select IRQ control */
+ outb(u_IRQDMAControl, irq_image); /* Set IRQ address */
- /*
- * Doing it second time
- */
+ /*
+ * Doing it second time
+ */
- OUTB (mix_image, u_Mixer); /* Select DMA control */
- OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */
+ outb(u_Mixer, mix_image); /* Select DMA control */
+ outb(u_IRQDMAControl, dma_image); /* Set DMA address */
- OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */
+ outb(u_Mixer, mix_image | 0x40); /* Select IRQ control */
+ outb(u_IRQDMAControl, irq_image); /* Set IRQ address */
- gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
+ gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
- mix_image &= ~0x02; /* Enable line out */
- mix_image |= 0x08; /* Enable IRQ */
- OUTB (mix_image, u_Mixer); /*
- * Turn mixer channels on
- * Note! Mic in is left off.
- */
+ mix_image &= ~0x02; /* Enable line out */
+ mix_image |= 0x08; /* Enable IRQ */
+ outb(u_Mixer, mix_image); /* Turn mixer channels on Note! Mic
+ * in is left off. */
- gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
+ gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
- gusintr (0); /* Serve pending interrupts */
- RESTORE_INTR (flags);
+ gusintr(0); /* Serve pending interrupts */
+ splx(flags);
}
int
-gus_wave_detect (int baseaddr)
+gus_wave_detect(int baseaddr)
{
- unsigned long i;
- unsigned long loc;
-
- gus_base = baseaddr;
-
- gus_write8 (0x4c, 0); /* Reset GF1 */
- gus_delay ();
- gus_delay ();
-
- gus_write8 (0x4c, 1); /* Release Reset */
- gus_delay ();
- gus_delay ();
-
- /* See if there is first block there.... */
- gus_poke (0L, 0xaa);
- if (gus_peek (0L) != 0xaa)
- return (0);
-
- /* Now zero it out so that I can check for mirroring .. */
- gus_poke (0L, 0x00);
- for (i = 1L; i < 1024L; i++)
- {
- int n, failed;
-
- /* check for mirroring ... */
- if (gus_peek (0L) != 0)
- break;
- loc = i << 10;
-
- for (n = loc - 1, failed = 0; n <= loc; n++)
- {
- gus_poke (loc, 0xaa);
- if (gus_peek (loc) != 0xaa)
- failed = 1;
-
- gus_poke (loc, 0x55);
- if (gus_peek (loc) != 0x55)
- failed = 1;
+ u_long i;
+ u_long loc;
+ gus_base = baseaddr;
+
+ gus_write8(0x4c, 0); /* Reset GF1 */
+ gus_delay();
+ gus_delay();
+
+ gus_write8(0x4c, 1); /* Release Reset */
+ gus_delay();
+ gus_delay();
+
+ /* See if there is first block there.... */
+ gus_poke(0L, 0xaa);
+ if (gus_peek(0L) != 0xaa)
+ return (0);
+
+ /* Now zero it out so that I can check for mirroring .. */
+ gus_poke(0L, 0x00);
+ for (i = 1L; i < 1024L; i++) {
+ int n, failed;
+
+ /* check for mirroring ... */
+ if (gus_peek(0L) != 0)
+ break;
+ loc = i << 10;
+
+ for (n = loc - 1, failed = 0; n <= loc; n++) {
+ gus_poke(loc, 0xaa);
+ if (gus_peek(loc) != 0xaa)
+ failed = 1;
+
+ gus_poke(loc, 0x55);
+ if (gus_peek(loc) != 0x55)
+ failed = 1;
+ }
+
+ if (failed)
+ break;
}
-
- if (failed)
- break;
- }
- gus_mem_size = i << 10;
- return 1;
+ gus_mem_size = i << 10;
+ return 1;
}
static int
-guswave_ioctl (int dev,
- unsigned int cmd, unsigned int arg)
+guswave_ioctl(int dev,
+ u_int cmd, ioctl_arg arg)
{
- switch (cmd)
- {
+ switch (cmd) {
case SNDCTL_SYNTH_INFO:
- gus_info.nr_voices = nr_voices;
- IOCTL_TO_USER ((char *) arg, 0, &gus_info, sizeof (gus_info));
- return 0;
- break;
+ gus_info.nr_voices = nr_voices;
+ bcopy(&gus_info, &(((char *) arg)[0]), sizeof(gus_info));
+ return 0;
+ break;
case SNDCTL_SEQ_RESETSAMPLES:
- reset_sample_memory ();
- return 0;
- break;
+ reset_sample_memory();
+ return 0;
+ break;
case SNDCTL_SEQ_PERCMODE:
- return 0;
- break;
+ return 0;
+ break;
case SNDCTL_SYNTH_MEMAVL:
- return gus_mem_size - free_mem_ptr - 32;
+ return gus_mem_size - free_mem_ptr - 32;
default:
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
}
static int
-guswave_set_instr (int dev, int voice, int instr_no)
+guswave_set_instr(int dev, int voice, int instr_no)
{
- int sample_no;
-
- if (instr_no < 0 || instr_no > MAX_PATCH)
- return RET_ERROR (EINVAL);
+ int sample_no;
- if (voice < 0 || voice > 31)
- return RET_ERROR (EINVAL);
+ if (instr_no < 0 || instr_no > MAX_PATCH)
+ return -(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 */
- }
+ if (voice < 0 || voice > 31)
+ return -(EINVAL);
- 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);
- }
+ 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;
- sample_map[voice] = sample_no;
- patch_map[voice] = instr_no;
- return 0;
+ if (sample_no < 0) {
+ printf("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
+ return -(EINVAL); /* Patch not defined */
+ }
+ if (sample_ptrs[sample_no] == -1) { /* Sample not loaded */
+ printf("GUS: Sample #%d not loaded for patch %d (voice %d)\n",
+ sample_no, instr_no, voice);
+ return -(EINVAL);
+ }
+ sample_map[voice] = sample_no;
+ patch_map[voice] = instr_no;
+ return 0;
}
static int
-guswave_kill_note (int dev, int voice, int note, int velocity)
+guswave_kill_note(int dev, int voice, int note, int velocity)
{
- unsigned long flags;
-
- DISABLE_INTR (flags);
- voice_alloc->map[voice] = 0xffff;
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].kill_pending = 1;
- RESTORE_INTR (flags);
- }
- else
- {
- RESTORE_INTR (flags);
- gus_voice_fade (voice);
+ u_long flags;
+
+ flags = splhigh();
+ /* voice_alloc->map[voice] = 0xffff; */
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) {
+ voices[voice].kill_pending = 1;
+ splx(flags);
+ } else {
+ splx(flags);
+ gus_voice_fade(voice);
}
- return 0;
+ splx(flags);
+ return 0;
}
static void
-guswave_aftertouch (int dev, int voice, int pressure)
+guswave_aftertouch(int dev, int voice, int pressure)
{
- short lo_limit, hi_limit;
- unsigned long flags;
-
- return; /* Procedure currently disabled */
-
- if (voice < 0 || voice > 31)
- return;
-
- if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
- return; /* Don't mix with envelopes */
-
- if (pressure < 32)
- {
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_rampoff ();
- compute_and_set_volume (voice, 255, 0); /* Back to original volume */
- RESTORE_INTR (flags);
- return;
- }
-
- hi_limit = voices[voice].current_volume;
- lo_limit = hi_limit * 99 / 100;
- if (lo_limit < 65)
- lo_limit = 65;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- if (hi_limit > (4095 - 65))
- {
- hi_limit = 4095 - 65;
- gus_voice_volume (hi_limit);
- }
- gus_ramp_range (lo_limit, hi_limit);
- gus_ramp_rate (3, 8);
- gus_rampon (0x58); /* Bidirectional, dow, loop */
- RESTORE_INTR (flags);
}
static void
-guswave_panning (int dev, int voice, int value)
+guswave_panning(int dev, int voice, int value)
{
- if (voice >= 0 || voice < 32)
- voices[voice].panning = value;
+ if (voice >= 0 || voice < 32)
+ voices[voice].panning = value;
}
static void
-guswave_volume_method (int dev, int mode)
+guswave_volume_method(int dev, int mode)
{
- if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
- volume_method = mode;
+ if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
+ volume_method = mode;
}
-static void
-compute_volume (int voice, int volume)
+void
+compute_volume(int voice, int volume)
{
- if (volume < 128)
- voices[voice].midi_volume = volume;
+ if (volume < 128)
+ voices[voice].midi_volume = volume;
- switch (volume_method)
- {
+ switch (volume_method) {
case VOL_METHOD_ADAGIO:
- voices[voice].initial_volume =
- gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
- voices[voice].expression_vol,
- voices[voice].patch_vol);
- break;
+ voices[voice].initial_volume =
+ gus_adagio_vol(voices[voice].midi_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;
+ case VOL_METHOD_LINEAR:/* Totally ignores patch-volume and expression */
+ voices[voice].initial_volume =
+ gus_linear_vol(volume, voices[voice].main_vol);
+ break;
default:
- voices[voice].initial_volume = volume_base +
- (voices[voice].midi_volume * volume_scale);
+ voices[voice].initial_volume = volume_base +
+ (voices[voice].midi_volume * volume_scale);
}
- if (voices[voice].initial_volume > 4030)
- voices[voice].initial_volume = 4030;
+ if (voices[voice].initial_volume > 4030)
+ voices[voice].initial_volume = 4030;
}
-static void
-compute_and_set_volume (int voice, int volume, int ramp_time)
+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;
+ int curr, target, rate;
+ u_long flags;
- DISABLE_INTR (flags);
- /*
- * CAUTION! Interrupts disabled. Enable them before returning
- */
-
- gus_select_voice (voice);
+ compute_volume(voice, volume);
+ voices[voice].current_volume = voices[voice].initial_volume;
- current = gus_read16 (0x09) >> 4;
- target = voices[voice].initial_volume;
+ flags = splhigh();
+ /*
+ * CAUTION! Interrupts disabled. Enable them before returning
+ */
- if (ramp_time == INSTANT_RAMP)
- {
- gus_rampoff ();
- gus_voice_volume (target);
- RESTORE_INTR (flags);
- return;
- }
+ gus_select_voice(voice);
- if (ramp_time == FAST_RAMP)
- rate = 63;
- else
- rate = 16;
- gus_ramp_rate (0, rate);
+ curr = gus_read16(0x09) >> 4;
+ target = voices[voice].initial_volume;
- if ((target - current) / 64 == 0) /* Close enough to target. */
- {
- gus_rampoff ();
- gus_voice_volume (target);
- RESTORE_INTR (flags);
- return;
+ if (ramp_time == INSTANT_RAMP) {
+ gus_rampoff();
+ gus_voice_volume(target);
+ splx(flags);
+ return;
}
-
- if (target > current)
- {
- if (target > (4095 - 65))
- target = 4095 - 65;
- gus_ramp_range (current, target);
- gus_rampon (0x00); /* Ramp up, once, no IRQ */
+ if (ramp_time == FAST_RAMP)
+ rate = 63;
+ else
+ rate = 16;
+ gus_ramp_rate(0, rate);
+
+ if ((target - curr) / 64 == 0) { /* Close enough to target. */
+ gus_rampoff();
+ gus_voice_volume(target);
+ splx(flags);
+ return;
}
- else
- {
- if (target < 65)
- target = 65;
-
- gus_ramp_range (target, current);
- gus_rampon (0x40); /* Ramp down, once, no irq */
+ if (target > curr) {
+ if (target > (4095 - 65))
+ target = 4095 - 65;
+ gus_ramp_range(curr, target);
+ gus_rampon(0x00); /* Ramp up, once, no IRQ */
+ } else {
+ if (target < 65)
+ target = 65;
+
+ gus_ramp_range(target, curr);
+ gus_rampon(0x40); /* Ramp down, once, no irq */
}
- RESTORE_INTR (flags);
+ splx(flags);
}
static void
-dynamic_volume_change (int voice)
+dynamic_volume_change(int voice)
{
- unsigned char status;
- unsigned long flags;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- status = gus_read8 (0x00); /* Get voice status */
- RESTORE_INTR (flags);
+ u_char status;
+ u_long flags;
- if (status & 0x03)
- return; /* Voice was not running */
+ flags = splhigh();
+ gus_select_voice(voice);
+ status = gus_read8(0x00); /* Get voice status */
+ splx(flags);
- if (!(voices[voice].mode & WAVE_ENVELOPES))
- {
- compute_and_set_volume (voice, voices[voice].midi_volume, 1);
- return;
- }
+ if (status & 0x03)
+ return; /* Voice was not running */
- /*
- * Voice is running and has envelopes.
- */
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- status = gus_read8 (0x0d); /* Ramping status */
- RESTORE_INTR (flags);
+ if (!(voices[voice].mode & WAVE_ENVELOPES)) {
+ compute_and_set_volume(voice, voices[voice].midi_volume, 1);
+ return;
+ }
+ /*
+ * Voice is running and has envelopes.
+ */
- if (status & 0x03) /* Sustain phase? */
- {
- compute_and_set_volume (voice, voices[voice].midi_volume, 1);
- return;
- }
+ flags = splhigh();
+ gus_select_voice(voice);
+ status = gus_read8(0x0d); /* Ramping status */
+ splx(flags);
- if (voices[voice].env_phase < 0)
- return;
+ if (status & 0x03) { /* Sustain phase? */
+ compute_and_set_volume(voice, voices[voice].midi_volume, 1);
+ return;
+ }
+ if (voices[voice].env_phase < 0)
+ return;
- compute_volume (voice, voices[voice].midi_volume);
+ compute_volume(voice, voices[voice].midi_volume);
}
static void
-guswave_controller (int dev, int voice, int ctrl_num, int value)
+guswave_controller(int dev, int voice, int ctrl_num, int value)
{
- unsigned long flags;
- unsigned long freq;
-
- if (voice < 0 || voice > 31)
- return;
-
- switch (ctrl_num)
- {
- case CTRL_PITCH_BENDER:
- voices[voice].bender = value;
-
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- {
- freq = compute_finetune (voices[voice].orig_freq, value,
- voices[voice].bender_range);
- voices[voice].current_freq = freq;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (freq);
- RESTORE_INTR (flags);
- }
- break;
-
- case CTRL_PITCH_BENDER_RANGE:
- voices[voice].bender_range = value;
- break;
- case CTL_EXPRESSION:
- value /= 128;
- case CTRL_EXPRESSION:
- 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;
-
- case CTL_PAN:
- voices[voice].panning = (value * 2) - 128;
- break;
-
- case CTL_MAIN_VOLUME:
- value = (value * 100) / 16383;
-
- case CTRL_MAIN_VOLUME:
- voices[voice].main_vol = value;
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- dynamic_volume_change (voice);
- break;
-
- default:
- break;
- }
+ u_long flags;
+ u_long freq;
+
+ if (voice < 0 || voice > 31)
+ return;
+
+ switch (ctrl_num) {
+ case CTRL_PITCH_BENDER:
+ voices[voice].bender = value;
+
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE) {
+ freq = compute_finetune(voices[voice].orig_freq, value,
+ voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_freq(freq);
+ splx(flags);
+ }
+ break;
+
+ case CTRL_PITCH_BENDER_RANGE:
+ voices[voice].bender_range = value;
+ break;
+ case CTL_EXPRESSION:
+ value /= 128;
+ case CTRL_EXPRESSION:
+ 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;
+
+ case CTL_PAN:
+ voices[voice].panning = (value * 2) - 128;
+ break;
+
+ case CTL_MAIN_VOLUME:
+ value = (value * 100) / 16383;
+
+ case CTRL_MAIN_VOLUME:
+ voices[voice].main_vol = value;
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change(voice);
+ break;
+
+ default:
+ break;
+ }
}
-static int
-guswave_start_note2 (int dev, int voice, int note_num, int volume)
+int
+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;
- unsigned long note_freq, base_note, freq, flags;
- unsigned char mode = 0;
-
- if (voice < 0 || voice > 31)
- {
- printk ("GUS: Invalid voice\n");
- return RET_ERROR (EINVAL);
+ int sample, best_sample, best_delta, delta_freq;
+ int is16bits, samplep, patch, pan;
+ u_long note_freq, base_note, freq, flags;
+ u_char mode = 0;
+
+ if (voice < 0 || voice > 31) {
+ printf("GUS: Invalid voice\n");
+ return -(EINVAL);
}
-
- if (note_num == 255)
- {
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- voices[voice].midi_volume = volume;
- dynamic_volume_change (voice);
- return 0;
+ if (note_num == 255) {
+ if (voices[voice].mode & WAVE_ENVELOPES) {
+ voices[voice].midi_volume = volume;
+ dynamic_volume_change(voice);
+ return 0;
}
-
- compute_and_set_volume (voice, volume, 1);
- return 0;
- }
-
- if ((patch = patch_map[voice]) == -1)
- {
- return RET_ERROR (EINVAL);
- }
-
- if ((samplep = patch_table[patch]) == -1)
- {
- return RET_ERROR (EINVAL);
+ compute_and_set_volume(voice, volume, 1);
+ return 0;
}
+ if ((patch = patch_map[voice]) == -1)
+ return -(EINVAL);
+ if ((samplep = patch_table[patch]) == -1)
+ return -(EINVAL);
+ note_freq = note_to_freq(note_num);
- note_freq = note_to_freq (note_num);
-
- /*
- * Find a sample within a patch so that the note_freq is between low_note
- * and high_note.
- */
- sample = -1;
-
- best_sample = samplep;
- best_delta = 1000000;
- while (samplep >= 0 && sample == -1)
- {
- delta_freq = note_freq - samples[samplep].base_note;
- if (delta_freq < 0)
- delta_freq = -delta_freq;
- if (delta_freq < best_delta)
- {
- best_sample = samplep;
- best_delta = delta_freq;
- }
- if (samples[samplep].low_note <= note_freq &&
- note_freq <= samples[samplep].high_note)
- sample = samplep;
- else
- samplep = samples[samplep].key; /*
- * Follow link
- */
+ /*
+ * Find a sample within a patch so that the note_freq is between
+ * low_note and high_note.
+ */
+ sample = -1;
+
+ best_sample = samplep;
+ best_delta = 1000000;
+ while (samplep >= 0 && sample == -1) {
+ dbg_samples = samples;
+ dbg_samplep = samplep;
+
+ delta_freq = note_freq - samples[samplep].base_note;
+ if (delta_freq < 0)
+ delta_freq = -delta_freq;
+ if (delta_freq < best_delta) {
+ best_sample = samplep;
+ best_delta = delta_freq;
+ }
+ if (samples[samplep].low_note <= note_freq &&
+ note_freq <= samples[samplep].high_note)
+ sample = samplep;
+ else
+ samplep = samples[samplep].key; /* Follow link */
}
- if (sample == -1)
- sample = best_sample;
+ if (sample == -1)
+ sample = best_sample;
- if (sample == -1)
- {
- printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
- return 0; /* Should play default patch ??? */
+ if (sample == -1) {
+ printf("GUS: Patch %d not defined for note %d\n", patch, note_num);
+ return 0; /* Should play default patch ??? */
}
+ is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
+ voices[voice].mode = samples[sample].mode;
+ voices[voice].patch_vol = samples[sample].volume;
- is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
- voices[voice].mode = samples[sample].mode;
- voices[voice].patch_vol = samples[sample].volume;
+ if (voices[voice].mode & WAVE_ENVELOPES) {
+ int i;
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- int i;
-
- for (i = 0; i < 6; i++)
- {
- voices[voice].env_rate[i] = samples[sample].env_rate[i];
- voices[voice].env_offset[i] = samples[sample].env_offset[i];
+ for (i = 0; i < 6; i++) {
+ voices[voice].env_rate[i] = samples[sample].env_rate[i];
+ voices[voice].env_offset[i] = samples[sample].env_offset[i];
}
}
+ sample_map[voice] = sample;
- sample_map[voice] = sample;
-
- base_note = samples[sample].base_note / 100; /* Try to avoid overflows */
- note_freq /= 100;
+ base_note = samples[sample].base_note / 100; /* Try to avoid overflows */
+ note_freq /= 100;
- freq = samples[sample].base_freq * note_freq / base_note;
+ freq = samples[sample].base_freq * note_freq / base_note;
- voices[voice].orig_freq = freq;
+ voices[voice].orig_freq = freq;
- /*
- * Since the pitch bender may have been set before playing the note, we
- * have to calculate the bending now.
- */
-
- freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender,
- voices[voice].bender_range);
- voices[voice].current_freq = freq;
-
- pan = (samples[sample].panning + voices[voice].panning) / 32;
- pan += 7;
- if (pan < 0)
- pan = 0;
- if (pan > 15)
- pan = 15;
+ /*
+ * Since the pitch bender may have been set before playing the note,
+ * we have to calculate the bending now.
+ */
- if (samples[sample].mode & WAVE_16_BITS)
- {
- mode |= 0x04; /* 16 bits */
- if ((sample_ptrs[sample] >> 18) !=
- ((sample_ptrs[sample] + samples[sample].len) >> 18))
- printk ("GUS: Sample address error\n");
+ freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender,
+ voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ pan = (samples[sample].panning + voices[voice].panning) / 32;
+ pan += 7;
+ if (pan < 0)
+ pan = 0;
+ if (pan > 15)
+ pan = 15;
+
+ if (samples[sample].mode & WAVE_16_BITS) {
+ mode |= 0x04; /* 16 bits */
+ if ((sample_ptrs[sample] >> 18) !=
+ ((sample_ptrs[sample] + samples[sample].len) >> 18))
+ printf("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 ();
- gus_rampoff ();
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_off();
+ gus_rampoff();
- RESTORE_INTR (flags);
+ splx(flags);
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- compute_volume (voice, volume);
- init_envelope (voice);
+ if (voices[voice].mode & WAVE_ENVELOPES) {
+ compute_volume(voice, volume);
+ init_envelope(voice);
+ } else {
+ compute_and_set_volume(voice, volume, 0);
}
- else
- compute_and_set_volume (voice, volume, 0);
- DISABLE_INTR (flags);
- gus_select_voice (voice);
+ flags = splhigh();
+ gus_select_voice(voice);
- if (samples[sample].mode & WAVE_LOOP_BACK)
- gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
- voices[voice].offset_pending, is16bits); /* start=end */
- else
- gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
- is16bits); /* Sample start=begin */
+ if (samples[sample].mode & WAVE_LOOP_BACK)
+ gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len -
+ voices[voice].offset_pending, is16bits); /* start=end */
+ else
+ gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
+ is16bits); /* Sample start=begin */
- if (samples[sample].mode & WAVE_LOOPING)
- {
- mode |= 0x08;
+ if (samples[sample].mode & WAVE_LOOPING) {
+ mode |= 0x08;
- if (samples[sample].mode & WAVE_BIDIR_LOOP)
- mode |= 0x10;
+ if (samples[sample].mode & WAVE_BIDIR_LOOP)
+ mode |= 0x10;
- if (samples[sample].mode & WAVE_LOOP_BACK)
- {
- gus_write_addr (0x0a,
- sample_ptrs[sample] + samples[sample].loop_end -
- voices[voice].offset_pending, is16bits);
- mode |= 0x40;
+ if (samples[sample].mode & WAVE_LOOP_BACK) {
+ 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 down at the end */
+ voices[voice].loop_irq_parm = 1;
+ gus_write_addr(0x02, sample_ptrs[sample],
+ is16bits); /* Loop start location */
+ gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1,
+ is16bits); /* Loop end location */
}
- else
- {
- mode |= 0x20; /* Loop IRQ at the end */
- voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */
- voices[voice].loop_irq_parm = 1;
- gus_write_addr (0x02, sample_ptrs[sample],
- is16bits);/* Loop start location */
- gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1,
- is16bits);/* Loop end location */
- }
- gus_voice_freq (freq);
- gus_voice_balance (pan);
- gus_voice_on (mode);
- RESTORE_INTR (flags);
+ gus_voice_freq(freq);
+ gus_voice_balance(pan);
+ gus_voice_on(mode);
+ splx(flags);
- return 0;
+ 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.
+ * 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)
+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);
+ long int flags;
+ int mode;
+ int ret_val = 0;
+
+ flags = splhigh();
+ if (note_num == 255) {
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) {
+ voices[voice].volume_pending = volume;
+ } else {
+ ret_val = guswave_start_note2(dev, voice, note_num, volume);
}
- }
- 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) || (int) ((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);
+ } 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) {
+ splx(flags); /* Run temporarily with interrupts
+ * enabled */
+ guswave_set_instr(voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ flags = splhigh();
+ gus_select_voice(voice); /* Reselect the voice
+ * (just to be sure) */
+ }
+ if ((mode & 0x01) || (int) ((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 */
}
}
- return ret_val;
+ splx(flags);
+ return ret_val;
}
static void
-guswave_reset (int dev)
+guswave_reset(int dev)
{
- int i;
+ int i;
- for (i = 0; i < 32; i++)
- {
- gus_voice_init (i);
- gus_voice_init2 (i);
+ for (i = 0; i < 32; i++) {
+ gus_voice_init(i);
+ gus_voice_init2(i);
}
}
static int
-guswave_open (int dev, int mode)
+guswave_open(int dev, int mode)
{
- int err;
+ int err;
+ int otherside = audio_devs[dev]->otherside;
- if (gus_busy)
- return RET_ERROR (EBUSY);
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return -(EBUSY);
+ }
+ if (audio_devs[dev]->busy)
+ return -(EBUSY);
- gus_initialize ();
+ gus_initialize();
+ voice_alloc->timestamp = 0;
- if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
- return err;
+ if ((err = DMAbuf_open_dma(gus_devnum)) < 0) {
+ printf("GUS: Loading saples without DMA\n");
+ gus_no_dma = 1; /* Upload samples using PIO */
+ } else
+ gus_no_dma = 0;
- RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
- gus_busy = 1;
- active_device = GUS_DEV_WAVE;
+ dram_sleep_flag.aborting = 0;
+ dram_sleep_flag.mode = WK_NONE;
+ active_device = GUS_DEV_WAVE;
- gus_reset ();
+ audio_devs[dev]->busy = 1;
+ gus_reset();
- return 0;
+ return 0;
}
static void
-guswave_close (int dev)
+guswave_close(int dev)
{
- gus_busy = 0;
- active_device = 0;
- gus_reset ();
+ int otherside = audio_devs[dev]->otherside;
- DMAbuf_close_dma (gus_devnum);
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return;
+ }
+ audio_devs[dev]->busy = 0;
+
+ active_device = 0;
+ gus_reset();
+
+ if (!gus_no_dma)
+ DMAbuf_close_dma(gus_devnum);
}
static int
-guswave_load_patch (int dev, int format, snd_rw_buf * addr,
- int offs, int count, int pmgr_flag)
+guswave_load_patch(int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag)
{
- struct patch_info patch;
- int instr;
- long sizeof_patch;
+ struct patch_info patch;
+ int instr;
+ long sizeof_patch;
- unsigned long blk_size, blk_end, left, src_offs, target;
+ u_long blk_size, blk_end, left, src_offs, target;
- sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
+ sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
- if (format != GUS_PATCH)
- {
- printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
- return RET_ERROR (EINVAL);
+ if (format != GUS_PATCH) {
+ printf("GUS Error: Invalid patch format (key) 0x%x\n", format);
+ return -(EINVAL);
}
-
- if (count < sizeof_patch)
- {
- printk ("GUS Error: Patch header too short\n");
- return RET_ERROR (EINVAL);
+ if (count < sizeof_patch) {
+ printf("GUS Error: Patch header too short\n");
+ return -(EINVAL);
}
+ count -= sizeof_patch;
- count -= sizeof_patch;
-
- if (free_sample >= MAX_SAMPLE)
- {
- printk ("GUS: Sample table full\n");
- return RET_ERROR (ENOSPC);
+ if (free_sample >= MAX_SAMPLE) {
+ printf("GUS: Sample table full\n");
+ return -(ENOSPC);
}
+ /*
+ * Copy the header from user space but ignore the first bytes which
+ * have been transferred already.
+ */
- /*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
- */
-
- COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs);
+ if (uiomove(&((char *) &patch)[offs], sizeof_patch - offs, addr)) {
+ printf("audio: Bad copyin()!\n");
+ };
- instr = patch.instr_no;
+ instr = patch.instr_no;
- if (instr < 0 || instr > MAX_PATCH)
- {
- printk ("GUS: Invalid patch number %d\n", instr);
- return RET_ERROR (EINVAL);
+ if (instr < 0 || instr > MAX_PATCH) {
+ printf("GUS: Invalid patch number %d\n", instr);
+ return -(EINVAL);
}
-
- if (count < patch.len)
- {
- printk ("GUS Warning: Patch record too short (%d<%d)\n",
- count, (int) patch.len);
- patch.len = count;
+ if (count < patch.len) {
+ printf("GUS Warning: Patch record too short (%d<%d)\n",
+ count, (int) patch.len);
+ patch.len = count;
}
-
- if (patch.len <= 0 || patch.len > gus_mem_size)
- {
- printk ("GUS: Invalid sample length %d\n", (int) patch.len);
- return RET_ERROR (EINVAL);
+ if (patch.len <= 0 || patch.len > gus_mem_size) {
+ printf("GUS: Invalid sample length %d\n", (int) patch.len);
+ return -(EINVAL);
}
-
- if (patch.mode & WAVE_LOOPING)
- {
- if (patch.loop_start < 0 || patch.loop_start >= patch.len)
- {
- printk ("GUS: Invalid loop start\n");
- return RET_ERROR (EINVAL);
+ if (patch.mode & WAVE_LOOPING) {
+ if (patch.loop_start < 0 || patch.loop_start >= patch.len) {
+ printf("GUS: Invalid loop start\n");
+ return -(EINVAL);
}
-
- if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
- {
- printk ("GUS: Invalid loop end\n");
- return RET_ERROR (EINVAL);
+ if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) {
+ printf("GUS: Invalid loop end\n");
+ return -(EINVAL);
}
}
-
- free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */
+ free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */
#define GUS_BANK_SIZE (256*1024)
- if (patch.mode & WAVE_16_BITS)
- {
- /*
- * 16 bit samples must fit one 256k bank.
- */
- if (patch.len >= GUS_BANK_SIZE)
- {
- printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
- return RET_ERROR (ENOSPC);
+ if (patch.mode & WAVE_16_BITS) {
+ /*
+ * 16 bit samples must fit one 256k bank.
+ */
+ if (patch.len >= GUS_BANK_SIZE) {
+ printf("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
+ return -(ENOSPC);
}
+ if ((free_mem_ptr / GUS_BANK_SIZE) !=
+ ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) {
+ u_long tmp_mem = /* Aligning to 256K */
+ ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
- if ((free_mem_ptr / GUS_BANK_SIZE) !=
- ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
- {
- unsigned long tmp_mem = /* Aling to 256K */
- ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
-
- if ((tmp_mem + patch.len) > gus_mem_size)
- return RET_ERROR (ENOSPC);
+ if ((tmp_mem + patch.len) > gus_mem_size)
+ return -(ENOSPC);
- free_mem_ptr = tmp_mem; /* This leaves unusable memory */
+ free_mem_ptr = tmp_mem; /* This leaves unusable memory */
}
}
+ if ((free_mem_ptr + patch.len) > gus_mem_size)
+ return -(ENOSPC);
- if ((free_mem_ptr + patch.len) > gus_mem_size)
- return RET_ERROR (ENOSPC);
+ sample_ptrs[free_sample] = free_mem_ptr;
- sample_ptrs[free_sample] = free_mem_ptr;
-
- /*
- * Tremolo is not possible with envelopes
- */
-
- if (patch.mode & WAVE_ENVELOPES)
- patch.mode &= ~WAVE_TREMOLO;
-
- memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
-
- /*
- * Link this_one sample to the list of samples for patch 'instr'.
- */
-
- samples[free_sample].key = patch_table[instr];
- patch_table[instr] = free_sample;
-
- /*
- * Use DMA to transfer the wave data to the DRAM
- */
+ /*
+ * Tremolo is not possible with envelopes
+ */
- left = patch.len;
- src_offs = 0;
- target = free_mem_ptr;
+ if (patch.mode & WAVE_ENVELOPES)
+ patch.mode &= ~WAVE_TREMOLO;
- while (left) /* Not completely transferred yet */
- {
- blk_size = audio_devs[gus_devnum]->buffsize;
- if (blk_size > left)
- blk_size = left;
+ bcopy(&patch, (char *) &samples[free_sample], sizeof_patch);
- /*
- * DMA cannot cross 256k bank boundaries. Check for that.
- */
- blk_end = target + blk_size;
-
- if ((target >> 18) != (blk_end >> 18))
- { /* Split the block */
+ /*
+ * Link this_one sample to the list of samples for patch 'instr'.
+ */
- blk_end &= ~(256 * 1024 - 1);
- blk_size = blk_end - target;
- }
+ samples[free_sample].key = patch_table[instr];
+ patch_table[instr] = free_sample;
-#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
- /*
- * For some reason the DMA is not possible. We have to use PIO.
- */
- {
- long i;
- unsigned char data;
+ /*
+ * Use DMA to transfer the wave data to the DRAM
+ */
- for (i = 0; i < blk_size; i++)
- {
- GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
- if (patch.mode & WAVE_UNSIGNED)
+ left = patch.len;
+ src_offs = 0;
+ target = free_mem_ptr;
- if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
- data ^= 0x80; /* Convert to signed */
- gus_poke (target + i, data);
- }
- }
-#else /* GUS_NO_DMA */
- {
- unsigned long address, hold_address;
- unsigned char dma_command;
- unsigned long flags;
+ while (left) { /* Not completely transferred yet */
+ /* blk_size = audio_devs[gus_devnum]->buffsize; */
+ blk_size = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
+ if (blk_size > left)
+ blk_size = left;
/*
- * OK, move now. First in and then out.
+ * DMA cannot cross 256k bank boundaries. Check for that.
*/
+ blk_end = target + blk_size;
- COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0],
- addr, sizeof_patch + src_offs,
- blk_size);
+ if ((target >> 18) != (blk_end >> 18)) { /* Split the block */
+ blk_end &= ~(256 * 1024 - 1);
+ blk_size = blk_end - target;
+ }
+ if (gus_no_dma) {
+ /*
+ * For some reason the DMA is not possible. We have
+ * to use PIO.
+ */
+ long i;
+ u_char data;
+
+ for (i = 0; i < blk_size; i++) {
+ uiomove((char *) &(data), 1, addr);
+ if (patch.mode & WAVE_UNSIGNED)
+ if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
+ data ^= 0x80; /* Convert to signed */
+ gus_poke(target + i, data);
+ }
+ } else {
+ u_long address, hold_address;
+ u_char dma_command;
+ u_long flags;
+
+ /*
+ * OK, move now. First in and then out.
+ */
+
+ if (uiomove(audio_devs[gus_devnum]->dmap_out->raw_buf, blk_size, addr)) {
+ printf("audio: Bad copyin()!\n");
+ };
+
+ flags = splhigh();
+ /******** INTERRUPTS DISABLED NOW ********/
+ gus_write8(0x41, 0); /* Disable GF1 DMA */
+ DMAbuf_start_dma(gus_devnum,
+ audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
+ blk_size, 1);
+
+ /*
+ * Set the DRAM address for the wave data
+ */
+
+ address = target;
+
+ if (audio_devs[gus_devnum]->dmachan1 > 3) {
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+ gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
- DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
- DMAbuf_start_dma (gus_devnum,
- audio_devs[gus_devnum]->dmap->raw_buf_phys[0],
- blk_size, DMA_MODE_WRITE);
+ /*
+ * Start the DMA transfer
+ */
- /*
- * Set the DRAM address for the wave data
- */
+ dma_command = 0x21; /* IRQ enable, DMA start */
+ if (patch.mode & WAVE_UNSIGNED)
+ dma_command |= 0x80; /* Invert MSB */
+ if (patch.mode & WAVE_16_BITS)
+ dma_command |= 0x40; /* 16 bit _DATA_ */
+ if (audio_devs[gus_devnum]->dmachan1 > 3)
+ dma_command |= 0x04; /* 16 bit DMA _channel_ */
- address = target;
+ gus_write8(0x41, dma_command); /* Lets bo luteet (=bugs) */
- if (audio_devs[gus_devnum]->dmachan > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
+ /*
+ * Sleep here until the DRAM DMA done interrupt is
+ * served
+ */
+ active_device = GUS_DEV_WAVE;
- gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
- /*
- * Start the DMA transfer
- */
+ {
+ int chn;
- dma_command = 0x21; /* IRQ enable, DMA start */
- if (patch.mode & WAVE_UNSIGNED)
- dma_command |= 0x80; /* Invert MSB */
- if (patch.mode & WAVE_16_BITS)
- dma_command |= 0x40; /* 16 bit _DATA_ */
- if (audio_devs[gus_devnum]->dmachan > 3)
- dma_command |= 0x04; /* 16 bit DMA _channel_ */
+ dram_sleep_flag.mode = WK_SLEEP;
+ dram_sleeper = &chn;
+ DO_SLEEP(chn, dram_sleep_flag, hz);
- gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */
+ };
+ if ((dram_sleep_flag.mode & WK_TIMEOUT))
+ printf("GUS: DMA Transfer timed out\n");
+ splx(flags);
+ }
/*
- * Sleep here until the DRAM DMA done interrupt is served
+ * Now the next part
*/
- active_device = GUS_DEV_WAVE;
-
- 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 */
-
- /*
- * Now the next part
- */
- left -= blk_size;
- src_offs += blk_size;
- target += blk_size;
+ left -= blk_size;
+ src_offs += blk_size;
+ target += blk_size;
- gus_write8 (0x41, 0); /* Stop DMA */
+ gus_write8(0x41, 0); /* Stop DMA */
}
- free_mem_ptr += patch.len;
+ free_mem_ptr += patch.len;
- if (!pmgr_flag)
- pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
- free_sample++;
- return 0;
+ if (!pmgr_flag)
+ pmgr_inform(dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
+ free_sample++;
+ return 0;
}
static void
-guswave_hw_control (int dev, unsigned char *event)
+guswave_hw_control(int dev, u_char *event)
{
- int voice, cmd;
- unsigned short p1, p2;
- unsigned long plong, flags;
-
- cmd = event[2];
- voice = event[3];
- p1 = *(unsigned short *) &event[4];
- 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)
- {
-
- case _GUS_NUMVOICES:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_select_max_voices (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICESAMPLE:
- guswave_set_instr (dev, voice, p1);
- break;
-
- case _GUS_VOICEON:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_voice_on (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEOFF:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_off ();
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEFADE:
- gus_voice_fade (voice);
- break;
-
- case _GUS_VOICEMODE:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_voice_mode (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEBALA:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_balance (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEFREQ:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (plong);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEVOL:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_volume (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEVOL2: /* Just update the software voice level */
- voices[voice].initial_volume =
- voices[voice].current_volume = p1;
- break;
-
- case _GUS_RAMPRANGE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_ramp_range (p1, p2);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPRATE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NJET-NJET */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_ramp_rate (p1, p2);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPMODE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_ramp_mode (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPON:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* EI-EI */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_rampon (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPOFF:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NEJ-NEJ */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_rampoff ();
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOLUME_SCALE:
- volume_base = p1;
- 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:;
- }
+ int voice, cmd;
+ u_short p1, p2;
+ u_long plong, flags;
+
+ cmd = event[2];
+ voice = event[3];
+ p1 = *(u_short *) &event[4];
+ p2 = *(u_short *) &event[6];
+ plong = *(u_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) {
+
+ case _GUS_NUMVOICES:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_select_max_voices(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICESAMPLE:
+ guswave_set_instr(dev, voice, p1);
+ break;
+
+ case _GUS_VOICEON:
+ flags = splhigh();
+ gus_select_voice(voice);
+ p1 &= ~0x20; /* Don't allow interrupts */
+ gus_voice_on(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEOFF:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_off();
+ splx(flags);
+ break;
+
+ case _GUS_VOICEFADE:
+ gus_voice_fade(voice);
+ break;
+
+ case _GUS_VOICEMODE:
+ flags = splhigh();
+ gus_select_voice(voice);
+ p1 &= ~0x20; /* Don't allow interrupts */
+ gus_voice_mode(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEBALA:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_balance(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEFREQ:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_freq(plong);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEVOL:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_volume(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEVOL2: /* Just update the software voice level */
+ voices[voice].initial_volume =
+ voices[voice].current_volume = p1;
+ break;
+
+ case _GUS_RAMPRANGE:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* NO-NO */
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_ramp_range(p1, p2);
+ splx(flags);
+ break;
+
+ case _GUS_RAMPRATE:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* NJET-NJET */
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_ramp_rate(p1, p2);
+ splx(flags);
+ break;
+
+ case _GUS_RAMPMODE:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* NO-NO */
+ flags = splhigh();
+ gus_select_voice(voice);
+ p1 &= ~0x20; /* Don't allow interrupts */
+ gus_ramp_mode(p1);
+ splx(flags);
+ break;
+
+ case _GUS_RAMPON:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* EI-EI */
+ flags = splhigh();
+ gus_select_voice(voice);
+ p1 &= ~0x20; /* Don't allow interrupts */
+ gus_rampon(p1);
+ splx(flags);
+ break;
+
+ case _GUS_RAMPOFF:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* NEJ-NEJ */
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_rampoff();
+ splx(flags);
+ break;
+
+ case _GUS_VOLUME_SCALE:
+ volume_base = p1;
+ volume_scale = p2;
+ break;
+
+ case _GUS_VOICE_POS:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_set_voice_pos(voice, plong);
+ splx(flags);
+ break;
+
+ default:;
+ }
}
static int
-gus_sampling_set_speed (int speed)
+gus_sampling_set_speed(int speed)
{
- if (speed <= 0)
- return gus_sampling_speed;
- if (speed > 44100)
- speed = 44100;
+ if (speed <= 0)
+ speed = gus_sampling_speed;
+
+ RANGE(speed, 4000, 44100);
+ gus_sampling_speed = speed;
- gus_sampling_speed = speed;
- return speed;
+ if (only_read_access) {
+ /* Compute nearest valid recording speed and return it */
+
+ speed = (9878400 / (gus_sampling_speed + 2)) / 16;
+ speed = (9878400 / (speed * 16)) - 2;
+ }
+ return speed;
}
static int
-gus_sampling_set_channels (int channels)
+gus_sampling_set_channels(int channels)
{
- if (!channels)
- return gus_sampling_channels;
- if (channels > 2)
- channels = 2;
- if (channels < 1)
- channels = 1;
- gus_sampling_channels = channels;
- return channels;
+ if (!channels)
+ return gus_sampling_channels;
+ RANGE(channels, 1, 2);
+ gus_sampling_channels = channels;
+ return channels;
}
static int
-gus_sampling_set_bits (int bits)
+gus_sampling_set_bits(int bits)
{
- if (!bits)
- return gus_sampling_bits;
+ if (!bits)
+ return gus_sampling_bits;
+
+ if (bits != 8 && bits != 16)
+ bits = 8;
- if (bits != 8 && bits != 16)
- bits = 8;
+ if (only_8_bits)
+ bits = 8;
- gus_sampling_bits = bits;
- return bits;
+ gus_sampling_bits = bits;
+ return bits;
}
static int
-gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+gus_sampling_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- switch (cmd)
- {
- case SOUND_PCM_WRITE_RATE:
- if (local)
- return gus_sampling_set_speed (arg);
- return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_RATE:
- if (local)
- return gus_sampling_speed;
- return IOCTL_OUT (arg, gus_sampling_speed);
- break;
-
- case SNDCTL_DSP_STEREO:
- if (local)
- return gus_sampling_set_channels (arg + 1) - 1;
- return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1);
- 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;
-
- case SOUND_PCM_READ_CHANNELS:
- if (local)
- return gus_sampling_channels;
- return IOCTL_OUT (arg, gus_sampling_channels);
- break;
-
- case SNDCTL_DSP_SETFMT:
- if (local)
- return gus_sampling_set_bits (arg);
- return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_BITS:
- if (local)
- return gus_sampling_bits;
- return IOCTL_OUT (arg, gus_sampling_bits);
-
- case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */
- return IOCTL_OUT (arg, RET_ERROR (EINVAL));
- break;
-
- case SOUND_PCM_READ_FILTER:
- return IOCTL_OUT (arg, RET_ERROR (EINVAL));
- break;
+ switch (cmd) {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return gus_sampling_set_speed((int) arg);
+ return *(int *) arg = gus_sampling_set_speed((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return gus_sampling_speed;
+ return *(int *) arg = gus_sampling_speed;
+ break;
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return gus_sampling_set_channels((int) arg + 1) - 1;
+ return *(int *) arg = gus_sampling_set_channels((*(int *) arg) + 1) - 1;
+ break;
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return gus_sampling_set_channels((int) arg);
+ return *(int *) arg = gus_sampling_set_channels((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return gus_sampling_channels;
+ return *(int *) arg = gus_sampling_channels;
+ break;
+
+ case SNDCTL_DSP_SETFMT:
+ if (local)
+ return gus_sampling_set_bits((int) arg);
+ return *(int *) arg = gus_sampling_set_bits((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return gus_sampling_bits;
+ return *(int *) arg = gus_sampling_bits;
+
+ case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */
+ return *(int *) arg = -(EINVAL);
+ break;
+
+ case SOUND_PCM_READ_FILTER:
+ return *(int *) arg = -(EINVAL);
+ break;
- default:
- return RET_ERROR (EINVAL);
- }
- return RET_ERROR (EINVAL);
+ }
+ return -(EINVAL);
}
static void
-gus_sampling_reset (int dev)
+gus_sampling_reset(int dev)
{
+ if (recording_active) {
+ gus_write8(0x49, 0x00); /* Halt recording */
+ set_input_volumes();
+ }
}
static int
-gus_sampling_open (int dev, int mode)
+gus_sampling_open(int dev, int mode)
{
-#ifdef GUS_NO_DMA
- printk ("GUS: DMA mode not enabled. Device not supported\n");
- return RET_ERROR (ENXIO);
-#endif
- if (gus_busy)
- return RET_ERROR (EBUSY);
+ int otherside = audio_devs[dev]->otherside;
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return -(EBUSY);
+ }
+ if (audio_devs[dev]->busy)
+ return -(EBUSY);
- gus_initialize ();
- gus_busy = 1;
- active_device = 0;
+ gus_initialize();
- gus_reset ();
- reset_sample_memory ();
- gus_select_max_voices (14);
+ active_device = 0;
- pcm_active = 0;
- dma_active = 0;
- pcm_opened = 1;
- if (mode & OPEN_READ)
- {
- recording_active = 1;
- set_input_volumes ();
- }
+ gus_reset();
+ reset_sample_memory();
+ gus_select_max_voices(14);
- return 0;
+ pcm_active = 0;
+ dma_active = 0;
+ pcm_opened = 1;
+ audio_devs[dev]->busy = 1;
+
+ if (mode & OPEN_READ) {
+ recording_active = 1;
+ set_input_volumes();
+ }
+ only_read_access = !(mode & OPEN_WRITE);
+ only_8_bits = mode & OPEN_READ;
+ if (only_8_bits)
+ audio_devs[dev]->format_mask = AFMT_U8;
+ else
+ audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE;
+
+ return 0;
}
static void
-gus_sampling_close (int dev)
+gus_sampling_close(int dev)
{
- gus_reset ();
- gus_busy = 0;
- pcm_opened = 0;
- active_device = 0;
+ int otherside = audio_devs[dev]->otherside;
+ audio_devs[dev]->busy = 0;
- if (recording_active)
- set_input_volumes ();
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return;
+ }
+ gus_reset();
- recording_active = 0;
+ pcm_opened = 0;
+ active_device = 0;
+
+ if (recording_active) {
+ gus_write8(0x49, 0x00); /* Halt recording */
+ set_input_volumes();
+ }
+ recording_active = 0;
}
static void
-gus_sampling_update_volume (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);
+ u_long flags;
+ int voice;
+
+ if (pcm_active && pcm_opened)
+ for (voice = 0; voice < gus_sampling_channels; voice++) {
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_rampoff();
+ gus_voice_volume(1530 + (25 * gus_pcm_volume));
+ gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
+ splx(flags);
+ }
}
static void
-play_next_pcm_block (void)
+play_next_pcm_block(void)
{
- unsigned long flags;
- int speed = gus_sampling_speed;
- int this_one, is16bits, chn;
- unsigned long dram_loc;
- unsigned char mode[2], ramp_mode[2];
+ u_long flags;
+ int speed = gus_sampling_speed;
+ int this_one, is16bits, chn;
+ u_long dram_loc;
+ u_char mode[2], ramp_mode[2];
- if (!pcm_qlen)
- return;
+ if (!pcm_qlen)
+ return;
- this_one = pcm_head;
+ this_one = pcm_head;
- for (chn = 0; chn < gus_sampling_channels; chn++)
- {
- mode[chn] = 0x00;
- ramp_mode[chn] = 0x03; /* Ramping and rollover off */
-
- if (chn == 0)
- {
- 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 */
- }
- else
- is16bits = 0;
-
- dram_loc = this_one * pcm_bsize;
- dram_loc += chn * pcm_banksize;
-
- if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */
- {
- mode[chn] |= 0x08; /* Enable loop */
- ramp_mode[chn] = 0x03;/* Disable rollover bit */
- }
- else
- {
- if (chn == 0)
- ramp_mode[chn] = 0x04; /* Enable rollover bit */
- }
-
- DISABLE_INTR (flags);
- gus_select_voice (chn);
- gus_voice_freq (speed);
-
- if (gus_sampling_channels == 1)
- gus_voice_balance (7); /* mono */
- else if (chn == 0)
- gus_voice_balance (0); /* left */
- else
- gus_voice_balance (15); /* right */
-
- if (!pcm_active) /* Playback not already active */
- {
- /*
- * The playback was not started yet (or there has been a pause).
- * Start the voice (again) and ask for a rollover irq at the end of
- * this_one block. If this_one one is last of the buffers, use just
- * the normal loop with irq.
- */
-
- gus_voice_off ();
- gus_rampoff ();
- gus_voice_volume (1530 + (25 * gus_pcm_volume));
- gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
-
- gus_write_addr (0x0a, dram_loc, is16bits); /* Starting position */
- gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start */
-
- if (chn != 0)
- gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
- is16bits); /* Loop end location */
- }
-
- if (chn == 0)
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
- is16bits); /* Loop end location */
- else
- mode[chn] |= 0x08; /* Enable looping */
-
- if (pcm_datasize[this_one] != pcm_bsize)
- {
- /*
- * Incompletely filled block. Possibly the last one.
- */
- if (chn == 0)
- {
- mode[chn] &= ~0x08; /* Disable looping */
- mode[chn] |= 0x20;/* Enable IRQ at the end */
- voices[0].loop_irq_mode = LMODE_PCM_STOP;
- ramp_mode[chn] = 0x03; /* No rollover bit */
- }
- else
- {
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
- is16bits); /* Loop end location */
- mode[chn] &= ~0x08; /* Disable looping */
- }
+ for (chn = 0; chn < gus_sampling_channels; chn++) {
+ mode[chn] = 0x00;
+ ramp_mode[chn] = 0x03; /* Ramping and rollover off */
+
+ if (chn == 0) {
+ 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 */
+ } else
+ is16bits = 0;
+
+ dram_loc = this_one * pcm_bsize;
+ dram_loc += chn * pcm_banksize;
+
+ if (this_one == (pcm_nblk - 1)) { /* Last fragment of the
+ * DRAM buffer */
+ mode[chn] |= 0x08; /* Enable loop */
+ ramp_mode[chn] = 0x03; /* Disable rollover bit */
+ } else {
+ if (chn == 0)
+ ramp_mode[chn] = 0x04; /* Enable rollover bit */
}
- RESTORE_INTR (flags);
+ flags = splhigh();
+ gus_select_voice(chn);
+ gus_voice_freq(speed);
+
+ if (gus_sampling_channels == 1)
+ gus_voice_balance(7); /* mono */
+ else if (chn == 0)
+ gus_voice_balance(0); /* left */
+ else
+ gus_voice_balance(15); /* right */
+
+ if (!pcm_active) { /* Playback not already active */
+ /*
+ * The playback was not started yet (or there has
+ * been a pause). Start the voice (again) and ask for
+ * a rollover irq at the end of this_one block. If
+ * this_one one is last of the buffers, use just the
+ * normal loop with irq.
+ */
+
+ gus_voice_off();
+ gus_rampoff();
+ gus_voice_volume(1530 + (25 * gus_pcm_volume));
+ gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
+
+ gus_write_addr(0x0a, dram_loc, is16bits); /* Starting position */
+ gus_write_addr(0x02, chn * pcm_banksize, is16bits); /* Loop start */
+
+ if (chn != 0)
+ gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
+ is16bits); /* Loop end location */
+ }
+ if (chn == 0)
+ gus_write_addr(0x04, dram_loc + pcm_datasize[this_one] - 1,
+ is16bits); /* Loop end location */
+ else
+ mode[chn] |= 0x08; /* Enable looping */
+
+ if (pcm_datasize[this_one] != pcm_bsize) {
+ /*
+ * Incompletely filled block. Possibly the last one.
+ */
+ if (chn == 0) {
+ mode[chn] &= ~0x08; /* Disable looping */
+ mode[chn] |= 0x20; /* Enable IRQ at the end */
+ voices[0].loop_irq_mode = LMODE_PCM_STOP;
+ ramp_mode[chn] = 0x03; /* No rollover bit */
+ } else {
+ gus_write_addr(0x04, dram_loc + pcm_datasize[this_one],
+ is16bits); /* Loop end location */
+ mode[chn] &= ~0x08; /* Disable looping */
+ }
+ }
+ splx(flags);
}
- for (chn = 0; chn < gus_sampling_channels; chn++)
- {
- DISABLE_INTR (flags);
- gus_select_voice (chn);
- gus_write8 (0x0d, ramp_mode[chn]);
- gus_voice_on (mode[chn]);
- RESTORE_INTR (flags);
+ for (chn = 0; chn < gus_sampling_channels; chn++) {
+ flags = splhigh();
+ gus_select_voice(chn);
+ gus_write8(0x0d, ramp_mode[chn]);
+ gus_voice_on(mode[chn]);
+ splx(flags);
}
- pcm_active = 1;
+ pcm_active = 1;
}
static void
-gus_transfer_output_block (int dev, unsigned long buf,
- int total_count, int intrflag, int chn)
+gus_transfer_output_block(int dev, u_long buf,
+ int total_count, int intrflag, int chn)
{
- /*
- * This routine transfers one block of audio data to the DRAM. In mono mode
- * it's called just once. When in stereo mode, this_one routine is called
- * once for both channels.
- *
- * The left/mono channel data is transferred to the beginning of dram and the
- * right data to the area pointed by gus_page_size.
- */
-
- int this_one, count;
- unsigned long flags;
- unsigned char dma_command;
- unsigned long address, hold_address;
-
- DISABLE_INTR (flags);
-
- count = total_count / gus_sampling_channels;
-
- if (chn == 0)
- {
- if (pcm_qlen >= pcm_nblk)
- printk ("GUS Warning: PCM buffers out of sync\n");
+ /*
+ * 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.
+ */
- this_one = pcm_current_block = pcm_tail;
- pcm_qlen++;
- pcm_tail = (pcm_tail + 1) % pcm_nblk;
- pcm_datasize[this_one] = count;
- }
- else
- this_one = pcm_current_block;
+ int this_one, count;
+ u_long flags;
+ u_char dma_command;
+ u_long address, hold_address;
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
- DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
+ flags = splhigh();
- address = this_one * pcm_bsize;
- address += chn * pcm_banksize;
+ count = total_count / gus_sampling_channels;
- if (audio_devs[dev]->dmachan > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
+ if (chn == 0) {
+ if (pcm_qlen >= pcm_nblk)
+ printf("GUS Warning: PCM buffers out of sync\n");
- gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+ this_one = pcm_current_block = pcm_tail;
+ pcm_qlen++;
+ pcm_tail = (pcm_tail + 1) % pcm_nblk;
+ pcm_datasize[this_one] = count;
+ } else
+ this_one = pcm_current_block;
- dma_command = 0x21; /* IRQ enable, DMA start */
+ gus_write8(0x41, 0); /* Disable GF1 DMA */
+ DMAbuf_start_dma(dev, buf + (chn * count), count, 1);
- if (gus_sampling_bits != 8)
- dma_command |= 0x40; /* 16 bit _DATA_ */
- else
- dma_command |= 0x80; /* Invert MSB */
+ address = this_one * pcm_bsize;
+ address += chn * pcm_banksize;
- if (audio_devs[dev]->dmachan > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
+ if (audio_devs[dev]->dmachan1 > 3) {
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+ gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
- gus_write8 (0x41, dma_command); /* Kickstart */
+ dma_command = 0x21; /* IRQ enable, DMA start */
- if (chn == (gus_sampling_channels - 1)) /* Last channel */
- {
- /*
- * Last (right or mono) channel data
- */
- dma_active = 1; /* DMA started. There is a unacknowledged buffer */
- active_device = GUS_DEV_PCM_DONE;
- if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize))
- {
- play_next_pcm_block ();
+ if (gus_sampling_bits != 8)
+ dma_command |= 0x40; /* 16 bit _DATA_ */
+ else
+ dma_command |= 0x80; /* Invert MSB */
+
+ if (audio_devs[dev]->dmachan1 > 3)
+ dma_command |= 0x04; /* 16 bit DMA channel */
+
+ gus_write8(0x41, dma_command); /* Kickstart */
+
+ if (chn == (gus_sampling_channels - 1)) { /* Last channel */
+ /*
+ * Last (right or mono) channel data
+ */
+ dma_active = 1; /* DMA started. There is a unacknowledged
+ * buffer */
+ active_device = GUS_DEV_PCM_DONE;
+ if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize)) {
+ play_next_pcm_block();
+ }
+ } else {
+ /*
+ * Left channel data. The right channel is transferred after
+ * DMA interrupt
+ */
+ active_device = GUS_DEV_PCM_CONTINUE;
}
- }
- else
- {
- /*
- * Left channel data. The right channel
- * is transferred after DMA interrupt
- */
- active_device = GUS_DEV_PCM_CONTINUE;
- }
- RESTORE_INTR (flags);
+ splx(flags);
}
static void
-gus_sampling_output_block (int dev, unsigned long buf, int total_count,
- int intrflag, int restart_dma)
+gus_sampling_output_block(int dev, u_long buf, int total_count,
+ int intrflag, int restart_dma)
{
- pcm_current_buf = buf;
- pcm_current_count = total_count;
- pcm_current_intrflag = intrflag;
- pcm_current_dev = dev;
- gus_transfer_output_block (dev, buf, total_count, intrflag, 0);
+ pcm_current_buf = buf;
+ pcm_current_count = total_count;
+ pcm_current_intrflag = intrflag;
+ pcm_current_dev = dev;
+ gus_transfer_output_block(dev, buf, total_count, intrflag, 0);
}
static void
-gus_sampling_start_input (int dev, unsigned long buf, int count,
- int intrflag, int restart_dma)
+gus_sampling_start_input(int dev, u_long buf, int count,
+ int intrflag, int restart_dma)
{
- unsigned long flags;
- unsigned char mode;
+ u_long flags;
+ u_char mode;
- DISABLE_INTR (flags);
+ flags = splhigh();
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+ DMAbuf_start_dma(dev, buf, count, 0);
- mode = 0xa0; /* DMA IRQ enabled, invert MSB */
+ mode = 0xa0; /* DMA IRQ enabled, invert MSB */
- if (audio_devs[dev]->dmachan > 3)
- mode |= 0x04; /* 16 bit DMA channel */
- if (gus_sampling_channels > 1)
- mode |= 0x02; /* Stereo */
- mode |= 0x01; /* DMA enable */
+ if (audio_devs[dev]->dmachan2 > 3)
+ mode |= 0x04; /* 16 bit DMA channel */
+ if (gus_sampling_channels > 1)
+ mode |= 0x02; /* Stereo */
+ mode |= 0x01; /* DMA enable */
- gus_write8 (0x49, mode);
+ gus_write8(0x49, mode);
- RESTORE_INTR (flags);
+ splx(flags);
}
static int
-gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
+gus_sampling_prepare_for_input(int dev, int bsize, int bcount)
{
- unsigned int rate;
+ u_int rate;
- rate = (9878400 / (gus_sampling_speed + 2)) / 16;
+ rate = (9878400 / (gus_sampling_speed + 2)) / 16;
- gus_write8 (0x48, rate & 0xff); /* Set sampling rate */
+ gus_write8(0x48, rate & 0xff); /* Set sampling rate */
- if (gus_sampling_bits != 8)
- {
- printk ("GUS Error: 16 bit recording not supported\n");
- return RET_ERROR (EINVAL);
+ if (gus_sampling_bits != 8) {
+ printf("GUS Error: 16 bit recording not supported\n");
+ return -(EINVAL);
}
-
- return 0;
+ return 0;
}
static int
-gus_sampling_prepare_for_output (int dev, int bsize, int bcount)
+gus_sampling_prepare_for_output(int dev, int bsize, int bcount)
{
- int i;
+ int i;
- long mem_ptr, mem_size;
+ long mem_ptr, mem_size;
- mem_ptr = 0;
- mem_size = gus_mem_size / gus_sampling_channels;
+ mem_ptr = 0;
+ mem_size = gus_mem_size / gus_sampling_channels;
- if (mem_size > (256 * 1024))
- mem_size = 256 * 1024;
+ if (mem_size > (256 * 1024))
+ mem_size = 256 * 1024;
- pcm_bsize = bsize / gus_sampling_channels;
- pcm_head = pcm_tail = pcm_qlen = 0;
+ pcm_bsize = bsize / gus_sampling_channels;
+ pcm_head = pcm_tail = pcm_qlen = 0;
- pcm_nblk = MAX_PCM_BUFFERS;
- if ((pcm_bsize * pcm_nblk) > mem_size)
- pcm_nblk = mem_size / pcm_bsize;
+ pcm_nblk = MAX_PCM_BUFFERS;
+ if ((pcm_bsize * pcm_nblk) > mem_size)
+ pcm_nblk = mem_size / pcm_bsize;
- for (i = 0; i < pcm_nblk; i++)
- pcm_datasize[i] = 0;
+ for (i = 0; i < pcm_nblk; i++)
+ pcm_datasize[i] = 0;
- pcm_banksize = pcm_nblk * pcm_bsize;
+ pcm_banksize = pcm_nblk * pcm_bsize;
- if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
- pcm_nblk--;
+ if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
+ pcm_nblk--;
- return 0;
+ return 0;
}
static int
-gus_local_qlen (int dev)
+gus_local_qlen(int dev)
{
- return pcm_qlen;
+ return pcm_qlen;
}
static void
-gus_copy_from_user (int dev, char *localbuf, int localoffs,
- snd_rw_buf * userbuf, int useroffs, int len)
+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);
- }
- else if (gus_sampling_bits == 8)
- {
- int in_left = useroffs;
- int in_right = useroffs + 1;
- char *out_left, *out_right;
- int i;
-
- len /= 2;
- localoffs /= 2;
- out_left = &localbuf[localoffs];
- out_right = out_left + pcm_bsize;
-
- for (i = 0; i < len; i++)
- {
- GET_BYTE_FROM_USER (*out_left++, userbuf, in_left);
- in_left += 2;
- GET_BYTE_FROM_USER (*out_right++, userbuf, in_right);
- in_right += 2;
+ if (gus_sampling_channels == 1) {
+
+ if (uiomove(&localbuf[localoffs], len, userbuf)) {
+ printf("audio: Bad copyin()!\n");
+ };
+ } else if (gus_sampling_bits == 8) {
+ int in_left = useroffs;
+ int in_right = useroffs + 1;
+ char *out_left, *out_right;
+ int i;
+
+ len /= 2;
+ localoffs /= 2;
+ out_left = &localbuf[localoffs];
+ out_right = out_left + pcm_bsize;
+
+ for (i = 0; i < len; i++) {
+ uiomove((char *) &(*out_left++), 1, userbuf);
+ in_left += 2;
+ uiomove((char *) &(*out_right++), 1, userbuf);
+ in_right += 2;
+ }
+ } else {
+ int in_left = useroffs;
+ int in_right = useroffs + 2;
+ short *out_left, *out_right;
+ int i;
+
+ len /= 4;
+ localoffs /= 2;
+
+ out_left = (short *) &localbuf[localoffs];
+ out_right = out_left + (pcm_bsize / 2);
+
+ for (i = 0; i < len; i++) {
+ uiomove((char *) &(*out_left++), 2, userbuf);
+ in_left += 2;
+ uiomove((char *) &(*out_right++), 2, userbuf);
+ in_right += 2;
+ }
}
- }
- else
- {
- int in_left = useroffs;
- int in_right = useroffs + 1;
- short *out_left, *out_right;
- int i;
-
- len /= 4;
- localoffs /= 4;
-
- out_left = (short *) &localbuf[localoffs];
- out_right = out_left + (pcm_bsize / 2);
-
- for (i = 0; i < len; i++)
- {
- GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left);
- in_left += 2;
- GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right);
- in_right += 2;
- }
- }
}
static struct audio_operations gus_sampling_operations =
{
- "Gravis UltraSound",
- NEEDS_RESTART,
- AFMT_U8 | AFMT_S16_LE,
- NULL,
- gus_sampling_open,
- gus_sampling_close,
- gus_sampling_output_block,
- gus_sampling_start_input,
- gus_sampling_ioctl,
- gus_sampling_prepare_for_input,
- gus_sampling_prepare_for_output,
- gus_sampling_reset,
- gus_sampling_reset,
- gus_local_qlen,
- gus_copy_from_user
+ "Gravis UltraSound",
+ NEEDS_RESTART,
+ AFMT_U8 | AFMT_S16_LE,
+ NULL,
+ gus_sampling_open,
+ gus_sampling_close,
+ gus_sampling_output_block,
+ gus_sampling_start_input,
+ gus_sampling_ioctl,
+ gus_sampling_prepare_for_input,
+ gus_sampling_prepare_for_output,
+ gus_sampling_reset,
+ gus_sampling_reset,
+ gus_local_qlen,
+ gus_copy_from_user
};
static void
-guswave_bender (int dev, int voice, int value)
+guswave_setup_voice(int dev, int voice, int chn)
{
- 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;
+ struct channel_info *info =
+ &synth_devs[dev]->chn_info[chn];
+
+ guswave_set_instr(dev, voice, info->pgm_num);
+
+ voices[voice].expression_vol =
+ info->controllers[CTL_EXPRESSION]; /* Just msb */
+ voices[voice].main_vol =
+ (info->controllers[CTL_MAIN_VOLUME] * 100) / 128;
+ voices[voice].panning =
+ (info->controllers[CTL_PAN] * 2) - 128;
+ voices[voice].bender = info->bender_value;
+}
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (freq);
- RESTORE_INTR (flags);
+static void
+guswave_bender(int dev, int voice, int value)
+{
+ int freq;
+ u_long flags;
+
+ voices[voice].bender = value - 8192;
+ freq = compute_finetune(voices[voice].orig_freq, value - 8192,
+ voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_freq(freq);
+ splx(flags);
}
static int
-guswave_patchmgr (int dev, struct patmgr_info *rec)
+guswave_patchmgr(int dev, struct patmgr_info * rec)
{
- int i, n;
+ int i, n;
- switch (rec->command)
- {
- case PM_GET_DEVTYPE:
- rec->parm1 = PMTYPE_WAVE;
- return 0;
- break;
+ switch (rec->command) {
+ case PM_GET_DEVTYPE:
+ rec->parm1 = PMTYPE_WAVE;
+ return 0;
+ break;
- case PM_GET_NRPGM:
- rec->parm1 = MAX_PATCH;
- return 0;
- break;
+ case PM_GET_NRPGM:
+ rec->parm1 = MAX_PATCH;
+ return 0;
+ break;
- case PM_GET_PGMMAP:
- rec->parm1 = MAX_PATCH;
+ case PM_GET_PGMMAP:
+ rec->parm1 = MAX_PATCH;
- for (i = 0; i < MAX_PATCH; i++)
- {
- int ptr = patch_table[i];
+ for (i = 0; i < MAX_PATCH; i++) {
+ int ptr = patch_table[i];
- rec->data.data8[i] = 0;
+ rec->data.data8[i] = 0;
- while (ptr >= 0 && ptr < free_sample)
- {
- rec->data.data8[i]++;
- ptr = samples[ptr].key; /* Follow link */
- }
- }
- return 0;
- break;
+ while (ptr >= 0 && ptr < free_sample) {
+ rec->data.data8[i]++;
+ ptr = samples[ptr].key; /* Follow link */
+ }
+ }
+ return 0;
+ break;
- case PM_GET_PGM_PATCHES:
- {
- int ptr = patch_table[rec->parm1];
-
- n = 0;
-
- while (ptr >= 0 && ptr < free_sample)
- {
- rec->data.data32[n++] = ptr;
- ptr = samples[ptr].key; /* Follow link */
- }
- }
- rec->parm1 = n;
- return 0;
- break;
-
- case PM_GET_PATCH:
- {
- int ptr = rec->parm1;
- struct patch_info *pat;
-
- if (ptr < 0 || ptr >= free_sample)
- return RET_ERROR (EINVAL);
-
- memcpy (rec->data.data8, (char *) &samples[ptr],
- sizeof (struct patch_info));
+ case PM_GET_PGM_PATCHES:
+ {
+ int ptr = patch_table[rec->parm1];
- pat = (struct patch_info *) rec->data.data8;
-
- pat->key = GUS_PATCH; /* Restore patch type */
- rec->parm1 = sample_ptrs[ptr]; /* DRAM location */
- rec->parm2 = sizeof (struct patch_info);
- }
- return 0;
- break;
-
- case PM_SET_PATCH:
- {
- int ptr = rec->parm1;
- struct patch_info *pat;
-
- if (ptr < 0 || ptr >= free_sample)
- return RET_ERROR (EINVAL);
-
- pat = (struct patch_info *) rec->data.data8;
-
- if (pat->len > samples[ptr].len) /* Cannot expand sample */
- return RET_ERROR (EINVAL);
-
- pat->key = samples[ptr].key; /* Ensure the link is correct */
-
- memcpy ((char *) &samples[ptr], rec->data.data8,
- sizeof (struct patch_info));
-
- pat->key = GUS_PATCH;
- }
- return 0;
- break;
-
- case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */
- {
- int sample = rec->parm1;
- int n;
- long offs = rec->parm2;
- int l = rec->parm3;
-
- if (sample < 0 || sample >= free_sample)
- return RET_ERROR (EINVAL);
-
- if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /* Invalid offset */
-
- n = samples[sample].len - offs; /* Num of bytes left */
-
- if (l > n)
- l = n;
-
- if (l > sizeof (rec->data.data8))
- l = sizeof (rec->data.data8);
-
- if (l <= 0)
- return RET_ERROR (EINVAL); /*
- * Was there a bug?
- */
-
- 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
- */
- }
- return 0;
- break;
-
- case PM_WRITE_PATCH: /*
- * Writes a block of wave data to the DRAM
- */
- {
- int sample = rec->parm1;
- int n;
- long offs = rec->parm2;
- int l = rec->parm3;
-
- if (sample < 0 || sample >= free_sample)
- return RET_ERROR (EINVAL);
-
- if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /*
- * Invalid offset
- */
-
- n = samples[sample].len - offs; /*
- * Nr of bytes left
- */
-
- if (l > n)
- l = n;
-
- if (l > sizeof (rec->data.data8))
- l = sizeof (rec->data.data8);
-
- if (l <= 0)
- return RET_ERROR (EINVAL); /*
- * Was there a bug?
- */
-
- 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
- */
- }
- return 0;
- break;
+ n = 0;
- default:
- return RET_ERROR (EINVAL);
- }
+ while (ptr >= 0 && ptr < free_sample) {
+ rec->data.data32[n++] = ptr;
+ ptr = samples[ptr].key; /* Follow link */
+ }
+ }
+ rec->parm1 = n;
+ return 0;
+ break;
+
+ case PM_GET_PATCH:
+ {
+ int ptr = rec->parm1;
+ struct patch_info *pat;
+
+ if (ptr < 0 || ptr >= free_sample)
+ return -(EINVAL);
+
+ bcopy((char *) &samples[ptr], rec->data.data8, sizeof(struct patch_info));
+
+ pat = (struct patch_info *) rec->data.data8;
+
+ pat->key = GUS_PATCH; /* Restore patch type */
+ rec->parm1 = sample_ptrs[ptr]; /* DRAM location */
+ rec->parm2 = sizeof(struct patch_info);
+ }
+ return 0;
+ break;
+
+ case PM_SET_PATCH:
+ {
+ int ptr = rec->parm1;
+ struct patch_info *pat;
+
+ if (ptr < 0 || ptr >= free_sample)
+ return -(EINVAL);
+
+ pat = (struct patch_info *) rec->data.data8;
+
+ if (pat->len > samples[ptr].len) /* Cannot expand sample */
+ return -(EINVAL);
+
+ pat->key = samples[ptr].key; /* Ensure the link is
+ * correct */
+
+ bcopy(rec->data.data8, (char *) &samples[ptr], sizeof(struct patch_info));
+
+ pat->key = GUS_PATCH;
+ }
+ return 0;
+ break;
+
+ case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */
+ {
+ int sample = rec->parm1;
+ int n;
+ long offs = rec->parm2;
+ int l = rec->parm3;
+
+ if (sample < 0 || sample >= free_sample)
+ return -(EINVAL);
+
+ if (offs < 0 || offs >= samples[sample].len)
+ return -(EINVAL); /* Invalid offset */
+
+ n = samples[sample].len - offs; /* Num of bytes left */
+
+ if (l > n)
+ l = n;
+
+ if (l > sizeof(rec->data.data8))
+ l = sizeof(rec->data.data8);
+
+ if (l <= 0)
+ return -(EINVAL); /* Was there a bug? */
+
+ 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 */
+ }
+ return 0;
+ break;
+
+ case PM_WRITE_PATCH: /* Writes a block of wave data to the DRAM */
+ {
+ int sample = rec->parm1;
+ int n;
+ long offs = rec->parm2;
+ int l = rec->parm3;
+
+ if (sample < 0 || sample >= free_sample)
+ return -(EINVAL);
+
+ if (offs < 0 || offs >= samples[sample].len)
+ return -(EINVAL); /* Invalid offset */
+
+ n = samples[sample].len - offs; /* Nr of bytes left */
+
+ if (l > n)
+ l = n;
+
+ if (l > sizeof(rec->data.data8))
+ l = sizeof(rec->data.data8);
+
+ if (l <= 0)
+ return -(EINVAL); /* Was there a bug? */
+
+ 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 */
+ }
+ return 0;
+ break;
+
+ default:
+ return -(EINVAL);
+ }
}
static int
-guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
+guswave_alloc(int dev, int chn, int note, struct voice_alloc_info * alloc)
{
- int i, p;
+ int i, p, best = -1, best_time = 0x7fffffff;
- p = alloc->ptr;
- /*
- * First look for a completely stopped voice
- */
+ p = alloc->ptr;
+ /*
+ * First look for a completely stopped voice
+ */
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0)
- {
- alloc->ptr = p;
- return p;
+ for (i = 0; i < alloc->max_voice; i++) {
+ if (alloc->map[p] == 0) {
+ alloc->ptr = p;
+ return p;
+ }
+ if (alloc->alloc_times[p] < best_time) {
+ best = p;
+ best_time = alloc->alloc_times[p];
+ }
+ p = (p + 1) % alloc->max_voice;
}
- p = (p + 1) % alloc->max_voice;
- }
- /*
- * Then look for a releasing voice
- */
+ /*
+ * Then look for a releasing voice
+ */
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0xffff)
- {
- alloc->ptr = p;
- return p;
+ for (i = 0; i < alloc->max_voice; i++) {
+ if (alloc->map[p] == 0xffff) {
+ alloc->ptr = p;
+ return p;
+ }
+ p = (p + 1) % alloc->max_voice;
}
- p = (p + 1) % alloc->max_voice;
- }
- printk ("GUS: Out of free voices\n");
- alloc->ptr = p;
- return p;
+ if (best >= 0)
+ p = best;
+
+ alloc->ptr = p;
+ return p;
}
static struct synth_operations guswave_operations =
{
- &gus_info,
- 0,
- SYNTH_TYPE_SAMPLE,
- SAMPLE_TYPE_GUS,
- guswave_open,
- guswave_close,
- guswave_ioctl,
- guswave_kill_note,
- guswave_start_note,
- guswave_set_instr,
- guswave_reset,
- guswave_hw_control,
- guswave_load_patch,
- guswave_aftertouch,
- guswave_controller,
- guswave_panning,
- guswave_volume_method,
- guswave_patchmgr,
- guswave_bender,
- guswave_alloc
+ &gus_info,
+ 0,
+ SYNTH_TYPE_SAMPLE,
+ SAMPLE_TYPE_GUS,
+ guswave_open,
+ guswave_close,
+ guswave_ioctl,
+ guswave_kill_note,
+ guswave_start_note,
+ guswave_set_instr,
+ guswave_reset,
+ guswave_hw_control,
+ guswave_load_patch,
+ guswave_aftertouch,
+ guswave_controller,
+ guswave_panning,
+ guswave_volume_method,
+ guswave_patchmgr,
+ guswave_bender,
+ guswave_alloc,
+ guswave_setup_voice
};
static void
-set_input_volumes (void)
+set_input_volumes(void)
{
- unsigned long flags;
- unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
+ u_long flags;
+ u_char mask = 0xff & ~0x06; /* Just line out enabled */
- DISABLE_INTR (flags);
+ if (have_gus_max) /* Don't disturb GUS MAX */
+ return;
- /*
- * 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;
- }
+ flags = splhigh();
- mix_image &= ~0x07;
- mix_image |= mask & 0x07;
- OUTB (mix_image, u_Mixer);
+ /*
+ * Enable channels having vol > 10% Note! bit 0x01 means the line in
+ * DISABLED while 0x04 means the 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(u_Mixer, mix_image);
- RESTORE_INTR (flags);
+ splx(flags);
}
int
-gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+gus_default_mixer_ioctl(int dev, u_int cmd, ioctl_arg 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));
+ if (((cmd >> 8) & 0xff) == 'M') {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ gus_recmask = (*(int *) 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 *(int *) arg = gus_recmask;
+ break;
+
+ case SOUND_MIXER_MIC:
+ {
+ int vol = (*(int *) arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_mic_vol = vol;
+ set_input_volumes();
+ return *(int *) arg = vol | (vol << 8);
+ }
+ break;
+
+ case SOUND_MIXER_LINE:
+ {
+ int vol = (*(int *) arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_line_vol = vol;
+ set_input_volumes();
+ return *(int *) arg = vol | (vol << 8);
+ }
+ break;
+
+ case SOUND_MIXER_PCM:
+ gus_pcm_volume = (*(int *) arg) & 0xff;
+ RANGE (gus_pcm_volume, 0, 100);
+ gus_sampling_update_volume();
+ return *(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8);
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ {
+ int voice;
+
+ gus_wave_volume = (*(int *) arg) & 0xff;
+
+ RANGE (gus_wave_volume , 0, 100);
+
+ if (active_device == GUS_DEV_WAVE)
+ for (voice = 0; voice < nr_voices; voice++)
+ dynamic_volume_change(voice); /* Apply the new vol */
+
+ return *(int *) arg = gus_wave_volume | (gus_wave_volume << 8);
+ }
+ break;
+
+ default:
+ return -(EINVAL);
}
- break;
+ else
+ switch (cmd & 0xff) { /* Return parameters */
- 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_RECSRC:
+ return *(int *) arg = gus_recmask;
+ 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_DEVMASK:
+ return *(int *) arg = MIX_DEVS;
+ break;
- case SOUND_MIXER_SYNTH:
- {
- int voice;
+ case SOUND_MIXER_STEREODEVS:
+ return *(int *) arg = 0;
+ break;
- gus_wave_volume = IOCTL_IN (arg) & 0xff;
+ case SOUND_MIXER_RECMASK:
+ return *(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE;
+ break;
- if (gus_wave_volume < 0)
- gus_wave_volume = 0;
- if (gus_wave_volume > 100)
- gus_wave_volume = 100;
+ case SOUND_MIXER_CAPS:
+ return *(int *) arg = 0;
+ break;
- if (active_device == GUS_DEV_WAVE)
- for (voice = 0; voice < nr_voices; voice++)
- dynamic_volume_change (voice); /* Apply the new vol */
+ case SOUND_MIXER_MIC:
+ return *(int *) arg = gus_mic_vol | (gus_mic_vol << 8);
+ break;
- return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ case SOUND_MIXER_LINE:
+ return *(int *) arg = gus_line_vol | (gus_line_vol << 8);
+ break;
+
+ case SOUND_MIXER_PCM:
+ return *(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8);
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return *(int *) arg = gus_wave_volume | (gus_wave_volume << 8);
+ break;
+
+ default:
+ return -(EINVAL);
}
- break;
+} else
+ return -(EINVAL);
+}
- default:
- return RET_ERROR (EINVAL);
- }
- else
- switch (cmd & 0xff) /*
- * Return parameters
- */
- {
-
- case SOUND_MIXER_RECSRC:
- return IOCTL_OUT (arg, gus_recmask);
- break;
+static struct mixer_operations gus_mixer_operations = {"Gravis Ultrasound", gus_default_mixer_ioctl};
- case SOUND_MIXER_DEVMASK:
- return IOCTL_OUT (arg, MIX_DEVS);
- break;
+static void
+gus_default_mixer_init()
+{
+if (num_mixers < MAX_MIXER_DEV) /* Don't install if there is another
+ * mixer */
+ mixer_devs[num_mixers++] = &gus_mixer_operations;
- case SOUND_MIXER_STEREODEVS:
- return IOCTL_OUT (arg, 0);
- break;
+if (have_gus_max) {
+ /*
+ * Enable all mixer channels on the GF1 side. Otherwise
+ * recording will not be possible using GUS MAX.
+ */
+ mix_image &= ~0x07;
+ mix_image |= 0x04; /* All channels enabled */
+ outb(u_Mixer, mix_image);
+}
+}
- case SOUND_MIXER_RECMASK:
- return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
- break;
+/* start of pnp code */
- case SOUND_MIXER_CAPS:
- return IOCTL_OUT (arg, 0);
- break;
+void
+SEND(int d, int r)
+{
+outb(PADDRESS, d);
+outb(PWRITE_DATA, r);
+}
- 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;
+/*
+ * Get the device's serial number. Returns 1 if the serial is valid.
+ */
+int
+get_serial(int rd_port, u_char *data)
+{
+ int i, bit, valid = 0, sum = 0x6a;
- default:
- return RET_ERROR (EINVAL);
- }
- }
- else
- return RET_ERROR (EINVAL);
+ bzero(data, sizeof(char) * 9);
+
+ for (i = 0; i < 72; i++) {
+ bit = inb((rd_port << 2) | 0x3) == 0x55;
+ DELAY(250); /* Delay 250 usec */
+
+ /* Can't Short Circuit the next evaluation, so 'and' is last */
+ bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
+ DELAY(250); /* Delay 250 usec */
+
+ valid = valid || bit;
+
+ if (i < 64)
+ sum = (sum >> 1) |
+ (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
+
+ data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
+ }
+ valid = valid && (data[8] == sum);
+
+ return valid;
}
-static struct mixer_operations gus_mixer_operations =
+void
+send_Initiation_LFSR()
{
- gus_default_mixer_ioctl
-};
+ int cur, i;
+
+ /* Reset the LSFR */
+ outb(PADDRESS, 0);
+ outb(PADDRESS, 0);
-static long
-gus_default_mixer_init (long mem_start)
+ cur = 0x6a;
+ outb(PADDRESS, cur);
+
+ for (i = 1; i < 32; i++) {
+ cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
+ outb(PADDRESS, cur);
+ }
+}
+
+
+
+int
+isolation_protocol(int rd_port)
{
- if (num_mixers < MAX_MIXER_DEV) /*
- * Don't install if there is another
- * mixer
- */
- mixer_devs[num_mixers++] = &gus_mixer_operations;
+ int csn;
+ u_char data[9];
+
+ send_Initiation_LFSR();
- return mem_start;
+ /* Reset CSN for All Cards */
+ SEND(0x02, 0x04);
+
+ for (csn = 1; (csn < MAX_CARDS); csn++) {
+ /* Wake up cards without a CSN */
+
+ SEND(WAKE, 0);
+ SEND(SET_RD_DATA, rd_port);
+ outb(PADDRESS, SERIAL_ISOLATION);
+ DELAY(1000); /* Delay 1 msec */
+ if (get_serial(rd_port, data)) {
+ printf("Board Vendor ID: %c%c%c%02x%02x",
+ ((data[0] & 0x7c) >> 2) + 64,
+ (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
+ (data[1] & 0x1f) + 64, data[2], data[3]);
+ printf(" Board Serial Number: %08x\n", *(int *) &(data[4]));
+
+ SEND(SET_CSN, csn); /* Move this out of this
+ * function XXX */
+ outb(PADDRESS, PSTATUS);
+
+
+ return rd_port;
+ } else
+ break;
+ }
+
+ return 0;
}
-long
-gus_wave_init (long mem_start, int irq, int dma)
+
+
+void
+IwaveDelay(WORD count)
{
- unsigned long flags;
- unsigned char val;
- char *model_num = "2.4";
- int gus_type = 0x24; /* 2.4 */
- int mixer_type = 0;
+ WORD cur_cnt = 0, last_cnt;
+ BYTE reg, portb;
+
+ count = 1193 * count; /* convert number of ms to counter */
+ last_cnt = count;
+ portb = inb(0x61) & 0xFC;
+ outb(0x61, portb); /* disable counter */
+ outb(0x43, 0xB0); /* load LSB first then MSB */
+ outb(0x42, (BYTE) count);
+ outb(0x42, (BYTE) (count >> 8));
+ outb(0x61, (BYTE) (portb | 0x01)); /* enable counter */
+ while (cur_cnt <= count) {
+ outb(0x43, 0x80); /* latch counter */
+ reg = inb(0x42);/* read latched value */
+ cur_cnt = (((WORD) inb(0x42)) << 8) | reg;
+ if (cur_cnt > last_cnt)
+ break;
+ last_cnt = cur_cnt;
+ }
+ outb(0x61, portb); /* disable counter */
+}
- /*
- * Try to identify the GUS model.
- *
- * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+/*
+ * ########################################################################
+ *
+ * FUNCTION: IwaveStopDma
+ *
+ * PROFILE: This function stops an active DMA transfer to or from the record or
+ * playback FIFOs. Set the "path" variable to either PLAYBACK or RECORD.
+ * ########################################################################
*/
- DISABLE_INTR (flags);
- OUTB (0x20, gus_base + 0x0f);
- val = INB (gus_base + 0x0f);
- RESTORE_INTR (flags);
+void
+IwaveStopDma(BYTE path)
+{
+ BYTE reg;
- 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.
- */
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | _CFIG1I); /* select CFIG1I */
+ outb(iw.cdatap, (BYTE) (inb(iw.cdatap) & ~path)); /* disable playback path */
+ LEAVE_CRITICAL;
+}
- val = INB (u_MixSelect);
+/*
+ * ########################################################################
+ *
+ * FUNCTION : IwaveInputSource
+ *
+ * PROFILE: This function allows the calling program to select among any of
+ * several possible sources to the ADC's. The possible input sources and
+ * their corresponding symbolic constants are: - Line (LINE_IN) - Aux1
+ * (AUX1_IN) - Microphone (MIC_IN) - Mixer (MIX_IN)
+ *
+ * Set the first argument to either LEFT_SOURCE or RIGHT_SOURCE. Always use the
+ * symbolic contants for the arguments.
+ *
+ * ########################################################################
+ */
+void
+IwaveInputSource(BYTE index, BYTE source)
+{
+ BYTE reg;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | index); /* select register CLICI or CRICI */
+ reg = inb(iw.cdatap) & ~MIX_IN;
+ source &= MIX_IN;
+ outb(iw.cdatap, (BYTE) (reg | source));
+ LEAVE_CRITICAL;
+}
+void
+IwavePnpGetCfg(void)
+{
+ WORD val;
+
+
+ ENTER_CRITICAL;
+ IwavePnpDevice(AUDIO);
+ outb(_PIDXR, 0x60); /* select P2X0HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P2XR[9:8] */
+ outb(_PIDXR, 0x61); /* select P2XRLI */
+ iw.p2xr = val + (WORD) inb(iw.pnprdp); /* get P2XR[7:4] */
+
+ outb(_PIDXR, 0x62); /* select P3X0HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P3XR[9:8] */
+ outb(_PIDXR, 0x63); /* select P3X0LI */
+ iw.p3xr = val + (WORD) inb(iw.pnprdp); /* get P3XR[7:3] */
+
+ outb(_PIDXR, 0x64); /* select PHCAI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get PCODAR[9:8] */
+ outb(_PIDXR, 0x65); /* select PLCAI */
+ iw.pcodar = val + (WORD) inb(iw.pnprdp); /* get PCODAR[7:2] */
+
+ outb(_PIDXR, 0x70); /* select PUI1SI */
+ iw.synth_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* Synth IRQ number */
+
+ outb(_PIDXR, 0x72); /* select PUI2SI */
+ iw.midi_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* MIDI IRQ number */
+
+ outb(_PIDXR, 0x74); /* select PUD1SI */
+ iw.dma1_chan = inb(iw.pnprdp) & 0x07; /* DMA1 chan (LMC/Codec Rec) */
+
+ outb(_PIDXR, 0x75); /* select PUD2SI */
+ iw.dma2_chan = inb(iw.pnprdp) & 0x07; /* DMA2 chan (codec play) */
+
+
+ IwavePnpDevice(EXT); /* select external device */
+ outb(_PIDXR, 0x60); /* select PRAHI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get PCDRAR[9:8] */
+ outb(_PIDXR, 0x61); /* select PRALI */
+ iw.pcdrar = val + (WORD) inb(iw.pnprdp); /* get PCDRAR[7:4] */
+ outb(_PIDXR, 0x62); /* select PATAHI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get PATAAR[9:8] */
+ outb(_PIDXR, 0x63); /* select PATALI */
+ iw.pataar = val + (WORD) inb(iw.pnprdp); /* get PATAAR[7:1] */
+
+ outb(_PIDXR, 0x70); /* select PRISI */
+ iw.ext_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* Ext Dev IRQ number */
+
+ outb(_PIDXR, 0x74); /* select PRDSI */
+ iw.ext_chan = inb(iw.pnprdp) & 0x07; /* Ext Dev DMA channel */
+
+ IwavePnpDevice(MPU401); /* Select MPU401 Device */
+ outb(_PIDXR, 0x60); /* select P401HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P401AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P401LI */
+ iw.p401ar = val + (WORD) inb(iw.pnprdp); /* get P401AR[7:1] */
+
+ outb(_PIDXR, 0x70); /* select PMISI */
+ iw.mpu_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* MPU401 Dev IRQ number */
+
+ IwavePnpDevice(GAME); /* Select GAME logical Device */
+ outb(_PIDXR, 0x60); /* select P201HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P201AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P201LI */
+ iw.p201ar = val + (WORD) inb(iw.pnprdp); /* get P201AR[7:6] */
+
+ IwavePnpDevice(EMULATION); /* Select SB and ADLIB Device */
+ outb(_PIDXR, 0x60); /* select P388HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P388AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P388LI */
+ iw.p388ar = val + inb(iw.pnprdp); /* get P388AR[7:6] */
+ outb(_PIDXR, 0x70); /* select PSBISI */
+ iw.emul_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* emulation Dev IRQ
+ * number */
+ LEAVE_CRITICAL;
+}
+
+void
+IwavePnpSetCfg(void)
+{
+ ENTER_CRITICAL;
+ IwavePnpDevice(AUDIO); /* select audio device */
+ outb(_PIDXR, 0x60); /* select P2X0HI */
+ outb(_PNPWRP, (BYTE) (iw.p2xr >> 8)); /* set P2XR[9:8] */
+ outb(_PIDXR, 0x61); /* select P2X0LI */
+ outb(_PNPWRP, (BYTE) iw.p2xr); /* set P2XR[7:4] */
+ /* P2XR[3:0]=0 */
+ outb(_PIDXR, 0x62); /* select P3X0HI */
+ outb(_PNPWRP, (BYTE) (iw.p3xr >> 8)); /* set P3XR[9:8] */
+ outb(_PIDXR, 0x63); /* select P3X0LI */
+ outb(_PNPWRP, (BYTE) (iw.p3xr)); /* set P3XR[7:3] */
+ /* P3XR[2:0]=0 */
+ outb(_PIDXR, 0x64); /* select PHCAI */
+ outb(_PNPWRP, (BYTE) (iw.pcodar >> 8)); /* set PCODAR[9:8] */
+ outb(_PIDXR, 0x65); /* select PLCAI */
+ outb(_PNPWRP, (BYTE) iw.pcodar); /* set PCODAR[7:2] */
+
+ outb(_PIDXR, 0x70); /* select PUI1SI */
+ outb(_PNPWRP, (BYTE) (iw.synth_irq & 0x0F)); /* Synth IRQ number */
+ outb(_PIDXR, 0x72); /* select PUI2SI */
+ outb(_PNPWRP, (BYTE) (iw.midi_irq & 0x0F)); /* MIDI IRQ number */
+
+ outb(_PIDXR, 0x74); /* select PUD1SI */
+ outb(_PNPWRP, (BYTE) (iw.dma1_chan & 0x07)); /* DMA channel 1 */
+ outb(_PIDXR, 0x75); /* select PUD2SI */
+ outb(_PNPWRP, (BYTE) (iw.dma2_chan & 0x07)); /* DMA channel 2 */
+
+ IwavePnpDevice(EXT);
+ outb(_PIDXR, 0x60); /* select PRAHI */
+ outb(_PNPWRP, (BYTE) (iw.pcdrar >> 8)); /* set PCDRAR[9:8] */
+ outb(_PIDXR, 0x61); /* select PRALI */
+ outb(_PNPWRP, (BYTE) iw.pcdrar); /* set PCDRAR[7:3] */
+ /* PCDRAR[2:0]=0 */
+ outb(_PIDXR, 0x62); /* select PATAHI */
+ outb(_PNPWRP, (BYTE) (iw.pataar >> 8)); /* set PATAAR[9:8] */
+ outb(_PIDXR, 0x63); /* select PATALI */
+ outb(_PNPWRP, (BYTE) iw.pataar); /* set PATAAR[7:1] */
+ /* PATAAR[0]=0 */
+ outb(_PIDXR, 0x70); /* select PRISI */
+ outb(_PNPWRP, (BYTE) (iw.ext_irq & 0x0F)); /* Ext Dev IRQ number */
+ outb(_PIDXR, 0x74); /* select PRDSI */
+ outb(_PNPWRP, (BYTE) (iw.ext_chan & 0x07)); /* Ext Dev DMA channel */
+
+ IwavePnpDevice(GAME);
+ outb(_PIDXR, 0x60); /* select P201HI */
+ outb(_PNPWRP, (BYTE) (iw.p201ar >> 8)); /* set P201RAR[9:8] */
+ outb(_PIDXR, 0x61); /* select P201LI */
+ outb(_PNPWRP, (BYTE) iw.p201ar); /* set P201AR[7:6] */
+
+ IwavePnpDevice(EMULATION);
+ outb(_PIDXR, 0x60); /* select P388HI */
+ outb(_PNPWRP, (BYTE) (iw.p388ar >> 8)); /* set P388AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P388LI */
+ outb(_PNPWRP, (BYTE) iw.p388ar); /* set P388AR[7:6] */
+
+ outb(_PIDXR, 0x70); /* select PSBISI */
+ outb(_PNPWRP, (BYTE) (iw.emul_irq & 0x0F)); /* emulation IRQ number */
+
+ IwavePnpDevice(MPU401);
+ outb(_PIDXR, 0x60); /* select P401HI */
+ outb(_PNPWRP, (BYTE) (iw.p401ar >> 8)); /* set P401AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P401LI */
+ outb(_PNPWRP, (BYTE) iw.p401ar); /* set P401AR[7:1] */
+
+ outb(_PIDXR, 0x70); /* select PMISI */
+ outb(_PNPWRP, (BYTE) (iw.mpu_irq & 0x0F)); /* MPU emulation IRQ
+ * number */
+ LEAVE_CRITICAL;
+}
+
+void
+IwaveCfgIOSpace(void)
+{
+ ENTER_CRITICAL;
+ IwavePnpDevice(AUDIO); /* select audio device */
+ outb(_PIDXR, 0x60); /* select P2X0HI */
+ outb(_PNPWRP, (BYTE) (iw.p2xr >> 8)); /* set P2XR[9:8] */
+ outb(_PIDXR, 0x61); /* select P2X0LI */
+ outb(_PNPWRP, (BYTE) iw.p2xr); /* set P2XR[7:4] */
+ /* P2XR[3:0]=0 */
+ outb(_PIDXR, 0x62); /* select P3X0HI */
+ outb(_PNPWRP, (BYTE) (iw.p3xr >> 8)); /* set P3XR[9:8] */
+ outb(_PIDXR, 0x63); /* select P3X0LI */
+ outb(_PNPWRP, (BYTE) (iw.p3xr)); /* set P3XR[7:3] */
+ /* P3XR[2:0]=0 */
+ outb(_PIDXR, 0x64); /* select PHCAI */
+ outb(_PNPWRP, (BYTE) (iw.pcodar >> 8)); /* set PCODAR[9:8] */
+ outb(_PIDXR, 0x65); /* select PLCAI */
+ outb(_PNPWRP, (BYTE) iw.pcodar); /* set PCODAR[7:2] */
+
+ IwavePnpDevice(EXT);
+ outb(_PIDXR, 0x60); /* select PRAHI */
+ outb(_PNPWRP, (BYTE) (iw.pcdrar >> 8)); /* set PCDRAR[9:8] */
+ outb(_PIDXR, 0x61); /* select PRALI */
+ outb(_PNPWRP, (BYTE) iw.pcdrar); /* set PCDRAR[7:3] */
+ /* PCDRAR[2:0]=0 */
+ outb(_PIDXR, 0x62); /* select PATAHI */
+ outb(_PNPWRP, (BYTE) (iw.pataar >> 8)); /* set PATAAR[9:8] */
+ outb(_PIDXR, 0x63); /* select PATALI */
+ outb(_PNPWRP, (BYTE) iw.pataar); /* set PATAAR[7:1] */
+ /* PATAAR[0]=0 */
+ IwavePnpDevice(GAME);
+ outb(_PIDXR, 0x60); /* select P201HI */
+ outb(_PNPWRP, (BYTE) (iw.p201ar >> 8)); /* set P201RAR[9:8] */
+ outb(_PIDXR, 0x61); /* select P201LI */
+ outb(_PNPWRP, (BYTE) iw.p201ar); /* set P201AR[7:6] */
+
+ IwavePnpDevice(EMULATION);
+ outb(_PIDXR, 0x60); /* select P388HI */
+ outb(_PNPWRP, (BYTE) (iw.p388ar >> 8)); /* set P388AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P388LI */
+ outb(_PNPWRP, (BYTE) iw.p388ar); /* set P388AR[7:6] */
+
+ IwavePnpDevice(MPU401);
+ outb(_PIDXR, 0x60); /* select P401HI */
+ outb(_PNPWRP, (BYTE) (iw.p401ar >> 8)); /* set P401AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P401LI */
+ outb(_PNPWRP, (BYTE) iw.p401ar); /* set P401AR[7:1] */
+ LEAVE_CRITICAL;
+}
- /*
- * 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;
+/* ######################################################################## */
+/* FILE: iwpnp.c */
+/* */
+/* REMARKS: This file contains the definitions for the InterWave's DDK */
+/* functions dedicated to the configuration of the InterWave */
+/* PNP logic. */
+/* */
+/* UPDATE: 4/07/95 */
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpKey */
+/* */
+/* PROFILE: This function issues the initiation key that places the PNP */
+/* logic into configuration mode. The PNP logic is quiescent at */
+/* power up and must be enabled by software. This function will */
+/* do 32 I/O writes to the PIDXR (0x0279). The function will */
+/* first reset the LFSR to its initial value by a sequence of two */
+/* write cycles of 0x00 to PIDXR before issuing the key. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpKey(void)
+{
+ /* send_Initiation_LFSR(); */
+
+ BYTE code = 0x6A;
+ BYTE msb;
+ BYTE i;
+
+ /* ############################################### */
+ /* Reset Linear Feedback Shift Reg. */
+ /* ############################################### */
+ outb(0x279, 0x00);
+ outb(0x279, 0x00);
+
+ outb(0x279, code); /* Initial value */
+
+ for (i = 1; i < 32; i++) {
+ msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
+ code = (code >> 1) | msb;
+ outb(0x279, code);
}
- else if (val < 10)
- {
- model_num = "3.7";
- gus_type = 0x37;
- mixer_type = ICS2101;
+
+}
+
+BYTE
+IwavePnpIsol(PORT * pnpread)
+{
+ int num_pnp_devs;
+ int rd_port = 0;
+ printf("Checking for GUS Plug-n-Play ...\n");
+
+ /* Try various READ_DATA ports from 0x203-0x3ff */
+ for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
+ if (0)
+ printf("Trying Read_Port at %x\n",
+ (rd_port << 2) | 0x3);
+
+ num_pnp_devs = isolation_protocol(rd_port);
+ if (num_pnp_devs) {
+ *pnpread = rd_port << 2 | 0x3;
+ break;
+ }
+ }
+ if (!num_pnp_devs) {
+ printf("No Plug-n-Play devices were found\n");
+ return 0;
+ }
+ return 1;
+}
+
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpSerial */
+/* */
+/* PROFILE: This function reads the first nine bytes of the data from */
+/* the serial EEPROM and returns the Vendor ID and the serial */
+/* number. First, it resets the EEPROM control logic by */
+/* issuing a WAKE[CSN] command. The function will return an */
+/* ASCII string for the vendor ID into the char array pointed */
+/* to by "vendor" in the VVVNNNN format. The serial number */
+/* is placed in the 32-bit variable pointed to by "serial". */
+/* Note that the 9th byte is read but not used as it is invalid */
+/* when the serial identifier is read via PRESDI. */
+/* */
+/* This function assumes that the PNP state machine is not in */
+/* the "wait for key state". Otherwise, unpredictable results */
+/* will be obtained. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpSerial(PORT pnprdp,
+ BYTE csn,
+ BYTE * vendor,
+ DWORD * serial)
+{
+ BYTE presdi, digit, i;
+
+ *serial = 0L;
+
+ /* ####################################### */
+ /* Reset Serial EEPROM logic */
+ /* ####################################### */
+ IwavePnpWake(csn); /* Wake card up */
+
+ for (i = 1; i <= 4; i++) {
+ IwavePnpPeek(pnprdp, 1, &presdi);
+
+ switch (i) {
+ case 1:
+ *(vendor++) = ((presdi & 0x7C) >> 2) | 0x40; /* 1st char */
+ *vendor = (presdi & 0x03) << 3; /* isolate bits[4:3] of
+ * 2nd char */
+ break;
+ case 2:
+ *vendor = ((presdi & 0xE0) >> 5) | (*vendor);
+ *(vendor++) = (*vendor) | 0x40; /* 2nd char */
+ *vendor = (presdi & 0x1F) | 0x40; /* 3rd char */
+ break;
+ case 3:
+ case 4:
+ digit = (presdi & 0xF0) >> 4;
+ if (digit <= 0x09)
+ *(++vendor) = digit + 0x30; /* ASCII of digit */
+ else
+ *(++vendor) = (digit & 0x07) + 0x3F;
+ digit = presdi & 0x0F;
+ if (digit <= 0x09)
+ *(++vendor) = digit + 0x30;
+ else
+ *(++vendor) = (digit & 0x07) + 0x3F;
+ break;
+ }
+ }
+ *(++vendor) = '\0';
+ IwavePnpPeek(pnprdp, 4, (BYTE *) serial);
+ IwavePnpPeek(pnprdp, 1, NULL); /* discard checksum */
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpPeek */
+/* */
+/* PROFILE: This function will return the number of specified bytes of */
+/* resource data from the serial EEPROM. The function will NOT */
+/* reset the serial EEPROM logic to allow reading the entire */
+/* EEPROM by issuing repeated calls. The caller must supply a */
+/* pointer to where the data are to be stored. */
+/* It is assumed that the InterWave is not in either "sleep" */
+/* or "wait for key" states. Note that on the first call, if */
+/* the caller means to read from the beggining of data the */
+/* serial EEPROM logic must be reset. For this, the caller */
+/* should issue a WAKE[CSN] command */
+/* */
+/* ######################################################################## */
+void
+IwavePnpPeek(PORT pnprdp, WORD bytes, BYTE * data)
+{
+ WORD i;
+ BYTE datum;
+
+ for (i = 1; i <= bytes; i++) {
+ outb(_PIDXR, 0x05); /* select PRESSI */
+
+ while (TRUE) { /* wait til new data byte is ready */
+ if (inb(pnprdp) & PNP_DATA_RDY)
+ break; /* new resource byte ready */
+ }
+ outb(_PIDXR, 0x04); /* select PRESDI */
+ datum = inb(pnprdp); /* read resource byte */
+ if (data != NULL)
+ *(data++) = datum; /* store it */
}
- else
- {
- model_num = "MAX";
- gus_type = 0x40;
- mixer_type = CS4231;
-#ifndef EXCLUDE_GUSMAX
- {
- unsigned char max_config = 0x40; /* Codec enable */
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpEeprom */
+/* */
+/* PROFILE: This function allows the caller to control the serial */
+/* EEPROM directly while the audio device is inactive. To */
+/* de-activate the audio device issue the call */
+/* IwavePnpActivate(AUDIO,OFF). */
+/* */
+/* ######################################################################## */
+void
+IwavePnpEeprom(BYTE ctrl)
+{
+ ENTER_CRITICAL;
+ outb(_PIDXR, 0xF1); /* select PSECI */
+ outb(_PNPWRP, ctrl); /* write PSECI */
+ LEAVE_CRITICAL;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpActivate */
+/* */
+/* PROFILE: This function will activate or de-activate the audio device */
+/* or the external device on the InterWave. Set the "dev" arg */
+/* to AUDIO for the audio device or EXT for the external device. */
+/* Set "bool" to ON or OFF to turn the device on or off the ISA */
+/* bus. Notice that for a logical device to work, it must be */
+/* activated. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpActivate(BYTE dev, BYTE bool)
+{
+ IwavePnpDevice(dev); /* select audio device */
+ ENTER_CRITICAL;
+ outb(_PIDXR, ACTIVATE_DEV); /* select Activate Register */
+ outb(_PNPWRP, bool); /* write register */
+ LEAVE_CRITICAL;
- if (dma > 3)
- max_config |= 0x30; /* 16 bit playback and capture DMAs */
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpDevice */
+/* */
+/* PROFILE: This function allows the caller to select between five */
+/* logical devices available on the InterWave.It is assumed */
+/* that the PNP state machine is in configuration mode. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpDevice(BYTE dev)
+{
+ ENTER_CRITICAL;
+ outb(_PIDXR, _PLDNI); /* select PLDNI */
+ outb(_PNPWRP, dev); /* write PLDNI */
+ LEAVE_CRITICAL;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpPower */
+/* */
+/* PROFILE: This function allows the caller to disable major sections of */
+/* the InterWave to prevent them from consuming power and */
+/* loading the ISA bus. */
+/* */
+/* It is assumed that the PNP state machine is in configuration */
+/* mode. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpPower(BYTE mode)
+{
+ ENTER_CRITICAL;
+ outb(_PIDXR, _PPWRI); /* select PPWRI */
+ outb(_PNPWRP, mode); /* write PPWRI */
+ LEAVE_CRITICAL;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpWake */
+/* */
+/* PROFILE: This function issues a WAKE[CSN] command to the InterWave. If */
+/* the CSN matches the PNP state machine will enter the */
+/* configuration state. Otherwise it will enter the sleep mode. */
+/* */
+/* It is assumed that the PNP state machine is not in the */
+/* "wait for key" state. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpWake(BYTE csn)
+{
+ ENTER_CRITICAL;
+ outb(_PIDXR, _PWAKEI); /* select PWAKEI */
+ outb(_PNPWRP, csn); /* write csn */
+ LEAVE_CRITICAL;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpIOcheck */
+/* */
+/* PROFILE: This function allows the caller to perform a conflict check */
+/* on an I/O port to be used by a logical device. The function */
+/* receives the base address of the I/O range as well as the */
+/* number of ports in the range and then performs the I/O check */
+/* protocol. It returns the address of the port if a conflict */
+/* is detected or IO_CHK if no conflict is detected. */
+/* */
+/* This function assumes that the logical device has been de- */
+/* activated and that the PNP state machine is in config mode. */
+/* */
+/* ######################################################################## */
+PORT
+IwavePnpIOcheck(PORT base, BYTE no_ports)
+{
+ BYTE i;
+ PORT portid;
- max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
+ outb(_PIDXR, RANGE_IOCHK); /* select IO range check reg */
- OUTB (max_config, gus_base + 0x106); /* UltraMax control */
- }
+ for (i = 0; i < no_ports; i++) {
+ portid = base + i; /* port to check */
+ outb(_PNPWRP, 0x02); /* must drive 0xAA onto bus */
+ if (inb(portid) != 0xAA)
+ return (portid); /* IO conflict detected */
- if (ad1848_detect (gus_base + 0x10c))
- {
- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
- gus_wave_volume = 90;
- have_gus_max = 1;
- ad1848_init ("GUS MAX", gus_base + 0x10c,
- -irq,
- dma,
- dma);
- }
- else
- printk ("[Where's the CS4231?]");
-#endif
+ outb(_PNPWRP, 0x03); /* must drive 0x55 onto bus */
+ if (inb(portid) != 0x55)
+ return (portid); /* IO conflict detected */
}
- }
- 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.
+ return (IO_OK);
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpGetCSN */
+/* */
+/* PROFILE: This function allows the caller to detect an InterWave based */
+/* adapter board and will return its asigned CSN so that an */
+/* an application can access its PnP interface and determine the */
+/* borad's current configuration. In conducting its search for */
+/* the InterWave IC, the function will use the first 32 bits of */
+/* the Serial Identifier called the vendor ID in the PnP ISA */
+/* spec. The last 4 bits in the Vendor ID represent a revision */
+/* number for the particular product and this function gives the */
+/* caller the option of taking this revision number into account */
+/* or not in the search. If the function fails to find the */
+/* InterWave IC it will return FALSE. */
+/* */
+/* ######################################################################## */
+BYTE
+IwavePnpGetCSN(DWORD VendorID, BYTE csn_max)
+{
+ BYTE csn;
+ DWORD vendor;
+
+ IwavePnpKey(); /* Key to access PnP Interface */
+ VendorID &= (0xFFFFFFF0); /* reset 4 least significant bits */
+
+ for (csn = 1; csn <= csn_max; csn++) {
+ IwavePnpWake(csn); /* Select card */
+ IwavePnpPeek(iw.pnprdp, 4, (BYTE *) & vendor); /* get vendor ID */
+ vendor &= (0xFFFFFFF0);
+ if (vendor == VendorID) { /* If IDs match, InterWave is
+ * found */
+ outb(_PIDXR, 0x02); /* Place all cards in
+ * wait-for-key state */
+ outb(0x0A79, 0x02);
+ return (csn);
+ }
+ }
+ outb(_PIDXR, 0x02); /* Place all cards in wait-for-key state */
+ outb(0x0A79, 0x02);
+ return (FALSE); /* InterWave IC not found */
+}
+/* ######################################################################## */
+/* */
+/*
+ * FUNCTION: IwavePnpPing
+ */
+/* */
+/* PROFILE: This function allows the caller to detect an InterWave based */
+/* adapter board and will return its asigned CSN so that an */
+/* an application can access its PnP interface and determine the */
+/* borad's current configuration. In conducting its search for */
+/* the InterWave IC, the function will use the first 32 bits of */
+/* the Serial Identifier called the vendor ID in the PnP ISA */
+/* spec. The last 4 bits in the Vendor ID represent a revision */
+/* number for the particular product and will not be included */
+/* in the search. The function will return the Vendor ID and the */
+/* calling application should check the revision bits to make */
+/* sure they are compatible with the board. */
+/* */
+/* ######################################################################## */
+BYTE
+IwavePnpPing(DWORD VendorID)
+{
+ BYTE csn;
+
+ VendorID &= (0xFFFFFFF0); /* reset 4 least significant bits */
+ IwavePnpKey(); /* Key to access PnP Interface */
+ while (iw.pnprdp <= 0x23F) {
+ for (csn = 1; csn <= 10; csn++) {
+ IwavePnpWake(csn); /* Select card */
+ IwavePnpPeek(iw.pnprdp, 4, (BYTE *) & iw.vendor); /* get vendor ID */
+
+
+ if (((iw.vendor) & 0xFFFFFFF0) == VendorID) { /* If IDs match,
+ * InterWave is found */
+
+ outb(_PIDXR, 0x02); /* Place all cards in
+ * wait-for-key state */
+ outb(0x0A79, 0x02);
+ return (csn);
+ }
+ }
+ iw.pnprdp += 0x04;
+ }
+ outb(_PIDXR, 0x02); /* Place all cards in wait-for-key state */
+ outb(0x0A79, 0x02);
+ return (FALSE); /* InterWave IC not found */
+}
+
+/* end of pnp code */
+
+WORD
+IwaveMemSize(void)
+{
+ BYTE datum = 0x55;
+ ADDRESS local = 0L;
+
+ outb(iw.igidxr, _LMCI);
+ outb(iw.i8dp, inb(iw.i8dp) & 0xFD); /* DRAM I/O cycles selected */
+
+ while (TRUE) {
+ IwaveMemPoke(local, datum);
+ IwaveMemPoke(local + 1L, datum + 1);
+ if (IwaveMemPeek(local) != datum || IwaveMemPeek(local + 1L) != (datum + 1) || IwaveMemPeek(0L) != 0x55)
+ break;
+ local += RAM_STEP;
+ datum++;
+ }
+ return ((WORD) (local >> 10));
+}
+
+BYTE
+IwaveMemPeek(ADDRESS addr)
+{
+ PORT p3xr;
+
+ p3xr = iw.p3xr;
+
+
+ outb(iw.igidxr, 0x43); /* Select LMALI */
+ outw(iw.i16dp, (WORD) addr); /* Lower 16 bits of LM */
+ outb(iw.igidxr, 0x44); /* Select LMAHI */
+ outb(iw.i8dp, (BYTE) (addr >> 16)); /* Upper 8 bits of LM */
+ return (inb(iw.lmbdr)); /* return byte from LMBDR */
+}
+
+
+void
+IwaveMemPoke(ADDRESS addr, BYTE datum)
+{
+ PORT p3xr;
+ p3xr = iw.p3xr;
+
+
+ outb(iw.igidxr, 0x43); /* Select LMALI */
+ outw(iw.i16dp, (WORD) addr); /* Lower 16 bits of LM */
+ outb(iw.igidxr, 0x44); /* Select LMAHI */
+ outb(iw.i8dp, (BYTE) (addr >> 16)); /* Upper 8 bits of LM */
+ outb(iw.lmbdr, datum); /* Write byte to LMBDR */
+}
+
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwaveMemCfg */
+/* */
+/* PROFILE : This function determines the amount of DRAM from its */
+/* configuration accross all banks. It sets the configuration */
+/* into register LMCFI and stores the total amount of DRAM */
+/* into iw.size_mem (Kbytes). */
+/* */
+/* The function first places the IC in enhanced mode to allow */
+/* full access to all DRAM locations. Then it selects full */
+/* addressing span (LMCFI[3:0]=0x0C). Finally, it determines */
+/* the amount of DRAM in each bank and from this the actual */
+/* configuration. */
+/* */
+/* Note that if a configuration other than one indicated in */
+/* the manual is implemented, this function will select */
+/* full addressing span (LMCFI[3:0]=0xC). */
+/* */
+/* ######################################################################## */
+void
+IwaveMemCfg(DWORD * lpbanks)
+{
+ DWORD bank[4] = {0L, 0L, 0L, 0L};
+ DWORD addr = 0L, base = 0L, cnt = 0L;
+ BYTE i, reg, ram = FALSE;
+ WORD lmcfi;
+ /* */
+ ENTER_CRITICAL;
+ outb(iw.igidxr, 0x99);
+ reg = inb(iw.i8dp); /* image of sgmi */
+ outb(iw.igidxr, 0x19);
+ outb(iw.i8dp, (BYTE) (reg | 0x01)); /* enable enhaced mode */
+ outb(iw.igidxr, _LMCFI);/* select LM Conf Reg */
+ lmcfi = inw(iw.i16dp) & 0xFFF0;
+ outw(iw.i16dp, lmcfi | 0x000C); /* max addr span */
+ /* */
+ /* Clear every RAM_STEPth location */
+ /* */
+ while (addr < RAM_MAX) {
+ IwaveMemPoke(addr, 0x00);
+ addr += RAM_STEP;
+ }
+ /* */
+ /* Determine amount of RAM in each bank */
+ /* */
+ for (i = 0; i < 4; i++) {
+ IwaveMemPoke(base, 0xAA); /* mark start of bank */
+ IwaveMemPoke(base + 1L, 0x55);
+ if ((IwaveMemPeek(base) == 0xAA) && (IwaveMemPeek(base + 1L) == 0x55))
+ ram = TRUE;
+ if (ram) {
+ while (cnt < BANK_MAX) {
+ bank[i] += RAM_STEP;
+ cnt += RAM_STEP;
+ addr = base + cnt;
+ if (IwaveMemPeek(addr) == 0xAA)
+ break;
+ }
+ }
+ if (lpbanks != NULL) {
+ *lpbanks = bank[i];
+ lpbanks++;
+ }
+ bank[i] = bank[i] >> 10;
+ base += BANK_MAX;
+ cnt = 0L;
+ ram = FALSE;
+ }
+ /* */
+ iw.flags &= ~DRAM_HOLES;
+ outb(iw.igidxr, _LMCFI);
+ if (bank[0] == 256 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi);
+ else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x01);
+ else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 256 && bank[3] == 256)
+ outw(iw.i16dp, lmcfi | 0x02);
+ else if (bank[0] == 256 && bank[1] == 1024 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x03);
+ else if (bank[0] == 256 && bank[1] == 1024 && bank[2] == 1024 && bank[3] == 1024)
+ outw(iw.i16dp, lmcfi | 0x04);
+ else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 1024 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x05);
+ else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 1024 && bank[3] == 1024)
+ outw(iw.i16dp, lmcfi | 0x06);
+ else if (bank[0] == 1024 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x07);
+ else if (bank[0] == 1024 && bank[1] == 1024 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x08);
+ else if (bank[0] == 1024 && bank[1] == 1024 && bank[2] == 1024 && bank[3] == 1024)
+ outw(iw.i16dp, lmcfi | 0x09);
+ else if (bank[0] == 4096 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x0A);
+ else if (bank[0] == 4096 && bank[1] == 4096 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x0B);
+ else /* Flag the non-contiguous config of memory */
+ iw.flags |= DRAM_HOLES;
+ /* */
+ outb(iw.igidxr, 0x19); /* restore sgmi */
+ outb(iw.i8dp, reg);
+ LEAVE_CRITICAL;
+}
+
+
+/* ######################################################################## */
+/**/
+/* FUNCTION: IwaveCodecIrq */
+/**/
+/* PROFILE: This function disables or enables the Codec Interrupts. To */
+/* enable interrupts set CEXTI[2] high thus causing all interrupt */
+/* sources (CSR3I[6:4]) to pass onto the IRQ pin. To disable */
+/* interrupts set CEXTI[1]=0. To enable Code IRQs issue this call: */
+/**/
+/* IwaveCodecIrq(CODEC_IRQ_ENABLE). To disable IRQs issue the call */
+/**/
+/* IwaveCodeIrq(~CODEC_IRQ_ENABLE). */
+/**/
+/* ######################################################################## */
+void
+IwaveCodecIrq(BYTE mode)
+{
+ BYTE reg;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | _CSR3I); /* select CSR3I */
+ outb(iw.cdatap, 0x00); /* clear all interrupts */
+ outb(iw.pcodar + 0x02, 0x00); /* clear CSR1R */
+ outb(iw.pcodar, reg | _CEXTI); /* select CEXTI */
+ reg = inb(iw.cdatap);
+ if (mode == CODEC_IRQ_ENABLE) /* enable Codec Irqs */
+ outb(iw.cdatap, (BYTE) (reg | CODEC_IRQ_ENABLE));
+ else /* disable Codec Irqs */
+ outb(iw.cdatap, (BYTE) (reg & ~CODEC_IRQ_ENABLE));
+ LEAVE_CRITICAL;
+}
+
+
+/* ######################################################################### */
+/**/
+/* FUNCTION: IwaveRegPeek */
+/**/
+/* PROFILE : This function returns the value stored in any readable */
+/* InterWave register. It takes as input a pointer to a */
+/* structure containing the addresses of the relocatable I/O */
+/* space as well as a register mnemonic. To correctly use this */
+/* function, the programmer must use the mnemonics defined in */
+/* "iwdefs.h". These mnemonics contain coded information used */
+/* by the function to properly access the desired register. */
+/**/
+/* An attempt to read from a write-only register will return */
+/* meaningless data. */
+/**/
+/* ######################################################################### */
+WORD
+IwaveRegPeek(DWORD reg_mnem)
+{
+ BYTE index, val;
+ WORD reg_id, offset;
+
+ offset = (WORD) ((BYTE) reg_mnem);
+ reg_id = (WORD) (reg_mnem >> 16);
+ index = (BYTE) (reg_mnem >> 8);
+
+ /* ################################################### */
+ /* Logic to read registers in P2XR block & GMCR */
+ /* ################################################### */
+
+ if (reg_id >= 0x0001 && reg_id <= 0x001A) { /* UMCR to GMCR */
+ if (reg_id <= 0x000E) /* UMCR to USRR */
+ return ((WORD) inb(iw.p2xr + offset));
+
+ if (reg_id == 0x0019)
+ return ((WORD) inb(iw.p201ar));
+
+ else { /* GUS Hidden registers or GMCR */
+ BYTE iveri;
+
+ outb(iw.igidxr, 0x5B); /* select IVERI */
+ iveri = inb(iw.i8dp); /* read IVERI */
+ outb(iw.i8dp, (BYTE) (iveri | 0x09)); /* set IVERI[3,0] */
+ if (reg_id == 0x001A) { /* GMCR */
+ val = inb(iw.p3xr);
+ outb(iw.i8dp, iveri); /* restore IVERI */
+ return ((WORD) val);
+ }
+ val = inb(iw.p2xr + 0x0F); /* read URCR */
+ val = (val & 0xF8) | index; /* value for URCR[2:0] */
+ outb(iw.p2xr + 0x0F, val); /* set URCR[2:0] */
+
+ if (reg_mnem == UDCI || reg_mnem == UICI) {
+ val = inb(iw.p2xr);
+ if (reg_mnem == UDCI)
+ outb(iw.p2xr, (BYTE) (val & 0xBF));
+ else
+ outb(iw.p2xr, (BYTE) (val | 0x40));
+ }
+ val = inb(iw.p2xr + 0x0B);
+ outb(iw.igidxr, 0x5B); /* select IVERI */
+ outb(iw.i8dp, iveri); /* restore IVERI */
+ return ((WORD) val); /* read register */
+ }
+ }
+ /* ################################################### */
+ /* Logic to read registers in P3XR block */
+ /* ################################################### */
+
+ if (reg_id >= 0x001B && reg_id <= 0x005C) { /* GMSR to LMBDR */
+ if (reg_id == 0x005C) /* LMBDR */
+ return ((WORD) inb(iw.lmbdr));
+
+ if (reg_id >= 0x001B && reg_id <= 0x0021) /* GMSR to I8DP */
+ if (offset == 0x04)
+ return (inw(iw.i16dp));
+ else
+ return ((WORD) inb(iw.p3xr + offset));
+ else { /* indexed registers */
+
+ if (reg_id <= 0x003F)
+ index |= 0x80; /* adjust for reading */
+
+ outb(iw.igidxr, index); /* select register */
+
+ if (offset == 0x04)
+ return (inw(iw.i16dp));
+ else
+ return ((WORD) inb(iw.i8dp));
+ }
+ }
+ /* #################################################### */
+ /* Logic to read registers in PCODAR block */
+ /* #################################################### */
+
+ if (reg_id >= 0x005D && reg_id <= 0x0081) { /* CIDXR to CLRCTI */
+ if (reg_id <= 0x0061)
+ return ((WORD) inb(iw.pcodar + offset)); /* CRDR */
+
+ else { /* indexed registers */
+ BYTE cidxr;
+
+ cidxr = inb(iw.pcodar);
+ cidxr = (cidxr & 0xE0) + index;
+ outb(iw.pcodar, cidxr); /* select register */
+ return ((WORD) inb(iw.cdatap));
+ }
+ }
+ /* ##################################################### */
+ /* Logic to read the PnP registers */
+ /* ##################################################### */
+ if (reg_id >= 0x0082 && reg_id <= 0x00B7) { /* PCSNBR to PMITI */
+ if (reg_id == 0x0085)
+ return ((WORD) inb(iw.pnprdp));
+
+ if (reg_id < 0x0085)
+ return ((WORD) inb((WORD) reg_mnem));
+
+ else { /* indexed registers */
+ if (reg_id >= 0x008E && reg_id <= 0x00B7) {
+ outb(0x0279, 0x07); /* select PLDNI */
+ outb(0xA79, (BYTE) offset); /* select logical dev */
+ }
+ outb(0x0279, index); /* select the register */
+ return ((WORD) inb(iw.pnprdp));
+ }
+ }
+ return 0;
+}
+/* ######################################################################### */
+/**/
+/* FUNCTION: IwaveRegPoke */
+/**/
+/* PROFILE : This function writes a value to any writable */
+/* InterWave register. It takes as input a pointer to a */
+/* structure containing the addresses of the relocatable I/O */
+/* space as well as a register mnemonic. To correctly use this */
+/* function, the programmer must use the mnemonics defined in */
+/* "iwdefs.h". These mnemonics contain coded information used */
+/* by the function to properly access the desired register. */
+/**/
+/* This function does not guard against writing to read-only */
+/* registers. It is the programmer's responsibility to ensure */
+/* that the writes are to valid registers. */
+/**/
+/* ######################################################################### */
+void
+IwaveRegPoke(DWORD reg_mnem, WORD datum)
+{
+ BYTE index;
+ BYTE val;
+ WORD reg_id;
+ WORD offset;
+
+ offset = (WORD) ((BYTE) reg_mnem);
+ reg_id = (WORD) (reg_mnem >> 16);
+ index = (BYTE) (reg_mnem >> 8);
+
+
+ /* ####################################################### */
+ /* Logic to write to registers in P2XR block */
+ /* ####################################################### */
+ if (reg_id >= 0x0001 && reg_id <= 0x0019) { /* UMCR to GGCR */
+ if (reg_id <= 0x000E) { /* UMCR to USRR */
+ outb(iw.p2xr + offset, (BYTE) datum);
+ return;
+ }
+ if (reg_id == 0x0019) {
+ outb(iw.p201ar, (BYTE) datum);
+ return;
+ } else { /* GUS Hidden registers */
+
+ BYTE iveri;
+
+ outb(iw.igidxr, 0x5B); /* select IVERI */
+ iveri = inb(iw.i8dp); /* read IVERI */
+ outb(iw.i8dp, (BYTE) (iveri | 0x09)); /* set IVERI[3,0] */
+ val = inb(iw.p2xr + 0x0F); /* read URCR */
+ val = (val & 0xF8) | index; /* value for URCR[2:0] */
+ outb(iw.p2xr + 0x0F, val); /* set URCR[2:0] */
+
+ if (reg_mnem == UDCI || reg_mnem == UICI) {
+ val = inb(iw.p2xr); /* read UMCR */
+ if (reg_mnem == UDCI)
+ outb(iw.p2xr, (BYTE) (val & 0xBF)); /* set UMCR[6]=0 */
+ else
+ outb(iw.p2xr, (BYTE) (val | 0x40)); /* set UMCR[6]=1 */
+ }
+ outb(iw.p2xr + 0x0B, (BYTE) datum); /* write register */
+ outb(iw.igidxr, 0x5B); /* select IVERI */
+ outb(iw.i8dp, iveri); /* restore IVERI */
+ return;
+ }
+ }
+ /* ############################################################# */
+ /* Logic to write to registers in P3XR block */
+ /* ############################################################# */
+
+ if (reg_id >= 0x001A && reg_id <= 0x005C) { /* GMCR to LMBDR */
+
+ if (reg_id == 0x005C) { /* LMBDR */
+ outb(iw.lmbdr, (BYTE) datum);
+ return;
+ }
+ if (reg_id == 0x001B) /* GMSR */
+ return;
+
+ if (reg_id >= 0x001A && reg_id <= 0x0021) /* GMCR to I8DP */
+ if (offset == 0x04)
+ outw(iw.i16dp, datum);
+ else
+ outb(iw.p3xr + offset, (BYTE) datum);
+ else { /* indexed registers */
+ outb(iw.igidxr, index); /* select register */
+
+ if (offset == 0x04)
+ outw(iw.i16dp, datum);
+ else
+ outb(iw.i8dp, (BYTE) datum);
+ }
+ }
+ /* /################################################### */
+ /* Logic to write to registers in PCODAR block */
+ /* ################################################### */
+
+ if (reg_id >= 0x005C && reg_id <= 0x0081) { /* CIDXR to CLRCTI */
+ if (reg_id <= 0x0061)
+ outb(iw.pcodar + offset, (BYTE) datum);
+
+ else { /* one of the indexed registers */
+ BYTE cidxr;
+
+ cidxr = inb(iw.pcodar);
+ cidxr = (cidxr & 0xE0) + index;
+ outb(iw.pcodar, cidxr); /* select register */
+ outb(iw.cdatap, (BYTE) datum);
+ }
+ }
+ /* ###################################################### */
+ /* Logic to write to the PnP registers */
+ /* ###################################################### */
+ if (reg_id >= 0x0082 && reg_id <= 0x00B7) {
+ if (reg_id == 0x0085) {
+ outb(iw.pnprdp, (BYTE) datum);
+ return;
+ }
+ if (reg_id < 0x0085)
+ outb((WORD) reg_mnem, (BYTE) datum);
+
+ else { /* one of the indexed registers */
+ if (reg_id >= 0x008E && reg_id <= 0x00B7) {
+ outb(0x0279, 0x07); /* select PLDNI */
+ outb(0xA79, (BYTE) offset); /* select logical dev */
+ }
+ outb(0x0279, index); /* select the register */
+ outb(0xA79, (BYTE) datum);
+ }
+ }
+}
+
+
+void
+IwaveLineLevel(char level, char index)
+{
+ char reg;
+
+ level &= 0x1F;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | index); /* select register */
+ outb(iw.cdatap, (BYTE) ((inb(iw.cdatap) & 0x80) | level)); /* set level */
+ LEAVE_CRITICAL;
+}
+
+void
+IwaveCodecMode(char mode)
+{
+ char reg;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | _CMODEI); /* select CMODEI */
+ outb(iw.cdatap, mode);
+ LEAVE_CRITICAL;
+ iw.cmode = mode;
+}
+
+void
+IwaveLineMute(BYTE mute, BYTE inx)
+{
+ BYTE reg;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | inx); /* select register */
+ if (mute == ON)
+ outb(iw.cdatap, (BYTE) (inb(iw.cdatap) | 0x80)); /* mute */
+ else
+ outb(iw.cdatap, (BYTE) (inb(iw.cdatap) & 0x7F)); /* unmute */
+ LEAVE_CRITICAL;
+}
+
+void
+Iwaveinitcodec()
+{
+
+ u_short iwl_codec_base = iw.pcodar;
+ u_short iwl_codec_data = iw.pcodar + 1;
+ u_short foo;
+
+
+
+ /*
+ * Set the CEXTI register foo = CODEC_CEXTI_DEFAULT;
+ * IWL_CODEC_OUT(EXTERNAL_CONTROL, foo);
+ */
+ /*
+ * Disable Interrupts iwl_codec_disable_irqs();
*/
- }
+ /* Set the CODEC to Operate in Mode 3 */
+ IWL_CODEC_OUT(MODE_SELECT_ID, 0x6C);
+ foo = inb(iwl_codec_data);
- printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+ /* Set the configuration registers to their default values */
+ foo = CODEC_CFIG1I_DEFAULT;
+ IWL_CODEC_OUT(CONFIG_1 | CODEC_MCE, foo);
+ outb(iwl_codec_base, CONFIG_1);
+ foo = CODEC_CFIG2I_DEFAULT;
+ IWL_CODEC_OUT(CONFIG_2, foo);
-#ifndef SCO
- sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
-#endif
+ foo = CODEC_CFIG3I_DEFAULT;
+ IWL_CODEC_OUT(CONFIG_3, foo);
- if (irq < 0 || irq > 15)
- {
- printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
- return mem_start;
- }
+}
- if (dma < 0 || dma > 7)
- {
- printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
- return mem_start;
- }
- gus_irq = irq;
- gus_dma = dma;
- if (num_synths >= MAX_SYNTH_DEV)
- printk ("GUS Error: Too many synthesizers\n");
- else
- {
- voice_alloc = &guswave_operations.alloc;
- synth_devs[num_synths++] = &guswave_operations;
- }
+int
+IwaveOpen(char voices, char mode, struct address_info * hw)
+{
- PERMANENT_MALLOC (struct patch_info *, samples,
- (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
+ u_long flags;
+ u_char tmp;
- reset_sample_memory ();
+ flags = splhigh();
- gus_initialize ();
+ iw.pnprdp = 0;
+ if (IwavePnpIsol(&iw.pnprdp)) {
- if (num_audiodevs < MAX_AUDIO_DEV)
- {
- audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations;
- audio_devs[gus_devnum]->dmachan = dma;
- audio_devs[gus_devnum]->buffcount = 1;
- audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
- }
- else
- printk ("GUS: Too many PCM devices available\n");
+ iw.vendor = GUS_PNP_ID;
- /*
- * Mixer dependent initialization.
- */
+ iw.csn = IwavePnpPing(iw.vendor);
- switch (mixer_type)
- {
- case ICS2101:
- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
- gus_wave_volume = 90;
- return ics2101_mixer_init (mem_start);
+ IwavePnpKey();
- case CS4231:
- /* Initialized elsewhere (ad1848.c) */
- default:
- return gus_default_mixer_init (mem_start);
- }
+ IwavePnpWake(iw.csn);
+
+ IwavePnpGetCfg();
+ IwavePnpKey();
+
+ IwavePnpWake(iw.csn);
+ }
+ if (hw->irq > 0) {
+ /* I see the user wants to set the GUS PnP */
+ /* Okay lets do it */
+ iw.csn = 1;
+ iw.p2xr = hw->io_base;
+ iw.p3xr = hw->io_base + 0x100;
+ iw.pcodar = hw->io_base + 0x10c;
+
+ iw.synth_irq = hw->irq;
+
+ iw.midi_irq = hw->irq;
+
+ iw.dma1_chan = hw->dma;
+
+ if (hw->dma2 == -1) {
+ iw.dma2_chan = hw->dma;
+ } else {
+ iw.dma2_chan = hw->dma2;
+ }
+
+
+ } else {
+
+ /* tell the os what we are doing 8) */
+ hw->io_base = iw.p2xr;
+ hw->irq = iw.synth_irq;
+ /*
+ * iw.dma1_chan = 1; iw.dma2_chan = 3 ;
+ */
+ hw->dma = iw.dma1_chan;
+ hw->dma2 = iw.dma2_chan;
- return mem_start;
+
+ }
+
+ if (iw.csn > 0 && iw.csn < MAX_GUS_PNP) {
+ gus_pnp_found[iw.csn] = hw->io_base;
+
+ }
+ iw.cdatap = iw.pcodar + 1;
+ iw.csr1r = iw.pcodar + 2;
+ iw.cxdr = iw.pcodar + 3;/* CPDR or CRDR */
+ iw.gmxr = iw.p3xr;
+ iw.gmxdr = iw.p3xr + 1; /* GMTDR or GMRDR */
+ iw.svsr = iw.p3xr + 2;
+ iw.igidxr = iw.p3xr + 3;
+ iw.i16dp = iw.p3xr + 4;
+ iw.i8dp = iw.p3xr + 5;
+ iw.lmbdr = iw.p3xr + 7;
+ iw.voices = voices;
+
+ if (iw.pnprdp > 0 && iw.csn > 0) {
+ IwavePnpSetCfg();
+ IwavePnpActivate(AUDIO, ON);
+ IwavePnpActivate(EXT, ON);
+ }
+ /* IwavePnpActivate(EMULATION,ON); */
+
+
+ /* reset */
+ outb(iw.igidxr, _URSTI);/* Pull reset */
+ outb(iw.i8dp, 0x00);
+ DELAY(1000 * 30);
+
+ outb(iw.i8dp, 0x01); /* Release reset */
+ DELAY(1000 * 30);
+
+ /* end of reset */
+
+
+ IwaveMemCfg(NULL);
+
+
+ tmp = IwaveRegPeek(IDECI);
+
+ IwaveRegPoke(IDECI, tmp | 0x18);
+
+ IwaveCodecMode(CODEC_MODE2); /* Default codec mode */
+ IwaveRegPoke(ICMPTI, 0);
+
+ outb(iw.igidxr, 0x99);
+ tmp = inb(iw.i8dp);
+ outb(iw.igidxr, 0x19);
+ outb(iw.i8dp, tmp);
+
+
+
+ IwaveCodecIrq(~CODEC_IRQ_ENABLE);
+
+ Iwaveinitcodec();
+
+ outb(iw.p2xr, 0x0c); /* Disable line in, mic and line out */
+
+ IwaveRegPoke(CLCI, 0x3f << 2);
+
+ IwaveLineLevel(0, _CLOAI);
+ IwaveLineLevel(0, _CROAI);
+
+ IwaveLineMute(OFF, _CLOAI);
+ IwaveLineMute(OFF, _CROAI);
+
+ IwaveLineLevel(0, _CLLICI);
+ IwaveLineLevel(0, _CRLICI);
+ IwaveLineMute(OFF, _CLLICI);
+ IwaveLineMute(OFF, _CRLICI);
+
+ IwaveLineLevel(0, _CLDACI);
+ IwaveLineLevel(0, _CRDACI);
+ IwaveLineMute(ON, _CLDACI);
+ IwaveLineMute(ON, _CRDACI);
+
+ IwaveLineLevel(0, _CLLICI);
+ IwaveLineLevel(0, _CRLICI);
+ IwaveLineMute(ON, _CLLICI);
+ IwaveLineMute(ON, _CRLICI);
+
+
+ IwaveInputSource(LEFT_SOURCE, MIC_IN);
+ IwaveInputSource(RIGHT_SOURCE, MIC_IN);
+
+ outb(iw.pcodar, 0x9 | 0x40);
+ outb(iw.cdatap, 0);
+ IwaveCodecIrq(CODEC_IRQ_ENABLE);
+ outb(iw.pcodar, _CFIG3I | 0x20);
+
+
+ outb(iw.cdatap, 0xC2); /* Enable Mode 3 IRQs & Synth */
+
+ outb(iw.igidxr, _URSTI);
+ outb(iw.i8dp, GF1_SET | GF1_OUT_ENABLE | GF1_IRQ_ENABLE);
+ DELAY(1000 * 30);
+ iw.size_mem = IwaveMemSize(); /* Bytes of RAM in this mode */
+ outb(iw.p2xr, 0xc); /* enable output */
+ IwaveRegPoke(CLCI, 0x3f << 2);
+
+ IwaveCodecIrq(CODEC_IRQ_ENABLE);
+ splx(flags);
+
+ DELAY(1000 * 100);
+ IwaveRegPoke(CPDFI, 0);
+
+ return (TRUE);
}
-static void
-do_loop_irq (int voice)
+
+void
+gus_wave_init(struct address_info * hw_config)
{
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
+ u_long flags;
+ u_char val, gus_pnp_seen = 0;
+ char *model_num = "2.4";
+ int gus_type = 0x24; /* 2.4 */
+ int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
+ int otherside = -1, i;
+
+ if (irq < 0 || irq > 15) {
+ printf("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
+ return;
+ }
+ if (dma < 0 || dma > 7) {
+ printf("ERROR! Invalid DMA#%d. GUS Disabled", dma);
+ return;
+ }
+ for (i = 0; i < MAX_GUS_PNP; i++) {
+ if (gus_pnp_found[i] != 0 && gus_pnp_found[i] == hw_config->io_base)
+ gus_pnp_seen = 1;
+ }
+#ifdef NOGUSPNP
+ gus_pnp_seen = 0;
+#endif
- DISABLE_INTR (flags);
- gus_select_voice (voice);
+ gus_irq = irq;
+ gus_dma = dma;
+ gus_dma2 = dma2;
- tmp = gus_read8 (0x00);
- tmp &= ~0x20; /*
- * Disable wave IRQ for this_one voice
- */
- gus_write8 (0x00, tmp);
+ if (gus_dma2 == -1)
+ gus_dma2 = dma;
- mode = voices[voice].loop_irq_mode;
- voices[voice].loop_irq_mode = 0;
- parm = voices[voice].loop_irq_parm;
+ /*
+ * Try to identify the GUS model.
+ *
+ * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+ */
- switch (mode)
- {
+ flags = splhigh();
+ outb(gus_base + 0x0f, 0x20);
+ val = inb(gus_base + 0x0f);
+ splx(flags);
- case LMODE_FINISH: /*
- * Final loop finished, shoot volume down
- */
-
- if ((int) (gus_read16 (0x09) >> 4) < 100) /*
- * Get current volume
- */
- {
- gus_voice_off ();
- gus_rampoff ();
- gus_voice_init (voice);
- break;
- }
- gus_ramp_range (65, 4065);
- 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; /* Signal to the play_next_pcm_block routine */
- case LMODE_PCM:
- {
- int orig_qlen = pcm_qlen;
- int flag; /* 0 or 2 */
-
- pcm_qlen--;
- pcm_head = (pcm_head + 1) % pcm_nblk;
- if (pcm_qlen)
- {
- play_next_pcm_block ();
- }
- else
- { /* Underrun. Just stop the voice */
- gus_voice_off ();
- gus_rampoff ();
- pcm_active = 0;
- }
+ 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);
/*
- * If the queue was full before this interrupt, the DMA transfer was
- * suspended. Let it continue now.
- */
- if (dma_active)
- {
- if (pcm_qlen == 0)
- flag = 1; /* Underflow */
+ * 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.
+ *
+ */
+
+ if (gus_pnp_seen)
+ val = 66;
+
+ 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 {
+ if (gus_pnp_seen)
+ model_num = "PNP";
else
- flag = 0;
- dma_active = 0;
- }
- else
- flag = 2; /* Just notify the dmabuf.c */
- DMAbuf_outputintr (gus_devnum, flag);
- }
- break;
+ model_num = "MAX";
+
+ gus_type = 0x40;
+ mixer_type = CS4231;
+#ifdef CONFIG_GUSMAX
+ {
+ u_char max_config = 0x40; /* Codec enable */
+
+ if (gus_dma2 == -1)
+ gus_dma2 = gus_dma;
+
+ if (gus_dma > 3)
+ max_config |= 0x10; /* 16 bit capture DMA */
+
+ if (gus_dma2 > 3)
+ max_config |= 0x20; /* 16 bit playback DMA */
+
+ max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from
+ * 2X0 */
+
+ outb(gus_base + 0x106, max_config); /* UltraMax control */
+ }
+
+ if (ad1848_detect(gus_base + 0x10c, NULL, hw_config->osp)) {
+
+ gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+ gus_wave_volume = 90;
+ have_gus_max = 1;
+ if (gus_pnp_seen) {
+
+ ad1848_init("GUS PNP", gus_base + 0x10c,
+ -irq,
+ gus_dma2, /* Playback DMA */
+ gus_dma, /* Capture DMA */
+ 1, /* Share DMA channels with GF1 */
+ hw_config->osp);
+
+
+ } else {
+ ad1848_init("GUS MAX", gus_base + 0x10c,
+ -irq,
+ gus_dma2, /* Playback DMA */
+ gus_dma, /* Capture DMA */
+ 1, /* Share DMA channels with GF1 */
+ hw_config->osp);
+ }
+ otherside = num_audiodevs - 1;
+
+ } else
+ printf("[Where's the CS4231?]");
+#else
+ printf("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n");
+#endif
+ }
+ } else {
+ /*
+ * ASIC not detected so the card must be 2.2 or 2.4. There
+ * could still be the 16-bit/mixer daughter card.
+ */
+ }
- default:;
+ if (gus_pnp_seen) {
+ sprintf(gus_info.name, "Gravis %s (%dk)", model_num, (int) gus_mem_size / 1024);
+ } else {
+ sprintf(gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+ }
+ conf_printf(gus_info.name, hw_config);
+
+ if (num_synths >= MAX_SYNTH_DEV)
+ printf("GUS Error: Too many synthesizers\n");
+ else {
+ voice_alloc = &guswave_operations.alloc;
+ synth_devs[num_synths++] = &guswave_operations;
+#ifdef CONFIG_SEQUENCER
+ gus_tmr_install(gus_base + 8);
+#endif
+ }
+ samples = (struct patch_info *) malloc((MAX_SAMPLE + 1) * sizeof(*samples), M_DEVBUF, M_NOWAIT);
+ if (!samples)
+ panic("SOUND: Cannot allocate memory\n");
+
+ reset_sample_memory();
+
+ gus_initialize();
+
+ if (num_audiodevs < MAX_AUDIO_DEV) {
+ audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations;
+ audio_devs[gus_devnum]->otherside = otherside;
+ audio_devs[gus_devnum]->dmachan1 = dma;
+ audio_devs[gus_devnum]->dmachan2 = dma2;
+ audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
+ if (otherside != -1) {
+ /*
+ * glue logic to prevent people from opening the gus
+ * max via the gf1 and the cs4231 side . Only the gf1
+ * or the cs4231 are allowed to be open
+ */
+
+ audio_devs[otherside]->otherside = gus_devnum;
+ }
+ if (dma2 != dma && dma2 != -1)
+ audio_devs[gus_devnum]->flags |= DMA_DUPLEX;
+ } else
+ printf("GUS: Too many PCM devices available\n");
+
+ /*
+ * Mixer dependent initialization.
+ */
+
+ switch (mixer_type) {
+ case ICS2101:
+ gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+ gus_wave_volume = 90;
+ ics2101_mixer_init();
+ return;
+
+ case CS4231:
+ /* Initialized elsewhere (ad1848.c) */
+ default:
+ gus_default_mixer_init();
+ return;
}
- RESTORE_INTR (flags);
}
static void
-do_volume_irq (int voice)
+do_loop_irq(int voice)
{
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
+ u_char tmp;
+ int mode, parm;
+ u_long flags;
+
+ flags = splhigh();
+ gus_select_voice(voice);
+
+ tmp = gus_read8(0x00);
+ tmp &= ~0x20; /* Disable wave IRQ for this_one voice */
+ gus_write8(0x00, tmp);
+
+ if (tmp & 0x03) /* Voice stopped */
+ voice_alloc->map[voice] = 0;
+
+ mode = voices[voice].loop_irq_mode;
+ voices[voice].loop_irq_mode = 0;
+ parm = voices[voice].loop_irq_parm;
+
+ switch (mode) {
+
+ case LMODE_FINISH: /* Final loop finished, shoot volume down */
+
+ if ((int) (gus_read16(0x09) >> 4) < 100) { /* Get current volume */
+ gus_voice_off();
+ gus_rampoff();
+ gus_voice_init(voice);
+ break;
+ }
+ gus_ramp_range(65, 4065);
+ 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; /* Signal to the play_next_pcm_block routine */
+ case LMODE_PCM:
+ {
+ int flag; /* 0 or 2 */
+
+ pcm_qlen--;
+ pcm_head = (pcm_head + 1) % pcm_nblk;
+ if (pcm_qlen && pcm_active) {
+ play_next_pcm_block();
+ } else {/* Underrun. Just stop the voice */
+ gus_select_voice(0); /* Left channel */
+ gus_voice_off();
+ gus_rampoff();
+ gus_select_voice(1); /* Right channel */
+ gus_voice_off();
+ gus_rampoff();
+ pcm_active = 0;
+ }
+
+ /*
+ * If the queue was full before this interrupt, the
+ * DMA transfer was suspended. Let it continue now.
+ */
+ if (dma_active) {
+ if (pcm_qlen == 0)
+ flag = 1; /* Underflow */
+ else
+ flag = 0;
+ dma_active = 0;
+ } else
+ flag = 2; /* Just notify the dmabuf.c */
+ DMAbuf_outputintr(gus_devnum, flag);
+ }
+ break;
+
+ default:;
+ }
+ splx(flags);
+}
- DISABLE_INTR (flags);
+void
+do_volume_irq(int voice)
+{
+ u_char tmp;
+ int mode, parm;
+ u_long flags;
- gus_select_voice (voice);
+ flags = splhigh();
- tmp = gus_read8 (0x0d);
- tmp &= ~0x20; /*
- * Disable volume ramp IRQ
- */
- gus_write8 (0x0d, tmp);
+ gus_select_voice(voice);
- mode = voices[voice].volume_irq_mode;
- voices[voice].volume_irq_mode = 0;
- parm = voices[voice].volume_irq_parm;
+ tmp = gus_read8(0x0d);
+ tmp &= ~0x20; /* Disable volume ramp IRQ */
+ gus_write8(0x0d, tmp);
- switch (mode)
- {
- 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,
- voices[voice].note_pending, 0);
+ mode = voices[voice].volume_irq_mode;
+ voices[voice].volume_irq_mode = 0;
+ parm = voices[voice].volume_irq_parm;
- if (voices[voice].sample_pending >= 0)
- {
- guswave_set_instr (voices[voice].dev_pending, voice,
- voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
+ switch (mode) {
+ case VMODE_HALT: /* Decay phase finished */
+ splx(flags);
+ gus_voice_init(voice);
+ break;
+
+ case VMODE_ENVELOPE:
+ gus_rampoff();
+ splx(flags);
+ step_envelope(voice);
+ break;
+
+ case VMODE_START_NOTE:
+ splx(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,
+ voices[voice].note_pending, 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:;
}
- break;
+}
- default:;
- }
+void
+gus_voice_irq(void)
+{
+ u_long wave_ignore = 0, volume_ignore = 0;
+ u_long voice_bit;
+
+ u_char src, voice;
+
+ while (1) {
+ src = gus_read8(0x0f); /* Get source info */
+ voice = src & 0x1f;
+ src &= 0xc0;
+
+ if (src == (0x80 | 0x40))
+ return; /* No interrupt */
+
+ voice_bit = 1 << voice;
+
+ if (!(src & 0x80)) /* Wave IRQ pending */
+ if (!(wave_ignore & voice_bit) && (int) 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) && (int) voice < nr_voices) { /* Not done yet */
+ volume_ignore |= voice_bit;
+ do_volume_irq(voice);
+ }
+ }
}
void
-gus_voice_irq (void)
+guswave_dma_irq(void)
{
- unsigned long wave_ignore = 0, volume_ignore = 0;
- unsigned long voice_bit;
+ u_char status;
+
+ status = gus_look8(0x41); /* Get DMA IRQ Status */
+ if (status & 0x40) /* DMA interrupt pending */
+ switch (active_device) {
+ case GUS_DEV_WAVE:
+ if ((dram_sleep_flag.mode & WK_SLEEP)) {
+ dram_sleep_flag.mode = WK_WAKEUP;
+ wakeup(dram_sleeper);
+ };
+ break;
- unsigned char src, voice;
+ case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */
+ gus_transfer_output_block(pcm_current_dev, pcm_current_buf,
+ pcm_current_count, pcm_current_intrflag, 1);
+ break;
- while (1)
- {
- src = gus_read8 (0x0f); /*
- * Get source info
- */
- voice = src & 0x1f;
- src &= 0xc0;
-
- if (src == (0x80 | 0x40))
- return; /*
- * No interrupt
- */
-
- voice_bit = 1 << voice;
-
- if (!(src & 0x80)) /*
- * Wave IRQ pending
- */
- if (!(wave_ignore & voice_bit) && (int) 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) && (int) voice < nr_voices) /*
- * Not done
- * yet
- */
- {
- volume_ignore |= voice_bit;
- do_volume_irq (voice);
- }
- }
+ case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */
+ if (pcm_qlen < pcm_nblk) {
+ int flag = (1 - dma_active) * 2; /* 0 or 2 */
+
+ if (pcm_qlen == 0)
+ flag = 1; /* Underrun */
+ dma_active = 0;
+ DMAbuf_outputintr(gus_devnum, flag);
+ }
+ break;
+
+ default:;
+ }
+
+ status = gus_look8(0x49); /* Get Sampling IRQ Status */
+ if (status & 0x40) { /* Sampling Irq pending */
+ DMAbuf_inputintr(gus_devnum);
+ }
}
+#ifdef CONFIG_SEQUENCER
+/*
+ * Timer stuff
+ */
+
+static volatile int select_addr, data_addr;
+static volatile int curr_timer = 0;
+
void
-guswave_dma_irq (void)
+gus_timer_command(u_int addr, u_int val)
{
- unsigned char status;
+ int i;
- status = gus_look8 (0x41); /* Get DMA IRQ Status */
- if (status & 0x40) /* DMA interrupt pending */
- switch (active_device)
- {
- case GUS_DEV_WAVE:
- if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag))
- WAKE_UP (dram_sleeper, dram_sleep_flag);
- break;
+ outb(select_addr, (u_char) (addr & 0xff));
- case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */
- gus_transfer_output_block (pcm_current_dev, pcm_current_buf,
- pcm_current_count,
- pcm_current_intrflag, 1);
- break;
+ for (i = 0; i < 2; i++)
+ inb(select_addr);
- case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */
- if (pcm_qlen < pcm_nblk)
- {
- int flag = (1 - dma_active) * 2; /* 0 or 2 */
+ outb(data_addr, (u_char) (val & 0xff));
- if (pcm_qlen == 0)
- flag = 1; /* Underrun */
- dma_active = 0;
- DMAbuf_outputintr (gus_devnum, flag);
- }
- break;
+ for (i = 0; i < 2; i++)
+ inb(select_addr);
+}
+
+static void
+arm_timer(int timer, u_int interval)
+{
+ curr_timer = timer;
+
+ if (timer == 1) {
+ gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */
+ gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */
+ gus_timer_command(0x04, 0x01); /* Start timer 1 */
+ } else {
+ gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */
+ gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */
+ gus_timer_command(0x04, 0x02); /* Start timer 2 */
+ }
- default:;
- }
+ gus_timer_enabled = 0;
+}
- status = gus_look8 (0x49); /*
- * Get Sampling IRQ Status
- */
- if (status & 0x40) /*
- * Sampling Irq pending
- */
- {
- DMAbuf_inputintr (gus_devnum);
+static u_int
+gus_tmr_start(int dev, u_int usecs_per_tick)
+{
+ int timer_no, resolution;
+ int divisor;
+
+ if (usecs_per_tick > (256 * 80)) {
+ timer_no = 2;
+ resolution = 320; /* usec */
+ } else {
+ timer_no = 1;
+ resolution = 80;/* usec */
}
+ divisor = (usecs_per_tick + (resolution / 2)) / resolution;
+
+ arm_timer(timer_no, divisor);
+
+ return divisor * resolution;
+}
+
+static void
+gus_tmr_disable(int dev)
+{
+ gus_write8(0x45, 0); /* Disable both timers */
+ gus_timer_enabled = 0;
}
+static void
+gus_tmr_restart(int dev)
+{
+ if (curr_timer == 1)
+ gus_write8(0x45, 0x04); /* Start timer 1 again */
+ else
+ gus_write8(0x45, 0x08); /* Start timer 2 again */
+}
+
+static struct sound_lowlev_timer gus_tmr =
+{
+ 0,
+ gus_tmr_start,
+ gus_tmr_disable,
+ gus_tmr_restart
+};
+
+static void
+gus_tmr_install(int io_base)
+{
+ select_addr = io_base;
+ data_addr = io_base + 1;
+
+ sound_timer_init(&gus_tmr, "GUS");
+}
+#endif
#endif
diff --git a/sys/i386/isa/sound/hex2hex.h b/sys/i386/isa/sound/hex2hex.h
index ecd7b4c4239c..5c909174780d 100644
--- a/sys/i386/isa/sound/hex2hex.h
+++ b/sys/i386/isa/sound/hex2hex.h
@@ -81,7 +81,7 @@ int hex2hex(char *source, char *target, char *varline)
}
fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n");
- fprintf(outf, "%s[] = {\n", varline);
+ fprintf(outf, "static unsigned char %s[] = {\n", varline);
for (i=0;i<l;i++)
{
diff --git a/sys/i386/isa/sound/ics2101.c b/sys/i386/isa/sound/ics2101.c
index 4147a070fd8e..4df8bdef006f 100644
--- a/sys/i386/isa/sound/ics2101.c
+++ b/sys/i386/isa/sound/ics2101.c
@@ -1,10 +1,10 @@
/*
* 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
@@ -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,240 +24,210 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
+ *
*/
-#include "sound_config.h"
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+#include <i386/isa/sound/sound_config.h>
-#include "ultrasound.h"
-#include "gus_hw.h"
+#if defined(CONFIG_GUS)
+
+#include <i386/isa/sound/ultrasound.h>
+#include <i386/isa/sound/gus_hw.h>
#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
SOUND_MASK_SYNTH| \
SOUND_MASK_CD | SOUND_MASK_VOLUME)
+extern sound_os_info *gus_osp;
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 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)
+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--;
+ /*
+ * Experimental volume scaling by Risto Kankkunen. This should give
+ * smoother volume response than just a plain multiplication.
+ */
+ int e;
+
+ RANGE(vol, 0, 100);
+ vol = (31 * vol + 50) / 100;
+ e = 0;
+ if (vol) {
+ while (vol < 16) {
+ vol <<= 1;
+ e--;
}
- vol -= 16;
- e += 7;
+ vol -= 16;
+ e += 7;
}
- return ((e << 4) + vol);
-#else
- return ((vol * 127) + 50) / 100;
-#endif
+ return ((e << 4) + vol);
}
static void
-write_mix (int dev, int chn, int vol)
+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;
+ 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);
+ flags = splhigh();
+ outb(u_MixSelect, ctrl_addr);
+ outb(u_MixData, selector[dev]);
+ outb(u_MixSelect, attn_addr);
+ outb(u_MixData, (unsigned char) vol);
+ splx(flags);
}
static int
-set_volumes (int dev, int vol)
+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;
+ int left = vol & 0x00ff;
+ int right = (vol >> 8) & 0x00ff;
+
+ RANGE (left, 0, 100);
+ RANGE (right, 0, 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)
+ics2101_mixer_ioctl(int dev, unsigned int cmd, ioctl_arg 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);
- }
+ 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 *(int *) arg = set_volumes(DEV_MIC, (*(int *) arg));
+ break;
+
+ case SOUND_MIXER_CD:
+ return *(int *) arg = set_volumes(DEV_CD, (*(int *) arg));
+ break;
+
+ case SOUND_MIXER_LINE:
+ return *(int *) arg = set_volumes(DEV_LINE, (*(int *) arg));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return *(int *) arg = set_volumes(DEV_GF1, (*(int *) arg));
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return *(int *) arg = set_volumes(DEV_VOL, (*(int *) arg));
+ break;
+
+ default:
+ return -(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 *(int *) arg = MIX_DEVS;
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return *(int *) arg = SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC;
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return *(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return *(int *) arg = 0;
+ break;
+
+ case SOUND_MIXER_MIC:
+ return *(int *) arg = volumes[DEV_MIC];
+ break;
+
+ case SOUND_MIXER_LINE:
+ return *(int *) arg = volumes[DEV_LINE];
+ break;
+
+ case SOUND_MIXER_CD:
+ return *(int *) arg = volumes[DEV_CD];
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return *(int *) arg = volumes[DEV_VOL];
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return *(int *) arg = volumes[DEV_GF1];
+ break;
+
+ default:
+ return -(EINVAL);
+ }
}
-
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static struct mixer_operations ics2101_mixer_operations =
{
- ics2101_mixer_ioctl
+ "ICS2101 Multimedia Mixer",
+ ics2101_mixer_ioctl
};
-long
-ics2101_mixer_init (long mem_start)
+void
+ics2101_mixer_init()
{
- int i;
+ int i;
- if (num_mixers < MAX_MIXER_DEV)
- {
- mixer_devs[num_mixers++] = &ics2101_mixer_operations;
+ 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.
- */
+ /*
+ * 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;
+ 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);
+ 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 533d60a22662..e42e79059f16 100644
--- a/sys/i386/isa/sound/local.h
+++ b/sys/i386/isa/sound/local.h
@@ -1,27 +1,174 @@
-/* Generated by configure. Don't edit!!!! */
-
-#define KERNEL_SOUNDCARD
-#undef EXCLUDE_PAS
-#undef EXCLUDE_SB
-#undef EXCLUDE_ADLIB
-#undef EXCLUDE_GUS
-#define EXCLUDE_MPU401
-#define EXCLUDE_UART6850
-#define EXCLUDE_PSS
-#undef EXCLUDE_GUS16
-#undef EXCLUDE_GUSMAX
-#undef EXCLUDE_MSS
-#undef EXCLUDE_SBPRO
-#undef EXCLUDE_SB16
-#undef EXCLUDE_AUDIO
-#undef EXCLUDE_MIDI
-#undef EXCLUDE_YM3812
-#undef EXCLUDE_SEQUENCER
-
-#define DSP_BUFFSIZE 32768
-#define SELECTED_SOUND_OPTIONS 0xffffff8f
-#define SOUND_VERSION_STRING "2.90-2"
-#define SOUND_CONFIG_DATE "Thu Sep 29 15:33:39 PDT 1994"
-#define SOUND_CONFIG_BY "swallace"
-#define SOUND_CONFIG_HOST "pal-r32-a07b.slip.nts.uci.edu"
-#define SOUND_CONFIG_DOMAIN ""
+/*
+ * local.h
+ *
+ * This file was generated by configure. But then HAND-EDITED. It will
+ * probably disappear in future revisions once the configuration process
+ * will become more like that of standard bsd code.
+ * lr 970714
+ *
+ */
+
+/* build hex2hex /tmp/foo.x trix_boot.h trix_boot */
+
+/*
+ * make everything conditioned on NSND>0 so as to detect errors
+ * because of missing "controller snd0" statement
+ */
+#define ALLOW_BUFFER_MAPPING 1
+
+#include "snd.h"
+#if NSND > 0
+#define CONFIGURE_SOUNDCARD
+
+#define CONFIG_SEQUENCER
+
+#include "gus.h"
+#if NGUS != 0 && !defined(CONFIG_GUS)
+#define CONFIG_GUS
+#define CONFIG_GUSMAX
+#endif
+
+#include "sscape.h"
+#if NSSCAPE != 0 && !defined(CONFIG_SSCAPE)
+#define CONFIG_SSCAPE
+#endif
+
+#include "trix.h"
+#if NTRIX > 0
+#define INCLUDE_TRIX_BOOT
+#define CONFIG_TRIX /* can use NTRIX > 0 instead */
+#define CONFIG_YM3812
+#endif
+
+#if defined(CONFIG_GUSMAX) || ( NSSCAPE > 0 ) || ( NTRIX > 0 )
+#define CONFIG_AD1848
+#endif
+
+#if defined(CONFIG_SEQUENCER) && (NTRIX == 0)
+#define CONFIG_MIDI
+#endif
+
+#include "sb.h"
+#if NSB > 0
+#define CONFIG_SB
+#endif
+
+#include "mss.h"
+#if NMSS != 0
+#define CONFIG_AD1848
+#define CONFIG_MSS
+#undef CONFIG_CS4232
+#endif
+
+#include "sbxvi.h"
+#if NSBXVI != 0 && !defined(CONFIG_SB16)
+#define CONFIG_SB16
+#define CONFIG_SBPRO /* FIXME: Also needs to be a sep option */
+#endif
+
+#include "sbmidi.h"
+#if NSBMIDI != 0 && !defined(CONFIG_SB16MIDI)
+#define CONFIG_SB16MIDI
+#endif
+
+#include "awe.h"
+#if NAWE != 0 && !defined(CONFIG_AWE32)
+#define CONFIG_AWE32
+#endif
+
+#include "pas.h"
+#if NPAS != 0 && !defined(CONFIG_PAS)
+#define CONFIG_PAS
+#endif
+
+#include "mpu.h"
+#if NMPU != 0 && !defined(CONFIG_MPU401)
+#define CONFIG_MPU401
+#endif
+
+#include "opl.h"
+#if NOPL != 0 && !defined(CONFIG_YM3812)
+#define CONFIG_YM3812
+#endif
+
+#define ALLOW_POLL
+
+/* #undef CONFIG_PAS */
+/* #undef CONFIG_ADLIB */
+/* #define CONFIG_GUS */
+/* #undef CONFIG_MPU401 */
+#undef CONFIG_UART6850
+#undef CONFIG_PSS
+#undef CONFIG_GUS16
+/* #undef CONFIG_MSS */
+/* #undef CONFIG_SSCAPE */
+#undef CONFIG_MAD16
+/* #undef CONFIG_CS4232 */
+#undef CONFIG_MAUI
+#undef CONFIG_PNP
+/* #undef CONFIG_SBPRO */
+/* #undef CONFIG_SB16 */
+#undef CONFIG_AEDSP16
+#define CONFIG_AUDIO /* obvious ? */
+
+#define CONFIG_MPU_EMU
+
+#define DSP_BUFFSIZE 32768*2
+/* #define SELECTED_SOUND_OPTIONS 0x0188090a */
+
+#ifndef TRIX_SB_BASE
+#define TRIX_SB_BASE 0x220
+#endif
+
+#ifndef TRIX_SB_IRQ
+#define TRIX_SB_IRQ 7
+#endif
+
+#ifndef TRIX_SB_DMA
+#define TRIX_SB_DMA 1
+#endif
+
+#ifndef TRIX_BASE
+#define TRIX_BASE 0x530
+#endif
+
+#ifndef TRIX_IRQ
+#define TRIX_IRQ 9
+#endif
+
+#ifndef TRIX_DMA
+#define TRIX_DMA 3
+#endif
+
+#ifndef TRIX_DMA2
+#define TRIX_DMA2 1
+#endif
+
+#ifndef GUS_BASE
+#define GUS_BASE 0x220
+#endif
+
+#ifndef GUS_IRQ
+#define GUS_IRQ 12
+#endif
+
+#ifndef GUS_MIDI_IRQ
+#define GUS_MIDI_IRQ GUS_IRQ
+#endif
+
+#ifndef GUS_DMA
+#define GUS_DMA 4
+#endif
+
+#ifndef GUS_DMA2
+#define GUS_DMA2 4
+#endif
+
+#define SOUND_CONFIG_DATE "Wed Aug 6 22:58:35 PDT 1997"
+#define SOUND_CONFIG_BY "Amancio Hasty"
+#define SOUND_CONFIG_HOST "rah"
+#define SOUND_CONFIG_DOMAIN "star-gate.com"
+
+#else /* NSND = 0 */
+#undef CONFIGURE_SOUNDCARD
+#endif
diff --git a/sys/i386/isa/sound/midi_ctrl.h b/sys/i386/isa/sound/midi_ctrl.h
index 616b5914c6e2..8b68c7d91db3 100644
--- a/sys/i386/isa/sound/midi_ctrl.h
+++ b/sys/i386/isa/sound/midi_ctrl.h
@@ -1,9 +1,9 @@
static unsigned char ctrl_def_values[128] =
{
- 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 0 to 7 */
- 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 8 to 15 */
- 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 16 to 23 */
- 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 24 to 31 */
+ 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 0 to 7 */
+ 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 8 to 15 */
+ 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 16 to 23 */
+ 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 24 to 31 */
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 32 to 39 */
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 40 to 47 */
diff --git a/sys/i386/isa/sound/midi_synth.c b/sys/i386/isa/sound/midi_synth.c
index fd6d8bde62cd..86032e3db16d 100644
--- a/sys/i386/isa/sound/midi_synth.c
+++ b/sys/i386/isa/sound/midi_synth.c
@@ -1,10 +1,10 @@
/*
* sound/midi_synth.c
- *
+ *
* High level midi sequencer manager for dumb MIDI interfaces.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -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,451 +24,650 @@
* 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"
+#define USE_SEQ_MACROS
+#define USE_SIMPLE_MACROS
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+#include <i386/isa/sound/sound_config.h>
+
+#if defined(CONFIGURE_SOUNDCARD) /* && defined(CONFIG_MIDI) */
#define _MIDI_SYNTH_C_
-DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
+static int *sysex_sleeper = NULL;
+static volatile struct snd_wait sysex_sleep_flag = {0};
-#include "midi_synth.h"
+#include <i386/isa/sound/midi_synth.h>
static int midi2synth[MAX_MIDI_DEV];
+static int sysex_state[MAX_MIDI_DEV] =
+{0};
static unsigned char prev_out_status[MAX_MIDI_DEV];
+#ifndef CONFIG_SEQUENCER
+#define STORE(cmd)
+#else
+#define STORE(cmd) { \
+ int len; \
+ unsigned char obuf[8]; \
+ cmd; \
+ seq_input_event(obuf, len); \
+}
+#endif
+
+#define _seqbuf obuf
+#define _seqbufptr 0
+#define _SEQ_ADVBUF(x) len=x
+
+void
+do_midi_msg(int synthno, unsigned char *msg, int mlen)
+{
+ switch (msg[0] & 0xf0) {
+ case 0x90:
+ if (msg[2] != 0) {
+ STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+ break;
+ }
+ msg[2] = 64;
+
+ case 0x80:
+ STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+ break;
+
+ case 0xA0:
+ STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+ break;
+
+ case 0xB0:
+ STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+ break;
+
+ case 0xC0:
+ STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1]));
+ break;
+
+ case 0xD0:
+ STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1]));
+ break;
+
+ case 0xE0:
+ STORE(SEQ_BENDER(synthno, msg[0] & 0x0f,
+ (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
+ break;
+
+ default:
+ /*
+ * printf ("MPU: Unknown midi channel message %02x\n",
+ * msg[0]);
+ */
+ ;
+ }
+}
+
static void
-midi_outc (int midi_dev, int data)
+midi_outc(int midi_dev, int data)
{
- int timeout;
-
- for (timeout = 0; timeout < 32000; timeout++)
- if (midi_devs[midi_dev]->putc (midi_dev, (unsigned char) (data & 0xff)))
- {
- if (data & 0x80) /*
- * Status byte
- */
- prev_out_status[midi_dev] =
- (unsigned char) (data & 0xff); /*
- * Store for running status
- */
- return; /*
- * Mission complete
- */
- }
-
- /*
- * Sorry! No space on buffers.
- */
- printk ("Midi send timed out\n");
+ int timeout;
+
+ for (timeout = 0; timeout < 32000; timeout++)
+ if (midi_devs[midi_dev]->putc(midi_dev, (unsigned char) (data & 0xff))) {
+ if (data & 0x80) /* Status byte */
+ prev_out_status[midi_dev] =
+ (unsigned char) (data & 0xff); /* Store for running
+ * status */
+ return; /* Mission complete */
+ }
+ /*
+ * Sorry! No space on buffers.
+ */
+ printf("Midi send timed out\n");
}
static int
-prefix_cmd (int midi_dev, unsigned char status)
+prefix_cmd(int midi_dev, unsigned char status)
{
- if (midi_devs[midi_dev]->prefix_cmd == NULL)
- return 1;
+ if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL)
+ return 1;
- return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
+ return midi_devs[midi_dev]->prefix_cmd(midi_dev, status);
}
static void
-midi_synth_input (int dev, unsigned char data)
+midi_synth_input(int orig_dev, unsigned char data)
{
- int orig_dev;
+ int dev;
+ struct midi_input_info *inc;
- if (dev < 0 || dev > num_synths)
- return;
+ static unsigned char len_tab[] = /* # of data bytes following a status */
+ {
+ 2, /* 8x */
+ 2, /* 9x */
+ 2, /* Ax */
+ 2, /* Bx */
+ 1, /* Cx */
+ 1, /* Dx */
+ 2, /* Ex */
+ 0 /* Fx */
+ };
+
+ if (orig_dev < 0 || orig_dev > num_midis)
+ return;
- if (data == 0xfe) /* Ignore active sensing */
- return;
+ if (data == 0xfe) /* Ignore active sensing */
+ return;
- orig_dev = midi2synth[dev];
+ dev = midi2synth[orig_dev];
+ inc = &midi_devs[orig_dev]->in_info;
+
+ switch (inc->m_state) {
+ case MST_INIT:
+ if (data & 0x80) { /* MIDI status byte */
+ if ((data & 0xf0) == 0xf0) { /* Common message */
+ switch (data) {
+ case 0xf0: /* Sysex */
+ inc->m_state = MST_SYSEX;
+ break; /* Sysex */
+
+ case 0xf1: /* MTC quarter frame */
+ case 0xf3: /* Song select */
+ inc->m_state = MST_DATA;
+ inc->m_ptr = 1;
+ inc->m_left = 1;
+ inc->m_buf[0] = data;
+ break;
+
+ case 0xf2: /* Song position pointer */
+ inc->m_state = MST_DATA;
+ inc->m_ptr = 1;
+ inc->m_left = 2;
+ inc->m_buf[0] = data;
+ break;
+
+ default:
+ inc->m_buf[0] = data;
+ inc->m_ptr = 1;
+ do_midi_msg(dev, inc->m_buf, inc->m_ptr);
+ inc->m_ptr = 0;
+ inc->m_left = 0;
+ }
+ } else {
+ inc->m_state = MST_DATA;
+ inc->m_ptr = 1;
+ inc->m_left = len_tab[(data >> 4) - 8];
+ inc->m_buf[0] = inc->m_prev_status = data;
+ }
+ } else if (inc->m_prev_status & 0x80) { /* Ignore if no previous
+ * status (yet) *//* Data byte (use running status) */
+ inc->m_state = MST_DATA;
+ inc->m_ptr = 2;
+ inc->m_left = len_tab[(data >> 4) - 8] - 1;
+ inc->m_buf[0] = inc->m_prev_status;
+ inc->m_buf[1] = data;
+ }
+ break; /* MST_INIT */
+
+ case MST_DATA:
+ inc->m_buf[inc->m_ptr++] = data;
+ if (--inc->m_left <= 0) {
+ inc->m_state = MST_INIT;
+ do_midi_msg(dev, inc->m_buf, inc->m_ptr);
+ inc->m_ptr = 0;
+ }
+ break; /* MST_DATA */
+
+ case MST_SYSEX:
+ if (data == 0xf7) { /* Sysex end */
+ inc->m_state = MST_INIT;
+ inc->m_left = 0;
+ inc->m_ptr = 0;
+ }
+ break; /* MST_SYSEX */
+ default:
+ printf("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state,
+ (int) data);
+ inc->m_state = MST_INIT;
+ }
}
static void
-midi_synth_output (int dev)
+leave_sysex(int dev)
{
- /*
- * Currently NOP
- */
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int timeout = 0;
+
+ if (!sysex_state[dev])
+ return;
+
+ sysex_state[dev] = 0;
+
+ while (!midi_devs[orig_dev]->putc(orig_dev, 0xf7) && timeout < 1000)
+ timeout++;
+
+ sysex_state[dev] = 0;
+}
+
+static void
+midi_synth_output(int dev)
+{
+ /*
+ * Currently NOP
+ */
}
int
-midi_synth_ioctl (int dev,
- unsigned int cmd, unsigned int arg)
+midi_synth_ioctl(int dev, unsigned int cmd, ioctl_arg arg)
{
- /*
- * int orig_dev = synth_devs[dev]->midi_dev;
- */
+ /*
+ * int orig_dev = synth_devs[dev]->midi_dev;
+ */
- switch (cmd)
- {
+ switch (cmd) {
case SNDCTL_SYNTH_INFO:
- IOCTL_TO_USER ((char *) arg, 0, synth_devs[dev]->info,
- sizeof (struct synth_info));
-
- return 0;
- break;
+ bcopy(synth_devs[dev]->info, &(((char *) arg)[0]), sizeof(struct synth_info));
+ return 0;
+ break;
case SNDCTL_SYNTH_MEMAVL:
- return 0x7fffffff;
- break;
+ return 0x7fffffff;
+ break;
default:
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
}
int
-midi_synth_kill_note (int dev, int channel, int note, int velocity)
+midi_synth_kill_note(int dev, int channel, int note, int velocity)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int msg, chn;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int msg, chn;
- if (note < 0 || note > 127)
- return 0;
- if (channel < 0 || channel > 15)
- return 0;
- if (velocity < 0)
- velocity = 0;
- if (velocity > 127)
- velocity = 127;
-
- msg = prev_out_status[orig_dev] & 0xf0;
- chn = prev_out_status[orig_dev] & 0x0f;
-
- if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80))
- { /*
- * Use running status
- */
- if (!prefix_cmd (orig_dev, note))
+ if (note < 0 || note > 127)
+ return 0;
+ if (channel < 0 || channel > 15)
return 0;
+ RANGE (velocity, 0, 127 ) ;
+ leave_sysex(dev);
- midi_outc (orig_dev, note);
-
- if (msg == 0x90) /*
- * Running status = Note on
- */
- midi_outc (orig_dev, 0);/*
- * Note on with velocity 0 == note
- * off
- */
- else
- midi_outc (orig_dev, velocity);
- }
- else
- {
- if (velocity == 64)
- {
- if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
- return 0;
- midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /*
- * Note on
- */
- midi_outc (orig_dev, note);
- midi_outc (orig_dev, 0); /*
- * Zero G
- */
- }
- else
- {
- if (!prefix_cmd (orig_dev, 0x80 | (channel & 0x0f)))
+ msg = prev_out_status[orig_dev] & 0xf0;
+ chn = prev_out_status[orig_dev] & 0x0f;
+
+ if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) { /* Use running status */
+ if (!prefix_cmd(orig_dev, note))
return 0;
- midi_outc (orig_dev, 0x80 | (channel & 0x0f)); /*
- * Note off
- */
- midi_outc (orig_dev, note);
- midi_outc (orig_dev, velocity);
+
+ midi_outc(orig_dev, note);
+
+ if (msg == 0x90)/* Running status = Note on */
+ midi_outc(orig_dev, 0); /* Note on with velocity 0 == note off */
+ else
+ midi_outc(orig_dev, velocity);
+ } else {
+ if (velocity == 64) {
+ if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f)))
+ return 0;
+ midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* Note on */
+ midi_outc(orig_dev, note);
+ midi_outc(orig_dev, 0); /* Zero G */
+ } else {
+ if (!prefix_cmd(orig_dev, 0x80 | (channel & 0x0f)))
+ return 0;
+ midi_outc(orig_dev, 0x80 | (channel & 0x0f)); /* Note off */
+ midi_outc(orig_dev, note);
+ midi_outc(orig_dev, velocity);
}
}
- return 0;
+ return 0;
}
int
-midi_synth_set_instr (int dev, int channel, int instr_no)
+midi_synth_set_instr(int dev, int channel, int instr_no)
{
- int orig_dev = synth_devs[dev]->midi_dev;
+ int orig_dev = synth_devs[dev]->midi_dev;
- if (instr_no < 0 || instr_no > 127)
- return 0;
- if (channel < 0 || channel > 15)
- return 0;
+ if (instr_no < 0 || instr_no > 127)
+ return 0;
+ if (channel < 0 || channel > 15)
+ return 0;
- if (!prefix_cmd (orig_dev, 0xc0 | (channel & 0x0f)))
- return 0;
- midi_outc (orig_dev, 0xc0 | (channel & 0x0f)); /*
- * Program change
- */
- midi_outc (orig_dev, instr_no);
+ leave_sysex(dev);
- return 0;
+ if (!prefix_cmd(orig_dev, 0xc0 | (channel & 0x0f)))
+ return 0;
+ midi_outc(orig_dev, 0xc0 | (channel & 0x0f)); /* Program change */
+ midi_outc(orig_dev, instr_no);
+
+ return 0;
}
int
-midi_synth_start_note (int dev, int channel, int note, int velocity)
+midi_synth_start_note(int dev, int channel, int note, int velocity)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int msg, chn;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int msg, chn;
- if (note < 0 || note > 127)
- return 0;
- if (channel < 0 || channel > 15)
- return 0;
- if (velocity < 0)
- velocity = 0;
- if (velocity > 127)
- velocity = 127;
-
- msg = prev_out_status[orig_dev] & 0xf0;
- chn = prev_out_status[orig_dev] & 0x0f;
-
- if (chn == channel && msg == 0x90)
- { /*
- * Use running status
- */
- if (!prefix_cmd (orig_dev, note))
+ if (note < 0 || note > 127)
return 0;
- midi_outc (orig_dev, note);
- midi_outc (orig_dev, velocity);
- }
- else
- {
- if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
+ if (channel < 0 || channel > 15)
return 0;
- midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /*
- * Note on
- */
- midi_outc (orig_dev, note);
- midi_outc (orig_dev, velocity);
+ RANGE (velocity, 0, 127 );
+ leave_sysex(dev);
+
+ msg = prev_out_status[orig_dev] & 0xf0;
+ chn = prev_out_status[orig_dev] & 0x0f;
+
+ if (chn == channel && msg == 0x90) { /* Use running status */
+ if (!prefix_cmd(orig_dev, note))
+ return 0;
+ midi_outc(orig_dev, note);
+ midi_outc(orig_dev, velocity);
+ } else {
+ if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f)))
+ return 0;
+ midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* Note on */
+ midi_outc(orig_dev, note);
+ midi_outc(orig_dev, velocity);
}
- return 0;
+ return 0;
}
void
-midi_synth_reset (int dev)
+midi_synth_reset(int dev)
{
+
+ leave_sysex(dev);
}
int
-midi_synth_open (int dev, int mode)
+midi_synth_open(int dev, int mode)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int err;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int err;
+ unsigned long flags;
+ struct midi_input_info *inc;
+
+ if (orig_dev < 0 || orig_dev > num_midis)
+ return -(ENXIO);
+
+ midi2synth[orig_dev] = dev;
+ sysex_state[dev] = 0;
+ prev_out_status[orig_dev] = 0;
+
+ if ((err = midi_devs[orig_dev]->open(orig_dev, mode,
+ midi_synth_input, midi_synth_output)) < 0)
+ return err;
- if (orig_dev < 0 || orig_dev > num_midis)
- return RET_ERROR (ENXIO);
+ inc = &midi_devs[orig_dev]->in_info;
- midi2synth[orig_dev] = dev;
- prev_out_status[orig_dev] = 0;
+ flags = splhigh();
+ inc->m_busy = 0;
+ inc->m_state = MST_INIT;
+ inc->m_ptr = 0;
+ inc->m_left = 0;
+ inc->m_prev_status = 0x00;
+ splx(flags);
- if ((err = midi_devs[orig_dev]->open (orig_dev, mode,
- midi_synth_input, midi_synth_output)) < 0)
- return err;
+ sysex_sleep_flag.aborting = 0;
+ sysex_sleep_flag.mode = WK_NONE;
- return 1;
+ return 1;
}
void
-midi_synth_close (int dev)
+midi_synth_close(int dev)
{
- int orig_dev = synth_devs[dev]->midi_dev;
+ int orig_dev = synth_devs[dev]->midi_dev;
- /*
- * Shut up the synths by sending just single active sensing message.
- */
- midi_devs[orig_dev]->putc (orig_dev, 0xfe);
+ leave_sysex(dev);
- midi_devs[orig_dev]->close (orig_dev);
+ /*
+ * Shut up the synths by sending just single active sensing message.
+ */
+ midi_devs[orig_dev]->putc(orig_dev, 0xfe);
+
+ midi_devs[orig_dev]->close(orig_dev);
}
void
-midi_synth_hw_control (int dev, unsigned char *event)
+midi_synth_hw_control(int dev, unsigned char *event)
{
}
int
-midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
- int offs, int count, int pmgr_flag)
+midi_synth_load_patch(int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag)
{
- int orig_dev = synth_devs[dev]->midi_dev;
+ int orig_dev = synth_devs[dev]->midi_dev;
- struct sysex_info sysex;
- int i;
- unsigned long left, src_offs, eox_seen = 0;
- int first_byte = 1;
+ struct sysex_info sysex;
+ int i;
+ unsigned long left, src_offs, eox_seen = 0;
+ int first_byte = 1;
+ int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex;
- if (!prefix_cmd (orig_dev, 0xf0))
- return 0;
+ leave_sysex(dev);
- if (format != SYSEX_PATCH)
- {
- printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format);
- return RET_ERROR (EINVAL);
- }
+ if (!prefix_cmd(orig_dev, 0xf0))
+ return 0;
- if (count < sizeof (struct sysex_info))
- {
- printk ("MIDI Error: Patch header too short\n");
- return RET_ERROR (EINVAL);
+ if (format != SYSEX_PATCH) {
+ printf("MIDI Error: Invalid patch format (key) 0x%x\n", format);
+ return -(EINVAL);
}
+ if (count < hdr_size) {
+ printf("MIDI Error: Patch header too short\n");
+ return -(EINVAL);
+ }
+ count -= hdr_size;
- count -= sizeof (struct sysex_info);
+ /*
+ * Copy the header from user space but ignore the first bytes which
+ * have been transferred already.
+ */
- /*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
- */
- COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs);
+ if (uiomove(&((char *) &sysex)[offs], hdr_size - offs, addr)) {
+ printf("sb: Bad copyin()!\n");
+ };
- if (count < sysex.len)
- {
- printk ("MIDI Warning: Sysex record too short (%d<%d)\n",
- count, (int) sysex.len);
- sysex.len = count;
+ if (count < sysex.len) {
+ printf("MIDI Warning: Sysex record too short (%d<%d)\n",
+ count, (int) sysex.len);
+ sysex.len = count;
}
+ left = sysex.len;
+ src_offs = 0;
- left = sysex.len;
- src_offs = 0;
+ sysex_sleep_flag.aborting = 0;
+ sysex_sleep_flag.mode = WK_NONE;
- RESET_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
-
- for (i = 0; i < left && !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag); i++)
- {
- unsigned char data;
+ for (i = 0; i < left && !(sysex_sleep_flag.aborting); i++) {
+ unsigned char data;
- GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i);
+ uiomove((char *) &(data), 1, addr);
- if (first_byte && data != 0xf0)
- midi_outc (orig_dev, 0xf0); /* Sysex start */
+ eox_seen = (i > 0 && data & 0x80); /* End of sysex */
- eox_seen = (data == 0xf7);/*
- * Last byte was end of sysex
- */
+ if (eox_seen && data != 0xf7)
+ data = 0xf7;
- if (i == 0)
- {
- if (data != 0xf0) /*
- * Sysex start
- */
- return RET_ERROR (EINVAL);
+ if (i == 0) {
+ if (data != 0xf0) {
+ printf("Error: Sysex start missing\n");
+ return -(EINVAL);
+ }
}
+ while (!midi_devs[orig_dev]->putc(orig_dev,
+ (unsigned char) (data & 0xff)) &&
+ !(sysex_sleep_flag.aborting)) {
+ int chn;
- while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
- !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag))
- DO_SLEEP (sysex_sleeper, sysex_sleep_flag, 1); /* Wait for timeout */
- if (!first_byte && data & 0x80)
- return 0;
- first_byte = 0;
+ sysex_sleeper = &chn;
+ DO_SLEEP(chn, sysex_sleep_flag, 1);
+
+ }; /* Wait for timeout */
+
+ if (!first_byte && data & 0x80)
+ return 0;
+ first_byte = 0;
}
- if (!eox_seen)
- midi_outc (orig_dev, 0xf7);
- return 0;
+ if (!eox_seen)
+ midi_outc(orig_dev, 0xf7);
+ return 0;
}
void
-midi_synth_panning (int dev, int channel, int pressure)
+midi_synth_panning(int dev, int channel, int pressure)
{
}
void
-midi_synth_aftertouch (int dev, int channel, int pressure)
+midi_synth_aftertouch(int dev, int channel, int pressure)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int msg, chn;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int msg, chn;
- if (pressure < 0 || pressure > 127)
- return;
- if (channel < 0 || channel > 15)
- return;
+ if (pressure < 0 || pressure > 127)
+ return;
+ if (channel < 0 || channel > 15)
+ return;
- msg = prev_out_status[orig_dev] & 0xf0;
- chn = prev_out_status[orig_dev] & 0x0f;
+ leave_sysex(dev);
- if (msg != 0xd0 || chn != channel) /*
- * Test for running status
- */
- {
- if (!prefix_cmd (orig_dev, 0xd0 | (channel & 0x0f)))
+ msg = prev_out_status[orig_dev] & 0xf0;
+ chn = prev_out_status[orig_dev] & 0x0f;
+
+ if (msg != 0xd0 || chn != channel) { /* Test for running status */
+ if (!prefix_cmd(orig_dev, 0xd0 | (channel & 0x0f)))
+ return;
+ midi_outc(orig_dev, 0xd0 | (channel & 0x0f)); /* Channel pressure */
+ } else if (!prefix_cmd(orig_dev, pressure))
return;
- midi_outc (orig_dev, 0xd0 | (channel & 0x0f)); /*
- * Channel pressure
- */
- }
- else if (!prefix_cmd (orig_dev, pressure))
- return;
- midi_outc (orig_dev, pressure);
+
+ midi_outc(orig_dev, pressure);
}
void
-midi_synth_controller (int dev, int channel, int ctrl_num, int value)
+midi_synth_controller(int dev, int channel, int ctrl_num, int value)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int chn, msg;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int chn, msg;
- if (ctrl_num < 1 || ctrl_num > 127)
- return; /* NOTE! Controller # 0 ignored */
- if (channel < 0 || channel > 15)
- return;
+ if (ctrl_num < 1 || ctrl_num > 127)
+ return; /* NOTE! Controller # 0 ignored */
+ if (channel < 0 || channel > 15)
+ return;
- msg = prev_out_status[orig_dev] & 0xf0;
- chn = prev_out_status[orig_dev] & 0x0f;
+ leave_sysex(dev);
- if (msg != 0xb0 || chn != channel)
- {
- if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f)))
+ msg = prev_out_status[orig_dev] & 0xf0;
+ chn = prev_out_status[orig_dev] & 0x0f;
+
+ if (msg != 0xb0 || chn != channel) {
+ if (!prefix_cmd(orig_dev, 0xb0 | (channel & 0x0f)))
+ return;
+ midi_outc(orig_dev, 0xb0 | (channel & 0x0f));
+ } else if (!prefix_cmd(orig_dev, ctrl_num))
return;
- midi_outc (orig_dev, 0xb0 | (channel & 0x0f));
- }
- else if (!prefix_cmd (orig_dev, ctrl_num))
- return;
- midi_outc (orig_dev, ctrl_num);
- midi_outc (orig_dev, value & 0x7f);
+ midi_outc(orig_dev, ctrl_num);
+ midi_outc(orig_dev, value & 0x7f);
}
int
-midi_synth_patchmgr (int dev, struct patmgr_info *rec)
+midi_synth_patchmgr(int dev, struct patmgr_info * rec)
{
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
void
-midi_synth_bender (int dev, int channel, int value)
+midi_synth_bender(int dev, int channel, int value)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int msg, prev_chn;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int msg, prev_chn;
- if (channel < 0 || channel > 15)
- return;
+ if (channel < 0 || channel > 15)
+ return;
+
+ if (value < 0 || value > 16383)
+ return;
- if (value < 0 || value > 16383)
- return;
+ leave_sysex(dev);
- msg = prev_out_status[orig_dev] & 0xf0;
- prev_chn = prev_out_status[orig_dev] & 0x0f;
+ msg = prev_out_status[orig_dev] & 0xf0;
+ prev_chn = prev_out_status[orig_dev] & 0x0f;
- if (msg != 0xd0 || prev_chn != channel) /*
- * * Test for running status */
- {
- if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f)))
+ if (msg != 0xd0 || prev_chn != channel) { /* Test for running status */
+ if (!prefix_cmd(orig_dev, 0xe0 | (channel & 0x0f)))
+ return;
+ midi_outc(orig_dev, 0xe0 | (channel & 0x0f));
+ } else if (!prefix_cmd(orig_dev, value & 0x7f))
return;
- midi_outc (orig_dev, 0xe0 | (channel & 0x0f));
- }
- else if (!prefix_cmd (orig_dev, value & 0x7f))
- return;
- midi_outc (orig_dev, value & 0x7f);
- midi_outc (orig_dev, (value >> 7) & 0x7f);
+ midi_outc(orig_dev, value & 0x7f);
+ midi_outc(orig_dev, (value >> 7) & 0x7f);
+}
+
+void
+midi_synth_setup_voice(int dev, int voice, int channel)
+{
}
+int
+midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
+{
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ switch (bytes[i]) {
+ case 0xf0: /* Start sysex */
+ if (!prefix_cmd(orig_dev, 0xf0))
+ return 0;
+ sysex_state[dev] = 1;
+ break;
+
+ case 0xf7: /* End sysex */
+ if (!sysex_state[dev]) /* Orphan sysex end */
+ return 0;
+ sysex_state[dev] = 0;
+ break;
+
+ default:
+ if (!sysex_state[dev])
+ return 0;
+
+ if (bytes[i] & 0x80) { /* Error. Another message before sysex end */
+ bytes[i] = 0xf7; /* Sysex end */
+ sysex_state[dev] = 0;
+ }
+ }
+
+ if (!midi_devs[orig_dev]->putc(orig_dev, bytes[i])) {
+ /*
+ * Hardware leve buffer is full. Abort the sysex message.
+ */
+
+ int timeout = 0;
+
+ bytes[i] = 0xf7;
+ sysex_state[dev] = 0;
+
+ while (!midi_devs[orig_dev]->putc(orig_dev, bytes[i]) &&
+ timeout < 1000)
+ timeout++;
+ }
+ if (!sysex_state[dev])
+ return 0;
+ }
+
+ return 0;
+}
#endif
diff --git a/sys/i386/isa/sound/midi_synth.h b/sys/i386/isa/sound/midi_synth.h
index 04075e294ca6..80e627be4ce1 100644
--- a/sys/i386/isa/sound/midi_synth.h
+++ b/sys/i386/isa/sound/midi_synth.h
@@ -1,5 +1,5 @@
int midi_synth_ioctl (int dev,
- unsigned int cmd, unsigned int arg);
+ unsigned int cmd, ioctl_arg arg);
int midi_synth_kill_note (int dev, int channel, int note, int velocity);
int midi_synth_set_instr (int dev, int channel, int instr_no);
int midi_synth_start_note (int dev, int channel, int note, int volume);
@@ -14,7 +14,8 @@ void midi_synth_aftertouch (int dev, int channel, int pressure);
void midi_synth_controller (int dev, int channel, int ctrl_num, int value);
int midi_synth_patchmgr (int dev, struct patmgr_info *rec);
void midi_synth_bender (int dev, int chn, int value);
-
+void midi_synth_setup_voice (int dev, int voice, int chn);
+int midi_synth_send_sysex(int dev, unsigned char *bytes,int len);
#ifndef _MIDI_SYNTH_C_
static struct synth_info std_synth_info =
@@ -40,6 +41,9 @@ static struct synth_operations std_midi_synth =
midi_synth_panning,
NULL,
midi_synth_patchmgr,
- midi_synth_bender
+ midi_synth_bender,
+ NULL, /* alloc_voice */
+ midi_synth_setup_voice,
+ midi_synth_send_sysex
};
#endif
diff --git a/sys/i386/isa/sound/midibuf.c b/sys/i386/isa/sound/midibuf.c
index ae0ddc3ea54b..e452e0a35f21 100644
--- a/sys/i386/isa/sound/midibuf.c
+++ b/sys/i386/isa/sound/midibuf.c
@@ -1,10 +1,10 @@
/*
* sound/midibuf.c
- *
+ *
* Device file manager for /dev/midi#
- *
+ *
* 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,420 +24,406 @@
* 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"
+#include <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+
+#if defined(CONFIG_MIDI)
/*
* Don't make MAX_QUEUE_SIZE larger than 4000
*/
#define MAX_QUEUE_SIZE 4000
+int
+MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait);
+
+void
+drain_midi_queue(int dev);
+
+static int *midi_sleeper[MAX_MIDI_DEV] = {NULL};
+static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = { {0}};
+static int *input_sleeper[MAX_MIDI_DEV] = {NULL};
+static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = { {0}};
-DEFINE_WAIT_QUEUES (midi_sleeper[MAX_MIDI_DEV], midi_sleep_flag[MAX_MIDI_DEV]);
-DEFINE_WAIT_QUEUES (input_sleeper[MAX_MIDI_DEV], input_sleep_flag[MAX_MIDI_DEV]);
-
-struct midi_buf
- {
- int len, head, tail;
- unsigned char queue[MAX_QUEUE_SIZE];
- };
-
-struct midi_parms
- {
- int prech_timeout; /*
- * Timeout before the first ch
- */
- };
-
-static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] =
-{NULL};
-static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] =
-{NULL};
+struct midi_buf {
+ int len, head, tail;
+ u_char queue[MAX_QUEUE_SIZE];
+};
+
+struct midi_parms {
+ int prech_timeout; /* Timeout before the first ch */
+};
+
+static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL};
+static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL};
static struct midi_parms parms[MAX_MIDI_DEV];
-static void midi_poll (unsigned long dummy);
+static void midi_poll(void *dummy);
-DEFINE_TIMER (poll_timer, midi_poll);
static volatile int open_devs = 0;
#define DATA_AVAIL(q) (q->len)
#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
#define QUEUE_BYTE(q, data) \
- if (SPACE_AVAIL(q)) \
- { \
- unsigned long flags; \
- DISABLE_INTR(flags); \
+ if (SPACE_AVAIL(q)) { \
+ u_long flags; \
+ flags = splhigh(); \
q->queue[q->tail] = (data); \
q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
- RESTORE_INTR(flags); \
+ splx(flags); \
}
#define REMOVE_BYTE(q, data) \
- if (DATA_AVAIL(q)) \
- { \
- unsigned long flags; \
- DISABLE_INTR(flags); \
+ if (DATA_AVAIL(q)) { \
+ u_long flags; \
+ flags = splhigh(); \
data = q->queue[q->head]; \
q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
- RESTORE_INTR(flags); \
+ splx(flags); \
}
void
-drain_midi_queue (int dev)
+drain_midi_queue(int dev)
{
- /*
- * Give the Midi driver time to drain its output queues
- */
+ /*
+ * Give the Midi driver time to drain its output queues
+ */
+
+ if (midi_devs[dev]->buffer_status != NULL)
+ while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) &&
+ midi_devs[dev]->buffer_status(dev)) {
+ int chn;
+
+ midi_sleeper[dev] = &chn;
+ DO_SLEEP(chn, midi_sleep_flag[dev], hz / 10);
- if (midi_devs[dev]->buffer_status != NULL)
- while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
- midi_devs[dev]->buffer_status (dev))
- DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], HZ / 10);
+ };
}
static void
-midi_input_intr (int dev, unsigned char data)
+midi_input_intr(int dev, u_char data)
{
- if (midi_in_buf[dev] == NULL)
- return;
-
- if (data == 0xfe) /*
- * Active sensing
- */
- return; /*
- * Ignore
- */
-
- if (SPACE_AVAIL (midi_in_buf[dev]))
- {
- QUEUE_BYTE (midi_in_buf[dev], data);
- if (SOMEONE_WAITING (input_sleeper[dev], input_sleep_flag[dev]))
- WAKE_UP (input_sleeper[dev], input_sleep_flag[dev]);
- }
-
+ if (midi_in_buf[dev] == NULL)
+ return;
+
+ if (data == 0xfe) /* Active sensing */
+ return; /* Ignore */
+
+ if (SPACE_AVAIL(midi_in_buf[dev])) {
+ QUEUE_BYTE(midi_in_buf[dev], data);
+ if ((input_sleep_flag[dev].mode & WK_SLEEP)) {
+ input_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(input_sleeper[dev]);
+ };
+ }
}
static void
-midi_output_intr (int dev)
+midi_output_intr(int dev)
{
- /*
- * Currently NOP
- */
+ /*
+ * Currently NOP
+ */
}
static void
-midi_poll (unsigned long dummy)
+midi_poll(void *dummy)
{
- unsigned long flags;
- int dev;
-
- DISABLE_INTR (flags);
- if (open_devs)
- {
- for (dev = 0; dev < num_midis; dev++)
- if (midi_out_buf[dev] != NULL)
- {
- while (DATA_AVAIL (midi_out_buf[dev]) &&
- midi_devs[dev]->putc (dev,
- midi_out_buf[dev]->queue[midi_out_buf[dev]->head]))
- {
- midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
- midi_out_buf[dev]->len--;
- }
-
- if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&
- SOMEONE_WAITING (midi_sleeper[dev], midi_sleep_flag[dev]))
- WAKE_UP (midi_sleeper[dev], midi_sleep_flag[dev]);
- }
- ACTIVATE_TIMER (poll_timer, midi_poll, 1); /*
- * Come back later
- */
- }
- RESTORE_INTR (flags);
+ u_long flags;
+ int dev;
+
+ flags = splhigh();
+ if (open_devs) {
+ for (dev = 0; dev < num_midis; dev++)
+ if (midi_out_buf[dev] != NULL) {
+ while (DATA_AVAIL(midi_out_buf[dev]) &&
+ midi_devs[dev]->putc(dev,
+ midi_out_buf[dev]->queue[midi_out_buf[dev]->head])) {
+ midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
+ midi_out_buf[dev]->len--;
+ }
+
+ if (DATA_AVAIL(midi_out_buf[dev]) < 100 &&
+ (midi_sleep_flag[dev].mode & WK_SLEEP)) {
+ midi_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(midi_sleeper[dev]);
+ };
+ }
+ timeout( midi_poll, 0, 1);; /* Come back later */
+ }
+ splx(flags);
}
int
-MIDIbuf_open (int dev, struct fileinfo *file)
+MIDIbuf_open(int dev, struct fileinfo * file)
{
- int mode, err;
- unsigned long flags;
+ int mode, err;
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
-
- if (num_midis > MAX_MIDI_DEV)
- {
- printk ("Sound: FATAL ERROR: Too many midi interfaces\n");
- num_midis = MAX_MIDI_DEV;
- }
-
- if (dev < 0 || dev >= num_midis)
- {
- printk ("Sound: Nonexistent MIDI interface %d\n", dev);
- return RET_ERROR (ENXIO);
- }
-
- /*
- * Interrupts disabled. Be careful
- */
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ if (num_midis > MAX_MIDI_DEV) {
+ printf("Sound: FATAL ERROR: Too many midi interfaces\n");
+ num_midis = MAX_MIDI_DEV;
+ }
+ if (dev < 0 || dev >= num_midis) {
+ printf("Sound: Nonexistent MIDI interface %d\n", dev);
+ return -(ENXIO);
+ }
+ /*
+ * Interrupts disabled. Be careful
+ */
- DISABLE_INTR (flags);
- if ((err = midi_devs[dev]->open (dev, mode,
- midi_input_intr, midi_output_intr)) < 0)
- {
- RESTORE_INTR (flags);
- return err;
- }
-
- parms[dev].prech_timeout = 0;
-
- RESET_WAIT_QUEUE (midi_sleeper[dev], midi_sleep_flag[dev]);
- RESET_WAIT_QUEUE (input_sleeper[dev], input_sleep_flag[dev]);
-
- midi_in_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));
-
- if (midi_in_buf[dev] == NULL)
- {
- printk ("midi: Can't allocate buffer\n");
- midi_devs[dev]->close (dev);
- RESTORE_INTR (flags);
- return RET_ERROR (EIO);
- }
- midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
-
- midi_out_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));
-
- if (midi_out_buf[dev] == NULL)
- {
- printk ("midi: Can't allocate buffer\n");
- midi_devs[dev]->close (dev);
- KERNEL_FREE (midi_in_buf[dev]);
- midi_in_buf[dev] = NULL;
- RESTORE_INTR (flags);
- return RET_ERROR (EIO);
- }
- midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
- if (!open_devs)
- ACTIVATE_TIMER (poll_timer, midi_poll, 1); /*
- * Come back later
- */
- open_devs++;
- RESTORE_INTR (flags);
-
- return err;
+ if ((err = midi_devs[dev]->open(dev, mode,
+ midi_input_intr, midi_output_intr)) < 0) {
+ return err;
+ }
+ parms[dev].prech_timeout = 0;
+
+ midi_in_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK);
+
+ if (midi_in_buf[dev] == NULL) {
+ printf("midi: Can't allocate buffer\n");
+ midi_devs[dev]->close(dev);
+ return -(EIO);
+ }
+ midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
+
+ midi_out_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK);
+
+ if (midi_out_buf[dev] == NULL) {
+ printf("midi: Can't allocate buffer\n");
+ midi_devs[dev]->close(dev);
+ free(midi_in_buf[dev], M_TEMP);
+ midi_in_buf[dev] = NULL;
+ return -(EIO);
+ }
+ midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
+ open_devs++;
+
+ {
+ midi_sleep_flag[dev].aborting = 0;
+ midi_sleep_flag[dev].mode = WK_NONE;
+ };
+ {
+ input_sleep_flag[dev].aborting = 0;
+ input_sleep_flag[dev].mode = WK_NONE;
+ };
+
+ if (open_devs < 2) { /* This was first open */
+ {
+ };
+
+ timeout( midi_poll, 0, 1);; /* Start polling */
+ }
+ return err;
}
void
-MIDIbuf_release (int dev, struct fileinfo *file)
+MIDIbuf_release(int dev, struct fileinfo * file)
{
- int mode;
- unsigned long flags;
+ int mode;
+ u_long flags;
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
- DISABLE_INTR (flags);
+ if (dev < 0 || dev >= num_midis)
+ return;
- /*
- * Wait until the queue is empty
- */
+ flags = splhigh();
+
+ /*
+ * Wait until the queue is empty
+ */
- if (mode != OPEN_READ)
- {
- midi_devs[dev]->putc (dev, 0xfe); /*
- * Active sensing to shut the
- * devices
- */
-
- while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
- DATA_AVAIL (midi_out_buf[dev]))
- DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0); /*
- * Sync
- */
-
- drain_midi_queue (dev); /*
- * Ensure the output queues are empty
- */
- }
-
- midi_devs[dev]->close (dev);
- KERNEL_FREE (midi_in_buf[dev]);
- KERNEL_FREE (midi_out_buf[dev]);
- midi_in_buf[dev] = NULL;
- midi_out_buf[dev] = NULL;
- open_devs--;
- RESTORE_INTR (flags);
+ if (mode != OPEN_READ) {
+ midi_devs[dev]->putc(dev, 0xfe); /* Active sensing to
+ * shut the devices */
+
+ while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) &&
+ DATA_AVAIL(midi_out_buf[dev])) {
+ int chn;
+ midi_sleeper[dev] = &chn;
+ DO_SLEEP(chn, midi_sleep_flag[dev], 0);
+
+ }; /* Sync */
+
+ drain_midi_queue(dev); /* Ensure the output queues are empty */
+ }
+ splx(flags);
+
+ midi_devs[dev]->close(dev);
+
+ free(midi_in_buf[dev], M_TEMP);
+ free(midi_out_buf[dev], M_TEMP);
+ midi_in_buf[dev] = NULL;
+ midi_out_buf[dev] = NULL;
+ if (open_devs < 2) {
+ };
+ open_devs--;
}
int
-MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+MIDIbuf_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
{
- unsigned long flags;
- int c, n, i;
- unsigned char tmp_data;
+ u_long flags;
+ int c, n, i;
+ u_char tmp_data;
- dev = dev >> 4;
+ dev = dev >> 4;
- if (!count)
- return 0;
+ if (!count)
+ return 0;
- DISABLE_INTR (flags);
+ flags = splhigh();
- c = 0;
+ c = 0;
- while (c < count)
- {
- n = SPACE_AVAIL (midi_out_buf[dev]);
+ while (c < count) {
+ n = SPACE_AVAIL(midi_out_buf[dev]);
- if (n == 0) /*
- * No space just now. We have to sleep
- */
- {
- DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0);
- if (PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]))
- {
- RESTORE_INTR (flags);
- return RET_ERROR (EINTR);
- }
-
- n = SPACE_AVAIL (midi_out_buf[dev]);
- }
+ if (n == 0) { /* No space just now. We have to sleep */
- if (n > (count - c))
- n = count - c;
+ {
+ int chn;
- for (i = 0; i < n; i++)
- {
- COPY_FROM_USER (&tmp_data, buf, c, 1);
- QUEUE_BYTE (midi_out_buf[dev], tmp_data);
- c++;
+ midi_sleeper[dev] = &chn;
+ DO_SLEEP(chn, midi_sleep_flag[dev], 0);
+ };
+
+ if (PROCESS_ABORTING(midi_sleep_flag[dev])) {
+ splx(flags);
+ return -(EINTR);
+ }
+ n = SPACE_AVAIL(midi_out_buf[dev]);
+ }
+ if (n > (count - c))
+ n = count - c;
+
+ for (i = 0; i < n; i++) {
+
+ if (uiomove((char *) &tmp_data, 1, buf)) {
+ printf("sb: Bad copyin()!\n");
+ };
+ QUEUE_BYTE(midi_out_buf[dev], tmp_data);
+ c++;
+ }
}
- }
- RESTORE_INTR (flags);
+ splx(flags);
- return c;
+ return c;
}
int
-MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+MIDIbuf_read(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
{
- int n, c = 0;
- unsigned long flags;
- unsigned char tmp_data;
+ int n, c = 0;
+ u_long flags;
+ u_char tmp_data;
- dev = dev >> 4;
+ dev = dev >> 4;
- DISABLE_INTR (flags);
-
- if (!DATA_AVAIL (midi_in_buf[dev])) /*
- * No data yet, wait
- */
- {
- DO_SLEEP (input_sleeper[dev], input_sleep_flag[dev],
- parms[dev].prech_timeout);
- if (PROCESS_ABORTING (input_sleeper[dev], input_sleep_flag[dev]))
- c = RET_ERROR (EINTR); /*
- * The user is getting restless
- */
- }
-
- if (c == 0 && DATA_AVAIL (midi_in_buf[dev])) /*
- * Got some bytes
- */
- {
- n = DATA_AVAIL (midi_in_buf[dev]);
- if (n > count)
- n = count;
- c = 0;
-
- while (c < n)
- {
- REMOVE_BYTE (midi_in_buf[dev], tmp_data);
- COPY_TO_USER (buf, c, &tmp_data, 1);
- c++;
- }
- }
+ flags = splhigh();
+
+ if (!DATA_AVAIL(midi_in_buf[dev])) { /* No data yet, wait */
- RESTORE_INTR (flags);
+ {
+ int chn;
- return c;
+
+ input_sleeper[dev] = &chn;
+ DO_SLEEP(chn, input_sleep_flag[dev],
+ parms[dev].prech_timeout);
+
+ };
+ if (PROCESS_ABORTING(input_sleep_flag[dev]))
+ c = -(EINTR); /* The user is getting restless */
+ }
+ if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) { /* Got some bytes */
+ n = DATA_AVAIL(midi_in_buf[dev]);
+ if (n > count)
+ n = count;
+ c = 0;
+
+ while (c < n) {
+ REMOVE_BYTE(midi_in_buf[dev], tmp_data);
+
+ if (uiomove((char *) &tmp_data, 1, buf)) {
+ printf("sb: Bad copyout()!\n");
+ };
+ c++;
+ }
+ }
+ splx(flags);
+
+ return c;
}
int
-MIDIbuf_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
+MIDIbuf_ioctl(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg)
{
- int val;
+ int val;
- dev = dev >> 4;
+ dev = dev >> 4;
- switch (cmd)
- {
+ if (((cmd >> 8) & 0xff) == 'C') {
+ if (midi_devs[dev]->coproc) /* Coprocessor ioctl */
+ return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
+ else
+ printf("/dev/midi%d: No coprocessor for this device\n", dev);
- case SNDCTL_MIDI_PRETIME:
- val = IOCTL_IN (arg);
- if (val < 0)
- val = 0;
+ return -(ENXIO);
+ } else
+ switch (cmd) {
- val = (HZ * val) / 10;
- parms[dev].prech_timeout = val;
- return IOCTL_OUT (arg, val);
- break;
+ case SNDCTL_MIDI_PRETIME:
+ val = (int) (*(int *) arg);
+ if (val < 0)
+ val = 0;
- default:
- return midi_devs[dev]->ioctl (dev, cmd, arg);
- }
+ val = (hz * val) / 10;
+ parms[dev].prech_timeout = val;
+ return *(int *) arg = val;
+ break;
+
+ default:
+ return midi_devs[dev]->ioctl(dev, cmd, arg);
+ }
}
-#ifdef ALLOW_SELECT
+#ifdef ALLOW_POLL
int
-MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait)
{
- dev = dev >> 4;
+ int revents = 0;
- switch (sel_type)
- {
- case SEL_IN:
- if (!DATA_AVAIL (midi_in_buf[dev]))
- {
- input_sleep_flag[dev].mode = WK_SLEEP;
- select_wait (&input_sleeper[dev], wait);
- return 0;
- }
- return 1;
- break;
+ dev = dev >> 4;
- case SEL_OUT:
- if (SPACE_AVAIL (midi_out_buf[dev]))
- {
- midi_sleep_flag[dev].mode = WK_SLEEP;
- select_wait (&midi_sleeper[dev], wait);
- return 0;
- }
- return 1;
- break;
+ if (events & (POLLIN | POLLRDNORM))
+ if (!DATA_AVAIL (midi_in_buf[dev]))
+ selrecord(wait, &selinfo[dev]);
+ else
+ revents |= events & (POLLIN | POLLRDNORM);
- case SEL_EX:
- return 0;
- }
+ if (events & (POLLOUT | POLLWRNORM))
+ if (SPACE_AVAIL (midi_out_buf[dev]))
+ selrecord(wait, &selinfo[dev]);
+ else
+ revents |= events & (POLLOUT | POLLWRNORM);
- return 0;
+ return revents;
}
#endif /* ALLOW_SELECT */
-long
-MIDIbuf_init (long mem_start)
-{
- return mem_start;
-}
+
#endif
diff --git a/sys/i386/isa/sound/mpu401.c b/sys/i386/isa/sound/mpu401.c
index 40be06638ac5..60b0c292221d 100644
--- a/sys/i386/isa/sound/mpu401.c
+++ b/sys/i386/isa/sound/mpu401.c
@@ -1,10 +1,10 @@
/*
* sound/mpu401.c
- *
+ *
* The low level driver for Roland MPU-401 compatible Midi cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,90 +24,91 @@
* 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: Riccardo Facchetti 24 Mar 1995 - Added the Audio Excel DSP 16
+ * initialization routine.
*/
#define USE_SEQ_MACROS
#define USE_SIMPLE_MACROS
-#include "sound_config.h"
+#include <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
-
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+#include <i386/isa/sound/coproc.h>
static int init_sequence[20]; /* NOTE! pos 0 = len, start pos 1. */
+
+#ifdef CONFIG_SEQUENCER
static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
-struct mpu_config
- {
- int base; /*
- * I/O base
- */
- int irq;
- int opened; /*
- * Open mode
- */
- int devno;
- int synthno;
- int uart_mode;
- int initialized;
- int mode;
+#endif
+
+struct mpu_config {
+ int base; /* I/O base */
+ int irq;
+ int opened; /* Open mode */
+ int devno;
+ int synthno;
+ int uart_mode;
+ int initialized;
+ int mode;
#define MODE_MIDI 1
#define MODE_SYNTH 2
- unsigned char version, revision;
- unsigned int capabilities;
+ u_char version, revision;
+ u_int capabilities;
#define MPU_CAP_INTLG 0x10000000
#define MPU_CAP_SYNC 0x00000010
#define MPU_CAP_FSK 0x00000020
#define MPU_CAP_CLS 0x00000040
#define MPU_CAP_SMPTE 0x00000080
#define MPU_CAP_2PORT 0x00000001
- int timer_flag;
+ int timer_flag;
#define MBUF_MAX 10
#define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \
- {printk("MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;}
- int m_busy;
- unsigned char m_buf[MBUF_MAX];
- int m_ptr;
- int m_state;
- int m_left;
- unsigned char last_status;
- void (*inputintr) (int dev, unsigned char data);
- unsigned short controls[32];
- };
+ {printf("MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;}
+ int m_busy;
+ u_char m_buf[MBUF_MAX];
+ int m_ptr;
+ int m_state;
+ int m_left;
+ u_char last_status;
+ void (*inputintr) (int dev, u_char data);
+ int shared_irq;
+ sound_os_info *osp;
+};
#define DATAPORT(base) (base)
#define COMDPORT(base) (base+1)
#define STATPORT(base) (base+1)
-#define mpu401_status(base) INB(STATPORT(base))
-#define input_avail(base) (!(mpu401_status(base)&INPUT_AVAIL))
-#define output_ready(base) (!(mpu401_status(base)&OUTPUT_READY))
-#define write_command(base, cmd) OUTB(cmd, COMDPORT(base))
-#define read_data(base) INB(DATAPORT(base))
+#define mpu401_status(devc) inb( STATPORT(devc->base))
+#define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL))
+#define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY))
+#define write_command(devc, cmd) outb( COMDPORT(devc->base), cmd)
+#define read_data(devc) inb( DATAPORT(devc->base))
-#define write_data(base, byte) OUTB(byte, DATAPORT(base))
+#define write_data(devc, byte) outb( DATAPORT(devc->base), byte)
#define OUTPUT_READY 0x40
#define INPUT_AVAIL 0x80
-#define MPU_ACK 0xF7
+#define MPU_ACK 0xFE
#define MPU_RESET 0xFF
#define UART_MODE_ON 0x3F
-static struct mpu_config dev_conf[MAX_MIDI_DEV] =
-{
- {0}};
+static struct mpu_config dev_conf[MAX_MIDI_DEV] = { {0}};
static int n_mpu_devs = 0;
-static int irq2dev[16];
+static volatile int irq2dev[17] =
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+static int reset_mpu401(struct mpu_config * devc);
+static void set_uart_mode(int dev, struct mpu_config * devc, int arg);
-static int reset_mpu401 (struct mpu_config *devc);
-static void set_uart_mode (int dev, struct mpu_config *devc, int arg);
-static void mpu_timer_init (int midi_dev);
-static void mpu_timer_interrupt (void);
-static void timer_ext_event (struct mpu_config *devc, int event, int parm);
+static void mpu_timer_init(int midi_dev);
+static void mpu_timer_interrupt(void);
+static void timer_ext_event(struct mpu_config * devc, int event, int parm);
static struct synth_info mpu_synth_info_proto =
{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, SYNTH_CAP_INPUT};
@@ -128,119 +129,57 @@ static struct synth_info mpu_synth_info[MAX_MIDI_DEV];
#define ST_SONGSEL 103 /* Song select */
#define ST_SONGPOS 104 /* Song position pointer */
-static unsigned char len_tab[] =/* # of data bytes following a status
- */
+static u_char len_tab[] =/* # of data bytes following a status */
{
- 2, /* 8x */
- 2, /* 9x */
- 2, /* Ax */
- 2, /* Bx */
- 1, /* Cx */
- 1, /* Dx */
- 2, /* Ex */
- 0 /* Fx */
+ 2, /* 8x */
+ 2, /* 9x */
+ 2, /* Ax */
+ 2, /* Bx */
+ 1, /* Cx */
+ 1, /* Dx */
+ 2, /* Ex */
+ 0 /* Fx */
};
+#ifndef CONFIG_SEQUENCER
+#define STORE(cmd)
+#else
#define STORE(cmd) \
-if (devc->opened & OPEN_READ) \
{ \
int len; \
- unsigned char obuf[8]; \
+ u_char obuf[8]; \
cmd; \
seq_input_event(obuf, len); \
}
+#endif
+
#define _seqbuf obuf
#define _seqbufptr 0
#define _SEQ_ADVBUF(x) len=x
-static void
-do_midi_msg (struct mpu_config *devc, unsigned char *msg, int mlen)
-{
- switch (msg[0] & 0xf0)
- {
- case 0x90:
- if (msg[2] != 0)
- {
- STORE (SEQ_START_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
- break;
- }
- msg[2] = 64;
-
- case 0x80:
- STORE (SEQ_STOP_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
- break;
-
- case 0xA0:
- STORE (SEQ_KEY_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
- break;
-
- case 0xB0:
- /*
- * Fix the controller value (combine MSB and LSB)
- */
- if (msg[1] < 64)
- {
- int ctrl = msg[1];
-
- if (ctrl < 32)
- {
- devc->controls[ctrl] = (msg[2] & 0x7f) << 7;
- }
- else
- {
- ctrl -= 32;
- devc->controls[ctrl] =
- (devc->controls[ctrl] & ~0x7f) | (msg[2] & 0x7f);
- }
- STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f,
- msg[1], devc->controls[ctrl]));
- }
- else
- STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
- break;
-
- case 0xC0:
- STORE (SEQ_SET_PATCH (devc->synthno, msg[0] & 0x0f, msg[1]));
- break;
-
- case 0xD0:
- STORE (SEQ_CHN_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1]));
- break;
-
- case 0xE0:
- STORE (SEQ_BENDER (devc->synthno, msg[0] & 0x0f,
- (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
- break;
-
- default:
- printk ("MPU: Unknown midi channel message %02x\n", msg[0]);
- }
-}
-
static int
-mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
+mpu_input_scanner(struct mpu_config * devc, u_char midic)
{
- switch (devc->m_state)
- {
+
+ switch (devc->m_state) {
case ST_INIT:
- switch (midic)
- {
+ switch (midic) {
case 0xf8:
- /* Timer overflow */
- break;
+ /* Timer overflow */
+ break;
case 0xfc:
- printk ("<all end>");
- break;
+ printf("<all end>");
+ break;
case 0xfd:
- if (devc->timer_flag)
- mpu_timer_interrupt ();
- break;
+ if (devc->timer_flag)
+ mpu_timer_interrupt();
+ break;
case 0xfe:
- return MPU_ACK;
- break;
+ return MPU_ACK;
+ break;
case 0xf0:
case 0xf1:
@@ -250,1472 +189,1440 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
case 0xf5:
case 0xf6:
case 0xf7:
- printk ("<Trk data rq #%d>", midic & 0x0f);
- break;
+ printf("<Trk data rq #%d>", midic & 0x0f);
+ break;
case 0xf9:
- printk ("<conductor rq>");
- break;
+ printf("<conductor rq>");
+ break;
case 0xff:
- devc->m_state = ST_SYSMSG;
- break;
+ devc->m_state = ST_SYSMSG;
+ break;
default:
- if (midic <= 0xef)
- {
- /* printk("mpu time: %d ", midic); */
- devc->m_state = ST_TIMED;
- }
- else
- printk ("<MPU: Unknown event %02x> ", midic);
+ if (midic <= 0xef) {
+ /* printf("mpu time: %d ", midic); */
+ devc->m_state = ST_TIMED;
+ } else
+ printf("<MPU: Unknown event %02x> ", midic);
}
- break;
+ break;
case ST_TIMED:
- {
- int msg = (midic & 0xf0) >> 4;
-
- devc->m_state = ST_DATABYTE;
- if (msg < 8) /* Data byte */
- {
- /* printk("midi msg (running status) "); */
- msg = (devc->last_status & 0xf0) >> 4;
- msg -= 8;
- devc->m_left = len_tab[msg] - 1;
-
- devc->m_ptr = 2;
- devc->m_buf[0] = devc->last_status;
- devc->m_buf[1] = midic;
-
- if (devc->m_left <= 0)
- {
+ {
+ int msg = ((int) (midic & 0xf0) >> 4);
+
+ devc->m_state = ST_DATABYTE;
+
+ if (msg < 8) { /* Data byte */
+ /* printf("midi msg (running status) "); */
+ msg = ((int) (devc->last_status & 0xf0) >> 4);
+ msg -= 8;
+ devc->m_left = len_tab[msg] - 1;
+
+ devc->m_ptr = 2;
+ devc->m_buf[0] = devc->last_status;
+ devc->m_buf[1] = midic;
+
+ if (devc->m_left <= 0) {
+ devc->m_state = ST_INIT;
+ do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
+ }
+ } else if (msg == 0xf) { /* MPU MARK */
devc->m_state = ST_INIT;
- do_midi_msg (devc, devc->m_buf, devc->m_ptr);
- devc->m_ptr = 0;
- }
- }
- else if (msg == 0xf) /* MPU MARK */
- {
- devc->m_state = ST_INIT;
-
- switch (midic)
- {
- case 0xf8:
- /* printk("NOP "); */
- break;
-
- case 0xf9:
- /* printk("meas end "); */
- break;
- case 0xfc:
- /* printk("data end "); */
- break;
-
- default:
- printk ("Unknown MPU mark %02x\n", midic);
- }
- }
- else
- {
- devc->last_status = midic;
- /* printk("midi msg "); */
- msg -= 8;
- devc->m_left = len_tab[msg];
-
- devc->m_ptr = 1;
- devc->m_buf[0] = midic;
-
- if (devc->m_left <= 0)
- {
- devc->m_state = ST_INIT;
- do_midi_msg (devc, devc->m_buf, devc->m_ptr);
- devc->m_ptr = 0;
- }
- }
- }
- break;
+ switch (midic) {
+ case 0xf8:
+ /* printf("NOP "); */
+ break;
+
+ case 0xf9:
+ /* printf("meas end "); */
+ break;
+
+ case 0xfc:
+ /* printf("data end "); */
+ break;
+
+ default:
+ printf("Unknown MPU mark %02x\n", midic);
+ }
+ } else {
+ devc->last_status = midic;
+ /* printf ("midi msg "); */
+ msg -= 8;
+ devc->m_left = len_tab[msg];
+
+ devc->m_ptr = 1;
+ devc->m_buf[0] = midic;
+
+ if (devc->m_left <= 0) {
+ devc->m_state = ST_INIT;
+ do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
+ }
+ }
+ }
+ break;
case ST_SYSMSG:
- switch (midic)
- {
+ switch (midic) {
case 0xf0:
- printk ("<SYX>");
- devc->m_state = ST_SYSEX;
- break;
+ printf("<SYX>");
+ devc->m_state = ST_SYSEX;
+ break;
case 0xf1:
- devc->m_state = ST_MTC;
- break;
+ devc->m_state = ST_MTC;
+ break;
case 0xf2:
- devc->m_state = ST_SONGPOS;
- devc->m_ptr = 0;
- break;
+ devc->m_state = ST_SONGPOS;
+ devc->m_ptr = 0;
+ break;
case 0xf3:
- devc->m_state = ST_SONGSEL;
- break;
+ devc->m_state = ST_SONGSEL;
+ break;
case 0xf6:
- /* printk("tune_request\n"); */
- devc->m_state = ST_INIT;
+ /* printf("tune_request\n"); */
+ devc->m_state = ST_INIT;
+ /* XXX do we need a break here ? - lr 970710 */
- /*
- * Real time messages
- */
+ /*
+ * Real time messages
+ */
case 0xf8:
- /* midi clock */
- devc->m_state = ST_INIT;
- timer_ext_event (devc, TMR_CLOCK, 0);
- break;
+ /* midi clock */
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_CLOCK, 0);
+ break;
case 0xfA:
- devc->m_state = ST_INIT;
- timer_ext_event (devc, TMR_START, 0);
- break;
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_START, 0);
+ break;
case 0xFB:
- devc->m_state = ST_INIT;
- timer_ext_event (devc, TMR_CONTINUE, 0);
- break;
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_CONTINUE, 0);
+ break;
case 0xFC:
- devc->m_state = ST_INIT;
- timer_ext_event (devc, TMR_STOP, 0);
- break;
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_STOP, 0);
+ break;
case 0xFE:
- /* active sensing */
- devc->m_state = ST_INIT;
- break;
+ /* active sensing */
+ devc->m_state = ST_INIT;
+ break;
case 0xff:
- /* printk("midi hard reset"); */
- devc->m_state = ST_INIT;
- break;
+ /* printf("midi hard reset"); */
+ devc->m_state = ST_INIT;
+ break;
default:
- printk ("unknown MIDI sysmsg %0x\n", midic);
- devc->m_state = ST_INIT;
+ printf("unknown MIDI sysmsg %0x\n", midic);
+ devc->m_state = ST_INIT;
}
- break;
+ break;
case ST_MTC:
- devc->m_state = ST_INIT;
- printk ("MTC frame %x02\n", midic);
- break;
+ devc->m_state = ST_INIT;
+ printf("MTC frame %x02\n", midic);
+ break;
case ST_SYSEX:
- if (midic == 0xf7)
- {
- printk ("<EOX>");
- devc->m_state = ST_INIT;
- }
- else
- printk ("%02x ", midic);
- break;
+ if (midic == 0xf7) {
+ printf("<EOX>");
+ devc->m_state = ST_INIT;
+ } else
+ printf("%02x ", midic);
+ break;
case ST_SONGPOS:
- BUFTEST (devc);
- devc->m_buf[devc->m_ptr++] = midic;
- if (devc->m_ptr == 2)
- {
- devc->m_state = ST_INIT;
- devc->m_ptr = 0;
- timer_ext_event (devc, TMR_SPP,
- ((devc->m_buf[1] & 0x7f) << 7) |
- (devc->m_buf[0] & 0x7f));
+ BUFTEST(devc);
+ devc->m_buf[devc->m_ptr++] = midic;
+ if (devc->m_ptr == 2) {
+ devc->m_state = ST_INIT;
+ devc->m_ptr = 0;
+ timer_ext_event(devc, TMR_SPP,
+ ((devc->m_buf[1] & 0x7f) << 7) | (devc->m_buf[0] & 0x7f));
}
- break;
+ break;
case ST_DATABYTE:
- BUFTEST (devc);
- devc->m_buf[devc->m_ptr++] = midic;
- if ((--devc->m_left) <= 0)
- {
- devc->m_state = ST_INIT;
- do_midi_msg (devc, devc->m_buf, devc->m_ptr);
- devc->m_ptr = 0;
+ BUFTEST(devc);
+ devc->m_buf[devc->m_ptr++] = midic;
+ if ((--devc->m_left) <= 0) {
+ devc->m_state = ST_INIT;
+ do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
}
- break;
+ break;
default:
- printk ("Bad state %d ", devc->m_state);
- devc->m_state = ST_INIT;
+ printf("Bad state %d ", devc->m_state);
+ devc->m_state = ST_INIT;
}
- return 1;
+ return 1;
}
static void
-mpu401_input_loop (struct mpu_config *devc)
+mpu401_input_loop(struct mpu_config * devc)
{
- unsigned long flags;
- int busy;
+ u_long flags;
+ int n, busy;
- DISABLE_INTR (flags);
- busy = devc->m_busy;
- devc->m_busy = 1;
- RESTORE_INTR (flags);
+ flags = splhigh();
+ busy = devc->m_busy;
+ devc->m_busy = 1;
+ splx(flags);
- if (busy)
- return;
+ if (busy) /* Already inside the scanner */
+ return;
- while (input_avail (devc->base))
- {
- unsigned char c = read_data (devc->base);
+ n = 50;
- if (devc->mode == MODE_SYNTH)
- {
- mpu_input_scanner (devc, c);
- }
- else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
- devc->inputintr (devc->devno, c);
+ while (input_avail(devc) && n-- > 0) {
+ u_char c = read_data(devc);
+
+ if (devc->mode == MODE_SYNTH) {
+ mpu_input_scanner(devc, c);
+ } else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
+ devc->inputintr(devc->devno, c);
}
- devc->m_busy = 0;
+ devc->m_busy = 0;
}
void
-mpuintr (int irq)
+mpuintr(int irq)
{
- struct mpu_config *devc;
- int dev;
-
-#ifdef linux
- sti ();
-#endif
+ struct mpu_config *devc;
+ int dev;
- if (irq < 1 || irq > 15)
- {
- printk ("MPU-401: Interrupt #%d?\n", irq);
- return;
- }
+ /*
+ * FreeBSD (and some others) pass unit number to the interrupt
+ * handler. In this case we have to scan the table for first handler.
+ */
- dev = irq2dev[irq];
- if (dev == -1)
- {
- printk ("MPU-401: Interrupt #%d?\n", irq);
- return;
- }
+ if (irq < 1 || irq > 15) {
+ dev = -1;
+ } else
+ dev = irq2dev[irq];
- devc = &dev_conf[dev];
+ if (dev == -1) {
+ int origirq = irq;
- if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
- if (input_avail (devc->base))
- mpu401_input_loop (devc);
+ for (irq = 0; irq <= 16; irq++)
+ if (irq2dev[irq] != -1)
+ break;
+ if (irq > 15) {
+ printf("MPU-401: Bogus interrupt #%d?\n", origirq);
+ return;
+ }
+ dev = irq2dev[irq];
+ devc = &dev_conf[dev];
+ } else
+ devc = &dev_conf[dev];
+
+ if (input_avail(devc))
+ if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
+ mpu401_input_loop(devc);
+ else {
+ /* Dummy read (just to acknowledge the interrupt) */
+ read_data(devc);
+ }
}
static int
-mpu401_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
-)
+mpu401_open(int dev, int mode,
+ void (*input) (int dev, u_char data), void (*output) (int dev))
{
- int err;
- struct mpu_config *devc;
+ int err;
+ struct mpu_config *devc;
- if (dev < 0 || dev >= num_midis)
- return RET_ERROR (ENXIO);
+ if (dev < 0 || dev >= num_midis)
+ return -(ENXIO);
- devc = &dev_conf[dev];
+ devc = &dev_conf[dev];
- if (devc->opened)
- {
- printk ("MPU-401: Midi busy\n");
- return RET_ERROR (EBUSY);
+ if (devc->opened) {
+ printf("MPU-401: Midi busy\n");
+ return -(EBUSY);
}
+ /*
+ * Verify that the device is really running. Some devices (such as
+ * Ensoniq SoundScape don't work before the on board processor (OBP)
+ * is initialized by downloadin it's microcode.
+ */
+
+ if (!devc->initialized) {
+ if (mpu401_status(devc) == 0xff) { /* Bus float */
+ printf("MPU-401: Device not initialized properly\n");
+ return -(EIO);
+ }
+ reset_mpu401(devc);
+ }
+ irq2dev[devc->irq] = dev;
- irq2dev[devc->irq] = dev;
- if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
- return err;
+ if (midi_devs[dev]->coproc)
+ if ((err = midi_devs[dev]->coproc->
+ open(midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) {
+ printf("MPU-401: Can't access coprocessor device\n");
- set_uart_mode (dev, devc, 1);
- devc->mode = MODE_MIDI;
- devc->synthno = 0;
+ return err;
+ }
+ set_uart_mode(dev, devc, 1);
+ devc->mode = MODE_MIDI;
+ devc->synthno = 0;
- mpu401_input_loop (devc);
+ mpu401_input_loop(devc);
- devc->inputintr = input;
- devc->opened = mode;
+ devc->inputintr = input;
+ devc->opened = mode;
- return 0;
+ return 0;
}
static void
-mpu401_close (int dev)
+mpu401_close(int dev)
{
- struct mpu_config *devc;
+ struct mpu_config *devc;
- devc = &dev_conf[dev];
+ devc = &dev_conf[dev];
- if (devc->uart_mode)
- reset_mpu401 (devc); /*
- * This disables the UART mode
- */
- devc->mode = 0;
+ if (devc->uart_mode)
+ reset_mpu401(devc); /* This disables the UART mode */
+ devc->mode = 0;
- snd_release_irq (devc->irq);
- devc->inputintr = NULL;
- irq2dev[devc->irq] = -1;
- devc->opened = 0;
+ devc->inputintr = NULL;
+
+ if (midi_devs[dev]->coproc)
+ midi_devs[dev]->coproc->close(midi_devs[dev]->coproc->devc, COPR_MIDI);
+ devc->opened = 0;
}
static int
-mpu401_out (int dev, unsigned char midi_byte)
+mpu401_out(int dev, u_char midi_byte)
{
- int timeout;
- unsigned long flags;
+ int timeout;
+ u_long flags;
- struct mpu_config *devc;
+ struct mpu_config *devc;
- devc = &dev_conf[dev];
+ devc = &dev_conf[dev];
-#if 0
- /*
- * Test for input since pending input seems to block the output.
- */
+ /*
+ * Sometimes it takes about 13000 loops before the output becomes
+ * ready (After reset). Normally it takes just about 10 loops.
+ */
- if (input_avail (devc->base))
- mpu401_input_loop (devc);
-#endif
- /*
- * Sometimes it takes about 13000 loops before the output becomes ready
- * (After reset). Normally it takes just about 10 loops.
- */
-
- for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--); /*
- * Wait
- */
-
- DISABLE_INTR (flags);
- if (!output_ready (devc->base))
<