Update the sound driver to VOXWARE 3.05 with one GUS patch from

Amancio.  There is some SoundSource support here that is primitive and
probably doesn't work, but I'll let the two submitters let me know
how my integration of that was since I don't have this card to test.
I've only tested this on my GUS MAX since it's all I have.

This all probably needs to be re-done anyway since we're widely variant
from the original VOXWARE source in the current layout.
Submitted by:	Amancio Hasty and Jim Lowe
Obtained from:  Hannu Savolainen
This commit is contained in:
Jordan K. Hubbard 1995-07-28 21:40:49 +00:00
parent 1c8fc26cb0
commit ae28ee13b4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=9748
60 changed files with 7520 additions and 1793 deletions

View file

@ -1,10 +1,22 @@
Changelog for version 2.90
Changelog for version 3.0-950506
------------------------------------
This is an intermediate release (v3.0 prototype with some experimental
features disabled). See experimental.txt for more info.
Since 3.0-94xxxx
- Too many changes
Since pre-3.0-949712
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

View file

@ -0,0 +1,6 @@
Informations about Audio Excel DSP 16 can be found in the source
file aedsp16.c
Please, read the head of the source before using it. It contain useful
informations.
Riccardo

View file

@ -0,0 +1,87 @@
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)

View file

@ -1,38 +1,26 @@
VoxWare v3.0
------------
This is a PROTOTYPE of the VoxWare v3.0 to be released late 94.
This is a late alpha/early beta of the VoxWare v3.0 to be relased May/June 95.
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 +55,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 +83,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 +101,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 +118,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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,130 @@
/*
* sound/ad1848_mixer.h
*
* Definitions for the mixer of AD1848 and compatible codecs.
*
* Copyright by Hannu Savolainen 1994
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. 2.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* The AD1848 codec has generic input lines called Line, Aux1 and Aux2.
* Soundcard manufacturers have connected actual inputs (CD, synth, line,
* etc) to these inputs in different order. Therefore it's difficult
* to assign mixer channels to to these inputs correctly. The following
* contains two alternative mappings. The first one is for GUS MAX and
* the second is just a generic one (line1, line2 and line3).
* (Actually this is not a mapping but rather some kind of interleaving
* solution).
*/
#ifdef GUSMAX_MIXER
#define MODE1_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD)
#define MODE1_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_MIC | \
SOUND_MASK_CD | \
SOUND_MASK_IGAIN | \
SOUND_MASK_PCM|SOUND_MASK_IMIX)
#define MODE2_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD | SOUND_MASK_SPEAKER | \
SOUND_MASK_IGAIN | \
SOUND_MASK_PCM | SOUND_MASK_IMIX)
#else /* Generic mapping */
#define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \
SOUND_MASK_LINE1)
#define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \
SOUND_MASK_LINE2 | \
SOUND_MASK_IGAIN | \
SOUND_MASK_PCM | SOUND_MASK_IMIX)
#define MODE2_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_MIC | \
SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \
SOUND_MASK_IGAIN | \
SOUND_MASK_PCM | SOUND_MASK_IMIX)
#endif
struct mixer_def {
unsigned int regno: 7;
unsigned int polarity:1; /* 0=normal, 1=reversed */
unsigned int bitpos:4;
unsigned int nbits:4;
};
typedef struct mixer_def mixer_ent;
/*
* Most of the mixer entries work in backwards. Setting the polarity field
* makes them to work correctly.
*
* The channel numbering used by individual soundcards is not fixed. Some
* cards have assigned different meanings for the AUX1, AUX2 and LINE inputs.
* The current version doesn't try to compensate this.
*/
#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}}
mixer_ent mix_devices[32][2] = { /* As used in GUS MAX */
MIX_ENT(SOUND_MIXER_VOLUME, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0),
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_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),
MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4),
MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5),
MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5),
MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5)
};
static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] =
{
0x5a5a, /* Master Volume */
0x3232, /* Bass */
0x3232, /* Treble */
0x4b4b, /* FM */
0x6464, /* PCM */
0x4b4b, /* PC Speaker */
0x4b4b, /* Ext Line */
0x1010, /* Mic */
0x4b4b, /* CD */
0x0000, /* Recording monitor */
0x4b4b, /* SB PCM */
0x4b4b, /* Recording level */
0x4b4b, /* Input gain */
0x4b4b, /* Output gain */
0x4b4b, /* Line1 */
0x4b4b, /* Line2 */
0x4b4b /* Line3 */
};
#define LEFT_CHN 0
#define RIGHT_CHN 1

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ad1848.c,v 1.3 1994/10/01 05:46:01 davidg Exp
*/
#include "sound_config.h"

View file

@ -0,0 +1,838 @@
/*
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 */

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* audio.c,v 1.6 1994/10/01 02:16:29 swallace Exp
*/
#include "sound_config.h"
@ -34,11 +33,13 @@
#ifndef EXCLUDE_AUDIO
#include "ulaw.h"
#include "coproc.h"
#define ON 1
#define OFF 0
static int wr_buff_no[MAX_AUDIO_DEV]; /*
* != -1, if there is
* a incomplete output
* block in the queue.
@ -46,6 +47,7 @@ static int wr_buff_no[MAX_AUDIO_DEV]; /*
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
@ -99,6 +101,16 @@ audio_open (int dev, struct fileinfo *file)
if ((ret = DMAbuf_open (dev, mode)) < 0)
return ret;
if (audio_devs[dev]->coproc)
if ((ret = audio_devs[dev]->coproc->
open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
{
audio_release (dev, file);
printk ("Sound: Can't access coprocessor device\n");
return ret;
}
local_conversion[dev] = 0;
if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
@ -116,6 +128,8 @@ audio_open (int dev, struct fileinfo *file)
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;
}
@ -135,6 +149,8 @@ audio_release (int dev, struct fileinfo *file)
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);
}
@ -156,9 +172,9 @@ translate_bytes (const void *table, void *buff, unsigned long 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");
"loop 1b\n\t":
: "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
: "bx", "cx", "di", "si", "ax");
}
#endif
@ -204,8 +220,17 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
* There is no incomplete buffers
*/
{
if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev],
&wr_buff_size[dev],
dev_nblock[dev])) < 0)
{
/* Handle nonblocking mode */
#if defined(__FreeBSD__)
if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EWOULDBLOCK))
#else
if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EAGAIN))
#endif
return p; /* No more space. Return # of accepted bytes */
return wr_buff_no[dev];
}
wr_buff_ptr[dev] = 0;
@ -285,8 +310,20 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
while (c)
{
if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
return buff_no;
if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l,
dev_nblock[dev])) < 0)
{
/* Nonblocking mode handling. Return current # of bytes */
#if defined(__FreeBSD__)
if (dev_nblock[dev] && buff_no == RET_ERROR (EWOULDBLOCK))
#else
if (dev_nblock[dev] && buff_no == RET_ERROR (EAGAIN))
#endif
return p;
return buff_no;
}
if (l > c)
l = c;
@ -325,56 +362,151 @@ audio_ioctl (int dev, struct fileinfo *file,
dev = dev >> 4;
switch (cmd)
if (((cmd >> 8) & 0xff) == 'C')
{
case SNDCTL_DSP_SYNC:
if (wr_buff_no[dev] >= 0)
{
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
if (audio_devs[dev]->coproc) /* Coprocessor ioctl */
return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0);
else
printk ("/dev/dsp%d: No coprocessor for this device\n", dev);
wr_buff_no[dev] = -1;
}
return DMAbuf_ioctl (dev, cmd, arg, 0);
break;
case SNDCTL_DSP_POST:
if (wr_buff_no[dev] >= 0)
{
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
wr_buff_no[dev] = -1;
}
return 0;
break;
case SNDCTL_DSP_RESET:
wr_buff_no[dev] = -1;
return DMAbuf_ioctl (dev, cmd, arg, 0);
break;
case SNDCTL_DSP_GETFMTS:
return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
break;
case SNDCTL_DSP_SETFMT:
return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
default:
return DMAbuf_ioctl (dev, cmd, arg, 0);
break;
return RET_ERROR (EREMOTEIO);
}
else
switch (cmd)
{
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;
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;
case SNDCTL_DSP_RESET:
wr_buff_no[dev] = -1;
return DMAbuf_ioctl (dev, cmd, arg, 0);
break;
case SNDCTL_DSP_GETFMTS:
return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
break;
case SNDCTL_DSP_SETFMT:
return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
case SNDCTL_DSP_GETISPACE:
if (audio_mode[dev] == AM_WRITE)
return RET_ERROR (EBUSY);
{
audio_buf_info info;
int err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1);
if (err < 0)
return err;
if (wr_buff_no[dev] != -1)
info.bytes += wr_buff_ptr[dev];
IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info));
return 0;
}
case SNDCTL_DSP_GETOSPACE:
if (audio_mode[dev] == AM_READ)
return RET_ERROR (EBUSY);
{
audio_buf_info info;
int err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1);
if (err < 0)
return err;
if (wr_buff_no[dev] != -1)
info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev];
IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info));
return 0;
}
case SNDCTL_DSP_NONBLOCK:
dev_nblock[dev] = 1;
return 0;
break;
default:
return DMAbuf_ioctl (dev, cmd, arg, 0);
}
}
long
audio_init (long mem_start)
{
/*
* NOTE! This routine could be called several times during boot.
*/
* NOTE! This routine could be called several times during boot.
*/
return mem_start;
}
#else
#ifdef ALLOW_SELECT
int
audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
int l;
char *dmabuf;
dev = dev >> 4;
switch (sel_type)
{
case SEL_IN:
if (audio_mode[dev] != AM_READ && /* Wrong direction */
audio_mode[dev] != AM_NONE)
return 0;
if (DMAbuf_getrdbuffer (dev, &dmabuf, &l,
1 /* Don't block */ ) >= 0)
return 1; /* We have data */
return DMAbuf_select (dev, file, sel_type, wait);
break;
case SEL_OUT:
if (audio_mode[dev] != AM_WRITE && /* Wrong direction */
audio_mode[dev] != AM_NONE)
return 0;
if (wr_buff_no[dev] != -1)
return 1; /* There is space in the current buffer */
return DMAbuf_select (dev, file, sel_type, wait);
break;
case SEL_EX:
return 0;
}
return 0;
}
#endif /* ALLOW_SELECT */
#else /* EXCLUDE_AUDIO */
/*
* Stub versions
*/

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* dev_table.c,v 1.6 1994/10/01 02:16:31 swallace Exp
*/
#define _DEV_TABLE_C_
@ -53,6 +52,8 @@ sndtable_init (long mem_start)
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
int drv;
printk ("Sound initialization started\n");
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)
@ -78,55 +79,20 @@ sndtable_init (long mem_start)
snd_installed_cards[i].enabled = 0; /*
* Mark as not detected
*/
printk ("Sound initialization complete\n");
return mem_start;
}
int
sndtable_probe (int unit, struct address_info *hw_config)
{
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
{
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
if (!unit)
return TRUE;
if (!unit)
return TRUE;
for (i = 0; i < (n - 1); i++)
if (snd_installed_cards[i].enabled)
if (snd_installed_cards[i].card_type == unit)
{
int drv;
snd_installed_cards[i].config.io_base = hw_config->io_base;
snd_installed_cards[i].config.irq = hw_config->irq;
snd_installed_cards[i].config.dma = hw_config->dma;
if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
snd_installed_cards[i].enabled = 0; /*
* Mark as not
* detected
*/
else if (sound_drivers[drv].probe (hw_config))
return 1;
snd_installed_cards[i].enabled = 0; /*
* Mark as not detected
*/
return 0;
}
return FALSE;
}
int
sndtable_init_card (int unit, struct address_info *hw_config)
{
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
if (!unit)
{
if (sndtable_init (0) != 0)
panic ("snd: Invalid memory allocation");
return TRUE;
}
for (i = 0; i < (n - 1); i++)
for (i = 0; i < (n - 1); i++)
if (snd_installed_cards[i].enabled)
if (snd_installed_cards[i].card_type == unit)
{
int drv;
@ -134,18 +100,54 @@ sndtable_init_card (int unit, struct address_info *hw_config)
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; /*
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
*/
else if (sound_drivers[drv].attach (0, hw_config) != 0)
panic ("snd#: Invalid memory allocation");
return TRUE;
return 0;
}
return FALSE;
}
return FALSE;
}
int
sndtable_init_card (int unit, struct address_info *hw_config)
{
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
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;
}
return FALSE;
}
int
sndtable_get_cardcount (void)
@ -160,8 +162,8 @@ sound_setup (char *str, int *ints)
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
/*
* First disable all drivers
*/
* First disable all drivers
*/
for (i = 0; i < n; i++)
snd_installed_cards[i].enabled = 0;
@ -169,8 +171,8 @@ sound_setup (char *str, int *ints)
if (ints[0] == 0 || ints[1] == 0)
return;
/*
* Then enable them one by time
*/
* Then enable them one by time
*/
for (i = 1; i <= ints[0]; i++)
{

View file

@ -2,7 +2,7 @@
* 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
@ -26,8 +26,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: dev_table.h,v 1.13 1995/03/28 07:56:11 bde Exp $
*/
*/
#ifndef _DEV_TABLE_H_
#define _DEV_TABLE_H_
@ -107,6 +107,20 @@ struct dma_buffparms {
int underrun_count;
};
/*
* 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, unsigned int cmd, unsigned int arg, int local);
void (*reset) (void *devc);
void *devc; /* Driver specific info */
} coproc_operations;
struct audio_operations {
char name[32];
int flags;
@ -117,9 +131,9 @@ struct audio_operations {
void *devc; /* Driver specific info */
int (*open) (int dev, int mode);
void (*close) (int dev);
void (*output_block) (int dev, unsigned long buf,
void (*output_block) (int dev, unsigned long buf,
int count, int intrflag, int dma_restart);
void (*start_input) (int dev, unsigned long buf,
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);
@ -133,9 +147,12 @@ struct audio_operations {
long buffsize;
int dmachan;
struct dma_buffparms *dmap;
struct coproc_operations *coproc;
int mixer_dev;
};
struct mixer_operations {
char name[32];
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
};
@ -162,14 +179,29 @@ struct synth_operations {
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);
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;
struct midi_input_info in_info;
int (*open) (int dev, int mode,
void (*inputintr)(int dev, unsigned char data),
void (*outputintr)(int dev)
@ -183,6 +215,7 @@ struct midi_operations {
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_timer_operations {
@ -197,7 +230,7 @@ struct sound_timer_operations {
void (*arm_timer)(int dev, long time);
};
#ifdef _DEV_TABLE_C_
#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;
@ -205,12 +238,12 @@ struct sound_timer_operations {
#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};
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};
struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] =
{NULL};
int num_sound_timers = 0;
#endif
@ -221,6 +254,12 @@ struct sound_timer_operations {
struct driver_info sound_drivers[] = {
#ifndef EXCLUDE_PSS
{SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss},
# ifdef PSS_MPU_BASE
{SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu},
# endif
# ifdef PSS_MSS_BASE
{SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss},
# endif
#endif
#ifndef EXCLUDE_YM3812
{SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib},
@ -237,11 +276,11 @@ struct sound_timer_operations {
#ifndef EXCLUDE_SB
{SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb},
#endif
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
#ifndef EXCLUDE_AUDIO
{SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect},
#endif
#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_SB16MIDI)
#ifndef EXCLUDE_MIDI
{SNDCARD_SB16MIDI,"SB16 MIDI", attach_sb16midi, probe_sb16midi},
#endif
#endif
@ -253,10 +292,20 @@ struct sound_timer_operations {
#endif
#ifndef EXCLUDE_GUS
{SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus},
#endif
#ifndef EXCLUDE_SSCAPE
{SNDCARD_SSCAPE, "Ensoniq Soundscape", attach_sscape, probe_sscape},
{SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound},
#endif
#ifndef EXCLUDE_TRIX
{SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro", attach_trix_wss, probe_trix_wss},
{SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)", attach_trix_sb, probe_trix_sb},
{SNDCARD_TRXPRO_MPU, "AudioTriX MIDI", attach_trix_mpu, probe_trix_mpu},
#endif
{0, "*?*", NULL, NULL}
};
#if defined(linux) || defined(__FreeBSD__)
/*
* List of devices actually configured in the system.
*
@ -266,7 +315,42 @@ struct sound_timer_operations {
struct card_info snd_installed_cards[] = {
#ifndef EXCLUDE_PSS
{SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE},
# ifdef PSS_MPU_BASE
{SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
# endif
# ifdef PSS_MSS_BASE
{SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA}, SND_DEFAULT_ENABLE},
# endif
#endif
#ifndef EXCLUDE_TRIX
{SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA}, SND_DEFAULT_ENABLE},
# ifdef TRIX_SB_BASE
{SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA}, SND_DEFAULT_ENABLE},
# endif
# ifdef TRIX_MPU_BASE
{SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
# endif
#endif
#ifndef EXCLUDE_SSCAPE
{SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA}, SND_DEFAULT_ENABLE},
{SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA}, 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
#ifndef EXCLUDE_PAS
{SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_SB
{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
#endif
#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
{SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
#ifdef MPU2_BASE
@ -276,25 +360,11 @@ struct sound_timer_operations {
{SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
#endif
#endif
#ifndef EXCLUDE_MSS
{SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE},
# ifdef MSS2_BASE
{SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA}, SND_DEFAULT_ENABLE},
# endif
#endif
#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
{SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_PAS
{SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_SB
{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
#endif
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
#ifndef EXCLUDE_AUDIO
{SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
@ -306,9 +376,9 @@ struct sound_timer_operations {
#ifndef EXCLUDE_GUS
#ifndef EXCLUDE_GUS16
{SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA}, SND_DEFAULT_ENABLE},
{SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, GUS_DMA_READ}, SND_DEFAULT_ENABLE},
#endif
{SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
{SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA_READ}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_YM3812
@ -317,11 +387,15 @@ struct sound_timer_operations {
{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);
#else
int num_sound_cards = 0;
#endif /* linux */
int num_sound_drivers =
sizeof(sound_drivers) / sizeof (struct driver_info);
#else
extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs;
@ -335,9 +409,9 @@ struct sound_timer_operations {
extern struct card_info snd_installed_cards[];
extern int num_sound_cards;
long sndtable_init(long mem_start);
int sndtable_probe(int unit, struct address_info *hw_config);
int sndtable_init_card(int unit, struct address_info *hw_config);
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);

View file

@ -3,7 +3,7 @@
*
* 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
@ -25,29 +25,24 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: dmabuf.c,v 1.15 1995/05/07 06:38:47 pst Exp $
*/
#include "sound_config.h"
#ifdef CONFIGURE_SOUNDCARD
#include "sound_calls.h"
#ifdef __FreeBSD__
#include <machine/soundcard.h>
extern struct selinfo selinfo[SND_NDEVS>>4];
#endif
#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
{0}; /*
* Primitive way to allocate
* such a large array.
* Needs dynamic run-time alloction.
*/
{
{0}}; /*
* Primitive way to allocate
* such a large array.
* Needs dynamic run-time alloction.
*/
static void
reorganize_buffers (int dev)
@ -83,10 +78,10 @@ reorganize_buffers (int dev)
sz = sr * nc * sz;
/*
* 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).
*/
* 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)
@ -111,9 +106,9 @@ reorganize_buffers (int dev)
else
{
/*
* The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
* the buffer sice computation has already been done.
*/
* 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;
@ -162,7 +157,6 @@ dma_init_buffers (int 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;
}
@ -255,7 +249,7 @@ dma_sync (int dev)
/*
* 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.
* audio data. We have to wait until the device has finished playing.
*/
DISABLE_INTR (flags);
@ -300,9 +294,10 @@ DMAbuf_release (int dev, int mode)
}
int
DMAbuf_start_input(int dev)
DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
{
unsigned long flags;
int err = EIO;
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
DISABLE_INTR (flags);
@ -324,7 +319,7 @@ DMAbuf_start_input(int dev)
if (!(dmap->flags & DMA_ALLOC_DONE))
reorganize_buffers (dev);
if (dmap->dma_mode)
if (!dmap->dma_mode)
{
int err;
@ -345,32 +340,24 @@ DMAbuf_start_input(int dev)
!(dmap->flags & DMA_STARTED));
dmap->flags |= DMA_ACTIVE | DMA_STARTED;
}
}
RESTORE_INTR (flags);
return 0;
}
int
DMAbuf_getrdbuffer (int dev, char **buf, int *len)
{
unsigned long flags;
int err = EIO;
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
DISABLE_INTR (flags);
if (!dmap->qlen)
{
if(err = DMAbuf_start_input(dev))
return err;
if (dontblock)
{
RESTORE_INTR (flags);
#if defined(__FreeBSD__)
return RET_ERROR (EWOULDBLOCK);
#else
return RET_ERROR (EAGAIN);
#endif
}
/* Wait for the next block */
err = EIO;
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
@ -436,15 +423,15 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
case SNDCTL_DSP_SETBLKSIZE:
{
int size = IOCTL_IN (arg);
int size = IOCTL_IN(arg);
if(!(dmap->flags & DMA_ALLOC_DONE) && size)
{
dmap->fragment_size = size;
return 0;
dmap->fragment_size = size;
return 0;
}
else
return RET_ERROR (EINVAL); /* Too late to change */
return RET_ERROR (EINVAL); /* Too late to change */
}
break;
@ -461,7 +448,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
}
if (dmap->subdivision != 0 ||
dmap->fragment_size)/* Loo late to change */
dmap->fragment_size) /* Loo late to change */
return RET_ERROR (EINVAL);
if (fact > MAX_REALTIME_FACTOR)
@ -484,7 +471,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
return RET_ERROR (EIO);
if (dmap->subdivision != 0 ||
dmap->fragment_size)/* Loo late to change */
dmap->fragment_size) /* Loo late to change */
return RET_ERROR (EINVAL);
bytes = fact & 0xffff;
@ -514,12 +501,24 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
}
break;
case SNDCTL_DSP_GETISPACE:
case SNDCTL_DSP_GETOSPACE:
if (!local)
return RET_ERROR (EINVAL);
{
audio_buf_info *info = (audio_buf_info *) arg;
info->fragments = dmap->qlen;
info->fragsize = dmap->fragment_size;
info->bytes = dmap->qlen * dmap->fragment_size;
}
return 0;
default:
return audio_devs[dev]->ioctl (dev, cmd, arg, local);
}
/* NOTREACHED */
return RET_ERROR (EIO);
}
static int
@ -528,13 +527,13 @@ 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 */
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.
*/
* Verify that there are no more pending buffers than the limit
* defined by the process.
*/
max = dmap->max_fragments;
len = dmap->qlen;
@ -544,8 +543,8 @@ space_in_queue (int dev)
tmp = audio_devs[dev]->local_qlen (dev);
if (tmp & len)
tmp--; /*
* This buffer has been counted twice
*/
* This buffer has been counted twice
*/
len += tmp;
}
@ -555,7 +554,7 @@ space_in_queue (int dev)
}
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;
@ -588,6 +587,13 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size)
}
if (dontblock)
#if defined(__FreeBSD__)
return RET_ERROR (EWOULDBLOCK);
#else
return RET_ERROR (EAGAIN);
#endif
DISABLE_INTR (flags);
abort = 0;
@ -692,28 +698,41 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
set_dma_count (chan, dmap->bytes_in_use);
enable_dma (chan);
RESTORE_INTR (flags);
#else /* linux */
#ifdef __FreeBSD__
isa_dmastart (B_RAW + ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE),
#else
#if defined(__FreeBSD__)
isa_dmastart (B_RAW + (dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
(caddr_t)dmap->raw_buf_phys[0],
dmap->bytes_in_use,
chan);
#else /* __FreeBSD__ */
#else /* else __FreeBSD__ */
#if defined(GENERIC_SYSV)
#ifndef DMAMODE_AUTO
printk ("sound: Invalid DMA mode for device %d\n", dev);
#endif /* DMAMODE_AUTO */
#endif
#if defined(SVR42)
/*
** send full count to snd_dma_prog, it will take care of subtracting
** one if it is required.
*/
snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use,
dma_mode, TRUE);
#else /* !SVR42 */
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
#ifdef DMAMODE_AUTO
| DMAMODE_AUTO
#endif /* DMAMODE_AUTO */
#endif
,
dmap->raw_buf_phys[0], dmap->bytes_in_use);
dmap->raw_buf_phys[0], dmap->bytes_in_use - 1);
dma_enable (chan);
#else /* GENERIC_SYSV */
#endif /* ! SVR42 */
#else
#error This routine is not valid for this OS.
#endif /* __FreeBSD__ */
#endif /* linux */
#endif
#endif
#endif
}
@ -728,24 +747,30 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
set_dma_count (chan, count);
enable_dma (chan);
RESTORE_INTR (flags);
#else /* linux */
#ifdef __FreeBSD__
#else
#if defined(__FreeBSD__)
isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
(caddr_t)physaddr,
count,
chan);
#else /* __FreeBSD__ */
#else /* FreeBSD */
#if defined(GENERIC_SYSV)
#if defined(SVR42)
snd_dma_prog (chan, physaddr, count, dma_mode, FALSE);
#else /* ! SVR42 */
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
physaddr, count);
dma_enable (chan);
#else /* GENERIC_SYSV */
#endif /* SVR42 */
#else
#error This routine is not valid for this OS.
#endif /* GENERIC_SYSV */
#endif /* __FreeBSD */
#endif
#endif /* linux */
#endif
}
return count;
@ -756,9 +781,13 @@ DMAbuf_init (long mem_start)
{
int dev;
#if defined(SVR42)
snd_dma_init ();
#endif /* SVR42 */
/*
* NOTE! This routine could be called several times.
*/
* NOTE! This routine could be called several times.
*/
for (dev = 0; dev < num_audiodevs; dev++)
audio_devs[dev]->dmap = &dmaps[dev];
@ -769,18 +798,22 @@ 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.
*/
* Event types:
* 0 = DMA transfer done. Device still has more data in the local
* buffer.
* 1 = DMA transfer done. Device doesn't have local buffer or it's
* empty now.
* 2 = No DMA transfer but the device has now more space in it's local
* buffer.
*/
unsigned long flags;
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
#if defined(SVR42)
snd_dma_intr (audio_devs[dev]->dmachan);
#endif /* SVR42 */
if (event_type != 2)
{
if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
@ -819,7 +852,7 @@ DMAbuf_outputintr (int dev, int event_type)
WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
}
RESTORE_INTR (flags);
#ifdef __FreeBSD__
#if defined(__FreeBSD__)
if(selinfo[dev].si_pid)
selwakeup(&selinfo[dev]);
#endif
@ -831,6 +864,10 @@ DMAbuf_inputintr (int dev)
unsigned long flags;
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
#if defined(SVR42)
snd_dma_intr (audio_devs[dev]->dmachan);
#endif /* SVR42 */
if (dmap->qlen == (dmap->nbufs - 1))
{
printk ("Sound: Recording overrun\n");
@ -862,7 +899,7 @@ DMAbuf_inputintr (int dev)
WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
}
RESTORE_INTR (flags);
#ifdef __FreeBSD__
#if defined(__FreeBSD__)
if(selinfo[dev].si_pid)
selwakeup(&selinfo[dev]);
#endif
@ -874,7 +911,7 @@ DMAbuf_open_dma (int dev)
unsigned long flags;
int chan = audio_devs[dev]->dmachan;
if (ALLOC_DMA_CHN (chan))
if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name))
{
printk ("Unable to grab DMA%d for the audio driver\n", chan);
return RET_ERROR (EBUSY);
@ -895,67 +932,80 @@ DMAbuf_close_dma (int dev)
{
int chan = audio_devs[dev]->dmachan;
DMAbuf_reset_dma (chan);
DMAbuf_reset_dma (dev);
RELEASE_DMA_CHN (chan);
}
void
DMAbuf_reset_dma (int chan)
DMAbuf_reset_dma (int dev)
{
#if 0
int chan = audio_devs[dev]->dmachan;
disable_dma (chan);
#endif
}
/*
* Used by unix select system call to see if data is ready.
*/
#ifdef ALLOW_SELECT
int
DMAbuf_output_ready(int dev)
DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
unsigned long flags;
if (!(dmap->flags & DMA_ALLOC_DONE))
reorganize_buffers (dev);
return space_in_queue (dev);
}
int
DMAbuf_input_ready(int dev)
{
int h,i,r;
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
r = 0;
if(dmap->qlen)
switch (sel_type)
{
if(dmap->fragment_size)
{
for(i=0; i<dmap->qlen; i++)
{
h = (dmap->qhead + i) % dmap->nbufs;
r += dmap->fragment_size - dmap->counts[h];
if(r >= dmap->fragment_size)
break;
}
if(r < dmap->fragment_size)
r = 0;
else
r = 1;
}
else
r = 1;
}
else
DMAbuf_start_input(dev);
return(r);
}
/*
* 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.
*/
case SEL_IN:
if (dmap->dma_mode != DMODE_INPUT)
return 0;
if (!dmap->qlen)
{
DISABLE_INTR (flags);
#if defined(__FreeBSD__)
selrecord(wait, &selinfo[dev]);
#else
dev_sleep_flag[dev].mode = WK_SLEEP;
select_wait (&dev_sleeper[dev], wait);
#endif
RESTORE_INTR (flags);
return 0;
}
return 1;
break;
case SEL_OUT:
if (dmap->dma_mode == DMODE_INPUT)
return 0;
if (dmap->dma_mode == DMODE_NONE)
return 1;
if (!space_in_queue (dev))
{
DISABLE_INTR (flags);
#if defined(__FreeBSD__)
selrecord(wait, &selinfo[dev]);
#else
dev_sleep_flag[dev].mode = WK_SLEEP;
select_wait (&dev_sleeper[dev], wait);
#endif
RESTORE_INTR (flags);
return 0;
}
return 1;
break;
case SEL_EX:
return 0;
}
return 0;
}
#endif /* ALLOW_SELECT */
#else /* EXCLUDE_AUDIO */
/*
* Stub versions if audio services not included
*/
@ -973,31 +1023,13 @@ DMAbuf_release (int dev, int mode)
}
int
DMAbuf_start_input (int dev)
DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
{
return RET_ERROR (EIO);
}
int
DMAbuf_input_ready (int dev)
{
return 0;
}
int
DMAbuf_output_ready (int dev)
{
return 0;
}
int
DMAbuf_getwrbuffer (int dev, char **buf, int *size)
{
return RET_ERROR (EIO);
}
int
DMAbuf_getrdbuffer (int dev, char **buf, int *len)
DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
{
return RET_ERROR (EIO);
}
@ -1033,19 +1065,19 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
}
int
DMAbuf_open_dma (int chan)
DMAbuf_open_dma (int dev)
{
return RET_ERROR (ENXIO);
}
void
DMAbuf_close_dma (int chan)
DMAbuf_close_dma (int dev)
{
return;
}
void
DMAbuf_reset_dma (int chan)
DMAbuf_reset_dma (int dev)
{
return;
}

