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

📄 via82cxxx_audio.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	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;	}	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;	unsigned int mask = 0, rd, wr;	DPRINTK ("ENTER\n");	assert (file != NULL);	card = file->private_data;	assert (card != NULL);	rd = (file->f_mode & FMODE_READ);	wr = (file->f_mode & FMODE_WRITE);	if (wr && (atomic_read (&card->ch_out.n_bufs) == 0)) {		assert (card->ch_out.is_active);                poll_wait(file, &card->ch_out.wait, wait);	}        if (rd) {		/* XXX is it ok, spec-wise, to start DMA here? */		via_chan_maybe_start (&card->ch_in);		if (atomic_read (&card->ch_in.n_bufs) == 0)	                poll_wait(file, &card->ch_in.wait, wait);	}	if (wr && (atomic_read (&card->ch_out.n_bufs) > 0))		mask |= POLLOUT | POLLWRNORM;	if (rd && (atomic_read (&card->ch_in.n_bufs) > 0))		mask |= POLLIN | POLLRDNORM;	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){	DPRINTK ("ENTER, nonblock = %d\n", nonblock);	if (chan->slop_len > 0)		via_chan_flush_frag (chan);	if (atomic_read (&chan->n_bufs) == VIA_DMA_BUFFERS)		goto out;	via_chan_maybe_start (chan);	while (atomic_read (&chan->n_bufs) < VIA_DMA_BUFFERS) {		if (nonblock) {			DPRINTK ("EXIT, returning -EAGAIN\n");			return -EAGAIN;		}#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		DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_bufs));		interruptible_sleep_on (&chan->wait);		if (signal_pending (current)) {			DPRINTK ("EXIT, returning -ERESTARTSYS\n");			return -ERESTARTSYS;		}	}#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_bufs));	}#endifout:	DPRINTK ("EXIT, returning 0\n");	return 0;}/** *	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;	info.fragstotal = VIA_DMA_BUFFERS;	info.fragsize = VIA_DMA_BUF_SIZE;	/* number of full fragments we can read/write without blocking */	info.fragments = atomic_read (&chan->n_bufs);	if ((chan->slop_len > 0) && (info.fragments > 0))		info.fragments--;	/* number of bytes that can be read or written immediately	 * without blocking.	 */	info.bytes = (info.fragments * VIA_DMA_BUF_SIZE);	if (chan->slop_len > 0)		info.bytes += VIA_DMA_BUF_SIZE - chan->slop_len;	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,				struct via_channel *chan,				void *arg){	count_info info;	spin_lock_irq (&card->lock);	info.bytes = chan->bytes;	info.blocks = chan->n_irqs;	chan->n_irqs = 0;	spin_unlock_irq (&card->lock);	if (chan->is_active) {		unsigned long extra;		info.ptr = atomic_read (&chan->hw_ptr) * VIA_DMA_BUF_SIZE;		extra = VIA_DMA_BUF_SIZE - inl (chan->iobase + VIA_BASE0_PCM_OUT_BLOCK_COUNT);		info.ptr += extra;		info.bytes += extra;	} else {		info.ptr = 0;	}	DPRINTK ("EXIT, returning bytes=%d, blocks=%d, ptr=%d\n",		info.bytes,		info.blocks,		info.ptr);	return copy_to_user (arg, &info, sizeof (info));}static int via_dsp_ioctl_trigger (struct via_channel *chan, int val){	int enable, do_something;	if (chan->is_record)		enable = (val & PCM_ENABLE_INPUT);	else		enable = (val & PCM_ENABLE_OUTPUT);	if (!chan->is_enabled && enable) {		do_something = 1;	} else if (chan->is_enabled && !enable) {		do_something = -1;	} else {		do_something = 0;	}	DPRINTK ("enable=%d, do_something=%d\n",		 enable, do_something);	if (chan->is_active && do_something)		return -EINVAL;	if (do_something == 1) {		chan->is_enabled = 1;		via_chan_maybe_start (chan);		DPRINTK ("Triggering input\n");	}	else if (do_something == -1) {		chan->is_enabled = 0;		DPRINTK ("Setup input trigger\n");	}	return 0;}static int via_dsp_ioctl (struct inode *inode, struct file *file,			  unsigned int cmd, unsigned long arg){	int rc, rd=0, wr=0, val=0;	struct via_info *card;	struct via_channel *chan;	int nonblock = (file->f_flags & O_NONBLOCK);	assert (file != NULL);	card = file->private_data;	assert (card != NULL);	if (file->f_mode & FMODE_WRITE)		wr = 1;	if (file->f_mode & FMODE_READ)		rd = 1;	rc = via_syscall_down (card, nonblock);	if (rc)		return rc;	rc = -EINVAL;	switch (cmd) {	/* OSS API version.  XXX unverified */	case OSS_GETVERSION:		DPRINTK("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n");		rc = put_user (SOUND_VERSION, (int *)arg);		break;	/* list of supported PCM data formats */	case SNDCTL_DSP_GETFMTS:		DPRINTK("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n");                rc = put_user (AFMT_U8 | AFMT_S16_LE, (int *)arg);		break;	/* query or set current channel's PCM data format */	case SNDCTL_DSP_SETFMT:		if (get_user(val, (int *)arg)) {			rc = -EFAULT;			break;		}		DPRINTK("DSP_SETFMT, val==%d\n", val);		if (val != AFMT_QUERY) {			rc = 0;			if (rc == 0 && rd)				rc = via_chan_set_fmt (card, &card->ch_in, val);			if (rc == 0 && wr)				rc = via_chan_set_fmt (card, &card->ch_out, val);			if (rc <= 0) {				if (rc == 0)					rc = -EINVAL;				break;			}			val = rc;		} else {			if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) ||			    (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_16BIT)))				val = AFMT_S16_LE;			else				val = AFMT_U8;		}		DPRINTK("SETFMT EXIT, returning %d\n", val);                rc = put_user (val, (int *)arg);		break;	/* query or set number of channels (1=mono, 2=stereo) */        case SNDCTL_DSP_CHANNELS:		if (get_user(val, (int *)arg)) {			rc = -EFAULT;			break;		}		DPRINTK("DSP_CHANNELS, val==%d\n", val);		if (val != 0) {			rc = 0;			if (rc == 0 && rd)				rc = via_chan_set_stereo (card, &card->ch_in, val);			if (rc == 0 && wr)				rc = via_chan_set_stereo (card, &card->ch_out, val);			if (rc <= 0) {				if (rc == 0)					rc = -EINVAL;				break;			}			val = rc;		} else {			if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_STEREO)) ||			    (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_STEREO)))				val = 2;			else				val = 1;		}		DPRINTK("CHANNELS EXIT, returning %d\n", val);                rc = put_user (val, (int *)arg);		break;	/* enable (val is not zero) or disable (val == 0) stereo */        case SNDCTL_DSP_STEREO:		if (get_user(val, (int *)arg)) {			rc = -EFAULT;			break;		}		DPRINTK("DSP_STEREO, val==%d\n", val);		rc = 0;		if (rc == 0 && rd)			rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1);		if (rc == 0 && wr)			rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1);		if (rc <= 0) {			if (rc == 0)				rc = -EINVAL;			break;		}		DPRINTK("STEREO EXIT, returning %d\n", val);                rc = 0;		break;	/* query or set sampling rate */        case SNDCTL_DSP_SPEED:		if (get_user(val, (int *)arg)) {			rc = -EFAULT;			break;		}		DPRINTK("DSP_SPEED, val==%d\n", val);		if (val < 0) {			rc = -EINVAL;			break;		}		if (val > 0) {			rc = 0;			if (rc == 0 && rd)				rc = via_chan_set_speed (card, &card->ch_in, val);			if (rc == 0 && wr)				rc = via_chan_set_speed (card, &card->ch_out, val);			if (rc <= 0) {				if (rc == 0)					rc = -EINVAL;				break;			}			val = rc;		} else {			if (rd)				val = card->ch_in.rate;			else if (wr)				val = card->ch_out.rate;			else				val = 0;		}		DPRINTK("SPEED EXIT, returning %d\n", val);                rc = put_user (val, (int *)arg);		break;	/* wait until all buffers have been played, and then stop device */	case SNDCTL_DSP_SYNC:		DPRINTK ("DSP_SYNC\n");		if (wr) {			DPRINTK("SYNC EXIT (after calling via_dsp_drain_playback)\n");			rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);		}		break;	/* stop recording/playback immediately */        case SNDCTL_DSP_RESET:		DPRINTK ("DSP_RESET\n");		if (rd) {			via_chan_clear (&card->ch_in);			via_chan_pcm_fmt (&card->ch_in, 1);		}		if (wr) {			via_chan_clear (&card->ch_out);			via_chan_pcm_fmt (&card->ch_out, 1);		}		rc = 0;		break;	/* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */	case SNDCTL_DSP_GETCAPS:		DPRINTK("DSP_GETCAPS\n");		rc = put_user(VIA_DSP_CAP, (int *)arg);		break;	/* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */	case SNDCTL_DSP_GETBLKSIZE:		DPRINTK("DSP_GETBLKSIZE\n");		rc = put_user(VIA_DMA_BUF_SIZE, (int *)arg);		break;	/* obtain information about input buffering */	case SNDCTL_DSP_GETISPACE:		DPRINTK("DSP_GETISPACE\n");		if (rd)			rc = via_dsp_ioctl_space (card, &card->ch_in, (void*) arg);		break;	/* obtain information about output buffering */	case SNDCTL_DSP_GETOSPACE:		DPRINTK("DSP_GETOSPACE\n");		if (wr)			rc = via_dsp_ioctl_space (card, &card->ch_out, (void*) arg);		break;	/* obtain information about input hardware pointer */	case SNDCTL_DSP_GETIPTR:		DPRINTK("DSP_GETIPTR\n");		if (rd)			rc = via_dsp_ioctl_ptr (card, &card->ch_in, (void*) arg);		break;	/* obtain information about output hardware pointer */	case SNDCTL_DSP_GETOPTR:		DPRINTK("DSP_GETOPTR\n");		if (wr)			rc = via_dsp_ioctl_ptr (card, &card->ch_out, (void*) arg);		break;	/* return number of bytes remaining to be played by DMA engine */	case SNDCTL_DSP_GETODELAY:		{		DPRINTK("DSP_GETODELAY\n");		chan = &card->ch_out;		if (!wr)			break;		val = VIA_DMA_BUFFERS - atomic_read (&chan->n_bufs);		if (val > 0) {			val *= VIA_DMA_BUF_SIZE;			val -= VIA_DMA

⌨️ 快捷键说明

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