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

📄 lan91c111.c

📁 Analog公司的ADSP_BF532上面实现以太网接口的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#endif

    // bank 2 already opened by main IRQ entry

    packet_number = _inpw(FIFO_REG);

    if ( packet_number & RXFIFO_REMPTY ) {
        // we got called , but nothing was on the FIFO
        // so, just leave
        return;
    }

    //  start reading from the start of the packet
    _outpw(PTR_REG, PTR_READ | PTR_RCV | PTR_AUTOINC);

    // First two words are status and packet_length
    status          = _inpw(DATA_REG);
    packet_length   = _inpw(DATA_REG);

    // store for debug
    LAN_state.rpsize = packet_length;

    // max 2k packets over Ethernet
    packet_length &= 0x07ff;  /* mask off top bits */

    if ( !(status & RS_ERRORS ) ){

#ifdef log_net_errs
        if ( status & RS_MULTICAST ) stats.multicast++;
#endif

        // collect the packet
        // first two words already read: status and packet size
        packet_length -= 4;

        if (!LAN_rx_packet.busy) {
            //store packet length
            LAN_rx_packet.length = packet_length;
            // flag buffer in use and pkt avail
            LAN_rx_packet.busy = 1;
            // assign pointer
            data = LAN_rx_packet.data;
            // global flag
            LAN_pkt_avail = 1;
        } else {
#ifdef log_net_errs
            stats.rx_dropped++;
#endif
            // drop packet
            goto done;
        }

#ifndef USE_16_BIT
        // read in 32bits
        for (i=0; i <= (packet_length >> 2); i++)
        {
            *data++ = _inpd(DATA_REG);
        }
#else
        for (i=0; i <= (packet_length >> 1); i++)
        {
            *data++ = _inpw(DATA_REG);
        }
#endif // USE_16_BIT
#ifdef log_net_errs
        lp->stats.rx_packets++;
#endif
    } else {
        // error ...
        LAN_error = 1;

#ifdef log_net_errs
        stats.rx_errors++;
        if ( status & RS_ALGNERR )  lp->stats.rx_frame_errors++;
        if ( status & (RS_TOOSHORT|RS_TOOLONG)) lp->stats.rx_length_errors++;
        if ( status & RS_BADCRC)    lp->stats.rx_crc_errors++;
#endif
    }

    while ( _inpw(MMU_CMD_REG ) & MC_BUSY );
done:
    //  good or bad, delete this packet */
    _outpw(MMU_CMD_REG, MC_RELEASE);

    return;
}


/******************************************************************************
 * TX IRQ Error Handler Function for SMSC91C111
 *
 * Purpose:  Handle the transmit error message.
 *  This is only called when an TX error occured because of
 *  the AUTO_RELEASE mode.
 *
 * Actions:
 *  - Save pointer and packet no
 *  - Get the packet no from the top of the queue
 *  - check if it's valid ( if not, is this an error??? )
 *  - read the status word
 *  - record the error
 *  - ( resend?  Not really, since we don't want old packets around )
 *  - Restore saved values
 *
 *****************************************************************************/
void smc_tx()
{
    BYTE saved_packet;
    BYTE packet_no;
    WORD tx_status;

    // bank 2 already opened by main IRQ entry
    saved_packet = _inp(PN_REG);
    packet_no = _inpw(FIFO_REG);
    packet_no &= 0x7F;

    // If the TX FIFO is empty then nothing to do
    if ( packet_no & TXFIFO_TEMPTY )
        return;

    // select this as the packet to read from
    _outp(PN_REG, packet_no);

    // read the first word (status word) from this packet
    _outpw(PTR_REG, PTR_AUTOINC|PTR_READ);

    // read tx status
    tx_status = _inpw(DATA_REG );

#ifdef log_net_errs
    stats.tx_errors++;
    if ( tx_status & TS_LOSTCAR ) stats.tx_carrier_errors++;
    if ( tx_status & TS_LATCOL  ) stats.tx_window_errors++;
#endif

    // re-enable transmit
    _outpw(BSR_REG, 0);
    _outpw(TCR_REG, _inpw(TCR_REG) | TCR_TXENA);

    // kill the packet
    _outpw(BSR_REG, 2);
    _outpw(MMU_CMD_REG, MC_FREEPKT);

    // one less packet waiting for me
    LAN_state.packets_waiting--;

    // Don't change Packet Number Reg until busy bit is cleared
    while ( _inpw(MMU_CMD_REG) & MC_BUSY );

    _outp(PN_REG, saved_packet);

    return;
}


/******************************************************************************
 * LANC91C111: smc_wait_to_send_packet()
 *
 * Purpose:
 *    Attempt to allocate memory for a packet, if chip-memory is not
 *    available, then tell the card to generate an interrupt when it
 *    is available.
 *
 * Actions:
 *  - if the saved_skb is not currently null, then drop this packet
 *  -   on the floor.  This should never happen, because of TBUSY.
 *  - if the saved_skb is null, then replace it with the current packet,
 *  - See if I can sending it now.
 *  - (NO): Enable interrupts and let the interrupt handler deal with it.
 *  - (YES):Send it now.
 *
 *****************************************************************************/
BYTE smc_wait_to_send_packet()
{
    WORD    length;
    WORD    numPages;
    WORD    time_out;
    volatile WORD    status;

    // set length
    length = MAX_TCP_TX_SIZE < LAN_tx_packet.length ? MAX_TCP_TX_SIZE : LAN_tx_packet.length;

    /*
     * The MMU wants the number of pages to be the number of 256 bytes
     * 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
     *
     * The 91C111 ignores the size bits, but the code is left intact
     * for backwards and future compatibility.
     *
     * Pkt size for allocating is data length +6 (for additional status
     * words, length and ctl!)
     *
     * If odd size then last byte is included in this header.
     */
    numPages = ((length & 0xfffe) + 6);
    numPages >>= 8; // Divide by 256

    if (!numPages) numPages++;

    if (numPages > 7 ) {
        // way too big packet, this is an error
        // free packet
        LAN_tx_packet.busy = 0;
        return 0;
    }
    // either way, a packet is waiting now
    LAN_state.packets_waiting++;

    // now, try to allocate the memory */
    _outpw(BSR_REG, 2);
    _outpw(MMU_CMD_REG, MC_ALLOC | numPages);

    /*
     * Performance Hack
     *
     * wait a short amount of time.. if I can send a packet now, I send
     * it now.  Otherwise, I enable an interrupt and wait for one to be
     * available.
     *
     * I could have handled this a slightly different way, by checking to
     * see if any memory was available in the FREE MEMORY register.  However,
     * either way, I need to generate an allocation, and the allocation works
     * no matter what, so I saw no point in checking free memory.
     */
//    time_out = 200; // number of iterations
    do {
        status = _inp(INT_REG);
        if ( status & IM_ALLOC_INT ) {
            /* acknowledge the interrupt */
            _outp(INT_REG, IM_ALLOC_INT);
            break;
        }
    } while (1);// --time_out );

    // too bad, no immediate allocation...
    if ( 0){//!time_out ) {
        // oh well, wait until the chip finds memory later
        smc_enable_int( IM_ALLOC_INT );

        /* Check the status bit one more time just in case */
        /* it snuk in between the time we last checked it */
        /* and when we set the interrupt bit */
        status = _inp(INT_REG );
        if ( !(status & IM_ALLOC_INT) ) return 0;

        // Looks like it did sneak in, so disable
        // the interrupt
        smc_disable_int( IM_ALLOC_INT );
    }
    // or YES - I can send the packet now..
    smc_hardware_send_packet();

    return 1;
}

/******************************************************************************
 * LANC91C111: smc_allocate_packet()
 *
 * Purpose:
 *    Attempt to allocate memory for a packet, if chip-memory is not
 *    available, then tell the card to generate an interrupt when it
 *    is available.
 *
 * Actions:
 *
 *****************************************************************************/
BYTE smc_allocate_packet()
{
    WORD    length;
    WORD    numPages;
    WORD    time_out;
    WORD    status;

    // set length
    length = MAX_TCP_TX_SIZE < LAN_tx_packet.length ? MAX_TCP_TX_SIZE : LAN_tx_packet.length;

    // clear allocation flag
    LAN_state.alloc_success = 0;

    /*
     * The MMU wants the number of pages to be the number of 256 bytes
     * 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
     *
     * Pkt size for allocating is data length +6 (for additional status
     * words, length and ctl!)
     *
     * If odd size then last byte is included in this header.
     */
    numPages = ((length & 0xfffe) + 6);
    numPages >>= 8; // Divide by 256

    if (numPages > 7 ) {
        // way too big packet, this is an error
        // free packet
        LAN_tx_packet.busy = 0;
        return 0;
    }
    // either way, a packet is waiting now
    LAN_state.packets_waiting++;

    // now, try to allocate the memory */
    _outpw(BSR_REG, 2);
    _outpw(MMU_CMD_REG, MC_ALLOC | numPages);

    /*
     * Performance Hack
     *
     * wait a short amount of time.. if I can allocate a packet now, I set
     * the flag now.  Otherwise, I enable an interrupt and wait for one to be
     * available.
     *
     */
    time_out = 200; // number of iterations
    do {
        status = _inp(INT_REG);
        if ( status & IM_ALLOC_INT ) {
            /* acknowledge the interrupt */
            _outp(INT_REG, IM_ALLOC_INT);
            break;
        }
    } while ( --time_out );

    // too bad, no immediate allocation...
    if ( !time_out )
    {
        /* Check the status bit one more time just in case */
        /* it snuk in between the time we last checked it */
        /* and when we set the interrupt bit */
        status = _inp(INT_REG );
        if ( !(status & IM_ALLOC_INT) ) return 0;
    }

    // or YES - I got my memory now...
    LAN_state.alloc_success = 1;

    return 1;
}


