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

📄 ctrl_rtl8019.c

📁 基于康草科技中一款SOPC开发板上的8019的以太网驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
        if (nextpg1 != hdr.ph_nextpg) {
            return NULL;
        }
        nextpg = nextpg1;
    }
    
    
    /*
     * Check packet status. It should have set bit 0, but
     * even without this bit packets seem to be OK.
     */
    if (!drop && ((hdr.ph_status & 0x0E) == 0)) {
        /*
         * Allocate a NETBUF.
         * Omit the fcs.
         */
        count = hdr.ph_size - 4;
        /* We allocate a pbuf chain of pbufs from the pool. */
    	p = pbuf_alloc(PBUF_RAW, count, PBUF_POOL);
        if (p != NULL ) {
            /*
             * Set remote dma byte count and
             * start address. Don't read the
             * header again.
             */
            IOWR_CTRL_RTL8019_RBCR0(dev->base_addr,count);
            IOWR_CTRL_RTL8019_RBCR1(dev->base_addr,count >> 8);
            IOWR_CTRL_RTL8019_RSAR0(dev->base_addr,sizeof(struct nic_pkt_header));
            IOWR_CTRL_RTL8019_RSAR1(dev->base_addr,bnry);

            /*
             * Perform the read.
             */
            IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_RD0_MSK);
            Delay16Cycles();
            for(q = p; q != NULL; q = q->next) 
      	    {
            	NicRead(dev->base_addr,q->payload, q->len);
            }
            NicCompleteDma(dev->base_addr);
        }
    }

    /*
     * Set boundary register to the last page we read.
     * This also drops packets with errors
     */
    if (--nextpg < NIC_FIRST_RX_PAGE)
        nextpg = NIC_STOP_PAGE - 1;
    IOWR_CTRL_RTL8019_BNRY(dev->base_addr,nextpg);
      
    return p;
}

/*!
 * Load a packet into the nic's transmit ring buffer.
 *
 *
 * param base NIC hardware base address.
 * param nb Network buffer structure containing the packet to be sent.
 *           The structure must have been allocated by a previous
 *           call NutNetBufAlloc().
 *
 * return 0 on success, -1 in case of any errors. Errors
 *         will automatically release the network buffer
 *         structure.
 */
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
    struct pbuf *q;
    ctrl_rtl8019_if *dev = netif->state;
    u_short i;
    u_char padding = 0;
    unsigned short int size;
    

    LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_output ( %#x)\n",p));
    
    size=0;
    for(q = p; q != NULL; q = q->next) 
    {
        size+=q->len;
    }
    
    /*
     * Calculate the number of bytes to be send. Do not
     * send packets larger than 1514 bytes.
     *
     * The previous version was wrong by specifying a maximum
     * of 1518, because it didn't take the CRC into account,
     * which is generated by the hardware and automatically
     * appended. Thanks to Bengt Florin, who discovered this.
     */
    if (size > 1514)
        return -1;

    /*
     * The controller will not append pad bytes,
     * so we have to do this.
     */
    if (size < 60) {
        padding = (u_char) (60 - p->tot_len);
        size = 60;
    }

    /*
     * Bengt Florin introduces polling mode for the transmitter. Be
     * aware, that this may introduce other problems. If a high
     * priority thread is waiting for the transmitter, it may hold
     * the CPU for more than 1.2 milliseconds in worst cases.
     */
     
    /*
     while (NICINB(NIC_CR) & NIC_CR_TXP)
        NutThreadYield();
    */

    /* we don't want to be interrupted by NIC owerflow */
    //irq_context=alt_irq_disable_all();

    /*
     * Set remote dma byte count
     * and start address.
     */
    IOWR_CTRL_RTL8019_RBCR0(dev->base_addr, size);
    IOWR_CTRL_RTL8019_RBCR1(dev->base_addr, size >> 8);
    IOWR_CTRL_RTL8019_RSAR0(dev->base_addr,0);
    IOWR_CTRL_RTL8019_RSAR1(dev->base_addr,NIC_FIRST_TX_PAGE);

    /*
     * Peform the write.
     */
    IOWR_CTRL_RTL8019_CR(dev->base_addr, CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_RD1_MSK);

    /*
     * Transfer the Ethernet frame.
     */
    for(q = p; q != NULL; q = q->next) 
    {
        NicWrite(dev->base_addr,q->payload, q->len);
    }
    
    /*
     * Add pad bytes.
     */
    for (i = 0; i < padding; i++)
        IOWR_CTRL_RTL8019_DATA(dev->base_addr,0);

    /*
     * Complete remote dma.
     */
    NicCompleteDma(dev->base_addr);

    /*
     * Number of bytes to be transmitted.
     */
    IOWR_CTRL_RTL8019_TBCR0(dev->base_addr,(size & 0xff));
    IOWR_CTRL_RTL8019_TBCR1(dev->base_addr,((size >> 8) & 0xff));

    /*
     * First page of packet to be transmitted.
     */
    IOWR_CTRL_RTL8019_TPSR(dev->base_addr,NIC_FIRST_TX_PAGE);

    /*
     * Start transmission.
     */
    IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_TXP_MSK | CTRL_RTL8019_CR_RD2_MSK);

    LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_ouptput () return OK\n"));
    return 0;
}


/*
 * \brief Handle NIC overflows.
 *
 * When a receiver buffer overflow occurs, the NIC will defer any subsequent
 * action until properly restarted.
 *
 * This routine is called within interrupt context, which introduces a big
 * problem. It waits for the last transmission to finish, which may take
 * several milliseconds. Since Nut/OS 3.5, we do not support nested interrupts
 * on AVR systems anymore. So this routine may now increase interrupt
 * latency in an unacceptable way. The solution might be to handle overflows
 * in the receiver thread.
 *
 * In any case, this routines needs a major redesign. But it has been
 * tested in its current form to gracefully withstand ping floods. Thanks
 * to Bengt Florin for contributing his code, which provides much more
 * stability than its predecessor.
 */
u_char NicOverflow(ctrl_rtl8019_if *dev)
{
    u_char cr;
    u_char resend = 0;
    u_char curr;

    /*
     * Wait for any transmission in progress. Save the command register,
     * so we can later determine, if NIC transmitter has been interrupted.
     * or reception in progress.
     */
    while (IORD_CTRL_RTL8019_CR(dev->base_addr) & CTRL_RTL8019_CR_TXP_MSK);
    cr = IORD_CTRL_RTL8019_CR(dev->base_addr);

    /*
     * Get the current page pointer. It points to the page where the NIC
     * will start saving the next incoming packet.
     */
    IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STP_MSK | CTRL_RTL8019_CR_RD2_MSK | CTRL_RTL8019_CR_PS0_MSK);
    curr = IORD_CTRL_RTL8019_CURR(dev->base_addr);
    IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STP_MSK | CTRL_RTL8019_CR_RD2_MSK);

    /* Clear remote byte count register. */
    IOWR_CTRL_RTL8019_RBCR0(dev->base_addr,0);
    IOWR_CTRL_RTL8019_RBCR1(dev->base_addr,0);

    /* Check for any incomplete transmission. */
    if ((cr & CTRL_RTL8019_CR_TXP_MSK) && ((IORD_CTRL_RTL8019_ISR(dev->base_addr) & (CTRL_RTL8019_ISR_PTX_MSK | CTRL_RTL8019_ISR_TXE_MSK)) == 0))
    {
        resend = 1;
    }

    /* Enter loopback mode and restart the NIC. */
    IOWR_CTRL_RTL8019_TCR(dev->base_addr,CTRL_RTL8019_TCR_LB0_MSK);
    IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_RD2_MSK);

    /*
     * Discard all packets from the receiver buffer. Set boundary
     * register to the last page we read.
     */
    if (--curr < NIC_FIRST_RX_PAGE) {
        curr = NIC_STOP_PAGE - 1;
    }
    IOWR_CTRL_RTL8019_BNRY(dev->base_addr,curr);

    /* Switch from loopback to normal mode mode. */
    IOWR_CTRL_RTL8019_TCR(dev->base_addr,0);

    /* Re-invoke any interrupted transmission. */
    if (resend) {
        IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_TXP_MSK | CTRL_RTL8019_CR_RD2_MSK);
    }

    /* Finally clear the overflow flag */
    IOWR_CTRL_RTL8019_ISR(dev->base_addr,CTRL_RTL8019_ISR_OVW_MSK);
    return resend;
}

/*
 * \brief NIC interrupt entry.
 */
void ctrl_rtl8019_irq(void* context, alt_u32 interrupt)
{
    u_char isr;
    
    int rx_frame_errors;
    int rx_crc_errors;
    int rx_missed_errors;
    ctrl_rtl8019_if *dev =  (ctrl_rtl8019_if *)context;
    
    isr = IORD_CTRL_RTL8019_ISR(dev->base_addr);
    IOWR_CTRL_RTL8019_ISR(dev->base_addr,0xff);

    /*
     * Recover from receive buffer overflow. This may take some
     * time, so we enable global interrupts but keep NIC
     * interrupts disabled.
     */
    if (isr & CTRL_RTL8019_ISR_OVW_MSK) {
        NicOverflow(dev);
    } else {
        /*
         * If this is a transmit interrupt, then a packet has been sent.
         * So we can clear the transmitter busy flag and wake up the
         * transmitter thread.
         */
        if (isr & CTRL_RTL8019_ISR_TXE_MSK);

        /*
         * If this is a receive interrupt, then wake up the receiver
         * thread.
         */
        if (isr & CTRL_RTL8019_ISR_PRX_MSK){
        	sys_mbox_post(rx_mbox, &dev->lwip_dev_list.dev);
        }

        if (isr & CTRL_RTL8019_ISR_RXE_MSK) {
            rx_frame_errors += IORD_CTRL_RTL8019_CNTR0(dev->base_addr);
            rx_crc_errors += IORD_CTRL_RTL8019_CNTR1(dev->base_addr);
            rx_missed_errors += IORD_CTRL_RTL8019_CNTR2(dev->base_addr);
        }
    }
}

/*-----------------------------------------------------------------------------------* 
 *
 * ctrl_rtl8019_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
ctrl_rtl8019_output(struct netif *netif, struct pbuf *p,
      struct ip_addr *ipaddr)
{
  err_t err;
  ctrl_rtl8019_if* dev = (ctrl_rtl8019_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;
}

#endif

⌨️ 快捷键说明

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