📄 ln7990end.c
字号:
*/LOCAL STATUS ln7990Recv ( LN7990END_DEVICE *pDrvCtrl, ln_rmd *pRmd ) { int len; u_long phys; M_BLK_ID pMblk; char* pCluster; char* pNewCluster; char* pTemp; CL_BLK_ID pClBlk; /* Packet must be checked for errors. */ /* If error flag */ /* OR if packet is not completely in one buffer */ if (LN_RMD_ERR (pRmd)) { DRV_LOG (DRV_DEBUG_RX, "RMD error!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } /* If we cannot get a buffer to loan then bail out. */ pNewCluster = netClusterGet(pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId); if (pNewCluster == NULL) { DRV_LOG (DRV_DEBUG_RX, "Cannot loan!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } if ((pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT)) == NULL) { netClFree (pDrvCtrl->end.pNetPool, pNewCluster); DRV_LOG (DRV_DEBUG_RX, "Out of Cluster Blocks!\n", 1, 2, 3, 4, 5, 6); 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. */ if ((pMblk = mBlkGet(pDrvCtrl->end.pNetPool, M_DONTWAIT, MT_DATA)) == NULL) { netClBlkFree (pDrvCtrl->end.pNetPool, pClBlk); netClFree (pDrvCtrl->end.pNetPool, pNewCluster); DRV_LOG (DRV_DEBUG_RX, "Out of M Blocks!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1); len = LN_PKT_LEN_GET (pRmd); /* get packet length */ /* Get pointer to packet */ LN_RMD_TO_ADDR (pDrvCtrl->memBase , pRmd, phys); pCluster = LN_CACHE_PHYS_TO_VIRT (phys); pCluster -= pDrvCtrl->offset; /* Join the cluster to the MBlock */ netClBlkJoin (pClBlk, pCluster, len, NULL, 0, 0, 0); netMblkClJoin (pMblk, pClBlk); /* make the packet data coherent */ LN_CACHE_INVALIDATE (pMblk->mBlkHdr.mData, len); pMblk->mBlkHdr.mData += pDrvCtrl->offset; pMblk->mBlkHdr.mLen = len; pMblk->mBlkHdr.mFlags |= M_PKTHDR; pMblk->mBlkPktHdr.len = len; DRV_LOG (DRV_DEBUG_RX, "Calling upper layer!\n", 1, 2, 3, 4, 5, 6); /* Deal with memory alignment. */ pNewCluster += pDrvCtrl->offset; LN_RMD_BUF_TO_ADDR (pRmd, pTemp, pNewCluster); LN_CLEAN_RXD (pRmd); /* Flush the write pipe */ CACHE_PIPE_FLUSH (); /* Advance our management index */ pDrvCtrl->rmdIndex = (pDrvCtrl->rmdIndex + 1) & (pDrvCtrl->rringSize - 1); /* Call the upper layer's receive routine. */ END_RCV_RTN_CALL(&pDrvCtrl->end, pMblk); return (OK);cleanRXD: LN_CLEAN_RXD (pRmd); /* Flush the write pipe */ CACHE_PIPE_FLUSH (); /* Advance our management index */ pDrvCtrl->rmdIndex = (pDrvCtrl->rmdIndex + 1) & (pDrvCtrl->rringSize - 1); return (OK); }/********************************************************************************* ln7990Send - the driver send routine** This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.* The buffer must already have the addressing information properly installed* in it. This is done by a higher layer. The last arguments are a free* routine to be called when the device is done with the buffer and a pointer* to the argument to pass to the free routine. ** RETURNS: OK or ERROR.*/LOCAL STATUS ln7990Send ( LN7990END_DEVICE *pDrvCtrl, /* device ptr */ M_BLK_ID pMblk /* data to send */ ) { ln_tmd* pTmd; int len = 0; void* pTemp; char* pBuf; char* pOrig; int s; /* * Obtain exclusive access to transmitter. This is necessary because * we might have more than one stack transmitting at once. */ if (!(pDrvCtrl->flags & LS_POLLING)) END_TX_SEM_TAKE (&pDrvCtrl->end, WAIT_FOREVER); /* * Here we handle both simple and vector transmit in the same place. * */#if 0 { M_BLK_ID pChunk; int count; pChunk = pMblk; for (count = 0; pChunk != NULL && (pChunk->mBlkHdr.mData != 0); pChunk = pChunk->m_next, count++) { if (pChunk->mBlkHdr.mLen <= 0) { netMblkClFree(pChunk); continue; } pTmd = pDrvCtrl->pTring + pDrvCtrl->tmdIndex; LN_CACHE_INVALIDATE (pTmd, TMD_SIZ); if ((pTmd->tbuf_stat & lntmd1_OWN) || (((pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1)) == pDrvCtrl->tmdIndexC)) { if (!(pDrvCtrl->flags & LS_POLLING)) END_TX_SEM_GIVE (&pDrvCtrl->end); /* Are we still on the first chunk? */ if (count == 0) netMblkClChainFree(pMblk); else /* Have to iteratively clean up. */ { } DRV_LOG (DRV_DEBUG_TX, "Out of TMDs!\n", 1, 2, 3, 4, 5, 6); return (END_ERR_BLOCK); } len = pChunk->mBlkHdr.mLen; LN_TMD_BUF_TO_ADDR(pTmd, pTemp, pChunk->mBlkHdr.mData); pTmd->tbuf_err = 0; /* clear buffer error status */ pTmd->tbuf_bcnt = -len; /* negative message byte count */ if (count == 0) pTmd->tbuf_stat |= lntmd1_STP; pTmd->tbuf_stat |= lntmd1_OWN; pDrvCtrl->freeRtn[pDrvCtrl->tmdIndex] = (FUNCPTR)netMblkClFree; pDrvCtrl->freeData[pDrvCtrl->tmdIndex].arg1 = pChunk; pDrvCtrl->freeData[pDrvCtrl->tmdIndex].arg2 = NULL; /* Advance our management index */ pDrvCtrl->tmdIndex = (pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1); } /* On the final tmd we set the END bit as well as OWN. */ pTmd->tbuf_stat |= lntmd1_OWN | lntmd1_ENP; /* If we only have one TMD for the packet then make sure of size. */ if (count == 1) { len = max (len, ETHERSMALL); pTmd->tbuf_bcnt = -len; } }#else pTmd = pDrvCtrl->pTring + pDrvCtrl->tmdIndex; LN_CACHE_INVALIDATE (pTmd, TMD_SIZ); if ((pTmd->tbuf_stat & lntmd1_OWN) || (((pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1)) == pDrvCtrl->tmdIndexC)) { if (!(pDrvCtrl->flags & LS_POLLING)) END_TX_SEM_GIVE (&pDrvCtrl->end); /* Are we still on the first chunk? */ DRV_LOG (DRV_DEBUG_TX, "Out of TMDs!\n", 1, 2, 3, 4, 5, 6); s = intLock(); pDrvCtrl->txBlocked = TRUE; intUnlock(s); return (END_ERR_BLOCK); } DRV_LOG (DRV_DEBUG_TX, "before cluster get %d %d\n", (int) pDrvCtrl->end.pNetPool, (int) pDrvCtrl->pClPoolId, 3, 4, 5, 6); pOrig = pBuf = netClusterGet(pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId); DRV_LOG (DRV_DEBUG_TX, "after cluster get\n", 1, 2, 3, 4, 5, 6); if (pBuf == NULL) { if (!(pDrvCtrl->flags & LS_POLLING)) END_TX_SEM_GIVE (&pDrvCtrl->end); netMblkClChainFree(pMblk); return (ERROR); } pBuf += pDrvCtrl->offset; len = netMblkToBufCopy (pMblk, pBuf, NULL); netMblkClChainFree(pMblk); LN_TMD_BUF_TO_ADDR(pTmd, pTemp, pBuf); len = max (len, ETHERSMALL); pTmd->tbuf_err = 0; /* clear buffer error status */ pTmd->tbuf_bcnt = -len; /* negative message byte count */ pTmd->tbuf_stat |= lntmd1_STP | lntmd1_OWN | lntmd1_ENP; pDrvCtrl->freeRtn[pDrvCtrl->tmdIndex] = (FUNCPTR)netClFree; pDrvCtrl->freeData[pDrvCtrl->tmdIndex].arg1 = pDrvCtrl->end.pNetPool; pDrvCtrl->freeData[pDrvCtrl->tmdIndex].arg2 = pOrig; /* Advance our management index */ pDrvCtrl->tmdIndex = (pDrvCtrl->tmdIndex + 1) & (pDrvCtrl->tringSize - 1);#endif /* Flush the write pipe */ CACHE_PIPE_FLUSH (); if (lnKickStartTx) { if (!(pDrvCtrl->flags & LS_POLLING)) ln7990CsrWrite (pDrvCtrl, 0, (lncsr_INEA | lncsr_TDMD)); else ln7990CsrWrite (pDrvCtrl, 0, lncsr_TDMD); } if (!(pDrvCtrl->flags & LS_POLLING)) END_TX_SEM_GIVE (&pDrvCtrl->end); /* Bump the statistic counter. */ END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1); return (OK); }/********************************************************************************* ln7990Ioctl - the driver I/O control routine** Process an ioctl request.*/LOCAL int ln7990Ioctl ( LN7990END_DEVICE *pDrvCtrl, int cmd, caddr_t data ) { 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; value--; /* HELP: WHY ??? */ END_FLAGS_CLR (&pDrvCtrl->end, value); } else { END_FLAGS_SET (&pDrvCtrl->end, value); } ln7990Config (pDrvCtrl); break; case EIOCGFLAGS: *(int *)data = END_FLAGS_GET(&pDrvCtrl->end); break; case EIOCPOLLSTART: error = ln7990PollStart (pDrvCtrl); break; case EIOCPOLLSTOP: error = ln7990PollStop (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 = LN_MIN_FBUF; break; case EIOCGMWIDTH: if (data == NULL) return (EINVAL); *(int *)data = pDrvCtrl->memWidth; break; case EIOCGHDRLEN: if (data == NULL) return (EINVAL); *(int *)data = 14; break; default: error = EINVAL; } return (error); }/********************************************************************************* ln7990Reset - hardware reset of chip (stop it)*/LOCAL void ln7990Reset ( LN7990END_DEVICE *pDrvCtrl ) { ln7990CsrWrite (pDrvCtrl, 0, lncsr_STOP); }/********************************************************************************* ln7990Csr0Read - read CSR 0 register** Assumes normal operation, where the RAP register has been left selecting* CSR0.*/LOCAL u_short ln7990Csr0Read ( LN7990END_DEVICE * pDrvCtrl /* driver control */ ) { USHORT result; SYS_IN_SHORT (pDrvCtrl, pDrvCtrl->pCsr, &result); return (result); /* get contents of CSR */ }/********************************************************************************* ln7990CsrWrite - select and write a CSR register**/LOCAL void ln7990CsrWrite ( LN7990END_DEVICE * pDrvCtrl, /* driver control */ int reg, /* register to select */ u_short value /* value to write */ ) { int level; level = intLock (); SYS_OUT_SHORT (pDrvCtrl, pDrvCtrl->pRap, (u_short)reg); SYS_OUT_SHORT (pDrvCtrl, pDrvCtrl->pCsr, value); intUnlock (level); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -