📄 if_cs.c
字号:
/* While there is still more to transmit */ while (pTxQueue->ifq_head != NULL) { /* Dequeue an mbuf chain from the transmit queue */ IF_DEQUEUE (pTxQueue, pMbufChain); /* Find the total length of the data to transmit */ length = 0; for (pMbuf=pMbufChain; pMbuf!=NULL; pMbuf=pMbuf->m_next) length += pMbuf->m_len; /* etherOutputHookRtn is not supported */ /* Request that the transmit be started after * all data has been copied */ if (pCs->inMemoryMode) { csPacketPageW (pCs, CS_PKTPG_TX_CMD, CS_TX_CMD_START_ALL); csPacketPageW (pCs, CS_PKTPG_TX_LENGTH, length); } else /* In IO mode */ { CS_OUT_WORD (pCs->ioAddr + CS_PORT_TX_CMD, CS_TX_CMD_START_ALL); CS_OUT_WORD (pCs->ioAddr + CS_PORT_TX_LENGTH, length); } /* Read the busStatus register which indicates success of the request */ busStatus = csPacketPageR (pCs, CS_PKTPG_BUS_ST); /* If there was an error in the transmit bid */ if (busStatus & CS_BUS_ST_TX_BID_ERR) { csError (pCs, "Transmit bid error (too big)"); /* Discard the bad mbuf chain */ m_freem (pMbufChain); pCs->arpCom.ac_if.if_oerrors++; /* Loop up to transmit the next chain */ } else if (busStatus & CS_BUS_ST_RDY4TXNOW) { /* The chip is ready for transmission now */ /* Copy the frame to the chip to start transmission */ csTxFrameCopy (pCs, pMbufChain); /* Free the mbuf chain */ m_freem (pMbufChain); /* Transmission is now in progress */ pCs->txInProgress = TRUE; break; /* Exit this routine */ } else csError (pCs, "Not ready for transmission now"); } /* Re-enable interrupt at the chip */ csPacketPageW (pCs, CS_PKTPG_BUS_CTL, csPacketPageR (pCs, CS_PKTPG_BUS_CTL) | CS_BUS_CTL_INT_ENBL); }/********************************************************************************* csTxFrameCopy - copies the packet from a mbuf chain to the chip** This routine copies the packet from a chain of mbufs to the chip. When all* the data has been copied, then the chip automatically begins transmitting* the data.** The reason why this "simple" copy routine is so long and complicated is* because all reads and writes to the chip must be done as 16-bit words.* If an mbuf has an odd number of bytes, then the last byte must be saved* and combined with the first byte of the next mbuf.** RETURNS: N/A*/LOCAL void csTxFrameCopy ( CS_SOFTC *pCs, struct mbuf *pMbufChain ) { struct mbuf *pMbuf; FAST USHORT *pFrame; FAST USHORT *pBuff; FAST USHORT *pBuffLimit; FAST int txDataPort; UCHAR *pStart; USHORT length; BOOL haveExtraByte; union { UCHAR byte[2]; USHORT word; } straddle; /* Initialize frame pointer and data port address */ pFrame = pCs->pPacketPage + (CS_PKTPG_TX_FRAME/2); txDataPort = pCs->ioAddr + CS_PORT_RXTX_DATA; haveExtraByte = FALSE; /* Start out with no extra byte */ /* Process the chain of mbufs */ for (pMbuf=pMbufChain; pMbuf!=NULL; pMbuf=pMbuf->m_next) { /* Setup starting pointer and length */ pStart = mtod (pMbuf, UCHAR *); length = pMbuf->m_len; /* If there is an extra byte left over from the previous mbuf */ if (haveExtraByte) { /* Add the first byte from this mbuf to make a word */ straddle.byte[1] = *pStart; /* Write the word which straddles the mbufs to the chip */ if (pCs->inMemoryMode) *pFrame++ = straddle.word; else { CS_OUT_WORD (txDataPort, straddle.word); } /* Adjust starting pointer and length */ pStart++; length--; } /* Point pBuff to the correct starting point */ pBuff = (USHORT *)pStart; /* If there are odd bytes remaining in the mbuf */ if (length & 1) { haveExtraByte = TRUE; /* Point pBuffLimit to the extra byte */ pBuffLimit = (USHORT *)(pStart+length-1); } else /* There is an even number of bytes remaining */ { haveExtraByte = FALSE; /* Point pBuffLimit to just beyond the last word */ pBuffLimit = (USHORT *)(pStart+length); } /* Copy the words in the mbuf to the chip */ if (pCs->inMemoryMode) while (pBuff < pBuffLimit) *pFrame++ = *pBuff++; else while (pBuff < pBuffLimit) { CS_OUT_WORD (txDataPort, *pBuff++); } /* If there is an extra byte left over in this mbuf * Save the extra byte for later */ if (haveExtraByte) straddle.byte[0] = *(UCHAR *)pBuff; } /* If there is an extra byte left over from the last mbuf */ if (haveExtraByte) { /* Add a zero byte to make a word */ straddle.byte[1] = 0; /* Write the last word to the chip */ if (pCs->inMemoryMode) *pFrame = straddle.word; else { CS_OUT_WORD (txDataPort, straddle.word); } } } /********************************************************************************* csIntr - Ethernet interface interrupt** This routine in the interrupt service routine. This routine is called by* assembly language wrapper code whenever the CS8900 chip generates and* interrupt. The wrapper code issues an EOI command intr. controller.** This routine processes the events on the Interrupt Status Queue. The events* are read one at a time from the ISQ and the appropriate event handlers are* called. The ISQ is read until it is empty. If the chip's interrupt request* line is active, then reading a zero from the ISQ will deactivate the* interrupt request line.** RETURNS: N/A*/LOCAL void csIntr ( int unit ) { FAST CS_SOFTC *pCs = &cs_softc[unit]; USHORT event; if (unit >= MAXUNITS) return; /* Ignore any interrupts that happen while the chip is being reset */ if (pCs->resetting) return; /* Read an event from the Interrupt Status Queue */ if (pCs->inMemoryMode) event = csPacketPageR (pCs, CS_PKTPG_ISQ); else { CS_IN_WORD (pCs->ioAddr + CS_PORT_ISQ, &event); } /* Process all the events in the Interrupt Status Queue */ while (event != 0) { /* Dispatch to an event handler based on the register number */ switch (event & CS_REG_NUM_MASK) { case CS_REG_NUM_RX_EVENT: csIntrRx (pCs, event); break; case CS_REG_NUM_TX_EVENT: csIntrTx (pCs, event); break; case CS_REG_NUM_BUF_EVENT: csIntrBuffer (pCs, event); break; default: csError (pCs, "Unknown interrupt event"); break; } /* Read another event from the Interrupt Status Queue */ if (pCs->inMemoryMode) event = csPacketPageR (pCs, CS_PKTPG_ISQ); else { CS_IN_WORD (pCs->ioAddr + CS_PORT_ISQ, &event); } } }/********************************************************************************* csIntrBuffer - interrupt handler for the receive miss event** The routine is called whenever an event occurs regarding the transmit and* receive buffers within the CS8900 chip. The only buffer event that could* happen with this network interface driver is the receive miss event. When* there are no receive buffers available within the chip and a packet arrives* from the LAN, then this interrupt is generated. This routine simply* increments the input error counter.** RETURNS: N/A*/LOCAL void csIntrBuffer ( CS_SOFTC *pCs, USHORT bufEvent ) { struct ifnet *pIf = &pCs->arpCom.ac_if; if (bufEvent & CS_BUF_EVENT_RX_MISS) { /* Increment the input error count */ pIf->if_ierrors++; csError (pCs, "Receive miss"); } if (bufEvent & CS_BUF_EVENT_SW_INT) { csError (pCs, "Software initiated interrupt"); } }/********************************************************************************* csIntrTx - interrupt handler for the transmission** This routine is called whenever the transmission of a packet has completed* successfully or unsuccessfully. If the transmission was not successful,* then the output error count is incremented. If collisions occured while* sending the packet, then the number of collisions is added to the collision* counter. If there are more packets on the transmit queue, then the next* packet is started at task time by calling csStartOutput() via netTask().** RETURNS: N/A*/LOCAL void csIntrTx ( CS_SOFTC *pCs, USHORT txEvent ) { struct ifnet *pIf = &pCs->arpCom.ac_if; /* If there were any errors transmitting this frame */ if (txEvent & (CS_TX_EVENT_LOSS_CRS | CS_TX_EVENT_SQE_ERR | CS_TX_EVENT_OUT_WIN | CS_TX_EVENT_JABBER | CS_TX_EVENT_16_COLL)) { /* Increment the output error count */ pIf->if_oerrors++; /* If debugging is enabled then log error messages */ if (pIf->if_flags & IFF_DEBUG) { if (txEvent & CS_TX_EVENT_LOSS_CRS) csError (pCs, "Loss of carrier"); if (txEvent & CS_TX_EVENT_SQE_ERR) csError (pCs, "SQE error"); if (txEvent & CS_TX_EVENT_OUT_WIN) csError (pCs, "Out-of-window collision"); if (txEvent & CS_TX_EVENT_JABBER) csError (pCs, "Jabber"); if (txEvent & CS_TX_EVENT_16_COLL) csError (pCs, "16 collisions"); } } /* Add the number of collisions for this frame */ if (txEvent & CS_TX_EVENT_16_COLL) pIf->if_collisions += 16; else pIf->if_collisions += ((txEvent & CS_TX_EVENT_COLL_MASK) >> 11); /* Transmission is no longer in progress */ pCs->txInProgress = FALSE; /* If there is more to transmit * Start the next transmission at task time */ if (pIf->if_snd.ifq_head != NULL) {#ifdef BSD43_DRIVER netJobAdd ((FUNCPTR)csStartOutput, pIf->if_unit, 0, 0, 0, 0);#else /* BSD43_DRIVER */ netJobAdd ((FUNCPTR)csStartOutput, (int)pCs, 0, 0, 0, 0);#endif /* BSD43_DRIVER */ } }/********************************************************************************* csIntrRx - interrupt handler for the reception** This routine is called whenever a packet is received at the chip. If the* packet is received with errors, then the input error count is incremented.* If the packet is received OK, then the data is copied to an internal receive* buffer and the csRxProcess() routine is called via netTask() to* process the received packet at task time.** RETURNS: N/A*/LOCAL void csIntrRx ( CS_SOFTC *pCs, USHORT rxEvent ) { struct ifnet *pIf = &pCs->arpCom.ac_if; CS_RXBUF *pRxBuff; /* If the frame was not received OK */ if (!(rxEvent & CS_RX_EVENT_RX_OK)) { /* Increment the input error count */ pIf->if_ierrors++; /* If debugging is enabled then log error messages */ if (pIf->if_flags & IFF_DEBUG) { /* If an error bit is set */ if (rxEvent != CS_REG_NUM_RX_EVENT) { if (rxEvent & CS_RX_EVENT_RUNT) csError (pCs, "Runt"); if (rxEvent & CS_RX_EVENT_X_DATA) csError (pCs, "Extra data"); if (rxEvent & CS_RX_EVENT_CRC_ERR) { if (rxEvent & CS_RX_EVENT_DRIBBLE) csError (pCs, "Alignment error"); else csError (pCs, "CRC Error"); } else if (rxEvent & CS_RX_EVENT_DRIBBLE) csError (pCs, "Dribble bits"); /* Must read the length of all received frames */ csPacketPageR (pCs, CS_PKTPG_RX_LENGTH); /* Skip the received frame */ csPacketPageW (pCs, CS_PKTPG_RX_CFG, csPacketPageR (pCs,CS_PKTPG_RX_CFG) | CS_RX_CFG_SKIP); } else csError (pCs, "Implied skip"); } return; } /* Get a receive frame buffer */ pRxBuff = csRxBuffAlloc (pCs); if (pRxBuff == NULL) /* If no buffer available */ { /* Increment the input error count */ pIf->if_ierrors++; csError (pCs, "No receive buffer available"); /* Must read the length of all received frames */ csPacketPageR (pCs, CS_PKTPG_RX_LENGTH); /* Skip the received frame */ csPacketPageW (pCs, CS_PKTPG_RX_CFG, csPacketPageR (pCs, CS_PKTPG_RX_CFG) | CS_RX_CFG_SKIP); return; } /* Copy the received frame from the chip to the buffer */ csRxFrameCopy (pCs, pRxBuff); /* Process the received frame at task time */ netJobAdd ((FUNCPTR)csRxProcess, (int)pCs, (int)pRxBuff, 0, 0, 0); }/********************************************************************************* csRxFrameCopy - copies a received frame from the chip to a receive buffer** This routine copies a received frame from the chip to a receive buffer.** RETURNS: N/A*/LOCAL void csRxFrameCopy ( CS_SOFTC *pCs,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -