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.
1250 lines
34 KiB
1250 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation All Rights Reserved
|
|
|
|
Module Name:
|
|
|
|
dispatch.c
|
|
|
|
Abstract:
|
|
|
|
This module handles the entry points to the driver and contains
|
|
utilities used privately by these functions.
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
Davis Walker (dwalker) Sept 6 2000
|
|
|
|
--*/
|
|
|
|
#include "hpsp.h"
|
|
|
|
//
|
|
// Driver entry points
|
|
//
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
VOID
|
|
HpsUnload (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
NTSTATUS
|
|
HpsAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
);
|
|
|
|
//
|
|
// IRP_MJ handlers
|
|
//
|
|
|
|
NTSTATUS
|
|
HpsDispatchPnp (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
HpsDispatchPower (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
HpsDispatchWmi (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
HpsCreateCloseDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
HpsDeviceControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
HpsDispatchNop(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
UNICODE_STRING HpsRegistryPath;
|
|
|
|
//
|
|
// Dispatch table
|
|
//
|
|
|
|
#define IRP_MN_PNP_MAXIMUM_FUNCTION IRP_MN_QUERY_LEGACY_BUS_INFORMATION
|
|
#define IRP_MN_PO_MAXIMUM_FUNCTION IRP_MN_QUERY_POWER
|
|
|
|
typedef
|
|
NTSTATUS
|
|
(*PHPS_DISPATCH)(
|
|
IN PIRP Irp,
|
|
IN PVOID Extension,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
PHPS_DISPATCH HpsPnpLowerDispatchTable[] = {
|
|
|
|
HpsStartLower, // IRP_MN_START_DEVICE
|
|
HpsPassIrp, // IRP_MN_QUERY_REMOVE_DEVICE
|
|
HpsRemoveLower, // IRP_MN_REMOVE_DEVICE
|
|
HpsPassIrp, // IRP_MN_CANCEL_REMOVE_DEVICE
|
|
HpsPassIrp, // IRP_MN_STOP_DEVICE
|
|
HpsPassIrp, // IRP_MN_QUERY_STOP_DEVICE
|
|
HpsPassIrp, // IRP_MN_CANCEL_STOP_DEVICE
|
|
HpsPassIrp, // IRP_MN_QUERY_DEVICE_RELATIONS
|
|
HpsQueryInterfaceLower, // IRP_MN_QUERY_INTERFACE
|
|
HpsPassIrp, // IRP_MN_QUERY_CAPABILITIES
|
|
HpsPassIrp, // IRP_MN_QUERY_RESOURCES
|
|
HpsPassIrp, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
|
|
HpsPassIrp, // IRP_MN_QUERY_DEVICE_TEXT
|
|
HpsPassIrp, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
|
|
HpsPassIrp, // Unused
|
|
HpsPassIrp, // IRP_MN_READ_CONFIG
|
|
HpsWriteConfigLower, // IRP_MN_WRITE_CONFIG
|
|
HpsPassIrp, // IRP_MN_EJECT
|
|
HpsPassIrp, // IRP_MN_SET_LOCK
|
|
HpsPassIrp, // IRP_MN_QUERY_ID
|
|
HpsPassIrp, // IRP_MN_QUERY_PNP_DEVICE_STATE
|
|
HpsPassIrp, // IRP_MN_QUERY_BUS_INFORMATION
|
|
HpsPassIrp, // IRP_MN_DEVICE_USAGE_NOTIFICATION
|
|
HpsPassIrp, // IRP_MN_SURPRISE_REMOVAL
|
|
HpsPassIrp // IRP_MN_QUERY_LEGACY_BUS_INFORMATION
|
|
};
|
|
|
|
PHPS_DISPATCH HpsPnpUpperDispatchTable[] = {
|
|
|
|
HpsPassIrp, // IRP_MN_START_DEVICE
|
|
HpsPassIrp, // IRP_MN_QUERY_REMOVE_DEVICE
|
|
HpsRemoveCommon, // IRP_MN_REMOVE_DEVICE
|
|
HpsPassIrp, // IRP_MN_CANCEL_REMOVE_DEVICE
|
|
HpsPassIrp, // IRP_MN_STOP_DEVICE
|
|
HpsPassIrp, // IRP_MN_QUERY_STOP_DEVICE
|
|
HpsPassIrp, // IRP_MN_CANCEL_STOP_DEVICE
|
|
HpsPassIrp, // IRP_MN_QUERY_DEVICE_RELATIONS
|
|
HpsPassIrp, // IRP_MN_QUERY_INTERFACE
|
|
HpsPassIrp, // IRP_MN_QUERY_CAPABILITIES
|
|
HpsPassIrp, // IRP_MN_QUERY_RESOURCES
|
|
HpsPassIrp, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
|
|
HpsPassIrp, // IRP_MN_QUERY_DEVICE_TEXT
|
|
HpsPassIrp, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
|
|
HpsPassIrp, // Unused
|
|
HpsPassIrp, // IRP_MN_READ_CONFIG
|
|
HpsPassIrp, // IRP_MN_WRITE_CONFIG
|
|
HpsPassIrp, // IRP_MN_EJECT
|
|
HpsPassIrp, // IRP_MN_SET_LOCK
|
|
HpsPassIrp, // IRP_MN_QUERY_ID
|
|
HpsPassIrp, // IRP_MN_QUERY_PNP_DEVICE_STATE
|
|
HpsPassIrp, // IRP_MN_QUERY_BUS_INFORMATION
|
|
HpsPassIrp, // IRP_MN_DEVICE_USAGE_NOTIFICATION
|
|
HpsPassIrp, // IRP_MN_SURPRISE_REMOVAL
|
|
HpsPassIrp // IRP_MN_QUERY_LEGACY_BUS_INFORMATION
|
|
};
|
|
|
|
//
|
|
// WMI entry points
|
|
// 625 this order is important, must match up to indices in hpwmi.h have appropriate comment.
|
|
//
|
|
WMIGUIDREGINFO HpsWmiGuidList[] =
|
|
{
|
|
{
|
|
&GUID_HPS_CONTROLLER_EVENT,
|
|
1,
|
|
WMIREG_FLAG_EVENT_ONLY_GUID // Flag as an event
|
|
},
|
|
|
|
{
|
|
&GUID_HPS_EVENT_CONTEXT,
|
|
1,
|
|
0
|
|
},
|
|
|
|
{
|
|
&GUID_HPS_INIT_DATA,
|
|
1,
|
|
0
|
|
},
|
|
|
|
{
|
|
&GUID_HPS_SLOT_METHOD, // Guid
|
|
1, // # of instances in each device
|
|
0 // Flags
|
|
}
|
|
};
|
|
|
|
#define HpsWmiGuidCount (sizeof(HpsWmiGuidList)/sizeof(WMIGUIDREGINFO))
|
|
|
|
WMILIB_CONTEXT HpsWmiContext = {
|
|
|
|
HpsWmiGuidCount,
|
|
HpsWmiGuidList, // GUID List
|
|
HpsWmiRegInfo, // QueryWmiRegInfo
|
|
HpsWmiQueryDataBlock, // QueryWmiDataBlock
|
|
HpsWmiSetDataBlock, // SetWmiDataBlock
|
|
NULL, // SetWmiDataItem
|
|
HpsWmiExecuteMethod, // ExecuteWmiMethod
|
|
HpsWmiFunctionControl // WmiFunctionControl
|
|
};
|
|
|
|
LIST_ENTRY HpsDeviceExtensions;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (INIT, DriverEntry)
|
|
#pragma alloc_text (PAGE, HpsUnload)
|
|
#pragma alloc_text (PAGE, HpsAddDevice)
|
|
#pragma alloc_text (PAGE, HpsDispatchPnp)
|
|
#pragma alloc_text (PAGE, HpsDispatchWmi)
|
|
#pragma alloc_text (PAGE, HpsCreateCloseDevice)
|
|
#pragma alloc_text (PAGE, HpsDeferProcessing)
|
|
#pragma alloc_text (PAGE, HpsSendPnpIrp)
|
|
#pragma alloc_text (PAGE, HpsPassIrp)
|
|
#pragma alloc_text (PAGE, HpsRemoveCommon)
|
|
// NOT PAGED, HpsCompletionRoutine
|
|
// NOT PAGED, HpsDeviceControl
|
|
// NOT PAGED, HpsDispatchPower
|
|
// NOT PAGED, HpsDispatchNop
|
|
|
|
#endif
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Driver entry point. This routine sets up entry points for
|
|
all future accesses
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to the driver object
|
|
|
|
RegistryPath - pointer to a unicode string representing the path
|
|
to a driver-specific registry key
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
ULONG index;
|
|
PDRIVER_DISPATCH *dispatch;
|
|
|
|
HpsRegistryPath.Buffer = ExAllocatePool(NonPagedPool,
|
|
RegistryPath->MaximumLength
|
|
);
|
|
if (!HpsRegistryPath.Buffer) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyUnicodeString(&HpsRegistryPath,
|
|
RegistryPath
|
|
);
|
|
|
|
InitializeListHead(&HpsDeviceExtensions);
|
|
|
|
//
|
|
// Create Dispatch Points
|
|
//
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = HpsDispatchPnp;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = HpsDispatchPower;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HpsDispatchWmi;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = HpsCreateCloseDevice;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = HpsCreateCloseDevice;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HpsDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HpsDispatchNop;
|
|
DriverObject->DriverExtension->AddDevice = HpsAddDevice;
|
|
DriverObject->DriverUnload = HpsUnload;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
VOID
|
|
HpsUnload (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Routine to free all resources allocated to the driver
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to the driver object originally passed
|
|
to the DriverEntry routine
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Device Object should be NULL by now
|
|
//
|
|
|
|
ASSERT(DriverObject->DeviceObject == NULL);
|
|
|
|
if (HpsRegistryPath.Buffer) {
|
|
ExFreePool(HpsRegistryPath.Buffer);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an FDO for ourselves and attach it to the stack.
|
|
This has to deal with the fact that our driver could either
|
|
be loaded as an upper or lower filter. It creates a different
|
|
device extension and has different initialization for these
|
|
two cases.
|
|
|
|
The upper filter exists solely so that the fdo of the device stack
|
|
doesn't fail requests before we get a chance to trap them. Virtually
|
|
all of the work of the driver happens in the lower filter.
|
|
|
|
Arguments:
|
|
|
|
Driver Object - pointer to our driver object
|
|
|
|
PhysicalDeviceObject - pointer to the PDO we are asked to attach to
|
|
|
|
Return Value:
|
|
|
|
NT Status code.
|
|
STATUS_SUCCESS if successful
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOLEAN initialized=FALSE;
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
PDEVICE_OBJECT lowerFilter = NULL;
|
|
PHPS_DEVICE_EXTENSION deviceExtension;
|
|
PHPS_COMMON_EXTENSION commonExtension;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Query our location on the stack. If upperFilter comes back
|
|
// NULL, we're the lower filter.
|
|
//
|
|
status = HpsGetLowerFilter(PhysicalDeviceObject,
|
|
&lowerFilter
|
|
);
|
|
|
|
//
|
|
// Create the FDO, differently for upper and lower filter
|
|
//
|
|
|
|
if (NT_SUCCESS(status) &&
|
|
(lowerFilter != NULL)) {
|
|
|
|
//
|
|
// We're an upper filter. Create a devobj with a limited extension,
|
|
// essentially just large enough to identify itself as the upper
|
|
// filter and to save its place on the stack
|
|
//
|
|
|
|
status = IoCreateDevice(DriverObject,
|
|
sizeof(HPS_COMMON_EXTENSION),
|
|
NULL, // FDOs are not named
|
|
FILE_DEVICE_BUS_EXTENDER, // since this is a bus driver filter
|
|
FILE_DEVICE_SECURE_OPEN, // to apply security descriptor to opens
|
|
FALSE,
|
|
&deviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Initialize device extension
|
|
//
|
|
commonExtension = deviceObject->DeviceExtension;
|
|
commonExtension->ExtensionTag = HpsUpperDeviceTag;
|
|
commonExtension->Self = deviceObject;
|
|
commonExtension->LowerDO = IoAttachDeviceToDeviceStack (
|
|
deviceObject,
|
|
PhysicalDeviceObject
|
|
);
|
|
if (commonExtension->LowerDO == NULL) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto cleanup;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// We're the lower filter
|
|
//
|
|
|
|
status = IoCreateDevice(DriverObject,
|
|
sizeof(HPS_DEVICE_EXTENSION),
|
|
NULL, // FDOs are not named
|
|
FILE_DEVICE_BUS_EXTENDER, // since this is a bus driver filter
|
|
FILE_DEVICE_SECURE_OPEN, // to apply security descriptor to opens
|
|
FALSE,
|
|
&deviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Initialize device extension
|
|
//
|
|
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
deviceExtension->ExtensionTag = HpsLowerDeviceTag;
|
|
deviceExtension->PhysicalDO = PhysicalDeviceObject;
|
|
deviceExtension->Self = deviceObject;
|
|
deviceExtension->LowerDO = IoAttachDeviceToDeviceStack (
|
|
deviceObject,
|
|
PhysicalDeviceObject
|
|
);
|
|
if (deviceExtension->LowerDO == NULL) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto cleanup;
|
|
}
|
|
status = HpsGetBusInterface(deviceExtension);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
deviceExtension->UseConfig = TRUE;
|
|
status = HpsInitConfigSpace(deviceExtension);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
initialized=TRUE;
|
|
|
|
}
|
|
}
|
|
|
|
if (initialized == FALSE) {
|
|
|
|
deviceExtension->UseConfig = FALSE;
|
|
status = HpsInitHBRB(deviceExtension);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
if (deviceExtension->HwInitData.NumSlots != 0) {
|
|
deviceExtension->SoftDevices = ExAllocatePool(PagedPool,
|
|
deviceExtension->HwInitData.NumSlots * sizeof(PSOFTPCI_DEVICE)
|
|
);
|
|
if (!deviceExtension->SoftDevices) {
|
|
|
|
goto cleanup;
|
|
}
|
|
RtlZeroMemory(deviceExtension->SoftDevices, deviceExtension->HwInitData.NumSlots * sizeof(PSOFTPCI_DEVICE));
|
|
}
|
|
|
|
//
|
|
// Register device interface
|
|
//
|
|
deviceExtension->SymbolicName = ExAllocatePoolWithTag(PagedPool,
|
|
sizeof(UNICODE_STRING),
|
|
HpsStringPool
|
|
);
|
|
if (!deviceExtension->SymbolicName) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
RtlInitUnicodeString(deviceExtension->SymbolicName,
|
|
NULL
|
|
);
|
|
status = IoRegisterDeviceInterface(deviceExtension->PhysicalDO,
|
|
&GUID_HPS_DEVICE_CLASS,
|
|
NULL,
|
|
deviceExtension->SymbolicName
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
deviceExtension->EventsEnabled = FALSE;
|
|
deviceExtension->WmiEventContext = NULL;
|
|
deviceExtension->WmiEventContextSize = 0;
|
|
status = IoWMIRegistrationControl(deviceObject,
|
|
WMIREG_ACTION_REGISTER
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
KeInitializeDpc(&deviceExtension->EventDpc,
|
|
HpsEventDpc,
|
|
deviceExtension
|
|
);
|
|
|
|
KeInitializeSpinLock(&deviceExtension->IntSpinLock);
|
|
KeInitializeSpinLock(&deviceExtension->RegisterLock);
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize device object flags
|
|
//
|
|
commonExtension = (PHPS_COMMON_EXTENSION)deviceObject->DeviceExtension;
|
|
deviceObject->Flags |= commonExtension->LowerDO->Flags &
|
|
(DO_POWER_PAGABLE | DO_POWER_INRUSH |
|
|
DO_BUFFERED_IO | DO_DIRECT_IO
|
|
);
|
|
|
|
|
|
//
|
|
// Everything worked successfully
|
|
//
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
|
|
if (deviceObject != NULL) {
|
|
//
|
|
// Make sure we're not still attached
|
|
//
|
|
commonExtension = (PHPS_COMMON_EXTENSION)deviceObject->DeviceExtension;
|
|
ASSERT(commonExtension->LowerDO == NULL);
|
|
if (commonExtension->ExtensionTag = HpsLowerDeviceTag) {
|
|
deviceExtension = (PHPS_DEVICE_EXTENSION)commonExtension;
|
|
IoWMIRegistrationControl(deviceObject,
|
|
WMIREG_ACTION_DEREGISTER
|
|
);
|
|
if (deviceExtension->SoftDevices) {
|
|
ExFreePool(deviceExtension->SoftDevices);
|
|
}
|
|
if (deviceExtension->SymbolicName) {
|
|
ExFreePool(deviceExtension->SymbolicName);
|
|
}
|
|
}
|
|
|
|
IoDeleteDevice(deviceObject);
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// IRP_MJ handler routines
|
|
//
|
|
|
|
NTSTATUS
|
|
HpsDispatchPnp (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The PnP dispatch routine. For most IRP_MN codes, we
|
|
simply pass the IRP on. The others are dealt with in
|
|
this function.
|
|
|
|
The upper filter trivially passes all IRP_MN codes except
|
|
for remove. The lower filter has a bit more work to do.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to the device object that represents us
|
|
|
|
Irp - pointer to the IRP to be serviced
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PHPS_DEVICE_EXTENSION deviceExtension;
|
|
PHPS_COMMON_EXTENSION commonExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Both upper and lower devexts start with an extension tag
|
|
// for identification
|
|
//
|
|
commonExtension = (PHPS_COMMON_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
ASSERT((commonExtension->ExtensionTag == HpsUpperDeviceTag) ||
|
|
(commonExtension->ExtensionTag == HpsLowerDeviceTag));
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (irpStack->MinorFunction <= IRP_MN_PNP_MAXIMUM_FUNCTION) {
|
|
|
|
//
|
|
// Since many of our dispatch functions do strange things like completing
|
|
// IRPs that usually shouldn't be completed and deferring processing, we
|
|
// let each one deal with passing the IRP along instead of doing it centrally
|
|
//
|
|
if (commonExtension->ExtensionTag == HpsUpperDeviceTag) {
|
|
|
|
status = HpsPnpUpperDispatchTable[irpStack->MinorFunction](Irp,
|
|
commonExtension,
|
|
irpStack
|
|
);
|
|
} else {
|
|
|
|
//
|
|
// We're the lower filter
|
|
//
|
|
deviceExtension = (PHPS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
status = HpsPnpLowerDispatchTable[irpStack->MinorFunction](Irp,
|
|
deviceExtension,
|
|
irpStack
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
status = HpsPassIrp(Irp,
|
|
commonExtension,
|
|
irpStack
|
|
);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
HpsDispatchPower (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The dispatch routine for IRP_MJ_POWER Irps. We don't care about
|
|
power at all, so these simply pass the IRP down to the next lower
|
|
driver.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to our device object
|
|
|
|
Irp - pointer to the current Irp
|
|
|
|
Return Value:
|
|
|
|
NT Status Code, as returned from processing by next lower driver
|
|
|
|
--*/
|
|
{
|
|
PHPS_COMMON_EXTENSION extension = (PHPS_COMMON_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// NOT PAGED
|
|
//
|
|
|
|
ASSERT(extension->ExtensionTag == HpsUpperDeviceTag ||
|
|
extension->ExtensionTag == HpsLowerDeviceTag);
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return PoCallDriver(extension->LowerDO,
|
|
Irp
|
|
);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsDispatchWmi (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The WMI dispatch routine.
|
|
|
|
The upper filter trivially passes all IRP_MN codes.
|
|
The lower filter dispatches the request to the appropriate
|
|
routine in the dispatch table.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to the device object that represents us
|
|
|
|
Irp - pointer to the IRP to be serviced
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
|
|
PHPS_COMMON_EXTENSION commonExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
SYSCTL_IRP_DISPOSITION disposition;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Both upper and lower devexts start with an extension tag
|
|
// for identification
|
|
//
|
|
commonExtension = (PHPS_COMMON_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
ASSERT((commonExtension->ExtensionTag == HpsUpperDeviceTag) ||
|
|
(commonExtension->ExtensionTag == HpsLowerDeviceTag));
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (commonExtension->ExtensionTag == HpsUpperDeviceTag) {
|
|
|
|
status = HpsPassIrp(Irp,
|
|
commonExtension,
|
|
irpStack
|
|
);
|
|
} else {
|
|
|
|
//
|
|
// Call WmiSystemControl to crack the IRP and call the appropriate
|
|
// callbacks.
|
|
//
|
|
status = WmiSystemControl(&HpsWmiContext,
|
|
commonExtension->Self,
|
|
Irp,
|
|
&disposition
|
|
);
|
|
switch (disposition) {
|
|
case IrpProcessed:
|
|
//
|
|
// The IRP has been fully processed and is out of our hands
|
|
//
|
|
break;
|
|
|
|
case IrpNotCompleted:
|
|
//
|
|
// We need to complete the IRP
|
|
//
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
break;
|
|
|
|
case IrpForward:
|
|
case IrpNotWmi:
|
|
default:
|
|
//
|
|
// We need to pass the IRP down.
|
|
//
|
|
status = HpsPassIrp(Irp,
|
|
commonExtension,
|
|
irpStack
|
|
);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsCreateCloseDevice (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The handler routine for IRP_MJ_CREATE requests. In order
|
|
to communicate with the user mode portion of the simulator,
|
|
this routine must succeed these requests. In this case, however,
|
|
there is no other work to do.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this stack location
|
|
|
|
Irp - Pointer to the current IRP
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HpsDeviceControl (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The handler routine for IRP_MJ_DEVICE_CONTROL IRPs. This routine
|
|
handles the communication with the user mode portion of the
|
|
simulator
|
|
|
|
Arguments:
|
|
|
|
Device Object - Pointer to the device object for this stack location
|
|
|
|
Irp - Pointer to the current IRP
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpStack;
|
|
PHPS_DEVICE_EXTENSION deviceExtension;
|
|
PHPS_COMMON_EXTENSION commonExtension;
|
|
|
|
//
|
|
// NOT PAGED
|
|
//
|
|
|
|
commonExtension = (PHPS_COMMON_EXTENSION) DeviceObject->DeviceExtension;
|
|
ASSERT((commonExtension->ExtensionTag == HpsUpperDeviceTag) ||
|
|
(commonExtension->ExtensionTag == HpsLowerDeviceTag));
|
|
|
|
if (commonExtension->ExtensionTag == HpsUpperDeviceTag) {
|
|
|
|
//
|
|
// For an upper filter, we don't want to handle these.
|
|
// Just pass them down.
|
|
//
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
} else {
|
|
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
deviceExtension = (PHPS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
status = HpsDeviceControlLower(Irp,
|
|
deviceExtension,
|
|
irpStack
|
|
);
|
|
}
|
|
|
|
//
|
|
// Unless the status is STATUS_NOT_SUPPORTED or STATUS_PENDING,
|
|
// we always complete this request because we only support
|
|
// private IOCTLs that will fail if they are passed down.
|
|
//
|
|
if (status == STATUS_NOT_SUPPORTED) {
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(commonExtension->LowerDO,
|
|
Irp
|
|
);
|
|
} else if (status == STATUS_PENDING) {
|
|
return status;
|
|
|
|
} else {
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT
|
|
);
|
|
return status;
|
|
}
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsDispatchNop(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PHPS_COMMON_EXTENSION commonExtension = (PHPS_COMMON_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(commonExtension->LowerDO,
|
|
Irp
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsRemoveCommon(
|
|
IN PIRP Irp,
|
|
IN PHPS_COMMON_EXTENSION Common,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This function performs the default remove handling for the driver.
|
|
|
|
Arguments:
|
|
|
|
Irp - The IRP that caused this request
|
|
|
|
Common - Device Extension for this device
|
|
|
|
IrpStack - The current IRP stack location
|
|
|
|
Return Value:
|
|
|
|
NT Status code
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DbgPrintEx(DPFLTR_HPS_ID,
|
|
DPFLTR_INFO_LEVEL,
|
|
"HPS-IRP Remove\n"
|
|
);
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = IoCallDriver(Common->LowerDO,
|
|
Irp
|
|
);
|
|
|
|
IoDetachDevice(Common->LowerDO);
|
|
IoDeleteDevice(Common->Self);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsPassIrp(
|
|
IN PIRP Irp,
|
|
IN PHPS_COMMON_EXTENSION Common,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
/*++
|
|
|
|
Function Description:
|
|
|
|
This routine is the default handler for PNP Irps. It simply passes
|
|
the request down to the next location in the stack
|
|
|
|
Arguments:
|
|
|
|
Irp - The IRP that caused this request
|
|
|
|
Common - The Device Extension for this device
|
|
|
|
IrpStack - The current IRP stack location
|
|
|
|
Return Value:
|
|
|
|
NT Status code
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(Common->LowerDO,
|
|
Irp
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsDeferProcessing (
|
|
IN PHPS_COMMON_EXTENSION Common,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine defers processing of an IRP until after a completion routine
|
|
has fired. In this case, the completion routine simply fires the event
|
|
that is initialized in this routine. By the time this routine returns, we
|
|
can be guaranteed that all lower drivers have finished processing the IRP.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - pointer to the current device extension
|
|
|
|
Irp - pointer to the current IRP
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KEVENT event;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
KeInitializeEvent(&event,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
IoSetCompletionRoutine(Irp,
|
|
HpsCompletionRoutine,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
status = IoCallDriver(Common->LowerDO,
|
|
Irp
|
|
);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
// we're still waiting on a lower driver to complete, so wait for
|
|
// the completion routine event to fire
|
|
|
|
KeWaitForSingleObject(
|
|
&event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
// by now, the completion routine must have executed
|
|
|
|
return Irp->IoStatus.Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsCompletionRoutine (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A simple completion routine for a PNP Irp. It simply fires an event
|
|
and returns STATUS_MORE_PROCESSING_REQUIRED, thereby returning control
|
|
to the function that set the completion routine in the first place.
|
|
This is done rather than performing the postprocessing tasks directly
|
|
in the completion routine because completion routines can be called at
|
|
Dispatch IRQL, meaning, among other things, no access to paged pool.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to our device object
|
|
|
|
Irp - pointer to the current Irp
|
|
|
|
Context - the context for this completion routine; in this case an
|
|
event to be fired.
|
|
|
|
Return Value:
|
|
|
|
STATUS_MORE_PROCESSING_REQUIRED
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// NOT PAGED
|
|
//
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
KeSetEvent((PKEVENT) Context,
|
|
IO_NO_INCREMENT,
|
|
FALSE
|
|
);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
HpsSendPnpIrp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIO_STACK_LOCATION IrpStack,
|
|
OUT PULONG_PTR Information OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This builds and send a pnp irp to a device.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The a device in the device stack the irp is to be sent to -
|
|
the top of the device stack is always found and the irp sent there first.
|
|
|
|
IrpStack - The initial stack location to use - contains the IRP minor code
|
|
and any parameters
|
|
|
|
Information - If provided contains the final value of the irps information
|
|
field.
|
|
|
|
Return Value:
|
|
|
|
The final status of the completed irp or an error if the irp couldn't be sent
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PIRP irp = NULL;
|
|
PIO_STACK_LOCATION newSp;
|
|
PDEVICE_OBJECT targetDevice = NULL;
|
|
KEVENT event;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(IrpStack->MajorFunction == IRP_MJ_PNP);
|
|
|
|
//
|
|
// Find out where we are sending the irp
|
|
//
|
|
targetDevice = IoGetAttachedDeviceReference(DeviceObject);
|
|
|
|
//
|
|
// Get an IRP
|
|
//
|
|
irp = IoAllocateIrp(targetDevice->StackSize,FALSE);
|
|
if (!irp) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Initialize the IRP
|
|
//
|
|
ASSERT(IrpStack->MajorFunction == IRP_MJ_PNP);
|
|
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Initialize the top stack location with the parameters passed in.
|
|
//
|
|
newSp = IoGetNextIrpStackLocation(irp);
|
|
RtlCopyMemory(newSp, IrpStack, sizeof(IO_STACK_LOCATION));
|
|
|
|
//
|
|
// Call the driver and wait for completion
|
|
//
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
IoSetCompletionRoutine(irp,
|
|
HpsCompletionRoutine,
|
|
&event,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
status = IoCallDriver(targetDevice, irp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
|
status = irp->IoStatus.Status;
|
|
}
|
|
|
|
//
|
|
// Return the information
|
|
//
|
|
if (ARGUMENT_PRESENT(Information)) {
|
|
|
|
if (!NT_ERROR(status)) {
|
|
|
|
*Information = irp->IoStatus.Information;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If it's an error, PnP will ignore the information value. If the
|
|
// driver expected PnP to free some memory, it is going to be
|
|
// sorely mistaken.
|
|
//
|
|
ASSERT(irp->IoStatus.Information == 0);
|
|
*Information = 0;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if (irp) {
|
|
IoFreeIrp(irp);
|
|
}
|
|
|
|
ObDereferenceObject(targetDevice);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|