[NTOS]
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / plugplay.c
index 9c01544..ed3b173 100644 (file)
@@ -141,7 +141,7 @@ IopTraverseDeviceNode(PDEVICE_NODE Node, PUNICODE_STRING DeviceInstance)
 }
 
 
-static PDEVICE_OBJECT
+PDEVICE_OBJECT
 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
 {
     if (IopRootDeviceNode == NULL)
@@ -167,7 +167,7 @@ static NTSTATUS
 IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
 {
     NTSTATUS Status = STATUS_SUCCESS;
-    UNICODE_STRING Name;
+    volatile UNICODE_STRING Name;
 
     Name.Buffer = NULL;
     _SEH2_TRY
@@ -208,6 +208,70 @@ IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
     return Status;
 }
 
+static NTSTATUS
+IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList)
+{
+    NTSTATUS Status;
+    UNICODE_STRING DeviceInstance;
+    PDEVICE_OBJECT DeviceObject = NULL;
+    ULONG BufferSize = 0;
+    GUID FilterGuid;
+    PZZWSTR SymbolicLinkList = NULL, LinkList;
+    ULONG TotalLength = 0;
+
+    _SEH2_TRY
+    {
+        ProbeForRead(DeviceList->FilterGuid, sizeof(GUID), sizeof(UCHAR));
+        RtlCopyMemory(&FilterGuid, DeviceList->FilterGuid, sizeof(GUID));
+
+        if (DeviceList->Buffer != NULL && DeviceList->BufferSize != 0)
+        {
+            BufferSize = DeviceList->BufferSize;
+            ProbeForWrite(DeviceList->Buffer, BufferSize, sizeof(UCHAR));
+        }
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        ExFreePool(DeviceInstance.Buffer);
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+
+    Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceList->DeviceInstance);
+    if (NT_SUCCESS(Status))
+    {
+        /* Get the device object */
+        DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
+        ExFreePool(DeviceInstance.Buffer);
+    }
+
+    Status = IoGetDeviceInterfaces(&FilterGuid, DeviceObject, DeviceList->Flags, &SymbolicLinkList);
+    ObDereferenceObject(DeviceObject);
+
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed */
+        return Status;
+    }
+
+    LinkList = SymbolicLinkList;
+    while (*SymbolicLinkList != UNICODE_NULL)
+    {
+        TotalLength += (wcslen(SymbolicLinkList) + 1) * sizeof(WCHAR);
+        SymbolicLinkList += wcslen(SymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
+    }
+    TotalLength += sizeof(UNICODE_NULL);
+
+    if (BufferSize >= TotalLength)
+    {
+        RtlCopyMemory(DeviceList->Buffer, SymbolicLinkList, TotalLength * sizeof(WCHAR));
+    }
+    DeviceList->BufferSize = TotalLength;
+    ExFreePool(LinkList);
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS
 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
 {
@@ -406,6 +470,53 @@ IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData)
     return Status;
 }
 
+static ULONG
+IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode)
+{
+    ULONG Output = 0;
+
+    if (DeviceNode->Parent == IopRootDeviceNode)
+        Output |= DN_ROOT_ENUMERATED;
+
+    if (DeviceNode->Flags & DNF_ADDED)
+        Output |= DN_DRIVER_LOADED;
+
+    /* FIXME: DN_ENUM_LOADED */
+
+    if (DeviceNode->Flags & DNF_STARTED)
+        Output |= DN_STARTED;
+
+    /* FIXME: Manual */
+
+    if (!(DeviceNode->Flags & DNF_PROCESSED))
+        Output |= DN_NEED_TO_ENUM;
+
+    /* DN_NOT_FIRST_TIME is 9x only */
+
+    /* FIXME: DN_HARDWARE_ENUM */
+
+    /* DN_LIAR and DN_HAS_MARK are 9x only */
+
+    if (DeviceNode->Problem != 0)
+        Output |= DN_HAS_PROBLEM;
+
+    /* FIXME: DN_FILTERED */
+
+    if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
+        Output |= DN_LEGACY_DRIVER;
+
+    if (DeviceNode->UserFlags & DNUF_DONT_SHOW_IN_UI)
+        Output |= DN_NO_SHOW_IN_DM;
+
+    if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE))
+        Output |= DN_DISABLEABLE;
+
+    /* FIXME: Implement the rest */
+
+    Output |= DN_NT_ENUMERATOR | DN_NT_DRIVER;
+
+    return Output;
+}
 
 static NTSTATUS
 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
