* COPYRIGHT: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/io/pnpmgr/plugplay.c
* PURPOSE: Plug-and-play interface routines
- * PROGRAMMERS: Eric Kohl <eric.kohl@t-online.de>
+ * PROGRAMMERS: Eric Kohl <eric.kohl@reactos.org>
*/
/* INCLUDES *****************************************************************/
#define NDEBUG
#include <debug.h>
-#if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, IopInitPlugPlayEvents)
-#endif
-
typedef struct _PNP_EVENT_ENTRY
{
LIST_ENTRY ListEntry;
PLUGPLAY_EVENT_BLOCK Event;
} PNP_EVENT_ENTRY, *PPNP_EVENT_ENTRY;
+typedef struct _IOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT
+{
+ PCUNICODE_STRING InstancePath;
+ PDEVICE_OBJECT DeviceObject;
+} IOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT, *PIOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT;
+
/* GLOBALS *******************************************************************/
/* FUNCTIONS *****************************************************************/
-NTSTATUS INIT_FUNCTION
+NTSTATUS
+IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode);
+
+CODE_SEG("INIT")
+NTSTATUS
IopInitPlugPlayEvents(VOID)
{
InitializeListHead(&IopPnpEventQueueHead);
return STATUS_SUCCESS;
}
+NTSTATUS
+IopQueueDeviceChangeEvent(
+ _In_ const GUID *EventGuid,
+ _In_ const GUID *InterfaceClassGuid,
+ _In_ PUNICODE_STRING SymbolicLinkName)
+{
+ PPNP_EVENT_ENTRY EventEntry;
+ UNICODE_STRING Copy;
+ ULONG TotalSize;
+
+ /* Allocate a big enough buffer */
+ Copy.Length = 0;
+ Copy.MaximumLength = SymbolicLinkName->Length + sizeof(UNICODE_NULL);
+ TotalSize =
+ FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, DeviceClass.SymbolicLinkName) +
+ Copy.MaximumLength;
+
+ EventEntry = ExAllocatePool(NonPagedPool,
+ TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
+ if (!EventEntry)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ RtlZeroMemory(EventEntry, TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
+
+ /* Fill the buffer with the event GUID */
+ RtlCopyMemory(&EventEntry->Event.EventGuid, EventGuid, sizeof(GUID));
+ EventEntry->Event.EventCategory = DeviceClassChangeEvent;
+ EventEntry->Event.TotalSize = TotalSize;
+
+ /* Fill the interface class GUID */
+ RtlCopyMemory(&EventEntry->Event.DeviceClass.ClassGuid, InterfaceClassGuid, sizeof(GUID));
+
+ /* Fill the symbolic link name */
+ RtlCopyMemory(&EventEntry->Event.DeviceClass.SymbolicLinkName,
+ SymbolicLinkName->Buffer, SymbolicLinkName->Length);
+ EventEntry->Event.DeviceClass.SymbolicLinkName[SymbolicLinkName->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+ InsertHeadList(&IopPnpEventQueueHead,
+ &EventEntry->ListEntry);
+ KeSetEvent(&IopPnpNotifyEvent,
+ 0,
+ FALSE);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+IopQueueDeviceInstallEvent(
+ _In_ const GUID *EventGuid,
+ _In_ PUNICODE_STRING DeviceId)
+{
+ PPNP_EVENT_ENTRY EventEntry;
+ UNICODE_STRING Copy;
+ ULONG TotalSize;
+
+ /* Allocate a big enough buffer */
+ Copy.Length = 0;
+ Copy.MaximumLength = DeviceId->Length + sizeof(UNICODE_NULL);
+ TotalSize =
+ FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, InstallDevice.DeviceId) +
+ Copy.MaximumLength;
+
+ EventEntry = ExAllocatePool(NonPagedPool,
+ TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
+ if (!EventEntry)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ RtlZeroMemory(EventEntry, TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
+
+ /* Fill the buffer with the event GUID */
+ RtlCopyMemory(&EventEntry->Event.EventGuid, EventGuid, sizeof(GUID));
+ EventEntry->Event.EventCategory = DeviceInstallEvent;
+ EventEntry->Event.TotalSize = TotalSize;
+
+ /* Fill the symbolic link name */
+ RtlCopyMemory(&EventEntry->Event.InstallDevice.DeviceId,
+ DeviceId->Buffer, DeviceId->Length);
+ EventEntry->Event.InstallDevice.DeviceId[DeviceId->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+ InsertHeadList(&IopPnpEventQueueHead, &EventEntry->ListEntry);
+
+ KeSetEvent(&IopPnpNotifyEvent, 0, FALSE);
+
+ return STATUS_SUCCESS;
+}
+
+
NTSTATUS
IopQueueTargetDeviceEvent(const GUID *Guid,
PUNICODE_STRING DeviceIds)
TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
if (!EventEntry)
return STATUS_INSUFFICIENT_RESOURCES;
+ RtlZeroMemory(EventEntry, TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
/* Fill the buffer with the event GUID */
RtlCopyMemory(&EventEntry->Event.EventGuid,
Copy.Buffer = EventEntry->Event.TargetDevice.DeviceIds;
Status = RtlAppendUnicodeStringToString(&Copy, DeviceIds);
if (!NT_SUCCESS(Status))
+ {
+ ExFreePool(EventEntry);
return Status;
+ }
InsertHeadList(&IopPnpEventQueueHead,
&EventEntry->ListEntry);
return STATUS_SUCCESS;
}
-
-/*
- * Remove the current PnP event from the tail of the event queue
- * and signal IopPnpNotifyEvent if there is yet another event in the queue.
- */
-static NTSTATUS
-IopRemovePlugPlayEvent(VOID)
-{
- /* Remove a pnp event entry from the tail of the queue */
- if (!IsListEmpty(&IopPnpEventQueueHead))
- {
- ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead), PNP_EVENT_ENTRY, ListEntry));
- }
-
- /* Signal the next pnp event in the queue */
- if (!IsListEmpty(&IopPnpEventQueueHead))
- {
- KeSetEvent(&IopPnpNotifyEvent,
- 0,
- FALSE);
- }
-
- return STATUS_SUCCESS;
-}
-
-static PDEVICE_OBJECT
-IopTraverseDeviceNode(PDEVICE_NODE Node, PUNICODE_STRING DeviceInstance)
+NTSTATUS
+IopFindDeviceInstanceTraverse(
+ _In_ PDEVICE_NODE DeviceNode,
+ _Inout_ PVOID Context)
{
- PDEVICE_OBJECT DeviceObject;
- PDEVICE_NODE ChildNode;
+ PIOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT DeviceInstanceContext = Context;
- if (RtlEqualUnicodeString(&Node->InstancePath,
- DeviceInstance, TRUE))
+ if (RtlEqualUnicodeString(&DeviceNode->InstancePath,
+ DeviceInstanceContext->InstancePath, TRUE))
{
- ObReferenceObject(Node->PhysicalDeviceObject);
- return Node->PhysicalDeviceObject;
- }
+ ObReferenceObject(DeviceNode->PhysicalDeviceObject);
+ DeviceInstanceContext->DeviceObject = DeviceNode->PhysicalDeviceObject;
- /* Traversal of all children nodes */
- for (ChildNode = Node->Child;
- ChildNode != NULL;
- ChildNode = ChildNode->Sibling)
- {
- DeviceObject = IopTraverseDeviceNode(ChildNode, DeviceInstance);
- if (DeviceObject != NULL)
- {
- return DeviceObject;
- }
+ /* Stop enumeration */
+ return STATUS_UNSUCCESSFUL;
}
- return NULL;
+ return STATUS_SUCCESS;
}
-
PDEVICE_OBJECT
IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
{
+ DEVICETREE_TRAVERSE_CONTEXT Context;
+ IOP_FIND_DEVICE_INSTANCE_TRAVERSE_CONTEXT DeviceInstanceContext;
+
if (IopRootDeviceNode == NULL)
return NULL;
return NULL;
}
- return IopTraverseDeviceNode(IopRootDeviceNode, DeviceInstance);
-
+ /* Traverse the device tree to find the matching device node */
+ DeviceInstanceContext.InstancePath = DeviceInstance;
+ DeviceInstanceContext.DeviceObject = NULL;
+ IopInitDeviceTreeTraverseContext(&Context,
+ IopRootDeviceNode,
+ IopFindDeviceInstanceTraverse,
+ &DeviceInstanceContext);
+ (void)IopTraverseDeviceTree(&Context);
+
+ /* In case of error or instance not found, this will still be NULL from above. */
+ return DeviceInstanceContext.DeviceObject;
}
static NTSTATUS
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
if (Name.Buffer)
+ {
ExFreePool(Name.Buffer);
+ }
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
return Status;
}
+
+static
+NTSTATUS
+PiControlInitializeDevice(
+ _In_ PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA ControlData)
+{
+ UNICODE_STRING DeviceInstance;
+ PDEVICE_OBJECT DeviceObject;
+ PDEVICE_NODE DeviceNode;
+ NTSTATUS Status = STATUS_SUCCESS;
+ HANDLE InstanceKey;
+
+ DPRINT("PiControlInitializeDevice(%p)\n", ControlData);
+
+ Status = IopCaptureUnicodeString(&DeviceInstance, &ControlData->DeviceInstance);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ DPRINT("Device: %wZ\n", &DeviceInstance);
+
+ /* Leave, if the device already exists */
+ DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
+ if (DeviceObject != NULL)
+ {
+ DPRINT1("Device %wZ already exists!\n", &DeviceInstance);
+ ObDereferenceObject(DeviceObject);
+ Status = STATUS_SUCCESS;
+ goto done;
+ }
+
+ DPRINT("Device %wZ does not exist!\n", &DeviceInstance);
+
+ /* Create a device node for the device instance */
+ Status = PnpRootCreateDeviceObject(&DeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("IoCreateDevice() failed (Status 0x%08lx)\n", Status);
+ goto done;
+ }
+
+ /* Allocate a new device node */
+ DeviceNode = PipAllocateDeviceNode(DeviceObject);
+ if (DeviceNode == NULL)
+ {
+ DPRINT1("Failed to allocate a device node!\n");
+ IoDeleteDevice(DeviceObject);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
+
+ // Set the device instance of the device node
+ // NOTE: a NULL-terminated string is required for PnpRootRegisterDevice
+ Status = RtlDuplicateUnicodeString(
+ RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
+ &DeviceInstance,
+ &DeviceNode->InstancePath);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlDuplicateUnicodeString() failed (Status 0x%08lx)\n", Status);
+ IopFreeDeviceNode(DeviceNode);
+ IoDeleteDevice(DeviceObject);
+ goto done;
+ }
+
+ DeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
+ DeviceNode->Flags |= DNF_MADEUP | DNF_IDS_QUERIED | DNF_ENUMERATED;
+ PiSetDevNodeState(DeviceNode, DeviceNodeInitialized);
+
+ Status = IopCreateDeviceKeyPath(&DeviceInstance, REG_OPTION_NON_VOLATILE, &InstanceKey);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
+ IopFreeDeviceNode(DeviceNode);
+ IoDeleteDevice(DeviceObject);
+ goto done;
+ }
+
+ /* Write the resource information to the registry */
+ IopSetDeviceInstanceData(InstanceKey, DeviceNode);
+
+ // Finish the root device registration
+ PnpRootRegisterDevice(DeviceObject);
+
+ /* Insert as a root enumerated device node */
+ PiInsertDevNode(DeviceNode, IopRootDeviceNode);
+
+ /* Report the device to the user-mode pnp manager */
+ IopQueueDeviceInstallEvent(&GUID_DEVICE_ENUMERATED, &DeviceNode->InstancePath);
+
+ ZwClose(InstanceKey);
+done:
+ ExFreePool(DeviceInstance.Buffer);
+
+ return Status;
+}
+
+
+/*
+ * Remove the current PnP event from the tail of the event queue
+ * and signal IopPnpNotifyEvent if there is yet another event in the queue.
+ */
+static
+NTSTATUS
+IopRemovePlugPlayEvent(
+ _In_ PPLUGPLAY_CONTROL_USER_RESPONSE_DATA ResponseData)
+{
+ /* Remove a pnp event entry from the tail of the queue */
+ if (!IsListEmpty(&IopPnpEventQueueHead))
+ {
+ ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead), PNP_EVENT_ENTRY, ListEntry));
+ }
+
+ /* Signal the next pnp event in the queue */
+ if (!IsListEmpty(&IopPnpEventQueueHead))
+ {
+ KeSetEvent(&IopPnpNotifyEvent,
+ 0,
+ FALSE);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+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);
}
_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;
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)
+ {
+ UNIMPLEMENTED;
+ BufferSize = 0;
+ Status = STATUS_NOT_IMPLEMENTED;
+ }
+ 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:
+ UNIMPLEMENTED;
+ BufferSize = 0;
+ Status = STATUS_NOT_IMPLEMENTED;
+ 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);
{
_SEH2_TRY
{
- memcpy(PropertyData->Buffer, Buffer, BufferSize);
+ RtlCopyMemory(PropertyData->Buffer, Buffer, BufferSize);
PropertyData->BufferSize = BufferSize;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- ExFreePool(TargetDeviceInstance.Buffer);
+ if (TargetDeviceInstance.Buffer != NULL)
+ {
+ ExFreePool(TargetDeviceInstance.Buffer);
+ }
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
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;
return Status;
}
+static
+BOOLEAN
+PiIsDevNodeStarted(
+ _In_ PDEVICE_NODE DeviceNode)
+{
+ return (DeviceNode->State == DeviceNodeStartPending ||
+ DeviceNode->State == DeviceNodeStartCompletion ||
+ DeviceNode->State == DeviceNodeStartPostWork ||
+ DeviceNode->State == DeviceNodeStarted ||
+ DeviceNode->State == DeviceNodeQueryStopped ||
+ DeviceNode->State == DeviceNodeEnumeratePending ||
+ DeviceNode->State == DeviceNodeEnumerateCompletion ||
+ DeviceNode->State == DeviceNodeStopped ||
+ DeviceNode->State == DeviceNodeRestartCompletion);
+}
+
static ULONG
IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode)
{
- ULONG Output = 0;
+ ULONG Output = DN_NT_ENUMERATOR | DN_NT_DRIVER;
if (DeviceNode->Parent == IopRootDeviceNode)
Output |= DN_ROOT_ENUMERATED;
- if (DeviceNode->Flags & DNF_ADDED)
+ // FIXME: review for deleted and removed states
+ if (DeviceNode->State >= DeviceNodeDriversAdded)
Output |= DN_DRIVER_LOADED;
- /* FIXME: DN_ENUM_LOADED */
-
- if (DeviceNode->Flags & DNF_STARTED)
+ if (PiIsDevNodeStarted(DeviceNode))
Output |= DN_STARTED;
- /* FIXME: Manual */
-
- if (!(DeviceNode->Flags & DNF_PROCESSED))
- Output |= DN_NEED_TO_ENUM;
+ if (DeviceNode->UserFlags & DNUF_WILL_BE_REMOVED)
+ Output |= DN_WILL_BE_REMOVED;
- /* DN_NOT_FIRST_TIME is 9x only */
+ if (DeviceNode->Flags & DNF_HAS_PROBLEM)
+ Output |= DN_HAS_PROBLEM;
- /* FIXME: DN_HARDWARE_ENUM */
+ if (DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM)
+ Output |= DN_PRIVATE_PROBLEM;
- /* DN_LIAR and DN_HAS_MARK are 9x only */
+ if (DeviceNode->Flags & DNF_DRIVER_BLOCKED)
+ Output |= DN_DRIVER_BLOCKED;
- if (DeviceNode->Problem != 0)
- Output |= DN_HAS_PROBLEM;
+ if (DeviceNode->Flags & DNF_CHILD_WITH_INVALID_ID)
+ Output |= DN_CHILD_WITH_INVALID_ID;
- /* FIXME: DN_FILTERED */
+ if (DeviceNode->Flags & DNF_HAS_PRIVATE_PROBLEM)
+ Output |= DN_PRIVATE_PROBLEM;
if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
Output |= DN_LEGACY_DRIVER;
if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE))
Output |= DN_DISABLEABLE;
- /* FIXME: Implement the rest */
-
- Output |= DN_NT_ENUMERATOR | DN_NT_DRIVER;
-
return Output;
}
Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance);
if (!NT_SUCCESS(Status))
+ {
return Status;
+ }
+
DPRINT("Device name: '%wZ'\n", &DeviceInstance);
_SEH2_TRY
}
_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);
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)
/* 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);
return Status;
}
-
-static NTSTATUS
-IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData)
+static
+NTSTATUS
+PiControlSyncDeviceAction(
+ _In_ PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceData,
+ _In_ PLUGPLAY_CONTROL_CLASS ControlClass)
{
PDEVICE_OBJECT DeviceObject;
- PDEVICE_NODE DeviceNode;
- NTSTATUS Status = STATUS_SUCCESS;
+ NTSTATUS Status;
UNICODE_STRING DeviceInstance;
- Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance);
+ ASSERT(ControlClass == PlugPlayControlEnumerateDevice ||
+ ControlClass == PlugPlayControlStartDevice ||
+ ControlClass == PlugPlayControlResetDevice);
+
+ Status = IopCaptureUnicodeString(&DeviceInstance, &DeviceData->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);
-
- ASSERT(DeviceNode->Flags & DNF_ENUMERATED);
- ASSERT(DeviceNode->Flags & DNF_PROCESSED);
+ DEVICE_ACTION Action;
- /* Check if there's already a driver loaded for this device */
- if (DeviceNode->Flags & DNF_ADDED)
+ switch (ControlClass)
{
-#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;
- }
+ case PlugPlayControlEnumerateDevice:
+ Action = PiActionEnumDeviceTree;
+ break;
+ case PlugPlayControlStartDevice:
+ Action = PiActionStartDevice;
+ break;
+ case PlugPlayControlResetDevice:
+ Action = PiActionResetDevice;
+ break;
+ default:
+ UNREACHABLE;
+ break;
}
- else
- {
- /* FIXME: What if the device really is disabled? */
- DeviceNode->Flags &= ~DNF_DISABLED;
- DeviceNode->Problem = 0;
- /* Load service data from the registry */
- Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
+ Status = PiPerformSyncDeviceAction(DeviceObject, Action);
- 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);
+
+ return Status;
+}
+
+static
+NTSTATUS
+PiControlQueryRemoveDevice(
+ _In_ PPLUGPLAY_CONTROL_QUERY_REMOVE_DATA ControlData)
+{
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ UNICODE_STRING DeviceInstance;
+
+ Status = IopCaptureUnicodeString(&DeviceInstance, &ControlData->DeviceInstance);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
+ if (DeviceInstance.Buffer != NULL)
+ {
+ ExFreePool(DeviceInstance.Buffer);
+ }
+ if (DeviceObject == NULL)
+ {
+ return STATUS_NO_SUCH_DEVICE;
}
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+
ObDereferenceObject(DeviceObject);
return Status;
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;
}
}
/* 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");
switch (PlugPlayControlClass)
{
+ case PlugPlayControlEnumerateDevice:
+ if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA))
+ return STATUS_INVALID_PARAMETER;
+ // the Flags field is not used anyway
+ return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer,
+ PlugPlayControlClass);
+
+// case PlugPlayControlRegisterNewDevice:
+// case PlugPlayControlDeregisterDevice:
+
+ case PlugPlayControlInitializeDevice:
+ if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA))
+ return STATUS_INVALID_PARAMETER;
+ return PiControlInitializeDevice((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer);
+
+ case PlugPlayControlStartDevice:
+ case PlugPlayControlResetDevice:
+ if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA))
+ return STATUS_INVALID_PARAMETER;
+ return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA)Buffer,
+ PlugPlayControlClass);
+
+// case PlugPlayControlUnlockDevice:
+ case PlugPlayControlQueryAndRemoveDevice:
+ if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_QUERY_REMOVE_DATA))
+ return STATUS_INVALID_PARAMETER;
+ return PiControlQueryRemoveDevice((PPLUGPLAY_CONTROL_QUERY_REMOVE_DATA)Buffer);
+
case PlugPlayControlUserResponse:
- if (Buffer || BufferLength != 0)
+ if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_USER_RESPONSE_DATA))
return STATUS_INVALID_PARAMETER;
- return IopRemovePlugPlayEvent();
+ return IopRemovePlugPlayEvent((PPLUGPLAY_CONTROL_USER_RESPONSE_DATA)Buffer);
+
+// 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;
return STATUS_INVALID_PARAMETER;
return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer);
- case PlugPlayControlResetDevice:
- if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA))
+ case PlugPlayControlQueryDeviceRelations:
+ if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA))
return STATUS_INVALID_PARAMETER;
- return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer);
+ return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)Buffer);
+
+// case PlugPlayControlTargetDeviceRelation:
+// case PlugPlayControlQueryConflictList:
+// case PlugPlayControlRetrieveDock:
+// case PlugPlayControlHaltDevice:
+// case PlugPlayControlGetBlockedDriverList:
default:
return STATUS_NOT_IMPLEMENTED;