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

📄 mdma_lan91c111.c

📁 lwip tcp/ip 协议栈 adsp BF533 DSP 移植 用 visual dsp++ 编译
💻 C
字号:
#define USE_16_BIT

#include <lan91c111.h>
#include <cdefbf533.h>
#include <ccblkfn.h>

int num_dma_protect_zeros=0;
static ADI_ETHER_LAN91C111_DATA *dev=0;
extern void *drv_CriticalHandle;
#define ENTER_CRITICAL_REGION() (drv_CriticalHandle=adi_int_EnterCriticalRegion(dev->CriticalData))
#define EXIT_CRTICIAL_REGION()  (adi_int_ExitCriticalRegion(drv_CriticalHandle)) 
// MDMA register offsets from the base register
//
#define  OFFSET_NXT_DES      0x0
#define  OFFSET_START_ADDR   0x4
#define  OFFSET_CONFIG       0x8 
#define  OFFSET_X_COUNT      0x10
#define  OFFSET_X_MODIFY     0x14
#define  OFFSET_Y_COUNT      0x18
#define  OFFSET_Y_MODIFY     0x1C
#define  OFFSET_IRQ_STATUS   0x28

/* sets values for the DMA registers */
#define SET_VAL_SHORT(addr,val) (((*(volatile unsigned short*)addr)) = val)
#define SET_VAL_ADDR(addr,val) (((*(volatile void**)addr)) = ((volatile void*)(val)))
#define GET_VAL_SHORT(addr,val) (val = (*(volatile unsigned short*)addr))

// Defined in lan91c111.c
// 
extern "C" transmit_complete();
extern "C" receive_complete();


/******************************************************************************
 * if mas_int is 1 it masks the ethernet interrupt. if its 0 unmasks it.
 *****************************************************************************/
#pragma optimize_off
void mask_ethernet_int(int mask_int)
{
	if(mask_int)
		 *pSIC_IMASK &= ~(1 << dev->DmaSICMaskBit);
	else
		 *pSIC_IMASK |= 1 << dev->DmaSICMaskBit;
}

/******************************************************************************
 * If any DMA operation is in progress then this will block. Else it will
 * lock the DMA and return
 *****************************************************************************/
void dma_protect(ADI_ETHER_LAN91C111_DATA *d,DMA_DIRECTION direction)
{
	while(1) 
	{
		ENTER_CRITICAL_REGION();
		if(dev->m_dma_protect == 0)
			break;
		else
			EXIT_CRTICIAL_REGION();
	}

	dev->m_dma_protect = 1;
	dev->m_dma_direction = direction;

	EXIT_CRTICIAL_REGION();
}

/******************************************************************************
 * releases the DMA so that either transmit or receive can use it.
 *****************************************************************************/
void dma_relinquish()
{
	ENTER_CRITICAL_REGION();
	dev->m_dma_protect = 0;
	dev->m_dma_direction = DMA_NONE;
	ssync();
	// set destination config to 0
	SET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_CONFIG),(unsigned short)0x0);
	ssync();
	// set source config to 0
	SET_VAL_SHORT((dev->SrcStreamBaseAddr+OFFSET_CONFIG),(unsigned short)0x0);
	ssync();
	EXIT_CRTICIAL_REGION();
}

/******************************************************************************
 * Mask or Unmask DMA interrupt, if the flag is true then masks the DMA int
 * else unmasks the dma interrupt
 * flag = 1 means enables the DMA interrupt in the SIC
 * flag = 0 means disables the  DMA interrupt in the SIC
 *****************************************************************************/
void dma_mask_en(int flag)
{
	unsigned int mask;
	mask = *pSIC_IMASK;
	// 1 means enable
	if(flag)
		mask |= 1 << dev->DmaSICMaskBit;
	else
		mask &= ~(0x0L | (1 << dev->DmaSICMaskBit));

	*pSIC_IMASK = mask;
	ssync();
}

/******************************************************************************
 * Rests the MDMA config registers and sets MDMA bit in SIC
 *****************************************************************************/
void init_dma(ADI_ETHER_LAN91C111_DATA *d)
{
	// set the global static to access device data
	dev =d;
	// set destination config to 0
	SET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_CONFIG),(unsigned short)0x0);
	ssync();
	// set source config to 0
	SET_VAL_SHORT((dev->SrcStreamBaseAddr+OFFSET_CONFIG),(unsigned short)0x0);
	ssync();
	// set the DMA error count to 0
	dev->MemDmaErrorCount=0;
	// set DMA stream bit in SIC. Stream0 its 21 and 22 for stream1
	dma_mask_en(1);

}

/******************************************************************************
 * DMA interrupt handler, Upon completion of the DMA operation this will get
 * called.
 *****************************************************************************/
