You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
732 lines
18 KiB
732 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pnp.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the IRP_MJ_PNP IRP processing routines for the
|
|
Plug and Play Memory driver. Dispatch routines are invoked through
|
|
tables located at the bottom of the module.
|
|
|
|
Author:
|
|
|
|
Dave Richards (daveri) 16-Aug-1999
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pnpmem.h"
|
|
|
|
NTSTATUS
|
|
PmPassIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmPnpDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmDeferProcessing(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmStartDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmQueryRemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmRemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmCancelRemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmQueryStopDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmCancelStopDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmQueryCapabilities(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PmSurpriseRemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, PmPassIrp)
|
|
#pragma alloc_text(PAGE, PmPnpDispatch)
|
|
#pragma alloc_text(PAGE, PmDeferProcessing)
|
|
#pragma alloc_text(PAGE, PmStartDevice)
|
|
#pragma alloc_text(PAGE, PmQueryRemoveDevice)
|
|
#pragma alloc_text(PAGE, PmRemoveDevice)
|
|
#pragma alloc_text(PAGE, PmCancelRemoveDevice)
|
|
#pragma alloc_text(PAGE, PmQueryStopDevice)
|
|
#pragma alloc_text(PAGE, PmCancelStopDevice)
|
|
#pragma alloc_text(PAGE, PmSurpriseRemoveDevice)
|
|
#pragma alloc_text(PAGE, PmQueryCapabilities)
|
|
#endif
|
|
|
|
PDRIVER_DISPATCH PmPnpDispatchTable[];
|
|
extern ULONG PmPnpDispatchTableSize;
|
|
|
|
NTSTATUS
|
|
PmPassIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
|
|
return IoCallDriver(deviceExtension->AttachedDevice, Irp);
|
|
}
|
|
|
|
NTSTATUS
|
|
PmPnpDispatch(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles IRP_MJ_PNP IRPs for FDOs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the FDO for which this IRP applies.
|
|
|
|
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
BOOLEAN isRemoveDevice;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get a pointer to our stack location and take appropriate action based
|
|
// on the minor function.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
IoAcquireRemoveLock(&deviceExtension->RemoveLock, (PVOID) Irp);
|
|
|
|
isRemoveDevice = irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE;
|
|
|
|
if ((irpSp->MinorFunction < PmPnpDispatchTableSize) &&
|
|
PmPnpDispatchTable[irpSp->MinorFunction]) {
|
|
|
|
status =
|
|
PmPnpDispatchTable[irpSp->MinorFunction](DeviceObject,
|
|
Irp
|
|
);
|
|
} else {
|
|
status = PmPassIrp(DeviceObject, Irp);
|
|
}
|
|
|
|
if (!isRemoveDevice) {
|
|
IoReleaseRemoveLock(&deviceExtension->RemoveLock, (PVOID) Irp);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmPnpCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to defer processing of an IRP until drivers
|
|
lower in the stack including the bus driver have done their
|
|
processing.
|
|
|
|
This routine triggers the event to indicate that processing of the
|
|
irp can now continue.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the FDO for which this IRP applies.
|
|
|
|
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
|
|
{
|
|
KeSetEvent((PKEVENT) Context, EVENT_INCREMENT, FALSE);
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmDeferProcessing(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to defer processing of an IRP until drivers
|
|
lower in the stack including the bus driver have done their
|
|
processing.
|
|
|
|
This routine uses an IoCompletion routine along with an event to
|
|
wait until the lower level drivers have completed processing of
|
|
the irp.
|
|
|
|
Arguments:
|
|
|
|
Parent - FDO extension for the FDO devobj in question
|
|
|
|
Irp - Pointer to the IRP_MJ_PNP IRP to defer
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
KEVENT event;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
//
|
|
// Set our completion routine
|
|
//
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,
|
|
PmPnpCompletion,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
status = IoCallDriver(deviceExtension->AttachedDevice, Irp);
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmStartDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function handles IRP_MN_START_DEVICE IRPs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The functional device object.
|
|
|
|
Irp - The I/O request packet.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION irpSp;
|
|
PPM_RANGE_LIST RangeList;
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
POWER_STATE power;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
status = PmDeferProcessing(DeviceObject, Irp);
|
|
if (!NT_SUCCESS(status)) {
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
PmDumpOsMemoryRanges(L"Before Start");
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
ASSERT(deviceExtension->RangeList == NULL);
|
|
|
|
if (irpSp->Parameters.StartDevice.AllocatedResources) {
|
|
RangeList = PmCreateRangeListFromCmResourceList(
|
|
irpSp->Parameters.StartDevice.AllocatedResources
|
|
);
|
|
if (RangeList == NULL) {
|
|
//
|
|
// The memory allocation failure here is more serious than
|
|
// is intially obvious. If we fail this allocation, we're
|
|
// going to get removed from the stack before we find out
|
|
// if the OS knows about this memory. If the OS knows
|
|
// about this memory already, then ejecting the PDO would
|
|
// cause the memory underneath the OS to disappear.
|
|
// Better to be on the stack, but not have added any
|
|
// memory then to be off the stack and leave a dangerous
|
|
// situation.
|
|
//
|
|
// Only solution is to arbitrarily fail
|
|
// IRP_MN_QUERY_REMOVE.
|
|
//
|
|
deviceExtension->FailQueryRemoves = TRUE;
|
|
}
|
|
} else {
|
|
RangeList = NULL;
|
|
}
|
|
|
|
PmTrimReservedMemory(deviceExtension, &RangeList);
|
|
|
|
PmDebugDumpRangeList(PNPMEM_MEMORY, "Memory Ranges to be added:\n",
|
|
RangeList);
|
|
if (deviceExtension->FailQueryRemoves) {
|
|
PmPrint((DPFLTR_WARNING_LEVEL | PNPMEM_MEMORY, "PNPMEM device can't be removed\n"));
|
|
}
|
|
|
|
if (RangeList != NULL) {
|
|
|
|
(VOID) PmAddPhysicalMemory(DeviceObject, RangeList);
|
|
deviceExtension->RangeList = RangeList;
|
|
}
|
|
|
|
power.DeviceState = PowerDeviceD0;
|
|
PoSetPowerState(DeviceObject, DevicePowerState, power);
|
|
deviceExtension->PowerState = PowerDeviceD0;
|
|
|
|
PmDumpOsMemoryRanges(L"After Start ");
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmQueryRemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function handles IRP_MN_QUERY_REMOVE_DEVICE IRPs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The functional device object.
|
|
|
|
Irp - The I/O request packet.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
if (!MemoryRemovalSupported) {
|
|
PmPrint((DPFLTR_WARNING_LEVEL | PNPMEM_MEMORY,
|
|
"QueryRemove vetoed because memory removal is not supported\n"));
|
|
status = STATUS_UNSUCCESSFUL;
|
|
} else if (deviceExtension->FailQueryRemoves) {
|
|
PmPrint((DPFLTR_WARNING_LEVEL | PNPMEM_MEMORY,
|
|
"QueryRemove vetoed because removing this memory device may contain special memory\n"));
|
|
status = STATUS_UNSUCCESSFUL;
|
|
} else if (deviceExtension->RangeList != NULL) {
|
|
status = PmRemovePhysicalMemory(deviceExtension->RangeList);
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// Some ranges may have been removed, before failure. Add
|
|
// them back. Should be low-cost due to optimizations in
|
|
// PmAddPhysicalMemory.
|
|
//
|
|
|
|
(VOID) PmAddPhysicalMemory(DeviceObject, deviceExtension->RangeList);
|
|
}
|
|
} else {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
Irp->IoStatus.Status = status;
|
|
if (NT_SUCCESS(status)) {
|
|
return PmPassIrp(DeviceObject, Irp);
|
|
} else {
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
PmRemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function handles IRP_MN_REMOVE_DEVICE IRPs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The functional device object.
|
|
|
|
Irp - The I/O request packet.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
PPM_RANGE_LIST RangeList;
|
|
POWER_STATE power;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
if ((deviceExtension->Flags & DF_SURPRISE_REMOVED) == 0) {
|
|
power.DeviceState = PowerDeviceD3;
|
|
PoSetPowerState(DeviceObject, DevicePowerState, power);
|
|
deviceExtension->PowerState = PowerDeviceD0;
|
|
|
|
if (deviceExtension->RangeList != NULL) {
|
|
status = PmRemovePhysicalMemory(deviceExtension->RangeList);
|
|
ASSERT(status == STATUS_SUCCESS);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
status = PmPassIrp(DeviceObject, Irp);
|
|
|
|
IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, (PVOID) Irp);
|
|
|
|
IoDetachDevice(deviceExtension->AttachedDevice);
|
|
deviceExtension->AttachedDevice = NULL;
|
|
|
|
if (deviceExtension->RangeList != NULL) {
|
|
PmFreeRangeList(deviceExtension->RangeList);
|
|
deviceExtension->RangeList = NULL;
|
|
}
|
|
|
|
IoDeleteDevice(DeviceObject);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmCancelRemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function handles IRP_MN_CANCEL_REMOVE_DEVICE IRPs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The functional device object.
|
|
|
|
Irp - The I/O request packet.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
(VOID) PmDeferProcessing(DeviceObject, Irp);
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
if (deviceExtension->RangeList != NULL) {
|
|
(VOID) PmAddPhysicalMemory(DeviceObject, deviceExtension->RangeList);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmQueryStopDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function handles IRP_MN_QUERY_STOP_DEVICE IRPs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The functional device object.
|
|
|
|
Irp - The I/O request packet.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_DEVICE_BUSY;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmCancelStopDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function handles IRP_MN_CANCEL_STOP_DEVICE IRPs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The functional device object.
|
|
|
|
Irp - The I/O request packet.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
(VOID) PmDeferProcessing(DeviceObject, Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PmQueryCapabilities(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
status = PmDeferProcessing(DeviceObject, Irp);
|
|
if (!NT_SUCCESS(status)) {
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
if (irpSp->Parameters.DeviceCapabilities.Capabilities->Version != 1) {
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
for (i = 0; i < PowerSystemMaximum; i++) {
|
|
deviceExtension->DeviceStateMapping[i] =
|
|
irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceState[i];
|
|
}
|
|
|
|
//
|
|
// Would *LIKE* to smash the eject supported, and removable bits
|
|
// here but this isn't really supported. The hot plug applet pops
|
|
// up (because the device is marked removable or ejectable) and
|
|
// then goes away a few seconds later when the driver is installed
|
|
// (and the capabilities requeried).
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PmSurpriseRemoveDevice(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PPM_DEVICE_EXTENSION deviceExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
if (deviceExtension->RangeList != NULL) {
|
|
PVOID parameterArray[4] = {0};
|
|
UCHAR buffer[] = "Memory module can not be surprise removed safely\n";
|
|
|
|
//
|
|
// Memory cannot be gracefully yanked from a running
|
|
// system.
|
|
//
|
|
|
|
KeBugCheckEx(FATAL_UNHANDLED_HARD_ERROR,
|
|
0x10001,
|
|
(ULONG_PTR) parameterArray,
|
|
(ULONG_PTR) buffer,
|
|
(ULONG_PTR) NULL);
|
|
|
|
}
|
|
|
|
deviceExtension->Flags |= DF_SURPRISE_REMOVED;
|
|
|
|
if (deviceExtension->RangeList != NULL) {
|
|
PmFreeRangeList(deviceExtension->RangeList);
|
|
deviceExtension->RangeList = NULL;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
return PmPassIrp(DeviceObject, Irp);
|
|
}
|
|
|
|
PDRIVER_DISPATCH PmPnpDispatchTable[] = {
|
|
PmStartDevice, // IRP_MN_START_DEVICE
|
|
PmQueryRemoveDevice, // IRP_MN_QUERY_REMOVE_DEVICE
|
|
PmRemoveDevice, // IRP_MN_REMOVE_DEVICE
|
|
PmCancelRemoveDevice, // IRP_MN_CANCEL_REMOVE_DEVICE
|
|
NULL, // IRP_MN_STOP_DEVICE (never get, fails query-stop)
|
|
PmQueryStopDevice, // IRP_MN_QUERY_STOP_DEVICE
|
|
PmCancelStopDevice, // IRP_MN_CANCEL_STOP_DEVICE
|
|
NULL, // IRP_MN_QUERY_DEVICE_RELATIONS
|
|
NULL, // IRP_MN_QUERY_INTERFACE
|
|
PmQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES
|
|
NULL, // IRP_MN_QUERY_RESOURCES
|
|
NULL, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
|
|
NULL, // IRP_MN_QUERY_DEVICE_TEXT
|
|
NULL, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
|
|
NULL, // unused
|
|
NULL, // IRP_MN_READ_CONFIG
|
|
NULL, // IRP_MN_WRITE_CONFIG
|
|
NULL, // IRP_MN_EJECT
|
|
NULL, // IRP_MN_SET_LOCK
|
|
NULL, // IRP_MN_QUERY_ID
|
|
NULL, // IRP_MN_QUERY_PNP_DEVICE_STATE
|
|
NULL, // IRP_MN_QUERY_BUS_INFORMATION
|
|
NULL, // IRP_MN_DEVICE_USAGE_NOTIFICATION
|
|
PmSurpriseRemoveDevice, // IRP_MN_SURPRISE_REMOVAL
|
|
};
|
|
|
|
ULONG PmPnpDispatchTableSize =
|
|
sizeof (PmPnpDispatchTable) / sizeof (PmPnpDispatchTable[0]);
|