xref: /reactos/ntoskrnl/io/pnpmgr/plugplay.c (revision fb5d5ecd)
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             PowerData->PD_Size = sizeof(CM_POWER_DATA);
369 /*
370             PowerData->PD_MostRecentPowerState;
371             PowerData->PD_Capabilities;
372             PowerData->PD_D1Latency;
373             PowerData->PD_D2Latency;
374             PowerData->PD_D3Latency;
375             PowerData->PD_PowerStateMapping[POWER_SYSTEM_MAXIMUM];
376             PowerData->PD_DeepestSystemWake;
377 */
378         }
379     }
380     else if (Property == PNP_PROPERTY_REMOVAL_POLICY_OVERRIDE)
381     {
382     }
383     else if (Property == PNP_PROPERTY_REMOVAL_POLICY_HARDWARE_DEFAULT)
384     {
385         if (BufferSize < sizeof(DeviceNode->HardwareRemovalPolicy))
386         {
387             BufferSize = 0;
388             Status = STATUS_BUFFER_TOO_SMALL;
389         }
390         else
391         {
392             BufferSize = sizeof(DeviceNode->HardwareRemovalPolicy);
393             RtlCopyMemory(Buffer,
394                           &DeviceNode->HardwareRemovalPolicy,
395                           BufferSize);
396         }
397     }
398     else
399     {
400         switch (Property)
401         {
402             case PNP_PROPERTY_UI_NUMBER:
403                 DeviceProperty = DevicePropertyUINumber;
404                 break;
405 
406             case PNP_PROPERTY_PHYSICAL_DEVICE_OBJECT_NAME:
407                 DeviceProperty = DevicePropertyPhysicalDeviceObjectName;
408                 break;
409 
410             case PNP_PROPERTY_BUSTYPEGUID:
411                 DeviceProperty = DevicePropertyBusTypeGuid;
412                 break;
413 
414             case PNP_PROPERTY_LEGACYBUSTYPE:
415                 DeviceProperty = DevicePropertyLegacyBusType;
416                 break;
417 
418             case PNP_PROPERTY_BUSNUMBER:
419                 DeviceProperty = DevicePropertyBusNumber;
420                 break;
421 
422             case PNP_PROPERTY_REMOVAL_POLICY:
423                 DeviceProperty = DevicePropertyRemovalPolicy;
424                 break;
425 
426             case PNP_PROPERTY_ADDRESS:
427                 DeviceProperty = DevicePropertyAddress;
428                 break;
429 
430             case PNP_PROPERTY_ENUMERATOR_NAME:
431                 DeviceProperty = DevicePropertyEnumeratorName;
432                 break;
433 
434             case PNP_PROPERTY_INSTALL_STATE:
435                 DeviceProperty = DevicePropertyInstallState;
436                 break;
437 
438 #if (WINVER >= _WIN32_WINNT_WS03)
439             case PNP_PROPERTY_LOCATION_PATHS:
440                 break;
441 #endif
442 
443 #if (WINVER >= _WIN32_WINNT_WIN7)
444             case PNP_PROPERTY_CONTAINERID:
445                 DeviceProperty = DevicePropertyContainerID;
446                 break;
447 #endif
448 
449             default:
450                 BufferSize = 0;
451                 Status = STATUS_INVALID_PARAMETER;
452                 break;
453         }
454 
455         if (Status == STATUS_SUCCESS)
456         {
457             Status = IoGetDeviceProperty(DeviceObject,
458                                          DeviceProperty,
459                                          BufferSize,
460                                          Buffer,
461                                          &BufferSize);
462         }
463     }
464 
465     ObDereferenceObject(DeviceObject);
466 
467     if (NT_SUCCESS(Status))
468     {
469         _SEH2_TRY
470         {
471             RtlCopyMemory(PropertyData->Buffer, Buffer, BufferSize);
472             PropertyData->BufferSize = BufferSize;
473         }
474         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
475         {
476             Status = _SEH2_GetExceptionCode();
477         }
478         _SEH2_END;
479     }
480 
481     ExFreePool(Buffer);
482     return Status;
483 }
484 
485 
486 static NTSTATUS
487 IopGetRelatedDevice(PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA RelatedDeviceData)
488 {
489     UNICODE_STRING RootDeviceName;
490     PDEVICE_OBJECT DeviceObject = NULL;
491     PDEVICE_NODE DeviceNode = NULL;
492     PDEVICE_NODE RelatedDeviceNode;
493     UNICODE_STRING TargetDeviceInstance;
494     NTSTATUS Status = STATUS_SUCCESS;
495     ULONG Relation = 0;
496     ULONG MaximumLength = 0;
497 
498     DPRINT("IopGetRelatedDevice() called\n");
499     DPRINT("Device name: %wZ\n", &RelatedDeviceData->TargetDeviceInstance);
500 
501     Status = IopCaptureUnicodeString(&TargetDeviceInstance, &RelatedDeviceData->TargetDeviceInstance);
502     if (!NT_SUCCESS(Status))
503     {
504         return Status;
505     }
506 
507     _SEH2_TRY
508     {
509         Relation = RelatedDeviceData->Relation;
510         MaximumLength = RelatedDeviceData->RelatedDeviceInstanceLength;
511         ProbeForWrite(RelatedDeviceData->RelatedDeviceInstance,
512                       MaximumLength,
513                       sizeof(WCHAR));
514     }
515     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
516     {
517         if (TargetDeviceInstance.Buffer != NULL)
518         {
519             ExFreePool(TargetDeviceInstance.Buffer);
520         }
521         _SEH2_YIELD(return _SEH2_GetExceptionCode());
522     }
523     _SEH2_END;
524 
525     RtlInitUnicodeString(&RootDeviceName,
526                          L"HTREE\\ROOT\\0");
527     if (RtlEqualUnicodeString(&TargetDeviceInstance,
528                               &RootDeviceName,
529                               TRUE))
530     {
531         DeviceNode = IopRootDeviceNode;
532         if (TargetDeviceInstance.Buffer != NULL)
533         {
534             ExFreePool(TargetDeviceInstance.Buffer);
535         }
536     }
537     else
538     {
539         /* Get the device object */
540         DeviceObject = IopGetDeviceObjectFromDeviceInstance(&TargetDeviceInstance);
541         if (TargetDeviceInstance.Buffer != NULL)
542         {
543             ExFreePool(TargetDeviceInstance.Buffer);
544         }
545         if (DeviceObject == NULL)
546             return STATUS_NO_SUCH_DEVICE;
547 
548         DeviceNode = ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
549     }
550 
551     switch (Relation)
552     {
553         case PNP_GET_PARENT_DEVICE:
554             RelatedDeviceNode = DeviceNode->Parent;
555             break;
556 
557         case PNP_GET_CHILD_DEVICE:
558             RelatedDeviceNode = DeviceNode->Child;
559             break;
560 
561         case PNP_GET_SIBLING_DEVICE:
562             RelatedDeviceNode = DeviceNode->Sibling;
563             break;
564 
565         default:
566             if (DeviceObject != NULL)
567             {
568                 ObDereferenceObject(DeviceObject);
569             }
570 
571             return STATUS_INVALID_PARAMETER;
572     }
573 
574     if (RelatedDeviceNode == NULL)
575     {
576         if (DeviceObject)
577         {
578             ObDereferenceObject(DeviceObject);
579         }
580 
581         return STATUS_NO_SUCH_DEVICE;
582     }
583 
584     if (RelatedDeviceNode->InstancePath.Length > MaximumLength)
585     {
586         if (DeviceObject)
587         {
588             ObDereferenceObject(DeviceObject);
589         }
590 
591         return STATUS_BUFFER_TOO_SMALL;
592     }
593 
594     /* Copy related device instance name */
595     _SEH2_TRY
596     {
597         RtlCopyMemory(RelatedDeviceData->RelatedDeviceInstance,
598                       RelatedDeviceNode->InstancePath.Buffer,
599                       RelatedDeviceNode->InstancePath.Length);
600         RelatedDeviceData->RelatedDeviceInstanceLength = RelatedDeviceNode->InstancePath.Length;
601     }
602     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
603     {
604         Status = _SEH2_GetExceptionCode();
605     }
606     _SEH2_END;
607 
608     if (DeviceObject != NULL)
609     {
610         ObDereferenceObject(DeviceObject);
611     }
612 
613     DPRINT("IopGetRelatedDevice() done\n");
614 
615     return Status;
616 }
617 
618 static ULONG
619 IopGetDeviceNodeStatus(PDEVICE_NODE DeviceNode)
620 {
621     ULONG Output = 0;
622 
623     if (DeviceNode->Parent == IopRootDeviceNode)
624         Output |= DN_ROOT_ENUMERATED;
625 
626     if (DeviceNode->Flags & DNF_ADDED)
627         Output |= DN_DRIVER_LOADED;
628 
629     /* FIXME: DN_ENUM_LOADED */
630 
631     if (DeviceNode->Flags & DNF_STARTED)
632         Output |= DN_STARTED;
633 
634     /* FIXME: Manual */
635 
636     if (!(DeviceNode->Flags & DNF_PROCESSED))
637         Output |= DN_NEED_TO_ENUM;
638 
639     /* DN_NOT_FIRST_TIME is 9x only */
640 
641     /* FIXME: DN_HARDWARE_ENUM */
642 
643     /* DN_LIAR and DN_HAS_MARK are 9x only */
644 
645     if (DeviceNode->Problem != 0)
646         Output |= DN_HAS_PROBLEM;
647 
648     /* FIXME: DN_FILTERED */
649 
650     if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
651         Output |= DN_LEGACY_DRIVER;
652 
653     if (DeviceNode->UserFlags & DNUF_DONT_SHOW_IN_UI)
654         Output |= DN_NO_SHOW_IN_DM;
655 
656     if (!(DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE))
657         Output |= DN_DISABLEABLE;
658 
659     /* FIXME: Implement the rest */
660 
661     Output |= DN_NT_ENUMERATOR | DN_NT_DRIVER;
662 
663     return Output;
664 }
665 
666 static NTSTATUS
667 IopDeviceStatus(PPLUGPLAY_CONTROL_STATUS_DATA StatusData)
668 {
669     PDEVICE_OBJECT DeviceObject;
670     PDEVICE_NODE DeviceNode;
671     ULONG Operation = 0;
672     ULONG DeviceStatus = 0;
673     ULONG DeviceProblem = 0;
674     UNICODE_STRING DeviceInstance;
675     NTSTATUS Status;
676 
677     DPRINT("IopDeviceStatus() called\n");
678 
679     Status = IopCaptureUnicodeString(&DeviceInstance, &StatusData->DeviceInstance);
680     if (!NT_SUCCESS(Status))
681     {
682         return Status;
683     }
684 
685     DPRINT("Device name: '%wZ'\n", &DeviceInstance);
686 
687     _SEH2_TRY
688     {
689         Operation = StatusData->Operation;
690         if (Operation == PNP_SET_DEVICE_STATUS)
691         {
692             DeviceStatus = StatusData->DeviceStatus;
693             DeviceProblem = StatusData->DeviceProblem;
694         }
695     }
696     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
697     {
698         if (DeviceInstance.Buffer != NULL)
699         {
700             ExFreePool(DeviceInstance.Buffer);
701         }
702         _SEH2_YIELD(return _SEH2_GetExceptionCode());
703     }
704     _SEH2_END;
705 
706     /* Get the device object */
707     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
708     if (DeviceInstance.Buffer != NULL)
709     {
710         ExFreePool(DeviceInstance.Buffer);
711     }
712     if (DeviceObject == NULL)
713     {
714         return STATUS_NO_SUCH_DEVICE;
715     }
716 
717     DeviceNode = IopGetDeviceNode(DeviceObject);
718 
719     switch (Operation)
720     {
721         case PNP_GET_DEVICE_STATUS:
722             DPRINT("Get status data\n");
723             DeviceStatus = IopGetDeviceNodeStatus(DeviceNode);
724             DeviceProblem = DeviceNode->Problem;
725             break;
726 
727         case PNP_SET_DEVICE_STATUS:
728             DPRINT1("Set status data is NOT SUPPORTED\n");
729             break;
730 
731         case PNP_CLEAR_DEVICE_STATUS:
732             DPRINT1("FIXME: Clear status data!\n");
733             break;
734     }
735 
736     ObDereferenceObject(DeviceObject);
737 
738     if (Operation == PNP_GET_DEVICE_STATUS)
739     {
740         _SEH2_TRY
741         {
742             StatusData->DeviceStatus = DeviceStatus;
743             StatusData->DeviceProblem = DeviceProblem;
744         }
745         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
746         {
747             Status = _SEH2_GetExceptionCode();
748         }
749         _SEH2_END;
750     }
751 
752     return Status;
753 }
754 
755 static
756 NTSTATUS
757 IopGetDeviceRelations(PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA RelationsData)
758 {
759     UNICODE_STRING DeviceInstance;
760     PDEVICE_OBJECT DeviceObject = NULL;
761     IO_STACK_LOCATION Stack;
762     IO_STATUS_BLOCK IoStatusBlock;
763     PDEVICE_RELATIONS DeviceRelations = NULL;
764     PDEVICE_OBJECT ChildDeviceObject;
765     PDEVICE_NODE ChildDeviceNode;
766     ULONG i;
767     ULONG Relations;
768     ULONG BufferSize, RequiredSize;
769     ULONG BufferLeft;
770     PWCHAR Buffer, Ptr;
771     NTSTATUS Status = STATUS_SUCCESS;
772 
773     DPRINT("IopGetDeviceRelations() called\n");
774     DPRINT("Device name: %wZ\n", &RelationsData->DeviceInstance);
775     DPRINT("Relations: %lu\n", RelationsData->Relations);
776     DPRINT("BufferSize: %lu\n", RelationsData->BufferSize);
777     DPRINT("Buffer: %p\n", RelationsData->Buffer);
778 
779     _SEH2_TRY
780     {
781         Relations = RelationsData->Relations;
782         BufferSize = RelationsData->BufferSize;
783         Buffer = RelationsData->Buffer;
784 
785         ProbeForWrite(Buffer, BufferSize, sizeof(CHAR));
786     }
787     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
788     {
789         _SEH2_YIELD(return _SEH2_GetExceptionCode());
790     }
791     _SEH2_END;
792 
793     Status = IopCaptureUnicodeString(&DeviceInstance, &RelationsData->DeviceInstance);
794     if (!NT_SUCCESS(Status))
795     {
796         DPRINT1("IopCaptureUnicodeString() failed (Status 0x%08lx)\n", Status);
797         return Status;
798     }
799 
800     /* Get the device object */
801     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
802     if (DeviceObject == NULL)
803     {
804         DPRINT1("IopGetDeviceObjectFromDeviceInstance() returned NULL\n");
805         Status = STATUS_NO_SUCH_DEVICE;
806         goto done;
807     }
808 
809     switch (Relations)
810     {
811         case PNP_EJECT_RELATIONS:
812             Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
813             break;
814 
815         case PNP_REMOVAL_RELATIONS:
816             Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
817             break;
818 
819         case PNP_POWER_RELATIONS:
820             Stack.Parameters.QueryDeviceRelations.Type = PowerRelations;
821             break;
822 
823         case PNP_BUS_RELATIONS:
824             Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
825             break;
826 
827         default:
828             Status = STATUS_INVALID_PARAMETER;
829             goto done;
830     }
831 
832     Status = IopInitiatePnpIrp(DeviceObject,
833                                &IoStatusBlock,
834                                IRP_MN_QUERY_DEVICE_RELATIONS,
835                                &Stack);
836     if (!NT_SUCCESS(Status))
837     {
838         DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
839         goto done;
840     }
841 
842     DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
843 
844     DPRINT("Found %d device relations\n", DeviceRelations->Count);
845 
846     _SEH2_TRY
847     {
848         RequiredSize = 0;
849         BufferLeft = BufferSize;
850         Ptr = Buffer;
851 
852         for (i = 0; i < DeviceRelations->Count; i++)
853         {
854             ChildDeviceObject = DeviceRelations->Objects[i];
855 
856             ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
857             if (ChildDeviceNode)
858             {
859                 DPRINT("Device instance: %wZ\n", &ChildDeviceNode->InstancePath);
860                 DPRINT("RequiredSize: %hu\n", ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
861 
862                 if (Ptr != NULL)
863                 {
864                     if (BufferLeft < ChildDeviceNode->InstancePath.Length + 2 * sizeof(WCHAR))
865                     {
866                         Status = STATUS_BUFFER_TOO_SMALL;
867                         break;
868                     }
869 
870                     RtlCopyMemory(Ptr,
871                                   ChildDeviceNode->InstancePath.Buffer,
872                                   ChildDeviceNode->InstancePath.Length);
873                     Ptr = (PWCHAR)((ULONG_PTR)Ptr + ChildDeviceNode->InstancePath.Length);
874                     *Ptr = UNICODE_NULL;
875                     Ptr = (PWCHAR)((ULONG_PTR)Ptr + sizeof(WCHAR));
876 
877                     BufferLeft -= (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
878                 }
879 
880                 RequiredSize += (ChildDeviceNode->InstancePath.Length + sizeof(WCHAR));
881             }
882         }
883 
884         if (Ptr != NULL && BufferLeft >= sizeof(WCHAR))
885             *Ptr = UNICODE_NULL;
886 
887         if (RequiredSize > 0)
888             RequiredSize += sizeof(WCHAR);
889 
890         DPRINT("BufferSize: %lu  RequiredSize: %lu\n", RelationsData->BufferSize, RequiredSize);
891 
892         RelationsData->BufferSize = RequiredSize;
893     }
894     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
895     {
896         Status = _SEH2_GetExceptionCode();
897     }
898     _SEH2_END;
899 
900 done:
901     if (DeviceRelations != NULL)
902         ExFreePool(DeviceRelations);
903 
904     if (DeviceObject != NULL)
905         ObDereferenceObject(DeviceObject);
906 
907     if (DeviceInstance.Buffer != NULL)
908         ExFreePool(DeviceInstance.Buffer);
909 
910     return Status;
911 }
912 
913 static NTSTATUS
914 IopGetDeviceDepth(PPLUGPLAY_CONTROL_DEPTH_DATA DepthData)
915 {
916     PDEVICE_OBJECT DeviceObject;
917     PDEVICE_NODE DeviceNode;
918     UNICODE_STRING DeviceInstance;
919     NTSTATUS Status = STATUS_SUCCESS;
920 
921     DPRINT("IopGetDeviceDepth() called\n");
922     DPRINT("Device name: %wZ\n", &DepthData->DeviceInstance);
923 
924     Status = IopCaptureUnicodeString(&DeviceInstance, &DepthData->DeviceInstance);
925     if (!NT_SUCCESS(Status))
926     {
927         return Status;
928     }
929 
930     /* Get the device object */
931     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
932     if (DeviceInstance.Buffer != NULL)
933     {
934         ExFreePool(DeviceInstance.Buffer);
935     }
936     if (DeviceObject == NULL)
937     {
938         return STATUS_NO_SUCH_DEVICE;
939     }
940 
941     DeviceNode = IopGetDeviceNode(DeviceObject);
942 
943     _SEH2_TRY
944     {
945         DepthData->Depth = DeviceNode->Level;
946     }
947     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
948     {
949         Status = _SEH2_GetExceptionCode();
950     }
951     _SEH2_END;
952 
953     ObDereferenceObject(DeviceObject);
954 
955     return Status;
956 }
957 
958 
959 static NTSTATUS
960 IopResetDevice(PPLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData)
961 {
962     PDEVICE_OBJECT DeviceObject;
963     PDEVICE_NODE DeviceNode;
964     NTSTATUS Status = STATUS_SUCCESS;
965     UNICODE_STRING DeviceInstance;
966 
967     Status = IopCaptureUnicodeString(&DeviceInstance, &ResetDeviceData->DeviceInstance);
968     if (!NT_SUCCESS(Status))
969     {
970         return Status;
971     }
972 
973     DPRINT("IopResetDevice(%wZ)\n", &DeviceInstance);
974 
975     /* Get the device object */
976     DeviceObject = IopGetDeviceObjectFromDeviceInstance(&DeviceInstance);
977     if (DeviceInstance.Buffer != NULL)
978     {
979         ExFreePool(DeviceInstance.Buffer);
980     }
981     if (DeviceObject == NULL)
982     {
983         return STATUS_NO_SUCH_DEVICE;
984     }
985 
986     /* Get the device node */
987     DeviceNode = IopGetDeviceNode(DeviceObject);
988 
989     ASSERT(DeviceNode->Flags & DNF_ENUMERATED);
990     ASSERT(DeviceNode->Flags & DNF_PROCESSED);
991 
992     /* Check if there's already a driver loaded for this device */
993     if (DeviceNode->Flags & DNF_ADDED)
994     {
995 #if 0
996         /* Remove the device node */
997         Status = IopRemoveDevice(DeviceNode);
998         if (NT_SUCCESS(Status))
999         {
1000             /* Invalidate device relations for the parent to reenumerate the device */
1001             DPRINT1("A new driver will be loaded for '%wZ' (FDO above removed)\n", &DeviceNode->InstancePath);
1002             Status = IoSynchronousInvalidateDeviceRelations(DeviceNode->Parent->PhysicalDeviceObject, BusRelations);
1003         }
1004         else
1005 #endif
1006         {
1007             /* A driver has already been loaded for this device */
1008             DPRINT1("A reboot is required for the current driver for '%wZ' to be replaced\n", &DeviceNode->InstancePath);
1009             DeviceNode->Problem = CM_PROB_NEED_RESTART;
1010         }
1011     }
1012     else
1013     {
1014         /* FIXME: What if the device really is disabled? */
1015         DeviceNode->Flags &= ~DNF_DISABLED;
1016         DeviceNode->Problem = 0;
1017 
1018         /* Load service data from the registry */
1019         Status = IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent);
1020 
1021         if (NT_SUCCESS(Status))
1022         {
1023             /* Start the service and begin PnP initialization of the device again */
1024             DPRINT1("A new driver will be loaded for '%wZ' (no FDO above)\n", &DeviceNode->InstancePath);
1025             Status = IopActionInitChildServices(DeviceNode, DeviceNode->Parent);
1026         }
1027     }
1028 
1029     ObDereferenceObject(DeviceObject);
1030 
1031     return Status;
1032 }
1033 
1034 /* PUBLIC FUNCTIONS **********************************************************/
1035 
1036 /*
1037  * Plug and Play event structure used by NtGetPlugPlayEvent.
1038  *
1039  * EventGuid
1040  *    Can be one of the following values:
1041  *       GUID_HWPROFILE_QUERY_CHANGE
1042  *       GUID_HWPROFILE_CHANGE_CANCELLED
1043  *       GUID_HWPROFILE_CHANGE_COMPLETE
1044  *       GUID_TARGET_DEVICE_QUERY_REMOVE
1045  *       GUID_TARGET_DEVICE_REMOVE_CANCELLED
1046  *       GUID_TARGET_DEVICE_REMOVE_COMPLETE
1047  *       GUID_PNP_CUSTOM_NOTIFICATION
1048  *       GUID_PNP_POWER_NOTIFICATION
1049  *       GUID_DEVICE_* (see above)
1050  *
1051  * EventCategory
1052  *    Type of the event that happened.
1053  *
1054  * Result
1055  *    ?
1056  *
1057  * Flags
1058  *    ?
1059  *
1060  * TotalSize
1061  *    Size of the event block including the device IDs and other
1062  *    per category specific fields.
1063  */
1064 
1065 /*
1066  * NtGetPlugPlayEvent
1067  *
1068  * Returns one Plug & Play event from a global queue.
1069  *
1070  * Parameters
1071  *    Reserved1
1072  *    Reserved2
1073  *       Always set to zero.
1074  *
1075  *    Buffer
1076  *       The buffer that will be filled with the event information on
1077  *       successful return from the function.
1078  *
1079  *    BufferSize
1080  *       Size of the buffer pointed by the Buffer parameter. If the
1081  *       buffer size is not large enough to hold the whole event
1082  *       information, error STATUS_BUFFER_TOO_SMALL is returned and
1083  *       the buffer remains untouched.
1084  *
1085  * Return Values
1086  *    STATUS_PRIVILEGE_NOT_HELD
1087  *    STATUS_BUFFER_TOO_SMALL
1088  *    STATUS_SUCCESS
1089  *
1090  * Remarks
1091  *    This function isn't multi-thread safe!
1092  *
1093  * @implemented
1094  */
1095 NTSTATUS
1096 NTAPI
1097 NtGetPlugPlayEvent(IN ULONG Reserved1,
1098                    IN ULONG Reserved2,
1099                    OUT PPLUGPLAY_EVENT_BLOCK Buffer,
1100                    IN ULONG BufferSize)
1101 {
1102     PPNP_EVENT_ENTRY Entry;
1103     NTSTATUS Status;
1104 
1105     DPRINT("NtGetPlugPlayEvent() called\n");
1106 
1107     /* Function can only be called from user-mode */
1108     if (KeGetPreviousMode() == KernelMode)
1109     {
1110         DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1111         return STATUS_ACCESS_DENIED;
1112     }
1113 
1114     /* Check for Tcb privilege */
1115     if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
1116                                 UserMode))
1117     {
1118         DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1119         return STATUS_PRIVILEGE_NOT_HELD;
1120     }
1121 
1122     /* Wait for a PnP event */
1123     DPRINT("Waiting for pnp notification event\n");
1124     Status = KeWaitForSingleObject(&IopPnpNotifyEvent,
1125                                    UserRequest,
1126                                    UserMode,
1127                                    FALSE,
1128                                    NULL);
1129     if (!NT_SUCCESS(Status) || Status == STATUS_USER_APC)
1130     {
1131         DPRINT("KeWaitForSingleObject() failed (Status %lx)\n", Status);
1132         ASSERT(Status == STATUS_USER_APC);
1133         return Status;
1134     }
1135 
1136     /* Get entry from the tail of the queue */
1137     Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink,
1138                               PNP_EVENT_ENTRY,
1139                               ListEntry);
1140 
1141     /* Check the buffer size */
1142     if (BufferSize < Entry->Event.TotalSize)
1143     {
1144         DPRINT1("Buffer is too small for the pnp-event\n");
1145         return STATUS_BUFFER_TOO_SMALL;
1146     }
1147 
1148     /* Copy event data to the user buffer */
1149     _SEH2_TRY
1150     {
1151         ProbeForWrite(Buffer,
1152                       Entry->Event.TotalSize,
1153                       sizeof(UCHAR));
1154         RtlCopyMemory(Buffer,
1155                       &Entry->Event,
1156                       Entry->Event.TotalSize);
1157     }
1158     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1159     {
1160         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1161     }
1162     _SEH2_END;
1163 
1164     DPRINT("NtGetPlugPlayEvent() done\n");
1165 
1166     return STATUS_SUCCESS;
1167 }
1168 
1169 /*
1170  * NtPlugPlayControl
1171  *
1172  * A function for doing various Plug & Play operations from user mode.
1173  *
1174  * Parameters
1175  *    PlugPlayControlClass
1176  *       0x00   Reenumerate device tree
1177  *
1178  *              Buffer points to UNICODE_STRING decribing the instance
1179  *              path (like "HTREE\ROOT\0" or "Root\ACPI_HAL\0000"). For
1180  *              more information about instance paths see !devnode command
1181  *              in kernel debugger or look at "Inside Windows 2000" book,
1182  *              chapter "Driver Loading, Initialization, and Installation".
1183  *
1184  *       0x01   Register new device
1185  *       0x02   Deregister device
1186  *       0x03   Initialize device
1187  *       0x04   Start device
1188  *       0x06   Query and remove device
1189  *       0x07   User response
1190  *
1191  *              Called after processing the message from NtGetPlugPlayEvent.
1192  *
1193  *       0x08   Generate legacy device
1194  *       0x09   Get interface device list
1195  *       0x0A   Get property data
1196  *       0x0B   Device class association (Registration)
1197  *       0x0C   Get related device
1198  *       0x0D   Get device interface alias
1199  *       0x0E   Get/set/clear device status
1200  *       0x0F   Get device depth
1201  *       0x10   Query device relations
1202  *       0x11   Query target device relation
1203  *       0x12   Query conflict list
1204  *       0x13   Retrieve dock data
1205  *       0x14   Reset device
1206  *       0x15   Halt device
1207  *       0x16   Get blocked driver data
1208  *
1209  *    Buffer
1210  *       The buffer contains information that is specific to each control
1211  *       code. The buffer is read-only.
1212  *
1213  *    BufferSize
1214  *       Size of the buffer pointed by the Buffer parameter. If the
1215  *       buffer size specifies incorrect value for specified control
1216  *       code, error ??? is returned.
1217  *
1218  * Return Values
1219  *    STATUS_PRIVILEGE_NOT_HELD
1220  *    STATUS_SUCCESS
1221  *    ...
1222  *
1223  * @unimplemented
1224  */
1225 NTSTATUS
1226 NTAPI
1227 NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass,
1228                   IN OUT PVOID Buffer,
1229                   IN ULONG BufferLength)
1230 {
1231     DPRINT("NtPlugPlayControl(%d %p %lu) called\n",
1232            PlugPlayControlClass, Buffer, BufferLength);
1233 
1234     /* Function can only be called from user-mode */
1235     if (KeGetPreviousMode() == KernelMode)
1236     {
1237         DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
1238         return STATUS_ACCESS_DENIED;
1239     }
1240 
1241     /* Check for Tcb privilege */
1242     if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
1243                                 UserMode))
1244     {
1245         DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
1246         return STATUS_PRIVILEGE_NOT_HELD;
1247     }
1248 
1249     /* Probe the buffer */
1250     _SEH2_TRY
1251     {
1252         ProbeForWrite(Buffer,
1253                       BufferLength,
1254                       sizeof(ULONG));
1255     }
1256     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1257     {
1258         _SEH2_YIELD(return _SEH2_GetExceptionCode());
1259     }
1260     _SEH2_END;
1261 
1262     switch (PlugPlayControlClass)
1263     {
1264 //        case PlugPlayControlEnumerateDevice:
1265 //        case PlugPlayControlRegisterNewDevice:
1266 //        case PlugPlayControlDeregisterDevice:
1267 //        case PlugPlayControlInitializeDevice:
1268 //        case PlugPlayControlStartDevice:
1269 //        case PlugPlayControlUnlockDevice:
1270 //        case PlugPlayControlQueryAndRemoveDevice:
1271 
1272         case PlugPlayControlUserResponse:
1273             if (Buffer || BufferLength != 0)
1274                 return STATUS_INVALID_PARAMETER;
1275             return IopRemovePlugPlayEvent();
1276 
1277 //        case PlugPlayControlGenerateLegacyDevice:
1278 
1279         case PlugPlayControlGetInterfaceDeviceList:
1280             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA))
1281                 return STATUS_INVALID_PARAMETER;
1282             return IopGetInterfaceDeviceList((PPLUGPLAY_CONTROL_INTERFACE_DEVICE_LIST_DATA)Buffer);
1283 
1284         case PlugPlayControlProperty:
1285             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA))
1286                 return STATUS_INVALID_PARAMETER;
1287             return IopGetDeviceProperty((PPLUGPLAY_CONTROL_PROPERTY_DATA)Buffer);
1288 
1289 //        case PlugPlayControlDeviceClassAssociation:
1290 
1291         case PlugPlayControlGetRelatedDevice:
1292             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA))
1293                 return STATUS_INVALID_PARAMETER;
1294             return IopGetRelatedDevice((PPLUGPLAY_CONTROL_RELATED_DEVICE_DATA)Buffer);
1295 
1296 //        case PlugPlayControlGetInterfaceDeviceAlias:
1297 
1298         case PlugPlayControlDeviceStatus:
1299             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_STATUS_DATA))
1300                 return STATUS_INVALID_PARAMETER;
1301             return IopDeviceStatus((PPLUGPLAY_CONTROL_STATUS_DATA)Buffer);
1302 
1303         case PlugPlayControlGetDeviceDepth:
1304             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEPTH_DATA))
1305                 return STATUS_INVALID_PARAMETER;
1306             return IopGetDeviceDepth((PPLUGPLAY_CONTROL_DEPTH_DATA)Buffer);
1307 
1308         case PlugPlayControlQueryDeviceRelations:
1309             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA))
1310                 return STATUS_INVALID_PARAMETER;
1311             return IopGetDeviceRelations((PPLUGPLAY_CONTROL_DEVICE_RELATIONS_DATA)Buffer);
1312 
1313 //        case PlugPlayControlTargetDeviceRelation:
1314 //        case PlugPlayControlQueryConflictList:
1315 //        case PlugPlayControlRetrieveDock:
1316 
1317         case PlugPlayControlResetDevice:
1318             if (!Buffer || BufferLength < sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA))
1319                 return STATUS_INVALID_PARAMETER;
1320             return IopResetDevice((PPLUGPLAY_CONTROL_RESET_DEVICE_DATA)Buffer);
1321 
1322 //        case PlugPlayControlHaltDevice:
1323 //        case PlugPlayControlGetBlockedDriverList:
1324 
1325         default:
1326             return STATUS_NOT_IMPLEMENTED;
1327     }
1328 
1329     return STATUS_NOT_IMPLEMENTED;
1330 }
1331