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" #includeextern 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; }