📄 if_eex.c
字号:
} }/********************************************************************************* eexCommand - deliver a command to the 82586 via SCB** This function causes the device to execute a command. It should be called* with interrupts from the device disabled. An error status is returned if* the command field does not return to zero, from a previous command, in a* reasonable amount of time.*/static STATUS eexCommand ( DRV_CTRL *pDrvCtrl, UINT16 cmd ) { int loopy; for (loopy = 0x8000; loopy--;) { /* wait for cmd zero */ if (sysInWord (pDrvCtrl->port + SCB_COMMAND) == 0) break; } if (loopy > 0) { /* fill in command */ sysOutWord (pDrvCtrl->port + SCB_COMMAND, cmd); eex586ChanAtn (pDrvCtrl); /* channel attention */ return (OK); } else { logMsg("eex driver: command field frozen\n", 0, 0, 0, 0, 0, 0); return (ERROR); } }/********************************************************************************* eexTxQPut - place a transmit frame on the transmit queue** The TFD has been filled in with the network pertinent data. This* routine will enqueue the TFD for transmission and attempt to feed* the queue to the device.*/static void eexTxQPut ( DRV_CTRL *pDrvCtrl, EEX_SHORTLINK tfdOffset ) { int unit; unit = pDrvCtrl->idr.ac_if.if_unit; eex586IntDisable (pDrvCtrl->idr.ac_if.if_unit); /* disable dev ints */ if (pDrvCtrl->txQueue.head != NULL) { /* Clear EL bit on previous tail frame */ sysOutWord (pDrvCtrl->port + WRPTR, pDrvCtrl->txQueue.tail + TF_COMMAND); sysOutWord (pDrvCtrl->port + DXREG, CFD_C_XMIT); } /* enqueue the TFD */ eexQPut (pDrvCtrl, (EEX_LIST *)&pDrvCtrl->txQueue, tfdOffset); sysOutWord (pDrvCtrl->port + WRPTR, pDrvCtrl->txQueue.tail + TF_COMMAND); sysOutWord (pDrvCtrl->port + DXREG, CFD_C_XMIT | CFD_C_EL); if (pDrvCtrl->txIdle) /* transmitter idle */ eexTxQFlush (pDrvCtrl); /* flush txQueue */ eex586IntEnable (pDrvCtrl->idr.ac_if.if_unit); /* enable dev ints */ }/********************************************************************************* eexTxQFlush - make cmd unit of device start processing cmds** This routine flushes the contents of the txQ to the cblQ and starts the* device transmitting the cblQ. Called only if transmit queue is not empty.* Sometimes called from interrupt handler.*/static void eexTxQFlush ( DRV_CTRL *pDrvCtrl ) { extern int sysClkRateGet(); /* we call this */ pDrvCtrl->cblQueue.head = pDrvCtrl->txQueue.head; /* remember cbl head */ pDrvCtrl->cblQueue.tail = pDrvCtrl->txQueue.tail; /* remember cbl tail */ eexQInit ( (EEX_LIST *)&pDrvCtrl->txQueue); /* tx queue now empty */ sysOutWord(pDrvCtrl->port + SCB_CBL, pDrvCtrl->cblQueue.head); pDrvCtrl->txIdle = FALSE; /* transmitter busy */ /* start watchdog */ wdStart ( pDrvCtrl->wid, (int) (sysClkRateGet() >> 1), (FUNCPTR) eexWatchDog, pDrvCtrl->idr.ac_if.if_unit ); /* start command unit */ eexCommand (pDrvCtrl, SCB_C_CUSTART); }/********************************************************************************* eexRxQPut - return a RFD to the receive queue for use by the device*/static void eexRxQPut ( DRV_CTRL *pDrvCtrl, EEX_SHORTLINK rfdOffset ) { EEX_SHORTLINK rxTail; UINT16 status; EEX_SHORTLINK rbdOffset; /* dhe 10/24/94 */ sysOutWord (pDrvCtrl->port + WRPTR, rfdOffset); sysOutWord (pDrvCtrl->port + DXREG, 0); /* clear status */ sysOutWord (pDrvCtrl->port + DXREG, CFD_C_EL); /* new end of list */ /* dhe 10/24/94 get the buffer pointer */ sysOutWord(pDrvCtrl->port + RDPTR, rfdOffset + RB_OFFSET); rbdOffset = sysInWord(pDrvCtrl->port + DXREG); /* dhe 10/24/94 TEST TEST zero the actual count of the buffer */ sysOutWord(pDrvCtrl->port + WRPTR, rbdOffset); sysOutWord(pDrvCtrl->port + DXREG, 0); rxTail = pDrvCtrl->rxQueue.tail; /* remember tail */ /* Put the RFD on the list */ eexQPut (pDrvCtrl, (EEX_LIST *) & pDrvCtrl->rxQueue, rfdOffset); if (rxTail != NULL) { sysOutWord (pDrvCtrl->port + WRPTR, rxTail + RF_COMMAND); sysOutWord (pDrvCtrl->port + DXREG, 0); /* clear old tail EL */ sysOutWord (pDrvCtrl->port + RDPTR, rxTail); status = sysInWord (pDrvCtrl->port + DXREG); if (status & (CFD_S_COMPLETE | CFD_S_BUSY)) { pDrvCtrl->freeRfd = rfdOffset; /* link questionable */ } else if (!(sysInWord (pDrvCtrl->port + SCB_STATUS) & SCB_S_RUREADY)) /* receiver dormant */ { eexRxStartup (pDrvCtrl); /* start receive unit */ } } else { pDrvCtrl->freeRfd = rfdOffset; /* first free RFD */ } }/********************************************************************************* eexRxQGet - get a successfully received frame from the receive queue** RETURNS: ptr to valid RFD, or NULL if none available*/static EEX_SHORTLINK eexRxQGet ( DRV_CTRL *pDrvCtrl ) { EEX_SHORTLINK rfdOffset = NULL; if (eexRxQFull (pDrvCtrl)) rfdOffset = eexQGet (pDrvCtrl, (EEX_LIST *)&pDrvCtrl->rxQueue); return (rfdOffset); }/********************************************************************************* eexRxQFull - boolean function to determine fullness of receive queue** RETURNS: TRUE if completely received frame is available, FALSE otherwise.*/static BOOL eexRxQFull ( DRV_CTRL *pDrvCtrl ) { return ( (pDrvCtrl->rxQueue.head != NULL) && ( sysOutWord (pDrvCtrl->port + RDPTR, pDrvCtrl->rxQueue.head), sysInWord (pDrvCtrl->port + DXREG) & CFD_S_COMPLETE ) ); }/********************************************************************************* eexQInit - initialize a singly linked node queue*/static void eexQInit ( EEX_LIST *pQueue ) { pQueue->head = pQueue->tail = NULL; /* init head & tail */ }/********************************************************************************* eexQGet - get a node from the head of a node queue** RETURNS: ptr to useable node, or NULL ptr if none available* Since we never alter links, we are taking the last node when head==tail.*/static EEX_SHORTLINK eexQGet ( DRV_CTRL *pDrvCtrl, EEX_LIST *pQueue ) { EEX_SHORTLINK pNode; if ( (pNode = (EEX_SHORTLINK) pQueue->head) != NULL) /* if list not empty */ { if (pQueue->head == pQueue->tail) pQueue->head = /* list now empty */ pQueue->tail = NULL; else pQueue->head = SUCC_FD (pNode); /* advance ptr */ } return (pNode); }/********************************************************************************* eexQPut - put a node on the tail of a node queue*/static void eexQPut ( DRV_CTRL *pDrvCtrl, EEX_LIST *pQueue, EEX_SHORTLINK pNode ) { /* assert (SUCC_FD (pQueue->tail) == pNode); */ if (pQueue->head == NULL) /* if list empty */ pQueue->head = pNode; /* new element is head */ pQueue->tail = pNode; /* update tail ptr */ }/********************************************************************************* eexWatchDog - if the watchdog timer fired off, we've hung during a transmit** Check the scb command to verify and if so, reinit.*/static void eexWatchDog ( int unit /* unit number */ ) { DRV_CTRL *pDrvCtrl; pDrvCtrl = & drvCtrl [unit]; /* sanity check. * If the scb status indicates that CU (transmit) is active * It might make sense to loop through the cfd's to look for * a complete bit as a sanity check , but given that we are * here and that transmit was active, we will go ahead and do * a reset. */ if (sysInWord (pDrvCtrl->port + SCB_STATUS) & SCB_S_CUACTIVE) { pDrvCtrl->transLocks++; /* local failure count */ pDrvCtrl->idr.ac_if.if_oerrors++; /* incr err count */ pDrvCtrl->idr.ac_if.if_opackets--; /* decr sent count */ DUMMY(unit); } }/********************************************************************************* eex586Init - Initialize board features** Does pretty much everything to initialize the 82586 and its memory* structures, either in this routine or in called routines.*/static STATUS eex586Init ( int unit ) { DRV_CTRL *pDrvCtrl; int ix; int port; EEX_SHORTLINK currentFd; /**** dhe 10/26/94 moved to global for reassigning during restart EEX_SHORTLINK lastFd; ****/ int connValue; pDrvCtrl = & drvCtrl [unit]; port = pDrvCtrl->port; eex586IntDisable (unit); /* disable device interrupts */ /* extract setup information from the board's EEPROM */ /* Remember that readEEPROM() sets the 82586 reset condition. */ pDrvCtrl->setup = eexReadEEPROM (pDrvCtrl, EEX_EEPROM_SETUP); pDrvCtrl->tpeBit = eexReadEEPROM (pDrvCtrl, EEX_EEPROM_TPE_BIT); pDrvCtrl->memSetup.wordView.memPage = eexReadEEPROM (pDrvCtrl, EEX_EEPROM_MEMPAGE); pDrvCtrl->memSetup.wordView.memDecode = eexReadEEPROM (pDrvCtrl, EEX_EEPROM_MEMDECODE); if (pDrvCtrl->attachment == ATTACHMENT_DEFAULT) if ( (pDrvCtrl->memSetup.wordView.memPage & MEMPAGE_AUTODETECT) != 0) { /* Here we would figure out which connector is in use; * "auto-detect" relies on software to do the actual detection. */ } else { if ( (pDrvCtrl->setup & SETUP_BNC) == 0) pDrvCtrl->attachment = ATTACHMENT_AUI; else if ( (pDrvCtrl->tpeBit & TPE_BIT) == 0) pDrvCtrl->attachment = ATTACHMENT_BNC; else pDrvCtrl->attachment = ATTACHMENT_RJ45; } /* Tell the board hardware which connector we're using */ connValue = sysInByte (port + ECR1) & ~(CONN_INTEGRITY | CONN_TRANSCEIVER); switch (pDrvCtrl->attachment) { case ATTACHMENT_AUI: break; case ATTACHMENT_BNC: connValue |= CONN_TRANSCEIVER; break; case ATTACHMENT_RJ45: connValue |= CONN_TRANSCEIVER | CONN_INTEGRITY; break; } /* 17jan95 jag * Only send the connector selection command if the board is * NOT in "auto-detect" mode. (If the board is in * "auto-detect" mode, another command might disrupt the * auto-detected mode). */ if ( (pDrvCtrl->memSetup.wordView.memPage & MEMPAGE_AUTODETECT) == 0) sysOutByte (port + ECR1, connValue); /* get our enet addr */ if (eexEnetAddrGet (pDrvCtrl, (char *)pDrvCtrl->idr.ac_enaddr) == ERROR) { errnoSet (S_iosLib_INVALID_ETHERNET_ADDRESS); return (ERROR); } /* Connect the interrupt handler */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -