This commit was generated by cvs2svn to compensate for changes in r3252,
which included commits to RCS files with non-trunk default branches.
This commit is contained in:
commit
8f25169ce6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=3253
953
sys/i386/isa/sound/ad1848.c
Normal file
953
sys/i386/isa/sound/ad1848.c
Normal file
@ -0,0 +1,953 @@
|
||||
/*
|
||||
* sound/ad1848.c
|
||||
*
|
||||
* The low level driver for the AD1848/CS4248 codec chip which
|
||||
* is used for example in the MS Sound System.
|
||||
*
|
||||
* The CS4231 which is used in the GUS MAX and some other cards is
|
||||
* upwards compatible with AD1848 and this driver is able to drive it.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1994
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEB(x)
|
||||
#define DEB1(x)
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)
|
||||
|
||||
#define IMODE_NONE 0
|
||||
#define IMODE_OUTPUT 1
|
||||
#define IMODE_INPUT 2
|
||||
#define IMODE_INIT 3
|
||||
#define IMODE_MIDI 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int base;
|
||||
int irq;
|
||||
int dma_capture, dma_playback;
|
||||
unsigned char MCE_bit;
|
||||
|
||||
int speed;
|
||||
unsigned char speed_bits;
|
||||
int channels;
|
||||
int audio_format;
|
||||
unsigned char format_bits;
|
||||
|
||||
int xfer_count;
|
||||
int irq_mode;
|
||||
int intr_active;
|
||||
int opened;
|
||||
char *chip_name;
|
||||
int mode;
|
||||
}
|
||||
|
||||
ad1848_info;
|
||||
|
||||
static int nr_ad1848_devs = 0;
|
||||
static char irq2dev[16] =
|
||||
{-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1};
|
||||
|
||||
static int ad_format_mask[2 /*devc->mode*/ ] =
|
||||
{
|
||||
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
|
||||
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM
|
||||
};
|
||||
|
||||
static ad1848_info dev_info[MAX_AUDIO_DEV];
|
||||
|
||||
#define io_Index_Addr(d) ((d)->base)
|
||||
#define io_Indexed_Data(d) ((d)->base+1)
|
||||
#define io_Status(d) ((d)->base+2)
|
||||
#define io_Polled_IO(d) ((d)->base+3)
|
||||
|
||||
static int ad1848_open (int dev, int mode);
|
||||
static void ad1848_close (int dev);
|
||||
static int ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
|
||||
static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
|
||||
static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
|
||||
static int ad1848_prepare_for_IO (int dev, int bsize, int bcount);
|
||||
static void ad1848_reset (int dev);
|
||||
static void ad1848_halt (int dev);
|
||||
void ad1848_interrupt (int dev);
|
||||
|
||||
static int
|
||||
ad_read (ad1848_info * devc, int reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
int x;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
|
||||
x = INB (io_Indexed_Data (devc));
|
||||
/* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void
|
||||
ad_write (ad1848_info * devc, int reg, int data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
|
||||
OUTB ((unsigned char) (data & 0xff), io_Indexed_Data (devc));
|
||||
/* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
ad_set_MCE (ad1848_info * devc, int state)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (state)
|
||||
devc->MCE_bit = 0x40;
|
||||
else
|
||||
devc->MCE_bit = 0x00;
|
||||
OUTB (devc->MCE_bit, io_Index_Addr (devc));
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
wait_for_calibration (ad1848_info * devc)
|
||||
{
|
||||
int timeout = 0;
|
||||
|
||||
/*
|
||||
* Wait until the auto calibration process has finished.
|
||||
*
|
||||
* 1) Wait until the chip becomes ready (reads don't return 0x80).
|
||||
* 2) Wait until the ACI bit of I11 gets on and then off.
|
||||
*/
|
||||
|
||||
timeout = 100000;
|
||||
while (timeout > 0 && INB (devc->base) == 0x80)
|
||||
timeout--;
|
||||
if (INB (devc->base) == 0x80)
|
||||
printk ("ad1848: Auto calibration timed out(1).\n");
|
||||
|
||||
timeout = 100000;
|
||||
while (timeout > 0 && !(ad_read (devc, 11) & 0x20))
|
||||
timeout--;
|
||||
if (!(ad_read (devc, 11) & 0x20))
|
||||
printk ("ad1848: Auto calibration timed out(2).\n");
|
||||
|
||||
timeout = 100000;
|
||||
while (timeout > 0 && ad_read (devc, 11) & 0x20)
|
||||
timeout--;
|
||||
if (ad_read (devc, 11) & 0x20)
|
||||
printk ("ad1848: Auto calibration timed out(3).\n");
|
||||
}
|
||||
|
||||
static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
|
||||
{
|
||||
{
|
||||
"Generic AD1848 codec",
|
||||
DMA_AUTOMODE,
|
||||
AFMT_U8, /* Will be set later */
|
||||
NULL,
|
||||
ad1848_open,
|
||||
ad1848_close,
|
||||
ad1848_output_block,
|
||||
ad1848_start_input,
|
||||
ad1848_ioctl,
|
||||
ad1848_prepare_for_IO,
|
||||
ad1848_prepare_for_IO,
|
||||
ad1848_reset,
|
||||
ad1848_halt,
|
||||
NULL,
|
||||
NULL
|
||||
}};
|
||||
|
||||
static int
|
||||
ad1848_open (int dev, int mode)
|
||||
{
|
||||
int err;
|
||||
ad1848_info *devc = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
DEB (printk ("ad1848_open(int mode = %X)\n", mode));
|
||||
|
||||
if (dev < 0 || dev >= num_audiodevs)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
if (devc->opened)
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
printk ("ad1848: Already opened\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
if (devc->irq) /* Not managed by another driver */
|
||||
if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt)) < 0)
|
||||
{
|
||||
printk ("ad1848: IRQ in use\n");
|
||||
RESTORE_INTR (flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (DMAbuf_open_dma (dev) < 0)
|
||||
{
|
||||
RESTORE_INTR (flags);
|
||||
printk ("ad1848: DMA in use\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
devc->intr_active = 0;
|
||||
devc->opened = 1;
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_close (int dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
DEB (printk ("ad1848_close(void)\n"));
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
devc->intr_active = 0;
|
||||
if (devc->irq) /* Not managed by another driver */
|
||||
snd_release_irq (devc->irq);
|
||||
ad1848_reset (dev);
|
||||
DMAbuf_close_dma (dev);
|
||||
devc->opened = 0;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
set_speed (ad1848_info * devc, int arg)
|
||||
{
|
||||
/*
|
||||
* The sampling speed is encoded in the least significant nible of I8. The
|
||||
* LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
|
||||
* three bits select the divisor (indirectly):
|
||||
*
|
||||
* The available speeds are in the following table. Keep the speeds in
|
||||
* the increasing order.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int speed;
|
||||
unsigned char bits;
|
||||
}
|
||||
speed_struct;
|
||||
|
||||
static speed_struct speed_table[] =
|
||||
{
|
||||
{5510, (0 << 1) | 1},
|
||||
{5510, (0 << 1) | 1},
|
||||
{6620, (7 << 1) | 1},
|
||||
{8000, (0 << 1) | 0},
|
||||
{9600, (7 << 1) | 0},
|
||||
{11025, (1 << 1) | 1},
|
||||
{16000, (1 << 1) | 0},
|
||||
{18900, (2 << 1) | 1},
|
||||
{22050, (3 << 1) | 1},
|
||||
{27420, (2 << 1) | 0},
|
||||
{32000, (3 << 1) | 0},
|
||||
{33075, (6 << 1) | 1},
|
||||
{37800, (4 << 1) | 1},
|
||||
{44100, (5 << 1) | 1},
|
||||
{48000, (6 << 1) | 0}
|
||||
};
|
||||
|
||||
int i, n, selected = -1;
|
||||
|
||||
n = sizeof (speed_table) / sizeof (speed_struct);
|
||||
|
||||
if (arg < speed_table[0].speed)
|
||||
selected = 0;
|
||||
if (arg > speed_table[n - 1].speed)
|
||||
selected = n - 1;
|
||||
|
||||
for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
|
||||
if (speed_table[i].speed == arg)
|
||||
selected = i;
|
||||
else if (speed_table[i].speed > arg)
|
||||
{
|
||||
int diff1, diff2;
|
||||
|
||||
diff1 = arg - speed_table[i - 1].speed;
|
||||
diff2 = speed_table[i].speed - arg;
|
||||
|
||||
if (diff1 < diff2)
|
||||
selected = i - 1;
|
||||
else
|
||||
selected = i;
|
||||
}
|
||||
|
||||
if (selected == -1)
|
||||
{
|
||||
printk ("ad1848: Can't find speed???\n");
|
||||
selected = 3;
|
||||
}
|
||||
|
||||
devc->speed = speed_table[selected].speed;
|
||||
devc->speed_bits = speed_table[selected].bits;
|
||||
return devc->speed;
|
||||
}
|
||||
|
||||
static int
|
||||
set_channels (ad1848_info * devc, int arg)
|
||||
{
|
||||
if (arg != 1 && arg != 2)
|
||||
return devc->channels;
|
||||
|
||||
devc->channels = arg;
|
||||
return arg;
|
||||
}
|
||||
|
||||
static int
|
||||
set_format (ad1848_info * devc, int arg)
|
||||
{
|
||||
|
||||
static struct format_tbl
|
||||
{
|
||||
int format;
|
||||
unsigned char bits;
|
||||
}
|
||||
format2bits [] =
|
||||
{
|
||||
{
|
||||
0, 0
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_MU_LAW, 1
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_A_LAW, 3
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_IMA_ADPCM, 5
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_U8, 0
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_S16_LE, 2
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_S16_BE, 6
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_S8, 0
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_U16_LE, 0
|
||||
}
|
||||
,
|
||||
{
|
||||
AFMT_U16_BE, 0
|
||||
}
|
||||
};
|
||||
int i, n = sizeof (format2bits) / sizeof (struct format_tbl);
|
||||
|
||||
if (!(arg & ad_format_mask[devc->mode]))
|
||||
arg = AFMT_U8;
|
||||
|
||||
devc->audio_format = arg;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (format2bits[i].format == arg)
|
||||
{
|
||||
if ((devc->format_bits = format2bits[i].bits) == 0)
|
||||
return devc->audio_format = AFMT_U8; /* Was not supported */
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
/* Still hanging here. Something must be terribly wrong */
|
||||
devc->format_bits = 0;
|
||||
return devc->audio_format = AFMT_U8;
|
||||
}
|
||||
|
||||
static int
|
||||
ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
|
||||
{
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SOUND_PCM_WRITE_RATE:
|
||||
if (local)
|
||||
return set_speed (devc, arg);
|
||||
return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_RATE:
|
||||
if (local)
|
||||
return devc->speed;
|
||||
return IOCTL_OUT (arg, devc->speed);
|
||||
|
||||
case SNDCTL_DSP_STEREO:
|
||||
if (local)
|
||||
return set_channels (devc, arg + 1) - 1;
|
||||
return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1);
|
||||
|
||||
case SOUND_PCM_WRITE_CHANNELS:
|
||||
if (local)
|
||||
return set_channels (devc, arg);
|
||||
return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_CHANNELS:
|
||||
if (local)
|
||||
return devc->channels;
|
||||
return IOCTL_OUT (arg, devc->channels);
|
||||
|
||||
case SNDCTL_DSP_SAMPLESIZE:
|
||||
if (local)
|
||||
return set_format (devc, arg);
|
||||
return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg)));
|
||||
|
||||
case SOUND_PCM_READ_BITS:
|
||||
if (local)
|
||||
return devc->audio_format;
|
||||
return IOCTL_OUT (arg, devc->audio_format);
|
||||
|
||||
default:;
|
||||
}
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
cnt = count;
|
||||
|
||||
if (devc->audio_format == AFMT_IMA_ADPCM)
|
||||
{
|
||||
cnt /= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
|
||||
cnt >>= 1;
|
||||
}
|
||||
if (devc->channels > 1)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE &&
|
||||
intrflag &&
|
||||
cnt == devc->xfer_count)
|
||||
{
|
||||
devc->irq_mode = IMODE_OUTPUT;
|
||||
devc->intr_active = 1;
|
||||
return; /*
|
||||
* Auto DMA mode on. No need to react
|
||||
*/
|
||||
}
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (dma_restart)
|
||||
{
|
||||
ad1848_halt (dev);
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
|
||||
}
|
||||
|
||||
ad_set_MCE (devc, 1);
|
||||
|
||||
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
|
||||
ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
|
||||
|
||||
|
||||
ad_write (devc, 9, 0x0d); /*
|
||||
* Playback enable, single DMA channel mode,
|
||||
* auto calibration on.
|
||||
*/
|
||||
|
||||
ad_set_MCE (devc, 0); /*
|
||||
* Starts the calibration process and
|
||||
* enters playback mode after it.
|
||||
*/
|
||||
wait_for_calibration (devc);
|
||||
|
||||
devc->xfer_count = cnt;
|
||||
devc->irq_mode = IMODE_OUTPUT;
|
||||
devc->intr_active = 1;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
|
||||
{
|
||||
unsigned long flags, cnt;
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
/* int count_reg = (devc->mode == 1) ? 14 : 30; */
|
||||
|
||||
cnt = count;
|
||||
if (devc->audio_format == AFMT_IMA_ADPCM)
|
||||
{
|
||||
cnt /= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
|
||||
cnt >>= 1;
|
||||
}
|
||||
if (devc->channels > 1)
|
||||
cnt >>= 1;
|
||||
cnt--;
|
||||
|
||||
if (audio_devs[dev]->flags & DMA_AUTOMODE &&
|
||||
intrflag &&
|
||||
cnt == devc->xfer_count)
|
||||
{
|
||||
devc->irq_mode = IMODE_INPUT;
|
||||
devc->intr_active = 1;
|
||||
return; /*
|
||||
* Auto DMA mode on. No need to react
|
||||
*/
|
||||
}
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (dma_restart)
|
||||
{
|
||||
ad1848_halt (dev);
|
||||
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
|
||||
}
|
||||
|
||||
ad_set_MCE (devc, 1);
|
||||
#if 0
|
||||
ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff));
|
||||
ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff));
|
||||
#else
|
||||
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
|
||||
ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
|
||||
if (devc->mode == 2)
|
||||
{
|
||||
ad_write (devc, 31, (unsigned char) (cnt & 0xff));
|
||||
ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff));
|
||||
}
|
||||
#endif
|
||||
|
||||
ad_write (devc, 9, 0x0e); /*
|
||||
* Capture enable, single DMA channel mode,
|
||||
* auto calibration on.
|
||||
*/
|
||||
|
||||
ad_set_MCE (devc, 0); /*
|
||||
* Starts the calibration process and
|
||||
* enters playback mode after it.
|
||||
*/
|
||||
wait_for_calibration (devc);
|
||||
|
||||
devc->xfer_count = cnt;
|
||||
devc->irq_mode = IMODE_INPUT;
|
||||
devc->intr_active = 1;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
ad1848_prepare_for_IO (int dev, int bsize, int bcount)
|
||||
{
|
||||
int timeout;
|
||||
unsigned char fs;
|
||||
unsigned long flags;
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
ad_set_MCE (devc, 1); /* Enables changes to the format select reg */
|
||||
fs = devc->speed_bits | (devc->format_bits << 5);
|
||||
|
||||
if (devc->channels > 1)
|
||||
fs |= 0x10;
|
||||
|
||||
ad_write (devc, 8, fs);
|
||||
/*
|
||||
* Write to I8 starts resyncronization. Wait until it completes.
|
||||
*/
|
||||
timeout = 10000;
|
||||
while (timeout > 0 && INB (devc->base) == 0x80)
|
||||
timeout--;
|
||||
|
||||
ad_set_MCE (devc, 0); /*
|
||||
* Starts the calibration process and
|
||||
* enters playback mode after it.
|
||||
*/
|
||||
wait_for_calibration (devc);
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* If mode == 2 (CS4231), set I28 also. It's the capture format register.
|
||||
*/
|
||||
if (devc->mode == 2)
|
||||
{
|
||||
ad_set_MCE (devc, 1);
|
||||
ad_write (devc, 28, fs);
|
||||
|
||||
/*
|
||||
* Write to I28 starts resyncronization. Wait until it completes.
|
||||
*/
|
||||
timeout = 10000;
|
||||
while (timeout > 0 && INB (devc->base) == 0x80)
|
||||
timeout--;
|
||||
|
||||
ad_set_MCE (devc, 0); /*
|
||||
* Starts the calibration process and
|
||||
* enters playback mode after it.
|
||||
*/
|
||||
wait_for_calibration (devc);
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
devc->xfer_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_reset (int dev)
|
||||
{
|
||||
ad1848_halt (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
ad1848_halt (int dev)
|
||||
{
|
||||
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
|
||||
ad_write (devc, 9, 0); /* Clear the PEN and CEN bits (among others) */
|
||||
OUTB (0, io_Status (devc)); /* Clear interrupt status */
|
||||
}
|
||||
|
||||
int
|
||||
ad1848_detect (int io_base)
|
||||
{
|
||||
|
||||
#define DDB(x) x
|
||||
|
||||
unsigned char tmp;
|
||||
int i;
|
||||
ad1848_info *devc = &dev_info[nr_ad1848_devs];
|
||||
unsigned char tmp1 = 0xff, tmp2 = 0xff;
|
||||
|
||||
if (nr_ad1848_devs >= MAX_AUDIO_DEV)
|
||||
return 0;
|
||||
|
||||
devc->base = io_base;
|
||||
devc->MCE_bit = 0x40;
|
||||
devc->irq = 0;
|
||||
devc->dma_capture = 0;
|
||||
devc->dma_playback = 0;
|
||||
devc->opened = 0;
|
||||
devc->chip_name = "AD1848";
|
||||
devc->mode = 1; /* MODE1 = original AD1848 */
|
||||
|
||||
/*
|
||||
* Check that the I/O address is in use.
|
||||
*
|
||||
* The bit 0x80 of the base I/O port is known to be 0 after the
|
||||
* chip has performed it's power on initialization. Just assume
|
||||
* this has happened before the OS is starting.
|
||||
*
|
||||
* If the I/O address is unused, it typically returns 0xff.
|
||||
*/
|
||||
|
||||
if ((INB (devc->base) & 0x80) != 0x00) /* Not a AD1884 */
|
||||
{
|
||||
DDB (printk ("ad_detect_A\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if it's possible to change contents of the indirect registers.
|
||||
* Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
|
||||
* so try to avoid using it.
|
||||
*/
|
||||
|
||||
ad_write (devc, 0, 0xaa);
|
||||
ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */
|
||||
|
||||
if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45)
|
||||
{
|
||||
DDB (printk ("ad_detect_B (%x/%x)\n", tmp1, tmp2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ad_write (devc, 0, 0x45);
|
||||
ad_write (devc, 1, 0xaa);
|
||||
|
||||
if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa)
|
||||
{
|
||||
DDB (printk ("ad_detect_C (%x/%x)\n", tmp1, tmp2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The indirect register I12 has some read only bits. Lets
|
||||
* try to change them.
|
||||
*/
|
||||
|
||||
tmp = ad_read (devc, 12);
|
||||
ad_write (devc, 12, (~tmp) & 0x0f);
|
||||
|
||||
if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f))
|
||||
{
|
||||
DDB (printk ("ad_detect_D (%x)\n", tmp1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE! Last 4 bits of the reg I12 tell the chip revision.
|
||||
* 0x01=RevB and 0x0A=RevC.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The original AD1848/CS4248 has just 15 indirect registers. This means
|
||||
* that I0 and I16 should return the same value (etc.).
|
||||
* Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
|
||||
* with CS4231.
|
||||
*/
|
||||
|
||||
ad_write (devc, 12, 0); /* Mode2=disabled */
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16)))
|
||||
{
|
||||
DDB (printk ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
|
||||
* The bit 0x80 is always 1 in CS4248 and CS4231.
|
||||
*/
|
||||
|
||||
ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
|
||||
|
||||
tmp1 = ad_read (devc, 12);
|
||||
if (tmp1 & 0x80)
|
||||
devc->chip_name = "CS4248";
|
||||
|
||||
if ((tmp1 & 0xc0) == (0x80 | 0x40))
|
||||
{
|
||||
/*
|
||||
* CS4231 detected - is it?
|
||||
*
|
||||
* Verify that setting I0 doesn't change I16.
|
||||
*/
|
||||
ad_write (devc, 16, 0); /* Set I16 to known value */
|
||||
|
||||
ad_write (devc, 0, 0x45);
|
||||
if ((tmp1 = ad_read (devc, 16)) != 0x45) /* No change -> CS4231? */
|
||||
{
|
||||
|
||||
ad_write (devc, 0, 0xaa);
|
||||
if ((tmp1 = ad_read (devc, 16)) == 0xaa) /* Rotten bits? */
|
||||
{
|
||||
DDB (printk ("ad_detect_H(%x)\n", tmp1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's a CS4231 - So what!
|
||||
* (Mode2 will be supported later)
|
||||
*/
|
||||
devc->chip_name = "CS4231";
|
||||
devc->mode = 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture)
|
||||
{
|
||||
/*
|
||||
* NOTE! If irq < 0, there is another driver which has allocated the IRQ
|
||||
* so that this driver doesn't need to allocate/deallocate it.
|
||||
* The actually used IRQ is ABS(irq).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initial values for the indirect registers of CS4248/AD1848.
|
||||
*/
|
||||
static int init_values[] =
|
||||
{
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
|
||||
0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00
|
||||
};
|
||||
int i, my_dev;
|
||||
ad1848_info *devc = &dev_info[nr_ad1848_devs];
|
||||
|
||||
if (!ad1848_detect (io_base))
|
||||
return;
|
||||
|
||||
devc->irq = (irq > 0) ? irq : 0;
|
||||
devc->dma_capture = dma_playback;
|
||||
devc->dma_playback = dma_capture;
|
||||
devc->opened = 0;
|
||||
|
||||
if (nr_ad1848_devs != 0)
|
||||
{
|
||||
memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs],
|
||||
(char *) &ad1848_pcm_operations[0],
|
||||
sizeof (struct audio_operations));
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
ad_write (devc, i, init_values[i]);
|
||||
|
||||
OUTB (0, io_Status (devc)); /* Clear pending interrupts */
|
||||
|
||||
#ifndef SCO
|
||||
sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
|
||||
"%s (%s)", name, devc->chip_name);
|
||||
#endif
|
||||
|
||||
if (irq > 0)
|
||||
printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
|
||||
|
||||
if (num_audiodevs < MAX_AUDIO_DEV)
|
||||
{
|
||||
audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs];
|
||||
if (irq > 0)
|
||||
irq2dev[irq] = my_dev;
|
||||
else if (irq < 0)
|
||||
irq2dev[-irq] = my_dev;
|
||||
|
||||
audio_devs[my_dev]->dmachan = dma_playback;
|
||||
audio_devs[my_dev]->buffcount = 1;
|
||||
audio_devs[my_dev]->buffsize = DSP_BUFFSIZE * 2;
|
||||
audio_devs[my_dev]->devc = devc;
|
||||
audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
|
||||
nr_ad1848_devs++;
|
||||
}
|
||||
else
|
||||
printk ("AD1848: Too many PCM devices available\n");
|
||||
}
|
||||
|
||||
void
|
||||
ad1848_interrupt (int irq)
|
||||
{
|
||||
unsigned char status;
|
||||
ad1848_info *devc;
|
||||
int dev;
|
||||
|
||||
if (irq < 0 || irq > 15)
|
||||
return; /* Bogus irq */
|
||||
dev = irq2dev[irq];
|
||||
if (dev < 0 || dev >= num_audiodevs)
|
||||
return; /* Bogus dev */
|
||||
|
||||
devc = (ad1848_info *) audio_devs[dev]->devc;
|
||||
status = INB (io_Status (devc));
|
||||
|
||||
if (status & 0x01)
|
||||
{
|
||||
if (devc->opened && devc->irq_mode == IMODE_OUTPUT)
|
||||
{
|
||||
DMAbuf_outputintr (dev, 1);
|
||||
}
|
||||
|
||||
if (devc->opened && devc->irq_mode == IMODE_INPUT)
|
||||
DMAbuf_inputintr (dev);
|
||||
}
|
||||
|
||||
OUTB (0, io_Status (devc)); /* Clear interrupt status */
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Some extra code for the MS Sound System
|
||||
*/
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS)
|
||||
|
||||
int
|
||||
probe_ms_sound (struct address_info *hw_config)
|
||||
{
|
||||
if ((INB (hw_config->io_base + 3) & 0x04) == 0)
|
||||
return 0; /* WSS ID test failed */
|
||||
|
||||
if (hw_config->irq > 11)
|
||||
return 0;
|
||||
|
||||
if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
|
||||
return 0;
|
||||
|
||||
return ad1848_detect (hw_config->io_base + 4);
|
||||
}
|
||||
|
||||
long
|
||||
attach_ms_sound (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
static unsigned char interrupt_bits[12] =
|
||||
{-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
|
||||
char bits;
|
||||
|
||||
static unsigned char dma_bits[4] = {1, 2, 0, 3};
|
||||
|
||||
int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
|
||||
|
||||
if (!ad1848_detect (hw_config->io_base + 4))
|
||||
return mem_start;
|
||||
|
||||
/*
|
||||
* Set the IRQ and DMA addresses.
|
||||
*/
|
||||
|
||||
bits = interrupt_bits[hw_config->irq];
|
||||
if (bits == -1)
|
||||
return mem_start;
|
||||
|
||||
OUTB (bits | 0x40, config_port); /* Verify IRQ (I guess) */
|
||||
if ((INB (version_port) & 0x40) == 0)
|
||||
printk ("[IRQ?]");
|
||||
|
||||
OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */
|
||||
|
||||
ad1848_init ("MS Sound System", hw_config->io_base + 4,
|
||||
hw_config->irq,
|
||||
hw_config->dma,
|
||||
hw_config->dma);
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
830
sys/i386/isa/sound/configure.c
Normal file
830
sys/i386/isa/sound/configure.c
Normal file
@ -0,0 +1,830 @@
|
||||
/*
|
||||
* sound/configure.c - Configuration program for the Linux Sound Driver
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define B(x) (1 << (x))
|
||||
|
||||
/*
|
||||
* Option numbers
|
||||
*/
|
||||
|
||||
#define OPT_PAS 0
|
||||
#define OPT_SB 1
|
||||
#define OPT_ADLIB 2
|
||||
#define OPT_LAST_MUTUAL 2
|
||||
|
||||
#define OPT_GUS 3
|
||||
#define OPT_MPU401 4
|
||||
#define OPT_UART6850 5
|
||||
#define OPT_PSS 6
|
||||
#define OPT_GUS16 7
|
||||
#define OPT_GUSMAX 8
|
||||
#define OPT_MSS 9
|
||||
|
||||
#define OPT_HIGHLEVEL 10 /* This must be same than the next one */
|
||||
#define OPT_SBPRO 10
|
||||
#define OPT_SB16 11
|
||||
#define OPT_AUDIO 12
|
||||
#define OPT_MIDI_AUTO 13
|
||||
#define OPT_MIDI 14
|
||||
#define OPT_YM3812_AUTO 15
|
||||
#define OPT_YM3812 16
|
||||
#define OPT_SEQUENCER 17
|
||||
#define OPT_LAST 17 /* Must be the same than the defined OPT */
|
||||
|
||||
#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \
|
||||
B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)|B(OPT_MSS))
|
||||
/*
|
||||
* Options that have been disabled for some reason (incompletely implemented
|
||||
* and/or tested). Don't remove from this list before looking at file
|
||||
* experimental.txt for further info.
|
||||
*/
|
||||
#define DISABLED_OPTIONS (B(OPT_PSS))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long conditions;
|
||||
unsigned long exclusive_options;
|
||||
char macro[20];
|
||||
int verify;
|
||||
int alias;
|
||||
int default_answ;
|
||||
}
|
||||
|
||||
hw_entry;
|
||||
|
||||
|
||||
/*
|
||||
* The rule table for the driver options. The first field defines a set of
|
||||
* options which must be selected before this entry can be selected. The
|
||||
* second field is a set of options which are not allowed with this one. If
|
||||
* the fourth field is zero, the option is selected without asking
|
||||
* confirmation from the user.
|
||||
*
|
||||
* With this version of the rule table it is possible to select just one type of
|
||||
* hardware.
|
||||
*
|
||||
* NOTE! Keep the following table and the questions array in sync with the
|
||||
* option numbering!
|
||||
*/
|
||||
|
||||
hw_entry hw_table[] =
|
||||
{
|
||||
/*
|
||||
* 0
|
||||
*/
|
||||
{0, 0, "PAS", 1, 0, 0},
|
||||
{0, 0, "SB", 1, 0, 0},
|
||||
{0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0, 0},
|
||||
|
||||
{0, 0, "GUS", 1, 0, 0},
|
||||
{0, 0, "MPU401", 1, 0, 0},
|
||||
{0, 0, "UART6850", 1, 0, 0},
|
||||
{0, 0, "PSS", 1, 0, 0},
|
||||
{B (OPT_GUS), 0, "GUS16", 1, 0, 0},
|
||||
{B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0},
|
||||
{0, 0, "MSS", 1, 0, 0},
|
||||
|
||||
{B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1},
|
||||
{B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1},
|
||||
{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1},
|
||||
{B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
|
||||
{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1},
|
||||
{B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
|
||||
{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
|
||||
{B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}
|
||||
};
|
||||
|
||||
char *questions[] =
|
||||
{
|
||||
"ProAudioSpectrum 16 support",
|
||||
"SoundBlaster support",
|
||||
"AdLib support",
|
||||
"Gravis Ultrasound support",
|
||||
"MPU-401 support (NOT for SB16)",
|
||||
"6850 UART Midi support",
|
||||
"PSS (ECHO-ADI2111) support",
|
||||
"16 bit sampling option of GUS (_NOT_ GUS MAX)",
|
||||
"GUS MAX support",
|
||||
"Microsoft Sound System support",
|
||||
|
||||
"SoundBlaster Pro support",
|
||||
"SoundBlaster 16 support",
|
||||
"digitized voice support",
|
||||
"This should not be asked",
|
||||
"MIDI interface support",
|
||||
"This should not be asked",
|
||||
"FM synthesizer (YM3812/OPL-3) support",
|
||||
"/dev/sequencer support",
|
||||
"Should I die"
|
||||
};
|
||||
|
||||
unsigned long selected_options = 0;
|
||||
int sb_dma = 0;
|
||||
|
||||
int
|
||||
can_select_option (int nr)
|
||||
{
|
||||
switch (nr)
|
||||
{
|
||||
case 0:
|
||||
fprintf (stderr, "The SoundBlaster, AdLib and ProAudioSpectrum\n"
|
||||
"CARDS cannot be installed at the same time.\n\n"
|
||||
"However the PAS16 has a SB emulator so you could select"
|
||||
"the SoundBlaster DRIVER with it.\n");
|
||||
fprintf (stderr, " - ProAudioSpectrum 16\n");
|
||||
fprintf (stderr, " - SoundBlaster / SB Pro\n");
|
||||
fprintf (stderr, " (Could be selected with a PAS16 also)\n");
|
||||
fprintf (stderr, " - AdLib\n");
|
||||
fprintf (stderr, "\nDon't enable SoundBlaster if you have GUS at 0x220!\n\n");
|
||||
break;
|
||||
|
||||
case OPT_LAST_MUTUAL + 1:
|
||||
fprintf (stderr, "\nThe following cards should work with any other cards.\n"
|
||||
"CAUTION! Don't enable MPU-401 if you don't have it.\n");
|
||||
break;
|
||||
|
||||
case OPT_HIGHLEVEL:
|
||||
fprintf (stderr, "\nSelect one or more of the following options\n");
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (hw_table[nr].conditions)
|
||||
if (!(hw_table[nr].conditions & selected_options))
|
||||
return 0;
|
||||
|
||||
if (hw_table[nr].exclusive_options)
|
||||
if (hw_table[nr].exclusive_options & selected_options)
|
||||
return 0;
|
||||
|
||||
if (DISABLED_OPTIONS & B (nr))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
think_positively (int def_answ)
|
||||
{
|
||||
char answ[512];
|
||||
int len;
|
||||
|
||||
if ((len = read (0, &answ, sizeof (answ))) < 1)
|
||||
{
|
||||
fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
|
||||
|
||||
perror ("stdin");
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
if (len < 2) /*
|
||||
* There is an additional LF at the end
|
||||
*/
|
||||
return def_answ;
|
||||
|
||||
answ[len - 1] = 0;
|
||||
|
||||
if (!strcmp (answ, "y") || !strcmp (answ, "Y"))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ask_value (char *format, int default_answer)
|
||||
{
|
||||
char answ[512];
|
||||
int len, num;
|
||||
|
||||
play_it_again_Sam:
|
||||
|
||||
if ((len = read (0, &answ, sizeof (answ))) < 1)
|
||||
{
|
||||
fprintf (stderr, "\n\nERROR! Cannot read stdin\n");
|
||||
|
||||
perror ("stdin");
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
if (len < 2) /*
|
||||
* There is an additional LF at the end
|
||||
*/
|
||||
return default_answer;
|
||||
|
||||
answ[len - 1] = 0;
|
||||
|
||||
if (sscanf (answ, format, &num) != 1)
|
||||
{
|
||||
fprintf (stderr, "Illegal format. Try again: ");
|
||||
goto play_it_again_Sam;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int i, num, def_size, full_driver = 1;
|
||||
char answ[10];
|
||||
|
||||
printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n\n");
|
||||
|
||||
fprintf (stderr, "\nConfiguring the sound support\n\n");
|
||||
|
||||
fprintf (stderr, "Do you want to include full version of the sound driver (n/y) ? ");
|
||||
|
||||
if (think_positively (0))
|
||||
{
|
||||
/*
|
||||
* Select all but some most dangerous cards. These cards are difficult to
|
||||
* detect reliably or conflict with some other cards (SCSI, Mitsumi)
|
||||
*/
|
||||
selected_options = 0xffffffff &
|
||||
~(B (OPT_MPU401) | B (OPT_UART6850) | B (OPT_PSS)) &
|
||||
~DISABLED_OPTIONS;
|
||||
|
||||
fprintf (stderr, "Note! MPU-401, PSS and 6850 UART drivers not enabled\n");
|
||||
full_driver = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Do you want to DISABLE the Sound Driver (n/y) ?");
|
||||
if (think_positively (0))
|
||||
{
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
exit (0);
|
||||
}
|
||||
/*
|
||||
* Partial driver
|
||||
*/
|
||||
|
||||
full_driver = 0;
|
||||
|
||||
for (i = 0; i <= OPT_LAST; i++)
|
||||
if (can_select_option (i))
|
||||
{
|
||||
if (!(selected_options & B (i))) /*
|
||||
* Not selected yet
|
||||
*/
|
||||
if (!hw_table[i].verify)
|
||||
{
|
||||
if (hw_table[i].alias)
|
||||
selected_options |= B (hw_table[i].alias);
|
||||
else
|
||||
selected_options |= B (i);
|
||||
}
|
||||
else
|
||||
{
|
||||
int def_answ = hw_table[i].default_answ;
|
||||
|
||||
fprintf (stderr,
|
||||
def_answ ? " %s (y/n) ? " : " %s (n/y) ? ",
|
||||
questions[i]);
|
||||
if (think_positively (def_answ))
|
||||
if (hw_table[i].alias)
|
||||
selected_options |= B (hw_table[i].alias);
|
||||
else
|
||||
selected_options |= B (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_SBPRO))
|
||||
{
|
||||
fprintf(stderr, "Do you want support for the mixer of SG NX Pro ? ");
|
||||
if (think_positively (0))
|
||||
printf("#define __SGNXPRO__\n");
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_SB16))
|
||||
selected_options |= B (OPT_SBPRO);
|
||||
|
||||
if (selected_options & B (OPT_PSS))
|
||||
{
|
||||
genld_again:
|
||||
fprintf
|
||||
(stderr,
|
||||
"if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n"
|
||||
"then you must include the LD in the kernel.\n"
|
||||
"(do you wish to include a LD) ? ");
|
||||
if (think_positively (0))
|
||||
{
|
||||
char path[512];
|
||||
|
||||
fprintf (stderr,
|
||||
"Enter the path to your LD file (pwd is sound): ");
|
||||
scanf ("%s", path);
|
||||
fprintf (stderr, "including LD file %s\n", path);
|
||||
selected_options |= B (OPT_SB) | B (OPT_MPU401) | B (OPT_ADLIB);
|
||||
|
||||
/* Gen LD header */
|
||||
{
|
||||
int fd;
|
||||
int count;
|
||||
char c;
|
||||
int i = 0;
|
||||
|
||||
if ((fd = open (path, 0)) > 0)
|
||||
{
|
||||
FILE *sf = fopen ("synth-ld.h", "w");
|
||||
|
||||
fprintf (sf, "/* automaticaly generated by configure */\n");
|
||||
fprintf (sf, "unsigned char pss_synth[] = {\n");
|
||||
while (1)
|
||||
{
|
||||
count = read (fd, &c, 1);
|
||||
if (count == 0)
|
||||
break;
|
||||
if (i != 0 && (i % 10) == 0)
|
||||
fprintf (sf, "\n");
|
||||
fprintf (sf, "0x%02x,", c & 0xFFL);
|
||||
i++;
|
||||
}
|
||||
fprintf (sf, "};\n"
|
||||
"#define pss_synthLen %d\n", i);
|
||||
fclose (sf);
|
||||
close (fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "couldn't open %s as the ld file\n",
|
||||
path);
|
||||
fprintf (stderr, "try again with correct path? ");
|
||||
if (think_positively (1))
|
||||
goto genld_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *sf = fopen ("synth-ld.h", "w");
|
||||
|
||||
fprintf (sf, "/* automaticaly generated by configure */\n");
|
||||
fprintf (sf, "unsigned char pss_synth[1];\n"
|
||||
"#define pss_synthLen 0\n");
|
||||
fclose (sf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(selected_options & ANY_DEVS))
|
||||
{
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n\n");
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
printf ("#define KERNEL_SOUNDCARD\n");
|
||||
|
||||
for (i = 0; i <= OPT_LAST; i++)
|
||||
if (!hw_table[i].alias)
|
||||
if (selected_options & B (i))
|
||||
printf ("#undef EXCLUDE_%s\n", hw_table[i].macro);
|
||||
else
|
||||
printf ("#define EXCLUDE_%s\n", hw_table[i].macro);
|
||||
|
||||
|
||||
/*
|
||||
* IRQ and DMA settings
|
||||
*/
|
||||
printf ("\n");
|
||||
|
||||
#if defined(linux)
|
||||
if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for SB?\n"
|
||||
"The factory default is 220\n"
|
||||
"Enter the SB I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x220);
|
||||
fprintf (stderr, "SB I/O base set to %03x\n", num);
|
||||
printf ("#define SBC_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for SoundBlaster?\n"
|
||||
"The IRQ address is defined by the jumpers on your card.\n"
|
||||
"The factory default is either 5 or 7 (depending on the model).\n"
|
||||
"Valid values are 9(=2), 5, 7 and 10.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 7);
|
||||
if (num != 9 && num != 5 && num != 7 && num != 10)
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 7;
|
||||
}
|
||||
fprintf (stderr, "SoundBlaster IRQ set to %d\n", num);
|
||||
|
||||
printf ("#define SBC_IRQ %d\n", num);
|
||||
|
||||
if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_PSS)))
|
||||
{
|
||||
fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
|
||||
"For SB 1.0, 1.5 and 2.0 this MUST be 1\n"
|
||||
"SB Pro supports DMA channels 0, 1 and 3 (jumper)\n"
|
||||
"For SB16 give the 8 bit DMA# here\n"
|
||||
"The default value is 1\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 1);
|
||||
if (num < 0 || num > 3)
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 1;
|
||||
}
|
||||
fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
|
||||
printf ("#define SBC_DMA %d\n", num);
|
||||
sb_dma = num;
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_SB16))
|
||||
{
|
||||
|
||||
fprintf (stderr, "\n16 bit DMA channel for SoundBlaster 16?\n"
|
||||
"Possible values are 5, 6 or 7\n"
|
||||
"The default value is 6\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 6);
|
||||
if ((num < 5 || num > 7) && (num != sb_dma))
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 6;
|
||||
}
|
||||
fprintf (stderr, "SoundBlaster DMA set to %d\n", num);
|
||||
printf ("#define SB16_DMA %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nI/O base for SB16 Midi?\n"
|
||||
"Possible values are 300 and 330\n"
|
||||
"The factory default is 330\n"
|
||||
"Enter the SB16 Midi I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x330);
|
||||
fprintf (stderr, "SB16 Midi I/O base set to %03x\n", num);
|
||||
printf ("#define SB16MIDI_BASE 0x%03x\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_PAS))
|
||||
{
|
||||
if (selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
|
||||
{
|
||||
fprintf (stderr, "\nIRQ number for ProAudioSpectrum?\n"
|
||||
"The recommended value is the IRQ used under DOS.\n"
|
||||
"Please refer to the ProAudioSpectrum User's Guide.\n"
|
||||
"The default value is 10.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 10);
|
||||
if (num == 6 || num < 3 || num > 15 || num == 2) /*
|
||||
* Illegal
|
||||
*/
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 10;
|
||||
}
|
||||
fprintf (stderr, "ProAudioSpectrum IRQ set to %d\n", num);
|
||||
printf ("#define PAS_IRQ %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_AUDIO))
|
||||
{
|
||||
fprintf (stderr, "\nDMA number for ProAudioSpectrum?\n"
|
||||
"The recommended value is the DMA channel under DOS.\n"
|
||||
"Please refer to the ProAudioSpectrum User's Guide.\n"
|
||||
"The default value is 3\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 3);
|
||||
if (num == 4 || num < 0 || num > 7)
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 3;
|
||||
}
|
||||
fprintf (stderr, "\nProAudioSpectrum DMA set to %d\n", num);
|
||||
printf ("#define PAS_DMA %d\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_GUS))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for Gravis Ultrasound?\n"
|
||||
"Valid choices are 210, 220, 230, 240, 250 or 260\n"
|
||||
"The factory default is 220\n"
|
||||
"Enter the GUS I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x220);
|
||||
if ((num > 0x260) || ((num & 0xf0f) != 0x200) || ((num & 0x0f0) > 0x060))
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 0x220;
|
||||
}
|
||||
|
||||
if ((selected_options & B (OPT_SB)) && (num == 0x220))
|
||||
{
|
||||
fprintf (stderr, "FATAL ERROR!!!!!!!!!!!!!!\n"
|
||||
"\t0x220 cannot be used if SoundBlaster is enabled.\n"
|
||||
"\tRun the config again.\n");
|
||||
printf ("#undef CONFIGURE_SOUNDCARD\n");
|
||||
printf ("#undef KERNEL_SOUNDCARD\n");
|
||||
exit (-1);
|
||||
}
|
||||
fprintf (stderr, "GUS I/O base set to %03x\n", num);
|
||||
printf ("#define GUS_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for Gravis UltraSound?\n"
|
||||
"The recommended value is the IRQ used under DOS.\n"
|
||||
"Please refer to the Gravis Ultrasound User's Guide.\n"
|
||||
"The default value is 15.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 15);
|
||||
if (num == 6 || num < 3 || num > 15 || num == 2) /*
|
||||
* Invalid
|
||||
*/
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 15;
|
||||
}
|
||||
fprintf (stderr, "Gravis UltraSound IRQ set to %d\n", num);
|
||||
printf ("#define GUS_IRQ %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nDMA number for Gravis UltraSound?\n"
|
||||
"The recommended value is the DMA channel under DOS.\n"
|
||||
"Please refer to the Gravis Ultrasound User's Guide.\n"
|
||||
"The default value is 6\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 6);
|
||||
if (num == 4 || num < 0 || num > 7)
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 6;
|
||||
}
|
||||
fprintf (stderr, "\nGravis UltraSound DMA set to %d\n", num);
|
||||
printf ("#define GUS_DMA %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_MPU401))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for MPU-401?\n"
|
||||
"The factory default is 330\n"
|
||||
"Enter the MPU-401 I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x330);
|
||||
fprintf (stderr, "MPU-401 I/O base set to %03x\n", num);
|
||||
printf ("#define MPU_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for MPU-401?\n"
|
||||
"Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
|
||||
"The default value is 9.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 9);
|
||||
if (num == 6 || num < 3 || num > 15) /*
|
||||
* Used for floppy
|
||||
*/
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 5;
|
||||
}
|
||||
fprintf (stderr, "MPU-401 IRQ set to %d\n", num);
|
||||
printf ("#define MPU_IRQ %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_UART6850))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for 6850 UART Midi?\n"
|
||||
"Be carefull. No defaults.\n"
|
||||
"Enter the 6850 UART I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0);
|
||||
if (num == 0)
|
||||
{
|
||||
/*
|
||||
* Invalid value entered
|
||||
*/
|
||||
printf ("#define EXCLUDE_UART6850\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "6850 UART I/O base set to %03x\n", num);
|
||||
printf ("#define U6850_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for 6850 UART?\n"
|
||||
"Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
|
||||
"The default value is 5.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 5);
|
||||
if (num == 6 || num < 3 || num > 15) /*
|
||||
* Used for floppy
|
||||
*/
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 5;
|
||||
}
|
||||
fprintf (stderr, "6850 UART IRQ set to %d\n", num);
|
||||
printf ("#define U6850_IRQ %d\n", num);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_PSS))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for PSS?\n"
|
||||
"The factory default is 220\n"
|
||||
"Enter the PSS I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x220);
|
||||
fprintf (stderr, "PSS I/O base set to %03x\n", num);
|
||||
printf ("#define PSS_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for PSS?\n"
|
||||
"Valid numbers are: 3, 4, 5, 7, 9(=2) or 10.\n"
|
||||
"The default value is 10.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 10);
|
||||
if (num == 6 || num < 3 || num > 15) /* Used for floppy */
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 7;
|
||||
}
|
||||
fprintf (stderr, "PSS IRQ set to %d\n", num);
|
||||
printf ("#define PSS_IRQ %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nDMA number for ECHO-PSS?\n"
|
||||
"The default value is 3\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 3);
|
||||
if (num == 4 || num < 0 || num > 7)
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 3;
|
||||
}
|
||||
fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num);
|
||||
printf ("#define PSS_DMA %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_MSS))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for MSS (MS Sound System)?\n"
|
||||
"The factory default is 530\n"
|
||||
"Other possible values are 604, E80 or F40\n"
|
||||
"Enter the MSS I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x530);
|
||||
fprintf (stderr, "MSS I/O base set to %03x\n", num);
|
||||
printf ("#define MSS_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for MSS?\n"
|
||||
"Valid numbers are: 7, 9(=2), 10 and 11.\n"
|
||||
"The default value is 10.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 10);
|
||||
if (num == 6 || num < 3 || num > 15) /* Used for floppy */
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 7;
|
||||
}
|
||||
fprintf (stderr, "MSS IRQ set to %d\n", num);
|
||||
printf ("#define MSS_IRQ %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nDMA number for MSS?\n"
|
||||
"Valid values are 1 and 3 (sometimes 0)"
|
||||
"The default value is 3\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 3);
|
||||
if (num == 4 || num < 0 || num > 7)
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 3;
|
||||
}
|
||||
fprintf (stderr, "\nMSS DMA set to %d\n", num);
|
||||
printf ("#define MSS_DMA %d\n", num);
|
||||
}
|
||||
|
||||
if (selected_options & B (OPT_GUS16))
|
||||
{
|
||||
fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n"
|
||||
"The factory default is 530\n"
|
||||
"Other possible values are 604, E80 or F40\n"
|
||||
"Enter the GUS16 I/O base: ");
|
||||
|
||||
num = ask_value ("%x", 0x530);
|
||||
fprintf (stderr, "GUS16 I/O base set to %03x\n", num);
|
||||
printf ("#define GUS16_BASE 0x%03x\n", num);
|
||||
|
||||
fprintf (stderr, "\nIRQ number for GUS16?\n"
|
||||
"Valid numbers are: 3, 4, 5, 7, or 9(=2).\n"
|
||||
"The default value is 7.\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 7);
|
||||
if (num == 6 || num < 3 || num > 15) /* Used for floppy */
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 7;
|
||||
}
|
||||
fprintf (stderr, "GUS16 IRQ set to %d\n", num);
|
||||
printf ("#define GUS16_IRQ %d\n", num);
|
||||
|
||||
fprintf (stderr, "\nDMA number for GUS16?\n"
|
||||
"The default value is 3\n"
|
||||
"Enter the value: ");
|
||||
|
||||
num = ask_value ("%d", 3);
|
||||
if (num < 0 || num > 3)
|
||||
{
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = 3;
|
||||
}
|
||||
fprintf (stderr, "\nGUS16 DMA set to %d\n", num);
|
||||
printf ("#define GUS16_DMA %d\n", num);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (selected_options & B (OPT_AUDIO))
|
||||
{
|
||||
def_size = 16384;
|
||||
|
||||
if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_SB16)))
|
||||
def_size = 32768;
|
||||
|
||||
#ifndef __386BSD__
|
||||
if ((selected_options & (B (OPT_PAS) | B (OPT_PAS) | B (OPT_GUS16) | B (OPT_GUSMAX) |
|
||||
B (OPT_MSS) | B (OPT_PSS))) &&
|
||||
!full_driver)
|
||||
def_size = 65536; /*
|
||||
* PAS16 or SB16
|
||||
*/
|
||||
#endif
|
||||
|
||||
fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n"
|
||||
"%d is recommended value for this configuration.\n"
|
||||
"Enter the value: ", def_size);
|
||||
|
||||
num = ask_value ("%d", def_size);
|
||||
if (num != 4096 && num != 16384 && num != 32768 && num != 65536)
|
||||
{
|
||||
|
||||
fprintf (stderr, "*** Illegal input! ***\n");
|
||||
num = def_size;
|
||||
}
|
||||
fprintf (stderr, "The DMA buffer size set to %d\n", num);
|
||||
printf ("#define DSP_BUFFSIZE %d\n", num);
|
||||
}
|
||||
|
||||
printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
|
||||
fprintf (stderr, "The sound driver is now configured.\n");
|
||||
|
||||
#if defined(SCO) || defined(ISC) || defined(SYSV)
|
||||
fprintf (stderr, "Remember to update the System file\n");
|
||||
#endif
|
||||
|
||||
exit (0);
|
||||
}
|
22
sys/i386/isa/sound/midi_ctrl.h
Normal file
22
sys/i386/isa/sound/midi_ctrl.h
Normal file
@ -0,0 +1,22 @@
|
||||
static unsigned char ctrl_def_values[128] =
|
||||
{
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 0 to 7 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 8 to 15 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 16 to 23 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 24 to 31 */
|
||||
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 32 to 39 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 40 to 47 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 48 to 55 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 56 to 63 */
|
||||
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 64 to 71 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 72 to 79 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 80 to 87 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 88 to 95 */
|
||||
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 96 to 103 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 104 to 111 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 112 to 119 */
|
||||
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 120 to 127 */
|
||||
};
|
474
sys/i386/isa/sound/midi_synth.c
Normal file
474
sys/i386/isa/sound/midi_synth.c
Normal file
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* sound/midi_synth.c
|
||||
*
|
||||
* High level midi sequencer manager for dumb MIDI interfaces.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#define _MIDI_SYNTH_C_
|
||||
|
||||
DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
|
||||
|
||||
#include "midi_synth.h"
|
||||
|
||||
static int midi2synth[MAX_MIDI_DEV];
|
||||
static unsigned char prev_out_status[MAX_MIDI_DEV];
|
||||
|
||||
static void
|
||||
midi_outc (int midi_dev, int data)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
for (timeout = 0; timeout < 32000; timeout++)
|
||||
if (midi_devs[midi_dev]->putc (midi_dev, (unsigned char) (data & 0xff)))
|
||||
{
|
||||
if (data & 0x80) /*
|
||||
* Status byte
|
||||
*/
|
||||
prev_out_status[midi_dev] =
|
||||
(unsigned char) (data & 0xff); /*
|
||||
* Store for running status
|
||||
*/
|
||||
return; /*
|
||||
* Mission complete
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Sorry! No space on buffers.
|
||||
*/
|
||||
printk ("Midi send timed out\n");
|
||||
}
|
||||
|
||||
static int
|
||||
prefix_cmd (int midi_dev, unsigned char status)
|
||||
{
|
||||
if (midi_devs[midi_dev]->prefix_cmd == NULL)
|
||||
return 1;
|
||||
|
||||
return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
|
||||
}
|
||||
|
||||
static void
|
||||
midi_synth_input (int dev, unsigned char data)
|
||||
{
|
||||
int orig_dev;
|
||||
|
||||
if (dev < 0 || dev > num_synths)
|
||||
return;
|
||||
|
||||
if (data == 0xfe) /* Ignore active sensing */
|
||||
return;
|
||||
|
||||
orig_dev = midi2synth[dev];
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
midi_synth_output (int dev)
|
||||
{
|
||||
/*
|
||||
* Currently NOP
|
||||
*/
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_ioctl (int dev,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
/*
|
||||
* int orig_dev = synth_devs[dev]->midi_dev;
|
||||
*/
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
|
||||
case SNDCTL_SYNTH_INFO:
|
||||
IOCTL_TO_USER ((char *) arg, 0, synth_devs[dev]->info,
|
||||
sizeof (struct synth_info));
|
||||
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_SYNTH_MEMAVL:
|
||||
return 0x7fffffff;
|
||||
break;
|
||||
|
||||
default:
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_kill_note (int dev, int channel, int note, int velocity)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int msg, chn;
|
||||
|
||||
if (note < 0 || note > 127)
|
||||
return 0;
|
||||
if (channel < 0 || channel > 15)
|
||||
return 0;
|
||||
if (velocity < 0)
|
||||
velocity = 0;
|
||||
if (velocity > 127)
|
||||
velocity = 127;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80))
|
||||
{ /*
|
||||
* Use running status
|
||||
*/
|
||||
if (!prefix_cmd (orig_dev, note))
|
||||
return 0;
|
||||
|
||||
midi_outc (orig_dev, note);
|
||||
|
||||
if (msg == 0x90) /*
|
||||
* Running status = Note on
|
||||
*/
|
||||
midi_outc (orig_dev, 0);/*
|
||||
* Note on with velocity 0 == note
|
||||
* off
|
||||
*/
|
||||
else
|
||||
midi_outc (orig_dev, velocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (velocity == 64)
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
|
||||
return 0;
|
||||
midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /*
|
||||
* Note on
|
||||
*/
|
||||
midi_outc (orig_dev, note);
|
||||
midi_outc (orig_dev, 0); /*
|
||||
* Zero G
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0x80 | (channel & 0x0f)))
|
||||
return 0;
|
||||
midi_outc (orig_dev, 0x80 | (channel & 0x0f)); /*
|
||||
* Note off
|
||||
*/
|
||||
midi_outc (orig_dev, note);
|
||||
midi_outc (orig_dev, velocity);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_set_instr (int dev, int channel, int instr_no)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
|
||||
if (instr_no < 0 || instr_no > 127)
|
||||
return 0;
|
||||
if (channel < 0 || channel > 15)
|
||||
return 0;
|
||||
|
||||
if (!prefix_cmd (orig_dev, 0xc0 | (channel & 0x0f)))
|
||||
return 0;
|
||||
midi_outc (orig_dev, 0xc0 | (channel & 0x0f)); /*
|
||||
* Program change
|
||||
*/
|
||||
midi_outc (orig_dev, instr_no);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_start_note (int dev, int channel, int note, int velocity)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int msg, chn;
|
||||
|
||||
if (note < 0 || note > 127)
|
||||
return 0;
|
||||
if (channel < 0 || channel > 15)
|
||||
return 0;
|
||||
if (velocity < 0)
|
||||
velocity = 0;
|
||||
if (velocity > 127)
|
||||
velocity = 127;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (chn == channel && msg == 0x90)
|
||||
{ /*
|
||||
* Use running status
|
||||
*/
|
||||
if (!prefix_cmd (orig_dev, note))
|
||||
return 0;
|
||||
midi_outc (orig_dev, note);
|
||||
midi_outc (orig_dev, velocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
|
||||
return 0;
|
||||
midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /*
|
||||
* Note on
|
||||
*/
|
||||
midi_outc (orig_dev, note);
|
||||
midi_outc (orig_dev, velocity);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_reset (int dev)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_open (int dev, int mode)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int err;
|
||||
|
||||
if (orig_dev < 0 || orig_dev > num_midis)
|
||||
return RET_ERROR (ENXIO);
|
||||
|
||||
midi2synth[orig_dev] = dev;
|
||||
prev_out_status[orig_dev] = 0;
|
||||
|
||||
if ((err = midi_devs[orig_dev]->open (orig_dev, mode,
|
||||
midi_synth_input, midi_synth_output)) < 0)
|
||||
return err;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_close (int dev)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
|
||||
/*
|
||||
* Shut up the synths by sending just single active sensing message.
|
||||
*/
|
||||
midi_devs[orig_dev]->putc (orig_dev, 0xfe);
|
||||
|
||||
midi_devs[orig_dev]->close (orig_dev);
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_hw_control (int dev, unsigned char *event)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
|
||||
int offs, int count, int pmgr_flag)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
|
||||
struct sysex_info sysex;
|
||||
int i;
|
||||
unsigned long left, src_offs, eox_seen = 0;
|
||||
int first_byte = 1;
|
||||
|
||||
if (!prefix_cmd (orig_dev, 0xf0))
|
||||
return 0;
|
||||
|
||||
if (format != SYSEX_PATCH)
|
||||
{
|
||||
printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format);
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
if (count < sizeof (struct sysex_info))
|
||||
{
|
||||
printk ("MIDI Error: Patch header too short\n");
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
count -= sizeof (struct sysex_info);
|
||||
|
||||
/*
|
||||
* Copy the header from user space but ignore the first bytes which have
|
||||
* been transferred already.
|
||||
*/
|
||||
|
||||
COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs);
|
||||
|
||||
if (count < sysex.len)
|
||||
{
|
||||
printk ("MIDI Warning: Sysex record too short (%d<%d)\n",
|
||||
count, (int) sysex.len);
|
||||
sysex.len = count;
|
||||
}
|
||||
|
||||
left = sysex.len;
|
||||
src_offs = 0;
|
||||
|
||||
RESET_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
|
||||
|
||||
for (i = 0; i < left && !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag); i++)
|
||||
{
|
||||
unsigned char data;
|
||||
|
||||
GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i);
|
||||
|
||||
if (first_byte && data != 0xf0)
|
||||
midi_outc (orig_dev, 0xf0); /* Sysex start */
|
||||
|
||||
eox_seen = (data == 0xf7);/*
|
||||
* Last byte was end of sysex
|
||||
*/
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
if (data != 0xf0) /*
|
||||
* Sysex start
|
||||
*/
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
|
||||
!PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag))
|
||||
DO_SLEEP (sysex_sleeper, sysex_sleep_flag, 1); /* Wait for timeout */
|
||||
|
||||
if (!first_byte && data & 0x80)
|
||||
return 0;
|
||||
first_byte = 0;
|
||||
}
|
||||
|
||||
if (!eox_seen)
|
||||
midi_outc (orig_dev, 0xf7);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_panning (int dev, int channel, int pressure)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_aftertouch (int dev, int channel, int pressure)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int msg, chn;
|
||||
|
||||
if (pressure < 0 || pressure > 127)
|
||||
return;
|
||||
if (channel < 0 || channel > 15)
|
||||
return;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (msg != 0xd0 || chn != channel) /*
|
||||
* Test for running status
|
||||
*/
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0xd0 | (channel & 0x0f)))
|
||||
return;
|
||||
midi_outc (orig_dev, 0xd0 | (channel & 0x0f)); /*
|
||||
* Channel pressure
|
||||
*/
|
||||
}
|
||||
else if (!prefix_cmd (orig_dev, pressure))
|
||||
return;
|
||||
midi_outc (orig_dev, pressure);
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_controller (int dev, int channel, int ctrl_num, int value)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int chn, msg;
|
||||
|
||||
if (ctrl_num < 1 || ctrl_num > 127)
|
||||
return; /* NOTE! Controller # 0 ignored */
|
||||
if (channel < 0 || channel > 15)
|
||||
return;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (msg != 0xb0 || chn != channel)
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f)))
|
||||
return;
|
||||
midi_outc (orig_dev, 0xb0 | (channel & 0x0f));
|
||||
}
|
||||
else if (!prefix_cmd (orig_dev, ctrl_num))
|
||||
return;
|
||||
|
||||
midi_outc (orig_dev, ctrl_num);
|
||||
midi_outc (orig_dev, value & 0x7f);
|
||||
}
|
||||
|
||||
int
|
||||
midi_synth_patchmgr (int dev, struct patmgr_info *rec)
|
||||
{
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
void
|
||||
midi_synth_bender (int dev, int channel, int value)
|
||||
{
|
||||
int orig_dev = synth_devs[dev]->midi_dev;
|
||||
int msg, prev_chn;
|
||||
|
||||
if (channel < 0 || channel > 15)
|
||||
return;
|
||||
|
||||
if (value < 0 || value > 16383)
|
||||
return;
|
||||
|
||||
msg = prev_out_status[orig_dev] & 0xf0;
|
||||
prev_chn = prev_out_status[orig_dev] & 0x0f;
|
||||
|
||||
if (msg != 0xd0 || prev_chn != channel) /*
|
||||
* * Test for running status */
|
||||
{
|
||||
if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f)))
|
||||
return;
|
||||
midi_outc (orig_dev, 0xe0 | (channel & 0x0f));
|
||||
}
|
||||
else if (!prefix_cmd (orig_dev, value & 0x7f))
|
||||
return;
|
||||
|
||||
midi_outc (orig_dev, value & 0x7f);
|
||||
midi_outc (orig_dev, (value >> 7) & 0x7f);
|
||||
}
|
||||
|
||||
#endif
|
45
sys/i386/isa/sound/midi_synth.h
Normal file
45
sys/i386/isa/sound/midi_synth.h
Normal file
@ -0,0 +1,45 @@
|
||||
int midi_synth_ioctl (int dev,
|
||||
unsigned int cmd, unsigned int arg);
|
||||
int midi_synth_kill_note (int dev, int channel, int note, int velocity);
|
||||
int midi_synth_set_instr (int dev, int channel, int instr_no);
|
||||
int midi_synth_start_note (int dev, int channel, int note, int volume);
|
||||
void midi_synth_reset (int dev);
|
||||
int midi_synth_open (int dev, int mode);
|
||||
void midi_synth_close (int dev);
|
||||
void midi_synth_hw_control (int dev, unsigned char *event);
|
||||
int midi_synth_load_patch (int dev, int format, snd_rw_buf * addr,
|
||||
int offs, int count, int pmgr_flag);
|
||||
void midi_synth_panning (int dev, int channel, int pressure);
|
||||
void midi_synth_aftertouch (int dev, int channel, int pressure);
|
||||
void midi_synth_controller (int dev, int channel, int ctrl_num, int value);
|
||||
int midi_synth_patchmgr (int dev, struct patmgr_info *rec);
|
||||
void midi_synth_bender (int dev, int chn, int value);
|
||||
|
||||
|
||||
#ifndef _MIDI_SYNTH_C_
|
||||
static struct synth_info std_synth_info =
|
||||
{MIDI_SYNTH_NAME, 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, MIDI_SYNTH_CAPS};
|
||||
|
||||
static struct synth_operations std_midi_synth =
|
||||
{
|
||||
&std_synth_info,
|
||||
0,
|
||||
SYNTH_TYPE_MIDI,
|
||||
0,
|
||||
midi_synth_open,
|
||||
midi_synth_close,
|
||||
midi_synth_ioctl,
|
||||
midi_synth_kill_note,
|
||||
midi_synth_start_note,
|
||||
midi_synth_set_instr,
|
||||
midi_synth_reset,
|
||||
midi_synth_hw_control,
|
||||
midi_synth_load_patch,
|
||||
midi_synth_aftertouch,
|
||||
midi_synth_controller,
|
||||
midi_synth_panning,
|
||||
NULL,
|
||||
midi_synth_patchmgr,
|
||||
midi_synth_bender
|
||||
};
|
||||
#endif
|
924
sys/i386/isa/sound/pss.c
Normal file
924
sys/i386/isa/sound/pss.c
Normal file
@ -0,0 +1,924 @@
|
||||
/* Marc.Hoffman@analog.com
|
||||
|
||||
This is a pss driver.
|
||||
|
||||
it is based on Greg.Yukna@analog.com @file{host} for DOG
|
||||
|
||||
Unfortunately I can't distribute the ld file needed to
|
||||
make the pss card to emulate the SB stuff.
|
||||
|
||||
I have provided a simple interface to the PSS unlike the
|
||||
DOG version. to download a new algorithim just cat it to
|
||||
/dev/pss 14,9.
|
||||
|
||||
You really need to rebuild this with the synth.ld file
|
||||
|
||||
get the <synth>.ld from your dos directory maybe
|
||||
voyetra\dsp001.ld
|
||||
|
||||
ld2inc < synth.ld > synth-ld.h
|
||||
(make config does the same).
|
||||
|
||||
rebuild
|
||||
|
||||
Okay if you blow things away no problem just
|
||||
|
||||
main(){ioctl(open("/dev/pss"),SNDCTL_PSS_RESET)};
|
||||
|
||||
and everything will be okay.
|
||||
|
||||
At first I was going to wory about applications that were using
|
||||
the sound stuff and disallow the use of /dev/pss. But for
|
||||
now I figured it doesn't matter.
|
||||
|
||||
And if you change algos all the other applications running die off
|
||||
due to DMA problems. Yeah just pull the plug and watch em die.
|
||||
|
||||
If the registers get hosed
|
||||
main(){ioctl(open("/dev/pss"),SNDCTL_PSS_SETUP_REGISTERS)};
|
||||
|
||||
Probably everything else can be done via mmap
|
||||
|
||||
Oh if you want to develope code for the ADSP-21xx or Program the
|
||||
1848 just send me mail and I will hook you up.
|
||||
|
||||
marc.hoffman@analog.com
|
||||
|
||||
*/
|
||||
#include "sound_config.h"
|
||||
|
||||
#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS)
|
||||
|
||||
#ifndef PSS_MSS_BASE
|
||||
#define PSS_MSS_BASE 0
|
||||
#endif
|
||||
|
||||
#ifndef PSS_MPU_BASE
|
||||
#define PSS_MPU_BASE 0
|
||||
#endif
|
||||
|
||||
#ifndef PSS_MPU_IRQ
|
||||
#define PSS_MPU_IRQ 0
|
||||
#endif
|
||||
|
||||
#undef DEB
|
||||
#define DEB(x) x
|
||||
|
||||
#include "pss.h"
|
||||
|
||||
static int pss_ok = 0;
|
||||
static int sb_ok = 0;
|
||||
|
||||
static int pss_base;
|
||||
static int pss_irq;
|
||||
static int pss_dma;
|
||||
|
||||
static int gamePort = 0;
|
||||
|
||||
static int sbInt;
|
||||
static int cdPol;
|
||||
static int cdAddr = 0; /* 0x340; */
|
||||
static int cdInt = 10;
|
||||
|
||||
/* Define these by hand in local.h */
|
||||
static int wssAddr = PSS_MSS_BASE;
|
||||
static int midiAddr = PSS_MPU_BASE;
|
||||
static int midiInt = PSS_MPU_IRQ;
|
||||
|
||||
static int SoundPortAddress;
|
||||
static int SoundPortData;
|
||||
static int speaker = 1;
|
||||
|
||||
|
||||
static struct pss_speaker default_speaker =
|
||||
{0, 0, 0, PSS_STEREO};
|
||||
|
||||
DEFINE_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
|
||||
|
||||
#include "synth-ld.h"
|
||||
|
||||
static int pss_download_boot (unsigned char *block, int size);
|
||||
static int pss_reset_dsp (void);
|
||||
|
||||
static inline void
|
||||
pss_outpw (unsigned short port, unsigned short value)
|
||||
{
|
||||
__asm__ __volatile__ ("outw %w0, %w1"
|
||||
: /* no outputs */
|
||||
:"a" (value), "d" (port));
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
pss_inpw (unsigned short port)
|
||||
{
|
||||
unsigned int _v;
|
||||
__asm__ __volatile__ ("inw %w1,%w0"
|
||||
:"=a" (_v):"d" (port), "0" (0));
|
||||
|
||||
return _v;
|
||||
}
|
||||
|
||||
static void
|
||||
PSS_write (int data)
|
||||
{
|
||||
int i, limit;
|
||||
|
||||
limit = GET_TIME () + 10; /* The timeout is 0.1 secods */
|
||||
/*
|
||||
* Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
|
||||
* called while interrupts are disabled. This means that the timer is
|
||||
* disabled also. However the timeout situation is a abnormal condition.
|
||||
* Normally the DSP should be ready to accept commands after just couple of
|
||||
* loops.
|
||||
*/
|
||||
|
||||
for (i = 0; i < 5000000 && GET_TIME () < limit; i++)
|
||||
{
|
||||
if (pss_inpw (pss_base + PSS_STATUS) & PSS_WRITE_EMPTY)
|
||||
{
|
||||
pss_outpw (pss_base + PSS_DATA, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
printk ("PSS: DSP Command (%04x) Timeout.\n", data);
|
||||
printk ("IRQ conflict???\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pss_setaddr (int addr, int configAddr)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = pss_inpw (configAddr);
|
||||
val &= ADDR_MASK;
|
||||
val |= (addr << 4);
|
||||
pss_outpw (configAddr, val);
|
||||
}
|
||||
|
||||
/*_____ pss_checkint
|
||||
This function tests an interrupt number to see if
|
||||
it is availible. It takes the interrupt button
|
||||
as it's argument and returns TRUE if the interrupt
|
||||
is ok.
|
||||
*/
|
||||
static int
|
||||
pss_checkint (int intNum)
|
||||
{
|
||||
int val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/*_____ Set the interrupt bits */
|
||||
switch (intNum)
|
||||
{
|
||||
case 3:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_3_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 5:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_5_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 7:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_7_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 9:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_9_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 10:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_10_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 11:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_11_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
case 12:
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_MASK;
|
||||
val |= INT_12_BITS;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
break;
|
||||
default:
|
||||
printk ("unknown interupt selected. %d\n", intNum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*_____ Set the interrupt test bit */
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val |= INT_TEST_BIT;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
|
||||
/*_____ Check if the interrupt is in use */
|
||||
/*_____ Do it a few times in case there is a delay */
|
||||
ret = 0;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
if (val & INT_TEST_PASS)
|
||||
{
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*_____ Clear the Test bit and the interrupt bits */
|
||||
val = pss_inpw (pss_base + PSS_CONFIG);
|
||||
val &= INT_TEST_BIT_MASK;
|
||||
val &= INT_MASK;
|
||||
pss_outpw (pss_base + PSS_CONFIG, val);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*____ pss_setint
|
||||
This function sets the correct bits in the
|
||||
configuration register to
|
||||
enable the chosen interrupt.
|
||||
*/
|
||||
static void
|
||||
pss_setint (int intNum, int configAddress)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (intNum)
|
||||
{
|
||||
case 0:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 3:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_3_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 5:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_5_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 7:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_7_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 9:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_9_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 10:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_10_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 11:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_11_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
case 12:
|
||||
val = pss_inpw (configAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_12_BITS;
|
||||
pss_outpw (configAddress, val);
|
||||
break;
|
||||
default:
|
||||
printk ("pss_setint unkown int\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*____ pss_setsbint
|
||||
This function sets the correct bits in the
|
||||
SoundBlaster configuration PSS register to
|
||||
enable the chosen interrupt.
|
||||
It takes a interrupt button as its argument.
|
||||
*/
|
||||
static void
|
||||
pss_setsbint (int intNum)
|
||||
{
|
||||
int val;
|
||||
int sbConfigAddress;
|
||||
|
||||
sbConfigAddress = pss_base + SB_CONFIG;
|
||||
switch (intNum)
|
||||
{
|
||||
case 3:
|
||||
val = pss_inpw (sbConfigAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_3_BITS;
|
||||
pss_outpw (sbConfigAddress, val);
|
||||
break;
|
||||
case 5:
|
||||
val = pss_inpw (sbConfigAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_5_BITS;
|
||||
pss_outpw (sbConfigAddress, val);
|
||||
break;
|
||||
case 7:
|
||||
val = pss_inpw (sbConfigAddress);
|
||||
val &= INT_MASK;
|
||||
val |= INT_7_BITS;
|
||||
pss_outpw (sbConfigAddress, val);
|
||||
break;
|
||||
default:
|
||||
printk ("pss_setsbint: unknown_int\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*____ pss_setsbdma
|
||||
This function sets the correct bits in the
|
||||
SoundBlaster configuration PSS register to
|
||||
enable the chosen DMA channel.
|
||||
It takes a DMA button as its argument.
|
||||
*/
|
||||
static void
|
||||
pss_setsbdma (int dmaNum)
|
||||
{
|
||||
int val;
|
||||
int sbConfigAddress;
|
||||
|
||||
sbConfigAddress = pss_base + SB_CONFIG;
|
||||
|
||||
switch (dmaNum)
|
||||
{
|
||||
case 1:
|
||||
val = pss_inpw (sbConfigAddress);
|
||||
val &= DMA_MASK;
|
||||
val |= DMA_1_BITS;
|
||||
pss_outpw (sbConfigAddress, val);
|
||||
break;
|
||||
default:
|
||||
printk ("Personal Sound System ERROR! pss_setsbdma: unknown_dma\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*____ pss_setwssdma
|
||||
This function sets the correct bits in the
|
||||
WSS configuration PSS register to
|
||||
enable the chosen DMA channel.
|
||||
It takes a DMA button as its argument.
|
||||
*/
|
||||
static void
|
||||
pss_setwssdma (int dmaNum)
|
||||
{
|
||||
int val;
|
||||
int wssConfigAddress;
|
||||
|
||||
wssConfigAddress = pss_base + PSS_WSS_CONFIG;
|
||||
|
||||
switch (dmaNum)
|
||||
{
|
||||
case 0:
|
||||
val = pss_inpw (wssConfigAddress);
|
||||
val &= DMA_MASK;
|
||||
val |= DMA_0_BITS;
|
||||
pss_outpw (wssConfigAddress, val);
|
||||
break;
|
||||
case 1:
|
||||
val = pss_inpw (wssConfigAddress);
|
||||
val &= DMA_MASK;
|
||||
val |= DMA_1_BITS;
|
||||
pss_outpw (wssConfigAddress, val);
|
||||
break;
|
||||
case 3:
|
||||
val = pss_inpw (wssConfigAddress);
|
||||
val &= DMA_MASK;
|
||||
val |= DMA_3_BITS;
|
||||
pss_outpw (wssConfigAddress, val);
|
||||
break;
|
||||
default:
|
||||
printk ("Personal Sound System ERROR! pss_setwssdma: unknown_dma\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*_____ SetSpeakerOut
|
||||
This function sets the Volume, Bass, Treble and Mode of
|
||||
the speaker out channel.
|
||||
*/
|
||||
void
|
||||
pss_setspeaker (struct pss_speaker *spk)
|
||||
{
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
if (spk->volume > PHILLIPS_VOL_MAX)
|
||||
spk->volume = PHILLIPS_VOL_MAX;
|
||||
if (spk->volume < PHILLIPS_VOL_MIN)
|
||||
spk->volume = PHILLIPS_VOL_MIN;
|
||||
|
||||
PSS_write (MASTER_VOLUME_LEFT
|
||||
| (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
PSS_write (MASTER_VOLUME_RIGHT
|
||||
| (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
|
||||
|
||||
if (spk->bass > PHILLIPS_BASS_MAX)
|
||||
spk->bass = PHILLIPS_BASS_MAX;
|
||||
if (spk->bass < PHILLIPS_BASS_MIN)
|
||||
spk->bass = PHILLIPS_BASS_MIN;
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
PSS_write (MASTER_BASS
|
||||
| (PHILLIPS_BASS_CONSTANT + spk->bass / PHILLIPS_BASS_STEP));
|
||||
|
||||
if (spk->treb > PHILLIPS_TREBLE_MAX)
|
||||
spk->treb = PHILLIPS_TREBLE_MAX;
|
||||
if (spk->treb < PHILLIPS_TREBLE_MIN)
|
||||
spk->treb = PHILLIPS_TREBLE_MIN;
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
PSS_write (MASTER_TREBLE
|
||||
| (PHILLIPS_TREBLE_CONSTANT + spk->treb / PHILLIPS_TREBLE_STEP));
|
||||
|
||||
PSS_write (SET_MASTER_COMMAND);
|
||||
PSS_write (MASTER_SWITCH | spk->mode);
|
||||
}
|
||||
|
||||
static void
|
||||
pss_init1848 (void)
|
||||
{
|
||||
/*_____ Wait for 1848 to init */
|
||||
while (INB (SoundPortAddress) & SP_IN_INIT);
|
||||
|
||||
/*_____ Wait for 1848 to autocal */
|
||||
OUTB (SoundPortAddress, SP_TEST_AND_INIT);
|
||||
while (INB (SoundPortData) & AUTO_CAL_IN_PROG);
|
||||
}
|
||||
|
||||
static int
|
||||
pss_configure_registers_to_look_like_sb (void)
|
||||
{
|
||||
pss_setaddr (wssAddr, pss_base + PSS_WSS_CONFIG);
|
||||
|
||||
SoundPortAddress = wssAddr + 4;
|
||||
SoundPortData = wssAddr + 5;
|
||||
|
||||
DEB (printk ("Turning Game Port %s.\n",
|
||||
gamePort ? "On" : "Off"));
|
||||
|
||||
/*_____ Turn on the Game port */
|
||||
if (gamePort)
|
||||
pss_outpw (pss_base + PSS_STATUS,
|
||||
pss_inpw (pss_base + PSS_STATUS) | GAME_BIT);
|
||||
else
|
||||
pss_outpw (pss_base + PSS_STATUS,
|
||||
pss_inpw (pss_base + PSS_STATUS) & GAME_BIT_MASK);
|
||||
|
||||
|
||||
DEB (printk ("PSS attaching base %x irq %d dma %d\n",
|
||||
pss_base, pss_irq, pss_dma));
|
||||
|
||||
/* Check if sb is enabled if it is check the interrupt */
|
||||
pss_outpw (pss_base + SB_CONFIG, 0);
|
||||
|
||||
if (pss_irq != 0)
|
||||
{
|
||||
DEB (printk ("PSS Emulating Sound Blaster ADDR %04x\n", pss_base));
|
||||
DEB (printk ("PSS SBC: attaching base %x irq %d dma %d\n",
|
||||
SBC_BASE, SBC_IRQ, SBC_DMA));
|
||||
|
||||
if (pss_checkint (SBC_IRQ) == 0)
|
||||
{
|
||||
printk ("PSS! attach: int_error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pss_setsbint (SBC_IRQ);
|
||||
pss_setsbdma (SBC_DMA);
|
||||
sb_ok = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_ok = 0;
|
||||
printk ("PSS: sound blaster error init\n");
|
||||
}
|
||||
|
||||
/* Check if cd is enabled if it is check the interrupt */
|
||||
pss_outpw (pss_base + CD_CONFIG, 0);
|
||||
|
||||
if (cdAddr != 0)
|
||||
{
|
||||
DEB (printk ("PSS:CD drive %x irq: %d", cdAddr, cdInt));
|
||||
if (cdInt != 0)
|
||||
{
|
||||
if (pss_checkint (cdInt) == 0)
|
||||
{
|
||||
printk ("Can't allocate cdInt %d\n", cdInt);
|
||||
}
|
||||
else
|
||||
{
|
||||
int val;
|
||||
|
||||
printk ("CD poll ");
|
||||
pss_setaddr (cdAddr, pss_base + CD_CONFIG);
|
||||
pss_setint (cdInt, pss_base + CD_CONFIG);
|
||||
|
||||
/* set the correct bit in the
|
||||
configuration register to
|
||||
set the irq polarity for the CD-Rom.
|
||||
NOTE: This bit is in the address config
|
||||
field, It must be configured after setting
|
||||
the CD-ROM ADDRESS!!! */
|
||||
val = pss_inpw (pss_base + CD_CONFIG);
|
||||
pss_outpw (pss_base + CD_CONFIG, 0);
|
||||
val &= CD_POL_MASK;
|
||||
if (cdPol)
|
||||
val |= CD_POL_BIT;
|
||||
pss_outpw (pss_base + CD_CONFIG, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if midi is enabled if it is check the interrupt */
|
||||
pss_outpw (pss_base + MIDI_CONFIG, 0);
|
||||
if (midiAddr != 0)
|
||||
{
|
||||
printk ("midi init %x %d\n", midiAddr, midiInt);
|
||||
if (pss_checkint (midiInt) == 0)
|
||||
{
|
||||
printk ("midi init int error %x %d\n", midiAddr, midiInt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pss_setaddr (midiAddr, pss_base + MIDI_CONFIG);
|
||||
pss_setint (midiInt, pss_base + MIDI_CONFIG);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
attach_pss (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
if (pss_ok)
|
||||
{
|
||||
if (hw_config)
|
||||
{
|
||||
printk (" <PSS-ESC614>");
|
||||
}
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
pss_ok = 1;
|
||||
|
||||
if (pss_configure_registers_to_look_like_sb () == 0)
|
||||
return mem_start;
|
||||
|
||||
if (sb_ok)
|
||||
if (pss_synthLen
|
||||
&& pss_download_boot (pss_synth, pss_synthLen))
|
||||
{
|
||||
if (speaker)
|
||||
pss_setspeaker (&default_speaker);
|
||||
pss_ok = 1;
|
||||
}
|
||||
else
|
||||
pss_reset_dsp ();
|
||||
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
int
|
||||
probe_pss (struct address_info *hw_config)
|
||||
{
|
||||
pss_base = hw_config->io_base;
|
||||
pss_irq = hw_config->irq;
|
||||
pss_dma = hw_config->dma;
|
||||
|
||||
if ((pss_inpw (pss_base + 4) & 0xff00) == 0x4500)
|
||||
{
|
||||
attach_pss (0, hw_config);
|
||||
return 1;
|
||||
}
|
||||
printk (" fail base %x irq %d dma %d\n", pss_base, pss_irq, pss_dma);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pss_reattach (void)
|
||||
{
|
||||
pss_ok = 0;
|
||||
attach_pss (0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pss_reset_dsp ()
|
||||
{
|
||||
unsigned long i, limit = GET_TIME () + 10;
|
||||
|
||||
pss_outpw (pss_base + PSS_CONTROL, 0x2000);
|
||||
|
||||
for (i = 0; i < 32768 && GET_TIME () < limit; i++)
|
||||
pss_inpw (pss_base + PSS_CONTROL);
|
||||
|
||||
pss_outpw (pss_base + PSS_CONTROL, 0x0000);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pss_download_boot (unsigned char *block, int size)
|
||||
{
|
||||
int i, limit, val, count;
|
||||
|
||||
printk ("PSS: downloading boot code synth.ld... ");
|
||||
|
||||
/*_____ Warn DSP software that a boot is coming */
|
||||
pss_outpw (pss_base + PSS_DATA, 0x00fe);
|
||||
|
||||
limit = GET_TIME () + 10;
|
||||
|
||||
for (i = 0; i < 32768 && GET_TIME () < limit; i++)
|
||||
if (pss_inpw (pss_base + PSS_DATA) == 0x5500)
|
||||
break;
|
||||
|
||||
pss_outpw (pss_base + PSS_DATA, *block++);
|
||||
|
||||
pss_reset_dsp ();
|
||||
printk ("start ");
|
||||
|
||||
count = 1;
|
||||
while (1)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 327670; j++)
|
||||
{
|
||||
/*_____ Wait for BG to appear */
|
||||
if (pss_inpw (pss_base + PSS_STATUS) & PSS_FLAG3)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == 327670)
|
||||
{
|
||||
/* It's ok we timed out when the file was empty */
|
||||
if (count >= size)
|
||||
break;
|
||||
else
|
||||
{
|
||||
printk ("\nPSS: DownLoad timeout problems, byte %d=%d\n",
|
||||
count, size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*_____ Send the next byte */
|
||||
pss_outpw (pss_base + PSS_DATA, *block++);
|
||||
count++;
|
||||
}
|
||||
|
||||
/*_____ Why */
|
||||
pss_outpw (pss_base + PSS_DATA, 0);
|
||||
|
||||
limit = GET_TIME () + 10;
|
||||
for (i = 0; i < 32768 && GET_TIME () < limit; i++)
|
||||
val = pss_inpw (pss_base + PSS_STATUS);
|
||||
|
||||
printk ("downloaded\n");
|
||||
|
||||
limit = GET_TIME () + 10;
|
||||
for (i = 0; i < 32768 && GET_TIME () < limit; i++)
|
||||
{
|
||||
val = pss_inpw (pss_base + PSS_STATUS);
|
||||
if (val & 0x4000)
|
||||
break;
|
||||
}
|
||||
|
||||
/* now read the version */
|
||||
for (i = 0; i < 32000; i++)
|
||||
{
|
||||
val = pss_inpw (pss_base + PSS_STATUS_REG);
|
||||
if (val & PSS_READ_FULL)
|
||||
break;
|
||||
}
|
||||
if (i == 32000)
|
||||
return 0;
|
||||
|
||||
val = pss_inpw (pss_base + PSS_DATA_REG);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* The following is a simple device driver for the pss.
|
||||
All I really care about is comunication to and from the pss.
|
||||
|
||||
The ability to reinitialize the <synth.ld> This will be
|
||||
default when release is choosen.
|
||||
|
||||
SNDCTL_PSS_DOWNLOAD:
|
||||
|
||||
Okay we need to creat new minor numbers for the
|
||||
DOWNLOAD functionality.
|
||||
|
||||
14,0x19 -- /dev/pssld where a read operation would output the
|
||||
current ld to user space
|
||||
where a write operation would effectively
|
||||
download a new ld.
|
||||
|
||||
14,0x09 -- /dev/psecho would open up a comunication path to the
|
||||
esc614 asic. Given the ability to send
|
||||
messages to the asic and recive messages too.
|
||||
|
||||
All messages would get read and written in the
|
||||
same manner. It would be up to the application
|
||||
and the ld to maintain a relationship
|
||||
of what the messages mean.
|
||||
|
||||
for this device we need to implement select. */
|
||||
#define CODE_BUFFER_LEN (64*1024)
|
||||
static char *code_buffer;
|
||||
static int code_length;
|
||||
|
||||
static int lock_pss = 0;
|
||||
|
||||
int
|
||||
pss_open (int dev, struct fileinfo *file)
|
||||
{
|
||||
int mode;
|
||||
|
||||
DEB (printk ("pss_open\n"));
|
||||
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
if (lock_pss)
|
||||
return 0;
|
||||
|
||||
lock_pss = 1;
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
if (mode == O_WRONLY)
|
||||
{
|
||||
printk ("pss-open for WRONLY\n");
|
||||
code_length = 0;
|
||||
}
|
||||
|
||||
RESET_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
pss_release (int dev, struct fileinfo *file)
|
||||
{
|
||||
int mode;
|
||||
|
||||
DEB (printk ("pss_release\n"));
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
mode = file->mode & O_ACCMODE;
|
||||
if (mode == O_WRONLY && code_length > 0)
|
||||
{
|
||||
#ifdef linux
|
||||
/* This just allows interrupts while the conversion is running */
|
||||
__asm__ ("sti");
|
||||
#endif
|
||||
if (!pss_download_boot (code_buffer, code_length))
|
||||
{
|
||||
pss_reattach ();
|
||||
}
|
||||
}
|
||||
lock_pss = 0;
|
||||
}
|
||||
|
||||
int
|
||||
pss_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
int c, p;
|
||||
|
||||
DEB (printk ("pss_read\n"));
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
p = 0;
|
||||
c = count;
|
||||
|
||||
return count - c;
|
||||
}
|
||||
|
||||
int
|
||||
pss_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
|
||||
{
|
||||
DEB (printk ("pss_write\n"));
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
dev = dev >> 4;
|
||||
|
||||
if (count) /* Flush output */
|
||||
{
|
||||
COPY_FROM_USER (&code_buffer[code_length], buf, 0, count);
|
||||
code_length += count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pss_ioctl (int dev, struct fileinfo *file,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
DEB (printk ("pss_ioctl dev=%d cmd=%x\n", dev, cmd));
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case SNDCTL_PSS_RESET:
|
||||
pss_reattach ();
|
||||
return 1;
|
||||
|
||||
case SNDCTL_PSS_SETUP_REGISTERS:
|
||||
pss_configure_registers_to_look_like_sb ();
|
||||
return 1;
|
||||
|
||||
case SNDCTL_PSS_SPEAKER:
|
||||
{
|
||||
struct pss_speaker params;
|
||||
COPY_FROM_USER (¶ms, (char *) arg, 0, sizeof (struct pss_speaker));
|
||||
|
||||
pss_setspeaker (¶ms);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return RET_ERROR (EIO);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is going to be used to implement
|
||||
waiting on messages sent from the DSP and to the
|
||||
DSP when comunication is used via the pss directly.
|
||||
|
||||
We need to find out if the pss can generate a diffrent
|
||||
interupt other than the one it has been setup for.
|
||||
|
||||
This way we can carry on a conversation with the pss
|
||||
on a seprate chanel. This would be usefull for debugging. */
|
||||
|
||||
pss_select (int dev, struct fileinfo * file, int sel_type, select_table * wait)
|
||||
{
|
||||
return 0;
|
||||
if (pss_ok == 0)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
dev = dev >> 4;
|
||||
|
||||
switch (sel_type)
|
||||
{
|
||||
case SEL_IN:
|
||||
select_wait (&pss_sleeper, wait);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SEL_OUT:
|
||||
select_wait (&pss_sleeper, wait);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SEL_EX:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
pss_init (long mem_start)
|
||||
{
|
||||
DEB (printk ("pss_init\n"));
|
||||
if (pss_ok)
|
||||
{
|
||||
code_buffer = mem_start;
|
||||
mem_start += CODE_BUFFER_LEN;
|
||||
}
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
#endif
|
371
sys/i386/isa/sound/pss.h
Normal file
371
sys/i386/isa/sound/pss.h
Normal file
@ -0,0 +1,371 @@
|
||||
/******************************************************************************
|
||||
|
||||
def.h
|
||||
|
||||
Version 1.3 11/2/93
|
||||
|
||||
Copyright (c) 1993 Analog Devices Inc. All rights reserved
|
||||
|
||||
******************************************************************************/
|
||||
/* Port offsets from base port for Sound Blaster DSP */
|
||||
#define DSP_PORT_CMSD0 0x00 /* C/MS music voice 1-6 data port, write only */
|
||||
#define DSP_PORT_CMSR0 0x01 /* C/MS music voice 1-6 register port, write only */
|
||||
#define DSP_PORT_CMSD1 0x02 /* C/MS music voice 7-12 data port, write only */
|
||||
#define DSP_PORT_CMSR1 0x03 /* C/MS music voice 7-12 register port, write only */
|
||||
|
||||
#define DSP_PORT_STATUS 0x04 /* DSP Status bits, read only */
|
||||
#define DSP_PORT_CONTROL 0x04 /* DSP Control bits, write only */
|
||||
#define DSP_PORT_DATA_LSB 0x05 /* Read or write LSB of 16 bit data */
|
||||
|
||||
|
||||
#define DSP_PORT_RESET 0x06 /* DSP Reset, write only */
|
||||
#define DSP_PORT_07h 0x07 /* reserved port */
|
||||
|
||||
#define DSP_PORT_FMD0 0x08 /* FM music data/status port, read/write */
|
||||
#define DSP_PORT_FMR0 0x09 /* FM music data/status port, write only */
|
||||
|
||||
#define DSP_PORT_RDDATA 0x0A /* DSP Read data, read only reading signals DSP */
|
||||
#define DSP_PORT_0Bh 0x0B /* reserved port */
|
||||
#define DSP_PORT_WRDATA 0x0C /* DSP Write data or command, write */
|
||||
#define DSP_PORT_WRBUSY 0x0C /* DSP Write buffer status (bit 7), read */
|
||||
#define DSP_PORT_0Dh 0x0D /* reserved port */
|
||||
#define DSP_PORT_DATAAVAIL 0x0E /* DSP Data available status (bit 7), read only */
|
||||
#define DSP_PORT_INTERFACE 0x0E /* Sets DMA Channel and Interrupt, write only */
|
||||
#define DSP_PORT_0Fh 0x0F /* reserved port (used on Pro cards) */
|
||||
|
||||
#define ADDR_MASK 0x003f
|
||||
|
||||
#define INT_MASK 0xffc7
|
||||
#define INT_3_BITS 0x0008
|
||||
#define INT_5_BITS 0x0010
|
||||
#define INT_7_BITS 0x0018
|
||||
#define INT_9_BITS 0x0020
|
||||
#define INT_10_BITS 0x0028
|
||||
#define INT_11_BITS 0x0030
|
||||
#define INT_12_BITS 0x0038
|
||||
|
||||
#define GAME_BIT 0x0400
|
||||
#define GAME_BIT_MASK 0xfbff
|
||||
|
||||
#define INT_TEST_BIT 0x0200
|
||||
#define INT_TEST_PASS 0x0100
|
||||
#define INT_TEST_BIT_MASK 0xFDFF
|
||||
|
||||
#define DMA_MASK 0xfff8
|
||||
#define DMA_0_BITS 0x0001
|
||||
#define DMA_1_BITS 0x0002
|
||||
#define DMA_3_BITS 0x0003
|
||||
#define DMA_5_BITS 0x0004
|
||||
#define DMA_6_BITS 0x0005
|
||||
#define DMA_7_BITS 0x0006
|
||||
|
||||
#define DMA_TEST_BIT 0x0080
|
||||
#define DMA_TEST_PASS 0x0040
|
||||
#define DMA_TEST_BIT_MASK 0xFF7F
|
||||
|
||||
|
||||
/* Echo DSP Flags */
|
||||
|
||||
#define DSP_FLAG3 0x10
|
||||
#define DSP_FLAG2 0x08
|
||||
#define DSP_FLAG1 0x80
|
||||
#define DSP_FLAG0 0x40
|
||||
|
||||
#define PSS_CONFIG 0x10
|
||||
#define PSS_WSS_CONFIG 0x12
|
||||
#define SB_CONFIG 0x14
|
||||
#define MIDI_CONFIG 0x18
|
||||
#define CD_CONFIG 0x16
|
||||
#define UART_CONFIG 0x1a
|
||||
|
||||
#define PSS_DATA 0x00
|
||||
#define PSS_STATUS 0x02
|
||||
#define PSS_CONTROL 0x02
|
||||
#define PSS_ID_VERS 0x04
|
||||
|
||||
#define PSS_FLAG3 0x0800
|
||||
#define PSS_FLAG2 0x0400
|
||||
#define PSS_FLAG1 0x1000
|
||||
#define PSS_FLAG0 0x0800
|
||||
|
||||
/*_____ WSS defines */
|
||||
#define WSS_BASE_ADDRESS 0x530
|
||||
#define WSS_CONFIG 0x0
|
||||
#define WSS_VERSION 0x03
|
||||
#define WSS_SP0 0x04
|
||||
#define WSS_SP1 0x05
|
||||
#define WSS_SP2 0x06
|
||||
#define WSS_SP3 0x07
|
||||
|
||||
/*_____ SoundPort register addresses */
|
||||
|
||||
#define SP_LIN_SOURCE_CTRL 0x00
|
||||
#define SP_RIN_SOURCE_CTRL 0x01
|
||||
#define SP_LIN_GAIN_CTRL 0x10
|
||||
#define SP_RIN_GAIN_CTRL 0x11
|
||||
#define SP_LAUX1_CTRL 0x02
|
||||
#define SP_RAUX1_CTRL 0x03
|
||||
#define SP_LAUX2_CTRL 0x04
|
||||
#define SP_RAUX2_CTRL 0x05
|
||||
#define SP_LOUT_CTRL 0x06
|
||||
#define SP_ROUT_CTRL 0x07
|
||||
#define SP_CLK_FORMAT 0x48
|
||||
#define SP_INT_CONF 0x09
|
||||
#define SP_INT_CONF_MCE 0x49
|
||||
#define SP_PIN_CTRL 0x0a
|
||||
#define SP_TEST_INIT 0x0b
|
||||
#define SP_MISC_CTRL 0x0c
|
||||
#define SP_MIX_CTRL 0x0d
|
||||
#define SP_DMA_UCNT 0x0e
|
||||
#define SP_DMA_LCNT 0x0f
|
||||
|
||||
/*_____ Gain constants */
|
||||
|
||||
#define GAIN_0 0x00
|
||||
#define GAIN_1_5 0x01
|
||||
#define GAIN_3 0x02
|
||||
#define GAIN_4_5 0x03
|
||||
#define GAIN_6 0x04
|
||||
#define GAIN_7_5 0x05
|
||||
#define GAIN_9 0x06
|
||||
#define GAIN_10_5 0x07
|
||||
#define GAIN_12 0x08
|
||||
#define GAIN_13_5 0x09
|
||||
#define GAIN_15 0x0a
|
||||
#define GAIN_16_5 0x0b
|
||||
#define GAIN_18 0x0c
|
||||
#define GAIN_19_5 0x0d
|
||||
#define GAIN_21 0x0e
|
||||
#define GAIN_22_5 0x0f
|
||||
#define MUTE 0XFFFF
|
||||
|
||||
/*_____ Attenuation constants */
|
||||
|
||||
#define ATTEN_0 0x00
|
||||
#define ATTEN_1_5 0x01
|
||||
#define ATTEN_3 0x02
|
||||
#define ATTEN_4_5 0x03
|
||||
#define ATTEN_6 0x04
|
||||
#define ATTEN_7_5 0x05
|
||||
#define ATTEN_9 0x06
|
||||
#define ATTEN_10_5 0x07
|
||||
#define ATTEN_12 0x08
|
||||
#define ATTEN_13_5 0x09
|
||||
#define ATTEN_15 0x0a
|
||||
#define ATTEN_16_5 0x0b
|
||||
#define ATTEN_18 0x0c
|
||||
#define ATTEN_19_5 0x0d
|
||||
#define ATTEN_21 0x0e
|
||||
#define ATTEN_22_5 0x0f
|
||||
|
||||
|
||||
#define PSS_WRITE_EMPTY 0x8000
|
||||
|
||||
#define CD_POL_MASK 0xFFBF
|
||||
#define CD_POL_BIT 0x0040
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
host.h
|
||||
|
||||
Version 1.2 9/27/93
|
||||
|
||||
Copyright (c) 1993 Analog Devices Inc. All rights reserved
|
||||
|
||||
******************************************************************************/
|
||||
#define SB_WRITE_FULL 0x80
|
||||
#define SB_READ_FULL 0x80
|
||||
#define SB_WRITE_STATUS 0x0C
|
||||
#define SB_READ_STATUS 0x0E
|
||||
#define SB_READ_DATA 0x0A
|
||||
#define SB_WRITE_DATA 0x0C
|
||||
|
||||
#define PSS_DATA_REG 0x00
|
||||
#define PSS_STATUS_REG 0x02
|
||||
#define PSS_WRITE_EMPTY 0x8000
|
||||
#define PSS_READ_FULL 0x4000
|
||||
|
||||
/*_____ 1848 Sound Port bit defines */
|
||||
|
||||
#define SP_IN_INIT 0x80
|
||||
#define MODE_CHANGE_ENABLE 0x40
|
||||
#define MODE_CHANGE_MASK 0xbf
|
||||
#define TRANSFER_DISABLE 0x20
|
||||
#define TRANSFER_DISABLE_MASK 0xdf
|
||||
#define ADDRESS_MASK 0xf0
|
||||
|
||||
/*_____ Status bits */
|
||||
#define INTERRUPT_STATUS 0x01
|
||||
#define PLAYBACK_READY 0x02
|
||||
#define PLAYBACK_LEFT 0x04
|
||||
/*_____ pbright is not left */
|
||||
#define PLAYBACK_UPPER 0x08
|
||||
/*_____ bplower is not upper */
|
||||
|
||||
#define SAMPLE_OVERRUN 0x10
|
||||
#define SAMPLE_UNDERRUN 0x10
|
||||
#define CAPTURE_READY 0x20
|
||||
#define CAPTURE_LEFT 0x40
|
||||
/*_____ cpright is not left */
|
||||
#define CAPTURE_UPPER 0x08
|
||||
/*_____ cplower is not upper */
|
||||
|
||||
/*_____ Input & Output regs bits */
|
||||
#define LINE_INPUT 0x80
|
||||
#define AUX_INPUT 0x40
|
||||
#define MIC_INPUT 0x80
|
||||
#define MIXED_DAC_INPUT 0xC0
|
||||
#define INPUT_GAIN_MASK 0xf0
|
||||
#define INPUT_MIC_GAIN_ENABLE 0x20
|
||||
#define INPUT_MIC_GAIN_MASK 0xdf
|
||||
#define INPUT_SOURCE_MASK 0x3f
|
||||
#define AUX_INPUT_ATTEN_MASK 0xf0
|
||||
#define AUX_INPUT_MUTE 0x80
|
||||
#define AUX_INPUT_MUTE_MASK 0x7f
|
||||
#define OUTPUT_MUTE 0x80
|
||||
#define OUTPUT_MUTE_MASK 0x7f
|
||||
#define OUTPUT_ATTEN_MASK 0xc0
|
||||
|
||||
/*_____ Clock and Data format reg bits */
|
||||
#define CLOCK_SELECT_MASK 0xfe
|
||||
#define CLOCK_XTAL2 0x01
|
||||
#define CLOCK_XTAL1 0x00
|
||||
#define CLOCK_FREQ_MASK 0xf1
|
||||
#define STEREO_MONO_MASK 0xef
|
||||
#define STEREO 0x10
|
||||
#define AUDIO_MONO 0x00
|
||||
#define LINEAR_COMP_MASK 0xdf
|
||||
#define LINEAR 0x00
|
||||
#define COMPANDED 0x20
|
||||
#define FORMAT_MASK 0xbf
|
||||
#define PCM 0x00
|
||||
#define ULAW 0x00
|
||||
#define TWOS_COMP 0x40
|
||||
#define ALAW 0x40
|
||||
|
||||
/*_____ Interface Configuration reg bits */
|
||||
#define PLAYBACK_ENABLE 0x01
|
||||
#define PLAYBACK_ENABLE_MASK 0xfe
|
||||
#define CAPTURE_ENABLE 0x02
|
||||
#define CAPTURE_ENABLE_MASK 0xfd
|
||||
#define SINGLE_DMA 0x04
|
||||
#define SINGLE_DMA_MASK 0xfb
|
||||
#define DUAL_DMA 0x00
|
||||
#define AUTO_CAL_ENABLE 0x08
|
||||
#define AUTO_CAL_DISABLE_MASK 0xf7
|
||||
#define PLAYBACK_PIO_ENABLE 0x40
|
||||
#define PLAYBACK_DMA_MASK 0xbf
|
||||
#define CAPTURE_PIO_ENABLE 0x80
|
||||
#define CAPTURE_DMA_MASK 0x7f
|
||||
|
||||
/*_____ Pin control bits */
|
||||
#define INTERRUPT_ENABLE 0x02
|
||||
#define INTERRUPT_MASK 0xfd
|
||||
|
||||
/*_____ Test and init reg bits */
|
||||
#define OVERRANGE_LEFT_MASK 0xfc
|
||||
#define OVERRANGE_RIGHT_MASK 0xf3
|
||||
#define DATA_REQUEST_STATUS 0x10
|
||||
#define AUTO_CAL_IN_PROG 0x20
|
||||
#define PLAYBACK_UNDERRUN 0x40
|
||||
#define CAPTURE_UNDERRUN 0x80
|
||||
|
||||
/*_____ Miscellaneous Control reg bits */
|
||||
#define ID_MASK 0xf0
|
||||
|
||||
/*_____ Digital Mix Control reg bits */
|
||||
#define DIGITAL_MIX1_MUTE_MASK 0xfe
|
||||
#define MIX_ATTEN_MASK 0x03
|
||||
|
||||
/*_____ 1848 Sound Port reg defines */
|
||||
|
||||
#define SP_LEFT_INPUT_CONTROL 0x0
|
||||
#define SP_RIGHT_INPUT_CONTROL 0x1
|
||||
#define SP_LEFT_AUX1_CONTROL 0x2
|
||||
#define SP_RIGHT_AUX1_CONTROL 0x3
|
||||
#define SP_LEFT_AUX2_CONTROL 0x4
|
||||
#define SP_RIGHT_AUX2_CONTROL 0x5
|
||||
#define SP_LEFT_OUTPUT_CONTROL 0x6
|
||||
#define SP_RIGHT_OUTPUT_CONTROL 0x7
|
||||
#define SP_CLOCK_DATA_FORMAT 0x8
|
||||
#define SP_INTERFACE_CONFIG 0x9
|
||||
#define SP_PIN_CONTROL 0xA
|
||||
#define SP_TEST_AND_INIT 0xB
|
||||
#define SP_MISC_INFO 0xC
|
||||
#define SP_DIGITAL_MIX 0xD
|
||||
#define SP_UPPER_BASE_COUNT 0xE
|
||||
#define SP_LOWER_BASE_COUNT 0xF
|
||||
|
||||
#define HOST_SP_ADDR (0x534)
|
||||
#define HOST_SP_DATA (0x535)
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
phillips.h
|
||||
|
||||
Version 1.2 9/27/93
|
||||
|
||||
Copyright (c) 1993 Analog Devices Inc. All rights reserved
|
||||
|
||||
******************************************************************************/
|
||||
/*_____ Phillips control SW defines */
|
||||
|
||||
/*_____ Settings and ranges */
|
||||
#define VOLUME_MAX 6
|
||||
#define VOLUME_MIN (-64)
|
||||
#define VOLUME_RANGE 70
|
||||
#define VOLUME_STEP 2
|
||||
#define BASS_MAX 15
|
||||
#define BASS_MIN (-12)
|
||||
#define BASS_STEP 2
|
||||
#define BASS_RANGE 27
|
||||
#define TREBLE_MAX 12
|
||||
#define TREBLE_MIN (-12)
|
||||
#define TREBLE_STEP 2
|
||||
#define TREBLE_RANGE 24
|
||||
|
||||
#define VOLUME_CONSTANT 252
|
||||
#define BASS_CONSTANT 246
|
||||
#define TREBLE_CONSTANT 246
|
||||
|
||||
/*_____ Software commands */
|
||||
#define SET_MASTER_COMMAND 0x0010
|
||||
#define MASTER_VOLUME_LEFT 0x0000
|
||||
#define MASTER_VOLUME_RIGHT 0x0100
|
||||
#define MASTER_BASS 0x0200
|
||||
#define MASTER_TREBLE 0x0300
|
||||
#define MASTER_SWITCH 0x0800
|
||||
|
||||
#define STEREO_MODE 0x00ce
|
||||
#define PSEUDO_MODE 0x00d6
|
||||
#define SPATIAL_MODE 0x00de
|
||||
#define MONO_MODE 0x00c6
|
||||
|
||||
|
||||
#define PSS_STEREO 0x00ce
|
||||
#define PSS_PSEUDO 0x00d6
|
||||
#define PSS_SPATIAL 0x00de
|
||||
#define PSS_MONO 0x00c6
|
||||
|
||||
#define PHILLIPS_VOL_MIN -64
|
||||
#define PHILLIPS_VOL_MAX 6
|
||||
#define PHILLIPS_VOL_DELTA 70
|
||||
#define PHILLIPS_VOL_INITIAL -20
|
||||
#define PHILLIPS_VOL_CONSTANT 252
|
||||
#define PHILLIPS_VOL_STEP 2
|
||||
#define PHILLIPS_BASS_MIN -12
|
||||
#define PHILLIPS_BASS_MAX 15
|
||||
#define PHILLIPS_BASS_DELTA 27
|
||||
#define PHILLIPS_BASS_INITIAL 0
|
||||
#define PHILLIPS_BASS_CONSTANT 246
|
||||
#define PHILLIPS_BASS_STEP 2
|
||||
#define PHILLIPS_TREBLE_MIN -12
|
||||
#define PHILLIPS_TREBLE_MAX 12
|
||||
#define PHILLIPS_TREBLE_DELTA 24
|
||||
#define PHILLIPS_TREBLE_INITIAL 0
|
||||
#define PHILLIPS_TREBLE_CONSTANT 246
|
||||
#define PHILLIPS_TREBLE_STEP 2
|
||||
|
406
sys/i386/isa/sound/sound_timer.c
Normal file
406
sys/i386/isa/sound/sound_timer.c
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* sound/sound_timer.c
|
||||
*
|
||||
* Timer for the level 2 interface of the /dev/sequencer. Uses the
|
||||
* 80 and 320 usec timers of OPL-3 (PAS16 only) and GUS.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SEQUENCER_C
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#if !defined(EXCLUDE_SEQUENCER) && (!defined(EXCLUDE_GUS) || (!defined(EXCLUDE_PAS) && !defined(EXCLUDE_YM3812)))
|
||||
|
||||
static volatile int initialized = 0, opened = 0, tmr_running = 0;
|
||||
static volatile time_t tmr_offs, tmr_ctr;
|
||||
static volatile unsigned long ticks_offs;
|
||||
static volatile int curr_tempo, curr_timebase;
|
||||
static volatile unsigned long curr_ticks;
|
||||
static volatile unsigned long next_event_time;
|
||||
static unsigned long prev_event_time;
|
||||
static volatile int select_addr, data_addr;
|
||||
static volatile int curr_timer = 0;
|
||||
static volatile unsigned long usecs_per_tmr; /* Length of the current interval */
|
||||
|
||||
|
||||
static void
|
||||
timer_command (unsigned int addr, unsigned int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
OUTB ((unsigned char) (addr & 0xff), select_addr);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
INB (select_addr);
|
||||
|
||||
OUTB ((unsigned char) (val & 0xff), data_addr);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
INB (select_addr);
|
||||
}
|
||||
|
||||
static void
|
||||
arm_timer (int timer, unsigned int interval)
|
||||
{
|
||||
|
||||
curr_timer = timer;
|
||||
|
||||
if (timer == 1)
|
||||
{
|
||||
gus_write8 (0x46, 256 - interval); /* Set counter for timer 1 */
|
||||
gus_write8 (0x45, 0x04); /* Enable timer 1 IRQ */
|
||||
timer_command (0x04, 0x01); /* Start timer 1 */
|
||||
}
|
||||
else
|
||||
{
|
||||
gus_write8 (0x47, 256 - interval); /* Set counter for timer 2 */
|
||||
gus_write8 (0x45, 0x08); /* Enable timer 2 IRQ */
|
||||
timer_command (0x04, 0x02); /* Start timer 2 */
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
tmr2ticks (int tmr_value)
|
||||
{
|
||||
/*
|
||||
* Convert timer ticks to MIDI ticks
|
||||
*/
|
||||
|
||||
unsigned long tmp;
|
||||
unsigned long scale;
|
||||
|
||||
tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */
|
||||
|
||||
scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */
|
||||
|
||||
return (tmp + (scale / 2)) / scale;
|
||||
}
|
||||
|
||||
static void
|
||||
reprogram_timer (void)
|
||||
{
|
||||
unsigned long usecs_per_tick;
|
||||
int timer_no, resolution;
|
||||
int divisor;
|
||||
|
||||
usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
|
||||
|
||||
/*
|
||||
* Don't kill the system by setting too high timer rate
|
||||
*/
|
||||
if (usecs_per_tick < 2000)
|
||||
usecs_per_tick = 2000;
|
||||
|
||||
if (usecs_per_tick > (256 * 80))
|
||||
{
|
||||
timer_no = 2;
|
||||
resolution = 320; /* usec */
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_no = 1;
|
||||
resolution = 80; /* usec */
|
||||
}
|
||||
|
||||
divisor = (usecs_per_tick + (resolution / 2)) / resolution;
|
||||
usecs_per_tmr = divisor * resolution;
|
||||
|
||||
arm_timer (timer_no, divisor);
|
||||
}
|
||||
|
||||
static void
|
||||
tmr_reset (void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
tmr_offs = 0;
|
||||
ticks_offs = 0;
|
||||
tmr_ctr = 0;
|
||||
next_event_time = 0xffffffff;
|
||||
prev_event_time = 0;
|
||||
curr_ticks = 0;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
timer_open (int dev, int mode)
|
||||
{
|
||||
if (opened)
|
||||
return RET_ERROR (EBUSY);
|
||||
|
||||
tmr_reset ();
|
||||
curr_tempo = 60;
|
||||
curr_timebase = HZ;
|
||||
opened = 1;
|
||||
reprogram_timer ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
timer_close (int dev)
|
||||
{
|
||||
opened = tmr_running = 0;
|
||||
gus_write8 (0x45, 0); /* Disable both timers */
|
||||
}
|
||||
|
||||
static int
|
||||
timer_event (int dev, unsigned char *event)
|
||||
{
|
||||
unsigned char cmd = event[1];
|
||||
unsigned long parm = *(int *) &event[4];
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case TMR_WAIT_REL:
|
||||
parm += prev_event_time;
|
||||
case TMR_WAIT_ABS:
|
||||
if (parm > 0)
|
||||
{
|
||||
long time;
|
||||
|
||||
if (parm <= curr_ticks) /* It's the time */
|
||||
return TIMER_NOT_ARMED;
|
||||
|
||||
time = parm;
|
||||
next_event_time = prev_event_time = time;
|
||||
|
||||
return TIMER_ARMED;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_START:
|
||||
tmr_reset ();
|
||||
tmr_running = 1;
|
||||
reprogram_timer ();
|
||||
break;
|
||||
|
||||
case TMR_STOP:
|
||||
tmr_running = 0;
|
||||
break;
|
||||
|
||||
case TMR_CONTINUE:
|
||||
tmr_running = 1;
|
||||
reprogram_timer ();
|
||||
break;
|
||||
|
||||
case TMR_TEMPO:
|
||||
if (parm)
|
||||
{
|
||||
if (parm < 8)
|
||||
parm = 8;
|
||||
if (parm > 250)
|
||||
parm = 250;
|
||||
tmr_offs = tmr_ctr;
|
||||
ticks_offs += tmr2ticks (tmr_ctr);
|
||||
tmr_ctr = 0;
|
||||
curr_tempo = parm;
|
||||
reprogram_timer ();
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_ECHO:
|
||||
seq_copy_to_input (event, 8);
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
return TIMER_NOT_ARMED;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
timer_get_time (int dev)
|
||||
{
|
||||
if (!opened)
|
||||
return 0;
|
||||
|
||||
return curr_ticks;
|
||||
}
|
||||
|
||||
static int
|
||||
timer_ioctl (int dev,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SNDCTL_TMR_SOURCE:
|
||||
return IOCTL_OUT (arg, TMR_INTERNAL);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_START:
|
||||
tmr_reset ();
|
||||
tmr_running = 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_STOP:
|
||||
tmr_running = 0;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_CONTINUE:
|
||||
tmr_running = 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TIMEBASE:
|
||||
{
|
||||
int val = IOCTL_IN (arg);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (val < 1)
|
||||
val = 1;
|
||||
if (val > 1000)
|
||||
val = 1000;
|
||||
curr_timebase = val;
|
||||
}
|
||||
|
||||
return IOCTL_OUT (arg, curr_timebase);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TEMPO:
|
||||
{
|
||||
int val = IOCTL_IN (arg);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (val < 8)
|
||||
val = 8;
|
||||
if (val > 250)
|
||||
val = 250;
|
||||
tmr_offs = tmr_ctr;
|
||||
ticks_offs += tmr2ticks (tmr_ctr);
|
||||
tmr_ctr = 0;
|
||||
curr_tempo = val;
|
||||
reprogram_timer ();
|
||||
}
|
||||
|
||||
return IOCTL_OUT (arg, curr_tempo);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_SEQ_CTRLRATE:
|
||||
if (IOCTL_IN (arg) != 0) /* Can't change */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_METRONOME:
|
||||
/* NOP */
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
timer_arm (int dev, long time)
|
||||
{
|
||||
if (time < 0)
|
||||
time = curr_ticks + 1;
|
||||
else if (time <= curr_ticks) /* It's the time */
|
||||
return;
|
||||
|
||||
next_event_time = prev_event_time = time;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct sound_timer_operations sound_timer =
|
||||
{
|
||||
{"OPL-3/GUS Timer", 0},
|
||||
1, /* Priority */
|
||||
0, /* Local device link */
|
||||
timer_open,
|
||||
timer_close,
|
||||
timer_event,
|
||||
timer_get_time,
|
||||
timer_ioctl,
|
||||
timer_arm
|
||||
};
|
||||
|
||||
void
|
||||
sound_timer_interrupt (void)
|
||||
{
|
||||
gus_write8 (0x45, 0); /* Ack IRQ */
|
||||
timer_command (4, 0x80); /* Reset IRQ flags */
|
||||
|
||||
if (!opened)
|
||||
return;
|
||||
|
||||
if (curr_timer == 1)
|
||||
gus_write8 (0x45, 0x04); /* Start timer 1 again */
|
||||
else
|
||||
gus_write8 (0x45, 0x08); /* Start timer 2 again */
|
||||
|
||||
if (!tmr_running)
|
||||
return;
|
||||
|
||||
tmr_ctr++;
|
||||
curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
|
||||
|
||||
if (curr_ticks >= next_event_time)
|
||||
{
|
||||
next_event_time = 0xffffffff;
|
||||
sequencer_timer ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sound_timer_init (int io_base)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (initialized)
|
||||
return; /* There is already a similar timer */
|
||||
|
||||
select_addr = io_base;
|
||||
data_addr = io_base + 1;
|
||||
|
||||
initialized = 1;
|
||||
|
||||
#if 1
|
||||
if (num_sound_timers >= MAX_TIMER_DEV)
|
||||
n = 0; /* Overwrite the system timer */
|
||||
else
|
||||
n = num_sound_timers++;
|
||||
#else
|
||||
n = 0;
|
||||
#endif
|
||||
|
||||
sound_timer_devs[n] = &sound_timer;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
304
sys/i386/isa/sound/sys_timer.c
Normal file
304
sys/i386/isa/sound/sys_timer.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* sound/sys_timer.c
|
||||
*
|
||||
* The default timer for the Level 2 sequencer interface
|
||||
* Uses the (100HZ) timer of kernel.
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SEQUENCER_C
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#ifndef EXCLUDE_SEQUENCER
|
||||
|
||||
static volatile int opened = 0, tmr_running = 0;
|
||||
static volatile time_t tmr_offs, tmr_ctr;
|
||||
static volatile unsigned long ticks_offs;
|
||||
static volatile int curr_tempo, curr_timebase;
|
||||
static volatile unsigned long curr_ticks;
|
||||
static volatile unsigned long next_event_time;
|
||||
static unsigned long prev_event_time;
|
||||
|
||||
static void poll_def_tmr (unsigned long dummy);
|
||||
|
||||
DEFINE_TIMER (def_tmr, poll_def_tmr);
|
||||
|
||||
static unsigned long
|
||||
tmr2ticks (int tmr_value)
|
||||
{
|
||||
/*
|
||||
* Convert system timer ticks (HZ) to MIDI ticks
|
||||
*/
|
||||
|
||||
unsigned long tmp;
|
||||
unsigned long scale;
|
||||
|
||||
tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */
|
||||
|
||||
scale = (60 * 1000) / (curr_tempo * curr_timebase); /* msecs per MIDI tick */
|
||||
|
||||
return (tmp + (scale / 2)) / scale;
|
||||
}
|
||||
|
||||
static void
|
||||
poll_def_tmr (unsigned long dummy)
|
||||
{
|
||||
|
||||
if (opened)
|
||||
{
|
||||
ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);
|
||||
|
||||
if (tmr_running)
|
||||
{
|
||||
tmr_ctr++;
|
||||
curr_ticks = ticks_offs + tmr2ticks (tmr_ctr);
|
||||
|
||||
if (curr_ticks >= next_event_time)
|
||||
{
|
||||
next_event_time = 0xffffffff;
|
||||
sequencer_timer ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tmr_reset (void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
tmr_offs = 0;
|
||||
ticks_offs = 0;
|
||||
tmr_ctr = 0;
|
||||
next_event_time = 0xffffffff;
|
||||
prev_event_time = 0;
|
||||
curr_ticks = 0;
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
def_tmr_open (int dev, int mode)
|
||||
{
|
||||
if (opened)
|
||||
return RET_ERROR (EBUSY);
|
||||
|
||||
tmr_reset ();
|
||||
curr_tempo = 60;
|
||||
curr_timebase = HZ;
|
||||
opened = 1;
|
||||
|
||||
ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
def_tmr_close (int dev)
|
||||
{
|
||||
opened = tmr_running = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
def_tmr_event (int dev, unsigned char *event)
|
||||
{
|
||||
unsigned char cmd = event[1];
|
||||
unsigned long parm = *(int *) &event[4];
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case TMR_WAIT_REL:
|
||||
parm += prev_event_time;
|
||||
case TMR_WAIT_ABS:
|
||||
if (parm > 0)
|
||||
{
|
||||
long time;
|
||||
|
||||
if (parm <= curr_ticks) /* It's the time */
|
||||
return TIMER_NOT_ARMED;
|
||||
|
||||
time = parm;
|
||||
next_event_time = prev_event_time = time;
|
||||
|
||||
return TIMER_ARMED;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_START:
|
||||
tmr_reset ();
|
||||
tmr_running = 1;
|
||||
break;
|
||||
|
||||
case TMR_STOP:
|
||||
tmr_running = 0;
|
||||
break;
|
||||
|
||||
case TMR_CONTINUE:
|
||||
tmr_running = 1;
|
||||
break;
|
||||
|
||||
case TMR_TEMPO:
|
||||
if (parm)
|
||||
{
|
||||
if (parm < 8)
|
||||
parm = 8;
|
||||
if (parm > 250)
|
||||
parm = 250;
|
||||
tmr_offs = tmr_ctr;
|
||||
ticks_offs += tmr2ticks (tmr_ctr);
|
||||
tmr_ctr = 0;
|
||||
curr_tempo = parm;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMR_ECHO:
|
||||
seq_copy_to_input (event, 8);
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
return TIMER_NOT_ARMED;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
def_tmr_get_time (int dev)
|
||||
{
|
||||
if (!opened)
|
||||
return 0;
|
||||
|
||||
return curr_ticks;
|
||||
}
|
||||
|
||||
static int
|
||||
def_tmr_ioctl (int dev,
|
||||
unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case SNDCTL_TMR_SOURCE:
|
||||
return IOCTL_OUT (arg, TMR_INTERNAL);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_START:
|
||||
tmr_reset ();
|
||||
tmr_running = 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_STOP:
|
||||
tmr_running = 0;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_CONTINUE:
|
||||
tmr_running = 1;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TIMEBASE:
|
||||
{
|
||||
int val = IOCTL_IN (arg);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (val < 1)
|
||||
val = 1;
|
||||
if (val > 1000)
|
||||
val = 1000;
|
||||
curr_timebase = val;
|
||||
}
|
||||
|
||||
return IOCTL_OUT (arg, curr_timebase);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_TEMPO:
|
||||
{
|
||||
int val = IOCTL_IN (arg);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (val < 8)
|
||||
val = 8;
|
||||
if (val > 250)
|
||||
val = 250;
|
||||
tmr_offs = tmr_ctr;
|
||||
ticks_offs += tmr2ticks (tmr_ctr);
|
||||
tmr_ctr = 0;
|
||||
curr_tempo = val;
|
||||
}
|
||||
|
||||
return IOCTL_OUT (arg, curr_tempo);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNDCTL_SEQ_CTRLRATE:
|
||||
if (IOCTL_IN (arg) != 0) /* Can't change */
|
||||
return RET_ERROR (EINVAL);
|
||||
|
||||
return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
|
||||
break;
|
||||
|
||||
case SNDCTL_TMR_METRONOME:
|
||||
/* NOP */
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
def_tmr_arm (int dev, long time)
|
||||
{
|
||||
if (time < 0)
|
||||
time = curr_ticks + 1;
|
||||
else if (time <= curr_ticks) /* It's the time */
|
||||
return;
|
||||
|
||||
next_event_time = prev_event_time = time;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct sound_timer_operations default_sound_timer =
|
||||
{
|
||||
{"System Timer", 0},
|
||||
0, /* Priority */
|
||||
0, /* Local device link */
|
||||
def_tmr_open,
|
||||
def_tmr_close,
|
||||
def_tmr_event,
|
||||
def_tmr_get_time,
|
||||
def_tmr_ioctl,
|
||||
def_tmr_arm
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
323
sys/i386/isa/sound/uart6850.c
Normal file
323
sys/i386/isa/sound/uart6850.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* sound/uart6850.c
|
||||
*
|
||||
* Copyright by Hannu Savolainen 1993
|
||||
*
|
||||
* Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl:
|
||||
* added 6850 support, used with COVOX SoundMaster II and custom cards.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met: 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer. 2.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sound_config.h"
|
||||
|
||||
#ifdef CONFIGURE_SOUNDCARD
|
||||
|
||||
#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
|
||||
|
||||
#define DATAPORT (uart6850_base) /*
|
||||
* * * Midi6850 Data I/O Port on IBM
|
||||
* */
|
||||
#define COMDPORT (uart6850_base+1) /*
|
||||
* * * Midi6850 Command Port on IBM */
|
||||
#define STATPORT (uart6850_base+1) /*
|
||||
* * * Midi6850 Status Port on IBM */
|
||||
|
||||
#define uart6850_status() INB(STATPORT)
|
||||
#define input_avail() ((uart6850_status()&INPUT_AVAIL))
|
||||
#define output_ready() ((uart6850_status()&OUTPUT_READY))
|
||||
#define uart6850_cmd(cmd) OUTB(cmd, COMDPORT)
|
||||
#define uart6850_read() INB(DATAPORT)
|
||||
#define uart6850_write(byte) OUTB(byte, DATAPORT)
|
||||
|
||||
#define OUTPUT_READY 0x02 /*
|
||||
* * * Mask for Data Read Ready Bit */
|
||||
#define INPUT_AVAIL 0x01 /*
|
||||
* * * Mask for Data Send Ready Bit */
|
||||
|
||||
#define UART_RESET 0x95 /*
|
||||
* * * 6850 Total Reset Command */
|
||||
#define UART_MODE_ON 0x03 /*
|
||||
* * * 6850 Send/Receive UART Mode */
|
||||
|
||||
static int uart6850_opened = 0;
|
||||
static int uart6850_base = 0x330;
|
||||
static int uart6850_irq;
|
||||
static int uart6850_detected = 0;
|
||||
static int my_dev;
|
||||
|
||||
static int reset_uart6850 (void);
|
||||
static void (*midi_input_intr) (int dev, unsigned char data);
|
||||
|
||||
static void
|
||||
uart6850_input_loop (void)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 10;
|
||||
|
||||
while (count) /*
|
||||
* Not timed out
|
||||
*/
|
||||
if (input_avail ())
|
||||
{
|
||||
unsigned char c = uart6850_read ();
|
||||
|
||||
count = 100;
|
||||
|
||||
if (uart6850_opened & OPEN_READ)
|
||||
midi_input_intr (my_dev, c);
|
||||
}
|
||||
else
|
||||
while (!input_avail () && count)
|
||||
count--;
|
||||
}
|
||||
|
||||
void
|
||||
m6850intr (int unit)
|
||||
{
|
||||
printk ("M");
|
||||
if (input_avail ())
|
||||
uart6850_input_loop ();
|
||||
}
|
||||
|
||||
/*
|
||||
* It looks like there is no input interrupts in the UART mode. Let's try
|
||||
* polling.
|
||||
*/
|
||||
|
||||
static void
|
||||
poll_uart6850 (unsigned long dummy)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DEFINE_TIMER (uart6850_timer, poll_uart6850);
|
||||
|
||||
if (!(uart6850_opened & OPEN_READ))
|
||||
return; /*
|
||||
* No longer required
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (input_avail ())
|
||||
uart6850_input_loop ();
|
||||
|
||||
ACTIVATE_TIMER (uart6850_timer, poll_uart6850, 1); /*
|
||||
* Come back later
|
||||
*/
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_open (int dev, int mode,
|
||||
void (*input) (int dev, unsigned char data),
|
||||
void (*output) (int dev)
|
||||
)
|
||||
{
|
||||
if (uart6850_opened)
|
||||
{
|
||||
printk ("Midi6850: Midi busy\n");
|
||||
return RET_ERROR (EBUSY);
|
||||
}
|
||||
|
||||
uart6850_cmd (UART_RESET);
|
||||
|
||||
uart6850_input_loop ();
|
||||
|
||||
midi_input_intr = input;
|
||||
uart6850_opened = mode;
|
||||
poll_uart6850 (0); /*
|
||||
* Enable input polling
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
uart6850_close (int dev)
|
||||
{
|
||||
uart6850_cmd (UART_MODE_ON);
|
||||
|
||||
uart6850_opened = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_out (int dev, unsigned char midi_byte)
|
||||
{
|
||||
int timeout;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Test for input since pending input seems to block the output.
|
||||
*/
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
if (input_avail ())
|
||||
uart6850_input_loop ();
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
/*
|
||||
* Sometimes it takes about 13000 loops before the output becomes ready
|
||||
* (After reset). Normally it takes just about 10 loops.
|
||||
*/
|
||||
|
||||
for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /*
|
||||
* Wait
|
||||
*/
|
||||
|
||||
if (!output_ready ())
|
||||
{
|
||||
printk ("Midi6850: Timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uart6850_write (midi_byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_command (int dev, unsigned char *midi_byte)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_start_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_end_read (int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_ioctl (int dev, unsigned cmd, unsigned arg)
|
||||
{
|
||||
return RET_ERROR (EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
uart6850_kick (int dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
uart6850_buffer_status (int dev)
|
||||
{
|
||||
return 0; /*
|
||||
* No data in buffers
|
||||
*/
|
||||
}
|
||||
|
||||
#define MIDI_SYNTH_NAME "6850 UART Midi"
|
||||
#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
|
||||
#include "midi_synth.h"
|
||||
|
||||
static struct midi_operations uart6850_operations =
|
||||
{
|
||||
{"6850 UART", 0, 0, SNDCARD_UART6850},
|
||||
&std_midi_synth,
|
||||
uart6850_open,
|
||||
uart6850_close,
|
||||
uart6850_ioctl,
|
||||
uart6850_out,
|
||||
uart6850_start_read,
|
||||
uart6850_end_read,
|
||||
uart6850_kick,
|
||||
uart6850_command,
|
||||
uart6850_buffer_status
|
||||
};
|
||||
|
||||
|
||||
long
|
||||
attach_uart6850 (long mem_start, struct address_info *hw_config)
|
||||
{
|
||||
int ok, timeout;
|
||||
unsigned long flags;
|
||||
|
||||
if (num_midis >= MAX_MIDI_DEV)
|
||||
{
|
||||
printk ("Sound: Too many midi devices detected\n");
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
uart6850_base = hw_config->io_base;
|
||||
uart6850_irq = hw_config->irq;
|
||||
|
||||
if (!uart6850_detected)
|
||||
return RET_ERROR (EIO);
|
||||
|
||||
DISABLE_INTR (flags);
|
||||
|
||||
for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /*
|
||||
* Wait
|
||||
*/
|
||||
uart6850_cmd (UART_MODE_ON);
|
||||
|
||||
ok = 1;
|
||||
|
||||
RESTORE_INTR (flags);
|
||||
|
||||
printk (" <6850 Midi Interface>");
|
||||
|
||||
std_midi_synth.midi_dev = my_dev = num_midis;
|
||||
midi_devs[num_midis++] = &uart6850_operations;
|
||||
return mem_start;
|
||||
}
|
||||
|
||||
static int
|
||||
reset_uart6850 (void)
|
||||
{
|
||||
uart6850_read ();
|
||||
return 1; /*
|
||||
* OK
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
probe_uart6850 (struct address_info *hw_config)
|
||||
{
|
||||
int ok = 0;
|
||||
|
||||
uart6850_base = hw_config->io_base;
|
||||
uart6850_irq = hw_config->irq;
|
||||
|
||||
if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0)
|
||||
return 0;
|
||||
|
||||
ok = reset_uart6850 ();
|
||||
|
||||
uart6850_detected = ok;
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user