/* * 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 #define NDEBUG #include /* 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\" 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; }