📄 mbcend.c
字号:
if (!(pDrvCtrl->flags & MBC_POLLING)) END_TX_SEM_GIVE (&pDrvCtrl->end); return (END_ERR_BLOCK); } pOrig = pBuf = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId); if (pBuf == NULL) { DRV_LOG (DRV_DEBUG_TX | DRV_DEBUG_ERROR, "%s%d: mbcSend: out of clusters\n", (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); if (!(pDrvCtrl->flags & MBC_POLLING)) END_TX_SEM_GIVE (&pDrvCtrl->end); netMblkClChainFree (pMblk); return (ERROR); } pBuf += pDrvCtrl->offset; len = netMblkToBufCopy (pMblk, pBuf, NULL); netMblkClChainFree (pMblk); len = max (len, ETHERSMALL); /* place a transmit request */ if (!(pDrvCtrl->flags & MBC_POLLING)) oldLevel = intLock (); pTxBd->dataPointer = pBuf; pTxBd->dataLength = len; pTxBd->statusMode &= ~(MBC_TXBD_ERRS|MBC_TXBD_RC); pTxBd->statusMode |= MBC_TXBD_R; /* Advance our management index, and register for cleaning */ pDrvCtrl->txBdNext = (pDrvCtrl->txBdNext + 1) % pDrvCtrl->txBdNum; pDrvCtrl->freeRtn [pDrvCtrl->txBdNext] = (FUNCPTR) netClFree; pDrvCtrl->freeData [pDrvCtrl->txBdNext].arg1 = pDrvCtrl->end.pNetPool; pDrvCtrl->freeData [pDrvCtrl->txBdNext].arg2 = pOrig; if (!(pDrvCtrl->flags & MBC_POLLING)) { intUnlock (oldLevel); END_TX_SEM_GIVE (&pDrvCtrl->end); } /* Bump the statistic counter. */ END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1); return (OK); }/******************************************************************************** mbcPacketGet - get next received message** Get next received message. Returns NULL if none are* ready.** RETURNS: ptr to next packet, or NULL if none ready.** NOMANUAL*/char* mbcPacketGet ( MBC_DEVICE * pDrvCtrl /* device structure */ ) { volatile MBC_BD * pRxBd; pRxBd = &pDrvCtrl->rxBdBase [pDrvCtrl->rxBdNext]; while (!(pRxBd->statusMode & MBC_RXBD_E)) { /* data chaining is not supported - check all error conditions */ 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))) { return (pRxBd->dataPointer); } END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1); /* * Fix for errata #9 -- Device Errata, Feb 20, 1997. * Ethernet frames may be incorrectly received after a rx FIFO * overflow. */ if ((pRxBd->statusMode & MBC_RXBD_L) && !(pRxBd->statusMode & MBC_RXBD_F)) { mbcDeviceRestart (pDrvCtrl); return (NULL); } /* reset buffer descriptor as empty */ pRxBd->statusMode |= MBC_RXBD_E; /* Advance our management index */ pDrvCtrl->rxBdNext = (pDrvCtrl->rxBdNext + 1) % pDrvCtrl->rxBdNum; pRxBd = &pDrvCtrl->rxBdBase [pDrvCtrl->rxBdNext]; } return (NULL); }/******************************************************************************** mbcRecv - process the next incoming packet** Handles one incoming packet. The packet is checked for errors.** RETURNS: OK.** NOMANUAL**/LOCAL STATUS mbcRecv ( MBC_DEVICE * pDrvCtrl, /* device structure */ char * pData /* packet to process */ ) { int len; M_BLK_ID pMblk; char * pNewCluster; char * pCluster; CL_BLK_ID pClBlk; volatile MBC_BD * pRxBd; pRxBd = &pDrvCtrl->rxBdBase [pDrvCtrl->rxBdNext]; /* * We implicitly are loaning here, if copying is necessary this * step may be skipped, but the data must be copied before being * passed up to the protocols. */ pNewCluster = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId); if (pNewCluster == NULL) { DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_ERROR, "%s%d: mbcRecv: out of clusters\n", (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } /* Grab a cluster block to marry to the cluster we received. */ pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT); if (pClBlk == NULL) { DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_ERROR, "%s%d: mbcRecv: out of cluster blocks\n", (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); netClFree (pDrvCtrl->end.pNetPool, pNewCluster); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } /* * OK we've got a spare, let's get an M_BLK_ID and marry it to the * one in the ring. */ pMblk = mBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT, MT_DATA); if (pMblk == NULL) { DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_ERROR, "%s%d: mbcRecv: out of M blocks\n", (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6); netClBlkFree (pDrvCtrl->end.pNetPool, pClBlk); netClFree (pDrvCtrl->end.pNetPool, pNewCluster); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } DRV_LOG (DRV_DEBUG_RX, "%s%d: mbcRecv %d: dataLength=%d dataPointer=%x data=%x\n", (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->rxBdNext, pRxBd->dataLength, (int) pRxBd->dataPointer, (int) pData); /* Add one to our unicast data. */ END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1); len = pRxBd->dataLength; pCluster = pRxBd->dataPointer - pDrvCtrl->offset; /* Join the cluster to the MBlock */ netClBlkJoin (pClBlk, pCluster, len, NULL, 0, 0, 0); netMblkClJoin (pMblk, pClBlk); pMblk->mBlkHdr.mData += pDrvCtrl->offset; pMblk->mBlkHdr.mLen = len; pMblk->mBlkHdr.mFlags |= M_PKTHDR; pMblk->mBlkPktHdr.len = len; /* make the packet data coherent */ MBC_CACHE_INVALIDATE (pMblk->mBlkHdr.mData, len); /* Installed (adjusted) new cluster, and reset descriptor */ pRxBd->dataPointer = pNewCluster + pDrvCtrl->offset; pRxBd->statusMode |= MBC_RXBD_E; /* Advance our management index */ pDrvCtrl->rxBdNext = (pDrvCtrl->rxBdNext + 1) % pDrvCtrl->rxBdNum;#ifdef DRV_DEBUG { char *pAddress = pCluster + pDrvCtrl->offset; if (pAddress[0] & 0x01) DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_MULTI, "Recv Multicast %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); }#endif /* Call the upper layer's receive routine. */ END_RCV_RTN_CALL (&pDrvCtrl->end, pMblk); return (OK);cleanRXD: /* Reset descriptor and advance management index */ pRxBd->statusMode |= MBC_RXBD_E; pDrvCtrl->rxBdNext = (pDrvCtrl->rxBdNext + 1) % pDrvCtrl->rxBdNum; return (OK); }/******************************************************************************** mbcHandleRcvInt - 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.** The double loop is to protect against a race condition where the interrupt* code see rxHandling as TRUE, but it is then turned off by task code.* This race is not fatal, but does cause occassional delays until a second* packet is received and then triggers the netTask to call this routine again.** RETURNS: N/A.*/LOCAL void mbcHandleRcvInt ( MBC_DEVICE * pDrvCtrl /* interrupting device */ ) { char * pData; do { pDrvCtrl->rxHandling = TRUE; while ((pData = mbcPacketGet (pDrvCtrl)) != NULL) mbcRecv (pDrvCtrl, pData); pDrvCtrl->rxHandling = FALSE; } while (mbcPacketGet (pDrvCtrl) != NULL); }/******************************************************************************** mbcIoctl - the driver I/O control routine** Process an ioctl request.** RETURNS: A command specific response, usually OK or ERROR.*/LOCAL int mbcIoctl ( void * pObj, /* device receiving command */ int cmd, /* ioctl command code */ caddr_t data /* command argument */ ) { MBC_DEVICE * pDrvCtrl = pObj; /* device receiving command */ int error = 0; long value; 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 - 1); END_FLAGS_CLR (&pDrvCtrl->end, value); } else { END_FLAGS_SET (&pDrvCtrl->end, value); } mbcConfig (pDrvCtrl); break; case EIOCGFLAGS: *(int *)data = END_FLAGS_GET(&pDrvCtrl->end); break; case EIOCPOLLSTART: /* Begin polled operation */ mbcPollStart (pDrvCtrl); break; case EIOCPOLLSTOP: /* End polled operation */ mbcPollStop (pDrvCtrl); break; 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 = MBC_MIN_FBUF; break; default: error = EINVAL; } return (error); }/******************************************************************************** mbcAddrFilterSet - 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.*/void mbcAddrFilterSet ( MBC_DEVICE * pDrvCtrl /* device to be updated */ ) { int len; int count; u_char c; u_char * pCp; u_long crc; ETHER_MULTI * pCurr; pDrvCtrl->mcastFilter[0] = 0x00; pDrvCtrl->mcastFilter[1] = 0x00; pDrvCtrl->mcastFilter[2] = 0x00; pDrvCtrl->mcastFilter[3] = 0x00; pDrvCtrl->mcastFilter[4] = 0x00; pDrvCtrl->mcastFilter[5] = 0x00; pDrvCtrl->mcastFilter[6] = 0x00; pDrvCtrl->mcastFilter[7] = 0x00; for (pCurr = END_MULTI_LST_FIRST (&pDrvCtrl->end); pCurr != NULL; pCurr = END_MULTI_LST_NEXT(pCurr)) { /* * AUTODIN-II, adapted for ethernet (bit reversed), * taken from the ln7990End.c driver */ pCp = (unsigned char *)&pCurr->addr; crc = 0xffffffff; for (len = 6; --len >= 0;) { c = *pCp++; for (count = 0; count < 8; count++) { if ((c & 0x01) ^ (crc & 0x01)) { crc >>= 1; crc = crc ^ 0xedb88320; } else { crc >>= 1; } c >>= 1; } } /* Just want the 6 most significant bits. */ crc = crc >> 26; /* Turn on the corresponding bit in the filter. */ pDrvCtrl->mcastFilter [crc >> 3] |= (1 << (crc & 0x07)); } }/******************************************************************************** mbcPollRcv - routine to receive a packet in polled mode.** This routine is called by a user to try and get a packet from the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -