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

📄 ne2000.c

📁 基于nucleus操作系统的GPRS无线数据传输终端全套源文件。包括支持ARM7的BSP,操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
     * Counter overflow and Remote DMA complete are *not* enabled.
     */
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_IMR), NORMAL_NE2000_INTS);

    /* Program command register for page 1.   */
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_1 | NE2000_CR_STP);

    /* Copy out our station (ethernet) address.   */
    for (i = 0; i < ETH_ALEN; ++i)
        OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_PAR0) + i, my_hw_addr[i]);

    /* Set current page pointer to next_packet (initialized above).   */
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_CURR), sc->next_packet);


    /* Set multicast filter on chip.            */
    /* If none needed lenmclist will be zero    */
    //ne2000_getmcaf((PFBYTE) pi->mcast.mclist, pi->mcast.lenmclist, 
    //            mcaf);

    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR0), mcaf[0]);
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR1), mcaf[1]);
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR2), mcaf[2]);
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR3), mcaf[3]);
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR4), mcaf[4]);
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR5), mcaf[5]);
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR6), mcaf[6]);
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_MAR7), mcaf[7]);


    /* ====================                    */
    /* Program command register for page 0.    */
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STP);

    /* set broadcast mode                     */
    /* NOTE: promiscous mode is not supported */
	/*  i = NE2000_RCR_AB;   */

    /* Accept multicasts and broadcasts   */
	//    i = NE2000_RCR_AB | NE2000_RCR_AM;
	i = NE2000_RCR_AB | NE2000_RCR_AM | NE2000_RCR_PRO;
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_RCR), i);

    /* Take interface out of loopback.   */
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TCR), 0);
    /* Fire up the interface.   */
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);

    NU_Control_Interrupts(previous_int_value);
}

