mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
6cac5b8c9e
- Remove unused "DriverObject" argument - Make "FullInstancePath" mandatory - Extract the PDO creation into separate function, it will be used later
1529 lines
48 KiB
C
1529 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_PDO_DEVICE_EXTENSION PdoDeviceExtension;
|
|
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;
|
|
|
|
PdoDeviceExtension = DeviceObject->DeviceExtension;
|
|
RtlZeroMemory(PdoDeviceExtension, sizeof(PNPROOT_PDO_DEVICE_EXTENSION));
|
|
PdoDeviceExtension->DeviceInfo = Device;
|
|
|
|
KeAcquireGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
InsertTailList(&DeviceExtension->DeviceListHead,
|
|
&Device->ListEntry);
|
|
DeviceExtension->DeviceListCount++;
|
|
KeReleaseGuardedMutex(&DeviceExtension->DeviceListLock);
|
|
|
|
RtlFreeUnicodeString(&InstancePathCopy);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PnpRootCreateDeviceObject(
|
|
OUT PDEVICE_OBJECT *DeviceObject)
|
|
{
|
|
NTSTATUS status = IoCreateDevice(
|
|
IopRootDriverObject,
|
|
sizeof(PNPROOT_PDO_DEVICE_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_CONTROLLER,
|
|
FILE_AUTOGENERATED_DEVICE_NAME,
|
|
FALSE,
|
|
DeviceObject);
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Creates a new PnP device for a legacy driver */
|
|
NTSTATUS
|
|
PnpRootCreateDevice(
|
|
IN PUNICODE_STRING ServiceName,
|
|
OUT PDEVICE_OBJECT *PhysicalDeviceObject,
|
|
OUT 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;
|
|
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; // "Root\<service_name>"
|
|
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;
|
|
}
|
|
|
|
// "0000" or higher
|
|
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);
|
|
|
|
// generate the full device instance path
|
|
FullInstancePath->MaximumLength = Device->DeviceID.Length + sizeof(L'\\') + 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);
|
|
RtlAppendUnicodeToString(FullInstancePath, L"\\");
|
|
RtlAppendUnicodeStringToString(FullInstancePath, &Device->InstanceID);
|
|
|
|
/* Initialize a device object */
|
|
Status = PnpRootCreateDeviceObject(&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 = PnpRootCreateDeviceObject(&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;
|
|
}
|