www.pudn.com > EBD9200EMAC.rar > Emac.c


//*---------------------------------------------------------------------------- 
//*         ATMEL Microcontroller Software Support  -  ROUSSET  - 
//*---------------------------------------------------------------------------- 
//* The software is delivered "AS IS" without warranty or condition of any 
//* kind, either express, implied or statutory. This includes without 
//* limitation any warranty or condition with respect to merchantability or 
//* fitness for any particular purpose, or against the infringements of 
//* intellectual property rights of others. 
//*---------------------------------------------------------------------------- 
//* File Name           : main.c 
//* Object              : main application written in C 
//* Creation            : Hi   11/18/2002 
//* 
//*---------------------------------------------------------------------------- 
#include "AT91RM9200.h" 
#include "lib_AT91RM9200.h" 
#include "Emac.h" 
#include  
 
extern unsigned int AT91F_GetTickCount(void); 
 
// Our Ethernet MAC address and IP address 
char OurEmacAddr[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; 
unsigned char OurIpAddr[4]  = {172, 17, 242, 132}; // {0x0A, 0xD7, 0xF5, 0xAC} 
 
//Buffer descriptor address must be word aligned 
#define AT91C_EMAC_TDLIST_BASE	0x20010000 
 
char RxPacket[NB_ETH_RX_PACKETS*ETH_PACKET_SIZE]; 
AT91PS_TdDescriptor tdList = (AT91PS_TdDescriptor)AT91C_EMAC_TDLIST_BASE; 
 
 
 
// **************************************************************************************************** 
// ** EMAC lowlevel functions  
// **************************************************************************************************** 
//*---------------------------------------------------------------------------- 
//* \fn    AT91F_MII_ReadPhy 
//* \brief This function return the MII phy register 
//*---------------------------------------------------------------------------- 
unsigned short AT91F_MII_ReadPhy( 
	AT91PS_EMAC pEmac,     // \arg Pointer to AT91PS_EMAC service 
	unsigned char addr)  
{ 
	unsigned int Wait = AT91F_GetTickCount() + 10; 
	unsigned int value = 0x60020000 | (addr << 18); 
 
	pEmac->EMAC_MAN = value; 
  	while(AT91F_GetTickCount() < Wait); 
	return (pEmac->EMAC_MAN & 0x0000ffff); 
} 
 
 
 
//*---------------------------------------------------------------------------- 
//* \fn    AT91F_MII_GetLinkSpeed 
//* \brief This function configure the link speed 
//*---------------------------------------------------------------------------- 
int MII_GetLinkSpeed(AT91PS_EMAC pEmac)     // \arg Pointer to AT91PS_EMAC service 
{ 
  unsigned short stat1, stat2;  
   
	stat1 = AT91F_MII_ReadPhy(pEmac, MII_STS_REG); 
	stat1 = AT91F_MII_ReadPhy(pEmac, MII_STS_REG); 
 
	stat2 = AT91F_MII_ReadPhy(pEmac, MII_STS2_REG); 
     
    //set MII for 100BaseTX and Full Duplex 
	if ((stat1 & 0x4000) && (stat2 & 0x8000) ) 
    	pEmac->EMAC_CFG |= (AT91C_EMAC_SPD| AT91C_EMAC_FD);     
    //set MII for 10BaseT and Full Duplex  
	else if ((stat1 & 0x1000) && (stat2 & 0x2000)) 
    	pEmac->EMAC_CFG = (pEmac->EMAC_CFG & AT91C_EMAC_SPD) | AT91C_EMAC_FD; 
    //set MII for 100BaseTX and Half Duplex  
	else if ((stat1 & 0x2000) && (stat2 & 0x4000)) 
    	pEmac->EMAC_CFG = (pEmac->EMAC_CFG | AT91C_EMAC_SPD ) & ~AT91C_EMAC_FD; 
    //set MII for 10BaseT and Half Duplex  
	else if ((stat1 & 0x0800) && (stat2 & 0x1000)) 
    	pEmac->EMAC_CFG = pEmac->EMAC_CFG & ~AT91C_EMAC_SPD & ~AT91C_EMAC_FD; 
 
	return 0; 
} 
 
//*---------------------------------------------------------------------------- 
//* \fn    AT91F_MDIO_StartupPhy 
//* \brief This function start the phy 
//*---------------------------------------------------------------------------- 
int AT91F_MDIO_StartupPhy(AT91PS_EMAC pEmac)     // \arg Pointer to AT91PS_EMAC service 
{ 
	int ret; 
	if(pEmac->EMAC_SR & AT91C_EMAC_LINK) 
		return 0; 
 
	pEmac->EMAC_CTL |= AT91C_EMAC_MPE; 
 
	ret = MII_GetLinkSpeed(pEmac); 
 
	pEmac->EMAC_CTL &= ~AT91C_EMAC_MPE; 
   
	return 0; 
} 
 
 
//*---------------------------------------------------------------------------- 
//* \fn    AT91F_EMACInit 
//* \brief This function initialise the ethernet 
//*---------------------------------------------------------------------------- 
int AT91F_EMACInit( // \return Status ( Success = 0) 
		AT91PS_EMAC pEmac,     // \arg Pointer to AT91PS_EMAC service 
		unsigned int pTdList) 
{ 
	int status; 
	 
	AT91F_EMAC_CfgPMC(); 
	AT91F_EMAC_CfgPIO(); 
 
	status = AT91F_MDIO_StartupPhy(pEmac); 
	if ( status ) 
		return status; 
 
	// the sequence write EMAC_SA1L and write EMAC_SA1H must be respected 
	pEmac->EMAC_SA1L = ((int)OurEmacAddr[2] << 24) | ((int)OurEmacAddr[3] << 16) | ((int)OurEmacAddr[4] << 8) | OurEmacAddr[5]; 
	pEmac->EMAC_SA1H = ((int)OurEmacAddr[0] << 8) | OurEmacAddr[1]; 
 
	pEmac->EMAC_RBQP = pTdList; 
	pEmac->EMAC_RSR  &= ~(AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA); 
	pEmac->EMAC_CFG  |= (AT91C_EMAC_CAF | AT91C_EMAC_NBC | AT91C_EMAC_RMII); 
	pEmac->EMAC_CFG  &= ~(AT91C_EMAC_CLK); 
	pEmac->EMAC_CTL  |= (AT91C_EMAC_TE | AT91C_EMAC_RE); 
 
 	return 0; 
} 
 
//*---------------------------------------------------------------------------- 
//* \fn    AT91F_EmacEntry 
//* \brief Initialise Emac to receive packets 
//*---------------------------------------------------------------------------- 
int AT91F_EmacEntry(void) 
{ 
	unsigned int i; 
	char *pRxPacket; 
	 
	pRxPacket = (char *)RxPacket; 
 
	// Initialise tdList descriptor. This descriptor must be WORD aligned 
	for (i = 0; i < NB_ETH_RX_PACKETS; ++i)  
	{ 
		tdList[i].addr = ((unsigned int) (pRxPacket + (i * ETH_PACKET_SIZE))) & 0xFFFFFFFC; 
		tdList[i].size = 0; 
	} 
	 
	// Set the WRAP bit at the end of the list descriptor 
	tdList[NB_ETH_RX_PACKETS-1].addr |= 0x02; 
	 
	return(AT91F_EMACInit(AT91C_BASE_EMAC, (unsigned int) tdList)); 
}	 
 
 
 
//*---------------------------------------------------------------------------- 
//* \fn    AT91F_IcmpChksum 
//* \brief Process ICMP Checksum... 
//*---------------------------------------------------------------------------- 
unsigned short AT91F_IcmpChksum(unsigned short *p, int len)  
{ 
	int i, t; 
	 
	for (i=0,t=0; i> 16); 
	return (~t);									 
} 
 
 
 
//*---------------------------------------------------------------------------- 
//* \fn    AT91F_ProcessEmacPacket 
//* \brief Process ARP and ICMP packets... 
//*---------------------------------------------------------------------------- 
int AT91F_ProcessEmacPacket(AT91PS_IPheader pHeader) 
{ 
	unsigned short *pFrameType, *pArpOp; 
	unsigned int i, icmp_len; 
	char *pData; 
	int status = AT91C_NO_IPPACKET; 
	 
	AT91PS_IPheader pIpHeader; 
	AT91PS_IcmpEchoHdr pIcmpEcho; 
	int process = 0; 
	 
 
	// Receive one packet		 
	process = 0;	 
	status = 0; 
	for (i = 0; i < NB_ETH_RX_PACKETS; ++i) {				 
		if(tdList[i].addr & 0x1) { 
			if (*AT91C_EMAC_RSR & AT91C_EMAC_REC) 
				(*AT91C_EMAC_RSR) |= AT91C_EMAC_REC; 
			process = 1;	 
			break;				 
		} 
	} 
		 
	if (!process) 
		return AT91C_NO_IPPACKET; 
						 
	process = i; 
		 
	// Process this packet 
	pFrameType = (unsigned short *) ((tdList[i].addr & 0xFFFFFFFC) + 12); 
	pData      = (char *)(tdList[i].addr & 0xFFFFFFFC); 
 
	switch (SWAP16(*pFrameType)) { 
	case PROT_ARP: // ARP Packet format 
		pArpOp = (unsigned short *) (pData + 20); 
 
		if (SWAP16(*pArpOp) == ARP_REQUEST) { 
		       // ARP REPLY operation 
			*pArpOp =  SWAP16(ARP_REPLY);				 
			// Fill the dest address and src address 
			for (i = 0; i <6; i++) { 
				// swap ethernet dest address and ethernet src address 
				pData[i] = pData[i+6]; 
				pData[i+6] = OurEmacAddr[i]; 
				// swap sender ethernet address and target ethernet address 
				pData[i+22] = OurEmacAddr[i]; 
				pData[i+32] = pData[i+6]; 
			}									 
				// swap sender IP address and target IP address 
			for (i = 0; i<4; i++) {				 
				pData[i+38] = pData[i+28]; 
				pData[i+28] = OurIpAddr[i]; 
			} 
				 
			if (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) 
				return AT91C_NO_IPPACKET; 
		  	*AT91C_EMAC_TSR |= AT91C_EMAC_COMP; 
			*AT91C_EMAC_TAR = (unsigned int)pData; 
 			*AT91C_EMAC_TCR = 0x40; 
		}			 
	break; // case PROT_ARP 
		 
	case PROT_IP:	// IP protocol frame 
		pIpHeader = (AT91PS_IPheader)(pData + 14);			 
		pIcmpEcho = (AT91PS_IcmpEchoHdr)((char *)pIpHeader + 20); 
		memcpy(pHeader, pIpHeader,sizeof(AT91S_IPheader)); 
 
#if AT91C_DISPLAY_ALL_IPHEADER 
		status = AT91C_IPPACKET; 
#endif		 
		 
		switch(pIpHeader->ip_p) { 
		case PROT_ICMP:		 
			// set the status variable to display in main.c only ICMP packets 
			status = AT91C_IPPACKET; 
				 
			// if ICMP_ECHO_REQUEST ==> resp = ICMP_ECHO_REPLY 
			if(pIcmpEcho->type == ICMP_ECHO_REQUEST) { 
				pIcmpEcho->type = ICMP_ECHO_REPLY; 
				pIcmpEcho->code = 0; 
				pIcmpEcho->cksum = 0; 
 
				// Checksum of the ICMP Message				 
				icmp_len = (SWAP16(pIpHeader->ip_len) - 20)/(sizeof(unsigned short)); 
			    pIcmpEcho->cksum = SWAP16(AT91F_IcmpChksum((unsigned short *) pIcmpEcho, icmp_len)); 
					 
				// Swap IP Dest address and IP Source address 
				for(i = 0; i <4; i++) { 
					pIpHeader->ip_dst[i] = pIpHeader->ip_src[i]; 
					pIpHeader->ip_src[i] = OurIpAddr[i]; 
				} 
 
				// Swap Eth Dest address and Eth Source address 
				for(i = 0; i <6; i++) { 
					pData[i] = pData[i + 6]; 
					pData[i+6] = OurEmacAddr[i]; 
				} 
					// send the echo_reply 
			  	*AT91C_EMAC_TSR |= AT91C_EMAC_COMP; 
				*AT91C_EMAC_TAR = (unsigned int)pData; 
				*AT91C_EMAC_TCR = SWAP16(pIpHeader->ip_len)+ 14; 
			} 
		break; // case PROT_ICMP 
 
		default: 
			break; 
		} 
	break; // case PROT_IP 
						 
	default: 
		break; 
	}// switch (SWAP16(*pFrameType)) 
	// process the packet 
	tdList[process].addr &= ~0x01; 
	return status; 
}