mirror of
https://github.com/reactos/reactos.git
synced 2024-07-08 13:45:06 +00:00
![Victor Perevertkin](/assets/img/avatar_default.png)
The root device object is in fact a PDO and a FDO at the same time. Thus there is no need in creating two device objects here, one is enough. This commit also removes the explicit device extension for the root DO, because the only reason it existed is to distinguish the root driver's FDO from its PDOs. This can easily be done by comparing with IopRootDeviceNode. Also collect some unused garbage while we are here.
1526 lines
48 KiB
C
1526 lines
48 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* COPYRIGHT: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/io/pnpmgr/pnproot.c
|
|
* PURPOSE: PnP manager root device
|
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
* Copyright 2007 Herv? Poussineau (hpoussin@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <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;
|
|
// Device ID
|
|
UNICODE_STRING DeviceID;
|
|
// Instance ID
|
|
UNICODE_STRING InstanceID;
|
|
// Device description
|
|
UNICODE_STRING DeviceDescription;
|
|
// Resource requirement list
|
|
PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirementsList;
|
|
// Associated resource list
|
|
PCM_RESOURCE_LIST ResourceList;
|
|
ULONG ResourceListSize;
|
|
} PNPROOT_DEVICE, *PPNPROOT_DEVICE;
|
|
|
|
/* Physical Device Object device extension for a child device */
|
|
typedef struct _PNPROOT_PDO_DEVICE_EXTENSION
|
|
{
|
|
// Informations about the device
|
|
PPNPROOT_DEVICE DeviceInfo;
|
|
} PNPROOT_PDO_DEVICE_EXTENSION, *PPNPROOT_PDO_DEVICE_EXTENSION;
|
|
|
|
/* Physical Device Object device extension for the Root bus device object */
|
|
typedef struct _PNPROOT_FDO_DEVICE_EXTENSION
|
|
{
|
|
// Namespace device list
|
|
LIST_ENTRY DeviceListHead;
|
|
// Number of (not removed) devices in device list
|
|
ULONG DeviceListCount;
|
|
// Lock for namespace device list
|
|
KGUARDED_MUTEX DeviceListLock;
|
|
} PNPROOT_FDO_DEVICE_EXTENSION, *PPNPROOT_FDO_DEVICE_EXTENSION;
|
|
|
|
typedef struct _BUFFER
|
|
{
|
|
PVOID *Data;
|
|
PULONG Length;
|
|
} BUFFER, *PBUFFER;
|
|
|
|
static PNPROOT_FDO_DEVICE_EXTENSION PnpRootDOExtension;
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
static NTSTATUS
|
|
LocateChildDevice(
|
|
IN PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,
|
|
IN PCUNICODE_STRING DeviceId,
|
|
IN PCWSTR InstanceId,
|
|
OUT PPNPROOT_DEVICE* ChildDevice OPTIONAL)
|
|
{
|
|
PPNPROOT_DEVICE Device;
|
|
UNICODE_STRING InstanceIdU;
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
/* Initialize the string to compare */
|
|
RtlInitUnicodeString(&InstanceIdU, InstanceId);
|
|
|
|
/* Start looping */
|
|
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
|
|
NextEntry != &DeviceExtension->DeviceListHead;
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
/* Get the entry */
|
|
Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry);
|
|
|
|
/* See if the strings match */
|
|
if (RtlEqualUnicodeString(DeviceId, &Device->DeviceID, TRUE) &&
|
|
RtlEqualUnicodeString(&InstanceIdU, &Device->InstanceID, TRUE))
|
|
{
|
|
/* They do, so set the pointer and return success */
|
|
if (ChildDevice)
|
|
*ChildDevice = Device;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* No device found */
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
NTSTATUS
|
|
PnpRootRegisterDevice(
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension = &PnpRootDOExtension;
|
|
PPNPROOT_DEVICE Device;
|
|
PDEVICE_NODE DeviceNode;
|
|
PWSTR InstancePath;
|
|
UNICODE_STRING InstancePathCopy;
|
|
|
|
Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
|
|
if (!Device) return STATUS_NO_MEMORY;
|
|
|
|
DeviceNode = IopGetDeviceNode(DeviceObject);
|
|
if (!RtlCreateUnicodeString(&InstancePathCopy, DeviceNode->InstancePath.Buffer))
|
|
{
|
|
ExFreePoolWithTag(Device, TAG_PNP_ROOT);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
InstancePath = wcsrchr(InstancePathCopy.Buffer, L'\\');
|
|
ASSERT(InstancePath);
|
|
|
|
if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath + 1))
|
|
{
|
|
RtlFreeUnicodeString(&InstancePathCopy);
|
|
ExFreePoolWithTag(Device, TAG_PNP_ROOT);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
InstancePath[0] = UNICODE_NULL;
|
|
|
|
if (!RtlCreateUnicodeString(&Device->DeviceID, InstancePathCopy.Buffer))
|
|
{
|
|
RtlFreeUnicodeString(&InstancePathCopy);
|
|
RtlFreeUnicodeString(&Device->InstanceID);
|
|
ExFreePoolWithTag(Device, TAG_PNP_ROOT);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
InstancePath[0] = L'\\';
|
|
|
|
Device->Pdo = DeviceObject;
|
|
|
|
KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
InsertTailList(&DeviceExtension->DeviceListHead,
|
|
&Device->ListEntry);
|
|
DeviceExtension->DeviceListCount++;
|
|
KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
|
|
RtlFreeUnicodeString(&InstancePathCopy);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Creates a new PnP device for a legacy driver */
|
|
NTSTATUS
|
|
PnpRootCreateDevice(
|
|
IN PUNICODE_STRING ServiceName,
|
|
IN OPTIONAL PDRIVER_OBJECT DriverObject,
|
|
OUT PDEVICE_OBJECT *PhysicalDeviceObject,
|
|
OUT OPTIONAL PUNICODE_STRING FullInstancePath)
|
|
{
|
|
PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
|
|
PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
|
|
UNICODE_STRING DevicePath;
|
|
WCHAR InstancePath[5];
|
|
PPNPROOT_DEVICE Device = NULL;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING PathSep = RTL_CONSTANT_STRING(L"\\");
|
|
ULONG NextInstance;
|
|
UNICODE_STRING EnumKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM);
|
|
HANDLE EnumHandle, DeviceKeyHandle = NULL, InstanceKeyHandle;
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
DeviceExtension = &PnpRootDOExtension;
|
|
KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
|
|
DPRINT("Creating a PnP root device for service '%wZ'\n", ServiceName);
|
|
|
|
DevicePath.Length = 0;
|
|
DevicePath.MaximumLength = sizeof(REGSTR_KEY_ROOTENUM) + sizeof(L'\\') + ServiceName->Length;
|
|
DevicePath.Buffer = ExAllocatePoolWithTag(PagedPool,
|
|
DevicePath.MaximumLength,
|
|
TAG_PNP_ROOT);
|
|
if (DevicePath.Buffer == NULL)
|
|
{
|
|
DPRINT1("ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
RtlAppendUnicodeToString(&DevicePath, REGSTR_KEY_ROOTENUM L"\\");
|
|
RtlAppendUnicodeStringToString(&DevicePath, ServiceName);
|
|
|
|
/* Initialize a PNPROOT_DEVICE structure */
|
|
Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
|
|
if (!Device)
|
|
{
|
|
DPRINT("ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
|
|
Device->DeviceID = DevicePath;
|
|
RtlInitEmptyUnicodeString(&DevicePath, NULL, 0);
|
|
|
|
Status = IopOpenRegistryKeyEx(&EnumHandle, NULL, &EnumKeyName, KEY_READ);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Device->DeviceID,
|
|
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
|
EnumHandle,
|
|
NULL);
|
|
Status = ZwCreateKey(&DeviceKeyHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
|
|
ObCloseHandle(EnumHandle, KernelMode);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to open registry key\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
tryagain:
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
QueryTable[0].Name = L"NextInstance";
|
|
QueryTable[0].EntryContext = &NextInstance;
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)DeviceKeyHandle,
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
for (NextInstance = 0; NextInstance <= 9999; NextInstance++)
|
|
{
|
|
_snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", NextInstance);
|
|
Status = LocateChildDevice(DeviceExtension, &Device->DeviceID, InstancePath, NULL);
|
|
if (Status == STATUS_NO_SUCH_DEVICE)
|
|
break;
|
|
}
|
|
|
|
if (NextInstance > 9999)
|
|
{
|
|
DPRINT1("Too many legacy devices reported for service '%wZ'\n", ServiceName);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto cleanup;
|
|
}
|
|
|
|
_snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", NextInstance);
|
|
Status = LocateChildDevice(DeviceExtension, &Device->DeviceID, InstancePath, NULL);
|
|
if (Status != STATUS_NO_SUCH_DEVICE || NextInstance > 9999)
|
|
{
|
|
DPRINT1("NextInstance value is corrupt! (%lu)\n", NextInstance);
|
|
RtlDeleteRegistryValue(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)DeviceKeyHandle,
|
|
L"NextInstance");
|
|
goto tryagain;
|
|
}
|
|
|
|
NextInstance++;
|
|
Status = RtlWriteRegistryValue(RTL_REGISTRY_HANDLE,
|
|
(PWSTR)DeviceKeyHandle,
|
|
L"NextInstance",
|
|
REG_DWORD,
|
|
&NextInstance,
|
|
sizeof(NextInstance));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to write new NextInstance value! (0x%x)\n", Status);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!RtlCreateUnicodeString(&Device->InstanceID, InstancePath))
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Finish creating the instance path in the registry */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Device->InstanceID,
|
|
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
|
|
DeviceKeyHandle,
|
|
NULL);
|
|
Status = ZwCreateKey(&InstanceKeyHandle, KEY_QUERY_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to create instance path (0x%x)\n", Status);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Just close the handle */
|
|
ObCloseHandle(InstanceKeyHandle, KernelMode);
|
|
|
|
if (FullInstancePath)
|
|
{
|
|
FullInstancePath->MaximumLength = Device->DeviceID.Length + PathSep.Length + Device->InstanceID.Length;
|
|
FullInstancePath->Length = 0;
|
|
FullInstancePath->Buffer = ExAllocatePool(PagedPool, FullInstancePath->MaximumLength);
|
|
if (!FullInstancePath->Buffer)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
RtlAppendUnicodeStringToString(FullInstancePath, &Device->DeviceID);
|
|
RtlAppendUnicodeStringToString(FullInstancePath, &PathSep);
|
|
RtlAppendUnicodeStringToString(FullInstancePath, &Device->InstanceID);
|
|
}
|
|
|
|
/* Initialize a device object */
|
|
Status = IoCreateDevice(
|
|
DriverObject ? DriverObject : IopRootDeviceNode->PhysicalDeviceObject->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%08lx\n", Status);
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
|
|
RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
|
|
PdoDeviceExtension->DeviceInfo = Device;
|
|
|
|
Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
|
|
Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
InsertTailList(
|
|
&DeviceExtension->DeviceListHead,
|
|
&Device->ListEntry);
|
|
DeviceExtension->DeviceListCount++;
|
|
|
|
*PhysicalDeviceObject = Device->Pdo;
|
|
DPRINT("Created PDO %p (%wZ\\%wZ)\n", *PhysicalDeviceObject, &Device->DeviceID, &Device->InstanceID);
|
|
Device = NULL;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
if (Device)
|
|
{
|
|
if (Device->Pdo)
|
|
IoDeleteDevice(Device->Pdo);
|
|
RtlFreeUnicodeString(&Device->DeviceID);
|
|
RtlFreeUnicodeString(&Device->InstanceID);
|
|
ExFreePoolWithTag(Device, TAG_PNP_ROOT);
|
|
}
|
|
RtlFreeUnicodeString(&DevicePath);
|
|
if (DeviceKeyHandle != NULL)
|
|
ObCloseHandle(DeviceKeyHandle, KernelMode);
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS NTAPI
|
|
QueryStringCallback(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext)
|
|
{
|
|
PUNICODE_STRING Destination = (PUNICODE_STRING)EntryContext;
|
|
UNICODE_STRING Source;
|
|
|
|
if (ValueType != REG_SZ || ValueLength == 0 || ValueLength % sizeof(WCHAR) != 0)
|
|
{
|
|
Destination->Length = 0;
|
|
Destination->MaximumLength = 0;
|
|
Destination->Buffer = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
Source.MaximumLength = Source.Length = (USHORT)ValueLength;
|
|
Source.Buffer = ValueData;
|
|
|
|
return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &Source, Destination);
|
|
}
|
|
|
|
static NTSTATUS NTAPI
|
|
QueryBinaryValueCallback(
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID ValueData,
|
|
IN ULONG ValueLength,
|
|
IN PVOID Context,
|
|
IN PVOID EntryContext)
|
|
{
|
|
PBUFFER Buffer = (PBUFFER)EntryContext;
|
|
PVOID BinaryValue;
|
|
|
|
if (ValueLength == 0)
|
|
{
|
|
*Buffer->Data = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
BinaryValue = ExAllocatePoolWithTag(PagedPool, ValueLength, TAG_PNP_ROOT);
|
|
if (BinaryValue == NULL)
|
|
return STATUS_NO_MEMORY;
|
|
RtlCopyMemory(BinaryValue, ValueData, ValueLength);
|
|
*Buffer->Data = BinaryValue;
|
|
if (Buffer->Length) *Buffer->Length = ValueLength;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
CreateDeviceFromRegistry(
|
|
_Inout_ PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension,
|
|
_Inout_ PUNICODE_STRING DevicePath,
|
|
_In_ PCWSTR InstanceId,
|
|
_In_ HANDLE SubKeyHandle)
|
|
{
|
|
NTSTATUS Status;
|
|
PPNPROOT_DEVICE Device;
|
|
HANDLE DeviceKeyHandle = NULL;
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[4];
|
|
BUFFER Buffer1, Buffer2;
|
|
|
|
/* If the device already exists, there's nothing to do */
|
|
Status = LocateChildDevice(DeviceExtension, DevicePath, InstanceId, &Device);
|
|
if (Status != STATUS_NO_SUCH_DEVICE)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Create a PPNPROOT_DEVICE object, and add it to the list of known devices */
|
|
Device = ExAllocatePoolWithTag(PagedPool, sizeof(PNPROOT_DEVICE), TAG_PNP_ROOT);
|
|
if (!Device)
|
|
{
|
|
DPRINT("ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
RtlZeroMemory(Device, sizeof(PNPROOT_DEVICE));
|
|
|
|
/* Fill device ID and instance ID */
|
|
Device->DeviceID = *DevicePath;
|
|
RtlInitEmptyUnicodeString(DevicePath, NULL, 0);
|
|
if (!RtlCreateUnicodeString(&Device->InstanceID, InstanceId))
|
|
{
|
|
DPRINT1("RtlCreateUnicodeString() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Open registry key to fill other informations */
|
|
Status = IopOpenRegistryKeyEx(&DeviceKeyHandle, SubKeyHandle, &Device->InstanceID, KEY_READ);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* If our key disappeared, let the caller go on */
|
|
DPRINT1("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
|
|
&Device->InstanceID, Status);
|
|
Status = STATUS_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Fill information from the device instance key */
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
QueryTable[0].QueryRoutine = QueryStringCallback;
|
|
QueryTable[0].Name = L"DeviceDesc";
|
|
QueryTable[0].EntryContext = &Device->DeviceDescription;
|
|
|
|
RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PCWSTR)DeviceKeyHandle,
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* Fill information from the LogConf subkey */
|
|
Buffer1.Data = (PVOID *)&Device->ResourceRequirementsList;
|
|
Buffer1.Length = NULL;
|
|
Buffer2.Data = (PVOID *)&Device->ResourceList;
|
|
Buffer2.Length = &Device->ResourceListSize;
|
|
RtlZeroMemory(QueryTable, sizeof(QueryTable));
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
|
|
QueryTable[0].Name = L"LogConf";
|
|
QueryTable[1].QueryRoutine = QueryBinaryValueCallback;
|
|
QueryTable[1].Name = L"BasicConfigVector";
|
|
QueryTable[1].EntryContext = &Buffer1;
|
|
QueryTable[2].QueryRoutine = QueryBinaryValueCallback;
|
|
QueryTable[2].Name = L"BootConfig";
|
|
QueryTable[2].EntryContext = &Buffer2;
|
|
|
|
if (!NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
|
|
(PCWSTR)DeviceKeyHandle,
|
|
QueryTable,
|
|
NULL,
|
|
NULL)))
|
|
{
|
|
/* Non-fatal error */
|
|
DPRINT1("Failed to read the LogConf key for %wZ\\%S\n", &Device->DeviceID, InstanceId);
|
|
}
|
|
|
|
/* Insert the newly created device into the list */
|
|
InsertTailList(&DeviceExtension->DeviceListHead,
|
|
&Device->ListEntry);
|
|
DeviceExtension->DeviceListCount++;
|
|
Device = NULL;
|
|
|
|
cleanup:
|
|
if (DeviceKeyHandle != NULL)
|
|
{
|
|
ZwClose(DeviceKeyHandle);
|
|
}
|
|
if (Device != NULL)
|
|
{
|
|
/* We have a device that has not been added to device list. We need to clean it up */
|
|
RtlFreeUnicodeString(&Device->DeviceID);
|
|
RtlFreeUnicodeString(&Device->InstanceID);
|
|
ExFreePoolWithTag(Device, TAG_PNP_ROOT);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS
|
|
IopShouldProcessDevice(
|
|
IN HANDLE SubKey,
|
|
IN PCWSTR InstanceID)
|
|
{
|
|
UNICODE_STRING DeviceReportedValue = RTL_CONSTANT_STRING(L"DeviceReported");
|
|
UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
|
|
UNICODE_STRING InstanceIDU;
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFullInformation;
|
|
HANDLE InstanceKey, ControlKey;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
ULONG Size, DeviceReported, ResultLength;
|
|
NTSTATUS Status;
|
|
|
|
Size = 128;
|
|
pKeyValueFullInformation = ExAllocatePool(PagedPool, Size);
|
|
if (!pKeyValueFullInformation)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Open Instance key */
|
|
RtlInitUnicodeString(&InstanceIDU, InstanceID);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&InstanceIDU,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
SubKey,
|
|
NULL);
|
|
Status = ZwOpenKey(&InstanceKey,
|
|
KEY_QUERY_VALUE,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(pKeyValueFullInformation);
|
|
return Status;
|
|
}
|
|
|
|
/* Read 'DeviceReported' Key */
|
|
Status = ZwQueryValueKey(InstanceKey, &DeviceReportedValue, KeyValueFullInformation, pKeyValueFullInformation, Size, &ResultLength);
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
|
{
|
|
ZwClose(InstanceKey);
|
|
ExFreePool(pKeyValueFullInformation);
|
|
DPRINT("No 'DeviceReported' value\n");
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
ZwClose(InstanceKey);
|
|
ExFreePool(pKeyValueFullInformation);
|
|
return Status;
|
|
}
|
|
if (pKeyValueFullInformation->Type != REG_DWORD || pKeyValueFullInformation->DataLength != sizeof(DeviceReported))
|
|
{
|
|
ZwClose(InstanceKey);
|
|
ExFreePool(pKeyValueFullInformation);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
RtlCopyMemory(&DeviceReported, (PVOID)((ULONG_PTR)pKeyValueFullInformation + pKeyValueFullInformation->DataOffset), sizeof(DeviceReported));
|
|
/* FIXME: Check DeviceReported value? */
|
|
ASSERT(DeviceReported == 1);
|
|
|
|
/* Open Control key */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&Control,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
InstanceKey,
|
|
NULL);
|
|
Status = ZwOpenKey(&ControlKey,
|
|
KEY_QUERY_VALUE,
|
|
&ObjectAttributes);
|
|
ZwClose(InstanceKey);
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
|
{
|
|
DPRINT("No 'Control' key\n");
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(pKeyValueFullInformation);
|
|
return Status;
|
|
}
|
|
|
|
/* Read 'DeviceReported' Key */
|
|
Status = ZwQueryValueKey(ControlKey, &DeviceReportedValue, KeyValueFullInformation, pKeyValueFullInformation, Size, &ResultLength);
|
|
ZwClose(ControlKey);
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
|
{
|
|
ExFreePool(pKeyValueFullInformation);
|
|
DPRINT("No 'DeviceReported' value\n");
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(pKeyValueFullInformation);
|
|
return Status;
|
|
}
|
|
if (pKeyValueFullInformation->Type != REG_DWORD || pKeyValueFullInformation->DataLength != sizeof(DeviceReported))
|
|
{
|
|
ExFreePool(pKeyValueFullInformation);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
RtlCopyMemory(&DeviceReported, (PVOID)((ULONG_PTR)pKeyValueFullInformation + pKeyValueFullInformation->DataOffset), sizeof(DeviceReported));
|
|
/* FIXME: Check DeviceReported value? */
|
|
ASSERT(DeviceReported == 1);
|
|
|
|
ExFreePool(pKeyValueFullInformation);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS
|
|
EnumerateDevices(
|
|
IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
|
|
PKEY_BASIC_INFORMATION KeyInfo = NULL, SubKeyInfo = NULL;
|
|
UNICODE_STRING LegacyU = RTL_CONSTANT_STRING(L"LEGACY_");
|
|
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\" REGSTR_PATH_SYSTEMENUM L"\\" REGSTR_KEY_ROOTENUM);
|
|
UNICODE_STRING SubKeyName;
|
|
UNICODE_STRING DevicePath;
|
|
HANDLE KeyHandle = NULL;
|
|
HANDLE SubKeyHandle = NULL;
|
|
ULONG KeyInfoSize, SubKeyInfoSize;
|
|
ULONG ResultSize;
|
|
ULONG Index1, Index2;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
DPRINT("EnumerateDevices(FDO %p)\n", DeviceObject);
|
|
|
|
DeviceExtension = &PnpRootDOExtension;
|
|
KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
|
|
/* Should hold most key names, but we reallocate below if it's too small */
|
|
KeyInfoSize = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + 64 * sizeof(WCHAR);
|
|
KeyInfo = ExAllocatePoolWithTag(PagedPool,
|
|
KeyInfoSize + sizeof(UNICODE_NULL),
|
|
TAG_PNP_ROOT);
|
|
if (!KeyInfo)
|
|
{
|
|
DPRINT("ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
SubKeyInfoSize = KeyInfoSize;
|
|
SubKeyInfo = ExAllocatePoolWithTag(PagedPool,
|
|
SubKeyInfoSize + sizeof(UNICODE_NULL),
|
|
TAG_PNP_ROOT);
|
|
if (!SubKeyInfo)
|
|
{
|
|
DPRINT("ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &KeyName, KEY_ENUMERATE_SUB_KEYS);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("IopOpenRegistryKeyEx(%wZ) failed with status 0x%08lx\n", &KeyName, Status);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Devices are sub-sub-keys of 'KeyName'. KeyName is already opened as
|
|
* KeyHandle. We'll first do a first enumeration to have first level keys,
|
|
* and an inner one to have the real devices list.
|
|
*/
|
|
Index1 = 0;
|
|
while (TRUE)
|
|
{
|
|
Status = ZwEnumerateKey(
|
|
KeyHandle,
|
|
Index1,
|
|
KeyBasicInformation,
|
|
KeyInfo,
|
|
KeyInfoSize,
|
|
&ResultSize);
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
else if (Status == STATUS_BUFFER_OVERFLOW ||
|
|
Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
ASSERT(KeyInfoSize < ResultSize);
|
|
KeyInfoSize = ResultSize;
|
|
ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
|
|
KeyInfo = ExAllocatePoolWithTag(PagedPool,
|
|
KeyInfoSize + sizeof(UNICODE_NULL),
|
|
TAG_PNP_ROOT);
|
|
if (!KeyInfo)
|
|
{
|
|
DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", KeyInfoSize);
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
continue;
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Terminate the string */
|
|
KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = 0;
|
|
|
|
/* Check if it is a legacy driver */
|
|
RtlInitUnicodeString(&SubKeyName, KeyInfo->Name);
|
|
if (RtlPrefixUnicodeString(&LegacyU, &SubKeyName, FALSE))
|
|
{
|
|
DPRINT("Ignoring legacy driver '%wZ'\n", &SubKeyName);
|
|
Index1++;
|
|
continue;
|
|
}
|
|
|
|
/* Open the key */
|
|
Status = IopOpenRegistryKeyEx(&SubKeyHandle, KeyHandle, &SubKeyName, KEY_ENUMERATE_SUB_KEYS);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("IopOpenRegistryKeyEx() failed for '%wZ' with status 0x%lx\n",
|
|
&SubKeyName, Status);
|
|
break;
|
|
}
|
|
|
|
/* Enumerate the sub-keys */
|
|
Index2 = 0;
|
|
while (TRUE)
|
|
{
|
|
Status = ZwEnumerateKey(
|
|
SubKeyHandle,
|
|
Index2,
|
|
KeyBasicInformation,
|
|
SubKeyInfo,
|
|
SubKeyInfoSize,
|
|
&ResultSize);
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
break;
|
|
}
|
|
else if (Status == STATUS_BUFFER_OVERFLOW ||
|
|
Status == STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
ASSERT(SubKeyInfoSize < ResultSize);
|
|
SubKeyInfoSize = ResultSize;
|
|
ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
|
|
SubKeyInfo = ExAllocatePoolWithTag(PagedPool,
|
|
SubKeyInfoSize + sizeof(UNICODE_NULL),
|
|
TAG_PNP_ROOT);
|
|
if (!SubKeyInfo)
|
|
{
|
|
DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", SubKeyInfoSize);
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
continue;
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
|
|
break;
|
|
}
|
|
|
|
/* Terminate the string */
|
|
SubKeyInfo->Name[SubKeyInfo->NameLength / sizeof(WCHAR)] = 0;
|
|
|
|
/* Compute device ID */
|
|
DevicePath.Length = 0;
|
|
DevicePath.MaximumLength = sizeof(REGSTR_KEY_ROOTENUM) + sizeof(L'\\') + SubKeyName.Length;
|
|
DevicePath.Buffer = ExAllocatePoolWithTag(PagedPool,
|
|
DevicePath.MaximumLength,
|
|
TAG_PNP_ROOT);
|
|
if (DevicePath.Buffer == NULL)
|
|
{
|
|
DPRINT1("ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
RtlAppendUnicodeToString(&DevicePath, REGSTR_KEY_ROOTENUM L"\\");
|
|
RtlAppendUnicodeStringToString(&DevicePath, &SubKeyName);
|
|
DPRINT("Found device %wZ\\%S!\n", &DevicePath, SubKeyInfo->Name);
|
|
|
|
Status = IopShouldProcessDevice(SubKeyHandle, SubKeyInfo->Name);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = CreateDeviceFromRegistry(DeviceExtension,
|
|
&DevicePath,
|
|
SubKeyInfo->Name,
|
|
SubKeyHandle);
|
|
|
|
/* If CreateDeviceFromRegistry didn't take ownership and zero this,
|
|
* we need to free it
|
|
*/
|
|
RtlFreeUnicodeString(&DevicePath);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else if (Status == STATUS_NO_SUCH_DEVICE)
|
|
{
|
|
DPRINT("Skipping device %wZ\\%S (not reported yet)\n", &DevicePath, SubKeyInfo->Name);
|
|
}
|
|
else
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
Index2++;
|
|
}
|
|
|
|
ZwClose(SubKeyHandle);
|
|
SubKeyHandle = NULL;
|
|
Index1++;
|
|
}
|
|
|
|
cleanup:
|
|
if (SubKeyHandle != NULL)
|
|
ZwClose(SubKeyHandle);
|
|
if (KeyHandle != NULL)
|
|
ZwClose(KeyHandle);
|
|
if (KeyInfo)
|
|
ExFreePoolWithTag(KeyInfo, TAG_PNP_ROOT);
|
|
if (SubKeyInfo)
|
|
ExFreePoolWithTag(SubKeyInfo, TAG_PNP_ROOT);
|
|
KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
return Status;
|
|
}
|
|
|
|
/* FUNCTION: Handle IRP_MN_QUERY_DEVICE_RELATIONS IRPs for the root bus device object
|
|
* ARGUMENTS:
|
|
* DeviceObject = Pointer to functional device object of the root bus driver
|
|
* Irp = Pointer to IRP that should be handled
|
|
* RETURNS:
|
|
* Status
|
|
*/
|
|
static NTSTATUS
|
|
PnpRootQueryDeviceRelations(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
|
|
PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_RELATIONS Relations = NULL, OtherRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
|
|
PPNPROOT_DEVICE Device = NULL;
|
|
ULONG Size;
|
|
NTSTATUS Status;
|
|
PLIST_ENTRY NextEntry;
|
|
|
|
DPRINT("PnpRootQueryDeviceRelations(FDO %p, Irp %p)\n", DeviceObject, Irp);
|
|
|
|
Status = EnumerateDevices(DeviceObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("EnumerateDevices() failed with status 0x%08lx\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
DeviceExtension = &PnpRootDOExtension;
|
|
|
|
Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + sizeof(PDEVICE_OBJECT) * DeviceExtension->DeviceListCount;
|
|
if (OtherRelations)
|
|
{
|
|
/* Another bus driver has already created a DEVICE_RELATIONS
|
|
* structure so we must merge this structure with our own */
|
|
|
|
Size += sizeof(PDEVICE_OBJECT) * OtherRelations->Count;
|
|
}
|
|
Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
|
|
if (!Relations)
|
|
{
|
|
DPRINT("ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
RtlZeroMemory(Relations, Size);
|
|
if (OtherRelations)
|
|
{
|
|
Relations->Count = OtherRelations->Count;
|
|
RtlCopyMemory(Relations->Objects, OtherRelations->Objects, sizeof(PDEVICE_OBJECT) * OtherRelations->Count);
|
|
}
|
|
|
|
KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
|
|
/* Start looping */
|
|
for (NextEntry = DeviceExtension->DeviceListHead.Flink;
|
|
NextEntry != &DeviceExtension->DeviceListHead;
|
|
NextEntry = NextEntry->Flink)
|
|
{
|
|
/* Get the entry */
|
|
Device = CONTAINING_RECORD(NextEntry, PNPROOT_DEVICE, ListEntry);
|
|
|
|
if (!Device->Pdo)
|
|
{
|
|
/* Create a physical device object for the
|
|
* device as it does not already have one */
|
|
Status = IoCreateDevice(
|
|
DeviceObject->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%08lx\n", Status);
|
|
break;
|
|
}
|
|
|
|
PdoDeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension;
|
|
RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
|
|
PdoDeviceExtension->DeviceInfo = Device;
|
|
|
|
Device->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
|
|
Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
}
|
|
|
|
/* Reference the physical device object. The PnP manager
|
|
will dereference it again when it is no longer needed */
|
|
ObReferenceObject(Device->Pdo);
|
|
|
|
Relations->Objects[Relations->Count++] = Device->Pdo;
|
|
}
|
|
KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)Relations;
|
|
|
|
cleanup:
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (OtherRelations)
|
|
ExFreePool(OtherRelations);
|
|
if (Relations)
|
|
ExFreePool(Relations);
|
|
if (Device && Device->Pdo)
|
|
{
|
|
IoDeleteDevice(Device->Pdo);
|
|
Device->Pdo = NULL;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* FUNCTION: Handle Plug and Play IRPs for the root bus device object
|
|
* ARGUMENTS:
|
|
* DeviceObject = Pointer to functional device object of the root bus driver
|
|
* Irp = Pointer to IRP that should be handled
|
|
* RETURNS:
|
|
* Status
|
|
*/
|
|
static NTSTATUS
|
|
PnpRootFdoPnpControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
NTSTATUS Status;
|
|
|
|
Status = Irp->IoStatus.Status;
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch (IrpSp->MinorFunction)
|
|
{
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
|
|
Status = PnpRootQueryDeviceRelations(DeviceObject, Irp);
|
|
break;
|
|
|
|
default:
|
|
// The root device object can receive only IRP_MN_QUERY_DEVICE_RELATIONS
|
|
ASSERT(FALSE);
|
|
DPRINT("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
|
|
break;
|
|
}
|
|
|
|
if (Status != STATUS_PENDING)
|
|
{
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS
|
|
PdoQueryDeviceRelations(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PDEVICE_RELATIONS Relations;
|
|
NTSTATUS Status = Irp->IoStatus.Status;
|
|
|
|
if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
|
|
return Status;
|
|
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
|
|
Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
|
if (!Relations)
|
|
{
|
|
DPRINT("ExAllocatePoolWithTag() failed\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
ObReferenceObject(DeviceObject);
|
|
Relations->Count = 1;
|
|
Relations->Objects[0] = DeviceObject;
|
|
Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = (ULONG_PTR)Relations;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS
|
|
PdoQueryCapabilities(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PDEVICE_CAPABILITIES DeviceCapabilities;
|
|
|
|
DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
|
|
|
|
if (DeviceCapabilities->Version != 1)
|
|
return STATUS_REVISION_MISMATCH;
|
|
|
|
DeviceCapabilities->UniqueID = TRUE;
|
|
/* FIXME: Fill other fields */
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS
|
|
PdoQueryResources(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
|
|
PCM_RESOURCE_LIST ResourceList;
|
|
|
|
DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (DeviceExtension->DeviceInfo->ResourceList)
|
|
{
|
|
/* Copy existing resource requirement list */
|
|
ResourceList = ExAllocatePool(
|
|
PagedPool,
|
|
DeviceExtension->DeviceInfo->ResourceListSize);
|
|
if (!ResourceList)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
RtlCopyMemory(
|
|
ResourceList,
|
|
DeviceExtension->DeviceInfo->ResourceList,
|
|
DeviceExtension->DeviceInfo->ResourceListSize);
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* No resources so just return without changing the status */
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
}
|
|
|
|
static NTSTATUS
|
|
PdoQueryResourceRequirements(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
|
|
|
|
DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (DeviceExtension->DeviceInfo->ResourceRequirementsList)
|
|
{
|
|
/* Copy existing resource requirement list */
|
|
ResourceList = ExAllocatePool(PagedPool, DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
|
|
if (!ResourceList)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
RtlCopyMemory(
|
|
ResourceList,
|
|
DeviceExtension->DeviceInfo->ResourceRequirementsList,
|
|
DeviceExtension->DeviceInfo->ResourceRequirementsList->ListSize);
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* No resource requirements so just return without changing the status */
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
}
|
|
|
|
static NTSTATUS
|
|
PdoQueryDeviceText(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
|
|
DEVICE_TEXT_TYPE DeviceTextType;
|
|
NTSTATUS Status = Irp->IoStatus.Status;
|
|
|
|
DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
DeviceTextType = IrpSp->Parameters.QueryDeviceText.DeviceTextType;
|
|
|
|
switch (DeviceTextType)
|
|
{
|
|
case DeviceTextDescription:
|
|
{
|
|
UNICODE_STRING String;
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
|
|
|
|
if (DeviceExtension->DeviceInfo->DeviceDescription.Buffer != NULL)
|
|
{
|
|
Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
|
|
&DeviceExtension->DeviceInfo->DeviceDescription,
|
|
&String);
|
|
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case DeviceTextLocationInformation:
|
|
{
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextLocationInformation\n");
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown query id type 0x%lx\n", DeviceTextType);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS
|
|
PdoQueryId(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
|
|
BUS_QUERY_ID_TYPE IdType;
|
|
NTSTATUS Status = Irp->IoStatus.Status;
|
|
|
|
DeviceExtension = (PPNPROOT_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
IdType = IrpSp->Parameters.QueryId.IdType;
|
|
|
|
switch (IdType)
|
|
{
|
|
case BusQueryDeviceID:
|
|
{
|
|
UNICODE_STRING String;
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
|
|
|
|
Status = RtlDuplicateUnicodeString(
|
|
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
|
|
&DeviceExtension->DeviceInfo->DeviceID,
|
|
&String);
|
|
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
|
|
break;
|
|
}
|
|
|
|
case BusQueryHardwareIDs:
|
|
case BusQueryCompatibleIDs:
|
|
{
|
|
/* Optional, do nothing */
|
|
break;
|
|
}
|
|
|
|
case BusQueryInstanceID:
|
|
{
|
|
UNICODE_STRING String;
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
|
|
|
|
Status = RtlDuplicateUnicodeString(
|
|
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
|
|
&DeviceExtension->DeviceInfo->InstanceID,
|
|
&String);
|
|
Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS
|
|
PdoQueryBusInformation(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PPNP_BUS_INFORMATION BusInfo;
|
|
NTSTATUS Status;
|
|
|
|
BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PNP_ROOT);
|
|
if (!BusInfo)
|
|
Status = STATUS_NO_MEMORY;
|
|
else
|
|
{
|
|
RtlCopyMemory(
|
|
&BusInfo->BusTypeGuid,
|
|
&GUID_BUS_TYPE_INTERNAL,
|
|
sizeof(BusInfo->BusTypeGuid));
|
|
BusInfo->LegacyBusType = PNPBus;
|
|
/* We're the only root bus enumerator on the computer */
|
|
BusInfo->BusNumber = 0;
|
|
Irp->IoStatus.Information = (ULONG_PTR)BusInfo;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* 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
|
|
*/
|
|
static NTSTATUS
|
|
PnpRootPdoPnpControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PPNPROOT_PDO_DEVICE_EXTENSION DeviceExtension;
|
|
PPNPROOT_FDO_DEVICE_EXTENSION FdoDeviceExtension;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
NTSTATUS Status;
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
FdoDeviceExtension = &PnpRootDOExtension;
|
|
Status = Irp->IoStatus.Status;
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch (IrpSp->MinorFunction)
|
|
{
|
|
case IRP_MN_START_DEVICE: /* 0x00 */
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
|
|
Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
|
|
Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCES: /* 0x0a */
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
|
|
Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
|
|
Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
|
|
Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
|
|
break;
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
/* Remove the device from the device list and decrement the device count*/
|
|
KeAcquireGuardedMutex(&FdoDeviceExtension->DeviceListLock);
|
|
RemoveEntryList(&DeviceExtension->DeviceInfo->ListEntry);
|
|
FdoDeviceExtension->DeviceListCount--;
|
|
KeReleaseGuardedMutex(&FdoDeviceExtension->DeviceListLock);
|
|
|
|
/* Free some strings we created */
|
|
RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceDescription);
|
|
RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->DeviceID);
|
|
RtlFreeUnicodeString(&DeviceExtension->DeviceInfo->InstanceID);
|
|
|
|
/* Free the resource requirements list */
|
|
if (DeviceExtension->DeviceInfo->ResourceRequirementsList != NULL)
|
|
ExFreePool(DeviceExtension->DeviceInfo->ResourceRequirementsList);
|
|
|
|
/* Free the boot resources list */
|
|
if (DeviceExtension->DeviceInfo->ResourceList != NULL)
|
|
ExFreePool(DeviceExtension->DeviceInfo->ResourceList);
|
|
|
|
/* Free the device info */
|
|
ExFreePool(DeviceExtension->DeviceInfo);
|
|
|
|
/* Finally, delete the device object */
|
|
IoDeleteDevice(DeviceObject);
|
|
|
|
/* Return success */
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case IRP_MN_QUERY_ID: /* 0x13 */
|
|
Status = PdoQueryId(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
|
|
break;
|
|
|
|
case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
|
|
DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
|
|
Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
|
|
break;
|
|
|
|
default:
|
|
DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", IrpSp->MinorFunction);
|
|
break;
|
|
}
|
|
|
|
if (Status != STATUS_PENDING)
|
|
{
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* FUNCTION: Handle Plug and Play IRPs
|
|
* ARGUMENTS:
|
|
* DeviceObject = Pointer to PDO or FDO
|
|
* Irp = Pointer to IRP that should be handled
|
|
* RETURNS:
|
|
* Status
|
|
*/
|
|
static NTSTATUS NTAPI
|
|
PnpRootPnpControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (IopRootDeviceNode == IopGetDeviceNode(DeviceObject))
|
|
Status = PnpRootFdoPnpControl(DeviceObject, Irp);
|
|
else
|
|
Status = PnpRootPdoPnpControl(DeviceObject, Irp);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* FUNCTION: Handle Power IRPs
|
|
* ARGUMENTS:
|
|
* DeviceObject = Pointer to PDO or FDO
|
|
* Irp = Pointer to IRP that should be handled
|
|
* RETURNS:
|
|
* Status
|
|
*/
|
|
static NTSTATUS NTAPI
|
|
PnpRootPowerControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS Status = Irp->IoStatus.Status;
|
|
|
|
switch (IrpSp->MinorFunction)
|
|
{
|
|
case IRP_MN_QUERY_POWER:
|
|
case IRP_MN_SET_POWER:
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
Irp->IoStatus.Status = Status;
|
|
PoStartNextPowerIrp(Irp);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
PnpRootInitializeDevExtension(VOID)
|
|
{
|
|
PnpRootDOExtension.DeviceListCount = 0;
|
|
InitializeListHead(&PnpRootDOExtension.DeviceListHead);
|
|
KeInitializeGuardedMutex(&PnpRootDOExtension.DeviceListLock);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
PnpRootAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject)
|
|
{
|
|
// AddDevice must never be called for the root driver
|
|
ASSERT(FALSE);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#if MI_TRACE_PFNS
|
|
PDEVICE_OBJECT IopPfnDumpDeviceObject;
|
|
|
|
NTSTATUS NTAPI
|
|
PnpRootCreateClose(
|
|
_In_ PDEVICE_OBJECT DeviceObject,
|
|
_In_ PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
|
|
if (DeviceObject != IopPfnDumpDeviceObject)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
if (IoStack->MajorFunction == IRP_MJ_CREATE)
|
|
{
|
|
MmDumpArmPfnDatabase(TRUE);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS NTAPI
|
|
PnpRootDriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath)
|
|
{
|
|
#if MI_TRACE_PFNS
|
|
NTSTATUS Status;
|
|
UNICODE_STRING PfnDumpDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PfnDump");
|
|
#endif
|
|
|
|
DPRINT("PnpRootDriverEntry(%p %wZ)\n", DriverObject, RegistryPath);
|
|
|
|
IopRootDriverObject = DriverObject;
|
|
|
|
DriverObject->DriverExtension->AddDevice = PnpRootAddDevice;
|
|
|
|
#if MI_TRACE_PFNS
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = PnpRootCreateClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = PnpRootCreateClose;
|
|
#endif
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = PnpRootPnpControl;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = PnpRootPowerControl;
|
|
|
|
#if MI_TRACE_PFNS
|
|
Status = IoCreateDevice(DriverObject,
|
|
0,
|
|
&PfnDumpDeviceName,
|
|
FILE_DEVICE_UNKNOWN,
|
|
0,
|
|
FALSE,
|
|
&IopPfnDumpDeviceObject);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Creating PFN Dump device failed with %lx\n", Status);
|
|
}
|
|
else
|
|
{
|
|
IopPfnDumpDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
}
|
|
#endif
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|