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