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

📄 via82cxxx_audio.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
static int __init via_ac97_init (struct via_info *card){	int rc;	u16 tmp16;	DPRINTK ("ENTER\n");	assert (card != NULL);	memset (&card->ac97, 0, sizeof (card->ac97));	card->ac97.private_data = card;	card->ac97.codec_read = via_ac97_read_reg;	card->ac97.codec_write = via_ac97_write_reg;	card->ac97.codec_wait = via_ac97_codec_wait;	card->ac97.dev_mixer = register_sound_mixer (&via_mixer_fops, -1);	if (card->ac97.dev_mixer < 0) {		printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n");		DPRINTK ("EXIT, returning -EIO\n");		return -EIO;	}	rc = via_ac97_reset (card);	if (rc) {		printk (KERN_ERR PFX "unable to reset AC97 codec, aborting\n");		goto err_out;	}	if (ac97_probe_codec (&card->ac97) == 0) {		printk (KERN_ERR PFX "unable to probe AC97 codec, aborting\n");		rc = -EIO;		goto err_out;	}	/* enable variable rate */	tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);	via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); 	/* 	 * If we cannot enable VRA, we have a locked-rate codec. 	 * We try again to enable VRA before assuming so, however. 	 */ 	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); 		tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); 		if ((tmp16 & 1) == 0) { 			card->locked_rate = 1; 			printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); 		} 	}	DPRINTK ("EXIT, returning 0\n");	return 0;err_out:	unregister_sound_mixer (card->ac97.dev_mixer);	DPRINTK ("EXIT, returning %d\n", rc);	return rc;}static void via_ac97_cleanup (struct via_info *card){	DPRINTK ("ENTER\n");	assert (card != NULL);	assert (card->ac97.dev_mixer >= 0);	unregister_sound_mixer (card->ac97.dev_mixer);	DPRINTK ("EXIT\n");}/**************************************************************** * * Interrupt-related code * *//** *	via_intr_channel - handle an interrupt for a single channel *	@chan: handle interrupt for this channel * *	This is the "meat" of the interrupt handler, *	containing the actions taken each time an interrupt *	occurs.  All communication and coordination with *	userspace takes place here. * *	Locking: inside card->lock */static void via_intr_channel (struct via_channel *chan){	u8 status;	int n;	/* check pertinent bits of status register for action bits */	status = inb (chan->iobase) & (VIA_SGD_FLAG | VIA_SGD_EOL | VIA_SGD_STOPPED);	if (!status)		return;	/* acknowledge any flagged bits ASAP */	outb (status, chan->iobase);	if (!chan->sgtable) /* XXX: temporary solution */		return;	/* grab current h/w ptr value */	n = atomic_read (&chan->hw_ptr);	/* sanity check: make sure our h/w ptr doesn't have a weird value */	assert (n >= 0);	assert (n < chan->frag_number);	/* reset SGD data structure in memory to reflect a full buffer,	 * and advance the h/w ptr, wrapping around to zero if needed	 */	if (n == (chan->frag_number - 1)) {		chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_EOL);		atomic_set (&chan->hw_ptr, 0);	} else {		chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_FLAG);		atomic_inc (&chan->hw_ptr);	}	/* accounting crap for SNDCTL_DSP_GETxPTR */	chan->n_irqs++;	chan->bytes += chan->frag_size;	if (chan->bytes < 0) /* handle overflow of 31-bit value */		chan->bytes = chan->frag_size;	/* wake up anyone listening to see when interrupts occur */	if (waitqueue_active (&chan->wait))		wake_up_all (&chan->wait);	DPRINTK ("%s intr, status=0x%02X, hwptr=0x%lX, chan->hw_ptr=%d\n",		 chan->name, status, (long) inl (chan->iobase + 0x04),		 atomic_read (&chan->hw_ptr));	/* all following checks only occur when not in mmap(2) mode */	if (chan->is_mapped)		return;	/* If we are recording, then n_frags represents the number	 * of fragments waiting to be handled by userspace.	 * If we are playback, then n_frags represents the number	 * of fragments remaining to be filled by userspace.	 * We increment here.  If we reach max number of fragments,	 * this indicates an underrun/overrun.  For this case under OSS,	 * we stop the record/playback process.	 */	if (atomic_read (&chan->n_frags) < chan->frag_number)		atomic_inc (&chan->n_frags);	assert (atomic_read (&chan->n_frags) <= chan->frag_number);	if (atomic_read (&chan->n_frags) == chan->frag_number) {		chan->is_active = 0;		via_chan_stop (chan->iobase);	}	DPRINTK ("%s intr, channel n_frags == %d\n", chan->name,		 atomic_read (&chan->n_frags));}static void via_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct via_info *card = dev_id;	u32 status32;	/* to minimize interrupt sharing costs, we use the SGD status	 * shadow register to check the status of all inputs and	 * outputs with a single 32-bit bus read.  If no interrupt	 * conditions are flagged, we exit immediately	 */	status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);	if (!(status32 & VIA_INTR_MASK))        {#ifdef CONFIG_MIDI_VIA82CXXX	    	 if (card->midi_devc)                    	uart401intr(irq, card->midi_devc, regs);#endif		return;    	}	DPRINTK ("intr, status32 == 0x%08X\n", status32);	/* synchronize interrupt handling under SMP.  this spinlock	 * goes away completely on UP	 */	spin_lock (&card->lock);	if (status32 & VIA_INTR_OUT)		via_intr_channel (&card->ch_out);	if (status32 & VIA_INTR_IN)		via_intr_channel (&card->ch_in);	if (status32 & VIA_INTR_FM)		via_intr_channel (&card->ch_fm);	spin_unlock (&card->lock);}/** *	via_interrupt_init - Initialize interrupt handling *	@card: Private info for specified board * *	Obtain and reserve IRQ for using in handling audio events. *	Also, disable any IRQ-generating resources, to make sure *	we don't get interrupts before we want them. */static int via_interrupt_init (struct via_info *card){	u8 tmp8;	DPRINTK ("ENTER\n");	assert (card != NULL);	assert (card->pdev != NULL);	/* check for sane IRQ number. can this ever happen? */	if (card->pdev->irq < 2) {		printk (KERN_ERR PFX "insane IRQ %d, aborting\n",			card->pdev->irq);		DPRINTK ("EXIT, returning -EIO\n");		return -EIO;	}	/* make sure FM irq is not routed to us */	pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);	if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {		tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;		pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);	}	if (request_irq (card->pdev->irq, via_interrupt, SA_SHIRQ, VIA_MODULE_NAME, card)) {		printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",			card->pdev->irq);		DPRINTK ("EXIT, returning -EBUSY\n");		return -EBUSY;	}	DPRINTK ("EXIT, returning 0\n");	return 0;}/**************************************************************** * * OSS DSP device * */static struct file_operations via_dsp_fops = {	owner:		THIS_MODULE,	open:		via_dsp_open,	release:	via_dsp_release,	read:		via_dsp_read,	write:		via_dsp_write,	poll:		via_dsp_poll,	llseek: 	no_llseek,	ioctl:		via_dsp_ioctl,	mmap:		via_dsp_mmap,};static int __init via_dsp_init (struct via_info *card){	u8 tmp8;	DPRINTK ("ENTER\n");	assert (card != NULL);	/* turn off legacy features, if not already */	pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8);	if (tmp8 & (VIA_CR42_SB_ENABLE |  VIA_CR42_FM_ENABLE)) {		tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE);		pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8);	}	via_stop_everything (card);	card->dev_dsp = register_sound_dsp (&via_dsp_fops, -1);	if (card->dev_dsp < 0) {		DPRINTK ("EXIT, returning -ENODEV\n");		return -ENODEV;	}	DPRINTK ("EXIT, returning 0\n");	return 0;}static void via_dsp_cleanup (struct via_info *card){	DPRINTK ("ENTER\n");	assert (card != NULL);	assert (card->dev_dsp >= 0);	via_stop_everything (card);	unregister_sound_dsp (card->dev_dsp);	DPRINTK ("EXIT\n");}static struct page * via_mm_nopage (struct vm_area_struct * vma,				    unsigned long address, int write_access){	struct via_info *card = vma->vm_private_data;	struct via_channel *chan = &card->ch_out;	struct page *dmapage;	unsigned long pgoff;	int rd, wr;	DPRINTK ("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh, wr %d\n",		 vma->vm_start,		 address - vma->vm_start,		 (address - vma->vm_start) >> PAGE_SHIFT,		 address,		 write_access);        if (address > vma->vm_end) {		DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n");		return NOPAGE_SIGBUS; /* Disallow mremap */	}        if (!card) {		DPRINTK ("EXIT, returning NOPAGE_OOM\n");		return NOPAGE_OOM;	/* Nothing allocated */	}	pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT);	rd = card->ch_in.is_mapped;	wr = card->ch_out.is_mapped;#ifndef VIA_NDEBUG	{	unsigned long max_bufs = chan->frag_number;	if (rd && wr) max_bufs *= 2;	/* via_dsp_mmap() should ensure this */	assert (pgoff < max_bufs);	}#endif	/* if full-duplex (read+write) and we have two sets of bufs,	 * then the playback buffers come first, sez soundcard.c */	if (pgoff >= chan->page_number) {		pgoff -= chan->page_number;		chan = &card->ch_in;	} else if (!wr)		chan = &card->ch_in;	assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0);	dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr);	DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n",		 dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr);	get_page (dmapage);	return dmapage;}#ifndef VM_RESERVEDstatic int via_mm_swapout (struct page *page, struct file *filp){	return 0;}#endif /* VM_RESERVED */struct vm_operations_struct via_mm_ops = {	nopage:		via_mm_nopage,#ifndef VM_RESERVED	swapout:	via_mm_swapout,#endif};static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma){	struct via_info *card;	int nonblock = (file->f_flags & O_NONBLOCK);	int rc = -EINVAL, rd=0, wr=0;	unsigned long max_size, size, start, offset;	assert (file != NULL);	assert (vma != NULL);	card = file->private_data;	assert (card != NULL);	DPRINTK ("ENTER, start %lXh, size %ld, pgoff %ld\n",		 vma->vm_start,		 vma->vm_end - vma->vm_start,		 vma->vm_pgoff);	max_size = 0;	if (vma->vm_flags & VM_READ) {		rd = 1;		via_chan_set_buffering(card, &card->ch_in, -1);		via_chan_buffer_init (card, &card->ch_in);		max_size += card->ch_in.page_number << PAGE_SHIFT;	}	if (vma->vm_flags & VM_WRITE) {		wr = 1;		via_chan_set_buffering(card, &card->ch_out, -1);		via_chan_buffer_init (card, &card->ch_out);		max_size += card->ch_out.page_number << PAGE_SHIFT;	}	start = vma->vm_start;	offset = (vma->vm_pgoff << PAGE_SHIFT);	size = vma->vm_end - vma->vm_start;	/* some basic size/offset sanity checks */	if (size > max_size)		goto out;	if (offset > max_size - size)		goto out;	rc = via_syscall_down (card, nonblock);	if (rc) goto out;	vma->vm_ops = &via_mm_ops;	vma->vm_private_data = card;#ifdef VM_RESERVED	vma->vm_flags |= VM_RESERVED;#endif	if (rd)		card->ch_in.is_mapped = 1;	if (wr)		card->ch_out.is_mapped = 1;	up (&card->syscall_sem);	rc = 0;out:	DPRINTK ("EXIT, returning %d\n", rc);	return rc;}static ssize_t via_dsp_do_read (struct via_info *card,				char *userbuf, size_t count,				int nonblock){        DECLARE_WAITQUEUE(wait, current);	const char *orig_userbuf = userbuf;	struct via_channel *chan = &card->ch_in;	size_t size;	int n, tmp;	ssize_t ret = 0;	/* if SGD has not yet been started, start it */	via_chan_maybe_start (chan);handle_one_block:	/* just to be a nice neighbor */	/* Thomas Sailer:	 * But also to ourselves, release semaphore if we do so */	if (current->need_resched) {		up(&card->syscall_sem);		schedule ();		ret = via_syscall_down (card, nonblock);		if (ret)			goto out;	}	/* grab current channel software pointer.  In the case of	 * recording, this is pointing to the next buffer that	 * will receive data from the audio hardware.	 */	n = chan->sw_ptr;	/* n_frags represents the number of fragments waiting	 * to be copied to userland.  sleep until at least	 * one buffer has been read from the audio hardware.	 */	add_wait_queue(&chan->wait, &wait);	for (;;) {		__set_current_state(TASK_INTERRUPTIBLE);		tmp = atomic_read (&chan->n_frags);		assert (tmp >= 0);		assert (tmp <= chan->frag_number);		if (tmp)			break;		if (nonblock || !chan->is_active) {			ret = -EAGAIN;			break;		}		up(&card->syscall_sem);		DPRINTK ("Sleeping on block %d\n", n);		schedule();		ret = via_syscall_down (card, nonblock);		if (ret)			break;		if (signal_pending (current)) {			ret = -ERESTARTSYS;			break;

⌨️ 快捷键说明

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