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