The code expects synchronous behaviour here, so until a better solution exists, IoSyn...
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnpmgr.c
index 29e4d25..77a470d 100644 (file)
@@ -25,17 +25,30 @@ KSPIN_LOCK IopDeviceTreeLock;
 PDRIVER_OBJECT IopRootDriverObject;
 PIO_BUS_TYPE_GUID_LIST IopBusTypeGuidList = NULL;
 
-static NTSTATUS INIT_FUNCTION
-IopSetRootDeviceInstanceData(PDEVICE_NODE DeviceNode);
-
 #if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, IopSetRootDeviceInstanceData)
 #pragma alloc_text(INIT, PnpInit)
 #pragma alloc_text(INIT, PnpInit2)
-#pragma alloc_text(INIT, IopUpdateRootKey)
-#pragma alloc_text(INIT, IopEnumerateDetectedDevices)
 #endif
 
+typedef struct _INVALIDATE_DEVICE_RELATION_DATA
+{
+    DEVICE_RELATION_TYPE Type;
+    PIO_WORKITEM WorkItem;
+    PKEVENT Event;
+    NTSTATUS Status;
+} INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
+
+static VOID NTAPI
+IopInvalidateDeviceRelations(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PVOID InvalidateContext);
+
+VOID
+NTAPI
+IoSynchronousInvalidateDeviceRelations(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN DEVICE_RELATION_TYPE Type);
+
 
 /* FUNCTIONS *****************************************************************/
 
@@ -138,8 +151,10 @@ IopStartDevice(
          if (IopDeviceNodeHasFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY))
       {
          DPRINT("Device needs enumeration, invalidating bus relations\n");
-         Status = IopInvalidateDeviceRelations(DeviceNode, BusRelations);
-                IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
+         /* Invalidate device relations synchronously
+            (otherwise there will be dirty read of DeviceNode) */
+         IoSynchronousInvalidateDeviceRelations(DeviceNode->PhysicalDeviceObject, BusRelations);
+         IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
       }
    }
 
@@ -177,35 +192,51 @@ IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
                             &Stack);
 }
 
-typedef struct _INVALIDATE_DEVICE_RELATION_DATA
-{
-    DEVICE_RELATION_TYPE Type;
-    PIO_WORKITEM WorkItem;
-} INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
-
-static VOID
+/*
+ * @implemented
+ */
+VOID
 NTAPI
-IoInvalidateDeviceRelationsWorker(
+IoInvalidateDeviceRelations(
     IN PDEVICE_OBJECT DeviceObject,
-    IN PVOID Context)
+    IN DEVICE_RELATION_TYPE Type)
 {
-    PINVALIDATE_DEVICE_RELATION_DATA Data = Context;
+    PIO_WORKITEM WorkItem;
+    PINVALIDATE_DEVICE_RELATION_DATA Data;
 
-    IopInvalidateDeviceRelations(IopGetDeviceNode(DeviceObject), Data->Type);
-    IoFreeWorkItem(Data->WorkItem);
-    ExFreePool(Data);
+    Data = ExAllocatePool(PagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
+    if (!Data)
+        return;
+    WorkItem = IoAllocateWorkItem(DeviceObject);
+    if (!WorkItem)
+    {
+        ExFreePool(Data);
+        return;
+    }
+
+    Data->Type = Type;
+    Data->WorkItem = WorkItem;
+    Data->Event = NULL;
+
+    IoQueueWorkItem(
+        WorkItem,
+        IopInvalidateDeviceRelations,
+        DelayedWorkQueue,
+        Data);
 }
 
 /*
  * @implemented
  */
 VOID
-STDCALL
-IoInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject,
-                            IN DEVICE_RELATION_TYPE Type)
+NTAPI
+IoSynchronousInvalidateDeviceRelations(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN DEVICE_RELATION_TYPE Type)
 {
     PIO_WORKITEM WorkItem;
     PINVALIDATE_DEVICE_RELATION_DATA Data;
+    KEVENT Event;
 
     Data = ExAllocatePool(PagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
     if (!Data)
@@ -217,25 +248,19 @@ IoInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject,
         return;
     }
 
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
     Data->Type = Type;
     Data->WorkItem = WorkItem;
+    Data->Event = &Event;
 
     IoQueueWorkItem(
         WorkItem,
-        IoInvalidateDeviceRelationsWorker,
+        IopInvalidateDeviceRelations,
         DelayedWorkQueue,
         Data);
-}
 
-/*
- * @unimplemented
- */
-VOID
-STDCALL
-IoSynchronousInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject,
-                                       IN DEVICE_RELATION_TYPE Type)
-{
-    UNIMPLEMENTED;
+    KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+    ExFreePool(Data);
 }
 
 /*
@@ -577,7 +602,7 @@ IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
       return STATUS_INSUFFICIENT_RESOURCES;
 
    KeyName.Length = 0;
-   KeyName.MaximumLength = KeyNameLength;
+   KeyName.MaximumLength = (USHORT)KeyNameLength;
    KeyName.Buffer = KeyNameBuffer;
 
    /*
@@ -603,7 +628,7 @@ IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
          ExFreePool(KeyNameBuffer);
          return Status;
       }
-      KeyName.Length += DriverKeyLength - sizeof(UNICODE_NULL);
+      KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
    }
    else
    {
@@ -734,7 +759,7 @@ IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
                  sizeof(GUID));
 
    /* The new entry is the index */
-   FoundIndex = IopBusTypeGuidList->GuidCount;
+   FoundIndex = (USHORT)IopBusTypeGuidList->GuidCount;
    IopBusTypeGuidList->GuidCount++;
 
 Quickie:
@@ -912,11 +937,11 @@ IopInitiatePnpIrp(PDEVICE_OBJECT DeviceObject,
    Irp->IoStatus.Information = 0;
 
    IrpSp = IoGetNextIrpStackLocation(Irp);
-   IrpSp->MinorFunction = MinorFunction;
+   IrpSp->MinorFunction = (UCHAR)MinorFunction;
 
    if (Stack)
    {
-      RtlMoveMemory(&IrpSp->Parameters,
+      RtlCopyMemory(&IrpSp->Parameters,
                     &Stack->Parameters,
                     sizeof(Stack->Parameters));
    }
@@ -1204,30 +1229,70 @@ IopSetDeviceInstanceData(HANDLE InstanceKey,
 }
 
 
-NTSTATUS
-IopAssignDeviceResources(PDEVICE_NODE DeviceNode)
+static NTSTATUS
+IopAssignDeviceResources(
+   IN PDEVICE_NODE DeviceNode,
+   OUT ULONG *pRequiredSize)
 {
    PIO_RESOURCE_LIST ResourceList;
    PIO_RESOURCE_DESCRIPTOR ResourceDescriptor;
-   PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
+   PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw;
+   PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
    ULONG NumberOfResources = 0;
-   ULONG i;
+   ULONG Size;
+   ULONG i, j;
    NTSTATUS Status;
 
-   /* Fill DeviceNode->ResourceList and DeviceNode->ResourceListTranslated;
-    * by using DeviceNode->ResourceRequirements */
+   if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
+   {
+      /* No resource needed for this device */
+      DeviceNode->ResourceList = NULL;
+      return STATUS_SUCCESS;
+   }
+
+   /* Fill DeviceNode->ResourceList
+    * FIXME: the PnP arbiter should go there!
+    * Actually, use the BootResources if provided, else the resource list #0
+    */
+
+   IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
 
-   if (!DeviceNode->ResourceRequirements
-      || DeviceNode->ResourceRequirements->AlternativeLists == 0)
+   if (DeviceNode->BootResources)
    {
-      DeviceNode->ResourceList = DeviceNode->ResourceListTranslated = NULL;
+      /* Browse the boot resources to know if we have some custom structures */
+      Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
+      for (i = 0; i < DeviceNode->BootResources->Count; i++)
+      {
+         pPartialResourceList = &DeviceNode->BootResources->List[i].PartialResourceList;
+         if (pPartialResourceList->Version != 1 || pPartialResourceList->Revision != 1)
+         {
+            Status = STATUS_REVISION_MISMATCH;
+            goto ByeBye;
+         }
+         Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
+            + pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+         for (j = 0; j < pPartialResourceList->Count; j++)
+         {
+            if (pPartialResourceList->PartialDescriptors[j].Type == CmResourceTypeDeviceSpecific)
+               Size += pPartialResourceList->PartialDescriptors[j].u.DeviceSpecificData.DataSize;
+         }
+      }
+
+      DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
+      if (!DeviceNode->ResourceList)
+      {
+         Status = STATUS_NO_MEMORY;
+         goto ByeBye;
+      }
+      RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, Size);
+
+      *pRequiredSize = Size;
       return STATUS_SUCCESS;
    }
 
+   /* Ok, here, we have to use the device requirement list */
    IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
 
-   /* FIXME: that's here that PnP arbiter should go */
-   /* Actually, simply use resource list #0 as assigned resource list */
    ResourceList = &DeviceNode->ResourceRequirements->List[0];
    if (ResourceList->Version != 1 || ResourceList->Revision != 1)
    {
@@ -1235,19 +1300,12 @@ IopAssignDeviceResources(PDEVICE_NODE DeviceNode)
       goto ByeBye;
    }
 
-   DeviceNode->ResourceList = ExAllocatePool(PagedPool,
-      sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+   Size = sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+   *pRequiredSize = Size;
+   DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
    if (!DeviceNode->ResourceList)
    {
-      Status = STATUS_INSUFFICIENT_RESOURCES;
-      goto ByeBye;
-   }
-
-   DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool,
-      sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
-   if (!DeviceNode->ResourceListTranslated)
-   {
-      Status = STATUS_INSUFFICIENT_RESOURCES;
+      Status = STATUS_NO_MEMORY;
       goto ByeBye;
    }
 
@@ -1257,12 +1315,6 @@ IopAssignDeviceResources(PDEVICE_NODE DeviceNode)
    DeviceNode->ResourceList->List[0].PartialResourceList.Version = 1;
    DeviceNode->ResourceList->List[0].PartialResourceList.Revision = 1;
 
-   DeviceNode->ResourceListTranslated->Count = 1;
-   DeviceNode->ResourceListTranslated->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType;
-   DeviceNode->ResourceListTranslated->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber;
-   DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Version = 1;
-   DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Revision = 1;
-
    for (i = 0; i < ResourceList->Count; i++)
    {
       ResourceDescriptor = &ResourceList->Descriptors[i];
@@ -1270,31 +1322,18 @@ IopAssignDeviceResources(PDEVICE_NODE DeviceNode)
       if (ResourceDescriptor->Option == 0 || ResourceDescriptor->Option == IO_RESOURCE_PREFERRED)
       {
          DescriptorRaw = &DeviceNode->ResourceList->List[0].PartialResourceList.PartialDescriptors[NumberOfResources];
-         DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[NumberOfResources];
          NumberOfResources++;
 
          /* Copy ResourceDescriptor to DescriptorRaw and DescriptorTranslated */
-         DescriptorRaw->Type = DescriptorTranslated->Type = ResourceDescriptor->Type;
-         DescriptorRaw->ShareDisposition = DescriptorTranslated->ShareDisposition = ResourceDescriptor->ShareDisposition;
-         DescriptorRaw->Flags = DescriptorTranslated->Flags = ResourceDescriptor->Flags;
+         DescriptorRaw->Type = ResourceDescriptor->Type;
+         DescriptorRaw->ShareDisposition = ResourceDescriptor->ShareDisposition;
+         DescriptorRaw->Flags = ResourceDescriptor->Flags;
          switch (ResourceDescriptor->Type)
          {
             case CmResourceTypePort:
             {
-               ULONG AddressSpace = 0; /* IO space */
                DescriptorRaw->u.Port.Start = ResourceDescriptor->u.Port.MinimumAddress;
-               DescriptorRaw->u.Port.Length = DescriptorTranslated->u.Port.Length
-                  = ResourceDescriptor->u.Port.Length;
-               if (!HalTranslateBusAddress(
-                  DeviceNode->ResourceRequirements->InterfaceType,
-                  DeviceNode->ResourceRequirements->BusNumber,
-                  DescriptorRaw->u.Port.Start,
-                  &AddressSpace,
-                  &DescriptorTranslated->u.Port.Start))
-               {
-                  Status = STATUS_UNSUCCESSFUL;
-                  goto ByeBye;
-               }
+               DescriptorRaw->u.Port.Length = ResourceDescriptor->u.Port.Length;
                break;
             }
             case CmResourceTypeInterrupt:
@@ -1354,54 +1393,26 @@ IopAssignDeviceResources(PDEVICE_NODE DeviceNode)
                      }
                   }
                }
-
-               DescriptorTranslated->u.Interrupt.Level = 0;
-               DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
-                  DeviceNode->ResourceRequirements->InterfaceType,
-                  DeviceNode->ResourceRequirements->BusNumber,
-                  DescriptorRaw->u.Interrupt.Level,
-                  DescriptorRaw->u.Interrupt.Vector,
-                  (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
-                  &DescriptorRaw->u.Interrupt.Affinity);
-               DescriptorTranslated->u.Interrupt.Affinity = DescriptorRaw->u.Interrupt.Affinity;
                break;
             }
             case CmResourceTypeMemory:
             {
-               ULONG AddressSpace = 1; /* Memory space */
                DescriptorRaw->u.Memory.Start = ResourceDescriptor->u.Memory.MinimumAddress;
-               DescriptorRaw->u.Memory.Length = DescriptorTranslated->u.Memory.Length
-                  = ResourceDescriptor->u.Memory.Length;
-               if (!HalTranslateBusAddress(
-                  DeviceNode->ResourceRequirements->InterfaceType,
-                  DeviceNode->ResourceRequirements->BusNumber,
-                  DescriptorRaw->u.Memory.Start,
-                  &AddressSpace,
-                  &DescriptorTranslated->u.Memory.Start))
-               {
-                  Status = STATUS_UNSUCCESSFUL;
-                  goto ByeBye;
-               }
+               DescriptorRaw->u.Memory.Length = ResourceDescriptor->u.Memory.Length;
                break;
             }
             case CmResourceTypeDma:
             {
-               DescriptorRaw->u.Dma.Channel = DescriptorTranslated->u.Dma.Channel
-                  = ResourceDescriptor->u.Dma.MinimumChannel;
-               DescriptorRaw->u.Dma.Port = DescriptorTranslated->u.Dma.Port
-                  = 0; /* FIXME */
-               DescriptorRaw->u.Dma.Reserved1 = DescriptorTranslated->u.Dma.Reserved1
-                  = 0;
+               DescriptorRaw->u.Dma.Channel = ResourceDescriptor->u.Dma.MinimumChannel;
+               DescriptorRaw->u.Dma.Port = 0; /* FIXME */
+               DescriptorRaw->u.Dma.Reserved1 = 0;
                break;
             }
             case CmResourceTypeBusNumber:
             {
-               DescriptorRaw->u.BusNumber.Start = DescriptorTranslated->u.BusNumber.Start
-                  = ResourceDescriptor->u.BusNumber.MinBusNumber;
-               DescriptorRaw->u.BusNumber.Length = DescriptorTranslated->u.BusNumber.Length
-                  = ResourceDescriptor->u.BusNumber.Length;
-               DescriptorRaw->u.BusNumber.Reserved = DescriptorTranslated->u.BusNumber.Reserved
-                  = ResourceDescriptor->u.BusNumber.Reserved;
+               DescriptorRaw->u.BusNumber.Start = ResourceDescriptor->u.BusNumber.MinBusNumber;
+               DescriptorRaw->u.BusNumber.Length = ResourceDescriptor->u.BusNumber.Length;
+               DescriptorRaw->u.BusNumber.Reserved = ResourceDescriptor->u.BusNumber.Reserved;
                break;
             }
             /*CmResourceTypeDevicePrivate:
@@ -1427,10 +1438,7 @@ IopAssignDeviceResources(PDEVICE_NODE DeviceNode)
    }
 
    DeviceNode->ResourceList->List[0].PartialResourceList.Count = NumberOfResources;
-   DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Count = NumberOfResources;
 
-   IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
-   IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
    return STATUS_SUCCESS;
 
 ByeBye:
@@ -1439,13 +1447,111 @@ ByeBye:
       ExFreePool(DeviceNode->ResourceList);
       DeviceNode->ResourceList = NULL;
    }
-   if (DeviceNode->ResourceListTranslated)
+   return Status;
+}
+
+
+static NTSTATUS
+IopTranslateDeviceResources(
+   IN PDEVICE_NODE DeviceNode,
+   IN ULONG RequiredSize)
+{
+   PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
+   PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
+   ULONG i, j;
+   NTSTATUS Status;
+
+   if (!DeviceNode->ResourceList)
    {
-      ExFreePool(DeviceNode->ResourceListTranslated);
       DeviceNode->ResourceListTranslated = NULL;
+      return STATUS_SUCCESS;
    }
 
-   IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
+   /* That's easy to translate a resource list. Just copy the
+    * untranslated one and change few fields in the copy
+    */
+   DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, RequiredSize);
+   if (!DeviceNode->ResourceListTranslated)
+   {
+      Status =STATUS_NO_MEMORY;
+      goto cleanup;
+   }
+   RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, RequiredSize);
+
+   for (i = 0; i < DeviceNode->ResourceList->Count; i++)
+   {
+      pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
+      for (j = 0; j < pPartialResourceList->Count; j++)
+      {
+         DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
+         DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
+         switch (DescriptorRaw->Type)
+         {
+            case CmResourceTypePort:
+            {
+               ULONG AddressSpace = 0; /* IO space */
+               if (!HalTranslateBusAddress(
+                  DeviceNode->ResourceList->List[i].InterfaceType,
+                  DeviceNode->ResourceList->List[i].BusNumber,
+                  DescriptorRaw->u.Port.Start,
+                  &AddressSpace,
+                  &DescriptorTranslated->u.Port.Start))
+               {
+                  Status = STATUS_UNSUCCESSFUL;
+                  goto cleanup;
+               }
+               break;
+            }
+            case CmResourceTypeInterrupt:
+            {
+               DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
+                  DeviceNode->ResourceList->List[i].InterfaceType,
+                  DeviceNode->ResourceList->List[i].BusNumber,
+                  DescriptorRaw->u.Interrupt.Level,
+                  DescriptorRaw->u.Interrupt.Vector,
+                  (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
+                  &DescriptorRaw->u.Interrupt.Affinity);
+               break;
+            }
+            case CmResourceTypeMemory:
+            {
+               ULONG AddressSpace = 1; /* Memory space */
+               if (!HalTranslateBusAddress(
+                  DeviceNode->ResourceList->List[i].InterfaceType,
+                  DeviceNode->ResourceList->List[i].BusNumber,
+                  DescriptorRaw->u.Memory.Start,
+                  &AddressSpace,
+                  &DescriptorTranslated->u.Memory.Start))
+               {
+                  Status = STATUS_UNSUCCESSFUL;
+                  goto cleanup;
+               }
+            }
+
+            case CmResourceTypeDma:
+            case CmResourceTypeBusNumber:
+            case CmResourceTypeDeviceSpecific:
+               /* Nothing to do */
+               break;
+            default:
+               DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
+               Status = STATUS_NOT_IMPLEMENTED;
+               goto cleanup;
+         }
+      }
+   }
+   return STATUS_SUCCESS;
+
+cleanup:
+   /* Yes! Also delete ResourceList because ResourceList and
+    * ResourceListTranslated should be a pair! */
+   ExFreePool(DeviceNode->ResourceList);
+   DeviceNode->ResourceList = NULL;
+   if (DeviceNode->ResourceListTranslated)
+   {
+      ExFreePool(DeviceNode->ResourceListTranslated);
+      DeviceNode->ResourceList = NULL;
+   }
    return Status;
 }
 
@@ -1521,14 +1627,14 @@ IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
          Status = STATUS_UNSUCCESSFUL;
       else
       {
-         KeyValue.Length = KeyValue.MaximumLength = ParentIdPrefixInformation->DataLength;
+         KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
          KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
       }
       goto cleanup;
    }
    if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
    {
-      KeyValue.Length = KeyValue.MaximumLength = ParentIdPrefixInformation->DataLength;
+      KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
       KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
       goto cleanup;
    }
@@ -2005,11 +2111,25 @@ IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
 
    ZwClose(InstanceKey);
 
-   Status = IopAssignDeviceResources(DeviceNode);
-   if (!NT_SUCCESS(Status))
+   IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
+   Status = IopAssignDeviceResources(DeviceNode, &RequiredLength);
+   if (NT_SUCCESS(Status))
+   {
+      Status = IopTranslateDeviceResources(DeviceNode, RequiredLength);
+      if (NT_SUCCESS(Status))
+      {
+         IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
+      }
+      else
+      {
+         DPRINT("IopTranslateDeviceResources() failed (Status 0x08lx)\n", Status);
+      }
+   }
+   else
    {
-      DPRINT("IopAssignDeviceResources() failed (Status %x)\n", Status);
+      DPRINT("IopAssignDeviceResources() failed (Status 0x08lx)\n", Status);
    }
+   IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
 
    DeviceNode->Flags |= DNF_PROCESSED;
 
@@ -2210,6 +2330,10 @@ IopActionInitChildServices(PDEVICE_NODE DeviceNode,
       PLDR_DATA_TABLE_ENTRY ModuleObject;
       PDRIVER_OBJECT DriverObject;
 
+      /* FIXME: Remove this once the bug is fixed */
+      if (DeviceNode->ServiceName.Buffer == NULL)
+          DPRINT1("Weird DeviceNode %p having ServiceName->Buffer==NULL. Probable stack corruption or memory overwrite.\n", DeviceNode);
+
       Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
       if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
       {
@@ -2338,256 +2462,165 @@ IopInitializePnpServices(IN PDEVICE_NODE DeviceNode,
    return IopTraverseDeviceTree(&Context);
 }
 
-
-NTSTATUS
-IopInvalidateDeviceRelations(IN PDEVICE_NODE DeviceNode,
-                             IN DEVICE_RELATION_TYPE Type)
+/* Invalidate device list enumerated by a device node.
+ * The call can be make synchronous by defining the Event field
+ * of the INVALIDATE_DEVICE_RELATION_DATA structure
+ */
+static VOID NTAPI
+IopInvalidateDeviceRelations(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PVOID InvalidateContext) /* PINVALIDATE_DEVICE_RELATION_DATA */
 {
-   DEVICETREE_TRAVERSE_CONTEXT Context;
-   PDEVICE_RELATIONS DeviceRelations;
-   IO_STATUS_BLOCK IoStatusBlock;
-   PDEVICE_NODE ChildDeviceNode;
-   IO_STACK_LOCATION Stack;
-   BOOLEAN BootDrivers;
-   OBJECT_ATTRIBUTES ObjectAttributes;
-   UNICODE_STRING LinkName;
-   HANDLE Handle;
-   NTSTATUS Status;
-   ULONG i;
-
-   DPRINT("DeviceNode 0x%p, Type %d\n", DeviceNode, Type);
-
-   DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
+    PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
+    PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
+    PKEVENT Event = Data->Event;
+    DEVICETREE_TRAVERSE_CONTEXT Context;
+    PDEVICE_RELATIONS DeviceRelations;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PDEVICE_NODE ChildDeviceNode;
+    IO_STACK_LOCATION Stack;
+    BOOLEAN BootDrivers;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"\\SystemRoot");
+    HANDLE Handle;
+    NTSTATUS Status;
+    ULONG i;
 
-   Stack.Parameters.QueryDeviceRelations.Type = Type/*BusRelations*/;
+    DPRINT("DeviceObject 0x%p\n", DeviceObject);
 
-   Status = IopInitiatePnpIrp(
-      DeviceNode->PhysicalDeviceObject,
-      &IoStatusBlock,
-      IRP_MN_QUERY_DEVICE_RELATIONS,
-      &Stack);
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("IopInitiatePnpIrp() failed\n");
-      return Status;
-   }
+    DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
 
-   DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
+    Stack.Parameters.QueryDeviceRelations.Type = Data->Type;
 
-   if ((!DeviceRelations) || (DeviceRelations->Count <= 0))
-   {
-      DPRINT("No PDOs\n");
-      if (DeviceRelations)
-      {
-         ExFreePool(DeviceRelations);
-      }
-      return STATUS_SUCCESS;
-   }
+    Status = IopInitiatePnpIrp(
+        DeviceObject,
+        &IoStatusBlock,
+        IRP_MN_QUERY_DEVICE_RELATIONS,
+        &Stack);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
+        goto cleanup;
+    }
 
-   DPRINT("Got %d PDOs\n", DeviceRelations->Count);
+    DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
 
-   /*
-    * Create device nodes for all discovered devices
-    */
+    if (!DeviceRelations || DeviceRelations->Count <= 0)
+    {
+        DPRINT("No PDOs\n");
+        if (DeviceRelations)
+        {
+            ExFreePool(DeviceRelations);
+        }
+        Status = STATUS_SUCCESS;
+        goto cleanup;
+    }
 
-   for (i = 0; i < DeviceRelations->Count; i++)
-   {
-      Status = IopCreateDeviceNode(
-         DeviceNode,
-         DeviceRelations->Objects[i],
-         &ChildDeviceNode);
-      DeviceNode->Flags |= DNF_ENUMERATED;
-      if (!NT_SUCCESS(Status))
-      {
-         DPRINT("No resources\n");
-         for (i = 0; i < DeviceRelations->Count; i++)
-            ObDereferenceObject(DeviceRelations->Objects[i]);
-         ExFreePool(DeviceRelations);
-         return STATUS_INSUFFICIENT_RESOURCES;
-      }
-   }
-   ExFreePool(DeviceRelations);
+    DPRINT("Got %d PDOs\n", DeviceRelations->Count);
 
-   /*
-    * Retrieve information about all discovered children from the bus driver
-    */
+    /*
+     * Create device nodes for all discovered devices
+     */
+    for (i = 0; i < DeviceRelations->Count; i++)
+    {
+        Status = IopCreateDeviceNode(
+            DeviceNode,
+            DeviceRelations->Objects[i],
+            &ChildDeviceNode);
+        DeviceNode->Flags |= DNF_ENUMERATED;
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("No resources\n");
+            for (i = 0; i < DeviceRelations->Count; i++)
+                ObDereferenceObject(DeviceRelations->Objects[i]);
+            ExFreePool(DeviceRelations);
+            Status = STATUS_NO_MEMORY;
+            goto cleanup;
+        }
+    }
+    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);
+        goto cleanup;
+    }
 
-   IopInitDeviceTreeTraverseContext(
-      &Context,
-      DeviceNode,
-      IopActionInterrogateDeviceStack,
-      DeviceNode);
+    /*
+     * 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 (%x)\n", Status);
-      return Status;
-   }
+    Status = IopTraverseDeviceTree(&Context);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
+        goto cleanup;
+    }
 
-   /*
-    * Retrieve configuration from the registry for discovered children
-    */
+    /*
+     * Get the state of the system boot. If the \\SystemRoot link isn't
+     * created yet, we will assume that it's possible to load only boot
+     * drivers.
+     */
+    InitializeObjectAttributes(
+        &ObjectAttributes,
+        &LinkName,
+        0,
+        NULL,
+        NULL);
+    Status = ZwOpenFile(
+        &Handle,
+        FILE_ALL_ACCESS,
+        &ObjectAttributes,
+        &IoStatusBlock,
+        0,
+        0);
+     if (NT_SUCCESS(Status))
+     {
+         BootDrivers = FALSE;
+         ZwClose(Handle);
+     }
+     else
+         BootDrivers = TRUE;
+
+    /*
+     * Initialize services for discovered children. Only boot drivers will
+     * be loaded from boot driver!
+     */
+    Status = IopInitializePnpServices(DeviceNode, BootDrivers);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
+        goto cleanup;
+    }
 
-   IopInitDeviceTreeTraverseContext(
-      &Context,
-      DeviceNode,
-      IopActionConfigureChildServices,
-      DeviceNode);
+    DPRINT("IopInvalidateDeviceRelations() finished\n");
+    Status = STATUS_SUCCESS;
 
-   Status = IopTraverseDeviceTree(&Context);
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
-      return Status;
-   }
-
-   /*
-    * Get the state of the system boot. If the \\SystemRoot link isn't
-    * created yet, we will assume that it's possible to load only boot
-    * drivers.
-    */
-
-   RtlInitUnicodeString(&LinkName, L"\\SystemRoot");
-
-   InitializeObjectAttributes(
-      &ObjectAttributes,
-      &LinkName,
-      0,
-      NULL,
-      NULL);
-
-   Status = ZwOpenFile(
-      &Handle,
-      FILE_ALL_ACCESS,
-      &ObjectAttributes,
-      &IoStatusBlock,
-      0,
-      0);
-   if(NT_SUCCESS(Status))
-   {
-     BootDrivers = FALSE;
-     ZwClose(Handle);
-   }
-   else
-     BootDrivers = TRUE;
-
-   /*
-    * Initialize services for discovered children. Only boot drivers will
-    * be loaded from boot driver!
-    */
-
-   Status = IopInitializePnpServices(DeviceNode, BootDrivers);
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("IopInitializePnpServices() failed with status (%x)\n", Status);
-      return Status;
-   }
-
-   DPRINT("IopInvalidateDeviceRelations() finished\n");
-   return STATUS_SUCCESS;
-}
-
-
-static
-NTSTATUS
-INIT_FUNCTION
-IopSetRootDeviceInstanceData(PDEVICE_NODE DeviceNode)
-{
-#if 0
-    PWSTR KeyBuffer;
-    HANDLE InstanceKey = NULL;
-    NTSTATUS Status;
-
-    /* Create registry key for the instance id, if it doesn't exist yet */
-    KeyBuffer = ExAllocatePool(PagedPool,
-                               (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
-    wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
-    wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
-    Status = IopCreateDeviceKeyPath(KeyBuffer,
-                                    &InstanceKey);
-    ExFreePool(KeyBuffer);
-    if (!NT_SUCCESS(Status))
+cleanup:
+    IoFreeWorkItem(Data->WorkItem);
+    if (Event)
     {
-        DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
-        return Status;
+        Data->Status = Status;
+        KeSetEvent(Event, 0, FALSE);
     }
-
-    /* FIXME: Set 'ConfigFlags' value */
-
-    ZwClose(InstanceKey);
-
-    return Status;
-#endif
-    return STATUS_SUCCESS;
-}
-
-
-VOID INIT_FUNCTION
-PnpInit(VOID)
-{
-   PDEVICE_OBJECT Pdo;
-   NTSTATUS Status;
-
-   DPRINT("PnpInit()\n");
-
-   KeInitializeSpinLock(&IopDeviceTreeLock);
-
-   /* Initialize the Bus Type GUID List */
-   IopBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
-   RtlZeroMemory(IopBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
-   ExInitializeFastMutex(&IopBusTypeGuidList->Lock);
-
-   /* Initialize PnP-Event notification support */
-   Status = IopInitPlugPlayEvents();
-   if (!NT_SUCCESS(Status))
-   {
-      CPRINT("IopInitPlugPlayEvents() failed\n");
-      KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
-   }
-
-   /*
-    * Create root device node
-    */
-
-   Status = IopCreateDriverObject(&IopRootDriverObject, NULL, 0, FALSE, NULL, 0);
-   if (!NT_SUCCESS(Status))
-   {
-      CPRINT("IoCreateDriverObject() failed\n");
-      KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
-   }
-
-   Status = IoCreateDevice(IopRootDriverObject, 0, NULL, FILE_DEVICE_CONTROLLER,
-      0, FALSE, &Pdo);
-   if (!NT_SUCCESS(Status))
-   {
-      CPRINT("IoCreateDevice() failed\n");
-      KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
-   }
-
-   Status = IopCreateDeviceNode(NULL, Pdo, &IopRootDeviceNode);
-   if (!NT_SUCCESS(Status))
-   {
-      CPRINT("Insufficient resources\n");
-      KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
-   }
-
-   if (!RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
-       L"HTREE\\ROOT\\0"))
-   {
-     CPRINT("Failed to create the instance path!\n");
-     KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, STATUS_UNSUCCESSFUL, 0, 0, 0);
-   }
-
-   /* Report the device to the user-mode pnp manager */
-   IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
-                             &IopRootDeviceNode->InstancePath);
-
-   IopRootDeviceNode->PhysicalDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
-   PnpRootDriverEntry(IopRootDriverObject, NULL);
-   IopRootDriverObject->DriverExtension->AddDevice(
-      IopRootDriverObject,
-      IopRootDeviceNode->PhysicalDeviceObject);
+    else
+        ExFreePool(Data);
 }
 
 static NTSTATUS INIT_FUNCTION
@@ -2595,15 +2628,20 @@ IopEnumerateDetectedDevices(
    IN HANDLE hBaseKey,
    IN PUNICODE_STRING RelativePath,
    IN HANDLE hRootKey,
-   IN BOOLEAN EnumerateSubKeys)
+   IN BOOLEAN EnumerateSubKeys,
+   IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
+   IN ULONG ParentBootResourcesLength)
 {
    UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
    UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
    UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
+   UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
+   UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
+   UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
    OBJECT_ATTRIBUTES ObjectAttributes;
    HANDLE hDevicesKey = NULL;
    HANDLE hDeviceKey = NULL;
-   HANDLE hLevel1Key, hLevel2Key = NULL;
+   HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
    UNICODE_STRING Level2NameU;
    WCHAR Level2Name[5];
    ULONG IndexDevice = 0;
@@ -2614,19 +2652,24 @@ IopEnumerateDetectedDevices(
    ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
    UNICODE_STRING DeviceName, ValueName;
    ULONG RequiredSize;
+   PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
+   ULONG BootResourcesLength;
    NTSTATUS Status;
 
    const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI BIOS");
-   UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03");
+   UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
    static ULONG DeviceIndexPci = 0;
+   /*const UNICODE_STRING IdentifierAcpi = RTL_CONSTANT_STRING(L"ACPI BIOS");
+   UNICODE_STRING HardwareIdAcpi = RTL_CONSTANT_STRING(L"*PNP0C08\0");
+   static ULONG DeviceIndexAcpi = 0;*/
    const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
-   UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501");
+   UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
    static ULONG DeviceIndexSerial = 0;
-   const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardPeripheral");
-   UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303");
+   const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
+   UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
    static ULONG DeviceIndexKeyboard = 0;
-   const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerPeripheral");
-   UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13");
+   const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
+   UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
    static ULONG DeviceIndexMouse = 0;
    PUNICODE_STRING pHardwareId;
    ULONG DeviceIndex = 0;
@@ -2681,12 +2724,12 @@ IopEnumerateDetectedDevices(
       IndexDevice++;
 
       /* Open device key */
-      DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
+      DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
       DeviceName.Buffer = pDeviceInformation->Name;
       InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
       Status = ZwOpenKey(
          &hDeviceKey,
-         KEY_QUERY_VALUE + EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0,
+         KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0),
          &ObjectAttributes);
       if (!NT_SUCCESS(Status))
       {
@@ -2694,6 +2737,87 @@ IopEnumerateDetectedDevices(
          goto cleanup;
       }
 
+      /* Read boot resources, and add then to parent ones */
+      Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
+      if (Status == STATUS_BUFFER_OVERFLOW)
+      {
+         ExFreePool(pValueInformation);
+         ValueInfoLength = RequiredSize;
+         pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
+         if (!pValueInformation)
+         {
+            DPRINT("ExAllocatePool() failed\n");
+            ZwDeleteKey(hLevel2Key);
+            Status = STATUS_NO_MEMORY;
+            goto cleanup;
+         }
+         Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
+      }
+      if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+      {
+         BootResources = ParentBootResources;
+         BootResourcesLength = ParentBootResourcesLength;
+      }
+      else if (!NT_SUCCESS(Status))
+      {
+         DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
+         goto nextdevice;
+      }
+      else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
+      {
+         DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
+         goto nextdevice;
+      }
+      else if (((PCM_FULL_RESOURCE_DESCRIPTOR)pValueInformation->Data)->PartialResourceList.Count == 0)
+      {
+         BootResources = ParentBootResources;
+         BootResourcesLength = ParentBootResourcesLength;
+      }
+      else
+      {
+         static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
+
+         /* Concatenate current resources and parent ones */
+         if (ParentBootResourcesLength == 0)
+            BootResourcesLength = pValueInformation->DataLength;
+         else
+            BootResourcesLength = ParentBootResourcesLength
+               + pValueInformation->DataLength
+               - Header;
+         BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
+         if (!BootResources)
+         {
+            DPRINT("ExAllocatePool() failed\n");
+            goto nextdevice;
+         }
+         if (ParentBootResourcesLength == 0)
+         {
+            RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
+         }
+         else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
+         {
+            RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
+            RtlCopyMemory(
+               (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
+               (PVOID)((ULONG_PTR)ParentBootResources + Header),
+               ParentBootResourcesLength - Header);
+            BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
+         }
+         else
+         {
+            RtlCopyMemory(BootResources, pValueInformation->Data, Header);
+            RtlCopyMemory(
+               (PVOID)((ULONG_PTR)BootResources + Header),
+               (PVOID)((ULONG_PTR)ParentBootResources + Header),
+               ParentBootResourcesLength - Header);
+            RtlCopyMemory(
+               (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
+               pValueInformation->Data + Header,
+               pValueInformation->DataLength - Header);
+            BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
+         }
+      }
+
       if (EnumerateSubKeys)
       {
          IndexSubKey = 0;
@@ -2721,10 +2845,16 @@ IopEnumerateDetectedDevices(
                goto cleanup;
             }
             IndexSubKey++;
-            DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
+            DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
             DeviceName.Buffer = pDeviceInformation->Name;
 
-            Status = IopEnumerateDetectedDevices(hDeviceKey, &DeviceName, hRootKey, TRUE);
+            Status = IopEnumerateDetectedDevices(
+               hDeviceKey,
+               &DeviceName,
+               hRootKey,
+               TRUE,
+               BootResources,
+               BootResourcesLength);
             if (!NT_SUCCESS(Status))
                goto cleanup;
          }
@@ -2747,26 +2877,27 @@ IopEnumerateDetectedDevices(
       }
       if (!NT_SUCCESS(Status))
       {
-         DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
-         goto nextdevice;
+         if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
+         {
+            DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
+            goto nextdevice;
+         }
       }
       else if (pValueInformation->Type != REG_SZ)
       {
          DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
          goto nextdevice;
       }
-
-      /* Assign hardware id to this device */
-      ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
-      ValueName.Buffer = (PWCHAR)pValueInformation->Data;
-      if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
-         ValueName.Length -= sizeof(WCHAR);
-      if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
+      else
       {
-         pHardwareId = &HardwareIdPci;
-         DeviceIndex = DeviceIndexPci++;
+         /* Assign hardware id to this device */
+         ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
+         ValueName.Buffer = (PWCHAR)pValueInformation->Data;
+         if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
+            ValueName.Length -= sizeof(WCHAR);
       }
-      else if (RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
+
+      if (RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
       {
          pHardwareId = &HardwareIdSerial;
          DeviceIndex = DeviceIndexSerial++;
@@ -2781,10 +2912,30 @@ IopEnumerateDetectedDevices(
          pHardwareId = &HardwareIdMouse;
          DeviceIndex = DeviceIndexMouse++;
       }
+      else if (NT_SUCCESS(Status))
+      {
+         /* Try to also match the device identifier */
+         if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
+         {
+            pHardwareId = &HardwareIdPci;
+            DeviceIndex = DeviceIndexPci++;
+         }
+         /*else if (RtlCompareUnicodeString(&ValueName, &IdentifierAcpi, FALSE) == 0)
+         {
+            pHardwareId = &HardwareIdAcpi;
+            DeviceIndex = DeviceIndexAcpi++;
+         }*/
+         else
+         {
+            /* Unknown device */
+            DPRINT("Unknown device '%wZ'\n", &ValueName);
+            goto nextdevice;
+         }
+      }
       else
       {
-         /* Unknown device */
-         DPRINT("Unknown device %wZ in %wZ\n", &ValueName, RelativePath);
+         /* Unknown key path */
+         DPRINT("Unknown key path %wZ\n", RelativePath);
          goto nextdevice;
       }
 
@@ -2796,7 +2947,7 @@ IopEnumerateDetectedDevices(
          &ObjectAttributes,
          0,
          NULL,
-         REG_OPTION_VOLATILE,
+         REG_OPTION_NON_VOLATILE,
          NULL);
       if (!NT_SUCCESS(Status))
       {
@@ -2808,11 +2959,11 @@ IopEnumerateDetectedDevices(
       InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
       Status = ZwCreateKey(
          &hLevel2Key,
-         KEY_SET_VALUE,
+         KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
          &ObjectAttributes,
          0,
          NULL,
-         REG_OPTION_VOLATILE,
+         REG_OPTION_NON_VOLATILE,
          NULL);
       ZwClose(hLevel1Key);
       if (!NT_SUCCESS(Status))
@@ -2828,15 +2979,44 @@ IopEnumerateDetectedDevices(
          ZwDeleteKey(hLevel2Key);
          goto nextdevice;
       }
-      Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
+      Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
       if (!NT_SUCCESS(Status))
       {
          DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
          ZwDeleteKey(hLevel2Key);
          goto nextdevice;
       }
+      if (BootResourcesLength > 0)
+      {
+         /* Save boot resources to 'LogConf\BootConfig' */
+         InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
+         Status = ZwCreateKey(
+            &hLogConf,
+            KEY_SET_VALUE,
+            &ObjectAttributes,
+            0,
+            NULL,
+            REG_OPTION_VOLATILE,
+            NULL);
+         if (!NT_SUCCESS(Status))
+         {
+            DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
+            ZwDeleteKey(hLevel2Key);
+            goto nextdevice;
+         }
+         Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_FULL_RESOURCE_DESCRIPTOR, BootResources, BootResourcesLength);
+         ZwClose(hLogConf);
+         if (!NT_SUCCESS(Status))
+         {
+            DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
+            ZwDeleteKey(hLevel2Key);
+            goto nextdevice;
+         }
+      }
 
 nextdevice:
+      if (BootResources && BootResources != ParentBootResources)
+         ExFreePool(BootResources);
       if (hLevel2Key)
       {
          ZwClose(hLevel2Key);
@@ -2863,52 +3043,279 @@ cleanup:
    return Status;
 }
 
-static NTSTATUS INIT_FUNCTION
-IopUpdateRootKey(VOID)
+static BOOLEAN INIT_FUNCTION
+IopIsAcpiComputer(VOID)
 {
-   UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum\\Root");
+   return FALSE;
+#if 0
    UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
+   UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
+   UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS");
    OBJECT_ATTRIBUTES ObjectAttributes;
-   HANDLE hRoot;
+   PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
+   ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
+   PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
+   ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
+   ULONG RequiredSize;
+   ULONG IndexDevice = 0;
+   UNICODE_STRING DeviceName, ValueName;
+   HANDLE hDevicesKey = NULL;
+   HANDLE hDeviceKey = NULL;
    NTSTATUS Status;
+   BOOLEAN ret = FALSE;
 
-   InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE, NULL, NULL);
-   Status = ZwOpenKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes);
+   InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_KERNEL_HANDLE, NULL, NULL);
+   Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
    if (!NT_SUCCESS(Status))
    {
       DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
-      return Status;
+      goto cleanup;
    }
-   Status = IopEnumerateDetectedDevices(
-      NULL,
-      &MultiKeyPathU,
-      hRoot,
-      TRUE);
-   ZwClose(hRoot);
-   return Status;
+
+   pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
+   if (!pDeviceInformation)
+   {
+      DPRINT("ExAllocatePool() failed\n");
+      Status = STATUS_NO_MEMORY;
+      goto cleanup;
+   }
+
+   pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
+   if (!pDeviceInformation)
+   {
+      DPRINT("ExAllocatePool() failed\n");
+      Status = STATUS_NO_MEMORY;
+      goto cleanup;
+   }
+
+   while (TRUE)
+   {
+      Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
+      if (Status == STATUS_NO_MORE_ENTRIES)
+         break;
+      else if (Status == STATUS_BUFFER_OVERFLOW)
+      {
+         ExFreePool(pDeviceInformation);
+         DeviceInfoLength = RequiredSize;
+         pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
+         if (!pDeviceInformation)
+         {
+            DPRINT("ExAllocatePool() failed\n");
+            Status = STATUS_NO_MEMORY;
+            goto cleanup;
+         }
+         Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
+      }
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
+         goto cleanup;
+      }
+      IndexDevice++;
+
+      /* Open device key */
+      DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
+      DeviceName.Buffer = pDeviceInformation->Name;
+      InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
+      Status = ZwOpenKey(
+         &hDeviceKey,
+         KEY_QUERY_VALUE,
+         &ObjectAttributes);
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
+         goto cleanup;
+      }
+
+      /* Read identifier */
+      Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
+      if (Status == STATUS_BUFFER_OVERFLOW)
+      {
+         ExFreePool(pValueInformation);
+         ValueInfoLength = RequiredSize;
+         pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
+         if (!pValueInformation)
+         {
+            DPRINT("ExAllocatePool() failed\n");
+            Status = STATUS_NO_MEMORY;
+            goto cleanup;
+         }
+         Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
+      }
+      if (!NT_SUCCESS(Status))
+      {
+         DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
+         goto nextdevice;
+      }
+      else if (pValueInformation->Type != REG_SZ)
+      {
+         DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
+         goto nextdevice;
+      }
+
+      ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
+      ValueName.Buffer = (PWCHAR)pValueInformation->Data;
+      if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
+         ValueName.Length -= sizeof(WCHAR);
+      if (RtlCompareUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE) == 0)
+      {
+         DPRINT("Found ACPI BIOS\n");
+         ret = TRUE;
+         goto cleanup;
+      }
+
+nextdevice:
+      ZwClose(hDeviceKey);
+      hDeviceKey = NULL;
+   }
+
+cleanup:
+   if (pDeviceInformation)
+      ExFreePool(pDeviceInformation);
+   if (pValueInformation)
+      ExFreePool(pValueInformation);
+   if (hDevicesKey)
+      ZwClose(hDevicesKey);
+   if (hDeviceKey)
+      ZwClose(hDeviceKey);
+   return ret;
+#endif
 }
 
-VOID INIT_FUNCTION
-PnpInit2(VOID)
+static NTSTATUS INIT_FUNCTION
+IopUpdateRootKey(VOID)
 {
+   UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum\\Root");
+   UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
+   UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
+   UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
+   UNICODE_STRING HalAcpiDevice = RTL_CONSTANT_STRING(L"ACPI_HAL");
+   UNICODE_STRING HalAcpiId = RTL_CONSTANT_STRING(L"0000");
+   UNICODE_STRING HalAcpiDeviceDesc = RTL_CONSTANT_STRING(L"HAL ACPI");
+   UNICODE_STRING HalAcpiHardwareID = RTL_CONSTANT_STRING(L"*PNP0C08\0");
+   OBJECT_ATTRIBUTES ObjectAttributes;
+   HANDLE hRoot, hHalAcpiDevice, hHalAcpiId;
    NTSTATUS Status;
 
-   /* Move information about devices detected by Freeloader to SYSTEM\CurrentControlSet\Root\ */
-   /* FIXME: this should be done only when ACPI is disabled or not present! */
-   Status = IopUpdateRootKey();
-   if (!NT_SUCCESS(Status))
+   InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE, NULL, NULL);
+   Status = ZwOpenKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes);
+   if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
    {
-      CPRINT("IopUpdateRootKey() failed\n");
-      KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
+      /* We are probably in 1st stage */
+      return STATUS_SUCCESS;
+   }
+   else if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
+      return Status;
    }
 
-   /* Set root device instance data */
-   Status = IopSetRootDeviceInstanceData(IopRootDeviceNode);
-   if (!NT_SUCCESS(Status))
+   if (IopIsAcpiComputer())
+   {
+      InitializeObjectAttributes(&ObjectAttributes, &HalAcpiDevice, OBJ_KERNEL_HANDLE, hRoot, NULL);
+      Status = ZwCreateKey(&hHalAcpiDevice, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
+      ZwClose(hRoot);
+      if (!NT_SUCCESS(Status))
+         return Status;
+      InitializeObjectAttributes(&ObjectAttributes, &HalAcpiId, OBJ_KERNEL_HANDLE, hHalAcpiDevice, NULL);
+      Status = ZwCreateKey(&hHalAcpiId, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
+      ZwClose(hHalAcpiDevice);
+      if (!NT_SUCCESS(Status))
+         return Status;
+      Status = ZwSetValueKey(hHalAcpiId, &DeviceDescU, 0, REG_SZ, HalAcpiDeviceDesc.Buffer, HalAcpiDeviceDesc.MaximumLength);
+      if (NT_SUCCESS(Status))
+         Status = ZwSetValueKey(hHalAcpiId, &HardwareIDU, 0, REG_MULTI_SZ, HalAcpiHardwareID.Buffer, HalAcpiHardwareID.MaximumLength);
+      ZwClose(hHalAcpiId);
+      return Status;
+   }
+   else
    {
-      CPRINT("Failed to set instance data\n");
-      KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
+      Status = IopEnumerateDetectedDevices(
+         NULL,
+         &MultiKeyPathU,
+         hRoot,
+         TRUE,
+         NULL,
+         0);
+      ZwClose(hRoot);
+      return Status;
    }
 }
 
+VOID INIT_FUNCTION
+PnpInit(VOID)
+{
+    PDEVICE_OBJECT Pdo;
+    NTSTATUS Status;
+
+    DPRINT("PnpInit()\n");
+
+    KeInitializeSpinLock(&IopDeviceTreeLock);
+
+    /* Initialize the Bus Type GUID List */
+    IopBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
+    RtlZeroMemory(IopBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
+    ExInitializeFastMutex(&IopBusTypeGuidList->Lock);
+
+    /* Initialize PnP-Event notification support */
+    Status = IopInitPlugPlayEvents();
+    if (!NT_SUCCESS(Status))
+    {
+        CPRINT("IopInitPlugPlayEvents() failed\n");
+        KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
+
+    /*
+    * Create root device node
+    */
+
+    Status = IopCreateDriverObject(&IopRootDriverObject, NULL, 0, FALSE, NULL, 0);
+    if (!NT_SUCCESS(Status))
+    {
+        CPRINT("IoCreateDriverObject() failed\n");
+        KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
+
+    Status = IoCreateDevice(IopRootDriverObject, 0, NULL, FILE_DEVICE_CONTROLLER,
+        0, FALSE, &Pdo);
+    if (!NT_SUCCESS(Status))
+    {
+        CPRINT("IoCreateDevice() failed\n");
+        KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
+
+    Status = IopCreateDeviceNode(NULL, Pdo, &IopRootDeviceNode);
+    if (!NT_SUCCESS(Status))
+    {
+        CPRINT("Insufficient resources\n");
+        KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
+
+    if (!RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
+        L"HTREE\\ROOT\\0"))
+    {
+        CPRINT("Failed to create the instance path!\n");
+        KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 0, 0, 0);
+    }
+
+    /* Report the device to the user-mode pnp manager */
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
+        &IopRootDeviceNode->InstancePath);
+
+    IopRootDeviceNode->PhysicalDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
+    PnpRootDriverEntry(IopRootDriverObject, NULL);
+    IopRootDriverObject->DriverExtension->AddDevice(
+        IopRootDriverObject,
+        IopRootDeviceNode->PhysicalDeviceObject);
+
+    /* Move information about devices detected by Freeloader to SYSTEM\CurrentControlSet\Root\ */
+    Status = IopUpdateRootKey();
+    if (!NT_SUCCESS(Status))
+    {
+        CPRINT("IopUpdateRootKey() failed\n");
+        KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
+    }
+}
+
+
 /* EOF */