View file

@ -23,26 +23,25 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* finetune.h,v 1.3 1994/08/02 07:39:51 davidg Exp
*/
unsigned short finetune_table[128] =
{
/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499,
/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567,
/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637,
/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707,
/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777,
/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848,
/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919,
/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991,
/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063,
/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136,
/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210,
/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284,
/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358,
/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433,
/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509,
/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499,
/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567,
/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637,
/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707,
/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777,
/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848,
/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919,
/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991,
/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063,
/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136,
/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210,
/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284,
/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358,
/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433,
/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509,
/* 120 */ 10518, 10528, 10537, 10547, 10556, 10566, 10576, 10585
};
#else

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* gus_card.c,v 1.11 1994/10/14 09:04:19 jkh Exp
*/
#include "sound_config.h"
@ -44,13 +43,14 @@ attach_gus_card (long mem_start, struct address_info *hw_config)
{
int io_addr;
snd_set_irq_handler (hw_config->irq, gusintr);
snd_set_irq_handler (hw_config->irq, gusintr, "Gravis Ultrasound");
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);
mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma,
hw_config->dma_read);
#ifndef EXCLUDE_MIDI
mem_start = gus_midi_init (mem_start);
#endif
@ -73,7 +73,8 @@ attach_gus_card (long mem_start, struct address_info *hw_config)
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);
mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma,
hw_config->dma_read);
#ifndef EXCLUDE_MIDI
mem_start = gus_midi_init (mem_start);
#endif
@ -117,7 +118,7 @@ probe_gus (struct address_info *hw_config)
}
void
gusintr (int irq)
gusintr (INT_HANDLER_PARMS (irq, dummy))
{
unsigned char src;
@ -127,7 +128,11 @@ gusintr (int irq)
#ifndef EXCLUDE_GUSMAX
if (have_gus_max)
adintr (irq);
# if defined(__FreeBSD__)
ad1848_interrupt (INT_HANDLER_CALL (gus_irq));
# else
ad1848_interrupt (INT_HANDLER_CALL (irq));
# endif
#endif
while (1)
@ -168,7 +173,7 @@ gusintr (int irq)
/*
* Some extra code for the 16 bit sampling option
*/
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16) && !defined(EXCLUDE_GUS)
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16)
int
probe_gus_db16 (struct address_info *hw_config)
@ -182,7 +187,7 @@ attach_gus_db16 (long mem_start, struct address_info *hw_config)
gus_pcm_volume = 100;
gus_wave_volume = 90;
ad1848_init ("gusxvi0: <GUS 16 bit sampling>", hw_config->io_base,
ad1848_init ("GUS 16 bit sampling", hw_config->io_base,
hw_config->irq,
hw_config->dma,
hw_config->dma);

View file

@ -1,6 +1,4 @@
/*
* gus_hw.h,v 1.3 1994/08/02 07:39:54 davidg Exp
*/
/*
* I/O addresses
*/

View file

@ -1,6 +1,3 @@
/*
* gus_linearvol.h,v 1.2 1994/08/02 07:39:57 davidg Exp
*/
static unsigned short gus_linearvol[128] = {
0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* gus_midi.c,v 1.6 1994/10/01 02:16:39 swallace Exp
*/
#include "sound_config.h"
@ -232,6 +231,7 @@ static struct midi_operations gus_midi_operations =
{
{"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
&std_midi_synth,
{0},
gus_midi_open,
gus_midi_close,
gus_midi_ioctl,
@ -297,10 +297,12 @@ gus_midi_interrupt (int dummy)
}
}
#if 0
if (stat & MIDI_FRAME_ERR)
printk ("Midi framing error\n");
printk ("GUS: Midi framing error\n");
if (stat & MIDI_OVERRUN && input_opened)
printk ("GUS: Midi input overrun\n");
#endif
RESTORE_INTR (flags);
}

View file

@ -2,8 +2,6 @@
* gus_vol.c - Compute volume for GUS.
*
* Greg Lee 1993.
*
* gus_vol.c,v 1.5 1994/10/01 02:16:40 swallace Exp
*/
#include "sound_config.h"
#ifndef EXCLUDE_GUS

View file

@ -25,19 +25,15 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: gus_wave.c,v 1.14 1995/03/12 23:33:52 swallace Exp $
*/
#include "sound_config.h"
#include <machine/ultrasound.h>
#include "ultrasound.h"
#include "gus_hw.h"
#undef OUTB
#define OUTB(val, port) outb(port, val)
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
#define MAX_SAMPLE 128
#define MAX_SAMPLE 150
#define MAX_PATCH 256
struct voice_info
@ -82,12 +78,14 @@ extern int gus_base;
extern int gus_irq, gus_dma;
static long gus_mem_size = 0;
static long free_mem_ptr = 0;
static int gus_busy = 0;
int gus_busy[MAX_AUDIO_DEV], gus_dspnum=0;
static int gus_dma_read=0;
static int nr_voices = 0;
static int gus_devnum = 0;
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;
int gus_wave_volume = 60;
int gus_pcm_volume = 80;
@ -478,10 +476,12 @@ gus_voice_init (int voice)
DISABLE_INTR (flags);
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;
RESTORE_INTR (flags);
}
@ -676,7 +676,7 @@ gus_initialize (void)
unsigned char dma_image, irq_image, tmp;
static unsigned char gus_irq_map[16] =
{0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
{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};
@ -744,7 +744,14 @@ gus_initialize (void)
irq_image |= tmp;
irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
dma_image = gus_dma_map[gus_dma_read] << 3;
if(!dma_image)
printk ("Warning! GUS DMA read channel not selected.\n");
if(gus_dma_read == gus_dma)
{
dma_image = 0x40; /* dual dma inhibited
Combine DMA1 (DRAM) and IRQ2 (ADC) */
}
tmp = gus_dma_map[gus_dma];
if (!tmp)
printk ("Warning! GUS DMA not selected\n");
@ -785,7 +792,7 @@ gus_initialize (void)
gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
gusintr (0); /* Serve pending interrupts */
gusintr (INT_HANDLER_CALL (0)); /* Serve pending interrupts */
RESTORE_INTR (flags);
}
@ -892,7 +899,7 @@ guswave_set_instr (int dev, int voice, int instr_no)
if (sample_no < 0)
{
printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
return RET_ERROR (EINVAL);/* Patch not defined */
return RET_ERROR (EINVAL); /* Patch not defined */
}
if (sample_ptrs[sample_no] == -1) /* Sample not loaded */
@ -913,7 +920,7 @@ guswave_kill_note (int dev, int voice, int note, int velocity)
unsigned long flags;
DISABLE_INTR (flags);
voice_alloc->map[voice] = 0xffff;
/* voice_alloc->map[voice] = 0xffff; */
if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
{
voices[voice].kill_pending = 1;
@ -925,17 +932,17 @@ guswave_kill_note (int dev, int voice, int note, int velocity)
gus_voice_fade (voice);
}
RESTORE_INTR (flags);
return 0;
}
static void
guswave_aftertouch (int dev, int voice, int pressure)
{
#if 0
short lo_limit, hi_limit;
unsigned long flags;
return; /* Procedure currently disabled */
if (voice < 0 || voice > 31)
return;
@ -968,6 +975,7 @@ guswave_aftertouch (int dev, int voice, int pressure)
gus_ramp_rate (3, 8);
gus_rampon (0x58); /* Bidirectional, dow, loop */
RESTORE_INTR (flags);
#endif /* 0 */
}
static void
@ -1024,8 +1032,8 @@ compute_and_set_volume (int voice, int volume, int ramp_time)
DISABLE_INTR (flags);
/*
* CAUTION! Interrupts disabled. Enable them before returning
*/
* CAUTION! Interrupts disabled. Enable them before returning
*/
gus_select_voice (voice);
@ -1234,8 +1242,8 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
note_freq <= samples[samplep].high_note)
sample = samplep;
else
samplep = samples[samplep].key; /*
* Follow link
samplep = samples[samplep].key; /*
* Follow link
*/
}
if (sample == -1)
@ -1340,9 +1348,9 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
}
gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start,
is16bits);/* Loop start location */
is16bits); /* Loop start location */
gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end,
is16bits);/* Loop end location */
is16bits); /* Loop end location */
}
else
{
@ -1350,9 +1358,9 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume)
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 */
is16bits); /* Loop start location */
gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1,
is16bits);/* Loop end location */
is16bits); /* Loop end location */
}
gus_voice_freq (freq);
gus_voice_balance (pan);
@ -1382,8 +1390,7 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
voices[voice].volume_pending = volume;
else
{
RESTORE_INTR (flags);
ret_val = guswave_start_note2 (dev, voice, note_num, volume);
ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume);
}
}
else
@ -1391,7 +1398,7 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
gus_select_voice (voice);
mode = gus_read8 (0x00);
if (mode & 0x20)
gus_write8 (0x00, mode & 0xdf); /* No interrupt! */
gus_write8 (0x00, mode & 0xdf); /* No interrupt! */
voices[voice].offset_pending = 0;
voices[voice].kill_pending = 0;
@ -1400,31 +1407,32 @@ guswave_start_note (int dev, int voice, int note_num, int volume)
if (voices[voice].sample_pending >= 0)
{
RESTORE_INTR (flags);
RESTORE_INTR (flags); /* Run temporarily with interrupts enabled */
guswave_set_instr (voices[voice].dev_pending, voice,
voices[voice].sample_pending);
voices[voice].sample_pending = -1;
DISABLE_INTR (flags);
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);
ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume);
}
else
{
voices[voice].dev_pending = dev;
voices[voice].dev_pending = gus_devnum;
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_ramp_rate (0, 63); /* Fastest possible rate */
gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
RESTORE_INTR (flags);
}
}
RESTORE_INTR (flags);
return ret_val;
}
@ -1445,16 +1453,19 @@ guswave_open (int dev, int mode)
{
int err;
if (gus_busy)
if (mode & OPEN_WRITE && gus_busy[gus_devnum] ||
mode & OPEN_READ && gus_busy[gus_dspnum])
return RET_ERROR (EBUSY);
gus_initialize ();
if(gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0)
gus_initialize ();
voice_alloc->timestamp = 0;
if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
return err;
RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
gus_busy = 1;
gus_busy[gus_devnum] = 1;
active_device = GUS_DEV_WAVE;
gus_reset ();
@ -1465,7 +1476,7 @@ guswave_open (int dev, int mode)
static void
guswave_close (int dev)
{
gus_busy = 0;
gus_busy[gus_devnum] = 0;
active_device = 0;
gus_reset ();
@ -1482,7 +1493,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
unsigned long blk_size, blk_end, left, src_offs, target;
sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
if (format != GUS_PATCH)
{
@ -1654,7 +1665,8 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
addr, sizeof_patch + src_offs,
blk_size);
DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/
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],
@ -1688,7 +1700,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
if (audio_devs[gus_devnum]->dmachan > 3)
dma_command |= 0x04; /* 16 bit DMA _channel_ */
gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */
gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */
/*
* Sleep here until the DRAM DMA done interrupt is served
@ -1716,7 +1728,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
free_mem_ptr += patch.len;
if (!pmgr_flag)
pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
pmgr_inform (gus_devnum, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
free_sample++;
return 0;
}
@ -1871,13 +1883,25 @@ guswave_hw_control (int dev, unsigned char *event)
static int
gus_sampling_set_speed (int speed)
{
if (speed <= 0)
return gus_sampling_speed;
speed = gus_sampling_speed;
if (speed < 4000)
speed = 4000;
if (speed > 44100)
speed = 44100;
gus_sampling_speed = 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;
}
@ -1961,8 +1985,6 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
break;
default:
return RET_ERROR (EINVAL);
}
return RET_ERROR (EINVAL);
}
@ -1975,17 +1997,36 @@ gus_sampling_reset (int dev)
static int
gus_sampling_open (int dev, int mode)
{
int dev_flag;
#ifdef GUS_NO_DMA
printk ("GUS: DMA mode not enabled. Device not supported\n");
return RET_ERROR (ENXIO);
#endif
dev_flag = 0;
if(mode & OPEN_WRITE)
{
if (gus_busy[gus_devnum])
return RET_ERROR(EBUSY);
if(dev != gus_devnum)
return RET_ERROR(ENXIO);
dev_flag = gus_busy[gus_devnum] = 1;
}
if(mode & OPEN_READ)
{
if(gus_busy[gus_dspnum]) {
if (dev_flag) gus_busy[gus_devnum] = 0;
return RET_ERROR(EBUSY);
}
if(dev != gus_dspnum) {
if (dev_flag) gus_busy[gus_devnum] = 0;
return RET_ERROR(ENXIO);
}
}
if (gus_busy)
return RET_ERROR (EBUSY);
if(gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0)
gus_initialize ();
gus_initialize ();
gus_busy = 1;
active_device = 0;
gus_reset ();
@ -2000,6 +2041,7 @@ gus_sampling_open (int dev, int mode)
recording_active = 1;
set_input_volumes ();
}
only_read_access = !(mode & OPEN_WRITE);
return 0;
}
@ -2007,10 +2049,12 @@ gus_sampling_open (int dev, int mode)
static void
gus_sampling_close (int dev)
{
gus_reset ();
gus_busy = 0;
pcm_opened = 0;
active_device = 0;
gus_busy[dev] = 0;
if (gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum]) {
active_device = 0;
gus_reset();
pcm_opened = 0;
}
if (recording_active)
set_input_volumes ();
@ -2024,16 +2068,16 @@ 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++)
{
DISABLE_INTR (flags);
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);
}
RESTORE_INTR (flags);
}
static void
@ -2075,7 +2119,7 @@ play_next_pcm_block (void)
if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */
{
mode[chn] |= 0x08; /* Enable loop */
ramp_mode[chn] = 0x03;/* Disable rollover bit */
ramp_mode[chn] = 0x03; /* Disable rollover bit */
}
else
{
@ -2112,12 +2156,12 @@ play_next_pcm_block (void)
gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start */
if (chn != 0)
gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
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],
gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1,
is16bits); /* Loop end location */
else
mode[chn] |= 0x08; /* Enable looping */
@ -2130,7 +2174,7 @@ play_next_pcm_block (void)
if (chn == 0)
{
mode[chn] &= ~0x08; /* Disable looping */
mode[chn] |= 0x20;/* Enable IRQ at the end */
mode[chn] |= 0x20; /* Enable IRQ at the end */
voices[0].loop_irq_mode = LMODE_PCM_STOP;
ramp_mode[chn] = 0x03; /* No rollover bit */
}
@ -2193,12 +2237,12 @@ gus_transfer_output_block (int dev, unsigned long buf,
this_one = pcm_current_block;
gus_write8 (0x41, 0); /* Disable GF1 DMA */
DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
DMAbuf_start_dma (gus_devnum, buf + (chn * count), count, DMA_MODE_WRITE);
address = this_one * pcm_bsize;
address += chn * pcm_banksize;
if (audio_devs[dev]->dmachan > 3)
if (audio_devs[gus_devnum]->dmachan > 3)
{
hold_address = address;
address = address >> 1;
@ -2215,7 +2259,7 @@ gus_transfer_output_block (int dev, unsigned long buf,
else
dma_command |= 0x80; /* Invert MSB */
if (audio_devs[dev]->dmachan > 3)
if (audio_devs[gus_devnum]->dmachan > 3)
dma_command |= 0x04; /* 16 bit DMA channel */
gus_write8 (0x41, dma_command); /* Kickstart */
@ -2235,9 +2279,9 @@ gus_transfer_output_block (int dev, unsigned long buf,
else
{
/*
* Left channel data. The right channel
* is transferred after DMA interrupt
*/
* Left channel data. The right channel
* is transferred after DMA interrupt
*/
active_device = GUS_DEV_PCM_CONTINUE;
}
@ -2251,8 +2295,8 @@ gus_sampling_output_block (int dev, unsigned long buf, int total_count,
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_dev = gus_devnum;
gus_transfer_output_block (gus_devnum, buf, total_count, intrflag, 0);
}
static void
@ -2264,11 +2308,11 @@ gus_sampling_start_input (int dev, unsigned long buf, int count,
DISABLE_INTR (flags);
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
DMAbuf_start_dma (gus_dspnum, buf, count, DMA_MODE_READ);
mode = 0xa0; /* DMA IRQ enabled, invert MSB */
if (audio_devs[dev]->dmachan > 3)
if (audio_devs[gus_dspnum]->dmachan > 3)
mode |= 0x04; /* 16 bit DMA channel */
if (gus_sampling_channels > 1)
mode |= 0x02; /* Stereo */
@ -2364,8 +2408,8 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs,
}
else
{
int in_left = useroffs;
int in_right = useroffs + 1;
int in_left = useroffs / 2;
int in_right = useroffs / 2 + 1;
short *out_left, *out_right;
int i;
@ -2404,6 +2448,42 @@ static struct audio_operations gus_sampling_operations =
gus_copy_from_user
};
static struct audio_operations gus_sampling_operations_read =
{
"Gravis UltraSound - read only",
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_setup_voice (int dev, int voice, int chn)
{
struct channel_info *info =
&synth_devs[gus_devnum]->chn_info[chn];
guswave_set_instr (gus_devnum, 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;
}
static void
guswave_bender (int dev, int voice, int value)
{
@ -2528,7 +2608,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
if (offs < 0 || offs >= samples[sample].len)
return RET_ERROR (EINVAL); /* Invalid offset */
n = samples[sample].len - offs; /* Num of bytes left */
n = samples[sample].len - offs; /* Num of bytes left */
if (l > n)
l = n;
@ -2542,7 +2622,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
*/
offs += sample_ptrs[sample]; /*
* Begin offset + offset to DRAM
* Begin offsess + offset to DRAM
*/
for (n = 0; n < l; n++)
@ -2571,8 +2651,8 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
* Invalid offset
*/
n = samples[sample].len - offs; /*
* Nr of bytes left
n = samples[sample].len - offs; /*
* Nr of bytes left
*/
if (l > n)
@ -2587,7 +2667,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
*/
offs += sample_ptrs[sample]; /*
* Begin offset + offset to DRAM
* Begin offsess + offset to DRAM
*/
for (n = 0; n < l; n++)
@ -2607,12 +2687,12 @@ guswave_patchmgr (int dev, struct patmgr_info *rec)
static int
guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
{
int i, p;
int i, p, best = -1, best_time = 0x7fffffff;
p = alloc->ptr;
/*
* First look for a completely stopped voice
*/
* First look for a completely stopped voice
*/
for (i = 0; i < alloc->max_voice; i++)
{
@ -2621,12 +2701,17 @@ guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
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;
}
/*
* Then look for a releasing voice
*/
* Then look for a releasing voice
*/
for (i = 0; i < alloc->max_voice; i++)
{
@ -2637,7 +2722,9 @@ guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
}
p = (p + 1) % alloc->max_voice;
}
printk ("GUS: Out of free voices\n");
if (best >= 0)
p = best;
alloc->ptr = p;
return p;
@ -2664,7 +2751,8 @@ static struct synth_operations guswave_operations =
guswave_volume_method,
guswave_patchmgr,
guswave_bender,
guswave_alloc
guswave_alloc,
guswave_setup_voice
};
static void
@ -2676,10 +2764,10 @@ set_input_volumes (void)
DISABLE_INTR (flags);
/*
* Enable channels having vol > 10%
* Note! bit 0x01 means line in DISABLED while 0x04 means
* mic in ENABLED.
*/
* Enable channels having vol > 10%
* Note! bit 0x01 means line in DISABLED while 0x04 means
* mic in ENABLED.
*/
if (gus_line_vol > 10)
mask &= ~0x01;
if (gus_mic_vol > 10)
@ -2688,8 +2776,8 @@ set_input_volumes (void)
if (recording_active)
{
/*
* Disable channel, if not selected for recording
*/
* Disable channel, if not selected for recording
*/
if (!(gus_recmask & SOUND_MASK_LINE))
mask |= 0x01;
if (!(gus_recmask & SOUND_MASK_MIC))
@ -2833,6 +2921,7 @@ gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
static struct mixer_operations gus_mixer_operations =
{
"Gravis Ultrasound",
gus_default_mixer_ioctl
};
@ -2849,7 +2938,7 @@ gus_default_mixer_init (long mem_start)
}
long
gus_wave_init (long mem_start, int irq, int dma)
gus_wave_init (long mem_start, int irq, int dma, int dma_read)
{
unsigned long flags;
unsigned char val;
@ -2857,11 +2946,29 @@ gus_wave_init (long mem_start, int irq, int dma)
int gus_type = 0x24; /* 2.4 */
int mixer_type = 0;
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;
}
if (dma_read == 0) dma_read = dma;
if (dma_read < 0 || dma_read > 7)
{
printk ("ERROR! Invalid DMA#%d. GUS DMA-read disabled", dma_read);
dma_read = dma;
}
/*
* Try to identify the GUS model.
*
* Versions < 3.6 don't have the digital ASIC. Try to probe it first.
*/
* Try to identify the GUS model.
*
* Versions < 3.6 don't have the digital ASIC. Try to probe it first.
*/
DISABLE_INTR (flags);
OUTB (0x20, gus_base + 0x0f);
@ -2871,9 +2978,9 @@ gus_wave_init (long mem_start, int irq, int dma)
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.
*/
* It has the digital ASIC so the card is at least v3.4.
* Next try to detect the true model.
*/
val = INB (u_MixSelect);
@ -2883,8 +2990,8 @@ gus_wave_init (long mem_start, int irq, int dma)
* 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.
*/
* soon after the SDK for GUS MAX is available.
*/
if (val == 255 || val < 5)
{
@ -2902,68 +3009,31 @@ gus_wave_init (long mem_start, int irq, int dma)
model_num = "MAX";
gus_type = 0x40;
mixer_type = CS4231;
#ifndef EXCLUDE_GUSMAX
{
unsigned char max_config = 0x40; /* Codec enable */
if (dma > 3)
max_config |= 0x30; /* 16 bit playback and capture DMAs */
max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
OUTB (max_config, gus_base + 0x106); /* UltraMax control */
}
if (ad1848_detect (gus_base + 0x10c))
{
gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
gus_wave_volume = 90;
have_gus_max = 1;
ad1848_init ("gusmax0: <GUS MAX>", gus_base + 0x10c,
-irq,
dma,
dma);
}
else
printk ("[Where's the CS4231?]");
#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.
* It has the same codec/mixer than MAX.
* At this time there is no support for it but it will appear soon.
*/
* ASIC not detected so the card must be 2.2 or 2.4.
* There could still be the 16-bit/mixer daughter card.
* It has the same codec/mixer than MAX.
* At this time there is no support for it but it will appear soon.
*/
}
#ifdef __FreeBSD__
printk ("gus0: <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
#else /* __FreeBSD__ */
#if defined(__FreeBSD__)
printk ("gus0: <Gravis UltraSound %s (%dk)>", model_num,
(int) gus_mem_size / 1024);
#else
printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
#endif /* __FreeBSD__ */
#ifndef SCO
sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
#endif
if (irq < 0 || irq > 15)
{
printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
return mem_start;
}
if (dma < 0 || dma > 7)
{
printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
return mem_start;
}
sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
gus_irq = irq;
gus_dma = dma;
gus_dma_read = dma_read;
if (num_synths >= MAX_SYNTH_DEV)
printk ("GUS Error: Too many synthesizers\n");
@ -2984,21 +3054,36 @@ gus_wave_init (long mem_start, int irq, int dma)
{
audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations;
audio_devs[gus_devnum]->dmachan = dma;
#ifndef NO_AUTODMA
audio_devs[gus_devnum]->buffcount = 1;
#else
audio_devs[gus_devnum]->flags &= ~DMA_AUTOMODE;
audio_devs[gus_devnum]->buffcount = DSP_BUFFCOUNT;
#endif
audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
gus_dspnum = gus_devnum;
gus_busy[gus_devnum] = 0;
gus_busy[gus_dspnum] = 0;
}
else
printk ("GUS: Too many PCM devices available\n");
/*
* Mixer dependent initialization.
*/
if (num_audiodevs < MAX_AUDIO_DEV)
{
if(dma_read && dma != dma_read)
{
audio_devs[gus_dspnum = num_audiodevs++]= &gus_sampling_operations_read;
audio_devs[gus_dspnum]->dmachan = gus_dma_read;
audio_devs[gus_dspnum]->buffcount = 1;
audio_devs[gus_dspnum]->buffsize = DSP_BUFFSIZE;
gus_busy[gus_dspnum] = 0;
}
else
{
gus_dspnum = gus_devnum;
}
}
else
printk ("GUS READ: Too many PCM devices available\n");
/*
* Mixer dependent initialization.
*/
switch (mixer_type)
{
case ICS2101:
@ -3008,11 +3093,37 @@ gus_wave_init (long mem_start, int irq, int dma)
case CS4231:
/* Initialized elsewhere (ad1848.c) */
#ifndef EXCLUDE_GUSMAX
{
unsigned char max_config = 0x40; /* Codec enable */
long mixer_init_return;
if (dma > 3)
max_config |= 0x30; /* 16 bit playback and capture DMAs */
max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
OUTB (max_config, gus_base + 0x106); /* UltraMax control */
mixer_init_return = gus_default_mixer_init(mem_start);
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_read, /* read write reversed */
dma);
}
else
printk ("[Where's the CS4231?]");
return mixer_init_return;
}
#endif
default:
return gus_default_mixer_init (mem_start);
}
return mem_start;
}
static void
@ -3031,6 +3142,9 @@ do_loop_irq (int 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;
@ -3042,9 +3156,9 @@ do_loop_irq (int voice)
* Final loop finished, shoot volume down
*/
if ((int) (gus_read16 (0x09) >> 4) < 100) /*
* Get current volume
*/
if ((int) (gus_read16 (0x09) >> 4) < 100) /*
* Get current volume
*/
{
gus_voice_off ();
gus_rampoff ();
@ -3065,26 +3179,29 @@ do_loop_irq (int voice)
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)
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 the queue was full before this interrupt, the DMA transfer was
* suspended. Let it continue now.
*/
if (dma_active)
{
if (pcm_qlen == 0)
@ -3187,9 +3304,9 @@ gus_voice_irq (void)
* Wave IRQ pending
*/
if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /*
* Not done
* yet
*/
* Not done
* yet
*/
{
wave_ignore |= voice_bit;
do_loop_irq (voice);
@ -3199,9 +3316,9 @@ gus_voice_irq (void)
* Volume IRQ pending
*/
if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /*
* Not done
* yet
*/
* Not done
* yet
*/
{
volume_ignore |= voice_bit;
do_volume_irq (voice);
@ -3251,7 +3368,10 @@ guswave_dma_irq (void)
* Sampling Irq pending
*/
{
DMAbuf_inputintr (gus_devnum);
if (gus_dma_read && gus_dma_read != gus_dma)
DMAbuf_inputintr (gus_dspnum);
else
DMAbuf_inputintr (gus_devnum);
}
}

View file

@ -0,0 +1,97 @@
/*
* This file is a part of configure.c
*
* hex2hex reads an input file in Intel HEX format and produces
* an (unsigned char) array which contains the bytes and writes it to the
* output file using C syntax
*/
#define MAX_SIZE (256*1024)
#define ABANDON(why) { \
fprintf(stderr, "%s: " why "\n", source); \
fclose(inf);fclose(outf);return 0; \
}
int hex2hex(char *source, char *target, char *varline)
{
FILE *inf, *outf;
int i,l, c;
unsigned char buf[MAX_SIZE];
if ((inf=fopen(source, "r"))==NULL)
{
perror(source);
return 0;
}
if ((outf=fopen(target, "w"))==NULL)
{
perror(target);
fclose(inf);
return 0;
}
l=0;
while ((c=getc(inf))!=EOF)
{
if (c == ':') /* Sync with beginning of line */
{
int n, check;
unsigned char sum;
int addr;
int linetype;
if (fscanf(inf, "%02x", &n) != 1)
ABANDON("File format error");
sum = n;
if (fscanf(inf, "%04x", &addr) != 1)
ABANDON("File format error");
sum += addr/256;
sum += addr%256;
if (fscanf(inf, "%02x", &linetype) != 1)
ABANDON("File format error");
sum += linetype;
if (linetype != 0)
continue;
for (i=0;i<n;i++)
{
if (fscanf(inf, "%02x", &c) != 1)
ABANDON("File format error");
if (addr >= MAX_SIZE)
ABANDON("File too large");
buf[addr++] = c;
if (addr > l)
l = addr;
sum += c;
}
if (fscanf(inf, "%02x", &check) != 1)
ABANDON("File format error");
sum = ~sum + 1;
if (check != sum)
ABANDON("Line checksum error");
}
}
fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n");
fprintf(outf, "%s[] = {\n", varline);
for (i=0;i<l;i++)
{
if (i) fprintf(outf, ",");
if (i && !(i % 16)) fprintf(outf, "\n");
fprintf(outf, "0x%02x", buf[i]);
}
fprintf(outf, "\n};\n\n");
fclose(inf);
fclose(outf);
return 1;
}

View file

@ -25,13 +25,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ics2101.c,v 1.4 1994/10/01 02:16:43 swallace Exp
*/
#include "sound_config.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
#include <machine/ultrasound.h>
#include "ultrasound.h"
#include "gus_hw.h"
#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
@ -50,10 +49,10 @@ scale_vol (int vol)
{
#if 1
/*
* Experimental volume scaling by Risto Kankkunen.
* This should give smoother volume response than just
* a plain multiplication.
*/
* Experimental volume scaling by Risto Kankkunen.
* This should give smoother volume response than just
* a plain multiplication.
*/
int e;
if (vol < 0)
@ -225,6 +224,7 @@ ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
static struct mixer_operations ics2101_mixer_operations =
{
"ICS2101 Multimedia Mixer",
ics2101_mixer_ioctl
};
@ -238,9 +238,9 @@ ics2101_mixer_init (long mem_start)
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)
{

View file

@ -5,7 +5,6 @@
#define DSP_BUFFSIZE 65536
#define SELECTED_SOUND_OPTIONS 0xffffffff
#define SOUND_VERSION_STRING "2.90-2"
#define SOUND_CONFIG_DATE "Sun Feb 5 14:38:12 EST 1995"
#define SOUND_CONFIG_BY "freebsd-hackers"
#define SOUND_CONFIG_HOST "freefall"
@ -17,6 +16,8 @@
#define KERNEL_SOUNDCARD
#endif
#define ALLOW_SELECT
/* PSS code does not work */
#ifndef EXCLUDE_PSS
#define EXCLUDE_PSS
@ -32,9 +33,28 @@
#define EXCLUDE_GUS16
#endif
#include "gusmax.h"
#if NGUSMAX == 0 && !defined(EXCLUDE_GUSMAX)
#define EXCLUDE_GUSMAX
#include "mss.h"
#if NMSS == 0 && !defined(EXCLUDE_MSS)
#define EXCLUDE_MSS
#endif
#include "trix.h"
#if NTRIX == 0 && !defined(EXCLUDE_TRIX)
#define EXCLUDE_TRIX
#endif
#include "sscape.h"
#if NSSCAPE == 0 && !defined(EXCLUDE_SSCAPE)
#define EXCLUDE_SSCAPE
#endif
#if !defined(GUSMAX) && !defined(EXCLUDE_GUSMAX)
# define EXCLUDE_GUSMAX
# if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && !defined(EXCLUDE_AD1848)
# define EXCLUDE_AD1848
# endif
#else
# define GUSMAX_MIXER
#endif
#include <sb.h>
@ -67,11 +87,6 @@
#define EXCLUDE_YM3812
#endif
#include "mss.h"
#if NMSS == 0 && !defined(EXCLUDE_MSS)
#define EXCLUDE_MSS
#endif
#include "uart.h"
#if NUART == 0 && !defined(EXCLUDE_UART6850)
#define EXCLUDE_UART6850

View file

@ -0,0 +1,91 @@
/*
* Initialization code for OPTI MAD16 interface chip by
* Davor Jadrijevic <davor@emard.pub.hr>
* (Included by ad1848.c when MAD16 support is enabled)
*
* It looks like MAD16 is similar than the Mozart chip (OAK OTI-601).
* It could be even possible that these chips are exactly the same. Can
* anybody confirm this?
*/
static void wr_a_mad16(int base, int v, int a)
{
OUTB(a, base + 0xf);
OUTB(v, base + 0x11);
}
static void wr_b_mad16(int base, int v, int a)
{
OUTB(a, base + 0xf);
OUTB(v, base + 0xd);
}
/*
static int rd_a_mad16(int base, int a)
{
OUTB(a, base + 0xf);
return INB(base + 0x11);
}
*/
static int rd_b_mad16(int base, int a)
{
OUTB(a, base + 0xf);
return INB(base + 0xd);
}
/*
static int rd_0_mad16(int base, int a)
{
OUTB(a, base + 0xf);
return INB(base + 0xf);
}
static void wr_ad(int base, int v, int a)
{
OUTB(a, base + 4);
OUTB(v, base + 5);
}
static int rd_ad(int base, int a)
{
OUTB(a, base + 4);
return INB(base + 5);
}
*/
static int mad16init(int adr)
{
int j;
long i;
static int ad1848_bases[] =
{ 0x220, -1, -1, 0x240, -1, -1, -1, -1, 0x530, 0xE80, 0xF40, 0x604, 0 };
int mad16_base = 0xf80, ad1848_base;
for(j = 0; (j < 16) && (ad1848_bases[j] != 0); j++)
if(adr == ad1848_bases[j])
break;
if( (ad1848_base = ad1848_bases[j]) < 0x530)
{
printk("Unknown MAD16 setting 0x%3X\n", adr);
return -1;
}
/* printk("OPTi MAD16 WSS at 0x%3X\n", ad1848_base); */
rd_b_mad16(mad16_base, 0xe2);
wr_a_mad16(mad16_base, 0x1a, 0xe2);
wr_b_mad16(mad16_base, j * 16 + 1, 0xe2);
wr_a_mad16(mad16_base, 0x1a, 0xe2);
for( i = 0; i < 10000; i++)
if( (INB(ad1848_base+4) & 0x80) == 0 )
break;
return 0;
};

View file

@ -1,18 +1,15 @@
/*
* midi_ctrl.h,v 1.2 1994/10/01 02:16:45 swallace Exp
*/
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 */
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 48 to 55 */
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 56 to 63 */
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 64 to 71 */
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 72 to 79 */
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 80 to 87 */

View file

@ -25,9 +25,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* midi_synth.c,v 1.2 1994/10/01 02:16:46 swallace Exp
*/
#define USE_SEQ_MACROS
#define USE_SIMPLE_MACROS
#include "sound_config.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
@ -41,6 +43,61 @@ DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
static int midi2synth[MAX_MIDI_DEV];
static unsigned char prev_out_status[MAX_MIDI_DEV];
#define STORE(cmd) \
{ \
int len; \
unsigned char obuf[8]; \
cmd; \
seq_input_event(obuf, len); \
}
#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:
printk ("MPU: Unknown midi channel message %02x\n", msg[0]);
}
}
static void
midi_outc (int midi_dev, int data)
{
@ -70,7 +127,7 @@ midi_outc (int midi_dev, int data)
static int
prefix_cmd (int midi_dev, unsigned char status)
{
if (midi_devs[midi_dev]->prefix_cmd == NULL)
if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL)
return 1;
return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
@ -80,6 +137,20 @@ static void
midi_synth_input (int dev, unsigned char data)
{
int orig_dev;
struct midi_input_info *inc;
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 (dev < 0 || dev > num_synths)
return;
@ -88,7 +159,86 @@ midi_synth_input (int dev, unsigned char data)
return;
orig_dev = midi2synth[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:
printk ("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state,
(int) data);
inc->m_state = MST_INIT;
}
}
static void
@ -156,9 +306,9 @@ midi_synth_kill_note (int dev, int channel, int note, int velocity)
if (msg == 0x90) /*
* Running status = Note on
*/
midi_outc (orig_dev, 0);/*
* Note on with velocity 0 == note
* off
midi_outc (orig_dev, 0); /*
* Note on with velocity 0 == note
* off
*/
else
midi_outc (orig_dev, velocity);
@ -262,6 +412,8 @@ midi_synth_open (int dev, int mode)
{
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 RET_ERROR (ENXIO);
@ -273,6 +425,16 @@ midi_synth_open (int dev, int mode)
midi_synth_input, midi_synth_output)) < 0)
return err;
inc = &midi_devs[orig_dev]->in_info;
DISABLE_INTR (flags);
inc->m_busy = 0;
inc->m_state = MST_INIT;
inc->m_ptr = 0;
inc->m_left = 0;
inc->m_prev_status = 0x00;
RESTORE_INTR (flags);
return 1;
}
@ -282,8 +444,8 @@ midi_synth_close (int dev)
int orig_dev = synth_devs[dev]->midi_dev;
/*
* Shut up the synths by sending just single active sensing message.
*/
* 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);
@ -304,6 +466,7 @@ midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
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;
@ -314,20 +477,20 @@ midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
return RET_ERROR (EINVAL);
}
if (count < sizeof (struct sysex_info))
if (count < hdr_size)
{
printk ("MIDI Error: Patch header too short\n");
return RET_ERROR (EINVAL);
}
count -= sizeof (struct sysex_info);
count -= hdr_size;
/*
* 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);
COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, hdr_size - offs);
if (count < sysex.len)
{
@ -345,21 +508,20 @@ midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
{
unsigned char data;
GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i);
GET_BYTE_FROM_USER (data, addr, hdr_size + i);
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 (data != 0xf0)
{
printk ("Error: Sysex start missing\n");
return RET_ERROR (EINVAL);
}
}
while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
@ -407,6 +569,7 @@ midi_synth_aftertouch (int dev, int channel, int pressure)
}
else if (!prefix_cmd (orig_dev, pressure))
return;
midi_outc (orig_dev, pressure);
}
@ -459,7 +622,8 @@ midi_synth_bender (int dev, int channel, int value)
prev_chn = prev_out_status[orig_dev] & 0x0f;
if (msg != 0xd0 || prev_chn != channel) /*
* * Test for running status */
* Test for running status
*/
{
if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f)))
return;
@ -472,4 +636,9 @@ midi_synth_bender (int dev, int channel, int value)
midi_outc (orig_dev, (value >> 7) & 0x7f);
}
void
midi_synth_setup_voice (int dev, int voice, int channel)
{
}
#endif

View file

@ -1,6 +1,3 @@
/*
* midi_synth.h,v 1.2 1994/10/01 02:16:47 swallace Exp
*/
int midi_synth_ioctl (int dev,
unsigned int cmd, unsigned int arg);
int midi_synth_kill_note (int dev, int channel, int note, int velocity);
@ -17,6 +14,7 @@ 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);
#ifndef _MIDI_SYNTH_C_
@ -43,6 +41,8 @@ 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
};
#endif

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* midibuf.c,v 1.6 1994/10/01 02:16:48 swallace Exp
*/
#include "sound_config.h"
@ -121,7 +120,10 @@ midi_input_intr (int dev, unsigned char data)
if (SOMEONE_WAITING (input_sleeper[dev], input_sleep_flag[dev]))
WAKE_UP (input_sleeper[dev], input_sleep_flag[dev]);
}
#if defined(__FreeBSD__)
if (selinfo[dev].si_pid)
selwakeup(&selinfo[dev]);
#endif
}
static void
@ -130,6 +132,10 @@ midi_output_intr (int dev)
/*
* Currently NOP
*/
#if defined(__FreeBSD__)
if (selinfo[dev].si_pid)
selwakeup(&selinfo[dev]);
#endif
}
static void
@ -185,8 +191,8 @@ MIDIbuf_open (int dev, struct fileinfo *file)
}
/*
* Interrupts disabled. Be careful
*/
* Interrupts disabled. Be careful
*/
DISABLE_INTR (flags);
if ((err = midi_devs[dev]->open (dev, mode,
@ -246,14 +252,14 @@ MIDIbuf_release (int dev, struct fileinfo *file)
DISABLE_INTR (flags);
/*
* Wait until the queue is empty
*/
* Wait until the queue is empty
*/
if (mode != OPEN_READ)
{
midi_devs[dev]->putc (dev, 0xfe); /*
* Active sensing to shut the
* devices
midi_devs[dev]->putc (dev, 0xfe); /*
* Active sensing to shut the
* devices
*/
while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
@ -380,22 +386,32 @@ MIDIbuf_ioctl (int dev, struct fileinfo *file,
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
printk ("/dev/midi%d: No coprocessor for this device\n", dev);
case SNDCTL_MIDI_PRETIME:
val = IOCTL_IN (arg);
if (val < 0)
val = 0;
val = (HZ * val) / 10;
parms[dev].prech_timeout = val;
return IOCTL_OUT (arg, val);
break;
default:
return midi_devs[dev]->ioctl (dev, cmd, arg);
return RET_ERROR (EREMOTEIO);
}
else
switch (cmd)
{
case SNDCTL_MIDI_PRETIME:
val = IOCTL_IN (arg);
if (val < 0)
val = 0;
val = (HZ * val) / 10;
parms[dev].prech_timeout = val;
return IOCTL_OUT (arg, val);
break;
default:
return midi_devs[dev]->ioctl (dev, cmd, arg);
}
}
#ifdef ALLOW_SELECT
@ -409,8 +425,12 @@ MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wai
case SEL_IN:
if (!DATA_AVAIL (midi_in_buf[dev]))
{
#if defined(__FreeBSD__)
selrecord(wait, &selinfo[dev]);
#else
input_sleep_flag[dev].mode = WK_SLEEP;
select_wait (&input_sleeper[dev], wait);
#endif
return 0;
}
return 1;
@ -419,8 +439,12 @@ MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wai
case SEL_OUT:
if (SPACE_AVAIL (midi_out_buf[dev]))
{
#if defined(__FreeBSD__)
selrecord(wait, &selinfo[dev]);
#else
midi_sleep_flag[dev].mode = WK_SLEEP;
select_wait (&midi_sleeper[dev], wait);
#endif
return 0;
}
return 1;

View file

@ -25,7 +25,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* mpu401.c,v 1.9 1994/10/01 02:16:49 swallace Exp
* Modified:
* Riccardo Facchetti 24 Mar 1995
* - Added the Audio Excel DSP 16 initialization routine.
*/
#define USE_SEQ_MACROS
@ -35,7 +37,8 @@
#ifdef CONFIGURE_SOUNDCARD
#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
#include "coproc.h"
static int init_sequence[20]; /* NOTE! pos 0 = len, start pos 1. */
static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
@ -76,7 +79,7 @@ struct mpu_config
int m_left;
unsigned char last_status;
void (*inputintr) (int dev, unsigned char data);
unsigned short controls[32];
int shared_irq;
};
#define DATAPORT(base) (base)
@ -102,7 +105,9 @@ static struct mpu_config dev_conf[MAX_MIDI_DEV] =
{0}};
static int n_mpu_devs = 0;
static int irq2dev[16];
static int irq2dev[16] =
{-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);
@ -129,7 +134,7 @@ 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 unsigned char len_tab[] = /* # of data bytes following a status
*/
{
2, /* 8x */
@ -143,7 +148,6 @@ static unsigned char len_tab[] =/* # of data bytes following a status
};
#define STORE(cmd) \
if (devc->opened & OPEN_READ) \
{ \
int len; \
unsigned char obuf[8]; \
@ -154,73 +158,10 @@ if (devc->opened & OPEN_READ) \
#define _seqbufptr 0
#define _SEQ_ADVBUF(x) len=x
static void
do_midi_msg (struct mpu_config *devc, unsigned char *msg, int mlen)
{
switch (msg[0] & 0xf0)
{
case 0x90:
if (msg[2] != 0)
{
STORE (SEQ_START_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
break;
}
msg[2] = 64;
case 0x80:
STORE (SEQ_STOP_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
break;
case 0xA0:
STORE (SEQ_KEY_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
break;
case 0xB0:
/*
* Fix the controller value (combine MSB and LSB)
*/
if (msg[1] < 64)
{
int ctrl = msg[1];
if (ctrl < 32)
{
devc->controls[ctrl] = (msg[2] & 0x7f) << 7;
}
else
{
ctrl -= 32;
devc->controls[ctrl] =
(devc->controls[ctrl] & ~0x7f) | (msg[2] & 0x7f);
}
STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f,
msg[1], devc->controls[ctrl]));
}
else
STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
break;
case 0xC0:
STORE (SEQ_SET_PATCH (devc->synthno, msg[0] & 0x0f, msg[1]));
break;
case 0xD0:
STORE (SEQ_CHN_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1]));
break;
case 0xE0:
STORE (SEQ_BENDER (devc->synthno, msg[0] & 0x0f,
(msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
break;
default:
printk ("MPU: Unknown midi channel message %02x\n", msg[0]);
}
}
static int
mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
{
switch (devc->m_state)
{
case ST_INIT:
@ -278,6 +219,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
int msg = (midic & 0xf0) >> 4;
devc->m_state = ST_DATABYTE;
if (msg < 8) /* Data byte */
{
/* printk("midi msg (running status) "); */
@ -292,7 +234,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
if (devc->m_left <= 0)
{
devc->m_state = ST_INIT;
do_midi_msg (devc, devc->m_buf, devc->m_ptr);
do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr);
devc->m_ptr = 0;
}
}
@ -321,7 +263,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
else
{
devc->last_status = midic;
/* printk("midi msg "); */
/* printk ("midi msg "); */
msg -= 8;
devc->m_left = len_tab[msg];
@ -331,7 +273,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
if (devc->m_left <= 0)
{
devc->m_state = ST_INIT;
do_midi_msg (devc, devc->m_buf, devc->m_ptr);
do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr);
devc->m_ptr = 0;
}
}
@ -364,8 +306,8 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
devc->m_state = ST_INIT;
/*
* Real time messages
*/
* Real time messages
*/
case 0xf8:
/* midi clock */
devc->m_state = ST_INIT;
@ -437,7 +379,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
if ((--devc->m_left) <= 0)
{
devc->m_state = ST_INIT;
do_midi_msg (devc, devc->m_buf, devc->m_ptr);
do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr);
devc->m_ptr = 0;
}
break;
@ -455,16 +397,19 @@ mpu401_input_loop (struct mpu_config *devc)
{
unsigned long flags;
int busy;
int n;
DISABLE_INTR (flags);
busy = devc->m_busy;
devc->m_busy = 1;
RESTORE_INTR (flags);
if (busy)
if (busy) /* Already inside the scanner */
return;
while (input_avail (devc->base))
n = 50;
while (input_avail (devc->base) && n-- > 0)
{
unsigned char c = read_data (devc->base);
@ -480,7 +425,7 @@ mpu401_input_loop (struct mpu_config *devc)
}
void
mpuintr (int irq)
mpuintr (INT_HANDLER_PARMS (irq, dummy))
{
struct mpu_config *devc;
int dev;
@ -498,15 +443,20 @@ mpuintr (int irq)
dev = irq2dev[irq];
if (dev == -1)
{
printk ("MPU-401: Interrupt #%d?\n", irq);
/* printk ("MPU-401: Interrupt #%d?\n", irq); */
return;
}
devc = &dev_conf[dev];
if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
if (input_avail (devc->base))
if (input_avail (devc->base))
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->base);
}
}
@ -530,9 +480,40 @@ mpu401_open (int dev, int mode,
return RET_ERROR (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->base) == 0xff) /* Bus float */
{
printk ("MPU-401: Device not initialized properly\n");
return RET_ERROR (EIO);
}
reset_mpu401 (devc);
}
irq2dev[devc->irq] = dev;
if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
return err;
if (devc->shared_irq == 0)
if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[dev]->info.name) < 0))
{
return err;
}
if (midi_devs[dev]->coproc)
if ((err = midi_devs[dev]->coproc->
open (midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0)
{
if (devc->shared_irq == 0)
snd_release_irq (devc->irq);
printk ("MPU-401: Can't access coprocessor device\n");
return err;
}
set_uart_mode (dev, devc, 1);
devc->mode = MODE_MIDI;
@ -559,9 +540,12 @@ mpu401_close (int dev)
*/
devc->mode = 0;
snd_release_irq (devc->irq);
if (devc->shared_irq == 0)
snd_release_irq (devc->irq);
devc->inputintr = NULL;
irq2dev[devc->irq] = -1;
if (midi_devs[dev]->coproc)
midi_devs[dev]->coproc->close (midi_devs[dev]->coproc->devc, COPR_MIDI);
devc->opened = 0;
}
@ -581,16 +565,16 @@ mpu401_out (int dev, unsigned char midi_byte)
*/
if (input_avail (devc->base))
mpu401_input_loop (devc);
{
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
*/
for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--);
DISABLE_INTR (flags);
if (!output_ready (devc->base))
@ -634,34 +618,42 @@ mpu401_command (int dev, mpu_command_rec * cmd)
* (After reset). Normally it takes just about 10 loops.
*/
for (timeout = 500000; timeout > 0 && !output_ready (devc->base); timeout--);
DISABLE_INTR (flags);
if (!output_ready (devc->base))
timeout = 30000;
retry:
if (timeout-- <= 0)
{
printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
RESTORE_INTR (flags);
return RET_ERROR (EIO);
}
DISABLE_INTR (flags);
if (!output_ready (devc->base))
{
RESTORE_INTR (flags);
goto retry;
}
write_command (devc->base, cmd->cmd);
ok = 0;
for (timeout = 500000; timeout > 0 && !ok; timeout--)
for (timeout = 50000; timeout > 0 && !ok; timeout--)
if (input_avail (devc->base))
if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK)
ok = 1;
{
if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK)
ok = 1;
}
if (!ok)
{
RESTORE_INTR (flags);
printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd);
/* printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */
return RET_ERROR (EIO);
}
if (cmd->nr_args)
for (i = 0; i < cmd->nr_args; i++)
{
for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--);
for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--);
if (!mpu401_out (dev, cmd->data[i]))
{
@ -688,7 +680,7 @@ mpu401_command (int dev, mpu_command_rec * cmd)
if (!ok)
{
RESTORE_INTR (flags);
printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd);
/* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */
return RET_ERROR (EIO);
}
}
@ -858,31 +850,64 @@ mpu_synth_open (int dev, int mode)
midi_dev = synth_devs[dev]->midi_dev;
if (midi_dev < 0 || midi_dev > num_midis)
return RET_ERROR (ENXIO);
{
return RET_ERROR (ENXIO);
}
devc = &dev_conf[midi_dev];
/*
* 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->base) == 0xff) /* Bus float */
{
printk ("MPU-401: Device not initialized properly\n");
return RET_ERROR (EIO);
}
reset_mpu401 (devc);
}
if (devc->opened)
{
printk ("MPU-401: Midi busy\n");
return RET_ERROR (EBUSY);
}
devc->opened = mode;
devc->mode = MODE_SYNTH;
devc->synthno = dev;
devc->inputintr = NULL;
irq2dev[devc->irq] = midi_dev;
if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
return err;
if (devc->shared_irq == 0)
if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[midi_dev]->info.name) < 0))
{
return err;
}
if (midi_devs[midi_dev]->coproc)
if ((err = midi_devs[midi_dev]->coproc->
open (midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0)
{
if (devc->shared_irq == 0)
snd_release_irq (devc->irq);
printk ("MPU-401: Can't access coprocessor device\n");
return err;
}
devc->opened = mode;
reset_mpu401 (devc);
if (mode & OPEN_READ)
{
exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */
exec_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */
exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */
}
return 0;
@ -900,11 +925,14 @@ mpu_synth_close (int dev)
exec_cmd (midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */
exec_cmd (midi_dev, 0x8a, 0); /* Disable data in stopped mode */
if (devc->shared_irq == 0)
snd_release_irq (devc->irq);
devc->inputintr = NULL;
if (midi_devs[midi_dev]->coproc)
midi_devs[midi_dev]->coproc->close (midi_devs[midi_dev]->coproc->devc, COPR_MIDI);
devc->opened = 0;
devc->mode = 0;
snd_release_irq (devc->irq);
devc->inputintr = NULL;
irq2dev[devc->irq] = -1;
}
#define MIDI_SYNTH_NAME "MPU-401 UART Midi"
@ -931,7 +959,9 @@ static struct synth_operations mpu401_synth_proto =
midi_synth_panning,
NULL,
midi_synth_patchmgr,
midi_synth_bender
midi_synth_bender,
NULL, /* alloc */
midi_synth_setup_voice
};
static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV];
@ -940,6 +970,7 @@ static struct midi_operations mpu401_midi_proto =
{
{"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
NULL,
{0},
mpu401_open,
mpu401_close,
mpu401_ioctl,
@ -963,25 +994,28 @@ mpu401_chk_version (struct mpu_config *devc)
if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0)
return;
if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */
return;
devc->version = tmp;
if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0)
return;
{
devc->version = 0;
return;
}
devc->revision = tmp;
}
long
attach_mpu401 (long mem_start, struct address_info *hw_config)
{
int i;
unsigned long flags;
char revision_char;
struct mpu_config *devc;
for (i = 0; i < 16; i++)
irq2dev[i] = -1;
if (num_midis >= MAX_MIDI_DEV)
{
printk ("MPU-401: Too many midi devices detected\n");
@ -1001,18 +1035,20 @@ attach_mpu401 (long mem_start, struct address_info *hw_config)
devc->timer_flag = 0;
devc->m_busy = 0;
devc->m_state = ST_INIT;
devc->shared_irq = hw_config->always_detect;
for (i = 0; i < 32; i++)
devc->controls[i] = 0x2000;
if (!hw_config->always_detect)
{
/* Verify the hardware again */
if (!reset_mpu401 (devc))
return mem_start;
if (!reset_mpu401 (devc))
return mem_start;
DISABLE_INTR (flags);
mpu401_chk_version (devc);
if (devc->version == 0)
mpu401_chk_version (devc);
RESTORE_INTR (flags);
DISABLE_INTR (flags);
mpu401_chk_version (devc);
if (devc->version == 0)
mpu401_chk_version (devc);
RESTORE_INTR (flags);
}
if (devc->version == 0)
{
@ -1049,20 +1085,18 @@ attach_mpu401 (long mem_start, struct address_info *hw_config)
MPU_CAP_CLS | MPU_CAP_2PORT;
revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
#ifdef __FreeBSD__
#if defined(__FreeBSD__)
printk ("mpu0: <MQX-%d%c MIDI Interface>",
#else
printk (" <MQX-%d%c MIDI Interface>",
#endif
ports,
revision_char);
#ifndef SCO
sprintf (mpu_synth_info[num_midis].name,
"MQX-%d%c MIDI Interface #%d",
ports,
revision_char,
n_mpu_devs);
#endif
}
else
{
@ -1073,7 +1107,7 @@ attach_mpu401 (long mem_start, struct address_info *hw_config)
devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
#ifdef __FreeBSD__
#if defined(__FreeBSD__)
printk ("mpu0: <MPU-401 MIDI Interface %d.%d%c>",
#else
printk (" <MPU-401 MIDI Interface %d.%d%c>",
@ -1081,20 +1115,16 @@ attach_mpu401 (long mem_start, struct address_info *hw_config)
(devc->version & 0xf0) >> 4,
devc->version & 0x0f,
revision_char);
#ifndef SCO
sprintf (mpu_synth_info[num_midis].name,
"MPU-401 %d.%d%c Midi interface #%d",
(devc->version & 0xf0) >> 4,
devc->version & 0x0f,
revision_char,
n_mpu_devs);
#endif
}
#ifndef SCO
strcpy (mpu401_midi_operations[num_midis].info.name,
mpu_synth_info[num_midis].name);
#endif
mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis;
mpu401_synth_operations[devc->devno].info =
@ -1103,6 +1133,7 @@ attach_mpu401 (long mem_start, struct address_info *hw_config)
if (devc->capabilities & MPU_CAP_INTLG) /* Has timer */
mpu_timer_init (num_midis);
irq2dev[devc->irq] = num_midis;
midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno];
return mem_start;
}
@ -1163,10 +1194,14 @@ set_uart_mode (int dev, struct mpu_config *devc, int arg)
{
if (!arg && devc->version == 0)
return;
{
return;
}
if ((devc->uart_mode == 0) == (arg == 0))
return; /* Already set */
{
return; /* Already set */
}
reset_mpu401 (devc); /* This exits the uart mode */
@ -1193,6 +1228,19 @@ probe_mpu401 (struct address_info *hw_config)
tmp_devc.irq = hw_config->irq;
tmp_devc.initialized = 0;
#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MPU401)
/*
* Initialize Audio Excel DSP 16 to MPU-401, before any operation.
*/
InitAEDSP16_MPU401 (hw_config);
#endif
if (hw_config->always_detect)
return 1;
if (INB (hw_config->io_base + 1) == 0xff)
return 0; /* Just bus float? */
ok = reset_mpu401 (&tmp_devc);
return ok;
@ -1216,11 +1264,11 @@ static unsigned long
clocks2ticks (unsigned long clocks)
{
/*
* The MPU-401 supports just a limited set of possible timebase values.
* Since the applications require more choices, the driver has to
* program the HW to do it's best and to convert between the HW and
* actual timebases.
*/
* The MPU-401 supports just a limited set of possible timebase values.
* Since the applications require more choices, the driver has to
* program the HW to do it's best and to convert between the HW and
* actual timebases.
*/
return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase;
}
@ -1278,8 +1326,8 @@ set_timer_mode (int midi_dev)
{
if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))
{
exec_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */
exec_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */
exec_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */
exec_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */
}
else if (timer_mode & TMR_MODE_FSK)
exec_cmd (midi_dev, 0x81, 0); /* Use FSK sync */
@ -1490,8 +1538,6 @@ mpu_timer_ioctl (int dev,
break;
case SNDCTL_TMR_START:
if (tmr_running)
return 0;
start_timer (midi_dev);
return 0;
break;

View file

@ -25,11 +25,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* opl3.c,v 1.7 1994/10/01 02:16:50 swallace Exp
*/
/*
* Major improvements to the FM handling 30AUG92 by Rob Hooft,
*/
/*
* hooft@chem.ruu.nl
*/
@ -45,6 +46,7 @@
* * OP4 * * begin here */
static int opl3_enabled = 0;
static int opl4_enabled = 0;
static int left_address = 0x388, right_address = 0x388, both_address = 0;
static int nr_voices = 9;
@ -188,7 +190,7 @@ opl3_detect (int ioaddr)
* Note2! The chip is initialized if detected.
*/
unsigned char stat1, stat2;
unsigned char stat1, stat2, signature;
int i;
if (already_initialized)
@ -201,22 +203,13 @@ opl3_detect (int ioaddr)
if (opl3_enabled)
ioaddr = left_address;
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /*
* Reset
* timers
* 1
* and
* 2
*/
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /*
* Reset the
* IRQ of FM
* * chicp
*/
/* Reset timers 1 and 2 */
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
stat1 = INB (ioaddr); /*
* Read status register
*/
/* Reset the IRQ of the FM chip */
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
signature = stat1 = INB (ioaddr); /* Status register */
if ((stat1 & 0xE0) != 0x00)
{
@ -225,23 +218,19 @@ opl3_detect (int ioaddr)
*/
}
opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /*
* Set timer 1 to
* 0xff
*/
opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */
opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
TIMER2_MASK | TIMER1_START); /*
* Unmask and start timer 1
*/
/*
* Now we have to delay at least 80 msec
* Now we have to delay at least 80 usec
*/
for (i = 0; i < 50; i++)
tenmicrosec (); /*
* To be sure
*/
tenmicrosec ();
stat2 = INB (ioaddr); /*
* Read status after timers have expired
@ -251,18 +240,10 @@ opl3_detect (int ioaddr)
* Stop the timers
*/
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /*
* Reset
* timers
* 1
* and
* 2
*/
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /*
* Reset the
* IRQ of FM
* * chicp
*/
/* Reset timers 1 and 2 */
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
/* Reset the IRQ of the FM chip */
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
if ((stat2 & 0xE0) != 0xc0)
{
@ -272,9 +253,41 @@ opl3_detect (int ioaddr)
}
/*
* There is a FM chicp in this address. Now set some default values.
* There is a FM chicp in this address. Detect the type (OPL2 to OPL4)
*/
if (signature == 0x06) /* OPL2 */
{
opl3_enabled = 0;
}
else if (signature == 0x00) /* OPL3 or OPL4 */
{
unsigned char tmp;
if (!opl3_enabled) /* Was not already enabled */
{
left_address = ioaddr;
right_address = ioaddr + 2;
opl3_enabled = 1;
}
/*
* Detect availability of OPL4 (_experimental_). Works propably
* only after a cold boot. In addition the OPL4 port
* of the chip may not be connected to the PC bus at all.
*/
opl3_command (right_address, OPL3_MODE_REGISTER, 0x00);
opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE);
if ((tmp = INB (ioaddr)) == 0x02) /* Have a OPL4 */
{
opl4_enabled = 1;
}
opl3_command (right_address, OPL3_MODE_REGISTER, 0);
}
for (i = 0; i < 9; i++)
opl3_command (ioaddr, KEYON_BLOCK + i, 0); /*
* Note off
@ -373,14 +386,14 @@ char fm_volume_table[128] =
-11, -11, -10, -10, -10, -9, -9, -8, /*
* 24 - 31
*/
-8, -8, -7, -7, -7, -6, -6, -6,/*
* 32 - 39
-8, -8, -7, -7, -7, -6, -6, -6, /*
* 32 - 39
*/
-5, -5, -5, -5, -4, -4, -4, -4,/*
* 40 - 47
-5, -5, -5, -5, -4, -4, -4, -4, /*
* 40 - 47
*/
-3, -3, -3, -3, -2, -2, -2, -2,/*
* 48 - 55
-3, -3, -3, -3, -2, -2, -2, -2, /*
* 48 - 55
*/
-2, -1, -1, -1, -1, 0, 0, 0, /*
* 56 - 63
@ -472,13 +485,13 @@ set_voice_volume (int voice, int volume)
calc_vol (&vol2, volume);
}
opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /*
* Modulator
* volume
opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /*
* Modulator
* volume
*/
opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /*
* Carrier
* volume
opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /*
* Carrier
* volume
*/
}
else
@ -525,7 +538,7 @@ set_voice_volume (int voice, int volume)
default: /*
* Why ??
*/ ;
*/ ;
}
opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
@ -857,12 +870,23 @@ opl3_reset (int dev)
static int
opl3_open (int dev, int mode)
{
int i;
if (!opl3_ok)
return RET_ERROR (ENXIO);
if (opl3_busy)
return RET_ERROR (EBUSY);
opl3_busy = 1;
voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
voice_alloc->timestamp = 0;
for (i = 0; i < 18; i++)
{
voice_alloc->map[i] = 0;
voice_alloc->alloc_times[i] = 0;
}
connection_mask = 0x00; /*
* Just 2 OP voices
*/
@ -876,6 +900,7 @@ opl3_close (int dev)
{
opl3_busy = 0;
voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
fm_info.nr_drums = 0;
fm_info.perc_mode = 0;
@ -1075,7 +1100,7 @@ opl3_bender (int dev, int voice, int value)
static int
opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
{
int i, p, avail_voices;
int i, p, best, first, avail_voices, best_time = 0x7fffffff;
struct sbi_instrument *instr;
int is4op;
int instr_no;
@ -1096,21 +1121,22 @@ opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
if (is4op)
{
p = 0;
first = p = 0;
avail_voices = 6;
}
else
{
if (nr_voices == 12) /* 4 OP mode. Use the '2 OP only' voices first */
p = 6;
first = p = 6;
else
p = 0;
first = p = 0;
avail_voices = nr_voices;
}
/*
* Now try to find a free voice
*/
* Now try to find a free voice
*/
best = first;
for (i = 0; i < avail_voices; i++)
{
@ -1118,15 +1144,36 @@ opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
{
return p;
}
p = (p + 1) % nr_voices;
if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */
{
best_time = alloc->alloc_times[p];
best = p;
}
p = (p + 1) % avail_voices;
}
/*
* Insert some kind of priority mechanism here.
*/
* Insert some kind of priority mechanism here.
*/
printk ("OPL3: Out of free voices\n");
return 0; /* All voices in use. Select the first one. */
if (best < 0)
best = 0;
if (best > nr_voices)
best -= nr_voices;
return best; /* All voices in use. Select the first one. */
}
static void
opl3_setup_voice (int dev, int voice, int chn)
{
struct channel_info *info =
&synth_devs[dev]->chn_info[chn];
opl3_set_instr (dev, voice,
info->pgm_num);
voices[voice].bender = info->bender_value;
}
static struct synth_operations opl3_operations =
@ -1150,7 +1197,8 @@ static struct synth_operations opl3_operations =
opl3_volume_method,
opl3_patchmgr,
opl3_bender,
opl3_alloc_voice
opl3_alloc_voice,
opl3_setup_voice
};
long
@ -1174,18 +1222,22 @@ opl3_init (long mem_start)
opl3_ok = 1;
if (opl3_enabled)
{
#ifdef __FreeBSD__
printk ("opl0: <Yamaha OPL-3 FM>");
if (opl4_enabled)
#if defined(__FreeBSD__)
printk ("opl0: <Yamaha OPL4/OPL3 FM>");
else
printk ("opl0: <Yamaha OPL-3 FM>");
#else
printk (" <Yamaha OPL-3 FM>");
printk (" <Yamaha OPL4/OPL3 FM>");
else
printk (" <Yamaha OPL-3 FM>");
#endif
fm_model = 2;
voice_alloc->max_voice = nr_voices = 18;
fm_info.nr_drums = 0;
fm_info.capabilities |= SYNTH_CAP_OPL3;
#ifndef SCO
strcpy (fm_info.name, "Yamaha OPL-3");
#endif
for (i = 0; i < 18; i++)
if (physical_voices[i].ioaddr == USE_LEFT)
@ -1193,15 +1245,23 @@ opl3_init (long mem_start)
else
physical_voices[i].ioaddr = right_address;
/* Enable OPL-3 mode */
opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE);
/* Select all 2-OP voices */
opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00);
opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE); /*
* Enable
* OPL-3
* mode
*/
opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00); /*
* Select
* all
* 2-OP
* *
* voices
*/
}
else
{
#ifdef __FreeBSD__
#if defined(__FreeBSD__)
printk ("opl0: <Yamaha 2-OP FM>");
#else
printk (" <Yamaha 2-OP FM>");

View file

@ -24,7 +24,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: opl3.c,v 1.7 1994/10/01 02:16:50 swallace Exp
*/
/*
@ -36,8 +35,8 @@
*
* The percussive mode is implemented in the left side only.
*
* With the above exceptions the both sides can be operated independently.
*
* With the above exeptions the both sides can be operated independently.
*
* A 4 OP voice can be created by setting the corresponding
* bit at offset 4 of the right side.
*
@ -46,7 +45,7 @@
* voice is made inaccessible.
*
* If a voice is set to the 2 OP mode, it works like 2 OP modes
* of the original YM3812 (AdLib). In addition the voice can
* of the original YM3812 (AdLib). In addition the voice can
* be connected the left, right or both stereo channels. It can
* even be left unconnected. This works with 4 OP voices also.
*
@ -81,6 +80,7 @@
#define OPL3_MODE_REGISTER 0x05 /* Right side */
#define OPL3_ENABLE 0x01
#define OPL4_ENABLE 0x02
#define KBD_SPLIT_REGISTER 0x08 /* Left side */
#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */
@ -179,13 +179,13 @@
* 0 0 >+-1-+--2--3--4-->
*
*
*
*
* +---+
* | |
* 0 1 >+-1-+--2-+
* |->
* >--3----4-+
*
*
* +---+
* | |
* 1 0 >+-1-+-----+

View file

@ -3,29 +3,6 @@
/*
* OS specific settings for FreeBSD
*
* Copyright by UWM - comments to soft-eng@cs.uwm.edu
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
*
* This chould be used as an example when porting the driver to a new
* operating systems.
*
@ -35,9 +12,7 @@
*
* If you have to make changes to other than these two files, please contact me
* before making the changes. It's possible that I have already made the
* change.
*
* os.h,v 1.13 1994/10/01 02:16:53 swallace Exp
* change.
*/
/*
@ -59,38 +34,47 @@
#include <i386/isa/isa_device.h>
#include <machine/cpufunc.h>
/* These few lines are used by 386BSD (only??). */
#if NSND > 0
#define CONFIGURE_SOUNDCARD
#else
#undef CONFIGURED_SOUNDCARD
#endif
/*
* Rest of the file is compiled only if the driver is really required.
*/
#ifdef CONFIGURE_SOUNDCARD
/*
/*
* select() is currently implemented in Linux specific way. Don't enable.
* I don't remember what the SHORT_BANNERS means so forget it.
*/
#undef ALLOW_SELECT
/*#undef ALLOW_SELECT*/
#define SHORT_BANNERS
/* The soundcard.h could be in a nonstandard place so inclyde it here. */
#include <machine/soundcard.h>
#include "soundcard.h"
/*
* Here is the first portability problem. Every OS has it's own way to
* pass a pointer to the buffer in read() and write() calls. In Linux it's
* just a char*. In BSD it's struct uio. This parameter is passed to
* all functions called from read() or write(). Since nothing can be
* all functions called from read() or write(). Since nothing can be
* assumed about this structure, the driver uses set of macros for
* accessing the user buffer.
* accessing the user buffer.
*
* The driver reads/writes bytes in the user buffer sequentially which
* means that calls like uiomove() can be used.
*
* snd_rw_buf is the type which is passed to the device file specific
* read() and write() calls.
*
*
* The following macros are used to move date to and from the
* user buffer. These macros should be used only when the
* user buffer. These macros should be used only when the
* target or source parameter has snd_rw_buf type.
* The offs parameter is a offset relative to the beginning of
* the user buffer. In Linux the offset is required but for example
@ -107,15 +91,17 @@ typedef struct uio snd_rw_buf;
* user space. The count is number of bytes to be moved.
*/
#define COPY_FROM_USER(target, source, offs, count) \
do { if (uiomove(target, count, (struct uio *)source)) { \
do { if (uiomove((caddr_t ) target, count, (struct uio *)source)) { \
printf ("sb: Bad copyin()!\n"); \
} } while(0)
/* Like COPY_FOM_USER but for writes. */
#define COPY_TO_USER(target, offs, source, count) \
do { if (uiomove(source, count, (struct uio *)target)) { \
printf ("sb: Bad copyout()!\n"); \
} } while(0)
/*
/*
* The following macros are like COPY_*_USER but work just with one byte (8bit),
* short (16 bit) or long (32 bit) at a time.
* The same restrictions apply than for COPY_*_USER
@ -125,6 +111,9 @@ typedef struct uio snd_rw_buf;
#define GET_WORD_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 4, (struct uio *)addr);}
#define PUT_WORD_TO_USER(addr, offs, data) {uiomove((char*)&(data), 4, (struct uio *)addr);}
#define EREMOTEIO -1
/*
* The way how the ioctl arguments are passed is another nonportable thing.
* In Linux the argument is just a pointer directly to the user segment. On
@ -161,8 +150,9 @@ typedef struct uio snd_rw_buf;
*/
struct snd_wait {
int mode; int aborting;
};
int mode;
int aborting;
};
/*
* DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define
@ -185,7 +175,7 @@ struct snd_wait {
* is aborts the process. This macro is called from close() to see if the
* buffers should be discarded. If this kind info is not available, a constant
* 1 or 0 could be returned (1 should be better than 0).
* I'm not sure if the following is correct for FreeBSD.
* I'm not sure if the following is correct for 386BSD.
*/
#define PROCESS_ABORTING(q, f) (f.aborting | curproc->p_siglist)
@ -194,7 +184,7 @@ struct snd_wait {
* the process is resumed if it receives a signal. The following is propably
* not the way how it should be done on 386bsd.
* The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE(),
* and the second is a workarea parameter. The third is a timeout
* and the second is a workarea parameter. The third is a timeout
* in ticks. Zero means no timeout.
*/
#define DO_SLEEP(q, f, time_limit) \
@ -202,13 +192,13 @@ struct snd_wait {
int flag, chn; \
f.mode = WK_SLEEP; \
q = &chn; \
flag=tsleep((caddr_t)&(chn), (PRIBIO-5)|PCATCH, "sndint", time_limit); \
flag=tsleep((caddr_t) &chn, (PRIBIO-5)|PCATCH, "sndint", time_limit); \
if(flag == ERESTART) f.aborting = 1;\
else f.aborting = 0;\
f.mode &= ~WK_SLEEP; \
}
/* An the following wakes up a process */
#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wakeup((caddr_t)q);}
#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wakeup((caddr_t) q);}
/*
* Timing macros. This driver assumes that there is a timer running in the
@ -220,11 +210,12 @@ struct snd_wait {
#define HZ hz
#endif
/*
/*
* GET_TIME() returns current value of the counter incremented at timer
* ticks. This can overflow, so the timeout might be real big...
*
*
*/
extern unsigned long get_time(void);
#define GET_TIME() get_time()
/*#define GET_TIME() (lbolt) */ /* Returns current time (1/HZ secs since boot) */
@ -250,11 +241,19 @@ extern unsigned long get_time(void);
*/
#define INB inb
/*
#define INW inb
#if 0
/*
* The outb(0, 0x80) is just for slowdown. It's bit unsafe since
* this address could be used for something usefull.
*/
#define OUTB(addr, data) {outb(data, addr);outb(0, 0x80);}
#define OUTW(addr, data) {outw(data, addr);outb(0, 0x80);}
#else
#define OUTB(addr, data) outb(data, addr)
#define OUTW(addr, data) outw(data, addr)
#endif
/* memcpy() was not defined og 386bsd. Lets define it here */
#define memcpy(d, s, c) bcopy(s, d, c)
@ -267,9 +266,9 @@ extern unsigned long get_time(void);
#define RET_ERROR(err) -(err)
/*
KERNEL_MALLOC() allocates requested number of memory and
KERNEL_FREE is used to free it.
/*
KERNEL_MALLOC() allocates requested number of memory and
KERNEL_FREE is used to free it.
These macros are never called from interrupt, in addition the
nbytes will never be more than 4096 bytes. Generally the driver
will allocate memory in blocks of 4k. If the kernel has just a
@ -289,8 +288,8 @@ extern unsigned long get_time(void);
* memory area. The type is the type of the mem_ptr.
*/
#define PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) \
{(mem_ptr) = (typecast)malloc((size), M_DEVBUF, M_NOWAIT); \
if (!(mem_ptr))panic("SOUND: Cannot allocate memory");}
{mem_ptr = (typecast)malloc(size, M_DEVBUF, M_NOWAIT); \
if (!mem_ptr)panic("SOUND: Cannot allocate memory\n");}
/*
* The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if
@ -310,11 +309,41 @@ extern unsigned long get_time(void);
* The rest of this file is not complete yet. The functions using these
* macros will not work
*/
#define ALLOC_DMA_CHN(chn) ({ 0; })
#define ALLOC_DMA_CHN(chn,deviceID) ({0; } )
#define RELEASE_DMA_CHN(chn) ({ 0; })
#define DMA_MODE_READ 0
#define DMA_MODE_WRITE 1
#define RELEASE_IRQ(irq_no)
/*
* The macro DECLARE_FILE() adds an entry to struct fileinfo referencing the
* connected filestructure.
* This entry must be initialized in sound_open() in soundcard.c
*
* ISSET_FILE_FLAG() allows checking of flags like O_NONBLOCK on files
*
*/
#define DECLARE_FILE() struct file *filp
#ifdef notdef
#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->filp->f_flag & (flag) ? \
1 : 0)
#else
#define ISSET_FILE_FLAG(fileinfo, flag) 0
#endif
#define INT_HANDLER_PROTO() void(*hndlr)(int)
#define INT_HANDLER_PARMS(irq, parms) int irq
#define INT_HANDLER_CALL(irq) irq
/*
* For select call...
*/
#ifdef ALLOW_SELECT
typedef struct proc select_table;
#define SEL_IN FREAD
#define SEL_OUT FWRITE
#define SEL_EX 0
extern struct selinfo selinfo[];
#endif
#endif
#endif

View file

@ -1,6 +1,3 @@
/*
* pas.h,v 1.6 1994/10/01 12:42:17 ache Exp
*/
/* */
/* Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards. */
/* */
@ -45,9 +42,11 @@
#define WAIT_STATE 0xBF88 /* R W Control Four-bit bus wait-state count (~140ns ea.) */
#define BOARD_REV_ID 0x2789 /* R Control Extended Board Revision ID */
#define CHIP_REV 0xFF88 /* R 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */
#define SYSTEM_CONFIGURATION_1 0x8388 /* R W Control */
#define S_C_1_PCS_ENABLE 0x01 /* R W PC speaker 1=enable, 0=disable PC speaker emulation */
#define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */
#define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */
#define S_C_1_FM_EMULATE_CLOCK 0x04 /* R W FM 1=use 28.224Mhz/2, 0=use 14.31818Mhz clock */
#define S_C_1_PCS_STEREO 0x10 /* R W PC speaker 1=enable PC speaker stereo effect, 0=disable */
#define S_C_1_PCS_REALSOUND 0x20 /* R W PC speaker 1=enable RealSound enhancement, 0=disable */
@ -62,6 +61,7 @@
#define IO_CONFIGURATION_1 0xF388 /* R W Control */
#define I_C_1_BOOT_RESET_ENABLE 0x80 /* R W Control 1=reset board on warm boot, 0=don't */
#define I_C_1_JOYSTICK_ENABLE 0x40 /* R W Control 1=enable joystick port, 0=don't */
#define IO_CONFIGURATION_2 0xF389 /* R W Control */
#define I_C_2_PCM_DMA_DISABLED 0x00 /* R W PCM PCM DMA disabled */
#define IO_CONFIGURATION_3 0xF38A /* R W Control */
@ -83,7 +83,7 @@
#define OPERATION_MODE_1 0xEF8B /* R Control */
#define O_M_1_CDROM_TYPE 0x03 /* R CD-ROM 3=SCSI, 2=Sony, 0=no CD-ROM interface */
#define O_M_1_FM_TYPE 0x04 /* R FM 1=stereo, 0=mono FM chip */
#define O_M_1_FM_TYPE 0x04 /* R FM 1=sterero, 0=mono FM chip */
#define O_M_1_PCM_TYPE 0x08 /* R PCM 1=16-bit Codec, 0=8-bit DAC */
#define OPERATION_MODE_2 0xFF8B /* R Control */
#define O_M_2_PCS_ENABLED 0x02 /* R PC speaker PC speaker emulation 1=enabled, 0=disabled */
@ -114,7 +114,7 @@
struct { /* R W Mixer Filter translation */
unsigned int freq:24;
unsigned int value:8;
} F_F_FILTER_translate[] =
} F_F_FILTER_translate[] =
{ { 73500, 0x01 }, /* 73500Hz - divide by 16 */
{ 65333, 0x02 }, /* 65333Hz - divide by 18 */
{ 49000, 0x09 }, /* 49000Hz - divide by 24 */
@ -131,7 +131,6 @@
#define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */
#define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */
#define CHIP_REV 0xFF88 /* R Control 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */
#define PAS_NONE 0
#define PAS_PLUS 1
#define PAS_CDPC 2
@ -142,7 +141,7 @@
unsigned char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */
{ 4, 1, 2, 3, 0, 5, 6, 7 };
unsigned char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */
{ 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 };
{ 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 };
unsigned char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */
{ 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 };
unsigned char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */
@ -150,7 +149,7 @@
unsigned char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */
{ 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
unsigned char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 };
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 };
#else
extern unsigned char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */
extern unsigned char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */
@ -251,4 +250,4 @@
#define MIDI_FIFO_STATUS 0x1B89 /* R W MIDI Midi fifo status */
#define MIDI_DATA 0x178A /* R W MIDI Midi data register */
#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */
#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */

View file

@ -26,7 +26,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* pas2_card.c,v 1.11 1994/10/01 12:42:17 ache Exp
*/
#include "sound_config.h"
@ -45,11 +44,11 @@ int translat_code;
static int pas_intr_mask = 0;
static int pas_irq = 0;
static char pas_model;
static unsigned char board_rev_id;
char pas_model;
static char *pas_model_names[] =
{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
extern void mix_write (unsigned char data, int ioaddr);
/*
* pas_read() and pas_write() are equivalents of INB() and OUTB()
*/
@ -72,23 +71,6 @@ pas_write (unsigned char data, int ioaddr)
OUTB (data, ioaddr ^ translat_code);
}
/*
* The Revision D cards have a problem with their MVA508 interface. The
* kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
* MSBs out of the output byte and to do a 16-bit out to the mixer port -
* 1.
*/
void
mix_write (unsigned char data, int ioaddr)
{
if (pas_model == PAS_16D) {
outw ((ioaddr ^ translat_code) - 1, data | (data << 8));
outb (0, 0x80);
} else
OUTB (data, ioaddr ^ translat_code);
}
void
pas2_msg (char *foo)
{
@ -98,13 +80,13 @@ pas2_msg (char *foo)
/******************* Begin of the Interrupt Handler ********************/
void
pasintr (int unused)
pasintr (INT_HANDLER_PARMS (irq, dummy))
{
int status;
status = pas_read (INTERRUPT_STATUS);
pas_write (status, INTERRUPT_STATUS); /*
* Clear interrupt
pas_write (status, INTERRUPT_STATUS); /*
* Clear interrupt
*/
if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
@ -136,7 +118,7 @@ pas_set_intr (int mask)
if (!pas_intr_mask)
{
if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0)
if ((err = snd_set_irq_handler (pas_irq, pasintr, "PAS16")) < 0)
return err;
}
pas_intr_mask |= mask;
@ -201,9 +183,13 @@ config_pas_hw (struct address_info *hw_config)
pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /*
* |
* S_M_OPL3_DUAL_MONO
*/ , SERIAL_MIXER);
*/ , SERIAL_MIXER);
pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1);
pas_write (I_C_1_BOOT_RESET_ENABLE
#ifdef PAS_JOYSTICK_ENABLE
| I_C_1_JOYSTICK_ENABLE
#endif
,IO_CONFIGURATION_1);
if (pas_irq < 0 || pas_irq > 15)
{
@ -238,9 +224,9 @@ config_pas_hw (struct address_info *hw_config)
}
/*
* This fixes the timing problems of the PAS due to the Symphony chipset
* as per Media Vision. Only define this if your PAS doesn't work correctly.
*/
* This fixes the timing problems of the PAS due to the Symphony chipset
* as per Media Vision. Only define this if your PAS doesn't work correctly.
*/
#ifdef SYMPHONY_PAS
OUTB (0x05, 0xa8);
OUTB (0x60, 0xa9);
@ -380,14 +366,13 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
if (detect_pas_hw (hw_config))
{
board_rev_id = pas_read (BOARD_REV_ID);
if (pas_model = pas_read (CHIP_REV))
if (pas_model = pas_read (CHIP_REV))
{
#ifdef __FreeBSD__
printk ("pas0: <%s rev %d>", pas_model_names[(int) pas_model], board_rev_id);
#else /* __FreeBSD__ */
printk ("pas0: <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
#else
printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
#endif /* __FreeBSD__ */
#endif
}
if (config_pas_hw (hw_config))

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* pas2_midi.c,v 1.6 1994/10/01 02:16:55 swallace Exp
*/
#include "sound_config.h"
@ -84,8 +83,8 @@ pas_midi_open (int dev, int mode,
if (mode == OPEN_READ || mode == OPEN_READWRITE)
{
ctrl |= M_C_ENA_INPUT_IRQ;/*
* Enable input
ctrl |= M_C_ENA_INPUT_IRQ; /*
* Enable input
*/
input_opened = 1;
}
@ -135,9 +134,9 @@ dump_to_midi (unsigned char midi_byte)
fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /*
* Fifo
* full
if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /*
* Fifo
* full
*/
{
return 0; /*
@ -240,6 +239,7 @@ static struct midi_operations pas_midi_operations =
{
{"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
&std_midi_synth,
{0},
pas_midi_open,
pas_midi_close,
pas_midi_ioctl,
@ -320,8 +320,10 @@ pas_midi_interrupt (void)
RESTORE_INTR (flags);
}
#if 0
if (stat & M_S_FRAMING_ERROR)
printk ("MIDI framing error\n");
#endif
if (stat & M_S_OUTPUT_OVERRUN)
{
@ -329,8 +331,8 @@ pas_midi_interrupt (void)
ofifo_bytes = 100;
}
pas_write (stat, MIDI_STATUS);/*
* Acknowledge interrupts
pas_write (stat, MIDI_STATUS); /*
* Acknowledge interrupts
*/
}

View file

@ -27,7 +27,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: pas2_mixer.c,v 1.7 1994/10/01 02:16:56 swallace Exp $
*/
#include "sound_config.h"
@ -36,18 +35,12 @@
#include "pas.h"
#define TRACE(what) /*
* * * (what) */
#define TRACE(what) /* (what) */
extern int translat_code;
extern char pas_model;
static int rec_devices = (SOUND_MASK_MIC); /*
* * * * Default *
* recording * source
*
* * */
static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */
static int mode_control = 0;
#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
@ -60,53 +53,48 @@ static int mode_control = 0;
static unsigned short levels[SOUND_MIXER_NRDEVICES] =
{
0x3232, /*
* Master Volume
*/
0x3232, /*
* Bass
*/
0x3232, /*
* Treble
*/
0x5050, /*
* FM
*/
0x4b4b, /*
* PCM
*/
0x3232, /*
* PC Speaker
*/
0x4b4b, /*
* Ext Line
*/
0x4b4b, /*
* Mic
*/
0x4b4b, /*
* CD
*/
0x6464, /*
* Recording monitor
*/
0x4b4b, /*
* SB PCM
*/
0x6464}; /*
0x3232, /* Master Volume */
0x3232, /* Bass */
0x3232, /* Treble */
0x5050, /* FM */
0x4b4b, /* PCM */
0x3232, /* PC Speaker */
0x4b4b, /* Ext Line */
0x4b4b, /* Mic */
0x4b4b, /* CD */
0x6464, /* Recording monitor */
0x4b4b, /* SB PCM */
0x6464 /* Recording level */
};
void
mix_write (unsigned char data, int ioaddr)
{
/*
* The Revision D cards have a problem with their MVA508 interface. The
* kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
* MSBs out of the output byte and to do a 16-bit out to the mixer port -
* 1. We need to do this because it isn't timing problem but chip access
* sequence problem.
*/
* * * * Recording level */
if (pas_model == PAS_16D)
{
OUTW (data | (data << 8), (ioaddr ^ translat_code) - 1);
OUTB (0x80, 0);
}
else
pas_write (data, ioaddr);
}
static int
mixer_output (int right_vol, int left_vol, int div, int bits,
int mixer /*
* Input or output mixer
*/ )
int mixer) /* Input or output mixer */
{
int left = left_vol * div / 100;
int right = right_vol * div / 100;
if (bits & P_M_MV508_MIXER)
{ /*
* Select input or output mixer
@ -161,9 +149,7 @@ pas_mixer_set (int whichDev, unsigned int level)
switch (whichDev)
{
case SOUND_MIXER_VOLUME: /*
* Master volume (0-63)
*/
case SOUND_MIXER_VOLUME: /* Master volume (0-63) */
levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
break;
@ -171,62 +157,39 @@ pas_mixer_set (int whichDev, unsigned int level)
* Note! Bass and Treble are mono devices. Will use just the left
* channel.
*/
case SOUND_MIXER_BASS: /*
* Bass (0-12)
*/
case SOUND_MIXER_BASS: /* Bass (0-12) */
levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
break;
case SOUND_MIXER_TREBLE: /*
* Treble (0-12)
*/
case SOUND_MIXER_TREBLE: /* Treble (0-12) */
levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
break;
case SOUND_MIXER_SYNTH: /*
* Internal synthesizer (0-31)
*/
case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
break;
case SOUND_MIXER_PCM: /*
* PAS PCM (0-31)
*/
case SOUND_MIXER_PCM: /* PAS PCM (0-31) */
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
break;
case SOUND_MIXER_ALTPCM: /*
* SB PCM (0-31)
*/
case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
break;
case SOUND_MIXER_SPEAKER: /*
* PC speaker (0-31)
*/
case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
break;
case SOUND_MIXER_LINE: /*
* External line (0-31)
*/
case SOUND_MIXER_LINE: /* External line (0-31) */
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
break;
case SOUND_MIXER_CD: /*
* CD (0-31)
*/
case SOUND_MIXER_CD: /* CD (0-31) */
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
break;
case SOUND_MIXER_MIC: /*
* External microphone (0-31)
*/
case SOUND_MIXER_MIC: /* External microphone (0-31) */
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
break;
case SOUND_MIXER_IMIX: /*
* Recording monitor (0-31) (Only available *
* on the Output Mixer)
*/
case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
P_M_MV508_OUTPUTMIX);
break;
case SOUND_MIXER_RECLEV: /*
* Recording level (0-15)
*/
case SOUND_MIXER_RECLEV: /* Recording level (0-15) */
levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
break;
@ -254,9 +217,7 @@ pas_mixer_set (int whichDev, unsigned int level)
if (level)
mode_control |= P_M_MV508_LOUDNESS;
set_mode (mode_control);
return !!level; /*
* 0 or 1
*/
return !!level; /* 0 or 1 */
break;
case SOUND_MIXER_RECSRC:
@ -306,7 +267,7 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
else
{ /*
* Read parameters
* Read parameters
*/
switch (cmd & 0xff)
@ -329,15 +290,11 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
break;
case SOUND_MIXER_CAPS:
return IOCTL_OUT (arg, 0); /*
* No special capabilities
*/
return IOCTL_OUT (arg, 0); /* No special capabilities */
break;
case SOUND_MIXER_MUTE:
return IOCTL_OUT (arg, 0); /*
* No mute yet
*/
return IOCTL_OUT (arg, 0); /* No mute yet */
break;
case SOUND_MIXER_ENHANCE:
@ -362,6 +319,7 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
static struct mixer_operations pas_mixer_operations =
{
"Pro Audio Spectrum 16",
pas_mixer_ioctl
};

View file

@ -26,7 +26,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* pas2_pcm.c,v 1.7 1994/10/01 02:16:57 swallace Exp
*/
#include "sound_config.h"
@ -79,14 +78,14 @@ pcm_set_speed (int arg)
tmp = pas_read (FILTER_FREQUENCY);
/*
* Set anti-aliasing filters according to sample rate. You really *NEED*
* to enable this feature for all normal recording unless you want to
* experiment with aliasing effects.
* These filters apply to the selected "recording" source.
* I (pfw) don't know the encoding of these 5 bits. The values shown
* come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
*/
/*
* Set anti-aliasing filters according to sample rate. You reall *NEED*
* to enable this feature for all normal recording unless you want to
* experiment with aliasing effects.
* These filters apply to the selected "recording" source.
* I (pfw) don't know the encoding of these 5 bits. The values shown
* come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
*/
#if !defined NO_AUTO_FILTER_SET
tmp &= 0xe0;
if (pcm_speed >= 2 * 17897)
@ -129,8 +128,8 @@ pcm_set_channels (int arg)
pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
pcm_channels = arg;
pcm_set_speed (pcm_speed);/*
* The speed must be reinitialized
pcm_set_speed (pcm_speed); /*
* The speed must be reinitialized
*/
}
@ -405,12 +404,7 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
{
audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;
audio_devs[my_devnum]->dmachan = hw_config->dma;
#ifndef NO_AUTODMA
audio_devs[my_devnum]->buffcount = 1;
#else
audio_devs[my_devnum]->flags &= ~DMA_AUTOMODE;
audio_devs[my_devnum]->buffcount = DSP_BUFFCOUNT;
#endif
audio_devs[my_devnum]->buffsize = 2 * DSP_BUFFSIZE;
}
else

View file

@ -1,7 +1,7 @@
/*
* sound/patmgr.c
*
* The patch manager interface for the /dev/sequencer
* The patch maneger interface for the /dev/sequencer
*
* Copyright by Hannu Savolainen 1993
*
@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* patmgr.c,v 1.7 1994/10/01 02:16:58 swallace Exp
*/
#define PATMGR_C
@ -132,7 +131,7 @@ pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
return RET_ERROR (EIO);
}
COPY_FROM_USER ((caddr_t)mbox[dev], buf, 0, 4);
COPY_FROM_USER (mbox[dev], buf, 0, 4);
if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE)
{
@ -235,8 +234,12 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2,
printk (" PATMGR: Server %d mbox full. Why?\n", dev);
else
{
mbox[dev] =
(struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info));
if ((mbox[dev] =
(struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info))) == NULL)
{
printk ("pmgr: Couldn't allocate memory for a message\n");
return 0;
}
mbox[dev]->key = PM_K_EVENT;
mbox[dev]->command = event;

