Integrated Hannu Savolainen's new VoxWare sound drivers, version 2.4.

These drivers now have full SoundBlaster 16 support.
This commit is contained in:
Steven Wallace 1994-03-11 10:27:25 +00:00
parent 3507018b5b
commit a75ba8fa22
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=1256
37 changed files with 5023 additions and 2332 deletions

View 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.

View File

@ -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

View File

@ -1,6 +1,5 @@
/*
* linux/kernel/chr_drv/sound/adlib_card.c
* sound/adlib_card.c
*
* Detection routine for the AdLib card.
*

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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,

View File

@ -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

View File

@ -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 ""

View File

@ -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);
}

View File

@ -1,5 +1,5 @@
/*
* linux/kernel/chr_drv/sound/midibuf.c
* sound/midibuf.c
*
* Device file manager for /dev/midi
*

View File

@ -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 ();

View File

@ -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)

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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
View 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

View 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

View 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

View File

@ -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

View 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

View 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

View 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

View File

@ -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)

View File

@ -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);

View File

@ -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

View 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

View File

@ -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