ethernetif.c

来自「基于ARM2200开发平台开发的嵌入式TCPIP协议栈」· C语言 代码 · 共 560 行

C
560
字号
/*
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
 * 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.
 *
 * This file is part of the lwIP TCP/IP stack.
 * 
 * Author: Adam Dunkels <adam@sics.se>
 *
 */

/*
 * This file is a skeleton for developing Ethernet network interface
 * drivers for lwIP. Add code to the low_level functions and do a
 * search-and-replace for the word "ethernetif" to replace it with
 * something that better describes your network interface.
 */
/************************************************************************************
最为重要的一个文件,他的主要功能是8019的收发驱动和收发机制的调度。驱动部分由自己实现。
为了它耗费了大量的时间去保证8019的稳定性,它也是整个协议栈正常与否的关键。
************************************************************************************/

#include "opt.h"
#include "def.h"
#include "mem.h"
#include "pbuf.h"
#include "sys.h"
#include "stats.h"

#include "etharp.h"
#include "RTL8019.h"
#include "LPC2294.h"
#include "ucos_ii.h"

/* Define those to better describe your network interface. */
#define IFNAME0 'e'
#define IFNAME1 'n'


struct netif  *MyNetif;	//要将它分配给初始化中创建的netif表,此结构需要把我们做好的底层驱动和选定的上层处理分配进去
struct netif *loop_netif;//环回接口的驱动

struct ethernetif {
  struct eth_addr *ethaddr;
  /* Add whatever per-interface state that is needed here. */
};

static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};

/* Forward declarations. */
static void  ethernetif_input(struct netif *netif);
static err_t ethernetif_output(struct netif *netif, struct pbuf *p,
             struct ip_addr *ipaddr);

static void
low_level_init(struct netif *netif)
{
  //struct ethernetif *ethernetif = netif->state;
  
  /* set MAC hardware address length */
  netif->hwaddr_len = 6;

  /* set MAC hardware address */
  netif->hwaddr[0] = My_hwaddr[0];
  netif->hwaddr[1] = My_hwaddr[1];
  netif->hwaddr[2] = My_hwaddr[2];
  netif->hwaddr[3] = My_hwaddr[3];
  netif->hwaddr[4] = My_hwaddr[4];
  netif->hwaddr[5] = My_hwaddr[5];

  /* maximum transfer unit */
  netif->mtu = 1500;
  
  /* broadcast capability */
  netif->flags = NETIF_FLAG_BROADCAST;
  netif->flags |= NETIF_FLAG_UP;
  /* Do whatever else is needed to initialize interface. */
  InitINT();
  init_8019();     
}

/*
 * low_level_output():
 *
 * Should do the actual transmission of the packet. The packet is
 * contained in the pbuf that is passed to the function. This pbuf
 * might be chained.
 *
 */

static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
  //struct ethernetif *ethernetif = netif->state;
  struct pbuf *q;

//  initiate transfer();
  
#if ETH_PAD_SIZE
  pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */
#endif

  for(q = p; q != NULL; q = q->next) {
    /* Send the data from the pbuf to the interface, one pbuf at a
       time. The size of the data in each pbuf is kept in the ->len
       variable. */
	//send data from(q->payload, q->len);
	send_frame(q->payload, q->len);
  }

	//signal that packet should be sent();

#if ETH_PAD_SIZE
  pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */
#endif
  
#if LINK_STATS
  lwip_stats.link.xmit++;
#endif /* LINK_STATS */      

  return ERR_OK;
}

/*
 * low_level_input():
 *
 * Should allocate a pbuf and transfer the bytes of the incoming
 * packet from the interface into the pbuf.
 *
 */

static struct pbuf *
low_level_input(struct netif *netif)
{
  	//struct ethernetif *ethernetif = netif->state;
  	struct pbuf *p, *q;
  	u16_t len,ii;
	unsigned char bnry,curr;
	unsigned char temp,temp1;
	unsigned char S_next_page;
	unsigned long * ttmp;
/**********************读取数据长度*******************************/
	page(0); 	//bnry page have read 读页指针						//
	bnry = Read8019Reg(0x03);										//
																	//
	page(1);	//curr writepoint 8019写页指针						//
	curr = Read8019Reg(0x07);										//

	page(0);
	
	if((bnry<0x4c) || (bnry>0x7f)){
		bnry = curr-1;
		if(bnry<0x4c)
			bnry = 0x7f;
	}	
	
	if ((curr==0))	return 0;	//读的过程出错
	S_next_page=bnry;
	bnry++;
	if (bnry>0x7f)	bnry=0x4c;
	if (bnry!=curr)	//此时表示有新的数据包在缓冲区里
	{
		//读取一包的前4个字节:4字节的8019头部
		page(0);
		//read page address high
		Write8019Reg(0x09, bnry);
		//read page address low
		Write8019Reg(0x08, 0x00);
		//read count high
		Write8019Reg(0x0b, 0x00);
		//read count low;
		Write8019Reg(0x0a, 0x04);
		//read dma
		Write8019Reg(0x00, 0x0a);

		temp = Read8019Reg(0x10);
		temp1 = Read8019Reg(0x10);
		
/********************/
if(temp1>0x7f||temp1<0x4c){
   	//page(1);
   	//curr = Read8019Reg(0x07);
   	
	if(curr==0x4c){
   		curr = 0x7f;
   	}
   	else{
   		curr--;
   	}
   	
   	page(0);
   	Write8019Reg(0x03, curr);
   	
   	Write8019Reg(0x0b, 0x00);	//complete dma page 0			//
	Write8019Reg(0x0a, 0x00);									//	
	Write8019Reg(0x00, 0x22);
   	return 0;   	
}

/********************/		
		S_next_page = temp1-1;		//next page start-1

		len = Read8019Reg(0x10);
		temp = Read8019Reg(0x10);
		
		len += temp<<8;
/********************/
if(len>1518||len<60){
   	//page(1);
   	//curr = Read8019Reg(0x07);
   	
   	if(curr==0x4c){
   		curr = 0x7f;
   	}
   	else{
   		curr--;
   	}
   	
   	page(0);
   	Write8019Reg(0x03, curr);
   	Write8019Reg(0x0b, 0x00);	//complete dma page 0			//
	Write8019Reg(0x0a, 0x00);									//	
	Write8019Reg(0x00, 0x22);
   	return 0;  	
}

/********************/
									//
	}
	else{
		Write8019Reg(0x0b, 0x00);	//complete dma page 0			//
	 	Write8019Reg(0x0a, 0x00);									//	
	 	Write8019Reg(0x00, 0x22);
		return 0;
	}																//
/*************************读取数据长度****************************/
  /* Obtain the size of the packet and put it into the "len"
     variable. */
  //len = GetPackedLen();

#if ETH_PAD_SIZE
  len += ETH_PAD_SIZE;						/* allow room for Ethernet padding */
#endif

  /* We allocate a pbuf chain of pbufs from the pool. */
  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
  
  if (p != NULL) {

#if ETH_PAD_SIZE
    pbuf_header(p, -ETH_PAD_SIZE);			/* drop the padding word */
#endif

    /* We iterate over the pbuf chain until we have read the entire
     * packet into the pbuf. */
    for(q = p; q != NULL; q = q->next) {
      /* Read enough bytes to fill this pbuf in the chain. The
       * available data in the pbuf is given by the q->len
       * variable. */
 		//read data into(q->payload, q->len);
 		//rcve_frame(q->payload, q->len);
/*************************读取数据********************************************************************/
	 	if (q->payload == NULL)
		{
			//out of RAM
			//Tell 8019 to skip the frame
			page(1);	//page1
			curr = Read8019Reg(0x07);
			page(0);		//切换回page0
	        bnry = curr -1;
	        if(bnry < 0x4c) bnry =0x7f;	//write to bnry   
			Write8019Reg(0x03, bnry);	//清除中断状态可以不用
			Write8019Reg(0x07, 0xff);
			return 0;
		}			
		//This flag keeps track of allocated rcve memory
		//rcve_buf_allocated = TRUE;
		//Call the assembler function to get the incoming frame
		//read page address high
		Write8019Reg(0x09, bnry);	//read page address low
		Write8019Reg(0x08, 0x04);	//read count high
		Write8019Reg(0x0b, (unsigned char)(q->len>>8));	//read count low;
		Write8019Reg(0x0a, (unsigned char)(q->len&0xff));	//read dma
		Write8019Reg(0x00, 0x0a);
		
		ttmp = q->payload;
	    for(ii=0;ii<q->len;ii++)
	    {
	    	*((unsigned char *)((unsigned long)ttmp+ii)) = Read8019Reg(0x10);
	    }	    	
	    	
		//dma complete  page0     
	   	Write8019Reg(0x0b, 0x00);
	   	Write8019Reg(0x0a, 0x00);
	   	Write8019Reg(0x00, 0x22);
	   	//Return pointer to start of buffer
		bnry=S_next_page;
		if (bnry<0x4c)  bnry=0x7f;	//write to bnry
		Write8019Reg(0x03, bnry);
	    Write8019Reg(0x07, 0xff);
/**********************读取数据*************************************************************************/
    }
 	//acknowledge that packet has been read();

#if ETH_PAD_SIZE
    pbuf_header(p, ETH_PAD_SIZE);			/* reclaim the padding word */
#endif

#if LINK_STATS
    lwip_stats.link.recv++;
#endif /* LINK_STATS */      
  } 
  else {
/**********drop packet();*********************************************************/
		/*Write8019Reg(0x09, bnry);	//read page address low
		Write8019Reg(0x08, 0x04);	//read count high
		Write8019Reg(0x0b, (unsigned char)(len>>8));	//read count low;
		Write8019Reg(0x0a, (unsigned char)(len&0xff));	//read dma
		Write8019Reg(0x00, 0x0a);
	 	for(ii=0;ii<len;ii++)
	    {
	    	*((unsigned char *)((unsigned long)ttmp)) = Read8019Reg(0x10);
	    }
	   	Write8019Reg(0x0b, 0x00);
	   	Write8019Reg(0x0a, 0x00);
	   	Write8019Reg(0x00, 0x22);这一段有问题*/
	   	Write8019Reg(0x0b, 0x00);
	   	Write8019Reg(0x0a, 0x00);
	   	Write8019Reg(0x00, 0x22);
		bnry=S_next_page;
		if (bnry<0x4c)  bnry=0x7f;	//write to bnry
		Write8019Reg(0x03, bnry);
	    Write8019Reg(0x07, 0xff);	   		    
/**********drop packet();*********************************************************/
	    
	#if LINK_STATS
	    lwip_stats.link.memerr++;
	    lwip_stats.link.drop++;
	#endif /* LINK_STATS */      
  }

  return p;  
}

/*
 * ethernetif_output():
 *
 * This function is called by the TCP/IP stack when an IP packet
 * should be sent. It calls the function called low_level_output() to
 * do the actual transmission of the packet.
 *
 */

static err_t
ethernetif_output(struct netif *netif, struct pbuf *p,
      struct ip_addr *ipaddr)
{
  
 /* resolve hardware address, then send (or queue) packet */
  return etharp_output(netif, ipaddr, p);
 
}

/*
 * ethernetif_input():
 *
 * This function should be called when a packet is ready to be read
 * from the interface. It uses the function low_level_input() that
 * should handle the actual reception of bytes from the network
 * interface.
 *
 */

static void
ethernetif_input(struct netif *netif)
{
  struct ethernetif *ethernetif;
  struct eth_hdr *ethhdr;
  struct pbuf *p;

  ethernetif = netif->state;
  
  /* move received packet into a new pbuf */
  p = low_level_input(netif);
  
  /* no packet could be read, silently ignore this */
  if (p == NULL) return;
  /* points to packet payload, which starts with an Ethernet header */
  ethhdr = p->payload;
	
#if LINK_STATS
  lwip_stats.link.recv++;
#endif /* LINK_STATS */

  ethhdr = p->payload;
    
  switch (htons(ethhdr->type)) {
  /* IP packet? */
  case ETHTYPE_IP:
    /* update ARP table */
    etharp_ip_input(netif, p);
    /* skip Ethernet header */
    pbuf_header(p, -sizeof(struct eth_hdr));
    /* pass to network layer */
    netif->input(p, netif);
    break;
      
    case ETHTYPE_ARP:
      /* pass p to ARP module  */
      etharp_arp_input(netif, ethernetif->ethaddr, p);
      break;
    default:
      pbuf_free(p);
      p = NULL;
      break;
  }
}

static void
arp_timer(void *arg)
{
  etharp_tmr();
  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}

/*
 * ethernetif_init():
 *
 * Should be called at the beginning of the program to set up the
 * network interface. It calls the function low_level_init() to do the
 * actual setup of the hardware.
 *
 */

err_t
ethernetif_init(struct netif *netif)
{
  struct ethernetif *ethernetif;
    
  ethernetif = mem_malloc(sizeof(struct ethernetif));
  
  if (ethernetif == NULL)
  {
  	LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
  	return ERR_MEM;
  }
  
  netif->state = ethernetif;
  netif->name[0] = IFNAME0;
  netif->name[1] = IFNAME1;
  netif->output = ethernetif_output;
  netif->linkoutput = low_level_output;
  
  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
  
  low_level_init(netif);

  etharp_init();

  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);

  return ERR_OK;
}


/*接收中断处理函数,它主要处理当一个接收完成后,进行包的解析和通知
上层协议进行包的处理*/
void IRQ_Eint2(void)
{
	unsigned char RegOfISR;
	unsigned char temp;
	unsigned char curr;
	
	page(0);
	Write8019Reg(0x0f, 0x00);
	/*停止接收*/
	temp = Read8019Reg(0x00);
	Write8019Reg(0x00, (temp&0xFC)|RTL_REV_STP|RTL_DMA_OVR);
	
	RegOfISR = Read8019Reg(0x07);     
    if((RegOfISR) & 0x10){
    	Write8019Reg(0x07, 0x10);
    }
    
    /*if((RegOfISR) & 0x08){
    	Write8019Reg(0x07, 0x08);
    }*/
    
    if((RegOfISR) & 0x04){
    	Write8019Reg(0x07, 0x04);
    	
    	page(1);
    	curr = Read8019Reg(0x07);
    	
    	if(curr==0x4c){
    		curr = 0x7f;
    	}
    	else{
    		curr--;
    	}
    	
    	page(0);
    	Write8019Reg(0x03, curr);
    }
    
    if((RegOfISR) & 0x01){
    	Write8019Reg(0x07, 0x01);
    
		while(query_8019())
		{
			ethernetif_input(MyNetif);
		}
	}
	
	if((RegOfISR) & 0x02){
		Write8019Reg(0x07, 0x02);	
	}
	
	if((RegOfISR) & 0x80){
    	Write8019Reg(0x07, 0xff);
    }
	Write8019Reg(0x0b, 0x00);	//complete dma page 0			//
	Write8019Reg(0x0a, 0x00);									//	
	Write8019Reg(0x00, 0x22);
	/*清除中断状态*/
	page(0);
    Write8019Reg(0x00, (temp&0xFC)|RTL_REV_STP|RTL_DMA_OVR);	
	Write8019Reg(0x07, 0xff);
	
	/*开始接收*/
	temp = Read8019Reg(0x00);
	Write8019Reg(0x00, (temp&0xFC)|RTL_REV_STA);
	
	Write8019Reg(0x0f, 0x11);
		
	EXTINT = 0x04;
	VICVectAddr = 0x00;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?