/* ********************************************************************   */
/* INTERRUPT routines.                                                    */
/* ********************************************************************   */ 
/* handle interrupts - this is the interrupt routine   */
void ne2000_interrupt(int minor_no)   /*__fn__*/
{
PNE2000_SOFTC sc;
UINT8          isr;
int           error;

    sc = off_to_softc();
    if (!sc)
        return;

	//ks_enable();  

    /* Set NIC to page 0 registers.   */
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);

    /* get interrupt status register   */
    isr = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_ISR));

    /* Loop until there are no more new interrupts.   */
    while (isr)
    {
        /*
         * Reset all the bits in the interrupt status register that we 
         * are 'acknowledging' by writing a '1' to each bit position 
         * that was set. (Writing a '1' *clears* the bit.)
         */
        OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_ISR), isr);

        /* ******   */
        /*
         * Handle transmitter interrupts.  Handle these first because
         * the receiver will reset the board under some conditions.
         */
        if (isr & (NE2000_ISR_PTX | NE2000_ISR_TXE)) /* pkt xmit or xmit error */
        {
            int collisions = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_NCR)) & 0x0f;

            /*
             * Check for transmit error.  If a TX completed with an
             * error, we end up throwing the packet away.  Really
             * the only error that is possible is excessive
             * collisions, and in this case it is best to allow the
             * automatic mechanisms of TCP to backoff the flow.  Of
             * course, with UDP we're screwed, but this is expected
             * when a network is heavily loaded.
             */
            error = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TSR));
            if ( (isr & NE2000_ISR_TXE) || 
                 (error & (NE2000_TSR_CDH | NE2000_TSR_CRS)) )
            {
                /* if transmit aborted (NE2000_TSR_ABT) due to excessive collisions,   */
                /* if collisions is 0 it really is 16 (excessive collisions)           */
                if (error & NE2000_TSR_ABT)
                {
                    sc->stats.collision_errors++;
                }

                /* Update output errors counter.   */
                sc->stats.errors_out++;

                //pi->xmit_status = ENETDOWN;
            } 
            else        /* no transmit error */
            {
                /* check for out of window collsions   */
                if (INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TSR)) & NE2000_TSR_OWC)
                    sc->stats.owc_collision++;
                if (collisions == 1)
                    sc->stats.one_collision++;
                else if (collisions >= 1)
                    sc->stats.multiple_collisions++;
                if (INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_TSR)) & NE2000_TSR_CRS) 
                    sc->stats.tx_carrier_errors++;
            }
            
            /* signal IP layer or driver that send is done   */
            //ks_invoke_output(/*pi*/);
            NU_Activate_HISR(&Ether_Xmit);
        }       /* pkt xmit or xmit error */

        /* ******                         */
        /* Handle receiver interrupts.    */
        if (isr & (NE2000_ISR_PRX | NE2000_ISR_RXE | NE2000_ISR_OVW)) 
        {
            /*
            * Overwrite warning.  In order to make sure that a
            * lockup of the local DMA hasn't occurred, we reset
            * and re-init the NIC.  The NSC manual suggests only a
            * partial reset/re-init is necessary - but some chips
            * seem to want more.  The DMA lockup has been seen
            * only with early rev chips - Methinks this bug was
            * fixed in later revs.  -DG
            */
            if (isr & NE2000_ISR_OVW) 
            {
                sc->stats.rx_overwrite_errors++;
                sc->stats.rx_other_errors++;
                sc->stats.errors_in++;

                /* Recover from ring buffer overflow.                    */
                /* disable sends and receives while recovery in progress */
                sc->do_recovery = NU_Retrieve_Clock();//ks_get_ticks();
        
                /* disable all interrupts   */
                OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_IMR), 0);

                /* save whether xmit is in progress   */
                sc->tpx = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR)) & NE2000_CR_TXP;

                /* STOP command to NIC; also set to page 0   */
                OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_STP | NE2000_CR_PAGE_0);
                /* Timer task will do the rest   */
            } 
            else 
            {
                /* Process Receiver Error.  One or more of:    */
                /*    CRC error,                               */
                /*    frame alignment error                    */
                /*    FIFO overrun, or                         */
                /*    missed packet.                           */
                /*                                             */
                if (isr & NE2000_ISR_RXE) 
                {
                    sc->stats.errors_in++;
                    sc->stats.rx_other_errors++;
                }

                /* Go get the packet(s).                        */
                /* - Doing this on an error is dubious          */
                /*   because there shouldn't be any data to get */
                /*   (we've configured the interface to not     */
                /*   accept packets with errors).               */
                /*                                              */
                /* process the receiver interrupt               */
                if (!sc->do_recovery)
                {
                    ne2000_read_ring_pkt(sc, TRUE);
                }
            }
        }           /* end receive interrupts */

        /*
         * Return NIC CR to standard state: page 0, remote DMA
         * complete, start (toggling the TXP bit off, even if was just
         * set in the transmit routine, is *okay* - it is 'edge'
         * triggered from low to high).
         */
        OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);

        /*
         * If the Network Talley Counters overflow, read them to reset
         * them.  It appears that old 8390's won't clear the ISR flag
         * otherwise - resulting in an infinite loop.
         */
        if (isr & NE2000_ISR_CNT) 
        {
            (void) INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CNTR0));
            (void) INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CNTR1));
            (void) INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CNTR2));
        }

        /* get isr for next loop   */
        isr = INBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_ISR));
    }       /* end of while(isr) */
}

/* ********************************************************************   */
/*
 * Retreive packet from shared memory and send to the next level up via
 * the input list. 
 */
 
UINT8    TEMP_BUF_R[2000];

void ne2000_get_packet(PNE2000_SOFTC sc, UINT16 nic_buf, int len, BOOLEAN rint)
{
PFBYTE msgdata;
int tmp_amount;
DV_DEVICE_ENTRY   *device;
int blen = len;

	msgdata = TEMP_BUF_R;		

    /* Allocate a packet to write the ethernet packet in.   */
    //msg = os_alloc_packet_input(len, DRIVER_ALLOC);
    //if (!msg)    
    //{
        //DEBUG_ERROR("ne2000_get_packet() - out of DCUs", NOVAR, 0, 0);
        //if (rint)
        //    sc->stats.packets_lost++;
        //return;
    //}

    /* write ethernet header to packet   */
    //msgdata = DCUTODATA(msg);
    ne2000_pio_readmem(sc, nic_buf, msgdata, sizeof(struct _ether));
    nic_buf = (UINT16)(nic_buf + sizeof(struct _ether));
    msgdata += sizeof(struct _ether);
    //DCUTOPACKET(msg)->length = len; 

    /* Pull packet off interface and put into packet.   */
    len -= sizeof(struct _ether);

    /* Handle wrap here   */
    if (nic_buf + len > sc->mem_end) 
    {
        tmp_amount = sc->mem_end - nic_buf;
        /* Copy amount up to end of NIC memory.   */
        ne2000_pio_readmem(sc, nic_buf, msgdata, tmp_amount);
        len -= tmp_amount;
        nic_buf = sc->mem_ring;
        msgdata += tmp_amount;
    }
    ne2000_pio_readmem(sc, nic_buf, msgdata, len);

    if (rint)
    {
        /* Pull packet off interface and put into packet.   */
        sc->stats.packets_in++;
        sc->stats.bytes_in += len;  
		
		et_data_ptr =  (UINT32)TEMP_BUF_R; 
        et_data_len = blen;
    	
    	device = DEV_Get_Dev_By_Name("RTL8019");
        device->dev_receive(device);
    }
    //else
    //    os_free_packet(msg);
}

