|
|
/*++
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);
}
|