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

📄 ctrl_rtl8019.c

📁 基于康草科技中一款SOPC开发板上的8019的以太网驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/************************************************
* www.21control.com
 ************************************************/
#ifdef LWIP

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

#include "alt_types.h"
#include "ctrl_rtl8019_regs.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"
#include "ctrl_rtl8019.h"


/* Unique descricption of the network interface. */
#define IFNAME0 'n'
#define IFNAME1 '9'

extern sys_mbox_t  rx_mbox;

static err_t
ctrl_rtl8019_output(struct netif *netif, struct pbuf *p,struct ip_addr *ipaddr);
static struct pbuf* low_level_input(ctrl_rtl8019_if *dev);
static err_t low_level_output(struct netif *netif, struct pbuf *p);
static err_t low_level_init(ctrl_rtl8019_if* dev);
void ctrl_rtl8019_irq(void* context, alt_u32 interrupt);

/*************************************************/

static inline void Delay16Cycles(void)
{
    unsigned int i;
    for(i=0;i<100;i++);
}

u_char reg_read(unsigned int base,u_char reg)
{
  unsigned char uc;
  
  uc=IORD_8DIRECT(base, reg); /* DYNAMIC MEMORY */
  //uc=IORD(base, reg);       /* NATIVE MEMORY SIZE */
  return uc;  
} 

u_char reg_write(base,reg, data)
{ 
  IOWR_8DIRECT(base, reg, data);/* DYNAMIC MEMORY */
  //IOWR(base, reg, data);      /* NATIVE MEMORY SIZE */
  return data;
}


void getState(unsigned char *RTL_BASE_ADDR)
{
  unsigned char old_cr,uc;
  unsigned char tsr,isr,rsr;
  unsigned char rcr,tcr,dcr,imr;
  unsigned char  pstart,pstop;
  int iRet;
  old_cr=IORD_CTRL_RTL8019_CR(0x00800000);
  
  //change to page0 
  IOWR_CTRL_RTL8019_CR(0x00800000,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_RD2_MSK );
  tsr=IORD_CTRL_RTL8019_TSR(0x00800000);
  isr=IORD_CTRL_RTL8019_ISR(0x00800000);
  rsr=IORD_CTRL_RTL8019_RSR(0x00800000);
  
  // change to page2 
  IOWR_CTRL_RTL8019_CR(0x00800000, CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_RD2_MSK |  CTRL_RTL8019_CR_PS1_MSK);
  
  pstop=IORD_CTRL_RTL8019_PSTOP(0x00800000);
  pstart=IORD_CTRL_RTL8019_PSTART(0x00800000);
  rcr=IORD_CTRL_RTL8019_RCR(0x00800000);
  tcr=IORD_CTRL_RTL8019_TCR(0x00800000);
  dcr=IORD_CTRL_RTL8019_DCR(0x00800000);
  imr=IORD_CTRL_RTL8019_IMR(0x00800000);
  
  IOWR_CTRL_RTL8019_CR(0x00800000,CTRL_RTL8019_CR_STP_MSK | CTRL_RTL8019_CR_RD2_MSK | CTRL_RTL8019_CR_PS0_MSK);
    
  uc=IORD_CTRL_RTL8019_PAR0(0x00800000);
  uc=IORD_CTRL_RTL8019_PAR1(0x00800000);
  uc=IORD_CTRL_RTL8019_PAR2(0x00800000);
  uc=IORD_CTRL_RTL8019_PAR3(0x00800000);
  uc=IORD_CTRL_RTL8019_PAR4(0x00800000);
  uc=IORD_CTRL_RTL8019_PAR5(0x00800000);
  
  IOWR_CTRL_RTL8019_CR(0x00800000,old_cr); 
}


/*!
 * Reset the Ethernet controller.
 * use hardware line e_rst
 */
int rtl8019_Reset(ctrl_rtl8019_if* dev)
{
    unsigned char  i;
    unsigned char  j;
    
    /*
     * Do the software reset by reading from the reset register followed
     * by writing to the reset register. Wait until the controller enters
     * the reset state.
     */
    for (j = 0; j < 20; j++) {
        IOWR_ALTERA_AVALON_PIO_DATA(E_RST_BASE,0x01); /* hardware reset*/
        //IORD_CTRL_RTL8019_RESET(dev->base_addr);
        OSTimeDlyHMSM(0,0,1,0);
        //IOWR_CTRL_RTL8019_RESET(dev->base_addr,0xff);
        IOWR_ALTERA_AVALON_PIO_DATA(E_RST_BASE,0x00); /* hardware reset*/
        for (i = 0; i < 20; i++) {
            OSTimeDlyHMSM(0,0,1,0);
            /*
             * We got the reset bit. However, Ethernut 1.1 may
             * still fail because the NIC hasn't got it's hardware
             * reset and the data lines remain in tristate. So we
             * read noise instead of the register. To solve this
             * problem, we will verify the NIC's id.
             */
            i=IORD_CTRL_RTL8019_ISR(dev->base_addr);
            if ((i & CTRL_RTL8019_ISR_RST_MSK ) != 0 )
                return 0;
                  
            i=IORD_CTRL_RTL8019_8019ID0(dev->base_addr); 
            if ( i == 0x50 )
                return 0;

            i= IORD_CTRL_RTL8019_8019ID1(dev->base_addr);
            if( i == 0x70)
                return 0; 
        }
    }
    return -1;
}


/*-----------------------------------------------------------------------------------* 
 *
 * ctrl_rtl8019_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 ctrl_rtl8019_input(ctrl_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 
    * 
    * The code which updates the ARP tables does not appear to be thread safe
    * so I've added a MUTEX around all calls to the arp code
    * 
    */
    sys_sem_wait(dev->arp_semaphore);
    etharp_ip_input(netif, p);
    sys_sem_signal(dev->arp_semaphore);
    /* skip Ethernet header */
    pbuf_header(p, -(s16_t)sizeof(struct eth_hdr));
    /* pass to network layer */
    netif->input(p, netif);
    break;
      
    case ETHTYPE_ARP:
      /* 
      * pass p to ARP module  
      * 
      * The code which updates the ARP tables does not appear to be thread safe
      * so I've added a MUTEX around all calls to the arp code
      * 
      */
      sys_sem_wait(dev->arp_semaphore);
      etharp_arp_input(netif, (struct eth_addr *)&netif->hwaddr, p);
      sys_sem_signal(dev->arp_semaphore);
      break;
    default:
      pbuf_free(p);
      p = NULL;
      break;
  }
}

/*-----------------------------------------------------------------------------------*
 *
 * ctrl_rtl8019_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 ctrl_rtl8019_init(struct netif *netif)
{
  err_t ret_code;
  ctrl_rtl8019_if* dev = (ctrl_rtl8019_if*)netif->state;
  dev->lwip_dev_list.dev.netif = netif;

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

  if (netif->state == NULL ) 
  {
    ret_code = ERR_IF;
    goto exit;
  }

  if (dev->bus_width != 8)
  {
    printf("This driver doesn't support the Ethernet add on card at present\n");
    ret_code = ERR_IF;
    goto exit;
  }

  ret_code = low_level_init(dev);
  if (ret_code == ERR_OK)
  {
    etharp_init();
  }
  else
  {
    free(netif->state);
  }

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

  return ret_code;
}

/*
 * Fires up the network interface. NIC interrupts
 * should have been disabled when calling this
 * function.
 */
static err_t low_level_init(ctrl_rtl8019_if* dev)
{
    unsigned char i,uc;

  /* 
  * 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;
    
    LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_init()\n"));
    
  
  /* Set MAC hardware address length */
  lwip_dev->netif->hwaddr_len = 6;
  
    /* reset chip */
    if (rtl8019_Reset(dev)) {
        return -1;
    }
    
    /*
     * Mask all interrupts and clear any interrupt status flag to set the
     * INT pin back to low.
     */
    IOWR_CTRL_RTL8019_IMR(dev->base_addr,0x00);
    IOWR_CTRL_RTL8019_ISR(dev->base_addr,0xff);
    OSTimeDlyHMSM(0,0,1,0);
    /*
     * During reset the nic loaded its initial configuration from an
     * external eeprom. On the ethernut board we do not have any
     * configuration eeprom, but simply tied the eeprom data line to
     * high level. So we have to clear some bits in the configuration
     * register. Switch to register page 3.
     */
    IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STP_MSK | CTRL_RTL8019_CR_RD2_MSK | CTRL_RTL8019_CR_PS0_MSK | CTRL_RTL8019_CR_PS1_MSK);
    
    /*
     * The nic configuration registers are write protected unless both
     * EEM bits are set to 1.
     */
    IOWR_CTRL_RTL8019_9346CR(dev->base_addr, CTRL_RTL8019_9346CR_EEM0_MSK | CTRL_RTL8019_9346CR_EEM1_MSK);
    
    /*
     * Network media had been set to 10Base2 by the virtual EEPROM and
     * will be set now to auto detect. This will initiate a link test.
     * We don't force 10BaseT, because this would disable the link test.
     */
    IOWR_CTRL_RTL8019_CONFIG2(dev->base_addr, CTRL_RTL8019_CONFIG2_BSELB_MSK);
    
    /*
     * Disable sleep and power down.
     *
     * The virtual EEPROM (resistor tight to VCC) will set all bits of
     * CONFIG3 to 1. Unfortunately we are not able to modify the full
     * duplex bit. The only solution is to use a real EEPROM or emulate
     * one.
     */
    //reg_write(RTL_BASE_ADDR,NIC_PG3_CONFIG3, NIC_CONFIG3_LEDS0 | NIC_CONFIG3_LEDS1);
    IOWR_CTRL_RTL8019_CONFIG3(dev->base_addr,CTRL_RTL8019_CONFIG3_LEDS0_MSK|CTRL_RTL8019_CONFIG3_LEDS1_MSK );
    
    /*
     * Reenable write protection of the nic configuration registers
     * and wait for link test to complete.
     */

⌨️ 快捷键说明

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