/* ********************************************************************   */
/* Ethernet interface receiver interrupt.                                 */
/* ********************************************************************   */

void ne2000_read_ring_pkt(PNE2000_SOFTC sc, BOOLEAN rint)
{
UINT16 boundary;
int  len;
struct ne2000_ring packet_hdr; 
UINT16 nic_packet_ptr;

    /* Set NIC to page 1 registers to get 'current' pointer.   */
    OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_1 | NE2000_CR_STA);

    /*
     * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
     * it points to where new data has been buffered.  The 'CURR' (current)
     * register points to the logical end of the ring-buffer - i.e. it
     * points to where additional new data will be added.  We loop here
     * until the logical beginning equals the logical end (or in other
     * words, until the ring-buffer is empty).
     */
    while (sc->next_packet != INBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_CURR))) 
    {
        /* Get pointer to this buffer's header structure.   */
        nic_packet_ptr = (UINT16)(sc->mem_ring + 
                                (sc->next_packet - sc->rec_page_start) * 
                                NE2000_PAGE_SIZE);

        /*
         * The UINT8 count includes a 4 UINT8 header that was added by
         * the NIC.
         */
        ne2000_pio_readmem(sc, nic_packet_ptr, (PFBYTE) &packet_hdr, 
                           sizeof(packet_hdr));

        len = (int)packet_hdr.count;

        /* Go get packet from shared memory, put it in a DCU and send it to 
           input exchange. */
        /* Adjust the pointer to the data to point past the header and
           Subtract the size of the CRC from the length */
        if (len <= ETHER_MAX_LEN)
        {
            ne2000_get_packet(sc, 
                    (UINT16)(nic_packet_ptr + sizeof(struct ne2000_ring)),
                    len - CRC_LEN, rint);
        } 

        /* Update next packet pointer.   */
        sc->next_packet = packet_hdr.next_packet;

        /*
         * Update NIC boundary pointer - being careful to keep it one
         * buffer behind (as recommended by NS databook).
         */
        boundary = (UINT16) (sc->next_packet - 1);
        if (boundary < sc->rec_page_start)
            boundary = (UINT16) (sc->rec_page_stop - 1);

        /* Set NIC to page 0 registers to update boundary register.   */
        OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P1_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_0 | NE2000_CR_STA);
        OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_BNRY), boundary);

        /*
         * Set NIC to page 1 registers before looping to top (prepare
         * to get 'CURR' current pointer).
         */
        OUTBYTE(REF_REG_ADDR(nic_addr_NE2000_P0_CR), NE2000_CR_RD2 | NE2000_CR_PAGE_1 | NE2000_CR_STA);
    }
}

/* ********************************************************************   */
/* RING BUFFER OVERFLOW RECOVERY                                          */
/* ********************************************************************   */

/* perform recovery for ring buffer overflow as suggested by             */
/* National Semiconductor DP8390D/NS32490D NIC Network Interface         */
/* Controller (September 1992) Document                                  */
/* NOTE: the rest of the recovery definatly cannot be done during        */
/* the interrupt due to the delay within the recovery code, therefore,   */
/* it is broken off in this routine just in case recovery ever attempted */
/* at the interrupt level                                                */
void ne2000_ring_overflow_recovery2(void)       /*__fn__*/
{
int resend;
PNE2000_SOFTC sc;
int       softc_off;

    //for (softc_off=0; softc_off<CFG_NUM_NE2000; softc_off++)
    {
        sc = (PNE2000_SOFTC) &ne2000softc[softc_off];

        //if (sc->do_recovery)
        //    break;
    }

    /* we have to wait at least 1.6 miliseconds to do ring overflow
       here we assume that 2 ticks is at least 1.6 milliseconds to
       save space on calculating time elapsed 

⌨️ 快捷键说明

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