?? eth.c
字號:
//-----------------------------------------------------------------------------
// Net ETH.C
//
// This module is the Ethernet layer
//-----------------------------------------------------------------------------
#include <string.h>
#include <stdlib.h>
#include "net.h"
#include "serial.h"
#include "arp.h"
#include "ip.h"
#include "eth.h"
#include "general.h"
#include "timer.h"
extern UCHAR arpbuf[];
extern UCHAR my_hwaddr[];
extern UCHAR rcve_buf_allocated;
extern UINT event_word;
UCHAR txd_buffer_select=0; //選擇網卡的發送緩沖區
//------------------------------------------------------------------------
// Initialize the Cirrus Logic 8019 chip
//------------------------------------------------------------------------
void page(unsigned char pagenumber)
{
unsigned char temp;
temp=reg00;
temp &= 0x3B ;
pagenumber <<= 6;
temp |= pagenumber;
reg00=temp;
}
void Rtl8019AS_Reset() //復位網卡
{
unsigned char temp;
temp=reg1f;//讀網卡的復位端口
Delay1ms(200);
reg1f=temp; //寫網卡的復位端口
Delay1ms(200);
}
void ReadRtl8019NodeID(void)//讀出網卡的物理地址存到my_ethernet_address.bytes[6]里
{
unsigned char i;
page(0);
reg09=0; //讀取網卡的ram的地址為0x0000
reg08=0;
reg0b=0;
reg0a=12; //讀取12個字節
reg00=0x0a; //讀ram
for (i=0;i<6;i++)
{
// my_hwaddr[i]=reg10;
// my_hwaddr[i]=reg10;
}
}
void WriteRtl8019NodeID()
{
page(1);
reg01=my_hwaddr[0];
reg02=my_hwaddr[1];
reg03=my_hwaddr[2];
reg04=my_hwaddr[3];
reg05=my_hwaddr[4];
reg06=my_hwaddr[5];
page(0);
}
void init_8019(void)
{
Rtl8019AS_Reset(); //復位8019
// R8019_CHIP_SELECT;
reg00=0x21; //使芯片處于停止模式,這時進行寄存器設置 停止模式下,將不會發送和接收數據包
Delay1ms(10); //延時10毫秒,確保芯片進入停止模式
page(0);
reg0a=0x00; reg0b=0x00;
reg0c= 0xe0; //monitor mode (no packet receive)
reg0d= 0xe2; //loop back mode 使芯片處于mon和loopback模式,跟外部網絡斷開
reg01=0x4c; reg02=0x80; reg03=0x4c; reg04=0x40;
reg07=0xff; //清除所有中斷標志位
reg0f=0x00; //disable all interrupt
reg0e=0xc8; //byte dma 8位dma方式
page(1);
reg07=0x4d; reg08=0x00; reg09=0x00; reg0a=0x00; reg0b=0x00;
reg0c=0x00; reg0d=0x00; reg0e=0x00; reg0f=0x00;
reg00=0x22; //這時讓芯片開始工作
ReadRtl8019NodeID(); //讀出網卡的物理地址48位
WriteRtl8019NodeID(); //將網卡地址寫入到mar寄存器
page(0);
reg0c=0xcc; //將網卡設置成正常的模式,跟外部網絡連接
reg0d=0xe0;
reg00=0x22; //這時讓芯片開始工作
reg07=0xff; //清除所有中斷標志位
}
//------------------------------------------------------------------------
// This functions checks 8019 status then sends an ethernet
// frame to it by calling an assembler function.
//------------------------------------------------------------------------
void send_frame(UCHAR * outbuf, UINT len)/*發送一個數據包的命令,長度最小為60字節,最大1514字節*/
{
UCHAR i;
UINT ii;
page(0);
if(len<60)len=60;
txd_buffer_select=~txd_buffer_select;
if (txd_buffer_select)
reg09=0x40 ; //txdwrite highaddress
else
reg09=0x46 ; //txdwrite highaddress
reg08=0x00; //read page address low
reg0b=len>>8; //read count high
reg0a=len&0xff; //read count low;
reg00=0x12; //write dma, page0
for (ii=0;ii<len;ii++)
{
reg10=*(outbuf+ii);
}
/* 以下3句為中止dma的操作,可以不要 */
reg0b=0x00; //read count high 中止DMA操作
reg0a=0x00; //read count low;
reg00=0x22; //complete dma page 0
for(i=0;i<16;i++) //最多重發16次
{
for(ii=0;ii<1000;ii++) //檢查txp為是否為低
{
if ((reg00&0x04)==0) break;
}
if ((reg04&0x01)!=0) break; //表示發送成功
reg00=0x3e;
}
reg07=0xff;
if(txd_buffer_select)
reg04=0x40; //txd packet start;
else
reg04=0x46; //txd packet start;
reg06=len>>8; //high byte counter
reg05=len&0xff; //low byte counter
reg07=0xff;
reg00=0x3e; //to sendpacket;
free(outbuf);
#ifdef DEBUG
PrintStr("ETH:send frame.\n");
#endif
}
//------------------------------------------------------------------------
// This functions checks the 8019 receive event status
// word to see if an ethernet frame has arrived. If so,
// set EVENT_ETH_ARRIVED bit in global event_word
//------------------------------------------------------------------------
void query_8019(void)
{
unsigned char bnry=0,curr=0;
page(0);
bnry=reg03; //bnry page have read 讀頁指針
page(1);
curr=reg07; //curr writepoint 8019寫頁指針
page(0);
if ((curr==0)) return;
bnry++;
if (bnry>0x7f) bnry=0x4c;
if (bnry!=curr) //此時表示有新的數據包在緩沖區里
{
SREG = 0<<SREG_I;
event_word |= EVENT_ETH_ARRIVED;
SREG = 1<<SREG_I;
}
reg0b=0x00; reg0a=0x00; reg00=0x22;//complete dma page 0
}
//------------------------------------------------------------------------
// This function gets an incoming Ethernet frame from the 8019.
// There may be more than 1 waiting but just allocate memory for
// one and read one in. Use the 8019 to queue incoming packets.
//------------------------------------------------------------------------
UCHAR* rcve_frame(void)//如果收到一個有效的數據包,返回收到的數據,否則返回NULL
{
UCHAR bnry=0,curr=0,next_page=0;
UINT len=0, ii;
UCHAR temp=0;
UCHAR* buf=0;
page(0);
bnry=reg03; //bnry page have read 讀頁指針
page(1);
curr=reg07; //curr writepoint 8019寫頁指針
page(0);
if ((curr==0)) return NULL; //讀的過程出錯
next_page=bnry;
bnry++;
if (bnry>0x7f) bnry=0x4c;
if (bnry!=curr) //此時表示有新的數據包在緩沖區里
{
//讀取一包的前4個字節:4字節的8019頭部
page(0);
reg09=bnry; //read page address high
reg08=0x00; //read page address low
reg0b=0x00; //read count high
reg0a=4; //read count low;
reg00=0x0a; //read dma
temp = reg10; temp = reg10;
next_page = temp-1; //next page start-1
len = reg10; temp = reg10;
len += temp<<8;
reg0b=0x00; reg0a=0x00; reg00=0x22;//complete dma page 0
// Allocate enough memory to hold the incoming frame
buf = (UCHAR*)malloc(len);
if (buf == NULL)
{
// out of RAM
// Tell 8019 to skip the frame
page(1);
curr=reg07; //page1
page(0); //切換回page0
bnry = curr -1;
if (bnry < 0x4c) bnry =0x7f;
reg03=bnry; //write to bnry
reg07=0xff; //清除中斷狀態可以不用
return NULL;
}
// This flag keeps track of allocated rcve memory
rcve_buf_allocated = TRUE;
// Call the assembler function to get the incoming frame
reg09=bnry; //read page address high
reg08=4; //read page address low
reg0b=len>>8; //read count high
reg0a=len&0xff; //read count low;
reg00=0x0a; //read dma
for(ii=0;ii<len;ii++)
{
buf[ii]=reg10;
}
reg0b=0x00; reg0a=0x00; reg00=0x22; //dma complete page0
// Return pointer to start of buffer
bnry=next_page;
if (bnry<0x4c) bnry=0x7f;
reg03=bnry; //write to bnry
reg07=0xff;
return (buf);
}
return NULL;
}
void eth_send(UCHAR * outbuf, UCHAR * hwaddr, UINT ptype, UINT len)
{
ETH_HEADER * eth;
eth = (ETH_HEADER *)outbuf;
// Add 14 byte Ethernet header
memcpy(eth->dest_hwaddr, hwaddr, 6);
memcpy(eth->source_hwaddr, my_hwaddr, 6);
eth->frame_type = swapint(ptype);
// We just added 14 bytes to length
send_frame(outbuf, len + 14);
}
//------------------------------------------------------------------------
// This is the handler for incoming Ethernet frames
// This is designed to handle standard Ethernet (RFC 893) frames
// See "TCP/IP Illustrated, Volume 1" Sect 2.2
//------------------------------------------------------------------------
void eth_rcve(UCHAR * inbuf)
{
ETH_HEADER * eth;
unsigned int frametype;
eth = (ETH_HEADER *)inbuf;
frametype = swapint(eth->frame_type);
// Reject frames in IEEE 802 format where Eth type field
// is used for length. Todo: Make it handle this format
if (frametype < 1520)
{
#ifdef DEBUG
PrintStr("ETH: IEEE 802 pkt rejected\n");
#endif
return;
}
// Figure out what type of frame it is from Eth header
// Call appropriate handler and supply address of buffer
switch (frametype)
{
case ARP_PACKET:
arp_rcve(inbuf);
break;
case IP_PACKET:
ip_rcve(inbuf);
break;
default:
#ifdef DEBUG
PrintStr("Error: Unknown pkt rcvd\n");
#endif
break;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -