windows-nt/Source/XPSP1/NT/net/ndis/sys/configm.c
2020-09-26 16:20:57 +08:00

3965 lines
119 KiB
C

/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
configm.c
Abstract:
NDIS wrapper functions for miniport configuration/initialization
Author:
Sean Selitrennikoff (SeanSe) 05-Oct-93
Jameel Hyder (JameelH) 01-Jun-95
Environment:
Kernel mode, FSD
Revision History:
--*/
#include <precomp.h>
#pragma hdrstop
//
// Define the module number for debug code.
//
#define MODULE_NUMBER MODULE_CONFIGM
NDIS_STATUS
NdisMRegisterMiniport(
IN NDIS_HANDLE NdisWrapperHandle,
IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
IN UINT CharacteristicsLength
)
/*++
Routine Description:
Used to register a Miniport driver with the wrapper.
Arguments:
Status - Status of the operation.
NdisWrapperHandle - Handle returned by NdisWInitializeWrapper.
MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table.
CharacteristicsLength - The length of MiniportCharacteristics.
Return Value:
None.
--*/
{
NDIS_STATUS Status;
PNDIS_M_DRIVER_BLOCK MiniBlock;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("==>NdisMRegisterMiniport: NdisWrapperHandle %p\n", NdisWrapperHandle));
Status = ndisRegisterMiniportDriver(NdisWrapperHandle,
MiniportCharacteristics,
CharacteristicsLength,
&MiniBlock);
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("NdisMRegisterMiniport: MiniBlock %p\n", MiniBlock));
ASSERT (CURRENT_IRQL < DISPATCH_LEVEL);
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("<==NdisMRegisterMiniport: MiniBlock %p, Status %lx\n", MiniBlock, Status));
return Status;
}
NDIS_STATUS
NdisIMRegisterLayeredMiniport(
IN NDIS_HANDLE NdisWrapperHandle,
IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
IN UINT CharacteristicsLength,
OUT PNDIS_HANDLE DriverHandle
)
/*++
Routine Description:
Used to register a layered Miniport driver with the wrapper.
Arguments:
Status - Status of the operation.
NdisWrapperHandle - Handle returned by NdisInitializeWrapper.
MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table.
CharacteristicsLength - The length of MiniportCharacteristics.
DriverHandle - Returns a handle which can be used to call NdisMInitializeDeviceInstance.
Return Value:
None.
--*/
{
NDIS_STATUS Status;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("==>NdisIMRegisterLayeredMiniport: NdisWrapperHandle %p\n", NdisWrapperHandle));
Status = ndisRegisterMiniportDriver(NdisWrapperHandle,
MiniportCharacteristics,
CharacteristicsLength,
DriverHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
PNDIS_M_DRIVER_BLOCK MiniBlock = (PNDIS_M_DRIVER_BLOCK)(*DriverHandle);
MiniBlock->Flags |= fMINIBLOCK_INTERMEDIATE_DRIVER;
INITIALIZE_MUTEX(&MiniBlock->IMStartRemoveMutex);
}
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("<==NdisIMRegisterLayeredMiniport: MiniBlock %p, Status %lx\n", *DriverHandle, Status));
return Status;
}
VOID
NdisIMDeregisterLayeredMiniport(
IN NDIS_HANDLE DriverHandle
)
{
//
// Do nothing for now
//
}
VOID
NdisIMAssociateMiniport(
IN NDIS_HANDLE DriverHandle,
IN NDIS_HANDLE ProtocolHandle
)
{
PNDIS_M_DRIVER_BLOCK MiniDriver = (PNDIS_M_DRIVER_BLOCK)DriverHandle;
PNDIS_PROTOCOL_BLOCK Protocol = (PNDIS_PROTOCOL_BLOCK)ProtocolHandle;
MiniDriver->AssociatedProtocol = Protocol;
Protocol->AssociatedMiniDriver = MiniDriver;
}
NDIS_STATUS
ndisRegisterMiniportDriver(
IN NDIS_HANDLE NdisWrapperHandle,
IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
IN UINT CharacteristicsLength,
OUT PNDIS_HANDLE DriverHandle
)
/*++
Routine Description:
Used to register a layered Miniport driver with the wrapper.
Arguments:
Status - Status of the operation.
NdisWrapperHandle - Handle returned by NdisWInitializeWrapper.
MiniportCharacteritics - The NDIS_MINIPORT_CHARACTERISTICS table.
CharacteristicsLength - The length of MiniportCharacteristics.
DriverHandle - Returns a handle which can be used to call NdisMInitializeDeviceInstance.
Return Value:
None.
--*/
{
PNDIS_M_DRIVER_BLOCK MiniBlock;
PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
UNICODE_STRING Us;
PWSTR pWch;
USHORT i, size;
NDIS_STATUS Status;
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("==>ndisRegisterMiniportDriver: NdisWrapperHandle %p\n", NdisWrapperHandle));
do
{
if (DriverInfo == NULL)
{
Status = NDIS_STATUS_FAILURE;
break;
}
//
// Check version numbers and CharacteristicsLength.
//
size = 0; // Used to indicate bad version below
if (MiniportCharacteristics->MinorNdisVersion == 0)
{
if (MiniportCharacteristics->MajorNdisVersion == 3)
{
size = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
}
else if (MiniportCharacteristics->MajorNdisVersion == 4)
{
size = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
}
else if (MiniportCharacteristics->MajorNdisVersion == 5)
{
size = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
}
}
else if (MiniportCharacteristics->MinorNdisVersion == 1)
{
if (MiniportCharacteristics->MajorNdisVersion == 5)
{
size = sizeof(NDIS51_MINIPORT_CHARACTERISTICS);
}
}
//
// Check that this is an NDIS 3.0/4.0/5.0 miniport.
//
if (size == 0)
{
Status = NDIS_STATUS_BAD_VERSION;
break;
}
//
// Check that CharacteristicsLength is enough.
//
if (CharacteristicsLength < size)
{
Status = NDIS_STATUS_BAD_CHARACTERISTICS;
break;
}
//
// Validate some stuff for NDIS 5.0
//
if (MiniportCharacteristics->MajorNdisVersion == 5)
{
if (MiniportCharacteristics->CoSendPacketsHandler != NULL)
{
if (MiniportCharacteristics->CoRequestHandler == NULL)
{
Status = NDIS_STATUS_BAD_CHARACTERISTICS;
break;
}
}
if (MiniportCharacteristics->MinorNdisVersion >= 1)
{
//
// for 5.1 miniports, having an AdapterShutdownHandler is mandatory
//
if (MiniportCharacteristics->AdapterShutdownHandler == NULL)
{
Status = NDIS_STATUS_BAD_CHARACTERISTICS;
break;
}
}
}
//
// Allocate memory for the NDIS MINIPORT block.
//
Status = IoAllocateDriverObjectExtension(DriverInfo->DriverObject, // DriverObject
(PVOID)NDIS_PNP_MINIPORT_DRIVER_ID,// MiniDriver magic number
sizeof(NDIS_M_DRIVER_BLOCK),
(PVOID)&MiniBlock);
if (!NT_SUCCESS(Status))
{
Status = NDIS_STATUS_RESOURCES;
break;
}
ZeroMemory(MiniBlock, sizeof(NDIS_M_DRIVER_BLOCK));
//
// Copy over the characteristics table.
//
CopyMemory(&MiniBlock->MiniportCharacteristics,
MiniportCharacteristics,
size);
//
// Check if the Driver is verifying
//
if (MmIsDriverVerifying(DriverInfo->DriverObject))
{
MiniBlock->Flags |= fMINIBLOCK_VERIFYING;
if (ndisFlags & NDIS_GFLAG_TRACK_MEM_ALLOCATION)
{
if (ndisDriverTrackAlloc == NULL)
{
ndisDriverTrackAlloc = MiniBlock;
}
else
{
//
// tracking memory alocation is allowed
// for one driver only. otherwise null out the
// global ndisDriverTrackAlloc to avoid confusion
// memory allocations will continue to get tracked
// but the result will not be very useful
//
ndisDriverTrackAlloc = NULL;
}
}
}
//
// No adapters yet registered for this Miniport.
//
MiniBlock->MiniportQueue = (PNDIS_MINIPORT_BLOCK)NULL;
//
// Set up the handlers for this driver. First setup Dummy handlers and then specific ones
//
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverInfo->DriverObject->MajorFunction[i] = ndisDummyIrpHandler;
}
//
// set up AddDevice handler for this miniport
//
DriverInfo->DriverObject->DriverExtension->AddDevice = ndisPnPAddDevice;
//
// Set up unload handler
//
DriverInfo->DriverObject->DriverUnload = ndisMUnload;
DriverInfo->DriverObject->MajorFunction[IRP_MJ_CREATE] = ndisCreateIrpHandler;
DriverInfo->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ndisDeviceControlIrpHandler;
DriverInfo->DriverObject->MajorFunction[IRP_MJ_CLOSE] = ndisCloseIrpHandler;
//
// setup a handler for PnP messages
//
DriverInfo->DriverObject->MajorFunction[IRP_MJ_PNP] = ndisPnPDispatch;
DriverInfo->DriverObject->MajorFunction[IRP_MJ_POWER] = ndisPowerDispatch;
DriverInfo->DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ndisWMIDispatch;
//
// Use this event to tell us when all adapters are removed from the mac
// during an unload
//
INITIALIZE_EVENT(&MiniBlock->MiniportsRemovedEvent);
// let the initial state stay reset, because the ref count
// going to zero is going to signal the event
MiniBlock->NdisDriverInfo = DriverInfo;
InitializeListHead(&MiniBlock->DeviceList);
ndisInitializeRef(&MiniBlock->Ref);
//
// Put Driver on global list.
//
PnPReferencePackage();
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
MiniBlock->NextDriver = ndisMiniDriverList;
ndisMiniDriverList = MiniBlock;
REF_NDIS_DRIVER_OBJECT();
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
PnPDereferencePackage();
*DriverHandle = MiniBlock;
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("<==ndisRegisterMiniportDriver: MiniBlock %p\n", MiniBlock));
return Status;
}
NDIS_STATUS
NdisMRegisterDevice(
IN NDIS_HANDLE NdisWrapperHandle,
IN PNDIS_STRING DeviceName,
IN PNDIS_STRING SymbolicName,
IN PDRIVER_DISPATCH * MajorFunctions,
OUT PDEVICE_OBJECT * pDeviceObject,
OUT NDIS_HANDLE * NdisDeviceHandle
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PDRIVER_OBJECT DriverObject;
PDEVICE_OBJECT DeviceObject;
PNDIS_M_DRIVER_BLOCK MiniBlock;
PNDIS_MINIPORT_BLOCK Miniport;
PNDIS_DEVICE_LIST DeviceList = NULL;
KIRQL OldIrql;
*pDeviceObject = NULL;
*NdisDeviceHandle = NULL;
//
// Check if the passed parameter is a NdisWrapperHandle or NdisMiniportHandle
//
if (DriverInfo->DriverObject == NULL)
{
Miniport = (PNDIS_MINIPORT_BLOCK)NdisWrapperHandle;
MiniBlock = Miniport->DriverHandle;
}
else
{
MiniBlock = (PNDIS_M_DRIVER_BLOCK)IoGetDriverObjectExtension(DriverInfo->DriverObject,
(PVOID)NDIS_PNP_MINIPORT_DRIVER_ID);
}
if (MiniBlock != NULL)
{
DriverObject = MiniBlock->NdisDriverInfo->DriverObject;
Status = IoCreateDevice(DriverObject, // DriverObject
sizeof(NDIS_WRAPPER_CONTEXT) +
sizeof(NDIS_DEVICE_LIST) + // DeviceExtension
DeviceName->Length + sizeof(WCHAR) +
SymbolicName->Length + sizeof(WCHAR),
DeviceName, // DeviceName
FILE_DEVICE_NETWORK, // DeviceType
FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics
FALSE, // Exclusive
&DeviceObject); // DeviceObject
if (NT_SUCCESS(Status))
{
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
Status = IoCreateSymbolicLink(SymbolicName, DeviceName);
if (!NT_SUCCESS(Status))
{
IoDeleteDevice(DeviceObject);
}
else
{
DeviceList = (PNDIS_DEVICE_LIST)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
RtlZeroMemory(DeviceList, sizeof(NDIS_DEVICE_LIST) +
DeviceName->Length + sizeof(WCHAR) +
SymbolicName->Length + sizeof(WCHAR));
DeviceList->Signature = (PVOID)CUSTOM_DEVICE_MAGIC_VALUE;
InitializeListHead(&DeviceList->List);
DeviceList->MiniBlock = MiniBlock;
DeviceList->DeviceObject = DeviceObject;
RtlCopyMemory(DeviceList->MajorFunctions,
MajorFunctions,
(IRP_MJ_MAXIMUM_FUNCTION+1)*sizeof(PDRIVER_DISPATCH));
DeviceList->DeviceName.Buffer = (PWCHAR)(DeviceList + 1);
DeviceList->DeviceName.Length = DeviceName->Length;
DeviceList->DeviceName.MaximumLength = DeviceName->Length + sizeof(WCHAR);
RtlCopyMemory(DeviceList->DeviceName.Buffer,
DeviceName->Buffer,
DeviceName->Length);
DeviceList->SymbolicLinkName.Buffer = (PWCHAR)((PUCHAR)DeviceList->DeviceName.Buffer + DeviceList->DeviceName.MaximumLength);
DeviceList->SymbolicLinkName.Length = SymbolicName->Length;
DeviceList->SymbolicLinkName.MaximumLength = SymbolicName->Length + sizeof(WCHAR);
RtlCopyMemory(DeviceList->SymbolicLinkName.Buffer,
SymbolicName->Buffer,
SymbolicName->Length);
PnPReferencePackage();
ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
InsertHeadList(&MiniBlock->DeviceList, &DeviceList->List);
RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
PnPDereferencePackage();
*pDeviceObject = DeviceObject;
*NdisDeviceHandle = DeviceList;
}
}
}
else
{
Status = NDIS_STATUS_NOT_SUPPORTED;
}
return Status;
}
NDIS_STATUS
NdisMDeregisterDevice(
IN NDIS_HANDLE NdisDeviceHandle
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PNDIS_DEVICE_LIST DeviceList = (PNDIS_DEVICE_LIST)NdisDeviceHandle;
PNDIS_M_DRIVER_BLOCK MiniBlock;
KIRQL OldIrql;
MiniBlock = DeviceList->MiniBlock;
PnPReferencePackage();
ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
RemoveEntryList(&DeviceList->List);
RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
PnPDereferencePackage();
IoDeleteSymbolicLink(&DeviceList->SymbolicLinkName);
IoDeleteDevice(DeviceList->DeviceObject);
return NDIS_STATUS_SUCCESS;
}
VOID
NdisMRegisterUnloadHandler(
IN NDIS_HANDLE NdisWrapperHandle,
IN PDRIVER_UNLOAD UnloadHandler
)
{
PNDIS_WRAPPER_HANDLE DriverInfo = (PNDIS_WRAPPER_HANDLE)NdisWrapperHandle;
PNDIS_M_DRIVER_BLOCK MiniBlock;
if (DriverInfo->DriverObject == NULL)
{
MiniBlock = (PNDIS_M_DRIVER_BLOCK)NdisWrapperHandle;
}
else
{
MiniBlock = (PNDIS_M_DRIVER_BLOCK)IoGetDriverObjectExtension(DriverInfo->DriverObject,
(PVOID)NDIS_PNP_MINIPORT_DRIVER_ID);
}
if (MiniBlock != NULL)
{
MiniBlock->UnloadHandler = UnloadHandler;
}
}
NDIS_STATUS
NdisIMDeInitializeDeviceInstance(
IN NDIS_HANDLE NdisMiniportHandle
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PNDIS_MINIPORT_BLOCK Miniport;
PNDIS_M_DRIVER_BLOCK MiniBlock;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("==>NdisIMDeInitializeDeviceInstance: Miniport %p\n", NdisMiniportHandle));
ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
Miniport = (PNDIS_MINIPORT_BLOCK)NdisMiniportHandle;
MiniBlock = Miniport->DriverHandle;
if (MINIPORT_INCREMENT_REF(Miniport))
{
ndisReferenceDriver(MiniBlock);
//
// for all practical purposes we want the same thing happens as in
// stopping the device, i.e. device objects remain and some certain fields that
// get initialized during AddDevice to be preserved.
//
Miniport->PnPDeviceState = NdisPnPDeviceStopped;
ndisPnPRemoveDevice(Miniport->DeviceObject, NULL);
Miniport->CurrentDevicePowerState = PowerDeviceUnspecified;
MINIPORT_DECREMENT_REF(Miniport);
ndisDereferenceDriver(MiniBlock, FALSE);
Status = NDIS_STATUS_SUCCESS;
}
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("<==NdisIMDeInitializeDeviceInstance: Miniport %p, Status %lx\n", NdisMiniportHandle, Status));
return Status;
}
VOID
ndisMFinishQueuedPendingOpen(
IN PNDIS_POST_OPEN_PROCESSING PostOpen
)
/*++
Routine Description:
Handles any pending NdisOpenAdapter() calls for miniports.
Arguments:
PostOpen: a tempoary structure to carry the open information around
Return Value:
Returns the status code of the open.
--*/
{
PNDIS_OPEN_BLOCK Open = PostOpen->Open;
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
PNDIS_AF_NOTIFY AfNotify = NULL;
NDIS_STATUS Status;
UINT OpenRef;
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>ndisMFinishQueuedPendingOpen: PostOpen %p\n", PostOpen));
PnPReferencePackage();
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
//
// If this is a binding that involves registration/open of address families, notify
//
ASSERT (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO) &&
(Open->ProtocolHandle->ProtocolCharacteristics.CoAfRegisterNotifyHandler != NULL));
Status = ndisCreateNotifyQueue(Miniport,
Open,
NULL,
&AfNotify);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
if (AfNotify != NULL)
{
//
// Notify existing clients of this registration
//
ndisNotifyAfRegistration(AfNotify);
}
FREE_POOL(PostOpen);
ndisDereferenceAfNotification(Open);
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
ndisMDereferenceOpen(Open);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==ndisMFinishQueuedPendingOpen: Open %p\n", Open));
}
NDIS_STATUS
NdisMRegisterIoPortRange(
OUT PVOID * PortOffset,
IN NDIS_HANDLE MiniportAdapterHandle,
IN UINT InitialPort,
IN UINT NumberOfPorts
)
/*++
Routine Description:
Sets up an IO port for operations.
Arguments:
PortOffset - The mapped port address the Miniport uses for NdisRaw functions.
MiniportAdapterHandle - Handle passed to Miniport Initialize.
InitialPort - Physical address of the starting port number.
NumberOfPorts - Number of ports to map.
Return Value:
None.
--*/
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
PHYSICAL_ADDRESS PortAddress;
PHYSICAL_ADDRESS InitialPortAddress;
ULONG addressSpace;
NDIS_STATUS Status;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor = NULL;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMRegisterIoPortRange: Miniport %p\n", Miniport));
// Miniport->InfoFlags |= NDIS_MINIPORT_USES_IO;
do
{
if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_REGISTER_IO))
{
#if DBG
DbgPrint("NdisMRegisterIoPortRange failed to verify miniport %p\n", Miniport);
#endif
Status = NDIS_STATUS_RESOURCES;
break;
}
InitialPortAddress.QuadPart = InitialPort;
#if !defined(_M_IX86)
Status = ndisTranslateResources(Miniport,
CmResourceTypePort,
InitialPortAddress,
&PortAddress,
&pResourceDescriptor);
if (Status != NDIS_STATUS_SUCCESS)
{
Status = NDIS_STATUS_FAILURE;
break;
}
if (pResourceDescriptor->Type == CmResourceTypeMemory)
addressSpace = 0;
else
addressSpace = -1;
if (addressSpace == 0)
{
//
// memory space
//
*(PortOffset) = (PULONG)MmMapIoSpace(PortAddress,
NumberOfPorts,
FALSE);
if (*(PortOffset) == (PULONG)NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
}
else
{
//
// I/O space
//
*(PortOffset) = ULongToPtr(PortAddress.LowPart);
}
#else // x86 platform
//
// make sure the port belongs to the device
//
Status = ndisTranslateResources(Miniport,
CmResourceTypePort,
InitialPortAddress,
&PortAddress,
&pResourceDescriptor);
if (Status != NDIS_STATUS_SUCCESS)
{
Status = NDIS_STATUS_FAILURE;
break;
}
if (pResourceDescriptor->Type == CmResourceTypeMemory)
{
//
// memory space
//
*(PortOffset) = (PULONG)MmMapIoSpace(PortAddress,
NumberOfPorts,
FALSE);
if (*(PortOffset) == (PULONG)NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
}
else
{
//
// I/O space
//
*(PortOffset) = (PULONG)PortAddress.LowPart;
}
#endif
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMRegisterIoPortRange: Miniport %p, Status %lx\n", Miniport, Status));
return Status;
}
VOID
NdisMDeregisterIoPortRange(
IN NDIS_HANDLE MiniportAdapterHandle,
IN UINT InitialPort,
IN UINT NumberOfPorts,
IN PVOID PortOffset
)
/*++
Routine Description:
Sets up an IO port for operations.
Arguments:
MiniportAdapterHandle - Handle passed to Miniport Initialize.
InitialPort - Physical address of the starting port number.
NumberOfPorts - Number of ports to map.
PortOffset - The mapped port address the Miniport uses for NdisRaw functions.
Return Value:
None.
--*/
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
PHYSICAL_ADDRESS PortAddress;
PHYSICAL_ADDRESS InitialPortAddress;
ULONG addressSpace;
CM_PARTIAL_RESOURCE_DESCRIPTOR Resource;
NDIS_STATUS Status;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMDeregisterIoPortRange: Miniport %p\n", Miniport));
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMDeregisterIoPortRange: Miniport %p\n", Miniport));
return;
}
NDIS_STATUS
NdisMMapIoSpace(
OUT PVOID * VirtualAddress,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
IN UINT Length
)
{
NDIS_STATUS Status;
ULONG addressSpace = 0;
PHYSICAL_ADDRESS PhysicalTemp;
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor = NULL;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("==>NdisMMapIoSpace\n"));
// Miniport->InfoFlags |= NDIS_MINIPORT_USES_MEMORY;
if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_MAP_IO_SPACE))
{
#if DBG
DbgPrint("NdisMMapIoSpace failed to verify miniport %p\n", Miniport);
#endif
*VirtualAddress = NULL;
return NDIS_STATUS_RESOURCES;
}
do
{
#if !defined(_M_IX86)
PhysicalTemp.HighPart = 0;
Status = ndisTranslateResources(Miniport,
CmResourceTypeMemory,
PhysicalAddress,
&PhysicalTemp,
&pResourceDescriptor);
if (Status != NDIS_STATUS_SUCCESS)
{
Status = NDIS_STATUS_FAILURE;
break;
}
if (pResourceDescriptor->Type == CmResourceTypeMemory)
addressSpace = 0;
else
addressSpace = -1;
#else
addressSpace = 0; // need to do MmMapIoSpace
Status = ndisTranslateResources(Miniport,
CmResourceTypeMemory,
PhysicalAddress,
&PhysicalTemp,
&pResourceDescriptor);
if (Status != NDIS_STATUS_SUCCESS)
{
Status = NDIS_STATUS_FAILURE;
break;
}
#endif
if (addressSpace == 0)
{
*VirtualAddress = MmMapIoSpace(PhysicalTemp, (Length), FALSE);
}
else
{
*VirtualAddress = ULongToPtr(PhysicalTemp.LowPart);
}
Status = NDIS_STATUS_SUCCESS;
if (*VirtualAddress == NULL)
{
Status = NDIS_STATUS_RESOURCES;
}
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMMapIoSpace: Miniport %p, Status %lx\n", MiniportAdapterHandle, Status));
return Status;
}
VOID
NdisMUnmapIoSpace(
IN NDIS_HANDLE MiniportAdapterHandle,
IN PVOID VirtualAddress,
IN UINT Length
)
{
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMUnmapIoSpace: Miniport %p\n", MiniportAdapterHandle));
#ifndef _ALPHA_
MmUnmapIoSpace(VirtualAddress, Length);
#endif
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMUnmapIoSpace: Miniport %p\n", MiniportAdapterHandle));
}
VOID
NdisMAllocateSharedMemory(
IN NDIS_HANDLE MiniportAdapterHandle,
IN ULONG Length,
IN BOOLEAN Cached,
OUT PVOID * VirtualAddress,
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
PDMA_ADAPTER SystemAdapterObject;
PNDIS_WRAPPER_CONTEXT WrapperContext;
PULONG Page;
ULONG Type;
PNDIS_SHARED_MEM_SIGNATURE pSharedMemSignature = NULL;
// Miniport->InfoFlags |= NDIS_MINIPORT_USES_SHARED_MEMORY;
SystemAdapterObject = Miniport->SystemAdapterObject;
WrapperContext = Miniport->WrapperContext;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMAllocateSharedMemory: Miniport %p, Length %lx\n", Miniport, Length));
PhysicalAddress->HighPart = PhysicalAddress->LowPart = 0;
if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_SHARED_MEM_ALLOC))
{
#if DBG
DbgPrint("NdisMAllocateSharedMemory failed to verify miniport %p\n", Miniport);
#endif
*VirtualAddress = NULL;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMAllocateSharedMemory: Miniport %p, Length %lx\n", Miniport, Length));
return;
}
if (Miniport->SystemAdapterObject == NULL)
{
*VirtualAddress = NULL;
return;
}
if (CURRENT_IRQL >= DISPATCH_LEVEL)
{
BAD_MINIPORT(Miniport, "Allocating Shared Memory at raised IRQL");
KeBugCheckEx(BUGCODE_ID_DRIVER,
(ULONG_PTR)Miniport,
Length,
0,
1);
}
//
// Compute allocation size by aligning to the proper boundary.
//
ASSERT(Length != 0);
Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1);
//
// Check to determine is there is enough room left in the current page
// to satisfy the allocation.
//
Type = Cached ? 1 : 0;
ExAcquireResourceExclusiveLite(&SharedMemoryResource, TRUE);
do
{
PALLOCATE_COMMON_BUFFER allocateCommonBuffer;
allocateCommonBuffer = *SystemAdapterObject->DmaOperations->AllocateCommonBuffer;
if (WrapperContext->SharedMemoryLeft[Type] < Length)
{
if ((Length + sizeof(NDIS_SHARED_MEM_SIGNATURE)) >= PAGE_SIZE)
{
//
// The allocation is greater than a page.
//
*VirtualAddress = allocateCommonBuffer(SystemAdapterObject,
Length,
PhysicalAddress,
Cached);
break;
}
//
// Allocate a new page for shared alocation.
//
WrapperContext->SharedMemoryPage[Type] =
allocateCommonBuffer(SystemAdapterObject,
PAGE_SIZE,
&WrapperContext->SharedMemoryAddress[Type],
Cached);
if (WrapperContext->SharedMemoryPage[Type] == NULL)
{
WrapperContext->SharedMemoryLeft[Type] = 0;
*VirtualAddress = NULL;
break;
}
//
// Initialize the reference count in the last ULONG of the page.
// Initialize the Tag in the second last ulong of the page
//
Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
pSharedMemSignature = (PNDIS_SHARED_MEM_SIGNATURE) ((PUCHAR)Page+ (PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE)));
pSharedMemSignature->Tag = NDIS_TAG_SHARED_MEMORY;
pSharedMemSignature->PageRef = 0;
WrapperContext->SharedMemoryLeft[Type] = PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE);
}
//
// Increment the reference count, set the address of the allocation,
// compute the physical address, and reduce the space remaining.
//
Page = (PULONG)WrapperContext->SharedMemoryPage[Type];
//
// First check whether Page is pointing to shared memory. Bugcheck to catch the driver
//
pSharedMemSignature = (PNDIS_SHARED_MEM_SIGNATURE) ((PUCHAR)Page+ (PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE)));
if (pSharedMemSignature->Tag != NDIS_TAG_SHARED_MEMORY)
{
ASSERT (pSharedMemSignature->Tag == NDIS_TAG_SHARED_MEMORY);
BAD_MINIPORT(Miniport, "Overwrote past allocated shared memory");
KeBugCheckEx(BUGCODE_ID_DRIVER,
(ULONG_PTR)Miniport,
(ULONG_PTR)Page,
(ULONG_PTR)WrapperContext,
(ULONG_PTR)pSharedMemSignature);
}
pSharedMemSignature->PageRef += 1;
*VirtualAddress = (PVOID)((PUCHAR)Page +
(PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE) - WrapperContext->SharedMemoryLeft[Type]));
PhysicalAddress->QuadPart = WrapperContext->SharedMemoryAddress[Type].QuadPart +
((ULONG_PTR)(*VirtualAddress) & (PAGE_SIZE - 1));
WrapperContext->SharedMemoryLeft[Type] -= Length;
} while (FALSE);
if (*VirtualAddress)
{
InterlockedIncrement(&Miniport->DmaAdapterRefCount);
}
ExReleaseResourceLite(&SharedMemoryResource);
#if DBG
if (*VirtualAddress == NULL)
{
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisMAllocateSharedMemory: Miniport %p, allocateCommonBuffer failed for %lx bytes\n", Miniport, Length));
}
#endif
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_64BITS_DMA) &&
(PhysicalAddress->HighPart > 0))
{
#if DBG
DbgPrint("NdisMAllocateSharedMemory: Miniport %p, allocateCommonBuffer returned a physical address > 4G for a"
" non-64bit DMA adapter. PhysAddress->HighPart = %p", Miniport, PhysicalAddress->HighPart);
#endif
ASSERT(PhysicalAddress->HighPart == 0);
}
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMAllocateSharedMemory: Miniport %p, Length %lx, Virtual Address %p\n", Miniport, Length, *VirtualAddress));
}
NDIS_STATUS
NdisMAllocateSharedMemoryAsync(
IN NDIS_HANDLE MiniportAdapterHandle,
IN ULONG Length,
IN BOOLEAN Cached,
IN PVOID Context
)
{
//
// Convert the handle to our internal structure.
//
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
PASYNC_WORKITEM pWorkItem = NULL;
// Miniport->InfoFlags |= NDIS_MINIPORT_USES_SHARED_MEMORY;
// Allocate a workitem
if ((Miniport->SystemAdapterObject != NULL) &&
(Miniport->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler != NULL))
{
pWorkItem = ALLOC_FROM_POOL(sizeof(ASYNC_WORKITEM), NDIS_TAG_ALLOC_SHARED_MEM_ASYNC);
}
if ((pWorkItem == NULL) ||
!MINIPORT_INCREMENT_REF(Miniport))
{
if (pWorkItem != NULL)
FREE_POOL(pWorkItem);
return NDIS_STATUS_FAILURE;
}
InterlockedIncrement(&Miniport->DmaAdapterRefCount);
// Initialize the workitem and queue it up to a worker thread
pWorkItem->Miniport = Miniport;
pWorkItem->Length = Length;
pWorkItem->Cached = Cached;
pWorkItem->Context = Context;
INITIALIZE_WORK_ITEM(&pWorkItem->ExWorkItem, ndisMQueuedAllocateSharedHandler, pWorkItem);
QUEUE_WORK_ITEM(&pWorkItem->ExWorkItem, CriticalWorkQueue);
return NDIS_STATUS_PENDING;
}
VOID
ndisMQueuedAllocateSharedHandler(
IN PASYNC_WORKITEM pWorkItem
)
{
KIRQL OldIrql;
// Allocate the memory
NdisMAllocateSharedMemory(pWorkItem->Miniport,
pWorkItem->Length,
pWorkItem->Cached,
&pWorkItem->VAddr,
&pWorkItem->PhyAddr);
//
// we shouldn't need to reference package here
//
ASSERT(ndisPkgs[NDSM_PKG].ReferenceCount > 0);
if (MINIPORT_TEST_FLAG(pWorkItem->Miniport, fMINIPORT_DESERIALIZE))
{
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
}
else
{
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(pWorkItem->Miniport, &OldIrql);
}
// Call the miniport back
(*pWorkItem->Miniport->DriverHandle->MiniportCharacteristics.AllocateCompleteHandler)(
pWorkItem->Miniport->MiniportAdapterContext,
pWorkItem->VAddr,
&pWorkItem->PhyAddr,
pWorkItem->Length,
pWorkItem->Context);
if (MINIPORT_TEST_FLAG(pWorkItem->Miniport, fMINIPORT_DESERIALIZE))
{
KeLowerIrql(OldIrql);
}
else
{
NDIS_RELEASE_MINIPORT_SPIN_LOCK(pWorkItem->Miniport, OldIrql);
}
ndisDereferenceDmaAdapter(pWorkItem->Miniport);
// Dereference the miniport
MINIPORT_DECREMENT_REF(pWorkItem->Miniport);
// And finally free the work-item
FREE_POOL(pWorkItem);
}
VOID
ndisFreeSharedMemory(
IN NDIS_HANDLE MiniportAdapterHandle,
IN ULONG Length,
IN BOOLEAN Cached,
IN PVOID VirtualAddress,
IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
PDMA_ADAPTER SystemAdapterObject;
PNDIS_WRAPPER_CONTEXT WrapperContext;
PULONG Page;
ULONG Type;
PNDIS_SHARED_MEM_SIGNATURE pSharedMemSignature = NULL;
PFREE_COMMON_BUFFER freeCommonBuffer;
//
// Get interesting information from the miniport.
//
SystemAdapterObject = Miniport->SystemAdapterObject;
WrapperContext = Miniport->WrapperContext;
if (SystemAdapterObject == NULL)
{
if (Miniport->SavedSystemAdapterObject)
SystemAdapterObject = Miniport->SavedSystemAdapterObject;
//
// Non-busmasters shouldn't call this routine.
//
ASSERT(SystemAdapterObject != NULL);
#if DBG
DbgPrint("Ndis: WARNING... Miniport %p freeing shared memory -after- freeing map registers.\n", Miniport);
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_VERIFYING) && (ndisFlags & NDIS_GFLAG_BREAK_ON_WARNING))
DbgBreakPoint();
#endif
Miniport->SystemAdapterObject = Miniport->SavedSystemAdapterObject;
}
freeCommonBuffer = *SystemAdapterObject->DmaOperations->FreeCommonBuffer;
//
// Compute allocation size by aligning to the proper boundary.
//
ASSERT(Length != 0);
Length = (Length + ndisDmaAlignment - 1) & ~(ndisDmaAlignment - 1);
//
// Free the specified memory.
//
ExAcquireResourceExclusiveLite(&SharedMemoryResource, TRUE);
if ((Length + sizeof(NDIS_SHARED_MEM_SIGNATURE)) >= PAGE_SIZE)
{
//
// The allocation is greater than a page free the page directly.
//
freeCommonBuffer(SystemAdapterObject,
Length,
PhysicalAddress,
VirtualAddress,
Cached);
}
else
{
//
// Decrement the reference count and if the result is zero, then free
// the page.
//
Page = (PULONG)((ULONG_PTR)VirtualAddress & ~(PAGE_SIZE - 1));
//
// First check whether Page is pointing to shared memory. Bugcheck to catch the driver
//
pSharedMemSignature = (PNDIS_SHARED_MEM_SIGNATURE) ((PUCHAR)Page + (PAGE_SIZE - sizeof(NDIS_SHARED_MEM_SIGNATURE)));
if (pSharedMemSignature->Tag != NDIS_TAG_SHARED_MEMORY)
{
ASSERT (pSharedMemSignature->Tag == NDIS_TAG_SHARED_MEMORY);
BAD_MINIPORT(Miniport, "Freeing shared memory not allocated");
KeBugCheckEx(BUGCODE_ID_DRIVER,
(ULONG_PTR)Miniport,
(ULONG_PTR)Page,
(ULONG_PTR)pSharedMemSignature,
(ULONG_PTR)VirtualAddress );
}
pSharedMemSignature->PageRef -= 1;
//
// If the references on the page have gone to zero then free the page
//
if (pSharedMemSignature->PageRef == 0)
{
//
// Compute the physical address of the page and free it.
//
PhysicalAddress.LowPart &= ~(PAGE_SIZE - 1);
freeCommonBuffer(SystemAdapterObject,
PAGE_SIZE,
PhysicalAddress,
Page,
Cached);
Type = Cached ? 1 : 0;
if ((PVOID)Page == WrapperContext->SharedMemoryPage[Type])
{
WrapperContext->SharedMemoryLeft[Type] = 0;
WrapperContext->SharedMemoryPage[Type] = NULL;
}
}
}
ndisDereferenceDmaAdapter(Miniport);
ExReleaseResourceLite(&SharedMemoryResource);
}
VOID
NdisMFreeSharedMemory(
IN NDIS_HANDLE MiniportAdapterHandle,
IN ULONG Length,
IN BOOLEAN Cached,
IN PVOID VirtualAddress,
IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
if (CURRENT_IRQL < DISPATCH_LEVEL)
{
ndisFreeSharedMemory(MiniportAdapterHandle,
Length,
Cached,
VirtualAddress,
PhysicalAddress);
}
else if (MINIPORT_INCREMENT_REF(Miniport))
{
PASYNC_WORKITEM pWorkItem = NULL;
// Allocate a work-item and queue it up to a worker thread
pWorkItem = ALLOC_FROM_POOL(sizeof(ASYNC_WORKITEM), NDIS_TAG_FREE_SHARED_MEM_ASYNC);
if (pWorkItem != NULL)
{
// Initialize the workitem and queue it up to a worker thread
pWorkItem->Miniport = Miniport;
pWorkItem->Length = Length;
pWorkItem->Cached = Cached;
pWorkItem->VAddr = VirtualAddress;
pWorkItem->PhyAddr = PhysicalAddress;
INITIALIZE_WORK_ITEM(&pWorkItem->ExWorkItem, ndisMQueuedFreeSharedHandler, pWorkItem);
QUEUE_WORK_ITEM(&pWorkItem->ExWorkItem, CriticalWorkQueue);
}
// What do we do now ?
}
}
VOID
ndisMQueuedFreeSharedHandler(
IN PASYNC_WORKITEM pWorkItem
)
{
// Free the memory
ndisFreeSharedMemory(pWorkItem->Miniport,
pWorkItem->Length,
pWorkItem->Cached,
pWorkItem->VAddr,
pWorkItem->PhyAddr);
// Dereference the miniport
MINIPORT_DECREMENT_REF(pWorkItem->Miniport);
// And finally free the work-item
FREE_POOL(pWorkItem);
}
NDIS_STATUS
NdisMRegisterDmaChannel(
OUT PNDIS_HANDLE MiniportDmaHandle,
IN NDIS_HANDLE MiniportAdapterHandle,
IN UINT DmaChannel,
IN BOOLEAN Dma32BitAddresses,
IN PNDIS_DMA_DESCRIPTION DmaDescription,
IN ULONG MaximumLength
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle);
NDIS_STATUS Status;
NDIS_INTERFACE_TYPE BusType;
ULONG BusNumber;
DEVICE_DESCRIPTION DeviceDescription;
PDMA_ADAPTER AdapterObject;
ULONG MapRegistersNeeded;
ULONG MapRegistersAllowed;
PNDIS_DMA_BLOCK DmaBlock;
KIRQL OldIrql;
NTSTATUS NtStatus;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMRegisterDmaChannel: Miniport %p\n", Miniport));
BusType = Miniport->BusType;
BusNumber = Miniport->BusNumber;
do
{
//
// Set up the device description; zero it out in case its
// size changes.
//
ZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
DeviceDescription.Master = MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER);
DeviceDescription.ScatterGather = MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER);
DeviceDescription.DemandMode = DmaDescription->DemandMode;
DeviceDescription.AutoInitialize = DmaDescription->AutoInitialize;
DeviceDescription.Dma32BitAddresses = Dma32BitAddresses;
DeviceDescription.BusNumber = Miniport->BusNumber;
DeviceDescription.DmaChannel = DmaChannel;
DeviceDescription.InterfaceType = 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 =
IoGetDmaAdapter(Miniport->PhysicalDeviceObject,
&DeviceDescription,
&MapRegistersAllowed);
if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersNeeded))
{
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate storage for our DMA block.
//
DmaBlock = (PNDIS_DMA_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_DMA_BLOCK), NDIS_TAG_DMA);
if (DmaBlock == (PNDIS_DMA_BLOCK)NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Use this event to tell us when ndisAllocationExecutionRoutine
// has been called.
//
INITIALIZE_EVENT(&DmaBlock->AllocationEvent);
//
// We save this to call IoFreeAdapterChannel later.
//
(PDMA_ADAPTER)DmaBlock->SystemAdapterObject = AdapterObject;
ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
PnPReferencePackage();
//
// Now allocate the adapter channel.
//
RAISE_IRQL_TO_DISPATCH(&OldIrql);
NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(AdapterObject,
Miniport->DeviceObject,
MapRegistersNeeded,
ndisDmaExecutionRoutine,
(PVOID)DmaBlock);
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
PnPDereferencePackage();
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
FREE_POOL(DmaBlock);
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// ndisDmaExecutionRoutine will set this event
// when it has been called.
//
NtStatus = WAIT_FOR_OBJECT(&DmaBlock->AllocationEvent, 0);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT_RAW(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
FREE_POOL(DmaBlock);
Status = NDIS_STATUS_RESOURCES;
break;
}
RESET_EVENT(&DmaBlock->AllocationEvent);
//
// We now have the DMA channel allocated, we are done.
//
DmaBlock->InProgress = FALSE;
*MiniportDmaHandle = (NDIS_HANDLE)DmaBlock;
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMRegisterDmaChannel: Miniport %p, Status %lx\n", Miniport, Status));
return Status;
}
VOID
NdisMDeregisterDmaChannel(
IN NDIS_HANDLE MiniportDmaHandle
)
{
KIRQL OldIrql;
PNDIS_DMA_BLOCK DmaBlock = (PNDIS_DMA_BLOCK)MiniportDmaHandle;
PPUT_DMA_ADAPTER putDmaAdapter;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMDeregisterDmaChannel\n"));
ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
PnPReferencePackage();
RAISE_IRQL_TO_DISPATCH(&OldIrql);
((PDMA_ADAPTER)DmaBlock->SystemAdapterObject)->DmaOperations->FreeAdapterChannel(DmaBlock->SystemAdapterObject);
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
putDmaAdapter = ((PDMA_ADAPTER)DmaBlock->SystemAdapterObject)->DmaOperations->PutDmaAdapter;
putDmaAdapter((PDMA_ADAPTER)DmaBlock->SystemAdapterObject);
PnPDereferencePackage();
FREE_POOL(DmaBlock);
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMDeregisterDmaChannel\n"));
}
NDIS_STATUS
NdisMAllocateMapRegisters(
IN NDIS_HANDLE MiniportAdapterHandle,
IN UINT DmaChannel,
IN NDIS_DMA_SIZE DmaSize,
IN ULONG BaseMapRegistersNeeded,
IN ULONG MaximumPhysicalMapping
)
/*++
Routine Description:
Allocates map registers for bus mastering devices.
Arguments:
MiniportAdapterHandle - Handle passed to MiniportInitialize.
BaseMapRegistersNeeded - The maximum number of base map registers needed
by the Miniport at any one time.
MaximumPhysicalMapping - Maximum length of a buffer that will have to be mapped.
Return Value:
None.
--*/
{
//
// Convert the handle to our internal structure.
//
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
//
// This is needed by HalGetAdapter.
//
DEVICE_DESCRIPTION DeviceDescription;
//
// Returned by HalGetAdapter.
//
ULONG MapRegistersAllowed;
//
// Returned by IoGetDmaAdapter.
//
PDMA_ADAPTER AdapterObject;
PALLOCATE_ADAPTER_CHANNEL allocateAdapterChannel;
PFREE_MAP_REGISTERS freeMapRegisters;
//
// Map registers needed per channel.
//
ULONG MapRegistersPerChannel;
NTSTATUS NtStatus;
KIRQL OldIrql;
USHORT i;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
BOOLEAN AllocationFailed;
KEVENT AllocationEvent;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMAllocateMapRegisters: Miniport %p, BaseMapRegistersNeeded %lx\n", Miniport, BaseMapRegistersNeeded));
ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
PnPReferencePackage();
// Miniport->InfoFlags |= NDIS_MINIPORT_USES_MAP_REGISTERS;
do
{
if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_MAP_REG_ALLOC))
{
#if DBG
DbgPrint("NdisMAllocateMapRegisters failed to verify miniport %p\n", Miniport);
#endif
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// 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 (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER))
{
Miniport->BaseMapRegistersNeeded = (USHORT)BaseMapRegistersNeeded;
Miniport->MaximumPhysicalMapping = MaximumPhysicalMapping;
//
// Allocate storage for holding the appropriate
// information for each map register.
//
Miniport->MapRegisters = NULL;
if (BaseMapRegistersNeeded > 0)
{
Miniport->MapRegisters = (PMAP_REGISTER_ENTRY)
ALLOC_FROM_POOL(sizeof(MAP_REGISTER_ENTRY) * BaseMapRegistersNeeded,
NDIS_TAG_MAP_REG);
if (Miniport->MapRegisters == (PMAP_REGISTER_ENTRY)NULL)
{
//
// Error out
//
NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
1,
0xFFFFFFFF);
Status = NDIS_STATUS_RESOURCES;
break;
}
}
//
// Use this event to tell us when ndisAllocationExecutionRoutine
// has been called.
//
Miniport->AllocationEvent = &AllocationEvent;
INITIALIZE_EVENT(&AllocationEvent);
//
// Set up the device description; zero it out in case its
// size changes.
//
ZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
DeviceDescription.Master = TRUE;
DeviceDescription.ScatterGather = TRUE;
DeviceDescription.BusNumber = Miniport->BusNumber;
DeviceDescription.DmaChannel = DmaChannel;
DeviceDescription.InterfaceType = Miniport->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 (DmaChannel > 4)
{
DeviceDescription.DmaWidth = Width16Bits;
}
else
{
DeviceDescription.DmaWidth = Width8Bits;
}
DeviceDescription.DmaSpeed = Compatible;
}
else if (DeviceDescription.InterfaceType == NdisInterfacePci)
{
if (DmaSize == NDIS_DMA_32BITS)
{
DeviceDescription.Dma32BitAddresses = TRUE;
}
else if (DmaSize == NDIS_DMA_64BITS)
{
DeviceDescription.Dma64BitAddresses = TRUE;
MINIPORT_SET_FLAG(Miniport, fMINIPORT_64BITS_DMA);
}
}
DeviceDescription.MaximumLength = MaximumPhysicalMapping;
//
// Determine how many map registers we need per channel.
//
MapRegistersPerChannel = ((MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
#if DBG
if (MapRegistersPerChannel > 16)
{
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_WARN,
("NdisMAllocateMapRegisters: Miniport %p, MaximumPhysicalMapping of 0x%lx\nwould require more than 16 MAP registers per channel, the call may fail\n",
Miniport, MaximumPhysicalMapping));
}
#endif
NDIS_WARN((Miniport->BaseMapRegistersNeeded * MapRegistersPerChannel > 0x40),
Miniport,
NDIS_GFLAG_WARN_LEVEL_0,
("ndisMInitializeAdapter: Miniport %p is asking for too many %ld > 64 map registers.\n",
Miniport, Miniport->BaseMapRegistersNeeded * MapRegistersPerChannel
));
//
// Get the adapter object.
//
AdapterObject =
IoGetDmaAdapter(Miniport->PhysicalDeviceObject, &DeviceDescription, &MapRegistersAllowed);
if ((AdapterObject == NULL) || (MapRegistersAllowed < MapRegistersPerChannel))
{
NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
1,
0xFFFFFFFF);
FREE_POOL(Miniport->MapRegisters);
Miniport->MapRegisters = NULL;
Status = NDIS_STATUS_RESOURCES;
if (AdapterObject != NULL)
{
RAISE_IRQL_TO_DISPATCH(&OldIrql);
((PDMA_ADAPTER)AdapterObject)->DmaOperations->PutDmaAdapter((PDMA_ADAPTER)AdapterObject);
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
}
break;
}
//
// We save this to call IoFreeMapRegisters later.
//
Miniport->SystemAdapterObject = AdapterObject;
Miniport->SavedSystemAdapterObject = NULL;
ASSERT(Miniport->DmaAdapterRefCount == 0);
InterlockedIncrement(&Miniport->DmaAdapterRefCount);
allocateAdapterChannel = *AdapterObject->DmaOperations->AllocateAdapterChannel;
freeMapRegisters = *AdapterObject->DmaOperations->FreeMapRegisters;
//
// Now loop, allocating an adapter channel each time, then
// freeing everything but the map registers.
//
AllocationFailed = FALSE;
for (i=0; i<Miniport->BaseMapRegistersNeeded; i++)
{
Miniport->CurrentMapRegister = i;
RAISE_IRQL_TO_DISPATCH(&OldIrql);
NtStatus = allocateAdapterChannel(AdapterObject,
Miniport->DeviceObject,
MapRegistersPerChannel,
ndisAllocationExecutionRoutine,
Miniport);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("AllocateAdapterChannel: %lx\n", NtStatus));
for (; i != 0; i--)
{
freeMapRegisters(Miniport->SystemAdapterObject,
Miniport->MapRegisters[i-1].MapRegister,
MapRegistersPerChannel);
}
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
1,
0xFFFFFFFF);
FREE_POOL(Miniport->MapRegisters);
Miniport->MapRegisters = NULL;
ndisDereferenceDmaAdapter(Miniport);
AllocationFailed = TRUE;
break;
}
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
//
// wait indefinitely for allocation routine to be called
//
NtStatus = WAIT_FOR_OBJECT(&AllocationEvent, 0);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
(" NDIS DMA AllocateAdapterChannel: %lx\n", NtStatus));
RAISE_IRQL_TO_DISPATCH(&OldIrql);
for (; i != 0; i--)
{
freeMapRegisters(Miniport->SystemAdapterObject,
Miniport->MapRegisters[i-1].MapRegister,
MapRegistersPerChannel);
}
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
1,
0xFFFFFFFF);
FREE_POOL(Miniport->MapRegisters);
Miniport->MapRegisters = NULL;
ndisDereferenceDmaAdapter(Miniport);
AllocationFailed = TRUE;
break;
}
RESET_EVENT(&AllocationEvent);
}
if (AllocationFailed)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
}
} while (FALSE);
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMAllocateMapRegisters: Miniport %p, Status %lx\n", Miniport, Status));
return Status;
}
VOID
NdisMFreeMapRegisters(
IN NDIS_HANDLE MiniportAdapterHandle
)
/*++
Routine Description:
Releases allocated map registers
Arguments:
MiniportAdapterHandle - Handle passed to MiniportInitialize.
Return Value:
None.
--*/
{
//
// Convert the handle to our internal structure.
//
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportAdapterHandle;
PFREE_MAP_REGISTERS freeMapRegisters;
KIRQL OldIrql;
ULONG i;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMFreeMapRegisters: Miniport %p\n", Miniport));
ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
PnPReferencePackage();
ASSERT(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER));
ASSERT(Miniport->MapRegisters != NULL);
ASSERT(Miniport->SystemAdapterObject != NULL);
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_BUS_MASTER) &&
(Miniport->MapRegisters != NULL))
{
ULONG MapRegistersPerChannel =
((Miniport->MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
freeMapRegisters = *Miniport->SystemAdapterObject->DmaOperations->FreeMapRegisters;
RAISE_IRQL_TO_DISPATCH(&OldIrql);
for (i = 0; i < Miniport->BaseMapRegistersNeeded; i++)
{
freeMapRegisters(Miniport->SystemAdapterObject,
Miniport->MapRegisters[i].MapRegister,
MapRegistersPerChannel);
}
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
//
// Map registers are allocated from non-paged pool.
// So this memory can be freed at DISPATCH
//
FREE_POOL(Miniport->MapRegisters);
Miniport->MapRegisters = NULL;
ndisDereferenceDmaAdapter(Miniport);
}
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMFreeMapRegisters: Miniport %p\n", Miniport));
}
ULONG
NdisMReadDmaCounter(
IN NDIS_HANDLE MiniportDmaHandle
)
/*++
Routine Description:
Reads the current value of the dma counter
Arguments:
MiniportDmaHandle - Handle for the DMA transfer.
Return Value:
current value of a DMA counter
--*/
{
return ((PDMA_ADAPTER)((PNDIS_DMA_BLOCK)(MiniportDmaHandle))->SystemAdapterObject)->DmaOperations->ReadDmaCounter(((PNDIS_DMA_BLOCK)(MiniportDmaHandle))->SystemAdapterObject);
}
VOID
ndisBugcheckHandler(
IN PNDIS_WRAPPER_CONTEXT WrapperContext,
IN ULONG Size
)
/*++
Routine Description:
This routine is called when a bugcheck occurs in the system.
Arguments:
Buffer -- Ndis wrapper context.
Size -- Size of wrapper context
Return Value:
Void.
--*/
{
PNDIS_MINIPORT_BLOCK Miniport;
if (Size == sizeof(NDIS_WRAPPER_CONTEXT))
{
Miniport = (PNDIS_MINIPORT_BLOCK)(WrapperContext + 1);
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SHUTTING_DOWN);
if (WrapperContext->ShutdownHandler != NULL)
{
WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
}
}
}
VOID
NdisMRegisterAdapterShutdownHandler(
IN NDIS_HANDLE MiniportHandle,
IN PVOID ShutdownContext,
IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler
)
/*++
Routine Description:
Deregisters an NDIS adapter.
Arguments:
MiniportHandle - The miniport.
ShutdownHandler - The Handler for the Adapter, to be called on shutdown.
Return Value:
none.
--*/
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("==>NdisMRegisterAdapterShutdownHandler: Miniport %p\n", Miniport));
if (WrapperContext->ShutdownHandler == NULL)
{
//
// Store information
//
WrapperContext->ShutdownHandler = ShutdownHandler;
WrapperContext->ShutdownContext = ShutdownContext;
//
// Register our shutdown handler for a bugcheck. (Note that we are
// already registered for shutdown notification.)
//
KeInitializeCallbackRecord(&WrapperContext->BugcheckCallbackRecord);
KeRegisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord, // callback record.
ndisBugcheckHandler, // callback routine.
WrapperContext, // free form buffer.
sizeof(NDIS_WRAPPER_CONTEXT), // buffer size.
"Ndis miniport"); // component id.
}
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("<==NdisMRegisterAdapterShutdownHandler: Miniport %p\n", Miniport));
}
VOID
NdisMDeregisterAdapterShutdownHandler(
IN NDIS_HANDLE MiniportHandle
)
/*++
Routine Description:
Arguments:
MiniportHandle - The miniport.
Return Value:
None.
--*/
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
PNDIS_WRAPPER_CONTEXT WrapperContext = Miniport->WrapperContext;
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("==>NdisMDeregisterAdapterShutdownHandler: Miniport %p\n", Miniport));
//
// Clear information
//
if (WrapperContext->ShutdownHandler != NULL)
{
KeDeregisterBugCheckCallback(&WrapperContext->BugcheckCallbackRecord);
WrapperContext->ShutdownHandler = NULL;
}
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
("<==NdisMDeregisterAdapterShutdownHandler: Miniport %p\n", Miniport));
}
NDIS_STATUS
NdisMPciAssignResources(
IN NDIS_HANDLE MiniportHandle,
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:
MiniportHandle - The miniport.
SlotNumber - Slot number of the device.
AssignedResources - The returned resources.
Return Value:
Status of the operation
--*/
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK) MiniportHandle;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMPciAssignResources: Miniport %p\n", Miniport));
NDIS_WARN(TRUE, Miniport, NDIS_GFLAG_WARN_LEVEL_3,
("NdisMPciAssignResources: Miniport %p should use NdisMQueryAdapterResources to get resources.\n", Miniport));
if ((Miniport->BusType != NdisInterfacePci) || (Miniport->AllocatedResources == NULL))
{
*AssignedResources = NULL;
DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMPciAssignResources: Miniport %p\n", Miniport));
return NDIS_STATUS_FAILURE;
}
*AssignedResources = &Miniport->AllocatedResources->List[0].PartialResourceList;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMPciAssignResources: Miniport %p\n", Miniport));
return NDIS_STATUS_SUCCESS;
}
VOID
NdisMQueryAdapterResources(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE WrapperConfigurationContext,
OUT PNDIS_RESOURCE_LIST ResourceList,
IN IN PUINT BufferSize
)
{
PDEVICE_OBJECT DeviceObject;
PNDIS_MINIPORT_BLOCK Miniport;
ULONG MemNeeded;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisMQueryAdapterResources: WrapperConfigurationContext %p\n", WrapperConfigurationContext));
DeviceObject = ((PNDIS_WRAPPER_CONFIGURATION_HANDLE)WrapperConfigurationContext)->DeviceObject;
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("NdisMQueryAdapterResources: Miniport %p\n", Miniport));
if (Miniport->AllocatedResources == NULL)
{
*Status = NDIS_STATUS_FAILURE;
}
else
{
MemNeeded = sizeof(CM_PARTIAL_RESOURCE_LIST) - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
+ Miniport->AllocatedResources->List[0].PartialResourceList.Count *
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
if (*BufferSize < MemNeeded)
{
*BufferSize = MemNeeded;
*Status = NDIS_STATUS_RESOURCES;
}
else
{
NdisMoveMemory(
ResourceList,
&Miniport->AllocatedResources->List[0].PartialResourceList,
MemNeeded
);
*Status = NDIS_STATUS_SUCCESS;
}
}
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisMQueryAdapterResources: Miniport %p, Status %lx\n", Miniport, *Status));
return;
}
NTSTATUS
ndisPnPAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
The AddDevice entry point is called by the Plug & Play manager
to inform the driver when a new device instance arrives that this
driver must control.
Arguments:
Return Value:
--*/
{
NTSTATUS NtStatus, Status;
PWSTR ExportData = NULL;
UNICODE_STRING ExportName, BusStr;
HANDLE Handle = NULL;
PUINT BusTypeData = NULL, CharacteristicsData = NULL;
ULONG ValueType;
RTL_QUERY_REGISTRY_TABLE LQueryTable[3];
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPnPAddDevice: DriverObject %p, PDO %p\n", DriverObject, PhysicalDeviceObject));
Status = STATUS_UNSUCCESSFUL;
do
{
#if NDIS_TEST_REG_FAILURE
NtStatus = STATUS_UNSUCCESSFUL;
#else
NtStatus = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
PLUGPLAY_REGKEY_DRIVER,
GENERIC_READ | MAXIMUM_ALLOWED,
&Handle);
#endif
#if !NDIS_NO_REGISTRY
if (!NT_SUCCESS(NtStatus))
break;
//
// 1.
// Switch to the Linkage key below this driver instance key
//
LQueryTable[0].QueryRoutine = NULL;
LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
LQueryTable[0].Name = L"Linkage";
//
// 2.
// Read the export and rootdevice keywords
//
LQueryTable[1].QueryRoutine = ndisReadParameter;
LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
LQueryTable[1].Name = L"Export";
LQueryTable[1].EntryContext = (PVOID)&ExportData;
LQueryTable[1].DefaultType = REG_NONE;
LQueryTable[2].QueryRoutine = NULL;
LQueryTable[2].Flags = 0;
LQueryTable[2].Name = NULL;
NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
Handle,
LQueryTable,
NULL,
NULL);
if (!NT_SUCCESS(NtStatus) || (ExportData == NULL))
break;
RtlInitUnicodeString(&ExportName, ExportData);
//
// 3.
// Read the bus-type and characteristics keywords
//
LQueryTable[0].QueryRoutine = ndisReadParameter;
LQueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
LQueryTable[0].Name = L"Characteristics";
LQueryTable[0].EntryContext = (PVOID)&CharacteristicsData;
LQueryTable[0].DefaultType = REG_NONE;
LQueryTable[1].QueryRoutine = NULL;
LQueryTable[1].Flags = 0;
LQueryTable[1].Name = NULL;
NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
Handle,
LQueryTable,
&ValueType,
NULL);
#else
if (NT_SUCCESS(NtStatus))
{
//
// 1.
// Switch to the Linkage key below this driver instance key
//
LQueryTable[0].QueryRoutine = NULL;
LQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
LQueryTable[0].Name = L"Linkage";
//
// 2.
// Read the export and rootdevice keywords
//
LQueryTable[1].QueryRoutine = ndisReadParameter;
LQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
LQueryTable[1].Name = L"Export";
LQueryTable[1].EntryContext = (PVOID)&ExportData;
LQueryTable[1].DefaultType = REG_NONE;
LQueryTable[2].QueryRoutine = NULL;
LQueryTable[2].Flags = 0;
LQueryTable[2].Name = NULL;
NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
Handle,
LQueryTable,
NULL,
NULL);
if (!NT_SUCCESS(NtStatus) || (ExportData == NULL))
break;
RtlInitUnicodeString(&ExportName, ExportData);
//
// 3.
// Read the bus-type and characteristics keywords
//
LQueryTable[0].QueryRoutine = ndisReadParameter;
LQueryTable[0].Flags = RTL_QUERY_REGISTRY_NOEXPAND;
LQueryTable[0].Name = L"Characteristics";
LQueryTable[0].EntryContext = (PVOID)&CharacteristicsData;
LQueryTable[0].DefaultType = REG_NONE;
LQueryTable[1].QueryRoutine = NULL;
LQueryTable[1].Flags = 0;
LQueryTable[1].Name = NULL;
NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
Handle,
LQueryTable,
&ValueType,
NULL);
}
else
{
ExportData = (PWSTR)ALLOC_FROM_POOL(sizeof(NDIS_DEFAULT_EXPORT_NAME),
NDIS_TAG_NAME_BUF);
if (ExportData == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory(ExportData, ndisDefaultExportName, sizeof(NDIS_DEFAULT_EXPORT_NAME));
RtlInitUnicodeString(&ExportName, ExportData);
}
#endif
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("ndisPnPAddDevice: Device: "));
DBGPRINT_UNICODE(DBG_COMP_PNP, DBG_LEVEL_INFO,
&ExportName);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("\n"));
Status = ndisAddDevice(DriverObject,
&ExportName,
PhysicalDeviceObject,
(CharacteristicsData != NULL) ? *CharacteristicsData : 0);
} while (FALSE);
if (Handle)
ZwClose(Handle);
if (ExportData != NULL)
FREE_POOL(ExportData);
if (CharacteristicsData != NULL)
FREE_POOL(CharacteristicsData);
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
(" ndisPnPAddDevice returning %lx\n", Status));
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPnPAddDevice: PDO %p\n", PhysicalDeviceObject));
return Status;
}
NDIS_STATUS
FASTCALL
ndisPnPStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp OPTIONAL
)
/*+++
Routine Description:
The handler for IRP_MN_START_DEVICE.
Arguments:
DeviceObject - The adapter's device object.
Irp - The IRP.
Adapter - a pointer to either AdapterBlock or MiniportBlock
Return Value:
NDIS_STATUS_SUCCESS if intializing the device was successful
Note: This routine can also be called from NdisImInitializeDeviceInstanceEx in which case
the Irp woud be NULL
---*/
{
PNDIS_MINIPORT_BLOCK Miniport;
PCM_RESOURCE_LIST AllocatedResources, AllocatedResourcesTranslated, pTempResources = NULL;
NDIS_STATUS Status;
PIO_STACK_LOCATION IrpSp;
NTSTATUS NtStatus;
ULONG MemNeeded = 0;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPnPStartDevice: DeviceObject\n", DeviceObject));
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("ndisPnPStartDevice: Miniport %p, ", Miniport));
DBGPRINT_UNICODE(DBG_COMP_PNP, DBG_LEVEL_INFO, Miniport->pAdapterInstanceName);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("\n"));
DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO, ("\n"));
if (Miniport->PnPDeviceState == NdisPnPDeviceStopped)
{
//
// re-initialize the miniport block structure without destroying what
// we set during AddDevice
//
ndisReinitializeMiniportBlock(Miniport);
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_RECEIVED_START);
}
do
{
if (Irp != NULL)
{
IrpSp = IoGetCurrentIrpStackLocation (Irp);
//
// save allocated resources with miniport/adapter structure
//
AllocatedResources = IrpSp->Parameters.StartDevice.AllocatedResources;
AllocatedResourcesTranslated = IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated;
if (AllocatedResources)
{
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_HARDWARE_DEVICE);
MemNeeded = sizeof(CM_RESOURCE_LIST) - sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
AllocatedResources->List[0].PartialResourceList.Count *
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
pTempResources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(2 * MemNeeded, NDIS_TAG_ALLOCATED_RESOURCES);
if (pTempResources == NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
NdisMoveMemory(pTempResources, AllocatedResources, MemNeeded);
NdisMoveMemory((PUCHAR)pTempResources + MemNeeded,
IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated, MemNeeded);
#if DBG
if ((ndisDebugLevel == DBG_LEVEL_INFO) &&
(ndisDebugSystems & DBG_COMP_PNP))
{
UINT j;
PCM_PARTIAL_RESOURCE_LIST pResourceList;
DbgPrint("ndisPnPStartDevice: Miniport %p, Non-Translated allocated resources\n", Miniport);
pResourceList = &(AllocatedResources->List[0].PartialResourceList);
for (j = 0; j < pResourceList->Count; j++)
{
switch (pResourceList->PartialDescriptors[j].Type)
{
case CmResourceTypePort:
DbgPrint("IO Port: %p, Length: %lx\n",
pResourceList->PartialDescriptors[j].u.Port.Start.LowPart,
pResourceList->PartialDescriptors[j].u.Port.Length);
break;
case CmResourceTypeMemory:
DbgPrint("Memory: %p, Length: %lx\n",
pResourceList->PartialDescriptors[j].u.Memory.Start.LowPart,
pResourceList->PartialDescriptors[j].u.Memory.Length);
break;
case CmResourceTypeInterrupt:
DbgPrint("Interrupt Level: %lx, Vector: %lx\n",
pResourceList->PartialDescriptors[j].u.Interrupt.Level,
pResourceList->PartialDescriptors[j].u.Interrupt.Vector);
break;
case CmResourceTypeDma:
DbgPrint("DMA Channel: %lx\n", pResourceList->PartialDescriptors[j].u.Dma.Channel);
break;
}
}
DbgPrint("ndisPnPStartDevice: Miniport %p, Translated allocated resources\n", Miniport);
pResourceList = &(AllocatedResourcesTranslated->List[0].PartialResourceList);
for (j = 0; j < pResourceList->Count; j++)
{
switch (pResourceList->PartialDescriptors[j].Type)
{
case CmResourceTypePort:
DbgPrint("IO Port: %p, Length: %lx\n",
pResourceList->PartialDescriptors[j].u.Port.Start.LowPart,
pResourceList->PartialDescriptors[j].u.Port.Length);
break;
case CmResourceTypeMemory:
DbgPrint("Memory: %p, Length: %lx\n",
pResourceList->PartialDescriptors[j].u.Memory.Start.LowPart,
pResourceList->PartialDescriptors[j].u.Memory.Length);
break;
case CmResourceTypeInterrupt:
DbgPrint("Interrupt Level: %lx, Vector: %lx\n",
pResourceList->PartialDescriptors[j].u.Interrupt.Level,
pResourceList->PartialDescriptors[j].u.Interrupt.Vector);
break;
case CmResourceTypeDma:
DbgPrint("DMA Channel: %lx\n", pResourceList->PartialDescriptors[j].u.Dma.Channel);
break;
}
}
}
#endif
} // end of if AllocatedResources != NULL
}
Miniport->AllocatedResources = pTempResources;
Miniport->AllocatedResourcesTranslated = (PCM_RESOURCE_LIST)((PUCHAR)pTempResources + MemNeeded);
Status = ndisInitializeAdapter(Miniport->DriverHandle,
DeviceObject,
Miniport->pAdapterInstanceName,
Miniport->DeviceContext);
if (Status == NDIS_STATUS_SUCCESS)
{
Miniport->PnPDeviceState = NdisPnPDeviceStarted;
NdisSetEvent(&Miniport->OpenReadyEvent);
KeQueryTickCount(&Miniport->NdisStats.StartTicks);
}
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPnPStartDevice: Miniport %p\n", Miniport));
return Status;
}
NTSTATUS
ndisQueryReferenceBusInterface(
IN PDEVICE_OBJECT PnpDeviceObject,
OUT PBUS_INTERFACE_REFERENCE* pBusInterface
)
/*++
Routine Description:
Queries the bus for the standard information interface.
Arguments:
PnpDeviceObject -
Contains the next device object on the Pnp stack.
PhysicalDeviceObject -
Contains the physical device object which was passed to the FDO during
the Add Device.
BusInterface -
The place in which to return the pointer to the Reference interface.
Return Value:
Returns STATUS_SUCCESS if the interface was retrieved, else an error.
--*/
{
NTSTATUS Status;
KEVENT Event;
IO_STATUS_BLOCK IoStatusBlock;
PIRP Irp;
PIO_STACK_LOCATION IrpStackNext;
PAGED_CODE();
*pBusInterface = (PBUS_INTERFACE_REFERENCE)ALLOC_FROM_POOL(sizeof(BUS_INTERFACE_REFERENCE), NDIS_TAG_BUS_INTERFACE);
if (*pBusInterface == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// There is no file object associated with this Irp, so the event may be located
// on the stack as a non-object manager object.
//
INITIALIZE_EVENT(&Event);
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
PnpDeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock);
if (Irp != NULL)
{
Irp->RequestorMode = KernelMode;
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IrpStackNext = IoGetNextIrpStackLocation(Irp);
//
// Create an interface query out of the Irp.
//
IrpStackNext->MinorFunction = IRP_MN_QUERY_INTERFACE;
IrpStackNext->Parameters.QueryInterface.InterfaceType = (GUID*)&REFERENCE_BUS_INTERFACE;
IrpStackNext->Parameters.QueryInterface.Size = sizeof(**pBusInterface);
IrpStackNext->Parameters.QueryInterface.Version = BUS_INTERFACE_REFERENCE_VERSION;
IrpStackNext->Parameters.QueryInterface.Interface = (PINTERFACE)*pBusInterface;
IrpStackNext->Parameters.QueryInterface.InterfaceSpecificData = NULL;
Status = IoCallDriver(PnpDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
//
// This waits using KernelMode, so that the stack, and therefore the
// event on that stack, is not paged out.
//
WAIT_FOR_OBJECT(&Event, NULL);
Status = IoStatusBlock.Status;
}
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(Status))
{
FREE_POOL(*pBusInterface);
*pBusInterface = NULL;
}
return Status;
}
NTSTATUS
ndisAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING pExportName,
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN ULONG Characteristics
)
/*++
Routine Description:
The AddDevice entry point is called by the Plug & Play manager
to inform the driver when a new device instance arrives that this
driver must control.
Arguments:
Return Value:
--*/
{
PDEVICE_OBJECT NextDeviceObject = NULL;
NTSTATUS NtStatus, Status = STATUS_UNSUCCESSFUL;
PDEVICE_OBJECT DevicePtr = NULL;
PNDIS_MINIPORT_BLOCK Miniport;
UNICODE_STRING us;
PWCHAR pPath;
PNDIS_M_DRIVER_BLOCK MiniBlock, TmpMiniBlock;
UINT NumComponents;
LONG Size;
BOOLEAN FreeDevice = FALSE;
PCM_RESOURCE_LIST pResourceList;
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisAddDevice: PDO %p\n", PhysicalDeviceObject));
PnPReferencePackage();
do
{
MiniBlock = (PNDIS_M_DRIVER_BLOCK)IoGetDriverObjectExtension(DriverObject,
(PVOID)NDIS_PNP_MINIPORT_DRIVER_ID);
{
//
// check to make sure the mini block is on our queue
//
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
TmpMiniBlock = ndisMiniDriverList;
while (TmpMiniBlock)
{
if (TmpMiniBlock == MiniBlock)
break;
TmpMiniBlock = TmpMiniBlock->NextDriver;
}
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
ASSERT(TmpMiniBlock == MiniBlock);
if (TmpMiniBlock != MiniBlock)
{
#if TRACK_UNLOAD
DbgPrint("ndisAddDevice: AddDevice called with a MiniBlock that is not on ndisMiniDriverList\n");
KeBugCheckEx(BUGCODE_ID_DRIVER,
(ULONG_PTR)MiniBlock,
(ULONG_PTR)DriverObject,
0,
0);
#endif
break;
}
}
//
// create DeviceObject and Miniport/Adapter structure now,
// we will set a few field here and the rest will be set during
// processing IRP_MN_START_DEVICE and InitializeAdapter call.
//
// Note: We need the device-name field double null terminated.
//
Size = sizeof(NDIS_MINIPORT_BLOCK) +
sizeof(NDIS_WRAPPER_CONTEXT) +
pExportName->Length + sizeof(WCHAR) + sizeof(WCHAR);
NtStatus = IoCreateDevice(DriverObject,
Size,
pExportName,
FILE_DEVICE_PHYSICAL_NETCARD,
FILE_DEVICE_SECURE_OPEN,
FALSE, // exclusive flag
&DevicePtr);
if(!NT_SUCCESS(NtStatus))
break;
DevicePtr->Flags &= ~DO_DEVICE_INITIALIZING;
DevicePtr->Flags |= DO_DIRECT_IO;
PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
FreeDevice = TRUE;
//
// Mark the device as being pageable.
//
DevicePtr->Flags |= DO_POWER_PAGABLE;
//
// Attach our FDO to the PDO. This routine will return the top most
// device that is attached to the PDO or the PDO itself if no other
// device objects have attached to it.
//
NextDeviceObject = IoAttachDeviceToDeviceStack(DevicePtr, PhysicalDeviceObject);
ZeroMemory(DevicePtr->DeviceExtension, Size);
Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DevicePtr->DeviceExtension + 1);
Miniport->Signature = (PVOID)MINIPORT_DEVICE_MAGIC_VALUE;
Miniport->DriverHandle = MiniBlock;
//
// initialize OpenReady event in case we get an open request before start IRP
//
NdisInitializeEvent(&Miniport->OpenReadyEvent);
INITIALIZE_SPIN_LOCK(&Miniport->Lock);
#if CHECK_TIMER
if (Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
INITIALIZE_SPIN_LOCK(&Miniport->TimerQueueLock);
#endif
Miniport->PrimaryMiniport = Miniport;
Miniport->PnPDeviceState = NdisPnPDeviceAdded;
Miniport->PhysicalDeviceObject = PhysicalDeviceObject;
Miniport->DeviceObject = DevicePtr;
Miniport->NextDeviceObject = NextDeviceObject;
Miniport->WrapperContext = DevicePtr->DeviceExtension;
InitializeListHead(&Miniport->PacketList);
//
// intialize the reference and set it to 0; we will increment it
// in ndisMinitializeAdapter
//
ndisInitializeULongRef(&Miniport->Ref);
Miniport->Ref.ReferenceCount = 0;
#ifdef TRACK_MINIPORT_REFCOUNTS
M_LOG_MINIPORT_SET_REF(Miniport, 0);
#endif
//
// Read the characteristics. This determines if the device is hidden or not (from device-manager)
//
if (Characteristics & 0x08)
{
//
// Bit 0x08 is NCF_HIDDEN
//
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_HIDDEN);
}
if (Characteristics & 0x02)
{
//
// Bit 0x02 is NCF_SOFTWARE_ENUMERATED
//
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_SWENUM);
}
//
// MiniportName must follow the MINIPORT_BLOCK.
//
ndisSetDeviceNames(pExportName,
&Miniport->MiniportName,
&Miniport->BaseName,
(PUCHAR)Miniport + sizeof(NDIS_MINIPORT_BLOCK));
NtStatus = ndisCreateAdapterInstanceName(&Miniport->pAdapterInstanceName,
PhysicalDeviceObject);
if (!NT_SUCCESS(NtStatus))
{
break;
}
Miniport->InstanceNumber = (USHORT)InterlockedIncrement(&ndisInstanceNumber);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("ndisAddDevice: Miniport %p, ", Miniport));
DBGPRINT_UNICODE(DBG_COMP_PNP, DBG_LEVEL_INFO,
Miniport->pAdapterInstanceName);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO, ("\n"));
if (Characteristics & 0x02)
{
PBUS_INTERFACE_REFERENCE BusInterface = NULL;
Status = ndisQueryReferenceBusInterface(PhysicalDeviceObject, &BusInterface);
if (NT_SUCCESS(Status))
{
Miniport->BusInterface = BusInterface;
}
else
{
ASSERT(BusInterface == NULL);
break;
}
}
//
// create a security descriptor for the device
//
Status = ndisCreateSecurityDescriptor(Miniport->DeviceObject,
&Miniport->SecurityDescriptor,
TRUE);
if (!NT_SUCCESS(Status))
{
FREE_POOL(Miniport->pAdapterInstanceName);
Status = STATUS_UNSUCCESSFUL;
break;
}
Status = STATUS_SUCCESS;
//
// Don't want to free up the device object.
//
FreeDevice = FALSE;
} while (FALSE);
if (FreeDevice)
{
//
// if device is created it is also attached
//
if (NextDeviceObject)
IoDetachDevice(NextDeviceObject);
IoDeleteDevice(DevicePtr);
DevicePtr = NULL;
}
if (DevicePtr && (NT_SUCCESS(Status)))
{
//
// if DevicePtr is not NULL, we do have a valid
// miniport. queue the miniport on global miniport queue
//
ACQUIRE_SPIN_LOCK(&ndisMiniportListLock, &OldIrql);
Miniport->NextGlobalMiniport = ndisMiniportList;
ndisMiniportList = Miniport;
RELEASE_SPIN_LOCK(&ndisMiniportListLock, OldIrql);
}
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisAddDevice: Miniport %p\n", Miniport));
return Status;
}
VOID
ndisSetDeviceNames(
IN PNDIS_STRING ExportName,
OUT PNDIS_STRING DeviceName,
OUT PNDIS_STRING BaseName,
IN PUCHAR Buffer
)
{
PNDIS_STRING BindPath;
PWSTR pComp, p;
USHORT i;
NDIS_STRING Str, SubStr;
DeviceName->Buffer = (PWSTR)Buffer;
DeviceName->Length = ExportName->Length;
DeviceName->MaximumLength = DeviceName->Length + sizeof(WCHAR);
RtlUpcaseUnicodeString(DeviceName,
ExportName,
FALSE);
//
// ExportName is in the form of \Device\<AdapterName>
// Extract BaseName which is the name w/o the "\Device\"
//
BaseName->Buffer = DeviceName->Buffer + (ndisDeviceStr.Length/sizeof(WCHAR));
BaseName->Length = DeviceName->Length - ndisDeviceStr.Length;
BaseName->MaximumLength = BaseName->Length + sizeof(WCHAR);
}
NTSTATUS
FASTCALL
ndisPnPQueryStopDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status;
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPnPQueryStopDevice: Miniport %p\n", Miniport));
do
{
if (Miniport->PnPCapabilities & NDIS_DEVICE_NOT_STOPPABLE)
{
Status = STATUS_UNSUCCESSFUL;
break;
}
//
// query_stop and stop are not reported to the user mode
// so we have to protect ourselves against cases that apps
// may have pending IO against the miniport
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
if (Miniport->UserModeOpenReferences != 0)
{
Status = STATUS_UNSUCCESSFUL;
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
break;
}
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
//
// for now do the same as query remove
//
Status = ndisPnPQueryRemoveDevice(DeviceObject, Irp);
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPnPQueryStopDevice: Miniport %p\n", Miniport));
return Status;
}
NTSTATUS
FASTCALL
ndisPnPCancelStopDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPnPCancelStopDevice\n"));
//
// for now do the same as cancel remove
//
Status = ndisPnPCancelRemoveDevice(DeviceObject, Irp);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPnPCancelStopDevice\n"));
return Status;
}
NTSTATUS
FASTCALL
ndisPnPStopDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPnPStopDevice\n"));
//
// do the same as remove
//
Status = ndisPnPRemoveDevice(DeviceObject, Irp);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPnPStopDevice\n"));
return Status;
}
NTSTATUS
FASTCALL
ndisPnPQueryRemoveDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
NTSTATUS Status = STATUS_SUCCESS;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPnPQueryRemoveDevice: Miniport %p, UserModeOpenReferences %lx\n", Miniport, Miniport->UserModeOpenReferences));
do
{
//
// If this was the network card used in a remote boot, then we
// can't remove it.
//
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_NETBOOT_CARD))
{
Status = STATUS_UNSUCCESSFUL;
break;
}
Status = ndisPnPNotifyAllTransports(Miniport,
NetEventQueryRemoveDevice,
NULL,
0);
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPnPQueryRemoveDevice: Miniport %p, Status 0x%x\n", Miniport, Status));
return Status;
}
NTSTATUS
FASTCALL
ndisPnPCancelRemoveDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
NTSTATUS Status = NDIS_STATUS_SUCCESS;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPnPCancelRemoveDevice: Miniport %p\n", Miniport));
Status = ndisPnPNotifyAllTransports(Miniport,
NetEventCancelRemoveDevice,
NULL,
0);
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPnPCancelRemoveDevice: Miniport %p\n", Miniport));
return STATUS_SUCCESS;
}
NTSTATUS
FASTCALL
ndisPnPRemoveDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp OPTIONAL
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
NTSTATUS Status = NDIS_STATUS_SUCCESS;
PNDIS_OPEN_BLOCK Open, NextOpen;
NDIS_BIND_CONTEXT UnbindContext;
KIRQL OldIrql;
BOOLEAN fAcquiredImMutex = FALSE;
PKMUTEX pIMStartRemoveMutex = NULL;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisPnPRemoveDevice: Miniport %p\n", Miniport));
PnPReferencePackage();
//
// there are three different cases that we can get a remove request
// a: the request is coming from PnP manager in response to a user mode
// app. In this case, the remove has been proceeded by a query remove
// which we happily failed if there was any legacy protocol bound to
// the adapter
//
// b. the request is coming from PnP manager because Starting the device failed
// in this case (hopefully) there is no binding at all. in this case it is not
// proceeded by query_remove and neet not be. we don't have any protocol bound
// to the adapter to worry about
//
// c. or it can come in response to a surprise style removal in which case we are
// hosed anyway. sending query_remove to protocols does not do any good
//
do
{
PNDIS_M_DRIVER_BLOCK MiniBlock;
PNDIS_MINIPORT_BLOCK TmpMiniport;
//
// find the miniport on driver queue
//
MiniBlock = Miniport->DriverHandle;
if (MiniBlock == NULL)
break;
//
// Intermediate drivers could be in the middle of initialization through the
// NdisIMInitializeDeviceInstance Code path. We need to synchronize
//
if (MiniBlock->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER)
{
pIMStartRemoveMutex = &MiniBlock->IMStartRemoveMutex;
WAIT_FOR_OBJECT(pIMStartRemoveMutex, NULL);
fAcquiredImMutex = TRUE;
}
ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
for (TmpMiniport = MiniBlock->MiniportQueue;
TmpMiniport != NULL;
TmpMiniport = TmpMiniport->NextMiniport)
{
if (TmpMiniport == Miniport)
{
break;
}
}
RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
if ((TmpMiniport != Miniport) || (Miniport->Ref.Closing == TRUE))
{
break;
}
ndisReferenceDriver(MiniBlock);
NdisResetEvent(&Miniport->OpenReadyEvent);
//
// Notify WMI of adapter removal.
//
if (Miniport->pAdapterInstanceName != NULL)
{
PWNODE_SINGLE_INSTANCE wnode;
PUCHAR ptmp;
NTSTATUS NtStatus;
ndisSetupWmiNode(Miniport,
Miniport->pAdapterInstanceName,
Miniport->MiniportName.Length + sizeof(USHORT),
(PVOID)&GUID_NDIS_NOTIFY_ADAPTER_REMOVAL,
&wnode);
if (wnode != NULL)
{
//
// Save the number of elements in the first ULONG.
//
ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
*((PUSHORT)ptmp) = Miniport->MiniportName.Length;
//
// Copy the data after the number of elements.
//
RtlCopyMemory(ptmp + sizeof(USHORT),
Miniport->MiniportName.Buffer,
Miniport->MiniportName.Length);
//
// Indicate the event to WMI. WMI will take care of freeing
// the WMI struct back to pool.
//
NtStatus = IoWMIWriteEvent(wnode);
if (!NT_SUCCESS(NtStatus))
{
DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
("ndisPnPRemoveDevice: Failed to indicate adapter removal\n"));
FREE_POOL(wnode);
}
}
}
//
// this will take care of closing all the bindings
//
ndisCloseMiniportBindings(Miniport);
if (Miniport->pIrpWaitWake)
{
if (IoCancelIrp(Miniport->pIrpWaitWake))
{
DBGPRINT_RAW(DBG_COMP_PM, DBG_LEVEL_INFO,
("ndisPnPRemoveDevice: Miniport %p, Successfully canceled wake irp\n", Miniport));
}
}
//
// get rid of wakeup patterns set on the miniport
//
{
PSINGLE_LIST_ENTRY Link;
PNDIS_PACKET_PATTERN_ENTRY pPatternEntry;
while (Miniport->PatternList.Next != NULL)
{
Link = PopEntryList(&Miniport->PatternList);
pPatternEntry = CONTAINING_RECORD(Link, NDIS_PACKET_PATTERN_ENTRY, Link);
//
// Free the memory taken by the pattern.
//
FREE_POOL(pPatternEntry);
}
}
//
// and this one will take care of the rest!
// we call this function even if the device has already been halted by
// ndisPMHaltMiniport. because that functions does not clean up everything.
// ndisMHaltMiniport will check for PM_HALTED flag and avoid re-doing what PMHalt
// has already done.
//
ndisMHaltMiniport(Miniport);
//
// Free the media-request structure, if present
//
if (Miniport->MediaRequest != NULL)
{
FREE_POOL(Miniport->MediaRequest);
Miniport->MediaRequest = NULL;
}
ndisDereferenceDriver(MiniBlock, FALSE);
{
UNICODE_STRING DeviceName, UpcaseDeviceName;
UNICODE_STRING SymbolicLink;
NTSTATUS NtStatus;
WCHAR SymLnkBuf[128];
SymbolicLink.Buffer = SymLnkBuf;
SymbolicLink.Length = 0;
SymbolicLink.MaximumLength = sizeof(SymLnkBuf);
RtlCopyUnicodeString(&SymbolicLink, &ndisDosDevicesStr);
RtlAppendUnicodeStringToString(&SymbolicLink,
&Miniport->BaseName);
NtStatus = IoDeleteSymbolicLink(&SymbolicLink);
if (!NT_SUCCESS(NtStatus))
{
#if DBG
DbgPrint("ndisPnPRemoveDevice: deleting symbolic link name failed for miniport %p, SymbolicLinkName %p, NtStatus %lx\n",
Miniport, &SymbolicLink, NtStatus);
#endif
}
}
} while (FALSE);
if(fAcquiredImMutex == TRUE)
{
RELEASE_MUTEX(pIMStartRemoveMutex);
}
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisPnPRemoveDevice: Miniport %p\n", Miniport));
return Status;
}
VOID
FASTCALL
ndisReinitializeMiniportBlock(
IN PNDIS_MINIPORT_BLOCK Miniport
)
{
PDEVICE_OBJECT PhysicalDeviceObject, DeviceObject, NextDeviceObject;
PNDIS_M_DRIVER_BLOCK MiniBlock;
PNDIS_MINIPORT_BLOCK NextGlobalMiniport;
PNDIS_MINIPORT_BLOCK PrimaryMiniport;
UNICODE_STRING BaseName, MiniportName;
PUNICODE_STRING InstanceName;
PNDIS_BIND_PATHS BindPaths;
PVOID WrapperContext;
NDIS_HANDLE DeviceContext;
ULONG PnPCapabilities;
ULONG FlagsToSave = 0;
ULONG PnPFlagsToSave = 0;
DEVICE_POWER_STATE CurrentDevicePowerState;
PVOID BusInterface;
USHORT InstanceNumber;
PSECURITY_DESCRIPTOR SecurityDescriptor;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisReinitializeMiniportBlock: Miniport %p\n", Miniport));
PhysicalDeviceObject = Miniport->PhysicalDeviceObject;
DeviceObject= Miniport->DeviceObject;
NextDeviceObject = Miniport->NextDeviceObject;
MiniBlock = Miniport->DriverHandle;
WrapperContext = Miniport->WrapperContext;
BaseName = Miniport->BaseName;
MiniportName = Miniport->MiniportName;
InstanceName = Miniport->pAdapterInstanceName;
DeviceContext = Miniport->DeviceContext;
BindPaths = Miniport->BindPaths;
PnPCapabilities = Miniport->PnPCapabilities;
PnPFlagsToSave = Miniport->PnPFlags & (fMINIPORT_RECEIVED_START |
fMINIPORT_SWENUM |
fMINIPORT_HIDDEN |
fMINIPORT_HARDWARE_DEVICE |
fMINIPORT_NDIS_WDM_DRIVER |
fMINIPORT_FILTER_IM
);
FlagsToSave = Miniport->Flags & fMINIPORT_REQUIRES_MEDIA_POLLING;
CurrentDevicePowerState = Miniport->CurrentDevicePowerState;
NextGlobalMiniport = Miniport->NextGlobalMiniport;
PrimaryMiniport = Miniport->PrimaryMiniport;
InstanceNumber = Miniport->InstanceNumber;
BusInterface = Miniport->BusInterface;
SecurityDescriptor = Miniport->SecurityDescriptor;
ZeroMemory(Miniport, FIELD_OFFSET(NDIS_MINIPORT_BLOCK, OpenReadyEvent));
ZeroMemory((PUCHAR)Miniport +
FIELD_OFFSET(NDIS_MINIPORT_BLOCK, OpenReadyEvent) +
sizeof(Miniport->OpenReadyEvent),
sizeof(NDIS_MINIPORT_BLOCK) -
FIELD_OFFSET(NDIS_MINIPORT_BLOCK, OpenReadyEvent) -
sizeof(Miniport->OpenReadyEvent));
//
// restore what we saved
//
Miniport->PnPDeviceState = NdisPnPDeviceAdded;
Miniport->Signature = (PVOID)MINIPORT_DEVICE_MAGIC_VALUE;
Miniport->DriverHandle = MiniBlock;
INITIALIZE_SPIN_LOCK(&Miniport->Lock);
#if CHECK_TIMER
if (Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
INITIALIZE_SPIN_LOCK(&Miniport->TimerQueueLock);
#endif
Miniport->PhysicalDeviceObject = PhysicalDeviceObject;
Miniport->DeviceObject = DeviceObject;
Miniport->NextDeviceObject = NextDeviceObject;
Miniport->WrapperContext = WrapperContext;
Miniport->BaseName = BaseName;
Miniport->MiniportName = MiniportName;
Miniport->pAdapterInstanceName = InstanceName;
Miniport->DeviceContext = DeviceContext;
Miniport->BindPaths = BindPaths;
Miniport->PnPCapabilities = PnPCapabilities;
Miniport->Flags = FlagsToSave;
Miniport->PnPFlags = PnPFlagsToSave;
Miniport->CurrentDevicePowerState = CurrentDevicePowerState;
Miniport->NextGlobalMiniport = NextGlobalMiniport;
Miniport->PrimaryMiniport = PrimaryMiniport;
Miniport->InstanceNumber = InstanceNumber;
Miniport->BusInterface = BusInterface;
InitializeListHead(&Miniport->PacketList);
Miniport->FirstPendingPacket = NULL;
if (MiniBlock->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER)
{
MINIPORT_SET_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER);
}
Miniport->SecurityDescriptor = SecurityDescriptor;
DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisReinitializeMiniportBlock: Miniport %p\n", Miniport));
}
EXPORT
VOID
NdisMGetDeviceProperty(
IN NDIS_HANDLE MiniportAdapterHandle,
IN OUT PDEVICE_OBJECT * PhysicalDeviceObject OPTIONAL,
IN OUT PDEVICE_OBJECT * FunctionalDeviceObject OPTIONAL,
IN OUT PDEVICE_OBJECT * NextDeviceObject OPTIONAL,
IN OUT PCM_RESOURCE_LIST * AllocatedResources OPTIONAL,
IN OUT PCM_RESOURCE_LIST * AllocatedResourcesTranslated OPTIONAL
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
//
// very likely this is a NDIS_WDM driver.
//
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HARDWARE_DEVICE))
{
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_NDIS_WDM_DRIVER);
}
if (ARGUMENT_PRESENT(PhysicalDeviceObject))
{
*PhysicalDeviceObject = Miniport->PhysicalDeviceObject;
}
if (ARGUMENT_PRESENT(FunctionalDeviceObject))
{
*FunctionalDeviceObject = Miniport->DeviceObject;
}
if (ARGUMENT_PRESENT(NextDeviceObject))
{
*NextDeviceObject = Miniport->NextDeviceObject;
}
if (ARGUMENT_PRESENT(AllocatedResources))
{
*AllocatedResources = Miniport->AllocatedResources;
}
if (ARGUMENT_PRESENT(AllocatedResourcesTranslated))
{
*AllocatedResourcesTranslated = Miniport->AllocatedResourcesTranslated;
}
return;
}
NTSTATUS
ndisWritePnPCapabilities(
IN PNDIS_MINIPORT_BLOCK Miniport,
IN ULONG PnPCapabilities
)
{
NTSTATUS RegistryStatus;
HANDLE Handle, RootHandle;
OBJECT_ATTRIBUTES ObjAttr;
UNICODE_STRING Root={0, 0, NULL};
do
{
#if NDIS_TEST_REG_FAILURE
RegistryStatus = STATUS_UNSUCCESSFUL;
RootHandle = NULL;
#else
RegistryStatus = IoOpenDeviceRegistryKey(Miniport->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DRIVER,
GENERIC_WRITE | MAXIMUM_ALLOWED,
&RootHandle);
#endif
if (!NT_SUCCESS(RegistryStatus))
{
break;
}
InitializeObjectAttributes(&ObjAttr,
&Root,
OBJ_CASE_INSENSITIVE,
RootHandle,
NULL);
RegistryStatus = ZwOpenKey(&Handle,
GENERIC_READ | MAXIMUM_ALLOWED,
&ObjAttr);
if (NT_SUCCESS(RegistryStatus))
{
RegistryStatus = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
Handle,
L"PnPCapabilities",
REG_DWORD,
&PnPCapabilities,
sizeof(ULONG));
ZwClose(Handle);
}
ZwClose(RootHandle);
} while (FALSE);
return RegistryStatus;
}
NDIS_STATUS
NdisMRemoveMiniport(
IN NDIS_HANDLE MiniportHandle
)
/*++
Routine Description:
Miniports call this routine to signal a device failure.
in response, ndis will ask PnP to send a REMOVE IRP for this device
Arguments:
MiniportHandle - Miniport
Return Value:
always successful
--*/
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportHandle;
MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_DEVICE_FAILED);
IoInvalidateDeviceState(Miniport->PhysicalDeviceObject);
return(NDIS_STATUS_SUCCESS);
}
PNDIS_MINIPORT_BLOCK
ndisFindMiniportOnGlobalList(
IN PNDIS_STRING DeviceName
)
/*++
Routine Description:
Find the Miniport with a matching device name on ndisMiniportList.
Arguments:
Return Value:
a pointer to MiniportBlock if found. NULL otherwise
--*/
{
KIRQL OldIrql;
PNDIS_MINIPORT_BLOCK Miniport;
NDIS_STRING UpcaseDevice;
PWSTR pwch;
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("==>ndisFindMiniportOnGlobalList: DeviceName %p\n", DeviceName));
//
// First we need to upcase the device-name before checking
//
UpcaseDevice.Length = DeviceName->Length;
UpcaseDevice.MaximumLength = DeviceName->Length + sizeof(WCHAR);
UpcaseDevice.Buffer = ALLOC_FROM_POOL(UpcaseDevice.MaximumLength, NDIS_TAG_STRING);
if ((pwch = UpcaseDevice.Buffer) == NULL)
{
return NULL;
}
RtlUpcaseUnicodeString(&UpcaseDevice, DeviceName, FALSE);
ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
PnPReferencePackage();
ACQUIRE_SPIN_LOCK(&ndisMiniportListLock, &OldIrql);
for (Miniport = ndisMiniportList;
Miniport != NULL;
Miniport = Miniport->NextGlobalMiniport)
{
if (NDIS_EQUAL_UNICODE_STRING(&UpcaseDevice, &Miniport->MiniportName))
{
break;
}
}
RELEASE_SPIN_LOCK(&ndisMiniportListLock, OldIrql);
PnPDereferencePackage();
FREE_POOL(pwch);
DBGPRINT(DBG_COMP_PNP, DBG_LEVEL_INFO,
("<==ndisFindMiniportOnGlobalList: Miniport %p\n", Miniport));
return Miniport;
}
ULONG
NdisMGetDmaAlignment(
IN NDIS_HANDLE MiniportAdapterHandle
)
{
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
ASSERT(CURRENT_IRQL < DISPATCH_LEVEL);
ASSERT(Miniport->SystemAdapterObject != NULL);
if (Miniport->SystemAdapterObject)
{
return (Miniport->SystemAdapterObject->DmaOperations->GetDmaAlignment(Miniport->SystemAdapterObject));
}
else
{
return 0;
}
}
ULONG
NdisGetSharedDataAlignment(
VOID
)
{
return KeGetRecommendedSharedDataAlignment();
}
VOID
ndisDereferenceDmaAdapter(
IN PNDIS_MINIPORT_BLOCK Miniport
)
{
PDMA_ADAPTER DmaAdapter;
PPUT_DMA_ADAPTER putDmaAdapter;
LONG DmaAdapterRefCount;
KIRQL OldIrql;
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
DmaAdapterRefCount = InterlockedDecrement(&Miniport->DmaAdapterRefCount);
ASSERT(DmaAdapterRefCount >= 0);
if (DmaAdapterRefCount == 0)
{
//
// free the dma adapter
//
DmaAdapter = Miniport->SystemAdapterObject;
ASSERT(DmaAdapter != NULL);
if (DmaAdapter != NULL)
{
Miniport->SavedSystemAdapterObject = Miniport->SystemAdapterObject;
putDmaAdapter = *DmaAdapter->DmaOperations->PutDmaAdapter;
putDmaAdapter(DmaAdapter);
Miniport->SystemAdapterObject = NULL;
}
if (Miniport->SGListLookasideList)
{
ExDeleteNPagedLookasideList(Miniport->SGListLookasideList);
FREE_POOL(Miniport->SGListLookasideList);
Miniport->SGListLookasideList = NULL;
}
if (Miniport->DmaResourcesReleasedEvent != NULL)
{
SET_EVENT(Miniport->DmaResourcesReleasedEvent);
}
}
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
}