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
......@@ -56,7 +58,9 @@ static int mcd_sizes[] = { 0 };
static int mcdPresent = 0;
static char mcd_buf[2048]; /* buffer for block size conversion */
static int mcd_bn = -1;
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;
......@@ -88,6 +92,15 @@ static int GetDiskInfo(void);
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)
......@@ -95,10 +108,13 @@ 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,10 +813,17 @@ 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;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 4;
......@@ -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
......
This diff is collapsed.
......@@ -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]);
COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
if (!dsp_devs[dev]->copy_from_user)
{ /* No device specific copy routine */
COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
}
else
dsp_devs[dev]->copy_from_user (dev,
wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
/* Insert local processing here */
if (dev_type == SND_DEV_AUDIO)
{
#ifdef linux
/* This just allows interrupts while the conversion is running */
__asm__ ("sti");
__asm__ ("sti");
#endif
translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
}
c -= l;
p += l;
......@@ -169,11 +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");
/* This just allows interrupts while the conversion is running */
__asm__ ("sti");
#endif
translate_bytes (dsp_ulaw, dmabuf, l);
translate_bytes (dsp_ulaw, dmabuf, l);
}
COPY_TO_USER (buf, p, dmabuf, l);
......@@ -205,6 +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
return RET_ERROR (EIO);
#else
if (dev_type == SND_DEV_AUDIO)
return RET_ERROR (EIO);
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
......
This diff is collapsed.
/*
* 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,21 +678,7 @@ 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) */
irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
tmp = gus_dma_map[gus_dma];
......@@ -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;
}
......@@ -228,6 +196,15 @@ config_pas_hw (struct address_info *hw_config)
ok = 0;
}
}
/*
* This fixes the timing problems of the PAS due to the Symphony chipset
* as per Media Vision. Only define this if your PAS doesn't work correctly.
*/
#ifdef SYMPHONY_PAS
OUTB(0x05,0xa8);
OUTB(0x60,0xa9);
#endif
#ifdef BROKEN_BUS_CLOCK
pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
......@@ -235,7 +212,6 @@ config_pas_hw (struct address_info *hw_config)
/* 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);
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
if (restart_dma)
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
count--;
if (count != pcm_count)
{
......@@ -288,7 +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);
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
if (restart_dma)
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
if (sound_dsp_dmachan[dev] > 3)
count >>= 1;
count--;
if (count != pcm_count)
{
pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
......@@ -374,6 +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;
}
This diff is collapsed.
/*
* 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
......
This diff is collapsed.
......@@ -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 */
......
This diff is collapsed.
This diff is collapsed.
......@@ -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