[NTOSKRNL]
authorCameron Gutman <aicommander@gmail.com>
Thu, 1 Apr 2010 06:58:32 +0000 (06:58 +0000)
committerCameron Gutman <aicommander@gmail.com>
Thu, 1 Apr 2010 06:58:32 +0000 (06:58 +0000)
- Change PnpRootCreateDevice's ServiceName parameter to be a full service name so it can be used by IoReportDetectedDevice (for reporting devices without the "LEGACY_" prefix) and change all of its callers accordingly
- Remove the broken implementation of IoReportDetectedDevice and replace it with a fully working implementation
- There is still a bug that it creates a new device instance every boot, but unlike the previous code, at least it creates one ;-)

svn path=/trunk/; revision=46639

reactos/ntoskrnl/io/pnpmgr/pnpmgr.c
reactos/ntoskrnl/io/pnpmgr/pnpreport.c
reactos/ntoskrnl/io/pnpmgr/pnproot.c

index 502787f..4e82088 100644 (file)
@@ -46,11 +46,12 @@ typedef struct _INVALIDATE_DEVICE_RELATION_DATA
 
 /* FUNCTIONS *****************************************************************/
 
-static NTSTATUS
+NTSTATUS
 IopAssignDeviceResources(
    IN PDEVICE_NODE DeviceNode,
    OUT ULONG *pRequiredSize);
-static NTSTATUS
+
+NTSTATUS
 IopTranslateDeviceResources(
    IN PDEVICE_NODE DeviceNode,
    IN ULONG RequiredSize);
@@ -361,6 +362,8 @@ IopCreateDeviceNode(PDEVICE_NODE ParentNode,
    PDEVICE_NODE Node;
    NTSTATUS Status;
    KIRQL OldIrql;
+   UNICODE_STRING FullServiceName;
+   UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
 
    DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
       ParentNode, PhysicalDeviceObject, ServiceName);
@@ -375,7 +378,22 @@ IopCreateDeviceNode(PDEVICE_NODE ParentNode,
 
    if (!PhysicalDeviceObject)
    {
-      Status = PnpRootCreateDevice(ServiceName, &PhysicalDeviceObject);
+      if (ServiceName)
+      {
+         FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName->Length;
+         FullServiceName.Length = 0;
+         FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
+         if (!FullServiceName.Buffer)
+         {
+            ExFreePool(Node);
+            return STATUS_INSUFFICIENT_RESOURCES;
+         }
+
+         RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
+         RtlAppendUnicodeStringToString(&FullServiceName, ServiceName);
+      }
+
+      Status = PnpRootCreateDevice(ServiceName ? &FullServiceName : NULL, &PhysicalDeviceObject);
       if (!NT_SUCCESS(Status))
       {
          DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
@@ -709,7 +727,6 @@ IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
 }
 
 
-static
 NTSTATUS
 IopSetDeviceInstanceData(HANDLE InstanceKey,
                          PDEVICE_NODE DeviceNode)
@@ -799,7 +816,7 @@ IopSetDeviceInstanceData(HANDLE InstanceKey,
 }
 
 
-static NTSTATUS
+NTSTATUS
 IopAssignDeviceResources(
    IN PDEVICE_NODE DeviceNode,
    OUT ULONG *pRequiredSize)
@@ -1014,7 +1031,7 @@ ByeBye:
 }
 
 
-static NTSTATUS
+NTSTATUS
 IopTranslateDeviceResources(
    IN PDEVICE_NODE DeviceNode,
    IN ULONG RequiredSize)
index e11c4b0..334a9ce 100644 (file)
@@ -3,7 +3,7 @@
  * COPYRIGHT:       GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/io/pnpmgr/pnpreport.c
  * PURPOSE:         Device Changes Reporting Functions
- * PROGRAMMERS:     Filip Navara (xnavara@volny.cz)
+ * PROGRAMMERS:     Cameron Gutman (cameron.gutman@reactos.org)
  */
 
 /* INCLUDES ******************************************************************/
 #define NDEBUG
 #include <debug.h>
 
+NTSTATUS
+NTAPI
+IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
+                       OUT PHANDLE Handle);
+
+NTSTATUS
+IopAssignDeviceResources(
+   IN PDEVICE_NODE DeviceNode,
+   OUT ULONG *pRequiredSize);
+
+NTSTATUS
+IopSetDeviceInstanceData(HANDLE InstanceKey,
+                         PDEVICE_NODE DeviceNode);
+
+NTSTATUS
+IopTranslateDeviceResources(
+   IN PDEVICE_NODE DeviceNode,
+   IN ULONG RequiredSize);
+
+NTSTATUS
+IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
+                                PVOID Context);
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+PWCHAR
+IopGetInterfaceTypeString(INTERFACE_TYPE IfType)
+{
+    switch (IfType)
+    {
+       case Internal:
+         return L"Internal";
+
+       case Isa:
+         return L"Isa";
+
+       case Eisa:
+         return L"Eisa";
+
+       case MicroChannel:
+         return L"MicroChannel";
+
+       case TurboChannel:
+         return L"TurboChannel";
+
+       case PCIBus:
+         return L"PCIBus";
+
+       case VMEBus:
+         return L"VMEBus";
+
+       case NuBus:
+         return L"NuBus";
+
+       case PCMCIABus:
+         return L"PCMCIABus";
+
+       case CBus:
+         return L"CBus";
+
+       case MPIBus:
+         return L"MPIBus";
+
+       case MPSABus:
+         return L"MPSABus";
+
+       case ProcessorInternal:
+         return L"ProcessorInternal";
+
+       case PNPISABus:
+         return L"PNPISABus";
+
+       case PNPBus:
+         return L"PNPBus";
+
+       case Vmcs:
+         return L"Vmcs";
+
+       default:
+         DPRINT1("Invalid bus type: %d\n", IfType);
+         return NULL;
+    }
+}
+
 /* PUBLIC FUNCTIONS **********************************************************/
 
 /*
@@ -30,29 +114,56 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
 {
     PDEVICE_NODE DeviceNode;
     PDEVICE_OBJECT Pdo;
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
+    HANDLE InstanceKey;
+    ULONG RequiredLength;
+    UNICODE_STRING ValueName, ServiceName;
+    WCHAR HardwareId[256];
+    PWCHAR IfString;
+    ULONG IdLength;
 
-    DPRINT("__FUNCTION__ (DeviceObject %p, *DeviceObject %p)\n",
+    DPRINT("IoReportDetectedDevice (DeviceObject %p, *DeviceObject %p)\n",
       DeviceObject, DeviceObject ? *DeviceObject : NULL);
 
-    /* if *DeviceObject is not NULL, we must use it as a PDO, and don't create a new one */
+    /* Create the service name (eg. ACPI_HAL) */
+    ServiceName.Buffer = DriverObject->DriverName.Buffer +
+       sizeof(DRIVER_ROOT_NAME) / sizeof(WCHAR) - 1;
+    ServiceName.Length = DriverObject->DriverName.Length -
+       sizeof(DRIVER_ROOT_NAME) + sizeof(WCHAR);
+    ServiceName.MaximumLength = ServiceName.Length;
+
+    /* If the interface type is unknown, treat it as internal */
+    if (LegacyBusType == InterfaceTypeUndefined)
+        LegacyBusType = Internal;
+
+    /* Get the string equivalent of the interface type */
+    IfString = IopGetInterfaceTypeString(LegacyBusType);
+
+    /* If NULL is returned then it's a bad type */
+    if (!IfString)
+        return STATUS_INVALID_PARAMETER;
+
+    /* We use the caller's PDO if they supplied one */
     if (DeviceObject && *DeviceObject)
     {
         Pdo = *DeviceObject;
+        DeviceNode = IopGetDeviceNode(*DeviceObject);
     }
     else
     {
-        UNICODE_STRING ServiceName;
-        ServiceName.Buffer = DriverObject->DriverName.Buffer +
-          sizeof(DRIVER_ROOT_NAME) / sizeof(WCHAR) - 1;
-        ServiceName.Length = DriverObject->DriverName.Length -
-          sizeof(DRIVER_ROOT_NAME) + sizeof(WCHAR);
-        ServiceName.MaximumLength = ServiceName.Length;
-
-        /* create a new PDO and return it in *DeviceObject */
+        /* Create the PDO */
+        Status = PnpRootCreateDevice(&ServiceName,
+                                     &Pdo);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("PnpRootCreateDevice() failed (Status 0x%08lx)\n", Status);
+            return Status;
+        }
+
+        /* Create the device node for the new PDO */
         Status = IopCreateDeviceNode(IopRootDeviceNode,
+                                     Pdo,
                                      NULL,
-                                     &ServiceName,
                                      &DeviceNode);
 
         if (!NT_SUCCESS(Status))
@@ -60,13 +171,129 @@ IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject,
             DPRINT("IopCreateDeviceNode() failed (Status 0x%08lx)\n", Status);
             return Status;
         }
+    }
+
+    /* We don't call AddDevice for devices reported this way */
+    IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
+
+    /* We don't send IRP_MN_START_DEVICE */
+    IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
+
+    /* This is a legacy driver for this device */
+    IopDeviceNodeSetFlag(DeviceNode, DNF_LEGACY_DRIVER);
+
+    /* Perform a manual configuration of our device */
+    IopActionInterrogateDeviceStack(DeviceNode, DeviceNode->Parent);
+    IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
+
+    /* Open a handle to the instance path key */
+    Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, &InstanceKey);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Add DETECTEDInterfaceType\DriverName */
+    IdLength = 0;
+    IdLength += swprintf(&HardwareId[IdLength],
+                         L"DETECTED%ls\\%wZ",
+                         IfString,
+                         &ServiceName);
+    HardwareId[IdLength++] = UNICODE_NULL;
+
+    /* Add DETECTED\DriverName */
+    IdLength += swprintf(&HardwareId[IdLength],
+                         L"DETECTED\\%wZ",
+                         &ServiceName);
+    HardwareId[IdLength++] = UNICODE_NULL;
+
+    /* Terminate the string with another null */
+    HardwareId[IdLength] = UNICODE_NULL;
+
+    /* Store the value for CompatibleIDs */
+    RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
+    Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR));
+    if (!NT_SUCCESS(Status))
+    {
+       DPRINT("Failed to write the compatible IDs: 0x%x\n", Status);
+       ZwClose(InstanceKey);
+       return Status;
+    }
 
-        Pdo = DeviceNode->PhysicalDeviceObject;
-        if (DeviceObject) *DeviceObject = Pdo;
-  }
+    /* Add a hardware ID if the driver didn't report one */
+    RtlInitUnicodeString(&ValueName, L"HardwareID");
+    if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+       /* Just use our most specific compatible ID */
+       IdLength = 0;
+       IdLength += swprintf(&HardwareId[IdLength],
+                            L"DETECTED%ls\\%wZ",
+                            IfString,
+                            &ServiceName);
+       HardwareId[++IdLength] = UNICODE_NULL;
+
+       /* Write the value to the registry */
+       Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_SZ, HardwareId, IdLength * sizeof(WCHAR));
+       if (!NT_SUCCESS(Status))
+       {
+          DPRINT("Failed to write the hardware ID: 0x%x\n", Status);
+          ZwClose(InstanceKey);
+          return Status;
+       }
+    }
+
+    /* Assign the resources to the device node */
+    DeviceNode->BootResources = ResourceList;
+    DeviceNode->ResourceRequirements = ResourceRequirements;
+
+    /* Set appropriate flags */
+    if (DeviceNode->BootResources)
+       IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
+
+    if (DeviceNode->ResourceRequirements)
+       IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_REPORTED);
+    else
+       IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED);
+
+    /* Write the resource information to the registry */
+    IopSetDeviceInstanceData(InstanceKey, DeviceNode);
+
+    /* Close the instance key handle */
+    ZwClose(InstanceKey);
 
-    /* we don't need to call AddDevice and send IRP_MN_START_DEVICE */
-    return Status;
+    /* If the caller didn't get the resources assigned for us, do it now */
+    if (!ResourceAssigned)
+    {
+       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);
+       }
+       IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
+
+       /* See if we failed */
+       if (!NT_SUCCESS(Status))
+       {
+           DPRINT("Assigning resources failed: 0x%x\n", Status);
+           return Status;
+       }
+    }
+
+    /* Report the device's enumeration to umpnpmgr */
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
+                              &DeviceNode->InstancePath);
+
+    /* Report the device's arrival to umpnpmgr */
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
+                              &DeviceNode->InstancePath);
+
+    DPRINT1("Reported device: %S (%wZ)\n", HardwareId, &DeviceNode->InstancePath);
+
+    /* Return the PDO */
+    if (DeviceObject) *DeviceObject = Pdo;
+
+    return STATUS_SUCCESS;
 }
 
 /*
index 5a5bf85..c622cba 100644 (file)
@@ -134,7 +134,7 @@ PnpRootCreateDevice(
     IN PDEVICE_OBJECT *PhysicalDeviceObject)
 {
     PPNPROOT_FDO_DEVICE_EXTENSION DeviceExtension;
-    UNICODE_STRING UnknownServiceName = RTL_CONSTANT_STRING(L"UNKNOWN");
+    UNICODE_STRING UnknownServiceName = RTL_CONSTANT_STRING(L"LEGACY_UNKNOWN");
     PUNICODE_STRING LocalServiceName;
     PPNPROOT_PDO_DEVICE_EXTENSION PdoDeviceExtension;
     WCHAR DevicePath[MAX_PATH + 1];
@@ -154,7 +154,7 @@ PnpRootCreateDevice(
     DPRINT("Creating a PnP root device for service '%wZ'\n", LocalServiceName);
 
     /* Search for a free instance ID */
-    _snwprintf(DevicePath, sizeof(DevicePath) / sizeof(WCHAR), L"%s\\LEGACY_%wZ", REGSTR_KEY_ROOTENUM, LocalServiceName);
+    _snwprintf(DevicePath, sizeof(DevicePath) / sizeof(WCHAR), L"%s\\%wZ", REGSTR_KEY_ROOTENUM, LocalServiceName);
     for (i = 0; i < 9999; i++)
     {
         _snwprintf(InstancePath, sizeof(InstancePath) / sizeof(WCHAR), L"%04lu", i);