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 IopPnpEnumerateDevice(PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA DeviceData
)
218 PDEVICE_OBJECT DeviceObject
;
219 UNICODE_STRING DeviceInstance
;
220 NTSTATUS Status
= STATUS_SUCCESS
;
222 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DeviceData
->DeviceInstance
);
223 if (!NT_SUCCESS(Status
))
228 DPRINT("IopPnpEnumerateDevice(%wZ)\n", &DeviceInstance
);
230 /* Get the device object */
231 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
232 if (DeviceInstance
.Buffer
!= NULL
)
234 ExFreePool(DeviceInstance
.Buffer
);
236 if (DeviceObject
== NULL
)
238 return STATUS_NO_SUCH_DEVICE
;
241 Status
= IopEnumerateDevice(DeviceObject
);
243 ObDereferenceObject(DeviceObject
);
249 IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList
)
252 PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList
;
253 UNICODE_STRING DeviceInstance
;
254 PDEVICE_OBJECT DeviceObject
= NULL
;
256 PZZWSTR SymbolicLinkList
= NULL
, LinkList
;
261 RtlCopyMemory(&StackList
, DeviceList
, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
));
263 ProbeForRead(StackList
.FilterGuid
, sizeof(GUID
), sizeof(UCHAR
));
264 RtlCopyMemory(&FilterGuid
, StackList
.FilterGuid
, sizeof(GUID
));
266 if (StackList
.Buffer
!= NULL
&& StackList
.BufferSize
!= 0)
268 ProbeForWrite(StackList
.Buffer
, StackList
.BufferSize
, sizeof(UCHAR
));
271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
273 _SEH2_YIELD(return _SEH2_GetExceptionCode());
277 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StackList
.DeviceInstance
);
278 if (NT_SUCCESS(Status
))
280 /* Get the device object */
281 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
282 if (DeviceInstance
.Buffer
!= NULL
)
284 ExFreePool(DeviceInstance
.Buffer
);
288 Status
= IoGetDeviceInterfaces(&FilterGuid
, DeviceObject
, StackList
.Flags
, &SymbolicLinkList
);
289 ObDereferenceObject(DeviceObject
);
291 if (!NT_SUCCESS(Status
))
297 LinkList
= SymbolicLinkList
;
298 while (*SymbolicLinkList
!= UNICODE_NULL
)
300 SymbolicLinkList
+= wcslen(SymbolicLinkList
) + (sizeof(UNICODE_NULL
) / sizeof(WCHAR
));
302 TotalLength
= ((SymbolicLinkList
- LinkList
+ 1) * sizeof(WCHAR
));
306 if (StackList
.Buffer
!= NULL
&&
307 StackList
.BufferSize
>= TotalLength
)
309 // We've already probed the buffer for writing above.
310 RtlCopyMemory(StackList
.Buffer
, LinkList
, TotalLength
);
313 DeviceList
->BufferSize
= TotalLength
;
315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
317 ExFreePool(LinkList
);
318 _SEH2_YIELD(return _SEH2_GetExceptionCode());
322 ExFreePool(LinkList
);
323 return STATUS_SUCCESS
;
327 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData
)
329 PDEVICE_OBJECT DeviceObject
= NULL
;
330 PDEVICE_NODE DeviceNode
;
331 UNICODE_STRING DeviceInstance
;
334 DEVICE_REGISTRY_PROPERTY DeviceProperty
;
338 DPRINT("IopGetDeviceProperty() called\n");
339 DPRINT("Device name: %wZ\n", &PropertyData
->DeviceInstance
);
341 Status
= IopCaptureUnicodeString(&DeviceInstance
, &PropertyData
->DeviceInstance
);
342 if (!NT_SUCCESS(Status
))
349 Property
= PropertyData
->Property
;
350 BufferSize
= PropertyData
->BufferSize
;
351 ProbeForWrite(PropertyData
->Buffer
,
355 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
357 if (DeviceInstance
.Buffer
!= NULL
)
359 ExFreePool(DeviceInstance
.Buffer
);
361 _SEH2_YIELD(return _SEH2_GetExceptionCode());
365 /* Get the device object */
366 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
367 if (DeviceInstance
.Buffer
!= NULL
)
369 ExFreePool(DeviceInstance
.Buffer
);
371 if (DeviceObject
== NULL
)
373 return STATUS_NO_SUCH_DEVICE
;
376 Buffer
= ExAllocatePool(NonPagedPool
, BufferSize
);
379 ObDereferenceObject(DeviceObject
);
380 return STATUS_INSUFFICIENT_RESOURCES
;
384 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
386 if (Property
== PNP_PROPERTY_POWER_DATA
)
388 if (BufferSize
< sizeof(CM_POWER_DATA
))
391 Status
= STATUS_BUFFER_TOO_SMALL
;
395 DEVICE_CAPABILITIES DeviceCapabilities
;
396 PCM_POWER_DATA PowerData
;
397 IO_STACK_LOCATION Stack
;
398 IO_STATUS_BLOCK IoStatusBlock
;
400 PowerData
= (PCM_POWER_DATA
)Buffer
;
401 RtlZeroMemory(PowerData
, sizeof(CM_POWER_DATA
));
402 PowerData
->PD_Size
= sizeof(CM_POWER_DATA
);
404 RtlZeroMemory(&DeviceCapabilities
, sizeof(DEVICE_CAPABILITIES
));
405 DeviceCapabilities
.Size
= sizeof(DEVICE_CAPABILITIES
);
406 DeviceCapabilities
.Version
= 1;
407 DeviceCapabilities
.Address
= -1;
408 DeviceCapabilities
.UINumber
= -1;
410 Stack
.Parameters
.DeviceCapabilities
.Capabilities
= &DeviceCapabilities
;
412 Status
= IopInitiatePnpIrp(DeviceObject
,
414 IRP_MN_QUERY_CAPABILITIES
,
416 if (NT_SUCCESS(Status
))
418 DPRINT("Got device capabiliities\n");
420 PowerData
->PD_MostRecentPowerState
= PowerDeviceD0
; // FIXME
421 if (DeviceCapabilities
.DeviceD1
)
422 PowerData
->PD_Capabilities
|= PDCAP_D1_SUPPORTED
;
423 if (DeviceCapabilities
.DeviceD2
)
424 PowerData
->PD_Capabilities
|= PDCAP_D2_SUPPORTED
;
425 if (DeviceCapabilities
.WakeFromD0
)
426 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D0_SUPPORTED
;
427 if (DeviceCapabilities
.WakeFromD1
)
428 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D1_SUPPORTED
;
429 if (DeviceCapabilities
.WakeFromD2
)
430 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D2_SUPPORTED
;
431 if (DeviceCapabilities
.WakeFromD3
)
432 PowerData
->PD_Capabilities
|= PDCAP_WAKE_FROM_D3_SUPPORTED
;
433 if (DeviceCapabilities
.WarmEjectSupported
)
434 PowerData
->PD_Capabilities
|= PDCAP_WARM_EJECT_SUPPORTED
;
435 PowerData
->PD_D1Latency
= DeviceCapabilities
.D1Latency
;
436 PowerData
->PD_D2Latency
= DeviceCapabilities
.D2Latency
;
437 PowerData
->PD_D3Latency
= DeviceCapabilities
.D3Latency
;
438 RtlCopyMemory(&PowerData
->PD_PowerStateMapping
,
439 &DeviceCapabilities
.DeviceState
,
440 sizeof(DeviceCapabilities
.DeviceState
));
441 PowerData
->PD_DeepestSystemWake
= DeviceCapabilities
.SystemWake
;
445 DPRINT("IRP_MN_QUERY_CAPABILITIES failed (Status 0x%08lx)\n", Status
);
447 PowerData
->PD_Capabilities
= PDCAP_D0_SUPPORTED
| PDCAP_D3_SUPPORTED
;
448 PowerData
->PD_MostRecentPowerState
= PowerDeviceD0
;
452 else if (Property
== PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE
)
455 else if (Property
== PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT
)
457 if (BufferSize
< sizeof(DeviceNode
->HardwareRemovalPolicy
))
460 Status
= STATUS_BUFFER_TOO_SMALL
;
464 BufferSize
= sizeof(DeviceNode
->HardwareRemovalPolicy
);
465 RtlCopyMemory(Buffer
,
466 &DeviceNode
->HardwareRemovalPolicy
,
474 case PNP_PROPERTY_UI_NUMBER
:
475 DeviceProperty
= DevicePropertyUINumber
;
478 case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME
:
479 DeviceProperty
= DevicePropertyPhysicalDeviceObjectName
;
482 case PNP_PROPERTY_BUSTYPEGUID
:
483 DeviceProperty
= DevicePropertyBusTypeGuid
;
486 case PNP_PROPERTY_LEGACYBUSTYPE
:
487 DeviceProperty
= DevicePropertyLegacyBusType
;
490 case PNP_PROPERTY_BUSNUMBER
:
491 DeviceProperty
= DevicePropertyBusNumber
;
494 case PNP_PROPERTY_REMOVAL_POLICY
:
495 DeviceProperty
= DevicePropertyRemovalPolicy
;
498 case PNP_PROPERTY_ADDRESS
:
499 DeviceProperty
= DevicePropertyAddress
;
502 case PNP_PROPERTY_ENUMERATOR_NAME
:
503 DeviceProperty
= DevicePropertyEnumeratorName
;
506 case PNP_PROPERTY_INSTALL_STATE
:
507 DeviceProperty
= DevicePropertyInstallState
;
510 #if (WINVER >= _WIN32_WINNT_WS03)
511 case PNP_PROPERTY_LOCATION_PATHS
:
515 #if (WINVER >= _WIN32_WINNT_WIN7)
516 case PNP_PROPERTY_CONTAINERID
:
517 DeviceProperty
= DevicePropertyContainerID
;
523 Status
= STATUS_INVALID_PARAMETER
;
527 if (Status
== STATUS_SUCCESS
)
529 Status
= IoGetDeviceProperty(DeviceObject
,
537 ObDereferenceObject(DeviceObject
);
539 if (NT_SUCCESS(Status
))
543 RtlCopyMemory(PropertyData
->Buffer
, Buffer
, BufferSize
);
544 PropertyData
->BufferSize
= BufferSize
;
546 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
548 Status
= _SEH2_GetExceptionCode();
559 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData
)
561 UNICODE_STRING RootDeviceName
;
562 PDEVICE_OBJECT DeviceObject
= NULL
;
563 PDEVICE_NODE DeviceNode
= NULL
;
564 PDEVICE_NODE RelatedDeviceNode
;
565 UNICODE_STRING TargetDeviceInstance
;
566 NTSTATUS Status
= STATUS_SUCCESS
;
568 ULONG MaximumLength
= 0;
570 DPRINT("IopGetRelatedDevice() called\n");
571 DPRINT("Device name: %wZ\n", &RelatedDeviceData
->TargetDeviceInstance
);
573 Status
= IopCaptureUnicodeString(&TargetDeviceInstance
, &RelatedDeviceData
->TargetDeviceInstance
);
574 if (!NT_SUCCESS(Status
))
581 Relation
= RelatedDeviceData
->Relation
;
582 MaximumLength
= RelatedDeviceData
->RelatedDeviceInstanceLength
;
583 ProbeForWrite(RelatedDeviceData
->RelatedDeviceInstance
,
587 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
589 if (TargetDeviceInstance
.Buffer
!= NULL
)
591 ExFreePool(TargetDeviceInstance
.Buffer
);
593 _SEH2_YIELD(return _SEH2_GetExceptionCode());
597 RtlInitUnicodeString(&RootDeviceName
,
599 if (RtlEqualUnicodeString(&TargetDeviceInstance
,
603 DeviceNode
= IopRootDeviceNode
;
604 if (TargetDeviceInstance
.Buffer
!= NULL
)
606 ExFreePool(TargetDeviceInstance
.Buffer
);
611 /* Get the device object */
612 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance
);
613 if (TargetDeviceInstance
.Buffer
!= NULL
)
615 ExFreePool(TargetDeviceInstance
.Buffer
);
617 if (DeviceObject
== NULL
)
618 return STATUS_NO_SUCH_DEVICE
;
620 DeviceNode
= ((PEXTENDED_DEVOBJ_EXTENSION
)DeviceObject
->DeviceObjectExtension
)->DeviceNode
;
625 case PNP_GET_PARENT_DEVICE
:
626 RelatedDeviceNode
= DeviceNode
->Parent
;
629 case PNP_GET_CHILD_DEVICE
:
630 RelatedDeviceNode
= DeviceNode
->Child
;
633 case PNP_GET_SIBLING_DEVICE
:
634 RelatedDeviceNode
= DeviceNode
->Sibling
;
638 if (DeviceObject
!= NULL
)
640 ObDereferenceObject(DeviceObject
);
643 return STATUS_INVALID_PARAMETER
;
646 if (RelatedDeviceNode
== NULL
)
650 ObDereferenceObject(DeviceObject
);
653 return STATUS_NO_SUCH_DEVICE
;
656 if (RelatedDeviceNode
->InstancePath
.Length
> MaximumLength
)
660 ObDereferenceObject(DeviceObject
);
663 return STATUS_BUFFER_TOO_SMALL
;
666 /* Copy related device instance name */
669 RtlCopyMemory(RelatedDeviceData
->RelatedDeviceInstance
,
670 RelatedDeviceNode
->InstancePath
.Buffer
,
671 RelatedDeviceNode
->InstancePath
.Length
);
672 RelatedDeviceData
->RelatedDeviceInstanceLength
= RelatedDeviceNode
->InstancePath
.Length
;
674 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
676 Status
= _SEH2_GetExceptionCode();
680 if (DeviceObject
!= NULL
)
682 ObDereferenceObject(DeviceObject
);
685 DPRINT("IopGetRelatedDevice() done\n");
691 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode
)
695 if (DeviceNode
->Parent
== IopRootDeviceNode
)
696 Output
|= DN_ROOT_ENUMERATED
;
698 if (DeviceNode
->Flags
& DNF_ADDED
)
699 Output
|= DN_DRIVER_LOADED
;
701 /* FIXME: DN_ENUM_LOADED */
703 if (DeviceNode
->Flags
& DNF_STARTED
)
704 Output
|= DN_STARTED
;
708 if (!(DeviceNode
->Flags
& DNF_PROCESSED
))
709 Output
|= DN_NEED_TO_ENUM
;
711 /* DN_NOT_FIRST_TIME is 9x only */
713 /* FIXME: DN_HARDWARE_ENUM */
715 /* DN_LIAR and DN_HAS_MARK are 9x only */
717 if (DeviceNode
->Problem
!= 0)
718 Output
|= DN_HAS_PROBLEM
;
720 /* FIXME: DN_FILTERED */
722 if (DeviceNode
->Flags
& DNF_LEGACY_DRIVER
)
723 Output
|= DN_LEGACY_DRIVER
;
725 if (DeviceNode
->UserFlags
& DNUF_DONT_SHOW_IN_UI
)
726 Output
|= DN_NO_SHOW_IN_DM
;
728 if (!(DeviceNode
->UserFlags
& DNUF_NOT_DISABLEABLE
))
729 Output
|= DN_DISABLEABLE
;
731 /* FIXME: Implement the rest */
733 Output
|= DN_NT_ENUMERATOR
| DN_NT_DRIVER
;
739 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData
)
741 PDEVICE_OBJECT DeviceObject
;
742 PDEVICE_NODE DeviceNode
;
744 ULONG DeviceStatus
= 0;
745 ULONG DeviceProblem
= 0;
746 UNICODE_STRING DeviceInstance
;
749 DPRINT("IopDeviceStatus() called\n");
751 Status
= IopCaptureUnicodeString(&DeviceInstance
, &StatusData
->DeviceInstance
);
752 if (!NT_SUCCESS(Status
))
757 DPRINT("Device name: '%wZ'\n", &DeviceInstance
);
761 Operation
= StatusData
->Operation
;
762 if (Operation
== PNP_SET_DEVICE_STATUS
)
764 DeviceStatus
= StatusData
->DeviceStatus
;
765 DeviceProblem
= StatusData
->DeviceProblem
;
768 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
770 if (DeviceInstance
.Buffer
!= NULL
)
772 ExFreePool(DeviceInstance
.Buffer
);
774 _SEH2_YIELD(return _SEH2_GetExceptionCode());
778 /* Get the device object */
779 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
780 if (DeviceInstance
.Buffer
!= NULL
)
782 ExFreePool(DeviceInstance
.Buffer
);
784 if (DeviceObject
== NULL
)
786 return STATUS_NO_SUCH_DEVICE
;
789 DeviceNode
= IopGetDeviceNode(DeviceObject
);
793 case PNP_GET_DEVICE_STATUS
:
794 DPRINT("Get status data\n");
795 DeviceStatus
= IopGetDeviceNodeStatus(DeviceNode
);
796 DeviceProblem
= DeviceNode
->Problem
;
799 case PNP_SET_DEVICE_STATUS
:
800 DPRINT1("Set status data is NOT SUPPORTED\n");
803 case PNP_CLEAR_DEVICE_STATUS
:
804 DPRINT1("FIXME: Clear status data!\n");
808 ObDereferenceObject(DeviceObject
);
810 if (Operation
== PNP_GET_DEVICE_STATUS
)
814 StatusData
->DeviceStatus
= DeviceStatus
;
815 StatusData
->DeviceProblem
= DeviceProblem
;
817 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
819 Status
= _SEH2_GetExceptionCode();
829 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData
)
831 UNICODE_STRING DeviceInstance
;
832 PDEVICE_OBJECT DeviceObject
= NULL
;
833 IO_STACK_LOCATION Stack
;
834 IO_STATUS_BLOCK IoStatusBlock
;
835 PDEVICE_RELATIONS DeviceRelations
= NULL
;
836 PDEVICE_OBJECT ChildDeviceObject
;
837 PDEVICE_NODE ChildDeviceNode
;
840 ULONG BufferSize
, RequiredSize
;
843 NTSTATUS Status
= STATUS_SUCCESS
;
845 DPRINT("IopGetDeviceRelations() called\n");
846 DPRINT("Device name: %wZ\n", &RelationsData
->DeviceInstance
);
847 DPRINT("Relations: %lu\n", RelationsData
->Relations
);
848 DPRINT("BufferSize: %lu\n", RelationsData
->BufferSize
);
849 DPRINT("Buffer: %p\n", RelationsData
->Buffer
);
853 Relations
= RelationsData
->Relations
;
854 BufferSize
= RelationsData
->BufferSize
;
855 Buffer
= RelationsData
->Buffer
;
857 ProbeForWrite(Buffer
, BufferSize
, sizeof(CHAR
));
859 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
861 _SEH2_YIELD(return _SEH2_GetExceptionCode());
865 Status
= IopCaptureUnicodeString(&DeviceInstance
, &RelationsData
->DeviceInstance
);
866 if (!NT_SUCCESS(Status
))
868 DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status
);
872 /* Get the device object */
873 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
874 if (DeviceObject
== NULL
)
876 DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n");
877 Status
= STATUS_NO_SUCH_DEVICE
;
883 case PNP_EJECT_RELATIONS
:
884 Stack
.Parameters
.QueryDeviceRelations
.Type
= EjectionRelations
;
887 case PNP_REMOVAL_RELATIONS
:
888 Stack
.Parameters
.QueryDeviceRelations
.Type
= RemovalRelations
;
891 case PNP_POWER_RELATIONS
:
892 Stack
.Parameters
.QueryDeviceRelations
.Type
= PowerRelations
;
895 case PNP_BUS_RELATIONS
:
896 Stack
.Parameters
.QueryDeviceRelations
.Type
= BusRelations
;
900 Status
= STATUS_INVALID_PARAMETER
;
904 Status
= IopInitiatePnpIrp(DeviceObject
,
906 IRP_MN_QUERY_DEVICE_RELATIONS
,
908 if (!NT_SUCCESS(Status
))
910 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status
);
914 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
916 DPRINT("Found %d device relations\n", DeviceRelations
->Count
);
921 BufferLeft
= BufferSize
;
924 for (i
= 0; i
< DeviceRelations
->Count
; i
++)
926 ChildDeviceObject
= DeviceRelations
->Objects
[i
];
928 ChildDeviceNode
= IopGetDeviceNode(ChildDeviceObject
);
931 DPRINT("Device instance: %wZ\n", &ChildDeviceNode
->InstancePath
);
932 DPRINT("RequiredSize: %hu\n", ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
936 if (BufferLeft
< ChildDeviceNode
->InstancePath
.Length
+ 2 * sizeof(WCHAR
))
938 Status
= STATUS_BUFFER_TOO_SMALL
;
943 ChildDeviceNode
->InstancePath
.Buffer
,
944 ChildDeviceNode
->InstancePath
.Length
);
945 Ptr
= (PWCHAR
)((ULONG_PTR
)Ptr
+ ChildDeviceNode
->InstancePath
.Length
);
947 Ptr
= (PWCHAR
)((ULONG_PTR
)Ptr
+ sizeof(WCHAR
));
949 BufferLeft
-= (ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
952 RequiredSize
+= (ChildDeviceNode
->InstancePath
.Length
+ sizeof(WCHAR
));
956 if (Ptr
!= NULL
&& BufferLeft
>= sizeof(WCHAR
))
959 if (RequiredSize
> 0)
960 RequiredSize
+= sizeof(WCHAR
);
962 DPRINT("BufferSize: %lu RequiredSize: %lu\n", RelationsData
->BufferSize
, RequiredSize
);
964 RelationsData
->BufferSize
= RequiredSize
;
966 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
968 Status
= _SEH2_GetExceptionCode();
973 if (DeviceRelations
!= NULL
)
974 ExFreePool(DeviceRelations
);
976 if (DeviceObject
!= NULL
)
977 ObDereferenceObject(DeviceObject
);
979 if (DeviceInstance
.Buffer
!= NULL
)
980 ExFreePool(DeviceInstance
.Buffer
);
986 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData
)
988 PDEVICE_OBJECT DeviceObject
;
989 PDEVICE_NODE DeviceNode
;
990 UNICODE_STRING DeviceInstance
;
991 NTSTATUS Status
= STATUS_SUCCESS
;
993 DPRINT("IopGetDeviceDepth() called\n");
994 DPRINT("Device name: %wZ\n", &DepthData
->DeviceInstance
);
996 Status
= IopCaptureUnicodeString(&DeviceInstance
, &DepthData
->DeviceInstance
);
997 if (!NT_SUCCESS(Status
))
1002 /* Get the device object */
1003 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
1004 if (DeviceInstance
.Buffer
!= NULL
)
1006 ExFreePool(DeviceInstance
.Buffer
);
1008 if (DeviceObject
== NULL
)
1010 return STATUS_NO_SUCH_DEVICE
;
1013 DeviceNode
= IopGetDeviceNode(DeviceObject
);
1017 DepthData
->Depth
= DeviceNode
->Level
;
1019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1021 Status
= _SEH2_GetExceptionCode();
1025 ObDereferenceObject(DeviceObject
);
1032 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData
)
1034 PDEVICE_OBJECT DeviceObject
;
1035 PDEVICE_NODE DeviceNode
;
1036 NTSTATUS Status
= STATUS_SUCCESS
;
1037 UNICODE_STRING DeviceInstance
;
1039 Status
= IopCaptureUnicodeString(&DeviceInstance
, &ResetDeviceData
->DeviceInstance
);
1040 if (!NT_SUCCESS(Status
))
1045 DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance
);
1047 /* Get the device object */
1048 DeviceObject
= IopGetDeviceObjectFromDeviceInstance(&DeviceInstance
);
1049 if (DeviceInstance
.Buffer
!= NULL
)
1051 ExFreePool(DeviceInstance
.Buffer
);
1053 if (DeviceObject
== NULL
)
1055 return STATUS_NO_SUCH_DEVICE
;
1058 /* Get the device node */
1059 DeviceNode
= IopGetDeviceNode(DeviceObject
);
1061 ASSERT(DeviceNode
->Flags
& DNF_ENUMERATED
);
1062 ASSERT(DeviceNode
->Flags
& DNF_PROCESSED
);
1064 /* Check if there's already a driver loaded for this device */
1065 if (DeviceNode
->Flags
& DNF_ADDED
)
1068 /* Remove the device node */
1069 Status
= IopRemoveDevice(DeviceNode
);
1070 if (NT_SUCCESS(Status
))
1072 /* Invalidate device relations for the parent to reenumerate the device */
1073 DPRINT1("A new driver will be loaded for '%wZ' (FDO above removed)\n", &DeviceNode
->InstancePath
);
1074 Status
= IoSynchronousInvalidateDeviceRelations(DeviceNode
->Parent
->PhysicalDeviceObject
, BusRelations
);
1079 /* A driver has already been loaded for this device */
1080 DPRINT1("A reboot is required for the current driver for '%wZ' to be replaced\n", &DeviceNode
->InstancePath
);
1081 DeviceNode
->Problem
= CM_PROB_NEED_RESTART
;
1086 /* FIXME: What if the device really is disabled? */
1087 DeviceNode
->Flags
&= ~DNF_DISABLED
;
1088 DeviceNode
->Problem
= 0;
1090 /* Load service data from the registry */
1091 Status
= IopActionConfigureChildServices(DeviceNode
, DeviceNode
->Parent
);
1093 if (NT_SUCCESS(Status
))
1095 /* Start the service and begin PnP initialization of the device again */
1096 DPRINT1("A new driver will be loaded for '%wZ' (no FDO above)\n", &DeviceNode
->InstancePath
);
1097 Status
= IopActionInitChildServices(DeviceNode
, DeviceNode
->Parent
);
1101 ObDereferenceObject(DeviceObject
);
1106 /* PUBLIC FUNCTIONS **********************************************************/
1109 * Plug and Play event structure used by NtGetPlugPlayEvent.
1112 * Can be one of the following values:
1113 * GUID_HWPROFILE_QUERY_CHANGE
1114 * GUID_HWPROFILE_CHANGE_CANCELLED
1115 * GUID_HWPROFILE_CHANGE_COMPLETE
1116 * GUID_TARGET_DEVICE_QUERY_REMOVE
1117 * GUID_TARGET_DEVICE_REMOVE_CANCELLED
1118 * GUID_TARGET_DEVICE_REMOVE_COMPLETE
1119 * GUID_PNP_CUSTOM_NOTIFICATION
1120 * GUID_PNP_POWER_NOTIFICATION
1121 * GUID_DEVICE_* (see above)
1124 * Type of the event that happened.
1133 * Size of the event block including the device IDs and other
1134 * per category specific fields.
1138 * NtGetPlugPlayEvent
1140 * Returns one Plug & Play event from a global queue.
1145 * Always set to zero.
1148 * The buffer that will be filled with the event information on
1149 * successful return from the function.
1152 * Size of the buffer pointed by the Buffer parameter. If the
1153 * buffer size is not large enough to hold the whole event
1154 * information, error STATUS_BUFFER_TOO_SMALL is returned and
1155 * the buffer remains untouched.
1158 * STATUS_PRIVILEGE_NOT_HELD
1159 * STATUS_BUFFER_TOO_SMALL
1163 * This function isn't multi-thread safe!
1169 NtGetPlugPlayEvent(IN ULONG Reserved1
,
1171 OUT PPLUGPLAY_EVENT_BLOCK Buffer
,
1172 IN ULONG BufferSize
)
1174 PPNP_EVENT_ENTRY Entry
;
1177 DPRINT("NtGetPlugPlayEvent() called\n");
1179 /* Function can only be called from user-mode */
1180 if (KeGetPreviousMode() == KernelMode
)
1182 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1183 return STATUS_ACCESS_DENIED
;
1186 /* Check for Tcb privilege */
1187 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1190 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1191 return STATUS_PRIVILEGE_NOT_HELD
;
1194 /* Wait for a PnP event */
1195 DPRINT("Waiting for pnp notification event\n");
1196 Status
= KeWaitForSingleObject(&IopPnpNotifyEvent
,
1201 if (!NT_SUCCESS(Status
) || Status
== STATUS_USER_APC
)
1203 DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status
);
1204 ASSERT(Status
== STATUS_USER_APC
);
1208 /* Get entry from the tail of the queue */
1209 Entry
= CONTAINING_RECORD(IopPnpEventQueueHead
.Blink
,
1213 /* Check the buffer size */
1214 if (BufferSize
< Entry
->Event
.TotalSize
)
1216 DPRINT1("Buffer is too small for the pnp-event\n");
1217 return STATUS_BUFFER_TOO_SMALL
;
1220 /* Copy event data to the user buffer */
1223 ProbeForWrite(Buffer
,
1224 Entry
->Event
.TotalSize
,
1226 RtlCopyMemory(Buffer
,
1228 Entry
->Event
.TotalSize
);
1230 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1232 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1236 DPRINT("NtGetPlugPlayEvent() done\n");
1238 return STATUS_SUCCESS
;
1244 * A function for doing various Plug & Play operations from user mode.
1247 * PlugPlayControlClass
1248 * 0x00 Reenumerate device tree
1250 * Buffer points to UNICODE_STRING decribing the instance
1251 * path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
1252 * more information about instance paths see !devnode command
1253 * in kernel debugger or look at "Inside Windows 2000" book,
1254 * chapter "Driver Loading, Initialization, and Installation".
1256 * 0x01 Register new device
1257 * 0x02 Deregister device
1258 * 0x03 Initialize device
1260 * 0x06 Query and remove device
1261 * 0x07 User response
1263 * Called after processing the message from NtGetPlugPlayEvent.
1265 * 0x08 Generate legacy device
1266 * 0x09 Get interface device list
1267 * 0x0A Get property data
1268 * 0x0B Device class association (Registration)
1269 * 0x0C Get related device
1270 * 0x0D Get device interface alias
1271 * 0x0E Get/set/clear device status
1272 * 0x0F Get device depth
1273 * 0x10 Query device relations
1274 * 0x11 Query target device relation
1275 * 0x12 Query conflict list
1276 * 0x13 Retrieve dock data
1279 * 0x16 Get blocked driver data
1282 * The buffer contains information that is specific to each control
1283 * code. The buffer is read-only.
1286 * Size of the buffer pointed by the Buffer parameter. If the
1287 * buffer size specifies incorrect value for specified control
1288 * code, error ??? is returned.
1291 * STATUS_PRIVILEGE_NOT_HELD
1299 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass
,
1300 IN OUT PVOID Buffer
,
1301 IN ULONG BufferLength
)
1303 DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
1304 PlugPlayControlClass
, Buffer
, BufferLength
);
1306 /* Function can only be called from user-mode */
1307 if (KeGetPreviousMode() == KernelMode
)
1309 DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1310 return STATUS_ACCESS_DENIED
;
1313 /* Check for Tcb privilege */
1314 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1317 DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1318 return STATUS_PRIVILEGE_NOT_HELD
;
1321 /* Probe the buffer */
1324 ProbeForWrite(Buffer
,
1328 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1330 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1334 switch (PlugPlayControlClass
)
1336 case PlugPlayControlEnumerateDevice
:
1337 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA
))
1338 return STATUS_INVALID_PARAMETER
;
1339 return IopPnpEnumerateDevice((PPLUGPLAY_CONTROL_ENUMERATE_DEVICE_DATA
)Buffer
);
1341 // case PlugPlayControlRegisterNewDevice:
1342 // case PlugPlayControlDeregisterDevice:
1343 // case PlugPlayControlInitializeDevice:
1344 // case PlugPlayControlStartDevice:
1345 // case PlugPlayControlUnlockDevice:
1346 // case PlugPlayControlQueryAndRemoveDevice:
1348 case PlugPlayControlUserResponse
:
1349 if (Buffer
|| BufferLength
!= 0)
1350 return STATUS_INVALID_PARAMETER
;
1351 return IopRemovePlugPlayEvent();
1353 // case PlugPlayControlGenerateLegacyDevice:
1355 case PlugPlayControlGetInterfaceDeviceList
:
1356 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
))
1357 return STATUS_INVALID_PARAMETER
;
1358 return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA
)Buffer
);
1360 case PlugPlayControlProperty
:
1361 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA
))
1362 return STATUS_INVALID_PARAMETER
;
1363 return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA
)Buffer
);
1365 // case PlugPlayControlDeviceClassAssociation:
1367 case PlugPlayControlGetRelatedDevice
:
1368 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA
))
1369 return STATUS_INVALID_PARAMETER
;
1370 return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA
)Buffer
);
1372 // case PlugPlayControlGetInterfaceDeviceAlias:
1374 case PlugPlayControlDeviceStatus
:
1375 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_STATUS_DATA
))
1376 return STATUS_INVALID_PARAMETER
;
1377 return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA
)Buffer
);
1379 case PlugPlayControlGetDeviceDepth
:
1380 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEPTH_DATA
))
1381 return STATUS_INVALID_PARAMETER
;
1382 return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA
)Buffer
);
1384 case PlugPlayControlQueryDeviceRelations
:
1385 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
))
1386 return STATUS_INVALID_PARAMETER
;
1387 return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA
)Buffer
);
1389 // case PlugPlayControlTargetDeviceRelation:
1390 // case PlugPlayControlQueryConflictList:
1391 // case PlugPlayControlRetrieveDock:
1393 case PlugPlayControlResetDevice
:
1394 if (!Buffer
|| BufferLength
< sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA
))
1395 return STATUS_INVALID_PARAMETER
;
1396 return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA
)Buffer
);
1398 // case PlugPlayControlHaltDevice:
1399 // case PlugPlayControlGetBlockedDriverList:
1402 return STATUS_NOT_IMPLEMENTED
;
1405 return STATUS_NOT_IMPLEMENTED
;