www.pudn.com > tcpip5151.rar > Eth.c
//----------------------------------------------------------------------------- // Net ETH.C // // This module is the Ethernet layer //----------------------------------------------------------------------------- #include#include #include #include #include #include "net.h" #include "serial.h" #include "arp.h" #include "ip.h" #include "eth.h" #define reg00 XBYTE[0xc000] //reg00- 10为isa网卡接口的寄存器地址300-310; #define reg01 XBYTE[0xc100] #define reg02 XBYTE[0xc200] #define reg03 XBYTE[0xc300] #define reg04 XBYTE[0xc400] #define reg05 XBYTE[0xc500] #define reg06 XBYTE[0xc600] #define reg07 XBYTE[0xc700] #define reg08 XBYTE[0xc800] #define reg09 XBYTE[0xc900] #define reg0a XBYTE[0xca00] #define reg0b XBYTE[0xcb00] #define reg0c XBYTE[0xcc00] #define reg0d XBYTE[0xcd00] #define reg0e XBYTE[0xce00] #define reg0f XBYTE[0xcf00] #define reg10 XBYTE[0xd000] bit txd_buffer_select=0; //选择网卡的发送缓冲区 extern UCHAR idata debug; extern UCHAR xdata arpbuf[]; extern UCHAR code my_hwaddr[]; void Delay1ms(unsigned char T); extern UCHAR idata rcve_buf_allocated; extern UINT volatile event_word; sbit RST8019=P3^2; //------------------------------------------------------------------------ // Initialize the Cirrus Logic 8019 chip //------------------------------------------------------------------------ void page(unsigned char pagenumber) { unsigned char data temp; temp=reg00; temp=temp&0x3B ; pagenumber=pagenumber <<6; temp=temp | pagenumber; reg00=temp; } void Rtl8019AS_Reset() //复位网卡 { RST8019=1; Delay1ms(200); Delay1ms(200); Delay1ms(200); RST8019=0; Delay1ms(100); } void ReadRtl8019NodeID(void)//读出网卡的物理地址存到my_ethernet_address.bytes[6]里 { unsigned char data 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 xdata * 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 >8; //high byte counter reg05=len&0xff; //low byte counter reg07=0xff; reg00=0x3e; //to sendpacket; free(outbuf); printf("ETH:send frame.\n"); } //------------------------------------------------------------------------ // 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) { char bnry,curr; page(0); bnry=reg03; //bnry page have read 读页指针 page(1); curr=reg07; //curr writepoint 8019写页指针 page(0); if ((curr==0)) return; bnry=bnry++; if (bnry>0x7f) bnry=0x4c; if (bnry!=curr) //此时表示有新的数据包在缓冲区里 { EA = 0; event_word |= EVENT_ETH_ARRIVED; EA = 1; } 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 xdata * rcve_frame(void)//如果收到一个有效的数据包,返回收到的数据,否则返回NULL { UCHAR bnry,curr,next_page; UINT len, ii; UCHAR temp; UCHAR xdata * buf; 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=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 xdata *)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 dest_hwaddr, hwaddr, 6); memcpy(eth->source_hwaddr, my_hwaddr, 6); eth->frame_type = 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 xdata * inbuf) { ETH_HEADER xdata * eth; eth = (ETH_HEADER xdata *)inbuf; // Reject frames in IEEE 802 format where Eth type field // is used for length. Todo: Make it handle this format if (eth->frame_type < 1520) { if (debug) printf("ETH: IEEE 802 pkt rejected\n"); return; } // Figure out what type of frame it is from Eth header // Call appropriate handler and supply address of buffer switch (eth->frame_type) { case ARP_PACKET: arp_rcve(inbuf); break; case IP_PACKET: ip_rcve(inbuf); break; default: if (debug) printf("Error: Unknown pkt rcvd\n"); break; } }