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

📄 cs8900.c

📁 基于ARM的CS8900的驱动程序
💻 C
字号:
/****************************************************************************
【文  件  名  称】CS8900.c
【功  能  描  述】FS2410XP教学平台实验程序
【程  序  版  本】3.0
【创建及创建日期】优龙公司/2005-XX-XX
【修改及修改日期】2005-5-23
****************************************************************************/
//头文件定义
#include "cs8900.h"
#include "..\INC\board.h"

#ifdef	TFTP_DOWNLOAD_SUPPORT

#define	IO_BASE_ADDR	0x19000300		//CS8900的基址

static  U8 OurEmacAddr[ETH_ALEN] = {0x00,0x80,0x48,0x12,0x34,0x56};	//MAC地址

#define PUBLIC
#define PRIVATE						static

#define IOREAD(o)					((USHORT)*((volatile USHORT *)(dwEthernetIOBase + (o))))
#define IOWRITE(o, d)				*((volatile USHORT *)(dwEthernetIOBase + (o))) = (USHORT)(d)

#define MEMREAD(o)					((USHORT)*((volatile USHORT *)(dwEthernetMemBase + (o))))
#define MEMWRITE(o, d)				*((volatile USHORT *)(dwEthernetMemBase + (o))) = (USHORT)(d)

//#define	DEBUG
#ifdef	DEBUG
#define	DBGMSG						printf
#else
#define DBGMSG(...)
#endif
#define MAX_COUNT					0x100000

#define CS8900DBG_PROBE				(1 << 0)

PRIVATE DWORD dwEthernetIOBase;
PRIVATE DWORD dwEthernetMemBase;

//#define CS8900_MEM_MODE

#ifdef	CS8900_MEM_MODE

#define READ_REG1					ReadReg
#define READ_REG2					MEMREAD

#define WRITE_REG1					WriteReg
#define WRITE_REG2					MEMWRITE

#else

#define READ_REG1					ReadReg
#define READ_REG2					ReadReg

#define WRITE_REG1					WriteReg
#define WRITE_REG2					WriteReg

#endif

PRIVATE	BOOL bIsPacket;

/********************************************************************
Function name: ReadReg
Parameter    : offset:CS8900的偏移地址
Description	 : 读CS8900的寄存器
Return		 : void
Argument     : 
Autor & date :
*********************************************************************/
PRIVATE USHORT 

ReadReg(USHORT offset)
{
	IOWRITE(IO_PACKET_PAGE_POINTER, offset);
	return IOREAD(IO_PACKET_PAGE_DATA_0);
}

/********************************************************************
Function name: WriteReg
Parameter    : offset:CS8900的偏移地址
Description	 : 写CS8900的寄存器
Return		 : void
Argument     : 
Autor & date :
*********************************************************************/
PRIVATE void 
WriteReg(USHORT offset, USHORT data)
{
	IOWRITE(IO_PACKET_PAGE_POINTER, offset);
	IOWRITE(IO_PACKET_PAGE_DATA_0 , data);
}

/********************************************************************
Function name: CS8900_Probe
Parameter    : iobase : I/O模式下的CS8900的基址
			   membase: 内存模式下的CS8900的基址
Description	 : 检测CS8900器件
Return		 : 返回真或假,真: 网卡被探测到, 否则没有
Argument     : 
Autor & date :
*********************************************************************/
PRIVATE BOOL 
Probe(DWORD iobase, DWORD membase)
{
	BOOL r = FALSE;
	USHORT sig;

	DBGMSG("::: CS8900 Probe()\n");

	dwEthernetIOBase  = iobase;
	dwEthernetMemBase = membase;

	do 
	{
		sig = IOREAD(IO_PACKET_PAGE_POINTER);
//		sig = IOREAD(IO_PACKET_PAGE_POINTER);
		DBGMSG("sig=%x\n", sig);
		if ( (sig & CS8900_SIGMSK) != CS8900_SIGNATURE)
		{
			DBGMSG("Signature Error\n");
			DBGMSG("%x\n", sig);
		//	DBGMSG("%x\n", IOREAD(IO_PACKET_PAGE_POINTER));
			break;
		}
		
		/* Check the EISA registration number.	*/
		sig = READ_REG1(PKTPG_EISA_NUMBER);
		DBGMSG("eisa=%x\n", sig);
		if (sig != CS8900_EISA_NUMBER)
		{
			DBGMSG("Eisa Number Error\n");
			DBGMSG("%x\n", sig);
			break;
		}
		
		/* Check the Product ID.				*/
		sig = READ_REG1(PKTPG_PRDCT_ID_CODE);
		DBGMSG("PID=%x\n", sig);
		if ((sig & CS8900_PRDCT_ID_MASK)
			!= CS8900_PRDCT_ID)
		{
			DBGMSG("Product ID Error\n");
			break;
		}
	   
		DBGMSG("CS8900 is Detected..\n");
		r = TRUE;
	} while (0);

	return r;
}


/********************************************************************
Function name: CS8900_Reset
Parameter    : void
Description	 : 复位CS8900
Return		 : 返回真(TRUE)或假(FALSE),TRUE:复位成功,否则没有
Argument     : 
Autor & date :
*********************************************************************/
PRIVATE BOOL 
CS8900_Reset(void)
{
	BOOL r = FALSE;
	USHORT dummy;
	int i;
											/* Set RESET bit of SelfCTL register.	*/
	do 
	{
		WRITE_REG1(PKTPG_SELF_CTL, SELF_CTL_RESET | SELF_CTL_LOW_BITS);

								/* Wait until INITD bit of SelfST register is set.	*/
		for (i = 0; i < MAX_COUNT; i++)
		{
			dummy = READ_REG1(PKTPG_SELF_ST);
			if (dummy & SELF_ST_INITD) break;
		}

		if (i >= MAX_COUNT)
		{
			DBGMSG("Reset failed (SelfST) \n");
			break;
		}

						/* Wait until SIBUSY bit of SelfST register is cleared.		*/
		for (i = 0; i < MAX_COUNT; i++)
		{
			dummy = READ_REG1(PKTPG_SELF_ST);
			if ((dummy & SELF_ST_SIBUSY) == 0) break;
		}

		if (i >= MAX_COUNT)
		{
			DBGMSG("Reset failed (SIBUSY) \n");
			break;
		}
		r = TRUE;
		DBGMSG("Reset Success!!\n");

	} while (0);

	return r;
}

/********************************************************************
Function name: EnableIRQ
Parameter    : void
Description	 : 使能CS8900的中断
Return		 : void
Argument     : 返回真(TRUE)或假(FALSE),TRUE:初始化成功,否则没有
Autor & date :
*********************************************************************/
PRIVATE void 
EnableIRQ(void)
{
	USHORT temp;
						/* If INTERRUPT_NUMBER is 0,							*/
						/*	Interrupt request will be generated from INTRQ0 pin */
	WRITE_REG2(PKTPG_INTERRUPT_NUMBER, INTERRUPT_NUMBER);

	temp = READ_REG2(PKTPG_BUS_CTL) | BUS_CTL_ENABLE_IRQ;

	WRITE_REG2(PKTPG_BUS_CTL, temp);

	temp = READ_REG2(PKTPG_LINE_CTL) | LINE_CTL_RX_ON | LINE_CTL_TX_ON;
	WRITE_REG2(PKTPG_LINE_CTL,temp);
}

/********************************************************************
Function name: Init
Parameter    : *mac:网卡的物理地址
Description	 : 初始化CS8900的相关寄存器
Return		 : 
Argument     : 
Autor & date :
*********************************************************************/
PRIVATE BOOL 
Init(USHORT *mac)
{
	USHORT temp;

#ifdef CS8900_MEM_MODE

	WRITE_REG1(PKTPG_MEMORY_BASE_ADDR     , (USHORT)(dwEthernetMemBase & 0xffff));
	WRITE_REG1(PKTPG_MEMORY_BASE_ADDR + 2 , (USHORT)(dwEthernetMemBase >> 16   ));
	WRITE_REG1(PKTPG_BUS_CTL              ,  BUS_CTL_MEMORY_E | BUS_CTL_LOW_BITS);

#endif

	temp = READ_REG2(PKTPG_LINE_CTL) | LINE_CTL_10_BASE_T | LINE_CTL_MOD_BACKOFF;
	WRITE_REG2(	PKTPG_LINE_CTL, temp);
						
	WRITE_REG2(PKTPG_RX_CFG, RX_CFG_RX_OK_I_E | RX_CFG_LOW_BITS);

	WRITE_REG2(PKTPG_RX_CTL,
		            RX_CTL_RX_OK_A | RX_CTL_IND_ADDR_A | RX_CTL_BROADCAST_A | RX_CTL_LOW_BITS);

	WRITE_REG2(PKTPG_INDIVISUAL_ADDR + 0, *mac++);
	WRITE_REG2(PKTPG_INDIVISUAL_ADDR + 2, *mac++);
	WRITE_REG2(PKTPG_INDIVISUAL_ADDR + 4, *mac  );

	WRITE_REG2(PKTPG_TX_CFG, TX_CFG_LOW_BITS);

	EnableIRQ();
			
	DBGMSG("CS8900_Init OK.\n");
	return TRUE;
}

/********************************************************************
Function name: RcvPkt
Parameter    : *pbData  :待存放接收数据的缓冲区数组
			   dwLength :可接收的最大数据长度
Description	 : 接收网络数据
Return		 : 返回接收的数据的长度
Argument     : 
Autor & date :
*********************************************************************/
PRIVATE int
RcvPkt(BYTE *pbData, DWORD dwLength)
{
/* use int rather than short for the reason of performance	*/
	DWORD   length;
	DWORD   rlen = 0;
	USHORT  *bp;
	USHORT	data;
	//unsigned char *Rcvdate;

		/* Discard RxStatus		*/
	data   = IOREAD(IO_RX_TX_DATA_0);/* Read the frame's length.		*/
	length = IOREAD(IO_RX_TX_DATA_0);

	if (length > dwLength) 
	length = 0;
	bp= (USHORT *)pbData;
	rlen = length;
	//printf("This is receive date:\n");
	while (rlen)
	{	
		data = IOREAD(IO_RX_TX_DATA_0);
		if (rlen == 1)
		  {
			*((BYTE *)bp) = (BYTE)data;
		  	rlen--;
		  }
		else
		  {
		  //8888888888888888888888888888888888888888888888
		  	//Rcvdate = (unsigned char *)&data;		//测试和显示接收数据
		  	//printf("(%x.%x)", Rcvdate[0], Rcvdate[1]);
		  //8888888888888888888888888888888888888888888888
			*bp++ = data;
			rlen -= 2;
		  }
	}
	//printf("\n 6666666666666666666666666666666666666666666 \n");
	return length;
}


/********************************************************************
Function name: TransmitPkt
Parameter    : *pbData  :要发送数据的缓冲区数组
			   slen	    :要发送数据的长度
Description	 : 向网络发送数据
Return		 : 返回0,成功
Argument     : 
Autor & date :
*********************************************************************/
PRIVATE USHORT 
TransmitPkt(BYTE *pbData, USHORT slen)
{
	USHORT * bp;
	USHORT   data;
	DWORD	 i;
//	unsigned char *senddate;
	
	/* Send Command */
	IOWRITE(IO_TX_CMD, TX_CMD_START_ALL | TX_CMD_LOW_BITS);
	IOWRITE(IO_TX_LENGTH, slen);

	/* Wait			*/
	for (i = 0; i < MAX_COUNT; i++)
	{
		data = READ_REG2(PKTPG_BUS_ST);
		if (data & BUS_ST_RDY_4_TX_NOW) break;
	} 

	if (i >= MAX_COUNT) return 1;

	bp = (USHORT *)pbData;
	//printf("This is send date:\n");
	while (slen)
	{			
	//8888888888888888888888888888888888888888888888
	//	 senddate = (unsigned char *)&(*bp);		//测试和显示发送数据
	//	 printf("(%x.%x)",senddate[0], senddate[1]);
	//8888888888888888888888888888888888888888888888
		IOWRITE(IO_RX_TX_DATA_0, *bp++);
		slen--;	
		if (slen) slen--;		
	}
	//printf("\n 8888888888888888888888888888888888888888888888 \n");
	return 0;
}

