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

📄 via82cxxx_audio.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		printk (KERN_ERR PFX "insane IRQ %d, aborting\n",			card->pdev->irq);		DPRINTK ("EXIT, returning -EIO\n");		return -EIO;	}	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;	}	/* we don't want interrupts until we're opened */	via_interrupt_disable (card);	DPRINTK ("EXIT, returning 0\n");	return 0;}/** *	via_interrupt_cleanup - Shutdown driver interrupt handling *	@card: Private info for specified board * *	Disable any potential interrupt sources in the Via audio *	hardware, and then release (un-reserve) the IRQ line *	in the kernel core. */static void via_interrupt_cleanup (struct via_info *card){	DPRINTK ("ENTER\n");	assert (card != NULL);	assert (card->pdev != NULL);	via_interrupt_disable (card);	free_irq (card->pdev->irq, card);	DPRINTK ("EXIT\n");}/**************************************************************** * * 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: 	via_llseek,	ioctl:		via_dsp_ioctl,#ifdef VIA_SUPPORT_MMAP	mmap:		via_dsp_mmap,#endif};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_MIDI_ENABLE |		    VIA_CR42_FM_ENABLE)) {		tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_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");}#ifdef VIA_SUPPORT_MMAPstatic 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);	assert (VIA_DMA_BUF_SIZE == PAGE_SIZE);        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 = VIA_DMA_BUFFERS;	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 >= VIA_DMA_BUFFERS) {		pgoff -= VIA_DMA_BUFFERS;		chan = &card->ch_in;	} else if (!wr)		chan = &card->ch_in;	assert ((((unsigned long)chan->sgbuf[pgoff].cpuaddr) % PAGE_SIZE) == 0);	dmapage = virt_to_page (chan->sgbuf[pgoff].cpuaddr);	DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n",		 dmapage, (unsigned long) chan->sgbuf[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);	assert (VIA_DMA_BUF_SIZE == PAGE_SIZE);	max_size = 0;	if (file->f_mode & FMODE_READ) {		rd = 1;		max_size += (VIA_DMA_BUFFERS * VIA_DMA_BUF_SIZE);	}	if (file->f_mode & FMODE_WRITE) {		wr = 1;		max_size += (VIA_DMA_BUFFERS * VIA_DMA_BUF_SIZE);	}	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;}#endif /* VIA_SUPPORT_MMAP */static ssize_t via_dsp_do_read (struct via_info *card,				char *userbuf, size_t count,				int nonblock){	const char *orig_userbuf = userbuf;	struct via_channel *chan = &card->ch_in;	size_t size;	int n, tmp;	/* if SGD has not yet been started, start it */	via_chan_maybe_start (chan);handle_one_block:	/* just to be a nice neighbor */	if (current->need_resched)		schedule ();	/* 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_bufs represents the number of buffers waiting	 * to be copied to userland.  sleep until at least	 * one buffer has been read from the audio hardware.	 */	tmp = atomic_read (&chan->n_bufs);	assert (tmp >= 0);	assert (tmp <= VIA_DMA_BUFFERS);	while (tmp == 0) {		if (nonblock || !chan->is_active)			return -EAGAIN;		DPRINTK ("Sleeping on block %d\n", n);		interruptible_sleep_on (&chan->wait);		if (signal_pending (current))			return -ERESTARTSYS;		tmp = atomic_read (&chan->n_bufs);	}	/* Now that we have a buffer we can read from, send	 * as much as sample data possible to userspace.	 */	while ((count > 0) && (chan->slop_len < VIA_DMA_BUF_SIZE)) {		size_t slop_left = VIA_DMA_BUF_SIZE - chan->slop_len;		size = (count < slop_left) ? count : slop_left;		if (copy_to_user (userbuf,				  chan->sgbuf[n].cpuaddr + chan->slop_len,				  size))			return -EFAULT;		count -= size;		chan->slop_len += size;		userbuf += size;	}	/* If we didn't copy the buffer completely to userspace,	 * stop now.	 */	if (chan->slop_len < VIA_DMA_BUF_SIZE)		goto out;	/*	 * If we get to this point, we copied one buffer completely	 * to userspace, give the buffer back to the hardware.	 */	/* advance channel software pointer to point to	 * the next buffer from which we will copy	 */	if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1))		chan->sw_ptr = 0;	else		chan->sw_ptr++;	/* mark one less buffer waiting to be processed */	assert (atomic_read (&chan->n_bufs) > 0);	atomic_dec (&chan->n_bufs);	/* we are at a block boundary, there is no fragment data */	chan->slop_len = 0;	DPRINTK("Flushed block %u, sw_ptr now %u, n_bufs now %d\n",		n, chan->sw_ptr, atomic_read (&chan->n_bufs));	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));	if (count > 0)		goto handle_one_block;out:	return userbuf - orig_userbuf;}static ssize_t via_dsp_read(struct file *file, char *buffer, size_t count, loff_t *ppos){	struct via_info *card;	int nonblock = (file->f_flags & O_NONBLOCK);	int rc;	DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",		 file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);	assert (file != NULL);	assert (buffer != NULL);	card = file->private_data;	assert (card != NULL);	if (ppos != &file->f_pos) {		DPRINTK ("EXIT, returning -ESPIPE\n");		return -ESPIPE;	}	rc = via_syscall_down (card, nonblock);	if (rc) goto out;	if (card->ch_in.is_mapped) {		rc = -ENXIO;		goto out_up;	}	rc = via_dsp_do_read (card, buffer, count, nonblock);out_up:	up (&card->syscall_sem);out:	DPRINTK("EXIT, returning %ld\n",(long) rc);	return rc;}static ssize_t via_dsp_do_write (struct via_info *card,				 const char *userbuf, size_t count,				 int nonblock){	const char *orig_userbuf = userbuf;	struct via_channel *chan = &card->ch_out;	volatile struct via_sgd_table *sgtable = chan->sgtable;	size_t size;	int n, tmp;handle_one_block:	/* just to be a nice neighbor */	if (current->need_resched)		schedule ();	/* grab current channel software pointer.  In the case of	 * playback, this is pointing to the next buffer that	 * should receive data from userland.	 */	n = chan->sw_ptr;	/* n_bufs represents the number of buffers remaining	 * to be filled by userspace.  Sleep until	 * at least one buffer is available for our use.	 */	tmp = atomic_read (&chan->n_bufs);	assert (tmp >= 0);	assert (tmp <= VIA_DMA_BUFFERS);	while (tmp == 0) {		if (nonblock || !chan->is_enabled)			return -EAGAIN;		DPRINTK ("Sleeping on block %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);		interruptible_sleep_on (&chan->wait);		if (signal_pending (current))			return -ERESTARTSYS;		tmp = atomic_read (&chan->n_bufs);	}	/* Now that we have a buffer we can write to, fill it up	 * as much as possible with data from userspace.	 */	while ((count > 0) && (chan->slop_len < VIA_DMA_BUF_SIZE)) {		size_t slop_left = VIA_DMA_BUF_SIZE - chan->slop_len;		size = (count < slop_left) ? count : slop_left;		if (copy_from_user (chan->sgbuf[n].cpuaddr + chan->slop_len,				    userbuf, size))			return -EFAULT;		count -= size;		chan->slop_len += size;		userbuf += size;	}	/* If we didn't fill up the buffer with data, stop now.	 * Put a 'stop' marker in the DMA table too, to tell the	 * audio hardware to stop if it gets here.	 */	if (chan->slop_len < VIA_DMA_BUF_SIZE) {		sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP);		goto out;	}	/*	 * If we get to this point, we have filled a buffer with	 * audio data, flush the buffer to audio hardware.	 */	/* Record the true size for the audio hardware to notice */	if (n == (VIA_DMA_BUFFERS - 1))		sgtable[n].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_EOL);	else		sgtable[n].count = cpu_to_le32 (VIA_DMA_BUF_SIZE | VIA_FLAG);	/* advance channel software pointer to point to	 * the next buffer we will fill with data	 */	if (chan->sw_ptr == (VIA_DMA_BUFFERS - 1))		chan->sw_ptr = 0;	else		chan->sw_ptr++;	/* mark one less buffer as being available for userspace consumption */	assert (atomic_read (&chan->n_bufs) > 0);	atomic_dec (&chan->n_bufs);	/* we are at a block boundary, there is no fragment data */	chan->slop_len = 0;	/* if SGD has not yet been started, start it */	via_chan_maybe_start (chan);	DPRINTK("Flushed block %u, sw_ptr now %u, n_bufs now %d\n",		n, chan->sw_ptr, atomic_read (&chan->n_bufs));	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));	if (count > 0)		goto handle_one_block;out:	return userbuf - orig_userbuf;}static ssize_t via_dsp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){	struct via_info *card;	ssize_t rc;	int nonblock = (file->f_flags & O_NONBLOCK);	DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n",		 file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);	assert (file != NULL);	assert (buffer != NULL);	card = file->private_data;

⌨️ 快捷键说明

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