📄 at91emacend.c
字号:
LOCAL STATUS at91EndSend
(
at91end_device *pDrvCtrl, /* device ptr */
M_BLK_ID pNBuff /* data to send */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
BOOL freeNow = TRUE;
UINT32 curtailptr, txdelta;
UINT32 oldlevel;
char *txbuf;
/*
ENDLOGMSG ((" Enter at91EndSend routine...\n", 1, 2, 3, 4, 5, 6));
*/
oldlevel = intLock ();
curtailptr = pDrvCtrl ->TxTailPtr;
txdelta = TX_FD_NUM - curtailptr + (pDrvCtrl ->TxPtr);
if( txdelta >= TX_FD_NUM )
txdelta -= TX_FD_NUM;
if( (txdelta < 3) && ( pDrvCtrl ->TXFifoStat != TXFIFOEMPTY ) )
{
intUnlock( oldlevel );
return ERROR;
}
intUnlock( oldlevel );
/*
* 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 );
/*
* fifo now have space for new packet
*/
txbuf = (pDrvCtrl ->pTxBufStart)[curtailptr].bufaddr;
(pDrvCtrl ->pTxBufStart)[curtailptr].len = pNBuff->mBlkPktHdr.len;
/* Set pointers in local structures to point to data. */
netMblkToBufCopy( pNBuff, (void *)txbuf, NULL ) ;
/* place a transmit request */
oldlevel = intLock (); /* now at91EndInt won't get confused */
if( pDrvCtrl ->TxTailPtr == (TX_FD_NUM-1) )
pDrvCtrl ->TxTailPtr = 0;
else
pDrvCtrl ->TxTailPtr ++;
if( pDrvCtrl ->TxTailPtr == pDrvCtrl ->TxPtr )
pDrvCtrl ->TXFifoStat = TXFIFOFULL;
else
pDrvCtrl ->TXFifoStat = TXFIFONORMAL;
if( (pemac ->EMAC_TSR) & EMAC_TSR_BNQ )
{
/*
* TxPtr ->next ready to send package
* TxTailPtr ->Next to accept transmit package
*/
TranNextPackage( pDrvCtrl );
}
intUnlock (oldlevel); /* now at91EndInt won't get confused */
END_TX_SEM_GIVE (&pDrvCtrl->end);
/* Bump the statistic counter. */
END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);
/*
* Cleanup. The driver must either free the packet now or
* set up a structure so it can be freed later after a transmit
* interrupt occurs.
*/
if (freeNow)
netMblkClChainFree (pNBuff);
/*
ENDLOGMSG ((" Leave at91EndSend routine...\n", 1, 2, 3, 4, 5, 6));
*/
return (OK);
}
/*******************************************************************************
*
* at91EndIoctl - the driver I/O control routine
*
* Process an ioctl request.
*
* RETURNS: A command specific response, usually OK or ERROR.
*/
LOCAL int at91EndIoctl
(
at91end_device *pDrvCtrl, /* device receiving command */
int cmd, /* ioctl command code */
caddr_t data /* command argument */
)
{
int error = 0;
long value;
/*
ENDLOGMSG ((" Enter at91EndIoctl routine...\n", 1, 2, 3, 4, 5, 6));
*/
switch (cmd)
{
case EIOCSADDR:
if (data == NULL)
return (EINVAL);
bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->end),
END_HADDR_LEN(&pDrvCtrl->end));
break;
case EIOCGADDR:
if (data == NULL)
return (EINVAL);
bcopy ((char *)END_HADDR(&pDrvCtrl->end), (char *)data,
END_HADDR_LEN(&pDrvCtrl->end));
break;
case EIOCSFLAGS:
value = (long)data;
if (value < 0)
{
value = ~value;
END_FLAGS_CLR (&pDrvCtrl->end, value);
}
else
{
END_FLAGS_SET (&pDrvCtrl->end, value);
}
at91EndConfig (pDrvCtrl);
break;
case EIOCGFLAGS:
*(int *)data = END_FLAGS_GET(&pDrvCtrl->end);
break;
case EIOCPOLLSTART:
at91EndPollStart (pDrvCtrl);
break;
case EIOCPOLLSTOP:
at91EndPollStop (pDrvCtrl);
break;
case EIOCGMIB2:
if (data == NULL)
return (EINVAL);
bcopy((char *)&pDrvCtrl->end.mib2Tbl, (char *)data,
sizeof(pDrvCtrl->end.mib2Tbl));
break;
case EIOCGFBUF:
if (data == NULL)
return (EINVAL);
*(int *)data = 0; /**END_MIN_FBUF;**/
break;
default:
error = EINVAL;
}
/*
ENDLOGMSG ((" Leave at91EndIoctl routine...\n", 1, 2, 3, 4, 5, 6));
*/
return (error);
}
/******************************************************************************
*
* at91EndConfig - reconfigure the interface under us.
*
* Reconfigure the interface setting promiscuous mode
*
* RETURNS: N/A.
*/
LOCAL void at91EndConfig
(
at91end_device *pDrvCtrl /* device to be re-configured */
)
{
at91EmacReset(pDrvCtrl); /* reset the chip */
/* Set up address filter for multicasting. */
if ( END_MULTI_LST_CNT( &pDrvCtrl->end ) > 0 )
at91EndAddrFilterSet ( pDrvCtrl );
at91EndFdFree(pDrvCtrl); /* Free the FDs */
at91EndFdInitialize(pDrvCtrl); /* Reinitialize FDs */
at91EndMacInitialize( pDrvCtrl ); /* Initialize MAC */
/* Was started before in interrupt mode? */
if ( (END_FLAGS_GET(&pDrvCtrl->end) & IFF_RUNNING) &&
((pDrvCtrl->flags & LS_POLLING) == 0) )
at91EndStart(pDrvCtrl); /* Start again */
return;
}
/*******************************************************************************
*
* at91EndPollStart - start polled mode operations
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndPollStart
(
at91end_device* pDrvCtrl /* device to be polled */
)
{
int oldLevel;
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
oldLevel = intLock (); /* disable ints during update */
intDisable (pDrvCtrl->level);
pDrvCtrl->flags |= LS_POLLING;
intUnlock (oldLevel); /* now at91EndInt won't get confused */
ENDLOGMSG (( "POLLing STARTED\n", 1, 2, 3, 4, 5, 6 ));
at91EndConfig (pDrvCtrl); /* reconfigure device */
/*
* enable receive
*/
pemac ->EMAC_CTL = EMAC_CTL_RE | EMAC_CTL_TE;
/* Set the flags to indicate that the device is up */
END_FLAGS_SET (&pDrvCtrl->end, IFF_UP | IFF_RUNNING);
return (OK);
}
/*******************************************************************************
*
* at91EndPollStop - stop polled mode operations
*
* This function terminates polled mode operation. The device returns to
* interrupt mode.
*
* The device interrupts are enabled, the current mode flag is switched
* to indicate interrupt mode and the device is then reconfigured for
* interrupt operation.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EndPollStop
(
at91end_device* pDrvCtrl /* device to be changed */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
int oldLevel;
/*
* stop all
*/
pemac ->EMAC_CTL = 0;
oldLevel = intLock (); /* disable ints during register updates */
pDrvCtrl->flags &= ~LS_POLLING;
intUnlock (oldLevel);
/*
* Restart in interrupt mode. Calling at91EndConfig without clearing
* IFF_RUNNING flag will result in calling at91EndStart automatically
*/
at91EndConfig (pDrvCtrl);
ENDLOGMSG (("END POLLing STOPPED\n", 1, 2, 3, 4, 5, 6));
return (OK);
}
/*******************************************************************************
*
* at91EndPollRcv - routine to receive a packet in polled mode.
*
* This routine is called by a user to try and get a packet from the
* device.
*
* RETURNS: OK upon success. EAGAIN is returned when no packet is available.
*/
LOCAL STATUS at91EndPollRcv
(
at91end_device *pDrvCtrl, /* device to be polled */
M_BLK_ID pMblk /* ptr to buffer */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
int len;
UINT32 rxptr;
STATUS retVal = EAGAIN;
ENDLOGMSG (( "entering at91EndPollRcv\n", 1, 2, 3, 4, 5, 6 ));
rxptr = pDrvCtrl ->rxBufPtr;
if( ( (pDrvCtrl ->RecvBufDesc[rxptr].bufaddr) & EMAC_RECV_DESC_HAVE_DATA ) == 0 )
return EAGAIN;
/* Upper layer must provide a valid buffer. */
len = pDrvCtrl ->RecvBufDesc[rxptr].recvstatus & (0x7FF) ;
if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT)))
{
ENDLOGMSG( ( "END: poll receive buffer too small to fit received buffer\n", 1,2,3,4,5,6 ) );
goto pollRcvExit;
}
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
bcopy ( (char*)(pDrvCtrl ->RecvBufDesc[rxptr].bufaddr&0xFFFFFFFC), pMblk->m_data, len );
pMblk->m_len = len;
/*pMblk->mBlkHdr.mData += OFFSET;*/
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
pMblk->mBlkPktHdr.len = len;
retVal = OK;
ENDLOGMSG ((" proces at91EndPollRcv OK\n", 1, 2, 3, 4, 5, 6));
pollRcvExit:
pDrvCtrl ->RecvBufDesc[rxptr].bufaddr &= 0xFFFFFFFE;
if( rxptr == (RX_FD_NUM-1) )
pDrvCtrl ->rxBufPtr = 0;
else
pDrvCtrl ->rxBufPtr ++;
return retVal;
}
/*******************************************************************************
*
* at91EndPollSend - routine to send a packet in polled mode.
*
* This routine is called by a user to try and send a packet on the
* device.
*
* RETURNS: OK upon success. EAGAIN if device is busy.
*/
LOCAL STATUS at91EndPollSend
(
at91end_device* pDrvCtrl, /* device to be polled */
M_BLK_ID pMblk /* packet to send */
)
{
EMAC_S* pemac = (EMAC_S*)EMAC_BASE_ADDR;
UINT32 curTxptr = pDrvCtrl ->TxPtr;
int len;
ENDLOGMSG ((" enter at91EndPollSend\n", 1, 2, 3, 4, 5, 6 ));
if( !(pemac ->EMAC_TSR&EMAC_TSR_TXIDLE ) )
{
return EAGAIN;
}
len = pMblk->mBlkPktHdr.len;
/* Set pointers in local structures to point to data. */
netMblkToBufCopy(pMblk, (void *)pDrvCtrl ->pTxBufStart[curTxptr].bufaddr, NULL) ;
pDrvCtrl ->pTxBufStart[curTxptr].len = len;
/*
* start transmit
*/
pemac ->EMAC_TAR = (UINT32)pDrvCtrl ->pTxBufStart[curTxptr].bufaddr;
pemac ->EMAC_TCR = len&(0x7FF);
/* Bump the statistic counter. */
END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);
/*
* Cleanup. The driver must either free the packet now or
* set up a structure so it can be freed later after a transmit
* interrupt occurs.
*/
netMblkClChainFree (pMblk);
ENDLOGMSG (("leaving at91EndPollSend\n", 1, 2, 3, 4, 5, 6));
return (OK);
}
/******************************************************************************
*
* at91EndAddrFilterSet - set the address filter for multicast addresses
*
* This routine goes through all of the multicast addresses on the list
* of addresses (added with the endAddrAdd() routine) and sets the
* device's filter correctly.
*
* RETURNS: N/A.
*/
LOCAL void at91EndAddrFilterSet
(
at91end_device *pDrvCtrl /* device to be updated */
)
{
ETHER_MULTI* pCurr;
UINT32 count;
ENDLOGMSG ((" Enter at91EndAddrFilterSet routine...\n", 1, 2, 3, 4, 5, 6));
for ( count = 0; count < (AT91EMAC_MAX_MULTI+1); count++ )
{
pDrvCtrl->addrListLow[count] = /* Zero the addresses */
pDrvCtrl->addrListHigh[count] = 0;
}
pDrvCtrl->mcastAddrCount = 0; /* Init the multi count */
pCurr = END_MULTI_LST_FIRST ( &pDrvCtrl->end );
/*
* Now copy the addresses from ether_multi_list to our own array. In our
* array, the first 6 bytes are for our own MAC address. This array is
* an exact replica of the internal CAM registers of Ethernet controller.
* The CAM registers will be updated in at91EndMacInitialize() function
*/
while ( pCurr != NULL )
{
if (pDrvCtrl->mcastAddrCount > AT91EMAC_MAX_MULTI )
break;
FormatETHSpecialAddrWord( &( pDrvCtrl ->addrListHigh[ pDrvCtrl ->mcastAddrCount + 1 ] ),
&(pDrvCtrl ->addrListLow[ pDrvCtrl ->mcastAddrCount + 1 ]), (BYTE*)(pCurr->addr) );
pDrvCtrl ->mcastAddrCount++; /* Bump the multicast address count */
pCurr = END_MULTI_LST_NEXT(pCurr); /* Get the next address in the list */
}
ENDLOGMSG ((" Leave at91EndAddrFilterSet routine...\n", 1, 2, 3, 4, 5, 6));
}
/*****************************************************************************
*
* at91EndMCastAdd - add a multicast address for the device
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -