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