83a4cb6000886ef6ed75bf9bfed2cd3d45d74cca
[reactos.git] / ntoskrnl / io / pnpmgr / plugplay.c
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 }