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.
 
 
 
 
 
 

1418 lines
32 KiB

#include <stdio.h>
#include <ndis.h>
#include "82595.h"
#include "eprohw.h"
#include "eprosw.h"
#include "epro.h"
#include "eprodbg.h"
NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT pDriverObject_,
IN PUNICODE_STRING RegistryPath_)
/*++
Routine Description:
This is the primary initialization routine for the EPRO driver.
It is simply responsible for the intializing the wrapper and registering
the Miniport driver. It then calls a system and architecture specific
routine that will initialize and register each adapter.
Arguments:
DriverObject - Pointer to driver object created by the system.
RegistryPath - Path to the parameters for this driver in the registry.
Return Value:
The status of the operation.
--*/
{
//
// Receives the status of the NdisMRegisterMiniport operation.
//
NDIS_STATUS status;
//
// Characteristics table for this driver.
//
NDIS_MINIPORT_CHARACTERISTICS EPro_Miniport_Char;
//
// Handle for referring to the wrapper about this driver.
//
NDIS_HANDLE ndisWrapperHandle;
//
// Initialize the wrapper.
//
NdisMInitializeWrapper(
&ndisWrapperHandle,
pDriverObject_,
RegistryPath_,
NULL);
//
// Initialize the Miniport characteristics for the call to
// NdisMRegisterMiniport.
//
// The major and minor version of the driver
EPro_Miniport_Char.MajorNdisVersion = EPRO_NDIS_MAJOR_VERSION;
EPro_Miniport_Char.MinorNdisVersion = EPRO_NDIS_MINOR_VERSION;
// our various Miniport handlers
EPro_Miniport_Char.CheckForHangHandler = EProCheckForHang;
EPro_Miniport_Char.DisableInterruptHandler = EProDisableInterrupts;
EPro_Miniport_Char.EnableInterruptHandler = EProEnableInterrupts;
EPro_Miniport_Char.HaltHandler = EProHalt;
EPro_Miniport_Char.HandleInterruptHandler = EProHandleInterrupt;
EPro_Miniport_Char.InitializeHandler = EProInitialize;
EPro_Miniport_Char.ISRHandler = EProISR;
EPro_Miniport_Char.QueryInformationHandler = EProQueryInformation;
EPro_Miniport_Char.ReconfigureHandler = NULL;
EPro_Miniport_Char.ResetHandler = EProReset;
EPro_Miniport_Char.SendHandler = EProSend;
EPro_Miniport_Char.SetInformationHandler = EProSetInformation;
EPro_Miniport_Char.TransferDataHandler = EProTransferData;
// register us as a miniport...
status = NdisMRegisterMiniport(
ndisWrapperHandle,
&EPro_Miniport_Char,
sizeof(EPro_Miniport_Char));
if (status != NDIS_STATUS_SUCCESS)
{
NdisTerminateWrapper(ndisWrapperHandle, NULL);
EPRO_DPRINTF_INIT(("DriverEntry UNSUCCESSFUL!\n"));
return STATUS_UNSUCCESSFUL;
}
EPRO_DPRINTF_INIT(("EPro DriverEntry Successful!\n"));
return(STATUS_SUCCESS);
}
NDIS_STATUS EProInitialize(
OUT PNDIS_STATUS openErrorStatus,
OUT PUINT selectedMediumIndex,
IN PNDIS_MEDIUM mediumArray,
IN UINT mediumArraySize,
IN NDIS_HANDLE miniportAdapterHandle,
IN NDIS_HANDLE configurationHandle)
/*++
Routine Description:
EProInitialize starts an adapter and registers resources with the
wrapper.
Arguments:
OpenErrorStatus - Extra status bytes for opening token ring adapters.
SelectedMediumIndex - Index of the media type chosen by the driver.
MediumArray - Array of media types for the driver to chose from.
MediumArraySize - Number of entries in the array.
MiniportAdapterHandle - Handle for passing to the wrapper when
referring to this adapter.
ConfigurationHandle - A handle to pass to NdisOpenConfiguration.
Return Values:
NDIS_STATUS_UNSUPPORTED_MEDIA - the wrapper tried to set a media
type we couldn't do
NDIS_STATUS_SUCCESS - operation succeeded ok
perhaps other error status returned from the NdisM calls..
--*/
{
PEPRO_ADAPTER adapter = NULL;
UINT i;
NDIS_STATUS status;
BOOLEAN fAllocatedAdapterMemory;
BOOLEAN fRegisteredIoPortRange;
//
// Find the 802.3 medium type and return it to the wrapper...
//
for (i = 0; i < mediumArraySize; i++)
{
if (mediumArray[i] == NdisMedium802_3)
{
break;
}
}
if (i == mediumArraySize)
{
return(NDIS_STATUS_UNSUPPORTED_MEDIA);
}
// Return the correct medium to the wrapper
//
*selectedMediumIndex = i;
fAllocatedAdapterMemory = FALSE;
fRegisteredIoPortRange = FALSE;
do
{
//
// Allocate Memory for the Adapter Structure
//
status = NdisAllocateMemory(
(PVOID *)&adapter,
sizeof(EPRO_ADAPTER),
0,
HighestAcceptableMax);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("Failed to allocate memory for the EPRO adapter stucture\n"));
break;
}
fAllocatedAdapterMemory = TRUE;
//
// Zero the adapter structure.
//
NdisZeroMemory(adapter, sizeof(EPRO_ADAPTER));
//
// Set some initial values in the adapter structure...
//
EProInitializeAdapterData(adapter);
//
// Save the miniport adapter handle for later
//
adapter->MiniportAdapterHandle = miniportAdapterHandle;
//
// Read configuration information for this adapter
//
status = EProReadConfiguration(adapter, configurationHandle);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("EProReadConfiguration FAILED!\n"));
break;
}
//
// Register our adapter handler with the wrapper.
//
NdisMSetAttributes(
adapter->MiniportAdapterHandle,
(NDIS_HANDLE)adapter,
FALSE,
adapter->BusType);
//
// Register the IO port range needed.
//
status = NdisMRegisterIoPortRange(
(PVOID *)(&adapter->IoPAddr),
adapter->MiniportAdapterHandle,
(ULONG)adapter->IoBaseAddr,
0x10);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("Could not register IO ports.\n"));
break;
}
fRegisteredIoPortRange = TRUE;
//
// Initialize the hardware and enable the card...
//
status = EProInitialReset(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("Failed Initial Reset\n"));
break;
}
//
// Now, the resetting is done - configure the hardware...
//
status = EProHWConfigure(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("Failed to configure EPRO hardware\n"));
break;
}
//
// If we are a step 2 or 3 adapter then update the eeprom if
// necessary. RM: add stepping 4.
//
if ((adapter->EProStepping == 2) || (adapter->EProStepping == 3) || (adapter->EProStepping == 4))
{
EProUpdateEEProm(adapter);
}
//
// Make sure that we do not free resources.
//
fAllocatedAdapterMemory = FALSE;
fRegisteredIoPortRange = FALSE;
} while (FALSE);
if (fRegisteredIoPortRange)
{
NdisMDeregisterIoPortRange(
adapter->MiniportAdapterHandle,
(ULONG)adapter->IoBaseAddr,
0x10,
(PVOID)adapter->IoPAddr);
}
if (fAllocatedAdapterMemory)
{
NdisFreeMemory(adapter, sizeof(EPRO_ADAPTER), 0);
}
return(status);
}
VOID EProUpdateEEProm(IN PEPRO_ADAPTER adapter)
/*++
Routine Description:
This routine is called after the card's configuration has been
read from the registry and after the card's IO ports have been
registered. Now we check the card's EEPROM and verify that the
configuration information in the registry matches that saved
in the EEPROM. If they DON'T match, we update the card's EEPROM
with the new info. Note that the registry always overrides the
info that is saved -- in fact the info saved on the card is never
used at all right now, except the IO address - it is always overriden
by defaults or the registry values. We just save it in case the user
boots to another OS or moves and re-installs the card (the detection
code DOES read the EEPROM-configured defaults, so a new install will
be interested in what we have set.)
Arguments:
adapter - pointer to our EPRO_ADAPTER structure
Return Values:
none
--*/
{
USHORT reg0, reg1;
BOOLEAN fCardUse8Bit;
BOOLEAN fUpdateEEPROM = FALSE;
USHORT cardIrq;
EProEERead(adapter, EPRO_EEPROM_CONFIG_OFFSET, &reg0);
EProEERead(adapter, EPRO_EEPROM_CONFIG1_OFFSET, &reg1);
//
// check the force 8-bit setting...
//
fCardUse8Bit = !(reg0 & EPRO_EEPROM_HOST_BUS_WD_MASK);
if (fCardUse8Bit != adapter->Use8Bit)
{
fUpdateEEPROM = TRUE;
if (adapter->Use8Bit)
{
reg0 &= ~EPRO_EEPROM_HOST_BUS_WD_MASK;
}
else
{
reg0 |= EPRO_EEPROM_HOST_BUS_WD_MASK;
}
}
//
// check the IRQ
//
switch(reg1 & EPRO_EEPROM_IRQ_MASK)
{
case 0:
cardIrq = (adapter->EProStepping == 4)? 3 : 9;
break;
case 1:
cardIrq = (adapter->EProStepping == 4)? 4 : 3;
break;
case 2:
cardIrq = 5;
break;
case 3:
cardIrq = (adapter->EProStepping == 4)? 7 : 10;
break;
case 4:
cardIrq = (adapter->EProStepping == 4)? 9 : 11;
break;
case 5:
cardIrq = (adapter->EProStepping == 4)? 10 : 5;
break;
case 6:
cardIrq = (adapter->EProStepping == 4)? 11 : 5;
break;
case 7:
cardIrq = (adapter->EProStepping == 4)? 12 : 5;
break;
default:
cardIrq = 0xff;
break;
}
EPRO_DPRINTF_INIT(("EEPROM Interrupt Number: 0x%x\n", cardIrq));
if (cardIrq != adapter->InterruptNumber)
{
EPRO_DPRINTF_INIT(("Changing EEPROM to interrupt number 0x%x\n", adapter->InterruptNumber));
fUpdateEEPROM = TRUE;
reg1 &= ~EPRO_EEPROM_IRQ_MASK;
//
// RM: in the following, some INTs are different for stepping 4.
// Unsupported ints default to IRQ 5. IRQ 2 and 9 are INT 0 for stepping 2/3.
//
switch(adapter->InterruptNumber)
{
case 2:
case 9:
reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_9_MASK : EPRO_EEPROM_IRQ_2_MASK;
break;
case 3:
reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_3_MASK : EPRO_EEPROM_IRQ_3_MASK;
break;
case 4:
reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_4_MASK : EPRO_EEPROM_IRQ_5_MASK;
break;
case 5:
reg1 |= EPRO_EEPROM_IRQ_5_MASK;
break;
case 7:
reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_7_MASK : EPRO_EEPROM_IRQ_5_MASK;
break;
case 10:
reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_10_MASK : EPRO_EEPROM_IRQ_10_MASK;
break;
case 11:
reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_11_MASK : EPRO_EEPROM_IRQ_11_MASK;
break;
case 12:
reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_12_MASK : EPRO_EEPROM_IRQ_5_MASK;
break;
default:
reg1 |= EPRO_EEPROM_IRQ_5_MASK;
break;
}
EPRO_DPRINTF_INIT(("EEPROM interrupt mask 0x%x\n", reg1 & EPRO_EEPROM_IRQ_MASK));
}
if (fUpdateEEPROM)
{
EProEEWrite(adapter, EPRO_EEPROM_CONFIG_OFFSET, reg0);
EProEEWrite(adapter, EPRO_EEPROM_CONFIG1_OFFSET, reg1);
EProEEUpdateChecksum(adapter);
}
}
NDIS_STATUS
EProReadConfiguration(
IN PEPRO_ADAPTER adapter,
IN NDIS_HANDLE configurationHandle
)
/*++
Routine Description:
Read card config info from the registry and set the values
in the adapter structure
Arguments:
adapter - pointer to our adapter structure
configurationHandle - a handle to a place in the registry we can
read our settings from
Return Values:
--*/
{
NDIS_STATUS status;
NDIS_HANDLE configHandle;
PNDIS_CONFIGURATION_PARAMETER returnedValue;
// These are the keys we read from the registry..
//
NDIS_STRING interruptNumberString = EPRO_REGISTRY_INTERRUPT_STRING;
// I/O Port Base Address
//
NDIS_STRING ioAddressString = EPRO_REGISTRY_IOADDRESS_STRING;
// OLD I/O Base Address
//
NDIS_STRING oldIOAddressString = EPRO_REGISTRY_OLDIOADDRESS_STRING;
// bus type
//
NDIS_STRING busTypeString = EPRO_REGISTRY_BUSTYPE_STRING;
// Transceiver Type
//
NDIS_STRING transceiverString = EPRO_REGISTRY_TRANSCEIVER_STRING;
// Io Channel Ready
//
NDIS_STRING IoChannelReadyString = EPRO_REGISTRY_IOCHRDY_STRING;
// Open the configuration file...
//
NdisOpenConfiguration(
&status,
&configHandle,
configurationHandle);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("EProReadConfiguration - failed in NdisOpenConfiguration\n"));
NdisFreeMemory(adapter, sizeof(adapter),0);
return(status);
}
// right now we'll just assume it's an isa card...
//
adapter->BusType = NdisInterfaceIsa;
// Do we need to update the IO base address?
//
adapter->fUpdateIOAddress = FALSE;
// Read "Real" IO Base Address (the one we want to use)
//
NdisReadConfiguration(&status,
&returnedValue,
configHandle,
&ioAddressString,
NdisParameterHexInteger);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("Error, can't find io address in registry...using default 0x300\n"));
adapter->IoBaseAddr = (PVOID)0x300;
}
else
{
adapter->IoBaseAddr = (PVOID)(returnedValue->ParameterData.IntegerData);
}
if ((adapter->IoBaseAddr > (PVOID)0x3f0) || (adapter->IoBaseAddr < (PVOID)0x200))
{
EPRO_DPRINTF_INIT(("Bad io address set in registry. Using 0x300.\n"));
adapter->IoBaseAddr = (PVOID)0x300;
}
//
// Read the InterruptNumber
//
NdisReadConfiguration(
&status,
&returnedValue,
configHandle,
&interruptNumberString,
NdisParameterHexInteger);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_REQ(("Error, can't read interrupt number from registry...using default\n"));
adapter->InterruptNumber = (CCHAR)5;
}
else
{
adapter->InterruptNumber = (CCHAR)(returnedValue->ParameterData.IntegerData);
}
// oh, yah, what was I on when I wrote this?
switch (adapter->InterruptNumber)
{
case 3:
case 5:
case 9:
case 10:
case 11:
// 4, 7 & 12 valid for v4 chips +RM
case 4:
case 7:
case 12:
break;
default:
adapter->InterruptNumber = (CCHAR)5;
}
//
// Read the TransceiverType
//
NdisReadConfiguration(
&status,
&returnedValue,
configHandle,
&transceiverString,
NdisParameterHexInteger);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_REQ(("Error, can't read transceiver type from registry...using AUTO\n"));
adapter->TransceiverType = (CCHAR)4;
}
else
{
adapter->TransceiverType = (CCHAR)(returnedValue->ParameterData.IntegerData);
}
//
// Read the IoChannelReady Setting
//
NdisReadConfiguration(
&status,
&returnedValue,
configHandle,
&IoChannelReadyString,
NdisParameterHexInteger);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_REQ(("Error, can't read transceiver type from registry...using AUTO\n"));
adapter->IoChannelReady = (CCHAR)4; // auto-detect is default
}
else
{
adapter->IoChannelReady = (CCHAR)(returnedValue->ParameterData.IntegerData);
}
//
// See if a MAC address has been specified in the registry to
// override our hardware-set one.
//
{
UINT addrLen;
PUCHAR netAddr;
NDIS_STATUS status;
//
// attempt to read the network address
//
NdisReadNetworkAddress(
&status,
&netAddr,
&addrLen,
configHandle);
// did the operation succeed?
//
if (status == NDIS_STATUS_SUCCESS)
{
adapter->UseDefaultAddress = FALSE;
// yes: use this address.
//
NdisMoveMemory(
&adapter->CurrentIndividualAddress,
netAddr,
EPRO_LENGTH_OF_ADDRESS);
}
else
{
// just use the one out of the eeprom
adapter->UseDefaultAddress = TRUE;
}
}
// Close the configuration file...
//
NdisCloseConfiguration(configHandle);
return(NDIS_STATUS_SUCCESS);
}
NDIS_STATUS EProInitialReset(PEPRO_ADAPTER adapter)
/*++
Routine Description:
This call really does two things: first, it calls
EProHWInitialize to set up the hardware, and then it
registers the card's interrupt and starts the card going.
Arguments:
adapter - pointer to our adapter structure...
Return Values:
--*/
{
NDIS_STATUS status;
status = EProHWInitialize(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("FAILED in EProHWInitialize.\n"));
return(status);
}
switch (adapter->IoChannelReady)
{
case EPRO_IOCHRDY_EARLY:
EPRO_DPRINTF_INIT(("EPro configured for EARLY IoChannelReady\n"));
break;
case EPRO_IOCHRDY_LATE:
EPRO_DPRINTF_INIT(("EPro configured for LATE IoChannelReady\n"));
break;
case EPRO_IOCHRDY_NEVER:
// They've set this in the cpanel - force 8 bits
//
EPRO_DPRINTF_INIT(("EPro configured for NEVER IoChannelReady\n"));
adapter->Use8Bit = TRUE;
break;
case EPRO_IOCHRDY_AUTO:
default:
EPRO_DPRINTF_INIT(("EPro configured for AUTO IoChannelReady\n"));
if (adapter->EProStepping < 4) //RM: don't do rev 4
{
if (!EProAltIOCHRDYTest(adapter))
{
EPRO_DPRINTF_INIT(("EPro failed the IOCHRDY test. Forcing 8-bit operation\n"));
// configure for 8-bit operation
//
EPRO_DPRINTF_INIT(("EPro configured for NEVER IoChannelReady\n"));
adapter->Use8Bit = TRUE;
}
}
break;
}
return(status);
}
NDIS_STATUS
EProHWInitialize(
IN PEPRO_ADAPTER adapter
)
/*++
Routine Description:
Now we start dealing with the card. Probe and verify its
existence, try to power it up if necessary, init it, etc.
Arguments:
adapter - pointer to our adapter structure
Return Values:
--*/
{
UCHAR buf[4], fExecDone, result, intReg;
UINT i;
// Make sure we're in bank 0
//
EPRO_SWITCH_BANK_0(adapter);
for (i = 0; i < 4; i++)
{
EPRO_RD_PORT_UCHAR(adapter, I82595_ID_REG, &buf[i]);
}
if (!EProVerifyRoundRobin(buf))
{
//
// hmm, didn't find the board. Try powering it up, then try again.
// It's concievable that the board was in its "powered down" state
// and so we try the powerup procedure as a last-ditch effort.
//
EPRO_DPRINTF_INIT(("Initial probe failing. Attempting to power board up.\n"));
if (!EProPowerupBoard(adapter))
{
EPRO_DPRINTF_INIT(("Couldn't power board up. Can't find board.\n"));
return(NDIS_STATUS_HARD_ERRORS);
}
}
// Do a full reset.
//
EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_FULL_RESET);
// poll for the card to be done it's init sequence.
//
for (i = 0; i < 10000; i++)
{
EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &intReg);
if (intReg & I82595_EXEC_INT_RCVD)
break;
NdisStallExecution(10);
}
if (i >= 10000)
{
EPRO_DPRINTF_INIT(("EPRO: Did NOT get return from init....\n"));
return(NDIS_STATUS_SOFT_ERRORS);
}
// According to the docs, writing a _1_ to the execution int bit
// clears it -- so we can just overwrite it to clear it.
//
EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, intReg);
return(NDIS_STATUS_SUCCESS);
}
NDIS_STATUS
EProHWConfigure(
IN PEPRO_ADAPTER adapter
)
/*++
Routine Description:
The second half of the init -- now the hardware has just been
told to reset. Wait for the reset to finish, then configure
the board...
Arguments:
adapter - pointer to our adapter structure
Return Values:
--*/
{
UCHAR result, intReg;
NDIS_STATUS status;
UINT i;
UCHAR intMask;
EPRO_DPRINTF_INIT(("EPRO: In EProHWConfigure\n"));
//
// Configure the adapter
//
EPRO_SWITCH_BANK_0(adapter);
//
// These two lines are a blatant hack to get around some timing
// problems I was having in the init sequence.
//
EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &result);
NdisStallExecution(1000);
if (!EProWaitForExeDma(adapter))
{
return(NDIS_STATUS_HARD_ERRORS);
}
// Set the 82595's config registers up for the driver.
// RM: Moved this up here so we have the chip version upfront.
//
// Switch to bank2 for configuration
//
EPRO_SWITCH_BANK_2(adapter);
//
// Get 82595 chip version.
//
EPRO_RD_PORT_UCHAR(adapter, I82595_STEPPING_REG, &result);
adapter->EProStepping = (result >> I82595_STEPPING_OFFSET);
EPRO_DPRINTF_INIT(("This is a level %x 82595\n", adapter->EProStepping));
if (adapter->EProStepping < 2)
{
adapter->EProUse32BitIO = FALSE;
EPRO_DPRINTF_INIT(("NOT using 32-bit I/O port.\n"));
}
else if (adapter->EProStepping > 4) //RM: included rev 4
{
//
// We don't support this step of the adapter!
//
EPRO_DPRINTF_INIT(("Do not support step %u epro's\n", adapter->EProStepping));
return(NDIS_STATUS_HARD_ERRORS);
}
else
{
//
// Step is 2, 3 or 4.
//
adapter->EProUse32BitIO = TRUE;
EPRO_DPRINTF_INIT(("using 32-bit I/O port.\n"));
}
//
// Set configuration register 1 in bank 2
//
EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG1_REG, EPRO_CONFIG_1);
//
// Set the transceiver type...
//
EPRO_DPRINTF_INIT(("EPRO: Transceiver type is 0x%x\n",
adapter->TransceiverType));
switch (adapter->TransceiverType)
{
case 1:
result = EPRO_CONFIG_3_AUI;
break;
case 2:
result = EPRO_CONFIG_3_BNC;
break;
case 3:
result = EPRO_CONFIG_3_TPE;
break;
case 4:
default:
result = EPRO_CONFIG_3_AUTO;
break;
}
EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG2_REG, EPRO_CONFIG_2);
EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG3_REG, result);
//
// Switch to Bank1
//
EPRO_SWITCH_BANK_1(adapter);
if (adapter->EProStepping < 4) //Alt Ready timing reg n/a in rev 4 --
// included in EEPROM for back-compat only
{
//
// Configure the card's IOCHRDY setting if we're forcing it
//
if (adapter->IoChannelReady == EPRO_IOCHRDY_EARLY)
{
//
// force EARLY (alternate) timing
//
EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result);
result |= I82595_ALT_IOCHRDY;
EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result);
}
//
// Configure the card's IOCHRDY setting if we're forcing it
//
if (adapter->IoChannelReady == EPRO_IOCHRDY_LATE)
{
//
// Force LATE (isa compatible) timing
//
EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result);
result &= ~I82595_ALT_IOCHRDY;
EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result);
}
}
//
// Do we have to use 8-bit?
//
if (adapter->Use8Bit)
{
EPRO_DPRINTF_INIT(("Using 8 bits\n"));
EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result);
result &= ~I82595_USE_8_BIT_FLAG;
EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result);
}
//
// Set the buffer limit registers...
//
EPRO_WR_PORT_UCHAR(adapter, I82595_TX_LOWER_LIMIT_REG, EPRO_TX_LOWER_LIMIT);
EPRO_WR_PORT_UCHAR(adapter, I82595_TX_UPPER_LIMIT_REG, EPRO_TX_UPPER_LIMIT);
EPRO_WR_PORT_UCHAR(adapter, I82595_RX_LOWER_LIMIT_REG, EPRO_RX_LOWER_LIMIT);
EPRO_WR_PORT_UCHAR(adapter, I82595_RX_UPPER_LIMIT_REG, EPRO_RX_UPPER_LIMIT);
//
// Tell the card what Interrupt to use, default to 5. RM: Added check for V4.
// Default bad IRQs to 5 (mask 2 for all steppings).
//
switch (adapter->InterruptNumber)
{
case 3:
intMask = (adapter->EProStepping == 4)? 0x0 : 0x1;
break;
case 4:
intMask = (adapter->EProStepping == 4)? 0x1 : 0x2;
break;
case 5:
intMask = 0x2;
break;
case 7:
intMask = (adapter->EProStepping == 4)? 0x3 : 0x2;
break;
case 9:
//
// note that this is out of order - because the epro
// uses the 0 to indicate 2/9 (2 on an 8-bit bus in DOS mode
// and 9 otherwise...or something like that) Anyways, it is
// 9 under NT.
//
intMask = (adapter->EProStepping == 4)? 0x4 : 0x0;
break;
case 10:
intMask = (adapter->EProStepping == 4)? 0x5 : 0x3;
break;
case 11:
intMask = (adapter->EProStepping == 4)? 0x6 : 0x4;
break;
case 12:
intMask = (adapter->EProStepping == 4)? 0x7 : 0x2;
break;
default:
EPRO_DPRINTF_INIT(("EPRO: invalid interrupt selected using interrupt 5."));
intMask = 0x2;
break;
}
EPRO_RD_PORT_UCHAR(adapter, I82595_INT_SELECT_REG, &result);
result &= ~(I82595_INTERRUPT_SELECT_MASK);
result |= intMask;
EPRO_WR_PORT_UCHAR(adapter, I82595_INT_SELECT_REG, result);
//
// Read the card's ethernet address out of the eeprom.
//
if (!EProCardReadEthernetAddress(adapter))
{
EPRO_DPRINTF_INIT(("EPRO: Could not read the EPro card's ethernet address.\n"));
return(NDIS_STATUS_SOFT_ERRORS);
}
if (adapter->UseDefaultAddress == TRUE)
{
//
// Copy the permanent address to the current address
//
NdisMoveMemory(
&adapter->CurrentIndividualAddress,
&adapter->PermanentIndividualAddress,
EPRO_LENGTH_OF_ADDRESS);
}
//
// Set the card's ethernet address to the one specified in
// adapter->current...
//
if (!EProSetEthernetAddress(adapter))
{
return(NDIS_STATUS_SOFT_ERRORS);
}
EPRO_SWITCH_BANK_1(adapter);
//
// flip the interrupt tri-state bit...
//
EPRO_RD_PORT_UCHAR(adapter, I82595_INTENABLE_REG, &result);
result|=I82595_ENABLE_INTS_FLAG;
EPRO_WR_PORT_UCHAR(adapter, I82595_INTENABLE_REG, result);
EPRO_SWITCH_BANK_0(adapter);
if (!EProWaitForExeDma(adapter))
{
return(NDIS_STATUS_SOFT_ERRORS);
}
//
// bank0
//
EPRO_SWITCH_BANK_0(adapter);
//
// Set the interrupt mask...
//
adapter->CurrentInterruptMask = EPRO_DEFAULT_INTERRUPTS;
//
// Register the interrupt.
//
status = NdisMRegisterInterrupt(
&adapter->Interrupt,
adapter->MiniportAdapterHandle,
adapter->InterruptNumber,
adapter->InterruptNumber,
FALSE,
FALSE,
NdisInterruptLatched);
if (status != NDIS_STATUS_SUCCESS)
{
EPRO_DPRINTF_INIT(("Register Interrupts FAILED\n"));
return(status);
}
//
// Enable interrupts...
//
EProEnableInterrupts((NDIS_HANDLE)adapter);
EProSelReset(adapter);
EPRO_DPRINTF_INIT(("EtherExpress Pro: configuration complete\n"));
return(NDIS_STATUS_SUCCESS);
}
BOOLEAN
EProVerifyRoundRobin(
IN UCHAR *buf
)
/*++
Routine Description:
This routine takes a sequence of 4 bytes passed in as the
result of 4 consecutive reads from the possible card's register
at address 2 (ie if base port is 0x300, 4 reads from 0x302) and
determines if the four constitute the EPro's ID signature. If they
do (epro identified) this returns TRUE, otherwise FALSE.
The 7th and 8th bits of these 4 should count 00 01 10 11 or some
permutation....
NOTE - if this code changes (because of chip updates, whatever) make
sure you change this function in the net-detection code (this function
is cut-and-pasted into detepro.c)
Arguments:
buf - a 4-byte character array with the four results in it...
Return Values:
TRUE if this is the 82595's signature
FALSE if it is not.
--*/
{
UCHAR ch;
int i, i1;
// Don't even bother. This works, take my word for it.
//
i1 = buf[0] >> 6;
for (i = 1; i < 4; i++)
{
i1 = (i1 > 2) ? 0 : i1 + 1;
if ((buf[i] >> 6) != i1)
{
return(FALSE);
}
}
return(TRUE);
}
BOOLEAN
EProPowerupBoard(
IN PEPRO_ADAPTER adapter
)
/*++
Routine Description:
The 82595 has a "powered down" state which could be why it didn't
respond correctly to the ID register probe.
Try the power up sequence. Return TRUE if the board responds
after the sequence, FALSE otherwise.
Arguments:
adapter - pointer to our adapter structure
Return Values:
TRUE - if the board was found after the power up sequence
FALSE - if it was not
--*/
{
UCHAR buf[4];
UINT i;
EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, 0);
// 32ms
//
NdisStallExecution(32000);
// Make sure we're in bank 0
//
EPRO_SWITCH_BANK_0(adapter);
for (i = 0; i < 4; i++)
{
EPRO_RD_PORT_UCHAR(adapter, I82595_ID_REG, &buf[i]);
}
return(EProVerifyRoundRobin(buf));
}
BOOLEAN
EProCardReadEthernetAddress(
IN PEPRO_ADAPTER adapter
)
{
USHORT data;
// EPRO_DPRINTF_INIT(("EProReadEthernetAddress\n"));
#ifdef EPRO_DUMP_EEPROM
// Dump the eeprom...
{
USHORT i;
for (i = 0; i < 64; i++)
{
if ((i % 16) == 0)
{
DbgPrint("\n");
}
EProEERead(adapter, i, &data);
DbgPrint("%x ", data);
}
DbgPrint("\n");
}
#endif
//
// Read the ethernet address out of the card. Also swap endian
// as you do it...
//
EProEERead(adapter, EPRO_ETHERNET_ADDR_H, &data);
adapter->PermanentIndividualAddress[4] = (UCHAR)(data >> 8);
adapter->PermanentIndividualAddress[5] = (UCHAR)(data & 0x00ff);
EProEERead(adapter, EPRO_ETHERNET_ADDR_M, &data);
adapter->PermanentIndividualAddress[2] = (UCHAR)(data >> 8);
adapter->PermanentIndividualAddress[3] = (UCHAR)(data & 0x00ff);
EProEERead(adapter, EPRO_ETHERNET_ADDR_L, &data);
adapter->PermanentIndividualAddress[0] = (UCHAR)(data >> 8);
adapter->PermanentIndividualAddress[1] = (UCHAR)(data & 0x00ff);
EPRO_DPRINTF_INIT(("MAC address read: %x %x %x %x %x %x\n",
adapter->PermanentIndividualAddress[0],
adapter->PermanentIndividualAddress[1],
adapter->PermanentIndividualAddress[2],
adapter->PermanentIndividualAddress[3],
adapter->PermanentIndividualAddress[4],
adapter->PermanentIndividualAddress[5]));
return(TRUE);
}
BOOLEAN EProSetEthernetAddress(PEPRO_ADAPTER adapter)
/*++
Routine Description:
The EPro's ethernet address is read out of the EEPROM by the driver
in EProReadEthernetAddress. It is stored by the driver in the
adapter->PermanentIndividualAddress array. This function takes the
address stored there (presumably set by ReadEthernetAddress) and
configures the board to use that address. It could also be used
to software-override the default ethernet address.
Note that the software does not support multiple IA addresses
(multiple non-multicast addresses) although the hardware does.
Arguments:
adapter - pointer to our adapter structure
Return Value:
TRUE if the operation was successful
FALSE if it failed
--*/
{
UCHAR result;
UINT i = 0;
// switch to bank2
EPRO_SWITCH_BANK_2(adapter);
// write out the ethernet address. Make sure you write to reg 9 last:
EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_0, adapter->PermanentIndividualAddress[0]);
EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_1, adapter->PermanentIndividualAddress[1]);
EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_2, adapter->PermanentIndividualAddress[2]);
EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_3, adapter->PermanentIndividualAddress[3]);
EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_4, adapter->PermanentIndividualAddress[4]);
// switch to bank0
EPRO_SWITCH_BANK_0(adapter);
if (!EProWaitForExeDma(adapter)) {
return(FALSE);
}
// switch to bank2
EPRO_SWITCH_BANK_2(adapter);
EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_5, adapter->PermanentIndividualAddress[5]);
return(TRUE);
}
BOOLEAN EProAltIOCHRDYTest(PEPRO_ADAPTER adapter)
/*++
Routine Description:
Check the current IOCHRDY timing and see if it is compatible.
if not, see if it can be changed and made compatible
otherwise fail.
Arguments:
adapter - pointer to our adapter structure
Return Values:
TRUE if the card can be configured properly to the way the machine
machine asserts the IOCHRDY line.
FALSE if the card could NOT be configured appropriately - the machine
is broken and we'll have to use 8-bit mode.
--*/
{
BOOLEAN testPending = TRUE, testResult, firstTime = TRUE;
UCHAR result;
// switch to bank 1
EPRO_SWITCH_BANK_1(adapter);
do
{
// Enter test mode...
EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result);
result |= I82595_IOCHRDY_TEST_FLAG;
EPRO_WR_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, result);
// Read from 0,1
EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &result);
EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result);
if (result & I82595_IOCHRDY_PASS_FLAG)
{
testPending = FALSE;
testResult = TRUE;
}
else
{
// test failed
if (firstTime)
{
// try it again - flip the current IOCHRDY timing and try again.
firstTime = FALSE;
EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result);
// toggle alt-rdy bit
result = (result & I82595_ALT_RDY_FLAG)?
result & (~I82595_ALT_RDY_FLAG) :
result | I82595_ALT_RDY_FLAG;
EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result);
}
else
{
// nope, failed twice, can't do it.
testPending = FALSE;
testResult = FALSE;
}
}
} while (testPending);
// turn the test off
EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result);
result &= ~I82595_IOCHRDY_TEST_FLAG;
EPRO_WR_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, result);
return(testResult);
}