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

2800 lines
65 KiB

/*++
Copyright (c) 1990-1992 Microsoft Corporation
Module Name:
sonic.c
Abstract:
This is the main file for the National Semiconductor SONIC
Ethernet controller. This driver conforms to the NDIS 3.0
miniport interface.
Author:
Adam Barr (adamba) 14-Nov-1990
Environment:
Kernel Mode - Or whatever is the equivalent.
Revision History:
--*/
#include <ndis.h>
#include <sonichrd.h>
#include <sonicsft.h>
//
// This variable is used to control debug output.
//
#if DBG
INT SonicDbg = 0;
#endif
STATIC
VOID
SonicHalt(
IN NDIS_HANDLE MiniportAdapterContext
);
STATIC
VOID
SonicShutdown(
IN NDIS_HANDLE MiniportAdapterContext
);
STATIC
NDIS_STATUS
SonicInitalize(
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE ConfigurationHandle
);
STATIC
NDIS_STATUS
SonicReset(
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext
);
STATIC
BOOLEAN
SonicSynchClearIsr(
IN PVOID Context
);
STATIC
VOID
SonicStopChip(
IN PSONIC_ADAPTER Adapter
);
STATIC
BOOLEAN
SetupRegistersAndInit(
IN PSONIC_ADAPTER Adapter
);
STATIC
BOOLEAN
SonicInitialInit(
IN PSONIC_ADAPTER Adapter
);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
STATIC
NDIS_STATUS
SonicRegisterAdapter(
IN NDIS_HANDLE NdisMacHandle,
IN NDIS_HANDLE ConfigurationHandle,
IN PUCHAR NetworkAddress,
IN UCHAR AdapterType,
IN UINT SlotNumber,
IN UINT Controller,
IN UINT MultifunctionAdapter,
IN UINT SonicInterruptVector,
IN UINT SonicInterruptLevel,
IN NDIS_INTERRUPT_MODE SonicInterruptMode
);
typedef enum {
SonicHardwareOk,
SonicHardwareChecksum,
SonicHardwareConfig
} SONIC_HARDWARE_STATUS;
STATIC
SONIC_HARDWARE_STATUS
SonicHardwareGetDetails(
IN PSONIC_ADAPTER Adapter,
IN UINT SlotNumber,
IN UINT Controller,
IN UINT MultifunctionAdapter,
OUT PULONG InitialPort,
OUT PULONG NumberOfPorts,
IN OUT PUINT InterruptVector,
IN OUT PUINT InterruptLevel,
OUT ULONG ErrorLogData[3]
);
STATIC
BOOLEAN
SonicHardwareGetAddress(
IN PSONIC_ADAPTER Adapter,
OUT ULONG ErrorLogData[3]
);
#ifdef SONIC_INTERNAL
//
// These routines are support reading the address for the
// sonic internal implementation on the R4000 motherboards.
//
STATIC
NTSTATUS
SonicHardwareSaveInformation(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
);
STATIC
BOOLEAN
SonicHardwareVerifyChecksum(
IN PSONIC_ADAPTER Adapter,
IN PUCHAR EthernetAddress,
OUT ULONG ErrorLogData[3]
);
#endif
SONIC_DRIVER SonicDriver;
#pragma NDIS_INIT_FUNCTION(DriverEntry)
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the primary initialization routine for the sonic driver.
It is simply responsible for the intializing the wrapper and registering
the MAC. 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.
Return Value:
The status of the operation.
--*/
{
//
// Receives the status of the NdisRegisterMac operation.
//
NDIS_STATUS Status;
NDIS_HANDLE SonicWrapperHandle;
static const NDIS_STRING MacName = NDIS_STRING_CONST("SONIC");
NDIS_MINIPORT_CHARACTERISTICS SonicChar;
#if NDIS_WIN
UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (ULONG)];
#endif
#if NDIS_WIN
((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=1;
((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=0;
*(PULONG)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=SONIC_COMPRESSED_ID;
(PVOID) DriverObject = (PVOID) pIds;
#endif
//
// Initialize the wrapper.
//
NdisMInitializeWrapper(
&SonicWrapperHandle,
DriverObject,
RegistryPath,
NULL
);
SonicDriver.WrapperHandle = SonicWrapperHandle;
//
// Initialize the miniport characteristics for the call to
// NdisMRegisterMiniport.
//
SonicChar.MajorNdisVersion = SONIC_NDIS_MAJOR_VERSION;
SonicChar.MinorNdisVersion = SONIC_NDIS_MINOR_VERSION;
SonicChar.CheckForHangHandler = SonicCheckForHang;
SonicChar.DisableInterruptHandler = SonicDisableInterrupt;
SonicChar.EnableInterruptHandler = SonicEnableInterrupt;
SonicChar.HaltHandler = SonicHalt;
SonicChar.HandleInterruptHandler = SonicHandleInterrupt;
SonicChar.InitializeHandler = SonicInitialize;
SonicChar.ISRHandler = SonicInterruptService;
SonicChar.QueryInformationHandler = SonicQueryInformation;
SonicChar.ReconfigureHandler = NULL;
SonicChar.ResetHandler = SonicReset;
SonicChar.SendHandler = SonicSend;
SonicChar.SetInformationHandler = SonicSetInformation;
SonicChar.TransferDataHandler = SonicTransferData;
Status = NdisMRegisterMiniport(
SonicWrapperHandle,
&SonicChar,
sizeof(SonicChar)
);
if (Status == NDIS_STATUS_SUCCESS) {
return NDIS_STATUS_SUCCESS;
}
//
// We can only get here if something went wrong with registering
// the mac or *all* of the adapters.
//
NdisTerminateWrapper(SonicWrapperHandle, NULL);
return NDIS_STATUS_FAILURE;
}
#if DBG
PVOID SonicAdapterAddress;
#endif
#pragma NDIS_INIT_FUNCTION(SonicRegisterAdapter)
STATIC
NDIS_STATUS
SonicRegisterAdapter(
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE ConfigurationHandle,
IN PUCHAR NetworkAddress,
IN UCHAR AdapterType,
IN UINT SlotNumber,
IN UINT Controller,
IN UINT MultifunctionAdapter,
IN UINT SonicInterruptVector,
IN UINT SonicInterruptLevel,
IN NDIS_INTERRUPT_MODE SonicInterruptMode
)
/*++
Routine Description:
This routine is responsible for the allocation of the datastructures
for the driver as well as any hardware specific details necessary
to talk with the device.
Arguments:
MiniportAdapterHandle - The handle given back to the driver from ndis when
the driver registered itself.
ConfigurationHandle - Config handle passed to MacAddAdapter.
NetworkAddress - The network address, or NULL if the default
should be used.
AdapterType - The type of the adapter; currently SONIC_ADAPTER_TYPE_EISA
and SONIC_ADAPTER_TYPE_INTERNAL are supported,
SlotNumber - The slot number for the EISA card.
Controller - The controller number for INTERNAL chips.
MultifunctionAdapter - The INTERNAL bus number for INTERNAL chips.
SonicInterruptVector - The interrupt vector to use for the adapter.
SonicInterruptLevel - The interrupt request level to use for this
adapter.
SonicInterruptMode - The interrupt mode to be use for this adapter.
Return Value:
Returns a failure status if anything occurred that prevents the
initialization of the adapter.
--*/
{
//
// Pointer for the adapter root.
//
PSONIC_ADAPTER Adapter;
//
// Status of various NDIS calls.
//
NDIS_STATUS Status;
//
// Number of ports needed
//
ULONG InitialPort;
ULONG NumberOfPorts;
//
// Returned from SonicHardwareGetDetails; if it failed,
// we log an error and exit.
//
SONIC_HARDWARE_STATUS HardwareDetailsStatus;
//
// Used to store error log data from SonicHardwareGetDetails.
//
ULONG ErrorLogData[3];
//
// We put in this assertion to make sure that ushort are 2 bytes.
// if they aren't then the initialization block definition needs
// to be changed.
//
// Also all of the logic that deals with status registers assumes
// that control registers are only 2 bytes.
//
ASSERT(sizeof(USHORT) == 2);
//
// The Sonic uses four bytes four physical addresses, so we
// must ensure that this is the case (SONIC_PHYSICAL_ADDRESS)
// is defined as a ULONG).
//
ASSERT(sizeof(SONIC_PHYSICAL_ADDRESS) == 4);
//
// Allocate the Adapter block.
//
SONIC_ALLOC_MEMORY(&Status, &Adapter, sizeof(SONIC_ADAPTER));
if (Status == NDIS_STATUS_SUCCESS) {
#if DBG
SonicAdapterAddress = Adapter;
#endif
SONIC_ZERO_MEMORY(
Adapter,
sizeof(SONIC_ADAPTER)
);
Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
Adapter->AdapterType = AdapterType;
if (SonicInterruptMode == NdisInterruptLatched) {
Adapter->InterruptLatched = TRUE;
}
Adapter->PermanentAddressValid = FALSE;
//
// Set the attributes
//
NdisMSetAttributes(
MiniportAdapterHandle,
(NDIS_HANDLE)Adapter,
TRUE,
(AdapterType == SONIC_ADAPTER_TYPE_EISA) ?
NdisInterfaceEisa :
NdisInterfaceInternal
);
//
// Allocate the map registers
//
Status = NdisMAllocateMapRegisters(
MiniportAdapterHandle,
0,
FALSE,
SONIC_MAX_FRAGMENTS * SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS,
SONIC_LARGE_BUFFER_SIZE
);
if (Status != NDIS_STATUS_SUCCESS) {
SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
return NDIS_STATUS_RESOURCES;
}
//
// This returns the I/O ports used by the Sonic and may
// modify SonicInterruptVector and SonicInterruptLevel,
// as well as modiying some fields in Adapter.
//
if ((HardwareDetailsStatus =
SonicHardwareGetDetails(
Adapter,
SlotNumber,
Controller,
MultifunctionAdapter,
&InitialPort,
&NumberOfPorts,
&SonicInterruptVector,
&SonicInterruptLevel,
ErrorLogData)) != SonicHardwareOk) {
//
// Error out.
//
NdisWriteErrorLogEntry(
MiniportAdapterHandle,
NDIS_ERROR_CODE_NETWORK_ADDRESS,
6,
hardwareDetails,
SONIC_ERRMSG_HARDWARE_ADDRESS,
NDIS_STATUS_FAILURE,
ErrorLogData[0],
ErrorLogData[1],
ErrorLogData[2]
);
NdisMFreeMapRegisters(MiniportAdapterHandle);
SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
return NDIS_STATUS_FAILURE;
}
//
// Register the port addresses.
//
Status = NdisMRegisterIoPortRange(
(PVOID *)(&(Adapter->SonicPortAddress)),
MiniportAdapterHandle,
InitialPort,
NumberOfPorts
);
if (Status != NDIS_STATUS_SUCCESS) {
NdisMFreeMapRegisters(MiniportAdapterHandle);
SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
return NDIS_STATUS_FAILURE;
}
Adapter->NumberOfPorts = NumberOfPorts;
Adapter->InitialPort = InitialPort;
//
// Allocate memory for all of the adapter structures.
//
Adapter->NumberOfTransmitDescriptors =
SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS;
Adapter->NumberOfReceiveBuffers =
SONIC_NUMBER_OF_RECEIVE_BUFFERS;
Adapter->NumberOfReceiveDescriptors =
SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS;
if (AllocateAdapterMemory(Adapter)) {
//
// Get the network address. This writes
// an error log entry if it fails. This routine
// may do nothing on some systems, if
// SonicHardwareGetDetails has already determined
// the network address.
//
if (!SonicHardwareGetAddress(Adapter, ErrorLogData)) {
NdisWriteErrorLogEntry(
MiniportAdapterHandle,
NDIS_ERROR_CODE_NETWORK_ADDRESS,
6,
hardwareDetails,
SONIC_ERRMSG_HARDWARE_ADDRESS,
NDIS_STATUS_FAILURE,
ErrorLogData[0],
ErrorLogData[1],
ErrorLogData[2]
);
DeleteAdapterMemory(Adapter);
NdisMFreeMapRegisters(MiniportAdapterHandle);
NdisMDeregisterIoPortRange(
MiniportAdapterHandle,
InitialPort,
NumberOfPorts,
(PVOID)Adapter->SonicPortAddress
);
SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
return NDIS_STATUS_FAILURE;
}
//
// Initialize the current hardware address.
//
SONIC_MOVE_MEMORY(
Adapter->CurrentNetworkAddress,
(NetworkAddress != NULL) ?
NetworkAddress :
Adapter->PermanentNetworkAddress,
ETH_LENGTH_OF_ADDRESS);
Adapter->LastTransmitDescriptor =
Adapter->TransmitDescriptorArea +
(Adapter->NumberOfTransmitDescriptors-1);
Adapter->NumberOfAvailableDescriptors =
Adapter->NumberOfTransmitDescriptors;
Adapter->AllocateableDescriptor =
Adapter->TransmitDescriptorArea;
Adapter->TransmittingDescriptor =
Adapter->TransmitDescriptorArea;
Adapter->FirstUncommittedDescriptor =
Adapter->TransmitDescriptorArea;
Adapter->PacketsSinceLastInterrupt = 0;
Adapter->CurrentReceiveBufferIndex = 0;
Adapter->CurrentReceiveDescriptorIndex = 0;
Adapter->LastReceiveDescriptor =
&Adapter->ReceiveDescriptorArea[
Adapter->NumberOfReceiveDescriptors-1];
//
// Flush the current receive buffer, which is the first one.
//
NdisFlushBuffer(
Adapter->ReceiveNdisBufferArea[0],
FALSE
);
Adapter->ReceiveDescriptorsExhausted = FALSE;
Adapter->ReceiveBuffersExhausted = FALSE;
Adapter->ReceiveControlRegister = SONIC_RCR_DEFAULT_VALUE;
Adapter->FirstFinishTransmit = NULL;
Adapter->LastFinishTransmit = NULL;
Adapter->ResetInProgress = FALSE;
Adapter->FirstInitialization = TRUE;
SONIC_ZERO_MEMORY (&Adapter->GeneralMandatory, GM_ARRAY_SIZE * sizeof(ULONG));
SONIC_ZERO_MEMORY (&Adapter->GeneralOptionalByteCount, GO_COUNT_ARRAY_SIZE * sizeof(SONIC_LARGE_INTEGER));
SONIC_ZERO_MEMORY (&Adapter->GeneralOptionalFrameCount, GO_COUNT_ARRAY_SIZE * sizeof(ULONG));
SONIC_ZERO_MEMORY (&Adapter->GeneralOptional, (GO_ARRAY_SIZE - GO_ARRAY_START) * sizeof(ULONG));
SONIC_ZERO_MEMORY (&Adapter->MediaMandatory, MM_ARRAY_SIZE * sizeof(ULONG));
SONIC_ZERO_MEMORY (&Adapter->MediaOptional, MO_ARRAY_SIZE * sizeof(ULONG));
//
// Initialize the CAM and associated things.
// At the beginning nothing is enabled since
// our filter is 0, although we do store
// our network address in the first slot.
//
Adapter->MulticastCamEnableBits = 0x0000;
Adapter->CurrentPacketFilter = 0;
Adapter->CamDescriptorArea->CamEnable = 0x0000;
Adapter->CamDescriptorsUsed = 0x0001;
Adapter->CamDescriptorAreaSize = 1;
SONIC_LOAD_CAM_FRAGMENT(
&Adapter->CamDescriptorArea->CamFragments[0],
0,
Adapter->CurrentNetworkAddress
);
//
// Initialize the interrupt.
//
Status = NdisMRegisterInterrupt(
&Adapter->Interrupt,
MiniportAdapterHandle,
SonicInterruptVector,
SonicInterruptLevel,
FALSE,
FALSE,
SonicInterruptMode
);
if (Status != NDIS_STATUS_SUCCESS) {
NdisWriteErrorLogEntry(
MiniportAdapterHandle,
NDIS_ERROR_CODE_INTERRUPT_CONNECT,
2,
registerAdapter,
SONIC_ERRMSG_INIT_INTERRUPT
);
DeleteAdapterMemory(Adapter);
NdisMFreeMapRegisters(MiniportAdapterHandle);
NdisMDeregisterIoPortRange(
MiniportAdapterHandle,
InitialPort,
NumberOfPorts,
(PVOID)Adapter->SonicPortAddress
);
SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
return Status;
}
//
// Start the card up. This writes an error
// log entry if it fails.
//
if (!SonicInitialInit(Adapter)) {
NdisMDeregisterInterrupt(&Adapter->Interrupt);
DeleteAdapterMemory(Adapter);
NdisMFreeMapRegisters(MiniportAdapterHandle);
NdisMDeregisterIoPortRange(
MiniportAdapterHandle,
InitialPort,
NumberOfPorts,
(PVOID)Adapter->SonicPortAddress
);
SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
return NDIS_STATUS_FAILURE;
} else {
//
// Register our shutdown handler.
//
NdisMRegisterAdapterShutdownHandler(
Adapter->MiniportAdapterHandle, // miniport handle.
Adapter, // shutdown context.
SonicShutdown // shutdown handler.
);
//
// All done.
//
return NDIS_STATUS_SUCCESS;
}
} else {
//
// Call to AllocateAdapterMemory failed.
//
NdisWriteErrorLogEntry(
MiniportAdapterHandle,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
2,
registerAdapter,
SONIC_ERRMSG_ALLOC_MEMORY
);
DeleteAdapterMemory(Adapter);
NdisMFreeMapRegisters(MiniportAdapterHandle);
NdisMDeregisterIoPortRange(
MiniportAdapterHandle,
InitialPort,
NumberOfPorts,
(PVOID)Adapter->SonicPortAddress
);
SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
return NDIS_STATUS_RESOURCES;
}
} else {
//
// Couldn't allocate adapter object.
//
return NDIS_STATUS_RESOURCES;
}
}
#pragma NDIS_INIT_FUNCTION(SonicInitialInit)
STATIC
BOOLEAN
SonicInitialInit(
IN PSONIC_ADAPTER Adapter
)
/*++
Routine Description:
This routine sets up the initial init of the driver.
Arguments:
Adapter - The adapter for the hardware.
Return Value:
None.
--*/
{
UINT Time = 50;
//
// First we make sure that the device is stopped.
//
SonicStopChip(Adapter);
//
// Set up the registers.
//
if (!SetupRegistersAndInit(Adapter)) {
NdisWriteErrorLogEntry(
Adapter->MiniportAdapterHandle,
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
3,
registerAdapter,
SONIC_ERRMSG_INITIAL_INIT
);
return FALSE;
}
//
// Delay execution for 1/2 second to give the sonic
// time to initialize.
//
while (Time > 0) {
if (!Adapter->FirstInitialization) {
break;
}
NdisStallExecution(10000);
Time--;
}
//
// The only way that first initialization could have
// been turned off is if we actually initialized.
//
if (!Adapter->FirstInitialization) {
ULONG PortValue;
//
// We actually did get the initialization.
//
// We can start the chip. We may not
// have any bindings to indicate to but this
// is unimportant.
//
SonicStartChip(Adapter);
NdisStallExecution(25000);
SONIC_READ_PORT(Adapter, SONIC_COMMAND, &PortValue);
return TRUE;
} else {
NdisWriteErrorLogEntry(
Adapter->MiniportAdapterHandle,
NDIS_ERROR_CODE_TIMEOUT,
2,
registerAdapter,
SONIC_ERRMSG_INITIAL_INIT
);
return FALSE;
}
}
STATIC
BOOLEAN
SonicSynchClearIsr(
IN PVOID Context
)
/*++
Routine Description:
This routine is used during a reset. It ensures that no
interrupts will come through, and that any DPRs that run
will find no interrupts to process.
Arguments:
Context - A pointer to a SONIC_ADAPTER structure.
Return Value:
Always returns true.
--*/
{
PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)Context;
SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS, 0xffff);
Adapter->SimulatedIsr = 0;
return TRUE;
}
extern
VOID
SonicStartChip(
IN PSONIC_ADAPTER Adapter
)
/*++
Routine Description:
This routine is used to start an already initialized sonic.
Arguments:
Adapter - The adapter for the SONIC to start.
Return Value:
None.
--*/
{
//
// Take us out of reset mode if we are in it.
//
SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
0x0000
);
SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
SONIC_CR_RECEIVER_ENABLE
);
}
STATIC
VOID
SonicStopChip(
IN PSONIC_ADAPTER Adapter
)
/*++
Routine Description:
This routine is used to stop a sonic.
This routine is *not* portable. It is specific to the 386
implementation of the sonic. On the bus master card the ACON bit
must be set in csr3, whereas on the decstation, csr3 remains clear.
Arguments:
Adapter - The adapter for the SONIC to stop.
Return Value:
None.
--*/
{
SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
SONIC_CR_RECEIVER_DISABLE |
SONIC_CR_SOFTWARE_RESET
);
}
extern
VOID
SonicStartCamReload(
IN PSONIC_ADAPTER Adapter
)
/*++
Routine Description:
This routine starts a CAM reload, which will cause an
interrupt when it is done.
Arguments:
Adapter - The adapter for the SONIC to reload.
Return Value:
None.
--*/
{
//
// Move CAM Enable into the appropriate spot.
//
SONIC_LOAD_CAM_ENABLE(
&Adapter->CamDescriptorArea->CamFragments[
Adapter->CamDescriptorAreaSize],
Adapter->CamDescriptorArea->CamEnable
);
//
// Flush the CAM before we start the reload.
//
SONIC_FLUSH_WRITE_BUFFER(Adapter->CamDescriptorAreaFlushBuffer);
SONIC_WRITE_PORT(Adapter, SONIC_CAM_DESCRIPTOR,
SONIC_GET_LOW_PART_ADDRESS(Adapter->CamDescriptorAreaPhysical)
);
SONIC_WRITE_PORT(Adapter, SONIC_CAM_DESCRIPTOR_COUNT,
(USHORT)Adapter->CamDescriptorAreaSize
);
//
// Start the Load CAM, which will cause an interrupt
// when it is done.
//
SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
SONIC_CR_LOAD_CAM
);
}
STATIC
VOID
SonicHalt(
IN NDIS_HANDLE MiniportAdapterContext
)
/*++
Routine Description:
SonicUnload is called when the driver is to remove itself.
Arguments:
MiniportAdapterContext - Context registered with the wrapper, really
a pointer to the adapter.
Return Value:
None.
--*/
{
PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
//
// Stop the chip.
//
SonicStopChip (Adapter);
NdisMDeregisterInterrupt(&Adapter->Interrupt);
DeleteAdapterMemory(Adapter);
NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
NdisMDeregisterIoPortRange(
Adapter->MiniportAdapterHandle,
Adapter->InitialPort,
Adapter->NumberOfPorts,
(PVOID)Adapter->SonicPortAddress
);
SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
return;
}
STATIC
VOID
SonicShutdown(
IN NDIS_HANDLE MiniportAdapterContext
)
/*++
Routine Description:
SonicShutdown is called when the system is shutdown or it bugchecks.
Arguments:
MiniportAdapterContext - Context registered with the wrapper, really
a pointer to the adapter.
Return Value:
None.
--*/
{
PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
//
// Stop the chip.
//
SonicStopChip (Adapter);
return;
}
#pragma NDIS_INIT_FUNCTION(SonicInitialize)
STATIC
NDIS_STATUS
SonicInitialize(
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE ConfigurationHandle
)
/*++
Routine Description:
SonicInitialize adds an adapter to the list supported
by this driver.
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 Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_FAILURE
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NDIS_HANDLE ConfigHandle;
NDIS_STRING AdapterTypeString = NDIS_STRING_CONST("AdapterType");
#ifdef SONIC_INTERNAL
NDIS_STRING MultifunctionAdapterString = NDIS_STRING_CONST("MultifunctionAdapter");
NDIS_STRING NetworkControllerString = NDIS_STRING_CONST("NetworkController");
#endif
PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
PUCHAR NetworkAddress;
UINT NetworkAddressLength;
UCHAR AdapterType;
UINT InterruptVector;
UINT InterruptLevel;
NDIS_INTERRUPT_MODE InterruptMode;
UINT SlotNumber;
UINT Controller = 0;
UINT MultifunctionAdapter = 0;
UINT i;
//
// Search for the 802.3 media type
//
for (i=0; i<MediumArraySize; i++) {
if (MediumArray[i] == NdisMedium802_3) {
break;
}
}
if (i == MediumArraySize) {
return NDIS_STATUS_UNSUPPORTED_MEDIA;
}
*SelectedMediumIndex = i;
//
// Open the configuration info.
//
NdisOpenConfiguration(
&Status,
&ConfigHandle,
ConfigurationHandle
);
if (Status != NDIS_STATUS_SUCCESS) {
return Status;
}
//
// Check that adapter type is supported.
// The default depends on the processor type.
//
AdapterType = SONIC_ADAPTER_TYPE_DEFAULT;
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&AdapterTypeString,
NdisParameterInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
//
// See if the adapter type is valid. We skip to AdapterTypeRecognized
// if the AdapterType is known to this driver.
//
#ifdef SONIC_EISA
if (ReturnedValue->ParameterData.IntegerData == SONIC_ADAPTER_TYPE_EISA) {
goto AdapterTypeRecognized;
}
#endif
#ifdef SONIC_INTERNAL
if (ReturnedValue->ParameterData.IntegerData == SONIC_ADAPTER_TYPE_INTERNAL) {
goto AdapterTypeRecognized;
}
#endif
//
// Card type not supported by this driver
//
#if DBG
DbgPrint("SONIC: Error in adapter type: %lx\n", ReturnedValue->ParameterData.IntegerData);
#endif
NdisCloseConfiguration(ConfigHandle);
return NDIS_STATUS_FAILURE;
AdapterTypeRecognized:
AdapterType = (UCHAR)ReturnedValue->ParameterData.IntegerData;
}
switch (AdapterType) {
#ifdef SONIC_EISA
case SONIC_ADAPTER_TYPE_EISA:
{
NDIS_EISA_FUNCTION_INFORMATION EisaData;
USHORT Portzc88;
UCHAR zc88Value;
UCHAR Mask;
UCHAR InitType;
UCHAR PortValue;
USHORT PortAddress;
PUCHAR CurrentChar;
BOOLEAN LastEntry;
NdisReadEisaSlotInformation(
&Status,
ConfigurationHandle,
&SlotNumber,
&EisaData
);
if (Status != NDIS_STATUS_SUCCESS) {
#if DBG
DbgPrint("SONIC: Could not read EISA data\n");
#endif
NdisCloseConfiguration(ConfigHandle);
return NDIS_STATUS_FAILURE;
}
CurrentChar = EisaData.InitializationData;
Portzc88 = (SlotNumber << 12) + 0xc88;
LastEntry = FALSE;
while (!LastEntry) {
InitType = *(CurrentChar++);
PortAddress = *((USHORT UNALIGNED *)CurrentChar);
CurrentChar += sizeof(USHORT);
if ((InitType & 0x80) == 0) {
LastEntry = TRUE;
}
PortValue = *(CurrentChar++);
if (InitType & 0x40) {
Mask = *(CurrentChar++);
} else {
Mask = 0;
}
//
// The only port we care about is zc88 (z is the
// slot number) since it has the interrupt in it.
//
if (PortAddress != Portzc88) {
continue;
}
zc88Value &= Mask;
zc88Value |= PortValue;
}
switch ((zc88Value & 0x06) >> 1) {
case 0:
InterruptVector = 5; break;
case 1:
InterruptVector = 9; break;
case 2:
InterruptVector = 10; break;
case 3:
InterruptVector = 11; break;
}
InterruptLevel = InterruptVector;
if ((zc88Value & 0x01) != 0) {
InterruptMode = NdisInterruptLatched;
} else {
InterruptMode = NdisInterruptLevelSensitive;
}
break;
}
#endif // SONIC_EISA
#ifdef SONIC_INTERNAL
case SONIC_ADAPTER_TYPE_INTERNAL:
{
//
// For the internal adapter, we read the MultifunctionAdapter number
// and NetworkController number, which are both optional. For
// passing to SonicRegisterAdapter.
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&MultifunctionAdapterString,
NdisParameterInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
MultifunctionAdapter = ReturnedValue->ParameterData.IntegerData;
}
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&NetworkControllerString,
NdisParameterInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
Controller = ReturnedValue->ParameterData.IntegerData;
}
//
// These are filled in by SonicHardwareGetDetails.
//
InterruptVector = 0;
InterruptLevel = 0;
//
// The internal adapter is level-sensitive.
//
InterruptMode = NdisInterruptLevelSensitive;
break;
}
#endif // SONIC_INTERNAL
default:
ASSERT(FALSE);
break;
}
//
// Read network address
//
NdisReadNetworkAddress(
&Status,
(PVOID *)&NetworkAddress,
&NetworkAddressLength,
ConfigHandle);
//
// Make sure that the address is the right length asnd
// at least one of the bytes is non-zero.
//
if ((Status == NDIS_STATUS_SUCCESS) &&
(NetworkAddressLength == ETH_LENGTH_OF_ADDRESS) &&
((NetworkAddress[0] |
NetworkAddress[1] |
NetworkAddress[2] |
NetworkAddress[3] |
NetworkAddress[4] |
NetworkAddress[5]) != 0)) {
#if DBG
if (SonicDbg) {
DbgPrint("SONIC: New Address = %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
NetworkAddress[0],
NetworkAddress[1],
NetworkAddress[2],
NetworkAddress[3],
NetworkAddress[4],
NetworkAddress[5]);
}
#endif
} else {
//
// Tells SonicRegisterAdapter to use the
// burned-in address.
//
NetworkAddress = NULL;
}
//
// Used passed-in adapter name to register.
//
Status = SonicRegisterAdapter(
MiniportAdapterHandle,
ConfigurationHandle,
NetworkAddress,
AdapterType,
SlotNumber,
Controller,
MultifunctionAdapter,
InterruptVector,
InterruptLevel,
InterruptMode
);
NdisCloseConfiguration(ConfigHandle);
return Status; // should be NDIS_STATUS_SUCCESS
}
STATIC
NDIS_STATUS
SonicReset(
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext
)
/*++
Routine Description:
The SonicReset request instructs the driver to issue a hardware reset
to the network adapter. The driver also resets its software state. See
the description of MiniportMReset for a detailed description of this request.
Arguments:
MiniportAdapterContext - Pointer to the adapter structure.
AddressingReset - Does the adapter need the addressing information reloaded.
Return Value:
The function value is the status of the operation.
--*/
{
PSONIC_ADAPTER Adapter =
PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
*AddressingReset = FALSE;
SetupForReset(Adapter);
StartAdapterReset(Adapter);
return NDIS_STATUS_PENDING;
}
extern
VOID
StartAdapterReset(
IN PSONIC_ADAPTER Adapter
)
/*++
Routine Description:
This is the first phase of resetting the adapter hardware.
It makes the following assumptions:
1) That the hardware has been stopped.
2) That it can not be preempted.
3) 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:
None.
--*/
{
//
// These are used for cleaning the rings.
//
PSONIC_RECEIVE_DESCRIPTOR CurrentReceiveDescriptor;
PSONIC_TRANSMIT_DESCRIPTOR CurrentTransmitDescriptor;
UINT i;
SONIC_PHYSICAL_ADDRESS SonicPhysicalAdr;
//
// Shut down the chip. We won't be doing any more work until
// the reset is complete.
//
SonicStopChip(Adapter);
//
// Once the chip is stopped we can't get any more interrupts.
// Any interrupts that are "queued" for processing could
// only possibly service this reset. It is therefore safe for
// us to clear the adapter global csr value.
//
Adapter->SimulatedIsr = 0;
Adapter->LastTransmitDescriptor =
Adapter->TransmitDescriptorArea +
(Adapter->NumberOfTransmitDescriptors-1);
Adapter->NumberOfAvailableDescriptors =
Adapter->NumberOfTransmitDescriptors;
Adapter->AllocateableDescriptor =
Adapter->TransmitDescriptorArea;
Adapter->TransmittingDescriptor =
Adapter->TransmitDescriptorArea;
Adapter->FirstUncommittedDescriptor =
Adapter->TransmitDescriptorArea;
Adapter->PacketsSinceLastInterrupt = 0;
Adapter->CurrentReceiveBufferIndex = 0;
Adapter->CurrentReceiveDescriptorIndex = 0;
Adapter->LastReceiveDescriptor =
&Adapter->ReceiveDescriptorArea[
Adapter->NumberOfReceiveDescriptors-1];
//
// Flush the current receive buffer, which is the first one.
//
NdisFlushBuffer(
Adapter->ReceiveNdisBufferArea[0],
FALSE
);
Adapter->ReceiveDescriptorsExhausted = FALSE;
Adapter->ReceiveBuffersExhausted = FALSE;
Adapter->ReceiveControlRegister = SONIC_RCR_DEFAULT_VALUE;
Adapter->HardwareFailure = FALSE;
//
// Clean the receive descriptors and initialize the link
// fields.
//
SONIC_ZERO_MEMORY(
Adapter->ReceiveDescriptorArea,
(sizeof(SONIC_RECEIVE_DESCRIPTOR)*Adapter->NumberOfReceiveDescriptors)
);
for (
i = 0, CurrentReceiveDescriptor = Adapter->ReceiveDescriptorArea;
i < Adapter->NumberOfReceiveDescriptors;
i++,CurrentReceiveDescriptor++
) {
CurrentReceiveDescriptor->InUse = SONIC_OWNED_BY_SONIC;
SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical) +
(i * sizeof(SONIC_RECEIVE_DESCRIPTOR));
if (i == 0) {
Adapter->ReceiveDescriptorArea[
Adapter->NumberOfReceiveDescriptors-1].Link =
SonicPhysicalAdr | SONIC_END_OF_LIST;
} else {
Adapter->ReceiveDescriptorArea[i-1].Link = SonicPhysicalAdr;
}
}
//
// Clean the transmit descriptors and initialize the link
// fields.
//
SONIC_ZERO_MEMORY(
Adapter->TransmitDescriptorArea,
(sizeof(SONIC_TRANSMIT_DESCRIPTOR)*Adapter->NumberOfTransmitDescriptors)
);
for (
i = 0, CurrentTransmitDescriptor = Adapter->TransmitDescriptorArea;
i < Adapter->NumberOfTransmitDescriptors;
i++,CurrentTransmitDescriptor++
) {
SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) +
(i * sizeof(SONIC_TRANSMIT_DESCRIPTOR));
if (i == 0) {
Adapter->TransmitDescriptorArea[Adapter->NumberOfTransmitDescriptors-1].Link = SonicPhysicalAdr;
} else {
(CurrentTransmitDescriptor-1)->Link = SonicPhysicalAdr;
}
}
//
// Recover all of the adapter buffers.
//
{
UINT i;
for (
i = 0;
i < (SONIC_NUMBER_OF_SMALL_BUFFERS +
SONIC_NUMBER_OF_MEDIUM_BUFFERS +
SONIC_NUMBER_OF_LARGE_BUFFERS);
i++
) {
Adapter->SonicBuffers[i].Next = i+1;
}
Adapter->SonicBufferListHeads[0] = -1;
Adapter->SonicBufferListHeads[1] = 0;
Adapter->SonicBuffers[SONIC_NUMBER_OF_SMALL_BUFFERS-1].Next = -1;
Adapter->SonicBufferListHeads[2] = SONIC_NUMBER_OF_SMALL_BUFFERS;
Adapter->SonicBuffers[(SONIC_NUMBER_OF_SMALL_BUFFERS+
SONIC_NUMBER_OF_MEDIUM_BUFFERS)-1].Next = -1;
Adapter->SonicBufferListHeads[3] = SONIC_NUMBER_OF_SMALL_BUFFERS +
SONIC_NUMBER_OF_MEDIUM_BUFFERS;
Adapter->SonicBuffers[(SONIC_NUMBER_OF_SMALL_BUFFERS+
SONIC_NUMBER_OF_MEDIUM_BUFFERS+
SONIC_NUMBER_OF_LARGE_BUFFERS)-1].Next = -1;
}
(VOID)SetupRegistersAndInit(Adapter);
}
STATIC
BOOLEAN
SetupRegistersAndInit(
IN PSONIC_ADAPTER Adapter
)
/*++
Routine Description:
It is this routines responsibility to make sure that the
initialization block is filled and the chip is initialized
*but not* started.
NOTE: This routine assumes that it is called with the lock
acquired OR that only a single thread of execution is working
with this particular adapter.
Arguments:
Adapter - The adapter whose hardware is to be initialized.
Return Value:
TRUE if the registers are initialized successfully.
--*/
{
USHORT CommandRegister;
UINT Time;
SONIC_WRITE_PORT(Adapter, SONIC_DATA_CONFIGURATION,
Adapter->DataConfigurationRegister
);
SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL,
Adapter->ReceiveControlRegister
);
SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK,
SONIC_INT_DEFAULT_VALUE
);
SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS,
(USHORT)0xffff
);
SONIC_WRITE_PORT(Adapter, SONIC_UPPER_TRANSMIT_DESCRIPTOR,
SONIC_GET_HIGH_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical))
);
SONIC_WRITE_PORT(Adapter, SONIC_CURR_TRANSMIT_DESCRIPTOR,
SONIC_GET_LOW_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical))
);
SONIC_WRITE_PORT(Adapter, SONIC_UPPER_RECEIVE_DESCRIPTOR,
SONIC_GET_HIGH_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical))
);
SONIC_WRITE_PORT(Adapter, SONIC_CURR_RECEIVE_DESCRIPTOR,
SONIC_GET_LOW_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical))
);
//
// The EOBC value cannot be odd (since the card register
// wants it in words); in addition it appears that the
// value in the register must be even, so this number
// has to be a multiple of 4.
//
ASSERT((SONIC_END_OF_BUFFER_COUNT & 0x3) == 0);
switch (Adapter->AdapterType) {
#ifdef SONIC_EISA
case SONIC_ADAPTER_TYPE_EISA:
//
// For the EISA card, set EOBC to 2 words more than real
// size.
//
// Add the appropriate correction for the rev. C problem.
//
SONIC_WRITE_PORT(Adapter, SONIC_END_OF_BUFFER_WORD_COUNT,
((SONIC_END_OF_BUFFER_COUNT+SONIC_EOBC_REV_C_CORRECTION) / 2) + 2
);
break;
#endif // SONIC_EISA
#ifdef SONIC_INTERNAL
case SONIC_ADAPTER_TYPE_INTERNAL:
//
// Add the appropriate correction for the rev. C problem.
//
SONIC_WRITE_PORT(Adapter, SONIC_END_OF_BUFFER_WORD_COUNT,
(SONIC_END_OF_BUFFER_COUNT+SONIC_EOBC_REV_C_CORRECTION) / 2
);
break;
#endif // SONIC_INTERNAL
default:
ASSERT(FALSE);
break;
}
SONIC_WRITE_PORT(Adapter, SONIC_UPPER_RECEIVE_RESOURCE,
SONIC_GET_HIGH_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
);
SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_START,
SONIC_GET_LOW_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
);
SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_END,
(USHORT)(SONIC_GET_LOW_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical)) +
sizeof(SONIC_RECEIVE_RESOURCE) *
Adapter->NumberOfReceiveBuffers)
);
SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_READ,
SONIC_GET_LOW_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
);
SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_WRITE,
SONIC_GET_LOW_PART_ADDRESS(
NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
);
//
// Now take us out of reset mode...
//
SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
0x0000
);
//
// ...and issue the Read RRA command.
//
SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
SONIC_CR_READ_RRA
);
//
// Wait for 1/5 second for Read RRA to finish.
//
Time = 20;
while (Time > 0) {
NdisStallExecution(10000);
SONIC_READ_PORT(Adapter, SONIC_COMMAND, &CommandRegister);
if ((CommandRegister & SONIC_CR_READ_RRA) == 0) {
break;
}
Time--;
}
if (Time == 0) {
#if DBG
DbgPrint("SONIC: Could not read RRA\n");
#endif
return FALSE;
}
//
// This will cause a LOAD_CAM interrupt when it is done.
//
SonicStartCamReload(Adapter);
return TRUE;
}
extern
VOID
SetupForReset(
IN PSONIC_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.
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 Section of packet
//
PSONIC_PACKET_RESERVED Reserved;
//
// Shut down the chip. We won't be doing any more work until
// the reset is complete. We take it out of reset mode, however.
//
SonicStopChip(Adapter);
Adapter->ResetInProgress = TRUE;
//
// Once the chip is stopped we can't get any more interrupts.
// This call ensures that any ISR which is just about to run
// will find no bits in the ISR, and any DPR which fires will
// find nothing queued to do.
//
NdisMSynchronizeWithInterrupt(
&Adapter->Interrupt,
SonicSynchClearIsr,
(PVOID)Adapter);
//
// Un-map all outstanding transmits
//
while (Adapter->FirstFinishTransmit != NULL) {
//
// Remove first packet from the queue
//
Packet = Adapter->FirstFinishTransmit;
Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
Adapter->FirstFinishTransmit = Reserved->Next;
if (Reserved->UsedSonicBuffer) {
continue;
}
//
// 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->DescriptorIndex * SONIC_MAX_FRAGMENTS;
//
// For each buffer
//
while (CurrentBuffer) {
//
// Finish the mapping
//
NdisMCompleteBufferPhysicalMapping(
Adapter->MiniportAdapterHandle,
CurrentBuffer,
CurMapRegister
);
++CurMapRegister;
NdisGetNextBuffer(
CurrentBuffer,
&CurrentBuffer
);
}
}
}
#ifdef SONIC_INTERNAL
//
// The next routines are to support reading the registry to
// obtain information about the internal sonic on the
// MIPS R4000 motherboards.
//
//
// This structure is used as the Context in the callbacks
// to SonicHardwareSaveInformation.
//
typedef struct _SONIC_HARDWARE_INFO {
//
// These are read out of the "Configuration Data"
// data.
//
CCHAR InterruptVector;
KIRQL InterruptLevel;
USHORT DataConfigurationRegister;
LARGE_INTEGER PortAddress;
BOOLEAN DataValid;
UCHAR EthernetAddress[8];
BOOLEAN AddressValid;
//
// This is set to TRUE if "Identifier" is equal to
// "SONIC".
//
BOOLEAN SonicIdentifier;
} SONIC_HARDWARE_INFO, *PSONIC_HARDWARE_INFO;
#pragma NDIS_INIT_FUNCTION(SonicHardwareSaveInformation)
STATIC
NTSTATUS
SonicHardwareSaveInformation(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
/*++
Routine Description:
This routine is a callback routine for RtlQueryRegistryValues.
It is called back with the data for the "Identifier" value
and verifies that it is "SONIC", then is called back with
the resource list and records the ports, interrupt number,
and DCR value.
Arguments:
ValueName - The name of the value ("Identifier" or "Configuration
Data").
ValueType - The type of the value (REG_SZ or REG_BINARY).
ValueData - The null-terminated data for the value.
ValueLength - The length of ValueData (ignored).
Context - A pointer to the SONIC_HARDWARE_INFO structure.
EntryContext - FALSE for "Identifier", TRUE for "Configuration Data".
Return Value:
STATUS_SUCCESS
--*/
{
PSONIC_HARDWARE_INFO HardwareInfo = (PSONIC_HARDWARE_INFO)Context;
if ((BOOLEAN)EntryContext) {
//
// This is the "Configuration Data" callback.
//
if ((ValueType == REG_BINARY || ValueType == REG_FULL_RESOURCE_DESCRIPTOR) &&
(ValueLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))) {
BOOLEAN InterruptRead = FALSE;
BOOLEAN PortAddressRead = FALSE;
BOOLEAN DeviceSpecificRead = FALSE;
UINT i;
PCM_PARTIAL_RESOURCE_LIST ResourceList;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
PCM_SONIC_DEVICE_DATA SonicDeviceData;
ResourceList =
&((PCM_FULL_RESOURCE_DESCRIPTOR)ValueData)->PartialResourceList;
for (i = 0; i < ResourceList->Count; i++) {
ResourceDescriptor = &(ResourceList->PartialDescriptors[i]);
switch (ResourceDescriptor->Type) {
case CmResourceTypePort:
HardwareInfo->PortAddress = ResourceDescriptor->u.Port.Start;
PortAddressRead = TRUE;
break;
case CmResourceTypeInterrupt:
HardwareInfo->InterruptVector = (CCHAR)ResourceDescriptor->u.Interrupt.Vector;
HardwareInfo->InterruptLevel = (KIRQL)ResourceDescriptor->u.Interrupt.Level;
InterruptRead = TRUE;
break;
case CmResourceTypeDeviceSpecific:
if (i == ResourceList->Count-1) {
SonicDeviceData = (PCM_SONIC_DEVICE_DATA)
&(ResourceList->PartialDescriptors[ResourceList->Count]);
//
// Make sure we have enough room for each element we read.
//
if (ResourceDescriptor->u.DeviceSpecificData.DataSize >=
(ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]))) {
HardwareInfo->DataConfigurationRegister =
SonicDeviceData->DataConfigurationRegister;
DeviceSpecificRead = TRUE;
//
// Version.Revision later than 0.0 means that
// the ethernet address is there too.
//
if ((SonicDeviceData->Version != 0) ||
(SonicDeviceData->Revision != 0)) {
if (ResourceDescriptor->u.DeviceSpecificData.DataSize >=
(ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]) + 8)) {
SONIC_MOVE_MEMORY(
HardwareInfo->EthernetAddress,
SonicDeviceData->EthernetAddress,
8);
HardwareInfo->AddressValid = TRUE;
}
}
}
}
break;
}
}
//
// Make sure we got all we wanted.
//
if (PortAddressRead && InterruptRead && DeviceSpecificRead) {
HardwareInfo->DataValid = TRUE;
}
}
} else {
static const WCHAR SonicString[] = L"SONIC";
//
// This is the "Identifier" callback.
//
if ((ValueType == REG_SZ) &&
(ValueLength >= sizeof(SonicString)) &&
(RtlCompareMemory (ValueData, (PVOID)&SonicString, sizeof(SonicString)) == sizeof(SonicString))) {
HardwareInfo->SonicIdentifier = TRUE;
}
}
return STATUS_SUCCESS;
}
#pragma NDIS_INIT_FUNCTION(SonicHardwareVerifyChecksum)
STATIC
BOOLEAN
SonicHardwareVerifyChecksum(
IN PSONIC_ADAPTER Adapter,
IN PUCHAR EthernetAddress,
OUT ULONG ErrorLogData[3]
)
/*++
Routine Description:
This routine verifies that the checksum on the address
for an internal sonic on a MIPS R4000 system is correct.
Arguments:
Adapter - The adapter which is being verified.
EthernetAddress - A pointer to the address, with the checksum
following it.
ErrorLogData - If the checksum is bad, returns the address
and the checksum we expected.
Return Value:
TRUE if the checksum is correct.
--*/
{
//
// Iteration variable.
//
UINT i;
//
// Holds the checksum value.
//
USHORT CheckSum = 0;
//
// The network address is stored in the first 6 bytes of
// EthernetAddress. Following that is a zero byte followed
// by a value such that the sum of a checksum on the six
// bytes and this value is 0xff. The checksum is computed
// by adding together the six bytes, with the carry being
// wrapped back to the first byte.
//
for (i=0; i<6; i++) {
CheckSum += EthernetAddress[i];
if (CheckSum > 0xff) {
CheckSum -= 0xff;
}
}
if ((EthernetAddress[6] != 0x00) ||
((EthernetAddress[7] + CheckSum) != 0xff)) {
ErrorLogData[0] = ((ULONG)(EthernetAddress[3]) << 24) +
((ULONG)(EthernetAddress[2]) << 16) +
((ULONG)(EthernetAddress[1]) << 8) +
((ULONG)(EthernetAddress[0]));
ErrorLogData[1] = ((ULONG)(EthernetAddress[7]) << 24) +
((ULONG)(EthernetAddress[6]) << 16) +
((ULONG)(EthernetAddress[5]) << 8) +
((ULONG)(EthernetAddress[4]));
ErrorLogData[2] = 0xff - CheckSum;
return FALSE;
}
return TRUE;
}
#endif // SONIC_INTERNAL
#pragma NDIS_INIT_FUNCTION(SonicHardwareGetDetails)
STATIC
SONIC_HARDWARE_STATUS
SonicHardwareGetDetails(
IN PSONIC_ADAPTER Adapter,
IN UINT SlotNumber,
IN UINT Controller,
IN UINT MultifunctionAdapter,
OUT PULONG InitialPort,
OUT PULONG NumberOfPorts,
IN OUT PUINT InterruptVector,
IN OUT PUINT InterruptLevel,
OUT ULONG ErrorLogData[3]
)
/*++
Routine Description:
This routine gets the initial port and number of ports for
the Sonic. It also sets Adapter->PortShift. The ports are
numbered 0, 1, 2, etc. but may appear as 16- or 32-bit
ports, so PortShift will be 1 or 2 depending on how wide
the ports are.
It also sets the value of Adapter->DataConfigurationRegister,
and may modify InterruptVector, InterruptLevel, and
Adapter->PermanentNetworkAddress.
Arguments:
Adapter - The adapter in question.
SlotNumber - For the EISA card this is the slot number that the
card is in.
Controller - For the internal version, it is the
NetworkController number.
MultifunctionAdapter - For the internal version, it is the adapter number.
InitialPort - The base of the Sonic ports.
NumberOfPorts - The number of bytes of ports to map.
InterruptVector - A pointer to the interrupt vector. Depending
on the card type, this may be passed in or returned by
this function.
InterruptLevel - A pointer to the interrupt level. Depending
on the card type, this may be passed in or returned by
this function.
ErrorLogData - If the return status is SonicHardwareChecksum,
this returns 3 longwords to be included in the error log.
Return Value:
SonicHardwareOk if successful, SonicHardwareChecksum if the
checksum is bad, SonicHardwareConfig for other problems.
--*/
{
switch (Adapter->AdapterType) {
#ifdef SONIC_EISA
case SONIC_ADAPTER_TYPE_EISA:
*InitialPort = (SlotNumber << 12);
*NumberOfPorts = 0xD00;
Adapter->PortShift = 1;
Adapter->DataConfigurationRegister =
SONIC_DCR_PROGRAMMABLE_OUTPUT_1 |
SONIC_DCR_USER_DEFINABLE_1 |
SONIC_DCR_3_WAIT_STATE |
SONIC_DCR_BLOCK_MODE_DMA |
SONIC_DCR_32_BIT_DATA_WIDTH |
SONIC_DCR_8_WORD_RECEIVE_FIFO |
SONIC_DCR_8_WORD_TRANSMIT_FIFO;
return SonicHardwareOk;
break;
#endif // SONIC_EISA
#ifdef SONIC_INTERNAL
case SONIC_ADAPTER_TYPE_INTERNAL:
{
//
// For MIPS R4000 systems, we have to query the registry to obtain
// information about ports, interrupts, and the value to be
// stored in the DCR register.
//
//
// NOTE: The following code is NT-specific, since that is
// currently the only system that runs on the MIPS R4000 hardware.
//
// We initialize an RTL_QUERY_TABLE to retrieve the Identifer
// and ConfigurationData strings from the registry.
//
PWSTR ConfigDataPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter\\#\\NetworkController\\#";
PWSTR IdentifierString = L"Identifier";
PWSTR ConfigDataString = L"Configuration Data";
RTL_QUERY_REGISTRY_TABLE QueryTable[4];
SONIC_HARDWARE_INFO SonicHardwareInfo;
NTSTATUS Status;
//
// Set up QueryTable to do the following:
//
//
// 1) Call SonicSaveHardwareInformation for the "Identifier"
// value.
//
QueryTable[0].QueryRoutine = SonicHardwareSaveInformation;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].Name = IdentifierString;
QueryTable[0].EntryContext = (PVOID)FALSE;
QueryTable[0].DefaultType = REG_NONE;
//
// 2) Call SonicSaveHardwareInformation for the "Configuration Data"
// value.
//
QueryTable[1].QueryRoutine = SonicHardwareSaveInformation;
QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[1].Name = ConfigDataString;
QueryTable[1].EntryContext = (PVOID)TRUE;
QueryTable[1].DefaultType = REG_NONE;
//
// 3) Stop
//
QueryTable[2].QueryRoutine = NULL;
QueryTable[2].Flags = 0;
QueryTable[2].Name = NULL;
//
// Modify ConfigDataPath to replace the two # symbols with
// the MultifunctionAdapter number and NetworkController number.
//
ConfigDataPath[67] = (WCHAR)('0' + MultifunctionAdapter);
ConfigDataPath[87] = (WCHAR)('0' + Controller);
SonicHardwareInfo.DataValid = FALSE;
SonicHardwareInfo.AddressValid = FALSE;
SonicHardwareInfo.SonicIdentifier = FALSE;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
ConfigDataPath,
QueryTable,
(PVOID)&SonicHardwareInfo,
NULL);
if (!NT_SUCCESS(Status)) {
#if DBG
DbgPrint ("SONIC: Could not read hardware information\n");
#endif
return SonicHardwareConfig;
}
if (SonicHardwareInfo.DataValid && SonicHardwareInfo.SonicIdentifier) {
*InterruptVector = (UINT)SonicHardwareInfo.InterruptVector;
*InterruptLevel = (UINT)SonicHardwareInfo.InterruptLevel;
*InitialPort = SonicHardwareInfo.PortAddress.LowPart;
*NumberOfPorts = 192;
Adapter->PortShift = 2;
Adapter->DataConfigurationRegister =
SonicHardwareInfo.DataConfigurationRegister;
if (SonicHardwareInfo.AddressValid) {
if (!SonicHardwareVerifyChecksum(Adapter, SonicHardwareInfo.EthernetAddress, ErrorLogData)) {
#if DBG
DbgPrint("SONIC: Invalid registry network address checksum!!\n");
#endif
return SonicHardwareChecksum;
}
SONIC_MOVE_MEMORY(
Adapter->PermanentNetworkAddress,
SonicHardwareInfo.EthernetAddress,
8);
Adapter->PermanentAddressValid = TRUE;
}
return SonicHardwareOk;
} else {
#if DBG
DbgPrint ("SONIC: Incorrect registry hardware information\n");
#endif
return SonicHardwareConfig;
}
break;
}
#endif // SONIC_INTERNAL
default:
ASSERT(FALSE);
break;
}
return SonicHardwareConfig;
}
#pragma NDIS_INIT_FUNCTION(SonicHardwareGetAddress)
STATIC
BOOLEAN
SonicHardwareGetAddress(
IN PSONIC_ADAPTER Adapter,
IN ULONG ErrorLogData[3]
)
/*++
Routine Description:
This routine gets the network address from the hardware.
Arguments:
Adapter - Where to store the network address.
ErrorLogData - If the checksum is bad, returns the address
and the checksum we expected.
Return Value:
TRUE if successful.
--*/
{
#define NVRAM_READ_ONLY_BASE 0x8000b000
//
// Iteration variable.
//
UINT i;
switch (Adapter->AdapterType) {
#ifdef SONIC_EISA
case SONIC_ADAPTER_TYPE_EISA:
//
// The EISA card has the address stored at ports xC90 to xC95,
// where x is the slot number.
//
for (i = 0; i < 6; i++) {
NdisRawReadPortUchar(
Adapter->SonicPortAddress + 0xc90 + i,
&Adapter->PermanentNetworkAddress[i]);
}
break;
#endif // SONIC_EISA
#ifdef SONIC_INTERNAL
case SONIC_ADAPTER_TYPE_INTERNAL:
{
NDIS_STATUS Status;
USHORT SiliconRevision;
if (!Adapter->PermanentAddressValid) {
//
// Physical addresses for call to NdisMapIoSpace.
//
NDIS_PHYSICAL_ADDRESS NvRamPhysical =
NDIS_PHYSICAL_ADDRESS_CONST(NVRAM_READ_ONLY_BASE, 0);
//
// Temporarily maps the NVRAM into our address space.
//
PVOID NvRamMapping;
//
// If PermanentAddressValid is still FALSE then the address
// was not read by SonicHardwareGetDetails, so we must do it
// here.
//
Status = NdisMMapIoSpace (
&NvRamMapping,
Adapter->MiniportAdapterHandle,
NvRamPhysical,
8
);
if (Status != NDIS_STATUS_SUCCESS) {
NdisWriteErrorLogEntry(
Adapter->MiniportAdapterHandle,
NDIS_ERROR_CODE_RESOURCE_CONFLICT,
0
);
return(FALSE);
}
//
// Verify that the checksum matches.
//
if (!SonicHardwareVerifyChecksum(Adapter, (PUCHAR)NvRamMapping, ErrorLogData)) {
#if DBG
DbgPrint("SONIC: Invalid NVRAM network address checksum!!\n");
#endif
NdisMUnmapIoSpace(Adapter->MiniportAdapterHandle, NvRamMapping, 8);
return FALSE;
}
//
// Checksum is OK, save the address.
//
for (i=0; i<6; i++) {
Adapter->PermanentNetworkAddress[i] = *((PUCHAR)NvRamMapping+i);
}
Adapter->PermanentAddressValid = TRUE;
NdisMUnmapIoSpace(Adapter->MiniportAdapterHandle, NvRamMapping, 8);
}
//
// The Data Configuration Register is already set up, but we
// change the FIFO initialization for old revisions.
//
SONIC_READ_PORT(Adapter, SONIC_SILICON_REVISION, &SiliconRevision);
if (SiliconRevision < 4) {
Adapter->DataConfigurationRegister =
(Adapter->DataConfigurationRegister & SONIC_DCR_FIFO_MASK) |
SONIC_DCR_8_WORD_RECEIVE_FIFO |
SONIC_DCR_8_WORD_TRANSMIT_FIFO;
}
break;
}
#endif // SONIC_INTERNAL
default:
ASSERT(FALSE);
break;
}
#if DBG
if (SonicDbg) {
DbgPrint("SONIC: ");
DbgPrint("[ %x-%x-%x-%x-%x-%x ]\n",
(UCHAR)Adapter->PermanentNetworkAddress[0],
(UCHAR)Adapter->PermanentNetworkAddress[1],
(UCHAR)Adapter->PermanentNetworkAddress[2],
(UCHAR)Adapter->PermanentNetworkAddress[3],
(UCHAR)Adapter->PermanentNetworkAddress[4],
(UCHAR)Adapter->PermanentNetworkAddress[5]);
DbgPrint("\n");
}
#endif
return TRUE;
}