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
)
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
;
170 volatile UNICODE_STRING Name
;
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
)
204 ExFreePool(Name
.Buffer
);
206 Status
= _SEH2_GetExceptionCode();
214 IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList
)
217 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList
;
218 UNICODE_STRING DeviceInstance
;
219 PDEVICE_OBJECT DeviceObject
= NULL
;
221 PZZWSTR SymbolicLinkList
= NULL
, LinkList
;
226 RtlCopyMemory(&StackList
, DeviceList
, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
));
228 ProbeForRead(StackList
.FilterGuid
, sizeof(GUID
), sizeof(UCHAR
));
229 RtlCopyMemory(&FilterGuid
, StackList
.FilterGuid
, sizeof(GUID
));
231 if (StackList
.Buffer
!= NULL
&& StackList
.BufferSize
!= 0)
233 ProbeForWrite(StackList
.Buffer
, StackList
.BufferSize
, sizeof(UCHAR
));
236 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
238 _SEH2_YIELD(return _SEH2_GetExceptionCode());
242 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StackList
.DeviceInstance
);
243 if (NT_SUCCESS(Status
))
245 /* Get the device object */
246 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
247 ExFreePool(DeviceInstance
.Buffer
);
250 Status
= IoGetDeviceInterfaces(&FilterGuid
, DeviceObject
, StackList
.Flags
, &SymbolicLinkList
);
251 ObDereferenceObject(DeviceObject
);
253 if (!NT_SUCCESS(Status
))
259 LinkList
= SymbolicLinkList
;
260 while (*SymbolicLinkList
!= UNICODE_NULL
)
262 SymbolicLinkList
+= wcslen(SymbolicLinkList
) + (sizeof(UNICODE_NULL
) / sizeof(WCHAR
));
264 TotalLength
= ((SymbolicLinkList
- LinkList
+ 1) * sizeof(WCHAR
));
268 if (StackList
.Buffer
!= NULL
&&
269 StackList
.BufferSize
>= TotalLength
)
271 // We've already probed the buffer for writing above.
272 RtlCopyMemory(StackList
.Buffer
, LinkList
, TotalLength
);
275 DeviceList
->BufferSize
= TotalLength
;
277 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
279 ExFreePool(LinkList
);
280 _SEH2_YIELD(return _SEH2_GetExceptionCode());
284 ExFreePool(LinkList
);
285 return STATUS_SUCCESS
;
289 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData
)
291 PDEVICE_OBJECT DeviceObject
= NULL
;
293 UNICODE_STRING DeviceInstance
;
298 DPRINT("IopGetDeviceProperty() called\n");
299 DPRINT("Device name: %wZ\n", &PropertyData
->DeviceInstance
);
301 Status
= IopCaptureUnicodeString(&DeviceInstance
, &PropertyData
->DeviceInstance
);
302 if (!NT_SUCCESS(Status
))
309 Property
= PropertyData
->Property
;
310 BufferSize
= PropertyData
->BufferSize
;
311 ProbeForWrite(PropertyData
->Buffer
,
315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
317 ExFreePool(DeviceInstance
.Buffer
);
318 _SEH2_YIELD(return _SEH2_GetExceptionCode());
322 /* Get the device object */
323 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
324 ExFreePool(DeviceInstance
.Buffer
);
325 if (DeviceObject
== NULL
)
327 return STATUS_NO_SUCH_DEVICE
;
330 Buffer
= ExAllocatePool(NonPagedPool
, BufferSize
);
333 return STATUS_INSUFFICIENT_RESOURCES
;
336 Status
= IoGetDeviceProperty(DeviceObject
,
342 ObDereferenceObject(DeviceObject
);
344 if (NT_SUCCESS(Status
))
348 memcpy(PropertyData
->Buffer
, Buffer
, BufferSize
);
349 PropertyData
->BufferSize
= BufferSize
;
351 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
353 Status
= _SEH2_GetExceptionCode();
364 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData
)
366 UNICODE_STRING RootDeviceName
;
367 PDEVICE_OBJECT DeviceObject
= NULL
;
368 PDEVICE_NODE DeviceNode
= NULL
;
369 PDEVICE_NODE RelatedDeviceNode
;
370 UNICODE_STRING TargetDeviceInstance
;
371 NTSTATUS Status
= STATUS_SUCCESS
;
373 ULONG MaximumLength
= 0;
375 DPRINT("IopGetRelatedDevice() called\n");
376 DPRINT("Device name: %wZ\n", &RelatedDeviceData
->TargetDeviceInstance
);
378 Status
= IopCaptureUnicodeString(&TargetDeviceInstance
, &RelatedDeviceData
->TargetDeviceInstance
);
379 if (!NT_SUCCESS(Status
))
386 Relation
= RelatedDeviceData
->Relation
;
387 MaximumLength
= RelatedDeviceData
->RelatedDeviceInstanceLength
;
388 ProbeForWrite(RelatedDeviceData
->RelatedDeviceInstance
,
392 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
394 ExFreePool(TargetDeviceInstance
.Buffer
);
395 _SEH2_YIELD(return _SEH2_GetExceptionCode());
399 RtlInitUnicodeString(&RootDeviceName
,
401 if (RtlEqualUnicodeString(&TargetDeviceInstance
,
405 DeviceNode
= IopRootDeviceNode
;
406 ExFreePool(TargetDeviceInstance
.Buffer
);
410 /* Get the device object */
411 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance
);
412 ExFreePool(TargetDeviceInstance
.Buffer
);
413 if (DeviceObject
== NULL
)
414 return STATUS_NO_SUCH_DEVICE
;
416 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
421 case PNP_GET_PARENT_DEVICE
:
422 RelatedDeviceNode
= DeviceNode
->Parent
;
425 case PNP_GET_CHILD_DEVICE
:
426 RelatedDeviceNode
= DeviceNode
->Child
;
429 case PNP_GET_SIBLING_DEVICE
:
430 RelatedDeviceNode
= DeviceNode
->Sibling
;
434 if (DeviceObject
!= NULL
)
436 ObDereferenceObject(DeviceObject
);
439 return STATUS_INVALID_PARAMETER
;
442 if (RelatedDeviceNode
== NULL
)
446 ObDereferenceObject(DeviceObject
);
449 return STATUS_NO_SUCH_DEVICE
;
452 if (RelatedDeviceNode
->InstancePath
.Length
> MaximumLength
)
456 ObDereferenceObject(DeviceObject
);
459 return STATUS_BUFFER_TOO_SMALL
;
462 /* Copy related device instance name */
465 RtlCopyMemory(RelatedDeviceData
->RelatedDeviceInstance
,
466 RelatedDeviceNode
->InstancePath
.Buffer
,
467 RelatedDeviceNode
->InstancePath
.Length
);
468 RelatedDeviceData
->RelatedDeviceInstanceLength
= RelatedDeviceNode
->InstancePath
.Length
;
470 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
472 Status
= _SEH2_GetExceptionCode();
476 if (DeviceObject
!= NULL
)
478 ObDereferenceObject(DeviceObject
);
481 DPRINT("IopGetRelatedDevice() done\n");
487 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode
)
491 if (DeviceNode
->Parent
== IopRootDeviceNode
)
492 Output
|= DN_ROOT_ENUMERATED
;
494 if (DeviceNode
->Flags
& DNF_ADDED
)
495 Output
|= DN_DRIVER_LOADED
;
497 /* FIXME: DN_ENUM_LOADED */
499 if (DeviceNode
->Flags
& DNF_STARTED
)
500 Output
|= DN_STARTED
;
504 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
505 Output
|= DN_NEED_TO_ENUM
;
507 /* DN_NOT_FIRST_TIME is 9x only */
509 /* FIXME: DN_HARDWARE_ENUM */
511 /* DN_LIAR and DN_HAS_MARK are 9x only */
513 if (DeviceNode
->Problem
!= 0)
514 Output
|= DN_HAS_PROBLEM
;
516 /* FIXME: DN_FILTERED */
518 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
519 Output
|= DN_LEGACY_DRIVER
;
521 if (DeviceNode
->UserFlags
& DNUF_DONT_SHOW_IN_UI
)
522 Output
|= DN_NO_SHOW_IN_DM
;
524 if (!(DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
))
525 Output
|= DN_DISABLEABLE
;
527 /* FIXME: Implement the rest */
529 Output
|= DN_NT_ENUMERATOR
| DN_NT_DRIVER
;
535 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData
)
537 PDEVICE_OBJECT DeviceObject
;
538 PDEVICE_NODE DeviceNode
;
540 ULONG DeviceStatus
= 0;
541 ULONG DeviceProblem
= 0;
542 UNICODE_STRING DeviceInstance
;
545 DPRINT("IopDeviceStatus() called\n");
547 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StatusData
->DeviceInstance
);
548 if (!NT_SUCCESS(Status
))
552 DPRINT("Device name: '%wZ'\n", &DeviceInstance
);
556 Operation
= StatusData
->Operation
;
557 if (Operation
== PNP_SET_DEVICE_STATUS
)
559 DeviceStatus
= StatusData
->DeviceStatus
;
560 DeviceProblem
= StatusData
->DeviceProblem
;
563 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
565 ExFreePool(DeviceInstance
.Buffer
);
566 _SEH2_YIELD(return _SEH2_GetExceptionCode());
570 /* Get the device object */
571 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
572 ExFreePool(DeviceInstance
.Buffer
);
573 if (DeviceObject
== NULL
)
575 return STATUS_NO_SUCH_DEVICE
;
578 DeviceNode
= IopGetDeviceNode(DeviceObject
);
582 case PNP_GET_DEVICE_STATUS
:
583 DPRINT("Get status data\n");
584 DeviceStatus
= IopGetDeviceNodeStatus(DeviceNode
);
585 DeviceProblem
= DeviceNode
->Problem
;
588 case PNP_SET_DEVICE_STATUS
:
589 DPRINT1("Set status data is NOT SUPPORTED\n");
592 case PNP_CLEAR_DEVICE_STATUS
:
593 DPRINT1("FIXME: Clear status data!\n");
597 ObDereferenceObject(DeviceObject
);
599 if (Operation
== PNP_GET_DEVICE_STATUS
)
603 StatusData
->DeviceStatus
= DeviceStatus
;
604 StatusData
->DeviceProblem
= DeviceProblem
;
606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
608 Status
= _SEH2_GetExceptionCode();
618 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData
)
620 PDEVICE_OBJECT DeviceObject
;
621 PDEVICE_NODE DeviceNode
;
622 UNICODE_STRING DeviceInstance
;
623 NTSTATUS Status
= STATUS_SUCCESS
;
625 DPRINT("IopGetDeviceDepth() called\n");
626 DPRINT("Device name: %wZ\n", &DepthData
->DeviceInstance
);
628 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DepthData
->DeviceInstance
);
629 if (!NT_SUCCESS(Status
))
634 /* Get the device object */
635 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
636 ExFreePool(DeviceInstance
.Buffer
);
637 if (DeviceObject
== NULL
)
639 return STATUS_NO_SUCH_DEVICE
;
642 DeviceNode
= IopGetDeviceNode(DeviceObject
);
646 DepthData
->Depth
= DeviceNode
->Level
;
648 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
650 Status
= _SEH2_GetExceptionCode();
654 ObDereferenceObject(DeviceObject
);
661 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData
)
663 PDEVICE_OBJECT DeviceObject
;
664 PDEVICE_NODE DeviceNode
;
665 NTSTATUS Status
= STATUS_SUCCESS
;
666 UNICODE_STRING DeviceInstance
;
668 Status
= IopCaptureUnicodeString(&DeviceInstance
, &ResetDeviceData
->DeviceInstance
);
669 if (!NT_SUCCESS(Status
))
673 DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance
);
675 /* Get the device object */
676 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
677 ExFreePool(DeviceInstance
.Buffer
);
678 if (DeviceObject
== NULL
)
680 return STATUS_NO_SUCH_DEVICE
;
683 /* Get the device node */
684 DeviceNode
= IopGetDeviceNode(DeviceObject
);
686 ASSERT(DeviceNode
->Flags
& DNF_ENUMERATED
);
687 ASSERT(DeviceNode
->Flags
& DNF_PROCESSED
);
689 /* Check if there's already a driver loaded for this device */
690 if (DeviceNode
->Flags
& DNF_ADDED
)
693 /* Remove the device node */
694 Status
= IopRemoveDevice(DeviceNode
);
695 if (NT_SUCCESS(Status
))
697 /* Invalidate device relations for the parent to reenumerate the device */
698 DPRINT1("A new driver will be loaded for '%wZ' (FDO above removed)\n", &DeviceNode
->InstancePath
);
699 Status
= IoSynchronousInvalidateDeviceRelations(DeviceNode
->Parent
->PhysicalDeviceObject
, BusRelations
);
704 /* A driver has already been loaded for this device */
705 DPRINT1("A reboot is required for the current driver for '%wZ' to be replaced\n", &DeviceNode
->InstancePath
);
706 DeviceNode
->Problem
= CM_PROB_NEED_RESTART
;
711 /* FIXME: What if the device really is disabled? */
712 DeviceNode
->Flags
&= ~DNF_DISABLED
;
713 DeviceNode
->Problem
= 0;
715 /* Load service data from the registry */
716 Status
= IopActionConfigureChildServices(DeviceNode
, DeviceNode
->Parent
);
718 if (NT_SUCCESS(Status
))
720 /* Start the service and begin PnP initialization of the device again */
721 DPRINT1("A new driver will be loaded for '%wZ' (no FDO above)\n", &DeviceNode
->InstancePath
);
722 Status
= IopActionInitChildServices(DeviceNode
, DeviceNode
->Parent
);
726 ObDereferenceObject(DeviceObject
);
731 /* PUBLIC FUNCTIONS **********************************************************/
734 * Plug and Play event structure used by NtGetPlugPlayEvent.
737 * Can be one of the following values:
738 * GUID_HWPROFILE_QUERY_CHANGE
739 * GUID_HWPROFILE_CHANGE_CANCELLED
740 * GUID_HWPROFILE_CHANGE_COMPLETE
741 * GUID_TARGET_DEVICE_QUERY_REMOVE
742 * GUID_TARGET_DEVICE_REMOVE_CANCELLED
743 * GUID_TARGET_DEVICE_REMOVE_COMPLETE
744 * GUID_PNP_CUSTOM_NOTIFICATION
745 * GUID_PNP_POWER_NOTIFICATION
746 * GUID_DEVICE_* (see above)
749 * Type of the event that happened.
758 * Size of the event block including the device IDs and other
759 * per category specific fields.
765 * Returns one Plug & Play event from a global queue.
770 * Always set to zero.
773 * The buffer that will be filled with the event information on
774 * successful return from the function.
777 * Size of the buffer pointed by the Buffer parameter. If the
778 * buffer size is not large enough to hold the whole event
779 * information, error STATUS_BUFFER_TOO_SMALL is returned and
780 * the buffer remains untouched.
783 * STATUS_PRIVILEGE_NOT_HELD
784 * STATUS_BUFFER_TOO_SMALL
788 * This function isn't multi-thread safe!
794 NtGetPlugPlayEvent(IN ULONG Reserved1
,
796 OUT PPLUGPLAY_EVENT_BLOCK Buffer
,
799 PPNP_EVENT_ENTRY Entry
;
802 DPRINT("NtGetPlugPlayEvent() called\n");
804 /* Function can only be called from user-mode */
805 if (KeGetPreviousMode() == KernelMode
)
807 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
808 return STATUS_ACCESS_DENIED
;
811 /* Check for Tcb privilege */
812 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
815 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
816 return STATUS_PRIVILEGE_NOT_HELD
;
819 /* Wait for a PnP event */
820 DPRINT("Waiting for pnp notification event\n");
821 Status
= KeWaitForSingleObject(&IopPnpNotifyEvent
,
826 if (!NT_SUCCESS(Status
) || Status
== STATUS_USER_APC
)
828 DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status
);
829 ASSERT(Status
== STATUS_USER_APC
);
833 /* Get entry from the tail of the queue */
834 Entry
= CONTAINING_RECORD(IopPnpEventQueueHead
.Blink
,
838 /* Check the buffer size */
839 if (BufferSize
< Entry
->Event
.TotalSize
)
841 DPRINT1("Buffer is too small for the pnp-event\n");
842 return STATUS_BUFFER_TOO_SMALL
;
845 /* Copy event data to the user buffer */
848 ProbeForWrite(Buffer
,
849 Entry
->Event
.TotalSize
,
851 RtlCopyMemory(Buffer
,
853 Entry
->Event
.TotalSize
);
855 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
857 _SEH2_YIELD(return _SEH2_GetExceptionCode());
861 DPRINT("NtGetPlugPlayEvent() done\n");
863 return STATUS_SUCCESS
;
869 * A function for doing various Plug & Play operations from user mode.
872 * PlugPlayControlClass
873 * 0x00 Reenumerate device tree
875 * Buffer points to UNICODE_STRING decribing the instance
876 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
877 * more information about instance paths see !devnode command
878 * in kernel debugger or look at "Inside Windows 2000" book,
879 * chapter "Driver Loading, Initialization, and Installation".
881 * 0x01 Register new device
882 * 0x02 Deregister device
883 * 0x03 Initialize device
885 * 0x06 Query and remove device
888 * Called after processing the message from NtGetPlugPlayEvent.
890 * 0x08 Generate legacy device
891 * 0x09 Get interface device list
892 * 0x0A Get property data
893 * 0x0B Device class association (Registration)
894 * 0x0C Get related device
895 * 0x0D Get device interface alias
896 * 0x0E Get/set/clear device status
897 * 0x0F Get device depth
898 * 0x10 Query device relations
899 * 0x11 Query target device relation
900 * 0x12 Query conflict list
901 * 0x13 Retrieve dock data
904 * 0x16 Get blocked driver data
907 * The buffer contains information that is specific to each control
908 * code. The buffer is read-only.
911 * Size of the buffer pointed by the Buffer parameter. If the
912 * buffer size specifies incorrect value for specified control
913 * code, error ??? is returned.
916 * STATUS_PRIVILEGE_NOT_HELD
924 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass
,
926 IN ULONG BufferLength
)
928 DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
929 PlugPlayControlClass
, Buffer
, BufferLength
);
931 /* Function can only be called from user-mode */
932 if (KeGetPreviousMode() == KernelMode
)
934 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
935 return STATUS_ACCESS_DENIED
;
938 /* Check for Tcb privilege */
939 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
942 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
943 return STATUS_PRIVILEGE_NOT_HELD
;
946 /* Probe the buffer */
949 ProbeForWrite(Buffer
,
953 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
955 _SEH2_YIELD(return _SEH2_GetExceptionCode());
959 switch (PlugPlayControlClass
)
961 case PlugPlayControlUserResponse
:
962 if (Buffer
|| BufferLength
!= 0)
963 return STATUS_INVALID_PARAMETER
;
964 return IopRemovePlugPlayEvent();
966 case PlugPlayControlGetInterfaceDeviceList
:
967 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
))
968 return STATUS_INVALID_PARAMETER
;
969 return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
)Buffer
);
971 case PlugPlayControlProperty
:
972 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA
))
973 return STATUS_INVALID_PARAMETER
;
974 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA
)Buffer
);
976 case PlugPlayControlGetRelatedDevice
:
977 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
))
978 return STATUS_INVALID_PARAMETER
;
979 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA
)Buffer
);
981 case PlugPlayControlDeviceStatus
:
982 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_STATUS_DATA
))
983 return STATUS_INVALID_PARAMETER
;
984 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA
)Buffer
);
986 case PlugPlayControlGetDeviceDepth
:
987 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEPTH_DATA
))
988 return STATUS_INVALID_PARAMETER
;
989 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA
)Buffer
);
991 case PlugPlayControlResetDevice
:
992 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA
))
993 return STATUS_INVALID_PARAMETER
;
994 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA
)Buffer
);
997 return STATUS_NOT_IMPLEMENTED
;
1000 return STATUS_NOT_IMPLEMENTED
;