📄 if_seeq.c
字号:
pDrvCtrl->rxNext = nextFrame; SEEQ_WRITE (pDev->pRxend, (nextFrame >> 8)); } while (headerStatus & SEEQ_RX_HSTAT_CHAIN); }/******************************************************************************** seeqTransmit - handle transmitted packets.** NOMANUAL*/LOCAL void seeqTransmit ( int unit ) { int pktCount; DRV_CTRL *pDrvCtrl = &drvCtrl[unit]; SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs; BOOL resetTx = FALSE;#ifdef DEBUG if (seeqDebug) logMsg ("TX Cnt %d Curr 0x%04x Next 0x%04x Space 0x%04x\n", pDrvCtrl->txCount, pDrvCtrl->txCurr, pDrvCtrl->txNext, TX_SPACE(pDrvCtrl), 0, 0);#endif /* If interface was shutdown, abort service request */ if (!(pDrvCtrl->idr.ac_if.if_flags & IFF_UP)) { pDrvCtrl->flags &= ~SEEQ_TX_OUTSTANDING; return; } if (!(pDrvCtrl->flags & SEEQ_TX_OUTSTANDING)) {#ifdef DEBUG if (seeqDebug) logMsg ("seeq: no TX request outstanding\n", 0, 0, 0, 0, 0, 0);#endif return; } pDrvCtrl->flags &= ~SEEQ_TX_OUTSTANDING; pktCount = pDrvCtrl->txCount; if (!pDrvCtrl->txCount) {#ifdef DEBUG if (seeqDebug) logMsg ("seeq: no xmit curr 0x%04x next 0x%04x space 0x%04x\n", pDrvCtrl->txCurr, pDrvCtrl->txNext, TX_SPACE(pDrvCtrl), 0, 0, 0);#endif return; } /* Now process the packets */ while (1) { USHORT tmp; USHORT nextFrame; USHORT frameCommand; USHORT frameStatus; if (seeqSetDMARead(pDrvCtrl, pDrvCtrl->txCurr) != OK) { /* re-queue for later processing. */#ifdef DEBUG if (seeqDebug) logMsg ("TX: Set DMA failed\n", 0, 0, 0, 0, 0, 0);#endif seeqTxReset (pDrvCtrl->unit); pDrvCtrl->flags |= SEEQ_TX_OUTSTANDING; netJobAdd ((FUNCPTR) seeqTransmit, unit, 0, 0, 0, 0); break; } /* Move curr to the end of the last transmitted packet */ nextFrame = SEEQ_READ (pDev->pBwind); /* get the frame status and command */ tmp = SEEQ_READ (pDev->pBwind); frameCommand = tmp >> 8; frameStatus = tmp & 0x00ff;#ifdef DEBUG if (seeqDebug) logMsg ("TX @ 0x%04x command %02x status 0x%02x next 0x%04x\n", pDrvCtrl->txCurr, frameCommand, frameStatus, nextFrame, 0, 0);#endif /* * At this point, we should be at a valid TX header since * txCount > 0. */ if (nextFrame > pDrvCtrl->txEnd) {#ifdef DEBUG if (seeqDebug) logMsg ("TX: bad next pointer\n", 0, 0, 0, 0, 0, 0);#endif resetTx = TRUE; } if (!(frameCommand & SEEQ_TX_CMD_XMIT)) {#ifdef DEBUG if (seeqDebug) logMsg ("TX: not an xmit header\n", 0, 0, 0, 0, 0, 0);#endif resetTx = TRUE; } if (!(frameCommand & SEEQ_TX_CMD_CHAIN)) {#ifdef DEBUG if (seeqDebug) logMsg ("TX: ran off end\n", 0, 0, 0, 0, 0, 0);#endif resetTx = TRUE; } if (!(frameCommand & SEEQ_TX_CMD_DATA)) {#ifdef DEBUG if (seeqDebug) logMsg ("TX: no data in packet\n", 0, 0, 0, 0, 0, 0);#endif resetTx = TRUE; } if (resetTx) {#ifdef DEBUG if (seeqDebug) logMsg ("TX: reset cnt %d curr 0x%04x cmd %02x stat 0x%02x next 0x%04x\n", pDrvCtrl->txCount, pDrvCtrl->txCurr, frameCommand, frameStatus, nextFrame, 0);#endif seeqTxReset (pDrvCtrl->unit); break; } /* If not done, stop processing. */ if (!(frameStatus & SEEQ_TX_PSTAT_DONE)) break; /* Check for error status. */ if (frameStatus & SEEQ_TX_PSTAT_BABBLE) ++pDrvCtrl->idr.ac_if.if_oerrors; if (frameStatus & SEEQ_TX_PSTAT_COLL16) pDrvCtrl->idr.ac_if.if_collisions += 16; else if (frameStatus & SEEQ_TX_PSTAT_COLL) ++pDrvCtrl->idr.ac_if.if_collisions; /* Move past this packet. */ pDrvCtrl->txCurr = nextFrame; /* Exit if all packets accounted for. */ if (!--pDrvCtrl->txCount) break; } /* If packets where waiting on the queue for free space, re-start */ if (((pktCount != pDrvCtrl->txCount) || resetTx) && (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL)) (void)netJobAdd ((FUNCPTR) seeqStart, unit, 0, 0, 0, 0); }/******************************************************************************** seeqInt - handle controller interrupt** This routine is called at interrupt level in response to an interrupt from* the controller. All of the real work is handled at task level through* netJobAdd.** NOMANUAL*/void seeqInt ( int unit ) { USHORT status; DRV_CTRL *pDrvCtrl = &drvCtrl[unit]; SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs; ++seeqIntCnt; status = SEEQ_READ (pDev->pStat); SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK) | SEEQ_CMD_ALL_ACK)); if (pDrvCtrl->idr.ac_if.if_flags & IFF_UP) { /* Make sure only one TX and RX request is outstanding at a time. */ if ((status & SEEQ_STAT_RX_INT) && !(pDrvCtrl->flags & SEEQ_RX_OUTSTANDING)) { pDrvCtrl->flags |= SEEQ_RX_OUTSTANDING; netJobAdd ((FUNCPTR) seeqReceive, unit, 0, 0, 0, 0); } if ((status & SEEQ_STAT_TX_INT) && !(pDrvCtrl->flags & SEEQ_TX_OUTSTANDING)) { pDrvCtrl->flags |= SEEQ_TX_OUTSTANDING; netJobAdd ((FUNCPTR) seeqTransmit, unit, 0, 0, 0, 0); } } }/******************************************************************************** seeqOutput - the driver output routine** NOMANUAL*/LOCAL int seeqOutput ( IDR *pIDR, MBUF *pMbuf, SOCK *pDest ) { return ether_output ((IFNET*)pIDR, pMbuf, pDest, (FUNCPTR) seeqStart, pIDR); }/******************************************************************************** seeqStart - start outputing a packet.** Get another datagram to send off of the interface queue,* and map it to the interface before starting the output.* This routine is called by seeqOutput().** NOMANUAL*/LOCAL void seeqStart ( int unit ) { DRV_CTRL *pDrvCtrl = &drvCtrl[unit]; SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs; int space; int s; s = splnet (); space = TX_SPACE(pDrvCtrl); if (space < (ETHERMTU + 8)) {#ifdef DEBUG if (seeqDebug) logMsg ("TX: low space %4d: flags %d curr 0x%04x next 0x%04x\n", space, pDrvCtrl->flags, pDrvCtrl->txCurr, pDrvCtrl->txNext, 0, 0);#endif /* May have dropped a TX interrupt */ if (pDrvCtrl->txLow++ > 2) { pDrvCtrl->txLow = 0; seeqTxReset (pDrvCtrl->unit); } else if (!(pDrvCtrl->flags & SEEQ_TX_OUTSTANDING)) { pDrvCtrl->flags |= SEEQ_TX_OUTSTANDING; netJobAdd ((FUNCPTR) seeqTransmit, unit, 0, 0, 0, 0); } } /* Only start if we have at least enough room */ if ((space >= ETHERMTU + 8) && pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL) { MBUF *pMbuf; int len; UCHAR *buf; USHORT txNext; BOOL error = FALSE; pDrvCtrl->txLow = 0; IF_DEQUEUE(&pDrvCtrl->idr.ac_if.if_snd, pMbuf); /* copy packet to write buffer */ copy_from_mbufs (pDrvCtrl->txBuf, pMbuf, len); buf = (UCHAR *) pDrvCtrl->txBuf; /* After this point, if there's a problem with the chip, the packet is lost. */ /* Adjust length to ensure minimum packet size */ len = max (ETHERSMALL, len); ++pDrvCtrl->txCount;#ifdef DEBUG if (seeqDebug > 1) { int i; char *ptr; static char lbuf[4096]; sprintf(lbuf, "TX %4d:", len); ptr = lbuf + strlen(lbuf); for (i = 0; i < len; ++i, ptr += 3) sprintf(ptr , " %02x", buf[i]); logMsg ("%s\n", (int) lbuf, 0, 0, 0, 0, 0); }#endif /* Compute where the next packet will go */ txNext = pDrvCtrl->txNext + len + 4; if (txNext > pDrvCtrl->txEnd) txNext -= (pDrvCtrl->txEnd + 1);#ifdef DEBUG if (seeqDebug) logMsg ("TX pkt: @ %04x len %4d space %5d next %04x\n", pDrvCtrl->txNext, len, TX_SPACE(pDrvCtrl), txNext, 0, 0);#endif /* place a transmit request (while TX possibly running) */ /* Setup for writing */ if (seeqSetDMAWrite(pDrvCtrl, pDrvCtrl->txNext) != OK) error = TRUE; if (error == FALSE) { /* Write a dummy header, so TX will stop if it catches up. */ SEEQ_WRITE (pDev->pBwind, 0); SEEQ_WRITE (pDev->pBwind, 0); /* Write out the packet, two bytes at a time */ for ( ; len >= 2; len -= 2, buf += 2) { SEEQ_WRITE (pDev->pBwind, *(USHORT *)buf); } if (len) { SEEQ_WRITE_BYTE (pDev->pBwind, *buf); } /* Write dummy end header to stop chain */ SEEQ_WRITE (pDev->pBwind, 0); SEEQ_WRITE (pDev->pBwind, 0); /* Flush FIFO and move back and write the real header */ if (seeqSetDMAWrite (pDrvCtrl, pDrvCtrl->txNext) != OK) error = TRUE; } if (error == FALSE) { /* TX packet header: next pointer (2 bytes) */ SEEQ_WRITE (pDev->pBwind, txNext); /* TX packet header: cmd and status bytes */ SEEQ_WRITE (pDev->pBwind, ((SEEQ_TX_CMD_SUCC_EN | SEEQ_TX_CMD_DATA | SEEQ_TX_CMD_CHAIN | SEEQ_TX_CMD_XMIT) << SEEQ_MSB_SHIFT)); /* Flush FIFO */ if (seeqFlushFIFO (pDrvCtrl) != OK) error = TRUE; } if (error == FALSE) { /* If TX has stopped, reload xmit pointer. */ if (!(SEEQ_READ(pDev->pStat) & SEEQ_STAT_TX_ON)) { SEEQ_WRITE (pDev->pTxptr, pDrvCtrl->txNext); } /* Adjust pointer to next buffer */ pDrvCtrl->txNext = txNext; /* Turn on Tx and ack the buffer interrupt */ SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK) | SEEQ_CMD_TX_ON | SEEQ_CMD_BUF_ACK)); } if (error == TRUE) seeqTxReset (pDrvCtrl->unit); } splx (s); }/******************************************************************************** seeqIoctl - the driver I/O control routine** Process an ioctl request.** NOMANUAL*/LOCAL int seeqIoctl ( IDR *ifp, int cmd, caddr_t data ) { int error = OK; switch (cmd) { case (int)SIOCSIFADDR: ifp->ac_ipaddr = IA_SIN (data)->sin_addr; break; case (int)SIOCSIFFLAGS: /* No further work to be done */ break; default: error = EINVAL; } return (error); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -