📄 es1938.cpp
字号:
}
snd_BUG();
return -EINVAL;
}
/* -----------------------------------------------------------------------
* Audio2 Playback (DAC)
* -----------------------------------------------------------------------*/
static snd_pcm_hardware_t snd_es1938_playback =
{
#if VXWORKS_COMPILER_CANT_HANDLE
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 6000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 0x8000, /* DMA controller screws on higher values */
.period_bytes_min = 64,
.period_bytes_max = 0x8000,
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 256,
#else
/*.info = */(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
/* .formats = */ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE,
/* .rates = */ SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
/*.rate_min = */6000,
/*.rate_max = */ 48000,
/*.channels_min = */ 1,
/*.channels_max = */ 2,
/* .buffer_bytes_max = */ 0x8000, /* DMA controller screws on higher values */
/* .period_bytes_min = */ 64,
/* .period_bytes_max = */ 0x8000,
/* .periods_min = */ 1,
/*.periods_max = */ 1024,
/*.fifo_size = */ 256,
#endif
};
static int snd_es1938_playback_open(snd_pcm_substream_t * substream)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
switch (substream->number) {
case 0:
chip->playback1_substream = substream;
break;
case 1:
if (chip->capture_substream)
return -EAGAIN;
chip->playback2_substream = substream;
break;
default:
snd_BUG();
return -EINVAL;
}
runtime->hw = snd_es1938_playback;
#if VX_BUILD_NO_INCLUDE
snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hw_constraints_clocks);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00);
#endif
return 0;
}
static int snd_es1938_capture_close(snd_pcm_substream_t * substream)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
chip->capture_substream = NULL;
return 0;
}
static int snd_es1938_playback_close(snd_pcm_substream_t * substream)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
switch (substream->number) {
case 0:
chip->playback1_substream = NULL;
break;
case 1:
chip->playback2_substream = NULL;
break;
default:
snd_BUG();
return -EINVAL;
}
return 0;
}
static int snd_es1938_playback1_trigger(snd_pcm_substream_t * substream,
int cmd)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
/* According to the documentation this should be:
0x13 but that value may randomly swap stereo channels */
snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x92);
udelay(10);
snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x93);
/* This two stage init gives the FIFO -> DAC connection time to
* settle before first data from DMA flows in. This should ensure
* no swapping of stereo channels. Report a bug if otherwise :-) */
outb(0x0a, SLIO_REG(chip, AUDIO2MODE));
chip->active |= DAC2;
break;
case SNDRV_PCM_TRIGGER_STOP:
outb(0, SLIO_REG(chip, AUDIO2MODE));
snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0);
chip->active &= ~DAC2;
break;
default:
return -EINVAL;
}
return 0;
}
static int snd_es1938_playback2_trigger(snd_pcm_substream_t * substream,
int cmd)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
int val;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
val = 5;
chip->active |= DAC1;
break;
case SNDRV_PCM_TRIGGER_STOP:
val = 0;
chip->active &= ~DAC1;
break;
default:
return -EINVAL;
}
snd_es1938_write(chip, ESS_CMD_DMACONTROL, val);
return 0;
}
static int snd_es1938_playback_trigger(snd_pcm_substream_t *substream,
int cmd)
{
switch (substream->number) {
case 0:
return snd_es1938_playback1_trigger(substream, cmd);
case 1:
return snd_es1938_playback2_trigger(substream, cmd);
}
snd_BUG();
return -EINVAL;
}
static snd_pcm_uframes_t snd_es1938_playback1_pointer(snd_pcm_substream_t * substream)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
size_t ptr;
#if 1
ptr = chip->dma2_size - inw(SLIO_REG(chip, AUDIO2DMACOUNT));
#else
ptr = inl(SLIO_REG(chip, AUDIO2DMAADDR)) - chip->dma2_start;
#endif
return ptr >> chip->dma2_shift;
}
static snd_pcm_uframes_t snd_es1938_playback2_pointer(snd_pcm_substream_t * substream)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
size_t ptr;
size_t old, newval;
#if 1
/* This stuff is *needed*, don't ask why - AB */
old = inw(SLDM_REG(chip, DMACOUNT));
while ((newval = inw(SLDM_REG(chip, DMACOUNT))) != old)
old = newval;
ptr = chip->dma1_size - 1 - newval;
#else
ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start;
#endif
return ptr >> chip->dma1_shift;
}
static snd_pcm_uframes_t snd_es1938_playback_pointer(snd_pcm_substream_t *substream)
{
switch (substream->number) {
case 0:
return snd_es1938_playback1_pointer(substream);
case 1:
return snd_es1938_playback2_pointer(substream);
}
snd_BUG();
return (snd_pcm_uframes_t) -EINVAL;
}
/* ----------------------------------------------------------------------
* Audio1 Capture (ADC)
* ----------------------------------------------------------------------*/
static snd_pcm_hardware_t snd_es1938_capture =
{
#if VXWORKS_COMPILER_CANT_HANDLE
.info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 6000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 0x8000, /* DMA controller screws on higher values */
.period_bytes_min = 64,
.period_bytes_max = 0x8000,
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 256,
#else
/*.info = */ (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER),
/*.formats = */ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE,
/* .rates = */ SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
/*.rate_min = */ 6000,
/*.rate_max = */ 48000,
/*.channels_min = */ 1,
/*.channels_max = */ 2,
/* .buffer_bytes_max = */ 0x8000, /* DMA controller screws on higher values */
/* .period_bytes_min = */ 64,
/*.period_bytes_max = */ 0x8000,
/*.periods_min = */ 1,
/*.periods_max = */ 1024,
/*.fifo_size = */ 256,
#endif
};
static int snd_es1938_capture_open(snd_pcm_substream_t * substream)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
if (chip->playback2_substream)
return -EAGAIN;
chip->capture_substream = substream;
runtime->hw = snd_es1938_capture;
#if VX_BUILD_NO_INCLUDE
snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&hw_constraints_clocks);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00);
#endif
return 0;
}
static snd_pcm_ops_t snd_es1938_playback_ops = {
snd_es1938_playback_open,
snd_es1938_playback_close,
/* snd_pcm_lib_ioctl,
.hw_params = snd_es1938_pcm_hw_params,
.hw_free = snd_es1938_pcm_hw_free,
*/ snd_es1938_playback_prepare,
snd_es1938_playback_trigger,
snd_es1938_set_volume,
snd_es1938_playback_pointer,
};
/* --------------------------------------------------------------------
* First channel for Extended Mode Audio 1 ADC Operation
* --------------------------------------------------------------------*/
static int snd_es1938_capture_prepare(snd_pcm_substream_t * substream)
{
es1938_t *chip = (es1938_t *) snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int u, is8, mono;
unsigned int size = snd_pcm_lib_buffer_bytes(substream);
unsigned int count = snd_pcm_lib_period_bytes(substream);
chip->dma1_size = size;
chip->dma1_start = runtime->dma_addr;
mono = (runtime->channels > 1) ? 0 : 1;
is8 = snd_pcm_format_width(runtime->format) == 16 ? 0 : 1;
u = snd_pcm_format_unsigned(runtime->format);
chip->dma1_shift = 2 - mono - is8;
snd_es1938_reset_fifo(chip);
/* program type */
snd_es1938_bits(chip, ESS_CMD_ANALOGCONTROL, 0x03, (mono ? 2 : 1));
/* set clock and counters */
snd_es1938_rate_set(chip, substream, ADC1);
count = 0x10000 - count;
snd_es1938_write(chip, ESS_CMD_DMACNTRELOADL, count & 0xff);
snd_es1938_write(chip, ESS_CMD_DMACNTRELOADH, count >> 8);
/* initialize and configure ADC */
snd_es1938_write(chip, ESS_CMD_SETFORMAT2, u ? 0x51 : 0x71);
snd_es1938_write(chip, ESS_CMD_SETFORMAT2, 0x90 |
(u ? 0x00 : 0x20) |
(is8 ? 0x00 : 0x04) |
(mono ? 0x40 : 0x08));
// snd_es1938_reset_fifo(chip);
/* 11. configure system interrupt controller and DMA controller */
snd_es1938_capture_setdma(chip);
return 0;
}
static int snd_es1938_capture_trigger(snd_pcm_substream_t * substream,
int cmd)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
int val;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
val = 0x0f;
chip->active |= ADC1;
break;
case SNDRV_PCM_TRIGGER_STOP:
val = 0x00;
chip->active &= ~ADC1;
break;
default:
return -EINVAL;
}
snd_es1938_write(chip, ESS_CMD_DMACONTROL, val);
return 0;
}
static snd_pcm_uframes_t snd_es1938_capture_pointer(snd_pcm_substream_t * substream)
{
es1938_t *chip = (es1938_t *)snd_pcm_substream_chip(substream);
size_t ptr;
size_t old, newval;
#if 1
/* This stuff is *needed*, don't ask why - AB */
old = inw(SLDM_REG(chip, DMACOUNT));
while ((newval = inw(SLDM_REG(chip, DMACOUNT))) != old)
old = newval;
ptr = chip->dma1_size - 1 - newval;
#else
ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start;
#endif
return ptr >> chip->dma1_shift;
}
static snd_pcm_ops_t snd_es1938_capture_ops = {
snd_es1938_capture_open,
snd_es1938_capture_close,
/* snd_pcm_lib_ioctl,
.hw_params = snd_es1938_pcm_hw_params,
.hw_free = snd_es1938_pcm_hw_free,
*/ snd_es1938_capture_prepare,
snd_es1938_capture_trigger,
0,
snd_es1938_capture_pointer,
/* .copy = snd_es1938_capture_copy, */
};
static void snd_es1938_free_pcm(snd_pcm_t *pcm)
{
/* this is already done by snd_pcm_free
snd_pcm_lib_preallocate_free_for_all(pcm);
*/
}
static int __devinit snd_es1938_new_pcm(es1938_t *chip, int device)
{
snd_pcm_t *pcm;
int err;
if ((err = snd_pcm_new(chip->card, "es-1938-1946", device, 2, 1, &pcm)) < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1938_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1938_capture_ops);
pcm->private_data = chip;
pcm->private_free = snd_es1938_free_pcm;
pcm->info_flags = 0;
strcpy(pcm->name, "ESS Solo-1");
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
chip->pcm = pcm;
return 0;
}
/* -----------------------------------------------------------------
* Write to some bits of a mixer register (return old value)
* -----------------------------------------------------------------*/
static int snd_es1938_mixer_bits(es1938_t *chip, unsigned char reg, unsigned char mask, unsigned char val)
{
unsigned long flags;
unsigned char old, newval, oval;
spin_lock_irqsave(&chip->mixer_lock, flags);
outb(reg, SLSB_REG(chip, MIXERADDR));
old = inb(SLSB_REG(chip, MIXERDATA));
oval = old & mask;
if (val != oval) {
newval = (old & ~mask) | (val & mask);
outb(newval, SLSB_REG(chip, MIXERDATA));
#ifdef REG_DEBUG
snd_printk_interrupt("Mixer reg %02x was %02x, set to %02x\n", reg, old, newval);
#endif
}
spin_unlock_irqrestore(&chip->mixer_lock, flags);
return oval;
}
static int snd_es1938_free(es1938_t *chip)
{
#if VXWORKS_UNUSED
if (chip->rmidi)
snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0);
snd_es1938_free_gameport(chip);
#endif
if (chip->irq >= 0)
{
free_irq(chip->irq, (void *)chip, snd_es1938_interrupt );
}
/* pci_release_regions(chip->pci); */
/* pci_disable_device(chip->pci); */
/* disable irqs */
outb(0x00, SLIO_REG(chip, IRQCONTROL));
/* added by Dan Walkes: turn the volume off here */
snd_es1938_mixer_write(chip,ESSSB_IREG_AUDIO2,0);
snd_es1938_mixer_write(chip,ESSSB_IREG_AUDIO1,0);
snd_es1938_reset_fifo( chip );
snd_es1938_reset( chip );
kfree(chip);
return 0;
}
static int snd_es1938_dev_free(snd_device_t *device)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -