[NTOS:IO] Move device manipulation functions from pnpmgr/pnpmgr.c to pnpmgr/devaction.c 2940/head
authorVictor Perevertkin <victor.perevertkin@reactos.org>
Sun, 21 Jun 2020 14:54:44 +0000 (17:54 +0300)
committerVictor Perevertkin <victor.perevertkin@reactos.org>
Wed, 24 Jun 2020 01:03:35 +0000 (04:03 +0300)
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 [new file with mode: 0644]
ntoskrnl/io/pnpmgr/pnpmgr.c
ntoskrnl/ntos.cmake

diff --git a/ntoskrnl/io/pnpmgr/devaction.c b/ntoskrnl/io/pnpmgr/devaction.c
new file mode 100644 (file)
index 0000000..1687709
--- /dev/null
@@ -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 <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* 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);
+}
index 436e137..8b9c92c 100644 (file)
@@ -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,2380 +458,565 @@ 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)
+IopGetSystemPowerDeviceObject(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);
+    KIRQL OldIrql;
 
-    if (!NT_SUCCESS(Status))
+    if (PopSystemPowerDeviceNode)
     {
-        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;
+        KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
+        *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
+        KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
 
-    /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
-    IopSynchronousCall(DeviceObject, &Stack, &Dummy);
+        return STATUS_SUCCESS;
+    }
 
-    IopNotifyPlugPlayNotification(DeviceObject,
-                                  EventCategoryTargetDeviceChange,
-                                  &GUID_TARGET_DEVICE_REMOVE_CANCELLED,
-                                  NULL,
-                                  NULL);
+    return STATUS_UNSUCCESSFUL;
 }
 
-static
-VOID
+USHORT
 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)
+IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
 {
-    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;
+    USHORT i = 0, FoundIndex = 0xFFFF;
+    ULONG NewSize;
+    PVOID NewList;
 
-    DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode);
-    DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath);
-    DPRINT("Service: %wZ\n", &DeviceNode->ServiceName);
+    /* Acquire the lock */
+    ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
 
-    if (DeviceNode->ServiceName.Buffer == NULL)
+    /* Loop all entries */
+    while (i < PnpBusTypeGuidList->GuidCount)
     {
-        DPRINT1("No service!\n");
-        return STATUS_SUCCESS;
+         /* Try to find a match */
+         if (RtlCompareMemory(BusTypeGuid,
+                              &PnpBusTypeGuidList->Guids[i],
+                              sizeof(GUID)) == sizeof(GUID))
+         {
+              /* Found it */
+              FoundIndex = i;
+              goto Quickie;
+         }
+         i++;
     }
 
-    ServiceKeyName.MaximumLength = ServicesKeyPath.Length + DeviceNode->ServiceName.Length + sizeof(UNICODE_NULL);
-    ServiceKeyName.Length = 0;
-    ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength);
-    if (ServiceKeyName.Buffer == NULL)
+    /* Check if we have to grow the list */
+    if (PnpBusTypeGuidList->GuidCount)
     {
-        DPRINT1("No ServiceKeyName.Buffer!\n");
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath);
-    RtlAppendUnicodeStringToString(&ServiceKeyName, &DeviceNode->ServiceName);
-
-    DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName);
+        /* Calculate the new size */
+        NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
+                 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
 
-    Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY);
-    if (!NT_SUCCESS(Status))
-    {
-        goto done;
-    }
+        /* Allocate the new copy */
+        NewList = ExAllocatePool(PagedPool, NewSize);
 
-    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)
+        if (!NewList)
         {
-            /* 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;
+            /* Fail */
+            ExFreePool(PnpBusTypeGuidList);
+            goto Quickie;
         }
 
-        /* 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++;
+        /* Now copy them, decrease the size too */
+        NewSize -= sizeof(GUID);
+        RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
 
-        /* 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;
+        /* Free the old list */
+        ExFreePool(PnpBusTypeGuidList);
 
-        /* Set the new NextInstance value */
-        RtlInitUnicodeString(&ValueName, L"NextInstance");
-        Status = ZwSetValueKey(ServiceEnumKey,
-                               &ValueName,
-                               0,
-                               REG_DWORD,
-                               &NextInstance,
-                               sizeof(NextInstance));
+        /* Use the new buffer */
+        PnpBusTypeGuidList = NewList;
     }
 
-done:
-    if (ServiceEnumKey != NULL)
-        ZwClose(ServiceEnumKey);
-
-    if (ServiceKey != NULL)
-        ZwClose(ServiceKey);
+    /* Copy the new GUID */
+    RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
+                  BusTypeGuid,
+                  sizeof(GUID));
 
-    ExFreePool(ServiceKeyName.Buffer);
+    /* The new entry is the index */
+    FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
+    PnpBusTypeGuidList->GuidCount++;
 
-    return Status;
+Quickie:
+    ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
+    return FoundIndex;
 }
 
-VOID
+NTSTATUS
 NTAPI
-IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
+IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
+                   IN PIO_STACK_LOCATION IoStackLocation,
+                   OUT PVOID *Information)
 {
-    IO_STACK_LOCATION Stack;
-    PDEVICE_NODE DeviceNode;
+    PIRP Irp;
+    PIO_STACK_LOCATION IrpStack;
+    IO_STATUS_BLOCK IoStatusBlock;
+    KEVENT Event;
     NTSTATUS Status;
-    PVOID Dummy;
-    DEVICE_CAPABILITIES DeviceCapabilities;
-
-    /* Get the device node */
-    DeviceNode = IopGetDeviceNode(DeviceObject);
+    PDEVICE_OBJECT TopDeviceObject;
+    PAGED_CODE();
 
-    ASSERT(!(DeviceNode->Flags & DNF_DISABLED));
+    /* Call the top of the device stack */
+    TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
 
-    /* Build the I/O stack location */
-    RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
-    Stack.MajorFunction = IRP_MJ_PNP;
-    Stack.MinorFunction = IRP_MN_START_DEVICE;
+    /* Allocate an IRP */
+    Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
+    if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
 
-    Stack.Parameters.StartDevice.AllocatedResources =
-         DeviceNode->ResourceList;
-    Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
-         DeviceNode->ResourceListTranslated;
+    /* Initialize to failure */
+    Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
+    Irp->IoStatus.Information = IoStatusBlock.Information = 0;
 
-    /* Do the call */
-    Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
-    if (!NT_SUCCESS(Status))
+    /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
+    if ((IoStackLocation->MajorFunction == IRP_MJ_PNP) &&
+        (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS))
     {
-        /* Send an IRP_MN_REMOVE_DEVICE request */
-        IopRemoveDevice(DeviceNode);
+        /* Copy the resource requirements list into the IOSB */
+        Irp->IoStatus.Information =
+        IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
+    }
 
-        /* Set the appropriate flag */
-        DeviceNode->Flags |= DNF_START_FAILED;
-        DeviceNode->Problem = CM_PROB_FAILED_START;
+    /* Initialize the event */
+    KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
 
-        DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status);
-        return;
-    }
+    /* Set them up */
+    Irp->UserIosb = &IoStatusBlock;
+    Irp->UserEvent = &Event;
+
+    /* Queue the IRP */
+    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+    IoQueueThreadIrp(Irp);
 
-    DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
+    /* Copy-in the stack */
+    IrpStack = IoGetNextIrpStackLocation(Irp);
+    *IrpStack = *IoStackLocation;
 
-    Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
-    if (!NT_SUCCESS(Status))
+    /* Call the driver */
+    Status = IoCallDriver(TopDeviceObject, Irp);
+    if (Status == STATUS_PENDING)
     {
-        DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
+        /* Wait for it */
+        KeWaitForSingleObject(&Event,
+                              Executive,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+        Status = IoStatusBlock.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;
+    /* Remove the reference */
+    ObDereferenceObject(TopDeviceObject);
 
-    /* We now need enumeration */
-    DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
+    /* Return the information */
+    *Information = (PVOID)IoStatusBlock.Information;
+    return Status;
 }
 
 NTSTATUS
 NTAPI
-IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
+IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
+                  IN OUT PIO_STATUS_BLOCK IoStatusBlock,
+                  IN UCHAR MinorFunction,
+                  IN PIO_STACK_LOCATION Stack OPTIONAL)
 {
-    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);
-    }
+    IO_STACK_LOCATION IoStackLocation;
 
-    /* Do we need to query IDs? This happens in the case of manual reporting */
-#if 0
-    if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
+    /* Fill out the stack information */
+    RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
+    IoStackLocation.MajorFunction = IRP_MJ_PNP;
+    IoStackLocation.MinorFunction = MinorFunction;
+    if (Stack)
     {
-        DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
-        /* And that case shouldn't happen yet */
-        ASSERT(FALSE);
+        /* Copy the rest */
+        RtlCopyMemory(&IoStackLocation.Parameters,
+                      &Stack->Parameters,
+                      sizeof(Stack->Parameters));
     }
-#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;
-}
+    /* Do the PnP call */
+    IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
+                                               &IoStackLocation,
+                                               (PVOID)&IoStatusBlock->Information);
+    return IoStatusBlock->Status;
+}
 
+/*
+ * IopCreateDeviceKeyPath
+ *
+ * Creates a registry key
+ *
+ * Parameters
+ *    RegistryPath
+ *        Name of the key to be created.
+ *    Handle
+ *        Handle to the newly created key
+ *
+ * Remarks
+ *     This method can create nested trees, so parent of RegistryPath can
+ *     be not existant, and will be created if needed.
+ */
 NTSTATUS
-IopStopDevice(
-    PDEVICE_NODE DeviceNode)
+NTAPI
+IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
+                       IN ULONG CreateOptions,
+                       OUT PHANDLE Handle)
 {
+    UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
+    HANDLE hParent = NULL, hKey;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING KeyName;
+    PCWSTR Current, Last;
+    USHORT Length;
     NTSTATUS Status;
 
-    DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath);
+    /* Assume failure */
+    *Handle = NULL;
+
+    /* Open root key for device instances */
+    Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
+        return Status;
+    }
+
+    Current = KeyName.Buffer = RegistryPath->Buffer;
+    Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
 
-    Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject);
-    if (NT_SUCCESS(Status))
+    /* Go up to the end of the string */
+    while (Current <= Last)
     {
-        IopSendStopDevice(DeviceNode->PhysicalDeviceObject);
+        if (Current != Last && *Current != L'\\')
+        {
+            /* Not the end of the string and not a separator */
+            Current++;
+            continue;
+        }
 
-        DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
-        DeviceNode->Flags |= DNF_STOPPED;
+        /* Prepare relative key name */
+        Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
+        KeyName.MaximumLength = KeyName.Length = Length;
+        DPRINT("Create '%wZ'\n", &KeyName);
 
-        return STATUS_SUCCESS;
+        /* Open key */
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &KeyName,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   hParent,
+                                   NULL);
+        Status = ZwCreateKey(&hKey,
+                             Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
+                             &ObjectAttributes,
+                             0,
+                             NULL,
+                             CreateOptions,
+                             NULL);
+
+        /* Close parent key handle, we don't need it anymore */
+        if (hParent)
+            ZwClose(hParent);
+
+        /* Key opening/creating failed? */
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
+            return Status;
+        }
+
+        /* Check if it is the end of the string */
+        if (Current == Last)
+        {
+            /* Yes, return success */
+            *Handle = hKey;
+            return STATUS_SUCCESS;
+        }
+
+        /* Start with this new parent key */
+        hParent = hKey;
+        Current++;
+        KeyName.Buffer = (PWSTR)Current;
     }
 
-    return Status;
+    return STATUS_UNSUCCESSFUL;
 }
 
 NTSTATUS
-IopStartDevice(
-    PDEVICE_NODE DeviceNode)
+IopSetDeviceInstanceData(HANDLE InstanceKey,
+                         PDEVICE_NODE DeviceNode)
 {
-    NTSTATUS Status;
-    HANDLE InstanceHandle = NULL, ControlHandle = NULL;
-    UNICODE_STRING KeyName, ValueString;
     OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING KeyName;
+    HANDLE LogConfKey, ControlKey, DeviceParamsKey;
+    ULONG ResCount;
+    ULONG ResultLength;
+    NTSTATUS Status;
 
-    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;
+    DPRINT("IopSetDeviceInstanceData() called\n");
 
-    /* FIX: Should be done in IoXxxPrepareDriverLoading */
-    // {
-    RtlInitUnicodeString(&KeyName, L"Control");
+    /* Create the 'LogConf' key */
+    RtlInitUnicodeString(&KeyName, L"LogConf");
     InitializeObjectAttributes(&ObjectAttributes,
                                &KeyName,
                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               InstanceHandle,
+                               InstanceKey,
                                NULL);
-    Status = ZwCreateKey(&ControlHandle,
-                         KEY_SET_VALUE,
+    Status = ZwCreateKey(&LogConfKey,
+                         KEY_ALL_ACCESS,
                          &ObjectAttributes,
                          0,
                          NULL,
+                         // FIXME? In r53694 it was silently turned from non-volatile into this,
+                         // without any extra warning. Is this still needed??
                          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)
+        /* Set 'BootConfig' value */
+        if (DeviceNode->BootResources != NULL)
         {
-            RtlInitUnicodeString(&ValueName, L"UINumber");
-            Status = ZwSetValueKey(InstanceKey,
-                                   &ValueName,
-                                   0,
-                                   REG_DWORD,
-                                   &DeviceCaps->UINumber,
-                                   sizeof(ULONG));
+            ResCount = DeviceNode->BootResources->Count;
+            if (ResCount != 0)
+            {
+                RtlInitUnicodeString(&KeyName, L"BootConfig");
+                Status = ZwSetValueKey(LogConfKey,
+                                       &KeyName,
+                                       0,
+                                       REG_RESOURCE_LIST,
+                                       DeviceNode->BootResources,
+                                       PnpDetermineResourceListSize(DeviceNode->BootResources));
+            }
         }
 
-        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)
+        /* Set 'BasicConfigVector' value */
+        if (DeviceNode->ResourceRequirements != NULL &&
+            DeviceNode->ResourceRequirements->ListSize != 0)
         {
-            case DeviceActionInvalidateDeviceRelations:
-                IoSynchronousInvalidateDeviceRelations(Data->DeviceObject,
-                                                       Data->InvalidateDeviceRelations.Type);
-                break;
-
-            default:
-                DPRINT1("Unimplemented device action %u\n", Data->Action);
-                break;
+            RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
+            Status = ZwSetValueKey(LogConfKey,
+                                   &KeyName,
+                                   0,
+                                   REG_RESOURCE_REQUIREMENTS_LIST,
+                                   DeviceNode->ResourceRequirements,
+                                   DeviceNode->ResourceRequirements->ListSize);
         }
 
-        ObDereferenceObject(Data->DeviceObject);
-        ExFreePoolWithTag(Data, TAG_IO);
-        KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
+        ZwClose(LogConfKey);
     }
-    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)
+    /* Set the 'ConfigFlags' value */
+    RtlInitUnicodeString(&KeyName, L"ConfigFlags");
+    Status = ZwQueryValueKey(InstanceKey,
+                             &KeyName,
+                             KeyValueBasicInformation,
+                             NULL,
+                             0,
+                             &ResultLength);
+    if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
     {
-        KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
-        return;
+        /* Write the default value */
+        ULONG DefaultConfigFlags = 0;
+        Status = ZwSetValueKey(InstanceKey,
+                               &KeyName,
+                               0,
+                               REG_DWORD,
+                               &DefaultConfigFlags,
+                               sizeof(DefaultConfigFlags));
     }
-    IopDeviceActionInProgress = TRUE;
-    KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
 
-    ExInitializeWorkItem(&IopDeviceActionWorkItem,
-                         IopDeviceActionWorker,
+    /* Create the 'Control' key */
+    RtlInitUnicodeString(&KeyName, L"Control");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyName,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               InstanceKey,
+                               NULL);
+    Status = ZwCreateKey(&ControlKey,
+                         0,
+                         &ObjectAttributes,
+                         0,
+                         NULL,
+                         REG_OPTION_VOLATILE,
                          NULL);
-    ExQueueWorkItem(&IopDeviceActionWorkItem,
-                    DelayedWorkQueue);
-}
-
-NTSTATUS
-IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
-{
-    KIRQL OldIrql;
-
-    if (PopSystemPowerDeviceNode)
-    {
-        KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
-        *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
-        KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
-
-        return STATUS_SUCCESS;
-    }
-
-    return STATUS_UNSUCCESSFUL;
-}
-
-USHORT
-NTAPI
-IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
-{
-    USHORT i = 0, FoundIndex = 0xFFFF;
-    ULONG NewSize;
-    PVOID NewList;
-
-    /* Acquire the lock */
-    ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
-
-    /* Loop all entries */
-    while (i < PnpBusTypeGuidList->GuidCount)
-    {
-         /* Try to find a match */
-         if (RtlCompareMemory(BusTypeGuid,
-                              &PnpBusTypeGuidList->Guids[i],
-                              sizeof(GUID)) == sizeof(GUID))
-         {
-              /* Found it */
-              FoundIndex = i;
-              goto Quickie;
-         }
-         i++;
-    }
-
-    /* Check if we have to grow the list */
-    if (PnpBusTypeGuidList->GuidCount)
-    {
-        /* Calculate the new size */
-        NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
-                 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
-
-        /* Allocate the new copy */
-        NewList = ExAllocatePool(PagedPool, NewSize);
-
-        if (!NewList)
-        {
-            /* Fail */
-            ExFreePool(PnpBusTypeGuidList);
-            goto Quickie;
-        }
-
-        /* Now copy them, decrease the size too */
-        NewSize -= sizeof(GUID);
-        RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
-
-        /* Free the old list */
-        ExFreePool(PnpBusTypeGuidList);
-
-        /* Use the new buffer */
-        PnpBusTypeGuidList = NewList;
-    }
-
-    /* Copy the new GUID */
-    RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
-                  BusTypeGuid,
-                  sizeof(GUID));
-
-    /* The new entry is the index */
-    FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
-    PnpBusTypeGuidList->GuidCount++;
-
-Quickie:
-    ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
-    return FoundIndex;
-}
-
-NTSTATUS
-NTAPI
-IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
-                   IN PIO_STACK_LOCATION IoStackLocation,
-                   OUT PVOID *Information)
-{
-    PIRP Irp;
-    PIO_STACK_LOCATION IrpStack;
-    IO_STATUS_BLOCK IoStatusBlock;
-    KEVENT Event;
-    NTSTATUS Status;
-    PDEVICE_OBJECT TopDeviceObject;
-    PAGED_CODE();
-
-    /* Call the top of the device stack */
-    TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
-
-    /* Allocate an IRP */
-    Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
-    if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
-
-    /* Initialize to failure */
-    Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
-    Irp->IoStatus.Information = IoStatusBlock.Information = 0;
-
-    /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
-    if ((IoStackLocation->MajorFunction == IRP_MJ_PNP) &&
-        (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS))
-    {
-        /* Copy the resource requirements list into the IOSB */
-        Irp->IoStatus.Information =
-        IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
-    }
-
-    /* Initialize the event */
-    KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
-
-    /* Set them up */
-    Irp->UserIosb = &IoStatusBlock;
-    Irp->UserEvent = &Event;
-
-    /* Queue the IRP */
-    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
-    IoQueueThreadIrp(Irp);
-
-    /* Copy-in the stack */
-    IrpStack = IoGetNextIrpStackLocation(Irp);
-    *IrpStack = *IoStackLocation;
-
-    /* Call the driver */
-    Status = IoCallDriver(TopDeviceObject, Irp);
-    if (Status == STATUS_PENDING)
-    {
-        /* Wait for it */
-        KeWaitForSingleObject(&Event,
-                              Executive,
-                              KernelMode,
-                              FALSE,
-                              NULL);
-        Status = IoStatusBlock.Status;
-    }
-
-    /* Remove the reference */
-    ObDereferenceObject(TopDeviceObject);
-
-    /* Return the information */
-    *Information = (PVOID)IoStatusBlock.Information;
-    return Status;
-}
-
-NTSTATUS
-NTAPI
-IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
-                  IN OUT PIO_STATUS_BLOCK IoStatusBlock,
-                  IN UCHAR MinorFunction,
-                  IN PIO_STACK_LOCATION Stack OPTIONAL)
-{
-    IO_STACK_LOCATION IoStackLocation;
-
-    /* Fill out the stack information */
-    RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
-    IoStackLocation.MajorFunction = IRP_MJ_PNP;
-    IoStackLocation.MinorFunction = MinorFunction;
-    if (Stack)
-    {
-        /* Copy the rest */
-        RtlCopyMemory(&IoStackLocation.Parameters,
-                      &Stack->Parameters,
-                      sizeof(Stack->Parameters));
-    }
-
-    /* Do the PnP call */
-    IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
-                                               &IoStackLocation,
-                                               (PVOID)&IoStatusBlock->Information);
-    return IoStatusBlock->Status;
-}
-
-/*
- * IopCreateDeviceKeyPath
- *
- * Creates a registry key
- *
- * Parameters
- *    RegistryPath
- *        Name of the key to be created.
- *    Handle
- *        Handle to the newly created key
- *
- * Remarks
- *     This method can create nested trees, so parent of RegistryPath can
- *     be not existant, and will be created if needed.
- */
-NTSTATUS
-NTAPI
-IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
-                       IN ULONG CreateOptions,
-                       OUT PHANDLE Handle)
-{
-    UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
-    HANDLE hParent = NULL, hKey;
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING KeyName;
-    PCWSTR Current, Last;
-    USHORT Length;
-    NTSTATUS Status;
-
-    /* Assume failure */
-    *Handle = NULL;
-
-    /* Open root key for device instances */
-    Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
-        return Status;
-    }
-
-    Current = KeyName.Buffer = RegistryPath->Buffer;
-    Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
-
-    /* Go up to the end of the string */
-    while (Current <= Last)
-    {
-        if (Current != Last && *Current != L'\\')
-        {
-            /* Not the end of the string and not a separator */
-            Current++;
-            continue;
-        }
-
-        /* Prepare relative key name */
-        Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
-        KeyName.MaximumLength = KeyName.Length = Length;
-        DPRINT("Create '%wZ'\n", &KeyName);
-
-        /* Open key */
-        InitializeObjectAttributes(&ObjectAttributes,
-                                   &KeyName,
-                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                                   hParent,
-                                   NULL);
-        Status = ZwCreateKey(&hKey,
-                             Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
-                             &ObjectAttributes,
-                             0,
-                             NULL,
-                             CreateOptions,
-                             NULL);
-
-        /* Close parent key handle, we don't need it anymore */
-        if (hParent)
-            ZwClose(hParent);
-
-        /* Key opening/creating failed? */
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
-            return Status;
-        }
-
-        /* Check if it is the end of the string */
-        if (Current == Last)
-        {
-            /* Yes, return success */
-            *Handle = hKey;
-            return STATUS_SUCCESS;
-        }
-
-        /* Start with this new parent key */
-        hParent = hKey;
-        Current++;
-        KeyName.Buffer = (PWSTR)Current;
-    }
-
-    return STATUS_UNSUCCESSFUL;
-}
-
-NTSTATUS
-IopSetDeviceInstanceData(HANDLE InstanceKey,
-                         PDEVICE_NODE DeviceNode)
-{
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING KeyName;
-    HANDLE LogConfKey, ControlKey, DeviceParamsKey;
-    ULONG ResCount;
-    ULONG ResultLength;
-    NTSTATUS Status;
-
-    DPRINT("IopSetDeviceInstanceData() called\n");
-
-    /* Create the 'LogConf' key */
-    RtlInitUnicodeString(&KeyName, L"LogConf");
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &KeyName,
-                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               InstanceKey,
-                               NULL);
-    Status = ZwCreateKey(&LogConfKey,
-                         KEY_ALL_ACCESS,
-                         &ObjectAttributes,
-                         0,
-                         NULL,
-                         // FIXME? In r53694 it was silently turned from non-volatile into this,
-                         // without any extra warning. Is this still needed??
-                         REG_OPTION_VOLATILE,
-                         NULL);
-    if (NT_SUCCESS(Status))
-    {
-        /* Set 'BootConfig' value */
-        if (DeviceNode->BootResources != NULL)
-        {
-            ResCount = DeviceNode->BootResources->Count;
-            if (ResCount != 0)
-            {
-                RtlInitUnicodeString(&KeyName, L"BootConfig");
-                Status = ZwSetValueKey(LogConfKey,
-                                       &KeyName,
-                                       0,
-                                       REG_RESOURCE_LIST,
-                                       DeviceNode->BootResources,
-                                       PnpDetermineResourceListSize(DeviceNode->BootResources));
-            }
-        }
-
-        /* Set 'BasicConfigVector' value */
-        if (DeviceNode->ResourceRequirements != NULL &&
-            DeviceNode->ResourceRequirements->ListSize != 0)
-        {
-            RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
-            Status = ZwSetValueKey(LogConfKey,
-                                   &KeyName,
-                                   0,
-                                   REG_RESOURCE_REQUIREMENTS_LIST,
-                                   DeviceNode->ResourceRequirements,
-                                   DeviceNode->ResourceRequirements->ListSize);
-        }
-
-        ZwClose(LogConfKey);
-    }
-
-    /* Set the 'ConfigFlags' value */
-    RtlInitUnicodeString(&KeyName, L"ConfigFlags");
-    Status = ZwQueryValueKey(InstanceKey,
-                             &KeyName,
-                             KeyValueBasicInformation,
-                             NULL,
-                             0,
-                             &ResultLength);
-    if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
-    {
-        /* Write the default value */
-        ULONG DefaultConfigFlags = 0;
-        Status = ZwSetValueKey(InstanceKey,
-                               &KeyName,
-                               0,
-                               REG_DWORD,
-                               &DefaultConfigFlags,
-                               sizeof(DefaultConfigFlags));
-    }
-
-    /* Create the 'Control' key */
-    RtlInitUnicodeString(&KeyName, L"Control");
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &KeyName,
-                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                               InstanceKey,
-                               NULL);
-    Status = ZwCreateKey(&ControlKey,
-                         0,
-                         &ObjectAttributes,
-                         0,
-                         NULL,
-                         REG_OPTION_VOLATILE,
-                         NULL);
-    if (NT_SUCCESS(Status))
-        ZwClose(ControlKey);
-
-    /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
-    if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
-    {
-        RtlInitUnicodeString(&KeyName, L"Device Parameters");
-        InitializeObjectAttributes(&ObjectAttributes,
-                                   &KeyName,
-                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
-                                   InstanceKey,
-                                   NULL);
-        Status = ZwCreateKey(&DeviceParamsKey,
-                             0,
-                             &ObjectAttributes,
-                             0,
-                             NULL,
-                             REG_OPTION_NON_VOLATILE,
-                             NULL);
-        if (NT_SUCCESS(Status))
-        {
-            ULONG FirmwareIdentified = 1;
-            RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
-            Status = ZwSetValueKey(DeviceParamsKey,
-                                   &KeyName,
-                                   0,
-                                   REG_DWORD,
-                                   &FirmwareIdentified,
-                                   sizeof(FirmwareIdentified));
-
-            ZwClose(DeviceParamsKey);
-        }
-    }
-
-    DPRINT("IopSetDeviceInstanceData() done\n");
-
-    return Status;
-}
-
-/*
- * IopGetParentIdPrefix
- *
- * Retrieve (or create) a string which identifies a device.
- *
- * Parameters
- *    DeviceNode
- *        Pointer to device node.
- *    ParentIdPrefix
- *        Pointer to the string where is returned the parent node identifier
- *
- * Remarks
- *     If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
- *     valid and its Buffer field is NULL-terminated. The caller needs to
- *     to free the string with RtlFreeUnicodeString when it is no longer
- *     needed.
- */
-
-NTSTATUS
-IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
-                     PUNICODE_STRING ParentIdPrefix)
-{
-    const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
-    ULONG KeyNameBufferLength;
-    PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
-    UNICODE_STRING KeyName = {0, 0, NULL};
-    UNICODE_STRING KeyValue;
-    UNICODE_STRING ValueName;
-    HANDLE hKey = NULL;
-    ULONG crc32;
-    NTSTATUS Status;
-
-    /* HACK: As long as some devices have a NULL device
-     * instance path, the following test is required :(
-     */
-    if (DeviceNode->Parent->InstancePath.Length == 0)
-    {
-        DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
-                &DeviceNode->InstancePath);
-        return STATUS_UNSUCCESSFUL;
-    }
-
-    /* 1. Try to retrieve ParentIdPrefix from registry */
-    KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
-    ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
-                                                      KeyNameBufferLength + sizeof(UNICODE_NULL),
-                                                      TAG_IO);
-    if (!ParentIdPrefixInformation)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    KeyName.Length = 0;
-    KeyName.MaximumLength = EnumKeyPath.Length +
-                            DeviceNode->Parent->InstancePath.Length +
-                            sizeof(UNICODE_NULL);
-    KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
-                                           KeyName.MaximumLength,
-                                           TAG_IO);
-    if (!KeyName.Buffer)
-    {
-        Status = STATUS_INSUFFICIENT_RESOURCES;
-        goto cleanup;
-    }
-
-    RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
-    RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
-
-    Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
-    if (!NT_SUCCESS(Status))
-    {
-        goto cleanup;
-    }
-    RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
-    Status = ZwQueryValueKey(hKey,
-                             &ValueName,
-                             KeyValuePartialInformation,
-                             ParentIdPrefixInformation,
-                             KeyNameBufferLength,
-                             &KeyNameBufferLength);
-    if (NT_SUCCESS(Status))
-    {
-        if (ParentIdPrefixInformation->Type != REG_SZ)
-        {
-            Status = STATUS_UNSUCCESSFUL;
-        }
-        else
-        {
-            KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
-            KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
-            KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
-            ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
-        }
-        goto cleanup;
-    }
-    if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
-    {
-        /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
-        KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
-        KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
-        KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
-        ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
-        goto cleanup;
-    }
-
-    /* 2. Create the ParentIdPrefix value */
-    crc32 = RtlComputeCrc32(0,
-                            (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
-                            DeviceNode->Parent->InstancePath.Length);
-
-    RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
-                       KeyNameBufferLength,
-                       L"%lx&%lx",
-                       DeviceNode->Parent->Level,
-                       crc32);
-    RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
-
-    /* 3. Try to write the ParentIdPrefix to registry */
-    Status = ZwSetValueKey(hKey,
-                           &ValueName,
-                           0,
-                           REG_SZ,
-                           KeyValue.Buffer,
-                           ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
-
-cleanup:
-    if (NT_SUCCESS(Status))
-    {
-        /* Duplicate the string to return it */
-        Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
-                                           &KeyValue,
-                                           ParentIdPrefix);
-    }
-    ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
-    RtlFreeUnicodeString(&KeyName);
-    if (hKey != NULL)
-    {
-        ZwClose(hKey);
-    }
-    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);
+        ZwClose(ControlKey);
 
-        if (!NT_SUCCESS(Status))
+    /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
+    if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
+    {
+        RtlInitUnicodeString(&KeyName, L"Device Parameters");
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &KeyName,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   InstanceKey,
+                                   NULL);
+        Status = ZwCreateKey(&DeviceParamsKey,
+                             0,
+                             &ObjectAttributes,
+                             0,
+                             NULL,
+                             REG_OPTION_NON_VOLATILE,
+                             NULL);
+        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;
-        }
+            ULONG FirmwareIdentified = 1;
+            RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
+            Status = ZwSetValueKey(DeviceParamsKey,
+                                   &KeyName,
+                                   0,
+                                   REG_DWORD,
+                                   &FirmwareIdentified,
+                                   sizeof(FirmwareIdentified));
 
-        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;
+            ZwClose(DeviceParamsKey);
         }
-
-        DPRINT("Got Service %S\n", Service->Buffer);
     }
 
-    return STATUS_SUCCESS;
+    DPRINT("IopSetDeviceInstanceData() done\n");
+
+    return Status;
 }
 
 /*
- * IopActionInitChildServices
+ * IopGetParentIdPrefix
  *
- * Initialize the service for all (direct) child nodes of a parent node
+ * Retrieve (or create) a string which identifies a device.
  *
  * Parameters
  *    DeviceNode
- *       Pointer to device node.
- *    Context
- *       Pointer to parent node to initialize child node services for.
+ *        Pointer to device node.
+ *    ParentIdPrefix
+ *        Pointer to the string where is returned the parent node identifier
  *
  * 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.
+ *     If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
+ *     valid and its Buffer field is NULL-terminated. The caller needs to
+ *     to free the string with RtlFreeUnicodeString when it is no longer
+ *     needed.
  */
 
 NTSTATUS
-IopActionInitChildServices(PDEVICE_NODE DeviceNode,
-                           PVOID Context)
+IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
+                     PUNICODE_STRING ParentIdPrefix)
 {
-    PDEVICE_NODE ParentDeviceNode;
+    const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
+    ULONG KeyNameBufferLength;
+    PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
+    UNICODE_STRING KeyName = {0, 0, NULL};
+    UNICODE_STRING KeyValue;
+    UNICODE_STRING ValueName;
+    HANDLE hKey = NULL;
+    ULONG crc32;
     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
+    /* HACK: As long as some devices have a NULL device
+     * instance path, the following test is required :(
      */
-    if (DeviceNode == ParentDeviceNode)
+    if (DeviceNode->Parent->InstancePath.Length == 0)
     {
-        DPRINT("Success\n");
-        return STATUS_SUCCESS;
+        DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
+                &DeviceNode->InstancePath);
+        return STATUS_UNSUCCESSFUL;
     }
 
-    /*
-     * 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).
-     */
+    /* 1. Try to retrieve ParentIdPrefix from registry */
+    KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
+    ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
+                                                      KeyNameBufferLength + sizeof(UNICODE_NULL),
+                                                      TAG_IO);
+    if (!ParentIdPrefixInformation)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
 
-    if (!(DeviceNode->Flags & DNF_PROCESSED))
+    KeyName.Length = 0;
+    KeyName.MaximumLength = EnumKeyPath.Length +
+                            DeviceNode->Parent->InstancePath.Length +
+                            sizeof(UNICODE_NULL);
+    KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
+                                           KeyName.MaximumLength,
+                                           TAG_IO);
+    if (!KeyName.Buffer)
     {
-        DPRINT1("Child not ready to be added\n");
-        return STATUS_SUCCESS;
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto cleanup;
     }
 
-    if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
-        IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
-        IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
-        return STATUS_SUCCESS;
+    RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
+    RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
 
-    if (DeviceNode->ServiceName.Buffer == NULL)
+    Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
+    if (!NT_SUCCESS(Status))
     {
-        /* 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);
-            }
-        }
+        goto cleanup;
     }
-    else
+    RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
+    Status = ZwQueryValueKey(hKey,
+                             &ValueName,
+                             KeyValuePartialInformation,
+                             ParentIdPrefixInformation,
+                             KeyNameBufferLength,
+                             &KeyNameBufferLength);
+    if (NT_SUCCESS(Status))
     {
-        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))
+        if (ParentIdPrefixInformation->Type != REG_SZ)
         {
-            /* Initialize the device, including all filters */
-            Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
-
-            /* Remove the extra reference */
-            ObDereferenceObject(DriverObject);
+            Status = STATUS_UNSUCCESSFUL;
         }
         else
         {
-            /*
-             * Don't disable when trying to load only boot drivers
-             */
-            if (!BootDrivers)
-            {
-                IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
-            }
+            KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
+            KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
+            KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
+            ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
         }
+        goto cleanup;
+    }
+    if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+        /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
+        KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
+        KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
+        KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
+        ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
+        goto cleanup;
     }
 
-    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;
+    /* 2. Create the ParentIdPrefix value */
+    crc32 = RtlComputeCrc32(0,
+                            (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
+                            DeviceNode->Parent->InstancePath.Length);
 
-    DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
+    RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
+                       KeyNameBufferLength,
+                       L"%lx&%lx",
+                       DeviceNode->Parent->Level,
+                       crc32);
+    RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
 
