⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 es1938.cpp

📁 devloped under vxwork, support ess sound card. driver library, include datasheet.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	}
	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 + -