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

📄 via82cxxx_audio.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	halted) when %SNDCTL_DSP_CHANNELS or SNDCTL_DSP_STEREO is given. * *	This function halts all audio operations for the given channel *	@chan, and then calls via_chan_pcm_fmt to set the audio hardware *	to enable or disable stereo. */static int via_chan_set_stereo (struct via_info *card,			        struct via_channel *chan, int val){	DPRINTK ("ENTER, channels = %d\n", val);	via_chan_clear (card, chan);	switch (val) {	/* mono */	case 1:		chan->pcm_fmt &= ~VIA_PCM_FMT_STEREO;		via_chan_pcm_fmt (chan, 0);		break;	/* stereo */	case 2:		chan->pcm_fmt |= VIA_PCM_FMT_STEREO;		via_chan_pcm_fmt (chan, 0);		break;	/* unknown */	default:		printk (KERN_WARNING PFX "unknown number of channels\n");		val = -EINVAL;		break;	}	DPRINTK ("EXIT, returning %d\n", val);	return val;}static int via_chan_set_buffering (struct via_info *card,                                struct via_channel *chan, int val){	int shift;        DPRINTK ("ENTER\n");	/* in both cases the buffer cannot be changed */	if (chan->is_active || chan->is_mapped) {		DPRINTK ("EXIT\n");		return -EINVAL;	}	/* called outside SETFRAGMENT */	/* set defaults or do nothing */	if (val < 0) {		if (chan->frag_size && chan->frag_number)			goto out;		DPRINTK ("\n");		chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate *				   ((chan->pcm_fmt & VIA_PCM_FMT_STEREO) ? 2 : 1) *				   ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;		shift = 0;		while (chan->frag_size) {			chan->frag_size >>= 1;			shift++;		}		chan->frag_size = 1 << shift;		chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME);		DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number);	} else {		chan->frag_size = 1 << (val & 0xFFFF);		chan->frag_number = (val >> 16) & 0xFFFF;		DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number);	}	/* quake3 wants frag_number to be a power of two */	shift = 0;	while (chan->frag_number) {		chan->frag_number >>= 1;		shift++;	}	chan->frag_number = 1 << shift;	if (chan->frag_size > VIA_MAX_FRAG_SIZE)		chan->frag_size = VIA_MAX_FRAG_SIZE;	else if (chan->frag_size < VIA_MIN_FRAG_SIZE)		chan->frag_size = VIA_MIN_FRAG_SIZE;	if (chan->frag_number < VIA_MIN_FRAG_NUMBER)                chan->frag_number = VIA_MIN_FRAG_NUMBER;	if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES)		chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size;out:	if (chan->is_record)		atomic_set (&chan->n_frags, 0);	else		atomic_set (&chan->n_frags, chan->frag_number);	DPRINTK ("EXIT\n");	return 0;}#ifdef VIA_CHAN_DUMP_BUFS/** *	via_chan_dump_bufs - Display DMA table contents *	@chan: Channel whose DMA table will be displayed * *	Debugging function which displays the contents of the *	scatter-gather DMA table for the given channel @chan. */static void via_chan_dump_bufs (struct via_channel *chan){	int i;	for (i = 0; i < chan->frag_number; i++) {		DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n",			 i, chan->sgtable[i].addr,			 chan->sgtable[i].count & 0x00FFFFFF,			 chan->sgtable[i].count & VIA_FLAG ? 1 : 0,			 chan->sgtable[i].count & VIA_EOL ? 1 : 0);	}	DPRINTK ("buf_in_use = %d, nextbuf = %d\n",		 atomic_read (&chan->buf_in_use),		 atomic_read (&chan->sw_ptr));}#endif /* VIA_CHAN_DUMP_BUFS *//** *	via_chan_flush_frag - Flush partially-full playback buffer to hardware *	@chan: Channel whose DMA table will be displayed * *	Flushes partially-full playback buffer to hardware. */static void via_chan_flush_frag (struct via_channel *chan){	DPRINTK ("ENTER\n");	assert (chan->slop_len > 0);	if (chan->sw_ptr == (chan->frag_number - 1))		chan->sw_ptr = 0;	else		chan->sw_ptr++;	chan->slop_len = 0;	assert (atomic_read (&chan->n_frags) > 0);	atomic_dec (&chan->n_frags);	DPRINTK ("EXIT\n");}/** *	via_chan_maybe_start - Initiate audio hardware DMA operation *	@chan: Channel whose DMA is to be started * *	Initiate DMA operation, if the DMA engine for the given *	channel @chan is not already active. */static inline void via_chan_maybe_start (struct via_channel *chan){	assert (chan->is_active == sg_active(chan->iobase));	if (!chan->is_active && chan->is_enabled) {		chan->is_active = 1;		sg_begin (chan);		DPRINTK ("starting channel %s\n", chan->name);	}}/**************************************************************** * * Interface to ac97-codec module * * *//** *	via_ac97_wait_idle - Wait until AC97 codec is not busy *	@card: Private info for specified board * *	Sleep until the AC97 codec is no longer busy. *	Returns the final value read from the SGD *	register being polled. */static u8 via_ac97_wait_idle (struct via_info *card){	u8 tmp8;	int counter = VIA_COUNTER_LIMIT;	DPRINTK ("ENTER/EXIT\n");	assert (card != NULL);	assert (card->pdev != NULL);	do {		udelay (15);		tmp8 = inb (card->baseaddr + 0x83);	} while ((tmp8 & VIA_CR83_BUSY) && (counter-- > 0));	if (tmp8 & VIA_CR83_BUSY)		printk (KERN_WARNING PFX "timeout waiting on AC97 codec\n");	return tmp8;}/** *	via_ac97_read_reg - Read AC97 standard register *	@codec: Pointer to generic AC97 codec info *	@reg: Index of AC97 register to be read * *	Read the value of a single AC97 codec register, *	as defined by the Intel AC97 specification. * *	Defines the standard AC97 read-register operation *	required by the kernel's ac97_codec interface. * *	Returns the 16-bit value stored in the specified *	register. */static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg){	unsigned long data;	struct via_info *card;	int counter;	DPRINTK ("ENTER\n");	assert (codec != NULL);	assert (codec->private_data != NULL);	card = codec->private_data;	/* Every time we write to register 80 we cause a transaction.	   The only safe way to clear the valid bit is to write it at	   the same time as the command */	data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID;	outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);	udelay (20);	for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {		udelay (1);		if ((((data = inl(card->baseaddr + VIA_BASE0_AC97_CTRL)) &		      (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID))			goto out;	}	printk (KERN_WARNING PFX "timeout while reading AC97 codec (0x%lX)\n", data);	goto err_out;out:	/* Once the valid bit has become set, we must wait a complete AC97	   frame before the data has settled. */	udelay(25);	data = (unsigned long) inl (card->baseaddr + VIA_BASE0_AC97_CTRL);	outb (0x02, card->baseaddr + 0x83);	if (((data & 0x007F0000) >> 16) == reg) {		DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n",			 data, data & 0x0000FFFF);		return data & 0x0000FFFF;	}	printk (KERN_WARNING "via82cxxx_audio: not our index: reg=0x%x, newreg=0x%lx\n",		reg, ((data & 0x007F0000) >> 16));err_out:	DPRINTK ("EXIT, returning 0\n");	return 0;}/** *	via_ac97_write_reg - Write AC97 standard register *	@codec: Pointer to generic AC97 codec info *	@reg: Index of AC97 register to be written *	@value: Value to be written to AC97 register * *	Write the value of a single AC97 codec register, *	as defined by the Intel AC97 specification. * *	Defines the standard AC97 write-register operation *	required by the kernel's ac97_codec interface. */static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value){	u32 data;	struct via_info *card;	int counter;	DPRINTK ("ENTER\n");	assert (codec != NULL);	assert (codec->private_data != NULL);	card = codec->private_data;	data = (reg << 16) + value;	outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL);	udelay (10);	for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) {		if ((inb (card->baseaddr + 0x83) & VIA_CR83_BUSY) == 0)			goto out;		udelay (15);	}	printk (KERN_WARNING PFX "timeout after AC97 codec write (0x%X, 0x%X)\n", reg, value);out:	DPRINTK ("EXIT\n");}static int via_mixer_open (struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	struct via_info *card;	struct pci_dev *pdev;	struct pci_driver *drvr;	DPRINTK ("ENTER\n");	pci_for_each_dev(pdev) {		drvr = pci_dev_driver (pdev);		if (drvr == &via_driver) {			assert (pci_get_drvdata (pdev) != NULL);			card = pci_get_drvdata (pdev);			if (card->ac97.dev_mixer == minor)				goto match;		}	}	DPRINTK ("EXIT, returning -ENODEV\n");	return -ENODEV;match:	file->private_data = &card->ac97;	DPRINTK ("EXIT, returning 0\n");	return 0;}static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd,			    unsigned long arg){	struct ac97_codec *codec = file->private_data;	struct via_info *card;	int nonblock = (file->f_flags & O_NONBLOCK);	int rc;	DPRINTK ("ENTER\n");	assert (codec != NULL);	card = codec->private_data;	assert (card != NULL);	rc = via_syscall_down (card, nonblock);	if (rc) goto out;	rc = codec->mixer_ioctl(codec, cmd, arg);	up (&card->syscall_sem);out:	DPRINTK ("EXIT, returning %d\n", rc);	return rc;}static struct file_operations via_mixer_fops = {	owner:		THIS_MODULE,	open:		via_mixer_open,	llseek:		no_llseek,	ioctl:		via_mixer_ioctl,};static int __init via_ac97_reset (struct via_info *card){	struct pci_dev *pdev = card->pdev;	u8 tmp8;	u16 tmp16;	DPRINTK ("ENTER\n");	assert (pdev != NULL);#ifndef NDEBUG	{		u8 r40,r41,r42,r43,r44,r48;		pci_read_config_byte (card->pdev, 0x40, &r40);		pci_read_config_byte (card->pdev, 0x41, &r41);		pci_read_config_byte (card->pdev, 0x42, &r42);		pci_read_config_byte (card->pdev, 0x43, &r43);		pci_read_config_byte (card->pdev, 0x44, &r44);		pci_read_config_byte (card->pdev, 0x48, &r48);		DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n",			r40,r41,r42,r43,r44,r48);		spin_lock_irq (&card->lock);		DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",			 inb (card->baseaddr + 0x00),			 inb (card->baseaddr + 0x01),			 inb (card->baseaddr + 0x02),			 inl (card->baseaddr + 0x04),			 inl (card->baseaddr + 0x0C),			 inl (card->baseaddr + 0x80),			 inl (card->baseaddr + 0x84));		spin_unlock_irq (&card->lock);	}#endif        /*         * Reset AC97 controller: enable, disable, enable,         * pausing after each command for good luck.  Only	 * do this if the codec is not ready, because it causes	 * loud pops and such due to such a hard codec reset.         */	pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8);	if ((tmp8 & VIA_CR40_AC97_READY) == 0) {        	pci_write_config_byte (pdev, VIA_ACLINK_CTRL,				       VIA_CR41_AC97_ENABLE |                		       VIA_CR41_AC97_RESET |				       VIA_CR41_AC97_WAKEUP);        	udelay (100);        	pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0);        	udelay (100);        	pci_write_config_byte (pdev, VIA_ACLINK_CTRL,				       VIA_CR41_AC97_ENABLE |				       VIA_CR41_PCM_ENABLE |                		       VIA_CR41_VRA | VIA_CR41_AC97_RESET);        	udelay (100);	}	/* Make sure VRA is enabled, in case we didn't do a	 * complete codec reset, above	 */	pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8);	if (((tmp8 & VIA_CR41_VRA) == 0) ||	    ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) ||	    ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) ||	    ((tmp8 & VIA_CR41_AC97_RESET) == 0)) {        	pci_write_config_byte (pdev, VIA_ACLINK_CTRL,				       VIA_CR41_AC97_ENABLE |				       VIA_CR41_PCM_ENABLE |                		       VIA_CR41_VRA | VIA_CR41_AC97_RESET);        	udelay (100);	}#if 0 /* this breaks on K7M */	/* disable legacy stuff */	pci_write_config_byte (pdev, 0x42, 0x00);	udelay(10);#endif	/* route FM trap to IRQ, disable FM trap */	pci_write_config_byte (pdev, 0x48, 0x05);	udelay(10);	/* disable all codec GPI interrupts */	outl (0, pci_resource_start (pdev, 0) + 0x8C);	/* WARNING: this line is magic.  Remove this	 * and things break. */	/* enable variable rate */ 	tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); 	if ((tmp16 & 1) == 0) 		via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);	DPRINTK ("EXIT, returning 0\n");	return 0;}static void via_ac97_codec_wait (struct ac97_codec *codec){	assert (codec->private_data != NULL);	via_ac97_wait_idle (codec->private_data);}

⌨️ 快捷键说明

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