-    IopInitDeviceTreeTraverseContext(
-        &Context,
-        DeviceNode,
-        IopActionInitChildServices,
-        DeviceNode);
+    /* 3. Try to write the ParentIdPrefix to registry */
+    Status = ZwSetValueKey(hKey,
+                           &ValueName,
+                           0,
+                           REG_SZ,
+                           KeyValue.Buffer,
+                           ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
 
-    return IopTraverseDeviceTree(&Context);
+cleanup:
+    if (NT_SUCCESS(Status))
+    {
+        /* Duplicate the string to return it */
+        Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+                                           &KeyValue,
+                                           ParentIdPrefix);
+    }
+    ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
+    RtlFreeUnicodeString(&KeyName);
+    if (hKey != NULL)
+    {
+        ZwClose(hKey);
+    }
+    return Status;
 }
 
 static
@@ -4108,152 +2273,33 @@ IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
     }
     else if (NT_SUCCESS(Status))
     {
-        /* We know up-front how much data to expect, check the caller's buffer */
-        *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
-        if (*ResultLength <= BufferLength)
-        {
-            /* Buffer is all good, copy the data */
-            RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
-
-            /* Check if we need to NULL-terminate the string */
-            if (NullTerminate)
-            {
-                /* Terminate the string */
-                ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
-            }
-
-            /* This is the success path */
-            Status = STATUS_SUCCESS;
-        }
-        else
-        {
-            /* Failure path */
-            Status = STATUS_BUFFER_TOO_SMALL;
-        }
-    }
-
-    /* Free any allocation we may have made, and return the status code */
-    if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
-    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
+        /* We know up-front how much data to expect, check the caller's buffer */
+        *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
+        if (*ResultLength <= BufferLength)
         {
-            DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
-            DeviceNode->BootResources = NULL;
-        }
+            /* Buffer is all good, copy the data */
+            RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
 
-        DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
+            /* Check if we need to NULL-terminate the string */
+            if (NullTerminate)
+            {
+                /* Terminate the string */
+                ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
+            }
 
-        Status = IopInitiatePnpIrp(PhysicalDeviceObject,
-                                   &IoStatusBlock,
-                                   IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
-                                   NULL);
-        if (NT_SUCCESS(Status))
-        {
-            DeviceNode->ResourceRequirements =
-            (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
+            /* This is the success path */
+            Status = STATUS_SUCCESS;
         }
         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);
+            /* Failure path */
+            Status = STATUS_BUFFER_TOO_SMALL;
         }
     }
+
+    /* Free any allocation we may have made, and return the status code */
+    if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
+    return Status;
 }
 
 /**
@@ -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
  */
index a938a42..e6c059f 100644 (file)
@@ -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