📄 pnp.c
字号:
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
PNP.C
Abstract:
This module contains contains the plugplay calls
PNP / WDM BUS driver.
Environment:
kernel mode only
Notes:
--*/
#include "pch.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, Serenum_AddDevice)
#pragma alloc_text (PAGE, Serenum_PnP)
#pragma alloc_text (PAGE, Serenum_FDO_PnP)
#pragma alloc_text (PAGE, Serenum_PDO_PnP)
#pragma alloc_text (PAGE, Serenum_PnPRemove)
//#pragma alloc_text (PAGE, Serenum_Remove)
#endif
NTSTATUS
Serenum_AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT BusPhysicalDeviceObject
)
/*++
Routine Description.
A bus has been found. Attach our FDO to it.
Allocate any required resources. Set things up. And be prepared for the
first ``start device.''
Arguments:
BusPhysicalDeviceObject - Device object representing the bus. That to which
we attach a new FDO.
DriverObject - This very self referenced driver.
--*/
{
NTSTATUS status;
PDEVICE_OBJECT deviceObject;
PFDO_DEVICE_DATA DeviceData;
ULONG nameLength;
PAGED_CODE ();
Serenum_KdPrint_Def (SER_DBG_PNP_TRACE, ("Add Device: 0x%x\n",
BusPhysicalDeviceObject));
//
// Create our FDO
//
status = IoCreateDevice (
DriverObject, // our driver object
sizeof (FDO_DEVICE_DATA), // device object extension size
NULL, // FDOs do not have names
FILE_DEVICE_BUS_EXTENDER,
0, // No special characteristics
TRUE, // our FDO is exclusive
&deviceObject); // The device object created
if (NT_SUCCESS (status)) {
DeviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension;
RtlFillMemory (DeviceData, sizeof (FDO_DEVICE_DATA), 0);
DeviceData->IsFDO = TRUE;
DeviceData->DebugLevel = SER_DEFAULT_DEBUG_OUTPUT_LEVEL;
DeviceData->Self = deviceObject;
DeviceData->AttachedPDO = NULL;
DeviceData->NumPDOs = 0;
DeviceData->DeviceState = PowerDeviceD0;
DeviceData->SystemState = PowerSystemWorking;
DeviceData->LastSetPowerState = PowerDeviceD0;
DeviceData->PDOLegacyEnumerated = FALSE;
DeviceData->PDOForcedRemove = FALSE;
DeviceData->PollingLocks = 0;
DeviceData->Polling = 0;
DeviceData->SystemWake=PowerSystemUnspecified;
DeviceData->DeviceWake=PowerDeviceUnspecified;
DeviceData->PollingWorker = IoAllocateWorkItem(deviceObject);
if (DeviceData->PollingWorker == NULL) {
Serenum_KdPrint(DeviceData, SER_DBG_SS_ERROR,
("Insufficient memory for Polling Routine.\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize the timer used for dynamic detection of attachment
// and removal of PNP devices.
//
KeInitializeTimerEx(
&DeviceData->PollingTimer,
NotificationTimer);
DeviceData->Removed = FALSE;
// Set the PDO for use with PlugPlay functions
DeviceData->UnderlyingPDO = BusPhysicalDeviceObject;
//
// Attach our filter driver to the device stack.
// the return value of IoAttachDeviceToDeviceStack is the top of the
// attachment chain. This is where all the IRPs should be routed.
//
// Our filter will send IRPs to the top of the stack and use the PDO
// for all PlugPlay functions.
//
DeviceData->TopOfStack = IoAttachDeviceToDeviceStack (
deviceObject,
BusPhysicalDeviceObject);
// Bias outstanding request to 1 so that we can look for a
// transition to zero when processing the remove device PlugPlay IRP.
DeviceData->OutstandingIO = 1;
KeInitializeEvent(&DeviceData->RemoveEvent,
SynchronizationEvent,
FALSE); // initialized to not signalled
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
deviceObject->Flags |= DO_POWER_PAGABLE;
//
// Tell the PlugPlay system that this device will need an interface
// device class shingle.
//
// It may be that the driver cannot hang the shingle until it starts
// the device itself, so that it can query some of its properties.
// (Aka the shingles guid (or ref string) is based on the properties
// of the device.)
//
status = IoRegisterDeviceInterface (
BusPhysicalDeviceObject,
(LPGUID) &GUID_SERENUM_BUS_ENUMERATOR,
NULL, // No ref string
&DeviceData->DevClassAssocName);
if (!NT_SUCCESS (status)) {
Serenum_KdPrint (DeviceData, SER_DBG_PNP_ERROR,
("AddDevice: IoRegisterDCA failed (%x)", status));
IoFreeWorkItem(DeviceData->PollingWorker);
IoDetachDevice (DeviceData->TopOfStack);
IoDeleteDevice (deviceObject);
return status;
}
//
// If for any reason you need to save values in a safe location that
// clients of this DeviceClassAssociate might be interested in reading
// here is the time to do so, with the function
// IoOpenDeviceClassRegistryKey
// the symbolic link name used is was returned in
// DeviceData->DevClassAssocName (the same name which is returned by
// IoGetDeviceClassAssociations and the SetupAPI equivs.
//
#if DBG
{
PWCHAR deviceName = NULL;
status = IoGetDeviceProperty (BusPhysicalDeviceObject,
DevicePropertyPhysicalDeviceObjectName,
0,
NULL,
&nameLength);
if ((nameLength != 0) && (status == STATUS_BUFFER_TOO_SMALL)) {
deviceName = ExAllocatePool (NonPagedPool, nameLength);
if (NULL == deviceName) {
goto someDebugStuffExit;
}
IoGetDeviceProperty (BusPhysicalDeviceObject,
DevicePropertyPhysicalDeviceObjectName,
nameLength, deviceName, &nameLength);
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
("AddDevice: %x to %x->%x (%ws) \n",
deviceObject, DeviceData->TopOfStack,
BusPhysicalDeviceObject, deviceName));
}
someDebugStuffExit:;
if (deviceName != NULL) {
ExFreePool(deviceName);
}
}
#endif
//
// Turn on the shingle and point it to the given device object.
//
status = IoSetDeviceInterfaceState (
&DeviceData->DevClassAssocName,
TRUE);
if (!NT_SUCCESS (status)) {
Serenum_KdPrint (DeviceData, SER_DBG_PNP_ERROR,
("AddDevice: IoSetDeviceClass failed (%x)", status));
return status;
}
DeviceData->PollingAllowed = 0;
DeviceData->PollingNotQueued = 1;
KeInitializeEvent(&DeviceData->PollingEvent, SynchronizationEvent,
FALSE);
KeInitializeEvent(&DeviceData->PollStateEvent, SynchronizationEvent,
TRUE);
KeInitializeDpc(
&DeviceData->DPCPolling,
(PKDEFERRED_ROUTINE) Serenum_PollingTimerRoutine,
DeviceData);
}
return status;
}
NTSTATUS
Serenum_FDO_PnPComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Pirp,
IN PVOID Context
);
NTSTATUS
Serenum_PnP (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Answer the plethora of Irp Major PnP IRPS.
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PCOMMON_DEVICE_DATA commonData;
KIRQL oldIrq;
PAGED_CODE ();
status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT (IRP_MJ_PNP == irpStack->MajorFunction);
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
if (commonData->Removed) {
Serenum_KdPrint (commonData, SER_DBG_PNP_TRACE,
("PNP: removed DO: %x got IRP: %x\n", DeviceObject, Irp));
Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
} else if (commonData->IsFDO) {
Serenum_KdPrint (commonData, SER_DBG_PNP_TRACE,
("PNP: Functional DO: %x IRP: %x\n", DeviceObject, Irp));
status = Serenum_FDO_PnP (
DeviceObject,
Irp,
irpStack,
(PFDO_DEVICE_DATA) commonData);
} else {
Serenum_KdPrint (commonData, SER_DBG_PNP_TRACE,
("PNP: Physical DO: %x IRP: %x\n", DeviceObject, Irp));
status = Serenum_PDO_PnP (
DeviceObject,
Irp,
irpStack,
(PPDO_DEVICE_DATA) commonData);
}
return status;
}
NTSTATUS
Serenum_FDO_PnP (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PIO_STACK_LOCATION IrpStack,
IN PFDO_DEVICE_DATA DeviceData
)
/*++
Routine Description:
Handle requests from the PlugPlay system for the BUS itself
NB: the various Minor functions of the PlugPlay system will not be
overlapped and do not have to be reentrant
--*/
{
NTSTATUS status;
KIRQL oldIrq;
KEVENT event;
ULONG length;
ULONG i;
PLIST_ENTRY entry;
PPDO_DEVICE_DATA pdoData;
PDEVICE_RELATIONS relations;
PIO_STACK_LOCATION stack;
PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL;
ULONG DebugLevelDefault = SER_DEFAULT_DEBUG_OUTPUT_LEVEL;
PAGED_CODE ();
status = Serenum_IncIoCount (DeviceData);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
stack = IoGetCurrentIrpStackLocation (Irp);
switch (IrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
//
// BEFORE you are allowed to ``touch'' the device object to which
// the FDO is attached (that send an irp from the bus to the Device
// object to which the bus is attached). You must first pass down
// the start IRP. It might not be powered on, or able to access or
// something.
//
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Start Device\n"));
if (DeviceData->Started) {
Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE,
("Device already started\n"));
status = STATUS_SUCCESS;
break;
}
KeInitializeEvent (&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext (Irp);
IoSetCompletionRoutine (Irp,
Serenum_FDO_PnPComplete,
&event,
TRUE,
TRUE,
TRUE);
status = IoCallDriver (DeviceData->TopOfStack, Irp);
if (STATUS_PENDING == status) {
// wait for it...
status = KeWaitForSingleObject (&event,
Executive,
KernelMode,
FALSE, // Not allertable
NULL); // No timeout structure
ASSERT (STATUS_SUCCESS == status);
status = Irp->IoStatus.Status;
}
if (NT_SUCCESS(status)) {
//
// Now we can touch the lower device object as it is now started.
//
if (DeviceData->TopOfStack->Flags & DO_BUFFERED_IO) {
DeviceObject->Flags |= DO_BUFFERED_IO;
} else if (DeviceData->TopOfStack->Flags & DO_DIRECT_IO) {
DeviceObject->Flags |= DO_DIRECT_IO;
}
//
// Get the debug level from the registry
//
if (NULL == (QueryTable = ExAllocatePool(
PagedPool,
sizeof(RTL_QUERY_REGISTRY_TABLE)*2
))) {
Serenum_KdPrint (DeviceData, SER_DBG_PNP_ERROR,
("Failed to allocate memory to query registy\n"));
DeviceData->DebugLevel = DebugLevelDefault;
} else {
RtlZeroMemory(
QueryTable,
sizeof(RTL_QUERY_REGISTRY_TABLE)*2
);
QueryTable[0].QueryRoutine = NULL;
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
QueryTable[0].EntryContext = &DeviceData->DebugLevel;
QueryTable[0].Name = L"DebugLevel";
QueryTable[0].DefaultType = REG_DWORD;
QueryTable[0].DefaultData = &DebugLevelDefault;
QueryTable[0].DefaultLength= sizeof(ULONG);
// CIMEXCIMEX: The rest of the table isn't filled in!
if (!NT_SUCCESS(RtlQueryRegistryValues(
RTL_REGISTRY_SERVICES,
L"Serenum",
QueryTable,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -