mirror of https://github.com/lianthony/NT4.0
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.
1805 lines
42 KiB
1805 lines
42 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
|