mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-02 15:03:41 +00:00
Integrated Hannu Savolainen's new VoxWare sound drivers, version 2.4.
These drivers now have full SoundBlaster 16 support.
This commit is contained in:
parent
3507018b5b
commit
a75ba8fa22
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=1256
55
sys/i386/isa/sound/CHANGELOG
Normal file
55
sys/i386/isa/sound/CHANGELOG
Normal file
@ -0,0 +1,55 @@
|
||||
Changelog for version 2.4
|
||||
-------------------------
|
||||
|
||||
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.
|
@ -1,67 +1,68 @@
|
||||
Release notes for the Linux Sound Driver 1.99.9
|
||||
-----------------------------------------------
|
||||
Release notes for the Linux Sound Driver 2.4
|
||||
--------------------------------------------
|
||||
|
||||
******** THIS IS A BETA TEST RELEASE ********
|
||||
which means that there can be some untested things. In theory
|
||||
there is a risk that this driver causes some trouble to your system.
|
||||
You should not use this driver before backing up your disks.
|
||||
NOTE! The sound driver is a part of the Linux kernel distribution also.
|
||||
Check that your kernel doesn't have more recent version than this
|
||||
when installing a separately distributed sound driver. The
|
||||
version number of this driver is defined in the makefile.
|
||||
|
||||
This version contains a driver for the SB16 also.
|
||||
The SB16 driver requires separate DMA channels for the 8 and 16 bit
|
||||
modes. There should be a way to share the 8 bit DMA channels between
|
||||
these modes but this feature is not supported yet.
|
||||
The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de).
|
||||
|
||||
The SB16 driver has also the Midi input capability even at the same
|
||||
time with the /dev/dsp. Also the WaveBlaster daughter board is supported.
|
||||
No support for the ASP chip yet (the ASP chip can be installed but it's
|
||||
not used by the driver).
|
||||
|
||||
You will need the snd-util-2.4.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/*.
|
||||
|
||||
Welcome to use the Gravis UltraSound driver for Linux. This
|
||||
driver still supports the same cards than version 1.0c
|
||||
(SoundBlaster, SB Pro, Pro Audio Spectrum 16 and AdLib).
|
||||
In addition there is rather limited support for MPU-401
|
||||
There is a new version of the tracker program available (tracker-3_19.lzh) but
|
||||
I don't know where it is available. The tracker 3.10 has bugs and it don't work
|
||||
without some fixes. Look at the README of the snd-util-2.3.
|
||||
|
||||
If you are looking for the installation instructions, please
|
||||
look at linux/Readme.
|
||||
|
||||
This version supports the following soundcards:
|
||||
GUS, SoundBlaster, SB Pro, SB16, Pro Audio Spectrum 16 and AdLib.
|
||||
In addition there is rather limited support for MPU-401.
|
||||
(and compatible) midi cards. Also the OPL-3 synthesizer
|
||||
of the SB Pro and PAS16 cards is now supported in the 4 OP
|
||||
modes.
|
||||
Most of the features of the /dev/sequencer device file are
|
||||
available just for GUS owners.
|
||||
|
||||
The SoundBlaster 16 and SB 16 ASP cards are not supported.
|
||||
They could work in mono mode with speeds < 22 kHz.
|
||||
The OPL-3 chicp of the SB 16 should work (without problems?).
|
||||
Is there anybody willing to implement the SB 16 support
|
||||
(have the SB 16 and the SDK for it)?
|
||||
|
||||
|
||||
This is the first version of the driver which has almost
|
||||
all of the features which I have planned to include into
|
||||
version 2.0. Some features are still missing and some ones
|
||||
doesn't work.
|
||||
|
||||
NOTE! There are separate driver for CD-ROMS supported by
|
||||
some soundcards. The driver for CDU31A (Fusion 16) is
|
||||
called cdu31a-0.6.diff.z. It will be contained in the
|
||||
Linux version 0.99.12. The driver for the CD-ROM of SB Pro
|
||||
is sbpcd0.4.tar.gz (these were the latest versions when I wrote
|
||||
this). These files should be at least at sunsite.unc.edu.
|
||||
As far as I know, there is no driver for the SCSI interface of PAS16
|
||||
(yet).
|
||||
Also the SCSI interface of the PAS16 should be supported by
|
||||
Linux 0.99.13k and later.
|
||||
|
||||
There is also a driver for joystick. Look for file joystick-0.5.tar.gz
|
||||
(sunsite).
|
||||
|
||||
Since this driver is a sound driver, it will not contain support
|
||||
for SCSI/CD-ROM/Joystick -devices.
|
||||
|
||||
Compatibility with the earlier versions
|
||||
---------------------------------------
|
||||
|
||||
This is just like the version 1.99.7/1.99.8. There is just some minor
|
||||
enhancements. Most of them are portability fixes. If you are porting
|
||||
this driver to any OS, please look at the 386bsd/os.h. There is some
|
||||
new macros and some macros have more parameters. In addition this file
|
||||
contains some usefull comments.
|
||||
In this version the ultrasound.h no longer includes the sys/soundcard.h
|
||||
You have to change the gmod.c of the snd-util-2.0 package and to add an
|
||||
include for it.
|
||||
|
||||
**** There is some ISC and 386bsd stuff in this driver. Please stay away ****
|
||||
This stuff is here just because I want to be in sync with the porters. These
|
||||
ports don't work yet.
|
||||
IMPORTANT!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
This version is not binary or source compatible with the version 1.0c.
|
||||
|
||||
The ioctl() interface has changed completely since version 1.0c. All
|
||||
programs using this driver must be at least recompiled.
|
||||
The snd-util-1.99.6 package contains some utilities for this version.
|
||||
The snd-util-2.0 package contains some utilities for this version.
|
||||
|
||||
The version 1.0c and earlier used a 'nonportable' ioctl calling scheme
|
||||
where the input argument was passed by value and the output value was
|
||||
@ -78,59 +79,46 @@ After version 1.99.0 this must be done as the following:
|
||||
|
||||
If you have an application written for the version 1.0, you should search
|
||||
for the strings SNDCTL_ and SOUND_ and to check the parameters.
|
||||
The following ioctl calls have changed:
|
||||
|
||||
SNDCTL_SEQ_GETOUTCOUNT
|
||||
SNDCTL_SEQ_GETINCOUNT
|
||||
SNDCTL_SEQ_TESTMIDI
|
||||
SNDCTL_DSP_SPEED
|
||||
SNDCTL_DSP_STEREO
|
||||
SNDCTL_DSP_GETBLKSIZE
|
||||
SNDCTL_DSP_SAMPLESIZE
|
||||
SOUND_PCM_WRITE_CHANNELS
|
||||
SOUND_PCM_WRITE_FILTER
|
||||
SOUND_PCM_READ_RATE
|
||||
SOUND_PCM_READ_CHANNELS
|
||||
SOUND_PCM_READ_BITS
|
||||
SOUND_PCM_READ_FILTER
|
||||
SOUND_PCM_WRITE_BITS
|
||||
SOUND_PCM_WRITE_RATE
|
||||
SOUND_MIXER_READ_* (several ones)
|
||||
SOUND_MIXER_WRITE_* (several ones)
|
||||
|
||||
Since the this version will support more than one synthesizer devices
|
||||
at the same time, the ioctl(SNDCTL_FM_LOAD_INSTR) is obsolete. In addition
|
||||
there is some new fields which must be initialized. Look at the sbiset.c in
|
||||
the snd-util-1.99.6 package for further info.
|
||||
the snd-util-2.0 package for further info.
|
||||
|
||||
The GUS patch format has changed since the version 1.99.3. You have to
|
||||
use latest versions of the programs in the sound/gustest directory. In
|
||||
addition the version 0.4g of the Adagio package supports this format.
|
||||
This version is almost 100% compatible with the alpha test version (1.99.9). The
|
||||
difference is in the installation procedure.
|
||||
|
||||
New features
|
||||
Using this driver with other operating systems than Linux
|
||||
---------------------------------------------------------
|
||||
|
||||
This package contains just the Linux version. The version 2.3
|
||||
for SCO is available at nic.funet.fi:pub/OS/Linux/ALPHA/sound.
|
||||
The version 2.3 doesn't work well with xxxxxBSD. Use the version
|
||||
2.3 for them.
|
||||
|
||||
/dev/sndstat
|
||||
------------
|
||||
|
||||
There is also some changes which make this version more usable than
|
||||
the version 1.0c.
|
||||
|
||||
- /dev/dsp and /dev/audio
|
||||
|
||||
The DMA buffering is now little bit more intelligent than earlier. The
|
||||
buffer size is selected run-time so that a buffer holds data for 0.5 to
|
||||
1.0 seconds of recording or playback. This makes recording more comfortable
|
||||
than with version 1.0. With the previous version there was sometimes more
|
||||
than 10 seconds of delay before the driver returned the first input byte.
|
||||
|
||||
There is also support for more than one digitized voice devices. The device
|
||||
files /dev/dsp1 and /dev/audio1 (minor 19 and 20) are available with PAS16.
|
||||
The /dev/dsp (/dev/audio) is connected to the PCM circuit of the PAS16 itself
|
||||
and the /dev/dsp1 (/dev/audio1) to the SB emulation of PAS16 card. Two
|
||||
dsp/audio devices are available also if you have combination of SB and GUS.
|
||||
With GUS and PAS16 you will have even three dsp/audio devices. These devices
|
||||
can be used independently and can be active at the same time (3 channels
|
||||
at the same time propably don't work).
|
||||
|
||||
The dsp/audio support of PAS16 should be much cleaner now since the
|
||||
constant clicking sound between the DMA blocks (about once per second) has
|
||||
been eliminated.
|
||||
|
||||
The stereo playback of GUS doesn't work perfectly. There is lot of
|
||||
clicking in the output.
|
||||
|
||||
- /dev/mixer
|
||||
|
||||
No changes.
|
||||
|
||||
There is no mixer for the GUS yet.
|
||||
|
||||
- /dev/sequencer
|
||||
|
||||
This part has the most changes. Mostly to support the rich
|
||||
features of the Gravis UltraSound. There is also the support
|
||||
for the OPL-3 synthesizer chip.
|
||||
|
||||
- /dev/sndstat
|
||||
The /dev/sndstat is now available in the SCO and BSD versions also.
|
||||
|
||||
This is a new devicefile for debugging purposes. A better place for
|
||||
it is in the /proc -directory but I was just too lazy to implement it
|
||||
@ -139,11 +127,13 @@ info about the current configuration (see the example below). If you
|
||||
send me a error/problem report, please include a printout from this
|
||||
device to your message (cat /dev/sndstat).
|
||||
|
||||
Note! This device file is currently present only in the Linux version
|
||||
of this driver.
|
||||
|
||||
------ cut here --- cat /dev/sndstat example --------
|
||||
Sound Driver:1.99.7 (Fri Jul 9 17:01:47 GMT 1993 root@lucifer.savolai.fi)
|
||||
Config options: 0x00000d4b
|
||||
|
||||
Major number: 14
|
||||
HW config:
|
||||
Type 4: Gravis Ultrasound at 0x210 irq 15 drq 6
|
||||
Type 3: ProAudioSpectrum at 0x388 irq 10 drq 3
|
||||
@ -166,12 +156,15 @@ Midi devices:
|
||||
Mixer(s) installed
|
||||
------ cut here ---- End of Example -----------
|
||||
|
||||
Known bugs/limitations
|
||||
----------------------
|
||||
|
||||
Known bugs
|
||||
----------
|
||||
|
||||
- There was clicking during stereo playback to /dev/dsp with GUS.
|
||||
* Fixed in 1.99.9 *
|
||||
- High speed recording of long audio samples (>20 second) to disk
|
||||
is not possible. Everything works until next sync() which delays the
|
||||
recording process too much. A delay longer than 0.1 to 0.3 seconds is
|
||||
too much.
|
||||
- The SB16 driver sometimes swaps the left and right channels together.
|
||||
- Midi input doesn't work with SB and SB Pro (SB16 works).
|
||||
- It's not possible to open /dev/dsp (or /dev/audio) while the
|
||||
/dev/sequencer is open for output and GUS is the only soundcard
|
||||
installed. It's possible if /dev/dsp is opened before /dev/sequencer
|
||||
@ -180,12 +173,70 @@ Known bugs
|
||||
- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed.
|
||||
It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI
|
||||
adapter.
|
||||
- There are some problems in midi input with MPU-401 and the SB16 midi
|
||||
(MPU-401 emulation). This makes it impossible to read long sysex dumps
|
||||
using these devices.
|
||||
- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting
|
||||
^C and playing again should solve this problem. This is propably caused by
|
||||
incompatibilities between GUS and certain VLB motherboards. Try to avoid
|
||||
incompatibilities between GUS and certain VLB motherboards (like mine).
|
||||
Try to avoid
|
||||
switching between VTs while patches are being loaded to the GUS.
|
||||
- There was some problems with GUS and Mitsumi CD in version 1.99.8. Fixed
|
||||
in 1.99.9.
|
||||
- /dev/audio sounded like stereo with GUS. Fixed in 1.99.9.
|
||||
This problem disappears completely if you define GUS_PATCH_NO_DMA in the
|
||||
local.h (after make config in linux). The drawback is that patch loading
|
||||
without DMA takes several times longer than with DMA.
|
||||
- There is a skeleton of the patch manager support. It don't work in
|
||||
this version.
|
||||
|
||||
|
||||
Future development
|
||||
------------------
|
||||
|
||||
- Since this driver is no longer just the Linux Sound Driver, it's time
|
||||
to give it a new name. I have planned to use name VoxWare.
|
||||
- I'm writing a Hacker's guide to the VoxWare sound driver. Should
|
||||
be ready within this(/next) year (alpha version).
|
||||
- Completion of the ISC, SCO and BSD ports. Port to SVR4.2.
|
||||
- I'm interested to implement/include support for new soundcards and
|
||||
operating systems.
|
||||
|
||||
Hint for the soundcard and OS manufacturers:
|
||||
I'm collecting soundcards (high end ones) and SDKs for them. In
|
||||
addition I'm collecting PC operating systems. I will be happy if
|
||||
somebody sends me such items. In addition such kind of donation
|
||||
makes it easier to change the VoxWare driver to support your
|
||||
soundcard or operating system. However, please contact me before
|
||||
sending anything.
|
||||
|
||||
I will propably release some fix versions within this and next year. At
|
||||
least when the non-Linux versions get ready. The next major release (3.0)
|
||||
will be quite complete rewrite and released after about a year (end of 94 or
|
||||
beginning of 95).
|
||||
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
This driver contains code by several contributors. In addition several other
|
||||
persons have given usefull suggestions. The following is a list of major
|
||||
contributors. (I could have forgotten some names.)
|
||||
|
||||
Craig Metz 1/2 of the PAS16 Mixer and PCM support
|
||||
Rob Hooft Volume computation algorithm for the FM synth.
|
||||
Mika Liljeberg uLaw encoding and decoding routines
|
||||
Greg Lee Volume computation algorithm for the GUS and
|
||||
lot's of valuable suggestions.
|
||||
Andy Warner ISC port
|
||||
Jim Lowe FreeBSD port
|
||||
Anders Baekgaard Bughunting and valuable suggestions.
|
||||
Joerg Schubert SB16 DSP support.
|
||||
Andrew Robinson Improvements to the GUS driver
|
||||
|
||||
Regards,
|
||||
|
||||
Hannu Savolainen
|
||||
hsavolai@cs.helsinki.fi
|
||||
|
||||
Snail mail: Hannu Savolainen
|
||||
Pallaksentie 4 A 2
|
||||
00970 Helsinki
|
||||
Finland
|
||||
|
@ -1,6 +1,5 @@
|
||||
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/adlib_card.c
|
||||
* sound/adlib_card.c
|
||||
*
|
||||
* Detection routine for the AdLib card.
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/audio.c
|
||||
* sound/audio.c
|
||||
*
|
||||
* Device file manager for /dev/audio
|
||||
*
|
||||
@ -38,23 +38,45 @@
|
||||
#define OFF 0
|
||||
|
||||
static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a
|
||||
|
||||
* incomplete output block */
|
||||
static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
|
||||
|
||||
static int audio_mode[MAX_DSP_DEV];
|
||||
|
||||
#define AM_NONE 0
|
||||
#define AM_WRITE 1
|
||||
#define AM_READ 2
|
||||
|
||||
static char *wr_dma_buf[MAX_DSP_DEV];
|
||||
|
||||
int
|
||||
audio_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
int mode;
|
||||
int ret;
|
||||
int bits;
|
||||
int dev_type = dev & 0x0f;
|
||||
int mode = file->mode & O_ACCMODE;
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
|
||||
if (dev_type == SND_DEV_DSP16)
|
||||
bits = 16;
|
||||
else
|
||||
bits = 8;
|
||||
|
||||
if ((ret = DMAbuf_open (dev, mode)) < 0)
|
||||
return ret;
|
||||
|
||||
if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
|
||||
{
|
||||
audio_release (dev, file);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
wr_buff_no[dev] = -1;
|
||||
audio_mode[dev] = AM_NONE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -94,9 +116,9 @@ translate_bytes (const void *table, void *buff, unsigned long n)
|
||||
"1:\tlodsb\n\t"
|
||||
"xlatb\n\t"
|
||||
"stosb\n\t"
|
||||
"loop 1b\n\t":
|
||||
:"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
|
||||
:"bx", "cx", "di", "si", "ax");
|
||||
"loop 1b\n\t":
|
||||
: "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
|
||||
: "bx", "cx", "di", "si", "ax");
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -106,12 +128,20 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
int c, p, l;
|
||||
int err;
|
||||
int dev_type = dev & 0x0f;
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
p = 0;
|
||||
c = count;
|
||||
|
||||
if (audio_mode[dev] == AM_READ) /* Direction changed */
|
||||
{
|
||||
wr_buff_no[dev] = -1;
|
||||
}
|
||||
|
||||
audio_mode[dev] = AM_WRITE;
|
||||
|
||||
if (!count) /* Flush output */
|
||||
{
|
||||
if (wr_buff_no[dev] >= 0)
|
||||
@ -136,15 +166,25 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
|
||||
l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
|
||||
|
||||
COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
|
||||
if (!dsp_devs[dev]->copy_from_user)
|
||||
{ /* No device specific copy routine */
|
||||
COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
|
||||
}
|
||||
else
|
||||
dsp_devs[dev]->copy_from_user (dev,
|
||||
wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
|
||||
|
||||
|
||||
/* Insert local processing here */
|
||||
|
||||
if (dev_type == SND_DEV_AUDIO)
|
||||
{
|
||||
#ifdef linux
|
||||
/* This just allows interrupts while the conversion is running */
|
||||
__asm__ ("sti");
|
||||
/* This just allows interrupts while the conversion is running */
|
||||
__asm__ ("sti");
|
||||
#endif
|
||||
translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
|
||||
translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
|
||||
}
|
||||
|
||||
c -= l;
|
||||
p += l;
|
||||
@ -169,11 +209,24 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
int c, p, l;
|
||||
char *dmabuf;
|
||||
int buff_no;
|
||||
int dev_type = dev & 0x0f;
|
||||
|
||||
dev = dev >> 4;
|
||||
p = 0;
|
||||
c = count;
|
||||
|
||||
if (audio_mode[dev] == AM_WRITE)
|
||||
{
|
||||
if (wr_buff_no[dev] >= 0)
|
||||
{
|
||||
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
|
||||
|
||||
wr_buff_no[dev] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
audio_mode[dev] = AM_READ;
|
||||
|
||||
while (c)
|
||||
{
|
||||
if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
|
||||
@ -183,12 +236,16 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
l = c;
|
||||
|
||||
/* Insert any local processing here. */
|
||||
|
||||
if (dev_type == SND_DEV_AUDIO)
|
||||
{
|
||||
#ifdef linux
|
||||
/* This just allows interrupts while the conversion is running */
|
||||
__asm__ ("sti");
|
||||
/* This just allows interrupts while the conversion is running */
|
||||
__asm__ ("sti");
|
||||
#endif
|
||||
|
||||
translate_bytes (dsp_ulaw, dmabuf, l);
|
||||
translate_bytes (dsp_ulaw, dmabuf, l);
|
||||
}
|
||||
|
||||
COPY_TO_USER (buf, p, dmabuf, l);
|
||||
|
||||
@ -205,6 +262,8 @@ int
|
||||
audio_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
int dev_type = dev & 0x0f;
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
switch (cmd)
|
||||
@ -235,11 +294,10 @@ audio_ioctl (int dev, struct fileinfo *file,
|
||||
break;
|
||||
|
||||
default:
|
||||
#if 1
|
||||
return RET_ERROR (EIO);
|
||||
#else
|
||||
if (dev_type == SND_DEV_AUDIO)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
return DMAbuf_ioctl (dev, cmd, arg, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,14 +324,14 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
|
||||
int
|
||||
audio_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
{
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
void
|
||||
audio_release (int dev, struct fileinfo *file)
|
||||
{
|
||||
};
|
||||
{
|
||||
};
|
||||
int
|
||||
audio_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/dev_table.c
|
||||
* sound/dev_table.c
|
||||
*
|
||||
* Device call tables.
|
||||
*
|
||||
@ -38,21 +38,24 @@ sndtable_init (long mem_start)
|
||||
int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
|
||||
|
||||
for (i = 0; i < (n - 1); i++)
|
||||
if (supported_drivers[i].probe (&supported_drivers[i].config))
|
||||
{
|
||||
if (supported_drivers[i].enabled)
|
||||
if (supported_drivers[i].probe (&supported_drivers[i].config))
|
||||
{
|
||||
#ifndef SHORT_BANNERS
|
||||
printk ("snd%d",
|
||||
supported_drivers[i].card_type);
|
||||
printk ("snd%d",
|
||||
supported_drivers[i].card_type);
|
||||
#endif
|
||||
|
||||
mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
|
||||
mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
|
||||
#ifndef SHORT_BANNERS
|
||||
printk (" at 0x%03x irq %d drq %d\n",
|
||||
supported_drivers[i].config.io_base,
|
||||
supported_drivers[i].config.irq,
|
||||
supported_drivers[i].config.dma);
|
||||
printk (" at 0x%x irq %d drq %d\n",
|
||||
supported_drivers[i].config.io_base,
|
||||
supported_drivers[i].config.irq,
|
||||
supported_drivers[i].config.dma);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
supported_drivers[i].enabled = 0; /* Mark as not detected */
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
@ -66,7 +69,15 @@ sndtable_probe (int unit, struct address_info *hw_config)
|
||||
|
||||
for (i = 0; i < (n - 1); i++)
|
||||
if (supported_drivers[i].card_type == unit)
|
||||
return supported_drivers[i].probe (hw_config);
|
||||
{
|
||||
supported_drivers[i].config.io_base = hw_config->io_base;
|
||||
supported_drivers[i].config.irq = hw_config->irq;
|
||||
supported_drivers[i].config.dma = hw_config->dma;
|
||||
if (supported_drivers[i].probe (hw_config))
|
||||
return 1;
|
||||
supported_drivers[i].enabled = 0; /* Mark as not detected */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -86,6 +97,10 @@ sndtable_init_card (int unit, struct address_info *hw_config)
|
||||
for (i = 0; i < (n - 1); i++)
|
||||
if (supported_drivers[i].card_type == unit)
|
||||
{
|
||||
supported_drivers[i].config.io_base = hw_config->io_base;
|
||||
supported_drivers[i].config.irq = hw_config->irq;
|
||||
supported_drivers[i].config.dma = hw_config->dma;
|
||||
|
||||
if (supported_drivers[i].attach (0, hw_config) != 0)
|
||||
panic ("snd#: Invalid memory allocation\n");
|
||||
return TRUE;
|
||||
@ -100,4 +115,100 @@ sndtable_get_cardcount (void)
|
||||
return num_dspdevs + num_mixers + num_synths + num_midis;
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
void
|
||||
sound_setup (char *str, int *ints)
|
||||
{
|
||||
int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
|
||||
|
||||
/*
|
||||
* First disable all drivers
|
||||
*/
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
supported_drivers[i].enabled = 0;
|
||||
|
||||
if (ints[0] == 0 || ints[1] == 0)
|
||||
return;
|
||||
/*
|
||||
* Then enable them one by time
|
||||
*/
|
||||
|
||||
for (i = 1; i <= ints[0]; i++)
|
||||
{
|
||||
int card_type, ioaddr, irq, dma, ptr, j;
|
||||
unsigned int val;
|
||||
|
||||
val = (unsigned int) ints[i];
|
||||
|
||||
card_type = (val & 0x0ff00000) >> 20;
|
||||
|
||||
if (card_type > 127)
|
||||
{
|
||||
/* Add any future extensions here */
|
||||
return;
|
||||
}
|
||||
|
||||
ioaddr = (val & 0x000fff00) >> 8;
|
||||
irq = (val & 0x000000f0) >> 4;
|
||||
dma = (val & 0x0000000f);
|
||||
|
||||
ptr = -1;
|
||||
for (j = 0; j < n && ptr == -1; j++)
|
||||
if (supported_drivers[j].card_type == card_type)
|
||||
ptr = j;
|
||||
|
||||
if (ptr == -1)
|
||||
printk ("Sound: Invalid setup parameter 0x%08x\n", val);
|
||||
else
|
||||
{
|
||||
supported_drivers[ptr].enabled = 1;
|
||||
supported_drivers[ptr].config.io_base = ioaddr;
|
||||
supported_drivers[ptr].config.irq = irq;
|
||||
supported_drivers[ptr].config.dma = dma;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void
|
||||
sound_chconf (int card_type, int ioaddr, int irq, int dma)
|
||||
{
|
||||
int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
|
||||
|
||||
int ptr, j;
|
||||
|
||||
ptr = -1;
|
||||
for (j = 0; j < n && ptr == -1; j++)
|
||||
if (supported_drivers[j].card_type == card_type)
|
||||
ptr = j;
|
||||
|
||||
if (ptr != -1)
|
||||
{
|
||||
supported_drivers[ptr].enabled = 1;
|
||||
if (ioaddr)
|
||||
supported_drivers[ptr].config.io_base = ioaddr;
|
||||
if (irq)
|
||||
supported_drivers[ptr].config.irq = irq;
|
||||
if (dma)
|
||||
supported_drivers[ptr].config.dma = dma;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct address_info *
|
||||
sound_getconf (int card_type)
|
||||
{
|
||||
int j, ptr;
|
||||
int n = sizeof (supported_drivers) / sizeof (struct card_info);
|
||||
|
||||
ptr = -1;
|
||||
for (j = 0; j < n && ptr == -1; j++)
|
||||
if (supported_drivers[j].card_type == card_type)
|
||||
ptr = j;
|
||||
|
||||
if (ptr == -1)
|
||||
return (struct address_info *) NULL;
|
||||
|
||||
return &supported_drivers[ptr].config;
|
||||
}
|
||||
#endif
|
||||
|
@ -46,6 +46,7 @@ struct card_info {
|
||||
long (*attach) (long mem_start, struct address_info *hw_config);
|
||||
int (*probe) (struct address_info *hw_config);
|
||||
struct address_info config;
|
||||
int enabled;
|
||||
};
|
||||
|
||||
/** UWM -- new MIDI structure here.. **/
|
||||
@ -59,8 +60,10 @@ struct audio_operations {
|
||||
char name[32];
|
||||
int (*open) (int dev, int mode);
|
||||
void (*close) (int dev);
|
||||
void (*output_block) (int dev, unsigned long buf, int count, int intrflag);
|
||||
void (*start_input) (int dev, unsigned long buf, int count, int intrflag);
|
||||
void (*output_block) (int dev, unsigned long buf,
|
||||
int count, int intrflag, int dma_restart);
|
||||
void (*start_input) (int dev, unsigned long buf,
|
||||
int count, int intrflag, int dma_restart);
|
||||
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local);
|
||||
int (*prepare_for_input) (int dev, int bufsize, int nbufs);
|
||||
int (*prepare_for_output) (int dev, int bufsize, int nbufs);
|
||||
@ -159,31 +162,42 @@ struct generic_midi_operations {
|
||||
*/
|
||||
|
||||
struct card_info supported_drivers[] = {
|
||||
#ifndef EXCLUDE_MPU401
|
||||
#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
|
||||
{SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401,
|
||||
{MPU_BASE, MPU_IRQ, 0}},
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_GUS
|
||||
{SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus,
|
||||
{GUS_BASE, GUS_IRQ, GUS_DMA}},
|
||||
{MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_PAS
|
||||
{SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas,
|
||||
{PAS_BASE, PAS_IRQ, PAS_DMA}},
|
||||
{PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_SB
|
||||
{SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb,
|
||||
{SBC_BASE, SBC_IRQ, SBC_DMA}},
|
||||
{SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
|
||||
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
|
||||
#ifndef EXCLUDE_AUDIO
|
||||
{SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect,
|
||||
{SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
#ifndef EXCLUDE_MIDI
|
||||
{SNDCARD_SB16MIDI,"SB16 MPU-401", attach_sb16midi, probe_sb16midi,
|
||||
{SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_GUS
|
||||
{SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus,
|
||||
{GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_YM3812
|
||||
{SNDCARD_ADLIB, "AdLib", attach_adlib_card, probe_adlib,
|
||||
{FM_MONO, 0, 0}},
|
||||
{FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
|
||||
#endif
|
||||
{0, "*?*", NULL}
|
||||
{0, "*?*", NULL, 0}
|
||||
};
|
||||
|
||||
int num_sound_drivers =
|
||||
@ -220,6 +234,8 @@ struct generic_midi_operations {
|
||||
long sndtable_init(long mem_start);
|
||||
int sndtable_get_cardcount (void);
|
||||
long CMIDI_init(long mem_start); /* */
|
||||
struct address_info *sound_getconf(int card_type);
|
||||
void sound_chconf(int card_type, int ioaddr, int irq, int dma);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/dmabuf.c
|
||||
* sound/dmabuf.c
|
||||
*
|
||||
* The DMA buffer manager for digitized voice applications
|
||||
*
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
|
||||
|
||||
#define MAX_SUB_BUFFERS 16
|
||||
#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR)
|
||||
|
||||
/*
|
||||
* The DSP channel can be used either for input or output. Variable
|
||||
@ -48,7 +48,6 @@
|
||||
#define DMODE_NONE 0
|
||||
#define DMODE_OUTPUT 1
|
||||
#define DMODE_INPUT 2
|
||||
#define DMODE_INIT 3
|
||||
|
||||
DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]);
|
||||
|
||||
@ -58,22 +57,6 @@ static int dma_mode[MAX_DSP_DEV] =
|
||||
static volatile int dmabuf_interrupted[MAX_DSP_DEV] =
|
||||
{0};
|
||||
|
||||
#ifdef ISC
|
||||
/* I don't like this. */
|
||||
#undef INTERRUPTIBLE_SLEEP_ON
|
||||
#define INTERRUPTIBLE_SLEEP_ON(A,F) { \
|
||||
A = F = 1; \
|
||||
if (sleep(&(A), (PZERO + 5) | PCATCH)) { \
|
||||
A = F = 0; \
|
||||
dmabuf_interrupted[dev] = 1; \
|
||||
dev_busy[dev] = 0; \
|
||||
dma_reset(dev); \
|
||||
dmabuf_interrupted[dev] = 0; \
|
||||
/* longjmp(u.u_qsav, 1); Where it goes??? */ \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Pointers to raw buffers
|
||||
*/
|
||||
@ -89,7 +72,10 @@ int snd_raw_count[MAX_DSP_DEV];
|
||||
*/
|
||||
|
||||
static int dev_busy[MAX_DSP_DEV];
|
||||
static int dev_needs_restart[MAX_DSP_DEV];
|
||||
static int dev_modes[MAX_DSP_DEV];
|
||||
static int dev_active[MAX_DSP_DEV];
|
||||
static int dev_started[MAX_DSP_DEV];
|
||||
static int dev_qlen[MAX_DSP_DEV];
|
||||
static int dev_qhead[MAX_DSP_DEV];
|
||||
static int dev_qtail[MAX_DSP_DEV];
|
||||
@ -101,9 +87,11 @@ static int bufferalloc_done[MAX_DSP_DEV] =
|
||||
* Logical buffers for each devices
|
||||
*/
|
||||
|
||||
static int dev_nbufs[MAX_DSP_DEV]; /* # of logical buffers ( >=
|
||||
* sound_buffcounts[dev] */
|
||||
static int dev_nbufs[MAX_DSP_DEV]; /* # of logical buffers ( >=
|
||||
|
||||
* sound_buffcounts[dev] */
|
||||
static int dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS];
|
||||
static int dev_subdivision[MAX_DSP_DEV];
|
||||
static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS];
|
||||
static char *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] =
|
||||
{
|
||||
@ -117,8 +105,8 @@ reorganize_buffers (int dev)
|
||||
* This routine breaks the physical device buffers to logical ones.
|
||||
*/
|
||||
|
||||
unsigned long i, p, n;
|
||||
unsigned long sr, nc, sz, bsz;
|
||||
unsigned i, p, n;
|
||||
unsigned sr, nc, sz, bsz;
|
||||
|
||||
sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
|
||||
nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
|
||||
@ -148,6 +136,17 @@ reorganize_buffers (int dev)
|
||||
if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev])
|
||||
bsz >>= 1; /* Need at least 2 buffers */
|
||||
|
||||
if (dev_subdivision[dev] == 0)
|
||||
dev_subdivision[dev] = 1; /* Default value */
|
||||
|
||||
bsz /= dev_subdivision[dev]; /* Use smaller buffers */
|
||||
|
||||
if (bsz == 0)
|
||||
bsz = 4096; /* Just a sanity check */
|
||||
|
||||
while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS)
|
||||
bsz <<= 1; /* Too much buffers */
|
||||
|
||||
dev_buffsize[dev] = bsz;
|
||||
n = 0;
|
||||
|
||||
@ -178,6 +177,21 @@ reorganize_buffers (int dev)
|
||||
bufferalloc_done[dev] = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
dma_init_buffers (int dev)
|
||||
{
|
||||
RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
dev_underrun[dev] = 0;
|
||||
|
||||
dev_busy[dev] = 1;
|
||||
|
||||
bufferalloc_done[dev] = 0;
|
||||
|
||||
dev_active[dev] = dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
|
||||
dev_needs_restart[dev] = dev_started[dev] = 0;
|
||||
dma_mode[dev] = DMODE_NONE;
|
||||
}
|
||||
|
||||
int
|
||||
DMAbuf_open (int dev, int mode)
|
||||
{
|
||||
@ -198,20 +212,23 @@ DMAbuf_open (int dev, int mode)
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
#ifdef USE_RUNTIME_DMAMEM
|
||||
sound_dma_malloc (dev);
|
||||
#endif
|
||||
|
||||
if (snd_raw_buf[dev][0] == NULL)
|
||||
return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
|
||||
|
||||
if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)
|
||||
return retval;
|
||||
|
||||
dev_underrun[dev] = 0;
|
||||
dev_modes[dev] = mode;
|
||||
dev_subdivision[dev] = 0;
|
||||
|
||||
dev_busy[dev] = 1;
|
||||
|
||||
reorganize_buffers (dev);
|
||||
bufferalloc_done[dev] = 0;
|
||||
|
||||
dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
|
||||
dma_init_buffers (dev);
|
||||
dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
|
||||
dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
|
||||
dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -219,12 +236,19 @@ DMAbuf_open (int dev, int mode)
|
||||
static void
|
||||
dma_reset (int dev)
|
||||
{
|
||||
dsp_devs[dev]->reset (dev);
|
||||
int retval;
|
||||
unsigned long flags;
|
||||
|
||||
dev_qlen[dev] = 0;
|
||||
dev_qhead[dev] = 0;
|
||||
dev_qtail[dev] = 0;
|
||||
dev_active[dev] = 0;
|
||||
DISABLE_INTR (flags);
|
||||
dsp_devs[dev]->reset (dev);
|
||||
dsp_devs[dev]->close (dev);
|
||||
|
||||
if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0)
|
||||
printk ("Sound: Reset failed - Can't reopen device\n");
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
dma_init_buffers (dev);
|
||||
reorganize_buffers (dev);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -241,11 +265,11 @@ dma_sync (int dev)
|
||||
timed_out = 0;
|
||||
time = GET_TIME ();
|
||||
|
||||
while ((!(PROCESS_ABORTING || dmabuf_interrupted[dev]) && !timed_out)
|
||||
while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
|
||||
dmabuf_interrupted[dev]) && !timed_out)
|
||||
&& dev_qlen[dev])
|
||||
{
|
||||
REQUEST_TIMEOUT (10 * HZ, dev_sleeper[dev]);
|
||||
INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
|
||||
if ((GET_TIME () - time) > (10 * HZ))
|
||||
timed_out = 1;
|
||||
}
|
||||
@ -259,11 +283,11 @@ dma_sync (int dev)
|
||||
DISABLE_INTR (flags);
|
||||
if (dsp_devs[dev]->has_output_drained) /* Device has hidden buffers */
|
||||
{
|
||||
while (!(PROCESS_ABORTING || dmabuf_interrupted[dev])
|
||||
while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
|
||||
dmabuf_interrupted[dev])
|
||||
&& !dsp_devs[dev]->has_output_drained (dev))
|
||||
{
|
||||
REQUEST_TIMEOUT (HZ / 4, dev_sleeper[dev]);
|
||||
INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4);
|
||||
}
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
@ -275,16 +299,20 @@ int
|
||||
DMAbuf_release (int dev, int mode)
|
||||
{
|
||||
|
||||
if (!(PROCESS_ABORTING || dmabuf_interrupted[dev])
|
||||
if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
|
||||
dmabuf_interrupted[dev])
|
||||
&& (dma_mode[dev] == DMODE_OUTPUT))
|
||||
{
|
||||
dma_sync (dev);
|
||||
}
|
||||
|
||||
dma_reset (dev);
|
||||
#ifdef USE_RUNTIME_DMAMEM
|
||||
sound_dma_free (dev);
|
||||
#endif
|
||||
|
||||
if (!dev_active[dev])
|
||||
dsp_devs[dev]->close (dev);
|
||||
dsp_devs[dev]->reset (dev);
|
||||
|
||||
dsp_devs[dev]->close (dev);
|
||||
|
||||
dma_mode[dev] = DMODE_NONE;
|
||||
dev_busy[dev] = 0;
|
||||
@ -296,40 +324,65 @@ int
|
||||
DMAbuf_getrdbuffer (int dev, char **buf, int *len)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!bufferalloc_done[dev])
|
||||
reorganize_buffers (dev);
|
||||
|
||||
if (!dma_mode[dev])
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = dsp_devs[dev]->prepare_for_input (dev,
|
||||
dev_buffsize[dev], dev_nbufs[dev])) < 0)
|
||||
return err;
|
||||
dma_mode[dev] = DMODE_INPUT;
|
||||
}
|
||||
|
||||
if (dma_mode[dev] != DMODE_INPUT)
|
||||
return RET_ERROR (EBUSY); /* Can't change mode on fly */
|
||||
int err = EIO;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (!dev_qlen[dev])
|
||||
{
|
||||
if (dev_needs_restart[dev])
|
||||
{
|
||||
dma_reset (dev);
|
||||
dev_needs_restart[dev] = 0;
|
||||
}
|
||||
|
||||
if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */
|
||||
{
|
||||
dma_sync (dev);
|
||||
dma_reset (dev);
|
||||
dma_mode[dev] = DMODE_NONE;
|
||||
}
|
||||
|
||||
if (!bufferalloc_done[dev])
|
||||
reorganize_buffers (dev);
|
||||
|
||||
if (!dma_mode[dev])
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = dsp_devs[dev]->prepare_for_input (dev,
|
||||
dev_buffsize[dev], dev_nbufs[dev])) < 0)
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
return err;
|
||||
}
|
||||
dma_mode[dev] = DMODE_INPUT;
|
||||
}
|
||||
|
||||
if (!dev_active[dev])
|
||||
{
|
||||
dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], dev_buffsize[dev], 0);
|
||||
dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
|
||||
dev_buffsize[dev], 0,
|
||||
!sound_dma_automode[dev] ||
|
||||
!dev_started[dev]);
|
||||
dev_active[dev] = 1;
|
||||
dev_started[dev] = 1;
|
||||
}
|
||||
|
||||
/* Wait for the next block */
|
||||
REQUEST_TIMEOUT (10 * HZ, dev_sleeper[dev]);
|
||||
INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
|
||||
if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
|
||||
err = EIO;
|
||||
SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
}
|
||||
else
|
||||
err = EINTR;
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
if (!dev_qlen[dev])
|
||||
return RET_ERROR (EINTR);
|
||||
return RET_ERROR (err);
|
||||
|
||||
*buf = &dev_buf[dev][dev_qhead[dev]][dev_counts[dev][dev_qhead[dev]]];
|
||||
*len = dev_buffsize[dev] - dev_counts[dev][dev_qhead[dev]];
|
||||
@ -391,6 +444,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
|
||||
case SNDCTL_DSP_SYNC:
|
||||
dma_sync (dev);
|
||||
dma_reset (dev);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
@ -401,6 +455,32 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
return IOCTL_OUT (arg, dev_buffsize[dev]);
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_SUBDIVIDE:
|
||||
{
|
||||
int fact = IOCTL_IN (arg);
|
||||
|
||||
if (fact == 0)
|
||||
{
|
||||
fact = dev_subdivision[dev];
|
||||
if (fact == 0)
|
||||
fact = 1;
|
||||
return IOCTL_OUT (arg, fact);
|
||||
}
|
||||
|
||||
if (dev_subdivision[dev] != 0) /* Too late to change */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
if (fact > MAX_REALTIME_FACTOR)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
dev_subdivision[dev] = fact;
|
||||
return IOCTL_OUT (arg, fact);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return dsp_devs[dev]->ioctl (dev, cmd, arg, local);
|
||||
}
|
||||
@ -412,6 +492,20 @@ int
|
||||
DMAbuf_getwrbuffer (int dev, char **buf, int *size)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err = EIO;
|
||||
|
||||
if (dma_mode[dev] == DMODE_INPUT) /* Was input -> Direction change */
|
||||
{
|
||||
dma_reset (dev);
|
||||
dma_mode[dev] = DMODE_NONE;
|
||||
}
|
||||
else if (dev_needs_restart[dev]) /* Restart buffering */
|
||||
{
|
||||
dma_sync (dev);
|
||||
dma_reset (dev);
|
||||
}
|
||||
|
||||
dev_needs_restart[dev] = 0;
|
||||
|
||||
if (!bufferalloc_done[dev])
|
||||
reorganize_buffers (dev);
|
||||
@ -426,10 +520,11 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (dma_mode[dev] != DMODE_OUTPUT)
|
||||
return RET_ERROR (EBUSY); /* Can't change mode on fly */
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
|
||||
if (dev_qlen[dev] == dev_nbufs[dev])
|
||||
{
|
||||
if (!dev_active[dev])
|
||||
@ -440,14 +535,20 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size)
|
||||
}
|
||||
|
||||
/* Wait for free space */
|
||||
REQUEST_TIMEOUT (60 * HZ, dev_sleeper[dev]); /* GUS requires up to 60
|
||||
* sec */
|
||||
INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
|
||||
if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
|
||||
err = EIO;
|
||||
SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
}
|
||||
else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
err = EINTR;
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
if (dev_qlen[dev] == dev_nbufs[dev])
|
||||
return RET_ERROR (EIO); /* We have got signal (?) */
|
||||
return RET_ERROR (err); /* We have got signal (?) */
|
||||
|
||||
*buf = dev_buf[dev][dev_qtail[dev]];
|
||||
*size = dev_buffsize[dev];
|
||||
@ -466,12 +567,17 @@ DMAbuf_start_output (int dev, int buff_no, int l)
|
||||
|
||||
dev_counts[dev][dev_qtail[dev]] = l;
|
||||
|
||||
dev_needs_restart[dev] = (l != dev_buffsize[dev]);
|
||||
|
||||
dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
|
||||
|
||||
if (!dev_active[dev])
|
||||
{
|
||||
dev_active[dev] = 1;
|
||||
dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], dev_counts[dev][dev_qhead[dev]], 0);
|
||||
dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
|
||||
dev_counts[dev][dev_qhead[dev]], 0,
|
||||
!sound_dma_automode[dev] || !dev_started[dev]);
|
||||
dev_started[dev] = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -500,9 +606,9 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
|
||||
disable_dma (chan);
|
||||
clear_dma_ff (chan);
|
||||
set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
|
||||
set_dma_addr (chan, snd_raw_buf_phys[dev][0]);
|
||||
set_dma_count (chan, sound_buffsizes[dev]);
|
||||
enable_dma (chan);
|
||||
set_dma_addr (chan, (caddr_t)snd_raw_buf_phys[dev][0]);
|
||||
set_dma_count (chan, (unsigned)sound_buffsizes[dev]);
|
||||
enable_dma ((unsigned)chan);
|
||||
RESTORE_INTR (flags);
|
||||
#else
|
||||
|
||||
@ -511,16 +617,22 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
|
||||
|
||||
isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
|
||||
(caddr_t)snd_raw_buf_phys[dev][0],
|
||||
(unsigned)sound_buffsizes[dev],
|
||||
(unsigned)chan);
|
||||
sound_buffsizes[dev],
|
||||
chan);
|
||||
#else
|
||||
#ifdef ISC
|
||||
#if defined(ISC) || defined(SCO)
|
||||
#ifndef DMAMODE_AUTO
|
||||
printk ("sound: Invalid DMA mode for device %d\n", dev);
|
||||
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) | DMAMODE_AUTO,
|
||||
snd_raw_buf_phys[dev][0], count - 1);
|
||||
#endif
|
||||
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
|
||||
#ifdef DMAMODE_AUTO
|
||||
| DMAMODE_AUTO
|
||||
#endif
|
||||
,
|
||||
snd_raw_buf_phys[dev][0], count);
|
||||
dma_enable (chan);
|
||||
#else
|
||||
# error This routine is not valid for this OS.
|
||||
#error This routine is not valid for this OS.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -545,12 +657,12 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
|
||||
chan);
|
||||
#else
|
||||
|
||||
#ifdef ISC
|
||||
#if defined(ISC) || defined(SCO)
|
||||
dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
|
||||
physaddr, count - 1);
|
||||
physaddr, count);
|
||||
dma_enable (chan);
|
||||
#else
|
||||
# error This routine is not valid for this OS.
|
||||
#error This routine is not valid for this OS.
|
||||
#endif /* !ISC */
|
||||
#endif
|
||||
|
||||
@ -584,37 +696,32 @@ DMAbuf_init (long mem_start)
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_outputintr (int dev)
|
||||
DMAbuf_outputintr (int dev, int underrun_flag)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_active[dev] = 0;
|
||||
dev_qlen[dev]--;
|
||||
dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
|
||||
dev_active[dev] = 0;
|
||||
|
||||
if (dev_qlen[dev])
|
||||
{
|
||||
dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], dev_counts[dev][dev_qhead[dev]], 1);
|
||||
dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
|
||||
dev_counts[dev][dev_qhead[dev]], 1,
|
||||
!sound_dma_automode[dev]);
|
||||
dev_active[dev] = 1;
|
||||
}
|
||||
else
|
||||
else if (underrun_flag)
|
||||
{
|
||||
if (dev_busy[dev])
|
||||
{
|
||||
dev_underrun[dev]++;
|
||||
dsp_devs[dev]->halt_xfer (dev);
|
||||
}
|
||||
else
|
||||
{ /* Device has been closed */
|
||||
dsp_devs[dev]->close (dev);
|
||||
}
|
||||
dev_underrun[dev]++;
|
||||
dsp_devs[dev]->halt_xfer (dev);
|
||||
dev_needs_restart[dev] = 1;
|
||||
}
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (dev_sleep_flag[dev])
|
||||
if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
dev_sleep_flag[dev] = 0;
|
||||
WAKE_UP (dev_sleeper[dev]);
|
||||
WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
@ -624,30 +731,33 @@ DMAbuf_inputintr (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_active[dev] = 0;
|
||||
if (!dev_busy[dev])
|
||||
{
|
||||
dsp_devs[dev]->close (dev);
|
||||
}
|
||||
else if (dev_qlen[dev] == (dev_nbufs[dev] - 1))
|
||||
{
|
||||
printk ("Sound: Recording overrun\n");
|
||||
dev_underrun[dev]++;
|
||||
dsp_devs[dev]->halt_xfer (dev);
|
||||
dev_active[dev] = 0;
|
||||
dev_needs_restart[dev] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dev_qlen[dev]++;
|
||||
dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
|
||||
|
||||
dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], dev_buffsize[dev], 1);
|
||||
dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
|
||||
dev_buffsize[dev], 1,
|
||||
!sound_dma_automode[dev]);
|
||||
dev_active[dev] = 1;
|
||||
}
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (dev_sleep_flag[dev])
|
||||
if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
|
||||
{
|
||||
dev_sleep_flag[dev] = 0;
|
||||
WAKE_UP (dev_sleeper[dev]);
|
||||
WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
@ -697,7 +807,7 @@ DMAbuf_reset_dma (int chan)
|
||||
*/
|
||||
|
||||
#else
|
||||
/* Stub versions if audio services not included */
|
||||
/* Stub versions if audio services not included */
|
||||
|
||||
int
|
||||
DMAbuf_open (int dev, int mode)
|
||||
@ -784,7 +894,7 @@ DMAbuf_inputintr (int dev)
|
||||
}
|
||||
|
||||
void
|
||||
DMAbuf_outputintr (int dev)
|
||||
DMAbuf_outputintr (int dev, int underrun_flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/gus_card.c
|
||||
* sound/gus_card.c
|
||||
*
|
||||
* Detection routine for the Gravis Ultrasound.
|
||||
*
|
||||
@ -37,76 +37,12 @@ void gusintr (int);
|
||||
|
||||
int gus_base, gus_irq, gus_dma;
|
||||
|
||||
static int
|
||||
set_gus_irq (int interrupt_level)
|
||||
{
|
||||
int retcode = EINVAL;
|
||||
|
||||
#ifdef linux
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = gusintr;
|
||||
|
||||
#ifdef SND_SA_INTERRUPT
|
||||
sa.sa_flags = SA_INTERRUPT;
|
||||
#else
|
||||
sa.sa_flags = 0;
|
||||
#endif
|
||||
|
||||
sa.sa_mask = 0;
|
||||
sa.sa_restorer = NULL;
|
||||
|
||||
retcode = irqaction (interrupt_level, &sa);
|
||||
|
||||
if (retcode < 0)
|
||||
{
|
||||
printk ("GUS: IRQ%d already in use\n", interrupt_level);
|
||||
}
|
||||
|
||||
#else
|
||||
/* # error Unimplemented for this OS */
|
||||
#endif
|
||||
return retcode;
|
||||
}
|
||||
|
||||
int
|
||||
gus_set_midi_irq (int interrupt_level)
|
||||
{
|
||||
int retcode = EINVAL;
|
||||
|
||||
#ifdef linux
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = gus_midi_interrupt;
|
||||
|
||||
#ifdef SND_SA_INTERRUPT
|
||||
sa.sa_flags = SA_INTERRUPT;
|
||||
#else
|
||||
sa.sa_flags = 0;
|
||||
#endif
|
||||
|
||||
sa.sa_mask = 0;
|
||||
sa.sa_restorer = NULL;
|
||||
|
||||
retcode = irqaction (interrupt_level, &sa);
|
||||
|
||||
if (retcode < 0)
|
||||
{
|
||||
printk ("GUS: IRQ%d already in use\n", interrupt_level);
|
||||
}
|
||||
|
||||
#else
|
||||
/* # error Unimplemented for this OS */
|
||||
#endif
|
||||
return retcode;
|
||||
}
|
||||
|
||||
long
|
||||
attach_gus_card (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
int io_addr;
|
||||
|
||||
set_gus_irq (hw_config->irq);
|
||||
snd_set_irq_handler (hw_config->irq, gusintr);
|
||||
|
||||
if (gus_wave_detect (hw_config->io_base)) /* Try first the default */
|
||||
{
|
||||
@ -127,7 +63,7 @@ attach_gus_card (long mem_start, struct address_info *hw_config)
|
||||
if (io_addr != hw_config->io_base) /* Already tested */
|
||||
if (gus_wave_detect (io_addr))
|
||||
{
|
||||
printk (" WARNING! GUS found at %03x, config was %03x ", io_addr, hw_config->io_base);
|
||||
printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
|
||||
mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
|
||||
#ifndef EXCLUDE_MIDI
|
||||
mem_start = gus_midi_init (mem_start);
|
||||
@ -168,7 +104,10 @@ void
|
||||
gusintr (int unit)
|
||||
{
|
||||
unsigned char src;
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef linux
|
||||
sti ();
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
@ -195,9 +134,7 @@ gusintr (int unit)
|
||||
|
||||
if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
gus_voice_irq ();
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/gus2_midi.c
|
||||
* sound/gus2_midi.c
|
||||
*
|
||||
* The low level driver for the GUS Midi Interface.
|
||||
*
|
||||
@ -215,7 +215,7 @@ gus_midi_buffer_status (int dev)
|
||||
|
||||
static struct midi_operations gus_midi_operations =
|
||||
{
|
||||
{"Gravis UltraSound", 0},
|
||||
{"Gravis UltraSound", 0, 0, SNDCARD_GUS},
|
||||
gus_midi_open,
|
||||
gus_midi_close,
|
||||
gus_midi_ioctl,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* gus_vol.c - Compute volume for GUS.
|
||||
*
|
||||
* Greg Lee 1993.
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
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
|
||||
@ -31,35 +31,48 @@ 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. */
|
||||
/*
|
||||
* Boost expression by voice volume above neutral.
|
||||
*/
|
||||
if (voicev > 65)
|
||||
xpn += voicev - 64;
|
||||
xpn += (voicev - 64) / 2;
|
||||
|
||||
/* Combine multiplicative and level components. */
|
||||
/*
|
||||
* Combine multiplicative and level components.
|
||||
*/
|
||||
x = vel * xpn * 6 + (voicev / 4) * x;
|
||||
|
||||
#ifdef GUS_VOLUME
|
||||
/*
|
||||
/*
|
||||
* Further adjustment by installation-specific master volume control
|
||||
* (default 50).
|
||||
* (default 60).
|
||||
*/
|
||||
x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
|
||||
#endif
|
||||
|
||||
if (x < (1 << 11))
|
||||
return (11 << 8);
|
||||
#ifdef GUS_USE_CHN_MAIN_VOLUME
|
||||
/*
|
||||
* Experimental support for the channel main volume
|
||||
*/
|
||||
|
||||
mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
|
||||
x = (x * mainv * mainv) / 16384;
|
||||
#endif
|
||||
|
||||
if (x < 2)
|
||||
return (0);
|
||||
else if (x >= 65535)
|
||||
return ((15 << 8) | 255);
|
||||
|
||||
/*
|
||||
/*
|
||||
* Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
|
||||
* mantissa m.
|
||||
*/
|
||||
@ -76,13 +89,15 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
|
||||
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. */
|
||||
/*
|
||||
* Adjust mantissa to 8 bits.
|
||||
*/
|
||||
if (m > 0)
|
||||
{
|
||||
if (i > 8)
|
||||
@ -91,10 +106,6 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
|
||||
m <<= 8 - i;
|
||||
}
|
||||
|
||||
/* low volumes give occasional sour notes */
|
||||
if (i < 11)
|
||||
return (11 << 8);
|
||||
|
||||
return ((i << 8) + m);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,14 @@
|
||||
/* These few lines are used by FreeBSD (only??). */
|
||||
|
||||
/* for FreeBSD */
|
||||
#include "snd.h"
|
||||
|
||||
#if NSND > 0
|
||||
#define CONFIGURE_SOUNDCARD
|
||||
#define KERNEL_SOUNDCARD
|
||||
#endif
|
||||
|
||||
#define DSP_BUFFSIZE 32768
|
||||
#define SELECTED_SOUND_OPTIONS 0xffffffff
|
||||
#define SOUND_VERSION_STRING "2.4"
|
||||
#define SOUND_CONFIG_DATE "Mon Mar 7 23:54:09 PST 1994"
|
||||
#define SOUND_CONFIG_BY "swallace"
|
||||
#define SOUND_CONFIG_HOST "freefall.cdrom.com"
|
||||
#define SOUND_CONFIG_DOMAIN ""
|
||||
|
@ -31,24 +31,27 @@
|
||||
#ifndef EXCLUDE_CHIP_MIDI
|
||||
|
||||
|
||||
static int generic_midi_busy[MAX_MIDI_DEV];
|
||||
static int generic_midi_busy[MAX_MIDI_DEV];
|
||||
|
||||
long CMIDI_init (long mem_start)
|
||||
long
|
||||
CMIDI_init (long mem_start)
|
||||
{
|
||||
|
||||
int i;
|
||||
int n = num_midi_drivers;
|
||||
/* int n = sizeof (midi_supported) / sizeof( struct generic_midi_info );
|
||||
*/
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if ( midi_supported[i].attach (mem_start) )
|
||||
{
|
||||
printk("MIDI: Successfully attached %s\n",midi_supported[i].name);
|
||||
}
|
||||
|
||||
}
|
||||
return (mem_start);
|
||||
int i;
|
||||
int n = num_midi_drivers;
|
||||
|
||||
/*
|
||||
* int n = sizeof (midi_supported) / sizeof( struct generic_midi_info );
|
||||
*/
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (midi_supported[i].attach (mem_start))
|
||||
{
|
||||
printk ("MIDI: Successfully attached %s\n", midi_supported[i].name);
|
||||
}
|
||||
|
||||
}
|
||||
return (mem_start);
|
||||
}
|
||||
|
||||
|
||||
@ -56,142 +59,143 @@ int
|
||||
CMIDI_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
|
||||
int mode, err, retval;
|
||||
int mode, err, retval;
|
||||
|
||||
dev = dev >> 4;
|
||||
dev = dev >> 4;
|
||||
|
||||
mode = file->mode & O_ACCMODE;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
|
||||
|
||||
if (generic_midi_busy[dev])
|
||||
return (RET_ERROR(EBUSY));
|
||||
if (generic_midi_busy[dev])
|
||||
return (RET_ERROR (EBUSY));
|
||||
|
||||
|
||||
if (dev >= num_generic_midis)
|
||||
{
|
||||
printk(" MIDI device %d not installed.\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (!generic_midi_devs[dev])
|
||||
{
|
||||
printk(" MIDI device %d not initialized\n",dev);
|
||||
if (dev >= num_generic_midis)
|
||||
{
|
||||
printk (" MIDI device %d not installed.\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* If all good and healthy, go ahead and issue call! */
|
||||
if (!generic_midi_devs[dev])
|
||||
{
|
||||
printk (" MIDI device %d not initialized\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
|
||||
retval = generic_midi_devs[dev]->open (dev, mode) ;
|
||||
/* If all good and healthy, go ahead and issue call! */
|
||||
|
||||
/* If everything ok, set device as busy */
|
||||
|
||||
if ( retval >= 0 )
|
||||
generic_midi_busy[dev] = 1;
|
||||
|
||||
return ( retval );
|
||||
retval = generic_midi_devs[dev]->open (dev, mode);
|
||||
|
||||
/* If everything ok, set device as busy */
|
||||
|
||||
if (retval >= 0)
|
||||
generic_midi_busy[dev] = 1;
|
||||
|
||||
return (retval);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
int
|
||||
CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
|
||||
int retval;
|
||||
|
||||
dev = dev >> 4;
|
||||
int retval;
|
||||
|
||||
if (dev >= num_generic_midis)
|
||||
{
|
||||
printk(" MIDI device %d not installed.\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
dev = dev >> 4;
|
||||
|
||||
/* Make double sure of healthiness -- doubt
|
||||
* Need we check this again??
|
||||
*
|
||||
*/
|
||||
|
||||
if (!generic_midi_devs[dev])
|
||||
{
|
||||
printk(" MIDI device %d not initialized\n",dev);
|
||||
if (dev >= num_generic_midis)
|
||||
{
|
||||
printk (" MIDI device %d not installed.\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* If all good and healthy, go ahead and issue call! */
|
||||
/*
|
||||
* Make double sure of healthiness -- doubt Need we check this again??
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
retval = generic_midi_devs[dev]->write (dev, buf);
|
||||
if (!generic_midi_devs[dev])
|
||||
{
|
||||
printk (" MIDI device %d not initialized\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
return ( retval );
|
||||
/* If all good and healthy, go ahead and issue call! */
|
||||
|
||||
}
|
||||
|
||||
retval = generic_midi_devs[dev]->write (dev, buf);
|
||||
|
||||
return (retval);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count)
|
||||
CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
int retval;
|
||||
|
||||
dev = dev >> 4;
|
||||
int retval;
|
||||
|
||||
if (dev >= num_generic_midis)
|
||||
{
|
||||
printk(" MIDI device %d not installed.\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
dev = dev >> 4;
|
||||
|
||||
/* Make double sure of healthiness -- doubt
|
||||
* Need we check this again??
|
||||
*
|
||||
*/
|
||||
|
||||
if (!generic_midi_devs[dev])
|
||||
{
|
||||
printk(" MIDI device %d not initialized\n",dev);
|
||||
if (dev >= num_generic_midis)
|
||||
{
|
||||
printk (" MIDI device %d not installed.\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* If all good and healthy, go ahead and issue call! */
|
||||
/*
|
||||
* Make double sure of healthiness -- doubt Need we check this again??
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
retval = generic_midi_devs[dev]->read(dev,buf);
|
||||
if (!generic_midi_devs[dev])
|
||||
{
|
||||
printk (" MIDI device %d not initialized\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
return (retval);
|
||||
/* If all good and healthy, go ahead and issue call! */
|
||||
|
||||
|
||||
retval = generic_midi_devs[dev]->read (dev, buf);
|
||||
|
||||
return (retval);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
CMIDI_close (int dev, struct fileinfo *file)
|
||||
{
|
||||
|
||||
int retval;
|
||||
dev = dev >> 4;
|
||||
int retval;
|
||||
|
||||
if (dev >= num_generic_midis)
|
||||
{
|
||||
printk(" MIDI device %d not installed.\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
dev = dev >> 4;
|
||||
|
||||
/* Make double sure of healthiness -- doubt
|
||||
* Need we check this again??
|
||||
*
|
||||
*/
|
||||
|
||||
if (!generic_midi_devs[dev])
|
||||
{
|
||||
printk(" MIDI device %d not initialized\n",dev);
|
||||
if (dev >= num_generic_midis)
|
||||
{
|
||||
printk (" MIDI device %d not installed.\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* If all good and healthy, go ahead and issue call! */
|
||||
/*
|
||||
* Make double sure of healthiness -- doubt Need we check this again??
|
||||
*
|
||||
*/
|
||||
|
||||
if (!generic_midi_devs[dev])
|
||||
{
|
||||
printk (" MIDI device %d not initialized\n", dev);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* If all good and healthy, go ahead and issue call! */
|
||||
|
||||
|
||||
generic_midi_devs[dev]->close(dev);
|
||||
generic_midi_devs[dev]->close (dev);
|
||||
|
||||
generic_midi_busy[dev] = 0; /* Free the device */
|
||||
generic_midi_busy[dev] = 0; /* Free the device */
|
||||
|
||||
return (0) ;
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/midibuf.c
|
||||
* sound/midibuf.c
|
||||
*
|
||||
* Device file manager for /dev/midi
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/mpu401.c
|
||||
* sound/mpu401.c
|
||||
*
|
||||
* The low level driver for Roland MPU-401 compatible Midi cards.
|
||||
*
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#define DATAPORT (mpu401_base)/* MPU-401 Data I/O Port on IBM */
|
||||
#define DATAPORT (mpu401_base) /* MPU-401 Data I/O Port on IBM */
|
||||
#define COMDPORT (mpu401_base+1) /* MPU-401 Command Port on IBM */
|
||||
#define STATPORT (mpu401_base+1) /* MPU-401 Status Port on IBM */
|
||||
|
||||
@ -95,21 +95,12 @@ mpuintr (int unit)
|
||||
* polling.
|
||||
*/
|
||||
|
||||
/* XXX WARNING: FreeBSD doesn't seem to have timer_lists like this,
|
||||
* so until I figure out how to do the analogous thing in FreeBSD, I'm
|
||||
* not all that sure WHAT this driver will do! It might work, depending
|
||||
* on the condition taken, but then again it might not! -jkh
|
||||
* XXX WARNING
|
||||
*/
|
||||
static void
|
||||
poll_mpu401 (unsigned long dummy)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef linux
|
||||
static struct timer_list mpu401_timer =
|
||||
{NULL, 0, 0, poll_mpu401};
|
||||
#endif
|
||||
DEFINE_TIMER (mpu401_timer, poll_mpu401);
|
||||
|
||||
if (!(mpu401_opened & OPEN_READ))
|
||||
return; /* No longer required */
|
||||
@ -119,46 +110,11 @@ poll_mpu401 (unsigned long dummy)
|
||||
if (input_avail ())
|
||||
mpu401_input_loop ();
|
||||
|
||||
#ifdef linux
|
||||
mpu401_timer.expires = 1;
|
||||
add_timer (&mpu401_timer); /* Come back later */
|
||||
#endif
|
||||
ACTIVATE_TIMER (mpu401_timer, poll_mpu401, 1); /* Come back later */
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
set_mpu401_irq (int interrupt_level)
|
||||
{
|
||||
int retcode = EINVAL;
|
||||
|
||||
#ifdef linux
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_handler = mpuintr;
|
||||
|
||||
#ifdef SND_SA_INTERRUPT
|
||||
sa.sa_flags = SA_INTERRUPT;
|
||||
#else
|
||||
sa.sa_flags = 0;
|
||||
#endif
|
||||
|
||||
sa.sa_mask = 0;
|
||||
sa.sa_restorer = NULL;
|
||||
|
||||
retcode = irqaction (interrupt_level, &sa);
|
||||
|
||||
if (retcode < 0)
|
||||
{
|
||||
printk ("MPU-401: IRQ%d already in use\n", interrupt_level);
|
||||
}
|
||||
|
||||
#else
|
||||
/* # error Unimplemented for this OS */
|
||||
#endif
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static int
|
||||
mpu401_open (int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
@ -257,7 +213,7 @@ mpu401_buffer_status (int dev)
|
||||
|
||||
static struct midi_operations mpu401_operations =
|
||||
{
|
||||
{"MPU-401", 0},
|
||||
{"MPU-401", 0, 0, SNDCARD_MPU401},
|
||||
mpu401_open,
|
||||
mpu401_close,
|
||||
mpu401_ioctl,
|
||||
@ -297,9 +253,7 @@ attach_mpu401 (long mem_start, struct address_info *hw_config)
|
||||
printk ("snd5: <Roland MPU-401>");
|
||||
|
||||
my_dev = num_midis;
|
||||
#ifdef linux
|
||||
mpu401_dev = num_midis;
|
||||
#endif
|
||||
midi_devs[num_midis++] = &mpu401_operations;
|
||||
return mem_start;
|
||||
}
|
||||
@ -311,7 +265,7 @@ reset_mpu401 (void)
|
||||
int ok, timeout, n;
|
||||
|
||||
/*
|
||||
* Send the RESET command. Try twice if no success at the first time.
|
||||
* Send the RESET command. Try again if no success at the first time.
|
||||
*/
|
||||
|
||||
ok = 0;
|
||||
@ -353,7 +307,7 @@ probe_mpu401 (struct address_info *hw_config)
|
||||
mpu401_base = hw_config->io_base;
|
||||
mpu401_irq = hw_config->irq;
|
||||
|
||||
if (set_mpu401_irq (mpu401_irq) < 0)
|
||||
if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0)
|
||||
return 0;
|
||||
|
||||
ok = reset_mpu401 ();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/opl3.c
|
||||
* sound/opl3.c
|
||||
*
|
||||
* A low level driver for Yamaha YM3812 and OPL-3 -chips
|
||||
*
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
#define MAX_VOICE 18
|
||||
#define OFFS_4OP 11 /* Definitions for the operators OP3 and OP4
|
||||
* begin here */
|
||||
* begin here */
|
||||
|
||||
static int opl3_enabled = 0;
|
||||
static int left_address = 0x388, right_address = 0x388, both_address = 0;
|
||||
@ -59,8 +59,7 @@ struct voice_info
|
||||
|
||||
static struct voice_info voices[MAX_VOICE];
|
||||
|
||||
typedef struct sbi_instrument instr_array[SBFM_MAXINSTR];
|
||||
static instr_array instrmap;
|
||||
static struct sbi_instrument *instrmap;
|
||||
static struct sbi_instrument *active_instrument[MAX_VOICE] =
|
||||
{NULL};
|
||||
|
||||
@ -71,11 +70,11 @@ static int already_initialized = 0;
|
||||
|
||||
static int opl3_ok = 0;
|
||||
static int opl3_busy = 0;
|
||||
static int fm_model = 0; /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2 */
|
||||
static int fm_model = 0; /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2 */
|
||||
|
||||
static int store_instr (int instr_no, struct sbi_instrument *instr);
|
||||
static void freq_to_fnum (int freq, int *block, int *fnum);
|
||||
static void opl3_command (int io_addr, const unsigned char addr, const unsigned char val);
|
||||
static void opl3_command (int io_addr, unsigned int addr, unsigned int val);
|
||||
static int opl3_kill_note (int dev, int voice, int velocity);
|
||||
static unsigned char connection_mask = 0x00;
|
||||
|
||||
@ -112,7 +111,7 @@ enter_4op_mode (void)
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
logical_voices[i] = voices_4op[i];
|
||||
nr_voices = 6;
|
||||
nr_voices = 12;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -140,7 +139,7 @@ opl3_ioctl (int dev,
|
||||
break;
|
||||
|
||||
case SNDCTL_SYNTH_INFO:
|
||||
fm_info.nr_voices = nr_voices;
|
||||
fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices;
|
||||
|
||||
IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info));
|
||||
return 0;
|
||||
@ -184,6 +183,9 @@ opl3_detect (int ioaddr)
|
||||
return 0; /* Do avoid duplicate initializations */
|
||||
}
|
||||
|
||||
if (opl3_enabled)
|
||||
ioaddr = left_address;
|
||||
|
||||
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset timers 1 and 2 */
|
||||
opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* Reset the IRQ of FM
|
||||
* chicp */
|
||||
@ -192,10 +194,10 @@ opl3_detect (int ioaddr)
|
||||
|
||||
if ((stat1 & 0xE0) != 0x00)
|
||||
{
|
||||
return 0; /* Should be 0x00 */
|
||||
return 0; /* Should be 0x00 */
|
||||
}
|
||||
|
||||
opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer 1 to 0xff */
|
||||
opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer 1 to 0xff */
|
||||
opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
|
||||
TIMER2_MASK | TIMER1_START); /* Unmask and start timer 1 */
|
||||
|
||||
@ -270,7 +272,7 @@ store_instr (int instr_no, struct sbi_instrument *instr)
|
||||
{
|
||||
|
||||
if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled))
|
||||
printk ("FM warning: Invalid patch format field (key) 0x%04x\n", instr->key);
|
||||
printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key);
|
||||
memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr));
|
||||
|
||||
return 0;
|
||||
@ -303,9 +305,9 @@ char fm_volume_table[128] =
|
||||
-24, -23, -21, -20, -19, -18, -18, -17, /* 8 - 15 */
|
||||
-16, -15, -15, -14, -13, -13, -12, -12, /* 16 - 23 */
|
||||
-11, -11, -10, -10, -10, -9, -9, -8, /* 24 - 31 */
|
||||
-8, -8, -7, -7, -7, -6, -6, -6,/* 32 - 39 */
|
||||
-5, -5, -5, -5, -4, -4, -4, -4,/* 40 - 47 */
|
||||
-3, -3, -3, -3, -2, -2, -2, -2,/* 48 - 55 */
|
||||
-8, -8, -7, -7, -7, -6, -6, -6, /* 32 - 39 */
|
||||
-5, -5, -5, -5, -4, -4, -4, -4, /* 40 - 47 */
|
||||
-3, -3, -3, -3, -2, -2, -2, -2, /* 48 - 55 */
|
||||
-2, -1, -1, -1, -1, 0, 0, 0, /* 56 - 63 */
|
||||
0, 0, 0, 1, 1, 1, 1, 1, /* 64 - 71 */
|
||||
1, 2, 2, 2, 2, 2, 2, 2, /* 72 - 79 */
|
||||
@ -362,7 +364,7 @@ set_voice_volume (int voice, int volume)
|
||||
vol2 = instr->operators[3];
|
||||
|
||||
if ((instr->operators[10] & 0x01))
|
||||
{ /* Additive synthesis */
|
||||
{ /* Additive synthesis */
|
||||
calc_vol (&vol1, volume);
|
||||
calc_vol (&vol2, volume);
|
||||
}
|
||||
@ -371,8 +373,8 @@ set_voice_volume (int voice, int volume)
|
||||
calc_vol (&vol2, volume);
|
||||
}
|
||||
|
||||
opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* Modulator volume */
|
||||
opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* Carrier volume */
|
||||
opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* Modulator volume */
|
||||
opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* Carrier volume */
|
||||
}
|
||||
else
|
||||
{ /* 4 OP voice */
|
||||
@ -412,7 +414,7 @@ set_voice_volume (int voice, int volume)
|
||||
calc_vol (&vol4, volume);
|
||||
break;
|
||||
|
||||
default:/* Why ?? */ ;
|
||||
default: /* Why ?? */ ;
|
||||
}
|
||||
|
||||
opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
|
||||
@ -616,7 +618,7 @@ freq_to_fnum (int freq, int *block, int *fnum)
|
||||
}
|
||||
|
||||
static void
|
||||
opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
|
||||
opl3_command (int io_addr, unsigned int addr, unsigned int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -625,7 +627,7 @@ opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
|
||||
* register. The OPL-3 survives with just two INBs
|
||||
*/
|
||||
|
||||
OUTB (addr, io_addr); /* Select register */
|
||||
OUTB ((unsigned char) (addr & 0xff), io_addr); /* Select register */
|
||||
|
||||
if (!opl3_enabled)
|
||||
tenmicrosec ();
|
||||
@ -633,7 +635,7 @@ opl3_command (int io_addr, const unsigned char addr, const unsigned char val)
|
||||
for (i = 0; i < 2; i++)
|
||||
INB (io_addr);
|
||||
|
||||
OUTB (val, io_addr + 1); /* Write to register */
|
||||
OUTB ((unsigned char) (val & 0xff), io_addr + 1); /* Write to register */
|
||||
|
||||
if (!opl3_enabled)
|
||||
{
|
||||
@ -849,8 +851,9 @@ opl3_controller (int dev, int voice, int ctrl_num, int value)
|
||||
data = fnum & 0xff; /* Least significant bits of fnumber */
|
||||
opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
|
||||
|
||||
data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); /* KEYON|OCTAVE|MS bits
|
||||
* of f-num */
|
||||
data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
|
||||
/* KEYON|OCTAVE|MS bits * of f-num */
|
||||
|
||||
voices[voice].keyon_byte = data;
|
||||
opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
|
||||
break;
|
||||
@ -892,6 +895,9 @@ opl3_init (long mem_start)
|
||||
{
|
||||
int i;
|
||||
|
||||
PERMANENT_MALLOC(struct sbi_instrument *, instrmap,
|
||||
SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
|
||||
|
||||
synth_devs[num_synths++] = &opl3_operations;
|
||||
fm_model = 0;
|
||||
opl3_ok = 1;
|
||||
@ -902,7 +908,9 @@ opl3_init (long mem_start)
|
||||
nr_voices = 18;
|
||||
fm_info.nr_drums = 0;
|
||||
fm_info.capabilities |= SYNTH_CAP_OPL3;
|
||||
#ifndef SCO
|
||||
strcpy (fm_info.name, "Yamaha OPL-3");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 18; i++)
|
||||
if (physical_voices[i].ioaddr == USE_LEFT)
|
||||
|
@ -3,7 +3,7 @@
|
||||
/*
|
||||
* OS specific settings for FreeBSD
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
* Copyright by UWM - comments to soft-eng@cs.uwm.edu
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -26,7 +26,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This should be used as an example when porting the driver to a new
|
||||
* This chould be used as an example when porting the driver to a new
|
||||
* operating systems.
|
||||
*
|
||||
* What you should do is to rewrite the soundcard.c and os.h (this file).
|
||||
@ -44,7 +44,6 @@
|
||||
|
||||
#include "param.h"
|
||||
#include "systm.h"
|
||||
#include "kernel.h"
|
||||
#include "ioctl.h"
|
||||
#include "tty.h"
|
||||
#include "proc.h"
|
||||
@ -52,6 +51,7 @@
|
||||
#include "conf.h"
|
||||
#include "file.h"
|
||||
#include "uio.h"
|
||||
#include "kernel.h"
|
||||
#include "syslog.h"
|
||||
#include "errno.h"
|
||||
#include "malloc.h"
|
||||
@ -63,10 +63,6 @@
|
||||
*/
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
/* lbolt is required by the FreeBSD version (only???) */
|
||||
extern int __timeout_val;
|
||||
extern int __process_aborting;
|
||||
|
||||
/*
|
||||
* select() is currently implemented in Linux specific way. Don't enable.
|
||||
* I don't remember what the SHORT_BANNERS means so forget it.
|
||||
@ -163,14 +159,25 @@ typedef struct uio snd_rw_buf;
|
||||
* The following macros define an interface to the process management.
|
||||
*/
|
||||
|
||||
struct snd_wait {
|
||||
int mode; int aborting;
|
||||
};
|
||||
|
||||
/*
|
||||
* DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define
|
||||
* a structure which can be passed as a parameter to a sleep(). The second
|
||||
* parameter is name of a flag variable (must be defined as int).
|
||||
*/
|
||||
#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; static int flag = 0
|
||||
#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; \
|
||||
static volatile struct snd_wait flag = {0}
|
||||
/* Like the above but defines an array of wait queues and flags */
|
||||
#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; static int flag = {0}
|
||||
#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; \
|
||||
static volatile struct snd_wait flag = {{0}}
|
||||
|
||||
#define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;}
|
||||
#define SET_ABORT_FLAG(q, f) f.aborting = 1
|
||||
#define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT)
|
||||
#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
|
||||
/*
|
||||
* This driver handles interrupts little bit nonstandard way. The following
|
||||
* macro is used to test if the current process has received a signal which
|
||||
@ -179,34 +186,28 @@ typedef struct uio snd_rw_buf;
|
||||
* 1 or 0 could be returned (1 should be better than 0).
|
||||
* I'm not sure if the following is correct for FreeBSD.
|
||||
*/
|
||||
#define PROCESS_ABORTING (__process_aborting | curproc->p_sig)
|
||||
/*
|
||||
* REQUEST_TIMEOUT is called before sleep. It shoud ensure that the
|
||||
* process is woken up after given number of ticks (1/HZ secs.).
|
||||
* The wqueue gives the wait queue.
|
||||
*/
|
||||
#define REQUEST_TIMEOUT(nticks, wqueue) __timeout_val = nticks;
|
||||
#define PROCESS_ABORTING(q, f) (f.aborting | curproc->p_sig)
|
||||
|
||||
/*
|
||||
* The following macro calls sleep. It should be implemented such that
|
||||
* the process is resumed if it receives a signal. The following is propably
|
||||
* not the way how it should be done on 386bsd.
|
||||
* The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE()
|
||||
* The second parameter is a flag. It must be initialized to 1 before sleep
|
||||
* and to zero after proces continues.
|
||||
* The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE(),
|
||||
* and the second is a workarea parameter. The third is a timeout
|
||||
* in ticks. Zero means no timeout.
|
||||
*/
|
||||
#define INTERRUPTIBLE_SLEEP_ON(on_what, flag) \
|
||||
#define DO_SLEEP(q, f, time_limit) \
|
||||
{ \
|
||||
flag = 1; \
|
||||
flag=tsleep((caddr_t)&(on_what), (PRIBIO-5)|PCATCH, "sndint", __timeout_val); \
|
||||
if(flag == ERESTART) __process_aborting = 1;\
|
||||
else __process_aborting = 0;\
|
||||
__timeout_val = 0; \
|
||||
flag = 0; \
|
||||
int flag, chn; \
|
||||
f.mode = WK_SLEEP; \
|
||||
q = &chn; \
|
||||
flag=tsleep((caddr_t)&(chn), (PRIBIO-5)|PCATCH, "sndint", time_limit); \
|
||||
if(flag == ERESTART) f.aborting = 1;\
|
||||
else f.aborting = 0;\
|
||||
f.mode &= ~WK_SLEEP; \
|
||||
}
|
||||
|
||||
/* An the following wakes up a process */
|
||||
#define WAKE_UP(who) wakeup((caddr_t)&(who))
|
||||
#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wakeup((caddr_t)q);}
|
||||
|
||||
/*
|
||||
* Timing macros. This driver assumes that there is a timer running in the
|
||||
@ -215,6 +216,7 @@ typedef struct uio snd_rw_buf;
|
||||
*/
|
||||
|
||||
#ifndef HZ
|
||||
extern int hz;
|
||||
#define HZ hz
|
||||
#endif
|
||||
|
||||
@ -223,9 +225,9 @@ typedef struct uio snd_rw_buf;
|
||||
* ticks. This can overflow, so the timeout might be real big...
|
||||
*
|
||||
*/
|
||||
#define GET_TIME() get_time()
|
||||
extern long get_time(void);
|
||||
/*#define GET_TIME() (lbolt)*/ /* Returns current time (1/HZ secs since boot) */
|
||||
#define GET_TIME() get_time()
|
||||
/*#define GET_TIME() (lbolt) */ /* Returns current time (1/HZ secs since boot) */
|
||||
|
||||
/*
|
||||
* The following three macros are called before and after atomic
|
||||
@ -248,7 +250,11 @@ extern long get_time(void);
|
||||
*/
|
||||
|
||||
#define INB inb
|
||||
#define OUTB(addr, data) outb(data, addr)
|
||||
/*
|
||||
* The outb(0, 0x80) is just for slowdown. It's bit unsafe since
|
||||
* this address could be used for something usefull.
|
||||
*/
|
||||
#define OUTB(addr, data) {outb(data, addr);outb(0, 0x80);}
|
||||
|
||||
/* memcpy() was not defined og 386bsd. Lets define it here */
|
||||
#define memcpy(d, s, c) bcopy(s, d, c)
|
||||
@ -273,6 +279,32 @@ extern long get_time(void);
|
||||
#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_TEMP, M_WAITOK)
|
||||
|
||||
/*
|
||||
* The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if
|
||||
* required. The name is the variable/name to be used and the proc is
|
||||
* the procedure to be called when the timer expires.
|
||||
*/
|
||||
|
||||
#define DEFINE_TIMER(name, proc)
|
||||
|
||||
/*
|
||||
* The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
|
||||
*/
|
||||
|
||||
#define ACTIVATE_TIMER(name, proc, time) \
|
||||
timeout((timeout_func_t)proc, 0, time);
|
||||
/*
|
||||
* The rest of this file is not complete yet. The functions using these
|
||||
* macros will not work
|
||||
|
@ -132,6 +132,7 @@
|
||||
#define PAS_PLUS 1
|
||||
#define PAS_CDPC 2
|
||||
#define PAS_16 3
|
||||
#define PAS_16D 4
|
||||
|
||||
#ifdef DEFINE_TRANSLATIONS
|
||||
char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */
|
||||
@ -141,11 +142,11 @@
|
||||
char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */
|
||||
{ 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x05, 0x06, 0x07 };
|
||||
char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */
|
||||
{ 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x00, 0x28, 0x30, 0x38 };
|
||||
{ 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x00, 0x28, 0x30, 0x38, 0, 0 };
|
||||
char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */
|
||||
{ 0x00, 0x40, 0x80, 0xC0 };
|
||||
{ 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
|
||||
char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */
|
||||
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 2, 3 };
|
||||
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 };
|
||||
#else
|
||||
extern char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */
|
||||
extern char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */
|
||||
|
@ -1,7 +1,7 @@
|
||||
#define _PAS2_CARD_C_
|
||||
#define SND_SA_INTERRUPT
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/pas2_card.c
|
||||
* sound/pas2_card.c
|
||||
*
|
||||
* Detection routine for the Pro Audio Spectrum cards.
|
||||
*
|
||||
@ -47,7 +47,7 @@ static int pas_irq = 0;
|
||||
|
||||
static char pas_model;
|
||||
static char *pas_model_names[] =
|
||||
{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16"};
|
||||
{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
|
||||
|
||||
/* pas_read() and pas_write() are equivalents of INB() and OUTB() */
|
||||
/* These routines perform the I/O address translation required */
|
||||
@ -79,7 +79,7 @@ pasintr (int unused)
|
||||
int status;
|
||||
|
||||
status = pas_read (INTERRUPT_STATUS);
|
||||
pas_write (status, INTERRUPT_STATUS); /* Clear interrupt */
|
||||
pas_write (status, INTERRUPT_STATUS); /* Clear interrupt */
|
||||
|
||||
if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
|
||||
{
|
||||
@ -100,39 +100,6 @@ pasintr (int unused)
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
set_pas_irq (int interrupt_level)
|
||||
{
|
||||
#ifdef linux
|
||||
int retcode;
|
||||
struct sigaction sa;
|
||||
|
||||
pas_write (0xff, INTERRUPT_STATUS); /* Reset pending interrupts */
|
||||
|
||||
sa.sa_handler = pasintr;
|
||||
|
||||
#ifdef SND_SA_INTERRUPT
|
||||
sa.sa_flags = SA_INTERRUPT;
|
||||
#else
|
||||
sa.sa_flags = 0;
|
||||
#endif
|
||||
|
||||
sa.sa_mask = 0;
|
||||
sa.sa_restorer = NULL;
|
||||
|
||||
retcode = irqaction (interrupt_level, &sa);
|
||||
|
||||
if (retcode < 0)
|
||||
{
|
||||
printk ("ProAudioSpectrum: IRQ%d already in use\n", interrupt_level);
|
||||
}
|
||||
return retcode;
|
||||
#else
|
||||
/* # error This routine does not work with this OS */
|
||||
return EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
pas_set_intr (int mask)
|
||||
{
|
||||
@ -143,7 +110,7 @@ pas_set_intr (int mask)
|
||||
|
||||
if (!pas_intr_mask)
|
||||
{
|
||||
if ((err = set_pas_irq (pas_irq)) < 0)
|
||||
if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0)
|
||||
return err;
|
||||
}
|
||||
pas_intr_mask |= mask;
|
||||
@ -163,7 +130,7 @@ pas_remove_intr (int mask)
|
||||
|
||||
if (!pas_intr_mask)
|
||||
{
|
||||
RELEASE_IRQ (pas_irq);
|
||||
snd_release_irq (pas_irq);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -230,20 +197,28 @@ config_pas_hw (struct address_info *hw_config)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This fixes the timing problems of the PAS due to the Symphony chipset
|
||||
* as per Media Vision. Only define this if your PAS doesn't work correctly.
|
||||
*/
|
||||
#ifdef SYMPHONY_PAS
|
||||
OUTB (0x05, 0xa8);
|
||||
OUTB (0x60, 0xa9);
|
||||
#endif
|
||||
|
||||
#ifdef BROKEN_BUS_CLOCK
|
||||
pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
|
||||
#else
|
||||
/* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1); */
|
||||
pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
|
||||
#endif
|
||||
/* pas_write(S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2); Don't do this */
|
||||
pas_write (0x18, SYSTEM_CONFIGURATION_3); /* ??? */
|
||||
|
||||
pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* Sets mute off and
|
||||
* selects filter rate
|
||||
* of 17.897 kHz */
|
||||
|
||||
if (pas_model == PAS_16)
|
||||
if (pas_model == PAS_16 || pas_model == PAS_16D)
|
||||
pas_write (8, PRESCALE_DIVIDER);
|
||||
else
|
||||
pas_write (0, PRESCALE_DIVIDER);
|
||||
@ -253,13 +228,35 @@ config_pas_hw (struct address_info *hw_config)
|
||||
|
||||
#if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
|
||||
|
||||
/* Turn on Sound Blaster compatibility */
|
||||
/* bit 1 = SB emulation */
|
||||
/* bit 0 = MPU401 emulation (CDPC only :-( ) */
|
||||
pas_write (0x02, COMPATIBILITY_ENABLE);
|
||||
{
|
||||
struct address_info *sb_config;
|
||||
|
||||
/* "Emulation address" */
|
||||
pas_write ((SBC_BASE >> 4) & 0x0f, EMULATION_ADDRESS);
|
||||
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)
|
||||
@ -305,7 +302,7 @@ detect_pas_hw (struct address_info *hw_config)
|
||||
if (board_id != foo) /* Not a PAS2 */
|
||||
return 0;
|
||||
|
||||
if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]));
|
||||
pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f];
|
||||
|
||||
return pas_model;
|
||||
}
|
||||
@ -330,11 +327,11 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
|
||||
mem_start = pas_pcm_init (mem_start, hw_config);
|
||||
#endif
|
||||
|
||||
# if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
|
||||
#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
|
||||
|
||||
sb_dsp_disable_midi (); /* The SB emulation don't support
|
||||
* midi */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_YM3812
|
||||
enable_opl3_mode (0x388, 0x38a, 0);
|
||||
@ -350,7 +347,6 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
|
||||
}
|
||||
}
|
||||
|
||||
printk ("\n");
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/pas2_midi.c
|
||||
* sound/pas2_midi.c
|
||||
*
|
||||
* The low level driver for the PAS Midi Interface.
|
||||
*
|
||||
@ -79,7 +79,7 @@ pas_midi_open (int dev, int mode,
|
||||
|
||||
if (mode == OPEN_READ || mode == OPEN_READWRITE)
|
||||
{
|
||||
ctrl |= M_C_ENA_INPUT_IRQ;/* Enable input */
|
||||
ctrl |= M_C_ENA_INPUT_IRQ; /* Enable input */
|
||||
input_opened = 1;
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ dump_to_midi (unsigned char midi_byte)
|
||||
|
||||
fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
|
||||
|
||||
if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* Fifo full */
|
||||
if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* Fifo full */
|
||||
{
|
||||
return 0; /* Upper layer will call again */
|
||||
}
|
||||
@ -212,7 +212,7 @@ pas_buffer_status (int dev)
|
||||
|
||||
static struct midi_operations pas_midi_operations =
|
||||
{
|
||||
{"Pro Audio Spectrum", 0},
|
||||
{"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
|
||||
pas_midi_open,
|
||||
pas_midi_close,
|
||||
pas_midi_ioctl,
|
||||
@ -283,11 +283,11 @@ pas_midi_interrupt (void)
|
||||
|
||||
if (stat & M_S_OUTPUT_OVERRUN)
|
||||
{
|
||||
printk ("MIDI output overrun %02x,%02x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
|
||||
printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
|
||||
ofifo_bytes = 100;
|
||||
}
|
||||
|
||||
pas_write (stat, MIDI_STATUS);/* Acknowledge interrupts */
|
||||
pas_write (stat, MIDI_STATUS); /* Acknowledge interrupts */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
#define _PAS2_MIXER_C_
|
||||
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/pas2_mixer.c
|
||||
* sound/pas2_mixer.c
|
||||
*
|
||||
* Mixer routines for the Pro Audio Spectrum cards.
|
||||
*
|
||||
@ -39,14 +39,14 @@
|
||||
|
||||
extern int translat_code;
|
||||
|
||||
static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */
|
||||
static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */
|
||||
static int mode_control = 0;
|
||||
|
||||
#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD | SOUND_MASK_ALTPCM)
|
||||
|
||||
#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD /*|SOUND_MASK_ALTPCM*/ | SOUND_MASK_IMIX | \
|
||||
SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
|
||||
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
|
||||
SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
|
||||
|
||||
@ -87,7 +87,7 @@ mixer_output (int right_vol, int left_vol, int div, int bits,
|
||||
}
|
||||
|
||||
if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
|
||||
{ /* Bass and trebble are mono devices */
|
||||
{ /* Bass and trebble are mono devices */
|
||||
pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
|
||||
pas_write (left, PARALLEL_MIXER);
|
||||
right_vol = left_vol;
|
||||
@ -331,7 +331,7 @@ mixer_get_levels (struct sb_mixer_levels *user_l)
|
||||
struct sb_mixer_levels l;
|
||||
|
||||
l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100; /* Master */
|
||||
l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100; /* Master */
|
||||
l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100; /* Master */
|
||||
|
||||
l.line.r = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_RIGHT) * 15) + 50) / 100; /* Line */
|
||||
l.line.l = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_LEFT) * 15) + 50) / 100;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#define _PAS2_PCM_C_
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/pas2_pcm.c
|
||||
* sound/pas2_pcm.c
|
||||
*
|
||||
* The low level driver for the Pro Audio Spectrum ADC/DAC.
|
||||
*
|
||||
@ -100,7 +100,7 @@ pcm_set_channels (int arg)
|
||||
pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
|
||||
|
||||
pcm_channels = arg;
|
||||
pcm_set_speed (pcm_speed);/* The speed must be reinitialized */
|
||||
pcm_set_speed (pcm_speed); /* The speed must be reinitialized */
|
||||
}
|
||||
|
||||
return pcm_channels;
|
||||
@ -148,6 +148,8 @@ pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
break;
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
if (local)
|
||||
return pcm_set_channels (arg);
|
||||
return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
@ -200,12 +202,6 @@ pas_pcm_open (int dev, int mode)
|
||||
|
||||
TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
|
||||
|
||||
if (mode != OPEN_READ && mode != OPEN_WRITE)
|
||||
{
|
||||
printk ("PAS2: Attempt to open PCM device for simultaneous read and write");
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
|
||||
return err;
|
||||
|
||||
@ -217,10 +213,6 @@ pas_pcm_open (int dev, int mode)
|
||||
|
||||
pcm_count = 0;
|
||||
|
||||
pcm_set_bits (8);
|
||||
pcm_set_channels (1);
|
||||
pcm_set_speed (DSP_DEFAULT_SPEED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -242,7 +234,8 @@ pas_pcm_close (int dev)
|
||||
}
|
||||
|
||||
static void
|
||||
pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
|
||||
pas_pcm_output_block (int dev, unsigned long buf, int count,
|
||||
int intrflag, int restart_dma)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
|
||||
@ -251,7 +244,6 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
|
||||
cnt = count;
|
||||
if (sound_dsp_dmachan[dev] > 3)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
if (sound_dma_automode[dev] &&
|
||||
intrflag &&
|
||||
@ -263,11 +255,11 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
|
||||
pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
|
||||
PCM_CONTROL);
|
||||
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
|
||||
if (restart_dma)
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
|
||||
|
||||
if (sound_dsp_dmachan[dev] > 3)
|
||||
count >>= 1;
|
||||
count--;
|
||||
|
||||
if (count != pcm_count)
|
||||
{
|
||||
@ -288,7 +280,8 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag)
|
||||
}
|
||||
|
||||
static void
|
||||
pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
|
||||
pas_pcm_start_input (int dev, unsigned long buf, int count,
|
||||
int intrflag, int restart_dma)
|
||||
{
|
||||
unsigned long flags;
|
||||
int cnt;
|
||||
@ -298,7 +291,6 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
|
||||
cnt = count;
|
||||
if (sound_dsp_dmachan[dev] > 3)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
if (sound_dma_automode[my_devnum] &&
|
||||
intrflag &&
|
||||
@ -307,13 +299,12 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
|
||||
if (restart_dma)
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
|
||||
|
||||
if (sound_dsp_dmachan[dev] > 3)
|
||||
count >>= 1;
|
||||
|
||||
count--;
|
||||
|
||||
if (count != pcm_count)
|
||||
{
|
||||
pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
|
||||
@ -374,6 +365,7 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
|
||||
sound_dsp_dmachan[my_devnum] = hw_config->dma;
|
||||
#ifndef PAS_NO_AUTODMA
|
||||
if (hw_config->dma > 3)
|
||||
{
|
||||
sound_buffcounts[my_devnum] = 1;
|
||||
@ -386,6 +378,11 @@ pas_pcm_init (long mem_start, struct address_info *hw_config)
|
||||
sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
|
||||
sound_dma_automode[my_devnum] = 1;
|
||||
}
|
||||
#else
|
||||
sound_buffcounts[my_devnum] = 2;
|
||||
sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
|
||||
sound_dma_automode[my_devnum] = 0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
printk ("PAS2: Too many PCM devices available\n");
|
||||
@ -413,7 +410,7 @@ pas_pcm_interrupt (unsigned char status, int cause)
|
||||
{
|
||||
|
||||
case PCM_DAC:
|
||||
DMAbuf_outputintr (my_devnum);
|
||||
DMAbuf_outputintr (my_devnum, 1);
|
||||
break;
|
||||
|
||||
case PCM_ADC:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/patmgr.c
|
||||
* sound/patmgr.c
|
||||
*
|
||||
* The patch maneger interface for the /dev/sequencer
|
||||
*
|
||||
@ -58,6 +58,8 @@ pmgr_open (int dev)
|
||||
return RET_ERROR (EBUSY);
|
||||
pmgr_opened[dev] = 1;
|
||||
|
||||
RESET_WAIT_QUEUE (server_procs[dev], server_wait_flag[dev]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -71,8 +73,8 @@ pmgr_release (int dev)
|
||||
mbox[dev]->key = PM_ERROR;
|
||||
mbox[dev]->parm1 = RET_ERROR (EIO);
|
||||
|
||||
if (appl_wait_flag)
|
||||
WAKE_UP (appl_proc);
|
||||
if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
|
||||
WAKE_UP (appl_proc, appl_wait_flag);
|
||||
}
|
||||
|
||||
pmgr_opened[dev] = 0;
|
||||
@ -90,13 +92,14 @@ pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
|
||||
while (!ok && !PROCESS_ABORTING)
|
||||
while (!ok && !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
while (!(mbox[dev] && msg_direction[dev] == A_TO_S) && !PROCESS_ABORTING)
|
||||
while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
|
||||
!PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
|
||||
{
|
||||
INTERRUPTIBLE_SLEEP_ON (server_procs[dev], server_wait_flag[dev]);
|
||||
DO_SLEEP (server_procs[dev], server_wait_flag[dev], 0);
|
||||
}
|
||||
|
||||
if (mbox[dev] && msg_direction[dev] == A_TO_S)
|
||||
@ -158,9 +161,9 @@ pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
COPY_FROM_USER (&((char *) mbox[dev])[4], buf, 4, count - 4);
|
||||
msg_direction[dev] = S_TO_A;
|
||||
|
||||
if (appl_wait_flag)
|
||||
if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
|
||||
{
|
||||
WAKE_UP (appl_proc);
|
||||
WAKE_UP (appl_proc, appl_wait_flag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,12 +188,12 @@ pmgr_access (int dev, struct patmgr_info *rec)
|
||||
mbox[dev] = rec;
|
||||
msg_direction[dev] = A_TO_S;
|
||||
|
||||
if (server_wait_flag[dev])
|
||||
if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
|
||||
{
|
||||
WAKE_UP (server_procs[dev]);
|
||||
WAKE_UP (server_procs[dev], server_wait_flag[dev]);
|
||||
}
|
||||
|
||||
INTERRUPTIBLE_SLEEP_ON (appl_proc, appl_wait_flag);
|
||||
DO_SLEEP (appl_proc, appl_wait_flag, 0);
|
||||
|
||||
if (msg_direction[dev] != S_TO_A)
|
||||
{
|
||||
@ -239,12 +242,12 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2,
|
||||
mbox[dev]->parm3 = p3;
|
||||
msg_direction[dev] = A_TO_S;
|
||||
|
||||
if (server_wait_flag[dev])
|
||||
if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
|
||||
{
|
||||
WAKE_UP (server_procs[dev]);
|
||||
WAKE_UP (server_procs[dev], server_wait_flag[dev]);
|
||||
}
|
||||
|
||||
INTERRUPTIBLE_SLEEP_ON (appl_proc, appl_wait_flag);
|
||||
DO_SLEEP (appl_proc, appl_wait_flag, 0);
|
||||
if (mbox[dev])
|
||||
KERNEL_FREE (mbox[dev]);
|
||||
mbox[dev] = NULL;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright by UWM -- comments to soft-eng@cs.uwm.edu
|
||||
* Copyright by UWM - comments to soft-eng@cs.uwm.edu
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -37,140 +37,148 @@
|
||||
/** Structure for handling operations **/
|
||||
|
||||
|
||||
static struct generic_midi_operations pro_midi_operations = {
|
||||
static struct generic_midi_operations pro_midi_operations =
|
||||
{
|
||||
|
||||
{"Pro_Audio_Spectrum 16 MV101", 0},
|
||||
pro_midi_open,
|
||||
pro_midi_close,
|
||||
pro_midi_write,
|
||||
pro_midi_read
|
||||
{"Pro_Audio_Spectrum 16 MV101", 0},
|
||||
pro_midi_open,
|
||||
pro_midi_close,
|
||||
pro_midi_write,
|
||||
pro_midi_read
|
||||
};
|
||||
|
||||
/*
|
||||
* Note! Note! Note!
|
||||
* Follow the same model for any other attach function you
|
||||
* Note! Note! Note! Follow the same model for any other attach function you
|
||||
* may write
|
||||
*/
|
||||
|
||||
long pro_midi_attach( long mem_start)
|
||||
long
|
||||
pro_midi_attach (long mem_start)
|
||||
{
|
||||
pro_midi_dev = num_generic_midis;
|
||||
generic_midi_devs[num_generic_midis++] = &pro_midi_operations;
|
||||
return mem_start;
|
||||
}
|
||||
}
|
||||
|
||||
int pro_midi_open(int dev, int mode)
|
||||
int
|
||||
pro_midi_open (int dev, int mode)
|
||||
{
|
||||
|
||||
int intr_mask, s;
|
||||
int intr_mask, s;
|
||||
|
||||
|
||||
s = splhigh();
|
||||
s = splhigh ();
|
||||
|
||||
|
||||
/* Reset the input and output FIFO pointers */
|
||||
/* Reset the input and output FIFO pointers */
|
||||
|
||||
|
||||
outb(MIDI_CONTROL,M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
|
||||
outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
|
||||
|
||||
/* Get the interrupt status */
|
||||
/* Get the interrupt status */
|
||||
|
||||
intr_mask = inb(INTERRUPT_MASK);
|
||||
intr_mask = inb (INTERRUPT_MASK);
|
||||
|
||||
|
||||
/* Enable MIDI IRQ */
|
||||
/* Enable MIDI IRQ */
|
||||
|
||||
intr_mask |= I_M_MIDI_IRQ_ENABLE;
|
||||
outb(INTERRUPT_MASK, intr_mask);
|
||||
intr_mask |= I_M_MIDI_IRQ_ENABLE;
|
||||
outb (INTERRUPT_MASK, intr_mask);
|
||||
|
||||
|
||||
/* Enable READ/WRITE on MIDI port. This part is quite unsure though */
|
||||
|
||||
outb(MIDI_CONTROL,M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ);
|
||||
outb (MIDI_CONTROL, M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ);
|
||||
|
||||
/* Acknowledge pending interrupts */
|
||||
|
||||
outb(MIDI_STATUS,0xff);
|
||||
outb (MIDI_STATUS, 0xff);
|
||||
|
||||
|
||||
splx(s);
|
||||
splx (s);
|
||||
|
||||
return(ESUCCESS);
|
||||
return (ESUCCESS);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void pro_midi_close(int dev)
|
||||
void
|
||||
pro_midi_close (int dev)
|
||||
{
|
||||
|
||||
int intr_mask;
|
||||
int intr_mask;
|
||||
|
||||
/* Clean up */
|
||||
/* Clean up */
|
||||
|
||||
outb(MIDI_CONTROL,M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
|
||||
intr_mask = inb(INTERRUPT_MASK);
|
||||
intr_mask &= ~I_M_MIDI_IRQ_ENABLE;
|
||||
outb(INTERRUPT_MASK,intr_mask);
|
||||
outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
|
||||
intr_mask = inb (INTERRUPT_MASK);
|
||||
intr_mask &= ~I_M_MIDI_IRQ_ENABLE;
|
||||
outb (INTERRUPT_MASK, intr_mask);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
int pro_midi_write(int dev, struct uio *uio)
|
||||
int
|
||||
pro_midi_write (int dev, struct uio *uio)
|
||||
{
|
||||
|
||||
int s;
|
||||
unsigned char data;
|
||||
int s;
|
||||
unsigned char data;
|
||||
|
||||
/* printf("midi: Going to do write routine..\n"); */
|
||||
while(uio->uio_resid) {
|
||||
/* printf("midi: Going to do write routine..\n"); */
|
||||
while (uio->uio_resid)
|
||||
{
|
||||
|
||||
if ( uiomove(&data,1,uio) ) return(ENOTTY);
|
||||
if (uiomove (&data, 1, uio))
|
||||
return (ENOTTY);
|
||||
|
||||
s = splhigh();
|
||||
s = splhigh ();
|
||||
|
||||
DELAY(30);
|
||||
outb(MIDI_DATA,data);
|
||||
DELAY(70); /* Ze best pause.. find a better one if
|
||||
* you can :)
|
||||
*/
|
||||
splx(s);
|
||||
}
|
||||
DELAY (30);
|
||||
outb (MIDI_DATA, data);
|
||||
DELAY (70); /* Ze best pause.. find a better one if you
|
||||
* can :) */
|
||||
splx (s);
|
||||
}
|
||||
|
||||
return(ESUCCESS);
|
||||
return (ESUCCESS);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int pro_midi_read(int dev, struct uio *uio)
|
||||
int
|
||||
pro_midi_read (int dev, struct uio *uio)
|
||||
{
|
||||
|
||||
int s;
|
||||
unsigned char data;
|
||||
int s;
|
||||
unsigned char data;
|
||||
|
||||
s = splhigh();
|
||||
s = splhigh ();
|
||||
|
||||
/* For each uio_iov[] entry .... */
|
||||
/* For each uio_iov[] entry .... */
|
||||
|
||||
while (uio->uio_resid) {
|
||||
while (uio->uio_resid)
|
||||
{
|
||||
|
||||
if((( inb(MIDI_STATUS) & M_S_INPUT_AVAIL) == 0 ) &&
|
||||
((inb(MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0 ) )
|
||||
if (((inb (MIDI_STATUS) & M_S_INPUT_AVAIL) == 0) &&
|
||||
((inb (MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0))
|
||||
|
||||
data = 0xfe;
|
||||
else
|
||||
data = inb(MIDI_DATA);
|
||||
data = 0xfe;
|
||||
else
|
||||
data = inb (MIDI_DATA);
|
||||
|
||||
if ( uiomove(&data, 1 , uio)) {
|
||||
if (uiomove (&data, 1, uio))
|
||||
{
|
||||
|
||||
printf("midi: Bad copyout()!\n");
|
||||
return(ENOTTY);
|
||||
printf ("midi: Bad copyout()!\n");
|
||||
return (ENOTTY);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
splx(s);
|
||||
return(ESUCCESS);
|
||||
}
|
||||
splx (s);
|
||||
return (ESUCCESS);
|
||||
|
||||
}
|
||||
|
||||
|
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
|
||||
|
641
sys/i386/isa/sound/sb16_dsp.c
Normal file
641
sys/i386/isa/sound/sb16_dsp.c
Normal file
@ -0,0 +1,641 @@
|
||||
/*
|
||||
* 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",
|
||||
sb16_dsp_open,
|
||||
sb16_dsp_close,
|
||||
sb16_dsp_output_block,
|
||||
sb16_dsp_start_input,
|
||||
sb16_dsp_ioctl,
|
||||
sb16_dsp_prepare_for_input,
|
||||
sb16_dsp_prepare_for_output,
|
||||
sb16_dsp_reset,
|
||||
sb16_dsp_halt,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int
|
||||
sb_dsp_command01 (unsigned char val)
|
||||
{
|
||||
int i = 1 << 16;
|
||||
|
||||
while (--i & (!INB (DSP_STATUS) & 0x80));
|
||||
if (!i)
|
||||
printk ("SB16 sb_dsp_command01 Timeout\n");
|
||||
return sb_dsp_command (val);
|
||||
}
|
||||
|
||||
static int
|
||||
wait_data_avail (int t)
|
||||
{
|
||||
int loopc = 5000000;
|
||||
|
||||
t += GET_TIME ();
|
||||
do
|
||||
{
|
||||
if (INB (DSP_DATA_AVAIL) & 0x80)
|
||||
return 1;
|
||||
}
|
||||
while (--loopc && GET_TIME () < t);
|
||||
printk ("!data_avail l=%d\n", loopc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
read_dsp (int t)
|
||||
{
|
||||
if (!wait_data_avail (t))
|
||||
return -1;
|
||||
else
|
||||
return INB (DSP_READ);
|
||||
}
|
||||
|
||||
static int
|
||||
dsp_ini2 (void)
|
||||
{
|
||||
#if 0
|
||||
/* sb_setmixer(0x83, sb_getmixer(0x83) | 0x03); */
|
||||
sb_dsp_command (0xe2);
|
||||
sb_dsp_command (0x76); /* E0 ??? */
|
||||
sb_dsp_command (0xe2);
|
||||
sb_dsp_command (0x30); /* A0 ??? */
|
||||
sb_dsp_command (0xe4);
|
||||
sb_dsp_command (0xaa);
|
||||
sb_dsp_command (0xe8);
|
||||
if (read_dsp (100) != 0xaa)
|
||||
printk ("Error dsp_ini2\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
static char *dsp_getmessage(unsigned char command,int maxn)
|
||||
{
|
||||
static char buff[100];
|
||||
int n=0;
|
||||
|
||||
sb_dsp_command(command);
|
||||
while(n<maxn && wait_data_avail(2)) {
|
||||
buff[++n]=INB(DSP_READ);
|
||||
if(!buff[n])
|
||||
break;
|
||||
}
|
||||
buff[0]=n;
|
||||
return buff;
|
||||
}
|
||||
|
||||
static void dsp_showmessage(unsigned char command,int len)
|
||||
{
|
||||
int n;
|
||||
unsigned char *c;
|
||||
c=dsp_getmessage(command,len);
|
||||
printk("DSP C=%x l=%d,lr=%d b=",command,len,c[0]);
|
||||
for(n=1;n<=c[0];n++)
|
||||
if(c[n]>=' ' & c[n]<='z')
|
||||
printk("%c",c[n]);
|
||||
else
|
||||
printk("|%x|",c[n]);
|
||||
printk("\n");
|
||||
}
|
||||
*/
|
||||
static int
|
||||
dsp_set_speed (int mode)
|
||||
{
|
||||
DEB (printk ("dsp_set_speed(%d)\n", mode));
|
||||
if (mode)
|
||||
{
|
||||
if (mode < 5000)
|
||||
mode = 5000;
|
||||
if (mode > 44100)
|
||||
mode = 44100;
|
||||
dsp_current_speed = mode;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int
|
||||
dsp_set_stereo (int mode)
|
||||
{
|
||||
DEB (printk ("dsp_set_stereo(%d)\n", mode));
|
||||
|
||||
dsp_stereo = mode;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int
|
||||
dsp_set_bits (int arg)
|
||||
{
|
||||
DEB (printk ("dsp_set_bits(%d)\n", arg));
|
||||
|
||||
if (arg)
|
||||
switch (arg)
|
||||
{
|
||||
case 8:
|
||||
dsp_16bit = 0;
|
||||
break;
|
||||
case 16:
|
||||
dsp_16bit = 1;
|
||||
break;
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
return dsp_16bit ? 16 : 8;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SOUND_PCM_WRITE_RATE:
|
||||
if (local)
|
||||
return dsp_set_speed (arg);
|
||||
return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_RATE:
|
||||
if (local)
|
||||
return dsp_current_speed;
|
||||
return IOCTL_OUT (arg, dsp_current_speed);
|
||||
|
||||
case SNDCTL_DSP_STEREO:
|
||||
if (local)
|
||||
return dsp_set_stereo (arg);
|
||||
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
if (local)
|
||||
return dsp_set_stereo (arg - 1) + 1;
|
||||
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
|
||||
|
||||
case SOUND_PCM_READ_CHANNELS:
|
||||
if (local)
|
||||
return dsp_stereo + 1;
|
||||
return IOCTL_OUT (arg, dsp_stereo + 1);
|
||||
|
||||
case SNDCTL_DSP_SAMPLESIZE:
|
||||
if (local)
|
||||
return dsp_set_bits (arg);
|
||||
return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_BITS:
|
||||
if (local)
|
||||
return dsp_16bit ? 16 : 8;
|
||||
return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
|
||||
|
||||
case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
|
||||
if (IOCTL_IN (arg) > 1)
|
||||
return IOCTL_OUT (arg, RET_ERROR (EINVAL));
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
sb16_dsp_open (int dev, int mode)
|
||||
{
|
||||
int retval;
|
||||
|
||||
DEB (printk ("sb16_dsp_open()\n"));
|
||||
if (!sb16_dsp_ok)
|
||||
{
|
||||
printk ("SB16 Error: SoundBlaster board not installed\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
if (intr_active)
|
||||
return RET_ERROR (EBUSY);
|
||||
|
||||
retval = sb_get_irq ();
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
if (ALLOC_DMA_CHN (dma8))
|
||||
{
|
||||
printk ("SB16: Unable to grab DMA%d\n", dma8);
|
||||
sb_free_irq ();
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
if (dma16 != dma8)
|
||||
if (ALLOC_DMA_CHN (dma16))
|
||||
{
|
||||
printk ("SB16: Unable to grab DMA%d\n", dma16);
|
||||
sb_free_irq ();
|
||||
RELEASE_DMA_CHN (dma8);
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
dsp_ini2 ();
|
||||
|
||||
irq_mode = IMODE_NONE;
|
||||
dsp_busy = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_close (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DEB (printk ("sb16_dsp_close()\n"));
|
||||
sb_dsp_command01 (0xd9);
|
||||
sb_dsp_command01 (0xd5);
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
RELEASE_DMA_CHN (dma8);
|
||||
|
||||
if (dma16 != dma8)
|
||||
RELEASE_DMA_CHN (dma16);
|
||||
sb_free_irq ();
|
||||
dsp_cleanup ();
|
||||
dsp_busy = 0;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
|
||||
cnt = count;
|
||||
if (dsp_16bit)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
#ifdef DEB_DMARES
|
||||
printk ("output_block: %x %d %d\n", buf, count, intrflag);
|
||||
if (intrflag)
|
||||
{
|
||||
int pos, chan = sound_dsp_dmachan[dev];
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
clear_dma_ff (chan);
|
||||
disable_dma (chan);
|
||||
pos = get_dma_residue (chan);
|
||||
enable_dma (chan);
|
||||
RESTORE_INTR (flags);
|
||||
printk ("dmapos=%d %x\n", pos, pos);
|
||||
}
|
||||
#endif
|
||||
if (sound_dma_automode[dev] &&
|
||||
intrflag &&
|
||||
cnt == dsp_count)
|
||||
{
|
||||
irq_mode = IMODE_OUTPUT;
|
||||
intr_active = 1;
|
||||
return; /* Auto mode on. No need to react */
|
||||
}
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (dma_restart)
|
||||
{
|
||||
sb16_dsp_halt (dev);
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
|
||||
}
|
||||
sb_dsp_command (0x41);
|
||||
sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
|
||||
sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
|
||||
sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6));
|
||||
sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
|
||||
(dsp_16bit ? 0x10 : 0)));
|
||||
sb_dsp_command01 ((unsigned char) (cnt & 0xff));
|
||||
sb_dsp_command ((unsigned char) (cnt >> 8));
|
||||
/* sb_dsp_command (0);
|
||||
sb_dsp_command (0); */
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
dsp_count = cnt;
|
||||
irq_mode = IMODE_OUTPUT;
|
||||
intr_active = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
|
||||
cnt = count;
|
||||
if (dsp_16bit)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
#ifdef DEB_DMARES
|
||||
printk ("start_input: %x %d %d\n", buf, count, intrflag);
|
||||
if (intrflag)
|
||||
{
|
||||
int pos, chan = sound_dsp_dmachan[dev];
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
clear_dma_ff (chan);
|
||||
disable_dma (chan);
|
||||
pos = get_dma_residue (chan);
|
||||
enable_dma (chan);
|
||||
RESTORE_INTR (flags);
|
||||
printk ("dmapos=%d %x\n", pos, pos);
|
||||
}
|
||||
#endif
|
||||
if (sound_dma_automode[dev] &&
|
||||
intrflag &&
|
||||
cnt == dsp_count)
|
||||
{
|
||||
irq_mode = IMODE_INPUT;
|
||||
intr_active = 1;
|
||||
return; /* Auto mode on. No need to react */
|
||||
}
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (dma_restart)
|
||||
{
|
||||
sb16_dsp_halt (dev);
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
|
||||
}
|
||||
|
||||
sb_dsp_command (0x42);
|
||||
sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
|
||||
sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
|
||||
sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce));
|
||||
sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
|
||||
(dsp_16bit ? 0x10 : 0)));
|
||||
sb_dsp_command01 ((unsigned char) (cnt & 0xff));
|
||||
sb_dsp_command ((unsigned char) (cnt >> 8));
|
||||
|
||||
/* sb_dsp_command (0);
|
||||
sb_dsp_command (0); */
|
||||
RESTORE_INTR (flags);
|
||||
dsp_count = cnt;
|
||||
irq_mode = IMODE_INPUT;
|
||||
intr_active = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
|
||||
{
|
||||
sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
|
||||
dsp_count = 0;
|
||||
dsp_cleanup ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
|
||||
{
|
||||
sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
|
||||
dsp_count = 0;
|
||||
dsp_cleanup ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dsp_cleanup (void)
|
||||
{
|
||||
irq_mode = IMODE_NONE;
|
||||
intr_active = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_reset (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
sb_reset_dsp ();
|
||||
dsp_cleanup ();
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
sb16_dsp_halt (int dev)
|
||||
{
|
||||
if (dsp_16bit)
|
||||
{
|
||||
sb_dsp_command01 (0xd9);
|
||||
sb_dsp_command01 (0xd5);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_dsp_command01 (0xda);
|
||||
sb_dsp_command01 (0xd0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_irq_hw (int level)
|
||||
{
|
||||
int ival;
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case 5:
|
||||
ival = 2;
|
||||
break;
|
||||
case 7:
|
||||
ival = 4;
|
||||
break;
|
||||
case 10:
|
||||
ival = 8;
|
||||
break;
|
||||
default:
|
||||
printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
|
||||
return;
|
||||
}
|
||||
sb_setmixer (IRQ_NR, ival);
|
||||
}
|
||||
|
||||
long
|
||||
sb16_dsp_init (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
int i, major, minor;
|
||||
|
||||
major = minor = 0;
|
||||
sb_dsp_command (0xe1); /* Get version */
|
||||
|
||||
for (i = 1000; i; i--)
|
||||
{
|
||||
if (INB (DSP_DATA_AVAIL) & 0x80)
|
||||
{ /* wait for Data Ready */
|
||||
if (major == 0)
|
||||
major = INB (DSP_READ);
|
||||
else
|
||||
{
|
||||
minor = INB (DSP_READ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SCO
|
||||
sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", major, minor);
|
||||
#endif
|
||||
|
||||
printk ("snd6: <%s>", sb16_dsp_operations.name);
|
||||
|
||||
if (num_dspdevs < MAX_DSP_DEV)
|
||||
{
|
||||
dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations;
|
||||
sound_dsp_dmachan[my_dev] = hw_config->dma;
|
||||
sound_buffcounts[my_dev] = 1;
|
||||
sound_buffsizes[my_dev] = DSP_BUFFSIZE;
|
||||
sound_dma_automode[my_dev] = 1;
|
||||
}
|
||||
else
|
||||
printk ("SB: Too many DSP devices available\n");
|
||||
sb16_dsp_ok = 1;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
sb16_dsp_detect (struct address_info *hw_config)
|
||||
{
|
||||
struct address_info *sb_config;
|
||||
|
||||
if (sb16_dsp_ok)
|
||||
return 1; /* Already initialized */
|
||||
|
||||
if (!(sb_config = sound_getconf (SNDCARD_SB)))
|
||||
{
|
||||
printk ("SB16 Error: Plain SB not configured\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sbc_base != hw_config->io_base)
|
||||
printk ("Warning! SB16 I/O != SB I/O\n");
|
||||
|
||||
/* sb_setmixer(OPSW,0xf);
|
||||
if(sb_getmixer(OPSW)!=0xf)
|
||||
return 0; */
|
||||
|
||||
if (!sb_reset_dsp ())
|
||||
return 0;
|
||||
|
||||
if (hw_config->irq != sb_config->irq)
|
||||
{
|
||||
printk ("SB16 Error: Invalid IRQ number %d/%d\n",
|
||||
sb_config->irq, hw_config->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hw_config->dma < 4)
|
||||
if (hw_config->dma != sb_config->dma)
|
||||
{
|
||||
printk ("SB16 Error: Invalid DMA channel %d/%d\n",
|
||||
sb_config->dma, hw_config->dma);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dma16 = hw_config->dma;
|
||||
dma8 = sb_config->dma;
|
||||
set_irq_hw (hw_config->irq);
|
||||
sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
|
||||
|
||||
DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", hw_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
|
314
sys/i386/isa/sound/sb16_midi.c
Normal file
314
sys/i386/isa/sound/sb16_midi.c
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
* sound/sb16_midi.c
|
||||
*
|
||||
* The low level driver for the MPU-401 UART emulation of the SB16.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#define DATAPORT (sb16midi_base) /* MPU-401 Data I/O Port on IBM */
|
||||
#define COMDPORT (sb16midi_base+1) /* MPU-401 Command Port on IBM */
|
||||
#define STATPORT (sb16midi_base+1) /* MPU-401 Status Port on IBM */
|
||||
|
||||
#define sb16midi_status() INB(STATPORT)
|
||||
#define input_avail() (!(sb16midi_status()&INPUT_AVAIL))
|
||||
#define output_ready() (!(sb16midi_status()&OUTPUT_READY))
|
||||
#define sb16midi_cmd(cmd) OUTB(cmd, COMDPORT)
|
||||
#define sb16midi_read() INB(DATAPORT)
|
||||
#define sb16midi_write(byte) OUTB(byte, DATAPORT)
|
||||
|
||||
#define OUTPUT_READY 0x40 /* Mask for Data Read Redy Bit */
|
||||
#define INPUT_AVAIL 0x80 /* Mask for Data Send Ready Bit */
|
||||
#define MPU_ACK 0xFE /* MPU-401 Acknowledge Response */
|
||||
#define MPU_RESET 0xFF /* MPU-401 Total Reset Command */
|
||||
#define UART_MODE_ON 0x3F /* MPU-401 "Dumb UART Mode" */
|
||||
|
||||
static int sb16midi_opened = 0;
|
||||
static int sb16midi_base = 0x330;
|
||||
static int sb16midi_detected = 0;
|
||||
static int my_dev;
|
||||
|
||||
static int reset_sb16midi (void);
|
||||
static void (*midi_input_intr) (int dev, unsigned char data);
|
||||
|
||||
static void
|
||||
sb16midi_input_loop (void)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 10;
|
||||
|
||||
while (count) /* Not timed out */
|
||||
if (input_avail ())
|
||||
{
|
||||
unsigned char c = sb16midi_read ();
|
||||
|
||||
count = 100;
|
||||
|
||||
if (sb16midi_opened & OPEN_READ)
|
||||
midi_input_intr (my_dev, c);
|
||||
}
|
||||
else
|
||||
while (!input_avail () && count)
|
||||
count--;
|
||||
}
|
||||
|
||||
void
|
||||
sb16midiintr (int unit)
|
||||
{
|
||||
if (input_avail ())
|
||||
sb16midi_input_loop ();
|
||||
}
|
||||
|
||||
/*
|
||||
* It looks like there is no input interrupts in the UART mode. Let's try
|
||||
* polling.
|
||||
*/
|
||||
|
||||
static void
|
||||
poll_sb16midi (unsigned long dummy)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DEFINE_TIMER (sb16midi_timer, poll_sb16midi);
|
||||
|
||||
if (!(sb16midi_opened & OPEN_READ))
|
||||
return; /* No longer required */
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (input_avail ())
|
||||
sb16midi_input_loop ();
|
||||
|
||||
ACTIVATE_TIMER (sb16midi_timer, poll_sb16midi, 1); /* Come back later */
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
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;
|
||||
poll_sb16midi (0); /* Enable input polling */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
sb16midi_close (int dev)
|
||||
{
|
||||
sb16midi_opened = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_out (int dev, unsigned char midi_byte)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Test for input since pending input seems to block the output.
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (input_avail ())
|
||||
sb16midi_input_loop ();
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* Sometimes it takes about 13000 loops before the output becomes ready
|
||||
* (After reset). Normally it takes just about 10 loops.
|
||||
*/
|
||||
|
||||
for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */
|
||||
|
||||
if (!output_ready ())
|
||||
{
|
||||
printk ("MPU-401: Timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sb16midi_write (midi_byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_command (int dev, unsigned char midi_byte)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_start_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_end_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_ioctl (int dev, unsigned cmd, unsigned arg)
|
||||
{
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
sb16midi_kick (int dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
sb16midi_buffer_status (int dev)
|
||||
{
|
||||
return 0; /* No data in buffers */
|
||||
}
|
||||
|
||||
static struct midi_operations sb16midi_operations =
|
||||
{
|
||||
{"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI},
|
||||
sb16midi_open,
|
||||
sb16midi_close,
|
||||
sb16midi_ioctl,
|
||||
sb16midi_out,
|
||||
sb16midi_start_read,
|
||||
sb16midi_end_read,
|
||||
sb16midi_kick,
|
||||
sb16midi_command,
|
||||
sb16midi_buffer_status
|
||||
};
|
||||
|
||||
|
||||
long
|
||||
attach_sb16midi (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
int ok, timeout;
|
||||
unsigned long flags;
|
||||
|
||||
sb16midi_base = hw_config->io_base;
|
||||
|
||||
if (!sb16midi_detected)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
|
||||
sb16midi_cmd (UART_MODE_ON);
|
||||
|
||||
ok = 0;
|
||||
for (timeout = 50000; timeout > 0 && !ok; timeout--)
|
||||
if (input_avail ())
|
||||
if (sb16midi_read () == MPU_ACK)
|
||||
ok = 1;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
printk ("snd7: <SoundBlaster MPU-401>");
|
||||
|
||||
my_dev = num_midis;
|
||||
midi_devs[num_midis++] = &sb16midi_operations;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
static int
|
||||
reset_sb16midi (void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ok, timeout, n;
|
||||
|
||||
/*
|
||||
* Send the RESET command. Try again if no success at the first time.
|
||||
*/
|
||||
|
||||
ok = 0;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
for (n = 0; n < 2 && !ok; n++)
|
||||
{
|
||||
for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
|
||||
sb16midi_cmd (MPU_RESET); /* Send MPU-401 RESET Command */
|
||||
|
||||
/*
|
||||
* Wait at least 25 msec. This method is not accurate so let's make the
|
||||
* loop bit longer. Cannot sleep since this is called during boot.
|
||||
*/
|
||||
|
||||
for (timeout = 50000; timeout > 0 && !ok; timeout--)
|
||||
if (input_avail ())
|
||||
if (sb16midi_read () == MPU_ACK)
|
||||
ok = 1;
|
||||
|
||||
}
|
||||
|
||||
sb16midi_opened = 0;
|
||||
if (ok)
|
||||
sb16midi_input_loop (); /* Flush input before enabling interrupts */
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
probe_sb16midi (struct address_info *hw_config)
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
sb16midi_base = hw_config->io_base;
|
||||
|
||||
if (sb_get_irq () < 0)
|
||||
return 0;
|
||||
|
||||
ok = reset_sb16midi ();
|
||||
|
||||
sb16midi_detected = ok;
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,6 +1,5 @@
|
||||
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/sb_card.c
|
||||
* sound/sb_card.c
|
||||
*
|
||||
* Detection routine for the SoundBlaster cards.
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
198
sys/i386/isa/sound/sb_midi.c
Normal file
198
sys/i386/isa/sound/sb_midi.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* sound/sb_dsp.c
|
||||
*
|
||||
* The low level driver for the SoundBlaster DS chips.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#include "sb.h"
|
||||
#undef SB_TEST_IRQ
|
||||
|
||||
/*
|
||||
* The DSP channel can be used either for input or output. Variable
|
||||
* 'sb_irq_mode' will be set when the program calls read or write first time
|
||||
* after open. Current version doesn't support mode changes without closing
|
||||
* and reopening the device. Support for this feature may be implemented in a
|
||||
* future version of this driver.
|
||||
*/
|
||||
|
||||
extern int sb_dsp_ok; /* Set to 1 after successful initialization */
|
||||
|
||||
extern int sb_midi_mode;
|
||||
extern int sb_midi_busy; /* 1 if the process has output to MIDI */
|
||||
extern int sb_dsp_busy;
|
||||
extern int sb_dsp_highspeed;
|
||||
|
||||
extern volatile int sb_irq_mode; /* IMODE_INPUT, IMODE_OUTPUT
|
||||
|
||||
* or IMODE_NONE */
|
||||
extern int sb_dsp_model; /* 1=SB, 2=SB Pro */
|
||||
extern int sb_duplex_midi;
|
||||
extern int sb_intr_active;
|
||||
|
||||
static int
|
||||
sb_midi_open (int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
void (*output) (int dev)
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sb_dsp_ok)
|
||||
{
|
||||
printk ("SB Error: MIDI hardware not installed\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
if (mode != OPEN_WRITE && !sb_duplex_midi)
|
||||
{
|
||||
if (num_midis == 1)
|
||||
printk ("SoundBlaster: Midi input not 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 */
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_midi_out (int dev, unsigned char midi_byte)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
sb_midi_busy = 1; /* Kill all notes after close */
|
||||
|
||||
if (sb_midi_mode == NORMAL_MIDI)
|
||||
{
|
||||
DISABLE_INTR (flags);
|
||||
if (sb_dsp_command (0x38))
|
||||
sb_dsp_command (midi_byte);
|
||||
else
|
||||
printk ("SB Error: Unable to send a MIDI byte\n");
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
else
|
||||
sb_dsp_command (midi_byte); /* UART write */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_midi_start_read (int dev)
|
||||
{
|
||||
if (sb_midi_mode != UART_MIDI)
|
||||
{
|
||||
printk ("SoundBlaster: MIDI input not implemented.\n");
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_midi_end_read (int dev)
|
||||
{
|
||||
if (sb_midi_mode == UART_MIDI)
|
||||
{
|
||||
sb_reset_dsp ();
|
||||
sb_intr_active = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_midi_ioctl (int dev, unsigned cmd, unsigned arg)
|
||||
{
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
|
||||
static struct midi_operations sb_midi_operations =
|
||||
{
|
||||
{"SoundBlaster", 0, 0, SNDCARD_SB},
|
||||
sb_midi_open,
|
||||
sb_midi_close,
|
||||
sb_midi_ioctl,
|
||||
sb_midi_out,
|
||||
sb_midi_start_read,
|
||||
sb_midi_end_read,
|
||||
NULL, /* Kick */
|
||||
NULL, /* command */
|
||||
NULL /* buffer_status */
|
||||
};
|
||||
|
||||
void
|
||||
sb_midi_init (int model)
|
||||
{
|
||||
midi_devs[num_midis++] = &sb_midi_operations;
|
||||
}
|
||||
|
||||
#endif
|
359
sys/i386/isa/sound/sb_mixer.c
Normal file
359
sys/i386/isa/sound/sb_mixer.c
Normal file
@ -0,0 +1,359 @@
|
||||
|
||||
/*
|
||||
* sound/sb_mixer.c
|
||||
*
|
||||
* The low level mixer driver for the SoundBlaster Pro and SB16 cards.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#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)));
|
||||
}
|
||||
|
||||
static int
|
||||
detect_mixer (void)
|
||||
{
|
||||
/*
|
||||
* Detect the mixer by changing parameters of two volume channels. If the
|
||||
* values read back match with the values written, the mixer is there (is
|
||||
* it?)
|
||||
*/
|
||||
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;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
change_bits (unsigned char *regval, int dev, int chn, int newval)
|
||||
{
|
||||
unsigned char mask;
|
||||
int shift;
|
||||
|
||||
mask = (1 << (*iomap)[dev][chn].nbits) - 1;
|
||||
newval = ((newval * mask) + 50) / 100; /* Scale it */
|
||||
|
||||
shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
|
||||
|
||||
*regval &= ~(mask << shift); /* Filter out the previous value */
|
||||
*regval |= (newval & mask) << shift; /* Set the new value */
|
||||
}
|
||||
|
||||
static int
|
||||
sb_mixer_get (int dev)
|
||||
{
|
||||
if (!((1 << dev) & supported_devices))
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
return levels[dev];
|
||||
}
|
||||
|
||||
static int
|
||||
sb_mixer_set (int dev, int value)
|
||||
{
|
||||
int left = value & 0x000000ff;
|
||||
int right = (value & 0x0000ff00) >> 8;
|
||||
|
||||
int regoffs;
|
||||
unsigned char val;
|
||||
|
||||
if (left > 100)
|
||||
left = 100;
|
||||
if (right > 100)
|
||||
right = 100;
|
||||
|
||||
if (dev > 31)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
if (!(supported_devices & (1 << dev))) /* Not supported */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
regoffs = (*iomap)[dev][LEFT_CHN].regno;
|
||||
|
||||
if (regoffs == 0)
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
val = sb_getmixer (regoffs);
|
||||
change_bits (&val, dev, LEFT_CHN, left);
|
||||
|
||||
levels[dev] = left | (left << 8);
|
||||
|
||||
if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */
|
||||
{
|
||||
sb_setmixer (regoffs, val); /* Save the old one */
|
||||
regoffs = (*iomap)[dev][RIGHT_CHN].regno;
|
||||
|
||||
if (regoffs == 0)
|
||||
return left | (left << 8); /* Just left channel present */
|
||||
|
||||
val = sb_getmixer (regoffs); /* Read the new one */
|
||||
}
|
||||
|
||||
change_bits (&val, dev, RIGHT_CHN, right);
|
||||
sb_setmixer (regoffs, val);
|
||||
|
||||
levels[dev] = left | (right << 8);
|
||||
return left | (right << 8);
|
||||
}
|
||||
|
||||
static void
|
||||
set_recsrc (int src)
|
||||
{
|
||||
sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
|
||||
}
|
||||
|
||||
static int
|
||||
set_recmask (int mask)
|
||||
{
|
||||
int devmask, i;
|
||||
unsigned char regimageL, regimageR;
|
||||
|
||||
devmask = mask & supported_rec_devices;
|
||||
|
||||
switch (mixer_model)
|
||||
{
|
||||
case 3:
|
||||
|
||||
if (devmask != SOUND_MASK_MIC &&
|
||||
devmask != SOUND_MASK_LINE &&
|
||||
devmask != SOUND_MASK_CD)
|
||||
{ /* More than one devices selected. Drop the
|
||||
* previous selection */
|
||||
devmask &= ~recmask;
|
||||
}
|
||||
|
||||
if (devmask != SOUND_MASK_MIC &&
|
||||
devmask != SOUND_MASK_LINE &&
|
||||
devmask != SOUND_MASK_CD)
|
||||
{ /* More than one devices selected. Default to
|
||||
* mic */
|
||||
devmask = SOUND_MASK_MIC;
|
||||
}
|
||||
|
||||
|
||||
if (devmask ^ recmask) /* Input source changed */
|
||||
{
|
||||
switch (devmask)
|
||||
{
|
||||
|
||||
case SOUND_MASK_MIC:
|
||||
set_recsrc (SRC_MIC);
|
||||
break;
|
||||
|
||||
case SOUND_MASK_LINE:
|
||||
set_recsrc (SRC_LINE);
|
||||
break;
|
||||
|
||||
case SOUND_MASK_CD:
|
||||
set_recsrc (SRC_CD);
|
||||
break;
|
||||
|
||||
default:
|
||||
set_recsrc (SRC_MIC);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (!devmask)
|
||||
devmask = SOUND_MASK_MIC;
|
||||
|
||||
regimageL = regimageR = 0;
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
|
||||
if ((1 << i) & devmask)
|
||||
{
|
||||
regimageL |= sb16_recmasks_L[i];
|
||||
regimageR |= sb16_recmasks_R[i];
|
||||
}
|
||||
sb_setmixer (SB16_IMASK_L, regimageL);
|
||||
sb_setmixer (SB16_IMASK_R, regimageR);
|
||||
break;
|
||||
}
|
||||
|
||||
recmask = devmask;
|
||||
return recmask;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
if (((cmd >> 8) & 0xff) == 'M')
|
||||
{
|
||||
if (cmd & IOC_IN)
|
||||
switch (cmd & 0xff)
|
||||
{
|
||||
case SOUND_MIXER_RECSRC:
|
||||
return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg)));
|
||||
break;
|
||||
|
||||
default:
|
||||
return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
|
||||
}
|
||||
else
|
||||
switch (cmd & 0xff) /* Return parameters */
|
||||
{
|
||||
|
||||
case SOUND_MIXER_RECSRC:
|
||||
return IOCTL_OUT (arg, recmask);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_DEVMASK:
|
||||
return IOCTL_OUT (arg, supported_devices);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_STEREODEVS:
|
||||
return IOCTL_OUT (arg, supported_devices &
|
||||
~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_RECMASK:
|
||||
return IOCTL_OUT (arg, supported_rec_devices);
|
||||
break;
|
||||
|
||||
case SOUND_MIXER_CAPS:
|
||||
return IOCTL_OUT (arg, mixer_caps);
|
||||
break;
|
||||
|
||||
default:
|
||||
return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
|
||||
}
|
||||
}
|
||||
else
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static struct mixer_operations sb_mixer_operations =
|
||||
{
|
||||
sb_mixer_ioctl
|
||||
};
|
||||
|
||||
static void
|
||||
sb_mixer_reset (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
|
||||
sb_mixer_set (i, levels[i]);
|
||||
set_recmask (SOUND_MASK_MIC);
|
||||
}
|
||||
|
||||
void
|
||||
sb_mixer_init (int major_model)
|
||||
{
|
||||
sb_setmixer (0x00, 0); /* Reset mixer */
|
||||
|
||||
if (!detect_mixer ())
|
||||
return; /* No mixer. Why? */
|
||||
|
||||
mixer_initialized = 1;
|
||||
mixer_model = major_model;
|
||||
|
||||
switch (major_model)
|
||||
{
|
||||
case 3:
|
||||
mixer_caps = SOUND_CAP_EXCL_INPUT;
|
||||
supported_devices = SBPRO_MIXER_DEVICES;
|
||||
supported_rec_devices = SBPRO_RECORDING_DEVICES;
|
||||
iomap = &sbpro_mix;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
mixer_caps = 0;
|
||||
supported_devices = SB16_MIXER_DEVICES;
|
||||
supported_rec_devices = SB16_RECORDING_DEVICES;
|
||||
iomap = &sb16_mix;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("SB Warning: Unsupported mixer type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mixer_devs[num_mixers++] = &sb_mixer_operations;
|
||||
sb_mixer_reset ();
|
||||
}
|
||||
|
||||
#endif
|
172
sys/i386/isa/sound/sb_mixer.h
Normal file
172
sys/i386/isa/sound/sb_mixer.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
|
||||
|
||||
#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
|
||||
SOUND_MASK_CD | SOUND_MASK_VOLUME)
|
||||
|
||||
#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
|
||||
|
||||
#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)
|
||||
};
|
||||
|
||||
mixer_tab sb16_mix = {
|
||||
MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4),
|
||||
MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4),
|
||||
MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5),
|
||||
MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
|
||||
MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2)
|
||||
};
|
||||
|
||||
static unsigned short levels[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x5a5a, /* Master Volume */
|
||||
0x3232, /* Bass */
|
||||
0x3232, /* Treble */
|
||||
0x4b4b, /* FM */
|
||||
0x4b4b, /* PCM */
|
||||
0x4b4b, /* PC Speaker */
|
||||
0x4b4b, /* Ext Line */
|
||||
0x0000, /* Mic */
|
||||
0x4b4b, /* CD */
|
||||
0x4b4b, /* Recording monitor */
|
||||
0x4b4b, /* SB PCM */
|
||||
0x4b4b}; /* Recording level */
|
||||
|
||||
static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x00, /* SOUND_MIXER_VOLUME */
|
||||
0x00, /* SOUND_MIXER_BASS */
|
||||
0x00, /* SOUND_MIXER_TREBLE */
|
||||
0x40, /* SOUND_MIXER_SYNTH */
|
||||
0x00, /* SOUND_MIXER_PCM */
|
||||
0x00, /* SOUND_MIXER_SPEAKER */
|
||||
0x10, /* SOUND_MIXER_LINE */
|
||||
0x01, /* SOUND_MIXER_MIC */
|
||||
0x04, /* SOUND_MIXER_CD */
|
||||
0x00, /* SOUND_MIXER_IMIX */
|
||||
0x00, /* SOUND_MIXER_ALTPCM */
|
||||
0x00 /* SOUND_MIXER_RECLEV */
|
||||
};
|
||||
|
||||
static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
|
||||
{
|
||||
0x00, /* SOUND_MIXER_VOLUME */
|
||||
0x00, /* SOUND_MIXER_BASS */
|
||||
0x00, /* SOUND_MIXER_TREBLE */
|
||||
0x20, /* SOUND_MIXER_SYNTH */
|
||||
0x00, /* SOUND_MIXER_PCM */
|
||||
0x00, /* SOUND_MIXER_SPEAKER */
|
||||
0x08, /* SOUND_MIXER_LINE */
|
||||
0x01, /* SOUND_MIXER_MIC */
|
||||
0x02, /* SOUND_MIXER_CD */
|
||||
0x00, /* SOUND_MIXER_IMIX */
|
||||
0x00, /* SOUND_MIXER_ALTPCM */
|
||||
0x00 /* SOUND_MIXER_RECLEV */
|
||||
};
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* linux/kernel/chr_drv/sound/sequencer.c
|
||||
* sound/sequencer.c
|
||||
*
|
||||
* The sequencer personality manager.
|
||||
*
|
||||
@ -37,7 +37,9 @@
|
||||
static int sequencer_ok = 0;
|
||||
|
||||
DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
|
||||
DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
|
||||
/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */
|
||||
#define midi_sleeper seq_sleeper
|
||||
#define midi_sleep_flag seq_sleep_flag
|
||||
|
||||
static int midi_opened[MAX_MIDI_DEV] =
|
||||
{0}; /* 1 if the process has opened MIDI */
|
||||
@ -49,8 +51,10 @@ long seq_time = 0; /* Reference point for the timer */
|
||||
#include "tuning.h"
|
||||
|
||||
#define EV_SZ 8
|
||||
static unsigned char queue[SEQ_MAX_QUEUE][EV_SZ];
|
||||
static unsigned char iqueue[SEQ_MAX_QUEUE][4];
|
||||
#define IEV_SZ 4
|
||||
static unsigned char *queue = NULL; /* SEQ_MAX_QUEUE * EV_SZ bytes */
|
||||
static unsigned char *iqueue = NULL; /* SEQ_MAX_QUEUE * IEV_SZ bytes */
|
||||
|
||||
static volatile int qhead = 0, qtail = 0, qlen = 0;
|
||||
static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
|
||||
static volatile int seq_playing = 0;
|
||||
@ -83,13 +87,13 @@ sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
if (!iqlen)
|
||||
{
|
||||
INTERRUPTIBLE_SLEEP_ON (midi_sleeper, midi_sleep_flag);
|
||||
DO_SLEEP (midi_sleeper, midi_sleep_flag, 0);
|
||||
|
||||
if (!iqlen)
|
||||
return count - c;
|
||||
}
|
||||
|
||||
COPY_TO_USER (buf, p, &iqueue[iqhead][0], 4);
|
||||
COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ);
|
||||
p += 4;
|
||||
c -= 4;
|
||||
|
||||
@ -114,14 +118,14 @@ copy_to_input (unsigned char *event)
|
||||
if (iqlen >= (SEQ_MAX_QUEUE - 1))
|
||||
return; /* Overflow */
|
||||
|
||||
memcpy (iqueue[iqtail], event, 4);
|
||||
memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ);
|
||||
iqlen++;
|
||||
iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (midi_sleep_flag)
|
||||
if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag))
|
||||
{
|
||||
WAKE_UP (midi_sleeper);
|
||||
WAKE_UP (midi_sleeper, midi_sleep_flag);
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
@ -266,16 +270,16 @@ seq_queue (unsigned char *note)
|
||||
if (!seq_playing)
|
||||
seq_startplay (); /* Give chance to drain the queue */
|
||||
|
||||
if (qlen >= SEQ_MAX_QUEUE && !seq_sleep_flag)
|
||||
if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
|
||||
{
|
||||
/* Sleep until there is enough space on the queue */
|
||||
INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
|
||||
DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
|
||||
}
|
||||
|
||||
if (qlen >= SEQ_MAX_QUEUE)
|
||||
return 0; /* To be sure */
|
||||
|
||||
memcpy (&queue[qtail][0], note, EV_SZ);
|
||||
memcpy (&queue[qtail * EV_SZ], note, EV_SZ);
|
||||
|
||||
qtail = (qtail + 1) % SEQ_MAX_QUEUE;
|
||||
qlen++;
|
||||
@ -342,7 +346,7 @@ seq_startplay (void)
|
||||
qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
|
||||
qlen--;
|
||||
|
||||
q = &queue[this_one][0];
|
||||
q = &queue[this_one * EV_SZ];
|
||||
|
||||
switch (q[0])
|
||||
{
|
||||
@ -378,10 +382,9 @@ seq_startplay (void)
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (seq_sleep_flag)
|
||||
if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
|
||||
{
|
||||
seq_sleep_flag = 0;
|
||||
WAKE_UP (seq_sleeper);
|
||||
WAKE_UP (seq_sleeper, seq_sleep_flag);
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
@ -449,10 +452,9 @@ seq_startplay (void)
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (seq_sleep_flag)
|
||||
if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
|
||||
{
|
||||
seq_sleep_flag = 0;
|
||||
WAKE_UP (seq_sleeper);
|
||||
WAKE_UP (seq_sleeper, seq_sleep_flag);
|
||||
}
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
@ -461,86 +463,87 @@ seq_startplay (void)
|
||||
|
||||
int
|
||||
sequencer_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
int retval, mode, i;
|
||||
{
|
||||
int retval, mode, i;
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
|
||||
DEB (printk ("sequencer_open(dev=%d)\n", dev));
|
||||
DEB (printk ("sequencer_open(dev=%d)\n", dev));
|
||||
|
||||
if (!sequencer_ok)
|
||||
{
|
||||
printk ("Soundcard: Sequencer not initialized\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
if (dev) /* Patch manager device */
|
||||
{
|
||||
int err;
|
||||
|
||||
dev--;
|
||||
if (pmgr_present[dev])
|
||||
return RET_ERROR (EBUSY);
|
||||
if ((err = pmgr_open (dev)) < 0)
|
||||
return err; /* Failed */
|
||||
|
||||
pmgr_present[dev] = 1;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (sequencer_busy)
|
||||
{
|
||||
printk ("Sequencer busy\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
if (!(num_synths + num_midis))
|
||||
if (!sequencer_ok)
|
||||
{
|
||||
printk ("Soundcard: Sequencer not initialized\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
synth_open_mask = 0;
|
||||
if (dev) /* Patch manager device */
|
||||
{
|
||||
int err;
|
||||
|
||||
if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
|
||||
for (i = 0; i < num_synths; i++) /* Open synth devices */
|
||||
if (synth_devs[i]->open (i, mode) < 0)
|
||||
printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
|
||||
else
|
||||
synth_open_mask |= (1 << i);
|
||||
dev--;
|
||||
if (pmgr_present[dev])
|
||||
return RET_ERROR (EBUSY);
|
||||
if ((err = pmgr_open (dev)) < 0)
|
||||
return err; /* Failed */
|
||||
|
||||
seq_time = GET_TIME ();
|
||||
pmgr_present[dev] = 1;
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_midis; i++)
|
||||
{
|
||||
midi_opened[i] = 0;
|
||||
midi_written[i] = 0;
|
||||
}
|
||||
if (sequencer_busy)
|
||||
{
|
||||
printk ("Sequencer busy\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
if (mode == OPEN_READ || mode == OPEN_READWRITE)
|
||||
{ /* Initialize midi input devices */
|
||||
if (!num_midis)
|
||||
{
|
||||
printk ("Sequencer: No Midi devices. Input not possible\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
if (!(num_synths + num_midis))
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
for (i = 0; i < num_midis; i++)
|
||||
{
|
||||
if ((retval = midi_devs[i]->open (i, mode,
|
||||
synth_open_mask = 0;
|
||||
|
||||
if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
|
||||
for (i = 0; i < num_synths; i++) /* Open synth devices */
|
||||
if (synth_devs[i]->open (i, mode) < 0)
|
||||
printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
|
||||
else
|
||||
synth_open_mask |= (1 << i);
|
||||
|
||||
seq_time = GET_TIME ();
|
||||
|
||||
for (i = 0; i < num_midis; i++)
|
||||
{
|
||||
midi_opened[i] = 0;
|
||||
midi_written[i] = 0;
|
||||
}
|
||||
|
||||
if (mode == OPEN_READ || mode == OPEN_READWRITE)
|
||||
{ /* Initialize midi input devices */
|
||||
if (!num_midis)
|
||||
{
|
||||
printk ("Sequencer: No Midi devices. Input not possible\n");
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_midis; i++)
|
||||
{
|
||||
if ((retval = midi_devs[i]->open (i, mode,
|
||||
sequencer_midi_input, sequencer_midi_output)) >= 0)
|
||||
midi_opened[i] = 1;
|
||||
}
|
||||
}
|
||||
midi_opened[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sequencer_busy = 1;
|
||||
seq_sleep_flag = midi_sleep_flag = 0;
|
||||
output_treshold = SEQ_MAX_QUEUE / 2;
|
||||
sequencer_busy = 1;
|
||||
RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
|
||||
RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
|
||||
output_treshold = SEQ_MAX_QUEUE / 2;
|
||||
|
||||
for (i = 0; i < num_synths; i++)
|
||||
if (pmgr_present[i])
|
||||
pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
|
||||
for (i = 0; i < num_synths; i++)
|
||||
if (pmgr_present[i])
|
||||
pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
seq_drain_midi_queues (void)
|
||||
@ -553,7 +556,7 @@ seq_drain_midi_queues (void)
|
||||
|
||||
n = 1;
|
||||
|
||||
while (!PROCESS_ABORTING && n)
|
||||
while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n)
|
||||
{
|
||||
n = 0;
|
||||
|
||||
@ -568,70 +571,70 @@ seq_drain_midi_queues (void)
|
||||
*/
|
||||
if (n)
|
||||
{
|
||||
REQUEST_TIMEOUT (HZ / 10, seq_sleeper);
|
||||
INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
|
||||
DO_SLEEP (seq_sleeper, seq_sleep_flag, HZ / 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sequencer_release (int dev, struct fileinfo *file)
|
||||
{
|
||||
int i;
|
||||
int mode = file->mode & O_ACCMODE;
|
||||
{
|
||||
int i;
|
||||
int mode = file->mode & O_ACCMODE;
|
||||
|
||||
dev = dev >> 4;
|
||||
dev = dev >> 4;
|
||||
|
||||
DEB (printk ("sequencer_release(dev=%d)\n", dev));
|
||||
DEB (printk ("sequencer_release(dev=%d)\n", dev));
|
||||
|
||||
if (dev) /* Patch manager device */
|
||||
{
|
||||
dev--;
|
||||
pmgr_release (dev);
|
||||
pmgr_present[dev] = 0;
|
||||
return;
|
||||
}
|
||||
if (dev) /* Patch manager device */
|
||||
{
|
||||
dev--;
|
||||
pmgr_release (dev);
|
||||
pmgr_present[dev] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Wait until the queue is empty
|
||||
*/
|
||||
while (!PROCESS_ABORTING && qlen)
|
||||
{
|
||||
seq_sync ();
|
||||
}
|
||||
*/
|
||||
|
||||
if (mode != OPEN_READ)
|
||||
seq_drain_midi_queues (); /* Ensure the output queues are empty */
|
||||
seq_reset ();
|
||||
if (mode != OPEN_READ)
|
||||
seq_drain_midi_queues (); /* Flush the all notes off messages */
|
||||
while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
|
||||
{
|
||||
seq_sync ();
|
||||
}
|
||||
|
||||
for (i = 0; i < num_midis; i++)
|
||||
if (midi_opened[i])
|
||||
midi_devs[i]->close (i);
|
||||
if (mode != OPEN_READ)
|
||||
seq_drain_midi_queues (); /* Ensure the output queues are empty */
|
||||
seq_reset ();
|
||||
if (mode != OPEN_READ)
|
||||
seq_drain_midi_queues (); /* Flush the all notes off messages */
|
||||
|
||||
if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
|
||||
for (i = 0; i < num_synths; i++)
|
||||
if (synth_open_mask & (1 << i)) /* Actually opened */
|
||||
if (synth_devs[i])
|
||||
synth_devs[i]->close (i);
|
||||
for (i = 0; i < num_midis; i++)
|
||||
if (midi_opened[i])
|
||||
midi_devs[i]->close (i);
|
||||
|
||||
if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
|
||||
for (i = 0; i < num_synths; i++)
|
||||
if (pmgr_present[i])
|
||||
pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
|
||||
if (synth_open_mask & (1 << i)) /* Actually opened */
|
||||
if (synth_devs[i])
|
||||
synth_devs[i]->close (i);
|
||||
|
||||
sequencer_busy = 0;
|
||||
}
|
||||
for (i = 0; i < num_synths; i++)
|
||||
if (pmgr_present[i])
|
||||
pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
|
||||
|
||||
sequencer_busy = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
seq_sync (void)
|
||||
{
|
||||
if (qlen && !seq_playing && !PROCESS_ABORTING)
|
||||
if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
|
||||
seq_startplay ();
|
||||
|
||||
if (qlen && !seq_sleep_flag) /* Queue not empty */
|
||||
if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* Queue not empty */
|
||||
{
|
||||
INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
|
||||
DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
|
||||
}
|
||||
|
||||
return qlen;
|
||||
@ -654,8 +657,7 @@ midi_outc (int dev, unsigned char data)
|
||||
|
||||
while (n && !midi_devs[dev]->putc (dev, data))
|
||||
{
|
||||
REQUEST_TIMEOUT (1, seq_sleeper);
|
||||
INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag);
|
||||
DO_SLEEP (seq_sleeper, seq_sleep_flag, 4);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
@ -684,8 +686,9 @@ seq_reset (void)
|
||||
{
|
||||
for (chn = 0; chn < 16; chn++)
|
||||
{
|
||||
midi_outc (i, 0xb0 + chn); /* Channel message */
|
||||
midi_outc (i, 0x7b);/* All notes off */
|
||||
midi_outc (i,
|
||||
(unsigned char) (0xb0 + (chn & 0xff))); /* Channel msg */
|
||||
midi_outc (i, 0x7b); /* All notes off */
|
||||
midi_outc (i, 0); /* Dummy parameter */
|
||||
}
|
||||
|
||||
@ -697,7 +700,7 @@ seq_reset (void)
|
||||
|
||||
seq_playing = 0;
|
||||
|
||||
if (seq_sleep_flag)
|
||||
if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
|
||||
printk ("Sequencer Warning: Unexpected sleeping process\n");
|
||||
|
||||
}
|
||||
@ -720,7 +723,7 @@ sequencer_ioctl (int dev, struct fileinfo *file,
|
||||
|
||||
if (mode == OPEN_READ)
|
||||
return 0;
|
||||
while (qlen && !PROCESS_ABORTING)
|
||||
while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
|
||||
seq_sync ();
|
||||
return 0;
|
||||
break;
|
||||
@ -979,7 +982,6 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w
|
||||
case SEL_IN:
|
||||
if (!iqlen)
|
||||
{
|
||||
midi_sleep_flag = 1;
|
||||
select_wait (&midi_sleeper, wait);
|
||||
return 0;
|
||||
}
|
||||
@ -990,7 +992,6 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w
|
||||
case SEL_OUT:
|
||||
if (qlen >= SEQ_MAX_QUEUE)
|
||||
{
|
||||
seq_sleep_flag = 1;
|
||||
select_wait (&seq_sleeper, wait);
|
||||
return 0;
|
||||
}
|
||||
@ -1039,7 +1040,7 @@ note_to_freq (int note_num)
|
||||
else if (octave > BASE_OCTAVE)
|
||||
note_freq <<= (octave - BASE_OCTAVE);
|
||||
|
||||
/* note_freq >>= 1; */
|
||||
/* note_freq >>= 1; */
|
||||
|
||||
return note_freq;
|
||||
}
|
||||
@ -1092,6 +1093,9 @@ sequencer_init (long mem_start)
|
||||
{
|
||||
|
||||
sequencer_ok = 1;
|
||||
PERMANENT_MALLOC (unsigned char *, queue, SEQ_MAX_QUEUE * EV_SZ, mem_start);
|
||||
PERMANENT_MALLOC (unsigned char *, iqueue, SEQ_MAX_QUEUE * IEV_SZ, mem_start);
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
@ -1111,14 +1115,14 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
|
||||
int
|
||||
sequencer_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
{
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
void
|
||||
sequencer_release (int dev, struct fileinfo *file)
|
||||
{
|
||||
}
|
||||
{
|
||||
}
|
||||
int
|
||||
sequencer_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
|
@ -16,23 +16,10 @@ int DMAbuf_open_dma (int chan);
|
||||
void DMAbuf_close_dma (int chan);
|
||||
void DMAbuf_reset_dma (int chan);
|
||||
void DMAbuf_inputintr(int dev);
|
||||
void DMAbuf_outputintr(int dev);
|
||||
void DMAbuf_outputintr(int dev, int underflow_flag);
|
||||
|
||||
/*
|
||||
* System calls for the /dev/dsp
|
||||
*/
|
||||
|
||||
int dsp_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int dsp_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int dsp_open (int dev, struct fileinfo *file, int bits);
|
||||
void dsp_release (int dev, struct fileinfo *file);
|
||||
int dsp_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg);
|
||||
int dsp_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
|
||||
long dsp_init (long mem_start);
|
||||
|
||||
/*
|
||||
* System calls for the /dev/audio
|
||||
* System calls for /dev/dsp and /dev/audio
|
||||
*/
|
||||
|
||||
int audio_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
@ -108,11 +95,46 @@ void tenmicrosec(void);
|
||||
void request_sound_timer (int count);
|
||||
void sound_stop_timer(void);
|
||||
int snd_ioctl_return(int *addr, int value);
|
||||
int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int));
|
||||
void snd_release_irq(int vect);
|
||||
void sound_dma_malloc(int dev);
|
||||
void sound_dma_free(int dev);
|
||||
|
||||
/* From sound_switch.c */
|
||||
int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
|
||||
int sound_open_sw (int dev, struct fileinfo *file);
|
||||
void sound_release_sw (int dev, struct fileinfo *file);
|
||||
int sound_ioctl_sw (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
/* From sb_dsp.c */
|
||||
int sb_dsp_detect (struct address_info *hw_config);
|
||||
long sb_dsp_init (long mem_start, struct address_info *hw_config);
|
||||
void sb_dsp_disable_midi(void);
|
||||
int sb_get_irq(void);
|
||||
void sb_free_irq(void);
|
||||
int sb_dsp_command (unsigned char val);
|
||||
int sb_reset_dsp (void);
|
||||
|
||||
/* From sb16_dsp.c */
|
||||
void sb16_dsp_interrupt (int unused);
|
||||
long sb16_dsp_init(long mem_start, struct address_info *hw_config);
|
||||
int sb16_dsp_detect(struct address_info *hw_config);
|
||||
|
||||
/* From sb16_midi.c */
|
||||
void sb16midiintr (int unit);
|
||||
long attach_sb16midi(long mem_start, struct address_info * hw_config);
|
||||
int probe_sb16midi(struct address_info *hw_config);
|
||||
|
||||
/* From sb_midi.c */
|
||||
void sb_midi_init(int model);
|
||||
|
||||
/* 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);
|
||||
void sb_mixer_init(int major_model);
|
||||
|
||||
/* From opl3.c */
|
||||
int opl3_detect (int ioaddr);
|
||||
@ -156,7 +178,7 @@ int gus_wave_detect(int baseaddr);
|
||||
long gus_wave_init(long mem_start, int irq, int dma);
|
||||
void gus_voice_irq(void);
|
||||
unsigned char gus_read8 (int reg);
|
||||
void gus_write8(int reg, unsigned char data);
|
||||
void gus_write8(int reg, unsigned int data);
|
||||
void guswave_dma_irq(void);
|
||||
void gus_delay(void);
|
||||
|
||||
|
@ -30,6 +30,16 @@
|
||||
|
||||
#include "local.h"
|
||||
|
||||
|
||||
#undef CONFIGURE_SOUNDCARD
|
||||
#undef DYNAMIC_BUFFER
|
||||
|
||||
#ifdef KERNEL_SOUNDCARD
|
||||
#define CONFIGURE_SOUNDCARD
|
||||
#define DYNAMIC_BUFFER
|
||||
#undef LOADABLE_SOUNDCARD
|
||||
#endif
|
||||
|
||||
#ifdef EXCLUDE_SEQUENCER
|
||||
#ifndef EXCLUDE_MIDI
|
||||
#define EXCLUDE_MIDI
|
||||
@ -42,6 +52,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SND_DEFAULT_ENABLE
|
||||
#define SND_DEFAULT_ENABLE 1
|
||||
#endif
|
||||
|
||||
/** UWM - new MIDI stuff **/
|
||||
|
||||
#ifdef EXCLUDE_CHIP_MIDI
|
||||
@ -75,6 +89,14 @@ If your card has nonstandard I/O address or IRQ number, change defines
|
||||
#define SBC_DMA 1
|
||||
#endif
|
||||
|
||||
#ifndef SB16_DMA
|
||||
#define SB16_DMA 6
|
||||
#endif
|
||||
|
||||
#ifndef SB16MIDI_BASE
|
||||
#define SB16MIDI_BASE 0x300
|
||||
#endif
|
||||
|
||||
#ifndef PAS_BASE
|
||||
#define PAS_BASE 0x388
|
||||
#endif
|
||||
@ -111,6 +133,10 @@ If your card has nonstandard I/O address or IRQ number, change defines
|
||||
#define MPU_IRQ 6
|
||||
#endif
|
||||
|
||||
#ifndef MAX_REALTIME_FACTOR
|
||||
#define MAX_REALTIME_FACTOR 4
|
||||
#endif
|
||||
|
||||
/************* PCM DMA buffer sizes *******************/
|
||||
|
||||
/* If you are using high playback or recording speeds, the default buffersize
|
||||
@ -132,8 +158,6 @@ If your card has nonstandard I/O address or IRQ number, change defines
|
||||
|
||||
#define DMA_AUTOINIT 0x10
|
||||
|
||||
#define SND_MAJOR 14
|
||||
|
||||
#define FM_MONO 0x388 /* This is the I/O address used by AdLib */
|
||||
|
||||
/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
|
||||
@ -178,10 +202,10 @@ If your card has nonstandard I/O address or IRQ number, change defines
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
|
||||
#define MAX_DSP_DEV 3
|
||||
#define MAX_MIXER_DEV 1
|
||||
#define MAX_DSP_DEV 4
|
||||
#define MAX_MIXER_DEV 2
|
||||
#define MAX_SYNTH_DEV 3
|
||||
#define MAX_MIDI_DEV 3
|
||||
#define MAX_MIDI_DEV 4
|
||||
|
||||
struct fileinfo {
|
||||
int mode; /* Open mode */
|
||||
@ -193,6 +217,15 @@ struct address_info {
|
||||
int dma;
|
||||
};
|
||||
|
||||
/*
|
||||
* Process wakeup reasons
|
||||
*/
|
||||
#define WK_NONE 0x00
|
||||
#define WK_WAKEUP 0x01
|
||||
#define WK_TIMEOUT 0x02
|
||||
#define WK_SIGNAL 0x04
|
||||
#define WK_SLEEP 0x08
|
||||
|
||||
#define OPEN_READ 1
|
||||
#define OPEN_WRITE 2
|
||||
#define OPEN_READWRITE 3
|
||||
|
444
sys/i386/isa/sound/sound_switch.c
Normal file
444
sys/i386/isa/sound/sound_switch.c
Normal file
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* sound/sound_switch.c
|
||||
*
|
||||
* The system call switch
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
struct sbc_device
|
||||
{
|
||||
int usecount;
|
||||
};
|
||||
|
||||
static struct sbc_device sbc_devices[SND_NDEVS] =
|
||||
{
|
||||
{0}};
|
||||
|
||||
static int in_use = 0; /* Total # of open device files (excluding
|
||||
|
||||
* minor 0) */
|
||||
|
||||
/*
|
||||
* /dev/sndstatus -device
|
||||
*/
|
||||
static char *status_buf = NULL;
|
||||
static int status_len, status_ptr;
|
||||
static int status_busy = 0;
|
||||
|
||||
static int
|
||||
put_status (char *s)
|
||||
{
|
||||
int l;
|
||||
|
||||
for (l = 0; l < 256, s[l]; l++); /* l=strlen(s); */
|
||||
|
||||
if (status_len + l >= 4000)
|
||||
return 0;
|
||||
|
||||
memcpy (&status_buf[status_len], s, l);
|
||||
status_len += l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
put_status_int (unsigned int val, int radix)
|
||||
{
|
||||
int l, v;
|
||||
|
||||
static char hx[] = "0123456789abcdef";
|
||||
char buf[11];
|
||||
|
||||
if (!val)
|
||||
return put_status ("0");
|
||||
|
||||
l = 0;
|
||||
buf[10] = 0;
|
||||
|
||||
while (val)
|
||||
{
|
||||
v = val % radix;
|
||||
val = val / radix;
|
||||
|
||||
buf[9 - l] = hx[v];
|
||||
l++;
|
||||
}
|
||||
|
||||
if (status_len + l >= 4000)
|
||||
return 0;
|
||||
|
||||
memcpy (&status_buf[status_len], &buf[10 - l], l);
|
||||
status_len += l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
init_status (void)
|
||||
{
|
||||
/*
|
||||
* Write the status information to the status_buf and update status_len.
|
||||
* There is a limit of 4000 bytes for the data.
|
||||
*/
|
||||
|
||||
int i;
|
||||
|
||||
status_ptr = 0;
|
||||
|
||||
put_status ("Sound Driver:" SOUND_VERSION_STRING
|
||||
" (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
|
||||
SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")"
|
||||
"\n");
|
||||
|
||||
if (!put_status ("Config options: "))
|
||||
return;
|
||||
if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
|
||||
return;
|
||||
|
||||
if (!put_status ("\n\nHW config: \n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < (num_sound_drivers - 1); i++)
|
||||
{
|
||||
if (!supported_drivers[i].enabled)
|
||||
if (!put_status ("("))
|
||||
return;
|
||||
|
||||
if (!put_status ("Type "))
|
||||
return;
|
||||
if (!put_status_int (supported_drivers[i].card_type, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (supported_drivers[i].name))
|
||||
return;
|
||||
if (!put_status (" at 0x"))
|
||||
return;
|
||||
if (!put_status_int (supported_drivers[i].config.io_base, 16))
|
||||
return;
|
||||
if (!put_status (" irq "))
|
||||
return;
|
||||
if (!put_status_int (supported_drivers[i].config.irq, 10))
|
||||
return;
|
||||
if (!put_status (" drq "))
|
||||
return;
|
||||
if (!put_status_int (supported_drivers[i].config.dma, 10))
|
||||
return;
|
||||
|
||||
if (!supported_drivers[i].enabled)
|
||||
if (!put_status (")"))
|
||||
return;
|
||||
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\nPCM devices:\n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_dspdevs; i++)
|
||||
{
|
||||
if (!put_status_int (i, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (dsp_devs[i]->name))
|
||||
return;
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\nSynth devices:\n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_synths; i++)
|
||||
{
|
||||
if (!put_status_int (i, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (synth_devs[i]->info->name))
|
||||
return;
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!put_status ("\nMidi devices:\n"))
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_midis; i++)
|
||||
{
|
||||
if (!put_status_int (i, 10))
|
||||
return;
|
||||
if (!put_status (": "))
|
||||
return;
|
||||
if (!put_status (midi_devs[i]->info.name))
|
||||
return;
|
||||
if (!put_status ("\n"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_mixers)
|
||||
{
|
||||
if (!put_status ("\nMixer(s) installed\n"))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!put_status ("\nNo mixers installed\n"))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
read_status (snd_rw_buf * buf, int count)
|
||||
{
|
||||
/*
|
||||
* Return at most 'count' bytes from the status_buf.
|
||||
*/
|
||||
int l, c;
|
||||
|
||||
l = count;
|
||||
c = status_len - status_ptr;
|
||||
|
||||
if (l > c)
|
||||
l = c;
|
||||
if (l <= 0)
|
||||
return 0;
|
||||
|
||||
COPY_TO_USER (buf, 0, &status_buf[status_ptr], l);
|
||||
status_ptr += l;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count));
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
case SND_DEV_STATUS:
|
||||
return read_status (buf, count);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
return audio_read (dev, file, buf, count);
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
return sequencer_read (dev, file, buf, count);
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MPU401
|
||||
case SND_DEV_MIDIN:
|
||||
return MIDIbuf_read (dev, file, buf, count);
|
||||
#endif
|
||||
|
||||
default:
|
||||
printk ("Sound: Undefined minor device %d\n", dev);
|
||||
}
|
||||
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
|
||||
int
|
||||
sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
|
||||
DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count));
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
return sequencer_write (dev, file, buf, count);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
return audio_write (dev, file, buf, count);
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int
|
||||
sound_open_sw (int dev, struct fileinfo *file)
|
||||
{
|
||||
int retval;
|
||||
|
||||
DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
|
||||
|
||||
if ((dev >= SND_NDEVS) || (dev < 0))
|
||||
{
|
||||
printk ("Invalid minor device %d\n", dev);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
case SND_DEV_STATUS:
|
||||
if (status_busy)
|
||||
return RET_ERROR (EBUSY);
|
||||
status_busy = 1;
|
||||
if ((status_buf = (char *) KERNEL_MALLOC (4000)) == NULL)
|
||||
return RET_ERROR (EIO);
|
||||
status_len = status_ptr = 0;
|
||||
init_status ();
|
||||
break;
|
||||
|
||||
case SND_DEV_CTL:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
if ((retval = sequencer_open (dev, file)) < 0)
|
||||
return retval;
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MPU401
|
||||
case SND_DEV_MIDIN:
|
||||
if ((retval = MIDIbuf_open (dev, file)) < 0)
|
||||
return retval;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
if ((retval = audio_open (dev, file)) < 0)
|
||||
return retval;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("Invalid minor device %d\n", dev);
|
||||
return RET_ERROR (ENXIO);
|
||||
}
|
||||
|
||||
sbc_devices[dev].usecount++;
|
||||
in_use++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sound_release_sw (int dev, struct fileinfo *file)
|
||||
{
|
||||
|
||||
DEB (printk ("sound_release_sw(dev=%d)\n", dev));
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
case SND_DEV_STATUS:
|
||||
if (status_buf)
|
||||
KERNEL_FREE (status_buf);
|
||||
status_buf = NULL;
|
||||
status_busy = 0;
|
||||
break;
|
||||
|
||||
case SND_DEV_CTL:
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
sequencer_release (dev, file);
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MPU401
|
||||
case SND_DEV_MIDIN:
|
||||
MIDIbuf_release (dev, file);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
audio_release (dev, file);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("Sound error: Releasing unknown device 0x%02x\n", dev);
|
||||
}
|
||||
|
||||
sbc_devices[dev].usecount--;
|
||||
in_use--;
|
||||
}
|
||||
|
||||
int
|
||||
sound_ioctl_sw (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
|
||||
case SND_DEV_CTL:
|
||||
|
||||
if (!num_mixers)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
if ((dev >> 4) >= num_mixers)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg);
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
return sequencer_ioctl (dev, file, cmd, arg);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
case SND_DEV_AUDIO:
|
||||
return audio_ioctl (dev, file, cmd, arg);
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MPU401
|
||||
case SND_DEV_MIDIN:
|
||||
return MIDIbuf_ioctl (dev, file, cmd, arg);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return RET_ERROR (EPERM);
|
||||
break;
|
||||
}
|
||||
|
||||
return RET_ERROR (EPERM);
|
||||
}
|
||||
#endif
|
@ -34,28 +34,20 @@
|
||||
|
||||
#include "dev_table.h"
|
||||
|
||||
int __timeout_val = 0;
|
||||
int __process_aborting = 0;
|
||||
|
||||
u_int snd1mask;
|
||||
u_int snd2mask;
|
||||
u_int snd3mask;
|
||||
u_int snd4mask;
|
||||
u_int snd5mask;
|
||||
|
||||
struct sbc_device
|
||||
{
|
||||
int usecount;
|
||||
};
|
||||
u_int snd6mask;
|
||||
u_int snd7mask;
|
||||
u_int snd8mask;
|
||||
u_int snd9mask;
|
||||
|
||||
#define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
|
||||
|
||||
static struct sbc_device sbc_devices[SND_NDEVS];
|
||||
static int timer_running = 0;
|
||||
|
||||
static int in_use = 0; /* Total # of open device files (excluding
|
||||
* minor 0) */
|
||||
|
||||
static int soundcards_installed = 0; /* Number of installed
|
||||
* soundcards */
|
||||
static int soundcard_configured = 0;
|
||||
@ -91,41 +83,7 @@ sndread (int dev, struct uio *buf)
|
||||
|
||||
dev = minor (dev);
|
||||
|
||||
DEB (printk ("sound_read(dev=%d, count=%d)\n", dev, count));
|
||||
|
||||
switch (dev & 0x0f) /* It really has to be 0x0f */
|
||||
{
|
||||
case SND_DEV_AUDIO:
|
||||
FIX_RETURN (audio_read (dev, &files[dev], buf, count));
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
FIX_RETURN (dsp_read (dev, &files[dev], buf, count));
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
FIX_RETURN (sequencer_read (dev, &files[dev], buf, count));
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_CHIP_MIDI
|
||||
case CMIDI_DEV_PRO:
|
||||
FIX_RETURN (CMIDI_read (dev, &files[dev], buf, count));
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef EXCLUDE_MPU401
|
||||
case SND_DEV_MIDIN:
|
||||
FIX_RETURN (MIDIbuf_read (dev, &files[dev], buf, count));
|
||||
#endif
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
FIX_RETURN (-EPERM);
|
||||
FIX_RETURN (sound_read_sw (dev, &files[dev], buf, count));
|
||||
}
|
||||
|
||||
int
|
||||
@ -133,37 +91,9 @@ sndwrite (int dev, struct uio *buf)
|
||||
{
|
||||
int count = buf->uio_resid;
|
||||
|
||||
DEB (printk ("sound_write(dev=%d, count=%d)\n", dev, count));
|
||||
|
||||
dev = minor (dev);
|
||||
|
||||
switch (dev & 0x0f) /* It really has to be 0x0f */
|
||||
{
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
FIX_RETURN (sequencer_write (dev, &files[dev], buf, count));
|
||||
break;
|
||||
|
||||
case SND_DEV_AUDIO:
|
||||
FIX_RETURN (audio_write (dev, &files[dev], buf, count));
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
FIX_RETURN (dsp_write (dev, &files[dev], buf, count));
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_CHIP_MIDI
|
||||
case CMIDI_DEV_PRO:
|
||||
FIX_RETURN (CMIDI_write (dev, &files[dev], buf, count));
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
FIX_RETURN (-EPERM);
|
||||
}
|
||||
|
||||
FIX_RETURN (count);
|
||||
FIX_RETURN (sound_write_sw (dev, &files[dev], buf, count));
|
||||
}
|
||||
|
||||
int
|
||||
@ -173,16 +103,6 @@ sndopen (dev_t dev, int flags)
|
||||
|
||||
dev = minor (dev);
|
||||
|
||||
/* printf("SND: Minor number is now : %ld\n",dev); */
|
||||
|
||||
DEB (printk ("sound_open(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
|
||||
|
||||
if ((dev >= SND_NDEVS) || (dev < 0))
|
||||
{
|
||||
printk ("Invalid minor device %d\n", dev);
|
||||
FIX_RETURN (-ENODEV);
|
||||
}
|
||||
|
||||
if (!soundcard_configured && dev)
|
||||
{
|
||||
printk ("SoundCard Error: The soundcard system has not been configured\n");
|
||||
@ -198,62 +118,7 @@ sndopen (dev_t dev, int flags)
|
||||
else if (flags & FWRITE)
|
||||
files[dev].mode = OPEN_WRITE;
|
||||
|
||||
switch (dev & 0x0f) /* It has to be 0x0f. Trust me */
|
||||
{
|
||||
case SND_DEV_CTL:
|
||||
if (!soundcards_installed)
|
||||
if (soundcard_configured)
|
||||
{
|
||||
printk ("Soundcard not installed\n");
|
||||
FIX_RETURN (-ENODEV);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
if ((retval = sequencer_open (dev, &files[dev])) < 0)
|
||||
FIX_RETURN (retval);
|
||||
break;
|
||||
|
||||
/** UWM stuff **/
|
||||
|
||||
#ifndef EXCLUDE_CHIP_MIDI
|
||||
case CMIDI_DEV_PRO:
|
||||
FIX_RETURN ( CMIDI_open (dev, &files[dev]) );
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef EXCLUDE_MPU401
|
||||
case SND_DEV_MIDIN:
|
||||
if ((retval = MIDIbuf_open (dev, &files[dev])) < 0)
|
||||
FIX_RETURN (retval);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SND_DEV_AUDIO:
|
||||
if ((retval = audio_open (dev, &files[dev])) < 0)
|
||||
FIX_RETURN (retval);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
if ((retval = dsp_open (dev, &files[dev], 8)) < 0)
|
||||
FIX_RETURN (retval);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP16:
|
||||
if ((retval = dsp_open (dev, &files[dev], 16)) < 0)
|
||||
FIX_RETURN (retval);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk ("Invalid minor device %d\n", dev);
|
||||
FIX_RETURN (-ENODEV);
|
||||
}
|
||||
|
||||
sbc_devices[dev].usecount++;
|
||||
in_use++;
|
||||
|
||||
FIX_RETURN (0);
|
||||
FIX_RETURN(sound_open_sw (dev, &files[dev]));
|
||||
}
|
||||
|
||||
int
|
||||
@ -262,41 +127,7 @@ sndclose (dev_t dev, int flags)
|
||||
|
||||
dev = minor (dev);
|
||||
|
||||
DEB (printk ("sound_release(dev=%d)\n", dev));
|
||||
|
||||
switch (dev & 0x0f) /* Has to be 0x0f */
|
||||
{
|
||||
case SND_DEV_SEQ:
|
||||
sequencer_release (dev, &files[dev]);
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_CHIP_MIDI
|
||||
case CMIDI_DEV_PRO:
|
||||
CMIDI_close (dev, &files[dev]);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef EXCLUDE_MPU401
|
||||
case SND_DEV_MIDIN:
|
||||
MIDIbuf_release (dev, &files[dev]);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SND_DEV_AUDIO:
|
||||
audio_release (dev, &files[dev]);
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
dsp_release (dev, &files[dev]);
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
sbc_devices[dev].usecount--;
|
||||
in_use--; /* If not control port */
|
||||
|
||||
sound_release_sw(dev, &files[dev]);
|
||||
FIX_RETURN (0);
|
||||
}
|
||||
|
||||
@ -305,46 +136,7 @@ sndioctl (dev_t dev, int cmd, caddr_t arg, int mode)
|
||||
{
|
||||
dev = minor (dev);
|
||||
|
||||
DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
|
||||
|
||||
switch (dev & 0x0f)
|
||||
{
|
||||
|
||||
case SND_DEV_CTL:
|
||||
if (!num_mixers)
|
||||
FIX_RETURN (-ENODEV);
|
||||
|
||||
if (dev >= num_mixers)
|
||||
FIX_RETURN (-ENODEV);
|
||||
|
||||
FIX_RETURN (mixer_devs[dev]->ioctl (dev, cmd, (unsigned int) arg));
|
||||
break;
|
||||
|
||||
case SND_DEV_SEQ:
|
||||
FIX_RETURN (sequencer_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
|
||||
break;
|
||||
|
||||
case SND_DEV_AUDIO:
|
||||
FIX_RETURN (audio_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
|
||||
break;
|
||||
|
||||
case SND_DEV_DSP:
|
||||
case SND_DEV_DSP16:
|
||||
FIX_RETURN (dsp_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
|
||||
break;
|
||||
|
||||
#ifndef EXCLUDE_MPU401
|
||||
case SND_DEV_MIDIN:
|
||||
FIX_RETURN (MIDIbuf_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
FIX_RETURN (-EPERM);
|
||||
break;
|
||||
}
|
||||
|
||||
FIX_RETURN (-EPERM);
|
||||
FIX_RETURN (sound_ioctl_sw (dev, &files[dev], cmd, (unsigned int) arg));
|
||||
}
|
||||
|
||||
int
|
||||
@ -380,7 +172,6 @@ sndprobe (struct isa_device *dev)
|
||||
hw_config.io_base = dev->id_iobase;
|
||||
hw_config.irq = ipri_to_irq (dev->id_irq);
|
||||
hw_config.dma = dev->id_drq;
|
||||
|
||||
|
||||
return sndtable_probe (dev->id_unit, &hw_config);
|
||||
}
|
||||
@ -430,7 +221,6 @@ sndattach (struct isa_device *dev)
|
||||
dsp_initialized = 1;
|
||||
mem_start = DMAbuf_init (mem_start);
|
||||
mem_start = audio_init (mem_start);
|
||||
mem_start = dsp_init (mem_start);
|
||||
}
|
||||
|
||||
/** UWM stuff **/
|
||||
@ -459,11 +249,6 @@ sndattach (struct isa_device *dev)
|
||||
mem_start = sequencer_init (mem_start);
|
||||
}
|
||||
|
||||
for (i = 0; i < SND_NDEVS; i++)
|
||||
{
|
||||
sbc_devices[i].usecount = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -514,7 +299,7 @@ void
|
||||
sound_stop_timer (void)
|
||||
{
|
||||
if (timer_running)
|
||||
untimeout ((timeout_func_t)sequencer_timer, 0); /* XXX should fix */
|
||||
untimeout ((timeout_func_t)sequencer_timer, 0);
|
||||
timer_running = 0;
|
||||
}
|
||||
|
||||
@ -532,6 +317,7 @@ sound_mem_init (void)
|
||||
{
|
||||
dsp_init_mask |= (1 << dev);
|
||||
|
||||
#if 1 /* 0 */
|
||||
if (sound_dma_automode[dev])
|
||||
{
|
||||
sound_dma_automode[dev] = 0; /* Not possible with FreeBSD */
|
||||
@ -551,8 +337,10 @@ sound_mem_init (void)
|
||||
dma_pagesize = 131072; /* 128k */
|
||||
else
|
||||
dma_pagesize = 65536;
|
||||
#endif
|
||||
#else
|
||||
dma_pagesize = 4096; /* use bounce buffer */
|
||||
#endif
|
||||
|
||||
|
||||
/* More sanity checks */
|
||||
|
||||
@ -561,6 +349,11 @@ sound_mem_init (void)
|
||||
sound_buffsizes[dev] &= ~0xfff; /* 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; /* -> 64k */
|
||||
#endif
|
||||
|
||||
/* Now allocate the buffers */
|
||||
|
||||
@ -616,4 +409,15 @@ snd_ioctl_return (int *addr, int value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
snd_set_irq_handler (int interrupt_level, void(*hndlr)(int))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
snd_release_irq(int vect)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user