Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1321 lines
30 KiB

/*++
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