📄 mb86960end.c
字号:
{ DRV_LOG(DRV_DEBUG_LOAD, "system memory unavailable\n", 1, 2, 3, 4, 5, 6); return (ERROR); } /* Initialize the memory pool. */ if (netPoolInit(pDrvCtrl->end.pNetPool, &fnMclBlkCfg, &fnClDescTbl[0], fnClDescTblNumEnt, NULL) == ERROR) { DRV_LOG (DRV_DEBUG_LOAD, "Could not init buffering\n", 1, 2, 3, 4, 5, 6); return (ERROR); }#ifdef DRV_DEBUG mb86960NetPool = *pDrvCtrl->end.pNetPool;#endif /* Store the cluster pool id as others need it later. */ pDrvCtrl->pClPoolId = clPoolIdGet (pDrvCtrl->end.pNetPool, sizeof(struct rx_frame), FALSE); DRV_LOG (DRV_DEBUG_LOAD, "Memory setup complete\n", 1, 2, 3, 4, 5, 6); return OK; }/********************************************************************************* mb86960Start - start the device** This function calls BSP functions to connect interrupts and start the* device running in interrupt mode.** RETURNS: OK or ERROR if ISR is not connected.**/LOCAL STATUS mb86960Start ( MB86960_END_CTRL * pDrvCtrl /* device to be started */ ) { STATUS result; SYS_INT_CONNECT (pDrvCtrl, mb86960Int, (int)pDrvCtrl, &result); if (result == ERROR) return ERROR; DRV_LOG (DRV_DEBUG_LOAD, "Interrupt connected.\n", 1, 2, 3, 4, 5, 6); /* Enable specific interrupts. */ SYS_OUT_SHORT ((pDrvCtrl->devBaseAddr + NICE_INTRMASK), NORM_INTRMASK); /* mark the interface -- up */ END_FLAGS_SET (&pDrvCtrl->end, (IFF_UP | IFF_RUNNING)); SYS_INT_ENABLE (pDrvCtrl); DRV_LOG (DRV_DEBUG_LOAD, "interrupt enabled.\n", 1, 2, 3, 4, 5, 6); return (OK); }/********************************************************************************* mb86960Int - handle controller interrupt** This routine is called at interrupt level in response to an interrupt from* the controller.** RETURNS: N/A.*/LOCAL void mb86960Int ( MB86960_END_CTRL * pDrvCtrl /* interrupting device */ ) { char * pDev; /* ptr to the device regs */ u_short event; u_short reg; pDev = pDrvCtrl->devBaseAddr; SYS_IN_SHORT((pDev + NICE_STATUS), event); SYS_IN_SHORT((pDev + NICE_INTRMASK), reg); DRV_LOG (DRV_DEBUG_INT, "i=0x%x:\n", event, 2, 3, 4, 5, 6); /* Handle receiver overflow event. */ if (event & DLCR1_OVR_FLO) { overFlowCnt++; /* bump the counter */ SYS_OUT_SHORT ((pDev + NICE_STATUS), DLCR1_OVR_FLO); return; } /* Handle the receiver event, only if it was enabled. */ if ((reg & DLCR3_RX_PKT) && (event & DLCR1_RX_PKT)) { SYS_OUT_SHORT ((pDev + NICE_INTRMASK), NO_RX_INTRMASK); /* disable */ netJobAdd ((FUNCPTR)mb86960HandleRcvInt, (int)pDrvCtrl, 0,0,0,0); } /* ACK the interrupts */ SYS_OUT_SHORT ((pDev + NICE_STATUS), event); }/********************************************************************************* mb86960HandleRcvInt - 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.** RETURNS: N/A.*/LOCAL void mb86960HandleRcvInt ( MB86960_END_CTRL * pDrvCtrl /* interrupting device */ ) { char * pDev = pDrvCtrl->devBaseAddr; MB86960_RX_FRAME * pCluster; MB86960_RX_FRAME temp; STATUS retCode; pDrvCtrl->flags |= LS_RCV_HANDLING_FLAG; while (mb86960RxMore (pDrvCtrl)) { /* * 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. */ pCluster = (MB86960_RX_FRAME *) netClusterGet(pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId); if (pCluster == NULL) { dropCnt++; DRV_LOG (DRV_DEBUG_RX, "Cannot loan!\n", 1, 2, 3, 4, 5, 6); mb86960PacketGet (pDrvCtrl, &temp); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); } else { retCode = mb86960PacketGet (pDrvCtrl, pCluster); if (retCode != ERROR) { (void) mb86960Recv (pDrvCtrl, pCluster); } else { END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); break; } } } pDrvCtrl->flags &= ~LS_RCV_HANDLING_FLAG; /* Turn the receive interrupts on again. */ SYS_OUT_SHORT ((pDev + NICE_INTRMASK), NORM_INTRMASK); }/********************************************************************************* mb86960RxMore - indicates more packets in the buffer** This routine indicates that there are more packets left in the buffer** RETURNS: TRUE or FALSE*/LOCAL BOOL mb86960RxMore ( MB86960_END_CTRL * pDrvCtrl /* interrupting device */ ) { u_short mode; char * pDev; /* ptr to the device regs */ pDev = pDrvCtrl->devBaseAddr; /* get ptr to device */ SYS_IN_SHORT ((pDev + NICE_MODE), mode); if (mode & DLCR5_BUF_EMPTY) return (FALSE); else return (TRUE); } /********************************************************************************* mb86960PacketGet - get next received message** Get next received message. Returns NULL if none are ready.** RETURNS: OK or ERROR.*/LOCAL STATUS mb86960PacketGet ( MB86960_END_CTRL * pDrvCtrl, /* device structure */ MB86960_RX_FRAME * pRxFrame /* pointer to an rx frame struct */ ) { int loopy; /* loop counter */ char * pDev; /* ptr to the device regs */ u_short * pDest; /* ptr to destination */ pDev = pDrvCtrl->devBaseAddr; /* get ptr to device */ /* Fill our local copy of the Rx header from the device's buffer. */ SYS_IN_SHORT((pDev + NICE_PORT), pRxFrame->rxHdr.status); SYS_IN_SHORT((pDev + NICE_PORT), pRxFrame->rxHdr.len); /* swap bytes if needed */ pRxFrame->rxHdr.len = MB86960_SWAP_SHORT(pRxFrame->rxHdr.len); /* Clear the status bit for packet ready. */ SYS_OUT_SHORT ((pDev + NICE_STATUS), DLCR1_RX_PKT); /* Sanity check the packet info. */ if ((!(pRxFrame->rxHdr.status & RX_HDR_STAT_GOOD)) || (pRxFrame->rxHdr.len < ETHERSMALL) || (pRxFrame->rxHdr.len > (ETHERMTU + SIZEOF_ETHERHEADER))) { /* END_FLAGS_CLR (&pDrvCtrl->end, (IFF_UP | IFF_RUNNING)); */ return (ERROR); } /* Fill our frame buffer from the device's buffer. */ pDest = (u_short *) &pRxFrame->enetHdr; /* stuff ptr */ for (loopy = pRxFrame->rxHdr.len; loopy > 0; loopy -= sizeof (u_short)) { SYS_IN_SHORT((pDev + NICE_PORT), *pDest++); } return (OK); }/********************************************************************************* mb86960Recv - process the next incoming packet** Handle one incoming packet. The packet is checked for errors.** RETURNS: OK */LOCAL STATUS mb86960Recv ( MB86960_END_CTRL * pDrvCtrl, /* device structure */ MB86960_RX_FRAME * pCluster /* pointer to header structure */ ) { int len; M_BLK_ID pMblk; CL_BLK_ID pClBlk; len = pCluster->rxHdr.len; /* obtain data length */ /* Grab a cluster block to marry to the cluster we received. */ if ((pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT)) == NULL) { netClFree (pDrvCtrl->end.pNetPool, (char *) pCluster); 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, (char *) pCluster); 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; } /* Add one to our unicast data. */ END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1); /* Join the cluster to the MBlock */ netClBlkJoin (pClBlk, (char *) pCluster, len, NULL, 0, 0, 0); netMblkClJoin (pMblk, pClBlk); pMblk->mBlkHdr.mData = (char *) MB86960_FRAME_DATA_ADDR_GET(pCluster); 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); /* Call the upper layer's receive routine. */ END_RCV_RTN_CALL(&pDrvCtrl->end, pMblk);cleanRXD: return (OK); }/********************************************************************************* mb86960Send - 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 mb86960Send ( MB86960_END_CTRL * pDrvCtrl, /* device ptr */ M_BLK_ID pMblk /* data to send */ ) { int oldLevel; STATUS status; DRV_LOG(DRV_DEBUG_TX, "Begin mb86960Send pDrvCtrl %p pMblk %p\n", (int ) pDrvCtrl, (int ) pMblk, 0, 0, 0, 0); if ((END_FLAGS_GET(&pDrvCtrl->end) & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) { DRV_LOG(DRV_DEBUG_TX, "Device is NOT UP and RUNNING\n", 0, 0, 0, 0, 0, 0); return (ERROR); } /* * Obtain exclusive access to transmitter. This is necessary because * we might have more than one stack transmitting at once. */ if (!(pDrvCtrl->flags & LS_POLLING)) semTake (pDrvCtrl->txSem, WAIT_FOREVER); /* place a transmit request */ if (!(pDrvCtrl->flags & LS_POLLING)) oldLevel = intLock (); /* now mb86960Int won't get confused */ /* send packet out over interface */ if ((status = mb89680Transmit (pDrvCtrl, pMblk)) == ERROR) { DRV_LOG(DRV_DEBUG_TX, "FAILED mb89680Transmit\n", 1, 2, 3, 4, 5, 6); /* update statistics */ END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_ERRS, +1); if (!(pDrvCtrl->flags & LS_POLLING)) { intUnlock (oldLevel); /* now mb86960Int won't get confused */ semGive (pDrvCtrl->txSem); } netMblkClChainFree (pMblk); return (ERROR); } if (!(pDrvCtrl->flags & LS_POLLING)) intUnlock (oldLevel); /* now mb86960Int won't get confused */ /* Advance our management index */ if (!(pDrvCtrl->flags & LS_POLLING)) semGive (pDrvCtrl->txSem); /* 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); return (OK); }/********************************************************************************* mb89680Transmit - kick start the transmitter after generic ether_output** This routine is responsible for tranmitting packets over physical media.* The data to be sent out is held in a chain of mbufs. The data in each mbuf * fragment must be copied to the device's packet buffer.** RETURNS: OK, or ERROR*/LOCAL STATUS mb89680Transmit ( MB86960_END_CTRL * pDrvCtrl, /* pointer to driver control struct */ M_BLK_ID pMblk /* pointer to am Mblk */ ) { int pktLen; /* total length of packet */ int dataLen; /* real length of data portion */ int loopy; /* loop counter */ char * nicePort; /* ptr to the nice buffer port */ u_short * pSource; /* ptr to source of data byte */ u_short temp; static char privateBuf [ETHERMTU]; /* get ptr to the buffer port */ nicePort = pDrvCtrl->devBaseAddr + NICE_PORT; /* * This driver maintains transmit resources internally. The * CPU cannot retrieve or examine them. */ dataLen = netMblkToBufCopy (pMblk, privateBuf, NULL); /* Ensure we send a legal size frame. */ pktLen = max (ETHERSMALL, dataLen); /* taking care of short packets, pad with 0s */ if (dataLen < ETHERSMALL) for (loopy = dataLen; loopy < pktLen; loopy++) privateBuf [loopy] = 0; /* Tell the device the length; in little endian order */ SYS_OUT_SHORT (nicePort, MB86960_SWAP_SHORT(pktLen)); pSource = (u_short *)privateBuf; for (loopy = pktLen; loopy > 0 ; loopy -= sizeof (u_short)) { SYS_OUT_SHORT (nicePort, *pSource); pSource++; } if (pktLen % sizeof (u_short)) /* packet size is odd */ { unsigned short lastByte; lastByte = 0; ( (char *) (&lastByte))[0] = ((char *) (pSource))[0]; SYS_OUT_SHORT (nicePort, lastByte); } /* See if transmitter is free and start it orelse wait. */ FOREVER { SYS_IN_SHORT((pDrvCtrl->devBaseAddr + NICE_TRANSMIT), temp); if ((temp & (0x7f << 8)) == 0) break; } SYS_OUT_SHORT((pDrvCtrl->devBaseAddr + NICE_TRANSMIT), KICK_TRANSMIT); return (OK); }/********************************************************************************* mb86960Ioctl - the driver I/O control routine** Process an ioctl request.** RETURNS: A command specific response, usually OK or ERROR.*/LOCAL int mb86960Ioctl ( MB86960_END_CTRL * pDrvCtrl, /* device receiving command */ int cmd, /* ioctl command code */ caddr_t data /* command argument */ ) { 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); END_FLAGS_CLR (&pDrvCtrl->end, value); } else { END_FLAGS_SET (&pDrvCtrl->end, value); } mb86960Config (pDrvCtrl); break; case EIOCGFLAGS: *(int *)data = END_FLAGS_GET(&pDrvCtrl->end); break; case EIOCPOLLSTART:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -