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

📄 pxa-audio.c

📁 Source files for pxa ac97 sound driver The packet contains the files that is listed below driv
💻 C
📖 第 1 页 / 共 2 页
字号:
		ret = buffer - buffer0;	return ret;}static int audio_sync(struct file *file){	audio_state_t *state = file->private_data;	audio_stream_t *s = state->output_stream;	audio_buf_t *b;	pxa_dma_desc *final_desc;	u_long dcmd_save = 0;	DECLARE_WAITQUEUE(wait, current);	if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped)		return 0;	/*	 * Send current buffer if it contains data.  Be sure to send	 * a full sample count.	 */	final_desc = NULL;	b = &s->buffers[s->usr_frag];	if (b->offset &= ~3) {		final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE];		b->offset &= (MAX_DMA_SIZE-1);		dcmd_save = final_desc->dcmd;		final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; 		final_desc->ddadr |= DDADR_STOP;		b->offset = 0;		b->dma_desc->ddadr &= ~DDADR_STOP;		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {			DDADR(s->dma_ch) = b->dma_desc->ddadr;			DCSR(s->dma_ch) = DCSR_RUN;		}	}	/* Wait for DMA to complete. */	set_current_state(TASK_INTERRUPTIBLE);#if 0	/* 	 * The STOPSTATE IRQ never seem to occur if DCSR_STOPIRQEN is set	 * along wotj DCSR_RUN.  Silicon bug?	 */	add_wait_queue(&s->stop_wq, &wait);	DCSR(s->dma_ch) |= DCSR_STOPIRQEN;	schedule();#else 	add_wait_queue(&s->frag_wq, &wait);	while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) {		schedule();		set_current_state(TASK_INTERRUPTIBLE);	}#endif	set_current_state(TASK_RUNNING);	remove_wait_queue(&s->frag_wq, &wait);	/* Restore the descriptor chain. */	if (final_desc) {		final_desc->dcmd = dcmd_save;		final_desc->ddadr &= ~DDADR_STOP;		b->dma_desc->ddadr |= DDADR_STOP;	}	return 0;}static unsigned int audio_poll(struct file *file,			       struct poll_table_struct *wait){	audio_state_t *state = file->private_data;	audio_stream_t *is = state->input_stream;	audio_stream_t *os = state->output_stream;	unsigned int mask = 0;	if (file->f_mode & FMODE_READ) {		/* Start audio input if not already active */		if (!is->buffers && audio_setup_buf(is))			return -ENOMEM;		if (DCSR(is->dma_ch) & DCSR_STOPSTATE) {			DDADR(is->dma_ch) = 				is->buffers[is->dma_frag].dma_desc->ddadr;			DCSR(is->dma_ch) = DCSR_RUN;		}		poll_wait(file, &is->frag_wq, wait);	}	if (file->f_mode & FMODE_WRITE) {		if (!os->buffers && audio_setup_buf(os))			return -ENOMEM;		poll_wait(file, &os->frag_wq, wait);	}	if (file->f_mode & FMODE_READ)		if (( is->mapped && is->bytecount > 0) ||		    (!is->mapped && atomic_read(&is->sem.count) > 0))			mask |= POLLIN | POLLRDNORM;	if (file->f_mode & FMODE_WRITE)		if (( os->mapped && os->bytecount > 0) ||		    (!os->mapped && atomic_read(&os->sem.count) > 0))			mask |= POLLOUT | POLLWRNORM;	return mask;}static int audio_ioctl( struct inode *inode, struct file *file,			uint cmd, ulong arg){	audio_state_t *state = file->private_data;	audio_stream_t *os = state->output_stream;	audio_stream_t *is = state->input_stream;	long val;	switch (cmd) {	case OSS_GETVERSION:		return put_user(SOUND_VERSION, (int *)arg);	case SNDCTL_DSP_GETBLKSIZE:		if (file->f_mode & FMODE_WRITE)			return put_user(os->fragsize, (int *)arg);		else			return put_user(is->fragsize, (int *)arg);	case SNDCTL_DSP_GETCAPS:		val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP;		if (is && os)			val |= DSP_CAP_DUPLEX;		return put_user(val, (int *)arg);	case SNDCTL_DSP_SETFRAGMENT:		if (get_user(val, (long *) arg))			return -EFAULT;		if (file->f_mode & FMODE_READ) {			int ret = audio_set_fragments(is, val);			if (ret < 0)				return ret;			ret = put_user(ret, (int *)arg);			if (ret)				return ret;		}		if (file->f_mode & FMODE_WRITE) {			int ret = audio_set_fragments(os, val);			if (ret < 0)				return ret;			ret = put_user(ret, (int *)arg);			if (ret)				return ret;		}		return 0;	case SNDCTL_DSP_SYNC:		return audio_sync(file);	case SNDCTL_DSP_SETDUPLEX:		return 0;	case SNDCTL_DSP_POST:		return 0;	case SNDCTL_DSP_GETTRIGGER:		val = 0;		if (file->f_mode & FMODE_READ && DCSR(is->dma_ch) & DCSR_RUN)			val |= PCM_ENABLE_INPUT;		if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN)			val |= PCM_ENABLE_OUTPUT;		return put_user(val, (int *)arg);	case SNDCTL_DSP_SETTRIGGER:		if (get_user(val, (int *)arg))			return -EFAULT;		if (file->f_mode & FMODE_READ) {			if (val & PCM_ENABLE_INPUT) {				if (!is->buffers && audio_setup_buf(is))					return -ENOMEM;				if (!(DCSR(is->dma_ch) & DCSR_RUN)) {					audio_buf_t *b = &is->buffers[is->dma_frag];					DDADR(is->dma_ch) = b->dma_desc->ddadr;					DCSR(is->dma_ch) = DCSR_RUN;				}			} else {				DCSR(is->dma_ch) = 0;			}		}		if (file->f_mode & FMODE_WRITE) {			if (val & PCM_ENABLE_OUTPUT) {				if (!os->buffers && audio_setup_buf(os))					return -ENOMEM;				if (!(DCSR(os->dma_ch) & DCSR_RUN)) {					audio_buf_t *b = &os->buffers[os->dma_frag];					DDADR(os->dma_ch) = b->dma_desc->ddadr;					DCSR(os->dma_ch) = DCSR_RUN;				}			} else {				DCSR(os->dma_ch) = 0;			}		}		return 0;	case SNDCTL_DSP_GETOSPACE:	case SNDCTL_DSP_GETISPACE:	    {		audio_buf_info inf = { 0, };		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;		if ((s == is && !(file->f_mode & FMODE_READ)) ||		    (s == os && !(file->f_mode & FMODE_WRITE)))			return -EINVAL;		if (!s->buffers && audio_setup_buf(s))			return -ENOMEM;		inf.bytes = atomic_read(&s->sem.count) * s->fragsize;		inf.bytes -= s->buffers[s->usr_frag].offset;		inf.fragments = inf.bytes / s->fragsize;		inf.fragsize = s->fragsize;		inf.fragstotal = s->nbfrags;		return copy_to_user((void *)arg, &inf, sizeof(inf));	    }	case SNDCTL_DSP_GETOPTR:	case SNDCTL_DSP_GETIPTR:	    {		count_info inf = { 0, };		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is;		dma_addr_t ptr;		int bytecount, offset, flags;		if ((s == is && !(file->f_mode & FMODE_READ)) ||		    (s == os && !(file->f_mode & FMODE_WRITE)))			return -EINVAL;		if (DCSR(s->dma_ch) & DCSR_RUN) {			audio_buf_t *b;			save_flags_cli(flags);			ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch);			b = &s->buffers[s->dma_frag];			offset = ptr - b->dma_desc->dsadr;			if (offset >= s->fragsize)				offset = s->fragsize - 4;		} else {			save_flags(flags);			offset = 0;		}		inf.ptr = s->dma_frag * s->fragsize + offset;		bytecount = s->bytecount + offset;		//s->bytecount = -offset;		inf.blocks = s->fragcount;		s->fragcount = 0;		restore_flags(flags);		if (bytecount < 0)			bytecount = 0;		inf.bytes = bytecount;		return copy_to_user((void *)arg, &inf, sizeof(inf));	    }	case SNDCTL_DSP_NONBLOCK:		file->f_flags |= O_NONBLOCK;		return 0;	case SNDCTL_DSP_RESET:		if (file->f_mode & FMODE_WRITE) 			audio_clear_buf(os);		if (file->f_mode & FMODE_READ)			audio_clear_buf(is);		return 0;	default:		return state->client_ioctl(inode, file, cmd, arg);	}	return 0;}static int audio_mmap(struct file *file, struct vm_area_struct *vma){	audio_state_t *state = file->private_data;	audio_stream_t *s;	unsigned long size, vma_addr;	int i, ret;	if (vma->vm_pgoff != 0)		return -EINVAL;	if (vma->vm_flags & VM_WRITE) {		if (!state->wr_ref)			return -EINVAL;;		s = state->output_stream;	} else if (vma->vm_flags & VM_READ) {		if (!state->rd_ref)			return -EINVAL;		s = state->input_stream;	} else return -EINVAL;	if (s->mapped)		return -EINVAL;	size = vma->vm_end - vma->vm_start;	if (size != s->fragsize * s->nbfrags)		return -EINVAL;	if (!s->buffers && audio_setup_buf(s))		return -ENOMEM;	vma_addr = vma->vm_start;	for (i = 0; i < s->nbfrags; i++) {		audio_buf_t *buf = &s->buffers[i];		if (!buf->master)			continue;		ret = remap_page_range(vma_addr, buf->dma_desc->dsadr,				       buf->master, vma->vm_page_prot);		if (ret)			return ret;		vma_addr += buf->master;	}	for (i = 0; i < s->nbfrags; i++)		s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP;	s->mapped = 1;	return 0;}static int audio_release(struct inode *inode, struct file *file){	audio_state_t *state = file->private_data;	down(&state->sem);	if (file->f_mode & FMODE_READ) {		audio_clear_buf(state->input_stream);		*state->input_stream->drcmr = 0;		pxa_free_dma(state->input_stream->dma_ch);		state->rd_ref = 0;	}	if (file->f_mode & FMODE_WRITE) {		audio_sync(file);		audio_clear_buf(state->output_stream);		*state->output_stream->drcmr = 0;		pxa_free_dma(state->output_stream->dma_ch);		state->wr_ref = 0;	}	up(&state->sem);	return 0;}int pxa_audio_attach(struct inode *inode, struct file *file,			 audio_state_t *state){	audio_stream_t *is = state->input_stream;	audio_stream_t *os = state->output_stream;	int err;	down(&state->sem);	/* access control */	err = -ENODEV;	if ((file->f_mode & FMODE_WRITE) && !os)		goto out;	if ((file->f_mode & FMODE_READ) && !is)		goto out;	err = -EBUSY;	if ((file->f_mode & FMODE_WRITE) && state->wr_ref)		goto out;	if ((file->f_mode & FMODE_READ) && state->rd_ref)		goto out;	/* request DMA channels */	if (file->f_mode & FMODE_WRITE) {		err = pxa_request_dma(os->name, DMA_PRIO_LOW, 					  audio_dma_irq, os);		if (err < 0)			goto out;		os->dma_ch = err;	}	if (file->f_mode & FMODE_READ) {		err = pxa_request_dma(is->name, DMA_PRIO_LOW,					  audio_dma_irq, is);		if (err < 0) {			if (file->f_mode & FMODE_WRITE) {				*os->drcmr = 0;				pxa_free_dma(os->dma_ch);			}			goto out;		}		is->dma_ch = err;	}	file->private_data	= state;	file->f_op->release	= audio_release;	file->f_op->write	= audio_write;	file->f_op->read	= audio_read;	file->f_op->mmap	= audio_mmap;	file->f_op->poll	= audio_poll;	file->f_op->ioctl	= audio_ioctl;	file->f_op->llseek	= no_llseek;	if ((file->f_mode & FMODE_WRITE)) {		state->wr_ref = 1;		os->fragsize = AUDIO_FRAGSIZE_DEFAULT;		os->nbfrags = AUDIO_NBFRAGS_DEFAULT;		os->output = 1;		os->mapped = 0;		init_waitqueue_head(&os->frag_wq);		init_waitqueue_head(&os->stop_wq);		*os->drcmr = os->dma_ch | DRCMR_MAPVLD;	}	if (file->f_mode & FMODE_READ) {		state->rd_ref = 1;		is->fragsize = AUDIO_FRAGSIZE_DEFAULT;		is->nbfrags = AUDIO_NBFRAGS_DEFAULT;		is->output = 0;		is->mapped = 0;		init_waitqueue_head(&is->frag_wq);		init_waitqueue_head(&is->stop_wq);		*is->drcmr = is->dma_ch | DRCMR_MAPVLD;	}	err = 0;out:	up(&state->sem);	return err;}EXPORT_SYMBOL(pxa_audio_attach);EXPORT_SYMBOL(pxa_audio_clear_buf);

⌨️ 快捷键说明

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