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 typedef struct _PNP_EVENT_ENTRY
18 PLUGPLAY_EVENT_BLOCK Event
;
19 } PNP_EVENT_ENTRY
, *PPNP_EVENT_ENTRY
;
22 /* GLOBALS *******************************************************************/
24 static LIST_ENTRY IopPnpEventQueueHead
;
25 static KEVENT IopPnpNotifyEvent
;
27 /* FUNCTIONS *****************************************************************/
31 IopInitPlugPlayEvents(VOID
)
33 InitializeListHead(&IopPnpEventQueueHead
);
35 KeInitializeEvent(&IopPnpNotifyEvent
,
39 return STATUS_SUCCESS
;
43 IopQueueTargetDeviceEvent(const GUID
*Guid
,
44 PUNICODE_STRING DeviceIds
)
46 PPNP_EVENT_ENTRY EventEntry
;
53 /* Allocate a big enough buffer */
55 Copy
.MaximumLength
= DeviceIds
->Length
+ sizeof(UNICODE_NULL
);
57 FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK
, TargetDevice
.DeviceIds
) +
60 EventEntry
= ExAllocatePool(NonPagedPool
,
61 TotalSize
+ FIELD_OFFSET(PNP_EVENT_ENTRY
, Event
));
63 return STATUS_INSUFFICIENT_RESOURCES
;
64 RtlZeroMemory(EventEntry
, TotalSize
+ FIELD_OFFSET(PNP_EVENT_ENTRY
, Event
));
66 /* Fill the buffer with the event GUID */
67 RtlCopyMemory(&EventEntry
->Event
.EventGuid
,
70 EventEntry
->Event
.EventCategory
= TargetDeviceChangeEvent
;
71 EventEntry
->Event
.TotalSize
= TotalSize
;
73 /* Fill the device id */
74 Copy
.Buffer
= EventEntry
->Event
.TargetDevice
.DeviceIds
;
75 Status
= RtlAppendUnicodeStringToString(&Copy
, DeviceIds
);
76 if (!NT_SUCCESS(Status
))
78 ExFreePool(EventEntry
);
82 InsertHeadList(&IopPnpEventQueueHead
,
83 &EventEntry
->ListEntry
);
84 KeSetEvent(&IopPnpNotifyEvent
,
88 return STATUS_SUCCESS
;
93 IopTraverseDeviceNode(PDEVICE_NODE Node
, PUNICODE_STRING DeviceInstance
)
95 PDEVICE_OBJECT DeviceObject
;
96 PDEVICE_NODE ChildNode
;
98 if (RtlEqualUnicodeString(&Node
->InstancePath
,
99 DeviceInstance
, TRUE
))
101 ObReferenceObject(Node
->PhysicalDeviceObject
);
102 return Node
->PhysicalDeviceObject
;
105 /* Traversal of all children nodes */
106 for (ChildNode
= Node
->Child
;
108 ChildNode
= ChildNode
->Sibling
)
110 DeviceObject
= IopTraverseDeviceNode(ChildNode
, DeviceInstance
);
111 if (DeviceObject
!= NULL
)
122 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance
)
124 if (IopRootDeviceNode
== NULL
)
127 if (DeviceInstance
== NULL
||
128 DeviceInstance
->Length
== 0)
130 if (IopRootDeviceNode
->PhysicalDeviceObject
)
132 ObReferenceObject(IopRootDeviceNode
->PhysicalDeviceObject
);
133 return IopRootDeviceNode
->PhysicalDeviceObject
;
139 return IopTraverseDeviceNode(IopRootDeviceNode
, DeviceInstance
);
143 IopCaptureUnicodeString(PUNICODE_STRING DstName
, PUNICODE_STRING SrcName
)
145 NTSTATUS Status
= STATUS_SUCCESS
;
146 volatile UNICODE_STRING Name
;
151 Name
.Length
= SrcName
->Length
;
152 Name
.MaximumLength
= SrcName
->MaximumLength
;
153 if (Name
.Length
> Name
.MaximumLength
)
155 Status
= STATUS_INVALID_PARAMETER
;
159 if (Name
.MaximumLength
)
161 ProbeForRead(SrcName
->Buffer
,
164 Name
.Buffer
= ExAllocatePool(NonPagedPool
, Name
.MaximumLength
);
165 if (Name
.Buffer
== NULL
)
167 Status
= STATUS_INSUFFICIENT_RESOURCES
;
171 memcpy(Name
.Buffer
, SrcName
->Buffer
, Name
.MaximumLength
);
176 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
180 ExFreePool(Name
.Buffer
);
182 Status
= _SEH2_GetExceptionCode();
190 IopPnpEnumerateDevice(PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA DeviceData
)
192 PDEVICE_OBJECT DeviceObject
;
193 UNICODE_STRING DeviceInstance
;
194 NTSTATUS Status
= STATUS_SUCCESS
;
196 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DeviceData
->DeviceInstance
);
197 if (!NT_SUCCESS(Status
))
202 DPRINT("IopPnpEnumerateDevice(%wZ)\n", &DeviceInstance
);
204 /* Get the device object */
205 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
206 if (DeviceInstance
.Buffer
!= NULL
)
208 ExFreePool(DeviceInstance
.Buffer
);
210 if (DeviceObject
== NULL
)
212 return STATUS_NO_SUCH_DEVICE
;
215 Status
= PiPerformSyncDeviceAction(DeviceObject
, PiActionEnumDeviceTree
);
217 ObDereferenceObject(DeviceObject
);
224 * Remove the current PnP event from the tail of the event queue
225 * and signal IopPnpNotifyEvent if there is yet another event in the queue.
229 IopRemovePlugPlayEvent(
230 _In_ PPLUGPLAY_CONTROL_USER_RESPONSE_DATA ResponseData
)
232 /* Remove a pnp event entry from the tail of the queue */
233 if (!IsListEmpty(&IopPnpEventQueueHead
))
235 ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead
), PNP_EVENT_ENTRY
, ListEntry
));
238 /* Signal the next pnp event in the queue */
239 if (!IsListEmpty(&IopPnpEventQueueHead
))
241 KeSetEvent(&IopPnpNotifyEvent
,
246 return STATUS_SUCCESS
;
251 IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList
)
254 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList
;
255 UNICODE_STRING DeviceInstance
;
256 PDEVICE_OBJECT DeviceObject
= NULL
;
258 PZZWSTR SymbolicLinkList
= NULL
, LinkList
;
263 RtlCopyMemory(&StackList
, DeviceList
, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
));
265 ProbeForRead(StackList
.FilterGuid
, sizeof(GUID
), sizeof(UCHAR
));
266 RtlCopyMemory(&FilterGuid
, StackList
.FilterGuid
, sizeof(GUID
));
268 if (StackList
.Buffer
!= NULL
&& StackList
.BufferSize
!= 0)
270 ProbeForWrite(StackList
.Buffer
, StackList
.BufferSize
, sizeof(UCHAR
));
273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
275 _SEH2_YIELD(return _SEH2_GetExceptionCode());
279 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StackList
.DeviceInstance
);
280 if (NT_SUCCESS(Status
))
282 /* Get the device object */
283 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
284 if (DeviceInstance
.Buffer
!= NULL
)
286 ExFreePool(DeviceInstance
.Buffer
);
290 Status
= IoGetDeviceInterfaces(&FilterGuid
, DeviceObject
, StackList
.Flags
, &SymbolicLinkList
);
291 ObDereferenceObject(DeviceObject
);
293 if (!NT_SUCCESS(Status
))
299 LinkList
= SymbolicLinkList
;
300 while (*SymbolicLinkList
!= UNICODE_NULL
)
302 SymbolicLinkList
+= wcslen(SymbolicLinkList
) + (sizeof(UNICODE_NULL
) / sizeof(WCHAR
));
304 TotalLength
= ((SymbolicLinkList
- LinkList
+ 1) * sizeof(WCHAR
));
308 if (StackList
.Buffer
!= NULL
&&
309 StackList
.BufferSize
>= TotalLength
)
311 // We've already probed the buffer for writing above.
312 RtlCopyMemory(StackList
.Buffer
, LinkList
, TotalLength
);
315 DeviceList
->BufferSize
= TotalLength
;
317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
319 ExFreePool(LinkList
);
320 _SEH2_YIELD(return _SEH2_GetExceptionCode());
324 ExFreePool(LinkList
);
325 return STATUS_SUCCESS
;
329 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData
)
331 PDEVICE_OBJECT DeviceObject
= NULL
;
332 PDEVICE_NODE DeviceNode
;
333 UNICODE_STRING DeviceInstance
;
336 DEVICE_REGISTRY_PROPERTY DeviceProperty
;
340 DPRINT("IopGetDeviceProperty() called\n");
341 DPRINT("Device name: %wZ\n", &PropertyData
->DeviceInstance
);
343 Status
= IopCaptureUnicodeString(&DeviceInstance
, &PropertyData
->DeviceInstance
);
344 if (!NT_SUCCESS(Status
))
351 Property
= PropertyData
->Property
;
352 BufferSize
= PropertyData
->BufferSize
;
353 ProbeForWrite(PropertyData
->Buffer
,
357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
359 if (DeviceInstance
.Buffer
!= NULL
)
361 ExFreePool(DeviceInstance
.Buffer
);
363 _SEH2_YIELD(return _SEH2_GetExceptionCode());
367 /* Get the device object */
368 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
369 if (DeviceInstance
.Buffer
!= NULL
)
371 ExFreePool(DeviceInstance
.Buffer
);
373 if (DeviceObject
== NULL
)
375 return STATUS_NO_SUCH_DEVICE
;
378 Buffer
= ExAllocatePool(NonPagedPool
, BufferSize
);
381 ObDereferenceObject(DeviceObject
);
382 return STATUS_INSUFFICIENT_RESOURCES
;
386 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
388 if (Property
== PNP_PROPERTY_POWER_DATA
)
390 if (BufferSize
< sizeof(CM_POWER_DATA
))
393 Status
= STATUS_BUFFER_TOO_SMALL
;
397 DEVICE_CAPABILITIES DeviceCapabilities
;
398 PCM_POWER_DATA PowerData
;
399 IO_STACK_LOCATION Stack
;
400 IO_STATUS_BLOCK IoStatusBlock
;
402 PowerData
= (PCM_POWER_DATA
)Buffer
;
403 RtlZeroMemory(PowerData
, sizeof(CM_POWER_DATA
));
404 PowerData
->PD_Size
= sizeof(CM_POWER_DATA
);
406 RtlZeroMemory(&DeviceCapabilities
, sizeof(DEVICE_CAPABILITIES
));
407 DeviceCapabilities
.Size
= sizeof(DEVICE_CAPABILITIES
);
408 DeviceCapabilities
.Version
= 1;
409 DeviceCapabilities
.Address
= -1;
410 DeviceCapabilities
.UINumber
= -1;
412 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= &DeviceCapabilities
;
414 Status
= IopInitiatePnpIrp(DeviceObject
,
416 IRP_MN_QUERY_CAPABILITIES
,
418 if (NT_SUCCESS(Status
))
420 DPRINT("Got device capabiliities\n");
422 PowerData
->PD_MostRecentPowerState
= PowerDeviceD0
; // FIXME
423 if (DeviceCapabilities
.DeviceD1
)
424 PowerData
->PD_Capabilities
|= PDCAP_D1_SUPPORTED
;
425 if (DeviceCapabilities
.DeviceD2
)
426 PowerData
->PD_Capabilities
|= PDCAP_D2_SUPPORTED
;
427 if (DeviceCapabilities
.WakeFromD0
)
428 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D0_SUPPORTED
;
429 if (DeviceCapabilities
.WakeFromD1
)
430 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D1_SUPPORTED
;
431 if (DeviceCapabilities
.WakeFromD2
)
432 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D2_SUPPORTED
;
433 if (DeviceCapabilities
.WakeFromD3
)
434 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D3_SUPPORTED
;
435 if (DeviceCapabilities
.WarmEjectSupported
)
436 PowerData
->PD_Capabilities
|= PDCAP_WARM_EJECT_SUPPORTED
;
437 PowerData
->PD_D1Latency
= DeviceCapabilities
.D1Latency
;
438 PowerData
->PD_D2Latency
= DeviceCapabilities
.D2Latency
;
439 PowerData
->PD_D3Latency
= DeviceCapabilities
.D3Latency
;
440 RtlCopyMemory(&PowerData
->PD_PowerStateMapping
,
441 &DeviceCapabilities
.DeviceState
,
442 sizeof(DeviceCapabilities
.DeviceState
));
443 PowerData
->PD_DeepestSystemWake
= DeviceCapabilities
.SystemWake
;
447 DPRINT("IRP_MN_QUERY_CAPABILITIES failed (Status 0x%08lx)\n", Status
);
449 PowerData
->PD_Capabilities
= PDCAP_D0_SUPPORTED
| PDCAP_D3_SUPPORTED
;
450 PowerData
->PD_MostRecentPowerState
= PowerDeviceD0
;
454 else if (Property
== PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE
)
457 else if (Property
== PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT
)
459 if (BufferSize
< sizeof(DeviceNode
->HardwareRemovalPolicy
))
462 Status
= STATUS_BUFFER_TOO_SMALL
;
466 BufferSize
= sizeof(DeviceNode
->HardwareRemovalPolicy
);
467 RtlCopyMemory(Buffer
,
468 &DeviceNode
->HardwareRemovalPolicy
,
476 case PNP_PROPERTY_UI_NUMBER
:
477 DeviceProperty
= DevicePropertyUINumber
;
480 case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME
:
481 DeviceProperty
= DevicePropertyPhysicalDeviceObjectName
;
484 case PNP_PROPERTY_BUSTYPEGUID
:
485 DeviceProperty
= DevicePropertyBusTypeGuid
;
488 case PNP_PROPERTY_LEGACYBUSTYPE
:
489 DeviceProperty
= DevicePropertyLegacyBusType
;
492 case PNP_PROPERTY_BUSNUMBER
:
493 DeviceProperty
= DevicePropertyBusNumber
;
496 case PNP_PROPERTY_REMOVAL_POLICY
:
497 DeviceProperty
= DevicePropertyRemovalPolicy
;
500 case PNP_PROPERTY_ADDRESS
:
501 DeviceProperty
= DevicePropertyAddress
;
504 case PNP_PROPERTY_ENUMERATOR_NAME
:
505 DeviceProperty
= DevicePropertyEnumeratorName
;
508 case PNP_PROPERTY_INSTALL_STATE
:
509 DeviceProperty
= DevicePropertyInstallState
;
512 #if (WINVER >= _WIN32_WINNT_WS03)
513 case PNP_PROPERTY_LOCATION_PATHS
:
517 #if (WINVER >= _WIN32_WINNT_WIN7)
518 case PNP_PROPERTY_CONTAINERID
:
519 DeviceProperty
= DevicePropertyContainerID
;
525 Status
= STATUS_INVALID_PARAMETER
;
529 if (Status
== STATUS_SUCCESS
)
531 Status
= IoGetDeviceProperty(DeviceObject
,
539 ObDereferenceObject(DeviceObject
);
541 if (NT_SUCCESS(Status
))
545 RtlCopyMemory(PropertyData
->Buffer
, Buffer
, BufferSize
);
546 PropertyData
->BufferSize
= BufferSize
;
548 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
550 Status
= _SEH2_GetExceptionCode();
561 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData
)
563 UNICODE_STRING RootDeviceName
;
564 PDEVICE_OBJECT DeviceObject
= NULL
;
565 PDEVICE_NODE DeviceNode
= NULL
;
566 PDEVICE_NODE RelatedDeviceNode
;
567 UNICODE_STRING TargetDeviceInstance
;
568 NTSTATUS Status
= STATUS_SUCCESS
;
570 ULONG MaximumLength
= 0;
572 DPRINT("IopGetRelatedDevice() called\n");
573 DPRINT("Device name: %wZ\n", &RelatedDeviceData
->TargetDeviceInstance
);
575 Status
= IopCaptureUnicodeString(&TargetDeviceInstance
, &RelatedDeviceData
->TargetDeviceInstance
);
576 if (!NT_SUCCESS(Status
))
583 Relation
= RelatedDeviceData
->Relation
;
584 MaximumLength
= RelatedDeviceData
->RelatedDeviceInstanceLength
;
585 ProbeForWrite(RelatedDeviceData
->RelatedDeviceInstance
,
589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
591 if (TargetDeviceInstance
.Buffer
!= NULL
)
593 ExFreePool(TargetDeviceInstance
.Buffer
);
595 _SEH2_YIELD(return _SEH2_GetExceptionCode());
599 RtlInitUnicodeString(&RootDeviceName
,
601 if (RtlEqualUnicodeString(&TargetDeviceInstance
,
605 DeviceNode
= IopRootDeviceNode
;
606 if (TargetDeviceInstance
.Buffer
!= NULL
)
608 ExFreePool(TargetDeviceInstance
.Buffer
);
613 /* Get the device object */
614 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance
);
615 if (TargetDeviceInstance
.Buffer
!= NULL
)
617 ExFreePool(TargetDeviceInstance
.Buffer
);
619 if (DeviceObject
== NULL
)
620 return STATUS_NO_SUCH_DEVICE
;
622 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
627 case PNP_GET_PARENT_DEVICE
:
628 RelatedDeviceNode
= DeviceNode
->Parent
;
631 case PNP_GET_CHILD_DEVICE
:
632 RelatedDeviceNode
= DeviceNode
->Child
;
635 case PNP_GET_SIBLING_DEVICE
:
636 RelatedDeviceNode
= DeviceNode
->Sibling
;
640 if (DeviceObject
!= NULL
)
642 ObDereferenceObject(DeviceObject
);
645 return STATUS_INVALID_PARAMETER
;
648 if (RelatedDeviceNode
== NULL
)
652 ObDereferenceObject(DeviceObject
);
655 return STATUS_NO_SUCH_DEVICE
;
658 if (RelatedDeviceNode
->InstancePath
.Length
> MaximumLength
)
662 ObDereferenceObject(DeviceObject
);
665 return STATUS_BUFFER_TOO_SMALL
;
668 /* Copy related device instance name */
671 RtlCopyMemory(RelatedDeviceData
->RelatedDeviceInstance
,
672 RelatedDeviceNode
->InstancePath
.Buffer
,
673 RelatedDeviceNode
->InstancePath
.Length
);
674 RelatedDeviceData
->RelatedDeviceInstanceLength
= RelatedDeviceNode
->InstancePath
.Length
;
676 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
678 Status
= _SEH2_GetExceptionCode();
682 if (DeviceObject
!= NULL
)
684 ObDereferenceObject(DeviceObject
);
687 DPRINT("IopGetRelatedDevice() done\n");
695 _In_ PDEVICE_NODE DeviceNode
)
697 return (DeviceNode
->State
== DeviceNodeStartPending
||
698 DeviceNode
->State
== DeviceNodeStartCompletion
||
699 DeviceNode
->State
== DeviceNodeStartPostWork
||
700 DeviceNode
->State
== DeviceNodeStarted
||
701 DeviceNode
->State
== DeviceNodeQueryStopped
||
702 DeviceNode
->State
== DeviceNodeEnumeratePending
||
703 DeviceNode
->State
== DeviceNodeEnumerateCompletion
||
704 DeviceNode
->State
== DeviceNodeStopped
||
705 DeviceNode
->State
== DeviceNodeRestartCompletion
);
709 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode
)
711 ULONG Output
= DN_NT_ENUMERATOR
| DN_NT_DRIVER
;
713 if (DeviceNode
->Parent
== IopRootDeviceNode
)
714 Output
|= DN_ROOT_ENUMERATED
;
716 // FIXME: review for deleted and removed states
717 if (DeviceNode
->State
>= DeviceNodeDriversAdded
)
718 Output
|= DN_DRIVER_LOADED
;
720 if (PiIsDevNodeStarted(DeviceNode
))
721 Output
|= DN_STARTED
;
723 if (DeviceNode
->UserFlags
& DNUF_WILL_BE_REMOVED
)
724 Output
|= DN_WILL_BE_REMOVED
;
726 if (DeviceNode
->Flags
& DNF_HAS_PROBLEM
)
727 Output
|= DN_HAS_PROBLEM
;
729 if (DeviceNode
->Flags
& DNF_HAS_PRIVATE_PROBLEM
)
730 Output
|= DN_PRIVATE_PROBLEM
;
732 if (DeviceNode
->Flags
& DNF_DRIVER_BLOCKED
)
733 Output
|= DN_DRIVER_BLOCKED
;
735 if (DeviceNode
->Flags
& DNF_CHILD_WITH_INVALID_ID
)
736 Output
|= DN_CHILD_WITH_INVALID_ID
;
738 if (DeviceNode
->Flags
& DNF_HAS_PRIVATE_PROBLEM
)
739 Output
|= DN_PRIVATE_PROBLEM
;
741 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
742 Output
|= DN_LEGACY_DRIVER
;
744 if (DeviceNode
->UserFlags
& DNUF_DONT_SHOW_IN_UI
)
745 Output
|= DN_NO_SHOW_IN_DM
;
747 if (!(DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
))
748 Output
|= DN_DISABLEABLE
;
754 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData
)
756 PDEVICE_OBJECT DeviceObject
;
757 PDEVICE_NODE DeviceNode
;
759 ULONG DeviceStatus
= 0;
760 ULONG DeviceProblem
= 0;
761 UNICODE_STRING DeviceInstance
;
764 DPRINT("IopDeviceStatus() called\n");
766 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StatusData
->DeviceInstance
);
767 if (!NT_SUCCESS(Status
))
772 DPRINT("Device name: '%wZ'\n", &DeviceInstance
);
776 Operation
= StatusData
->Operation
;
777 if (Operation
== PNP_SET_DEVICE_STATUS
)
779 DeviceStatus
= StatusData
->DeviceStatus
;
780 DeviceProblem
= StatusData
->DeviceProblem
;
783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
785 if (DeviceInstance
.Buffer
!= NULL
)
787 ExFreePool(DeviceInstance
.Buffer
);
789 _SEH2_YIELD(return _SEH2_GetExceptionCode());
793 /* Get the device object */
794 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
795 if (DeviceInstance
.Buffer
!= NULL
)
797 ExFreePool(DeviceInstance
.Buffer
);
799 if (DeviceObject
== NULL
)
801 return STATUS_NO_SUCH_DEVICE
;
804 DeviceNode
= IopGetDeviceNode(DeviceObject
);
808 case PNP_GET_DEVICE_STATUS
:
809 DPRINT("Get status data\n");
810 DeviceStatus
= IopGetDeviceNodeStatus(DeviceNode
);
811 DeviceProblem
= DeviceNode
->Problem
;
814 case PNP_SET_DEVICE_STATUS
:
815 DPRINT1("Set status data is NOT SUPPORTED\n");
818 case PNP_CLEAR_DEVICE_STATUS
:
819 DPRINT1("FIXME: Clear status data!\n");
823 ObDereferenceObject(DeviceObject
);
825 if (Operation
== PNP_GET_DEVICE_STATUS
)
829 StatusData
->DeviceStatus
= DeviceStatus
;
830 StatusData
->DeviceProblem
= DeviceProblem
;
832 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
834 Status
= _SEH2_GetExceptionCode();
844 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData
)
846 UNICODE_STRING DeviceInstance
;
847 PDEVICE_OBJECT DeviceObject
= NULL
;
848 IO_STACK_LOCATION Stack
;
849 IO_STATUS_BLOCK IoStatusBlock
;
850 PDEVICE_RELATIONS DeviceRelations
= NULL
;
851 PDEVICE_OBJECT ChildDeviceObject
;
852 PDEVICE_NODE ChildDeviceNode
;
855 ULONG BufferSize
, RequiredSize
;
858 NTSTATUS Status
= STATUS_SUCCESS
;
860 DPRINT("IopGetDeviceRelations() called\n");
861 DPRINT("Device name: %wZ\n", &RelationsData
->DeviceInstance
);
862 DPRINT("Relations: %lu\n", RelationsData
->Relations
);
863 DPRINT("BufferSize: %lu\n", RelationsData
->BufferSize
);
864 DPRINT("Buffer: %p\n", RelationsData
->Buffer
);
868 Relations
= RelationsData
->Relations
;
869 BufferSize
= RelationsData
->BufferSize
;
870 Buffer
= RelationsData
->Buffer
;
872 ProbeForWrite(Buffer
, BufferSize
, sizeof(CHAR
));
874 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
876 _SEH2_YIELD(return _SEH2_GetExceptionCode());
880 Status
= IopCaptureUnicodeString(&DeviceInstance
, &RelationsData
->DeviceInstance
);
881 if (!NT_SUCCESS(Status
))
883 DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status
);
887 /* Get the device object */
888 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
889 if (DeviceObject
== NULL
)
891 DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n");
892 Status
= STATUS_NO_SUCH_DEVICE
;
898 case PNP_EJECT_RELATIONS
:
899 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
902 case PNP_REMOVAL_RELATIONS
:
903 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
906 case PNP_POWER_RELATIONS
:
907 Stack
.Parameters
.QueryDeviceRelations
.Type
= PowerRelations
;
910 case PNP_BUS_RELATIONS
:
911 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
915 Status
= STATUS_INVALID_PARAMETER
;
919 Status
= IopInitiatePnpIrp(DeviceObject
,
921 IRP_MN_QUERY_DEVICE_RELATIONS
,
923 if (!NT_SUCCESS(Status
))
925 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
929 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
931 DPRINT("Found %d device relations\n", DeviceRelations
->Count
);
936 BufferLeft
= BufferSize
;
939 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
941 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
943 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
946 DPRINT("Device instance: %wZ\n", &ChildDeviceNode
->InstancePath
);
947 DPRINT("RequiredSize: %hu\n", ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
951 if (BufferLeft
< ChildDeviceNode
->InstancePath
.Length
+ 2 * sizeof(WCHAR
))
953 Status
= STATUS_BUFFER_TOO_SMALL
;
958 ChildDeviceNode
->InstancePath
.Buffer
,
959 ChildDeviceNode
->InstancePath
.Length
);
960 Ptr
= (PWCHAR
)((ULONG_PTR
)Ptr
+ ChildDeviceNode
->InstancePath
.Length
);
962 Ptr
= (PWCHAR
)((ULONG_PTR
)Ptr
+ sizeof(WCHAR
));
964 BufferLeft
-= (ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
967 RequiredSize
+= (ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
971 if (Ptr
!= NULL
&& BufferLeft
>= sizeof(WCHAR
))
974 if (RequiredSize
> 0)
975 RequiredSize
+= sizeof(WCHAR
);
977 DPRINT("BufferSize: %lu RequiredSize: %lu\n", RelationsData
->BufferSize
, RequiredSize
);
979 RelationsData
->BufferSize
= RequiredSize
;
981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
983 Status
= _SEH2_GetExceptionCode();
988 if (DeviceRelations
!= NULL
)
989 ExFreePool(DeviceRelations
);
991 if (DeviceObject
!= NULL
)
992 ObDereferenceObject(DeviceObject
);
994 if (DeviceInstance
.Buffer
!= NULL
)
995 ExFreePool(DeviceInstance
.Buffer
);
1001 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData
)
1003 PDEVICE_OBJECT DeviceObject
;
1004 PDEVICE_NODE DeviceNode
;
1005 UNICODE_STRING DeviceInstance
;
1006 NTSTATUS Status
= STATUS_SUCCESS
;
1008 DPRINT("IopGetDeviceDepth() called\n");
1009 DPRINT("Device name: %wZ\n", &DepthData
->DeviceInstance
);
1011 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DepthData
->DeviceInstance
);
1012 if (!NT_SUCCESS(Status
))
1017 /* Get the device object */
1018 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
1019 if (DeviceInstance
.Buffer
!= NULL
)
1021 ExFreePool(DeviceInstance
.Buffer
);
1023 if (DeviceObject
== NULL
)
1025 return STATUS_NO_SUCH_DEVICE
;
1028 DeviceNode
= IopGetDeviceNode(DeviceObject
);
1032 DepthData
->Depth
= DeviceNode
->Level
;
1034 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1036 Status
= _SEH2_GetExceptionCode();
1040 ObDereferenceObject(DeviceObject
);
1047 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData
)
1049 PDEVICE_OBJECT DeviceObject
;
1051 UNICODE_STRING DeviceInstance
;
1053 Status
= IopCaptureUnicodeString(&DeviceInstance
, &ResetDeviceData
->DeviceInstance
);
1054 if (!NT_SUCCESS(Status
))
1059 DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance
);
1061 /* Get the device object */
1062 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
1063 if (DeviceInstance
.Buffer
!= NULL
)
1065 ExFreePool(DeviceInstance
.Buffer
);
1067 if (DeviceObject
== NULL
)
1069 return STATUS_NO_SUCH_DEVICE
;
1072 Status
= PiPerformSyncDeviceAction(DeviceObject
, PiActionResetDevice
);
1074 ObDereferenceObject(DeviceObject
);
1079 /* PUBLIC FUNCTIONS **********************************************************/
1082 * Plug and Play event structure used by NtGetPlugPlayEvent.
1085 * Can be one of the following values:
1086 * GUID_HWPROFILE_QUERY_CHANGE
1087 * GUID_HWPROFILE_CHANGE_CANCELLED
1088 * GUID_HWPROFILE_CHANGE_COMPLETE
1089 * GUID_TARGET_DEVICE_QUERY_REMOVE
1090 * GUID_TARGET_DEVICE_REMOVE_CANCELLED
1091 * GUID_TARGET_DEVICE_REMOVE_COMPLETE
1092 * GUID_PNP_CUSTOM_NOTIFICATION
1093 * GUID_PNP_POWER_NOTIFICATION
1094 * GUID_DEVICE_* (see above)
1097 * Type of the event that happened.
1106 * Size of the event block including the device IDs and other
1107 * per category specific fields.
1111 * NtGetPlugPlayEvent
1113 * Returns one Plug & Play event from a global queue.
1118 * Always set to zero.
1121 * The buffer that will be filled with the event information on
1122 * successful return from the function.
1125 * Size of the buffer pointed by the Buffer parameter. If the
1126 * buffer size is not large enough to hold the whole event
1127 * information, error STATUS_BUFFER_TOO_SMALL is returned and
1128 * the buffer remains untouched.
1131 * STATUS_PRIVILEGE_NOT_HELD
1132 * STATUS_BUFFER_TOO_SMALL
1136 * This function isn't multi-thread safe!
1142 NtGetPlugPlayEvent(IN ULONG Reserved1
,
1144 OUT PPLUGPLAY_EVENT_BLOCK Buffer
,
1145 IN ULONG BufferSize
)
1147 PPNP_EVENT_ENTRY Entry
;
1150 DPRINT("NtGetPlugPlayEvent() called\n");
1152 /* Function can only be called from user-mode */
1153 if (KeGetPreviousMode() == KernelMode
)
1155 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1156 return STATUS_ACCESS_DENIED
;
1159 /* Check for Tcb privilege */
1160 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1163 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1164 return STATUS_PRIVILEGE_NOT_HELD
;
1167 /* Wait for a PnP event */
1168 DPRINT("Waiting for pnp notification event\n");
1169 Status
= KeWaitForSingleObject(&IopPnpNotifyEvent
,
1174 if (!NT_SUCCESS(Status
) || Status
== STATUS_USER_APC
)
1176 DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status
);
1177 ASSERT(Status
== STATUS_USER_APC
);
1181 /* Get entry from the tail of the queue */
1182 Entry
= CONTAINING_RECORD(IopPnpEventQueueHead
.Blink
,
1186 /* Check the buffer size */
1187 if (BufferSize
< Entry
->Event
.TotalSize
)
1189 DPRINT1("Buffer is too small for the pnp-event\n");
1190 return STATUS_BUFFER_TOO_SMALL
;
1193 /* Copy event data to the user buffer */
1196 ProbeForWrite(Buffer
,
1197 Entry
->Event
.TotalSize
,
1199 RtlCopyMemory(Buffer
,
1201 Entry
->Event
.TotalSize
);
1203 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1205 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1209 DPRINT("NtGetPlugPlayEvent() done\n");
1211 return STATUS_SUCCESS
;
1217 * A function for doing various Plug & Play operations from user mode.
1220 * PlugPlayControlClass
1221 * 0x00 Reenumerate device tree
1223 * Buffer points to UNICODE_STRING decribing the instance
1224 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
1225 * more information about instance paths see !devnode command
1226 * in kernel debugger or look at "Inside Windows 2000" book,
1227 * chapter "Driver Loading, Initialization, and Installation".
1229 * 0x01 Register new device
1230 * 0x02 Deregister device
1231 * 0x03 Initialize device
1233 * 0x06 Query and remove device
1234 * 0x07 User response
1236 * Called after processing the message from NtGetPlugPlayEvent.
1238 * 0x08 Generate legacy device
1239 * 0x09 Get interface device list
1240 * 0x0A Get property data
1241 * 0x0B Device class association (Registration)
1242 * 0x0C Get related device
1243 * 0x0D Get device interface alias
1244 * 0x0E Get/set/clear device status
1245 * 0x0F Get device depth
1246 * 0x10 Query device relations
1247 * 0x11 Query target device relation
1248 * 0x12 Query conflict list
1249 * 0x13 Retrieve dock data
1252 * 0x16 Get blocked driver data
1255 * The buffer contains information that is specific to each control
1256 * code. The buffer is read-only.
1259 * Size of the buffer pointed by the Buffer parameter. If the
1260 * buffer size specifies incorrect value for specified control
1261 * code, error ??? is returned.
1264 * STATUS_PRIVILEGE_NOT_HELD
1272 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass
,
1273 IN OUT PVOID Buffer
,
1274 IN ULONG BufferLength
)
1276 DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
1277 PlugPlayControlClass
, Buffer
, BufferLength
);
1279 /* Function can only be called from user-mode */
1280 if (KeGetPreviousMode() == KernelMode
)
1282 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1283 return STATUS_ACCESS_DENIED
;
1286 /* Check for Tcb privilege */
1287 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1290 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1291 return STATUS_PRIVILEGE_NOT_HELD
;
1294 /* Probe the buffer */
1297 ProbeForWrite(Buffer
,
1301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1303 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1307 switch (PlugPlayControlClass
)
1309 case PlugPlayControlEnumerateDevice
:
1310 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA
))
1311 return STATUS_INVALID_PARAMETER
;
1312 return IopPnpEnumerateDevice((PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA
)Buffer
);
1314 // case PlugPlayControlRegisterNewDevice:
1315 // case PlugPlayControlDeregisterDevice:
1316 // case PlugPlayControlInitializeDevice:
1317 // case PlugPlayControlStartDevice:
1318 // case PlugPlayControlUnlockDevice:
1319 // case PlugPlayControlQueryAndRemoveDevice:
1321 case PlugPlayControlUserResponse
:
1322 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_USER_RESPONSE_DATA
))
1323 return STATUS_INVALID_PARAMETER
;
1324 return IopRemovePlugPlayEvent((PPLUGPLAY_CONTROL_USER_RESPONSE_DATA
)Buffer
);
1326 // case PlugPlayControlGenerateLegacyDevice:
1328 case PlugPlayControlGetInterfaceDeviceList
:
1329 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
))
1330 return STATUS_INVALID_PARAMETER
;
1331 return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
)Buffer
);
1333 case PlugPlayControlProperty
:
1334 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA
))
1335 return STATUS_INVALID_PARAMETER
;
1336 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA
)Buffer
);
1338 // case PlugPlayControlDeviceClassAssociation:
1340 case PlugPlayControlGetRelatedDevice
:
1341 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
))
1342 return STATUS_INVALID_PARAMETER
;
1343 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA
)Buffer
);
1345 // case PlugPlayControlGetInterfaceDeviceAlias:
1347 case PlugPlayControlDeviceStatus
:
1348 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_STATUS_DATA
))
1349 return STATUS_INVALID_PARAMETER
;
1350 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA
)Buffer
);
1352 case PlugPlayControlGetDeviceDepth
:
1353 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEPTH_DATA
))
1354 return STATUS_INVALID_PARAMETER
;
1355 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA
)Buffer
);
1357 case PlugPlayControlQueryDeviceRelations
:
1358 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
))
1359 return STATUS_INVALID_PARAMETER
;
1360 return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
)Buffer
);
1362 // case PlugPlayControlTargetDeviceRelation:
1363 // case PlugPlayControlQueryConflictList:
1364 // case PlugPlayControlRetrieveDock:
1366 case PlugPlayControlResetDevice
:
1367 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA
))
1368 return STATUS_INVALID_PARAMETER
;
1369 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA
)Buffer
);
1371 // case PlugPlayControlHaltDevice:
1372 // case PlugPlayControlGetBlockedDriverList:
1375 return STATUS_NOT_IMPLEMENTED
;
1378 return STATUS_NOT_IMPLEMENTED
;