View file

@ -1,6 +1,3 @@
/*
* sb.h,v 1.2 1994/08/02 07:40:34 davidg Exp
*/
#define DSP_RESET (sbc_base + 0x6)
#define DSP_READ (sbc_base + 0xA)
#define DSP_WRITE (sbc_base + 0xC)

View file

@ -27,7 +27,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* sb16_dsp.c,v 1.8 1994/10/01 02:17:02 swallace Exp
*/
#define DEB(x)
@ -43,11 +42,11 @@
extern int sbc_base;
static int sb16_dsp_ok = 0;/*
static int sb16_dsp_ok = 0; /*
* * * * Set to 1 after successful *
* * initialization */
* * * * Set to 1 after successful *
* * initialization */
static int dsp_16bit = 0;
static int dsp_stereo = 0;
static int dsp_current_speed = 8000; /*
@ -79,6 +78,7 @@ static void sb16_dsp_halt (int dev);
static int dsp_set_speed (int);
static int dsp_set_stereo (int);
static void dsp_cleanup (void);
int sb_reset_dsp (void);
static struct audio_operations sb16_dsp_operations =
{
@ -228,7 +228,7 @@ sb16_dsp_open (int dev, int mode)
sb_reset_dsp ();
if (ALLOC_DMA_CHN (dma8))
if (ALLOC_DMA_CHN (dma8, "SB16 (8bit)"))
{
printk ("SB16: Unable to grab DMA%d\n", dma8);
sb_free_irq ();
@ -236,7 +236,7 @@ sb16_dsp_open (int dev, int mode)
}
if (dma16 != dma8)
if (ALLOC_DMA_CHN (dma16))
if (ALLOC_DMA_CHN (dma16, "SB16 (16bit)"))
{
printk ("SB16: Unable to grab DMA%d\n", dma16);
sb_free_irq ();
@ -436,6 +436,7 @@ sb16_dsp_halt (int dev)
sb_dsp_command01 (0xda);
sb_dsp_command01 (0xd0);
}
DMAbuf_reset_dma (dev);
}
static void
@ -472,12 +473,10 @@ sb16_dsp_init (long mem_start, struct address_info *hw_config)
if (sbc_major < 4)
return mem_start; /* Not a SB16 */
#ifndef SCO
sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
#endif
#ifdef __FreeBSD__
printk ("sbxvi0: <%s>", sb16_dsp_operations.name);
#if defined(__FreeBSD__)
printk ("sbxvo0: <%s>", sb16_dsp_operations.name);
#else
printk (" <%s>", sb16_dsp_operations.name);
#endif
@ -486,12 +485,7 @@ sb16_dsp_init (long mem_start, struct address_info *hw_config)
{
audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations;
audio_devs[my_dev]->dmachan = hw_config->dma;
#ifndef NO_AUTODMA
audio_devs[my_dev]->buffcount = 1;
#else
audio_devs[my_dev]->flags &= ~DMA_AUTOMODE;
audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT;
#endif
audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
}
else
@ -541,8 +535,8 @@ sb16_dsp_detect (struct address_info *hw_config)
DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
/*
* dsp_showmessage(0xe3,99);
*/
* dsp_showmessage(0xe3,99);
*/
sb16_dsp_ok = 1;
return 1;
}