void dma_interrupt_handler(void *arg,unsigned int v, unsigned int g)
{
	short dma_status=0x0;
	ADI_DCB_RESULT result;


	// NO DMA in action. May be spurious interrupt.
	if(dev->m_dma_protect == 0)
	{
		num_dma_protect_zeros++;
		return;
	}

	ENTER_CRITICAL_REGION();

	// set destination config register
	SET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_CONFIG),(unsigned short)0x0);
	ssync();
	// set source config register
	SET_VAL_SHORT((dev->SrcStreamBaseAddr+OFFSET_CONFIG),(unsigned short)0x0);
	ssync();
	// get dma status register
	GET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_IRQ_STATUS),dma_status);

	// check for the dma complete.
	//
	if(dma_status & DMA_DONE)
	{
		dma_status |= DMA_DONE;
		// acknowledge DMA  completion
		SET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_IRQ_STATUS),dma_status);
	}
	// DMA error
	else if (dma_status & DMA_ERR)
	{
		dev->MemDmaErrorCount++;
		dma_status |= DMA_DONE;
		// acknowledge dma error
		SET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_IRQ_STATUS),dma_status);
	}
	ssync();

	switch(dev->m_dma_direction)
	{
		//
		// Transmit Complete
		//
		case DMA_DIR_TX:
				transmit_complete();
     			if (dev->DCBHandle != NULL) 
				{
				 	result = adi_dcb_Post(dev->DCBHandle,0,dev->DMCallback,dev->DeviceHandle,ADI_ETHER_EVENT_FRAME_XMIT,dev->m_TxDequeuedHead->CallbackParameter);
     			}
				else 
				{
			     	(dev->DMCallback)(dev->DeviceHandle,ADI_ETHER_EVENT_FRAME_XMIT,dev->m_TxDequeuedHead->CallbackParameter);
			     	result = ADI_DCB_RESULT_SUCCESS;
     			}
				if (result == ADI_DCB_RESULT_SUCCESS) 
				{
				//## what happens if a packet is trasnmitted while in the callback
			        dev->m_TxDequeuedHead = NULL;
			  		dev->m_TxDequeuedTail = NULL;
					dev->m_TxDequeuedCount = 0;
				}
				break;
		//
		// Receive Complete
		//
		case DMA_DIR_RX:
			receive_complete();
			if (dev->m_RxDequeuedHead != NULL) 
			{
				if (dev->DCBHandle!=NULL) 
				{
	            	result = adi_dcb_Post(dev->DCBHandle,0,dev->DMCallback,dev->DeviceHandle,ADI_ETHER_EVENT_FRAME_RCVD,dev->m_RxDequeuedHead->CallbackParameter);
				} 
				else 
				{
					(dev->DMCallback)(dev->DeviceHandle,ADI_ETHER_EVENT_FRAME_RCVD,dev->m_RxDequeuedHead->CallbackParameter);
			     	result = ADI_DCB_RESULT_SUCCESS;
				}
				if (result == ADI_DCB_RESULT_SUCCESS) 
				{
					//## what happens if a packet is received while in the callback
	            	dev->m_RxDequeuedHead = NULL;
	      			dev->m_RxDequeuedTail = NULL;
		  			dev->m_RxDequeuedCount = 0;  
				}
			}
			break;
		//
		// default
		//
		default:
			break;
	} // switch end

	dev->m_dma_protect = 0;
	dev->m_dma_direction = DMA_NONE;
	ssync();

	EXIT_CRTICIAL_REGION();
}

/******************************************************************************
 * Trasfer  num_bytes from source address to the destination address
 *
 *****************************************************************************/
void dma_initiate_transfer(unsigned long src_addr, unsigned long des_addr,
						   unsigned long num_bytes,DMA_DIRECTION dir)
{
	unsigned short 	dma_config_source;
	unsigned short 	dma_config_destination;
	unsigned short 	d0_x_modify, s0_x_modify;

	ENTER_CRITICAL_REGION();

	if(dir == DMA_DIR_TX) {
		d0_x_modify = 0; // auto increment, same port.
		s0_x_modify = DMA_WORD_SIZE;
	} else {	
		d0_x_modify = DMA_WORD_SIZE;
		s0_x_modify = 0; // auto inrement, same port.
	}

	// configure the source address register
	SET_VAL_ADDR((dev->SrcStreamBaseAddr+OFFSET_START_ADDR),src_addr);
	ssync();
	// configure number of bytes to send at the source end
	SET_VAL_SHORT((dev->SrcStreamBaseAddr+OFFSET_X_COUNT),(unsigned short)num_bytes);
	ssync();
	// configure modify at the source end
	SET_VAL_SHORT((dev->SrcStreamBaseAddr+OFFSET_X_MODIFY),(unsigned short)s0_x_modify);
	ssync();

	// configure destination address register
	*pMDMA_D0_START_ADDR =	(volatile void*)des_addr;
	ssync();

	//configure destination x_count register
	SET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_X_COUNT),(unsigned short)num_bytes);
	ssync();
	// configure destiantion x_modify register
	SET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_X_MODIFY),(unsigned short)d0_x_modify);
	ssync();

	// Configure source DMA config register, enable bit set, and transfer
	// size if 16 bits.
	//
	dma_config_source = (WDSIZE_16 | DMAEN);
	SET_VAL_SHORT((dev->SrcStreamBaseAddr+OFFSET_CONFIG),(unsigned short)dma_config_source);
	ssync();

	// Configure destination config register, enable DMA, transfer size 16
	// bits and enable DMA completion interrupt
	//
	dma_config_destination = (DI_EN | WDSIZE_16 | DMAEN | WNR); 
	ssync();
	// DMA transfer starts here.
	SET_VAL_SHORT((dev->DstStreamBaseAddr+OFFSET_CONFIG),(unsigned short)dma_config_destination);
	ssync();
	csync();
	EXIT_CRTICIAL_REGION();

}

⌨️ 快捷键说明

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