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