xref: /reactos/ntoskrnl/io/pnpmgr/plugplay.c (revision f2df3bf0)
1 /*
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>
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #if defined (ALLOC_PRAGMA)
16 #pragma alloc_text(INIT, IopInitPlugPlayEvents)
17 #endif
18 
19 typedef struct _PNP_EVENT_ENTRY
20 {
21     LIST_ENTRY ListEntry;
22     PLUGPLAY_EVENT_BLOCK Event;
23 } PNP_EVENT_ENTRY, *PPNP_EVENT_ENTRY;
24 
25 
26 /* GLOBALS *******************************************************************/
27 
28 static LIST_ENTRY IopPnpEventQueueHead;
29 static KEVENT IopPnpNotifyEvent;
30 
31 /* FUNCTIONS *****************************************************************/
32 
33 NTSTATUS INIT_FUNCTION
34 IopInitPlugPlayEvents(VOID)
35 {
36     InitializeListHead(&IopPnpEventQueueHead);
37 
38     KeInitializeEvent(&IopPnpNotifyEvent,
39                       SynchronizationEvent,
40                       FALSE);
41 
42     return STATUS_SUCCESS;
43 }
44 
45 NTSTATUS
46 IopQueueTargetDeviceEvent(const GUID *Guid,
47                           PUNICODE_STRING DeviceIds)
48 {
49     PPNP_EVENT_ENTRY EventEntry;
50     UNICODE_STRING Copy;
51     ULONG TotalSize;
52     NTSTATUS Status;
53 
54     ASSERT(DeviceIds);
55 
56     /* Allocate a big enough buffer */
57     Copy.Length = 0;
58     Copy.MaximumLength = DeviceIds->Length + sizeof(UNICODE_NULL);
59     TotalSize =
60         FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) +
61         Copy.MaximumLength;
62 
63     EventEntry = ExAllocatePool(NonPagedPool,
64                                 TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
65     if (!EventEntry)
66         return STATUS_INSUFFICIENT_RESOURCES;
67 
68     /* Fill the buffer with the event GUID */
69     RtlCopyMemory(&EventEntry->Event.EventGuid,
70                   Guid,
71                   sizeof(GUID));
72     EventEntry->Event.EventCategory = TargetDeviceChangeEvent;
73     EventEntry->Event.TotalSize = TotalSize;
74 
75     /* Fill the device id */
76     Copy.Buffer = EventEntry->Event.TargetDevice.DeviceIds;
77     Status = RtlAppendUnicodeStringToString(&Copy, DeviceIds);
78     if (!NT_SUCCESS(Status))
79     {
80         ExFreePool(EventEntry);
81         return Status;
82     }
83 
84     InsertHeadList(&IopPnpEventQueueHead,
85                    &EventEntry->ListEntry);
86     KeSetEvent(&IopPnpNotifyEvent,
87                0,
88                FALSE);
89 
90     return STATUS_SUCCESS;
91 }
92 
93 
94 /*
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.
97  */
98 static NTSTATUS
99 IopRemovePlugPlayEvent(VOID)
100 {
101     /* Remove a pnp event entry from the tail of the queue */
102     if (!IsListEmpty(&IopPnpEventQueueHead))
103     {
104         ExFreePool(CONTAINING_RECORD(RemoveTailList(&IopPnpEventQueueHead), PNP_EVENT_ENTRY, ListEntry));
105     }
106 
107     /* Signal the next pnp event in the queue */
108     if (!IsListEmpty(&IopPnpEventQueueHead))
109     {
110         KeSetEvent(&IopPnpNotifyEvent,
111                    0,
112                    FALSE);
113     }
114 
115     return STATUS_SUCCESS;
116 }
117 
118 static PDEVICE_OBJECT
119 IopTraverseDeviceNode(PDEVICE_NODE Node, PUNICODE_STRING DeviceInstance)
120 {
121     PDEVICE_OBJECT DeviceObject;
122     PDEVICE_NODE ChildNode;
123 
124     if (RtlEqualUnicodeString(&Node->InstancePath,
125                               DeviceInstance, TRUE))
126     {
127         ObReferenceObject(Node->PhysicalDeviceObject);
128         return Node->PhysicalDeviceObject;
129     }
130 
131     /* Traversal of all children nodes */
132     for (ChildNode = Node->Child;
133          ChildNode != NULL;
134          ChildNode = ChildNode->Sibling)
135     {
136         DeviceObject = IopTraverseDeviceNode(ChildNode, DeviceInstance);
137         if (DeviceObject != NULL)
138         {
139             return DeviceObject;
140         }
141     }
142 
143     return NULL;
144 }
145 
146 
147 PDEVICE_OBJECT
148 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
149 {
150     if (IopRootDeviceNode == NULL)
151         return NULL;
152 
153     if (DeviceInstance == NULL ||
154         DeviceInstance->Length == 0)
155     {
156         if (IopRootDeviceNode->PhysicalDeviceObject)
157         {
158             ObReferenceObject(IopRootDeviceNode->PhysicalDeviceObject);
159             return IopRootDeviceNode->PhysicalDeviceObject;
160         }
161         else
162             return NULL;
163     }
164 
165     return IopTraverseDeviceNode(IopRootDeviceNode, DeviceInstance);
166 }
167 
168 static NTSTATUS
169 IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
170 {
171     NTSTATUS Status = STATUS_SUCCESS;
172     volatile UNICODE_STRING Name;
173 
174     Name.Buffer = NULL;
175     _SEH2_TRY
176     {
177         Name.Length = SrcName->Length;
178         Name.MaximumLength = SrcName->MaximumLength;
179         if (Name.Length > Name.MaximumLength)
180         {
181             Status = STATUS_INVALID_PARAMETER;
182             _SEH2_LEAVE;
183         }
184 
185         if (Name.MaximumLength)
186         {
187             ProbeForRead(SrcName->Buffer,
188                          Name.MaximumLength,
189                          sizeof(WCHAR));
190             Name.Buffer = ExAllocatePool(NonPagedPool, Name.MaximumLength);
191             if (Name.Buffer == NULL)
192             {
193                 Status = STATUS_INSUFFICIENT_RESOURCES;
194                 _SEH2_LEAVE;
195             }
196 
197             memcpy(Name.Buffer, SrcName->Buffer, Name.MaximumLength);
198         }
199 
200         *DstName = Name;
201     }
202     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
203     {
204         if (Name.Buffer)
205         {
206             ExFreePool(Name.Buffer);
207         }
208         Status = _SEH2_GetExceptionCode();
209     }
210     _SEH2_END;
211 
212     return Status;
213 }
214 
215 static NTSTATUS
216 IopGetInterfaceDeviceList(PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA DeviceList)
217 {
218     NTSTATUS Status;
219     PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA StackList;
220     UNICODE_STRING DeviceInstance;
221     PDEVICE_OBJECT DeviceObject = NULL;
222     GUID FilterGuid;
223     PZZWSTR SymbolicLinkList = NULL, LinkList;
224     SIZE_T TotalLength;
225 
226     _SEH2_TRY
227     {
228         RtlCopyMemory(&StackList, DeviceList, sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA));
229 
230         ProbeForRead(StackList.FilterGuid, sizeof(GUID), sizeof(UCHAR));
231         RtlCopyMemory(&FilterGuid, StackList.FilterGuid, sizeof(GUID));
232 
233         if (StackList.Buffer != NULL && StackList.BufferSize != 0)
234         {
235             ProbeForWrite(StackList.Buffer, StackList.BufferSize, sizeof(UCHAR));
236         }
237     }
238     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
239     {
240         _SEH2_YIELD(return _SEH2_GetExceptionCode());
241     }
242     _SEH2_END;
243 
244     Status = IopCaptureUnicodeString(&DeviceInstance, &StackList.DeviceInstance);
245     if (NT_SUCCESS(Status))
246     {
247         /* Get the device object */
248         DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
249         if (DeviceInstance.Buffer != NULL)
250         {
251             ExFreePool(DeviceInstance.Buffer);
252         }
253     }
254 
255     Status = IoGetDeviceInterfaces(&FilterGuid, DeviceObject, StackList.Flags, &SymbolicLinkList);
256     ObDereferenceObject(DeviceObject);
257 
258     if (!NT_SUCCESS(Status))
259     {
260         /* failed */
261         return Status;
262     }
263 
264     LinkList = SymbolicLinkList;
265     while (*SymbolicLinkList != UNICODE_NULL)
266     {
267         SymbolicLinkList += wcslen(SymbolicLinkList) + (sizeof(UNICODE_NULL) / sizeof(WCHAR));
268     }
269     TotalLength = ((SymbolicLinkList - LinkList + 1) * sizeof(WCHAR));
270 
271     _SEH2_TRY
272     {
273         if (StackList.Buffer != NULL &&
274             StackList.BufferSize >= TotalLength)
275         {
276             // We've already probed the buffer for writing above.
277             RtlCopyMemory(StackList.Buffer, LinkList, TotalLength);
278         }
279 
280         DeviceList->BufferSize = TotalLength;
281     }
282     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
283     {
284         ExFreePool(LinkList);
285         _SEH2_YIELD(return _SEH2_GetExceptionCode());
286     }
287     _SEH2_END;
288 
289     ExFreePool(LinkList);
290     return STATUS_SUCCESS;
291 }
292 
293 static NTSTATUS
294 IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
295 {
296     PDEVICE_OBJECT DeviceObject = NULL;
297     PDEVICE_NODE DeviceNode;
298     UNICODE_STRING DeviceInstance;
299     ULONG BufferSize;
300     ULONG Property;
301     DEVICE_REGISTRY_PROPERTY DeviceProperty;
302     PVOID Buffer;
303     NTSTATUS Status;
304 
305     DPRINT("IopGetDeviceProperty() called\n");
306     DPRINT("Device name: %wZ\n", &PropertyData->DeviceInstance);
307 
308     Status = IopCaptureUnicodeString(&DeviceInstance, &PropertyData->DeviceInstance);
309     if (!NT_SUCCESS(Status))
310     {
311         return Status;
312     }
313 
314     _SEH2_TRY
315     {
316         Property = PropertyData->Property;
317         BufferSize = PropertyData->BufferSize;
318         ProbeForWrite(PropertyData->Buffer,
319                       BufferSize,
320                       sizeof(UCHAR));
321     }
322     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
323     {
324         if (DeviceInstance.Buffer != NULL)
325         {
326             ExFreePool(DeviceInstance.Buffer);
327         }
328         _SEH2_YIELD(return _SEH2_GetExceptionCode());
329     }
330     _SEH2_END;
331 
332     /* Get the device object */
333     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
334     if (DeviceInstance.Buffer != NULL)
335     {
336         ExFreePool(DeviceInstance.Buffer);
337     }
338     if (DeviceObject == NULL)
339     {
340         return STATUS_NO_SUCH_DEVICE;
341     }
342 
343     Buffer = ExAllocatePool(NonPagedPool, BufferSize);
344     if (Buffer == NULL)
345     {
346         ObDereferenceObject(DeviceObject);
347         return STATUS_INSUFFICIENT_RESOURCES;
348     }
349 
350 
351     DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
352 
353     if (Property == PNP_PROPERTY_POWER_DATA)
354     {
355         if (BufferSize < sizeof(CM_POWER_DATA))
356         {
357             BufferSize = 0;
358             Status = STATUS_BUFFER_TOO_SMALL;
359         }
360         else
361         {
362 //            DEVICE_CAPABILITIES DeviceCapabilities;
363             PCM_POWER_DATA PowerData;
364 
365 //            Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
366 
367             PowerData = (PCM_POWER_DATA)Buffer;
368 
369             RtlZeroMemory(PowerData, sizeof(CM_POWER_DATA));
370             PowerData->PD_Size = sizeof(CM_POWER_DATA);
371 //            PowerData->PD_MostRecentPowerState;
372             PowerData->PD_Capabilities = PDCAP_D0_SUPPORTED | PDCAP_D3_SUPPORTED;
373 /*
374             if (DeviceCapabilities.DeviceD1)
375                 PowerData->PD_Capabilities |= PDCAP_D1_SUPPORTED;
376             if (DeviceCapabilities.DeviceD2)
377                 PowerData->PD_Capabilities |= PDCAP_D2_SUPPORTED;
378             if (DeviceCapabilities.WakeFromD0)
379                 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D0_SUPPORTED;
380             if (DeviceCapabilities.WakeFromD1)
381                 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D1_SUPPORTED;
382             if (DeviceCapabilities.WakeFromD2)
383                 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D2_SUPPORTED;
384             if (DeviceCapabilities.WakeFromD3)
385                 PowerData->PD_Capabilities |= PDCAP_WAKE_FROM_D3_SUPPORTED;
386             if (DeviceCapabilities.WarmEjectSupported)
387                 PowerData->PD_Capabilities |= PDCAP_WARM_EJECT_SUPPORTED;
388             PowerData->PD_D1Latency = DeviceCapabilities.D1Latency;
389             PowerData->PD_D2Latency = DeviceCapabilities.D2Latency;
390             PowerData->PD_D3Latency = DeviceCapabilities.D3Latency;
391             RtlCopyMemory(&PowerData->PD_PowerStateMapping,
392                           &DeviceCapabilities.DeviceState,
393                           sizeof(DeviceCapabilities.DeviceState));
394             PowerData->PD_DeepestSystemWake = DeviceCapabilities.SystemWake;
395 */
396         }
397     }
398     else if (Property == PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE)
399     {
400     }
401     else if (Property == PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT)
402     {
403         if (BufferSize < sizeof(DeviceNode->HardwareRemovalPolicy))
404         {
405             BufferSize = 0;
406             Status = STATUS_BUFFER_TOO_SMALL;
407         }
408         else
409         {
410             BufferSize = sizeof(DeviceNode->HardwareRemovalPolicy);
411             RtlCopyMemory(Buffer,
412                           &DeviceNode->HardwareRemovalPolicy,
413                           BufferSize);
414         }
415     }
416     else
417     {
418         switch (Property)
419         {
420             case PNP_PROPERTY_UI_NUMBER:
421                 DeviceProperty = DevicePropertyUINumber;
422                 break;
423 
424             case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME:
425                 DeviceProperty = DevicePropertyPhysicalDeviceObjectName;
426                 break;
427 
428             case PNP_PROPERTY_BUSTYPEGUID:
429                 DeviceProperty = DevicePropertyBusTypeGuid;
430                 break;
431 
432             case PNP_PROPERTY_LEGACYBUSTYPE:
433                 DeviceProperty = DevicePropertyLegacyBusType;
434                 break;
435 
436             case PNP_PROPERTY_BUSNUMBER:
437                 DeviceProperty = DevicePropertyBusNumber;
438                 break;
439 
440             case PNP_PROPERTY_REMOVAL_POLICY:
441                 DeviceProperty = DevicePropertyRemovalPolicy;
442                 break;
443 
444             case PNP_PROPERTY_ADDRESS:
445                 DeviceProperty = DevicePropertyAddress;
446                 break;
447 
448             case PNP_PROPERTY_ENUMERATOR_NAME:
449                 DeviceProperty = DevicePropertyEnumeratorName;
450                 break;
451 
452             case PNP_PROPERTY_INSTALL_STATE:
453                 DeviceProperty = DevicePropertyInstallState;
454                 break;
455 
456 #if (WINVER >= _WIN32_WINNT_WS03)
457             case PNP_PROPERTY_LOCATION_PATHS:
458                 break;
459 #endif
460 
461 #if (WINVER >= _WIN32_WINNT_WIN7)
462             case PNP_PROPERTY_CONTAINERID:
463                 DeviceProperty = DevicePropertyContainerID;
464                 break;
465 #endif
466 
467             default:
468                 BufferSize = 0;
469                 Status = STATUS_INVALID_PARAMETER;
470                 break;
471         }
472 
473         if (Status == STATUS_SUCCESS)
474         {
475             Status = IoGetDeviceProperty(DeviceObject,
476                                          DeviceProperty,
477                                          BufferSize,
478                                          Buffer,
479                                          &BufferSize);
480         }
481     }
482 
483     ObDereferenceObject(DeviceObject);
484 
485     if (NT_SUCCESS(Status))
486     {
487         _SEH2_TRY
488         {
489             RtlCopyMemory(PropertyData->Buffer, Buffer, BufferSize);
490             PropertyData->BufferSize = BufferSize;
491         }
492         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
493         {
494             Status = _SEH2_GetExceptionCode();
495         }
496         _SEH2_END;
497     }
498 
499     ExFreePool(Buffer);
500     return Status;
501 }
502 
503 
504 static NTSTATUS
505 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData)
506 {
507     UNICODE_STRING RootDeviceName;
508     PDEVICE_OBJECT DeviceObject = NULL;
509     PDEVICE_NODE DeviceNode = NULL;
510     PDEVICE_NODE RelatedDeviceNode;
511     UNICODE_STRING TargetDeviceInstance;
512     NTSTATUS Status = STATUS_SUCCESS;
513     ULONG Relation = 0;
514     ULONG MaximumLength = 0;
515 
516     DPRINT("IopGetRelatedDevice() called\n");
517     DPRINT("Device name: %wZ\n", &RelatedDeviceData->TargetDeviceInstance);
518 
519     Status = IopCaptureUnicodeString(&TargetDeviceInstance, &RelatedDeviceData->TargetDeviceInstance);
520     if (!NT_SUCCESS(Status))
521     {
522         return Status;
523     }
524 
525     _SEH2_TRY
526     {
527         Relation = RelatedDeviceData->Relation;
528         MaximumLength = RelatedDeviceData->RelatedDeviceInstanceLength;
529         ProbeForWrite(RelatedDeviceData->RelatedDeviceInstance,
530                       MaximumLength,
531                       sizeof(WCHAR));
532     }
533     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
534     {
535         if (TargetDeviceInstance.Buffer != NULL)
536         {
537             ExFreePool(TargetDeviceInstance.Buffer);
538         }
539         _SEH2_YIELD(return _SEH2_GetExceptionCode());
540     }
541     _SEH2_END;
542 
543     RtlInitUnicodeString(&RootDeviceName,
544                          L"HTREE\\ROOT\\0");
545     if (RtlEqualUnicodeString(&TargetDeviceInstance,
546                               &RootDeviceName,
547                               TRUE))
548     {
549         DeviceNode = IopRootDeviceNode;
550         if (TargetDeviceInstance.Buffer != NULL)
551         {
552             ExFreePool(TargetDeviceInstance.Buffer);
553         }
554     }
555     else
556     {
557         /* Get the device object */
558         DeviceObject = IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance);
559         if (TargetDeviceInstance.Buffer != NULL)
560         {
561             ExFreePool(TargetDeviceInstance.Buffer);
562         }
563         if (DeviceObject == NULL)
564             return STATUS_NO_SUCH_DEVICE;
565 
566         DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
567     }
568 
569     switch (Relation)
570     {
571         case PNP_GET_PARENT_DEVICE:
572             RelatedDeviceNode = DeviceNode->Parent;
573             break;
574 
575         case PNP_GET_CHILD_DEVICE:
576             RelatedDeviceNode = DeviceNode->Child;
577             break;
578 
579         case PNP_GET_SIBLING_DEVICE:
580             RelatedDeviceNode = DeviceNode->Sibling;
581             break;
582 
583         default:
584             if (DeviceObject != NULL)
585             {
586                 ObDereferenceObject(DeviceObject);
587             }
588 
589             return STATUS_INVALID_PARAMETER;
590     }
591 
592     if (RelatedDeviceNode == NULL)
593     {
594         if (DeviceObject)
595         {
596             ObDereferenceObject(DeviceObject);
597         }
598 
599         return STATUS_NO_SUCH_DEVICE;
600     }
601 
602     if (RelatedDeviceNode->InstancePath.Length > MaximumLength)
603     {
604         if (DeviceObject)
605         {
606             ObDereferenceObject(DeviceObject);
607         }
608 
609         return STATUS_BUFFER_TOO_SMALL;
610     }
611 
612     /* Copy related device instance name */
613     _SEH2_TRY
614     {
615         RtlCopyMemory(RelatedDeviceData->RelatedDeviceInstance,
616                       RelatedDeviceNode->InstancePath.Buffer,
617                       RelatedDeviceNode->InstancePath.Length);
618         RelatedDeviceData->RelatedDeviceInstanceLength = RelatedDeviceNode->InstancePath.Length;
619     }
620     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
621     {
622         Status = _SEH2_GetExceptionCode();
623     }
624     _SEH2_END;
625 
626     if (DeviceObject != NULL)
627     {
628         ObDereferenceObject(DeviceObject);
629     }
630 
631     DPRINT("IopGetRelatedDevice() done\n");
632 
633     return Status;
634 }
635 
636 static ULONG
637 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode)
638 {
639     ULONG Output = 0;
640 
641     if (DeviceNode->Parent == IopRootDeviceNode)
642         Output |= DN_ROOT_ENUMERATED;
643 
644     if (DeviceNode->Flags & DNF_ADDED)
645         Output |= DN_DRIVER_LOADED;
646 
647     /* FIXME: DN_ENUM_LOADED */
648 
649     if (DeviceNode->Flags & DNF_STARTED)
650         Output |= DN_STARTED;
651 
652     /* FIXME: Manual */
653 
654     if (!(DeviceNode->Flags & DNF_PROCESSED))
655         Output |= DN_NEED_TO_ENUM;
656 
657     /* DN_NOT_FIRST_TIME is 9x only */
658 
659     /* FIXME: DN_HARDWARE_ENUM */
660 
661     /* DN_LIAR and DN_HAS_MARK are 9x only */
662 
663     if (DeviceNode->Problem != 0)
664         Output |= DN_HAS_PROBLEM;
665 
666     /* FIXME: DN_FILTERED */
667 
668     if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
669         Output |= DN_LEGACY_DRIVER;
670 
671     if (DeviceNode->UserFlags & DNUF_DONT_SHOW_IN_UI)
672         Output |= DN_NO_SHOW_IN_DM;
673 
674     if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE))
675         Output |= DN_DISABLEABLE;
676 
677     /* FIXME: Implement the rest */
678 
679     Output |= DN_NT_ENUMERATOR | DN_NT_DRIVER;
680 
681     return Output;
682 }
683 
684 static NTSTATUS
685 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
686 {
687     PDEVICE_OBJECT DeviceObject;
688     PDEVICE_NODE DeviceNode;
689     ULONG Operation = 0;
690     ULONG DeviceStatus = 0;
691     ULONG DeviceProblem = 0;
692     UNICODE_STRING DeviceInstance;
693     NTSTATUS Status;
694 
695     DPRINT("IopDeviceStatus() called\n");
696 
697     Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance);
698     if (!NT_SUCCESS(Status))
699     {
700         return Status;
701     }
702 
703     DPRINT("Device name: '%wZ'\n", &DeviceInstance);
704 
705     _SEH2_TRY
706     {
707         Operation = StatusData->Operation;
708         if (Operation == PNP_SET_DEVICE_STATUS)
709         {
710             DeviceStatus = StatusData->DeviceStatus;
711             DeviceProblem = StatusData->DeviceProblem;
712         }
713     }
714     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
715     {
716         if (DeviceInstance.Buffer != NULL)
717         {
718             ExFreePool(DeviceInstance.Buffer);
719         }
720         _SEH2_YIELD(return _SEH2_GetExceptionCode());
721     }
722     _SEH2_END;
723 
724     /* Get the device object */
725     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
726     if (DeviceInstance.Buffer != NULL)
727     {
728         ExFreePool(DeviceInstance.Buffer);
729     }
730     if (DeviceObject == NULL)
731     {
732         return STATUS_NO_SUCH_DEVICE;
733     }
734 
735     DeviceNode = IopGetDeviceNode(DeviceObject);
736 
737     switch (Operation)
738     {
739         case PNP_GET_DEVICE_STATUS:
740             DPRINT("Get status data\n");
741             DeviceStatus = IopGetDeviceNodeStatus(DeviceNode);
742             DeviceProblem = DeviceNode->Problem;
743             break;
744 
745         case PNP_SET_DEVICE_STATUS:
746             DPRINT1("Set status data is NOT SUPPORTED\n");
747             break;
748 
749         case PNP_CLEAR_DEVICE_STATUS:
750             DPRINT1("FIXME: Clear status data!\n");
751             break;
752     }
753 
754     ObDereferenceObject(DeviceObject);
755 
756     if (Operation == PNP_GET_DEVICE_STATUS)
757     {
758         _SEH2_TRY
759         {
760             StatusData->DeviceStatus = DeviceStatus;
761             StatusData->DeviceProblem = DeviceProblem;
762         }
763         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
764         {
765             Status = _SEH2_GetExceptionCode();
766         }
767         _SEH2_END;
768     }
769 
770     return Status;
771 }
772 
773 static
774 NTSTATUS
775 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData)
776 {
777     UNICODE_STRING DeviceInstance;
778     PDEVICE_OBJECT DeviceObject = NULL;
779     IO_STACK_LOCATION Stack;
780     IO_STATUS_BLOCK IoStatusBlock;
781     PDEVICE_RELATIONS DeviceRelations = NULL;
782     PDEVICE_OBJECT ChildDeviceObject;
783     PDEVICE_NODE ChildDeviceNode;
784     ULONG i;
785     ULONG Relations;
786     ULONG BufferSize, RequiredSize;
787     ULONG BufferLeft;
788     PWCHAR Buffer, Ptr;
789     NTSTATUS Status = STATUS_SUCCESS;
790 
791     DPRINT("IopGetDeviceRelations() called\n");
792     DPRINT("Device name: %wZ\n", &RelationsData->DeviceInstance);
793     DPRINT("Relations: %lu\n", RelationsData->Relations);
794     DPRINT("BufferSize: %lu\n", RelationsData->BufferSize);
795     DPRINT("Buffer: %p\n", RelationsData->Buffer);
796 
797     _SEH2_TRY
798     {
799         Relations = RelationsData->Relations;
800         BufferSize = RelationsData->BufferSize;
801         Buffer = RelationsData->Buffer;
802 
803         ProbeForWrite(Buffer, BufferSize, sizeof(CHAR));
804     }
805     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
806     {
807         _SEH2_YIELD(return _SEH2_GetExceptionCode());
808     }
809     _SEH2_END;
810 
811     Status = IopCaptureUnicodeString(&DeviceInstance, &RelationsData->DeviceInstance);
812     if (!NT_SUCCESS(Status))
813     {
814         DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status);
815         return Status;
816     }
817 
818     /* Get the device object */
819     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
820     if (DeviceObject == NULL)
821     {
822         DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n");
823         Status = STATUS_NO_SUCH_DEVICE;
824         goto done;
825     }
826 
827     switch (Relations)
828     {
829         case PNP_EJECT_RELATIONS:
830             Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
831             break;
832 
833         case PNP_REMOVAL_RELATIONS:
834             Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
835             break;
836 
837         case PNP_POWER_RELATIONS:
838             Stack.Parameters.QueryDeviceRelations.Type = PowerRelations;
839             break;
840 
841         case PNP_BUS_RELATIONS:
842             Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
843             break;
844 
845         default:
846             Status = STATUS_INVALID_PARAMETER;
847             goto done;
848     }
849 
850     Status = IopInitiatePnpIrp(DeviceObject,
851                                &IoStatusBlock,
852                                IRP_MN_QUERY_DEVICE_RELATIONS,
853                                &Stack);
854     if (!NT_SUCCESS(Status))
855     {
856         DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
857         goto done;
858     }
859 
860     DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
861 
862     DPRINT("Found %d device relations\n", DeviceRelations->Count);
863 
864     _SEH2_TRY
865     {
866         RequiredSize = 0;
867         BufferLeft = BufferSize;
868         Ptr = Buffer;
869 
870         for (i = 0; i < DeviceRelations->Count; i++)
871         {
872             ChildDeviceObject = DeviceRelations->Objects[i];
873 
874             ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
875             if (ChildDeviceNode)
876             {
877                 DPRINT("Device instance: %wZ\n", &ChildDeviceNode->InstancePath);
878                 DPRINT("RequiredSize: %hu\n", ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
879 
880                 if (Ptr != NULL)
881                 {
882                     if (BufferLeft < ChildDeviceNode->InstancePath.Length + 2 * sizeof(WCHAR))
883                     {
884                         Status = STATUS_BUFFER_TOO_SMALL;
885                         break;
886                     }
887 
888                     RtlCopyMemory(Ptr,
889                                   ChildDeviceNode->InstancePath.Buffer,
890                                   ChildDeviceNode->InstancePath.Length);
891                     Ptr = (PWCHAR)((ULONG_PTR)Ptr + ChildDeviceNode->InstancePath.Length);
892                     *Ptr = UNICODE_NULL;
893                     Ptr = (PWCHAR)((ULONG_PTR)Ptr + sizeof(WCHAR));
894 
895                     BufferLeft -= (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
896                 }
897 
898                 RequiredSize += (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
899             }
900         }
901 
902         if (Ptr != NULL && BufferLeft >= sizeof(WCHAR))
903             *Ptr = UNICODE_NULL;
904 
905         if (RequiredSize > 0)
906             RequiredSize += sizeof(WCHAR);
907 
908         DPRINT("BufferSize: %lu  RequiredSize: %lu\n", RelationsData->BufferSize, RequiredSize);
909 
910         RelationsData->BufferSize = RequiredSize;
911     }
912     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
913     {
914         Status = _SEH2_GetExceptionCode();
915     }
916     _SEH2_END;
917 
918 done:
919     if (DeviceRelations != NULL)
920         ExFreePool(DeviceRelations);
921 
922     if (DeviceObject != NULL)
923         ObDereferenceObject(DeviceObject);
924 
925     if (DeviceInstance.Buffer != NULL)
926         ExFreePool(DeviceInstance.Buffer);
927 
928     return Status;
929 }
930 
931 static NTSTATUS
932 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData)
933 {
934     PDEVICE_OBJECT DeviceObject;
935     PDEVICE_NODE DeviceNode;
936     UNICODE_STRING DeviceInstance;
937     NTSTATUS Status = STATUS_SUCCESS;
938 
939     DPRINT("IopGetDeviceDepth() called\n");
940     DPRINT("Device name: %wZ\n", &DepthData->DeviceInstance);
941 
942     Status = IopCaptureUnicodeString(&DeviceInstance, &DepthData->DeviceInstance);
943     if (!NT_SUCCESS(Status))
944     {
945         return Status;
946     }
947 
948     /* Get the device object */
949     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
950     if (DeviceInstance.Buffer != NULL)
951     {
952         ExFreePool(DeviceInstance.Buffer);
953     }
954     if (DeviceObject == NULL)
955     {
956         return STATUS_NO_SUCH_DEVICE;
957     }
958 
959     DeviceNode = IopGetDeviceNode(DeviceObject);
960 
961     _SEH2_TRY
962     {
963         DepthData->Depth = DeviceNode->Level;
964     }
965     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
966     {
967         Status = _SEH2_GetExceptionCode();
968     }
969     _SEH2_END;
970 
971     ObDereferenceObject(DeviceObject);
972 
973     return Status;
974 }
975 
976 
977 static NTSTATUS
978 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData)
979 {
980     PDEVICE_OBJECT DeviceObject;
981     PDEVICE_NODE DeviceNode;
982     NTSTATUS Status = STATUS_SUCCESS;
983     UNICODE_STRING DeviceInstance;
984 
985     Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance);
986     if (!NT_SUCCESS(Status))
987     {
988         return Status;
989     }
990 
991     DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance);
992 
993     /* Get the device object */
994     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
995     if (DeviceInstance.Buffer != NULL)
996     {
997         ExFreePool(DeviceInstance.Buffer);
998     }
999     if (DeviceObject == NULL)
1000     {
1001         return STATUS_NO_SUCH_DEVICE;
1002     }
1003 
1004     /* Get the device node */
1005     DeviceNode = IopGetDeviceNode(DeviceObject);
1006 
1007     ASSERT(DeviceNode->Flags & DNF_ENUMERATED);
1008     ASSERT(DeviceNode->Flags & DNF_PROCESSED);
1009 
1010     /* Check if there's already a driver loaded for this device */
1011     if (DeviceNode->Flags & DNF_ADDED)
1012     {
1013 #if 0
1014         /* Remove the device node */
1015         Status = IopRemoveDevice(DeviceNode);
1016         if (NT_SUCCESS(Status))
1017         {
1018             /* Invalidate device relations for the parent to reenumerate the device */
1019             DPRINT1("A new driver will be loaded for '%wZ' (FDO above removed)\n", &DeviceNode->InstancePath);
1020             Status = IoSynchronousInvalidateDeviceRelations(DeviceNode->Parent->PhysicalDeviceObject, BusRelations);
1021         }
1022         else
1023 #endif
1024         {
1025             /* A driver has already been loaded for this device */
1026             DPRINT1("A reboot is required for the current driver for '%wZ' to be replaced\n", &DeviceNode->InstancePath);
1027             DeviceNode->Problem = CM_PROB_NEED_RESTART;
1028         }
1029     }
1030     else
1031     {
1032         /* FIXME: What if the device really is disabled? */
1033         DeviceNode->Flags &= ~DNF_DISABLED;
1034         DeviceNode->Problem = 0;
1035 
1036         /* Load service data from the registry */
1037         Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
1038 
1039         if (NT_SUCCESS(Status))
1040         {
1041             /* Start the service and begin PnP initialization of the device again */
1042             DPRINT1("A new driver will be loaded for '%wZ' (no FDO above)\n", &DeviceNode->InstancePath);
1043             Status = IopActionInitChildServices(DeviceNode, DeviceNode->Parent);
1044         }
1045     }
1046 
1047     ObDereferenceObject(DeviceObject);
1048 
1049     return Status;
1050 }
1051 
1052 /* PUBLIC FUNCTIONS **********************************************************/
1053 
1054 /*
1055  * Plug and Play event structure used by NtGetPlugPlayEvent.
1056  *
1057  * EventGuid
1058  *    Can be one of the following values:
1059  *       GUID_HWPROFILE_QUERY_CHANGE
1060  *       GUID_HWPROFILE_CHANGE_CANCELLED
1061  *       GUID_HWPROFILE_CHANGE_COMPLETE
1062  *       GUID_TARGET_DEVICE_QUERY_REMOVE
1063  *       GUID_TARGET_DEVICE_REMOVE_CANCELLED
1064  *       GUID_TARGET_DEVICE_REMOVE_COMPLETE
1065  *       GUID_PNP_CUSTOM_NOTIFICATION
1066  *       GUID_PNP_POWER_NOTIFICATION
1067  *       GUID_DEVICE_* (see above)
1068  *
1069  * EventCategory
1070  *    Type of the event that happened.
1071  *
1072  * Result
1073  *    ?
1074  *
1075  * Flags
1076  *    ?
1077  *
1078  * TotalSize
1079  *    Size of the event block including the device IDs and other
1080  *    per category specific fields.
1081  */
1082 
1083 /*
1084  * NtGetPlugPlayEvent
1085  *
1086  * Returns one Plug & Play event from a global queue.
1087  *
1088  * Parameters
1089  *    Reserved1
1090  *    Reserved2
1091  *       Always set to zero.
1092  *
1093  *    Buffer
1094  *       The buffer that will be filled with the event information on
1095  *       successful return from the function.
1096  *
1097  *    BufferSize
1098  *       Size of the buffer pointed by the Buffer parameter. If the
1099  *       buffer size is not large enough to hold the whole event
1100  *       information, error STATUS_BUFFER_TOO_SMALL is returned and
1101  *       the buffer remains untouched.
1102  *
1103  * Return Values
1104  *    STATUS_PRIVILEGE_NOT_HELD
1105  *    STATUS_BUFFER_TOO_SMALL
1106  *    STATUS_SUCCESS
1107  *
1108  * Remarks
1109  *    This function isn't multi-thread safe!
1110  *
1111  * @implemented
1112  */
1113 NTSTATUS
1114 NTAPI
1115 NtGetPlugPlayEvent(IN ULONG Reserved1,
1116                    IN ULONG Reserved2,
1117                    OUT PPLUGPLAY_EVENT_BLOCK Buffer,
1118                    IN ULONG BufferSize)
1119 {
1120     PPNP_EVENT_ENTRY Entry;
1121     NTSTATUS Status;
1122 
1123     DPRINT("NtGetPlugPlayEvent() called\n");
1124 
1125     /* Function can only be called from user-mode */
1126     if (KeGetPreviousMode() == KernelMode)
1127     {
1128         DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1129         return STATUS_ACCESS_DENIED;
1130     }
1131 
1132     /* Check for Tcb privilege */
1133     if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
1134                                 UserMode))
1135     {
1136         DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1137         return STATUS_PRIVILEGE_NOT_HELD;
1138     }
1139 
1140     /* Wait for a PnP event */
1141     DPRINT("Waiting for pnp notification event\n");
1142     Status = KeWaitForSingleObject(&IopPnpNotifyEvent,
1143                                    UserRequest,
1144                                    UserMode,
1145                                    FALSE,
1146                                    NULL);
1147     if (!NT_SUCCESS(Status) || Status == STATUS_USER_APC)
1148     {
1149         DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status);
1150         ASSERT(Status == STATUS_USER_APC);
1151         return Status;
1152     }
1153 
1154     /* Get entry from the tail of the queue */
1155     Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink,
1156                               PNP_EVENT_ENTRY,
1157                               ListEntry);
1158 
1159     /* Check the buffer size */
1160     if (BufferSize < Entry->Event.TotalSize)
1161     {
1162         DPRINT1("Buffer is too small for the pnp-event\n");
1163         return STATUS_BUFFER_TOO_SMALL;
1164     }
1165 
1166     /* Copy event data to the user buffer */
1167     _SEH2_TRY
1168     {
1169         ProbeForWrite(Buffer,
1170                       Entry->Event.TotalSize,
1171                       sizeof(UCHAR));
1172         RtlCopyMemory(Buffer,
1173                       &Entry->Event,
1174                       Entry->Event.TotalSize);
1175     }
1176     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1177     {
1178         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1179     }
1180     _SEH2_END;
1181 
1182     DPRINT("NtGetPlugPlayEvent() done\n");
1183 
1184     return STATUS_SUCCESS;
1185 }
1186 
1187 /*
1188  * NtPlugPlayControl
1189  *
1190  * A function for doing various Plug & Play operations from user mode.
1191  *
1192  * Parameters
1193  *    PlugPlayControlClass
1194  *       0x00   Reenumerate device tree
1195  *
1196  *              Buffer points to UNICODE_STRING decribing the instance
1197  *              path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
1198  *              more information about instance paths see !devnode command
1199  *              in kernel debugger or look at "Inside Windows 2000" book,
1200  *              chapter "Driver Loading, Initialization, and Installation".
1201  *
1202  *       0x01   Register new device
1203  *       0x02   Deregister device
1204  *       0x03   Initialize device
1205  *       0x04   Start device
1206  *       0x06   Query and remove device
1207  *       0x07   User response
1208  *
1209  *              Called after processing the message from NtGetPlugPlayEvent.
1210  *
1211  *       0x08   Generate legacy device
1212  *       0x09   Get interface device list
1213  *       0x0A   Get property data
1214  *       0x0B   Device class association (Registration)
1215  *       0x0C   Get related device
1216  *       0x0D   Get device interface alias
1217  *       0x0E   Get/set/clear device status
1218  *       0x0F   Get device depth
1219  *       0x10   Query device relations
1220  *       0x11   Query target device relation
1221  *       0x12   Query conflict list
1222  *       0x13   Retrieve dock data
1223  *       0x14   Reset device
1224  *       0x15   Halt device
1225  *       0x16   Get blocked driver data
1226  *
1227  *    Buffer
1228  *       The buffer contains information that is specific to each control
1229  *       code. The buffer is read-only.
1230  *
1231  *    BufferSize
1232  *       Size of the buffer pointed by the Buffer parameter. If the
1233  *       buffer size specifies incorrect value for specified control
1234  *       code, error ??? is returned.
1235  *
1236  * Return Values
1237  *    STATUS_PRIVILEGE_NOT_HELD
1238  *    STATUS_SUCCESS
1239  *    ...
1240  *
1241  * @unimplemented
1242  */
1243 NTSTATUS
1244 NTAPI
1245 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
1246                   IN OUT PVOID Buffer,
1247                   IN ULONG BufferLength)
1248 {
1249     DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
1250            PlugPlayControlClass, Buffer, BufferLength);
1251 
1252     /* Function can only be called from user-mode */
1253     if (KeGetPreviousMode() == KernelMode)
1254     {
1255         DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1256         return STATUS_ACCESS_DENIED;
1257     }
1258 
1259     /* Check for Tcb privilege */
1260     if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
1261                                 UserMode))
1262     {
1263         DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1264         return STATUS_PRIVILEGE_NOT_HELD;
1265     }
1266 
1267     /* Probe the buffer */
1268     _SEH2_TRY
1269     {
1270         ProbeForWrite(Buffer,
1271                       BufferLength,
1272                       sizeof(ULONG));
1273     }
1274     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1275     {
1276         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1277     }
1278     _SEH2_END;
1279 
1280     switch (PlugPlayControlClass)
1281     {
1282 //        case PlugPlayControlEnumerateDevice:
1283 //        case PlugPlayControlRegisterNewDevice:
1284 //        case PlugPlayControlDeregisterDevice:
1285 //        case PlugPlayControlInitializeDevice:
1286 //        case PlugPlayControlStartDevice:
1287 //        case PlugPlayControlUnlockDevice:
1288 //        case PlugPlayControlQueryAndRemoveDevice:
1289 
1290         case PlugPlayControlUserResponse:
1291             if (Buffer || BufferLength != 0)
1292                 return STATUS_INVALID_PARAMETER;
1293             return IopRemovePlugPlayEvent();
1294 
1295 //        case PlugPlayControlGenerateLegacyDevice:
1296 
1297         case PlugPlayControlGetInterfaceDeviceList:
1298             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA))
1299                 return STATUS_INVALID_PARAMETER;
1300             return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)Buffer);
1301 
1302         case PlugPlayControlProperty:
1303             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA))
1304                 return STATUS_INVALID_PARAMETER;
1305             return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA)Buffer);
1306 
1307 //        case PlugPlayControlDeviceClassAssociation:
1308 
1309         case PlugPlayControlGetRelatedDevice:
1310             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA))
1311                 return STATUS_INVALID_PARAMETER;
1312             return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA)Buffer);
1313 
1314 //        case PlugPlayControlGetInterfaceDeviceAlias:
1315 
1316         case PlugPlayControlDeviceStatus:
1317             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_STATUS_DATA))
1318                 return STATUS_INVALID_PARAMETER;
1319             return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA)Buffer);
1320 
1321         case PlugPlayControlGetDeviceDepth:
1322             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEPTH_DATA))
1323                 return STATUS_INVALID_PARAMETER;
1324             return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer);
1325 
1326         case PlugPlayControlQueryDeviceRelations:
1327             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA))
1328                 return STATUS_INVALID_PARAMETER;
1329             return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)Buffer);
1330 
1331 //        case PlugPlayControlTargetDeviceRelation:
1332 //        case PlugPlayControlQueryConflictList:
1333 //        case PlugPlayControlRetrieveDock:
1334 
1335         case PlugPlayControlResetDevice:
1336             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA))
1337                 return STATUS_INVALID_PARAMETER;
1338             return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer);
1339 
1340 //        case PlugPlayControlHaltDevice:
1341 //        case PlugPlayControlGetBlockedDriverList:
1342 
1343         default:
1344             return STATUS_NOT_IMPLEMENTED;
1345     }
1346 
1347     return STATUS_NOT_IMPLEMENTED;
1348 }
1349