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

📄 motcpmend.c

📁 powerPC866 系列平台BSP移植开发的参考代码
💻 C
📖 第 1 页 / 共 5 页
字号:
* and the waiting for the device to decide to transmit it.
*
* If it detects a transmission error, the restart command is issued.
*
* These routine should not call any kernel functions.
*
* RETURNS: OK or EAGAIN
*/

LOCAL STATUS motCpmEndPollSend
    (
    END_CTRL    *pDrvCtrl,	/* pointer to END_CTRL structure */
    M_BLK_ID    pMblk	/* data to send */
    )
    {
    int		length;
    SCC_BUF *	pTxBd;
    u_char *	pad;
    char *	pBuf;

    MOTCPMLOGMSG(("motCpmEndPollSend \n", 0, 0, 0, 0, 0, 0));

    if (pDrvCtrl->txStop)
	return (ERROR);

    /* get a free transmit frame descriptor */

    pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext];

    /* check if a transmit buffer descriptor is available */

    if ((pTxBd->statusMode & SCC_ETHER_TX_BD_R) ||
	(((pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum)
			== pDrvCtrl->txBdIndexC))
	{
	return (EAGAIN);
	}

    /* fill the transmit frame descriptor */
    
    pBuf = pDrvCtrl->txPoolBuf;   
 
    length = netMblkToBufCopy (pMblk, (char *)pBuf, NULL);

    pTxBd->dataPointer = (u_char *) pBuf;

    /* padding mechanism in Rev A is buggy - do in software */

    if (length < FRAME_MIN)
	{
	pad = pTxBd->dataPointer + length;
	for (; length != FRAME_MIN; length++, pad++)
	    *pad = 0x88;
	}

    pTxBd->dataLength = length;

    if (pTxBd->statusMode & SCC_ETHER_TX_BD_W)
	pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
			    SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  |
			    SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R;
    else
	pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD |
			    SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  |
			    SCC_ETHER_TX_BD_R;

    /* incr BD count */

    pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) %
				pDrvCtrl->ether.txBdNum;

    /* Bump the statistic counter. */

    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1);

    /*
     * Spin until we've sent it.
     */

    while (pTxBd->statusMode & SCC_ETHER_TX_BD_R)
	;

    if (pTxBd->statusMode & (SCC_ETHER_TX_BD_RL | SCC_ETHER_TX_BD_UN |
			    SCC_ETHER_TX_BD_CSL | SCC_ETHER_TX_BD_LC))
	{
	/* An error has occured, restart the transmitter */

	pDrvCtrl->txStop = TRUE;

	motCpmTxRestart (pDrvCtrl);
	}

    /* 
     * we are allow to do this because transmit queue is empty when we
     * start polling mode.
     */

    pDrvCtrl->txBdIndexC = pDrvCtrl->ether.txBdNext;

    return (OK);
    }

/*******************************************************************************
*
* motCpmEndPollReceive - receive a packet in polled mode
*
* This routine is called by a user to try and get a packet from the
* device. It returns EAGAIN if no packet is available. The caller must
* supply a M_BLK_ID with enough space to contain the receiving packet. If
* enough buffer is not available then EAGAIN is returned.
*
* These routine should not call any kernel functions.
*
* RETURNS: OK or EAGAIN
*/

LOCAL STATUS motCpmEndPollReceive
    (
    END_CTRL    *pDrvCtrl,	/* pointer to END_CTRL structure */
    M_BLK_ID    pMblk
    )
    {
    SCC_BUF *	pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext];
    int		length;
    int		status = EAGAIN;

    MOTCPMLOGMSG(("motCpmEndPollReceive \n", 0, 0, 0, 0, 0, 0));

    /* if we have not received packets, leave immediatly */

    if (pRxBd->statusMode & SCC_ETHER_RX_BD_E)
	return (EAGAIN);

    /* check packets for errors */

    if (((pRxBd->statusMode & (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L))
			   == (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L))
       && !(pRxBd->statusMode & (SCC_ETHER_RX_BD_CL |
				SCC_ETHER_RX_BD_OV | SCC_ETHER_RX_BD_CR |
				SCC_ETHER_RX_BD_SH | SCC_ETHER_RX_BD_NO |
				SCC_ETHER_RX_BD_LG)))
	{
	/* adjust length to data only */

	length = pRxBd->dataLength - 4;

	if ((length - SIZEOF_ETHERHEADER) <= 0)
	    {
	    /* bump input error packet counter */

	    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
	    goto cleanRxBd;
	    }

	/* 
	 * Upper layer provides the buffer.
         * If buffer is not large enough, we return.
	 */

	/* copy data */

        if ((pMblk->mBlkHdr.mLen < length) ||
            (!(pMblk->mBlkHdr.mFlags & M_EXT)))
            {
            goto cleanRxBd;
            }
        
	bcopy ((char *) pRxBd->dataPointer, (char *)pMblk->mBlkHdr.mData,
               length);
	pMblk->mBlkHdr.mLen = length;
	pMblk->mBlkPktHdr.len = length;
	pMblk->mBlkHdr.mFlags |= M_PKTHDR;

	/* bump input packet counter */

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

	status = OK;
	}
    else
	{
	/* bump input error packet counter */

	END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1);
	}

cleanRxBd:
    motCpmCleanRxBd (pDrvCtrl, pRxBd);	/* reset buffer descriptor as empty */

    return (status);
    }

/*******************************************************************************
*
* motCpmIntr - network interface interrupt handler
*
* This routine gets called at interrupt level. It handles work that 
* requires minimal processing. Interrupt processing that is more 
* extensive gets handled at task level. The network task, netTask(), is 
* provided for this function. Routines get added to the netTask() work 
* queue via the netJobAdd() command.
*
* RETURNS: N/A
*/

LOCAL void motCpmIntr
    (
    END_CTRL *	pDrvCtrl	/* pointer to END_CTRL structure */
    )
    {
    BOOL rxHandle = FALSE;
    BOOL txbHandle = FALSE;
    
    /* check for spurious interrupt -> initialized ? */

    if (!pDrvCtrl->endObject.attached)
	{
        pDrvCtrl->ether.pSccReg->scce = 0xffff;

        *CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask;
	return;
	}

    /* handle receive events */

    if ((pDrvCtrl->ether.pSccReg->sccm & SCC_ETHER_SCCX_RXF) &&
        (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_RXF))
	{
        (void) netJobAdd ((FUNCPTR) motCpmHandleInt, (int) pDrvCtrl, 
			  0, 0, 0, 0); 

	/* turn off receive interrupts for now - motCpmHandleIt turns back on */

        pDrvCtrl->ether.pSccReg->sccm &= ~SCC_ETHER_SCCX_RXF;
	rxHandle = TRUE;
        }

    /* check for output errors */

    if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXE)
	{
	/* clean the transmit buffer descriptor queue */
	/* NOTE: HBC error not supported -> always RESTART Tx here */

        (void) netJobAdd ((FUNCPTR) motCpmTxRestart, (int) pDrvCtrl, 
			  0, 0, 0, 0);
	pDrvCtrl->txStop = TRUE;
	}

    /* handle transmitter events - BD full condition -> ever happen ? */

    if ((pDrvCtrl->ether.pSccReg->sccm & SCC_ETHER_SCCX_TXB) &&
        (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXB))
	{
	txbHandle = TRUE;
	}

    /* check for input busy condition */

    if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_BSY)
        pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_BSY; 

    /* acknowledge all other interrupts - ignore events */

    pDrvCtrl->ether.pSccReg->scce = (pDrvCtrl->ether.pSccReg->scce &
				    ~(SCC_ETHER_SCCX_RXF |
				      SCC_ETHER_SCCX_TXE |
				      SCC_ETHER_SCCX_TXB |
				      SCC_ETHER_SCCX_BSY));

    /* 
     * clean the transmit buffer descriptor queue if we have 
     * received a transmit interrupt and if we are not already
     * cleaning this transmit queue.
     */

    if ((pDrvCtrl->txStop || txbHandle) && !pDrvCtrl->txCleaning)
        {
    	motCpmCleanTxBdQueue (pDrvCtrl);
        if (pDrvCtrl->txBlocked)
            {
            pDrvCtrl->txBlocked = FALSE;
            (void) netJobAdd ((FUNCPTR) muxTxRestart,
                              (int)&pDrvCtrl->endObject,
                              0, 0, 0, 0);
            }
        }

    /* acknowledge interrupts */

    if (rxHandle)
        pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF; 
    if (pDrvCtrl->txStop)
        pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXE; 
    if (txbHandle)
        pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXB; 

    *CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask;

    }

/*******************************************************************************
*
* motCpmMCastFilterSet - set the group addres filter for a multicast addresse.
*
* To add an address in the processor group address hash filter, we use
* the SET GROUP ADDRESS command. This command can be executed at any 
* time, regadless of whether the Ethernet channel is enabled.
*
* RETURNS : N/A 
*
*/

LOCAL void motCpmMCastFilterSet
    (
    END_CTRL *  pDrvCtrl,	/* pointer to END_CTRL structure */
    char *      pAddress        /* Address to delete from the table. */
    )
    {
    MOTCPMLOGMSG(("motCpmMCastFilterSet \n", 0, 0, 0, 0, 0, 0));

    /* add multicast address */

    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_h =
					(pAddress[5] << 8) + pAddress[4];
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_m =
					(pAddress[3] << 8) + pAddress[2];
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_l =
					(pAddress[1] << 8) + pAddress[0];

    /* issue the set group address command to the CP */

    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);

    *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) |
				       CPM_CR_SCC_SET_GROUP |
				       CPM_CR_FLG;

    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG);
    }

/*******************************************************************************
*
* motCpmMCastConfig - reconfigure the interface under us.
*
* Reconfigure the interface changing the multicast interface list.
*
* In order to delete an address from the hash tabke, the Ethernet channel
* should be disabled, the hash table registers should be cleared, and 
* the SET GROUP ADDRESS command must be executed for the remaining 
* desired addresses. This is required because the hash table may have mapped
* multiple addresses to the same hash table bit.
*
* RETURNS : N/A 
*/

LOCAL void motCpmMCastConfig
    (
    END_CTRL *  pDrvCtrl	/* pointer to END_CTRL structure */
    )
    {
    ETHER_MULTI *	pCurr;

    MOTCPMLOGMSG(("motCpmMCastConfig \n",0,0,0,0,0,0));

    /* disable the ethernet channel */

    motCpmReset (pDrvCtrl);

    /* clear hash table group registers */

    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr1     = 0x0000;
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr2     = 0x0000;
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr3     = 0x0000;
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr4     = 0x0000;

    /* restore remaining addresses */

    for (pCurr = END_MULTI_LST_FIRST(&pDrvCtrl->endObject); pCurr != NULL;
			pCurr = (ETHER_MULTI *)lstNext(&pCurr->node))
	{
	/* add multicast address */
	motCpmMCastFilterSet (pDrvCtrl, pCurr->addr);
	}

    /* restart the ethernet channel */

    motCpmRestart (pDrvCtrl);
    }

/*******************************************************************************
*
* motCpmRestart - network interface restart routine
*
* This routine restarts the device.  This includes enabling interrupts, 
* starting the transmitter and receiver, and calling the bsp-specific
* LAN enable routine to do any target specific enabling.
*
* This routine follows the instructions in MC68EN360/MPC821 Users's Manual :
* "Disabling the SCCs on the Fly"
*
* The complement 

⌨️ 快捷键说明

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