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

📄 i810_audio.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
 *  S/PDIF, we turn off the analog output. This may not be *  the right thing to do. * *  Assumptions: *     The DSP sample rate must already be set to a supported *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort. */static void i810_set_spdif_output(struct i810_state *state, int slots, int rate){	int	vol;	int	aud_reg;	struct ac97_codec *codec = state->card->ac97_codec[0];	if(!(state->card->ac97_features & 4)) {#ifdef DEBUG		printk(KERN_WARNING "i810_audio: S/PDIF transmitter not available.\n");#endif		state->card->ac97_status &= ~SPDIF_ON;	} else {		if ( slots == -1 ) { /* Turn off S/PDIF */			aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);			i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));			/* If the volume wasn't muted before we turned on S/PDIF, unmute it */			if ( !(state->card->ac97_status & VOL_MUTED) ) {				aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);				i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));			}			state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);			return;		}		vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);		state->card->ac97_status = vol & VOL_MUTED;		/* Set S/PDIF transmitter sample rate */		aud_reg = i810_ac97_get(codec, AC97_SPDIF_CONTROL);		switch ( rate ) {			case 32000:				aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K; 				break;			 case 44100:			 	aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K; 				break;			case 48000:			 	aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K; 				break;			default:#ifdef DEBUG				printk(KERN_WARNING "i810_audio: %d sample rate not supported by S/PDIF.\n", rate);#endif				/* turn off S/PDIF */				aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);				i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));				state->card->ac97_status &= ~SPDIF_ON;				return;		}		i810_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);				aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);		aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_VRA | AC97_EA_SPDIF;		i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);		state->card->ac97_status |= SPDIF_ON;		/* Check to make sure the configuration is valid */		aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);		if ( ! (aud_reg & 0x0400) ) {#ifdef DEBUG			printk(KERN_WARNING "i810_audio: S/PDIF transmitter configuration not valid (0x%04x).\n", aud_reg);#endif			/* turn off S/PDIF */			i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));			state->card->ac97_status &= ~SPDIF_ON;			return;		}		/* Mute the analog output */		/* Should this only mute the PCM volume??? */		i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED));	}}/* i810_set_dac_channels * *  Configure the codec's multi-channel DACs * *  The logic is backwards. Setting the bit to 1 turns off the DAC.  * *  What about the ICH? We currently configure it using the *  SNDCTL_DSP_CHANNELS ioctl.  If we're turnning on the DAC,  *  does that imply that we want the ICH set to support *  these channels? *   *  TODO: *    vailidate that the codec really supports these DACs *    before turning them on.  */static void i810_set_dac_channels(struct i810_state *state, int channel){	int	aud_reg;	struct ac97_codec *codec = state->card->ac97_codec[0];	aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);	aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;	state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);	switch ( channel ) {		case 2: /* always enabled */			break;		case 4:			aud_reg &= ~AC97_EA_PRJ;			state->card->ac97_status |= SURR_ON;			break;		case 6:			aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);			state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;			break;		default:			break;	}	i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);}/* set playback sample rate */static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate){		struct dmabuf *dmabuf = &state->dmabuf;	u32 new_rate;	struct ac97_codec *codec=state->card->ac97_codec[0];		if(!(state->card->ac97_features&0x0001))	{		dmabuf->rate = clocking;#ifdef DEBUG		printk("Asked for %d Hz, but ac97_features says we only do %dHz.  Sorry!\n",		       rate,clocking);#endif		       		return clocking;	}				if (rate > 48000)		rate = 48000;	if (rate < 8000)		rate = 8000;	dmabuf->rate = rate;			/*	 *	Adjust for misclocked crap	 */	rate = ( rate * clocking)/48000;	if(strict_clocking && rate < 8000) {		rate = 8000;		dmabuf->rate = (rate * 48000)/clocking;	}        new_rate=ac97_set_dac_rate(codec, rate);	if(new_rate != rate) {		dmabuf->rate = (new_rate * 48000)/clocking;	}#ifdef DEBUG	printk("i810_audio: called i810_set_dac_rate : asked for %d, got %d\n", rate, dmabuf->rate);#endif	rate = new_rate;	return dmabuf->rate;}/* set recording sample rate */static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate){	struct dmabuf *dmabuf = &state->dmabuf;	u32 new_rate;	struct ac97_codec *codec=state->card->ac97_codec[0];		if(!(state->card->ac97_features&0x0001))	{		dmabuf->rate = clocking;		return clocking;	}				if (rate > 48000)		rate = 48000;	if (rate < 8000)		rate = 8000;	dmabuf->rate = rate;	/*	 *	Adjust for misclocked crap	 */	 	rate = ( rate * clocking)/48000;	if(strict_clocking && rate < 8000) {		rate = 8000;		dmabuf->rate = (rate * 48000)/clocking;	}	new_rate = ac97_set_adc_rate(codec, rate);		if(new_rate != rate) {		dmabuf->rate = (new_rate * 48000)/clocking;		rate = new_rate;	}#ifdef DEBUG	printk("i810_audio: called i810_set_adc_rate : rate = %d/%d\n", dmabuf->rate, rate);#endif	return dmabuf->rate;}/* get current playback/recording dma buffer pointer (byte offset from LBA),   called with spinlock held! */   static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned int civ, offset, port, port_picb, bytes = 2;		if (!dmabuf->enable)		return 0;	if (rec)		port = state->card->iobase + dmabuf->read_channel->port;	else		port = state->card->iobase + dmabuf->write_channel->port;	if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) {		port_picb = port + OFF_SR;		bytes = 1;	} else		port_picb = port + OFF_PICB;	do {		civ = inb(port+OFF_CIV) & 31;		offset = inw(port_picb);		/* Must have a delay here! */ 		if(offset == 0)			udelay(1);		/* Reread both registers and make sure that that total		 * offset from the first reading to the second is 0.		 * There is an issue with SiS hardware where it will count		 * picb down to 0, then update civ to the next value,		 * then set the new picb to fragsize bytes.  We can catch		 * it between the civ update and the picb update, making		 * it look as though we are 1 fragsize ahead of where we		 * are.  The next to we get the address though, it will		 * be back in the right place, and we will suddenly think		 * we just went forward dmasize - fragsize bytes, causing		 * totally stupid *huge* dma overrun messages.  We are		 * assuming that the 1us delay is more than long enough		 * that we won't have to worry about the chip still being		 * out of sync with reality ;-)		 */	} while (civ != (inb(port+OFF_CIV) & 31) || offset != inw(port_picb));		 	return (((civ + 1) * dmabuf->fragsize - (bytes * offset))		% dmabuf->dmasize);}/* Stop recording (lock held) */static inline void __stop_adc(struct i810_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	struct i810_card *card = state->card;	dmabuf->enable &= ~ADC_RUNNING;	outb(0, card->iobase + PI_CR);	// wait for the card to acknowledge shutdown	while( inb(card->iobase + PI_CR) != 0 ) ;	// now clear any latent interrupt bits (like the halt bit)	if(card->pci_id == PCI_DEVICE_ID_SI_7012)		outb( inb(card->iobase + PI_PICB), card->iobase + PI_PICB );	else		outb( inb(card->iobase + PI_SR), card->iobase + PI_SR );	outl( inl(card->iobase + GLOB_STA) & INT_PI, card->iobase + GLOB_STA);}static void stop_adc(struct i810_state *state){	struct i810_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	__stop_adc(state);	spin_unlock_irqrestore(&card->lock, flags);}static inline void __start_adc(struct i810_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&	    (dmabuf->trigger & PCM_ENABLE_INPUT)) {		dmabuf->enable |= ADC_RUNNING;		outb((1<<4) | (1<<2) | 1, state->card->iobase + PI_CR);	}}static void start_adc(struct i810_state *state){	struct i810_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	__start_adc(state);	spin_unlock_irqrestore(&card->lock, flags);}/* stop playback (lock held) */static inline void __stop_dac(struct i810_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	struct i810_card *card = state->card;	dmabuf->enable &= ~DAC_RUNNING;	outb(0, card->iobase + PO_CR);	// wait for the card to acknowledge shutdown	while( inb(card->iobase + PO_CR) != 0 ) ;	// now clear any latent interrupt bits (like the halt bit)	if(card->pci_id == PCI_DEVICE_ID_SI_7012)		outb( inb(card->iobase + PO_PICB), card->iobase + PO_PICB );	else		outb( inb(card->iobase + PO_SR), card->iobase + PO_SR );	outl( inl(card->iobase + GLOB_STA) & INT_PO, card->iobase + GLOB_STA);}static void stop_dac(struct i810_state *state){	struct i810_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	__stop_dac(state);	spin_unlock_irqrestore(&card->lock, flags);}	static inline void __start_dac(struct i810_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {		dmabuf->enable |= DAC_RUNNING;		outb((1<<4) | (1<<2) | 1, state->card->iobase + PO_CR);	}}static void start_dac(struct i810_state *state){	struct i810_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	__start_dac(state);	spin_unlock_irqrestore(&card->lock, flags);}#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)#define DMABUF_MINORDER 1/* allocate DMA buffer, playback and recording buffer should be allocated seperately */static int alloc_dmabuf(struct i810_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	void *rawbuf= NULL;	int order, size;	struct page *page, *pend;	/* If we don't have any oss frag params, then use our default ones */	if(dmabuf->ossmaxfrags == 0)		dmabuf->ossmaxfrags = 4;	if(dmabuf->ossfragsize == 0)		dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags;	size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;	if(dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)		return 0;	/* alloc enough to satisfy the oss params */	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {		if ( (PAGE_SIZE<<order) > size )			continue;		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,						   PAGE_SIZE << order,						   &dmabuf->dma_handle)))			break;	}	if (!rawbuf)		return -ENOMEM;#ifdef DEBUG	printk("i810_audio: allocated %ld (order = %d) bytes at %p\n",	       PAGE_SIZE << order, order, rawbuf);#endif	dmabuf->ready  = dmabuf->mapped = 0;	dmabuf->rawbuf = rawbuf;	dmabuf->buforder = order;		/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */	pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);	for (page = virt_to_page(rawbuf); page <= pend; page++)		mem_map_reserve(page);	return 0;}/* free DMA buffer */static void dealloc_dmabuf(struct i810_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	struct page *page, *pend;	if (dmabuf->rawbuf) {		/* undo marking the pages as reserved */		pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);		for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)			mem_map_unreserve(page);		pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder,				    dmabuf->rawbuf, dmabuf->dma_handle);	}	dmabuf->rawbuf = NULL;	dmabuf->mapped = dmabuf->ready = 0;}static int prog_dmabuf(struct i810_state *state, unsigned rec){	struct dmabuf *dmabuf = &state->dmabuf;	struct i810_channel *c;	struct sg_item *sg;	unsigned long flags;	int ret;	unsigned fragint;	int i;	spin_lock_irqsave(&state->card->lock, flags);	if(dmabuf->enable & DAC_RUNNING)		__stop_dac(state);	if(dmabuf->enable & ADC_RUNNING)		__stop_adc(state);	dmabuf->total_bytes = 0;	dmabuf->count = dmabuf->error = 0;	dmabuf->swptr = dmabuf->hwptr = 0;	spin_unlock_irqrestore(&state->card->lock, flags);	/* allocate DMA buffer, let alloc_dmabuf determine if we are already	 * allocated well enough or if we should replace the current buffer

⌨️ 快捷键说明

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