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