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

📄 dma_ep93xx.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	 *  interrupt on the channel.	 */	uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);	uiCONTROL &= ~CONTROL_M2M_NFBINTEN;	outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );	/*	 * enable the done interrupt.	 */	uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);	uiCONTROL |= CONTROL_M2M_DONEINTEN;	outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );	/*	 *  Update the dma channel instance transfer state.	 */	dma->xfer_enable = TRUE;	dma->pause = FALSE;	/*	 *  Program up the first buffer descriptor with a source and destination	 *  and a byte count.	 */	outl( dma->buffer_queue[dma->current_buffer].source,	      M2M_reg_base+M2M_OFFSET_SAR_BASE0 );	outl( dma->buffer_queue[dma->current_buffer].dest,	      M2M_reg_base+M2M_OFFSET_DAR_BASE0 );	outl( dma->buffer_queue[dma->current_buffer].size,	      M2M_reg_base+M2M_OFFSET_BCR0 );	/*	 *  Decrement the new buffers counter.	 */	dma->new_buffers--;	/*	 * Set up the second buffer descriptor with a second buffer if we have	 * a second buffer.	 */	if (dma->new_buffers) {		outl( dma->buffer_queue[(dma->current_buffer + 1) %					MAX_EP93XX_DMA_BUFFERS].source,		      M2M_reg_base+M2M_OFFSET_SAR_BASE1 );		outl( dma->buffer_queue[(dma->current_buffer + 1) %					MAX_EP93XX_DMA_BUFFERS].dest,		      M2M_reg_base+M2M_OFFSET_DAR_BASE1 );		outl( dma->buffer_queue[(dma->current_buffer + 1) %					MAX_EP93XX_DMA_BUFFERS].size,		      M2M_reg_base+M2M_OFFSET_BCR1 );		uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);		uiCONTROL |= CONTROL_M2M_NFBINTEN;		outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );		dma->new_buffers--;	}	/*	 *  Now we enable the channel.  This initiates the transfer.	 */	uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);	uiCONTROL |= CONTROL_M2M_ENABLE;	outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );	inl(M2M_reg_base + M2M_OFFSET_CONTROL);	/*	 *  If this is a memory to memory transfer, we need to s/w trigger the	 *  transfer by setting the start bit within the control register.	 */	if (dma->device == DMA_MEMORY) {		uiCONTROL = inl(M2M_reg_base+M2M_OFFSET_CONTROL);		uiCONTROL |= CONTROL_M2M_START;		outl( uiCONTROL, M2M_reg_base+M2M_OFFSET_CONTROL );	}	DPRINTK("DMA - It's been started!!");	DPRINTK("CONTROL - 0x%x \n",	inl(M2M_reg_base+M2M_OFFSET_CONTROL) );	DPRINTK("STATUS - 0x%x \n",	 inl(M2M_reg_base+M2M_OFFSET_STATUS) );	DPRINTK("BCR0 - 0x%x \n",	   dma->buffer_queue[dma->current_buffer].size);	DPRINTK("SAR_BASE0 - 0x%x \n",  inl(M2M_reg_base+M2M_OFFSET_SAR_BASE0) );	DPRINTK("SAR_CUR0 - 0x%x \n",   inl(M2M_reg_base+M2M_OFFSET_SAR_CURRENT0) );	DPRINTK("DAR_BASE0 - 0x%x \n",  inl(M2M_reg_base+M2M_OFFSET_DAR_BASE0) );	DPRINTK("DAR_CUR0 - 0x%x \n",   inl(M2M_reg_base+M2M_OFFSET_DAR_CURRENT0) );	/*	 *  Unmask irqs	 */	local_irq_restore(flags);	/*	 *  Success.	 */	return(0);}/***************************************************************************** * *  DMA interface functions * ****************************************************************************//***************************************************************************** * *  int dma_init(int handle, unsigned int flags_m2p, unsigned int flags_m2m, *			   dma_callback callback, unsigned int user_data) * *  Description: Configure the DMA channel and install a callback function. * *  handle:	 Handle unique the each instance of the dma interface, used *			  to verify this call. *  flags_m2p   Flags used to configure an M2P/P2M dma channel and determine *			  if a callback function and user_data information are included *			  in this call. This field should be NULL if handle represents *			  an M2M channel. *  flags_m2m   Flags used to configure an M2M dma channel and determine *			  if a callback function and user_data information are included *			  in this call. This field should be NULL if handle represents *			  an M2P/P2M channel. *  callback	function pointer which is called near the end of the *			  dma channel's irq handler. *  user_data   defined by the calling driver. * ****************************************************************************/intep93xx_dma_config(int handle, unsigned int flags_m2p, unsigned int flags_m2m,		  dma_callback callback, unsigned int user_data){	int  channel;	ep93xx_dma_t * dma;	int flags;	unsigned int M2P_reg_base, uiCONTROL;	/*	 *  Get the DMA hw channel # from the handle.	 */	channel = dma_get_channel_from_handle(handle);	/*	 *  See if this is a valid handle.	 */	if (channel < 0) {		printk(KERN_ERR			   "DMA Config: Invalid dma handle.\n");		return(-EINVAL);	}	DPRINTK("DMA Config \n");	dma = &dma_chan[channel];	local_irq_save(flags);	/*	 *  Check if the channel is currently transferring.	 */	if (dma->xfer_enable) {		local_irq_restore(flags);		return(-EINVAL);	}	/*	 *  Check if this is an m2m function.	 */	if (channel >= 10) {		local_irq_restore(flags);		/*		 *  Call another function to handle m2m config.		 */		return(dma_config_m2m(dma, flags_m2m, callback, user_data));	}	/*	 *  Setup a pointer into the dma channel's register set.	 */	M2P_reg_base = dma->reg_base;	/*	 *  By default we enable the stall interrupt.	 */	uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);	uiCONTROL |= CONTROL_M2P_STALLINTEN;	outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );	/*	 *  Configure the channel for an error from the peripheral.	 */	uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);	if ( flags_m2p && CHANNEL_ERROR_INT_ENABLE )		uiCONTROL |= CONTROL_M2P_CHERRORINTEN;	else		uiCONTROL &= ~CONTROL_M2P_CHERRORINTEN;	outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );	uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);	if ( flags_m2p && CHANNEL_ABORT )		uiCONTROL |= CONTROL_M2P_ABRT;	else		uiCONTROL &= ~CONTROL_M2P_ABRT;	outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );	uiCONTROL = inl(M2P_reg_base+M2P_OFFSET_CONTROL);	if ( flags_m2p && IGNORE_CHANNEL_ERROR )		uiCONTROL |= CONTROL_M2P_ICE;	else		uiCONTROL &= ~CONTROL_M2P_ICE;	outl( uiCONTROL, M2P_reg_base+M2P_OFFSET_CONTROL );	/*	 *  Save the callback function in the dma instance for this channel.	 */	dma->callback = callback;	/*	 *  Save the user data in the the dma instance for this channel.	 */	dma->user_data = user_data;	/*	 *  Put the dma instance into the pause state by setting the	 *  pause bit to true.	 */	dma->pause = TRUE;	local_irq_restore(flags);	/*	 *  Success.	 */	return(0);}/***************************************************************************** * *  int dma_start(int handle, unsigned int channels, unsigned int * handles) * *  Description: Initiate a transfer on up to 3 channels. * *  handle:	 handle for the channel to initiate transfer on. *  channels:   number of channels to initiate transfers on. *  handles:	pointer to an array of handles, one for each channel which *			   is to be started. * ****************************************************************************/intep93xx_dma_start(int handle, unsigned int channels, unsigned int * handles){	ep93xx_dma_t * dma_pointers[3];	unsigned int M2P_reg_bases[3];	unsigned int loop, flags, uiCONTROL;	int  channel;	/*	 *  Get the DMA hw channel # from the handle.	 */	channel = dma_get_channel_from_handle(handle);	/*	 *  See if this is a valid handle.	 */	if (channel < 0) {		printk(KERN_ERR "DMA Start: Invalid dma handle.\n");		return(-EINVAL);	}	if (channels < 1) {		printk(KERN_ERR "DMA Start: Invalid parameter.\n");		return(-EINVAL);	}	DPRINTK("DMA Start \n");	/*	 *  Mask off registers.	 */	local_irq_save(flags);	/*	 *  Check if this is a start multiple.	 */	if (channels > 1) {		DPRINTK("DMA ERROR: Start, multiple start not supported yet \n");		return(-1);	} else {		/*		 *  Check if this channel is already transferring.		 */		if (dma_chan[channel].xfer_enable && !dma_chan[channel].pause) {			printk(KERN_ERR				   "DMA Start: Invalid command for channel %d.\n", channel);			/*			 *  Unmask irqs			 */			local_irq_restore(flags);			/*			 *  This channel is already transferring, so return an error.			 */			return(-EINVAL);		}		/*		 *  If this is an M2M channel, call a different function.		 */		if (channel >= 10) {			/*			 *  Unmask irqs			 */			local_irq_restore(flags);			/*			 *  Call the m2m start function.  Only start one channel.			 */			return(dma_start_m2m(channel, &dma_chan[channel]));		}		/*		 *  Make sure the channel has at least one buffer in the queue.		 */		if (dma_chan[channel].new_buffers < 1) {			DPRINTK("DMA Start: Channel starved.\n");			/*			 *  This channel does not have enough buffers queued up,			 *  so enter the pause by starvation state.			 */			dma_chan[channel].xfer_enable = TRUE;			dma_chan[channel].pause = TRUE;			/*			 *  Unmask irqs			 */			local_irq_restore(flags);			/*			 *  Success.			 */			return(0);		}		/*		 *  Set up a dma instance pointer for this dma channel.		 */		dma_pointers[0] = &dma_chan[channel];		/*		 * Set up a pointer to the register set for this channel.		 */		M2P_reg_bases[0] = dma_pointers[0]->reg_base;	}	/*	 *  Setup both MAXCNT registers with values from the next two buffers	 *  in the queue, and enable the next frame buffer interrupt on the channel.	 */	for (loop = 0; loop < channels; loop++) {		/*		 *  By default we enable the next frame buffer interrupt.		 */		uiCONTROL = inl(M2P_reg_bases[loop]+M2P_OFFSET_CONTROL);		uiCONTROL |= CONTROL_M2P_NFBINTEN;		outl( uiCONTROL, M2P_reg_bases[loop]+M2P_OFFSET_CONTROL );		/*		 *  Check if we need to restore a paused transfer.		 */		if (dma_pointers[loop]->pause_buf.buf_id != -1)			outl( dma_pointers[loop]->pause_buf.size,			      M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT0 );		else			outl( dma_pointers[loop]->buffer_queue[dma_pointers[loop]->current_buffer].size,			      M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT0 );	}	for (loop = 0; loop < channels; loop++) {		/*		 *  Enable the specified dma channels.		 */		uiCONTROL = inl(M2P_reg_bases[loop]+M2P_OFFSET_CONTROL);		uiCONTROL |= CONTROL_M2P_ENABLE;		outl( uiCONTROL, M2P_reg_bases[loop]+M2P_OFFSET_CONTROL );		/*		 *  Update the dma channel instance transfer state.		 */		dma_pointers[loop]->xfer_enable = TRUE;		dma_pointers[loop]->pause = FALSE;		if (dma_pointers[loop]->pause_buf.buf_id == -1)			dma_pointers[loop]->new_buffers--;	}	/*	 *  Program up the BASE0 registers for all specified channels, this	 *  will initiate transfers on all specified channels.	 */	for (loop = 0; loop < channels; loop++)		/*		 *  Check if we need to restore a paused transfer.		 */		if (dma_pointers[loop]->pause_buf.buf_id != -1) {			outl( dma_pointers[loop]->pause_buf.source,			      M2P_reg_bases[loop]+M2P_OFFSET_BASE0 );			/*			 *  Set the pause buffer to NULL			 */			dma_pointers[loop]->pause_buf.buf_id = -1;			dma_pointers[loop]->pause_buf.size = 0;		} else			outl( dma_pointers[loop]->buffer_queue[				  dma_pointers[loop]->current_buffer].source,			      M2P_reg_bases[loop]+M2P_OFFSET_BASE0 );	/*	 *  Before restoring irqs setup the second MAXCNT/BASE	 *  register with a second buffer.	 */	for (loop = 0; loop < channels; loop++)		if (dma_pointers[loop]->new_buffers) {			outl( dma_pointers[loop]->buffer_queue[				  (dma_pointers[loop]->current_buffer + 1) %				  MAX_EP93XX_DMA_BUFFERS].size,			      M2P_reg_bases[loop]+M2P_OFFSET_MAXCNT1 );			outl( dma_pointers[loop]->buffer_queue[				  (dma_pointers[loop]->current_buffer + 1) %				  MAX_EP93XX_DMA_BUFFERS].source,			      M2P_reg_bases[loop]+M2P_OFFSET_BASE1 );		}	/*	  DPRINTK("DMA - It's been started!!");	  DPRINTK("STATUS - 0x%x \n",	 inl(M2P_reg_base+M2P_OFFSET_STATUS) );	  DPRINTK("CONTROL - 0x%x \n",	inl(M2P_reg_base+M2P_OFFSET_CONTROL) );	  DPRINTK("REMAIN - 0x%x \n",	 inl(M2P_reg_base+M2P_OFFSET_REMAIN) );	  DPRINTK("PPALLOC - 0x%x \n",	inl(M2P_reg_base+M2P_OFFSET_PPALLOC) );	  DPRINTK("BASE0 - 0x%x \n",	  inl(M2P_reg_base+M2P_OFFSET_BASE0) );	  DPRINTK("MAXCNT0 - 0x%x \n",	inl(M2P_reg_base+M2P_OFFSET_MAXCNT0) );	  DPRINTK("CURRENT0 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT0) );	  DPRINTK("BASE1 - 0x%x \n",	  inl(M2P_reg_base+M2P_OFFSET_BASE1) );	  DPRINTK("MAXCNT1 - 0x%x \n",	inl(M2P_reg_base+M2P_OFFSET_MAXCNT1) );	  DPRINTK("CURRENT1 - 0x%x \n",   inl(M2P_reg_base+M2P_OFFSET_CURRENT1) );	  DPRINTK("Pause - %d \n", dma_pointers[0]->pause);	  DPRINTK("xfer_enable - %d \n", dma_pointers[0]->xfer_enable);	  DPRINTK("total bytes - 0x%x \n", dma_pointers[0]->total_bytes);	  DPRINTK("total buffer - %d \n", dma_pointers[0]->total_buffers);	  DPRINTK("new buffers - %d \n", dma_pointers[0]->new_buffers);	  DPRINTK("current buffer - %d \n", dma_pointers[0]->current_buffer);	  DPRINTK("last buffer - %d \n", dma_pointers[0]->last_buffer);	  DPRINTK("used buffers - %d \n", dma_pointers[0]->used_buffers);	*/	/*	 *  Unmask irqs	 */	local_irq_restore(flags);	/*	 *  Success.	 */	return(0);}/***************************************************************************** * *  int ep93xx_dma_add_buffer(int handle, unsigned int * address, *						 unsigned int size, unsigned int last) * *  Description: Add a buffer entry to the DMA buffer queue. * *  handle:	 handle for the channel to add this buffer to. *  address:	Pointer to an integer which is the start address of the *			  buffer which is to be added to the queue. *  size:	   size of the buffer in bytes.

⌨️ 快捷键说明

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