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.
 
 
 
 
 
 

2071 lines
47 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
Elnk.c
Abstract:
This is the main file for the 3Com Etherlink/MC and Etherlink 16
Ethernet adapters. This driver conforms to the NDIS 3.0 interface.
Author:
Johnson R. Apacible (JohnsonA) 10-June-1991
Environment:
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
Revision History:
--*/
#include <ndis.h>
//
// So we can trace things...
//
#define STATIC
#include <efilter.h>
#include <elnkhw.h>
#include <elnksw.h>
#include "keywords.h"
//
// Globals
//
NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
NDIS_HANDLE ElnkMacHandle;
LIST_ENTRY ElnkAdapterList;
NDIS_SPIN_LOCK ElnkAdapterListLock;
NDIS_HANDLE ElnkNdisWrapperHandle;
PDRIVER_OBJECT ElnkDriverObject;
STATIC
BOOLEAN
ElnkInitialInit(
IN PELNK_ADAPTER Adapter,
IN UINT ElnkInterruptVector
);
STATIC
NDIS_STATUS
ElnkOpenAdapter(
OUT PNDIS_STATUS OpenErrorStatus,
OUT NDIS_HANDLE *MacBindingHandle,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE NdisBindingContext,
IN NDIS_HANDLE MacAdapterContext,
IN UINT OpenOptions,
IN PSTRING AddressingInformation OPTIONAL
);
VOID
Elnk16GenerateIdPattern(
IN PELNK_ADAPTER Adapter
);
STATIC
NDIS_STATUS
ElnkCloseAdapter(
IN NDIS_HANDLE MacBindingHandle
);
extern
VOID
ElnkQueueRequest(
IN PELNK_ADAPTER Adapter,
IN PNDIS_REQUEST NdisRequest
);
STATIC
NDIS_STATUS
ElnkReset(
IN NDIS_HANDLE MacBindingHandle
);
VOID
ElnkUnloadMac(
IN NDIS_HANDLE MacMacContext
);
VOID
ElnkRemoveAdapter(
IN NDIS_HANDLE MacAdapterContext
);
NDIS_STATUS
ElnkAddAdapter(
IN NDIS_HANDLE MacMacContext,
IN NDIS_HANDLE ConfigurationHandle,
IN PNDIS_STRING DeviceName
);
STATIC
VOID
ElnkCloseAction(
IN NDIS_HANDLE MacBindingHandle
);
VOID
InitializeAdapterVariables(
IN PELNK_ADAPTER Adapter
);
VOID
ResetAdapterVariables(
IN PELNK_ADAPTER Adapter
);
VOID
ElnkDeleteAdapterMemory(
IN PELNK_ADAPTER Adapter
);
BOOLEAN
ElnkAllocateAdapterMemory(
IN PELNK_ADAPTER Adapter
);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
#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 Elnk 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 NdisWrapperHandle;
#if ELNKMC
static NDIS_STRING MacName = NDIS_STRING_CONST("ELNKMC");
#if NDIS_WIN
UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (USHORT)];
#endif
#else
static NDIS_STRING MacName = NDIS_STRING_CONST("ELNK16");
#endif
char Tmp[sizeof(NDIS_MAC_CHARACTERISTICS)];
PNDIS_MAC_CHARACTERISTICS ElnkChar = (PNDIS_MAC_CHARACTERISTICS)Tmp;
#if NDIS_WIN
#if ELNKMC
((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=0;
((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=1;
*(PUSHORT)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=ELNKMC_ADAPTER_ID;
(PVOID) DriverObject = (PVOID) pIds;
#endif
#endif
//
// Initialize the wrapper.
//
NdisInitializeWrapper(
&NdisWrapperHandle,
DriverObject,
RegistryPath,
NULL
);
ElnkDriverObject = DriverObject;
ElnkNdisWrapperHandle = NdisWrapperHandle;
//
// Initialize the MAC characteristics for the call to
// NdisRegisterMac.
//
ElnkChar->MajorNdisVersion = ELNK_NDIS_MAJOR_VERSION;
ElnkChar->MinorNdisVersion = ELNK_NDIS_MINOR_VERSION;
ElnkChar->OpenAdapterHandler = ElnkOpenAdapter;
ElnkChar->CloseAdapterHandler = ElnkCloseAdapter;
ElnkChar->RequestHandler = ElnkRequest;
ElnkChar->SendHandler = ElnkSend;
ElnkChar->TransferDataHandler = ElnkTransferData;
ElnkChar->ResetHandler = ElnkReset;
ElnkChar->QueryGlobalStatisticsHandler = ElnkQueryGlobalStatistics;
ElnkChar->UnloadMacHandler = ElnkUnloadMac;
ElnkChar->AddAdapterHandler = ElnkAddAdapter;
ElnkChar->RemoveAdapterHandler = ElnkRemoveAdapter;
ElnkChar->Name = MacName;
//
// Initialize Globals
//
InitializeListHead(&ElnkAdapterList);
NdisAllocateSpinLock(&ElnkAdapterListLock);
NdisRegisterMac(
&Status,
&ElnkMacHandle,
NdisWrapperHandle,
NULL,
ElnkChar,
sizeof(*ElnkChar)
);
if (Status != NDIS_STATUS_SUCCESS) {
if ELNKDEBUG DPrint1("Elnk: NdisRegisterMac failed\n");
NdisFreeSpinLock(&ElnkAdapterListLock);
NdisTerminateWrapper(NdisWrapperHandle, NULL);
return NDIS_STATUS_FAILURE;
}
return(NDIS_STATUS_SUCCESS);
}
#if ELNKMC
#pragma NDIS_INIT_FUNCTION(ElnkmcRegisterAdapter)
NDIS_STATUS
ElnkmcRegisterAdapter(
IN NDIS_HANDLE NdisMacHandle,
IN NDIS_HANDLE ConfigurationHandle,
IN PNDIS_STRING DeviceName,
IN UINT ElnkInterruptVector,
IN NDIS_PHYSICAL_ADDRESS ElnkSharedRam,
IN USHORT ElnkIOBase,
IN PUCHAR CurrentAddress,
IN UINT MaximumMulticastAddresses,
IN UINT MaximumOpenAdapters,
IN BOOLEAN ConfigError,
IN NDIS_STATUS ConfigErrorCode
)
/*++
Routine Description:
This routine (and its interface) are not portable. They are
defined by the OS and the architecture.
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:
NdisMacHandle - The handle given back to the mac from ndis when
the mac registered itself.
ConfigurationHandle - Handle passed to MacAddAdapter.
DeviceName - The string containing the name to give to the device
adapter. This name is preallocated by the caller and cannot be
reused until the adapter is unloaded.
ElnkInterruptVector - The interrupt vector to used for the adapter.
ElnkSharedRam - address of the card RAM to be mapped.
ElnkIOBase - base address of the card port I/O addresses.
CurrentAddress - the alternative address to be used by the card. If NULL,
the BIA is used.
MaximumMulticastAddresses - The maximum number of multicast
addresses to filter at any one time.
MaximumOpenAdapters - The maximum number of opens at any one time.
ConfigError - Was there a configuration error
ConfigErrorCode - The NDIS_ERROR_CODE to log as the error.
Return Value:
Returns false if anything occurred that prevents the initialization
of the adapter.
--*/
{
//
// Pointer for the adapter root.
//
PELNK_ADAPTER Adapter;
//
// status of various calls
//
NDIS_STATUS Status;
//
// adapter information
//
NDIS_ADAPTER_INFORMATION AdapterInformation;
//
// Allocate the Adapter block.
//
Status = ELNK_ALLOC_PHYS(&Adapter, sizeof(ELNK_ADAPTER));
if ( Status == NDIS_STATUS_SUCCESS ) {
NdisZeroMemory(
Adapter,
sizeof(ELNK_ADAPTER)
);
Adapter->NdisMacHandle = NdisMacHandle;
//
// Should an alternative address be used?
//
if (CurrentAddress != NULL) {
Adapter->AddressChanged = TRUE;
ETH_COPY_NETWORK_ADDRESS(
Adapter->CurrentAddress,
CurrentAddress
);
} else {
Adapter->AddressChanged = FALSE;
}
//
// Set the port addresses.
//
Adapter->IoBase = ElnkIOBase;
Adapter->CurrentCsr = CSR_DEFAULT;
Adapter->IsExternal = TRUE;
Adapter->CardOffset = 0xC000;
Adapter->SharedRamSize = 16;
Adapter->SharedRamPhys = NdisGetPhysicalAddressLow(ElnkSharedRam);
Adapter->InterruptVector = ElnkInterruptVector;
Adapter->NumberOfTransmitBuffers =
ELNKMC_NUMBER_OF_TRANSMIT_BUFFERS;
Adapter->NumberOfReceiveBuffers =
ELNKMC_NUMBER_OF_RECEIVE_BUFFERS;
Adapter->MemoryIsMapped = FALSE;
//
// Initialize the interrupt.
//
InitializeListHead(&Adapter->OpenBindings);
InitializeListHead(&Adapter->CloseList);
Adapter->IsrLevel = (KIRQL)(HIGH_LEVEL - ElnkInterruptVector);
InitializeAdapterVariables(Adapter);
ResetAdapterVariables(Adapter);
//
// We can start the chip. We may not
// have any bindings to indicate to but this
// is unimportant.
//
NdisZeroMemory(&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
AdapterInformation.DmaChannel = 0;
AdapterInformation.Master = FALSE;
AdapterInformation.AdapterType = NdisInterfaceMca;
AdapterInformation.PhysicalMapRegistersNeeded = 0;
AdapterInformation.MaximumPhysicalMapping = 0;
AdapterInformation.NumberOfPortDescriptors = 1;
AdapterInformation.PortDescriptors[0].InitialPort = (ULONG)(Adapter->IoBase);
AdapterInformation.PortDescriptors[0].NumberOfPorts = 0x10;
AdapterInformation.PortDescriptors[0].PortOffset = NULL;
if (NdisRegisterAdapter(
&Adapter->NdisAdapterHandle,
Adapter->NdisMacHandle,
Adapter,
ConfigurationHandle,
DeviceName,
&AdapterInformation
) != NDIS_STATUS_SUCCESS) {
ElnkLogError(
Adapter,
registerAdapter,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
if ELNKDEBUG DPrint1("ElnkmcRegisterAdapter: NdisRegisterAdapter failed\n");
ELNK_FREE_PHYS(Adapter);
return NDIS_STATUS_FAILURE;
}
if (ConfigError) {
ElnkLogError(
Adapter,
registerAdapter,
ConfigErrorCode,
0
);
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
ELNK_FREE_PHYS(Adapter);
return(NDIS_STATUS_FAILURE);
}
//
// Allocate adapter structures
//
if (!ElnkAllocateAdapterMemory(Adapter)) {
ElnkLogError(
Adapter,
registerAdapter,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
if ELNKDEBUG DPrint1("ElnkRegisterAdapter - unsuccessful memory allocation\n");
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
ELNK_FREE_PHYS(Adapter);
return(NDIS_STATUS_RESOURCES);
}
NdisInitializeTimer(
&Adapter->DeadmanTimer,
(PVOID) ElnkDeadmanDpc,
(PVOID) Adapter
);
NdisInitializeTimer(
&Adapter->DeferredTimer,
(PVOID) ElnkStandardInterruptDpc,
(PVOID) Adapter
);
NdisAllocateSpinLock(&Adapter->Lock);
//
// Get station address
//
ElnkGetStationAddress(Adapter);
//
// Check for validity of the address
//
if (((Adapter->NetworkAddress[0] == 0xFF) &&
(Adapter->NetworkAddress[1] == 0xFF) &&
(Adapter->NetworkAddress[2] == 0xFF) &&
(Adapter->NetworkAddress[3] == 0xFF) &&
(Adapter->NetworkAddress[4] == 0xFF) &&
(Adapter->NetworkAddress[5] == 0xFF)) ||
((Adapter->NetworkAddress[0] == 0x00) &&
(Adapter->NetworkAddress[1] == 0x00) &&
(Adapter->NetworkAddress[2] == 0x00) &&
(Adapter->NetworkAddress[3] == 0x00) &&
(Adapter->NetworkAddress[4] == 0x00) &&
(Adapter->NetworkAddress[5] == 0x00)))
{
ElnkLogError(
Adapter,
startChip,
NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
0);
return(NDIS_STATUS_FAILURE);
}
//
// Do the initial init first so we can get the adapter's address
// before creating the filter DB.
//
Adapter->FilterDB = NULL;
if (!EthCreateFilter(
MaximumMulticastAddresses,
ElnkChangeAddresses,
ElnkChangeClass,
ElnkCloseAction,
Adapter->CurrentAddress,
&Adapter->Lock,
&Adapter->FilterDB
)) {
ElnkLogError(
Adapter,
registerAdapter,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
if ELNKDEBUG
DPrint1("ElnkRegisterAdapter - unsuccessful filter create.\n");
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
NdisFreeSpinLock(&Adapter->Lock);
ELNK_FREE_PHYS(Adapter);
return NDIS_STATUS_RESOURCES;
}
if (!ElnkInitialInit(Adapter, ElnkInterruptVector))
{
EthDeleteFilter(Adapter->FilterDB);
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
NdisFreeSpinLock(&Adapter->Lock);
ELNK_FREE_PHYS(Adapter);
return NDIS_STATUS_FAILURE;
}
else
{
//
// Record it in the global adapter list.
//
NdisInterlockedInsertTailList(&ElnkAdapterList,
&Adapter->AdapterList,
&ElnkAdapterListLock
);
return NDIS_STATUS_SUCCESS;
}
} else {
if ELNKDEBUG DPrint1("ElnkRegisterAdapter - failed allocation of adapter block.\n");
return NDIS_STATUS_RESOURCES;
}
}
#else
#pragma NDIS_INIT_FUNCTION(Elnk16RegisterAdapter)
NDIS_STATUS
Elnk16RegisterAdapter(
IN NDIS_HANDLE NdisMacHandle,
IN NDIS_HANDLE ConfigurationHandle,
IN PNDIS_STRING DeviceName,
IN UINT InterruptVector,
IN NDIS_PHYSICAL_ADDRESS WinBase,
IN UINT WindowSize,
IN USHORT IoBase,
IN BOOLEAN IsExternal,
IN BOOLEAN ZwsEnabled,
IN PUCHAR CurrentAddress,
IN UINT MaximumMulticastAddresses,
IN UINT MaximumOpenAdapters,
IN BOOLEAN ConfigError,
IN NDIS_STATUS ConfigErrorCode
)
/*++
Routine Description:
This routine (and its interface) are not portable. They are
defined by the OS and the architecture.
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:
NdisMacHandle - The handle given back to the mac from ndis when
the mac registered itself.
ConfigurationHandle - Handle passed to MacAddAdapter.
DeviceName - The string containing the name to give to the device
adapter. This name is preallocated by the caller and cannot be
reused until the adapter is unloaded.
InterruptVector - The interrupt vector to used for the adapter.
WinBase - Base address of card window.
WindowSize - Size of card window.
IoBase - address of I/O base register.
IsExternal - are we using the external transceiver?
ZwsEnable - should Zero Wait Status be enabled
CurrentAddress - the alternative address to be used by the card. If NULL,
the BIA is used.
MaximumMulticastAddresses - The maximum number of multicast
addresses to filter at any one time.
MaximumOpenAdapters - The maximum number of opens at any one time.
ConfigError - Was there a configuration error
ConfigErrorCode - The NDIS_ERROR_CODE to log as the error.
Return Value:
Returns NDIS_STATUS_FAILURE if anything occurred that prevents the initialization
of the adapter.
--*/
{
//
// Pointer for the adapter root.
//
PELNK_ADAPTER Adapter;
//
// status of various calls
//
NDIS_STATUS Status;
//
// adapter information
//
NDIS_ADAPTER_INFORMATION AdapterInformation;
//
// Allocate the Adapter block.
//
Status = ELNK_ALLOC_PHYS(&Adapter, sizeof(ELNK_ADAPTER));
if ( Status == NDIS_STATUS_SUCCESS ) {
NdisZeroMemory(
Adapter,
sizeof(ELNK_ADAPTER)
);
Adapter->NdisMacHandle = NdisMacHandle;
//
// Should an alternative address be used?
//
if (CurrentAddress != NULL) {
Adapter->AddressChanged = TRUE;
ETH_COPY_NETWORK_ADDRESS(
Adapter->CurrentAddress,
CurrentAddress
);
} else {
Adapter->AddressChanged = FALSE;
}
//
// Set the port addresses.
//
Adapter->IoBase = IoBase;
Adapter->CurrentCsr = CSR_DEFAULT;
Adapter->SharedRamPhys = NdisGetPhysicalAddressLow(WinBase);
Adapter->SharedRamSize = WindowSize;
//
// Allocate memory for all of the adapter structures.
//
Adapter->MemoryIsMapped = FALSE;
//
// Initialize the interrupt.
//
InitializeListHead(&Adapter->OpenBindings);
InitializeListHead(&Adapter->CloseList);
Adapter->IsrLevel = (KIRQL)(HIGH_LEVEL - InterruptVector);
Adapter->InterruptVector = (UINT) InterruptVector;
//
// We can start the chip. We may not
// have any bindings to indicate to but this
// is unimportant.
//
NdisZeroMemory(&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
AdapterInformation.DmaChannel = 0;
AdapterInformation.Master = FALSE;
AdapterInformation.AdapterType = NdisInterfaceIsa;
AdapterInformation.PhysicalMapRegistersNeeded = 0;
AdapterInformation.MaximumPhysicalMapping = 0;
AdapterInformation.NumberOfPortDescriptors = 1;
AdapterInformation.PortDescriptors[0].InitialPort = (ULONG)(Adapter->IoBase);
AdapterInformation.PortDescriptors[0].NumberOfPorts = 0x10;
AdapterInformation.PortDescriptors[0].PortOffset = NULL;
if (NdisRegisterAdapter(
&Adapter->NdisAdapterHandle,
Adapter->NdisMacHandle,
Adapter,
ConfigurationHandle,
DeviceName,
&AdapterInformation
) != NDIS_STATUS_SUCCESS) {
ElnkLogError(
Adapter,
registerAdapter,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
if ELNKDEBUG DPrint1("Elnk16RegisterAdapter: NdisRegisterAdapter failed\n");
ELNK_FREE_PHYS(Adapter);
return NDIS_STATUS_FAILURE;
}
if (ConfigError) {
ElnkLogError(
Adapter,
registerAdapter,
ConfigErrorCode,
0
);
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
ELNK_FREE_PHYS(Adapter);
return(NDIS_STATUS_FAILURE);
}
//
// Verify the Configuration of the hardware
//
if (!Elnk16ConfigureAdapter(
Adapter,
IsExternal,
ZwsEnabled
)) {
ElnkLogError(
Adapter,
registerAdapter,
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
0
);
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
ELNK_FREE_PHYS(Adapter);
return(NDIS_STATUS_FAILURE);
}
//
// Allocate adapter structures
//
if (!ElnkAllocateAdapterMemory(Adapter)) {
ElnkLogError(
Adapter,
registerAdapter,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
if ELNKDEBUG DPrint1("ElnkRegisterAdapter - unsuccessful memory allocation\n");
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
ELNK_FREE_PHYS(Adapter);
return(NDIS_STATUS_FAILURE);
}
InitializeAdapterVariables(Adapter);
ResetAdapterVariables(Adapter);
NdisInitializeTimer(
&Adapter->DeadmanTimer,
(PVOID) ElnkDeadmanDpc,
(PVOID) Adapter
);
NdisInitializeTimer(
&Adapter->DeferredTimer,
(PVOID) ElnkStandardInterruptDpc,
(PVOID) Adapter
);
NdisAllocateSpinLock(&Adapter->Lock);
//
// Get station address
//
ElnkGetStationAddress(Adapter);
//
// Check for validity of the address
//
if (((Adapter->NetworkAddress[0] == 0xFF) &&
(Adapter->NetworkAddress[1] == 0xFF) &&
(Adapter->NetworkAddress[2] == 0xFF) &&
(Adapter->NetworkAddress[3] == 0xFF) &&
(Adapter->NetworkAddress[4] == 0xFF) &&
(Adapter->NetworkAddress[5] == 0xFF)) ||
((Adapter->NetworkAddress[0] == 0x00) &&
(Adapter->NetworkAddress[1] == 0x00) &&
(Adapter->NetworkAddress[2] == 0x00) &&
(Adapter->NetworkAddress[3] == 0x00) &&
(Adapter->NetworkAddress[4] == 0x00) &&
(Adapter->NetworkAddress[5] == 0x00)))
{
ElnkLogError(
Adapter,
startChip,
NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER,
0);
return(NDIS_STATUS_FAILURE);
}
if (!EthCreateFilter(
MaximumMulticastAddresses,
ElnkChangeAddresses,
ElnkChangeClass,
ElnkCloseAction,
Adapter->CurrentAddress,
&Adapter->Lock,
&Adapter->FilterDB
)) {
ElnkLogError(
Adapter,
registerAdapter,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
if ELNKDEBUG
DPrint1("ElnkRegisterAdapter - unsuccessful filter create.\n");
ElnkDeleteAdapterMemory(Adapter);
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
NdisFreeSpinLock(&Adapter->Lock);
ELNK_FREE_PHYS(Adapter);
return NDIS_STATUS_FAILURE;
}
if (!ElnkInitialInit(
Adapter,
Adapter->InterruptVector
)) {
EthDeleteFilter(Adapter->FilterDB);
ElnkDeleteAdapterMemory(Adapter);
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
NdisFreeSpinLock(&Adapter->Lock);
ELNK_FREE_PHYS(Adapter);
return NDIS_STATUS_FAILURE;
}
//
// Record it in the global adapter list.
//
NdisInterlockedInsertTailList(&ElnkAdapterList,
&Adapter->AdapterList,
&ElnkAdapterListLock
);
return NDIS_STATUS_SUCCESS;
} else {
if ELNKDEBUG DPrint1("ElnkRegisterAdapter - unsuccessful allocation of adapter block.\n");
return NDIS_STATUS_FAILURE;
}
}
#endif
#pragma NDIS_INIT_FUNCTION(ElnkAllocateAdapterMemory)
BOOLEAN
ElnkAllocateAdapterMemory(
IN PELNK_ADAPTER Adapter
)
/*++
Routine Description:
This routine is responsible for the allocation of the datastructures
for the Adapter structure.
Arguments:
Adapter - the adapter structure to allocate for.
Return Value:
Returns false if we cannot allocate memory.
--*/
{
NDIS_STATUS Status;
//
// add 1 for multicast block
//
Status = ELNK_ALLOC_PHYS(
&Adapter->TransmitInfo,
sizeof(ELNK_TRANSMIT_INFO) *
(Adapter->NumberOfTransmitBuffers + 1)
);
if (Status != NDIS_STATUS_SUCCESS) {
ElnkLogError(
Adapter,
allocateAdapterMemory,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
0
);
ElnkDeleteAdapterMemory(Adapter);
return(FALSE);
}
Status = ELNK_ALLOC_PHYS(
&Adapter->ReceiveInfo,
sizeof(ELNK_RECEIVE_INFO) *
Adapter->NumberOfReceiveBuffers
);
if (Status != NDIS_STATUS_SUCCESS) {
ElnkLogError(
Adapter,
allocateAdapterMemory,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
1
);
ElnkDeleteAdapterMemory(Adapter);
return(FALSE);
}
return(TRUE);
}
VOID
ElnkDeleteAdapterMemory(
IN PELNK_ADAPTER Adapter
)
/*++
Routine Description:
This routine is responsible for the deallocation of the datastructures
for the Adapter structure.
Arguments:
Adapter - the adapter structure to deallocate for.
Return Value:
None.
--*/
{
if (Adapter->TransmitInfo != NULL) {
ELNK_FREE_PHYS(Adapter->TransmitInfo);
}
if (Adapter->ReceiveInfo != NULL) {
ELNK_FREE_PHYS(Adapter->ReceiveInfo);
}
}
#pragma NDIS_INIT_FUNCTION(InitializeAdapterVariables)
VOID
InitializeAdapterVariables(
IN PELNK_ADAPTER Adapter
)
/*++
Routine Description:
This routine is initializes the adapter variables.
Arguments:
Adapter - the adapter structure to initialize
Return Value:
None.
--*/
{
//
// No long necessary -- we zero structure out and this routine is
// only called at initialinit time.
//
// Adapter->OpenCount = 0;
//
Adapter->References = 1;
Adapter->ResetInProgress = FALSE;
Adapter->ResettingOpen = NULL;
Adapter->OldParameterField = DEFAULT_PARM5;
Adapter->FirstOpen = TRUE;
Adapter->FirstReset = TRUE;
Adapter->DoingProcessing = FALSE;
Adapter->ProcessingRequests = FALSE;
Adapter->StatisticsField = 0x12345678;
//
// Packet counts
//
// No long necessary -- we zero structure out and this routine is
// only called at initialinit time.
//
// Adapter->GoodTransmits = 0;
// Adapter->GoodReceives = 0;
//
// Count of transmit errors
//
// No long necessary -- we zero structure out and this routine is
// only called at initialinit time.
//
// Adapter->RetryFailure = 0;
// Adapter->LostCarrier = 0;
// Adapter->UnderFlow = 0;
// Adapter->NoClearToSend = 0;
// Adapter->Deferred = 0;
// Adapter->OneRetry = 0;
// Adapter->MoreThanOneRetry = 0;
//
// Count of receive errors
//
// No long necessary -- we zero structure out and this routine is
// only called at initialinit time.
//
// Adapter->FrameTooShort = 0;
// Adapter->NoEofDetected = 0;
}
VOID
ResetAdapterVariables(
IN PELNK_ADAPTER Adapter
)
/*++
Routine Description:
This routine resets the adapter variables to their post reset value
Arguments:
Adapter - the adapter structure whose elements are to be reset
Return Value:
None.
--*/
{
Adapter->TransmitsQueued = 0;
Adapter->FirstRequest = NULL;
Adapter->LastRequest = NULL;
Adapter->FirstPendingCommand = ELNK_EMPTY;
Adapter->LastPendingCommand = ELNK_EMPTY;
Adapter->NextCommandBlock = 0;
Adapter->NumberOfAvailableCommandBlocks =
Adapter->NumberOfTransmitBuffers;
Adapter->FirstLoopBack = NULL;
Adapter->LastLoopBack = NULL;
Adapter->FirstFinishTransmit = NULL;
Adapter->LastFinishTransmit = NULL;
Adapter->StageOpen = TRUE;
Adapter->AlreadyProcessingStage = FALSE;
Adapter->FirstStagePacket = NULL;
Adapter->LastStagePacket = NULL;
}
STATIC
NDIS_STATUS
ElnkOpenAdapter(
OUT PNDIS_STATUS OpenErrorStatus,
OUT NDIS_HANDLE *MacBindingHandle,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE NdisBindingContext,
IN NDIS_HANDLE MacAdapterContext,
IN UINT OpenOptions,
IN PSTRING AddressingInformation OPTIONAL
)
/*++
Routine Description:
This routine is used to create an open instance of an adapter, in effect
creating a binding between an upper-level module and the MAC module over
the adapter.
Arguments:
MacBindingHandle - A pointer to a location in which the MAC stores
a context value that it uses to represent this binding.
SelectedMediumIndex - Index in MediumArray of the medium type that
the MAC wishes to be viewed as.
MediumArray - Array of medium types which a protocol supports.
MediumArraySize - Number of elements in MediumArray.
NdisBindingContext - A value to be recorded by the MAC and passed as
context whenever an indication is delivered by the MAC for this binding.
MacAdapterContext - The value associated with the adapter that is being
opened when the MAC registered the adapter with NdisRegisterAdapter.
OpenOptions - bit mask.
AddressingInformation - An optional pointer to a variable length string
containing hardware-specific information that can be used to program the
device. (This is not used by this MAC.)
Return Value:
The function value is the status of the operation. If the MAC does not
complete this request synchronously, the value would be
NDIS_STATUS_PENDING.
--*/
{
//
// The ELNK_ADAPTER that this open binding should belong too.
//
PELNK_ADAPTER Adapter;
//
// for index
//
UINT i;
//
// return status
//
NDIS_STATUS Status;
//
// Pointer to the space allocated for the binding.
//
PELNK_OPEN NewOpen;
//
// Pointer to the reserved portion of ndisrequest
//
PELNK_REQUEST_RESERVED Reserved;
//
// Holds the status that should be returned to the caller.
//
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
OpenErrorStatus; AddressingInformation; OpenOptions;
//
// If we are being removed, don't allow new opens.
//
Adapter = PELNK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
NdisInterlockedAddUlong(&Adapter->References, 1, &Adapter->Lock);
//
// Search for the medium type (802.3)
//
for (i = 0; i < MediumArraySize; i++){
if (MediumArray[i] == NdisMedium802_3){
break;
}
}
if (i == MediumArraySize){
NdisAcquireSpinLock(&Adapter->Lock);
StatusToReturn = NDIS_STATUS_UNSUPPORTED_MEDIA;
goto OpenDoDeferred;
}
*SelectedMediumIndex = i;
//
// Allocate the space for the open binding. Fill in the fields.
//
Status = ELNK_ALLOC_PHYS(&NewOpen, sizeof(ELNK_OPEN));
if (Status != NDIS_STATUS_SUCCESS) {
NdisAcquireSpinLock(&Adapter->Lock);
StatusToReturn = NDIS_STATUS_RESOURCES;
goto OpenDoDeferred;
}
*MacBindingHandle = BINDING_HANDLE_FROM_PELNK_OPEN(NewOpen);
InitializeListHead(&NewOpen->OpenList);
NewOpen->NdisBindingContext = NdisBindingContext;
NewOpen->References = 1;
NewOpen->BindingShuttingDown = FALSE;
NewOpen->OwningAdapter = Adapter;
NewOpen->ProtOptionFlags = 0;
NewOpen->OpenCloseRequest.RequestType = NdisRequestOpen;
Reserved = PELNK_RESERVED_FROM_REQUEST(&NewOpen->OpenCloseRequest);
Reserved->OpenBlock = NewOpen;
Reserved->Next = (PNDIS_REQUEST)NULL;
NdisAcquireSpinLock(&Adapter->Lock);
ElnkQueueRequest(Adapter, &NewOpen->OpenCloseRequest);
StatusToReturn = NDIS_STATUS_PENDING;
//
// Fire off the timer for the next state.
//
if (Adapter->FirstOpen) {
Adapter->FirstOpen = FALSE;
NdisSetTimer(
&Adapter->DeadmanTimer,
2000
);
}
OpenDoDeferred:
ELNK_DO_DEFERRED(Adapter);
return StatusToReturn;
}
STATIC
NDIS_STATUS
ElnkCloseAdapter(
IN NDIS_HANDLE MacBindingHandle
)
/*++
Routine Description:
This routine causes the MAC to close an open handle (binding).
Arguments:
MacBindingHandle - The context value returned by the MAC when the
adapter was opened. In reality it is a PELNK_OPEN.
Return Value:
The function value is the status of the operation.
--*/
{
//
// Elnk Adapter this open belongs to
//
PELNK_ADAPTER Adapter;
//
// Pointer to the space allocated for the binding
//
PELNK_OPEN Open;
//
// Status to return to the caller
//
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
//
// Hold the lock while we update the reference counts for the
// adapter and the open.
//
Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
NdisAcquireSpinLock(&Adapter->Lock);
Adapter->References++;
//
// Don't do anything if it's closing
//
if (!Open->BindingShuttingDown) {
PELNK_REQUEST_RESERVED Reserved = PELNK_RESERVED_FROM_REQUEST(&Open->OpenCloseRequest);
Open->OpenCloseRequest.RequestType = NdisRequestClose;
Reserved->OpenBlock = Open;
Reserved->Next = (PNDIS_REQUEST)NULL;
Open->References++;
ElnkQueueRequest(Adapter, &Open->OpenCloseRequest);
//
// Remove the creation reference.
//
Open->References--;
StatusToReturn = NDIS_STATUS_PENDING;
} else {
StatusToReturn = NDIS_STATUS_CLOSING;
}
//
// This macro assumes it is called with the lock held,
// and releases it.
//
ELNK_DO_DEFERRED(Adapter);
return StatusToReturn;
}
extern
VOID
ElnkUnloadMac(
IN NDIS_HANDLE MacMacContext
)
/*++
Routine Description:
ElnkUnload is called when the MAC is to unload itself.
Arguments:
Return Value:
None.
--*/
{
NDIS_STATUS InitStatus;
//
// If the list is empty, or we just emptied it,
// then unload ourselves.
//
ASSERT(IsListEmpty(&ElnkAdapterList));
NdisFreeSpinLock(&ElnkAdapterListLock);
NdisDeregisterMac(
&InitStatus,
ElnkMacHandle
);
NdisTerminateWrapper(
ElnkNdisWrapperHandle,
NULL
);
return;
}
#pragma NDIS_INIT_FUNCTION(ElnkAddAdapter)
#if ELNKMC
extern
NDIS_STATUS
ElnkAddAdapter(
IN NDIS_HANDLE MacMacContext,
IN NDIS_HANDLE ConfigurationHandle,
IN PNDIS_STRING AdapterName
)
/*++
Routine Description:
ElnkAddAdapter adds an adapter to the list supported
by this MAC.
Arguments:
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
--*/
{
NDIS_HANDLE ConfigHandle;
NDIS_STATUS Status;
NDIS_STRING NetAddrStr = NETWORK_ADDRESS;
UINT ChannelNumber = 0;
UINT InterruptLevel;
USHORT IoBase;
ULONG RamBase;
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
NDIS_MCA_POS_DATA McaData;
UCHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS];
PUCHAR CurrentAddress = NULL;
ULONG Length;
PVOID NetAddress;
BOOLEAN ConfigError = FALSE;
NDIS_STATUS ConfigErrorCode;
NdisOpenConfiguration(
&Status,
&ConfigHandle,
ConfigurationHandle
);
if (Status != NDIS_STATUS_SUCCESS) {
return NDIS_STATUS_FAILURE;
}
NdisReadMcaPosInformation(
&Status,
ConfigurationHandle,
&ChannelNumber,
&McaData
);
if (Status != NDIS_STATUS_SUCCESS) {
ConfigError = TRUE;
ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
goto RegisterAdapter;
}
//
// Interpret POS data
//
switch ((McaData.PosData1 & REG1_IO_BASE_MASK)>>1) {
case 0x00:
IoBase = 0x0300;
break;
case 0x01:
IoBase = 0x1300;
break;
case 0x02:
IoBase = 0x2300;
break;
case 0x03:
IoBase = 0x3300;
break;
}
switch ((McaData.PosData1 & REG1_RAM_BASE_MASK)>>3) {
case 0x00:
RamBase = 0x0C0000;
break;
case 0x01:
RamBase = 0x0C8000;
break;
case 0x02:
RamBase = 0x0D0000;
break;
case 0x03:
RamBase = 0x0D8000;
break;
}
switch ((McaData.PosData1 & REG1_INTERRUPT_LEVEL_MASK)>>6) {
case 0x00:
InterruptLevel = 12;
break;
case 0x01:
InterruptLevel = 7;
break;
case 0x02:
InterruptLevel = 3;
break;
case 0x03:
InterruptLevel = 9;
break;
}
//
// Read net address
//
NdisReadNetworkAddress(
&Status,
&NetAddress,
&Length,
ConfigHandle
);
if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
ETH_COPY_NETWORK_ADDRESS(
NetworkAddress,
NetAddress
);
CurrentAddress = NetworkAddress;
}
RegisterAdapter:
NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
NdisSetPhysicalAddressLow(PhysicalAddress, RamBase);
Status = ElnkmcRegisterAdapter(
ElnkMacHandle,
ConfigurationHandle,
AdapterName,
InterruptLevel,
PhysicalAddress,
IoBase,
CurrentAddress,
ELNK_MAXIMUM_MULTICAST,
32,
ConfigError,
ConfigErrorCode
);
NdisCloseConfiguration(ConfigHandle);
return Status;
}
#else
extern
NDIS_STATUS
ElnkAddAdapter(
IN NDIS_HANDLE MacMacContext,
IN NDIS_HANDLE ConfigurationHandle,
IN PNDIS_STRING AdapterName
)
/*++
Routine Description:
ElnkAddAdapter adds an adapter to the list supported
by this MAC.
Arguments:
Return Value:
NDIS_STATUS_SUCCESS
NDIS_STATUS_PENDING
--*/
{
NDIS_HANDLE ConfigHandle;
NDIS_STATUS Status;
PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
NDIS_STRING NetAddrStr = NETWORK_ADDRESS;
NDIS_STRING TransStr = NDIS_STRING_CONST("Transceiver");
NDIS_STRING InterruptStr = NDIS_STRING_CONST("InterruptNumber");
NDIS_STRING IoPortStr = IOBASE;
NDIS_STRING RamBaseStr = NDIS_STRING_CONST("MemoryMappedBaseAddress");
NDIS_STRING ZWStr = NDIS_STRING_CONST("ZeroWaitState");
NDIS_STRING RamSizeStr = NDIS_STRING_CONST("MemoryMappedSize");
USHORT IoBase;
UINT InterruptVector;
BOOLEAN IsExternal;
BOOLEAN ZwsEnabled;
ULONG WindowBase;
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
UINT WindowSize;
UCHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS];
PUCHAR CurrentAddress = NULL;
ULONG Length;
PVOID NetAddress;
BOOLEAN ConfigError = FALSE;
NDIS_STATUS ConfigErrorCode;
NdisOpenConfiguration(
&Status,
&ConfigHandle,
ConfigurationHandle
);
if (Status != NDIS_STATUS_SUCCESS) {
return NDIS_STATUS_FAILURE;
}
//
// Read net address
//
NdisReadNetworkAddress(
&Status,
&NetAddress,
&Length,
ConfigHandle
);
if ((Length == ETH_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
ETH_COPY_NETWORK_ADDRESS(
NetworkAddress,
NetAddress
);
CurrentAddress = NetworkAddress;
}
#if NDIS_NT
//
// Let's get the interrupt number
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&InterruptStr,
NdisParameterInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
InterruptVector = ReturnedValue->ParameterData.IntegerData;
} else {
InterruptVector = ELNK16_DEFAULT_INTERRUPT_VECTOR;
}
{
UCHAR i;
static UINT Interrupts[] = {3,5,7,9,10,11,12,15};
for (i=0; i < 8; i++) {
if (Interrupts[i] == InterruptVector) {
break;
}
}
if (i == 8) {
ConfigError = TRUE;
ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
goto RegisterAdapter;
}
}
#endif // NDIS_NT
//
// Get the Io Port
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&IoPortStr,
NdisParameterHexInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
IoBase = (USHORT) ReturnedValue->ParameterData.IntegerData;
} else {
IoBase = ELNK16_DEFAULT_IOBASE;
}
{
UINT i;
for (i=0x200; i < 0x3f0; i += 0x10) {
if ((i == 0x270) ||
// (i == 0x290) ||
(i == 0x2f0) ||
(i == 0x370) ||
(i == 0x3b0) ||
(i == 0x3c0) ||
(i == 0x3d0)) {
continue;
}
if (i == IoBase) {
break;
}
}
if (i != IoBase) {
ConfigError = TRUE;
ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
goto RegisterAdapter;
}
}
#if NDIS_NT
//
// Get the RamBase
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&RamBaseStr,
NdisParameterHexInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
WindowBase = ReturnedValue->ParameterData.IntegerData;
} else {
WindowBase = ELNK16_DEFAULT_WINBASE;
}
if ((WindowBase < 0xC0000) ||
(WindowBase > 0xDFFFF) ||
((WindowBase & 0x3FFF) != 0x0)) {
ConfigError = TRUE;
ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
goto RegisterAdapter;
}
//
// Let's get the size of the Window
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&RamSizeStr,
NdisParameterHexInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
WindowSize = ReturnedValue->ParameterData.IntegerData;
} else {
WindowSize = ELNK16_DEFAULT_WINDOW_SIZE;
}
//
// Convert to local method
//
WindowSize = WindowSize >> 10;
if ((WindowSize != 16) &&
(WindowSize != 32) &&
(WindowSize != 48) &&
(WindowSize != 64)) {
ConfigError = TRUE;
ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
goto RegisterAdapter;
}
//
// Are we using External Transceiver?
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&TransStr,
NdisParameterInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
IsExternal = (ReturnedValue->ParameterData.IntegerData == 1)?TRUE:FALSE;
} else {
IsExternal = TRUE;
}
//
// Do we want to enable Zero wait state
//
NdisReadConfiguration(
&Status,
&ReturnedValue,
ConfigHandle,
&ZWStr,
NdisParameterInteger
);
if (Status == NDIS_STATUS_SUCCESS) {
ZwsEnabled = (ReturnedValue->ParameterData.IntegerData == 1)?TRUE:FALSE;
} else {
ZwsEnabled = TRUE;
}
#endif // NDIS_NT
#if NDIS_WIN
// use defaults for now. We will read these values from eeprom.
InterruptVector = ELNK16_DEFAULT_INTERRUPT_VECTOR;
WindowBase = ELNK16_DEFAULT_WINBASE;
WindowSize = ELNK16_DEFAULT_WINDOW_SIZE;
IsExternal = TRUE;
ZwsEnabled = TRUE;
#endif // NDIS_WIN
RegisterAdapter:
NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
NdisSetPhysicalAddressLow(PhysicalAddress, WindowBase);
Status = Elnk16RegisterAdapter(
ElnkMacHandle,
ConfigurationHandle,
AdapterName,
InterruptVector,
PhysicalAddress,
WindowSize,
IoBase,
IsExternal,
ZwsEnabled,
CurrentAddress,
ELNK_MAXIMUM_MULTICAST,
32,
ConfigError,
ConfigErrorCode
);
if (Status != NDIS_STATUS_SUCCESS) {
if ELNKDEBUG DPrint1("Elnk16AddAdapter: Elnk16RegisterAdapter failed\n");
}
NdisCloseConfiguration(ConfigHandle);
return Status;
}
#endif
extern
VOID
ElnkRemoveAdapter(
IN NDIS_HANDLE MacAdapterContext
)
/*++
Routine Description:
ElnkRemoveAdapter removes an adapter previously registered
with NdisRegisterAdapter.
Arguments:
MacAdapterContext - The context value that the MAC passed
to NdisRegisterAdapter; actually as pointer to a
ELNK_ADAPTER.
Return Value:
None.
--*/
{
PELNK_ADAPTER Adapter;
BOOLEAN Cancelled;
Adapter = PELNK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
ASSERT(Adapter->OpenCount == 0);
//
// There are no opens left, so remove ourselves.
//
NdisCancelTimer(&Adapter->DeadmanTimer,&Cancelled);
NdisRemoveInterrupt(&Adapter->Interrupt);
EthDeleteFilter(Adapter->FilterDB);
NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
NdisFreeSpinLock(&Adapter->Lock);
NdisAcquireSpinLock(&ElnkAdapterListLock);
RemoveEntryList(&Adapter->AdapterList);
NdisReleaseSpinLock(&ElnkAdapterListLock);
ELNK_FREE_PHYS(Adapter);
#if !ELNKMC
//
// Put the card in START state. This leaves the
// card in the same state as a hardware powerup.
// This guarantees that the card is in a known workable
// state if an additional AddAdapter is issued before the
// power has been cycled. Otherwise, the AddAdapter fails.
//
// Go to Run state
NdisRawWritePortUchar(ELNK16_ID_PORT,0x00);
Elnk16GenerateIdPattern(Adapter);
NdisRawWritePortUchar(ELNK16_ID_PORT,0x00);
// Go to Reset state
Elnk16GenerateIdPattern(Adapter);
// Go to IoLoad state
Elnk16GenerateIdPattern(Adapter);
// Go to Config state
NdisRawWritePortUchar(ELNK16_ID_PORT,(UCHAR)0xFF);
// Reset the card, which leaves the card in Start state
NdisRawWritePortUchar(ELNK16_ICR,ICR_RESET);
#endif
return;
}