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.
2497 lines
58 KiB
2497 lines
58 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ne3200.c
|
|
|
|
Abstract:
|
|
|
|
This is the main file 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>
|
|
#include "keywords.h"
|
|
|
|
//
|
|
// Global data block for holding MAC.BIN infomormation.
|
|
//
|
|
NE3200_GLOBAL_DATA NE3200Globals = {0};
|
|
BOOLEAN FirstAdd = TRUE;
|
|
|
|
//
|
|
// Global for the largest acceptable piece of memory
|
|
//
|
|
NDIS_PHYSICAL_ADDRESS MinusOne = NDIS_PHYSICAL_ADDRESS_CONST (-1, -1);
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// Debugging flags for various debugging modes.
|
|
//
|
|
ULONG NE3200Debug = 0 ; // NE3200_DEBUG_LOUD |
|
|
// NE3200_DEBUG_ACQUIRE |
|
|
// NE3200_DEBUG_SUBMIT |
|
|
// NE3200_DEBUG_DUMP_COMMAND
|
|
// ;
|
|
#endif
|
|
|
|
|
|
//
|
|
// Forward declarations for functions in this file
|
|
//
|
|
STATIC
|
|
BOOLEAN
|
|
NE3200AllocateAdapterMemory(
|
|
IN PNE3200_ADAPTER Adapter
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
NE3200DeleteAdapterMemory(
|
|
IN PNE3200_ADAPTER Adapter
|
|
);
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
NE3200InitialInit(
|
|
IN PNE3200_ADAPTER Adapter,
|
|
IN UINT NE3200InterruptVector,
|
|
IN NDIS_INTERRUPT_MODE NE3200InterruptMode
|
|
);
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
NE3200InitializeGlobals(
|
|
OUT PNE3200_GLOBAL_DATA Globals,
|
|
IN NDIS_HANDLE MiniportAdapterHandle
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
NE3200DestroyGlobals(
|
|
IN PNE3200_GLOBAL_DATA Globals
|
|
);
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
|
|
VOID
|
|
NE3200Shutdown(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
);
|
|
|
|
#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 NE3200 driver.
|
|
It is simply responsible for the intializing the wrapper and registering
|
|
the Miniport driver. It then calls a system and architecture specific
|
|
routine that will initialize and register each adapter.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by the system.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Receives the status of the NdisRegisterMiniport operation.
|
|
//
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// The characteristics table
|
|
//
|
|
NDIS_MINIPORT_CHARACTERISTICS NE3200Char;
|
|
|
|
//
|
|
// The handle returned by NdisMInitializeWrapper
|
|
//
|
|
NDIS_HANDLE NdisWrapperHandle;
|
|
|
|
#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)=EISA_NE3200_IDENTIFICATION;
|
|
(PVOID)DriverObject=(PVOID)pIds;
|
|
#endif
|
|
|
|
//
|
|
// Initialize the wrapper.
|
|
//
|
|
NdisMInitializeWrapper(
|
|
&NdisWrapperHandle,
|
|
DriverObject,
|
|
RegistryPath,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Initialize the Miniport characteristics for the call to
|
|
// NdisMRegisterMiniport.
|
|
//
|
|
NE3200Globals.NE3200NdisWrapperHandle = NdisWrapperHandle;
|
|
|
|
NE3200Char.MajorNdisVersion = NE3200_NDIS_MAJOR_VERSION;
|
|
NE3200Char.MinorNdisVersion = NE3200_NDIS_MINOR_VERSION;
|
|
NE3200Char.CheckForHangHandler = NE3200CheckForHang;
|
|
NE3200Char.DisableInterruptHandler = NE3200DisableInterrupt;
|
|
NE3200Char.EnableInterruptHandler = NE3200EnableInterrupt;
|
|
NE3200Char.HaltHandler = NE3200Halt;
|
|
NE3200Char.HandleInterruptHandler = NE3200HandleInterrupt;
|
|
NE3200Char.InitializeHandler = NE3200Initialize;
|
|
NE3200Char.ISRHandler = NE3200Isr;
|
|
NE3200Char.QueryInformationHandler = NE3200QueryInformation;
|
|
NE3200Char.ReconfigureHandler = NULL;
|
|
NE3200Char.ResetHandler = NE3200Reset;
|
|
NE3200Char.SendHandler = NE3200Send;
|
|
NE3200Char.SetInformationHandler = NE3200SetInformation;
|
|
NE3200Char.TransferDataHandler = NE3200TransferData;
|
|
|
|
//
|
|
// Register this driver with NDIS
|
|
//
|
|
Status = NdisMRegisterMiniport(
|
|
NdisWrapperHandle,
|
|
&NE3200Char,
|
|
sizeof(NE3200Char)
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// We can only get here if something went wrong with registering
|
|
// the driver or *all* of the adapters.
|
|
//
|
|
NE3200DestroyGlobals(&NE3200Globals);
|
|
NdisTerminateWrapper(NdisWrapperHandle, NULL);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
#pragma NDIS_INIT_FUNCTION(NE3200RegisterAdapter)
|
|
|
|
BOOLEAN
|
|
NE3200RegisterAdapter(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN UINT EisaSlot,
|
|
IN UINT InterruptVector,
|
|
IN NDIS_INTERRUPT_MODE InterruptMode,
|
|
IN PUCHAR CurrentAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
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 by ndis identifying this mini-port.
|
|
|
|
EisaSlot - The EISA Slot Number for this NE3200 adapter.
|
|
|
|
InterruptVector - The interrupt vector to used for the adapter.
|
|
|
|
InterruptMode - The interrupt mode (Latched or LevelSensitive)
|
|
used for this adapter.
|
|
|
|
CurrentAddress - The address the card will assume. If this is NULL,
|
|
then the card will use the BIA.
|
|
|
|
Return Value:
|
|
|
|
Returns false if anything occurred that prevents the initialization
|
|
of the adapter.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Status of nt calls
|
|
//
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Pointer for the adapter root.
|
|
//
|
|
PNE3200_ADAPTER Adapter;
|
|
|
|
//
|
|
// All of the code that manipulates physical addresses depends
|
|
// on the fact that physical addresses are 4 byte quantities.
|
|
//
|
|
ASSERT(sizeof(NE3200_PHYSICAL_ADDRESS) == 4);
|
|
|
|
//
|
|
// Allocate the Adapter block.
|
|
//
|
|
NE3200_ALLOC_PHYS(&Status, &Adapter, sizeof(NE3200_ADAPTER));
|
|
|
|
if ( Status == NDIS_STATUS_SUCCESS ) {
|
|
|
|
//
|
|
// The IoBase Address for this adapter
|
|
//
|
|
ULONG AdapterIoBase;
|
|
|
|
//
|
|
// The resulting mapped base address
|
|
//
|
|
PUCHAR MappedIoBase;
|
|
|
|
//
|
|
// Initialize the adapter structure to all zeros
|
|
//
|
|
NdisZeroMemory(
|
|
Adapter,
|
|
sizeof(NE3200_ADAPTER)
|
|
);
|
|
|
|
#if DBG
|
|
Adapter->LogAddress = Adapter->Log;
|
|
#endif
|
|
|
|
//
|
|
// Save the adapter handle
|
|
//
|
|
Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
|
|
|
|
//
|
|
// Compute the base address
|
|
//
|
|
AdapterIoBase = (ULONG)(EisaSlot << 12);
|
|
|
|
//
|
|
// Save the base address
|
|
//
|
|
Adapter->AdapterIoBase = AdapterIoBase;
|
|
|
|
//
|
|
// Set the attributes for this adapter
|
|
//
|
|
NdisMSetAttributes(
|
|
MiniportAdapterHandle,
|
|
(NDIS_HANDLE)Adapter,
|
|
TRUE,
|
|
NdisInterfaceEisa
|
|
);
|
|
|
|
//
|
|
// Register the reset port addresses.
|
|
//
|
|
Status = NdisMRegisterIoPortRange(
|
|
(PVOID *)(&(Adapter->ResetPort)),
|
|
MiniportAdapterHandle,
|
|
AdapterIoBase,
|
|
0x4
|
|
);
|
|
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NE3200_FREE_PHYS(Adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Register the command ports
|
|
//
|
|
Status = NdisMRegisterIoPortRange(
|
|
(PVOID *)(&(MappedIoBase)),
|
|
MiniportAdapterHandle,
|
|
AdapterIoBase + NE3200_ID_PORT,
|
|
0x20
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NE3200_FREE_PHYS(Adapter);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase,
|
|
4,
|
|
(PVOID)Adapter->ResetPort
|
|
);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Allocate the map registers
|
|
//
|
|
Status = NdisMAllocateMapRegisters(
|
|
MiniportAdapterHandle,
|
|
0,
|
|
FALSE,
|
|
NE3200_NUMBER_OF_COMMAND_BLOCKS * NE3200_MAXIMUM_BLOCKS_PER_PACKET,
|
|
MAXIMUM_ETHERNET_PACKET_SIZE
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NE3200_FREE_PHYS(Adapter);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase,
|
|
4,
|
|
(PVOID)Adapter->ResetPort
|
|
);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase + NE3200_ID_PORT,
|
|
0x20,
|
|
(PVOID)MappedIoBase
|
|
);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Should an alternative ethernet address be used?
|
|
//
|
|
if (CurrentAddress != NULL) {
|
|
|
|
Adapter->AddressChanged = TRUE;
|
|
|
|
NdisMoveMemory(
|
|
Adapter->CurrentAddress,
|
|
CurrentAddress,
|
|
NE3200_LENGTH_OF_ADDRESS
|
|
);
|
|
} else {
|
|
|
|
Adapter->AddressChanged = FALSE;
|
|
}
|
|
|
|
//
|
|
// Save the eisa slot number
|
|
//
|
|
Adapter->EisaSlot = EisaSlot;
|
|
//DbgPrint( "NE3200: Adapter %x is slot %d\n", Adapter, EisaSlot );
|
|
|
|
//
|
|
// ResetPort is set by NdisRegisterAdapter.
|
|
// MappedIoBase is set in NdisRegisterAdapter to be the mapped
|
|
// of NE3200_ID_PORT. Now we set the other ports based on
|
|
// this offset.
|
|
//
|
|
Adapter->SystemInterruptPort = MappedIoBase + NE3200_SYSTEM_INTERRUPT_PORT - NE3200_ID_PORT;
|
|
Adapter->LocalDoorbellInterruptPort = MappedIoBase + NE3200_LOCAL_DOORBELL_INTERRUPT_PORT - NE3200_ID_PORT;
|
|
Adapter->SystemDoorbellMaskPort = MappedIoBase + NE3200_SYSTEM_DOORBELL_MASK_PORT - NE3200_ID_PORT;
|
|
Adapter->SystemDoorbellInterruptPort = MappedIoBase + NE3200_SYSTEM_DOORBELL_INTERRUPT_PORT - NE3200_ID_PORT;
|
|
Adapter->BaseMailboxPort = MappedIoBase + NE3200_BASE_MAILBOX_PORT - NE3200_ID_PORT;
|
|
|
|
//
|
|
// Allocate the global resources if needed.
|
|
//
|
|
if (FirstAdd) {
|
|
|
|
if (!NE3200InitializeGlobals(&NE3200Globals, Adapter->MiniportAdapterHandle)) {
|
|
|
|
NdisMFreeMapRegisters(MiniportAdapterHandle);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase,
|
|
4,
|
|
(PVOID)Adapter->ResetPort
|
|
);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase + NE3200_ID_PORT,
|
|
0x20,
|
|
(PVOID)MappedIoBase
|
|
);
|
|
NE3200_FREE_PHYS(Adapter);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
FirstAdd = FALSE;
|
|
}
|
|
|
|
//
|
|
// Setup default numbers for resources
|
|
//
|
|
Adapter->NumberOfTransmitBuffers = NE3200_NUMBER_OF_TRANSMIT_BUFFERS;
|
|
Adapter->NumberOfReceiveBuffers = NE3200_NUMBER_OF_RECEIVE_BUFFERS;
|
|
Adapter->NumberOfCommandBlocks = NE3200_NUMBER_OF_COMMAND_BLOCKS;
|
|
Adapter->NumberOfPublicCommandBlocks = NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS;
|
|
|
|
//
|
|
// Allocate memory for all of the adapter structures.
|
|
//
|
|
if (NE3200AllocateAdapterMemory(Adapter)) {
|
|
|
|
//
|
|
// Set the initial internal state
|
|
//
|
|
NE3200ResetVariables(Adapter);
|
|
|
|
//
|
|
// Initialize the timer for doing asynchronous resets
|
|
//
|
|
NdisMInitializeTimer(
|
|
&Adapter->ResetTimer,
|
|
MiniportAdapterHandle,
|
|
(PVOID) NE3200ResetHandler,
|
|
(PVOID) Adapter
|
|
);
|
|
|
|
//
|
|
// Now start the adapter
|
|
//
|
|
if (!NE3200InitialInit(
|
|
Adapter,
|
|
InterruptVector,
|
|
InterruptMode
|
|
)) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
|
0
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
NdisMFreeMapRegisters(MiniportAdapterHandle);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase,
|
|
4,
|
|
(PVOID)Adapter->ResetPort
|
|
);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase + NE3200_ID_PORT,
|
|
0x20,
|
|
(PVOID)MappedIoBase
|
|
);
|
|
NE3200_FREE_PHYS(Adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Enable further interrupts.
|
|
//
|
|
NE3200_WRITE_SYSTEM_DOORBELL_MASK(
|
|
Adapter,
|
|
NE3200_SYSTEM_DOORBELL_MASK
|
|
);
|
|
|
|
//
|
|
// Record it in the global adapter list.
|
|
//
|
|
|
|
InsertTailList(&NE3200Globals.AdapterList,
|
|
&Adapter->AdapterList,
|
|
);
|
|
|
|
//
|
|
// Register our shutdown handler.
|
|
//
|
|
|
|
NdisMRegisterAdapterShutdownHandler(
|
|
Adapter->MiniportAdapterHandle, // miniport handle.
|
|
Adapter, // shutdown context.
|
|
NE3200Shutdown // shutdown handler.
|
|
);
|
|
|
|
return(TRUE);
|
|
|
|
} else {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
registerAdapter,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
0
|
|
);
|
|
|
|
NdisMFreeMapRegisters(MiniportAdapterHandle);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase,
|
|
4,
|
|
(PVOID)Adapter->ResetPort
|
|
);
|
|
NdisMDeregisterIoPortRange(MiniportAdapterHandle,
|
|
AdapterIoBase + NE3200_ID_PORT,
|
|
0x20,
|
|
(PVOID)MappedIoBase
|
|
);
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
registerAdapter,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
1
|
|
);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
#pragma NDIS_INIT_FUNCTION(NE3200AllocateAdapterMemory)
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
NE3200AllocateAdapterMemory(
|
|
IN PNE3200_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates memory for:
|
|
|
|
- Configuration Block
|
|
|
|
- Command Queue
|
|
|
|
- Receive Queue
|
|
|
|
- Receive Buffers
|
|
|
|
- Transmit Buffers for use if user transmit buffers don't meet hardware
|
|
contraints
|
|
|
|
- Structures to map Command Queue entries back to the packets.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter to allocate memory for.
|
|
|
|
Return Value:
|
|
|
|
Returns FALSE if some memory needed for the adapter could not
|
|
be allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Status of allocation
|
|
//
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Allocate the public command block
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
sizeof(NE3200_SUPER_COMMAND_BLOCK) * NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS,
|
|
FALSE,
|
|
(PVOID *) &Adapter->PublicCommandQueue,
|
|
&Adapter->PublicCommandQueuePhysical
|
|
);
|
|
|
|
if (Adapter->PublicCommandQueue == NULL) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
1
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate the card multicast table
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY *
|
|
NE3200_MAXIMUM_MULTICAST,
|
|
FALSE, // noncached
|
|
(PVOID*)&Adapter->CardMulticastTable,
|
|
&Adapter->CardMulticastTablePhysical
|
|
);
|
|
|
|
if (Adapter->CardMulticastTable == NULL) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
2
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate the Configuration Block.
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
sizeof(NE3200_CONFIGURATION_BLOCK),
|
|
FALSE, // noncached
|
|
(PVOID*)&Adapter->ConfigurationBlock,
|
|
&Adapter->ConfigurationBlockPhysical
|
|
);
|
|
|
|
if (Adapter->ConfigurationBlock == NULL) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
3
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Allocate the Padding Buffer used to pad very short
|
|
// packets to the minimum Ethernet packet size (60 bytes).
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
MINIMUM_ETHERNET_PACKET_SIZE,
|
|
FALSE,
|
|
(PVOID*)&Adapter->PaddingVirtualAddress,
|
|
&Adapter->PaddingPhysicalAddress
|
|
);
|
|
|
|
if (Adapter->PaddingVirtualAddress == NULL) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
4
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Zero the Padding Buffer so we don't pad with garbage.
|
|
//
|
|
NdisZeroMemory(
|
|
Adapter->PaddingVirtualAddress,
|
|
MINIMUM_ETHERNET_PACKET_SIZE
|
|
);
|
|
|
|
|
|
//
|
|
// Allocate the Command Queue.
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
sizeof(NE3200_SUPER_COMMAND_BLOCK) *
|
|
Adapter->NumberOfCommandBlocks,
|
|
FALSE,
|
|
(PVOID*)&Adapter->CommandQueue,
|
|
&Adapter->CommandQueuePhysical
|
|
);
|
|
|
|
|
|
if (!Adapter->CommandQueue) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
5
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Set the tail pointer
|
|
//
|
|
Adapter->LastCommandBlockAllocated =
|
|
Adapter->CommandQueue + Adapter->NumberOfCommandBlocks;
|
|
|
|
//
|
|
// Clear the command list
|
|
//
|
|
NdisZeroMemory(
|
|
Adapter->CommandQueue,
|
|
sizeof(NE3200_SUPER_COMMAND_BLOCK) * Adapter->NumberOfCommandBlocks
|
|
);
|
|
|
|
//
|
|
// 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;
|
|
|
|
NdisSetPhysicalAddressHigh (CurrentCommandBlock->Self, 0);
|
|
NdisSetPhysicalAddressLow(
|
|
CurrentCommandBlock->Self,
|
|
NdisGetPhysicalAddressLow(Adapter->CommandQueuePhysical) +
|
|
i * sizeof(NE3200_SUPER_COMMAND_BLOCK));
|
|
|
|
CurrentCommandBlock->AvailableCommandBlockCounter =
|
|
&Adapter->NumberOfAvailableCommandBlocks;
|
|
CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
|
|
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;
|
|
|
|
NdisSetPhysicalAddressHigh (CurrentCommandBlock->Self, 0);
|
|
NdisSetPhysicalAddressLow(
|
|
CurrentCommandBlock->Self,
|
|
NdisGetPhysicalAddressLow(Adapter->PublicCommandQueuePhysical) +
|
|
i * sizeof(NE3200_SUPER_COMMAND_BLOCK));
|
|
|
|
CurrentCommandBlock->AvailableCommandBlockCounter =
|
|
&Adapter->NumberOfPublicCommandBlocks;
|
|
CurrentCommandBlock->CommandBlockIndex = (USHORT)i;
|
|
CurrentCommandBlock->Timeout = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate Flush Buffer Pool
|
|
//
|
|
NdisAllocateBufferPool(
|
|
&Status,
|
|
(PVOID*)&Adapter->FlushBufferPoolHandle,
|
|
NE3200_NUMBER_OF_TRANSMIT_BUFFERS +
|
|
Adapter->NumberOfReceiveBuffers
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
6
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Allocate the Receive Queue.
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
sizeof(NE3200_SUPER_RECEIVE_ENTRY) *
|
|
Adapter->NumberOfReceiveBuffers,
|
|
FALSE,
|
|
(PVOID*)&Adapter->ReceiveQueue,
|
|
&Adapter->ReceiveQueuePhysical
|
|
);
|
|
|
|
if (!Adapter->ReceiveQueue) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
7
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Clear the receive ring
|
|
//
|
|
NdisZeroMemory(
|
|
Adapter->ReceiveQueue,
|
|
sizeof(NE3200_SUPER_RECEIVE_ENTRY) * Adapter->NumberOfReceiveBuffers
|
|
);
|
|
|
|
|
|
//
|
|
// Allocate the receive buffers and attach them to the Receive
|
|
// Queue entries.
|
|
//
|
|
for(
|
|
i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
|
|
i < Adapter->NumberOfReceiveBuffers;
|
|
i++, CurrentReceiveEntry++
|
|
) {
|
|
|
|
//
|
|
// Allocate the actual receive buffers
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
NE3200_SIZE_OF_RECEIVE_BUFFERS,
|
|
TRUE,
|
|
&CurrentReceiveEntry->ReceiveBuffer,
|
|
&CurrentReceiveEntry->ReceiveBufferPhysical
|
|
);
|
|
|
|
if (!CurrentReceiveEntry->ReceiveBuffer) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
8
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Build flush buffers
|
|
//
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&CurrentReceiveEntry->FlushBuffer,
|
|
Adapter->FlushBufferPoolHandle,
|
|
CurrentReceiveEntry->ReceiveBuffer,
|
|
NE3200_SIZE_OF_RECEIVE_BUFFERS
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
9
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Initialize receive buffers
|
|
//
|
|
NdisFlushBuffer(CurrentReceiveEntry->FlushBuffer, FALSE);
|
|
|
|
CurrentReceiveEntry->Hardware.State = NE3200_STATE_FREE;
|
|
CurrentReceiveEntry->Hardware.FrameSize = NE3200_SIZE_OF_RECEIVE_BUFFERS;
|
|
CurrentReceiveEntry->Hardware.NextPending =
|
|
NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) +
|
|
(i + 1) * sizeof(NE3200_SUPER_RECEIVE_ENTRY);
|
|
|
|
CurrentReceiveEntry->Hardware.BufferDescriptor.BlockLength =
|
|
NE3200_SIZE_OF_RECEIVE_BUFFERS;
|
|
CurrentReceiveEntry->Hardware.BufferDescriptor.PhysicalAddress =
|
|
NdisGetPhysicalAddressLow(CurrentReceiveEntry->ReceiveBufferPhysical);
|
|
|
|
NdisSetPhysicalAddressHigh (CurrentReceiveEntry->Self, 0);
|
|
NdisSetPhysicalAddressLow(
|
|
CurrentReceiveEntry->Self,
|
|
NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) +
|
|
i * 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;
|
|
|
|
//
|
|
// Allocate the array of buffer descriptors.
|
|
//
|
|
NE3200_ALLOC_PHYS(
|
|
&Status,
|
|
&Adapter->NE3200Buffers,
|
|
sizeof(NE3200_BUFFER_DESCRIPTOR)*
|
|
(NE3200_NUMBER_OF_TRANSMIT_BUFFERS)
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
0xA
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Zero the memory of all the descriptors so that we can
|
|
// know which buffers weren't allocated incase we can't allocate
|
|
// them all.
|
|
//
|
|
NdisZeroMemory(
|
|
Adapter->NE3200Buffers,
|
|
sizeof(NE3200_BUFFER_DESCRIPTOR)*
|
|
(NE3200_NUMBER_OF_TRANSMIT_BUFFERS)
|
|
);
|
|
|
|
|
|
//
|
|
// Allocate each of the buffers and fill in the
|
|
// buffer descriptor.
|
|
//
|
|
Adapter->NE3200BufferListHead = 0;
|
|
|
|
for (
|
|
i = 0;
|
|
i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS;
|
|
i++
|
|
) {
|
|
|
|
//
|
|
// Allocate a buffer
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
NE3200_SIZE_OF_TRANSMIT_BUFFERS,
|
|
TRUE,
|
|
&Adapter->NE3200Buffers[i].VirtualNE3200Buffer,
|
|
&Adapter->NE3200Buffers[i].PhysicalNE3200Buffer
|
|
);
|
|
|
|
if (!Adapter->NE3200Buffers[i].VirtualNE3200Buffer) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
0xB
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Build flush buffers
|
|
//
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&Adapter->NE3200Buffers[i].FlushBuffer,
|
|
Adapter->FlushBufferPoolHandle,
|
|
Adapter->NE3200Buffers[i].VirtualNE3200Buffer,
|
|
NE3200_SIZE_OF_TRANSMIT_BUFFERS
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
|
3,
|
|
allocateAdapterMemory,
|
|
NE3200_ERRMSG_ALLOC_MEM,
|
|
0xC
|
|
);
|
|
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Insert this buffer into the queue
|
|
//
|
|
Adapter->NE3200Buffers[i].Next = i+1;
|
|
Adapter->NE3200Buffers[i].BufferSize = NE3200_SIZE_OF_TRANSMIT_BUFFERS;
|
|
|
|
}
|
|
|
|
//
|
|
// Make sure that the last buffer correctly terminates the free list.
|
|
//
|
|
Adapter->NE3200Buffers[i-1].Next = -1;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
NE3200DeleteAdapterMemory(
|
|
IN PNE3200_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deallocates memory for:
|
|
|
|
- Command Queue.
|
|
|
|
- Receive Queue.
|
|
|
|
- Receive buffers
|
|
|
|
- Transmit Buffers for use if user transmit buffers don't meet hardware
|
|
contraints
|
|
|
|
- Structures to map transmit ring entries back to the packets.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter to deallocate memory for.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Do the public command queue
|
|
//
|
|
if (Adapter->PublicCommandQueue) {
|
|
NdisMFreeSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
sizeof(NE3200_SUPER_COMMAND_BLOCK) * NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS,
|
|
FALSE,
|
|
Adapter->PublicCommandQueue,
|
|
Adapter->PublicCommandQueuePhysical
|
|
);
|
|
}
|
|
|
|
//
|
|
// The table for downloading multicast addresses
|
|
//
|
|
if (Adapter->CardMulticastTable) {
|
|
NdisMFreeSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY *
|
|
NE3200_MAXIMUM_MULTICAST,
|
|
FALSE,
|
|
Adapter->CardMulticastTable,
|
|
Adapter->CardMulticastTablePhysical
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// The configuration block
|
|
//
|
|
if (Adapter->ConfigurationBlock) {
|
|
|
|
NdisMFreeSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
sizeof(NE3200_CONFIGURATION_BLOCK),
|
|
FALSE,
|
|
Adapter->ConfigurationBlock,
|
|
Adapter->ConfigurationBlockPhysical
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// The pad buffer for short packets
|
|
//
|
|
if (Adapter->PaddingVirtualAddress) {
|
|
|
|
NdisMFreeSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
MINIMUM_ETHERNET_PACKET_SIZE,
|
|
FALSE,
|
|
Adapter->PaddingVirtualAddress,
|
|
Adapter->PaddingPhysicalAddress
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// The private command blocks
|
|
//
|
|
if (Adapter->CommandQueue) {
|
|
|
|
NdisMFreeSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
sizeof(NE3200_SUPER_COMMAND_BLOCK) *
|
|
Adapter->NumberOfCommandBlocks,
|
|
FALSE,
|
|
Adapter->CommandQueue,
|
|
Adapter->CommandQueuePhysical
|
|
);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// The receive buffers
|
|
//
|
|
if (Adapter->ReceiveQueue) {
|
|
|
|
//
|
|
// Pointer to current Receive Entry being deallocated.
|
|
//
|
|
PNE3200_SUPER_RECEIVE_ENTRY CurrentReceiveEntry;
|
|
|
|
//
|
|
// Simple iteration counter.
|
|
//
|
|
UINT i;
|
|
|
|
|
|
for(
|
|
i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue;
|
|
i < Adapter->NumberOfReceiveBuffers;
|
|
i++, CurrentReceiveEntry++
|
|
) {
|
|
|
|
|
|
if (CurrentReceiveEntry->ReceiveBuffer) {
|
|
|
|
//
|
|
// Free the memory
|
|
//
|
|
NdisMFreeSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
NE3200_SIZE_OF_RECEIVE_BUFFERS,
|
|
TRUE,
|
|
CurrentReceiveEntry->ReceiveBuffer,
|
|
CurrentReceiveEntry->ReceiveBufferPhysical
|
|
);
|
|
|
|
|
|
if (CurrentReceiveEntry->FlushBuffer) {
|
|
|
|
//
|
|
// Free the flush buffer
|
|
//
|
|
NdisFreeBuffer(
|
|
CurrentReceiveEntry->FlushBuffer
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Free the receive ring
|
|
//
|
|
NdisMFreeSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
sizeof(NE3200_SUPER_RECEIVE_ENTRY) *
|
|
Adapter->NumberOfReceiveBuffers,
|
|
FALSE,
|
|
Adapter->ReceiveQueue,
|
|
Adapter->ReceiveQueuePhysical
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Free the merge buffers
|
|
//
|
|
if (Adapter->NE3200Buffers) {
|
|
|
|
//
|
|
// Loop counter
|
|
//
|
|
UINT i;
|
|
|
|
for (
|
|
i = 0;
|
|
i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS;
|
|
i++
|
|
) {
|
|
|
|
|
|
if (Adapter->NE3200Buffers[i].VirtualNE3200Buffer) {
|
|
|
|
//
|
|
// Free the memory
|
|
//
|
|
NdisMFreeSharedMemory(
|
|
Adapter->MiniportAdapterHandle,
|
|
NE3200_SIZE_OF_TRANSMIT_BUFFERS,
|
|
TRUE,
|
|
Adapter->NE3200Buffers[i].VirtualNE3200Buffer,
|
|
Adapter->NE3200Buffers[i].PhysicalNE3200Buffer
|
|
);
|
|
|
|
if (Adapter->NE3200Buffers[i].FlushBuffer) {
|
|
|
|
//
|
|
// Free the flush buffer
|
|
//
|
|
NdisFreeBuffer(
|
|
Adapter->NE3200Buffers[i].FlushBuffer
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Free the buffer ring
|
|
//
|
|
NE3200_FREE_PHYS(Adapter->NE3200Buffers);
|
|
|
|
}
|
|
|
|
if (Adapter->FlushBufferPoolHandle) {
|
|
|
|
//
|
|
// Free the buffer pool
|
|
//
|
|
NdisFreeBufferPool(
|
|
Adapter->FlushBufferPoolHandle
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#pragma NDIS_INIT_FUNCTION(NE3200InitializeGlobals)
|
|
|
|
STATIC
|
|
BOOLEAN
|
|
NE3200InitializeGlobals(
|
|
OUT PNE3200_GLOBAL_DATA Globals,
|
|
IN NDIS_HANDLE MiniportAdapterHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will initialize the global data structure used
|
|
by all adapters managed by this driver. This routine is only
|
|
called once, when the driver is initializing the first
|
|
adapter.
|
|
|
|
Arguments:
|
|
|
|
Globals - Pointer to the global data structure to initialize.
|
|
|
|
AdapterHandle - The handle to be used to allocate shared memory.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// File with the download code.
|
|
//
|
|
NDIS_STRING FileName=NDIS_STRING_CONST("ne3200.bin");
|
|
|
|
//
|
|
// Handle for the file.
|
|
//
|
|
NDIS_HANDLE FileHandle;
|
|
|
|
//
|
|
// Length of the file.
|
|
//
|
|
UINT FileLength;
|
|
|
|
//
|
|
// Status of NDIS calls
|
|
//
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Virtual address of the download software in the file.
|
|
//
|
|
PVOID ImageBuffer;
|
|
|
|
//
|
|
// The value to return
|
|
//
|
|
BOOLEAN ReturnValue = TRUE;
|
|
|
|
//
|
|
// Save the adpater handle that did the allocations
|
|
//
|
|
Globals->MacBinAdapterHandle = MiniportAdapterHandle;
|
|
|
|
//
|
|
// Allocate the buffer.
|
|
//
|
|
NdisMAllocateSharedMemory(
|
|
MiniportAdapterHandle,
|
|
NE3200_MACBIN_LENGTH,
|
|
FALSE,
|
|
&Globals->MacBinVirtualAddress,
|
|
&Globals->MacBinPhysicalAddress
|
|
);
|
|
|
|
if (Globals->MacBinVirtualAddress == NULL) {
|
|
NE3200DestroyGlobals(Globals);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Store the length
|
|
//
|
|
Globals->MacBinLength = NE3200_MACBIN_LENGTH;
|
|
|
|
|
|
//
|
|
// Open the file with the download code
|
|
//
|
|
NdisOpenFile(
|
|
&Status,
|
|
&FileHandle,
|
|
&FileLength,
|
|
&FileName,
|
|
MinusOne
|
|
);
|
|
|
|
if (Status==NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Map the file into virtual memory
|
|
//
|
|
NdisMapFile(
|
|
&Status,
|
|
&ImageBuffer,
|
|
FileHandle
|
|
);
|
|
|
|
if (Status==NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Copy the download code into the shared memory space
|
|
//
|
|
NdisMoveMemory(Globals->MacBinVirtualAddress,ImageBuffer,FileLength);
|
|
|
|
//
|
|
// Done with the file
|
|
//
|
|
NdisUnmapFile(FileHandle);
|
|
|
|
} else {
|
|
|
|
ReturnValue = FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// Close the file
|
|
//
|
|
NdisCloseFile(FileHandle);
|
|
|
|
} else {
|
|
|
|
ReturnValue = FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// AdapterListHead is initially empty
|
|
//
|
|
InitializeListHead(&Globals->AdapterList);
|
|
|
|
//
|
|
// All done.
|
|
//
|
|
return ReturnValue;
|
|
|
|
}
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
NE3200DestroyGlobals(
|
|
IN PNE3200_GLOBAL_DATA Globals
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees all global data allocated with
|
|
NE3200InitializeGlobals. This routine is called just before
|
|
the driver is unloaded.
|
|
|
|
Arguments:
|
|
|
|
Globals - Pointer to the global data structure to destroy.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Free the memory with the download software in it.
|
|
//
|
|
if (Globals->MacBinVirtualAddress != NULL) {
|
|
|
|
NdisMFreeSharedMemory(
|
|
Globals->MacBinAdapterHandle,
|
|
NE3200_MACBIN_LENGTH,
|
|
FALSE,
|
|
Globals->MacBinVirtualAddress,
|
|
Globals->MacBinPhysicalAddress
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#pragma NDIS_INIT_FUNCTION(NE3200Initialize)
|
|
|
|
NDIS_STATUS
|
|
NE3200Initialize(
|
|
OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE ConfigurationHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NE3200Initialize starts an adapter.
|
|
|
|
Arguments:
|
|
|
|
See NDIS 3.0 Miniport spec.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_PENDING
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Handle returned by NdisOpenConfiguration
|
|
//
|
|
NDIS_HANDLE ConfigHandle;
|
|
|
|
//
|
|
// For changing the network address of this adapter.
|
|
//
|
|
NDIS_STRING NetAddrStr = NETWORK_ADDRESS;
|
|
UCHAR NetworkAddress[NE3200_LENGTH_OF_ADDRESS];
|
|
PUCHAR CurrentAddress;
|
|
PVOID NetAddress;
|
|
ULONG Length;
|
|
|
|
//
|
|
// The type of interrupt the adapter is set to use, level
|
|
// sensitive, or edged.
|
|
//
|
|
NDIS_INTERRUPT_MODE InterruptType;
|
|
|
|
//
|
|
// The interrupt number to use.
|
|
//
|
|
UINT InterruptVector;
|
|
|
|
//
|
|
// The slot number the adapter is located in
|
|
//
|
|
UINT EisaSlot;
|
|
|
|
//
|
|
// The port to look for in the EISA slot information
|
|
//
|
|
USHORT Portz800;
|
|
|
|
//
|
|
// The default value to use.
|
|
//
|
|
UCHAR z800Value;
|
|
|
|
//
|
|
// The mast to apply to the default values
|
|
//
|
|
UCHAR Mask;
|
|
|
|
//
|
|
// The type of initialization described in the EISA slot information.
|
|
//
|
|
UCHAR InitType;
|
|
|
|
//
|
|
// The port value for this iteration
|
|
//
|
|
UCHAR PortValue;
|
|
|
|
//
|
|
// The current port address to initialize
|
|
//
|
|
USHORT PortAddress;
|
|
|
|
//
|
|
// The location in the EISA slot information buffer
|
|
//
|
|
PUCHAR CurrentChar;
|
|
|
|
//
|
|
// Set to TRUE when done processing EISA slot information
|
|
//
|
|
BOOLEAN LastEntry;
|
|
|
|
//
|
|
// The EISA data
|
|
//
|
|
NDIS_EISA_FUNCTION_INFORMATION EisaData;
|
|
|
|
//
|
|
// Temporary looping variable
|
|
//
|
|
ULONG i;
|
|
|
|
//
|
|
// For signalling a configuration error
|
|
//
|
|
BOOLEAN ConfigError = FALSE;
|
|
NDIS_STATUS ConfigErrorCode;
|
|
|
|
//
|
|
// Status of NDIS calls
|
|
//
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Search for the medium type (802.3)
|
|
//
|
|
for (i = 0; i < MediumArraySize; i++){
|
|
|
|
if (MediumArray[i] == NdisMedium802_3){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Ethernet was not found. Return an error.
|
|
//
|
|
if (i == MediumArraySize){
|
|
|
|
return NDIS_STATUS_UNSUPPORTED_MEDIA;
|
|
|
|
}
|
|
|
|
//
|
|
// Select ethernet
|
|
//
|
|
*SelectedMediumIndex = i;
|
|
|
|
//
|
|
// Open the configuration handle
|
|
//
|
|
NdisOpenConfiguration(
|
|
&Status,
|
|
&ConfigHandle,
|
|
ConfigurationHandle
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Set address to default, using the burned in adapter address
|
|
//
|
|
CurrentAddress = NULL;
|
|
|
|
//
|
|
// Read an overriding net address
|
|
//
|
|
NdisReadNetworkAddress(
|
|
&Status,
|
|
&NetAddress,
|
|
&Length,
|
|
ConfigHandle
|
|
);
|
|
|
|
if ((Length == NE3200_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
|
|
|
|
//
|
|
// Save overriding net address
|
|
//
|
|
NdisMoveMemory(
|
|
NetworkAddress,
|
|
NetAddress,
|
|
NE3200_LENGTH_OF_ADDRESS
|
|
);
|
|
|
|
CurrentAddress = NetworkAddress;
|
|
|
|
}
|
|
|
|
//
|
|
// Read the EISA configuration information
|
|
//
|
|
NdisReadEisaSlotInformation(
|
|
&Status,
|
|
ConfigurationHandle,
|
|
&EisaSlot,
|
|
&EisaData
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
ConfigError = TRUE;
|
|
ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
|
|
|
|
goto RegisterAdapter;
|
|
|
|
}
|
|
|
|
//
|
|
// Start at the beginning of the buffer
|
|
//
|
|
CurrentChar = EisaData.InitializationData;
|
|
|
|
//
|
|
// This is the port to look for
|
|
//
|
|
Portz800 = (EisaSlot << 12) + 0x800;
|
|
|
|
LastEntry = FALSE;
|
|
|
|
while (!LastEntry) {
|
|
|
|
|
|
InitType = *(CurrentChar++);
|
|
PortAddress = *((USHORT UNALIGNED *) CurrentChar++);
|
|
CurrentChar++;
|
|
|
|
//
|
|
// Check for last entry in EISA information
|
|
//
|
|
if ((InitType & 0x80) == 0) {
|
|
LastEntry = TRUE;
|
|
}
|
|
|
|
//
|
|
// Is this the port we are interested in?
|
|
//
|
|
if (PortAddress != Portz800) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Yes, get the port value to use
|
|
//
|
|
PortValue = *(CurrentChar++);
|
|
|
|
//
|
|
// Get the mask to use.
|
|
//
|
|
if (InitType & 0x40) {
|
|
Mask = *(CurrentChar++);
|
|
} else {
|
|
Mask = 0;
|
|
}
|
|
|
|
//
|
|
// Mask old value and or on new value.
|
|
//
|
|
z800Value &= Mask;
|
|
z800Value |= PortValue;
|
|
}
|
|
|
|
//
|
|
// Now, interpret the port data
|
|
//
|
|
// Get interrupt
|
|
//
|
|
|
|
switch (z800Value & 0x07) {
|
|
case 0x00:
|
|
|
|
ConfigError = TRUE;
|
|
ConfigErrorCode = NDIS_ERROR_CODE_HARDWARE_FAILURE;
|
|
|
|
goto RegisterAdapter;
|
|
|
|
case 0x01:
|
|
InterruptVector = 5;
|
|
break;
|
|
case 0x02:
|
|
InterruptVector = 9;
|
|
break;
|
|
case 0x03:
|
|
InterruptVector = 10;
|
|
break;
|
|
case 0x04:
|
|
InterruptVector = 11;
|
|
break;
|
|
case 0x05:
|
|
InterruptVector = 15;
|
|
break;
|
|
default:
|
|
|
|
ConfigError = TRUE;
|
|
ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
|
|
|
|
goto RegisterAdapter;
|
|
|
|
}
|
|
|
|
//
|
|
// Get interrupt mode
|
|
//
|
|
|
|
if (z800Value & 0x20) {
|
|
InterruptType = NdisInterruptLatched;
|
|
} else {
|
|
InterruptType = NdisInterruptLevelSensitive;
|
|
}
|
|
|
|
RegisterAdapter:
|
|
|
|
//
|
|
// Were there any errors?
|
|
//
|
|
if (ConfigError) {
|
|
|
|
NdisWriteErrorLogEntry(
|
|
MiniportAdapterHandle,
|
|
ConfigErrorCode,
|
|
0
|
|
);
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
} else if (NE3200RegisterAdapter(
|
|
MiniportAdapterHandle,
|
|
EisaSlot,
|
|
InterruptVector,
|
|
InterruptType,
|
|
CurrentAddress
|
|
)) {
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
//
|
|
// All done
|
|
//
|
|
NdisCloseConfiguration(ConfigHandle);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NE3200Halt(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NE3200Halts removes an adapter previously initialized.
|
|
|
|
Arguments:
|
|
|
|
MacAdapterContext - The context value that the Miniport returned
|
|
from Ne3200Initialize; actually as pointer to an NE3200_ADAPTER.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// The adapter to halt
|
|
//
|
|
PNE3200_ADAPTER Adapter;
|
|
|
|
Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
|
|
|
|
//
|
|
// Shut down the h/w
|
|
//
|
|
NE3200Shutdown(Adapter);
|
|
|
|
//
|
|
// Disconnect the interrupt
|
|
//
|
|
NdisMDeregisterInterrupt(&Adapter->Interrupt);
|
|
|
|
//
|
|
// Delete all resources
|
|
//
|
|
NE3200DeleteAdapterMemory(Adapter);
|
|
|
|
//
|
|
// Free map registers
|
|
//
|
|
NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
|
|
|
|
//
|
|
// Remove ports
|
|
//
|
|
NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
|
|
Adapter->AdapterIoBase,
|
|
4,
|
|
(PVOID)Adapter->ResetPort
|
|
);
|
|
|
|
//
|
|
// Remove ports
|
|
//
|
|
NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
|
|
Adapter->AdapterIoBase + NE3200_ID_PORT,
|
|
0x20,
|
|
(PVOID)(Adapter->SystemInterruptPort -
|
|
NE3200_SYSTEM_INTERRUPT_PORT + NE3200_ID_PORT)
|
|
);
|
|
|
|
//
|
|
// Remove from global adapter list
|
|
//
|
|
RemoveEntryList(&Adapter->AdapterList);
|
|
|
|
//
|
|
// Free the adapter structure
|
|
//
|
|
NE3200_FREE_PHYS(Adapter);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
NE3200Shutdown(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NE3200Shutdown shuts down the h/w.
|
|
|
|
Arguments:
|
|
|
|
MacAdapterContext - The context value that the Miniport returned
|
|
from Ne3200Initialize; actually as pointer to an NE3200_ADAPTER.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// The adapter to halt
|
|
//
|
|
PNE3200_ADAPTER Adapter;
|
|
|
|
//
|
|
// Temporary looping variable
|
|
//
|
|
ULONG i;
|
|
|
|
Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
|
|
|
|
//
|
|
// Shut down the chip.
|
|
//
|
|
NE3200StopChip(Adapter);
|
|
|
|
//
|
|
// Pause, waiting for the chip to stop.
|
|
//
|
|
NdisStallExecution(500000);
|
|
|
|
//
|
|
// 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
|
|
);
|
|
|
|
SyncNE3200ClearDoorbellInterrupt(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
|
|
);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NE3200TransferData(
|
|
OUT PNDIS_PACKET Packet,
|
|
OUT PUINT BytesTransferred,
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN NDIS_HANDLE MiniportReceiveContext,
|
|
IN UINT ByteOffset,
|
|
IN UINT BytesToTransfer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A protocol calls the NE3200TransferData request (indirectly via
|
|
NdisTransferData) from within its Receive event handler
|
|
to instruct the Miniport to copy the contents of the received packet
|
|
a specified paqcket buffer.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - The context value returned by the driver when the
|
|
adapter was initialized. In reality this is a pointer to NE3200_ADAPTER.
|
|
|
|
MiniportReceiveContext - The context value passed by the driver on its call
|
|
to NdisMIndicateReceive. The driver can use this value to determine
|
|
which packet, on which adapter, is being received.
|
|
|
|
ByteOffset - An unsigned integer specifying the offset within the
|
|
received packet at which the copy is to begin. If the entire packet
|
|
is to be copied, ByteOffset must be zero.
|
|
|
|
BytesToTransfer - An unsigned integer specifying the number of bytes
|
|
to copy. It is legal to transfer zero bytes; this has no effect. If
|
|
the sum of ByteOffset and BytesToTransfer is greater than the size
|
|
of the received packet, then the remainder of the packet (starting from
|
|
ByteOffset) is transferred, and the trailing portion of the receive
|
|
buffer is not modified.
|
|
|
|
Packet - A pointer to a descriptor for the packet storage into which
|
|
the MAC is to copy the received packet.
|
|
|
|
BytesTransfered - A pointer to an unsigned integer. The MAC writes
|
|
the actual number of bytes transferred into this location. This value
|
|
is not valid if the return status is STATUS_PENDING.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// The adapter to transfer from
|
|
//
|
|
PNE3200_ADAPTER Adapter;
|
|
|
|
//
|
|
// Holds the count of the number of ndis buffers comprising the
|
|
// destination packet.
|
|
//
|
|
UINT DestinationBufferCount;
|
|
|
|
//
|
|
// Points to the buffer into which we are putting data.
|
|
//
|
|
PNDIS_BUFFER DestinationCurrentBuffer;
|
|
|
|
//
|
|
// Points to the location in Buffer from which we are extracting data.
|
|
//
|
|
PUCHAR SourceCurrentAddress;
|
|
|
|
//
|
|
// Holds the virtual address of the current destination buffer.
|
|
//
|
|
PVOID DestinationVirtualAddress;
|
|
|
|
//
|
|
// Holds the length of the current destination buffer.
|
|
//
|
|
UINT DestinationCurrentLength;
|
|
|
|
//
|
|
// Keep track of the bytes transferred so far.
|
|
//
|
|
UINT LocalBytesCopied = 0;
|
|
|
|
//
|
|
// Get the adapter structure
|
|
//
|
|
Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
|
|
|
|
*BytesTransferred = 0;
|
|
|
|
//
|
|
// Take care of boundary condition of zero length copy.
|
|
//
|
|
if (!BytesToTransfer) {
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Get the first buffer of the destination.
|
|
//
|
|
NdisQueryPacket(
|
|
Packet,
|
|
NULL,
|
|
&DestinationBufferCount,
|
|
&DestinationCurrentBuffer,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Could have a null packet.
|
|
//
|
|
if (!DestinationBufferCount) {
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Get first buffer information
|
|
//
|
|
NdisQueryBuffer(
|
|
DestinationCurrentBuffer,
|
|
&DestinationVirtualAddress,
|
|
&DestinationCurrentLength
|
|
);
|
|
|
|
//
|
|
// Set up the source address.
|
|
//
|
|
SourceCurrentAddress = (PUCHAR)(MiniportReceiveContext) + ByteOffset + NE3200_HEADER_SIZE;
|
|
|
|
//
|
|
// While there is still data to copy
|
|
//
|
|
while (LocalBytesCopied < BytesToTransfer) {
|
|
|
|
//
|
|
// Check to see whether we've exhausted the current destination
|
|
// buffer. If so, move onto the next one.
|
|
//
|
|
if (!DestinationCurrentLength) {
|
|
|
|
//
|
|
// Get the next buffer
|
|
//
|
|
NdisGetNextBuffer(
|
|
DestinationCurrentBuffer,
|
|
&DestinationCurrentBuffer
|
|
);
|
|
|
|
if (!DestinationCurrentBuffer) {
|
|
|
|
//
|
|
// We've reached the end of the packet. We return
|
|
// with what we've done so far. (Which must be shorter
|
|
// than requested.)
|
|
//
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Get this buffers information
|
|
//
|
|
NdisQueryBuffer(
|
|
DestinationCurrentBuffer,
|
|
&DestinationVirtualAddress,
|
|
&DestinationCurrentLength
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the data.
|
|
//
|
|
{
|
|
|
|
//
|
|
// Holds the amount of data to move.
|
|
//
|
|
UINT AmountToMove;
|
|
|
|
//
|
|
// Holds the amount desired remaining.
|
|
//
|
|
UINT Remaining = BytesToTransfer - LocalBytesCopied;
|
|
|
|
|
|
AmountToMove = DestinationCurrentLength;
|
|
|
|
AmountToMove = ((Remaining < AmountToMove)?
|
|
(Remaining):(AmountToMove));
|
|
|
|
NE3200_MOVE_MEMORY(
|
|
DestinationVirtualAddress,
|
|
SourceCurrentAddress,
|
|
AmountToMove
|
|
);
|
|
|
|
SourceCurrentAddress += AmountToMove;
|
|
LocalBytesCopied += AmountToMove;
|
|
DestinationCurrentLength -= AmountToMove;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*BytesTransferred = LocalBytesCopied;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
STATIC
|
|
NDIS_STATUS
|
|
NE3200Reset(
|
|
OUT PBOOLEAN AddressingReset,
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The NE3200Reset request instructs the Miniport to issue a hardware reset
|
|
to the network adapter. The driver also resets its software state. See
|
|
the description of NdisMReset for a detailed description of this request.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - Pointer to the adapter structure.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// The adapter to reset
|
|
//
|
|
PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
|
|
|
|
IF_LOG('w');
|
|
|
|
//
|
|
// Start the reset process
|
|
//
|
|
NE3200SetupForReset(
|
|
Adapter
|
|
);
|
|
|
|
//
|
|
// Call Handle interrupt to continue the reset process
|
|
//
|
|
NE3200HandleInterrupt(
|
|
(NDIS_HANDLE)Adapter
|
|
);
|
|
|
|
IF_LOG('W');
|
|
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
BOOLEAN
|
|
NE3200CheckForHang(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to check on the head of the command
|
|
block queue. It will fire off the queue if the head has
|
|
been sleeping on the job.
|
|
|
|
It also detects when the ne3200 adapter has failed, where the
|
|
symptoms are that the adapter will transmit packets, but will
|
|
not receive them.
|
|
|
|
Arguments:
|
|
|
|
Context - Really a pointer to the adapter.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// The adapter to check over
|
|
//
|
|
PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
|
|
|
|
//
|
|
// The first command that is outstanding
|
|
//
|
|
PNE3200_SUPER_COMMAND_BLOCK FirstPending = Adapter->FirstCommandOnCard;
|
|
|
|
//
|
|
// Check if the command is stalled
|
|
//
|
|
if( (FirstPending != NULL) &&
|
|
(FirstPending->Hardware.State == NE3200_STATE_WAIT_FOR_ADAPTER) ) {
|
|
|
|
//
|
|
// See if the command block has timed-out.
|
|
//
|
|
|
|
if ( FirstPending->Timeout ) {
|
|
|
|
if ( FirstPending->TimeoutCount >= 2) {
|
|
|
|
//
|
|
// Give up, the card appears dead.
|
|
//
|
|
Adapter->ResetAsynchronous = TRUE;
|
|
Adapter->SendInterrupt = FALSE;
|
|
Adapter->NoReceiveInterruptCount = 0;
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Re-sumbit the block.
|
|
//
|
|
NE3200_WRITE_COMMAND_POINTER(
|
|
Adapter,
|
|
NdisGetPhysicalAddressLow(FirstPending->Self)
|
|
);
|
|
|
|
NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(
|
|
Adapter,
|
|
NE3200_LOCAL_DOORBELL_NEW_COMMAND
|
|
);
|
|
|
|
IF_LOG('+');
|
|
|
|
FirstPending->TimeoutCount++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
IF_LOG('0');
|
|
|
|
//
|
|
// Let the next call find the stall
|
|
//
|
|
FirstPending->Timeout = TRUE;
|
|
FirstPending->TimeoutCount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Check if the receive side has died.
|
|
//
|
|
if ((!Adapter->ReceiveInterrupt) && (Adapter->SendInterrupt)) {
|
|
|
|
//
|
|
// If we go five times with no receives, but we are sending then
|
|
// we will reset the adapter.
|
|
//
|
|
if ((Adapter->NoReceiveInterruptCount == 5) && !Adapter->ResetInProgress) {
|
|
|
|
//
|
|
// We've waited long enough
|
|
//
|
|
Adapter->ResetAsynchronous = TRUE;
|
|
Adapter->SendInterrupt = FALSE;
|
|
Adapter->NoReceiveInterruptCount = 0;
|
|
|
|
return(TRUE);
|
|
|
|
} else {
|
|
|
|
Adapter->NoReceiveInterruptCount++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// If we got a receive or there are no sends, doesn't matter. Reset
|
|
// the state.
|
|
//
|
|
Adapter->SendInterrupt = FALSE;
|
|
Adapter->ReceiveInterrupt = FALSE;
|
|
Adapter->NoReceiveInterruptCount = 0;
|
|
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|