/********************************************************************
Function name: CS8900DBG_IsReceivedPacket
Parameter    : void
Description	 : 检测是否有数据到来,如果有,通知接收程序准备接收
Return		 : 返回真(TRUE)或假(FALSE),TRUE:有数据,否则没有
Argument     : 
Autor & date :
*********************************************************************/
PUBLIC BOOL
CS8900DBG_IsReceivedPacket(void)
{
	USHORT event;
	BOOL   r = FALSE;
	event = IOREAD(IO_ISQ);
//	DBGMSG("%x\n", event);
	if ( ((event & ISQ_REG_NUM   )    == REG_NUM_RX_EVENT ) &&
		 ((event & RX_EVENT_RX_OK)    == RX_EVENT_RX_OK   ) &&
		 ((event & RX_EVENT_IND_ADDR) | (event & RX_CTL_BROADCAST_A))) 
	{
		r = bIsPacket = TRUE;
//		DBGMSG("%x\n", event);
	}
	else
		bIsPacket = FALSE;
	return r;
}

/********************************************************************
Function name: board_eth_init
Parameter    : void
Description	 : 网络初始化函数,用来设置CS8900的MAC地址和工作模式
Return		 : 返回0或非0,0:初始化成功,否则不成功
Argument     : 探测CS8900,复位CS8900以及初始化CS8900
Autor & date :
*********************************************************************/
int board_eth_init(void)
{	
	int r;

	bIsPacket = FALSE;
    
    DBGMSG("::: CS8900DBG_Init\r\n");//输出调试信息
    
	DBGMSG("CS8900 Mac Address: %x:%x:%x:%x:%x:%x\r\n",
			  OurEmacAddr[0], OurEmacAddr[1],
			  OurEmacAddr[2], OurEmacAddr[3],
			  OurEmacAddr[4], OurEmacAddr[5]);//设置物理地址
	r = -1;
    do {
		if (!Probe(IO_BASE_ADDR, 0))		break;//检测CS8900,获得相关信息
		if (!CS8900_Reset())				break;//复位CS8900
		if (!Init((USHORT *)OurEmacAddr))	break;//初始化CS8900
		r = 0;
	} while (0);
	return r;
}

/********************************************************************
Function name: board_eth_lnk_stat
Parameter    : void
Description	 : 联接函数
Return		 : 返回0或非0,0:初始化成功,否则不成功
Argument     : 
Autor & date :
*********************************************************************/
int board_eth_lnk_stat(void)
{
	return 0;
}


/********************************************************************
Function name: board_eth_send
Parameter    : *data:要发送数据的缓冲区指针
			   len  :要发送数据长度
Description	 : 发送数据,主要用来将上层传送过来的数据包发送出去
Return		 : 返回0,成功
Argument     : 
Autor & date :
*********************************************************************/
int board_eth_send(unsigned char *data, unsigned int len)

{		
	return TransmitPkt((BYTE *)data, len);//用来发送数据包
}

/********************************************************************
Function name: board_eth_rcv
Parameter    : *data:待存放接收数据的缓冲区指针,指向数据缓冲区的指针
			   len  :数据的最大长度
Description	 : 用于接收数据,将该数据包上传给IP层
Return		 : 如果有数据则返回0,没有数据则返回-1
Argument     : 
Autor & date :
*********************************************************************/
int board_eth_rcv(unsigned char *data, unsigned int *len)
{
	int r = -1;
	if(CS8900DBG_IsReceivedPacket()) //判断是否是需要接受包
	   {                                 
		U16 size;	
		bIsPacket = FALSE;
		size = RcvPkt((BYTE *)data, 1532);//CS8900接受包返回接收的数据的长度
		*len = size;
		r = 0;
		}
	return r;                       //没有数据就返回-1
}

/********************************************************************
Function name: board_eth_get_addr
Parameter    : *addr:待存放MAC地址的指针
Description	 : 获得MAC地址
Return		 : 返回0,成功
Argument     : 
Autor & date :
*********************************************************************/
int board_eth_get_addr(unsigned char *addr)
{
	memcpy(addr, OurEmacAddr, ETH_ALEN);
	return 0;
}

#endif
/********************************************************************/

⌨️ 快捷键说明

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