📄 at91emacend.c
字号:
case EIOCGMIB2233:
case EIOCGMIB2: /* return MIB information */
if (data == NULL)
return(EINVAL);
bcopy((char *)&pDrvCtrl->end.mib2Tbl, (char *)data,
sizeof(pDrvCtrl->end.mib2Tbl));
break;
case EIOCGFBUF: /* return minimum First Buffer for chaining */
if (data == NULL)
return(EINVAL);
*(int *)data = EMAC_MIN_FBUF;
break;
case EIOCGHDRLEN:
if (data == NULL)
return(EINVAL);
*(int *)data = EH_SIZE;
break;
default: /* unknown request */
error = EINVAL;
}
return(error);
}
/******************************************************************************
*
* at91EmacEndConfig - reconfigure the interface under us.
*
* Reconfigure the interface setting promiscuous mode, and changing the
* multicast interface list.
*
* RETURNS: N/A.
*/
LOCAL void at91EmacEndConfig
(
EMAC_END_DEVICE *pDrvCtrl /* device to be re-configured */
)
{
/* Set promiscuous mode if it's asked for. */
if (END_FLAGS_GET(&pDrvCtrl->end) & IFF_PROMISC)
{
EMAC_REG(EMAC_CFG) |= EMAC_CFG_CAF;
EMAC_END_LOG (EMAC_END_DBG_IOCTL, "Setting promiscuous mode on!\n", 1, 2, 3, 4, 5, 6);
}
else
{
EMAC_REG(EMAC_CFG) &= ~EMAC_CFG_CAF;
EMAC_END_LOG (EMAC_END_DBG_IOCTL, "Setting promiscuous mode off!\n", 1, 2, 3, 4, 5, 6);
}
/* Set up address filter for multicasting. */
if (END_MULTI_LST_CNT(&pDrvCtrl->end) > 0)
{
at91EmacEndAddrFilterSet (pDrvCtrl);
}
return;
}
/*******************************************************************************
*
* at91EmacEndCrcGet - compute the cyclic redoundant code
*
* This routine computes the 32-bit cyclic redoundant code (CRC) for the
* 6-byte array pointed to by <pAddr>.
*
* RETURNS: The 32-bit value representing the CRC.
*/
LOCAL UINT32 at91EmacEndCrcGet
(
UCHAR * pAddr
)
{
UINT32 crc = INIT_REFLECTED;
UINT32 len = 6;
while (len--)
{
crc = crc32table[(crc ^ *pAddr++) & 0xFFL] ^ (crc >> 8);
}
return crc;
}
/******************************************************************************
*
* at91EmacEndAddrFilterSet - 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 at91EmacEndAddrFilterSet
(
EMAC_END_DEVICE *pDrvCtrl /* device to be updated */
)
{
ETHER_MULTI * pCurr;
UINT32 crc;
UINT32 index;
int count;
UINT32 hashTbl[2];
hashTbl[0] = 0;
hashTbl[1] = 0;
count = 0;
pCurr = END_MULTI_LST_FIRST (&pDrvCtrl->end);
while (pCurr != NULL)
{
crc = at91EmacEndCrcGet((UCHAR *) &pCurr->addr);
index = EMAC_CRC_TO_FILTER_INDEX (crc);
/* hash table is on 64 bits (6 bits indexed) */
hashTbl[index >> 5] |= 1 << (index & 31);
count++;
EMAC_END_LOG (EMAC_END_DBG_HASH, "at91EmacEndAddrFilterSet: %02x:%02x:%02x:%02x:%02x:%02x\n",
pCurr->addr[0], pCurr->addr[1], pCurr->addr[2], pCurr->addr[3], pCurr->addr[4], pCurr->addr[5]);
EMAC_END_LOG (EMAC_END_DBG_HASH, "at91EmacEndAddrFilterSet: crc = 0x%x, index = %i (%i)\n",
crc, index, count, 4, 5, 6);
pCurr = END_MULTI_LST_NEXT(pCurr);
}
EMAC_REG(EMAC_HSH) = hashTbl[1];
EMAC_REG(EMAC_HSL) = hashTbl[0];
if (count > 0)
{
EMAC_REG(EMAC_CFG) |= EMAC_CFG_MTI;
EMAC_END_LOG (EMAC_END_DBG_HASH, "Enable Multicast Hash (hsh = 0x%08x, hsl = 0x%08x)!\n",
hashTbl[1], hashTbl[0], 3, 4, 5, 6);
}
else
{
EMAC_REG(EMAC_CFG) &= ~EMAC_CFG_MTI;
EMAC_END_LOG (EMAC_END_DBG_HASH, "Disable Multicast Hash (hsh = 0x%08x, hsl = 0x%08x)!\n",
hashTbl[1], hashTbl[0], 3, 4, 5, 6);
}
}
/*******************************************************************************
*
* at91EmacEndPollRcv - routine to receive a packet in polled mode.
*
* Polled mode operation takes place without any kernel or other OS
* services available. Use extreme care to insure that this code does not
* call any kernel services. Polled mode is only for WDB system mode use.
* Kernel services, semaphores, tasks, etc, are not available during WDB
* system mode.
*
* The WDB agent polls the device constantly looking for new data. Typically
* the device has a ring of RFDs to receive incoming packets. This routine
* examines the ring for any new data and copies it to the provided mblk.
* The concern here is to keep the device supplied with empty buffers at all
* time.
*
* RETURNS: OK upon success. EAGAIN is returned when no packet is available.
* A return of ERROR indicates a hardware fault or no support for polled mode
* at all.
*/
LOCAL STATUS at91EmacEndPollRcv
(
EMAC_END_DEVICE * pDrvCtrl, /* device to be polled */
M_BLK_ID pMblk /* ptr to buffer */
)
{
char * pPacket;
int len = 0;
int count;
volatile RXBUF_HDR * pRxHdr;
/* check for an incoming packet */
count = 0;
while ((pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs & RXBUF_ADD_OWNED) != RXBUF_ADD_OWNED
&& count < pDrvCtrl->rxNum)
{
count++;
/* update index */
if (pDrvCtrl->rxIndex == (pDrvCtrl->rxNum - 1))
{
pDrvCtrl->rxIndex = 0;
}
else
{
pDrvCtrl->rxIndex++;
}
}
if (count >= pDrvCtrl->rxNum)
{
return(EAGAIN);
}
pRxHdr = (volatile RXBUF_HDR *) &pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex];
if ((pRxHdr->adrs & RXBUF_ADD_OWNED) != RXBUF_ADD_OWNED)
{
return(EAGAIN);
}
/* Get packet and length from device buffer/descriptor */
len = pRxHdr->status & RXBUF_STAT_LEN_MASK; /* size including FCS */
pPacket = (char *) (pRxHdr->adrs & RXBUF_ADD_BASE_MASK);
/* Upper layer must provide a valid buffer. */
if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT)))
{
return (EAGAIN);
}
/* Invalidate cache */
END_CACHE_INVALIDATE(pPacket,len);
/* Process device packet into net buffer */
pMblk->m_data += 2; /* ensure that IP header is word aligned */
bcopy (pPacket, pMblk->m_data, 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 */
/* give back buffer to EMAC (DMA) */
pRxHdr->adrs &= ~RXBUF_ADD_OWNED;
/* clear any status bits that may be set. */
EMAC_REG(EMAC_RSR) = (EMAC_RSR_REC | EMAC_RSR_OVR | EMAC_RSR_BNA);
at91EmacEndNumRecv++;
return (OK);
}
/*******************************************************************************
*
* at91EmacEndPollSend - routine to send a packet in polled mode.
*
* Polled mode operation takes place without any kernel or other OS
* services available. Use extreme care to insure that this code does not
* call any kernel services. Polled mode is only for WDB system mode use.
* Kernel services, semaphores, tasks, etc, are not available during WDB
* system mode.
*
* A typical implementation is to set aside a fixed buffer for polled send
* operation. Copy the mblk data to the buffer and pass the fixed buffer
* to the device. Performance is not a consideration for polled operations.
*
* An alternate implementation is a synchronous one. The routine accepts
* user data but does not return until the data has actually been sent. If an
* error occurs, the routine returns EAGAIN and the user will retry the request.
*
* If the device returns OK, then the data has been sent and the user may free
* the associated mblk. The driver never frees the mblk in polled mode.
* The calling routine will free the mblk upon success.
*
* RETURNS: OK upon success. EAGAIN if device is busy or no resources.
* A return of ERROR indicates a hardware fault or no support for polled mode
* at all.
*/
LOCAL STATUS at91EmacEndPollSend
(
EMAC_END_DEVICE* pDrvCtrl, /* device to be polled */
M_BLK_ID pMblk /* packet to send */
)
{
int len;
UINT32 stat;
/* Check if TX is busy */
stat = EMAC_REG(EMAC_TSR);
if ((stat & EMAC_TSR_BNQ) != EMAC_TSR_BNQ)
{
return ((STATUS) EAGAIN);
}
/* Copy data from mblk */
len = netMblkToBufCopy (pMblk, pDrvCtrl->pTxPollBuf, NULL);
len = max (ETHERSMALL, len);
/* Ensure data coherency */
END_CACHE_FLUSH(pDrvCtrl->pTxPollBuf,len);
/* Set the descriptor to send data */
EMAC_REG(EMAC_TAR) = (UINT32) pDrvCtrl->pTxPollBuf;
EMAC_REG(EMAC_TCR) = EMAC_TCR_LEN((UINT32) len);
at91EmacEndNumSend++;
return (OK);
}
/*****************************************************************************
*
* at91EmacEndMCastAdd - add a multicast address for the device
*
* This routine adds a multicast address to whatever the driver
* is already listening for. It then resets the address filter.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EmacEndMCastAdd
(
EMAC_END_DEVICE *pDrvCtrl, /* device pointer */
char* pAddress /* new address to add */
)
{
int error;
if ((error = etherMultiAdd (&pDrvCtrl->end.multiList,pAddress)) == ENETRESET)
{
at91EmacEndConfig (pDrvCtrl);
}
return (OK);
}
/*****************************************************************************
*
* at91EmacEndMCastDel - delete a multicast address for the device
*
* This routine removes a multicast address from whatever the driver
* is listening for. It then resets the address filter.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EmacEndMCastDel
(
EMAC_END_DEVICE *pDrvCtrl, /* device pointer */
char* pAddress /* address to be deleted */
)
{
int error;
if ((error = etherMultiDel (&pDrvCtrl->end.multiList, (char *)pAddress)) == ENETRESET)
{
at91EmacEndConfig (pDrvCtrl);
}
return (OK);
}
/*****************************************************************************
*
* at91EmacEndMCastGet - get the multicast address list for the device
*
* This routine gets the multicast list of whatever the driver
* is already listening for.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EmacEndMCastGet
(
EMAC_END_DEVICE *pDrvCtrl, /* device pointer */
MULTI_TABLE* pTable /* address table to be filled in */
)
{
return (etherMultiGet (&pDrvCtrl->end.multiList, pTable));
}
/*******************************************************************************
*
* at91EmacEndStop - stop the device
*
* This function calls BSP functions to disconnect interrupts and stop
* the device from operating in interrupt mode.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS at91EmacEndStop
(
EMAC_END_DEVICE *pDrvCtrl /* device to be stopped */
)
{
STATUS result = OK;
END_FLAGS_CLR (&pDrvCtrl->end, IFF_UP | IFF_RUNNING);
/* Disable TX/RX */
EMAC_REG(EMAC_CTL) &= ~(EMAC_CTL_TE | EMAC_CTL_RE);
/* Disable interrupts */
EMAC_REG(EMAC_IDR) = EMAC_INT_RCOM | EMAC_INT_RBNA
| EMAC_INT_TUND | EMAC_INT_RTRY | EMAC_INT_TCOM
| EMAC_I
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -