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

📄 freedev_lan91c111.c

📁 lan91c111网络接口的设计 包括功能设计文件和驱动程序文件
💻 C
📖 第 1 页 / 共 3 页
字号:
   *  
   */
  if (alt_irq_register ( dev->irq, dev, 
                          freedev_lan91c111_irq))
  {
    ret_code = ERR_IF;
    goto exit;
  }
  else
  {
#if LINK_STATS
      IOWR_FREEDEV_LAN91C111_MSK(dev->base_addr, 
                            FREEDEV_LAN91C111_INT_RCV_INT_MSK |
                            FREEDEV_LAN91C111_INT_RX_OVRN_INT_MSK);
#else
      IOWR_FREEDEV_LAN91C111_MSK(dev->base_addr, 
                            FREEDEV_LAN91C111_INT_RCV_INT_MSK);

#endif /* LINK_STATS */
  }

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

  return ret_code;
 
}

/*
* 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
*/

/*-----------------------------------------------------------------------------------* 
 *
 * 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.
 *
 * 
 * This funciton should be changed to use all the available transmit
 * packets in the Lan91C111
 *-----------------------------------------------------------------------------------*/

static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
  struct pbuf *q;
  int total_length_sent = 0;
  int i, unaligned, end, base;
  alt_u8 irq_value, *datap;
  alt_u16 mmu_status, ptr_status;
  freedev_lan91c111_if *dev = netif->state;

  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_output ( %#x)\n",p));

  /* Wait for the last Tx to complete */
  do 
  {
    irq_value = IORD_FREEDEV_LAN91C111_IST(dev->base_addr);
  }while(!(irq_value & FREEDEV_LAN91C111_INT_TX_EMPTY_INT_MSK));

  /* Clear the interrupt */
  IOWR_FREEDEV_LAN91C111_ACK( dev->base_addr, 
                                    FREEDEV_LAN91C111_INT_TX_EMPTY_INT_MSK);


  /* Always re-use the same packet */
  IOWR_FREEDEV_LAN91C111_PNR( dev->base_addr, 
                                    dev->tx_packet_no);

  /*
  * The Pointer Register and the MMUCR register are used in both TX and RX and are context sensitive, so 
  * protect them with a semaphore
  */
  sys_sem_wait(dev->semaphore);

  do 
  {
    ptr_status = IORD_FREEDEV_LAN91C111_PTR( dev->base_addr);
  }while (ptr_status & FREEDEV_LAN91C111_PTR_NOT_EMPTY_MSK);

  
  IOWR_FREEDEV_LAN91C111_PTR( dev->base_addr,
                                    FREEDEV_LAN91C111_PTR_AUTO_INCR_MSK);

  /* The status word */
  IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr, 0);

  /* 
  * The byte count including the 6 control bytes 
  *
  * Bit odd this, but the length is always written as even, if the frame is an odd length
  * then the byte is written as one of the control words and an appropriate bit is set
  *
  */
  IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr, ((p->tot_len & ~1) + 6));

  for(q = p; q != NULL; q = q->next) 
  {
    /* 
    * Write each buffer of data to the device
    *
    * Nios requres accesses to be aligned on the correct boundary
    * 
    * You could just do this with 
    * for(i=0;i<q->len;i++)
    *   write_register8( dev, DATA_OFFSET, *(alt_u8*)(q->payload+i));
    *
    * But this is more efficient
    */

    unaligned = ((int)q->payload) % 4;
    unaligned = (4 - unaligned) % 4;

    switch (unaligned)
    {
      case 3:
        IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
                                      *(alt_u8*)q->payload);
        IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr,
                                      *((alt_u16*)((alt_u8*)q->payload + 1)));
        break;
      case 2:
        IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr,
                                      *(alt_u16*)q->payload);
        break;
      case 1:
        IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
                                      *(alt_u8*)q->payload);
        break;
    }

   datap = q->payload;
   end = q->len-3 ;
   base = dev->base_addr;
   for (i=unaligned;i<end;i+=4) {
    
       IOWR_FREEDEV_LAN91C111_DATA_WORD( base,
                                         *((u32_t *)(datap+i)));     
    }

    switch (q->len - i){
      case 3:
        IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr,
                                      *((alt_u16*)((alt_u8*)q->payload + q->len - 3)));
        IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
                                      *((alt_u8*)((alt_u8*)q->payload + q->len -1)));
        break;
      case 2: 
        IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr,
                                      *((alt_u16*)((alt_u8*)q->payload + q->len - 2)));
        break;
      case 1:
        IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
                                      *((alt_u8*)((alt_u8*)q->payload + q->len -1)));
        break;
    }

    total_length_sent += q->len;

    /*
    * Last buffer in the packet?
    */
    if (total_length_sent == p->tot_len) 
    {
      if (p->tot_len & 1) 
      {
        IOWR_FREEDEV_LAN91C111_DATA_BYTE( dev->base_addr,
                                    FREEDEV_LAN91C111_CONTROL_ODD_MSK);
      }
      else 
      {
        IOWR_FREEDEV_LAN91C111_DATA_HW( dev->base_addr, 0);
      }
    }
  }

  /* Wait for any pending commands to complete */
  do 
  {
    mmu_status = IORD_FREEDEV_LAN91C111_MMUCR(dev->base_addr);
  }while (mmu_status & FREEDEV_LAN91C111_MMUCR_BUSY_MSK);

  /* Queue the packet */
  IOWR_FREEDEV_LAN91C111_MMUCR( dev->base_addr,
                                  FREEDEV_LAN91C111_MMUCR_ENQUEUE_MSK);
  sys_sem_signal(dev->semaphore);

#if LINK_STATS
  lwip_stats.link.xmit++;
#endif /* LINK_STATS */      
  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_ouptput () return OK\n"));


  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(freedev_lan91c111_if *dev)
{
  struct pbuf *p=NULL, *q;
  alt_u32 status;
  alt_u16 packet_number, mmu_status, ptr_status;
  int length, i, unaligned, end, base;
  alt_u8 *data_ptr; 

  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_input()\n"));

  packet_number = IORD_FREEDEV_LAN91C111_RX_FIFO(
                                              dev->base_addr);
  if ( packet_number & FREEDEV_LAN91C111_RX_FIFO_REMPTY_MSK ) 
  {
    LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_input (exits p =0)\n"));
    return 0;
  }

  /*
  * The Pointer Register and the MMUCR register are used in both TX and RX and are context sensitive, so 
  * protect them with a semaphore
  */
  sys_sem_wait(dev->semaphore);

  do 
  {
    ptr_status = IORD_FREEDEV_LAN91C111_PTR( dev->base_addr);
  }while (ptr_status & FREEDEV_LAN91C111_PTR_NOT_EMPTY_MSK);

  
  IOWR_FREEDEV_LAN91C111_PTR( dev->base_addr,
                                    FREEDEV_LAN91C111_PTR_READ_MSK |
                                    FREEDEV_LAN91C111_PTR_AUTO_INCR_MSK |
                                    FREEDEV_LAN91C111_PTR_RCV_MSK);

  /* The first two half-words are status and byte count */
  status = IORD_FREEDEV_LAN91C111_DATA_WORD(dev->base_addr);
  length = (status & 0xffff0000ul) >> 16;
  status &= 0xffff;

  if (status & (FREEDEV_LAN91C111_RS_TOO_SHORT_MSK | 
                FREEDEV_LAN91C111_RS_TOO_LONG_MSK | 
                FREEDEV_LAN91C111_RS_BAD_CRC_MSK | 
                FREEDEV_LAN91C111_RS_ALGN_ERR_MSK))  
  {
#if LINK_STATS
    lwip_stats.link.drop++;
#endif /* LINK_STATS */
  }
  else 
  {
    /* We've already read two of the words */
    length -= 4;

    /* We allocate a pbuf chain of pbufs from the pool. */
    p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
    if (p != NULL) 
    {
      /* We iterate over the pbuf chain until we have read the entire
         packet into the pbuf. */
      for(q = p; q != NULL; q = q->next) 
      {

        /* 
        * Fill each buffer in the chain
        *
        * On Nios all the memory accesses must be aligned 
        */

        unaligned = (int)q->payload % 4;
        unaligned = (4 - unaligned) % 4;

        switch (unaligned)
        {
        case 3:
          *((alt_u8*)q->payload) = 
            IORD_FREEDEV_LAN91C111_DATA_BYTE(dev->base_addr);
          *((alt_u16*)((alt_u8*)q->payload+1)) = 
            IORD_FREEDEV_LAN91C111_DATA_HW(dev->base_addr);
          break;
        case 2:
          *((alt_u16*)q->payload) = 
            IORD_FREEDEV_LAN91C111_DATA_HW(dev->base_addr);
          break;
        case 1:
          *((alt_u8*)q->payload) = 
            IORD_FREEDEV_LAN91C111_DATA_BYTE(dev->base_addr);
          break;
        }

        end = q->len-3;
        data_ptr = q->payload;
        base = dev->base_addr;
        for (i = unaligned; i < end; i+= 4)
        {
          *((u32_t*)((alt_u8*)data_ptr + i)) = 
            IORD_FREEDEV_LAN91C111_DATA_WORD(base);
        }

        switch (q->len - i)
        {
        case 3:
          *((alt_u16*)((alt_u8*)q->payload + i)) = 
            IORD_FREEDEV_LAN91C111_DATA_HW(dev->base_addr);
          *((alt_u8*)((alt_u8*)q->payload + i + 2)) = 
            IORD_FREEDEV_LAN91C111_DATA_BYTE(dev->base_addr);
          break;
        case 2:
          *((alt_u16*)((alt_u8*)q->payload + i)) = 
            IORD_FREEDEV_LAN91C111_DATA_HW(dev->base_addr);
          break;
        case 1:
          *((alt_u8*)((alt_u8*)q->payload + i)) = 
            IORD_FREEDEV_LAN91C111_DATA_BYTE(dev->base_addr);
          break;
        }
      }

#if LINK_STATS
      lwip_stats.link.recv++;
#endif /* LINK_STATS */      
    } 
    else 
    {
#if LINK_STATS
      lwip_stats.link.memerr++;
      lwip_stats.link.drop++;
#endif /* LINK_STATS */      
    }
  }

  /* Wait for any pending commands to complete */
  do 
  {
    mmu_status = IORD_FREEDEV_LAN91C111_MMUCR(dev->base_addr);
  }while (mmu_status & FREEDEV_LAN91C111_MMUCR_BUSY_MSK);

  /* Just get rid of the packet */
  IOWR_FREEDEV_LAN91C111_MMUCR(dev->base_addr,
            FREEDEV_LAN91C111_MMUCR_REMOVE_RELEASE_MSK);
  sys_sem_signal(dev->semaphore);

  LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_input (exits p =%#x)\n", p));
  return p;  
}


/*-----------------------------------------------------------------------------------* 
 *
 * freedev_lan91c111_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 actuall transmission of the packet.
 *
 * 
 *-----------------------------------------------------------------------------------*/
static err_t
freedev_lan91c111_output(struct netif *netif, struct pbuf *p,
      struct ip_addr *ipaddr)
{
  err_t err;
  freedev_lan91c111_if* dev = (freedev_lan91c111_if*)netif->state;

  sys_sem_wait(dev->arp_semaphore);

  /* 
  * resolve hardware address, then send (or queue) packet 
  * 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
  * 
  */
  
  err = etharp_output(netif, ipaddr, p);
  sys_sem_signal(dev->arp_semaphore);

  return err;
}

/*
* 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
*/
#endif

⌨️ 快捷键说明

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