2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/plugplay.c
5 * PURPOSE: Plug-and-play interface routines
7 * PROGRAMMERS: Eric Kohl <eric.kohl@t-online.de>
10 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, IopInitPlugPlayEvents)
21 typedef struct _PNP_EVENT_ENTRY
24 PLUGPLAY_EVENT_BLOCK Event
;
25 } PNP_EVENT_ENTRY
, *PPNP_EVENT_ENTRY
;
28 /* GLOBALS *******************************************************************/
30 static LIST_ENTRY IopPnpEventQueueHead
;
31 static KEVENT IopPnpNotifyEvent
;
33 /* FUNCTIONS *****************************************************************/
35 NTSTATUS INIT_FUNCTION
36 IopInitPlugPlayEvents(VOID
)
38 InitializeListHead(&IopPnpEventQueueHead
);
40 KeInitializeEvent(&IopPnpNotifyEvent
,
44 return STATUS_SUCCESS
;
49 IopQueueTargetDeviceEvent(const GUID
*Guid
,
50 PUNICODE_STRING DeviceIds
)
52 PPNP_EVENT_ENTRY EventEntry
;
56 FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK
, TargetDevice
.DeviceIds
) +
57 DeviceIds
->MaximumLength
;
59 EventEntry
= ExAllocatePool(NonPagedPool
,
60 TotalSize
+ FIELD_OFFSET(PNP_EVENT_ENTRY
, Event
));
61 if (EventEntry
== NULL
)
62 return STATUS_INSUFFICIENT_RESOURCES
;
64 memcpy(&EventEntry
->Event
.EventGuid
,
67 EventEntry
->Event
.EventCategory
= TargetDeviceChangeEvent
;
68 EventEntry
->Event
.TotalSize
= TotalSize
;
70 memcpy(&EventEntry
->Event
.TargetDevice
.DeviceIds
,
72 DeviceIds
->MaximumLength
);
74 InsertHeadList(&IopPnpEventQueueHead
,
75 &EventEntry
->ListEntry
);
76 KeSetEvent(&IopPnpNotifyEvent
,
80 return STATUS_SUCCESS
;
85 * Remove the current PnP event from the tail of the event queue
86 * and signal IopPnpNotifyEvent if there is yet another event in the queue.
89 IopRemovePlugPlayEvent(VOID
)
91 /* Remove a pnp event entry from the tail of the queue */
92 if (!IsListEmpty(&IopPnpEventQueueHead
))
94 ExFreePool(RemoveTailList(&IopPnpEventQueueHead
));
97 /* Signal the next pnp event in the queue */
98 if (!IsListEmpty(&IopPnpEventQueueHead
))
100 KeSetEvent(&IopPnpNotifyEvent
,
105 return STATUS_SUCCESS
;
110 * Plug and Play event structure used by NtGetPlugPlayEvent.
113 * Can be one of the following values:
114 * GUID_HWPROFILE_QUERY_CHANGE
115 * GUID_HWPROFILE_CHANGE_CANCELLED
116 * GUID_HWPROFILE_CHANGE_COMPLETE
117 * GUID_TARGET_DEVICE_QUERY_REMOVE
118 * GUID_TARGET_DEVICE_REMOVE_CANCELLED
119 * GUID_TARGET_DEVICE_REMOVE_COMPLETE
120 * GUID_PNP_CUSTOM_NOTIFICATION
121 * GUID_PNP_POWER_NOTIFICATION
122 * GUID_DEVICE_* (see above)
125 * Type of the event that happened.
134 * Size of the event block including the device IDs and other
135 * per category specific fields.
140 * Returns one Plug & Play event from a global queue.
145 * Always set to zero.
148 * The buffer that will be filled with the event information on
149 * successful return from the function.
152 * Size of the buffer pointed by the Buffer parameter. If the
153 * buffer size is not large enough to hold the whole event
154 * information, error STATUS_BUFFER_TOO_SMALL is returned and
155 * the buffer remains untouched.
158 * STATUS_PRIVILEGE_NOT_HELD
159 * STATUS_BUFFER_TOO_SMALL
163 * This function isn't multi-thread safe!
168 NtGetPlugPlayEvent(IN ULONG Reserved1
,
170 OUT PPLUGPLAY_EVENT_BLOCK Buffer
,
173 PPNP_EVENT_ENTRY Entry
;
176 DPRINT("NtGetPlugPlayEvent() called\n");
178 /* Function can only be called from user-mode */
179 if (KeGetPreviousMode() == KernelMode
)
181 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
182 return STATUS_ACCESS_DENIED
;
185 /* Check for Tcb privilege */
186 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
189 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
190 return STATUS_PRIVILEGE_NOT_HELD
;
193 /* Wait for a PnP event */
194 DPRINT("Waiting for pnp notification event\n");
195 Status
= KeWaitForSingleObject(&IopPnpNotifyEvent
,
200 if (!NT_SUCCESS(Status
))
202 DPRINT1("KeWaitForSingleObject() failed (Status %lx)\n", Status
);
206 /* Get entry from the tail of the queue */
207 Entry
= CONTAINING_RECORD(IopPnpEventQueueHead
.Blink
,
211 /* Check the buffer size */
212 if (BufferSize
< Entry
->Event
.TotalSize
)
214 DPRINT1("Buffer is too small for the pnp-event\n");
215 return STATUS_BUFFER_TOO_SMALL
;
218 /* Copy event data to the user buffer */
221 Entry
->Event
.TotalSize
);
223 DPRINT("NtGetPlugPlayEvent() done\n");
225 return STATUS_SUCCESS
;
229 static PDEVICE_OBJECT
230 IopTraverseDeviceNode(PDEVICE_NODE Node
, PUNICODE_STRING DeviceInstance
)
232 PDEVICE_OBJECT DeviceObject
;
233 PDEVICE_NODE ChildNode
;
235 if (RtlEqualUnicodeString(&Node
->InstancePath
,
236 DeviceInstance
, TRUE
))
238 ObReferenceObject(Node
->PhysicalDeviceObject
);
239 return Node
->PhysicalDeviceObject
;
242 /* Traversal of all children nodes */
243 for (ChildNode
= Node
->Child
;
245 ChildNode
= ChildNode
->NextSibling
)
247 DeviceObject
= IopTraverseDeviceNode(ChildNode
, DeviceInstance
);
248 if (DeviceObject
!= NULL
)
258 static PDEVICE_OBJECT
259 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
)
262 OBJECT_ATTRIBUTES ObjectAttributes
;
263 UNICODE_STRING KeyName
, ValueName
;
264 LPWSTR KeyNameBuffer
;
265 HANDLE InstanceKeyHandle
;
266 HANDLE ControlKeyHandle
;
268 PKEY_VALUE_PARTIAL_INFORMATION ValueInformation
;
269 ULONG ValueInformationLength
;
270 PDEVICE_OBJECT DeviceObject
= NULL
;
272 DPRINT("IopGetDeviceObjectFromDeviceInstance(%wZ) called\n", DeviceInstance
);
274 KeyNameBuffer
= ExAllocatePool(PagedPool
,
275 (49 * sizeof(WCHAR
)) + DeviceInstance
->Length
);
276 if (KeyNameBuffer
== NULL
)
278 DPRINT1("Failed to allocate key name buffer!\n");
282 wcscpy(KeyNameBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
283 wcscat(KeyNameBuffer
, DeviceInstance
->Buffer
);
285 RtlInitUnicodeString(&KeyName
,
287 InitializeObjectAttributes(&ObjectAttributes
,
289 OBJ_CASE_INSENSITIVE
,
293 Status
= ZwOpenKey(&InstanceKeyHandle
,
296 ExFreePool(KeyNameBuffer
);
297 if (!NT_SUCCESS(Status
))
299 DPRINT1("Failed to open the instance key (Status %lx)\n", Status
);
303 /* Open the 'Control' subkey */
304 RtlInitUnicodeString(&KeyName
,
306 InitializeObjectAttributes(&ObjectAttributes
,
308 OBJ_CASE_INSENSITIVE
,
312 Status
= ZwOpenKey(&ControlKeyHandle
,
315 ZwClose(InstanceKeyHandle
);
316 if (!NT_SUCCESS(Status
))
318 DPRINT1("Failed to open the 'Control' key (Status %lx)\n", Status
);
322 /* Query the 'DeviceReference' value */
323 RtlInitUnicodeString(&ValueName
,
325 ValueInformationLength
= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
,
326 Data
[0]) + sizeof(ULONG
);
327 ValueInformation
= ExAllocatePool(PagedPool
, ValueInformationLength
);
328 if (ValueInformation
== NULL
)
330 DPRINT1("Failed to allocate the name information buffer!\n");
331 ZwClose(ControlKeyHandle
);
335 Status
= ZwQueryValueKey(ControlKeyHandle
,
337 KeyValuePartialInformation
,
339 ValueInformationLength
,
340 &ValueInformationLength
);
341 ZwClose(ControlKeyHandle
);
342 if (!NT_SUCCESS(Status
))
344 DPRINT1("Failed to query the 'DeviceReference' value (Status %lx)\n", Status
);
348 /* Check the device object */
349 RtlCopyMemory(&DeviceObject
,
350 ValueInformation
->Data
,
351 sizeof(PDEVICE_OBJECT
));
353 DPRINT("DeviceObject: %p\n", DeviceObject
);
355 if (DeviceObject
->Type
!= IO_TYPE_DEVICE
||
356 DeviceObject
->DeviceObjectExtension
== NULL
||
357 DeviceObject
->DeviceObjectExtension
->DeviceNode
== NULL
||
358 !RtlEqualUnicodeString(&DeviceObject
->DeviceObjectExtension
->DeviceNode
->InstancePath
,
359 DeviceInstance
, TRUE
))
361 DPRINT1("Invalid object type!\n");
365 DPRINT("Instance path: %wZ\n", &DeviceObject
->DeviceObjectExtension
->DeviceNode
->InstancePath
);
367 ObReferenceObject(DeviceObject
);
369 DPRINT("IopGetDeviceObjectFromDeviceInstance() done\n");
374 if (IopRootDeviceNode
== NULL
)
377 if (DeviceInstance
== NULL
||
378 DeviceInstance
->Length
== 0
381 if (IopRootDeviceNode
->PhysicalDeviceObject
)
383 ObReferenceObject(IopRootDeviceNode
->PhysicalDeviceObject
);
384 return IopRootDeviceNode
->PhysicalDeviceObject
;
390 return IopTraverseDeviceNode(IopRootDeviceNode
, DeviceInstance
);
395 IopCaptureUnicodeString(PUNICODE_STRING DstName
, PUNICODE_STRING SrcName
)
397 NTSTATUS Status
= STATUS_SUCCESS
;
403 Name
.Length
= SrcName
->Length
;
404 Name
.MaximumLength
= SrcName
->MaximumLength
;
405 if (Name
.Length
> Name
.MaximumLength
)
407 Status
= STATUS_INVALID_PARAMETER
;
410 if (Name
.MaximumLength
)
412 ProbeForRead(SrcName
->Buffer
,
415 Name
.Buffer
= ExAllocatePool(NonPagedPool
, Name
.MaximumLength
);
416 if (Name
.Buffer
== NULL
)
418 Status
= STATUS_INSUFFICIENT_RESOURCES
;
421 memcpy(Name
.Buffer
, SrcName
->Buffer
, Name
.MaximumLength
);
427 Status
= _SEH_GetExceptionCode();
431 if (!NT_SUCCESS(Status
) && Name
.Buffer
)
433 ExFreePool(Name
.Buffer
);
439 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData
)
441 PDEVICE_OBJECT DeviceObject
= NULL
;
442 NTSTATUS Status
= STATUS_SUCCESS
;
443 UNICODE_STRING DeviceInstance
;
448 DPRINT("IopGetDeviceProperty() called\n");
449 DPRINT("Device name: %wZ\n", &PropertyData
->DeviceInstance
);
451 Status
= IopCaptureUnicodeString(&DeviceInstance
, &PropertyData
->DeviceInstance
);
452 if (!NT_SUCCESS(Status
))
459 Property
= PropertyData
->Property
;
460 BufferSize
= PropertyData
->BufferSize
;
461 ProbeForWrite(PropertyData
->Buffer
,
467 Status
= _SEH_GetExceptionCode();
471 if (!NT_SUCCESS(Status
))
473 ExFreePool(DeviceInstance
.Buffer
);
477 /* Get the device object */
478 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&PropertyData
->DeviceInstance
);
479 ExFreePool(DeviceInstance
.Buffer
);
480 if (DeviceObject
== NULL
)
482 return STATUS_NO_SUCH_DEVICE
;
485 Buffer
= ExAllocatePool(NonPagedPool
, BufferSize
);
488 return STATUS_INSUFFICIENT_RESOURCES
;
492 Status
= IoGetDeviceProperty(DeviceObject
,
498 ObDereferenceObject(DeviceObject
);
500 if (NT_SUCCESS(Status
))
504 memcpy(Buffer
, PropertyData
->Buffer
, BufferSize
);
505 PropertyData
->BufferSize
= BufferSize
;
509 Status
= _SEH_GetExceptionCode();
519 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData
)
521 UNICODE_STRING RootDeviceName
;
522 PDEVICE_OBJECT DeviceObject
= NULL
;
523 PDEVICE_NODE DeviceNode
= NULL
;
524 PDEVICE_NODE RelatedDeviceNode
;
525 UNICODE_STRING TargetDeviceInstance
;
526 NTSTATUS Status
= STATUS_SUCCESS
;
528 ULONG MaximumLength
= 0;
530 DPRINT("IopGetRelatedDevice() called\n");
531 DPRINT("Device name: %wZ\n", &RelatedDeviceData
->TargetDeviceInstance
);
533 Status
= IopCaptureUnicodeString(&TargetDeviceInstance
, &RelatedDeviceData
->TargetDeviceInstance
);
534 if (!NT_SUCCESS(Status
))
541 Relation
= RelatedDeviceData
->Relation
;
542 MaximumLength
= RelatedDeviceData
->RelatedDeviceInstance
.MaximumLength
;
543 ProbeForWrite(RelatedDeviceData
->RelatedDeviceInstance
.Buffer
,
549 Status
= _SEH_GetExceptionCode();
553 if (!NT_SUCCESS(Status
))
555 ExFreePool(TargetDeviceInstance
.Buffer
);
559 RtlInitUnicodeString(&RootDeviceName
,
561 if (RtlEqualUnicodeString(&TargetDeviceInstance
,
565 DeviceNode
= IopRootDeviceNode
;
566 ExFreePool(TargetDeviceInstance
.Buffer
);
570 /* Get the device object */
571 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance
);
572 ExFreePool(TargetDeviceInstance
.Buffer
);
573 if (DeviceObject
== NULL
)
574 return STATUS_NO_SUCH_DEVICE
;
576 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
581 case PNP_GET_PARENT_DEVICE
:
582 RelatedDeviceNode
= DeviceNode
->Parent
;
585 case PNP_GET_CHILD_DEVICE
:
586 RelatedDeviceNode
= DeviceNode
->Child
;
589 case PNP_GET_SIBLING_DEVICE
:
590 RelatedDeviceNode
= DeviceNode
->NextSibling
;
594 if (DeviceObject
!= NULL
)
596 ObDereferenceObject(DeviceObject
);
599 return STATUS_INVALID_PARAMETER
;
602 if (RelatedDeviceNode
== NULL
)
606 ObDereferenceObject(DeviceObject
);
609 return STATUS_NO_SUCH_DEVICE
;
612 if (RelatedDeviceNode
->InstancePath
.Length
> MaximumLength
)
616 ObDereferenceObject(DeviceObject
);
619 return STATUS_BUFFER_TOO_SMALL
;
622 /* Copy related device instance name */
625 RtlCopyMemory(RelatedDeviceData
->RelatedDeviceInstance
.Buffer
,
626 RelatedDeviceNode
->InstancePath
.Buffer
,
627 RelatedDeviceNode
->InstancePath
.Length
);
628 RelatedDeviceData
->RelatedDeviceInstance
.Length
= RelatedDeviceNode
->InstancePath
.Length
;
632 Status
= _SEH_GetExceptionCode();
636 if (DeviceObject
!= NULL
)
638 ObDereferenceObject(DeviceObject
);
641 DPRINT("IopGetRelatedDevice() done\n");
648 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData
)
650 PDEVICE_OBJECT DeviceObject
;
651 PDEVICE_NODE DeviceNode
;
653 ULONG DeviceStatus
= 0;
654 ULONG DeviceProblem
= 0;
655 UNICODE_STRING DeviceInstance
;
656 NTSTATUS Status
= STATUS_SUCCESS
;
658 DPRINT("IopDeviceStatus() called\n");
659 DPRINT("Device name: %wZ\n", &StatusData
->DeviceInstance
);
661 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StatusData
->DeviceInstance
);
662 if (!NT_SUCCESS(Status
))
669 Operation
= StatusData
->Operation
;
670 if (Operation
== PNP_SET_DEVICE_STATUS
)
672 DeviceStatus
= StatusData
->DeviceStatus
;
673 DeviceProblem
= StatusData
->DeviceProblem
;
678 Status
= _SEH_GetExceptionCode();
682 if (!NT_SUCCESS(Status
))
684 if (DeviceInstance
.Buffer
)
686 ExFreePool(DeviceInstance
.Buffer
);
691 /* Get the device object */
692 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&StatusData
->DeviceInstance
);
693 ExFreePool(DeviceInstance
.Buffer
);
694 if (DeviceObject
== NULL
)
695 return STATUS_NO_SUCH_DEVICE
;
697 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
701 case PNP_GET_DEVICE_STATUS
:
702 DPRINT("Get status data\n");
703 DeviceStatus
= DeviceNode
->Flags
;
704 DeviceProblem
= DeviceNode
->Problem
;
707 case PNP_SET_DEVICE_STATUS
:
708 DPRINT("Set status data\n");
709 DeviceNode
->Flags
= DeviceStatus
;
710 DeviceNode
->Problem
= DeviceProblem
;
713 case PNP_CLEAR_DEVICE_STATUS
:
714 DPRINT1("FIXME: Clear status data!\n");
718 ObDereferenceObject(DeviceObject
);
720 if (Operation
== PNP_GET_DEVICE_STATUS
)
724 StatusData
->DeviceStatus
= DeviceStatus
;
725 StatusData
->DeviceProblem
= DeviceProblem
;
729 Status
= _SEH_GetExceptionCode();
739 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData
)
741 PDEVICE_OBJECT DeviceObject
;
742 PDEVICE_NODE DeviceNode
;
743 UNICODE_STRING DeviceInstance
;
744 NTSTATUS Status
= STATUS_SUCCESS
;
746 DPRINT("IopGetDeviceDepth() called\n");
747 DPRINT("Device name: %wZ\n", &DepthData
->DeviceInstance
);
749 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DepthData
->DeviceInstance
);
750 if (!NT_SUCCESS(Status
))
755 /* Get the device object */
756 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DepthData
->DeviceInstance
);
757 ExFreePool(DeviceInstance
.Buffer
);
758 if (DeviceObject
== NULL
)
759 return STATUS_NO_SUCH_DEVICE
;
761 DeviceNode
= IopGetDeviceNode(DeviceObject
);
763 DepthData
->Depth
= DeviceNode
->Level
;
765 ObDereferenceObject(DeviceObject
);
769 DepthData
->Depth
= DeviceNode
->Level
;
773 Status
= _SEH_GetExceptionCode();
782 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData
)
784 PDEVICE_OBJECT DeviceObject
;
785 PDEVICE_NODE DeviceNode
;
786 NTSTATUS Status
= STATUS_SUCCESS
;
787 UNICODE_STRING DeviceInstance
;
789 DPRINT("IopResetDevice() called\n");
790 DPRINT("Device name: %wZ\n", &ResetDeviceData
->DeviceInstance
);
792 Status
= IopCaptureUnicodeString(&DeviceInstance
, &ResetDeviceData
->DeviceInstance
);
793 if (!NT_SUCCESS(Status
))
798 /* Get the device object */
799 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
800 ExFreePool(DeviceInstance
.Buffer
);
801 if (DeviceObject
== NULL
)
802 return STATUS_NO_SUCH_DEVICE
;
804 DeviceNode
= IopGetDeviceNode(DeviceObject
);
806 /* FIXME: we should stop the device, before starting it again */
808 /* Start the device */
809 IopDeviceNodeClearFlag(DeviceNode
, DNF_DISABLED
);
810 Status
= IopActionConfigureChildServices(DeviceNode
, DeviceNode
->Parent
);
812 if (NT_SUCCESS(Status
))
813 Status
= IopActionInitChildServices(DeviceNode
, DeviceNode
->Parent
, FALSE
);
815 ObDereferenceObject(DeviceObject
);
824 * A function for doing various Plug & Play operations from user mode.
827 * PlugPlayControlClass
828 * 0x00 Reenumerate device tree
830 * Buffer points to UNICODE_STRING decribing the instance
831 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
832 * more information about instance paths see !devnode command
833 * in kernel debugger or look at "Inside Windows 2000" book,
834 * chapter "Driver Loading, Initialization, and Installation".
836 * 0x01 Register new device
837 * 0x02 Deregister device
838 * 0x03 Initialize device
840 * 0x06 Query and remove device
843 * Called after processing the message from NtGetPlugPlayEvent.
845 * 0x08 Generate legacy device
846 * 0x09 Get interface device list
847 * 0x0A Get property data
848 * 0x0B Device class association (Registration)
849 * 0x0C Get related device
850 * 0x0D Get device interface alias
851 * 0x0E Get/set/clear device status
852 * 0x0F Get device depth
853 * 0x10 Query device relations
854 * 0x11 Query target device relation
855 * 0x12 Query conflict list
856 * 0x13 Retrieve dock data
859 * 0x16 Get blocked driver data
862 * The buffer contains information that is specific to each control
863 * code. The buffer is read-only.
866 * Size of the buffer pointed by the Buffer parameter. If the
867 * buffer size specifies incorrect value for specified control
868 * code, error ??? is returned.
871 * STATUS_PRIVILEGE_NOT_HELD
878 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass
,
880 IN ULONG BufferLength
)
882 NTSTATUS Status
= STATUS_SUCCESS
;
884 DPRINT("NtPlugPlayControl(%lu %p %lu) called\n",
885 PlugPlayControlClass
, Buffer
, BufferLength
);
887 /* Function can only be called from user-mode */
888 if (KeGetPreviousMode() == KernelMode
)
890 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
891 return STATUS_ACCESS_DENIED
;
894 /* Check for Tcb privilege */
895 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
898 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
899 return STATUS_PRIVILEGE_NOT_HELD
;
902 /* Probe the buffer */
905 ProbeForWrite(Buffer
,
911 Status
= _SEH_GetExceptionCode();
915 if (!NT_SUCCESS(Status
))
920 switch (PlugPlayControlClass
)
922 case PlugPlayControlUserResponse
:
923 if (Buffer
|| BufferLength
!= 0)
924 return STATUS_INVALID_PARAMETER
;
925 return IopRemovePlugPlayEvent();
927 case PlugPlayControlProperty
:
928 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA
))
929 return STATUS_INVALID_PARAMETER
;
930 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA
)Buffer
);
932 case PlugPlayControlGetRelatedDevice
:
933 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
))
934 return STATUS_INVALID_PARAMETER
;
935 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA
)Buffer
);
937 case PlugPlayControlDeviceStatus
:
938 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_STATUS_DATA
))
939 return STATUS_INVALID_PARAMETER
;
940 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA
)Buffer
);
942 case PlugPlayControlGetDeviceDepth
:
943 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEPTH_DATA
))
944 return STATUS_INVALID_PARAMETER
;
945 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA
)Buffer
);
947 case PlugPlayControlResetDevice
:
948 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA
))
949 return STATUS_INVALID_PARAMETER
;
950 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA
)Buffer
);
953 return STATUS_NOT_IMPLEMENTED
;
956 return STATUS_NOT_IMPLEMENTED
;