⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zlg_avalon_rtl8019.c

📁 周立功 SOPC嵌入式系统实验教程 网卡芯片驱动及其应用
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************Copyright (c)**************************************************
**                               Guangzhou ZHIYUAN ELECTRONIC CO.,LTD.
**                                      Research centre
**                         http://www.zyinside.com, http://www.zlgmcu.com
**
**---------------------------------------File Info-----------------------------------------------------
** File name:			zlg_avalon_rtl8019.c
** Latest modified Date:  2005-09-30
** Latest Version:		    1.0
** Descriptions:		LWIP ethernet interface for the RTL8019 on the  ZLG NiosII board
**
**------------------------------------------------------------------------------------------------------
** Created by:			Jing.Zhang
** Created date:		2005-09-30
** Version:				  1.0
** Descriptions:		The original version
**
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
********************************************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "zlg_avalon_rtl8019.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/netif.h"
#include "lwip/stats.h"
#include "netif/etharp.h"
#include "system.h"
#include "arch/perf.h"
#include "sys/alt_irq.h"
#ifdef ALT_DEBUG
int reg;
#endif
//#include "debug.h"

/* Unique description of the network interface. */
#define IFNAME0 ZLG_8019AS_CHIP_ID0
#define IFNAME1 ZLG_8019AS_CHIP_ID1

extern sys_mbox_t  rx_mbox;


/*-------------            Private functions  Prototypes       ------------*/

static err_t low_level_init(zlg_avalon_rtl8019_if* dev);
static struct pbuf* low_level_input(zlg_avalon_rtl8019_if *dev);
static err_t low_level_output(struct netif *netif, struct pbuf *p);
static err_t zlg_avalon_rtl8019_output(struct netif *netif, struct pbuf *p,
      struct ip_addr *ipaddr);
static void zlg_avalon_rtl8019_irq(void* context, alt_u32 interrupt);      




/*********************************************************************************************************
** Function name:			low_level_init
**
** Descriptions:			Initialize the rti8019 into the specific mode  
**
** input parameters:	dev -- a pointer to rti8019 device structure
**						
** Returned value:		err_t -- error information 
**         
** Used global variables:	None
** Calling modules:			  
**
** Created by:				Jing.Zhang
** Created Date:			2005/12/08
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static err_t low_level_init(zlg_avalon_rtl8019_if* dev)
{
  /* 
  * Need to have a pointer to a generice lwip_dev
  * This is so that the get_mac_addr function interface
  * is device agnostic
  */
  alt_lwip_dev* lwip_dev = &dev->lwip_dev_list.dev;
  err_t ret_code = ERR_OK;
  alt_u32 i;
  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_init()\n"));

  /*
  * Disable interrupts
  */
  IOWR_ALTERA_AVALON_PIO_EDGE_CAP(dev->irq_pio_base, 0);
  IOWR_ALTERA_AVALON_PIO_IRQ_MASK(dev->irq_pio_base, 0);
  /*
  * Initialize the MAC address as "00 14 97 0f 02 95"
  */
  lwip_dev->netif->hwaddr[0] = 0x00;
  lwip_dev->netif->hwaddr[1] = 0x14;
  lwip_dev->netif->hwaddr[2] = 0x97;
  lwip_dev->netif->hwaddr[3] = 0x0f;
  lwip_dev->netif->hwaddr[4] = 0x02;
  lwip_dev->netif->hwaddr[5] = 0x95;
  /* maximum transfer unit */
  lwip_dev->netif->mtu = 1500;
  /* broadcast capability */
  lwip_dev->netif->flags = NETIF_FLAG_BROADCAST;
  /* Set MAC hardware address length */
  lwip_dev->netif->hwaddr_len = 6;
  /* reset the rtl8019 and power it on*/
  RTL8019_HRST(dev->rst_pio_base);
  RTL8019_SRST(dev->base_addr);
  /* Prepare for configuring rtl8019 */
  SET_CR_REG(dev->base_addr,0x21);
  usleep(2000);//Wait 2ms for stop command is complete
  
  /* Clear RBCR0 and RBCR1              */
  SET_RBCR0_REG(dev->base_addr,0x00);
  SET_RBCR1_REG(dev->base_addr,0x00);
  SET_RCR_REG(dev->base_addr,0xe0);
  SET_TCR_REG(dev->base_addr,0xe2);
  /* Set the range of receive buffer ring */
  SET_PSTART_REG(dev->base_addr,0x4c);
  SET_PSTOP_REG(dev->base_addr,0x80);
  SET_BNRY_REG(dev->base_addr,0x4c);
  /* Set the start page of transmit buffer */
  SET_TPSR_REG(dev->base_addr,0x40);
  /* Little endian, word-wide DMA transfer */
  SET_DCR_REG(dev->base_addr,0xc9);
  /* Clear all the interrupt flags in ISR  */
  SET_ISR_REG(dev->base_addr,0xff);
  SET_IMR_REG(dev->base_addr,0x00);
 
  /* Select register page1 explicitly      */
  SelectPage(dev->base_addr, 1);       
  /* Set current page as 0x4d              */
  SET_CURR_REG(dev->base_addr,0x4d);
  /* Disable the multicast address     */
  for(i=0; i<8; i++)
  {
	  SET_MAR_REG(dev->base_addr,i,0x00);
  }
  /* START rtl8019 in the normal mode        */
  SET_CR_REG(dev->base_addr,0x22);
  /* Select register page1 explicitly      */
  SelectPage(dev->base_addr, 1); 
  for(i=0; i<6; i++)
  {
	  SET_PAR_REG(dev->base_addr,i,lwip_dev->netif->hwaddr[i]);
  }
  SelectPage(dev->base_addr, 0);
  SET_RCR_REG(dev->base_addr,0xc4);
  SET_TCR_REG(dev->base_addr,0xe0);
  SET_CR_REG(dev->base_addr,0x22);  
  SET_ISR_REG(dev->base_addr,0xff);
 
  /* Create semaphore for low_level_input and low_level_ouput */
  dev->semaphore = sys_sem_new(1);
  if (dev->semaphore == NULL)
  {
    ret_code = ERR_MEM;
    goto exit;
  }
  /* Create semaphore for ARP service */
  dev->arp_semaphore = sys_sem_new(1);
  if (dev->arp_semaphore == NULL)
  {
    ret_code = ERR_MEM;
    goto exit;
  }

  /*
   *  Install ISR and turn on interrupts
   *  
   *  If you're counting stats then we also turn on the RCV_OVRN 
   *  interrupt and increment the error counter for each interrupt
   *  
   */
  if (alt_irq_register ( dev->irq, dev, zlg_avalon_rtl8019_irq))
  {
    ret_code = ERR_IF;
    goto exit;
  }
  

exit:
  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_init() exit = %d\n", ret_code));

  return ret_code;
 
}

/*********************************************************************************************************
** Function name:	    zlg_avalon_rtl8019_init
**
** Descriptions:	 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.
**
** input parameters:	netif -- a pointer to a net device
**		               				
** Returned value:		err_t -- error information 
**         
** Used global variables:	None
** Calling modules:		
**
** Created by:				Jing.Zhang
** Created Date:			2005/12/08
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/

err_t zlg_avalon_rtl8019_init(struct netif *netif)
{
  err_t ret_code;
  zlg_avalon_rtl8019_if* dev = (zlg_avalon_rtl8019_if*)netif->state;
  dev->lwip_dev_list.dev.netif = netif;

  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("alt_avalon_lan91c111_init()\n"));
  netif->name[0] = IFNAME0;
  netif->name[1] = IFNAME1;
  netif->output = zlg_avalon_rtl8019_output;
  netif->linkoutput = low_level_output;

  if (netif->state == NULL ) 
  {
    ret_code = ERR_IF;
    goto exit;
  }
  /* Do the actual configuration of hardware   */
  ret_code = low_level_init(dev);
  if (ret_code == ERR_OK)
  {
    etharp_init();
  }
  else
  {
    free(netif->state);
  }
  /* Enable interrupts                          */
  IOWR_ALTERA_AVALON_PIO_EDGE_CAP(dev->irq_pio_base, 0);
  IOWR_ALTERA_AVALON_PIO_IRQ_MASK(dev->irq_pio_base, 1);
  SelectPage(dev->base_addr, 0); 
  SET_IMR_REG(dev->base_addr,0x11);

exit:
  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("alt_avalon_lan91c111_init() exit = %d\n",ret_code));

  return ret_code;
}

/*********************************************************************************************************
** Function name:	    zlg_avalon_rtl8019_irq
**
** Descriptions:        The Interrupt handler
**
** input parameters:	context   -- a parameter passed to callback function
**                      interrupt -- interrupt id
**		               				
** Returned value:		none 
**         
** Used global variables:	None
** Calling modules:		
**
** Created by:				Jing.Zhang
** Created Date:			2005/11/08
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void zlg_avalon_rtl8019_irq(void* context, alt_u32 interrupt)
{
  alt_u8  irq_status,curr,bnry;
  zlg_avalon_rtl8019_if *dev =  (zlg_avalon_rtl8019_if *)context;

  SelectPage(dev->base_addr,0);
  irq_status = GET_ISR_REG(dev->base_addr);
  SET_ISR_REG(dev->base_addr,irq_status); //Acknowledge the Interrupt request
  /*
   *  Rx Overrun, clear the interrupt and increase the stats counter
   */
  if(irq_status & ZLG_8019AS_ISR_OVW_MSK)
  {
#if LINK_STATS
    lwip_stats.link.drop++;   
#endif 	  
    SelectPage(dev->base_addr,1);
    curr = GET_CURR_REG(dev->base_addr);
    SelectPage(dev->base_addr,0);
    bnry = curr -1;  //restore the value of bnry
    if(bnry < 0x4c)  
    {
      bnry = 0x7f; 
    }
    SET_BNRY_REG(dev->base_addr,bnry); //restore the bnry register
  }
  else
  {
  /*
   *  Packet to Receive
   * 
   *  signal the thread which will read the data and disable interrupts
   *
   */
      if(irq_status & ZLG_8019AS_ISR_PRX_MSK)
      {
       /* Disable interrupt                   */
       //IOWR_ALTERA_AVALON_PIO_EDGE_CAP(dev->irq_pio_base, 0);
       //IOWR_ALTERA_AVALON_PIO_IRQ_MASK(dev->irq_pio_base, 0);
       //SelectPage(dev->base_addr,0);
       //SET_IMR_REG(dev->base_addr,0x00);
       /* Issue the signal                    */
       sys_mbox_post(rx_mbox, &dev->lwip_dev_list.dev);
      }
  }
}


/*********************************************************************************************************
** Function name:	    zlg_avalon_rtl8019_input
**
** Descriptions:    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.
**
** input parameters:	dev -- a pointer to a rtl8019 device structure
**		               				
** Returned value:		none 
**         
** Used global variables:	None
** Calling modules:		
**
** Created by:				Jing.Zhang
** Created Date:			2005/12/08
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/

static void zlg_avalon_rtl8019_input(zlg_avalon_rtl8019_if *dev)
{
  struct eth_hdr  *ethhdr;
  struct pbuf     *p;
  struct netif*   netif = dev->lwip_dev_list.dev.netif;

  /* move received packet into a new pbuf */
  p = low_level_input(dev);

  /* no packet could be read, silently ignore this */
  if (p == NULL) return;

  ethhdr = p->payload;

  switch (htons(ethhdr->type)) {
  /* IP packet? */
  case ETHTYPE_IP:
    /* 
    * update ARP table 
    */
    sys_sem_wait(dev->arp_semaphore);
    etharp_ip_input(netif, p);

⌨️ 快捷键说明

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