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

📄 via82cxxx_audio.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* the hardware might return a value different than what we	 * passed to it, so read the rate value back from hardware	 * to see what we came up with	 */	chan->rate = via_ac97_read_reg (ac97, rate_reg);	DPRINTK ("EXIT, returning rate %d Hz\n", chan->rate);	return chan->rate;}/**************************************************************** * * Channel-specific operations * * *//** *	via_chan_init_defaults - Initialize a struct via_channel *	@card: Private audio chip info *	@chan: Channel to be initialized * *	Zero @chan, and then set all static defaults for the structure. */static void via_chan_init_defaults (struct via_info *card, struct via_channel *chan){	memset (chan, 0, sizeof (*chan));	if (chan == &card->ch_out) {		chan->name = "PCM-OUT";		chan->iobase = card->baseaddr + VIA_BASE0_PCM_OUT_CHAN;	} else if (chan == &card->ch_in) {		chan->name = "PCM-IN";		chan->iobase = card->baseaddr + VIA_BASE0_PCM_IN_CHAN;		chan->is_record = 1;	} else if (chan == &card->ch_fm) {		chan->name = "PCM-OUT-FM";		chan->iobase = card->baseaddr + VIA_BASE0_FM_OUT_CHAN;	} else {		BUG();	}	init_waitqueue_head (&chan->wait);	chan->pcm_fmt = VIA_PCM_FMT_MASK;	chan->is_enabled = 1;	if (chan->is_record)		atomic_set (&chan->n_bufs, 0);	else		atomic_set (&chan->n_bufs, VIA_DMA_BUFFERS);	atomic_set (&chan->hw_ptr, 0);}/** *	via_chan_init - Initialize PCM channel *	@card: Private audio chip info *	@chan: Channel to be initialized * *	Performs all the preparations necessary to begin *	using a PCM channel. * *	Currently the preparations include allocating the *	scatter-gather DMA table and buffers, setting the *	PCM channel to a known state, and passing the *	address of the DMA table to the hardware. * *	Note that special care is taken when passing the *	DMA table address to hardware, because it was found *	during driver development that the hardware did not *	always "take" the address. */static int via_chan_init (struct via_info *card, struct via_channel *chan){	int i;	DPRINTK ("ENTER\n");	/* bzero channel structure, and init members to defaults */	via_chan_init_defaults (card, chan);	/* alloc DMA-able memory for scatter-gather table */	chan->sgtable = pci_alloc_consistent (card->pdev,		(sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS),		&chan->sgt_handle);	if (!chan->sgtable) {		printk (KERN_ERR PFX "DMA table alloc fail, aborting\n");		DPRINTK ("EXIT\n");		return -ENOMEM;	}	memset ((void*)chan->sgtable, 0,		(sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS));	/* alloc DMA-able memory for scatter-gather buffers */	for (i = 0; i < VIA_DMA_BUFFERS; i++) {		chan->sgbuf[i].cpuaddr =			pci_alloc_consistent (card->pdev, VIA_DMA_BUF_SIZE,					      &chan->sgbuf[i].handle);		if (!chan->sgbuf[i].cpuaddr)			goto err_out_nomem;		if (i < (VIA_DMA_BUFFERS - 1))			chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG);		else			chan->sgtable[i].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL);		chan->sgtable[i].addr = cpu_to_le32 (chan->sgbuf[i].handle);#ifndef VIA_NDEBUG		memset (chan->sgbuf[i].cpuaddr, 0xBC, VIA_DMA_BUF_SIZE);#endif#if 1		DPRINTK ("dmabuf #%d (h=%lx, 32(h)=%lx, v2p=%lx, a=%p)\n",			 i, (long)chan->sgbuf[i].handle,			 (long)chan->sgtable[i].addr,			 virt_to_phys(chan->sgbuf[i].cpuaddr),			 chan->sgbuf[i].cpuaddr);#endif		assert ((VIA_DMA_BUF_SIZE % PAGE_SIZE) == 0);	}	/* stop any existing channel output */	via_chan_clear (chan);	via_chan_status_clear (chan->iobase);	via_chan_pcm_fmt (chan, 1);	/* set location of DMA-able scatter-gather info table */	DPRINTK("outl (0x%X, 0x%04lX)\n",		cpu_to_le32 (chan->sgt_handle),		chan->iobase + VIA_PCM_TABLE_ADDR);	via_ac97_wait_idle (card);	outl (cpu_to_le32 (chan->sgt_handle),	      chan->iobase + VIA_PCM_TABLE_ADDR);	udelay (20);	via_ac97_wait_idle (card);	DPRINTK("inl (0x%lX) = %x\n",		chan->iobase + VIA_PCM_TABLE_ADDR,		inl(chan->iobase + VIA_PCM_TABLE_ADDR));	DPRINTK ("EXIT\n");	return 0;err_out_nomem:	printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n");	via_chan_free (card, chan);	DPRINTK ("EXIT\n");	return -ENOMEM;}/** *	via_chan_free - Release a PCM channel *	@card: Private audio chip info *	@chan: Channel to be released * *	Performs all the functions necessary to clean up *	an initialized channel. * *	Currently these functions include disabled any *	active DMA operations, setting the PCM channel *	back to a known state, and releasing any allocated *	sound buffers. */static void via_chan_free (struct via_info *card, struct via_channel *chan){	int i;	DPRINTK ("ENTER\n");	synchronize_irq();	spin_lock_irq (&card->lock);	/* stop any existing channel output */	via_chan_stop (chan->iobase);	via_chan_status_clear (chan->iobase);	via_chan_pcm_fmt (chan, 1);	spin_unlock_irq (&card->lock);	/* zero location of DMA-able scatter-gather info table */	via_ac97_wait_idle(card);	outl (0, chan->iobase + VIA_PCM_TABLE_ADDR);	for (i = 0; i < VIA_DMA_BUFFERS; i++)		if (chan->sgbuf[i].cpuaddr) {			assert ((VIA_DMA_BUF_SIZE % PAGE_SIZE) == 0);			pci_free_consistent (card->pdev, VIA_DMA_BUF_SIZE,					     chan->sgbuf[i].cpuaddr,					     chan->sgbuf[i].handle);			chan->sgbuf[i].cpuaddr = NULL;			chan->sgbuf[i].handle = 0;		}	if (chan->sgtable) {		pci_free_consistent (card->pdev,			(sizeof (struct via_sgd_table) * VIA_DMA_BUFFERS),			(void*)chan->sgtable, chan->sgt_handle);		chan->sgtable = NULL;	}	DPRINTK ("EXIT\n");}/** *	via_chan_pcm_fmt - Update PCM channel settings *	@chan: Channel to be updated *	@reset: Boolean.  If non-zero, channel will be reset *		to 8-bit mono mode. * *	Stores the settings of the current PCM format, *	8-bit or 16-bit, and mono/stereo, into the *	hardware settings for the specified channel. *	If @reset is non-zero, the channel is reset *	to 8-bit mono mode.  Otherwise, the channel *	is set to the values stored in the channel *	information struct @chan. */static void via_chan_pcm_fmt (struct via_channel *chan, int reset){	DPRINTK ("ENTER, pcm_fmt=0x%02X, reset=%s\n",		 chan->pcm_fmt, reset ? "yes" : "no");	assert (chan != NULL);	if (reset)		/* reset to 8-bit mono mode */		chan->pcm_fmt = 0;	/* enable interrupts on FLAG and EOL */	chan->pcm_fmt |= VIA_CHAN_TYPE_MASK;	/* if we are recording, enable recording fifo bit */	if (chan->is_record)		chan->pcm_fmt |= VIA_PCM_REC_FIFO;	/* set interrupt select bits where applicable (PCM & FM out channels) */	if (!chan->is_record)		chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;	outb (chan->pcm_fmt, chan->iobase + 2);	DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",		 chan->pcm_fmt,		 inb (chan->iobase + 2));}/** *	via_chan_clear - Stop DMA channel operation, and reset pointers *	@chan: Channel to be cleared * *	Call via_chan_stop to halt DMA operations, and then resets *	all software pointers which track DMA operation. */static void via_chan_clear (struct via_channel *chan){	DPRINTK ("ENTER\n");	via_chan_stop (chan->iobase);	chan->is_active = 0;	chan->is_mapped = 0;	chan->is_enabled = 1;	chan->slop_len = 0;	chan->sw_ptr = 0;	chan->n_irqs = 0;	atomic_set (&chan->hw_ptr, 0);	if (chan->is_record)		atomic_set (&chan->n_bufs, 0);	else		atomic_set (&chan->n_bufs, VIA_DMA_BUFFERS);	DPRINTK ("EXIT\n");}/** *	via_chan_set_speed - Set PCM sample rate for given channel *	@card: Private info for specified board *	@chan: Channel whose sample rate will be adjusted *	@val: New sample rate, in Khz * *	Helper function for the %SNDCTL_DSP_SPEED ioctl.  OSS semantics *	demand that all audio operations halt (if they are not already *	halted) when the %SNDCTL_DSP_SPEED is given. * *	This function halts all audio operations for the given channel *	@chan, and then calls via_set_rate to set the audio hardware *	to the new rate. */static int via_chan_set_speed (struct via_info *card,			       struct via_channel *chan, int val){	DPRINTK ("ENTER, requested rate = %d\n", val);	via_chan_clear (chan);	val = via_set_rate (&card->ac97, chan, val);	DPRINTK ("EXIT, returning %d\n", val);	return val;}/** *	via_chan_set_fmt - Set PCM sample size for given channel *	@card: Private info for specified board *	@chan: Channel whose sample size will be adjusted *	@val: New sample size, use the %AFMT_xxx constants * *	Helper function for the %SNDCTL_DSP_SETFMT ioctl.  OSS semantics *	demand that all audio operations halt (if they are not already *	halted) when the %SNDCTL_DSP_SETFMT 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 the new sample size, either 8-bit or 16-bit. */static int via_chan_set_fmt (struct via_info *card,			     struct via_channel *chan, int val){	DPRINTK ("ENTER, val=%s\n",		 val == AFMT_U8 ? "AFMT_U8" :	 	 val == AFMT_S16_LE ? "AFMT_S16_LE" :		 "unknown");	via_chan_clear (chan);	assert (val != AFMT_QUERY); /* this case is handled elsewhere */	switch (val) {	case AFMT_S16_LE:		if ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) == 0) {			chan->pcm_fmt |= VIA_PCM_FMT_16BIT;			via_chan_pcm_fmt (chan, 0);		}		break;	case AFMT_U8:		if (chan->pcm_fmt & VIA_PCM_FMT_16BIT) {			chan->pcm_fmt &= ~VIA_PCM_FMT_16BIT;			via_chan_pcm_fmt (chan, 0);		}		break;	default:		DPRINTK ("unknown AFMT: 0x%X\n", val);		val = AFMT_S16_LE;	}	DPRINTK ("EXIT\n");	return val;}/** *	via_chan_set_stereo - Enable or disable stereo for a DMA channel *	@card: Private info for specified board *	@chan: Channel whose stereo setting will be adjusted *	@val: New sample size, use the %AFMT_xxx constants * *	Helper function for the %SNDCTL_DSP_CHANNELS and %SNDCTL_DSP_STEREO ioctls.  OSS semantics *	demand that all audio operations halt (if they are not already *	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 (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;}#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 < VIA_DMA_BUFFERS; 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 == (VIA_DMA_BUFFERS - 1))		chan->sw_ptr = 0;	else		chan->sw_ptr++;	chan->slop_len = 0;	assert (atomic_read (&chan->n_bufs) > 0);	atomic_dec (&chan->n_bufs);	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){	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);

⌨️ 快捷键说明

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