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

📄 at91emacend.c

📁 VxWorks BSP for AT91RM92
💻 C
📖 第 1 页 / 共 5 页
字号:
*
* at91EmacEndInt - handle controller interrupt
*
* This routine is called at interrupt level in response to an interrupt from
* the controller.
*
* RETURNS: N/A.
*/

LOCAL void at91EmacEndInt
    (
    EMAC_END_DEVICE  *pDrvCtrl	/* interrupting device */
    )
    {
    UINT32      stat;

    at91EmacEndIntCount++;
    
    EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Got an interrupt!\n", 1, 2, 3, 4, 5, 6);

    /* Read the device status register */

    stat = EMAC_REG(EMAC_ISR);

    /* Receive complete */
    if ((stat & EMAC_INT_RCOM) == EMAC_INT_RCOM) 
        {
        at91EmacEndIntRCOM++;
        
        EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Rx complete.\n", 0,0,0,0,0,0);
        
        if (!(pDrvCtrl->rxHandling))
            {
            pDrvCtrl->rxHandling = TRUE;
            netJobAdd ((FUNCPTR)at91EmacEndHandleRcvInt, (int)pDrvCtrl, 0,0,0,0);
            
            EMAC_REG(EMAC_IDR) = EMAC_INT_RCOM; /* disable interrupt to reduce RX interrupts overhead */
            }
        }

    /* Transmit complete */
    if ((stat & EMAC_INT_TCOM) == EMAC_INT_TCOM) 
        {
        at91EmacEndIntTCOM++;

        EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Tx complete.\n", 0,0,0,0,0,0);
        
        /* The TCOM bit is set even if the transmission failed. */
        if ((stat & EMAC_INT_TUND) == EMAC_INT_TUND)
            {
            at91EmacEndIntTUND++;

            EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Tx Buffer underrun.\n", 0,0,0,0,0,0);
            }
        
        if ((stat & EMAC_INT_RTRY) == EMAC_INT_RTRY)
            {
            at91EmacEndIntRTRY++;
            
            EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Transmit Retry limt.\n", 0,0,0,0,0,0);
            }
        
        /* send next packet */
        (void) at91EmacEndNextSend(pDrvCtrl);
        }

    /* Receive Buffer Not Available */
    if ((stat & EMAC_INT_RBNA) == EMAC_INT_RBNA) 
        {
        at91EmacEndIntRBNA++;

        EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Rx Buffer Not Available.\n", 0,0,0,0,0,0);
		
        /*
         * Workaround for errata #11 -> stop and restart receiver
         * (occurs even if receive buffer is 64 bytes aligned)
         */
        
        EMAC_REG(EMAC_CTL) &= ~EMAC_CTL_RE;
        EMAC_REG(EMAC_CTL) |= EMAC_CTL_RE;
        }

    /* Rx Overrun */
    if ((stat & EMAC_INT_ROVR) == EMAC_INT_ROVR) 
        {
        at91EmacEndIntROVR++;

        EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Rx Overrun.\n", 0,0,0,0,0,0);
        }
    }

/*******************************************************************************
*
* at91EmacEndRecv - process the next incoming packet
*
* Handle one incoming packet.  The packet is checked for errors.
*
* RETURNS: N/A.
*/

LOCAL STATUS at91EmacEndRecv
    (
    EMAC_END_DEVICE *   pDrvCtrl,	/* device structure */
    char *              pData,		/* packet to process */
    int                 len         /* length of packet to process */
    )
    {
    M_BLK_ID 	pMblk;
    char *      pNewCluster;
    CL_BLK_ID	pClBlk;


    /*
     * loaning is not used here (due to alignement required for IP Header),
     * the data must be copied before being passed up to the protocols.
     */

    pNewCluster = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId);

    if (pNewCluster == NULL)
        {
    	EMAC_END_LOG (EMAC_END_DBG_RX, "at91EmacEndRecv: Cannot Get Cluster !\n", 1, 2, 3, 4, 5, 6);
    	END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
    	return(ERROR);
        }

    /* Grab a cluster block to marry to the cluster we received. */

    if ((pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT)) == NULL)
        {
        netClFree (pDrvCtrl->end.pNetPool, (UCHAR *)pNewCluster);
        EMAC_END_LOG (EMAC_END_DBG_RX, "at91EmacEndRecv: Out of Cluster Blocks!\n", 1, 2, 3, 4, 5, 6);
        END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
    	return(ERROR);
        }

    if ((pMblk = mBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT, MT_DATA)) == NULL)
        {
        netClBlkFree (pDrvCtrl->end.pNetPool, pClBlk);
        netClFree (pDrvCtrl->end.pNetPool, (UCHAR *)pNewCluster);
        EMAC_END_LOG (EMAC_END_DBG_RX, "at91EmacEndRecv: Out of M Blocks!\n", 1, 2, 3, 4, 5, 6);
        END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
    	return(ERROR);
        }

    /* make the packet data coherent */

    END_CACHE_INVALIDATE (pData, len);
    
    /* Join the cluster to the MBlock */

    netClBlkJoin (pClBlk, pNewCluster, len, NULL, 0, 0, 0);
    netMblkClJoin (pMblk, pClBlk);

    END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);

    /* copy the data */
    pMblk->mBlkHdr.mData += 2;  /* Hints to ensure that IP header is word aligned !!! */
                                /* Dest MAC + Src MAC + length/Type = 14 bytes */

    bcopy (pData, pMblk->mBlkHdr.mData, len);
    
    pMblk->mBlkHdr.mFlags |= M_PKTHDR;	/* set the packet header */
    pMblk->mBlkHdr.mLen   = len;		/* set the data len */
    pMblk->mBlkPktHdr.len = len;	    /* set the total len */

    at91EmacEndNumRecv++;

    EMAC_END_LOG (EMAC_END_DBG_RX, "at91EmacEndRecv: Calling upper layer!\n", 1, 2, 3, 4, 5, 6);

    /* Call the upper layer's receive routine. */

    END_RCV_RTN_CALL(&pDrvCtrl->end, pMblk);

    return (OK);
    }

/*******************************************************************************
*
* at91EmacEndHandleRcvInt - task level interrupt service for input packets
*
* This routine is called at task level indirectly by the interrupt
* service routine to do any message received processing.
*
* RETURNS: N/A.
*/

LOCAL void at91EmacEndHandleRcvInt
    (
    EMAC_END_DEVICE *pDrvCtrl	/* interrupting device */
    )
    {
    int     len;
    char *  pData;
    int     nLoop = 0;

    EMAC_END_LOG(EMAC_END_DBG_RX,"at91EmacEndHandleRcvInt: Entering...\n", 1, 2, 3, 4, 5, 6 );
    
    pDrvCtrl->rxHandling = TRUE;

    /* check for all packet received */

    while ((pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs & RXBUF_ADD_OWNED) == RXBUF_ADD_OWNED)
        {
        len   = pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].status & RXBUF_STAT_LEN_MASK;   /* size including FCS */
        pData = (char *) (pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs & RXBUF_ADD_BASE_MASK);

        EMAC_END_LOG(EMAC_END_DBG_RX,"rxIndex = %i, adrs = 0x%x, status = 0x%08x\n",
                     pDrvCtrl->rxIndex,
                     pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs,
                     pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].status,
                      4, 5, 6);

#ifdef DELAY_RX
        EMAC_END_LOG_DELAY(EMAC_END_DBG_RX);
#endif /* DELAY_RX */

        at91EmacEndRecv(pDrvCtrl, pData, len);

        /* give back buffer to DMA */
        pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].status = 0;
        pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs &= ~RXBUF_ADD_OWNED;

        /* update index */
        if (pDrvCtrl->rxIndex == (pDrvCtrl->rxNum - 1))
            {
            pDrvCtrl->rxIndex = 0;
            }
        else
            {
            pDrvCtrl->rxIndex++;
            }

        nLoop++;
        }

    /* update watermark */
    if (nLoop > at91EmacEndMaxLoopRecv)
        {
        at91EmacEndMaxLoopRecv = nLoop;
        }

    pDrvCtrl->rxHandling = FALSE;

    EMAC_REG(EMAC_IER) = EMAC_INT_RCOM; /* re-enable RX interrupt */

    EMAC_END_LOG(EMAC_END_DBG_RX,"at91EmacEndHandleRcvInt: End.\n", 1, 2, 3, 4, 5, 6 );
    }

/*******************************************************************************
*
* at91EmacEndSend - the driver send routine
*
* This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
* The buffer must already have the addressing information properly installed
* in it.  This is done by a higher layer.  The last arguments are a free
* routine to be called when the device is done with the buffer and a pointer
* to the argument to pass to the free routine.
*
* RETURNS: OK, ERROR, or END_ERR_BLOCK.
*/

LOCAL STATUS at91EmacEndSend
    (
    EMAC_END_DEVICE * pDrvCtrl,	/* device ptr */
    M_BLK_ID     pMblk		/* data to send */
    )
    {
    int                     oldLevel = 0;
    int                     length;
    char *                  pBuf;
    volatile TXBUF_HDR *    pBufHdr;
    
    if (pDrvCtrl->flags & EMAC_POLLING)
        {
        return(ERROR);
        }
    
    /*
     * Obtain exclusive access to transmitter.  This is necessary because
     * we might have more than one stack transmitting at once.
     */

	END_TX_SEM_TAKE (&pDrvCtrl->end, WAIT_FOREVER);
    
    /* check if buffer available (tx underrun ?) */
    pBufHdr = (volatile TXBUF_HDR *) &pDrvCtrl->txHdrs[pDrvCtrl->txIndexWr];
    
    if (pBufHdr->inUse)
        {
        at91EmacEndNumTXRetry++;

        EMAC_END_LOG(EMAC_END_DBG_TX,"at91EmacEndSend: TX buffer underrun !\n", 1, 2, 3, 4, 5, 6 );
        END_TX_SEM_GIVE (&pDrvCtrl->end);
        return(END_ERR_BLOCK);
        }

    /* put packet to transmit in TX queue (use txIndexWr) */
    pBuf   = pBufHdr->pAdrs;

    length = netMblkToBufCopy (pMblk, pBuf, NULL);
    length = max (ETHERSMALL, length);
    
    pBufHdr->length = length;
    pBufHdr->inUse  = TRUE;

    /* next index */
    if (pDrvCtrl->txIndexWr == (pDrvCtrl->txNum -1))
        {
        pDrvCtrl->txIndexWr = 0;
        }
    else
        {
        pDrvCtrl->txIndexWr++;
        }


    EMAC_END_LOG(EMAC_END_DBG_TX,"at91EmacEndSend: enqueue -> pMblk=0x%x, pBuf=0x%x, len=%i\n",
                 (int) pMblk, (int) pBuf, length, 4, 5, 6 );


    END_CACHE_FLUSH(pBuf,length);
    
    /* initiate transmit of next packet (if required) (use txIndexRd) */
    
    oldLevel = intLock ();	/* protect at91EmacEndInt */

    /* send next packet */
    (void) at91EmacEndNextSend(pDrvCtrl);

    intUnlock (oldLevel);
    
	END_TX_SEM_GIVE (&pDrvCtrl->end);

    /* Bump the statistics counters. */
    END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);

    /*
     * Cleanup.  free the mblk chain
     * after the device is finished with the TFD.
     */

    netMblkClChainFree (pMblk);

    return (OK);
    }

/*******************************************************************************
*
* at91EmacEndIoctl - the driver I/O control routine
*
* Process an ioctl request.
*
* RETURNS: A command specific response, usually OK or ERROR.
*/

LOCAL int at91EmacEndIoctl
    (
    EMAC_END_DEVICE * pDrvCtrl, /* device receiving command */
    int cmd,            /* ioctl command code */
    caddr_t data        /* command argument */
    )
    {
    int error = 0;
    long value;

    switch ((unsigned)cmd)
        {
        case EIOCSADDR:     /* set MAC address */
            if (data == NULL)
                return(EINVAL);
            bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->end),
                   END_HADDR_LEN(&pDrvCtrl->end));
            break;

        case EIOCGADDR:     /* get MAC address */
            if (data == NULL)
                return(EINVAL);
            bcopy ((char *)END_HADDR(&pDrvCtrl->end), (char *)data,
                   END_HADDR_LEN(&pDrvCtrl->end));
            break;

        case EIOCSFLAGS:    /* set (or clear) flags */
            value = (long)data;
            if (value < 0)
                {
                value = -value;
                value--;
                END_FLAGS_CLR (&pDrvCtrl->end, value);
                }
            else
                {
                END_FLAGS_SET (&pDrvCtrl->end, value);
                }
            at91EmacEndConfig (pDrvCtrl);
            break;

        case EIOCGFLAGS:    /* get flags */
            *(int *)data = END_FLAGS_GET(&pDrvCtrl->end);
            break;

        case EIOCPOLLSTART: /* Begin polled operation */
            at91EmacEndPollStart (pDrvCtrl);
            break;

        case EIOCPOLLSTOP:  /* End polled operation */
            at91EmacEndPollStop (pDrvCtrl);
            break;

⌨️ 快捷键说明

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