📄 if_elt.c
字号:
** eltBoardInit - prepare the board for operation**/static void eltBoardInit ( int unit ) { ELT_CTRL * pDrvCtrl; int port; int index; UINT16 transceiver; pDrvCtrl = pEltCtrl [unit]; port = pDrvCtrl->port; eltIntDisable (pDrvCtrl); /* make it OK to change register window */ sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_ADDRESS); for (index = 0; index < EA_SIZE; index++) sysOutByte (port + index, pDrvCtrl->idr.ac_enaddr [index]); /* Select the transceiver hardware (attachment) then do whatever is * necessary to activate the selected attachment. * A truly complete implementation would probably check to see * if the selected attachment were present. */ sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_CONFIG); transceiver = sysInWord (port + ADDRESS_CONFIG); if (pDrvCtrl->attachment == ATTACHMENT_DEFAULT) { switch (transceiver & AC_XCVR_MASK) { case AC_XCVR_TPE: pDrvCtrl->attachment = ATTACHMENT_RJ45; break; case AC_XCVR_BNC: pDrvCtrl->attachment = ATTACHMENT_BNC; break; case AC_XCVR_AUI: pDrvCtrl->attachment = ATTACHMENT_AUI; break; default: /* there's only one other value; it's "reserved" */ pDrvCtrl->attachment = ATTACHMENT_AUI; /* good enough */ break; } } /* Now set the selected attachment type, even if it was already selected */ transceiver &= ~AC_XCVR_MASK; switch (pDrvCtrl->attachment) { case ATTACHMENT_RJ45: sysOutWord (port + ADDRESS_CONFIG, transceiver | AC_XCVR_TPE); sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_DIAGNOSTIC); sysOutByte (port + MEDIA_STATUS, sysInByte (port + MEDIA_STATUS) | MT_S_JABBER_ENABLE | MT_S_LINK_BEAT_ENABLE); break; case ATTACHMENT_BNC: sysOutWord (port + ADDRESS_CONFIG, transceiver | AC_XCVR_BNC); sysOutWord (port + ELT_COMMAND, START_COAX); break; case ATTACHMENT_AUI: default: sysOutWord (port + ADDRESS_CONFIG, transceiver | AC_XCVR_AUI); break; } /* enable normal Ethernet address recognition */ pDrvCtrl->rxFilter = RX_F_NORMAL; /* * Define the set of status bits that could cause interrupts. * There is no interrupt cause indicator separate from the board status. * To keep the ISR from seeing status conditions we didn't want to be * interrrupted for, we must mask the STATUS off, not the interrupt. * This prevents the condition from interrupting and also prevents * the ISR from seeing the condition even if it is true. * The interrupt mask is set only once to the set of all conditions * we might want to be interrupted by; the status mask is set and * cleared according to which conditions we want at any particular * time. The intMask field in the control structure * is named for its effect; it is really used in the status mask * command (3Com calls it the read zero mask). */ /* enable the status bits we currently want to cause interrupts */ eltIntMaskSet (pDrvCtrl, ADAPTER_FAILURE | TX_COMPLETE | RX_COMPLETE | RX_EARLY | UPDATE_STATS); /* enable the collection of statistics */ sysOutWord (port + ELT_COMMAND, STATS_ENABLE); /* enable the hardware to generate interrupt requests */ sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_CONFIG); sysOutWord (port + CONFIG_CONTROL, CC_ENABLE); sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_OPERATING); eltIntEnable (pDrvCtrl); eltRxStart (pDrvCtrl); eltTxStart (pDrvCtrl); }/********************************************************************************* eltMemoryInit - initialize memory structures** The only thing we allocate from system meory besides the driver control* structure is the frame buffer pool. Here we malloc it as one big region* and divide it up into receive and transmit buffers.*/static STATUS eltMemoryInit ( int unit ) { ELT_CTRL * pDrvCtrl; ELT_FRAME * pFrame; int index; pDrvCtrl = pEltCtrl [unit]; /* Initialize our data structures */ pDrvCtrl->pFrameArea = malloc ( (1 + pDrvCtrl->nRxFrames) * sizeof (ELT_FRAME)); if (pDrvCtrl->pFrameArea == NULL) return (ERROR); pFrame = pDrvCtrl->pFrameArea; pDrvCtrl->pTxFrame = pFrame++; /* first allocate tx frame */ pDrvCtrl->pRxHead = pFrame; /* first rx frame */ for (index = pDrvCtrl->nRxFrames; index > 0; index--) { pFrame->count = 0; pFrame->nextByte = pFrame->header; pFrame->length = 0; pFrame->lNext = pFrame + 1; pFrame++; } pDrvCtrl->pRxTail = pFrame - 1; /* last rx frame */ pDrvCtrl->pRxTail->lNext = NULL; pDrvCtrl->pRxCurrent = pDrvCtrl->pRxHead; pDrvCtrl->nLoanFrames = pDrvCtrl->nRxFrames - MIN_NUM_RX_FRAMES; return (OK); }/********************************************************************************* eltReset - reset the elt interface** Mark interface as inactive and reset the adapter.*/static void eltReset ( int unit ) { ELT_CTRL * pDrvCtrl; pDrvCtrl = pEltCtrl [unit]; eltIntDisable (pDrvCtrl); /* prevent device from interrupting */ sysOutWord (pDrvCtrl->port + ELT_COMMAND, RX_RESET); sysOutWord (pDrvCtrl->port + ELT_COMMAND, TX_RESET); }/********************************************************************************* eltIoctl - interface ioctl procedure** Process an interface ioctl request.*/static int eltIoctl ( IDR *pIDR, int cmd, caddr_t data ) { int unit; ELT_CTRL * pDrvCtrl; int error;#ifdef ELT_DEBUG printf ("elt: ioctl: pIDR=%x cmd=%x data=%x\n", pIDR, cmd, data);#endif /* ELT_DEBUG */ unit = pIDR->ac_if.if_unit; pDrvCtrl = pEltCtrl [unit]; error = 0; switch (cmd) { case SIOCSIFADDR: ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr; arpwhohas (pIDR, &IA_SIN (data)->sin_addr); break; case SIOCSIFFLAGS: /* Set promiscuous mode according to current interface flags */ pDrvCtrl->rxFilter = ( (pIDR->ac_if.if_flags & IFF_PROMISC) != 0) ? RX_F_PROMISCUOUS : RX_F_NORMAL; sysOutWord (pDrvCtrl->port + ELT_COMMAND, SET_RX_FILTER | pDrvCtrl->rxFilter); break; default: error = EINVAL; } return (error); }#ifdef BSD43_DRIVER/********************************************************************************* eltOutput - interface output routine.** This is the entry point for packets arriving from protocols above. This* routine merely calls our specific output routines that eventually lead* to a transmit to the network.** RETURNS: 0 or appropriate errno*/static int eltOutput ( IDR * pIDR, MBUF * pMbuf, SOCK * pDestAddr ) {#ifdef ELT_DEBUG printf ("elt: output: pIDR=%x pMbuf=%x pDestAddr=%x\n", pIDR, pMbuf, pDestAddr);#endif /* ELT_DEBUG */ return (ether_output ( (IFNET *)pIDR, pMbuf, pDestAddr, (FUNCPTR) eltTxOutputStart, pIDR)); }#endif/********************************************************************************* eltTxOutputStart - start output on the board** This routine is called from ether_output() when a new packet is enqueued* in the interface mbuf queue.** Note that this function is ALWAYS called between an splnet() and an splx().* This is true because netTask(), and ether_output() take care of* this when calling this function. Therefore, no calls to these spl functions* are needed anywhere in this output thread.*/#ifdef BSD43_DRIVERstatic void eltTxOutputStart ( int unit ) { ELT_CTRL * pDrvCtrl; pDrvCtrl = pEltCtrl [unit];#elsestatic void eltTxOutputStart ( ELT_CTRL * pDrvCtrl ) {#endif if (sysInWord (pDrvCtrl->port + TX_FREE_BYTES) >= TX_IDLE_COUNT) {#ifdef ELT_TIMING /* pretend we queued eltTxFlush, to keep the counts straight */ if ( (int)++pDrvCtrl->eltStat.taskQTxOuts > (int)pDrvCtrl->eltStat.maxTxTaskQ) pDrvCtrl->eltStat.maxTxTaskQ = pDrvCtrl->eltStat.taskQTxOuts;#endif /* ELT_TIMING */ eltTxFlush (pDrvCtrl, FALSE); /* not called via netJobAdd() */ } }/********************************************************************************* eltInt - entry point for handling interrupts from the EtherLink III** Most of the board's interrupting conditions must be actually handled to* clear the interrupting condition; the ACK command does nothing for them.* Where we defer handling to the task level, we mask the status conditions* to prevent a repeated interrupt. This works everywhere except when there* are received packets waiting to be delivered to the protocols; this is* synchronized by a flag.** Note that the board manual says to acknowledge the board interrupts before* acknowledging the processor interrupt, presumably because of level-sensitive* logic somewhere.*/static void eltInt ( ELT_CTRL * pDrvCtrl ) { UINT16 status; UINT16 statusDiag; UINT16 statusRx; UINT16 statusRxNew; UINT8 statusTx; UINT16 length; int ix = 0; int port = pDrvCtrl->port; BOOL needTxStart = FALSE; volatile ELT_FRAME * pFrame; STATUS result;#ifdef ELT_TIMING { int time = (int) sysInByte (pDrvCtrl->port + TIMER); if (time> pDrvCtrl->eltStat.maxIntLatency) pDrvCtrl->eltStat.maxIntLatency = time; if (pDrvCtrl->interruptTime == -1) pDrvCtrl->interruptTime = time; else if (pDrvCtrl->interruptTime >= 0) pDrvCtrl->interruptTime = -1; }#endif /* ELT_TIMING */ status = sysInByte (pDrvCtrl->port + ELT_STATUS) & 0x00ff; if ( (status & INTERRUPT_LATCH) == 0) { ++pDrvCtrl->eltStat.strayint; return; } else ++pDrvCtrl->eltStat.interrupts; /* Handle adapter failure first in case other conditions mask it */ if ( (status & ADAPTER_FAILURE) != 0) { sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_DIAGNOSTIC); statusDiag = sysInWord (port + FIFO_DIAGNOSTIC); sysOutWord (port + ELT_COMMAND, SELECT_WINDOW | WIN_OPERATING); if ( (statusDiag & FD_TX_OVERRUN) != 0) { ++pDrvCtrl->eltStat.txoverruns; sysOutWord (port + ELT_COMMAND, TX_RESET); eltTxStart (pDrvCtrl); } if ( (status & FD_RX_UNDERRUN) != 0) { ++pDrvCtrl->eltStat.rxunderruns; sysOutWord (port + ELT_COMMAND, RX_RESET); eltRxStart (pDrvCtrl); } } /* Handle receive complete interrupt */ if ( (status & (RX_COMPLETE | RX_EARLY)) != 0) { if ( (status & RX_EARLY) != 0) ++pDrvCtrl->eltStat.rxearly; if (pDrvCtrl->pRxCurrent == NULL) ++pDrvCtrl->eltStat.rxnobuffers;#ifdef ELT_TIMING { int timeNow; int timeDelta; if (pDrvCtrl->interruptTime >= 0) { timeNow = (int)sysInByte (port + TIMER); if (timeNow == 0xff) ++pDrvCtrl->eltStat.timerOverflow; else { ++pDrvCtrl->eltStat.timerUpdates; timeDelta = timeNow - pDrvCtrl->interruptTime; if (timeDelta > pDrvCtrl->eltStat.maxRxLatency) pDrvCtrl->eltStat.maxRxLatency = timeDelta; if ( (pDrvCtrl->eltStat.minRxLatency == 0) || (timeDelta < pDrvCtrl->eltStat.minRxLatency)) pDrvCtrl->eltStat.minRxLatency = timeDelta;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -