cs46xx_lib.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,248 行 · 第 1/5 页

C
2,248
字号
	default:		result = -EINVAL;		break;	}#ifndef CONFIG_SND_CS46XX_NEW_DSP	spin_unlock(&chip->reg_lock);#endif	return result;}static int snd_cs46xx_capture_trigger(snd_pcm_substream_t * substream,				      int cmd){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	unsigned int tmp;	int result = 0;	spin_lock(&chip->reg_lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		tmp = snd_cs46xx_peek(chip, BA1_CCTL);		tmp &= 0xffff0000;		snd_cs46xx_poke(chip, BA1_CCTL, chip->capt.ctl | tmp);		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		tmp = snd_cs46xx_peek(chip, BA1_CCTL);		tmp &= 0xffff0000;		snd_cs46xx_poke(chip, BA1_CCTL, tmp);		break;	default:		result = -EINVAL;		break;	}	spin_unlock(&chip->reg_lock);	return result;}#ifdef CONFIG_SND_CS46XX_NEW_DSPstatic int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm,				       int sample_rate) {	/* If PCMReaderSCB and SrcTaskSCB not created yet ... */	if ( cpcm->pcm_channel == NULL) {		cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, 								   cpcm, cpcm->hw_buf.addr,cpcm->pcm_channel_id);		if (cpcm->pcm_channel == NULL) {			snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");			return -ENOMEM;		}		cpcm->pcm_channel->sample_rate = sample_rate;	} else	/* if sample rate is changed */	if ((int)cpcm->pcm_channel->sample_rate != sample_rate) {		int unlinked = cpcm->pcm_channel->unlinked;		cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);		if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, 									 cpcm->hw_buf.addr,									 cpcm->pcm_channel_id)) == NULL) {			snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");			return -ENOMEM;		}		if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel);		cpcm->pcm_channel->sample_rate = sample_rate;	}	return 0;}#endifstatic int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,					 snd_pcm_hw_params_t * hw_params){	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_pcm_t *cpcm;	int err;#ifdef CONFIG_SND_CS46XX_NEW_DSP	cs46xx_t *chip = snd_pcm_substream_chip(substream);	int sample_rate = params_rate(hw_params);	int period_size = params_period_bytes(hw_params);#endif	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);#ifdef CONFIG_SND_CS46XX_NEW_DSP	snd_assert (sample_rate != 0, return -ENXIO);	down (&chip->spos_mutex);	if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {		up (&chip->spos_mutex);		return -ENXIO;	}	snd_assert (cpcm->pcm_channel != NULL);	if (!cpcm->pcm_channel) {		up (&chip->spos_mutex);		return -ENXIO;	}	if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size)) {		 up (&chip->spos_mutex);		 return -EINVAL;	 }	snd_printdd ("period_size (%d), periods (%d) buffer_size(%d)\n",		     period_size, params_periods(hw_params),		     params_buffer_bytes(hw_params));#endif	if (params_periods(hw_params) == CS46XX_FRAGS) {		if (runtime->dma_area != cpcm->hw_buf.area)			snd_pcm_lib_free_pages(substream);		runtime->dma_area = cpcm->hw_buf.area;		runtime->dma_addr = cpcm->hw_buf.addr;		runtime->dma_bytes = cpcm->hw_buf.bytes;#ifdef CONFIG_SND_CS46XX_NEW_DSP		if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {			substream->ops = &snd_cs46xx_playback_ops;		} else if (cpcm->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {			substream->ops = &snd_cs46xx_playback_rear_ops;		} else if (cpcm->pcm_channel_id == DSP_PCM_CENTER_LFE_CHANNEL) {			substream->ops = &snd_cs46xx_playback_clfe_ops;		} else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {			substream->ops = &snd_cs46xx_playback_iec958_ops;		} else {			snd_assert(0);		}#else		substream->ops = &snd_cs46xx_playback_ops;#endif	} else {		if (runtime->dma_area == cpcm->hw_buf.area) {			runtime->dma_area = NULL;			runtime->dma_addr = 0;			runtime->dma_bytes = 0;		}		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) {#ifdef CONFIG_SND_CS46XX_NEW_DSP			up (&chip->spos_mutex);#endif			return err;		}#ifdef CONFIG_SND_CS46XX_NEW_DSP		if (cpcm->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {			substream->ops = &snd_cs46xx_playback_indirect_ops;		} else if (cpcm->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {			substream->ops = &snd_cs46xx_playback_indirect_rear_ops;		} else if (cpcm->pcm_channel_id == DSP_PCM_CENTER_LFE_CHANNEL) {			substream->ops = &snd_cs46xx_playback_indirect_clfe_ops;		} else if (cpcm->pcm_channel_id == DSP_IEC958_CHANNEL) {			substream->ops = &snd_cs46xx_playback_indirect_iec958_ops;		} else {			snd_assert(0);		}#else		substream->ops = &snd_cs46xx_playback_indirect_ops;#endif	}#ifdef CONFIG_SND_CS46XX_NEW_DSP	up (&chip->spos_mutex);#endif	return 0;}static int snd_cs46xx_playback_hw_free(snd_pcm_substream_t * substream){	/*cs46xx_t *chip = snd_pcm_substream_chip(substream);*/	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_pcm_t *cpcm;	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);	/* if play_back open fails, then this function	   is called and cpcm can actually be NULL here */	if (!cpcm) return -ENXIO;	if (runtime->dma_area != cpcm->hw_buf.area)		snd_pcm_lib_free_pages(substream);    	runtime->dma_area = NULL;	runtime->dma_addr = 0;	runtime->dma_bytes = 0;	return 0;}static int snd_cs46xx_playback_prepare(snd_pcm_substream_t * substream){	unsigned int tmp;	unsigned int pfie;	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	cs46xx_pcm_t *cpcm;	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);#ifdef CONFIG_SND_CS46XX_NEW_DSP    snd_assert (cpcm->pcm_channel != NULL, return -ENXIO);	pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 );	pfie &= ~0x0000f03f;#else	/* old dsp */	pfie = snd_cs46xx_peek(chip, BA1_PFIE); 	pfie &= ~0x0000f03f;#endif	cpcm->shift = 2;	/* if to convert from stereo to mono */	if (runtime->channels == 1) {		cpcm->shift--;		pfie |= 0x00002000;	}	/* if to convert from 8 bit to 16 bit */	if (snd_pcm_format_width(runtime->format) == 8) {		cpcm->shift--;		pfie |= 0x00001000;	}	/* if to convert to unsigned */	if (snd_pcm_format_unsigned(runtime->format))		pfie |= 0x00008000;	/* Never convert byte order when sample stream is 8 bit */	if (snd_pcm_format_width(runtime->format) != 8) {		/* convert from big endian to little endian */		if (snd_pcm_format_big_endian(runtime->format))			pfie |= 0x00004000;	}		cpcm->sw_bufsize = snd_pcm_lib_buffer_bytes(substream);	cpcm->sw_data = cpcm->sw_io = cpcm->sw_ready = 0;	cpcm->hw_data = cpcm->hw_io = cpcm->hw_ready = 0;	cpcm->appl_ptr = 0;#ifdef CONFIG_SND_CS46XX_NEW_DSP	tmp = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2);	tmp &= ~0x000003ff;	tmp |= (4 << cpcm->shift) - 1;	/* playback transaction count register */	snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2, tmp);	/* playback format && interrupt enable */	snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2, pfie | cpcm->pcm_channel->pcm_slot);#else	snd_cs46xx_poke(chip, BA1_PBA, cpcm->hw_buf.addr);	tmp = snd_cs46xx_peek(chip, BA1_PDTC);	tmp &= ~0x000003ff;	tmp |= (4 << cpcm->shift) - 1;	snd_cs46xx_poke(chip, BA1_PDTC, tmp);	snd_cs46xx_poke(chip, BA1_PFIE, pfie);	snd_cs46xx_set_play_sample_rate(chip, runtime->rate);#endif	return 0;}static int snd_cs46xx_capture_hw_params(snd_pcm_substream_t * substream,					snd_pcm_hw_params_t * hw_params){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	int err;#ifdef CONFIG_SND_CS46XX_NEW_DSP	cs46xx_dsp_pcm_ostream_set_period (chip, params_period_bytes(hw_params));#endif	if (runtime->periods == CS46XX_FRAGS) {		if (runtime->dma_area != chip->capt.hw_buf.area)			snd_pcm_lib_free_pages(substream);		runtime->dma_area = chip->capt.hw_buf.area;		runtime->dma_addr = chip->capt.hw_buf.addr;		runtime->dma_bytes = chip->capt.hw_buf.bytes;		substream->ops = &snd_cs46xx_capture_ops;	} else {		if (runtime->dma_area == chip->capt.hw_buf.area) {			runtime->dma_area = NULL;			runtime->dma_addr = 0;			runtime->dma_bytes = 0;		}		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)			return err;		substream->ops = &snd_cs46xx_capture_indirect_ops;	}	return 0;}static int snd_cs46xx_capture_hw_free(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	if (runtime->dma_area != chip->capt.hw_buf.area)		snd_pcm_lib_free_pages(substream);	runtime->dma_area = NULL;	runtime->dma_addr = 0;	runtime->dma_bytes = 0;	return 0;}static int snd_cs46xx_capture_prepare(snd_pcm_substream_t * substream){	cs46xx_t *chip = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_buf.addr);	chip->capt.shift = 2;	chip->capt.sw_bufsize = snd_pcm_lib_buffer_bytes(substream);	chip->capt.sw_data = chip->capt.sw_io = chip->capt.sw_ready = 0;	chip->capt.hw_data = chip->capt.hw_io = chip->capt.hw_ready = 0;	chip->capt.appl_ptr = 0;	snd_cs46xx_set_capture_sample_rate(chip, runtime->rate);	return 0;}static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs){	cs46xx_t *chip = snd_magic_cast(cs46xx_t, dev_id, return IRQ_NONE);	u32 status1;#ifdef CONFIG_SND_CS46XX_NEW_DSP	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	u32 status2;	int i;	cs46xx_pcm_t *cpcm = NULL;#endif	/*	 *  Read the Interrupt Status Register to clear the interrupt	 */	status1 = snd_cs46xx_peekBA0(chip, BA0_HISR);	if ((status1 & 0x7fffffff) == 0) {		snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV);		return IRQ_NONE;	}#ifdef CONFIG_SND_CS46XX_NEW_DSP	status2 = snd_cs46xx_peekBA0(chip, BA0_HSR0);	for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) {		if (i <= 15) {			if ( status1 & (1 << i) ) {				if (i == CS46XX_DSP_CAPTURE_CHANNEL) {					if (chip->capt.substream)						snd_pcm_period_elapsed(chip->capt.substream);				} else {					if (ins->pcm_channels[i].active &&					    ins->pcm_channels[i].private_data &&					    !ins->pcm_channels[i].unlinked) {						cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, continue);						snd_pcm_period_elapsed(cpcm->substream);					}				}			}		} else {			if ( status2 & (1 << (i - 16))) {				if (ins->pcm_channels[i].active && 				    ins->pcm_channels[i].private_data &&				    !ins->pcm_channels[i].unlinked) {					cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, continue);					snd_pcm_period_elapsed(cpcm->substream);				}			}		}	}#else	/* old dsp */	if ((status1 & HISR_VC0) && chip->playback_pcm) {		if (chip->playback_pcm->substream)			snd_pcm_period_elapsed(chip->playback_pcm->substream);	}	if ((status1 & HISR_VC1) && chip->pcm) {		if (chip->capt.substream)			snd_pcm_period_elapsed(chip->capt.substream);	}#endif	if ((status1 & HISR_MIDI) && chip->rmidi) {		unsigned char c;				spin_lock(&chip->reg_lock);		while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_RBE) == 0) {			c = snd_cs46xx_peekBA0(chip, BA0_MIDRP);			if ((chip->midcr & MIDCR_RIE) == 0)				continue;			snd_rawmidi_receive(chip->midi_input, &c, 1);		}		while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_TBF) == 0) {			if ((chip->midcr & MIDCR_TIE) == 0)				break;			if (snd_rawmidi_transmit(chip->midi_output, &c, 1) != 1) {				chip->midcr &= ~MIDCR_TIE;				snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);				break;			}			snd_cs46xx_pokeBA0(chip, BA0_MIDWP, c);		}		spin_unlock(&chip->reg_lock);	}	/*	 *  EOI to the PCI part....reenables interrupts	 */	snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV);	return IRQ_HANDLED;}static snd_pcm_hardware_t snd_cs46xx_playback ={	.info =			(SNDRV_PCM_INFO_MMAP |				 SNDRV_PCM_INFO_INTERLEAVED | 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_RESUME),	.formats =		(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |				 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5500,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(256 * 1024),	.period_bytes_min =	CS46XX_MIN_PERIOD_SIZE,	.period_bytes_max =	CS46XX_MAX_PERIOD_SIZE,	.periods_min =		CS46XX_FRAGS,	.periods_max =		1024,	.fifo_size =		0,};static snd_pcm_hardware_t snd_cs46xx_capture ={

⌨️ 快捷键说明

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