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

📄 via82cxxx_audio.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
		}	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&chan->wait, &wait);	if (ret)		goto out;	/* 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 < chan->frag_size)) {		size_t slop_left = chan->frag_size - chan->slop_len;		void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr;		unsigned ofs = n % (PAGE_SIZE / chan->frag_size);		size = (count < slop_left) ? count : slop_left;		if (copy_to_user (userbuf,				  base + ofs + chan->slop_len,				  size)) {			ret = -EFAULT;			goto out;		}		count -= size;		chan->slop_len += size;		userbuf += size;	}	/* If we didn't copy the buffer completely to userspace,	 * stop now.	 */	if (chan->slop_len < chan->frag_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 == (chan->frag_number - 1))		chan->sw_ptr = 0;	else		chan->sw_ptr++;	/* mark one less buffer waiting to be processed */	assert (atomic_read (&chan->n_frags) > 0);	atomic_dec (&chan->n_frags);	/* we are at a block boundary, there is no fragment data */	chan->slop_len = 0;	DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",		n, chan->sw_ptr, atomic_read (&chan->n_frags));	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) ? (userbuf - orig_userbuf) : ret;}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;	}	via_chan_set_buffering(card, &card->ch_in, -1);        rc = via_chan_buffer_init (card, &card->ch_in);	if (rc)		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){        DECLARE_WAITQUEUE(wait, current);	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;	ssize_t ret = 0;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 fragment pointer.  In the case of	 * playback, this is pointing to the next fragment that	 * should receive data from userland.	 */	n = chan->sw_ptr;	/* n_frags represents the number of fragments remaining	 * to be filled by userspace.  Sleep until	 * at least one fragment is available for our use.	 */	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 page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record);		schedule();		ret = via_syscall_down (card, nonblock);		if (ret)			break;		if (signal_pending (current)) {			ret = -ERESTARTSYS;			break;		}	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&chan->wait, &wait);	if (ret)		goto out;	/* Now that we have at least one fragment we can write to, fill the buffer	 * as much as possible with data from userspace.	 */	while ((count > 0) && (chan->slop_len < chan->frag_size)) {		size_t slop_left = chan->frag_size - chan->slop_len;		size = (count < slop_left) ? count : slop_left;		if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len,				    userbuf, size)) {			ret = -EFAULT;			goto out;		}		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 < chan->frag_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 == (chan->frag_number - 1))                sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL);        else                sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG);	/* advance channel software pointer to point to	 * the next buffer we will fill with data	 */	if (chan->sw_ptr == (chan->frag_number - 1))		chan->sw_ptr = 0;	else		chan->sw_ptr++;	/* mark one less buffer as being available for userspace consumption */	assert (atomic_read (&chan->n_frags) > 0);	atomic_dec (&chan->n_frags);	/* 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_frags now %d\n",		n, chan->sw_ptr, atomic_read (&chan->n_frags));	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;	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_out.is_mapped) {		rc = -ENXIO;		goto out_up;	}	via_chan_set_buffering(card, &card->ch_out, -1);	rc = via_chan_buffer_init (card, &card->ch_out);	if (rc)		goto out_up;	rc = via_dsp_do_write (card, buffer, count, nonblock);out_up:	up (&card->syscall_sem);out:	DPRINTK ("EXIT, returning %ld\n",(long) rc);	return rc;}static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait){	struct via_info *card;	struct via_channel *chan;	unsigned int mask = 0;	DPRINTK ("ENTER\n");	assert (file != NULL);	card = file->private_data;	assert (card != NULL);	if (file->f_mode & FMODE_READ) {		chan = &card->ch_in;		if (sg_active (chan->iobase))	                poll_wait(file, &chan->wait, wait);		if (atomic_read (&chan->n_frags) > 0)			mask |= POLLIN | POLLRDNORM;	}	if (file->f_mode & FMODE_WRITE) {		chan = &card->ch_out;		if (sg_active (chan->iobase))	                poll_wait(file, &chan->wait, wait);		if (atomic_read (&chan->n_frags) > 0)			mask |= POLLOUT | POLLWRNORM;	}	DPRINTK ("EXIT, returning %u\n", mask);	return mask;}/** *	via_dsp_drain_playback - sleep until all playback samples are flushed *	@card: Private info for specified board *	@chan: Channel to drain *	@nonblock: boolean, non-zero if O_NONBLOCK is set * *	Sleeps until all playback has been flushed to the audio *	hardware. * *	Locking: inside card->syscall_sem */static int via_dsp_drain_playback (struct via_info *card,				   struct via_channel *chan, int nonblock){        DECLARE_WAITQUEUE(wait, current);	int ret = 0;	DPRINTK ("ENTER, nonblock = %d\n", nonblock);	if (chan->slop_len > 0)		via_chan_flush_frag (chan);	if (atomic_read (&chan->n_frags) == chan->frag_number)		goto out;	via_chan_maybe_start (chan);	add_wait_queue(&chan->wait, &wait);	for (;;) {		__set_current_state(TASK_INTERRUPTIBLE);		if (atomic_read (&chan->n_frags) >= chan->frag_number)			break;		if (nonblock) {			DPRINTK ("EXIT, returning -EAGAIN\n");			ret = -EAGAIN;			break;		}#ifdef VIA_DEBUG		{		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);		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 (!chan->is_active)			printk (KERN_ERR "sleeping but not active\n");#endif		up(&card->syscall_sem);		DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags));		schedule();		if ((ret = via_syscall_down (card, nonblock)))			break;		if (signal_pending (current)) {			DPRINTK ("EXIT, returning -ERESTARTSYS\n");			ret = -ERESTARTSYS;			break;		}	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&chan->wait, &wait);#ifdef VIA_DEBUG	{		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);		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));		DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags));	}#endifout:	DPRINTK ("EXIT, returning %d\n", ret);	return ret;}/** *	via_dsp_ioctl_space - get information about channel buffering *	@card: Private info for specified board *	@chan: pointer to channel-specific info *	@arg: user buffer for returned information * *	Handles SNDCTL_DSP_GETISPACE and SNDCTL_DSP_GETOSPACE. * *	Locking: inside card->syscall_sem */static int via_dsp_ioctl_space (struct via_info *card,				struct via_channel *chan,				void *arg){	audio_buf_info info;	via_chan_set_buffering(card, chan, -1);	info.fragstotal = chan->frag_number;	info.fragsize = chan->frag_size;	/* number of full fragments we can read/write without blocking */	info.fragments = atomic_read (&chan->n_frags);	if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0))		info.fragments--;	/* number of bytes that can be read or written immediately	 * without blocking.	 */	info.bytes = (info.fragments * chan->frag_size);	if (chan->slop_len % chan->frag_size > 0)		info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size);	DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n",		info.fragstotal,		info.fragsize,		info.fragments,		info.bytes);	return copy_to_user (arg, &info, sizeof (info));}/** *	via_dsp_ioctl_ptr - get information about hardware buffer ptr *	@card: Private info for specified board *	@chan: pointer to channel-specific info *	@arg: user buffer for returned information * *	Handles SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR. * *	Locking: inside card->syscall_sem */static int via_dsp_ioctl_ptr (struct via_info *card

⌨️ 快捷键说明

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