diff options
Diffstat (limited to 'private/ntos/ndis/ne3200/reset.c')
-rw-r--r-- | private/ntos/ndis/ne3200/reset.c | 1805 |
1 files changed, 1805 insertions, 0 deletions
diff --git a/private/ntos/ndis/ne3200/reset.c b/private/ntos/ndis/ne3200/reset.c new file mode 100644 index 000000000..1da22a03e --- /dev/null +++ b/private/ntos/ndis/ne3200/reset.c @@ -0,0 +1,1805 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + reset.c + +Abstract: + + This is the file containing the reset code for the Novell NE3200 EISA + Ethernet adapter. This driver conforms to the NDIS 3.0 miniport + interface. + +Author: + + Keith Moore (KeithMo) 08-Jan-1991 + +Environment: + +Revision History: + +--*/ + +#include <ne3200sw.h> + +// +// Global information stored in ne3200.c. This is used for +// getting at the download software +// +extern NE3200_GLOBAL_DATA NE3200Globals; + +// +// Forward declarations of functions in this file +// +extern +VOID +NE3200ProcessRequestQueue( + IN PNE3200_ADAPTER Adapter, + IN BOOLEAN StatisticsUpdated + ); + +STATIC +VOID +NE3200SetConfigurationBlock( + IN PNE3200_ADAPTER Adapter + ); + +STATIC +BOOLEAN +NE3200SetConfigurationBlockAndInit( + IN PNE3200_ADAPTER Adapter + ); + +NDIS_STATUS +NE3200ChangeCurrentAddress( + IN PNE3200_ADAPTER Adapter + ); + +VOID +NE3200ResetCommandBlocks( + IN PNE3200_ADAPTER Adapter + ); + +extern +VOID +NE3200GetStationAddress( + IN PNE3200_ADAPTER Adapter + ); + +extern +VOID +NE3200SetupForReset( + IN PNE3200_ADAPTER Adapter + ); + +STATIC +VOID +NE3200DoResetIndications( + IN PNE3200_ADAPTER Adapter, + IN NDIS_STATUS Status + ); + +VOID +NE3200ResetHandler( + IN PVOID SystemSpecific1, + IN PNE3200_ADAPTER Adapter, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +BOOLEAN +NE3200InitialInit( + IN PNE3200_ADAPTER Adapter, + IN UINT NE3200InterruptVector, + IN NDIS_INTERRUPT_MODE NE3200InterruptMode + ); + + +#pragma NDIS_INIT_FUNCTION(NE3200InitialInit) + +BOOLEAN +NE3200InitialInit( + IN PNE3200_ADAPTER Adapter, + IN UINT NE3200InterruptVector, + IN NDIS_INTERRUPT_MODE NE3200InterruptMode + ) + +/*++ + +Routine Description: + + This routine sets up the initial init of the driver, by + stopping the adapter, connecting the interrupt and initializing + the adapter. + +Arguments: + + Adapter - The adapter for the hardware. + +Return Value: + + TRUE if the initialization succeeds, else FALSE. + +--*/ + +{ + // + // Status of NDIS calls + // + NDIS_STATUS Status; + + // + // First we make sure that the device is stopped. + // + NE3200StopChip(Adapter); + + // + // The ISR will set this to FALSE if we get an interrupt + // + Adapter->InitialInit = TRUE; + + // + // Initialize the interrupt. + // + Status = NdisMRegisterInterrupt( + &Adapter->Interrupt, + Adapter->MiniportAdapterHandle, + NE3200InterruptVector, + NE3200InterruptVector, + FALSE, + FALSE, + NE3200InterruptMode + ); + + // + // So far so good + // + if (Status == NDIS_STATUS_SUCCESS) { + + // + // Now try to initialize the adapter + // + if (!NE3200SetConfigurationBlockAndInit(Adapter)) { + + // + // Failed. Write out an error log entry. + // + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_TIMEOUT, + 2, + initialInit, + NE3200_ERRMSG_NO_DELAY + ); + + // + // Unhook the interrupt + // + NdisMDeregisterInterrupt(&Adapter->Interrupt); + + Adapter->InitialInit = FALSE; + + return FALSE; + + } + + // + // Get hardware assigned network address. + // + NE3200GetStationAddress( + Adapter + ); + + // + // We can start the chip. We may not + // have any bindings to indicate to but this + // is unimportant. + // + Status = NE3200ChangeCurrentAddress(Adapter); + + Adapter->InitialInit = FALSE; + + return(Status == NDIS_STATUS_SUCCESS); + + } else { + + // + // Interrupt line appears to be taken. Notify user. + // + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_INTERRUPT_CONNECT, + 2, + initialInit, + NE3200_ERRMSG_INIT_INTERRUPT + ); + + Adapter->InitialInit = FALSE; + + return(FALSE); + } + +} + +VOID +NE3200StartChipAndDisableInterrupts( + IN PNE3200_ADAPTER Adapter, + IN PNE3200_SUPER_RECEIVE_ENTRY FirstReceiveEntry + ) + +/*++ + +Routine Description: + + This routine is used to start an already initialized NE3200, + but to keep the interrupt line masked. + +Arguments: + + Adapter - The adapter for the NE3200 to start. + + FirstReceiveEntry - Pointer to the first receive entry to be + used by the adapter. + +Return Value: + + None. + +--*/ + +{ + + IF_LOG('%'); + + // + // Write the new receive pointer. + // + NE3200_WRITE_RECEIVE_POINTER( + Adapter, + NdisGetPhysicalAddressLow(FirstReceiveEntry->Self) + ); + + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + NE3200_LOCAL_DOORBELL_NEW_RECEIVE + ); + + // + // Initialize the doorbell & system interrupt masks + // + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + NE3200_SYSTEM_INTERRUPT_ENABLE + ); + + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATUS, + 0 + ); + +} + +VOID +NE3200EnableAdapter( + IN NDIS_HANDLE Context + ) + +/*++ + +Routine Description: + + This routine is used to start an already initialized NE3200. + +Arguments: + + Context - The adapter for the NE3200 to start. + +Return Value: + + None. + +--*/ + +{ + PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context; + + IF_LOG('#'); + + // + // Initialize the doorbell & system interrupt masks + // + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + NE3200_SYSTEM_INTERRUPT_ENABLE + ); + + if (!Adapter->InterruptsDisabled) { + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + NE3200_SYSTEM_DOORBELL_MASK + ); + } + + NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT( + Adapter, + NE3200_SYSTEM_DOORBELL_MASK + ); + + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATUS, + 0 + ); + +} + +VOID +NE3200EnableInterrupt( + IN NDIS_HANDLE Context + ) + +/*++ + +Routine Description: + + This routine is used to turn on the interrupt mask. + +Arguments: + + Context - The adapter for the NE3200 to start. + +Return Value: + + None. + +--*/ + +{ + PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context; + + IF_LOG('E'); + + // + // Enable further interrupts. + // + Adapter->InterruptsDisabled = FALSE; + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + NE3200_SYSTEM_DOORBELL_MASK + ); + +} + +VOID +NE3200DisableInterrupt( + IN NDIS_HANDLE Context + ) + +/*++ + +Routine Description: + + This routine is used to turn off the interrupt mask. + +Arguments: + + Context - The adapter for the NE3200 to start. + +Return Value: + + None. + +--*/ + +{ + PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context; + + // + // Initialize the doorbell mask + // + Adapter->InterruptsDisabled = TRUE; + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + IF_LOG('D'); +} + +VOID +NE3200StopChip( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to stop the NE3200. + +Arguments: + + Adapter - The NE3200 adapter to stop. + +Return Value: + + None. + +--*/ + +{ + + IF_LOG('h'); + + // + // Packet reception can be stopped by writing a + // (ULONG)-1 to the Receive Packet Mailbox port. + // Also, commands can be stopped by writing a -1 + // to the Command Pointer Mailbox port. + // + NE3200_WRITE_RECEIVE_POINTER( + Adapter, + NE3200_NULL + ); + + NE3200_WRITE_COMMAND_POINTER( + Adapter, + NE3200_NULL + ); + + // + // Ack any outstanding interrupts + // + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + NE3200_LOCAL_DOORBELL_NEW_RECEIVE | NE3200_LOCAL_DOORBELL_NEW_COMMAND + ); + + // + // Disable the doorbell & system interrupt masks. + // + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + 0 + ); + + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT( + Adapter, + 0 + ); + +} + +STATIC +VOID +NE3200SetConfigurationBlock( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine simply fills the configuration block + with the information necessary for initialization. + +Arguments: + + Adapter - The adapter which holds the initialization block + to initialize. + +Return Value: + + None. + + +--*/ + +{ + + PNE3200_CONFIGURATION_BLOCK Configuration; + + // + // Get the configuration block + // + Configuration = Adapter->ConfigurationBlock; + + // + // Initialize it to zero + // + NdisZeroMemory( + Configuration, + sizeof(NE3200_CONFIGURATION_BLOCK) + ); + + // + // Set up default values + // + Configuration->ByteCount = 12; + Configuration->FifoThreshold = 8; + Configuration->AddressLength = 6; + Configuration->SeparateAddressAndLength = 1; + Configuration->PreambleLength = 2; + Configuration->InterframeSpacing = 96; + Configuration->SlotTime = 512; + Configuration->MaximumRetries = 15; + Configuration->DisableBroadcast = 1; + Configuration->MinimumFrameLength = 64; + +} + +VOID +NE3200DoAdapterReset( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This is the resetting the adapter hardware. + + It makes the following assumptions: + + 1) That the hardware has been stopped. + + 2) That no other adapter activity can occur. + + When this routine is finished all of the adapter information + will be as if the driver was just initialized. + +Arguments: + + Adapter - The adapter whose hardware is to be reset. + +Return Value: + + not. + +--*/ +{ + + // + // Recover all of the adapter transmit merge buffers. + // + { + + UINT i; + + for ( + i = 0; + i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS; + i++ + ) { + + Adapter->NE3200Buffers[i].Next = i+1; + + } + + Adapter->NE3200BufferListHead = 0; + Adapter->NE3200Buffers[NE3200_NUMBER_OF_TRANSMIT_BUFFERS-1].Next = -1; + + } + + // + // Reset all state variables + // + NE3200ResetVariables(Adapter); + + // + // Recover all command blocks + // + NE3200ResetCommandBlocks(Adapter); + + // + // Initialize the adapter + // + NE3200SetConfigurationBlockAndInit(Adapter); + + +} + +STATIC +BOOLEAN +NE3200SetConfigurationBlockAndInit( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + It is this routine's responsibility to make sure that the + Configuration block is filled and the adapter is initialized + *but not* started. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + If ResetAsynchoronous is FALSE, then returns TRUE if reset successful, + FALSE if reset unsuccessful. + + If ResetAsynchoronous is TRUE, then always returns TRUE. + +--*/ +{ + + // + // Fill in the adapter's initialization block. + // + NE3200SetConfigurationBlock(Adapter); + + // + // Set the initial state for the ResetDpc state machine. + // + Adapter->ResetState = NE3200ResetStateStarting; + + // + // Go through the reset + // + NE3200ResetHandler(NULL, Adapter, NULL, NULL); + + // + // Is Synchronous resets, then check the final result + // + if (!Adapter->ResetAsynchronous) { + + return((Adapter->ResetResult == NE3200ResetResultSuccessful)); + + } else { + + return(TRUE); + + } + +} + +VOID +NE3200ResetHandler( + IN PVOID SystemSpecific1, + IN PNE3200_ADAPTER Adapter, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) + +/*++ + +Routine Description: + + This manages the reset/download process. It is + responsible for resetting the adapter, waiting for proper + status, downloading MAC.BIN, waiting for MAC.BIN initialization, + and optionally sending indications to the appropriate protocol. + + Since the NE3200's status registers must be polled during the + reset/download process, this is implemented as a state machine. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + None. + +--*/ +{ + + // + // Physical address of the MAC.BIN buffer. + // + NDIS_PHYSICAL_ADDRESS MacBinPhysicalAddress; + + // + // Status from the adapter. + // + UCHAR Status; + + // + // Simple iteration counter. + // + UINT i; + + // + // Loop until the reset has completed. + // + while (Adapter->ResetState != NE3200ResetStateComplete) { + + switch (Adapter->ResetState) { + + // + // The first stage of resetting an NE3200 + // + case NE3200ResetStateStarting : + + // + // Unfortunately, a hardware reset to the NE3200 does *not* + // reset the BMIC chip. To ensure that we read a proper status, + // we'll clear all of the BMIC's registers. + // + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + 0 + ); + + // + // I changed this to ff since the original 0 didn't work for + // some cases. since we don't have the specs.... + // + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + 0xff + ); + + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + NE3200_SYNC_CLEAR_SYSTEM_DOORBELL_INTERRUPT( + Adapter + ); + + for (i = 0 ; i < 16 ; i += 4 ) { + + NE3200_WRITE_MAILBOX_ULONG( + Adapter, + i, + 0L + ); + + } + + // + // Toggle the NE3200's reset line. + // + NE3200_WRITE_RESET( + Adapter, + NE3200_RESET_BIT_ON + ); + + NE3200_WRITE_RESET( + Adapter, + NE3200_RESET_BIT_OFF + ); + + // + // Switch to the next state. + // + Adapter->ResetState = NE3200ResetStateResetting; + Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_RESET; + + // + // Loop to the next processing + // + break; + + // + // Part Deux. The actual downloading of the software. + // + case NE3200ResetStateResetting : + + // + // Read the status mailbox. + // + NE3200_READ_MAILBOX_UCHAR(Adapter, NE3200_MAILBOX_RESET_STATUS, &Status); + + if (Status == NE3200_RESET_PASSED) { + + // + // We have good reset. Initiate the MAC.BIN download. + // + + // + // The station address for this adapter can be forced to + // a specific value at initialization time. When MAC.BIN + // first gets control, it reads mailbox 10. If this mailbox + // contains a 0xFF, then the burned-in PROM station address + // is used. If this mailbox contains any value other than + // 0xFF, then mailboxes 10-15 are read. The six bytes + // stored in these mailboxes then become the station address. + // + // Since we have no need for this feature, we will always + // initialize mailbox 10 with a 0xFF. + // + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID, + 0xFF + ); + + + // + // Get the MAC.BIN buffer. + // + MacBinPhysicalAddress = NE3200Globals.MacBinPhysicalAddress; + + // + // Download MAC.BIN to the card. + // + NE3200_WRITE_MAILBOX_USHORT( + Adapter, + NE3200_MAILBOX_MACBIN_LENGTH, + NE3200Globals.MacBinLength + ); + + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_MACBIN_DOWNLOAD_MODE, + NE3200_MACBIN_DIRECT + ); + + NE3200_WRITE_MAILBOX_ULONG( + Adapter, + NE3200_MAILBOX_MACBIN_POINTER, + NdisGetPhysicalAddressLow(MacBinPhysicalAddress) + ); + + NE3200_WRITE_MAILBOX_USHORT( + Adapter, + NE3200_MAILBOX_MACBIN_TARGET, + NE3200_MACBIN_TARGET_ADDRESS >> 1 + ); + + // + // This next OUT "kicks" the loader into action. + // + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_RESET_STATUS, + 0 + ); + + // + // Switch to the next state. + // + Adapter->ResetState = NE3200ResetStateDownloading; + Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_DOWNLOAD; + + // + // Loop to the next state. + // + + } else if (Status == NE3200_RESET_FAILED) { + + // + // Reset failure. Notify the authorities and + // next of kin. + // + Adapter->ResetResult = NE3200ResetResultResetFailure; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + // + // Still waiting for results, check if we have + // timed out waiting. + // + Adapter->ResetTimeoutCounter--; + + if (Adapter->ResetTimeoutCounter == 0) { + + // + // We've timed-out. Bad news. Notify the death. + // + Adapter->ResetResult = NE3200ResetResultResetTimeout; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + // + // For Synchronous resets, we stall. For async, + // we set a timer to check later. + // + if (!Adapter->ResetAsynchronous) { + + // + // Otherwise, wait and try again. + // + NdisStallExecution(10000); + + } else{ + + // + // Try again later. + // + NdisMSetTimer(&Adapter->ResetTimer, 100); + + return; + + } + + } + + } + + break; + + // + // Part Three: The download was started. Check for completion, + // and reload the current station address. + // + case NE3200ResetStateDownloading : + + // + // Read the download status. + // + NE3200_READ_MAILBOX_UCHAR(Adapter, NE3200_MAILBOX_STATUS, &Status); + + if (Status == NE3200_INITIALIZATION_PASSED) { + + // + // According to documentation from Compaq, this next port + // write will (in a future MAC.BIN) tell MAC.BIN whether or + // not to handle loopback internally. This value is currently + // not used, but must still be written to the port. + // + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATUS, + 1 + ); + + // + // Initialization is good, the card is ready. + // + NE3200StartChipAndDisableInterrupts(Adapter, + Adapter->ReceiveQueueHead + ); + + { + + // + // Do the work for updating the current address + // + + // + // This points to the public Command Block. + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // This points to the adapter's configuration block. + // + PNE3200_CONFIGURATION_BLOCK ConfigurationBlock = + Adapter->ConfigurationBlock; + + // + // Get a public command block. + // + NE3200AcquirePublicCommandBlock(Adapter, + &CommandBlock + ); + + Adapter->ResetHandlerCommandBlock = CommandBlock; + + // + // Setup the command block. + // + + CommandBlock->NextCommand = NULL; + + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = + NE3200_COMMAND_CONFIGURE_82586; + CommandBlock->Hardware.PARAMETERS.CONFIGURE.ConfigurationBlock = + NdisGetPhysicalAddressLow(Adapter->ConfigurationBlockPhysical); + + // + // Now that we've got the command block built, + // let's do it! + // + NE3200SubmitCommandBlock(Adapter, CommandBlock); + + Adapter->ResetState = NE3200ResetStateReloadAddress; + Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_DOWNLOAD; + + } + + } else if (Status == NE3200_INITIALIZATION_FAILED) { + + // + // Initialization failed. Notify the wrapper. + // + Adapter->ResetResult = NE3200ResetResultInitializationFailure; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + // + // See if we've timed-out waiting for the download to + // complete. + // + Adapter->ResetTimeoutCounter--; + + if (Adapter->ResetTimeoutCounter == 0) { + + // + // We've timed-out. Bad news. + // + Adapter->ResetResult = NE3200ResetResultInitializationTimeout; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + // + // For Synchronous resets, we stall. For async, + // we set a timer to check later. + // + if (!Adapter->ResetAsynchronous) { + + // + // Otherwise, wait and try again. + // + NdisStallExecution(10000); + + } else{ + + // + // Try again later. + // + NdisMSetTimer(&Adapter->ResetTimer, 100); + return; + + } + + } + + } + + break; + + // + // Part Last: Waiting for the configuring of the adapter + // to complete + // + case NE3200ResetStateReloadAddress : + + // + // Read the command block status. + // + if (Adapter->ResetHandlerCommandBlock->Hardware.State == + NE3200_STATE_EXECUTION_COMPLETE) { + + // + // return this command block + // + NE3200RelinquishCommandBlock(Adapter, + Adapter->ResetHandlerCommandBlock + ); + + // + // Reset is complete. Do those indications. + // + Adapter->ResetResult = NE3200ResetResultSuccessful; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_SUCCESS); + + } else { + + // + // See if we've timed-out. + // + Adapter->ResetTimeoutCounter--; + + if (Adapter->ResetTimeoutCounter == 0) { + + // + // We've timed-out. Bad news. + // + + // + // return this command block + // + NE3200RelinquishCommandBlock(Adapter, + Adapter->ResetHandlerCommandBlock + ); + + Adapter->ResetResult = NE3200ResetResultInitializationTimeout; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + if ( Adapter->ResetTimeoutCounter == + (NE3200_TIMEOUT_DOWNLOAD/2) ) { + + // + // The command may have stalled, try again. + // + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + NE3200_LOCAL_DOORBELL_NEW_COMMAND + ); + + } + + // + // For Synchronous resets, we stall. For async, + // we set a timer to check later. + // + if (!Adapter->ResetAsynchronous) { + + // + // Otherwise, wait and try again. + // + NdisStallExecution(10000); + + } else{ + + // + // Check again later + // + NdisMSetTimer(&Adapter->ResetTimer, 100); + return; + + } + + } + + } + + break; + + default : + + // + // Somehow, we reached an invalid state. + // + + // + // We'll try to salvage our way out of this. + // + Adapter->ResetResult = NE3200ResetResultInvalidState; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 3, + resetDpc, + NE3200_ERRMSG_BAD_STATE, + (ULONG)(Adapter->ResetState) + ); + + break; + } + + } + +} + +STATIC +VOID +NE3200DoResetIndications( + IN PNE3200_ADAPTER Adapter, + IN NDIS_STATUS Status + ) + +/*++ + +Routine Description: + + This routine is called by NE3200ResetHandler to perform any + indications which need to be done after a reset. Note that + this routine will be called after either a successful reset + or a failed reset. + +Arguments: + + Adapter - The adapter whose hardware has been initialized. + + Status - The status of the reset to send to the protocol(s). + +Return Value: + + None. + +--*/ +{ + // + // Re-start the card if the reset was successful, else stop it. + // + if (Status == NDIS_STATUS_SUCCESS) { + + NdisMSynchronizeWithInterrupt( + &(Adapter->Interrupt), + NE3200EnableAdapter, + (PVOID)(Adapter) + ); + + } else { + + // + // Reset has failed. + // + + NE3200StopChip(Adapter); + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 0 + ); + } + + // + // Setup the network address. + // + NE3200ChangeCurrentAddress(Adapter); + + Adapter->ResetInProgress = FALSE; + + // + // Reset default reset method + // + Adapter->ResetAsynchronous = FALSE; + + if (!Adapter->InitialInit) { + + // + // Signal the end of the reset + // + NdisMResetComplete( + Adapter->MiniportAdapterHandle, + Status, + TRUE + ); + + } + +} + +extern +VOID +NE3200SetupForReset( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to fill in the who and why a reset is + being set up as well as setting the appropriate fields in the + adapter. + + NOTE: This routine must be called with the lock acquired. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + None. + +--*/ +{ + // + // Ndis buffer mapped + // + PNDIS_BUFFER CurrentBuffer; + + // + // Map register that was used + // + UINT CurMapRegister; + + // + // Packet to abort + // + PNDIS_PACKET Packet; + + // + // Reserved portion of the packet. + // + PNE3200_RESERVED Reserved; + + // + // Pointer to command block being processed. + // + PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->FirstCommandOnCard; + + + + Adapter->ResetInProgress = TRUE; + + // + // Shut down the chip. We won't be doing any more work until + // the reset is complete. + // + NE3200StopChip(Adapter); + + // + // Un-map all outstanding transmits + // + while (CurrentCommandBlock != NULL) { + + if (CurrentCommandBlock->Hardware.CommandCode == NE3200_COMMAND_TRANSMIT) { + + // + // Remove first packet from the queue + // + Packet = CurrentCommandBlock->OwningPacket; + Reserved = PNE3200_RESERVED_FROM_PACKET(Packet); + + if (Reserved->UsedNE3200Buffer) { + goto GetNextCommandBlock; + } + + // + // The transmit is finished, so we can release + // the physical mapping used for it. + // + NdisQueryPacket( + Packet, + NULL, + NULL, + &CurrentBuffer, + NULL + ); + + // + // Get starting map register + // + CurMapRegister = Reserved->CommandBlockIndex * + NE3200_MAXIMUM_BLOCKS_PER_PACKET; + + // + // For each buffer + // + while (CurrentBuffer) { + + // + // Finish the mapping + // + NdisMCompleteBufferPhysicalMapping( + Adapter->MiniportAdapterHandle, + CurrentBuffer, + CurMapRegister + ); + + ++CurMapRegister; + + NdisGetNextBuffer( + CurrentBuffer, + &CurrentBuffer + ); + + } + + } + +GetNextCommandBlock: + + CurrentCommandBlock = CurrentCommandBlock->NextCommand; + + // + // Now do the pending queue + // + if (CurrentCommandBlock == NULL) { + + if (Adapter->FirstWaitingCommand != NULL) { + + CurrentCommandBlock = Adapter->FirstWaitingCommand; + Adapter->FirstWaitingCommand = NULL; + + } + + } + + } + +} + + +#pragma NDIS_INIT_FUNCTION(NE3200GetStationAddress) + +VOID +NE3200GetStationAddress( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine gets the network address from the hardware. + + NOTE: This routine assumes that it is called *immediately* + after MAC.BIN has been downloaded. It should only be called + immediately after SetConfigurationBlockAndInit() has completed. + +Arguments: + + Adapter - Where to store the network address. + +Return Value: + + None. + +--*/ + +{ + // + // Read the station address from the ports + // + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID, + &Adapter->NetworkAddress[0] + ); + + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID + 1, + &Adapter->NetworkAddress[1] + ); + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID + 2, + &Adapter->NetworkAddress[2] + ); + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID + 3, + &Adapter->NetworkAddress[3] + ); + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID + 4, + &Adapter->NetworkAddress[4] + ); + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID +5, + &Adapter->NetworkAddress[5] + ); + + if (!Adapter->AddressChanged) { + + // + // Copy the real address to be used as the current address. + // + NdisMoveMemory( + Adapter->CurrentAddress, + Adapter->NetworkAddress, + NE3200_LENGTH_OF_ADDRESS + ); + + } + +} + + +VOID +NE3200ResetVariables( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine sets variables to their proper value after a reset. + +Arguments: + + Adapter - Adapter we are resetting. + +Return Value: + + None. + +--*/ + +{ + // + // Clear the command queues + // + Adapter->FirstCommandOnCard = NULL; + Adapter->FirstWaitingCommand = NULL; + + // + // Reset the receive buffer ring + // + Adapter->ReceiveQueueHead = Adapter->ReceiveQueue; + Adapter->ReceiveQueueTail = + Adapter->ReceiveQueue + Adapter->NumberOfReceiveBuffers - 1; + + // + // Reset count of available command blocks + // + Adapter->NumberOfAvailableCommandBlocks = Adapter->NumberOfCommandBlocks; + Adapter->NumberOfPublicCommandBlocks = NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS; + Adapter->NextPublicCommandBlock = 0; + Adapter->NextCommandBlock = Adapter->CommandQueue; + + // + // Reset transmitting and receiving states + // + Adapter->PacketResubmission = FALSE; + Adapter->TransmitsQueued = 0; + Adapter->CurrentReceiveIndex = 0; + +} + +VOID +NE3200ResetCommandBlocks( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine sets command block elementsto their proper value after a reset. + +Arguments: + + Adapter - Adapter we are resetting. + +Return Value: + + None. + +--*/ + +{ + // + // Pointer to a Receive Entry. Used while initializing + // the Receive Queue. + // + PNE3200_SUPER_RECEIVE_ENTRY CurrentReceiveEntry; + + // + // Pointer to a Command Block. Used while initializing + // the Command Queue. + // + PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock; + + // + // Simple iteration variable. + // + UINT i; + + // + // Put the Command Blocks into a known state. + // + for( + i = 0, CurrentCommandBlock = Adapter->CommandQueue; + i < Adapter->NumberOfCommandBlocks; + i++, CurrentCommandBlock++ + ) { + + CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE; + CurrentCommandBlock->Hardware.NextPending = NE3200_NULL; + + CurrentCommandBlock->NextCommand = NULL; + CurrentCommandBlock->AvailableCommandBlockCounter = + &Adapter->NumberOfAvailableCommandBlocks; + CurrentCommandBlock->Timeout = FALSE; + } + + // + // Now do the same for the public command queue. + // + for( + i = 0, CurrentCommandBlock = Adapter->PublicCommandQueue; + i < NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS; + i++, CurrentCommandBlock++ + ) { + + CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE; + CurrentCommandBlock->Hardware.NextPending = NE3200_NULL; + CurrentCommandBlock->NextCommand = NULL; + CurrentCommandBlock->AvailableCommandBlockCounter = + &Adapter->NumberOfPublicCommandBlocks; + CurrentCommandBlock->CommandBlockIndex = (USHORT)i; + CurrentCommandBlock->Timeout = FALSE; + } + + // + // Reset the receive buffers. + // + for( + i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue; + i < Adapter->NumberOfReceiveBuffers; + i++, CurrentReceiveEntry++ + ) { + + + // + // Initialize receive buffers + // + CurrentReceiveEntry->Hardware.State = NE3200_STATE_FREE; + CurrentReceiveEntry->Hardware.NextPending = + NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) + + (i + 1) * sizeof(NE3200_SUPER_RECEIVE_ENTRY); + CurrentReceiveEntry->NextEntry = CurrentReceiveEntry + 1; + + } + + // + // Make sure the last entry is properly terminated. + // + (CurrentReceiveEntry - 1)->Hardware.NextPending = NE3200_NULL; + (CurrentReceiveEntry - 1)->NextEntry = Adapter->ReceiveQueue; + +} + + +NDIS_STATUS +NE3200ChangeCurrentAddress( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to modify the card address. + +Arguments: + + Adapter - The adapter for the NE3200 to change address. + +Return Value: + + NDIS_STATUS_SUCCESS, if everything went ok + NDIS_STATUS_FAILURE, otherwise + +--*/ +{ + + // + // Modify the card address if needed + // + + if (Adapter->AddressChanged) { + + // + // The command block for submitting the change + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // Temporary looping variable + // + UINT i; + + // + // Get a public command block for the request + // + NE3200AcquirePublicCommandBlock(Adapter, + &CommandBlock + ); + + // + // Setup the command block. + // + CommandBlock->NextCommand = NULL; + + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = NE3200_COMMAND_SET_STATION_ADDRESS; + + // + // Copy in the address + // + NdisMoveMemory( + CommandBlock->Hardware.PARAMETERS.SET_ADDRESS.NewStationAddress, + Adapter->CurrentAddress, + NE3200_LENGTH_OF_ADDRESS + ); + + // + // Now that we've got the command block built, + // let's do it! + // + NE3200SubmitCommandBlock(Adapter, CommandBlock); + + // + // Wait for the command block to finish + // + for (i = 0; i < 100000; i++) { + NdisStallExecution(100); + if (CommandBlock->Hardware.State == NE3200_STATE_EXECUTION_COMPLETE) { + break; + } + } + + // + // Check the status of the command. + // + if (CommandBlock->Hardware.State != NE3200_STATE_EXECUTION_COMPLETE) { + + // + // Failed + // + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 0 + ); + + return NDIS_STATUS_FAILURE; + + } + + // + // return this command block + // + NE3200RelinquishCommandBlock(Adapter, CommandBlock); + + } + return NDIS_STATUS_SUCCESS; +} + +BOOLEAN +SyncNE3200ClearDoorbellInterrupt( + IN PVOID SyncContext + ) +/*++ + +Routine Description: + + Clears the Doorbell Interrupt Port. + +Arguments: + + SyncContext - pointer to the adapter block + +Return Value: + + Always TRUE + +--*/ + +{ + + PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)SyncContext; + + // + // Clear the value + // + NdisRawWritePortUchar( + (ULONG)(Adapter->SystemDoorbellInterruptPort), + (UCHAR)0 + ); + + return(FALSE); +} + |