summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/elnk3/card.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/elnk3/card.c1321
1 files changed, 1321 insertions, 0 deletions
diff --git a/private/ntos/ndis/elnk3/card.c b/private/ntos/ndis/elnk3/card.c
new file mode 100644
index 000000000..ba8e26d9f
--- /dev/null
+++ b/private/ntos/ndis/elnk3/card.c
@@ -0,0 +1,1321 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ card.c
+
+Abstract:
+
+ Ndis 3.0 MAC driver for the 3Com Etherlink III
+
+Author:
+
+ Brian Lieuallen BrianLie 09/22/92
+
+Environment:
+
+ Kernel Mode Operating Systems : NT
+
+Revision History:
+
+ Portions borrowed from ELNK3 driver by
+ Earle R. Horton (EarleH)
+
+
+
+
+--*/
+
+
+
+#include <ndis.h>
+#include <efilter.h>
+
+#include "debug.h"
+
+
+#include "elnk3hrd.h"
+#include "elnk3sft.h"
+#include "elnk3.h"
+
+#include "keywords.h"
+
+
+#pragma NDIS_INIT_FUNCTION(Elnk3FindIsaBoards)
+#pragma NDIS_INIT_FUNCTION(Elnk3ActivateIsaBoard)
+#pragma NDIS_INIT_FUNCTION(ReadStationAddress)
+#pragma NDIS_INIT_FUNCTION(ELNK3WriteIDSequence)
+#pragma NDIS_INIT_FUNCTION(ELNK3ContentionTest)
+#pragma NDIS_INIT_FUNCTION(Elnk3GetEisaResources)
+#pragma NDIS_INIT_FUNCTION(CardEnable)
+#pragma NDIS_INIT_FUNCTION(CardTest)
+#pragma NDIS_INIT_FUNCTION(ELNK3ReadEEProm)
+#pragma NDIS_INIT_FUNCTION(Elnk3ProgramEEProm)
+#pragma NDIS_INIT_FUNCTION(Elnk3WriteEEProm)
+#pragma NDIS_INIT_FUNCTION(Elnk3WaitEEPromNotBusy)
+
+
+BOOLEAN
+CardTest (
+ OUT PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+
+ IF_INIT_LOUD (DbgPrint("Elnk3: CardTest(): Entered\n");)
+
+
+ if (!ReadStationAddress(pAdapter)) {
+ return FALSE;
+ }
+
+
+ if (!CardEnable(pAdapter)) {
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CardEnable(
+ IN PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+Routine Description:
+
+ This routine enables the card hardware and sets the dma channel and
+ interrupts number by writing to the Cards option register
+
+Arguments:
+
+Return Value:
+
+Note:
+
+ This should not be called before the registry is read and the Dma
+ and interrupt info is in place.
+
+--*/
+
+{
+
+ USHORT Temp;
+ UINT i;
+ ULONG Limit;
+ USHORT AddressConfig;
+ USHORT RevisionLevel;
+
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable\n");)
+
+
+ CardReset(pAdapter);
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_FIFO);
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_FREE_RX_BYTES,&pAdapter->RxFifoSize);
+
+
+ //
+ // Set the station address
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_STATIONADDRESS);
+
+ for (i=0;i<3;i++) {
+ Temp=pAdapter->StationAddress[i*2] | (((USHORT)pAdapter->StationAddress[i*2+1])<<8);
+ ELNK3WriteAdapterUshort(pAdapter,(i*2),Temp);
+ }
+
+ //
+ // Read address config register to find out transceiver type
+ //
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_SETUP);
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_CfgAddress,&AddressConfig);
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_DIAGNOSTICS);
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Address config register is %04x\n",AddressConfig);)
+
+ if ((AddressConfig >> 14) == 0) {
+ //
+ // Enable link beat on TP
+ //
+ if (pAdapter->EEpromSoftwareInfo & LINK_BEAT_DISABLED) {
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: NOT Enabling link beat on 10 Base-T\n");)
+
+ ELNK3WriteAdapterUshort(pAdapter,PORT_MEDIA_TYPE, MEDIA_JABBER);
+
+ } else {
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: Enabling link beat on 10 Base-T\n");)
+
+ ELNK3WriteAdapterUshort(pAdapter,PORT_MEDIA_TYPE,MEDIA_LINK_BEAT | MEDIA_JABBER);
+
+ }
+
+ }
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_NET_DIAG,&RevisionLevel);
+
+ RevisionLevel= ((RevisionLevel & 0x1e) >> 1);
+
+ pAdapter->RevisionLevel=(UCHAR)RevisionLevel;
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING);
+
+ //
+ // Test to see if the interrupt works or not
+ //
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff);
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,EC_INT_INTERRUPT_REQUESTED);
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0xff);
+
+ pAdapter->InitInterrupt=FALSE;
+
+ pAdapter->AdapterInitializing=TRUE;
+
+ ELNK3_COMMAND(pAdapter,EC_REQUEST_INTERRUPT,0);
+
+ Limit=2000;
+
+ while ((--Limit>0) && (!pAdapter->InitInterrupt)) {
+ NdisStallExecution(10);
+ }
+
+ pAdapter->AdapterInitializing=FALSE;
+
+ //
+ // Did it time out or did we get an interrupt
+ //
+ if (Limit==0) {
+ IF_INIT_LOUD(DbgPrint("ELNK3: Did not receive interrupt\n");)
+ return FALSE;
+ }
+
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+
+
+// ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0);
+// ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
+
+ if ((AddressConfig >> 14) == 3) {
+ //
+ // turn on 10base2 converter
+ //
+ IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: Turning on 10base2 converter\n");)
+
+ ELNK3_COMMAND(pAdapter,EC_START_COAX_XCVR,0);
+
+ NdisStallExecution(800);
+ }
+
+
+
+ pAdapter->CurrentInterruptMask=EC_INT_RX_EARLY |
+ EC_INT_TX_COMPLETE |
+ EC_INT_RX_COMPLETE |
+ EC_INT_TX_AVAILABLE |
+ EC_INT_ADAPTER_FAILURE |
+ EC_INT_INTERRUPT_REQUESTED;
+
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask);
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,pAdapter->CurrentInterruptMask);
+
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Adapter initialized correctly\n");)
+ return TRUE;
+}
+
+
+
+BOOLEAN
+CardReInit(
+ IN PELNK3_ADAPTER pAdapter
+ )
+
+{
+ USHORT FifoStatus;
+ USHORT FreeFifoBytes;
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_DIAGNOSTICS);
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_FIFO_DIAG,&FifoStatus);
+
+ ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING);
+
+ if (FifoStatus & RX_UNDERRUN) {
+ IF_LOUD(DbgPrint("ELNK3: Receive Underrun\n");)
+
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0);
+
+ ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, pAdapter->RxFilter);
+ }
+
+ if (FifoStatus & TX_OVERRUN) {
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_TxFree,&FreeFifoBytes);
+
+ IF_LOUD(DbgPrint("ELNK3: Transmit Overrun - Bytesfree=%d\n",FreeFifoBytes);)
+
+
+ ELNK3_COMMAND(pAdapter,EC_TX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
+ }
+
+
+ return TRUE;
+
+}
+
+
+VOID
+CardReStart(
+ IN PELNK3_ADAPTER pAdapter
+ )
+
+{
+
+ IF_LOUD(DbgPrint("ELNK3: CardRestart\n");)
+
+ //
+ // put the filter back
+ //
+ ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, 0);
+
+
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0x00);
+
+ pAdapter->CurrentInterruptMask=EC_INT_RX_EARLY |
+ EC_INT_TX_COMPLETE |
+ EC_INT_RX_COMPLETE |
+ EC_INT_TX_AVAILABLE |
+ EC_INT_ADAPTER_FAILURE |
+ EC_INT_INTERRUPT_REQUESTED;
+
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask);
+
+
+
+ //
+ // Reset and re-enable the receiver
+ //
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0);
+
+
+ //
+ // reset and restart the transmitter
+ //
+ ELNK3_COMMAND(pAdapter,EC_TX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0);
+
+ ELNK3_COMMAND(pAdapter,EC_SET_TX_START,pAdapter->TxStartThreshold & 0x7ff);
+
+ //
+ // clear all pending interrupts
+ //
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff);
+
+ //
+ // reset the receive buffer info
+ //
+ pAdapter->CurrentPacket=0;
+
+ pAdapter->TransContext[0].BytesAlreadyRead=0;
+ pAdapter->TransContext[0].PacketLength=0;
+
+ pAdapter->TransContext[1].BytesAlreadyRead=0;
+ pAdapter->TransContext[1].PacketLength=0;
+}
+
+
+VOID
+CardReStartDone(
+ IN PELNK3_ADAPTER pAdapter
+ )
+
+{
+
+ IF_LOUD(DbgPrint("ELNK3: CardRestartDone\n");)
+
+ ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0xff);
+ //
+ // put the filter back
+ //
+ ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, pAdapter->RxFilter);
+
+ return;
+}
+
+
+VOID
+CardReset(
+ IN PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+{
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Reset Card\n");)
+
+ //
+ // Mask everything
+ //
+ ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,0);
+
+ //
+ // Clear all interrupt reasons
+ //
+ ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff);
+
+
+ ELNK3_COMMAND(pAdapter,EC_RX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+
+ ELNK3_COMMAND(pAdapter,EC_TX_RESET,0);
+ ELNK3_WAIT_NOT_BUSY(pAdapter);
+}
+
+
+
+
+BOOLEAN
+ReadStationAddress(
+ OUT PELNK3_ADAPTER pAdapter
+ )
+/*++
+
+ Routine Description:
+ Read the station address from the PROM
+
+ Arguments:
+
+
+ Return Value:
+
+
+--*/
+
+{
+
+ UINT i,Sum;
+ USHORT Temp;
+
+ Sum=0;
+
+ IF_INIT_LOUD( DbgPrint("Elnk3: The Station address is ");)
+
+ ELNK3_SELECT_WINDOW(pAdapter,0);
+
+
+ //
+ // Read the eeprom software info to see if we need
+ // to enable link beat of not
+ //
+ pAdapter->EEpromSoftwareInfo=ELNK3ReadEEProm(
+ pAdapter,
+ (UCHAR)EEPROM_SOFTWARE_INFO
+ );
+
+
+
+ for (i=0;i<3;i++) {
+ Temp=ELNK3ReadEEProm(
+ pAdapter,
+ (UCHAR)i
+ );
+
+
+ pAdapter->PermanentAddress[i*2] = Temp>>8;
+ pAdapter->PermanentAddress[i*2+1] = Temp & 0x00ff;
+ IF_INIT_LOUD( DbgPrint(" %04X",Temp);)
+ }
+
+ //
+ // Put the product id value back in the eeprom data register
+ //
+ ELNK3ReadEEProm(
+ pAdapter,
+ (UCHAR)EEPROM_PRODUCT_ID
+ );
+
+
+
+
+ //
+ // Copy in permanent address if necessary
+ //
+
+ if (!(pAdapter->StationAddress[0] |
+ pAdapter->StationAddress[1] |
+ pAdapter->StationAddress[2] |
+ pAdapter->StationAddress[3] |
+ pAdapter->StationAddress[4] |
+ pAdapter->StationAddress[5])) {
+
+ ETH_COPY_NETWORK_ADDRESS(pAdapter->StationAddress,
+ pAdapter->PermanentAddress
+ );
+ }
+
+
+ IF_INIT_LOUD( DbgPrint("\n");)
+
+
+ return TRUE;
+}
+
+
+
+
+
+UINT
+Elnk3FindIsaBoards(
+ IN PMAC_BLOCK pMacBlock
+ )
+
+{
+
+ PVOID IdPort=pMacBlock->TranslatedIdPort;
+ UINT i;
+ USHORT ProductId;
+
+
+ if (pMacBlock->IsaAdaptersFound != 0) {
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: FindIsaBorads: called again\n");)
+
+ return pMacBlock->IsaAdaptersFound;
+ }
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: FindIsaBorads: called, first time\n");)
+
+ //
+ // Untag all adapters
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+0);
+
+ //
+ // We find all the ISA boards in the system and tag them
+ // We note each ones configured I/O base, so that
+ // we can reset all of the ones not configured as EISA
+ //
+
+ for (i=0; i<7 ; i++) {
+
+ //
+ // Get the cards' attention
+ //
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // See if there any cards out there
+ //
+ if ( ELNK3ContentionTest( IdPort, EE_MANUFACTURER_CODE ) == EISA_MANUFACTURER_ID ) {
+ //
+ // we found at least one
+ //
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD0 );
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD1 );
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD2 );
+
+ //
+ // This one won the contention battle
+ // Get it's i/o base and irq from the eeprom
+ //
+
+ ProductId=ELNK3ContentionTest( IdPort, EE_VULCAN_PROD_ID );
+
+ ProductId&=0xf0ff;
+
+ if (ProductId == 0x9050) {
+ //
+ // This one is a elnk3 adapter
+ //
+ pMacBlock->IsaCards[i].AddressConfigRegister=
+ ELNK3ContentionTest( IdPort, EE_ADDR_CONFIGURATION );
+
+ pMacBlock->IsaCards[i].IOPort= 0x200 + ((pMacBlock->IsaCards[i].AddressConfigRegister & 0x1f)<<4);
+
+ } else {
+ //
+ // We found a 3Com card that is not an elnk3.
+ // We will set the base address, to make it look like an EISA
+ // one so that code below will leave it alone
+ //
+ IF_INIT_LOUD(DbgPrint("Elnk3: Found non-elnk3 during contention ProductId=%04x\n",ProductId);)
+
+ pMacBlock->IsaCards[i].IOPort=0x3f0;
+ }
+
+ pMacBlock->IsaCards[i].Tagged=TRUE;
+ //
+ // Tag it so it don't bother us again
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+(i+1));
+
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 card #%d, io=%04x\n",
+ i,
+ pMacBlock->IsaCards[i].IOPort
+ );)
+
+
+ } else {
+ //
+ // No more elnk3 cards
+ //
+ break;
+ }
+ }
+
+
+ //
+ // Now all of the ISA adapters have been found and tagged
+ // We now go through and reset all of the ones that are
+ // not configured as EISA.
+ //
+
+ for (i=0; i<7 ; i++) {
+
+ //
+ // Get the cards' attention
+ //
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // If it is not configured as eisa reset it
+ //
+ if ((pMacBlock->IsaCards[i].IOPort != 0x03f0) && pMacBlock->IsaCards[i].Tagged) {
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Reseting Elnk3 card #%d\n",i);)
+
+ //
+ // Put the others back to sleep
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1));
+
+ //
+ // Reset this one
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_RESET);
+
+ NdisStallExecution(500);
+
+ } else {
+#if DBG
+ if (pMacBlock->IsaCards[i].Tagged) {
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: NOT Reseting EISA configured Elnk3 card #%d\n",i);)
+ }
+#endif
+ }
+
+ }
+
+ //
+ // Now we go and find the adapters for real.
+ //
+
+ //
+ // Untag all adapters
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+0);
+
+
+ for (i=0; i<7 ; i++) {
+
+ //
+ // Get the cards' attention
+ //
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // See if there any cards out there
+ //
+ if ( ELNK3ContentionTest( IdPort, EE_MANUFACTURER_CODE ) == EISA_MANUFACTURER_ID ) {
+
+ //
+ // we found at least one
+ //
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD0 );
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD1 );
+ ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD2 );
+
+ //
+ // This one won the contention battle
+ // Get it's i/o base and irq from the eeprom
+ //
+
+ ProductId=ELNK3ContentionTest( IdPort, EE_VULCAN_PROD_ID );
+
+ ProductId&=0xf0ff;
+
+ if (ProductId == 0x9050) {
+ //
+ // This one is a elnk3 adapter
+ //
+
+ pMacBlock->IsaCards[i].AddressConfigRegister=
+ ELNK3ContentionTest( IdPort, EE_ADDR_CONFIGURATION );
+
+ pMacBlock->IsaCards[i].ResourceConfigRegister=
+ ELNK3ContentionTest( IdPort, EE_RESOURCE_CONFIGURATION );
+
+
+ pMacBlock->IsaCards[i].IOPort= 0x200 + ((pMacBlock->IsaCards[i].AddressConfigRegister & 0x1f)<<4);
+ pMacBlock->IsaCards[i].Irq=pMacBlock->IsaCards[i].ResourceConfigRegister >> 12;
+
+ if (pMacBlock->IsaCards[i].IOPort == 0x03f0) {
+ //
+ // This one is configured as EISA. Mark it as active
+ // so it will be ignored
+ //
+ IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 ISA configed as EISA\n");)
+
+ pMacBlock->IsaCards[i].Active=TRUE;
+ }
+
+ } else {
+ //
+ // We found a 3Com card that is not an elnk3.
+ // We will set the base address, to make it look like an EISA
+ // one so that code below will leave it alone
+ //
+ IF_INIT_LOUD(DbgPrint("Elnk3: Found non-elnk3 during contention ProductId=%04x\n",ProductId);)
+
+ pMacBlock->IsaCards[i].IOPort=0x3f0;
+
+ pMacBlock->IsaCards[i].Active=TRUE;
+ }
+
+
+ //
+ // Tag it so it don't bother us again
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+(i+1));
+
+
+ IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 card #%d, io=%04x, irq=%d\n",
+ i,
+ pMacBlock->IsaCards[i].IOPort,
+ pMacBlock->IsaCards[i].Irq
+ );)
+
+ //
+ // One more found
+ //
+ pMacBlock->IsaAdaptersFound++;
+
+ } else {
+ //
+ // No more elnk3 cards
+ //
+ break;
+ }
+ }
+
+ return pMacBlock->IsaAdaptersFound;
+
+}
+
+
+BOOLEAN
+Elnk3ActivateIsaBoard(
+ IN PMAC_BLOCK pMacBlock,
+ IN PELNK3_ADAPTER pAdapter,
+ IN NDIS_HANDLE AdapterHandle,
+ IN PUCHAR TranslatedIoBase,
+ IN ULONG ConfigIoBase,
+ IN OUT PULONG Irq,
+ IN ULONG Transceiver,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+{
+
+ PVOID IdPort=pMacBlock->TranslatedIdPort;
+ UINT i;
+ USHORT AddressConfig;
+ USHORT ResourceConfig;
+
+ for (i=0; i<pMacBlock->IsaAdaptersFound; i++) {
+ //
+ // Search our table for a card that matches the I/O base passed
+ // in from the registry
+ //
+
+ if ((pMacBlock->IsaCards[i].IOPort == ConfigIoBase)
+ &&
+ (pMacBlock->IsaCards[i].Irq==*Irq)
+ &&
+ ((pMacBlock->IsaCards[i].AddressConfigRegister>>14) == (USHORT)Transceiver)
+ &&
+ (!pMacBlock->IsaCards[i].Active)) {
+ //
+ // Everything matched and it is not currently active
+ //
+
+ IF_LOUD(DbgPrint("ELNK3: Found Match-Activating ISA card # %d at %04x\n",i,ConfigIoBase);)
+ //
+ // Found one, Now get the cards' attention
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // Put the others back to sleep
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1));
+
+ //
+ // Activate it at the its configured base.
+ //
+ NdisRawWritePortUchar(IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4));
+
+ //
+ // this one is in use now
+ //
+ pMacBlock->IsaCards[i].Active=TRUE;
+
+ //
+ // enable the IRQ drivers
+ //
+ NdisRawWritePortUchar(
+ TranslatedIoBase+PORT_CfgControl,
+ CCR_ENABLE
+ );
+
+ return TRUE;
+ }
+ }
+
+ IF_LOUD(DbgPrint("ELNK3: Did not find an adapter that matched i/O base %04x\n",ConfigIoBase);)
+
+ //
+ // Did not find a match, So now we activate the first unused
+ // card at the address supplied in the registry.
+ //
+ if ((*Irq != 0) && (Transceiver != 2)) {
+ //
+ // The irq and transceiver parameters are present,
+ // so we will reprogram the card to make them match
+ //
+
+ for (i=0; i<pMacBlock->IsaAdaptersFound; i++) {
+ //
+ // Search our table for a card that has not been activated
+ //
+
+ if ((!pMacBlock->IsaCards[i].Active)) {
+
+ IF_LOUD(DbgPrint("ELNK3: Reconfiguring ISA card # %d to %04x, %d, %d\n",i,ConfigIoBase,*Irq,Transceiver);)
+
+ //
+ // Found one, Now get the cards' attention
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // Put the others back to sleep
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1));
+
+ //
+ // Activate where we want it
+ //
+ NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4));
+
+ //
+ // in use now
+ //
+ pMacBlock->IsaCards[i].Active=TRUE;
+
+ //
+ // set the transceiver bits in the address config register
+ //
+ NdisRawReadPortUshort(
+ TranslatedIoBase+PORT_CfgAddress,
+ &AddressConfig
+ );
+
+ //
+ // only want the change the transceiver bits and io base
+ //
+ AddressConfig &= 0x3fc0;
+
+ AddressConfig |= (Transceiver << 14) | ((ConfigIoBase - 0x200) >> 4);
+
+ NdisRawWritePortUshort(
+ TranslatedIoBase+PORT_CfgAddress,
+ AddressConfig
+ );
+
+ //
+ // set the irq number in resources config register
+ //
+ ResourceConfig=((USHORT)*Irq << 12) | 0x0f00;
+
+
+ NdisRawWritePortUshort(
+ TranslatedIoBase+PORT_CfgResource,
+ ResourceConfig
+ );
+
+ //
+ // enable the IRQ drivers
+ //
+ NdisRawWritePortUchar(
+ TranslatedIoBase+PORT_CfgControl,
+ CCR_ENABLE
+ );
+
+
+ //
+ // Program the eeprom to match the registry
+ //
+ Elnk3ProgramEEProm(
+ pAdapter,
+ AddressConfig,
+ ResourceConfig
+ );
+
+ return TRUE;
+ }
+ }
+
+ //
+ // Did not find any un activated cards
+ //
+ IF_LOUD(DbgPrint("ELNK3: Did not find an un activated adapter\n");)
+
+ return FALSE;
+
+ } else {
+ //
+ // the irq and/or transceiver values were missing from the registry.
+ // Activate the card where the eeprom says it should be.
+ //
+ IF_LOUD(DbgPrint("Elnk3: irq and transceiver values missing\n");)
+
+ for (i=0; i<pMacBlock->IsaAdaptersFound; i++) {
+ //
+ // Search our table for a card that has not been activated
+ //
+ if ((pMacBlock->IsaCards[i].IOPort == ConfigIoBase)
+ &&
+ (!pMacBlock->IsaCards[i].Active)) {
+
+ IF_LOUD(DbgPrint("ELNK3: Activating ISA card # %d at %04x\n",i,ConfigIoBase);)
+
+ //
+ // Found one, Now get the cards' attention
+ //
+
+ ELNK3WriteIDSequence( IdPort );
+
+ //
+ // Put the others back to sleep
+ //
+ NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1));
+
+ //
+ // Activate where we want it
+ //
+ NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4));
+
+ //
+ // enable the IRQ drivers
+ //
+ NdisRawWritePortUchar(
+ TranslatedIoBase+PORT_CfgControl,
+ CCR_ENABLE
+ );
+
+ //
+ // in use now
+ //
+ pMacBlock->IsaCards[i].Active=TRUE;
+
+ *Irq=pMacBlock->IsaCards[i].Irq;
+
+ IF_INIT_LOUD(DbgPrint("Elnk3: Missing IRQ is now %d\n",*Irq);)
+
+ {
+ NDIS_CONFIGURATION_PARAMETER Value;
+ NDIS_STATUS Status;
+ NDIS_STRING IrqKeyword = INTERRUPT;
+ NDIS_STRING TransceiverKeyword = TRANSCEIVER;
+ NDIS_HANDLE ConfigHandle = NULL;
+
+ //
+ // Open the configuration database.
+ //
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ return(FALSE);
+ }
+
+ Value.ParameterType = NdisParameterInteger;
+ Value.ParameterData.IntegerData = *Irq;
+ NdisWriteConfiguration(
+ &Status,
+ ConfigHandle,
+ &IrqKeyword,
+ &Value);
+
+ Value.ParameterType = NdisParameterInteger;
+ Value.ParameterData.IntegerData =
+ pMacBlock->IsaCards[i].AddressConfigRegister>>14;
+ NdisWriteConfiguration(
+ &Status,
+ ConfigHandle,
+ &TransceiverKeyword,
+ &Value);
+
+ NdisCloseConfiguration(ConfigHandle);
+ }
+
+ return TRUE;
+ }
+ }
+
+ //
+ // Did not find any un activated cards
+ //
+ IF_LOUD(DbgPrint("ELNK3: Did not find an un activated adapter\n");)
+
+ return FALSE;
+ }
+}
+
+
+VOID
+Elnk3ProgramEEProm(
+ PELNK3_ADAPTER pAdapter,
+ USHORT AddressConfig,
+ USHORT ResourceConfig
+ )
+
+{
+ USHORT Temp;
+ USHORT CheckSum;
+
+ Elnk3WriteEEProm(
+ pAdapter,
+ EE_ADDR_CONFIGURATION,
+ AddressConfig
+ );
+
+ Elnk3WriteEEProm(
+ pAdapter,
+ EE_RESOURCE_CONFIGURATION,
+ ResourceConfig
+ );
+
+ Temp=ELNK3ReadEEProm(
+ pAdapter,
+ EE_SOFTWARE_CONFIG_INFO
+ );
+
+ CheckSum=((AddressConfig>>8) ^ (AddressConfig & 0x00ff));
+
+ CheckSum= CheckSum ^ (ResourceConfig >> 8);
+ CheckSum= CheckSum ^ (ResourceConfig & 0x00ff);
+
+ CheckSum= CheckSum ^ (Temp >> 8);
+ CheckSum= CheckSum ^ (Temp & 0x00ff);
+
+ Temp=ELNK3ReadEEProm(
+ pAdapter,
+ EE_CHECK_SUM
+ );
+
+ Elnk3WriteEEProm(
+ pAdapter,
+ EE_CHECK_SUM,
+ (USHORT)((Temp & 0xff00) | (CheckSum & 0x00ff))
+ );
+
+}
+
+
+
+
+VOID
+ELNK3WriteIDSequence(
+ IN PVOID IdPort
+ )
+/*++
+
+Routine Description:
+
+ Writes the magic EtherLink III wake up sequence to a port.
+
+ This puts all uninitialized EtherLink III cards on the bus in the ID_CMD
+ state.
+
+ Must be called with exclusive access to all 1x0h ports, where x is any
+ hex digit.
+
+
+Arguments:
+
+
+Return Value:
+
+
+
+--*/
+
+
+{
+ USHORT outval;
+ UINT i;
+
+ NdisRawWritePortUchar(IdPort,0);
+ NdisRawWritePortUchar(IdPort,0);
+
+
+ for ( outval = 0xff, i = 255 ; i-- ; ) {
+ NdisRawWritePortUchar(IdPort,outval);
+ outval <<= 1;
+ if ( ( outval & 0x0100 ) != 0 ){
+ outval ^= 0xCF;
+ }
+ }
+}
+
+
+
+
+USHORT
+ELNK3ContentionTest(
+ IN PVOID IdPort,
+ IN UCHAR EEPromWord
+ )
+{
+
+ UCHAR data;
+ USHORT result;
+ UINT i;
+
+ NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_READ_PROM + EEPromWord);
+
+
+ /*
+ 3COM's detection code has a 400 microsecond delay here.
+ */
+ NdisStallExecution(400);
+
+ for ( i = 16, result = 0 ; i-- ; ) {
+ result <<= 1;
+ NdisRawReadPortUchar(IdPort,&data);
+ result += (data & 1);
+ }
+ return (result);
+}
+
+
+
+
+
+
+
+
+
+
+
+USHORT
+ELNK3ReadEEProm(
+ IN PELNK3_ADAPTER Adapter,
+ IN UCHAR EEPromWord
+)
+{
+ USHORT result;
+ ULONG Limit=10;
+
+ // Issue an EEPROM read command.
+
+ NdisRawWritePortUchar(Adapter->PortOffsets[PORT_EECmd],(UCHAR)(IDCMD_READ_PROM+EEPromWord));
+
+ //
+ // Spin until the EEPROM busy bit goes off.
+ //
+ Elnk3WaitEEPromNotBusy(Adapter);
+
+ //
+ // Fetch the data from the EEPROM data register.
+ //
+ ELNK3ReadAdapterUshort(Adapter,PORT_EEData,&result);
+
+ return ( result );
+}
+
+VOID
+Elnk3WriteEEProm(
+ IN PELNK3_ADAPTER pAdapter,
+ IN UCHAR EEPromWord,
+ IN USHORT Value
+ )
+
+{
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+ //
+ // put the data in the data register
+ //
+ ELNK3WriteAdapterUshort(pAdapter,PORT_EEData,Value);
+
+ //
+ // enable erase and write
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_EW_ENABLE);
+
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+ //
+ // erase the register
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_ERASE+EEPromWord);
+
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+ //
+ // enable erase and write again
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_EW_ENABLE);
+
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+ //
+ // Now write the data
+ //
+ ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_WRITE+EEPromWord);
+
+ Elnk3WaitEEPromNotBusy(pAdapter);
+
+}
+
+VOID
+Elnk3WaitEEPromNotBusy(
+ PELNK3_ADAPTER Adapter
+ )
+
+{
+
+ USHORT result;
+ ULONG Limit;
+ //
+ // Spin until the EEPROM busy bit goes off.
+ //
+ Limit=100;
+
+ ELNK3ReadAdapterUshort(Adapter,PORT_EECmd,&result);
+
+ while ((--Limit>0) && ( (result & EE_BUSY) != 0)) {
+
+ NdisStallExecution(1000);
+ ELNK3ReadAdapterUshort(Adapter,PORT_EECmd,&result);
+
+ }
+
+#if DBG
+ if (Limit == 0) {
+
+ IF_LOUD(DbgPrint("Elnk3: time out waiting for eeprom to not be busy\n");)
+
+ }
+#endif
+
+}
+
+
+VOID
+Elnk3GetEisaResources(
+ IN PELNK3_ADAPTER pAdapter,
+ IN OUT PULONG Irq
+ )
+
+{
+ USHORT Config;
+
+ ELNK3_SELECT_WINDOW(pAdapter, WNO_SETUP);
+
+ ELNK3ReadAdapterUshort(pAdapter,PORT_CfgResource,&Config);
+
+ IF_LOUD(DbgPrint("Elnk3: Eisa Irq is %d\n",Config>>12);)
+
+ *Irq=Config>>12;
+
+}
+
+
+#ifdef IO_DBG
+USHORT ELNK3_READ_PORT_USHORT( PVOID Adapter, ULONG Offset )
+{
+ USHORT data;
+ data = READ_PORT_USHORT((PUSHORT)((PELNK3_ADAPTER)Adapter)->PortOffsets[Offset]);
+ IF_IO_LOUD(DbgPrint("read ushort %x from port %x\n", data, Offset );)
+ return data;
+}
+USHORT ELNK3_READ_PORT_USHORT_DIRECT( PVOID Offset )
+{
+ USHORT data;
+ data = READ_PORT_USHORT((PUSHORT)Offset);
+ IF_IO_LOUD(DbgPrint("read ushort %x from port %x\n", data, Offset );)
+ return data;
+}
+#endif
+