www.pudn.com > zlIP-8051-rtl8019as.zip > RTL8019.c


/* 
 * Copyright (c) 2003 Electronic Engineering department of NAN KAI university 
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met: 
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 * 3. The name of the author may not be used to endorse or promote products 
 *    derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE. 
 * 
 * Author: zlin  
 * 
 */ 
#include "..\GloblDef\GloblDef.h" 
#include "..\TCPIP\TCPIPmem.h" 
#include "..\Netif\RTL8019.h" 
 
/* to prevent call RTLSendPacket() when RTLSendPackt() is already is called, InSending 
is used. example when process run in RTLSendPacket() and a interrupt ocurr then call  
RTLSendPacket again, then the Register would have changed when interrupt return. */ 
static BYTE DT_XDATA InSending; 
 
sbit reset8019=P3^4; 
void rtl8019as_rst(); 
 
 
void rtl8019as_rst() 
{ 
   unsigned int idata i; 
 
   reset8019=1;                                                          /*²ÉÓÃÀäÆô¶¯¸´Î» */ 
   for(i=0;i<250;i++); 
   reset8019=0; 
   for(i=0;i<250;i++); 
} 
 
 
 
static BYTE DT_XDATA StartPageOfPacket; 
/* receive head information */ 
/*struct RTLReceiveHeader 
{ 
	BYTE ReceiveStatus; 
	BYTE NextPacketStartPage; 
	BYTE PacketSizeLow; 
	BYTE PacketSizeHigh; 
}Head;for some unknown resean Head must be a gloal value. */ 
static BYTE DT_XDATA Head[4];  
 
/* last trasmit start page */ 
static BYTE DT_XDATA LastSendStartPage; 
 
/* read rtl8019 register. port is reg address */ 
/*BYTE ReadReg(WORD port)  
{ 
	return *((BYTE xdata *)port); 
}*/ 
#define ReadReg(port) (*((BYTE DT_XDATA *)port)) 
 
/* write value to register */ 
/*void WriteReg(WORD port,BYTE value)  
{ 
	*((BYTE xdata *)port) = value; 
}*/ 
#define WriteReg(port,value) (*((BYTE DT_XDATA *)port) = value) 
 
/* select which page of register to use*/ 
/* TO DO:set bit 7-6 in CR, CR_TXP must be 0(if 1 the packet is retrasmit) */ 
#define RTLPage(Index) WriteReg(CR,(ReadReg(CR) & 0x3B)|(BYTE)(Index << 6)) 
 
/* reset rtl8019 and init registers, LocalMacAddr is MAC address */ 
void RTLInit(BYTE LocalMACAddr[]) REENTRANT_MUL 
{ 
	BYTE temp; 
	int i; 
	 
 
    rtl8019as_rst(); 
 
 
	/* after hardware reset a longdelay is necessary for rtl to self-initial */ 
	for(i=0; i < RTL_DELAY_AFTER_HARDWARE_RESET; i++);	 
	 
	/* reset: write to reset prot */ 
	temp = ReadReg(RESET_PORT); 
	WriteReg(RESET_PORT,temp); 
	 
	/* init RTL registers*/ 
	WriteReg(CR,(CR_PAGE0 | CR_ABORT_COMPLETE_DMA | CR_STOP_COMMAND)); /* set page0, stop command. command is stop after power up. */ 
 
	WriteReg(PSTART_WPAGE0,	RECEIVE_START_PAGE);	/* Pstart	*/ 
	WriteReg(PSTOP_WPAGE0,	RECEIVE_STOP_PAGE);		/* Pstop	*/ 
	WriteReg(BNRY_WPAGE0,		RECEIVE_START_PAGE);	/* BNRY		*/ 
	WriteReg(TPSR_WPAGE0,		SEND_START_PAGE0);	/* TPSR		*/ 
 
	WriteReg(RCR_WPAGE0,		0xCE);	/* RCR: refer to define of RCR in Rtl8019as.h */ 
	WriteReg(TCR_WPAGE0,		0xE0);	/* TCR: refer to define of TCR in Rtl8019as.h */ 
	WriteReg(DCR_WPAGE0,		0xC8);	/* DCR: refer to define of DCR in Rtl8019as.h */ 
 
	WriteReg(IMR_WPAGE0,0);				/* RTL recieve interrupt enabled */ 
	WriteReg(ISR_WPAGE0,		0xFF);	/* write FF to clear up all interrupt status */ 
 
	RTLPage(1); 
 
	WriteReg(CURR_WPAGE1,RECEIVE_START_PAGE + 1);	 
	 
	/* MAR0 */ 
	/*WriteReg(0x08,0x00);	 
	WriteReg(0x09,0x41); 
	WriteReg(0x0a,0x00); 
	WriteReg(0x0b,0x80); 
	WriteReg(0x0c,0x00); 
	WriteReg(0x0d,0x00); 
	WriteReg(0x0e,0x00); 
	WriteReg(0x0f,0x00);*/ 
 
	/* set phisical address */ 
	WriteReg(PRA0_WPAGE1,LocalMACAddr[0]); 
	WriteReg(PRA1_WPAGE1,LocalMACAddr[1]); 
	WriteReg(PRA2_WPAGE1,LocalMACAddr[2]); 
	WriteReg(PRA3_WPAGE1,LocalMACAddr[3]); 
	WriteReg(PRA4_WPAGE1,LocalMACAddr[4]); 
	WriteReg(PRA5_WPAGE1,LocalMACAddr[5]); 
 
	/* transimit start page */ 
	LastSendStartPage = SEND_START_PAGE0; 
	StartPageOfPacket = RECEIVE_START_PAGE + 1; 
 
	/* in the beginning, no packet is in sending */ 
	InSending = FALSE; 
 
	/* initial over, start command and receive */ 
	WriteReg(CR,(CR_PAGE0 | CR_ABORT_COMPLETE_DMA | CR_START_COMMAND)); 
} 
 
/* write buffer to rlt ram */ 
void RTLWriteRam(WORD address, WORD size, BYTE DT_XDATA * buff) REENTRANT_SIG 
{ 
	BYTE DT_XDATA *Endp; 
	BYTE PrePage;	/* store page */ 
	PrePage = ReadReg(CR); 
	RTLPage(0); 
	WriteReg(RSARH_WPAGE0,(BYTE)((address>>8)&0x00ff)); 
	WriteReg(RSARL_WPAGE0,(BYTE)address); 
	WriteReg(RBCRH_WPAGE0,(BYTE)((size>>8)&0x00ff)); 
	WriteReg(RBCRL_WPAGE0,(BYTE)size); 
	WriteReg(CR,(0x00 | CR_REMOTE_WRITE | CR_START_COMMAND)); 
	for(Endp = buff + size; buff < Endp;) 
	{ 
		WriteReg(REMOTE_DMA_PORT,*(buff++)); 
	} 
	/* complete dma */ 
	WriteReg(RBCRH_WPAGE0,0); 
	WriteReg(RBCRL_WPAGE0,0); 
	WriteReg(CR,((PrePage&0xC0) | CR_ABORT_COMPLETE_DMA | CR_START_COMMAND)); 
} 
 
/* read rlt ram data to buffer */ 
void RTLReadRam(WORD address,WORD size,BYTE DT_XDATA * buff) REENTRANT_MUL 
{ 
	BYTE DT_XDATA * Endp; 
	BYTE PrePage;	/* store page */ 
	 
	PrePage = ReadReg(CR); 
	RTLPage(0); 
	WriteReg(RSARH_WPAGE0,(BYTE)((address>>8)&0x00ff)); 
	WriteReg(RSARL_WPAGE0,(BYTE)address); 
	WriteReg(RBCRH_WPAGE0,(BYTE)((size>>8)&0x00ff)); 
	WriteReg(RBCRL_WPAGE0,(BYTE)size); 
	WriteReg(CR,(0x00 | CR_REMOTE_READ | CR_START_COMMAND)); 
	for(Endp = buff + size; buff < Endp;) 
	{ 
		*(buff++) = ReadReg(REMOTE_DMA_PORT); 
	} 
	/* complete dma */ 
	WriteReg(RBCRH_WPAGE0,0); 
	WriteReg(RBCRL_WPAGE0,0); 
	WriteReg(CR,((PrePage&0xC0) | CR_ABORT_COMPLETE_DMA | CR_START_COMMAND)); 
} 
/* call this function to send a packet by RTL8019. packet store in ram 
starts at 'buffer' and its size is 'size'. 'size' should not large than 
MAX_PACKET_SIZE or the excess data will be discard. */ 
BOOL RTLSendPacket(BYTE DT_XDATA * buffer,WORD size) REENTRANT_SIG 
{ 
	BYTE StartPage; 
	BYTE PrePage; 
	 
	/* if send is already running */ 
	if(InSending == TRUE) 
		return FALSE; 
	else 
		InSending = TRUE; 
	/* store page */ 
	PrePage = ReadReg(CR); 
	 
	/* check pakcet size */ 
	if(size < MIN_PACKET_SIZE) 
	{ 
		size = MIN_PACKET_SIZE; 
	} 
	else 
	{ 
		if(size > MAX_PACKET_SIZE) 
			size = MAX_PACKET_SIZE; 
	} 
 
	/* write packet to ram */ 
	if(LastSendStartPage == SEND_START_PAGE0) 
	{ 
		StartPage = SEND_START_PAGE1; 
		LastSendStartPage = SEND_START_PAGE1; 
	} 
	else 
	{ 
		StartPage = SEND_START_PAGE0; 
		LastSendStartPage = SEND_START_PAGE0; 
	} 
	RTLWriteRam((WORD)(((WORD)StartPage)<<8),size,buffer); 
	 
	/* wait for last time trasmition to complete */ 
	while((ReadReg(CR) & CR_TXP) == CR_TXP); 
 
	/* write trasmit start page and size */ 
	RTLPage(0); 
	WriteReg(TPSR_WPAGE0,StartPage);	/* TPSR */				 
	WriteReg(TBCRL_WPAGE0,(BYTE)size);/*low */					 
	WriteReg(TBCRH_WPAGE0,(BYTE)((size>>8)&0x00ff));	/*high*/ 
	WriteReg(CR,((PrePage&0xC0) | CR_ABORT_COMPLETE_DMA | CR_TXP | CR_START_COMMAND));		 
	 
	InSending = FALSE; 
	return TRUE; 
} 
 
/* call this function to receive a ethernet packet from RTL8019.  
return value:  
	NULL: no packet can receive yet.  
	not NULL:  
		a address point to MemHead. This Head contain merory  
		Imformation(memory start address, memory end address ...) of  
		received packet. Memory is allocated by function 'MemAllocate(WORD size)'. 
		a example of struct SMemHead is: 
 
		struct SMemHead 
		{ 
			BOOL used;						// if in using  
			BYTE DT_XDATA *pStart;			// the start address of memory  
			BYTE DT_XDATA *pEnd; 
		}; 
		 
		You can use your own struct SMemHead and MemAllocat function in your project.		 
*/ 
struct SMemHead DT_XDATA * RTLReceivePacket() REENTRANT_SIG 
{ 
	BYTE curr,bnry; 
	WORD address; 
	WORD PacketSize; 
	struct SMemHead DT_XDATA *MemHead; 
 
	/* if send is running don't crrupt RTL register*/ 
	if(InSending == TRUE) 
		return NULL; 
 
	MemHead = NULL; 
 
	RTLPage(1); 
	curr = ReadReg(CURR_RPAGE1); 
	RTLPage(0); 
 
	/* check if startpage exceed range becasue of unknow error */ 
	if(StartPageOfPacket >= RECEIVE_STOP_PAGE || StartPageOfPacket < RECEIVE_START_PAGE) 
	{ 
		/* use curr as the StartPageOfPacket in this case */ 
		StartPageOfPacket = curr; 
		return NULL; 
	} 
	 
	/* check if there is packets to read */ 
	if(StartPageOfPacket == curr) 
		return NULL; 
 
	/*  
	 * read a packet  
	 */ 
 
	/* read packet head imformation */ 
	address = ((WORD)StartPageOfPacket)<<8; 
	RTLReadRam(address,4,Head); 
 
	/* check rsr, if isn't a good packet no read */ 
	if(Head[0] & RSR_RECEIVE_NO_ERROR) 
	{ 
		/* this is a good packet */ 
 
		/* packet size, sub 4 bytes, this 4 byte is MAC checksum */ 
		PacketSize = ((WORD)Head[3])*256 + Head[2] - 4;	 
 
		/* allocate buffer and read packet into buffer */ 
		if((MemHead = MemAllocate(PacketSize)) != NULL) 
		{	 
			/* if packet is put from bnry+1 to receive_stop_page and receive 
			   start page to next packet startpage, that is if bnry+1 > next 
			   packet start page and next start page != receive_start_page,  
			   we need read by two times. the first time from bnry+1 to receive 
			   _stop_page, the second time from receive start page to next packet 
			   startpage. 
			*/ 
			address += 4; 
			if(StartPageOfPacket > Head[1] && Head[1] != RECEIVE_START_PAGE) 
			{ 
				RTLReadRam(address,(WORD)((((WORD)RECEIVE_STOP_PAGE)<<8) - address),MemHead->pStart);	/* read from rtl */ 
				RTLReadRam((WORD)(((WORD)RECEIVE_START_PAGE)<<8),(WORD)(PacketSize - ((((WORD)RECEIVE_STOP_PAGE)<<8) - address)), 
					MemHead->pStart + ((((WORD)RECEIVE_STOP_PAGE)<<8) - address));	/* read from rtl */ 
			} 
			else 
			{ 
				RTLReadRam(address,PacketSize,MemHead->pStart);	/* read from rtl */ 
			} 
			 
		} 
	} 
	 
	/* get next packet start page */ 
	StartPageOfPacket = Head[1]; 
 
	/* reset bnry */ 
	bnry = StartPageOfPacket - 1; 
	if(bnry < RECEIVE_START_PAGE) 
		bnry = RECEIVE_STOP_PAGE - 1; 
	WriteReg(BNRY_WPAGE0,bnry); 
 
	return MemHead; 
} 
 
/*void Start8019() 
{ 
	WriteReg(CR,CR_ABORT_COMPLETE_DMA | CR_START_COMMAND); 
} 
 
void Stop8019() 
{ 
	WriteReg(CR,CR_ABORT_COMPLETE_DMA | CR_STOP_COMMAND); 
}*/