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