summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/ndis30/wrapper.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ndis/ndis30/wrapper.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/ndis/ndis30/wrapper.c')
-rw-r--r--private/ntos/ndis/ndis30/wrapper.c17480
1 files changed, 17480 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndis30/wrapper.c b/private/ntos/ndis/ndis30/wrapper.c
new file mode 100644
index 000000000..9373647c4
--- /dev/null
+++ b/private/ntos/ndis/ndis30/wrapper.c
@@ -0,0 +1,17480 @@
+/*++
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ wrapper.c
+
+Abstract:
+
+ NDIS wrapper functions
+
+Author:
+
+ Adam Barr (adamba) 11-Jul-1990
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+ 26-Feb-1991 JohnsonA Added Debugging Code
+ 10-Jul-1991 JohnsonA Implement revised Ndis Specs
+
+--*/
+
+
+#include <precomp.h>
+#pragma hdrstop
+
+#include <stdarg.h>
+
+//
+// The following are counters used for debugging
+//
+
+#if NDISDBG
+BOOLEAN NdisChkErrorFlag=TRUE; // parameter checking on
+int NdisMsgLevel=TRACE_ALL; // no trace
+#endif
+
+PNDIS_MAC_BLOCK NdisMacList = (PNDIS_MAC_BLOCK)NULL;
+NDIS_SPIN_LOCK NdisMacListLock = {0};
+
+BOOLEAN NdisInitialInitNeeded = TRUE;
+BOOLEAN NdisUpOnlyEventLogged = FALSE;
+
+//
+// Global variables for tracking memory allocated for shared memory
+//
+ERESOURCE SharedMemoryResource = {0};
+
+//
+// Global variables for tracking on NT 3.1 protocols that do not
+// use any of the filter packages.
+//
+PNDIS_OPEN_BLOCK GlobalOpenList = NULL;
+NDIS_SPIN_LOCK GlobalOpenListLock = {0};
+
+//
+// Debug variable for filter packages
+//
+#if DBG
+BOOLEAN NdisCheckBadDrivers = FALSE;
+
+extern NDIS_SPIN_LOCK PacketLogSpinLock;
+#endif
+
+//
+// Arcnet specific stuff
+//
+#define WRAPPER_ARC_BUFFERS 8
+#define WRAPPER_ARC_HEADER_SIZE 4
+
+//
+// Define constants used internally to identify regular opens from
+// query global statistics ones.
+//
+
+#define NDIS_OPEN_INTERNAL 1
+#define NDIS_OPEN_QUERY_STATISTICS 2
+
+//
+// This is the structure pointed to by the FsContext of an
+// open used for query statistics.
+//
+// NOTE: THIS STRUCTURE MUST, MUST, MUST ALIGN WITH THE
+// NDIS_M_USER_OPEN_CONTEXT STRUCTURE!!!
+//
+
+typedef struct _NDIS_USER_OPEN_CONTEXT {
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ ULONG OidCount;
+ PNDIS_OID OidArray;
+} NDIS_USER_OPEN_CONTEXT, *PNDIS_USER_OPEN_CONTEXT;
+
+//
+// An active query single statistic request.
+//
+
+typedef struct _NDIS_QUERY_GLOBAL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+} NDIS_QUERY_GLOBAL_REQUEST, *PNDIS_QUERY_GLOBAL_REQUEST;
+
+
+//
+// An active query all statistics request.
+//
+
+typedef struct _NDIS_QUERY_ALL_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_ALL_REQUEST, *PNDIS_QUERY_ALL_REQUEST;
+
+
+//
+// An temporary request used during an open.
+//
+
+typedef struct _NDIS_QUERY_OPEN_REQUEST {
+ PIRP Irp;
+ NDIS_REQUEST Request;
+ NDIS_STATUS NdisStatus;
+ KEVENT Event;
+} NDIS_QUERY_OPEN_REQUEST, *PNDIS_QUERY_OPEN_REQUEST;
+
+
+//
+// Used to queue configuration parameters
+//
+
+typedef struct _NDIS_CONFIGURATION_PARAMETER_QUEUE {
+ struct _NDIS_CONFIGURATION_PARAMETER_QUEUE* Next;
+ NDIS_CONFIGURATION_PARAMETER Parameter;
+} NDIS_CONFIGURATION_PARAMETER_QUEUE, *PNDIS_CONFIGURATION_PARAMETER_QUEUE;
+
+//
+// Configuration Handle
+//
+
+typedef struct _NDIS_CONFIGURATION_HANDLE {
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterList;
+} NDIS_CONFIGURATION_HANDLE, *PNDIS_CONFIGURATION_HANDLE;
+
+//
+// This is used during addadapter/miniportinitialize so that when the
+// driver calls any NdisImmediatexxx routines we can access its driverobj.
+//
+typedef struct _NDIS_WRAPPER_CONFIGURATION_HANDLE
+{
+ RTL_QUERY_REGISTRY_TABLE ParametersQueryTable[4];
+ PDRIVER_OBJECT DriverObject;
+}
+ NDIS_WRAPPER_CONFIGURATION_HANDLE,
+ *PNDIS_WRAPPER_CONFIGURATION_HANDLE;
+
+//
+// Describes an open NDIS file
+//
+
+typedef struct _NDIS_FILE_DESCRIPTOR {
+ PVOID Data;
+ NDIS_SPIN_LOCK Lock;
+ BOOLEAN Mapped;
+} NDIS_FILE_DESCRIPTOR, *PNDIS_FILE_DESCRIPTOR;
+
+//
+// IRP handlers established on behalf of NDIS devices by
+// the wrapper.
+//
+
+NTSTATUS
+NdisCreateIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisDeviceControlIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisCloseIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisSuccessIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+
+NTSTATUS
+NdisQueryOidList(
+ PNDIS_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ );
+
+NTSTATUS
+NdisMQueryOidList(
+ PNDIS_M_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ );
+
+VOID
+NdisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+
+BOOLEAN
+NdisQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ );
+
+NDIS_STATUS
+MiniportAdjustMaximumLookahead(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ );
+
+BOOLEAN
+NdisMKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ );
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NDIS_STATUS
+NdisMacReceiveHandler(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+NdisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+PNDIS_OPEN_BLOCK
+GetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ );
+
+NTSTATUS
+NdisShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ );
+
+VOID
+NdisUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+BOOLEAN
+NdisIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ );
+
+VOID
+NdisDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ );
+
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ );
+
+NTSTATUS
+WrapperSaveParameters(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ );
+
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ );
+
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ );
+
+NDIS_STATUS
+NdisCallDriverAddAdapter(
+ IN PNDIS_MAC_BLOCK NewMacP
+ );
+
+NDIS_STATUS
+NdisMWanSend(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisLinkHandle,
+ IN PVOID Packet
+ );
+
+
+CCHAR NdisMacAdapterDpcTargetProcessor = -1;
+
+//
+// Routines for dealing with making the MAC specific routines pagable
+//
+
+NDIS_SPIN_LOCK NdisMacReferenceLock = {0};
+KEVENT NdisMacPagedInEvent = {0};
+ULONG NdisMacReferenceCount = 0;
+PVOID NdisMacImageHandle = {0};
+
+VOID
+NdisMacInitializePackage(VOID)
+{
+ //
+ // Allocate the spin lock
+ //
+ NdisAllocateSpinLock(&NdisMacReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ KeInitializeEvent(
+ &NdisMacPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+NdisMacReferencePackage(VOID)
+{
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Increment the reference count
+ //
+ NdisMacReferenceCount++;
+
+ if (NdisMacReferenceCount == 1) {
+
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ KeResetEvent(
+ &NdisMacPagedInEvent
+ );
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ NdisMacImageHandle = MmLockPagableCodeSection(NdisIsr);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &NdisMacPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &NdisMacPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+NdisMacDereferencePackage(VOID)
+{
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ NdisMacReferenceCount--;
+
+ if (NdisMacReferenceCount == 0) {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(NdisMacImageHandle);
+
+ } else {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisMacReferenceLock);
+
+ }
+
+}
+
+
+
+//
+// Routines for dealing with making the initialization routines pagable
+//
+
+NDIS_SPIN_LOCK NdisInitReferenceLock = {0};
+KEVENT NdisInitPagedInEvent = {0};
+ULONG NdisInitReferenceCount = 0;
+PVOID NdisInitImageHandle = {0};
+
+VOID
+NdisInitInitializePackage(VOID)
+{
+ //
+ // Allocate the spin lock
+ //
+ NdisAllocateSpinLock(&NdisInitReferenceLock);
+
+ //
+ // Initialize the "in page" event.
+ //
+ KeInitializeEvent(
+ &NdisInitPagedInEvent,
+ NotificationEvent,
+ FALSE
+ );
+}
+
+VOID
+NdisInitReferencePackage(VOID)
+{
+
+ //
+ // Grab the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Increment the reference count
+ //
+ NdisInitReferenceCount++;
+
+ if (NdisInitReferenceCount == 1) {
+
+ //
+ // We are the first reference. Page everything in.
+ //
+
+ //
+ // Clear the event
+ //
+ KeResetEvent(
+ &NdisInitPagedInEvent
+ );
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Page in all the functions
+ //
+ NdisInitImageHandle = MmLockPagableCodeSection(NdisReadConfiguration);
+
+ //
+ // Signal to everyone to go
+ //
+ KeSetEvent(
+ &NdisInitPagedInEvent,
+ 0L,
+ FALSE
+ );
+
+ } else {
+
+ //
+ // Set the spin lock free
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Wait for everything to be paged in
+ //
+ KeWaitForSingleObject(
+ &NdisInitPagedInEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ NULL
+ );
+
+ }
+
+}
+
+VOID
+NdisInitDereferencePackage(VOID)
+{
+
+ //
+ // Get the spin lock
+ //
+ ACQUIRE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ NdisInitReferenceCount--;
+
+ if (NdisInitReferenceCount == 0) {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ //
+ // Page out all the functions
+ //
+ MmUnlockPagableImageSection(NdisInitImageHandle);
+
+ } else {
+
+ //
+ // Let next one in
+ //
+ RELEASE_SPIN_LOCK(&NdisInitReferenceLock);
+
+ }
+}
+
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGENDSI, NdisPciAssignResources)
+#pragma alloc_text(PAGENDSI, NdisReadMcaPosInformation)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformationEx)
+#pragma alloc_text(PAGENDSI, NdisReadEisaSlotInformation)
+#pragma alloc_text(PAGENDSI, NdisCallDriverAddAdapter)
+#pragma alloc_text(PAGENDSW, NdisDereferenceMac)
+#pragma alloc_text(PAGENDSW, NdisDereferenceAdapter)
+#pragma alloc_text(PAGENDSW, NdisKillAdapter)
+#pragma alloc_text(PAGENDSW, NdisDeQueueAdapterOnMac)
+#pragma alloc_text(PAGENDSW, NdisQueueAdapterOnMac)
+#pragma alloc_text(PAGENDSW, NdisKillOpen)
+#pragma alloc_text(PAGENDSW, NdisKillOpenAndNotifyProtocol)
+#pragma alloc_text(PAGENDSW, NdisCloseIrpHandler)
+#pragma alloc_text(PAGENDSW, NdisCompleteQueryStatistics)
+#pragma alloc_text(PAGENDSW, NdisQueryOidList)
+#pragma alloc_text(PAGENDSW, NdisFinishOpen)
+#pragma alloc_text(PAGENDSW, NdisCompleteCloseAdapter)
+#pragma alloc_text(PAGENDSW, NdisCompleteOpenAdapter)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapterShutdownHandler)
+#pragma alloc_text(PAGENDSI, NdisRegisterAdapter)
+#pragma alloc_text(PAGENDSI, NdisInitializeWrapper)
+#pragma alloc_text(PAGENDSW, NdisMacReceiveCompleteHandler)
+#pragma alloc_text(PAGENDSW, NdisMacReceiveHandler)
+#pragma alloc_text(PAGENDSW, GetOpenBlockFromProtocolBindingContext)
+#pragma alloc_text(PAGENDSI, NdisAllocateDmaChannel)
+#pragma alloc_text(PAGENDSW, NdisShutdown)
+#pragma alloc_text(PAGENDSW, NdisUnload)
+#pragma alloc_text(PAGENDSI, NdisInitializeInterrupt)
+#pragma alloc_text(PAGENDSW, NdisDpc)
+#pragma alloc_text(PAGENDSW, NdisIsr)
+#pragma alloc_text(PAGENDSI, NdisMapIoSpace)
+#pragma alloc_text(PAGENDSI, NdisReadNetworkAddress)
+#pragma alloc_text(PAGENDSI, NdisCloseConfiguration)
+#pragma alloc_text(PAGENDSI, NdisReadConfiguration)
+#pragma alloc_text(PAGENDSI, WrapperSaveParameters)
+#pragma alloc_text(PAGENDSI, NdisOpenConfiguration)
+#pragma alloc_text(PAGENDSI, NdisOverrideBusNumber)
+#pragma alloc_text(INIT, DriverEntry)
+
+#endif
+
+
+//
+// This constant is used for places where NdisAllocateMemory
+// needs to be called and the HighestAcceptableAddress does
+// not matter.
+//
+
+static const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
+ NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
+
+#if defined(_ALPHA_)
+
+typedef struct _NDIS_LOOKAHEAD_ELEMENT {
+
+ ULONG Length;
+ struct _NDIS_LOOKAHEAD_ELEMENT *Next;
+
+} NDIS_LOOKAHEAD_ELEMENT, *PNDIS_LOOKAHEAD_ELEMENT;
+
+NDIS_SPIN_LOCK NdisLookaheadBufferLock = {0};
+ULONG NdisLookaheadBufferLength = 0;
+PNDIS_LOOKAHEAD_ELEMENT NdisLookaheadBufferList = NULL;
+
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ Temporary entry point needed to initialize the NDIS wrapper driver.
+
+Arguments:
+
+ DriverObject - Pointer to the driver object created by the system.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ return STATUS_SUCCESS;
+
+} // DriverEntry
+
+
+NDIS_STATUS
+NdisInitialInit(
+ IN PDRIVER_OBJECT Driver OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This routine is used for all one time initialization of NDIS variables.
+ It seems that DriverEntry is *not* called for ndis.sys due to its type.
+
+Arguments:
+
+ Driver - Optional pointer to an NT driver object. Used to log an error,
+ if necessary.
+
+Return Value:
+
+ NTSTATUS - Status of initialization. Currently, this routine can only
+ fail if built for UP and loaded on MP.
+
+--*/
+
+{
+ Driver;
+
+ if (NdisInitialInitNeeded) {
+
+#if defined(UP_DRIVER)
+ //
+ // If built for UP, ensure that this is a UP system.
+ //
+
+ if (*KeNumberProcessors != 1) {
+
+ if (ARGUMENT_PRESENT(Driver) && !NdisUpOnlyEventLogged) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+
+ errorLogEntry = IoAllocateErrorLogEntry( Driver, sizeof(IO_ERROR_LOG_PACKET) );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_UP_DRIVER_ON_MP;
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->NumberOfStrings = 0;
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ NdisUpOnlyEventLogged = TRUE;
+ }
+
+ }
+
+ return NDIS_STATUS_BAD_VERSION; //!!! better status?
+ }
+
+#endif // defined(UP_DRIVER)
+
+ NdisInitialInitNeeded = FALSE;
+ NdisAllocateSpinLock(&NdisMacListLock);
+
+ ArcInitializePackage();
+ EthInitializePackage();
+ FddiInitializePackage();
+ TrInitializePackage();
+ MiniportInitializePackage();
+ NdisInitInitializePackage();
+ NdisMacInitializePackage();
+
+#if defined(_ALPHA_)
+ NdisAllocateSpinLock(&NdisLookaheadBufferLock);
+#endif
+
+ ExInitializeResource(&SharedMemoryResource);
+
+ NdisAllocateSpinLock(&GlobalOpenListLock);
+
+#if DBG
+ NdisAllocateSpinLock(&PacketLogSpinLock);
+#endif
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+//
+// Configuration Requests
+//
+
+VOID
+NdisOpenConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to open the parameter subkey of the
+ adapter registry tree.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Returns a handle which is used in calls to
+ NdisReadConfiguration and NdisCloseConfiguration.
+
+ WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE
+ that is set up for this driver's parameters.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Handle to be returned
+ //
+ PNDIS_CONFIGURATION_HANDLE HandleToReturn;
+
+
+ //
+ // Allocate the configuration handle
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID*) &HandleToReturn,
+ sizeof(NDIS_CONFIGURATION_HANDLE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS) {
+ return;
+ }
+
+ HandleToReturn->KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ HandleToReturn->ParameterList = NULL;
+ *ConfigurationHandle = (NDIS_HANDLE) HandleToReturn;
+
+ return;
+}
+
+
+NTSTATUS
+WrapperSaveParameters(
+ 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 with the value for a specified parameter. It allocates
+ memory to hold the data and copies it over.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value.
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Points to the head of the parameter chain.
+
+ EntryContext - A pointer to
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE)Context;
+
+ //
+ // Where the user wants a pointer returned to the data.
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER *ParameterValue =
+ (PNDIS_CONFIGURATION_PARAMETER *)EntryContext;
+
+ //
+ // Use this to link parameters allocated to this open
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+
+
+ //
+ // Allocate our parameter node
+ //
+
+ Status = NdisAllocateMemory(
+ (PVOID*)&ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0,
+ HighestAcceptableMax);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)Status;
+ }
+
+
+ *ParameterValue = &ParameterNode->Parameter;
+
+ //
+ // Map registry datatypes to ndis data types
+ //
+
+ if (ValueType == REG_DWORD) {
+
+ //
+ // The registry says that the data is in a dword boundary.
+ //
+
+ (*ParameterValue)->ParameterType = NdisParameterInteger;
+ (*ParameterValue)->ParameterData.IntegerData =
+ *((PULONG) ValueData);
+
+ } else if ((ValueType == REG_SZ) || (ValueType == REG_MULTI_SZ)) {
+
+ (*ParameterValue)->ParameterType =
+ (ValueType == REG_SZ) ? NdisParameterString : NdisParameterMultiString;
+
+ (*ParameterValue)->ParameterData.StringData.Buffer =
+ ExAllocatePoolWithTag(NonPagedPool, ValueLength, ' DN');
+
+ if (((*ParameterValue)->ParameterData.StringData.Buffer) == NULL) {
+ NdisFreeMemory (ParameterNode, sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE), 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory ((*ParameterValue)->ParameterData.StringData.Buffer,
+ ValueData, ValueLength);
+ (*ParameterValue)->ParameterData.StringData.Length = (USHORT)ValueLength;
+ (*ParameterValue)->ParameterData.StringData.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Special fix; if a string ends in a NULL and that is included
+ // in the length, remove it.
+ //
+
+ if (ValueType == REG_SZ) {
+ if ((((PUCHAR)ValueData)[ValueLength-1] == 0) &&
+ (((PUCHAR)ValueData)[ValueLength-2] == 0)) {
+ (*ParameterValue)->ParameterData.StringData.Length -= 2;
+ }
+ }
+
+ } else {
+
+ NdisFreeMemory(
+ ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0
+ );
+
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+
+ }
+
+
+ //
+ // Queue this parameter node
+ //
+
+ ParameterNode->Next = NdisConfigHandle->ParameterList;
+ NdisConfigHandle->ParameterList = ParameterNode;
+
+ return STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ IN NDIS_PARAMETER_TYPE ParameterType
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to read the parameter for a configuration
+ keyword from the configuration database.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ParameterValue - Returns the value for this keyword.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+ Keyword - The keyword to search for.
+
+ ParameterType - Ignored on NT, specifies the type of the value.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Status of our requests
+ //
+ NTSTATUS RegistryStatus;
+
+ //
+ // There are some built-in parameters which can always be
+ // read, even if not present in the registry. This is the
+ // number of them.
+ //
+
+#define BUILT_IN_COUNT 2
+
+ //
+ // The names of the built-in parameters.
+ //
+
+ static NDIS_STRING BuiltInStrings[BUILT_IN_COUNT] =
+ { NDIS_STRING_CONST ("Environment"),
+ NDIS_STRING_CONST ("ProcessorType") };
+
+ //
+ // The values to return for the built-in parameters.
+ //
+
+ static NDIS_CONFIGURATION_PARAMETER BuiltInParameters[BUILT_IN_COUNT] =
+ { { NdisParameterInteger, NdisEnvironmentWindowsNt },
+ { NdisParameterInteger,
+#if defined(_M_IX86)
+ NdisProcessorX86
+#elif defined(_M_MRX000)
+ NdisProcessorMips
+#elif defined(_ALPHA_)
+ NdisProcessorAlpha
+#else
+ NdisProcessorPpc
+#endif
+ } };
+
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // index variable
+ //
+ UINT i;
+
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+
+
+ //
+ // First check if this is one of the built-in parameters.
+ //
+
+ for (i = 0; i < BUILT_IN_COUNT; i++) {
+ if (RtlEqualUnicodeString(Keyword, &BuiltInStrings[i], TRUE)) {
+ *Status = NDIS_STATUS_SUCCESS;
+ *ParameterValue = &BuiltInParameters[i];
+ return;
+ }
+ }
+
+
+ //
+ // Allocate room for a null-terminated version of the keyword
+ //
+
+ KeywordBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ Keyword->Length + sizeof(WCHAR),
+ ' DN');
+ if (KeywordBuffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+ RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ *(PWCHAR)(((PUCHAR)KeywordBuffer)+Keyword->Length) = (WCHAR)L'\0';
+
+
+ //
+ // Finish initializing the table for this query.
+ //
+
+ NdisConfigHandle->KeyQueryTable[1].Name = KeywordBuffer;
+ NdisConfigHandle->KeyQueryTable[1].EntryContext = ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfigHandle.
+ //
+
+ RegistryStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfigHandle->KeyQueryTable[3].Name,
+ NdisConfigHandle->KeyQueryTable,
+ NdisConfigHandle, // context
+ NULL);
+
+
+ ExFreePool (KeywordBuffer); // no longer needed
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+}
+
+
+VOID
+NdisWriteConfiguration(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Keyword,
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to write a parameter to the configuration database.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ ConfigurationHandle - Handle passed to the driver's AddAdapter routine.
+
+ Keyword - The keyword to set.
+
+ ParameterValue - Specifies the new value for this keyword.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Status of our requests
+ //
+ NTSTATUS RegistryStatus;
+
+ //
+ // The ConfigurationHandle is really a pointer to a registry query table.
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // The name of the Parameters key.
+ //
+ PWSTR Parameters = L"\\Parameters";
+ ULONG ParametersLength = (wcslen(Parameters) + 1) * sizeof(WCHAR);
+
+ ULONG DriverLength = wcslen(NdisConfigHandle->KeyQueryTable[3].Name) * sizeof(WCHAR);
+
+ //
+ // Holds a null-terminated version of the name of the Parameters key.
+ //
+ PWSTR KeyNameBuffer;
+
+ //
+ // Holds a null-terminated version of the keyword.
+ //
+ PWSTR KeywordBuffer;
+
+ //
+ // Variables describing the parameter value.
+ //
+ PVOID ValueData;
+ ULONG ValueLength;
+ ULONG ValueType;
+
+ //
+ // Get the value data.
+ //
+ if ( ParameterValue->ParameterType == NdisParameterInteger ) {
+ ValueData = &ParameterValue->ParameterData.IntegerData;
+ ValueLength = sizeof(ParameterValue->ParameterData.IntegerData);
+ ValueType = REG_DWORD;
+ } else if ( (ParameterValue->ParameterType == NdisParameterString) ||
+ (ParameterValue->ParameterType == NdisParameterMultiString) ) {
+ ValueData = ParameterValue->ParameterData.StringData.Buffer;
+ ValueLength = ParameterValue->ParameterData.StringData.Length;
+ ValueType = ParameterValue->ParameterType == NdisParameterString ?
+ REG_SZ : REG_MULTI_SZ;
+ } else {
+ *Status = NDIS_STATUS_NOT_SUPPORTED;
+ return;
+ }
+
+ //
+ // Allocate room for the Parameters key name (e.g., L"Elnk3\Parameters").
+ //
+
+ KeyNameBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ DriverLength + ParametersLength,
+ ' DN');
+ if (KeyNameBuffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlCopyMemory (KeyNameBuffer, NdisConfigHandle->KeyQueryTable[3].Name, DriverLength);
+ RtlCopyMemory ((PCHAR)KeyNameBuffer + DriverLength, Parameters, ParametersLength);
+
+ //
+ // Allocate room for a null-terminated version of the keyword
+ //
+
+ KeywordBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ Keyword->Length + sizeof(WCHAR),
+ ' DN');
+ if (KeywordBuffer == NULL) {
+ ExFreePool (KeyNameBuffer);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlCopyMemory (KeywordBuffer, Keyword->Buffer, Keyword->Length);
+ *(PWCHAR)((PUCHAR)KeywordBuffer+Keyword->Length) = (WCHAR)L'\0';
+
+ //
+ // Write the value to the registry.
+ //
+
+ RegistryStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ KeyNameBuffer,
+ KeywordBuffer,
+ ValueType,
+ ValueData,
+ ValueLength
+ );
+
+ ExFreePool (KeywordBuffer); // no longer needed
+ ExFreePool (KeyNameBuffer);
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+}
+
+
+
+VOID
+NdisCloseConfiguration(
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to close a configuration database opened by
+ NdisOpenConfiguration.
+
+Arguments:
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Obtain the actual configuration handle structure
+ //
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Pointer to a parameter node
+ //
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+ //
+ // deallocate the parameter nodes
+ //
+
+ ParameterNode = NdisConfigHandle->ParameterList;
+
+ while (ParameterNode != NULL) {
+
+ NdisConfigHandle->ParameterList = ParameterNode->Next;
+
+ if ((ParameterNode->Parameter.ParameterType == NdisParameterString) ||
+ (ParameterNode->Parameter.ParameterType == NdisParameterMultiString)) {
+ ExFreePool (ParameterNode->Parameter.ParameterData.StringData.Buffer);
+ }
+
+ NdisFreeMemory(
+ ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0
+ );
+
+ ParameterNode = NdisConfigHandle->ParameterList;
+ }
+
+ NdisFreeMemory(
+ ConfigurationHandle,
+ sizeof(NDIS_CONFIGURATION_HANDLE),
+ 0);
+}
+
+
+
+VOID
+NdisReadNetworkAddress(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * NetworkAddress,
+ OUT PUINT NetworkAddressLength,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to read the "NetworkAddress" parameter
+ from the configuration database. It reads the value as a
+ string separated by hyphens, then converts it to a binary
+ array and stores the result.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NetworkAddress - Returns a pointer to the address.
+
+ NetworkAddressLength - Returns the length of the address.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Convert the handle to its real value
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Variables used in reading the data from the registry
+ //
+
+ NTSTATUS NtStatus;
+ PWSTR NetworkAddressString = L"NetworkAddress";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+
+ //
+ // Variables used in converting the address
+ //
+
+ UCHAR ConvertArray[3];
+ PWSTR CurrentReadLoc;
+ PWSTR AddressEnd;
+ PUCHAR CurrentWriteLoc;
+ UINT TotalBytesRead;
+ ULONG TempUlong;
+ ULONG AddressLength;
+
+
+ //
+ // Finish initializing the table for this query.
+ //
+
+ NdisConfigHandle->KeyQueryTable[1].Name = NetworkAddressString;
+ NdisConfigHandle->KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfigHandle.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfigHandle->KeyQueryTable[3].Name,
+ NdisConfigHandle->KeyQueryTable,
+ NdisConfigHandle, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ if (ParameterValue->ParameterType != NdisParameterString) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+
+ //
+ // Now convert the address to binary (we do this
+ // in-place, since this allows us to use the memory
+ // already allocated which is automatically freed
+ // by NdisCloseConfiguration).
+ //
+
+ ConvertArray[2] = '\0';
+ CurrentReadLoc = (PWSTR)ParameterValue->ParameterData.StringData.Buffer;
+ CurrentWriteLoc = (PUCHAR)CurrentReadLoc;
+ TotalBytesRead = ParameterValue->ParameterData.StringData.Length;
+ AddressEnd = CurrentReadLoc + (TotalBytesRead / sizeof(WCHAR));
+ AddressLength = 0;
+
+ while ((CurrentReadLoc+2) <= AddressEnd) {
+
+ //
+ // Copy the current two-character value into ConvertArray
+ //
+
+ ConvertArray[0] = (UCHAR)(*(CurrentReadLoc++));
+ ConvertArray[1] = (UCHAR)(*(CurrentReadLoc++));
+
+ //
+ // Convert it to a Ulong and update
+ //
+
+ NtStatus = RtlCharToInteger (
+ ConvertArray,
+ 16,
+ &TempUlong);
+
+ if (!NT_SUCCESS(NtStatus)) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ *(CurrentWriteLoc++) = (UCHAR)TempUlong;
+ ++AddressLength;
+
+ //
+ // If the next character is a hyphen, skip it.
+ //
+
+ if (CurrentReadLoc < AddressEnd) {
+ if (*CurrentReadLoc == (WCHAR)L'-') {
+ ++CurrentReadLoc;
+ }
+ }
+ }
+
+
+ *Status = STATUS_SUCCESS;
+ *NetworkAddress = ParameterValue->ParameterData.StringData.Buffer;
+ *NetworkAddressLength = AddressLength;
+
+}
+
+
+VOID
+NdisReadBindingInformation(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STRING * Binding,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to read the binding information for
+ this adapter from the configuration database. The value
+ returned is a pointer to a string containing the bind
+ that matches the export for the current AddAdapter call.
+
+ This function is meant for NDIS drivers that are layered
+ on top of other NDIS drivers. Binding would be passed to
+ NdisOpenAdapter as the AdapterName.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ Binding - Returns the binding data.
+
+ ConfigurationHandle - Handle returned by NdisOpenConfiguration. Points
+ to the parameter subkey.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Convert the handle to its real value
+ //
+
+ PNDIS_CONFIGURATION_HANDLE NdisConfigHandle =
+ (PNDIS_CONFIGURATION_HANDLE) ConfigurationHandle;
+
+ //
+ // Use this to link parameters allocated to this open
+ //
+
+ PNDIS_CONFIGURATION_PARAMETER_QUEUE ParameterNode;
+
+
+ //
+ // For layered drivers, this points to the binding. For
+ // non-layered drivers, it is NULL. This is set up before
+ // the call to AddAdapter.
+ //
+
+ if (NdisConfigHandle->KeyQueryTable[3].EntryContext == NULL) {
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+
+ //
+ // Allocate our parameter node
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID*)&ParameterNode,
+ sizeof(NDIS_CONFIGURATION_PARAMETER_QUEUE),
+ 0,
+ HighestAcceptableMax);
+
+ if (*Status != NDIS_STATUS_SUCCESS) {
+ return;
+ }
+
+
+ //
+ // We set this to Integer because if we set it to String
+ // then CloseConfiguration would try to free the string,
+ // which we don't want.
+ //
+
+ ParameterNode->Parameter.ParameterType = NdisParameterInteger;
+
+ RtlInitUnicodeString(
+ &ParameterNode->Parameter.ParameterData.StringData,
+ NdisConfigHandle->KeyQueryTable[3].EntryContext);
+
+ //
+ // Queue this parameter node
+ //
+
+ ParameterNode->Next = NdisConfigHandle->ParameterList;
+ NdisConfigHandle->ParameterList = ParameterNode;
+
+ *Binding = &ParameterNode->Parameter.ParameterData.StringData;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+//
+// Packet and Buffer requests
+//
+
+
+VOID
+NdisAllocatePacketPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors,
+ IN UINT ProtocolReservedLength
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a packet pool. All packets are the same
+ size for a given pool (as determined by ProtocolReservedLength),
+ so a simple linked list of free packets is set up initially.
+
+Arguments:
+
+ Status - Returns the final status (always NDIS_STATUS_SUCCESS).
+ PoolHandle - Returns a pointer to the pool.
+ NumberOfDescriptors - Number of packet descriptors needed.
+ ProtocolReservedLength - How long the ProtocolReserved field
+ should be for packets in this pool.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL TmpPool;
+ PUCHAR FreeEntry;
+ UINT PacketLength;
+ UINT i;
+
+ //
+ // Set up the size of packets in this pool (rounded
+ // up to sizeof(ULONG) for alignment).
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisAllocatePacketPool\n");
+
+ PacketLength = sizeof(NDIS_PACKET) - 1 + ProtocolReservedLength;
+ PacketLength = ((PacketLength+(sizeof(ULONG)-1)) / sizeof(ULONG))
+ * sizeof(ULONG);
+
+ //
+ // Allocate space needed
+ //
+ TmpPool = (PNDIS_PACKET_POOL) ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_PACKET_POOL) +
+ PacketLength * NumberOfDescriptors -
+ 1,
+ 'ppDN'
+ );
+
+ if (TmpPool == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ TmpPool->PacketLength = PacketLength;
+
+ //
+ // First entry in free list is at beginning of pool space.
+ //
+
+ TmpPool->FreeList = (PNDIS_PACKET)TmpPool->Buffer;
+ FreeEntry = TmpPool->Buffer;
+
+ for (i = 1; i < NumberOfDescriptors; i++) {
+
+ //
+ // Each entry is linked to the "packet" PacketLength bytes
+ // ahead of it, using the Private.Head field.
+ //
+
+ ((PNDIS_PACKET)FreeEntry)->Private.Head =
+ (PNDIS_BUFFER)(FreeEntry + PacketLength);
+ FreeEntry += PacketLength;
+ }
+
+ //
+ // Final free list entry.
+ //
+
+ ((PNDIS_PACKET)FreeEntry)->Private.Head = (PNDIS_BUFFER)NULL;
+
+
+ NdisAllocateSpinLock(&TmpPool->SpinLock);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ *PoolHandle = (NDIS_HANDLE)TmpPool;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisAllocatePacketPool\n");
+}
+
+
+
+VOID
+NdisAllocateBufferPool(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE PoolHandle,
+ IN UINT NumberOfDescriptors
+ )
+/*++
+
+Routine Description:
+
+ Initializes a block of storage so that buffer descriptors can be
+ allocated.
+
+Arguments:
+
+ Status - status of the request.
+ PoolHandle - handle that is used to specify the pool
+ NumberOfDescriptors - Number of buffer descriptors in the pool.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // A nop for NT
+ //
+ UNREFERENCED_PARAMETER(NumberOfDescriptors);
+ *PoolHandle = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+VOID
+NdisFreeBufferPool(
+ IN NDIS_HANDLE PoolHandle
+ )
+/*++
+
+Routine Description:
+
+ Terminates usage of a buffer descriptor pool.
+
+Arguments:
+
+ PoolHandle - handle that is used to specify the pool
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PoolHandle);
+}
+
+VOID
+NdisAllocateBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID VirtualAddress,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Creates a buffer descriptor to describe a segment of virtual memory
+ allocated via NdisAllocateMemory (which always allocates nonpaged).
+
+Arguments:
+
+ Status - Status of the request.
+ Buffer - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ VirtualAddress - The virtual address of the buffer.
+ Length - The Length of the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ if ((*Buffer = IoAllocateMdl(
+ VirtualAddress,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ )) == NULL) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ MmBuildMdlForNonPagedPool(*Buffer);
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+}
+
+
+VOID
+NdisCopyBuffer(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * Buffer,
+ IN NDIS_HANDLE PoolHandle,
+ IN PVOID MemoryDescriptor,
+ IN UINT Offset,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Used to create a buffer descriptor given a memory descriptor.
+
+Arguments:
+
+ Status - Status of the request.
+ Buffer - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ MemoryDescriptor - Pointer to the descriptor of the source memory.
+ Offset - The Offset in the sources memory from which the copy is to
+ begin
+ Length - Number of Bytes to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_BUFFER SourceDescriptor = (PNDIS_BUFFER)MemoryDescriptor;
+ PVOID BaseVa = (((PUCHAR)MmGetMdlVirtualAddress(SourceDescriptor)) + Offset);
+
+ UNREFERENCED_PARAMETER(PoolHandle);
+
+ if ((*Buffer = IoAllocateMdl(
+ BaseVa,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ )) == NULL ) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ } else {
+
+ IoBuildPartialMdl(
+ SourceDescriptor,
+ *Buffer,
+ BaseVa,
+ Length);
+
+ (*Buffer)->Next = NULL;
+ *Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+}
+
+
+VOID
+NdisAllocatePacket(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_PACKET * Packet,
+ IN NDIS_HANDLE PoolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates a packet out of a packet pool.
+
+Arguments:
+
+ Status - Returns the final status.
+ Packet - Return a pointer to the packet.
+ PoolHandle - The packet pool to allocate from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET_POOL TmpPool = (PNDIS_PACKET_POOL)PoolHandle;
+
+ ACQUIRE_SPIN_LOCK(&TmpPool->SpinLock);
+
+
+ //
+ // See if any packets are on pool free list.
+ //
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisAllocatePacket\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(PoolHandle)) {
+ NdisPrint1("AllocatePacket: NULL Pool address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(PoolHandle)) {
+ NdisPrint1("AllocatePacket: Pool not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (TmpPool->FreeList == (PNDIS_PACKET)NULL) {
+
+ //
+ // No, cannot satisfy request.
+ //
+
+ RELEASE_SPIN_LOCK(&TmpPool->SpinLock);
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n");
+ return;
+ }
+
+ //
+ // Yes, take free packet off head of list and return it.
+ //
+
+ *Packet = TmpPool->FreeList;
+ TmpPool->FreeList = (PNDIS_PACKET)(*Packet)->Private.Head;
+ RELEASE_SPIN_LOCK(&TmpPool->SpinLock);
+
+
+ //
+ // Clear packet elements.
+ //
+
+ RtlZeroMemory((PVOID)*Packet, TmpPool->PacketLength);
+ (*Packet)->Private.Head = (PNDIS_BUFFER)NULL; // don't need to set Tail
+ (*Packet)->Private.Pool = (PNDIS_PACKET_POOL)PoolHandle;
+ (*Packet)->Private.Count = 0;
+ (*Packet)->Private.PhysicalCount = 0;
+ (*Packet)->Private.TotalLength = 0;
+ (*Packet)->Private.ValidCounts = TRUE;
+
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisAllocatePacket\n");
+}
+
+
+VOID
+NdisUnchainBufferAtFront(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Takes a buffer off the front of a packet.
+
+Arguments:
+
+ Packet - The packet to be modified.
+ Buffer - Returns the packet on the front, or NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ *Buffer = Packet->Private.Head;
+
+ //
+ // If packet is not empty, remove head buffer.
+ //
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtFront\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Null Packet Pointer\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Packet not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsPacket(Packet)) {
+ NdisPrint1("UnchainBufferAtFront: Illegal Packet Size\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (*Buffer != (PNDIS_BUFFER)NULL) {
+ Packet->Private.Head = (*Buffer)->Next; // may be NULL
+ (*Buffer)->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ }
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtFront\n");
+}
+
+VOID
+NdisUnchainBufferAtBack(
+ IN OUT PNDIS_PACKET Packet,
+ OUT PNDIS_BUFFER * Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Takes a buffer off the end of a packet.
+
+Arguments:
+
+ Packet - The packet to be modified.
+ Buffer - Returns the packet on the end, or NULL.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER TmpBufP = Packet->Private.Head;
+ PNDIS_BUFFER Result;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisUnchainBufferAtBack\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Null Packet Pointer\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Packet not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsPacket(Packet)) {
+ NdisPrint1("UnchainBufferAtBack: Illegal Packet Size\n");
+ DbgBreakPoint();
+ }
+ }
+ if (TmpBufP != (PNDIS_BUFFER)NULL) {
+
+ //
+ // The packet is not empty, return the tail buffer.
+ //
+
+ Result = Packet->Private.Tail;
+ if (TmpBufP == Result) {
+
+ //
+ // There was only one buffer on the queue.
+ //
+
+ Packet->Private.Head = (PNDIS_BUFFER)NULL;
+ } else {
+
+ //
+ // Determine the new tail buffer.
+ //
+
+ while (TmpBufP->Next != Result) {
+ TmpBufP = TmpBufP->Next;
+ }
+ Packet->Private.Tail = TmpBufP;
+ TmpBufP->Next = NULL;
+ }
+
+ Result->Next = (PNDIS_BUFFER)NULL;
+ Packet->Private.ValidCounts = FALSE;
+ } else {
+
+ //
+ // Packet is empty.
+ //
+
+ Result = (PNDIS_BUFFER)NULL;
+ }
+
+ *Buffer = Result;
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisUnchainBufferAtBack\n");
+}
+
+
+
+VOID
+NdisCopyFromPacketToPacket(
+ IN PNDIS_PACKET Destination,
+ IN UINT DestinationOffset,
+ IN UINT BytesToCopy,
+ IN PNDIS_PACKET Source,
+ IN UINT SourceOffset,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet to an ndis packet.
+
+Arguments:
+
+ Destination - The packet should be copied in to.
+
+ DestinationOffset - The offset from the beginning of the packet
+ into which the data should start being placed.
+
+ BytesToCopy - The number of bytes to copy from the source packet.
+
+ Source - The ndis packet from which to copy data.
+
+ SourceOffset - The offset from the start of the packet from which
+ to start copying data.
+
+ BytesCopied - The number of bytes actually copied from the source
+ packet. This can be less than BytesToCopy if the source or destination
+ packet is too short.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // source packet.
+ //
+ UINT SourceBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER SourceCurrentBuffer;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the virtual address of the current source buffer.
+ //
+ PVOID SourceVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Holds the length of the current source buffer.
+ //
+ UINT SourceCurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Destination,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!DestinationBufferCount) return;
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Get the first buffer of the source.
+ //
+
+ NdisQueryPacket(
+ Source,
+ NULL,
+ &SourceBufferCount,
+ &SourceCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!SourceBufferCount) return;
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!DestinationCurrentLength) {
+
+ 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;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+ continue;
+
+ }
+
+
+ //
+ // Check to see whether we've exhausted the current source
+ // buffer. If so, move onto the next one.
+ //
+
+ if (!SourceCurrentLength) {
+
+ NdisGetNextBuffer(
+ SourceCurrentBuffer,
+ &SourceCurrentBuffer
+ );
+
+ if (!SourceCurrentBuffer) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ SourceCurrentBuffer,
+ &SourceVirtualAddress,
+ &SourceCurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (DestinationOffset) {
+
+ if (DestinationOffset > DestinationCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ DestinationOffset -= DestinationCurrentLength;
+ DestinationCurrentLength = 0;
+ continue;
+
+ } else {
+
+ DestinationVirtualAddress = (PCHAR)DestinationVirtualAddress
+ + DestinationOffset;
+ DestinationCurrentLength -= DestinationOffset;
+ DestinationOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (SourceOffset) {
+
+ if (SourceOffset > SourceCurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ SourceOffset -= SourceCurrentLength;
+ SourceCurrentLength = 0;
+ continue;
+
+ } else {
+
+ SourceVirtualAddress = (PCHAR)SourceVirtualAddress
+ + SourceOffset;
+ SourceCurrentLength -= SourceOffset;
+ SourceOffset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToCopy - LocalBytesCopied;
+
+ AmountToMove =
+ ((SourceCurrentLength <= DestinationCurrentLength)?
+ (SourceCurrentLength):(DestinationCurrentLength));
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ RtlCopyMemory(
+ DestinationVirtualAddress,
+ SourceVirtualAddress,
+ AmountToMove
+ );
+
+ DestinationVirtualAddress =
+ (PCHAR)DestinationVirtualAddress + AmountToMove;
+ SourceVirtualAddress =
+ (PCHAR)SourceVirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ SourceCurrentLength -= AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
+//
+// Operating System Requests
+//
+//
+
+
+VOID
+NdisMapIoSpace(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * VirtualAddress,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Map virtual memory address space onto a physical address.
+
+Arguments:
+
+ Status - resulting status
+ VirtualAddress - resulting address in virtual space.
+ NdisAdapterHandle - value returned by NdisRegisterAdapter.
+ PhysicalAddress - Physical address.
+ Length - Size of requested memory mapping
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG addressSpace = 0;
+ ULONG NumberOfElements;
+ PHYSICAL_ADDRESS PhysicalTemp;
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusType :
+ Miniport->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusNumber :
+ Miniport->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+
+ NumberOfElements = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources->List[0].PartialResourceList.Count + 1:
+ Miniport->Resources->List[0].PartialResourceList.Count + 1);
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources:
+ Miniport->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements-1)
+ );
+ } else {
+
+ //
+ // Setup initial resource info -- NOTE: This is definitely a mini-port
+ //
+ ASSERT(AdptrP->DeviceObject == NULL);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup memory
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Start =
+ PhysicalAddress;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Memory.Length =
+ Length;
+ Resources->List[0].PartialResourceList.Count++;
+
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver :
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->DeviceObject:
+ Miniport->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources :
+ Miniport->Resources) != NULL) {
+ ExFreePool(((AdptrP->DeviceObject != NULL) ?
+ AdptrP->Resources:
+ Miniport->Resources));
+ }
+
+ if (AdptrP->DeviceObject != NULL) {
+ AdptrP->Resources = Resources;
+ } else {
+ Miniport->Resources = Resources;
+ }
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+
+ if (Conflict) {
+
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ volatile ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer :
+ Miniport->MiniportName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ &(AdptrP->AdapterName.Buffer[++i]):
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdptrP->DeviceObject != NULL) ?
+ ((ULONG)AdptrP->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->DeviceObject:
+ Miniport->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 34) // wstrlen("FFFFFFFFFFFFFFFF") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_MEMORY_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in memory address
+ //
+
+ for (StringSize = 0; StringSize < 2; StringSize++) {
+
+ if (StringSize == 0) {
+
+ //
+ // Do high part
+ //
+
+ Value = NdisGetPhysicalAddressHigh(PhysicalAddress);
+
+ } else {
+
+ //
+ // Do Low part
+ //
+
+ Value = NdisGetPhysicalAddressLow(PhysicalAddress);
+
+ }
+
+ //
+ // Convert value
+ //
+
+ for (i = 1; i <= (sizeof(ULONG) * 2); i++) {
+
+ switch ((Value >> (((sizeof(ULONG) * 2) - i) * 4)) & 0x0F) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ case 10:
+ Character = L'A';
+ break;
+ case 11:
+ Character = L'B';
+ break;
+ case 12:
+ Character = L'C';
+ break;
+ case 13:
+ Character = L'D';
+ break;
+ case 14:
+ Character = L'E';
+ break;
+ case 15:
+ Character = L'F';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ }
+
+ }
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ if ( !HalTranslateBusAddress(
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusType:
+ Miniport->BusType),
+ ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->BusNumber :
+ Miniport->BusNumber),
+ PhysicalAddress,
+ &addressSpace,
+ &PhysicalTemp
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE);
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *VirtualAddress = (PVOID)(PhysicalTemp.LowPart);
+
+ }
+
+ if (*VirtualAddress == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ } else {
+ *Status = NDIS_STATUS_SUCCESS;
+ }
+}
+
+NDIS_STATUS
+NdisAllocateMemory(
+ OUT PVOID *VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ )
+/*++
+
+Routine Description:
+
+ Allocate memory for use by a protocol or a MAC driver
+
+Arguments:
+
+ VirtualAddress - Returns a pointer to the allocated memory.
+ Length - Size of requested allocation in bytes.
+ MaximumPhysicalAddress - Highest addressable address of the allocated
+ memory.. 0 means highest system memory possible.
+ MemoryFlags - Bit mask that allows the caller to specify attributes
+ of the allocated memory. 0 means standard memory.
+
+ other options:
+
+ NDIS_MEMORY_CONTIGUOUS
+ NDIS_MEMORY_NONCACHED
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if successful.
+ NDIS_STATUS_FAILURE if not successful. *VirtualAddress will be NULL.
+
+
+--*/
+{
+ //
+ // Depending on the value of MemoryFlags, we allocate three different
+ // types of memory.
+ //
+
+ if (MemoryFlags == 0) {
+
+ *VirtualAddress = ExAllocatePoolWithTag(NonPagedPool, Length, 'maDN');
+
+ } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) {
+
+ *VirtualAddress = MmAllocateNonCachedMemory(Length);
+
+ } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) {
+
+ *VirtualAddress = MmAllocateContiguousMemory(Length, HighestAcceptableAddress);
+
+ }
+
+ if (*VirtualAddress == NULL) {
+
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisFreeMemory(
+ IN PVOID VirtualAddress,
+ IN UINT Length,
+ IN UINT MemoryFlags
+ )
+/*++
+
+Routine Description:
+
+ Releases memory allocated using NdisAllocateMemory.
+
+Arguments:
+
+ VirtualAddress - Pointer to the memory to be freed.
+ Length - Size of allocation in bytes.
+ MemoryFlags - Bit mask that allows the caller to specify attributes
+ of the allocated memory. 0 means standard memory.
+
+ other options:
+
+ NDIS_MEMORY_CONTIGUOUS
+ NDIS_MEMORY_NONCACHED
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Depending on the value of MemoryFlags, we allocate three free 3
+ // types of memory.
+ //
+
+ if (MemoryFlags == 0) {
+
+ ExFreePool(VirtualAddress);
+
+ } else if (MemoryFlags & NDIS_MEMORY_NONCACHED) {
+
+ MmFreeNonCachedMemory(VirtualAddress, Length);
+
+ } else if (MemoryFlags & NDIS_MEMORY_CONTIGUOUS) {
+
+ MmFreeContiguousMemory(VirtualAddress);
+
+ }
+
+}
+
+VOID
+NdisInitializeTimer(
+ IN OUT PNDIS_TIMER NdisTimer,
+ IN PNDIS_TIMER_FUNCTION TimerFunction,
+ IN PVOID FunctionContext
+ )
+/*++
+
+Routine Description:
+
+ Sets up an NdisTimer object, initializing the DPC in the timer to
+ the function and context.
+
+Arguments:
+
+ NdisTimer - the timer object.
+ TimerFunction - Routine to start.
+ FunctionContext - Context of TimerFunction.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KeInitializeTimer(&(NdisTimer)->Timer);
+
+ //
+ // Initialize our dpc. If Dpc was previously initialized, this will
+ // reinitialize it.
+ //
+
+ KeInitializeDpc(
+ &NdisTimer->Dpc,
+ (PKDEFERRED_ROUTINE) TimerFunction,
+ FunctionContext
+ );
+
+ KeSetImportanceDpc(
+ &NdisTimer->Dpc,
+ LowImportance
+ );
+}
+
+
+VOID
+NdisSetTimer(
+ IN PNDIS_TIMER NdisTimer,
+ IN UINT MillisecondsToDelay
+ )
+/*++
+
+Routine Description:
+
+ Sets up TimerFunction to fire after MillisecondsToDelay.
+
+Arguments:
+
+ NdisTimer - the timer object.
+ MillisecondsToDelay - Amount of time before TimerFunction is started.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LARGE_INTEGER FireUpTime;
+
+ FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsToDelay, -10000);
+
+ //
+ // Set the timer
+ //
+ KeSetTimer(
+ &NdisTimer->Timer,
+ FireUpTime,
+ &NdisTimer->Dpc
+ );
+}
+
+
+BOOLEAN
+NdisIsr(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Mac interrupts, calling the appropriate Mac ISR and DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(Context);
+
+ BOOLEAN (*InterruptIsr)(PVOID) = (BOOLEAN (*) (PVOID))(NdisInterrupt->MacIsr);
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ //
+ // Call MacIsr
+ //
+
+ if((*InterruptIsr)(NdisInterrupt->InterruptContext) != FALSE){
+
+ //
+ // Queue MacDpc if needed
+ //
+
+ Increment((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (!(KeInsertQueueDpc(&(NdisInterrupt->InterruptDpc),NULL,NULL))) {
+
+ //
+ // If the DPC was already queued, then we have an extra
+ // reference (we do it this way to ensure that the reference
+ // is added *before* the DPC is queued).
+ //
+
+ Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) {
+
+ //
+ // We need to queue a DPC to set the event because we
+ // can't do it from the ISR. We know that the interrupt
+ // DPC won't fire because the refcount is 0, so we reuse it.
+ //
+
+ KeInitializeDpc(
+ &NdisInterrupt->InterruptDpc,
+ NdisLastCountRemovedFunction,
+ (PVOID)(&NdisInterrupt->DpcsCompletedEvent)
+ );
+
+ //
+ // When NdisLastCountRemovedFunction runs it will set
+ // the event.
+ //
+
+ KeInsertQueueDpc (&(NdisInterrupt->InterruptDpc), NULL, NULL);
+
+ }
+ }
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
+
+VOID
+NdisLastCountRemovedFunction(
+ IN struct _KDPC *Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ Queued from NdisIsr if the refcount is zero and we need to
+ set the event, since we can't do that from an ISR.
+
+Arguments:
+
+ Dpc - Will be NdisInterrupt->InterruptDpc.
+
+ DeferredContext - Points to the event to set.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNREFERENCED_PARAMETER (Dpc);
+ UNREFERENCED_PARAMETER (SystemArgument1);
+ UNREFERENCED_PARAMETER (SystemArgument2);
+
+ KeSetEvent(
+ (PKEVENT)DeferredContext,
+ 0L,
+ FALSE
+ );
+}
+
+
+VOID
+NdisDpc(
+ IN PVOID SystemSpecific1,
+ IN PVOID InterruptContext,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+/*++
+
+Routine Description:
+
+ Handles ALL Mac interrupt DPCs, calling the appropriate Mac DPC
+ depending on the context.
+
+Arguments:
+
+ Interrupt - Interrupt object for the Mac.
+
+ Context - Really a pointer to the Interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Get adapter from context.
+ //
+
+ PNDIS_INTERRUPT NdisInterrupt = (PNDIS_INTERRUPT)(InterruptContext);
+
+ VOID (*MacDpc)(PVOID) = (VOID (*) (PVOID))(NdisInterrupt->MacDpc);
+
+ //
+ // Call MacDpc
+ //
+
+ (*((PNDIS_DEFERRED_PROCESSING)MacDpc))(SystemSpecific1,
+ NdisInterrupt->InterruptContext,
+ SystemSpecific2,
+ SystemSpecific3
+ );
+
+ Decrement((PLONG)&NdisInterrupt->DpcCount,&NdisInterrupt->DpcCountLock);
+
+ if (NdisInterrupt->Removing && (NdisInterrupt->DpcCount==0)) {
+
+ KeSetEvent(
+ &NdisInterrupt->DpcsCompletedEvent,
+ 0L,
+ FALSE
+ );
+ }
+
+
+}
+
+
+VOID
+NdisInitializeInterrupt(
+ OUT PNDIS_STATUS Status,
+ IN OUT PNDIS_INTERRUPT NdisInterrupt,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_INTERRUPT_SERVICE InterruptServiceRoutine,
+ IN PVOID InterruptContext,
+ IN PNDIS_DEFERRED_PROCESSING DeferredProcessingRoutine,
+ IN UINT InterruptVector,
+ IN UINT InterruptLevel,
+ IN BOOLEAN SharedInterrupt,
+ IN NDIS_INTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the interrupt and sets up the Dpc.
+
+Arguments:
+
+ Status - Status of this request.
+ InterruptDpc - The Dpc object corresponding to DeferredProcessingRoutine.
+ Interrupt - Points to driver allocated memory that the wrapper fills in
+ with information about the interrupt handler.
+ InterruptServiceRoutine - The ISR that is called for this interrupt.
+ InterruptContext - Value passed to the ISR.
+ DeferredProcessingRoutine - The DPC queued by the ISR.
+ InterruptVector - Interrupt number used by the ISR.
+ InterruptMode - Type of interrupt the adapter generates.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(NdisAdapterHandle);
+ ULONG Vector;
+ ULONG NumberOfElements;
+ KIRQL Irql;
+ KAFFINITY InterruptAffinity;
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ BOOLEAN IsAMiniport;
+ PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)(NdisInterrupt);
+
+ IsAMiniport = (AdptrP->DeviceObject == NULL);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if (((IsAMiniport ?
+ Miniport->BusType:
+ AdptrP->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ ((IsAMiniport ?
+ Miniport->BusNumber:
+ AdptrP->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the interrupt, and then re-submitting the resource list.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources) != NULL) {
+
+ NumberOfElements = (IsAMiniport ?
+ Miniport->Resources->List[0].PartialResourceList.Count + 1 :
+ AdptrP->Resources->List[0].PartialResourceList.Count + 1);
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if ((IsAMiniport ?
+ Miniport->Resources :
+ AdptrP->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ (IsAMiniport ?
+ Miniport->Resources :
+ AdptrP->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements - 1)
+ );
+
+ } else {
+
+ //
+ // Setup initial resource info
+ //
+ ASSERT(IsAMiniport);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup interrupt
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeInterrupt;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ SharedInterrupt ? CmResourceShareShared : CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ (InterruptMode == NdisInterruptLatched) ?
+ CM_RESOURCE_INTERRUPT_LATCHED :
+ CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Level =
+ InterruptLevel;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Interrupt.Vector =
+ InterruptVector;
+ Resources->List[0].PartialResourceList.Count++;
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ (IsAMiniport ?
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdptrP->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources) != NULL) {
+ ExFreePool((IsAMiniport ?
+ Miniport->Resources:
+ AdptrP->Resources));
+ }
+
+ if (IsAMiniport) {
+
+ Miniport->Resources = Resources;
+
+ } else {
+
+ AdptrP->Resources = Resources;
+
+
+ }
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer :
+ Miniport->MiniportName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdptrP->DeviceObject != NULL) ?
+ &(AdptrP->AdapterName.Buffer[++i]):
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdptrP->DeviceObject != NULL) ?
+ AdptrP->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdptrP->DeviceObject != NULL) ?
+ ((ULONG)AdptrP->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdptrP->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_INTERRUPT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in interrupt level
+ //
+
+ Value = InterruptLevel;
+
+ //
+ // Convert value
+ //
+ // I couldn't think of a better way to do this (with some
+ // loop). If you find one, plz put it in.
+ //
+
+ if (Value > 9) {
+
+ switch (Value / 10) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+
+ }
+
+ switch (Value) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // We must do this stuff first because if we connect the
+ // interrupt first then an interrupt could occur before
+ // the MacISR is recorded in the Ndis interrupt structure.
+ //
+
+ if (IsAMiniport) {
+
+ KeInitializeSpinLock(&(MiniportInterrupt->DpcCountLock));
+ Miniport->Interrupt = MiniportInterrupt;
+ MiniportInterrupt->DpcCount = 0;
+ MiniportInterrupt->MiniportIdField = NULL;
+ MiniportInterrupt->Miniport = Miniport;
+ MiniportInterrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler;
+ MiniportInterrupt->MiniportDpc = Miniport->DriverHandle->MiniportCharacteristics.HandleInterruptHandler;
+ MiniportInterrupt->SharedInterrupt = SharedInterrupt;
+ MiniportInterrupt->IsrRequested = (BOOLEAN)DeferredProcessingRoutine;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ } else {
+
+ NdisInterrupt->MacIsr = InterruptServiceRoutine;
+ NdisInterrupt->MacDpc = DeferredProcessingRoutine;
+ NdisInterrupt->InterruptContext = InterruptContext;
+ KeInitializeSpinLock(&(NdisInterrupt->DpcCountLock));
+ NdisInterrupt->DpcCount = 0;
+ NdisInterrupt->Removing = FALSE;
+
+ }
+
+ //
+ // This is used to tell when all Dpcs are completed after the
+ // interrupt has been removed.
+ //
+
+ KeInitializeEvent(
+ (IsAMiniport ?
+ &MiniportInterrupt->DpcsCompletedEvent :
+ &NdisInterrupt->DpcsCompletedEvent),
+ NotificationEvent,
+ FALSE
+ );
+
+ //
+ // Initialize our dpc.
+ //
+
+ if (NdisMacAdapterDpcTargetProcessor < 0) {
+ NdisMacAdapterDpcTargetProcessor = (**(PCCHAR *)&KeNumberProcessors) - 1;
+ }
+
+ if (IsAMiniport) {
+
+ KeInitializeDpc(
+ &MiniportInterrupt->InterruptDpc,
+ (PKDEFERRED_ROUTINE) NdisMDpc,
+ MiniportInterrupt
+ );
+
+ KeSetImportanceDpc(
+ &MiniportInterrupt->InterruptDpc,
+ LowImportance
+ );
+
+ KeSetTargetProcessorDpc (
+ &MiniportInterrupt->InterruptDpc,
+ NdisMacAdapterDpcTargetProcessor
+ );
+ } else {
+
+ KeInitializeDpc(
+ &NdisInterrupt->InterruptDpc,
+ (PKDEFERRED_ROUTINE) NdisDpc,
+ NdisInterrupt
+ );
+
+ KeSetImportanceDpc(
+ &NdisInterrupt->InterruptDpc,
+ LowImportance
+ );
+
+ KeSetTargetProcessorDpc (
+ &NdisInterrupt->InterruptDpc,
+ NdisMacAdapterDpcTargetProcessor
+ );
+ }
+
+ NdisMacAdapterDpcTargetProcessor -= 1;
+
+ //
+ // Get the system interrupt vector and IRQL.
+ //
+
+ Vector = HalGetInterruptVector(
+ (IsAMiniport ?
+ Miniport->BusType :
+ AdptrP->BusType), // InterfaceType
+ (IsAMiniport ?
+ Miniport->BusNumber :
+ AdptrP->BusNumber), // BusNumber
+ (ULONG)InterruptLevel, // BusInterruptLevel
+ (ULONG)InterruptVector, // BusInterruptVector
+ &Irql, // Irql
+ &InterruptAffinity
+ );
+
+ if (IsAMiniport) {
+
+ NtStatus = IoConnectInterrupt(
+ &MiniportInterrupt->InterruptObject,
+ (PKSERVICE_ROUTINE)NdisMIsr,
+ MiniportInterrupt,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)InterruptMode,
+ SharedInterrupt,
+ InterruptAffinity,
+ FALSE
+ );
+
+ } else {
+
+ NtStatus = IoConnectInterrupt(
+ &NdisInterrupt->InterruptObject,
+ (PKSERVICE_ROUTINE)NdisIsr,
+ NdisInterrupt,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ (KINTERRUPT_MODE)InterruptMode,
+ SharedInterrupt,
+ InterruptAffinity,
+ FALSE
+ );
+ }
+
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+}
+
+VOID
+NdisRemoveInterrupt(
+ IN PNDIS_INTERRUPT Interrupt
+ )
+/*++
+
+Routine Description:
+
+ Removes the interrupt, will not return until all interrupts and
+ interrupt dpcs are completed.
+
+Arguments:
+
+ Interrupt - Points to driver allocated memory that the wrapper filled
+ with information about the interrupt handler.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MINIPORT_INTERRUPT MiniportInterrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
+
+ if (MiniportInterrupt->MiniportIdField == NULL) {
+
+ MiniportInterrupt->Miniport->BeingRemoved = TRUE;
+
+ } else {
+
+ Interrupt->Removing = TRUE;
+
+ }
+
+ //
+ // Now we disconnect the interrupt. NOTE: they are aligned in both structures
+ //
+
+ IoDisconnectInterrupt(
+ Interrupt->InterruptObject
+ );
+
+ //
+ // Right now we know that any Dpcs that may fire are counted.
+ // We don't have to guard this with a spin lock because the
+ // Dpc will set the event if if completes first, or we may
+ // wait for a little while for it to complete.
+ //
+
+ if (Interrupt->DpcCount > 0) {
+
+ //
+ // Now we wait for all dpcs to complete.
+ //
+
+ KeWaitForSingleObject(
+ &Interrupt->DpcsCompletedEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(
+ &Interrupt->DpcsCompletedEvent
+ );
+
+
+ }
+
+}
+
+
+
+VOID
+NdisUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a driver is supposed to unload. Ndis
+ converts this into a set of calls to MacRemoveAdapter() for each
+ adapter that the Mac has open. When the last adapter deregisters
+ itself it will call MacUnload().
+
+Arguments:
+
+ DriverObject - the driver object for the mac that is to unload.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_MAC_BLOCK MacP;
+ PNDIS_ADAPTER_BLOCK Adapter, NextAdapter;
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ //
+ // Search for the MacP
+ //
+
+ MacP = NdisMacList;
+
+ while (MacP != (PNDIS_MAC_BLOCK)NULL) {
+
+ if (MacP->NdisMacInfo->NdisWrapperDriver == DriverObject) {
+
+ break;
+
+ }
+
+ MacP = MacP->NextMac;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ if (MacP == (PNDIS_MAC_BLOCK)NULL) {
+
+ //
+ // It is already gone. Just return.
+ //
+
+ return;
+
+ }
+
+ MacP->Unloading = TRUE;
+
+
+ //
+ // Now call MACRemoveAdapter() for each Adapter.
+ //
+
+ Adapter = MacP->AdapterQueue;
+
+ while (Adapter != (PNDIS_ADAPTER_BLOCK)NULL) {
+
+ NextAdapter = Adapter->NextAdapter; // since queue may change
+
+ (MacP->MacCharacteristics.RemoveAdapterHandler)(
+ Adapter->MacAdapterContext
+ );
+
+ //
+ // If a shutdown handler was registered then deregister it.
+ //
+ NdisDeregisterAdapterShutdownHandler(Adapter);
+
+ Adapter = NextAdapter;
+
+ }
+
+
+ //
+ // Wait for all adapters to be gonzo.
+ //
+
+ KeWaitForSingleObject(
+ &MacP->AdaptersRemovedEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PTIME)NULL
+ );
+
+ KeResetEvent(
+ &MacP->AdaptersRemovedEvent
+ );
+
+
+ //
+ // Now call the MACUnload routine
+ //
+
+ (MacP->MacCharacteristics.UnloadMacHandler)(MacP->MacMacContext);
+
+
+ //
+ // Now remove the last reference (this will remove it from the list)
+ //
+ ASSERT(MacP->Ref.ReferenceCount == 1);
+
+ NdisDereferenceMac(MacP);
+}
+
+
+NTSTATUS
+NdisShutdown(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
+ shutdown routine, if one is registered.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
+ PNDIS_ADAPTER_BLOCK Miniport = (PNDIS_ADAPTER_BLOCK)(WrapperContext + 1);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisShutdown\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+
+ //
+ // Call the shutdown routine
+ //
+
+ WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisShutdown\n");
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+NdisAllocateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ OUT PVOID *VirtualAddress,
+ OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory to be shared between the driver and the adapter.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - Length of the memory to allocate.
+ Cached - TRUE if memory is to be cached.
+ VirtualAddress - Returns the virtual address of the memory,
+ or NULL if the memory cannot be allocated.
+ PhysicalAddress - Returns the physical address of the memory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Alignment;
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PADAPTER_OBJECT SystemAdapterObject;
+ PNDIS_WRAPPER_CONTEXT WrapperContext;
+ PULONG Page;
+ ULONG Type;
+
+ //
+ // Get interesting information from the adapter/miniport.
+ //
+
+ if ( AdaptP->DeviceObject != NULL ) {
+ SystemAdapterObject = AdaptP->SystemAdapterObject;
+ WrapperContext = AdaptP->WrapperContext;
+ } else {
+ SystemAdapterObject = Miniport->SystemAdapterObject;
+ WrapperContext = Miniport->WrapperContext;
+ }
+
+ //
+ // Non-busmasters shouldn't call this routine.
+ //
+
+ if (SystemAdapterObject == NULL) {
+ *VirtualAddress = NULL;
+ KdPrint(("NDIS: You are not a busmaster\n"));
+ return;
+ }
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Alignment = HalGetDmaAlignmentRequirement();
+ if (sizeof(ULONG) > Alignment) {
+ Alignment = sizeof(ULONG);
+ }
+
+ Length = (Length + Alignment - 1) & ~(Alignment - 1);
+
+ //
+ // Check to determine is there is enough room left in the current page
+ // to satisfy the allocation.
+ //
+
+ Type = Cached ? 1 : 0;
+ ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
+ if (WrapperContext->SharedMemoryLeft[Type] < Length) {
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE) {
+
+ //
+ // The allocation is greater than a page.
+ //
+
+ *VirtualAddress = HalAllocateCommonBuffer(
+ SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ Cached);
+
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+ }
+
+ //
+ // Allocate a new page for shared alocation.
+ //
+
+ WrapperContext->SharedMemoryPage[Type] =
+ HalAllocateCommonBuffer(
+ SystemAdapterObject,
+ PAGE_SIZE,
+ &WrapperContext->SharedMemoryAddress[Type],
+ Cached);
+
+ if (WrapperContext->SharedMemoryPage[Type] == NULL) {
+ WrapperContext->SharedMemoryLeft[Type] = 0;
+ *VirtualAddress = NULL;
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+ }
+
+ //
+ // Initialize the reference count in the last ULONG of the page.
+ //
+
+ Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] = 0;
+ WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(ULONG);
+ }
+
+ //
+ // Increment the reference count, set the address of the allocation,
+ // compute the physical address, and reduce the space remaining.
+ //
+
+ Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] += 1;
+ *VirtualAddress = (PVOID)((PUCHAR)Page +
+ (PAGE_SIZE - sizeof(ULONG) - WrapperContext->SharedMemoryLeft[Type]));
+
+#if !defined(BUILD_FOR_3_1)
+ PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart +
+ ((ULONG)*VirtualAddress & (PAGE_SIZE - 1));
+#else
+ *PhysicalAddress = RtlLargeIntegerAdd(
+ WrapperContext->SharedMemoryAddress[Type],
+ RtlConvertUlongToLargeInteger((ULONG)*VirtualAddress & (PAGE_SIZE - 1))
+ );
+#endif
+
+ WrapperContext->SharedMemoryLeft[Type] -= Length;
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+}
+
+
+#undef NdisUpdateSharedMemory
+
+VOID
+NdisUpdateSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Ensures that the data to be read from a shared memory region is
+ fully up-to-date.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - The length of the shared memory.
+ VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
+ PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // There is no underlying HAL routine for this anymore,
+ // it is not needed. This is macro'd to nothing in the
+ // header file now. This is there for backward compatibility
+
+ NdisAdapterHandle; Length; VirtualAddress; PhysicalAddress;
+
+}
+
+
+VOID
+NdisFreeSharedMemory(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG Length,
+ IN BOOLEAN Cached,
+ IN PVOID VirtualAddress,
+ IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates memory to be shared between the driver and the adapter.
+
+Arguments:
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+ Length - Length of the memory to allocate.
+ Cached - TRUE if memory was allocated cached.
+ VirtualAddress - Virtual address returned by NdisAllocateSharedMemory.
+ PhysicalAddress - The physical address returned by NdisAllocateSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Alignment;
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ PADAPTER_OBJECT SystemAdapterObject;
+ PNDIS_WRAPPER_CONTEXT WrapperContext;
+ PULONG Page;
+ ULONG Type;
+
+ //
+ // Get interesting information from the adapter/miniport.
+ //
+
+ if ( AdaptP->DeviceObject != NULL ) {
+ SystemAdapterObject = AdaptP->SystemAdapterObject;
+ WrapperContext = AdaptP->WrapperContext;
+ } else {
+ SystemAdapterObject = Miniport->SystemAdapterObject;
+ WrapperContext = Miniport->WrapperContext;
+ }
+
+ //
+ // Non-busmasters shouldn't call this routine.
+ //
+
+ ASSERT(SystemAdapterObject != NULL);
+
+ //
+ // Compute allocation size by aligning to the proper boundary.
+ //
+
+ ASSERT(Length != 0);
+
+ Alignment = HalGetDmaAlignmentRequirement();
+ if (sizeof(ULONG) > Alignment) {
+ Alignment = sizeof(ULONG);
+ }
+
+ Length = (Length + Alignment - 1) & ~(Alignment - 1);
+
+ //
+ // Free the specified memory.
+ //
+
+ ExAcquireResourceExclusive(&SharedMemoryResource, TRUE);
+ if ((Length + sizeof(ULONG)) >= PAGE_SIZE) {
+
+ //
+ // The allocation is greater than a page free the page directly.
+ //
+
+ HalFreeCommonBuffer(
+ SystemAdapterObject,
+ Length,
+ PhysicalAddress,
+ VirtualAddress,
+ Cached);
+
+ } else {
+
+ //
+ // Decrement the reference count and if the result is zero, then free
+ // the page.
+ //
+
+ Page = (PULONG)((ULONG)VirtualAddress & ~(PAGE_SIZE - 1));
+ Page[(PAGE_SIZE / sizeof(ULONG)) - 1] -= 1;
+ if (Page[(PAGE_SIZE / sizeof(ULONG)) - 1] == 0) {
+
+ //
+ // Compute the physical address of the page and free it.
+ //
+
+ PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1);
+ HalFreeCommonBuffer(
+ SystemAdapterObject,
+ PAGE_SIZE,
+ PhysicalAddress,
+ Page,
+ Cached);
+
+ Type = Cached ? 1 : 0;
+ if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type]) {
+ WrapperContext->SharedMemoryLeft[Type] = 0;
+ WrapperContext->SharedMemoryPage[Type] = NULL;
+ }
+ }
+ }
+
+ ExReleaseResource(&SharedMemoryResource);
+ return;
+}
+
+
+IO_ALLOCATION_ACTION
+NdisDmaExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is an execution routine for AllocateAdapterChannel,
+ if is called when an adapter channel allocated by NdisAllocate
+ DmaChannel is available.
+
+Arguments:
+
+ DeviceObject - The device object of the adapter.
+
+ Irp - ??.
+
+ MapRegisterBase - The address of the first translation table
+ assigned to us.
+
+ Context - A pointer to the NDIS_DMA_BLOCK in question.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)Context;
+
+ UNREFERENCED_PARAMETER (Irp);
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+
+ //
+ // Save the map register base.
+ //
+
+ DmaBlock->MapRegisterBase = MapRegisterBase;
+
+ //
+ // This will free the thread that is waiting for this callback.
+ //
+
+ KeSetEvent(
+ &DmaBlock->AllocationEvent,
+ 0L,
+ FALSE
+ );
+
+ return KeepObject;
+}
+
+
+
+VOID
+NdisAllocateDmaChannel(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisDmaHandle,
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_DMA_DESCRIPTION DmaDescription,
+ IN ULONG MaximumLength
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up a DMA channel for future DMA operations.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NdisDmaHandle - Returns a handle used to specify this channel to
+ future operations.
+
+ NdisAdapterHandle - handle returned by NdisRegisterAdapter.
+
+ DmaDescription - Details of the DMA channel.
+
+ MaximumLength - The maximum length DMA transfer that will be done
+ using this channel.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // For registering this set of resources
+ //
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+
+ //
+ // Needed to call HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersNeeded;
+
+ //
+ // Map registers allowed per channel.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Saves the structure we allocate for this channel.
+ //
+ PNDIS_DMA_BLOCK DmaBlock;
+
+ //
+ // Convert the handle to our internal structure.
+ PNDIS_ADAPTER_BLOCK AdapterBlock =
+ (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) NdisAdapterHandle;
+ BOOLEAN IsAMiniport;
+
+ //
+ // Save our IRQL when we raise it to call IoAllocateAdapterChannel.
+ //
+ KIRQL OldIrql;
+ ULONG NumberOfElements;
+
+ NTSTATUS NtStatus;
+
+ LARGE_INTEGER TimeoutValue;
+
+ IsAMiniport = (AdapterBlock->DeviceObject == NULL);
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if (((IsAMiniport ?
+ Miniport->BusType :
+ AdapterBlock->BusType) == (NDIS_INTERFACE_TYPE)-1) ||
+ ((IsAMiniport ?
+ Miniport->BusNumber :
+ AdapterBlock->BusNumber) == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ NumberOfElements =
+ (IsAMiniport ?
+ Miniport->Resources->List[0].PartialResourceList.Count :
+ AdapterBlock->Resources->List[0].PartialResourceList.Count) + 1;
+
+ } else {
+
+ NumberOfElements = 1;
+ }
+
+ //
+ // First check for resource conflict by expanding current resource list,
+ // adding in the mapped space, and then re-submitting the resource list.
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ NumberOfElements,
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ RtlCopyMemory (Resources,
+ (IsAMiniport ? Miniport->Resources : AdapterBlock->Resources),
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (NumberOfElements - 1)
+ );
+ } else {
+
+ //
+ // Setup initial resource info
+ //
+ ASSERT(IsAMiniport);
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = Miniport->AdapterType;
+ Resources->List[0].BusNumber = Miniport->BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup DMA Channel
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeDma;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ 0;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel =
+ (IsAMiniport ? Miniport->ChannelNumber :
+ (DmaDescription->DmaChannelSpecified ?
+ DmaDescription->DmaChannel : AdapterBlock->ChannelNumber));
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port =
+ DmaDescription->DmaPort;
+ Resources->List[0].PartialResourceList.Count++;
+
+
+ //
+ // Make the call
+ //
+
+ *Status = IoReportResourceUsage(
+ NULL,
+ (IsAMiniport ?
+ Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver :
+ AdapterBlock->MacHandle->NdisMacInfo->NdisWrapperDriver),
+ NULL,
+ 0,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ if ((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources) != NULL) {
+
+ ExFreePool((IsAMiniport ? Miniport->Resources : AdapterBlock->Resources));
+
+ }
+
+ if (IsAMiniport) {
+
+ Miniport->Resources = Resources;
+
+ } else {
+
+ AdapterBlock->Resources = Resources;
+
+ }
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (*Status != STATUS_SUCCESS)) {
+
+
+ if (Conflict) {
+
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG i;
+ ULONG StringSize;
+ PUCHAR Place;
+ PWCH baseFileName;
+ WCHAR Character;
+ ULONG Value;
+
+ baseFileName = (IsAMiniport ?
+ Miniport->MiniportName.Buffer :
+ AdapterBlock->AdapterName.Buffer);
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < (IsAMiniport ? Miniport->MiniportName.Length :
+ AdapterBlock->AdapterName.Length)
+ / sizeof(WCHAR);
+ i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ((IsAMiniport ?
+ Miniport->MiniportName.Buffer[i] :
+ AdapterBlock->AdapterName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+
+ baseFileName = (IsAMiniport ?
+ &(Miniport->MiniportName.Buffer[++i]) :
+ &(AdapterBlock->AdapterName.Buffer[++i]));
+
+ }
+
+ }
+
+ StringSize = (IsAMiniport ?
+ Miniport->MiniportName.MaximumLength :
+ AdapterBlock->AdapterName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ (IsAMiniport ?
+ ((ULONG)Miniport->MiniportName.Buffer) :
+ ((ULONG)AdapterBlock->AdapterName.Buffer)));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (IsAMiniport ?
+ Miniport->DeviceObject :
+ AdapterBlock->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize +
+ 6) // wstrlen("99") * sizeof(WHCAR) + sizeof(UNICODE_NULL)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_DMA_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize;
+
+ } else {
+
+ Place = ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET);
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ errorLogEntry->NumberOfStrings++;
+
+ //
+ // Put in dma channel
+ //
+
+ Value = (IsAMiniport ? Miniport->ChannelNumber :
+ AdapterBlock->ChannelNumber);
+
+ //
+ // Convert value
+ //
+ // I couldn't think of a better way to do this (with some
+ // loop). If you find one, plz put it in.
+ //
+
+ if (Value > 9) {
+
+ switch (Value / 10) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Value -= 10;
+
+ }
+
+ switch (Value) {
+
+ case 0:
+ Character = L'0';
+ break;
+ case 1:
+ Character = L'1';
+ break;
+ case 2:
+ Character = L'2';
+ break;
+ case 3:
+ Character = L'3';
+ break;
+ case 4:
+ Character = L'4';
+ break;
+ case 5:
+ Character = L'5';
+ break;
+ case 6:
+ Character = L'6';
+ break;
+ case 7:
+ Character = L'7';
+ break;
+ case 8:
+ Character = L'8';
+ break;
+ case 9:
+ Character = L'9';
+ break;
+ }
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ Place += sizeof(WCHAR);
+
+ Character = UNICODE_NULL;
+
+ memcpy((PVOID)Place, (PVOID)&Character, sizeof(WCHAR));
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+ *Status = NDIS_STATUS_RESOURCE_CONFLICT;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = (IsAMiniport ? Miniport->Master : FALSE);
+ DeviceDescription.ScatterGather = (IsAMiniport ? Miniport->Master : FALSE);
+ DeviceDescription.DemandMode = DmaDescription->DemandMode;
+ DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize;
+ DeviceDescription.Dma32BitAddresses = (IsAMiniport ? Miniport->Dma32BitAddresses : FALSE);
+ DeviceDescription.BusNumber = (IsAMiniport ? Miniport->BusNumber : AdapterBlock->BusNumber);
+ DeviceDescription.DmaChannel = (IsAMiniport ? Miniport->ChannelNumber :
+ (DmaDescription->DmaChannelSpecified ?
+ DmaDescription->DmaChannel : AdapterBlock->ChannelNumber));
+ DeviceDescription.InterfaceType = (IsAMiniport ? Miniport->BusType : AdapterBlock->BusType);
+ DeviceDescription.DmaWidth = DmaDescription->DmaWidth;
+ DeviceDescription.DmaSpeed = DmaDescription->DmaSpeed;
+ DeviceDescription.MaximumLength = MaximumLength;
+ DeviceDescription.DmaPort = DmaDescription->DmaPort;
+
+
+ MapRegistersNeeded = ((MaximumLength - 2) / PAGE_SIZE) + 2;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersNeeded)) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+
+ //
+ // Allocate storage for our DMA block.
+ //
+
+ DmaBlock = (PNDIS_DMA_BLOCK)ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_DMA_BLOCK), 'bdDN');
+
+ if (DmaBlock == (PNDIS_DMA_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+
+ //
+ // Use this event to tell us when NdisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ KeInitializeEvent(
+ &DmaBlock->AllocationEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ //
+ // We save this to call IoFreeAdapterChannel later.
+ //
+
+ DmaBlock->SystemAdapterObject = AdapterObject;
+
+
+ //
+ // Now allocate the adapter channel.
+ //
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NtStatus = IoAllocateAdapterChannel(
+ AdapterObject,
+ (IsAMiniport ? Miniport->DeviceObject : AdapterBlock->DeviceObject),
+ MapRegistersNeeded,
+ NdisDmaExecutionRoutine,
+ (PVOID)DmaBlock
+ );
+
+ KeLowerIrql(OldIrql);
+
+ if (!NT_SUCCESS(NtStatus)) {
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool (DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // NdisDmaExecutionRoutine will set this event
+ // when it has been called.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &DmaBlock->AllocationEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool (DmaBlock);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ KeResetEvent(
+ &DmaBlock->AllocationEvent
+ );
+
+
+ //
+ // We now have the DMA channel allocated, we are done.
+ //
+
+ DmaBlock->InProgress = FALSE;
+
+ *NdisDmaHandle = (NDIS_HANDLE)DmaBlock;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisFreeDmaChannel(
+ IN PNDIS_HANDLE NdisDmaHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Frees a DMA channel allocated with NdisAllocateDmaChannel.
+
+Arguments:
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel, indicating the
+ DMA channel that is to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KIRQL OldIrql;
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ IoFreeAdapterChannel (DmaBlock->SystemAdapterObject);
+ KeLowerIrql(OldIrql);
+
+ ExFreePool (DmaBlock);
+
+}
+
+
+VOID
+NdisSetupDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ Sets up the host DMA controller for a DMA transfer. The
+ DMA controller is set up to transfer the specified MDL.
+ Since we register all DMA channels as non-scatter/gather,
+ IoMapTransfer will ensure that the entire MDL is
+ in a single logical piece for transfer.
+
+Arguments:
+
+ Status - Returns the status of the request.
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel.
+
+ Buffer - An NDIS_BUFFER which describes the host memory involved in the
+ transfer.
+
+ Offset - An offset within buffer where the transfer should
+ start.
+
+ Length - The length of the transfer. VirtualAddress plus Length must not
+ extend beyond the end of the buffer.
+
+ WriteToDevice - TRUE for a download operation (host to adapter); FALSE
+ for an upload operation (adapter to host).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+ PHYSICAL_ADDRESS LogicalAddress;
+ ULONG LengthMapped;
+
+
+ //
+ // Make sure another request is not in progress.
+ //
+
+ if (DmaBlock->InProgress) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ DmaBlock->InProgress = TRUE;
+
+ //
+ // Use IoMapTransfer to set up the transfer.
+ //
+
+ LengthMapped = Length;
+
+ LogicalAddress = IoMapTransfer(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ &LengthMapped,
+ WriteToDevice
+ );
+
+ if (LengthMapped != Length) {
+
+ //
+ // Somehow the request could not be mapped competely,
+ // this should not happen for a non-scatter/gather adapter.
+ //
+
+ (VOID)IoFlushAdapterBuffers(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ LengthMapped,
+ WriteToDevice
+ );
+
+ DmaBlock->InProgress = FALSE;
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisCompleteDmaTransfer(
+ OUT PNDIS_STATUS Status,
+ IN PNDIS_HANDLE NdisDmaHandle,
+ IN PNDIS_BUFFER Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ Completes a previously started DMA transfer.
+
+Arguments:
+
+ Status - Returns the status of the transfer.
+
+ NdisDmaHandle - Handle returned by NdisAllocateDmaChannel.
+
+ Buffer - An NDIS_BUFFER which was passed to NdisSetupDmaTransfer.
+
+ Offset - the offset passed to NdisSetupDmaTransfer.
+
+ Length - The length passed to NdisSetupDmaTransfer.
+
+ WriteToDevice - TRUE for a download operation (host to adapter); FALSE
+ for an upload operation (adapter to host).
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)NdisDmaHandle;
+ BOOLEAN Successful;
+
+ Successful = IoFlushAdapterBuffers(
+ DmaBlock->SystemAdapterObject,
+ (PMDL)Buffer,
+ DmaBlock->MapRegisterBase,
+ (PUCHAR)(MmGetMdlVirtualAddress(Buffer)) + Offset,
+ Length,
+ WriteToDevice);
+
+ *Status = (Successful ? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES);
+ DmaBlock->InProgress = FALSE;
+
+}
+
+//
+// Requests used by protocol modules
+//
+//
+
+VOID
+NdisRegisterProtocol(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisProtocolHandle,
+ IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS protocol.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisProtocolHandle - Returns a handle referring to this protocol.
+ ProtocolCharacteritics - The NDIS_PROTOCOL_CHARACTERISTICS table.
+ CharacteristicsLength - The length of ProtocolCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PROTOCOL_BLOCK NewProtP;
+ UINT MemNeeded;
+
+ //
+ // Do any initial initialization that may be necessary. Note: this
+ // routine will notice if this is the second or later call to it.
+ //
+ *Status = NdisInitialInit( NULL );
+ if (!NT_SUCCESS(*Status)) {
+ return;
+ }
+
+ //
+ // Check that this is an NDIS 3.1 protocol.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterProtocol\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(ProtocolCharacteristics->OpenAdapterCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: OpenAdapterCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->CloseAdapterCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: CloseAdapterCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->SendCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: SendCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->TransferDataCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: TransferDataCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ResetCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: ResetCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->RequestCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: RequestCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveHandler)) {
+ NdisPrint1("RegisterProtocol: ReceiveHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->ReceiveCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: ReceiveCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusHandler)) {
+ NdisPrint1("RegisterProtocol: StatusHandler Null\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolCharacteristics->StatusCompleteHandler)) {
+ NdisPrint1("RegisterProtocol: StatusCompleteHandler Null\n");
+ DbgBreakPoint();
+ }
+ }
+
+
+ if (ProtocolCharacteristics->MajorNdisVersion != 3 ||
+ ProtocolCharacteristics->MinorNdisVersion != 0) {
+ *Status = NDIS_STATUS_BAD_VERSION;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ if (CharacteristicsLength < sizeof(NDIS_PROTOCOL_CHARACTERISTICS)) {
+ *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Allocate memory for the NDIS protocol block.
+ //
+
+ MemNeeded = sizeof(NDIS_PROTOCOL_BLOCK);
+ NewProtP = (PNDIS_PROTOCOL_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bpDN');
+ if (NewProtP == (PNDIS_PROTOCOL_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+ return;
+ }
+ RtlZeroMemory(NewProtP, sizeof(NDIS_PROTOCOL_BLOCK));
+
+ NewProtP->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ RtlCopyMemory((PVOID)&NewProtP->ProtocolCharacteristics,
+ (PVOID)ProtocolCharacteristics, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+
+#if NDISDBG
+ IF_TRACE(TRACE_IMPT) NdisPrint2(" Protocol: %s\n",ProtocolCharacteristics->Name);
+#endif
+
+ //
+ // No opens for this protocol yet.
+ //
+
+ NewProtP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NdisInitializeRef(&NewProtP->Ref);
+ *NdisProtocolHandle = (NDIS_HANDLE)NewProtP;
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterProtocol\n");
+}
+
+VOID
+NdisDeregisterProtocol(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisProtocolHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS protocol.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
+
+Return Value:
+
+ None.
+
+Note:
+
+ This will kill all the opens for this protocol.
+
+--*/
+
+{
+
+ PNDIS_PROTOCOL_BLOCK OldProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+
+ //
+ // If the protocol is already closing, return.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&OldProtP->ProtocolCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisProtocolHandle)) {
+ NdisPrint1("DeregisterProtocol: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle)) {
+ NdisPrint1("DeregisterProtocol: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldProtP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n");
+ return;
+ }
+
+
+ //
+ // Kill all the opens for this protocol.
+ //
+
+ while (OldProtP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) {
+
+ //
+ // This removes it from the protocol's OpenQueue etc.
+ //
+
+ NdisKillOpenAndNotifyProtocol(OldProtP->OpenQueue);
+ }
+
+ NdisDereferenceProtocol(OldProtP);
+
+ *Status = NDIS_STATUS_SUCCESS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterProtocol\n");
+}
+
+
+NDIS_STATUS
+NdisMacReceiveHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+ KIRQL oldIrql;
+
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ Status =
+ (Open->PostNt31ReceiveHandler) (
+ ProtocolBindingContext,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize);
+
+ KeLowerIrql( oldIrql );
+ return Status;
+}
+
+
+VOID
+NdisMacReceiveCompleteHandler(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK Open;
+ KIRQL oldIrql;
+ KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
+
+ //
+ // Find protocol binding context and get associated open for it.
+ //
+ Open = GetOpenBlockFromProtocolBindingContext(ProtocolBindingContext);
+ ASSERT(Open != NULL);
+
+ (Open->PostNt31ReceiveCompleteHandler) (
+ ProtocolBindingContext
+ );
+ KeLowerIrql( oldIrql );
+ return;
+}
+
+PNDIS_OPEN_BLOCK
+GetOpenBlockFromProtocolBindingContext(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+{
+ PNDIS_OPEN_BLOCK TmpOpen;
+ PNDIS_OPEN_BLOCK PrvOpen = NULL;
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen != NULL) {
+
+ if (TmpOpen->ProtocolBindingContext == ProtocolBindingContext) {
+
+ if (TmpOpen != GlobalOpenList) {
+
+ //
+ // Put this one at the front of the list
+ //
+
+ PrvOpen->NextGlobalOpen = TmpOpen->NextGlobalOpen;
+ TmpOpen->NextGlobalOpen = GlobalOpenList;
+ GlobalOpenList = TmpOpen;
+
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ return(TmpOpen);
+
+ }
+
+ PrvOpen = TmpOpen;
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ return((PNDIS_OPEN_BLOCK)NULL);
+
+}
+
+VOID
+MiniportOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation,
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PNDIS_OPEN_BLOCK NewOpenP,
+ IN PFILE_OBJECT FileObject,
+ IN BOOLEAN UsingEncapsulation
+ )
+/*++
+
+Routine Description:
+
+ This routine handles opening a miniport either directly from NdisOpenAdapter()
+ of from our deferred processing routine if the open had to pend.
+
+ NOTE: Must be called with spin lock held.
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_M_OPEN_BLOCK MiniportOpen;
+ PNDIS_MAC_BLOCK FakeMac;
+ BOOLEAN FilterOpen;
+ PNDIS_PROTOCOL_BLOCK TmpProtP;
+
+ ASSERT( MINIPORT_LOCK_ACQUIRED(Miniport) );
+
+ if (!NdisReferenceMiniport(Miniport)) {
+
+ //
+ // The adapter is closing.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+
+ *Status = NDIS_STATUS_CLOSING;
+
+ return;
+ }
+
+ //
+ // Increment the protocol's reference count.
+ //
+
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+
+ if (!NdisReferenceProtocol(TmpProtP)) {
+
+ //
+ // The protocol is closing.
+ //
+
+ NdisDereferenceMiniport(Miniport);
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ return;
+ }
+
+
+ //
+ // Now allocate a complete set of MAC structures for the protocol
+ // and set them up to transfer to the Miniport handler routines.
+ //
+
+ if (Miniport->DriverHandle->FakeMac == NULL) {
+
+ FakeMac = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_MAC_BLOCK),
+ ' DN'
+ );
+
+ if (FakeMac == NULL) {
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ RtlZeroMemory(FakeMac, sizeof(NDIS_MAC_BLOCK));
+ Miniport->DriverHandle->FakeMac = FakeMac;
+ FakeMac->MacCharacteristics.OpenAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.CloseAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.SendHandler = NdisMSend;
+ FakeMac->MacCharacteristics.ResetHandler = NdisMReset;
+ FakeMac->MacCharacteristics.RequestHandler = NdisMRequest;
+ FakeMac->MacCharacteristics.QueryGlobalStatisticsHandler = NULL;
+ FakeMac->MacCharacteristics.UnloadMacHandler = NULL;
+ FakeMac->MacCharacteristics.AddAdapterHandler = NULL;
+ FakeMac->MacCharacteristics.RemoveAdapterHandler = NULL;
+
+ //
+ // If transfer data calls don't pend then we'll use the faster
+ // NdisMTransferDataSync().
+ //
+
+ if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) {
+ FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferDataSync;
+ } else {
+ FakeMac->MacCharacteristics.TransferDataHandler = NdisMTransferData;
+ }
+
+ //
+ // Keep the SendHandler the same for WAN miniports
+ //
+
+ if (Miniport->MediaType == NdisMediumWan) {
+
+ FakeMac->MacCharacteristics.SendHandler =
+ (PVOID)Miniport->DriverHandle->MiniportCharacteristics.SendHandler;
+ }
+
+ } else {
+
+ FakeMac = Miniport->DriverHandle->FakeMac;
+
+ }
+
+ //
+ // Allocate an open within the Miniport context
+ //
+ MiniportOpen = (PNDIS_M_OPEN_BLOCK)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_M_OPEN_BLOCK),
+ ' DN'
+ );
+
+ if (MiniportOpen == (PNDIS_M_OPEN_BLOCK)NULL) {
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+ NdisZeroMemory(MiniportOpen, sizeof(NDIS_M_OPEN_BLOCK));
+
+ MiniportOpen->DriverHandle = Miniport->DriverHandle;
+ MiniportOpen->MiniportHandle = Miniport;
+ MiniportOpen->ProtocolHandle = TmpProtP;
+ MiniportOpen->FakeOpen = NewOpenP;
+ MiniportOpen->ProtocolBindingContext = ProtocolBindingContext;
+ MiniportOpen->MiniportAdapterContext = Miniport->MiniportAdapterContext;
+ MiniportOpen->FileObject = FileObject;
+ MiniportOpen->Closing = FALSE;
+ MiniportOpen->CloseRequestHandle = 0;
+ MiniportOpen->CurrentLookahead = Miniport->CurrentLookahead;
+
+ NdisAllocateSpinLock(&(MiniportOpen->SpinLock));
+
+ MiniportOpen->References = 1;
+ MiniportOpen->UsingEthEncapsulation = UsingEncapsulation;
+ MiniportOpen->SendHandler =
+ Miniport->DriverHandle->MiniportCharacteristics.SendHandler;
+ MiniportOpen->TransferDataHandler =
+ Miniport->DriverHandle->MiniportCharacteristics.TransferDataHandler;
+ MiniportOpen->SendCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ MiniportOpen->TransferDataCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ MiniportOpen->ReceiveHandler =
+ TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ MiniportOpen->ReceiveCompleteHandler =
+ TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+
+ //
+ // Set up the elements of the open structure.
+ //
+
+ NdisAllocateSpinLock(&NewOpenP->SpinLock);
+ NewOpenP->Closing = FALSE;
+
+ NewOpenP->AdapterHandle = (NDIS_HANDLE) Miniport;
+ NewOpenP->ProtocolHandle = TmpProtP;
+ NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
+ NewOpenP->MacBindingHandle = (NDIS_HANDLE)MiniportOpen;
+
+ //
+ // for speed, instead of having to use AdapterHandle->MacHandle
+ //
+ NewOpenP->MacHandle = (NDIS_HANDLE)FakeMac;
+
+ //
+ // for even more speed....
+ //
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ NewOpenP->TransferDataHandler = NdisMArcTransferData;
+
+ } else {
+
+ if ( (Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0 ) {
+ NewOpenP->TransferDataHandler = NdisMTransferDataSync;
+ } else {
+ NewOpenP->TransferDataHandler = NdisMTransferData;
+ }
+ }
+
+ NewOpenP->SendHandler = NdisMSend;
+
+ //
+ // For WAN miniports, the send handler is different
+ //
+
+ if ( Miniport->MediaType == NdisMediumWan ) {
+
+ NewOpenP->SendHandler = (PVOID)NdisMWanSend;
+ }
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+ NewOpenP->ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+
+ //
+ // Save a pointer to the file object in the open...
+ //
+
+ NewOpenP->FileObject = FileObject;
+
+ //
+ // ...and a pointer to the open in the file object.
+ //
+
+ FileObject->FsContext = (PVOID)NewOpenP;
+
+ *NdisBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+ //
+ // Insert the open into the filter package
+ //
+
+ switch (Miniport->MediaType) {
+
+ case NdisMediumArcnet878_2:
+
+ if ( !UsingEncapsulation ) {
+
+ FilterOpen = ArcNoteFilterOpenAdapter(
+ Miniport->ArcDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+
+ break;
+ }
+
+ //
+ // If we're using ethernet encapsulation then
+ // we simply fall through to the ethernet stuff.
+ //
+
+ case NdisMedium802_3:
+
+ FilterOpen = EthNoteFilterOpenAdapter(
+ Miniport->EthDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+ case NdisMedium802_5:
+
+ FilterOpen = TrNoteFilterOpenAdapter(
+ Miniport->TrDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+ case NdisMediumFddi:
+
+ FilterOpen = FddiNoteFilterOpenAdapter(
+ Miniport->FddiDB,
+ MiniportOpen,
+ (NDIS_HANDLE)NewOpenP,
+ &MiniportOpen->FilterHandle
+ );
+ break;
+
+
+ case NdisMediumWan:
+ //
+ // Bogus non-NULL value
+ //
+
+ FilterOpen = 1;
+ break;
+ }
+
+ //
+ // Check for an open filter failure.
+ //
+
+ if ( !FilterOpen ) {
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceMiniport(Miniport);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)MiniportOpen);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ return;
+
+ }
+
+ NdisQueueOpenOnProtocol(NewOpenP, TmpProtP);
+
+ //
+ // Everything has been filled in. Synchronize access to the
+ // adapter block and link the new open adapter in.
+ //
+
+ MiniportOpen->MiniportNextOpen = Miniport->OpenQueue;
+ Miniport->OpenQueue = MiniportOpen;
+
+ //
+ // NOTE: This must be called at DPC_LEVEL, which it is.
+ //
+ MiniportAdjustMaximumLookahead(Miniport);
+
+ *Status = NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+MiniportFinishPendingOpens(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+ Handles any pending NdisOpenAdapter() calls for miniports.
+
+ NOTE: Must be called with spin lock held.
+
+ NOTE: Must be called with lock acquired flag set.
+
+Arguments:
+
+ Miniport.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen;
+ NDIS_STATUS Status;
+ NDIS_STATUS OpenErrorStatus;
+
+ while( Miniport->FirstPendingOpen != NULL ) {
+
+ MiniportPendingOpen = Miniport->FirstPendingOpen;
+
+ //
+ // Do the open again.
+ //
+
+ MiniportOpenAdapter(
+ &Status,
+ &OpenErrorStatus,
+ MiniportPendingOpen->NdisBindingHandle,
+ MiniportPendingOpen->NdisProtocolHandle,
+ MiniportPendingOpen->ProtocolBindingContext,
+ MiniportPendingOpen->AdapterName,
+ MiniportPendingOpen->OpenOptions,
+ MiniportPendingOpen->AddressingInformation,
+ MiniportPendingOpen->Miniport,
+ MiniportPendingOpen->NewOpenP,
+ MiniportPendingOpen->FileObject,
+ MiniportPendingOpen->UsingEncapsulation
+ );
+
+ //
+ // If the open didn't pend then call the NdisCompleteOpenAdapter(),
+ //
+
+ if ( Status != NDIS_STATUS_PENDING ) {
+
+ PNDIS_OPEN_BLOCK OpenP = MiniportPendingOpen->NewOpenP;
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ Status,
+ OpenErrorStatus
+ );
+ }
+
+ //
+ // Get the next pending open.
+ //
+
+ Miniport->FirstPendingOpen = MiniportPendingOpen->NextPendingOpen;
+
+ //
+ // We're done with this pending open context.
+ //
+
+ NdisFreeMemory(
+ MiniportPendingOpen,
+ sizeof(MINIPORT_PENDING_OPEN),
+ 0
+ );
+
+ }
+}
+
+
+
+UCHAR NdisInternalEaName[4] = "NDIS";
+UCHAR NdisInternalEaValue[8] = "INTERNAL";
+
+VOID
+NdisOpenAdapter(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PNDIS_HANDLE NdisBindingHandle,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE NdisProtocolHandle,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_STRING AdapterName,
+ IN UINT OpenOptions,
+ IN PSTRING AddressingInformation OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Opens a connection between a protocol and an adapter (MAC).
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisBindingHandle - Returns a handle referring to this open.
+ 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.
+ NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
+ ProtocolBindingContext - A context for indications.
+ AdapterName - The name of the adapter to open.
+ OpenOptions - bit mask.
+ AddressingInformation - Information passed to MacOpenAdapter.
+
+Return Value:
+
+ None.
+
+Note:
+
+ This function opens the adapter which will cause an IRP_MJ_CREATE
+ to be sent to the adapter, which is ignored. However, after that we
+ can access the file object for the open, and fill it in as
+ appropriate. The work is done here rather than in the IRP_MJ_CREATE
+ handler because this avoids having to pass the parameters to
+ NdisOpenAdapter through to the adapter.
+
+--*/
+
+{
+ HANDLE FileHandle;
+ OBJECT_ATTRIBUTES ObjectAttr;
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT DeviceObject;
+ PNDIS_OPEN_BLOCK NewOpenP;
+ PNDIS_PROTOCOL_BLOCK TmpProtP;
+ PNDIS_ADAPTER_BLOCK TmpAdaptP;
+ NDIS_STATUS OpenStatus;
+ NTSTATUS NtOpenStatus;
+ IO_STATUS_BLOCK IoStatus;
+ PFILE_FULL_EA_INFORMATION OpenEa;
+ ULONG OpenEaLength;
+ BOOLEAN UsingEncapsulation;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+
+ //
+ // Allocate memory for the NDIS open block.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisOpenAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisProtocolHandle)) {
+ NdisPrint1("OpenAdapter: Null ProtocolHandle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisProtocolHandle)) {
+ NdisPrint1("OpenAdapter: ProtocolHandle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(ProtocolBindingContext)) {
+ NdisPrint1("OpenAdapter: Null Context\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtocolBindingContext)) {
+ NdisPrint1("OpenAdapter: Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ NewOpenP = (PNDIS_OPEN_BLOCK) ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(NDIS_OPEN_BLOCK),
+ 'boDN'
+ );
+
+ if (NewOpenP == (PNDIS_OPEN_BLOCK)NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+
+ return;
+ }
+
+ RtlZeroMemory(NewOpenP, sizeof(NDIS_OPEN_BLOCK));
+
+ OpenEaLength = sizeof(FILE_FULL_EA_INFORMATION) +
+ sizeof(NdisInternalEaName) +
+ sizeof(NdisInternalEaValue);
+
+ OpenEa = ExAllocatePoolWithTag (NonPagedPool, OpenEaLength, ' DN');
+
+ if (OpenEa == NULL) {
+ ExFreePool (NewOpenP);
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+ OpenEa->NextEntryOffset = 0;
+ OpenEa->Flags = 0;
+ OpenEa->EaNameLength = sizeof(NdisInternalEaName);
+ OpenEa->EaValueLength = sizeof(NdisInternalEaValue);
+
+ RtlCopyMemory(
+ OpenEa->EaName,
+ NdisInternalEaName,
+ sizeof(NdisInternalEaName)
+ );
+
+ RtlCopyMemory(
+ &OpenEa->EaName[OpenEa->EaNameLength+1],
+ NdisInternalEaValue,
+ sizeof(NdisInternalEaValue)
+ );
+
+
+ //
+ // Obtain a handle to the driver's file object.
+ //
+
+ InitializeObjectAttributes(
+ &ObjectAttr,
+ AdapterName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+
+ NtOpenStatus = ZwCreateFile(&FileHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttr,
+ &IoStatus,
+ (PLARGE_INTEGER) NULL, // allocation size
+ 0L, // file attributes
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
+ FILE_OPEN, // create disposition
+ 0, // create options
+ OpenEa,
+ OpenEaLength);
+
+
+ ExFreePool(OpenEa);
+
+ if (NtOpenStatus != STATUS_SUCCESS) {
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+
+ //
+ // Convert the file handle into a pointer to the adapter's
+ // file object.
+ //
+
+ ObReferenceObjectByHandle(FileHandle,
+ 0,
+ NULL,
+ KernelMode,
+ (PVOID *) &FileObject,
+ NULL
+ );
+
+ //
+ // Close the file handle, now that we have the object reference.
+ //
+
+ ZwClose(FileHandle);
+
+ //
+ // From the file object, obtain the device object.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
+
+ //
+ // Increment the adapter's reference count.
+ //
+
+ TmpAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+
+ //
+ // Check if this is a Miniport or mac
+ //
+
+ if (TmpAdaptP->DeviceObject != DeviceObject) {
+
+ //
+ // It is a Miniport
+ //
+
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)TmpAdaptP;
+ ULONG i;
+
+ UsingEncapsulation = FALSE;
+
+ //
+ // Select the medium to use
+ //
+
+ for (i = 0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == Miniport->MediaType) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == MediumArraySize){
+
+ //
+ // Check for ethernet encapsulation on Arcnet as
+ // a possible combination.
+ //
+ if (Miniport->MediaType == NdisMediumArcnet878_2) {
+
+ for (i = 0; i < MediumArraySize; i++){
+
+ if (MediumArray[i] == NdisMedium802_3) {
+ break;
+ }
+ }
+
+ if (i == MediumArraySize) {
+
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ return;
+
+ }
+
+ //
+ // encapsulated ethernet, so we add in the wrapper's
+ // ability to support (emulate) the multicast stuff
+ //
+
+ Miniport->SupportedPacketFilters |= (NDIS_PACKET_TYPE_MULTICAST |
+ NDIS_PACKET_TYPE_ALL_MULTICAST);
+
+ UsingEncapsulation = TRUE;
+
+ } else {
+
+ *Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ return;
+
+ }
+
+ }
+
+ *SelectedMediumIndex = i;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->Lock);
+
+ //
+ // Lock the miniport. If the lock fails, then
+ // we must pend this open and try it later.
+ //
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ if ( LocalLock ) {
+
+ MiniportOpenAdapter(
+ Status,
+ OpenErrorStatus,
+ NdisBindingHandle,
+ NdisProtocolHandle,
+ ProtocolBindingContext,
+ AdapterName,
+ OpenOptions,
+ AddressingInformation,
+ Miniport,
+ NewOpenP,
+ FileObject,
+ UsingEncapsulation
+ );
+
+ } else {
+
+ PMINIPORT_PENDING_OPEN MiniportPendingOpen;
+
+ //
+ // Allocate some space for this pending structure.
+ // We free in after we call NdisOpenComplete.
+ //
+
+ *Status = NdisAllocateMemory(
+ (PVOID *) &MiniportPendingOpen,
+ sizeof(MINIPORT_PENDING_OPEN),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if ( *Status == NDIS_STATUS_SUCCESS ) {
+
+ //
+ // Save off the parameters for this open so we can
+ // do the actual NdisOpenAdapter() later on.
+ //
+
+ MiniportPendingOpen->NextPendingOpen = NULL;
+ MiniportPendingOpen->NdisBindingHandle = NdisBindingHandle;
+ MiniportPendingOpen->NdisProtocolHandle = NdisProtocolHandle;
+ MiniportPendingOpen->ProtocolBindingContext = ProtocolBindingContext;
+ MiniportPendingOpen->AdapterName = AdapterName;
+ MiniportPendingOpen->OpenOptions = OpenOptions;
+ MiniportPendingOpen->AddressingInformation = AddressingInformation;
+ MiniportPendingOpen->Miniport = Miniport;
+ MiniportPendingOpen->NewOpenP = NewOpenP;
+ MiniportPendingOpen->FileObject = FileObject;
+ MiniportPendingOpen->UsingEncapsulation = UsingEncapsulation;
+
+ if ( Miniport->FirstPendingOpen == NULL ) {
+
+ Miniport->FirstPendingOpen = MiniportPendingOpen;
+
+ } else {
+
+ Miniport->LastPendingOpen->NextPendingOpen = MiniportPendingOpen;
+ }
+
+ Miniport->LastPendingOpen = MiniportPendingOpen;
+
+ //
+ // Make sure MiniportProcessDeferred() completes the open.
+ //
+
+ *Status = NDIS_STATUS_PENDING;
+
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ } else {
+
+ ObDereferenceObject((PVOID) FileObject);
+ ExFreePool((PVOID) NewOpenP);
+ }
+ }
+
+ //
+ // Unlock the miniport.
+ //
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->Lock);
+ KeLowerIrql(OldIrql);
+
+ return;
+ }
+
+ //
+ // It is a mac
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint2("openadapter: adaptername=%s\n",TmpAdaptP->AdapterName.Buffer);
+ if (!NdisReferenceAdapter(TmpAdaptP)) {
+
+ //
+ // The adapter is closing.
+ //
+
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+ //
+ // Increment the protocol's reference count.
+ //
+
+ TmpProtP = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
+ if (!NdisReferenceProtocol(TmpProtP)) {
+
+ //
+ // The protocol is closing.
+ //
+
+ NdisDereferenceAdapter(TmpAdaptP);
+ ObDereferenceObject((PVOID)FileObject);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_CLOSING;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+ }
+
+
+ //
+ // Set up the elements of the open structure.
+ //
+
+ NdisAllocateSpinLock(&NewOpenP->SpinLock);
+ NewOpenP->Closing = FALSE;
+
+ NewOpenP->AdapterHandle = TmpAdaptP;
+ NewOpenP->ProtocolHandle = TmpProtP;
+
+ //
+ // for speed, instead of having to use AdapterHandle->MacHandle
+ //
+ NewOpenP->MacHandle = TmpAdaptP->MacHandle;
+
+ //
+ // for even more speed....
+ //
+
+ NewOpenP->SendHandler = TmpAdaptP->MacHandle->MacCharacteristics.SendHandler;
+ NewOpenP->TransferDataHandler = TmpAdaptP->MacHandle->MacCharacteristics.TransferDataHandler;
+
+ NewOpenP->SendCompleteHandler = TmpProtP->ProtocolCharacteristics.SendCompleteHandler;
+ NewOpenP->TransferDataCompleteHandler = TmpProtP->ProtocolCharacteristics.TransferDataCompleteHandler;
+
+ //
+ // Now we have to fake some stuff to get all indications to happen
+ // at DPC_LEVEL. What we do is start the pointer at an NDIS function
+ // which will guarantee that it occurs.
+ //
+ // Then, by extending the OPEN structure and adding the real handlers
+ // at the end we can use these for drivers compiled with this header.
+ //
+ NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
+ NewOpenP->PostNt31ReceiveHandler = TmpProtP->ProtocolCharacteristics.ReceiveHandler;
+ NewOpenP->PostNt31ReceiveCompleteHandler = TmpProtP->ProtocolCharacteristics.ReceiveCompleteHandler;
+ NewOpenP->ReceiveHandler = NdisMacReceiveHandler;
+ NewOpenP->ReceiveCompleteHandler = NdisMacReceiveCompleteHandler;
+
+ //
+ // Patch the open into the global list of macs
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ NewOpenP->NextGlobalOpen = GlobalOpenList;
+ GlobalOpenList = NewOpenP;
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+
+ //
+ // Save a pointer to the file object in the open...
+ //
+
+ NewOpenP->FileObject = FileObject;
+
+ //
+ // ...and a pointer to the open in the file object.
+ //
+
+ FileObject->FsContext = (PVOID)NewOpenP;
+
+
+ *NdisBindingHandle = (NDIS_HANDLE)NewOpenP;
+
+
+ //
+ // Call MacOpenAdapter, see what we shall see...
+ //
+
+ OpenStatus = (TmpAdaptP->MacHandle->MacCharacteristics.OpenAdapterHandler) (
+ OpenErrorStatus,
+ &NewOpenP->MacBindingHandle,
+ SelectedMediumIndex,
+ MediumArray,
+ MediumArraySize,
+ (NDIS_HANDLE)NewOpenP,
+ TmpAdaptP->MacAdapterContext,
+ OpenOptions,
+ AddressingInformation
+ );
+
+ if ((OpenStatus == NDIS_STATUS_SUCCESS) && NdisFinishOpen(NewOpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else if (OpenStatus == NDIS_STATUS_PENDING) {
+
+ *Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == NewOpenP) {
+
+ GlobalOpenList = NewOpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != NewOpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = NewOpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ObDereferenceObject((PVOID)FileObject);
+ NdisDereferenceAdapter(TmpAdaptP);
+ NdisDereferenceProtocol(TmpProtP);
+ ExFreePool((PVOID)NewOpenP);
+ *Status = NDIS_STATUS_OPEN_FAILED;
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisOpenAdapter\n");
+ return;
+}
+
+
+VOID
+NdisCloseAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a connection between a protocol and an adapter (MAC).
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisBindingHandle - The handle returned by NdisOpenAdapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_OPEN_BLOCK OpenP = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
+
+ if (OpenP->AdapterHandle->DeviceObject == NULL) {
+
+ //
+ // This is a Miniport
+ // This returns TRUE if it finished synchronously.
+ //
+
+ if (NdisMKillOpen(OpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ *Status = NDIS_STATUS_PENDING; // will complete later
+
+ }
+ return;
+ }
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCloseAdapter\n");
+ NdisPrint3(" Protocol %wZ is closing Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &(OpenP->AdapterHandle)->AdapterName);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisBindingHandle)) {
+ NdisPrint1("OpenAdapter: Null BindingHandle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingHandle)) {
+ NdisPrint1("OpenAdapter: BindingHandle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ //
+ // This returns TRUE if it finished synchronously.
+ //
+
+ if (NdisKillOpen(OpenP)) {
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ } else {
+
+ *Status = NDIS_STATUS_PENDING; // will complete later
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisCloseAdapter\n");
+#undef OpenP
+}
+
+
+//
+// Requests Used by MAC Drivers
+//
+//
+
+
+
+VOID
+NdisInitializeWrapper(
+ OUT PNDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2,
+ IN PVOID SystemSpecific3
+ )
+
+/*++
+
+Routine Description:
+
+ Called at the beginning of every MAC's initialization routine.
+
+Arguments:
+
+ NdisWrapperHandle - A MAC specific handle for the wrapper.
+
+ SystemSpecific1, a pointer to the driver object for the MAC.
+ SystemSpecific2, a PUNICODE_STRING containing the location of
+ the registry subtree for this driver.
+ SystemSpecific3, unused on NT.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+
+ PNDIS_WRAPPER_HANDLE NdisMacInfo;
+
+ UNREFERENCED_PARAMETER (SystemSpecific3);
+
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisInitializeWrapper\n");
+
+ Status = NdisAllocateMemory(
+ (PVOID*) (NdisWrapperHandle),
+ sizeof(NDIS_WRAPPER_HANDLE),
+ 0,
+ HighestAcceptableMax
+ );
+
+ if ( Status == NDIS_STATUS_SUCCESS ) {
+
+ NdisMacInfo = (PNDIS_WRAPPER_HANDLE) (*NdisWrapperHandle);
+ NdisMacInfo->NdisWrapperDriver = (PDRIVER_OBJECT) SystemSpecific1;
+ NdisMacInfo->NdisWrapperConfigurationHandle = (HANDLE) SystemSpecific2;
+
+ } else {
+
+ *NdisWrapperHandle = NULL;
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisInitializeWrapper\n");
+}
+
+VOID
+NdisTerminateWrapper(
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN PVOID SystemSpecific
+ )
+
+/*++
+
+Routine Description:
+
+ Called at the end of every MAC's termination routine.
+
+Arguments:
+
+ NdisWrapperHandle - The handle returned from NdisInitializeWrapper.
+
+ SystemSpecific - No defined value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisTerminateWrapper\n");
+
+ UNREFERENCED_PARAMETER(SystemSpecific);
+
+
+ if (NdisMacInfo != NULL) {
+
+ NdisFreeMemory(NdisMacInfo, sizeof(NDIS_WRAPPER_HANDLE), 0);
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisTerminateWrapper\n");
+
+ return;
+}
+
+VOID
+NdisRegisterMac(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE MacMacContext,
+ IN PNDIS_MAC_CHARACTERISTICS MacCharacteristics,
+ IN UINT CharacteristicsLength
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS MAC.
+
+Arguments:
+
+ Status - Returns the final status.
+ NdisMacHandle - Returns a handle referring to this MAC.
+ NdisWrapperHandle - Handle returned by NdisInitializeWrapper.
+ MacMacContext - Context for calling MACUnloadMac and MACAddAdapter.
+ MacCharacteritics - The NDIS_MAC_CHARACTERISTICS table.
+ CharacteristicsLength - The length of MacCharacteristics.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MAC_BLOCK NewMacP;
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)(NdisWrapperHandle);
+ UINT MemNeeded;
+
+ //
+ // check that this is an NDIS 3.0 MAC.
+ //
+ IF_TRACE(TRACE_IMPT) NdisPrint1("==>NdisRegisterMac\n");
+
+ //
+ // Do any initial initialization that may be necessary. Note: this
+ // routine will notice if this is the second or later call to it.
+ //
+ *Status = NdisInitialInit( NdisMacInfo->NdisWrapperDriver );
+ if (!NT_SUCCESS(*Status)) {
+ return;
+ }
+
+ *NdisMacHandle = (NDIS_HANDLE)NULL;
+
+ if (NdisMacInfo == NULL) {
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ return;
+
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(MacCharacteristics->OpenAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null OpenAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->CloseAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null CloseAdapterHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->SendHandler)) {
+ NdisPrint1("RegisterMac: Null SendHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->TransferDataHandler)) {
+ NdisPrint1("RegisterMac: Null TransferDataHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->ResetHandler)) {
+ NdisPrint1("RegisterMac: Null ResetHandler \n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(MacCharacteristics->RequestHandler)) {
+ NdisPrint1("RegisterMac: Null RequestHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->QueryGlobalStatisticsHandler)) {
+ NdisPrint1("RegisterMac: Null QueryGlobalStatisticsHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->UnloadMacHandler)) {
+ NdisPrint1("RegisterMac: Null UnloadMacHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->AddAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null AddAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacCharacteristics->RemoveAdapterHandler)) {
+ NdisPrint1("RegisterMac: Null RemoveAdapterHandler \n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (MacCharacteristics->MajorNdisVersion != 3 ||
+ MacCharacteristics->MinorNdisVersion != 0) {
+ *Status = NDIS_STATUS_BAD_VERSION;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+
+ //
+ // Check that CharacteristicsLength is enough.
+ //
+
+ if (CharacteristicsLength < sizeof(NDIS_MAC_CHARACTERISTICS)) {
+ NdisPrint3("char len = %d < %d\n",CharacteristicsLength,
+ sizeof(NDIS_MAC_CHARACTERISTICS));
+
+ *Status = NDIS_STATUS_BAD_CHARACTERISTICS;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+
+ //
+ // Allocate memory for the NDIS MAC block.
+ //
+ MemNeeded = sizeof(NDIS_MAC_BLOCK) + MacCharacteristics->Name.Length;
+ NewMacP = (PNDIS_MAC_BLOCK)ExAllocatePoolWithTag(NonPagedPool, MemNeeded, 'bmDN');
+ if (NewMacP == (PNDIS_MAC_BLOCK)NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+ return;
+ }
+ RtlZeroMemory(NewMacP, sizeof(NDIS_MAC_BLOCK));
+
+ NewMacP->Length = MemNeeded;
+
+ //
+ // Copy over the characteristics table.
+ //
+
+ RtlCopyMemory((PVOID)&NewMacP->MacCharacteristics,
+ (PVOID)MacCharacteristics, sizeof(NDIS_MAC_CHARACTERISTICS));
+
+ //
+ // Move buffer pointer to correct location (extra space at the end of
+ // the characteristics table)
+ //
+
+ (NewMacP->MacCharacteristics).Name.Buffer =
+ (PWSTR)((PUCHAR)NewMacP + sizeof(NDIS_MAC_BLOCK));
+
+
+ //
+ // Copy String over.
+ //
+
+ RtlCopyMemory(
+ (NewMacP->MacCharacteristics).Name.Buffer,
+ (MacCharacteristics->Name).Buffer,
+ (MacCharacteristics->Name).Length
+ );
+
+ //
+ // No adapters yet registered for this MAC.
+ //
+
+ NewMacP->AdapterQueue = (PNDIS_ADAPTER_BLOCK)NULL;
+
+ NewMacP->MacMacContext = MacMacContext;
+
+ //
+ // Set up unload handler
+ //
+
+ NdisMacInfo->NdisWrapperDriver->DriverUnload = NdisUnload;
+
+ //
+ // Set up shutdown handler
+ //
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_SHUTDOWN] = NdisShutdown;
+
+ //
+ // Set up the handlers for this driver (they all do nothing).
+ //
+
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CREATE] = NdisCreateIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisDeviceControlIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLEANUP] = NdisSuccessIrpHandler;
+ NdisMacInfo->NdisWrapperDriver->MajorFunction[IRP_MJ_CLOSE] = NdisCloseIrpHandler;
+
+ NewMacP->NdisMacInfo = NdisMacInfo;
+
+ //
+ // Put MAC on global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ NewMacP->NextMac = NdisMacList;
+ NdisMacList = NewMacP;
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ //
+ // Use this event to tell us when all adapters are removed from the mac
+ // during an unload
+ //
+
+ KeInitializeEvent(
+ &NewMacP->AdaptersRemovedEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NewMacP->Unloading = FALSE;
+
+ NdisInitializeRef(&NewMacP->Ref);
+
+ *NdisMacHandle = (NDIS_HANDLE)NewMacP;
+
+ NdisInitReferencePackage();
+
+ if (NdisMacInfo->NdisWrapperConfigurationHandle) {
+
+ if (NdisCallDriverAddAdapter(NewMacP) == NDIS_STATUS_SUCCESS) {
+ *Status = NDIS_STATUS_SUCCESS;
+ } else {
+ *Status = NDIS_STATUS_FAILURE;
+ NdisDereferenceMac(NewMacP);
+ }
+ } else {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+
+ NdisInitDereferencePackage();
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterMac\n");
+}
+
+
+VOID
+NdisDeregisterMac(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisMacHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS MAC.
+
+Arguments:
+
+ Status - Returns the status of the request.
+ NdisMacHandle - The handle returned by NdisRegisterMac.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_MAC_BLOCK OldMacP = (PNDIS_MAC_BLOCK)NdisMacHandle;
+
+ //
+ // If the MAC is already closing, return.
+ //
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ if (OldMacP == NULL) {
+
+ return;
+ }
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterMac\n");
+ NdisPrint2(" Mac %wZ being deregistered\n",&OldMacP->MacCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisMacHandle)) {
+ NdisPrint1("DeregisterMac: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisMacHandle)) {
+ NdisPrint1("DeregisterMac: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldMacP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n");
+ return;
+ }
+
+
+ ASSERT(OldMacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterMac\n");
+}
+
+IO_ALLOCATION_ACTION
+NdisAllocationExecutionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the execution routine for AllocateAdapterChannel,
+ if is called when the map registers have been assigned.
+
+Arguments:
+
+ DeviceObject - The device object of the adapter.
+
+ Irp - ??.
+
+ MapRegisterBase - The address of the first translation table
+ assigned to us.
+
+ Context - A pointer to the Adapter in question.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK AdaptP = (PNDIS_ADAPTER_BLOCK)Context;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)Context;
+
+ Irp; DeviceObject;
+
+ //
+ // Save this translation entry in the correct spot.
+ //
+
+ if (AdaptP->DeviceObject == NULL) {
+
+ Miniport->MapRegisters[Miniport->CurrentMapRegister].MapRegister = MapRegisterBase;
+
+ } else {
+
+ AdaptP->MapRegisters[AdaptP->CurrentMapRegister].MapRegister = MapRegisterBase;
+
+ }
+
+ //
+ // This will free the thread that is waiting for this callback.
+ //
+
+ KeSetEvent(
+ ((AdaptP->DeviceObject == NULL) ?
+ &Miniport->AllocationEvent :
+ &AdaptP->AllocationEvent),
+ 0L,
+ FALSE
+ );
+
+ return DeallocateObjectKeepRegisters;
+}
+
+
+
+NDIS_STATUS
+NdisRegisterAdapter(
+ OUT PNDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE MacAdapterContext,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN PNDIS_STRING AdapterName,
+ IN PVOID AdapterInformation
+ )
+
+/*++
+
+Routine Description:
+
+ Register an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - Returns a handle referring to this adapter.
+ NdisMacHandle - A handle for a previously registered MAC.
+ MacAdapterContext - A context for calls into this MAC.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ AdapterName - The name the adapter should be registered under.
+ AdapterInformation - Contains adapter information. For future
+ use. NULL for the meantime. Storage for it
+ must be allocated by the caller.
+
+Return Value:
+
+ The final status.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK NewAdaptP;
+ PDEVICE_OBJECT TmpDeviceP;
+ PNDIS_MAC_BLOCK TmpMacP;
+ NTSTATUS NtStatus;
+ NDIS_STRING NdisAdapterName;
+ PHYSICAL_ADDRESS PortAddress;
+ PHYSICAL_ADDRESS InitialPortAddress;
+ ULONG addressSpace;
+ PNDIS_ADAPTER_INFORMATION AdapterInfo = (PNDIS_ADAPTER_INFORMATION)AdapterInformation;
+ BOOLEAN Conflict;
+ PCM_RESOURCE_LIST Resources;
+ LARGE_INTEGER TimeoutValue;
+ BOOLEAN AllocateIndividualPorts = TRUE;
+ ULONG i;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_STATUS Status;
+ KIRQL OldIrql;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisRegisterAdapter\n");
+ }
+
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisMacHandle)) {
+ NdisPrint1("RegisterAdapter: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisMacHandle)) {
+ NdisPrint1("RegisterAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacAdapterContext)) {
+ NdisPrint1("RegisterAdapter: Null Context\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacAdapterContext)) {
+ NdisPrint1("RegisterAdapter: Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ //
+ // Increment the MAC's refernce count.
+ //
+
+ if (!NdisReferenceMac((PNDIS_MAC_BLOCK)NdisMacHandle)) {
+
+ //
+ // The MAC is closing.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_CLOSING;
+ }
+
+ //
+ // Allocate the string structure and space for the string. This
+ // must be allocated from nonpaged pool, because it is touched by
+ // NdisWriteErrorLogEntry, which may be called from DPC level.
+ //
+
+ NdisAdapterName.Buffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ AdapterName->MaximumLength,
+ 'naDN'
+ );
+ if (NdisAdapterName.Buffer == NULL) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NdisAdapterName.MaximumLength = AdapterName->MaximumLength;
+ NdisAdapterName.Length = AdapterName->Length;
+
+ RtlCopyMemory(NdisAdapterName.Buffer,
+ AdapterName->Buffer,
+ AdapterName->MaximumLength
+ );
+
+ //
+ // Create a device object for this adapter.
+ //
+
+ NtStatus = IoCreateDevice(
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ sizeof(NDIS_ADAPTER_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size
+ AdapterName,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &TmpDeviceP
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ ExFreePool( NdisAdapterName.Buffer );
+ return NDIS_STATUS_DEVICE_FAILED;
+ }
+
+
+ //
+ // Initialize the NDIS adapter block in the device object extension
+ //
+ // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
+ // NDIS_ADAPTER_BLOCK, so we put it first in the extension.
+ //
+
+ ASSERT( (sizeof(NDIS_WRAPPER_CONTEXT) & 3) <= (sizeof(NDIS_ADAPTER_BLOCK) & 3) );
+
+ NewAdaptP = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1);
+ RtlZeroMemory(NewAdaptP, sizeof(NDIS_ADAPTER_BLOCK));
+
+ NewAdaptP->DeviceObject = TmpDeviceP;
+ NewAdaptP->MacHandle = TmpMacP = (PNDIS_MAC_BLOCK)NdisMacHandle;
+ NewAdaptP->MacAdapterContext = MacAdapterContext;
+ NewAdaptP->AdapterName = NdisAdapterName;
+ // NewAdaptP->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
+
+ NewAdaptP->WrapperContext = TmpDeviceP->DeviceExtension;
+
+ //
+ // Get the BusNumber and BusType from the context
+ //
+
+ if (((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultType ==
+ (NDIS_INTERFACE_TYPE)-1) {
+
+ BusType = (NDIS_INTERFACE_TYPE)-1;
+
+ } else {
+
+ BusType = AdapterInfo->AdapterType;
+
+ }
+
+ BusNumber = ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength;
+
+ //
+ // Check that if there is no bus number or no bus type that the driver is not
+ // going to try to acquire any hardware resources
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) || (BusNumber == (ULONG)-1)) {
+
+ if ((AdapterInfo != NULL) &&
+ ((AdapterInfo->NumberOfPortDescriptors != 0) ||
+ (AdapterInfo->Master))) {
+
+ //
+ // Error out
+ //
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return NDIS_STATUS_BAD_CHARACTERISTICS;
+
+ }
+
+ }
+
+ //
+ // Copy over any PCI assigned resources
+ //
+ if ((BusType == NdisInterfacePci) &&
+ (BusNumber != -1) &&
+ (AdapterInfo != NULL) &&
+ (TmpMacP->PciAssignedResources != NULL)) {
+
+ //
+ // Reassign old resources to this device
+ //
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Allocate a new buffer
+ //
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (AdapterInfo->NumberOfPortDescriptors +
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count +
+ (((AdapterInfo->Master == TRUE) &&
+ (AdapterInfo->AdapterType == NdisInterfaceIsa))
+ ?1
+ :0)),
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ ExFreePool( TmpMacP->PciAssignedResources );
+ NdisDereferenceMac(TmpMacP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Copy over old resource list
+ //
+ NdisMoveMemory(Resources,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ TmpMacP->PciAssignedResources->List[0].PartialResourceList.Count
+ );
+
+ TmpMacP->PciAssignedResources->Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ TmpMacP->PciAssignedResources,
+ sizeof(CM_RESOURCE_LIST),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool( TmpMacP->PciAssignedResources);
+
+ TmpMacP->PciAssignedResources = NULL;
+
+ } else {
+
+ //
+ // Allocate a new buffer for non-pci devices
+ //
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ (AdapterInfo->NumberOfPortDescriptors +
+ (((AdapterInfo->Master == TRUE) &&
+ (AdapterInfo->AdapterType == NdisInterfaceIsa))
+ ?1
+ :0)),
+ 'lrDN'
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Fix up counts for non-pci devices
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ }
+
+ //
+ // Setup resources for the ports
+ //
+
+ if ((BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ if (AdapterInfo != NULL) {
+
+ ULONG HighestPort;
+ ULONG LowestPort;
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = AdapterInfo->AdapterType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+
+ NewAdaptP->Resources = Resources;
+ NewAdaptP->BusNumber = BusNumber;
+ NewAdaptP->BusType = BusType;
+ NewAdaptP->AdapterType = AdapterInfo->AdapterType;
+ NewAdaptP->Master = AdapterInfo->Master;
+
+ //
+ // NewAdaptP->InitialPort and NumberOfPorts refer to the
+ // union of all port mappings specified; the area must
+ // cover all possible ports. We scan the list, keeping track
+ // of the highest and lowest ports used.
+ //
+
+ if (AdapterInfo->NumberOfPortDescriptors > 0) {
+
+
+ //
+ // Setup port
+ //
+ LowestPort = AdapterInfo->PortDescriptors[0].InitialPort;
+ HighestPort = LowestPort + AdapterInfo->PortDescriptors[0].NumberOfPorts;
+
+ if (AdapterInfo->PortDescriptors[0].PortOffset == NULL) {
+
+ AllocateIndividualPorts = FALSE;
+
+ }
+
+ for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) {
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Type =
+ CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].Flags =
+ (AdapterInfo->AdapterType == NdisInterfaceInternal)?
+ CM_RESOURCE_PORT_MEMORY : CM_RESOURCE_PORT_IO;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start.QuadPart =
+ (ULONG)AdapterInfo->PortDescriptors[i].InitialPort;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(AdapterInfo->PortDescriptors[i].InitialPort));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count + i].u.Port.Length =
+ AdapterInfo->PortDescriptors[i].NumberOfPorts;
+
+ if (AdapterInfo->PortDescriptors[i].PortOffset == NULL) {
+
+ AllocateIndividualPorts = FALSE;
+
+ }
+
+ if (AdapterInfo->PortDescriptors[i].InitialPort < LowestPort) {
+ LowestPort = AdapterInfo->PortDescriptors[i].InitialPort;
+ }
+ if ((AdapterInfo->PortDescriptors[i].InitialPort +
+ AdapterInfo->PortDescriptors[i].NumberOfPorts) > HighestPort) {
+ HighestPort = AdapterInfo->PortDescriptors[i].InitialPort +
+ AdapterInfo->PortDescriptors[i].NumberOfPorts;
+ }
+ }
+
+ NewAdaptP->InitialPort = LowestPort;
+ NewAdaptP->NumberOfPorts = HighestPort - LowestPort;
+
+ } else {
+
+ NewAdaptP->NumberOfPorts = 0;
+
+ }
+
+ Resources->List[0].PartialResourceList.Count += AdapterInfo->NumberOfPortDescriptors;
+
+ } else {
+
+ //
+ // Error out
+ //
+
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ }
+
+ NewAdaptP->BeingRemoved = FALSE;
+
+ if ((BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ //
+ // Submit Resources
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ baseFileName = NewAdaptP->AdapterName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]);
+ }
+
+ }
+
+ StringSize = NewAdaptP->AdapterName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ TmpDeviceP,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+ return(NDIS_STATUS_RESOURCE_CONFLICT);
+
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // If port mapping is needed, we do that. If the result
+ // is in memory, we have to map it. We map only the
+ // ports specified in AdapterInformation; the default
+ // is to map the first 4K.
+ //
+ // Note that NumberOfPorts can only be 0 if AdapterInfo
+ // is provided and explicitly sets it to 0, so in that
+ // case it is OK to leave the adapter in a state where
+ // a call to NdisXXXPort will probably crash (because
+ // PortOffset will be undefined).
+ //
+
+ if (NewAdaptP->NumberOfPorts > 0) {
+
+ if (AllocateIndividualPorts) {
+
+ //
+ // We get here if we are supposed to allocate ports on an
+ // individual bases -- which implies that the driver will
+ // be using the Raw functions.
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ for (i = 0; i < AdapterInfo->NumberOfPortDescriptors; i++) {
+
+ addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+
+ InitialPortAddress.LowPart = AdapterInfo->PortDescriptors[i].InitialPort;
+ InitialPortAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ NewAdaptP->BusType, // InterfaceType
+ NewAdaptP->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *(AdapterInfo->PortDescriptors[i].PortOffset) = MmMapIoSpace(
+ PortAddress,
+ AdapterInfo->PortDescriptors[i].NumberOfPorts,
+ FALSE
+ );
+
+ if (*(AdapterInfo->PortDescriptors[i].PortOffset) == NULL) {
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *(AdapterInfo->PortDescriptors[i].PortOffset) = (PUCHAR)PortAddress.LowPart;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // The driver will not use the Raw functions, only the
+ // old NdisRead and NdisWrite port functions.
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ addressSpace = (NewAdaptP->AdapterType == NdisInterfaceInternal) ? 0 : 1;
+ InitialPortAddress.LowPart = NewAdaptP->InitialPort;
+ InitialPortAddress.HighPart = 0;
+ if ( !HalTranslateBusAddress(
+ NewAdaptP->BusType, // InterfaceType
+ NewAdaptP->BusNumber, // BusNumber
+ InitialPortAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &PortAddress // Translated address
+ ) ) {
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ NewAdaptP->InitialPortMapping = MmMapIoSpace(
+ PortAddress,
+ NewAdaptP->NumberOfPorts,
+ FALSE
+ );
+
+ if (NewAdaptP->InitialPortMapping == NULL) {
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NewAdaptP->InitialPortMapped = TRUE;
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ NewAdaptP->InitialPortMapping = (PUCHAR)PortAddress.LowPart;
+ NewAdaptP->InitialPortMapped = FALSE;
+
+ }
+
+ //
+ // PortOffset holds the mapped address of port 0.
+ //
+
+ NewAdaptP->PortOffset = NewAdaptP->InitialPortMapping - NewAdaptP->InitialPort;
+
+ }
+
+ } else {
+
+ //
+ // Technically should not allow this, but do it until
+ // all drivers register their info correctly.
+ //
+
+ NewAdaptP->PortOffset = 0;
+
+ }
+
+ }
+
+ //
+ // If the driver want to be called back now, use
+ // supplied callback routine.
+ //
+
+ if ((AdapterInfo != NULL) && (AdapterInfo->ActivateCallback != NULL)) {
+
+ Status = (*(AdapterInfo->ActivateCallback))((NDIS_HANDLE)NewAdaptP,
+ MacAdapterContext,
+ AdapterInfo->DmaChannel
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Exit
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return Status;
+
+ }
+
+ }
+
+ //
+ // Set information from AdapterInformation. The call back
+ // routine can set these values.
+ //
+
+ NewAdaptP->ChannelNumber = AdapterInfo->DmaChannel;
+ NewAdaptP->PhysicalMapRegistersNeeded =
+ AdapterInfo->PhysicalMapRegistersNeeded;
+ NewAdaptP->MaximumPhysicalMapping =
+ AdapterInfo->MaximumPhysicalMapping;
+
+
+ //
+ // Check for resource conflic on DmaChannel.
+ //
+
+ if ((NewAdaptP->Master) &&
+ (BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ if (NewAdaptP->AdapterType == NdisInterfaceIsa) {
+
+ //
+ // Put the DMA channel in the resource list.
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Type =
+ CmResourceTypeDma;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].ShareDisposition =
+ CmResourceShareDeviceExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].Flags =
+ 0;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Channel =
+ NewAdaptP->ChannelNumber;
+ Resources->List[0].PartialResourceList.PartialDescriptors[Resources->List[0].PartialResourceList.Count].u.Dma.Port =
+ 0;
+ Resources->List[0].PartialResourceList.Count++;
+
+ }
+
+ //
+ // Submit Resources
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ NewAdaptP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
+ Resources->List[0].PartialResourceList.Count,
+ TRUE,
+ &Conflict
+ );
+
+ //
+ // Check for conflict.
+ //
+
+ if (Conflict || (NtStatus != STATUS_SUCCESS)) {
+
+ if (Conflict) {
+
+ //
+ // Log an error
+ //
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ baseFileName = NewAdaptP->AdapterName.Buffer;
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0; i < NewAdaptP->AdapterName.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( NewAdaptP->AdapterName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = &(NewAdaptP->AdapterName.Buffer[++i]);
+ }
+
+ }
+
+ StringSize = NewAdaptP->AdapterName.MaximumLength -
+ (((ULONG)baseFileName) - ((ULONG)NewAdaptP->AdapterName.Buffer)) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ TmpDeviceP,
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ if ((NewAdaptP->Master) &&
+ (NewAdaptP->AdapterType == Isa)){
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_PORT_OR_DMA_CONFLICT;
+
+ } else {
+
+ errorLogEntry->ErrorCode = EVENT_NDIS_IO_PORT_CONFLICT;
+
+ }
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ sizeof(IO_ERROR_LOG_PACKET),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+ return(NDIS_STATUS_RESOURCE_CONFLICT);
+
+ }
+
+ //
+ // Free memory
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+
+
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ }
+
+ //
+ // If the device is a busmaster, we get an adapter
+ // object for it.
+ // If map registers are needed, we loop, allocating an
+ // adapter channel for each map register needed.
+ //
+
+ if ((NewAdaptP->Master) &&
+ (BusType != (NDIS_INTERFACE_TYPE)-1) &&
+ (BusNumber != (ULONG)-1)) {
+
+ //
+ // This is needed by HalGetAdapter.
+ //
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ ULONG MapRegistersAllowed;
+
+ //
+ // Returned by HalGetAdapter.
+ //
+ PADAPTER_OBJECT AdapterObject;
+
+ //
+ // Map registers needed per channel.
+ //
+ ULONG MapRegistersPerChannel;
+
+ NTSTATUS Status;
+
+ //
+ // Allocate storage for holding the appropriate
+ // information for each map register.
+ //
+
+ NewAdaptP->MapRegisters = (PMAP_REGISTER_ENTRY)
+ ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(MAP_REGISTER_ENTRY) *
+ NewAdaptP->PhysicalMapRegistersNeeded,
+ 'rmDN');
+
+ if (NewAdaptP->MapRegisters == (PMAP_REGISTER_ENTRY)NULL) {
+
+ //
+ // Error out
+ //
+
+ ExFreePool(Resources);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // Use this event to tell us when NdisAllocationExecutionRoutine
+ // has been called.
+ //
+
+ KeInitializeEvent(
+ &NewAdaptP->AllocationEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+
+ //
+ // Set up the device description; zero it out in case its
+ // size changes.
+ //
+
+ RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
+
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.Master = TRUE;
+ DeviceDescription.ScatterGather = TRUE;
+
+ DeviceDescription.BusNumber = NewAdaptP->BusNumber;
+ DeviceDescription.DmaChannel = NewAdaptP->ChannelNumber;
+ DeviceDescription.InterfaceType = NewAdaptP->AdapterType;
+
+ if (DeviceDescription.InterfaceType == NdisInterfaceIsa) {
+
+ //
+ // For ISA devices, the width is based on the DMA channel:
+ // 0-3 == 8 bits, 5-7 == 16 bits. Timing is compatibility
+ // mode.
+ //
+
+ if (NewAdaptP->ChannelNumber > 4) {
+ DeviceDescription.DmaWidth = Width16Bits;
+ } else {
+ DeviceDescription.DmaWidth = Width8Bits;
+ }
+ DeviceDescription.DmaSpeed = Compatible;
+
+ } else if ((DeviceDescription.InterfaceType == NdisInterfaceMca) ||
+ (DeviceDescription.InterfaceType == NdisInterfaceEisa) ||
+ (DeviceDescription.InterfaceType == NdisInterfacePci))
+ {
+ DeviceDescription.Dma32BitAddresses = AdapterInfo->Dma32BitAddresses;
+ DeviceDescription.DmaPort = 0;
+
+ }
+
+ DeviceDescription.MaximumLength = NewAdaptP->MaximumPhysicalMapping;
+
+
+ //
+ // Determine how many map registers we need per channel.
+ //
+
+ MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ //
+ // Get the adapter object.
+ //
+
+ AdapterObject = HalGetAdapter (&DeviceDescription, &MapRegistersAllowed);
+
+ if (AdapterObject == NULL) {
+
+ ExFreePool(Resources);
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ ASSERT (MapRegistersAllowed >= MapRegistersPerChannel);
+
+ //
+ // We save this to call IoFreeMapRegisters later.
+ //
+
+ NewAdaptP->SystemAdapterObject = AdapterObject;
+
+
+ //
+ // Now loop, allocating an adapter channel each time, then
+ // freeing everything but the map registers.
+ //
+
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++) {
+
+ NewAdaptP->CurrentMapRegister = i;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ Status = IoAllocateAdapterChannel(
+ AdapterObject,
+ NewAdaptP->DeviceObject,
+ MapRegistersPerChannel,
+ NdisAllocationExecutionRoutine,
+ (PVOID)NewAdaptP
+ );
+
+ KeLowerIrql(OldIrql);
+
+ if (!NT_SUCCESS(Status)) {
+
+#if DBG
+ DbgPrint("NDIS: Failed to load driver because of\n");
+ DbgPrint("NDIS: insufficient map registers.\n");
+ DbgPrint("NDIS: AllocateAdapterChannel: %lx\n", Status);
+#endif
+
+ ExFreePool(Resources);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return(NDIS_STATUS_RESOURCES);
+ }
+
+ TimeoutValue.QuadPart = Int32x32To64(2 * 1000, -10000);
+
+ //
+ // NdisAllocationExecutionRoutine will set this event
+ // when it has gotten FirstTranslationEntry.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &NewAdaptP->AllocationEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ NdisPrint2("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus);
+ ExFreePool(Resources);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (; i != 0; i--) {
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i-1].MapRegister,
+ MapRegistersPerChannel
+ );
+ }
+
+ KeLowerIrql(OldIrql);
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ return(NDIS_STATUS_RESOURCES);
+
+ }
+
+ KeResetEvent(
+ &NewAdaptP->AllocationEvent
+ );
+
+ }
+
+ }
+
+
+
+ NdisInitializeRef(&NewAdaptP->Ref);
+
+
+ if (!NdisQueueAdapterOnMac(NewAdaptP, TmpMacP)) {
+
+ //
+ // The MAC is closing, undo what we have done.
+ //
+
+ ExFreePool(Resources);
+ if (NewAdaptP->Master) {
+ ULONG MapRegistersPerChannel =
+ ((NewAdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+
+ for (i=0; i<NewAdaptP->PhysicalMapRegistersNeeded; i++) {
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IoFreeMapRegisters(
+ NewAdaptP->SystemAdapterObject,
+ NewAdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel
+ );
+
+ KeLowerIrql(OldIrql);
+ }
+
+ ExFreePool(NewAdaptP->MapRegisters);
+ }
+ IoDeleteDevice(TmpDeviceP);
+ ExFreePool( NdisAdapterName.Buffer );
+ NdisDereferenceMac(TmpMacP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_CLOSING;
+ }
+
+ NdisMacReferencePackage();
+
+ //
+ // Add an extra reference because the wrapper is using the MAC
+ //
+ NdisReferenceAdapter(NewAdaptP);
+
+ *NdisAdapterHandle = (NDIS_HANDLE)NewAdaptP;
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisRegisterAdapter\n");
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS
+NdisDeregisterAdapter(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+
+ //
+ // KillAdapter does all the work.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeregisterAdapter\n");
+ NdisPrint2(" Deregistering Adapter %s\n",
+ ((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle)->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(NdisAdapterHandle)) {
+ NdisPrint1("DeregisterAdapter: Null Handle\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisAdapterHandle)) {
+ NdisPrint1("DeregisterAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ NdisKillAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ //
+ // Remove reference from wrapper
+ //
+ NdisDereferenceAdapter((PNDIS_ADAPTER_BLOCK)NdisAdapterHandle);
+
+ NdisMacDereferencePackage();
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeregisterAdapter\n");
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID
+NdisRegisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PVOID ShutdownContext,
+ IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+ ShutdownContext - Context to pass the the handler, when called.
+
+ ShutdownHandler - The Handler for the Adapter, to be called on shutdown.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler == NULL) {
+
+ //
+ // Store information
+ //
+
+ WrapperContext->ShutdownHandler = ShutdownHandler;
+ WrapperContext->ShutdownContext = ShutdownContext;
+
+ //
+ // Register our shutdown handler for either a system shutdown
+ // notification or a bugcheck.
+ //
+
+ IoRegisterShutdownNotification(Adapter->DeviceObject);
+
+#if !defined(BUILD_FOR_3_1)
+ KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
+
+ KeRegisterBugCheckCallback(
+ &WrapperContext->BugcheckCallbackRecord, // callback record.
+ (PVOID) NdisBugcheckHandler, // callback routine.
+ (PVOID) WrapperContext, // free form buffer.
+ sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
+ "Ndis mac" // component id.
+ );
+#endif
+
+ }
+}
+
+
+VOID
+NdisDeregisterAdapterShutdownHandler(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Deregisters an NDIS adapter.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS.
+
+--*/
+
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK) NdisAdapterHandle;
+ PNDIS_WRAPPER_CONTEXT WrapperContext = Adapter->WrapperContext;
+
+ if (WrapperContext->ShutdownHandler != NULL) {
+
+ //
+ // Clear information
+ //
+
+ WrapperContext->ShutdownHandler = NULL;
+
+ IoUnregisterShutdownNotification(Adapter->DeviceObject);
+
+#if !defined(BUILD_FOR_3_1)
+ KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
+#endif
+
+ }
+}
+
+
+VOID
+NdisReleaseAdapterResources(
+ IN NDIS_HANDLE NdisAdapterHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Informs the wrapper that the resources (such as interrupt,
+ I/O ports, etc.) have been shut down in some way such that
+ they will not interfere with other devices in the system.
+
+Arguments:
+
+ NdisAdapterHandle - The handle returned by NdisRegisterAdapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCM_RESOURCE_LIST Resources;
+ BOOLEAN Conflict;
+ NTSTATUS NtStatus;
+ PNDIS_ADAPTER_BLOCK AdptrP = (PNDIS_ADAPTER_BLOCK)(NdisAdapterHandle);
+
+ Resources = AdptrP->Resources;
+
+ //
+ // Clear count
+ //
+
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ //
+ // Make the call
+ //
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ AdptrP->MacHandle->NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ 0,
+ AdptrP->DeviceObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ TRUE,
+ &Conflict
+ );
+
+
+ return;
+
+}
+
+
+VOID
+NdisWriteErrorLogEntry(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN NDIS_ERROR_CODE ErrorCode,
+ IN ULONG NumberOfErrorValues,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ This function allocates an I/O error log record, fills it in and writes it
+ to the I/O error log.
+
+
+Arguments:
+
+ NdisAdapterHandle - points to the adapter block.
+
+ ErrorCode - Ndis code mapped to a string.
+
+ NumberOfErrorValues - number of ULONGS to store for the error.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+
+ va_list ArgumentPointer;
+
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG i;
+ ULONG StringSize;
+ PWCH baseFileName;
+
+ if (AdapterBlock == NULL) {
+
+ return;
+
+ }
+
+ if (AdapterBlock->DeviceObject != NULL) {
+ baseFileName = AdapterBlock->AdapterName.Buffer;
+ } else {
+ baseFileName = Miniport->MiniportName.Buffer;
+ }
+
+ //
+ // Parse out the path name, leaving only the device name.
+ //
+
+ for ( i = 0;
+ i < ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Length :
+ Miniport->MiniportName.Length) / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set baseFileName to
+ // the character after the separator.
+ //
+
+ if ( ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.Buffer[i] :
+ Miniport->MiniportName.Buffer[i]) == OBJ_NAME_PATH_SEPARATOR ) {
+ baseFileName = ((AdapterBlock->DeviceObject != NULL) ?
+ &(AdapterBlock->AdapterName.Buffer[++i]) :
+ &(Miniport->MiniportName.Buffer[++i]));
+ }
+
+ }
+
+ StringSize = ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->AdapterName.MaximumLength :
+ Miniport->MiniportName.MaximumLength) -
+ (((ULONG)baseFileName) -
+ ((AdapterBlock->DeviceObject != NULL) ?
+ ((ULONG)AdapterBlock->AdapterName.Buffer) :
+ ((ULONG)Miniport->MiniportName.Buffer))) ;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ ((AdapterBlock->DeviceObject != NULL) ?
+ AdapterBlock->DeviceObject :
+ Miniport->DeviceObject),
+ (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG) +
+ StringSize)
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->ErrorCode = ErrorCode;
+
+ //
+ // store the time
+ //
+
+ errorLogEntry->MajorFunctionCode = 0;
+ errorLogEntry->RetryCount = 0;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = 0;
+ errorLogEntry->SequenceNumber = 0;
+ errorLogEntry->IoControlCode = 0;
+
+ //
+ // Store Data
+ //
+
+ errorLogEntry->DumpDataSize = (USHORT)(NumberOfErrorValues * sizeof(ULONG));
+
+ va_start(ArgumentPointer, NumberOfErrorValues);
+
+ for (i = 0; i < NumberOfErrorValues; i++) {
+
+ errorLogEntry->DumpData[i] = va_arg(ArgumentPointer, ULONG);
+
+ }
+
+ va_end(ArgumentPointer);
+
+
+ //
+ // Set string information
+ //
+
+ if (StringSize != 0) {
+
+ errorLogEntry->NumberOfStrings = 1;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG);
+
+
+ RtlCopyMemory (
+ ((PUCHAR)errorLogEntry) +
+ (sizeof(IO_ERROR_LOG_PACKET) +
+ NumberOfErrorValues * sizeof(ULONG)),
+ (PVOID)baseFileName,
+ StringSize
+ );
+
+ } else {
+
+ errorLogEntry->NumberOfStrings = 0;
+
+ }
+
+ //
+ // write it out
+ //
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+}
+
+
+VOID
+NdisCompleteOpenAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+{
+ PNDIS_OPEN_BLOCK OpenP = (PNDIS_OPEN_BLOCK)NdisBindingContext;
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCompleteOpenAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteOpenAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteOpenAdapter: Binding Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ if (!NdisFinishOpen(OpenP)) {
+ Status = NDIS_STATUS_CLOSING;
+ }
+ }
+
+ (OpenP->ProtocolHandle->ProtocolCharacteristics.OpenAdapterCompleteHandler) (
+ OpenP->ProtocolBindingContext,
+ Status,
+ OpenErrorStatus
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Something went wrong, clean up and exit.
+ //
+
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == OpenP) {
+
+ GlobalOpenList = OpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != OpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = OpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ObDereferenceObject((PVOID)OpenP->FileObject);
+ NdisDereferenceAdapter(OpenP->AdapterHandle);
+ NdisDereferenceProtocol(OpenP->ProtocolHandle);
+ ExFreePool((PVOID)OpenP);
+
+ }
+
+}
+
+
+VOID
+NdisCompleteCloseAdapter(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ )
+
+{
+ PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK) NdisBindingContext;
+ PNDIS_OPEN_BLOCK TmpOpen;
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisCompleteCloseAdapter\n");
+ }
+ IF_ERROR_CHK {
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteCloseAdapter: Handle not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(NdisBindingContext)) {
+ NdisPrint1("NdisCompleteCloseAdapter: Binding Context not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Status
+ );
+
+ NdisDeQueueOpenOnAdapter(Open, Open->AdapterHandle);
+ NdisDeQueueOpenOnProtocol(Open, Open->ProtocolHandle);
+
+ NdisDereferenceProtocol(Open->ProtocolHandle);
+ NdisDereferenceAdapter(Open->AdapterHandle);
+ NdisFreeSpinLock(&Open->SpinLock);
+
+ //
+ // This sends an IRP_MJ_CLOSE IRP.
+ //
+
+ ObDereferenceObject((PVOID)(Open->FileObject));
+
+ //
+ // Remove from global list
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == Open) {
+
+ GlobalOpenList = Open->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != Open) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = Open->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ExFreePool((PVOID)(NdisBindingContext));
+}
+
+
+
+
+BOOLEAN
+NdisReferenceRef(
+ IN PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds a reference to an object.
+
+Arguments:
+
+ RefP - A pointer to the REFERENCE portion of the object.
+
+Return Value:
+
+ TRUE if the reference was added.
+ FALSE if the object was closing.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisReferenceRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisReferenceRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisReferenceRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+
+ if (RefP->Closing) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n");
+ return FALSE;
+ }
+
+ ++(RefP->ReferenceCount);
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisReferenceRef\n");
+ return TRUE;
+}
+
+BOOLEAN
+NdisDereferenceRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a reference to an object.
+
+Arguments:
+
+ RefP - A pointer to the REFERENCE portion of the object.
+
+Return Value:
+
+ TRUE if the reference count is now 0.
+ FALSE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDereferenceRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisDereferenceRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisDereferenceRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+ --(RefP->ReferenceCount);
+ if (RefP->ReferenceCount == 0) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n");
+ return TRUE;
+ }
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisDereferenceRef\n");
+ return FALSE;
+}
+
+
+VOID
+NdisInitializeRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisInitializeRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisInitializeRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisInitializeRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ RefP->Closing = FALSE;
+ RefP->ReferenceCount = 1;
+ NdisAllocateSpinLock(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisInitializeRef\n");
+}
+
+BOOLEAN
+NdisCloseRef(
+ PREFERENCE RefP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes a reference count structure.
+
+Arguments:
+
+ RefP - The structure to be closed.
+
+Return Value:
+
+ FALSE if it was already closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseRef\n");
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(RefP)) {
+ NdisPrint1("NdisCloseRef: NULL Reference address\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(RefP)) {
+ NdisPrint1("NdisCloseRef: Reference not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&RefP->SpinLock);
+
+ if (RefP->Closing) {
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n");
+ return FALSE;
+ }
+
+ RefP->Closing = TRUE;
+
+ RELEASE_SPIN_LOCK(&RefP->SpinLock);
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseRef\n");
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NdisQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+
+/*++
+
+Routine Description:
+
+ Attaches an open block to the list of opens for a protocol.
+
+Arguments:
+
+ OpenP - The open block to be queued.
+ ProtP - The protocol block to queue it to.
+
+Return Value:
+
+ TRUE if the operation is successful.
+ FALSE if the protocol is closing.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueOpenOnProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(ProtP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Null Protocol Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtP)) {
+ NdisPrint1("NdisQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+ ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+
+ //
+ // Make sure the protocol is not closing.
+ //
+
+ if (ProtP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n");
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->ProtocolNextOpen = ProtP->OpenQueue;
+ ProtP->OpenQueue = OpenP;
+
+
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueOpenOnProtocol\n");
+ return TRUE;
+}
+
+VOID
+NdisDeQueueOpenOnProtocol(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_PROTOCOL_BLOCK ProtP
+ )
+
+/*++
+
+Routine Description:
+
+ Detaches an open block from the list of opens for a protocol.
+
+Arguments:
+
+ OpenP - The open block to be dequeued.
+ ProtP - The protocol block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueOpenOnProtocol\n");
+ NdisPrint2(" Protocol: %wZ\n",&ProtP->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ if (DbgIsNull(ProtP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Null Protocol Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(ProtP)) {
+ NdisPrint1("NdisDeQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+
+ }
+
+ ACQUIRE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (ProtP->OpenQueue == OpenP) {
+ ProtP->OpenQueue = OpenP->ProtocolNextOpen;
+ } else {
+ PNDIS_OPEN_BLOCK PP = ProtP->OpenQueue;
+
+ while (PP->ProtocolNextOpen != OpenP) {
+ PP = PP->ProtocolNextOpen;
+ }
+
+ PP->ProtocolNextOpen = PP->ProtocolNextOpen->ProtocolNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&ProtP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueOpenOnProtocol\n");
+}
+
+VOID
+NdisDeQueueOpenOnMiniport(
+ IN PNDIS_M_OPEN_BLOCK OpenP,
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Detaches an open block from the list of opens for a Miniport.
+
+Arguments:
+
+ OpenP - The open block to be dequeued.
+ Miniport - The Miniport block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock);
+
+ OpenP->References--;
+
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (Miniport->OpenQueue == OpenP) {
+ Miniport->OpenQueue = OpenP->MiniportNextOpen;
+ } else {
+ PNDIS_M_OPEN_BLOCK PP = Miniport->OpenQueue;
+
+ while (PP->MiniportNextOpen != OpenP) {
+ PP = PP->MiniportNextOpen;
+ }
+
+ PP->MiniportNextOpen = PP->MiniportNextOpen->MiniportNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock);
+}
+
+
+
+BOOLEAN
+NdisFinishOpen(
+ IN PNDIS_OPEN_BLOCK OpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Performs the final functions of NdisOpenAdapter. Called when
+ MacOpenAdapter is done.
+
+Arguments:
+
+ OpenP - The open block to finish up.
+
+Return Value:
+
+ FALSE if the adapter or the protocol is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ //
+ // Add us to the adapter's queue of opens.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisFinishOpen\n");
+ NdisPrint3(" Protocol %wZ is being bound to Adapter %wZ\n",
+ &(OpenP->ProtocolHandle)->ProtocolCharacteristics.Name,
+ &OpenP->AdapterHandle->AdapterName);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisFinishOpen: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisFinishOpen: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ if (!NdisQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle)) {
+
+ //
+ // The adapter is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return FALSE;
+ }
+
+
+ //
+ // Add us to the protocol's queue of opens.
+ //
+
+ if (!NdisQueueOpenOnProtocol(OpenP, OpenP->ProtocolHandle)) {
+
+ //
+ // The protocol is closing.
+ //
+ // Call MacCloseAdapter(), don't worry about it completing.
+ //
+
+ (OpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OpenP->MacBindingHandle);
+
+ //
+ // Undo the queueing we just did.
+ //
+
+ NdisDeQueueOpenOnAdapter(OpenP, OpenP->AdapterHandle);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return FALSE;
+ }
+
+
+ //
+ // Both queueings succeeded.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisFinishOpen\n");
+ return TRUE;
+}
+
+NTSTATUS
+NdisCreateIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_CREATE IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PFILE_FULL_EA_INFORMATION IrpEaInfo;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_ADAPTER_BLOCK AdapterBlock;
+ BOOLEAN IsAMiniport;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCreateIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ AdapterBlock = (PNDIS_ADAPTER_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
+ IsAMiniport = (AdapterBlock->DeviceObject == NULL);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ IrpEaInfo = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ if (IrpEaInfo == NULL) {
+
+ //
+ // This is a user-mode open, do whatever.
+ //
+
+ OpenContext = (PNDIS_USER_OPEN_CONTEXT)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_USER_OPEN_CONTEXT), ' DN');
+
+ if (OpenContext == NULL) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ OpenContext->DeviceObject = DeviceObject;
+
+ OpenContext->AdapterBlock = AdapterBlock;
+ OpenContext->OidCount = 0;
+ OpenContext->OidArray = NULL;
+
+ IrpSp->FileObject->FsContext = (PVOID)OpenContext;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_QUERY_STATISTICS;
+
+ if (IsAMiniport) {
+ Status = NdisMQueryOidList((PNDIS_M_USER_OPEN_CONTEXT)OpenContext, Irp);
+ } else {
+ Status = NdisQueryOidList(OpenContext, Irp);
+ }
+
+ if (Status != STATUS_SUCCESS) {
+ ExFreePool (OpenContext);
+ }
+
+ }
+
+ } else {
+
+ //
+ // This is an internal open, verify the EA.
+ //
+
+ if ((IrpEaInfo->EaNameLength != sizeof(NdisInternalEaName)) ||
+ (RtlCompareMemory(IrpEaInfo->EaName, NdisInternalEaName, sizeof(NdisInternalEaName)) !=
+ sizeof(NdisInternalEaName)) ||
+ (IrpEaInfo->EaValueLength != sizeof(NdisInternalEaValue)) ||
+ (RtlCompareMemory(&IrpEaInfo->EaName[IrpEaInfo->EaNameLength+1],
+ NdisInternalEaValue, sizeof(NdisInternalEaValue)) !=
+ sizeof(NdisInternalEaValue))) {
+
+ //
+ // Something is wrong, reject it.
+ //
+
+ Status = STATUS_UNSUCCESSFUL;
+
+ } else {
+
+ //
+ // It checks out, just return success and everything
+ // else is done directly using the device object.
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = (PVOID)NDIS_OPEN_INTERNAL;
+
+ }
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n");
+ return Status;
+}
+
+
+
+NTSTATUS
+NdisQueryOidList(
+ PNDIS_USER_OPEN_CONTEXT OpenContext,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will take care of querying the complete OID
+ list for the MAC and filling in OpenContext->OidArray
+ with the ones that are statistics. It blocks when the
+ MAC pends and so is synchronous.
+
+Arguments:
+
+ OpenContext - The open context.
+ Irp = The IRP that the open was done on (used at completion
+ to distinguish the request).
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ NDIS_QUERY_OPEN_REQUEST OpenRequest;
+ NDIS_STATUS NdisStatus;
+ PNDIS_OID TmpBuffer;
+ ULONG TmpBufferLength;
+ UINT i, j;
+
+ //
+ // First query the OID list with no buffer, to find out
+ // how big it should be.
+ //
+
+ KeInitializeEvent(
+ &OpenRequest.Event,
+ NotificationEvent,
+ FALSE
+ );
+
+ OpenRequest.Irp = Irp;
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = NULL;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ } else if ((NdisStatus != NDIS_STATUS_INVALID_LENGTH) &&
+ (NdisStatus != NDIS_STATUS_BUFFER_TOO_SHORT)) {
+
+ return(NdisStatus);
+
+ }
+
+ //
+ // Now we know how much is needed, allocate temp storage...
+ //
+
+ TmpBufferLength = OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded;
+ TmpBuffer = ExAllocatePoolWithTag(NonPagedPool, TmpBufferLength, ' DN');
+
+ if (TmpBuffer == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // ...and query the real list.
+ //
+
+ KeResetEvent(
+ &OpenRequest.Event
+ );
+
+
+ OpenRequest.Request.RequestType = NdisRequestQueryStatistics;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_SUPPORTED_LIST;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBuffer = TmpBuffer;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.InformationBufferLength = TmpBufferLength;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ OpenRequest.Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &OpenRequest.Request);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &OpenRequest.Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = OpenRequest.NdisStatus;
+
+ }
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+
+ //
+ // Now go through the buffer, counting the statistics OIDs.
+ //
+
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ ++OpenContext->OidCount;
+ }
+ }
+
+ //
+ // Now allocate storage for the real OID array.
+ //
+
+ OpenContext->OidArray = ExAllocatePoolWithTag (NonPagedPool, OpenContext->OidCount * sizeof(NDIS_OID), ' DN');
+
+ if (OpenContext->OidArray == NULL) {
+ ExFreePool (TmpBuffer);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now go through the buffer, copying the statistics OIDs.
+ //
+
+ j = 0;
+ for (i=0; i<TmpBufferLength/sizeof(NDIS_OID); i++) {
+
+ if ((TmpBuffer[i] & 0x00ff0000) == 0x00020000) {
+ OpenContext->OidArray[j] = TmpBuffer[i];
+ ++j;
+ }
+ }
+
+ ASSERT (j == OpenContext->OidCount);
+
+ ExFreePool (TmpBuffer);
+ return STATUS_SUCCESS;
+}
+
+#define NDIS_STATISTICS_HEADER_SIZE FIELD_OFFSET(NDIS_STATISTICS_VALUE,Data[0])
+
+
+
+NTSTATUS
+NdisDeviceControlIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_DEVICE_CONTROL IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ NDIS_STATUS NdisStatus;
+ UINT CurrentOid;
+ ULONG BytesWritten, BytesWrittenThisOid;
+ PUCHAR Buffer;
+ ULONG BufferLength;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisDeviceControlIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 != (PVOID)NDIS_OPEN_QUERY_STATISTICS) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // Allocate a request.
+ //
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ GlobalRequest = (PNDIS_QUERY_GLOBAL_REQUEST)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_GLOBAL_REQUEST), ' DN');
+
+ if (GlobalRequest == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ GlobalRequest->Irp = Irp;
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL) {
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ } else {
+
+ Miniport = NULL;
+
+ }
+
+ //
+ // Fill in the NDIS request.
+ //
+
+ GlobalRequest->Request.RequestType = NdisRequestQueryStatistics;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.Oid =
+ *((PULONG)(Irp->AssociatedIrp.SystemBuffer));
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
+ MmGetSystemAddressForMdl (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
+ MmGetMdlByteCount (Irp->MdlAddress);
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ GlobalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+
+ if (Miniport != NULL) {
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(GlobalRequest->Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(GlobalRequest->Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(GlobalRequest->Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(GlobalRequest->Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+
+ }
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if ( LocalLock ) {
+ if (!Miniport->ProcessingDeferred) {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ } else {
+
+ //
+ // Pass the request to the MAC.
+ //
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &GlobalRequest->Request);
+
+ //
+ // NdisCompleteQueryStatistics handles the completion.
+ //
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+ NdisCompleteQueryStatistics(
+ (NDIS_HANDLE)OpenContext->AdapterBlock,
+ &GlobalRequest->Request,
+ NdisStatus);
+ }
+
+ }
+
+ Status = STATUS_PENDING;
+
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+
+ //
+ // Allocate a request.
+ //
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_QUERY_ALL_REQUEST), ' DN');
+
+ if (AllRequest == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ if (OpenContext->AdapterBlock->DeviceObject == NULL) {
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)(OpenContext->AdapterBlock);
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+
+ } else {
+
+ Miniport = NULL;
+
+ }
+
+ AllRequest->Irp = Irp;
+
+ Buffer = (PUCHAR)MmGetSystemAddressForMdl (Irp->MdlAddress);
+ BufferLength = MmGetMdlByteCount (Irp->MdlAddress);
+ BytesWritten = 0;
+
+ KeInitializeEvent(
+ &AllRequest->Event,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ for (CurrentOid = 0; CurrentOid<OpenContext->OidCount; CurrentOid++) {
+
+ //
+ // We need room for an NDIS_STATISTICS_VALUE (OID,
+ // Length, Data).
+ //
+
+ if (BufferLength < (ULONG)NDIS_STATISTICS_HEADER_SIZE) {
+ NdisStatus = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ AllRequest->Request.RequestType = NdisRequestQueryStatistics;
+
+ AllRequest->Request.DATA.QUERY_INFORMATION.Oid =
+ OpenContext->OidArray[CurrentOid];
+ AllRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer =
+ Buffer + NDIS_STATISTICS_HEADER_SIZE;
+ AllRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
+ BufferLength - NDIS_STATISTICS_HEADER_SIZE;
+
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0;
+
+ if (Miniport != NULL) {
+
+ PNDIS_REQUEST_RESERVED Reserved;
+
+ Reserved = PNDIS_RESERVED_FROM_PNDIS_REQUEST(&(AllRequest->Request));
+ Reserved->Next = NULL;
+ Miniport->LastPendingRequest = &(AllRequest->Request);
+
+ if (Miniport->FirstPendingRequest == NULL) {
+
+ Miniport->FirstPendingRequest = &(AllRequest->Request);
+
+ } else {
+
+ PNDIS_RESERVED_FROM_PNDIS_REQUEST(Miniport->LastPendingRequest)->Next =
+ &(AllRequest->Request);
+
+ }
+
+ if (Miniport->MiniportRequest == NULL) {
+
+ Miniport->RunDoRequests = TRUE;
+ Miniport->ProcessOddDeferredStuff = TRUE;
+
+ }
+
+ //
+ // If we were able to grab the local lock then we can do some
+ // deferred processing now.
+ //
+
+ if ( LocalLock ) {
+ if (!Miniport->ProcessingDeferred) {
+ MiniportProcessDeferred(Miniport);
+ }
+ }
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisStatus =
+ (OpenContext->AdapterBlock->MacHandle->MacCharacteristics.QueryGlobalStatisticsHandler) (
+ OpenContext->AdapterBlock->MacAdapterContext,
+ &AllRequest->Request);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ if (Miniport != NULL) {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &AllRequest->Event,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = AllRequest->NdisStatus;
+
+ if (Miniport != NULL) {
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ ACQUIRE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ LOCK_MINIPORT(Miniport, LocalLock);
+ }
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ PNDIS_STATISTICS_VALUE StatisticsValue =
+ (PNDIS_STATISTICS_VALUE)Buffer;
+
+ //
+ // Create the equivalent of an NDIS_STATISTICS_VALUE
+ // element for this OID value (the data itself was
+ // already written in the right place.
+ //
+
+ StatisticsValue->Oid = OpenContext->OidArray[CurrentOid];
+ StatisticsValue->DataLength = AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
+
+ //
+ // Advance our pointers.
+ //
+
+ BytesWrittenThisOid =
+ AllRequest->Request.DATA.QUERY_INFORMATION.BytesWritten +
+ NDIS_STATISTICS_HEADER_SIZE;
+ Buffer += BytesWrittenThisOid;
+ BufferLength -= BytesWrittenThisOid;
+ BytesWritten += BytesWrittenThisOid;
+
+ } else {
+
+ break;
+
+ }
+
+ KeResetEvent(
+ &AllRequest->Event
+ );
+
+ }
+
+ if (Miniport != NULL) {
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ RELEASE_SPIN_LOCK_DPC(&(Miniport->Lock));
+ KeLowerIrql(OldIrql);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_INVALID_LENGTH) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ } else if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ Irp->IoStatus.Information = BytesWritten;
+ Irp->IoStatus.Status = Status;
+
+ break;
+
+ default:
+
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ }
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCreateIrplHandler\n");
+ return Status;
+}
+
+
+
+VOID
+NdisCompleteQueryStatistics(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by MACs when they have completed
+ processing of a MacQueryGlobalStatistics call.
+
+Arguments:
+
+ NdisAdapterHandle - The NDIS adapter context.
+ NdisRequest - The request that has been completed.
+ Status - The status of the request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_ADAPTER_BLOCK AdapterBlock = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
+ PNDIS_QUERY_ALL_REQUEST AllRequest;
+ PNDIS_QUERY_OPEN_REQUEST OpenRequest;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ //
+ // Rely on the fact that all our request structures start with
+ // the same fields: Irp followed by the NdisRequest.
+ //
+
+ GlobalRequest = CONTAINING_RECORD (NdisRequest, NDIS_QUERY_GLOBAL_REQUEST, Request);
+ Irp = GlobalRequest->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_CREATE:
+
+ //
+ // This request is one of the ones made during an open,
+ // while we are trying to determine the OID list. We
+ // set the event we are waiting for, the open code
+ // takes care of the rest.
+ //
+
+ OpenRequest = (PNDIS_QUERY_OPEN_REQUEST)GlobalRequest;
+
+ OpenRequest->NdisStatus = Status;
+ KeSetEvent(
+ &OpenRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ //
+ // This is a real user request, process it as such.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_NDIS_QUERY_GLOBAL_STATS:
+
+ //
+ // A single query, complete the IRP.
+ //
+
+ Irp->IoStatus.Information =
+ NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else if (Status == NDIS_STATUS_INVALID_LENGTH) {
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; // what else ?
+ }
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ExFreePool (GlobalRequest);
+ break;
+
+ case IOCTL_NDIS_QUERY_ALL_STATS:
+
+ //
+ // An "all" query.
+ //
+
+ AllRequest = (PNDIS_QUERY_ALL_REQUEST)GlobalRequest;
+
+ AllRequest->NdisStatus = Status;
+ KeSetEvent(
+ &AllRequest->Event,
+ 0L,
+ FALSE);
+
+ break;
+
+ }
+
+ break;
+
+ }
+
+}
+
+
+
+NTSTATUS
+NdisCloseIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The handle for IRP_MJ_CLOSE IRPs.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ STATUS_SUCCESS if it should be.
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION IrpSp;
+ PNDIS_USER_OPEN_CONTEXT OpenContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisCloseIrpHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_INTERNAL) {
+
+ //
+ // An internal open, nothing needs to be done.
+ //
+
+ } else {
+
+ //
+ // Free the query context.
+ //
+
+ ASSERT (IrpSp->FileObject->FsContext2 == (PVOID)NDIS_OPEN_QUERY_STATISTICS);
+
+ OpenContext = IrpSp->FileObject->FsContext;
+ ExFreePool (OpenContext->OidArray);
+ ExFreePool (OpenContext);
+
+ }
+
+ Irp->IoStatus.Status = Status;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisCloseIrplHandler\n");
+ return Status;
+}
+
+NTSTATUS
+NdisSuccessIrpHandler(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ The "success handler" for any IRPs that we can ignore.
+
+Arguments:
+
+ DeviceObject - The adapter's device object.
+ Irp - The IRP.
+
+Return Value:
+
+ Always STATUS_SUCCESS.
+
+--*/
+
+{
+
+ DeviceObject; // to avoid "unused formal parameter" warning
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("==>NdisSuccessIrplHandler\n");
+ IF_ERROR_CHK {
+ if (DbgIsNull(Irp)) {
+ NdisPrint1(": Null Irp\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(Irp)) {
+ NdisPrint1(": Irp not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+ IF_TRACE(TRACE_ALL) NdisPrint1("<==NdisSuccessIrplHandler\n");
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NdisKillOpenAndNotifyProtocol(
+ IN PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open and notifies the protocol; used when the
+ close is internally generated by the NDIS wrapper (due to
+ a protocol or adapter deregistering with outstanding opens).
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Indicate the status to the protocol.
+ //
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillOpenAndNotifyProtocol\n");
+ NdisPrint3(" Closing Adapter %wZ and notifying Protocol %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldOpenP)) {
+ NdisPrint1("NdisKillOpenAndNotifyProtocol: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldOpenP)) {
+ NdisPrint1("NdisKillOpenAndNotifyProtocol: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ (OldOpenP->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
+ OldOpenP->ProtocolBindingContext,
+ NDIS_STATUS_CLOSING,
+ NULL,
+ 0); // need real reason here
+
+
+ //
+ // Now KillOpen will do the real work.
+ //
+
+ if (OldOpenP->AdapterHandle->DeviceObject == NULL) {
+ //
+ // Miniport
+ //
+ (void)NdisMKillOpen(OldOpenP);
+ } else {
+ //
+ // Mac
+ //
+ (void)NdisKillOpen(OldOpenP);
+ }
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpenAndNotifyProtocol\n");
+}
+
+
+BOOLEAN
+NdisKillOpen(
+ PNDIS_OPEN_BLOCK OldOpenP
+ )
+
+/*++
+
+Routine Description:
+
+ Closes an open. Used when NdisCloseAdapter is called, and also
+ for internally generated closes.
+
+Arguments:
+
+ OldOpenP - The open to be closed.
+
+Return Value:
+
+ TRUE if the open finished, FALSE if it pended.
+
+--*/
+
+{
+ PNDIS_OPEN_BLOCK TmpOpen;
+ PFILE_OBJECT FileObject = OldOpenP->FileObject;
+
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillOpen\n");
+ NdisPrint3(" Closing Adapter %wZ as requested by %wZ\n",
+ &OldOpenP->AdapterHandle->AdapterName,
+ &(OldOpenP->ProtocolHandle)->ProtocolCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldOpenP)) {
+ NdisPrint1("NdisKillOpen: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldOpenP)) {
+ NdisPrint1("NdisKillOpen: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&OldOpenP->SpinLock);
+
+ //
+ // See if this open is already closing.
+ //
+
+ if (OldOpenP->Closing) {
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return TRUE;
+ }
+
+
+ //
+ // Indicate to others that this open is closing.
+ //
+
+ OldOpenP->Closing = TRUE;
+ RELEASE_SPIN_LOCK(&OldOpenP->SpinLock);
+
+ //
+ // Inform the MAC.
+ //
+
+ if ((OldOpenP->MacHandle->MacCharacteristics.CloseAdapterHandler) (
+ OldOpenP->MacBindingHandle) == NDIS_STATUS_PENDING) {
+
+ //
+ // MacCloseAdapter pended, will complete later.
+ //
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return FALSE;
+ }
+
+ //
+ // Remove the reference for this open.
+ //
+ ObDereferenceObject((PVOID)FileObject);
+
+ //
+ // Remove us from the adapter and protocol open queues.
+ //
+
+ NdisDeQueueOpenOnAdapter(OldOpenP, OldOpenP->AdapterHandle);
+ NdisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
+
+
+ //
+ // MacCloseAdapter did not pend; we ignore the return code.
+ //
+
+ NdisDereferenceProtocol(OldOpenP->ProtocolHandle);
+ NdisDereferenceAdapter(OldOpenP->AdapterHandle);
+
+ NdisFreeSpinLock(&OldOpenP->SpinLock);
+
+ //
+ // Remove from global adpater list
+ //
+ ACQUIRE_SPIN_LOCK(&GlobalOpenListLock);
+
+ if (GlobalOpenList == OldOpenP) {
+
+ GlobalOpenList = OldOpenP->NextGlobalOpen;
+
+ } else {
+
+ TmpOpen = GlobalOpenList;
+
+ while (TmpOpen->NextGlobalOpen != OldOpenP) {
+
+ TmpOpen = TmpOpen->NextGlobalOpen;
+
+ }
+
+ TmpOpen->NextGlobalOpen = OldOpenP->NextGlobalOpen;
+
+ }
+
+ RELEASE_SPIN_LOCK(&GlobalOpenListLock);
+
+ ExFreePool((PVOID)OldOpenP);
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillOpen\n");
+ return TRUE;
+}
+
+
+BOOLEAN
+NdisQueueAdapterOnMac(
+ IN PNDIS_ADAPTER_BLOCK AdaptP,
+ IN PNDIS_MAC_BLOCK MacP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an adapter to a list of adapters for a MAC.
+
+Arguments:
+
+ AdaptP - The adapter block to queue.
+ MacP - The MAC block to queue it to.
+
+Return Value:
+
+ FALSE if the MAC is closing.
+ TRUE otherwise.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueAdapterOnMac\n");
+ NdisPrint2(" Adapter %wZ being added to MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name);
+ }
+
+ IF_ERROR_CHK {
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Null Mac Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacP)) {
+ NdisPrint1("NdisQueueAdapterOnMac: Mac Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ //
+ // Make sure the MAC is not closing.
+ //
+
+ if (MacP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n");
+ return FALSE;
+ }
+
+
+ //
+ // Add this adapter at the head of the queue
+ //
+
+ AdaptP->NextAdapter = MacP->AdapterQueue;
+ MacP->AdapterQueue = AdaptP;
+
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnMac\n");
+ return TRUE;
+}
+
+
+VOID
+NdisDeQueueAdapterOnMac(
+ PNDIS_ADAPTER_BLOCK AdaptP,
+ PNDIS_MAC_BLOCK MacP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an adapter from a list of adapters for a MAC.
+
+Arguments:
+
+ AdaptP - The adapter block to dequeue.
+ MacP - The MAC block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueAdapterOnMac\n");
+ NdisPrint2(" Adapter %wZ being removed from MAC list\n",&AdaptP->MacHandle->MacCharacteristics.Name);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(MacP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Null Mac Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(MacP)) {
+ NdisPrint1("NdisDeQueueAdapterOnMac: Mac Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ ACQUIRE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ //
+ // Find the MAC on the queue, and remove it.
+ //
+
+ if (MacP->AdapterQueue == AdaptP) {
+ MacP->AdapterQueue = AdaptP->NextAdapter;
+ } else {
+ PNDIS_ADAPTER_BLOCK MP = MacP->AdapterQueue;
+
+ while (MP->NextAdapter != AdaptP) {
+ MP = MP->NextAdapter;
+ }
+
+ MP->NextAdapter = MP->NextAdapter->NextAdapter;
+ }
+
+ RELEASE_SPIN_LOCK(&MacP->Ref.SpinLock);
+
+ if (MacP->Unloading && (MacP->AdapterQueue == (PNDIS_ADAPTER_BLOCK)NULL)) {
+
+ KeSetEvent(
+ &MacP->AdaptersRemovedEvent,
+ 0L,
+ FALSE
+ );
+
+ }
+
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnMac\n");
+}
+
+
+
+VOID
+NdisKillAdapter(
+ PNDIS_ADAPTER_BLOCK OldAdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an adapter. Called by NdisDeregisterAdapter and also
+ for internally generated deregistrations.
+
+Arguments:
+
+ OldAdaptP - The adapter to be removed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // If the adapter is already closing, return.
+ //
+
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisKillAdapter\n");
+ NdisPrint2(" Removing Adapter %s\n",OldAdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OldAdaptP)) {
+ NdisPrint1("NdisKillAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OldAdaptP)) {
+ NdisPrint1("NdisKillAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (!NdisCloseRef(&OldAdaptP->Ref)) {
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n");
+ return;
+ }
+
+
+ //
+ // Kill all the opens for this adapter.
+ //
+
+ while (OldAdaptP->OpenQueue != (PNDIS_OPEN_BLOCK)NULL) {
+
+ //
+ // This removes it from the adapter's OpenQueue etc.
+ //
+
+ NdisKillOpenAndNotifyProtocol(OldAdaptP->OpenQueue);
+ }
+
+
+ //
+ // Remove the adapter from the MAC's list.
+ //
+
+ NdisDeQueueAdapterOnMac(OldAdaptP, OldAdaptP->MacHandle);
+
+ NdisDereferenceAdapter(OldAdaptP);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisKillAdapter\n");
+}
+
+
+
+VOID
+NdisDereferenceAdapter(
+ PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Dereferences an adapter. If the reference count goes to zero,
+ it frees resources associated with the adapter.
+
+Arguments:
+
+ AdaptP - The adapter to be dereferenced.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (NdisDereferenceRef(&AdaptP->Ref)) {
+
+ //
+ // Free resource memory
+ //
+
+ if (AdaptP->Resources != NULL) {
+
+ ExFreePool(AdaptP->Resources);
+
+ }
+
+ ExFreePool(AdaptP->AdapterName.Buffer);
+
+ if (AdaptP->Master) {
+ UINT i;
+ ULONG MapRegistersPerChannel =
+ ((AdaptP->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ for (i=0; i<AdaptP->PhysicalMapRegistersNeeded; i++) {
+ IoFreeMapRegisters(
+ AdaptP->SystemAdapterObject,
+ AdaptP->MapRegisters[i].MapRegister,
+ MapRegistersPerChannel);
+ }
+
+ KeLowerIrql(OldIrql);
+ }
+
+ if ((AdaptP->NumberOfPorts > 0) && AdaptP->InitialPortMapped) {
+ MmUnmapIoSpace (AdaptP->InitialPortMapping, AdaptP->NumberOfPorts);
+ }
+
+ NdisDereferenceMac(AdaptP->MacHandle);
+ IoDeleteDevice(AdaptP->DeviceObject);
+
+ }
+}
+
+
+BOOLEAN
+NdisQueueOpenOnAdapter(
+ IN PNDIS_OPEN_BLOCK OpenP,
+ IN PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an open to a list of opens for an adapter.
+
+Arguments:
+
+ OpenP - The open block to queue.
+ AdaptP - The adapter block to queue it to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ // attach ourselves to the adapter object linked list of opens
+ ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+
+ //
+ // Make sure the adapter is not closing.
+ //
+
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisQueueAdapterOnAdapter\n");
+ NdisPrint2(" Open being added to list for Adapter %s\n",AdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+ if (AdaptP->Ref.Closing) {
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n");
+ return FALSE;
+ }
+
+
+ //
+ // Attach this open at the head of the queue.
+ //
+
+ OpenP->AdapterNextOpen = AdaptP->OpenQueue;
+ AdaptP->OpenQueue = OpenP;
+
+
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisQueueAdapterOnAdapter\n");
+ return TRUE;
+}
+
+VOID
+NdisDeQueueOpenOnAdapter(
+ PNDIS_OPEN_BLOCK OpenP,
+ PNDIS_ADAPTER_BLOCK AdaptP
+ )
+
+/*++
+
+Routine Description:
+
+ Removes an open from a list of opens for an adapter.
+
+Arguments:
+
+ OpenP - The open block to dequeue.
+ AdaptP - The adapter block to dequeue it from.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IF_TRACE(TRACE_IMPT) {
+ NdisPrint1("==>NdisDeQueueAdapterOnAdapter\n");
+ NdisPrint2(" Open being removed from list for Adapter %s\n",AdaptP->AdapterName.Buffer);
+ }
+ IF_ERROR_CHK {
+ if (DbgIsNull(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Null Open Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(OpenP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Open Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ if (DbgIsNull(AdaptP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Null Adapter Block\n");
+ DbgBreakPoint();
+ }
+ if (!DbgIsNonPaged(AdaptP)) {
+ NdisPrint1("NdisDeQueueOpenOnAdapter: Adapter Block not in NonPaged Memory\n");
+ DbgBreakPoint();
+ }
+ }
+
+ ACQUIRE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ //
+ // Find the open on the queue, and remove it.
+ //
+
+ if (AdaptP->OpenQueue == OpenP) {
+ AdaptP->OpenQueue = OpenP->AdapterNextOpen;
+ } else {
+ PNDIS_OPEN_BLOCK AP = AdaptP->OpenQueue;
+
+ while (AP->AdapterNextOpen != OpenP) {
+ AP = AP->AdapterNextOpen;
+ }
+
+ AP->AdapterNextOpen = AP->AdapterNextOpen->AdapterNextOpen;
+ }
+
+ RELEASE_SPIN_LOCK(&AdaptP->Ref.SpinLock);
+ IF_TRACE(TRACE_IMPT) NdisPrint1("<==NdisDeQueueAdapterOnAdapter\n");
+}
+
+
+VOID
+NdisDereferenceMac(
+ PNDIS_MAC_BLOCK MacP
+ )
+/*++
+
+Routine Description:
+
+ Removes a reference from the mac, deleting it if the count goes to 0.
+
+Arguments:
+
+ MacP - The Mac block to dereference.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (NdisDereferenceRef(&(MacP)->Ref)) {
+
+ //
+ // Remove it from the global list.
+ //
+
+ ACQUIRE_SPIN_LOCK(&NdisMacListLock);
+
+ if (NdisMacList == MacP) {
+
+ NdisMacList = MacP->NextMac;
+
+ } else {
+
+ PNDIS_MAC_BLOCK TmpMacP = NdisMacList;
+
+ while(TmpMacP->NextMac != MacP) {
+
+ TmpMacP = TmpMacP->NextMac;
+
+ }
+
+ TmpMacP->NextMac = TmpMacP->NextMac->NextMac;
+
+ }
+
+ RELEASE_SPIN_LOCK(&NdisMacListLock);
+
+ if ( MacP->PciAssignedResources != NULL ) {
+ ExFreePool( MacP->PciAssignedResources );
+ }
+
+ ExFreePool((PVOID)(MacP));
+ }
+
+
+}
+
+
+
+//
+// Stubs to compile with Ndis 3.0 kernel.
+//
+
+NDIS_STATUS
+EthAddFilterAddress() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+EthDeleteFilterAddress() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+NDIS_STATUS
+NdisInitializePacketPool() {
+ return(NDIS_STATUS_FAILURE);
+}
+
+
+
+NTSTATUS
+WrapperSaveLinkage(
+ 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 with the values for the "Bind" and "Export" multi-strings
+ for a given driver. It allocates memory to hold the data and copies
+ it over.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" or "Export" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Unused.
+
+ EntryContext - A pointer to the pointer that holds the copied data.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PWSTR * Data = ((PWSTR *)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(Context);
+
+
+ *Data = ExAllocatePoolWithTag (NonPagedPool, ValueLength, ' DN');
+
+ if (*Data == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (*Data, ValueData, ValueLength);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+WrapperCheckRoute(
+ 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 with the value for the "Route" multi-string. It
+ counts the number of "'s in the first string and if it is
+ more than two than it knows that this is a layered driver.
+
+Arguments:
+
+ ValueName - The name of the value ("Route" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - Unused.
+
+ EntryContext - A pointer to a BOOLEAN that is set to TRUE
+ if the driver is layered.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+
+ PWSTR CurRouteLoc = (PWSTR)ValueData;
+ UINT QuoteCount = 0;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+ UNREFERENCED_PARAMETER(Context);
+
+ while (*CurRouteLoc != 0) {
+
+ if (*CurRouteLoc == (WCHAR)L'"') {
+ ++QuoteCount;
+ }
+ ++CurRouteLoc;
+ }
+
+ if (QuoteCount > 2) {
+ *(PBOOLEAN)EntryContext = TRUE;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+NDIS_STATUS
+NdisCallDriverAddAdapter(
+ IN PNDIS_MAC_BLOCK NewMacP
+ )
+
+/*++
+
+Routine Description:
+
+ Reads the driver registry bindings and calls add adapter for each
+ one.
+
+Arguments:
+
+ NewMacP - Pointer to the Mac block allocated for this Mac.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Pointer to a Miniport
+ //
+ PNDIS_M_DRIVER_BLOCK WDriver = (PNDIS_M_DRIVER_BLOCK)NewMacP;
+
+ //
+ // Number of adapters added successfully
+ //
+ UINT AdaptersAdded = 0;
+
+ //
+ // Status of calls to MacAddAdapter
+ //
+ NDIS_STATUS AddAdapterStatus;
+
+ //
+ // Status of calls to MiniportInitialize
+ //
+ NDIS_STATUS MiniportInitializeStatus;
+ NDIS_STATUS OpenErrorStatus;
+
+ UINT SelectedMediumIndex;
+
+ NDIS_MEDIUM MediumArray[] = {NdisMedium802_3,
+ NdisMedium802_5,
+ NdisMediumFddi,
+ NdisMediumArcnet878_2,
+ NdisMediumWan };
+
+ UINT MediumArraySize = 5;
+
+ //
+ // Status of registry requests.
+ //
+ NTSTATUS RegistryStatus;
+ NTSTATUS NtStatus;
+
+ //
+ // subkey containing the card parameters
+ //
+ PWSTR Linkage = L"Linkage";
+
+ //
+ // subkeys below "Linkage"
+ //
+
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ PWSTR Route = L"Route";
+
+ //
+ // These hold the REG_MULTI_SZ read from "Bind" and "Export".
+ //
+
+ PWSTR BindData;
+ PWSTR ExportData;
+
+ //
+ // These hold our place in the REG_MULTI_SZ read for
+ // "Bind" and "Export".
+ //
+
+ PWSTR CurBindValue;
+ PWSTR CurExportValue;
+
+ //
+ // Will be set to TRUE if the driver is layered (that is,
+ // it binds to another NDIS driver, not to an adapter).
+ //
+
+ BOOLEAN LayeredDriver;
+
+ //
+ // subkey below the driver's service key.
+ //
+
+ PWSTR Parameters = L"Parameters";
+
+ //
+ // The path to our configuration data.
+ //
+ PUNICODE_STRING ConfigurationString;
+
+ //
+ // Holds a null-terminated copy of ConfigurationString
+ //
+ PWSTR ConfigurationPath;
+
+ ULONG i;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+
+ //
+ // Holds the key below services where Parameters are stored.
+ //
+ PWCH BaseFileName;
+
+ //
+ // Used to instruct RtlQueryRegistryValues to read the
+ // Linkage\Bind and Linkage\Export keys
+ //
+ RTL_QUERY_REGISTRY_TABLE LinkageQueryTable[5];
+
+ //
+ // Used to instruct RtlQueryRegistryValues to read the
+ // [Driver]\Parameters keys. This is passed as the
+ // ConfigContext to the MacAddAdapter routine.
+ //
+
+ NDIS_WRAPPER_CONFIGURATION_HANDLE ConfigurationHandle;
+
+ NDIS_WRAPPER_CONFIGURATION_HANDLE WrapperConfigurationHandle;
+
+ //
+ // Used for calls to other Ndis routines
+ //
+ NDIS_STATUS NdisStatus;
+
+ BOOLEAN IsAMiniport;
+
+#define BLOCK_LOCK_MINIPORT(_M, _L) \
+ { \
+ ACQUIRE_SPIN_LOCK(&_M->Lock); \
+ LOCK_MINIPORT(_M, _L); \
+ while (!_L) { \
+ UNLOCK_MINIPORT(_M, _L); \
+ RELEASE_SPIN_LOCK(&_M->Lock); \
+ ACQUIRE_SPIN_LOCK(&_M->Lock); \
+ LOCK_MINIPORT(_M, _L); \
+ } \
+ RELEASE_SPIN_LOCK(&_M->Lock); \
+ }
+
+ IsAMiniport = (WDriver->MiniportIdField == (NDIS_HANDLE)0x01);
+
+ //
+ // Set up LinkageQueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below this driver's key
+ //
+
+ LinkageQueryTable[0].QueryRoutine = NULL;
+ LinkageQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ LinkageQueryTable[0].Name = Linkage;
+
+ //
+ // 2) Call WrapperSaveLinkage for "Bind" (as a single multi-string),
+ // which will allocate storage and save the data in BindData.
+ //
+
+ LinkageQueryTable[1].QueryRoutine = WrapperSaveLinkage;
+ LinkageQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[1].Name = Bind;
+ LinkageQueryTable[1].EntryContext = (PVOID)&BindData;
+ LinkageQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call WrapperSaveLinkage for "Export" (as a single multi-string)
+ // which will allocate storage and save the data in ExportData.
+ //
+
+ LinkageQueryTable[2].QueryRoutine = WrapperSaveLinkage;
+ LinkageQueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[2].Name = Export;
+ LinkageQueryTable[2].EntryContext = (PVOID)&ExportData;
+ LinkageQueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4) Call WrapperCheckRoute for "Route" (as a single multi-string)
+ // which will set LayeredDriver to TRUE for a layered driver (this
+ // is optional, the default is FALSE).
+ //
+
+ LinkageQueryTable[3].QueryRoutine = WrapperCheckRoute;
+ LinkageQueryTable[3].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
+ LinkageQueryTable[3].Name = Route;
+ LinkageQueryTable[3].EntryContext = (PVOID)&LayeredDriver;
+ LinkageQueryTable[3].DefaultType = REG_NONE;
+
+ LayeredDriver = FALSE;
+
+ //
+ // 5) Stop
+ //
+
+ LinkageQueryTable[4].QueryRoutine = NULL;
+ LinkageQueryTable[4].Flags = 0;
+ LinkageQueryTable[4].Name = NULL;
+
+
+ //
+ // Allocate room for a null-terminated version of the config path
+ //
+
+ if (IsAMiniport) {
+
+ ConfigurationString = (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle);
+
+ } else {
+
+ ConfigurationString = (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle);
+
+ }
+
+ ConfigurationPath = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ ConfigurationString->Length + sizeof(WCHAR),
+ ' DN');
+ if (ConfigurationPath == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (ConfigurationPath, ConfigurationString->Buffer, ConfigurationString->Length);
+ *(PWCHAR)(((PUCHAR)ConfigurationPath)+ConfigurationString->Length) = (WCHAR)L'\0';
+
+ BindData = NULL;
+ ExportData = NULL;
+
+ RegistryStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ ConfigurationPath,
+ LinkageQueryTable,
+ (PVOID)NULL, // no context needed
+ NULL);
+
+ if (!NT_SUCCESS(RegistryStatus)) {
+
+ //
+ // Free memory if needed, exit.
+ //
+
+ ExFreePool (ConfigurationPath);
+
+ if (BindData != NULL) {
+ ExFreePool (BindData);
+ }
+ if (ExportData != NULL) {
+ ExFreePool (ExportData);
+ }
+
+#if DBG
+ if (IsAMiniport) {
+
+ DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n",
+ (PUNICODE_STRING)(WDriver->NdisDriverInfo->NdisWrapperConfigurationHandle),
+ RegistryStatus);
+
+ } else {
+
+ DbgPrint("NDIS: Could not read Bind/Export for %Z: %lx\n",
+ (PUNICODE_STRING)(NewMacP->NdisMacInfo->NdisWrapperConfigurationHandle),
+ RegistryStatus);
+
+ }
+#endif
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // NdisReadConfiguration assumes that ParametersQueryTable[3].Name is
+ // a key below the services key where the Parameters should be read,
+ // for layered drivers we store the last piece of Configuration
+ // Path there, leading to the desired effect.
+ //
+ // I.e, ConfigurationPath == "...\Services\Driver".
+ //
+ // For a layered driver, ParameterQueryTable[3].Name is "Driver"
+ // for all calls to AddAdapter, and parameters are read from
+ // "...\Services\Driver\Parameters" for all calls.
+ //
+ // For a non-layered driver, ParametersQueryTable[3].Name might be
+ // "Driver01" for the first call to AddAdapter, "Driver02" for the
+ // second, etc., and parameters are read from
+ // "..\Services\Driver01\Parameters" for the first call to
+ // AddAdapter, "...\Services\Driver02\Parameters" for the second
+ // call, etc.
+ //
+
+ if (LayeredDriver) {
+
+ BaseFileName = ConfigurationPath;
+
+ for ( i = 0; i < ConfigurationString->Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set BaseFileName to
+ // the character after the separator.
+ //
+
+ if ( ConfigurationPath[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ BaseFileName = &(ConfigurationPath[++i]);
+ }
+
+ }
+
+#if DBG
+ DbgPrint ("NDIS: Loading layered driver %ws\n", BaseFileName);
+#endif
+
+ }
+
+
+ //
+ // Set up ParametersQueryTable. We set most of it up here,
+ // then call the MAC's AddAdapter routine with its address
+ // as a ConfigContext. Inside ReadConfiguration, we get
+ // the ConfigContext back and can then finish initializing
+ // the table and use RtlQueryRegistryValues (with a
+ // callback to WrapperSaveParameter) to read the value
+ // specified.
+ //
+
+
+ //
+ // 1) Switch to the Parameters key below the [DriverName] key
+ // (DriverName is passed as a parameter to RtlQueryRegistryValues).
+ //
+
+ ConfigurationHandle.ParametersQueryTable[0].QueryRoutine = NULL;
+ ConfigurationHandle.ParametersQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ ConfigurationHandle.ParametersQueryTable[0].Name = Parameters;
+
+ //
+ // 2) Call WrapperSaveParameter for a parameter, which
+ // will allocate storage for it.
+ //
+ // ParametersQueryTable[1].Name and ParametersQueryTable[1].EntryContext
+ // are filled in inside ReadConfiguration, in preparation
+ // for the callback.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[1].QueryRoutine = WrapperSaveParameters;
+ ConfigurationHandle.ParametersQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ ConfigurationHandle.ParametersQueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ ConfigurationHandle.ParametersQueryTable[2].QueryRoutine = NULL;
+ ConfigurationHandle.ParametersQueryTable[2].Flags = 0;
+ ConfigurationHandle.ParametersQueryTable[2].Name = NULL;
+
+ //
+ // NOTE: Some fields in ParametersQueryTable[3] are used to
+ // store information for later retrieval.
+ //
+
+
+
+ //
+ // OK, Now lock down all the filter packages. If a MAC or
+ // Miniport driver uses any of these, then the filter package
+ // will reference itself, to keep the image in memory.
+ //
+ ArcReferencePackage();
+ EthReferencePackage();
+ FddiReferencePackage();
+ TrReferencePackage();
+ MiniportReferencePackage();
+ NdisMacReferencePackage();
+
+ //
+ // For each binding, get the handle to the card object.
+ // Call the driver's addadapter routine.
+ //
+
+ CurBindValue = BindData;
+ CurExportValue = ExportData;
+
+ while ((*CurBindValue != 0) && (*CurExportValue != 0)) {
+
+ UNICODE_STRING CurBindString;
+ UNICODE_STRING CurExportString;
+ NDIS_CONFIGURATION_HANDLE TmpConfigHandle;
+ NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
+ NDIS_STRING BusNumberStr = NDIS_STRING_CONST("BusNumber");
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ PDEVICE_OBJECT TmpDeviceP;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ LARGE_INTEGER TimeoutValue;
+
+ TimeoutValue.QuadPart = Int32x32To64(100 * 1000, -10000);
+
+ //
+ // Setup the query table to point to the section in
+ // the registry corresponding to what was specified
+ // in "Bind". The "Parameters" key below this is where
+ // config parameters are read from.
+ //
+
+ RtlInitUnicodeString (&CurBindString, CurBindValue);
+
+ //
+ // For layered drivers, BaseFileName is already
+ // initialized.
+ //
+
+ if (!LayeredDriver) {
+
+ //
+ // Parse out the path name, leaving only the driver name.
+ //
+
+ BaseFileName = CurBindString.Buffer;
+
+ for ( i = 0; i < CurBindString.Length / sizeof(WCHAR); i++ ) {
+
+ //
+ // If s points to a directory separator, set fileBaseName to
+ // the character after the separator.
+ //
+
+ if ( CurBindString.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
+ BaseFileName = &(CurBindString.Buffer[++i]);
+ }
+
+ }
+
+ //
+ // Set this to NULL, in case NdisReadBindingInformation
+ // is called.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].EntryContext = NULL;
+
+ } else {
+
+ //
+ // This will be returned by NdisReadBindingInformation.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].EntryContext = CurBindValue;
+
+ }
+
+
+ //
+ // Save the driver name here; later we will use this as
+ // a parameter to RtlQueryRegistryValues.
+ //
+
+ ConfigurationHandle.ParametersQueryTable[3].Name = BaseFileName;
+
+ //
+ // Also, save the BusType and BusNumber so that we can pull them
+ // out in NdisRegisterAdapter(), NdisReadEisaSlotInformation() and
+ // NdisReadPosInformation().
+ //
+
+ TmpConfigHandle.KeyQueryTable = ConfigurationHandle.ParametersQueryTable;
+ TmpConfigHandle.ParameterList = NULL;
+
+ //
+ // Read Bus Number
+ //
+
+ NdisReadConfiguration(
+ &NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusNumberStr,
+ NdisParameterInteger
+ );
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ BusNumber = ReturnedValue->ParameterData.IntegerData;
+
+ } else {
+
+ BusNumber = (ULONG)(-1);
+ }
+
+ //
+ // Read Bus Type
+ //
+
+ NdisReadConfiguration(
+ &NdisStatus,
+ &ReturnedValue,
+ &TmpConfigHandle,
+ &BusTypeStr,
+ NdisParameterInteger
+ );
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ BusType = (NDIS_INTERFACE_TYPE)(ReturnedValue->ParameterData.IntegerData);
+
+ } else {
+
+ BusType = (NDIS_INTERFACE_TYPE)(-1);
+
+ }
+
+ ConfigurationHandle.ParametersQueryTable[3].DefaultType = (ULONG)(BusType);
+ ConfigurationHandle.ParametersQueryTable[3].DefaultLength = (ULONG)(BusNumber);
+ ConfigurationHandle.ParametersQueryTable[3].DefaultData = NULL;
+
+ //
+ // Call adapter callback. The current value for "Export"
+ // is what we tell him to name this device.
+ //
+
+ RtlInitUnicodeString (&CurExportString, CurExportValue);
+
+ if (IsAMiniport)
+ {
+ ConfigurationHandle.DriverObject = WDriver->NdisDriverInfo->NdisWrapperDriver;
+ }
+ else
+ {
+ ConfigurationHandle.DriverObject = NewMacP->NdisMacInfo->NdisWrapperDriver;
+ }
+
+ if (IsAMiniport)
+ {
+ KIRQL OldIrql;
+ ULONG MaximumLongAddresses;
+ UCHAR CurrentLongAddress[6];
+ ULONG MaximumShortAddresses;
+ UCHAR CurrentShortAddress[2];
+ UINT BytesWritten;
+ UINT BytesNeeded;
+ UINT PacketFilter = 0x1;
+ UCHAR i;
+ BOOLEAN LocalLock;
+ PARC_BUFFER_LIST Buffer;
+ PVOID DataBuffer;
+
+ //
+ // Initialize device.
+ //
+
+ if (!NdisReferenceDriver((PNDIS_M_DRIVER_BLOCK)WDriver)) {
+
+ //
+ // The driver is closing.
+ //
+
+ goto LoopBottom;
+
+ }
+
+ NtStatus = IoCreateDevice(
+ WDriver->NdisDriverInfo->NdisWrapperDriver,
+ sizeof(NDIS_MINIPORT_BLOCK) + sizeof(NDIS_WRAPPER_CONTEXT), // device extension size
+ &CurExportString,
+ FILE_DEVICE_PHYSICAL_NETCARD,
+ 0,
+ FALSE, // exclusive flag
+ &TmpDeviceP
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+
+ //
+ // Initialize the Miniport adapter block in the device object extension
+ //
+ // *** NDIS_WRAPPER_CONTEXT has a higher alignment requirement than
+ // NDIS_MINIPORT_BLOCK, so we put it first in the extension.
+ //
+
+ Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)TmpDeviceP->DeviceExtension + 1);
+
+ Miniport->WrapperContext = TmpDeviceP->DeviceExtension;
+
+ Miniport->BusType = BusType;
+ Miniport->BusNumber = BusNumber;
+ Miniport->DeviceObject = TmpDeviceP;
+ Miniport->DriverHandle = WDriver;
+ Miniport->MiniportName.Buffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ CurExportString.MaximumLength,
+ 'naDN'
+ );
+
+ if (Miniport->MiniportName.Buffer == NULL) {
+ NdisDereferenceDriver(WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportName.MaximumLength = CurExportString.MaximumLength;
+ Miniport->MiniportName.Length = CurExportString.Length;
+
+ RtlCopyMemory(Miniport->MiniportName.Buffer,
+ CurExportString.Buffer,
+ CurExportString.MaximumLength
+ );
+
+ Miniport->OpenQueue = (PNDIS_M_OPEN_BLOCK)NULL;
+ Miniport->EthDB = NULL;
+ Miniport->TrDB = NULL;
+ Miniport->FddiDB = NULL;
+ Miniport->ArcDB = NULL;
+ Miniport->BeingRemoved = FALSE;
+ Miniport->SendResourcesAvailable = 0xffffff;
+ Miniport->Flags = 0; // a value that cannot be a pointer.
+ Miniport->InAddDriver = TRUE;
+ NdisAllocateSpinLock(&Miniport->Lock);
+ //KeSetSpecialSpinLock(&Miniport->Lock, "miniport lock" );
+
+ NdisInitializeRef(&Miniport->Ref);
+
+ NdisInitializeTimer(
+ &Miniport->DpcTimer,
+ (PVOID) NdisMDpcTimer,
+ (PVOID) Miniport
+ );
+
+ NdisInitializeTimer(
+ &Miniport->WakeUpDpcTimer,
+ (PVOID) NdisMWakeUpDpc,
+ (PVOID) Miniport
+ );
+
+ if (!NdisQueueMiniportOnDriver(Miniport, WDriver)) {
+
+ //
+ // The Driver is closing, undo what we have done.
+ //
+
+ ExFreePool(Miniport->MiniportName.Buffer);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+
+ //
+ // Now we do something really bogus. We create many
+ // temporary filter databases, just in case any indications
+ // happen.
+ //
+
+ if (!EthCreateFilter(
+ 1,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->EthDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!TrCreateFilter(
+ NdisMChangeFunctionalAddress,
+ NdisMChangeGroupAddress,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &(Miniport->TrDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!FddiCreateFilter(
+ 1,
+ 1,
+ NdisMChangeFddiAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &(Miniport->FddiDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ if (!ArcCreateFilter(
+ Miniport,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress[0],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)
+ )) {
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Call adapter callback. The current value for "Export"
+ // is what we tell him to name this device.
+ //
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ MiniportInitializeStatus =
+ (WDriver->MiniportCharacteristics.InitializeHandler)(
+ &OpenErrorStatus,
+ &SelectedMediumIndex,
+ MediumArray,
+ MediumArraySize,
+ (NDIS_HANDLE)(Miniport),
+ (NDIS_HANDLE)&ConfigurationHandle
+ );
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ //
+ // Free the slot information buffer
+ //
+
+ if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) {
+
+ ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData);
+
+ }
+
+ if (MiniportInitializeStatus == NDIS_STATUS_SUCCESS) {
+
+ ASSERT(SelectedMediumIndex < MediumArraySize);
+
+ Miniport->MediaType = MediumArray[SelectedMediumIndex];
+
+ KeInitializeEvent(
+ &Miniport->RequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ //
+ // Query maximum lookahead
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x2
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ //
+ // Now adjust based on media type
+ //
+
+ switch(Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 14 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 14 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 32 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 32 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumFddi:
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 16 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 16 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumArcnet878_2:
+ Miniport->MaximumLookahead = (NDIS_M_MAX_LOOKAHEAD - 50 < MaximumLongAddresses) ?
+ NDIS_M_MAX_LOOKAHEAD - 50 :
+ MaximumLongAddresses;
+ break;
+
+ case NdisMediumWan:
+ Miniport->MaximumLookahead = 1514;
+
+ }
+
+ Miniport->CurrentLookahead = Miniport->MaximumLookahead;
+
+ //
+ // Query mac options
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_MAC_OPTIONS,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x3
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ Miniport->MacOptions = (UINT)MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x4
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Create filter package
+ //
+ switch(Miniport->MediaType) {
+
+ case NdisMedium802_3:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x5
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x6
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_3_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x7
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x8
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!EthCreateFilter(
+ MaximumLongAddresses,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x9
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMedium802_5:
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_802_5_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xA
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xB
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!TrCreateFilter(
+ NdisMChangeFunctionalAddress,
+ NdisMChangeGroupAddress,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->TrDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0xC
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_LONG_MAX_LIST_SIZE,
+ &MaximumLongAddresses,
+ sizeof(MaximumLongAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xD
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumLongAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumLongAddresses = MaximumLongAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xE
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Query maximum MulticastAddress
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_SHORT_MAX_LIST_SIZE,
+ &MaximumShortAddresses,
+ sizeof(MaximumShortAddresses),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0xF
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (MaximumShortAddresses > NDIS_M_MAX_MULTI_LIST) {
+
+ MaximumShortAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ }
+
+ Miniport->MaximumShortAddresses = MaximumShortAddresses;
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x10
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_LONG_CURRENT_ADDR,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x11
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x12
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_FDDI_SHORT_CURRENT_ADDR,
+ &(CurrentShortAddress),
+ sizeof(CurrentShortAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x13
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x14
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!FddiCreateFilter(
+ MaximumLongAddresses,
+ MaximumShortAddresses,
+ NdisMChangeFddiAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ CurrentShortAddress,
+ &Miniport->Lock,
+ &Miniport->FddiDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x15
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // In case of an encapsulated ethernet binding, we need
+ // to return the maximum number of multicast addresses
+ // possible.
+ //
+
+ Miniport->MaximumLongAddresses = NDIS_M_MAX_MULTI_LIST;
+
+ //
+ // Allocate Buffer pools
+ //
+ NdisAllocateBufferPool(&NdisStatus,
+ &Miniport->ArcnetBufferPool,
+ WRAPPER_ARC_BUFFERS
+ );
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x16
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ NdisAllocateMemory((PVOID)&Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax
+ );
+
+ if (Buffer == NULL) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x18
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ NdisAllocateMemory((PVOID)&DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0,
+ HighestAcceptableMax
+ );
+
+
+ if (DataBuffer == NULL) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x19
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ for (i = WRAPPER_ARC_BUFFERS; i != 0 ; i--) {
+
+ Buffer->BytesLeft = Buffer->Size = WRAPPER_ARC_HEADER_SIZE;
+ Buffer->Buffer = DataBuffer;
+ Buffer->Next = Miniport->ArcnetFreeBufferList;
+ Miniport->ArcnetFreeBufferList = Buffer;
+
+ Buffer++;
+ DataBuffer = (PVOID)(((PUCHAR)DataBuffer) +
+ WRAPPER_ARC_HEADER_SIZE);
+
+ }
+
+
+ //
+ // Get current address
+ //
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_ARCNET_CURRENT_ADDRESS,
+ &CurrentLongAddress[5], // address = 00-00-00-00-00-XX
+ 1,
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1A
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeBufferPool(Miniport->ArcnetBufferPool);
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1B
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->ArcnetAddress = CurrentLongAddress[5];
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ if (!ArcCreateFilter(
+ Miniport,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress[5],
+ &Miniport->Lock,
+ &(Miniport->ArcDB)
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x1C
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ // Zero all but the last one.
+
+ CurrentLongAddress[0] = 0;
+ CurrentLongAddress[1] = 0;
+ CurrentLongAddress[2] = 0;
+ CurrentLongAddress[3] = 0;
+ CurrentLongAddress[4] = 0;
+
+ if (!EthCreateFilter(
+ 32,
+ NdisMChangeEthAddresses,
+ NdisMChangeClass,
+ NdisMCloseAction,
+ CurrentLongAddress,
+ &Miniport->Lock,
+ &Miniport->EthDB
+ )) {
+
+ //
+ // Halt the miniport driver
+ //
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ 0xFF00FF00,
+ 0x1D
+ );
+ NdisFreeMemory(Buffer,
+ sizeof(ARC_BUFFER_LIST) *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ NdisFreeMemory(DataBuffer,
+ WRAPPER_ARC_HEADER_SIZE *
+ WRAPPER_ARC_BUFFERS,
+ 0
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ case NdisMediumWan:
+
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryInformation;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.QueryInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_WAN_CURRENT_ADDRESS,
+ &(CurrentLongAddress),
+ sizeof(CurrentLongAddress),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x7
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x8
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ //
+ // Now undo the bogus filter package. We lock
+ // the miniport so that no dpcs will get queued.
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ Miniport->InInitialize = TRUE;
+ Miniport->NormalInterrupts = FALSE;
+
+ EthDeleteFilter(Miniport->EthDB);
+ Miniport->EthDB = NULL;
+ TrDeleteFilter(Miniport->TrDB);
+ Miniport->TrDB = NULL;
+ FddiDeleteFilter(Miniport->FddiDB);
+ Miniport->FddiDB = NULL;
+ ArcDeleteFilter(Miniport->ArcDB);
+ Miniport->ArcDB = NULL;
+
+ Miniport->InInitialize = FALSE;
+ CHECK_FOR_NORMAL_INTERRUPTS(Miniport);
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ break;
+
+ }
+
+ //
+ // Get supported packet filters
+ //
+ Miniport->SupportedPacketFilters = 0;
+
+ //
+ // Set the filter packages bit mask to fake it out.
+ //
+ if (Miniport->EthDB) {
+ Miniport->EthDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+ if (Miniport->TrDB) {
+ Miniport->TrDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+ if (Miniport->FddiDB) {
+ Miniport->FddiDB->CombinedPacketFilter = 0xFFFFFFFF;
+ }
+
+ //
+ // For WAN there is no packet filter
+ //
+
+ if (Miniport->MediaType==NdisMediumWan) {
+ goto SkipFilter;
+ }
+
+ for (i=0; i<31; i++) {
+
+ //
+ // Set packet filter
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ NtStatus = KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ &TimeoutValue
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+
+ //
+ // Halt the miniport driver
+ //
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+
+ (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler) (
+ Miniport->MiniportAdapterContext
+ );
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NdisWriteErrorLogEntry(
+ (NDIS_HANDLE)Miniport,
+ NDIS_ERROR_CODE_DRIVER_FAILURE,
+ 2,
+ 0xFF00FF00,
+ 0x1E
+ );
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+
+ }
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Miniport->SupportedPacketFilters |= PacketFilter;
+ }
+
+ PacketFilter = PacketFilter << 1;
+
+ }
+
+ //
+ // Set packet filter
+ //
+ Miniport->MiniportRequest = &Miniport->InternalRequest;
+ PacketFilter = 0;
+
+ Miniport->InternalRequest.RequestType = NdisRequestQueryStatistics;
+
+ BLOCK_LOCK_MINIPORT(Miniport, LocalLock);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ NdisStatus =
+ (Miniport->DriverHandle->MiniportCharacteristics.SetInformationHandler) (
+ Miniport->MiniportAdapterContext,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ &PacketFilter,
+ sizeof(PacketFilter),
+ &BytesWritten,
+ &BytesNeeded
+ );
+
+ KeLowerIrql(OldIrql);
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ //
+ // Fire a DPC to do anything
+ //
+ if ((NdisStatus == NDIS_STATUS_PENDING) ||
+ (NdisStatus == NDIS_STATUS_SUCCESS)) {
+
+ Miniport->RunDpc = FALSE;
+ NdisSetTimer(&(Miniport->DpcTimer), 1);
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Miniport->RequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ KeResetEvent(
+ &Miniport->RequestEvent
+ );
+
+ NdisStatus = Miniport->RequestStatus;
+
+ }
+
+ //
+ // Set the filter packages bit mask to fake it out.
+ //
+ if (Miniport->EthDB) {
+ Miniport->EthDB->CombinedPacketFilter = 0;
+ }
+ if (Miniport->TrDB) {
+ Miniport->TrDB->CombinedPacketFilter = 0;
+ }
+ if (Miniport->FddiDB) {
+ Miniport->FddiDB->CombinedPacketFilter = 0;
+ }
+
+SkipFilter:
+
+ //
+ // Start wake up timer
+ //
+ NdisSetTimer(&(Miniport->WakeUpDpcTimer), 2000);
+
+ //
+ // Done with adding this MINIPORT!!!
+ //
+ Miniport->MiniportRequest = NULL;
+ Miniport->InAddDriver = FALSE;
+
+ IoRegisterShutdownNotification(Miniport->DeviceObject);
+
+ ++AdaptersAdded;
+
+ } else{
+
+ //
+ // Undo all the stuff from this mini-port
+ //
+ ExFreePool(Miniport->MiniportName.Buffer);
+ NdisDequeueMiniportOnDriver(Miniport, WDriver);
+ IoDeleteDevice(TmpDeviceP);
+ NdisDereferenceDriver(WDriver);
+ goto LoopBottom;
+ }
+
+ } else {
+
+ //
+ // NDIS 3.0 MAC
+ //
+ AddAdapterStatus =
+ (NewMacP->MacCharacteristics.AddAdapterHandler)(
+ NewMacP->MacMacContext,
+ &ConfigurationHandle,
+ &CurExportString
+ );
+
+
+ //
+ // Free the slot information buffer
+ //
+
+ if (ConfigurationHandle.ParametersQueryTable[3].DefaultData != NULL ) {
+
+ ExFreePool(ConfigurationHandle.ParametersQueryTable[3].DefaultData);
+
+ }
+
+ if (AddAdapterStatus == NDIS_STATUS_SUCCESS) {
+ ++AdaptersAdded;
+ }
+
+ }
+
+LoopBottom:
+
+
+ //
+ // Now advance the "Bind" and "Export" values.
+ //
+
+ CurBindValue = (PWCHAR)((PUCHAR)CurBindValue + CurBindString.MaximumLength);
+ CurExportValue = (PWCHAR)((PUCHAR)CurExportValue + CurExportString.MaximumLength);
+
+ }
+
+
+ //
+ // OK, Now dereference all the filter packages. If a MAC or
+ // Miniport driver uses any of these, then the filter package
+ // will reference itself, to keep the image in memory.
+ //
+ ArcDereferencePackage();
+ EthDereferencePackage();
+ FddiDereferencePackage();
+ TrDereferencePackage();
+ MiniportDereferencePackage();
+ NdisMacDereferencePackage();
+
+ //
+ // Now close the handles we opened at the beginning.
+ //
+
+
+ ExFreePool (ConfigurationPath);
+ ExFreePool (BindData);
+ ExFreePool (ExportData);
+
+ //
+ // Succeed if any adapters were added.
+ //
+
+ if (AdaptersAdded > 0) {
+ return NDIS_STATUS_SUCCESS;
+ } else {
+ return NDIS_STATUS_FAILURE;
+ }
+
+#undef BLOCK_LOCK_MINIPORT
+
+}
+
+
+VOID
+NdisReadEisaSlotInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION EisaData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the EISA data from the slot given.
+
+Arguments:
+
+ Status - Status of request to be returned to the user.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ SlotNumber - the EISA Slot where the card is at.
+ EisaData - pointer to a buffer where the EISA configuration is to be
+ returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer;
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ ULONG DataLength;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG CompressedId = 0;
+ PWSTR CompressedIDString = L"EisaCompressedId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ PWSTR Parameters = L"\\Parameters";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ ULONG Length;
+ PWSTR PathName;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData;
+
+ *SlotNumber = 0;
+
+ if (BusType != Eisa) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ //
+ // Find the CompressedId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ CompressedId = 0xffffffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ CompressedId = 0xffffffff;
+ } else {
+ CompressedId = ParameterValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Was there already a buffer allocated?
+ //
+
+ if (SlotInformation == NULL) {
+
+ //
+ // No, allocate a buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *SlotNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ if ((CompressedId != 0xFFFFFFFF) &&
+ ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ //
+ // Search this slot
+ //
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ SearchSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ if ((DataLength == 0) ||
+ (SearchSlotNumber == 0xFF)) {
+ //
+ // End of slots.
+ //
+ break;
+
+ }
+
+ if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *SlotNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Get the new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)
+ );
+
+ }
+
+ EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION)
+ ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION));
+
+ *EisaData = *EisaBlockPointer;
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadEisaSlotInformationEx(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT SlotNumber,
+ OUT PNDIS_EISA_FUNCTION_INFORMATION *EisaData,
+ OUT PUINT NumberOfFunctions
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the EISA data from the slot given.
+
+Arguments:
+
+ Status - Status of request to be returned to the user.
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ SlotNumber - the EISA Slot where the card is at.
+ EisaData - pointer to a buffer where the EISA configuration is to be
+ returned.
+ NumberOfFunctions - Returns the number of function structures in the EisaData.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_EISA_FUNCTION_INFORMATION EisaBlockPointer;
+ PNDIS_EISA_SLOT_INFORMATION SlotInformation;
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ ULONG DataLength;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG CompressedId = 0;
+ PWSTR CompressedIDString = L"EisaCompressedId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ PWSTR Parameters = L"\\Parameters";
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ ULONG Length;
+ PWSTR PathName;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ SlotInformation = NdisConfiguration.KeyQueryTable[3].DefaultData;
+
+ *SlotNumber = 0;
+ *NumberOfFunctions = 2;
+
+ if (BusType != Eisa) {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+
+ //
+ // Find the CompressedId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = CompressedIDString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ CompressedId = 0xffffffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ CompressedId = 0xffffffff;
+ } else {
+ CompressedId = ParameterValue->ParameterData.IntegerData;
+ }
+
+ //
+ // Was there already a buffer allocated?
+ //
+
+ if (SlotInformation == NULL) {
+
+ //
+ // No, allocate a buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions *
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *SlotNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ *SlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ if ((CompressedId != 0xFFFFFFFF) &&
+ ((SlotInformation->CompressedId & 0xFFFFFF) != CompressedId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (TRUE) {
+
+ //
+ // Search this slot
+ //
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ SearchSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ if ((DataLength == 0) ||
+ (SearchSlotNumber == 0xFF)) {
+ //
+ // End of slots.
+ //
+ break;
+
+ }
+
+ if ((SlotInformation->CompressedId & 0xFFFFFF) == CompressedId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *SlotNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Get the new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ }
+
+
+ //
+ // Now check for multiple functions in the Eisa data.
+ //
+
+ while (DataLength == (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))) {
+
+ *NumberOfFunctions++;
+
+ //
+ // Now allocate a new buffer
+ //
+
+ SlotInformation = (PNDIS_EISA_SLOT_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions *
+ sizeof(NDIS_EISA_FUNCTION_INFORMATION)),
+ 'isDN'
+ );
+
+ if (SlotInformation == NULL) {
+
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+
+ }
+
+ //
+ // Free any old buffer
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = SlotInformation;
+
+ //
+ // Get new information
+ //
+
+ DataLength = HalGetBusData(
+ EisaConfiguration,
+ BusNumber,
+ FoundSlotNumber,
+ (PVOID)SlotInformation,
+ sizeof(NDIS_EISA_SLOT_INFORMATION) +
+ (*NumberOfFunctions * sizeof(NDIS_EISA_FUNCTION_INFORMATION))
+ );
+
+ }
+
+ EisaBlockPointer = (PNDIS_EISA_FUNCTION_INFORMATION)
+ ((PUCHAR)SlotInformation + sizeof(CM_EISA_SLOT_INFORMATION));
+
+ *EisaData = EisaBlockPointer;
+ *NumberOfFunctions--; // We overshoot by 1 to verify last one found.
+ *Status = NDIS_STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisReadMcaPosInformation(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ OUT PUINT ChannelNumber,
+ OUT PNDIS_MCA_POS_DATA McaData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the MCA data from the POS corresponding to
+ the channel specified.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+ ChannelNumber - the MCA channel number.
+ McaData - pointer to a buffer where the channel information is to be
+ returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ OBJECT_ATTRIBUTES BusObjectAttributes;
+ PWSTR McaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
+ PWSTR ConfigData = L"Configuration Data";
+ PWSTR PosIdString = L"McaPosId";
+ PWSTR SlotNumberString = L"SlotNumber";
+ UNICODE_STRING RootName;
+ UNICODE_STRING BusName;
+ UNICODE_STRING ConfigDataName;
+ NTSTATUS NtStatus;
+ PKEY_BASIC_INFORMATION BasicInformation;
+ PKEY_VALUE_FULL_INFORMATION ValueInformation;
+ PUCHAR BufferPointer;
+ PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
+ PCM_PARTIAL_RESOURCE_LIST ResourceList;
+ PNDIS_MCA_POS_DATA McaBlockPointer;
+ HANDLE McaHandle, BusHandle;
+ ULONG BytesWritten, BytesNeeded;
+ ULONG Index;
+ ULONG i;
+ ULONG BusNumber;
+ ULONG MaxSlotNumber;
+ ULONG SearchSlotNumber;
+ ULONG FoundSlotNumber;
+ BOOLEAN Found;
+ USHORT PosId;
+ NDIS_INTERFACE_TYPE BusType;
+ NDIS_CONFIGURATION_HANDLE NdisConfiguration;
+ PNDIS_CONFIGURATION_PARAMETER ParameterValue;
+ PWSTR Parameters = L"\\Parameters";
+ ULONG Length;
+ PWSTR PathName;
+
+ *Status = NDIS_STATUS_FAILURE;
+
+ NdisConfiguration.KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ BusType = (NDIS_INTERFACE_TYPE)(NdisConfiguration.KeyQueryTable[3].DefaultType);
+ BusNumber = NdisConfiguration.KeyQueryTable[3].DefaultLength;
+
+ //
+ // First check if any bus access is allowed
+ //
+
+ if ((BusType == (NDIS_INTERFACE_TYPE)-1) ||
+ (BusNumber == (ULONG)-1)) {
+
+ return;
+
+ }
+
+
+ if (BusType != MicroChannel) {
+
+ return;
+
+ }
+
+ *ChannelNumber = 0;
+
+ //
+ // Find the PosId for this board.
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = PosIdString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if (NtStatus != NDIS_STATUS_SUCCESS) {
+ PosId = 0xffff;
+ } else if (ParameterValue->ParameterType != NdisParameterInteger) {
+ PosId = 0xffff;
+ } else {
+ PosId = (USHORT)(ParameterValue->ParameterData.IntegerData);
+ }
+
+ RtlInitUnicodeString(
+ &RootName,
+ McaPath
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &RootName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)NULL,
+ NULL
+ );
+
+ //
+ // Open the root.
+ //
+
+ NtStatus = ZwOpenKey(
+ &McaHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ return;
+
+ }
+
+ Index = 0;
+
+ while (TRUE) {
+
+ //
+ // Enumerate through keys, searching for the proper bus number
+ //
+
+ NtStatus = ZwEnumerateKey(
+ McaHandle,
+ Index,
+ KeyBasicInformation,
+ NULL,
+ 0,
+ &BytesNeeded
+ );
+
+ //
+ // That should fail!
+ //
+
+ if (BytesNeeded == 0) {
+
+ Index++;
+ continue;
+
+ }
+
+ BasicInformation = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ BytesNeeded,
+ ' DN'
+ );
+
+ if (BasicInformation == NULL) {
+
+ ZwClose(McaHandle);
+
+ return;
+ }
+
+ NtStatus = ZwEnumerateKey(
+ McaHandle,
+ Index,
+ KeyBasicInformation,
+ BasicInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ ExFreePool(BasicInformation);
+
+ ZwClose(McaHandle);
+
+ return;
+ }
+
+
+ //
+ // Init the BusName String
+ //
+
+ BusName.MaximumLength = (USHORT)BasicInformation->NameLength;
+ BusName.Length = (USHORT)BasicInformation->NameLength;
+ BusName.Buffer = BasicInformation->Name;
+
+ //
+ // Now try to find Configuration Data within this Key
+ //
+
+ InitializeObjectAttributes(
+ &BusObjectAttributes,
+ &BusName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)McaHandle,
+ NULL
+ );
+
+ //
+ // Open the MCA root + Bus Number
+ //
+
+ NtStatus = ZwOpenKey(
+ &BusHandle,
+ KEY_READ,
+ &BusObjectAttributes
+ );
+
+ ExFreePool(BasicInformation);
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ Index++;
+
+ continue;
+
+ }
+
+ //
+ // opening the configuration data. This first call tells us how
+ // much memory we need to allocate
+ //
+
+ RtlInitUnicodeString(
+ &ConfigDataName,
+ ConfigData
+ );
+
+ //
+ // This should fail
+ //
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ NULL,
+ 0,
+ &BytesNeeded
+ );
+
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePoolWithTag(
+ NonPagedPool,
+ BytesNeeded,
+ ' DN'
+ );
+
+
+ if (ValueInformation == NULL) {
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+
+ Index++;
+
+ ExFreePool(ValueInformation);
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ //
+ // Search for our bus number and type
+ //
+
+
+ //
+ // What we got back from the registry is actually a blob of data that
+ // looks like this
+ //
+ // ------------------------------------------
+ // |FULL |PAR |PAR |MCA |MCA |MCA |
+ // |RES. |RES |RES |POS |POS |POS | . . .
+ // |DESC |LIST|DESC|DATA|DATA|DATA|
+ // ------------------------------------------
+ // slot 0 1 2 . . .
+ //
+ // Out of this mess we need to grovel a pointer to the first block
+ // of MCA_POS_DATA, then we can just index by slot number.
+ //
+
+ BufferPointer = ((PUCHAR)ValueInformation) + ValueInformation->DataOffset;
+ FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR) BufferPointer;
+
+ if (FullResource->InterfaceType != MicroChannel) {
+
+ //
+ // Get next key
+ //
+
+ ExFreePool(ValueInformation);
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+ if (FullResource->BusNumber != BusNumber) {
+
+ //
+ // Get next key
+ //
+
+ ExFreePool(ValueInformation);
+
+ Index++;
+
+ ZwClose(BusHandle);
+
+ continue;
+
+ }
+
+
+ //
+ // Found it!!
+ //
+
+ ResourceList = &FullResource->PartialResourceList;
+
+ //
+ // Find the device-specific information, which is where the POS data is.
+ //
+
+ for (i=0; i<ResourceList->Count; i++) {
+ if (ResourceList->PartialDescriptors[i].Type == CmResourceTypeDeviceSpecific) {
+ break;
+ }
+ }
+
+ if (i == ResourceList->Count) {
+ //
+ // Couldn't find device-specific information.
+ //
+
+#if DBG
+ DbgPrint("NDIS: couldn't find POS data in registry\n");
+#endif
+
+ ExFreePool(ValueInformation);
+ *Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
+ return;
+
+ }
+
+ //
+ // Was there a buffer already there?
+ //
+
+ if (NdisConfiguration.KeyQueryTable[3].DefaultData != NULL) {
+
+ //
+ // Free it
+ //
+
+ ExFreePool(NdisConfiguration.KeyQueryTable[3].DefaultData);
+
+ }
+
+ //
+ // Now read the slot number
+ //
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ //
+ // Get the value from the registry; this chains it on to the
+ // parameter list at NdisConfiguration.
+ //
+
+ NtStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ NdisConfiguration.KeyQueryTable,
+ &NdisConfiguration, // context
+ NULL);
+
+ if ((NtStatus == NDIS_STATUS_SUCCESS) &&
+ (ParameterValue->ParameterType == NdisParameterInteger)) {
+
+ *ChannelNumber = ParameterValue->ParameterData.IntegerData;
+
+ } else {
+
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Store buffer
+ //
+
+ NdisConfiguration.KeyQueryTable[3].DefaultData = ValueInformation;
+
+ McaBlockPointer = (PNDIS_MCA_POS_DATA)(&ResourceList->PartialDescriptors[i+1]);
+ MaxSlotNumber = ResourceList->PartialDescriptors[i].u.DeviceSpecificData.DataSize /
+ sizeof(NDIS_MCA_POS_DATA);
+
+ *McaData = *(McaBlockPointer + (*ChannelNumber) - 1);
+
+ if ((PosId != 0xFFFF) &&
+ (McaData->AdapterId != PosId)) {
+
+ //
+ // The card seems to have been moved on us. Now we search for it.
+ //
+
+ SearchSlotNumber = 1;
+ Found = FALSE;
+
+ while (SearchSlotNumber <= MaxSlotNumber) {
+
+ *McaData = *(McaBlockPointer + (SearchSlotNumber - 1));
+
+ if (McaData->AdapterId == PosId) {
+
+ //
+ // Found one!
+ //
+
+ if (Found) {
+
+ //
+ // Uh-oh, found two of them! Fail
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ Found = TRUE;
+ FoundSlotNumber = SearchSlotNumber;
+
+ }
+
+ SearchSlotNumber++;
+
+ }
+
+ if (!Found) {
+ //
+ // No card found
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ return;
+
+ }
+
+ //
+ // Find the SlotNumber parameter in the registry.
+ //
+
+ *ChannelNumber = FoundSlotNumber;
+
+ NdisConfiguration.KeyQueryTable[1].Name = SlotNumberString;
+ NdisConfiguration.KeyQueryTable[1].EntryContext = &ParameterValue;
+
+ Length = wcslen(NdisConfiguration.KeyQueryTable[3].Name);
+
+ PathName = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR),
+ ' DN'
+ );
+
+ if (PathName != NULL) {
+
+ NdisZeroMemory(PathName, sizeof(L"\\Parameters") +
+ (Length * sizeof(WCHAR)) +
+ sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ Length * sizeof(WCHAR)
+ );
+
+ NdisMoveMemory(PathName + Length, Parameters, sizeof(L"\\Parameters"));
+
+ //
+ // Update the value
+ //
+
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ PathName,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ ExFreePool(PathName);
+
+ }
+
+ //
+ // Update the value
+ //
+ NtStatus = RtlWriteRegistryValue(
+ RTL_REGISTRY_SERVICES,
+ NdisConfiguration.KeyQueryTable[3].Name,
+ SlotNumberString,
+ REG_DWORD,
+ &FoundSlotNumber,
+ sizeof(FoundSlotNumber)
+ );
+
+ //
+ // Get the new information
+ //
+
+ *McaData = *(McaBlockPointer + (FoundSlotNumber - 1));
+
+ }
+
+ *Status = NDIS_STATUS_SUCCESS;
+
+ ZwClose(McaHandle);
+
+ return;
+
+ }
+
+}
+
+#if !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+/*++
+
+Routine Description:
+
+ This routine uses the Hal to assign a set of resources to a PCI
+ device.
+
+Arguments:
+
+ NdisMacHandle - Handle returned from NdisRegisterMac.
+
+ NdisWrapperHandle - Handle returned from NdisInitializeWrapper.
+
+ WrapperConfigurationContext - Handle passed to MacAddAdapter.
+
+ SlotNumber - Slot number of the device.
+
+ AssignedResources - The returned resources.
+
+Return Value:
+
+ Status of the operation
+
+--*/
+{
+ NTSTATUS NtStatus;
+ ULONG BusNumber;
+ NDIS_INTERFACE_TYPE BusType;
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable;
+ PCM_RESOURCE_LIST AllocatedResources = NULL;
+ PNDIS_WRAPPER_HANDLE NdisMacInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
+
+ //
+ // Get the BusNumber and the BusType from the Context here!!
+ //
+
+ KeyQueryTable = (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+
+ BusType = (NDIS_INTERFACE_TYPE)KeyQueryTable[3].DefaultType;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ NtStatus = HalAssignSlotResources (
+ (PUNICODE_STRING)(NdisMacInfo->NdisWrapperConfigurationHandle),
+ NULL,
+ NdisMacInfo->NdisWrapperDriver,
+ NULL,
+ BusType,
+ BusNumber,
+ SlotNumber,
+ &AllocatedResources
+ );
+
+ if (NtStatus != STATUS_SUCCESS) {
+ *AssignedResources = NULL;
+ return(NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Store resources into the driver wide block
+ //
+ ((PNDIS_MAC_BLOCK)NdisMacHandle)->PciAssignedResources = AllocatedResources;
+
+ *AssignedResources = &(AllocatedResources->List[0].PartialResourceList);
+
+ return(NDIS_STATUS_SUCCESS);
+
+}
+
+
+
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ NdisAdapterHandle - Adapter we are talking about.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes read.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG DataLength;
+
+ if (Adapter->DeviceObject == NULL) {
+
+ //
+ // This is a mini-port
+ //
+
+#if DBG
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ } else {
+
+#if DBG
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ }
+
+}
+
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ NdisAdapterHandle - Adapter we are talking about.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes written.
+
+--*/
+{
+ PNDIS_ADAPTER_BLOCK Adapter = (PNDIS_ADAPTER_BLOCK)NdisAdapterHandle;
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)NdisAdapterHandle;
+ ULONG DataLength;
+
+ if (Adapter->DeviceObject == NULL) {
+
+ //
+ // This is a mini-port
+ //
+
+#if DBG
+ ASSERT(Miniport->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ Miniport->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ } else {
+
+#if DBG
+ ASSERT(Adapter->BusType == NdisInterfacePci);
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ Adapter->BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+
+ }
+
+}
+
+#else // !defined(BUILD_FOR_3_1)
+
+NDIS_STATUS
+NdisPciAssignResources(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE NdisWrapperHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ OUT PNDIS_RESOURCE_LIST *AssignedResources
+ )
+{
+ return NDIS_STATUS_FAILURE;
+}
+
+ULONG
+NdisReadPciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+ULONG
+NdisWritePciSlotInformation(
+ IN NDIS_HANDLE NdisAdapterHandle,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+#endif // else !defined(BUILD_FOR_3_1)
+
+
+VOID
+NdisOpenFile(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE FileHandle,
+ OUT PUINT FileLength,
+ IN PNDIS_STRING FileName,
+ IN NDIS_PHYSICAL_ADDRESS HighestAcceptableAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file for future mapping and reads its contents
+ into allocated memory.
+
+Arguments:
+
+ Status - The status of the operation
+
+ FileHandle - A handle to be associated with this open
+
+ FileLength - Returns the length of the file
+
+ FileName - The name of the file
+
+ HighestAcceptableAddress - The highest physical address at which
+ the memory for the file can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS NtStatus;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE NtFileHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG LengthOfFile;
+ WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\";
+ NDIS_STRING FullFileName;
+ ULONG FullFileNameLength;
+ PNDIS_FILE_DESCRIPTOR FileDescriptor;
+ PVOID FileImage;
+
+ //
+ // This structure represents the data from the
+ // NtQueryInformationFile API with an information
+ // class of FileStandardInformation.
+ //
+
+ FILE_STANDARD_INFORMATION StandardInfo;
+
+
+ //
+ // Insert the correct path prefix.
+ //
+
+ FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength;
+ FullFileName.Buffer = ExAllocatePoolWithTag (NonPagedPool, FullFileNameLength, ' DN');
+
+ if (FullFileName.Buffer == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ return;
+ }
+ FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
+ FullFileName.MaximumLength = (USHORT)FullFileNameLength;
+ RtlCopyMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
+
+ RtlAppendUnicodeStringToString (&FullFileName, FileName);
+
+#if DBG
+ DbgPrint ("NDIS: Attempting to open %Z\n", &FullFileName);
+#endif
+
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &FullFileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ NtStatus = ZwCreateFile(
+ &NtFileHandle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &ObjectAttributes,
+ &IoStatus,
+ NULL,
+ 0,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint ("Error opening file %x\n", NtStatus);
+#endif
+ ExFreePool (FullFileName.Buffer);
+ *Status = NDIS_STATUS_FILE_NOT_FOUND;
+ return;
+ }
+
+ ExFreePool (FullFileName.Buffer);
+
+ //
+ // Query the object to determine its length.
+ //
+
+ NtStatus = ZwQueryInformationFile(
+ NtFileHandle,
+ &IoStatus,
+ &StandardInfo,
+ sizeof(FILE_STANDARD_INFORMATION),
+ FileStandardInformation
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint ("Error querying info on file %x\n", NtStatus);
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+ }
+
+ LengthOfFile = StandardInfo.EndOfFile.LowPart;
+
+#if DBG
+ DbgPrint ("File length is %d\n", LengthOfFile);
+#endif
+
+ //
+ // Might be corrupted.
+ //
+
+ if (LengthOfFile < 1) {
+#if DBG
+ DbgPrint ("Bad file length %d\n", LengthOfFile);
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+ }
+
+ //
+ // Allocate buffer for this file
+ //
+
+ FileImage = ExAllocatePoolWithTag(NonPagedPool, LengthOfFile, ' DN');
+
+ if (FileImage == NULL) {
+
+#if DBG
+ DbgPrint ("Could not allocate buffer\n");
+#endif
+ ZwClose(NtFileHandle);
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ return;
+
+ }
+
+ //
+ // Read the file into our buffer.
+ //
+
+ NtStatus = ZwReadFile(
+ NtFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ FileImage,
+ LengthOfFile,
+ NULL,
+ NULL
+ );
+
+ ZwClose(NtFileHandle);
+
+ if ((!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile)) {
+#if DBG
+ DbgPrint ("error reading file %x\n", NtStatus);
+#endif
+ *Status = NDIS_STATUS_ERROR_READING_FILE;
+ ExFreePool(FileImage);
+ return;
+ }
+
+ //
+ // Allocate a structure to describe the file.
+ //
+
+ FileDescriptor = ExAllocatePoolWithTag (NonPagedPool, sizeof(NDIS_FILE_DESCRIPTOR), ' DN');
+
+ if (FileDescriptor == NULL) {
+ *Status = NDIS_STATUS_RESOURCES;
+ ExFreePool(FileImage);
+ return;
+ }
+
+
+ FileDescriptor->Data = FileImage;
+ NdisAllocateSpinLock (&FileDescriptor->Lock);
+ FileDescriptor->Mapped = FALSE;
+
+ *FileHandle = (NDIS_HANDLE)FileDescriptor;
+ *FileLength = LengthOfFile;
+ *Status = STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisCloseFile(
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine closes a file previously opened with NdisOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by NdisOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ ExFreePool (FileDescriptor->Data);
+ ExFreePool (FileDescriptor);
+
+}
+
+
+VOID
+NdisMapFile(
+ OUT PNDIS_STATUS Status,
+ OUT PVOID * MappedBuffer,
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps an open file, so that the contents can be accessed.
+ Files can only have one active mapping at any time.
+
+Arguments:
+
+ Status - The status of the operation
+
+ MappedBuffer - Returns the virtual address of the mapping.
+
+ FileHandle - The handle returned by NdisOpenFile.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ ACQUIRE_SPIN_LOCK(&FileDescriptor->Lock);
+
+ if (FileDescriptor->Mapped == TRUE) {
+ *Status = NDIS_STATUS_ALREADY_MAPPED;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock);
+ return;
+ }
+
+ FileDescriptor->Mapped = TRUE;
+ RELEASE_SPIN_LOCK (&FileDescriptor->Lock);
+
+ *MappedBuffer = FileDescriptor->Data;
+ *Status = STATUS_SUCCESS;
+
+}
+
+
+VOID
+NdisUnmapFile(
+ IN NDIS_HANDLE FileHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unmaps a file previously mapped with NdisOpenFile.
+ The file is unmapped if needed and the memory is freed.
+
+Arguments:
+
+ FileHandle - The handle returned by NdisOpenFile
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_FILE_DESCRIPTOR FileDescriptor = (PNDIS_FILE_DESCRIPTOR)FileHandle;
+
+ FileDescriptor->Mapped = FALSE;
+
+}
+
+
+#if defined(_ALPHA_)
+VOID
+NdisCreateLookaheadBufferFromSharedMemory(
+ IN PVOID pSharedMemory,
+ IN UINT LookaheadLength,
+ OUT PVOID *pLookaheadBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a lookahead buffer from a pointer to shared
+ RAM because some architectures (like ALPHA) do not allow access
+ through a pointer to shared ram.
+
+Arguments:
+
+ pSharedMemory - Pointer to shared ram space.
+
+ LookaheadLength - Amount of Lookahead to copy.
+
+ pLookaheadBuffer - Pointer to host memory space with a copy of the
+ stuff in pSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_LOOKAHEAD_ELEMENT TmpElement;
+
+ ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ if (NdisLookaheadBufferLength < (LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT))) {
+
+ //
+ // Free current list
+ //
+ while (NdisLookaheadBufferList != NULL) {
+
+ TmpElement = NdisLookaheadBufferList;
+ NdisLookaheadBufferList = NdisLookaheadBufferList->Next;
+
+ ExFreePool ( TmpElement ) ;
+
+ }
+
+ NdisLookaheadBufferLength = LookaheadLength +
+ sizeof(NDIS_LOOKAHEAD_ELEMENT);
+
+ }
+
+ if (NdisLookaheadBufferList == NULL) {
+
+ NdisLookaheadBufferList = (PNDIS_LOOKAHEAD_ELEMENT)ExAllocatePoolWithTag(
+ NonPagedPool,
+ NdisLookaheadBufferLength,
+ 'blDN'
+ );
+
+ if (NdisLookaheadBufferList == NULL) {
+
+ *pLookaheadBuffer = NULL;
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+ return;
+
+ }
+
+ NdisLookaheadBufferList->Next = NULL;
+ NdisLookaheadBufferList->Length = NdisLookaheadBufferLength;
+
+ }
+
+
+ //
+ // Get the buffer
+ //
+
+ *pLookaheadBuffer = (PVOID)(NdisLookaheadBufferList + 1);
+ NdisLookaheadBufferList = NdisLookaheadBufferList->Next;
+
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ //
+ // Copy the stuff across
+ //
+
+ READ_REGISTER_BUFFER_UCHAR(pSharedMemory, *pLookaheadBuffer, LookaheadLength);
+
+}
+
+
+VOID
+NdisDestroyLookaheadBufferFromSharedMemory(
+ IN PVOID pLookaheadBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine returns resources associated with a lookahead buffer.
+
+Arguments:
+
+ pLookaheadBuffer - Lookahead buffer created by
+ CreateLookaheadBufferFromSharedMemory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_LOOKAHEAD_ELEMENT Element = (PNDIS_LOOKAHEAD_ELEMENT)pLookaheadBuffer;
+
+ Element--;
+
+ if (Element->Length != NdisLookaheadBufferLength) {
+
+ ExFreePool(Element);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ Element->Next = NdisLookaheadBufferList;
+ NdisLookaheadBufferList = Element;
+
+ RELEASE_SPIN_LOCK(&NdisLookaheadBufferLock);
+
+ }
+
+}
+
+#endif // _ALPHA_
+
+
+BOOLEAN CheckPortUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG PortNumber,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+)
+/*++
+
+Routine Description:
+
+ This routine checks if a port is currently in use somewhere in the
+ system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ PortNumber - Address of the port to access.
+ Length - Number of ports from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ return(FALSE);
+
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup port
+ //
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypePort;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ (InterfaceType == Internal)?
+ CM_RESOURCE_PORT_MEMORY :
+ CM_RESOURCE_PORT_IO;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start.QuadPart = PortNumber;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(PortNumber));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length =
+ Length;
+
+ //
+ // Submit Resources
+ //
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+NTSTATUS
+StartMapping(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG InitialAddress,
+ IN ULONG Length,
+ OUT PVOID *InitialMapping,
+ OUT PBOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initialize the mapping of a address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ InitialAddress - Address to access.
+ Length - Number of bytes from the base address to access.
+ InitialMapping - The virtual address space to use when accessing the
+ address.
+ Mapped - Did an MmMapIoSpace() take place.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PHYSICAL_ADDRESS Address;
+ PHYSICAL_ADDRESS InitialPhysAddress;
+ ULONG addressSpace;
+
+ //
+ // Get the system physical address for this card. The card uses
+ // I/O space, except for "internal" Jazz devices which use
+ // memory space.
+ //
+
+ *Mapped = FALSE;
+
+ addressSpace = (InterfaceType == Internal) ? 0 : 1;
+
+ InitialPhysAddress.LowPart = InitialAddress;
+
+ InitialPhysAddress.HighPart = 0;
+
+ if ( !HalTranslateBusAddress(
+ InterfaceType, // InterfaceType
+ BusNumber, // BusNumber
+ InitialPhysAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &Address // Translated address
+ ) ) {
+
+ //
+ // It would be nice to return a better status here, but we only get
+ // TRUE/FALSE back from HalTranslateBusAddress.
+ //
+
+ return NDIS_STATUS_FAILURE;
+ }
+
+ if (addressSpace == 0) {
+
+ //
+ // memory space
+ //
+
+ *InitialMapping = MmMapIoSpace(
+ Address,
+ Length,
+ FALSE
+ );
+
+ if (*InitialMapping == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Mapped = TRUE;
+
+ } else {
+
+ //
+ // I/O space
+ //
+
+ *InitialMapping = (PVOID)Address.LowPart;
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+NTSTATUS
+EndMapping(
+ IN PVOID InitialMapping,
+ IN ULONG Length,
+ IN BOOLEAN Mapped
+ )
+
+/*++
+
+Routine Description:
+
+ This routine undoes the mapping of an address into virtual
+ space dependent on the bus number, etc.
+
+Arguments:
+
+ InitialMapping - The virtual address space to use when accessing the
+ address.
+ Length - Number of bytes from the base address to access.
+ Mapped - Do we need to call MmUnmapIoSpace.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ if (Mapped) {
+
+ //
+ // memory space
+ //
+
+ MmUnmapIoSpace(InitialMapping, Length);
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+VOID
+NdisImmediateReadPortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a UCHAR. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (UCHAR)0xFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (UCHAR)0xFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_UCHAR((PUCHAR)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(UCHAR),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateReadPortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PUSHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a USHORT. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (USHORT)0xFFFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (USHORT)0xFFFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_USHORT((PUSHORT)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(USHORT),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateReadPortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ OUT PULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from a port a ULONG. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject
+ ) == FALSE) {
+
+ *Data = (ULONG)0xFFFFFFFF;
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ *Data = (ULONG)0xFFFFFFFF;
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ *Data = READ_PORT_ULONG((PULONG)PortMapping);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(ULONG),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUchar(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a UCHAR. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(UCHAR),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_UCHAR((PUCHAR)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(UCHAR),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUshort(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN USHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a USHORT. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(USHORT),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_USHORT((PUSHORT)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(USHORT),
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWritePortUlong(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG Port,
+ IN ULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to a port a ULONG. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ Port - Port number to read from.
+
+ Data - Pointer to place to store the result.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID PortMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the port is available.
+ //
+ if (CheckPortUsage(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ Port,
+ sizeof(ULONG),
+ &PortMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from the port
+ //
+
+ WRITE_PORT_ULONG((PULONG)PortMapping, Data);
+
+ //
+ // End port mapping
+ //
+
+ EndMapping(
+ PortMapping,
+ sizeof(ULONG),
+ Mapped
+ );
+
+}
+
+BOOLEAN CheckMemoryUsage(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN ULONG Address,
+ IN ULONG Length,
+ IN PDRIVER_OBJECT DriverObject
+)
+/*++
+Routine Description:
+
+ This routine checks if a range of memory is currently in use somewhere
+ in the system via IoReportUsage -- which fails if there is a conflict.
+
+Arguments:
+
+ InterfaceType - The bus type (ISA, EISA)
+ BusNumber - Bus number in the system
+ Address - Starting Address of the memory to access.
+ Length - Length of memory from the base address to access.
+
+Return Value:
+
+ FALSE if there is a conflict, else TRUE
+
+--*/
+{
+ NTSTATUS NtStatus;
+ BOOLEAN Conflict;
+ NTSTATUS FirstNtStatus;
+ BOOLEAN FirstConflict;
+ PCM_RESOURCE_LIST Resources;
+
+ //
+ // Allocate space for resources
+ //
+
+ Resources = (PCM_RESOURCE_LIST)ExAllocatePool(
+ NonPagedPool,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
+ );
+
+ if (Resources == NULL) {
+
+ //
+ // Error out
+ //
+
+ return(FALSE);
+
+ }
+
+ Resources->Count = 1;
+ Resources->List[0].InterfaceType = InterfaceType;
+ Resources->List[0].BusNumber = BusNumber;
+ Resources->List[0].PartialResourceList.Version = 0;
+ Resources->List[0].PartialResourceList.Revision = 0;
+ Resources->List[0].PartialResourceList.Count = 1;
+
+ //
+ // Setup memory
+ //
+
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Type =
+ CmResourceTypeMemory;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition =
+ CmResourceShareDriverExclusive;
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].Flags =
+ CM_RESOURCE_MEMORY_READ_WRITE;
+#if !defined(BUILD_FOR_3_1)
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start.QuadPart = Address;
+#else
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Start =
+ RtlConvertUlongToLargeInteger((ULONG)(Address));
+#endif
+ Resources->List[0].PartialResourceList.PartialDescriptors[0].u.Memory.Length =
+ Length;
+
+
+ //
+ // Submit Resources
+ //
+
+ FirstNtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &FirstConflict
+ );
+
+ //
+ // Now clear it out
+ //
+ Resources->List[0].PartialResourceList.Count = 0;
+
+ NtStatus = IoReportResourceUsage(
+ NULL,
+ DriverObject,
+ Resources,
+ sizeof(CM_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
+ NULL,
+ NULL,
+ 0,
+ TRUE,
+ &Conflict
+ );
+
+ ExFreePool(Resources);
+
+ //
+ // Check for conflict.
+ //
+
+ if (FirstConflict || (FirstNtStatus != STATUS_SUCCESS)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+VOID
+NdisImmediateReadSharedMemory(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SharedMemoryAddress,
+ OUT PUCHAR Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine read into a buffer from shared ram. It does all the mapping,
+ etc, to do the read here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ SharedMemoryAddress - The physical address to read from.
+
+ Buffer - The buffer to read into.
+
+ Length - Length of the buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID MemoryMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available.
+ //
+ if (CheckMemoryUsage(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Read from memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(Buffer, MemoryMapping, Length);
+
+#else
+
+ READ_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ EndMapping(
+ MemoryMapping,
+ Length,
+ Mapped
+ );
+
+}
+
+VOID
+NdisImmediateWriteSharedMemory(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SharedMemoryAddress,
+ IN PUCHAR Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a buffer to shared ram. It does all the mapping,
+ etc, to do the write here.
+
+Arguments:
+
+ WrapperConfigurationContext - The handle used to call NdisOpenConfig.
+
+ SharedMemoryAddress - The physical address to write to.
+
+ Buffer - The buffer to write.
+
+ Length - Length of the buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ PDRIVER_OBJECT DriverObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DriverObject;
+ BOOLEAN Mapped;
+ PVOID MemoryMapping;
+ NDIS_INTERFACE_TYPE BusType;
+ ULONG BusNumber;
+ NTSTATUS Status;
+
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+ //
+ // Check that the memory is available.
+ //
+ if (CheckMemoryUsage(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ DriverObject
+ ) == FALSE) {
+
+ return;
+
+ }
+
+ //
+ // Map the space
+ //
+
+ Status = StartMapping(
+ BusType,
+ BusNumber,
+ SharedMemoryAddress,
+ Length,
+ &MemoryMapping,
+ &Mapped
+ );
+
+ if (!NT_SUCCESS(Status)) {
+
+ return;
+
+ }
+
+ //
+ // Write to memory
+ //
+
+#ifdef _M_IX86
+
+ memcpy(MemoryMapping, Buffer, Length);
+
+#else
+
+ WRITE_REGISTER_BUFFER_UCHAR(MemoryMapping,Buffer,Length);
+
+#endif
+
+ //
+ // End mapping
+ //
+
+ EndMapping(
+ MemoryMapping,
+ Length,
+ Mapped
+ );
+
+}
+
+#if !defined(BUILD_FOR_3_1)
+
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine reads from the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes read.
+
+--*/
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ ULONG BusNumber;
+ ULONG DataLength;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+#if DBG
+ {
+ NDIS_INTERFACE_TYPE BusType;
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ ASSERT(BusType == NdisInterfacePci);
+ }
+#endif
+
+ DataLength = HalGetBusDataByOffset(
+ PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+}
+
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This routine writes to the PCI configuration space a specified
+ length of bytes at a certain offset.
+
+Arguments:
+
+ WrapperConfigurationContext - Context passed to MacAddAdapter.
+
+ SlotNumber - The slot number of the device.
+
+ Offset - Offset to read from
+
+ Buffer - Place to store the bytes
+
+ Length - Number of bytes to read
+
+Return Value:
+
+ Returns the number of bytes written.
+
+--*/
+{
+ PRTL_QUERY_REGISTRY_TABLE KeyQueryTable =
+ (PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext;
+ ULONG BusNumber;
+ ULONG DataLength;
+
+ BusNumber = KeyQueryTable[3].DefaultLength;
+
+#if DBG
+ {
+ NDIS_INTERFACE_TYPE BusType;
+ BusType = (NDIS_INTERFACE_TYPE)(KeyQueryTable[3].DefaultType);
+ ASSERT(BusType == NdisInterfacePci);
+ }
+#endif
+
+ DataLength = HalSetBusDataByOffset(
+ PCIConfiguration,
+ BusNumber,
+ SlotNumber,
+ Buffer,
+ Offset,
+ Length
+ );
+
+ return(DataLength);
+}
+
+#else // !defined(BUILD_FOR_3_1)
+
+ULONG
+NdisImmediateReadPciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+ULONG
+NdisImmediateWritePciSlotInformation(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN ULONG SlotNumber,
+ IN ULONG Offset,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+{
+ return 0;
+}
+
+#endif // !defined(BUILD_FOR_3_1)
+
+
+CCHAR
+NdisSystemProcessorCount(
+ VOID
+ )
+{
+ return *KeNumberProcessors;
+}
+
+
+VOID
+NdisOverrideBusNumber(
+ IN NDIS_HANDLE WrapperConfigurationContext,
+ IN NDIS_HANDLE MiniportAdapterHandle OPTIONAL,
+ IN ULONG BusNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to override the BusNumber value retrieved
+ from the registry. It is expected to be used by PCI drivers
+ that discover that their adapter's bus number has changed.
+
+Arguments:
+
+ WrapperConfigurationContext - a handle pointing to an RTL_QUERY_REGISTRY_TABLE
+ that is set up for this driver's parameters.
+
+ MiniportAdapterHandle - points to the adapter block, if the calling
+ driver is a miniport. If the calling driver is a full MAC, this
+ parameter must be NULL.
+
+ BusNumber - the new bus number.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ((PRTL_QUERY_REGISTRY_TABLE)WrapperConfigurationContext)[3].DefaultLength = BusNumber;
+
+ if (Miniport != NULL) {
+ Miniport->BusNumber = BusNumber;
+ }
+
+ return;
+}
+