View file

@ -25,14 +25,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* sb16_midi.c,v 1.4 1994/10/01 02:17:03 swallace Exp
*/
#include "sound_config.h"
#ifdef CONFIGURE_SOUNDCARD
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16MIDI) && !defined(EXCLUDE_MIDI)
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
#include "sb.h"
@ -181,6 +180,7 @@ static struct midi_operations sb16midi_operations =
{
{"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI},
&std_midi_synth,
{0},
sb16midi_open,
sb16midi_close,
sb16midi_ioctl,
@ -225,11 +225,7 @@ attach_sb16midi (long mem_start, struct address_info *hw_config)
return mem_start;
}
#ifdef __FreeBSD__
printk ("sbmidi: <SoundBlaster MPU-401>");
#else
printk (" <SoundBlaster MPU-401>");
#endif
std_midi_synth.midi_dev = my_dev = num_midis;
midi_devs[num_midis++] = &sb16midi_operations;

View file

@ -25,7 +25,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* sb_card.c,v 1.5 1994/08/02 07:40:39 davidg Exp
* Modified:
* Riccardo Facchetti 24 Mar 1995
* - Added the Audio Excel DSP 16 initialization routine.
*/
#include "sound_config.h"
@ -47,6 +49,12 @@ attach_sb_card (long mem_start, struct address_info *hw_config)
int
probe_sb (struct address_info *hw_config)
{
#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_SBPRO)
/*
* Initialize Audio Excel DSP 16 to SBPRO.
*/
InitAEDSP16_SBPRO (hw_config);
#endif
return sb_dsp_detect (hw_config);
}

View file

@ -26,10 +26,11 @@
* SUCH DAMAGE.
*
* Modified:
* Hunyue Yau Jan 6 1994
* Added code to support Sound Galaxy NX Pro
* Hunyue Yau Jan 6 1994
* Added code to support Sound Galaxy NX Pro
*
* $Id: sb_dsp.c,v 1.22 1994/12/10 22:55:50 ats Exp $
* JRA Gibson April 1995
* Code added for MV ProSonic/Jazz 16 in 16 bit mode
*/
#include "sound_config.h"
@ -43,6 +44,7 @@
int sbc_base = 0;
static int sbc_irq = 0;
static int open_mode = 0; /* Read, write or both */
int Jazz16_detected = 0;
/*
* The DSP channel can be used either for input or output. Variable
@ -84,6 +86,21 @@ volatile int sb_irq_mode = IMODE_NONE; /*
* IMODE_NONE */
static volatile int irq_ok = 0;
#ifdef JAZZ16
/* 16 bit support
*/
static int dsp_16bit = 0;
static int dma8 = 1;
static int dma16 = 5;
static int dsp_set_bits (int arg);
static int initialize_ProSonic16 (void);
/* end of 16 bit support
*/
#endif
int sb_duplex_midi = 0;
static int my_dev = 0;
@ -104,8 +121,8 @@ sb_dsp_command (unsigned char val)
int i;
unsigned long limit;
limit = GET_TIME () + HZ / 10;/*
* The timeout is 0.1 seconds
limit = GET_TIME () + HZ / 10; /*
* The timeout is 0.1 secods
*/
/*
@ -131,27 +148,22 @@ sb_dsp_command (unsigned char val)
}
void
sbintr (int unit)
sbintr (INT_HANDLER_PARMS (irq, dummy))
{
int status;
#ifndef EXCLUDE_SBPRO
if (sb16)
{
unsigned char src = sb_getmixer (IRQ_STAT); /*
* * * * Interrupt
* source * *
* register */
unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */
#ifndef EXCLUDE_SB16
if (src & 3)
sb16_dsp_interrupt (unit);
sb16_dsp_interrupt (irq);
#ifndef EXCLUDE_MIDI
if (src & 4)
sb16midiintr (unit); /*
sb16midiintr (irq); /*
* SB MPU401 interrupt
*/
#endif
@ -160,13 +172,13 @@ sbintr (int unit)
if (!(src & 1))
return; /*
* Not a DSP interrupt
* Not a DSP interupt
*/
}
#endif
status = INB (DSP_DATA_AVAIL);/*
* Clear interrupt
status = INB (DSP_DATA_AVAIL); /*
* Clear interrupt
*/
if (sb_intr_active)
@ -192,7 +204,7 @@ sbintr (int unit)
case IMODE_MIDI:
#ifndef EXCLUDE_MIDI
sb_midi_interrupt (unit);
sb_midi_interrupt (irq);
#endif
break;
@ -209,7 +221,7 @@ sb_get_irq (void)
int ok;
if (!sb_irq_usecount)
if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0)
if ((ok = snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster")) < 0)
return ok;
sb_irq_usecount++;
@ -282,16 +294,16 @@ dsp_speed (int speed)
speed = 4000;
/*
* Older SB models don't support higher speeds than 22050.
*/
* Older SB models don't support higher speeds than 22050.
*/
if (sbc_major < 2 ||
(sbc_major == 2 && sbc_minor == 0))
max_speed = 22050;
/*
* SB models earlier than SB Pro have low limit for the input speed.
*/
* SB models earlier than SB Pro have low limit for the input speed.
*/
if (open_mode != OPEN_WRITE) /* Recording is possible */
if (sbc_major < 3) /* Limited input speed with these cards */
if (sbc_major == 2 && sbc_minor > 0)
@ -304,11 +316,14 @@ dsp_speed (int speed)
* Invalid speed
*/
if (dsp_stereo && speed > 22050)
speed = 22050;
/* Logitech SoundMan Games and Jazz16 cards can support 44.1kHz stereo */
#if !defined (SM_GAMES)
/*
* Max. stereo speed is 22050
*/
if (dsp_stereo && speed > 22050 && Jazz16_detected == 0)
speed = 22050;
#endif
if ((speed > 22050) && sb_midi_busy)
{
@ -349,7 +364,7 @@ dsp_speed (int speed)
tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
DISABLE_INTR (flags);
if (sb_dsp_command (0x40))/*
if (sb_dsp_command (0x40)) /*
* Set time constant
*/
sb_dsp_command (tconst);
@ -409,14 +424,14 @@ sb_dsp_output_block (int dev, unsigned long buf, int count,
if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
if (sb_dsp_command (0x48))/*
* High speed size
if (sb_dsp_command (0x48)) /*
* High speed size
*/
{
sb_dsp_command ((unsigned char) (count & 0xff));
sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
sb_dsp_command (0x91);/*
* High speed 8 bit DAC
sb_dsp_command (0x91); /*
* High speed 8 bit DAC
*/
}
else
@ -426,8 +441,8 @@ sb_dsp_output_block (int dev, unsigned long buf, int count,
else
{
DISABLE_INTR (flags);
if (sb_dsp_command (0x14))/*
* 8-bit DAC (DMA)
if (sb_dsp_command (0x14)) /*
* 8-bit DAC (DMA)
*/
{
sb_dsp_command ((unsigned char) (count & 0xff));
@ -463,14 +478,14 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
if (sb_dsp_command (0x48))/*
* High speed size
if (sb_dsp_command (0x48)) /*
* High speed size
*/
{
sb_dsp_command ((unsigned char) (count & 0xff));
sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
sb_dsp_command (0x99);/*
* High speed 8 bit ADC
sb_dsp_command (0x99); /*
* High speed 8 bit ADC
*/
}
else
@ -480,8 +495,8 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
else
{
DISABLE_INTR (flags);
if (sb_dsp_command (0x24))/*
* 8-bit ADC (DMA)
if (sb_dsp_command (0x24)) /*
* 8-bit ADC (DMA)
*/
{
sb_dsp_command ((unsigned char) (count & 0xff));
@ -511,11 +526,23 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount)
* SB Pro
*/
{
#ifdef JAZZ16
/* Select correct dma channel
* for 16/8 bit acccess
*/
audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
if (dsp_stereo)
sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
else
sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
#else
/* 8 bit only cards use this
*/
if (dsp_stereo)
sb_dsp_command (0xa8);
else
sb_dsp_command (0xa0);
#endif
dsp_speed (dsp_current_speed); /*
* Speed must be recalculated if
* #channels * changes
@ -535,7 +562,19 @@ sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
* SB Pro
*/
{
#ifdef JAZZ16
/* 16 bit specific instructions
*/
audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
if (Jazz16_detected != 2) /* SM Wave */
sb_mixer_set_stereo (dsp_stereo);
if (dsp_stereo)
sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
else
sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
#else
sb_mixer_set_stereo (dsp_stereo);
#endif
dsp_speed (dsp_current_speed); /*
* Speed must be recalculated if
* #channels * changes
@ -616,12 +655,28 @@ sb_dsp_open (int dev, int mode)
if (retval)
return retval;
/* Allocate 8 bit dma
*/
if (DMAbuf_open_dma (dev) < 0)
{
sb_free_irq ();
printk ("SB: DMA Busy\n");
return RET_ERROR (EBUSY);
}
#ifdef JAZZ16
/* Allocate 16 bit dma
*/
if (Jazz16_detected != 0)
if (dma16 != dma8)
{
if (ALLOC_DMA_CHN (dma16, "Jazz16 16 bit"))
{
sb_free_irq ();
RELEASE_DMA_CHN (dma8);
return RET_ERROR (EBUSY);
}
}
#endif
sb_irq_mode = IMODE_NONE;
@ -634,6 +689,13 @@ sb_dsp_open (int dev, int mode)
static void
sb_dsp_close (int dev)
{
#ifdef JAZZ16
/* Release 16 bit dma channel
*/
if (Jazz16_detected)
RELEASE_DMA_CHN (dma16);
#endif
DMAbuf_close_dma (dev);
sb_free_irq ();
dsp_cleanup ();
@ -643,6 +705,32 @@ sb_dsp_close (int dev)
open_mode = 0;
}
#ifdef JAZZ16
/* Function dsp_set_bits() only required for 16 bit cards
*/
static int
dsp_set_bits (int arg)
{
if (arg)
if (Jazz16_detected == 0)
dsp_16bit = 0;
else
switch (arg)
{
case 8:
dsp_16bit = 0;
break;
case 16:
dsp_16bit = 1;
break;
default:
dsp_16bit = 0;
}
return dsp_16bit ? 16 : 8;
}
#endif /* ifdef JAZZ16 */
static int
sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
{
@ -678,14 +766,31 @@ sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
break;
#ifdef JAZZ16
/* Word size specific cases here.
* SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS
*/
case SNDCTL_DSP_SETFMT:
if (local)
return dsp_set_bits (arg);
return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
break;
case SOUND_PCM_READ_BITS:
if (local)
return dsp_16bit ? 16 : 8;
return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
break;
#else
case SOUND_PCM_WRITE_BITS:
case SOUND_PCM_READ_BITS:
if (local)
return 8;
return IOCTL_OUT (arg, 8);/*
* Only 8 bits/sample supported
return IOCTL_OUT (arg, 8); /*
* Only 8 bits/sample supported
*/
break;
#endif /* ifdef JAZZ16 */
case SOUND_PCM_WRITE_FILTER:
case SOUND_PCM_READ_FILTER:
@ -715,6 +820,232 @@ sb_dsp_reset (int dev)
#endif
#ifdef JAZZ16
/*
* Initialization of a Media Vision ProSonic 16 Soundcard.
* The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets
* the base address, the DMA-channels, interrupts and enables the joystickport.
*
* Also used by Jazz 16 (same card, different name)
*
* written 1994 by Rainer Vranken
* E-Mail: rvranken@polaris.informatik.uni-essen.de
*/
#ifndef MPU_BASE /* take default values if not specified */
#define MPU_BASE 0x330
#endif
#ifndef MPU_IRQ
#define MPU_IRQ 9
#endif
unsigned int
get_sb_byte (void)
{
int i;
for (i = 1000; i; i--)
if (INB (DSP_DATA_AVAIL) & 0x80)
{
return INB (DSP_READ);
}
return 0xffff;
}
#ifdef SM_WAVE
/*
* Logitech Soundman Wave detection and initialization by Hannu Savolainen.
*
* There is a microcontroller (8031) in the SM Wave card for MIDI emulation.
* it's located at address MPU_BASE+4. MPU_BASE+7 is a SM Wave specific
* control register for MC reset, SCSI, OPL4 and DSP (future expansion)
* address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16
* based soundcard.
*/
static void
smw_putmem (int base, int addr, unsigned char val)
{
unsigned long flags;
DISABLE_INTR (flags);
OUTB (addr & 0xff, base + 1); /* Low address bits */
OUTB (addr >> 8, base + 2); /* High address bits */
OUTB (val, base); /* Data */
RESTORE_INTR (flags);
}
static unsigned char
smw_getmem (int base, int addr)
{
unsigned long flags;
unsigned char val;
DISABLE_INTR (flags);
OUTB (addr & 0xff, base + 1); /* Low address bits */
OUTB (addr >> 8, base + 2); /* High address bits */
val = INB (base); /* Data */
RESTORE_INTR (flags);
return val;
}
static int
initialize_smw (void)
{
#ifdef SMW_MIDI0001_INCLUDED
#include "smw-midi0001.h"
#else
unsigned char smw_ucode[1];
int smw_ucodeLen = 0;
#endif
int mp_base = MPU_BASE + 4; /* Microcontroller base */
int i;
unsigned char control;
/*
* Reset the microcontroller so that the RAM can be accessed
*/
control = INB (MPU_BASE + 7);
OUTB (control | 3, MPU_BASE + 7); /* Set last two bits to 1 (?) */
OUTB ((control & 0xfe) | 2, MPU_BASE + 7); /* xxxxxxx0 resets the mc */
for (i = 0; i < 300; i++) /* Wait at least 1ms */
tenmicrosec ();
OUTB (control & 0xfc, MPU_BASE + 7); /* xxxxxx00 enables RAM */
/*
* Detect microcontroller by probing the 8k RAM area
*/
smw_putmem (mp_base, 0, 0x00);
smw_putmem (mp_base, 1, 0xff);
tenmicrosec ();
if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff)
{
printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n",
smw_getmem (mp_base, 0), smw_getmem (mp_base, 1));
return 0; /* No RAM */
}
/*
* There is RAM so assume it's really a SM Wave
*/
#ifdef SMW_MIDI0001_INCLUDED
if (smw_ucodeLen != 8192)
{
printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n");
return 1;
}
#endif
/*
* Download microcode
*/
for (i = 0; i < 8192; i++)
smw_putmem (mp_base, i, smw_ucode[i]);
/*
* Verify microcode
*/
for (i = 0; i < 8192; i++)
if (smw_getmem (mp_base, i) != smw_ucode[i])
{
printk ("SM Wave: Microcode verification failed\n");
return 0;
}
control = 0;
#ifdef SMW_SCSI_IRQ
/*
* Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt
* is disabled by default.
*
* Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10.
*/
{
static unsigned char scsi_irq_bits[] =
{0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0};
control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6;
}
#endif
#ifdef SMW_OPL4_ENABLE
/*
* Make the OPL4 chip visible on the PC bus at 0x380.
*
* There is no need to enable this feature since VoxWare
* doesn't support OPL4 yet. Also there is no RAM in SM Wave so
* enabling OPL4 is pretty useless.
*/
control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */
/* control |= 0x20; Uncomment this if you want to use IRQ7 */
#endif
OUTB (control | 0x03, MPU_BASE + 7); /* xxxxxx11 restarts */
return 1;
}
#endif
static int
initialize_ProSonic16 (void)
{
int x;
static unsigned char int_translat[16] =
{0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] =
{0, 1, 0, 2, 0, 3, 0, 4};
OUTB (0xAF, 0x201); /* ProSonic/Jazz16 wakeup */
for (x = 0; x < 1000; ++x) /* wait 10 milliseconds */
tenmicrosec ();
OUTB (0x50, 0x201);
OUTB ((sbc_base & 0x70) | ((MPU_BASE & 0x30) >> 4), 0x201);
if (sb_reset_dsp ())
{ /* OK. We have at least a SB */
/* Check the version number of ProSonic (I guess) */
if (!sb_dsp_command (0xFA))
return 1;
if (get_sb_byte () != 0x12)
return 1;
if (sb_dsp_command (0xFB) && /* set DMA-channels and Interrupts */
sb_dsp_command ((dma_translat[JAZZ_DMA16] << 4) | dma_translat[SBC_DMA]) &&
sb_dsp_command ((int_translat[MPU_IRQ] << 4) | int_translat[sbc_irq]))
{
Jazz16_detected = 1;
#ifdef SM_WAVE
if (initialize_smw ())
Jazz16_detected = 2;
#endif
sb_dsp_disable_midi ();
}
return 1; /* There was at least a SB */
}
return 0; /* No SB or ProSonic16 detected */
}
#endif /* ifdef JAZZ16 */
int
sb_dsp_detect (struct address_info *hw_config)
{
@ -725,9 +1056,16 @@ sb_dsp_detect (struct address_info *hw_config)
return 0; /*
* Already initialized
*/
#ifdef JAZZ16
dma8 = hw_config->dma;
dma16 = JAZZ_DMA16;
if (!initialize_ProSonic16 ())
return 0;
#else
if (!sb_reset_dsp ())
return 0;
#endif
return 1; /*
* Detected
@ -737,7 +1075,7 @@ sb_dsp_detect (struct address_info *hw_config)
#ifndef EXCLUDE_AUDIO
static struct audio_operations sb_dsp_operations =
{
"SoundBlaster ",
"SoundBlaster",
NOTHING_SPECIAL,
AFMT_U8, /* Just 8 bits. Poor old SB */
NULL,
@ -792,6 +1130,9 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
#ifndef EXCLUDE_SBPRO
if (sbc_major >= 3)
mixer_type = sb_mixer_init (sbc_major);
#else
if (sbc_major >= 3)
printk ("\n\n\n\nNOTE! SB Pro support is required with your soundcard!\n\n\n");
#endif
#ifndef EXCLUDE_YM3812
@ -801,35 +1142,46 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
#endif
#ifndef EXCLUDE_AUDIO
if (sbc_major >= 3)
{
#if !defined(SCO) && !defined(EXCLUDE_AUDIO)
# ifdef __SGNXPRO__
if (Jazz16_detected)
{
if (Jazz16_detected == 2)
sprintf (sb_dsp_operations.name, "SoundMan Wave %d.%d", sbc_major, sbc_minor);
else
sprintf (sb_dsp_operations.name, "MV Jazz16 %d.%d", sbc_major, sbc_minor);
sb_dsp_operations.format_mask |= AFMT_S16_LE; /* Hurrah, 16 bits */
}
else
#ifdef __SGNXPRO__
if (mixer_type == 2)
{
sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
}
else
# endif
#endif
if (sbc_major == 4)
{
sprintf (sb_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
}
else
{
sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
}
#endif
}
else
{
#ifndef SCO
sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
#endif
}
#ifdef __FreeBSD__
#if defined(__FreeBSD__)
printk ("sb0: <%s>", sb_dsp_operations.name);
#else
printk (" <%s>", sb_dsp_operations.name);
#endif
#ifndef EXCLUDE_AUDIO
#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
if (!sb16) /*
* There is a better driver for SB16
@ -844,6 +1196,8 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
}
else
printk ("SB: Too many DSP devices available\n");
#else
printk (" <SoundBlaster (configured without audio support)>");
#endif
#ifndef EXCLUDE_MIDI

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sb_midi.c,v 1.4 1994/10/01 02:17:05 swallace Exp $
*/
#include "sound_config.h"
@ -43,7 +42,7 @@
* future version of this driver.
*/
extern int sb_dsp_ok; /* Set to 1 after successful initialization */
extern int sb_dsp_ok; /* Set to 1 atfer successful initialization */
extern int sbc_base;
extern int sb_midi_mode;
@ -218,6 +217,7 @@ static struct midi_operations sb_midi_operations =
{
{"SoundBlaster", 0, 0, SNDCARD_SB},
&std_midi_synth,
{0},
sb_midi_open,
sb_midi_close,
sb_midi_ioctl,

View file

@ -27,10 +27,9 @@
* SUCH DAMAGE.
*
* Modified:
* Hunyue Yau Jan 6 1994
* Added code to support the Sound Galaxy NX Pro mixer.
* Hunyue Yau Jan 6 1994
* Added code to support the Sound Galaxy NX Pro mixer.
*
* sb_mixer.c,v 1.4 1994/10/01 02:17:07 swallace Exp
*/
#include "sound_config.h"
@ -43,6 +42,7 @@
#undef SB_TEST_IRQ
extern int sbc_base;
extern int Jazz16_detected;
static int mixer_initialized = 0;
@ -98,9 +98,9 @@ sb_mixer_set_stereo (int mode)
/*
* Returns:
* 0 No mixer detected.
* 1 Only a plain Sound Blaster Pro style mixer detected.
* 2 The Sound Galaxy NX Pro mixer detected.
* 0 No mixer detected.
* 1 Only a plain Sound Blaster Pro style mixer detected.
* 2 The Sound Galaxy NX Pro mixer detected.
*/
static int
detect_mixer (void)
@ -110,6 +110,7 @@ detect_mixer (void)
#endif
int retcode = 1;
extern int sbc_major;
/*
* Detect the mixer by changing parameters of two volume channels. If the
@ -128,8 +129,8 @@ detect_mixer (void)
#ifdef __SGNXPRO__
/* Attempt to detect the SG NX Pro by check for valid bass/treble
* registers.
*/
* registers.
*/
oldbass = sb_getmixer (BASS_LVL);
oldtreble = sb_getmixer (TREBLE_LVL);
@ -148,6 +149,21 @@ detect_mixer (void)
*/
sb_setmixer (BASS_LVL, oldbass);
sb_setmixer (TREBLE_LVL, oldtreble);
/*
* If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16.
* In this case it's good idea to disable the Disney Sound Source
* compatibility mode. It's useless and just causes noise every time the
* LPT-port is accessed.
*
* Also place the card into WSS mode.
*/
if (sbc_major == 3)
{
OUTB (0x01, sbc_base + 0x1c);
OUTB (0x00, sbc_base + 0x1a);
}
#endif
return retcode;
}
@ -182,6 +198,100 @@ sb_mixer_get (int dev)
return levels[dev];
}
#ifdef JAZZ16
static char smw_mix_regs[] = /* Left mixer registers */
{
0x0b, /* SOUND_MIXER_VOLUME */
0x0d, /* SOUND_MIXER_BASS */
0x0d, /* SOUND_MIXER_TREBLE */
0x05, /* SOUND_MIXER_SYNTH */
0x09, /* SOUND_MIXER_PCM */
0x00, /* SOUND_MIXER_SPEAKER */
0x03, /* SOUND_MIXER_LINE */
0x01, /* SOUND_MIXER_MIC */
0x07, /* SOUND_MIXER_CD */
0x00, /* SOUND_MIXER_IMIX */
0x00, /* SOUND_MIXER_ALTPCM */
0x00, /* SOUND_MIXER_RECLEV */
0x00, /* SOUND_MIXER_IGAIN */
0x00, /* SOUND_MIXER_OGAIN */
0x00, /* SOUND_MIXER_LINE1 */
0x00, /* SOUND_MIXER_LINE2 */
0x00 /* SOUND_MIXER_LINE3 */
};
static void
smw_mixer_init (void)
{
int i;
sb_setmixer (0x00, 0x18); /* Mute unused (Telephone) line */
sb_setmixer (0x10, 0x38); /* Config register 2 */
supported_devices = 0;
for (i = 0; i < sizeof (smw_mix_regs); i++)
if (smw_mix_regs[i] != 0)
supported_devices |= (1 << i);
supported_rec_devices = supported_devices &
~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM |
SOUND_MASK_VOLUME);
}
static int
smw_mixer_set (int dev, int value)
{
int left = value & 0x000000ff;
int right = (value & 0x0000ff00) >> 8;
int reg, val;
if (left > 100)
left = 100;
if (right > 100)
right = 100;
if (dev > 31)
return RET_ERROR (EINVAL);
if (!(supported_devices & (1 << dev))) /* Not supported */
return RET_ERROR (EINVAL);
switch (dev)
{
case SOUND_MIXER_VOLUME:
sb_setmixer (0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */
sb_setmixer (0x0c, 96 - (96 * right / 100));
break;
case SOUND_MIXER_BASS:
case SOUND_MIXER_TREBLE:
levels[dev] = left | (right << 8);
/* Set left bass and treble values */
val = ((levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / 100) << 4;
val |= ((levels[SOUND_MIXER_BASS] & 0xff) * 16 / 100) & 0x0f;
sb_setmixer (0x0d, val);
/* Set right bass and treble values */
val = (((levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / 100) << 4;
val |= (((levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / 100) & 0x0f;
sb_setmixer (0x0e, val);
break;
default:
reg = smw_mix_regs[dev];
if (reg == 0)
return RET_ERROR (EINVAL);
sb_setmixer (reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */
sb_setmixer (reg + 1, (24 - (24 * right / 100)) | 0x40);
}
levels[dev] = left | (right << 8);
return left | (right << 8);
}
#endif
static int
sb_mixer_set (int dev, int value)
{
@ -191,6 +301,11 @@ sb_mixer_set (int dev, int value)
int regoffs;
unsigned char val;
#ifdef JAZZ16
if (Jazz16_detected == 2)
return smw_mixer_set (dev, value);
#endif
if (left > 100)
left = 100;
if (right > 100)
@ -234,6 +349,7 @@ sb_mixer_set (int dev, int value)
}
change_bits (&val, dev, RIGHT_CHN, right);
sb_setmixer (regoffs, val);
levels[dev] = left | (right << 8);
@ -338,6 +454,7 @@ sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
break;
default:
return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
}
else
@ -355,8 +472,11 @@ sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
break;
case SOUND_MIXER_STEREODEVS:
return IOCTL_OUT (arg, supported_devices &
~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
if (Jazz16_detected)
return IOCTL_OUT (arg, supported_devices);
else
return IOCTL_OUT (arg, supported_devices &
~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
break;
case SOUND_MIXER_RECMASK:
@ -377,6 +497,7 @@ sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
static struct mixer_operations sb_mixer_operations =
{
"SoundBlaster",
sb_mixer_ioctl
};
@ -415,6 +536,18 @@ sb_mixer_init (int major_model)
{
case 3:
mixer_caps = SOUND_CAP_EXCL_INPUT;
#ifdef JAZZ16
if (Jazz16_detected == 2) /* SM Wave */
{
supported_devices = 0;
supported_rec_devices = 0;
iomap = &sbpro_mix;
smw_mixer_init ();
mixer_type = 1;
}
else
#endif
#ifdef __SGNXPRO__
if (mixer_type == 2) /* A SGNXPRO was detected */
{

View file

@ -1,10 +1,10 @@
/*
* sound/sb_mixer.h
*
*
* Definitions for the SB Pro and SB16 mixers
*
*
* Copyright by Hannu Savolainen 1993
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@ -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
@ -28,8 +28,7 @@
* Modified:
* Hunyue Yau Jan 6 1994
* Added defines for the Sound Galaxy NX Pro mixer.
*
* sb_mixer.h,v 1.4 1994/10/01 02:17:08 swallace Exp
*
*/
#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
@ -52,16 +51,17 @@
SOUND_MASK_CD)
#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD | SOUND_MASK_RECLEV | \
SOUND_MASK_CD | \
SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
/*
* Mixer registers
*
*
* NOTE! RECORD_SRC == IN_FILTER
*/
/*
/*
* Mixer registers of SB Pro
*/
#define VOC_VOL 0x04
@ -80,7 +80,7 @@
#define OPSW 0x3c
/*
* Additional registers on the SG NX Pro
* Additional registers on the SG NX Pro
*/
#define COVOX_VOL 0x42
#define TREBLE_LVL 0x44
@ -145,7 +145,9 @@ MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0)
};
#endif
@ -161,23 +163,51 @@ MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5),
MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2)
MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */
MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2),
MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2)
};
#ifdef SM_GAMES /* Master volume is lower and PCM & FM volumes
higher than with SB Pro. This improves the
sound quality */
static unsigned short levels[SOUND_MIXER_NRDEVICES] =
{
0x5a5a, /* Master Volume */
0x3232, /* Bass */
0x3232, /* Treble */
0x4b4b, /* FM */
0x4b4b, /* PCM */
0x2020, /* Master Volume */
0x4b4b, /* Bass */
0x4b4b, /* Treble */
0x6464, /* FM */
0x6464, /* PCM */
0x4b4b, /* PC Speaker */
0x4b4b, /* Ext Line */
0x0000, /* Mic */
0x4b4b, /* CD */
0x4b4b, /* Recording monitor */
0x4b4b, /* SB PCM */
0x4b4b}; /* Recording level */
0x4b4b, /* Recording level */
0x4b4b, /* Input gain */
0x4b4b}; /* Output gain */
#else /* If the user selected just plain SB Pro */
static unsigned short levels[SOUND_MIXER_NRDEVICES] =
{
0x5a5a, /* Master Volume */
0x4b4b, /* Bass */
0x4b4b, /* Treble */
0x4b4b, /* FM */
0x4b4b, /* PCM */
0x4b4b, /* PC Speaker */
0x4b4b, /* Ext Line */
0x1010, /* Mic */
0x4b4b, /* CD */
0x4b4b, /* Recording monitor */
0x4b4b, /* SB PCM */
0x4b4b, /* Recording level */
0x4b4b, /* Input gain */
0x4b4b}; /* Output gain */
#endif /* SM_GAMES */
static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
{
@ -192,7 +222,9 @@ static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
0x04, /* SOUND_MIXER_CD */
0x00, /* SOUND_MIXER_IMIX */
0x00, /* SOUND_MIXER_ALTPCM */
0x00 /* SOUND_MIXER_RECLEV */
0x00, /* SOUND_MIXER_RECLEV */
0x00, /* SOUND_MIXER_IGAIN */
0x00 /* SOUND_MIXER_OGAIN */
};
static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
@ -208,7 +240,9 @@ static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
0x02, /* SOUND_MIXER_CD */
0x00, /* SOUND_MIXER_IMIX */
0x00, /* SOUND_MIXER_ALTPCM */
0x00 /* SOUND_MIXER_RECLEV */
0x00, /* SOUND_MIXER_RECLEV */
0x00, /* SOUND_MIXER_IGAIN */
0x00 /* SOUND_MIXER_OGAIN */
};
/*

View file

@ -25,11 +25,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sequencer.c,v 1.7 1994/10/01 02:17:09 swallace Exp $
*/
#define SEQUENCER_C
#include "sound_config.h"
#include "midi_ctrl.h"
#ifdef CONFIGURE_SOUNDCARD
@ -50,7 +50,7 @@ static int max_synthdev = 0;
/*
* The seq_mode gives the operating mode of the sequencer:
* 1 = level1 (the default)
* 2 = level2 (extended capabilities)
* 2 = level2 (extended capabilites)
*/
#define SEQ_1 1
@ -84,7 +84,7 @@ static int output_treshold;
static int pre_event_timeout;
static unsigned synth_open_mask;
static int seq_queue (unsigned char *note);
static int seq_queue (unsigned char *note, char nonblock);
static void seq_startplay (void);
static int seq_sync (void);
static void seq_reset (void);
@ -114,6 +114,12 @@ sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
DISABLE_INTR (flags);
if (!iqlen)
{
if (ISSET_FILE_FLAG (file, O_NONBLOCK))
{
RESTORE_INTR (flags);
return RET_ERROR (EAGAIN);
}
DO_SLEEP (midi_sleeper, midi_sleep_flag, pre_event_timeout);
if (!iqlen)
@ -152,8 +158,8 @@ seq_copy_to_input (unsigned char *event, int len)
unsigned long flags;
/*
* Verify that the len is valid for the current mode.
*/
* Verify that the len is valid for the current mode.
*/
if (len != 4 && len != 8)
return;
@ -173,6 +179,10 @@ seq_copy_to_input (unsigned char *event, int len)
WAKE_UP (midi_sleeper, midi_sleep_flag);
}
RESTORE_INTR (flags);
#if defined(__FreeBSD__)
if (selinfo[0].si_pid)
selwakeup(&selinfo[0]);
#endif
}
static void
@ -332,12 +342,17 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
}
if (!seq_queue (event))
if (!seq_queue (event, ISSET_FILE_FLAG (file, O_NONBLOCK)))
{
int processed = count - c;
if (!seq_playing)
seq_startplay ();
return count - c;
if (!processed && ISSET_FILE_FLAG (file, O_NONBLOCK))
return RET_ERROR (EAGAIN);
else
return processed;
}
p += ev_size;
@ -347,11 +362,13 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
if (!seq_playing)
seq_startplay ();
return count;
return count; /* This will "eat" chunks shorter than 4 bytes (if written
* alone) Should we really do that ?
*/
}
static int
seq_queue (unsigned char *note)
seq_queue (unsigned char *note, char nonblock)
{
/*
@ -364,7 +381,7 @@ seq_queue (unsigned char *note)
* Give chance to drain the queue
*/
if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
if (!nonblock && qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
/*
* Sleep until there is enough space on the queue
@ -373,10 +390,11 @@ seq_queue (unsigned char *note)
}
if (qlen >= SEQ_MAX_QUEUE)
return 0; /*
{
return 0; /*
* To be sure
*/
}
memcpy (&queue[qtail * EV_SZ], note, EV_SZ);
qtail = (qtail + 1) % SEQ_MAX_QUEUE;
@ -463,6 +481,8 @@ alloc_voice (int dev, int chn, int note)
voice = synth_devs[dev]->alloc_voice (dev, chn, note,
&synth_devs[dev]->alloc);
synth_devs[dev]->alloc.map[voice] = key;
synth_devs[dev]->alloc.alloc_times[voice] =
synth_devs[dev]->alloc.timestamp++;
return voice;
}
@ -486,33 +506,47 @@ seq_chn_voice_event (unsigned char *event)
if (seq_mode == SEQ_2)
{
if (synth_devs[dev]->alloc_voice)
voice = find_voice (dev, chn, note);
voice = find_voice (dev, chn, note);
if (cmd == MIDI_NOTEON && parm == 0)
{
cmd = MIDI_NOTEOFF;
parm = 64;
}
{
cmd = MIDI_NOTEOFF;
parm = 64;
}
}
switch (cmd)
{
case MIDI_NOTEON:
if (note > 127 && note != 255)
if (note > 127 && note != 255) /* Not a seq2 feature */
return;
if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice)
{
{ /* Internal synthesizer (FM, GUS, etc) */
voice = alloc_voice (dev, chn, note);
}
if (voice == -1)
voice = chn;
if (seq_mode == SEQ_2 && dev < num_synths)
{
/*
* The MIDI channel 10 is a percussive channel. Use the note
* number to select the proper patch (128 to 255) to play.
*/
if (chn == 9)
{
synth_devs[dev]->set_instr (dev, voice, 128 + note);
note = 60; /* Middle C */
}
}
if (seq_mode == SEQ_2)
{
synth_devs[dev]->set_instr (dev, voice,
synth_devs[dev]->chn_info[chn].pgm_num);
synth_devs[dev]->setup_voice (dev, voice, chn);
}
synth_devs[dev]->start_note (dev, voice, note, parm);
@ -525,7 +559,9 @@ seq_chn_voice_event (unsigned char *event)
break;
case MIDI_KEY_PRESSURE:
/* To be implemented */
if (voice == -1)
voice = chn;
synth_devs[dev]->aftertouch (dev, voice, parm);
break;
default:;
@ -556,33 +592,27 @@ seq_chn_common_event (unsigned char *event)
if (seq_mode == SEQ_2)
{
synth_devs[dev]->chn_info[chn].pgm_num = p1;
if (dev >= num_synths)
synth_devs[dev]->set_instr (dev, chn, p1);
}
else
synth_devs[dev]->set_instr (dev, chn, p1);
break;
case MIDI_CTL_CHANGE:
if (p1 == CTRL_MAIN_VOLUME)
{
w14 = (unsigned short) (((int) w14 * 16383) / 100);
p1 = CTL_MAIN_VOLUME;
}
if (p1 == CTRL_EXPRESSION)
{
w14 *= 128;
p1 = CTL_EXPRESSION;
}
if (seq_mode == SEQ_2)
{
if (chn > 15 || p1 > 127)
break;
synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0xff;
synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f;
if (dev < num_synths)
{
int val = w14 & 0xff;
int val = w14 & 0x7f;
int i, key;
if (p1 < 64) /* Combine MSB and LSB */
{
@ -592,20 +622,42 @@ seq_chn_common_event (unsigned char *event)
chn_info[chn].controllers[p1 | 32] & 0x7f);
p1 &= ~32;
}
else
val = synth_devs[dev]->chn_info[chn].controllers[p1];
synth_devs[dev]->controller (dev, chn, p1, val);
/* Handle all playing notes on this channel */
key = (chn << 8);
for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++)
if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key)
synth_devs[dev]->controller (dev, i, p1, val);
}
else
synth_devs[dev]->controller (dev, chn, p1, w14);
}
else
else /* Mode 1 */
synth_devs[dev]->controller (dev, chn, p1, w14);
break;
case MIDI_PITCH_BEND:
synth_devs[dev]->bender (dev, chn, w14);
if (seq_mode == SEQ_2)
{
synth_devs[dev]->chn_info[chn].bender_value = w14;
if (dev < num_synths)
{ /* Handle all playing notes on this channel */
int i, key;
key = (chn << 8);
for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++)
if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key)
synth_devs[dev]->bender (dev, i, w14);
}
else
synth_devs[dev]->bender (dev, chn, w14);
}
else /* MODE 1 */
synth_devs[dev]->bender (dev, chn, w14);
break;
default:;
@ -634,6 +686,9 @@ seq_timing_event (unsigned char *event)
WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
#if defined(__FreeBSD__)
/* must issue a wakeup for anyone waiting (select) XXX */
#endif
}
}
return ret;
@ -645,9 +700,9 @@ seq_timing_event (unsigned char *event)
parm += prev_event_time;
/*
* NOTE! No break here. Execution of TMR_WAIT_REL continues in the
* next case (TMR_WAIT_ABS)
*/
* NOTE! No break here. Execution of TMR_WAIT_REL continues in the
* next case (TMR_WAIT_ABS)
*/
case TMR_WAIT_ABS:
if (parm > 0)
@ -670,6 +725,9 @@ seq_timing_event (unsigned char *event)
WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
#if defined(__FreeBSD__)
/* must issue a wakeup for select XXX */
#endif
}
return TIMER_ARMED;
@ -715,151 +773,173 @@ seq_local_event (unsigned char *event)
printk ("seq_local_event() called. WHY????????\n");
}
static int
play_event (unsigned char *q)
{
/*
* NOTE! This routine returns
* 0 = normal event played.
* 1 = Timer armed. Suspend playback until timer callback.
* 2 = MIDI output buffer full. Restore queue and suspend until timer
*/
unsigned long *delay;
switch (q[0])
{
case SEQ_NOTEOFF:
if (synth_open_mask & (1 << 0))
if (synth_devs[0])
synth_devs[0]->kill_note (0, q[1], 255, q[3]);
break;
case SEQ_NOTEON:
if (q[4] < 128 || q[4] == 255)
if (synth_open_mask & (1 << 0))
if (synth_devs[0])
synth_devs[0]->start_note (0, q[1], q[2], q[3]);
break;
case SEQ_WAIT:
delay = (unsigned long *) q; /*
* Bytes 1 to 3 are containing the *
* delay in GET_TIME()
*/
*delay = (*delay >> 8) & 0xffffff;
if (*delay > 0)
{
long time;
seq_playing = 1;
time = *delay;
prev_event_time = time;
request_sound_timer (time);
if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
{
unsigned long flags;
DISABLE_INTR (flags);
if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
#if defined(__FreeBSD__)
/* must issue a wakeup for selects XXX */
#endif
}
/*
* The timer is now active and will reinvoke this function
* after the timer expires. Return to the caller now.
*/
return 1;
}
break;
case SEQ_PGMCHANGE:
if (synth_open_mask & (1 << 0))
if (synth_devs[0])
synth_devs[0]->set_instr (0, q[1], q[2]);
break;
case SEQ_SYNCTIMER: /*
* Reset timer
*/
seq_time = GET_TIME ();
prev_input_time = 0;
prev_event_time = 0;
break;
case SEQ_MIDIPUTC: /*
* Put a midi character
*/
if (midi_opened[q[2]])
{
int dev;
dev = q[2];
if (!midi_devs[dev]->putc (dev, q[1]))
{
/*
* Output FIFO is full. Wait one timer cycle and try again.
*/
seq_playing = 1;
request_sound_timer (-1);
return 2;
}
else
midi_written[dev] = 1;
}
break;
case SEQ_ECHO:
seq_copy_to_input (q, 4); /*
* Echo back to the process
*/
break;
case SEQ_PRIVATE:
if ((int) q[1] < max_synthdev)
synth_devs[q[1]]->hw_control (q[1], q);
break;
case SEQ_EXTENDED:
extended_event (q);
break;
case EV_CHN_VOICE:
seq_chn_voice_event (q);
break;
case EV_CHN_COMMON:
seq_chn_common_event (q);
break;
case EV_TIMING:
if (seq_timing_event (q) == TIMER_ARMED)
{
return 1;
}
break;
case EV_SEQ_LOCAL:
seq_local_event (q);
break;
default:;
}
return 0;
}
static void
seq_startplay (void)
{
int this_one;
unsigned long *delay;
unsigned char *q;
unsigned long flags;
int this_one, action;
while (qlen > 0)
{
seq_playing = 1;
DISABLE_INTR (flags);
qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
qlen--;
RESTORE_INTR (flags);
q = &queue[this_one * EV_SZ];
seq_playing = 1;
switch (q[0])
{
case SEQ_NOTEOFF:
if (synth_open_mask & (1 << 0))
if (synth_devs[0])
synth_devs[0]->kill_note (0, q[1], 255, q[3]);
break;
case SEQ_NOTEON:
if (q[4] < 128 || q[4] == 255)
if (synth_open_mask & (1 << 0))
if (synth_devs[0])
synth_devs[0]->start_note (0, q[1], q[2], q[3]);
break;
case SEQ_WAIT:
delay = (unsigned long *) q; /*
* Bytes 1 to 3 are containing the *
* delay in GET_TIME()
*/
*delay = (*delay >> 8) & 0xffffff;
if (*delay > 0)
if ((action = play_event (&queue[this_one * EV_SZ])))
{ /* Suspend playback. Next timer routine invokes this routine again */
if (action == 2)
{
long time;
seq_playing = 1;
time = *delay;
prev_event_time = time;
request_sound_timer (time);
if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
{
unsigned long flags;
DISABLE_INTR (flags);
if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
}
/*
* The timer is now active and will reinvoke this function
* after the timer expires. Return to the caller now.
*/
return;
qlen++;
qhead = this_one;
}
break;
case SEQ_PGMCHANGE:
if (synth_open_mask & (1 << 0))
if (synth_devs[0])
synth_devs[0]->set_instr (0, q[1], q[2]);
break;
case SEQ_SYNCTIMER: /*
* Reset timer
*/
seq_time = GET_TIME ();
prev_input_time = 0;
prev_event_time = 0;
break;
case SEQ_MIDIPUTC: /*
* Put a midi character
*/
if (midi_opened[q[2]])
{
int dev;
dev = q[2];
if (!midi_devs[dev]->putc (dev, q[1]))
{
/*
* Output FIFO is full. Wait one timer cycle and try again.
*/
qlen++;
qhead = this_one; /*
* Restore queue
*/
seq_playing = 1;
request_sound_timer (-1);
return;
}
else
midi_written[dev] = 1;
}
break;
case SEQ_ECHO:
seq_copy_to_input (q, 4); /*
* Echo back to the process
*/
break;
case SEQ_PRIVATE:
if ((int) q[1] < max_synthdev)
synth_devs[q[1]]->hw_control (q[1], q);
break;
case SEQ_EXTENDED:
extended_event (q);
break;
case EV_CHN_VOICE:
seq_chn_voice_event (q);
break;
case EV_CHN_COMMON:
seq_chn_common_event (q);
break;
case EV_TIMING:
if (seq_timing_event (q) == TIMER_ARMED)
{
return;
}
break;
case EV_SEQ_LOCAL:
seq_local_event (q);
break;
default:;
return;
}
}
@ -876,14 +956,15 @@ seq_startplay (void)
WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
#if defined(__FreeBSD__)
/* must issue a wakeup for selects XXX */
#endif
}
}
static void
reset_controllers (int dev, unsigned char *controller, int update_dev)
{
#include "midi_ctrl.h"
int i;
@ -915,6 +996,7 @@ setup_mode2 (void)
reset_controllers (dev,
synth_devs[dev]->chn_info[chn].controllers,
0);
synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */
}
}
@ -999,7 +1081,6 @@ sequencer_open (int dev, struct fileinfo *file)
if (level == 2)
{
printk ("Using timer #%d\n", tmr_no);
if (tmr == NULL)
{
printk ("sequencer: No timer for level 2\n");
@ -1036,7 +1117,7 @@ sequencer_open (int dev, struct fileinfo *file)
{
printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp);
if (synth_devs[i]->midi_dev)
printk ("(Maps to midi dev #%d\n", synth_devs[i]->midi_dev);
printk ("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev);
}
else
{
@ -1092,7 +1173,7 @@ seq_drain_midi_queues (void)
n = 1;
while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n)
while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && n)
{
n = 0;
@ -1133,10 +1214,10 @@ sequencer_release (int dev, struct fileinfo *file)
}
/*
* * Wait until the queue is empty
* * Wait until the queue is empty (if we don't have nonblock)
*/
if (mode != OPEN_READ)
if (mode != OPEN_READ && !ISSET_FILE_FLAG (file, O_NONBLOCK))
while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
{
seq_sync ();
@ -1181,16 +1262,17 @@ sequencer_release (int dev, struct fileinfo *file)
static int
seq_sync (void)
{
unsigned long flags;
if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
seq_startplay ();
if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /*
* Queue not
* empty
*/
DISABLE_INTR (flags);
if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
{
DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
}
RESTORE_INTR (flags);
return qlen;
}
@ -1203,26 +1285,23 @@ midi_outc (int dev, unsigned char data)
*/
int n;
unsigned long flags;
/*
* This routine sends one byte to the Midi channel.
*/
/*
* If the output Fifo is full, it waits until there
*/
/*
* is space in the queue
*/
n = 300; /*
* Timeout in jiffies
*/
n = 3 * HZ; /* Timeout */
DISABLE_INTR (flags);
while (n && !midi_devs[dev]->putc (dev, data))
{
DO_SLEEP (seq_sleeper, seq_sleep_flag, 4);
n--;
}
RESTORE_INTR (flags);
}
static void
@ -1233,8 +1312,8 @@ seq_reset (void)
*/
int i;
int chn;
unsigned long flags;
sound_stop_timer ();
seq_time = GET_TIME ();
@ -1251,13 +1330,20 @@ seq_reset (void)
if (seq_mode == SEQ_2)
{
for (i = 0; i < max_synthdev; i++)
if (synth_open_mask & (1 << i))
if (synth_devs[i])
for (chn = 0; chn < 16; chn++)
synth_devs[i]->controller (i, chn, 0xfe, 0); /* All notes off */
for (chn = 0; chn < 16; chn++)
for (i = 0; i < max_synthdev; i++)
if (synth_open_mask & (1 << i))
if (synth_devs[i])
{
synth_devs[i]->controller (i, chn, 123, 0); /* All notes off */
synth_devs[i]->controller (i, chn, 121, 0); /* Reset all ctl */
synth_devs[i]->bender (i, chn, 1 << 13); /* Bender off */
}
}
else
/* seq_mode == SEQ_1 */
{
for (i = 0; i < max_mididev; i++)
if (midi_written[i]) /*
@ -1265,25 +1351,18 @@ seq_reset (void)
*/
{
/*
* Sending just a ACTIVE SENSING message should be enough to stop all
* playing notes. Since there are devices not recognizing the
* active sensing, we have to send some all notes off messages also.
*/
* Sending just a ACTIVE SENSING message should be enough to stop all
* playing notes. Since there are devices not recognizing the
* active sensing, we have to send some all notes off messages also.
*/
midi_outc (i, 0xfe);
for (chn = 0; chn < 16; chn++)
{
midi_outc (i,
(unsigned char) (0xb0 + (chn & 0xff))); /*
* Channel
* msg
*/
midi_outc (i, 0x7b); /*
* All notes off
*/
midi_outc (i, 0); /*
* Dummy parameter
*/
(unsigned char) (0xb0 + (chn & 0x0f))); /* control change */
midi_outc (i, 0x7b); /* All notes off */
midi_outc (i, 0); /* Dummy parameter */
}
midi_devs[i]->close (i);
@ -1295,8 +1374,13 @@ seq_reset (void)
seq_playing = 0;
DISABLE_INTR (flags);
if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
printk ("Sequencer Warning: Unexpected sleeping process\n");
{
/* printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */
WAKE_UP (seq_sleeper, seq_sleep_flag);
}
RESTORE_INTR (flags);
}
@ -1304,22 +1388,22 @@ static void
seq_panic (void)
{
/*
* This routine is called by the application in case the user
* wants to reset the system to the default state.
*/
* This routine is called by the application in case the user
* wants to reset the system to the default state.
*/
seq_reset ();
/*
* Since some of the devices don't recognize the active sensing and
* all notes off messages, we have to shut all notes manually.
*
* TO BE IMPLEMENTED LATER
*/
* Since some of the devices don't recognize the active sensing and
* all notes off messages, we have to shut all notes manually.
*
* TO BE IMPLEMENTED LATER
*/
/*
* Also return the controllers to their default states
*/
* Also return the controllers to their default states
*/
}
int
@ -1524,6 +1608,21 @@ sequencer_ioctl (int dev, struct fileinfo *file,
}
break;
case SNDCTL_SEQ_OUTOFBAND:
{
struct seq_event_rec event;
unsigned long flags;
IOCTL_FROM_USER ((char *) &event, (char *) arg, 0, sizeof (event));
DISABLE_INTR (flags);
play_event (event.arr);
RESTORE_INTR (flags);
return 0;
}
break;
case SNDCTL_MIDI_INFO:
{
struct midi_info inf;
@ -1545,7 +1644,11 @@ sequencer_ioctl (int dev, struct fileinfo *file,
struct patmgr_info *inf;
int dev, err;
inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf));
if ((inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf))) == NULL)
{
printk ("patmgr: Can't allocate memory for a message\n");
return RET_ERROR (EIO);
}
IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf));
dev = inf->device;
@ -1579,7 +1682,11 @@ sequencer_ioctl (int dev, struct fileinfo *file,
struct patmgr_info *inf;
int dev, err;
inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf));
if ((inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf))) == NULL)
{
printk ("patmgr: Can't allocate memory for a message\n");
return RET_ERROR (EIO);
}
IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf));
dev = inf->device;
@ -1670,26 +1777,38 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w
switch (sel_type)
{
case SEL_IN:
DISABLE_INTR (flags);
if (!iqlen)
{
DISABLE_INTR (flags);
#if defined(__FreeBSD__)
selrecord(wait, &selinfo[dev]);
#else
midi_sleep_flag.mode = WK_SLEEP;
select_wait (&midi_sleeper, wait);
#endif
RESTORE_INTR (flags);
return 0;
}
midi_sleep_flag.mode &= ~WK_SLEEP;
RESTORE_INTR (flags);
return 1;
break;
case SEL_OUT:
DISABLE_INTR (flags);
if (qlen >= SEQ_MAX_QUEUE)
{
DISABLE_INTR (flags);
#if defined(__FreeBSD__)
selrecord(wait, &selinfo[dev]);
#else
seq_sleep_flag.mode = WK_SLEEP;
select_wait (&seq_sleeper, wait);
#endif
RESTORE_INTR (flags);
return 0;
}
seq_sleep_flag.mode &= ~WK_SLEEP;
RESTORE_INTR (flags);
return 1;
break;
@ -1853,9 +1972,9 @@ sequencer_init (long mem_start)
return mem_start;
}
#ifdef ALLOW_SELECT
int
/* sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) -SMP */
sequencer_select (int dev, struct fileinfo *file, int sel_type, void * wait)
sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
return RET_ERROR (EIO);
}
@ -1863,3 +1982,5 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, void * wait)
#endif
#endif
#endif

View file

@ -1,29 +1,24 @@
/*
* DMA buffer calls
*
* $Id: sound_calls.h,v 1.12 1995/05/07 06:38:48 pst Exp $
*/
#ifndef _MACHINE_ISA_SOUND_H_
#define _MACHINE_ISA_SOUND_H_
int DMAbuf_open(int dev, int mode);
int DMAbuf_output_ready(int dev);
int DMAbuf_input_ready(int dev);
int DMAbuf_release(int dev, int mode);
int DMAbuf_getwrbuffer(int dev, char **buf, int *size);
int DMAbuf_getrdbuffer(int dev, char **buf, int *len);
int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock);
int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock);
int DMAbuf_rmchars(int dev, int buff_no, int c);
int DMAbuf_start_input(int dev);
int DMAbuf_start_output(int dev, int buff_no, int l);
int DMAbuf_ioctl(int dev, unsigned int cmd, unsigned int arg, int local);
long DMAbuf_init(long mem_start);
int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
int DMAbuf_open_dma (int chan);
void DMAbuf_close_dma (int chan);
void DMAbuf_reset_dma (int chan);
int DMAbuf_open_dma (int dev);
void DMAbuf_close_dma (int dev);
void DMAbuf_reset_dma (int dev);
void DMAbuf_inputintr(int dev);
void DMAbuf_outputintr(int dev, int underflow_flag);
#ifdef ALLOW_SELECT
int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
#endif
/*
* System calls for /dev/dsp and /dev/audio
@ -38,6 +33,10 @@ int audio_ioctl (int dev, struct fileinfo *file,
int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
long audio_init (long mem_start);
#ifdef ALLOW_SELECT
int audio_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
#endif
/*
* System calls for the /dev/sequencer
*/
@ -87,28 +86,20 @@ long CMIDI_init (long mem_start);
int CMIDI_open (int dev, struct fileinfo *file);
int CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
int CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
int CMIDI_close (int dev, struct fileinfo *file);
int CMIDI_close (int dev, struct fileinfo *file);
/*
*
* Misc calls from various sources
*/
/* From pro_midi.c */
long pro_midi_attach(long mem_start);
int pro_midi_open(int dev, int mode);
void pro_midi_close(int dev);
int pro_midi_write(int dev, snd_rw_buf *uio);
int pro_midi_read(int dev, snd_rw_buf *uio);
/* From soundcard.c */
long soundcard_init(long mem_start);
void tenmicrosec(void);
void request_sound_timer (int count);
void sound_stop_timer(void);
int snd_ioctl_return(int *addr, int value);
int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int));
int snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO(), char *name);
void snd_release_irq(int vect);
void sound_dma_malloc(int dev);
void sound_dma_free(int dev);
@ -131,7 +122,7 @@ int sb_dsp_command (unsigned char val);
int sb_reset_dsp (void);
/* From sb16_dsp.c */
void sb16_dsp_interrupt (int unused);
void sb16_dsp_interrupt (int irq);
long sb16_dsp_init(long mem_start, struct address_info *hw_config);
int sb16_dsp_detect(struct address_info *hw_config);
@ -163,7 +154,6 @@ long attach_adlib_card(long mem_start, struct address_info *hw_config);
int probe_adlib(struct address_info *hw_config);
/* From pas_card.c */
void mix_write(unsigned char data, int ioaddr);
long attach_pas_card(long mem_start, struct address_info *hw_config);
int probe_pas(struct address_info *hw_config);
int pas_set_intr(int mask);
@ -186,13 +176,13 @@ void pas_midi_interrupt(void);
long attach_gus_card(long mem_start, struct address_info * hw_config);
int probe_gus(struct address_info *hw_config);
int gus_set_midi_irq(int num);
void gusintr(int);
void gusintr(INT_HANDLER_PARMS(irq, dummy));
long attach_gus_db16(long mem_start, struct address_info * hw_config);
int probe_gus_db16(struct address_info *hw_config);
/* From gus_wave.c */
int gus_wave_detect(int baseaddr);
long gus_wave_init(long mem_start, int irq, int dma);
long gus_wave_init(long mem_start, int irq, int dma, int dma_read);
void gus_voice_irq(void);
unsigned char gus_read8 (int reg);
void gus_write8(int reg, unsigned int data);
@ -207,6 +197,7 @@ void gus_midi_interrupt(int dummy);
/* From mpu401.c */
long attach_mpu401(long mem_start, struct address_info * hw_config);
int probe_mpu401(struct address_info *hw_config);
void mpuintr(INT_HANDLER_PARMS(irq, dummy));
/* From uart6850.c */
long attach_uart6850(long mem_start, struct address_info * hw_config);
@ -234,13 +225,23 @@ void sound_timer_interrupt(void);
/* From ad1848.c */
void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture);
int ad1848_detect (int io_base);
void adintr (int dev);
void ad1848_interrupt (INT_HANDLER_PARMS(irq, dummy));
long attach_ms_sound(long mem_start, struct address_info * hw_config);
int probe_ms_sound(struct address_info *hw_config);
/* From pss.c */
int probe_pss (struct address_info *hw_config);
long attach_pss (long mem_start, struct address_info *hw_config);
int probe_pss_mpu (struct address_info *hw_config);
long attach_pss_mpu (long mem_start, struct address_info *hw_config);
int probe_pss_mss (struct address_info *hw_config);
long attach_pss_mss (long mem_start, struct address_info *hw_config);
/* From sscape.c */
int probe_sscape (struct address_info *hw_config);
long attach_sscape (long mem_start, struct address_info *hw_config);
int probe_ss_ms_sound (struct address_info *hw_config);
long attach_ss_ms_sound(long mem_start, struct address_info * hw_config);
int pss_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
int pss_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
@ -251,4 +252,18 @@ int pss_ioctl (int dev, struct fileinfo *file,
int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
long pss_init(long mem_start);
#endif /* _MACHINE_ISA_SOUND_H_ */
/* From aedsp16.c */
int InitAEDSP16_SBPRO(struct address_info *hw_config);
int InitAEDSP16_MSS(struct address_info *hw_config);
int InitAEDSP16_MPU401(struct address_info *hw_config);
/* From midi_synth.c */
void do_midi_msg (int synthno, unsigned char *msg, int mlen);
/* From trix.c */
long attach_trix_wss (long mem_start, struct address_info *hw_config);
int probe_trix_wss (struct address_info *hw_config);
long attach_trix_sb (long mem_start, struct address_info *hw_config);
int probe_trix_sb (struct address_info *hw_config);
long attach_trix_mpu (long mem_start, struct address_info *hw_config);
int probe_trix_mpu (struct address_info *hw_config);

View file

@ -2,7 +2,7 @@
*
* A driver for Soundcards, misc configuration parameters.
*
*
*
* Copyright by Hannu Savolainen 1993
*
* Redistribution and use in source and binary forms, with or without
@ -26,10 +26,15 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sound_config.h,v 1.9 1995/03/12 23:34:07 swallace Exp $
*/
#include "local.h"
#include "os.h"
#include "soundvers.h"
#if !defined(PSS_MPU_BASE) && defined(EXCLUDE_SSCAPE) && defined(EXCLUDE_TRIX)
#define EXCLUDE_MPU_EMU
#endif
#if defined(ISC) || defined(SCO) || defined(SVR42)
#define GENERIC_SYSV
@ -39,10 +44,14 @@
* Disable the AD1848 driver if there are no other drivers requiring it.
*/
#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX)
#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX) && defined(EXCLUDE_SSCAPE) && defined(EXCLUDE_TRIX)
#define EXCLUDE_AD1848
#endif
#ifdef PSS_MSS_BASE
#undef EXCLUDE_AD1848
#endif
#undef CONFIGURE_SOUNDCARD
#undef DYNAMIC_BUFFER
@ -53,9 +62,9 @@
#endif
#ifdef EXCLUDE_SEQUENCER
#ifndef EXCLUDE_YM3812
#define EXCLUDE_MIDI
#define EXCLUDE_YM3812
#endif
#define EXCLUDE_OPL3
#endif
#ifndef SND_DEFAULT_ENABLE
@ -117,16 +126,8 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define GUS_DMA 6
#endif
#ifndef GUS16_BASE
#define GUS16_BASE 0x530
#endif
#ifndef GUS16_IRQ
#define GUS16_IRQ 7
#endif
#ifndef GUS16_DMA
#define GUS16_DMA 3
#ifndef GUS_DMA_READ
#define GUS_DMA_READ 3
#endif
#ifndef MPU_BASE
@ -150,32 +151,68 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define PSS_DMA 1
#endif
#ifndef MAX_REALTIME_FACTOR
#define MAX_REALTIME_FACTOR 4
#endif
#ifndef MSS_BASE
#define MSS_BASE 0x530
#endif
#ifndef MSS_IRQ
#define MSS_IRQ 10
#define MSS_BASE 0
#endif
#ifndef MSS_DMA
#define MSS_DMA 1
#define MSS_DMA 0
#endif
#ifndef U6850_BASE
#define U6850_BASE 0x330
#ifndef MSS_IRQ
#define MSS_IRQ 0
#endif
#ifndef U6850_IRQ
#define U6850_IRQ 5
#ifndef GUS16_BASE
#define GUS16_BASE 0
#endif
#ifndef U6850_DMA
#define U6850_DMA 1
#ifndef GUS16_DMA
#define GUS16_DMA 0
#endif
#ifndef GUS16_IRQ
#define GUS16_IRQ 0
#endif
#ifndef SSCAPE_BASE
#define SSCAPE_BASE 0
#endif
#ifndef SSCAPE_DMA
#define SSCAPE_DMA 0
#endif
#ifndef SSCAPE_IRQ
#define SSCAPE_IRQ 0
#endif
#ifndef SSCAPE_MSS_BASE
#define SSCAPE_MSS_BASE 0
#endif
#ifndef SSCAPE_MSS_DMA
#define SSCAPE_MSS_DMA 0
#endif
#ifndef SSCAPE_MSS_IRQ
#define SSCAPE_MSS_IRQ 0
#endif
#ifndef TRIX_BASE
#define TRIX_BASE 0x530
#endif
#ifndef TRIX_IRQ
#define TRIX_IRQ 10
#endif
#ifndef TRIX_DMA
#define TRIX_DMA 1
#endif
#ifndef MAX_REALTIME_FACTOR
#define MAX_REALTIME_FACTOR 4
#endif
/************* PCM DMA buffer sizes *******************/
@ -227,7 +264,7 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
#define SND_DEV_STATUS 6 /* /dev/sndstat */
/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
#define SND_DEV_SEQ2 8 /* /dev/sequecer, level 2 interface */
#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
#define SND_DEV_PSS SND_DEV_SNDPROC
@ -237,19 +274,22 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define OFF 0
#define MAX_AUDIO_DEV 5
#define MAX_MIXER_DEV 2
#define MAX_MIXER_DEV 5
#define MAX_SYNTH_DEV 3
#define MAX_MIDI_DEV 6
#define MAX_TIMER_DEV 3
struct fileinfo {
int mode; /* Open mode */
int mode; /* Open mode */
DECLARE_FILE(); /* Reference to file-flags. OS-dependent. */
};
struct address_info {
int io_base;
int irq;
int dma;
int dma; /* write dma channel */
int dma_read; /* read dma channel */
int always_detect; /* 1=Trust me, it's there */
};
#define SYNTH_MAX_VOICES 32
@ -259,10 +299,13 @@ struct voice_alloc_info {
int used_voices;
int ptr; /* For device specific use */
unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */
int timestamp;
int alloc_times[SYNTH_MAX_VOICES];
};
struct channel_info {
int pgm_num;
int bender_value;
unsigned char controllers[128];
};
@ -279,17 +322,18 @@ struct channel_info {
#define OPEN_WRITE 2
#define OPEN_READWRITE 3
#include "os.h"
#include "sound_calls.h"
#include "dev_table.h"
#ifndef DEB
#define DEB(x)
#endif
#ifndef AUDIO_DDB
#define AUDIO_DDB(x)
#endif
#define TIMER_ARMED 121234
#define TIMER_NOT_ARMED 1
#define FUTURE_VERSION
#endif
#endif

View file

@ -25,7 +25,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* sound_switch.c,v 1.4 1994/10/01 02:17:12 swallace Exp
*/
#include "sound_config.h"
@ -116,7 +115,7 @@ init_status (void)
status_ptr = 0;
put_status ("Sound Driver:" SOUND_VERSION_STRING
put_status ("VoxWare Sound Driver:" SOUND_VERSION_STRING
" (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")"
"\n");
@ -185,7 +184,11 @@ init_status (void)
return;
}
if (!put_status ("\nPCM devices:\n"))
#ifdef EXCLUDE_AUDIO
if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n"))
return;
#else
if (!put_status ("\nAudio devices:\n"))
return;
for (i = 0; i < num_audiodevs; i++)
@ -199,7 +202,12 @@ init_status (void)
if (!put_status ("\n"))
return;
}
#endif
#ifdef EXCLUDE_SEQUENCER
if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n"))
return;
#else
if (!put_status ("\nSynth devices:\n"))
return;
@ -214,7 +222,12 @@ init_status (void)
if (!put_status ("\n"))
return;
}
#endif
#ifdef EXCLUDE_MIDI
if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n"))
return;
#else
if (!put_status ("\nMidi devices:\n"))
return;
@ -229,8 +242,9 @@ init_status (void)
if (!put_status ("\n"))
return;
}
#endif
if (!put_status ("\nMIDI Timers:\n"))
if (!put_status ("\nTimers:\n"))
return;
for (i = 0; i < num_sound_timers; i++)
@ -245,12 +259,20 @@ init_status (void)
return;
}
if (!put_status ("\n"))
return;
if (!put_status_int (num_mixers, 10))
return;
if (!put_status (" mixer(s) installed\n"))
if (!put_status ("\nMixers:\n"))
return;
for (i = 0; i < num_mixers; i++)
{
if (!put_status_int (i, 10))
return;
if (!put_status (": "))
return;
if (!put_status (mixer_devs[i]->name))
return;
if (!put_status ("\n"))
return;
}
}
static int
@ -292,23 +314,16 @@ sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
return audio_read (dev, file, buf, count);
break;
#ifndef EXCLUDE_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
return sequencer_read (dev, file, buf, count);
break;
#endif
#ifndef EXCLUDE_MIDI
case SND_DEV_MIDIN:
return MIDIbuf_read (dev, file, buf, count);
#endif
#ifndef EXCLUDE_PSS
case SND_DEV_PSS:
return pss_read (dev, file, buf, count);
#endif
default:
printk ("Sound: Undefined minor device %d\n", dev);
}
@ -325,12 +340,10 @@ sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
switch (dev & 0x0f)
{
#ifndef EXCLUDE_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
return sequencer_write (dev, file, buf, count);
break;
#endif
case SND_DEV_DSP:
case SND_DEV_DSP16:
@ -343,11 +356,6 @@ sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
return MIDIbuf_write (dev, file, buf, count);
#endif
#ifndef EXCLUDE_PSS
case SND_DEV_PSS:
return pss_write (dev, file, buf, count);
#endif
default:
return RET_ERROR (EPERM);
}
@ -384,13 +392,11 @@ sound_open_sw (int dev, struct fileinfo *file)
return 0;
break;
#ifndef EXCLUDE_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
if ((retval = sequencer_open (dev, file)) < 0)
return retval;
break;
#endif
#ifndef EXCLUDE_MIDI
case SND_DEV_MIDIN:
@ -399,13 +405,6 @@ sound_open_sw (int dev, struct fileinfo *file)
break;
#endif
#ifndef EXCLUDE_PSS
case SND_DEV_PSS:
if ((retval = pss_open (dev, file)) < 0)
return retval;
break;
#endif
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
@ -442,12 +441,10 @@ sound_release_sw (int dev, struct fileinfo *file)
case SND_DEV_CTL:
break;
#ifndef EXCLUDE_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
sequencer_release (dev, file);
break;
#endif
#ifndef EXCLUDE_MIDI
case SND_DEV_MIDIN:
@ -455,12 +452,6 @@ sound_release_sw (int dev, struct fileinfo *file)
break;
#endif
#ifndef EXCLUDE_PSS
case SND_DEV_PSS:
pss_release (dev, file);
break;
#endif
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
@ -481,11 +472,27 @@ sound_ioctl_sw (int dev, struct fileinfo *file,
{
DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
if ((dev & 0x0f) != SND_DEV_CTL && num_mixers > 0)
if ((cmd >> 8) & 0xff == 'M') /*
* Mixer ioctl
*/
return mixer_devs[0]->ioctl (0, cmd, arg);
if ((cmd >> 8) & 0xff == 'M' && num_mixers > 0) /* Mixer ioctl */
if ((dev & 0x0f) != SND_DEV_CTL)
{
int dtype = dev & 0x0f;
int mixdev;
switch (dtype)
{
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
mixdev = audio_devs[dev >> 4]->mixer_dev;
if (mixdev < 0 || mixdev >= num_mixers)
return RET_ERROR (ENXIO);
return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg);
break;
default:
return mixer_devs[0]->ioctl (0, cmd, arg);
}
}
switch (dev & 0x0f)
{
@ -503,12 +510,10 @@ sound_ioctl_sw (int dev, struct fileinfo *file,
return mixer_devs[dev]->ioctl (dev, cmd, arg);
break;
#ifndef EXCLUDE_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
return sequencer_ioctl (dev, file, cmd, arg);
break;
#endif
case SND_DEV_DSP:
case SND_DEV_DSP16:
@ -522,12 +527,6 @@ sound_ioctl_sw (int dev, struct fileinfo *file,
break;
#endif
#ifndef EXCLUDE_PSS
case SND_DEV_PSS:
return pss_ioctl (dev, file, cmd, arg);
break;
#endif
default:
return RET_ERROR (EPERM);
break;

View file

@ -26,7 +26,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* sound_timer.c,v 1.2 1994/10/01 02:17:13 swallace Exp
*/
#define SEQUENCER_C
@ -88,8 +87,8 @@ static unsigned long
tmr2ticks (int tmr_value)
{
/*
* Convert timer ticks to MIDI ticks
*/
* Convert timer ticks to MIDI ticks
*/
unsigned long tmp;
unsigned long scale;
@ -111,8 +110,8 @@ reprogram_timer (void)
usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
/*
* Don't kill the system by setting too high timer rate
*/
* Don't kill the system by setting too high timer rate
*/
if (usecs_per_tick < 2000)
usecs_per_tick = 2000;

View file

@ -1,8 +1,8 @@
/*
* sound/386bsd/soundcard.c
*
*
* Soundcard driver for FreeBSD.
*
*
* Copyright by Hannu Savolainen 1993
*
* Redistribution and use in source and binary forms, with or without
@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: soundcard.c,v 1.25 1995/05/11 19:26:24 rgrimes Exp $
* $Id: soundcard.c,v 1.24 1995/03/12 23:34:10 swallace Exp $
*/
#include "sound_config.h"
@ -78,6 +78,14 @@ struct isa_driver gusmaxdriver = {sndprobe, sndattach, "gusmax"};
struct isa_driver uartdriver = {sndprobe, sndattach, "uart"};
struct isa_driver mssdriver = {sndprobe, sndattach, "mss"};
void
adintr(INT_HANDLER_PARMS(irq,dummy))
{
#ifndef EXCLUDE_AD1848
ad1848_interrupt(INT_HANDLER_CALL(irq));
#endif
}
unsigned
long
get_time(void)
@ -91,7 +99,7 @@ int x;
return timecopy.tv_usec/(1000000/HZ) +
(unsigned long)timecopy.tv_sec*HZ;
}
int
sndread (int dev, struct uio *buf)
@ -162,31 +170,40 @@ sndioctl (dev_t dev, int cmd, caddr_t arg, int mode)
int
sndselect (int dev, int rw, struct proc *p)
{
int r,s;
dev = minor (dev);
DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
DEB (printk ("snd_select(dev=%d, rw=%d, pid=%d)\n", dev, rw, p->p_pid));
#ifdef ALLOW_SELECT
switch (dev & 0x0f)
{
#ifndef EXCLUDE_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
return sequencer_select (dev, &files[dev], rw, p);
break;
#endif
r = 0;
DISABLE_INTR(s);
switch (rw) {
case FREAD: /* record */
if(DMAbuf_input_ready(dev >> 4))
r = 1;
else
selrecord(p, &selinfo[dev >> 4]);
break;
case FWRITE: /* play */
if(DMAbuf_output_ready(dev >> 4))
r = 1;
else
selrecord(p, &selinfo[dev >> 4]);
break;
}
RESTORE_INTR(s);
#ifndef EXCLUDE_MIDI
case SND_DEV_MIDIN:
return MIDIbuf_select (dev, &files[dev], rw, p);
break;
#endif
return r;
#ifndef EXCLUDE_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
return audio_select (dev, &files[dev], rw, p);
break;
#endif
default:
return 0;
}
#endif
return 0;
}
static unsigned short
@ -243,7 +260,8 @@ sndprobe (struct isa_device *dev)
hw_config.io_base = dev->id_iobase;
hw_config.irq = ipri_to_irq (dev->id_irq);
hw_config.dma = dev->id_drq;
hw_config.dma_read = dev->id_flags; /* misuse the flags field for read dma*/
if(unit)
return sndtable_probe (unit, &hw_config);
else
@ -256,7 +274,7 @@ sndattach (struct isa_device *dev)
int i, unit;
static int midi_initialized = 0;
static int seq_initialized = 0;
static int generic_midi_initialized = 0;
static int generic_midi_initialized = 0;
unsigned long mem_start = 0xefffffffUL;
struct address_info hw_config;
@ -264,6 +282,7 @@ sndattach (struct isa_device *dev)
hw_config.io_base = dev->id_iobase;
hw_config.irq = ipri_to_irq (dev->id_irq);
hw_config.dma = dev->id_drq;
hw_config.dma_read = dev->id_flags; /* misuse the flags field for read dma*/
if(!unit)
return FALSE;
@ -400,7 +419,7 @@ sound_mem_init (void)
if (tmpbuf == NULL)
{
printk ("snd: Unable to allocate %ld bytes of buffer\n",
printk ("snd: Unable to allocate %d bytes of buffer\n",
audio_devs[dev]->buffsize);
return;
}
@ -429,11 +448,12 @@ snd_ioctl_return (int *addr, int value)
}
int
snd_set_irq_handler (int interrupt_level, void(*hndlr)(int))
snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO(), char *name)
{
return 1;
}
void
snd_release_irq(int vect)
{

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
#define SOUND_VERSION_STRING "3.0-beta-950506"

1120
sys/i386/isa/sound/sscape.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* sys_timer.c,v 1.2 1994/10/01 02:17:16 swallace Exp
*/
#define SEQUENCER_C
@ -52,13 +51,13 @@ static unsigned long
tmr2ticks (int tmr_value)
{
/*
* Convert system timer ticks (HZ) to MIDI ticks
*/
* Convert system timer ticks (HZ) to MIDI ticks
*/
unsigned long tmp;
unsigned long scale;
tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */
tmp = (tmr_value * 1000) / HZ; /* Convert to msecs */
scale = (60 * 1000) / (curr_tempo * curr_timebase); /* msecs per MIDI tick */

323
sys/i386/isa/sound/trix.c Normal file
View file

@ -0,0 +1,323 @@
/*
* sound/trix.c
*
* Low level driver for the MediaTriX AudioTriX Pro
* (MT-0002-PC Control Chip)
*
* Copyright by Hannu Savolainen 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
* notice, this list of conditions and the following disclaimer. 2.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include "sound_config.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_TRIX)
#ifdef INCLUDE_TRIX_BOOT
#include "trix_boot.h"
#endif
static int kilroy_was_here = 0; /* Don't detect twice */
static int sb_initialized = 0;
static int mpu_initialized = 0;
static unsigned char
trix_read (int addr)
{
OUTB ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */
return INB (0x391); /* MT-0002-PC ASIC data */
}
static void
trix_write (int addr, int data)
{
OUTB ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */
OUTB ((unsigned char) data, 0x391); /* MT-0002-PC ASIC data */
}
static void
download_boot (int base)
{
int i = 0, n = sizeof (trix_boot);
trix_write (0xf8, 0x00); /* ??????? */
OUTB (0x01, base + 6); /* Clear the internal data pointer */
OUTB (0x00, base + 6); /* Restart */
/*
* Write the boot code to the RAM upload/download register.
* Each write increments the internal data pointer.
*/
OUTB (0x01, base + 6); /* Clear the internal data pointer */
OUTB (0x1A, 0x390); /* Select RAM download/upload port */
for (i = 0; i < n; i++)
OUTB (trix_boot[i], 0x391);
for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */
OUTB (0x00, 0x391);
OUTB (0x00, base + 6); /* Reset */
OUTB (0x50, 0x390); /* ?????? */
}
static int
trix_set_wss_port (struct address_info *hw_config)
{
unsigned char addr_bits;
if (kilroy_was_here) /* Already initialized */
return 0;
kilroy_was_here = 1;
if (trix_read (0x15) != 0x71) /* No asic signature */
return 0;
/*
* Disable separate wave playback and recording DMA channels since
* the driver doesn't support duplex mode yet.
*/
trix_write (0x13, trix_read (0x13) & ~0x80);
trix_write (0x14, trix_read (0x14) & ~0x80);
/*
* Configure the ASIC to place the codec to the proper I/O location
*/
switch (hw_config->io_base)
{
case 0x530:
addr_bits = 0;
break;
case 0x604:
addr_bits = 1;
break;
case 0xE80:
addr_bits = 2;
break;
case 0xF40:
addr_bits = 3;
break;
default:
return 0;
}
trix_write (0x19, (trix_read (0x19) & 0x03) | addr_bits);
return 1;
}
/*
* Probe and attach routines for the Windows Sound System mode of
* AudioTriX Pro
*/
int
probe_trix_wss (struct address_info *hw_config)
{
/*
* Check if the IO port returns valid signature. The original MS Sound
* system returns 0x04 while some cards (AudioTriX Pro for example)
* return 0x00.
*/
if (!trix_set_wss_port (hw_config))
return 0;
if ((INB (hw_config->io_base + 3) & 0x3f) != 0x00)
{
DDB (printk ("No MSS signature detected on port 0x%x\n", hw_config->io_base));
return 0;
}
if (hw_config->irq > 11)
{
printk ("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq);
return 0;
}
if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
{
printk ("AudioTriX: Bad WSS 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)
{
printk ("AudioTriX: Can't use DMA0 with a 8 bit card\n");
return 0;
}
if (hw_config->irq > 7 && hw_config->irq != 9 && INB (hw_config->io_base + 3) & 0x80)
{
printk ("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq);
return 0;
}
return ad1848_detect (hw_config->io_base + 4);
}
long
attach_trix_wss (long mem_start, struct address_info *hw_config)
{
static unsigned char interrupt_bits[12] =
{-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
char bits;
static unsigned char dma_bits[4] =
{1, 2, 0, 3};
int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
if (!kilroy_was_here)
return mem_start;
/*
* Set the IRQ and DMA addresses.
*/
bits = interrupt_bits[hw_config->irq];
if (bits == -1)
return mem_start;
OUTB (bits | 0x40, config_port);
if ((INB (version_port) & 0x40) == 0)
printk ("[IRQ Conflict?]");
OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */
ad1848_init ("AudioTriX Pro", hw_config->io_base + 4,
hw_config->irq,
hw_config->dma,
hw_config->dma);
return mem_start;
}
int
probe_trix_sb (struct address_info *hw_config)
{
int tmp;
unsigned char conf;
static char irq_translate[] =
{-1, -1, -1, 0, 1, 2, -1, 3};
#ifndef INCLUDE_TRIX_BOOT
return 0; /* No boot code -> no fun */
#endif
if (!kilroy_was_here)
return 0; /* AudioTriX Pro has not been detected earlier */
if (sb_initialized)
return 0;
if (hw_config->io_base & 0xffffff8f != 0x200)
return 0;
tmp = hw_config->irq;
if (tmp > 7)
return 0;
if (irq_translate[tmp] == -1)
return 0;
tmp = hw_config->dma;
if (tmp != 1 && tmp != 3)
return 0;
conf = 0x84; /* DMA and IRQ enable */
conf |= hw_config->io_base & 0x70; /* I/O address bits */
conf |= irq_translate[hw_config->irq];
if (hw_config->dma == 3)
conf |= 0x08;
trix_write (0x1b, conf);
download_boot (hw_config->io_base);
sb_initialized = 1;
return 1;
}
long
attach_trix_sb (long mem_start, struct address_info *hw_config)
{
printk (" <AudioTriX>");
return mem_start;
}
long
attach_trix_mpu (long mem_start, struct address_info *hw_config)
{
return attach_mpu401 (mem_start, hw_config);
}
int
probe_trix_mpu (struct address_info *hw_config)
{
unsigned char conf;
static char irq_bits[] =
{-1, -1, -1, 1, 2, 3, -1, 4, -1, 5};
if (!kilroy_was_here)
return 0; /* AudioTriX Pro has not been detected earlier */
if (!sb_initialized)
return 0;
if (mpu_initialized)
return 0;
if (hw_config->irq > 9)
return 0;
if (irq_bits[hw_config->irq] == -1)
return 0;
switch (hw_config->io_base)
{
case 0x330:
conf = 0x00;
break;
case 0x370:
conf = 0x04;
break;
case 0x3b0:
conf = 0x08;
break;
case 0x3f0:
conf = 0x0c;
break;
default:
return 0; /* Invalid port */
}
conf |= irq_bits[hw_config->irq] << 4;
trix_write (0x19, (trix_read (0x19) & 0x83) | conf);
mpu_initialized = 1;
return probe_mpu401 (hw_config);
}
#endif

View file

@ -1,29 +1,26 @@
/*
* tuning.h,v 1.2 1994/08/02 07:41:00 davidg Exp
*/
#ifdef SEQUENCER_C
unsigned short semitone_tuning[24] =
unsigned short semitone_tuning[24] =
{
/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983,
/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784,
/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983,
/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784,
/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
};
unsigned short cent_tuning[100] =
{
/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041,
/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087,
/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134,
/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181,
/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228,
/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275,
/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323,
/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371,
/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419,
/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467,
/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515,
/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564,
/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041,
/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087,
/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134,
/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181,
/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228,
/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275,
/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323,
/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371,
/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419,
/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467,
/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515,
/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564,
/* 96 */ 10570, 10576, 10582, 10589
};
#else

View file

@ -26,7 +26,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* uart6850.c,v 1.2 1994/10/01 02:17:17 swallace Exp
*/
#include "sound_config.h"
@ -94,9 +93,8 @@ uart6850_input_loop (void)
}
void
m6850intr (int unit)
m6850intr (INTR_HANDLER_PARMS (irq, dummy))
{
printk ("M");
if (input_avail ())
uart6850_input_loop ();
}
@ -244,6 +242,7 @@ static struct midi_operations uart6850_operations =
{
{"6850 UART", 0, 0, SNDCARD_UART6850},
&std_midi_synth,
{0},
uart6850_open,
uart6850_close,
uart6850_ioctl,
@ -285,7 +284,7 @@ attach_uart6850 (long mem_start, struct address_info *hw_config)
RESTORE_INTR (flags);
#ifdef __FreeBSD__
#if defined(__FreeBSD__)
printk ("uart0: <6850 Midi Interface>");
#else
printk (" <6850 Midi Interface>");
@ -314,7 +313,7 @@ probe_uart6850 (struct address_info *hw_config)
uart6850_base = hw_config->io_base;
uart6850_irq = hw_config->irq;
if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0)
if (snd_set_irq_handler (uart6850_irq, m6850intr, "MIDI6850") < 0)
return 0;
ok = reset_uart6850 ();

View file

@ -1,69 +1,69 @@
static unsigned char ulaw_dsp[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2,
5, 9, 13, 17, 21, 25, 29, 33,
37, 41, 45, 49, 53, 57, 61, 65,
68, 70, 72, 74, 76, 78, 80, 82,
84, 86, 88, 90, 92, 94, 96, 98,
100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115,
115, 116, 116, 117, 117, 118, 118, 119,
119, 120, 120, 121, 121, 122, 122, 123,
123, 123, 124, 124, 124, 124, 125, 125,
125, 125, 126, 126, 126, 126, 127, 127,
127, 127, 127, 127, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
252, 248, 244, 240, 236, 232, 228, 224,
220, 216, 212, 208, 204, 200, 196, 192,
189, 187, 185, 183, 181, 179, 177, 175,
173, 171, 169, 167, 165, 163, 161, 159,
157, 156, 155, 154, 153, 152, 151, 150,
149, 148, 147, 146, 145, 144, 143, 142,
142, 141, 141, 140, 140, 139, 139, 138,
138, 137, 137, 136, 136, 135, 135, 134,
134, 134, 133, 133, 133, 133, 132, 132,
132, 132, 131, 131, 131, 131, 130, 130,
130, 130, 130, 130, 129, 129, 129, 129,
129, 129, 129, 129, 128, 128, 128, 128,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2,
5, 9, 13, 17, 21, 25, 29, 33,
37, 41, 45, 49, 53, 57, 61, 65,
68, 70, 72, 74, 76, 78, 80, 82,
84, 86, 88, 90, 92, 94, 96, 98,
100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115,
115, 116, 116, 117, 117, 118, 118, 119,
119, 120, 120, 121, 121, 122, 122, 123,
123, 123, 124, 124, 124, 124, 125, 125,
125, 125, 126, 126, 126, 126, 127, 127,
127, 127, 127, 127, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
252, 248, 244, 240, 236, 232, 228, 224,
220, 216, 212, 208, 204, 200, 196, 192,
189, 187, 185, 183, 181, 179, 177, 175,
173, 171, 169, 167, 165, 163, 161, 159,
157, 156, 155, 154, 153, 152, 151, 150,
149, 148, 147, 146, 145, 144, 143, 142,
142, 141, 141, 140, 140, 139, 139, 138,
138, 137, 137, 136, 136, 135, 135, 134,
134, 134, 133, 133, 133, 133, 132, 132,
132, 132, 131, 131, 131, 131, 130, 130,
130, 130, 130, 130, 129, 129, 129, 129,
129, 129, 129, 129, 128, 128, 128, 128,
};
static unsigned char dsp_ulaw[] = {
31, 31, 31, 32, 32, 32, 32, 33,
33, 33, 33, 34, 34, 34, 34, 35,
35, 35, 35, 36, 36, 36, 36, 37,
37, 37, 37, 38, 38, 38, 38, 39,
39, 39, 39, 40, 40, 40, 40, 41,
41, 41, 41, 42, 42, 42, 42, 43,
43, 43, 43, 44, 44, 44, 44, 45,
45, 45, 45, 46, 46, 46, 46, 47,
47, 47, 47, 48, 48, 49, 49, 50,
50, 51, 51, 52, 52, 53, 53, 54,
54, 55, 55, 56, 56, 57, 57, 58,
58, 59, 59, 60, 60, 61, 61, 62,
62, 63, 63, 64, 65, 66, 67, 68,
69, 70, 71, 72, 73, 74, 75, 76,
77, 78, 79, 81, 83, 85, 87, 89,
91, 93, 95, 99, 103, 107, 111, 119,
255, 247, 239, 235, 231, 227, 223, 221,
219, 217, 215, 213, 211, 209, 207, 206,
205, 204, 203, 202, 201, 200, 199, 198,
197, 196, 195, 194, 193, 192, 191, 191,
190, 190, 189, 189, 188, 188, 187, 187,
186, 186, 185, 185, 184, 184, 183, 183,
182, 182, 181, 181, 180, 180, 179, 179,
178, 178, 177, 177, 176, 176, 175, 175,
175, 175, 174, 174, 174, 174, 173, 173,
173, 173, 172, 172, 172, 172, 171, 171,
171, 171, 170, 170, 170, 170, 169, 169,
169, 169, 168, 168, 168, 168, 167, 167,
167, 167, 166, 166, 166, 166, 165, 165,
165, 165, 164, 164, 164, 164, 163, 163,
163, 163, 162, 162, 162, 162, 161, 161,
161, 161, 160, 160, 160, 160, 159, 159,
31, 31, 31, 32, 32, 32, 32, 33,
33, 33, 33, 34, 34, 34, 34, 35,
35, 35, 35, 36, 36, 36, 36, 37,
37, 37, 37, 38, 38, 38, 38, 39,
39, 39, 39, 40, 40, 40, 40, 41,
41, 41, 41, 42, 42, 42, 42, 43,
43, 43, 43, 44, 44, 44, 44, 45,
45, 45, 45, 46, 46, 46, 46, 47,
47, 47, 47, 48, 48, 49, 49, 50,
50, 51, 51, 52, 52, 53, 53, 54,
54, 55, 55, 56, 56, 57, 57, 58,
58, 59, 59, 60, 60, 61, 61, 62,
62, 63, 63, 64, 65, 66, 67, 68,
69, 70, 71, 72, 73, 74, 75, 76,
77, 78, 79, 81, 83, 85, 87, 89,
91, 93, 95, 99, 103, 107, 111, 119,
255, 247, 239, 235, 231, 227, 223, 221,
219, 217, 215, 213, 211, 209, 207, 206,
205, 204, 203, 202, 201, 200, 199, 198,
197, 196, 195, 194, 193, 192, 191, 191,
190, 190, 189, 189, 188, 188, 187, 187,
186, 186, 185, 185, 184, 184, 183, 183,
182, 182, 181, 181, 180, 180, 179, 179,
178, 178, 177, 177, 176, 176, 175, 175,
175, 175, 174, 174, 174, 174, 173, 173,
173, 173, 172, 172, 172, 172, 171, 171,
171, 171, 170, 170, 170, 170, 169, 169,
169, 169, 168, 168, 168, 168, 167, 167,
167, 167, 166, 166, 166, 166, 165, 165,
165, 165, 164, 164, 164, 164, 163, 163,
163, 163, 162, 162, 162, 162, 161, 161,
161, 161, 160, 160, 160, 160, 159, 159,
};

View file

@ -0,0 +1,121 @@
#ifndef _ULTRASOUND_H_
#define _ULTRASOUND_H_
/*
* Copyright by Hannu Savolainen 1993
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
* ultrasound.h - Macros for programming the Gravis Ultrasound
* These macros are extremely device dependent
* and not portable.
*/
/*
* Private events for Gravis Ultrasound (GUS)
*
* Format:
* byte 0 - SEQ_PRIVATE (0xfe)
* byte 1 - Synthesizer device number (0-N)
* byte 2 - Command (see below)
* byte 3 - Voice number (0-31)
* bytes 4 and 5 - parameter P1 (unsigned short)
* bytes 6 and 7 - parameter P2 (unsigned short)
*
* Commands:
* Each command affects one voice defined in byte 3.
* Unused parameters (P1 and/or P2 *MUST* be initialized to zero).
* _GUS_NUMVOICES - Sets max. number of concurrent voices (P1=14-31, default 16)
* _GUS_VOICESAMPLE- ************ OBSOLETE *************
* _GUS_VOICEON - Starts voice (P1=voice mode)
* _GUS_VOICEOFF - Stops voice (no parameters)
* _GUS_VOICEFADE - Stops the voice smoothly.
* _GUS_VOICEMODE - Alters the voice mode, don't start or stop voice (P1=voice mode)
* _GUS_VOICEBALA - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7)
* _GUS_VOICEFREQ - Sets voice (sample) playback frequency (P1=Hz)
* _GUS_VOICEVOL - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
* _GUS_VOICEVOL2 - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
* (Like GUS_VOICEVOL but doesn't change the hw
* volume. It just updates volume in the voice table).
*
* _GUS_RAMPRANGE - Sets limits for volume ramping (P1=low volume, P2=high volume)
* _GUS_RAMPRATE - Sets the speed for volume ramping (P1=scale, P2=rate)
* _GUS_RAMPMODE - Sets the volume ramping mode (P1=ramping mode)
* _GUS_RAMPON - Starts volume ramping (no parameters)
* _GUS_RAMPOFF - Stops volume ramping (no parameters)
* _GUS_VOLUME_SCALE - Changes the volume calculation constants
* for all voices.
*/
#define _GUS_NUMVOICES 0x00
#define _GUS_VOICESAMPLE 0x01 /* OBSOLETE */
#define _GUS_VOICEON 0x02
#define _GUS_VOICEOFF 0x03
#define _GUS_VOICEMODE 0x04
#define _GUS_VOICEBALA 0x05
#define _GUS_VOICEFREQ 0x06
#define _GUS_VOICEVOL 0x07
#define _GUS_RAMPRANGE 0x08
#define _GUS_RAMPRATE 0x09
#define _GUS_RAMPMODE 0x0a
#define _GUS_RAMPON 0x0b
#define _GUS_RAMPOFF 0x0c
#define _GUS_VOICEFADE 0x0d
#define _GUS_VOLUME_SCALE 0x0e
#define _GUS_VOICEVOL2 0x0f
#define _GUS_VOICE_POS 0x10
/*
* GUS API macros
*/
#define _GUS_CMD(chn, voice, cmd, p1, p2) \
{_SEQ_NEEDBUF(8); _seqbuf[_seqbufptr] = SEQ_PRIVATE;\
_seqbuf[_seqbufptr+1] = (chn); _seqbuf[_seqbufptr+2] = cmd;\
_seqbuf[_seqbufptr+3] = voice;\
*(unsigned short*)&_seqbuf[_seqbufptr+4] = p1;\
*(unsigned short*)&_seqbuf[_seqbufptr+6] = p2;\
_SEQ_ADVBUF(8);}
#define GUS_NUMVOICES(chn, p1) _GUS_CMD(chn, 0, _GUS_NUMVOICES, (p1), 0)
#define GUS_VOICESAMPLE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICESAMPLE, (p1), 0) /* OBSOLETE */
#define GUS_VOICEON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEON, (p1), 0)
#define GUS_VOICEOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEOFF, 0, 0)
#define GUS_VOICEFADE(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEFADE, 0, 0)
#define GUS_VOICEMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEMODE, (p1), 0)
#define GUS_VOICEBALA(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEBALA, (p1), 0)
#define GUS_VOICEFREQ(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICEFREQ, \
(p) & 0xffff, ((p) >> 16) & 0xffff)
#define GUS_VOICEVOL(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL, (p1), 0)
#define GUS_VOICEVOL2(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL2, (p1), 0)
#define GUS_RAMPRANGE(chn, voice, low, high) _GUS_CMD(chn, voice, _GUS_RAMPRANGE, (low), (high))
#define GUS_RAMPRATE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_RAMPRATE, (p1), (p2))
#define GUS_RAMPMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPMODE, (p1), 0)
#define GUS_RAMPON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPON, (p1), 0)
#define GUS_RAMPOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_RAMPOFF, 0, 0)
#define GUS_VOLUME_SCALE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_VOLUME_SCALE, (p1), (p2))
#define GUS_VOICE_POS(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICE_POS, \
(p) & 0xffff, ((p) >> 16) & 0xffff)
#endif