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 * Remove the current PnP event from the tail of the event queue
191 * and signal IopPnpNotifyEvent if there is yet another event in the queue.
195 IopRemovePlugPlayEvent(
196 _In_ PPLUGPLAY_CONTROL_USER_RESPONSE_DATA ResponseData
)
198 /* Remove a pnp event entry from the tail of the queue */
199 if (!IsListEmpty(&IopPnpEventQueueHead
))
201 ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead
), PNP_EVENT_ENTRY
, ListEntry
));
204 /* Signal the next pnp event in the queue */
205 if (!IsListEmpty(&IopPnpEventQueueHead
))
207 KeSetEvent(&IopPnpNotifyEvent
,
212 return STATUS_SUCCESS
;
217 IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList
)
220 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList
;
221 UNICODE_STRING DeviceInstance
;
222 PDEVICE_OBJECT DeviceObject
= NULL
;
224 PZZWSTR SymbolicLinkList
= NULL
, LinkList
;
229 RtlCopyMemory(&StackList
, DeviceList
, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
));
231 ProbeForRead(StackList
.FilterGuid
, sizeof(GUID
), sizeof(UCHAR
));
232 RtlCopyMemory(&FilterGuid
, StackList
.FilterGuid
, sizeof(GUID
));
234 if (StackList
.Buffer
!= NULL
&& StackList
.BufferSize
!= 0)
236 ProbeForWrite(StackList
.Buffer
, StackList
.BufferSize
, sizeof(UCHAR
));
239 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
241 _SEH2_YIELD(return _SEH2_GetExceptionCode());
245 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StackList
.DeviceInstance
);
246 if (NT_SUCCESS(Status
))
248 /* Get the device object */
249 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
250 if (DeviceInstance
.Buffer
!= NULL
)
252 ExFreePool(DeviceInstance
.Buffer
);
256 Status
= IoGetDeviceInterfaces(&FilterGuid
, DeviceObject
, StackList
.Flags
, &SymbolicLinkList
);
257 ObDereferenceObject(DeviceObject
);
259 if (!NT_SUCCESS(Status
))
265 LinkList
= SymbolicLinkList
;
266 while (*SymbolicLinkList
!= UNICODE_NULL
)
268 SymbolicLinkList
+= wcslen(SymbolicLinkList
) + (sizeof(UNICODE_NULL
) / sizeof(WCHAR
));
270 TotalLength
= ((SymbolicLinkList
- LinkList
+ 1) * sizeof(WCHAR
));
274 if (StackList
.Buffer
!= NULL
&&
275 StackList
.BufferSize
>= TotalLength
)
277 // We've already probed the buffer for writing above.
278 RtlCopyMemory(StackList
.Buffer
, LinkList
, TotalLength
);
281 DeviceList
->BufferSize
= TotalLength
;
283 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
285 ExFreePool(LinkList
);
286 _SEH2_YIELD(return _SEH2_GetExceptionCode());
290 ExFreePool(LinkList
);
291 return STATUS_SUCCESS
;
295 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData
)
297 PDEVICE_OBJECT DeviceObject
= NULL
;
298 PDEVICE_NODE DeviceNode
;
299 UNICODE_STRING DeviceInstance
;
302 DEVICE_REGISTRY_PROPERTY DeviceProperty
;
306 DPRINT("IopGetDeviceProperty() called\n");
307 DPRINT("Device name: %wZ\n", &PropertyData
->DeviceInstance
);
309 Status
= IopCaptureUnicodeString(&DeviceInstance
, &PropertyData
->DeviceInstance
);
310 if (!NT_SUCCESS(Status
))
317 Property
= PropertyData
->Property
;
318 BufferSize
= PropertyData
->BufferSize
;
319 ProbeForWrite(PropertyData
->Buffer
,
323 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
325 if (DeviceInstance
.Buffer
!= NULL
)
327 ExFreePool(DeviceInstance
.Buffer
);
329 _SEH2_YIELD(return _SEH2_GetExceptionCode());
333 /* Get the device object */
334 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
335 if (DeviceInstance
.Buffer
!= NULL
)
337 ExFreePool(DeviceInstance
.Buffer
);
339 if (DeviceObject
== NULL
)
341 return STATUS_NO_SUCH_DEVICE
;
344 Buffer
= ExAllocatePool(NonPagedPool
, BufferSize
);
347 ObDereferenceObject(DeviceObject
);
348 return STATUS_INSUFFICIENT_RESOURCES
;
352 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
354 if (Property
== PNP_PROPERTY_POWER_DATA
)
356 if (BufferSize
< sizeof(CM_POWER_DATA
))
359 Status
= STATUS_BUFFER_TOO_SMALL
;
363 DEVICE_CAPABILITIES DeviceCapabilities
;
364 PCM_POWER_DATA PowerData
;
365 IO_STACK_LOCATION Stack
;
366 IO_STATUS_BLOCK IoStatusBlock
;
368 PowerData
= (PCM_POWER_DATA
)Buffer
;
369 RtlZeroMemory(PowerData
, sizeof(CM_POWER_DATA
));
370 PowerData
->PD_Size
= sizeof(CM_POWER_DATA
);
372 RtlZeroMemory(&DeviceCapabilities
, sizeof(DEVICE_CAPABILITIES
));
373 DeviceCapabilities
.Size
= sizeof(DEVICE_CAPABILITIES
);
374 DeviceCapabilities
.Version
= 1;
375 DeviceCapabilities
.Address
= -1;
376 DeviceCapabilities
.UINumber
= -1;
378 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= &DeviceCapabilities
;
380 Status
= IopInitiatePnpIrp(DeviceObject
,
382 IRP_MN_QUERY_CAPABILITIES
,
384 if (NT_SUCCESS(Status
))
386 DPRINT("Got device capabiliities\n");
388 PowerData
->PD_MostRecentPowerState
= PowerDeviceD0
; // FIXME
389 if (DeviceCapabilities
.DeviceD1
)
390 PowerData
->PD_Capabilities
|= PDCAP_D1_SUPPORTED
;
391 if (DeviceCapabilities
.DeviceD2
)
392 PowerData
->PD_Capabilities
|= PDCAP_D2_SUPPORTED
;
393 if (DeviceCapabilities
.WakeFromD0
)
394 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D0_SUPPORTED
;
395 if (DeviceCapabilities
.WakeFromD1
)
396 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D1_SUPPORTED
;
397 if (DeviceCapabilities
.WakeFromD2
)
398 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D2_SUPPORTED
;
399 if (DeviceCapabilities
.WakeFromD3
)
400 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D3_SUPPORTED
;
401 if (DeviceCapabilities
.WarmEjectSupported
)
402 PowerData
->PD_Capabilities
|= PDCAP_WARM_EJECT_SUPPORTED
;
403 PowerData
->PD_D1Latency
= DeviceCapabilities
.D1Latency
;
404 PowerData
->PD_D2Latency
= DeviceCapabilities
.D2Latency
;
405 PowerData
->PD_D3Latency
= DeviceCapabilities
.D3Latency
;
406 RtlCopyMemory(&PowerData
->PD_PowerStateMapping
,
407 &DeviceCapabilities
.DeviceState
,
408 sizeof(DeviceCapabilities
.DeviceState
));
409 PowerData
->PD_DeepestSystemWake
= DeviceCapabilities
.SystemWake
;
413 DPRINT("IRP_MN_QUERY_CAPABILITIES failed (Status 0x%08lx)\n", Status
);
415 PowerData
->PD_Capabilities
= PDCAP_D0_SUPPORTED
| PDCAP_D3_SUPPORTED
;
416 PowerData
->PD_MostRecentPowerState
= PowerDeviceD0
;
420 else if (Property
== PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE
)
423 else if (Property
== PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT
)
425 if (BufferSize
< sizeof(DeviceNode
->HardwareRemovalPolicy
))
428 Status
= STATUS_BUFFER_TOO_SMALL
;
432 BufferSize
= sizeof(DeviceNode
->HardwareRemovalPolicy
);
433 RtlCopyMemory(Buffer
,
434 &DeviceNode
->HardwareRemovalPolicy
,
442 case PNP_PROPERTY_UI_NUMBER
:
443 DeviceProperty
= DevicePropertyUINumber
;
446 case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME
:
447 DeviceProperty
= DevicePropertyPhysicalDeviceObjectName
;
450 case PNP_PROPERTY_BUSTYPEGUID
:
451 DeviceProperty
= DevicePropertyBusTypeGuid
;
454 case PNP_PROPERTY_LEGACYBUSTYPE
:
455 DeviceProperty
= DevicePropertyLegacyBusType
;
458 case PNP_PROPERTY_BUSNUMBER
:
459 DeviceProperty
= DevicePropertyBusNumber
;
462 case PNP_PROPERTY_REMOVAL_POLICY
:
463 DeviceProperty
= DevicePropertyRemovalPolicy
;
466 case PNP_PROPERTY_ADDRESS
:
467 DeviceProperty
= DevicePropertyAddress
;
470 case PNP_PROPERTY_ENUMERATOR_NAME
:
471 DeviceProperty
= DevicePropertyEnumeratorName
;
474 case PNP_PROPERTY_INSTALL_STATE
:
475 DeviceProperty
= DevicePropertyInstallState
;
478 #if (WINVER >= _WIN32_WINNT_WS03)
479 case PNP_PROPERTY_LOCATION_PATHS
:
483 #if (WINVER >= _WIN32_WINNT_WIN7)
484 case PNP_PROPERTY_CONTAINERID
:
485 DeviceProperty
= DevicePropertyContainerID
;
491 Status
= STATUS_INVALID_PARAMETER
;
495 if (Status
== STATUS_SUCCESS
)
497 Status
= IoGetDeviceProperty(DeviceObject
,
505 ObDereferenceObject(DeviceObject
);
507 if (NT_SUCCESS(Status
))
511 RtlCopyMemory(PropertyData
->Buffer
, Buffer
, BufferSize
);
512 PropertyData
->BufferSize
= BufferSize
;
514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
516 Status
= _SEH2_GetExceptionCode();
527 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData
)
529 UNICODE_STRING RootDeviceName
;
530 PDEVICE_OBJECT DeviceObject
= NULL
;
531 PDEVICE_NODE DeviceNode
= NULL
;
532 PDEVICE_NODE RelatedDeviceNode
;
533 UNICODE_STRING TargetDeviceInstance
;
534 NTSTATUS Status
= STATUS_SUCCESS
;
536 ULONG MaximumLength
= 0;
538 DPRINT("IopGetRelatedDevice() called\n");
539 DPRINT("Device name: %wZ\n", &RelatedDeviceData
->TargetDeviceInstance
);
541 Status
= IopCaptureUnicodeString(&TargetDeviceInstance
, &RelatedDeviceData
->TargetDeviceInstance
);
542 if (!NT_SUCCESS(Status
))
549 Relation
= RelatedDeviceData
->Relation
;
550 MaximumLength
= RelatedDeviceData
->RelatedDeviceInstanceLength
;
551 ProbeForWrite(RelatedDeviceData
->RelatedDeviceInstance
,
555 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
557 if (TargetDeviceInstance
.Buffer
!= NULL
)
559 ExFreePool(TargetDeviceInstance
.Buffer
);
561 _SEH2_YIELD(return _SEH2_GetExceptionCode());
565 RtlInitUnicodeString(&RootDeviceName
,
567 if (RtlEqualUnicodeString(&TargetDeviceInstance
,
571 DeviceNode
= IopRootDeviceNode
;
572 if (TargetDeviceInstance
.Buffer
!= NULL
)
574 ExFreePool(TargetDeviceInstance
.Buffer
);
579 /* Get the device object */
580 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance
);
581 if (TargetDeviceInstance
.Buffer
!= NULL
)
583 ExFreePool(TargetDeviceInstance
.Buffer
);
585 if (DeviceObject
== NULL
)
586 return STATUS_NO_SUCH_DEVICE
;
588 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
593 case PNP_GET_PARENT_DEVICE
:
594 RelatedDeviceNode
= DeviceNode
->Parent
;
597 case PNP_GET_CHILD_DEVICE
:
598 RelatedDeviceNode
= DeviceNode
->Child
;
601 case PNP_GET_SIBLING_DEVICE
:
602 RelatedDeviceNode
= DeviceNode
->Sibling
;
606 if (DeviceObject
!= NULL
)
608 ObDereferenceObject(DeviceObject
);
611 return STATUS_INVALID_PARAMETER
;
614 if (RelatedDeviceNode
== NULL
)
618 ObDereferenceObject(DeviceObject
);
621 return STATUS_NO_SUCH_DEVICE
;
624 if (RelatedDeviceNode
->InstancePath
.Length
> MaximumLength
)
628 ObDereferenceObject(DeviceObject
);
631 return STATUS_BUFFER_TOO_SMALL
;
634 /* Copy related device instance name */
637 RtlCopyMemory(RelatedDeviceData
->RelatedDeviceInstance
,
638 RelatedDeviceNode
->InstancePath
.Buffer
,
639 RelatedDeviceNode
->InstancePath
.Length
);
640 RelatedDeviceData
->RelatedDeviceInstanceLength
= RelatedDeviceNode
->InstancePath
.Length
;
642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
644 Status
= _SEH2_GetExceptionCode();
648 if (DeviceObject
!= NULL
)
650 ObDereferenceObject(DeviceObject
);
653 DPRINT("IopGetRelatedDevice() done\n");
661 _In_ PDEVICE_NODE DeviceNode
)
663 return (DeviceNode
->State
== DeviceNodeStartPending
||
664 DeviceNode
->State
== DeviceNodeStartCompletion
||
665 DeviceNode
->State
== DeviceNodeStartPostWork
||
666 DeviceNode
->State
== DeviceNodeStarted
||
667 DeviceNode
->State
== DeviceNodeQueryStopped
||
668 DeviceNode
->State
== DeviceNodeEnumeratePending
||
669 DeviceNode
->State
== DeviceNodeEnumerateCompletion
||
670 DeviceNode
->State
== DeviceNodeStopped
||
671 DeviceNode
->State
== DeviceNodeRestartCompletion
);
675 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode
)
677 ULONG Output
= DN_NT_ENUMERATOR
| DN_NT_DRIVER
;
679 if (DeviceNode
->Parent
== IopRootDeviceNode
)
680 Output
|= DN_ROOT_ENUMERATED
;
682 // FIXME: review for deleted and removed states
683 if (DeviceNode
->State
>= DeviceNodeDriversAdded
)
684 Output
|= DN_DRIVER_LOADED
;
686 if (PiIsDevNodeStarted(DeviceNode
))
687 Output
|= DN_STARTED
;
689 if (DeviceNode
->UserFlags
& DNUF_WILL_BE_REMOVED
)
690 Output
|= DN_WILL_BE_REMOVED
;
692 if (DeviceNode
->Flags
& DNF_HAS_PROBLEM
)
693 Output
|= DN_HAS_PROBLEM
;
695 if (DeviceNode
->Flags
& DNF_HAS_PRIVATE_PROBLEM
)
696 Output
|= DN_PRIVATE_PROBLEM
;
698 if (DeviceNode
->Flags
& DNF_DRIVER_BLOCKED
)
699 Output
|= DN_DRIVER_BLOCKED
;
701 if (DeviceNode
->Flags
& DNF_CHILD_WITH_INVALID_ID
)
702 Output
|= DN_CHILD_WITH_INVALID_ID
;
704 if (DeviceNode
->Flags
& DNF_HAS_PRIVATE_PROBLEM
)
705 Output
|= DN_PRIVATE_PROBLEM
;
707 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
708 Output
|= DN_LEGACY_DRIVER
;
710 if (DeviceNode
->UserFlags
& DNUF_DONT_SHOW_IN_UI
)
711 Output
|= DN_NO_SHOW_IN_DM
;
713 if (!(DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
))
714 Output
|= DN_DISABLEABLE
;
720 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData
)
722 PDEVICE_OBJECT DeviceObject
;
723 PDEVICE_NODE DeviceNode
;
725 ULONG DeviceStatus
= 0;
726 ULONG DeviceProblem
= 0;
727 UNICODE_STRING DeviceInstance
;
730 DPRINT("IopDeviceStatus() called\n");
732 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StatusData
->DeviceInstance
);
733 if (!NT_SUCCESS(Status
))
738 DPRINT("Device name: '%wZ'\n", &DeviceInstance
);
742 Operation
= StatusData
->Operation
;
743 if (Operation
== PNP_SET_DEVICE_STATUS
)
745 DeviceStatus
= StatusData
->DeviceStatus
;
746 DeviceProblem
= StatusData
->DeviceProblem
;
749 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
751 if (DeviceInstance
.Buffer
!= NULL
)
753 ExFreePool(DeviceInstance
.Buffer
);
755 _SEH2_YIELD(return _SEH2_GetExceptionCode());
759 /* Get the device object */
760 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
761 if (DeviceInstance
.Buffer
!= NULL
)
763 ExFreePool(DeviceInstance
.Buffer
);
765 if (DeviceObject
== NULL
)
767 return STATUS_NO_SUCH_DEVICE
;
770 DeviceNode
= IopGetDeviceNode(DeviceObject
);
774 case PNP_GET_DEVICE_STATUS
:
775 DPRINT("Get status data\n");
776 DeviceStatus
= IopGetDeviceNodeStatus(DeviceNode
);
777 DeviceProblem
= DeviceNode
->Problem
;
780 case PNP_SET_DEVICE_STATUS
:
781 DPRINT1("Set status data is NOT SUPPORTED\n");
784 case PNP_CLEAR_DEVICE_STATUS
:
785 DPRINT1("FIXME: Clear status data!\n");
789 ObDereferenceObject(DeviceObject
);
791 if (Operation
== PNP_GET_DEVICE_STATUS
)
795 StatusData
->DeviceStatus
= DeviceStatus
;
796 StatusData
->DeviceProblem
= DeviceProblem
;
798 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
800 Status
= _SEH2_GetExceptionCode();
810 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData
)
812 UNICODE_STRING DeviceInstance
;
813 PDEVICE_OBJECT DeviceObject
= NULL
;
814 IO_STACK_LOCATION Stack
;
815 IO_STATUS_BLOCK IoStatusBlock
;
816 PDEVICE_RELATIONS DeviceRelations
= NULL
;
817 PDEVICE_OBJECT ChildDeviceObject
;
818 PDEVICE_NODE ChildDeviceNode
;
821 ULONG BufferSize
, RequiredSize
;
824 NTSTATUS Status
= STATUS_SUCCESS
;
826 DPRINT("IopGetDeviceRelations() called\n");
827 DPRINT("Device name: %wZ\n", &RelationsData
->DeviceInstance
);
828 DPRINT("Relations: %lu\n", RelationsData
->Relations
);
829 DPRINT("BufferSize: %lu\n", RelationsData
->BufferSize
);
830 DPRINT("Buffer: %p\n", RelationsData
->Buffer
);
834 Relations
= RelationsData
->Relations
;
835 BufferSize
= RelationsData
->BufferSize
;
836 Buffer
= RelationsData
->Buffer
;
838 ProbeForWrite(Buffer
, BufferSize
, sizeof(CHAR
));
840 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
842 _SEH2_YIELD(return _SEH2_GetExceptionCode());
846 Status
= IopCaptureUnicodeString(&DeviceInstance
, &RelationsData
->DeviceInstance
);
847 if (!NT_SUCCESS(Status
))
849 DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status
);
853 /* Get the device object */
854 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
855 if (DeviceObject
== NULL
)
857 DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n");
858 Status
= STATUS_NO_SUCH_DEVICE
;
864 case PNP_EJECT_RELATIONS
:
865 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
868 case PNP_REMOVAL_RELATIONS
:
869 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
872 case PNP_POWER_RELATIONS
:
873 Stack
.Parameters
.QueryDeviceRelations
.Type
= PowerRelations
;
876 case PNP_BUS_RELATIONS
:
877 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
881 Status
= STATUS_INVALID_PARAMETER
;
885 Status
= IopInitiatePnpIrp(DeviceObject
,
887 IRP_MN_QUERY_DEVICE_RELATIONS
,
889 if (!NT_SUCCESS(Status
))
891 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
895 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
897 DPRINT("Found %d device relations\n", DeviceRelations
->Count
);
902 BufferLeft
= BufferSize
;
905 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
907 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
909 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
912 DPRINT("Device instance: %wZ\n", &ChildDeviceNode
->InstancePath
);
913 DPRINT("RequiredSize: %hu\n", ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
917 if (BufferLeft
< ChildDeviceNode
->InstancePath
.Length
+ 2 * sizeof(WCHAR
))
919 Status
= STATUS_BUFFER_TOO_SMALL
;
924 ChildDeviceNode
->InstancePath
.Buffer
,
925 ChildDeviceNode
->InstancePath
.Length
);
926 Ptr
= (PWCHAR
)((ULONG_PTR
)Ptr
+ ChildDeviceNode
->InstancePath
.Length
);
928 Ptr
= (PWCHAR
)((ULONG_PTR
)Ptr
+ sizeof(WCHAR
));
930 BufferLeft
-= (ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
933 RequiredSize
+= (ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
937 if (Ptr
!= NULL
&& BufferLeft
>= sizeof(WCHAR
))
940 if (RequiredSize
> 0)
941 RequiredSize
+= sizeof(WCHAR
);
943 DPRINT("BufferSize: %lu RequiredSize: %lu\n", RelationsData
->BufferSize
, RequiredSize
);
945 RelationsData
->BufferSize
= RequiredSize
;
947 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
949 Status
= _SEH2_GetExceptionCode();
954 if (DeviceRelations
!= NULL
)
955 ExFreePool(DeviceRelations
);
957 if (DeviceObject
!= NULL
)
958 ObDereferenceObject(DeviceObject
);
960 if (DeviceInstance
.Buffer
!= NULL
)
961 ExFreePool(DeviceInstance
.Buffer
);
967 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData
)
969 PDEVICE_OBJECT DeviceObject
;
970 PDEVICE_NODE DeviceNode
;
971 UNICODE_STRING DeviceInstance
;
972 NTSTATUS Status
= STATUS_SUCCESS
;
974 DPRINT("IopGetDeviceDepth() called\n");
975 DPRINT("Device name: %wZ\n", &DepthData
->DeviceInstance
);
977 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DepthData
->DeviceInstance
);
978 if (!NT_SUCCESS(Status
))
983 /* Get the device object */
984 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
985 if (DeviceInstance
.Buffer
!= NULL
)
987 ExFreePool(DeviceInstance
.Buffer
);
989 if (DeviceObject
== NULL
)
991 return STATUS_NO_SUCH_DEVICE
;
994 DeviceNode
= IopGetDeviceNode(DeviceObject
);
998 DepthData
->Depth
= DeviceNode
->Level
;
1000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1002 Status
= _SEH2_GetExceptionCode();
1006 ObDereferenceObject(DeviceObject
);
1013 PiControlSyncDeviceAction(
1014 _In_ PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA DeviceData
,
1015 _In_ PLUGPLAY_CONTROL_CLASS ControlClass
)
1017 PDEVICE_OBJECT DeviceObject
;
1019 UNICODE_STRING DeviceInstance
;
1021 ASSERT(ControlClass
== PlugPlayControlEnumerateDevice
||
1022 ControlClass
== PlugPlayControlStartDevice
||
1023 ControlClass
== PlugPlayControlResetDevice
);
1025 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DeviceData
->DeviceInstance
);
1026 if (!NT_SUCCESS(Status
))
1031 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
1032 if (DeviceInstance
.Buffer
!= NULL
)
1034 ExFreePool(DeviceInstance
.Buffer
);
1036 if (DeviceObject
== NULL
)
1038 return STATUS_NO_SUCH_DEVICE
;
1041 DEVICE_ACTION Action
;
1043 switch (ControlClass
)
1045 case PlugPlayControlEnumerateDevice
:
1046 Action
= PiActionEnumDeviceTree
;
1048 case PlugPlayControlStartDevice
:
1049 Action
= PiActionStartDevice
;
1051 case PlugPlayControlResetDevice
:
1052 Action
= PiActionResetDevice
;
1059 Status
= PiPerformSyncDeviceAction(DeviceObject
, Action
);
1061 ObDereferenceObject(DeviceObject
);
1066 /* PUBLIC FUNCTIONS **********************************************************/
1069 * Plug and Play event structure used by NtGetPlugPlayEvent.
1072 * Can be one of the following values:
1073 * GUID_HWPROFILE_QUERY_CHANGE
1074 * GUID_HWPROFILE_CHANGE_CANCELLED
1075 * GUID_HWPROFILE_CHANGE_COMPLETE
1076 * GUID_TARGET_DEVICE_QUERY_REMOVE
1077 * GUID_TARGET_DEVICE_REMOVE_CANCELLED
1078 * GUID_TARGET_DEVICE_REMOVE_COMPLETE
1079 * GUID_PNP_CUSTOM_NOTIFICATION
1080 * GUID_PNP_POWER_NOTIFICATION
1081 * GUID_DEVICE_* (see above)
1084 * Type of the event that happened.
1093 * Size of the event block including the device IDs and other
1094 * per category specific fields.
1098 * NtGetPlugPlayEvent
1100 * Returns one Plug & Play event from a global queue.
1105 * Always set to zero.
1108 * The buffer that will be filled with the event information on
1109 * successful return from the function.
1112 * Size of the buffer pointed by the Buffer parameter. If the
1113 * buffer size is not large enough to hold the whole event
1114 * information, error STATUS_BUFFER_TOO_SMALL is returned and
1115 * the buffer remains untouched.
1118 * STATUS_PRIVILEGE_NOT_HELD
1119 * STATUS_BUFFER_TOO_SMALL
1123 * This function isn't multi-thread safe!
1129 NtGetPlugPlayEvent(IN ULONG Reserved1
,
1131 OUT PPLUGPLAY_EVENT_BLOCK Buffer
,
1132 IN ULONG BufferSize
)
1134 PPNP_EVENT_ENTRY Entry
;
1137 DPRINT("NtGetPlugPlayEvent() called\n");
1139 /* Function can only be called from user-mode */
1140 if (KeGetPreviousMode() == KernelMode
)
1142 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1143 return STATUS_ACCESS_DENIED
;
1146 /* Check for Tcb privilege */
1147 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1150 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1151 return STATUS_PRIVILEGE_NOT_HELD
;
1154 /* Wait for a PnP event */
1155 DPRINT("Waiting for pnp notification event\n");
1156 Status
= KeWaitForSingleObject(&IopPnpNotifyEvent
,
1161 if (!NT_SUCCESS(Status
) || Status
== STATUS_USER_APC
)
1163 DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status
);
1164 ASSERT(Status
== STATUS_USER_APC
);
1168 /* Get entry from the tail of the queue */
1169 Entry
= CONTAINING_RECORD(IopPnpEventQueueHead
.Blink
,
1173 /* Check the buffer size */
1174 if (BufferSize
< Entry
->Event
.TotalSize
)
1176 DPRINT1("Buffer is too small for the pnp-event\n");
1177 return STATUS_BUFFER_TOO_SMALL
;
1180 /* Copy event data to the user buffer */
1183 ProbeForWrite(Buffer
,
1184 Entry
->Event
.TotalSize
,
1186 RtlCopyMemory(Buffer
,
1188 Entry
->Event
.TotalSize
);
1190 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1192 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1196 DPRINT("NtGetPlugPlayEvent() done\n");
1198 return STATUS_SUCCESS
;
1204 * A function for doing various Plug & Play operations from user mode.
1207 * PlugPlayControlClass
1208 * 0x00 Reenumerate device tree
1210 * Buffer points to UNICODE_STRING decribing the instance
1211 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
1212 * more information about instance paths see !devnode command
1213 * in kernel debugger or look at "Inside Windows 2000" book,
1214 * chapter "Driver Loading, Initialization, and Installation".
1216 * 0x01 Register new device
1217 * 0x02 Deregister device
1218 * 0x03 Initialize device
1220 * 0x06 Query and remove device
1221 * 0x07 User response
1223 * Called after processing the message from NtGetPlugPlayEvent.
1225 * 0x08 Generate legacy device
1226 * 0x09 Get interface device list
1227 * 0x0A Get property data
1228 * 0x0B Device class association (Registration)
1229 * 0x0C Get related device
1230 * 0x0D Get device interface alias
1231 * 0x0E Get/set/clear device status
1232 * 0x0F Get device depth
1233 * 0x10 Query device relations
1234 * 0x11 Query target device relation
1235 * 0x12 Query conflict list
1236 * 0x13 Retrieve dock data
1239 * 0x16 Get blocked driver data
1242 * The buffer contains information that is specific to each control
1243 * code. The buffer is read-only.
1246 * Size of the buffer pointed by the Buffer parameter. If the
1247 * buffer size specifies incorrect value for specified control
1248 * code, error ??? is returned.
1251 * STATUS_PRIVILEGE_NOT_HELD
1259 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass
,
1260 IN OUT PVOID Buffer
,
1261 IN ULONG BufferLength
)
1263 DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
1264 PlugPlayControlClass
, Buffer
, BufferLength
);
1266 /* Function can only be called from user-mode */
1267 if (KeGetPreviousMode() == KernelMode
)
1269 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1270 return STATUS_ACCESS_DENIED
;
1273 /* Check for Tcb privilege */
1274 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1277 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1278 return STATUS_PRIVILEGE_NOT_HELD
;
1281 /* Probe the buffer */
1284 ProbeForWrite(Buffer
,
1288 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1290 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1294 switch (PlugPlayControlClass
)
1296 case PlugPlayControlEnumerateDevice
:
1297 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA
))
1298 return STATUS_INVALID_PARAMETER
;
1299 // the Flags field is not used anyway
1300 return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA
)Buffer
,
1301 PlugPlayControlClass
);
1303 // case PlugPlayControlRegisterNewDevice:
1304 // case PlugPlayControlDeregisterDevice:
1305 // case PlugPlayControlInitializeDevice:
1307 case PlugPlayControlStartDevice
:
1308 case PlugPlayControlResetDevice
:
1309 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEVICE_CONTROL_DATA
))
1310 return STATUS_INVALID_PARAMETER
;
1311 return PiControlSyncDeviceAction((PPLUGPLAY_CONTROL_DEVICE_CONTROL_DATA
)Buffer
,
1312 PlugPlayControlClass
);
1314 // case PlugPlayControlUnlockDevice:
1315 // case PlugPlayControlQueryAndRemoveDevice:
1317 case PlugPlayControlUserResponse
:
1318 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_USER_RESPONSE_DATA
))
1319 return STATUS_INVALID_PARAMETER
;
1320 return IopRemovePlugPlayEvent((PPLUGPLAY_CONTROL_USER_RESPONSE_DATA
)Buffer
);
1322 // case PlugPlayControlGenerateLegacyDevice:
1324 case PlugPlayControlGetInterfaceDeviceList
:
1325 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
))
1326 return STATUS_INVALID_PARAMETER
;
1327 return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
)Buffer
);
1329 case PlugPlayControlProperty
:
1330 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA
))
1331 return STATUS_INVALID_PARAMETER
;
1332 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA
)Buffer
);
1334 // case PlugPlayControlDeviceClassAssociation:
1336 case PlugPlayControlGetRelatedDevice
:
1337 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
))
1338 return STATUS_INVALID_PARAMETER
;
1339 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA
)Buffer
);
1341 // case PlugPlayControlGetInterfaceDeviceAlias:
1343 case PlugPlayControlDeviceStatus
:
1344 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_STATUS_DATA
))
1345 return STATUS_INVALID_PARAMETER
;
1346 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA
)Buffer
);
1348 case PlugPlayControlGetDeviceDepth
:
1349 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEPTH_DATA
))
1350 return STATUS_INVALID_PARAMETER
;
1351 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA
)Buffer
);
1353 case PlugPlayControlQueryDeviceRelations
:
1354 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
))
1355 return STATUS_INVALID_PARAMETER
;
1356 return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
)Buffer
);
1358 // case PlugPlayControlTargetDeviceRelation:
1359 // case PlugPlayControlQueryConflictList:
1360 // case PlugPlayControlRetrieveDock:
1361 // case PlugPlayControlHaltDevice:
1362 // case PlugPlayControlGetBlockedDriverList:
1365 return STATUS_NOT_IMPLEMENTED
;
1368 return STATUS_NOT_IMPLEMENTED
;