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

📄 csl_emac.c

📁 这是测试SEED-VPM642系统中网络的接口的测试的程序。(闭环)
💻 C
📖 第 1 页 / 共 4 页
字号:
/*-----------------------------------------------------------------------*\
* EMAC_getStatistics()
*
* Called to get the current device statistics. The statistics structure
* contains a collection of event counts for various packet sent and
* receive properties. Reading the statistics also clears the current
* statistic counters, so the values read represent a delta from the last
* call.
*
* The statistics information is copied into the structure pointed to
* by the pStatistics argument.
*
* The function returns zero on success, or an error code on failure.
*
* Possible error code include:
*   EMAC_ERROR_INVALID   - A calling parameter is invalid
*
\*-----------------------------------------------------------------------*/
uint EMAC_getStatistics( Handle hEMAC, EMAC_Statistics *pStatistics )
{
    EMAC_Device  *pd = (EMAC_Device *)hEMAC;

    /* Validate our handle */
    if( !pd || pd->DevMagic != EMAC_DEVMAGIC || !pStatistics )
        return( EMAC_ERROR_INVALID );

    /* Update the stats */
    emacUpdateStats( pd );

    /* Copy the updated stats to the application */
    *pStatistics = pd->Stats;

    /* Clear our copy */
    memset( &pd->Stats, 0, sizeof(EMAC_Statistics) );

    return(0);
}


/*-----------------------------------------------------------------------*\
* EMAC_setMulticast()
*
* This function is called to install a list of multicast addresses for
* use in multicast address filtering. Each time this function is called,
* any current multicast configuration is discarded in favor of the new
* list. Thus a set with a list size of zero will remove all multicast
* addresses from the device.
*
* Note that the multicast list configuration is stateless in that the
* list of multicast addresses used to build the configuration is not
* retained. Thus it is impossible to examine a list of currently installed
* addresses.
*
* The addresses to install are pointed to by pMCastList. The length of
* this list in bytes is 6 times the value of AddrCnt. When AddrCnt is
* zero, the pMCastList parameter can be NULL.
*
* The function returns zero on success, or an error code on failure.
* The multicast list settings are not altered in the event of a failure
* code.
*
* Possible error code include:
*   EMAC_ERROR_INVALID   - A calling parameter is invalid
*
\*-----------------------------------------------------------------------*/
uint EMAC_setMulticast( Handle hEMAC, uint AddrCnt, Uint8 *pMCastList )
{
    EMAC_Device  *pd = (EMAC_Device *)hEMAC;
    uint        tmp1,tmp2;
    Uint8       HashVal,tmpval;

    /* Validate our handle */
    if( !pd || pd->DevMagic != EMAC_DEVMAGIC || (AddrCnt && !pMCastList) )
        return( EMAC_ERROR_INVALID );

    /* Clear the hash bits */
    pd->MacHash1 = 0;
    pd->MacHash2 = 0;

    /* For each address in the list, hash and set the bit */
    for( tmp1=0; tmp1<AddrCnt; tmp1++ )
    {
        HashVal=0;

        for( tmp2=0; tmp2<2; tmp2++ )
        {
            tmpval = *pMCastList++;
            HashVal ^= (tmpval>>2)^(tmpval<<4);
            tmpval = *pMCastList++;
            HashVal ^= (tmpval>>4)^(tmpval<<2);
            tmpval = *pMCastList++;
            HashVal ^= (tmpval>>6)^(tmpval);
        }

        if( HashVal & 0x20 )
            pd->MacHash2 |= (1<<(HashVal&0x1f));
        else
            pd->MacHash1 |= (1<<(HashVal&0x1f));
    }

    /* We only write the hash table if the filter setting allows */
    if( pd->RxFilter < EMAC_RXFILTER_ALLMULTICAST )
    {
        EMAC_RSET( MACHASH1, pd->MacHash1 );
        EMAC_RSET( MACHASH2, pd->MacHash2 );
    }

    return(0);
}


/*-----------------------------------------------------------------------*\
* EMAC_sendPacket()
*
* Sends a Ethernet data packet out the EMAC device. On a non-error return,
* the EMAC device takes ownership of the packet. The packet is returned
* to the application's free pool once it has been transmitted.
*
* The function returns zero on success, or an error code on failure.
* When an error code is returned, the EMAC device has not taken ownership
* of the packet.
*
* Possible error codes include:
*   EMAC_ERROR_INVALID   - A calling parameter is invalid
*   EMAC_ERROR_BADPACKET - The packet structure is invalid
*
\*-----------------------------------------------------------------------*/
uint EMAC_sendPacket( Handle hEMAC, EMAC_Pkt *pPkt )
{
    EMAC_Device  *pd = (EMAC_Device *)hEMAC;
    uint        fragcnt,pktlen;
    EMAC_Pkt     *pPktLast;
    EMAC_DescCh  *pdc;

    /* Validate our handle */
    if( !pd || pd->DevMagic != EMAC_DEVMAGIC || !pPkt )
        return( EMAC_ERROR_INVALID );

    /* Do some packet validation */
    if( !(pPkt->Flags & EMAC_PKT_FLAGS_SOP) )
        return( EMAC_ERROR_BADPACKET );

    if( pPkt->PktChannel >= pd->Config.TxChannels )
        return( EMAC_ERROR_BADPACKET );

    if( pPkt->PktLength < 14 || pPkt->PktLength > pd->PktMTU )
        return( EMAC_ERROR_BADPACKET );

    /* Count the number of frags in this packet */
    fragcnt = 1;
    pktlen  = pPkt->PktLength;
    pPktLast = pPkt;
    while( !(pPktLast->Flags & EMAC_PKT_FLAGS_EOP) )
    {
        if( !pPktLast->pNext )
            return( EMAC_ERROR_INVALID );
        pktlen -= pPktLast->ValidLen;
        pPktLast = pPktLast->pNext;
        fragcnt++;

        /* At this point we can't have another SOP */
        if( pPktLast->Flags & EMAC_PKT_FLAGS_SOP )
            return( EMAC_ERROR_INVALID );
    }

    /* Make sure PktLength and ValidLen agree */
    if( pktlen != pPkt->ValidLen )
        return( EMAC_ERROR_BADPACKET );

    /* The final packet frag must be the last in the list */
    if( pPktLast->pNext )
        return( EMAC_ERROR_BADPACKET );

    /* The frag count must be correct */
    if( fragcnt != pPkt->PktFrags )
        return( EMAC_ERROR_BADPACKET );

    /* Now pad for 60 byte min size. We only pad the last fragment */
    if( pPkt->PktLength < 60 )
    {
        pktlen = 60 - pPkt->PktLength;
        pPkt->PktLength = 60;
        pPktLast->ValidLen += pktlen;
    }

    /* Get a local pointer to the descriptor channel */
    pdc = &(pd->TxCh[pPkt->PktChannel]);

    /* Make sure this packet does not have too many frags to fit */
    if( fragcnt > pdc->DescMax )
        return( EMAC_ERROR_BADPACKET );

    /*
    // Queue and packet and service transmitter
    */
    pqPushChain( &pdc->WaitQueue, pPkt, pPktLast, fragcnt );
    emacEnqueueTx( pdc );

    return(0);
}


/*-----------------------------------------------------------------------*\
* EMAC_serviceCheck()
*
* This function should be called every time there is an EMAC device
* interrupt. It maintains the status the EMAC.
*
* Note that the application has the responsibility for mapping the
* physical device index to the correct EMAC_serviceCheck() function. If
* more than one EMAC device is on the same interrupt, the function must be
* called for each device.
*
* Possible error codes include:
*   EMAC_ERROR_INVALID   - A calling parameter is invalid
*   EMAC_ERROR_MACFATAL  - Fatal error in the MAC - Call EMAC_close()
*
\*-----------------------------------------------------------------------*/
uint EMAC_serviceCheck( Handle hEMAC )
{
    EMAC_Device  *pd = (EMAC_Device *)hEMAC;
    Uint32      intflags,Desc,mask;
    uint        tmp;

    /* Validate our handle */
    if( !pd || pd->DevMagic != EMAC_DEVMAGIC )
        return( EMAC_ERROR_INVALID );

    /* Disable EMAC/MDIO interrupts in wrapper */
    EMAC_FSETS( EWCTL, INTEN, DISABLE );

    /* Read the interrupt cause */
    intflags = EMAC_RGET( MACINVECTOR );

        /* Look for fatal errors first */
        if( intflags & EMAC_FMK( MACINVECTOR, HOSTPEND, 1 ) )
        {
            /* Read the error status - we'll decode it by hand */
            pd->FatalError = EMAC_RGET( MACSTATUS );

            /* Tell the application */
            (*localDev.Config.pfcbStatus)(pd->hApplication);

            /* return with interrupt disabled in the wrapper */
        return( EMAC_ERROR_MACFATAL );
        }

        /* Look for statistics interrupt */
        if( intflags & EMAC_FMK( MACINVECTOR, STATPEND, 1 ) )
        {
        /* Read the stats and reset to zero         */
        /* This is necessary to clear the interrupt */
            emacUpdateStats( pd );

            /* Tell the application */
            (*localDev.Config.pfcbStatistics)(pd->hApplication);
        }

    /* Look for TX interrupt (channel 0-max) */
        for( tmp=0; tmp<pd->Config.TxChannels; tmp++ )
    {
        mask = EMAC_FMK( MACINVECTOR, TXPEND, 1<<tmp );
        if( intflags & mask )
        {
            /*
            // For multichannel operation, we need to
            // apply an errata workaround.
            */
            do
        {
            Desc = EMAC_RGETI( TXINTACK, tmp );
            EMAC_RSETI( TXINTACK, tmp, Desc );
            } while( pd->Config.TxChannels>1 && (EMAC_RGET(MACINVECTOR)&mask) );

            emacDequeueTx( &pd->TxCh[tmp], (EMAC_Desc *)Desc );
    }
    }

    /* Look for RX interrupt (channel 0) */
    if( intflags & EMAC_FMK( MACINVECTOR, RXPEND, 1<<0 ) )
    {
        /*
        // For multichannel operation, we need to apply the
        // same errata workaround as TX. However this driver
        // example only supports one RX channel.
        */
        Desc = EMAC_RGET( RX0INTACK );
        EMAC_RSET( RX0INTACK, Desc );

        emacDequeueRx( &pd->RxCh, (EMAC_Desc *)Desc );
    }

    /* Enable EMAC/MDIO interrupts in wrapper */
    EMAC_FSETS( EWCTL, INTEN, ENABLE );

    return(0);
}

/*-----------------------------------------------------------------------*\
* EMAC_timerTick()
*
* This function should be called for each device in the system on a
* periodic basis of 100mS (10 times a second). It is used to check the
* status of the EMAC and MDIO device, and to potentially recover from
* low Rx buffer conditions.
*
* Strict timing is not required, but the application should make a
* reasonable attempt to adhere to the 100mS mark. A missed call should
* not be "made up" by making mulitple sequential calls.
*
* A "polling" driver (one that calls EMAC_serviceCheck() in a tight loop),
* must also adhere to the 100mS timing on this function.
*
* Possible error codes include:
*   EMAC_ERROR_INVALID   - A calling parameter is invalid
*
\*-----------------------------------------------------------------------*/
uint EMAC_timerTick( Handle hEMAC )
{
    EMAC_Device  *pd = (EMAC_Device *)hEMAC;
    uint         mdioStatus,linkStatus;

    /* Validate our handle */
    if( !pd || pd->DevMagic != EMAC_DEVMAGIC )
        return( EMAC_ERROR_INVALID );

    /* Signal the MDIO */
    mdioStatus = MDIO_timerTick( pd->hMDIO );

    /* On a new link, set the EMAC duplex */
    if( mdioStatus == MDIO_EVENT_LINKUP )
    {
        MDIO_getStatus( pd->hMDIO, 0, &linkStatus );

        if( linkStatus == MDIO_LINKSTATUS_FD10 ||
            linkStatus == MDIO_LINKSTATUS_FD100 )
        {
            EMAC_FSETS( MACCONTROL, FULLDUPLEX, ENABLE );
        }
        else
        {
            EMAC_FSETS( MACCONTROL, FULLDUPLEX, DISABLE );
        }
    }

    if( mdioStatus != MDIO_EVENT_NOCHANGE )
        (*localDev.Config.pfcbStatus)(pd->hApplication);

    /* Re-fill Rx buffer queue if needed */
    if( pd->RxCh.DescCount != pd->RxCh.DescMax )
        emacEnqueueRx( &pd->RxCh, 1 );

    return ( 0 );
}


#endif /* EMAC_SUPPORT */
/******************************************************************************\
* End of emac.c
\******************************************************************************/

⌨️ 快捷键说明

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