[NTOSKRNL] IoGetDeviceProperty: Add support for the DevicePropertyRemovalPolicy...
[reactos.git] / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 PDEVICE_NODE IopRootDeviceNode;
19 KSPIN_LOCK IopDeviceTreeLock;
20 ERESOURCE PpRegistryDeviceResource;
21 KGUARDED_MUTEX PpDeviceReferenceTableLock;
22 RTL_AVL_TABLE PpDeviceReferenceTable;
23
24 extern ERESOURCE IopDriverLoadResource;
25 extern ULONG ExpInitializationPhase;
26 extern BOOLEAN ExpInTextModeSetup;
27 extern BOOLEAN PnpSystemInit;
28
29 #define MAX_DEVICE_ID_LEN 200
30 #define MAX_SEPARATORS_INSTANCEID 0
31 #define MAX_SEPARATORS_DEVICEID 1
32
33 /* DATA **********************************************************************/
34
35 PDRIVER_OBJECT IopRootDriverObject;
36 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
37 LIST_ENTRY IopDeviceActionRequestList;
38 WORK_QUEUE_ITEM IopDeviceActionWorkItem;
39 BOOLEAN IopDeviceActionInProgress;
40 KSPIN_LOCK IopDeviceActionLock;
41
42 typedef struct _DEVICE_ACTION_DATA
43 {
44 LIST_ENTRY RequestListEntry;
45 PDEVICE_OBJECT DeviceObject;
46 DEVICE_RELATION_TYPE Type;
47 } DEVICE_ACTION_DATA, *PDEVICE_ACTION_DATA;
48
49 /* FUNCTIONS *****************************************************************/
50 NTSTATUS
51 NTAPI
52 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
53 IN ULONG CreateOptions,
54 OUT PHANDLE Handle);
55
56 VOID
57 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject);
58
59 NTSTATUS
60 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force);
61
62 PDEVICE_OBJECT
63 IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance);
64
65 PDEVICE_NODE
66 FASTCALL
67 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
68 {
69 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
70 }
71
72 VOID
73 IopFixupDeviceId(PWCHAR String)
74 {
75 SIZE_T Length = wcslen(String), i;
76
77 for (i = 0; i < Length; i++)
78 {
79 if (String[i] == L'\\')
80 String[i] = L'#';
81 }
82 }
83
84 VOID
85 NTAPI
86 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
87 {
88 NTSTATUS Status;
89 HANDLE CriticalDeviceKey, InstanceKey;
90 OBJECT_ATTRIBUTES ObjectAttributes;
91 UNICODE_STRING CriticalDeviceKeyU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
92 UNICODE_STRING CompatibleIdU = RTL_CONSTANT_STRING(L"CompatibleIDs");
93 UNICODE_STRING HardwareIdU = RTL_CONSTANT_STRING(L"HardwareID");
94 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service");
95 UNICODE_STRING ClassGuidU = RTL_CONSTANT_STRING(L"ClassGUID");
96 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
97 ULONG HidLength = 0, CidLength = 0, BufferLength;
98 PWCHAR IdBuffer, OriginalIdBuffer;
99
100 /* Open the device instance key */
101 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
102 if (Status != STATUS_SUCCESS)
103 return;
104
105 Status = ZwQueryValueKey(InstanceKey,
106 &HardwareIdU,
107 KeyValuePartialInformation,
108 NULL,
109 0,
110 &HidLength);
111 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
112 {
113 ZwClose(InstanceKey);
114 return;
115 }
116
117 Status = ZwQueryValueKey(InstanceKey,
118 &CompatibleIdU,
119 KeyValuePartialInformation,
120 NULL,
121 0,
122 &CidLength);
123 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
124 {
125 CidLength = 0;
126 }
127
128 BufferLength = HidLength + CidLength;
129 BufferLength -= (((CidLength != 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
130
131 /* Allocate a buffer to hold data from both */
132 OriginalIdBuffer = IdBuffer = ExAllocatePool(PagedPool, BufferLength);
133 if (!IdBuffer)
134 {
135 ZwClose(InstanceKey);
136 return;
137 }
138
139 /* Compute the buffer size */
140 if (HidLength > CidLength)
141 BufferLength = HidLength;
142 else
143 BufferLength = CidLength;
144
145 PartialInfo = ExAllocatePool(PagedPool, BufferLength);
146 if (!PartialInfo)
147 {
148 ZwClose(InstanceKey);
149 ExFreePool(OriginalIdBuffer);
150 return;
151 }
152
153 Status = ZwQueryValueKey(InstanceKey,
154 &HardwareIdU,
155 KeyValuePartialInformation,
156 PartialInfo,
157 HidLength,
158 &HidLength);
159 if (Status != STATUS_SUCCESS)
160 {
161 ExFreePool(PartialInfo);
162 ExFreePool(OriginalIdBuffer);
163 ZwClose(InstanceKey);
164 return;
165 }
166
167 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
168 HidLength = PartialInfo->DataLength - ((CidLength != 0) ? sizeof(WCHAR) : 0);
169 RtlCopyMemory(IdBuffer, PartialInfo->Data, HidLength);
170
171 if (CidLength != 0)
172 {
173 Status = ZwQueryValueKey(InstanceKey,
174 &CompatibleIdU,
175 KeyValuePartialInformation,
176 PartialInfo,
177 CidLength,
178 &CidLength);
179 if (Status != STATUS_SUCCESS)
180 {
181 ExFreePool(PartialInfo);
182 ExFreePool(OriginalIdBuffer);
183 ZwClose(InstanceKey);
184 return;
185 }
186
187 /* Copy CID next */
188 CidLength = PartialInfo->DataLength;
189 RtlCopyMemory(((PUCHAR)IdBuffer) + HidLength, PartialInfo->Data, CidLength);
190 }
191
192 /* Free our temp buffer */
193 ExFreePool(PartialInfo);
194
195 InitializeObjectAttributes(&ObjectAttributes,
196 &CriticalDeviceKeyU,
197 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
198 NULL,
199 NULL);
200 Status = ZwOpenKey(&CriticalDeviceKey,
201 KEY_ENUMERATE_SUB_KEYS,
202 &ObjectAttributes);
203 if (!NT_SUCCESS(Status))
204 {
205 /* The critical device database doesn't exist because
206 * we're probably in 1st stage setup, but it's ok */
207 ExFreePool(OriginalIdBuffer);
208 ZwClose(InstanceKey);
209 return;
210 }
211
212 while (*IdBuffer)
213 {
214 USHORT StringLength = (USHORT)wcslen(IdBuffer) + 1, Index;
215
216 IopFixupDeviceId(IdBuffer);
217
218 /* Look through all subkeys for a match */
219 for (Index = 0; TRUE; Index++)
220 {
221 ULONG NeededLength;
222 PKEY_BASIC_INFORMATION BasicInfo;
223
224 Status = ZwEnumerateKey(CriticalDeviceKey,
225 Index,
226 KeyBasicInformation,
227 NULL,
228 0,
229 &NeededLength);
230 if (Status == STATUS_NO_MORE_ENTRIES)
231 break;
232 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
233 {
234 UNICODE_STRING ChildIdNameU, RegKeyNameU;
235
236 BasicInfo = ExAllocatePool(PagedPool, NeededLength);
237 if (!BasicInfo)
238 {
239 /* No memory */
240 ExFreePool(OriginalIdBuffer);
241 ZwClose(CriticalDeviceKey);
242 ZwClose(InstanceKey);
243 return;
244 }
245
246 Status = ZwEnumerateKey(CriticalDeviceKey,
247 Index,
248 KeyBasicInformation,
249 BasicInfo,
250 NeededLength,
251 &NeededLength);
252 if (Status != STATUS_SUCCESS)
253 {
254 /* This shouldn't happen */
255 ExFreePool(BasicInfo);
256 continue;
257 }
258
259 ChildIdNameU.Buffer = IdBuffer;
260 ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR);
261 RegKeyNameU.Buffer = BasicInfo->Name;
262 RegKeyNameU.MaximumLength = RegKeyNameU.Length = (USHORT)BasicInfo->NameLength;
263
264 if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE))
265 {
266 HANDLE ChildKeyHandle;
267
268 InitializeObjectAttributes(&ObjectAttributes,
269 &ChildIdNameU,
270 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
271 CriticalDeviceKey,
272 NULL);
273
274 Status = ZwOpenKey(&ChildKeyHandle,
275 KEY_QUERY_VALUE,
276 &ObjectAttributes);
277 if (Status != STATUS_SUCCESS)
278 {
279 ExFreePool(BasicInfo);
280 continue;
281 }
282
283 /* Check if there's already a driver installed */
284 Status = ZwQueryValueKey(InstanceKey,
285 &ClassGuidU,
286 KeyValuePartialInformation,
287 NULL,
288 0,
289 &NeededLength);
290 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
291 {
292 ExFreePool(BasicInfo);
293 continue;
294 }
295
296 Status = ZwQueryValueKey(ChildKeyHandle,
297 &ClassGuidU,
298 KeyValuePartialInformation,
299 NULL,
300 0,
301 &NeededLength);
302 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
303 {
304 ExFreePool(BasicInfo);
305 continue;
306 }
307
308 PartialInfo = ExAllocatePool(PagedPool, NeededLength);
309 if (!PartialInfo)
310 {
311 ExFreePool(OriginalIdBuffer);
312 ExFreePool(BasicInfo);
313 ZwClose(InstanceKey);
314 ZwClose(ChildKeyHandle);
315 ZwClose(CriticalDeviceKey);
316 return;
317 }
318
319 /* Read ClassGUID entry in the CDDB */
320 Status = ZwQueryValueKey(ChildKeyHandle,
321 &ClassGuidU,
322 KeyValuePartialInformation,
323 PartialInfo,
324 NeededLength,
325 &NeededLength);
326 if (Status != STATUS_SUCCESS)
327 {
328 ExFreePool(BasicInfo);
329 continue;
330 }
331
332 /* Write it to the ENUM key */
333 Status = ZwSetValueKey(InstanceKey,
334 &ClassGuidU,
335 0,
336 REG_SZ,
337 PartialInfo->Data,
338 PartialInfo->DataLength);
339 if (Status != STATUS_SUCCESS)
340 {
341 ExFreePool(BasicInfo);
342 ExFreePool(PartialInfo);
343 ZwClose(ChildKeyHandle);
344 continue;
345 }
346
347 Status = ZwQueryValueKey(ChildKeyHandle,
348 &ServiceU,
349 KeyValuePartialInformation,
350 NULL,
351 0,
352 &NeededLength);
353 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
354 {
355 ExFreePool(PartialInfo);
356 PartialInfo = ExAllocatePool(PagedPool, NeededLength);
357 if (!PartialInfo)
358 {
359 ExFreePool(OriginalIdBuffer);
360 ExFreePool(BasicInfo);
361 ZwClose(InstanceKey);
362 ZwClose(ChildKeyHandle);
363 ZwClose(CriticalDeviceKey);
364 return;
365 }
366
367 /* Read the service entry from the CDDB */
368 Status = ZwQueryValueKey(ChildKeyHandle,
369 &ServiceU,
370 KeyValuePartialInformation,
371 PartialInfo,
372 NeededLength,
373 &NeededLength);
374 if (Status != STATUS_SUCCESS)
375 {
376 ExFreePool(BasicInfo);
377 ExFreePool(PartialInfo);
378 ZwClose(ChildKeyHandle);
379 continue;
380 }
381
382 /* Write it to the ENUM key */
383 Status = ZwSetValueKey(InstanceKey,
384 &ServiceU,
385 0,
386 REG_SZ,
387 PartialInfo->Data,
388 PartialInfo->DataLength);
389 if (Status != STATUS_SUCCESS)
390 {
391 ExFreePool(BasicInfo);
392 ExFreePool(PartialInfo);
393 ZwClose(ChildKeyHandle);
394 continue;
395 }
396
397 DPRINT("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU);
398 }
399 else
400 {
401 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU);
402 }
403
404 ExFreePool(OriginalIdBuffer);
405 ExFreePool(PartialInfo);
406 ExFreePool(BasicInfo);
407 ZwClose(InstanceKey);
408 ZwClose(ChildKeyHandle);
409 ZwClose(CriticalDeviceKey);
410
411 /* That's it */
412 return;
413 }
414
415 ExFreePool(BasicInfo);
416 }
417 else
418 {
419 /* Umm, not sure what happened here */
420 continue;
421 }
422 }
423
424 /* Advance to the next ID */
425 IdBuffer += StringLength;
426 }
427
428 ExFreePool(OriginalIdBuffer);
429 ZwClose(InstanceKey);
430 ZwClose(CriticalDeviceKey);
431 }
432
433 NTSTATUS
434 FASTCALL
435 IopInitializeDevice(PDEVICE_NODE DeviceNode,
436 PDRIVER_OBJECT DriverObject)
437 {
438 PDEVICE_OBJECT Fdo;
439 NTSTATUS Status;
440
441 if (!DriverObject)
442 {
443 /* Special case for bus driven devices */
444 DeviceNode->Flags |= DNF_ADDED;
445 return STATUS_SUCCESS;
446 }
447
448 if (!DriverObject->DriverExtension->AddDevice)
449 {
450 DeviceNode->Flags |= DNF_LEGACY_DRIVER;
451 }
452
453 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
454 {
455 DeviceNode->Flags |= (DNF_ADDED | DNF_STARTED);
456 return STATUS_SUCCESS;
457 }
458
459 /* This is a Plug and Play driver */
460 DPRINT("Plug and Play driver found\n");
461 ASSERT(DeviceNode->PhysicalDeviceObject);
462
463 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
464 &DriverObject->DriverName,
465 &DeviceNode->InstancePath);
466 Status = DriverObject->DriverExtension->AddDevice(DriverObject,
467 DeviceNode->PhysicalDeviceObject);
468 if (!NT_SUCCESS(Status))
469 {
470 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
471 &DriverObject->DriverName,
472 &DeviceNode->InstancePath,
473 Status);
474 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
475 DeviceNode->Problem = CM_PROB_FAILED_ADD;
476 return Status;
477 }
478
479 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
480
481 /* Check if we have a ACPI device (needed for power management) */
482 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
483 {
484 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
485
486 /* There can be only one system power device */
487 if (!SystemPowerDeviceNodeCreated)
488 {
489 PopSystemPowerDeviceNode = DeviceNode;
490 ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject);
491 SystemPowerDeviceNodeCreated = TRUE;
492 }
493 }
494
495 ObDereferenceObject(Fdo);
496
497 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
498
499 return STATUS_SUCCESS;
500 }
501
502 static
503 NTSTATUS
504 NTAPI
505 IopSendEject(IN PDEVICE_OBJECT DeviceObject)
506 {
507 IO_STACK_LOCATION Stack;
508 PVOID Dummy;
509
510 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
511 Stack.MajorFunction = IRP_MJ_PNP;
512 Stack.MinorFunction = IRP_MN_EJECT;
513
514 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
515 }
516
517 static
518 VOID
519 NTAPI
520 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
521 {
522 IO_STACK_LOCATION Stack;
523 PVOID Dummy;
524
525 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
526 Stack.MajorFunction = IRP_MJ_PNP;
527 Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL;
528
529 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
530 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
531 }
532
533 static
534 NTSTATUS
535 NTAPI
536 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
537 {
538 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
539 IO_STACK_LOCATION Stack;
540 PVOID Dummy;
541 NTSTATUS Status;
542
543 ASSERT(DeviceNode);
544
545 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
546 &DeviceNode->InstancePath);
547
548 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
549 Stack.MajorFunction = IRP_MJ_PNP;
550 Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE;
551
552 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
553
554 IopNotifyPlugPlayNotification(DeviceObject,
555 EventCategoryTargetDeviceChange,
556 &GUID_TARGET_DEVICE_QUERY_REMOVE,
557 NULL,
558 NULL);
559
560 if (!NT_SUCCESS(Status))
561 {
562 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath);
563 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
564 &DeviceNode->InstancePath);
565 }
566
567 return Status;
568 }
569
570 static
571 NTSTATUS
572 NTAPI
573 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject)
574 {
575 IO_STACK_LOCATION Stack;
576 PVOID Dummy;
577
578 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
579 Stack.MajorFunction = IRP_MJ_PNP;
580 Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE;
581
582 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
583 }
584
585 static
586 VOID
587 NTAPI
588 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
589 {
590 IO_STACK_LOCATION Stack;
591 PVOID Dummy;
592 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
593
594 /* Drop all our state for this device in case it isn't really going away */
595 DeviceNode->Flags &= DNF_ENUMERATED | DNF_PROCESSED;
596
597 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
598 Stack.MajorFunction = IRP_MJ_PNP;
599 Stack.MinorFunction = IRP_MN_REMOVE_DEVICE;
600
601 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
602 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
603
604 IopNotifyPlugPlayNotification(DeviceObject,
605 EventCategoryTargetDeviceChange,
606 &GUID_TARGET_DEVICE_REMOVE_COMPLETE,
607 NULL,
608 NULL);
609 ObDereferenceObject(DeviceObject);
610 }
611
612 static
613 VOID
614 NTAPI
615 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
616 {
617 IO_STACK_LOCATION Stack;
618 PVOID Dummy;
619
620 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
621 Stack.MajorFunction = IRP_MJ_PNP;
622 Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE;
623
624 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
625 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
626
627 IopNotifyPlugPlayNotification(DeviceObject,
628 EventCategoryTargetDeviceChange,
629 &GUID_TARGET_DEVICE_REMOVE_CANCELLED,
630 NULL,
631 NULL);
632 }
633
634 static
635 VOID
636 NTAPI
637 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject)
638 {
639 IO_STACK_LOCATION Stack;
640 PVOID Dummy;
641
642 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
643 Stack.MajorFunction = IRP_MJ_PNP;
644 Stack.MinorFunction = IRP_MN_STOP_DEVICE;
645
646 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
647 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
648 }
649
650 VOID
651 NTAPI
652 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
653 {
654 IO_STACK_LOCATION Stack;
655 PDEVICE_NODE DeviceNode;
656 NTSTATUS Status;
657 PVOID Dummy;
658 DEVICE_CAPABILITIES DeviceCapabilities;
659
660 /* Get the device node */
661 DeviceNode = IopGetDeviceNode(DeviceObject);
662
663 ASSERT(!(DeviceNode->Flags & DNF_DISABLED));
664
665 /* Build the I/O stack location */
666 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
667 Stack.MajorFunction = IRP_MJ_PNP;
668 Stack.MinorFunction = IRP_MN_START_DEVICE;
669
670 Stack.Parameters.StartDevice.AllocatedResources =
671 DeviceNode->ResourceList;
672 Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
673 DeviceNode->ResourceListTranslated;
674
675 /* Do the call */
676 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
677 if (!NT_SUCCESS(Status))
678 {
679 /* Send an IRP_MN_REMOVE_DEVICE request */
680 IopRemoveDevice(DeviceNode);
681
682 /* Set the appropriate flag */
683 DeviceNode->Flags |= DNF_START_FAILED;
684 DeviceNode->Problem = CM_PROB_FAILED_START;
685
686 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status);
687 return;
688 }
689
690 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
691
692 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
693 if (!NT_SUCCESS(Status))
694 {
695 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
696 }
697
698 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
699 IoInvalidateDeviceState(DeviceObject);
700
701 /* Otherwise, mark us as started */
702 DeviceNode->Flags |= DNF_STARTED;
703 DeviceNode->Flags &= ~DNF_STOPPED;
704
705 /* We now need enumeration */
706 DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
707 }
708
709 NTSTATUS
710 NTAPI
711 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
712 {
713 PDEVICE_OBJECT DeviceObject;
714 NTSTATUS Status;
715 PAGED_CODE();
716
717 /* Sanity check */
718 ASSERT((DeviceNode->Flags & DNF_ADDED));
719 ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED |
720 DNF_RESOURCE_REPORTED |
721 DNF_NO_RESOURCE_REQUIRED)));
722
723 /* Get the device object */
724 DeviceObject = DeviceNode->PhysicalDeviceObject;
725
726 /* Check if we're not started yet */
727 if (!(DeviceNode->Flags & DNF_STARTED))
728 {
729 /* Start us */
730 IopStartDevice2(DeviceObject);
731 }
732
733 /* Do we need to query IDs? This happens in the case of manual reporting */
734 #if 0
735 if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
736 {
737 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
738 /* And that case shouldn't happen yet */
739 ASSERT(FALSE);
740 }
741 #endif
742
743 /* Make sure we're started, and check if we need enumeration */
744 if ((DeviceNode->Flags & DNF_STARTED) &&
745 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY))
746 {
747 /* Enumerate us */
748 IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations);
749 Status = STATUS_SUCCESS;
750 }
751 else
752 {
753 /* Nothing to do */
754 Status = STATUS_SUCCESS;
755 }
756
757 /* Return */
758 return Status;
759 }
760
761 NTSTATUS
762 IopStopDevice(
763 PDEVICE_NODE DeviceNode)
764 {
765 NTSTATUS Status;
766
767 DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath);
768
769 Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject);
770 if (NT_SUCCESS(Status))
771 {
772 IopSendStopDevice(DeviceNode->PhysicalDeviceObject);
773
774 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
775 DeviceNode->Flags |= DNF_STOPPED;
776
777 return STATUS_SUCCESS;
778 }
779
780 return Status;
781 }
782
783 NTSTATUS
784 IopStartDevice(
785 PDEVICE_NODE DeviceNode)
786 {
787 NTSTATUS Status;
788 HANDLE InstanceHandle = NULL, ControlHandle = NULL;
789 UNICODE_STRING KeyName, ValueString;
790 OBJECT_ATTRIBUTES ObjectAttributes;
791
792 if (DeviceNode->Flags & DNF_DISABLED)
793 return STATUS_SUCCESS;
794
795 Status = IopAssignDeviceResources(DeviceNode);
796 if (!NT_SUCCESS(Status))
797 goto ByeBye;
798
799 /* New PnP ABI */
800 IopStartAndEnumerateDevice(DeviceNode);
801
802 /* FIX: Should be done in new device instance code */
803 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceHandle);
804 if (!NT_SUCCESS(Status))
805 goto ByeBye;
806
807 /* FIX: Should be done in IoXxxPrepareDriverLoading */
808 // {
809 RtlInitUnicodeString(&KeyName, L"Control");
810 InitializeObjectAttributes(&ObjectAttributes,
811 &KeyName,
812 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
813 InstanceHandle,
814 NULL);
815 Status = ZwCreateKey(&ControlHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
816 if (!NT_SUCCESS(Status))
817 goto ByeBye;
818
819 RtlInitUnicodeString(&KeyName, L"ActiveService");
820 ValueString = DeviceNode->ServiceName;
821 if (!ValueString.Buffer)
822 RtlInitUnicodeString(&ValueString, L"");
823 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, ValueString.Buffer, ValueString.Length + sizeof(UNICODE_NULL));
824 // }
825
826 ByeBye:
827 if (ControlHandle != NULL)
828 ZwClose(ControlHandle);
829
830 if (InstanceHandle != NULL)
831 ZwClose(InstanceHandle);
832
833 return Status;
834 }
835
836 NTSTATUS
837 NTAPI
838 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
839 PDEVICE_CAPABILITIES DeviceCaps)
840 {
841 IO_STATUS_BLOCK StatusBlock;
842 IO_STACK_LOCATION Stack;
843 NTSTATUS Status;
844 HANDLE InstanceKey;
845 UNICODE_STRING ValueName;
846
847 /* Set up the Header */
848 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
849 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
850 DeviceCaps->Version = 1;
851 DeviceCaps->Address = -1;
852 DeviceCaps->UINumber = -1;
853
854 /* Set up the Stack */
855 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
856 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
857
858 /* Send the IRP */
859 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
860 &StatusBlock,
861 IRP_MN_QUERY_CAPABILITIES,
862 &Stack);
863 if (!NT_SUCCESS(Status))
864 {
865 if (Status != STATUS_NOT_SUPPORTED)
866 {
867 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status);
868 }
869 return Status;
870 }
871
872 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCaps->Version + sizeof(DeviceCaps->Version));
873
874 if (DeviceCaps->NoDisplayInUI)
875 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
876 else
877 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
878
879 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
880 if (NT_SUCCESS(Status))
881 {
882 /* Set 'Capabilities' value */
883 RtlInitUnicodeString(&ValueName, L"Capabilities");
884 Status = ZwSetValueKey(InstanceKey,
885 &ValueName,
886 0,
887 REG_DWORD,
888 &DeviceNode->CapabilityFlags,
889 sizeof(ULONG));
890
891 /* Set 'UINumber' value */
892 if (DeviceCaps->UINumber != MAXULONG)
893 {
894 RtlInitUnicodeString(&ValueName, L"UINumber");
895 Status = ZwSetValueKey(InstanceKey,
896 &ValueName,
897 0,
898 REG_DWORD,
899 &DeviceCaps->UINumber,
900 sizeof(ULONG));
901 }
902
903 ZwClose(InstanceKey);
904 }
905
906 return Status;
907 }
908
909 static
910 VOID
911 NTAPI
912 IopDeviceActionWorker(
913 _In_ PVOID Context)
914 {
915 PLIST_ENTRY ListEntry;
916 PDEVICE_ACTION_DATA Data;
917 KIRQL OldIrql;
918
919 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
920 while (!IsListEmpty(&IopDeviceActionRequestList))
921 {
922 ListEntry = RemoveHeadList(&IopDeviceActionRequestList);
923 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
924 Data = CONTAINING_RECORD(ListEntry,
925 DEVICE_ACTION_DATA,
926 RequestListEntry);
927
928 IoSynchronousInvalidateDeviceRelations(Data->DeviceObject,
929 Data->Type);
930
931 ObDereferenceObject(Data->DeviceObject);
932 ExFreePoolWithTag(Data, TAG_IO);
933 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
934 }
935 IopDeviceActionInProgress = FALSE;
936 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
937 }
938
939 NTSTATUS
940 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
941 {
942 KIRQL OldIrql;
943
944 if (PopSystemPowerDeviceNode)
945 {
946 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
947 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
948 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
949
950 return STATUS_SUCCESS;
951 }
952
953 return STATUS_UNSUCCESSFUL;
954 }
955
956 USHORT
957 NTAPI
958 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
959 {
960 USHORT i = 0, FoundIndex = 0xFFFF;
961 ULONG NewSize;
962 PVOID NewList;
963
964 /* Acquire the lock */
965 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
966
967 /* Loop all entries */
968 while (i < PnpBusTypeGuidList->GuidCount)
969 {
970 /* Try to find a match */
971 if (RtlCompareMemory(BusTypeGuid,
972 &PnpBusTypeGuidList->Guids[i],
973 sizeof(GUID)) == sizeof(GUID))
974 {
975 /* Found it */
976 FoundIndex = i;
977 goto Quickie;
978 }
979 i++;
980 }
981
982 /* Check if we have to grow the list */
983 if (PnpBusTypeGuidList->GuidCount)
984 {
985 /* Calculate the new size */
986 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
987 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
988
989 /* Allocate the new copy */
990 NewList = ExAllocatePool(PagedPool, NewSize);
991
992 if (!NewList)
993 {
994 /* Fail */
995 ExFreePool(PnpBusTypeGuidList);
996 goto Quickie;
997 }
998
999 /* Now copy them, decrease the size too */
1000 NewSize -= sizeof(GUID);
1001 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
1002
1003 /* Free the old list */
1004 ExFreePool(PnpBusTypeGuidList);
1005
1006 /* Use the new buffer */
1007 PnpBusTypeGuidList = NewList;
1008 }
1009
1010 /* Copy the new GUID */
1011 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
1012 BusTypeGuid,
1013 sizeof(GUID));
1014
1015 /* The new entry is the index */
1016 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
1017 PnpBusTypeGuidList->GuidCount++;
1018
1019 Quickie:
1020 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
1021 return FoundIndex;
1022 }
1023
1024 /*
1025 * DESCRIPTION
1026 * Creates a device node
1027 *
1028 * ARGUMENTS
1029 * ParentNode = Pointer to parent device node
1030 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
1031 * to have the root device node create one
1032 * (eg. for legacy drivers)
1033 * DeviceNode = Pointer to storage for created device node
1034 *
1035 * RETURN VALUE
1036 * Status
1037 */
1038 NTSTATUS
1039 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
1040 PDEVICE_OBJECT PhysicalDeviceObject,
1041 PUNICODE_STRING ServiceName,
1042 PDEVICE_NODE *DeviceNode)
1043 {
1044 PDEVICE_NODE Node;
1045 NTSTATUS Status;
1046 KIRQL OldIrql;
1047 UNICODE_STRING FullServiceName;
1048 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
1049 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
1050 UNICODE_STRING KeyName, ClassName;
1051 PUNICODE_STRING ServiceName1;
1052 ULONG LegacyValue;
1053 UNICODE_STRING ClassGUID;
1054 HANDLE InstanceHandle;
1055
1056 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1057 ParentNode, PhysicalDeviceObject, ServiceName);
1058
1059 Node = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE);
1060 if (!Node)
1061 {
1062 return STATUS_INSUFFICIENT_RESOURCES;
1063 }
1064
1065 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
1066
1067 if (!ServiceName)
1068 ServiceName1 = &UnknownDeviceName;
1069 else
1070 ServiceName1 = ServiceName;
1071
1072 if (!PhysicalDeviceObject)
1073 {
1074 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length + sizeof(UNICODE_NULL);
1075 FullServiceName.Length = 0;
1076 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
1077 if (!FullServiceName.Buffer)
1078 {
1079 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1080 return STATUS_INSUFFICIENT_RESOURCES;
1081 }
1082
1083 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
1084 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
1085 RtlUpcaseUnicodeString(&FullServiceName, &FullServiceName, FALSE);
1086
1087 Status = PnpRootCreateDevice(&FullServiceName, NULL, &PhysicalDeviceObject, &Node->InstancePath);
1088 if (!NT_SUCCESS(Status))
1089 {
1090 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
1091 ExFreePool(FullServiceName.Buffer);
1092 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1093 return Status;
1094 }
1095
1096 /* Create the device key for legacy drivers */
1097 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
1098 if (!NT_SUCCESS(Status))
1099 {
1100 ExFreePool(FullServiceName.Buffer);
1101 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1102 return Status;
1103 }
1104
1105 Node->ServiceName.MaximumLength = ServiceName1->Length + sizeof(UNICODE_NULL);
1106 Node->ServiceName.Length = 0;
1107 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, Node->ServiceName.MaximumLength);
1108 if (!Node->ServiceName.Buffer)
1109 {
1110 ZwClose(InstanceHandle);
1111 ExFreePool(FullServiceName.Buffer);
1112 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1113 return Status;
1114 }
1115
1116 RtlCopyUnicodeString(&Node->ServiceName, ServiceName1);
1117
1118 if (ServiceName)
1119 {
1120 RtlInitUnicodeString(&KeyName, L"Service");
1121 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length + sizeof(UNICODE_NULL));
1122 }
1123
1124 if (NT_SUCCESS(Status))
1125 {
1126 RtlInitUnicodeString(&KeyName, L"Legacy");
1127 LegacyValue = 1;
1128 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
1129
1130 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1131 LegacyValue = 0;
1132 ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
1133
1134 if (NT_SUCCESS(Status))
1135 {
1136 RtlInitUnicodeString(&KeyName, L"Class");
1137 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
1138 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length + sizeof(UNICODE_NULL));
1139 if (NT_SUCCESS(Status))
1140 {
1141 RtlInitUnicodeString(&KeyName, L"ClassGUID");
1142 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
1143 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length + sizeof(UNICODE_NULL));
1144 if (NT_SUCCESS(Status))
1145 {
1146 // FIXME: Retrieve the real "description" by looking at the "DisplayName" string
1147 // of the corresponding CurrentControlSet\Services\xxx entry for this driver.
1148 RtlInitUnicodeString(&KeyName, L"DeviceDesc");
1149 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName1->Buffer, ServiceName1->Length + sizeof(UNICODE_NULL));
1150 }
1151 }
1152 }
1153 }
1154
1155 ZwClose(InstanceHandle);
1156 ExFreePool(FullServiceName.Buffer);
1157
1158 if (!NT_SUCCESS(Status))
1159 {
1160 ExFreePool(Node->ServiceName.Buffer);
1161 ExFreePoolWithTag(Node, TAG_IO_DEVNODE);
1162 return Status;
1163 }
1164
1165 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
1166 IopDeviceNodeSetFlag(Node, DNF_PROCESSED);
1167 IopDeviceNodeSetFlag(Node, DNF_ADDED);
1168 IopDeviceNodeSetFlag(Node, DNF_STARTED);
1169 }
1170
1171 Node->PhysicalDeviceObject = PhysicalDeviceObject;
1172
1173 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
1174
1175 if (ParentNode)
1176 {
1177 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1178 Node->Parent = ParentNode;
1179 Node->Sibling = NULL;
1180 if (ParentNode->LastChild == NULL)
1181 {
1182 ParentNode->Child = Node;
1183 ParentNode->LastChild = Node;
1184 }
1185 else
1186 {
1187 ParentNode->LastChild->Sibling = Node;
1188 ParentNode->LastChild = Node;
1189 }
1190 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1191 Node->Level = ParentNode->Level + 1;
1192 }
1193
1194 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1195
1196 *DeviceNode = Node;
1197
1198 return STATUS_SUCCESS;
1199 }
1200
1201 NTSTATUS
1202 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
1203 {
1204 KIRQL OldIrql;
1205 PDEVICE_NODE PrevSibling = NULL;
1206
1207 /* All children must be deleted before a parent is deleted */
1208 ASSERT(!DeviceNode->Child);
1209 ASSERT(DeviceNode->PhysicalDeviceObject);
1210
1211 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1212
1213 /* Get previous sibling */
1214 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
1215 {
1216 PrevSibling = DeviceNode->Parent->Child;
1217 while (PrevSibling->Sibling != DeviceNode)
1218 PrevSibling = PrevSibling->Sibling;
1219 }
1220
1221 /* Unlink from parent if it exists */
1222 if (DeviceNode->Parent)
1223 {
1224 if (DeviceNode->Parent->LastChild == DeviceNode)
1225 {
1226 DeviceNode->Parent->LastChild = PrevSibling;
1227 if (PrevSibling)
1228 PrevSibling->Sibling = NULL;
1229 }
1230 if (DeviceNode->Parent->Child == DeviceNode)
1231 DeviceNode->Parent->Child = DeviceNode->Sibling;
1232 }
1233
1234 /* Unlink from sibling list */
1235 if (PrevSibling)
1236 PrevSibling->Sibling = DeviceNode->Sibling;
1237
1238 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1239
1240 RtlFreeUnicodeString(&DeviceNode->InstancePath);
1241
1242 RtlFreeUnicodeString(&DeviceNode->ServiceName);
1243
1244 if (DeviceNode->ResourceList)
1245 {
1246 ExFreePool(DeviceNode->ResourceList);
1247 }
1248
1249 if (DeviceNode->ResourceListTranslated)
1250 {
1251 ExFreePool(DeviceNode->ResourceListTranslated);
1252 }
1253
1254 if (DeviceNode->ResourceRequirements)
1255 {
1256 ExFreePool(DeviceNode->ResourceRequirements);
1257 }
1258
1259 if (DeviceNode->BootResources)
1260 {
1261 ExFreePool(DeviceNode->BootResources);
1262 }
1263
1264 ((PEXTENDED_DEVOBJ_EXTENSION)DeviceNode->PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = NULL;
1265 ExFreePoolWithTag(DeviceNode, TAG_IO_DEVNODE);
1266
1267 return STATUS_SUCCESS;
1268 }
1269
1270 NTSTATUS
1271 NTAPI
1272 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
1273 IN PIO_STACK_LOCATION IoStackLocation,
1274 OUT PVOID *Information)
1275 {
1276 PIRP Irp;
1277 PIO_STACK_LOCATION IrpStack;
1278 IO_STATUS_BLOCK IoStatusBlock;
1279 KEVENT Event;
1280 NTSTATUS Status;
1281 PDEVICE_OBJECT TopDeviceObject;
1282 PAGED_CODE();
1283
1284 /* Call the top of the device stack */
1285 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
1286
1287 /* Allocate an IRP */
1288 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
1289 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1290
1291 /* Initialize to failure */
1292 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
1293 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
1294
1295 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1296 if (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
1297 {
1298 /* Copy the resource requirements list into the IOSB */
1299 Irp->IoStatus.Information =
1300 IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
1301 }
1302
1303 /* Initialize the event */
1304 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1305
1306 /* Set them up */
1307 Irp->UserIosb = &IoStatusBlock;
1308 Irp->UserEvent = &Event;
1309
1310 /* Queue the IRP */
1311 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1312 IoQueueThreadIrp(Irp);
1313
1314 /* Copy-in the stack */
1315 IrpStack = IoGetNextIrpStackLocation(Irp);
1316 *IrpStack = *IoStackLocation;
1317
1318 /* Call the driver */
1319 Status = IoCallDriver(TopDeviceObject, Irp);
1320 if (Status == STATUS_PENDING)
1321 {
1322 /* Wait for it */
1323 KeWaitForSingleObject(&Event,
1324 Executive,
1325 KernelMode,
1326 FALSE,
1327 NULL);
1328 Status = IoStatusBlock.Status;
1329 }
1330
1331 /* Remove the reference */
1332 ObDereferenceObject(TopDeviceObject);
1333
1334 /* Return the information */
1335 *Information = (PVOID)IoStatusBlock.Information;
1336 return Status;
1337 }
1338
1339 NTSTATUS
1340 NTAPI
1341 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
1342 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
1343 IN UCHAR MinorFunction,
1344 IN PIO_STACK_LOCATION Stack OPTIONAL)
1345 {
1346 IO_STACK_LOCATION IoStackLocation;
1347
1348 /* Fill out the stack information */
1349 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
1350 IoStackLocation.MajorFunction = IRP_MJ_PNP;
1351 IoStackLocation.MinorFunction = MinorFunction;
1352 if (Stack)
1353 {
1354 /* Copy the rest */
1355 RtlCopyMemory(&IoStackLocation.Parameters,
1356 &Stack->Parameters,
1357 sizeof(Stack->Parameters));
1358 }
1359
1360 /* Do the PnP call */
1361 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
1362 &IoStackLocation,
1363 (PVOID)&IoStatusBlock->Information);
1364 return IoStatusBlock->Status;
1365 }
1366
1367 NTSTATUS
1368 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
1369 {
1370 PDEVICE_NODE ParentDeviceNode;
1371 PDEVICE_NODE ChildDeviceNode;
1372 NTSTATUS Status;
1373
1374 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1375 ParentDeviceNode = Context->DeviceNode;
1376
1377 /* Call the action routine */
1378 Status = (Context->Action)(ParentDeviceNode, Context->Context);
1379 if (!NT_SUCCESS(Status))
1380 {
1381 return Status;
1382 }
1383
1384 /* Traversal of all children nodes */
1385 for (ChildDeviceNode = ParentDeviceNode->Child;
1386 ChildDeviceNode != NULL;
1387 ChildDeviceNode = ChildDeviceNode->Sibling)
1388 {
1389 /* Pass the current device node to the action routine */
1390 Context->DeviceNode = ChildDeviceNode;
1391
1392 Status = IopTraverseDeviceTreeNode(Context);
1393 if (!NT_SUCCESS(Status))
1394 {
1395 return Status;
1396 }
1397 }
1398
1399 return Status;
1400 }
1401
1402
1403 NTSTATUS
1404 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
1405 {
1406 NTSTATUS Status;
1407
1408 DPRINT("Context 0x%p\n", Context);
1409
1410 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
1411 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
1412
1413 /* Start from the specified device node */
1414 Context->DeviceNode = Context->FirstDeviceNode;
1415
1416 /* Recursively traverse the device tree */
1417 Status = IopTraverseDeviceTreeNode(Context);
1418 if (Status == STATUS_UNSUCCESSFUL)
1419 {
1420 /* The action routine just wanted to terminate the traversal with status
1421 code STATUS_SUCCESS */
1422 Status = STATUS_SUCCESS;
1423 }
1424
1425 return Status;
1426 }
1427
1428
1429 /*
1430 * IopCreateDeviceKeyPath
1431 *
1432 * Creates a registry key
1433 *
1434 * Parameters
1435 * RegistryPath
1436 * Name of the key to be created.
1437 * Handle
1438 * Handle to the newly created key
1439 *
1440 * Remarks
1441 * This method can create nested trees, so parent of RegistryPath can
1442 * be not existant, and will be created if needed.
1443 */
1444 NTSTATUS
1445 NTAPI
1446 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
1447 IN ULONG CreateOptions,
1448 OUT PHANDLE Handle)
1449 {
1450 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
1451 HANDLE hParent = NULL, hKey;
1452 OBJECT_ATTRIBUTES ObjectAttributes;
1453 UNICODE_STRING KeyName;
1454 PCWSTR Current, Last;
1455 USHORT Length;
1456 NTSTATUS Status;
1457
1458 /* Assume failure */
1459 *Handle = NULL;
1460
1461 /* Create a volatile device tree in 1st stage so we have a clean slate
1462 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1463 if (ExpInTextModeSetup) CreateOptions |= REG_OPTION_VOLATILE;
1464
1465 /* Open root key for device instances */
1466 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
1467 if (!NT_SUCCESS(Status))
1468 {
1469 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
1470 return Status;
1471 }
1472
1473 Current = KeyName.Buffer = RegistryPath->Buffer;
1474 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
1475
1476 /* Go up to the end of the string */
1477 while (Current <= Last)
1478 {
1479 if (Current != Last && *Current != L'\\')
1480 {
1481 /* Not the end of the string and not a separator */
1482 Current++;
1483 continue;
1484 }
1485
1486 /* Prepare relative key name */
1487 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
1488 KeyName.MaximumLength = KeyName.Length = Length;
1489 DPRINT("Create '%wZ'\n", &KeyName);
1490
1491 /* Open key */
1492 InitializeObjectAttributes(&ObjectAttributes,
1493 &KeyName,
1494 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1495 hParent,
1496 NULL);
1497 Status = ZwCreateKey(&hKey,
1498 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
1499 &ObjectAttributes,
1500 0,
1501 NULL,
1502 CreateOptions,
1503 NULL);
1504
1505 /* Close parent key handle, we don't need it anymore */
1506 if (hParent)
1507 ZwClose(hParent);
1508
1509 /* Key opening/creating failed? */
1510 if (!NT_SUCCESS(Status))
1511 {
1512 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
1513 return Status;
1514 }
1515
1516 /* Check if it is the end of the string */
1517 if (Current == Last)
1518 {
1519 /* Yes, return success */
1520 *Handle = hKey;
1521 return STATUS_SUCCESS;
1522 }
1523
1524 /* Start with this new parent key */
1525 hParent = hKey;
1526 Current++;
1527 KeyName.Buffer = (PWSTR)Current;
1528 }
1529
1530 return STATUS_UNSUCCESSFUL;
1531 }
1532
1533 NTSTATUS
1534 IopSetDeviceInstanceData(HANDLE InstanceKey,
1535 PDEVICE_NODE DeviceNode)
1536 {
1537 OBJECT_ATTRIBUTES ObjectAttributes;
1538 UNICODE_STRING KeyName;
1539 HANDLE LogConfKey, ControlKey, DeviceParamsKey;
1540 ULONG ResCount;
1541 ULONG ResultLength;
1542 NTSTATUS Status;
1543
1544 DPRINT("IopSetDeviceInstanceData() called\n");
1545
1546 /* Create the 'LogConf' key */
1547 RtlInitUnicodeString(&KeyName, L"LogConf");
1548 InitializeObjectAttributes(&ObjectAttributes,
1549 &KeyName,
1550 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1551 InstanceKey,
1552 NULL);
1553 Status = ZwCreateKey(&LogConfKey,
1554 KEY_ALL_ACCESS,
1555 &ObjectAttributes,
1556 0,
1557 NULL,
1558 REG_OPTION_VOLATILE,
1559 NULL);
1560 if (NT_SUCCESS(Status))
1561 {
1562 /* Set 'BootConfig' value */
1563 if (DeviceNode->BootResources != NULL)
1564 {
1565 ResCount = DeviceNode->BootResources->Count;
1566 if (ResCount != 0)
1567 {
1568 RtlInitUnicodeString(&KeyName, L"BootConfig");
1569 Status = ZwSetValueKey(LogConfKey,
1570 &KeyName,
1571 0,
1572 REG_RESOURCE_LIST,
1573 DeviceNode->BootResources,
1574 PnpDetermineResourceListSize(DeviceNode->BootResources));
1575 }
1576 }
1577
1578 /* Set 'BasicConfigVector' value */
1579 if (DeviceNode->ResourceRequirements != NULL &&
1580 DeviceNode->ResourceRequirements->ListSize != 0)
1581 {
1582 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1583 Status = ZwSetValueKey(LogConfKey,
1584 &KeyName,
1585 0,
1586 REG_RESOURCE_REQUIREMENTS_LIST,
1587 DeviceNode->ResourceRequirements,
1588 DeviceNode->ResourceRequirements->ListSize);
1589 }
1590
1591 ZwClose(LogConfKey);
1592 }
1593
1594 /* Set the 'ConfigFlags' value */
1595 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1596 Status = ZwQueryValueKey(InstanceKey,
1597 &KeyName,
1598 KeyValueBasicInformation,
1599 NULL,
1600 0,
1601 &ResultLength);
1602 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1603 {
1604 /* Write the default value */
1605 ULONG DefaultConfigFlags = 0;
1606 Status = ZwSetValueKey(InstanceKey,
1607 &KeyName,
1608 0,
1609 REG_DWORD,
1610 &DefaultConfigFlags,
1611 sizeof(DefaultConfigFlags));
1612 }
1613
1614 /* Create the 'Control' key */
1615 RtlInitUnicodeString(&KeyName, L"Control");
1616 InitializeObjectAttributes(&ObjectAttributes,
1617 &KeyName,
1618 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1619 InstanceKey,
1620 NULL);
1621 Status = ZwCreateKey(&ControlKey,
1622 0,
1623 &ObjectAttributes,
1624 0,
1625 NULL,
1626 REG_OPTION_VOLATILE,
1627 NULL);
1628 if (NT_SUCCESS(Status))
1629 ZwClose(ControlKey);
1630
1631 /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
1632 if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
1633 {
1634 RtlInitUnicodeString(&KeyName, L"Device Parameters");
1635 InitializeObjectAttributes(&ObjectAttributes,
1636 &KeyName,
1637 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1638 InstanceKey,
1639 NULL);
1640 Status = ZwCreateKey(&DeviceParamsKey,
1641 0,
1642 &ObjectAttributes,
1643 0,
1644 NULL,
1645 REG_OPTION_NON_VOLATILE,
1646 NULL);
1647 if (NT_SUCCESS(Status))
1648 {
1649 ULONG FirmwareIdentified = 1;
1650 RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
1651 Status = ZwSetValueKey(DeviceParamsKey,
1652 &KeyName,
1653 0,
1654 REG_DWORD,
1655 &FirmwareIdentified,
1656 sizeof(FirmwareIdentified));
1657
1658 ZwClose(DeviceParamsKey);
1659 }
1660 }
1661
1662 DPRINT("IopSetDeviceInstanceData() done\n");
1663
1664 return Status;
1665 }
1666
1667 /*
1668 * IopGetParentIdPrefix
1669 *
1670 * Retrieve (or create) a string which identifies a device.
1671 *
1672 * Parameters
1673 * DeviceNode
1674 * Pointer to device node.
1675 * ParentIdPrefix
1676 * Pointer to the string where is returned the parent node identifier
1677 *
1678 * Remarks
1679 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1680 * valid and its Buffer field is NULL-terminated. The caller needs to
1681 * to free the string with RtlFreeUnicodeString when it is no longer
1682 * needed.
1683 */
1684
1685 NTSTATUS
1686 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1687 PUNICODE_STRING ParentIdPrefix)
1688 {
1689 const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1690 ULONG KeyNameBufferLength;
1691 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1692 UNICODE_STRING KeyName = {0, 0, NULL};
1693 UNICODE_STRING KeyValue;
1694 UNICODE_STRING ValueName;
1695 HANDLE hKey = NULL;
1696 ULONG crc32;
1697 NTSTATUS Status;
1698
1699 /* HACK: As long as some devices have a NULL device
1700 * instance path, the following test is required :(
1701 */
1702 if (DeviceNode->Parent->InstancePath.Length == 0)
1703 {
1704 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1705 &DeviceNode->InstancePath);
1706 return STATUS_UNSUCCESSFUL;
1707 }
1708
1709 /* 1. Try to retrieve ParentIdPrefix from registry */
1710 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1711 ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
1712 KeyNameBufferLength + sizeof(UNICODE_NULL),
1713 TAG_IO);
1714 if (!ParentIdPrefixInformation)
1715 {
1716 return STATUS_INSUFFICIENT_RESOURCES;
1717 }
1718
1719 KeyName.Length = 0;
1720 KeyName.MaximumLength = EnumKeyPath.Length +
1721 DeviceNode->Parent->InstancePath.Length +
1722 sizeof(UNICODE_NULL);
1723 KeyName.Buffer = ExAllocatePoolWithTag(PagedPool,
1724 KeyName.MaximumLength,
1725 TAG_IO);
1726 if (!KeyName.Buffer)
1727 {
1728 Status = STATUS_INSUFFICIENT_RESOURCES;
1729 goto cleanup;
1730 }
1731
1732 RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
1733 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1734
1735 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
1736 if (!NT_SUCCESS(Status))
1737 {
1738 goto cleanup;
1739 }
1740 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1741 Status = ZwQueryValueKey(hKey,
1742 &ValueName,
1743 KeyValuePartialInformation,
1744 ParentIdPrefixInformation,
1745 KeyNameBufferLength,
1746 &KeyNameBufferLength);
1747 if (NT_SUCCESS(Status))
1748 {
1749 if (ParentIdPrefixInformation->Type != REG_SZ)
1750 {
1751 Status = STATUS_UNSUCCESSFUL;
1752 }
1753 else
1754 {
1755 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1756 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1757 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1758 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1759 }
1760 goto cleanup;
1761 }
1762 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1763 {
1764 /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
1765 KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1766 KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1767 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1768 ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1769 goto cleanup;
1770 }
1771
1772 /* 2. Create the ParentIdPrefix value */
1773 crc32 = RtlComputeCrc32(0,
1774 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1775 DeviceNode->Parent->InstancePath.Length);
1776
1777 RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
1778 KeyNameBufferLength,
1779 L"%lx&%lx",
1780 DeviceNode->Parent->Level,
1781 crc32);
1782 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
1783
1784 /* 3. Try to write the ParentIdPrefix to registry */
1785 Status = ZwSetValueKey(hKey,
1786 &ValueName,
1787 0,
1788 REG_SZ,
1789 KeyValue.Buffer,
1790 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1791
1792 cleanup:
1793 if (NT_SUCCESS(Status))
1794 {
1795 /* Duplicate the string to return it */
1796 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1797 &KeyValue,
1798 ParentIdPrefix);
1799 }
1800 ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
1801 RtlFreeUnicodeString(&KeyName);
1802 if (hKey != NULL)
1803 {
1804 ZwClose(hKey);
1805 }
1806 return Status;
1807 }
1808
1809 static
1810 BOOLEAN
1811 IopValidateID(
1812 _In_ PWCHAR Id,
1813 _In_ BUS_QUERY_ID_TYPE QueryType)
1814 {
1815 PWCHAR PtrChar;
1816 PWCHAR StringEnd;
1817 WCHAR Char;
1818 ULONG SeparatorsCount = 0;
1819 PWCHAR PtrPrevChar = NULL;
1820 ULONG MaxSeparators;
1821 BOOLEAN IsMultiSz;
1822
1823 PAGED_CODE();
1824
1825 switch (QueryType)
1826 {
1827 case BusQueryDeviceID:
1828 MaxSeparators = MAX_SEPARATORS_DEVICEID;
1829 IsMultiSz = FALSE;
1830 break;
1831 case BusQueryInstanceID:
1832 MaxSeparators = MAX_SEPARATORS_INSTANCEID;
1833 IsMultiSz = FALSE;
1834 break;
1835
1836 case BusQueryHardwareIDs:
1837 case BusQueryCompatibleIDs:
1838 MaxSeparators = MAX_SEPARATORS_DEVICEID;
1839 IsMultiSz = TRUE;
1840 break;
1841
1842 default:
1843 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
1844 return FALSE;
1845 }
1846
1847 StringEnd = Id + MAX_DEVICE_ID_LEN;
1848
1849 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
1850 {
1851 Char = *PtrChar;
1852
1853 if (Char == UNICODE_NULL)
1854 {
1855 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
1856 {
1857 if (MaxSeparators == SeparatorsCount || IsMultiSz)
1858 {
1859 return TRUE;
1860 }
1861
1862 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1863 SeparatorsCount, MaxSeparators);
1864 goto ErrorExit;
1865 }
1866
1867 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
1868 PtrPrevChar = PtrChar;
1869 SeparatorsCount = 0;
1870 }
1871 else if (Char < ' ' || Char > 0x7F || Char == ',')
1872 {
1873 DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
1874 goto ErrorExit;
1875 }
1876 else if (Char == ' ')
1877 {
1878 *PtrChar = '_';
1879 }
1880 else if (Char == '\\')
1881 {
1882 SeparatorsCount++;
1883
1884 if (SeparatorsCount > MaxSeparators)
1885 {
1886 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1887 SeparatorsCount, MaxSeparators);
1888 goto ErrorExit;
1889 }
1890 }
1891 }
1892
1893 DPRINT1("IopValidateID: Not terminated ID\n");
1894
1895 ErrorExit:
1896 // FIXME logging
1897 return FALSE;
1898 }
1899
1900 NTSTATUS
1901 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
1902 HANDLE InstanceKey)
1903 {
1904 IO_STACK_LOCATION Stack;
1905 IO_STATUS_BLOCK IoStatusBlock;
1906 PWSTR Ptr;
1907 UNICODE_STRING ValueName;
1908 NTSTATUS Status;
1909 ULONG Length, TotalLength;
1910 BOOLEAN IsValidID;
1911
1912 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1913
1914 RtlZeroMemory(&Stack, sizeof(Stack));
1915 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1916 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1917 &IoStatusBlock,
1918 IRP_MN_QUERY_ID,
1919 &Stack);
1920 if (NT_SUCCESS(Status))
1921 {
1922 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs);
1923
1924 if (!IsValidID)
1925 {
1926 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
1927 }
1928
1929 TotalLength = 0;
1930
1931 Ptr = (PWSTR)IoStatusBlock.Information;
1932 DPRINT("Hardware IDs:\n");
1933 while (*Ptr)
1934 {
1935 DPRINT(" %S\n", Ptr);
1936 Length = (ULONG)wcslen(Ptr) + 1;
1937
1938 Ptr += Length;
1939 TotalLength += Length;
1940 }
1941 DPRINT("TotalLength: %hu\n", TotalLength);
1942 DPRINT("\n");
1943
1944 RtlInitUnicodeString(&ValueName, L"HardwareID");
1945 Status = ZwSetValueKey(InstanceKey,
1946 &ValueName,
1947 0,
1948 REG_MULTI_SZ,
1949 (PVOID)IoStatusBlock.Information,
1950 (TotalLength + 1) * sizeof(WCHAR));
1951 if (!NT_SUCCESS(Status))
1952 {
1953 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1954 }
1955 }
1956 else
1957 {
1958 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1959 }
1960
1961 return Status;
1962 }
1963
1964 NTSTATUS
1965 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
1966 HANDLE InstanceKey)
1967 {
1968 IO_STACK_LOCATION Stack;
1969 IO_STATUS_BLOCK IoStatusBlock;
1970 PWSTR Ptr;
1971 UNICODE_STRING ValueName;
1972 NTSTATUS Status;
1973 ULONG Length, TotalLength;
1974 BOOLEAN IsValidID;
1975
1976 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1977
1978 RtlZeroMemory(&Stack, sizeof(Stack));
1979 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1980 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1981 &IoStatusBlock,
1982 IRP_MN_QUERY_ID,
1983 &Stack);
1984 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1985 {
1986 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs);
1987
1988 if (!IsValidID)
1989 {
1990 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
1991 }
1992
1993 TotalLength = 0;
1994
1995 Ptr = (PWSTR)IoStatusBlock.Information;
1996 DPRINT("Compatible IDs:\n");
1997 while (*Ptr)
1998 {
1999 DPRINT(" %S\n", Ptr);
2000 Length = (ULONG)wcslen(Ptr) + 1;
2001
2002 Ptr += Length;
2003 TotalLength += Length;
2004 }
2005 DPRINT("TotalLength: %hu\n", TotalLength);
2006 DPRINT("\n");
2007
2008 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
2009 Status = ZwSetValueKey(InstanceKey,
2010 &ValueName,
2011 0,
2012 REG_MULTI_SZ,
2013 (PVOID)IoStatusBlock.Information,
2014 (TotalLength + 1) * sizeof(WCHAR));
2015 if (!NT_SUCCESS(Status))
2016 {
2017 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
2018 }
2019 }
2020 else
2021 {
2022 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2023 }
2024
2025 return Status;
2026 }
2027
2028 NTSTATUS
2029 IopCreateDeviceInstancePath(
2030 _In_ PDEVICE_NODE DeviceNode,
2031 _Out_ PUNICODE_STRING InstancePath)
2032 {
2033 IO_STATUS_BLOCK IoStatusBlock;
2034 UNICODE_STRING DeviceId;
2035 UNICODE_STRING InstanceId;
2036 IO_STACK_LOCATION Stack;
2037 NTSTATUS Status;
2038 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
2039 DEVICE_CAPABILITIES DeviceCapabilities;
2040 BOOLEAN IsValidID;
2041
2042 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2043
2044 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
2045 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2046 &IoStatusBlock,
2047 IRP_MN_QUERY_ID,
2048 &Stack);
2049 if (!NT_SUCCESS(Status))
2050 {
2051 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
2052 return Status;
2053 }
2054
2055 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID);
2056
2057 if (!IsValidID)
2058 {
2059 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
2060 }
2061
2062 /* Save the device id string */
2063 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information);
2064
2065 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
2066
2067 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
2068 if (!NT_SUCCESS(Status))
2069 {
2070 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
2071 RtlFreeUnicodeString(&DeviceId);
2072 return Status;
2073 }
2074
2075 /* This bit is only check after enumeration */
2076 if (DeviceCapabilities.HardwareDisabled)
2077 {
2078 /* FIXME: Cleanup device */
2079 DeviceNode->Flags |= DNF_DISABLED;
2080 RtlFreeUnicodeString(&DeviceId);
2081 return STATUS_PLUGPLAY_NO_DEVICE;
2082 }
2083 else
2084 {
2085 DeviceNode->Flags &= ~DNF_DISABLED;
2086 }
2087
2088 if (!DeviceCapabilities.UniqueID)
2089 {
2090 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2091 DPRINT("Instance ID is not unique\n");
2092 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
2093 if (!NT_SUCCESS(Status))
2094 {
2095 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
2096 RtlFreeUnicodeString(&DeviceId);
2097 return Status;
2098 }
2099 }
2100
2101 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2102
2103 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
2104 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2105 &IoStatusBlock,
2106 IRP_MN_QUERY_ID,
2107 &Stack);
2108 if (!NT_SUCCESS(Status))
2109 {
2110 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
2111 ASSERT(IoStatusBlock.Information == 0);
2112 }
2113
2114 if (IoStatusBlock.Information)
2115 {
2116 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID);
2117
2118 if (!IsValidID)
2119 {
2120 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
2121 }
2122 }
2123
2124 RtlInitUnicodeString(&InstanceId,
2125 (PWSTR)IoStatusBlock.Information);
2126
2127 InstancePath->Length = 0;
2128 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
2129 ParentIdPrefix.Length +
2130 InstanceId.Length +
2131 sizeof(UNICODE_NULL);
2132 if (ParentIdPrefix.Length && InstanceId.Length)
2133 {
2134 InstancePath->MaximumLength += sizeof(WCHAR);
2135 }
2136
2137 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
2138 InstancePath->MaximumLength,
2139 TAG_IO);
2140 if (!InstancePath->Buffer)
2141 {
2142 RtlFreeUnicodeString(&InstanceId);
2143 RtlFreeUnicodeString(&ParentIdPrefix);
2144 RtlFreeUnicodeString(&DeviceId);
2145 return STATUS_INSUFFICIENT_RESOURCES;
2146 }
2147
2148 /* Start with the device id */
2149 RtlCopyUnicodeString(InstancePath, &DeviceId);
2150 RtlAppendUnicodeToString(InstancePath, L"\\");
2151
2152 /* Add information from parent bus device to InstancePath */
2153 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
2154 if (ParentIdPrefix.Length && InstanceId.Length)
2155 {
2156 RtlAppendUnicodeToString(InstancePath, L"&");
2157 }
2158
2159 /* Finally, add the id returned by the driver stack */
2160 RtlAppendUnicodeStringToString(InstancePath, &InstanceId);
2161
2162 /*
2163 * FIXME: Check for valid characters, if there is invalid characters
2164 * then bugcheck
2165 */
2166
2167 RtlFreeUnicodeString(&InstanceId);
2168 RtlFreeUnicodeString(&DeviceId);
2169 RtlFreeUnicodeString(&ParentIdPrefix);
2170
2171 return STATUS_SUCCESS;
2172 }
2173
2174 /*
2175 * IopActionInterrogateDeviceStack
2176 *
2177 * Retrieve information for all (direct) child nodes of a parent node.
2178 *
2179 * Parameters
2180 * DeviceNode
2181 * Pointer to device node.
2182 * Context
2183 * Pointer to parent node to retrieve child node information for.
2184 *
2185 * Remarks
2186 * Any errors that occur are logged instead so that all child services have a chance
2187 * of being interrogated.
2188 */
2189
2190 NTSTATUS
2191 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
2192 PVOID Context)
2193 {
2194 IO_STATUS_BLOCK IoStatusBlock;
2195 PWSTR DeviceDescription;
2196 PWSTR LocationInformation;
2197 PDEVICE_NODE ParentDeviceNode;
2198 IO_STACK_LOCATION Stack;
2199 NTSTATUS Status;
2200 ULONG RequiredLength;
2201 LCID LocaleId;
2202 HANDLE InstanceKey = NULL;
2203 UNICODE_STRING ValueName;
2204 UNICODE_STRING InstancePathU;
2205 PDEVICE_OBJECT OldDeviceObject;
2206
2207 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2208 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2209
2210 ParentDeviceNode = (PDEVICE_NODE)Context;
2211
2212 /*
2213 * We are called for the parent too, but we don't need to do special
2214 * handling for this node
2215 */
2216 if (DeviceNode == ParentDeviceNode)
2217 {
2218 DPRINT("Success\n");
2219 return STATUS_SUCCESS;
2220 }
2221
2222 /*
2223 * Make sure this device node is a direct child of the parent device node
2224 * that is given as an argument
2225 */
2226 if (DeviceNode->Parent != ParentDeviceNode)
2227 {
2228 DPRINT("Skipping 2+ level child\n");
2229 return STATUS_SUCCESS;
2230 }
2231
2232 /* Skip processing if it was already completed before */
2233 if (DeviceNode->Flags & DNF_PROCESSED)
2234 {
2235 /* Nothing to do */
2236 return STATUS_SUCCESS;
2237 }
2238
2239 /* Get Locale ID */
2240 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2241 if (!NT_SUCCESS(Status))
2242 {
2243 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2244 return Status;
2245 }
2246
2247 /*
2248 * FIXME: For critical errors, cleanup and disable device, but always
2249 * return STATUS_SUCCESS.
2250 */
2251
2252 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
2253 if (!NT_SUCCESS(Status))
2254 {
2255 if (Status != STATUS_PLUGPLAY_NO_DEVICE)
2256 {
2257 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
2258 }
2259
2260 /* We have to return success otherwise we abort the traverse operation */
2261 return STATUS_SUCCESS;
2262 }
2263
2264 /* Verify that this is not a duplicate */
2265 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
2266 if (OldDeviceObject != NULL)
2267 {
2268 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
2269
2270 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
2271 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
2272 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
2273
2274 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
2275 0x01,
2276 (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
2277 (ULONG_PTR)OldDeviceObject,
2278 0);
2279 }
2280
2281 DeviceNode->InstancePath = InstancePathU;
2282
2283 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2284
2285 /*
2286 * Create registry key for the instance id, if it doesn't exist yet
2287 */
2288 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
2289 if (!NT_SUCCESS(Status))
2290 {
2291 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2292
2293 /* We have to return success otherwise we abort the traverse operation */
2294 return STATUS_SUCCESS;
2295 }
2296
2297 IopQueryHardwareIds(DeviceNode, InstanceKey);
2298
2299 IopQueryCompatibleIds(DeviceNode, InstanceKey);
2300
2301 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2302
2303 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2304 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2305 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2306 &IoStatusBlock,
2307 IRP_MN_QUERY_DEVICE_TEXT,
2308 &Stack);
2309 DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information
2310 : NULL;
2311 /* This key is mandatory, so even if the Irp fails, we still write it */
2312 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2313 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2314 {
2315 if (DeviceDescription &&
2316 *DeviceDescription != UNICODE_NULL)
2317 {
2318 /* This key is overriden when a driver is installed. Don't write the
2319 * new description if another one already exists */
2320 Status = ZwSetValueKey(InstanceKey,
2321 &ValueName,
2322 0,
2323 REG_SZ,
2324 DeviceDescription,
2325 ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR));
2326 }
2327 else
2328 {
2329 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2330 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2331
2332 Status = ZwSetValueKey(InstanceKey,
2333 &ValueName,
2334 0,
2335 REG_SZ,
2336 DeviceDesc.Buffer,
2337 DeviceDesc.MaximumLength);
2338 if (!NT_SUCCESS(Status))
2339 {
2340 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2341 }
2342
2343 }
2344 }
2345
2346 if (DeviceDescription)
2347 {
2348 ExFreePoolWithTag(DeviceDescription, 0);
2349 }
2350
2351 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2352
2353 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2354 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2355 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2356 &IoStatusBlock,
2357 IRP_MN_QUERY_DEVICE_TEXT,
2358 &Stack);
2359 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2360 {
2361 LocationInformation = (PWSTR)IoStatusBlock.Information;
2362 DPRINT("LocationInformation: %S\n", LocationInformation);
2363 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2364 Status = ZwSetValueKey(InstanceKey,
2365 &ValueName,
2366 0,
2367 REG_SZ,
2368 LocationInformation,
2369 ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR));
2370 if (!NT_SUCCESS(Status))
2371 {
2372 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2373 }
2374
2375 ExFreePoolWithTag(LocationInformation, 0);
2376 }
2377 else
2378 {
2379 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2380 }
2381
2382 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2383
2384 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2385 &IoStatusBlock,
2386 IRP_MN_QUERY_BUS_INFORMATION,
2387 NULL);
2388 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2389 {
2390 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2391
2392 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2393 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2394 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2395 ExFreePoolWithTag(BusInformation, 0);
2396 }
2397 else
2398 {
2399 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2400
2401 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2402 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2403 DeviceNode->ChildBusTypeIndex = -1;
2404 }
2405
2406 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2407
2408 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2409 &IoStatusBlock,
2410 IRP_MN_QUERY_RESOURCES,
2411 NULL);
2412 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2413 {
2414 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2415 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2416 }
2417 else
2418 {
2419 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2420 DeviceNode->BootResources = NULL;
2421 }
2422
2423 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2424
2425 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2426 &IoStatusBlock,
2427 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2428 NULL);
2429 if (NT_SUCCESS(Status))
2430 {
2431 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2432 }
2433 else
2434 {
2435 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2436 DeviceNode->ResourceRequirements = NULL;
2437 }
2438
2439 if (InstanceKey != NULL)
2440 {
2441 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2442 }
2443
2444 ZwClose(InstanceKey);
2445
2446 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2447
2448 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2449 {
2450 /* Report the device to the user-mode pnp manager */
2451 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2452 &DeviceNode->InstancePath);
2453 }
2454
2455 return STATUS_SUCCESS;
2456 }
2457
2458 static
2459 VOID
2460 IopHandleDeviceRemoval(
2461 IN PDEVICE_NODE DeviceNode,
2462 IN PDEVICE_RELATIONS DeviceRelations)
2463 {
2464 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2465 ULONG i;
2466 BOOLEAN Found;
2467
2468 if (DeviceNode == IopRootDeviceNode)
2469 return;
2470
2471 while (Child != NULL)
2472 {
2473 NextChild = Child->Sibling;
2474 Found = FALSE;
2475
2476 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
2477 {
2478 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
2479 {
2480 Found = TRUE;
2481 break;
2482 }
2483 }
2484
2485 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
2486 {
2487 /* Send removal IRPs to all of its children */
2488 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
2489
2490 /* Send the surprise removal IRP */
2491 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
2492
2493 /* Tell the user-mode PnP manager that a device was removed */
2494 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
2495 &Child->InstancePath);
2496
2497 /* Send the remove device IRP */
2498 IopSendRemoveDevice(Child->PhysicalDeviceObject);
2499 }
2500
2501 Child = NextChild;
2502 }
2503 }
2504
2505 NTSTATUS
2506 IopEnumerateDevice(
2507 IN PDEVICE_OBJECT DeviceObject)
2508 {
2509 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2510 DEVICETREE_TRAVERSE_CONTEXT Context;
2511 PDEVICE_RELATIONS DeviceRelations;
2512 PDEVICE_OBJECT ChildDeviceObject;
2513 IO_STATUS_BLOCK IoStatusBlock;
2514 PDEVICE_NODE ChildDeviceNode;
2515 IO_STACK_LOCATION Stack;
2516 NTSTATUS Status;
2517 ULONG i;
2518
2519 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2520
2521 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
2522 {
2523 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
2524
2525 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2526 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2527 &DeviceNode->InstancePath);
2528 }
2529
2530 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2531
2532 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2533
2534 Status = IopInitiatePnpIrp(
2535 DeviceObject,
2536 &IoStatusBlock,
2537 IRP_MN_QUERY_DEVICE_RELATIONS,
2538 &Stack);
2539 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2540 {
2541 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2542 return Status;
2543 }
2544
2545 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2546
2547 /*
2548 * Send removal IRPs for devices that have disappeared
2549 * NOTE: This code handles the case where no relations are specified
2550 */
2551 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2552
2553 /* Now we bail if nothing was returned */
2554 if (!DeviceRelations)
2555 {
2556 /* We're all done */
2557 DPRINT("No PDOs\n");
2558 return STATUS_SUCCESS;
2559 }
2560
2561 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2562
2563 /*
2564 * Create device nodes for all discovered devices
2565 */
2566 for (i = 0; i < DeviceRelations->Count; i++)
2567 {
2568 ChildDeviceObject = DeviceRelations->Objects[i];
2569 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2570
2571 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2572 if (!ChildDeviceNode)
2573 {
2574 /* One doesn't exist, create it */
2575 Status = IopCreateDeviceNode(
2576 DeviceNode,
2577 ChildDeviceObject,
2578 NULL,
2579 &ChildDeviceNode);
2580 if (NT_SUCCESS(Status))
2581 {
2582 /* Mark the node as enumerated */
2583 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2584
2585 /* Mark the DO as bus enumerated */
2586 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2587 }
2588 else
2589 {
2590 /* Ignore this DO */
2591 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2592 ObDereferenceObject(ChildDeviceObject);
2593 }
2594 }
2595 else
2596 {
2597 /* Mark it as enumerated */
2598 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2599 ObDereferenceObject(ChildDeviceObject);
2600 }
2601 }
2602 ExFreePool(DeviceRelations);
2603
2604 /*
2605 * Retrieve information about all discovered children from the bus driver
2606 */
2607 IopInitDeviceTreeTraverseContext(
2608 &Context,
2609 DeviceNode,
2610 IopActionInterrogateDeviceStack,
2611 DeviceNode);
2612
2613 Status = IopTraverseDeviceTree(&Context);
2614 if (!NT_SUCCESS(Status))
2615 {
2616 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2617 return Status;
2618 }
2619
2620 /*
2621 * Retrieve configuration from the registry for discovered children
2622 */
2623 IopInitDeviceTreeTraverseContext(
2624 &Context,
2625 DeviceNode,
2626 IopActionConfigureChildServices,
2627 DeviceNode);
2628
2629 Status = IopTraverseDeviceTree(&Context);
2630 if (!NT_SUCCESS(Status))
2631 {
2632 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2633 return Status;
2634 }
2635
2636 /*
2637 * Initialize services for discovered children.
2638 */
2639 Status = IopInitializePnpServices(DeviceNode);
2640 if (!NT_SUCCESS(Status))
2641 {
2642 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2643 return Status;
2644 }
2645
2646 DPRINT("IopEnumerateDevice() finished\n");
2647 return STATUS_SUCCESS;
2648 }
2649
2650
2651 /*
2652 * IopActionConfigureChildServices
2653 *
2654 * Retrieve configuration for all (direct) child nodes of a parent node.
2655 *
2656 * Parameters
2657 * DeviceNode
2658 * Pointer to device node.
2659 * Context
2660 * Pointer to parent node to retrieve child node configuration for.
2661 *
2662 * Remarks
2663 * Any errors that occur are logged instead so that all child services have a chance of beeing
2664 * configured.
2665 */
2666
2667 NTSTATUS
2668 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2669 PVOID Context)
2670 {
2671 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2672 PDEVICE_NODE ParentDeviceNode;
2673 PUNICODE_STRING Service;
2674 UNICODE_STRING ClassGUID;
2675 NTSTATUS Status;
2676 DEVICE_CAPABILITIES DeviceCaps;
2677
2678 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2679
2680 ParentDeviceNode = (PDEVICE_NODE)Context;
2681
2682 /*
2683 * We are called for the parent too, but we don't need to do special
2684 * handling for this node
2685 */
2686 if (DeviceNode == ParentDeviceNode)
2687 {
2688 DPRINT("Success\n");
2689 return STATUS_SUCCESS;
2690 }
2691
2692 /*
2693 * Make sure this device node is a direct child of the parent device node
2694 * that is given as an argument
2695 */
2696
2697 if (DeviceNode->Parent != ParentDeviceNode)
2698 {
2699 DPRINT("Skipping 2+ level child\n");
2700 return STATUS_SUCCESS;
2701 }
2702
2703 if (!(DeviceNode->Flags & DNF_PROCESSED))
2704 {
2705 DPRINT1("Child not ready to be configured\n");
2706 return STATUS_SUCCESS;
2707 }
2708
2709 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2710 {
2711 WCHAR RegKeyBuffer[MAX_PATH];
2712 UNICODE_STRING RegKey;
2713
2714 /* Install the service for this if it's in the CDDB */
2715 IopInstallCriticalDevice(DeviceNode);
2716
2717 RegKey.Length = 0;
2718 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2719 RegKey.Buffer = RegKeyBuffer;
2720
2721 /*
2722 * Retrieve configuration from Enum key
2723 */
2724
2725 Service = &DeviceNode->ServiceName;
2726
2727 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2728 RtlInitUnicodeString(Service, NULL);
2729 RtlInitUnicodeString(&ClassGUID, NULL);
2730
2731 QueryTable[0].Name = L"Service";
2732 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2733 QueryTable[0].EntryContext = Service;
2734
2735 QueryTable[1].Name = L"ClassGUID";
2736 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2737 QueryTable[1].EntryContext = &ClassGUID;
2738 QueryTable[1].DefaultType = REG_SZ;
2739 QueryTable[1].DefaultData = L"";
2740 QueryTable[1].DefaultLength = 0;
2741
2742 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2743 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2744
2745 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2746 RegKey.Buffer, QueryTable, NULL, NULL);
2747
2748 if (!NT_SUCCESS(Status))
2749 {
2750 /* FIXME: Log the error */
2751 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2752 &DeviceNode->InstancePath, Status);
2753 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2754 return STATUS_SUCCESS;
2755 }
2756
2757 if (Service->Buffer == NULL)
2758 {
2759 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2760 DeviceCaps.RawDeviceOK)
2761 {
2762 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2763 RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0);
2764 }
2765 else if (ClassGUID.Length != 0)
2766 {
2767 /* Device has a ClassGUID value, but no Service value.
2768 * Suppose it is using the NULL driver, so state the
2769 * device is started */
2770 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2771 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2772 }
2773 else
2774 {
2775 DeviceNode->Problem = CM_PROB_FAILED_INSTALL;
2776 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2777 }
2778 return STATUS_SUCCESS;
2779 }
2780
2781 DPRINT("Got Service %S\n", Service->Buffer);
2782 }
2783
2784 return STATUS_SUCCESS;
2785 }
2786
2787 /*
2788 * IopActionInitChildServices
2789 *
2790 * Initialize the service for all (direct) child nodes of a parent node
2791 *
2792 * Parameters
2793 * DeviceNode
2794 * Pointer to device node.
2795 * Context
2796 * Pointer to parent node to initialize child node services for.
2797 *
2798 * Remarks
2799 * If the driver image for a service is not loaded and initialized
2800 * it is done here too. Any errors that occur are logged instead so
2801 * that all child services have a chance of being initialized.
2802 */
2803
2804 NTSTATUS
2805 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2806 PVOID Context)
2807 {
2808 PDEVICE_NODE ParentDeviceNode;
2809 NTSTATUS Status;
2810 BOOLEAN BootDrivers = !PnpSystemInit;
2811
2812 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2813
2814 ParentDeviceNode = Context;
2815
2816 /*
2817 * We are called for the parent too, but we don't need to do special
2818 * handling for this node
2819 */
2820 if (DeviceNode == ParentDeviceNode)
2821 {
2822 DPRINT("Success\n");
2823 return STATUS_SUCCESS;
2824 }
2825
2826 /*
2827 * We don't want to check for a direct child because
2828 * this function is called during boot to reinitialize
2829 * devices with drivers that couldn't load yet due to
2830 * stage 0 limitations (ie can't load from disk yet).
2831 */
2832
2833 if (!(DeviceNode->Flags & DNF_PROCESSED))
2834 {
2835 DPRINT1("Child not ready to be added\n");
2836 return STATUS_SUCCESS;
2837 }
2838
2839 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2840 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2841 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2842 return STATUS_SUCCESS;
2843
2844 if (DeviceNode->ServiceName.Buffer == NULL)
2845 {
2846 /* We don't need to worry about loading the driver because we're
2847 * being driven in raw mode so our parent must be loaded to get here */
2848 Status = IopInitializeDevice(DeviceNode, NULL);
2849 if (NT_SUCCESS(Status))
2850 {
2851 Status = IopStartDevice(DeviceNode);
2852 if (!NT_SUCCESS(Status))
2853 {
2854 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2855 &DeviceNode->InstancePath, Status);
2856 }
2857 }
2858 }
2859 else
2860 {
2861 PLDR_DATA_TABLE_ENTRY ModuleObject;
2862 PDRIVER_OBJECT DriverObject;
2863
2864 KeEnterCriticalRegion();
2865 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
2866 /* Get existing DriverObject pointer (in case the driver has
2867 already been loaded and initialized) */
2868 Status = IopGetDriverObject(
2869 &DriverObject,
2870 &DeviceNode->ServiceName,
2871 FALSE);
2872
2873 if (!NT_SUCCESS(Status))
2874 {
2875 /* Driver is not initialized, try to load it */
2876 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2877
2878 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2879 {
2880 /* Initialize the driver */
2881 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2882 &DeviceNode->ServiceName, FALSE, &DriverObject);
2883 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY;
2884 }
2885 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD)
2886 {
2887 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
2888 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE;
2889 }
2890 else
2891 {
2892 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2893 &DeviceNode->ServiceName, Status);
2894 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
2895 }
2896 }
2897 ExReleaseResourceLite(&IopDriverLoadResource);
2898 KeLeaveCriticalRegion();
2899
2900 /* Driver is loaded and initialized at this point */
2901 if (NT_SUCCESS(Status))
2902 {
2903 /* Initialize the device, including all filters */
2904 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2905
2906 /* Remove the extra reference */
2907 ObDereferenceObject(DriverObject);
2908 }
2909 else
2910 {
2911 /*
2912 * Don't disable when trying to load only boot drivers
2913 */
2914 if (!BootDrivers)
2915 {
2916 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2917 }
2918 }
2919 }
2920
2921 return STATUS_SUCCESS;
2922 }
2923
2924 /*
2925 * IopInitializePnpServices
2926 *
2927 * Initialize services for discovered children
2928 *
2929 * Parameters
2930 * DeviceNode
2931 * Top device node to start initializing services.
2932 *
2933 * Return Value
2934 * Status
2935 */
2936 NTSTATUS
2937 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2938 {
2939 DEVICETREE_TRAVERSE_CONTEXT Context;
2940
2941 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2942
2943 IopInitDeviceTreeTraverseContext(
2944 &Context,
2945 DeviceNode,
2946 IopActionInitChildServices,
2947 DeviceNode);
2948
2949 return IopTraverseDeviceTree(&Context);
2950 }
2951
2952 static NTSTATUS INIT_FUNCTION
2953 IopEnumerateDetectedDevices(
2954 IN HANDLE hBaseKey,
2955 IN PUNICODE_STRING RelativePath OPTIONAL,
2956 IN HANDLE hRootKey,
2957 IN BOOLEAN EnumerateSubKeys,
2958 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2959 IN ULONG ParentBootResourcesLength)
2960 {
2961 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2962 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2963 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2964 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2965 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2966 OBJECT_ATTRIBUTES ObjectAttributes;
2967 HANDLE hDevicesKey = NULL;
2968 HANDLE hDeviceKey = NULL;
2969 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2970 UNICODE_STRING Level2NameU;
2971 WCHAR Level2Name[5];
2972 ULONG IndexDevice = 0;
2973 ULONG IndexSubKey;
2974 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2975 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2976 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2977 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2978 UNICODE_STRING DeviceName, ValueName;
2979 ULONG RequiredSize;
2980 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2981 ULONG BootResourcesLength;
2982 NTSTATUS Status;
2983
2984 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2985 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2986 static ULONG DeviceIndexSerial = 0;
2987 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2988 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2989 static ULONG DeviceIndexKeyboard = 0;
2990 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2991 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2992 static ULONG DeviceIndexMouse = 0;
2993 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2994 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2995 static ULONG DeviceIndexParallel = 0;
2996 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2997 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2998 static ULONG DeviceIndexFloppy = 0;
2999 UNICODE_STRING HardwareIdKey;
3000 PUNICODE_STRING pHardwareId;
3001 ULONG DeviceIndex = 0;
3002 PUCHAR CmResourceList;
3003 ULONG ListCount;
3004
3005 if (RelativePath)
3006 {
3007 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
3008 if (!NT_SUCCESS(Status))
3009 {
3010 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3011 goto cleanup;
3012 }
3013 }
3014 else
3015 hDevicesKey = hBaseKey;
3016
3017 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3018 if (!pDeviceInformation)
3019 {
3020 DPRINT("ExAllocatePool() failed\n");
3021 Status = STATUS_NO_MEMORY;
3022 goto cleanup;
3023 }
3024
3025 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3026 if (!pValueInformation)
3027 {
3028 DPRINT("ExAllocatePool() failed\n");
3029 Status = STATUS_NO_MEMORY;
3030 goto cleanup;
3031 }
3032
3033 while (TRUE)
3034 {
3035 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3036 if (Status == STATUS_NO_MORE_ENTRIES)
3037 break;
3038 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3039 {
3040 ExFreePool(pDeviceInformation);
3041 DeviceInfoLength = RequiredSize;
3042 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3043 if (!pDeviceInformation)
3044 {
3045 DPRINT("ExAllocatePool() failed\n");
3046 Status = STATUS_NO_MEMORY;
3047 goto cleanup;
3048 }
3049 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3050 }
3051 if (!NT_SUCCESS(Status))
3052 {
3053 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3054 goto cleanup;
3055 }
3056 IndexDevice++;
3057
3058 /* Open device key */
3059 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3060 DeviceName.Buffer = pDeviceInformation->Name;
3061
3062 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3063 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3064 if (!NT_SUCCESS(Status))
3065 {
3066 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3067 goto cleanup;
3068 }
3069
3070 /* Read boot resources, and add then to parent ones */
3071 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3072 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3073 {
3074 ExFreePool(pValueInformation);
3075 ValueInfoLength = RequiredSize;
3076 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3077 if (!pValueInformation)
3078 {
3079 DPRINT("ExAllocatePool() failed\n");
3080 ZwDeleteKey(hLevel2Key);
3081 Status = STATUS_NO_MEMORY;
3082 goto cleanup;
3083 }
3084 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3085 }
3086 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3087 {
3088 BootResources = ParentBootResources;
3089 BootResourcesLength = ParentBootResourcesLength;
3090 }
3091 else if (!NT_SUCCESS(Status))
3092 {
3093 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3094 goto nextdevice;
3095 }
3096 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3097 {
3098 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3099 goto nextdevice;
3100 }
3101 else
3102 {
3103 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3104
3105 /* Concatenate current resources and parent ones */
3106 if (ParentBootResourcesLength == 0)
3107 BootResourcesLength = pValueInformation->DataLength;
3108 else
3109 BootResourcesLength = ParentBootResourcesLength
3110 + pValueInformation->DataLength
3111 - Header;
3112 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3113 if (!BootResources)
3114 {
3115 DPRINT("ExAllocatePool() failed\n");
3116 goto nextdevice;
3117 }
3118 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3119 {
3120 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3121 }
3122 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3123 {
3124 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3125 RtlCopyMemory(
3126 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3127 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3128 ParentBootResourcesLength - Header);
3129 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3130 }
3131 else
3132 {
3133 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3134 RtlCopyMemory(
3135 (PVOID)((ULONG_PTR)BootResources + Header),
3136 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3137 ParentBootResourcesLength - Header);
3138 RtlCopyMemory(
3139 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3140 pValueInformation->Data + Header,
3141 pValueInformation->DataLength - Header);
3142 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3143 }
3144 }
3145
3146 if (EnumerateSubKeys)
3147 {
3148 IndexSubKey = 0;
3149 while (TRUE)
3150 {
3151 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3152 if (Status == STATUS_NO_MORE_ENTRIES)
3153 break;
3154 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3155 {
3156 ExFreePool(pDeviceInformation);
3157 DeviceInfoLength = RequiredSize;
3158 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3159 if (!pDeviceInformation)
3160 {
3161 DPRINT("ExAllocatePool() failed\n");
3162 Status = STATUS_NO_MEMORY;
3163 goto cleanup;
3164 }
3165 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3166 }
3167 if (!NT_SUCCESS(Status))
3168 {
3169 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3170 goto cleanup;
3171 }
3172 IndexSubKey++;
3173 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3174 DeviceName.Buffer = pDeviceInformation->Name;
3175
3176 Status = IopEnumerateDetectedDevices(
3177 hDeviceKey,
3178 &DeviceName,
3179 hRootKey,
3180 TRUE,
3181 BootResources,
3182 BootResourcesLength);
3183 if (!NT_SUCCESS(Status))
3184 goto cleanup;
3185 }
3186 }
3187
3188 /* Read identifier */
3189 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3190 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3191 {
3192 ExFreePool(pValueInformation);
3193 ValueInfoLength = RequiredSize;
3194 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3195 if (!pValueInformation)
3196 {
3197 DPRINT("ExAllocatePool() failed\n");
3198 Status = STATUS_NO_MEMORY;
3199 goto cleanup;
3200 }
3201 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3202 }
3203 if (!NT_SUCCESS(Status))
3204 {
3205 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
3206 {
3207 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3208 goto nextdevice;
3209 }
3210 ValueName.Length = ValueName.MaximumLength = 0;
3211 }
3212 else if (pValueInformation->Type != REG_SZ)
3213 {
3214 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3215 goto nextdevice;
3216 }
3217 else
3218 {
3219 /* Assign hardware id to this device */
3220 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3221 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3222 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3223 ValueName.Length -= sizeof(WCHAR);
3224 }
3225
3226 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3227 {
3228 pHardwareId = &HardwareIdSerial;
3229 DeviceIndex = DeviceIndexSerial++;
3230 }
3231 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3232 {
3233 pHardwareId = &HardwareIdKeyboard;
3234 DeviceIndex = DeviceIndexKeyboard++;
3235 }
3236 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3237 {
3238 pHardwareId = &HardwareIdMouse;
3239 DeviceIndex = DeviceIndexMouse++;
3240 }
3241 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3242 {
3243 pHardwareId = &HardwareIdParallel;
3244 DeviceIndex = DeviceIndexParallel++;
3245 }
3246 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3247 {
3248 pHardwareId = &HardwareIdFloppy;
3249 DeviceIndex = DeviceIndexFloppy++;
3250 }
3251 else
3252 {
3253 /* Unknown key path */
3254 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3255 goto nextdevice;
3256 }
3257
3258 /* Prepare hardware id key (hardware id value without final \0) */
3259 HardwareIdKey = *pHardwareId;
3260 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3261
3262 /* Add the detected device to Root key */
3263 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3264 Status = ZwCreateKey(
3265 &hLevel1Key,
3266 KEY_CREATE_SUB_KEY,
3267 &ObjectAttributes,
3268 0,
3269 NULL,
3270 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3271 NULL);
3272 if (!NT_SUCCESS(Status))
3273 {
3274 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3275 goto nextdevice;
3276 }
3277 swprintf(Level2Name, L"%04lu", DeviceIndex);
3278 RtlInitUnicodeString(&Level2NameU, Level2Name);
3279 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3280 Status = ZwCreateKey(
3281 &hLevel2Key,
3282 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3283 &ObjectAttributes,
3284 0,
3285 NULL,
3286 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3287 NULL);
3288 ZwClose(hLevel1Key);
3289 if (!NT_SUCCESS(Status))
3290 {
3291 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3292 goto nextdevice;
3293 }
3294 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3295 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3296 if (!NT_SUCCESS(Status))
3297 {
3298 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3299 ZwDeleteKey(hLevel2Key);
3300 goto nextdevice;
3301 }
3302 /* Create 'LogConf' subkey */
3303 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3304 Status = ZwCreateKey(
3305 &hLogConf,
3306 KEY_SET_VALUE,
3307 &ObjectAttributes,
3308 0,
3309 NULL,
3310 REG_OPTION_VOLATILE,
3311 NULL);
3312 if (!NT_SUCCESS(Status))
3313 {
3314 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3315 ZwDeleteKey(hLevel2Key);
3316 goto nextdevice;
3317 }
3318 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3319 {
3320 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3321 if (!CmResourceList)
3322 {
3323 ZwClose(hLogConf);
3324 ZwDeleteKey(hLevel2Key);
3325 goto nextdevice;
3326 }
3327
3328 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3329 ListCount = 1;
3330 RtlCopyMemory(CmResourceList,
3331 &ListCount,
3332 sizeof(ULONG));
3333
3334 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3335 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3336 BootResources,
3337 BootResourcesLength);
3338
3339 /* Save boot resources to 'LogConf\BootConfig' */
3340 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3341 if (!NT_SUCCESS(Status))
3342 {
3343 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3344 ZwClose(hLogConf);
3345 ZwDeleteKey(hLevel2Key);
3346 goto nextdevice;
3347 }
3348 }
3349 ZwClose(hLogConf);
3350
3351 nextdevice:
3352 if (BootResources && BootResources != ParentBootResources)
3353 {
3354 ExFreePool(BootResources);
3355 BootResources = NULL;
3356 }
3357 if (hLevel2Key)
3358 {
3359 ZwClose(hLevel2Key);
3360 hLevel2Key = NULL;
3361 }
3362 if (hDeviceKey)
3363 {
3364 ZwClose(hDeviceKey);
3365 hDeviceKey = NULL;
3366 }
3367 }
3368
3369 Status = STATUS_SUCCESS;
3370
3371 cleanup:
3372 if (hDevicesKey && hDevicesKey != hBaseKey)
3373 ZwClose(hDevicesKey);
3374 if (hDeviceKey)
3375 ZwClose(hDeviceKey);
3376 if (pDeviceInformation)
3377 ExFreePool(pDeviceInformation);
3378 if (pValueInformation)
3379 ExFreePool(pValueInformation);
3380 return Status;
3381 }
3382
3383 static BOOLEAN INIT_FUNCTION
3384 IopIsFirmwareMapperDisabled(VOID)
3385 {
3386 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3387 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3388 OBJECT_ATTRIBUTES ObjectAttributes;
3389 HANDLE hPnpKey;
3390 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3391 ULONG DesiredLength, Length;
3392 ULONG KeyValue = 0;
3393 NTSTATUS Status;
3394
3395 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3396 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3397 if (NT_SUCCESS(Status))
3398 {
3399 Status = ZwQueryValueKey(hPnpKey,
3400 &KeyNameU,
3401 KeyValuePartialInformation,
3402 NULL,
3403 0,
3404 &DesiredLength);
3405 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3406 (Status == STATUS_BUFFER_OVERFLOW))
3407 {
3408 Length = DesiredLength;
3409 KeyInformation = ExAllocatePool(PagedPool, Length);
3410 if (KeyInformation)
3411 {
3412 Status = ZwQueryValueKey(hPnpKey,
3413 &KeyNameU,
3414 KeyValuePartialInformation,
3415 KeyInformation,
3416 Length,
3417 &DesiredLength);
3418 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3419 {
3420 KeyValue = (ULONG)(*KeyInformation->Data);
3421 }
3422 else
3423 {
3424 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3425 }
3426
3427 ExFreePool(KeyInformation);
3428 }
3429 else
3430 {
3431 DPRINT1("Failed to allocate memory for registry query\n");
3432 }
3433 }
3434 else
3435 {
3436 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3437 }
3438
3439 ZwClose(hPnpKey);
3440 }
3441 else
3442 {
3443 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3444 }
3445
3446 DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3447
3448 return (KeyValue != 0) ? TRUE : FALSE;
3449 }
3450
3451 NTSTATUS
3452 NTAPI
3453 INIT_FUNCTION
3454 IopUpdateRootKey(VOID)
3455 {
3456 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3457 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3458 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3459 OBJECT_ATTRIBUTES ObjectAttributes;
3460 HANDLE hEnum, hRoot;
3461 NTSTATUS Status;
3462
3463 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3464 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3465 if (!NT_SUCCESS(Status))
3466 {
3467 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3468 return Status;
3469 }
3470
3471 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3472 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3473 ZwClose(hEnum);
3474 if (!NT_SUCCESS(Status))
3475 {
3476 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3477 return Status;
3478 }
3479
3480 if (!IopIsFirmwareMapperDisabled())
3481 {
3482 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3483 if (!NT_SUCCESS(Status))
3484 {
3485 /* Nothing to do, don't return with an error status */
3486 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3487 ZwClose(hRoot);
3488 return STATUS_SUCCESS;
3489 }
3490 Status = IopEnumerateDetectedDevices(
3491 hEnum,
3492 NULL,
3493 hRoot,
3494 TRUE,
3495 NULL,
3496 0);
3497 ZwClose(hEnum);
3498 }
3499 else
3500 {
3501 /* Enumeration is disabled */
3502 Status = STATUS_SUCCESS;
3503 }
3504
3505 ZwClose(hRoot);
3506
3507 return Status;
3508 }
3509
3510 NTSTATUS
3511 NTAPI
3512 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3513 HANDLE ParentKey,
3514 PUNICODE_STRING Name,
3515 ACCESS_MASK DesiredAccess)
3516 {
3517 OBJECT_ATTRIBUTES ObjectAttributes;
3518 NTSTATUS Status;
3519
3520 PAGED_CODE();
3521
3522 *KeyHandle = NULL;
3523
3524 InitializeObjectAttributes(&ObjectAttributes,
3525 Name,
3526 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3527 ParentKey,
3528 NULL);
3529
3530 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3531
3532 return Status;
3533 }
3534
3535 NTSTATUS
3536 NTAPI
3537 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3538 IN HANDLE RootHandle OPTIONAL,
3539 IN PUNICODE_STRING KeyName,
3540 IN ACCESS_MASK DesiredAccess,
3541 IN ULONG CreateOptions,
3542 OUT PULONG Disposition OPTIONAL)
3543 {
3544 OBJECT_ATTRIBUTES ObjectAttributes;
3545 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3546 USHORT Length;
3547 HANDLE HandleArray[2];
3548 BOOLEAN Recursing = TRUE;
3549 PWCHAR pp, p, p1;
3550 UNICODE_STRING KeyString;
3551 NTSTATUS Status = STATUS_SUCCESS;
3552 PAGED_CODE();
3553
3554 /* P1 is start, pp is end */
3555 p1 = KeyName->Buffer;
3556 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3557
3558 /* Create the target key */
3559 InitializeObjectAttributes(&ObjectAttributes,
3560 KeyName,
3561 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3562 RootHandle,
3563 NULL);
3564 Status = ZwCreateKey(&HandleArray[i],
3565 DesiredAccess,
3566 &ObjectAttributes,
3567 0,
3568 NULL,
3569 CreateOptions,
3570 &KeyDisposition);
3571
3572 /* Now we check if this failed */
3573 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3574 {
3575 /* Target key failed, so we'll need to create its parent. Setup array */
3576 HandleArray[0] = NULL;
3577 HandleArray[1] = RootHandle;
3578
3579 /* Keep recursing for each missing parent */
3580 while (Recursing)
3581 {
3582 /* And if we're deep enough, close the last handle */
3583 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3584
3585 /* We're setup to ping-pong between the two handle array entries */
3586 RootHandleIndex = i;
3587 i = (i + 1) & 1;
3588
3589 /* Clear the one we're attempting to open now */
3590 HandleArray[i] = NULL;
3591
3592 /* Process the parent key name */
3593 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3594 Length = (USHORT)(p - p1) * sizeof(WCHAR);
3595
3596 /* Is there a parent name? */
3597 if (Length)
3598 {
3599 /* Build the unicode string for it */
3600 KeyString.Buffer = p1;
3601 KeyString.Length = KeyString.MaximumLength = Length;
3602
3603 /* Now try opening the parent */
3604 InitializeObjectAttributes(&ObjectAttributes,
3605 &KeyString,
3606 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3607 HandleArray[RootHandleIndex],
3608 NULL);
3609 Status = ZwCreateKey(&HandleArray[i],
3610 DesiredAccess,
3611 &ObjectAttributes,
3612 0,
3613 NULL,
3614 CreateOptions,
3615 &KeyDisposition);
3616 if (NT_SUCCESS(Status))
3617 {
3618 /* It worked, we have one more handle */
3619 NestedCloseLevel++;
3620 }
3621 else
3622 {
3623 /* Parent key creation failed, abandon loop */
3624 Recursing = FALSE;
3625 continue;
3626 }
3627 }
3628 else
3629 {
3630 /* We don't have a parent name, probably corrupted key name */
3631 Status = STATUS_INVALID_PARAMETER;
3632 Recursing = FALSE;
3633 continue;
3634 }
3635
3636 /* Now see if there's more parents to create */
3637 p1 = p + 1;
3638 if ((p == pp) || (p1 == pp))
3639 {
3640 /* We're done, hopefully successfully, so stop */
3641 Recursing = FALSE;
3642 }
3643 }
3644
3645 /* Outer loop check for handle nesting that requires closing the top handle */
3646 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3647 }
3648
3649 /* Check if we broke out of the loop due to success */
3650 if (NT_SUCCESS(Status))
3651 {
3652 /* Return the target handle (we closed all the parent ones) and disposition */
3653 *Handle = HandleArray[i];
3654 if (Disposition) *Disposition = KeyDisposition;
3655 }
3656
3657 /* Return the success state */
3658 return Status;
3659 }
3660
3661 NTSTATUS
3662 NTAPI
3663 IopGetRegistryValue(IN HANDLE Handle,
3664 IN PWSTR ValueName,
3665 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3666 {
3667 UNICODE_STRING ValueString;
3668 NTSTATUS Status;
3669 PKEY_VALUE_FULL_INFORMATION FullInformation;
3670 ULONG Size;
3671 PAGED_CODE();
3672
3673 RtlInitUnicodeString(&ValueString, ValueName);
3674
3675 Status = ZwQueryValueKey(Handle,
3676 &ValueString,
3677 KeyValueFullInformation,
3678 NULL,
3679 0,
3680 &Size);
3681 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3682 (Status != STATUS_BUFFER_TOO_SMALL))
3683 {
3684 return Status;
3685 }
3686
3687 FullInformation = ExAllocatePool(NonPagedPool, Size);
3688 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3689
3690 Status = ZwQueryValueKey(Handle,
3691 &ValueString,
3692 KeyValueFullInformation,
3693 FullInformation,
3694 Size,
3695 &Size);
3696 if (!NT_SUCCESS(Status))
3697 {
3698 ExFreePool(FullInformation);
3699 return Status;
3700 }
3701
3702 *Information = FullInformation;
3703 return STATUS_SUCCESS;
3704 }
3705
3706 RTL_GENERIC_COMPARE_RESULTS
3707 NTAPI
3708 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3709 IN PVOID FirstStruct,
3710 IN PVOID SecondStruct)
3711 {
3712 /* FIXME: TODO */
3713 ASSERT(FALSE);
3714 return 0;
3715 }
3716
3717 //
3718 // The allocation function is called by the generic table package whenever
3719 // it needs to allocate memory for the table.
3720 //
3721
3722 PVOID
3723 NTAPI
3724 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3725 IN CLONG ByteSize)
3726 {
3727 /* FIXME: TODO */
3728 ASSERT(FALSE);
3729 return NULL;
3730 }
3731
3732 VOID
3733 NTAPI
3734 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3735 IN PVOID Buffer)
3736 {
3737 /* FIXME: TODO */
3738 ASSERT(FALSE);
3739 }
3740
3741 VOID
3742 NTAPI
3743 PpInitializeDeviceReferenceTable(VOID)
3744 {
3745 /* Setup the guarded mutex and AVL table */
3746 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3747 RtlInitializeGenericTableAvl(
3748 &PpDeviceReferenceTable,
3749 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3750 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3751 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3752 NULL);
3753 }
3754
3755 BOOLEAN
3756 NTAPI
3757 PiInitPhase0(VOID)
3758 {
3759 /* Initialize the resource when accessing device registry data */
3760 ExInitializeResourceLite(&PpRegistryDeviceResource);
3761
3762 /* Setup the device reference AVL table */
3763 PpInitializeDeviceReferenceTable();
3764 return TRUE;
3765 }
3766
3767 BOOLEAN
3768 NTAPI
3769 PpInitSystem(VOID)
3770 {
3771 /* Check the initialization phase */
3772 switch (ExpInitializationPhase)
3773 {
3774 case 0:
3775
3776 /* Do Phase 0 */
3777 return PiInitPhase0();
3778
3779 case 1:
3780
3781 /* Do Phase 1 */
3782 return TRUE;
3783 //return PiInitPhase1();
3784
3785 default:
3786
3787 /* Don't know any other phase! Bugcheck! */
3788 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3789 return FALSE;
3790 }
3791 }
3792
3793 LONG IopNumberDeviceNodes;
3794
3795 PDEVICE_NODE
3796 NTAPI
3797 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
3798 {
3799 PDEVICE_NODE DeviceNode;
3800 PAGED_CODE();
3801
3802 /* Allocate it */
3803 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE);
3804 if (!DeviceNode) return DeviceNode;
3805
3806 /* Statistics */
3807 InterlockedIncrement(&IopNumberDeviceNodes);
3808
3809 /* Set it up */
3810 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3811 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3812 DeviceNode->BusNumber = -1;
3813 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3814 DeviceNode->ChildBusNumber = -1;
3815 DeviceNode->ChildBusTypeIndex = -1;
3816 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3817 InitializeListHead(&DeviceNode->DeviceArbiterList);
3818 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3819 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3820 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3821 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3822
3823 /* Check if there is a PDO */
3824 if (PhysicalDeviceObject)
3825 {
3826 /* Link it and remove the init flag */
3827 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3828 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3829 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3830 }
3831
3832 /* Return the node */
3833 return DeviceNode;
3834 }
3835
3836 /* PUBLIC FUNCTIONS **********************************************************/
3837
3838 NTSTATUS
3839 NTAPI
3840 PnpBusTypeGuidGet(IN USHORT Index,
3841 IN LPGUID BusTypeGuid)
3842 {
3843 NTSTATUS Status = STATUS_SUCCESS;
3844
3845 /* Acquire the lock */
3846 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3847
3848 /* Validate size */
3849 if (Index < PnpBusTypeGuidList->GuidCount)
3850 {
3851 /* Copy the data */
3852 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3853 }
3854 else
3855 {
3856 /* Failure path */
3857 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3858 }
3859
3860 /* Release lock and return status */
3861 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3862 return Status;
3863 }
3864
3865 NTSTATUS
3866 NTAPI
3867 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3868 IN PHANDLE DeviceInstanceHandle,
3869 IN ACCESS_MASK DesiredAccess)
3870 {
3871 NTSTATUS Status;
3872 HANDLE KeyHandle;
3873 PDEVICE_NODE DeviceNode;
3874 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3875 PAGED_CODE();
3876
3877 /* Open the enum key */
3878 Status = IopOpenRegistryKeyEx(&KeyHandle,
3879 NULL,
3880 &KeyName,
3881 KEY_READ);
3882 if (!NT_SUCCESS(Status)) return Status;
3883
3884 /* Make sure we have an instance path */
3885 DeviceNode = IopGetDeviceNode(DeviceObject);
3886 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3887 {
3888 /* Get the instance key */
3889 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3890 KeyHandle,
3891 &DeviceNode->InstancePath,
3892 DesiredAccess);
3893 }
3894 else
3895 {
3896 /* Fail */
3897 Status = STATUS_INVALID_DEVICE_REQUEST;
3898 }
3899
3900 /* Close the handle and return status */
3901 ZwClose(KeyHandle);
3902 return Status;
3903 }
3904
3905 ULONG
3906 NTAPI
3907 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3908 {
3909 ULONG FinalSize, PartialSize, EntrySize, i, j;
3910 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3911 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3912
3913 /* If we don't have one, that's easy */
3914 if (!ResourceList) return 0;
3915
3916 /* Start with the minimum size possible */
3917 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3918
3919 /* Loop each full descriptor */
3920 FullDescriptor = ResourceList->List;
3921 for (i = 0; i < ResourceList->Count; i++)
3922 {
3923 /* Start with the minimum size possible */
3924 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3925 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3926
3927 /* Loop each partial descriptor */
3928 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3929 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3930 {
3931 /* Start with the minimum size possible */
3932 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3933
3934 /* Check if there is extra data */
3935 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3936 {
3937 /* Add that data */
3938 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3939 }
3940
3941 /* The size of partial descriptors is bigger */
3942 PartialSize += EntrySize;
3943
3944 /* Go to the next partial descriptor */
3945 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3946 }
3947
3948 /* The size of full descriptors is bigger */
3949 FinalSize += PartialSize;
3950
3951 /* Go to the next full descriptor */
3952 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3953 }
3954
3955 /* Return the final size */
3956 return FinalSize;
3957 }
3958
3959 NTSTATUS
3960 NTAPI
3961 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3962 IN ULONG ValueType,
3963 IN PWSTR ValueName,
3964 IN PWSTR KeyName,
3965 OUT PVOID Buffer,
3966 IN PULONG BufferLength)
3967 {
3968 NTSTATUS Status;
3969 HANDLE KeyHandle, SubHandle;
3970 UNICODE_STRING KeyString;
3971 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3972 ULONG Length;
3973 PAGED_CODE();
3974
3975 /* Find the instance key */
3976 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3977 if (NT_SUCCESS(Status))
3978 {
3979 /* Check for name given by caller */
3980 if (KeyName)
3981 {
3982 /* Open this key */
3983 RtlInitUnicodeString(&KeyString, KeyName);
3984 Status = IopOpenRegistryKeyEx(&SubHandle,
3985 KeyHandle,
3986 &KeyString,
3987 KEY_READ);
3988 if (NT_SUCCESS(Status))
3989 {
3990 /* And use this handle instead */
3991 ZwClose(KeyHandle);
3992 KeyHandle = SubHandle;
3993 }
3994 }
3995
3996 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3997 if (NT_SUCCESS(Status))
3998 {
3999 /* Now get the size of the property */
4000 Status = IopGetRegistryValue(KeyHandle,
4001 ValueName,
4002 &KeyValueInfo);
4003 }
4004
4005 /* Close the key */
4006 ZwClose(KeyHandle);
4007 }
4008
4009 /* Fail if any of the registry operations failed */
4010 if (!NT_SUCCESS(Status)) return Status;
4011
4012 /* Check how much data we have to copy */
4013 Length = KeyValueInfo->DataLength;
4014 if (*BufferLength >= Length)
4015 {
4016 /* Check for a match in the value type */
4017 if (KeyValueInfo->Type == ValueType)
4018 {
4019 /* Copy the data */
4020 RtlCopyMemory(Buffer,
4021 (PVOID)((ULONG_PTR)KeyValueInfo +
4022 KeyValueInfo->DataOffset),
4023 Length);
4024 }
4025 else
4026 {
4027 /* Invalid registry property type, fail */
4028 Status = STATUS_INVALID_PARAMETER_2;
4029 }
4030 }
4031 else
4032 {
4033 /* Buffer is too small to hold data */
4034 Status = STATUS_BUFFER_TOO_SMALL;
4035 }
4036
4037 /* Return the required buffer length, free the buffer, and return status */
4038 *BufferLength = Length;
4039 ExFreePool(KeyValueInfo);
4040 return Status;
4041 }
4042
4043 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
4044 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
4045 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
4046
4047 /*
4048 * @implemented
4049 */
4050 NTSTATUS
4051 NTAPI
4052 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
4053 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
4054 IN ULONG BufferLength,
4055 OUT PVOID PropertyBuffer,
4056 OUT PULONG ResultLength)
4057 {
4058 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4059 DEVICE_CAPABILITIES DeviceCaps;
4060 ULONG ReturnLength = 0, Length = 0, ValueType;
4061 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
4062 PVOID Data = NULL;
4063 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
4064 GUID BusTypeGuid;
4065 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
4066 BOOLEAN NullTerminate = FALSE;
4067
4068 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
4069
4070 /* Assume failure */
4071 *ResultLength = 0;
4072
4073 /* Only PDOs can call this */
4074 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
4075
4076 /* Handle all properties */
4077 switch (DeviceProperty)
4078 {
4079 case DevicePropertyBusTypeGuid:
4080
4081 /* Get the GUID from the internal cache */
4082 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
4083 if (!NT_SUCCESS(Status)) return Status;
4084
4085 /* This is the format of the returned data */
4086 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
4087
4088 case DevicePropertyLegacyBusType:
4089
4090 /* Validate correct interface type */
4091 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
4092 return STATUS_OBJECT_NAME_NOT_FOUND;
4093
4094 /* This is the format of the returned data */
4095 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
4096
4097 case DevicePropertyBusNumber:
4098
4099 /* Validate correct bus number */
4100 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
4101 return STATUS_OBJECT_NAME_NOT_FOUND;
4102
4103 /* This is the format of the returned data */
4104 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
4105
4106 case DevicePropertyEnumeratorName:
4107
4108 /* Get the instance path */
4109 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
4110
4111 /* Sanity checks */
4112 ASSERT((BufferLength & 1) == 0);
4113 ASSERT(DeviceInstanceName != NULL);
4114
4115 /* Get the name from the path */
4116 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
4117 ASSERT(EnumeratorNameEnd);
4118
4119 /* This string needs to be NULL-terminated */
4120 NullTerminate = TRUE;
4121
4122 /* This is the format of the returned data */
4123 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
4124 DeviceInstanceName);
4125
4126 case DevicePropertyAddress:
4127
4128 /* Query the device caps */
4129 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
4130 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
4131 return STATUS_OBJECT_NAME_NOT_FOUND;
4132
4133 /* This is the format of the returned data */
4134 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
4135
4136 case DevicePropertyBootConfigurationTranslated:
4137
4138 /* Validate we have resources */
4139 if (!DeviceNode->BootResources)
4140 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
4141 {
4142 /* No resources will still fake success, but with 0 bytes */
4143 *ResultLength = 0;
4144 return STATUS_SUCCESS;
4145 }
4146
4147 /* This is the format of the returned data */
4148 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
4149 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
4150
4151 case DevicePropertyPhysicalDeviceObjectName:
4152
4153 /* Sanity check for Unicode-sized string */
4154 ASSERT((BufferLength & 1) == 0);
4155
4156 /* Allocate name buffer */
4157 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
4158 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
4159 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
4160
4161 /* Query the PDO name */
4162 Status = ObQueryNameString(DeviceObject,
4163 ObjectNameInfo,
4164 Length,
4165 ResultLength);
4166 if (Status == STATUS_INFO_LENGTH_MISMATCH)
4167 {
4168 /* It's up to the caller to try again */
4169 Status = STATUS_BUFFER_TOO_SMALL;
4170 }
4171
4172 /* This string needs to be NULL-terminated */
4173 NullTerminate = TRUE;
4174
4175 /* Return if successful */
4176 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
4177 ObjectNameInfo->Name.Buffer);
4178
4179 /* Let the caller know how big the name is */
4180 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
4181 break;
4182
4183 case DevicePropertyRemovalPolicy:
4184 PIP_RETURN_DATA(sizeof(UCHAR), &DeviceNode->RemovalPolicy);
4185
4186 /* Handle the registry-based properties */
4187 case DevicePropertyUINumber:
4188 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
4189 case DevicePropertyLocationInformation:
4190 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
4191 case DevicePropertyDeviceDescription:
4192 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
4193 case DevicePropertyHardwareID:
4194 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
4195 case DevicePropertyCompatibleIDs:
4196 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
4197 case DevicePropertyBootConfiguration:
4198 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
4199 case DevicePropertyClassName:
4200 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
4201 case DevicePropertyClassGuid:
4202 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
4203 case DevicePropertyDriverKeyName:
4204 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
4205 case DevicePropertyManufacturer:
4206 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
4207 case DevicePropertyFriendlyName:
4208 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
4209 case DevicePropertyContainerID:
4210 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
4211 PIP_UNIMPLEMENTED();
4212 break;
4213 case DevicePropertyInstallState:
4214 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD);
4215 break;
4216 case DevicePropertyResourceRequirements:
4217 PIP_UNIMPLEMENTED();
4218 case DevicePropertyAllocatedResources:
4219 PIP_UNIMPLEMENTED();
4220 default:
4221 return STATUS_INVALID_PARAMETER_2;
4222 }
4223
4224 /* Having a registry value name implies registry data */
4225 if (ValueName)
4226 {
4227 /* We know up-front how much data to expect */
4228 *ResultLength = BufferLength;
4229
4230 /* Go get the data, use the LogConf subkey if necessary */
4231 Status = PiGetDeviceRegistryProperty(DeviceObject,
4232 ValueType,
4233 ValueName,
4234 (DeviceProperty ==
4235 DevicePropertyBootConfiguration) ?
4236 L"LogConf": NULL,
4237 PropertyBuffer,
4238 ResultLength);
4239 }
4240 else if (NT_SUCCESS(Status))
4241 {
4242 /* We know up-front how much data to expect, check the caller's buffer */
4243 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
4244 if (*ResultLength <= BufferLength)
4245 {
4246 /* Buffer is all good, copy the data */
4247 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
4248
4249 /* Check if we need to NULL-terminate the string */
4250 if (NullTerminate)
4251 {
4252 /* Terminate the string */
4253 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
4254 }
4255
4256 /* This is the success path */
4257 Status = STATUS_SUCCESS;
4258 }
4259 else
4260 {
4261 /* Failure path */
4262 Status = STATUS_BUFFER_TOO_SMALL;
4263 }
4264 }
4265
4266 /* Free any allocation we may have made, and return the status code */
4267 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
4268 return Status;
4269 }
4270
4271 /*
4272 * @implemented
4273 */
4274 VOID
4275 NTAPI
4276 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
4277 {
4278 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4279 IO_STACK_LOCATION Stack;
4280 ULONG PnPFlags;
4281 NTSTATUS Status;
4282 IO_STATUS_BLOCK IoStatusBlock;
4283
4284 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
4285 Stack.MajorFunction = IRP_MJ_PNP;
4286 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
4287
4288 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
4289 if (!NT_SUCCESS(Status))
4290 {
4291 if (Status != STATUS_NOT_SUPPORTED)
4292 {
4293 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status);
4294 }
4295 return;
4296 }
4297
4298 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
4299 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
4300 else
4301 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
4302
4303 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
4304 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
4305 else
4306 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
4307
4308 if ((PnPFlags & PNP_DEVICE_REMOVED) ||
4309 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
4310 {
4311 /* Flag it if it's failed */
4312 if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START;
4313
4314 /* Send removal IRPs to all of its children */
4315 IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE);
4316
4317 /* Send surprise removal */
4318 IopSendSurpriseRemoval(PhysicalDeviceObject);
4319
4320 /* Tell the user-mode PnP manager that a device was removed */
4321 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
4322 &DeviceNode->InstancePath);
4323
4324 IopSendRemoveDevice(PhysicalDeviceObject);
4325 }
4326 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
4327 {
4328 /* Stop for resource rebalance */
4329 Status = IopStopDevice(DeviceNode);
4330 if (!NT_SUCCESS(Status))
4331 {
4332 DPRINT1("Failed to stop device for rebalancing\n");
4333
4334 /* Stop failed so don't rebalance */
4335 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED;
4336 }
4337 }
4338
4339 /* Resource rebalance */
4340 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
4341 {
4342 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4343
4344 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4345 &IoStatusBlock,
4346 IRP_MN_QUERY_RESOURCES,
4347 NULL);
4348 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
4349 {
4350 DeviceNode->BootResources =
4351 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
4352 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
4353 }
4354 else
4355 {
4356 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
4357 DeviceNode->BootResources = NULL;
4358 }
4359
4360 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4361
4362 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4363 &IoStatusBlock,
4364 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
4365 NULL);
4366 if (NT_SUCCESS(Status))
4367 {
4368 DeviceNode->ResourceRequirements =
4369 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
4370 }
4371 else
4372 {
4373 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
4374 DeviceNode->ResourceRequirements = NULL;
4375 }
4376
4377 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4378 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS)
4379 {
4380 DPRINT1("Restart after resource rebalance failed\n");
4381
4382 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
4383 DeviceNode->Flags |= DNF_START_FAILED;
4384
4385 IopRemoveDevice(DeviceNode);
4386 }
4387 }
4388 }
4389
4390 /**
4391 * @name IoOpenDeviceRegistryKey
4392 *
4393 * Open a registry key unique for a specified driver or device instance.
4394 *
4395 * @param DeviceObject Device to get the registry key for.
4396 * @param DevInstKeyType Type of the key to return.
4397 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4398 * @param DevInstRegKey Handle to the opened registry key on
4399 * successful return.
4400 *
4401 * @return Status.
4402 *
4403 * @implemented
4404 */
4405 NTSTATUS
4406 NTAPI
4407 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
4408 IN ULONG DevInstKeyType,
4409 IN ACCESS_MASK DesiredAccess,
4410 OUT PHANDLE DevInstRegKey)
4411 {
4412 static WCHAR RootKeyName[] =
4413 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4414 static WCHAR ProfileKeyName[] =
4415 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4416 static WCHAR ClassKeyName[] = L"Control\\Class\\";
4417 static WCHAR EnumKeyName[] = L"Enum\\";
4418 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4419 ULONG KeyNameLength;
4420 PWSTR KeyNameBuffer;
4421 UNICODE_STRING KeyName;
4422 ULONG DriverKeyLength;
4423 OBJECT_ATTRIBUTES ObjectAttributes;
4424 PDEVICE_NODE DeviceNode = NULL;
4425 NTSTATUS Status;
4426
4427 DPRINT("IoOpenDeviceRegistryKey() called\n");
4428
4429 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
4430 {
4431 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4432 return STATUS_INVALID_PARAMETER;
4433 }
4434
4435 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
4436 return STATUS_INVALID_DEVICE_REQUEST;
4437 DeviceNode = IopGetDeviceNode(DeviceObject);
4438
4439 /*
4440 * Calculate the length of the base key name. This is the full
4441 * name for driver key or the name excluding "Device Parameters"
4442 * subkey for device key.
4443 */
4444
4445 KeyNameLength = sizeof(RootKeyName);
4446 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4447 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4448 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4449 {
4450 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4451 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4452 0, NULL, &DriverKeyLength);
4453 if (Status != STATUS_BUFFER_TOO_SMALL)
4454 return Status;
4455 KeyNameLength += DriverKeyLength;
4456 }
4457 else
4458 {
4459 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4460 DeviceNode->InstancePath.Length;
4461 }
4462
4463 /*
4464 * Now allocate the buffer for the key name...
4465 */
4466
4467 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4468 if (KeyNameBuffer == NULL)
4469 return STATUS_INSUFFICIENT_RESOURCES;
4470
4471 KeyName.Length = 0;
4472 KeyName.MaximumLength = (USHORT)KeyNameLength;
4473 KeyName.Buffer = KeyNameBuffer;
4474
4475 /*
4476 * ...and build the key name.
4477 */
4478
4479 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4480 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4481
4482 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4483 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4484
4485 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4486 {
4487 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4488 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4489 DriverKeyLength, KeyNameBuffer +
4490 (KeyName.Length / sizeof(WCHAR)),
4491 &DriverKeyLength);
4492 if (!NT_SUCCESS(Status))
4493 {
4494 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4495 ExFreePool(KeyNameBuffer);
4496 return Status;
4497 }
4498 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4499 }
4500 else
4501 {
4502 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4503 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
4504 if (DeviceNode->InstancePath.Length == 0)
4505 {
4506 ExFreePool(KeyNameBuffer);
4507 return Status;
4508 }
4509 }
4510
4511 /*
4512 * Open the base key.
4513 */
4514 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
4515 if (!NT_SUCCESS(Status))
4516 {
4517 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4518 ExFreePool(KeyNameBuffer);
4519 return Status;
4520 }
4521 ExFreePool(KeyNameBuffer);
4522
4523 /*
4524 * For driver key we're done now.
4525 */
4526
4527 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4528 return Status;
4529
4530 /*
4531 * Let's go further. For device key we must open "Device Parameters"
4532 * subkey and create it if it doesn't exist yet.
4533 */
4534
4535 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4536 InitializeObjectAttributes(&ObjectAttributes,
4537 &KeyName,
4538 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4539 *DevInstRegKey,
4540 NULL);
4541 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
4542 0, NULL, ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, NULL);
4543 ZwClose(ObjectAttributes.RootDirectory);
4544
4545 return Status;
4546 }
4547
4548 static
4549 NTSTATUS
4550 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force)
4551 {
4552 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
4553 NTSTATUS Status;
4554 KIRQL OldIrql;
4555
4556 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4557 ChildDeviceNode = ParentDeviceNode->Child;
4558 while (ChildDeviceNode != NULL)
4559 {
4560 NextDeviceNode = ChildDeviceNode->Sibling;
4561 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4562
4563 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force);
4564 if (!NT_SUCCESS(Status))
4565 {
4566 FailedRemoveDevice = ChildDeviceNode;
4567 goto cleanup;
4568 }
4569
4570 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4571 ChildDeviceNode = NextDeviceNode;
4572 }
4573 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4574
4575 return STATUS_SUCCESS;
4576
4577 cleanup:
4578 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4579 ChildDeviceNode = ParentDeviceNode->Child;
4580 while (ChildDeviceNode != NULL)
4581 {
4582 NextDeviceNode = ChildDeviceNode->Sibling;
4583 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4584
4585 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4586
4587 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4588 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4589 if (ChildDeviceNode == FailedRemoveDevice)
4590 return Status;
4591
4592 ChildDeviceNode = NextDeviceNode;
4593
4594 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4595 }
4596 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4597
4598 return Status;
4599 }
4600
4601 static
4602 VOID
4603 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4604 {
4605 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4606 KIRQL OldIrql;
4607
4608 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4609 ChildDeviceNode = ParentDeviceNode->Child;
4610 while (ChildDeviceNode != NULL)
4611 {
4612 NextDeviceNode = ChildDeviceNode->Sibling;
4613 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4614
4615 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
4616
4617 ChildDeviceNode = NextDeviceNode;
4618
4619 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4620 }
4621 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4622 }
4623
4624 static
4625 VOID
4626 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4627 {
4628 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4629 KIRQL OldIrql;
4630
4631 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4632 ChildDeviceNode = ParentDeviceNode->Child;
4633 while (ChildDeviceNode != NULL)
4634 {
4635 NextDeviceNode = ChildDeviceNode->Sibling;
4636 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4637
4638 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4639
4640 ChildDeviceNode = NextDeviceNode;
4641
4642 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4643 }
4644 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4645 }
4646
4647 static
4648 NTSTATUS
4649 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force)
4650 {
4651 /* This function DOES NOT dereference the device objects on SUCCESS
4652 * but it DOES dereference device objects on FAILURE */
4653
4654 ULONG i, j;
4655 NTSTATUS Status;
4656
4657 for (i = 0; i < DeviceRelations->Count; i++)
4658 {
4659 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force);
4660 if (!NT_SUCCESS(Status))
4661 {
4662 j = i;
4663 goto cleanup;
4664 }
4665 }
4666
4667 return STATUS_SUCCESS;
4668
4669 cleanup:
4670 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4671 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4672 for (i = 0; i <= j; i++)
4673 {
4674 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4675 ObDereferenceObject(DeviceRelations->Objects[i]);
4676 DeviceRelations->Objects[i] = NULL;
4677 }
4678 for (; i < DeviceRelations->Count; i++)
4679 {
4680 ObDereferenceObject(DeviceRelations->Objects[i]);
4681 DeviceRelations->Objects[i] = NULL;
4682 }
4683 ExFreePool(DeviceRelations);
4684
4685 return Status;
4686 }
4687
4688 static
4689 VOID
4690 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4691 {
4692 /* This function DOES dereference the device objects in all cases */
4693
4694 ULONG i;
4695
4696 for (i = 0; i < DeviceRelations->Count; i++)
4697 {
4698 IopSendRemoveDevice(DeviceRelations->Objects[i]);
4699 DeviceRelations->Objects[i] = NULL;
4700 }
4701
4702 ExFreePool(DeviceRelations);
4703 }
4704
4705 static
4706 VOID
4707 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4708 {
4709 /* This function DOES dereference the device objects in all cases */
4710
4711 ULONG i;
4712
4713 for (i = 0; i < DeviceRelations->Count; i++)
4714 {
4715 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4716 ObDereferenceObject(DeviceRelations->Objects[i]);
4717 DeviceRelations->Objects[i] = NULL;
4718 }
4719
4720 ExFreePool(DeviceRelations);
4721 }
4722
4723 VOID
4724 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
4725 {
4726 IO_STACK_LOCATION Stack;
4727 IO_STATUS_BLOCK IoStatusBlock;
4728 PDEVICE_RELATIONS DeviceRelations;
4729 NTSTATUS Status;
4730
4731 IopCancelRemoveDevice(DeviceObject);
4732
4733 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4734
4735 Status = IopInitiatePnpIrp(DeviceObject,
4736 &IoStatusBlock,
4737 IRP_MN_QUERY_DEVICE_RELATIONS,
4738 &Stack);
4739 if (!NT_SUCCESS(Status))
4740 {
4741 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4742 DeviceRelations = NULL;
4743 }
4744 else
4745 {
4746 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4747 }
4748
4749 if (DeviceRelations)
4750 IopCancelRemoveDeviceRelations(DeviceRelations);
4751 }
4752
4753 NTSTATUS
4754 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force)
4755 {
4756 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4757 IO_STACK_LOCATION Stack;
4758 IO_STATUS_BLOCK IoStatusBlock;
4759 PDEVICE_RELATIONS DeviceRelations;
4760 NTSTATUS Status;
4761
4762 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force)
4763 {
4764 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
4765 return STATUS_UNSUCCESSFUL;
4766 }
4767
4768 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
4769 {
4770 DPRINT1("Removal vetoed by failing the query remove request\n");
4771
4772 IopCancelRemoveDevice(DeviceObject);
4773
4774 return STATUS_UNSUCCESSFUL;
4775 }
4776
4777 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4778
4779 Status = IopInitiatePnpIrp(DeviceObject,
4780 &IoStatusBlock,
4781 IRP_MN_QUERY_DEVICE_RELATIONS,
4782 &Stack);
4783 if (!NT_SUCCESS(Status))
4784 {
4785 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4786 DeviceRelations = NULL;
4787 }
4788 else
4789 {
4790 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4791 }
4792
4793 if (DeviceRelations)
4794 {
4795 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force);
4796 if (!NT_SUCCESS(Status))
4797 return Status;
4798 }
4799
4800 Status = IopQueryRemoveChildDevices(DeviceNode, Force);
4801 if (!NT_SUCCESS(Status))
4802 {
4803 if (DeviceRelations)
4804 IopCancelRemoveDeviceRelations(DeviceRelations);
4805 return Status;
4806 }
4807
4808 if (DeviceRelations)
4809 IopSendRemoveDeviceRelations(DeviceRelations);
4810 IopSendRemoveChildDevices(DeviceNode);
4811
4812 return STATUS_SUCCESS;
4813 }
4814
4815 NTSTATUS
4816 IopRemoveDevice(PDEVICE_NODE DeviceNode)
4817 {
4818 NTSTATUS Status;
4819
4820 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
4821
4822 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE);
4823 if (NT_SUCCESS(Status))
4824 {
4825 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
4826 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
4827 &DeviceNode->InstancePath);
4828 return STATUS_SUCCESS;
4829 }
4830
4831 return Status;
4832 }
4833
4834 /*
4835 * @implemented
4836 */
4837 VOID
4838 NTAPI
4839 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
4840 {
4841 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4842 PDEVICE_RELATIONS DeviceRelations;
4843 IO_STATUS_BLOCK IoStatusBlock;
4844 IO_STACK_LOCATION Stack;
4845 DEVICE_CAPABILITIES Capabilities;
4846 NTSTATUS Status;
4847
4848 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
4849 &DeviceNode->InstancePath);
4850
4851 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
4852 {
4853 goto cleanup;
4854 }
4855
4856 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
4857
4858 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4859 &IoStatusBlock,
4860 IRP_MN_QUERY_DEVICE_RELATIONS,
4861 &Stack);
4862 if (!NT_SUCCESS(Status))
4863 {
4864 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4865 DeviceRelations = NULL;
4866 }
4867 else
4868 {
4869 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4870 }
4871
4872 if (DeviceRelations)
4873 {
4874 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE);
4875 if (!NT_SUCCESS(Status))
4876 goto cleanup;
4877 }
4878
4879 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE);
4880 if (!NT_SUCCESS(Status))
4881 {
4882 if (DeviceRelations)
4883 IopCancelRemoveDeviceRelations(DeviceRelations);
4884 goto cleanup;
4885 }
4886
4887 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS)
4888 {
4889 if (DeviceRelations)
4890 IopCancelRemoveDeviceRelations(DeviceRelations);
4891 IopCancelRemoveChildDevices(DeviceNode);
4892 goto cleanup;
4893 }
4894
4895 if (DeviceRelations)
4896 IopSendRemoveDeviceRelations(DeviceRelations);
4897 IopSendRemoveChildDevices(DeviceNode);
4898
4899 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT;
4900 if (Capabilities.EjectSupported)
4901 {
4902 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
4903 {
4904 goto cleanup;
4905 }
4906 }
4907 else
4908 {
4909 DeviceNode->Flags |= DNF_DISABLED;
4910 }
4911
4912 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
4913 &DeviceNode->InstancePath);
4914
4915 return;
4916
4917 cleanup:
4918 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
4919 &DeviceNode->InstancePath);
4920 }
4921
4922 /*
4923 * @implemented
4924 */
4925 VOID
4926 NTAPI
4927 IoInvalidateDeviceRelations(
4928 IN PDEVICE_OBJECT DeviceObject,
4929 IN DEVICE_RELATION_TYPE Type)
4930 {
4931 PDEVICE_ACTION_DATA Data;
4932 KIRQL OldIrql;
4933
4934 Data = ExAllocatePoolWithTag(NonPagedPool,
4935 sizeof(DEVICE_ACTION_DATA),
4936 TAG_IO);
4937 if (!Data)
4938 return;
4939
4940 ObReferenceObject(DeviceObject);
4941 Data->DeviceObject = DeviceObject;
4942 Data->Type = Type;
4943
4944 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
4945 InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry);
4946 if (IopDeviceActionInProgress)
4947 {
4948 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
4949 return;
4950 }
4951 IopDeviceActionInProgress = TRUE;
4952 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
4953
4954 ExInitializeWorkItem(&IopDeviceActionWorkItem,
4955 IopDeviceActionWorker,
4956 NULL);
4957 ExQueueWorkItem(&IopDeviceActionWorkItem,
4958 DelayedWorkQueue);
4959 }
4960
4961 /*
4962 * @implemented
4963 */
4964 NTSTATUS
4965 NTAPI
4966 IoSynchronousInvalidateDeviceRelations(
4967 IN PDEVICE_OBJECT DeviceObject,
4968 IN DEVICE_RELATION_TYPE Type)
4969 {
4970 PAGED_CODE();
4971
4972 switch (Type)
4973 {
4974 case BusRelations:
4975 /* Enumerate the device */
4976 return IopEnumerateDevice(DeviceObject);
4977 case PowerRelations:
4978 /* Not handled yet */
4979 return STATUS_NOT_IMPLEMENTED;
4980 case TargetDeviceRelation:
4981 /* Nothing to do */
4982 return STATUS_SUCCESS;
4983 default:
4984 /* Ejection relations are not supported */
4985 return STATUS_NOT_SUPPORTED;
4986 }
4987 }
4988
4989 /*
4990 * @implemented
4991 */
4992 BOOLEAN
4993 NTAPI
4994 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
4995 IN ULONG BusNumber,
4996 IN PHYSICAL_ADDRESS BusAddress,
4997 IN OUT PULONG AddressSpace,
4998 OUT PPHYSICAL_ADDRESS TranslatedAddress)
4999 {
5000 /* FIXME: Notify the resource arbiter */
5001
5002 return HalTranslateBusAddress(InterfaceType,
5003 BusNumber,
5004 BusAddress,
5005 AddressSpace,
5006 TranslatedAddress);
5007 }