emac.c revision 199767f8919635c4928607450d9e0abb932109ce
/*******************************************************************************
*
* Filename: emac.c
*
*
* Revision information:
*
* 28AUG2004 kb_admin initial creation
* 08JAN2005 kb_admin added tftp download
* also adapted from external sources
*
* BEGIN_KBDD_BLOCK
* No warranty, expressed or implied, is included with this software. It is
* provided "AS IS" and no warranty of any kind including statutory or aspects
* relating to merchantability or fitness for any purpose is provided. All
* intellectual property rights of others is maintained with the respective
* owners. This software is not copyrighted and is intended for reference
* only.
* END_BLOCK
*
* $FreeBSD$
******************************************************************************/
#include "at91rm9200.h"
#include "at91rm9200_lowlevel.h"
#include "emac.h"
#include "lib.h"
/* ****************************** GLOBALS *************************************/
static receive_descriptor_t *p_rxBD;
static unsigned short localPort;
static unsigned short serverPort;
static unsigned serverMACSet;
static unsigned localIPSet, serverIPSet;
static unsigned lastSize;
static unsigned char serverMACAddr[6];
static int ackBlock;
static char *dlAddress;
static unsigned transmitBuffer[1024 / sizeof(unsigned)];
static unsigned tftpSendPacket[256 / sizeof(unsigned)];
/*
* .KB_C_FN_DEFINITION_START
* unsigned short IP_checksum(unsigned short *p, int len)
* This private function calculates the IP checksum for various headers.
* .KB_C_FN_DEFINITION_END
*/
static unsigned short
IP_checksum(unsigned short *p, int len)
{
unsigned i, t;
len &= ~1;
for (i=0,t=0; i<len; i+=2, ++p)
t += SWAP16(*p);
t = (t & 0xffff) + (t >> 16);
return (~t);
}
/*
* .KB_C_FN_DEFINITION_START
* void GetServerAddress(void)
* This private function sends an ARP request to determine the server MAC.
* .KB_C_FN_DEFINITION_END
*/
static void
GetServerAddress(void)
{
// wait until transmit is available
while (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ))
continue;
*AT91C_EMAC_TAR = (unsigned)transmitBuffer;
*AT91C_EMAC_TCR = 0x40;
}
/*
* .KB_C_FN_DEFINITION_START
* void Send_TFTP_Packet(char *tftpData, unsigned tftpLength)
* This private function initializes and send a TFTP packet.
* .KB_C_FN_DEFINITION_END
*/
static void
{
unsigned t_checksum;
while (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ))
continue;
*AT91C_EMAC_TAR = (unsigned)tftpSendPacket;
}
/*
* .KB_C_FN_DEFINITION_START
* void TFTP_RequestFile(char *filename)
* This private function sends a RRQ packet to the server.
* .KB_C_FN_DEFINITION_END
*/
static void
TFTP_RequestFile(char *filename)
{
unsigned length;
length += 2;
}
/*
* .KB_C_FN_DEFINITION_START
* void TFTP_ACK_Data(char *data, unsigned short block_num, unsigned short len)
* This private function sends an ACK packet to the server.
* .KB_C_FN_DEFINITION_END
*/
static void
{
++ackBlock;
if (ackBlock % 128 == 0)
}
if (len < 512) {
ackBlock = -2;
}
}
/*
* .KB_C_FN_DEFINITION_START
* void CheckForNewPacket(ip_header_t *pHeader)
* This private function polls for received ethernet packets and handles
* any here.
* .KB_C_FN_DEFINITION_END
*/
static int
{
unsigned short *pFrameType;
unsigned i;
char *pData;
int process = 0;
process = 0;
for (i = 0; i < MAX_RX_PACKETS; ++i) {
process = 1;
(*AT91C_EMAC_RSR) |= (*AT91C_EMAC_RSR);
break;
}
}
if (!process)
return (0);
process = i;
switch (*pFrameType) {
case SWAP16(PROTOCOL_ARP):
// check if new server info is available
if ((!serverMACSet) &&
(char*)serverIPAddr, 4)))) {
serverMACSet = 1;
}
// ARP REPLY operation
// Fill the dest address and src address
for (i = 0; i <6; i++) {
// swap ethernet dest address and ethernet src address
// swap sender ethernet address and target ethernet address
}
// swap sender IP address and target IP address
for (i = 0; i<4; i++) {
}
if (!(*AT91C_EMAC_TSR & AT91C_EMAC_BNQ)) break;
*AT91C_EMAC_TAR = (unsigned)pData;
*AT91C_EMAC_TCR = 0x40;
}
break;
case SWAP16(PROTOCOL_IP):
break;
break;
if (ackBlock == -1) {
break;
ackBlock = 0;
}
break;
}
}
return (1);
}
/*
* .KB_C_FN_DEFINITION_START
* unsigned short AT91F_MII_ReadPhy (AT91PS_EMAC pEmac, unsigned char addr)
* This private function reads the PHY device.
* .KB_C_FN_DEFINITION_END
*/
#ifndef BOOT_BWCT
static unsigned short
{
}
#endif
/*
* .KB_C_FN_DEFINITION_START
* unsigned short AT91F_MII_WritePhy (AT91PS_EMAC pEmac, unsigned char addr, unsigned short s)
* This private function writes the PHY device.
* .KB_C_FN_DEFINITION_END
*/
#ifdef BOOT_TSC
static unsigned short
{
}
#endif
/*
* .KB_C_FN_DEFINITION_START
* void MII_GetLinkSpeed(AT91PS_EMAC pEmac)
* This private function determines the link speed set by the PHY.
* .KB_C_FN_DEFINITION_END
*/
static void
{
unsigned short stat2;
#endif
unsigned update;
#ifdef BOOT_TSC
unsigned sec;
int i;
#endif
#ifdef BOOT_BWCT
/* hardcoded link speed since we connect a switch via MII */
update |= AT91C_EMAC_SPD;
update |= AT91C_EMAC_FD;
#endif
#if defined(BOOT_KB920X) || defined(BOOT_CENTIPAD)
if (!(stat2 & MII_STS2_LINK))
return ;
if (stat2 & MII_STS2_100TX)
update |= AT91C_EMAC_SPD;
if (stat2 & MII_STS2_FDX)
update |= AT91C_EMAC_FD;
#endif
#ifdef BOOT_TSC
while (1) {
for (i = 0; i < 10; i++) {
if (stat2 & MII_STS_LINK_STAT)
break;
printf(".");
sec = GetSeconds();
while (GetSeconds() == sec)
continue;
}
if (stat2 & MII_STS_LINK_STAT)
break;
printf("Resetting MII...");
}
printf("emac: link");
printf(" 100TX");
update |= AT91C_EMAC_SPD;
}
printf(" FDX");
update |= AT91C_EMAC_FD;
}
printf("\n");
#endif
}
/*
* .KB_C_FN_DEFINITION_START
* void AT91F_EmacEntry(void)
* This private function initializes the EMAC on the chip.
* .KB_C_FN_DEFINITION_END
*/
static void
AT91F_EmacEntry(void)
{
unsigned i;
char *pRxPacket = (char*)RX_DATA_START;
for (i = 0; i < MAX_RX_PACKETS; ++i) {
}
// Set the WRAP bit at the end of the list descriptor
}
/* ************************** GLOBAL FUNCTIONS ********************************/
/*
* .KB_C_FN_DEFINITION_START
* void SetServerIPAddress(unsigned address)
* This global function sets the IP of the TFTP download server.
* .KB_C_FN_DEFINITION_END
*/
void
SetServerIPAddress(unsigned address)
{
// force update in case the IP has changed
serverMACSet = 0;
serverIPSet = 1;
}
/*
* .KB_C_FN_DEFINITION_START
* void SetLocalIPAddress(unsigned address)
* This global function sets the IP of this module.
* .KB_C_FN_DEFINITION_END
*/
void
SetLocalIPAddress(unsigned address)
{
// force update in case the IP has changed
serverMACSet = 0;
localIPSet = 1;
}
/*
* .KB_C_FN_DEFINITION_START
* void TFTP_Download(unsigned address, char *filename)
* This global function initiates and processes a tftp download request.
* The server IP, local IP, local MAC must be set before this function is
* executed.
* .KB_C_FN_DEFINITION_END
*/
void
{
unsigned thisSeconds;
int timeout;
return ;
lastSize = 0;
timeout = 10;
++localPort;
ackBlock = -1;
while (timeout) {
if (CheckForNewPacket(&IpHeader)) {
if (ackBlock == -2)
break;
timeout = 10;
} else if (GetSeconds() == thisSeconds) {
--timeout;
if (!serverMACSet)
else if (ackBlock == -1)
else {
// Be sure to send a NAK, which is done by
// ACKing the last block we got.
}
}
}
if (timeout == 0)
printf("TFTP TIMEOUT!\n");
}