[NTOSKRNL] IopGetDeviceProperty: Send an IRP_MN_QUERY_CAPABILITIES request to the...
[reactos.git] / ntoskrnl / io / pnpmgr / plugplay.c
index 8b088f5..9aafd07 100644 (file)
@@ -76,7 +76,10 @@ IopQueueTargetDeviceEvent(const GUID *Guid,
     Copy.Buffer = EventEntry->Event.TargetDevice.DeviceIds;
     Status = RtlAppendUnicodeStringToString(&Copy, DeviceIds);
     if (!NT_SUCCESS(Status))
+    {
+        ExFreePool(EventEntry);
         return Status;
+    }
 
     InsertHeadList(&IopPnpEventQueueHead,
                    &EventEntry->ListEntry);
@@ -160,7 +163,6 @@ IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
     }
 
     return IopTraverseDeviceNode(IopRootDeviceNode, DeviceInstance);
-
 }
 
 static NTSTATUS
@@ -200,7 +202,9 @@ IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
         if (Name.Buffer)
+        {
             ExFreePool(Name.Buffer);
+        }
         Status = _SEH2_GetExceptionCode();
     }
     _SEH2_END;
@@ -208,15 +212,95 @@ IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
     return Status;
 }
 
+static NTSTATUS
+IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList)
+{
+    NTSTATUS Status;
+    PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList;
+    UNICODE_STRING DeviceInstance;
+    PDEVICE_OBJECT DeviceObject = NULL;
+    GUID FilterGuid;
+    PZZWSTR SymbolicLinkList = NULL, LinkList;
+    SIZE_T TotalLength;
+
+    _SEH2_TRY
+    {
+        RtlCopyMemory(&StackList, DeviceList, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
+
+        ProbeForRead(StackList.FilterGuid, sizeof(GUID), sizeof(UCHAR));
+        RtlCopyMemory(&FilterGuid, StackList.FilterGuid, sizeof(GUID));
+
+        if (StackList.Buffer != NULL && StackList.BufferSize != 0)
+        {
+            ProbeForWrite(StackList.Buffer, StackList.BufferSize, sizeof(UCHAR));
+        }
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    Status = IopCaptureUnicodeString(&DeviceInstance, &StackList.DeviceInstance);
+    if (NT_SUCCESS(Status))
+    {
+        /* Get the device object */
+        DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
+        if (DeviceInstance.Buffer != NULL)
+        {
+            ExFreePool(DeviceInstance.Buffer);
+        }
+    }
+
+    Status = IoGetDeviceInterfaces(&FilterGuid, DeviceObject, StackList.Flags, &SymbolicLinkList);
+    ObDereferenceObject(DeviceObject);
+
+    if (!NT_SUCCESS(Status))
+    {
+        /* failed */
+        return Status;
+    }
+
+    LinkList = SymbolicLinkList;
+    while (*SymbolicLinkList != UNICODE_NULL)
+    {
+        SymbolicLinkList += wcslen(SymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
+    }
+    TotalLength = ((SymbolicLinkList - LinkList + 1) * sizeof(WCHAR));
+
+    _SEH2_TRY
+    {
+        if (StackList.Buffer != NULL &&
+            StackList.BufferSize >= TotalLength)
+        {
+            // We've already probed the buffer for writing above.
+            RtlCopyMemory(StackList.Buffer, LinkList, TotalLength);
+        }
+
+        DeviceList->BufferSize = TotalLength;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        ExFreePool(LinkList);
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    ExFreePool(LinkList);
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS
 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
 {
     PDEVICE_OBJECT DeviceObject = NULL;
-    NTSTATUS Status;
+    PDEVICE_NODE DeviceNode;
     UNICODE_STRING DeviceInstance;
     ULONG BufferSize;
-    ULONG Property = 0;
+    ULONG Property;
+    DEVICE_REGISTRY_PROPERTY DeviceProperty;
     PVOID Buffer;
+    NTSTATUS Status;
 
     DPRINT("IopGetDeviceProperty() called\n");
     DPRINT("Device name: %wZ\n", &PropertyData->DeviceInstance);
@@ -237,14 +321,20 @@ IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        ExFreePool(DeviceInstance.Buffer);
+        if (DeviceInstance.Buffer != NULL)
+        {
+            ExFreePool(DeviceInstance.Buffer);
+        }
         _SEH2_YIELD(return _SEH2_GetExceptionCode());
     }
     _SEH2_END;
 
     /* Get the device object */
     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
-    ExFreePool(DeviceInstance.Buffer);
+    if (DeviceInstance.Buffer != NULL)
+    {
+        ExFreePool(DeviceInstance.Buffer);
+    }
     if (DeviceObject == NULL)
     {
         return STATUS_NO_SUCH_DEVICE;
@@ -253,14 +343,163 @@ IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
     Buffer = ExAllocatePool(NonPagedPool, BufferSize);
     if (Buffer == NULL)
     {
+        ObDereferenceObject(DeviceObject);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    Status = IoGetDeviceProperty(DeviceObject,
-                                 Property,
-                                 BufferSize,
-                                 Buffer,
-                                 &BufferSize);
+
+    DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
+
+    if (Property == PNP_PROPERTY_POWER_DATA)
+    {
+        if (BufferSize < sizeof(CM_POWER_DATA))
+        {
+            BufferSize = 0;
+            Status = STATUS_BUFFER_TOO_SMALL;
+        }
+        else
+        {
+            DEVICE_CAPABILITIES DeviceCapabilities;
+            PCM_POWER_DATA PowerData;
+            IO_STACK_LOCATION Stack;
+            IO_STATUS_BLOCK IoStatusBlock;
+
+            PowerData = (PCM_POWER_DATA)Buffer;
+            RtlZeroMemory(PowerData, sizeof(CM_POWER_DATA));
+            PowerData->PD_Size = sizeof(CM_POWER_DATA);
+
+            RtlZeroMemory(&DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
+            DeviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES);
+            DeviceCapabilities.Version = 1;
+            DeviceCapabilities.Address = -1;
+            DeviceCapabilities.UINumber = -1;
+
+            Stack.Parameters.DeviceCapabilities.Capabilities = &DeviceCapabilities;
+
+            Status = IopInitiatePnpIrp(DeviceObject,
+                                       &IoStatusBlock,
+                                       IRP_MN_QUERY_CAPABILITIES,
+                                       &Stack);
+            if (NT_SUCCESS(Status))
+            {
+                DPRINT("Got device capabiliities\n");
+
+                PowerData->PD_MostRecentPowerState = PowerDeviceD0; // FIXME
+                if (DeviceCapabilities.DeviceD1)
+                    PowerData->PD_Capabilities |= PDCAP_D1_SUPPORTED;
+                if (DeviceCapabilities.DeviceD2)
+                    PowerData->PD_Capabilities |= PDCAP_D2_SUPPORTED;
+                if (DeviceCapabilities.WakeFromD0)
+                    PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D0_SUPPORTED;
+                if (DeviceCapabilities.WakeFromD1)
+                    PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D1_SUPPORTED;
+                if (DeviceCapabilities.WakeFromD2)
+                    PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D2_SUPPORTED;
+                if (DeviceCapabilities.WakeFromD3)
+                    PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D3_SUPPORTED;
+                if (DeviceCapabilities.WarmEjectSupported)
+                    PowerData->PD_Capabilities |= PDCAP_WARM_EJECT_SUPPORTED;
+                PowerData->PD_D1Latency = DeviceCapabilities.D1Latency;
+                PowerData->PD_D2Latency = DeviceCapabilities.D2Latency;
+                PowerData->PD_D3Latency = DeviceCapabilities.D3Latency;
+                RtlCopyMemory(&PowerData->PD_PowerStateMapping,
+                              &DeviceCapabilities.DeviceState,
+                              sizeof(DeviceCapabilities.DeviceState));
+                PowerData->PD_DeepestSystemWake = DeviceCapabilities.SystemWake;
+            }
+            else
+            {
+                DPRINT("IRP_MN_QUERY_CAPABILITIES failed (Status 0x%08lx)\n", Status);
+
+                PowerData->PD_Capabilities = PDCAP_D0_SUPPORTED | PDCAP_D3_SUPPORTED;
+                PowerData->PD_MostRecentPowerState = PowerDeviceD0;
+            }
+        }
+    }
+    else if (Property == PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE)
+    {
+    }
+    else if (Property == PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT)
+    {
+        if (BufferSize < sizeof(DeviceNode->HardwareRemovalPolicy))
+        {
+            BufferSize = 0;
+            Status = STATUS_BUFFER_TOO_SMALL;
+        }
+        else
+        {
+            BufferSize = sizeof(DeviceNode->HardwareRemovalPolicy);
+            RtlCopyMemory(Buffer,
+                          &DeviceNode->HardwareRemovalPolicy,
+                          BufferSize);
+        }
+    }
+    else
+    {
+        switch (Property)
+        {
+            case PNP_PROPERTY_UI_NUMBER:
+                DeviceProperty = DevicePropertyUINumber;
+                break;
+
+            case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME:
+                DeviceProperty = DevicePropertyPhysicalDeviceObjectName;
+                break;
+
+            case PNP_PROPERTY_BUSTYPEGUID:
+                DeviceProperty = DevicePropertyBusTypeGuid;
+                break;
+
+            case PNP_PROPERTY_LEGACYBUSTYPE:
+                DeviceProperty = DevicePropertyLegacyBusType;
+                break;
+
+            case PNP_PROPERTY_BUSNUMBER:
+                DeviceProperty = DevicePropertyBusNumber;
+                break;
+
+            case PNP_PROPERTY_REMOVAL_POLICY:
+                DeviceProperty = DevicePropertyRemovalPolicy;
+                break;
+
+            case PNP_PROPERTY_ADDRESS:
+                DeviceProperty = DevicePropertyAddress;
+                break;
+
+            case PNP_PROPERTY_ENUMERATOR_NAME:
+                DeviceProperty = DevicePropertyEnumeratorName;
+                break;
+
+            case PNP_PROPERTY_INSTALL_STATE:
+                DeviceProperty = DevicePropertyInstallState;
+                break;
+
+#if (WINVER >= _WIN32_WINNT_WS03)
+            case PNP_PROPERTY_LOCATION_PATHS:
+                break;
+#endif
+
+#if (WINVER >= _WIN32_WINNT_WIN7)
+            case PNP_PROPERTY_CONTAINERID:
+                DeviceProperty = DevicePropertyContainerID;
+                break;
+#endif
+
+            default:
+                BufferSize = 0;
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+        }
+
+        if (Status == STATUS_SUCCESS)
+        {
+            Status = IoGetDeviceProperty(DeviceObject,
+                                         DeviceProperty,
+                                         BufferSize,
+                                         Buffer,
+                                         &BufferSize);
+        }
+    }
 
     ObDereferenceObject(DeviceObject);
 
@@ -268,7 +507,7 @@ IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
     {
         _SEH2_TRY
         {
-            memcpy(PropertyData->Buffer, Buffer, BufferSize);
+            RtlCopyMemory(PropertyData->Buffer, Buffer, BufferSize);
             PropertyData->BufferSize = BufferSize;
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
@@ -314,7 +553,10 @@ IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData)
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        ExFreePool(TargetDeviceInstance.Buffer);
+        if (TargetDeviceInstance.Buffer != NULL)
+        {
+            ExFreePool(TargetDeviceInstance.Buffer);
+        }
         _SEH2_YIELD(return _SEH2_GetExceptionCode());
     }
     _SEH2_END;
@@ -326,13 +568,19 @@ IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData)
                               TRUE))
     {
         DeviceNode = IopRootDeviceNode;
-        ExFreePool(TargetDeviceInstance.Buffer);
+        if (TargetDeviceInstance.Buffer != NULL)
+        {
+            ExFreePool(TargetDeviceInstance.Buffer);
+        }
     }
     else
     {
         /* Get the device object */
         DeviceObject = IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance);
-        ExFreePool(TargetDeviceInstance.Buffer);
+        if (TargetDeviceInstance.Buffer != NULL)
+        {
+            ExFreePool(TargetDeviceInstance.Buffer);
+        }
         if (DeviceObject == NULL)
             return STATUS_NO_SUCH_DEVICE;
 
@@ -469,7 +717,10 @@ IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
 
     Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance);
     if (!NT_SUCCESS(Status))
+    {
         return Status;
+    }
+
     DPRINT("Device name: '%wZ'\n", &DeviceInstance);
 
     _SEH2_TRY
@@ -483,16 +734,24 @@ IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        if (DeviceInstance.Buffer) ExFreePool(DeviceInstance.Buffer);
+        if (DeviceInstance.Buffer != NULL)
+        {
+            ExFreePool(DeviceInstance.Buffer);
+        }
         _SEH2_YIELD(return _SEH2_GetExceptionCode());
     }
     _SEH2_END;
 
     /* Get the device object */
     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
-    ExFreePool(DeviceInstance.Buffer);
+    if (DeviceInstance.Buffer != NULL)
+    {
+        ExFreePool(DeviceInstance.Buffer);
+    }
     if (DeviceObject == NULL)
+    {
         return STATUS_NO_SUCH_DEVICE;
+    }
 
     DeviceNode = IopGetDeviceNode(DeviceObject);
 
@@ -532,6 +791,163 @@ IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
     return Status;
 }
 
+static
+NTSTATUS
+IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData)
+{
+    UNICODE_STRING DeviceInstance;
+    PDEVICE_OBJECT DeviceObject = NULL;
+    IO_STACK_LOCATION Stack;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PDEVICE_RELATIONS DeviceRelations = NULL;
+    PDEVICE_OBJECT ChildDeviceObject;
+    PDEVICE_NODE ChildDeviceNode;
+    ULONG i;
+    ULONG Relations;
+    ULONG BufferSize, RequiredSize;
+    ULONG BufferLeft;
+    PWCHAR Buffer, Ptr;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    DPRINT("IopGetDeviceRelations() called\n");
+    DPRINT("Device name: %wZ\n", &RelationsData->DeviceInstance);
+    DPRINT("Relations: %lu\n", RelationsData->Relations);
+    DPRINT("BufferSize: %lu\n", RelationsData->BufferSize);
+    DPRINT("Buffer: %p\n", RelationsData->Buffer);
+
+    _SEH2_TRY
+    {
+        Relations = RelationsData->Relations;
+        BufferSize = RelationsData->BufferSize;
+        Buffer = RelationsData->Buffer;
+
+        ProbeForWrite(Buffer, BufferSize, sizeof(CHAR));
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    Status = IopCaptureUnicodeString(&DeviceInstance, &RelationsData->DeviceInstance);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status);
+        return Status;
+    }
+
+    /* Get the device object */
+    DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
+    if (DeviceObject == NULL)
+    {
+        DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n");
+        Status = STATUS_NO_SUCH_DEVICE;
+        goto done;
+    }
+
+    switch (Relations)
+    {
+        case PNP_EJECT_RELATIONS:
+            Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
+            break;
+
+        case PNP_REMOVAL_RELATIONS:
+            Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
+            break;
+
+        case PNP_POWER_RELATIONS:
+            Stack.Parameters.QueryDeviceRelations.Type = PowerRelations;
+            break;
+
+        case PNP_BUS_RELATIONS:
+            Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
+            break;
+
+        default:
+            Status = STATUS_INVALID_PARAMETER;
+            goto done;
+    }
+
+    Status = IopInitiatePnpIrp(DeviceObject,
+                               &IoStatusBlock,
+                               IRP_MN_QUERY_DEVICE_RELATIONS,
+                               &Stack);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
+        goto done;
+    }
+
+    DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
+
+    DPRINT("Found %d device relations\n", DeviceRelations->Count);
+
+    _SEH2_TRY
+    {
+        RequiredSize = 0;
+        BufferLeft = BufferSize;
+        Ptr = Buffer;
+
+        for (i = 0; i < DeviceRelations->Count; i++)
+        {
+            ChildDeviceObject = DeviceRelations->Objects[i];
+
+            ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
+            if (ChildDeviceNode)
+            {
+                DPRINT("Device instance: %wZ\n", &ChildDeviceNode->InstancePath);
+                DPRINT("RequiredSize: %hu\n", ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
+
+                if (Ptr != NULL)
+                {
+                    if (BufferLeft < ChildDeviceNode->InstancePath.Length + 2 * sizeof(WCHAR))
+                    {
+                        Status = STATUS_BUFFER_TOO_SMALL;
+                        break;
+                    }
+
+                    RtlCopyMemory(Ptr,
+                                  ChildDeviceNode->InstancePath.Buffer,
+                                  ChildDeviceNode->InstancePath.Length);
+                    Ptr = (PWCHAR)((ULONG_PTR)Ptr + ChildDeviceNode->InstancePath.Length);
+                    *Ptr = UNICODE_NULL;
+                    Ptr = (PWCHAR)((ULONG_PTR)Ptr + sizeof(WCHAR));
+
+                    BufferLeft -= (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
+                }
+
+                RequiredSize += (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
+            }
+        }
+
+        if (Ptr != NULL && BufferLeft >= sizeof(WCHAR))
+            *Ptr = UNICODE_NULL;
+
+        if (RequiredSize > 0)
+            RequiredSize += sizeof(WCHAR);
+
+        DPRINT("BufferSize: %lu  RequiredSize: %lu\n", RelationsData->BufferSize, RequiredSize);
+
+        RelationsData->BufferSize = RequiredSize;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+done:
+    if (DeviceRelations != NULL)
+        ExFreePool(DeviceRelations);
+
+    if (DeviceObject != NULL)
+        ObDereferenceObject(DeviceObject);
+
+    if (DeviceInstance.Buffer != NULL)
+        ExFreePool(DeviceInstance.Buffer);
+
+    return Status;
+}
 
 static NTSTATUS
 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData)
@@ -552,9 +968,14 @@ IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData)
 
     /* Get the device object */
     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
-    ExFreePool(DeviceInstance.Buffer);
+    if (DeviceInstance.Buffer != NULL)
+    {
+        ExFreePool(DeviceInstance.Buffer);
+    }
     if (DeviceObject == NULL)
+    {
         return STATUS_NO_SUCH_DEVICE;
+    }
 
     DeviceNode = IopGetDeviceNode(DeviceObject);
 
@@ -584,15 +1005,22 @@ IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData)
 
     Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance);
     if (!NT_SUCCESS(Status))
+    {
         return Status;
+    }
 
     DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance);
 
     /* Get the device object */
     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
-    ExFreePool(DeviceInstance.Buffer);
+    if (DeviceInstance.Buffer != NULL)
+    {
+        ExFreePool(DeviceInstance.Buffer);
+    }
     if (DeviceObject == NULL)
+    {
         return STATUS_NO_SUCH_DEVICE;
+    }
 
     /* Get the device node */
     DeviceNode = IopGetDeviceNode(DeviceObject);
@@ -734,12 +1162,13 @@ NtGetPlugPlayEvent(IN ULONG Reserved1,
     DPRINT("Waiting for pnp notification event\n");
     Status = KeWaitForSingleObject(&IopPnpNotifyEvent,
                                    UserRequest,
-                                   KernelMode,
+                                   UserMode,
                                    FALSE,
                                    NULL);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(Status) || Status == STATUS_USER_APC)
     {
-        DPRINT1("KeWaitForSingleObject() failed (Status %lx)\n", Status);
+        DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status);
+        ASSERT(Status == STATUS_USER_APC);
         return Status;
     }
 
@@ -756,9 +1185,20 @@ NtGetPlugPlayEvent(IN ULONG Reserved1,
     }
 
     /* Copy event data to the user buffer */
-    memcpy(Buffer,
-           &Entry->Event,
-           Entry->Event.TotalSize);
+    _SEH2_TRY
+    {
+        ProbeForWrite(Buffer,
+                      Entry->Event.TotalSize,
+                      sizeof(UCHAR));
+        RtlCopyMemory(Buffer,
+                      &Entry->Event,
+                      Entry->Event.TotalSize);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
 
     DPRINT("NtGetPlugPlayEvent() done\n");
 
@@ -860,21 +1300,40 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
 
     switch (PlugPlayControlClass)
     {
+//        case PlugPlayControlEnumerateDevice:
+//        case PlugPlayControlRegisterNewDevice:
+//        case PlugPlayControlDeregisterDevice:
+//        case PlugPlayControlInitializeDevice:
+//        case PlugPlayControlStartDevice:
+//        case PlugPlayControlUnlockDevice:
+//        case PlugPlayControlQueryAndRemoveDevice:
+
         case PlugPlayControlUserResponse:
             if (Buffer || BufferLength != 0)
                 return STATUS_INVALID_PARAMETER;
             return IopRemovePlugPlayEvent();
 
+//        case PlugPlayControlGenerateLegacyDevice:
+
+        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;
             return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA)Buffer);
 
+//        case PlugPlayControlDeviceClassAssociation:
+
         case PlugPlayControlGetRelatedDevice:
             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA))
                 return STATUS_INVALID_PARAMETER;
             return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA)Buffer);
 
+//        case PlugPlayControlGetInterfaceDeviceAlias:
+
         case PlugPlayControlDeviceStatus:
             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_STATUS_DATA))
                 return STATUS_INVALID_PARAMETER;
@@ -885,11 +1344,23 @@ NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
                 return STATUS_INVALID_PARAMETER;
             return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer);
 
+        case PlugPlayControlQueryDeviceRelations:
+            if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA))
+                return STATUS_INVALID_PARAMETER;
+            return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)Buffer);
+
+//        case PlugPlayControlTargetDeviceRelation:
+//        case PlugPlayControlQueryConflictList:
+//        case PlugPlayControlRetrieveDock:
+
         case PlugPlayControlResetDevice:
             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA))
                 return STATUS_INVALID_PARAMETER;
             return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer);
 
+//        case PlugPlayControlHaltDevice:
+//        case PlugPlayControlGetBlockedDriverList:
+
         default:
             return STATUS_NOT_IMPLEMENTED;
     }