📄 pnproot.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/io/pnproot.c
* PURPOSE: PnP manager root device
*
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *******************************************************************/
#define ENUM_NAME_ROOT L"Root"
/* DATA **********************************************************************/
typedef struct _PNPROOT_DEVICE
{
// Entry on device list
LIST_ENTRY ListEntry;
// Physical Device Object of device
PDEVICE_OBJECT Pdo;
// Service name
UNICODE_STRING ServiceName;
// Device ID
UNICODE_STRING DeviceID;
// Instance ID
UNICODE_STRING InstanceID;
// Device description
UNICODE_STRING DeviceDescription;
// Boot resource list
PCM_FULL_RESOURCE_DESCRIPTOR BootResourceList;
SIZE_T BootResourceListSize;
// Resource requirement list
PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirementsList;
} PNPROOT_DEVICE, *PPNPROOT_DEVICE;
typedef enum
{
dsStopped,
dsStarted,
dsPaused,
dsRemoved,
dsSurpriseRemoved
} PNPROOT_DEVICE_STATE;
#include <pshpack1.h>
typedef struct _PNPROOT_COMMON_DEVICE_EXTENSION
{
// Pointer to device object, this device extension is associated with
PDEVICE_OBJECT DeviceObject;
// Wether this device extension is for an FDO or PDO
BOOLEAN IsFDO;
// Wether the device is removed
BOOLEAN Removed;
// Current device power state for the device
DEVICE_POWER_STATE DevicePowerState;
} PNPROOT_COMMON_DEVICE_EXTENSION, *PPNPROOT_COMMON_DEVICE_EXTENSION;
/* Physical Device Object device extension for a child device */
typedef struct _PNPROOT_PDO_DEVICE_EXTENSION
{
// Common device data
PNPROOT_COMMON_DEVICE_EXTENSION Common;
// Device
PPNPROOT_DEVICE Device;
} PNPROOT_PDO_DEVICE_EXTENSION, *PPNPROOT_PDO_DEVICE_EXTENSION;
/* Functional Device Object device extension for the PCI driver device object */
typedef struct _PNPROOT_FDO_DEVICE_EXTENSION
{
// Common device data
PNPROOT_COMMON_DEVICE_EXTENSION Common;
// Physical Device Object
PDEVICE_OBJECT Pdo;
// Lower device object
PDEVICE_OBJECT Ldo;
// Current state of the driver
PNPROOT_DEVICE_STATE State;
// Namespace device list
LIST_ENTRY DeviceListHead;
// Number of (not removed) devices in device list
ULONG DeviceListCount;
// Lock for namespace device list
// FIXME: Use fast mutex instead?
KSPIN_LOCK DeviceListLock;
} PNPROOT_FDO_DEVICE_EXTENSION, *PPNPROOT_FDO_DEVICE_EXTENSION;
#include <poppack.h>
PDEVICE_OBJECT PnpRootDeviceObject;
/* FUNCTIONS *****************************************************************/
/* Physical Device Object routines */
NTSTATUS
PnpRootCreateDevice(
PDEVICE_OBJECT *PhysicalDeviceObject)
{
PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
PPNPROOT_DEVICE Device;
NTSTATUS Status;
/* This function should be obsoleted soon */
DPRINT("Called\n");
DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)PnpRootDeviceObject->DeviceExtension;
Device = (PPNPROOT_DEVICE)ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
if (!Device)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
Status = IoCreateDevice(
PnpRootDeviceObject->DriverObject,
sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
NULL,
FILE_DEVICE_CONTROLLER,
FILE_AUTOGENERATED_DEVICE_NAME,
FALSE,
&Device->Pdo);
if (!NT_SUCCESS(Status)) {
DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
ExFreePool(Device);
return Status;
}
Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
//Device->Pdo->Flags |= DO_POWER_PAGABLE;
PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
PdoDeviceExtension->Common.IsFDO = FALSE;
PdoDeviceExtension->Common.DeviceObject = Device->Pdo;
PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0;
ExInterlockedInsertTailList(
&DeviceExtension->DeviceListHead,
&Device->ListEntry,
&DeviceExtension->DeviceListLock);
DeviceExtension->DeviceListCount++;
*PhysicalDeviceObject = Device->Pdo;
return STATUS_SUCCESS;
}
NTSTATUS
PdoQueryId(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
UNICODE_STRING String;
NTSTATUS Status;
DPRINT("Called\n");
DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
// Irp->IoStatus.Information = 0;
Status = STATUS_SUCCESS;
RtlInitUnicodeString(&String, NULL);
switch (IrpSp->Parameters.QueryId.IdType) {
case BusQueryDeviceID:
if (DeviceExtension->Device)
Status = RtlDuplicateUnicodeString(TRUE,
&DeviceExtension->Device->DeviceID,
&String);
else
Status = RtlCreateUnicodeString(&String, ENUM_NAME_ROOT L"\\LEGACY_UNKNOWN");
DPRINT("DeviceID: %wZ\n", &String);
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
break;
case BusQueryHardwareIDs:
case BusQueryCompatibleIDs:
Status = STATUS_NOT_IMPLEMENTED;
break;
case BusQueryInstanceID:
if (DeviceExtension->Device)
Status = RtlDuplicateUnicodeString(TRUE,
&DeviceExtension->Device->InstanceID,
&String);
else
Status = RtlCreateUnicodeString(&String, L"0000");
DPRINT("InstanceID: %S\n", String.Buffer);
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
break;
case BusQueryDeviceSerialNumber:
default:
Status = STATUS_NOT_IMPLEMENTED;
}
return Status;
}
NTSTATUS
PdoQueryResources(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
PCM_RESOURCE_LIST ResourceList;
ULONG ResourceListSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
DPRINT("Called\n");
DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
if (!DeviceExtension->Device || DeviceExtension->Device->BootResourceList == NULL)
{
/* Create an empty resource list */
ResourceList = ExAllocatePool(PagedPool, ResourceListSize);
if (ResourceList == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
ResourceList->Count = 0;
Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
}
else
{
/* Copy existing resource list */
ResourceList = ExAllocatePool(PagedPool,
FIELD_OFFSET(CM_RESOURCE_LIST, List) + DeviceExtension->Device->BootResourceListSize);
if (ResourceList == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
ResourceList->Count = 1;
RtlCopyMemory(
&ResourceList->List,
DeviceExtension->Device->BootResourceList,
DeviceExtension->Device->BootResourceListSize);
Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
}
return STATUS_SUCCESS;
}
NTSTATUS
PdoQueryResourceRequirements(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
ULONG ResourceListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List);
DPRINT("Called\n");
DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
if (!DeviceExtension->Device || DeviceExtension->Device->ResourceRequirementsList == NULL)
{
/* Create an empty resource list */
ResourceList = ExAllocatePool(PagedPool, ResourceListSize);
if (ResourceList == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
RtlZeroMemory(ResourceList, ResourceListSize);
ResourceList->ListSize = ResourceListSize;
Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
}
else
{
/* Copy existing resource requirement list */
ResourceList = ExAllocatePool(PagedPool, DeviceExtension->Device->ResourceRequirementsList->ListSize);
if (ResourceList == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyMemory(
ResourceList,
DeviceExtension->Device->ResourceRequirementsList,
DeviceExtension->Device->ResourceRequirementsList->ListSize);
Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
}
return STATUS_SUCCESS;
}
static NTSTATUS
PnpRootPdoQueryCapabilities(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
PDEVICE_CAPABILITIES DeviceCapabilities;
DPRINT("Called\n");
DeviceExtension = (PPNPROOT_FDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
if (DeviceCapabilities->Version != 1)
return STATUS_UNSUCCESSFUL;
DeviceCapabilities->UniqueID = TRUE;
/* FIXME: Fill other fields */
return STATUS_SUCCESS;
}
/*
* FUNCTION: Handle Plug and Play IRPs for the child device
* ARGUMENTS:
* DeviceObject = Pointer to physical device object of the child device
* Irp = Pointer to IRP that should be handled
* RETURNS:
* Status
*/
NTSTATUS
PnpRootPdoPnpControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PIO_STACK_LOCATION IrpSp;
NTSTATUS Status;
DPRINT("Called\n");
Status = Irp->IoStatus.Status;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
switch (IrpSp->MinorFunction) {
#if 0
case IRP_MN_QUERY_BUS_INFORMATION:
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
/* FIXME: Handle for TargetDeviceRelation */
break;
#endif
case IRP_MN_QUERY_ID:
Status = PdoQueryId(DeviceObject, Irp, IrpSp);
break;
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
break;
case IRP_MN_QUERY_RESOURCES:
Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
break;
case IRP_MN_QUERY_CAPABILITIES:
Status = PnpRootPdoQueryCapabilities(DeviceObject, Irp, IrpSp);
break;
case IRP_MN_START_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_STOP_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
Status = STATUS_SUCCESS;
break;
default:
DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
break;
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
DPRINT("Leaving. Status 0x%X\n", Status);
return Status;
}
/*
* FUNCTION: Handle power management IRPs for the child device
* ARGUMENTS:
* DeviceObject = Pointer to physical device object of the child device
* Irp = Pointer to IRP that should be handled
* RETURNS:
* Status
*/
NTSTATUS
PnpRootPdoPowerControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PIO_STACK_LOCATION IrpSp;
NTSTATUS Status;
DPRINT("Called\n");
Status = Irp->IoStatus.Status;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
switch (IrpSp->MinorFunction) {
default:
DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
Status = STATUS_NOT_IMPLEMENTED;
break;
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
DPRINT("Leaving. Status 0x%X\n", Status);
return Status;
}
/* Functional Device Object routines */
static NTSTATUS
PnpRootReadRegistryBinary(
IN PWSTR KeyName,
IN PWSTR ValueKeyName,
OUT PVOID* Buffer,
OUT SIZE_T* BufferSize OPTIONAL)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING KeyNameU;
UNICODE_STRING ValueKeyNameU;
KEY_VALUE_PARTIAL_INFORMATION Size;
PKEY_VALUE_PARTIAL_INFORMATION Data = NULL;
ULONG DataSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
HANDLE KeyHandle;
NTSTATUS Status;
DPRINT("Called\n");
RtlInitUnicodeString(&KeyNameU, KeyName);
RtlInitUnicodeString(&ValueKeyNameU, ValueKeyName);
InitializeObjectAttributes(
&ObjectAttributes,
&KeyNameU,
OBJ_CASE_INSENSITIVE,
NULL, /* Root dir */
NULL); /* Security descriptor */
Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwOpenKey() failed (Status 0x%08lx)\n", Status);
return Status;
}
Status = ZwQueryValueKey(
KeyHandle,
&ValueKeyNameU,
KeyValuePartialInformation,
&Size, DataSize,
&DataSize);
if (Status != STATUS_BUFFER_OVERFLOW)
{
DPRINT("ZwQueryValueKey() failed (Status 0x%08lx)\n", Status);
ZwClose(KeyHandle);
return Status;
}
while (Status == STATUS_BUFFER_OVERFLOW)
{
if (Data)
ExFreePoolWithTag(Data, TAG_PNP_ROOT);
Data = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(PagedPool, DataSize, TAG_PNP_ROOT);
if (!Data)
{
DPRINT("ExAllocatePoolWithTag() failed\n", Status);
ZwClose(KeyHandle);
return STATUS_NO_MEMORY;
}
Status = ZwQueryValueKey(
KeyHandle,
&ValueKeyNameU,
KeyValuePartialInformation,
Data, DataSize,
&DataSize);
if (NT_SUCCESS(Status))
{
*Buffer = ExAllocatePoolWithTag(PagedPool, Data->DataLength, TAG_PNP_ROOT);
if (BufferSize) *BufferSize = Data->DataLength;
if (!*Buffer)
{
DPRINT("ExAllocatePoolWithTag() failed\n", Status);
ExFreePoolWithTag(Data, TAG_PNP_ROOT);
ZwClose(KeyHandle);
return STATUS_NO_MEMORY;
}
RtlCopyMemory(
*Buffer,
Data->Data,
Data->DataLength);
break;
}
}
if (Data)
ExFreePoolWithTag(Data, TAG_PNP_ROOT);
ZwClose(KeyHandle);
return Status;
}
NTSTATUS
PnpRootFdoReadDeviceInfo(
PPNPROOT_DEVICE Device)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
PUNICODE_STRING DeviceDesc;
WCHAR KeyName[MAX_PATH];
NTSTATUS Status;
DPRINT("Called\n");
/* Retrieve configuration from Enum key */
DeviceDesc = &Device->DeviceDescription;
wcscpy(KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
wcscat(KeyName, ENUM_NAME_ROOT);
wcscat(KeyName, L"\\");
wcscat(KeyName, Device->ServiceName.Buffer);
wcscat(KeyName, L"\\");
wcscat(KeyName, Device->InstanceID.Buffer);
DPRINT("KeyName %S\n", KeyName);
/* 1. Read informations in instance key */
RtlZeroMemory(QueryTable, sizeof(QueryTable));
RtlInitUnicodeString(DeviceDesc, NULL);
QueryTable[0].Name = L"DeviceDesc";
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
QueryTable[0].EntryContext = DeviceDesc;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
KeyName,
QueryTable,
NULL,
NULL);
DPRINT("RtlQueryRegistryValues() returned status 0x%08lx\n", Status);
if (!NT_SUCCESS(Status))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -