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

📄 omap-audio-dma-intfc.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
		s->fragcount++;		if (++s->dma_tail >= s->nbfrags)			s->dma_tail = 0;		if (!s->mapped)			up(&s->sem);		else			s->pending_frags++;		wake_up(&s->wq);	}	/* 	 * Since multiple channels are working in a ping-pong fashion,	 * we have a scenario where we have filled all the buffers, yet we	 * expect two callbacks (1 for previous filled buffer and one for last	 * filled buffer). These will happen one after the next.	 * Disable the channels as soon as we detect that we are completing the	 * link	 */	if (1 >= s->pending_frags) {		DPRINTK		    ("\n OMAP_AUDIO : callback we are stopping the chain for %d \n",		     lch);		omap_stop_dma(lch);		disable_chain(lch);	} else {		DPRINTK		    ("\n OMAP_AUDIO : audio_process_dma called from callback");		audio_process_dma(s);	}	FN_OUT(0);}static intaudio_set_dma_params_play(audio_stream_t * s, lch_chain * dma_chain, int pos,			  int size){	int ret;	dma_channel_params params;	params.data_type = 0x1;	/* data type 16 */	params.elem_count = 32;	params.frame_count = s->fragsize / (2 * params.elem_count);	params.src_amode = 1;	/* post increment */	params.src_start = pos;	params.src_ei = 0;	params.src_fi = 0;	params.dst_amode = 0;	/* constant */	/* mcbsp */	params.dst_start = AUDIO_MCBSP_DATAWRITE;	params.trigger = AUDIO_DMA_TX;	params.dst_ei = 0;	params.dst_fi = 0;	params.sync_mode = 0x0;	params.src_or_dst_synch = 0;	/* DEST synch */	ret = omap_set_dma_params_chain(dma_chain, params);	return ret;}static intaudio_set_dma_params_capture(audio_stream_t * s, lch_chain * dma_chain,			     int pos, int size){	int ret;	dma_channel_params params;	params.data_type = 0x1;	/* data type 16 */	params.elem_count = 32;	params.frame_count = s->fragsize / (2 * params.elem_count);	params.src_amode = 0;	/* post increment */	/* mcbsp */	params.src_start = AUDIO_MCBSP_DATAREAD;	params.trigger = AUDIO_DMA_RX;	params.src_ei = 0;	params.src_fi = 0;	params.dst_amode = 1;	params.dst_start = pos;	params.dst_ei = 0;	params.dst_fi = 0;	params.sync_mode = 0x0;	params.src_or_dst_synch = 1;	/* SRC SYNCH */	ret = omap_set_dma_params_chain(dma_chain, params);	return ret;}int audio_process_dma(audio_stream_t * s){	int ret;	unsigned long flags;	DPRINTK	    (": pending_frags = %d, usr_head = %d, dma_head = %d, dma_tail = %d, bytecount = %d, fragcount = %d\n",	     s->pending_frags, s->usr_head, s->dma_head, s->dma_tail,	     s->bytecount, s->fragcount);	local_irq_save(flags);	while ((!s->stopped) && (s->pending_frags)) {		audio_buf_t *b = &s->buffers[s->dma_head];		u_int dma_size = s->fragsize - b->offset;		if (dma_size > MAX_DMA_SIZE)			dma_size = CUT_DMA_SIZE;		if (s->input_or_output == FMODE_WRITE)			/*playback */		{			DPRINTK			    ("\n PLAYBACK DMA : data ptr = %x , data size = %x",			     b->dma_addr + b->offset, dma_size);			ret =			    audio_set_dma_params_play(s, s->dma_chain,						      b->dma_addr + b->offset,						      dma_size);		} else {			DPRINTK			    ("\n CAPTURE DMA : data ptr = %x , data size = %x",			     b->dma_addr + b->offset, dma_size);			ret =			    audio_set_dma_params_capture(s, s->dma_chain,							 b->dma_addr +							 b->offset, dma_size);		}		if (ret != 0) {			DPRINTK			    ("\nERROR: omap_audio.c: set_params cannot be done, trying again ...\n");			local_irq_restore(flags);			return -2;	/* indicate queue full */		}		ret = omap_start_dma_chain(s->dma_chain);		DPRINTK("\n OMAP_AUDIO : chain started");		if (ret) {			FN_OUT(1);			printk("\n Error: OMAP_AUDIO : dma start failed");			local_irq_restore(flags);			return -1;		}		b->dma_ref++;		b->offset += dma_size;		if (b->offset >= s->fragsize) {			s->pending_frags--;			if (++s->dma_head >= s->nbfrags)				s->dma_head = 0;		}	}	local_irq_restore(flags);	FN_OUT(0);	return 0;}int audio_setup_buf(audio_stream_t * s){	int frag;	int dmasize = 0;	char *dmabuf = NULL;	dma_addr_t dmaphys = 0;	FN_IN;	if (s->buffers) {		FN_OUT(1);		return -EBUSY;	}	s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);	if (!s->buffers)		goto err;	memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);	for (frag = 0; frag < s->nbfrags; frag++) {		audio_buf_t *b = &s->buffers[frag];		/*		 * Let's allocate non-cached memory for DMA buffers.		 * We try to allocate all memory at once.		 * If this fails (a common reason is memory fragmentation),		 * then we allocate more smaller buffers.		 */		if (!dmasize) {			dmasize = (s->nbfrags - frag) * s->fragsize;			do {				dmabuf = dma_alloc_coherent(NULL,							    dmasize,							    &dmaphys,							    GFP_KERNEL |							    GFP_DMA);				if (!dmabuf)					dmasize -= s->fragsize;			}			while (!dmabuf && dmasize);			if (!dmabuf)				goto err;			b->master = dmasize;			memzero(dmabuf, dmasize);		}		b->data = dmabuf;		b->dma_addr = dmaphys;		DPRINTK("buf %d: start %p dma %#08x master %d fragsize %d\n",			frag, b->data, b->dma_addr, b->master, s->fragsize);		dmabuf += s->fragsize;		dmaphys += s->fragsize;		dmasize -= s->fragsize;	}	s->usr_head = s->dma_head = s->dma_tail = 0;	s->bytecount = 0;	s->fragcount = 0;	sema_init(&s->sem, s->nbfrags);	FN_OUT(0);	return 0;      err:	printk(AUDIO_NAME ": unable to allocate audio memory\n ");	audio_discard_buf(s);	FN_OUT(1);	return -ENOMEM;}void audio_discard_buf(audio_stream_t * s){	FN_IN;	/* ensure DMA isn't using those buffers */	audio_reset(s);	if (s->buffers) {		int frag;		for (frag = 0; frag < s->nbfrags; frag++) {			if (!s->buffers[frag].master)				continue;			dma_free_coherent(NULL,					  s->buffers[frag].master,					  s->buffers[frag].data,					  s->buffers[frag].dma_addr);		}		kfree(s->buffers);		s->buffers = NULL;	}	FN_OUT(0);}u_int audio_get_dma_pos(audio_stream_t * s){	audio_buf_t *b = &s->buffers[s->dma_tail];	u_int offset;	FN_IN;	if (b->dma_ref) {		if (s->input_or_output == FMODE_WRITE)			offset =			    omap_get_dma_pos_src(s->dma_chain->queue_head) -			    b->dma_addr;		else			offset =			    omap_get_dma_pos_dst(s->dma_chain->queue_head) -			    b->dma_addr;		if (offset >= s->fragsize)			offset = s->fragsize - 4;	} else if (s->pending_frags) {		offset = b->offset;	} else {		offset = 0;	}	FN_OUT(offset);	return offset;}void audio_prime_rx(audio_state_t * state){	audio_stream_t *is = state->input_stream;	unsigned long flags;	FN_IN;	local_irq_save(flags);	is->pending_frags = is->nbfrags;	sema_init(&is->sem, 0);	is->active = 1;	audio_process_dma(is);	local_irq_restore(flags);	FN_OUT(0);}void audio_reset(audio_stream_t * s){	FN_IN;	if (s->buffers) {		audio_stop_dma(s);		s->buffers[s->dma_head].offset = 0;		s->buffers[s->usr_head].offset = 0;		s->usr_head = s->dma_head;		s->pending_frags = 0;		sema_init(&s->sem, s->nbfrags);	}	s->active = 0;	s->stopped = 0;	FN_OUT(0);}int audio_set_fragments(audio_stream_t * s, int val){	FN_IN;;	if (s->active)		return -EBUSY;	if (s->buffers)		audio_discard_buf(s);	s->nbfrags = (val >> 16) & 0x7FFF;	val &= 0xFFFF;	if (val < 4)		val = 4;	if (val > 15)		val = 15;	s->fragsize = 1 << val;	if (s->nbfrags < 2)		s->nbfrags = 2;	if (s->nbfrags * s->fragsize > 128 * 1024)		s->nbfrags = 128 * 1024 / s->fragsize;	FN_OUT(0);	if (audio_setup_buf(s))		return -ENOMEM;	return val | (s->nbfrags << 16);}void audio_stop_dma(audio_stream_t * s){	u_int pos;	unsigned long flags;	audio_buf_t *b;	FN_IN;	if (s->dma_spinref > 0 || !s->buffers)		return;	local_irq_save(flags);	s->stopped = 1;	omap_stop_dma_chain(s->dma_chain);	pos = audio_get_dma_pos(s);	omap_clear_dma_chain(s->dma_chain);	local_irq_restore(flags);	/* back up pointers to be ready to restart from the same spot */	while (s->dma_head != s->dma_tail) {		b = &s->buffers[s->dma_head];		if (b->dma_ref) {			b->dma_ref = 0;			b->offset = 0;		}		s->pending_frags++;		if (s->dma_head == 0)			s->dma_head = s->nbfrags;		s->dma_head--;	}	b = &s->buffers[s->dma_head];	if (b->dma_ref) {		b->offset = pos;		b->dma_ref = 0;	}	FN_OUT(0);}int audio_sync(struct file *file){	audio_state_t *state = file->private_data;	audio_stream_t *s = state->output_stream;	audio_buf_t *b;	u_int shiftval = 0;	unsigned long flags;	DECLARE_WAITQUEUE(wait, current);	FN_IN;	if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) {		FN_OUT(1);		return 0;	}	/*	 * Send current buffer if it contains data.  Be sure to send	 * a full sample count.	 */	b = &s->buffers[s->usr_head];	if (b->offset &= ~3) {		down(&s->sem);		/*		 * HACK ALERT !		 * To avoid increased complexity in the rest of the code		 * where full fragment sizes are assumed, we cheat a little		 * with the start pointer here and don't forget to restore		 * it later.		 */		shiftval = s->fragsize - b->offset;		b->offset = shiftval;		b->dma_addr -= shiftval;		b->data -= shiftval;		s->bytecount -= shiftval;		if (++s->usr_head >= s->nbfrags)			s->usr_head = 0;		local_irq_save(flags);		s->pending_frags++;		audio_process_dma(s);		local_irq_restore(flags);	}	/* Let's wait for all buffers to complete */	set_current_state(TASK_INTERRUPTIBLE);	DPRINTK("---1");	add_wait_queue(&s->wq, &wait);	DPRINTK("---2");	while ((s->pending_frags || (atomic_read(&s->sem.count) < s->nbfrags))	       && !signal_pending(current)) {		DPRINTK("---3 pf=%d sc=%d nbfg=%d sp=%d ", s->pending_frags,			atomic_read(&s->sem.count), s->nbfrags,			signal_pending(current));		schedule();		DPRINTK("---4");		set_current_state(TASK_INTERRUPTIBLE);		DPRINTK("---5");	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&s->wq, &wait);	/* undo the pointer hack above */	if (shiftval) {		local_irq_save(flags);		b->dma_addr += shiftval;		b->data += shiftval;		/* ensure sane DMA code behavior if not yet processed */		if (b->offset != 0)			b->offset = s->fragsize;		local_irq_restore(flags);	}	FN_OUT(0);	return 0;}#endif				/* End of #ifdef CONFIG_ARCH_OMAP24XX *//********************************************************************************* * * audio_get_dma_callback(): return the dma interface call back function * *********************************************************************************/dma_callback_t audio_get_dma_callback(void){	FN_IN;	FN_OUT(0);	return audio_dma_callback;}MODULE_AUTHOR("Texas Instruments");MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");MODULE_LICENSE("GPL");#if CONFIG_ARCH_OMAP16XXEXPORT_SYMBOL(omap_clear_sound_dma);EXPORT_SYMBOL(omap_request_sound_dma);EXPORT_SYMBOL(omap_free_sound_dma);#endif				/* End of #if CONFIG_ARCH_OMAP16XX */EXPORT_SYMBOL(audio_get_dma_callback);EXPORT_SYMBOL(audio_setup_buf);EXPORT_SYMBOL(audio_process_dma);EXPORT_SYMBOL(audio_prime_rx);EXPORT_SYMBOL(audio_set_fragments);EXPORT_SYMBOL(audio_sync);EXPORT_SYMBOL(audio_stop_dma);EXPORT_SYMBOL(audio_get_dma_pos);EXPORT_SYMBOL(audio_reset);EXPORT_SYMBOL(audio_discard_buf);

⌨️ 快捷键说明

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