Commit 6da98bdd authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14a

parent 7e842588
VERSION = 0.99
PATCHLEVEL = 14
ALPHA =
ALPHA = a
all: Version zImage
......
......@@ -28,6 +28,8 @@
(stud11@cc4.kuleuven.ac.be)
0.3.2 bug fixes to the ioclts and merged with ALPHA0.99-pl12
(Jon Tombs <jon@robots.ox.ac.uk>)
0.3.3 Added more #defines and mcd_setup()
(Jon Tombs <jon@gtex02.us.es>)
*/
......@@ -38,6 +40,7 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
/* #define REALLY_SLOW_IO */
#include <asm/system.h>
......@@ -46,7 +49,6 @@
#define MAJOR_NR MITSUMI_CDROM_MAJOR
#include "blk.h"
#include <linux/mcd.h>
#if 0
......@@ -57,6 +59,8 @@ static int mcdPresent = 0;
static char mcd_buf[2048]; /* buffer for block size conversion */
static int mcd_bn = -1;
static short mcd_port = MCD_BASE_ADDR;
static int mcd_irq = MCD_INTR_NR;
static int McdTimeout, McdTries;
static struct wait_queue *mcd_waitq = NULL;
......@@ -89,16 +93,28 @@ static int GetToc(void);
static int getValue(unsigned char *result);
void mcd_setup(char *str, int *ints)
{
if (ints[0] > 0)
mcd_port = ints[1];
if (ints[0] > 1)
mcd_irq = ints[2];
}
int
check_mcd_media_change(int full_dev, int flag)
{
int retval, target;
#if 1 /* the below is not reliable */
return 0;
#endif
target = MINOR(full_dev);
if (target > 0) {
printk("Mitsumi CD-ROM request error: invalid device.\n");
printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
return 0;
}
......@@ -122,10 +138,11 @@ statusCmd(void)
{
int st, retry;
for (retry = 0; retry < 3; retry++)
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */
st = getMcdStatus(100);
st = getMcdStatus(MCD_STATUS_DELAY);
if (st != -1)
break;
}
......@@ -143,10 +160,10 @@ mcdPlay(struct mcd_Play_msf *arg)
{
int retry, st;
for (retry = 0; retry < 3; retry++)
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
sendMcdCmd(MCMD_PLAY_READ, arg);
st = getMcdStatus(200);
st = getMcdStatus(2 * MCD_STATUS_DELAY);
if (st != -1)
break;
}
......@@ -207,7 +224,7 @@ mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
case CDROMSTOP: /* Spin down the drive */
outb(MCMD_STOP, MCDPORT(0));
i = getMcdStatus(100);
i = getMcdStatus(MCD_STATUS_DELAY);
/* should we do anything if it fails? */
......@@ -219,7 +236,7 @@ mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
return -EINVAL;
outb(MCMD_STOP, MCDPORT(0));
i = getMcdStatus(100);
i = getMcdStatus(MCD_STATUS_DELAY);
if (GetQChannelInfo(&qInfo) < 0)
{
......@@ -291,7 +308,7 @@ printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
if (audioStatus == CDROM_AUDIO_PLAY) {
outb(MCMD_STOP, MCDPORT(0));
i = getMcdStatus(100);
i = getMcdStatus(MCD_STATUS_DELAY);
audioStatus = CDROM_AUDIO_NO_STATUS;
}
......@@ -439,7 +456,7 @@ printk("VOL %d %d\n", volctrl.channel0 & 0xFF, volctrl.channel1 & 0xFF);
outb(volctrl.channel1, MCDPORT(0));
outb(1, MCDPORT(0));
i = getMcdStatus(100);
i = getMcdStatus(MCD_STATUS_DELAY);
if (i < 0)
return -EIO;
......@@ -454,7 +471,7 @@ printk("VOL %d %d\n", volctrl.channel0 & 0xFF, volctrl.channel1 & 0xFF);
}
outb(0xF8, MCDPORT(0));
i = getMcdStatus(100);
i = getMcdStatus(MCD_STATUS_DELAY);
printk("F8 -> %02X\n", i & 0xFF);
#endif
return 0;
......@@ -547,7 +564,7 @@ do_mcd_request(void)
goto repeat;
}
McdTries = 3;
McdTries = MCD_RETRY_ATTEMPTS;
mcd_start();
}
......@@ -561,7 +578,7 @@ mcd_start()
{
if (McdTries == 0)
{
printk("mcd: read failed after 3 tries\n");
printk("mcd: read failed after %d tries\n", MCD_RETRY_ATTEMPTS);
end_request(0);
SET_TIMER(do_mcd_request, 1); /* wait a bit, try again */
return;
......@@ -569,7 +586,7 @@ mcd_start()
McdTries--;
outb(0x40, MCDPORT(0)); /* get status */
McdTimeout = 100;
McdTimeout = MCD_STATUS_DELAY;
SET_TIMER(mcd_status, 1);
}
......@@ -796,7 +813,14 @@ mcd_init(unsigned long mem_start, unsigned long mem_end)
if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
{
printk("Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR);
printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n",
MAJOR_NR);
return mem_start;
}
if (check_region(mcd_port, 4)) {
printk("mcd: Init failed, I/O port (%X) already in use\n",
mcd_port);
return mem_start;
}
......@@ -815,7 +839,8 @@ mcd_init(unsigned long mem_start, unsigned long mem_end)
break;
if (count >= 1000000) {
printk("mitsumi init failed...\n");
printk("mcd: Init failed. No mcd device at 0x%x irq %d\n",
mcd_port, mcd_irq);
return mem_start;
}
count = inb(MCDPORT(0)); /* pick up the status */
......@@ -823,11 +848,14 @@ mcd_init(unsigned long mem_start, unsigned long mem_end)
outb(MCMD_GET_VERSION,MCDPORT(0));
for(count=0;count<3;count++)
if(getValue(result+count)) {
printk("mitsumi get version failed...\n");
printk("mcd: mitsumi get version failed at 0x%d\n",
mcd_port);
return mem_start;
}
printk("Mitsumi version : %02X %c %x\n",result[0],result[1],result[2]);
printk("mcd: Mitsumi version : %02X %c %x\n",
result[0],result[1],result[2]);
mcdVersion=result[2];
......@@ -838,12 +866,13 @@ mcd_init(unsigned long mem_start, unsigned long mem_end)
if (irqaction(MCD_INTR_NR, &mcd_sigaction))
{
printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", MCD_INTR_NR);
printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", MCD_INTR_NR);
return mem_start;
}
snarf_region(mcd_port, 4);
mcdPresent = 1;
printk("Mitsumi CD-ROM Drive present\n");
printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n",
mcd_port, mcd_irq);
return mem_start;
}
......@@ -1018,14 +1047,14 @@ GetQChannelInfo(struct mcd_Toc *qp)
unsigned char notUsed;
int retry;
for (retry = 0; retry < 3; retry++)
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
if (getMcdStatus(100) != -1)
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
if (retry >= 3)
if (retry >= MCD_RETRY_ATTEMPTS)
return -1;
if (getValue(&qp -> ctrl_addr) < 0) return -1;
......@@ -1073,14 +1102,14 @@ GetDiskInfo()
{
int retry;
for (retry = 0; retry < 3; retry++)
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_GET_DISK_INFO, MCDPORT(0));
if (getMcdStatus(100) != -1)
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
if (retry >= 3)
if (retry >= MCD_RETRY_ATTEMPTS)
return -1;
if (getValue(&DiskInfo.first) < 0) return -1;
......@@ -1129,25 +1158,25 @@ GetToc()
i = DiskInfo.last + 3;
for (retry = 0; retry < 3; retry++)
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_STOP, MCDPORT(0));
if (getMcdStatus(100) != -1)
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
if (retry >= 3)
if (retry >= MCD_RETRY_ATTEMPTS)
return -1;
for (retry = 0; retry < 3; retry++)
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_SET_MODE, MCDPORT(0));
outb(0x05, MCDPORT(0)); /* mode: toc */
if (getMcdStatus(100) != -1)
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
if (retry >= 3)
if (retry >= MCD_RETRY_ATTEMPTS)
return -1;
for (limit = 300; limit > 0; limit--)
......@@ -1169,11 +1198,11 @@ GetToc()
Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
for (retry = 0; retry < 3; retry++)
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_SET_MODE, MCDPORT(0));
outb(0x01, MCDPORT(0));
if (getMcdStatus(100) != -1)
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
......
......@@ -260,9 +260,6 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
return 0;
}
/*
* This only works as the 386 is low-byte-first
*/
static int set_termio(struct tty_struct * tty, struct termio * termio,
int channel)
{
......@@ -270,18 +267,18 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
struct termio tmp_termio;
struct termios old_termios = *tty->termios;
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
i = check_change(tty, channel);
if (i)
return i;
for (i=0 ; i< (sizeof (*termio)) ; i++)
((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
memcpy_fromfs(&tmp_termio, termio, sizeof(*termio));
*(unsigned short *)&tty->termios->c_iflag = tmp_termio.c_iflag;
*(unsigned short *)&tty->termios->c_oflag = tmp_termio.c_oflag;
*(unsigned short *)&tty->termios->c_cflag = tmp_termio.c_cflag;
*(unsigned short *)&tty->termios->c_lflag = tmp_termio.c_lflag;
for(i=0 ; i < NCC ; i++)
tty->termios->c_cc[i] = tmp_termio.c_cc[i];
SET_LOW_BITS(tty->termios->c_iflag, tmp_termio.c_iflag);
SET_LOW_BITS(tty->termios->c_oflag, tmp_termio.c_oflag);
SET_LOW_BITS(tty->termios->c_cflag, tmp_termio.c_cflag);
SET_LOW_BITS(tty->termios->c_lflag, tmp_termio.c_lflag);
memcpy(tty->termios->c_cc, tmp_termio.c_cc, NCC);
/* see if packet mode change of state */
......
......@@ -14,7 +14,7 @@
*/
static char *version =
"smc-ultra.c:v0.03 11/21/93 Donald Becker (becker@super.org)\n";
"smc-ultra.c:v0.04 11/30/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
......@@ -70,7 +70,7 @@ int ultra_probe(struct device *dev)
for (port = &ports[0]; *port; port++) {
if (check_region(*port, 32))
continue;
if ((inb(*port + 7) & 0xF0) == 0x20
if ((inb(*port + 7) & 0xF0) == 0x20 /* Check chip ID nibble. */
&& ultraprobe1(*port, dev) == 0)
return 0;
}
......@@ -85,12 +85,8 @@ int ultraprobe1(int ioaddr, struct device *dev)
int checksum = 0;
char *model_name;
int num_pages;
unsigned char reg1, eeprom_irq = 0;
unsigned char eeprom_irq = 0;
/* Second probe check: at most one bit can be set in register 1. */
reg1 = inb(ioaddr + 1);
if (reg1 & (reg1 - 1))
return ENODEV;
/* Select the station address register set. */
outb(0x7f & inb(ioaddr + 4), ioaddr + 4);
......
Changelog for version 2.2b
-------------------------
Since 2.2
- Minor polishing.
- Interpreting of boot time arguments (sound=) for Linux.
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.
......@@ -5,7 +5,8 @@
#
#
VERSION = 2.0
VERSION = 2.2b
TARGET_OS = linux
USRINCDIR = /usr/include
.c.s:
......@@ -15,10 +16,10 @@ USRINCDIR = /usr/include
.c.o:
$(CC) $(CFLAGS) -c $<
OBJS = soundcard.o dsp.o audio.o dmabuf.o sb_dsp.o dev_table.o \
OBJS = soundcard.o audio.o dmabuf.o sb_dsp.o dev_table.o \
opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \
pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \
gus_midi.o gus_vol.o patmgr.o
gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o
all: local.h sound.a
......@@ -27,11 +28,16 @@ sound.a: $(OBJS)
$(AR) rcs sound.a $(OBJS)
sync
clean:
rm -f core core.* *.o *.a tmp_make *~ x z *%
rm -f configure Makefile sound_stub.c
for i in *.c;do rm -f `basename $$i .c`.s;done
indent:
for n in *.c;do echo indent $$n;indent $$n;done
local.h:
rm -f configure
$(MAKE) clean
$(MAKE) config
$(MAKE) dep
......@@ -43,9 +49,6 @@ config: configure
@echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h
@echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\" >> local.h
clrconf:
rm -f local.h .depend os.h soundcard.c
configure: configure.c
$(HOSTCC) -o configure configure.c
@cat .blurb
......
Release notes for the Linux Sound Driver 2.1
Release notes for the Linux Sound Driver 2.2b
-----------------------------------------------
This version is just version 2.0 with some kind of SB16
support. The SB16 works now in 8 bit mono mode up to speed
44100 Hz. Stereo recording and playback is not supported with
the SB16 yet. Also the 16 bit mode is missing.
In addition this has capability to read the configuration
parameters at boot time (only in the Linux version - See linux/Readme).
You will need the snd-util-2.0.tar.gz and snd-data-0.1.tar.Z
packages to use this driver. They should be in the same
......@@ -24,9 +26,8 @@ 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 but it doesn't.
The SoundBlaster 16 and SB 16 ASP cards are now supported
but just in 8 bit mono mode (up to 44.1 kHz).
NOTE! There are separate driver for CD-ROMS supported by
some soundcards. The driver for CDU31A (Fusion 16) is
......@@ -98,7 +99,7 @@ difference is in the installation procedure.
Using the driver under other environments than Linux
----------------------------------------------------
**** There is some ISC stuff in this driver. Please stay away ****
**** There is some ISC and SCO stuff in this driver. Please stay away ****
This stuff is here just because I want to be in sync with the porters. This
ports don't work yet.
The ISC port is by Andy Warner (andy@harris.nl).
......@@ -113,49 +114,10 @@ In addition I'm preparing a SCO port myself. Yet again, these ports
are little incomplete and untested. It could be possible to get them to work
with finite amount of hacking but be careful.
New features
/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
NOTE! This device file is available only for Linux at this time.
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
......@@ -194,12 +156,9 @@ 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 *
- 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
......@@ -212,9 +171,6 @@ Known bugs
^C and playing again should solve this problem. This is propably caused by
incompatibilities between GUS and certain VLB motherboards. 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.
- There is a skeleton of the patch manager support. It don't work in
this version.
......@@ -222,12 +178,12 @@ Known bugs
Future development
------------------
- The SB16 card should be fully supported some day. The SDK for it is
not available yet so it's not possible to implement the 16 bit mode yet.
- The SB16 card should be fully supported some day. I have the SDK for it
now so it should not take infinite time to implement it.
- 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 year (alpha version).
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.
......@@ -270,3 +226,242 @@ Snail mail: Hannu Savolainen
Pallaksentie 4 A 2
00970 Helsinki
Finland
---------- linux/Readme:
Sound Card Driver version 2.2
This directory contains the driver for various PC soundcards.
The following cards are supported:
AdLib
SoundBlaster (1.0-2.0) and compatibles, including
ThunderBoard and Ati Stereo F/X.
SoundBlaster Pro and SB Pro 2
SoundBlaster 16 (8 bit mono only)
ProAudioSpectrum 16
(The original ProAudioSpectrum and the PAS+ are not supported
(and propably will remain unsupported)).
If you have any problems, please contact me.
Installation
------------
- Since this driver is a part of the Linux kernel distribution, no
special steps are required to build the driver itself.
- To build the device files you need to run the enclosed shell scrip
(see below).
- Copy the sound/ultrasound.h and sound/soundcard.h to /usr/include/sys.
(Remove the old ones from /usr/include/sys /usr/include/linux first).
Boot time configuration (using lilo)
------------------------------------
This version of the sound driver has capability to accept the configuration
parameters from the boot loader (for example lilo). By default the
driver is booted using the parameters given before compiling the driver
('make config' or 'make soundconf'). If the kernel is booted using lilo and
the boot command is given manually, it's possible to give the configuration
parameters on the command line. Just hold down the <Alt> key when lilo
starts. Then give the boot command manually and append a sound= argument
to the boot command line. For example:
lilo boot: linux sound=0x222071,0x138800
The sound= argument could contain several configuration entries separated by a
comma. Each option gives the configuration for one sound device.
Give the options in the order given below. Other order of use is undefined.
Each option is encoded as the following:
0xTaaaId, where
|| ||
|| |+---- d = DMA channel (0, 1, 3, 5, 6 or 7)
|| +----- I = IRQ (HEXADECIMAL!!! 1=1, ..., 9=9, 10=a, ..., 15=f)
|+-------- aaa = I/O address (hexadecimal)
+---------- T = device type 1=FM Synth (YM3812 or OPL3)
2=SoundBlaster (1.0 to 2.0, Pro, 16)
3=ProAudioSpectrum16
4=Gravis UltraSound
5=MPU-401 UART midi
These are the configuration templates for various soundcards:
0) Disable the sound driver
sound=0
1) AdLib
sound=0x138800
2) SoundBlaster family and compatibles
sound=0x2220Id,0x138800 (remember to set the IRQ and DMA)
3) ProAudioSpectrum16, ProAudioStudio16, Logitech Soundman16 etc.
sound=0x3388Id,0x2220Id,0x138800 (set the DMAs and IRQs)
4) Gravis UltraSound
sound=0x42X0Id (X is 1, 2, 3 or 4. Set the DMA and IRQ)
5) MPU-401
sound=0x5aaaI0
If you have more than one soundcards, you have to concatenate the options
for each of the cards. There cannot be more than one sound= argument in the
command line. For example use "sound=0x5aaaI0,0x138800" if you have AdLib
and MPU-401 on your system.
If there are two or more sound= arguments
in the boot command line, just the last one takes effect. The earlier ones
will be ignored silently.
The boot time configuration feature is intended mainly for distributors of
precompiled kernels. When this feature is used, drivers for all of the
cards have to be enabled before compiling the driver. The configurator program
doesn't enable MPU-401 when the full driver option is selected. It must be
enabled by uncommenting "#define EXCLUDE_MPU401" in the sound/local.h.
Important note!
The sound driver is enabled by default. If the kernel is booted without
using the sound=0 option, the sound driver is initialized using the compile
time parameters. This could be dangerous (specially if the MPU-401 driver
is enabled with I/O address 0x330 (used by AHA-1542 also)). If you want to
compile the driver to be inactive by default, you have to append a
#define SND_DEFAULT_ENABLE 0
to the sound/local.h before compiling the driver.
Remember to check that the sound setup routine is included in the
bootparams structure in linux/init/main.c. It should contain the following
lines:
#ifdef CONFIG_SOUND
{ "sound=", sound_setup },
#endif
In case these lines were not there, you have to insert them (the driver works
without them but it's not possible to give the boot time parameters for the
sound driver). Add also the following line somewhere near the beginning of
linux/init/main.c:
extern void sound_setup(char *str, int *ints);
Problems
--------
If you have any kind of problems, there is a debugging feature which
could help you to solve the problem. To use it, just execute the
command:
cat /dev/sndstat
and look at the output. It should display some usefull info about the
driver configuration. If there is no /dev/sndstat
(/dev/sndstat: No such file or directory), ensure that you have executed the
soundinstall script (at the end of this file). The message:
/dev/dsp: No such device means that you don't have the sound driver installed
on your kernel or the driver version is earlier than 1.99.6.
- /dev/???????: No such file or directory.
Run the script at the end of this file.
- /dev/???????: No such device.
You have not booted with a kernel containing the driver or the I/O address
configuration doesn't match your hardaware.
- The module player (str) plays just a second and then stops completely.
You have incorrect IRQ settings (usual with SB cards).
- There is pauses in the playback of the module player (str).
The str program requires more than 40% of the speed of a 486/50 to play
without pauses at 44 kHz speed. A 386/25 can hardly play faster than 22 kHz.
You should use lower speed (-s speed), buy a faster computer or a Gravis
UltraSound card. (If you already have GUS, you should use gmod and not the
str). If the DSP_BUFFSIZE in the sound/local.h is less than (nr_channels*
speed_in_Hz * (bits/8))/2, it could explain the pausing problem. Also check
that the turbo swich is on and don't run applications like weather forecasting
on background. Sometimes (very rarely) an IRQ conflict can cause similar
problems with SB cards.
If you want to play modules on a 386sx while recompiling the world, buy a GUS.
It runs without burning your CPU.
Hannu Savolainen
hsavolai@cs.helsinki.fi
----------------- cut here ------------------------------
#!/bin/sh
#
# soudinstall
#
# by Craig Metz - cmetz@thor.tjhsst.edu
#
# Create the devices
#
# Mixer (14, 0)
#
if [ -e /dev/mixer ]; then
rm -f /dev/mixer
fi
mknod -m 666 /dev/mixer c 14 0
#
# Sequencer (14, 1)
#
if [ -e /dev/sequencer ]; then
rm -f /dev/sequencer
fi
mknod -m 666 /dev/sequencer c 14 1
#
# MIDI (14, 2) [ Not implemented ]
#
if [ -e /dev/midi ]; then
rm -f /dev/midi
fi
mknod -m 666 /dev/midi c 14 2
#
# DSP (14, 3)
#
if [ -e /dev/dsp ]; then
rm -f /dev/dsp
fi
mknod -m 666 /dev/dsp c 14 3
#
# SPARC audio (14, 4) [ Not fully implemented ]
#
if [ -e /dev/audio ]; then
rm -f /dev/audio
fi
mknod -m 666 /dev/audio c 14 4
#
# DSP2 (14, 19) /dev/dsp for the second soundcard.
# Also the SB emulation part of the
# PAS16 card.
#
if [ -e /dev/dsp1 ]; then
rm -f /dev/dsp1
fi
mknod -m 666 /dev/dsp1 c 14 19
#
# SPARC audio1 (14, 20) [ Not fully implemented ]
# /dev/audio for the second soundcard.
# Also the SB emulation part of the
# PAS16 card.
#
if [ -e /dev/audio1 ]; then
rm -f /dev/audio1
fi
mknod -m 666 /dev/audio1 c 14 20
#
# /dev/sndstat (14,6) For debugging purposes
#
if [ -e /dev/sndstat ]; then
rm -f /dev/sndstat
fi
mknod -m 666 /dev/sndstat c 14 6
exit 0
......@@ -40,21 +40,41 @@
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;
}
......@@ -106,12 +126,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 +164,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]);
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");
#endif
translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
}
c -= l;
p += l;
......@@ -169,11 +207,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 +234,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");
#endif
translate_bytes (dsp_ulaw, dmabuf, l);
}
COPY_TO_USER (buf, p, dmabuf, l);
......@@ -205,6 +260,7 @@ 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 +291,10 @@ audio_ioctl (int dev, struct fileinfo *file,
break;
default:
#if 1
if (dev_type == SND_DEV_AUDIO)
return RET_ERROR (EIO);
#else
return DMAbuf_ioctl (dev, cmd, arg, 0);
#endif
}
}
......
......@@ -43,17 +43,18 @@
#define OPT_HIGHLEVEL 5
#define OPT_SBPRO 5
#define OPT_AUDIO 6
#define OPT_MIDI_AUTO 7
#define OPT_MIDI 8
#define OPT_YM3812_AUTO 9 /* Select this automaticly if user selects
#define OPT_SB16 6
#define OPT_AUDIO 7
#define OPT_MIDI_AUTO 8
#define OPT_MIDI 9
#define OPT_YM3812_AUTO 10 /* Select this automaticly if user selects
* MIDI or AdLib driver */
#define OPT_YM3812 10 /* Select this if the previous one was not
#define OPT_YM3812 11 /* Select this if the previous one was not
* selected */
#define OPT_SEQUENCER 11
#define OPT_CHIP_MIDI 12 /* New support added at UW - Milwauklee UW -
#define OPT_SEQUENCER 12
#define OPT_CHIP_MIDI 13 /* New support added at UW - Milwauklee UW -
* Milwauklee */
#define OPT_LAST 11
#define OPT_LAST 12
#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)|B(OPT_MPU401))
......@@ -94,6 +95,7 @@ hw_entry hw_table[] =
{0, 0, "GUS", 1, 0},
{0, 0, "MPU401", 1, 0},
{B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0},
{B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0},
{B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0},
{B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI},
{B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0},
......@@ -112,7 +114,8 @@ char *questions[] =
"Gravis Ultrasound support",
"MPU-401 support",
"SoundBlaster Pro support (mixer)",
"SoundBlaster Pro support (required for SB16 also)",
"SoundBlaster 16 support",
"digitized voice support",
"This should not be asked",
"MIDI interface support",
......@@ -327,11 +330,12 @@ main (int argc, char *argv[])
fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
"For SB 1.0, 1.5 and 2.0 this MUST be 1\n"
"SB Pro supports DMA channels 0, 1 and 3 (jumper)\n"
"For SB16 give the 8 bit DMA# here\n"
"The default value is 1\n"
"Enter the value: ");
num = ask_value ("%d", 1);
if (num < 0 || num > 7 || num == 4)
if (num < 0 || num > 3)
{
fprintf (stderr, "*** Illegal input! ***\n");
......@@ -340,6 +344,25 @@ main (int argc, char *argv[])
fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
printf ("#define SBC_DMA %d\n", num);
}
if (selected_options & B (OPT_SB16))
{
fprintf (stderr, "\n16 bit DMA channel for SoundBlaster 16?\n"
"Possible values are 5, 6 or 7\n"
"The default value is 6\n"
"Enter the value: ");
num = ask_value ("%d", 6);
if (num < 5 || num > 7)
{
fprintf (stderr, "*** Illegal input! ***\n");
num = 6;
}
fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
printf ("#define SB16_DMA %d\n", num);
}
}
if (selected_options & B (OPT_PAS))
......
......@@ -38,6 +38,7 @@ 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].enabled)
if (supported_drivers[i].probe (&supported_drivers[i].config))
{
#ifndef SHORT_BANNERS
......@@ -100,4 +101,72 @@ sndtable_get_cardcount (void)
return num_dspdevs + num_mixers + num_synths + num_midis;
}
void sound_setup(char *str, int *ints)
{
int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
printk("sound_setup(%d) called\n", ints[0]);
/*
* 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;
}
}
}
struct address_info *sound_getconf(int card_type)
{
int j, ptr;
int n = sizeof (supported_drivers) / sizeof (struct card_info);
ptr = -1;
for (j=0;j<n && ptr == -1;j++)
if (supported_drivers[j].card_type == card_type)
ptr = j;
if (ptr == -1) return (struct address_info *)NULL;
return &supported_drivers[ptr].config;
}
#endif
......@@ -46,6 +46,7 @@ struct card_info {
long (*attach) (long mem_start, struct address_info *hw_config);
int (*probe) (struct address_info *hw_config);
struct address_info config;
int enabled;
};
/** UWM -- new MIDI structure here.. **/
......@@ -59,8 +60,10 @@ struct audio_operations {
char name[32];
int (*open) (int dev, int mode);
void (*close) (int dev);
void (*output_block) (int dev, unsigned long buf, int count, int intrflag);
void (*start_input) (int dev, unsigned long buf, int count, int intrflag);
void (*output_block) (int dev, unsigned long buf,
int count, int intrflag, int dma_restart);
void (*start_input) (int dev, unsigned long buf,
int count, int intrflag, int dma_restart);
int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local);
int (*prepare_for_input) (int dev, int bufsize, int nbufs);
int (*prepare_for_output) (int dev, int bufsize, int nbufs);
......@@ -159,31 +162,36 @@ 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}},
{MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
#endif
#ifndef EXCLUDE_GUS
{SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus,
{GUS_BASE, GUS_IRQ, GUS_DMA}},
{GUS_BASE, GUS_IRQ, GUS_DMA}, 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) && !defined(EXCLUDE_AUDIO)
{SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect,
{SBC_BASE, SBC_IRQ, SB16_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 +228,7 @@ 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);
#endif
#endif
......
......@@ -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]);
......@@ -73,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];
......@@ -88,10 +90,10 @@ static int bufferalloc_done[MAX_DSP_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] =
{
{NULL}};
{{NULL}};
static int dev_buffsize[MAX_DSP_DEV];
static void
......@@ -110,7 +112,8 @@ reorganize_buffers (int dev)
if (sr < 1 || nc < 1 || sz < 1)
{
printk ("SOUND: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);
printk ("SOUND: Invalid PCM parameters[%d] sr=%lu, nc=%lu, sz=%lu\n",
dev, sr, nc, sz);
sr = DSP_DEFAULT_SPEED;
nc = 1;
sz = 8;
......@@ -132,6 +135,16 @@ 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;
......@@ -162,6 +175,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)
{
......@@ -188,15 +216,13 @@ DMAbuf_open (int dev, int mode)
if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)
return retval;
RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
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;
}
......@@ -204,12 +230,19 @@ DMAbuf_open (int dev, int mode)
static void
dma_reset (int dev)
{
int retval;
unsigned long flags;
DISABLE_INTR(flags);
dsp_devs[dev]->reset (dev);
dsp_devs[dev]->close (dev);
dev_qlen[dev] = 0;
dev_qhead[dev] = 0;
dev_qtail[dev] = 0;
dev_active[dev] = 0;
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
......@@ -267,9 +300,8 @@ DMAbuf_release (int dev, int mode)
dma_sync (dev);
}
dma_reset (dev);
dsp_devs[dev]->reset (dev);
if (!dev_active[dev])
dsp_devs[dev]->close (dev);
dma_mode[dev] = DMODE_NONE;
......@@ -282,6 +314,14 @@ int
DMAbuf_getrdbuffer (int dev, char **buf, int *len)
{
unsigned long flags;
int err = EIO;
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);
......@@ -296,25 +336,39 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len)
dma_mode[dev] = DMODE_INPUT;
}
if (dma_mode[dev] != DMODE_INPUT)
return RET_ERROR (EBUSY); /* Can't change mode on fly */
DISABLE_INTR (flags);
if (!dev_qlen[dev])
{
if (dev_needs_restart[dev])
{
dma_reset(dev);
}
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 */
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\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]];
......@@ -376,6 +430,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;
......@@ -386,6 +441,30 @@ 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);
}
......@@ -399,6 +478,20 @@ 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);
......@@ -412,8 +505,6 @@ 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);
......@@ -461,12 +552,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;
......@@ -516,7 +612,7 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
| DMAMODE_AUTO
#endif
,
snd_raw_buf_phys[dev][0], count /* - 1 ???? */ );
snd_raw_buf_phys[dev][0], count);
dma_enable (chan);
#else
# error This routine is not valid for this OS.
......@@ -583,30 +679,27 @@ 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
{
if (dev_busy[dev])
if (underrun_flag)
{
dev_underrun[dev]++;
dsp_devs[dev]->halt_xfer (dev);
}
else
{ /* Device has been closed */
dsp_devs[dev]->close (dev);
}
dev_needs_restart[dev] = 1;
}
DISABLE_INTR (flags);
......@@ -622,7 +715,6 @@ DMAbuf_inputintr (int dev)
{
unsigned long flags;
dev_active[dev] = 0;
if (!dev_busy[dev])
{
dsp_devs[dev]->close (dev);
......@@ -631,13 +723,17 @@ DMAbuf_inputintr (int dev)
{
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;
}
......@@ -781,7 +877,7 @@ DMAbuf_inputintr (int dev)
}
void
DMAbuf_outputintr (int dev)
DMAbuf_outputintr (int dev, int underrun_flag)
{
return;
}
......
/*
* linux/kernel/chr_drv/sound/dsp.c
*
* Device file manager for /dev/dsp
*
* Copyright by Hannu Savolainen 1993
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. 2.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include "sound_config.h"
#ifdef CONFIGURE_SOUNDCARD
#ifndef EXCLUDE_AUDIO
#define ON 1
#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_buf_ptr[MAX_DSP_DEV];
static char *wr_dma_buf[MAX_DSP_DEV];
int
dsp_open (int dev, struct fileinfo *file, int bits)
{
int mode;
int ret;
dev = dev >> 4;
mode = file->mode & O_ACCMODE;
if ((ret = DMAbuf_open (dev, mode)) < 0)
return ret;
if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
{
dsp_release (dev, file);
return RET_ERROR (ENXIO);
}
wr_buff_no[dev] = -1;
return ret;
}
void
dsp_release (int dev, struct fileinfo *file)
{
int mode;
dev = dev >> 4;
mode = file->mode & O_ACCMODE;
if (wr_buff_no[dev] >= 0)
{
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
wr_buff_no[dev] = -1;
}
DMAbuf_release (dev, mode);
}
int
dsp_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
int c, p, l;
int err;
dev = dev >> 4;
p = 0;
c = count;
if (!count) /* Flush output */
{
if (wr_buff_no[dev] >= 0)
{
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
wr_buff_no[dev] = -1;
}
return 0;
}
while (c)
{ /* Perform output blocking */
if (wr_buff_no[dev] < 0) /* There is no incomplete buffers */
{
if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev],
&wr_buff_size[dev])) < 0)
return wr_buff_no[dev];
wr_buf_ptr[dev] = 0;
}
l = c;
if (l > (wr_buff_size[dev] - wr_buf_ptr[dev]))
l = (wr_buff_size[dev] - wr_buf_ptr[dev]);
if (!dsp_devs[dev]->copy_from_user)
{ /* No device specific copy routine */
COPY_FROM_USER (&wr_dma_buf[dev][wr_buf_ptr[dev]], buf, p, l);
}
else
dsp_devs[dev]->copy_from_user (dev,
wr_dma_buf[dev], wr_buf_ptr[dev], buf, p, l);
c -= l;
p += l;
wr_buf_ptr[dev] += l;
if (wr_buf_ptr[dev] >= wr_buff_size[dev])
{
if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev])) < 0)
return err;
wr_buff_no[dev] = -1;
}
}
return count;
}
int
dsp_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
int c, p, l;
char *dmabuf;
int buff_no;
dev = dev >> 4;
p = 0;
c = count;
while (c)
{
if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
return buff_no;
if (l > c)
l = c;
/* Insert any local processing here. */
COPY_TO_USER (buf, 0, dmabuf, l);
DMAbuf_rmchars (dev, buff_no, l);
p += l;
c -= l;
}
return count - c;
}
int
dsp_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, unsigned int arg)
{
dev = dev >> 4;
switch (cmd)
{
case SNDCTL_DSP_SYNC:
if (wr_buff_no[dev] >= 0)
{
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
wr_buff_no[dev] = -1;
}
return DMAbuf_ioctl (dev, cmd, arg, 0);
break;
case SNDCTL_DSP_POST:
if (wr_buff_no[dev] >= 0)
{
DMAbuf_start_output (dev, wr_buff_no[dev], wr_buf_ptr[dev]);
wr_buff_no[dev] = -1;
}
return 0;
break;
case SNDCTL_DSP_RESET:
wr_buff_no[dev] = -1;
return DMAbuf_ioctl (dev, cmd, arg, 0);
break;
default:
return DMAbuf_ioctl (dev, cmd, arg, 0);
}
}
long
dsp_init (long mem_start)
{
return mem_start;
}
#else
/* Stub version */
int
dsp_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
return RET_ERROR (EIO);
}
int
dsp_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
{
return RET_ERROR (EIO);
}
int
dsp_open (int dev, struct fileinfo *file, int bits)
{
return RET_ERROR (ENXIO);
}
void
dsp_release (int dev, struct fileinfo *file)
{
};
int
dsp_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, unsigned int arg)
{
return RET_ERROR (EIO);
}
int
dsp_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
{
return RET_ERROR (EIO);
}
long
dsp_init (long mem_start)
{
return mem_start;
}
#endif
#endif
......@@ -37,76 +37,12 @@ void gusintr (int);
int gus_base, gus_irq, gus_dma;
static int
set_gus_irq (int interrupt_level)
{
int retcode;
#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;
#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 */
{
......
......@@ -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,
......
......@@ -105,7 +105,8 @@ DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
/*
* Variables and buffers for PCM output
*/
#define MAX_PCM_BUFFERS 32 /* Don't change */
#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /* Don't change */
static int pcm_bsize, /* Current blocksize */
pcm_nblk, /* Current # of blocks */
pcm_banksize; /* # bytes allocated for channels */
......@@ -667,9 +668,6 @@ gus_initialize (void)
*
* The GUS supports two IRQs and two DMAs.
*
* If GUS_MIDI_IRQ is defined and if it's != GUS_IRQ, separate Midi IRQ is set
* up. Otherwise the same IRQ is shared by the both devices.
*
* Just one DMA channel is used. This prevents simultaneous ADC and DAC.
* Adding this support requires significant changes to the dmabuf.c, dsp.c
* and audio.c also.
......@@ -680,20 +678,6 @@ gus_initialize (void)
if (!tmp)
printk ("Warning! GUS IRQ not selected\n");
irq_image |= tmp;
if (GUS_MIDI_IRQ != gus_irq)
{ /* The midi irq was defined and != wave irq */
tmp = gus_irq_map[GUS_MIDI_IRQ];
tmp <<= 3;
if (!tmp)
printk ("Warning! GUS Midi IRQ not selected\n");
else
gus_set_midi_irq (GUS_MIDI_IRQ);
irq_image |= tmp;
}
else
irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
......@@ -1325,14 +1309,14 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
if (count < patch.len)
{
printk ("GUS Warning: Patch record too short (%d<%d)\n",
printk ("GUS Warning: Patch record too short (%d<%lu)\n",
count, patch.len);
patch.len = count;
}
if (patch.len <= 0 || patch.len > gus_mem_size)
{
printk ("GUS: Invalid sample length %d\n", patch.len);
printk ("GUS: Invalid sample length %lu\n", patch.len);
return RET_ERROR (EINVAL);
}
......@@ -1362,7 +1346,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
*/
if (patch.len >= GUS_BANK_SIZE)
{
printk ("GUS: Sample (16 bit) too long %d\n", patch.len);
printk ("GUS: Sample (16 bit) too long %lu\n", patch.len);
return RET_ERROR (ENOSPC);
}
......@@ -1424,7 +1408,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
blk_size = blk_end - target;
}
#ifdef GUS_NO_DMA
#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
/*
* For some reason the DMA is not possible. We have to use PIO.
*/
......@@ -1435,6 +1419,10 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr,
for (i = 0; i < blk_size; i++)
{
GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
if (patch.mode & WAVE_UNSIGNED)
if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
data ^= 0x80; /* Convert to signed */
gus_poke (target + i, data);
}
}
......@@ -1717,6 +1705,7 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
break;
case SOUND_PCM_WRITE_CHANNELS:
if (local) return gus_sampling_set_channels(arg);
return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg)));
break;
......@@ -1774,9 +1763,6 @@ gus_sampling_open (int dev, int mode)
reset_sample_memory ();
gus_select_max_voices (14);
gus_sampling_set_bits (8);
gus_sampling_set_channels (1);
gus_sampling_set_speed (DSP_DEFAULT_SPEED);
pcm_active = 0;
return 0;
......@@ -1987,7 +1973,8 @@ gus_transfer_output_block (int dev, unsigned long buf,
}
static void
gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intrflag)
gus_sampling_output_block (int dev, unsigned long buf, int total_count,
int intrflag, int restart_dma)
{
pcm_current_buf = buf;
pcm_current_count = total_count;
......@@ -1997,7 +1984,8 @@ gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intr
}
static void
gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag)
gus_sampling_start_input (int dev, unsigned long buf, int count,
int intrflag, int restart_dma)
{
unsigned long flags;
unsigned char mode;
......@@ -2329,7 +2317,7 @@ static struct synth_operations guswave_operations =
long
gus_wave_init (long mem_start, int irq, int dma)
{
printk (" <Gravis UltraSound %dk>", gus_mem_size / 1024);
printk (" <Gravis UltraSound %luk>", gus_mem_size / 1024);
if (irq < 0 || irq > 15)
{
......@@ -2426,7 +2414,7 @@ do_loop_irq (int voice)
if (orig_qlen == pcm_nblk)
{
DMAbuf_outputintr (gus_devnum);
DMAbuf_outputintr (gus_devnum, 0);
}
}
break;
......@@ -2530,7 +2518,7 @@ guswave_dma_irq (void)
case GUS_DEV_PCM_DONE:
if (pcm_qlen < pcm_nblk)
{
DMAbuf_outputintr (gus_devnum);
DMAbuf_outputintr (gus_devnum, pcm_qlen == 0);
}
break;
......
......@@ -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 */
......@@ -100,8 +100,7 @@ poll_mpu401 (unsigned long dummy)
{
unsigned long flags;
static struct timer_list mpu401_timer =
{NULL, 0, 0, poll_mpu401};
DEFINE_TIMER(mpu401_timer, poll_mpu401);
if (!(mpu401_opened & OPEN_READ))
return; /* No longer required */
......@@ -111,44 +110,11 @@ poll_mpu401 (unsigned long dummy)
if (input_avail ())
mpu401_input_loop ();
mpu401_timer.expires = 1;
add_timer (&mpu401_timer); /* Come back later */
ACTIVATE_TIMER(mpu401_timer, poll_mpu401, 1); /* Come back later */
RESTORE_INTR (flags);
}
static int
set_mpu401_irq (int interrupt_level)
{
int retcode;
#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),
......@@ -247,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,
......@@ -299,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;
......@@ -341,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 ();
......
......@@ -87,7 +87,7 @@ struct snd_wait {
#define DO_SLEEP(q, f, time_limit) \
{ unsigned long tl;\
if (time_limit) tl = current->timeout = jiffies + (time_limit); \
else tl = 0; \
else tl = 0xffffffff; \
f.mode = WK_SLEEP;interruptible_sleep_on(&q); \
if (!(f.mode & WK_WAKEUP)) \
{ \
......@@ -128,5 +128,23 @@ struct snd_wait {
#define KERNEL_MALLOC(nbytes) kmalloc(nbytes, GFP_KERNEL)
#define KERNEL_FREE(addr) kfree(addr)
/*
* 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) \
static struct timer_list name = \
{NULL, 0, 0, proc}
/*
* The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
*/
#define ACTIVATE_TIMER(name, proc, time) \
{name.expires = time; \
add_timer (&name);}
#define INB inb
#define OUTB outb
......@@ -141,11 +141,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 */
......
......@@ -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 */
......@@ -100,38 +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 */
#endif
}
int
pas_set_intr (int mask)
{
......@@ -142,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;
......@@ -162,7 +130,7 @@ pas_remove_intr (int mask)
if (!pas_intr_mask)
{
RELEASE_IRQ (pas_irq);
snd_release_irq (pas_irq);
}
return 0;
}
......@@ -229,13 +197,21 @@ 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
......@@ -252,13 +228,35 @@ config_pas_hw (struct address_info *hw_config)
#if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
{
struct address_info *sb_config;
if ((sb_config=sound_getconf(SNDCARD_SB)))
{
unsigned char irq_dma;
/* Turn on Sound Blaster compatibility */
/* bit 1 = SB emulation */
/* bit 0 = MPU401 emulation (CDPC only :-( ) */
pas_write (0x02, COMPATIBILITY_ENABLE);
/* "Emulation address" */
pas_write ((SBC_BASE >> 4) & 0x0f, 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)
......@@ -304,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;
}
......@@ -349,7 +347,6 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
}
}
printk ("\n");
return mem_start;
}
......
......@@ -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,
......
......@@ -200,12 +200,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 +211,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 +232,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 +242,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 +253,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);
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 +278,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 +289,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 +297,12 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag)
DISABLE_INTR (flags);
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 +363,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 +376,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 +408,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:
......
#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
/* Sorry! */
#include "sound_config.h"
void
sb16_dsp_interrupt (int unused)
{
}
long sb16_dsp_init(long mem_start, struct address_info *hw_config)
{
return mem_start;
}
int sb16_dsp_detect(struct address_info *hw_config)
{
return 0;
}
/*
* linux/kernel/chr_drv/sound/sb_dsp.c
* sound/sb_dsp.c
*
* The low level driver for the SoundBlaster DS chips.
*
......@@ -25,152 +25,74 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The mixer support is based on the SB-BSD 1.5 driver by (C) Steve Haehnichen
* <shaehnic@ucsd.edu>
*/
#include "sound_config.h"
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
#include "sb.h"
#include "sb_mixer.h"
#undef SB_TEST_IRQ
#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 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)
static int sbc_base = 0;
int sbc_base = 0;
static int sbc_irq = 0;
#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD | SOUND_MASK_VOLUME)
/*
* Mixer registers
*
* NOTE! RECORD_SRC == IN_FILTER
*/
#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 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)
/* Convenient byte masks */
#define B1(x) ((x) & 0x01)
#define B2(x) ((x) & 0x03)
#define B3(x) ((x) & 0x07)
#define B4(x) ((x) & 0x0f)
#define B5(x) ((x) & 0x1f)
#define B6(x) ((x) & 0x3f)
#define B7(x) ((x) & 0x7f)
#define B8(x) ((x) & 0xff)
#define F(x) (!!(x)) /* 0 or 1 only */
#define MONO_DAC 0x00
#define STEREO_DAC 0x02
/* DSP Commands */
#define DSP_CMD_SPKON 0xD1
#define DSP_CMD_SPKOFF 0xD3
/*
* The DSP channel can be used either for input or output. Variable
* 'irq_mode' will be set when the program calls read or write first time
* '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.
*/
#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
static int sb_dsp_ok = 0; /* Set to 1 after successful initialization */
int sb_dsp_ok = 0; /* Set to 1 after successful initialization */
static int midi_disabled = 0;
static int dsp_highspeed = 0, dsp_stereo = 0;
int sb_dsp_highspeed = 0;
static int major=1, minor=0; /* DSP version */
static int dsp_stereo = 0;
static int dsp_current_speed = DSP_DEFAULT_SPEED;
static int sb16 = 0;
static int irq_verified = 0;
#ifndef EXCLUDE_SBPRO
static int rec_devices = SOUND_MASK_MIC;
static int hi_filter = 0, filter_in = 0, filter_out = 0;
#endif
static int midi_mode = NORMAL_MIDI;
static int midi_busy = 0; /* 1 if the process has output to MIDI */
static int dsp_busy = 0;
int sb_midi_mode = NORMAL_MIDI;
int sb_midi_busy = 0; /* 1 if the process has output to MIDI */
int sb_dsp_busy = 0;
static volatile int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT
volatile int sb_irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT
* or IMODE_NONE */
static volatile int irq_ok = 0;
static int dsp_model = 1; /* 1=SB, 2=SB Pro */
static int duplex_midi = 0;
int sb_dsp_model = 1; /* 1=SB, 2=SB Pro */
int sb_duplex_midi = 0;
static int my_dev = 0;
static volatile int intr_active = 0;
volatile int sb_intr_active = 0;
static int dsp_speed (int);
static int dsp_set_stereo (int mode);
static int dsp_command (unsigned char val);
#ifndef EXCLUDE_SBPRO
static void setmixer (unsigned char port, unsigned char value);
static int getmixer (unsigned char port);
static void init_mixer (void);
static int detect_mixer (void);
#endif
int sb_dsp_command (unsigned char val);
#if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
/* Common code for the midi and pcm functions */
static int
dsp_command (unsigned char val)
int
sb_dsp_command (unsigned char val)
{
int i, limit;
limit = GET_TIME () + 10; /* The timeout is 0.1 secods */
/*
* Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
* Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
* called while interrupts are disabled. This means that the timer is
* disabled also. However the timeout situation is a abnormal condition.
* Normally the DSP should be ready to accept commands after just couple of
* loops.
*/
for (i = 0; i < 5000000 && GET_TIME () < limit; i++)
for (i = 0; i < 500000 && GET_TIME () < limit; i++)
{
if ((INB (DSP_STATUS) & 0x80) == 0)
{
......@@ -185,14 +107,19 @@ dsp_command (unsigned char val)
}
void
sbintr (int unused)
sbintr (int unit)
{
int status, data;
#ifndef EXCLUDE_SBPRO
if (sb16)
{
unsigned char src = getmixer (0x82); /* Interrupt status register */
unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt status register */
#ifndef EXCLUDE_SB16
if (src & 2) sb16_dsp_interrupt(unit);
#endif
if (!(src & 1))
return; /* Not a DSP interupt */
......@@ -201,22 +128,22 @@ sbintr (int unused)
status = INB (DSP_DATA_AVAIL);/* Clear interrupt */
if (intr_active)
switch (irq_mode)
if (sb_intr_active)
switch (sb_irq_mode)
{
case IMODE_OUTPUT:
intr_active = 0;
DMAbuf_outputintr (my_dev);
sb_intr_active = 0;
DMAbuf_outputintr (my_dev, 1);
break;
case IMODE_INPUT:
intr_active = 0;
sb_intr_active = 0;
DMAbuf_inputintr (my_dev);
/* A complete buffer has been input. Let's start new one */
break;
case IMODE_INIT:
intr_active = 0;
sb_intr_active = 0;
irq_ok = 1;
break;
......@@ -232,40 +159,33 @@ sbintr (int unused)
}
}
static int
set_dsp_irq (int interrupt_level)
{
int retcode;
static int sb_irq_usecount = 0;
#ifdef linux
struct sigaction sa;
int
sb_get_irq(void)
{
int ok;
sa.sa_handler = sbintr;
if (!sb_irq_usecount)
if ((ok=snd_set_irq_handler(sbc_irq, sbintr))<0) return ok;
#ifdef SND_SA_INTERRUPT
sa.sa_flags = SA_INTERRUPT;
#else
sa.sa_flags = 0;
#endif
sb_irq_usecount++;
sa.sa_mask = 0;
sa.sa_restorer = NULL;
return 0;
}
retcode = irqaction (interrupt_level, &sa);
void
sb_free_irq(void)
{
if (!sb_irq_usecount) return;
if (retcode < 0)
{
printk ("SoundBlaster: IRQ%d already in use\n", interrupt_level);
}
sb_irq_usecount--;
#else
/* # error Unimplemented for this OS */
#endif
return retcode;
if (!sb_irq_usecount) snd_release_irq(sbc_irq);
}
static int
reset_dsp (void)
int
sb_reset_dsp (void)
{
int loopc;
......@@ -293,9 +213,9 @@ static void
dsp_speaker (char state)
{
if (state)
dsp_command (DSP_CMD_SPKON);
sb_dsp_command (DSP_CMD_SPKON);
else
dsp_command (DSP_CMD_SPKOFF);
sb_dsp_command (DSP_CMD_SPKOFF);
}
static int
......@@ -304,14 +224,13 @@ dsp_speed (int speed)
unsigned char tconst;
unsigned long flags;
if (speed < 4000)
speed = 4000;
if (speed > 44100)
speed = 44100; /* Invalid speed */
if (dsp_model == 1 && speed > 22050)
if (sb_dsp_model == 1 && speed > 22050)
speed = 22050;
/* SB Classic doesn't support higher speed */
......@@ -320,44 +239,51 @@ dsp_speed (int speed)
speed = 22050;
/* Max. stereo speed is 22050 */
if ((speed > 22050) && midi_busy)
if ((speed > 22050) && sb_midi_busy)
{
printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n");
speed = 22050;
}
if (dsp_stereo)
speed <<= 1;
speed *= 2;
/* Now the speed should be valid */
if (speed > 22050)
{ /* High speed mode */
tconst = (unsigned char) ((65536 - (256000000 / speed)) >> 8);
dsp_highspeed = 1;
int tmp;
tconst = (unsigned char) ((65536 -
((256000000+speed/2) / speed)) >> 8);
sb_dsp_highspeed = 1;
DISABLE_INTR (flags);
if (dsp_command (0x40))
dsp_command (tconst);
if (sb_dsp_command (0x40))
sb_dsp_command (tconst);
RESTORE_INTR (flags);
speed = (256000000 / (65536 - (tconst << 8)));
tmp = 65536 - (tconst << 8);
speed = (256000000+tmp/2) / tmp;
}
else
{
dsp_highspeed = 0;
tconst = (256 - (1000000 / speed)) & 0xff;
int tmp;
sb_dsp_highspeed = 0;
tconst = (256 - ((1000000+speed/2) / speed)) & 0xff;
DISABLE_INTR (flags);
if (dsp_command (0x40)) /* Set time constant */
dsp_command (tconst);
if (sb_dsp_command (0x40)) /* Set time constant */
sb_dsp_command (tconst);
RESTORE_INTR (flags);
speed = 1000000 / (256 - tconst);
tmp = 256 - tconst;
speed = (1000000+tmp/2) / tmp;
}
if (dsp_stereo)
speed >>= 1;
speed /= 2;
dsp_current_speed = speed;
return speed;
......@@ -368,49 +294,47 @@ dsp_set_stereo (int mode)
{
dsp_stereo = 0;
if (dsp_model == 1 || sb16)
#ifdef EXCLUDE_SBPRO
return 0;
#else
if (sb_dsp_model == 1 || sb16)
return 0; /* Sorry no stereo */
if (mode && midi_busy)
if (mode && sb_midi_busy)
{
printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n");
return 0;
}
dsp_stereo = !!mode;
#ifndef EXCLUDE_SBPRO
setmixer (OUT_FILTER, ((getmixer (OUT_FILTER) & ~STEREO_DAC)
| (mode ? STEREO_DAC : MONO_DAC)));
return dsp_stereo;
#endif
dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels
* changes */
return mode;
}
static void
sb_dsp_output_block (int dev, unsigned long buf, int count, int intrflag)
sb_dsp_output_block (int dev, unsigned long buf, int count,
int intrflag, int restart_dma)
{
unsigned long flags;
if (!irq_mode)
if (!sb_irq_mode)
dsp_speaker (ON);
irq_mode = IMODE_OUTPUT;
sb_irq_mode = IMODE_OUTPUT;
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
count--;
if (dsp_highspeed)
if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
if (dsp_command (0x48)) /* High speed size */
if (sb_dsp_command (0x48)) /* High speed size */
{
dsp_command (count & 0xff);
dsp_command ((count >> 8) & 0xff);
dsp_command (0x91); /* High speed 8 bit DAC */
sb_dsp_command (count & 0xff);
sb_dsp_command ((count >> 8) & 0xff);
sb_dsp_command (0x91); /* High speed 8 bit DAC */
}
else
printk ("SB Error: Unable to start (high speed) DAC\n");
......@@ -419,43 +343,44 @@ sb_dsp_output_block (int dev, unsigned long buf, int count, int intrflag)
else
{
DISABLE_INTR (flags);
if (dsp_command (0x14)) /* 8-bit DAC (DMA) */
if (sb_dsp_command (0x14)) /* 8-bit DAC (DMA) */
{
dsp_command (count & 0xff);
dsp_command ((count >> 8) & 0xff);
sb_dsp_command (count & 0xff);
sb_dsp_command ((count >> 8) & 0xff);
}
else
printk ("SB Error: Unable to start DAC\n");
RESTORE_INTR (flags);
}
intr_active = 1;
sb_intr_active = 1;
}
static void
sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag)
sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
int restart_dma)
{
/* Start a DMA input to the buffer pointed by dmaqtail */
unsigned long flags;
if (!irq_mode)
if (!sb_irq_mode)
dsp_speaker (OFF);
irq_mode = IMODE_INPUT;
sb_irq_mode = IMODE_INPUT;
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
count--;
if (dsp_highspeed)
if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
if (dsp_command (0x48)) /* High speed size */
if (sb_dsp_command (0x48)) /* High speed size */
{
dsp_command (count & 0xff);
dsp_command ((count >> 8) & 0xff);
dsp_command (0x99); /* High speed 8 bit ADC */
sb_dsp_command (count & 0xff);
sb_dsp_command ((count >> 8) & 0xff);
sb_dsp_command (0x99); /* High speed 8 bit ADC */
}
else
printk ("SB Error: Unable to start (high speed) ADC\n");
......@@ -464,23 +389,23 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag)
else
{
DISABLE_INTR (flags);
if (dsp_command (0x24)) /* 8-bit ADC (DMA) */
if (sb_dsp_command (0x24)) /* 8-bit ADC (DMA) */
{
dsp_command (count & 0xff);
dsp_command ((count >> 8) & 0xff);
sb_dsp_command (count & 0xff);
sb_dsp_command ((count >> 8) & 0xff);
}
else
printk ("SB Error: Unable to start ADC\n");
RESTORE_INTR (flags);
}
intr_active = 1;
sb_intr_active = 1;
}
static void
dsp_cleanup (void)
{
intr_active = 0;
sb_intr_active = 0;
}
static int
......@@ -488,6 +413,17 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount)
{
dsp_cleanup ();
dsp_speaker (OFF);
if (major == 3) /* SB Pro */
{
if (dsp_stereo)
sb_dsp_command(0xa8);
else
sb_dsp_command(0xa0);
dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels
* changes */
}
return 0;
}
......@@ -496,6 +432,13 @@ sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
{
dsp_cleanup ();
dsp_speaker (ON);
if (major == 3) /* SB Pro */
{
sb_mixer_set_stereo(dsp_stereo);
dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels
* changes */
}
return 0;
}
......@@ -505,50 +448,80 @@ sb_dsp_halt_xfer (int dev)
}
static int
sb_dsp_open (int dev, int mode)
verify_irq (void)
{
int retval;
#if 0
DEFINE_WAIT_QUEUE(testq, testf);
if (!sb_dsp_ok)
irq_ok = 0;
if (sb_get_irq () == -1)
{
printk ("SB Error: SoundBlaster board not installed\n");
return RET_ERROR (ENXIO);
printk ("*** SB Error: Irq %d already in use\n", sbc_irq);
return 0;
}
sb_irq_mode = IMODE_INIT;
sb_dsp_command (0xf2); /* This should cause immediate interrupt */
DO_SLEEP(testq, testf, HZ / 5);
sb_free_irq();
if (!irq_ok)
{
printk ("SB Error: Incorrect IRQ setting (%d)\n", sbc_irq);
printk ("SB Warning: IRQ%d test not passed!", sbc_irq);
irq_ok = 1;
}
#else
irq_ok = 1;
#endif
return irq_ok;
}
static int
sb_dsp_open (int dev, int mode)
{
int retval;
if (!sb_dsp_ok)
{
printk ("SB Error: SoundBlaster board not installed\n");
return RET_ERROR (ENXIO);
}
if (intr_active || (midi_busy && midi_mode == UART_MIDI))
if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI))
{
printk ("SB: PCM not possible during MIDI input\n");
return RET_ERROR (EBUSY);
}
if (mode != OPEN_READ && mode != OPEN_WRITE)
if (!irq_verified)
{
printk ("SoundBlaster error: DAC and ACD not possible simultaneously\n");
return RET_ERROR (EINVAL);
verify_irq();
irq_verified = 1;
}
else
if (!irq_ok)
printk("SB Warning: Incorrect IRQ setting %d\n",
sbc_irq);
retval = set_dsp_irq (sbc_irq);
retval = sb_get_irq ();
if (retval)
return retval;
if (!DMAbuf_open_dma (dev))
{
RELEASE_IRQ (sbc_irq);
sb_free_irq ();
printk ("SB: DMA Busy\n");
return RET_ERROR (EBUSY);
}
dsp_set_stereo (OFF);
dsp_speed (DSP_DEFAULT_SPEED);
irq_mode = IMODE_NONE;
sb_irq_mode = IMODE_NONE;
dsp_busy = 1;
sb_dsp_busy = 1;
return 0;
}
......@@ -557,12 +530,11 @@ static void
sb_dsp_close (int dev)
{
DMAbuf_close_dma (dev);
RELEASE_IRQ (sbc_irq);
sb_free_irq ();
dsp_cleanup ();
dsp_speed (DSP_DEFAULT_SPEED);
dsp_set_stereo (OFF);
dsp_speaker (OFF);
dsp_busy = 0;
sb_dsp_busy = 0;
sb_dsp_highspeed = 0;
}
static int
......@@ -624,7 +596,7 @@ sb_dsp_reset (int dev)
DISABLE_INTR (flags);
reset_dsp ();
sb_reset_dsp ();
dsp_cleanup ();
RESTORE_INTR (flags);
......@@ -641,538 +613,12 @@ sb_dsp_detect (struct address_info *hw_config)
if (sb_dsp_ok)
return 0; /* Already initialized */
if (!reset_dsp ())
if (!sb_reset_dsp ())
return 0;
return 1; /* Detected */
}
#ifndef EXCLUDE_SBPRO
static void
setmixer (unsigned char port, unsigned char value)
{
OUTB (port, MIXER_ADDR); /* Select register */
tenmicrosec ();
OUTB (value, MIXER_DATA);
tenmicrosec ();
}
static int
getmixer (unsigned char port)
{
int val;
OUTB (port, MIXER_ADDR); /* Select register */
tenmicrosec ();
val = INB (MIXER_DATA);
tenmicrosec ();
return val;
}
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?)
*/
setmixer (FM_VOL, 0xff);
setmixer (VOC_VOL, 0x33);
if (getmixer (FM_VOL) != 0xff)
return 0; /* No match */
if (getmixer (VOC_VOL) != 0x33)
return 0;
return 1;
}
static void
init_mixer (void)
{
setmixer (MASTER_VOL, 0xbb);
setmixer (VOC_VOL, 0x99);
setmixer (LINE_VOL, 0xbb);
setmixer (FM_VOL, 0x99);
setmixer (CD_VOL, 0x11);
setmixer (MIC_MIX, 0x11);
setmixer (RECORD_SRC, 0x31);
setmixer (OUT_FILTER, 0x31);
}
static void
set_filter (int record_source, int hifreq_filter, int filter_input, int filter_output)
{
setmixer (RECORD_SRC, (record_source
| (hifreq_filter ? FREQ_HI : FREQ_LOW)
| (filter_input ? FILT_ON : FILT_OFF)));
setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC)
| (filter_output ? FILT_ON : FILT_OFF)));
hi_filter = hifreq_filter;
filter_in = filter_input;
filter_out = filter_output;
}
static int
mixer_output (int right_vol, int left_vol, int div, int device)
{
int left = ((left_vol * div) + 50) / 100;
int right = ((right_vol * div) + 50) / 100;
setmixer (device, ((left & 0xf) << 4) | (right & 0xf));
return (left_vol | (right_vol << 8));
}
static int
sbp_mixer_set (int whichDev, unsigned int level)
{
int left, right, devmask;
left = level & 0x7f;
right = (level & 0x7f00) >> 8;
switch (whichDev)
{
case SOUND_MIXER_VOLUME: /* Master volume (0-15) */
return mixer_output (right, left, 15, MASTER_VOL);
break;
case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-15) */
return mixer_output (right, left, 15, FM_VOL);
break;
case SOUND_MIXER_PCM: /* PAS PCM (0-15) */
return mixer_output (right, left, 15, VOC_VOL);
break;
case SOUND_MIXER_LINE: /* External line (0-15) */
return mixer_output (right, left, 15, LINE_VOL);
break;
case SOUND_MIXER_CD: /* CD (0-15) */
return mixer_output (right, left, 15, CD_VOL);
break;
case SOUND_MIXER_MIC: /* External microphone (0-7) */
return mixer_output (right, left, 7, MIC_VOL);
break;
case SOUND_MIXER_RECSRC:
devmask = level & POSSIBLE_RECORDING_DEVICES;
if (devmask != SOUND_MASK_MIC &&
devmask != SOUND_MASK_LINE &&
devmask != SOUND_MASK_CD)
{ /* More than one devices selected. Drop the
* previous selection */
devmask &= ~rec_devices;
}
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 ^ rec_devices)/* Input source changed */
{
switch (devmask)
{
case SOUND_MASK_MIC:
set_filter (SRC_MIC, hi_filter, filter_in, filter_out);
break;
case SOUND_MASK_LINE:
set_filter (SRC_LINE, hi_filter, filter_in, filter_out);
break;
case SOUND_MASK_CD:
set_filter (SRC_CD, hi_filter, filter_in, filter_out);
break;
default:
set_filter (SRC_MIC, hi_filter, filter_in, filter_out);
}
}
rec_devices = devmask;
return rec_devices;
break;
default:
return RET_ERROR (EINVAL);
}
}
static int
mixer_input (int div, int device)
{
int level, left, right, half;
level = getmixer (device);
half = div / 2;
left = ((((level & 0xf0) >> 4) * 100) + half) / div;
right = (((level & 0x0f) * 100) + half) / div;
return (right << 8) | left;
}
static int
sbp_mixer_get (int whichDev)
{
switch (whichDev)
{
case SOUND_MIXER_VOLUME: /* Master volume (0-15) */
return mixer_input (15, MASTER_VOL);
break;
case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-15) */
return mixer_input (15, FM_VOL);
break;
case SOUND_MIXER_PCM: /* PAS PCM (0-15) */
return mixer_input (15, VOC_VOL);
break;
case SOUND_MIXER_LINE: /* External line (0-15) */
return mixer_input (15, LINE_VOL);
break;
case SOUND_MIXER_CD: /* CD (0-15) */
return mixer_input (15, CD_VOL);
break;
case SOUND_MIXER_MIC: /* External microphone (0-7) */
return mixer_input (7, MIC_VOL);
break;
default:
return RET_ERROR (EINVAL);
}
}
/*
* Sets mixer volume levels. All levels except mic are 0 to 15, mic is 7. See
* sbinfo.doc for details on granularity and such. Basically, the mixer
* forces the lowest bit high, effectively reducing the possible settings by
* one half. Yes, that's right, volume levels have 8 settings, and
* microphone has four. Sucks.
*/
static int
mixer_set_levels (struct sb_mixer_levels *user_l)
{
struct sb_mixer_levels l;
IOCTL_FROM_USER ((char *) &l, ((char *) user_l), 0, sizeof (l));
if (l.master.l & ~0xF || l.master.r & ~0xF
|| l.line.l & ~0xF || l.line.r & ~0xF
|| l.voc.l & ~0xF || l.voc.r & ~0xF
|| l.fm.l & ~0xF || l.fm.r & ~0xF
|| l.cd.l & ~0xF || l.cd.r & ~0xF
|| l.mic & ~0x7)
return (RET_ERROR (EINVAL));
setmixer (MASTER_VOL, (l.master.l << 4) | l.master.r);
setmixer (LINE_VOL, (l.line.l << 4) | l.line.r);
setmixer (VOC_VOL, (l.voc.l << 4) | l.voc.r);
setmixer (FM_VOL, (l.fm.l << 4) | l.fm.r);
setmixer (CD_VOL, (l.cd.l << 4) | l.cd.r);
setmixer (MIC_VOL, l.mic);
return (0);
}
/*
* This sets aspects of the Mixer that are not volume levels. (Recording
* source, filter level, I/O filtering, and stereo.)
*/
static int
mixer_set_params (struct sb_mixer_params *user_p)
{
struct sb_mixer_params p;
IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p));
if (p.record_source != SRC_MIC
&& p.record_source != SRC_CD
&& p.record_source != SRC_LINE)
return (EINVAL);
/*
* I'm not sure if this is The Right Thing. Should stereo be entirely
* under control of DSP? I like being able to toggle it while a sound is
* playing, so I do this... because I can.
*/
dsp_stereo = !!p.dsp_stereo;
set_filter (p.record_source, p.hifreq_filter, p.filter_input, p.filter_output);
switch (p.record_source)
{
case SRC_MIC:
rec_devices = SOUND_MASK_MIC;
break;
case SRC_LINE:
rec_devices = SOUND_MASK_LINE;
break;
case SRC_CD:
rec_devices = SOUND_MASK_CD;
}
return (0);
}
/* Read the current mixer level settings into the user's struct. */
static int
mixer_get_levels (struct sb_mixer_levels *user_l)
{
S_BYTE val;
struct sb_mixer_levels l;
val = getmixer (MASTER_VOL); /* Master */
l.master.l = B4 (val >> 4);
l.master.r = B4 (val);
val = getmixer (LINE_VOL); /* FM */
l.line.l = B4 (val >> 4);
l.line.r = B4 (val);
val = getmixer (VOC_VOL); /* DAC */
l.voc.l = B4 (val >> 4);
l.voc.r = B4 (val);
val = getmixer (FM_VOL); /* FM */
l.fm.l = B4 (val >> 4);
l.fm.r = B4 (val);
val = getmixer (CD_VOL); /* CD */
l.cd.l = B4 (val >> 4);
l.cd.r = B4 (val);
val = getmixer (MIC_VOL); /* Microphone */
l.mic = B3 (val);
IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l));
return (0);
}
/* Read the current mixer parameters into the user's struct. */
static int
mixer_get_params (struct sb_mixer_params *user_params)
{
S_BYTE val;
struct sb_mixer_params params;
val = getmixer (RECORD_SRC);
params.record_source = val & 0x07;
params.hifreq_filter = !!(val & FREQ_HI);
params.filter_input = (val & FILT_OFF) ? OFF : ON;
params.filter_output = (getmixer (OUT_FILTER) & FILT_OFF) ? OFF : ON;
params.dsp_stereo = dsp_stereo;
IOCTL_TO_USER ((char *) user_params, 0, (char *) &params, sizeof (params));
return (0);
}
static int
sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
{
if (((cmd >> 8) & 0xff) == 'M')
{
if (cmd & IOC_IN)
return IOCTL_OUT (arg, sbp_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
else
{ /* Read parameters */
switch (cmd & 0xff)
{
case SOUND_MIXER_RECSRC:
return IOCTL_OUT (arg, rec_devices);
break;
case SOUND_MIXER_DEVMASK:
return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
break;
case SOUND_MIXER_STEREODEVS:
return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~SOUND_MASK_MIC);
break;
case SOUND_MIXER_RECMASK:
return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES);
break;
case SOUND_MIXER_CAPS:
return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT);
break;
default:
return IOCTL_OUT (arg, sbp_mixer_get (cmd & 0xff));
}
}
}
else
{
switch (cmd)
{
case MIXER_IOCTL_SET_LEVELS:
return (mixer_set_levels ((struct sb_mixer_levels *) arg));
case MIXER_IOCTL_SET_PARAMS:
return (mixer_set_params ((struct sb_mixer_params *) arg));
case MIXER_IOCTL_READ_LEVELS:
return (mixer_get_levels ((struct sb_mixer_levels *) arg));
case MIXER_IOCTL_READ_PARAMS:
return (mixer_get_params ((struct sb_mixer_params *) arg));
case MIXER_IOCTL_RESET:
init_mixer ();
return (0);
default:
return RET_ERROR (EINVAL);
}
}
}
/* End of mixer code */
#endif
#ifndef EXCLUDE_MIDI
/* Midi code */
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 && !duplex_midi)
{
if (num_midis == 1)
printk ("SoundBlaster: Midi input not currently supported\n");
return RET_ERROR (EPERM);
}
midi_mode = NORMAL_MIDI;
if (mode != OPEN_WRITE)
{
if (dsp_busy || intr_active)
return RET_ERROR (EBUSY);
midi_mode = UART_MIDI;
}
if (dsp_highspeed || dsp_stereo)
{
printk ("SB Error: Midi output not possible during stereo or high speed audio\n");
return RET_ERROR (EBUSY);
}
if (midi_mode == UART_MIDI)
{
irq_mode = IMODE_MIDI;
reset_dsp ();
dsp_speaker (OFF);
if (!dsp_command (0x35))
return RET_ERROR (EIO); /* Enter the UART mode */
intr_active = 1;
if ((ret = set_dsp_irq (sbc_irq)) < 0)
{
reset_dsp ();
return 0; /* IRQ not free */
}
}
midi_busy = 1;
return 0;
}
static void
sb_midi_close (int dev)
{
if (midi_mode == UART_MIDI)
{
reset_dsp (); /* The only way to kill the UART mode */
RELEASE_IRQ (sbc_irq);
}
intr_active = 0;
midi_busy = 0;
}
static int
sb_midi_out (int dev, unsigned char midi_byte)
{
unsigned long flags;
midi_busy = 1; /* Kill all notes after close */
if (midi_mode == NORMAL_MIDI)
{
DISABLE_INTR (flags);
if (dsp_command (0x38))
dsp_command (midi_byte);
else
printk ("SB Error: Unable to send a MIDI byte\n");
RESTORE_INTR (flags);
}
else
dsp_command (midi_byte); /* UART write */
return 1;
}
static int
sb_midi_start_read (int dev)
{
if (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 (midi_mode == UART_MIDI)
{
reset_dsp ();
intr_active = 0;
}
return 0;
}
static int
sb_midi_ioctl (int dev, unsigned cmd, unsigned arg)
{
return RET_ERROR (EPERM);
}
/* End of midi code */
#endif
#ifndef EXCLUDE_AUDIO
static struct audio_operations sb_dsp_operations =
{
......@@ -1192,104 +638,41 @@ static struct audio_operations sb_dsp_operations =
#endif
#ifndef EXCLUDE_SBPRO
static struct mixer_operations sb_mixer_operations =
{
sb_mixer_ioctl
};
#endif
#ifndef EXCLUDE_MIDI
static struct midi_operations sb_midi_operations =
{
{"SoundBlaster", 0},
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 */
};
#endif
static int
verify_irq (void)
{
#if 0
unsigned long loop;
irq_ok = 0;
if (set_dsp_irq (sbc_irq) == -1)
{
printk ("*** SB Error: Irq %d already in use\n", sbc_irq);
return 0;
}
irq_mode = IMODE_INIT;
dsp_command (0xf2); /* This should cause immediate interrupt */
for (loop = 100000; loop > 0 && !irq_ok; loop--);
RELEASE_IRQ (sbc_irq);
if (!irq_ok)
{
printk ("SB Warning: IRQ test not passed!");
irq_ok = 1;
}
#else
irq_ok = 1;
#endif
return irq_ok;
}
long
sb_dsp_init (long mem_start, struct address_info *hw_config)
{
int i, major, minor;
int i;
major = minor = 0;
dsp_command (0xe1); /* Get version */
sb_dsp_command (0xe1); /* Get version */
for (i = 1000; i; i--)
{
if (inb (DSP_DATA_AVAIL) & 0x80)
if (INB (DSP_DATA_AVAIL) & 0x80)
{ /* wait for Data Ready */
if (major == 0)
major = inb (DSP_READ);
major = INB (DSP_READ);
else
{
minor = inb (DSP_READ);
minor = INB (DSP_READ);
break;
}
}
}
#ifndef EXCLUDE_SBPRO
if (detect_mixer ())
{
#ifndef SCO
sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", major, minor);
#endif
init_mixer ();
mixer_devs[num_mixers++] = &sb_mixer_operations;
if (major == 2 || major == 3)
duplex_midi = 1;
sb_duplex_midi = 1;
if (major == 4)
sb16 = 1;
if (major >= 3)
dsp_model = 2;
sb_dsp_model = 2;
#ifndef EXCLUDE_SBPRO
if (major >= 3)
sb_mixer_init(major);
#endif
#ifndef EXCLUDE_YM8312
if (major > 3 || (major == 3 && minor > 0)) /* SB Pro2 or later */
......@@ -1297,19 +680,22 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
}
#endif
if (major >= 3)
{
#ifndef SCO
sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", major, minor);
#endif
}
else
#endif
{
#ifndef SCO
sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", major, minor);
#endif
}
printk (" <%s>", sb_dsp_operations.name);
if (!verify_irq ())
return mem_start;
#ifndef EXCLUDE_AUDIO
if (num_dspdevs < MAX_DSP_DEV)
{
......@@ -1326,7 +712,7 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
#ifndef EXCLUDE_MIDI
if (!midi_disabled) /* Midi don't work in the SB emulation mode
* of PAS */
midi_devs[num_midis++] = &sb_midi_operations;
sb_midi_init(major);
#endif
sb_dsp_ok = 1;
......
/*
* 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
/*
* 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 char port, unsigned char value)
{
unsigned long flags;
DISABLE_INTR(flags);
OUTB (port, MIXER_ADDR); /* Select register */
tenmicrosec ();
OUTB (value, MIXER_DATA);
tenmicrosec ();
RESTORE_INTR(flags);
}
int
sb_getmixer (unsigned char port)
{
int val;
unsigned long flags;
DISABLE_INTR(flags);
OUTB (port, 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 regimage;
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;
regimage = 0;
for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
if ((1<<i) & devmask)
regimage |= sb16_recmasks[i];
sb_setmixer(SB16_IMASK_L, regimage);
sb_setmixer(SB16_IMASK_R, regimage);
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);
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
/*
* 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_SPEAKER | 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 {
char name[20];
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) \
{{#name,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] =
{
0x4b4b, /* Master Volume */
0x3232, /* Bass */
0x3232, /* Treble */
0x4b4b, /* FM */
0x4b4b, /* PCM */
0x4b4b, /* PC Speaker */
0x4b4b, /* Ext Line */
0x3232, /* Mic */
0x4b4b, /* CD */
0x4b4b, /* Recording monitor */
0x4b4b, /* SB PCM */
0x4b4b}; /* Recording level */
static unsigned char sb16_recmasks[SOUND_MIXER_NRDEVICES] =
{
0x00, /* SOUND_MIXER_VOLUME */
0x00, /* SOUND_MIXER_BASS */
0x00, /* SOUND_MIXER_TREBLE */
0x60, /* SOUND_MIXER_SYNTH */
0x00, /* SOUND_MIXER_PCM */
0x00, /* SOUND_MIXER_SPEAKER */
0x18, /* SOUND_MIXER_LINE */
0x01, /* SOUND_MIXER_MIC */
0x06, /* SOUND_MIXER_CD */
0x00, /* SOUND_MIXER_IMIX */
0x00, /* SOUND_MIXER_ALTPCM */
0x00 /* SOUND_MIXER_RECLEV */
};
#endif
......@@ -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,31 @@ 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);
/* 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 sb_midi.c */
void sb_midi_init(int model);
/* From sb_mixer.c */
void sb_setmixer (unsigned char port, unsigned char value);
int sb_getmixer (unsigned char port);
void sb_mixer_set_stereo(int mode);
void sb_mixer_init(int major_model);
/* From opl3.c */
int opl3_detect (int ioaddr);
......
......@@ -46,6 +46,10 @@
#define EXCLUDE_OPL3
#endif
#ifndef SND_DEFAULT_ENABLE
#define SND_DEFAULT_ENABLE 1
#endif
/** UWM - new MIDI stuff **/
#ifdef EXCLUDE_CHIP_MIDI
......@@ -77,6 +81,10 @@ 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 PAS_BASE
#define PAS_BASE 0x388
#endif
......@@ -113,6 +121,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
......@@ -178,10 +190,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_DSP_DEV 4
#define MAX_MIXER_DEV 1
#define MAX_SYNTH_DEV 3
#define MAX_MIDI_DEV 3
#define MAX_MIDI_DEV 4
struct fileinfo {
int mode; /* Open mode */
......
/*
* linux/kernel/chr_drv/sound/soundcard.c
*
......@@ -43,7 +44,6 @@ extern long seq_time;
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;
......@@ -106,18 +106,29 @@ init_status (void)
for (i = 0; i < (num_sound_drivers - 1); i++)
{
sprintf (tmp_buf, "Type %d: %s ",
if (!supported_drivers[i].enabled)
if (!put_status ("("))
return;
sprintf (tmp_buf, "Type %02x: %s",
supported_drivers[i].card_type,
supported_drivers[i].name);
if (!put_status (tmp_buf))
return;
sprintf (tmp_buf, " at 0x%03x irq %d drq %d\n",
sprintf (tmp_buf, " at 0x%03x irq %d drq %d",
supported_drivers[i].config.io_base,
supported_drivers[i].config.irq,
supported_drivers[i].config.dma);
if (!put_status (tmp_buf))
return;
if (!supported_drivers[i].enabled)
if (!put_status (")"))
return;
if (!put_status ("\n"))
return;
}
if (!put_status ("\nPCM devices:\n"))
......@@ -210,13 +221,10 @@ sound_read (struct inode *inode, struct file *file, char *buf, int count)
return read_status (buf, count);
break;
case SND_DEV_AUDIO:
return audio_read (dev, &files[dev], buf, count);
break;
case SND_DEV_DSP:
case SND_DEV_DSP16:
return dsp_read (dev, &files[dev], buf, count);
case SND_DEV_AUDIO:
return audio_read (dev, &files[dev], buf, count);
break;
case SND_DEV_SEQ:
......@@ -252,13 +260,10 @@ sound_write (struct inode *inode, struct file *file, char *buf, int count)
return sequencer_write (dev, &files[dev], buf, count);
break;
case SND_DEV_AUDIO:
return audio_write (dev, &files[dev], buf, count);
break;
case SND_DEV_DSP:
case SND_DEV_DSP16:
return dsp_write (dev, &files[dev], buf, count);
case SND_DEV_AUDIO:
return audio_write (dev, &files[dev], buf, count);
break;
default:
......@@ -338,18 +343,10 @@ sound_open (struct inode *inode, struct file *file)
break;
#endif
case SND_DEV_AUDIO:
if ((retval = audio_open (dev, &files[dev])) < 0)
return retval;
break;
case SND_DEV_DSP:
if ((retval = dsp_open (dev, &files[dev], 8)) < 0)
return retval;
break;
case SND_DEV_DSP16:
if ((retval = dsp_open (dev, &files[dev], 16)) < 0)
case SND_DEV_AUDIO:
if ((retval = audio_open (dev, &files[dev])) < 0)
return retval;
break;
......@@ -396,13 +393,10 @@ sound_release (struct inode *inode, struct file *file)
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]);
case SND_DEV_AUDIO:
audio_release (dev, &files[dev]);
break;
default:
......@@ -442,13 +436,10 @@ sound_ioctl (struct inode *inode, struct file *file,
return sequencer_ioctl (dev, &files[dev], cmd, arg);
break;
case SND_DEV_AUDIO:
return audio_ioctl (dev, &files[dev], cmd, arg);
break;
case SND_DEV_DSP:
case SND_DEV_DSP16:
return dsp_ioctl (dev, &files[dev], cmd, arg);
case SND_DEV_AUDIO:
return audio_ioctl (dev, &files[dev], cmd, arg);
break;
#ifndef EXCLUDE_MPU401
......@@ -520,7 +511,6 @@ soundcard_init (long mem_start)
{
mem_start = DMAbuf_init (mem_start);
mem_start = audio_init (mem_start);
mem_start = dsp_init (mem_start);
}
#ifndef EXCLUDE_MPU401
......@@ -548,9 +538,44 @@ tenmicrosec (void)
inb (0x80);
}
int
snd_set_irq_handler (int interrupt_level, void(*hndlr)(int))
{
int retcode;
struct sigaction sa;
sa.sa_handler = hndlr;
#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 ("Sound: IRQ%d already in use\n", interrupt_level);
}
return retcode;
}
void
snd_release_irq(int vect)
{
free_irq(vect);
}
void
request_sound_timer (int count)
{
#ifndef EXCLUDE_SEQUENCER
if (count < 0)
count = jiffies + (-count);
else
......@@ -558,13 +583,16 @@ request_sound_timer (int count)
timer_table[SOUND_TIMER].fn = sequencer_timer;
timer_table[SOUND_TIMER].expires = count;
timer_active |= 1 << SOUND_TIMER;
#endif
}
void
sound_stop_timer (void)
{
#ifndef EXCLUDE_SEQUENCER
timer_table[SOUND_TIMER].expires = 0;
timer_active &= ~(1 << SOUND_TIMER);
#endif
}
#ifndef EXCLUDE_AUDIO
......
......@@ -50,6 +50,7 @@
#define SNDCARD_PAS 3
#define SNDCARD_GUS 4
#define SNDCARD_MPU401 5
#define SNDCARD_SB16 6
/***********************************
* IOCTL Commands for /dev/sequencer
......@@ -402,744 +403,8 @@ struct midi_info {
char name[30];
int device; /* 0-N. INITIALIZE BEFORE CALLING */
unsigned long capabilities; /* To be defined later */
int dummies[19]; /* Reserve space */
};
/********************************************
* IOCTL commands for /dev/dsp and /dev/audio
*/
#define SNDCTL_DSP_RESET _IO ('P', 0)
#define SNDCTL_DSP_SYNC _IO ('P', 1)
#define SNDCTL_DSP_SPEED _IOWR('P', 2, int)
#define SNDCTL_DSP_STEREO _IOWR('P', 3, int)
#define SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
#define SNDCTL_DSP_SAMPLESIZE _IOWR('P', 5, int) /* 8, 12 or 16 */
#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int)
#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
#define SNDCTL_DSP_POST _IO ('P', 8)
#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
#define SOUND_PCM_READ_BITS _IOR ('P', 5, int)
#define SOUND_PCM_READ_FILTER _IOR ('P', 7, int)
/* Some alias names */
#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SAMPLESIZE
#define SOUND_PCM_WRITE_RATE SNDCTL_DSP_SPEED
#define SOUND_PCM_POST SNDCTL_DSP_POST
#define SOUND_PCM_RESET SNDCTL_DSP_RESET
#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC
/*********************************************
* IOCTL commands for /dev/mixer
*/
/*
* Mixer devices
*
* There can be up to 20 different analog mixer channels. The
* SOUND_MIXER_NRDEVICES gives the currently supported maximum.
* The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells
* the devices supported by the particular mixer.
*/
#define SOUND_MIXER_NRDEVICES 12
#define SOUND_MIXER_VOLUME 0
#define SOUND_MIXER_BASS 1
#define SOUND_MIXER_TREBLE 2
#define SOUND_MIXER_SYNTH 3
#define SOUND_MIXER_PCM 4
#define SOUND_MIXER_SPEAKER 5
#define SOUND_MIXER_LINE 6
#define SOUND_MIXER_MIC 7
#define SOUND_MIXER_CD 8
#define SOUND_MIXER_IMIX 9 /* Recording monitor */
#define SOUND_MIXER_ALTPCM 10
#define SOUND_MIXER_RECLEV 11 /* Recording level */
/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */
/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */
#define SOUND_ONOFF_MIN 28
#define SOUND_ONOFF_MAX 30
#define SOUND_MIXER_MUTE 28 /* 0 or 1 */
#define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */
#define SOUND_MIXER_LOUD 30 /* 0 or 1 */
/* Note! Number 31 cannot be used since the sign bit is reserved */
#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
"Mic ", "CD ", "Mix ", "Pcm2 ", "rec"}
#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
"mic", "cd", "mix", "pcm2", "rec"}
/* Device bitmask identifiers */
#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */
#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */
#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */
#define SOUND_MIXER_CAPS 0xfc
#define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */
#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
/* Device mask bits */
#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME)
#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS)
#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE)
#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH)
#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM)
#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER)
#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE)
#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC)
#define SOUND_MASK_CD (1 << SOUND_MIXER_CD)
#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX)
#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM)
#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV)
#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE)
#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE)
#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD)
#define MIXER_READ(dev) _IOR('M', dev, int)
#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME)
#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS)
#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE)
#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH)
#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM)
#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER)
#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE)
#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC)
#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD)
#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX)
#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM)
#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV)
#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE)
#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE)
#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD)
#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC)
#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK)
#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK)
#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
#define MIXER_WRITE(dev) _IOWR('M', dev, int)
#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS)
#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE)
#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH)
#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM)
#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER)
#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE)
#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC)
#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD)
#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX)
#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM)
#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV)
#define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE)
#define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE)
#define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD)
#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC)
/*
* The following mixer ioctl calls are compatible with the BSD driver by
* Steve Haehnichen <shaehnic@ucsd.edu>
*
* Since this interface is entirely SB specific, it will be dropped in the
* near future.
*/
typedef unsigned char S_BYTE;
typedef unsigned char S_FLAG;
struct stereo_vol
{
S_BYTE l; /* Left volume */
S_BYTE r; /* Right volume */
};
#define MIXER_IOCTL_SET_LEVELS _IOW ('s', 20, struct sb_mixer_levels)
#define MIXER_IOCTL_SET_PARAMS _IOW ('s', 21, struct sb_mixer_params)
#define MIXER_IOCTL_READ_LEVELS _IOR ('s', 22, struct sb_mixer_levels)
#define MIXER_IOCTL_READ_PARAMS _IOR ('s', 23, struct sb_mixer_params)
#define MIXER_IOCTL_RESET _IO ('s', 24)
/*
* Mixer volume levels for MIXER_IOCTL_SET_VOL & MIXER_IOCTL_READ_VOL
*/
struct sb_mixer_levels
{
struct stereo_vol master; /* Master volume */
struct stereo_vol voc; /* DSP Voice volume */
struct stereo_vol fm; /* FM volume */
struct stereo_vol line; /* Line-in volume */
struct stereo_vol cd; /* CD audio */
S_BYTE mic; /* Microphone level */
};
/*
* Mixer parameters for MIXER_IOCTL_SET_PARAMS & MIXER_IOCTL_READ_PARAMS
*/
struct sb_mixer_params
{
S_BYTE record_source; /* Recording source (See SRC_xxx below) */
S_FLAG hifreq_filter; /* Filter frequency (hi/low) */
S_FLAG filter_input; /* ANFI input filter */
S_FLAG filter_output; /* DNFI output filter */
S_FLAG dsp_stereo; /* 1 if DSP is in Stereo mode */
};
#define SRC_MIC 1 /* Select Microphone recording source */
#define SRC_CD 3 /* Select CD recording source */
#define SRC_LINE 7 /* Use Line-in for recording source */
#if !defined(KERNEL) && !defined(INKERNEL)
/*
* Some convenience macros to simplify programming of the
* /dev/sequencer interface
*
* These macros define the API which should be used when possible.
*/
void seqbuf_dump(void); /* This function must be provided by programs */
/* Sample seqbuf_dump() implementation:
*
* SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes
*
* int seqfd; -- The file descriptor for /dev/sequencer.
*
* void
* seqbuf_dump ()
* {
* if (_seqbufptr)
* if (write (seqfd, _seqbuf, _seqbufptr) == -1)
* {
* perror ("write /dev/sequencer");
* exit (-1);
* }
* _seqbufptr = 0;
* }
*/
#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len, _seqbufptr = 0
#define SEQ_PM_DEFINES struct patmgr_info _pm_info
#define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
#define _SEQ_ADVBUF(len) _seqbufptr += len
#define SEQ_DUMPBUF seqbuf_dump
#define PM_LOAD_PATCH(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
_pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
_pm_info.parm1 = bank, _pm_info.parm2 = 1, \
ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
#define PM_LOAD_PATCHES(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
_pm_info.device=dev, memcpy(_pm_info.data.data8, pgm, 128), \
_pm_info.parm1 = bank, _pm_info.parm2 = 128, \
ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
#define SEQ_START_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\
_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
_seqbuf[_seqbufptr+1] = SEQ_NOTEON;\
_seqbuf[_seqbufptr+2] = (dev);\
_seqbuf[_seqbufptr+3] = (voice);\
_seqbuf[_seqbufptr+4] = (note);\
_seqbuf[_seqbufptr+5] = (vol);\
_seqbuf[_seqbufptr+6] = 0;\
_seqbuf[_seqbufptr+7] = 0;\
_SEQ_ADVBUF(8);}
#define SEQ_STOP_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\
_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
_seqbuf[_seqbufptr+1] = SEQ_NOTEOFF;\
_seqbuf[_seqbufptr+2] = (dev);\
_seqbuf[_seqbufptr+3] = (voice);\
_seqbuf[_seqbufptr+4] = (note);\
_seqbuf[_seqbufptr+5] = (vol);\
_seqbuf[_seqbufptr+6] = 0;\
_seqbuf[_seqbufptr+7] = 0;\
_SEQ_ADVBUF(8);}
#define SEQ_CHN_PRESSURE(dev, voice, pressure) {_SEQ_NEEDBUF(8);\
_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
_seqbuf[_seqbufptr+1] = SEQ_AFTERTOUCH;\
_seqbuf[_seqbufptr+2] = (dev);\
_seqbuf[_seqbufptr+3] = (voice);\
_seqbuf[_seqbufptr+4] = (pressure);\
_seqbuf[_seqbufptr+5] = 0;\
_seqbuf[_seqbufptr+6] = 0;\
_seqbuf[_seqbufptr+7] = 0;\
_SEQ_ADVBUF(8);}
#define SEQ_PANNING(dev, voice, pos) {_SEQ_NEEDBUF(8);\
_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
_seqbuf[_seqbufptr+1] = SEQ_BALANCE;\
_seqbuf[_seqbufptr+2] = (dev);\
_seqbuf[_seqbufptr+3] = (voice);\
(char)_seqbuf[_seqbufptr+4] = (pos);\
_seqbuf[_seqbufptr+5] = 0;\
_seqbuf[_seqbufptr+6] = 0;\
_seqbuf[_seqbufptr+7] = 0;\
_SEQ_ADVBUF(8);}
#define SEQ_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\
_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
_seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
_seqbuf[_seqbufptr+2] = (dev);\
_seqbuf[_seqbufptr+3] = (voice);\
_seqbuf[_seqbufptr+4] = (controller);\
*(short *)&_seqbuf[_seqbufptr+5] = (value);\
_seqbuf[_seqbufptr+7] = 0;\
_SEQ_ADVBUF(8);}
#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_EXPRESSION, value)
#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_MAIN_VOLUME, value)
#define SEQ_START_TIMER() {_SEQ_NEEDBUF(4);\
_seqbuf[_seqbufptr] = SEQ_SYNCTIMER;\
_seqbuf[_seqbufptr+1] = 0;\
_seqbuf[_seqbufptr+2] = 0;\
_seqbuf[_seqbufptr+3] = 0;\
_SEQ_ADVBUF(4);}
#define SEQ_SET_PATCH(dev, voice, patch) {_SEQ_NEEDBUF(8);\
_seqbuf[_seqbufptr] = SEQ_EXTENDED;\
_seqbuf[_seqbufptr+1] = SEQ_PGMCHANGE;\
_seqbuf[_seqbufptr+2] = (dev);\
_seqbuf[_seqbufptr+3] = (voice);\
_seqbuf[_seqbufptr+4] = (patch);\
_seqbuf[_seqbufptr+5] = 0;\
_seqbuf[_seqbufptr+6] = 0;\
_seqbuf[_seqbufptr+7] = 0;\
_SEQ_ADVBUF(8);}
#define SEQ_WAIT_TIME(ticks) {_SEQ_NEEDBUF(4);\
*(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_WAIT | ((ticks) << 8);\
_SEQ_ADVBUF(4);}
#define SEQ_ECHO_BACK(key) {_SEQ_NEEDBUF(4);\
*(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_ECHO | ((key) << 8);\
_SEQ_ADVBUF(4);}
#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\
_seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
_seqbuf[_seqbufptr+1] = (byte);\
_seqbuf[_seqbufptr+2] = (device);\
_seqbuf[_seqbufptr+3] = 0;\
_SEQ_ADVBUF(4);}
#define SEQ_WRPATCH(patch, len) {if (_seqbufptr) seqbuf_dump();\
if (write(seqfd, (char*)(patch), len)==-1) \
perror("Write patch: /dev/sequencer");}
#endif
long soundcard_init(long mem_start);
#endif
#ifndef SOUNDCARD_H
#define SOUNDCARD_H
/*
* Copyright by Hannu Savolainen 1993
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
*/
/*
* If you make modifications to this file, please contact me before
* distributing the modified version. There is already enough
* divercity in the world.
*
* Regards,
* Hannu Savolainen
* hsavolai@cs.helsinki.fi
*/
#define SOUND_VERSION 200
#include <sys/ioctl.h>
/*
* Supported card ID numbers (Should be somewhere else?)
*/
#define SNDCARD_ADLIB 1
#define SNDCARD_SB 2
#define SNDCARD_PAS 3
#define SNDCARD_GUS 4
#define SNDCARD_MPU401 5
/***********************************
* IOCTL Commands for /dev/sequencer
*/
#ifndef _IOWR
/* @(#)ioctlp.h */
/* Ioctl's have the command encoded in the lower word,
* and the size of any in or out parameters in the upper
* word. The high 2 bits of the upper word are used
* to encode the in/out status of the parameter; for now
* we restrict parameters to at most 128 bytes.
*/
/* #define IOCTYPE (0xff<<8) */
#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
#define IOC_VOID 0x20000000 /* no parameters */
#define IOC_OUT 0x40000000 /* copy out parameters */
#define IOC_IN 0x80000000 /* copy in parameters */
#define IOC_INOUT (IOC_IN|IOC_OUT)
/* the 0x20000000 is so we can distinguish new ioctl's from old */
#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y))
#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
/* this should be _IORW, but stdio got there first */
#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
#endif /* !_IOWR */
#define SNDCTL_SEQ_RESET _IO ('Q', 0)
#define SNDCTL_SEQ_SYNC _IO ('Q', 1)
#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info)
#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (HZ) */
#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int)
#define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int)
#define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int)
#define SNDCTL_FM_LOAD_INSTR _IOW ('Q', 7, struct sbi_instrument) /* Valid for FM only */
#define SNDCTL_SEQ_TESTMIDI _IOW ('Q', 8, int)
#define SNDCTL_SEQ_RESETSAMPLES _IOW ('Q', 9, int)
#define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int)
#define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int)
#define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info)
#define SNDCTL_SEQ_TRESHOLD _IOW ('Q',13, int)
#define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */
#define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */
#define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info)
/*
* Sample loading mechanism for internal synthesizers (/dev/sequencer)
* The following patch_info structure has been designed to support
* Gravis UltraSound. It tries to be universal format for uploading
* sample based patches but is propably too limited.
*/
struct patch_info {
short key; /* Use GUS_PATCH here */
#define GUS_PATCH 0x04fd
#define OBSOLETE_GUS_PATCH 0x02fd
short device_no; /* Synthesizer number */
short instr_no; /* Midi pgm# */
unsigned long mode;
/*
* The least significant byte has the same format than the GUS .PAT
* files
*/
#define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */
#define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */
#define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */
#define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */
#define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */
#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/
#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */
/* (use the env_rate/env_offs fields). */
/* Linux specific bits */
#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */
#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */
#define WAVE_SCALE 0x00040000 /* The scaling info is valid */
/* Other bits must be zeroed */
long len; /* Size of the wave data in bytes */
long loop_start, loop_end; /* Byte offsets from the beginning */
/*
* The base_freq and base_note fields are used when computing the
* playback speed for a note. The base_note defines the tone frequency
* which is heard if the sample is played using the base_freq as the
* playback speed.
*
* The low_note and high_note fields define the minimum and maximum note
* frequencies for which this sample is valid. It is possible to define
* more than one samples for a instrument number at the same time. The
* low_note and high_note fields are used to select the most suitable one.
*
* The fields base_note, high_note and low_note should contain
* the note frequency multiplied by 1000. For example value for the
* middle A is 440*1000.
*/
unsigned int base_freq;
unsigned long base_note;
unsigned long high_note;
unsigned long low_note;
int panning; /* -128=left, 127=right */
int detuning;
/* New fields introduced in version 1.99.5 */
/* Envelope. Enabled by mode bit WAVE_ENVELOPES */
unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */
unsigned char env_offset[ 6 ]; /* 255 == 100% */
/*
* The tremolo, vibrato and scale info are not supported yet.
* Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or
* WAVE_SCALE
*/
unsigned char tremolo_sweep;
unsigned char tremolo_rate;
unsigned char tremolo_depth;
unsigned char vibrato_sweep;
unsigned char vibrato_rate;
unsigned char vibrato_depth;
int scale_frequency;
unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */
int volume;
int spare[4];
char data[0]; /* The waveform data starts here */
};
/*
* Patch management interface (/dev/sequencer, /dev/patmgr#)
* Don't use these calls if you want to maintain compatibility with
* the future versions of the driver.
*/
#define PS_NO_PATCHES 0 /* No patch support on device */
#define PS_MGR_NOT_OK 1 /* Plain patch support (no mgr) */
#define PS_MGR_OK 2 /* Patch manager supported */
#define PS_MANAGED 3 /* Patch manager running */
#define SNDCTL_PMGR_IFACE _IOWR('P', 1, struct patmgr_info)
/*
* The patmgr_info is a fixed size structure which is used for two
* different purposes. The intended use is for communication between
* the application using /dev/sequencer and the patch manager daemon
* associated with a synthesizer device (ioctl(SNDCTL_PMGR_ACCESS)).
*
* This structure is also used with ioctl(SNDCTL_PGMR_IFACE) which allows
* a patch manager daemon to read and write device parameters. This
* ioctl available through /dev/sequencer also. Avoid using it since it's
* extremely hardware dependent. In addition access trough /dev/sequencer
* may confuse the patch manager daemon.
*/
struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
unsigned long key; /* Don't worry. Reserved for communication
between the patch manager and the driver. */
#define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */
#define PM_K_COMMAND 2 /* Request from a application */
#define PM_K_RESPONSE 3 /* From patmgr to application */
#define PM_ERROR 4 /* Error returned by the patmgr */
int device;
int command;
/*
* Commands 0x000 to 0xfff reserved for patch manager programs
*/
#define PM_GET_DEVTYPE 1 /* Returns type of the patch mgr interface of dev */
#define PMTYPE_FM2 1 /* 2 OP fm */
#define PMTYPE_FM4 2 /* Mixed 4 or 2 op FM (OPL-3) */
#define PMTYPE_WAVE 3 /* Wave table synthesizer (GUS) */
#define PM_GET_NRPGM 2 /* Returns max # of midi programs in parm1 */
#define PM_GET_PGMMAP 3 /* Returns map of loaded midi programs in data8 */
#define PM_GET_PGM_PATCHES 4 /* Return list of patches of a program (parm1) */
#define PM_GET_PATCH 5 /* Return patch header of patch parm1 */
#define PM_SET_PATCH 6 /* Set patch header of patch parm1 */
#define PM_READ_PATCH 7 /* Read patch (wave) data */
#define PM_WRITE_PATCH 8 /* Write patch (wave) data */
/*
* Commands 0x1000 to 0xffff are for communication between the patch manager
* and the client
*/
#define _PM_LOAD_PATCH 0x100
/*
* Commands above 0xffff reserved for device specific use
*/
long parm1;
long parm2;
long parm3;
union {
unsigned char data8[4000];
unsigned short data16[2000];
unsigned long data32[1000];
struct patch_info patch;
} data;
};
/*
* When a patch manager daemon is present, it will be informed by the
* driver when something important happens. For example when the
* /dev/sequencer is opened or closed. A record with key == PM_K_EVENT is
* returned. The command field contains the event type:
*/
#define PM_E_OPENED 1 /* /dev/sequencer opened */
#define PM_E_CLOSED 2 /* /dev/sequencer closed */
#define PM_E_PATCH_RESET 3 /* SNDCTL_RESETSAMPLES called */
#define PM_E_PATCH_LOADED 4 /* A patch has been loaded by appl */
/*
* /dev/sequencer input events.
*
* The data written to the /dev/sequencer is a stream of events. Events
* are records of 4 or 8 bytes. The first byte defines the size.
* Any number of events can be written with a write call. There
* is a set of macros for sending these events. Use these macros if you
* want to maximize portability of your program.
*
* Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events.
* (All input events are currently 4 bytes long. Be prepared to support
* 8 byte events also. If you receive any event having first byte >= 0xf0,
* it's a 8 byte event.
*
* The events are documented at the end of this file.
*
* Normal events (4 bytes)
* There is also a 8 byte version of most of the 4 byte events. The
* 8 byte one is recommended.
*/
#define SEQ_NOTEOFF 0
#define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */
#define SEQ_NOTEON 1
#define SEQ_FMNOTEON SEQ_NOTEON
#define SEQ_WAIT 2
#define SEQ_PGMCHANGE 3
#define SEQ_FMPGMCHANGE SEQ_PGMCHANGE
#define SEQ_SYNCTIMER 4
#define SEQ_MIDIPUTC 5
#define SEQ_DRUMON 6 /*** OBSOLETE ***/
#define SEQ_DRUMOFF 7 /*** OBSOLETE ***/
#define SEQ_ECHO 8 /* For synching programs with output */
#define SEQ_AFTERTOUCH 9
#define SEQ_CONTROLLER 10
#define CTRL_PITCH_BENDER 255
#define CTRL_PITCH_BENDER_RANGE 254
#define CTRL_EXPRESSION 253
#define CTRL_MAIN_VOLUME 252
#define SEQ_BALANCE 11
/*
* Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as
* input events.
*/
/*
* Event codes 0xf0 to 0xfc are reserved for future extensions.
*/
#define SEQ_FULLSIZE 0xfd /* Long events */
/*
* SEQ_FULLSIZE events are used for loading patches/samples to the
* synthesizer devices. These events are passed directly to the driver
* of the associated synthesizer device. There is no limit to the size
* of the extended events. These events are not queued but executed
* immediately when the write() is called (execution can take several
* seconds of time).
*
* When a SEQ_FULLSIZE message is written to the device, it must
* be written using exactly one write() call. Other events cannot
* be mixed to the same write.
*
* For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the
* /dev/sequencer. Don't write other data together with the instrument structure
* Set the key field of the structure to FM_PATCH. The device field is used to
* route the patch to the corresponding device.
*
* For Gravis UltraSound use struct patch_info. Initialize the key field
* to GUS_PATCH.
*/
#define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */
#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) */
/*
* Extended events for synthesizers (8 bytes)
*
* Format:
*
* b0 = SEQ_EXTENDED
* b1 = command
* b2 = device
* b3-b7 = parameters
*
* Command b3 b4 b5 b6 b7
* ----------------------------------------------------------------------------
* SEQ_NOTEON voice note volume 0 0
* SEQ_NOTEOFF voice note volume 0 0
* SEQ_PGMCHANGE voice pgm 0 0 0
* SEQ_DRUMON (voice) drum# volume 0 0
* SEQ_DRUMOFF (voice) drum# volume 0 0
*/
/*
* Record for FM patches
*/
typedef unsigned char sbi_instr_data[32];
struct sbi_instrument {
unsigned short key; /* Initialize to FM_PATCH or OPL3_PATCH */
#define FM_PATCH 0x01fd
#define OPL3_PATCH 0x03fd
short device; /* Synth# (0-4) */
int channel; /* Program# to be initialized */
sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */
};
struct synth_info { /* Read only */
char name[30];
int device; /* 0-N. INITIALIZE BEFORE CALLING */
int synth_type;
#define SYNTH_TYPE_FM 0
#define SYNTH_TYPE_SAMPLE 1
int synth_subtype;
#define FM_TYPE_ADLIB 0x00
#define FM_TYPE_OPL3 0x01
#define SAMPLE_TYPE_GUS 0x10
int perc_mode; /* No longer supported */
int nr_voices;
int nr_drums; /* Obsolete field */
int instr_bank_size;
unsigned long capabilities;
#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */
#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */
int dummies[19]; /* Reserve space */
};
struct midi_info {
char name[30];
int device; /* 0-N. INITIALIZE BEFORE CALLING */
unsigned long capabilities; /* To be defined later */
int dummies[19]; /* Reserve space */
int dev_type;
int dummies[18]; /* Reserve space */
};
/********************************************
......@@ -1155,6 +420,7 @@ struct midi_info {
#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int)
#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
#define SNDCTL_DSP_POST _IO ('P', 8)
#define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int)
#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
......@@ -1167,6 +433,7 @@ struct midi_info {
#define SOUND_PCM_POST SNDCTL_DSP_POST
#define SOUND_PCM_RESET SNDCTL_DSP_RESET
#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC
#define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE
/*********************************************
* IOCTL commands for /dev/mixer
......
......@@ -32,8 +32,6 @@
* and not portable.
*/
#include "soundcard.h"
/*
* Private events for Gravis Ultrasound (GUS)
*
......
......@@ -392,7 +392,7 @@ void isofs_read_inode(struct inode * inode)
};
if (isonum_723 (raw_inode->volume_sequence_number) != 1) {
panic("Multi volume CD somehow got mounted.\n");
printk("Multi volume CD somehow got mounted.\n");
};
if (raw_inode->interleave[0]) {
......
......@@ -52,7 +52,7 @@ __asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr));
#define put_fs_long(x,addr) put_user_long((x),(int *)(addr))
static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned long n)
{
__asm__("cld\n\t"
"push %%es\n\t"
......@@ -72,7 +72,55 @@ __asm__("cld\n\t"
:"cx","di","si");
}
static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
static inline void __constant_memcpy_tofs(void * to, const void * from, unsigned long n)
{
switch (n) {
case 0:
return;
case 1:
put_user_byte(*(const char *) from, (char *) to);
return;
case 2:
put_user_word(*(const short *) from, (short *) to);
return;
case 3:
put_user_word(*(const short *) from, (short *) to);
put_user_byte(*(2+(const char *) from), 2+(char *) to);
return;
case 4:
put_user_long(*(const int *) from, (int *) to);
return;
}
#define COMMON(x) \
__asm__("cld\n\t" \
"push %%es\n\t" \
"push %%fs\n\t" \
"pop %%es\n\t" \
"rep ; movsl\n\t" \
x \
"pop %%es" \
: /* no outputs */ \
:"c" (n/4),"D" ((long) to),"S" ((long) from) \
:"cx","di","si")
switch (n % 4) {
case 0:
COMMON("");
return;
case 1:
COMMON("movsb\n\t");
return;
case 2:
COMMON("movsw\n\t");
return;
case 3:
COMMON("movsw\n\tmovsb\n\t");
return;
}
#undef COMMON
}
static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigned long n)
{
__asm__("cld\n\t"
"testb $1,%%cl\n\t"
......@@ -85,9 +133,63 @@ __asm__("cld\n\t"
"rep ; fs ; movsl"
: /* no outputs */
:"c" (n),"D" ((long) to),"S" ((long) from)
:"cx","di","si");
:"cx","di","si","memory");
}
static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n)
{
switch (n) {
case 0:
return;
case 1:
*(char *)to = get_user_byte((const char *) from);
return;
case 2:
*(short *)to = get_user_word((const short *) from);
return;
case 3:
*(short *) to = get_user_word((const short *) from);
*(char *) to = get_user_byte(2+(const char *) from);
return;
case 4:
*(int *) to = get_user_long((const int *) from);
return;
}
#define COMMON(x) \
__asm__("cld\n\t" \
"rep ; fs ; movsl\n\t" \
x \
: /* no outputs */ \
:"c" (n/4),"D" ((long) to),"S" ((long) from) \
:"cx","di","si","memory")
switch (n % 4) {
case 0:
COMMON("");
return;
case 1:
COMMON("fs ; movsb");
return;
case 2:
COMMON("fs ; movsw");
return;
case 3:
COMMON("fs ; movsw\n\tfs ; movsb");
return;
}
#undef COMMON
}
#define memcpy_fromfs(to, from, n) \
(__builtin_constant_p(n) ? \
__constant_memcpy_fromfs((to),(from),(n)) : \
__generic_memcpy_fromfs((to),(from),(n)))
#define memcpy_tofs(to, from, n) \
(__builtin_constant_p(n) ? \
__constant_memcpy_tofs((to),(from),(n)) : \
__generic_memcpy_tofs((to),(from),(n)))
/*
* Someone who knows GNU asm better than I should double check the followig.
* It seems to work, but I don't know if I'm doing something subtly wrong.
......
......@@ -22,14 +22,19 @@
*/
/* *** change this to set the I/O port address */
#define MCDPORT(x) (0x320 + (x))
#define MCD_BASE_ADDR 0x300
/* *** change this to set the interrupt number */
#define MCD_INTR_NR 11
/* Increase this if you get lots of timeouts */
#define MCD_STATUS_DELAY 100
/* number of times to retry a command before giving up */
#define MCD_RETRY_ATTEMPTS 3
/* port access macro */
#define MCDPORT(x) (mcd_port + (x))
/* status bits */
......
......@@ -84,11 +84,13 @@ extern void hd_setup(char *str, int *ints);
extern void bmouse_setup(char *str, int *ints);
extern void eth_setup(char *str, int *ints);
extern void xd_setup(char *str, int *ints);
extern void mcd_setup(char *str, int *ints);
extern void st0x_setup(char *str, int *ints);
extern void tmc8xx_setup(char *str, int *ints);
extern void t128_setup(char *str, int *ints);
extern void generic_NCR5380_setup(char *str, int *intr);
extern void aha152x_setup(char *str, int *ints);
extern void sound_setup(char *str, int *ints);
#ifdef CONFIG_SYSVIPC
extern void ipc_init(void);
......@@ -189,6 +191,12 @@ struct {
#endif
#ifdef CONFIG_BLK_DEV_XD
{ "xd=", xd_setup },
#endif
#ifdef CONFIG_MCD
{ "mcd=", mcd_setup },
#endif
#ifdef CONFIG_SOUND
{ "sound=", sound_setup },
#endif
{ 0, 0 }
};
......@@ -366,11 +374,11 @@ asmlinkage void start_kernel(void)
memory_start = kmalloc_init(memory_start,memory_end);
memory_start = chr_dev_init(memory_start,memory_end);
memory_start = blk_dev_init(memory_start,memory_end);
sti();
calibrate_delay();
#ifdef CONFIG_INET
memory_start = net_dev_init(memory_start,memory_end);
#endif
sti();
calibrate_delay();
#ifdef CONFIG_SCSI
memory_start = scsi_dev_init(memory_start,memory_end);
#endif
......
......@@ -175,6 +175,10 @@ asmlinkage void math_emulate(long arg)
#endif /* CONFIG_MATH_EMULATION */
static unsigned long itimer_ticks = 0;
static unsigned long itimer_next = ~0;
static unsigned long lost_ticks = 0;
/*
* 'schedule()' is the scheduler function. It's a very simple and nice
* scheduler: it's not perfect, but certainly works for most things.
......@@ -192,15 +196,36 @@ asmlinkage void schedule(void)
int c;
struct task_struct * p;
struct task_struct * next;
unsigned long ticks;
/* check alarm, wake up any interruptible tasks that have got a signal */
cli();
ticks = itimer_ticks;
itimer_ticks = 0;
itimer_next = ~0;
sti();
need_resched = 0;
p = &init_task;
for (;;) {
if ((p = p->next_task) == &init_task)
goto confuse_gcc1;
if (ticks && p->it_real_value) {
if (p->it_real_value <= ticks) {
send_sig(SIGALRM, p, 1);
if (!p->it_real_incr) {
p->it_real_value = 0;
goto end_itimer;
}
do {
p->it_real_value += p->it_real_incr;
} while (p->it_real_value <= ticks);
}
p->it_real_value -= ticks;
if (p->it_real_value < itimer_next)
itimer_next = p->it_real_value;
}
end_itimer:
if (p->state != TASK_INTERRUPTIBLE)
continue;
if (p->signal & ~p->blocked) {
......@@ -503,8 +528,6 @@ static void second_overflow(void)
last_rtc_update = xtime.tv_sec;
}
static int lost_ticks = 0;
/*
* disregard lost ticks for now.. We don't care enough.
*/
......@@ -532,7 +555,6 @@ static void do_timer(struct pt_regs * regs)
{
unsigned long mask;
struct timer_struct *tp = timer_table+0;
struct task_struct * task_p;
long ltemp;
......@@ -609,16 +631,6 @@ static void do_timer(struct pt_regs * regs)
current->counter=0;
need_resched = 1;
}
/* Update ITIMER_REAL for every task */
for_each_task(task_p) {
if (!task_p->it_real_value)
continue;
if (--task_p->it_real_value)
continue;
send_sig(SIGALRM,task_p,1);
task_p->it_real_value = task_p->it_real_incr;
need_resched = 1;
}
/* Update ITIMER_PROF for the current task */
if (current->it_prof_value && !(--current->it_prof_value)) {
current->it_prof_value = current->it_prof_incr;
......@@ -636,6 +648,9 @@ static void do_timer(struct pt_regs * regs)
sti();
}
cli();
itimer_ticks++;
if (itimer_ticks > itimer_next)
need_resched = 1;
if (next_timer) {
if (next_timer->expires) {
next_timer->expires--;
......
......@@ -55,7 +55,7 @@
#define NET16(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
#define INET_DEBUG
#undef INET_DEBUG
#ifdef INET_DEBUG
# define DPRINTF(x) dprintf x
#else
......
......@@ -1126,6 +1126,8 @@ ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
} else raddr = iph->daddr;
dev2 = rt->rt_dev;
if (dev == dev2)
return;
/*
* We now allocate a new buffer, and copy the datagram into it.
* If the indicated interface is up and running, kick it.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment