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

📄 es1968.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	spin_lock(&chip->reg_lock);	__apu_set_register(chip, es->apu[0], 5, es->base[0]);	snd_es1968_trigger_apu(chip, es->apu[0], es->apu_mode[0]);	if (es->mode == ESM_MODE_CAPTURE) {		__apu_set_register(chip, es->apu[2], 5, es->base[2]);		snd_es1968_trigger_apu(chip, es->apu[2], es->apu_mode[2]);	}	if (es->fmt & ESS_FMT_STEREO) {		__apu_set_register(chip, es->apu[1], 5, es->base[1]);		snd_es1968_trigger_apu(chip, es->apu[1], es->apu_mode[1]);		if (es->mode == ESM_MODE_CAPTURE) {			__apu_set_register(chip, es->apu[3], 5, es->base[3]);			snd_es1968_trigger_apu(chip, es->apu[3], es->apu_mode[3]);		}	}	spin_unlock(&chip->reg_lock);}static void snd_es1968_pcm_stop(struct es1968 *chip, struct esschan *es){	spin_lock(&chip->reg_lock);	snd_es1968_trigger_apu(chip, es->apu[0], 0);	snd_es1968_trigger_apu(chip, es->apu[1], 0);	if (es->mode == ESM_MODE_CAPTURE) {		snd_es1968_trigger_apu(chip, es->apu[2], 0);		snd_es1968_trigger_apu(chip, es->apu[3], 0);	}	spin_unlock(&chip->reg_lock);}/* set the wavecache control reg */static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es,					 int channel, u32 addr, int capture){	u32 tmpval = (addr - 0x10) & 0xFFF8;	if (! capture) {		if (!(es->fmt & ESS_FMT_16BIT))			tmpval |= 4;	/* 8bit */		if (es->fmt & ESS_FMT_STEREO)			tmpval |= 2;	/* stereo */	}	/* set the wavecache control reg */	wave_set_register(chip, es->apu[channel] << 3, tmpval);#ifdef CONFIG_PM	es->wc_map[channel] = tmpval;#endif}static void snd_es1968_playback_setup(struct es1968 *chip, struct esschan *es,				      struct snd_pcm_runtime *runtime){	u32 pa;	int high_apu = 0;	int channel, apu;	int i, size;	unsigned long flags;	u32 freq;	size = es->dma_size >> es->wav_shift;	if (es->fmt & ESS_FMT_STEREO)		high_apu++;	for (channel = 0; channel <= high_apu; channel++) {		apu = es->apu[channel];		snd_es1968_program_wavecache(chip, es, channel, es->memory->buf.addr, 0);		/* Offset to PCMBAR */		pa = es->memory->buf.addr;		pa -= chip->dma.addr;		pa >>= 1;	/* words */		pa |= 0x00400000;	/* System RAM (Bit 22) */		if (es->fmt & ESS_FMT_STEREO) {			/* Enable stereo */			if (channel)				pa |= 0x00800000;	/* (Bit 23) */			if (es->fmt & ESS_FMT_16BIT)				pa >>= 1;		}		/* base offset of dma calcs when reading the pointer		   on this left one */		es->base[channel] = pa & 0xFFFF;		for (i = 0; i < 16; i++)			apu_set_register(chip, apu, i, 0x0000);		/* Load the buffer into the wave engine */		apu_set_register(chip, apu, 4, ((pa >> 16) & 0xFF) << 8);		apu_set_register(chip, apu, 5, pa & 0xFFFF);		apu_set_register(chip, apu, 6, (pa + size) & 0xFFFF);		/* setting loop == sample len */		apu_set_register(chip, apu, 7, size);		/* clear effects/env.. */		apu_set_register(chip, apu, 8, 0x0000);		/* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */		apu_set_register(chip, apu, 9, 0xD000);		/* clear routing stuff */		apu_set_register(chip, apu, 11, 0x0000);		/* dma on, no envelopes, filter to all 1s) */		apu_set_register(chip, apu, 0, 0x400F);		if (es->fmt & ESS_FMT_16BIT)			es->apu_mode[channel] = ESM_APU_16BITLINEAR;		else			es->apu_mode[channel] = ESM_APU_8BITLINEAR;		if (es->fmt & ESS_FMT_STEREO) {			/* set panning: left or right */			/* Check: different panning. On my Canyon 3D Chipset the			   Channels are swapped. I don't know, about the output			   to the SPDif Link. Perhaps you have to change this			   and not the APU Regs 4-5. */			apu_set_register(chip, apu, 10,					 0x8F00 | (channel ? 0 : 0x10));			es->apu_mode[channel] += 1;	/* stereo */		} else			apu_set_register(chip, apu, 10, 0x8F08);	}	spin_lock_irqsave(&chip->reg_lock, flags);	/* clear WP interrupts */	outw(1, chip->io_port + 0x04);	/* enable WP ints */	outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ);	spin_unlock_irqrestore(&chip->reg_lock, flags);	freq = runtime->rate;	/* set frequency */	if (freq > 48000)		freq = 48000;	if (freq < 4000)		freq = 4000;	/* hmmm.. */	if (!(es->fmt & ESS_FMT_16BIT) && !(es->fmt & ESS_FMT_STEREO))		freq >>= 1;	freq = snd_es1968_compute_rate(chip, freq);	/* Load the frequency, turn on 6dB */	snd_es1968_apu_set_freq(chip, es->apu[0], freq);	snd_es1968_apu_set_freq(chip, es->apu[1], freq);}static void init_capture_apu(struct es1968 *chip, struct esschan *es, int channel,			     unsigned int pa, unsigned int bsize,			     int mode, int route){	int i, apu = es->apu[channel];	es->apu_mode[channel] = mode;	/* set the wavecache control reg */	snd_es1968_program_wavecache(chip, es, channel, pa, 1);	/* Offset to PCMBAR */	pa -= chip->dma.addr;	pa >>= 1;	/* words */	/* base offset of dma calcs when reading the pointer	   on this left one */	es->base[channel] = pa & 0xFFFF;	pa |= 0x00400000;	/* bit 22 -> System RAM */	/* Begin loading the APU */	for (i = 0; i < 16; i++)		apu_set_register(chip, apu, i, 0x0000);	/* need to enable subgroups.. and we should probably	   have different groups for different /dev/dsps..  */	apu_set_register(chip, apu, 2, 0x8);	/* Load the buffer into the wave engine */	apu_set_register(chip, apu, 4, ((pa >> 16) & 0xFF) << 8);	apu_set_register(chip, apu, 5, pa & 0xFFFF);	apu_set_register(chip, apu, 6, (pa + bsize) & 0xFFFF);	apu_set_register(chip, apu, 7, bsize);	/* clear effects/env.. */	apu_set_register(chip, apu, 8, 0x00F0);	/* amplitude now?  sure.  why not.  */	apu_set_register(chip, apu, 9, 0x0000);	/* set filter tune, radius, polar pan */	apu_set_register(chip, apu, 10, 0x8F08);	/* route input */	apu_set_register(chip, apu, 11, route);	/* dma on, no envelopes, filter to all 1s) */	apu_set_register(chip, apu, 0, 0x400F);}static void snd_es1968_capture_setup(struct es1968 *chip, struct esschan *es,				     struct snd_pcm_runtime *runtime){	int size;	u32 freq;	unsigned long flags;	size = es->dma_size >> es->wav_shift;	/* APU assignments:	   0 = mono/left SRC	   1 = right SRC	   2 = mono/left Input Mixer	   3 = right Input Mixer	*/	/* data seems to flow from the codec, through an apu into	   the 'mixbuf' bit of page, then through the SRC apu	   and out to the real 'buffer'.  ok.  sure.  */	/* input mixer (left/mono) */	/* parallel in crap, see maestro reg 0xC [8-11] */	init_capture_apu(chip, es, 2,			 es->mixbuf->buf.addr, ESM_MIXBUF_SIZE/4, /* in words */			 ESM_APU_INPUTMIXER, 0x14);	/* SRC (left/mono); get input from inputing apu */	init_capture_apu(chip, es, 0, es->memory->buf.addr, size,			 ESM_APU_SRCONVERTOR, es->apu[2]);	if (es->fmt & ESS_FMT_STEREO) {		/* input mixer (right) */		init_capture_apu(chip, es, 3,				 es->mixbuf->buf.addr + ESM_MIXBUF_SIZE/2,				 ESM_MIXBUF_SIZE/4, /* in words */				 ESM_APU_INPUTMIXER, 0x15);		/* SRC (right) */		init_capture_apu(chip, es, 1,				 es->memory->buf.addr + size*2, size,				 ESM_APU_SRCONVERTOR, es->apu[3]);	}	freq = runtime->rate;	/* Sample Rate conversion APUs don't like 0x10000 for their rate */	if (freq > 47999)		freq = 47999;	if (freq < 4000)		freq = 4000;	freq = snd_es1968_compute_rate(chip, freq);	/* Load the frequency, turn on 6dB */	snd_es1968_apu_set_freq(chip, es->apu[0], freq);	snd_es1968_apu_set_freq(chip, es->apu[1], freq);	/* fix mixer rate at 48khz.  and its _must_ be 0x10000. */	freq = 0x10000;	snd_es1968_apu_set_freq(chip, es->apu[2], freq);	snd_es1968_apu_set_freq(chip, es->apu[3], freq);	spin_lock_irqsave(&chip->reg_lock, flags);	/* clear WP interrupts */	outw(1, chip->io_port + 0x04);	/* enable WP ints */	outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ);	spin_unlock_irqrestore(&chip->reg_lock, flags);}/******************* *  ALSA Interface * *******************/static int snd_es1968_pcm_prepare(struct snd_pcm_substream *substream){	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct esschan *es = runtime->private_data;	es->dma_size = snd_pcm_lib_buffer_bytes(substream);	es->frag_size = snd_pcm_lib_period_bytes(substream);	es->wav_shift = 1; /* maestro handles always 16bit */	es->fmt = 0;	if (snd_pcm_format_width(runtime->format) == 16)		es->fmt |= ESS_FMT_16BIT;	if (runtime->channels > 1) {		es->fmt |= ESS_FMT_STEREO;		if (es->fmt & ESS_FMT_16BIT) /* 8bit is already word shifted */			es->wav_shift++;	}	es->bob_freq = snd_es1968_calc_bob_rate(chip, es, runtime);	switch (es->mode) {	case ESM_MODE_PLAY:		snd_es1968_playback_setup(chip, es, runtime);		break;	case ESM_MODE_CAPTURE:		snd_es1968_capture_setup(chip, es, runtime);		break;	}	return 0;}static int snd_es1968_pcm_trigger(struct snd_pcm_substream *substream, int cmd){	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct esschan *es = substream->runtime->private_data;	spin_lock(&chip->substream_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		if (es->running)			break;		snd_es1968_bob_inc(chip, es->bob_freq);		es->count = 0;		es->hwptr = 0;		snd_es1968_pcm_start(chip, es);		es->running = 1;		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		if (! es->running)			break;		snd_es1968_pcm_stop(chip, es);		es->running = 0;		snd_es1968_bob_dec(chip);		break;	}	spin_unlock(&chip->substream_lock);	return 0;}static snd_pcm_uframes_t snd_es1968_pcm_pointer(struct snd_pcm_substream *substream){	struct es1968 *chip = snd_pcm_substream_chip(substream);	struct esschan *es = substream->runtime->private_data;	unsigned int ptr;	ptr = snd_es1968_get_dma_ptr(chip, es) << es->wav_shift;		return bytes_to_frames(substream->runtime, ptr % es->dma_size);}static struct snd_pcm_hardware snd_es1968_playback = {	.info =			(SNDRV_PCM_INFO_MMAP |               		         SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 /*SNDRV_PCM_INFO_PAUSE |*/				 SNDRV_PCM_INFO_RESUME),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		4000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	65536,	.period_bytes_min =	256,	.period_bytes_max =	65536,	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static struct snd_pcm_hardware snd_es1968_capture = {	.info =			(SNDRV_PCM_INFO_NONINTERLEAVED |				 SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_MMAP_VALID |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 /*SNDRV_PCM_INFO_PAUSE |*/				 SNDRV_PCM_INFO_RESUME),	.formats =		/*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		4000,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	65536,	.period_bytes_min =	256,	.period_bytes_max =	65536,	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};/* *************************   * DMA memory management *   *************************//* Because the Maestro can only take addresses relative to the PCM base address   register :( */static int calc_available_memory_size(struct es1968 *chip){	int max_size = 0;	struct esm_memory *buf;	mutex_lock(&chip->memory_mutex);	list_for_each_entry(buf, &chip->buf_list, list) {		if (buf->empty && buf->buf.bytes > max_size)			max_size = buf->buf.bytes;	}	mutex_unlock(&chip->memory_mutex);	if (max_size >= 128*1024)		max_size = 127*1024;	return max_size;}/* allocate a new memory chunk with the specified size */static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size){	struct esm_memory *buf;	size = ALIGN(size, ESM_MEM_ALIGN);	mutex_lock(&chip->memory_mutex);	list_for_each_entry(buf, &chip->buf_list, list) {		if (buf->empty && buf->buf.bytes >= size)			goto __found;	}	mutex_unlock(&chip->memory_mutex);	return NULL;__found:	if (buf->buf.bytes > size) {		struct esm_memory *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL);		if (chunk == NULL) {			mutex_unlock(&chip->memory_mutex);			return NULL;		}		chunk->buf = buf->buf;		chunk->buf.bytes -= size;		chunk->buf.area += size;		chunk->buf.addr += size;		chunk->empty = 1;		buf->buf.bytes = size;		list_add(&chunk->list, &buf->list);	}	buf->empty = 0;	mutex_unlock(&chip->memory_mutex);	return buf;}/* free a memory chunk */static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf){	struct esm_memory *chunk;	mutex_lock(&chip->memory_mutex);	buf->empty = 1;	if (buf->list.prev != &chip->buf_list) {		chunk = list_entry(buf->list.prev, struct esm_memory, list);		if (chunk->empty) {			chunk->buf.bytes += buf->buf.bytes;			list_del(&buf->list);			kfree(buf);			buf = chunk;		}	}	if (buf->list.next != &chip->buf_list) {		chunk = list_entry(buf->list.next, struct esm_memory, list);		if (chunk->empty) {			buf->buf.bytes += chunk->buf.bytes;			list_del(&chunk->list);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -