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

📄 omap-audio-dma-intfc.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	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);}/*************************************************************************************** * * Sync up the buffers before we shutdown, else under-run errors will happen * **************************************************************************************/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;		local_irq_save(flags);		s->bytecount -= shiftval;		if (++s->usr_head >= s->nbfrags)			s->usr_head = 0;		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 - (s->pending_frags %d atomic_read(&s->sem.count) %d  s->nbfrags %d !signal_pending(current)=%d\n",		     s->pending_frags, atomic_read(&s->sem.count), s->nbfrags,		     !signal_pending(current));		schedule();		set_current_state(TASK_INTERRUPTIBLE);	}	DPRINTK("---4");	set_current_state(TASK_RUNNING);	remove_wait_queue(&s->wq, &wait);	DPRINTK("---5");	/* 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);	}	DPRINTK("---E\n");	FN_OUT(0);	return 0;}/*************************************************************************************** * * Stop all the DMA channels of the stream * **************************************************************************************/void audio_stop_dma(audio_stream_t * s){	int *chan = s->lch;	int i;	FN_IN;	if (unlikely(NULL == chan)) {		BUG();		return;	}	for (i = 0; i < NUMBER_OF_CHANNELS_TO_LINK; i++) {		int cur_chan = chan[i];		omap_stop_dma(cur_chan);		DPRINTK("%d- Channel Stop:%d\n", i, chan[i]);	}	s->started = 0;	FN_OUT(0);	return;}/*************************************************************************************** * * Get the dma posn * **************************************************************************************/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) {		offset = omap_get_dma_pos(s->lch[s->dma_q_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;}/*************************************************************************************** * * Reset the audio buffers * **************************************************************************************/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 = s->prevbuf = 0;		sema_init(&s->sem, s->nbfrags);	}	s->active = 0;	s->stopped = 0;	s->started = 0;	FN_OUT(0);	return;}/*************************************************************************************** * * Clear any pending transfers * **************************************************************************************/void omap_clear_sound_dma(audio_stream_t * s){	FN_IN;	omap_clear_dma(s->lch[s->dma_q_head]);	FN_OUT(0);	return;}/*********************************** MODULE FUNCTIONS DEFINTIONS ***********************/#ifdef OMAP1610_MCBSP1_BASE#undef OMAP1610_MCBSP1_BASE#endif#define OMAP1610_MCBSP1_BASE    0xE1011000/*************************************************************************************** * * DMA related functions * **************************************************************************************/static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,				     u_int dma_size){	int dt = 0x1;		/* data type 16 */	int cen = 32;		/* Stereo */	int cfn = dma_size / (2 * cen);	FN_IN;	DPRINTK(" Params are: channel=%d,dt=%d,cen=%d,cfn=%d,dma_size=%d\n",		channel, dt, cen, cfn, dma_size);	omap_set_dma_dest_params(channel, 0x05, 0x00,				 (OMAP1610_MCBSP1_BASE + 0x806));	omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr);	omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00);	FN_OUT(0);	return 0;}static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,					u_int dma_size){	int dt = 0x1;		/* data type 16 */	int cen = 16;		/* mono */	int cfn = dma_size / (2 * cen);	FN_IN;	DPRINTK(" Params are: channel=%d,dt=%d,cen=%d,cfn=%d,dma_size=%d\n",		channel, dt, cen, cfn, dma_size);	omap_set_dma_src_params(channel, 0x05, 0x00,				(OMAP1610_MCBSP1_BASE + 0x802));	omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr);	omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00);	FN_OUT(0);	return 0;}static int audio_start_dma_chain(audio_stream_t * s){	int channel = s->lch[s->dma_q_head];	FN_IN;	if (!s->started) {		DPRINTK("STARTDMA %d\n", channel);		omap_start_dma(channel);		s->started = 1;	}	/* else the dma itself will progress forward with out our help */	FN_OUT(0);	return 0;}/* Start DMA - * Do the initial set of work to initialize all the channels as required. * We shall then initate a transfer */static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr,				u_int dma_size){	int ret = -EPERM;	FN_IN;	if (unlikely(dma_size > MAX_DMA_SIZE)) {		ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,		    MAX_DMA_SIZE);		return -EOVERFLOW;	}	DPRINTK("BEFORE CHECK head=%d, tail=%d\n", s->dma_q_head,		s->dma_q_tail);	if (AUDIO_QUEUE_FULL(s)) {		DPRINTK("QUEUE FULL!\n");		ret = -2;		goto sound_out;	}	if (s->input_or_output == FMODE_WRITE)		/*playback */	{		DPRINTK("PLAYBACK DMA : data ptr = %x , data size = %x\n",			dma_ptr, dma_size);		ret =		    audio_set_dma_params_play(s->lch[s->dma_q_tail], dma_ptr,					      dma_size);	} else {		DPRINTK		    ("CAPTURE DMA : data ptr = %x , data size = %x\n",		     dma_ptr, dma_size);		ret =		    audio_set_dma_params_capture(s->lch[s->dma_q_tail], dma_ptr,						 dma_size);	}	if (ret != 0) {		DPRINTK("set_params cannot be done, trying again ...\n");		ret = -2;	/* indicate queue full */		goto sound_out;	}	AUDIO_INCREMENT_TAIL(s);	DPRINTK("AFTER START head=%d, tail=%d [%d]\n", s->dma_q_head,		s->dma_q_tail, s->lch[s->dma_q_head]);	ret = audio_start_dma_chain(s);	DPRINTK("\n OMAP_AUDIO : chain started");	if (ret) {		ERR("dma start failed");	}      sound_out:	FN_OUT(ret);	return ret;}/*************************************************************************************** * * ISR related functions * **************************************************************************************//* The work item handler */static void audio_dsr_handler(unsigned long inData){	void *data = (void *)inData;	struct audio_isr_work_item *work = data;	audio_stream_t *s = (work->s);	int sound_curr_lch = work->current_lch;	u16 ch_status = work->ch_status;	FN_IN;	DPRINTK("DS%d\n", sound_curr_lch);	DPRINTK("lch=%d,status=0x%x, data=%p as=%p\n", sound_curr_lch,		ch_status, data, s);	if (AUDIO_QUEUE_EMPTY(s)) {		ERR("Interrupt(%d)  for empty queue(h=%d, T=%d)???\n",		    sound_curr_lch, s->dma_q_head, s->dma_q_tail);		ERR("nbfrag=%d,pendfrags=%d,USR-H=%d, QH-%d QT-%d\n",		    s->nbfrags, s->pending_frags, s->usr_head, s->dma_head,		    s->dma_tail);		FN_OUT(-1);		return;	}	AUDIO_INCREMENT_HEAD(s);	/* Empty the queue */	/* Try to fill again */	audio_dma_callback(sound_curr_lch, ch_status, s);	FN_OUT(0);}/* Macro to trace the IRQ calls - checks for multi-channel irqs *///#define IRQ_TRACE#ifdef IRQ_TRACE#define MAX_UP 10static char xyz[MAX_UP] = { 0 };static int h = 0;#endif/* ISRs have to be short and smart.. So we transfer every heavy duty stuff to the  * work item */static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status, void *data){	int dma_status = ch_status;	audio_stream_t *s = (audio_stream_t *) data;	FN_IN;#ifdef IRQ_TRACE	xyz[h++] = '0' + sound_curr_lch;	if (h == MAX_UP - 1) {		printk("%s-", xyz);		h = 0;	}#endif	DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n", sound_curr_lch,		ch_status, dma_status, data);	if (dma_status & (DCSR_ERROR)) {		omap_writew(omap_readw(OMAP_DMA_CCR(sound_curr_lch)) & ~DCCR_EN,			    OMAP_DMA_CCR(sound_curr_lch));		ERR("DCSR_ERROR!\n");		FN_OUT(-1);		return;	}	/* Start the work item  - we ping pong the work items */	if (!work_item_running) {		work1.current_lch = sound_curr_lch;		work1.ch_status = ch_status;		work1.s = s;		/* schedule tasklet 1 */		tasklet_schedule(&audio_isr_work1);		work_item_running = 1;	} else {		work2.current_lch = sound_curr_lch;		work2.ch_status = ch_status;		work2.s = s;		/* schedule tasklet 2 */		tasklet_schedule(&audio_isr_work2);		work_item_running = 0;	}	FN_OUT(0);	return;}/* The call back that handles buffer stuff */static void audio_dma_callback(int lch, u16 ch_status, void *data){	audio_stream_t *s = data;	audio_buf_t *b = &s->buffers[s->dma_tail];	FN_IN;	DPRINTK(": b->dma_ref = %d, b->offset = %d\n", b->dma_ref, b->offset);	if (s->dma_spinref > 0) {		s->dma_spinref--;	} else if (!s->buffers) {		printk(KERN_CRIT		       "omap_audio: received DMA IRQ for non existent buffers!\n");		return;	} else if (b->dma_ref && --b->dma_ref == 0 && b->offset >= s->fragsize) {		/* This fragment is done */		b->offset = 0;		s->bytecount += s->fragsize;		s->fragcount++;		s->dma_spinref = -s->dma_spinref;		if (++s->dma_tail >= s->nbfrags)			s->dma_tail = 0;		if (!s->mapped)			up(&s->sem);		else			s->pending_frags++;		wake_up(&s->wq);	}	/* Detect End of transfer and Clean up 	 * Pend frags will be 1 . This means that there is one more chunk of data to 	 * complete transmission. This implies if channel 1 and channel 2 have data, 	 * the callback is for channel1 and channel 2 is currently being transmitted 	 * by the DMA. If we wait for Channel 2's completion before stopping the DMA, 	 * we will be late since the channels are chained, and the channel 1 would 	 * have already started trasmitting (junk data), hence a spurious call back 	 * would occur (for channel 1). Hence we forgo the last buffer transmission.	 */	if ((s->pending_frags < s->prevbuf)	    && (s->pending_frags <= (NUMBER_OF_CHANNELS_TO_LINK - 1))) {		DPRINTK("%s Stop pend=%d prev=%d\n", __FUNCTION__,		       s->pending_frags, s->prevbuf);		omap_stop_dma(s->lch[s->dma_q_head]);		omap_stop_dma(s->lch[s->dma_q_tail]);		//audio_queue_count =0;		AUDIO_QUEUE_INIT(s);		b->offset = 0;		s->bytecount += s->fragsize;		s->fragcount++;		if (++s->dma_tail >= s->nbfrags)			s->dma_tail = 0;		if (!s->mapped) {			while (s->nbfrags != atomic_read(&s->sem.count))				up(&s->sem);		}		s->prevbuf = s->pending_frags = 0;		wake_up(&s->wq);		s->started = 0;	} else {		s->prevbuf = s->pending_frags;		audio_process_dma(s);	}	FN_OUT(0);	return;}#endif				/* End of #if CONFIG_ARCH_OMAP16XX *//******************* THE FOLLOWING IS FOR OMAP24xx **************************/#ifdef CONFIG_ARCH_OMAP24XX#define MAX_DMA_SIZE		 0x2000#define CUT_DMA_SIZE		 0x2000static void audio_dma_callback(int lch, u16 ch_status, void *data){	audio_stream_t *s = data;	audio_buf_t *b = &s->buffers[s->dma_tail];	DPRINTK(": b->dma_ref = %d, b->offset = %d\n", b->dma_ref, b->offset);	if (!s->buffers) {		printk(KERN_CRIT		       "omap_audio: received DMA IRQ for non existent buffers!\n");		return;	} else if (b->dma_ref && --b->dma_ref == 0 && b->offset >= s->fragsize) {		/* This fragment is done */		b->offset = 0;		s->bytecount += s->fragsize;

⌨️ 快捷键说明

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