2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/plugplay.c
5 * PURPOSE: Plug-and-play interface routines
6 * PROGRAMMERS: Eric Kohl <eric.kohl@t-online.de>
9 /* INCLUDES *****************************************************************/
15 #if defined (ALLOC_PRAGMA)
16 #pragma alloc_text(INIT, IopInitPlugPlayEvents)
19 typedef struct _PNP_EVENT_ENTRY
22 PLUGPLAY_EVENT_BLOCK Event
;
23 } PNP_EVENT_ENTRY
, *PPNP_EVENT_ENTRY
;
26 /* GLOBALS *******************************************************************/
28 static LIST_ENTRY IopPnpEventQueueHead
;
29 static KEVENT IopPnpNotifyEvent
;
31 /* FUNCTIONS *****************************************************************/
33 NTSTATUS INIT_FUNCTION
34 IopInitPlugPlayEvents(VOID
)
36 InitializeListHead(&IopPnpEventQueueHead
);
38 KeInitializeEvent(&IopPnpNotifyEvent
,
42 return STATUS_SUCCESS
;
46 IopQueueTargetDeviceEvent(const GUID
*Guid
,
47 PUNICODE_STRING DeviceIds
)
49 PPNP_EVENT_ENTRY EventEntry
;
56 /* Allocate a big enough buffer */
58 Copy
.MaximumLength
= DeviceIds
->Length
+ sizeof(UNICODE_NULL
);
60 FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK
, TargetDevice
.DeviceIds
) +
63 EventEntry
= ExAllocatePool(NonPagedPool
,
64 TotalSize
+ FIELD_OFFSET(PNP_EVENT_ENTRY
, Event
));
66 return STATUS_INSUFFICIENT_RESOURCES
;
68 /* Fill the buffer with the event GUID */
69 RtlCopyMemory(&EventEntry
->Event
.EventGuid
,
72 EventEntry
->Event
.EventCategory
= TargetDeviceChangeEvent
;
73 EventEntry
->Event
.TotalSize
= TotalSize
;
75 /* Fill the device id */
76 Copy
.Buffer
= EventEntry
->Event
.TargetDevice
.DeviceIds
;
77 Status
= RtlAppendUnicodeStringToString(&Copy
, DeviceIds
);
78 if (!NT_SUCCESS(Status
))
81 InsertHeadList(&IopPnpEventQueueHead
,
82 &EventEntry
->ListEntry
);
83 KeSetEvent(&IopPnpNotifyEvent
,
87 return STATUS_SUCCESS
;
92 * Remove the current PnP event from the tail of the event queue
93 * and signal IopPnpNotifyEvent if there is yet another event in the queue.
96 IopRemovePlugPlayEvent(VOID
)
98 /* Remove a pnp event entry from the tail of the queue */
99 if (!IsListEmpty(&IopPnpEventQueueHead
))
101 ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead
), PNP_EVENT_ENTRY
, ListEntry
));
104 /* Signal the next pnp event in the queue */
105 if (!IsListEmpty(&IopPnpEventQueueHead
))
107 KeSetEvent(&IopPnpNotifyEvent
,
112 return STATUS_SUCCESS
;
115 static PDEVICE_OBJECT
116 IopTraverseDeviceNode(PDEVICE_NODE Node
, PUNICODE_STRING DeviceInstance
)
118 PDEVICE_OBJECT DeviceObject
;
119 PDEVICE_NODE ChildNode
;
121 if (RtlEqualUnicodeString(&Node
->InstancePath
,
122 DeviceInstance
, TRUE
))
124 ObReferenceObject(Node
->PhysicalDeviceObject
);
125 return Node
->PhysicalDeviceObject
;
128 /* Traversal of all children nodes */
129 for (ChildNode
= Node
->Child
;
131 ChildNode
= ChildNode
->Sibling
)
133 DeviceObject
= IopTraverseDeviceNode(ChildNode
, DeviceInstance
);
134 if (DeviceObject
!= NULL
)
144 static PDEVICE_OBJECT
145 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
)
147 if (IopRootDeviceNode
== NULL
)
150 if (DeviceInstance
== NULL
||
151 DeviceInstance
->Length
== 0)
153 if (IopRootDeviceNode
->PhysicalDeviceObject
)
155 ObReferenceObject(IopRootDeviceNode
->PhysicalDeviceObject
);
156 return IopRootDeviceNode
->PhysicalDeviceObject
;
162 return IopTraverseDeviceNode(IopRootDeviceNode
, DeviceInstance
);
167 IopCaptureUnicodeString(PUNICODE_STRING DstName
, PUNICODE_STRING SrcName
)
169 NTSTATUS Status
= STATUS_SUCCESS
;
175 Name
.Length
= SrcName
->Length
;
176 Name
.MaximumLength
= SrcName
->MaximumLength
;
177 if (Name
.Length
> Name
.MaximumLength
)
179 Status
= STATUS_INVALID_PARAMETER
;
183 if (Name
.MaximumLength
)
185 ProbeForRead(SrcName
->Buffer
,
188 Name
.Buffer
= ExAllocatePool(NonPagedPool
, Name
.MaximumLength
);
189 if (Name
.Buffer
== NULL
)
191 Status
= STATUS_INSUFFICIENT_RESOURCES
;
195 memcpy(Name
.Buffer
, SrcName
->Buffer
, Name
.MaximumLength
);
200 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
203 ExFreePool(Name
.Buffer
);
204 Status
= _SEH2_GetExceptionCode();
212 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData
)
214 PDEVICE_OBJECT DeviceObject
= NULL
;
216 UNICODE_STRING DeviceInstance
;
221 DPRINT("IopGetDeviceProperty() called\n");
222 DPRINT("Device name: %wZ\n", &PropertyData
->DeviceInstance
);
224 Status
= IopCaptureUnicodeString(&DeviceInstance
, &PropertyData
->DeviceInstance
);
225 if (!NT_SUCCESS(Status
))
232 Property
= PropertyData
->Property
;
233 BufferSize
= PropertyData
->BufferSize
;
234 ProbeForWrite(PropertyData
->Buffer
,
238 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
240 ExFreePool(DeviceInstance
.Buffer
);
241 _SEH2_YIELD(return _SEH2_GetExceptionCode());
245 /* Get the device object */
246 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
247 ExFreePool(DeviceInstance
.Buffer
);
248 if (DeviceObject
== NULL
)
250 return STATUS_NO_SUCH_DEVICE
;
253 Buffer
= ExAllocatePool(NonPagedPool
, BufferSize
);
256 return STATUS_INSUFFICIENT_RESOURCES
;
259 Status
= IoGetDeviceProperty(DeviceObject
,
265 ObDereferenceObject(DeviceObject
);
267 if (NT_SUCCESS(Status
))
271 memcpy(PropertyData
->Buffer
, Buffer
, BufferSize
);
272 PropertyData
->BufferSize
= BufferSize
;
274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
276 Status
= _SEH2_GetExceptionCode();
287 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData
)
289 UNICODE_STRING RootDeviceName
;
290 PDEVICE_OBJECT DeviceObject
= NULL
;
291 PDEVICE_NODE DeviceNode
= NULL
;
292 PDEVICE_NODE RelatedDeviceNode
;
293 UNICODE_STRING TargetDeviceInstance
;
294 NTSTATUS Status
= STATUS_SUCCESS
;
296 ULONG MaximumLength
= 0;
298 DPRINT("IopGetRelatedDevice() called\n");
299 DPRINT("Device name: %wZ\n", &RelatedDeviceData
->TargetDeviceInstance
);
301 Status
= IopCaptureUnicodeString(&TargetDeviceInstance
, &RelatedDeviceData
->TargetDeviceInstance
);
302 if (!NT_SUCCESS(Status
))
309 Relation
= RelatedDeviceData
->Relation
;
310 MaximumLength
= RelatedDeviceData
->RelatedDeviceInstanceLength
;
311 ProbeForWrite(RelatedDeviceData
->RelatedDeviceInstance
,
315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
317 ExFreePool(TargetDeviceInstance
.Buffer
);
318 _SEH2_YIELD(return _SEH2_GetExceptionCode());
322 RtlInitUnicodeString(&RootDeviceName
,
324 if (RtlEqualUnicodeString(&TargetDeviceInstance
,
328 DeviceNode
= IopRootDeviceNode
;
329 ExFreePool(TargetDeviceInstance
.Buffer
);
333 /* Get the device object */
334 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance
);
335 ExFreePool(TargetDeviceInstance
.Buffer
);
336 if (DeviceObject
== NULL
)
337 return STATUS_NO_SUCH_DEVICE
;
339 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
344 case PNP_GET_PARENT_DEVICE
:
345 RelatedDeviceNode
= DeviceNode
->Parent
;
348 case PNP_GET_CHILD_DEVICE
:
349 RelatedDeviceNode
= DeviceNode
->Child
;
352 case PNP_GET_SIBLING_DEVICE
:
353 RelatedDeviceNode
= DeviceNode
->Sibling
;
357 if (DeviceObject
!= NULL
)
359 ObDereferenceObject(DeviceObject
);
362 return STATUS_INVALID_PARAMETER
;
365 if (RelatedDeviceNode
== NULL
)
369 ObDereferenceObject(DeviceObject
);
372 return STATUS_NO_SUCH_DEVICE
;
375 if (RelatedDeviceNode
->InstancePath
.Length
> MaximumLength
)
379 ObDereferenceObject(DeviceObject
);
382 return STATUS_BUFFER_TOO_SMALL
;
385 /* Copy related device instance name */
388 RtlCopyMemory(RelatedDeviceData
->RelatedDeviceInstance
,
389 RelatedDeviceNode
->InstancePath
.Buffer
,
390 RelatedDeviceNode
->InstancePath
.Length
);
391 RelatedDeviceData
->RelatedDeviceInstanceLength
= RelatedDeviceNode
->InstancePath
.Length
;
393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
395 Status
= _SEH2_GetExceptionCode();
399 if (DeviceObject
!= NULL
)
401 ObDereferenceObject(DeviceObject
);
404 DPRINT("IopGetRelatedDevice() done\n");
411 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData
)
413 PDEVICE_OBJECT DeviceObject
;
414 PDEVICE_NODE DeviceNode
;
416 ULONG DeviceStatus
= 0;
417 ULONG DeviceProblem
= 0;
418 UNICODE_STRING DeviceInstance
;
421 DPRINT("IopDeviceStatus() called\n");
423 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StatusData
->DeviceInstance
);
424 if (!NT_SUCCESS(Status
))
426 DPRINT("Device name: '%wZ'\n", &DeviceInstance
);
430 Operation
= StatusData
->Operation
;
431 if (Operation
== PNP_SET_DEVICE_STATUS
)
433 DeviceStatus
= StatusData
->DeviceStatus
;
434 DeviceProblem
= StatusData
->DeviceProblem
;
437 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
439 if (DeviceInstance
.Buffer
) ExFreePool(DeviceInstance
.Buffer
);
440 _SEH2_YIELD(return _SEH2_GetExceptionCode());
444 /* Get the device object */
445 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
446 ExFreePool(DeviceInstance
.Buffer
);
447 if (DeviceObject
== NULL
)
448 return STATUS_NO_SUCH_DEVICE
;
450 DeviceNode
= IopGetDeviceNode(DeviceObject
);
454 case PNP_GET_DEVICE_STATUS
:
455 DPRINT("Get status data\n");
456 DeviceStatus
= DeviceNode
->Flags
;
457 DeviceProblem
= DeviceNode
->Problem
;
460 case PNP_SET_DEVICE_STATUS
:
461 DPRINT("Set status data\n");
462 DeviceNode
->Flags
= DeviceStatus
;
463 DeviceNode
->Problem
= DeviceProblem
;
466 case PNP_CLEAR_DEVICE_STATUS
:
467 DPRINT1("FIXME: Clear status data!\n");
471 ObDereferenceObject(DeviceObject
);
473 if (Operation
== PNP_GET_DEVICE_STATUS
)
477 StatusData
->DeviceStatus
= DeviceStatus
;
478 StatusData
->DeviceProblem
= DeviceProblem
;
480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
482 Status
= _SEH2_GetExceptionCode();
492 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData
)
494 PDEVICE_OBJECT DeviceObject
;
495 PDEVICE_NODE DeviceNode
;
496 UNICODE_STRING DeviceInstance
;
497 NTSTATUS Status
= STATUS_SUCCESS
;
499 DPRINT("IopGetDeviceDepth() called\n");
500 DPRINT("Device name: %wZ\n", &DepthData
->DeviceInstance
);
502 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DepthData
->DeviceInstance
);
503 if (!NT_SUCCESS(Status
))
508 /* Get the device object */
509 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
510 ExFreePool(DeviceInstance
.Buffer
);
511 if (DeviceObject
== NULL
)
512 return STATUS_NO_SUCH_DEVICE
;
514 DeviceNode
= IopGetDeviceNode(DeviceObject
);
518 DepthData
->Depth
= DeviceNode
->Level
;
520 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
522 Status
= _SEH2_GetExceptionCode();
526 ObDereferenceObject(DeviceObject
);
533 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData
)
535 PDEVICE_OBJECT DeviceObject
;
536 PDEVICE_NODE DeviceNode
;
537 NTSTATUS Status
= STATUS_SUCCESS
;
538 UNICODE_STRING DeviceInstance
;
540 Status
= IopCaptureUnicodeString(&DeviceInstance
, &ResetDeviceData
->DeviceInstance
);
541 if (!NT_SUCCESS(Status
))
544 DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance
);
546 /* Get the device object */
547 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
548 ExFreePool(DeviceInstance
.Buffer
);
549 if (DeviceObject
== NULL
)
550 return STATUS_NO_SUCH_DEVICE
;
552 /* Get the device node */
553 DeviceNode
= IopGetDeviceNode(DeviceObject
);
555 /* Check if an FDO has been added to the stack */
556 if (DeviceNode
->Flags
& DNF_ADDED
)
558 /* Remove the device node */
559 Status
= IopRemoveDevice(DeviceNode
);
560 if (!NT_SUCCESS(Status
))
562 DPRINT1("WARNING: Ignoring failed IopRemoveDevice() for %wZ (likely a driver bug)\n", &DeviceNode
->InstancePath
);
565 /* Invalidate device relations for the parent to reenumerate the device */
566 Status
= IoSynchronousInvalidateDeviceRelations(DeviceNode
->Parent
->PhysicalDeviceObject
, BusRelations
);
568 DPRINT1("Reset PDO with FDO present: 0x%x\n", Status
);
572 /* FIXME: We might clear some important flags */
573 ASSERT(DeviceNode
->Flags
& DNF_ENUMERATED
);
574 ASSERT(DeviceNode
->Flags
& DNF_PROCESSED
);
575 DeviceNode
->Flags
= DNF_ENUMERATED
| DNF_PROCESSED
;
577 /* Load service data from the registry */
578 Status
= IopActionConfigureChildServices(DeviceNode
, DeviceNode
->Parent
);
580 if (NT_SUCCESS(Status
))
582 /* Start the service and begin PnP initialization of the device again */
583 Status
= IopActionInitChildServices(DeviceNode
, DeviceNode
->Parent
);
586 DPRINT1("Reset PDO with no FDO present: 0x%x\n", Status
);
589 ObDereferenceObject(DeviceObject
);
594 /* PUBLIC FUNCTIONS **********************************************************/
597 * Plug and Play event structure used by NtGetPlugPlayEvent.
600 * Can be one of the following values:
601 * GUID_HWPROFILE_QUERY_CHANGE
602 * GUID_HWPROFILE_CHANGE_CANCELLED
603 * GUID_HWPROFILE_CHANGE_COMPLETE
604 * GUID_TARGET_DEVICE_QUERY_REMOVE
605 * GUID_TARGET_DEVICE_REMOVE_CANCELLED
606 * GUID_TARGET_DEVICE_REMOVE_COMPLETE
607 * GUID_PNP_CUSTOM_NOTIFICATION
608 * GUID_PNP_POWER_NOTIFICATION
609 * GUID_DEVICE_* (see above)
612 * Type of the event that happened.
621 * Size of the event block including the device IDs and other
622 * per category specific fields.
628 * Returns one Plug & Play event from a global queue.
633 * Always set to zero.
636 * The buffer that will be filled with the event information on
637 * successful return from the function.
640 * Size of the buffer pointed by the Buffer parameter. If the
641 * buffer size is not large enough to hold the whole event
642 * information, error STATUS_BUFFER_TOO_SMALL is returned and
643 * the buffer remains untouched.
646 * STATUS_PRIVILEGE_NOT_HELD
647 * STATUS_BUFFER_TOO_SMALL
651 * This function isn't multi-thread safe!
657 NtGetPlugPlayEvent(IN ULONG Reserved1
,
659 OUT PPLUGPLAY_EVENT_BLOCK Buffer
,
662 PPNP_EVENT_ENTRY Entry
;
665 DPRINT("NtGetPlugPlayEvent() called\n");
667 /* Function can only be called from user-mode */
668 if (KeGetPreviousMode() == KernelMode
)
670 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
671 return STATUS_ACCESS_DENIED
;
674 /* Check for Tcb privilege */
675 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
678 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
679 return STATUS_PRIVILEGE_NOT_HELD
;
682 /* Wait for a PnP event */
683 DPRINT("Waiting for pnp notification event\n");
684 Status
= KeWaitForSingleObject(&IopPnpNotifyEvent
,
689 if (!NT_SUCCESS(Status
))
691 DPRINT1("KeWaitForSingleObject() failed (Status %lx)\n", Status
);
695 /* Get entry from the tail of the queue */
696 Entry
= CONTAINING_RECORD(IopPnpEventQueueHead
.Blink
,
700 /* Check the buffer size */
701 if (BufferSize
< Entry
->Event
.TotalSize
)
703 DPRINT1("Buffer is too small for the pnp-event\n");
704 return STATUS_BUFFER_TOO_SMALL
;
707 /* Copy event data to the user buffer */
710 Entry
->Event
.TotalSize
);
712 DPRINT("NtGetPlugPlayEvent() done\n");
714 return STATUS_SUCCESS
;
720 * A function for doing various Plug & Play operations from user mode.
723 * PlugPlayControlClass
724 * 0x00 Reenumerate device tree
726 * Buffer points to UNICODE_STRING decribing the instance
727 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
728 * more information about instance paths see !devnode command
729 * in kernel debugger or look at "Inside Windows 2000" book,
730 * chapter "Driver Loading, Initialization, and Installation".
732 * 0x01 Register new device
733 * 0x02 Deregister device
734 * 0x03 Initialize device
736 * 0x06 Query and remove device
739 * Called after processing the message from NtGetPlugPlayEvent.
741 * 0x08 Generate legacy device
742 * 0x09 Get interface device list
743 * 0x0A Get property data
744 * 0x0B Device class association (Registration)
745 * 0x0C Get related device
746 * 0x0D Get device interface alias
747 * 0x0E Get/set/clear device status
748 * 0x0F Get device depth
749 * 0x10 Query device relations
750 * 0x11 Query target device relation
751 * 0x12 Query conflict list
752 * 0x13 Retrieve dock data
755 * 0x16 Get blocked driver data
758 * The buffer contains information that is specific to each control
759 * code. The buffer is read-only.
762 * Size of the buffer pointed by the Buffer parameter. If the
763 * buffer size specifies incorrect value for specified control
764 * code, error ??? is returned.
767 * STATUS_PRIVILEGE_NOT_HELD
775 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass
,
777 IN ULONG BufferLength
)
779 DPRINT("NtPlugPlayControl(%lu %p %lu) called\n",
780 PlugPlayControlClass
, Buffer
, BufferLength
);
782 /* Function can only be called from user-mode */
783 if (KeGetPreviousMode() == KernelMode
)
785 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
786 return STATUS_ACCESS_DENIED
;
789 /* Check for Tcb privilege */
790 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
793 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
794 return STATUS_PRIVILEGE_NOT_HELD
;
797 /* Probe the buffer */
800 ProbeForWrite(Buffer
,
804 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
806 _SEH2_YIELD(return _SEH2_GetExceptionCode());
810 switch (PlugPlayControlClass
)
812 case PlugPlayControlUserResponse
:
813 if (Buffer
|| BufferLength
!= 0)
814 return STATUS_INVALID_PARAMETER
;
815 return IopRemovePlugPlayEvent();
817 case PlugPlayControlProperty
:
818 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA
))
819 return STATUS_INVALID_PARAMETER
;
820 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA
)Buffer
);
822 case PlugPlayControlGetRelatedDevice
:
823 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
))
824 return STATUS_INVALID_PARAMETER
;
825 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA
)Buffer
);
827 case PlugPlayControlDeviceStatus
:
828 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_STATUS_DATA
))
829 return STATUS_INVALID_PARAMETER
;
830 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA
)Buffer
);
832 case PlugPlayControlGetDeviceDepth
:
833 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEPTH_DATA
))
834 return STATUS_INVALID_PARAMETER
;
835 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA
)Buffer
);
837 case PlugPlayControlResetDevice
:
838 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA
))
839 return STATUS_INVALID_PARAMETER
;
840 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA
)Buffer
);
843 return STATUS_NOT_IMPLEMENTED
;
846 return STATUS_NOT_IMPLEMENTED
;