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
))
80 ExFreePool(EventEntry
);
84 InsertHeadList(&IopPnpEventQueueHead
,
85 &EventEntry
->ListEntry
);
86 KeSetEvent(&IopPnpNotifyEvent
,
90 return STATUS_SUCCESS
;
95 * Remove the current PnP event from the tail of the event queue
96 * and signal IopPnpNotifyEvent if there is yet another event in the queue.
99 IopRemovePlugPlayEvent(VOID
)
101 /* Remove a pnp event entry from the tail of the queue */
102 if (!IsListEmpty(&IopPnpEventQueueHead
))
104 ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead
), PNP_EVENT_ENTRY
, ListEntry
));
107 /* Signal the next pnp event in the queue */
108 if (!IsListEmpty(&IopPnpEventQueueHead
))
110 KeSetEvent(&IopPnpNotifyEvent
,
115 return STATUS_SUCCESS
;
118 static PDEVICE_OBJECT
119 IopTraverseDeviceNode(PDEVICE_NODE Node
, PUNICODE_STRING DeviceInstance
)
121 PDEVICE_OBJECT DeviceObject
;
122 PDEVICE_NODE ChildNode
;
124 if (RtlEqualUnicodeString(&Node
->InstancePath
,
125 DeviceInstance
, TRUE
))
127 ObReferenceObject(Node
->PhysicalDeviceObject
);
128 return Node
->PhysicalDeviceObject
;
131 /* Traversal of all children nodes */
132 for (ChildNode
= Node
->Child
;
134 ChildNode
= ChildNode
->Sibling
)
136 DeviceObject
= IopTraverseDeviceNode(ChildNode
, DeviceInstance
);
137 if (DeviceObject
!= NULL
)
148 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
)
150 if (IopRootDeviceNode
== NULL
)
153 if (DeviceInstance
== NULL
||
154 DeviceInstance
->Length
== 0)
156 if (IopRootDeviceNode
->PhysicalDeviceObject
)
158 ObReferenceObject(IopRootDeviceNode
->PhysicalDeviceObject
);
159 return IopRootDeviceNode
->PhysicalDeviceObject
;
165 return IopTraverseDeviceNode(IopRootDeviceNode
, DeviceInstance
);
169 IopCaptureUnicodeString(PUNICODE_STRING DstName
, PUNICODE_STRING SrcName
)
171 NTSTATUS Status
= STATUS_SUCCESS
;
172 volatile UNICODE_STRING Name
;
177 Name
.Length
= SrcName
->Length
;
178 Name
.MaximumLength
= SrcName
->MaximumLength
;
179 if (Name
.Length
> Name
.MaximumLength
)
181 Status
= STATUS_INVALID_PARAMETER
;
185 if (Name
.MaximumLength
)
187 ProbeForRead(SrcName
->Buffer
,
190 Name
.Buffer
= ExAllocatePool(NonPagedPool
, Name
.MaximumLength
);
191 if (Name
.Buffer
== NULL
)
193 Status
= STATUS_INSUFFICIENT_RESOURCES
;
197 memcpy(Name
.Buffer
, SrcName
->Buffer
, Name
.MaximumLength
);
202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
206 ExFreePool(Name
.Buffer
);
208 Status
= _SEH2_GetExceptionCode();
216 IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList
)
219 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList
;
220 UNICODE_STRING DeviceInstance
;
221 PDEVICE_OBJECT DeviceObject
= NULL
;
223 PZZWSTR SymbolicLinkList
= NULL
, LinkList
;
228 RtlCopyMemory(&StackList
, DeviceList
, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
));
230 ProbeForRead(StackList
.FilterGuid
, sizeof(GUID
), sizeof(UCHAR
));
231 RtlCopyMemory(&FilterGuid
, StackList
.FilterGuid
, sizeof(GUID
));
233 if (StackList
.Buffer
!= NULL
&& StackList
.BufferSize
!= 0)
235 ProbeForWrite(StackList
.Buffer
, StackList
.BufferSize
, sizeof(UCHAR
));
238 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
240 _SEH2_YIELD(return _SEH2_GetExceptionCode());
244 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StackList
.DeviceInstance
);
245 if (NT_SUCCESS(Status
))
247 /* Get the device object */
248 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
249 if (DeviceInstance
.Buffer
!= NULL
)
251 ExFreePool(DeviceInstance
.Buffer
);
255 Status
= IoGetDeviceInterfaces(&FilterGuid
, DeviceObject
, StackList
.Flags
, &SymbolicLinkList
);
256 ObDereferenceObject(DeviceObject
);
258 if (!NT_SUCCESS(Status
))
264 LinkList
= SymbolicLinkList
;
265 while (*SymbolicLinkList
!= UNICODE_NULL
)
267 SymbolicLinkList
+= wcslen(SymbolicLinkList
) + (sizeof(UNICODE_NULL
) / sizeof(WCHAR
));
269 TotalLength
= ((SymbolicLinkList
- LinkList
+ 1) * sizeof(WCHAR
));
273 if (StackList
.Buffer
!= NULL
&&
274 StackList
.BufferSize
>= TotalLength
)
276 // We've already probed the buffer for writing above.
277 RtlCopyMemory(StackList
.Buffer
, LinkList
, TotalLength
);
280 DeviceList
->BufferSize
= TotalLength
;
282 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
284 ExFreePool(LinkList
);
285 _SEH2_YIELD(return _SEH2_GetExceptionCode());
289 ExFreePool(LinkList
);
290 return STATUS_SUCCESS
;
294 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData
)
296 PDEVICE_OBJECT DeviceObject
= NULL
;
298 UNICODE_STRING DeviceInstance
;
303 DPRINT("IopGetDeviceProperty() called\n");
304 DPRINT("Device name: %wZ\n", &PropertyData
->DeviceInstance
);
306 Status
= IopCaptureUnicodeString(&DeviceInstance
, &PropertyData
->DeviceInstance
);
307 if (!NT_SUCCESS(Status
))
314 Property
= PropertyData
->Property
;
315 BufferSize
= PropertyData
->BufferSize
;
316 ProbeForWrite(PropertyData
->Buffer
,
320 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
322 if (DeviceInstance
.Buffer
!= NULL
)
324 ExFreePool(DeviceInstance
.Buffer
);
326 _SEH2_YIELD(return _SEH2_GetExceptionCode());
330 /* Get the device object */
331 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
332 if (DeviceInstance
.Buffer
!= NULL
)
334 ExFreePool(DeviceInstance
.Buffer
);
336 if (DeviceObject
== NULL
)
338 return STATUS_NO_SUCH_DEVICE
;
341 Buffer
= ExAllocatePool(NonPagedPool
, BufferSize
);
344 return STATUS_INSUFFICIENT_RESOURCES
;
347 Status
= IoGetDeviceProperty(DeviceObject
,
353 ObDereferenceObject(DeviceObject
);
355 if (NT_SUCCESS(Status
))
359 RtlCopyMemory(PropertyData
->Buffer
, Buffer
, BufferSize
);
360 PropertyData
->BufferSize
= BufferSize
;
362 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
364 Status
= _SEH2_GetExceptionCode();
375 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData
)
377 UNICODE_STRING RootDeviceName
;
378 PDEVICE_OBJECT DeviceObject
= NULL
;
379 PDEVICE_NODE DeviceNode
= NULL
;
380 PDEVICE_NODE RelatedDeviceNode
;
381 UNICODE_STRING TargetDeviceInstance
;
382 NTSTATUS Status
= STATUS_SUCCESS
;
384 ULONG MaximumLength
= 0;
386 DPRINT("IopGetRelatedDevice() called\n");
387 DPRINT("Device name: %wZ\n", &RelatedDeviceData
->TargetDeviceInstance
);
389 Status
= IopCaptureUnicodeString(&TargetDeviceInstance
, &RelatedDeviceData
->TargetDeviceInstance
);
390 if (!NT_SUCCESS(Status
))
397 Relation
= RelatedDeviceData
->Relation
;
398 MaximumLength
= RelatedDeviceData
->RelatedDeviceInstanceLength
;
399 ProbeForWrite(RelatedDeviceData
->RelatedDeviceInstance
,
403 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
405 if (TargetDeviceInstance
.Buffer
!= NULL
)
407 ExFreePool(TargetDeviceInstance
.Buffer
);
409 _SEH2_YIELD(return _SEH2_GetExceptionCode());
413 RtlInitUnicodeString(&RootDeviceName
,
415 if (RtlEqualUnicodeString(&TargetDeviceInstance
,
419 DeviceNode
= IopRootDeviceNode
;
420 if (TargetDeviceInstance
.Buffer
!= NULL
)
422 ExFreePool(TargetDeviceInstance
.Buffer
);
427 /* Get the device object */
428 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance
);
429 if (TargetDeviceInstance
.Buffer
!= NULL
)
431 ExFreePool(TargetDeviceInstance
.Buffer
);
433 if (DeviceObject
== NULL
)
434 return STATUS_NO_SUCH_DEVICE
;
436 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
441 case PNP_GET_PARENT_DEVICE
:
442 RelatedDeviceNode
= DeviceNode
->Parent
;
445 case PNP_GET_CHILD_DEVICE
:
446 RelatedDeviceNode
= DeviceNode
->Child
;
449 case PNP_GET_SIBLING_DEVICE
:
450 RelatedDeviceNode
= DeviceNode
->Sibling
;
454 if (DeviceObject
!= NULL
)
456 ObDereferenceObject(DeviceObject
);
459 return STATUS_INVALID_PARAMETER
;
462 if (RelatedDeviceNode
== NULL
)
466 ObDereferenceObject(DeviceObject
);
469 return STATUS_NO_SUCH_DEVICE
;
472 if (RelatedDeviceNode
->InstancePath
.Length
> MaximumLength
)
476 ObDereferenceObject(DeviceObject
);
479 return STATUS_BUFFER_TOO_SMALL
;
482 /* Copy related device instance name */
485 RtlCopyMemory(RelatedDeviceData
->RelatedDeviceInstance
,
486 RelatedDeviceNode
->InstancePath
.Buffer
,
487 RelatedDeviceNode
->InstancePath
.Length
);
488 RelatedDeviceData
->RelatedDeviceInstanceLength
= RelatedDeviceNode
->InstancePath
.Length
;
490 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
492 Status
= _SEH2_GetExceptionCode();
496 if (DeviceObject
!= NULL
)
498 ObDereferenceObject(DeviceObject
);
501 DPRINT("IopGetRelatedDevice() done\n");
507 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode
)
511 if (DeviceNode
->Parent
== IopRootDeviceNode
)
512 Output
|= DN_ROOT_ENUMERATED
;
514 if (DeviceNode
->Flags
& DNF_ADDED
)
515 Output
|= DN_DRIVER_LOADED
;
517 /* FIXME: DN_ENUM_LOADED */
519 if (DeviceNode
->Flags
& DNF_STARTED
)
520 Output
|= DN_STARTED
;
524 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
525 Output
|= DN_NEED_TO_ENUM
;
527 /* DN_NOT_FIRST_TIME is 9x only */
529 /* FIXME: DN_HARDWARE_ENUM */
531 /* DN_LIAR and DN_HAS_MARK are 9x only */
533 if (DeviceNode
->Problem
!= 0)
534 Output
|= DN_HAS_PROBLEM
;
536 /* FIXME: DN_FILTERED */
538 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
539 Output
|= DN_LEGACY_DRIVER
;
541 if (DeviceNode
->UserFlags
& DNUF_DONT_SHOW_IN_UI
)
542 Output
|= DN_NO_SHOW_IN_DM
;
544 if (!(DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
))
545 Output
|= DN_DISABLEABLE
;
547 /* FIXME: Implement the rest */
549 Output
|= DN_NT_ENUMERATOR
| DN_NT_DRIVER
;
555 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData
)
557 PDEVICE_OBJECT DeviceObject
;
558 PDEVICE_NODE DeviceNode
;
560 ULONG DeviceStatus
= 0;
561 ULONG DeviceProblem
= 0;
562 UNICODE_STRING DeviceInstance
;
565 DPRINT("IopDeviceStatus() called\n");
567 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StatusData
->DeviceInstance
);
568 if (!NT_SUCCESS(Status
))
573 DPRINT("Device name: '%wZ'\n", &DeviceInstance
);
577 Operation
= StatusData
->Operation
;
578 if (Operation
== PNP_SET_DEVICE_STATUS
)
580 DeviceStatus
= StatusData
->DeviceStatus
;
581 DeviceProblem
= StatusData
->DeviceProblem
;
584 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
586 if (DeviceInstance
.Buffer
!= NULL
)
588 ExFreePool(DeviceInstance
.Buffer
);
590 _SEH2_YIELD(return _SEH2_GetExceptionCode());
594 /* Get the device object */
595 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
596 if (DeviceInstance
.Buffer
!= NULL
)
598 ExFreePool(DeviceInstance
.Buffer
);
600 if (DeviceObject
== NULL
)
602 return STATUS_NO_SUCH_DEVICE
;
605 DeviceNode
= IopGetDeviceNode(DeviceObject
);
609 case PNP_GET_DEVICE_STATUS
:
610 DPRINT("Get status data\n");
611 DeviceStatus
= IopGetDeviceNodeStatus(DeviceNode
);
612 DeviceProblem
= DeviceNode
->Problem
;
615 case PNP_SET_DEVICE_STATUS
:
616 DPRINT1("Set status data is NOT SUPPORTED\n");
619 case PNP_CLEAR_DEVICE_STATUS
:
620 DPRINT1("FIXME: Clear status data!\n");
624 ObDereferenceObject(DeviceObject
);
626 if (Operation
== PNP_GET_DEVICE_STATUS
)
630 StatusData
->DeviceStatus
= DeviceStatus
;
631 StatusData
->DeviceProblem
= DeviceProblem
;
633 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
635 Status
= _SEH2_GetExceptionCode();
645 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData
)
647 UNICODE_STRING DeviceInstance
;
648 PDEVICE_OBJECT DeviceObject
= NULL
;
649 IO_STACK_LOCATION Stack
;
650 IO_STATUS_BLOCK IoStatusBlock
;
651 PDEVICE_RELATIONS DeviceRelations
= NULL
;
652 PDEVICE_OBJECT ChildDeviceObject
;
653 PDEVICE_NODE ChildDeviceNode
;
656 ULONG BufferSize
, RequiredSize
;
659 NTSTATUS Status
= STATUS_SUCCESS
;
661 DPRINT("IopGetDeviceRelations() called\n");
662 DPRINT("Device name: %wZ\n", &RelationsData
->DeviceInstance
);
663 DPRINT("Relations: %lu\n", RelationsData
->Relations
);
664 DPRINT("BufferSize: %lu\n", RelationsData
->BufferSize
);
665 DPRINT("Buffer: %p\n", RelationsData
->Buffer
);
669 Relations
= RelationsData
->Relations
;
670 BufferSize
= RelationsData
->BufferSize
;
671 Buffer
= RelationsData
->Buffer
;
673 ProbeForWrite(Buffer
, BufferSize
, sizeof(CHAR
));
675 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
677 _SEH2_YIELD(return _SEH2_GetExceptionCode());
681 Status
= IopCaptureUnicodeString(&DeviceInstance
, &RelationsData
->DeviceInstance
);
682 if (!NT_SUCCESS(Status
))
684 DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status
);
688 /* Get the device object */
689 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
690 if (DeviceObject
== NULL
)
692 DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n");
693 Status
= STATUS_NO_SUCH_DEVICE
;
699 case 0: /* EjectRelations */
700 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
703 case 1: /* RemovalRelations */
704 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
707 case 2: /* PowerRelations */
708 Stack
.Parameters
.QueryDeviceRelations
.Type
= PowerRelations
;
711 case 3: /* BusRelations */
712 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
716 Status
= STATUS_INVALID_PARAMETER
;
720 Status
= IopInitiatePnpIrp(DeviceObject
,
722 IRP_MN_QUERY_DEVICE_RELATIONS
,
724 if (!NT_SUCCESS(Status
))
726 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
730 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
732 DPRINT("Found %d device relations\n", DeviceRelations
->Count
);
737 BufferLeft
= BufferSize
;
740 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
742 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
744 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
747 DPRINT("Device instance: %wZ\n", &ChildDeviceNode
->InstancePath
);
748 DPRINT("RequiredSize: %hu\n", ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
752 if (BufferLeft
< ChildDeviceNode
->InstancePath
.Length
+ 2 * sizeof(WCHAR
))
754 Status
= STATUS_BUFFER_TOO_SMALL
;
759 ChildDeviceNode
->InstancePath
.Buffer
,
760 ChildDeviceNode
->InstancePath
.Length
);
761 Ptr
= (PWCHAR
)((ULONG_PTR
)Ptr
+ ChildDeviceNode
->InstancePath
.Length
);
763 Ptr
= (PWCHAR
)((ULONG_PTR
)Ptr
+ sizeof(WCHAR
));
765 BufferLeft
-= (ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
768 RequiredSize
+= (ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
772 if (Ptr
!= NULL
&& BufferLeft
>= sizeof(WCHAR
))
775 if (RequiredSize
> 0)
776 RequiredSize
+= sizeof(WCHAR
);
778 DPRINT("BufferSize: %lu RequiredSize: %lu\n", RelationsData
->BufferSize
, RequiredSize
);
780 RelationsData
->BufferSize
= RequiredSize
;
782 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
784 Status
= _SEH2_GetExceptionCode();
789 if (DeviceRelations
!= NULL
)
790 ExFreePool(DeviceRelations
);
792 if (DeviceObject
!= NULL
)
793 ObDereferenceObject(DeviceObject
);
795 if (DeviceInstance
.Buffer
!= NULL
)
796 ExFreePool(DeviceInstance
.Buffer
);
802 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData
)
804 PDEVICE_OBJECT DeviceObject
;
805 PDEVICE_NODE DeviceNode
;
806 UNICODE_STRING DeviceInstance
;
807 NTSTATUS Status
= STATUS_SUCCESS
;
809 DPRINT("IopGetDeviceDepth() called\n");
810 DPRINT("Device name: %wZ\n", &DepthData
->DeviceInstance
);
812 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DepthData
->DeviceInstance
);
813 if (!NT_SUCCESS(Status
))
818 /* Get the device object */
819 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
820 if (DeviceInstance
.Buffer
!= NULL
)
822 ExFreePool(DeviceInstance
.Buffer
);
824 if (DeviceObject
== NULL
)
826 return STATUS_NO_SUCH_DEVICE
;
829 DeviceNode
= IopGetDeviceNode(DeviceObject
);
833 DepthData
->Depth
= DeviceNode
->Level
;
835 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
837 Status
= _SEH2_GetExceptionCode();
841 ObDereferenceObject(DeviceObject
);
848 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData
)
850 PDEVICE_OBJECT DeviceObject
;
851 PDEVICE_NODE DeviceNode
;
852 NTSTATUS Status
= STATUS_SUCCESS
;
853 UNICODE_STRING DeviceInstance
;
855 Status
= IopCaptureUnicodeString(&DeviceInstance
, &ResetDeviceData
->DeviceInstance
);
856 if (!NT_SUCCESS(Status
))
861 DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance
);
863 /* Get the device object */
864 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
865 if (DeviceInstance
.Buffer
!= NULL
)
867 ExFreePool(DeviceInstance
.Buffer
);
869 if (DeviceObject
== NULL
)
871 return STATUS_NO_SUCH_DEVICE
;
874 /* Get the device node */
875 DeviceNode
= IopGetDeviceNode(DeviceObject
);
877 ASSERT(DeviceNode
->Flags
& DNF_ENUMERATED
);
878 ASSERT(DeviceNode
->Flags
& DNF_PROCESSED
);
880 /* Check if there's already a driver loaded for this device */
881 if (DeviceNode
->Flags
& DNF_ADDED
)
884 /* Remove the device node */
885 Status
= IopRemoveDevice(DeviceNode
);
886 if (NT_SUCCESS(Status
))
888 /* Invalidate device relations for the parent to reenumerate the device */
889 DPRINT1("A new driver will be loaded for '%wZ' (FDO above removed)\n", &DeviceNode
->InstancePath
);
890 Status
= IoSynchronousInvalidateDeviceRelations(DeviceNode
->Parent
->PhysicalDeviceObject
, BusRelations
);
895 /* A driver has already been loaded for this device */
896 DPRINT1("A reboot is required for the current driver for '%wZ' to be replaced\n", &DeviceNode
->InstancePath
);
897 DeviceNode
->Problem
= CM_PROB_NEED_RESTART
;
902 /* FIXME: What if the device really is disabled? */
903 DeviceNode
->Flags
&= ~DNF_DISABLED
;
904 DeviceNode
->Problem
= 0;
906 /* Load service data from the registry */
907 Status
= IopActionConfigureChildServices(DeviceNode
, DeviceNode
->Parent
);
909 if (NT_SUCCESS(Status
))
911 /* Start the service and begin PnP initialization of the device again */
912 DPRINT1("A new driver will be loaded for '%wZ' (no FDO above)\n", &DeviceNode
->InstancePath
);
913 Status
= IopActionInitChildServices(DeviceNode
, DeviceNode
->Parent
);
917 ObDereferenceObject(DeviceObject
);
922 /* PUBLIC FUNCTIONS **********************************************************/
925 * Plug and Play event structure used by NtGetPlugPlayEvent.
928 * Can be one of the following values:
929 * GUID_HWPROFILE_QUERY_CHANGE
930 * GUID_HWPROFILE_CHANGE_CANCELLED
931 * GUID_HWPROFILE_CHANGE_COMPLETE
932 * GUID_TARGET_DEVICE_QUERY_REMOVE
933 * GUID_TARGET_DEVICE_REMOVE_CANCELLED
934 * GUID_TARGET_DEVICE_REMOVE_COMPLETE
935 * GUID_PNP_CUSTOM_NOTIFICATION
936 * GUID_PNP_POWER_NOTIFICATION
937 * GUID_DEVICE_* (see above)
940 * Type of the event that happened.
949 * Size of the event block including the device IDs and other
950 * per category specific fields.
956 * Returns one Plug & Play event from a global queue.
961 * Always set to zero.
964 * The buffer that will be filled with the event information on
965 * successful return from the function.
968 * Size of the buffer pointed by the Buffer parameter. If the
969 * buffer size is not large enough to hold the whole event
970 * information, error STATUS_BUFFER_TOO_SMALL is returned and
971 * the buffer remains untouched.
974 * STATUS_PRIVILEGE_NOT_HELD
975 * STATUS_BUFFER_TOO_SMALL
979 * This function isn't multi-thread safe!
985 NtGetPlugPlayEvent(IN ULONG Reserved1
,
987 OUT PPLUGPLAY_EVENT_BLOCK Buffer
,
990 PPNP_EVENT_ENTRY Entry
;
993 DPRINT("NtGetPlugPlayEvent() called\n");
995 /* Function can only be called from user-mode */
996 if (KeGetPreviousMode() == KernelMode
)
998 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
999 return STATUS_ACCESS_DENIED
;
1002 /* Check for Tcb privilege */
1003 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1006 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1007 return STATUS_PRIVILEGE_NOT_HELD
;
1010 /* Wait for a PnP event */
1011 DPRINT("Waiting for pnp notification event\n");
1012 Status
= KeWaitForSingleObject(&IopPnpNotifyEvent
,
1017 if (!NT_SUCCESS(Status
) || Status
== STATUS_USER_APC
)
1019 DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status
);
1020 ASSERT(Status
== STATUS_USER_APC
);
1024 /* Get entry from the tail of the queue */
1025 Entry
= CONTAINING_RECORD(IopPnpEventQueueHead
.Blink
,
1029 /* Check the buffer size */
1030 if (BufferSize
< Entry
->Event
.TotalSize
)
1032 DPRINT1("Buffer is too small for the pnp-event\n");
1033 return STATUS_BUFFER_TOO_SMALL
;
1036 /* Copy event data to the user buffer */
1039 ProbeForWrite(Buffer
,
1040 Entry
->Event
.TotalSize
,
1042 RtlCopyMemory(Buffer
,
1044 Entry
->Event
.TotalSize
);
1046 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1048 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1052 DPRINT("NtGetPlugPlayEvent() done\n");
1054 return STATUS_SUCCESS
;
1060 * A function for doing various Plug & Play operations from user mode.
1063 * PlugPlayControlClass
1064 * 0x00 Reenumerate device tree
1066 * Buffer points to UNICODE_STRING decribing the instance
1067 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
1068 * more information about instance paths see !devnode command
1069 * in kernel debugger or look at "Inside Windows 2000" book,
1070 * chapter "Driver Loading, Initialization, and Installation".
1072 * 0x01 Register new device
1073 * 0x02 Deregister device
1074 * 0x03 Initialize device
1076 * 0x06 Query and remove device
1077 * 0x07 User response
1079 * Called after processing the message from NtGetPlugPlayEvent.
1081 * 0x08 Generate legacy device
1082 * 0x09 Get interface device list
1083 * 0x0A Get property data
1084 * 0x0B Device class association (Registration)
1085 * 0x0C Get related device
1086 * 0x0D Get device interface alias
1087 * 0x0E Get/set/clear device status
1088 * 0x0F Get device depth
1089 * 0x10 Query device relations
1090 * 0x11 Query target device relation
1091 * 0x12 Query conflict list
1092 * 0x13 Retrieve dock data
1095 * 0x16 Get blocked driver data
1098 * The buffer contains information that is specific to each control
1099 * code. The buffer is read-only.
1102 * Size of the buffer pointed by the Buffer parameter. If the
1103 * buffer size specifies incorrect value for specified control
1104 * code, error ??? is returned.
1107 * STATUS_PRIVILEGE_NOT_HELD
1115 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass
,
1116 IN OUT PVOID Buffer
,
1117 IN ULONG BufferLength
)
1119 DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
1120 PlugPlayControlClass
, Buffer
, BufferLength
);
1122 /* Function can only be called from user-mode */
1123 if (KeGetPreviousMode() == KernelMode
)
1125 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1126 return STATUS_ACCESS_DENIED
;
1129 /* Check for Tcb privilege */
1130 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1133 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1134 return STATUS_PRIVILEGE_NOT_HELD
;
1137 /* Probe the buffer */
1140 ProbeForWrite(Buffer
,
1144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1146 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1150 switch (PlugPlayControlClass
)
1152 // case PlugPlayControlEnumerateDevice:
1153 // case PlugPlayControlRegisterNewDevice:
1154 // case PlugPlayControlDeregisterDevice:
1155 // case PlugPlayControlInitializeDevice:
1156 // case PlugPlayControlStartDevice:
1157 // case PlugPlayControlUnlockDevice:
1158 // case PlugPlayControlQueryAndRemoveDevice:
1160 case PlugPlayControlUserResponse
:
1161 if (Buffer
|| BufferLength
!= 0)
1162 return STATUS_INVALID_PARAMETER
;
1163 return IopRemovePlugPlayEvent();
1165 // case PlugPlayControlGenerateLegacyDevice:
1167 case PlugPlayControlGetInterfaceDeviceList
:
1168 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
))
1169 return STATUS_INVALID_PARAMETER
;
1170 return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
)Buffer
);
1172 case PlugPlayControlProperty
:
1173 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA
))
1174 return STATUS_INVALID_PARAMETER
;
1175 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA
)Buffer
);
1177 // case PlugPlayControlDeviceClassAssociation:
1179 case PlugPlayControlGetRelatedDevice
:
1180 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
))
1181 return STATUS_INVALID_PARAMETER
;
1182 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA
)Buffer
);
1184 // case PlugPlayControlGetInterfaceDeviceAlias:
1186 case PlugPlayControlDeviceStatus
:
1187 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_STATUS_DATA
))
1188 return STATUS_INVALID_PARAMETER
;
1189 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA
)Buffer
);
1191 case PlugPlayControlGetDeviceDepth
:
1192 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEPTH_DATA
))
1193 return STATUS_INVALID_PARAMETER
;
1194 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA
)Buffer
);
1196 case PlugPlayControlQueryDeviceRelations
:
1197 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
))
1198 return STATUS_INVALID_PARAMETER
;
1199 return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
)Buffer
);
1201 // case PlugPlayControlTargetDeviceRelation:
1202 // case PlugPlayControlQueryConflictList:
1203 // case PlugPlayControlRetrieveDock:
1205 case PlugPlayControlResetDevice
:
1206 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA
))
1207 return STATUS_INVALID_PARAMETER
;
1208 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA
)Buffer
);
1210 // case PlugPlayControlHaltDevice:
1211 // case PlugPlayControlGetBlockedDriverList:
1214 return STATUS_NOT_IMPLEMENTED
;
1217 return STATUS_NOT_IMPLEMENTED
;