/******************************************************************************
 * LANC91C111: smc_hardware_send_packet
 *
 * Purpose:
 *  This sends the actual packet to the SMC9xxx chip.
 *
 * Actions:
 *  - First, see if a pending packet is available.
 *      this should NOT be called if there is none
 *  - Find the packet number that the chip allocated
 *  - Point the data pointers at it in memory
 *  - Set the length word in the chip's memory
 *  - Dump the packet to chip memory
 *  - Check if a last byte is needed ( odd length packet )
 *      if so, set the control flag right
 *  - Tell the LAn 91C111 to send it
 *  - Enable the transmit interrupt, so I know if it failed
 *  - Free the packet data if I actually sent it.
 *
 *****************************************************************************/
void    smc_hardware_send_packet()
{
    BYTE    packet_no;
    WORD    length;
    int     i;
#ifndef USE_16_BIT
    DWORD   *buf;
#else
    WORD    *buf;
#endif

    // no data to send...
    if ( !LAN_tx_packet.busy ) return;

    // get pointer
    buf = LAN_tx_packet.data;

    // get length
    length = LAN_tx_packet.length;

    // If I get here, I _know_ there is a packet slot waiting for me
    packet_no = _inp(AR_REG);

    // or isn't there?  BAD CHIP
    if ( packet_no & AR_FAILED ) return;

    // we have a packet address, so tell the card to use it
    _outp(PN_REG, packet_no);

    // point to the beginning of the packet
    _outpw(PTR_REG, PTR_AUTOINC);

    // send the packet length ( +6 for status, length and ctl byte )
    //   and the status word ( set to zeros ) */

#ifndef USE_16_BIT
    _outpd(DATA_REG, (length+6) << 16);
#else
    _outpw(DATA_REG, 0);
    _outpw(DATA_REG, (length+6));
#endif

    // send the actual data
#ifndef USE_16_BIT
    for (i=0; i < (length>>2); i++)
        _outpd(DATA_REG, *buf++);
    // last 16 bit word
    if ( length & 0x2  ) _outpw(DATA_REG, *buf);
#else
    for (i=0; i < (length>>1); i++)
        _outpw(DATA_REG, *buf++);
#endif // USE_32_BIT

    /* Send the last byte, if there is one.   */
    if ((length & 1) == 0)
    {
        // write 0 as CONTROL BYTE
        _outpw(DATA_REG, 0x0000);
    }
    else
    {
#ifndef USE_16_BIT
        // last byte to be sent
        if (length & 2) *buf = (*buf>>16);
#endif
        // last byte to be sent
        _outpw(DATA_REG, 0x2000 | (*buf) & 0xff);
    }

    // enable the interrupts
    smc_enable_int( (IM_TX_INT | IM_TX_EMPTY_INT) );

    // and let the chipset deal with it
    _outpw(MMU_CMD_REG, MC_ENQUEUE);

    // we can send another packet
    LAN_tx_packet.busy = 0;

    return;
}


/******************************************************************************
 * LANC91C111: smc_enable_int
 *
 * Purpose:
 *  Change the current IRQ mask
 *
 * Actions:
 *
 *****************************************************************************/
void smc_enable_int (BYTE IRQ)
{
    WORD page;

    // save old page
    page = _inpw(BSR_REG);
    // switch to bank 2
    _outpw(BSR_REG, 2);
    // update current mask
    _outp(IM_REG, _inp(IM_REG) | IRQ);
    // restore bank
    _outpw(BSR_REG, page);
}

/******************************************************************************
 * LANC91C111: smc_disable_int
 *
 * Purpose:
 *  Change the current IRQ mask
 *
 * Actions:
 *
 *****************************************************************************/
void smc_disable_int (BYTE IRQ)
{
    WORD page;
    BYTE mask;

    // save old page
    page = _inpw(BSR_REG);
    // switch to bank 2
    _outpw(BSR_REG, 2);
    // write new mask
    _outp(IM_REG, _inp(IM_REG) & ~IRQ);
    // restore bank
    _outpw(BSR_REG, page);
}

/******************************************************************************
 * IRQ Sub Function: smc_phy_interrupt for the LAN91C111
 *
 * Purpose:
 *  Handle interrupts relating to PHY register 18.
 *
 * Actions:
 *  Log last Phy18 Interrupt Source
 *
 *****************************************************************************/
void smc_phy_interrupt()
{
    WORD phy18;

    while (1)
    {
        // Read PHY Register 18, Status Output
        phy18 = smc_read_phy_register(PHY_INT_REG);

        // Exit if no more changes
        if (phy18 == LAN_state.lastPhy18)
        break;

        // Update the last phy 18 variable
        LAN_state.lastPhy18 = phy18;
    } // end while
}

// end-of-file

⌨️ 快捷键说明

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