diff options
Diffstat (limited to 'private/ntos/ndis/ieepro/init.c')
-rw-r--r-- | private/ntos/ndis/ieepro/init.c | 1418 |
1 files changed, 1418 insertions, 0 deletions
diff --git a/private/ntos/ndis/ieepro/init.c b/private/ntos/ndis/ieepro/init.c new file mode 100644 index 000000000..b94ae0e02 --- /dev/null +++ b/private/ntos/ndis/ieepro/init.c @@ -0,0 +1,1418 @@ +#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, ®0); + EProEERead(adapter, EPRO_EEPROM_CONFIG1_OFFSET, ®1); + + // + // 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); +} + |