@@ -453,14 +564,12 @@ IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
     {
         case PNP_GET_DEVICE_STATUS:
             DPRINT("Get status data\n");
-            DeviceStatus = DeviceNode->Flags;
+            DeviceStatus = IopGetDeviceNodeStatus(DeviceNode);
             DeviceProblem = DeviceNode->Problem;
             break;
 
         case PNP_SET_DEVICE_STATUS:
-            DPRINT("Set status data\n");
-            DeviceNode->Flags = DeviceStatus;
-            DeviceNode->Problem = DeviceProblem;
+            DPRINT1("Set status data is NOT SUPPORTED\n");
             break;
 
         case PNP_CLEAR_DEVICE_STATUS:
@@ -549,16 +658,48 @@ IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData)
     if (DeviceObject == NULL)
         return STATUS_NO_SUCH_DEVICE;
 
+    /* Get the device node */
     DeviceNode = IopGetDeviceNode(DeviceObject);
 
-    /* FIXME: we should stop the device, before starting it again */
+    ASSERT(DeviceNode->Flags & DNF_ENUMERATED);
+    ASSERT(DeviceNode->Flags & DNF_PROCESSED);
 
-    /* Start the device */
-    IopDeviceNodeClearFlag(DeviceNode, DNF_DISABLED);
-    Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
+    /* Check if there's already a driver loaded for this device */
+    if (DeviceNode->Flags & DNF_ADDED)
+    {
+#if 0
+        /* Remove the device node */
+        Status = IopRemoveDevice(DeviceNode);
+        if (NT_SUCCESS(Status))
+        {
+            /* Invalidate device relations for the parent to reenumerate the device */
+            DPRINT1("A new driver will be loaded for '%wZ' (FDO above removed)\n", &DeviceNode->InstancePath);
+            Status = IoSynchronousInvalidateDeviceRelations(DeviceNode->Parent->PhysicalDeviceObject, BusRelations);
+        }
+        else
+#endif
+        {
+            /* A driver has already been loaded for this device */
+            DPRINT1("A reboot is required for the current driver for '%wZ' to be replaced\n", &DeviceNode->InstancePath);
+            DeviceNode->Problem = CM_PROB_NEED_RESTART;
+        }
+    }
+    else
+    {
+        /* FIXME: What if the device really is disabled? */
+        DeviceNode->Flags &= ~DNF_DISABLED;
+        DeviceNode->Problem = 0;
 
-    if (NT_SUCCESS(Status))
-        Status = IopActionInitChildServices(DeviceNode, DeviceNode->Parent);
+        /* Load service data from the registry */
+        Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
+
+        if (NT_SUCCESS(Status))
+        {
+            /* Start the service and begin PnP initialization of the device again */
+            DPRINT1("A new driver will be loaded for '%wZ' (no FDO above)\n", &DeviceNode->InstancePath);
+            Status = IopActionInitChildServices(DeviceNode, DeviceNode->Parent);
+        }
+    }
 
     ObDereferenceObject(DeviceObject);
 
@@ -750,7 +891,7 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
                   IN OUT PVOID Buffer,
                   IN ULONG BufferLength)
 {
-    DPRINT("NtPlugPlayControl(%lu %p %lu) called\n",
+    DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
            PlugPlayControlClass, Buffer, BufferLength);
 
     /* Function can only be called from user-mode */
@@ -788,6 +929,11 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
                 return STATUS_INVALID_PARAMETER;
             return IopRemovePlugPlayEvent();
 
+        case PlugPlayControlGetInterfaceDeviceList:
+            if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA))
+                return STATUS_INVALID_PARAMETER;
+            return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)Buffer);
+
         case PlugPlayControlProperty:
             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA))
                 return STATUS_INVALID_PARAMETER;