Hannu Savolainen's VoxWare original sound drivers, version 2.9.
This commit is contained in:
commit
fbb347fe32
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/AMANCIO/; revision=3252
110
sys/i386/isa/sound/CHANGELOG
Normal file
110
sys/i386/isa/sound/CHANGELOG
Normal file
@ -0,0 +1,110 @@
|
||||
Changelog for version 2.90
|
||||
------------------------------------
|
||||
|
||||
This is an intermediate release (v3.0 prototype with some experimental
|
||||
features disabled). See experimental.txt for more info.
|
||||
|
||||
Since pre-3.0-949712
|
||||
- GUS MAX support
|
||||
- Partially working MSS/WSS support (could work with some cards).
|
||||
- Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs
|
||||
(GUS MAX, GUS16, WSS etc). Hardware ADPCM is possible with GUS16 and
|
||||
GUS MAX, but it doesn't work yet.
|
||||
Since pre-3.0-940426
|
||||
- AD1848/CS4248/CS4231 codec support (MSS, GUS MAX, Aztec, Orchid etc).
|
||||
This codec chip is used in various soundcards. This version is developed
|
||||
for the 16 bit daughtercard of GUS. It should work with other cards also
|
||||
if the following requirements are met:
|
||||
- The I/O, IRQ and DMA settings are jumper selectable or
|
||||
the card is initialized by booting DOS before booting Linux (etc.).
|
||||
- You add the IO, IRQ and DMA settings manually to the local.h.
|
||||
(Just define GUS16_BASE, GUS16_IRQ and GUS16_DMA). Note that
|
||||
the base address bust be the base address of the codec chip not the
|
||||
card itself. For the GUS16 these are the same but most MSS compatible
|
||||
cards have the codec located at card_base+4.
|
||||
- Some minor changes
|
||||
|
||||
Since 2.5 (******* MAJOR REWRITE ***********)
|
||||
|
||||
This version is based on v2.3. I have tried to maintain two versions
|
||||
together so that this one should have the same features than v2.5.
|
||||
Something may still be missing. If you notice such things, please let me
|
||||
know.
|
||||
|
||||
The Readme.v30 contains more details.
|
||||
|
||||
- /dev/midi## devices.
|
||||
- /dev/sequencer2
|
||||
|
||||
Since 2.5-beta2
|
||||
- Some fine tuning to the GUS v3.7 mixer code.
|
||||
- Fixed speed limits for the plain SB (1.0 to 2.0).
|
||||
|
||||
Since 2.5-beta
|
||||
- Fixed OPL-3 detection with SB. Caused problems with PAS16.
|
||||
- GUS v3.7 mixer support.
|
||||
|
||||
Since 2.4
|
||||
- Mixer support for Sound Galaxy NX Pro (define __SGNXPRO__ on your local.h).
|
||||
- Fixed truncated sound on /dev/dsp when the device is closed.
|
||||
- Linear volume mode for GUS
|
||||
- Pitch bends larger than +/- 2 octaves.
|
||||
- MIDI recording for SB and SB Pro. (Untested).
|
||||
- Some other fixes.
|
||||
- SB16 MIDI and DSP drivers only initialized if SB16 actually installed.
|
||||
- Implemented better detection for OPL-3. This should be usefull if you
|
||||
have an old SB Pro (the non-OPL-3 one) or a SB 2.0 clone which has a OPL-3.
|
||||
- SVR4.2 support by Ian Hartas. Initial ALPHA TEST version (untested).
|
||||
|
||||
Since 2.3b
|
||||
- Fixed bug which made it impossible to make long recordings to disk.
|
||||
Recording was not restarted after a buffer overflow situation.
|
||||
- Limited mixer support for GUS.
|
||||
- Numerous improvements to the GUS driver by Andrew Robinson. Including
|
||||
some click removal etc.
|
||||
|
||||
Since 2.3
|
||||
- Fixed some minor bugs in the SB16 driver.
|
||||
|
||||
Since 2.2b
|
||||
- Full SB16 DSP support. 8/16 bit, mono/stereo
|
||||
- The SCO and FreeBSD versions should be in sync now. There are some
|
||||
problems with SB16 and GUS in the freebsd versions.
|
||||
The DMA buffer allocation of the SCO version has been polished but
|
||||
there could still be some problems. At least it hogs memory.
|
||||
The DMA channel
|
||||
configuration method used in the sco/System is a hack.
|
||||
- Support for the MPU emulation of the SB16.
|
||||
- Some big arrays are now allocated boot time. This makes the bss segment
|
||||
smaller which makes it possible to use the full driver with
|
||||
NetBSD. These arrays are not allocated if no suitable soundcard is available.
|
||||
- Fixed a bug in the compute_and_set_volume in gus_wave.c
|
||||
- Fixed the too fast mono playback problem of SB Pro and PAS16.
|
||||
|
||||
Since 2.2
|
||||
- Stereo recording for SB Pro. Somehow it was missing and nobody
|
||||
had noticed it earlier.
|
||||
- Minor polishing.
|
||||
- Interpreting of boot time arguments (sound=) for Linux.
|
||||
- Breakup of sb_dsp.c. Parts of the code has been moved to
|
||||
sb_mixer.c and sb_midi.c
|
||||
|
||||
Since 2.1
|
||||
- Preliminary support for SB16.
|
||||
- The SB16 mixer is supported in it's native mode.
|
||||
- Digitized voice capability up to 44.1 kHz/8 bit/mono
|
||||
(16 bit and stereo support coming in the next release).
|
||||
- Fixed some bugs in the digitized voice driver for PAS16.
|
||||
- Proper initialization of the SB emulation of latest PAS16 models.
|
||||
|
||||
- Significantly improved /dev/dsp and /dev/audio support.
|
||||
- Now supports half duplex mode. It's now possible to record and
|
||||
playback without closing and reopening the device.
|
||||
- It's possible to use smaller buffers than earlier. There is a new
|
||||
ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &n) where n should be 1, 2 or 4.
|
||||
This call instructs the driver to use smaller buffers. The default
|
||||
buffer size (0.5 to 1.0 seconds) is divided by n. Should be called
|
||||
immediately after opening the device.
|
||||
|
||||
Since 2.0
|
||||
Just cosmetic changes.
|
25
sys/i386/isa/sound/COPYING
Normal file
25
sys/i386/isa/sound/COPYING
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
80
sys/i386/isa/sound/README
Normal file
80
sys/i386/isa/sound/README
Normal file
@ -0,0 +1,80 @@
|
||||
VoxWare v2.90 release notes
|
||||
--------------------------
|
||||
|
||||
|
||||
This version includes some hidden features which
|
||||
are described in the file experimental.txt
|
||||
Some of these features are not enabled by default. Look at
|
||||
experimental.txt for more info.
|
||||
|
||||
I just decided to release this version with some
|
||||
incompletely implemented features disabled since
|
||||
there are some new features required by a popular
|
||||
application. In addition there is also support
|
||||
for the GUS MAX and the 16 bit sampling option of GUS.
|
||||
|
||||
The MSS/WSS support works now. At least with SG NX Pro 16.
|
||||
|
||||
********* IMPORTANT *****************************************
|
||||
Linux 1.0 or later is required to by this driver version.
|
||||
|
||||
Don't distribute binaries which use /dev/sequencer and are
|
||||
compiled with the soundcard.h of this version. They will
|
||||
not work with version 2.x of the driver.
|
||||
*************************************************************
|
||||
|
||||
|
||||
You will need the snd-util-2.5.tar.gz and snd-data-0.1.tar.Z
|
||||
packages to use this driver. They should be in the same
|
||||
ftp site or BBS from where you got this driver. For
|
||||
example at nic.funet.fi:pub/OS/Linux/*.
|
||||
|
||||
If you are looking for the installation instructions, please
|
||||
look at linux/Readme.
|
||||
|
||||
Compatibility with the earlier versions
|
||||
---------------------------------------
|
||||
|
||||
This version is backward compatible with the version 2.X. All programs
|
||||
compiled with sys/soundcard.h of v2.X should work without problems.
|
||||
PROGRAMS COMPILED WITH THE sys/soundcard.h OF THIS VERSION WILL NOT
|
||||
WORK WITH v2.X DRIVER. BE CAREFULL WHEN DISTRIBUTING BINARIES COMPILED
|
||||
FOR THIS VERSION.
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
This driver contains code by several contributors. In addition several other
|
||||
persons have given usefull suggestions. The following is a list of major
|
||||
contributors. (I could have forgotten some names.)
|
||||
|
||||
Craig Metz 1/2 of the PAS16 Mixer and PCM support
|
||||
Rob Hooft Volume computation algorithm for the FM synth.
|
||||
Mika Liljeberg uLaw encoding and decoding routines
|
||||
Greg Lee Volume computation algorithm for the GUS and
|
||||
lot's of valuable suggestions.
|
||||
Andy Warner ISC port
|
||||
Jim Lowe FreeBSD port
|
||||
Anders Baekgaard Bughunting and valuable suggestions.
|
||||
Joerg Schubert SB16 DSP support.
|
||||
Andrew Robinson Improvements to the GUS driver
|
||||
Megens SA MIDI recording for SB and SB Pro.
|
||||
Mikael Nordqvist Linear volume support for GUS.
|
||||
Mikael Nordqvist Linear volume support for GUS.
|
||||
Ian Hartas SVR4.2 port
|
||||
Markus Aroharju and
|
||||
Risto Kankkunen Major contributions to the mixer support
|
||||
of GUS v3.7.
|
||||
Hunyue Yau Mixer support for SG NX Pro.
|
||||
Marc Hoffman PSS support.
|
||||
|
||||
Regards,
|
||||
|
||||
Hannu Savolainen
|
||||
hannu@voxware.pp.fi
|
||||
|
||||
Snail mail: Hannu Savolainen
|
||||
Pallaksentie 4 A 2
|
||||
00970 Helsinki
|
||||
Finland
|
||||
FAX: +358 0 395 1968 (usually not connected)
|
953
sys/i386/isa/sound/ad1848.c
Normal file
953
sys/i386/isa/sound/ad1848.c
Normal file
@ -0,0 +1,953 @@
|
||||
/*
|
||||
* sound/ad1848.c
|
||||
*
|
||||
* The low level driver for the AD1848/CS4248 codec chip which
|
||||
* is used for example in the MS Sound System.
|
||||
*
|
||||
* The CS4231 which is used in the GUS MAX and some other cards is
|
||||
* upwards compatible with AD1848 and this driver is able to drive it.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1994
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEB(x)
|
||||
#define DEB1(x)
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)
|
||||
|
||||
#define IMODE_NONE 0
|
||||
#define IMODE_OUTPUT 1
|
||||
#define IMODE_INPUT 2
|
||||
#define IMODE_INIT 3
|
||||
#define IMODE_MIDI 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int base;
|
||||
int irq;
|
||||
int dma_capture, dma_playback;
|
||||
unsigned char MCE_bit;
|
||||
|
||||
int speed;
|
||||
unsigned char speed_bits;
|
||||
int channels;
|
||||
int audio_format;
|
||||
unsigned char format_bits;
|
||||
|
||||
int xfer_count;
|
||||
int irq_mode;
|
||||
int intr_active;
|
||||
int opened;
|
||||
char *chip_name;
|
||||
int mode;
|
||||
}
|
||||
|
||||
ad1848_info;
|
||||
|
||||
static int nr_ad1848_devs = 0;
|
||||
static char irq2dev[16] =
|
||||
{-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1};
|
||||
|
||||
static int ad_format_mask[2 /*devc->mode*/ ] =
|
||||
{
|
||||
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
|
||||
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM
|
||||
};
|
||||
|
||||
static ad1848_info dev_info[MAX_AUDIO_DEV];
|
||||
|
||||
#define io_Index_Addr(d) ((d)->base)
|
||||
#define io_Indexed_Data(d) ((d)->base+1)
|
||||
#define io_Status(d) ((d)->base+2)
|
||||
#define io_Polled_IO(d) ((d)->base+3)
|
||||
|
||||
static int ad1848_open (int dev, int mode);
|
||||
static void ad1848_close (int dev);
|
||||
static int ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
|
||||
static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
|
||||
static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
|
||||
static int ad1848_prepare_for_IO (int dev, int bsize, int bcount);
|
||||
static void ad1848_reset (int dev);
|
||||
static void ad1848_halt (int dev);
|
||||
void ad1848_interrupt (int dev);
|
||||
|
||||
static int
|
||||
ad_read (ad1848_info * devc, int reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
int x;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
|
||||
x = INB (io_Indexed_Data (devc));
|
||||
/* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void
|
||||
ad_write (ad1848_info * devc, int reg, int data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
|
||||
OUTB ((unsigned char) (data & 0xff), io_Indexed_Data (devc));
|
||||
/* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
ad_set_MCE (ad1848_info * devc, int state)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (state)
|
||||
devc->MCE_bit = 0x40;
|
||||
else
|
||||
devc->MCE_bit = 0x00;
|
||||
OUTB (devc->MCE_bit, io_Index_Addr (devc));
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
wait_for_calibration (ad1848_info * devc)
|
||||
{
|
||||
int timeout = 0;
|
||||
|
||||
/*
|
||||
* Wait until the auto calibration process has finished.
|
||||
*
|
||||
* 1) Wait until the chip becomes ready (reads don't return 0x80).
|
||||
* 2) Wait until the ACI bit of I11 gets on and then off.
|
||||
*/
|
||||
|
||||
timeout = 100000;
|
||||
while (timeout > 0 && INB (devc->base) == 0x80)
|
||||
timeout--;
|
||||
if (INB (devc->base) == 0x80)
|
||||
printk ("ad1848: Auto calibration timed out(1).\n");
|
||||
|
||||
timeout = 100000;
|
||||
while (timeout > 0 && !(ad_read (devc, 11) & 0x20))
|
||||
timeout--;
|
||||
if (!(ad_read (devc, 11) & 0x20))
|
||||
printk ("ad1848: Auto calibration timed out(2).\n");
|
||||
|
||||
timeout = 100000;
|
||||
while (timeout > 0 && ad_read (devc, 11) & 0x20)
|
||||
timeout--;
|
||||
if (ad_read (devc, 11) & 0x20)
|
||||
printk ("ad1848: Auto calibration timed out(3).\n");
|
||||
}
|
||||
|
||||
static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
|
||||
{
|
||||
{
|
||||
"Generic AD1848 codec",
|
||||
DMA_AUTOMODE,
|
||||
AFMT_U8, /* Will be set later */
|
||||
NULL,
|
||||
ad1848_open,
|
||||
ad1848_close,
|
||||
ad1848_output_block,
|
||||
ad1848_start_input,
|
||||
ad1848_ioctl,
|
||||
ad1848_prepare_for_IO,
|
||||
ad1848_prepare_for_IO,
|
||||
ad1848_reset,
|
||||
ad1848_halt,
|
||||
NULL,
|
||||
NULL
|
||||
}};
|
||||
|
||||
static int
|
||||
ad1848_open (int dev, int mode)
|
||||
{
|
||||
int err;
|
||||
ad1848_info *devc = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
DEB (printk ("ad1848_open(int mode = %X)\n", mode));
|
||||
|
||||
if (dev < 0 || dev >= num_audiodevs)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (devc->opened)
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
printk ("ad1848: Already opened\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
if (devc->irq) /* Not managed by another driver */
|
||||
if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt)) < 0)
|
||||
{
|
||||
printk ("ad1848: IRQ in use\n");
|
||||
RESTORE_INTR (flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (DMAbuf_open_dma (dev) < 0)
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
printk ("ad1848: DMA in use\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
devc->intr_active = 0;
|
||||
devc->opened = 1;
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_close (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
DEB (printk ("ad1848_close(void)\n"));
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
devc->intr_active = 0;
|
||||
if (devc->irq) /* Not managed by another driver */
|
||||
snd_release_irq (devc->irq);
|
||||
ad1848_reset (dev);
|
||||
DMAbuf_close_dma (dev);
|
||||
devc->opened = 0;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
set_speed (ad1848_info * devc, int arg)
|
||||
{
|
||||
/*
|
||||
* The sampling speed is encoded in the least significant nible of I8. The
|
||||
* LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
|
||||
* three bits select the divisor (indirectly):
|
||||
*
|
||||
* The available speeds are in the following table. Keep the speeds in
|
||||
* the increasing order.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int speed;
|
||||
unsigned char bits;
|
||||
}
|
||||
speed_struct;
|
||||
|
||||
static speed_struct speed_table[] =
|
||||
{
|
||||
{5510, (0 << 1) | 1},
|
||||
{5510, (0 << 1) | 1},
|
||||
{6620, (7 << 1) | 1},
|
||||
{8000, (0 << 1) | 0},
|
||||
{9600, (7 << 1) | 0},
|
||||
{11025, (1 << 1) | 1},
|
||||
{16000, (1 << 1) | 0},
|
||||
{18900, (2 << 1) | 1},
|
||||
{22050, (3 << 1) | 1},
|
||||
{27420, (2 << 1) | 0},
|
||||
{32000, (3 << 1) | 0},
|
||||
{33075, (6 << 1) | 1},
|
||||
{37800, (4 << 1) | 1},
|
||||
{44100, (5 << 1) | 1},
|
||||
{48000, (6 << 1) | 0}
|
||||
};
|
||||
|
||||
int i, n, selected = -1;
|
||||
|
||||
n = sizeof (speed_table) / sizeof (speed_struct);
|
||||
|
||||
if (arg < speed_table[0].speed)
|
||||
selected = 0;
|
||||
if (arg > speed_table[n - 1].speed)
|
||||
selected = n - 1;
|
||||
|
||||
for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
|
||||
if (speed_table[i].speed == arg)
|
||||
selected = i;
|
||||
else if (speed_table[i].speed > arg)
|
||||
{
|
||||
int diff1, diff2;
|
||||
|
||||
diff1 = arg - speed_table[i - 1].speed;
|
||||
diff2 = speed_table[i].speed - arg;
|
||||
|
||||
if (diff1 < diff2)
|
||||
selected = i - 1;
|
||||
else
|
||||
selected = i;
|
||||
}
|
||||
|
||||
if (selected == -1)
|
||||
{
|
||||
printk ("ad1848: Can't find speed???\n");
|
||||
selected = 3;
|
||||
}
|
||||
|
||||
devc->speed = speed_table[selected].speed;
|
||||
devc->speed_bits = speed_table[selected].bits;
|
||||
return devc->speed;
|
||||
}
|
||||
|
||||
static int
|
||||
set_channels (ad1848_info * devc, int arg)
|
||||
{
|
||||
if (arg != 1 && arg != 2)
|
||||
return devc->channels;
|
||||
|
||||
devc->channels = arg;
|
||||
return arg;
|
||||
}
|
||||
|
||||
static int
|
||||
set_format (ad1848_info * devc, int arg)
|
||||
{
|
||||
|
||||
static struct format_tbl
|
||||
{
|
||||
int format;
|
||||
unsigned char bits;
|
||||
}
|
||||
format2bits [] =
|
||||
{
|
||||
{
|
||||
0, 0
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_MU_LAW, 1
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_A_LAW, 3
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_IMA_ADPCM, 5
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_U8, 0
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_S16_LE, 2
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_S16_BE, 6
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_S8, 0
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_U16_LE, 0
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_U16_BE, 0
|
||||
}
|
||||
};
|
||||
int i, n = sizeof (format2bits) / sizeof (struct format_tbl);
|
||||
|
||||
if (!(arg & ad_format_mask[devc->mode]))
|
||||
arg = AFMT_U8;
|
||||
|
||||
devc->audio_format = arg;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (format2bits[i].format == arg)
|
||||
{
|
||||
if ((devc->format_bits = format2bits[i].bits) == 0)
|
||||
return devc->audio_format = AFMT_U8; /* Was not supported */
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
/* Still hanging here. Something must be terribly wrong */
|
||||
devc->format_bits = 0;
|
||||
return devc->audio_format = AFMT_U8;
|
||||
}
|
||||
|
||||
static int
|
||||
ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
{
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SOUND_PCM_WRITE_RATE:
|
||||
if (local)
|
||||
return set_speed (devc, arg);
|
||||
return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_RATE:
|
||||
if (local)
|
||||
return devc->speed;
|
||||
return IOCTL_OUT (arg, devc->speed);
|
||||
|
||||
case SNDCTL_DSP_STEREO:
|
||||
if (local)
|
||||
return set_channels (devc, arg + 1) - 1;
|
||||
return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1);
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
if (local)
|
||||
return set_channels (devc, arg);
|
||||
return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_CHANNELS:
|
||||
if (local)
|
||||
return devc->channels;
|
||||
return IOCTL_OUT (arg, devc->channels);
|
||||
|
||||
case SNDCTL_DSP_SAMPLESIZE:
|
||||
if (local)
|
||||
return set_format (devc, arg);
|
||||
return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_BITS:
|
||||
if (local)
|
||||
return devc->audio_format;
|
||||
return IOCTL_OUT (arg, devc->audio_format);
|
||||
|
||||
default:;
|
||||
}
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
cnt = count;
|
||||
|
||||
if (devc->audio_format == AFMT_IMA_ADPCM)
|
||||
{
|
||||
cnt /= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
|
||||
cnt >>= 1;
|
||||
}
|
||||
if (devc->channels > 1)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE &&
|
||||
intrflag &&
|
||||
cnt == devc->xfer_count)
|
||||
{
|
||||
devc->irq_mode = IMODE_OUTPUT;
|
||||
devc->intr_active = 1;
|
||||
return; /*
|
||||
* Auto DMA mode on. No need to react
|
||||
*/
|
||||
}
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (dma_restart)
|
||||
{
|
||||
ad1848_halt (dev);
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
|
||||
}
|
||||
|
||||
ad_set_MCE (devc, 1);
|
||||
|
||||
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
|
||||
ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
|
||||
|
||||
|
||||
ad_write (devc, 9, 0x0d); /*
|
||||
* Playback enable, single DMA channel mode,
|
||||
* auto calibration on.
|
||||
*/
|
||||
|
||||
ad_set_MCE (devc, 0); /*
|
||||
* Starts the calibration process and
|
||||
* enters playback mode after it.
|
||||
*/
|
||||
wait_for_calibration (devc);
|
||||
|
||||
devc->xfer_count = cnt;
|
||||
devc->irq_mode = IMODE_OUTPUT;
|
||||
devc->intr_active = 1;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
/* int count_reg = (devc->mode == 1) ? 14 : 30; */
|
||||
|
||||
cnt = count;
|
||||
if (devc->audio_format == AFMT_IMA_ADPCM)
|
||||
{
|
||||
cnt /= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
|
||||
cnt >>= 1;
|
||||
}
|
||||
if (devc->channels > 1)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE &&
|
||||
intrflag &&
|
||||
cnt == devc->xfer_count)
|
||||
{
|
||||
devc->irq_mode = IMODE_INPUT;
|
||||
devc->intr_active = 1;
|
||||
return; /*
|
||||
* Auto DMA mode on. No need to react
|
||||
*/
|
||||
}
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (dma_restart)
|
||||
{
|
||||
ad1848_halt (dev);
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
|
||||
}
|
||||
|
||||
ad_set_MCE (devc, 1);
|
||||
#if 0
|
||||
ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff));
|
||||
ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff));
|
||||
#else
|
||||
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
|
||||
ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
|
||||
if (devc->mode == 2)
|
||||
{
|
||||
ad_write (devc, 31, (unsigned char) (cnt & 0xff));
|
||||
ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff));
|
||||
}
|
||||
#endif
|
||||
|
||||
ad_write (devc, 9, 0x0e); /*
|
||||
* Capture enable, single DMA channel mode,
|
||||
* auto calibration on.
|
||||
*/
|
||||
|
||||
ad_set_MCE (devc, 0); /*
|
||||
* Starts the calibration process and
|
||||
* enters playback mode after it.
|
||||
*/
|
||||
wait_for_calibration (devc);
|
||||
|
||||
devc->xfer_count = cnt;
|
||||
devc->irq_mode = IMODE_INPUT;
|
||||
devc->intr_active = 1;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
ad1848_prepare_for_IO (int dev, int bsize, int bcount)
|
||||
{
|
||||
int timeout;
|
||||
unsigned char fs;
|
||||
unsigned long flags;
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
ad_set_MCE (devc, 1); /* Enables changes to the format select reg */
|
||||
fs = devc->speed_bits | (devc->format_bits << 5);
|
||||
|
||||
if (devc->channels > 1)
|
||||
fs |= 0x10;
|
||||
|
||||
ad_write (devc, 8, fs);
|
||||
/*
|
||||
* Write to I8 starts resyncronization. Wait until it completes.
|
||||
*/
|
||||
timeout = 10000;
|
||||
while (timeout > 0 && INB (devc->base) == 0x80)
|
||||
timeout--;
|
||||
|
||||
ad_set_MCE (devc, 0); /*
|
||||
* Starts the calibration process and
|
||||
* enters playback mode after it.
|
||||
*/
|
||||
wait_for_calibration (devc);
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* If mode == 2 (CS4231), set I28 also. It's the capture format register.
|
||||
*/
|
||||
if (devc->mode == 2)
|
||||
{
|
||||
ad_set_MCE (devc, 1);
|
||||
ad_write (devc, 28, fs);
|
||||
|
||||
/*
|
||||
* Write to I28 starts resyncronization. Wait until it completes.
|
||||
*/
|
||||
timeout = 10000;
|
||||
while (timeout > 0 && INB (devc->base) == 0x80)
|
||||
timeout--;
|
||||
|
||||
ad_set_MCE (devc, 0); /*
|
||||
* Starts the calibration process and
|
||||
* enters playback mode after it.
|
||||
*/
|
||||
wait_for_calibration (devc);
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
devc->xfer_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_reset (int dev)
|
||||
{
|
||||
ad1848_halt (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_halt (int dev)
|
||||
{
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
ad_write (devc, 9, 0); /* Clear the PEN and CEN bits (among others) */
|
||||
OUTB (0, io_Status (devc)); /* Clear interrupt status */
|
||||
}
|
||||
|
||||
int
|
||||
ad1848_detect (int io_base)
|
||||
{
|
||||
|
||||
#define DDB(x) x
|
||||
|
||||
unsigned char tmp;
|
||||
int i;
|
||||
ad1848_info *devc = &dev_info[nr_ad1848_devs];
|
||||
unsigned char tmp1 = 0xff, tmp2 = 0xff;
|
||||
|
||||
if (nr_ad1848_devs >= MAX_AUDIO_DEV)
|
||||
return 0;
|
||||
|
||||
devc->base = io_base;
|
||||
devc->MCE_bit = 0x40;
|
||||
devc->irq = 0;
|
||||
devc->dma_capture = 0;
|
||||
devc->dma_playback = 0;
|
||||
devc->opened = 0;
|
||||
devc->chip_name = "AD1848";
|
||||
devc->mode = 1; /* MODE1 = original AD1848 */
|
||||
|
||||
/*
|
||||
* Check that the I/O address is in use.
|
||||
*
|
||||
* The bit 0x80 of the base I/O port is known to be 0 after the
|
||||
* chip has performed it's power on initialization. Just assume
|
||||
* this has happened before the OS is starting.
|
||||
*
|
||||
* If the I/O address is unused, it typically returns 0xff.
|
||||
*/
|
||||
|
||||
if ((INB (devc->base) & 0x80) != 0x00) /* Not a AD1884 */
|
||||
{
|
||||
DDB (printk ("ad_detect_A\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if it's possible to change contents of the indirect registers.
|
||||
* Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
|
||||
* so try to avoid using it.
|
||||
*/
|
||||
|
||||
ad_write (devc, 0, 0xaa);
|
||||
ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */
|
||||
|
||||
if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45)
|
||||
{
|
||||
DDB (printk ("ad_detect_B (%x/%x)\n", tmp1, tmp2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ad_write (devc, 0, 0x45);
|
||||
ad_write (devc, 1, 0xaa);
|
||||
|
||||
if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa)
|
||||
{
|
||||
DDB (printk ("ad_detect_C (%x/%x)\n", tmp1, tmp2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The indirect register I12 has some read only bits. Lets
|
||||
* try to change them.
|
||||
*/
|
||||
|
||||
tmp = ad_read (devc, 12);
|
||||
ad_write (devc, 12, (~tmp) & 0x0f);
|
||||
|
||||
if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f))
|
||||
{
|
||||
DDB (printk ("ad_detect_D (%x)\n", tmp1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE! Last 4 bits of the reg I12 tell the chip revision.
|
||||
* 0x01=RevB and 0x0A=RevC.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The original AD1848/CS4248 has just 15 indirect registers. This means
|
||||
* that I0 and I16 should return the same value (etc.).
|
||||
* Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
|
||||
* with CS4231.
|
||||
*/
|
||||
|
||||
ad_write (devc, 12, 0); /* Mode2=disabled */
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16)))
|
||||
{
|
||||
DDB (printk ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
|
||||
* The bit 0x80 is always 1 in CS4248 and CS4231.
|
||||
*/
|
||||
|
||||
ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
|
||||
|
||||
tmp1 = ad_read (devc, 12);
|
||||
if (tmp1 & 0x80)
|
||||
devc->chip_name = "CS4248";
|
||||
|
||||
if ((tmp1 & 0xc0) == (0x80 | 0x40))
|
||||
{
|
||||
/*
|
||||
* CS4231 detected - is it?
|
||||
*
|
||||
* Verify that setting I0 doesn't change I16.
|
||||
*/
|
||||
ad_write (devc, 16, 0); /* Set I16 to known value */
|
||||
|
||||
ad_write (devc, 0, 0x45);
|
||||
if ((tmp1 = ad_read (devc, 16)) != 0x45) /* No change -> CS4231? */
|
||||
{
|
||||
|
||||
ad_write (devc, 0, 0xaa);
|
||||
if ((tmp1 = ad_read (devc, 16)) == 0xaa) /* Rotten bits? */
|
||||
{
|
||||
DDB (printk ("ad_detect_H(%x)\n", tmp1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's a CS4231 - So what!
|
||||
* (Mode2 will be supported later)
|
||||
*/
|
||||
devc->chip_name = "CS4231";
|
||||
devc->mode = 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture)
|
||||
{
|
||||
/*
|
||||
* NOTE! If irq < 0, there is another driver which has allocated the IRQ
|
||||
* so that this driver doesn't need to allocate/deallocate it.
|
||||
* The actually used IRQ is ABS(irq).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initial values for the indirect registers of CS4248/AD1848.
|
||||
*/
|
||||
static int init_values[] =
|
||||
{
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
|
||||
0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00
|
||||
};
|
||||
int i, my_dev;
|
||||
ad1848_info *devc = &dev_info[nr_ad1848_devs];
|
||||
|
||||
if (!ad1848_detect (io_base))
|
||||
return;
|
||||
|
||||
devc->irq = (irq > 0) ? irq : 0;
|
||||
devc->dma_capture = dma_playback;
|
||||
devc->dma_playback = dma_capture;
|
||||
devc->opened = 0;
|
||||
|
||||
if (nr_ad1848_devs != 0)
|
||||
{
|
||||
memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs],
|
||||
(char *) &ad1848_pcm_operations[0],
|
||||
sizeof (struct audio_operations));
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
ad_write (devc, i, init_values[i]);
|
||||
|
||||
OUTB (0, io_Status (devc)); /* Clear pending interrupts */
|
||||
|
||||
#ifndef SCO
|
||||
sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
|
||||
"%s (%s)", name, devc->chip_name);
|
||||
#endif
|
||||
|
||||
if (irq > 0)
|
||||
printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
|
||||
|
||||
if (num_audiodevs < MAX_AUDIO_DEV)
|
||||
{
|
||||
audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs];
|
||||
if (irq > 0)
|
||||
irq2dev[irq] = my_dev;
|
||||
else if (irq < 0)
|
||||
irq2dev[-irq] = my_dev;
|
||||
|
||||
audio_devs[my_dev]->dmachan = dma_playback;
|
||||
audio_devs[my_dev]->buffcount = 1;
|
||||
audio_devs[my_dev]->buffsize = DSP_BUFFSIZE * 2;
|
||||
audio_devs[my_dev]->devc = devc;
|
||||
audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
|
||||
nr_ad1848_devs++;
|
||||
}
|
||||
else
|
||||
printk ("AD1848: Too many PCM devices available\n");
|
||||
}
|
||||
|
||||
void
|
||||
ad1848_interrupt (int irq)
|
||||
{
|
||||
unsigned char status;
|
||||
ad1848_info *devc;
|
||||
int dev;
|
||||
|
||||
if (irq < 0 || irq > 15)
|
||||
return; /* Bogus irq */
|
||||
dev = irq2dev[irq];
|
||||
if (dev < 0 || dev >= num_audiodevs)
|
||||
return; /* Bogus dev */
|
||||
|
||||
devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
status = INB (io_Status (devc));
|
||||
|
||||
if (status & 0x01)
|
||||
{
|
||||
if (devc->opened && devc->irq_mode == IMODE_OUTPUT)
|
||||
{
|
||||
DMAbuf_outputintr (dev, 1);
|
||||
}
|
||||
|
||||
if (devc->opened && devc->irq_mode == IMODE_INPUT)
|
||||
DMAbuf_inputintr (dev);
|
||||
}
|
||||
|
||||
OUTB (0, io_Status (devc)); /* Clear interrupt status */
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Some extra code for the MS Sound System
|
||||
*/
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS)
|
||||
|
||||
int
|
||||
probe_ms_sound (struct address_info *hw_config)
|
||||
{
|
||||
if ((INB (hw_config->io_base + 3) & 0x04) == 0)
|
||||
return 0; /* WSS ID test failed */
|
||||
|
||||
if (hw_config->irq > 11)
|
||||
return 0;
|
||||
|
||||
if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
|
||||
return 0;
|
||||
|
||||
return ad1848_detect (hw_config->io_base + 4);
|
||||
}
|
||||
|
||||
long
|
||||
attach_ms_sound (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
static unsigned char interrupt_bits[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 (!ad1848_detect (hw_config->io_base + 4))
|
||||
return mem_start;
|
||||
|
||||
/*
|
||||
* Set the IRQ and DMA addresses.
|
||||
*/
|
||||
|
||||
bits = interrupt_bits[hw_config->irq];
|
||||
if (bits == -1)
|
||||
return mem_start;
|
||||
|
||||
OUTB (bits | 0x40, config_port); /* Verify IRQ (I guess) */
|
||||
if ((INB (version_port) & 0x40) == 0)
|
||||
printk ("[IRQ?]");
|
||||
|
||||
OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */
|
||||
|
||||
ad1848_init ("MS Sound System", hw_config->io_base + 4,
|
||||
hw_config->irq,
|
||||
hw_config->dma,
|
||||
hw_config->dma);
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
51
sys/i386/isa/sound/adlib_card.c
Normal file
51
sys/i386/isa/sound/adlib_card.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* sound/adlib_card.c
|
||||
*
|
||||
* Detection routine for the AdLib card.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* 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_YM3812)
|
||||
|
||||
long
|
||||
attach_adlib_card (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
|
||||
if (opl3_detect (FM_MONO))
|
||||
{
|
||||
mem_start = opl3_init (mem_start);
|
||||
}
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
probe_adlib (struct address_info *hw_config)
|
||||
{
|
||||
return opl3_detect (FM_MONO);
|
||||
}
|
||||
|
||||
#endif
|
424
sys/i386/isa/sound/audio.c
Normal file
424
sys/i386/isa/sound/audio.c
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* sound/audio.c
|
||||
*
|
||||
* Device file manager for /dev/audio
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
|
||||
#include "ulaw.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.
|
||||
*/
|
||||
static int wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
|
||||
|
||||
static int audio_mode[MAX_AUDIO_DEV];
|
||||
|
||||
#define AM_NONE 0
|
||||
#define AM_WRITE 1
|
||||
#define AM_READ 2
|
||||
|
||||
static char *wr_dma_buf[MAX_AUDIO_DEV];
|
||||
static int audio_format[MAX_AUDIO_DEV];
|
||||
static int local_conversion[MAX_AUDIO_DEV];
|
||||
|
||||
static int
|
||||
set_format (int dev, int fmt)
|
||||
{
|
||||
if (fmt != AFMT_QUERY)
|
||||
{
|
||||
|
||||
local_conversion[dev] = 0;
|
||||
|
||||
if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */
|
||||
if (fmt == AFMT_MU_LAW)
|
||||
{
|
||||
fmt = AFMT_U8;
|
||||
local_conversion[dev] = AFMT_MU_LAW;
|
||||
}
|
||||
else
|
||||
fmt = AFMT_U8; /* This is always supported */
|
||||
|
||||
audio_format[dev] = DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, fmt, 1);
|
||||
}
|
||||
|
||||
if (local_conversion[dev]) /* This shadows the HW format */
|
||||
return local_conversion[dev];
|
||||
|
||||
return audio_format[dev];
|
||||
}
|
||||
|
||||
int
|
||||
audio_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
int ret;
|
||||
int bits;
|
||||
int dev_type = dev & 0x0f;
|
||||
int mode = file->mode & O_ACCMODE;
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
if (dev_type == SND_DEV_DSP16)
|
||||
bits = 16;
|
||||
else
|
||||
bits = 8;
|
||||
|
||||
if ((ret = DMAbuf_open (dev, mode)) < 0)
|
||||
return ret;
|
||||
|
||||
local_conversion[dev] = 0;
|
||||
|
||||
if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
|
||||
{
|
||||
audio_release (dev, file);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
if (dev_type == SND_DEV_AUDIO)
|
||||
{
|
||||
set_format (dev, AFMT_MU_LAW);
|
||||
}
|
||||
else
|
||||
set_format (dev, bits);
|
||||
|
||||
wr_buff_no[dev] = -1;
|
||||
audio_mode[dev] = AM_NONE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
audio_release (int dev, struct fileinfo *file)
|
||||
{
|
||||
int mode;
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
|
||||
if (wr_buff_no[dev] >= 0)
|
||||
{
|
||||
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
|
||||
|
||||
wr_buff_no[dev] = -1;
|
||||
}
|
||||
|
||||
DMAbuf_release (dev, mode);
|
||||
}
|
||||
|
||||
#ifdef NO_INLINE_ASM
|
||||
static void
|
||||
translate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
buff[i] = table[buff[i]];
|
||||
}
|
||||
|
||||
#else
|
||||
extern inline void
|
||||
translate_bytes (const void *table, void *buff, unsigned long n)
|
||||
{
|
||||
__asm__ ("cld\n"
|
||||
"1:\tlodsb\n\t"
|
||||
"xlatb\n\t"
|
||||
"stosb\n\t"
|
||||
"loop 1b\n\t":
|
||||
:"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
|
||||
:"bx", "cx", "di", "si", "ax");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
int c, p, l;
|
||||
int err;
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
p = 0;
|
||||
c = count;
|
||||
|
||||
if (audio_mode[dev] == AM_READ) /*
|
||||
* Direction changed
|
||||
*/
|
||||
{
|
||||
wr_buff_no[dev] = -1;
|
||||
}
|
||||
|
||||
audio_mode[dev] = AM_WRITE;
|
||||
|
||||
if (!count) /*
|
||||
* Flush output
|
||||
*/
|
||||
{
|
||||
if (wr_buff_no[dev] >= 0)
|
||||
{
|
||||
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
|
||||
|
||||
wr_buff_no[dev] = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (c)
|
||||
{ /*
|
||||
* Perform output blocking
|
||||
*/
|
||||
if (wr_buff_no[dev] < 0) /*
|
||||
* There is no incomplete buffers
|
||||
*/
|
||||
{
|
||||
if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
|
||||
{
|
||||
return wr_buff_no[dev];
|
||||
}
|
||||
wr_buff_ptr[dev] = 0;
|
||||
}
|
||||
|
||||
l = c;
|
||||
if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
|
||||
l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
|
||||
|
||||
if (!audio_devs[dev]->copy_from_user)
|
||||
{ /*
|
||||
* No device specific copy routine
|
||||
*/
|
||||
COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
|
||||
}
|
||||
else
|
||||
audio_devs[dev]->copy_from_user (dev,
|
||||
wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
|
||||
|
||||
|
||||
/*
|
||||
* Insert local processing here
|
||||
*/
|
||||
|
||||
if (local_conversion[dev] == AFMT_MU_LAW)
|
||||
{
|
||||
#ifdef linux
|
||||
/*
|
||||
* This just allows interrupts while the conversion is running
|
||||
*/
|
||||
__asm__ ("sti");
|
||||
#endif
|
||||
translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
|
||||
}
|
||||
|
||||
c -= l;
|
||||
p += l;
|
||||
wr_buff_ptr[dev] += l;
|
||||
|
||||
if (wr_buff_ptr[dev] >= wr_buff_size[dev])
|
||||
{
|
||||
if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
wr_buff_no[dev] = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
int c, p, l;
|
||||
char *dmabuf;
|
||||
int buff_no;
|
||||
|
||||
dev = dev >> 4;
|
||||
p = 0;
|
||||
c = count;
|
||||
|
||||
if (audio_mode[dev] == AM_WRITE)
|
||||
{
|
||||
if (wr_buff_no[dev] >= 0)
|
||||
{
|
||||
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
|
||||
|
||||
wr_buff_no[dev] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
audio_mode[dev] = AM_READ;
|
||||
|
||||
while (c)
|
||||
{
|
||||
if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
|
||||
return buff_no;
|
||||
|
||||
if (l > c)
|
||||
l = c;
|
||||
|
||||
/*
|
||||
* Insert any local processing here.
|
||||
*/
|
||||
|
||||
if (local_conversion[dev] == AFMT_MU_LAW)
|
||||
{
|
||||
#ifdef linux
|
||||
/*
|
||||
* This just allows interrupts while the conversion is running
|
||||
*/
|
||||
__asm__ ("sti");
|
||||
#endif
|
||||
|
||||
translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
|
||||
}
|
||||
|
||||
COPY_TO_USER (buf, p, dmabuf, l);
|
||||
|
||||
DMAbuf_rmchars (dev, buff_no, l);
|
||||
|
||||
p += l;
|
||||
c -= l;
|
||||
}
|
||||
|
||||
return count - c;
|
||||
}
|
||||
|
||||
int
|
||||
audio_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SNDCTL_DSP_SYNC:
|
||||
if (wr_buff_no[dev] >= 0)
|
||||
{
|
||||
DMAbuf_start_output (dev, wr_buff_no[dev], wr_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)));
|
||||
|
||||
default:
|
||||
return DMAbuf_ioctl (dev, cmd, arg, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
long
|
||||
audio_init (long mem_start)
|
||||
{
|
||||
/*
|
||||
* NOTE! This routine could be called several times during boot.
|
||||
*/
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#else
|
||||
/*
|
||||
* Stub versions
|
||||
*/
|
||||
|
||||
int
|
||||
audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
int
|
||||
audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
int
|
||||
audio_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
void
|
||||
audio_release (int dev, struct fileinfo *file)
|
||||
{
|
||||
};
|
||||
int
|
||||
audio_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
int
|
||||
audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
long
|
||||
audio_init (long mem_start)
|
||||
{
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
830
sys/i386/isa/sound/configure.c
Normal file
830
sys/i386/isa/sound/configure.c
Normal file
@ -0,0 +1,830 @@
|
||||
/*
|
||||
* sound/configure.c - Configuration program for the Linux Sound Driver
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* 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 <stdio.h>
|
||||
|
||||
#define B(x) (1 << (x))
|
||||
|
||||
/*
|
||||
* Option numbers
|
||||
*/
|
||||
|
||||
#define OPT_PAS 0
|
||||
#define OPT_SB 1
|
||||
#define OPT_ADLIB 2
|
||||
#define OPT_LAST_MUTUAL 2
|
||||
|
||||
#define OPT_GUS 3
|
||||
#define OPT_MPU401 4
|
||||
#define OPT_UART6850 5
|
||||
#define OPT_PSS 6
|
||||
#define OPT_GUS16 7
|
||||
#define OPT_GUSMAX 8
|
||||
#define OPT_MSS 9
|
||||
|
||||
#define OPT_HIGHLEVEL 10 /* This must be same than the next one */
|
||||
#define OPT_SBPRO 10
|
||||
#define OPT_SB16 11
|
||||
#define OPT_AUDIO 12
|
||||
#define OPT_MIDI_AUTO 13
|
||||
#define OPT_MIDI 14
|
||||
#define OPT_YM3812_AUTO 15
|
||||
#define OPT_YM3812 16
|
||||
#define OPT_SEQUENCER 17
|
||||
#define OPT_LAST 17 /* Must be the same than the defined OPT */
|
||||
|
||||
#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \
|
||||
B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)|B(OPT_MSS))
|
||||
/*
|
||||
* Options that have been disabled for some reason (incompletely implemented
|
||||
* and/or tested). Don't remove from this list before looking at file
|
||||
* experimental.txt for further info.
|
||||
*/
|
||||
#define DISABLED_OPTIONS (B(OPT_PSS))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long conditions;
|
||||
unsigned long exclusive_options;
|
||||
char macro[20];
|
||||
int verify;
|
||||
int alias;
|
||||
int default_answ;
|
||||
}
|
||||
|
||||
hw_entry;
|
||||
|
||||
|
||||
/*
|
||||
* The rule table for the driver options. The first field defines a set of
|
||||
* options which must be selected before this entry can be selected. The
|
||||
* second field is a set of options which are not allowed with this one. If
|
||||
* the fourth field is zero, the option is selected without asking
|
||||
* confirmation from the user.
|
||||
*
|
||||
* With this version of the rule table it is possible to select just one type of
|
||||
* hardware.
|
||||
*
|
||||
* NOTE! Keep the following table and the questions array in sync with the
|
||||
* option numbering!
|
||||
*/
|
||||
|
||||
hw_entry hw_table[] =
|
||||
{
|
||||
/*
|
||||
* 0
|
||||
*/
|
||||
{0, 0, "PAS", 1, 0, 0},
|
||||
{0, 0, "SB", 1, 0, 0},
|
||||
{0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0, 0},
|
||||
|
||||
{0, 0, "GUS", 1, 0, 0},
|
||||
{0, 0, "MPU401", 1, 0, 0},
|
||||
{0, 0, "UART6850", 1, 0, 0},
|
||||
{0, 0, "PSS", 1, 0, 0},
|
||||
{B (OPT_GUS), 0, "GUS16", 1, 0, 0},
|
||||
{B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0},
|
||||
{0, 0, "MSS", 1, 0, 0},
|
||||
|
||||
{B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1},
|
||||
{B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1},
|
||||
{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1},
|
||||
{B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
|
||||
{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1},
|
||||
{B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
|
||||
{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
|
||||
{B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}
|
||||
};
|
||||
|
||||
char *questions[] =
|
||||
{
|
||||
"ProAudioSpectrum 16 support",
|
||||
"SoundBlaster support",
|
||||
"AdLib support",
|
||||
"Gravis Ultrasound support",
|
||||
"MPU-401 support (NOT for SB16)",
|
||||
"6850 UART Midi support",
|
||||
"PSS (ECHO-ADI2111) support",
|
||||
"16 bit sampling option of GUS (_NOT_ GUS MAX)",
|
||||
"GUS MAX support",
|
||||
"Microsoft Sound System support",
|
||||
|
||||
"SoundBlaster Pro support",
|
||||
"SoundBlaster 16 support",
|
||||
"digitized voice support",
|
||||
"This should not be asked",
|
||||
"MIDI interface support",
|
||||
"This should not be asked",
|
||||
"FM synthesizer (YM3812/OPL-3) support",
|
||||
"/dev/sequencer support",
|
||||
"Should I die"
|
||||
};
|
||||
|
||||
unsigned long selected_options = 0;
|
||||
int sb_dma = 0;
|
||||
|
||||
int
|
||||
can_select_option (int nr)
|
||||
{
|
||||
switch (nr)
|
||||
{
|
||||
case 0:
|
||||
fprintf (stderr, "The SoundBlaster, AdLib and ProAudioSpectrum\n"
|
||||
"CARDS cannot be installed at the same time.\n\n"
|
||||
"However the PAS16 has a SB emulator so you could select"
|
||||
"the SoundBlaster DRIVER with it.\n");
|
||||
fprintf (stderr, " - ProAudioSpectrum 16\n");
|
||||
fprintf (stderr, " - SoundBlaster / SB Pro\n");
|
||||
fprintf (stderr, " (Could be selected with a PAS16 also)\n");
|
||||
fprintf (stderr, " - AdLib\n");
|
||||
fprintf (stderr, "\nDon't enable SoundBlaster if you have GUS at 0x220!\n\n");
|
||||
break;
|
||||
|
||||
case OPT_LAST_MUTUAL + 1:
|
||||
fprintf (stderr, "\nThe following cards should work with any other cards.\n"
|
||||
"CAUTION! Don't enable MPU-401 if you don't have it.\n");
|
||||
break;
|
||||
|
||||
case OPT_HIGHLEVEL:
|
||||
fprintf (stderr, "\nSelect one or more of the following options\n");
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (hw_table[nr].conditions)
|
||||
if (!(hw_table[nr].conditions & selected_options))
|
||||
return 0;
|
||||
|
||||
if (hw_table[nr].exclusive_options)
|
||||
if (hw_table[nr].exclusive_options & selected_options)
|
||||
return 0;
|
||||
|
||||
if (DISABLED_OPTIONS & B (nr))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
think_positively (int def_answ)
|
||||
{
|
||||
char answ[512];
|
||||
int len;
|
||||
|
||||
if ((len = read (0, &answ, sizeof (answ))) < 1)
|
||||
{
|
||||
fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
|
||||
|
||||
perror ("stdin");
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
if (len < 2) /*
|
||||
* There is an additional LF at the end
|
||||
*/
|
||||
return def_answ;
|
||||
|
||||
answ[len - 1] = 0;
|
||||
|
||||
if (!strcmp (answ, "y") || !strcmp (answ, "Y"))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ask_value (char *format, int default_answer)
|
||||
{
|
||||
char answ[512];
|
||||
int len, num;
|
||||
|
||||
play_it_again_Sam:
|
||||
|
||||
if ((len = read (0, &answ, sizeof (answ))) < 1)
|
||||
{
|
||||
fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
|
||||
|
||||
perror ("stdin");
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
if (len < 2) /*
|
||||
* There is an additional LF at the end
|
||||
*/
|
||||
return default_answer;
|
||||
|
||||
answ[len - 1] = 0;
|
||||
|
||||
if (sscanf (answ, format, &num) != 1)
|
||||
{
|
||||
fprintf (stderr, "Illegal format. Try again: ");
|
||||
goto play_it_again_Sam;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int i, num, def_size, full_driver = 1;
|
||||
char answ[10];
|
||||
|
||||
printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n\n");
|
||||
|
||||
fprintf (stderr, "\nConfiguring the sound support\n\n");
|
||||
|
||||
fprintf (stderr, "Do you want to include full version of the sound driver (n/y) ? ");
|
||||
|
||||
if (think_positively (0))
|
||||
{
|
||||
/*
|
||||
* Select all but some most dangerous cards. These cards are difficult to
|
||||
* detect reliably or conflict with some other cards (SCSI, Mitsumi)
|
||||
*/
|
||||
selected_options = 0xffffffff &
|
||||
~(B (OPT_MPU401) | B (OPT_UART6850) | B (OPT_PSS)) &
|
||||
~DISABLED_OPTIONS;
|
||||
|
||||
fprintf (stderr, "Note! MPU-401, PSS and 6850 UART drivers not enabled\n");
|
||||
full_driver = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Do you want to DISABLE the Sound Driver (n/y) ?");
|
||||
if (think_positively (0))
|
||||
{
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
exit (0);
|
||||
}
|
||||
/*
|
||||
* Partial driver
|
||||
*/
|
||||
|
||||
full_driver = 0;
|
||||
|
||||
for (i = 0; i <= OPT_LAST; i++)
|
||||
if (can_select_option (i))
|
||||
{
|
||||
if (!(selected_options & B (i))) /*
|
||||
* Not selected yet
|
||||
*/
|
||||
if (!hw_table[i].verify)
|
||||
{
|
||||
if (hw_table[i].alias)
|
||||
selected_options |= B (hw_table[i].alias);
|
||||
else
|
||||
selected_options |= B (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
int def_answ = hw_table[i].default_answ;
|
||||
|
||||
fprintf (stderr,
|
||||
def_answ ? " %s (y/n) ? " : " %s (n/y) ? ",
|
||||
questions[i]);
|
||||
if (think_positively (def_answ))
|
||||
if (hw_table[i].alias)
|
||||
selected_options |= B (hw_table[i].alias);
|
||||
else
|
||||
selected_options |= B (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_SBPRO))
|
||||
{
|
||||
fprintf(stderr, "Do you want support for the mixer of SG NX Pro ? ");
|
||||
if (think_positively (0))
|
||||
printf("#define __SGNXPRO__\n");
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_SB16))
|
||||
selected_options |= B (OPT_SBPRO);
|
||||
|
||||
if (selected_options & B (OPT_PSS))
|
||||
{
|
||||
genld_again:
|
||||
fprintf
|
||||
(stderr,
|
||||
"if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n"
|
||||
"then you must include the LD in the kernel.\n"
|
||||
"(do you wish to include a LD) ? ");
|
||||
if (think_positively (0))
|
||||
{
|
||||
char path[512];
|
||||
|
||||
fprintf (stderr,
|
||||
"Enter the path to your LD file (pwd is sound): ");
|
||||
scanf ("%s", path);
|
||||
fprintf (stderr, "including LD file %s\n", path);
|
||||
selected_options |= B (OPT_SB) | B (OPT_MPU401) | B (OPT_ADLIB);
|
||||
|
||||
/* Gen LD header */
|
||||
{
|
||||
int fd;
|
||||
int count;
|
||||
char c;
|
||||
int i = 0;
|
||||
|
||||
if ((fd = open (path, 0)) > 0)
|
||||
{
|
||||
FILE *sf = fopen ("synth-ld.h", "w");
|
||||
|
||||
fprintf (sf, "/* automaticaly generated by configure */\n");
|
||||
fprintf (sf, "unsigned char pss_synth[] = {\n");
|
||||
while (1)
|
||||
{
|
||||
count = read (fd, &c, 1);
|
||||
if (count == 0)
|
||||
break;
|
||||
if (i != 0 && (i % 10) == 0)
|
||||
fprintf (sf, "\n");
|
||||
fprintf (sf, "0x%02x,", c & 0xFFL);
|
||||
i++;
|
||||
}
|
||||
fprintf (sf, "};\n"
|
||||
"#define pss_synthLen %d\n", i);
|
||||
fclose (sf);
|
||||
close (fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "couldn't open %s as the ld file\n",
|
||||
path);
|
||||
fprintf (stderr, "try again with correct path? ");
|
||||
if (think_positively (1))
|
||||
goto genld_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *sf = fopen ("synth-ld.h", "w");
|
||||
|
||||
fprintf (sf, "/* automaticaly generated by configure */\n");
|
||||
fprintf (sf, "unsigned char pss_synth[1];\n"
|
||||
"#define pss_synthLen 0\n");
|
||||
fclose (sf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(selected_options & ANY_DEVS))
|
||||
{
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n\n");
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
printf ("#define KERNEL_SOUNDCARD\n");
|
||||
|
||||
for (i = 0; i <= OPT_LAST; i++)
|
||||
if (!hw_table[i].alias)
|
||||
if (selected_options & B (i))
|
||||
printf ("#undef EXCLUDE_%s\n", hw_table[i].macro);
|
||||
else
|
||||
printf ("#define EXCLUDE_%s\n", hw_table[i].macro);
|
||||
|
||||
|
||||
/*
|
||||
* IRQ and DMA settings
|
||||
*/
|
||||
printf ("\n");
|
||||
|
||||
#if defined(linux)
|
||||
if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for SB?\n"
|
||||
"The factory default is 220\n"
|
||||
"Enter the SB I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x220);
|
||||
fprintf (stderr, "SB I/O base set to %03x\n", num);
|
||||
printf ("#define SBC_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for SoundBlaster?\n"
|
||||
"The IRQ address is defined by the jumpers on your card.\n"
|
||||
"The factory default is either 5 or 7 (depending on the model).\n"
|
||||
"Valid values are 9(=2), 5, 7 and 10.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 7);
|
||||
if (num != 9 && num != 5 && num != 7 && num != 10)
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 7;
|
||||
}
|
||||
fprintf (stderr, "SoundBlaster IRQ set to %d\n", num);
|
||||
|
||||
printf ("#define SBC_IRQ %d\n", num);
|
||||
|
||||
if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_PSS)))
|
||||
{
|
||||
fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
|
||||
"For SB 1.0, 1.5 and 2.0 this MUST be 1\n"
|
||||
"SB Pro supports DMA channels 0, 1 and 3 (jumper)\n"
|
||||
"For SB16 give the 8 bit DMA# here\n"
|
||||
"The default value is 1\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 1);
|
||||
if (num < 0 || num > 3)
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 1;
|
||||
}
|
||||
fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
|
||||
printf ("#define SBC_DMA %d\n", num);
|
||||
sb_dma = num;
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_SB16))
|
||||
{
|
||||
|
||||
fprintf (stderr, "\n16 bit DMA channel for SoundBlaster 16?\n"
|
||||
"Possible values are 5, 6 or 7\n"
|
||||
"The default value is 6\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 6);
|
||||
if ((num < 5 || num > 7) && (num != sb_dma))
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 6;
|
||||
}
|
||||
fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
|
||||
printf ("#define SB16_DMA %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nI/O base for SB16 Midi?\n"
|
||||
"Possible values are 300 and 330\n"
|
||||
"The factory default is 330\n"
|
||||
"Enter the SB16 Midi I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x330);
|
||||
fprintf (stderr, "SB16 Midi I/O base set to %03x\n", num);
|
||||
printf ("#define SB16MIDI_BASE 0x%03x\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_PAS))
|
||||
{
|
||||
if (selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
|
||||
{
|
||||
fprintf (stderr, "\nIRQ number for ProAudioSpectrum?\n"
|
||||
"The recommended value is the IRQ used under DOS.\n"
|
||||
"Please refer to the ProAudioSpectrum User's Guide.\n"
|
||||
"The default value is 10.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 10);
|
||||
if (num == 6 || num < 3 || num > 15 || num == 2) /*
|
||||
* Illegal
|
||||
*/
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 10;
|
||||
}
|
||||
fprintf (stderr, "ProAudioSpectrum IRQ set to %d\n", num);
|
||||
printf ("#define PAS_IRQ %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_AUDIO))
|
||||
{
|
||||
fprintf (stderr, "\nDMA number for ProAudioSpectrum?\n"
|
||||
"The recommended value is the DMA channel under DOS.\n"
|
||||
"Please refer to the ProAudioSpectrum User's Guide.\n"
|
||||
"The default value is 3\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 3);
|
||||
if (num == 4 || num < 0 || num > 7)
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 3;
|
||||
}
|
||||
fprintf (stderr, "\nProAudioSpectrum DMA set to %d\n", num);
|
||||
printf ("#define PAS_DMA %d\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_GUS))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for Gravis Ultrasound?\n"
|
||||
"Valid choices are 210, 220, 230, 240, 250 or 260\n"
|
||||
"The factory default is 220\n"
|
||||
"Enter the GUS I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x220);
|
||||
if ((num > 0x260) || ((num & 0xf0f) != 0x200) || ((num & 0x0f0) > 0x060))
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 0x220;
|
||||
}
|
||||
|
||||
if ((selected_options & B (OPT_SB)) && (num == 0x220))
|
||||
{
|
||||
fprintf (stderr, "FATAL ERROR!!!!!!!!!!!!!!\n"
|
||||
"\t0x220 cannot be used if SoundBlaster is enabled.\n"
|
||||
"\tRun the config again.\n");
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
exit (-1);
|
||||
}
|
||||
fprintf (stderr, "GUS I/O base set to %03x\n", num);
|
||||
printf ("#define GUS_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for Gravis UltraSound?\n"
|
||||
"The recommended value is the IRQ used under DOS.\n"
|
||||
"Please refer to the Gravis Ultrasound User's Guide.\n"
|
||||
"The default value is 15.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 15);
|
||||
if (num == 6 || num < 3 || num > 15 || num == 2) /*
|
||||
* Invalid
|
||||
*/
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 15;
|
||||
}
|
||||
fprintf (stderr, "Gravis UltraSound IRQ set to %d\n", num);
|
||||
printf ("#define GUS_IRQ %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nDMA number for Gravis UltraSound?\n"
|
||||
"The recommended value is the DMA channel under DOS.\n"
|
||||
"Please refer to the Gravis Ultrasound User's Guide.\n"
|
||||
"The default value is 6\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 6);
|
||||
if (num == 4 || num < 0 || num > 7)
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 6;
|
||||
}
|
||||
fprintf (stderr, "\nGravis UltraSound DMA set to %d\n", num);
|
||||
printf ("#define GUS_DMA %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_MPU401))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for MPU-401?\n"
|
||||
"The factory default is 330\n"
|
||||
"Enter the MPU-401 I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x330);
|
||||
fprintf (stderr, "MPU-401 I/O base set to %03x\n", num);
|
||||
printf ("#define MPU_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for MPU-401?\n"
|
||||
"Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
|
||||
"The default value is 9.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 9);
|
||||
if (num == 6 || num < 3 || num > 15) /*
|
||||
* Used for floppy
|
||||
*/
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 5;
|
||||
}
|
||||
fprintf (stderr, "MPU-401 IRQ set to %d\n", num);
|
||||
printf ("#define MPU_IRQ %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_UART6850))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for 6850 UART Midi?\n"
|
||||
"Be carefull. No defaults.\n"
|
||||
"Enter the 6850 UART I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0);
|
||||
if (num == 0)
|
||||
{
|
||||
/*
|
||||
* Invalid value entered
|
||||
*/
|
||||
printf ("#define EXCLUDE_UART6850\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "6850 UART I/O base set to %03x\n", num);
|
||||
printf ("#define U6850_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for 6850 UART?\n"
|
||||
"Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
|
||||
"The default value is 5.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 5);
|
||||
if (num == 6 || num < 3 || num > 15) /*
|
||||
* Used for floppy
|
||||
*/
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 5;
|
||||
}
|
||||
fprintf (stderr, "6850 UART IRQ set to %d\n", num);
|
||||
printf ("#define U6850_IRQ %d\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_PSS))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for PSS?\n"
|
||||
"The factory default is 220\n"
|
||||
"Enter the PSS I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x220);
|
||||
fprintf (stderr, "PSS I/O base set to %03x\n", num);
|
||||
printf ("#define PSS_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for PSS?\n"
|
||||
"Valid numbers are: 3, 4, 5, 7, 9(=2) or 10.\n"
|
||||
"The default value is 10.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 10);
|
||||
if (num == 6 || num < 3 || num > 15) /* Used for floppy */
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 7;
|
||||
}
|
||||
fprintf (stderr, "PSS IRQ set to %d\n", num);
|
||||
printf ("#define PSS_IRQ %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nDMA number for ECHO-PSS?\n"
|
||||
"The default value is 3\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 3);
|
||||
if (num == 4 || num < 0 || num > 7)
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 3;
|
||||
}
|
||||
fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num);
|
||||
printf ("#define PSS_DMA %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_MSS))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for MSS (MS Sound System)?\n"
|
||||
"The factory default is 530\n"
|
||||
"Other possible values are 604, E80 or F40\n"
|
||||
"Enter the MSS I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x530);
|
||||
fprintf (stderr, "MSS I/O base set to %03x\n", num);
|
||||
printf ("#define MSS_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for MSS?\n"
|
||||
"Valid numbers are: 7, 9(=2), 10 and 11.\n"
|
||||
"The default value is 10.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 10);
|
||||
if (num == 6 || num < 3 || num > 15) /* Used for floppy */
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 7;
|
||||
}
|
||||
fprintf (stderr, "MSS IRQ set to %d\n", num);
|
||||
printf ("#define MSS_IRQ %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nDMA number for MSS?\n"
|
||||
"Valid values are 1 and 3 (sometimes 0)"
|
||||
"The default value is 3\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 3);
|
||||
if (num == 4 || num < 0 || num > 7)
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 3;
|
||||
}
|
||||
fprintf (stderr, "\nMSS DMA set to %d\n", num);
|
||||
printf ("#define MSS_DMA %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_GUS16))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n"
|
||||
"The factory default is 530\n"
|
||||
"Other possible values are 604, E80 or F40\n"
|
||||
"Enter the GUS16 I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x530);
|
||||
fprintf (stderr, "GUS16 I/O base set to %03x\n", num);
|
||||
printf ("#define GUS16_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for GUS16?\n"
|
||||
"Valid numbers are: 3, 4, 5, 7, or 9(=2).\n"
|
||||
"The default value is 7.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 7);
|
||||
if (num == 6 || num < 3 || num > 15) /* Used for floppy */
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 7;
|
||||
}
|
||||
fprintf (stderr, "GUS16 IRQ set to %d\n", num);
|
||||
printf ("#define GUS16_IRQ %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nDMA number for GUS16?\n"
|
||||
"The default value is 3\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 3);
|
||||
if (num < 0 || num > 3)
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 3;
|
||||
}
|
||||
fprintf (stderr, "\nGUS16 DMA set to %d\n", num);
|
||||
printf ("#define GUS16_DMA %d\n", num);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (selected_options & B (OPT_AUDIO))
|
||||
{
|
||||
def_size = 16384;
|
||||
|
||||
if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_SB16)))
|
||||
def_size = 32768;
|
||||
|
||||
#ifndef __386BSD__
|
||||
if ((selected_options & (B (OPT_PAS) | B (OPT_PAS) | B (OPT_GUS16) | B (OPT_GUSMAX) |
|
||||
B (OPT_MSS) | B (OPT_PSS))) &&
|
||||
!full_driver)
|
||||
def_size = 65536; /*
|
||||
* PAS16 or SB16
|
||||
*/
|
||||
#endif
|
||||
|
||||
fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n"
|
||||
"%d is recommended value for this configuration.\n"
|
||||
"Enter the value: ", def_size);
|
||||
|
||||
num = ask_value ("%d", def_size);
|
||||
if (num != 4096 && num != 16384 && num != 32768 && num != 65536)
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = def_size;
|
||||
}
|
||||
fprintf (stderr, "The DMA buffer size set to %d\n", num);
|
||||
printf ("#define DSP_BUFFSIZE %d\n", num);
|
||||
}
|
||||
|
||||
printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
|
||||
fprintf (stderr, "The sound driver is now configured.\n");
|
||||
|
||||
#if defined(SCO) || defined(ISC) || defined(SYSV)
|
||||
fprintf (stderr, "Remember to update the System file\n");
|
||||
#endif
|
||||
|
||||
exit (0);
|
||||
}
|
269
sys/i386/isa/sound/dev_table.c
Normal file
269
sys/i386/isa/sound/dev_table.c
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* sound/dev_table.c
|
||||
*
|
||||
* Device call tables.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _DEV_TABLE_C_
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
int
|
||||
snd_find_driver (int type)
|
||||
{
|
||||
int i, n = sizeof (sound_drivers) / sizeof (struct driver_info);
|
||||
|
||||
for (i = 0; i < (n - 1); i++)
|
||||
if (sound_drivers[i].card_type == type)
|
||||
return i;
|
||||
|
||||
return -1; /*
|
||||
* Not found
|
||||
*/
|
||||
}
|
||||
|
||||
long
|
||||
sndtable_init (long mem_start)
|
||||
{
|
||||
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
|
||||
int drv;
|
||||
|
||||
for (i = 0; i < (n - 1); i++)
|
||||
if (snd_installed_cards[i].enabled)
|
||||
if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
|
||||
snd_installed_cards[i].enabled = 0; /*
|
||||
* Mark as not detected
|
||||
*/
|
||||
else if (sound_drivers[drv].probe (&snd_installed_cards[i].config))
|
||||
{
|
||||
#ifndef SHORT_BANNERS
|
||||
printk ("snd%d",
|
||||
snd_installed_cards[i].card_type);
|
||||
#endif
|
||||
|
||||
mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config);
|
||||
#ifndef SHORT_BANNERS
|
||||
printk (" at 0x%x irq %d drq %d\n",
|
||||
snd_installed_cards[i].config.io_base,
|
||||
snd_installed_cards[i].config.irq,
|
||||
snd_installed_cards[i].config.dma);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
snd_installed_cards[i].enabled = 0; /*
|
||||
* Mark as not detected
|
||||
*/
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
sndtable_probe (int unit, struct address_info *hw_config)
|
||||
{
|
||||
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
|
||||
|
||||
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\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)
|
||||
{
|
||||
return num_audiodevs + num_mixers + num_synths + num_midis;
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
void
|
||||
sound_setup (char *str, int *ints)
|
||||
{
|
||||
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
|
||||
|
||||
/*
|
||||
* First disable all drivers
|
||||
*/
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
snd_installed_cards[i].enabled = 0;
|
||||
|
||||
if (ints[0] == 0 || ints[1] == 0)
|
||||
return;
|
||||
/*
|
||||
* Then enable them one by time
|
||||
*/
|
||||
|
||||
for (i = 1; i <= ints[0]; i++)
|
||||
{
|
||||
int card_type, ioaddr, irq, dma, ptr, j;
|
||||
unsigned int val;
|
||||
|
||||
val = (unsigned int) ints[i];
|
||||
|
||||
card_type = (val & 0x0ff00000) >> 20;
|
||||
|
||||
if (card_type > 127)
|
||||
{
|
||||
/*
|
||||
* Add any future extensions here
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
ioaddr = (val & 0x000fff00) >> 8;
|
||||
irq = (val & 0x000000f0) >> 4;
|
||||
dma = (val & 0x0000000f);
|
||||
|
||||
ptr = -1;
|
||||
for (j = 0; j < n && ptr == -1; j++)
|
||||
if (snd_installed_cards[j].card_type == card_type &&
|
||||
!snd_installed_cards[j].enabled) /*
|
||||
* Not already found
|
||||
*/
|
||||
ptr = j;
|
||||
|
||||
if (ptr == -1)
|
||||
printk ("Sound: Invalid setup parameter 0x%08x\n", val);
|
||||
else
|
||||
{
|
||||
snd_installed_cards[ptr].enabled = 1;
|
||||
snd_installed_cards[ptr].config.io_base = ioaddr;
|
||||
snd_installed_cards[ptr].config.irq = irq;
|
||||
snd_installed_cards[ptr].config.dma = dma;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
void
|
||||
sound_chconf (int card_type, int ioaddr, int irq, int dma)
|
||||
{
|
||||
int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
|
||||
|
||||
int ptr, j;
|
||||
|
||||
ptr = -1;
|
||||
for (j = 0; j < n && ptr == -1; j++)
|
||||
if (snd_installed_cards[j].card_type == card_type &&
|
||||
!snd_installed_cards[j].enabled) /*
|
||||
* Not already found
|
||||
*/
|
||||
ptr = j;
|
||||
|
||||
if (ptr != -1)
|
||||
{
|
||||
snd_installed_cards[ptr].enabled = 1;
|
||||
if (ioaddr)
|
||||
snd_installed_cards[ptr].config.io_base = ioaddr;
|
||||
if (irq)
|
||||
snd_installed_cards[ptr].config.irq = irq;
|
||||
if (dma)
|
||||
snd_installed_cards[ptr].config.dma = dma;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct address_info *
|
||||
sound_getconf (int card_type)
|
||||
{
|
||||
int j, ptr;
|
||||
int n = sizeof (snd_installed_cards) / sizeof (struct card_info);
|
||||
|
||||
ptr = -1;
|
||||
for (j = 0; j < n && ptr == -1; j++)
|
||||
if (snd_installed_cards[j].card_type == card_type)
|
||||
ptr = j;
|
||||
|
||||
if (ptr == -1)
|
||||
return (struct address_info *) NULL;
|
||||
|
||||
return &snd_installed_cards[ptr].config;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
sound_setup (char *str, int *ints)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
345
sys/i386/isa/sound/dev_table.h
Normal file
345
sys/i386/isa/sound/dev_table.h
Normal file
@ -0,0 +1,345 @@
|
||||
/*
|
||||
* dev_table.h
|
||||
*
|
||||
* Global definitions for device call tables
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _DEV_TABLE_H_
|
||||
#define _DEV_TABLE_H_
|
||||
|
||||
/*
|
||||
* NOTE! NOTE! NOTE! NOTE!
|
||||
*
|
||||
* If you modify this file, please check the dev_table.c also.
|
||||
*
|
||||
* NOTE! NOTE! NOTE! NOTE!
|
||||
*/
|
||||
|
||||
struct driver_info {
|
||||
int card_type; /* From soundcard.h */
|
||||
char *name;
|
||||
long (*attach) (long mem_start, struct address_info *hw_config);
|
||||
int (*probe) (struct address_info *hw_config);
|
||||
};
|
||||
|
||||
struct card_info {
|
||||
int card_type; /* Link (search key) to the driver list */
|
||||
struct address_info config;
|
||||
int enabled;
|
||||
};
|
||||
|
||||
/*
|
||||
* Device specific parameters (used only by dmabuf.c)
|
||||
*/
|
||||
#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR)
|
||||
|
||||
#define DMODE_NONE 0
|
||||
#define DMODE_OUTPUT 1
|
||||
#define DMODE_INPUT 2
|
||||
|
||||
struct dma_buffparms {
|
||||
int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
|
||||
|
||||
/*
|
||||
* Pointers to raw buffers
|
||||
*/
|
||||
|
||||
char *raw_buf[DSP_BUFFCOUNT];
|
||||
unsigned long raw_buf_phys[DSP_BUFFCOUNT];
|
||||
int raw_count;
|
||||
|
||||
/*
|
||||
* Device state tables
|
||||
*/
|
||||
|
||||
unsigned long flags;
|
||||
#define DMA_BUSY 0x00000001
|
||||
#define DMA_RESTART 0x00000002
|
||||
#define DMA_ACTIVE 0x00000004
|
||||
#define DMA_STARTED 0x00000008
|
||||
#define DMA_ALLOC_DONE 0x00000020
|
||||
|
||||
int open_mode;
|
||||
|
||||
/*
|
||||
* Queue parameters.
|
||||
*/
|
||||
int qlen;
|
||||
int qhead;
|
||||
int qtail;
|
||||
|
||||
int nbufs;
|
||||
int counts[MAX_SUB_BUFFERS];
|
||||
int subdivision;
|
||||
char *buf[MAX_SUB_BUFFERS];
|
||||
unsigned long buf_phys[MAX_SUB_BUFFERS];
|
||||
|
||||
int fragment_size;
|
||||
int max_fragments;
|
||||
|
||||
int bytes_in_use;
|
||||
|
||||
int underrun_count;
|
||||
};
|
||||
|
||||
struct audio_operations {
|
||||
char name[32];
|
||||
int flags;
|
||||
#define NOTHING_SPECIAL 0
|
||||
#define NEEDS_RESTART 1
|
||||
#define DMA_AUTOMODE 2
|
||||
int format_mask; /* Bitmask for supported audio formats */
|
||||
void *devc; /* Driver specific info */
|
||||
int (*open) (int dev, int mode);
|
||||
void (*close) (int dev);
|
||||
void (*output_block) (int dev, unsigned long buf,
|
||||
int count, int intrflag, int dma_restart);
|
||||
void (*start_input) (int dev, unsigned long buf,
|
||||
int count, int intrflag, int dma_restart);
|
||||
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local);
|
||||
int (*prepare_for_input) (int dev, int bufsize, int nbufs);
|
||||
int (*prepare_for_output) (int dev, int bufsize, int nbufs);
|
||||
void (*reset) (int dev);
|
||||
void (*halt_xfer) (int dev);
|
||||
int (*local_qlen)(int dev);
|
||||
void (*copy_from_user)(int dev, char *localbuf, int localoffs,
|
||||
snd_rw_buf *userbuf, int useroffs, int len);
|
||||
int buffcount;
|
||||
long buffsize;
|
||||
int dmachan;
|
||||
struct dma_buffparms *dmap;
|
||||
};
|
||||
|
||||
struct mixer_operations {
|
||||
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
|
||||
};
|
||||
|
||||
struct synth_operations {
|
||||
struct synth_info *info;
|
||||
int midi_dev;
|
||||
int synth_type;
|
||||
int synth_subtype;
|
||||
|
||||
int (*open) (int dev, int mode);
|
||||
void (*close) (int dev);
|
||||
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
|
||||
int (*kill_note) (int dev, int voice, int note, int velocity);
|
||||
int (*start_note) (int dev, int voice, int note, int velocity);
|
||||
int (*set_instr) (int dev, int voice, int instr);
|
||||
void (*reset) (int dev);
|
||||
void (*hw_control) (int dev, unsigned char *event);
|
||||
int (*load_patch) (int dev, int format, snd_rw_buf *addr,
|
||||
int offs, int count, int pmgr_flag);
|
||||
void (*aftertouch) (int dev, int voice, int pressure);
|
||||
void (*controller) (int dev, int voice, int ctrl_num, int value);
|
||||
void (*panning) (int dev, int voice, int value);
|
||||
void (*volume_method) (int dev, int mode);
|
||||
int (*pmgr_interface) (int dev, struct patmgr_info *info);
|
||||
void (*bender) (int dev, int chn, int value);
|
||||
int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc);
|
||||
|
||||
struct voice_alloc_info alloc;
|
||||
struct channel_info chn_info[16];
|
||||
};
|
||||
|
||||
struct midi_operations {
|
||||
struct midi_info info;
|
||||
struct synth_operations *converter;
|
||||
int (*open) (int dev, int mode,
|
||||
void (*inputintr)(int dev, unsigned char data),
|
||||
void (*outputintr)(int dev)
|
||||
);
|
||||
void (*close) (int dev);
|
||||
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
|
||||
int (*putc) (int dev, unsigned char data);
|
||||
int (*start_read) (int dev);
|
||||
int (*end_read) (int dev);
|
||||
void (*kick)(int dev);
|
||||
int (*command) (int dev, unsigned char *data);
|
||||
int (*buffer_status) (int dev);
|
||||
int (*prefix_cmd) (int dev, unsigned char status);
|
||||
};
|
||||
|
||||
struct sound_timer_operations {
|
||||
struct sound_timer_info info;
|
||||
int priority;
|
||||
int devlink;
|
||||
int (*open)(int dev, int mode);
|
||||
void (*close)(int dev);
|
||||
int (*event)(int dev, unsigned char *ev);
|
||||
unsigned long (*get_time)(int dev);
|
||||
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
|
||||
void (*arm_timer)(int dev, long time);
|
||||
};
|
||||
|
||||
#ifdef _DEV_TABLE_C_
|
||||
struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0;
|
||||
struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
|
||||
struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0;
|
||||
struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
|
||||
|
||||
#ifndef EXCLUDE_SEQUENCER
|
||||
extern struct sound_timer_operations default_sound_timer;
|
||||
struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] =
|
||||
{&default_sound_timer, NULL};
|
||||
int num_sound_timers = 1;
|
||||
#else
|
||||
struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] =
|
||||
{NULL};
|
||||
int num_sound_timers = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* List of low level drivers compiled into the kernel.
|
||||
*/
|
||||
|
||||
struct driver_info sound_drivers[] = {
|
||||
#ifndef EXCLUDE_PSS
|
||||
{SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss},
|
||||
#endif
|
||||
#ifndef EXCLUDE_YM3812
|
||||
{SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib},
|
||||
#endif
|
||||
#ifndef EXCLUDE_PAS
|
||||
{SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas},
|
||||
#endif
|
||||
#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
|
||||
{SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401},
|
||||
#endif
|
||||
#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
|
||||
{SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850},
|
||||
#endif
|
||||
#ifndef EXCLUDE_SB
|
||||
{SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb},
|
||||
#endif
|
||||
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
{SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect},
|
||||
#endif
|
||||
#ifndef EXCLUDE_MIDI
|
||||
{SNDCARD_SB16MIDI,"SB16 MIDI", attach_sb16midi, probe_sb16midi},
|
||||
#endif
|
||||
#endif
|
||||
#ifndef EXCLUDE_GUS16
|
||||
{SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16},
|
||||
#endif
|
||||
#ifndef EXCLUDE_MSS
|
||||
{SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound},
|
||||
#endif
|
||||
#ifndef EXCLUDE_GUS
|
||||
{SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus},
|
||||
#endif
|
||||
{0, "*?*", NULL, NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
* List of devices actually configured in the system.
|
||||
*
|
||||
* Note! The detection order is significant. Don't change it.
|
||||
*/
|
||||
|
||||
struct card_info snd_installed_cards[] = {
|
||||
#ifndef EXCLUDE_PSS
|
||||
{SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
|
||||
{SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
|
||||
#ifdef MPU2_BASE
|
||||
{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
#ifdef MPU3_BASE
|
||||
{SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
#endif
|
||||
#ifndef EXCLUDE_MSS
|
||||
{SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE},
|
||||
# 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},
|
||||
#endif
|
||||
#ifndef EXCLUDE_MIDI
|
||||
{SNDCARD_SB16MIDI,{SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_GUS
|
||||
#ifndef EXCLUDE_GUS16
|
||||
{SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
{SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_YM3812
|
||||
{SNDCARD_ADLIB, {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
{0, {0}, 0}
|
||||
};
|
||||
|
||||
int num_sound_drivers =
|
||||
sizeof(sound_drivers) / sizeof (struct driver_info);
|
||||
int num_sound_cards =
|
||||
sizeof(snd_installed_cards) / sizeof (struct card_info);
|
||||
|
||||
|
||||
#else
|
||||
extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs;
|
||||
extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
|
||||
extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths;
|
||||
extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
|
||||
extern struct sound_timer_operations * sound_timer_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_sound_timers;
|
||||
|
||||
extern struct driver_info sound_drivers[];
|
||||
extern int num_sound_drivers;
|
||||
extern struct card_info snd_installed_cards[];
|
||||
extern int num_sound_cards;
|
||||
|
||||
long sndtable_init(long mem_start);
|
||||
int sndtable_get_cardcount (void);
|
||||
struct address_info *sound_getconf(int card_type);
|
||||
void sound_chconf(int card_type, int ioaddr, int irq, int dma);
|
||||
int snd_find_driver(int type);
|
||||
|
||||
#endif /* _DEV_TABLE_C_ */
|
||||
#endif /* _DEV_TABLE_H_ */
|
964
sys/i386/isa/sound/dmabuf.c
Normal file
964
sys/i386/isa/sound/dmabuf.c
Normal file
@ -0,0 +1,964 @@
|
||||
/*
|
||||
* sound/dmabuf.c
|
||||
*
|
||||
* The DMA buffer manager for digitized voice applications
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993, 1994
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#include "sound_calls.h"
|
||||
|
||||
#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.
|
||||
*/
|
||||
|
||||
static void
|
||||
reorganize_buffers (int dev)
|
||||
{
|
||||
/*
|
||||
* This routine breaks the physical device buffers to logical ones.
|
||||
*/
|
||||
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
struct audio_operations *dsp_dev = audio_devs[dev];
|
||||
|
||||
unsigned i, p, n;
|
||||
unsigned sr, nc, sz, bsz;
|
||||
|
||||
if (dmap->fragment_size == 0)
|
||||
{ /* Compute the fragment size using the default algorithm */
|
||||
|
||||
sr = dsp_dev->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
|
||||
nc = dsp_dev->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
|
||||
sz = dsp_dev->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
|
||||
|
||||
if (sr < 1 || nc < 1 || sz < 1)
|
||||
{
|
||||
printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
|
||||
dev, sr, nc, sz);
|
||||
sr = DSP_DEFAULT_SPEED;
|
||||
nc = 1;
|
||||
sz = 8;
|
||||
}
|
||||
|
||||
sz /= 8; /* #bits -> #bytes */
|
||||
|
||||
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).
|
||||
*/
|
||||
|
||||
bsz = dsp_dev->buffsize;
|
||||
while (bsz > sz)
|
||||
bsz /= 2;
|
||||
|
||||
if (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize)
|
||||
bsz /= 2; /* Needs at least 2 buffers */
|
||||
|
||||
if (dmap->subdivision == 0) /* Not already set */
|
||||
dmap->subdivision = 1; /* Init to default value */
|
||||
|
||||
bsz /= dmap->subdivision;
|
||||
|
||||
if (bsz < 64)
|
||||
bsz = 4096; /* Just a sanity check */
|
||||
|
||||
while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS)
|
||||
bsz *= 2;
|
||||
|
||||
dmap->fragment_size = bsz;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
|
||||
* the buffer sice computation has already been done.
|
||||
*/
|
||||
if (dmap->fragment_size > audio_devs[dev]->buffsize)
|
||||
dmap->fragment_size = audio_devs[dev]->buffsize;
|
||||
bsz = dmap->fragment_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now computing addresses for the logical buffers
|
||||
*/
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < dmap->raw_count &&
|
||||
n < dmap->max_fragments &&
|
||||
n < MAX_SUB_BUFFERS; i++)
|
||||
{
|
||||
p = 0;
|
||||
|
||||
while ((p + bsz) <= dsp_dev->buffsize &&
|
||||
n < dmap->max_fragments &&
|
||||
n < MAX_SUB_BUFFERS)
|
||||
{
|
||||
dmap->buf[n] = dmap->raw_buf[i] + p;
|
||||
dmap->buf_phys[n] = dmap->raw_buf_phys[i] + p;
|
||||
p += bsz;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
dmap->nbufs = n;
|
||||
dmap->bytes_in_use = n * bsz;
|
||||
|
||||
for (i = 0; i < dmap->nbufs; i++)
|
||||
{
|
||||
dmap->counts[i] = 0;
|
||||
}
|
||||
|
||||
dmap->flags |= DMA_ALLOC_DONE;
|
||||
}
|
||||
|
||||
static void
|
||||
dma_init_buffers (int dev)
|
||||
{
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev];
|
||||
|
||||
RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
|
||||
dmap->flags = DMA_BUSY; /* Other flags off */
|
||||
dmap->qlen = dmap->qhead = dmap->qtail = 0;
|
||||
|
||||
dmap->qlen = dmap->qtail = dmap->qhead = 0;
|
||||
dmap->dma_mode = DMODE_NONE;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_open (int dev, int mode)
|
||||
{
|
||||
int retval;
|
||||
struct dma_buffparms *dmap = NULL;
|
||||
|
||||
if (dev >= num_audiodevs)
|
||||
{
|
||||
printk ("PCM device %d not installed.\n", dev);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
if (!audio_devs[dev])
|
||||
{
|
||||
printk ("PCM device %d not initialized\n", dev);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
dmap = audio_devs[dev]->dmap = &dmaps[dev];
|
||||
|
||||
if (dmap->flags & DMA_BUSY)
|
||||
return RET_ERROR (EBUSY);
|
||||
|
||||
#ifdef USE_RUNTIME_DMAMEM
|
||||
dmap->raw_buf[0] = NULL;
|
||||
sound_dma_malloc (dev);
|
||||
#endif
|
||||
|
||||
if (dmap->raw_buf[0] == NULL)
|
||||
return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
|
||||
|
||||
if ((retval = audio_devs[dev]->open (dev, mode)) < 0)
|
||||
return retval;
|
||||
|
||||
dmap->open_mode = mode;
|
||||
dmap->subdivision = dmap->underrun_count = 0;
|
||||
dmap->fragment_size = 0;
|
||||
dmap->max_fragments = 65536; /* Just a large value */
|
||||
|
||||
dma_init_buffers (dev);
|
||||
audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
|
||||
audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
|
||||
audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dma_reset (int dev)
|
||||
{
|
||||
int retval;
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
audio_devs[dev]->reset (dev);
|
||||
audio_devs[dev]->close (dev);
|
||||
|
||||
if ((retval = audio_devs[dev]->open (dev, audio_devs[dev]->dmap->open_mode)) < 0)
|
||||
printk ("Sound: Reset failed - Can't reopen device\n");
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
dma_init_buffers (dev);
|
||||
reorganize_buffers (dev);
|
||||
}
|
||||
|
||||
static int
|
||||
dma_sync (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])
|
||||
&& audio_devs[dev]->dmap->qlen)
|
||||
{
|
||||
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
|
||||
if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
return audio_devs[dev]->dmap->qlen;
|
||||
}
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* Some devices such as GUS have huge amount of on board RAM for the
|
||||
* audio data. We have to wait util the device has finished playing.
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */
|
||||
{
|
||||
while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
&& audio_devs[dev]->local_qlen (dev))
|
||||
{
|
||||
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ);
|
||||
}
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
return audio_devs[dev]->dmap->qlen;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_release (int dev, int mode)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
&& (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT))
|
||||
{
|
||||
dma_sync (dev);
|
||||
}
|
||||
|
||||
#ifdef USE_RUNTIME_DMAMEM
|
||||
sound_dma_free (dev);
|
||||
#endif
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
audio_devs[dev]->reset (dev);
|
||||
|
||||
audio_devs[dev]->close (dev);
|
||||
|
||||
audio_devs[dev]->dmap->dma_mode = DMODE_NONE;
|
||||
audio_devs[dev]->dmap->flags &= ~DMA_BUSY;
|
||||
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 (dmap->flags & DMA_RESTART)
|
||||
{
|
||||
dma_reset (dev);
|
||||
dmap->flags &= ~DMA_RESTART;
|
||||
}
|
||||
|
||||
if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */
|
||||
{
|
||||
dma_sync (dev);
|
||||
dma_reset (dev);
|
||||
dmap->dma_mode = DMODE_NONE;
|
||||
}
|
||||
|
||||
if (!(dmap->flags & DMA_ALLOC_DONE))
|
||||
reorganize_buffers (dev);
|
||||
|
||||
if (dmap->dma_mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = audio_devs[dev]->prepare_for_input (dev,
|
||||
dmap->fragment_size, dmap->nbufs)) < 0)
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
return err;
|
||||
}
|
||||
dmap->dma_mode = DMODE_INPUT;
|
||||
}
|
||||
|
||||
if (!(dmap->flags & DMA_ACTIVE))
|
||||
{
|
||||
audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
|
||||
dmap->fragment_size, 0,
|
||||
!(audio_devs[dev]->flags & DMA_AUTOMODE) ||
|
||||
!(dmap->flags & DMA_STARTED));
|
||||
dmap->flags |= DMA_ACTIVE | DMA_STARTED;
|
||||
}
|
||||
|
||||
/* Wait for the next block */
|
||||
|
||||
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
|
||||
if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
|
||||
err = EIO;
|
||||
SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
}
|
||||
else
|
||||
err = EINTR;
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
if (!dmap->qlen)
|
||||
return RET_ERROR (err);
|
||||
|
||||
*buf = &dmap->buf[dmap->qhead][dmap->counts[dmap->qhead]];
|
||||
*len = dmap->fragment_size - dmap->counts[dmap->qhead];
|
||||
|
||||
return dmap->qhead;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_rmchars (int dev, int buff_no, int c)
|
||||
{
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
|
||||
int p = dmap->counts[dmap->qhead] + c;
|
||||
|
||||
if (p >= dmap->fragment_size)
|
||||
{ /* This buffer is completely empty */
|
||||
dmap->counts[dmap->qhead] = 0;
|
||||
if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
|
||||
printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n",
|
||||
dev, dmap->qlen, dmap->nbufs);
|
||||
dmap->qlen--;
|
||||
dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
|
||||
}
|
||||
else
|
||||
dmap->counts[dmap->qhead] = p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
{
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SNDCTL_DSP_RESET:
|
||||
dma_reset (dev);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_SYNC:
|
||||
dma_sync (dev);
|
||||
dma_reset (dev);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_GETBLKSIZE:
|
||||
if (!(dmap->flags & DMA_ALLOC_DONE))
|
||||
reorganize_buffers (dev);
|
||||
|
||||
return IOCTL_OUT (arg, dmap->fragment_size);
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_SUBDIVIDE:
|
||||
{
|
||||
int fact = IOCTL_IN (arg);
|
||||
|
||||
if (fact == 0)
|
||||
{
|
||||
fact = dmap->subdivision;
|
||||
if (fact == 0)
|
||||
fact = 1;
|
||||
return IOCTL_OUT (arg, fact);
|
||||
}
|
||||
|
||||
if (dmap->subdivision != 0 ||
|
||||
dmap->fragment_size)/* Loo late to change */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
if (fact > MAX_REALTIME_FACTOR)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
dmap->subdivision = fact;
|
||||
return IOCTL_OUT (arg, fact);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_SETFRAGMENT:
|
||||
{
|
||||
int fact = IOCTL_IN (arg);
|
||||
int bytes, count;
|
||||
|
||||
if (fact == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
if (dmap->subdivision != 0 ||
|
||||
dmap->fragment_size)/* Loo late to change */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
bytes = fact & 0xffff;
|
||||
count = (fact >> 16) & 0xffff;
|
||||
|
||||
if (count == 0)
|
||||
count = MAX_SUB_BUFFERS;
|
||||
|
||||
if (bytes < 7 || bytes > 17) /* <64 || > 128k */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
if (count < 2)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
dmap->fragment_size = (1 << bytes);
|
||||
dmap->max_fragments = count;
|
||||
|
||||
if (dmap->fragment_size > audio_devs[dev]->buffsize)
|
||||
dmap->fragment_size = audio_devs[dev]->buffsize;
|
||||
|
||||
if (dmap->fragment_size == audio_devs[dev]->buffsize &&
|
||||
audio_devs[dev]->flags & DMA_AUTOMODE)
|
||||
dmap->fragment_size /= 2; /* Needs at least 2 buffers */
|
||||
|
||||
dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */
|
||||
return IOCTL_OUT (arg, bytes | (count << 16));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return audio_devs[dev]->ioctl (dev, cmd, arg, local);
|
||||
}
|
||||
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
static int
|
||||
space_in_queue (int dev)
|
||||
{
|
||||
int len, max, tmp;
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
|
||||
if (dmap->qlen == dmap->nbufs)/* No space at all */
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Verify that there are no more pending buffers than the limit
|
||||
* defined by the process.
|
||||
*/
|
||||
|
||||
max = dmap->max_fragments;
|
||||
len = dmap->qlen;
|
||||
|
||||
if (audio_devs[dev]->local_qlen)
|
||||
{
|
||||
tmp = audio_devs[dev]->local_qlen (dev);
|
||||
if (tmp & len)
|
||||
tmp--; /*
|
||||
* This buffer has been counted twice
|
||||
*/
|
||||
len += tmp;
|
||||
}
|
||||
|
||||
if (len >= max)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_getwrbuffer (int dev, char **buf, int *size)
|
||||
{
|
||||
unsigned long flags;
|
||||
int abort, err = EIO;
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
|
||||
if (dmap->dma_mode == DMODE_INPUT) /* Direction change */
|
||||
{
|
||||
dma_reset (dev);
|
||||
dmap->dma_mode = DMODE_NONE;
|
||||
}
|
||||
else if (dmap->flags & DMA_RESTART) /* Restart buffering */
|
||||
{
|
||||
dma_sync (dev);
|
||||
dma_reset (dev);
|
||||
}
|
||||
|
||||
dmap->flags &= ~DMA_RESTART;
|
||||
|
||||
if (!(dmap->flags & DMA_ALLOC_DONE))
|
||||
reorganize_buffers (dev);
|
||||
|
||||
if (!dmap->dma_mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
dmap->dma_mode = DMODE_OUTPUT;
|
||||
if ((err = audio_devs[dev]->prepare_for_output (dev,
|
||||
dmap->fragment_size, dmap->nbufs)) < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
abort = 0;
|
||||
while (!space_in_queue (dev) &&
|
||||
!abort)
|
||||
{
|
||||
/*
|
||||
* Wait for free space
|
||||
*/
|
||||
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
|
||||
if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
|
||||
err = EIO;
|
||||
abort = 1;
|
||||
SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
}
|
||||
else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
err = EINTR;
|
||||
abort = 1;
|
||||
}
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
if (!space_in_queue (dev))
|
||||
{
|
||||
return RET_ERROR (err); /* Caught a signal ? */
|
||||
}
|
||||
|
||||
*buf = dmap->buf[dmap->qtail];
|
||||
*size = dmap->fragment_size;
|
||||
dmap->counts[dmap->qtail] = 0;
|
||||
|
||||
return dmap->qtail;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_start_output (int dev, int buff_no, int l)
|
||||
{
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
|
||||
if (buff_no != dmap->qtail)
|
||||
printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
|
||||
|
||||
dmap->qlen++;
|
||||
if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
|
||||
printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
|
||||
dev, dmap->qlen, dmap->nbufs);
|
||||
|
||||
dmap->counts[dmap->qtail] = l;
|
||||
|
||||
if ((l != dmap->fragment_size) &&
|
||||
((audio_devs[dev]->flags & DMA_AUTOMODE) &&
|
||||
audio_devs[dev]->flags & NEEDS_RESTART))
|
||||
dmap->flags |= DMA_RESTART;
|
||||
else
|
||||
dmap->flags &= ~DMA_RESTART;
|
||||
|
||||
dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
|
||||
|
||||
if (!(dmap->flags & DMA_ACTIVE))
|
||||
{
|
||||
dmap->flags |= DMA_ACTIVE;
|
||||
audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
|
||||
dmap->counts[dmap->qhead], 0,
|
||||
!(audio_devs[dev]->flags & DMA_AUTOMODE) ||
|
||||
!(dmap->flags & DMA_STARTED));
|
||||
dmap->flags |= DMA_STARTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
|
||||
{
|
||||
int chan = audio_devs[dev]->dmachan;
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* This function is not as portable as it should be.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The count must be one less than the actual size. This is handled by
|
||||
* set_dma_addr()
|
||||
*/
|
||||
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE)
|
||||
{ /*
|
||||
* Auto restart mode. Transfer the whole *
|
||||
* buffer
|
||||
*/
|
||||
#ifdef linux
|
||||
DISABLE_INTR (flags);
|
||||
disable_dma (chan);
|
||||
clear_dma_ff (chan);
|
||||
set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
|
||||
set_dma_addr (chan, dmap->raw_buf_phys[0]);
|
||||
set_dma_count (chan, dmap->bytes_in_use);
|
||||
enable_dma (chan);
|
||||
RESTORE_INTR (flags);
|
||||
#else
|
||||
|
||||
#ifdef __386BSD__
|
||||
printk ("sound: Invalid DMA mode for device %d\n", dev);
|
||||
|
||||
isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
|
||||
dmap->raw_buf_phys[0],
|
||||
dmap->bytes_in_use,
|
||||
chan);
|
||||
#else
|
||||
#if defined(GENERIC_SYSV)
|
||||
#ifndef DMAMODE_AUTO
|
||||
printk ("sound: Invalid DMA mode for device %d\n", dev);
|
||||
#endif
|
||||
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
|
||||
#ifdef DMAMODE_AUTO
|
||||
| DMAMODE_AUTO
|
||||
#endif
|
||||
,
|
||||
dmap->raw_buf_phys[0], dmap->bytes_in_use);
|
||||
dma_enable (chan);
|
||||
#else
|
||||
#error This routine is not valid for this OS.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef linux
|
||||
DISABLE_INTR (flags);
|
||||
disable_dma (chan);
|
||||
clear_dma_ff (chan);
|
||||
set_dma_mode (chan, dma_mode);
|
||||
set_dma_addr (chan, physaddr);
|
||||
set_dma_count (chan, count);
|
||||
enable_dma (chan);
|
||||
RESTORE_INTR (flags);
|
||||
#else
|
||||
#ifdef __386BSD__
|
||||
isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
|
||||
physaddr,
|
||||
count,
|
||||
chan);
|
||||
#else
|
||||
|
||||
#if defined(GENERIC_SYSV)
|
||||
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
|
||||
physaddr, count);
|
||||
dma_enable (chan);
|
||||
#else
|
||||
#error This routine is not valid for this OS.
|
||||
#endif /* GENERIC_SYSV */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
long
|
||||
DMAbuf_init (long mem_start)
|
||||
{
|
||||
int dev;
|
||||
|
||||
/*
|
||||
* NOTE! This routine could be called several times.
|
||||
*/
|
||||
|
||||
for (dev = 0; dev < num_audiodevs; dev++)
|
||||
audio_devs[dev]->dmap = &dmaps[dev];
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_outputintr (int dev, int 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.
|
||||
*/
|
||||
|
||||
unsigned long flags;
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
|
||||
if (event_type != 2)
|
||||
{
|
||||
if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
|
||||
{
|
||||
printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
|
||||
dev, dmap->qlen, dmap->nbufs);
|
||||
return;
|
||||
}
|
||||
|
||||
dmap->qlen--;
|
||||
dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
|
||||
dmap->flags &= ~DMA_ACTIVE;
|
||||
|
||||
if (dmap->qlen)
|
||||
{
|
||||
audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead],
|
||||
dmap->counts[dmap->qhead], 1,
|
||||
!(audio_devs[dev]->flags & DMA_AUTOMODE));
|
||||
dmap->flags |= DMA_ACTIVE;
|
||||
}
|
||||
else if (event_type == 1)
|
||||
{
|
||||
dmap->underrun_count++;
|
||||
audio_devs[dev]->halt_xfer (dev);
|
||||
if ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
|
||||
audio_devs[dev]->flags & NEEDS_RESTART)
|
||||
dmap->flags |= DMA_RESTART;
|
||||
else
|
||||
dmap->flags &= ~DMA_RESTART;
|
||||
}
|
||||
} /* event_type != 2 */
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_inputintr (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct dma_buffparms *dmap = audio_devs[dev]->dmap;
|
||||
|
||||
if (dmap->qlen == (dmap->nbufs - 1))
|
||||
{
|
||||
printk ("Sound: Recording overrun\n");
|
||||
dmap->underrun_count++;
|
||||
audio_devs[dev]->halt_xfer (dev);
|
||||
dmap->flags &= ~DMA_ACTIVE;
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE)
|
||||
dmap->flags |= DMA_RESTART;
|
||||
else
|
||||
dmap->flags &= ~DMA_RESTART;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmap->qlen++;
|
||||
if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
|
||||
printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
|
||||
dev, dmap->qlen, dmap->nbufs);
|
||||
dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
|
||||
|
||||
audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail],
|
||||
dmap->fragment_size, 1,
|
||||
!(audio_devs[dev]->flags & DMA_AUTOMODE));
|
||||
dmap->flags |= DMA_ACTIVE;
|
||||
}
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_open_dma (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
int chan = audio_devs[dev]->dmachan;
|
||||
|
||||
if (ALLOC_DMA_CHN (chan))
|
||||
{
|
||||
printk ("Unable to grab DMA%d for the audio driver\n", chan);
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
#ifdef linux
|
||||
disable_dma (chan);
|
||||
clear_dma_ff (chan);
|
||||
#endif
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_close_dma (int dev)
|
||||
{
|
||||
int chan = audio_devs[dev]->dmachan;
|
||||
|
||||
DMAbuf_reset_dma (chan);
|
||||
RELEASE_DMA_CHN (chan);
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_reset_dma (int chan)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* The sound_mem_init() is called by mem_init() immediately after mem_map is
|
||||
* initialized and before free_page_list is created.
|
||||
*
|
||||
* This routine allocates DMA buffers at the end of available physical memory (
|
||||
* <16M) and marks pages reserved at mem_map.
|
||||
*/
|
||||
|
||||
#else
|
||||
/*
|
||||
* Stub versions if audio services not included
|
||||
*/
|
||||
|
||||
int
|
||||
DMAbuf_open (int dev, int mode)
|
||||
{
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_release (int dev, int mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_getwrbuffer (int dev, char **buf, int *size)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_getrdbuffer (int dev, char **buf, int *len)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_rmchars (int dev, int buff_no, int c)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_start_output (int dev, int buff_no, int l)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
long
|
||||
DMAbuf_init (long mem_start)
|
||||
{
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
|
||||
{
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_open_dma (int chan)
|
||||
{
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_close_dma (int chan)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_reset_dma (int chan)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_inputintr (int dev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_outputintr (int dev, int underrun_flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
49
sys/i386/isa/sound/finetune.h
Normal file
49
sys/i386/isa/sound/finetune.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifdef SEQUENCER_C
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
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,
|
||||
/* 120 */ 10518, 10528, 10537, 10547, 10556, 10566, 10576, 10585
|
||||
};
|
||||
#else
|
||||
extern unsigned short finetune_table[128];
|
||||
#endif
|
193
sys/i386/isa/sound/gus_card.c
Normal file
193
sys/i386/isa/sound/gus_card.c
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* sound/gus_card.c
|
||||
*
|
||||
* Detection routine for the Gravis Ultrasound.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
|
||||
|
||||
#include "gus_hw.h"
|
||||
|
||||
void gusintr (int);
|
||||
|
||||
int gus_base, gus_irq, gus_dma;
|
||||
extern int gus_wave_volume;
|
||||
extern int gus_pcm_volume;
|
||||
extern int have_gus_max;
|
||||
|
||||
long
|
||||
attach_gus_card (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
int io_addr;
|
||||
|
||||
snd_set_irq_handler (hw_config->irq, gusintr);
|
||||
|
||||
if (gus_wave_detect (hw_config->io_base)) /*
|
||||
* Try first the default
|
||||
*/
|
||||
{
|
||||
mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
|
||||
#ifndef EXCLUDE_MIDI
|
||||
mem_start = gus_midi_init (mem_start);
|
||||
#endif
|
||||
#ifndef EXCLUDE_SEQUENCER
|
||||
sound_timer_init (hw_config->io_base + 8);
|
||||
#endif
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#ifndef EXCLUDE_GUS_IODETECT
|
||||
|
||||
/*
|
||||
* Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
|
||||
*/
|
||||
|
||||
for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
|
||||
if (io_addr != hw_config->io_base) /*
|
||||
* Already tested
|
||||
*/
|
||||
if (gus_wave_detect (io_addr))
|
||||
{
|
||||
printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
|
||||
mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
|
||||
#ifndef EXCLUDE_MIDI
|
||||
mem_start = gus_midi_init (mem_start);
|
||||
#endif
|
||||
#ifndef EXCLUDE_SEQUENCER
|
||||
sound_timer_init (io_addr + 8);
|
||||
#endif
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return mem_start; /*
|
||||
* Not detected
|
||||
*/
|
||||
}
|
||||
|
||||
int
|
||||
probe_gus (struct address_info *hw_config)
|
||||
{
|
||||
int io_addr;
|
||||
|
||||
if (gus_wave_detect (hw_config->io_base))
|
||||
return 1;
|
||||
|
||||
#ifndef EXCLUDE_GUS_IODETECT
|
||||
|
||||
/*
|
||||
* Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
|
||||
*/
|
||||
|
||||
for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
|
||||
if (io_addr != hw_config->io_base) /*
|
||||
* Already tested
|
||||
*/
|
||||
if (gus_wave_detect (io_addr))
|
||||
return 1;
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gusintr (int irq)
|
||||
{
|
||||
unsigned char src;
|
||||
|
||||
#ifdef linux
|
||||
sti ();
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_GUSMAX
|
||||
if (have_gus_max)
|
||||
ad1848_interrupt (irq);
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!(src = INB (u_IrqStatus)))
|
||||
return;
|
||||
|
||||
if (src & DMA_TC_IRQ)
|
||||
{
|
||||
guswave_dma_irq ();
|
||||
}
|
||||
|
||||
if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
|
||||
{
|
||||
#ifndef EXCLUDE_MIDI
|
||||
gus_midi_interrupt (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
|
||||
{
|
||||
#ifndef EXCLUDE_SEQUENCER
|
||||
sound_timer_interrupt ();
|
||||
#else
|
||||
gus_write8 (0x45, 0); /* Stop timers */
|
||||
#endif
|
||||
}
|
||||
|
||||
if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
|
||||
{
|
||||
gus_voice_irq ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some extra code for the 16 bit sampling option
|
||||
*/
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16)
|
||||
|
||||
int
|
||||
probe_gus_db16 (struct address_info *hw_config)
|
||||
{
|
||||
return ad1848_detect (hw_config->io_base);
|
||||
}
|
||||
|
||||
long
|
||||
attach_gus_db16 (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
gus_pcm_volume = 100;
|
||||
gus_wave_volume = 90;
|
||||
|
||||
ad1848_init ("GUS 16 bit sampling", hw_config->io_base,
|
||||
hw_config->irq,
|
||||
hw_config->dma,
|
||||
hw_config->dma);
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
50
sys/i386/isa/sound/gus_hw.h
Normal file
50
sys/i386/isa/sound/gus_hw.h
Normal file
@ -0,0 +1,50 @@
|
||||
|
||||
/*
|
||||
* I/O addresses
|
||||
*/
|
||||
|
||||
#define u_Base (gus_base + 0x000)
|
||||
#define u_Mixer u_Base
|
||||
#define u_Status (gus_base + 0x006)
|
||||
#define u_TimerControl (gus_base + 0x008)
|
||||
#define u_TimerData (gus_base + 0x009)
|
||||
#define u_IRQDMAControl (gus_base + 0x00b)
|
||||
#define u_MidiControl (gus_base + 0x100)
|
||||
#define MIDI_RESET 0x03
|
||||
#define MIDI_ENABLE_XMIT 0x20
|
||||
#define MIDI_ENABLE_RCV 0x80
|
||||
#define u_MidiStatus u_MidiControl
|
||||
#define MIDI_RCV_FULL 0x01
|
||||
#define MIDI_XMIT_EMPTY 0x02
|
||||
#define MIDI_FRAME_ERR 0x10
|
||||
#define MIDI_OVERRUN 0x20
|
||||
#define MIDI_IRQ_PEND 0x80
|
||||
#define u_MidiData (gus_base + 0x101)
|
||||
#define u_Voice (gus_base + 0x102)
|
||||
#define u_Command (gus_base + 0x103)
|
||||
#define u_DataLo (gus_base + 0x104)
|
||||
#define u_DataHi (gus_base + 0x105)
|
||||
#define u_MixData (gus_base + 0x106) /* Rev. 3.7+ mixing */
|
||||
#define u_MixSelect (gus_base + 0x506) /* registers. */
|
||||
#define u_IrqStatus u_Status
|
||||
# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */
|
||||
# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */
|
||||
# define GF1_TIMER1_IRQ 0x04 /* general purpose timer */
|
||||
# define GF1_TIMER2_IRQ 0x08 /* general purpose timer */
|
||||
# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */
|
||||
# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */
|
||||
# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */
|
||||
|
||||
#define ICS2101 1
|
||||
# define ICS_MIXDEVS 6
|
||||
# define DEV_MIC 0
|
||||
# define DEV_LINE 1
|
||||
# define DEV_CD 2
|
||||
# define DEV_GF1 3
|
||||
# define DEV_UNUSED 4
|
||||
# define DEV_VOL 5
|
||||
|
||||
# define CHN_LEFT 0
|
||||
# define CHN_RIGHT 1
|
||||
#define CS4231 2
|
||||
#define u_DRAMIO (gus_base + 0x107)
|
18
sys/i386/isa/sound/gus_linearvol.h
Normal file
18
sys/i386/isa/sound/gus_linearvol.h
Normal file
@ -0,0 +1,18 @@
|
||||
static unsigned short gus_linearvol[128] = {
|
||||
0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
|
||||
0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
|
||||
0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
|
||||
0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
|
||||
0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
|
||||
0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
|
||||
0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
|
||||
0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
|
||||
0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
|
||||
0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
|
||||
0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
|
||||
0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
|
||||
0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
|
||||
0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
|
||||
0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
|
||||
0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
|
||||
};
|
309
sys/i386/isa/sound/gus_midi.c
Normal file
309
sys/i386/isa/sound/gus_midi.c
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* sound/gus2_midi.c
|
||||
*
|
||||
* The low level driver for the GUS Midi Interface.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#include "gus_hw.h"
|
||||
|
||||
#if !defined(EXCLUDE_GUS) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
static int midi_busy = 0, input_opened = 0;
|
||||
static int my_dev;
|
||||
static int output_used = 0;
|
||||
static volatile unsigned char gus_midi_control;
|
||||
|
||||
static void (*midi_input_intr) (int dev, unsigned char data);
|
||||
|
||||
static unsigned char tmp_queue[256];
|
||||
static volatile int qlen;
|
||||
static volatile unsigned char qhead, qtail;
|
||||
extern int gus_base, gus_irq, gus_dma;
|
||||
|
||||
#define GUS_MIDI_STATUS() INB(u_MidiStatus)
|
||||
|
||||
static int
|
||||
gus_midi_open (int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
void (*output) (int dev)
|
||||
)
|
||||
{
|
||||
|
||||
if (midi_busy)
|
||||
{
|
||||
printk ("GUS: Midi busy\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
OUTB (MIDI_RESET, u_MidiControl);
|
||||
gus_delay ();
|
||||
|
||||
gus_midi_control = 0;
|
||||
input_opened = 0;
|
||||
|
||||
if (mode == OPEN_READ || mode == OPEN_READWRITE)
|
||||
{
|
||||
gus_midi_control |= MIDI_ENABLE_RCV;
|
||||
input_opened = 1;
|
||||
}
|
||||
|
||||
if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
|
||||
{
|
||||
gus_midi_control |= MIDI_ENABLE_XMIT;
|
||||
}
|
||||
|
||||
OUTB (gus_midi_control, u_MidiControl); /*
|
||||
* Enable
|
||||
*/
|
||||
|
||||
midi_busy = 1;
|
||||
qlen = qhead = qtail = output_used = 0;
|
||||
midi_input_intr = input;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dump_to_midi (unsigned char midi_byte)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ok = 0;
|
||||
|
||||
output_used = 1;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY)
|
||||
{
|
||||
ok = 1;
|
||||
OUTB (midi_byte, u_MidiData);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Enable Midi xmit interrupts (again)
|
||||
*/
|
||||
gus_midi_control |= MIDI_ENABLE_XMIT;
|
||||
OUTB (gus_midi_control, u_MidiControl);
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void
|
||||
gus_midi_close (int dev)
|
||||
{
|
||||
/*
|
||||
* Reset FIFO pointers, disable intrs
|
||||
*/
|
||||
|
||||
OUTB (MIDI_RESET, u_MidiControl);
|
||||
midi_busy = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gus_midi_out (int dev, unsigned char midi_byte)
|
||||
{
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Drain the local queue first
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
while (qlen && dump_to_midi (tmp_queue[qhead]))
|
||||
{
|
||||
qlen--;
|
||||
qhead++;
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* Output the byte if the local queue is empty.
|
||||
*/
|
||||
|
||||
if (!qlen)
|
||||
if (dump_to_midi (midi_byte))
|
||||
return 1; /*
|
||||
* OK
|
||||
*/
|
||||
|
||||
/*
|
||||
* Put to the local queue
|
||||
*/
|
||||
|
||||
if (qlen >= 256)
|
||||
return 0; /*
|
||||
* Local queue full
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
tmp_queue[qtail] = midi_byte;
|
||||
qlen++;
|
||||
qtail++;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
gus_midi_start_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gus_midi_end_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gus_midi_ioctl (int dev, unsigned cmd, unsigned arg)
|
||||
{
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
gus_midi_kick (int dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
gus_midi_buffer_status (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!output_used)
|
||||
return 0;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (qlen && dump_to_midi (tmp_queue[qhead]))
|
||||
{
|
||||
qlen--;
|
||||
qhead++;
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY);
|
||||
}
|
||||
|
||||
#define MIDI_SYNTH_NAME "Gravis Ultrasound Midi"
|
||||
#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
|
||||
#include "midi_synth.h"
|
||||
|
||||
static struct midi_operations gus_midi_operations =
|
||||
{
|
||||
{"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
|
||||
&std_midi_synth,
|
||||
gus_midi_open,
|
||||
gus_midi_close,
|
||||
gus_midi_ioctl,
|
||||
gus_midi_out,
|
||||
gus_midi_start_read,
|
||||
gus_midi_end_read,
|
||||
gus_midi_kick,
|
||||
NULL, /*
|
||||
* command
|
||||
*/
|
||||
gus_midi_buffer_status,
|
||||
NULL
|
||||
};
|
||||
|
||||
long
|
||||
gus_midi_init (long mem_start)
|
||||
{
|
||||
if (num_midis >= MAX_MIDI_DEV)
|
||||
{
|
||||
printk ("Sound: Too many midi devices detected\n");
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
OUTB (MIDI_RESET, u_MidiControl);
|
||||
|
||||
std_midi_synth.midi_dev = my_dev = num_midis;
|
||||
midi_devs[num_midis++] = &gus_midi_operations;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
void
|
||||
gus_midi_interrupt (int dummy)
|
||||
{
|
||||
unsigned char stat, data;
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
stat = GUS_MIDI_STATUS ();
|
||||
|
||||
if (stat & MIDI_RCV_FULL)
|
||||
{
|
||||
data = INB (u_MidiData);
|
||||
if (input_opened)
|
||||
midi_input_intr (my_dev, data);
|
||||
}
|
||||
|
||||
if (stat & MIDI_XMIT_EMPTY)
|
||||
{
|
||||
while (qlen && dump_to_midi (tmp_queue[qhead]))
|
||||
{
|
||||
qlen--;
|
||||
qhead++;
|
||||
}
|
||||
|
||||
if (!qlen)
|
||||
{
|
||||
/*
|
||||
* Disable Midi output interrupts, since no data in the buffer
|
||||
*/
|
||||
gus_midi_control &= ~MIDI_ENABLE_XMIT;
|
||||
OUTB (gus_midi_control, u_MidiControl);
|
||||
}
|
||||
}
|
||||
|
||||
if (stat & MIDI_FRAME_ERR)
|
||||
printk ("Midi framing error\n");
|
||||
if (stat & MIDI_OVERRUN && input_opened)
|
||||
printk ("GUS: Midi input overrun\n");
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
147
sys/i386/isa/sound/gus_vol.c
Normal file
147
sys/i386/isa/sound/gus_vol.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* gus_vol.c - Compute volume for GUS.
|
||||
*
|
||||
* Greg Lee 1993.
|
||||
*/
|
||||
#include "sound_config.h"
|
||||
#ifndef EXCLUDE_GUS
|
||||
#include "gus_linearvol.h"
|
||||
|
||||
#define GUS_VOLUME gus_wave_volume
|
||||
|
||||
|
||||
extern int gus_wave_volume;
|
||||
|
||||
/*
|
||||
* Calculate gus volume from note velocity, main volume, expression, and
|
||||
* intrinsic patch volume given in patch library. Expression is multiplied
|
||||
* in, so it emphasizes differences in note velocity, while main volume is
|
||||
* added in -- I don't know whether this is right, but it seems reasonable to
|
||||
* me. (In the previous stage, main volume controller messages were changed
|
||||
* to expression controller messages, if they were found to be used for
|
||||
* dynamic volume adjustments, so here, main volume can be assumed to be
|
||||
* constant throughout a song.)
|
||||
*
|
||||
* Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
|
||||
* we can give a big boost to very weak voices like nylon guitar and the
|
||||
* basses. The normal value is 64. Strings are assigned lower values.
|
||||
*/
|
||||
unsigned short
|
||||
gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
|
||||
{
|
||||
int i, m, n, x;
|
||||
|
||||
|
||||
/*
|
||||
* A voice volume of 64 is considered neutral, so adjust the main volume if
|
||||
* something other than this neutral value was assigned in the patch
|
||||
* library.
|
||||
*/
|
||||
x = 256 + 6 * (voicev - 64);
|
||||
|
||||
/*
|
||||
* Boost expression by voice volume above neutral.
|
||||
*/
|
||||
if (voicev > 65)
|
||||
xpn += voicev - 64;
|
||||
xpn += (voicev - 64) / 2;
|
||||
|
||||
/*
|
||||
* Combine multiplicative and level components.
|
||||
*/
|
||||
x = vel * xpn * 6 + (voicev / 4) * x;
|
||||
|
||||
#ifdef GUS_VOLUME
|
||||
/*
|
||||
* Further adjustment by installation-specific master volume control
|
||||
* (default 60).
|
||||
*/
|
||||
x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
|
||||
#endif
|
||||
|
||||
#ifdef GUS_USE_CHN_MAIN_VOLUME
|
||||
/*
|
||||
* Experimental support for the channel main volume
|
||||
*/
|
||||
|
||||
mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
|
||||
x = (x * mainv * mainv) / 16384;
|
||||
#endif
|
||||
|
||||
if (x < 2)
|
||||
return (0);
|
||||
else if (x >= 65535)
|
||||
return ((15 << 8) | 255);
|
||||
|
||||
/*
|
||||
* Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
|
||||
* mantissa m.
|
||||
*/
|
||||
n = x;
|
||||
i = 7;
|
||||
if (n < 128)
|
||||
{
|
||||
while (i > 0 && n < (1 << i))
|
||||
i--;
|
||||
}
|
||||
else
|
||||
while (n > 255)
|
||||
{
|
||||
n >>= 1;
|
||||
i++;
|
||||
}
|
||||
/*
|
||||
* Mantissa is part of linear volume not expressed in exponent. (This is
|
||||
* not quite like real logs -- I wonder if it's right.)
|
||||
*/
|
||||
m = x - (1 << i);
|
||||
|
||||
/*
|
||||
* Adjust mantissa to 8 bits.
|
||||
*/
|
||||
if (m > 0)
|
||||
{
|
||||
if (i > 8)
|
||||
m >>= i - 8;
|
||||
else if (i < 8)
|
||||
m <<= 8 - i;
|
||||
}
|
||||
|
||||
return ((i << 8) + m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Volume-values are interpreted as linear values. Volume is based on the
|
||||
* value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
|
||||
* and the volume set by the mixer-device (default 60%).
|
||||
*/
|
||||
|
||||
unsigned short
|
||||
gus_linear_vol (int vol, int mainvol)
|
||||
{
|
||||
int mixer_mainvol;
|
||||
|
||||
if (vol <= 0)
|
||||
vol = 0;
|
||||
else if (vol >= 127)
|
||||
vol = 127;
|
||||
|
||||
#ifdef GUS_VOLUME
|
||||
mixer_mainvol = GUS_VOLUME;
|
||||
#else
|
||||
mixer_mainvol = 100;
|
||||
#endif
|
||||
|
||||
#ifdef GUS_USE_CHN_MAIN_VOLUME
|
||||
if (mainvol <= 0)
|
||||
mainvol = 0;
|
||||
else if (mainvol >= 127)
|
||||
mainvol = 127;
|
||||
#else
|
||||
mainvol = 128;
|
||||
#endif
|
||||
|
||||
return gus_linearvol[(((vol * mainvol) / 128) * mixer_mainvol) / 100];
|
||||
}
|
||||
|
||||
#endif
|
3246
sys/i386/isa/sound/gus_wave.c
Normal file
3246
sys/i386/isa/sound/gus_wave.c
Normal file
File diff suppressed because it is too large
Load Diff
263
sys/i386/isa/sound/ics2101.c
Normal file
263
sys/i386/isa/sound/ics2101.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* sound/ics2101.c
|
||||
*
|
||||
* Driver for the ICS2101 mixer of GUS v3.7.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1994
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
|
||||
|
||||
#include "ultrasound.h"
|
||||
#include "gus_hw.h"
|
||||
|
||||
#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
|
||||
SOUND_MASK_SYNTH| \
|
||||
SOUND_MASK_CD | SOUND_MASK_VOLUME)
|
||||
|
||||
extern int gus_base;
|
||||
static int volumes[ICS_MIXDEVS];
|
||||
static int left_fix[ICS_MIXDEVS] =
|
||||
{1, 1, 1, 2, 1, 2};
|
||||
static int right_fix[ICS_MIXDEVS] =
|
||||
{2, 2, 2, 1, 2, 1};
|
||||
|
||||
static int
|
||||
scale_vol (int vol)
|
||||
{
|
||||
#if 1
|
||||
/*
|
||||
* Experimental volume scaling by Risto Kankkunen.
|
||||
* This should give smoother volume response than just
|
||||
* a plain multiplication.
|
||||
*/
|
||||
int e;
|
||||
|
||||
if (vol < 0)
|
||||
vol = 0;
|
||||
if (vol > 100)
|
||||
vol = 100;
|
||||
vol = (31 * vol + 50) / 100;
|
||||
e = 0;
|
||||
if (vol)
|
||||
{
|
||||
while (vol < 16)
|
||||
{
|
||||
vol <<= 1;
|
||||
e--;
|
||||
}
|
||||
vol -= 16;
|
||||
e += 7;
|
||||
}
|
||||
return ((e << 4) + vol);
|
||||
#else
|
||||
return ((vol * 127) + 50) / 100;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
write_mix (int dev, int chn, int vol)
|
||||
{
|
||||
int *selector;
|
||||
unsigned long flags;
|
||||
int ctrl_addr = dev << 3;
|
||||
int attn_addr = dev << 3;
|
||||
|
||||
vol = scale_vol (vol);
|
||||
|
||||
if (chn == CHN_LEFT)
|
||||
{
|
||||
selector = left_fix;
|
||||
ctrl_addr |= 0x00;
|
||||
attn_addr |= 0x02;
|
||||
}
|
||||
else
|
||||
{
|
||||
selector = right_fix;
|
||||
ctrl_addr |= 0x01;
|
||||
attn_addr |= 0x03;
|
||||
}
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
OUTB (ctrl_addr, u_MixSelect);
|
||||
OUTB (selector[dev], u_MixData);
|
||||
OUTB (attn_addr, u_MixSelect);
|
||||
OUTB ((unsigned char) vol, u_MixData);
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
set_volumes (int dev, int vol)
|
||||
{
|
||||
int left = vol & 0x00ff;
|
||||
int right = (vol >> 8) & 0x00ff;
|
||||
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
if (left > 100)
|
||||
left = 100;
|
||||
if (right < 0)
|
||||
right = 0;
|
||||
if (right > 100)
|
||||
right = 100;
|
||||
|
||||
write_mix (dev, CHN_LEFT, left);
|
||||
write_mix (dev, CHN_RIGHT, right);
|
||||
|
||||
vol = left + (right << 8);
|
||||
volumes[dev] = vol;
|
||||
return vol;
|
||||
}
|
||||
|
||||
static int
|
||||
ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
if (((cmd >> 8) & 0xff) == 'M')
|
||||
{
|
||||
if (cmd & IOC_IN)
|
||||
switch (cmd & 0xff)
|
||||
{
|
||||
case SOUND_MIXER_RECSRC:
|
||||
return gus_default_mixer_ioctl (dev, cmd, arg);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_MIC:
|
||||
return IOCTL_OUT (arg, set_volumes (DEV_MIC, IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_CD:
|
||||
return IOCTL_OUT (arg, set_volumes (DEV_CD, IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_LINE:
|
||||
return IOCTL_OUT (arg, set_volumes (DEV_LINE, IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_SYNTH:
|
||||
return IOCTL_OUT (arg, set_volumes (DEV_GF1, IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_VOLUME:
|
||||
return IOCTL_OUT (arg, set_volumes (DEV_VOL, IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
else
|
||||
switch (cmd & 0xff) /*
|
||||
* Return parameters
|
||||
*/
|
||||
{
|
||||
|
||||
case SOUND_MIXER_RECSRC:
|
||||
return gus_default_mixer_ioctl (dev, cmd, arg);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_DEVMASK:
|
||||
return IOCTL_OUT (arg, MIX_DEVS);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_STEREODEVS:
|
||||
return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
|
||||
SOUND_MASK_SYNTH | SOUND_MASK_VOLUME |
|
||||
SOUND_MASK_MIC);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_RECMASK:
|
||||
return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_CAPS:
|
||||
return IOCTL_OUT (arg, 0);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_MIC:
|
||||
return IOCTL_OUT (arg, volumes[DEV_MIC]);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_LINE:
|
||||
return IOCTL_OUT (arg, volumes[DEV_LINE]);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_CD:
|
||||
return IOCTL_OUT (arg, volumes[DEV_CD]);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_VOLUME:
|
||||
return IOCTL_OUT (arg, volumes[DEV_VOL]);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_SYNTH:
|
||||
return IOCTL_OUT (arg, volumes[DEV_GF1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static struct mixer_operations ics2101_mixer_operations =
|
||||
{
|
||||
ics2101_mixer_ioctl
|
||||
};
|
||||
|
||||
long
|
||||
ics2101_mixer_init (long mem_start)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (num_mixers < MAX_MIXER_DEV)
|
||||
{
|
||||
mixer_devs[num_mixers++] = &ics2101_mixer_operations;
|
||||
|
||||
/*
|
||||
* Some GUS v3.7 cards had some channels flipped. Disable
|
||||
* the flipping feature if the model id is other than 5.
|
||||
*/
|
||||
|
||||
if (INB (u_MixSelect) != 5)
|
||||
{
|
||||
for (i = 0; i < ICS_MIXDEVS; i++)
|
||||
left_fix[i] = 1;
|
||||
for (i = 0; i < ICS_MIXDEVS; i++)
|
||||
right_fix[i] = 2;
|
||||
}
|
||||
|
||||
set_volumes (DEV_GF1, 0x5a5a);
|
||||
set_volumes (DEV_CD, 0x5a5a);
|
||||
set_volumes (DEV_MIC, 0x0000);
|
||||
set_volumes (DEV_LINE, 0x5a5a);
|
||||
set_volumes (DEV_VOL, 0x5a5a);
|
||||
set_volumes (DEV_UNUSED, 0x0000);
|
||||
}
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
27
sys/i386/isa/sound/local.h
Normal file
27
sys/i386/isa/sound/local.h
Normal file
@ -0,0 +1,27 @@
|
||||
/* Generated by configure. Don't edit!!!! */
|
||||
|
||||
#define KERNEL_SOUNDCARD
|
||||
#undef EXCLUDE_PAS
|
||||
#undef EXCLUDE_SB
|
||||
#undef EXCLUDE_ADLIB
|
||||
#undef EXCLUDE_GUS
|
||||
#define EXCLUDE_MPU401
|
||||
#define EXCLUDE_UART6850
|
||||
#define EXCLUDE_PSS
|
||||
#undef EXCLUDE_GUS16
|
||||
#undef EXCLUDE_GUSMAX
|
||||
#undef EXCLUDE_MSS
|
||||
#undef EXCLUDE_SBPRO
|
||||
#undef EXCLUDE_SB16
|
||||
#undef EXCLUDE_AUDIO
|
||||
#undef EXCLUDE_MIDI
|
||||
#undef EXCLUDE_YM3812
|
||||
#undef EXCLUDE_SEQUENCER
|
||||
|
||||
#define DSP_BUFFSIZE 32768
|
||||
#define SELECTED_SOUND_OPTIONS 0xffffff8f
|
||||
#define SOUND_VERSION_STRING "2.90-2"
|
||||
#define SOUND_CONFIG_DATE "Thu Sep 29 15:33:39 PDT 1994"
|
||||
#define SOUND_CONFIG_BY "swallace"
|
||||
#define SOUND_CONFIG_HOST "pal-r32-a07b.slip.nts.uci.edu"
|
||||
#define SOUND_CONFIG_DOMAIN ""
|
22
sys/i386/isa/sound/midi_ctrl.h
Normal file
22
sys/i386/isa/sound/midi_ctrl.h
Normal file
@ -0,0 +1,22 @@
|
||||
static unsigned char ctrl_def_values[128] =
|
||||
{
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 0 to 7 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 8 to 15 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 16 to 23 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 24 to 31 */
|
||||
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 32 to 39 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 40 to 47 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 48 to 55 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 56 to 63 */
|
||||
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 64 to 71 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 72 to 79 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 80 to 87 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 88 to 95 */
|
||||
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 96 to 103 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 104 to 111 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 112 to 119 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 120 to 127 */
|
||||
};
|
474
sys/i386/isa/sound/midi_synth.c
Normal file
474
sys/i386/isa/sound/midi_synth.c
Normal file
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* sound/midi_synth.c
|
||||
*
|
||||
* High level midi sequencer manager for dumb MIDI interfaces.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#define _MIDI_SYNTH_C_
|
||||
|
||||
DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
|
||||
|
||||
#include "midi_synth.h"
|
||||
|
||||
static int midi2synth[MAX_MIDI_DEV];
|
||||
static unsigned char prev_out_status[MAX_MIDI_DEV];
|
||||
|
||||
static void
|
||||
midi_outc (int midi_dev, int data)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
for (timeout = 0; timeout < 32000; timeout++)
|
||||
if (midi_devs[midi_dev]->putc (midi_dev, (unsigned char) (data & 0xff)))
|
||||
{
|
||||
if (data & 0x80) /*
|
||||
* Status byte
|
||||
*/
|
||||
prev_out_status[midi_dev] =
|
||||
(unsigned char) (data & 0xff); /*
|
||||
* Store for running status
|
||||
*/
|
||||
return; /*
|
||||
* Mission complete
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Sorry! No space on buffers.
|
||||
*/
|
||||
printk ("Midi send timed out\n");
|
||||
}
|
||||
|
||||
static int
|
||||
prefix_cmd (int midi_dev, unsigned char status)
|
||||
{
|
||||
if (midi_devs[midi_dev]->prefix_cmd == NULL)
|
||||
return 1;
|
||||
|
||||
return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
|
||||
}
|
||||
|
||||
static void
|
||||
midi_synth_input (int dev, unsigned char data)
|
||||
{
|
||||
int orig_dev;
|
||||
|
||||
if (dev < 0 || dev > num_synths)
|
||||
return;
|
||||
|
||||
if (data == 0xfe) /* Ignore active sensing */
|
||||
return;
|
||||
|
||||
orig_dev = midi2synth[dev];
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
midi_synth_output (int dev)
|
||||
{
|
||||
/*
|
||||
* Currently NOP
|
||||
*/
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_ioctl (int dev,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
/*
|
||||
* int orig_dev = synth_devs[dev]->midi_dev;
|
||||
*/
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
|
||||
case SNDCTL_SYNTH_INFO:
|
||||
IOCTL_TO_USER ((char *) arg, 0, synth_devs[dev]->info,
|
||||
sizeof (struct synth_info));
|
||||
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_SYNTH_MEMAVL:
|
||||
return 0x7fffffff;
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_kill_note (int dev, int channel, int note, int velocity)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int msg, chn;
|
||||
|
||||
if (note < 0 || note > 127)
|
||||
return 0;
|
||||
if (channel < 0 || channel > 15)
|
||||
return 0;
|
||||
if (velocity < 0)
|
||||
velocity = 0;
|
||||
if (velocity > 127)
|
||||
velocity = 127;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80))
|
||||
{ /*
|
||||
* Use running status
|
||||
*/
|
||||
if (!prefix_cmd (orig_dev, note))
|
||||
return 0;
|
||||
|
||||
midi_outc (orig_dev, note);
|
||||
|
||||
if (msg == 0x90) /*
|
||||
* Running status = Note on
|
||||
*/
|
||||
midi_outc (orig_dev, 0);/*
|
||||
* Note on with velocity 0 == note
|
||||
* off
|
||||
*/
|
||||
else
|
||||
midi_outc (orig_dev, velocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (velocity == 64)
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
|
||||
return 0;
|
||||
midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /*
|
||||
* Note on
|
||||
*/
|
||||
midi_outc (orig_dev, note);
|
||||
midi_outc (orig_dev, 0); /*
|
||||
* Zero G
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0x80 | (channel & 0x0f)))
|
||||
return 0;
|
||||
midi_outc (orig_dev, 0x80 | (channel & 0x0f)); /*
|
||||
* Note off
|
||||
*/
|
||||
midi_outc (orig_dev, note);
|
||||
midi_outc (orig_dev, velocity);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_set_instr (int dev, int channel, int instr_no)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
|
||||
if (instr_no < 0 || instr_no > 127)
|
||||
return 0;
|
||||
if (channel < 0 || channel > 15)
|
||||
return 0;
|
||||
|
||||
if (!prefix_cmd (orig_dev, 0xc0 | (channel & 0x0f)))
|
||||
return 0;
|
||||
midi_outc (orig_dev, 0xc0 | (channel & 0x0f)); /*
|
||||
* Program change
|
||||
*/
|
||||
midi_outc (orig_dev, instr_no);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_start_note (int dev, int channel, int note, int velocity)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int msg, chn;
|
||||
|
||||
if (note < 0 || note > 127)
|
||||
return 0;
|
||||
if (channel < 0 || channel > 15)
|
||||
return 0;
|
||||
if (velocity < 0)
|
||||
velocity = 0;
|
||||
if (velocity > 127)
|
||||
velocity = 127;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (chn == channel && msg == 0x90)
|
||||
{ /*
|
||||
* Use running status
|
||||
*/
|
||||
if (!prefix_cmd (orig_dev, note))
|
||||
return 0;
|
||||
midi_outc (orig_dev, note);
|
||||
midi_outc (orig_dev, velocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
|
||||
return 0;
|
||||
midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /*
|
||||
* Note on
|
||||
*/
|
||||
midi_outc (orig_dev, note);
|
||||
midi_outc (orig_dev, velocity);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_reset (int dev)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_open (int dev, int mode)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int err;
|
||||
|
||||
if (orig_dev < 0 || orig_dev > num_midis)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
midi2synth[orig_dev] = dev;
|
||||
prev_out_status[orig_dev] = 0;
|
||||
|
||||
if ((err = midi_devs[orig_dev]->open (orig_dev, mode,
|
||||
midi_synth_input, midi_synth_output)) < 0)
|
||||
return err;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_close (int dev)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
|
||||
/*
|
||||
* Shut up the synths by sending just single active sensing message.
|
||||
*/
|
||||
midi_devs[orig_dev]->putc (orig_dev, 0xfe);
|
||||
|
||||
midi_devs[orig_dev]->close (orig_dev);
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_hw_control (int dev, unsigned char *event)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
|
||||
int offs, int count, int pmgr_flag)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
|
||||
struct sysex_info sysex;
|
||||
int i;
|
||||
unsigned long left, src_offs, eox_seen = 0;
|
||||
int first_byte = 1;
|
||||
|
||||
if (!prefix_cmd (orig_dev, 0xf0))
|
||||
return 0;
|
||||
|
||||
if (format != SYSEX_PATCH)
|
||||
{
|
||||
printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format);
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
if (count < sizeof (struct sysex_info))
|
||||
{
|
||||
printk ("MIDI Error: Patch header too short\n");
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
count -= sizeof (struct sysex_info);
|
||||
|
||||
/*
|
||||
* Copy the header from user space but ignore the first bytes which have
|
||||
* been transferred already.
|
||||
*/
|
||||
|
||||
COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs);
|
||||
|
||||
if (count < sysex.len)
|
||||
{
|
||||
printk ("MIDI Warning: Sysex record too short (%d<%d)\n",
|
||||
count, (int) sysex.len);
|
||||
sysex.len = count;
|
||||
}
|
||||
|
||||
left = sysex.len;
|
||||
src_offs = 0;
|
||||
|
||||
RESET_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
|
||||
|
||||
for (i = 0; i < left && !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag); i++)
|
||||
{
|
||||
unsigned char data;
|
||||
|
||||
GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i);
|
||||
|
||||
if (first_byte && data != 0xf0)
|
||||
midi_outc (orig_dev, 0xf0); /* Sysex start */
|
||||
|
||||
eox_seen = (data == 0xf7);/*
|
||||
* Last byte was end of sysex
|
||||
*/
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
if (data != 0xf0) /*
|
||||
* Sysex start
|
||||
*/
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
|
||||
!PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag))
|
||||
DO_SLEEP (sysex_sleeper, sysex_sleep_flag, 1); /* Wait for timeout */
|
||||
|
||||
if (!first_byte && data & 0x80)
|
||||
return 0;
|
||||
first_byte = 0;
|
||||
}
|
||||
|
||||
if (!eox_seen)
|
||||
midi_outc (orig_dev, 0xf7);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_panning (int dev, int channel, int pressure)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_aftertouch (int dev, int channel, int pressure)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int msg, chn;
|
||||
|
||||
if (pressure < 0 || pressure > 127)
|
||||
return;
|
||||
if (channel < 0 || channel > 15)
|
||||
return;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (msg != 0xd0 || chn != channel) /*
|
||||
* Test for running status
|
||||
*/
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0xd0 | (channel & 0x0f)))
|
||||
return;
|
||||
midi_outc (orig_dev, 0xd0 | (channel & 0x0f)); /*
|
||||
* Channel pressure
|
||||
*/
|
||||
}
|
||||
else if (!prefix_cmd (orig_dev, pressure))
|
||||
return;
|
||||
midi_outc (orig_dev, pressure);
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_controller (int dev, int channel, int ctrl_num, int value)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int chn, msg;
|
||||
|
||||
if (ctrl_num < 1 || ctrl_num > 127)
|
||||
return; /* NOTE! Controller # 0 ignored */
|
||||
if (channel < 0 || channel > 15)
|
||||
return;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (msg != 0xb0 || chn != channel)
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f)))
|
||||
return;
|
||||
midi_outc (orig_dev, 0xb0 | (channel & 0x0f));
|
||||
}
|
||||
else if (!prefix_cmd (orig_dev, ctrl_num))
|
||||
return;
|
||||
|
||||
midi_outc (orig_dev, ctrl_num);
|
||||
midi_outc (orig_dev, value & 0x7f);
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_patchmgr (int dev, struct patmgr_info *rec)
|
||||
{
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_bender (int dev, int channel, int value)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int msg, prev_chn;
|
||||
|
||||
if (channel < 0 || channel > 15)
|
||||
return;
|
||||
|
||||
if (value < 0 || value > 16383)
|
||||
return;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
prev_chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (msg != 0xd0 || prev_chn != channel) /*
|
||||
* * Test for running status */
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f)))
|
||||
return;
|
||||
midi_outc (orig_dev, 0xe0 | (channel & 0x0f));
|
||||
}
|
||||
else if (!prefix_cmd (orig_dev, value & 0x7f))
|
||||
return;
|
||||
|
||||
midi_outc (orig_dev, value & 0x7f);
|
||||
midi_outc (orig_dev, (value >> 7) & 0x7f);
|
||||
}
|
||||
|
||||
#endif
|
45
sys/i386/isa/sound/midi_synth.h
Normal file
45
sys/i386/isa/sound/midi_synth.h
Normal file
@ -0,0 +1,45 @@
|
||||
int midi_synth_ioctl (int dev,
|
||||
unsigned int cmd, unsigned int arg);
|
||||
int midi_synth_kill_note (int dev, int channel, int note, int velocity);
|
||||
int midi_synth_set_instr (int dev, int channel, int instr_no);
|
||||
int midi_synth_start_note (int dev, int channel, int note, int volume);
|
||||
void midi_synth_reset (int dev);
|
||||
int midi_synth_open (int dev, int mode);
|
||||
void midi_synth_close (int dev);
|
||||
void midi_synth_hw_control (int dev, unsigned char *event);
|
||||
int midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
|
||||
int offs, int count, int pmgr_flag);
|
||||
void midi_synth_panning (int dev, int channel, int pressure);
|
||||
void midi_synth_aftertouch (int dev, int channel, int pressure);
|
||||
void midi_synth_controller (int dev, int channel, int ctrl_num, int value);
|
||||
int midi_synth_patchmgr (int dev, struct patmgr_info *rec);
|
||||
void midi_synth_bender (int dev, int chn, int value);
|
||||
|
||||
|
||||
#ifndef _MIDI_SYNTH_C_
|
||||
static struct synth_info std_synth_info =
|
||||
{MIDI_SYNTH_NAME, 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, MIDI_SYNTH_CAPS};
|
||||
|
||||
static struct synth_operations std_midi_synth =
|
||||
{
|
||||
&std_synth_info,
|
||||
0,
|
||||
SYNTH_TYPE_MIDI,
|
||||
0,
|
||||
midi_synth_open,
|
||||
midi_synth_close,
|
||||
midi_synth_ioctl,
|
||||
midi_synth_kill_note,
|
||||
midi_synth_start_note,
|
||||
midi_synth_set_instr,
|
||||
midi_synth_reset,
|
||||
midi_synth_hw_control,
|
||||
midi_synth_load_patch,
|
||||
midi_synth_aftertouch,
|
||||
midi_synth_controller,
|
||||
midi_synth_panning,
|
||||
NULL,
|
||||
midi_synth_patchmgr,
|
||||
midi_synth_bender
|
||||
};
|
||||
#endif
|
443
sys/i386/isa/sound/midibuf.c
Normal file
443
sys/i386/isa/sound/midibuf.c
Normal file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
* sound/midibuf.c
|
||||
*
|
||||
* Device file manager for /dev/midi#
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
/*
|
||||
* Don't make MAX_QUEUE_SIZE larger than 4000
|
||||
*/
|
||||
|
||||
#define MAX_QUEUE_SIZE 4000
|
||||
|
||||
DEFINE_WAIT_QUEUES (midi_sleeper[MAX_MIDI_DEV], midi_sleep_flag[MAX_MIDI_DEV]);
|
||||
DEFINE_WAIT_QUEUES (input_sleeper[MAX_MIDI_DEV], input_sleep_flag[MAX_MIDI_DEV]);
|
||||
|
||||
struct midi_buf
|
||||
{
|
||||
int len, head, tail;
|
||||
unsigned char queue[MAX_QUEUE_SIZE];
|
||||
};
|
||||
|
||||
struct midi_parms
|
||||
{
|
||||
int prech_timeout; /*
|
||||
* Timeout before the first ch
|
||||
*/
|
||||
};
|
||||
|
||||
static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] =
|
||||
{NULL};
|
||||
static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] =
|
||||
{NULL};
|
||||
static struct midi_parms parms[MAX_MIDI_DEV];
|
||||
|
||||
static void midi_poll (unsigned long dummy);
|
||||
|
||||
DEFINE_TIMER (poll_timer, midi_poll);
|
||||
static volatile int open_devs = 0;
|
||||
|
||||
#define DATA_AVAIL(q) (q->len)
|
||||
#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
|
||||
|
||||
#define QUEUE_BYTE(q, data) \
|
||||
if (SPACE_AVAIL(q)) \
|
||||
{ \
|
||||
unsigned long flags; \
|
||||
DISABLE_INTR(flags); \
|
||||
q->queue[q->tail] = (data); \
|
||||
q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
|
||||
RESTORE_INTR(flags); \
|
||||
}
|
||||
|
||||
#define REMOVE_BYTE(q, data) \
|
||||
if (DATA_AVAIL(q)) \
|
||||
{ \
|
||||
unsigned long flags; \
|
||||
DISABLE_INTR(flags); \
|
||||
data = q->queue[q->head]; \
|
||||
q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
|
||||
RESTORE_INTR(flags); \
|
||||
}
|
||||
|
||||
void
|
||||
drain_midi_queue (int dev)
|
||||
{
|
||||
|
||||
/*
|
||||
* Give the Midi driver time to drain its output queues
|
||||
*/
|
||||
|
||||
if (midi_devs[dev]->buffer_status != NULL)
|
||||
while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
|
||||
midi_devs[dev]->buffer_status (dev))
|
||||
DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], HZ / 10);
|
||||
}
|
||||
|
||||
static void
|
||||
midi_input_intr (int dev, unsigned char data)
|
||||
{
|
||||
if (midi_in_buf[dev] == NULL)
|
||||
return;
|
||||
|
||||
if (data == 0xfe) /*
|
||||
* Active sensing
|
||||
*/
|
||||
return; /*
|
||||
* Ignore
|
||||
*/
|
||||
|
||||
if (SPACE_AVAIL (midi_in_buf[dev]))
|
||||
{
|
||||
QUEUE_BYTE (midi_in_buf[dev], data);
|
||||
if (SOMEONE_WAITING (input_sleeper[dev], input_sleep_flag[dev]))
|
||||
WAKE_UP (input_sleeper[dev], input_sleep_flag[dev]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
midi_output_intr (int dev)
|
||||
{
|
||||
/*
|
||||
* Currently NOP
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
midi_poll (unsigned long dummy)
|
||||
{
|
||||
unsigned long flags;
|
||||
int dev;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (open_devs)
|
||||
{
|
||||
for (dev = 0; dev < num_midis; dev++)
|
||||
if (midi_out_buf[dev] != NULL)
|
||||
{
|
||||
while (DATA_AVAIL (midi_out_buf[dev]) &&
|
||||
midi_devs[dev]->putc (dev,
|
||||
midi_out_buf[dev]->queue[midi_out_buf[dev]->head]))
|
||||
{
|
||||
midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
|
||||
midi_out_buf[dev]->len--;
|
||||
}
|
||||
|
||||
if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&
|
||||
SOMEONE_WAITING (midi_sleeper[dev], midi_sleep_flag[dev]))
|
||||
WAKE_UP (midi_sleeper[dev], midi_sleep_flag[dev]);
|
||||
}
|
||||
ACTIVATE_TIMER (poll_timer, midi_poll, 1); /*
|
||||
* Come back later
|
||||
*/
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
int
|
||||
MIDIbuf_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
int mode, err;
|
||||
unsigned long flags;
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
|
||||
if (num_midis > MAX_MIDI_DEV)
|
||||
{
|
||||
printk ("Sound: FATAL ERROR: Too many midi interfaces\n");
|
||||
num_midis = MAX_MIDI_DEV;
|
||||
}
|
||||
|
||||
if (dev < 0 || dev >= num_midis)
|
||||
{
|
||||
printk ("Sound: Nonexistent MIDI interface %d\n", dev);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupts disabled. Be careful
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if ((err = midi_devs[dev]->open (dev, mode,
|
||||
midi_input_intr, midi_output_intr)) < 0)
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
parms[dev].prech_timeout = 0;
|
||||
|
||||
RESET_WAIT_QUEUE (midi_sleeper[dev], midi_sleep_flag[dev]);
|
||||
RESET_WAIT_QUEUE (input_sleeper[dev], input_sleep_flag[dev]);
|
||||
|
||||
midi_in_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));
|
||||
|
||||
if (midi_in_buf[dev] == NULL)
|
||||
{
|
||||
printk ("midi: Can't allocate buffer\n");
|
||||
midi_devs[dev]->close (dev);
|
||||
RESTORE_INTR (flags);
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
|
||||
|
||||
midi_out_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf));
|
||||
|
||||
if (midi_out_buf[dev] == NULL)
|
||||
{
|
||||
printk ("midi: Can't allocate buffer\n");
|
||||
midi_devs[dev]->close (dev);
|
||||
KERNEL_FREE (midi_in_buf[dev]);
|
||||
midi_in_buf[dev] = NULL;
|
||||
RESTORE_INTR (flags);
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
|
||||
if (!open_devs)
|
||||
ACTIVATE_TIMER (poll_timer, midi_poll, 1); /*
|
||||
* Come back later
|
||||
*/
|
||||
open_devs++;
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
MIDIbuf_release (int dev, struct fileinfo *file)
|
||||
{
|
||||
int mode;
|
||||
unsigned long flags;
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
/*
|
||||
* Wait until the queue is empty
|
||||
*/
|
||||
|
||||
if (mode != OPEN_READ)
|
||||
{
|
||||
midi_devs[dev]->putc (dev, 0xfe); /*
|
||||
* Active sensing to shut the
|
||||
* devices
|
||||
*/
|
||||
|
||||
while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
|
||||
DATA_AVAIL (midi_out_buf[dev]))
|
||||
DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0); /*
|
||||
* Sync
|
||||
*/
|
||||
|
||||
drain_midi_queue (dev); /*
|
||||
* Ensure the output queues are empty
|
||||
*/
|
||||
}
|
||||
|
||||
midi_devs[dev]->close (dev);
|
||||
KERNEL_FREE (midi_in_buf[dev]);
|
||||
KERNEL_FREE (midi_out_buf[dev]);
|
||||
midi_in_buf[dev] = NULL;
|
||||
midi_out_buf[dev] = NULL;
|
||||
open_devs--;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
int
|
||||
MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
unsigned long flags;
|
||||
int c, n, i;
|
||||
unsigned char tmp_data;
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
c = 0;
|
||||
|
||||
while (c < count)
|
||||
{
|
||||
n = SPACE_AVAIL (midi_out_buf[dev]);
|
||||
|
||||
if (n == 0) /*
|
||||
* No space just now. We have to sleep
|
||||
*/
|
||||
{
|
||||
DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0);
|
||||
if (PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]))
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
return RET_ERROR (EINTR);
|
||||
}
|
||||
|
||||
n = SPACE_AVAIL (midi_out_buf[dev]);
|
||||
}
|
||||
|
||||
if (n > (count - c))
|
||||
n = count - c;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
COPY_FROM_USER (&tmp_data, buf, c, 1);
|
||||
QUEUE_BYTE (midi_out_buf[dev], tmp_data);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
int n, c = 0;
|
||||
unsigned long flags;
|
||||
unsigned char tmp_data;
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (!DATA_AVAIL (midi_in_buf[dev])) /*
|
||||
* No data yet, wait
|
||||
*/
|
||||
{
|
||||
DO_SLEEP (input_sleeper[dev], input_sleep_flag[dev],
|
||||
parms[dev].prech_timeout);
|
||||
if (PROCESS_ABORTING (input_sleeper[dev], input_sleep_flag[dev]))
|
||||
c = RET_ERROR (EINTR); /*
|
||||
* The user is getting restless
|
||||
*/
|
||||
}
|
||||
|
||||
if (c == 0 && DATA_AVAIL (midi_in_buf[dev])) /*
|
||||
* Got some bytes
|
||||
*/
|
||||
{
|
||||
n = DATA_AVAIL (midi_in_buf[dev]);
|
||||
if (n > count)
|
||||
n = count;
|
||||
c = 0;
|
||||
|
||||
while (c < n)
|
||||
{
|
||||
REMOVE_BYTE (midi_in_buf[dev], tmp_data);
|
||||
COPY_TO_USER (buf, c, &tmp_data, 1);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int
|
||||
MIDIbuf_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
int val;
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
|
||||
case SNDCTL_MIDI_PRETIME:
|
||||
val = IOCTL_IN (arg);
|
||||
if (val < 0)
|
||||
val = 0;
|
||||
|
||||
val = (HZ * val) / 10;
|
||||
parms[dev].prech_timeout = val;
|
||||
return IOCTL_OUT (arg, val);
|
||||
break;
|
||||
|
||||
default:
|
||||
return midi_devs[dev]->ioctl (dev, cmd, arg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ALLOW_SELECT
|
||||
int
|
||||
MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
|
||||
{
|
||||
dev = dev >> 4;
|
||||
|
||||
switch (sel_type)
|
||||
{
|
||||
case SEL_IN:
|
||||
if (!DATA_AVAIL (midi_in_buf[dev]))
|
||||
{
|
||||
input_sleep_flag[dev].mode = WK_SLEEP;
|
||||
select_wait (&input_sleeper[dev], wait);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case SEL_OUT:
|
||||
if (SPACE_AVAIL (midi_out_buf[dev]))
|
||||
{
|
||||
midi_sleep_flag[dev].mode = WK_SLEEP;
|
||||
select_wait (&midi_sleeper[dev], wait);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case SEL_EX:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ALLOW_SELECT */
|
||||
|
||||
long
|
||||
MIDIbuf_init (long mem_start)
|
||||
{
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
1722
sys/i386/isa/sound/mpu401.c
Normal file
1722
sys/i386/isa/sound/mpu401.c
Normal file
File diff suppressed because it is too large
Load Diff
1225
sys/i386/isa/sound/opl3.c
Normal file
1225
sys/i386/isa/sound/opl3.c
Normal file
File diff suppressed because it is too large
Load Diff
260
sys/i386/isa/sound/opl3.h
Normal file
260
sys/i386/isa/sound/opl3.h
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* opl3.h - Definitions of the OPL-3 registers
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* The OPL-3 mode is switched on by writing 0x01, to the offset 5
|
||||
* of the right side.
|
||||
*
|
||||
* Another special register at the right side is at offset 4. It contains
|
||||
* a bit mask defining which voices are used as 4 OP voices.
|
||||
*
|
||||
* The percussive mode is implemented in the left side only.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* For example setting the rightmost bit (0x01) changes the
|
||||
* first voice on the right side to the 4 OP mode. The fourth
|
||||
* 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
|
||||
* be connected the left, right or both stereo channels. It can
|
||||
* even be left unconnected. This works with 4 OP voices also.
|
||||
*
|
||||
* The stereo connection bits are located in the FEEDBACK_CONNECTION
|
||||
* register of the voice (0xC0-0xC8). In 4 OP voices these bits are
|
||||
* in the second half of the voice.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Register numbers for the global registers
|
||||
*/
|
||||
|
||||
#define TEST_REGISTER 0x01
|
||||
#define ENABLE_WAVE_SELECT 0x20
|
||||
|
||||
#define TIMER1_REGISTER 0x02
|
||||
#define TIMER2_REGISTER 0x03
|
||||
#define TIMER_CONTROL_REGISTER 0x04 /* Left side */
|
||||
#define IRQ_RESET 0x80
|
||||
#define TIMER1_MASK 0x40
|
||||
#define TIMER2_MASK 0x20
|
||||
#define TIMER1_START 0x01
|
||||
#define TIMER2_START 0x02
|
||||
|
||||
#define CONNECTION_SELECT_REGISTER 0x04 /* Right side */
|
||||
#define RIGHT_4OP_0 0x01
|
||||
#define RIGHT_4OP_1 0x02
|
||||
#define RIGHT_4OP_2 0x04
|
||||
#define LEFT_4OP_0 0x08
|
||||
#define LEFT_4OP_1 0x10
|
||||
#define LEFT_4OP_2 0x20
|
||||
|
||||
#define OPL3_MODE_REGISTER 0x05 /* Right side */
|
||||
#define OPL3_ENABLE 0x01
|
||||
|
||||
#define KBD_SPLIT_REGISTER 0x08 /* Left side */
|
||||
#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */
|
||||
#define KEYBOARD_SPLIT 0x40
|
||||
|
||||
#define PERCUSSION_REGISTER 0xbd /* Left side only */
|
||||
#define TREMOLO_DEPTH 0x80
|
||||
#define VIBRATO_DEPTH 0x40
|
||||
#define PERCUSSION_ENABLE 0x20
|
||||
#define BASSDRUM_ON 0x10
|
||||
#define SNAREDRUM_ON 0x08
|
||||
#define TOMTOM_ON 0x04
|
||||
#define CYMBAL_ON 0x02
|
||||
#define HIHAT_ON 0x01
|
||||
|
||||
/*
|
||||
* Offsets to the register banks for operators. To get the
|
||||
* register number just add the operator offset to the bank offset
|
||||
*
|
||||
* AM/VIB/EG/KSR/Multiple (0x20 to 0x35)
|
||||
*/
|
||||
#define AM_VIB 0x20
|
||||
#define TREMOLO_ON 0x80
|
||||
#define VIBRATO_ON 0x40
|
||||
#define SUSTAIN_ON 0x20
|
||||
#define KSR 0x10 /* Key scaling rate */
|
||||
#define MULTIPLE_MASK 0x0f /* Frequency multiplier */
|
||||
|
||||
/*
|
||||
* KSL/Total level (0x40 to 0x55)
|
||||
*/
|
||||
#define KSL_LEVEL 0x40
|
||||
#define KSL_MASK 0xc0 /* Envelope scaling bits */
|
||||
#define TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */
|
||||
|
||||
/*
|
||||
* Attack / Decay rate (0x60 to 0x75)
|
||||
*/
|
||||
#define ATTACK_DECAY 0x60
|
||||
#define ATTACK_MASK 0xf0
|
||||
#define DECAY_MASK 0x0f
|
||||
|
||||
/*
|
||||
* Sustain level / Release rate (0x80 to 0x95)
|
||||
*/
|
||||
#define SUSTAIN_RELEASE 0x80
|
||||
#define SUSTAIN_MASK 0xf0
|
||||
#define RELEASE_MASK 0x0f
|
||||
|
||||
/*
|
||||
* Wave select (0xE0 to 0xF5)
|
||||
*/
|
||||
#define WAVE_SELECT 0xe0
|
||||
|
||||
/*
|
||||
* Offsets to the register banks for voices. Just add to the
|
||||
* voice number to get the register number.
|
||||
*
|
||||
* F-Number low bits (0xA0 to 0xA8).
|
||||
*/
|
||||
#define FNUM_LOW 0xa0
|
||||
|
||||
/*
|
||||
* F-number high bits / Key on / Block (octave) (0xB0 to 0xB8)
|
||||
*/
|
||||
#define KEYON_BLOCK 0xb0
|
||||
#define KEYON_BIT 0x20
|
||||
#define BLOCKNUM_MASK 0x1c
|
||||
#define FNUM_HIGH_MASK 0x03
|
||||
|
||||
/*
|
||||
* Feedback / Connection (0xc0 to 0xc8)
|
||||
*
|
||||
* These registers have two new bits when the OPL-3 mode
|
||||
* is selected. These bits controls connecting the voice
|
||||
* to the stereo channels. For 4 OP voices this bit is
|
||||
* defined in the second half of the voice (add 3 to the
|
||||
* register offset).
|
||||
*
|
||||
* For 4 OP voices the connection bit is used in the
|
||||
* both halfs (gives 4 ways to connect the operators).
|
||||
*/
|
||||
#define FEEDBACK_CONNECTION 0xc0
|
||||
#define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */
|
||||
#define CONNECTION_BIT 0x01
|
||||
/*
|
||||
* In the 4 OP mode there is four possible configurations how the
|
||||
* operators can be connected together (in 2 OP modes there is just
|
||||
* AM or FM). The 4 OP connection mode is defined by the rightmost
|
||||
* bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halfs.
|
||||
*
|
||||
* First half Second half Mode
|
||||
*
|
||||
* +---+
|
||||
* v |
|
||||
* 0 0 >+-1-+--2--3--4-->
|
||||
*
|
||||
*
|
||||
*
|
||||
* +---+
|
||||
* | |
|
||||
* 0 1 >+-1-+--2-+
|
||||
* |->
|
||||
* >--3----4-+
|
||||
*
|
||||
* +---+
|
||||
* | |
|
||||
* 1 0 >+-1-+-----+
|
||||
* |->
|
||||
* >--2--3--4-+
|
||||
*
|
||||
* +---+
|
||||
* | |
|
||||
* 1 1 >+-1-+--+
|
||||
* |
|
||||
* >--2--3-+->
|
||||
* |
|
||||
* >--4----+
|
||||
*/
|
||||
#define STEREO_BITS 0x30 /* OPL-3 only */
|
||||
#define VOICE_TO_LEFT 0x10
|
||||
#define VOICE_TO_RIGHT 0x20
|
||||
|
||||
/*
|
||||
* Definition table for the physical voices
|
||||
*/
|
||||
|
||||
struct physical_voice_info {
|
||||
unsigned char voice_num;
|
||||
unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */
|
||||
unsigned short ioaddr; /* I/O port (left or right side) */
|
||||
unsigned char op[4]; /* Operator offsets */
|
||||
};
|
||||
|
||||
/*
|
||||
* There is 18 possible 2 OP voices
|
||||
* (9 in the left and 9 in the right).
|
||||
* The first OP is the modulator and 2nd is the carrier.
|
||||
*
|
||||
* The first three voices in the both sides may be connected
|
||||
* with another voice to a 4 OP voice. For example voice 0
|
||||
* can be connected with voice 3. The operators of voice 3 are
|
||||
* used as operators 3 and 4 of the new 4 OP voice.
|
||||
* In this case the 2 OP voice number 0 is the 'first half' and
|
||||
* voice 3 is the second.
|
||||
*/
|
||||
|
||||
#define USE_LEFT 0
|
||||
#define USE_RIGHT 1
|
||||
|
||||
static struct physical_voice_info physical_voices[18] =
|
||||
{
|
||||
/* No Mode Side OP1 OP2 OP3 OP4 */
|
||||
/* --------------------------------------------------- */
|
||||
{ 0, 2, USE_LEFT, {0x00, 0x03, 0x08, 0x0b}},
|
||||
{ 1, 2, USE_LEFT, {0x01, 0x04, 0x09, 0x0c}},
|
||||
{ 2, 2, USE_LEFT, {0x02, 0x05, 0x0a, 0x0d}},
|
||||
|
||||
{ 3, 2, USE_LEFT, {0x08, 0x0b, 0x00, 0x00}},
|
||||
{ 4, 2, USE_LEFT, {0x09, 0x0c, 0x00, 0x00}},
|
||||
{ 5, 2, USE_LEFT, {0x0a, 0x0d, 0x00, 0x00}},
|
||||
|
||||
{ 6, 2, USE_LEFT, {0x10, 0x13, 0x00, 0x00}}, /* Used by percussive voices */
|
||||
{ 7, 2, USE_LEFT, {0x11, 0x14, 0x00, 0x00}}, /* if the percussive mode */
|
||||
{ 8, 2, USE_LEFT, {0x12, 0x15, 0x00, 0x00}}, /* is selected */
|
||||
|
||||
{ 0, 2, USE_RIGHT, {0x00, 0x03, 0x08, 0x0b}},
|
||||
{ 1, 2, USE_RIGHT, {0x01, 0x04, 0x09, 0x0c}},
|
||||
{ 2, 2, USE_RIGHT, {0x02, 0x05, 0x0a, 0x0d}},
|
||||
|
||||
{ 3, 2, USE_RIGHT, {0x08, 0x0b, 0x00, 0x00}},
|
||||
{ 4, 2, USE_RIGHT, {0x09, 0x0c, 0x00, 0x00}},
|
||||
{ 5, 2, USE_RIGHT, {0x0a, 0x0d, 0x00, 0x00}},
|
||||
|
||||
{ 6, 2, USE_RIGHT, {0x10, 0x13, 0x00, 0x00}},
|
||||
{ 7, 2, USE_RIGHT, {0x11, 0x14, 0x00, 0x00}},
|
||||
{ 8, 2, USE_RIGHT, {0x12, 0x15, 0x00, 0x00}}
|
||||
};
|
306
sys/i386/isa/sound/os.h
Normal file
306
sys/i386/isa/sound/os.h
Normal file
@ -0,0 +1,306 @@
|
||||
#ifndef _OS_H_
|
||||
#define _OS_H_
|
||||
/*
|
||||
* OS specific settings for 386BSD
|
||||
*
|
||||
* This chould be used as an example when porting the driver to a new
|
||||
* operating systems.
|
||||
*
|
||||
* What you should do is to rewrite the soundcard.c and os.h (this file).
|
||||
* You should create a new subdirectory and put these two files there.
|
||||
* In addition you have to do a makefile.<OS>.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Insert here the includes required by your kernel.
|
||||
*/
|
||||
|
||||
#include "param.h"
|
||||
#include "systm.h"
|
||||
#include "ioctl.h"
|
||||
#include "tty.h"
|
||||
#include "proc.h"
|
||||
#include "user.h"
|
||||
#include "conf.h"
|
||||
#include "file.h"
|
||||
#include "uio.h"
|
||||
/* #include "kernel.h" */
|
||||
#include "syslog.h"
|
||||
#include "errno.h"
|
||||
#include "malloc.h"
|
||||
#include "buf.h"
|
||||
#include "i386/isa/isa_device.h"
|
||||
|
||||
/* These few lines are used by 386BSD (only??). */
|
||||
|
||||
#if NSND > 0
|
||||
#define KERNEL_SOUNDCARD
|
||||
#else
|
||||
#undef KERNEL_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
|
||||
#define SHORT_BANNERS
|
||||
|
||||
/* The soundcard.h could be in a nonstandard place so inclyde it here. */
|
||||
#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
|
||||
* assumed about this structure, the driver uses set of macros for
|
||||
* 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
|
||||
* 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
|
||||
* BSD passes the offset info in the uio structure. It could be usefull
|
||||
* if these macros verify that the offs parameter and the value in
|
||||
* the snd_rw_buf structure are equal.
|
||||
*/
|
||||
typedef struct uio snd_rw_buf;
|
||||
|
||||
/*
|
||||
* Move bytes from the buffer which the application given in a
|
||||
* write() call.
|
||||
* offs is position relative to the beginning of the buffer in
|
||||
* user space. The count is number of bytes to be moved.
|
||||
*/
|
||||
#define COPY_FROM_USER(target, source, offs, count) \
|
||||
if (uiomove(target, count, source)) { \
|
||||
printf ("sb: Bad copyin()!\n"); \
|
||||
} else
|
||||
/* Like COPY_FOM_USER but for writes. */
|
||||
#define COPY_TO_USER(target, offs, source, count) \
|
||||
if (uiomove(source, count, target)) { \
|
||||
printf ("sb: Bad copyout()!\n"); \
|
||||
} else
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
#define GET_BYTE_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 1, addr);}
|
||||
#define GET_SHORT_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 2, addr);}
|
||||
#define GET_WORD_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 4, addr);}
|
||||
#define PUT_WORD_TO_USER(addr, offs, data) {uiomove((char*)&(data), 4, addr);}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 386bsd the data is already moved to the kernel space. The following
|
||||
* macros should handle the difference.
|
||||
*/
|
||||
|
||||
/*
|
||||
* IOCTL_FROM_USER is used to copy a record pointed by the argument to
|
||||
* a buffer in the kernel space. On 386bsd it can be done just by calling
|
||||
* memcpy. With Linux a memcpy_from_fs should be called instead.
|
||||
* Parameters of the following macros are like in the COPY_*_USER macros.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When the ioctl argument points to a record or array (longer than 32 bits),
|
||||
* the macros IOCTL_*_USER are used. It's assumed that the source and target
|
||||
* parameters are direct memory addresses.
|
||||
*/
|
||||
#define IOCTL_FROM_USER(target, source, offs, count) {memcpy(target, &((source)[offs]), count);}
|
||||
#define IOCTL_TO_USER(target, offs, source, count) {memcpy(&((target)[offs]), source, count);}
|
||||
/* The following macros are used if the ioctl argument points to 32 bit int */
|
||||
#define IOCTL_IN(arg) (*(int*)arg)
|
||||
#define IOCTL_OUT(arg, ret) *(int*)arg = ret
|
||||
|
||||
/*
|
||||
* When the driver displays something to the console, printk() will be called.
|
||||
* The name can be changed here.
|
||||
*/
|
||||
#define printk printf
|
||||
|
||||
/*
|
||||
* The following macros define an interface to the process management.
|
||||
*/
|
||||
|
||||
struct snd_wait {
|
||||
int mode; int aborting;
|
||||
};
|
||||
|
||||
/*
|
||||
* DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define
|
||||
* a structure which can be passed as a parameter to a sleep(). The second
|
||||
* parameter is name of a flag variable (must be defined as int).
|
||||
*/
|
||||
#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; \
|
||||
static volatile struct snd_wait flag = {0}
|
||||
/* Like the above but defines an array of wait queues and flags */
|
||||
#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; \
|
||||
static volatile struct snd_wait flag = {{0}}
|
||||
|
||||
#define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;}
|
||||
#define SET_ABORT_FLAG(q, f) f.aborting = 1
|
||||
#define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT)
|
||||
#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
|
||||
/*
|
||||
* This driver handles interrupts little bit nonstandard way. The following
|
||||
* macro is used to test if the current process has received a signal which
|
||||
* 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 386BSD.
|
||||
*/
|
||||
#define PROCESS_ABORTING(q, f) (f.aborting | curproc->p_sig)
|
||||
|
||||
/*
|
||||
* The following macro calls sleep. It should be implemented such that
|
||||
* the process is resumed if it receives a signal. The following is propably
|
||||
* not the way how it should be done on 386bsd.
|
||||
* The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE(),
|
||||
* 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) \
|
||||
{ \
|
||||
int flag, chn; \
|
||||
f.mode = WK_SLEEP; \
|
||||
q = &chn; \
|
||||
flag=tsleep(&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(q);}
|
||||
|
||||
/*
|
||||
* Timing macros. This driver assumes that there is a timer running in the
|
||||
* kernel. The timer should return a value which is increased once at every
|
||||
* timer tick. The macro HZ should return the number of such ticks/sec.
|
||||
*/
|
||||
|
||||
#ifndef HZ
|
||||
extern int hz;
|
||||
#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...
|
||||
*
|
||||
*/
|
||||
unsigned long get_time(void);
|
||||
#define GET_TIME() get_time()
|
||||
/*#define GET_TIME() (lbolt) /* Returns current time (1/HZ secs since boot) */
|
||||
|
||||
/*
|
||||
* The following three macros are called before and after atomic
|
||||
* code sequences. The flags parameter has always type of unsigned long.
|
||||
* The macro DISABLE_INTR() should ensure that all interrupts which
|
||||
* may invoke any part of the driver (timer, soundcard interrupts) are
|
||||
* disabled.
|
||||
* RESTORE_INTR() should return the interrupt status back to the
|
||||
* state when DISABLE_INTR() was called. The flags parameter is
|
||||
* a variable which can carry 32 bits of state information between
|
||||
* DISABLE_INTR() and RESTORE_INTR() calls.
|
||||
*/
|
||||
#define DISABLE_INTR(flags) flags = splhigh()
|
||||
#define RESTORE_INTR(flags) splx(flags)
|
||||
|
||||
/*
|
||||
* INB() and OUTB() should be obvious. NOTE! The order of
|
||||
* paratemeters of OUTB() is different than on some other
|
||||
* operating systems.
|
||||
*/
|
||||
|
||||
#define INB inb
|
||||
/*
|
||||
* The outb(0, 0x80) is just for slowdown. It's bit unsafe since
|
||||
* this address could be used for something usefull.
|
||||
*/
|
||||
#define OUTB(addr, data) {outb(data, addr);outb(0, 0x80);}
|
||||
|
||||
/* memcpy() was not defined og 386bsd. Lets define it here */
|
||||
#define memcpy(d, s, c) bcopy(s, d, c)
|
||||
|
||||
/*
|
||||
* When a error (such as EINVAL) is returned by a function,
|
||||
* the following macro is used. The driver assumes that a
|
||||
* error is signalled by returning a negative value.
|
||||
*/
|
||||
|
||||
#define RET_ERROR(err) -(err)
|
||||
|
||||
/*
|
||||
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
|
||||
page level memory allocation, 4K can be safely used as the size
|
||||
(the nbytes parameter can be ignored).
|
||||
*/
|
||||
#define KERNEL_MALLOC(nbytes) malloc(nbytes, M_TEMP, M_WAITOK)
|
||||
#define KERNEL_FREE(addr) free(addr, M_TEMP)
|
||||
|
||||
/*
|
||||
* The macro PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr)
|
||||
* returns size bytes of
|
||||
* (kernel virtual) memory which will never get freed by the driver.
|
||||
* This macro is called only during boot. The linux_ptr is a linux specific
|
||||
* parameter which should be ignored in other operating systems.
|
||||
* The mem_ptr is a pointer variable where the macro assigns pointer to the
|
||||
* memory area. The type is the type of the mem_ptr.
|
||||
*/
|
||||
#define PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) \
|
||||
{mem_ptr = (typecast)malloc(size, M_DEVBUF, M_NOWAIT); \
|
||||
if (!mem_ptr)panic("SOUND: Cannot allocate memory\n");}
|
||||
|
||||
/*
|
||||
* The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if
|
||||
* required. The name is the variable/name to be used and the proc is
|
||||
* the procedure to be called when the timer expires.
|
||||
*/
|
||||
|
||||
#define DEFINE_TIMER(name, proc)
|
||||
|
||||
/*
|
||||
* The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
|
||||
*/
|
||||
|
||||
#define ACTIVATE_TIMER(name, proc, time) \
|
||||
timeout(proc, 0, time);
|
||||
/*
|
||||
* The rest of this file is not complete yet. The functions using these
|
||||
* macros will not work
|
||||
*/
|
||||
#define ALLOC_DMA_CHN(chn) (0)
|
||||
#define RELEASE_DMA_CHN(chn) (0)
|
||||
#define DMA_MODE_READ 0
|
||||
#define DMA_MODE_WRITE 1
|
||||
#define RELEASE_IRQ(irq_no)
|
||||
|
||||
#endif
|
||||
#endif
|
250
sys/i386/isa/sound/pas.h
Normal file
250
sys/i386/isa/sound/pas.h
Normal file
@ -0,0 +1,250 @@
|
||||
/* */
|
||||
/* Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards. */
|
||||
/* */
|
||||
/* Feel free to use this header file in any application you create that has support for the Media Vision */
|
||||
/* Pro AudioSpectrum second generation sound cards. Other uses prohibited without prior permission. */
|
||||
/* */
|
||||
/* - cmetz@thor.tjhsst.edu */
|
||||
/* */
|
||||
/* Notes: */
|
||||
/* */
|
||||
/* * All of these ports go into the MVD101 multimedia controller chip, which then signals the other chips to do */
|
||||
/* the actual work. Many ports like the FM ones functionally attach directly to the destination chip though */
|
||||
/* they don't actually have a direct connection. */
|
||||
/* */
|
||||
/* * The PAS2 series cards have an MVD101 multimedia controller chip, the original PAS cards don't. The original */
|
||||
/* PAS cards are pretty defunct now, so no attempt is made here to support them. */
|
||||
/* */
|
||||
/* * The PAS2 series cards are all really different at the hardware level, though the MVD101 hides some of the */
|
||||
/* incompatibilities, there still are differences that need to be accounted for. */
|
||||
/* */
|
||||
/* Card CD-ROM interface PCM chip Mixer chip FM chip */
|
||||
/* PAS Plus Sony proprietary (Crystal?) 8-bit DAC National OPL3 */
|
||||
/* PAS 16 Zilog SCSI MVA416 16-bit Codec MVA508 OPL3 */
|
||||
/* CDPC Sony proprietary Sony 16-bit Codec National OPL3 */
|
||||
/* Fusion CD 16 Sony proprietary MVA416 16-bit Codec MVA508 OPL3 */
|
||||
/* Fusion CD Sony proprietary (Crystal?) 8-bit DAC National OPL3 */
|
||||
/* */
|
||||
#define PAS_DEFAULT_BASE 0x388
|
||||
|
||||
/* Symbolic Name Value R W Subsystem Description */
|
||||
#define SPEAKER_CONTROL 0x61 /* W PC speaker Control register */
|
||||
#define SPEAKER_CONTROL_GHOST 0x738B /* R W PC speaker Control ghost register */
|
||||
#define SPEAKER_TIMER_CONTROL 0x43 /* W PC speaker Timer control register */
|
||||
#define SPEAKER_TIMER_CONTROL_GHOST 0x778B /* R W PC speaker Timer control register ghost */
|
||||
#define SPEAKER_TIMER_DATA 0x42 /* W PC speaker Timer data register */
|
||||
#define SPEAKER_TIMER_DATA_GHOST 0x138A /* R W PC speaker Timer data register ghost */
|
||||
|
||||
#define WARM_BOOT 0x41 /* W Control Used to detect system warm boot */
|
||||
#define WARM_BOOT_GHOST 0x7789 /* ? W Control Use to get the card to fake warm boot */
|
||||
#define MASTER_DECODE 0x9A01 /* W Control Address >> 2 of card base address */
|
||||
#define PRESCALE_DIVIDER 0xBF8A /* R W PCM Ration between Codec clock and master clock */
|
||||
#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 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_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 */
|
||||
#define S_C_1_FORCE_EXT_RESET 0x40 /* R W Control Force external reset */
|
||||
#define S_C_1_FORCE_INT_RESET 0x80 /* R W Control Force internal reset */
|
||||
#define SYSTEM_CONFIGURATION_2 0x8389 /* R W Control */
|
||||
#define S_C_2_PCM_OVERSAMPLING 0x03 /* R W PCM 00=0x, 01=2x, 10=4x, 11=reserved */
|
||||
#define S_C_2_PCM_16_BIT 0x04 /* R W PCM 1=16-bit, 0=8-bit samples */
|
||||
#define SYSTEM_CONFIGURATION_3 0x838A /* R W Control */
|
||||
#define S_C_3_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=use 1.008Mhz clock for PCM, 0=don't */
|
||||
#define SYSTEM_CONFIGURATION_4 0x838B /* R W Control CD-ROM interface controls */
|
||||
|
||||
#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 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 */
|
||||
#define I_C_3_PCM_IRQ_DISABLED 0x00 /* R W PCM PCM IRQ disabled */
|
||||
|
||||
#define COMPATIBILITY_ENABLE 0xF788 /* R W Control */
|
||||
#define C_E_MPU401_ENABLE 0x01 /* R W MIDI 1=enable, 0=disable MPU401 MIDI emulation */
|
||||
#define C_E_SB_ENABLE 0x02 /* R W PCM 1=enable, 0=disable Sound Blaster emulation */
|
||||
#define C_E_SB_ACTIVE 0x04 /* R PCM "Sound Blaster Interrupt active" */
|
||||
#define C_E_MPU401_ACTIVE 0x08 /* R MIDI "MPU UART mode active" */
|
||||
#define C_E_PCM_COMPRESSION 0x10 /* R W PCM 1=enable, 0=disabled compression */
|
||||
#define EMULATION_ADDRESS 0xF789 /* R W Control */
|
||||
#define E_A_SB_BASE 0x0f /* R W PCM bits A4-A7 for SB base port */
|
||||
#define E_A_MPU401_BASE 0xf0 /* R W MIDI bits A4-A7 for MPU401 base port */
|
||||
#define EMULATION_CONFIGURATION 0xFB8A /* R W ***** Only valid on newer PAS2 cards (?) ***** */
|
||||
#define E_C_MPU401_IRQ 0x07 /* R W MIDI MPU401 emulation IRQ */
|
||||
#define E_C_SB_IRQ 0x38 /* R W PCM SB emulation IRQ */
|
||||
#define E_C_SB_DMA 0xC0 /* R W PCM SB emulation DMA */
|
||||
|
||||
#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=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 */
|
||||
#define O_M_2_BUS_TIMING 0x10 /* R Control 1=AT bus timing, 0=XT bus timing */
|
||||
#define O_M_2_BOARD_REVISION 0xe0 /* R Control Board revision */
|
||||
|
||||
#define INTERRUPT_MASK 0x0B8B /* R W Control */
|
||||
#define I_M_FM_LEFT_IRQ_ENABLE 0x01 /* R W FM Enable FM left interrupt */
|
||||
#define I_M_FM_RIGHT_IRQ_ENABLE 0x02 /* R W FM Enable FM right interrupt */
|
||||
#define I_M_PCM_RATE_IRQ_ENABLE 0x04 /* R W PCM Enable Sample Rate interrupt */
|
||||
#define I_M_PCM_BUFFER_IRQ_ENABLE 0x08 /* R W PCM Enable Sample Buffer interrupt */
|
||||
#define I_M_MIDI_IRQ_ENABLE 0x10 /* R W MIDI Enable MIDI interrupt */
|
||||
#define I_M_BOARD_REV 0xE0 /* R Control Board revision */
|
||||
|
||||
#define INTERRUPT_STATUS 0x0B89 /* R W Control */
|
||||
#define I_S_FM_LEFT_IRQ 0x01 /* R W FM Left FM Interrupt Pending */
|
||||
#define I_S_FM_RIGHT_IRQ 0x02 /* R W FM Right FM Interrupt Pending */
|
||||
#define I_S_PCM_SAMPLE_RATE_IRQ 0x04 /* R W PCM Sample Rate Interrupt Pending */
|
||||
#define I_S_PCM_SAMPLE_BUFFER_IRQ 0x08 /* R W PCM Sample Buffer Interrupt Pending */
|
||||
#define I_S_MIDI_IRQ 0x10 /* R W MIDI MIDI Interrupt Pending */
|
||||
#define I_S_PCM_CHANNEL 0x20 /* R W PCM 1=right, 0=left */
|
||||
#define I_S_RESET_ACTIVE 0x40 /* R W Control Reset is active (Timed pulse not finished) */
|
||||
#define I_S_PCM_CLIPPING 0x80 /* R W PCM Clipping has occurred */
|
||||
|
||||
#define FILTER_FREQUENCY 0x0B8A /* R W Control */
|
||||
#define F_F_FILTER_DISABLED 0x00 /* R W Mixer No filter */
|
||||
#if 0
|
||||
struct { /* R W Mixer Filter translation */
|
||||
unsigned int freq:24;
|
||||
unsigned int value:8;
|
||||
} F_F_FILTER_translate[] =
|
||||
{ { 73500, 0x01 }, /* 73500Hz - divide by 16 */
|
||||
{ 65333, 0x02 }, /* 65333Hz - divide by 18 */
|
||||
{ 49000, 0x09 }, /* 49000Hz - divide by 24 */
|
||||
{ 36750, 0x11 }, /* 36750Hz - divide by 32 */
|
||||
{ 24500, 0x19 }, /* 24500Hz - divide by 48 */
|
||||
{ 18375, 0x07 }, /* 18375Hz - divide by 64 */
|
||||
{ 12783, 0x0f }, /* 12783Hz - divide by 92 */
|
||||
{ 12250, 0x04 }, /* 12250Hz - divide by 96 */
|
||||
{ 9188, 0x17 }, /* 9188Hz - divide by 128 */
|
||||
{ 6125, 0x1f }, /* 6125Hz - divide by 192 */
|
||||
};
|
||||
#endif
|
||||
#define F_F_MIXER_UNMUTE 0x20 /* R W Mixer 1=disable, 0=enable board mute */
|
||||
#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 PAS_NONE 0
|
||||
#define PAS_PLUS 1
|
||||
#define PAS_CDPC 2
|
||||
#define PAS_16 3
|
||||
#define PAS_16D 4
|
||||
|
||||
#ifdef DEFINE_TRANSLATIONS
|
||||
unsigned char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */
|
||||
{ 4, 1, 2, 3, 0, 5, 6, 7 };
|
||||
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 };
|
||||
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 */
|
||||
{ 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 };
|
||||
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 };
|
||||
#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 */
|
||||
extern unsigned char E_C_MPU401_IRQ_translate[]; /* R W MIDI MPU401 emulation IRQ value translation */
|
||||
extern unsigned char E_C_SB_IRQ_translate[]; /* R W PCM SB emulation IRQ translate */
|
||||
extern unsigned char E_C_SB_DMA_translate[]; /* R W PCM SB emulation DMA translate */
|
||||
extern unsigned char O_M_1_to_card[]; /* R W Control Translate (OM1 & 0x0f) to card type */
|
||||
#endif
|
||||
|
||||
#define PARALLEL_MIXER 0x078B /* W Mixer Documented for MVD101 as FM Mono Right decode?? */
|
||||
#define P_M_MV508_ADDRESS 0x80 /* W Mixer MVD508 Address/mixer select */
|
||||
#define P_M_MV508_DATA 0x00
|
||||
#define P_M_MV508_LEFT 0x20 /* W Mixer MVD508 Left channel select */
|
||||
#define P_M_MV508_RIGHT 0x40 /* W Mixer MVD508 Right channel select */
|
||||
#define P_M_MV508_BOTH 0x00 /* W Mixer MVD508 Both channel select */
|
||||
#define P_M_MV508_MIXER 0x10 /* W Mixer MVD508 Select a mixer (rather than a volume) */
|
||||
#define P_M_MV508_VOLUME 0x00
|
||||
|
||||
#define P_M_MV508_INPUTMIX 0x20 /* W Mixer MVD508 Select mixer A */
|
||||
#define P_M_MV508_OUTPUTMIX 0x00 /* W Mixer MVD508 Select mixer B */
|
||||
|
||||
#define P_M_MV508_MASTER_A 0x01 /* W Mixer MVD508 Master volume control A (output) */
|
||||
#define P_M_MV508_MASTER_B 0x02 /* W Mixer MVD508 Master volume control B (DSP input) */
|
||||
#define P_M_MV508_BASS 0x03 /* W Mixer MVD508 Bass control */
|
||||
#define P_M_MV508_TREBLE 0x04 /* W Mixer MVD508 Treble control */
|
||||
#define P_M_MV508_MODE 0x05 /* W Mixer MVD508 Master mode control */
|
||||
|
||||
#define P_M_MV508_LOUDNESS 0x04 /* W Mixer MVD508 Mode control - Loudness filter */
|
||||
#define P_M_MV508_ENHANCE_BITS 0x03
|
||||
#define P_M_MV508_ENHANCE_NONE 0x00 /* W Mixer MVD508 Mode control - No stereo enhancement */
|
||||
#define P_M_MV508_ENHANCE_40 0x01 /* W Mixer MVD508 Mode control - 40% stereo enhancement */
|
||||
#define P_M_MV508_ENHANCE_60 0x02 /* W Mixer MVD508 Mode control - 60% stereo enhancement */
|
||||
#define P_M_MV508_ENHANCE_80 0x03 /* W Mixer MVD508 Mode control - 80% stereo enhancement */
|
||||
|
||||
#define P_M_MV508_FM 0x00 /* W Mixer MVD508 Channel 0 - FM */
|
||||
#define P_M_MV508_IMIXER 0x01 /* W Mixer MVD508 Channel 1 - Input mixer (rec monitor) */
|
||||
#define P_M_MV508_LINE 0x02 /* W Mixer MVD508 Channel 2 - Line in */
|
||||
#define P_M_MV508_CDROM 0x03 /* W Mixer MVD508 Channel 3 - CD-ROM */
|
||||
#define P_M_MV508_MIC 0x04 /* W Mixer MVD508 Channel 4 - Microphone */
|
||||
#define P_M_MV508_PCM 0x05 /* W Mixer MVD508 Channel 5 - PCM */
|
||||
#define P_M_MV508_SPEAKER 0x06 /* W Mixer MVD508 Channel 6 - PC Speaker */
|
||||
#define P_M_MV508_SB 0x07 /* W Mixer MVD508 Channel 7 - SB DSP */
|
||||
|
||||
#define SERIAL_MIXER 0xB88 /* R W Control Serial mixer control (used other ways) */
|
||||
#define S_M_PCM_RESET 0x01 /* R W PCM Codec/DSP reset */
|
||||
#define S_M_FM_RESET 0x02 /* R W FM FM chip reset */
|
||||
#define S_M_SB_RESET 0x04 /* R W PCM SB emulation chip reset */
|
||||
#define S_M_MIXER_RESET 0x10 /* R W Mixer Mixer chip reset */
|
||||
#define S_M_INTEGRATOR_ENABLE 0x40 /* R W Speaker Enable PC speaker integrator (FORCE RealSound) */
|
||||
#define S_M_OPL3_DUAL_MONO 0x80 /* R W FM Set the OPL-3 to dual mono mode */
|
||||
|
||||
#define PCM_CONTROL 0xF8A /* R W PCM PCM Control Register */
|
||||
#define P_C_MIXER_CROSS_FIELD 0x0f
|
||||
#define P_C_MIXER_CROSS_R_TO_R 0x01 /* R W Mixer Connect Right to Right */
|
||||
#define P_C_MIXER_CROSS_L_TO_R 0x02 /* R W Mixer Connect Left to Right */
|
||||
#define P_C_MIXER_CROSS_R_TO_L 0x04 /* R W Mixer Connect Right to Left */
|
||||
#define P_C_MIXER_CROSS_L_TO_L 0x08 /* R W Mixer Connect Left to Left */
|
||||
#define P_C_PCM_DAC_MODE 0x10 /* R W PCM Playback (DAC) mode */
|
||||
#define P_C_PCM_ADC_MODE 0x00 /* R W PCM Record (ADC) mode */
|
||||
#define P_C_PCM_MONO 0x20 /* R W PCM Mono mode */
|
||||
#define P_C_PCM_STEREO 0x00 /* R W PCM Stereo mode */
|
||||
#define P_C_PCM_ENABLE 0x40 /* R W PCM Enable PCM engine */
|
||||
#define P_C_PCM_DMA_ENABLE 0x80 /* R W PCM Enable DRQ */
|
||||
|
||||
#define SAMPLE_COUNTER_CONTROL 0x138B /* R W PCM Sample counter control register */
|
||||
#define S_C_C_SQUARE_WAVE 0x04 /* R W PCM Square wave generator (use for sample rate) */
|
||||
#define S_C_C_RATE 0x06 /* R W PCM Rate generator (use for sample buffer count) */
|
||||
#define S_C_C_LSB_THEN_MSB 0x30 /* R W PCM Change all 16 bits, LSB first, then MSB */
|
||||
|
||||
/* MVD101 and SDK documentations have S_C_C_SAMPLE_RATE and S_C_C_SAMPLE_BUFFER transposed. Only one works :-) */
|
||||
#define S_C_C_SAMPLE_RATE 0x00 /* R W PCM Select sample rate timer */
|
||||
#define S_C_C_SAMPLE_BUFFER 0x40 /* R W PCM Select sample buffer counter */
|
||||
|
||||
#define S_C_C_PC_SPEAKER 0x80 /* R W PCM Select PC speaker counter */
|
||||
|
||||
#define SAMPLE_RATE_TIMER 0x1388 /* W PCM Sample rate timer register (PCM wait interval) */
|
||||
#define SAMPLE_BUFFER_COUNTER 0x1389 /* R W PCM Sample buffer counter (DMA buffer size) */
|
||||
|
||||
#define MIDI_CONTROL 0x178b /* R W MIDI Midi control register */
|
||||
#define M_C_ENA_TSTAMP_IRQ 0x01 /* R W MIDI Enable Time Stamp Interrupts */
|
||||
#define M_C_ENA_TME_COMP_IRQ 0x02 /* R W MIDI Enable time compare interrupts */
|
||||
#define M_C_ENA_INPUT_IRQ 0x04 /* R W MIDI Enable input FIFO interrupts */
|
||||
#define M_C_ENA_OUTPUT_IRQ 0x08 /* R W MIDI Enable output FIFO interrupts */
|
||||
#define M_C_ENA_OUTPUT_HALF_IRQ 0x10 /* R W MIDI Enable output FIFO half full interrupts */
|
||||
#define M_C_RESET_INPUT_FIFO 0x20 /* R W MIDI Reset input FIFO pointer */
|
||||
#define M_C_RESET_OUTPUT_FIFO 0x40 /* R W MIDI Reset output FIFO pointer */
|
||||
#define M_C_ENA_THRU_MODE 0x80 /* R W MIDI Echo input to output (THRU) */
|
||||
|
||||
#define MIDI_STATUS 0x1B88 /* R W MIDI Midi (interrupt) status register */
|
||||
#define M_S_TIMESTAMP 0x01 /* R W MIDI Midi time stamp interrupt occurred */
|
||||
#define M_S_COMPARE 0x02 /* R W MIDI Midi compare time interrupt occurred */
|
||||
#define M_S_INPUT_AVAIL 0x04 /* R W MIDI Midi input data available interrupt occurred */
|
||||
#define M_S_OUTPUT_EMPTY 0x08 /* R W MIDI Midi output FIFO empty interrupt occurred */
|
||||
#define M_S_OUTPUT_HALF_EMPTY 0x10 /* R W MIDI Midi output FIFO half empty interrupt occurred */
|
||||
#define M_S_INPUT_OVERRUN 0x20 /* R W MIDI Midi input overrun error occurred */
|
||||
#define M_S_OUTPUT_OVERRUN 0x40 /* R W MIDI Midi output overrun error occurred */
|
||||
#define M_S_FRAMING_ERROR 0x80 /* R W MIDI Midi input framing error occurred */
|
||||
|
||||
#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 */
|
407
sys/i386/isa/sound/pas2_card.c
Normal file
407
sys/i386/isa/sound/pas2_card.c
Normal file
@ -0,0 +1,407 @@
|
||||
#define _PAS2_CARD_C_
|
||||
/*
|
||||
* sound/pas2_card.c
|
||||
*
|
||||
* Detection routine for the Pro Audio Spectrum cards.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* 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_PAS)
|
||||
|
||||
#define DEFINE_TRANSLATIONS
|
||||
#include "pas.h"
|
||||
|
||||
/*
|
||||
* The Address Translation code is used to convert I/O register addresses to
|
||||
* be relative to the given base -register
|
||||
*/
|
||||
|
||||
int translat_code;
|
||||
static int pas_intr_mask = 0;
|
||||
static int pas_irq = 0;
|
||||
|
||||
static char pas_model;
|
||||
static char *pas_model_names[] =
|
||||
{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
|
||||
|
||||
/*
|
||||
* pas_read() and pas_write() are equivalents of INB() and OUTB()
|
||||
*/
|
||||
/*
|
||||
* These routines perform the I/O address translation required
|
||||
*/
|
||||
/*
|
||||
* to support other than the default base address
|
||||
*/
|
||||
|
||||
unsigned char
|
||||
pas_read (int ioaddr)
|
||||
{
|
||||
return INB (ioaddr ^ translat_code);
|
||||
}
|
||||
|
||||
void
|
||||
pas_write (unsigned char data, int ioaddr)
|
||||
{
|
||||
OUTB (data, ioaddr ^ translat_code);
|
||||
}
|
||||
|
||||
void
|
||||
pas2_msg (char *foo)
|
||||
{
|
||||
printk (" PAS2: %s.\n", foo);
|
||||
}
|
||||
|
||||
/******************* Begin of the Interrupt Handler ********************/
|
||||
|
||||
void
|
||||
pasintr (int unused)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = pas_read (INTERRUPT_STATUS);
|
||||
pas_write (status, INTERRUPT_STATUS); /*
|
||||
* Clear interrupt
|
||||
*/
|
||||
|
||||
if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
|
||||
{
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
pas_pcm_interrupt (status, 1);
|
||||
#endif
|
||||
status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ;
|
||||
}
|
||||
if (status & I_S_MIDI_IRQ)
|
||||
{
|
||||
#ifndef EXCLUDE_MIDI
|
||||
#ifdef EXCLUDE_PRO_MIDI
|
||||
pas_midi_interrupt ();
|
||||
#endif
|
||||
#endif
|
||||
status &= ~I_S_MIDI_IRQ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
pas_set_intr (int mask)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!mask)
|
||||
return 0;
|
||||
|
||||
if (!pas_intr_mask)
|
||||
{
|
||||
if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0)
|
||||
return err;
|
||||
}
|
||||
pas_intr_mask |= mask;
|
||||
|
||||
pas_write (pas_intr_mask, INTERRUPT_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pas_remove_intr (int mask)
|
||||
{
|
||||
if (!mask)
|
||||
return 0;
|
||||
|
||||
pas_intr_mask &= ~mask;
|
||||
pas_write (pas_intr_mask, INTERRUPT_MASK);
|
||||
|
||||
if (!pas_intr_mask)
|
||||
{
|
||||
snd_release_irq (pas_irq);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************* End of the Interrupt handler **********************/
|
||||
|
||||
/******************* Begin of the Initialization Code ******************/
|
||||
|
||||
int
|
||||
config_pas_hw (struct address_info *hw_config)
|
||||
{
|
||||
char ok = 1;
|
||||
unsigned int_ptrs; /* scsi/sound interrupt pointers */
|
||||
|
||||
pas_irq = hw_config->irq;
|
||||
|
||||
pas_write (0x00, INTERRUPT_MASK);
|
||||
|
||||
pas_write (0x36, SAMPLE_COUNTER_CONTROL); /*
|
||||
* Local timer control *
|
||||
* register
|
||||
*/
|
||||
|
||||
pas_write (0x36, SAMPLE_RATE_TIMER); /*
|
||||
* Sample rate timer (16 bit)
|
||||
*/
|
||||
pas_write (0, SAMPLE_RATE_TIMER);
|
||||
|
||||
pas_write (0x74, SAMPLE_COUNTER_CONTROL); /*
|
||||
* Local timer control *
|
||||
* register
|
||||
*/
|
||||
|
||||
pas_write (0x74, SAMPLE_BUFFER_COUNTER); /*
|
||||
* Sample count register (16
|
||||
* * bit)
|
||||
*/
|
||||
pas_write (0, SAMPLE_BUFFER_COUNTER);
|
||||
|
||||
pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY);
|
||||
pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL);
|
||||
pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /*
|
||||
* |
|
||||
* S_M_OPL3_DUAL_MONO
|
||||
*/ , SERIAL_MIXER);
|
||||
|
||||
pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1);
|
||||
|
||||
if (pas_irq < 0 || pas_irq > 15)
|
||||
{
|
||||
printk ("PAS2: Invalid IRQ %d", pas_irq);
|
||||
ok = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int_ptrs = pas_read (IO_CONFIGURATION_3);
|
||||
int_ptrs |= I_C_3_PCM_IRQ_translate[pas_irq] & 0xf;
|
||||
pas_write (int_ptrs, IO_CONFIGURATION_3);
|
||||
if (!I_C_3_PCM_IRQ_translate[pas_irq])
|
||||
{
|
||||
printk ("PAS2: Invalid IRQ %d", pas_irq);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hw_config->dma < 0 || hw_config->dma > 7)
|
||||
{
|
||||
printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
|
||||
ok = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pas_write (I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2);
|
||||
if (!I_C_2_PCM_DMA_translate[hw_config->dma])
|
||||
{
|
||||
printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This fixes the timing problems of the PAS due to the Symphony chipset
|
||||
* as per Media Vision. Only define this if your PAS doesn't work correctly.
|
||||
*/
|
||||
#ifdef SYMPHONY_PAS
|
||||
OUTB (0x05, 0xa8);
|
||||
OUTB (0x60, 0xa9);
|
||||
#endif
|
||||
|
||||
#ifdef BROKEN_BUS_CLOCK
|
||||
pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
|
||||
#else
|
||||
/*
|
||||
* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);
|
||||
*/
|
||||
pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
|
||||
#endif
|
||||
pas_write (0x18, SYSTEM_CONFIGURATION_3); /*
|
||||
* ???
|
||||
*/
|
||||
|
||||
pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /*
|
||||
* Sets mute
|
||||
* off and *
|
||||
* selects
|
||||
* filter
|
||||
* rate * of
|
||||
* 17.897 kHz
|
||||
*/
|
||||
|
||||
if (pas_model == PAS_16 || pas_model == PAS_16D)
|
||||
pas_write (8, PRESCALE_DIVIDER);
|
||||
else
|
||||
pas_write (0, PRESCALE_DIVIDER);
|
||||
|
||||
pas_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
|
||||
pas_write (5, PARALLEL_MIXER);
|
||||
|
||||
#if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
|
||||
|
||||
{
|
||||
struct address_info *sb_config;
|
||||
|
||||
if ((sb_config = sound_getconf (SNDCARD_SB)))
|
||||
{
|
||||
unsigned char irq_dma;
|
||||
|
||||
/*
|
||||
* Turn on Sound Blaster compatibility
|
||||
*/
|
||||
/*
|
||||
* bit 1 = SB emulation
|
||||
*/
|
||||
/*
|
||||
* bit 0 = MPU401 emulation (CDPC only :-( )
|
||||
*/
|
||||
pas_write (0x02, COMPATIBILITY_ENABLE);
|
||||
|
||||
/*
|
||||
* "Emulation address"
|
||||
*/
|
||||
pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
|
||||
|
||||
if (!E_C_SB_DMA_translate[sb_config->dma])
|
||||
printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
|
||||
sb_config->dma);
|
||||
|
||||
if (!E_C_SB_IRQ_translate[sb_config->irq])
|
||||
printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
|
||||
sb_config->irq);
|
||||
|
||||
irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
|
||||
E_C_SB_IRQ_translate[sb_config->irq];
|
||||
|
||||
pas_write (irq_dma, EMULATION_CONFIGURATION);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ok)
|
||||
pas2_msg ("Driver not enabled");
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int
|
||||
detect_pas_hw (struct address_info *hw_config)
|
||||
{
|
||||
unsigned char board_id, foo;
|
||||
|
||||
/*
|
||||
* WARNING: Setting an option like W:1 or so that disables warm boot reset
|
||||
* of the card will screw up this detect code something fierce. Adding code
|
||||
* to handle this means possibly interfering with other cards on the bus if
|
||||
* you have something on base port 0x388. SO be forewarned.
|
||||
*/
|
||||
|
||||
OUTB (0xBC, MASTER_DECODE); /*
|
||||
* Talk to first board
|
||||
*/
|
||||
OUTB (hw_config->io_base >> 2, MASTER_DECODE); /*
|
||||
* Set base address
|
||||
*/
|
||||
translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base;
|
||||
pas_write (1, WAIT_STATE); /*
|
||||
* One wait-state
|
||||
*/
|
||||
|
||||
board_id = pas_read (INTERRUPT_MASK);
|
||||
|
||||
if (board_id == 0xff)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We probably have a PAS-series board, now check for a PAS2-series board
|
||||
* by trying to change the board revision bits. PAS2-series hardware won't
|
||||
* let you do this - the bits are read-only.
|
||||
*/
|
||||
|
||||
foo = board_id ^ 0xe0;
|
||||
|
||||
pas_write (foo, INTERRUPT_MASK);
|
||||
foo = INB (INTERRUPT_MASK);
|
||||
pas_write (board_id, INTERRUPT_MASK);
|
||||
|
||||
if (board_id != foo) /*
|
||||
* Not a PAS2
|
||||
*/
|
||||
return 0;
|
||||
|
||||
pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f];
|
||||
|
||||
return pas_model;
|
||||
}
|
||||
|
||||
long
|
||||
attach_pas_card (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
pas_irq = hw_config->irq;
|
||||
|
||||
if (detect_pas_hw (hw_config))
|
||||
{
|
||||
|
||||
if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]))
|
||||
{
|
||||
printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
|
||||
}
|
||||
|
||||
if (config_pas_hw (hw_config))
|
||||
{
|
||||
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
mem_start = pas_pcm_init (mem_start, hw_config);
|
||||
#endif
|
||||
|
||||
#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
|
||||
|
||||
sb_dsp_disable_midi (); /*
|
||||
* The SB emulation don't support *
|
||||
* midi
|
||||
*/
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_YM3812
|
||||
enable_opl3_mode (0x388, 0x38a, 0);
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_MIDI
|
||||
#ifdef EXCLUDE_PRO_MIDI
|
||||
mem_start = pas_midi_init (mem_start);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
pas_init_mixer ();
|
||||
}
|
||||
}
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
probe_pas (struct address_info *hw_config)
|
||||
{
|
||||
return detect_pas_hw (hw_config);
|
||||
}
|
||||
|
||||
#endif
|
338
sys/i386/isa/sound/pas2_midi.c
Normal file
338
sys/i386/isa/sound/pas2_midi.c
Normal file
@ -0,0 +1,338 @@
|
||||
/*
|
||||
* sound/pas2_midi.c
|
||||
*
|
||||
* The low level driver for the PAS Midi Interface.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#include "pas.h"
|
||||
|
||||
#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_MIDI) && defined(EXCLUDE_PRO_MIDI)
|
||||
|
||||
static int midi_busy = 0, input_opened = 0;
|
||||
static int my_dev;
|
||||
static volatile int ofifo_bytes = 0;
|
||||
|
||||
static unsigned char tmp_queue[256];
|
||||
static volatile int qlen;
|
||||
static volatile unsigned char qhead, qtail;
|
||||
|
||||
static void (*midi_input_intr) (int dev, unsigned char data);
|
||||
|
||||
static int
|
||||
pas_midi_open (int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
void (*output) (int dev)
|
||||
)
|
||||
{
|
||||
int err;
|
||||
unsigned long flags;
|
||||
unsigned char ctrl;
|
||||
|
||||
|
||||
if (midi_busy)
|
||||
{
|
||||
printk ("PAS2: Midi busy\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset input and output FIFO pointers
|
||||
*/
|
||||
pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO,
|
||||
MIDI_CONTROL);
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Enable input available and output FIFO empty interrupts
|
||||
*/
|
||||
|
||||
ctrl = 0;
|
||||
input_opened = 0;
|
||||
midi_input_intr = input;
|
||||
|
||||
if (mode == OPEN_READ || mode == OPEN_READWRITE)
|
||||
{
|
||||
ctrl |= M_C_ENA_INPUT_IRQ;/*
|
||||
* Enable input
|
||||
*/
|
||||
input_opened = 1;
|
||||
}
|
||||
|
||||
if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
|
||||
{
|
||||
ctrl |= M_C_ENA_OUTPUT_IRQ | /*
|
||||
* Enable output
|
||||
*/
|
||||
M_C_ENA_OUTPUT_HALF_IRQ;
|
||||
}
|
||||
|
||||
pas_write (ctrl,
|
||||
MIDI_CONTROL);
|
||||
|
||||
/*
|
||||
* Acknowledge any pending interrupts
|
||||
*/
|
||||
|
||||
pas_write (0xff, MIDI_STATUS);
|
||||
ofifo_bytes = 0;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
midi_busy = 1;
|
||||
qlen = qhead = qtail = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pas_midi_close (int dev)
|
||||
{
|
||||
|
||||
/*
|
||||
* Reset FIFO pointers, disable intrs
|
||||
*/
|
||||
pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL);
|
||||
|
||||
pas_remove_intr (I_M_MIDI_IRQ_ENABLE);
|
||||
midi_busy = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dump_to_midi (unsigned char midi_byte)
|
||||
{
|
||||
int fifo_space, x;
|
||||
|
||||
fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
|
||||
|
||||
if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /*
|
||||
* Fifo
|
||||
* full
|
||||
*/
|
||||
{
|
||||
return 0; /*
|
||||
* Upper layer will call again
|
||||
*/
|
||||
}
|
||||
|
||||
ofifo_bytes++;
|
||||
|
||||
pas_write (midi_byte, MIDI_DATA);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pas_midi_out (int dev, unsigned char midi_byte)
|
||||
{
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Drain the local queue first
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
while (qlen && dump_to_midi (tmp_queue[qhead]))
|
||||
{
|
||||
qlen--;
|
||||
qhead++;
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* Output the byte if the local queue is empty.
|
||||
*/
|
||||
|
||||
if (!qlen)
|
||||
if (dump_to_midi (midi_byte))
|
||||
return 1; /*
|
||||
* OK
|
||||
*/
|
||||
|
||||
/*
|
||||
* Put to the local queue
|
||||
*/
|
||||
|
||||
if (qlen >= 256)
|
||||
return 0; /*
|
||||
* Local queue full
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
tmp_queue[qtail] = midi_byte;
|
||||
qlen++;
|
||||
qtail++;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pas_midi_start_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pas_midi_end_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pas_midi_ioctl (int dev, unsigned cmd, unsigned arg)
|
||||
{
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
pas_midi_kick (int dev)
|
||||
{
|
||||
ofifo_bytes = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pas_buffer_status (int dev)
|
||||
{
|
||||
return !qlen;
|
||||
}
|
||||
|
||||
#define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi"
|
||||
#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
|
||||
#include "midi_synth.h"
|
||||
|
||||
static struct midi_operations pas_midi_operations =
|
||||
{
|
||||
{"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
|
||||
&std_midi_synth,
|
||||
pas_midi_open,
|
||||
pas_midi_close,
|
||||
pas_midi_ioctl,
|
||||
pas_midi_out,
|
||||
pas_midi_start_read,
|
||||
pas_midi_end_read,
|
||||
pas_midi_kick,
|
||||
NULL, /*
|
||||
* command
|
||||
*/
|
||||
pas_buffer_status,
|
||||
NULL
|
||||
};
|
||||
|
||||
long
|
||||
pas_midi_init (long mem_start)
|
||||
{
|
||||
if (num_midis >= MAX_MIDI_DEV)
|
||||
{
|
||||
printk ("Sound: Too many midi devices detected\n");
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
std_midi_synth.midi_dev = my_dev = num_midis;
|
||||
midi_devs[num_midis++] = &pas_midi_operations;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
void
|
||||
pas_midi_interrupt (void)
|
||||
{
|
||||
unsigned char stat;
|
||||
int i, incount;
|
||||
unsigned long flags;
|
||||
|
||||
stat = pas_read (MIDI_STATUS);
|
||||
|
||||
if (stat & M_S_INPUT_AVAIL) /*
|
||||
* Input byte available
|
||||
*/
|
||||
{
|
||||
incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /*
|
||||
* Input FIFO count
|
||||
*/
|
||||
if (!incount)
|
||||
incount = 16;
|
||||
|
||||
for (i = 0; i < incount; i++)
|
||||
if (input_opened)
|
||||
{
|
||||
midi_input_intr (my_dev, pas_read (MIDI_DATA));
|
||||
}
|
||||
else
|
||||
pas_read (MIDI_DATA); /*
|
||||
* Flush
|
||||
*/
|
||||
}
|
||||
|
||||
if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY))
|
||||
{
|
||||
if (!(stat & M_S_OUTPUT_EMPTY))
|
||||
{
|
||||
ofifo_bytes = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
ofifo_bytes = 0;
|
||||
}
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
while (qlen && dump_to_midi (tmp_queue[qhead]))
|
||||
{
|
||||
qlen--;
|
||||
qhead++;
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
if (stat & M_S_FRAMING_ERROR)
|
||||
printk ("MIDI framing error\n");
|
||||
|
||||
if (stat & M_S_OUTPUT_OVERRUN)
|
||||
{
|
||||
printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
|
||||
ofifo_bytes = 100;
|
||||
}
|
||||
|
||||
pas_write (stat, MIDI_STATUS);/*
|
||||
* Acknowledge interrupts
|
||||
*/
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
398
sys/i386/isa/sound/pas2_mixer.c
Normal file
398
sys/i386/isa/sound/pas2_mixer.c
Normal file
@ -0,0 +1,398 @@
|
||||
#define _PAS2_MIXER_C_
|
||||
|
||||
/*
|
||||
* sound/pas2_mixer.c
|
||||
*
|
||||
* Mixer routines for the Pro Audio Spectrum cards.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* 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_PAS)
|
||||
|
||||
#include "pas.h"
|
||||
|
||||
#define TRACE(what) /*
|
||||
* * * (what) */
|
||||
|
||||
extern int translat_code;
|
||||
|
||||
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 | \
|
||||
SOUND_MASK_CD | SOUND_MASK_ALTPCM)
|
||||
|
||||
#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
|
||||
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
|
||||
SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
|
||||
|
||||
static unsigned short levels[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x3232, /*
|
||||
* Master Volume
|
||||
*/
|
||||
0x3232, /*
|
||||
* Bass
|
||||
*/
|
||||
0x3232, /*
|
||||
* Treble
|
||||
*/
|
||||
0x5050, /*
|
||||
* FM
|
||||
*/
|
||||
0x4b4b, /*
|
||||
* PCM
|
||||
*/
|
||||
0x3232, /*
|
||||
* PC Speaker
|
||||
*/
|
||||
0x4b4b, /*
|
||||
* Ext Line
|
||||
*/
|
||||
0x4b4b, /*
|
||||
* Mic
|
||||
*/
|
||||
0x4b4b, /*
|
||||
* CD
|
||||
*/
|
||||
0x6464, /*
|
||||
* Recording monitor
|
||||
*/
|
||||
0x4b4b, /*
|
||||
* SB PCM
|
||||
*/
|
||||
0x6464}; /*
|
||||
|
||||
|
||||
* * * * Recording level */
|
||||
|
||||
static int
|
||||
mixer_output (int right_vol, int left_vol, int div, int bits,
|
||||
int mixer /*
|
||||
* Input or output mixer
|
||||
*/ )
|
||||
{
|
||||
int left = left_vol * div / 100;
|
||||
int right = right_vol * div / 100;
|
||||
|
||||
/*
|
||||
* The Revision D cards have a problem with their MVA508 interface. The
|
||||
* kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
|
||||
* MSBs out of the output byte and to do a 16-bit out to the mixer port -
|
||||
* 1. We don't need to do this because the call to pas_write more than
|
||||
* compensates for the timing problems.
|
||||
*/
|
||||
|
||||
if (bits & P_M_MV508_MIXER)
|
||||
{ /*
|
||||
* Select input or output mixer
|
||||
*/
|
||||
left |= mixer;
|
||||
right |= mixer;
|
||||
}
|
||||
|
||||
if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
|
||||
{ /*
|
||||
* Bass and trebble are mono devices
|
||||
*/
|
||||
pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
|
||||
pas_write (left, PARALLEL_MIXER);
|
||||
right_vol = left_vol;
|
||||
}
|
||||
else
|
||||
{
|
||||
pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
|
||||
pas_write (left, PARALLEL_MIXER);
|
||||
pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
|
||||
pas_write (right, PARALLEL_MIXER);
|
||||
}
|
||||
|
||||
return (left_vol | (right_vol << 8));
|
||||
}
|
||||
|
||||
void
|
||||
set_mode (int new_mode)
|
||||
{
|
||||
pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
|
||||
pas_write (new_mode, PARALLEL_MIXER);
|
||||
|
||||
mode_control = new_mode;
|
||||
}
|
||||
|
||||
static int
|
||||
pas_mixer_set (int whichDev, unsigned int level)
|
||||
{
|
||||
int left, right, devmask, changed, i, mixer = 0;
|
||||
|
||||
TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
|
||||
|
||||
left = level & 0x7f;
|
||||
right = (level & 0x7f00) >> 8;
|
||||
|
||||
if (whichDev < SOUND_MIXER_NRDEVICES)
|
||||
if ((1 << whichDev) & rec_devices)
|
||||
mixer = P_M_MV508_INPUTMIX;
|
||||
else
|
||||
mixer = P_M_MV508_OUTPUTMIX;
|
||||
|
||||
switch (whichDev)
|
||||
{
|
||||
case SOUND_MIXER_VOLUME: /*
|
||||
* Master volume (0-63)
|
||||
*/
|
||||
levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Note! Bass and Treble are mono devices. Will use just the left
|
||||
* channel.
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
|
||||
break;
|
||||
|
||||
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)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
|
||||
break;
|
||||
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)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_MUTE:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_ENHANCE:
|
||||
i = 0;
|
||||
level &= 0x7f;
|
||||
if (level)
|
||||
i = (level / 20) - 1;
|
||||
|
||||
mode_control &= ~P_M_MV508_ENHANCE_BITS;
|
||||
mode_control |= P_M_MV508_ENHANCE_BITS;
|
||||
set_mode (mode_control);
|
||||
|
||||
if (i)
|
||||
i = (i + 1) * 20;
|
||||
return i;
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_LOUD:
|
||||
mode_control &= ~P_M_MV508_LOUDNESS;
|
||||
if (level)
|
||||
mode_control |= P_M_MV508_LOUDNESS;
|
||||
set_mode (mode_control);
|
||||
return !!level; /*
|
||||
* 0 or 1
|
||||
*/
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_RECSRC:
|
||||
devmask = level & POSSIBLE_RECORDING_DEVICES;
|
||||
|
||||
changed = devmask ^ rec_devices;
|
||||
rec_devices = devmask;
|
||||
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
|
||||
if (changed & (1 << i))
|
||||
{
|
||||
pas_mixer_set (i, levels[i]);
|
||||
}
|
||||
return rec_devices;
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
return (levels[whichDev]);
|
||||
}
|
||||
|
||||
/*****/
|
||||
|
||||
static int
|
||||
getmixer (int dev, int chn)
|
||||
{
|
||||
if (chn == P_M_MV508_RIGHT)
|
||||
{
|
||||
return (levels[dev] >> 8) & 0x7f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return levels[dev] & 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pas_mixer_reset (void)
|
||||
{
|
||||
int foo;
|
||||
|
||||
TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
|
||||
|
||||
for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
|
||||
pas_mixer_set (foo, levels[foo]);
|
||||
|
||||
set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
|
||||
}
|
||||
|
||||
int
|
||||
pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
|
||||
|
||||
if (((cmd >> 8) & 0xff) == 'M')
|
||||
{
|
||||
if (cmd & IOC_IN)
|
||||
return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
|
||||
else
|
||||
{ /*
|
||||
* Read parameters
|
||||
*/
|
||||
|
||||
switch (cmd & 0xff)
|
||||
{
|
||||
|
||||
case SOUND_MIXER_RECSRC:
|
||||
return IOCTL_OUT (arg, rec_devices);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_STEREODEVS:
|
||||
return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_DEVMASK:
|
||||
return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_RECMASK:
|
||||
return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_CAPS:
|
||||
return IOCTL_OUT (arg, 0); /*
|
||||
* No special capabilities
|
||||
*/
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_MUTE:
|
||||
return IOCTL_OUT (arg, 0); /*
|
||||
* No mute yet
|
||||
*/
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_ENHANCE:
|
||||
if (!(mode_control & P_M_MV508_ENHANCE_BITS))
|
||||
return IOCTL_OUT (arg, 0);
|
||||
return IOCTL_OUT (arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_LOUD:
|
||||
if (mode_control & P_M_MV508_LOUDNESS)
|
||||
return IOCTL_OUT (arg, 1);
|
||||
return IOCTL_OUT (arg, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return IOCTL_OUT (arg, levels[cmd & 0xff]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static struct mixer_operations pas_mixer_operations =
|
||||
{
|
||||
pas_mixer_ioctl
|
||||
};
|
||||
|
||||
int
|
||||
pas_init_mixer (void)
|
||||
{
|
||||
pas_mixer_reset ();
|
||||
|
||||
if (num_mixers < MAX_MIXER_DEV)
|
||||
mixer_devs[num_mixers++] = &pas_mixer_operations;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
453
sys/i386/isa/sound/pas2_pcm.c
Normal file
453
sys/i386/isa/sound/pas2_pcm.c
Normal file
@ -0,0 +1,453 @@
|
||||
#define _PAS2_PCM_C_
|
||||
/*
|
||||
* sound/pas2_pcm.c
|
||||
*
|
||||
* The low level driver for the Pro Audio Spectrum ADC/DAC.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#include "pas.h"
|
||||
|
||||
#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO)
|
||||
|
||||
#define TRACE(WHAT) /*
|
||||
* * * (WHAT) */
|
||||
|
||||
#define PAS_PCM_INTRBITS (0x08)
|
||||
/*
|
||||
* Sample buffer timer interrupt enable
|
||||
*/
|
||||
|
||||
#define PCM_NON 0
|
||||
#define PCM_DAC 1
|
||||
#define PCM_ADC 2
|
||||
|
||||
static unsigned long pcm_speed = 0; /* sampling rate */
|
||||
static unsigned char pcm_channels = 1; /* channels (1 or 2) */
|
||||
static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */
|
||||
static unsigned char pcm_filter = 0; /* filter FLAG */
|
||||
static unsigned char pcm_mode = PCM_NON;
|
||||
static unsigned long pcm_count = 0;
|
||||
static unsigned short pcm_bitsok = 8; /* mask of OK bits */
|
||||
static int my_devnum = 0;
|
||||
|
||||
int
|
||||
pcm_set_speed (int arg)
|
||||
{
|
||||
int foo, tmp;
|
||||
unsigned long flags;
|
||||
|
||||
if (arg > 44100)
|
||||
arg = 44100;
|
||||
if (arg < 5000)
|
||||
arg = 5000;
|
||||
|
||||
foo = (1193180 + (arg / 2)) / arg;
|
||||
arg = 1193180 / foo;
|
||||
|
||||
if (pcm_channels & 2)
|
||||
foo = foo >> 1;
|
||||
|
||||
pcm_speed = arg;
|
||||
|
||||
tmp = pas_read (FILTER_FREQUENCY);
|
||||
|
||||
/*
|
||||
* Set anti-aliasing filters according to sample rate. You reall *NEED*
|
||||
* to enable this feature for all normal recording unless you want to
|
||||
* experiment with aliasing effects.
|
||||
* These filters apply to the selected "recording" source.
|
||||
* I (pfw) don't know the encoding of these 5 bits. The values shown
|
||||
* come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
|
||||
*/
|
||||
#if !defined NO_AUTO_FILTER_SET
|
||||
tmp &= 0xe0;
|
||||
if (pcm_speed >= 2 * 17897)
|
||||
tmp |= 0x21;
|
||||
else if (pcm_speed >= 2 * 15909)
|
||||
tmp |= 0x22;
|
||||
else if (pcm_speed >= 2 * 11931)
|
||||
tmp |= 0x29;
|
||||
else if (pcm_speed >= 2 * 8948)
|
||||
tmp |= 0x31;
|
||||
else if (pcm_speed >= 2 * 5965)
|
||||
tmp |= 0x39;
|
||||
else if (pcm_speed >= 2 * 2982)
|
||||
tmp |= 0x24;
|
||||
pcm_filter = tmp;
|
||||
#endif
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
|
||||
pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
|
||||
pas_write (foo & 0xff, SAMPLE_RATE_TIMER);
|
||||
pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);
|
||||
pas_write (tmp, FILTER_FREQUENCY);
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return pcm_speed;
|
||||
}
|
||||
|
||||
int
|
||||
pcm_set_channels (int arg)
|
||||
{
|
||||
|
||||
if ((arg != 1) && (arg != 2))
|
||||
return pcm_channels;
|
||||
|
||||
if (arg != pcm_channels)
|
||||
{
|
||||
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
|
||||
*/
|
||||
}
|
||||
|
||||
return pcm_channels;
|
||||
}
|
||||
|
||||
int
|
||||
pcm_set_bits (int arg)
|
||||
{
|
||||
if ((arg & pcm_bitsok) != arg)
|
||||
return pcm_bits;
|
||||
|
||||
if (arg != pcm_bits)
|
||||
{
|
||||
pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);
|
||||
|
||||
pcm_bits = arg;
|
||||
}
|
||||
|
||||
return pcm_bits;
|
||||
}
|
||||
|
||||
static int
|
||||
pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
{
|
||||
TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SOUND_PCM_WRITE_RATE:
|
||||
if (local)
|
||||
return pcm_set_speed (arg);
|
||||
return IOCTL_OUT (arg, pcm_set_speed (IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_PCM_READ_RATE:
|
||||
if (local)
|
||||
return pcm_speed;
|
||||
return IOCTL_OUT (arg, pcm_speed);
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_STEREO:
|
||||
if (local)
|
||||
return pcm_set_channels (arg + 1) - 1;
|
||||
return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg) + 1) - 1);
|
||||
break;
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
if (local)
|
||||
return pcm_set_channels (arg);
|
||||
return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_PCM_READ_CHANNELS:
|
||||
if (local)
|
||||
return pcm_channels;
|
||||
return IOCTL_OUT (arg, pcm_channels);
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_SETFMT:
|
||||
if (local)
|
||||
return pcm_set_bits (arg);
|
||||
return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_PCM_READ_BITS:
|
||||
if (local)
|
||||
return pcm_bits;
|
||||
return IOCTL_OUT (arg, pcm_bits);
|
||||
|
||||
case SOUND_PCM_WRITE_FILTER: /*
|
||||
* NOT YET IMPLEMENTED
|
||||
*/
|
||||
if (IOCTL_IN (arg) > 1)
|
||||
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
|
||||
break;
|
||||
|
||||
pcm_filter = IOCTL_IN (arg);
|
||||
case SOUND_PCM_READ_FILTER:
|
||||
return IOCTL_OUT (arg, pcm_filter);
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
pas_pcm_reset (int dev)
|
||||
{
|
||||
TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
|
||||
|
||||
pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
|
||||
}
|
||||
|
||||
static int
|
||||
pas_pcm_open (int dev, int mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
|
||||
|
||||
if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
|
||||
return err;
|
||||
|
||||
if (DMAbuf_open_dma (dev) < 0)
|
||||
{
|
||||
pas_remove_intr (PAS_PCM_INTRBITS);
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
pcm_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
pas_pcm_close (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n"));
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
pas_pcm_reset (dev);
|
||||
DMAbuf_close_dma (dev);
|
||||
pas_remove_intr (PAS_PCM_INTRBITS);
|
||||
pcm_mode = PCM_NON;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
pas_pcm_output_block (int dev, unsigned long buf, int count,
|
||||
int intrflag, int restart_dma)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
|
||||
TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
|
||||
|
||||
cnt = count;
|
||||
if (audio_devs[dev]->dmachan > 3)
|
||||
cnt >>= 1;
|
||||
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE &&
|
||||
intrflag &&
|
||||
cnt == pcm_count)
|
||||
return; /*
|
||||
* Auto mode on. No need to react
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
|
||||
PCM_CONTROL);
|
||||
|
||||
if (restart_dma)
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
|
||||
|
||||
if (audio_devs[dev]->dmachan > 3)
|
||||
count >>= 1;
|
||||
|
||||
if (count != pcm_count)
|
||||
{
|
||||
pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
|
||||
pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
|
||||
pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
|
||||
pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
|
||||
pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
|
||||
|
||||
pcm_count = count;
|
||||
}
|
||||
pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
|
||||
pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
|
||||
|
||||
pcm_mode = PCM_DAC;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
pas_pcm_start_input (int dev, unsigned long buf, int count,
|
||||
int intrflag, int restart_dma)
|
||||
{
|
||||
unsigned long flags;
|
||||
int cnt;
|
||||
|
||||
TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
|
||||
|
||||
cnt = count;
|
||||
if (audio_devs[dev]->dmachan > 3)
|
||||
cnt >>= 1;
|
||||
|
||||
if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&
|
||||
intrflag &&
|
||||
cnt == pcm_count)
|
||||
return; /*
|
||||
* Auto mode on. No need to react
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (restart_dma)
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
|
||||
|
||||
if (audio_devs[dev]->dmachan > 3)
|
||||
count >>= 1;
|
||||
|
||||
if (count != pcm_count)
|
||||
{
|
||||
pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
|
||||
pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
|
||||
pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
|
||||
pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
|
||||
pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
|
||||
|
||||
pcm_count = count;
|
||||
}
|
||||
pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
|
||||
pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
|
||||
|
||||
pcm_mode = PCM_ADC;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int
|
||||
pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct audio_operations pas_pcm_operations =
|
||||
{
|
||||
"Pro Audio Spectrum",
|
||||
DMA_AUTOMODE,
|
||||
AFMT_U8 | AFMT_S16_LE,
|
||||
NULL,
|
||||
pas_pcm_open,
|
||||
pas_pcm_close,
|
||||
pas_pcm_output_block,
|
||||
pas_pcm_start_input,
|
||||
pas_pcm_ioctl,
|
||||
pas_pcm_prepare_for_input,
|
||||
pas_pcm_prepare_for_output,
|
||||
pas_pcm_reset,
|
||||
pas_pcm_reset,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
long
|
||||
pas_pcm_init (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));
|
||||
|
||||
pcm_bitsok = 8;
|
||||
if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)
|
||||
pcm_bitsok |= 16;
|
||||
|
||||
pcm_set_speed (DSP_DEFAULT_SPEED);
|
||||
|
||||
if (num_audiodevs < MAX_AUDIO_DEV)
|
||||
{
|
||||
audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;
|
||||
audio_devs[my_devnum]->dmachan = hw_config->dma;
|
||||
audio_devs[my_devnum]->buffcount = 1;
|
||||
audio_devs[my_devnum]->buffsize = 2 * DSP_BUFFSIZE;
|
||||
}
|
||||
else
|
||||
printk ("PAS2: Too many PCM devices available\n");
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
void
|
||||
pas_pcm_interrupt (unsigned char status, int cause)
|
||||
{
|
||||
if (cause == 1) /*
|
||||
* PCM buffer done
|
||||
*/
|
||||
{
|
||||
/*
|
||||
* Halt the PCM first. Otherwise we don't have time to start a new
|
||||
* block before the PCM chip proceeds to the next sample
|
||||
*/
|
||||
|
||||
if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE))
|
||||
{
|
||||
pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
|
||||
PCM_CONTROL);
|
||||
}
|
||||
|
||||
switch (pcm_mode)
|
||||
{
|
||||
|
||||
case PCM_DAC:
|
||||
DMAbuf_outputintr (my_devnum, 1);
|
||||
break;
|
||||
|
||||
case PCM_ADC:
|
||||
DMAbuf_inputintr (my_devnum);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("PAS: Unexpected PCM interrupt\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
264
sys/i386/isa/sound/patmgr.c
Normal file
264
sys/i386/isa/sound/patmgr.c
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* sound/patmgr.c
|
||||
*
|
||||
* The patch maneger interface for the /dev/sequencer
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define PATMGR_C
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SEQUENCER)
|
||||
|
||||
DEFINE_WAIT_QUEUES (server_procs[MAX_SYNTH_DEV],
|
||||
server_wait_flag[MAX_SYNTH_DEV]);
|
||||
|
||||
static struct patmgr_info *mbox[MAX_SYNTH_DEV] =
|
||||
{NULL};
|
||||
static volatile int msg_direction[MAX_SYNTH_DEV] =
|
||||
{0};
|
||||
|
||||
static int pmgr_opened[MAX_SYNTH_DEV] =
|
||||
{0};
|
||||
|
||||
#define A_TO_S 1
|
||||
#define S_TO_A 2
|
||||
|
||||
DEFINE_WAIT_QUEUE (appl_proc, appl_wait_flag);
|
||||
|
||||
int
|
||||
pmgr_open (int dev)
|
||||
{
|
||||
if (dev < 0 || dev >= num_synths)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
if (pmgr_opened[dev])
|
||||
return RET_ERROR (EBUSY);
|
||||
pmgr_opened[dev] = 1;
|
||||
|
||||
RESET_WAIT_QUEUE (server_procs[dev], server_wait_flag[dev]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
pmgr_release (int dev)
|
||||
{
|
||||
|
||||
if (mbox[dev]) /*
|
||||
* Killed in action. Inform the client
|
||||
*/
|
||||
{
|
||||
|
||||
mbox[dev]->key = PM_ERROR;
|
||||
mbox[dev]->parm1 = RET_ERROR (EIO);
|
||||
|
||||
if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
|
||||
WAKE_UP (appl_proc, appl_wait_flag);
|
||||
}
|
||||
|
||||
pmgr_opened[dev] = 0;
|
||||
}
|
||||
|
||||
int
|
||||
pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ok = 0;
|
||||
|
||||
if (count != sizeof (struct patmgr_info))
|
||||
{
|
||||
printk ("PATMGR%d: Invalid read count\n", dev);
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
while (!ok && !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
|
||||
!PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
|
||||
{
|
||||
DO_SLEEP (server_procs[dev], server_wait_flag[dev], 0);
|
||||
}
|
||||
|
||||
if (mbox[dev] && msg_direction[dev] == A_TO_S)
|
||||
{
|
||||
COPY_TO_USER (buf, 0, (char *) mbox[dev], count);
|
||||
msg_direction[dev] = 0;
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
return RET_ERROR (EINTR);
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (count < 4)
|
||||
{
|
||||
printk ("PATMGR%d: Write count < 4\n", dev);
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
COPY_FROM_USER (mbox[dev], buf, 0, 4);
|
||||
|
||||
if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE)
|
||||
{
|
||||
int tmp_dev;
|
||||
|
||||
tmp_dev = ((unsigned short *) mbox[dev])[2];
|
||||
if (tmp_dev != dev)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev],
|
||||
buf, 4, count, 1);
|
||||
}
|
||||
|
||||
if (count != sizeof (struct patmgr_info))
|
||||
{
|
||||
printk ("PATMGR%d: Invalid write count\n", dev);
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* If everything went OK, there should be a preallocated buffer in the
|
||||
* mailbox and a client waiting.
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (mbox[dev] && !msg_direction[dev])
|
||||
{
|
||||
COPY_FROM_USER (&((char *) mbox[dev])[4], buf, 4, count - 4);
|
||||
msg_direction[dev] = S_TO_A;
|
||||
|
||||
if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
|
||||
{
|
||||
WAKE_UP (appl_proc, appl_wait_flag);
|
||||
}
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
pmgr_access (int dev, struct patmgr_info *rec)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (mbox[dev])
|
||||
printk (" PATMGR: Server %d mbox full. Why?\n", dev);
|
||||
else
|
||||
{
|
||||
rec->key = PM_K_COMMAND;
|
||||
mbox[dev] = rec;
|
||||
msg_direction[dev] = A_TO_S;
|
||||
|
||||
if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
|
||||
{
|
||||
WAKE_UP (server_procs[dev], server_wait_flag[dev]);
|
||||
}
|
||||
|
||||
DO_SLEEP (appl_proc, appl_wait_flag, 0);
|
||||
|
||||
if (msg_direction[dev] != S_TO_A)
|
||||
{
|
||||
rec->key = PM_ERROR;
|
||||
rec->parm1 = RET_ERROR (EIO);
|
||||
}
|
||||
else if (rec->key == PM_ERROR)
|
||||
{
|
||||
err = rec->parm1;
|
||||
if (err > 0)
|
||||
err = -err;
|
||||
}
|
||||
|
||||
mbox[dev] = NULL;
|
||||
msg_direction[dev] = 0;
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2,
|
||||
unsigned long p3, unsigned long p4)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
if (!pmgr_opened[dev])
|
||||
return 0;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (mbox[dev])
|
||||
printk (" PATMGR: Server %d mbox full. Why?\n", dev);
|
||||
else
|
||||
{
|
||||
mbox[dev] =
|
||||
(struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info));
|
||||
|
||||
mbox[dev]->key = PM_K_EVENT;
|
||||
mbox[dev]->command = event;
|
||||
mbox[dev]->parm1 = p1;
|
||||
mbox[dev]->parm2 = p2;
|
||||
mbox[dev]->parm3 = p3;
|
||||
msg_direction[dev] = A_TO_S;
|
||||
|
||||
if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
|
||||
{
|
||||
WAKE_UP (server_procs[dev], server_wait_flag[dev]);
|
||||
}
|
||||
|
||||
DO_SLEEP (appl_proc, appl_wait_flag, 0);
|
||||
if (mbox[dev])
|
||||
KERNEL_FREE (mbox[dev]);
|
||||
mbox[dev] = NULL;
|
||||
msg_direction[dev] = 0;
|
||||
}
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
924
sys/i386/isa/sound/pss.c
Normal file
924
sys/i386/isa/sound/pss.c
Normal file
@ -0,0 +1,924 @@
|
||||
/* Marc.Hoffman@analog.com
|
||||
|
||||
This is a pss driver.
|
||||
|
||||
it is based on Greg.Yukna@analog.com @file{host} for DOG
|
||||
|
||||
Unfortunately I can't distribute the ld file needed to
|
||||
make the pss card to emulate the SB stuff.
|
||||
|
||||
I have provided a simple interface to the PSS unlike the
|
||||
DOG version. to download a new algorithim just cat it to
|
||||
/dev/pss 14,9.
|
||||
|
||||
You really need to rebuild this with the synth.ld file
|
||||
|
||||
get the <synth>.ld from your dos directory maybe
|
||||
voyetra\dsp001.ld
|
||||
|
||||
ld2inc < synth.ld > synth-ld.h
|
||||
(make config does the same).
|
||||
|
||||
rebuild
|
||||
|
||||
Okay if you blow things away no problem just
|
||||
|
||||
main(){ioctl(open("/dev/pss"),SNDCTL_PSS_RESET)};
|
||||
|
||||
and everything will be okay.
|
||||
|
||||
At first I was going to wory about applications that were using
|
||||
the sound stuff and disallow the use of /dev/pss. But for
|
||||
now I figured it doesn't matter.
|
||||
|
||||
And if you change algos all the other applications running die off
|
||||
due to DMA problems. Yeah just pull the plug and watch em die.
|
||||
|
||||
If the registers get hosed
|
||||
main(){ioctl(open("/dev/pss"),SNDCTL_PSS_SETUP_REGISTERS)};
|
||||
|
||||
Probably everything else can be done via mmap
|
||||
|
||||
Oh if you want to develope code for the ADSP-21xx or Program the
|
||||
1848 just send me mail and I will hook you up.
|
||||
|
||||
marc.hoffman@analog.com
|
||||
|
||||
*/
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS)
|
||||
|
||||
#ifndef PSS_MSS_BASE
|
||||
#define PSS_MSS_BASE 0
|
||||
#endif
|
||||
|
||||
#ifndef PSS_MPU_BASE
|
||||
#define PSS_MPU_BASE 0
|
||||
#endif
|
||||
|
||||
#ifndef PSS_MPU_IRQ
|
||||
#define PSS_MPU_IRQ 0
|
||||
#endif
|
||||
|
||||
#undef DEB
|
||||
#define DEB(x) x
|
||||
|
||||
#include "pss.h"
|
||||
|
||||
static int pss_ok = 0;
|
||||
static int sb_ok = 0;
|
||||
|
||||
static int pss_base;
|
||||
static int pss_irq;
|
||||
static int pss_dma;
|
||||
|
||||
static int gamePort = 0;
|
||||
|
||||
static int sbInt;
|
||||
static int cdPol;
|
||||
static int cdAddr = 0; /* 0x340; */
|
||||
static int cdInt = 10;
|
||||
|
||||
/* Define these by hand in local.h */
|
||||
static int wssAddr = PSS_MSS_BASE;
|
||||
static int midiAddr = PSS_MPU_BASE;
|
||||
static int midiInt = PSS_MPU_IRQ;
|
||||
|
||||
static int SoundPortAddress;
|
||||
static int SoundPortData;
|
||||
static int speaker = 1;
|
||||
|
||||
|
||||
static struct pss_speaker default_speaker =
|
||||
{0, 0, 0, PSS_STEREO};
|
||||
|
||||
DEFINE_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
|
||||
|
||||
#include "synth-ld.h"
|
||||
|
||||
static int pss_download_boot (unsigned char *block, int size);
|
||||
static int pss_reset_dsp (void);
|
||||
|
||||
static inline void
|
||||
pss_outpw (unsigned short port, unsigned short value)
|
||||
{
|
||||
__asm__ __volatile__ ("outw %w0, %w1"
|
||||
: /* no outputs */
|
||||
:"a" (value), "d" (port));
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
pss_inpw (unsigned short port)
|
||||
{
|
||||
unsigned int _v;
|
||||
__asm__ __volatile__ ("inw %w1,%w0"
|
||||
:"=a" (_v):"d" (port), "0" (0));
|
||||
|
||||
return _v;
|
||||
}
|
||||
|
||||
static void
|
||||
PSS_write (int data)
|
||||
{
|
||||
int i, limit;
|
||||
|
||||
limit = GET_TIME () + 10; /* The timeout is 0.1 secods */
|
||||
/*
|
||||
* Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
|
||||
* called while interrupts are disabled. This means that the timer is
|
||||
* disabled also. However the timeout situation is a abnormal condition.
|
||||
* Normally the DSP should be ready to accept commands after just couple of
|
||||
* loops.
|
||||
*/
|
||||
|
||||
for (i = 0; i < 5000000 && GET_TIME () < limit; i++)
|
||||
{
|
||||
if (pss_inpw (pss_base + PSS_STATUS) & PSS_WRITE_EMPTY)
|
||||
{
|
||||
pss_outpw (pss_base + PSS_DATA, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
printk ("PSS: DSP Command (%04x) Timeout.\n", data);
|
||||
printk ("IRQ conflict???\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pss_setaddr (int addr, int configAddr)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = pss_inpw (configAddr);
|
||||
val &= ADDR_MASK;
|
||||
val |= (addr << 4);
|
||||
pss_outpw (configAddr, val);
|
||||
}
|
||||
|
||||
/*_____ pss_checkint
|
||||
This function tests an interrupt number to see if
|
||||
it is availible. It takes the interrupt button
|
||||
as it's argument and returns TRUE if the interrupt
|
||||
is ok.
|
||||
*/
|
||||
static int
|
||||
pss_checkint (int intNum)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/*_____ Set the interrupt bits */
|
||||
switch (intNum)
|
||||
{
|
||||
case 3:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_3_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 5:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_5_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 7:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_7_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 9:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_9_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 10:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_10_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 11:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_11_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 12:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_12_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
default:
|
||||
printk ("unknown interupt selected. %d\n", intNum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*_____ Set the interrupt test bit */
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val |= INT_TEST_BIT;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
|
||||
/*_____ Check if the interrupt is in use */
|
||||
/*_____ Do it a few times in case there is a delay */
|
||||
ret = 0;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
if (val & INT_TEST_PASS)
|
||||
{
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*_____ Clear the Test bit and the interrupt bits */
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_TEST_BIT_MASK;
|
||||
val &= INT_MASK;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*____ pss_setint
|
||||
This function sets the correct bits in the
|
||||
configuration register to
|
||||
enable the chosen interrupt.
|
||||
*/
|
||||
static void
|
||||
pss_setint (int intNum, int configAddress)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (intNum)
|
||||
{
|
||||
case 0:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 3:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_3_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 5:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_5_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 7:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_7_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 9:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_9_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 10:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_10_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 11:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_11_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 12:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_12_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
default:
|
||||
printk ("pss_setint unkown int\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*____ pss_setsbint
|
||||
This function sets the correct bits in the
|
||||
SoundBlaster configuration PSS register to
|
||||
enable the chosen interrupt.
|
||||
It takes a interrupt button as its argument.
|
||||
*/
|
||||
static void
|
||||
pss_setsbint (int intNum)
|
||||
{
|
||||
int val;
|
||||
int sbConfigAddress;
|
||||
|
||||
sbConfigAddress = pss_base + SB_CONFIG;
|
||||
switch (intNum)
|
||||
{
|
||||
case 3:
|
||||
val = pss_inpw (sbConfigAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_3_BITS;
|
||||
pss_outpw (sbConfigAddress, val);
|
||||
break;
|
||||
case 5:
|
||||
val = pss_inpw (sbConfigAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_5_BITS;
|
||||
pss_outpw (sbConfigAddress, val);
|
||||
break;
|
||||
case 7:
|
||||
val = pss_inpw (sbConfigAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_7_BITS;
|
||||
pss_outpw (sbConfigAddress, val);
|
||||
break;
|
||||
default:
|
||||
printk ("pss_setsbint: unknown_int\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*____ pss_setsbdma
|
||||
This function sets the correct bits in the
|
||||
SoundBlaster configuration PSS register to
|
||||
enable the chosen DMA channel.
|
||||
It takes a DMA button as its argument.
|
||||
*/
|
||||
static void
|
||||
pss_setsbdma (int dmaNum)
|
||||
{
|
||||
int val;
|
||||
int sbConfigAddress;
|
||||
|
||||
sbConfigAddress = pss_base + SB_CONFIG;
|
||||
|
||||
switch (dmaNum)
|
||||
{
|
||||
case 1:
|
||||
val = pss_inpw (sbConfigAddress);
|
||||
val &= DMA_MASK;
|
||||
val |= DMA_1_BITS;
|
||||
pss_outpw (sbConfigAddress, val);
|
||||
break;
|
||||
default:
|
||||
printk ("Personal Sound System ERROR! pss_setsbdma: unknown_dma\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*____ pss_setwssdma
|
||||
This function sets the correct bits in the
|
||||
WSS configuration PSS register to
|
||||
enable the chosen DMA channel.
|
||||
It takes a DMA button as its argument.
|
||||
*/
|
||||
static void
|
||||
pss_setwssdma (int dmaNum)
|
||||
{
|
||||
int val;
|
||||
int wssConfigAddress;
|
||||
|
||||
wssConfigAddress = pss_base + PSS_WSS_CONFIG;
|
||||
|
||||
switch (dmaNum)
|
||||
{
|
||||
case 0:
|
||||
val = pss_inpw (wssConfigAddress);
|
||||
val &= DMA_MASK;
|
||||
val |= DMA_0_BITS;
|
||||
pss_outpw (wssConfigAddress, val);
|
||||
break;
|
||||
case 1:
|
||||
val = pss_inpw (wssConfigAddress);
|
||||
val &= DMA_MASK;
|
||||
val |= DMA_1_BITS;
|
||||
pss_outpw (wssConfigAddress, val);
|
||||
break;
|
||||
case 3:
|
||||
val = pss_inpw (wssConfigAddress);
|
||||
val &= DMA_MASK;
|
||||
val |= DMA_3_BITS;
|
||||
pss_outpw (wssConfigAddress, val);
|
||||
break;
|
||||
default:
|
||||
printk ("Personal Sound System ERROR! pss_setwssdma: unknown_dma\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*_____ SetSpeakerOut
|
||||
This function sets the Volume, Bass, Treble and Mode of
|
||||
the speaker out channel.
|
||||
*/
|
||||
void
|
||||
pss_setspeaker (struct pss_speaker *spk)
|
||||
{
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
if (spk->volume > PHILLIPS_VOL_MAX)
|
||||
spk->volume = PHILLIPS_VOL_MAX;
|
||||
if (spk->volume < PHILLIPS_VOL_MIN)
|
||||
spk->volume = PHILLIPS_VOL_MIN;
|
||||
|
||||
PSS_write (MASTER_VOLUME_LEFT
|
||||
| (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
PSS_write (MASTER_VOLUME_RIGHT
|
||||
| (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
|
||||
|
||||
if (spk->bass > PHILLIPS_BASS_MAX)
|
||||
spk->bass = PHILLIPS_BASS_MAX;
|
||||
if (spk->bass < PHILLIPS_BASS_MIN)
|
||||
spk->bass = PHILLIPS_BASS_MIN;
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
PSS_write (MASTER_BASS
|
||||
| (PHILLIPS_BASS_CONSTANT + spk->bass / PHILLIPS_BASS_STEP));
|
||||
|
||||
if (spk->treb > PHILLIPS_TREBLE_MAX)
|
||||
spk->treb = PHILLIPS_TREBLE_MAX;
|
||||
if (spk->treb < PHILLIPS_TREBLE_MIN)
|
||||
spk->treb = PHILLIPS_TREBLE_MIN;
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
PSS_write (MASTER_TREBLE
|
||||
| (PHILLIPS_TREBLE_CONSTANT + spk->treb / PHILLIPS_TREBLE_STEP));
|
||||
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
PSS_write (MASTER_SWITCH | spk->mode);
|
||||
}
|
||||
|
||||
static void
|
||||
pss_init1848 (void)
|
||||
{
|
||||
/*_____ Wait for 1848 to init */
|
||||
while (INB (SoundPortAddress) & SP_IN_INIT);
|
||||
|
||||
/*_____ Wait for 1848 to autocal */
|
||||
OUTB (SoundPortAddress, SP_TEST_AND_INIT);
|
||||
while (INB (SoundPortData) & AUTO_CAL_IN_PROG);
|
||||
}
|
||||
|
||||
static int
|
||||
pss_configure_registers_to_look_like_sb (void)
|
||||
{
|
||||
pss_setaddr (wssAddr, pss_base + PSS_WSS_CONFIG);
|
||||
|
||||
SoundPortAddress = wssAddr + 4;
|
||||
SoundPortData = wssAddr + 5;
|
||||
|
||||
DEB (printk ("Turning Game Port %s.\n",
|
||||
gamePort ? "On" : "Off"));
|
||||
|
||||
/*_____ Turn on the Game port */
|
||||
if (gamePort)
|
||||
pss_outpw (pss_base + PSS_STATUS,
|
||||
pss_inpw (pss_base + PSS_STATUS) | GAME_BIT);
|
||||
else
|
||||
pss_outpw (pss_base + PSS_STATUS,
|
||||
pss_inpw (pss_base + PSS_STATUS) & GAME_BIT_MASK);
|
||||
|
||||
|
||||
DEB (printk ("PSS attaching base %x irq %d dma %d\n",
|
||||
pss_base, pss_irq, pss_dma));
|
||||
|
||||
/* Check if sb is enabled if it is check the interrupt */
|
||||
pss_outpw (pss_base + SB_CONFIG, 0);
|
||||
|
||||
if (pss_irq != 0)
|
||||
{
|
||||
DEB (printk ("PSS Emulating Sound Blaster ADDR %04x\n", pss_base));
|
||||
DEB (printk ("PSS SBC: attaching base %x irq %d dma %d\n",
|
||||
SBC_BASE, SBC_IRQ, SBC_DMA));
|
||||
|
||||
if (pss_checkint (SBC_IRQ) == 0)
|
||||
{
|
||||
printk ("PSS! attach: int_error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pss_setsbint (SBC_IRQ);
|
||||
pss_setsbdma (SBC_DMA);
|
||||
sb_ok = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_ok = 0;
|
||||
printk ("PSS: sound blaster error init\n");
|
||||
}
|
||||
|
||||
/* Check if cd is enabled if it is check the interrupt */
|
||||
pss_outpw (pss_base + CD_CONFIG, 0);
|
||||
|
||||
if (cdAddr != 0)
|
||||
{
|
||||
DEB (printk ("PSS:CD drive %x irq: %d", cdAddr, cdInt));
|
||||
if (cdInt != 0)
|
||||
{
|
||||
if (pss_checkint (cdInt) == 0)
|
||||
{
|
||||
printk ("Can't allocate cdInt %d\n", cdInt);
|
||||
}
|
||||
else
|
||||
{
|
||||
int val;
|
||||
|
||||
printk ("CD poll ");
|
||||
pss_setaddr (cdAddr, pss_base + CD_CONFIG);
|
||||
pss_setint (cdInt, pss_base + CD_CONFIG);
|
||||
|
||||
/* set the correct bit in the
|
||||
configuration register to
|
||||
set the irq polarity for the CD-Rom.
|
||||
NOTE: This bit is in the address config
|
||||
field, It must be configured after setting
|
||||
the CD-ROM ADDRESS!!! */
|
||||
val = pss_inpw (pss_base + CD_CONFIG);
|
||||
pss_outpw (pss_base + CD_CONFIG, 0);
|
||||
val &= CD_POL_MASK;
|
||||
if (cdPol)
|
||||
val |= CD_POL_BIT;
|
||||
pss_outpw (pss_base + CD_CONFIG, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if midi is enabled if it is check the interrupt */
|
||||
pss_outpw (pss_base + MIDI_CONFIG, 0);
|
||||
if (midiAddr != 0)
|
||||
{
|
||||
printk ("midi init %x %d\n", midiAddr, midiInt);
|
||||
if (pss_checkint (midiInt) == 0)
|
||||
{
|
||||
printk ("midi init int error %x %d\n", midiAddr, midiInt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pss_setaddr (midiAddr, pss_base + MIDI_CONFIG);
|
||||
pss_setint (midiInt, pss_base + MIDI_CONFIG);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
attach_pss (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
if (pss_ok)
|
||||
{
|
||||
if (hw_config)
|
||||
{
|
||||
printk (" <PSS-ESC614>");
|
||||
}
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
pss_ok = 1;
|
||||
|
||||
if (pss_configure_registers_to_look_like_sb () == 0)
|
||||
return mem_start;
|
||||
|
||||
if (sb_ok)
|
||||
if (pss_synthLen
|
||||
&& pss_download_boot (pss_synth, pss_synthLen))
|
||||
{
|
||||
if (speaker)
|
||||
pss_setspeaker (&default_speaker);
|
||||
pss_ok = 1;
|
||||
}
|
||||
else
|
||||
pss_reset_dsp ();
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
probe_pss (struct address_info *hw_config)
|
||||
{
|
||||
pss_base = hw_config->io_base;
|
||||
pss_irq = hw_config->irq;
|
||||
pss_dma = hw_config->dma;
|
||||
|
||||
if ((pss_inpw (pss_base + 4) & 0xff00) == 0x4500)
|
||||
{
|
||||
attach_pss (0, hw_config);
|
||||
return 1;
|
||||
}
|
||||
printk (" fail base %x irq %d dma %d\n", pss_base, pss_irq, pss_dma);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pss_reattach (void)
|
||||
{
|
||||
pss_ok = 0;
|
||||
attach_pss (0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pss_reset_dsp ()
|
||||
{
|
||||
unsigned long i, limit = GET_TIME () + 10;
|
||||
|
||||
pss_outpw (pss_base + PSS_CONTROL, 0x2000);
|
||||
|
||||
for (i = 0; i < 32768 && GET_TIME () < limit; i++)
|
||||
pss_inpw (pss_base + PSS_CONTROL);
|
||||
|
||||
pss_outpw (pss_base + PSS_CONTROL, 0x0000);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pss_download_boot (unsigned char *block, int size)
|
||||
{
|
||||
int i, limit, val, count;
|
||||
|
||||
printk ("PSS: downloading boot code synth.ld... ");
|
||||
|
||||
/*_____ Warn DSP software that a boot is coming */
|
||||
pss_outpw (pss_base + PSS_DATA, 0x00fe);
|
||||
|
||||
limit = GET_TIME () + 10;
|
||||
|
||||
for (i = 0; i < 32768 && GET_TIME () < limit; i++)
|
||||
if (pss_inpw (pss_base + PSS_DATA) == 0x5500)
|
||||
break;
|
||||
|
||||
pss_outpw (pss_base + PSS_DATA, *block++);
|
||||
|
||||
pss_reset_dsp ();
|
||||
printk ("start ");
|
||||
|
||||
count = 1;
|
||||
while (1)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 327670; j++)
|
||||
{
|
||||
/*_____ Wait for BG to appear */
|
||||
if (pss_inpw (pss_base + PSS_STATUS) & PSS_FLAG3)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == 327670)
|
||||
{
|
||||
/* It's ok we timed out when the file was empty */
|
||||
if (count >= size)
|
||||
break;
|
||||
else
|
||||
{
|
||||
printk ("\nPSS: DownLoad timeout problems, byte %d=%d\n",
|
||||
count, size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*_____ Send the next byte */
|
||||
pss_outpw (pss_base + PSS_DATA, *block++);
|
||||
count++;
|
||||
}
|
||||
|
||||
/*_____ Why */
|
||||
pss_outpw (pss_base + PSS_DATA, 0);
|
||||
|
||||
limit = GET_TIME () + 10;
|
||||
for (i = 0; i < 32768 && GET_TIME () < limit; i++)
|
||||
val = pss_inpw (pss_base + PSS_STATUS);
|
||||
|
||||
printk ("downloaded\n");
|
||||
|
||||
limit = GET_TIME () + 10;
|
||||
for (i = 0; i < 32768 && GET_TIME () < limit; i++)
|
||||
{
|
||||
val = pss_inpw (pss_base + PSS_STATUS);
|
||||
if (val & 0x4000)
|
||||
break;
|
||||
}
|
||||
|
||||
/* now read the version */
|
||||
for (i = 0; i < 32000; i++)
|
||||
{
|
||||
val = pss_inpw (pss_base + PSS_STATUS_REG);
|
||||
if (val & PSS_READ_FULL)
|
||||
break;
|
||||
}
|
||||
if (i == 32000)
|
||||
return 0;
|
||||
|
||||
val = pss_inpw (pss_base + PSS_DATA_REG);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* The following is a simple device driver for the pss.
|
||||
All I really care about is comunication to and from the pss.
|
||||
|
||||
The ability to reinitialize the <synth.ld> This will be
|
||||
default when release is choosen.
|
||||
|
||||
SNDCTL_PSS_DOWNLOAD:
|
||||
|
||||
Okay we need to creat new minor numbers for the
|
||||
DOWNLOAD functionality.
|
||||
|
||||
14,0x19 -- /dev/pssld where a read operation would output the
|
||||
current ld to user space
|
||||
where a write operation would effectively
|
||||
download a new ld.
|
||||
|
||||
14,0x09 -- /dev/psecho would open up a comunication path to the
|
||||
esc614 asic. Given the ability to send
|
||||
messages to the asic and recive messages too.
|
||||
|
||||
All messages would get read and written in the
|
||||
same manner. It would be up to the application
|
||||
and the ld to maintain a relationship
|
||||
of what the messages mean.
|
||||
|
||||
for this device we need to implement select. */
|
||||
#define CODE_BUFFER_LEN (64*1024)
|
||||
static char *code_buffer;
|
||||
static int code_length;
|
||||
|
||||
static int lock_pss = 0;
|
||||
|
||||
int
|
||||
pss_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
int mode;
|
||||
|
||||
DEB (printk ("pss_open\n"));
|
||||
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
if (lock_pss)
|
||||
return 0;
|
||||
|
||||
lock_pss = 1;
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
if (mode == O_WRONLY)
|
||||
{
|
||||
printk ("pss-open for WRONLY\n");
|
||||
code_length = 0;
|
||||
}
|
||||
|
||||
RESET_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
pss_release (int dev, struct fileinfo *file)
|
||||
{
|
||||
int mode;
|
||||
|
||||
DEB (printk ("pss_release\n"));
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
if (mode == O_WRONLY && code_length > 0)
|
||||
{
|
||||
#ifdef linux
|
||||
/* This just allows interrupts while the conversion is running */
|
||||
__asm__ ("sti");
|
||||
#endif
|
||||
if (!pss_download_boot (code_buffer, code_length))
|
||||
{
|
||||
pss_reattach ();
|
||||
}
|
||||
}
|
||||
lock_pss = 0;
|
||||
}
|
||||
|
||||
int
|
||||
pss_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
int c, p;
|
||||
|
||||
DEB (printk ("pss_read\n"));
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
p = 0;
|
||||
c = count;
|
||||
|
||||
return count - c;
|
||||
}
|
||||
|
||||
int
|
||||
pss_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
DEB (printk ("pss_write\n"));
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
dev = dev >> 4;
|
||||
|
||||
if (count) /* Flush output */
|
||||
{
|
||||
COPY_FROM_USER (&code_buffer[code_length], buf, 0, count);
|
||||
code_length += count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pss_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
DEB (printk ("pss_ioctl dev=%d cmd=%x\n", dev, cmd));
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SNDCTL_PSS_RESET:
|
||||
pss_reattach ();
|
||||
return 1;
|
||||
|
||||
case SNDCTL_PSS_SETUP_REGISTERS:
|
||||
pss_configure_registers_to_look_like_sb ();
|
||||
return 1;
|
||||
|
||||
case SNDCTL_PSS_SPEAKER:
|
||||
{
|
||||
struct pss_speaker params;
|
||||
COPY_FROM_USER (¶ms, (char *) arg, 0, sizeof (struct pss_speaker));
|
||||
|
||||
pss_setspeaker (¶ms);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is going to be used to implement
|
||||
waiting on messages sent from the DSP and to the
|
||||
DSP when comunication is used via the pss directly.
|
||||
|
||||
We need to find out if the pss can generate a diffrent
|
||||
interupt other than the one it has been setup for.
|
||||
|
||||
This way we can carry on a conversation with the pss
|
||||
on a seprate chanel. This would be usefull for debugging. */
|
||||
|
||||
pss_select (int dev, struct fileinfo * file, int sel_type, select_table * wait)
|
||||
{
|
||||
return 0;
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
switch (sel_type)
|
||||
{
|
||||
case SEL_IN:
|
||||
select_wait (&pss_sleeper, wait);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SEL_OUT:
|
||||
select_wait (&pss_sleeper, wait);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SEL_EX:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
pss_init (long mem_start)
|
||||
{
|
||||
DEB (printk ("pss_init\n"));
|
||||
if (pss_ok)
|
||||
{
|
||||
code_buffer = mem_start;
|
||||
mem_start += CODE_BUFFER_LEN;
|
||||
}
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
371
sys/i386/isa/sound/pss.h
Normal file
371
sys/i386/isa/sound/pss.h
Normal file
@ -0,0 +1,371 @@
|
||||
/******************************************************************************
|
||||
|
||||
def.h
|
||||
|
||||
Version 1.3 11/2/93
|
||||
|
||||
Copyright (c) 1993 Analog Devices Inc. All rights reserved
|
||||
|
||||
******************************************************************************/
|
||||
/* Port offsets from base port for Sound Blaster DSP */
|
||||
#define DSP_PORT_CMSD0 0x00 /* C/MS music voice 1-6 data port, write only */
|
||||
#define DSP_PORT_CMSR0 0x01 /* C/MS music voice 1-6 register port, write only */
|
||||
#define DSP_PORT_CMSD1 0x02 /* C/MS music voice 7-12 data port, write only */
|
||||
#define DSP_PORT_CMSR1 0x03 /* C/MS music voice 7-12 register port, write only */
|
||||
|
||||
#define DSP_PORT_STATUS 0x04 /* DSP Status bits, read only */
|
||||
#define DSP_PORT_CONTROL 0x04 /* DSP Control bits, write only */
|
||||
#define DSP_PORT_DATA_LSB 0x05 /* Read or write LSB of 16 bit data */
|
||||
|
||||
|
||||
#define DSP_PORT_RESET 0x06 /* DSP Reset, write only */
|
||||
#define DSP_PORT_07h 0x07 /* reserved port */
|
||||
|
||||
#define DSP_PORT_FMD0 0x08 /* FM music data/status port, read/write */
|
||||
#define DSP_PORT_FMR0 0x09 /* FM music data/status port, write only */
|
||||
|
||||
#define DSP_PORT_RDDATA 0x0A /* DSP Read data, read only reading signals DSP */
|
||||
#define DSP_PORT_0Bh 0x0B /* reserved port */
|
||||
#define DSP_PORT_WRDATA 0x0C /* DSP Write data or command, write */
|
||||
#define DSP_PORT_WRBUSY 0x0C /* DSP Write buffer status (bit 7), read */
|
||||
#define DSP_PORT_0Dh 0x0D /* reserved port */
|
||||
#define DSP_PORT_DATAAVAIL 0x0E /* DSP Data available status (bit 7), read only */
|
||||
#define DSP_PORT_INTERFACE 0x0E /* Sets DMA Channel and Interrupt, write only */
|
||||
#define DSP_PORT_0Fh 0x0F /* reserved port (used on Pro cards) */
|
||||
|
||||
#define ADDR_MASK 0x003f
|
||||
|
||||
#define INT_MASK 0xffc7
|
||||
#define INT_3_BITS 0x0008
|
||||
#define INT_5_BITS 0x0010
|
||||
#define INT_7_BITS 0x0018
|
||||
#define INT_9_BITS 0x0020
|
||||
#define INT_10_BITS 0x0028
|
||||
#define INT_11_BITS 0x0030
|
||||
#define INT_12_BITS 0x0038
|
||||
|
||||
#define GAME_BIT 0x0400
|
||||
#define GAME_BIT_MASK 0xfbff
|
||||
|
||||
#define INT_TEST_BIT 0x0200
|
||||
#define INT_TEST_PASS 0x0100
|
||||
#define INT_TEST_BIT_MASK 0xFDFF
|
||||
|
||||
#define DMA_MASK 0xfff8
|
||||
#define DMA_0_BITS 0x0001
|
||||
#define DMA_1_BITS 0x0002
|
||||
#define DMA_3_BITS 0x0003
|
||||
#define DMA_5_BITS 0x0004
|
||||
#define DMA_6_BITS 0x0005
|
||||
#define DMA_7_BITS 0x0006
|
||||
|
||||
#define DMA_TEST_BIT 0x0080
|
||||
#define DMA_TEST_PASS 0x0040
|
||||
#define DMA_TEST_BIT_MASK 0xFF7F
|
||||
|
||||
|
||||
/* Echo DSP Flags */
|
||||
|
||||
#define DSP_FLAG3 0x10
|
||||
#define DSP_FLAG2 0x08
|
||||
#define DSP_FLAG1 0x80
|
||||
#define DSP_FLAG0 0x40
|
||||
|
||||
#define PSS_CONFIG 0x10
|
||||
#define PSS_WSS_CONFIG 0x12
|
||||
#define SB_CONFIG 0x14
|
||||
#define MIDI_CONFIG 0x18
|
||||
#define CD_CONFIG 0x16
|
||||
#define UART_CONFIG 0x1a
|
||||
|
||||
#define PSS_DATA 0x00
|
||||
#define PSS_STATUS 0x02
|
||||
#define PSS_CONTROL 0x02
|
||||
#define PSS_ID_VERS 0x04
|
||||
|
||||
#define PSS_FLAG3 0x0800
|
||||
#define PSS_FLAG2 0x0400
|
||||
#define PSS_FLAG1 0x1000
|
||||
#define PSS_FLAG0 0x0800
|
||||
|
||||
/*_____ WSS defines */
|
||||
#define WSS_BASE_ADDRESS 0x530
|
||||
#define WSS_CONFIG 0x0
|
||||
#define WSS_VERSION 0x03
|
||||
#define WSS_SP0 0x04
|
||||
#define WSS_SP1 0x05
|
||||
#define WSS_SP2 0x06
|
||||
#define WSS_SP3 0x07
|
||||
|
||||
/*_____ SoundPort register addresses */
|
||||
|
||||
#define SP_LIN_SOURCE_CTRL 0x00
|
||||
#define SP_RIN_SOURCE_CTRL 0x01
|
||||
#define SP_LIN_GAIN_CTRL 0x10
|
||||
#define SP_RIN_GAIN_CTRL 0x11
|
||||
#define SP_LAUX1_CTRL 0x02
|
||||
#define SP_RAUX1_CTRL 0x03
|
||||
#define SP_LAUX2_CTRL 0x04
|
||||
#define SP_RAUX2_CTRL 0x05
|
||||
#define SP_LOUT_CTRL 0x06
|
||||
#define SP_ROUT_CTRL 0x07
|
||||
#define SP_CLK_FORMAT 0x48
|
||||
#define SP_INT_CONF 0x09
|
||||
#define SP_INT_CONF_MCE 0x49
|
||||
#define SP_PIN_CTRL 0x0a
|
||||
#define SP_TEST_INIT 0x0b
|
||||
#define SP_MISC_CTRL 0x0c
|
||||
#define SP_MIX_CTRL 0x0d
|
||||
#define SP_DMA_UCNT 0x0e
|
||||
#define SP_DMA_LCNT 0x0f
|
||||
|
||||
/*_____ Gain constants */
|
||||
|
||||
#define GAIN_0 0x00
|
||||
#define GAIN_1_5 0x01
|
||||
#define GAIN_3 0x02
|
||||
#define GAIN_4_5 0x03
|
||||
#define GAIN_6 0x04
|
||||
#define GAIN_7_5 0x05
|
||||
#define GAIN_9 0x06
|
||||
#define GAIN_10_5 0x07
|
||||
#define GAIN_12 0x08
|
||||
#define GAIN_13_5 0x09
|
||||
#define GAIN_15 0x0a
|
||||
#define GAIN_16_5 0x0b
|
||||
#define GAIN_18 0x0c
|
||||
#define GAIN_19_5 0x0d
|
||||
#define GAIN_21 0x0e
|
||||
#define GAIN_22_5 0x0f
|
||||
#define MUTE 0XFFFF
|
||||
|
||||
/*_____ Attenuation constants */
|
||||
|
||||
#define ATTEN_0 0x00
|
||||
#define ATTEN_1_5 0x01
|
||||
#define ATTEN_3 0x02
|
||||
#define ATTEN_4_5 0x03
|
||||
#define ATTEN_6 0x04
|
||||
#define ATTEN_7_5 0x05
|
||||
#define ATTEN_9 0x06
|
||||
#define ATTEN_10_5 0x07
|
||||
#define ATTEN_12 0x08
|
||||
#define ATTEN_13_5 0x09
|
||||
#define ATTEN_15 0x0a
|
||||
#define ATTEN_16_5 0x0b
|
||||
#define ATTEN_18 0x0c
|
||||
#define ATTEN_19_5 0x0d
|
||||
#define ATTEN_21 0x0e
|
||||
#define ATTEN_22_5 0x0f
|
||||
|
||||
|
||||
#define PSS_WRITE_EMPTY 0x8000
|
||||
|
||||
#define CD_POL_MASK 0xFFBF
|
||||
#define CD_POL_BIT 0x0040
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
host.h
|
||||
|
||||
Version 1.2 9/27/93
|
||||
|
||||
Copyright (c) 1993 Analog Devices Inc. All rights reserved
|
||||
|
||||
******************************************************************************/
|
||||
#define SB_WRITE_FULL 0x80
|
||||
#define SB_READ_FULL 0x80
|
||||
#define SB_WRITE_STATUS 0x0C
|
||||
#define SB_READ_STATUS 0x0E
|
||||
#define SB_READ_DATA 0x0A
|
||||
#define SB_WRITE_DATA 0x0C
|
||||
|
||||
#define PSS_DATA_REG 0x00
|
||||
#define PSS_STATUS_REG 0x02
|
||||
#define PSS_WRITE_EMPTY 0x8000
|
||||
#define PSS_READ_FULL 0x4000
|
||||
|
||||
/*_____ 1848 Sound Port bit defines */
|
||||
|
||||
#define SP_IN_INIT 0x80
|
||||
#define MODE_CHANGE_ENABLE 0x40
|
||||
#define MODE_CHANGE_MASK 0xbf
|
||||
#define TRANSFER_DISABLE 0x20
|
||||
#define TRANSFER_DISABLE_MASK 0xdf
|
||||
#define ADDRESS_MASK 0xf0
|
||||
|
||||
/*_____ Status bits */
|
||||
#define INTERRUPT_STATUS 0x01
|
||||
#define PLAYBACK_READY 0x02
|
||||
#define PLAYBACK_LEFT 0x04
|
||||
/*_____ pbright is not left */
|
||||
#define PLAYBACK_UPPER 0x08
|
||||
/*_____ bplower is not upper */
|
||||
|
||||
#define SAMPLE_OVERRUN 0x10
|
||||
#define SAMPLE_UNDERRUN 0x10
|
||||
#define CAPTURE_READY 0x20
|
||||
#define CAPTURE_LEFT 0x40
|
||||
/*_____ cpright is not left */
|
||||
#define CAPTURE_UPPER 0x08
|
||||
/*_____ cplower is not upper */
|
||||
|
||||
/*_____ Input & Output regs bits */
|
||||
#define LINE_INPUT 0x80
|
||||
#define AUX_INPUT 0x40
|
||||
#define MIC_INPUT 0x80
|
||||
#define MIXED_DAC_INPUT 0xC0
|
||||
#define INPUT_GAIN_MASK 0xf0
|
||||
#define INPUT_MIC_GAIN_ENABLE 0x20
|
||||
#define INPUT_MIC_GAIN_MASK 0xdf
|
||||
#define INPUT_SOURCE_MASK 0x3f
|
||||
#define AUX_INPUT_ATTEN_MASK 0xf0
|
||||
#define AUX_INPUT_MUTE 0x80
|
||||
#define AUX_INPUT_MUTE_MASK 0x7f
|
||||
#define OUTPUT_MUTE 0x80
|
||||
#define OUTPUT_MUTE_MASK 0x7f
|
||||
#define OUTPUT_ATTEN_MASK 0xc0
|
||||
|
||||
/*_____ Clock and Data format reg bits */
|
||||
#define CLOCK_SELECT_MASK 0xfe
|
||||
#define CLOCK_XTAL2 0x01
|
||||
#define CLOCK_XTAL1 0x00
|
||||
#define CLOCK_FREQ_MASK 0xf1
|
||||
#define STEREO_MONO_MASK 0xef
|
||||
#define STEREO 0x10
|
||||
#define AUDIO_MONO 0x00
|
||||
#define LINEAR_COMP_MASK 0xdf
|
||||
#define LINEAR 0x00
|
||||
#define COMPANDED 0x20
|
||||
#define FORMAT_MASK 0xbf
|
||||
#define PCM 0x00
|
||||
#define ULAW 0x00
|
||||
#define TWOS_COMP 0x40
|
||||
#define ALAW 0x40
|
||||
|
||||
/*_____ Interface Configuration reg bits */
|
||||
#define PLAYBACK_ENABLE 0x01
|
||||
#define PLAYBACK_ENABLE_MASK 0xfe
|
||||
#define CAPTURE_ENABLE 0x02
|
||||
#define CAPTURE_ENABLE_MASK 0xfd
|
||||
#define SINGLE_DMA 0x04
|
||||
#define SINGLE_DMA_MASK 0xfb
|
||||
#define DUAL_DMA 0x00
|
||||
#define AUTO_CAL_ENABLE 0x08
|
||||
#define AUTO_CAL_DISABLE_MASK 0xf7
|
||||
#define PLAYBACK_PIO_ENABLE 0x40
|
||||
#define PLAYBACK_DMA_MASK 0xbf
|
||||
#define CAPTURE_PIO_ENABLE 0x80
|
||||
#define CAPTURE_DMA_MASK 0x7f
|
||||
|
||||
/*_____ Pin control bits */
|
||||
#define INTERRUPT_ENABLE 0x02
|
||||
#define INTERRUPT_MASK 0xfd
|
||||
|
||||
/*_____ Test and init reg bits */
|
||||
#define OVERRANGE_LEFT_MASK 0xfc
|
||||
#define OVERRANGE_RIGHT_MASK 0xf3
|
||||
#define DATA_REQUEST_STATUS 0x10
|
||||
#define AUTO_CAL_IN_PROG 0x20
|
||||
#define PLAYBACK_UNDERRUN 0x40
|
||||
#define CAPTURE_UNDERRUN 0x80
|
||||
|
||||
/*_____ Miscellaneous Control reg bits */
|
||||
#define ID_MASK 0xf0
|
||||
|
||||
/*_____ Digital Mix Control reg bits */
|
||||
#define DIGITAL_MIX1_MUTE_MASK 0xfe
|
||||
#define MIX_ATTEN_MASK 0x03
|
||||
|
||||
/*_____ 1848 Sound Port reg defines */
|
||||
|
||||
#define SP_LEFT_INPUT_CONTROL 0x0
|
||||
#define SP_RIGHT_INPUT_CONTROL 0x1
|
||||
#define SP_LEFT_AUX1_CONTROL 0x2
|
||||
#define SP_RIGHT_AUX1_CONTROL 0x3
|
||||
#define SP_LEFT_AUX2_CONTROL 0x4
|
||||
#define SP_RIGHT_AUX2_CONTROL 0x5
|
||||
#define SP_LEFT_OUTPUT_CONTROL 0x6
|
||||
#define SP_RIGHT_OUTPUT_CONTROL 0x7
|
||||
#define SP_CLOCK_DATA_FORMAT 0x8
|
||||
#define SP_INTERFACE_CONFIG 0x9
|
||||
#define SP_PIN_CONTROL 0xA
|
||||
#define SP_TEST_AND_INIT 0xB
|
||||
#define SP_MISC_INFO 0xC
|
||||
#define SP_DIGITAL_MIX 0xD
|
||||
#define SP_UPPER_BASE_COUNT 0xE
|
||||
#define SP_LOWER_BASE_COUNT 0xF
|
||||
|
||||
#define HOST_SP_ADDR (0x534)
|
||||
#define HOST_SP_DATA (0x535)
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
phillips.h
|
||||
|
||||
Version 1.2 9/27/93
|
||||
|
||||
Copyright (c) 1993 Analog Devices Inc. All rights reserved
|
||||
|
||||
******************************************************************************/
|
||||
/*_____ Phillips control SW defines */
|
||||
|
||||
/*_____ Settings and ranges */
|
||||
#define VOLUME_MAX 6
|
||||
#define VOLUME_MIN (-64)
|
||||
#define VOLUME_RANGE 70
|
||||
#define VOLUME_STEP 2
|
||||
#define BASS_MAX 15
|
||||
#define BASS_MIN (-12)
|
||||
#define BASS_STEP 2
|
||||
#define BASS_RANGE 27
|
||||
#define TREBLE_MAX 12
|
||||
#define TREBLE_MIN (-12)
|
||||
#define TREBLE_STEP 2
|
||||
#define TREBLE_RANGE 24
|
||||
|
||||
#define VOLUME_CONSTANT 252
|
||||
#define BASS_CONSTANT 246
|
||||
#define TREBLE_CONSTANT 246
|
||||
|
||||
/*_____ Software commands */
|
||||
#define SET_MASTER_COMMAND 0x0010
|
||||
#define MASTER_VOLUME_LEFT 0x0000
|
||||
#define MASTER_VOLUME_RIGHT 0x0100
|
||||
#define MASTER_BASS 0x0200
|
||||
#define MASTER_TREBLE 0x0300
|
||||
#define MASTER_SWITCH 0x0800
|
||||
|
||||
#define STEREO_MODE 0x00ce
|
||||
#define PSEUDO_MODE 0x00d6
|
||||
#define SPATIAL_MODE 0x00de
|
||||
#define MONO_MODE 0x00c6
|
||||
|
||||
|
||||
#define PSS_STEREO 0x00ce
|
||||
#define PSS_PSEUDO 0x00d6
|
||||
#define PSS_SPATIAL 0x00de
|
||||
#define PSS_MONO 0x00c6
|
||||
|
||||
#define PHILLIPS_VOL_MIN -64
|
||||
#define PHILLIPS_VOL_MAX 6
|
||||
#define PHILLIPS_VOL_DELTA 70
|
||||
#define PHILLIPS_VOL_INITIAL -20
|
||||
#define PHILLIPS_VOL_CONSTANT 252
|
||||
#define PHILLIPS_VOL_STEP 2
|
||||
#define PHILLIPS_BASS_MIN -12
|
||||
#define PHILLIPS_BASS_MAX 15
|
||||
#define PHILLIPS_BASS_DELTA 27
|
||||
#define PHILLIPS_BASS_INITIAL 0
|
||||
#define PHILLIPS_BASS_CONSTANT 246
|
||||
#define PHILLIPS_BASS_STEP 2
|
||||
#define PHILLIPS_TREBLE_MIN -12
|
||||
#define PHILLIPS_TREBLE_MAX 12
|
||||
#define PHILLIPS_TREBLE_DELTA 24
|
||||
#define PHILLIPS_TREBLE_INITIAL 0
|
||||
#define PHILLIPS_TREBLE_CONSTANT 246
|
||||
#define PHILLIPS_TREBLE_STEP 2
|
||||
|
28
sys/i386/isa/sound/sb.h
Normal file
28
sys/i386/isa/sound/sb.h
Normal file
@ -0,0 +1,28 @@
|
||||
#define DSP_RESET (sbc_base + 0x6)
|
||||
#define DSP_READ (sbc_base + 0xA)
|
||||
#define DSP_WRITE (sbc_base + 0xC)
|
||||
#define DSP_COMMAND (sbc_base + 0xC)
|
||||
#define DSP_STATUS (sbc_base + 0xC)
|
||||
#define DSP_DATA_AVAIL (sbc_base + 0xE)
|
||||
#define DSP_DATA_AVL16 (sbc_base + 0xF)
|
||||
#define MIXER_ADDR (sbc_base + 0x4)
|
||||
#define MIXER_DATA (sbc_base + 0x5)
|
||||
#define OPL3_LEFT (sbc_base + 0x0)
|
||||
#define OPL3_RIGHT (sbc_base + 0x2)
|
||||
#define OPL3_BOTH (sbc_base + 0x8)
|
||||
/* DSP Commands */
|
||||
|
||||
#define DSP_CMD_SPKON 0xD1
|
||||
#define DSP_CMD_SPKOFF 0xD3
|
||||
#define DSP_CMD_DMAON 0xD0
|
||||
#define DSP_CMD_DMAOFF 0xD4
|
||||
|
||||
#define IMODE_NONE 0
|
||||
#define IMODE_OUTPUT 1
|
||||
#define IMODE_INPUT 2
|
||||
#define IMODE_INIT 3
|
||||
#define IMODE_MIDI 4
|
||||
|
||||
#define NORMAL_MIDI 0
|
||||
#define UART_MIDI 1
|
||||
|
568
sys/i386/isa/sound/sb16_dsp.c
Normal file
568
sys/i386/isa/sound/sb16_dsp.c
Normal file
@ -0,0 +1,568 @@
|
||||
/*
|
||||
* sound/sb16_dsp.c
|
||||
*
|
||||
* The low level driver for the SoundBlaster DSP chip.
|
||||
*
|
||||
* (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de)
|
||||
*
|
||||
* based on SB-driver by (C) Hannu Savolainen
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEB(x)
|
||||
#define DEB1(x)
|
||||
/*
|
||||
* #define DEB_DMARES
|
||||
*/
|
||||
#include "sound_config.h"
|
||||
#include "sb.h"
|
||||
#include "sb_mixer.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
|
||||
|
||||
extern int sbc_base;
|
||||
|
||||
static int sb16_dsp_ok = 0;/*
|
||||
|
||||
|
||||
* * * * Set to 1 after successful *
|
||||
* * initialization */
|
||||
static int dsp_16bit = 0;
|
||||
static int dsp_stereo = 0;
|
||||
static int dsp_current_speed = 8000; /*
|
||||
|
||||
|
||||
* * * * DSP_DEFAULT_SPEED; */
|
||||
static int dsp_busy = 0;
|
||||
static int dma16, dma8;
|
||||
static unsigned long dsp_count = 0;
|
||||
|
||||
static int irq_mode = IMODE_NONE; /*
|
||||
|
||||
|
||||
* * * * IMODE_INPUT, IMODE_OUTPUT
|
||||
* or * * IMODE_NONE */
|
||||
static int my_dev = 0;
|
||||
|
||||
static volatile int intr_active = 0;
|
||||
|
||||
static int sb16_dsp_open (int dev, int mode);
|
||||
static void sb16_dsp_close (int dev);
|
||||
static void sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
|
||||
static void sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
|
||||
static int sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
|
||||
static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
|
||||
static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
|
||||
static void sb16_dsp_reset (int dev);
|
||||
static void sb16_dsp_halt (int dev);
|
||||
static int dsp_set_speed (int);
|
||||
static int dsp_set_stereo (int);
|
||||
static void dsp_cleanup (void);
|
||||
int sb_reset_dsp (void);
|
||||
|
||||
static struct audio_operations sb16_dsp_operations =
|
||||
{
|
||||
"SoundBlaster 16",
|
||||
DMA_AUTOMODE,
|
||||
AFMT_U8 | AFMT_S16_LE,
|
||||
NULL,
|
||||
sb16_dsp_open,
|
||||
sb16_dsp_close,
|
||||
sb16_dsp_output_block,
|
||||
sb16_dsp_start_input,
|
||||
sb16_dsp_ioctl,
|
||||
sb16_dsp_prepare_for_input,
|
||||
sb16_dsp_prepare_for_output,
|
||||
sb16_dsp_reset,
|
||||
sb16_dsp_halt,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int
|
||||
sb_dsp_command01 (unsigned char val)
|
||||
{
|
||||
int i = 1 << 16;
|
||||
|
||||
while (--i & (!INB (DSP_STATUS) & 0x80));
|
||||
if (!i)
|
||||
printk ("SB16 sb_dsp_command01 Timeout\n");
|
||||
return sb_dsp_command (val);
|
||||
}
|
||||
|
||||
static int
|
||||
dsp_set_speed (int mode)
|
||||
{
|
||||
DEB (printk ("dsp_set_speed(%d)\n", mode));
|
||||
if (mode)
|
||||
{
|
||||
if (mode < 5000)
|
||||
mode = 5000;
|
||||
if (mode > 44100)
|
||||
mode = 44100;
|
||||
dsp_current_speed = mode;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int
|
||||
dsp_set_stereo (int mode)
|
||||
{
|
||||
DEB (printk ("dsp_set_stereo(%d)\n", mode));
|
||||
|
||||
dsp_stereo = mode;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int
|
||||
dsp_set_bits (int arg)
|
||||
{
|
||||
DEB (printk ("dsp_set_bits(%d)\n", arg));
|
||||
|
||||
if (arg)
|
||||
switch (arg)
|
||||
{
|
||||
case 8:
|
||||
dsp_16bit = 0;
|
||||
break;
|
||||
case 16:
|
||||
dsp_16bit = 1;
|
||||
break;
|
||||
default:
|
||||
dsp_16bit = 0;
|
||||
}
|
||||
return dsp_16bit ? 16 : 8;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SOUND_PCM_WRITE_RATE:
|
||||
if (local)
|
||||
return dsp_set_speed (arg);
|
||||
return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_RATE:
|
||||
if (local)
|
||||
return dsp_current_speed;
|
||||
return IOCTL_OUT (arg, dsp_current_speed);
|
||||
|
||||
case SNDCTL_DSP_STEREO:
|
||||
if (local)
|
||||
return dsp_set_stereo (arg);
|
||||
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
if (local)
|
||||
return dsp_set_stereo (arg - 1) + 1;
|
||||
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
|
||||
|
||||
case SOUND_PCM_READ_CHANNELS:
|
||||
if (local)
|
||||
return dsp_stereo + 1;
|
||||
return IOCTL_OUT (arg, dsp_stereo + 1);
|
||||
|
||||
case SNDCTL_DSP_SETFMT:
|
||||
if (local)
|
||||
return dsp_set_bits (arg);
|
||||
return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_BITS:
|
||||
if (local)
|
||||
return dsp_16bit ? 16 : 8;
|
||||
return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
|
||||
|
||||
case SOUND_PCM_WRITE_FILTER: /*
|
||||
* NOT YET IMPLEMENTED
|
||||
*/
|
||||
if (IOCTL_IN (arg) > 1)
|
||||
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
sb16_dsp_open (int dev, int mode)
|
||||
{
|
||||
int retval;
|
||||
|
||||
DEB (printk ("sb16_dsp_open()\n"));
|
||||
if (!sb16_dsp_ok)
|
||||
{
|
||||
printk ("SB16 Error: SoundBlaster board not installed\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
if (intr_active)
|
||||
return RET_ERROR (EBUSY);
|
||||
|
||||
retval = sb_get_irq ();
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
sb_reset_dsp ();
|
||||
|
||||
if (ALLOC_DMA_CHN (dma8))
|
||||
{
|
||||
printk ("SB16: Unable to grab DMA%d\n", dma8);
|
||||
sb_free_irq ();
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
if (dma16 != dma8)
|
||||
if (ALLOC_DMA_CHN (dma16))
|
||||
{
|
||||
printk ("SB16: Unable to grab DMA%d\n", dma16);
|
||||
sb_free_irq ();
|
||||
RELEASE_DMA_CHN (dma8);
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
irq_mode = IMODE_NONE;
|
||||
dsp_busy = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_close (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DEB (printk ("sb16_dsp_close()\n"));
|
||||
sb_dsp_command01 (0xd9);
|
||||
sb_dsp_command01 (0xd5);
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
RELEASE_DMA_CHN (dma8);
|
||||
|
||||
if (dma16 != dma8)
|
||||
RELEASE_DMA_CHN (dma16);
|
||||
sb_free_irq ();
|
||||
dsp_cleanup ();
|
||||
dsp_busy = 0;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
|
||||
cnt = count;
|
||||
if (dsp_16bit)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
#ifdef DEB_DMARES
|
||||
printk ("output_block: %x %d %d\n", buf, count, intrflag);
|
||||
if (intrflag)
|
||||
{
|
||||
int pos, chan = audio_devs[dev]->dmachan;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
clear_dma_ff (chan);
|
||||
disable_dma (chan);
|
||||
pos = get_dma_residue (chan);
|
||||
enable_dma (chan);
|
||||
RESTORE_INTR (flags);
|
||||
printk ("dmapos=%d %x\n", pos, pos);
|
||||
}
|
||||
#endif
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE &&
|
||||
intrflag &&
|
||||
cnt == dsp_count)
|
||||
{
|
||||
irq_mode = IMODE_OUTPUT;
|
||||
intr_active = 1;
|
||||
return; /*
|
||||
* Auto mode on. No need to react
|
||||
*/
|
||||
}
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (dma_restart)
|
||||
{
|
||||
sb16_dsp_halt (dev);
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
|
||||
}
|
||||
sb_dsp_command (0x41);
|
||||
sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
|
||||
sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
|
||||
sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6));
|
||||
sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
|
||||
(dsp_16bit ? 0x10 : 0)));
|
||||
sb_dsp_command01 ((unsigned char) (cnt & 0xff));
|
||||
sb_dsp_command ((unsigned char) (cnt >> 8));
|
||||
|
||||
dsp_count = cnt;
|
||||
irq_mode = IMODE_OUTPUT;
|
||||
intr_active = 1;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
|
||||
cnt = count;
|
||||
if (dsp_16bit)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
#ifdef DEB_DMARES
|
||||
printk ("start_input: %x %d %d\n", buf, count, intrflag);
|
||||
if (intrflag)
|
||||
{
|
||||
int pos, chan = audio_devs[dev]->dmachan;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
clear_dma_ff (chan);
|
||||
disable_dma (chan);
|
||||
pos = get_dma_residue (chan);
|
||||
enable_dma (chan);
|
||||
RESTORE_INTR (flags);
|
||||
printk ("dmapos=%d %x\n", pos, pos);
|
||||
}
|
||||
#endif
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE &&
|
||||
intrflag &&
|
||||
cnt == dsp_count)
|
||||
{
|
||||
irq_mode = IMODE_INPUT;
|
||||
intr_active = 1;
|
||||
return; /*
|
||||
* Auto mode on. No need to react
|
||||
*/
|
||||
}
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (dma_restart)
|
||||
{
|
||||
sb_reset_dsp ();
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
|
||||
}
|
||||
|
||||
sb_dsp_command (0x42);
|
||||
sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
|
||||
sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
|
||||
sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce));
|
||||
sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
|
||||
(dsp_16bit ? 0x10 : 0)));
|
||||
sb_dsp_command01 ((unsigned char) (cnt & 0xff));
|
||||
sb_dsp_command ((unsigned char) (cnt >> 8));
|
||||
|
||||
dsp_count = cnt;
|
||||
irq_mode = IMODE_INPUT;
|
||||
intr_active = 1;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
|
||||
{
|
||||
audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
|
||||
dsp_count = 0;
|
||||
dsp_cleanup ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
|
||||
{
|
||||
audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
|
||||
dsp_count = 0;
|
||||
dsp_cleanup ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dsp_cleanup (void)
|
||||
{
|
||||
irq_mode = IMODE_NONE;
|
||||
intr_active = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_reset (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
sb_reset_dsp ();
|
||||
dsp_cleanup ();
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_halt (int dev)
|
||||
{
|
||||
if (dsp_16bit)
|
||||
{
|
||||
sb_dsp_command01 (0xd9);
|
||||
sb_dsp_command01 (0xd5);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_dsp_command01 (0xda);
|
||||
sb_dsp_command01 (0xd0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_irq_hw (int level)
|
||||
{
|
||||
int ival;
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case 5:
|
||||
ival = 2;
|
||||
break;
|
||||
case 7:
|
||||
ival = 4;
|
||||
break;
|
||||
case 9:
|
||||
ival = 1;
|
||||
break;
|
||||
case 10:
|
||||
ival = 8;
|
||||
break;
|
||||
default:
|
||||
printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
|
||||
return;
|
||||
}
|
||||
sb_setmixer (IRQ_NR, ival);
|
||||
}
|
||||
|
||||
long
|
||||
sb16_dsp_init (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
extern int sbc_major, sbc_minor;
|
||||
|
||||
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
|
||||
|
||||
printk (" <%s>", sb16_dsp_operations.name);
|
||||
|
||||
if (num_audiodevs < MAX_AUDIO_DEV)
|
||||
{
|
||||
audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations;
|
||||
audio_devs[my_dev]->dmachan = hw_config->dma;
|
||||
audio_devs[my_dev]->buffcount = 1;
|
||||
audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
|
||||
}
|
||||
else
|
||||
printk ("SB: Too many DSP devices available\n");
|
||||
sb16_dsp_ok = 1;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
sb16_dsp_detect (struct address_info *hw_config)
|
||||
{
|
||||
struct address_info *sb_config;
|
||||
extern int sbc_major;
|
||||
|
||||
if (sb16_dsp_ok)
|
||||
return 1; /* Can't drive two cards */
|
||||
|
||||
if (!(sb_config = sound_getconf (SNDCARD_SB)))
|
||||
{
|
||||
printk ("SB16 Error: Plain SB not configured\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0;
|
||||
*/
|
||||
|
||||
if (!sb_reset_dsp ())
|
||||
return 0;
|
||||
|
||||
if (sbc_major < 4) /* Set by the plain SB driver */
|
||||
return 0; /* Not a SB16 */
|
||||
|
||||
if (hw_config->dma < 4)
|
||||
if (hw_config->dma != sb_config->dma)
|
||||
{
|
||||
printk ("SB16 Error: Invalid DMA channel %d/%d\n",
|
||||
sb_config->dma, hw_config->dma);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dma16 = hw_config->dma;
|
||||
dma8 = sb_config->dma;
|
||||
set_irq_hw (sb_config->irq);
|
||||
sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
|
||||
|
||||
DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
|
||||
|
||||
/*
|
||||
* dsp_showmessage(0xe3,99);
|
||||
*/
|
||||
sb16_dsp_ok = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
sb16_dsp_interrupt (int unused)
|
||||
{
|
||||
int data;
|
||||
|
||||
data = INB (DSP_DATA_AVL16); /*
|
||||
* Interrupt acknowledge
|
||||
*/
|
||||
|
||||
if (intr_active)
|
||||
switch (irq_mode)
|
||||
{
|
||||
case IMODE_OUTPUT:
|
||||
intr_active = 0;
|
||||
DMAbuf_outputintr (my_dev, 1);
|
||||
break;
|
||||
|
||||
case IMODE_INPUT:
|
||||
intr_active = 0;
|
||||
DMAbuf_inputintr (my_dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("SoundBlaster: Unexpected interrupt\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
304
sys/i386/isa/sound/sb16_midi.c
Normal file
304
sys/i386/isa/sound/sb16_midi.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* sound/sb16_midi.c
|
||||
*
|
||||
* The low level driver for the MPU-401 UART emulation of the SB16.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#include "sb.h"
|
||||
|
||||
#define DATAPORT (sb16midi_base)
|
||||
#define COMDPORT (sb16midi_base+1)
|
||||
#define STATPORT (sb16midi_base+1)
|
||||
|
||||
#define sb16midi_status() INB(STATPORT)
|
||||
#define input_avail() (!(sb16midi_status()&INPUT_AVAIL))
|
||||
#define output_ready() (!(sb16midi_status()&OUTPUT_READY))
|
||||
#define sb16midi_cmd(cmd) OUTB(cmd, COMDPORT)
|
||||
#define sb16midi_read() INB(DATAPORT)
|
||||
#define sb16midi_write(byte) OUTB(byte, DATAPORT)
|
||||
|
||||
#define OUTPUT_READY 0x40
|
||||
#define INPUT_AVAIL 0x80
|
||||
#define MPU_ACK 0xFE
|
||||
#define MPU_RESET 0xFF
|
||||
#define UART_MODE_ON 0x3F
|
||||
|
||||
static int sb16midi_opened = 0;
|
||||
static int sb16midi_base = 0x330;
|
||||
static int sb16midi_detected = 0;
|
||||
static int my_dev;
|
||||
extern int sbc_base;
|
||||
|
||||
static int reset_sb16midi (void);
|
||||
static void (*midi_input_intr) (int dev, unsigned char data);
|
||||
|
||||
static void
|
||||
sb16midi_input_loop (void)
|
||||
{
|
||||
while (input_avail ())
|
||||
{
|
||||
unsigned char c = sb16midi_read ();
|
||||
|
||||
if (sb16midi_opened & OPEN_READ)
|
||||
midi_input_intr (my_dev, c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sb16midiintr (int unit)
|
||||
{
|
||||
if (input_avail ())
|
||||
sb16midi_input_loop ();
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_open (int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
void (*output) (int dev)
|
||||
)
|
||||
{
|
||||
if (sb16midi_opened)
|
||||
{
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
sb16midi_input_loop ();
|
||||
|
||||
midi_input_intr = input;
|
||||
sb16midi_opened = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb16midi_close (int dev)
|
||||
{
|
||||
sb16midi_opened = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_out (int dev, unsigned char midi_byte)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Test for input since pending input seems to block the output.
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (input_avail ())
|
||||
sb16midi_input_loop ();
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* Sometimes it takes about 13000 loops before the output becomes ready
|
||||
* (After reset). Normally it takes just about 10 loops.
|
||||
*/
|
||||
|
||||
for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /*
|
||||
* Wait
|
||||
*/
|
||||
|
||||
if (!output_ready ())
|
||||
{
|
||||
printk ("MPU-401: Timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sb16midi_write (midi_byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_start_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_end_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_ioctl (int dev, unsigned cmd, unsigned arg)
|
||||
{
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
sb16midi_kick (int dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_buffer_status (int dev)
|
||||
{
|
||||
return 0; /*
|
||||
* No data in buffers
|
||||
*/
|
||||
}
|
||||
|
||||
#define MIDI_SYNTH_NAME "SoundBlaster 16 Midi"
|
||||
#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
|
||||
#include "midi_synth.h"
|
||||
|
||||
static struct midi_operations sb16midi_operations =
|
||||
{
|
||||
{"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI},
|
||||
&std_midi_synth,
|
||||
sb16midi_open,
|
||||
sb16midi_close,
|
||||
sb16midi_ioctl,
|
||||
sb16midi_out,
|
||||
sb16midi_start_read,
|
||||
sb16midi_end_read,
|
||||
sb16midi_kick,
|
||||
NULL,
|
||||
sb16midi_buffer_status,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
long
|
||||
attach_sb16midi (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
int ok, timeout;
|
||||
unsigned long flags;
|
||||
|
||||
sb16midi_base = hw_config->io_base;
|
||||
|
||||
if (!sb16midi_detected)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /*
|
||||
* Wait
|
||||
*/
|
||||
sb16midi_cmd (UART_MODE_ON);
|
||||
|
||||
ok = 0;
|
||||
for (timeout = 50000; timeout > 0 && !ok; timeout--)
|
||||
if (input_avail ())
|
||||
if (sb16midi_read () == MPU_ACK)
|
||||
ok = 1;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
if (num_midis >= MAX_MIDI_DEV)
|
||||
{
|
||||
printk ("Sound: Too many midi devices detected\n");
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
printk (" <SoundBlaster MPU-401>");
|
||||
|
||||
std_midi_synth.midi_dev = my_dev = num_midis;
|
||||
midi_devs[num_midis++] = &sb16midi_operations;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
static int
|
||||
reset_sb16midi (void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ok, timeout, n;
|
||||
|
||||
/*
|
||||
* Send the RESET command. Try again if no success at the first time.
|
||||
*/
|
||||
|
||||
ok = 0;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
for (n = 0; n < 2 && !ok; n++)
|
||||
{
|
||||
for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /*
|
||||
* Wait
|
||||
*/
|
||||
sb16midi_cmd (MPU_RESET); /*
|
||||
* Send MPU-401 RESET Command
|
||||
*/
|
||||
|
||||
/*
|
||||
* Wait at least 25 msec. This method is not accurate so let's make the
|
||||
* loop bit longer. Cannot sleep since this is called during boot.
|
||||
*/
|
||||
|
||||
for (timeout = 50000; timeout > 0 && !ok; timeout--)
|
||||
if (input_avail ())
|
||||
if (sb16midi_read () == MPU_ACK)
|
||||
ok = 1;
|
||||
|
||||
}
|
||||
|
||||
sb16midi_opened = 0;
|
||||
if (ok)
|
||||
sb16midi_input_loop (); /*
|
||||
* Flush input before enabling interrupts
|
||||
*/
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
probe_sb16midi (struct address_info *hw_config)
|
||||
{
|
||||
int ok = 0;
|
||||
int i;
|
||||
extern int sbc_major;
|
||||
|
||||
if (sbc_major < 4)
|
||||
return 0; /* Not a SB16 */
|
||||
|
||||
sb16midi_base = hw_config->io_base;
|
||||
|
||||
if (sb_get_irq () < 0)
|
||||
return 0;
|
||||
|
||||
ok = reset_sb16midi ();
|
||||
|
||||
sb16midi_detected = ok;
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
52
sys/i386/isa/sound/sb_card.c
Normal file
52
sys/i386/isa/sound/sb_card.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* sound/sb_card.c
|
||||
*
|
||||
* Detection routine for the SoundBlaster cards.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
|
||||
|
||||
long
|
||||
attach_sb_card (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_MIDI)
|
||||
if (!sb_dsp_detect (hw_config))
|
||||
return mem_start;
|
||||
mem_start = sb_dsp_init (mem_start, hw_config);
|
||||
#endif
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
probe_sb (struct address_info *hw_config)
|
||||
{
|
||||
return sb_dsp_detect (hw_config);
|
||||
}
|
||||
|
||||
#endif
|
863
sys/i386/isa/sound/sb_dsp.c
Normal file
863
sys/i386/isa/sound/sb_dsp.c
Normal file
@ -0,0 +1,863 @@
|
||||
/*
|
||||
* sound/sb_dsp.c
|
||||
*
|
||||
* The low level driver for the SoundBlaster DSP chip (SB1.0 to 2.1, SB Pro).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modified:
|
||||
* Hunyue Yau Jan 6 1994
|
||||
* Added code to support Sound Galaxy NX Pro
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
|
||||
|
||||
#include "sb.h"
|
||||
#include "sb_mixer.h"
|
||||
#undef SB_TEST_IRQ
|
||||
|
||||
int sbc_base = 0;
|
||||
static int sbc_irq = 0;
|
||||
static int open_mode = 0; /* Read, write or both */
|
||||
|
||||
/*
|
||||
* The DSP channel can be used either for input or output. Variable
|
||||
* 'sb_irq_mode' will be set when the program calls read or write first time
|
||||
* after open. Current version doesn't support mode changes without closing
|
||||
* and reopening the device. Support for this feature may be implemented in a
|
||||
* future version of this driver.
|
||||
*/
|
||||
|
||||
int sb_dsp_ok = 0; /*
|
||||
|
||||
|
||||
* * * * Set to 1 after successful
|
||||
* initialization * */
|
||||
static int midi_disabled = 0;
|
||||
int sb_dsp_highspeed = 0;
|
||||
int sbc_major = 1, sbc_minor = 0; /*
|
||||
|
||||
|
||||
* * * * DSP version */
|
||||
static int dsp_stereo = 0;
|
||||
static int dsp_current_speed = DSP_DEFAULT_SPEED;
|
||||
static int sb16 = 0;
|
||||
static int irq_verified = 0;
|
||||
|
||||
int sb_midi_mode = NORMAL_MIDI;
|
||||
int sb_midi_busy = 0; /*
|
||||
|
||||
|
||||
* * * * 1 if the process has output
|
||||
* to * * MIDI */
|
||||
int sb_dsp_busy = 0;
|
||||
|
||||
volatile int sb_irq_mode = IMODE_NONE; /*
|
||||
|
||||
|
||||
* * * * IMODE_INPUT, *
|
||||
* IMODE_OUTPUT * * or *
|
||||
* IMODE_NONE */
|
||||
static volatile int irq_ok = 0;
|
||||
|
||||
int sb_duplex_midi = 0;
|
||||
static int my_dev = 0;
|
||||
|
||||
volatile int sb_intr_active = 0;
|
||||
|
||||
static int dsp_speed (int);
|
||||
static int dsp_set_stereo (int mode);
|
||||
int sb_dsp_command (unsigned char val);
|
||||
|
||||
#if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
|
||||
|
||||
/*
|
||||
* Common code for the midi and pcm functions
|
||||
*/
|
||||
|
||||
int
|
||||
sb_dsp_command (unsigned char val)
|
||||
{
|
||||
int i;
|
||||
unsigned long limit;
|
||||
|
||||
limit = GET_TIME () + HZ / 10;/*
|
||||
* The timeout is 0.1 secods
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
|
||||
* called while interrupts are disabled. This means that the timer is
|
||||
* disabled also. However the timeout situation is a abnormal condition.
|
||||
* Normally the DSP should be ready to accept commands after just couple of
|
||||
* loops.
|
||||
*/
|
||||
|
||||
for (i = 0; i < 500000 && GET_TIME () < limit; i++)
|
||||
{
|
||||
if ((INB (DSP_STATUS) & 0x80) == 0)
|
||||
{
|
||||
OUTB (val, DSP_COMMAND);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val);
|
||||
printk ("IRQ conflict???\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sbintr (int unit)
|
||||
{
|
||||
int status;
|
||||
|
||||
#ifndef EXCLUDE_SBPRO
|
||||
if (sb16)
|
||||
{
|
||||
unsigned char src = sb_getmixer (IRQ_STAT); /*
|
||||
|
||||
|
||||
* * * * Interrupt
|
||||
* source * *
|
||||
* register */
|
||||
|
||||
#ifndef EXCLUDE_SB16
|
||||
if (src & 3)
|
||||
sb16_dsp_interrupt (unit);
|
||||
|
||||
#ifndef EXCLUDE_MIDI
|
||||
if (src & 4)
|
||||
sb16midiintr (unit); /*
|
||||
* SB MPU401 interrupt
|
||||
*/
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
if (!(src & 1))
|
||||
return; /*
|
||||
* Not a DSP interupt
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
status = INB (DSP_DATA_AVAIL);/*
|
||||
* Clear interrupt
|
||||
*/
|
||||
|
||||
if (sb_intr_active)
|
||||
switch (sb_irq_mode)
|
||||
{
|
||||
case IMODE_OUTPUT:
|
||||
sb_intr_active = 0;
|
||||
DMAbuf_outputintr (my_dev, 1);
|
||||
break;
|
||||
|
||||
case IMODE_INPUT:
|
||||
sb_intr_active = 0;
|
||||
DMAbuf_inputintr (my_dev);
|
||||
/*
|
||||
* A complete buffer has been input. Let's start new one
|
||||
*/
|
||||
break;
|
||||
|
||||
case IMODE_INIT:
|
||||
sb_intr_active = 0;
|
||||
irq_ok = 1;
|
||||
break;
|
||||
|
||||
case IMODE_MIDI:
|
||||
#ifndef EXCLUDE_MIDI
|
||||
sb_midi_interrupt (unit);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("SoundBlaster: Unexpected interrupt\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int sb_irq_usecount = 0;
|
||||
|
||||
int
|
||||
sb_get_irq (void)
|
||||
{
|
||||
int ok;
|
||||
|
||||
if (!sb_irq_usecount)
|
||||
if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0)
|
||||
return ok;
|
||||
|
||||
sb_irq_usecount++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sb_free_irq (void)
|
||||
{
|
||||
if (!sb_irq_usecount)
|
||||
return;
|
||||
|
||||
sb_irq_usecount--;
|
||||
|
||||
if (!sb_irq_usecount)
|
||||
snd_release_irq (sbc_irq);
|
||||
}
|
||||
|
||||
int
|
||||
sb_reset_dsp (void)
|
||||
{
|
||||
int loopc;
|
||||
|
||||
OUTB (1, DSP_RESET);
|
||||
tenmicrosec ();
|
||||
OUTB (0, DSP_RESET);
|
||||
tenmicrosec ();
|
||||
tenmicrosec ();
|
||||
tenmicrosec ();
|
||||
|
||||
for (loopc = 0; loopc < 1000 && !(INB (DSP_DATA_AVAIL) & 0x80); loopc++); /*
|
||||
* Wait
|
||||
* for
|
||||
* data
|
||||
* *
|
||||
* available
|
||||
* status
|
||||
*/
|
||||
|
||||
if (INB (DSP_READ) != 0xAA)
|
||||
return 0; /*
|
||||
* Sorry
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
|
||||
static void
|
||||
dsp_speaker (char state)
|
||||
{
|
||||
if (state)
|
||||
sb_dsp_command (DSP_CMD_SPKON);
|
||||
else
|
||||
sb_dsp_command (DSP_CMD_SPKOFF);
|
||||
}
|
||||
|
||||
static int
|
||||
dsp_speed (int speed)
|
||||
{
|
||||
unsigned char tconst;
|
||||
unsigned long flags;
|
||||
int max_speed = 44100;
|
||||
|
||||
if (speed < 4000)
|
||||
speed = 4000;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (open_mode != OPEN_WRITE) /* Recording is possible */
|
||||
if (sbc_major < 3) /* Limited input speed with these cards */
|
||||
if (sbc_major == 2 && sbc_minor > 0)
|
||||
max_speed = 15000;
|
||||
else
|
||||
max_speed = 13000;
|
||||
|
||||
if (speed > max_speed)
|
||||
speed = max_speed; /*
|
||||
* Invalid speed
|
||||
*/
|
||||
|
||||
if (dsp_stereo && speed > 22050)
|
||||
speed = 22050;
|
||||
/*
|
||||
* Max. stereo speed is 22050
|
||||
*/
|
||||
|
||||
if ((speed > 22050) && sb_midi_busy)
|
||||
{
|
||||
printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n");
|
||||
speed = 22050;
|
||||
}
|
||||
|
||||
if (dsp_stereo)
|
||||
speed *= 2;
|
||||
|
||||
/*
|
||||
* Now the speed should be valid
|
||||
*/
|
||||
|
||||
if (speed > 22050)
|
||||
{ /*
|
||||
* High speed mode
|
||||
*/
|
||||
int tmp;
|
||||
|
||||
tconst = (unsigned char) ((65536 -
|
||||
((256000000 + speed / 2) / speed)) >> 8);
|
||||
sb_dsp_highspeed = 1;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (sb_dsp_command (0x40))
|
||||
sb_dsp_command (tconst);
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
tmp = 65536 - (tconst << 8);
|
||||
speed = (256000000 + tmp / 2) / tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
int tmp;
|
||||
|
||||
sb_dsp_highspeed = 0;
|
||||
tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (sb_dsp_command (0x40))/*
|
||||
* Set time constant
|
||||
*/
|
||||
sb_dsp_command (tconst);
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
tmp = 256 - tconst;
|
||||
speed = (1000000 + tmp / 2) / tmp;
|
||||
}
|
||||
|
||||
if (dsp_stereo)
|
||||
speed /= 2;
|
||||
|
||||
dsp_current_speed = speed;
|
||||
return speed;
|
||||
}
|
||||
|
||||
static int
|
||||
dsp_set_stereo (int mode)
|
||||
{
|
||||
dsp_stereo = 0;
|
||||
|
||||
#ifdef EXCLUDE_SBPRO
|
||||
return 0;
|
||||
#else
|
||||
if (sbc_major < 3 || sb16)
|
||||
return 0; /*
|
||||
* Sorry no stereo
|
||||
*/
|
||||
|
||||
if (mode && sb_midi_busy)
|
||||
{
|
||||
printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dsp_stereo = !!mode;
|
||||
return dsp_stereo;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
sb_dsp_output_block (int dev, unsigned long buf, int count,
|
||||
int intrflag, int restart_dma)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!sb_irq_mode)
|
||||
dsp_speaker (ON);
|
||||
|
||||
sb_irq_mode = IMODE_OUTPUT;
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
|
||||
|
||||
if (audio_devs[dev]->dmachan > 3)
|
||||
count >>= 1;
|
||||
count--;
|
||||
|
||||
if (sb_dsp_highspeed)
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
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
|
||||
*/
|
||||
}
|
||||
else
|
||||
printk ("SB Error: Unable to start (high speed) DAC\n");
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
if (sb_dsp_command (0x14))/*
|
||||
* 8-bit DAC (DMA)
|
||||
*/
|
||||
{
|
||||
sb_dsp_command ((unsigned char) (count & 0xff));
|
||||
sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
|
||||
}
|
||||
else
|
||||
printk ("SB Error: Unable to start DAC\n");
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
sb_intr_active = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
|
||||
int restart_dma)
|
||||
{
|
||||
/*
|
||||
* Start a DMA input to the buffer pointed by dmaqtail
|
||||
*/
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
if (!sb_irq_mode)
|
||||
dsp_speaker (OFF);
|
||||
|
||||
sb_irq_mode = IMODE_INPUT;
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
|
||||
|
||||
if (audio_devs[dev]->dmachan > 3)
|
||||
count >>= 1;
|
||||
count--;
|
||||
|
||||
if (sb_dsp_highspeed)
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
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
|
||||
*/
|
||||
}
|
||||
else
|
||||
printk ("SB Error: Unable to start (high speed) ADC\n");
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
if (sb_dsp_command (0x24))/*
|
||||
* 8-bit ADC (DMA)
|
||||
*/
|
||||
{
|
||||
sb_dsp_command ((unsigned char) (count & 0xff));
|
||||
sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
|
||||
}
|
||||
else
|
||||
printk ("SB Error: Unable to start ADC\n");
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
sb_intr_active = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
dsp_cleanup (void)
|
||||
{
|
||||
sb_intr_active = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_dsp_prepare_for_input (int dev, int bsize, int bcount)
|
||||
{
|
||||
dsp_cleanup ();
|
||||
dsp_speaker (OFF);
|
||||
|
||||
if (sbc_major == 3) /*
|
||||
* SB Pro
|
||||
*/
|
||||
{
|
||||
if (dsp_stereo)
|
||||
sb_dsp_command (0xa8);
|
||||
else
|
||||
sb_dsp_command (0xa0);
|
||||
|
||||
dsp_speed (dsp_current_speed); /*
|
||||
* Speed must be recalculated if
|
||||
* #channels * changes
|
||||
*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
|
||||
{
|
||||
dsp_cleanup ();
|
||||
dsp_speaker (ON);
|
||||
|
||||
#ifndef EXCLUDE_SBPRO
|
||||
if (sbc_major == 3) /*
|
||||
* SB Pro
|
||||
*/
|
||||
{
|
||||
sb_mixer_set_stereo (dsp_stereo);
|
||||
dsp_speed (dsp_current_speed); /*
|
||||
* Speed must be recalculated if
|
||||
* #channels * changes
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb_dsp_halt_xfer (int dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
verify_irq (void)
|
||||
{
|
||||
#if 0
|
||||
DEFINE_WAIT_QUEUE (testq, testf);
|
||||
|
||||
irq_ok = 0;
|
||||
|
||||
if (sb_get_irq () == -1)
|
||||
{
|
||||
printk ("*** SB Error: Irq %d already in use\n", sbc_irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
sb_irq_mode = IMODE_INIT;
|
||||
|
||||
sb_dsp_command (0xf2); /*
|
||||
* This should cause immediate interrupt
|
||||
*/
|
||||
|
||||
DO_SLEEP (testq, testf, HZ / 5);
|
||||
|
||||
sb_free_irq ();
|
||||
|
||||
if (!irq_ok)
|
||||
{
|
||||
printk ("SB Warning: IRQ%d test not passed!", sbc_irq);
|
||||
irq_ok = 1;
|
||||
}
|
||||
#else
|
||||
irq_ok = 1;
|
||||
#endif
|
||||
return irq_ok;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_dsp_open (int dev, int mode)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!sb_dsp_ok)
|
||||
{
|
||||
printk ("SB Error: SoundBlaster board not installed\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI))
|
||||
{
|
||||
printk ("SB: PCM not possible during MIDI input\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
if (!irq_verified)
|
||||
{
|
||||
verify_irq ();
|
||||
irq_verified = 1;
|
||||
}
|
||||
else if (!irq_ok)
|
||||
printk ("SB Warning: Incorrect IRQ setting %d\n",
|
||||
sbc_irq);
|
||||
|
||||
retval = sb_get_irq ();
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (DMAbuf_open_dma (dev) < 0)
|
||||
{
|
||||
sb_free_irq ();
|
||||
printk ("SB: DMA Busy\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
sb_irq_mode = IMODE_NONE;
|
||||
|
||||
sb_dsp_busy = 1;
|
||||
open_mode = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb_dsp_close (int dev)
|
||||
{
|
||||
DMAbuf_close_dma (dev);
|
||||
sb_free_irq ();
|
||||
dsp_cleanup ();
|
||||
dsp_speaker (OFF);
|
||||
sb_dsp_busy = 0;
|
||||
sb_dsp_highspeed = 0;
|
||||
open_mode = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SOUND_PCM_WRITE_RATE:
|
||||
if (local)
|
||||
return dsp_speed (arg);
|
||||
return IOCTL_OUT (arg, dsp_speed (IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_PCM_READ_RATE:
|
||||
if (local)
|
||||
return dsp_current_speed;
|
||||
return IOCTL_OUT (arg, dsp_current_speed);
|
||||
break;
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
if (local)
|
||||
return dsp_set_stereo (arg - 1) + 1;
|
||||
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
|
||||
break;
|
||||
|
||||
case SOUND_PCM_READ_CHANNELS:
|
||||
if (local)
|
||||
return dsp_stereo + 1;
|
||||
return IOCTL_OUT (arg, dsp_stereo + 1);
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_STEREO:
|
||||
if (local)
|
||||
return dsp_set_stereo (arg);
|
||||
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
case SOUND_PCM_WRITE_BITS:
|
||||
case SOUND_PCM_READ_BITS:
|
||||
if (local)
|
||||
return 8;
|
||||
return IOCTL_OUT (arg, 8);/*
|
||||
* Only 8 bits/sample supported
|
||||
*/
|
||||
break;
|
||||
|
||||
case SOUND_PCM_WRITE_FILTER:
|
||||
case SOUND_PCM_READ_FILTER:
|
||||
return RET_ERROR (EINVAL);
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
sb_dsp_reset (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
sb_reset_dsp ();
|
||||
dsp_speed (dsp_current_speed);
|
||||
dsp_cleanup ();
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
sb_dsp_detect (struct address_info *hw_config)
|
||||
{
|
||||
sbc_base = hw_config->io_base;
|
||||
sbc_irq = hw_config->irq;
|
||||
|
||||
if (sb_dsp_ok)
|
||||
return 0; /*
|
||||
* Already initialized
|
||||
*/
|
||||
|
||||
if (!sb_reset_dsp ())
|
||||
return 0;
|
||||
|
||||
return 1; /*
|
||||
* Detected
|
||||
*/
|
||||
}
|
||||
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
static struct audio_operations sb_dsp_operations =
|
||||
{
|
||||
"SoundBlaster",
|
||||
NOTHING_SPECIAL,
|
||||
AFMT_U8, /* Just 8 bits. Poor old SB */
|
||||
NULL,
|
||||
sb_dsp_open,
|
||||
sb_dsp_close,
|
||||
sb_dsp_output_block,
|
||||
sb_dsp_start_input,
|
||||
sb_dsp_ioctl,
|
||||
sb_dsp_prepare_for_input,
|
||||
sb_dsp_prepare_for_output,
|
||||
sb_dsp_reset,
|
||||
sb_dsp_halt_xfer,
|
||||
NULL, /* local_qlen */
|
||||
NULL /* copy_from_user */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
long
|
||||
sb_dsp_init (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
int i;
|
||||
int mixer_type = 0;
|
||||
|
||||
sbc_major = sbc_minor = 0;
|
||||
sb_dsp_command (0xe1); /*
|
||||
* Get version
|
||||
*/
|
||||
|
||||
for (i = 1000; i; i--)
|
||||
{
|
||||
if (INB (DSP_DATA_AVAIL) & 0x80)
|
||||
{ /*
|
||||
* wait for Data Ready
|
||||
*/
|
||||
if (sbc_major == 0)
|
||||
sbc_major = INB (DSP_READ);
|
||||
else
|
||||
{
|
||||
sbc_minor = INB (DSP_READ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sbc_major == 2 || sbc_major == 3)
|
||||
sb_duplex_midi = 1;
|
||||
|
||||
if (sbc_major == 4)
|
||||
sb16 = 1;
|
||||
|
||||
#ifndef EXCLUDE_SBPRO
|
||||
if (sbc_major >= 3)
|
||||
mixer_type = sb_mixer_init (sbc_major);
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_YM8312
|
||||
|
||||
if (sbc_major > 3 ||
|
||||
(sbc_major == 3 && INB (0x388) == 0x00)) /* Should be 0x06 if not OPL-3 */
|
||||
enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
|
||||
#endif
|
||||
|
||||
if (sbc_major >= 3)
|
||||
{
|
||||
#ifndef SCO
|
||||
# ifdef __SGNXPRO__
|
||||
if (mixer_type == 2)
|
||||
{
|
||||
sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
printk (" <%s>", sb_dsp_operations.name);
|
||||
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
|
||||
if (!sb16) /*
|
||||
* There is a better driver for SB16
|
||||
*/
|
||||
#endif
|
||||
if (num_audiodevs < MAX_AUDIO_DEV)
|
||||
{
|
||||
audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations;
|
||||
audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT;
|
||||
audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
|
||||
audio_devs[my_dev]->dmachan = hw_config->dma;
|
||||
}
|
||||
else
|
||||
printk ("SB: Too many DSP devices available\n");
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_MIDI
|
||||
if (!midi_disabled && !sb16) /*
|
||||
* Midi don't work in the SB emulation mode *
|
||||
* of PAS, SB16 has better midi interface
|
||||
*/
|
||||
sb_midi_init (sbc_major);
|
||||
#endif
|
||||
|
||||
sb_dsp_ok = 1;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
void
|
||||
sb_dsp_disable_midi (void)
|
||||
{
|
||||
midi_disabled = 1;
|
||||
}
|
||||
|
||||
#endif
|
252
sys/i386/isa/sound/sb_midi.c
Normal file
252
sys/i386/isa/sound/sb_midi.c
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* sound/sb_dsp.c
|
||||
*
|
||||
* The low level driver for the SoundBlaster DS chips.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#include "sb.h"
|
||||
#undef SB_TEST_IRQ
|
||||
|
||||
/*
|
||||
* The DSP channel can be used either for input or output. Variable
|
||||
* 'sb_irq_mode' will be set when the program calls read or write first time
|
||||
* after open. Current version doesn't support mode changes without closing
|
||||
* and reopening the device. Support for this feature may be implemented in a
|
||||
* future version of this driver.
|
||||
*/
|
||||
|
||||
extern int sb_dsp_ok; /* Set to 1 atfer successful initialization */
|
||||
extern int sbc_base;
|
||||
|
||||
extern int sb_midi_mode;
|
||||
extern int sb_midi_busy; /*
|
||||
|
||||
|
||||
* * * * 1 if the process has output to MIDI
|
||||
*
|
||||
*/
|
||||
extern int sb_dsp_busy;
|
||||
extern int sb_dsp_highspeed;
|
||||
|
||||
extern volatile int sb_irq_mode;
|
||||
extern int sb_duplex_midi;
|
||||
extern int sb_intr_active;
|
||||
int input_opened = 0;
|
||||
static int my_dev;
|
||||
|
||||
void (*midi_input_intr) (int dev, unsigned char data);
|
||||
|
||||
static int
|
||||
sb_midi_open (int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
void (*output) (int dev)
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sb_dsp_ok)
|
||||
{
|
||||
printk ("SB Error: MIDI hardware not installed\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
if (sb_midi_busy)
|
||||
return RET_ERROR (EBUSY);
|
||||
|
||||
if (mode != OPEN_WRITE && !sb_duplex_midi)
|
||||
{
|
||||
if (num_midis == 1)
|
||||
printk ("SoundBlaster: Midi input not currently supported\n");
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
|
||||
sb_midi_mode = NORMAL_MIDI;
|
||||
if (mode != OPEN_WRITE)
|
||||
{
|
||||
if (sb_dsp_busy || sb_intr_active)
|
||||
return RET_ERROR (EBUSY);
|
||||
sb_midi_mode = UART_MIDI;
|
||||
}
|
||||
|
||||
if (sb_dsp_highspeed)
|
||||
{
|
||||
printk ("SB Error: Midi output not possible during stereo or high speed audio\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
if (sb_midi_mode == UART_MIDI)
|
||||
{
|
||||
sb_irq_mode = IMODE_MIDI;
|
||||
|
||||
sb_reset_dsp ();
|
||||
|
||||
if (!sb_dsp_command (0x35))
|
||||
return RET_ERROR (EIO); /*
|
||||
* Enter the UART mode
|
||||
*/
|
||||
sb_intr_active = 1;
|
||||
|
||||
if ((ret = sb_get_irq ()) < 0)
|
||||
{
|
||||
sb_reset_dsp ();
|
||||
return 0; /*
|
||||
* IRQ not free
|
||||
*/
|
||||
}
|
||||
input_opened = 1;
|
||||
midi_input_intr = input;
|
||||
}
|
||||
|
||||
sb_midi_busy = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb_midi_close (int dev)
|
||||
{
|
||||
if (sb_midi_mode == UART_MIDI)
|
||||
{
|
||||
sb_reset_dsp (); /*
|
||||
* The only way to kill the UART mode
|
||||
*/
|
||||
sb_free_irq ();
|
||||
}
|
||||
sb_intr_active = 0;
|
||||
sb_midi_busy = 0;
|
||||
input_opened = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_midi_out (int dev, unsigned char midi_byte)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (sb_midi_mode == NORMAL_MIDI)
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
if (sb_dsp_command (0x38))
|
||||
sb_dsp_command (midi_byte);
|
||||
else
|
||||
printk ("SB Error: Unable to send a MIDI byte\n");
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
else
|
||||
sb_dsp_command (midi_byte); /*
|
||||
* UART write
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_midi_start_read (int dev)
|
||||
{
|
||||
if (sb_midi_mode != UART_MIDI)
|
||||
{
|
||||
printk ("SoundBlaster: MIDI input not implemented.\n");
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_midi_end_read (int dev)
|
||||
{
|
||||
if (sb_midi_mode == UART_MIDI)
|
||||
{
|
||||
sb_reset_dsp ();
|
||||
sb_intr_active = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_midi_ioctl (int dev, unsigned cmd, unsigned arg)
|
||||
{
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
|
||||
void
|
||||
sb_midi_interrupt (int dummy)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char data;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
data = INB (DSP_READ);
|
||||
if (input_opened)
|
||||
midi_input_intr (my_dev, data);
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
#define MIDI_SYNTH_NAME "SoundBlaster Midi"
|
||||
#define MIDI_SYNTH_CAPS 0
|
||||
#include "midi_synth.h"
|
||||
|
||||
static struct midi_operations sb_midi_operations =
|
||||
{
|
||||
{"SoundBlaster", 0, 0, SNDCARD_SB},
|
||||
&std_midi_synth,
|
||||
sb_midi_open,
|
||||
sb_midi_close,
|
||||
sb_midi_ioctl,
|
||||
sb_midi_out,
|
||||
sb_midi_start_read,
|
||||
sb_midi_end_read,
|
||||
NULL, /*
|
||||
* Kick
|
||||
*/
|
||||
NULL, /*
|
||||
* command
|
||||
*/
|
||||
NULL, /*
|
||||
* buffer_status
|
||||
*/
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
sb_midi_init (int model)
|
||||
{
|
||||
if (num_midis >= MAX_MIDI_DEV)
|
||||
{
|
||||
printk ("Sound: Too many midi devices detected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
std_midi_synth.midi_dev = num_midis;
|
||||
my_dev = num_midis;
|
||||
midi_devs[num_midis++] = &sb_midi_operations;
|
||||
}
|
||||
|
||||
#endif
|
453
sys/i386/isa/sound/sb_mixer.c
Normal file
453
sys/i386/isa/sound/sb_mixer.c
Normal file
@ -0,0 +1,453 @@
|
||||
|
||||
/*
|
||||
* sound/sb_mixer.c
|
||||
*
|
||||
* The low level mixer driver for the SoundBlaster Pro and SB16 cards.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modified:
|
||||
* Hunyue Yau Jan 6 1994
|
||||
* Added code to support the Sound Galaxy NX Pro mixer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO)
|
||||
#define __SB_MIXER_C__
|
||||
|
||||
#include "sb.h"
|
||||
#include "sb_mixer.h"
|
||||
#undef SB_TEST_IRQ
|
||||
|
||||
extern int sbc_base;
|
||||
|
||||
static int mixer_initialized = 0;
|
||||
|
||||
static int supported_rec_devices;
|
||||
static int supported_devices;
|
||||
static int recmask = 0;
|
||||
static int mixer_model;
|
||||
static int mixer_caps;
|
||||
static mixer_tab *iomap;
|
||||
|
||||
void
|
||||
sb_setmixer (unsigned int port, unsigned int value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /*
|
||||
* Select register
|
||||
*/
|
||||
tenmicrosec ();
|
||||
OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
|
||||
tenmicrosec ();
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
int
|
||||
sb_getmixer (unsigned int port)
|
||||
{
|
||||
int val;
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /*
|
||||
* Select register
|
||||
*/
|
||||
tenmicrosec ();
|
||||
val = INB (MIXER_DATA);
|
||||
tenmicrosec ();
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
sb_mixer_set_stereo (int mode)
|
||||
{
|
||||
if (!mixer_initialized)
|
||||
return;
|
||||
|
||||
sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
|
||||
| (mode ? STEREO_DAC : MONO_DAC)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0 No mixer detected.
|
||||
* 1 Only a plain Sound Blaster Pro style mixer detected.
|
||||
* 2 The Sound Galaxy NX Pro mixer detected.
|
||||
*/
|
||||
static int
|
||||
detect_mixer (void)
|
||||
{
|
||||
#ifdef __SGNXPRO__
|
||||
int oldbass, oldtreble;
|
||||
|
||||
#endif
|
||||
int retcode = 1;
|
||||
|
||||
/*
|
||||
* Detect the mixer by changing parameters of two volume channels. If the
|
||||
* values read back match with the values written, the mixer is there (is
|
||||
* it?)
|
||||
*/
|
||||
sb_setmixer (FM_VOL, 0xff);
|
||||
sb_setmixer (VOC_VOL, 0x33);
|
||||
|
||||
if (sb_getmixer (FM_VOL) != 0xff)
|
||||
return 0; /*
|
||||
* No match
|
||||
*/
|
||||
if (sb_getmixer (VOC_VOL) != 0x33)
|
||||
return 0;
|
||||
|
||||
#ifdef __SGNXPRO__
|
||||
/* Attempt to detect the SG NX Pro by check for valid bass/treble
|
||||
* registers.
|
||||
*/
|
||||
oldbass = sb_getmixer (BASS_LVL);
|
||||
oldtreble = sb_getmixer (TREBLE_LVL);
|
||||
|
||||
sb_setmixer (BASS_LVL, 0xaa);
|
||||
sb_setmixer (TREBLE_LVL, 0x55);
|
||||
|
||||
if ((sb_getmixer (BASS_LVL) != 0xaa) ||
|
||||
(sb_getmixer (TREBLE_LVL) != 0x55))
|
||||
{
|
||||
retcode = 1; /* 1 == Only SB Pro detected */
|
||||
}
|
||||
else
|
||||
retcode = 2; /* 2 == SG NX Pro detected */
|
||||
/* Restore register in either case since SG NX Pro has EEPROM with
|
||||
* 'preferred' values stored.
|
||||
*/
|
||||
sb_setmixer (BASS_LVL, oldbass);
|
||||
sb_setmixer (TREBLE_LVL, oldtreble);
|
||||
#endif
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static void
|
||||
change_bits (unsigned char *regval, int dev, int chn, int newval)
|
||||
{
|
||||
unsigned char mask;
|
||||
int shift;
|
||||
|
||||
mask = (1 << (*iomap)[dev][chn].nbits) - 1;
|
||||
newval = (int) ((newval * mask) + 50) / 100; /*
|
||||
* Scale it
|
||||
*/
|
||||
|
||||
shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
|
||||
|
||||
*regval &= ~(mask << shift); /*
|
||||
* Filter out the previous value
|
||||
*/
|
||||
*regval |= (newval & mask) << shift; /*
|
||||
* Set the new value
|
||||
*/
|
||||
}
|
||||
|
||||
static int
|
||||
sb_mixer_get (int dev)
|
||||
{
|
||||
if (!((1 << dev) & supported_devices))
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
return levels[dev];
|
||||
}
|
||||
|
||||
static int
|
||||
sb_mixer_set (int dev, int value)
|
||||
{
|
||||
int left = value & 0x000000ff;
|
||||
int right = (value & 0x0000ff00) >> 8;
|
||||
|
||||
int regoffs;
|
||||
unsigned char val;
|
||||
|
||||
if (left > 100)
|
||||
left = 100;
|
||||
if (right > 100)
|
||||
right = 100;
|
||||
|
||||
if (dev > 31)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
if (!(supported_devices & (1 << dev))) /*
|
||||
* Not supported
|
||||
*/
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
regoffs = (*iomap)[dev][LEFT_CHN].regno;
|
||||
|
||||
if (regoffs == 0)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
val = sb_getmixer (regoffs);
|
||||
change_bits (&val, dev, LEFT_CHN, left);
|
||||
|
||||
levels[dev] = left | (left << 8);
|
||||
|
||||
if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /*
|
||||
* Change register
|
||||
*/
|
||||
{
|
||||
sb_setmixer (regoffs, val); /*
|
||||
* Save the old one
|
||||
*/
|
||||
regoffs = (*iomap)[dev][RIGHT_CHN].regno;
|
||||
|
||||
if (regoffs == 0)
|
||||
return left | (left << 8); /*
|
||||
* Just left channel present
|
||||
*/
|
||||
|
||||
val = sb_getmixer (regoffs); /*
|
||||
* Read the new one
|
||||
*/
|
||||
}
|
||||
|
||||
change_bits (&val, dev, RIGHT_CHN, right);
|
||||
sb_setmixer (regoffs, val);
|
||||
|
||||
levels[dev] = left | (right << 8);
|
||||
return left | (right << 8);
|
||||
}
|
||||
|
||||
static void
|
||||
set_recsrc (int src)
|
||||
{
|
||||
sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
|
||||
}
|
||||
|
||||
static int
|
||||
set_recmask (int mask)
|
||||
{
|
||||
int devmask, i;
|
||||
unsigned char regimageL, regimageR;
|
||||
|
||||
devmask = mask & supported_rec_devices;
|
||||
|
||||
switch (mixer_model)
|
||||
{
|
||||
case 3:
|
||||
|
||||
if (devmask != SOUND_MASK_MIC &&
|
||||
devmask != SOUND_MASK_LINE &&
|
||||
devmask != SOUND_MASK_CD)
|
||||
{ /*
|
||||
* More than one devices selected. Drop the *
|
||||
* previous selection
|
||||
*/
|
||||
devmask &= ~recmask;
|
||||
}
|
||||
|
||||
if (devmask != SOUND_MASK_MIC &&
|
||||
devmask != SOUND_MASK_LINE &&
|
||||
devmask != SOUND_MASK_CD)
|
||||
{ /*
|
||||
* More than one devices selected. Default to
|
||||
* * mic
|
||||
*/
|
||||
devmask = SOUND_MASK_MIC;
|
||||
}
|
||||
|
||||
|
||||
if (devmask ^ recmask) /*
|
||||
* Input source changed
|
||||
*/
|
||||
{
|
||||
switch (devmask)
|
||||
{
|
||||
|
||||
case SOUND_MASK_MIC:
|
||||
set_recsrc (SRC_MIC);
|
||||
break;
|
||||
|
||||
case SOUND_MASK_LINE:
|
||||
set_recsrc (SRC_LINE);
|
||||
break;
|
||||
|
||||
case SOUND_MASK_CD:
|
||||
set_recsrc (SRC_CD);
|
||||
break;
|
||||
|
||||
default:
|
||||
set_recsrc (SRC_MIC);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (!devmask)
|
||||
devmask = SOUND_MASK_MIC;
|
||||
|
||||
regimageL = regimageR = 0;
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
|
||||
if ((1 << i) & devmask)
|
||||
{
|
||||
regimageL |= sb16_recmasks_L[i];
|
||||
regimageR |= sb16_recmasks_R[i];
|
||||
}
|
||||
sb_setmixer (SB16_IMASK_L, regimageL);
|
||||
sb_setmixer (SB16_IMASK_R, regimageR);
|
||||
break;
|
||||
}
|
||||
|
||||
recmask = devmask;
|
||||
return recmask;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
if (((cmd >> 8) & 0xff) == 'M')
|
||||
{
|
||||
if (cmd & IOC_IN)
|
||||
switch (cmd & 0xff)
|
||||
{
|
||||
case SOUND_MIXER_RECSRC:
|
||||
return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
default:
|
||||
return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
|
||||
}
|
||||
else
|
||||
switch (cmd & 0xff) /*
|
||||
* Return parameters
|
||||
*/
|
||||
{
|
||||
|
||||
case SOUND_MIXER_RECSRC:
|
||||
return IOCTL_OUT (arg, recmask);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_DEVMASK:
|
||||
return IOCTL_OUT (arg, supported_devices);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_STEREODEVS:
|
||||
return IOCTL_OUT (arg, supported_devices &
|
||||
~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_RECMASK:
|
||||
return IOCTL_OUT (arg, supported_rec_devices);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_CAPS:
|
||||
return IOCTL_OUT (arg, mixer_caps);
|
||||
break;
|
||||
|
||||
default:
|
||||
return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
|
||||
}
|
||||
}
|
||||
else
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static struct mixer_operations sb_mixer_operations =
|
||||
{
|
||||
sb_mixer_ioctl
|
||||
};
|
||||
|
||||
static void
|
||||
sb_mixer_reset (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
|
||||
sb_mixer_set (i, levels[i]);
|
||||
set_recmask (SOUND_MASK_MIC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a code depending on whether a SG NX Pro was detected.
|
||||
* 1 == Plain SB Pro
|
||||
* 2 == SG NX Pro detected.
|
||||
* 3 == SB16
|
||||
*
|
||||
* Used to update message.
|
||||
*/
|
||||
int
|
||||
sb_mixer_init (int major_model)
|
||||
{
|
||||
int mixer_type = 0;
|
||||
|
||||
sb_setmixer (0x00, 0); /* Reset mixer */
|
||||
|
||||
if (!(mixer_type = detect_mixer ()))
|
||||
return 0; /* No mixer. Why? */
|
||||
|
||||
mixer_initialized = 1;
|
||||
mixer_model = major_model;
|
||||
|
||||
switch (major_model)
|
||||
{
|
||||
case 3:
|
||||
mixer_caps = SOUND_CAP_EXCL_INPUT;
|
||||
#ifdef __SGNXPRO__
|
||||
if (mixer_type == 2) /* A SGNXPRO was detected */
|
||||
{
|
||||
supported_devices = SGNXPRO_MIXER_DEVICES;
|
||||
supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
|
||||
iomap = &sgnxpro_mix;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
supported_devices = SBPRO_MIXER_DEVICES;
|
||||
supported_rec_devices = SBPRO_RECORDING_DEVICES;
|
||||
iomap = &sbpro_mix;
|
||||
mixer_type = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
mixer_caps = 0;
|
||||
supported_devices = SB16_MIXER_DEVICES;
|
||||
supported_rec_devices = SB16_RECORDING_DEVICES;
|
||||
iomap = &sb16_mix;
|
||||
mixer_type = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("SB Warning: Unsupported mixer type\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (num_mixers < MAX_MIXER_DEV)
|
||||
mixer_devs[num_mixers++] = &sb_mixer_operations;
|
||||
sb_mixer_reset ();
|
||||
return mixer_type;
|
||||
}
|
||||
|
||||
#endif
|
221
sys/i386/isa/sound/sb_mixer.h
Normal file
221
sys/i386/isa/sound/sb_mixer.h
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* sound/sb_mixer.h
|
||||
*
|
||||
* Definitions for the SB Pro and SB16 mixers
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Modified:
|
||||
* Hunyue Yau Jan 6 1994
|
||||
* Added defines for the Sound Galaxy NX Pro mixer.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
|
||||
|
||||
/* Same as SB Pro, unless I find otherwise */
|
||||
#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
|
||||
|
||||
#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD | SOUND_MASK_VOLUME)
|
||||
|
||||
/* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
|
||||
* channel is the COVOX/DisneySoundSource emulation volume control
|
||||
* on the mixer. It does NOT control speaker volume. Should have own
|
||||
* mask eventually?
|
||||
*/
|
||||
#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
|
||||
SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
|
||||
|
||||
#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD)
|
||||
|
||||
#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD | SOUND_MASK_RECLEV | \
|
||||
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
|
||||
|
||||
/*
|
||||
* Mixer registers
|
||||
*
|
||||
* NOTE! RECORD_SRC == IN_FILTER
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mixer registers of SB Pro
|
||||
*/
|
||||
#define VOC_VOL 0x04
|
||||
#define MIC_VOL 0x0A
|
||||
#define MIC_MIX 0x0A
|
||||
#define RECORD_SRC 0x0C
|
||||
#define IN_FILTER 0x0C
|
||||
#define OUT_FILTER 0x0E
|
||||
#define MASTER_VOL 0x22
|
||||
#define FM_VOL 0x26
|
||||
#define CD_VOL 0x28
|
||||
#define LINE_VOL 0x2E
|
||||
#define IRQ_NR 0x80
|
||||
#define DMA_NR 0x81
|
||||
#define IRQ_STAT 0x82
|
||||
#define OPSW 0x3c
|
||||
|
||||
/*
|
||||
* Additional registers on the SG NX Pro
|
||||
*/
|
||||
#define COVOX_VOL 0x42
|
||||
#define TREBLE_LVL 0x44
|
||||
#define BASS_LVL 0x46
|
||||
|
||||
#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */
|
||||
#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */
|
||||
#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */
|
||||
#define FILT_OFF (1 << 5)
|
||||
|
||||
#define MONO_DAC 0x00
|
||||
#define STEREO_DAC 0x02
|
||||
|
||||
/*
|
||||
* Mixer registers of SB16
|
||||
*/
|
||||
#define SB16_IMASK_L 0x3d
|
||||
#define SB16_IMASK_R 0x3e
|
||||
|
||||
#define LEFT_CHN 0
|
||||
#define RIGHT_CHN 1
|
||||
|
||||
struct mixer_def {
|
||||
unsigned int regno: 8;
|
||||
unsigned int bitoffs:4;
|
||||
unsigned int nbits:4;
|
||||
};
|
||||
|
||||
|
||||
typedef struct mixer_def mixer_tab[32][2];
|
||||
typedef struct mixer_def mixer_ent;
|
||||
|
||||
#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \
|
||||
{{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}}
|
||||
|
||||
#ifdef __SB_MIXER_C__
|
||||
mixer_tab sbpro_mix = {
|
||||
MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
|
||||
};
|
||||
|
||||
#ifdef __SGNXPRO__
|
||||
mixer_tab sgnxpro_mix = {
|
||||
MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_BASS, 0x46, 2, 3, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 2, 3, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_SPEAKER, 0x42, 2, 3, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
|
||||
MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
|
||||
};
|
||||
#endif
|
||||
|
||||
mixer_tab sb16_mix = {
|
||||
MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4),
|
||||
MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4),
|
||||
MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2)
|
||||
};
|
||||
|
||||
static unsigned short levels[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x5a5a, /* Master Volume */
|
||||
0x3232, /* Bass */
|
||||
0x3232, /* Treble */
|
||||
0x4b4b, /* FM */
|
||||
0x4b4b, /* PCM */
|
||||
0x4b4b, /* PC Speaker */
|
||||
0x4b4b, /* Ext Line */
|
||||
0x0000, /* Mic */
|
||||
0x4b4b, /* CD */
|
||||
0x4b4b, /* Recording monitor */
|
||||
0x4b4b, /* SB PCM */
|
||||
0x4b4b}; /* Recording level */
|
||||
|
||||
static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x00, /* SOUND_MIXER_VOLUME */
|
||||
0x00, /* SOUND_MIXER_BASS */
|
||||
0x00, /* SOUND_MIXER_TREBLE */
|
||||
0x40, /* SOUND_MIXER_SYNTH */
|
||||
0x00, /* SOUND_MIXER_PCM */
|
||||
0x00, /* SOUND_MIXER_SPEAKER */
|
||||
0x10, /* SOUND_MIXER_LINE */
|
||||
0x01, /* SOUND_MIXER_MIC */
|
||||
0x04, /* SOUND_MIXER_CD */
|
||||
0x00, /* SOUND_MIXER_IMIX */
|
||||
0x00, /* SOUND_MIXER_ALTPCM */
|
||||
0x00 /* SOUND_MIXER_RECLEV */
|
||||
};
|
||||
|
||||
static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x00, /* SOUND_MIXER_VOLUME */
|
||||
0x00, /* SOUND_MIXER_BASS */
|
||||
0x00, /* SOUND_MIXER_TREBLE */
|
||||
0x20, /* SOUND_MIXER_SYNTH */
|
||||
0x00, /* SOUND_MIXER_PCM */
|
||||
0x00, /* SOUND_MIXER_SPEAKER */
|
||||
0x08, /* SOUND_MIXER_LINE */
|
||||
0x01, /* SOUND_MIXER_MIC */
|
||||
0x02, /* SOUND_MIXER_CD */
|
||||
0x00, /* SOUND_MIXER_IMIX */
|
||||
0x00, /* SOUND_MIXER_ALTPCM */
|
||||
0x00 /* SOUND_MIXER_RECLEV */
|
||||
};
|
||||
|
||||
/*
|
||||
* Recording sources (SB Pro)
|
||||
*/
|
||||
|
||||
#define SRC_MIC 1 /* Select Microphone recording source */
|
||||
#define SRC_CD 3 /* Select CD recording source */
|
||||
#define SRC_LINE 7 /* Use Line-in for recording source */
|
||||
|
||||
#endif
|
1861
sys/i386/isa/sound/sequencer.c
Normal file
1861
sys/i386/isa/sound/sequencer.c
Normal file
File diff suppressed because it is too large
Load Diff
243
sys/i386/isa/sound/sound_calls.h
Normal file
243
sys/i386/isa/sound/sound_calls.h
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* DMA buffer calls
|
||||
*/
|
||||
|
||||
int DMAbuf_open(int dev, int mode);
|
||||
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_rmchars(int dev, int buff_no, int c);
|
||||
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);
|
||||
void DMAbuf_inputintr(int dev);
|
||||
void DMAbuf_outputintr(int dev, int underflow_flag);
|
||||
|
||||
/*
|
||||
* System calls for /dev/dsp and /dev/audio
|
||||
*/
|
||||
|
||||
int audio_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int audio_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int audio_open (int dev, struct fileinfo *file);
|
||||
void audio_release (int dev, struct fileinfo *file);
|
||||
int audio_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg);
|
||||
int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
|
||||
long audio_init (long mem_start);
|
||||
|
||||
/*
|
||||
* System calls for the /dev/sequencer
|
||||
*/
|
||||
|
||||
int sequencer_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int sequencer_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int sequencer_open (int dev, struct fileinfo *file);
|
||||
void sequencer_release (int dev, struct fileinfo *file);
|
||||
int sequencer_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg);
|
||||
int sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
|
||||
long sequencer_init (long mem_start);
|
||||
void sequencer_timer(void);
|
||||
int note_to_freq(int note_num);
|
||||
unsigned long compute_finetune(unsigned long base_freq, int bend, int range);
|
||||
void seq_input_event(unsigned char *event, int len);
|
||||
void seq_copy_to_input (unsigned char *event, int len);
|
||||
|
||||
#ifdef ALLOW_SELECT
|
||||
int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* System calls for the /dev/midi
|
||||
*/
|
||||
|
||||
int MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int MIDIbuf_open (int dev, struct fileinfo *file);
|
||||
void MIDIbuf_release (int dev, struct fileinfo *file);
|
||||
int MIDIbuf_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg);
|
||||
int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
|
||||
void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
|
||||
long MIDIbuf_init(long mem_start);
|
||||
|
||||
#ifdef ALLOW_SELECT
|
||||
int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* System calls for the generic midi interface.
|
||||
*
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
*
|
||||
* 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));
|
||||
void snd_release_irq(int vect);
|
||||
void sound_dma_malloc(int dev);
|
||||
void sound_dma_free(int dev);
|
||||
|
||||
/* From sound_switch.c */
|
||||
int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int sound_open_sw (int dev, struct fileinfo *file);
|
||||
void sound_release_sw (int dev, struct fileinfo *file);
|
||||
int sound_ioctl_sw (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
/* From sb_dsp.c */
|
||||
int sb_dsp_detect (struct address_info *hw_config);
|
||||
long sb_dsp_init (long mem_start, struct address_info *hw_config);
|
||||
void sb_dsp_disable_midi(void);
|
||||
int sb_get_irq(void);
|
||||
void sb_free_irq(void);
|
||||
int sb_dsp_command (unsigned char val);
|
||||
int sb_reset_dsp (void);
|
||||
|
||||
/* From sb16_dsp.c */
|
||||
void sb16_dsp_interrupt (int unused);
|
||||
long sb16_dsp_init(long mem_start, struct address_info *hw_config);
|
||||
int sb16_dsp_detect(struct address_info *hw_config);
|
||||
|
||||
/* From sb16_midi.c */
|
||||
void sb16midiintr (int unit);
|
||||
long attach_sb16midi(long mem_start, struct address_info * hw_config);
|
||||
int probe_sb16midi(struct address_info *hw_config);
|
||||
void sb_midi_interrupt(int dummy);
|
||||
|
||||
/* From sb_midi.c */
|
||||
void sb_midi_init(int model);
|
||||
|
||||
/* From sb_mixer.c */
|
||||
void sb_setmixer (unsigned int port, unsigned int value);
|
||||
int sb_getmixer (unsigned int port);
|
||||
void sb_mixer_set_stereo(int mode);
|
||||
int sb_mixer_init(int major_model);
|
||||
|
||||
/* From opl3.c */
|
||||
int opl3_detect (int ioaddr);
|
||||
long opl3_init(long mem_start);
|
||||
|
||||
/* From sb_card.c */
|
||||
long attach_sb_card(long mem_start, struct address_info *hw_config);
|
||||
int probe_sb(struct address_info *hw_config);
|
||||
|
||||
/* From adlib_card.c */
|
||||
long attach_adlib_card(long mem_start, struct address_info *hw_config);
|
||||
int probe_adlib(struct address_info *hw_config);
|
||||
|
||||
/* From pas_card.c */
|
||||
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);
|
||||
int pas_remove_intr(int mask);
|
||||
unsigned char pas_read(int ioaddr);
|
||||
void pas_write(unsigned char data, int ioaddr);
|
||||
|
||||
/* From pas_audio.c */
|
||||
void pas_pcm_interrupt(unsigned char status, int cause);
|
||||
long pas_pcm_init(long mem_start, struct address_info *hw_config);
|
||||
|
||||
/* From pas_mixer.c */
|
||||
int pas_init_mixer(void);
|
||||
|
||||
/* From pas_midi.c */
|
||||
long pas_midi_init(long mem_start);
|
||||
void pas_midi_interrupt(void);
|
||||
|
||||
/* From gus_card.c */
|
||||
long attach_gus_card(long mem_start, struct address_info * hw_config);
|
||||
int probe_gus(struct address_info *hw_config);
|
||||
int gus_set_midi_irq(int num);
|
||||
void gusintr(int);
|
||||
long attach_gus_db16(long mem_start, struct address_info * hw_config);
|
||||
int probe_gus_db16(struct address_info *hw_config);
|
||||
|
||||
/* From gus_wave.c */
|
||||
int gus_wave_detect(int baseaddr);
|
||||
long gus_wave_init(long mem_start, int irq, int dma);
|
||||
void gus_voice_irq(void);
|
||||
unsigned char gus_read8 (int reg);
|
||||
void gus_write8(int reg, unsigned int data);
|
||||
void guswave_dma_irq(void);
|
||||
void gus_delay(void);
|
||||
int gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg);
|
||||
|
||||
/* From gus_midi.c */
|
||||
long gus_midi_init(long mem_start);
|
||||
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);
|
||||
|
||||
/* From uart6850.c */
|
||||
long attach_uart6850(long mem_start, struct address_info * hw_config);
|
||||
int probe_uart6850(struct address_info *hw_config);
|
||||
|
||||
/* From opl3.c */
|
||||
void enable_opl3_mode(int left, int right, int both);
|
||||
|
||||
/* From patmgr.c */
|
||||
int pmgr_open(int dev);
|
||||
void pmgr_release(int dev);
|
||||
int pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count);
|
||||
int pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count);
|
||||
int pmgr_access(int dev, struct patmgr_info *rec);
|
||||
int pmgr_inform(int dev, int event, unsigned long parm1, unsigned long parm2,
|
||||
unsigned long parm3, unsigned long parm4);
|
||||
|
||||
/* From ics2101.c */
|
||||
long ics2101_mixer_init(long mem_start);
|
||||
|
||||
/* From sound_timer.c */
|
||||
void sound_timer_init(int io_base);
|
||||
void sound_timer_interrupt(void);
|
||||
|
||||
/* From ad1848.c */
|
||||
void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture);
|
||||
int ad1848_detect (int io_base);
|
||||
void ad1848_interrupt (int dev);
|
||||
long attach_ms_sound(long mem_start, struct address_info * hw_config);
|
||||
int probe_ms_sound(struct address_info *hw_config);
|
||||
|
||||
/* From pss.c */
|
||||
int probe_pss (struct address_info *hw_config);
|
||||
long attach_pss (long mem_start, struct address_info *hw_config);
|
||||
|
||||
int pss_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int pss_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int pss_open (int dev, struct fileinfo *file);
|
||||
void pss_release (int dev, struct fileinfo *file);
|
||||
int pss_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg);
|
||||
int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
|
||||
long pss_init(long mem_start);
|
258
sys/i386/isa/sound/sound_config.h
Normal file
258
sys/i386/isa/sound/sound_config.h
Normal file
@ -0,0 +1,258 @@
|
||||
/* sound_config.h
|
||||
*
|
||||
* A driver for Soundcards, misc configuration parameters.
|
||||
*
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "local.h"
|
||||
|
||||
#if defined(ISC) || defined(SCO) || defined(SVR42)
|
||||
#define GENERIC_SYSV
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Disable the AD1848 driver if there are no other drivers requiring it.
|
||||
*/
|
||||
|
||||
#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX)
|
||||
#define EXCLUDE_AD1848
|
||||
#endif
|
||||
|
||||
#undef CONFIGURE_SOUNDCARD
|
||||
#undef DYNAMIC_BUFFER
|
||||
|
||||
#ifdef KERNEL_SOUNDCARD
|
||||
#define CONFIGURE_SOUNDCARD
|
||||
#define DYNAMIC_BUFFER
|
||||
#undef LOADABLE_SOUNDCARD
|
||||
#endif
|
||||
|
||||
#ifdef EXCLUDE_SEQUENCER
|
||||
#define EXCLUDE_MIDI
|
||||
#define EXCLUDE_YM3812
|
||||
#define EXCLUDE_OPL3
|
||||
#endif
|
||||
|
||||
#ifndef SND_DEFAULT_ENABLE
|
||||
#define SND_DEFAULT_ENABLE 1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
/* ****** IO-address, DMA and IRQ settings ****
|
||||
|
||||
If your card has nonstandard I/O address or IRQ number, change defines
|
||||
for the following settings in your kernel Makefile */
|
||||
|
||||
#ifndef SBC_BASE
|
||||
#define SBC_BASE 0x220 /* 0x220 is the factory default. */
|
||||
#endif
|
||||
|
||||
#ifndef SBC_IRQ
|
||||
#define SBC_IRQ 7 /* IQR7 is the factory default. */
|
||||
#endif
|
||||
|
||||
#ifndef SBC_DMA
|
||||
#define SBC_DMA 1
|
||||
#endif
|
||||
|
||||
#ifndef SB16_DMA
|
||||
#define SB16_DMA 6
|
||||
#endif
|
||||
|
||||
#ifndef SB16MIDI_BASE
|
||||
#define SB16MIDI_BASE 0x300
|
||||
#endif
|
||||
|
||||
#ifndef PAS_BASE
|
||||
#define PAS_BASE 0x388
|
||||
#endif
|
||||
|
||||
#ifndef PAS_IRQ
|
||||
#define PAS_IRQ 5
|
||||
#endif
|
||||
|
||||
#ifndef PAS_DMA
|
||||
#define PAS_DMA 3
|
||||
#endif
|
||||
|
||||
#ifndef GUS_BASE
|
||||
#define GUS_BASE 0x220
|
||||
#endif
|
||||
|
||||
#ifndef GUS_IRQ
|
||||
#define GUS_IRQ 15
|
||||
#endif
|
||||
|
||||
#ifndef GUS_MIDI_IRQ
|
||||
#define GUS_MIDI_IRQ GUS_IRQ
|
||||
#endif
|
||||
|
||||
#ifndef GUS_DMA
|
||||
#define GUS_DMA 6
|
||||
#endif
|
||||
|
||||
#ifndef MPU_BASE
|
||||
#define MPU_BASE 0x330
|
||||
#endif
|
||||
|
||||
#ifndef MPU_IRQ
|
||||
#define MPU_IRQ 6
|
||||
#endif
|
||||
|
||||
/* Echo Personal Sound System */
|
||||
#ifndef PSS_BASE
|
||||
#define PSS_BASE 0x220 /* 0x240 or */
|
||||
#endif
|
||||
|
||||
#ifndef PSS_IRQ
|
||||
#define PSS_IRQ 7
|
||||
#endif
|
||||
|
||||
#ifndef PSS_DMA
|
||||
#define PSS_DMA 1
|
||||
#endif
|
||||
|
||||
#ifndef MAX_REALTIME_FACTOR
|
||||
#define MAX_REALTIME_FACTOR 4
|
||||
#endif
|
||||
|
||||
/************* PCM DMA buffer sizes *******************/
|
||||
|
||||
/* If you are using high playback or recording speeds, the default buffersize
|
||||
is too small. DSP_BUFFSIZE must be 64k or less.
|
||||
|
||||
A rule of thumb is 64k for PAS16, 32k for PAS+, 16k for SB Pro and
|
||||
4k for SB.
|
||||
|
||||
If you change the DSP_BUFFSIZE, don't modify this file.
|
||||
Use the make config command instead. */
|
||||
|
||||
#ifndef DSP_BUFFSIZE
|
||||
#define DSP_BUFFSIZE (4096)
|
||||
#endif
|
||||
|
||||
#ifndef DSP_BUFFCOUNT
|
||||
#define DSP_BUFFCOUNT 2 /* 2 is recommended. */
|
||||
#endif
|
||||
|
||||
#define DMA_AUTOINIT 0x10
|
||||
|
||||
#define FM_MONO 0x388 /* This is the I/O address used by AdLib */
|
||||
|
||||
/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
|
||||
driver. (There is no need to alter this) */
|
||||
#define SEQ_MAX_QUEUE 1024
|
||||
|
||||
#define SBFM_MAXINSTR (256) /* Size of the FM Instrument bank */
|
||||
/* 128 instruments for general MIDI setup and 16 unassigned */
|
||||
|
||||
/*
|
||||
* Minor numbers for the sound driver.
|
||||
*
|
||||
* Unfortunately Creative called the codec chip of SB as a DSP. For this
|
||||
* reason the /dev/dsp is reserved for digitized audio use. There is a
|
||||
* device for true DSP processors but it will be called something else.
|
||||
* In v3.0 it's /dev/sndproc but this could be a temporary solution.
|
||||
*/
|
||||
|
||||
#define SND_NDEVS 256 /* Number of supported devices */
|
||||
#define SND_DEV_CTL 0 /* Control port /dev/mixer */
|
||||
#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
|
||||
synthesizer and MIDI output) */
|
||||
#define SND_DEV_MIDIN 2 /* Raw midi access */
|
||||
#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
|
||||
#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
|
||||
#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
|
||||
#define SND_DEV_STATUS 6 /* /dev/sndstat */
|
||||
/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
|
||||
#define SND_DEV_SEQ2 8 /* /dev/sequecer, level 2 interface */
|
||||
#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
|
||||
#define SND_DEV_PSS SND_DEV_SNDPROC
|
||||
|
||||
#define DSP_DEFAULT_SPEED 8000
|
||||
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
|
||||
#define MAX_AUDIO_DEV 5
|
||||
#define MAX_MIXER_DEV 2
|
||||
#define MAX_SYNTH_DEV 3
|
||||
#define MAX_MIDI_DEV 6
|
||||
#define MAX_TIMER_DEV 3
|
||||
|
||||
struct fileinfo {
|
||||
int mode; /* Open mode */
|
||||
};
|
||||
|
||||
struct address_info {
|
||||
int io_base;
|
||||
int irq;
|
||||
int dma;
|
||||
};
|
||||
|
||||
#define SYNTH_MAX_VOICES 32
|
||||
|
||||
struct voice_alloc_info {
|
||||
int max_voice;
|
||||
int used_voices;
|
||||
int ptr; /* For device specific use */
|
||||
unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */
|
||||
};
|
||||
|
||||
struct channel_info {
|
||||
int pgm_num;
|
||||
unsigned char controllers[128];
|
||||
};
|
||||
|
||||
/*
|
||||
* Process wakeup reasons
|
||||
*/
|
||||
#define WK_NONE 0x00
|
||||
#define WK_WAKEUP 0x01
|
||||
#define WK_TIMEOUT 0x02
|
||||
#define WK_SIGNAL 0x04
|
||||
#define WK_SLEEP 0x08
|
||||
|
||||
#define OPEN_READ 1
|
||||
#define OPEN_WRITE 2
|
||||
#define OPEN_READWRITE 3
|
||||
|
||||
#include "os.h"
|
||||
#include "sound_calls.h"
|
||||
#include "dev_table.h"
|
||||
|
||||
#ifndef DEB
|
||||
#define DEB(x)
|
||||
|
||||
#define TIMER_ARMED 121234
|
||||
#define TIMER_NOT_ARMED 1
|
||||
|
||||
#define FUTURE_VERSION
|
||||
#endif
|
||||
|
||||
#endif
|
528
sys/i386/isa/sound/sound_switch.c
Normal file
528
sys/i386/isa/sound/sound_switch.c
Normal file
@ -0,0 +1,528 @@
|
||||
/*
|
||||
* sound/sound_switch.c
|
||||
*
|
||||
* The system call switch
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
struct sbc_device
|
||||
{
|
||||
int usecount;
|
||||
};
|
||||
|
||||
static struct sbc_device sbc_devices[SND_NDEVS] =
|
||||
{
|
||||
{0}};
|
||||
|
||||
static int in_use = 0; /*
|
||||
|
||||
|
||||
* * * * Total # of open device files
|
||||
* (excluding * * * minor 0) */
|
||||
|
||||
/*
|
||||
* /dev/sndstatus -device
|
||||
*/
|
||||
static char *status_buf = NULL;
|
||||
static int status_len, status_ptr;
|
||||
static int status_busy = 0;
|
||||
|
||||
static int
|
||||
put_status (char *s)
|
||||
{
|
||||
int l;
|
||||
|
||||
for (l = 0; l < 256, s[l]; l++); /*
|
||||
* l=strlen(s);
|
||||
*/
|
||||
|
||||
if (status_len + l >= 4000)
|
||||
return 0;
|
||||
|
||||
memcpy (&status_buf[status_len], s, l);
|
||||
status_len += l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
put_status_int (unsigned int val, int radix)
|
||||
{
|
||||
int l, v;
|
||||
|
||||
static char hx[] = "0123456789abcdef";
|
||||
char buf[11];
|
||||
|
||||
if (!val)
|
||||
return put_status ("0");
|
||||
|
||||
l = 0;
|
||||
buf[10] = 0;
|
||||
|
||||
while (val)
|
||||
{
|
||||
v = val % radix;
|
||||
val = val / radix;
|
||||
|
||||
buf[9 - l] = hx[v];
|
||||
l++;
|
||||
}
|
||||
|
||||
if (status_len + l >= 4000)
|
||||
return 0;
|
||||
|
||||
memcpy (&status_buf[status_len], &buf[10 - l], l);
|
||||
status_len += l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
init_status (void)
|
||||
{
|
||||
/*
|
||||
* Write the status information to the status_buf and update status_len.
|
||||
* There is a limit of 4000 bytes for the data.
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
status_ptr = 0;
|
||||
|
||||
put_status ("Sound Driver:" SOUND_VERSION_STRING
|
||||
" (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
|
||||
SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")"
|
||||
"\n");
|
||||
|
||||
if (!put_status ("Config options: "))
|
||||
return;
|
||||
if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
|
||||
return;
|
||||
|
||||
if (!put_status ("\n\nInstalled drivers: \n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < (num_sound_drivers - 1); i++)
|
||||
{
|
||||
if (!put_status ("Type "))
|
||||
return;
|
||||
if (!put_status_int (sound_drivers[i].card_type, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (sound_drivers[i].name))
|
||||
return;
|
||||
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\n\nCard config: \n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < (num_sound_cards - 1); i++)
|
||||
{
|
||||
int drv;
|
||||
|
||||
if (!snd_installed_cards[i].enabled)
|
||||
if (!put_status ("("))
|
||||
return;
|
||||
|
||||
/*
|
||||
* if (!put_status_int(snd_installed_cards[i].card_type, 10)) return;
|
||||
* if (!put_status (": ")) return;
|
||||
*/
|
||||
|
||||
if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1)
|
||||
if (!put_status (sound_drivers[drv].name))
|
||||
return;
|
||||
|
||||
if (!put_status (" at 0x"))
|
||||
return;
|
||||
if (!put_status_int (snd_installed_cards[i].config.io_base, 16))
|
||||
return;
|
||||
if (!put_status (" irq "))
|
||||
return;
|
||||
if (!put_status_int (snd_installed_cards[i].config.irq, 10))
|
||||
return;
|
||||
if (!put_status (" drq "))
|
||||
return;
|
||||
if (!put_status_int (snd_installed_cards[i].config.dma, 10))
|
||||
return;
|
||||
|
||||
if (!snd_installed_cards[i].enabled)
|
||||
if (!put_status (")"))
|
||||
return;
|
||||
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\nPCM devices:\n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_audiodevs; i++)
|
||||
{
|
||||
if (!put_status_int (i, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (audio_devs[i]->name))
|
||||
return;
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\nSynth devices:\n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_synths; i++)
|
||||
{
|
||||
if (!put_status_int (i, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (synth_devs[i]->info->name))
|
||||
return;
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\nMidi devices:\n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_midis; i++)
|
||||
{
|
||||
if (!put_status_int (i, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (midi_devs[i]->info.name))
|
||||
return;
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\nMIDI Timers:\n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_sound_timers; i++)
|
||||
{
|
||||
if (!put_status_int (i, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (sound_timer_devs[i]->info.name))
|
||||
return;
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
if (!put_status_int (num_mixers, 10))
|
||||
return;
|
||||
if (!put_status (" mixer(s) installed\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
read_status (snd_rw_buf * buf, int count)
|
||||
{
|
||||
/*
|
||||
* Return at most 'count' bytes from the status_buf.
|
||||
*/
|
||||
int l, c;
|
||||
|
||||
l = count;
|
||||
c = status_len - status_ptr;
|
||||
|
||||
if (l > c)
|
||||
l = c;
|
||||
if (l <= 0)
|
||||
return 0;
|
||||
|
||||
COPY_TO_USER (buf, 0, &status_buf[status_ptr], l);
|
||||
status_ptr += l;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count));
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
case SND_DEV_STATUS:
|
||||
return read_status (buf, count);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
return audio_read (dev, file, buf, count);
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
case SND_DEV_SEQ2:
|
||||
return sequencer_read (dev, file, buf, count);
|
||||
break;
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
|
||||
int
|
||||
sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
|
||||
DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count));
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
case SND_DEV_SEQ2:
|
||||
return sequencer_write (dev, file, buf, count);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
return audio_write (dev, file, buf, count);
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MIDI
|
||||
case SND_DEV_MIDIN:
|
||||
return MIDIbuf_write (dev, file, buf, count);
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_PSS
|
||||
case SND_DEV_PSS:
|
||||
return pss_write (dev, file, buf, count);
|
||||
#endif
|
||||
|
||||
default:
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
sound_open_sw (int dev, struct fileinfo *file)
|
||||
{
|
||||
int retval;
|
||||
|
||||
DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
|
||||
|
||||
if ((dev >= SND_NDEVS) || (dev < 0))
|
||||
{
|
||||
printk ("Invalid minor device %d\n", dev);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
case SND_DEV_STATUS:
|
||||
if (status_busy)
|
||||
return RET_ERROR (EBUSY);
|
||||
status_busy = 1;
|
||||
if ((status_buf = (char *) KERNEL_MALLOC (4000)) == NULL)
|
||||
return RET_ERROR (EIO);
|
||||
status_len = status_ptr = 0;
|
||||
init_status ();
|
||||
break;
|
||||
|
||||
case SND_DEV_CTL:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
case SND_DEV_SEQ2:
|
||||
if ((retval = sequencer_open (dev, file)) < 0)
|
||||
return retval;
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MIDI
|
||||
case SND_DEV_MIDIN:
|
||||
if ((retval = MIDIbuf_open (dev, file)) < 0)
|
||||
return retval;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_PSS
|
||||
case SND_DEV_PSS:
|
||||
if ((retval = pss_open (dev, file)) < 0)
|
||||
return retval;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
if ((retval = audio_open (dev, file)) < 0)
|
||||
return retval;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("Invalid minor device %d\n", dev);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
sbc_devices[dev].usecount++;
|
||||
in_use++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sound_release_sw (int dev, struct fileinfo *file)
|
||||
{
|
||||
|
||||
DEB (printk ("sound_release_sw(dev=%d)\n", dev));
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
case SND_DEV_STATUS:
|
||||
if (status_buf)
|
||||
KERNEL_FREE (status_buf);
|
||||
status_buf = NULL;
|
||||
status_busy = 0;
|
||||
break;
|
||||
|
||||
case SND_DEV_CTL:
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
case SND_DEV_SEQ2:
|
||||
sequencer_release (dev, file);
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MIDI
|
||||
case SND_DEV_MIDIN:
|
||||
MIDIbuf_release (dev, file);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_PSS
|
||||
case SND_DEV_PSS:
|
||||
pss_release (dev, file);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
audio_release (dev, file);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("Sound error: Releasing unknown device 0x%02x\n", dev);
|
||||
}
|
||||
|
||||
sbc_devices[dev].usecount--;
|
||||
in_use--;
|
||||
}
|
||||
|
||||
int
|
||||
sound_ioctl_sw (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
|
||||
|
||||
if ((dev & 0x0f) != SND_DEV_CTL && num_mixers > 0)
|
||||
if ((cmd >> 8) & 0xff == 'M') /*
|
||||
* Mixer ioctl
|
||||
*/
|
||||
return mixer_devs[0]->ioctl (0, cmd, arg);
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
|
||||
case SND_DEV_CTL:
|
||||
|
||||
if (!num_mixers)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
if (dev >= num_mixers)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
return mixer_devs[dev]->ioctl (dev, cmd, arg);
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
case SND_DEV_SEQ2:
|
||||
return sequencer_ioctl (dev, file, cmd, arg);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
return audio_ioctl (dev, file, cmd, arg);
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MIDI
|
||||
case SND_DEV_MIDIN:
|
||||
return MIDIbuf_ioctl (dev, file, cmd, arg);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_PSS
|
||||
case SND_DEV_PSS:
|
||||
return pss_ioctl (dev, file, cmd, arg);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return RET_ERROR (EPERM);
|
||||
break;
|
||||
}
|
||||
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
|
||||
#endif
|
406
sys/i386/isa/sound/sound_timer.c
Normal file
406
sys/i386/isa/sound/sound_timer.c
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* sound/sound_timer.c
|
||||
*
|
||||
* Timer for the level 2 interface of the /dev/sequencer. Uses the
|
||||
* 80 and 320 usec timers of OPL-3 (PAS16 only) and GUS.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SEQUENCER_C
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#if !defined(EXCLUDE_SEQUENCER) && (!defined(EXCLUDE_GUS) || (!defined(EXCLUDE_PAS) && !defined(EXCLUDE_YM3812)))
|
||||
|
||||
static volatile int initialized = 0, opened = 0, tmr_running = 0;
|
||||
static volatile time_t tmr_offs, tmr_ctr;
|
||||
static volatile unsigned long ticks_offs;
|
||||
static volatile int curr_tempo, curr_timebase;
|
||||
static volatile unsigned long curr_ticks;
|
||||
static volatile unsigned long next_event_time;
|
||||
static unsigned long prev_event_time;
|
||||
static volatile int select_addr, data_addr;
|
||||
static volatile int curr_timer = 0;
|
||||
static volatile unsigned long usecs_per_tmr; /* Length of the current interval */
|
||||
|
||||
|
||||
static void
|
||||
timer_command (unsigned int addr, unsigned int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
OUTB ((unsigned char) (addr & 0xff), select_addr);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
INB (select_addr);
|
||||
|
||||
OUTB ((unsigned char) (val & 0xff), data_addr);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
INB (select_addr);
|
||||
}
|
||||
|
||||
static void
|
||||
arm_timer (int timer, unsigned int interval)
|
||||
{
|
||||
|
||||
curr_timer = timer;
|
||||
|
||||
if (timer == 1)
|
||||
{
|
||||
gus_write8 (0x46, 256 - interval); /* Set counter for timer 1 */
|
||||
gus_write8 (0x45, 0x04); /* Enable timer 1 IRQ */
|
||||
timer_command (0x04, 0x01); /* Start timer 1 */
|
||||
}
|
||||
else
|
||||
{
|
||||
gus_write8 (0x47, 256 - interval); /* Set counter for timer 2 */
|
||||
gus_write8 (0x45, 0x08); /* Enable timer 2 IRQ */
|
||||
timer_command (0x04, 0x02); /* Start timer 2 */
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
tmr2ticks (int tmr_value)
|
||||
{
|
||||
/*
|
||||
* Convert timer ticks to MIDI ticks
|
||||
*/
|
||||
|
||||
unsigned long tmp;
|
||||
unsigned long scale;
|
||||
|
||||
tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */
|
||||
|
||||
scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */
|
||||
|
||||
return (tmp + (scale / 2)) / scale;
|
||||
}
|
||||
|
||||
static void
|
||||
reprogram_timer (void)
|
||||
{
|
||||
unsigned long usecs_per_tick;
|
||||
int timer_no, resolution;
|
||||
int divisor;
|
||||
|
||||
usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
|
||||
|
||||
/*
|
||||
* Don't kill the system by setting too high timer rate
|
||||
*/
|
||||
if (usecs_per_tick < 2000)
|
||||
usecs_per_tick = 2000;
|
||||
|
||||
if (usecs_per_tick > (256 * 80))
|
||||
{
|
||||
timer_no = 2;
|
||||
resolution = 320; /* usec */
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_no = 1;
|
||||
resolution = 80; /* usec */
|
||||
}
|
||||
|
||||
divisor = (usecs_per_tick + (resolution / 2)) / resolution;
|
||||
usecs_per_tmr = divisor * resolution;
|
||||
|
||||
arm_timer (timer_no, divisor);
|
||||
}
|
||||
|
||||
static void
|
||||
tmr_reset (void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
tmr_offs = 0;
|
||||
ticks_offs = 0;
|
||||
tmr_ctr = 0;
|
||||
next_event_time = 0xffffffff;
|
||||
prev_event_time = 0;
|
||||
curr_ticks = 0;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
timer_open (int dev, int mode)
|
||||
{
|
||||
if (opened)
|
||||
return RET_ERROR (EBUSY);
|
||||
|
||||
tmr_reset ();
|
||||
curr_tempo = 60;
|
||||
curr_timebase = HZ;
|
||||
opened = 1;
|
||||
reprogram_timer ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
timer_close (int dev)
|
||||
{
|
||||
opened = tmr_running = 0;
|
||||
gus_write8 (0x45, 0); /* Disable both timers */
|
||||
}
|
||||
|
||||
static int
|
||||
timer_event (int dev, unsigned char *event)
|
||||
{
|
||||
unsigned char cmd = event[1];
|
||||
unsigned long parm = *(int *) &event[4];
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case TMR_WAIT_REL:
|
||||
parm += prev_event_time;
|
||||
case TMR_WAIT_ABS:
|
||||
if (parm > 0)
|
||||
{
|
||||
long time;
|
||||
|
||||
if (parm <= curr_ticks) /* It's the time */
|
||||
return TIMER_NOT_ARMED;
|
||||
|
||||
time = parm;
|
||||
next_event_time = prev_event_time = time;
|
||||
|
||||
return TIMER_ARMED;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_START:
|
||||
tmr_reset ();
|
||||
tmr_running = 1;
|
||||
reprogram_timer ();
|
||||
break;
|
||||
|
||||
case TMR_STOP:
|
||||
tmr_running = 0;
|
||||
break;
|
||||
|
||||
case TMR_CONTINUE:
|
||||
tmr_running = 1;
|
||||
reprogram_timer ();
|
||||
break;
|
||||
|
||||
case TMR_TEMPO:
|
||||
if (parm)
|
||||
{
|
||||
if (parm < 8)
|
||||
parm = 8;
|
||||
if (parm > 250)
|
||||
parm = 250;
|
||||
tmr_offs = tmr_ctr;
|
||||
ticks_offs += tmr2ticks (tmr_ctr);
|
||||
tmr_ctr = 0;
|
||||
curr_tempo = parm;
|
||||
reprogram_timer ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_ECHO:
|
||||
seq_copy_to_input (event, 8);
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
return TIMER_NOT_ARMED;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
timer_get_time (int dev)
|
||||
{
|
||||
if (!opened)
|
||||
return 0;
|
||||
|
||||
return curr_ticks;
|
||||
}
|
||||
|
||||
static int
|
||||
timer_ioctl (int dev,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SNDCTL_TMR_SOURCE:
|
||||
return IOCTL_OUT (arg, TMR_INTERNAL);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_START:
|
||||
tmr_reset ();
|
||||
tmr_running = 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_STOP:
|
||||
tmr_running = 0;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_CONTINUE:
|
||||
tmr_running = 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TIMEBASE:
|
||||
{
|
||||
int val = IOCTL_IN (arg);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (val < 1)
|
||||
val = 1;
|
||||
if (val > 1000)
|
||||
val = 1000;
|
||||
curr_timebase = val;
|
||||
}
|
||||
|
||||
return IOCTL_OUT (arg, curr_timebase);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TEMPO:
|
||||
{
|
||||
int val = IOCTL_IN (arg);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (val < 8)
|
||||
val = 8;
|
||||
if (val > 250)
|
||||
val = 250;
|
||||
tmr_offs = tmr_ctr;
|
||||
ticks_offs += tmr2ticks (tmr_ctr);
|
||||
tmr_ctr = 0;
|
||||
curr_tempo = val;
|
||||
reprogram_timer ();
|
||||
}
|
||||
|
||||
return IOCTL_OUT (arg, curr_tempo);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_SEQ_CTRLRATE:
|
||||
if (IOCTL_IN (arg) != 0) /* Can't change */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_METRONOME:
|
||||
/* NOP */
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
timer_arm (int dev, long time)
|
||||
{
|
||||
if (time < 0)
|
||||
time = curr_ticks + 1;
|
||||
else if (time <= curr_ticks) /* It's the time */
|
||||
return;
|
||||
|
||||
next_event_time = prev_event_time = time;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct sound_timer_operations sound_timer =
|
||||
{
|
||||
{"OPL-3/GUS Timer", 0},
|
||||
1, /* Priority */
|
||||
0, /* Local device link */
|
||||
timer_open,
|
||||
timer_close,
|
||||
timer_event,
|
||||
timer_get_time,
|
||||
timer_ioctl,
|
||||
timer_arm
|
||||
};
|
||||
|
||||
void
|
||||
sound_timer_interrupt (void)
|
||||
{
|
||||
gus_write8 (0x45, 0); /* Ack IRQ */
|
||||
timer_command (4, 0x80); /* Reset IRQ flags */
|
||||
|
||||
if (!opened)
|
||||
return;
|
||||
|
||||
if (curr_timer == 1)
|
||||
gus_write8 (0x45, 0x04); /* Start timer 1 again */
|
||||
else
|
||||
gus_write8 (0x45, 0x08); /* Start timer 2 again */
|
||||
|
||||
if (!tmr_running)
|
||||
return;
|
||||
|
||||
tmr_ctr++;
|
||||
curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
|
||||
|
||||
if (curr_ticks >= next_event_time)
|
||||
{
|
||||
next_event_time = 0xffffffff;
|
||||
sequencer_timer ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sound_timer_init (int io_base)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (initialized)
|
||||
return; /* There is already a similar timer */
|
||||
|
||||
select_addr = io_base;
|
||||
data_addr = io_base + 1;
|
||||
|
||||
initialized = 1;
|
||||
|
||||
#if 1
|
||||
if (num_sound_timers >= MAX_TIMER_DEV)
|
||||
n = 0; /* Overwrite the system timer */
|
||||
else
|
||||
n = num_sound_timers++;
|
||||
#else
|
||||
n = 0;
|
||||
#endif
|
||||
|
||||
sound_timer_devs[n] = &sound_timer;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
401
sys/i386/isa/sound/soundcard.c
Normal file
401
sys/i386/isa/sound/soundcard.c
Normal file
@ -0,0 +1,401 @@
|
||||
/*
|
||||
* sound/386bsd/soundcard.c
|
||||
*
|
||||
* Soundcard driver for 386BSD.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#include "dev_table.h"
|
||||
|
||||
u_int snd1mask;
|
||||
u_int snd2mask;
|
||||
u_int snd3mask;
|
||||
u_int snd4mask;
|
||||
u_int snd5mask;
|
||||
u_int snd6mask;
|
||||
u_int snd7mask;
|
||||
u_int snd8mask;
|
||||
u_int snd9mask;
|
||||
|
||||
#define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
|
||||
|
||||
static int timer_running = 0;
|
||||
|
||||
static int soundcards_installed = 0; /* Number of installed
|
||||
* soundcards */
|
||||
static int soundcard_configured = 0;
|
||||
|
||||
static struct fileinfo files[SND_NDEVS];
|
||||
|
||||
int sndprobe (struct isa_device *dev);
|
||||
int sndattach (struct isa_device *dev);
|
||||
int sndopen (dev_t dev, int flags);
|
||||
int sndclose (dev_t dev, int flags);
|
||||
int sndioctl (dev_t dev, int cmd, caddr_t arg, int mode);
|
||||
int sndread (int dev, struct uio *uio);
|
||||
int sndwrite (int dev, struct uio *uio);
|
||||
int sndselect (int dev, int rw);
|
||||
static void sound_mem_init(void);
|
||||
|
||||
unsigned long
|
||||
get_time(void)
|
||||
{
|
||||
extern struct timeval time;
|
||||
struct timeval timecopy;
|
||||
int x;
|
||||
|
||||
x = splclock();
|
||||
timecopy = time;
|
||||
splx(x);
|
||||
return timecopy.tv_usec/(1000000/HZ) +
|
||||
(unsigned long)timecopy.tv_sec*HZ;
|
||||
}
|
||||
|
||||
int
|
||||
sndread (int dev, struct uio *buf)
|
||||
{
|
||||
int count = buf->uio_resid;
|
||||
|
||||
dev = minor (dev);
|
||||
|
||||
FIX_RETURN (sound_read_sw (dev, &files[dev], buf, count));
|
||||
}
|
||||
|
||||
int
|
||||
sndwrite (int dev, struct uio *buf)
|
||||
{
|
||||
int count = buf->uio_resid;
|
||||
|
||||
dev = minor (dev);
|
||||
|
||||
FIX_RETURN (sound_write_sw (dev, &files[dev], buf, count));
|
||||
}
|
||||
|
||||
int
|
||||
sndopen (dev_t dev, int flags)
|
||||
{
|
||||
int retval;
|
||||
|
||||
dev = minor (dev);
|
||||
|
||||
if (!soundcard_configured && dev)
|
||||
{
|
||||
printk ("SoundCard Error: The soundcard system has not been configured\n");
|
||||
FIX_RETURN (-ENODEV);
|
||||
}
|
||||
|
||||
files[dev].mode = 0;
|
||||
|
||||
if (flags & FREAD && flags & FWRITE)
|
||||
files[dev].mode = OPEN_READWRITE;
|
||||
else if (flags & FREAD)
|
||||
files[dev].mode = OPEN_READ;
|
||||
else if (flags & FWRITE)
|
||||
files[dev].mode = OPEN_WRITE;
|
||||
|
||||
FIX_RETURN(sound_open_sw (dev, &files[dev]));
|
||||
}
|
||||
|
||||
int
|
||||
sndclose (dev_t dev, int flags)
|
||||
{
|
||||
|
||||
dev = minor (dev);
|
||||
|
||||
sound_release_sw(dev, &files[dev]);
|
||||
FIX_RETURN (0);
|
||||
}
|
||||
|
||||
int
|
||||
sndioctl (dev_t dev, int cmd, caddr_t arg, int mode)
|
||||
{
|
||||
dev = minor (dev);
|
||||
|
||||
FIX_RETURN (sound_ioctl_sw (dev, &files[dev], cmd, (unsigned int) arg));
|
||||
}
|
||||
|
||||
int
|
||||
sndselect (int dev, int rw)
|
||||
{
|
||||
dev = minor (dev);
|
||||
|
||||
DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
|
||||
|
||||
FIX_RETURN (0);
|
||||
}
|
||||
|
||||
static short
|
||||
ipri_to_irq (unsigned short ipri)
|
||||
{
|
||||
/*
|
||||
* Converts the ipri (bitmask) to the corresponding irq number
|
||||
*/
|
||||
int irq;
|
||||
|
||||
for (irq = 0; irq < 16; irq++)
|
||||
if (ipri == (1 << irq))
|
||||
return irq;
|
||||
|
||||
return -1; /* Invalid argument */
|
||||
}
|
||||
|
||||
int
|
||||
sndprobe (struct isa_device *dev)
|
||||
{
|
||||
struct address_info hw_config;
|
||||
|
||||
hw_config.io_base = dev->id_iobase;
|
||||
hw_config.irq = ipri_to_irq (dev->id_irq);
|
||||
hw_config.dma = dev->id_drq;
|
||||
|
||||
return sndtable_probe (dev->id_unit, &hw_config);
|
||||
}
|
||||
|
||||
int
|
||||
sndattach (struct isa_device *dev)
|
||||
{
|
||||
int i;
|
||||
static int midi_initialized = 0;
|
||||
static int seq_initialized = 0;
|
||||
static int generic_midi_initialized = 0;
|
||||
unsigned long mem_start = 0xefffffff;
|
||||
struct address_info hw_config;
|
||||
|
||||
hw_config.io_base = dev->id_iobase;
|
||||
hw_config.irq = ipri_to_irq (dev->id_irq);
|
||||
hw_config.dma = dev->id_drq;
|
||||
|
||||
if (dev->id_unit) /* Card init */
|
||||
if (!sndtable_init_card (dev->id_unit, &hw_config))
|
||||
{
|
||||
printf (" <Driver not configured>");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Init the high level sound driver
|
||||
*/
|
||||
|
||||
if (!(soundcards_installed = sndtable_get_cardcount ()))
|
||||
{
|
||||
printf (" <No such hardware>");
|
||||
return FALSE; /* No cards detected */
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
if (num_audiodevs) /* Audio devices present */
|
||||
{
|
||||
mem_start = DMAbuf_init (mem_start);
|
||||
mem_start = audio_init (mem_start);
|
||||
sound_mem_init ();
|
||||
}
|
||||
|
||||
soundcard_configured = 1;
|
||||
#endif
|
||||
|
||||
if (num_midis && !midi_initialized)
|
||||
{
|
||||
midi_initialized = 1;
|
||||
mem_start = MIDIbuf_init (mem_start);
|
||||
}
|
||||
|
||||
if ((num_midis + num_synths) && !seq_initialized)
|
||||
{
|
||||
seq_initialized = 1;
|
||||
mem_start = sequencer_init (mem_start);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
tenmicrosec (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
inb (0x80);
|
||||
}
|
||||
|
||||
void
|
||||
request_sound_timer (int count)
|
||||
{
|
||||
static int current = 0;
|
||||
int tmp = count;
|
||||
|
||||
if (count < 0)
|
||||
timeout (sequencer_timer, 0, -count);
|
||||
else
|
||||
{
|
||||
|
||||
if (count < current)
|
||||
current = 0; /* Timer restarted */
|
||||
|
||||
count = count - current;
|
||||
|
||||
current = tmp;
|
||||
|
||||
if (!count)
|
||||
count = 1;
|
||||
|
||||
timeout (sequencer_timer, 0, count);
|
||||
}
|
||||
timer_running = 1;
|
||||
}
|
||||
|
||||
void
|
||||
sound_stop_timer (void)
|
||||
{
|
||||
if (timer_running)
|
||||
untimeout (sequencer_timer, 0);
|
||||
timer_running = 0;
|
||||
}
|
||||
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
static void
|
||||
sound_mem_init (void)
|
||||
{
|
||||
int i, dev;
|
||||
unsigned long dma_pagesize;
|
||||
static unsigned long dsp_init_mask = 0;
|
||||
|
||||
for (dev = 0; dev < num_audiodevs; dev++) /* Enumerate devices */
|
||||
if (!(dsp_init_mask & (1 << dev))) /* Not already done */
|
||||
if (sound_buffcounts[dev] > 0 && sound_dsp_dmachan[dev] > 0)
|
||||
{
|
||||
dsp_init_mask |= (1 << dev);
|
||||
|
||||
if (sound_dma_automode[dev])
|
||||
{
|
||||
sound_dma_automode[dev] = 0; /* Not possible with 386BSD */
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (sound_buffcounts[dev] == 1)
|
||||
{
|
||||
sound_buffcounts[dev] = 2;
|
||||
sound_buffsizes[dev] /= 2;
|
||||
}
|
||||
|
||||
if (sound_buffsizes[dev] > 65536) /* Larger is not possible (yet) */
|
||||
sound_buffsizes[dev] = 65536;
|
||||
|
||||
if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536)
|
||||
dma_pagesize = 131072; /* 128k */
|
||||
else
|
||||
dma_pagesize = 65536;
|
||||
|
||||
/* More sanity checks */
|
||||
|
||||
if (sound_buffsizes[dev] > dma_pagesize)
|
||||
sound_buffsizes[dev] = dma_pagesize;
|
||||
sound_buffsizes[dev] &= 0xfffff000; /* Truncate to n*4k */
|
||||
if (sound_buffsizes[dev] < 4096)
|
||||
sound_buffsizes[dev] = 4096;
|
||||
#else
|
||||
dma_pagesize = 4096;
|
||||
sound_buffsizes[dev] = 4096;
|
||||
sound_buffcounts[dev] = 16; /* 16*4k -> 64k */
|
||||
#endif
|
||||
|
||||
/* Now allocate the buffers */
|
||||
|
||||
for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++)
|
||||
{
|
||||
/*
|
||||
* The DMA buffer allocation algorithm hogs memory. We allocate
|
||||
* a memory area which is two times the requires size. This
|
||||
* guarantees that it contains at least one valid DMA buffer.
|
||||
*
|
||||
* This really needs some kind of finetuning.
|
||||
*/
|
||||
char *tmpbuf = malloc (2*sound_buffsizes[dev], M_DEVBUF, M_NOWAIT);
|
||||
unsigned long addr, rounded, start, end;
|
||||
|
||||
if (tmpbuf == NULL)
|
||||
{
|
||||
printk ("snd: Unable to allocate %d bytes of buffer\n",
|
||||
2 * sound_buffsizes[dev]);
|
||||
return;
|
||||
}
|
||||
|
||||
addr = kvtop (tmpbuf);
|
||||
/*
|
||||
* Align the start address if required
|
||||
*/
|
||||
start = (addr & ~(dma_pagesize - 1));
|
||||
end = ((addr+sound_buffsizes[dev]-1) & ~(dma_pagesize - 1));
|
||||
|
||||
if (start != end)
|
||||
rounded = end;
|
||||
else
|
||||
rounded = addr; /* Fits to the same DMA page */
|
||||
|
||||
snd_raw_buf[dev][snd_raw_count[dev]] =
|
||||
&tmpbuf[rounded - addr]; /* Compute offset */
|
||||
/*
|
||||
* Use virtual address as the physical address, since
|
||||
* isa_dmastart performs the phys address computation.
|
||||
*/
|
||||
snd_raw_buf_phys[dev][snd_raw_count[dev]] =
|
||||
(unsigned long) snd_raw_buf[dev][snd_raw_count[dev]];
|
||||
}
|
||||
} /* for dev */
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct isa_driver snddriver =
|
||||
{sndprobe, sndattach, "snd"};
|
||||
|
||||
int
|
||||
snd_ioctl_return (int *addr, int value)
|
||||
{
|
||||
if (value < 0)
|
||||
return value; /* Error */
|
||||
suword (addr, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
snd_set_irq_handler (int interrupt_level, void(*hndlr)(int))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
snd_release_irq(int vect)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
304
sys/i386/isa/sound/sys_timer.c
Normal file
304
sys/i386/isa/sound/sys_timer.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* sound/sys_timer.c
|
||||
*
|
||||
* The default timer for the Level 2 sequencer interface
|
||||
* Uses the (100HZ) timer of kernel.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SEQUENCER_C
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#ifndef EXCLUDE_SEQUENCER
|
||||
|
||||
static volatile int opened = 0, tmr_running = 0;
|
||||
static volatile time_t tmr_offs, tmr_ctr;
|
||||
static volatile unsigned long ticks_offs;
|
||||
static volatile int curr_tempo, curr_timebase;
|
||||
static volatile unsigned long curr_ticks;
|
||||
static volatile unsigned long next_event_time;
|
||||
static unsigned long prev_event_time;
|
||||
|
||||
static void poll_def_tmr (unsigned long dummy);
|
||||
|
||||
DEFINE_TIMER (def_tmr, poll_def_tmr);
|
||||
|
||||
static unsigned long
|
||||
tmr2ticks (int tmr_value)
|
||||
{
|
||||
/*
|
||||
* Convert system timer ticks (HZ) to MIDI ticks
|
||||
*/
|
||||
|
||||
unsigned long tmp;
|
||||
unsigned long scale;
|
||||
|
||||
tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */
|
||||
|
||||
scale = (60 * 1000) / (curr_tempo * curr_timebase); /* msecs per MIDI tick */
|
||||
|
||||
return (tmp + (scale / 2)) / scale;
|
||||
}
|
||||
|
||||
static void
|
||||
poll_def_tmr (unsigned long dummy)
|
||||
{
|
||||
|
||||
if (opened)
|
||||
{
|
||||
ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);
|
||||
|
||||
if (tmr_running)
|
||||
{
|
||||
tmr_ctr++;
|
||||
curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
|
||||
|
||||
if (curr_ticks >= next_event_time)
|
||||
{
|
||||
next_event_time = 0xffffffff;
|
||||
sequencer_timer ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tmr_reset (void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
tmr_offs = 0;
|
||||
ticks_offs = 0;
|
||||
tmr_ctr = 0;
|
||||
next_event_time = 0xffffffff;
|
||||
prev_event_time = 0;
|
||||
curr_ticks = 0;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
def_tmr_open (int dev, int mode)
|
||||
{
|
||||
if (opened)
|
||||
return RET_ERROR (EBUSY);
|
||||
|
||||
tmr_reset ();
|
||||
curr_tempo = 60;
|
||||
curr_timebase = HZ;
|
||||
opened = 1;
|
||||
|
||||
ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
def_tmr_close (int dev)
|
||||
{
|
||||
opened = tmr_running = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
def_tmr_event (int dev, unsigned char *event)
|
||||
{
|
||||
unsigned char cmd = event[1];
|
||||
unsigned long parm = *(int *) &event[4];
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case TMR_WAIT_REL:
|
||||
parm += prev_event_time;
|
||||
case TMR_WAIT_ABS:
|
||||
if (parm > 0)
|
||||
{
|
||||
long time;
|
||||
|
||||
if (parm <= curr_ticks) /* It's the time */
|
||||
return TIMER_NOT_ARMED;
|
||||
|
||||
time = parm;
|
||||
next_event_time = prev_event_time = time;
|
||||
|
||||
return TIMER_ARMED;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_START:
|
||||
tmr_reset ();
|
||||
tmr_running = 1;
|
||||
break;
|
||||
|
||||
case TMR_STOP:
|
||||
tmr_running = 0;
|
||||
break;
|
||||
|
||||
case TMR_CONTINUE:
|
||||
tmr_running = 1;
|
||||
break;
|
||||
|
||||
case TMR_TEMPO:
|
||||
if (parm)
|
||||
{
|
||||
if (parm < 8)
|
||||
parm = 8;
|
||||
if (parm > 250)
|
||||
parm = 250;
|
||||
tmr_offs = tmr_ctr;
|
||||
ticks_offs += tmr2ticks (tmr_ctr);
|
||||
tmr_ctr = 0;
|
||||
curr_tempo = parm;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_ECHO:
|
||||
seq_copy_to_input (event, 8);
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
return TIMER_NOT_ARMED;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
def_tmr_get_time (int dev)
|
||||
{
|
||||
if (!opened)
|
||||
return 0;
|
||||
|
||||
return curr_ticks;
|
||||
}
|
||||
|
||||
static int
|
||||
def_tmr_ioctl (int dev,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SNDCTL_TMR_SOURCE:
|
||||
return IOCTL_OUT (arg, TMR_INTERNAL);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_START:
|
||||
tmr_reset ();
|
||||
tmr_running = 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_STOP:
|
||||
tmr_running = 0;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_CONTINUE:
|
||||
tmr_running = 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TIMEBASE:
|
||||
{
|
||||
int val = IOCTL_IN (arg);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (val < 1)
|
||||
val = 1;
|
||||
if (val > 1000)
|
||||
val = 1000;
|
||||
curr_timebase = val;
|
||||
}
|
||||
|
||||
return IOCTL_OUT (arg, curr_timebase);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TEMPO:
|
||||
{
|
||||
int val = IOCTL_IN (arg);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (val < 8)
|
||||
val = 8;
|
||||
if (val > 250)
|
||||
val = 250;
|
||||
tmr_offs = tmr_ctr;
|
||||
ticks_offs += tmr2ticks (tmr_ctr);
|
||||
tmr_ctr = 0;
|
||||
curr_tempo = val;
|
||||
}
|
||||
|
||||
return IOCTL_OUT (arg, curr_tempo);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_SEQ_CTRLRATE:
|
||||
if (IOCTL_IN (arg) != 0) /* Can't change */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_METRONOME:
|
||||
/* NOP */
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
def_tmr_arm (int dev, long time)
|
||||
{
|
||||
if (time < 0)
|
||||
time = curr_ticks + 1;
|
||||
else if (time <= curr_ticks) /* It's the time */
|
||||
return;
|
||||
|
||||
next_event_time = prev_event_time = time;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct sound_timer_operations default_sound_timer =
|
||||
{
|
||||
{"System Timer", 0},
|
||||
0, /* Priority */
|
||||
0, /* Local device link */
|
||||
def_tmr_open,
|
||||
def_tmr_close,
|
||||
def_tmr_event,
|
||||
def_tmr_get_time,
|
||||
def_tmr_ioctl,
|
||||
def_tmr_arm
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
29
sys/i386/isa/sound/tuning.h
Normal file
29
sys/i386/isa/sound/tuning.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifdef SEQUENCER_C
|
||||
|
||||
unsigned short semitone_tuning[24] =
|
||||
{
|
||||
/* 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,
|
||||
/* 96 */ 10570, 10576, 10582, 10589
|
||||
};
|
||||
#else
|
||||
extern unsigned short semitone_tuning[24];
|
||||
extern unsigned short cent_tuning[100];
|
||||
#endif
|
323
sys/i386/isa/sound/uart6850.c
Normal file
323
sys/i386/isa/sound/uart6850.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* sound/uart6850.c
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl:
|
||||
* added 6850 support, used with COVOX SoundMaster II and custom cards.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#define DATAPORT (uart6850_base) /*
|
||||
* * * Midi6850 Data I/O Port on IBM
|
||||
* */
|
||||
#define COMDPORT (uart6850_base+1) /*
|
||||
* * * Midi6850 Command Port on IBM */
|
||||
#define STATPORT (uart6850_base+1) /*
|
||||
* * * Midi6850 Status Port on IBM */
|
||||
|
||||
#define uart6850_status() INB(STATPORT)
|
||||
#define input_avail() ((uart6850_status()&INPUT_AVAIL))
|
||||
#define output_ready() ((uart6850_status()&OUTPUT_READY))
|
||||
#define uart6850_cmd(cmd) OUTB(cmd, COMDPORT)
|
||||
#define uart6850_read() INB(DATAPORT)
|
||||
#define uart6850_write(byte) OUTB(byte, DATAPORT)
|
||||
|
||||
#define OUTPUT_READY 0x02 /*
|
||||
* * * Mask for Data Read Ready Bit */
|
||||
#define INPUT_AVAIL 0x01 /*
|
||||
* * * Mask for Data Send Ready Bit */
|
||||
|
||||
#define UART_RESET 0x95 /*
|
||||
* * * 6850 Total Reset Command */
|
||||
#define UART_MODE_ON 0x03 /*
|
||||
* * * 6850 Send/Receive UART Mode */
|
||||
|
||||
static int uart6850_opened = 0;
|
||||
static int uart6850_base = 0x330;
|
||||
static int uart6850_irq;
|
||||
static int uart6850_detected = 0;
|
||||
static int my_dev;
|
||||
|
||||
static int reset_uart6850 (void);
|
||||
static void (*midi_input_intr) (int dev, unsigned char data);
|
||||
|
||||
static void
|
||||
uart6850_input_loop (void)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 10;
|
||||
|
||||
while (count) /*
|
||||
* Not timed out
|
||||
*/
|
||||
if (input_avail ())
|
||||
{
|
||||
unsigned char c = uart6850_read ();
|
||||
|
||||
count = 100;
|
||||
|
||||
if (uart6850_opened & OPEN_READ)
|
||||
midi_input_intr (my_dev, c);
|
||||
}
|
||||
else
|
||||
while (!input_avail () && count)
|
||||
count--;
|
||||
}
|
||||
|
||||
void
|
||||
m6850intr (int unit)
|
||||
{
|
||||
printk ("M");
|
||||
if (input_avail ())
|
||||
uart6850_input_loop ();
|
||||
}
|
||||
|
||||
/*
|
||||
* It looks like there is no input interrupts in the UART mode. Let's try
|
||||
* polling.
|
||||
*/
|
||||
|
||||
static void
|
||||
poll_uart6850 (unsigned long dummy)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DEFINE_TIMER (uart6850_timer, poll_uart6850);
|
||||
|
||||
if (!(uart6850_opened & OPEN_READ))
|
||||
return; /*
|
||||
* No longer required
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (input_avail ())
|
||||
uart6850_input_loop ();
|
||||
|
||||
ACTIVATE_TIMER (uart6850_timer, poll_uart6850, 1); /*
|
||||
* Come back later
|
||||
*/
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_open (int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
void (*output) (int dev)
|
||||
)
|
||||
{
|
||||
if (uart6850_opened)
|
||||
{
|
||||
printk ("Midi6850: Midi busy\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
uart6850_cmd (UART_RESET);
|
||||
|
||||
uart6850_input_loop ();
|
||||
|
||||
midi_input_intr = input;
|
||||
uart6850_opened = mode;
|
||||
poll_uart6850 (0); /*
|
||||
* Enable input polling
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
uart6850_close (int dev)
|
||||
{
|
||||
uart6850_cmd (UART_MODE_ON);
|
||||
|
||||
uart6850_opened = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_out (int dev, unsigned char midi_byte)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Test for input since pending input seems to block the output.
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (input_avail ())
|
||||
uart6850_input_loop ();
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* Sometimes it takes about 13000 loops before the output becomes ready
|
||||
* (After reset). Normally it takes just about 10 loops.
|
||||
*/
|
||||
|
||||
for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /*
|
||||
* Wait
|
||||
*/
|
||||
|
||||
if (!output_ready ())
|
||||
{
|
||||
printk ("Midi6850: Timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uart6850_write (midi_byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_command (int dev, unsigned char *midi_byte)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_start_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_end_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_ioctl (int dev, unsigned cmd, unsigned arg)
|
||||
{
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
uart6850_kick (int dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_buffer_status (int dev)
|
||||
{
|
||||
return 0; /*
|
||||
* No data in buffers
|
||||
*/
|
||||
}
|
||||
|
||||
#define MIDI_SYNTH_NAME "6850 UART Midi"
|
||||
#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
|
||||
#include "midi_synth.h"
|
||||
|
||||
static struct midi_operations uart6850_operations =
|
||||
{
|
||||
{"6850 UART", 0, 0, SNDCARD_UART6850},
|
||||
&std_midi_synth,
|
||||
uart6850_open,
|
||||
uart6850_close,
|
||||
uart6850_ioctl,
|
||||
uart6850_out,
|
||||
uart6850_start_read,
|
||||
uart6850_end_read,
|
||||
uart6850_kick,
|
||||
uart6850_command,
|
||||
uart6850_buffer_status
|
||||
};
|
||||
|
||||
|
||||
long
|
||||
attach_uart6850 (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
int ok, timeout;
|
||||
unsigned long flags;
|
||||
|
||||
if (num_midis >= MAX_MIDI_DEV)
|
||||
{
|
||||
printk ("Sound: Too many midi devices detected\n");
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
uart6850_base = hw_config->io_base;
|
||||
uart6850_irq = hw_config->irq;
|
||||
|
||||
if (!uart6850_detected)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /*
|
||||
* Wait
|
||||
*/
|
||||
uart6850_cmd (UART_MODE_ON);
|
||||
|
||||
ok = 1;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
printk (" <6850 Midi Interface>");
|
||||
|
||||
std_midi_synth.midi_dev = my_dev = num_midis;
|
||||
midi_devs[num_midis++] = &uart6850_operations;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
static int
|
||||
reset_uart6850 (void)
|
||||
{
|
||||
uart6850_read ();
|
||||
return 1; /*
|
||||
* OK
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
probe_uart6850 (struct address_info *hw_config)
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
uart6850_base = hw_config->io_base;
|
||||
uart6850_irq = hw_config->irq;
|
||||
|
||||
if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0)
|
||||
return 0;
|
||||
|
||||
ok = reset_uart6850 ();
|
||||
|
||||
uart6850_detected = ok;
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
69
sys/i386/isa/sound/ulaw.h
Normal file
69
sys/i386/isa/sound/ulaw.h
Normal file
@ -0,0 +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,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
Loading…
Reference in New Issue
Block a user