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

📄 omap-audio.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	if ((buffer - buffer0))		ret = buffer - buffer0;	DPRINTK("audio_write: return=%d\n", ret);	return ret;}/********************************************************************************* * * audio_read(): Exposed as read() function * *********************************************************************************/static intaudio_read(struct file *file, char *buffer, size_t count, loff_t * ppos){	char *buffer0 = buffer;	audio_state_t *state = file->private_data;	audio_stream_t *s = state->input_stream;	int chunksize, ret = 0;#ifdef OMAP_AUDIO_DMA_RETRY	int ret1 = 0, try_count = 0;#endif	unsigned long flags;	DPRINTK("audio_read: count=%d\n", count);	if (*ppos != file->f_pos) {		printk("AudioRead - FPOS not ppos ppos=0x%x fpos =0x%x\n",		       (u32) * ppos, (u32) file->f_pos);		return -ESPIPE;	}	if (s->mapped) {		printk("AudioRead - s already mapped\n");		return -ENXIO;	}	if (!s->active) {		if (!s->buffers && audio_setup_buf(s)) {			printk("AudioRead - No Memory\n");			return -ENOMEM;		}		audio_prime_rx(state);	}	while (count > 0) {		audio_buf_t *b = &s->buffers[s->usr_head];		/* Wait for a buffer to become full */		if (file->f_flags & O_NONBLOCK) {			ret = -EAGAIN;			if (down_trylock(&s->sem))				break;		} else {			ret = -ERESTARTSYS;			if (down_interruptible(&s->sem))				break;		}		/* Grab data from the current buffer */		chunksize = s->fragsize - b->offset;		if (chunksize > count)			chunksize = count;		DPRINTK("read %d from %d\n", chunksize, s->usr_head);		if (copy_to_user(buffer, b->data + b->offset, chunksize)) {			up(&s->sem);			return -EFAULT;		}		buffer += chunksize;		count -= chunksize;		b->offset += chunksize;		if (b->offset < s->fragsize) {			up(&s->sem);			break;		}		/* Update pointers and return current fragment to DMA */		local_irq_save(flags);		b->offset = 0;		if (++s->usr_head >= s->nbfrags)			s->usr_head = 0;		s->pending_frags++;		local_irq_restore(flags);#ifdef OMAP_AUDIO_DMA_RETRY		try_count = 0;		ret1 = 0;		do {			ret1 = audio_process_dma(s);			if (ret1 == -2) {	/* Queue full? */				udelay(QUEUE_WAIT_TIME);	/* give a chance to empty queue */			}			try_count++;		}		while ((try_count < MAX_QUEUE_FULL_RETRIES) && (ret1 == -2));#else		audio_process_dma(s);#endif#ifdef OMAP_AUDIO_DMA_RETRY		/* recovery strategy */		if (ret1) {			printk(KERN_ERR			       "audio_read: Queue is Full or dma processing error (%d)!\n",			       ret1);			break;		}#endif	}	if ((buffer - buffer0))		ret = buffer - buffer0;	DPRINTK("audio_read: return=%d\n", ret);	return ret;}/********************************************************************************* * * audio_mmap(): Exposed as mmap Function * *********************************************************************************/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;	FN_IN;	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, vma_addr, buf->dma_addr, buf->master,				     vma->vm_page_prot);		if (ret)			return ret;		vma_addr += buf->master;	}	s->mapped = 1;	FN_OUT(0);	return 0;}/********************************************************************************* * * audio_poll(): Exposed as poll function * *********************************************************************************/static unsigned intaudio_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;	DPRINTK("audio_poll(): mode=%s%s\n",		(file->f_mode & FMODE_READ) ? "r" : "",		(file->f_mode & FMODE_WRITE) ? "w" : "");	if (file->f_mode & FMODE_READ) {		/* Start audio input if not already active */		if (!is->active) {			if (!is->buffers && audio_setup_buf(is))				return -ENOMEM;			audio_prime_rx(state);		}		poll_wait(file, &is->wq, wait);	}	if (file->f_mode & FMODE_WRITE) {		if (!os->buffers && audio_setup_buf(os))			return -ENOMEM;		poll_wait(file, &os->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;	DPRINTK("audio_poll() returned mask of %s%s\n",		(mask & POLLIN) ? "r" : "", (mask & POLLOUT) ? "w" : "");	FN_OUT(mask);	return mask;}/********************************************************************************* * * audio_llseek(): Exposed as lseek() function. * *********************************************************************************/static loff_t audio_llseek(struct file *file, loff_t offset, int origin){	FN_IN;	FN_OUT(0);	return -ESPIPE;}/********************************************************************************* * * audio_ioctl(): Handles generic ioctls. If there is a request for something this * fn cannot handle, its then given to client specific ioctl routine, that will take * up platform specific requests * *********************************************************************************/static intaudio_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;	DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd);	/* dispatch based on command */	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;		FN_OUT(1);		return put_user(val, (int *)arg);	case SNDCTL_DSP_SETFRAGMENT:		if (get_user(val, (long *)arg)) {			FN_OUT(2);			return -EFAULT;		}		if (file->f_mode & FMODE_READ) {			int ret = audio_set_fragments(is, val);			if (ret < 0) {				FN_OUT(3);				return ret;			}			ret = put_user(ret, (int *)arg);			if (ret) {				FN_OUT(4);				return ret;			}		}		if (file->f_mode & FMODE_WRITE) {			int ret = audio_set_fragments(os, val);			if (ret < 0) {				FN_OUT(5);				return ret;			}			ret = put_user(ret, (int *)arg);			if (ret) {				FN_OUT(6);				return ret;			}		}		FN_OUT(7);		return 0;	case SNDCTL_DSP_SYNC:		FN_OUT(8);		return audio_sync(file);	case SNDCTL_DSP_SETDUPLEX:		FN_OUT(9);		return 0;	case SNDCTL_DSP_POST:		FN_OUT(10);		return 0;	case SNDCTL_DSP_GETTRIGGER:		val = 0;		if (file->f_mode & FMODE_READ && is->active && !is->stopped)			val |= PCM_ENABLE_INPUT;		if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)			val |= PCM_ENABLE_OUTPUT;		FN_OUT(11);		return put_user(val, (int *)arg);	case SNDCTL_DSP_SETTRIGGER:		if (get_user(val, (int *)arg)) {			FN_OUT(12);			return -EFAULT;		}		if (file->f_mode & FMODE_READ) {			if (val & PCM_ENABLE_INPUT) {				unsigned long flags;				if (!is->active) {					if (!is->buffers && audio_setup_buf(is)) {						FN_OUT(13);						return -ENOMEM;					}					audio_prime_rx(state);				}				local_irq_save(flags);				is->stopped = 0;				local_irq_restore(flags);				audio_process_dma(is);			} else {				audio_stop_dma(is);			}		}		if (file->f_mode & FMODE_WRITE) {			if (val & PCM_ENABLE_OUTPUT) {				unsigned long flags;				if (!os->buffers && audio_setup_buf(os)) {					FN_OUT(14);					return -ENOMEM;				}				local_irq_save(flags);				if (os->mapped && !os->pending_frags) {					os->pending_frags = os->nbfrags;					sema_init(&os->sem, 0);					os->active = 1;				}				os->stopped = 0;				local_irq_restore(flags);				audio_process_dma(os);			} else {				audio_stop_dma(os);			}		}		FN_OUT(15);		return 0;	case SNDCTL_DSP_GETOPTR:	case SNDCTL_DSP_GETIPTR:		{			count_info inf = { 0, };			audio_stream_t *s =			    (cmd == SNDCTL_DSP_GETOPTR) ? os : is;			int bytecount, offset;			unsigned long flags;			if ((s == is && !(file->f_mode & FMODE_READ)) ||			    (s == os && !(file->f_mode & FMODE_WRITE))) {				FN_OUT(16);				return -EINVAL;			}			if (s->active) {				local_irq_save(flags);				offset = audio_get_dma_pos(s);				inf.ptr = s->dma_tail * s->fragsize + offset;				bytecount = s->bytecount + offset;				s->bytecount = -offset;				inf.blocks = s->fragcount;				s->fragcount = 0;				local_irq_restore(flags);				if (bytecount < 0)					bytecount = 0;				inf.bytes = bytecount;			}			FN_OUT(17);			return copy_to_user((void *)arg, &inf, sizeof(inf));		}	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))) {				FN_OUT(18);				return -EINVAL;			}			if (!s->buffers && audio_setup_buf(s)) {				FN_OUT(19);				return -ENOMEM;			}			inf.bytes = atomic_read(&s->sem.count) * s->fragsize;			inf.fragments = inf.bytes / s->fragsize;			inf.fragsize = s->fragsize;			inf.fragstotal = s->nbfrags;			FN_OUT(20);			return copy_to_user((void *)arg, &inf, sizeof(inf));		}	case SNDCTL_DSP_NONBLOCK:		file->f_flags |= O_NONBLOCK;		FN_OUT(21);		return 0;	case SNDCTL_DSP_RESET:		if (file->f_mode & FMODE_READ) {			audio_reset(is);			if (state->need_tx_for_rx) {				unsigned long flags;				local_irq_save(flags);				os->spin_idle = 0;				local_irq_restore(flags);			}		}		if (file->f_mode & FMODE_WRITE) {			audio_reset(os);		}		FN_OUT(22);		return 0;	default:		/*		 * Let the client of this module handle the		 * non generic ioctls		 */		FN_OUT(23);		return state->client_ioctl(inode, file, cmd, arg);	}	FN_OUT(0);	return 0;}/********************************************************************************* * * audio_open(): Exposed as open() function * *********************************************************************************/static int audio_open(struct inode *inode, struct file *file){	audio_state_t *state = (&audio_state);	audio_stream_t *os = state->output_stream;	audio_stream_t *is = state->input_stream;	int err, need_tx_dma;	static unsigned char tsc2101_init_flag = 0;	FN_IN;	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;	err = -EINVAL;	if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !os)		goto out;	/* request DMA channels */	need_tx_dma = ((file->f_mode & FMODE_WRITE) ||		       ((file->f_mode & FMODE_READ) && state->need_tx_for_rx));	if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx))		need_tx_dma = 0;	if (need_tx_dma) {		DMA_REQUEST(err, os, audio_dma_callback);		DPRINTK(" err: %d\n", err);		if (err < 0)			goto out;	}	if (file->f_mode & FMODE_READ) {		DMA_REQUEST(err, is, audio_dma_callback);		if (err < 0) {			if (need_tx_dma)				DMA_FREE(os);			goto out;		}	}	/* now complete initialisation */	if (!AUDIO_ACTIVE(state)) {		if (state->hw_init && !tsc2101_init_flag) {			state->hw_init(state->data);			tsc2101_init_flag = 0;		}	}	if ((file->f_mode & FMODE_WRITE)) {		state->wr_ref = 1;		audio_reset(os);		os->fragsize = AUDIO_FRAGSIZE_DEFAULT;		os->nbfrags = AUDIO_NBFRAGS_DEFAULT;		os->mapped = 0;		init_waitqueue_head(&os->wq);	}	if (file->f_mode & FMODE_READ) {		state->rd_ref = 1;		audio_reset(is);		is->fragsize = AUDIO_FRAGSIZE_DEFAULT;		is->nbfrags = AUDIO_NBFRAGS_DEFAULT;		is->mapped = 0;		init_waitqueue_head(&is->wq);	}	file->private_data = state;	err = 0;      out:	up(&state->sem);	FN_OUT(err);	return err;}/********************************************************************************* * * audio_release(): Exposed as release function() * *********************************************************************************/static int audio_release(struct inode *inode, struct file *file){	audio_state_t *state = file->private_data;	audio_stream_t *os = state->output_stream;	audio_stream_t *is = state->input_stream;	FN_IN;	down(&state->sem);	if (file->f_mode & FMODE_READ) {		audio_discard_buf(is);		DMA_FREE(is);		is->dma_spinref = 0;		if (state->need_tx_for_rx) {			os->spin_idle = 0;			if (!state->wr_ref) {				DMA_FREE(os);				os->dma_spinref = 0;			}		}		state->rd_ref = 0;	}	if (file->f_mode & FMODE_WRITE) {		audio_sync(file);		audio_discard_buf(os);		if (!state->need_tx_for_rx || !state->rd_ref) {			DMA_FREE(os);			os->dma_spinref = 0;		}		state->wr_ref = 0;	}	if (!AUDIO_ACTIVE(state)) {		if (state->hw_shutdown)			state->hw_shutdown(state->data);	}	up(&state->sem);	FN_OUT(0);	return 0;}EXPORT_SYMBOL(audio_register_codec);EXPORT_SYMBOL(audio_unregister_codec);EXPORT_SYMBOL(audio_get_fops);MODULE_AUTHOR("Texas Instruments");MODULE_DESCRIPTION("Common audio handling for OMAP processors");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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