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

📄 freedev_lan91c111.c

📁 lan91c111网络接口的设计 包括功能设计文件和驱动程序文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
* Register definitions for the Rtl8019as ethernet chip used on the Nios II
* FreeDev2.1 development boards
* Create by Free-electron
* author:liu-jun-sheng
* address:MoGanShan road HangZhou ZheJiang China 
* tel:0571-88846603
* www.Free-Electron.com.cn
* date:2005/12/02
*/
#ifdef LWIP

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

#include "alt_types.h"
#include "freedev_lan91c111_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 "freedev_lan91c111.h"



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

extern sys_mbox_t  rx_mbox;

/* 
* Prototypes
*/
static err_t low_level_init(freedev_lan91c111_if* dev);
static struct pbuf* low_level_input(freedev_lan91c111_if *dev);
static err_t low_level_output(struct netif *netif, struct pbuf *p);
static err_t freedev_lan91c111_output(struct netif *netif, struct pbuf *p,
      struct ip_addr *ipaddr);

/*-----------------------------------------------------------------------------------* 
 *
 * freedev_lan91c111_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 freedev_lan91c111_input(freedev_lan91c111_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;
  }
}

/*-----------------------------------------------------------------------------------*
 *
 * freedev_lan91c111_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 freedev_lan91c111_init(struct netif *netif)
{
  err_t ret_code;
  freedev_lan91c111_if* dev = (freedev_lan91c111_if*)netif->state;
  dev->lwip_dev_list.dev.netif = netif;

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

  if (netif->state == NULL ) 
  {
    ret_code = ERR_IF;
    goto exit;
  }
  
  /* 20051227 modify by free_electron
  if (dev->bus_width != 32)
  {
    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, ("freedev_lan91c111_init() exit = %d\n",ret_code));

  return ret_code;
}


/*
* freedev_lan91c111_irq
*
* The Interrupt handler
*/
static void freedev_lan91c111_irq(void* context, alt_u32 interrupt)
{
  alt_u8  irq_status;
  alt_u8  irq_msk;
  freedev_lan91c111_if *dev =  (freedev_lan91c111_if *)context;

  irq_status = IORD_FREEDEV_LAN91C111_IST(dev->base_addr);

  /*
   *  Rx Overrun, clear the interrupt and increment the stats counter
   */
#if LINK_STATS
  if(irq_status & FREEDEV_LAN91C111_INT_RX_OVRN_INT_MSK)
  {
    lwip_stats.link.drop++;
    IOWR_FREEDEV_LAN91C111_ACK(dev->base_addr, 
                            FREEDEV_LAN91C111_INT_RX_OVRN_INT_MSK);
  }
#endif /* LINK_STATS */

  /*
   *  Packet to Receive
   * 
   *  signal the thread which will read the data and disable interrupts
   *
   */
  irq_msk = IORD_FREEDEV_LAN91C111_MSK(dev->base_addr); 

  if((irq_status & FREEDEV_LAN91C111_INT_RCV_INT_MSK) && 
      (irq_msk & FREEDEV_LAN91C111_INT_RCV_INT_MSK))
  {
    irq_msk &= ~FREEDEV_LAN91C111_INT_RCV_INT_MSK;
    IOWR_FREEDEV_LAN91C111_MSK(dev->base_addr, irq_msk);
    sys_mbox_post(rx_mbox, &dev->lwip_dev_list.dev);
  }
  return;
}

/*
* freedev_lan91c111_rx
* Handle all the receives
*/
void freedev_lan91c111_rx(  alt_lwip_dev* dev )
{
  alt_u8  irq_msk;
  alt_u8  irq_status;
  freedev_lan91c111_if *lan_dev = (freedev_lan91c111_if *)dev->netif->state;
  
  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("lan91c111_rx()"));

  irq_status = IORD_FREEDEV_LAN91C111_IST(lan_dev->base_addr);
  while(irq_status & FREEDEV_LAN91C111_INT_RCV_INT_MSK)
  {
    freedev_lan91c111_input(lan_dev);
    irq_status = IORD_FREEDEV_LAN91C111_IST(lan_dev->base_addr);
  }
  
  /* Re-enable RX interrupts */
  irq_msk = IORD_FREEDEV_LAN91C111_MSK(lan_dev->base_addr); 
  irq_msk |= FREEDEV_LAN91C111_INT_RCV_INT_MSK;
  IOWR_FREEDEV_LAN91C111_MSK(lan_dev->base_addr, irq_msk);
}

/*
* Clock one bit of data to the PHY
*/
static void clock_phy_bit(freedev_lan91c111_if* dev, const unsigned value)
{
  IOWR_FREEDEV_LAN91C111_MGMT(dev->base_addr, value);
  IOWR_FREEDEV_LAN91C111_MGMT(dev->base_addr, value |
                                    FREEDEV_LAN91C111_MGMT_MCLK_MSK);
}

/*
* Read a PHY register, this involves manually clocking lots
* of data.
*/
static alt_u16 read_phy_register(freedev_lan91c111_if* dev, 
                                 const unsigned phy_register)
{
  alt_u16 register_value;
  alt_u16 old_bank;
  alt_u16 mgmt_value;
  int i;

  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("read_phy_register (%d)=", phy_register));

  /*
  * Swap to bank 3
  */
  old_bank = IORD_FREEDEV_LAN91C111_BSR(dev->base_addr);
  IOWR_FREEDEV_LAN91C111_BSR( dev->base_addr,3);

  mgmt_value = IORD_FREEDEV_LAN91C111_MGMT( dev->base_addr);
  mgmt_value &= 0xfff0;

  /* Output an Idle of 32 1's */
  for(i=0;i<32;i++)
  {
    clock_phy_bit(dev, mgmt_value | 
                                  FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                  FREEDEV_LAN91C111_MGMT_MDO_MSK );
  }

  /* Ouput 01 which marks the change of cycle */
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK );
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                    FREEDEV_LAN91C111_MGMT_MDO_MSK );
  
  /* Output the command, 10 = read */
  clock_phy_bit(dev, mgmt_value |
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                    FREEDEV_LAN91C111_MGMT_MDO_MSK );
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK );

  /* Output the PHY address, 0 is the internal PHY */
  for(i=0;i<5;i++) 
  {
    clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK );
  }

  /* Write the Register Address, MSB first */
  for(i=4;i>=0;i--) 
  {
    clock_phy_bit(dev, mgmt_value | 
                                  FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                  ((phy_register >> i) & 0x1));
  }

  /* 
  * The datasheet says we output Z0 here, however Application Note 79 mentions a chip bug
  * which configuring the Nat Semi in built PHY we only output Z, if using an off chip PHY
  * uncomment the second line
  */
  clock_phy_bit(dev, mgmt_value);
  /*
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK );
  */

  register_value = 0;

  /* Read in the data */
  for(i=15;i>=0;i--) 
  {
    clock_phy_bit(dev, mgmt_value);
    register_value |= 
      ((IORD_FREEDEV_LAN91C111_MGMT(dev->base_addr) 
       & FREEDEV_LAN91C111_MGMT_MDI_MSK) >> 1) << i;
  }

  /* Output the Turnaround bit */
  clock_phy_bit(dev, mgmt_value);

  IOWR_FREEDEV_LAN91C111_MGMT(dev->base_addr, mgmt_value);

  IOWR_FREEDEV_LAN91C111_BSR( dev->base_addr,old_bank);

  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, (" %#x\n", register_value));
  return register_value;
}

/*
* Write to a PHY register, this involves manually clocking out lots
* of data.
*/
static void write_phy_register(freedev_lan91c111_if* dev, 
                        const unsigned phy_register,
                        const alt_u16 value)
{
  alt_u16 old_bank;
  alt_u16 mgmt_value;
  int i;

  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("write_phy_register (%d, %#x)\n", phy_register, value));

  /*
  * Swap to bank 3, if this code is ever changed to run with interrups we will
  * need a critical section here
  */
  old_bank = IORD_FREEDEV_LAN91C111_BSR(dev->base_addr);
  IOWR_FREEDEV_LAN91C111_BSR( dev->base_addr,3);

  mgmt_value = IORD_FREEDEV_LAN91C111_MGMT(dev->base_addr);
  mgmt_value &= 0xfff0;

  /* Output an Idle of 32 1's */
  for(i=0;i<32;i++) 
  {
    clock_phy_bit(dev, mgmt_value | 
                                  FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                  FREEDEV_LAN91C111_MGMT_MDO_MSK );
  }

  /* Ouput 01 which marks the change of cycle */
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK );
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                    FREEDEV_LAN91C111_MGMT_MDO_MSK );
  
  /* Output the command, 01 = write */
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK );
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                    FREEDEV_LAN91C111_MGMT_MDO_MSK );


  /* Output the PHY address, 0 is the internal PHY */
  for(i=0;i<5;i++) 
  {
    clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK );
  }

  /* Write the Register Address, MSB first */
  for(i=4;i>=0;i--) 
  {
    clock_phy_bit(dev, mgmt_value | 
                                  FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                  ((phy_register >> i) & 0x1));
  }

  /* Write 10 to the turnaround bit */
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK | 
                                    FREEDEV_LAN91C111_MGMT_MDO_MSK );
  clock_phy_bit(dev, mgmt_value | 
                                    FREEDEV_LAN91C111_MGMT_MDOE_MSK );

  /* Now write the data MSB first */

⌨️ 快捷键说明

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