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