📄 elt3c509end.c
字号:
pDrvCtrl->flags |= ELT3C_POLLING; intUnlock (oldLevel); /* now elt3c509Int won't get confused */ elt3c509IntDisable (pDrvCtrl); ENDLOGMSG (("STARTED\n", 1, 2, 3, 4, 5, 6)); elt3c509Config (pDrvCtrl); /* reconfigure device */ return (OK); }/********************************************************************************* elt3c509PollStop - stop polled mode operations** This function terminates polled mode operation. The device returns to* interrupt mode.** The device interrupts are enabled, the current mode flag is switched* to indicate interrupt mode and the device is then reconfigured for* interrupt operation.** RETURNS: OK or ERROR.*/LOCAL STATUS elt3c509PollStop ( ELT3C509_DEVICE * pDrvCtrl /* device structure */ ) { int oldLevel; oldLevel = intLock (); /* disable ints during register updates */ pDrvCtrl->flags &= ~ELT3C_POLLING; intUnlock (oldLevel); elt3c509IntEnable (pDrvCtrl); elt3c509Config (pDrvCtrl); ENDLOGMSG (("STOPPED\n", 1, 2, 3, 4, 5, 6)); return (OK); }/********************************************************************************* elt3c509IntEnable - enable board to cause interrupts** Because the board has maskable status, this routine can simply set the* mask to all ones. We set all the bits symbolically; the effect is the* same. Note that the interrupt latch is not maskable; if none of the other* mask bits are set, no interrupts will occur at all. Only those interrupts* whose status bits are enabled will actually occur. Note that the "intMask"* field in the device control structure is really the status mask.** RETURNS: N/A.*/LOCAL void elt3c509IntEnable ( ELT3C509_DEVICE * pDrvCtrl /* device structure */ ) { UINT16 status; SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->port + ELT3C509_STATUS, status); status &= 0x00ff; SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, ACK_INTERRUPT | status); SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, MASK_INTERRUPT | ADAPTER_FAILURE | TX_COMPLETE | TX_AVAILABLE | RX_COMPLETE | RX_EARLY | INTERRUPT_REQ | UPDATE_STATS); }/********************************************************************************* elt3c509IntDisable - prevent board from causing interrupts** This routine simply sets all the interrupt mask bits to zero.* It is intended for guarding board-critical sections.** RETURNS: N/A.*/LOCAL void elt3c509IntDisable ( ELT3C509_DEVICE * pDrvCtrl /* device structure */ ) { UINT16 status; SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, MASK_INTERRUPT | 0); SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->port + ELT3C509_STATUS, status); status &= 0x00ff; SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, ACK_INTERRUPT | status); }/********************************************************************************* elt3c509TxStart - turn on board's transmit function** RETURNS: N/A.*/LOCAL void elt3c509TxStart ( ELT3C509_DEVICE * pDrvCtrl /* device structure */ ) { SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, TX_ENABLE); }/********************************************************************************* elt3c509RxStart - enable board to start receiving** RETURNS: N/A.*/LOCAL void elt3c509RxStart ( ELT3C509_DEVICE * pDrvCtrl /* device structure */ ) { SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, SET_RX_FILTER | pDrvCtrl->rxFilter); SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, RX_ENABLE); }/********************************************************************************* elt3c509Reset - reset the elt3c509 interface** Mark interface as inactive and reset the adapter.** RETURNS: N/A.*/LOCAL void elt3c509Reset ( ELT3C509_DEVICE * pDrvCtrl /* device structure */ ) { elt3c509IntDisable (pDrvCtrl); /* prevent device from interrupting */ SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, RX_RESET); SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, TX_RESET); }/********************************************************************************* elt3c509StatFlush - flush the board's statistics registers to statistics* block Called when the board reports that its statistics registers are getting* full, or when someone wants to see the current statistics (to fully update* the statistics block).** Note that reading a statistics register zeroes it in the hardware.* Note also that zeroing all the registers is necessary and sufficient* to clear the interrupt condition.** Must be called with board or system interrupts disabled.** RETURNS: N/A.*/LOCAL void elt3c509StatFlush ( ELT3C509_DEVICE * pDrvCtrl /* device structure */ ) { int port; UINT16 tempCounter; port = pDrvCtrl->port; SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, SELECT_WINDOW | WIN_STATISTICS); SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, STATS_DISABLE); SYS_IN_BYTE (pDrvCtrl, port+CARRIER_LOSTS, tempCounter); pDrvCtrl->elt3c509Stat.nocarriers += tempCounter & 0x0f; SYS_IN_BYTE (pDrvCtrl, port+SQE_FAILURES, tempCounter); pDrvCtrl->elt3c509Stat.heartbeats += tempCounter & 0x0f; SYS_IN_BYTE (pDrvCtrl, port+MULT_COLLISIONS, tempCounter); pDrvCtrl->elt3c509Stat.multcollisions += tempCounter & 0x3f; SYS_IN_BYTE (pDrvCtrl, port+ONE_COLLISIONS, tempCounter); pDrvCtrl->elt3c509Stat.collisions += tempCounter & 0x3f; SYS_IN_BYTE (pDrvCtrl, port+LATE_COLLISIONS, tempCounter); pDrvCtrl->elt3c509Stat.latecollisions += tempCounter; SYS_IN_BYTE (pDrvCtrl, port+RECV_OVERRUNS, tempCounter); pDrvCtrl->elt3c509Stat.rxoverruns += tempCounter; SYS_IN_BYTE (pDrvCtrl, port+GOOD_TRANSMITS, tempCounter); pDrvCtrl->elt3c509Stat.txnoerror += tempCounter; SYS_IN_BYTE (pDrvCtrl, port+GOOD_RECEIVES, tempCounter); pDrvCtrl->elt3c509Stat.rxnoerror += tempCounter; SYS_IN_BYTE (pDrvCtrl, port+TX_DEFERRALS, tempCounter); pDrvCtrl->elt3c509Stat.deferring += tempCounter; /* Must read all the registers to be sure to clear the interrupt */ SYS_IN_WORD (pDrvCtrl, port + BYTES_RECEIVED, tempCounter); SYS_IN_WORD (pDrvCtrl, port + BYTES_TRANSMITTED, tempCounter); SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, STATS_ENABLE); SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, SELECT_WINDOW | WIN_OPERATING); }/********************************************************************************* elt3c509IntMaskSet - enable specific status conditions to cause interrupts** Sets bit(s) in the intMask field of the device control structure and in* the board's "read zero mask" where a one bit enables the corresponding* status condition to be read and to cause an interrupt.** RETURNS: N/A.*/LOCAL void elt3c509IntMaskSet ( ELT3C509_DEVICE * pDrvCtrl, /* device structure */ int maskBits /* mask bits */ ) { elt3c509IntDisable (pDrvCtrl); pDrvCtrl->intMask |= maskBits; SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, MASK_STATUS | pDrvCtrl->intMask); elt3c509IntEnable (pDrvCtrl); }/********************************************************************************* elt3c509Activate - attempt to activate the adapter with given address** The 3Com 3C509 ISA adapter does not enable itself at power-on. This is* left to the driver, which presumably knows which board it wants. This* we do know, from the port field in the driver control structure.** As a helpful side effect, this routine stores the OEM Ethernet address* of the selected adapter into the driver control structure.** Note that this procedure will activate only one board of the given I/O* address; this is presumably designed in by 3Com as a helpful feature.** RETURNS: OK or ERROR.*/LOCAL STATUS elt3c509Activate ( ELT3C509_DEVICE * pDrvCtrl ) { int adapterPort; /* I/O address of adapter we're to look for */ int selectedPort; /* I/O address of adapter we've found */ int addressConfig; /* adapter's address configuration register */ int resourceConfig; /* adapter's resource configuration register */ char nodeAddress [EA_SIZE]; STATUS status = OK; /* presume OK, change if there's a problem */ adapterPort = pDrvCtrl->port; elt3c509IdCommand (ID_PORT); /* wake up all adapters */ SYS_OUT_BYTE (pDrvCtrl, ID_PORT, ID_SET_TAG); /* clear all tags */ /* first see if there's a 3Com 3C5xx board out there at all */ if (elt3c509IdEepromRead (EE_A_MANUFACTURER) != MANUFACTURER_ID) return (ERROR); /* Identify adapters one by one until we find the right one; * as we eliminate adapters, we tag them so they don't participate * in the next round of contention eliminations. Along the way, * as part of the adapter contention process, we read out the * station address and resource configuration. */ do { elt3c509IdCommand (ID_PORT); /* prepare for contention */ /* Now read all untagged adapters' addresses from EEPROM * a bit at a time. Tagged adapters ignore the reads therefore * won't be found; we find the next untagged adapter. */ * (UINT16 *) &nodeAddress [0] = elt3c509IdEepromRead (EE_A_OEM_NODE_0); * (UINT16 *) &nodeAddress [2] = elt3c509IdEepromRead (EE_A_OEM_NODE_1); * (UINT16 *) &nodeAddress [4] = elt3c509IdEepromRead (EE_A_OEM_NODE_2); resourceConfig = elt3c509IdEepromRead (EE_A_RESOURCE); addressConfig = elt3c509IdEepromRead (EE_A_ADDRESS); if ((addressConfig & AC_IO_BASE_MASK) == AC_IO_BASE_EISA) { /* the EISA base address is the last possible one; if we hit * this value without finding the adapter we want, we're done. */ status = ERROR; break; } selectedPort = (addressConfig & AC_IO_BASE_MASK) * AC_IO_BASE_FACTOR + AC_IO_BASE_ZERO; ENDLOGMSG (("elt: activate: adapter at 0x%04x\n", selectedPort, 2, 3, 4, 5, 6)); /* tag this adapter so if we don't want it it won't contend again */ SYS_OUT_BYTE (pDrvCtrl, ID_PORT, ID_SET_TAG + 1); } while (selectedPort != adapterPort); if (status != ERROR) { SYS_OUT_BYTE (pDrvCtrl, ID_PORT, ID_ACTIVATE); uswab (nodeAddress, (char *)pDrvCtrl->enetAddr, EA_SIZE); } return (status); }/********************************************************************************* elt3c509IdCommand - put all adapters into ID command state** This procedure synchronizes the ID state machines of all installed 3Com* adapters in preparation for contending among them.** RETURNS: N/A.*/LOCAL void elt3c509IdCommand ( int idPort /* I/O address to use as ID port (1x0 hex) */ ) { int idValue; /* data read or written to ID port */ int count; /* We should guard this routine since the ID procedure touches * all unactivated adapters. In fact the first three writes should * be guarded against any possible intervening write to any port * 0x100, 0x110, 0x120, ... , 0x1f0. */ SYS_OUT_BYTE (pDrvCtrl, idPort, ID_RESET); /* select the ID port */ /* put adapters in ID-WAIT state */ SYS_OUT_BYTE (pDrvCtrl, idPort, ID_RESET); idValue = ID_SEQUENCE_INITIAL; for (count = ID_SEQUENCE_LENGTH; count > 0; count--) { SYS_OUT_BYTE (pDrvCtrl, idPort, idValue); idValue <<= 1; if ((idValue & ID_CARRY_BIT) != 0) idValue ^= ID_POLYNOMIAL; } }/********************************************************************************* elt3c509EepromRead - read one 16-bit adapter EEPROM register.** RETURNS: Value from an offset of the EEPROM.*/LOCAL int elt3c509EepromRead ( int port, int offset ) { int ix; UINT16 epromStatus; SYS_OUT_WORD (NULL, port + EEPROM_CONTROL, 0x80 + offset); /* wait 162 us minimum */ for (ix = 0; ix < 300; ix++) sysDelay (); SYS_IN_WORD (NULL, port + EEPROM_DATA, epromStatus); return (epromStatus); }/********************************************************************************* elt3c509IdEepromRead - read one 16-bit adapter EEPROM register** Read an EEPROM register bitwise by way of the ID port. Used for adapter* contention process and to find out what's in the EEPROM. Addresses are* masked to a valid size; invalid addresses are simply truncated.** RETURNS: Value from an offset of Eeprom.*/LOCAL UINT16 elt3c509IdEepromRead ( int address /* EEPROM register address */ ) { int bitCount; UINT16 value; UINT16 tempVal; SYS_OUT_BYTE (NULL, ID_PORT, ID_EEPROM_READ | (address & ID_EEPROM_MASK)); taskDelay (2); /* must wait for 162 uS read cycle */ value = 0; for (bitCount = ID_REGISTER_SIZE; bitCount > 0; bitCount--) { value <<= 1; SYS_IN_BYTE (NULL, ID_PORT, tempVal); value |= (tempVal & 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -