From 21e9e2baa57b744f2367b702c23f580611adad6c Mon Sep 17 00:00:00 2001 From: Victor Perevertkin Date: Sun, 21 Jun 2020 17:54:44 +0300 Subject: [PATCH] [NTOS:IO] Move device manipulation functions from pnpmgr/pnpmgr.c to pnpmgr/devaction.c And rearrange them in more logical order. This effectively splits the file, leaving public "Io" functions in pnpmgr.c along with some things not related do device object management. Functions which manipulate the device tree are left in devaction.c. In future all these functions will only be accessed from DeviceActionWorker. While being public API, IoRequestDeviceEject and IoInvalidateDeviceState have been moved to devaction.c as well. In next commits they will be converted to DeviceActionWorker routines and their callers will be put in pnpmgr.c --- ntoskrnl/io/pnpmgr/devaction.c | 2375 ++++++++++++++++++++++++++++++++ ntoskrnl/io/pnpmgr/pnpmgr.c | 2328 ------------------------------- ntoskrnl/ntos.cmake | 1 + 3 files changed, 2376 insertions(+), 2328 deletions(-) create mode 100644 ntoskrnl/io/pnpmgr/devaction.c diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c new file mode 100644 index 00000000000..16877098994 --- /dev/null +++ b/ntoskrnl/io/pnpmgr/devaction.c @@ -0,0 +1,2375 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: PnP manager device manipulation functions + * COPYRIGHT: Casper S. Hornstrup (chorns@users.sourceforge.net) + * 2007 Hervé Poussineau (hpoussin@reactos.org) + * 2014-2017 Thomas Faber (thomas.faber@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +extern ERESOURCE IopDriverLoadResource; +extern BOOLEAN PnpSystemInit; +extern PDEVICE_NODE IopRootDeviceNode; + +#define MAX_DEVICE_ID_LEN 200 +#define MAX_SEPARATORS_INSTANCEID 0 +#define MAX_SEPARATORS_DEVICEID 1 + +/* DATA **********************************************************************/ + +LIST_ENTRY IopDeviceActionRequestList; +WORK_QUEUE_ITEM IopDeviceActionWorkItem; +BOOLEAN IopDeviceActionInProgress; +KSPIN_LOCK IopDeviceActionLock; + +/* FUNCTIONS *****************************************************************/ + +PDEVICE_OBJECT +IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance); + +NTSTATUS +IopGetParentIdPrefix(PDEVICE_NODE DeviceNode, PUNICODE_STRING ParentIdPrefix); + +USHORT +NTAPI +IopGetBusTypeGuidIndex(LPGUID BusTypeGuid); + +NTSTATUS +IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode); + +VOID +NTAPI +IopInstallCriticalDevice(PDEVICE_NODE DeviceNode); + +static +VOID +IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject); + +static +NTSTATUS +IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force); + +static +BOOLEAN +IopValidateID( + _In_ PWCHAR Id, + _In_ BUS_QUERY_ID_TYPE QueryType) +{ + PWCHAR PtrChar; + PWCHAR StringEnd; + WCHAR Char; + ULONG SeparatorsCount = 0; + PWCHAR PtrPrevChar = NULL; + ULONG MaxSeparators; + BOOLEAN IsMultiSz; + + PAGED_CODE(); + + switch (QueryType) + { + case BusQueryDeviceID: + MaxSeparators = MAX_SEPARATORS_DEVICEID; + IsMultiSz = FALSE; + break; + case BusQueryInstanceID: + MaxSeparators = MAX_SEPARATORS_INSTANCEID; + IsMultiSz = FALSE; + break; + + case BusQueryHardwareIDs: + case BusQueryCompatibleIDs: + MaxSeparators = MAX_SEPARATORS_DEVICEID; + IsMultiSz = TRUE; + break; + + default: + DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType); + return FALSE; + } + + StringEnd = Id + MAX_DEVICE_ID_LEN; + + for (PtrChar = Id; PtrChar < StringEnd; PtrChar++) + { + Char = *PtrChar; + + if (Char == UNICODE_NULL) + { + if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1)) + { + if (MaxSeparators == SeparatorsCount || IsMultiSz) + { + return TRUE; + } + + DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", + SeparatorsCount, MaxSeparators); + goto ErrorExit; + } + + StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1; + PtrPrevChar = PtrChar; + SeparatorsCount = 0; + } + else if (Char < ' ' || Char > 0x7F || Char == ',') + { + DPRINT1("IopValidateID: Invalid character - %04X\n", Char); + goto ErrorExit; + } + else if (Char == ' ') + { + *PtrChar = '_'; + } + else if (Char == '\\') + { + SeparatorsCount++; + + if (SeparatorsCount > MaxSeparators) + { + DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", + SeparatorsCount, MaxSeparators); + goto ErrorExit; + } + } + } + + DPRINT1("IopValidateID: Not terminated ID\n"); + +ErrorExit: + // FIXME logging + return FALSE; +} + +static +NTSTATUS +IopCreateDeviceInstancePath( + _In_ PDEVICE_NODE DeviceNode, + _Out_ PUNICODE_STRING InstancePath) +{ + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING DeviceId; + UNICODE_STRING InstanceId; + IO_STACK_LOCATION Stack; + NTSTATUS Status; + UNICODE_STRING ParentIdPrefix = { 0, 0, NULL }; + DEVICE_CAPABILITIES DeviceCapabilities; + BOOLEAN IsValidID; + + DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n"); + + Stack.Parameters.QueryId.IdType = BusQueryDeviceID; + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_ID, + &Stack); + if (!NT_SUCCESS(Status)) + { + DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status); + return Status; + } + + IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID); + + if (!IsValidID) + { + DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode); + } + + /* Save the device id string */ + RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information); + + DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n"); + + Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); + if (!NT_SUCCESS(Status)) + { + DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status); + RtlFreeUnicodeString(&DeviceId); + return Status; + } + + /* This bit is only check after enumeration */ + if (DeviceCapabilities.HardwareDisabled) + { + /* FIXME: Cleanup device */ + DeviceNode->Flags |= DNF_DISABLED; + RtlFreeUnicodeString(&DeviceId); + return STATUS_PLUGPLAY_NO_DEVICE; + } + else + { + DeviceNode->Flags &= ~DNF_DISABLED; + } + + if (!DeviceCapabilities.UniqueID) + { + /* Device has not a unique ID. We need to prepend parent bus unique identifier */ + DPRINT("Instance ID is not unique\n"); + Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix); + if (!NT_SUCCESS(Status)) + { + DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status); + RtlFreeUnicodeString(&DeviceId); + return Status; + } + } + + DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n"); + + Stack.Parameters.QueryId.IdType = BusQueryInstanceID; + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_ID, + &Stack); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status); + ASSERT(IoStatusBlock.Information == 0); + } + + if (IoStatusBlock.Information) + { + IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID); + + if (!IsValidID) + { + DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode); + } + } + + RtlInitUnicodeString(&InstanceId, + (PWSTR)IoStatusBlock.Information); + + InstancePath->Length = 0; + InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) + + ParentIdPrefix.Length + + InstanceId.Length + + sizeof(UNICODE_NULL); + if (ParentIdPrefix.Length && InstanceId.Length) + { + InstancePath->MaximumLength += sizeof(WCHAR); + } + + InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool, + InstancePath->MaximumLength, + TAG_IO); + if (!InstancePath->Buffer) + { + RtlFreeUnicodeString(&InstanceId); + RtlFreeUnicodeString(&ParentIdPrefix); + RtlFreeUnicodeString(&DeviceId); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Start with the device id */ + RtlCopyUnicodeString(InstancePath, &DeviceId); + RtlAppendUnicodeToString(InstancePath, L"\\"); + + /* Add information from parent bus device to InstancePath */ + RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix); + if (ParentIdPrefix.Length && InstanceId.Length) + { + RtlAppendUnicodeToString(InstancePath, L"&"); + } + + /* Finally, add the id returned by the driver stack */ + RtlAppendUnicodeStringToString(InstancePath, &InstanceId); + + /* + * FIXME: Check for valid characters, if there is invalid characters + * then bugcheck + */ + + RtlFreeUnicodeString(&InstanceId); + RtlFreeUnicodeString(&DeviceId); + RtlFreeUnicodeString(&ParentIdPrefix); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode, + PDEVICE_CAPABILITIES DeviceCaps) +{ + IO_STATUS_BLOCK StatusBlock; + IO_STACK_LOCATION Stack; + NTSTATUS Status; + HANDLE InstanceKey; + UNICODE_STRING ValueName; + + /* Set up the Header */ + RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES)); + DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES); + DeviceCaps->Version = 1; + DeviceCaps->Address = -1; + DeviceCaps->UINumber = -1; + + /* Set up the Stack */ + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps; + + /* Send the IRP */ + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &StatusBlock, + IRP_MN_QUERY_CAPABILITIES, + &Stack); + if (!NT_SUCCESS(Status)) + { + if (Status != STATUS_NOT_SUPPORTED) + { + DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status); + } + return Status; + } + + /* Map device capabilities to capability flags */ + DeviceNode->CapabilityFlags = 0; + if (DeviceCaps->LockSupported) + DeviceNode->CapabilityFlags |= 0x00000001; // CM_DEVCAP_LOCKSUPPORTED + + if (DeviceCaps->EjectSupported) + DeviceNode->CapabilityFlags |= 0x00000002; // CM_DEVCAP_EJECTSUPPORTED + + if (DeviceCaps->Removable) + DeviceNode->CapabilityFlags |= 0x00000004; // CM_DEVCAP_REMOVABLE + + if (DeviceCaps->DockDevice) + DeviceNode->CapabilityFlags |= 0x00000008; // CM_DEVCAP_DOCKDEVICE + + if (DeviceCaps->UniqueID) + DeviceNode->CapabilityFlags |= 0x00000010; // CM_DEVCAP_UNIQUEID + + if (DeviceCaps->SilentInstall) + DeviceNode->CapabilityFlags |= 0x00000020; // CM_DEVCAP_SILENTINSTALL + + if (DeviceCaps->RawDeviceOK) + DeviceNode->CapabilityFlags |= 0x00000040; // CM_DEVCAP_RAWDEVICEOK + + if (DeviceCaps->SurpriseRemovalOK) + DeviceNode->CapabilityFlags |= 0x00000080; // CM_DEVCAP_SURPRISEREMOVALOK + + if (DeviceCaps->HardwareDisabled) + DeviceNode->CapabilityFlags |= 0x00000100; // CM_DEVCAP_HARDWAREDISABLED + + if (DeviceCaps->NonDynamic) + DeviceNode->CapabilityFlags |= 0x00000200; // CM_DEVCAP_NONDYNAMIC + + if (DeviceCaps->NoDisplayInUI) + DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; + else + DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; + + Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); + if (NT_SUCCESS(Status)) + { + /* Set 'Capabilities' value */ + RtlInitUnicodeString(&ValueName, L"Capabilities"); + Status = ZwSetValueKey(InstanceKey, + &ValueName, + 0, + REG_DWORD, + &DeviceNode->CapabilityFlags, + sizeof(ULONG)); + + /* Set 'UINumber' value */ + if (DeviceCaps->UINumber != MAXULONG) + { + RtlInitUnicodeString(&ValueName, L"UINumber"); + Status = ZwSetValueKey(InstanceKey, + &ValueName, + 0, + REG_DWORD, + &DeviceCaps->UINumber, + sizeof(ULONG)); + } + + ZwClose(InstanceKey); + } + + return Status; +} + +static +NTSTATUS +IopQueryHardwareIds(PDEVICE_NODE DeviceNode, + HANDLE InstanceKey) +{ + IO_STACK_LOCATION Stack; + IO_STATUS_BLOCK IoStatusBlock; + PWSTR Ptr; + UNICODE_STRING ValueName; + NTSTATUS Status; + ULONG Length, TotalLength; + BOOLEAN IsValidID; + + DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n"); + + RtlZeroMemory(&Stack, sizeof(Stack)); + Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs; + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_ID, + &Stack); + if (NT_SUCCESS(Status)) + { + IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs); + + if (!IsValidID) + { + DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode); + } + + TotalLength = 0; + + Ptr = (PWSTR)IoStatusBlock.Information; + DPRINT("Hardware IDs:\n"); + while (*Ptr) + { + DPRINT(" %S\n", Ptr); + Length = (ULONG)wcslen(Ptr) + 1; + + Ptr += Length; + TotalLength += Length; + } + DPRINT("TotalLength: %hu\n", TotalLength); + DPRINT("\n"); + + RtlInitUnicodeString(&ValueName, L"HardwareID"); + Status = ZwSetValueKey(InstanceKey, + &ValueName, + 0, + REG_MULTI_SZ, + (PVOID)IoStatusBlock.Information, + (TotalLength + 1) * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); + } + } + else + { + DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); + } + + return Status; +} + +static +NTSTATUS +IopQueryCompatibleIds(PDEVICE_NODE DeviceNode, + HANDLE InstanceKey) +{ + IO_STACK_LOCATION Stack; + IO_STATUS_BLOCK IoStatusBlock; + PWSTR Ptr; + UNICODE_STRING ValueName; + NTSTATUS Status; + ULONG Length, TotalLength; + BOOLEAN IsValidID; + + DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n"); + + RtlZeroMemory(&Stack, sizeof(Stack)); + Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs; + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_ID, + &Stack); + if (NT_SUCCESS(Status) && IoStatusBlock.Information) + { + IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs); + + if (!IsValidID) + { + DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode); + } + + TotalLength = 0; + + Ptr = (PWSTR)IoStatusBlock.Information; + DPRINT("Compatible IDs:\n"); + while (*Ptr) + { + DPRINT(" %S\n", Ptr); + Length = (ULONG)wcslen(Ptr) + 1; + + Ptr += Length; + TotalLength += Length; + } + DPRINT("TotalLength: %hu\n", TotalLength); + DPRINT("\n"); + + RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); + Status = ZwSetValueKey(InstanceKey, + &ValueName, + 0, + REG_MULTI_SZ, + (PVOID)IoStatusBlock.Information, + (TotalLength + 1) * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status); + } + } + else + { + DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); + } + + return Status; +} + +/* + * IopActionInterrogateDeviceStack + * + * Retrieve information for all (direct) child nodes of a parent node. + * + * Parameters + * DeviceNode + * Pointer to device node. + * Context + * Pointer to parent node to retrieve child node information for. + * + * Remarks + * Any errors that occur are logged instead so that all child services have a chance + * of being interrogated. + */ + +NTSTATUS +IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, + PVOID Context) +{ + IO_STATUS_BLOCK IoStatusBlock; + PWSTR DeviceDescription; + PWSTR LocationInformation; + PDEVICE_NODE ParentDeviceNode; + IO_STACK_LOCATION Stack; + NTSTATUS Status; + ULONG RequiredLength; + LCID LocaleId; + HANDLE InstanceKey = NULL; + UNICODE_STRING ValueName; + UNICODE_STRING InstancePathU; + PDEVICE_OBJECT OldDeviceObject; + + DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context); + DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject); + + ParentDeviceNode = (PDEVICE_NODE)Context; + + /* + * We are called for the parent too, but we don't need to do special + * handling for this node + */ + if (DeviceNode == ParentDeviceNode) + { + DPRINT("Success\n"); + return STATUS_SUCCESS; + } + + /* + * Make sure this device node is a direct child of the parent device node + * that is given as an argument + */ + if (DeviceNode->Parent != ParentDeviceNode) + { + DPRINT("Skipping 2+ level child\n"); + return STATUS_SUCCESS; + } + + /* Skip processing if it was already completed before */ + if (DeviceNode->Flags & DNF_PROCESSED) + { + /* Nothing to do */ + return STATUS_SUCCESS; + } + + /* Get Locale ID */ + Status = ZwQueryDefaultLocale(FALSE, &LocaleId); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status); + return Status; + } + + /* + * FIXME: For critical errors, cleanup and disable device, but always + * return STATUS_SUCCESS. + */ + + Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU); + if (!NT_SUCCESS(Status)) + { + if (Status != STATUS_PLUGPLAY_NO_DEVICE) + { + DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status); + } + + /* We have to return success otherwise we abort the traverse operation */ + return STATUS_SUCCESS; + } + + /* Verify that this is not a duplicate */ + OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU); + if (OldDeviceObject != NULL) + { + PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject); + + DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU); + DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath); + DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath); + + KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, + 0x01, + (ULONG_PTR)DeviceNode->PhysicalDeviceObject, + (ULONG_PTR)OldDeviceObject, + 0); + } + + DeviceNode->InstancePath = InstancePathU; + + DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer); + + /* + * Create registry key for the instance id, if it doesn't exist yet + */ + Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create the instance key! (Status %lx)\n", Status); + + /* We have to return success otherwise we abort the traverse operation */ + return STATUS_SUCCESS; + } + + IopQueryHardwareIds(DeviceNode, InstanceKey); + + IopQueryCompatibleIds(DeviceNode, InstanceKey); + + DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n"); + + Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription; + Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_DEVICE_TEXT, + &Stack); + DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information + : NULL; + /* This key is mandatory, so even if the Irp fails, we still write it */ + RtlInitUnicodeString(&ValueName, L"DeviceDesc"); + if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) + { + if (DeviceDescription && + *DeviceDescription != UNICODE_NULL) + { + /* This key is overriden when a driver is installed. Don't write the + * new description if another one already exists */ + Status = ZwSetValueKey(InstanceKey, + &ValueName, + 0, + REG_SZ, + DeviceDescription, + ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR)); + } + else + { + UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device"); + DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status); + + Status = ZwSetValueKey(InstanceKey, + &ValueName, + 0, + REG_SZ, + DeviceDesc.Buffer, + DeviceDesc.MaximumLength); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status); + } + + } + } + + if (DeviceDescription) + { + ExFreePoolWithTag(DeviceDescription, 0); + } + + DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n"); + + Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation; + Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_DEVICE_TEXT, + &Stack); + if (NT_SUCCESS(Status) && IoStatusBlock.Information) + { + LocationInformation = (PWSTR)IoStatusBlock.Information; + DPRINT("LocationInformation: %S\n", LocationInformation); + RtlInitUnicodeString(&ValueName, L"LocationInformation"); + Status = ZwSetValueKey(InstanceKey, + &ValueName, + 0, + REG_SZ, + LocationInformation, + ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); + } + + ExFreePoolWithTag(LocationInformation, 0); + } + else + { + DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); + } + + DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n"); + + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_BUS_INFORMATION, + NULL); + if (NT_SUCCESS(Status) && IoStatusBlock.Information) + { + PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information; + + DeviceNode->ChildBusNumber = BusInformation->BusNumber; + DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType; + DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid); + ExFreePoolWithTag(BusInformation, 0); + } + else + { + DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); + + DeviceNode->ChildBusNumber = 0xFFFFFFF0; + DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; + DeviceNode->ChildBusTypeIndex = -1; + } + + DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); + + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_RESOURCES, + NULL); + if (NT_SUCCESS(Status) && IoStatusBlock.Information) + { + DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information; + IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); + } + else + { + DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); + DeviceNode->BootResources = NULL; + } + + DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); + + Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_RESOURCE_REQUIREMENTS, + NULL); + if (NT_SUCCESS(Status)) + { + DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; + } + else + { + DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); + DeviceNode->ResourceRequirements = NULL; + } + + if (InstanceKey != NULL) + { + IopSetDeviceInstanceData(InstanceKey, DeviceNode); + } + + ZwClose(InstanceKey); + + IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED); + + if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER)) + { + /* Report the device to the user-mode pnp manager */ + IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED, + &DeviceNode->InstancePath); + } + + return STATUS_SUCCESS; +} + +/* + * IopActionConfigureChildServices + * + * Retrieve configuration for all (direct) child nodes of a parent node. + * + * Parameters + * DeviceNode + * Pointer to device node. + * Context + * Pointer to parent node to retrieve child node configuration for. + * + * Remarks + * Any errors that occur are logged instead so that all child services have a chance of beeing + * configured. + */ + +NTSTATUS +IopActionConfigureChildServices(PDEVICE_NODE DeviceNode, + PVOID Context) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[3]; + PDEVICE_NODE ParentDeviceNode; + PUNICODE_STRING Service; + UNICODE_STRING ClassGUID; + NTSTATUS Status; + DEVICE_CAPABILITIES DeviceCaps; + + DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context); + + ParentDeviceNode = (PDEVICE_NODE)Context; + + /* + * We are called for the parent too, but we don't need to do special + * handling for this node + */ + if (DeviceNode == ParentDeviceNode) + { + DPRINT("Success\n"); + return STATUS_SUCCESS; + } + + /* + * Make sure this device node is a direct child of the parent device node + * that is given as an argument + */ + + if (DeviceNode->Parent != ParentDeviceNode) + { + DPRINT("Skipping 2+ level child\n"); + return STATUS_SUCCESS; + } + + if (!(DeviceNode->Flags & DNF_PROCESSED)) + { + DPRINT1("Child not ready to be configured\n"); + return STATUS_SUCCESS; + } + + if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED))) + { + UNICODE_STRING RegKey; + + /* Install the service for this if it's in the CDDB */ + IopInstallCriticalDevice(DeviceNode); + + /* + * Retrieve configuration from Enum key + */ + + Service = &DeviceNode->ServiceName; + + RtlZeroMemory(QueryTable, sizeof(QueryTable)); + RtlInitUnicodeString(Service, NULL); + RtlInitUnicodeString(&ClassGUID, NULL); + + QueryTable[0].Name = L"Service"; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[0].EntryContext = Service; + + QueryTable[1].Name = L"ClassGUID"; + QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[1].EntryContext = &ClassGUID; + QueryTable[1].DefaultType = REG_SZ; + QueryTable[1].DefaultData = L""; + QueryTable[1].DefaultLength = 0; + + RegKey.Length = 0; + RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) + DeviceNode->InstancePath.Length; + RegKey.Buffer = ExAllocatePoolWithTag(PagedPool, + RegKey.MaximumLength, + TAG_IO); + if (RegKey.Buffer == NULL) + { + IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeToString(&RegKey, ENUM_ROOT); + RtlAppendUnicodeToString(&RegKey, L"\\"); + RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath); + + Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, + RegKey.Buffer, QueryTable, NULL, NULL); + ExFreePoolWithTag(RegKey.Buffer, TAG_IO); + + if (!NT_SUCCESS(Status)) + { + /* FIXME: Log the error */ + DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n", + &DeviceNode->InstancePath, Status); + IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); + return STATUS_SUCCESS; + } + + if (Service->Buffer == NULL) + { + if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) && + DeviceCaps.RawDeviceOK) + { + DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName); + RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0); + } + else if (ClassGUID.Length != 0) + { + /* Device has a ClassGUID value, but no Service value. + * Suppose it is using the NULL driver, so state the + * device is started */ + DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath); + IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); + } + else + { + DeviceNode->Problem = CM_PROB_FAILED_INSTALL; + IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); + } + return STATUS_SUCCESS; + } + + DPRINT("Got Service %S\n", Service->Buffer); + } + + return STATUS_SUCCESS; +} + +/* + * IopActionInitChildServices + * + * Initialize the service for all (direct) child nodes of a parent node + * + * Parameters + * DeviceNode + * Pointer to device node. + * Context + * Pointer to parent node to initialize child node services for. + * + * Remarks + * If the driver image for a service is not loaded and initialized + * it is done here too. Any errors that occur are logged instead so + * that all child services have a chance of being initialized. + */ + +NTSTATUS +IopActionInitChildServices(PDEVICE_NODE DeviceNode, + PVOID Context) +{ + PDEVICE_NODE ParentDeviceNode; + NTSTATUS Status; + BOOLEAN BootDrivers = !PnpSystemInit; + + DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context); + + ParentDeviceNode = Context; + + /* + * We are called for the parent too, but we don't need to do special + * handling for this node + */ + if (DeviceNode == ParentDeviceNode) + { + DPRINT("Success\n"); + return STATUS_SUCCESS; + } + + /* + * We don't want to check for a direct child because + * this function is called during boot to reinitialize + * devices with drivers that couldn't load yet due to + * stage 0 limitations (ie can't load from disk yet). + */ + + if (!(DeviceNode->Flags & DNF_PROCESSED)) + { + DPRINT1("Child not ready to be added\n"); + return STATUS_SUCCESS; + } + + if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) || + IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) || + IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED)) + return STATUS_SUCCESS; + + if (DeviceNode->ServiceName.Buffer == NULL) + { + /* We don't need to worry about loading the driver because we're + * being driven in raw mode so our parent must be loaded to get here */ + Status = IopInitializeDevice(DeviceNode, NULL); + if (NT_SUCCESS(Status)) + { + Status = IopStartDevice(DeviceNode); + if (!NT_SUCCESS(Status)) + { + DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n", + &DeviceNode->InstancePath, Status); + } + } + } + else + { + PLDR_DATA_TABLE_ENTRY ModuleObject; + PDRIVER_OBJECT DriverObject; + + KeEnterCriticalRegion(); + ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE); + /* Get existing DriverObject pointer (in case the driver has + already been loaded and initialized) */ + Status = IopGetDriverObject( + &DriverObject, + &DeviceNode->ServiceName, + FALSE); + + if (!NT_SUCCESS(Status)) + { + /* Driver is not initialized, try to load it */ + Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject); + + if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED) + { + /* Initialize the driver */ + Status = IopInitializeDriverModule(DeviceNode, ModuleObject, + &DeviceNode->ServiceName, FALSE, &DriverObject); + if (!NT_SUCCESS(Status)) + DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY; + } + else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD) + { + DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName); + DeviceNode->Problem = CM_PROB_DISABLED_SERVICE; + } + else + { + DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n", + &DeviceNode->ServiceName, Status); + if (!BootDrivers) + DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD; + } + } + ExReleaseResourceLite(&IopDriverLoadResource); + KeLeaveCriticalRegion(); + + /* Driver is loaded and initialized at this point */ + if (NT_SUCCESS(Status)) + { + /* Initialize the device, including all filters */ + Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject); + + /* Remove the extra reference */ + ObDereferenceObject(DriverObject); + } + else + { + /* + * Don't disable when trying to load only boot drivers + */ + if (!BootDrivers) + { + IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); + } + } + } + + return STATUS_SUCCESS; +} + +static +NTSTATUS +IopSetServiceEnumData(PDEVICE_NODE DeviceNode) +{ + UNICODE_STRING ServicesKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); + UNICODE_STRING ServiceKeyName; + UNICODE_STRING EnumKeyName; + UNICODE_STRING ValueName; + PKEY_VALUE_FULL_INFORMATION KeyValueInformation; + HANDLE ServiceKey = NULL, ServiceEnumKey = NULL; + ULONG Disposition; + ULONG Count = 0, NextInstance = 0; + WCHAR ValueBuffer[6]; + NTSTATUS Status = STATUS_SUCCESS; + + DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode); + DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath); + DPRINT("Service: %wZ\n", &DeviceNode->ServiceName); + + if (DeviceNode->ServiceName.Buffer == NULL) + { + DPRINT1("No service!\n"); + return STATUS_SUCCESS; + } + + ServiceKeyName.MaximumLength = ServicesKeyPath.Length + DeviceNode->ServiceName.Length + sizeof(UNICODE_NULL); + ServiceKeyName.Length = 0; + ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength); + if (ServiceKeyName.Buffer == NULL) + { + DPRINT1("No ServiceKeyName.Buffer!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath); + RtlAppendUnicodeStringToString(&ServiceKeyName, &DeviceNode->ServiceName); + + DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName); + + Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY); + if (!NT_SUCCESS(Status)) + { + goto done; + } + + RtlInitUnicodeString(&EnumKeyName, L"Enum"); + Status = IopCreateRegistryKeyEx(&ServiceEnumKey, + ServiceKey, + &EnumKeyName, + KEY_SET_VALUE, + REG_OPTION_VOLATILE, + &Disposition); + if (NT_SUCCESS(Status)) + { + if (Disposition == REG_OPENED_EXISTING_KEY) + { + /* Read the NextInstance value */ + Status = IopGetRegistryValue(ServiceEnumKey, + L"Count", + &KeyValueInformation); + if (!NT_SUCCESS(Status)) + goto done; + + if ((KeyValueInformation->Type == REG_DWORD) && + (KeyValueInformation->DataLength)) + { + /* Read it */ + Count = *(PULONG)((ULONG_PTR)KeyValueInformation + + KeyValueInformation->DataOffset); + } + + ExFreePool(KeyValueInformation); + KeyValueInformation = NULL; + + /* Read the NextInstance value */ + Status = IopGetRegistryValue(ServiceEnumKey, + L"NextInstance", + &KeyValueInformation); + if (!NT_SUCCESS(Status)) + goto done; + + if ((KeyValueInformation->Type == REG_DWORD) && + (KeyValueInformation->DataLength)) + { + NextInstance = *(PULONG)((ULONG_PTR)KeyValueInformation + + KeyValueInformation->DataOffset); + } + + ExFreePool(KeyValueInformation); + KeyValueInformation = NULL; + } + + /* Set the instance path */ + swprintf(ValueBuffer, L"%lu", NextInstance); + RtlInitUnicodeString(&ValueName, ValueBuffer); + Status = ZwSetValueKey(ServiceEnumKey, + &ValueName, + 0, + REG_SZ, + DeviceNode->InstancePath.Buffer, + DeviceNode->InstancePath.MaximumLength); + if (!NT_SUCCESS(Status)) + goto done; + + /* Increment Count and NextInstance */ + Count++; + NextInstance++; + + /* Set the new Count value */ + RtlInitUnicodeString(&ValueName, L"Count"); + Status = ZwSetValueKey(ServiceEnumKey, + &ValueName, + 0, + REG_DWORD, + &Count, + sizeof(Count)); + if (!NT_SUCCESS(Status)) + goto done; + + /* Set the new NextInstance value */ + RtlInitUnicodeString(&ValueName, L"NextInstance"); + Status = ZwSetValueKey(ServiceEnumKey, + &ValueName, + 0, + REG_DWORD, + &NextInstance, + sizeof(NextInstance)); + } + +done: + if (ServiceEnumKey != NULL) + ZwClose(ServiceEnumKey); + + if (ServiceKey != NULL) + ZwClose(ServiceKey); + + ExFreePool(ServiceKeyName.Buffer); + + return Status; +} + +static +VOID +NTAPI +IopStartDevice2(IN PDEVICE_OBJECT DeviceObject) +{ + IO_STACK_LOCATION Stack; + PDEVICE_NODE DeviceNode; + NTSTATUS Status; + PVOID Dummy; + DEVICE_CAPABILITIES DeviceCapabilities; + + /* Get the device node */ + DeviceNode = IopGetDeviceNode(DeviceObject); + + ASSERT(!(DeviceNode->Flags & DNF_DISABLED)); + + /* Build the I/O stack location */ + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_START_DEVICE; + + Stack.Parameters.StartDevice.AllocatedResources = + DeviceNode->ResourceList; + Stack.Parameters.StartDevice.AllocatedResourcesTranslated = + DeviceNode->ResourceListTranslated; + + /* Do the call */ + Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); + if (!NT_SUCCESS(Status)) + { + /* Send an IRP_MN_REMOVE_DEVICE request */ + IopRemoveDevice(DeviceNode); + + /* Set the appropriate flag */ + DeviceNode->Flags |= DNF_START_FAILED; + DeviceNode->Problem = CM_PROB_FAILED_START; + + DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status); + return; + } + + DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n"); + + Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); + } + + /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */ + IoInvalidateDeviceState(DeviceObject); + + /* Otherwise, mark us as started */ + DeviceNode->Flags |= DNF_STARTED; + DeviceNode->Flags &= ~DNF_STOPPED; + + /* We now need enumeration */ + DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY; +} + +static +NTSTATUS +NTAPI +IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode) +{ + PDEVICE_OBJECT DeviceObject; + NTSTATUS Status; + PAGED_CODE(); + + /* Sanity check */ + ASSERT((DeviceNode->Flags & DNF_ADDED)); + ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED | + DNF_RESOURCE_REPORTED | + DNF_NO_RESOURCE_REQUIRED))); + + /* Get the device object */ + DeviceObject = DeviceNode->PhysicalDeviceObject; + + /* Check if we're not started yet */ + if (!(DeviceNode->Flags & DNF_STARTED)) + { + /* Start us */ + IopStartDevice2(DeviceObject); + } + + /* Do we need to query IDs? This happens in the case of manual reporting */ +#if 0 + if (DeviceNode->Flags & DNF_NEED_QUERY_IDS) + { + DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n"); + /* And that case shouldn't happen yet */ + ASSERT(FALSE); + } +#endif + + IopSetServiceEnumData(DeviceNode); + + /* Make sure we're started, and check if we need enumeration */ + if ((DeviceNode->Flags & DNF_STARTED) && + (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)) + { + /* Enumerate us */ + IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations); + Status = STATUS_SUCCESS; + } + else + { + /* Nothing to do */ + Status = STATUS_SUCCESS; + } + + /* Return */ + return Status; +} + +NTSTATUS +IopStartDevice( + PDEVICE_NODE DeviceNode) +{ + NTSTATUS Status; + HANDLE InstanceHandle = NULL, ControlHandle = NULL; + UNICODE_STRING KeyName, ValueString; + OBJECT_ATTRIBUTES ObjectAttributes; + + if (DeviceNode->Flags & DNF_DISABLED) + return STATUS_SUCCESS; + + Status = IopAssignDeviceResources(DeviceNode); + if (!NT_SUCCESS(Status)) + goto ByeBye; + + /* New PnP ABI */ + IopStartAndEnumerateDevice(DeviceNode); + + /* FIX: Should be done in new device instance code */ + Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceHandle); + if (!NT_SUCCESS(Status)) + goto ByeBye; + + /* FIX: Should be done in IoXxxPrepareDriverLoading */ + // { + RtlInitUnicodeString(&KeyName, L"Control"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + InstanceHandle, + NULL); + Status = ZwCreateKey(&ControlHandle, + KEY_SET_VALUE, + &ObjectAttributes, + 0, + NULL, + REG_OPTION_VOLATILE, + NULL); + if (!NT_SUCCESS(Status)) + goto ByeBye; + + RtlInitUnicodeString(&KeyName, L"ActiveService"); + ValueString = DeviceNode->ServiceName; + if (!ValueString.Buffer) + RtlInitUnicodeString(&ValueString, L""); + Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, ValueString.Buffer, ValueString.Length + sizeof(UNICODE_NULL)); + // } + +ByeBye: + if (ControlHandle != NULL) + ZwClose(ControlHandle); + + if (InstanceHandle != NULL) + ZwClose(InstanceHandle); + + return Status; +} + +static +NTSTATUS +NTAPI +IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject) +{ + IO_STACK_LOCATION Stack; + PVOID Dummy; + + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE; + + return IopSynchronousCall(DeviceObject, &Stack, &Dummy); +} + +static +VOID +NTAPI +IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject) +{ + IO_STACK_LOCATION Stack; + PVOID Dummy; + + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_STOP_DEVICE; + + /* Drivers should never fail a IRP_MN_STOP_DEVICE request */ + IopSynchronousCall(DeviceObject, &Stack, &Dummy); +} + +NTSTATUS +IopStopDevice( + PDEVICE_NODE DeviceNode) +{ + NTSTATUS Status; + + DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath); + + Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject); + if (NT_SUCCESS(Status)) + { + IopSendStopDevice(DeviceNode->PhysicalDeviceObject); + + DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); + DeviceNode->Flags |= DNF_STOPPED; + + return STATUS_SUCCESS; + } + + return Status; +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +static +VOID +NTAPI +IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject) +{ + IO_STACK_LOCATION Stack; + PVOID Dummy; + PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); + + /* Drop all our state for this device in case it isn't really going away */ + DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED; + + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_REMOVE_DEVICE; + + /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */ + IopSynchronousCall(DeviceObject, &Stack, &Dummy); + + IopNotifyPlugPlayNotification(DeviceObject, + EventCategoryTargetDeviceChange, + &GUID_TARGET_DEVICE_REMOVE_COMPLETE, + NULL, + NULL); + ObDereferenceObject(DeviceObject); +} + +static +VOID +IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) +{ + /* This function DOES dereference the device objects in all cases */ + + ULONG i; + + for (i = 0; i < DeviceRelations->Count; i++) + { + IopSendRemoveDevice(DeviceRelations->Objects[i]); + DeviceRelations->Objects[i] = NULL; + } + + ExFreePool(DeviceRelations); +} + +static +VOID +IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) +{ + PDEVICE_NODE ChildDeviceNode, NextDeviceNode; + KIRQL OldIrql; + + KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); + ChildDeviceNode = ParentDeviceNode->Child; + while (ChildDeviceNode != NULL) + { + NextDeviceNode = ChildDeviceNode->Sibling; + KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); + + IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); + + ChildDeviceNode = NextDeviceNode; + + KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); + } + KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +} + +static +VOID +NTAPI +IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject) +{ + IO_STACK_LOCATION Stack; + PVOID Dummy; + + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL; + + /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */ + IopSynchronousCall(DeviceObject, &Stack, &Dummy); +} + +static +VOID +NTAPI +IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject) +{ + IO_STACK_LOCATION Stack; + PVOID Dummy; + + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE; + + /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */ + IopSynchronousCall(DeviceObject, &Stack, &Dummy); + + IopNotifyPlugPlayNotification(DeviceObject, + EventCategoryTargetDeviceChange, + &GUID_TARGET_DEVICE_REMOVE_CANCELLED, + NULL, + NULL); +} + +static +VOID +IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) +{ + PDEVICE_NODE ChildDeviceNode, NextDeviceNode; + KIRQL OldIrql; + + KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); + ChildDeviceNode = ParentDeviceNode->Child; + while (ChildDeviceNode != NULL) + { + NextDeviceNode = ChildDeviceNode->Sibling; + KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); + + IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); + + ChildDeviceNode = NextDeviceNode; + + KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); + } + KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); +} + +static +VOID +IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) +{ + /* This function DOES dereference the device objects in all cases */ + + ULONG i; + + for (i = 0; i < DeviceRelations->Count; i++) + { + IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); + ObDereferenceObject(DeviceRelations->Objects[i]); + DeviceRelations->Objects[i] = NULL; + } + + ExFreePool(DeviceRelations); +} + +static +VOID +IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject) +{ + IO_STACK_LOCATION Stack; + IO_STATUS_BLOCK IoStatusBlock; + PDEVICE_RELATIONS DeviceRelations; + NTSTATUS Status; + + IopCancelRemoveDevice(DeviceObject); + + Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; + + Status = IopInitiatePnpIrp(DeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_DEVICE_RELATIONS, + &Stack); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); + DeviceRelations = NULL; + } + else + { + DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; + } + + if (DeviceRelations) + IopCancelRemoveDeviceRelations(DeviceRelations); +} + +static +NTSTATUS +NTAPI +IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject) +{ + PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); + IO_STACK_LOCATION Stack; + PVOID Dummy; + NTSTATUS Status; + + ASSERT(DeviceNode); + + IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING, + &DeviceNode->InstancePath); + + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE; + + Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); + + IopNotifyPlugPlayNotification(DeviceObject, + EventCategoryTargetDeviceChange, + &GUID_TARGET_DEVICE_QUERY_REMOVE, + NULL, + NULL); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath); + IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED, + &DeviceNode->InstancePath); + } + + return Status; +} + +static +NTSTATUS +IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force) +{ + PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; + NTSTATUS Status; + KIRQL OldIrql; + + KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); + ChildDeviceNode = ParentDeviceNode->Child; + while (ChildDeviceNode != NULL) + { + NextDeviceNode = ChildDeviceNode->Sibling; + KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); + + Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); + if (!NT_SUCCESS(Status)) + { + FailedRemoveDevice = ChildDeviceNode; + goto cleanup; + } + + KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); + ChildDeviceNode = NextDeviceNode; + } + KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); + + return STATUS_SUCCESS; + +cleanup: + KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); + ChildDeviceNode = ParentDeviceNode->Child; + while (ChildDeviceNode != NULL) + { + NextDeviceNode = ChildDeviceNode->Sibling; + KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); + + IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); + + /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device + * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ + if (ChildDeviceNode == FailedRemoveDevice) + return Status; + + ChildDeviceNode = NextDeviceNode; + + KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); + } + KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); + + return Status; +} + +static +NTSTATUS +IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force) +{ + /* This function DOES NOT dereference the device objects on SUCCESS + * but it DOES dereference device objects on FAILURE */ + + ULONG i, j; + NTSTATUS Status; + + for (i = 0; i < DeviceRelations->Count; i++) + { + Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force); + if (!NT_SUCCESS(Status)) + { + j = i; + goto cleanup; + } + } + + return STATUS_SUCCESS; + +cleanup: + /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device + * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ + for (i = 0; i <= j; i++) + { + IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); + ObDereferenceObject(DeviceRelations->Objects[i]); + DeviceRelations->Objects[i] = NULL; + } + for (; i < DeviceRelations->Count; i++) + { + ObDereferenceObject(DeviceRelations->Objects[i]); + DeviceRelations->Objects[i] = NULL; + } + ExFreePool(DeviceRelations); + + return Status; +} + +static +NTSTATUS +IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force) +{ + PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); + IO_STACK_LOCATION Stack; + IO_STATUS_BLOCK IoStatusBlock; + PDEVICE_RELATIONS DeviceRelations; + NTSTATUS Status; + + if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force) + { + DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath); + return STATUS_UNSUCCESSFUL; + } + + if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS) + { + DPRINT1("Removal vetoed by failing the query remove request\n"); + + IopCancelRemoveDevice(DeviceObject); + + return STATUS_UNSUCCESSFUL; + } + + Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; + + Status = IopInitiatePnpIrp(DeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_DEVICE_RELATIONS, + &Stack); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); + DeviceRelations = NULL; + } + else + { + DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; + } + + if (DeviceRelations) + { + Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); + if (!NT_SUCCESS(Status)) + return Status; + } + + Status = IopQueryRemoveChildDevices(DeviceNode, Force); + if (!NT_SUCCESS(Status)) + { + if (DeviceRelations) + IopCancelRemoveDeviceRelations(DeviceRelations); + return Status; + } + + if (DeviceRelations) + IopSendRemoveDeviceRelations(DeviceRelations); + IopSendRemoveChildDevices(DeviceNode); + + return STATUS_SUCCESS; +} + +static +VOID +IopHandleDeviceRemoval( + IN PDEVICE_NODE DeviceNode, + IN PDEVICE_RELATIONS DeviceRelations) +{ + PDEVICE_NODE Child = DeviceNode->Child, NextChild; + ULONG i; + BOOLEAN Found; + + if (DeviceNode == IopRootDeviceNode) + return; + + while (Child != NULL) + { + NextChild = Child->Sibling; + Found = FALSE; + + for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++) + { + if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child) + { + Found = TRUE; + break; + } + } + + if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED)) + { + /* Send removal IRPs to all of its children */ + IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE); + + /* Send the surprise removal IRP */ + IopSendSurpriseRemoval(Child->PhysicalDeviceObject); + + /* Tell the user-mode PnP manager that a device was removed */ + IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, + &Child->InstancePath); + + /* Send the remove device IRP */ + IopSendRemoveDevice(Child->PhysicalDeviceObject); + } + + Child = NextChild; + } +} + +NTSTATUS +IopRemoveDevice(PDEVICE_NODE DeviceNode) +{ + NTSTATUS Status; + + DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); + + Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE); + if (NT_SUCCESS(Status)) + { + IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject); + IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, + &DeviceNode->InstancePath); + return STATUS_SUCCESS; + } + + return Status; +} + +/* + * @implemented + */ +VOID +NTAPI +IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) +{ + PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); + IO_STACK_LOCATION Stack; + ULONG_PTR PnPFlags; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE; + + Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags); + if (!NT_SUCCESS(Status)) + { + if (Status != STATUS_NOT_SUPPORTED) + { + DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status); + } + return; + } + + if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) + DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE; + else + DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE; + + if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI) + DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; + else + DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; + + if ((PnPFlags & PNP_DEVICE_REMOVED) || + ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))) + { + /* Flag it if it's failed */ + if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START; + + /* Send removal IRPs to all of its children */ + IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE); + + /* Send surprise removal */ + IopSendSurpriseRemoval(PhysicalDeviceObject); + + /* Tell the user-mode PnP manager that a device was removed */ + IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, + &DeviceNode->InstancePath); + + IopSendRemoveDevice(PhysicalDeviceObject); + } + else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)) + { + /* Stop for resource rebalance */ + Status = IopStopDevice(DeviceNode); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to stop device for rebalancing\n"); + + /* Stop failed so don't rebalance */ + PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED; + } + } + + /* Resource rebalance */ + if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) + { + DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); + + Status = IopInitiatePnpIrp(PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_RESOURCES, + NULL); + if (NT_SUCCESS(Status) && IoStatusBlock.Information) + { + DeviceNode->BootResources = + (PCM_RESOURCE_LIST)IoStatusBlock.Information; + IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); + } + else + { + DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); + DeviceNode->BootResources = NULL; + } + + DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); + + Status = IopInitiatePnpIrp(PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_RESOURCE_REQUIREMENTS, + NULL); + if (NT_SUCCESS(Status)) + { + DeviceNode->ResourceRequirements = + (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; + } + else + { + DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); + DeviceNode->ResourceRequirements = NULL; + } + + /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */ + if (IopStartDevice(DeviceNode) != STATUS_SUCCESS) + { + DPRINT1("Restart after resource rebalance failed\n"); + + DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); + DeviceNode->Flags |= DNF_START_FAILED; + + IopRemoveDevice(DeviceNode); + } + } +} + +/* + * IopInitializePnpServices + * + * Initialize services for discovered children + * + * Parameters + * DeviceNode + * Top device node to start initializing services. + * + * Return Value + * Status + */ +NTSTATUS +IopInitializePnpServices(IN PDEVICE_NODE DeviceNode) +{ + DEVICETREE_TRAVERSE_CONTEXT Context; + + DPRINT("IopInitializePnpServices(%p)\n", DeviceNode); + + IopInitDeviceTreeTraverseContext( + &Context, + DeviceNode, + IopActionInitChildServices, + DeviceNode); + + return IopTraverseDeviceTree(&Context); +} + + +NTSTATUS +IopEnumerateDevice( + IN PDEVICE_OBJECT DeviceObject) +{ + PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); + DEVICETREE_TRAVERSE_CONTEXT Context; + PDEVICE_RELATIONS DeviceRelations; + PDEVICE_OBJECT ChildDeviceObject; + IO_STATUS_BLOCK IoStatusBlock; + PDEVICE_NODE ChildDeviceNode; + IO_STACK_LOCATION Stack; + NTSTATUS Status; + ULONG i; + + DPRINT("DeviceObject 0x%p\n", DeviceObject); + + if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY) + { + DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY; + + DPRINT("Sending GUID_DEVICE_ARRIVAL\n"); + IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, + &DeviceNode->InstancePath); + } + + DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n"); + + Stack.Parameters.QueryDeviceRelations.Type = BusRelations; + + Status = IopInitiatePnpIrp( + DeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_DEVICE_RELATIONS, + &Stack); + if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) + { + DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); + return Status; + } + + DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; + + /* + * Send removal IRPs for devices that have disappeared + * NOTE: This code handles the case where no relations are specified + */ + IopHandleDeviceRemoval(DeviceNode, DeviceRelations); + + /* Now we bail if nothing was returned */ + if (!DeviceRelations) + { + /* We're all done */ + DPRINT("No PDOs\n"); + return STATUS_SUCCESS; + } + + DPRINT("Got %u PDOs\n", DeviceRelations->Count); + + /* + * Create device nodes for all discovered devices + */ + for (i = 0; i < DeviceRelations->Count; i++) + { + ChildDeviceObject = DeviceRelations->Objects[i]; + ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0); + + ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); + if (!ChildDeviceNode) + { + /* One doesn't exist, create it */ + Status = IopCreateDeviceNode( + DeviceNode, + ChildDeviceObject, + NULL, + &ChildDeviceNode); + if (NT_SUCCESS(Status)) + { + /* Mark the node as enumerated */ + ChildDeviceNode->Flags |= DNF_ENUMERATED; + + /* Mark the DO as bus enumerated */ + ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; + } + else + { + /* Ignore this DO */ + DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i); + ObDereferenceObject(ChildDeviceObject); + } + } + else + { + /* Mark it as enumerated */ + ChildDeviceNode->Flags |= DNF_ENUMERATED; + ObDereferenceObject(ChildDeviceObject); + } + } + ExFreePool(DeviceRelations); + + /* + * Retrieve information about all discovered children from the bus driver + */ + IopInitDeviceTreeTraverseContext( + &Context, + DeviceNode, + IopActionInterrogateDeviceStack, + DeviceNode); + + Status = IopTraverseDeviceTree(&Context); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); + return Status; + } + + /* + * Retrieve configuration from the registry for discovered children + */ + IopInitDeviceTreeTraverseContext( + &Context, + DeviceNode, + IopActionConfigureChildServices, + DeviceNode); + + Status = IopTraverseDeviceTree(&Context); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); + return Status; + } + + /* + * Initialize services for discovered children. + */ + Status = IopInitializePnpServices(DeviceNode); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status); + return Status; + } + + DPRINT("IopEnumerateDevice() finished\n"); + return STATUS_SUCCESS; +} + +static +NTSTATUS +NTAPI +IopSendEject(IN PDEVICE_OBJECT DeviceObject) +{ + IO_STACK_LOCATION Stack; + PVOID Dummy; + + RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); + Stack.MajorFunction = IRP_MJ_PNP; + Stack.MinorFunction = IRP_MN_EJECT; + + return IopSynchronousCall(DeviceObject, &Stack, &Dummy); +} + +/* + * @implemented + */ +VOID +NTAPI +IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject) +{ + PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); + PDEVICE_RELATIONS DeviceRelations; + IO_STATUS_BLOCK IoStatusBlock; + IO_STACK_LOCATION Stack; + DEVICE_CAPABILITIES Capabilities; + NTSTATUS Status; + + IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT, + &DeviceNode->InstancePath); + + if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS) + { + goto cleanup; + } + + Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; + + Status = IopInitiatePnpIrp(PhysicalDeviceObject, + &IoStatusBlock, + IRP_MN_QUERY_DEVICE_RELATIONS, + &Stack); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); + DeviceRelations = NULL; + } + else + { + DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; + } + + if (DeviceRelations) + { + Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE); + if (!NT_SUCCESS(Status)) + goto cleanup; + } + + Status = IopQueryRemoveChildDevices(DeviceNode, FALSE); + if (!NT_SUCCESS(Status)) + { + if (DeviceRelations) + IopCancelRemoveDeviceRelations(DeviceRelations); + goto cleanup; + } + + if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS) + { + if (DeviceRelations) + IopCancelRemoveDeviceRelations(DeviceRelations); + IopCancelRemoveChildDevices(DeviceNode); + goto cleanup; + } + + if (DeviceRelations) + IopSendRemoveDeviceRelations(DeviceRelations); + IopSendRemoveChildDevices(DeviceNode); + + DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT; + if (Capabilities.EjectSupported) + { + if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS) + { + goto cleanup; + } + } + else + { + DeviceNode->Flags |= DNF_DISABLED; + } + + IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT, + &DeviceNode->InstancePath); + + return; + +cleanup: + IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED, + &DeviceNode->InstancePath); +} + +static +VOID +NTAPI +IopDeviceActionWorker( + _In_ PVOID Context) +{ + PLIST_ENTRY ListEntry; + PDEVICE_ACTION_DATA Data; + KIRQL OldIrql; + + KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); + while (!IsListEmpty(&IopDeviceActionRequestList)) + { + ListEntry = RemoveHeadList(&IopDeviceActionRequestList); + KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); + Data = CONTAINING_RECORD(ListEntry, + DEVICE_ACTION_DATA, + RequestListEntry); + + switch (Data->Action) + { + case DeviceActionInvalidateDeviceRelations: + IoSynchronousInvalidateDeviceRelations(Data->DeviceObject, + Data->InvalidateDeviceRelations.Type); + break; + + default: + DPRINT1("Unimplemented device action %u\n", Data->Action); + break; + } + + ObDereferenceObject(Data->DeviceObject); + ExFreePoolWithTag(Data, TAG_IO); + KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); + } + IopDeviceActionInProgress = FALSE; + KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); +} + +VOID +IopQueueDeviceAction( + _In_ PDEVICE_ACTION_DATA ActionData) +{ + PDEVICE_ACTION_DATA Data; + KIRQL OldIrql; + + DPRINT("IopQueueDeviceAction(%p)\n", ActionData); + + Data = ExAllocatePoolWithTag(NonPagedPool, + sizeof(DEVICE_ACTION_DATA), + TAG_IO); + if (!Data) + return; + + ObReferenceObject(ActionData->DeviceObject); + RtlCopyMemory(Data, ActionData, sizeof(DEVICE_ACTION_DATA)); + + DPRINT("Action %u\n", Data->Action); + + KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); + InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry); + if (IopDeviceActionInProgress) + { + KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); + return; + } + IopDeviceActionInProgress = TRUE; + KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); + + ExInitializeWorkItem(&IopDeviceActionWorkItem, + IopDeviceActionWorker, + NULL); + ExQueueWorkItem(&IopDeviceActionWorkItem, + DelayedWorkQueue); +} diff --git a/ntoskrnl/io/pnpmgr/pnpmgr.c b/ntoskrnl/io/pnpmgr/pnpmgr.c index 436e1376f9a..8b9c92ca466 100644 --- a/ntoskrnl/io/pnpmgr/pnpmgr.c +++ b/ntoskrnl/io/pnpmgr/pnpmgr.c @@ -19,35 +19,15 @@ ERESOURCE PpRegistryDeviceResource; KGUARDED_MUTEX PpDeviceReferenceTableLock; RTL_AVL_TABLE PpDeviceReferenceTable; -extern ERESOURCE IopDriverLoadResource; extern ULONG ExpInitializationPhase; -extern BOOLEAN PnpSystemInit; -extern PDEVICE_NODE IopRootDeviceNode; - -#define MAX_DEVICE_ID_LEN 200 -#define MAX_SEPARATORS_INSTANCEID 0 -#define MAX_SEPARATORS_DEVICEID 1 /* DATA **********************************************************************/ PDRIVER_OBJECT IopRootDriverObject; PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL; -LIST_ENTRY IopDeviceActionRequestList; -WORK_QUEUE_ITEM IopDeviceActionWorkItem; -BOOLEAN IopDeviceActionInProgress; -KSPIN_LOCK IopDeviceActionLock; /* FUNCTIONS *****************************************************************/ -VOID -IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject); - -NTSTATUS -IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force); - -PDEVICE_OBJECT -IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance); - VOID IopFixupDeviceId(PWCHAR String) { @@ -478,668 +458,6 @@ IopInitializeDevice(PDEVICE_NODE DeviceNode, return STATUS_SUCCESS; } -static -NTSTATUS -NTAPI -IopSendEject(IN PDEVICE_OBJECT DeviceObject) -{ - IO_STACK_LOCATION Stack; - PVOID Dummy; - - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_EJECT; - - return IopSynchronousCall(DeviceObject, &Stack, &Dummy); -} - -static -VOID -NTAPI -IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject) -{ - IO_STACK_LOCATION Stack; - PVOID Dummy; - - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL; - - /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */ - IopSynchronousCall(DeviceObject, &Stack, &Dummy); -} - -static -NTSTATUS -NTAPI -IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject) -{ - PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); - IO_STACK_LOCATION Stack; - PVOID Dummy; - NTSTATUS Status; - - ASSERT(DeviceNode); - - IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING, - &DeviceNode->InstancePath); - - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE; - - Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); - - IopNotifyPlugPlayNotification(DeviceObject, - EventCategoryTargetDeviceChange, - &GUID_TARGET_DEVICE_QUERY_REMOVE, - NULL, - NULL); - - if (!NT_SUCCESS(Status)) - { - DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath); - IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED, - &DeviceNode->InstancePath); - } - - return Status; -} - -static -NTSTATUS -NTAPI -IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject) -{ - IO_STACK_LOCATION Stack; - PVOID Dummy; - - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE; - - return IopSynchronousCall(DeviceObject, &Stack, &Dummy); -} - -static -VOID -NTAPI -IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject) -{ - IO_STACK_LOCATION Stack; - PVOID Dummy; - PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); - - /* Drop all our state for this device in case it isn't really going away */ - DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED; - - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_REMOVE_DEVICE; - - /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */ - IopSynchronousCall(DeviceObject, &Stack, &Dummy); - - IopNotifyPlugPlayNotification(DeviceObject, - EventCategoryTargetDeviceChange, - &GUID_TARGET_DEVICE_REMOVE_COMPLETE, - NULL, - NULL); - ObDereferenceObject(DeviceObject); -} - -static -VOID -NTAPI -IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject) -{ - IO_STACK_LOCATION Stack; - PVOID Dummy; - - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE; - - /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */ - IopSynchronousCall(DeviceObject, &Stack, &Dummy); - - IopNotifyPlugPlayNotification(DeviceObject, - EventCategoryTargetDeviceChange, - &GUID_TARGET_DEVICE_REMOVE_CANCELLED, - NULL, - NULL); -} - -static -VOID -NTAPI -IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject) -{ - IO_STACK_LOCATION Stack; - PVOID Dummy; - - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_STOP_DEVICE; - - /* Drivers should never fail a IRP_MN_STOP_DEVICE request */ - IopSynchronousCall(DeviceObject, &Stack, &Dummy); -} - -static -NTSTATUS -IopSetServiceEnumData(PDEVICE_NODE DeviceNode) -{ - UNICODE_STRING ServicesKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); - UNICODE_STRING ServiceKeyName; - UNICODE_STRING EnumKeyName; - UNICODE_STRING ValueName; - PKEY_VALUE_FULL_INFORMATION KeyValueInformation; - HANDLE ServiceKey = NULL, ServiceEnumKey = NULL; - ULONG Disposition; - ULONG Count = 0, NextInstance = 0; - WCHAR ValueBuffer[6]; - NTSTATUS Status = STATUS_SUCCESS; - - DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode); - DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath); - DPRINT("Service: %wZ\n", &DeviceNode->ServiceName); - - if (DeviceNode->ServiceName.Buffer == NULL) - { - DPRINT1("No service!\n"); - return STATUS_SUCCESS; - } - - ServiceKeyName.MaximumLength = ServicesKeyPath.Length + DeviceNode->ServiceName.Length + sizeof(UNICODE_NULL); - ServiceKeyName.Length = 0; - ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength); - if (ServiceKeyName.Buffer == NULL) - { - DPRINT1("No ServiceKeyName.Buffer!\n"); - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath); - RtlAppendUnicodeStringToString(&ServiceKeyName, &DeviceNode->ServiceName); - - DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName); - - Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY); - if (!NT_SUCCESS(Status)) - { - goto done; - } - - RtlInitUnicodeString(&EnumKeyName, L"Enum"); - Status = IopCreateRegistryKeyEx(&ServiceEnumKey, - ServiceKey, - &EnumKeyName, - KEY_SET_VALUE, - REG_OPTION_VOLATILE, - &Disposition); - if (NT_SUCCESS(Status)) - { - if (Disposition == REG_OPENED_EXISTING_KEY) - { - /* Read the NextInstance value */ - Status = IopGetRegistryValue(ServiceEnumKey, - L"Count", - &KeyValueInformation); - if (!NT_SUCCESS(Status)) - goto done; - - if ((KeyValueInformation->Type == REG_DWORD) && - (KeyValueInformation->DataLength)) - { - /* Read it */ - Count = *(PULONG)((ULONG_PTR)KeyValueInformation + - KeyValueInformation->DataOffset); - } - - ExFreePool(KeyValueInformation); - KeyValueInformation = NULL; - - /* Read the NextInstance value */ - Status = IopGetRegistryValue(ServiceEnumKey, - L"NextInstance", - &KeyValueInformation); - if (!NT_SUCCESS(Status)) - goto done; - - if ((KeyValueInformation->Type == REG_DWORD) && - (KeyValueInformation->DataLength)) - { - NextInstance = *(PULONG)((ULONG_PTR)KeyValueInformation + - KeyValueInformation->DataOffset); - } - - ExFreePool(KeyValueInformation); - KeyValueInformation = NULL; - } - - /* Set the instance path */ - swprintf(ValueBuffer, L"%lu", NextInstance); - RtlInitUnicodeString(&ValueName, ValueBuffer); - Status = ZwSetValueKey(ServiceEnumKey, - &ValueName, - 0, - REG_SZ, - DeviceNode->InstancePath.Buffer, - DeviceNode->InstancePath.MaximumLength); - if (!NT_SUCCESS(Status)) - goto done; - - /* Increment Count and NextInstance */ - Count++; - NextInstance++; - - /* Set the new Count value */ - RtlInitUnicodeString(&ValueName, L"Count"); - Status = ZwSetValueKey(ServiceEnumKey, - &ValueName, - 0, - REG_DWORD, - &Count, - sizeof(Count)); - if (!NT_SUCCESS(Status)) - goto done; - - /* Set the new NextInstance value */ - RtlInitUnicodeString(&ValueName, L"NextInstance"); - Status = ZwSetValueKey(ServiceEnumKey, - &ValueName, - 0, - REG_DWORD, - &NextInstance, - sizeof(NextInstance)); - } - -done: - if (ServiceEnumKey != NULL) - ZwClose(ServiceEnumKey); - - if (ServiceKey != NULL) - ZwClose(ServiceKey); - - ExFreePool(ServiceKeyName.Buffer); - - return Status; -} - -VOID -NTAPI -IopStartDevice2(IN PDEVICE_OBJECT DeviceObject) -{ - IO_STACK_LOCATION Stack; - PDEVICE_NODE DeviceNode; - NTSTATUS Status; - PVOID Dummy; - DEVICE_CAPABILITIES DeviceCapabilities; - - /* Get the device node */ - DeviceNode = IopGetDeviceNode(DeviceObject); - - ASSERT(!(DeviceNode->Flags & DNF_DISABLED)); - - /* Build the I/O stack location */ - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_START_DEVICE; - - Stack.Parameters.StartDevice.AllocatedResources = - DeviceNode->ResourceList; - Stack.Parameters.StartDevice.AllocatedResourcesTranslated = - DeviceNode->ResourceListTranslated; - - /* Do the call */ - Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy); - if (!NT_SUCCESS(Status)) - { - /* Send an IRP_MN_REMOVE_DEVICE request */ - IopRemoveDevice(DeviceNode); - - /* Set the appropriate flag */ - DeviceNode->Flags |= DNF_START_FAILED; - DeviceNode->Problem = CM_PROB_FAILED_START; - - DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status); - return; - } - - DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n"); - - Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status); - } - - /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */ - IoInvalidateDeviceState(DeviceObject); - - /* Otherwise, mark us as started */ - DeviceNode->Flags |= DNF_STARTED; - DeviceNode->Flags &= ~DNF_STOPPED; - - /* We now need enumeration */ - DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY; -} - -NTSTATUS -NTAPI -IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode) -{ - PDEVICE_OBJECT DeviceObject; - NTSTATUS Status; - PAGED_CODE(); - - /* Sanity check */ - ASSERT((DeviceNode->Flags & DNF_ADDED)); - ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED | - DNF_RESOURCE_REPORTED | - DNF_NO_RESOURCE_REQUIRED))); - - /* Get the device object */ - DeviceObject = DeviceNode->PhysicalDeviceObject; - - /* Check if we're not started yet */ - if (!(DeviceNode->Flags & DNF_STARTED)) - { - /* Start us */ - IopStartDevice2(DeviceObject); - } - - /* Do we need to query IDs? This happens in the case of manual reporting */ -#if 0 - if (DeviceNode->Flags & DNF_NEED_QUERY_IDS) - { - DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n"); - /* And that case shouldn't happen yet */ - ASSERT(FALSE); - } -#endif - - IopSetServiceEnumData(DeviceNode); - - /* Make sure we're started, and check if we need enumeration */ - if ((DeviceNode->Flags & DNF_STARTED) && - (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)) - { - /* Enumerate us */ - IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations); - Status = STATUS_SUCCESS; - } - else - { - /* Nothing to do */ - Status = STATUS_SUCCESS; - } - - /* Return */ - return Status; -} - -NTSTATUS -IopStopDevice( - PDEVICE_NODE DeviceNode) -{ - NTSTATUS Status; - - DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath); - - Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject); - if (NT_SUCCESS(Status)) - { - IopSendStopDevice(DeviceNode->PhysicalDeviceObject); - - DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); - DeviceNode->Flags |= DNF_STOPPED; - - return STATUS_SUCCESS; - } - - return Status; -} - -NTSTATUS -IopStartDevice( - PDEVICE_NODE DeviceNode) -{ - NTSTATUS Status; - HANDLE InstanceHandle = NULL, ControlHandle = NULL; - UNICODE_STRING KeyName, ValueString; - OBJECT_ATTRIBUTES ObjectAttributes; - - if (DeviceNode->Flags & DNF_DISABLED) - return STATUS_SUCCESS; - - Status = IopAssignDeviceResources(DeviceNode); - if (!NT_SUCCESS(Status)) - goto ByeBye; - - /* New PnP ABI */ - IopStartAndEnumerateDevice(DeviceNode); - - /* FIX: Should be done in new device instance code */ - Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceHandle); - if (!NT_SUCCESS(Status)) - goto ByeBye; - - /* FIX: Should be done in IoXxxPrepareDriverLoading */ - // { - RtlInitUnicodeString(&KeyName, L"Control"); - InitializeObjectAttributes(&ObjectAttributes, - &KeyName, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - InstanceHandle, - NULL); - Status = ZwCreateKey(&ControlHandle, - KEY_SET_VALUE, - &ObjectAttributes, - 0, - NULL, - REG_OPTION_VOLATILE, - NULL); - if (!NT_SUCCESS(Status)) - goto ByeBye; - - RtlInitUnicodeString(&KeyName, L"ActiveService"); - ValueString = DeviceNode->ServiceName; - if (!ValueString.Buffer) - RtlInitUnicodeString(&ValueString, L""); - Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, ValueString.Buffer, ValueString.Length + sizeof(UNICODE_NULL)); - // } - -ByeBye: - if (ControlHandle != NULL) - ZwClose(ControlHandle); - - if (InstanceHandle != NULL) - ZwClose(InstanceHandle); - - return Status; -} - -NTSTATUS -NTAPI -IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode, - PDEVICE_CAPABILITIES DeviceCaps) -{ - IO_STATUS_BLOCK StatusBlock; - IO_STACK_LOCATION Stack; - NTSTATUS Status; - HANDLE InstanceKey; - UNICODE_STRING ValueName; - - /* Set up the Header */ - RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES)); - DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES); - DeviceCaps->Version = 1; - DeviceCaps->Address = -1; - DeviceCaps->UINumber = -1; - - /* Set up the Stack */ - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps; - - /* Send the IRP */ - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &StatusBlock, - IRP_MN_QUERY_CAPABILITIES, - &Stack); - if (!NT_SUCCESS(Status)) - { - if (Status != STATUS_NOT_SUPPORTED) - { - DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status); - } - return Status; - } - - /* Map device capabilities to capability flags */ - DeviceNode->CapabilityFlags = 0; - if (DeviceCaps->LockSupported) - DeviceNode->CapabilityFlags |= 0x00000001; // CM_DEVCAP_LOCKSUPPORTED - - if (DeviceCaps->EjectSupported) - DeviceNode->CapabilityFlags |= 0x00000002; // CM_DEVCAP_EJECTSUPPORTED - - if (DeviceCaps->Removable) - DeviceNode->CapabilityFlags |= 0x00000004; // CM_DEVCAP_REMOVABLE - - if (DeviceCaps->DockDevice) - DeviceNode->CapabilityFlags |= 0x00000008; // CM_DEVCAP_DOCKDEVICE - - if (DeviceCaps->UniqueID) - DeviceNode->CapabilityFlags |= 0x00000010; // CM_DEVCAP_UNIQUEID - - if (DeviceCaps->SilentInstall) - DeviceNode->CapabilityFlags |= 0x00000020; // CM_DEVCAP_SILENTINSTALL - - if (DeviceCaps->RawDeviceOK) - DeviceNode->CapabilityFlags |= 0x00000040; // CM_DEVCAP_RAWDEVICEOK - - if (DeviceCaps->SurpriseRemovalOK) - DeviceNode->CapabilityFlags |= 0x00000080; // CM_DEVCAP_SURPRISEREMOVALOK - - if (DeviceCaps->HardwareDisabled) - DeviceNode->CapabilityFlags |= 0x00000100; // CM_DEVCAP_HARDWAREDISABLED - - if (DeviceCaps->NonDynamic) - DeviceNode->CapabilityFlags |= 0x00000200; // CM_DEVCAP_NONDYNAMIC - - if (DeviceCaps->NoDisplayInUI) - DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; - else - DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; - - Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); - if (NT_SUCCESS(Status)) - { - /* Set 'Capabilities' value */ - RtlInitUnicodeString(&ValueName, L"Capabilities"); - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_DWORD, - &DeviceNode->CapabilityFlags, - sizeof(ULONG)); - - /* Set 'UINumber' value */ - if (DeviceCaps->UINumber != MAXULONG) - { - RtlInitUnicodeString(&ValueName, L"UINumber"); - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_DWORD, - &DeviceCaps->UINumber, - sizeof(ULONG)); - } - - ZwClose(InstanceKey); - } - - return Status; -} - -static -VOID -NTAPI -IopDeviceActionWorker( - _In_ PVOID Context) -{ - PLIST_ENTRY ListEntry; - PDEVICE_ACTION_DATA Data; - KIRQL OldIrql; - - KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); - while (!IsListEmpty(&IopDeviceActionRequestList)) - { - ListEntry = RemoveHeadList(&IopDeviceActionRequestList); - KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); - Data = CONTAINING_RECORD(ListEntry, - DEVICE_ACTION_DATA, - RequestListEntry); - - switch (Data->Action) - { - case DeviceActionInvalidateDeviceRelations: - IoSynchronousInvalidateDeviceRelations(Data->DeviceObject, - Data->InvalidateDeviceRelations.Type); - break; - - default: - DPRINT1("Unimplemented device action %u\n", Data->Action); - break; - } - - ObDereferenceObject(Data->DeviceObject); - ExFreePoolWithTag(Data, TAG_IO); - KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); - } - IopDeviceActionInProgress = FALSE; - KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); -} - -VOID -IopQueueDeviceAction( - _In_ PDEVICE_ACTION_DATA ActionData) -{ - PDEVICE_ACTION_DATA Data; - KIRQL OldIrql; - - DPRINT("IopQueueDeviceAction(%p)\n", ActionData); - - Data = ExAllocatePoolWithTag(NonPagedPool, - sizeof(DEVICE_ACTION_DATA), - TAG_IO); - if (!Data) - return; - - ObReferenceObject(ActionData->DeviceObject); - RtlCopyMemory(Data, ActionData, sizeof(DEVICE_ACTION_DATA)); - - DPRINT("Action %u\n", Data->Action); - - KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql); - InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry); - if (IopDeviceActionInProgress) - { - KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); - return; - } - IopDeviceActionInProgress = TRUE; - KeReleaseSpinLock(&IopDeviceActionLock, OldIrql); - - ExInitializeWorkItem(&IopDeviceActionWorkItem, - IopDeviceActionWorker, - NULL); - ExQueueWorkItem(&IopDeviceActionWorkItem, - DelayedWorkQueue); -} - NTSTATUS IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject) { @@ -1701,1159 +1019,6 @@ cleanup: return Status; } -static -BOOLEAN -IopValidateID( - _In_ PWCHAR Id, - _In_ BUS_QUERY_ID_TYPE QueryType) -{ - PWCHAR PtrChar; - PWCHAR StringEnd; - WCHAR Char; - ULONG SeparatorsCount = 0; - PWCHAR PtrPrevChar = NULL; - ULONG MaxSeparators; - BOOLEAN IsMultiSz; - - PAGED_CODE(); - - switch (QueryType) - { - case BusQueryDeviceID: - MaxSeparators = MAX_SEPARATORS_DEVICEID; - IsMultiSz = FALSE; - break; - case BusQueryInstanceID: - MaxSeparators = MAX_SEPARATORS_INSTANCEID; - IsMultiSz = FALSE; - break; - - case BusQueryHardwareIDs: - case BusQueryCompatibleIDs: - MaxSeparators = MAX_SEPARATORS_DEVICEID; - IsMultiSz = TRUE; - break; - - default: - DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType); - return FALSE; - } - - StringEnd = Id + MAX_DEVICE_ID_LEN; - - for (PtrChar = Id; PtrChar < StringEnd; PtrChar++) - { - Char = *PtrChar; - - if (Char == UNICODE_NULL) - { - if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1)) - { - if (MaxSeparators == SeparatorsCount || IsMultiSz) - { - return TRUE; - } - - DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", - SeparatorsCount, MaxSeparators); - goto ErrorExit; - } - - StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1; - PtrPrevChar = PtrChar; - SeparatorsCount = 0; - } - else if (Char < ' ' || Char > 0x7F || Char == ',') - { - DPRINT1("IopValidateID: Invalid character - %04X\n", Char); - goto ErrorExit; - } - else if (Char == ' ') - { - *PtrChar = '_'; - } - else if (Char == '\\') - { - SeparatorsCount++; - - if (SeparatorsCount > MaxSeparators) - { - DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n", - SeparatorsCount, MaxSeparators); - goto ErrorExit; - } - } - } - - DPRINT1("IopValidateID: Not terminated ID\n"); - -ErrorExit: - // FIXME logging - return FALSE; -} - -NTSTATUS -IopQueryHardwareIds(PDEVICE_NODE DeviceNode, - HANDLE InstanceKey) -{ - IO_STACK_LOCATION Stack; - IO_STATUS_BLOCK IoStatusBlock; - PWSTR Ptr; - UNICODE_STRING ValueName; - NTSTATUS Status; - ULONG Length, TotalLength; - BOOLEAN IsValidID; - - DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n"); - - RtlZeroMemory(&Stack, sizeof(Stack)); - Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs; - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_ID, - &Stack); - if (NT_SUCCESS(Status)) - { - IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs); - - if (!IsValidID) - { - DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode); - } - - TotalLength = 0; - - Ptr = (PWSTR)IoStatusBlock.Information; - DPRINT("Hardware IDs:\n"); - while (*Ptr) - { - DPRINT(" %S\n", Ptr); - Length = (ULONG)wcslen(Ptr) + 1; - - Ptr += Length; - TotalLength += Length; - } - DPRINT("TotalLength: %hu\n", TotalLength); - DPRINT("\n"); - - RtlInitUnicodeString(&ValueName, L"HardwareID"); - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_MULTI_SZ, - (PVOID)IoStatusBlock.Information, - (TotalLength + 1) * sizeof(WCHAR)); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); - } - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); - } - - return Status; -} - -NTSTATUS -IopQueryCompatibleIds(PDEVICE_NODE DeviceNode, - HANDLE InstanceKey) -{ - IO_STACK_LOCATION Stack; - IO_STATUS_BLOCK IoStatusBlock; - PWSTR Ptr; - UNICODE_STRING ValueName; - NTSTATUS Status; - ULONG Length, TotalLength; - BOOLEAN IsValidID; - - DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n"); - - RtlZeroMemory(&Stack, sizeof(Stack)); - Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs; - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_ID, - &Stack); - if (NT_SUCCESS(Status) && IoStatusBlock.Information) - { - IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs); - - if (!IsValidID) - { - DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode); - } - - TotalLength = 0; - - Ptr = (PWSTR)IoStatusBlock.Information; - DPRINT("Compatible IDs:\n"); - while (*Ptr) - { - DPRINT(" %S\n", Ptr); - Length = (ULONG)wcslen(Ptr) + 1; - - Ptr += Length; - TotalLength += Length; - } - DPRINT("TotalLength: %hu\n", TotalLength); - DPRINT("\n"); - - RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_MULTI_SZ, - (PVOID)IoStatusBlock.Information, - (TotalLength + 1) * sizeof(WCHAR)); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status); - } - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status); - } - - return Status; -} - -NTSTATUS -IopCreateDeviceInstancePath( - _In_ PDEVICE_NODE DeviceNode, - _Out_ PUNICODE_STRING InstancePath) -{ - IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING DeviceId; - UNICODE_STRING InstanceId; - IO_STACK_LOCATION Stack; - NTSTATUS Status; - UNICODE_STRING ParentIdPrefix = { 0, 0, NULL }; - DEVICE_CAPABILITIES DeviceCapabilities; - BOOLEAN IsValidID; - - DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n"); - - Stack.Parameters.QueryId.IdType = BusQueryDeviceID; - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_ID, - &Stack); - if (!NT_SUCCESS(Status)) - { - DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status); - return Status; - } - - IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID); - - if (!IsValidID) - { - DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode); - } - - /* Save the device id string */ - RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information); - - DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n"); - - Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities); - if (!NT_SUCCESS(Status)) - { - DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status); - RtlFreeUnicodeString(&DeviceId); - return Status; - } - - /* This bit is only check after enumeration */ - if (DeviceCapabilities.HardwareDisabled) - { - /* FIXME: Cleanup device */ - DeviceNode->Flags |= DNF_DISABLED; - RtlFreeUnicodeString(&DeviceId); - return STATUS_PLUGPLAY_NO_DEVICE; - } - else - { - DeviceNode->Flags &= ~DNF_DISABLED; - } - - if (!DeviceCapabilities.UniqueID) - { - /* Device has not a unique ID. We need to prepend parent bus unique identifier */ - DPRINT("Instance ID is not unique\n"); - Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix); - if (!NT_SUCCESS(Status)) - { - DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status); - RtlFreeUnicodeString(&DeviceId); - return Status; - } - } - - DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n"); - - Stack.Parameters.QueryId.IdType = BusQueryInstanceID; - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_ID, - &Stack); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status); - ASSERT(IoStatusBlock.Information == 0); - } - - if (IoStatusBlock.Information) - { - IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID); - - if (!IsValidID) - { - DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode); - } - } - - RtlInitUnicodeString(&InstanceId, - (PWSTR)IoStatusBlock.Information); - - InstancePath->Length = 0; - InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) + - ParentIdPrefix.Length + - InstanceId.Length + - sizeof(UNICODE_NULL); - if (ParentIdPrefix.Length && InstanceId.Length) - { - InstancePath->MaximumLength += sizeof(WCHAR); - } - - InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool, - InstancePath->MaximumLength, - TAG_IO); - if (!InstancePath->Buffer) - { - RtlFreeUnicodeString(&InstanceId); - RtlFreeUnicodeString(&ParentIdPrefix); - RtlFreeUnicodeString(&DeviceId); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Start with the device id */ - RtlCopyUnicodeString(InstancePath, &DeviceId); - RtlAppendUnicodeToString(InstancePath, L"\\"); - - /* Add information from parent bus device to InstancePath */ - RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix); - if (ParentIdPrefix.Length && InstanceId.Length) - { - RtlAppendUnicodeToString(InstancePath, L"&"); - } - - /* Finally, add the id returned by the driver stack */ - RtlAppendUnicodeStringToString(InstancePath, &InstanceId); - - /* - * FIXME: Check for valid characters, if there is invalid characters - * then bugcheck - */ - - RtlFreeUnicodeString(&InstanceId); - RtlFreeUnicodeString(&DeviceId); - RtlFreeUnicodeString(&ParentIdPrefix); - - return STATUS_SUCCESS; -} - -/* - * IopActionInterrogateDeviceStack - * - * Retrieve information for all (direct) child nodes of a parent node. - * - * Parameters - * DeviceNode - * Pointer to device node. - * Context - * Pointer to parent node to retrieve child node information for. - * - * Remarks - * Any errors that occur are logged instead so that all child services have a chance - * of being interrogated. - */ - -NTSTATUS -IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, - PVOID Context) -{ - IO_STATUS_BLOCK IoStatusBlock; - PWSTR DeviceDescription; - PWSTR LocationInformation; - PDEVICE_NODE ParentDeviceNode; - IO_STACK_LOCATION Stack; - NTSTATUS Status; - ULONG RequiredLength; - LCID LocaleId; - HANDLE InstanceKey = NULL; - UNICODE_STRING ValueName; - UNICODE_STRING InstancePathU; - PDEVICE_OBJECT OldDeviceObject; - - DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context); - DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject); - - ParentDeviceNode = (PDEVICE_NODE)Context; - - /* - * We are called for the parent too, but we don't need to do special - * handling for this node - */ - if (DeviceNode == ParentDeviceNode) - { - DPRINT("Success\n"); - return STATUS_SUCCESS; - } - - /* - * Make sure this device node is a direct child of the parent device node - * that is given as an argument - */ - if (DeviceNode->Parent != ParentDeviceNode) - { - DPRINT("Skipping 2+ level child\n"); - return STATUS_SUCCESS; - } - - /* Skip processing if it was already completed before */ - if (DeviceNode->Flags & DNF_PROCESSED) - { - /* Nothing to do */ - return STATUS_SUCCESS; - } - - /* Get Locale ID */ - Status = ZwQueryDefaultLocale(FALSE, &LocaleId); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status); - return Status; - } - - /* - * FIXME: For critical errors, cleanup and disable device, but always - * return STATUS_SUCCESS. - */ - - Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU); - if (!NT_SUCCESS(Status)) - { - if (Status != STATUS_PLUGPLAY_NO_DEVICE) - { - DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status); - } - - /* We have to return success otherwise we abort the traverse operation */ - return STATUS_SUCCESS; - } - - /* Verify that this is not a duplicate */ - OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU); - if (OldDeviceObject != NULL) - { - PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject); - - DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU); - DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath); - DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath); - - KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, - 0x01, - (ULONG_PTR)DeviceNode->PhysicalDeviceObject, - (ULONG_PTR)OldDeviceObject, - 0); - } - - DeviceNode->InstancePath = InstancePathU; - - DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer); - - /* - * Create registry key for the instance id, if it doesn't exist yet - */ - Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to create the instance key! (Status %lx)\n", Status); - - /* We have to return success otherwise we abort the traverse operation */ - return STATUS_SUCCESS; - } - - IopQueryHardwareIds(DeviceNode, InstanceKey); - - IopQueryCompatibleIds(DeviceNode, InstanceKey); - - DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n"); - - Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription; - Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_TEXT, - &Stack); - DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information - : NULL; - /* This key is mandatory, so even if the Irp fails, we still write it */ - RtlInitUnicodeString(&ValueName, L"DeviceDesc"); - if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) - { - if (DeviceDescription && - *DeviceDescription != UNICODE_NULL) - { - /* This key is overriden when a driver is installed. Don't write the - * new description if another one already exists */ - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_SZ, - DeviceDescription, - ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR)); - } - else - { - UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device"); - DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status); - - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_SZ, - DeviceDesc.Buffer, - DeviceDesc.MaximumLength); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status); - } - - } - } - - if (DeviceDescription) - { - ExFreePoolWithTag(DeviceDescription, 0); - } - - DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n"); - - Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation; - Stack.Parameters.QueryDeviceText.LocaleId = LocaleId; - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_TEXT, - &Stack); - if (NT_SUCCESS(Status) && IoStatusBlock.Information) - { - LocationInformation = (PWSTR)IoStatusBlock.Information; - DPRINT("LocationInformation: %S\n", LocationInformation); - RtlInitUnicodeString(&ValueName, L"LocationInformation"); - Status = ZwSetValueKey(InstanceKey, - &ValueName, - 0, - REG_SZ, - LocationInformation, - ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR)); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status); - } - - ExFreePoolWithTag(LocationInformation, 0); - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); - } - - DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n"); - - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_BUS_INFORMATION, - NULL); - if (NT_SUCCESS(Status) && IoStatusBlock.Information) - { - PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information; - - DeviceNode->ChildBusNumber = BusInformation->BusNumber; - DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType; - DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid); - ExFreePoolWithTag(BusInformation, 0); - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); - - DeviceNode->ChildBusNumber = 0xFFFFFFF0; - DeviceNode->ChildInterfaceType = InterfaceTypeUndefined; - DeviceNode->ChildBusTypeIndex = -1; - } - - DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); - - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_RESOURCES, - NULL); - if (NT_SUCCESS(Status) && IoStatusBlock.Information) - { - DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information; - IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); - DeviceNode->BootResources = NULL; - } - - DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); - - Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_RESOURCE_REQUIREMENTS, - NULL); - if (NT_SUCCESS(Status)) - { - DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); - DeviceNode->ResourceRequirements = NULL; - } - - if (InstanceKey != NULL) - { - IopSetDeviceInstanceData(InstanceKey, DeviceNode); - } - - ZwClose(InstanceKey); - - IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED); - - if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER)) - { - /* Report the device to the user-mode pnp manager */ - IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED, - &DeviceNode->InstancePath); - } - - return STATUS_SUCCESS; -} - -static -VOID -IopHandleDeviceRemoval( - IN PDEVICE_NODE DeviceNode, - IN PDEVICE_RELATIONS DeviceRelations) -{ - PDEVICE_NODE Child = DeviceNode->Child, NextChild; - ULONG i; - BOOLEAN Found; - - if (DeviceNode == IopRootDeviceNode) - return; - - while (Child != NULL) - { - NextChild = Child->Sibling; - Found = FALSE; - - for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++) - { - if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child) - { - Found = TRUE; - break; - } - } - - if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED)) - { - /* Send removal IRPs to all of its children */ - IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE); - - /* Send the surprise removal IRP */ - IopSendSurpriseRemoval(Child->PhysicalDeviceObject); - - /* Tell the user-mode PnP manager that a device was removed */ - IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, - &Child->InstancePath); - - /* Send the remove device IRP */ - IopSendRemoveDevice(Child->PhysicalDeviceObject); - } - - Child = NextChild; - } -} - -NTSTATUS -IopEnumerateDevice( - IN PDEVICE_OBJECT DeviceObject) -{ - PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); - DEVICETREE_TRAVERSE_CONTEXT Context; - PDEVICE_RELATIONS DeviceRelations; - PDEVICE_OBJECT ChildDeviceObject; - IO_STATUS_BLOCK IoStatusBlock; - PDEVICE_NODE ChildDeviceNode; - IO_STACK_LOCATION Stack; - NTSTATUS Status; - ULONG i; - - DPRINT("DeviceObject 0x%p\n", DeviceObject); - - if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY) - { - DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY; - - DPRINT("Sending GUID_DEVICE_ARRIVAL\n"); - IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, - &DeviceNode->InstancePath); - } - - DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n"); - - Stack.Parameters.QueryDeviceRelations.Type = BusRelations; - - Status = IopInitiatePnpIrp( - DeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_RELATIONS, - &Stack); - if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) - { - DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); - return Status; - } - - DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; - - /* - * Send removal IRPs for devices that have disappeared - * NOTE: This code handles the case where no relations are specified - */ - IopHandleDeviceRemoval(DeviceNode, DeviceRelations); - - /* Now we bail if nothing was returned */ - if (!DeviceRelations) - { - /* We're all done */ - DPRINT("No PDOs\n"); - return STATUS_SUCCESS; - } - - DPRINT("Got %u PDOs\n", DeviceRelations->Count); - - /* - * Create device nodes for all discovered devices - */ - for (i = 0; i < DeviceRelations->Count; i++) - { - ChildDeviceObject = DeviceRelations->Objects[i]; - ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0); - - ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject); - if (!ChildDeviceNode) - { - /* One doesn't exist, create it */ - Status = IopCreateDeviceNode( - DeviceNode, - ChildDeviceObject, - NULL, - &ChildDeviceNode); - if (NT_SUCCESS(Status)) - { - /* Mark the node as enumerated */ - ChildDeviceNode->Flags |= DNF_ENUMERATED; - - /* Mark the DO as bus enumerated */ - ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE; - } - else - { - /* Ignore this DO */ - DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i); - ObDereferenceObject(ChildDeviceObject); - } - } - else - { - /* Mark it as enumerated */ - ChildDeviceNode->Flags |= DNF_ENUMERATED; - ObDereferenceObject(ChildDeviceObject); - } - } - ExFreePool(DeviceRelations); - - /* - * Retrieve information about all discovered children from the bus driver - */ - IopInitDeviceTreeTraverseContext( - &Context, - DeviceNode, - IopActionInterrogateDeviceStack, - DeviceNode); - - Status = IopTraverseDeviceTree(&Context); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); - return Status; - } - - /* - * Retrieve configuration from the registry for discovered children - */ - IopInitDeviceTreeTraverseContext( - &Context, - DeviceNode, - IopActionConfigureChildServices, - DeviceNode); - - Status = IopTraverseDeviceTree(&Context); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status); - return Status; - } - - /* - * Initialize services for discovered children. - */ - Status = IopInitializePnpServices(DeviceNode); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status); - return Status; - } - - DPRINT("IopEnumerateDevice() finished\n"); - return STATUS_SUCCESS; -} - - -/* - * IopActionConfigureChildServices - * - * Retrieve configuration for all (direct) child nodes of a parent node. - * - * Parameters - * DeviceNode - * Pointer to device node. - * Context - * Pointer to parent node to retrieve child node configuration for. - * - * Remarks - * Any errors that occur are logged instead so that all child services have a chance of beeing - * configured. - */ - -NTSTATUS -IopActionConfigureChildServices(PDEVICE_NODE DeviceNode, - PVOID Context) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[3]; - PDEVICE_NODE ParentDeviceNode; - PUNICODE_STRING Service; - UNICODE_STRING ClassGUID; - NTSTATUS Status; - DEVICE_CAPABILITIES DeviceCaps; - - DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context); - - ParentDeviceNode = (PDEVICE_NODE)Context; - - /* - * We are called for the parent too, but we don't need to do special - * handling for this node - */ - if (DeviceNode == ParentDeviceNode) - { - DPRINT("Success\n"); - return STATUS_SUCCESS; - } - - /* - * Make sure this device node is a direct child of the parent device node - * that is given as an argument - */ - - if (DeviceNode->Parent != ParentDeviceNode) - { - DPRINT("Skipping 2+ level child\n"); - return STATUS_SUCCESS; - } - - if (!(DeviceNode->Flags & DNF_PROCESSED)) - { - DPRINT1("Child not ready to be configured\n"); - return STATUS_SUCCESS; - } - - if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED))) - { - UNICODE_STRING RegKey; - - /* Install the service for this if it's in the CDDB */ - IopInstallCriticalDevice(DeviceNode); - - /* - * Retrieve configuration from Enum key - */ - - Service = &DeviceNode->ServiceName; - - RtlZeroMemory(QueryTable, sizeof(QueryTable)); - RtlInitUnicodeString(Service, NULL); - RtlInitUnicodeString(&ClassGUID, NULL); - - QueryTable[0].Name = L"Service"; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; - QueryTable[0].EntryContext = Service; - - QueryTable[1].Name = L"ClassGUID"; - QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; - QueryTable[1].EntryContext = &ClassGUID; - QueryTable[1].DefaultType = REG_SZ; - QueryTable[1].DefaultData = L""; - QueryTable[1].DefaultLength = 0; - - RegKey.Length = 0; - RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) + DeviceNode->InstancePath.Length; - RegKey.Buffer = ExAllocatePoolWithTag(PagedPool, - RegKey.MaximumLength, - TAG_IO); - if (RegKey.Buffer == NULL) - { - IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlAppendUnicodeToString(&RegKey, ENUM_ROOT); - RtlAppendUnicodeToString(&RegKey, L"\\"); - RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath); - - Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, - RegKey.Buffer, QueryTable, NULL, NULL); - ExFreePoolWithTag(RegKey.Buffer, TAG_IO); - - if (!NT_SUCCESS(Status)) - { - /* FIXME: Log the error */ - DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n", - &DeviceNode->InstancePath, Status); - IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); - return STATUS_SUCCESS; - } - - if (Service->Buffer == NULL) - { - if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) && - DeviceCaps.RawDeviceOK) - { - DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName); - RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0); - } - else if (ClassGUID.Length != 0) - { - /* Device has a ClassGUID value, but no Service value. - * Suppose it is using the NULL driver, so state the - * device is started */ - DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath); - IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); - } - else - { - DeviceNode->Problem = CM_PROB_FAILED_INSTALL; - IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); - } - return STATUS_SUCCESS; - } - - DPRINT("Got Service %S\n", Service->Buffer); - } - - return STATUS_SUCCESS; -} - -/* - * IopActionInitChildServices - * - * Initialize the service for all (direct) child nodes of a parent node - * - * Parameters - * DeviceNode - * Pointer to device node. - * Context - * Pointer to parent node to initialize child node services for. - * - * Remarks - * If the driver image for a service is not loaded and initialized - * it is done here too. Any errors that occur are logged instead so - * that all child services have a chance of being initialized. - */ - -NTSTATUS -IopActionInitChildServices(PDEVICE_NODE DeviceNode, - PVOID Context) -{ - PDEVICE_NODE ParentDeviceNode; - NTSTATUS Status; - BOOLEAN BootDrivers = !PnpSystemInit; - - DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context); - - ParentDeviceNode = Context; - - /* - * We are called for the parent too, but we don't need to do special - * handling for this node - */ - if (DeviceNode == ParentDeviceNode) - { - DPRINT("Success\n"); - return STATUS_SUCCESS; - } - - /* - * We don't want to check for a direct child because - * this function is called during boot to reinitialize - * devices with drivers that couldn't load yet due to - * stage 0 limitations (ie can't load from disk yet). - */ - - if (!(DeviceNode->Flags & DNF_PROCESSED)) - { - DPRINT1("Child not ready to be added\n"); - return STATUS_SUCCESS; - } - - if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) || - IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) || - IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED)) - return STATUS_SUCCESS; - - if (DeviceNode->ServiceName.Buffer == NULL) - { - /* We don't need to worry about loading the driver because we're - * being driven in raw mode so our parent must be loaded to get here */ - Status = IopInitializeDevice(DeviceNode, NULL); - if (NT_SUCCESS(Status)) - { - Status = IopStartDevice(DeviceNode); - if (!NT_SUCCESS(Status)) - { - DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n", - &DeviceNode->InstancePath, Status); - } - } - } - else - { - PLDR_DATA_TABLE_ENTRY ModuleObject; - PDRIVER_OBJECT DriverObject; - - KeEnterCriticalRegion(); - ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE); - /* Get existing DriverObject pointer (in case the driver has - already been loaded and initialized) */ - Status = IopGetDriverObject( - &DriverObject, - &DeviceNode->ServiceName, - FALSE); - - if (!NT_SUCCESS(Status)) - { - /* Driver is not initialized, try to load it */ - Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject); - - if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED) - { - /* Initialize the driver */ - Status = IopInitializeDriverModule(DeviceNode, ModuleObject, - &DeviceNode->ServiceName, FALSE, &DriverObject); - if (!NT_SUCCESS(Status)) - DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY; - } - else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD) - { - DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName); - DeviceNode->Problem = CM_PROB_DISABLED_SERVICE; - } - else - { - DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n", - &DeviceNode->ServiceName, Status); - if (!BootDrivers) - DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD; - } - } - ExReleaseResourceLite(&IopDriverLoadResource); - KeLeaveCriticalRegion(); - - /* Driver is loaded and initialized at this point */ - if (NT_SUCCESS(Status)) - { - /* Initialize the device, including all filters */ - Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject); - - /* Remove the extra reference */ - ObDereferenceObject(DriverObject); - } - else - { - /* - * Don't disable when trying to load only boot drivers - */ - if (!BootDrivers) - { - IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED); - } - } - } - - return STATUS_SUCCESS; -} - -/* - * IopInitializePnpServices - * - * Initialize services for discovered children - * - * Parameters - * DeviceNode - * Top device node to start initializing services. - * - * Return Value - * Status - */ -NTSTATUS -IopInitializePnpServices(IN PDEVICE_NODE DeviceNode) -{ - DEVICETREE_TRAVERSE_CONTEXT Context; - - DPRINT("IopInitializePnpServices(%p)\n", DeviceNode); - - IopInitDeviceTreeTraverseContext( - &Context, - DeviceNode, - IopActionInitChildServices, - DeviceNode); - - return IopTraverseDeviceTree(&Context); -} - static INIT_FUNCTION NTSTATUS @@ -4137,125 +2302,6 @@ IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject, return Status; } -/* - * @implemented - */ -VOID -NTAPI -IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject) -{ - PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); - IO_STACK_LOCATION Stack; - ULONG_PTR PnPFlags; - NTSTATUS Status; - IO_STATUS_BLOCK IoStatusBlock; - - RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION)); - Stack.MajorFunction = IRP_MJ_PNP; - Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE; - - Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags); - if (!NT_SUCCESS(Status)) - { - if (Status != STATUS_NOT_SUPPORTED) - { - DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status); - } - return; - } - - if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE) - DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE; - else - DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE; - - if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI) - DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI; - else - DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI; - - if ((PnPFlags & PNP_DEVICE_REMOVED) || - ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))) - { - /* Flag it if it's failed */ - if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START; - - /* Send removal IRPs to all of its children */ - IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE); - - /* Send surprise removal */ - IopSendSurpriseRemoval(PhysicalDeviceObject); - - /* Tell the user-mode PnP manager that a device was removed */ - IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, - &DeviceNode->InstancePath); - - IopSendRemoveDevice(PhysicalDeviceObject); - } - else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)) - { - /* Stop for resource rebalance */ - Status = IopStopDevice(DeviceNode); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to stop device for rebalancing\n"); - - /* Stop failed so don't rebalance */ - PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED; - } - } - - /* Resource rebalance */ - if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED) - { - DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n"); - - Status = IopInitiatePnpIrp(PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_RESOURCES, - NULL); - if (NT_SUCCESS(Status) && IoStatusBlock.Information) - { - DeviceNode->BootResources = - (PCM_RESOURCE_LIST)IoStatusBlock.Information; - IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status); - DeviceNode->BootResources = NULL; - } - - DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n"); - - Status = IopInitiatePnpIrp(PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_RESOURCE_REQUIREMENTS, - NULL); - if (NT_SUCCESS(Status)) - { - DeviceNode->ResourceRequirements = - (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information; - } - else - { - DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status); - DeviceNode->ResourceRequirements = NULL; - } - - /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */ - if (IopStartDevice(DeviceNode) != STATUS_SUCCESS) - { - DPRINT1("Restart after resource rebalance failed\n"); - - DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING); - DeviceNode->Flags |= DNF_START_FAILED; - - IopRemoveDevice(DeviceNode); - } - } -} - /** * @name IoOpenDeviceRegistryKey * @@ -4419,380 +2465,6 @@ IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, return Status; } -static -NTSTATUS -IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force) -{ - PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice; - NTSTATUS Status; - KIRQL OldIrql; - - KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); - ChildDeviceNode = ParentDeviceNode->Child; - while (ChildDeviceNode != NULL) - { - NextDeviceNode = ChildDeviceNode->Sibling; - KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); - - Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force); - if (!NT_SUCCESS(Status)) - { - FailedRemoveDevice = ChildDeviceNode; - goto cleanup; - } - - KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); - ChildDeviceNode = NextDeviceNode; - } - KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); - - return STATUS_SUCCESS; - -cleanup: - KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); - ChildDeviceNode = ParentDeviceNode->Child; - while (ChildDeviceNode != NULL) - { - NextDeviceNode = ChildDeviceNode->Sibling; - KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); - - IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); - - /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device - * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ - if (ChildDeviceNode == FailedRemoveDevice) - return Status; - - ChildDeviceNode = NextDeviceNode; - - KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); - } - KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); - - return Status; -} - -static -VOID -IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) -{ - PDEVICE_NODE ChildDeviceNode, NextDeviceNode; - KIRQL OldIrql; - - KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); - ChildDeviceNode = ParentDeviceNode->Child; - while (ChildDeviceNode != NULL) - { - NextDeviceNode = ChildDeviceNode->Sibling; - KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); - - IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject); - - ChildDeviceNode = NextDeviceNode; - - KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); - } - KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); -} - -static -VOID -IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode) -{ - PDEVICE_NODE ChildDeviceNode, NextDeviceNode; - KIRQL OldIrql; - - KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); - ChildDeviceNode = ParentDeviceNode->Child; - while (ChildDeviceNode != NULL) - { - NextDeviceNode = ChildDeviceNode->Sibling; - KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); - - IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject); - - ChildDeviceNode = NextDeviceNode; - - KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql); - } - KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql); -} - -static -NTSTATUS -IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force) -{ - /* This function DOES NOT dereference the device objects on SUCCESS - * but it DOES dereference device objects on FAILURE */ - - ULONG i, j; - NTSTATUS Status; - - for (i = 0; i < DeviceRelations->Count; i++) - { - Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force); - if (!NT_SUCCESS(Status)) - { - j = i; - goto cleanup; - } - } - - return STATUS_SUCCESS; - -cleanup: - /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device - * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */ - for (i = 0; i <= j; i++) - { - IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); - ObDereferenceObject(DeviceRelations->Objects[i]); - DeviceRelations->Objects[i] = NULL; - } - for (; i < DeviceRelations->Count; i++) - { - ObDereferenceObject(DeviceRelations->Objects[i]); - DeviceRelations->Objects[i] = NULL; - } - ExFreePool(DeviceRelations); - - return Status; -} - -static -VOID -IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) -{ - /* This function DOES dereference the device objects in all cases */ - - ULONG i; - - for (i = 0; i < DeviceRelations->Count; i++) - { - IopSendRemoveDevice(DeviceRelations->Objects[i]); - DeviceRelations->Objects[i] = NULL; - } - - ExFreePool(DeviceRelations); -} - -static -VOID -IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations) -{ - /* This function DOES dereference the device objects in all cases */ - - ULONG i; - - for (i = 0; i < DeviceRelations->Count; i++) - { - IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]); - ObDereferenceObject(DeviceRelations->Objects[i]); - DeviceRelations->Objects[i] = NULL; - } - - ExFreePool(DeviceRelations); -} - -VOID -IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject) -{ - IO_STACK_LOCATION Stack; - IO_STATUS_BLOCK IoStatusBlock; - PDEVICE_RELATIONS DeviceRelations; - NTSTATUS Status; - - IopCancelRemoveDevice(DeviceObject); - - Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; - - Status = IopInitiatePnpIrp(DeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_RELATIONS, - &Stack); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); - DeviceRelations = NULL; - } - else - { - DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; - } - - if (DeviceRelations) - IopCancelRemoveDeviceRelations(DeviceRelations); -} - -NTSTATUS -IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force) -{ - PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); - IO_STACK_LOCATION Stack; - IO_STATUS_BLOCK IoStatusBlock; - PDEVICE_RELATIONS DeviceRelations; - NTSTATUS Status; - - if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force) - { - DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath); - return STATUS_UNSUCCESSFUL; - } - - if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS) - { - DPRINT1("Removal vetoed by failing the query remove request\n"); - - IopCancelRemoveDevice(DeviceObject); - - return STATUS_UNSUCCESSFUL; - } - - Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations; - - Status = IopInitiatePnpIrp(DeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_RELATIONS, - &Stack); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); - DeviceRelations = NULL; - } - else - { - DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; - } - - if (DeviceRelations) - { - Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force); - if (!NT_SUCCESS(Status)) - return Status; - } - - Status = IopQueryRemoveChildDevices(DeviceNode, Force); - if (!NT_SUCCESS(Status)) - { - if (DeviceRelations) - IopCancelRemoveDeviceRelations(DeviceRelations); - return Status; - } - - if (DeviceRelations) - IopSendRemoveDeviceRelations(DeviceRelations); - IopSendRemoveChildDevices(DeviceNode); - - return STATUS_SUCCESS; -} - -NTSTATUS -IopRemoveDevice(PDEVICE_NODE DeviceNode) -{ - NTSTATUS Status; - - DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath); - - Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE); - if (NT_SUCCESS(Status)) - { - IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject); - IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, - &DeviceNode->InstancePath); - return STATUS_SUCCESS; - } - - return Status; -} - -/* - * @implemented - */ -VOID -NTAPI -IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject) -{ - PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject); - PDEVICE_RELATIONS DeviceRelations; - IO_STATUS_BLOCK IoStatusBlock; - IO_STACK_LOCATION Stack; - DEVICE_CAPABILITIES Capabilities; - NTSTATUS Status; - - IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT, - &DeviceNode->InstancePath); - - if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS) - { - goto cleanup; - } - - Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations; - - Status = IopInitiatePnpIrp(PhysicalDeviceObject, - &IoStatusBlock, - IRP_MN_QUERY_DEVICE_RELATIONS, - &Stack); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status); - DeviceRelations = NULL; - } - else - { - DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; - } - - if (DeviceRelations) - { - Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE); - if (!NT_SUCCESS(Status)) - goto cleanup; - } - - Status = IopQueryRemoveChildDevices(DeviceNode, FALSE); - if (!NT_SUCCESS(Status)) - { - if (DeviceRelations) - IopCancelRemoveDeviceRelations(DeviceRelations); - goto cleanup; - } - - if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS) - { - if (DeviceRelations) - IopCancelRemoveDeviceRelations(DeviceRelations); - IopCancelRemoveChildDevices(DeviceNode); - goto cleanup; - } - - if (DeviceRelations) - IopSendRemoveDeviceRelations(DeviceRelations); - IopSendRemoveChildDevices(DeviceNode); - - DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT; - if (Capabilities.EjectSupported) - { - if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS) - { - goto cleanup; - } - } - else - { - DeviceNode->Flags |= DNF_DISABLED; - } - - IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT, - &DeviceNode->InstancePath); - - return; - -cleanup: - IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED, - &DeviceNode->InstancePath); -} - /* * @implemented */ diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake index a938a42b783..e6c059fdb49 100644 --- a/ntoskrnl/ntos.cmake +++ b/ntoskrnl/ntos.cmake @@ -152,6 +152,7 @@ list(APPEND SOURCE ${REACTOS_SOURCE_DIR}/ntoskrnl/io/iomgr/util.c ${REACTOS_SOURCE_DIR}/ntoskrnl/io/iomgr/volume.c ${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/arbs.c + ${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/devaction.c ${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/devnode.c ${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/plugplay.c ${REACTOS_SOURCE_DIR}/ntoskrnl/io/pnpmgr/pnpdma.c