📄 mbcend.c
字号:
* device.** RETURNS: OK upon success. EAGAIN is returned when no packet is available.*/LOCAL STATUS mbcPollRcv ( void * pObj, /* device to be polled */ M_BLK_ID pMblk /* ptr to buffer */ ) { int len; MBC_DEVICE * pDrvCtrl = pObj; /* device to be polled */ volatile MBC_BD * pRxBd; pRxBd = &pDrvCtrl->rxBdBase [pDrvCtrl->rxBdNext]; len = pRxBd->dataLength; /* If no packet is available return immediately */ if (pRxBd->statusMode & MBC_RXBD_E) return (EAGAIN); /* Upper layer must provide a valid buffer. */ if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT))) { DRV_LOG (DRV_DEBUG_POLL_RX, "%s%d: mbcPollRcv: rxBdNext=%d bad mblk\n", (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->rxBdNext, 4, 5, 6); return (EAGAIN); } /* Check packet and device for errors */ if (((pRxBd->statusMode & (MBC_RXBD_F | MBC_RXBD_L)) != (MBC_RXBD_F | MBC_RXBD_L)) || (pRxBd->statusMode & (MBC_RXBD_CL | MBC_RXBD_OV | MBC_RXBD_CR | MBC_RXBD_SH | MBC_RXBD_NO | MBC_RXBD_LG))) { /* packet has an error */ DRV_LOG (DRV_DEBUG_POLL_RX | DRV_DEBUG_ERROR, "%s%d: mbcPollRcv: rxBdNext=%d bad packet stat=%x\n", (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->rxBdNext, pRxBd->statusMode, 5, 6); pRxBd->statusMode |= MBC_RXBD_E; pDrvCtrl->rxBdNext = (pDrvCtrl->rxBdNext + 1) % pDrvCtrl->rxBdNum; return (EAGAIN); } END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1); pMblk->mBlkHdr.mData += pDrvCtrl->offset; bcopy (pRxBd->dataPointer, pMblk->mBlkHdr.mData, len); pMblk->mBlkHdr.mLen = len; pMblk->mBlkHdr.mFlags |= M_PKTHDR; pMblk->mBlkPktHdr.len = len; /* Done with packet, clean up and give it to the device. */ pRxBd->statusMode |= MBC_RXBD_E; pDrvCtrl->rxBdNext = (pDrvCtrl->rxBdNext + 1) % pDrvCtrl->rxBdNum; DRV_LOG (DRV_DEBUG_POLL_RX, "%s%d: mbcPollRcv: rxBdNext=%d good packet len=%d\n", (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->rxBdNext, len, 5, 6); return (OK); }/******************************************************************************** mbcPollSend - routine to send a packet in polled mode.** This routine is called by a user to try to send a packet on the* device.** RETURNS: OK upon success. EAGAIN if device is busy.*/LOCAL STATUS mbcPollSend ( void * pObj, /* device to be polled */ M_BLK_ID pMblk /* packet to send */ ) { char * pBuf = NULL; int len; int oldLevel; MBC_DEVICE * pDrvCtrl = pObj; /* device to be polled */ volatile MBC_BD * pTxBd; /* test to see if TX is busy */ pTxBd = &pDrvCtrl->txBdBase [pDrvCtrl->txBdNext]; if (pTxBd->statusMode & MBC_TXBD_R) { DRV_LOG (DRV_DEBUG_POLL_TX | DRV_DEBUG_ERROR, "%s%d: mbcPollSend: no Tx desc. txBdNext=%d\n", (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->txBdNext, 4, 5, 6); return (EAGAIN); } /* Check if descriptor is clean */ if (pTxBd->dataPointer) { DRV_LOG (DRV_DEBUG_POLL_TX | DRV_DEBUG_ERROR, "%s%d: mbcPollSend: needs cleaning\n", (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); if (!pDrvCtrl->txCleaning == TRUE); netJobAdd ((FUNCPTR)mbcScrubTRing, (int) pDrvCtrl, 0, 0, 0, 0); return (EAGAIN); } /* * If packet is in a single block, we can transmit * directly from the M_BLK, otherwise we have to copy. */ #if 0 /* XXX */ if (pMblk->mBlkHdr.mNext == NULL) { len = max (ETHERSMALL, pMblk->m_len); pTxBd->dataPointer = pMblk->m_data; } else#endif /* 0 */ { pBuf = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId); if (pBuf == NULL) { DRV_LOG (DRV_DEBUG_POLL_TX | DRV_DEBUG_ERROR, "%s%d: mbcPollSend: no clusters\n", (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); return (EAGAIN); } len = netMblkToBufCopy (pMblk, pBuf, NULL); pTxBd->dataPointer = pBuf; } DRV_LOG (DRV_DEBUG_POLL_TX, "%s%d: mbcPollSend: txBdNext=%d len=%d\n", (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->txBdNext, len, 5, 6); CACHE_PIPE_FLUSH (); /* Bump the statistic counter. */ END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1); /* Start transmission */ oldLevel = intLock (); pTxBd->dataLength = len; pTxBd->statusMode &= ~(MBC_TXBD_ERRS|MBC_TXBD_RC); pTxBd->statusMode |= MBC_TXBD_R; intUnlock (oldLevel); /* Advance our management index. */ pDrvCtrl->txBdNext = (pDrvCtrl->txBdNext + 1) % pDrvCtrl->txBdNum; /* Spin until packet has been sent. */ while (pTxBd->statusMode & MBC_TXBD_R) ; /* Manually clean descriptor. */ pTxBd->dataPointer = NULL; pTxBd->statusMode &= ~MBC_TXBD_ERRS; /* Free allocated cluster (if any), and clean tx ring (if needed) */ if (pBuf != NULL) netClFree (pDrvCtrl->end.pNetPool, pBuf); if (!pDrvCtrl->txCleaning) { pDrvCtrl->txCleaning = TRUE; mbcScrubTRing (pDrvCtrl); } return (OK); }/******************************************************************************** mbcMCastAdd - 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 mbcMCastAdd ( void * pObj, /* device pointer */ char * pAddress /* new address to add */ ) { int error; MBC_DEVICE * pDrvCtrl = pObj; /* device pointer */ DRV_LOG (DRV_DEBUG_LOAD | DRV_DEBUG_MULTI, "mbcMCastAdd %02x:%02x:%02x:%02x:%02x:%02x\n", pAddress[0]&0xff, pAddress[1]&0xff, pAddress[2]&0xff, pAddress[3]&0xff, pAddress[4]&0xff, pAddress[5]&0xff); error = etherMultiAdd (&pDrvCtrl->end.multiList, pAddress); if (error == ENETRESET) mbcConfig (pDrvCtrl); return (OK); }/******************************************************************************** mbcMCastDel - 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 mbcMCastDel ( void * pObj, /* device pointer */ char * pAddress /* address to be deleted */ ) { int error; MBC_DEVICE * pDrvCtrl = pObj; /* device pointer */ DRV_LOG (DRV_DEBUG_LOAD | DRV_DEBUG_MULTI, "mbcMCastDel %02x:%02x:%02x:%02x:%02x:%02x\n", pAddress[0]&0xff, pAddress[1]&0xff, pAddress[2]&0xff, pAddress[3]&0xff, pAddress[4]&0xff, pAddress[5]&0xff); error = etherMultiDel (&pDrvCtrl->end.multiList, pAddress); if (error == ENETRESET) mbcConfig (pDrvCtrl); return (OK); }/******************************************************************************** mbcMCastGet - 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 mbcMCastGet ( void * pObj, /* device pointer */ MULTI_TABLE * pTable /* address table to be filled in */ ) { MBC_DEVICE * pDrvCtrl = pObj; /* device pointer */ return (etherMultiGet (&pDrvCtrl->end.multiList, pTable)); }/******************************************************************************** mbcStop - 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 mbcStop ( void * pObj /* device to be stopped */ ) { MBC_DEVICE * pDrvCtrl = pObj; /* device to be stopped */ STATUS result = OK; /* stop/disable the device. */ mbcReset (pDrvCtrl); SYS_INT_DISCONNECT (pDrvCtrl, mbcInt, (int)pDrvCtrl, &result);#ifdef DRV_DEBUG if (result == ERROR) { DRV_LOG (DRV_DEBUG_LOAD | DRV_DEBUG_ERROR, "Could not disconnect interrupt!\n", 1, 2, 3, 4, 5, 6); }#endif /* DRV_DEBUG */ return (result); }/******************************************************************************** mbcUnload - unload a driver from the system** This function first brings down the device, and then frees any* stuff that was allocated by the driver in the load function.** RETURNS: OK.*/LOCAL STATUS mbcUnload ( void * pObj /* device to be unloaded */ ) { MBC_DEVICE * pDrvCtrl = pObj; /* device to be unloaded */ END_OBJECT_UNLOAD (&pDrvCtrl->end); /* Free the shared DMA memory. */ if (pDrvCtrl->flags & MBC_MEM_ALLOC_FLAG) cacheDmaFree (pDrvCtrl->bufBase); return (OK); }/******************************************************************************** mbcPollStart - start polled mode operations** RETURNS: OK.*/LOCAL STATUS mbcPollStart ( MBC_DEVICE * pDrvCtrl /* device to be polled */ ) { int oldLevel; DRV_LOG (DRV_DEBUG_POLL, "%s%d: ultraPollStart\n", (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); oldLevel = intLock (); /* disable ints during update */ SYS_OUT_SHORT (pDrvCtrl, MBC_IMASK, 0x00); pDrvCtrl->flags |= MBC_POLLING; intUnlock (oldLevel); /* now mbcInt won't get confused */ return (OK); }/******************************************************************************** mbcPollStop - 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 mbcPollStop ( MBC_DEVICE * pDrvCtrl /* device to be polled */ ) { int oldLevel; DRV_LOG (DRV_DEBUG_POLL, "%s%d: ultraPollStop\n", (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); /* re-enable interrupts */ oldLevel = intLock (); /* disable ints during register updates */ SYS_OUT_SHORT (pDrvCtrl, MBC_IMASK, MBC_IMASK_RXF | MBC_IMASK_EBE); pDrvCtrl->flags &= ~MBC_POLLING; intUnlock (oldLevel); return (OK); }/******************************************************************************** mbcReset - reset device** RETURNS: N/A.** NOMANUAL*/LOCAL void mbcReset ( MBC_DEVICE * pDrvCtrl /* interrupting device */ ) { int counter = 0xffff; /* Disable interrupts */ SYS_OUT_SHORT (pDrvCtrl, MBC_IMASK, 0x00); /* clear pending `graceful stop complete' event, and start one */ SYS_OUT_SHORT (pDrvCtrl, MBC_IEVNT, MBC_IEVNT_GRA); SYS_OUT_SHORT (pDrvCtrl, MBC_ECNTL, MBC_ECNTL_GTS); /* wait for graceful stop to register */ while (counter--) { USHORT event; SYS_IN_SHORT (pDrvCtrl, MBC_IEVNT, &event); if (event & MBC_IEVNT_GRA) break; } /* disable the receiver and transmitter. */ SYS_RESET_SHORT (pDrvCtrl, MBC_ECNTL, MBC_ECNTL_ENBL); pDrvCtrl->resetCounter++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -