8f79fc40577034b11d3f51be5eef3cd516c4633b
[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
1851 /*
1852 * IopActionInterrogateDeviceStack
1853 *
1854 * Retrieve information for all (direct) child nodes of a parent node.
1855 *
1856 * Parameters
1857 * DeviceNode
1858 * Pointer to device node.
1859 * Context
1860 * Pointer to parent node to retrieve child node information for.
1861 *
1862 * Remarks
1863 * Any errors that occur are logged instead so that all child services have a chance
1864 * of being interrogated.
1865 */
1866
1867 NTSTATUS
1868 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
1869 PVOID Context)
1870 {
1871 IO_STATUS_BLOCK IoStatusBlock;
1872 PWSTR InformationString;
1873 PDEVICE_NODE ParentDeviceNode;
1874 WCHAR InstancePath[MAX_PATH];
1875 IO_STACK_LOCATION Stack;
1876 NTSTATUS Status;
1877 ULONG RequiredLength;
1878 LCID LocaleId;
1879 HANDLE InstanceKey = NULL;
1880 UNICODE_STRING ValueName;
1881 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
1882 UNICODE_STRING InstancePathU;
1883 DEVICE_CAPABILITIES DeviceCapabilities;
1884 PDEVICE_OBJECT OldDeviceObject;
1885
1886 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1887 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1888
1889 ParentDeviceNode = (PDEVICE_NODE)Context;
1890
1891 /*
1892 * We are called for the parent too, but we don't need to do special
1893 * handling for this node
1894 */
1895 if (DeviceNode == ParentDeviceNode)
1896 {
1897 DPRINT("Success\n");
1898 return STATUS_SUCCESS;
1899 }
1900
1901 /*
1902 * Make sure this device node is a direct child of the parent device node
1903 * that is given as an argument
1904 */
1905 if (DeviceNode->Parent != ParentDeviceNode)
1906 {
1907 DPRINT("Skipping 2+ level child\n");
1908 return STATUS_SUCCESS;
1909 }
1910
1911 /* Skip processing if it was already completed before */
1912 if (DeviceNode->Flags & DNF_PROCESSED)
1913 {
1914 /* Nothing to do */
1915 return STATUS_SUCCESS;
1916 }
1917
1918 /* Get Locale ID */
1919 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
1920 if (!NT_SUCCESS(Status))
1921 {
1922 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
1923 return Status;
1924 }
1925
1926 /*
1927 * FIXME: For critical errors, cleanup and disable device, but always
1928 * return STATUS_SUCCESS.
1929 */
1930
1931 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1932
1933 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1934 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1935 &IoStatusBlock,
1936 IRP_MN_QUERY_ID,
1937 &Stack);
1938 if (!NT_SUCCESS(Status))
1939 {
1940 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1941
1942 /* We have to return success otherwise we abort the traverse operation */
1943 return STATUS_SUCCESS;
1944 }
1945
1946 /* Copy the device id string */
1947 InformationString = (PWSTR)IoStatusBlock.Information;
1948 wcscpy(InstancePath, InformationString);
1949
1950 /*
1951 * FIXME: Check for valid characters, if there is invalid characters
1952 * then bugcheck.
1953 */
1954
1955 ExFreePoolWithTag(InformationString, 0);
1956
1957 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1958
1959 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1960 if (!NT_SUCCESS(Status))
1961 {
1962 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1963
1964 /* We have to return success otherwise we abort the traverse operation */
1965 return STATUS_SUCCESS;
1966 }
1967
1968 /* This bit is only check after enumeration */
1969 if (DeviceCapabilities.HardwareDisabled)
1970 {
1971 /* FIXME: Cleanup device */
1972 DeviceNode->Flags |= DNF_DISABLED;
1973 return STATUS_SUCCESS;
1974 }
1975 else
1976 {
1977 DeviceNode->Flags &= ~DNF_DISABLED;
1978 }
1979
1980 if (!DeviceCapabilities.UniqueID)
1981 {
1982 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1983 DPRINT("Instance ID is not unique\n");
1984 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1985 if (!NT_SUCCESS(Status))
1986 {
1987 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1988
1989 /* We have to return success otherwise we abort the traverse operation */
1990 return STATUS_SUCCESS;
1991 }
1992 }
1993
1994 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1995
1996 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1997 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1998 &IoStatusBlock,
1999 IRP_MN_QUERY_ID,
2000 &Stack);
2001 if (NT_SUCCESS(Status))
2002 {
2003 InformationString = (PWSTR)IoStatusBlock.Information;
2004
2005 /* Append the instance id string */
2006 wcscat(InstancePath, L"\\");
2007 if (ParentIdPrefix.Length > 0)
2008 {
2009 /* Add information from parent bus device to InstancePath */
2010 wcscat(InstancePath, ParentIdPrefix.Buffer);
2011 if (InformationString && *InformationString)
2012 {
2013 wcscat(InstancePath, L"&");
2014 }
2015 }
2016 if (InformationString)
2017 {
2018 wcscat(InstancePath, InformationString);
2019 }
2020
2021 /*
2022 * FIXME: Check for valid characters, if there is invalid characters
2023 * then bugcheck
2024 */
2025
2026 if (InformationString)
2027 {
2028 ExFreePoolWithTag(InformationString, 0);
2029 }
2030 }
2031 else
2032 {
2033 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2034 }
2035 RtlFreeUnicodeString(&ParentIdPrefix);
2036
2037 if (!RtlCreateUnicodeString(&InstancePathU, InstancePath))
2038 {
2039 DPRINT("No resources\n");
2040 /* FIXME: Cleanup and disable device */
2041 }
2042
2043 /* Verify that this is not a duplicate */
2044 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
2045 if (OldDeviceObject != NULL)
2046 {
2047 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
2048
2049 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
2050 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
2051 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
2052
2053 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
2054 0x01,
2055 (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
2056 (ULONG_PTR)OldDeviceObject,
2057 0);
2058 }
2059
2060 DeviceNode->InstancePath = InstancePathU;
2061
2062 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2063
2064 /*
2065 * Create registry key for the instance id, if it doesn't exist yet
2066 */
2067 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
2068 if (!NT_SUCCESS(Status))
2069 {
2070 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2071
2072 /* We have to return success otherwise we abort the traverse operation */
2073 return STATUS_SUCCESS;
2074 }
2075
2076 IopQueryHardwareIds(DeviceNode, InstanceKey);
2077
2078 IopQueryCompatibleIds(DeviceNode, InstanceKey);
2079
2080 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2081
2082 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2083 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2084 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2085 &IoStatusBlock,
2086 IRP_MN_QUERY_DEVICE_TEXT,
2087 &Stack);
2088 InformationString = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information
2089 : NULL;
2090 /* This key is mandatory, so even if the Irp fails, we still write it */
2091 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2092 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2093 {
2094 if (InformationString &&
2095 *InformationString != UNICODE_NULL)
2096 {
2097 /* This key is overriden when a driver is installed. Don't write the
2098 * new description if another one already exists */
2099 Status = ZwSetValueKey(InstanceKey,
2100 &ValueName,
2101 0,
2102 REG_SZ,
2103 InformationString,
2104 ((ULONG)wcslen(InformationString) + 1) * sizeof(WCHAR));
2105 }
2106 else
2107 {
2108 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2109 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2110
2111 Status = ZwSetValueKey(InstanceKey,
2112 &ValueName,
2113 0,
2114 REG_SZ,
2115 DeviceDesc.Buffer,
2116 DeviceDesc.MaximumLength);
2117 if (!NT_SUCCESS(Status))
2118 {
2119 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2120 }
2121
2122 }
2123 }
2124
2125 if (InformationString)
2126 {
2127 ExFreePoolWithTag(InformationString, 0);
2128 }
2129
2130 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2131
2132 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2133 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2134 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2135 &IoStatusBlock,
2136 IRP_MN_QUERY_DEVICE_TEXT,
2137 &Stack);
2138 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2139 {
2140 InformationString = (PWSTR)IoStatusBlock.Information;
2141 DPRINT("LocationInformation: %S\n", InformationString);
2142 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2143 Status = ZwSetValueKey(InstanceKey,
2144 &ValueName,
2145 0,
2146 REG_SZ,
2147 InformationString,
2148 ((ULONG)wcslen(InformationString) + 1) * sizeof(WCHAR));
2149 if (!NT_SUCCESS(Status))
2150 {
2151 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2152 }
2153
2154 ExFreePoolWithTag(InformationString, 0);
2155 }
2156 else
2157 {
2158 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2159 }
2160
2161 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2162
2163 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2164 &IoStatusBlock,
2165 IRP_MN_QUERY_BUS_INFORMATION,
2166 NULL);
2167 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2168 {
2169 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2170
2171 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2172 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2173 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2174 ExFreePoolWithTag(BusInformation, 0);
2175 }
2176 else
2177 {
2178 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2179
2180 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2181 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2182 DeviceNode->ChildBusTypeIndex = -1;
2183 }
2184
2185 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2186
2187 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2188 &IoStatusBlock,
2189 IRP_MN_QUERY_RESOURCES,
2190 NULL);
2191 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2192 {
2193 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2194 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2195 }
2196 else
2197 {
2198 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2199 DeviceNode->BootResources = NULL;
2200 }
2201
2202 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2203
2204 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2205 &IoStatusBlock,
2206 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2207 NULL);
2208 if (NT_SUCCESS(Status))
2209 {
2210 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2211 }
2212 else
2213 {
2214 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2215 DeviceNode->ResourceRequirements = NULL;
2216 }
2217
2218 if (InstanceKey != NULL)
2219 {
2220 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2221 }
2222
2223 ZwClose(InstanceKey);
2224
2225 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2226
2227 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2228 {
2229 /* Report the device to the user-mode pnp manager */
2230 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2231 &DeviceNode->InstancePath);
2232 }
2233
2234 return STATUS_SUCCESS;
2235 }
2236
2237 static
2238 VOID
2239 IopHandleDeviceRemoval(
2240 IN PDEVICE_NODE DeviceNode,
2241 IN PDEVICE_RELATIONS DeviceRelations)
2242 {
2243 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2244 ULONG i;
2245 BOOLEAN Found;
2246
2247 if (DeviceNode == IopRootDeviceNode)
2248 return;
2249
2250 while (Child != NULL)
2251 {
2252 NextChild = Child->Sibling;
2253 Found = FALSE;
2254
2255 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
2256 {
2257 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
2258 {
2259 Found = TRUE;
2260 break;
2261 }
2262 }
2263
2264 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
2265 {
2266 /* Send removal IRPs to all of its children */
2267 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
2268
2269 /* Send the surprise removal IRP */
2270 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
2271
2272 /* Tell the user-mode PnP manager that a device was removed */
2273 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
2274 &Child->InstancePath);
2275
2276 /* Send the remove device IRP */
2277 IopSendRemoveDevice(Child->PhysicalDeviceObject);
2278 }
2279
2280 Child = NextChild;
2281 }
2282 }
2283
2284 NTSTATUS
2285 IopEnumerateDevice(
2286 IN PDEVICE_OBJECT DeviceObject)
2287 {
2288 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2289 DEVICETREE_TRAVERSE_CONTEXT Context;
2290 PDEVICE_RELATIONS DeviceRelations;
2291 PDEVICE_OBJECT ChildDeviceObject;
2292 IO_STATUS_BLOCK IoStatusBlock;
2293 PDEVICE_NODE ChildDeviceNode;
2294 IO_STACK_LOCATION Stack;
2295 NTSTATUS Status;
2296 ULONG i;
2297
2298 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2299
2300 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
2301 {
2302 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
2303
2304 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2305 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2306 &DeviceNode->InstancePath);
2307 }
2308
2309 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2310
2311 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2312
2313 Status = IopInitiatePnpIrp(
2314 DeviceObject,
2315 &IoStatusBlock,
2316 IRP_MN_QUERY_DEVICE_RELATIONS,
2317 &Stack);
2318 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2319 {
2320 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2321 return Status;
2322 }
2323
2324 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2325
2326 /*
2327 * Send removal IRPs for devices that have disappeared
2328 * NOTE: This code handles the case where no relations are specified
2329 */
2330 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2331
2332 /* Now we bail if nothing was returned */
2333 if (!DeviceRelations)
2334 {
2335 /* We're all done */
2336 DPRINT("No PDOs\n");
2337 return STATUS_SUCCESS;
2338 }
2339
2340 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2341
2342 /*
2343 * Create device nodes for all discovered devices
2344 */
2345 for (i = 0; i < DeviceRelations->Count; i++)
2346 {
2347 ChildDeviceObject = DeviceRelations->Objects[i];
2348 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2349
2350 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2351 if (!ChildDeviceNode)
2352 {
2353 /* One doesn't exist, create it */
2354 Status = IopCreateDeviceNode(
2355 DeviceNode,
2356 ChildDeviceObject,
2357 NULL,
2358 &ChildDeviceNode);
2359 if (NT_SUCCESS(Status))
2360 {
2361 /* Mark the node as enumerated */
2362 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2363
2364 /* Mark the DO as bus enumerated */
2365 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2366 }
2367 else
2368 {
2369 /* Ignore this DO */
2370 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2371 ObDereferenceObject(ChildDeviceObject);
2372 }
2373 }
2374 else
2375 {
2376 /* Mark it as enumerated */
2377 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2378 ObDereferenceObject(ChildDeviceObject);
2379 }
2380 }
2381 ExFreePool(DeviceRelations);
2382
2383 /*
2384 * Retrieve information about all discovered children from the bus driver
2385 */
2386 IopInitDeviceTreeTraverseContext(
2387 &Context,
2388 DeviceNode,
2389 IopActionInterrogateDeviceStack,
2390 DeviceNode);
2391
2392 Status = IopTraverseDeviceTree(&Context);
2393 if (!NT_SUCCESS(Status))
2394 {
2395 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2396 return Status;
2397 }
2398
2399 /*
2400 * Retrieve configuration from the registry for discovered children
2401 */
2402 IopInitDeviceTreeTraverseContext(
2403 &Context,
2404 DeviceNode,
2405 IopActionConfigureChildServices,
2406 DeviceNode);
2407
2408 Status = IopTraverseDeviceTree(&Context);
2409 if (!NT_SUCCESS(Status))
2410 {
2411 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2412 return Status;
2413 }
2414
2415 /*
2416 * Initialize services for discovered children.
2417 */
2418 Status = IopInitializePnpServices(DeviceNode);
2419 if (!NT_SUCCESS(Status))
2420 {
2421 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2422 return Status;
2423 }
2424
2425 DPRINT("IopEnumerateDevice() finished\n");
2426 return STATUS_SUCCESS;
2427 }
2428
2429
2430 /*
2431 * IopActionConfigureChildServices
2432 *
2433 * Retrieve configuration for all (direct) child nodes of a parent node.
2434 *
2435 * Parameters
2436 * DeviceNode
2437 * Pointer to device node.
2438 * Context
2439 * Pointer to parent node to retrieve child node configuration for.
2440 *
2441 * Remarks
2442 * Any errors that occur are logged instead so that all child services have a chance of beeing
2443 * configured.
2444 */
2445
2446 NTSTATUS
2447 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2448 PVOID Context)
2449 {
2450 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2451 PDEVICE_NODE ParentDeviceNode;
2452 PUNICODE_STRING Service;
2453 UNICODE_STRING ClassGUID;
2454 NTSTATUS Status;
2455 DEVICE_CAPABILITIES DeviceCaps;
2456
2457 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2458
2459 ParentDeviceNode = (PDEVICE_NODE)Context;
2460
2461 /*
2462 * We are called for the parent too, but we don't need to do special
2463 * handling for this node
2464 */
2465 if (DeviceNode == ParentDeviceNode)
2466 {
2467 DPRINT("Success\n");
2468 return STATUS_SUCCESS;
2469 }
2470
2471 /*
2472 * Make sure this device node is a direct child of the parent device node
2473 * that is given as an argument
2474 */
2475
2476 if (DeviceNode->Parent != ParentDeviceNode)
2477 {
2478 DPRINT("Skipping 2+ level child\n");
2479 return STATUS_SUCCESS;
2480 }
2481
2482 if (!(DeviceNode->Flags & DNF_PROCESSED))
2483 {
2484 DPRINT1("Child not ready to be configured\n");
2485 return STATUS_SUCCESS;
2486 }
2487
2488 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2489 {
2490 WCHAR RegKeyBuffer[MAX_PATH];
2491 UNICODE_STRING RegKey;
2492
2493 /* Install the service for this if it's in the CDDB */
2494 IopInstallCriticalDevice(DeviceNode);
2495
2496 RegKey.Length = 0;
2497 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2498 RegKey.Buffer = RegKeyBuffer;
2499
2500 /*
2501 * Retrieve configuration from Enum key
2502 */
2503
2504 Service = &DeviceNode->ServiceName;
2505
2506 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2507 RtlInitUnicodeString(Service, NULL);
2508 RtlInitUnicodeString(&ClassGUID, NULL);
2509
2510 QueryTable[0].Name = L"Service";
2511 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2512 QueryTable[0].EntryContext = Service;
2513
2514 QueryTable[1].Name = L"ClassGUID";
2515 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2516 QueryTable[1].EntryContext = &ClassGUID;
2517 QueryTable[1].DefaultType = REG_SZ;
2518 QueryTable[1].DefaultData = L"";
2519 QueryTable[1].DefaultLength = 0;
2520
2521 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2522 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2523
2524 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2525 RegKey.Buffer, QueryTable, NULL, NULL);
2526
2527 if (!NT_SUCCESS(Status))
2528 {
2529 /* FIXME: Log the error */
2530 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2531 &DeviceNode->InstancePath, Status);
2532 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2533 return STATUS_SUCCESS;
2534 }
2535
2536 if (Service->Buffer == NULL)
2537 {
2538 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2539 DeviceCaps.RawDeviceOK)
2540 {
2541 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2542
2543 DeviceNode->ServiceName.Length = 0;
2544 DeviceNode->ServiceName.MaximumLength = 0;
2545 DeviceNode->ServiceName.Buffer = NULL;
2546 }
2547 else if (ClassGUID.Length != 0)
2548 {
2549 /* Device has a ClassGUID value, but no Service value.
2550 * Suppose it is using the NULL driver, so state the
2551 * device is started */
2552 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2553 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2554 }
2555 else
2556 {
2557 DeviceNode->Problem = CM_PROB_FAILED_INSTALL;
2558 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2559 }
2560 return STATUS_SUCCESS;
2561 }
2562
2563 DPRINT("Got Service %S\n", Service->Buffer);
2564 }
2565
2566 return STATUS_SUCCESS;
2567 }
2568
2569 /*
2570 * IopActionInitChildServices
2571 *
2572 * Initialize the service for all (direct) child nodes of a parent node
2573 *
2574 * Parameters
2575 * DeviceNode
2576 * Pointer to device node.
2577 * Context
2578 * Pointer to parent node to initialize child node services for.
2579 *
2580 * Remarks
2581 * If the driver image for a service is not loaded and initialized
2582 * it is done here too. Any errors that occur are logged instead so
2583 * that all child services have a chance of being initialized.
2584 */
2585
2586 NTSTATUS
2587 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2588 PVOID Context)
2589 {
2590 PDEVICE_NODE ParentDeviceNode;
2591 NTSTATUS Status;
2592 BOOLEAN BootDrivers = !PnpSystemInit;
2593
2594 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2595
2596 ParentDeviceNode = Context;
2597
2598 /*
2599 * We are called for the parent too, but we don't need to do special
2600 * handling for this node
2601 */
2602 if (DeviceNode == ParentDeviceNode)
2603 {
2604 DPRINT("Success\n");
2605 return STATUS_SUCCESS;
2606 }
2607
2608 /*
2609 * We don't want to check for a direct child because
2610 * this function is called during boot to reinitialize
2611 * devices with drivers that couldn't load yet due to
2612 * stage 0 limitations (ie can't load from disk yet).
2613 */
2614
2615 if (!(DeviceNode->Flags & DNF_PROCESSED))
2616 {
2617 DPRINT1("Child not ready to be added\n");
2618 return STATUS_SUCCESS;
2619 }
2620
2621 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2622 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2623 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2624 return STATUS_SUCCESS;
2625
2626 if (DeviceNode->ServiceName.Buffer == NULL)
2627 {
2628 /* We don't need to worry about loading the driver because we're
2629 * being driven in raw mode so our parent must be loaded to get here */
2630 Status = IopInitializeDevice(DeviceNode, NULL);
2631 if (NT_SUCCESS(Status))
2632 {
2633 Status = IopStartDevice(DeviceNode);
2634 if (!NT_SUCCESS(Status))
2635 {
2636 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2637 &DeviceNode->InstancePath, Status);
2638 }
2639 }
2640 }
2641 else
2642 {
2643 PLDR_DATA_TABLE_ENTRY ModuleObject;
2644 PDRIVER_OBJECT DriverObject;
2645
2646 KeEnterCriticalRegion();
2647 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
2648 /* Get existing DriverObject pointer (in case the driver has
2649 already been loaded and initialized) */
2650 Status = IopGetDriverObject(
2651 &DriverObject,
2652 &DeviceNode->ServiceName,
2653 FALSE);
2654
2655 if (!NT_SUCCESS(Status))
2656 {
2657 /* Driver is not initialized, try to load it */
2658 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2659
2660 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2661 {
2662 /* Initialize the driver */
2663 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2664 &DeviceNode->ServiceName, FALSE, &DriverObject);
2665 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY;
2666 }
2667 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD)
2668 {
2669 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
2670 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE;
2671 }
2672 else
2673 {
2674 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2675 &DeviceNode->ServiceName, Status);
2676 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
2677 }
2678 }
2679 ExReleaseResourceLite(&IopDriverLoadResource);
2680 KeLeaveCriticalRegion();
2681
2682 /* Driver is loaded and initialized at this point */
2683 if (NT_SUCCESS(Status))
2684 {
2685 /* Initialize the device, including all filters */
2686 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2687
2688 /* Remove the extra reference */
2689 ObDereferenceObject(DriverObject);
2690 }
2691 else
2692 {
2693 /*
2694 * Don't disable when trying to load only boot drivers
2695 */
2696 if (!BootDrivers)
2697 {
2698 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2699 }
2700 }
2701 }
2702
2703 return STATUS_SUCCESS;
2704 }
2705
2706 /*
2707 * IopInitializePnpServices
2708 *
2709 * Initialize services for discovered children
2710 *
2711 * Parameters
2712 * DeviceNode
2713 * Top device node to start initializing services.
2714 *
2715 * Return Value
2716 * Status
2717 */
2718 NTSTATUS
2719 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2720 {
2721 DEVICETREE_TRAVERSE_CONTEXT Context;
2722
2723 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2724
2725 IopInitDeviceTreeTraverseContext(
2726 &Context,
2727 DeviceNode,
2728 IopActionInitChildServices,
2729 DeviceNode);
2730
2731 return IopTraverseDeviceTree(&Context);
2732 }
2733
2734 static NTSTATUS INIT_FUNCTION
2735 IopEnumerateDetectedDevices(
2736 IN HANDLE hBaseKey,
2737 IN PUNICODE_STRING RelativePath OPTIONAL,
2738 IN HANDLE hRootKey,
2739 IN BOOLEAN EnumerateSubKeys,
2740 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2741 IN ULONG ParentBootResourcesLength)
2742 {
2743 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2744 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2745 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2746 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2747 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2748 OBJECT_ATTRIBUTES ObjectAttributes;
2749 HANDLE hDevicesKey = NULL;
2750 HANDLE hDeviceKey = NULL;
2751 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2752 UNICODE_STRING Level2NameU;
2753 WCHAR Level2Name[5];
2754 ULONG IndexDevice = 0;
2755 ULONG IndexSubKey;
2756 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2757 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2758 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2759 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2760 UNICODE_STRING DeviceName, ValueName;
2761 ULONG RequiredSize;
2762 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2763 ULONG BootResourcesLength;
2764 NTSTATUS Status;
2765
2766 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2767 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2768 static ULONG DeviceIndexSerial = 0;
2769 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2770 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2771 static ULONG DeviceIndexKeyboard = 0;
2772 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2773 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2774 static ULONG DeviceIndexMouse = 0;
2775 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2776 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2777 static ULONG DeviceIndexParallel = 0;
2778 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2779 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2780 static ULONG DeviceIndexFloppy = 0;
2781 UNICODE_STRING HardwareIdKey;
2782 PUNICODE_STRING pHardwareId;
2783 ULONG DeviceIndex = 0;
2784 PUCHAR CmResourceList;
2785 ULONG ListCount;
2786
2787 if (RelativePath)
2788 {
2789 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2790 if (!NT_SUCCESS(Status))
2791 {
2792 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2793 goto cleanup;
2794 }
2795 }
2796 else
2797 hDevicesKey = hBaseKey;
2798
2799 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2800 if (!pDeviceInformation)
2801 {
2802 DPRINT("ExAllocatePool() failed\n");
2803 Status = STATUS_NO_MEMORY;
2804 goto cleanup;
2805 }
2806
2807 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2808 if (!pValueInformation)
2809 {
2810 DPRINT("ExAllocatePool() failed\n");
2811 Status = STATUS_NO_MEMORY;
2812 goto cleanup;
2813 }
2814
2815 while (TRUE)
2816 {
2817 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2818 if (Status == STATUS_NO_MORE_ENTRIES)
2819 break;
2820 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2821 {
2822 ExFreePool(pDeviceInformation);
2823 DeviceInfoLength = RequiredSize;
2824 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2825 if (!pDeviceInformation)
2826 {
2827 DPRINT("ExAllocatePool() failed\n");
2828 Status = STATUS_NO_MEMORY;
2829 goto cleanup;
2830 }
2831 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2832 }
2833 if (!NT_SUCCESS(Status))
2834 {
2835 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2836 goto cleanup;
2837 }
2838 IndexDevice++;
2839
2840 /* Open device key */
2841 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2842 DeviceName.Buffer = pDeviceInformation->Name;
2843
2844 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
2845 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
2846 if (!NT_SUCCESS(Status))
2847 {
2848 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2849 goto cleanup;
2850 }
2851
2852 /* Read boot resources, and add then to parent ones */
2853 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2854 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2855 {
2856 ExFreePool(pValueInformation);
2857 ValueInfoLength = RequiredSize;
2858 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2859 if (!pValueInformation)
2860 {
2861 DPRINT("ExAllocatePool() failed\n");
2862 ZwDeleteKey(hLevel2Key);
2863 Status = STATUS_NO_MEMORY;
2864 goto cleanup;
2865 }
2866 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2867 }
2868 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2869 {
2870 BootResources = ParentBootResources;
2871 BootResourcesLength = ParentBootResourcesLength;
2872 }
2873 else if (!NT_SUCCESS(Status))
2874 {
2875 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2876 goto nextdevice;
2877 }
2878 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2879 {
2880 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2881 goto nextdevice;
2882 }
2883 else
2884 {
2885 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2886
2887 /* Concatenate current resources and parent ones */
2888 if (ParentBootResourcesLength == 0)
2889 BootResourcesLength = pValueInformation->DataLength;
2890 else
2891 BootResourcesLength = ParentBootResourcesLength
2892 + pValueInformation->DataLength
2893 - Header;
2894 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2895 if (!BootResources)
2896 {
2897 DPRINT("ExAllocatePool() failed\n");
2898 goto nextdevice;
2899 }
2900 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2901 {
2902 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2903 }
2904 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2905 {
2906 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2907 RtlCopyMemory(
2908 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2909 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2910 ParentBootResourcesLength - Header);
2911 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2912 }
2913 else
2914 {
2915 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2916 RtlCopyMemory(
2917 (PVOID)((ULONG_PTR)BootResources + Header),
2918 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2919 ParentBootResourcesLength - Header);
2920 RtlCopyMemory(
2921 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2922 pValueInformation->Data + Header,
2923 pValueInformation->DataLength - Header);
2924 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2925 }
2926 }
2927
2928 if (EnumerateSubKeys)
2929 {
2930 IndexSubKey = 0;
2931 while (TRUE)
2932 {
2933 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2934 if (Status == STATUS_NO_MORE_ENTRIES)
2935 break;
2936 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2937 {
2938 ExFreePool(pDeviceInformation);
2939 DeviceInfoLength = RequiredSize;
2940 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2941 if (!pDeviceInformation)
2942 {
2943 DPRINT("ExAllocatePool() failed\n");
2944 Status = STATUS_NO_MEMORY;
2945 goto cleanup;
2946 }
2947 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2948 }
2949 if (!NT_SUCCESS(Status))
2950 {
2951 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2952 goto cleanup;
2953 }
2954 IndexSubKey++;
2955 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2956 DeviceName.Buffer = pDeviceInformation->Name;
2957
2958 Status = IopEnumerateDetectedDevices(
2959 hDeviceKey,
2960 &DeviceName,
2961 hRootKey,
2962 TRUE,
2963 BootResources,
2964 BootResourcesLength);
2965 if (!NT_SUCCESS(Status))
2966 goto cleanup;
2967 }
2968 }
2969
2970 /* Read identifier */
2971 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2972 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2973 {
2974 ExFreePool(pValueInformation);
2975 ValueInfoLength = RequiredSize;
2976 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2977 if (!pValueInformation)
2978 {
2979 DPRINT("ExAllocatePool() failed\n");
2980 Status = STATUS_NO_MEMORY;
2981 goto cleanup;
2982 }
2983 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2984 }
2985 if (!NT_SUCCESS(Status))
2986 {
2987 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2988 {
2989 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2990 goto nextdevice;
2991 }
2992 ValueName.Length = ValueName.MaximumLength = 0;
2993 }
2994 else if (pValueInformation->Type != REG_SZ)
2995 {
2996 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2997 goto nextdevice;
2998 }
2999 else
3000 {
3001 /* Assign hardware id to this device */
3002 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3003 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3004 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3005 ValueName.Length -= sizeof(WCHAR);
3006 }
3007
3008 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3009 {
3010 pHardwareId = &HardwareIdSerial;
3011 DeviceIndex = DeviceIndexSerial++;
3012 }
3013 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3014 {
3015 pHardwareId = &HardwareIdKeyboard;
3016 DeviceIndex = DeviceIndexKeyboard++;
3017 }
3018 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3019 {
3020 pHardwareId = &HardwareIdMouse;
3021 DeviceIndex = DeviceIndexMouse++;
3022 }
3023 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3024 {
3025 pHardwareId = &HardwareIdParallel;
3026 DeviceIndex = DeviceIndexParallel++;
3027 }
3028 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3029 {
3030 pHardwareId = &HardwareIdFloppy;
3031 DeviceIndex = DeviceIndexFloppy++;
3032 }
3033 else
3034 {
3035 /* Unknown key path */
3036 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3037 goto nextdevice;
3038 }
3039
3040 /* Prepare hardware id key (hardware id value without final \0) */
3041 HardwareIdKey = *pHardwareId;
3042 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3043
3044 /* Add the detected device to Root key */
3045 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3046 Status = ZwCreateKey(
3047 &hLevel1Key,
3048 KEY_CREATE_SUB_KEY,
3049 &ObjectAttributes,
3050 0,
3051 NULL,
3052 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3053 NULL);
3054 if (!NT_SUCCESS(Status))
3055 {
3056 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3057 goto nextdevice;
3058 }
3059 swprintf(Level2Name, L"%04lu", DeviceIndex);
3060 RtlInitUnicodeString(&Level2NameU, Level2Name);
3061 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3062 Status = ZwCreateKey(
3063 &hLevel2Key,
3064 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3065 &ObjectAttributes,
3066 0,
3067 NULL,
3068 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3069 NULL);
3070 ZwClose(hLevel1Key);
3071 if (!NT_SUCCESS(Status))
3072 {
3073 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3074 goto nextdevice;
3075 }
3076 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3077 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3078 if (!NT_SUCCESS(Status))
3079 {
3080 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3081 ZwDeleteKey(hLevel2Key);
3082 goto nextdevice;
3083 }
3084 /* Create 'LogConf' subkey */
3085 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3086 Status = ZwCreateKey(
3087 &hLogConf,
3088 KEY_SET_VALUE,
3089 &ObjectAttributes,
3090 0,
3091 NULL,
3092 REG_OPTION_VOLATILE,
3093 NULL);
3094 if (!NT_SUCCESS(Status))
3095 {
3096 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3097 ZwDeleteKey(hLevel2Key);
3098 goto nextdevice;
3099 }
3100 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3101 {
3102 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3103 if (!CmResourceList)
3104 {
3105 ZwClose(hLogConf);
3106 ZwDeleteKey(hLevel2Key);
3107 goto nextdevice;
3108 }
3109
3110 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3111 ListCount = 1;
3112 RtlCopyMemory(CmResourceList,
3113 &ListCount,
3114 sizeof(ULONG));
3115
3116 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3117 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3118 BootResources,
3119 BootResourcesLength);
3120
3121 /* Save boot resources to 'LogConf\BootConfig' */
3122 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3123 if (!NT_SUCCESS(Status))
3124 {
3125 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3126 ZwClose(hLogConf);
3127 ZwDeleteKey(hLevel2Key);
3128 goto nextdevice;
3129 }
3130 }
3131 ZwClose(hLogConf);
3132
3133 nextdevice:
3134 if (BootResources && BootResources != ParentBootResources)
3135 {
3136 ExFreePool(BootResources);
3137 BootResources = NULL;
3138 }
3139 if (hLevel2Key)
3140 {
3141 ZwClose(hLevel2Key);
3142 hLevel2Key = NULL;
3143 }
3144 if (hDeviceKey)
3145 {
3146 ZwClose(hDeviceKey);
3147 hDeviceKey = NULL;
3148 }
3149 }
3150
3151 Status = STATUS_SUCCESS;
3152
3153 cleanup:
3154 if (hDevicesKey && hDevicesKey != hBaseKey)
3155 ZwClose(hDevicesKey);
3156 if (hDeviceKey)
3157 ZwClose(hDeviceKey);
3158 if (pDeviceInformation)
3159 ExFreePool(pDeviceInformation);
3160 if (pValueInformation)
3161 ExFreePool(pValueInformation);
3162 return Status;
3163 }
3164
3165 static BOOLEAN INIT_FUNCTION
3166 IopIsFirmwareMapperDisabled(VOID)
3167 {
3168 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3169 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3170 OBJECT_ATTRIBUTES ObjectAttributes;
3171 HANDLE hPnpKey;
3172 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3173 ULONG DesiredLength, Length;
3174 ULONG KeyValue = 0;
3175 NTSTATUS Status;
3176
3177 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3178 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3179 if (NT_SUCCESS(Status))
3180 {
3181 Status = ZwQueryValueKey(hPnpKey,
3182 &KeyNameU,
3183 KeyValuePartialInformation,
3184 NULL,
3185 0,
3186 &DesiredLength);
3187 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3188 (Status == STATUS_BUFFER_OVERFLOW))
3189 {
3190 Length = DesiredLength;
3191 KeyInformation = ExAllocatePool(PagedPool, Length);
3192 if (KeyInformation)
3193 {
3194 Status = ZwQueryValueKey(hPnpKey,
3195 &KeyNameU,
3196 KeyValuePartialInformation,
3197 KeyInformation,
3198 Length,
3199 &DesiredLength);
3200 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3201 {
3202 KeyValue = (ULONG)(*KeyInformation->Data);
3203 }
3204 else
3205 {
3206 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3207 }
3208
3209 ExFreePool(KeyInformation);
3210 }
3211 else
3212 {
3213 DPRINT1("Failed to allocate memory for registry query\n");
3214 }
3215 }
3216 else
3217 {
3218 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3219 }
3220
3221 ZwClose(hPnpKey);
3222 }
3223 else
3224 {
3225 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3226 }
3227
3228 DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3229
3230 return (KeyValue != 0) ? TRUE : FALSE;
3231 }
3232
3233 NTSTATUS
3234 NTAPI
3235 INIT_FUNCTION
3236 IopUpdateRootKey(VOID)
3237 {
3238 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3239 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3240 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3241 OBJECT_ATTRIBUTES ObjectAttributes;
3242 HANDLE hEnum, hRoot;
3243 NTSTATUS Status;
3244
3245 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3246 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3247 if (!NT_SUCCESS(Status))
3248 {
3249 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3250 return Status;
3251 }
3252
3253 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3254 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3255 ZwClose(hEnum);
3256 if (!NT_SUCCESS(Status))
3257 {
3258 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3259 return Status;
3260 }
3261
3262 if (!IopIsFirmwareMapperDisabled())
3263 {
3264 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3265 if (!NT_SUCCESS(Status))
3266 {
3267 /* Nothing to do, don't return with an error status */
3268 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3269 ZwClose(hRoot);
3270 return STATUS_SUCCESS;
3271 }
3272 Status = IopEnumerateDetectedDevices(
3273 hEnum,
3274 NULL,
3275 hRoot,
3276 TRUE,
3277 NULL,
3278 0);
3279 ZwClose(hEnum);
3280 }
3281 else
3282 {
3283 /* Enumeration is disabled */
3284 Status = STATUS_SUCCESS;
3285 }
3286
3287 ZwClose(hRoot);
3288
3289 return Status;
3290 }
3291
3292 NTSTATUS
3293 NTAPI
3294 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3295 HANDLE ParentKey,
3296 PUNICODE_STRING Name,
3297 ACCESS_MASK DesiredAccess)
3298 {
3299 OBJECT_ATTRIBUTES ObjectAttributes;
3300 NTSTATUS Status;
3301
3302 PAGED_CODE();
3303
3304 *KeyHandle = NULL;
3305
3306 InitializeObjectAttributes(&ObjectAttributes,
3307 Name,
3308 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3309 ParentKey,
3310 NULL);
3311
3312 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3313
3314 return Status;
3315 }
3316
3317 NTSTATUS
3318 NTAPI
3319 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3320 IN HANDLE RootHandle OPTIONAL,
3321 IN PUNICODE_STRING KeyName,
3322 IN ACCESS_MASK DesiredAccess,
3323 IN ULONG CreateOptions,
3324 OUT PULONG Disposition OPTIONAL)
3325 {
3326 OBJECT_ATTRIBUTES ObjectAttributes;
3327 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3328 USHORT Length;
3329 HANDLE HandleArray[2];
3330 BOOLEAN Recursing = TRUE;
3331 PWCHAR pp, p, p1;
3332 UNICODE_STRING KeyString;
3333 NTSTATUS Status = STATUS_SUCCESS;
3334 PAGED_CODE();
3335
3336 /* P1 is start, pp is end */
3337 p1 = KeyName->Buffer;
3338 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3339
3340 /* Create the target key */
3341 InitializeObjectAttributes(&ObjectAttributes,
3342 KeyName,
3343 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3344 RootHandle,
3345 NULL);
3346 Status = ZwCreateKey(&HandleArray[i],
3347 DesiredAccess,
3348 &ObjectAttributes,
3349 0,
3350 NULL,
3351 CreateOptions,
3352 &KeyDisposition);
3353
3354 /* Now we check if this failed */
3355 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3356 {
3357 /* Target key failed, so we'll need to create its parent. Setup array */
3358 HandleArray[0] = NULL;
3359 HandleArray[1] = RootHandle;
3360
3361 /* Keep recursing for each missing parent */
3362 while (Recursing)
3363 {
3364 /* And if we're deep enough, close the last handle */
3365 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3366
3367 /* We're setup to ping-pong between the two handle array entries */
3368 RootHandleIndex = i;
3369 i = (i + 1) & 1;
3370
3371 /* Clear the one we're attempting to open now */
3372 HandleArray[i] = NULL;
3373
3374 /* Process the parent key name */
3375 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3376 Length = (USHORT)(p - p1) * sizeof(WCHAR);
3377
3378 /* Is there a parent name? */
3379 if (Length)
3380 {
3381 /* Build the unicode string for it */
3382 KeyString.Buffer = p1;
3383 KeyString.Length = KeyString.MaximumLength = Length;
3384
3385 /* Now try opening the parent */
3386 InitializeObjectAttributes(&ObjectAttributes,
3387 &KeyString,
3388 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3389 HandleArray[RootHandleIndex],
3390 NULL);
3391 Status = ZwCreateKey(&HandleArray[i],
3392 DesiredAccess,
3393 &ObjectAttributes,
3394 0,
3395 NULL,
3396 CreateOptions,
3397 &KeyDisposition);
3398 if (NT_SUCCESS(Status))
3399 {
3400 /* It worked, we have one more handle */
3401 NestedCloseLevel++;
3402 }
3403 else
3404 {
3405 /* Parent key creation failed, abandon loop */
3406 Recursing = FALSE;
3407 continue;
3408 }
3409 }
3410 else
3411 {
3412 /* We don't have a parent name, probably corrupted key name */
3413 Status = STATUS_INVALID_PARAMETER;
3414 Recursing = FALSE;
3415 continue;
3416 }
3417
3418 /* Now see if there's more parents to create */
3419 p1 = p + 1;
3420 if ((p == pp) || (p1 == pp))
3421 {
3422 /* We're done, hopefully successfully, so stop */
3423 Recursing = FALSE;
3424 }
3425 }
3426
3427 /* Outer loop check for handle nesting that requires closing the top handle */
3428 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3429 }
3430
3431 /* Check if we broke out of the loop due to success */
3432 if (NT_SUCCESS(Status))
3433 {
3434 /* Return the target handle (we closed all the parent ones) and disposition */
3435 *Handle = HandleArray[i];
3436 if (Disposition) *Disposition = KeyDisposition;
3437 }
3438
3439 /* Return the success state */
3440 return Status;
3441 }
3442
3443 NTSTATUS
3444 NTAPI
3445 IopGetRegistryValue(IN HANDLE Handle,
3446 IN PWSTR ValueName,
3447 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3448 {
3449 UNICODE_STRING ValueString;
3450 NTSTATUS Status;
3451 PKEY_VALUE_FULL_INFORMATION FullInformation;
3452 ULONG Size;
3453 PAGED_CODE();
3454
3455 RtlInitUnicodeString(&ValueString, ValueName);
3456
3457 Status = ZwQueryValueKey(Handle,
3458 &ValueString,
3459 KeyValueFullInformation,
3460 NULL,
3461 0,
3462 &Size);
3463 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3464 (Status != STATUS_BUFFER_TOO_SMALL))
3465 {
3466 return Status;
3467 }
3468
3469 FullInformation = ExAllocatePool(NonPagedPool, Size);
3470 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3471
3472 Status = ZwQueryValueKey(Handle,
3473 &ValueString,
3474 KeyValueFullInformation,
3475 FullInformation,
3476 Size,
3477 &Size);
3478 if (!NT_SUCCESS(Status))
3479 {
3480 ExFreePool(FullInformation);
3481 return Status;
3482 }
3483
3484 *Information = FullInformation;
3485 return STATUS_SUCCESS;
3486 }
3487
3488 RTL_GENERIC_COMPARE_RESULTS
3489 NTAPI
3490 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3491 IN PVOID FirstStruct,
3492 IN PVOID SecondStruct)
3493 {
3494 /* FIXME: TODO */
3495 ASSERT(FALSE);
3496 return 0;
3497 }
3498
3499 //
3500 // The allocation function is called by the generic table package whenever
3501 // it needs to allocate memory for the table.
3502 //
3503
3504 PVOID
3505 NTAPI
3506 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3507 IN CLONG ByteSize)
3508 {
3509 /* FIXME: TODO */
3510 ASSERT(FALSE);
3511 return NULL;
3512 }
3513
3514 VOID
3515 NTAPI
3516 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3517 IN PVOID Buffer)
3518 {
3519 /* FIXME: TODO */
3520 ASSERT(FALSE);
3521 }
3522
3523 VOID
3524 NTAPI
3525 PpInitializeDeviceReferenceTable(VOID)
3526 {
3527 /* Setup the guarded mutex and AVL table */
3528 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3529 RtlInitializeGenericTableAvl(
3530 &PpDeviceReferenceTable,
3531 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3532 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3533 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3534 NULL);
3535 }
3536
3537 BOOLEAN
3538 NTAPI
3539 PiInitPhase0(VOID)
3540 {
3541 /* Initialize the resource when accessing device registry data */
3542 ExInitializeResourceLite(&PpRegistryDeviceResource);
3543
3544 /* Setup the device reference AVL table */
3545 PpInitializeDeviceReferenceTable();
3546 return TRUE;
3547 }
3548
3549 BOOLEAN
3550 NTAPI
3551 PpInitSystem(VOID)
3552 {
3553 /* Check the initialization phase */
3554 switch (ExpInitializationPhase)
3555 {
3556 case 0:
3557
3558 /* Do Phase 0 */
3559 return PiInitPhase0();
3560
3561 case 1:
3562
3563 /* Do Phase 1 */
3564 return TRUE;
3565 //return PiInitPhase1();
3566
3567 default:
3568
3569 /* Don't know any other phase! Bugcheck! */
3570 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3571 return FALSE;
3572 }
3573 }
3574
3575 LONG IopNumberDeviceNodes;
3576
3577 PDEVICE_NODE
3578 NTAPI
3579 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
3580 {
3581 PDEVICE_NODE DeviceNode;
3582 PAGED_CODE();
3583
3584 /* Allocate it */
3585 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE);
3586 if (!DeviceNode) return DeviceNode;
3587
3588 /* Statistics */
3589 InterlockedIncrement(&IopNumberDeviceNodes);
3590
3591 /* Set it up */
3592 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3593 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3594 DeviceNode->BusNumber = -1;
3595 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3596 DeviceNode->ChildBusNumber = -1;
3597 DeviceNode->ChildBusTypeIndex = -1;
3598 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3599 InitializeListHead(&DeviceNode->DeviceArbiterList);
3600 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3601 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3602 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3603 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3604
3605 /* Check if there is a PDO */
3606 if (PhysicalDeviceObject)
3607 {
3608 /* Link it and remove the init flag */
3609 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3610 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3611 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3612 }
3613
3614 /* Return the node */
3615 return DeviceNode;
3616 }
3617
3618 /* PUBLIC FUNCTIONS **********************************************************/
3619
3620 NTSTATUS
3621 NTAPI
3622 PnpBusTypeGuidGet(IN USHORT Index,
3623 IN LPGUID BusTypeGuid)
3624 {
3625 NTSTATUS Status = STATUS_SUCCESS;
3626
3627 /* Acquire the lock */
3628 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3629
3630 /* Validate size */
3631 if (Index < PnpBusTypeGuidList->GuidCount)
3632 {
3633 /* Copy the data */
3634 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3635 }
3636 else
3637 {
3638 /* Failure path */
3639 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3640 }
3641
3642 /* Release lock and return status */
3643 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3644 return Status;
3645 }
3646
3647 NTSTATUS
3648 NTAPI
3649 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3650 IN PHANDLE DeviceInstanceHandle,
3651 IN ACCESS_MASK DesiredAccess)
3652 {
3653 NTSTATUS Status;
3654 HANDLE KeyHandle;
3655 PDEVICE_NODE DeviceNode;
3656 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3657 PAGED_CODE();
3658
3659 /* Open the enum key */
3660 Status = IopOpenRegistryKeyEx(&KeyHandle,
3661 NULL,
3662 &KeyName,
3663 KEY_READ);
3664 if (!NT_SUCCESS(Status)) return Status;
3665
3666 /* Make sure we have an instance path */
3667 DeviceNode = IopGetDeviceNode(DeviceObject);
3668 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3669 {
3670 /* Get the instance key */
3671 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3672 KeyHandle,
3673 &DeviceNode->InstancePath,
3674 DesiredAccess);
3675 }
3676 else
3677 {
3678 /* Fail */
3679 Status = STATUS_INVALID_DEVICE_REQUEST;
3680 }
3681
3682 /* Close the handle and return status */
3683 ZwClose(KeyHandle);
3684 return Status;
3685 }
3686
3687 ULONG
3688 NTAPI
3689 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3690 {
3691 ULONG FinalSize, PartialSize, EntrySize, i, j;
3692 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3693 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3694
3695 /* If we don't have one, that's easy */
3696 if (!ResourceList) return 0;
3697
3698 /* Start with the minimum size possible */
3699 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3700
3701 /* Loop each full descriptor */
3702 FullDescriptor = ResourceList->List;
3703 for (i = 0; i < ResourceList->Count; i++)
3704 {
3705 /* Start with the minimum size possible */
3706 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3707 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3708
3709 /* Loop each partial descriptor */
3710 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3711 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3712 {
3713 /* Start with the minimum size possible */
3714 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3715
3716 /* Check if there is extra data */
3717 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3718 {
3719 /* Add that data */
3720 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3721 }
3722
3723 /* The size of partial descriptors is bigger */
3724 PartialSize += EntrySize;
3725
3726 /* Go to the next partial descriptor */
3727 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3728 }
3729
3730 /* The size of full descriptors is bigger */
3731 FinalSize += PartialSize;
3732
3733 /* Go to the next full descriptor */
3734 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3735 }
3736
3737 /* Return the final size */
3738 return FinalSize;
3739 }
3740
3741 NTSTATUS
3742 NTAPI
3743 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3744 IN ULONG ValueType,
3745 IN PWSTR ValueName,
3746 IN PWSTR KeyName,
3747 OUT PVOID Buffer,
3748 IN PULONG BufferLength)
3749 {
3750 NTSTATUS Status;
3751 HANDLE KeyHandle, SubHandle;
3752 UNICODE_STRING KeyString;
3753 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3754 ULONG Length;
3755 PAGED_CODE();
3756
3757 /* Find the instance key */
3758 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3759 if (NT_SUCCESS(Status))
3760 {
3761 /* Check for name given by caller */
3762 if (KeyName)
3763 {
3764 /* Open this key */
3765 RtlInitUnicodeString(&KeyString, KeyName);
3766 Status = IopOpenRegistryKeyEx(&SubHandle,
3767 KeyHandle,
3768 &KeyString,
3769 KEY_READ);
3770 if (NT_SUCCESS(Status))
3771 {
3772 /* And use this handle instead */
3773 ZwClose(KeyHandle);
3774 KeyHandle = SubHandle;
3775 }
3776 }
3777
3778 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3779 if (NT_SUCCESS(Status))
3780 {
3781 /* Now get the size of the property */
3782 Status = IopGetRegistryValue(KeyHandle,
3783 ValueName,
3784 &KeyValueInfo);
3785 }
3786
3787 /* Close the key */
3788 ZwClose(KeyHandle);
3789 }
3790
3791 /* Fail if any of the registry operations failed */
3792 if (!NT_SUCCESS(Status)) return Status;
3793
3794 /* Check how much data we have to copy */
3795 Length = KeyValueInfo->DataLength;
3796 if (*BufferLength >= Length)
3797 {
3798 /* Check for a match in the value type */
3799 if (KeyValueInfo->Type == ValueType)
3800 {
3801 /* Copy the data */
3802 RtlCopyMemory(Buffer,
3803 (PVOID)((ULONG_PTR)KeyValueInfo +
3804 KeyValueInfo->DataOffset),
3805 Length);
3806 }
3807 else
3808 {
3809 /* Invalid registry property type, fail */
3810 Status = STATUS_INVALID_PARAMETER_2;
3811 }
3812 }
3813 else
3814 {
3815 /* Buffer is too small to hold data */
3816 Status = STATUS_BUFFER_TOO_SMALL;
3817 }
3818
3819 /* Return the required buffer length, free the buffer, and return status */
3820 *BufferLength = Length;
3821 ExFreePool(KeyValueInfo);
3822 return Status;
3823 }
3824
3825 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3826 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3827 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
3828
3829 /*
3830 * @implemented
3831 */
3832 NTSTATUS
3833 NTAPI
3834 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
3835 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
3836 IN ULONG BufferLength,
3837 OUT PVOID PropertyBuffer,
3838 OUT PULONG ResultLength)
3839 {
3840 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
3841 DEVICE_CAPABILITIES DeviceCaps;
3842 ULONG ReturnLength = 0, Length = 0, ValueType;
3843 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
3844 PVOID Data = NULL;
3845 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
3846 GUID BusTypeGuid;
3847 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
3848 BOOLEAN NullTerminate = FALSE;
3849
3850 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
3851
3852 /* Assume failure */
3853 *ResultLength = 0;
3854
3855 /* Only PDOs can call this */
3856 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
3857
3858 /* Handle all properties */
3859 switch (DeviceProperty)
3860 {
3861 case DevicePropertyBusTypeGuid:
3862
3863 /* Get the GUID from the internal cache */
3864 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
3865 if (!NT_SUCCESS(Status)) return Status;
3866
3867 /* This is the format of the returned data */
3868 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
3869
3870 case DevicePropertyLegacyBusType:
3871
3872 /* Validate correct interface type */
3873 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
3874 return STATUS_OBJECT_NAME_NOT_FOUND;
3875
3876 /* This is the format of the returned data */
3877 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
3878
3879 case DevicePropertyBusNumber:
3880
3881 /* Validate correct bus number */
3882 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
3883 return STATUS_OBJECT_NAME_NOT_FOUND;
3884
3885 /* This is the format of the returned data */
3886 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
3887
3888 case DevicePropertyEnumeratorName:
3889
3890 /* Get the instance path */
3891 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
3892
3893 /* Sanity checks */
3894 ASSERT((BufferLength & 1) == 0);
3895 ASSERT(DeviceInstanceName != NULL);
3896
3897 /* Get the name from the path */
3898 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
3899 ASSERT(EnumeratorNameEnd);
3900
3901 /* This string needs to be NULL-terminated */
3902 NullTerminate = TRUE;
3903
3904 /* This is the format of the returned data */
3905 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
3906 DeviceInstanceName);
3907
3908 case DevicePropertyAddress:
3909
3910 /* Query the device caps */
3911 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
3912 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
3913 return STATUS_OBJECT_NAME_NOT_FOUND;
3914
3915 /* This is the format of the returned data */
3916 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
3917
3918 case DevicePropertyBootConfigurationTranslated:
3919
3920 /* Validate we have resources */
3921 if (!DeviceNode->BootResources)
3922 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3923 {
3924 /* No resources will still fake success, but with 0 bytes */
3925 *ResultLength = 0;
3926 return STATUS_SUCCESS;
3927 }
3928
3929 /* This is the format of the returned data */
3930 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
3931 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
3932
3933 case DevicePropertyPhysicalDeviceObjectName:
3934
3935 /* Sanity check for Unicode-sized string */
3936 ASSERT((BufferLength & 1) == 0);
3937
3938 /* Allocate name buffer */
3939 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
3940 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
3941 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
3942
3943 /* Query the PDO name */
3944 Status = ObQueryNameString(DeviceObject,
3945 ObjectNameInfo,
3946 Length,
3947 ResultLength);
3948 if (Status == STATUS_INFO_LENGTH_MISMATCH)
3949 {
3950 /* It's up to the caller to try again */
3951 Status = STATUS_BUFFER_TOO_SMALL;
3952 }
3953
3954 /* This string needs to be NULL-terminated */
3955 NullTerminate = TRUE;
3956
3957 /* Return if successful */
3958 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
3959 ObjectNameInfo->Name.Buffer);
3960
3961 /* Let the caller know how big the name is */
3962 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
3963 break;
3964
3965 /* Handle the registry-based properties */
3966 case DevicePropertyUINumber:
3967 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
3968 case DevicePropertyLocationInformation:
3969 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
3970 case DevicePropertyDeviceDescription:
3971 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
3972 case DevicePropertyHardwareID:
3973 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
3974 case DevicePropertyCompatibleIDs:
3975 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
3976 case DevicePropertyBootConfiguration:
3977 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
3978 case DevicePropertyClassName:
3979 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
3980 case DevicePropertyClassGuid:
3981 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
3982 case DevicePropertyDriverKeyName:
3983 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
3984 case DevicePropertyManufacturer:
3985 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
3986 case DevicePropertyFriendlyName:
3987 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
3988 case DevicePropertyContainerID:
3989 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3990 PIP_UNIMPLEMENTED();
3991 case DevicePropertyRemovalPolicy:
3992 PIP_UNIMPLEMENTED();
3993 break;
3994 case DevicePropertyInstallState:
3995 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD);
3996 break;
3997 case DevicePropertyResourceRequirements:
3998 PIP_UNIMPLEMENTED();
3999 case DevicePropertyAllocatedResources:
4000 PIP_UNIMPLEMENTED();
4001 default:
4002 return STATUS_INVALID_PARAMETER_2;
4003 }
4004
4005 /* Having a registry value name implies registry data */
4006 if (ValueName)
4007 {
4008 /* We know up-front how much data to expect */
4009 *ResultLength = BufferLength;
4010
4011 /* Go get the data, use the LogConf subkey if necessary */
4012 Status = PiGetDeviceRegistryProperty(DeviceObject,
4013 ValueType,
4014 ValueName,
4015 (DeviceProperty ==
4016 DevicePropertyBootConfiguration) ?
4017 L"LogConf": NULL,
4018 PropertyBuffer,
4019 ResultLength);
4020 }
4021 else if (NT_SUCCESS(Status))
4022 {
4023 /* We know up-front how much data to expect, check the caller's buffer */
4024 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
4025 if (*ResultLength <= BufferLength)
4026 {
4027 /* Buffer is all good, copy the data */
4028 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
4029
4030 /* Check if we need to NULL-terminate the string */
4031 if (NullTerminate)
4032 {
4033 /* Terminate the string */
4034 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
4035 }
4036
4037 /* This is the success path */
4038 Status = STATUS_SUCCESS;
4039 }
4040 else
4041 {
4042 /* Failure path */
4043 Status = STATUS_BUFFER_TOO_SMALL;
4044 }
4045 }
4046
4047 /* Free any allocation we may have made, and return the status code */
4048 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
4049 return Status;
4050 }
4051
4052 /*
4053 * @implemented
4054 */
4055 VOID
4056 NTAPI
4057 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
4058 {
4059 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4060 IO_STACK_LOCATION Stack;
4061 ULONG PnPFlags;
4062 NTSTATUS Status;
4063 IO_STATUS_BLOCK IoStatusBlock;
4064
4065 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
4066 Stack.MajorFunction = IRP_MJ_PNP;
4067 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
4068
4069 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
4070 if (!NT_SUCCESS(Status))
4071 {
4072 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status);
4073 return;
4074 }
4075
4076 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
4077 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
4078 else
4079 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
4080
4081 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
4082 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
4083 else
4084 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
4085
4086 if ((PnPFlags & PNP_DEVICE_REMOVED) ||
4087 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
4088 {
4089 /* Flag it if it's failed */
4090 if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START;
4091
4092 /* Send removal IRPs to all of its children */
4093 IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE);
4094
4095 /* Send surprise removal */
4096 IopSendSurpriseRemoval(PhysicalDeviceObject);
4097
4098 /* Tell the user-mode PnP manager that a device was removed */
4099 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
4100 &DeviceNode->InstancePath);
4101
4102 IopSendRemoveDevice(PhysicalDeviceObject);
4103 }
4104 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
4105 {
4106 /* Stop for resource rebalance */
4107 Status = IopStopDevice(DeviceNode);
4108 if (!NT_SUCCESS(Status))
4109 {
4110 DPRINT1("Failed to stop device for rebalancing\n");
4111
4112 /* Stop failed so don't rebalance */
4113 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED;
4114 }
4115 }
4116
4117 /* Resource rebalance */
4118 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
4119 {
4120 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4121
4122 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4123 &IoStatusBlock,
4124 IRP_MN_QUERY_RESOURCES,
4125 NULL);
4126 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
4127 {
4128 DeviceNode->BootResources =
4129 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
4130 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
4131 }
4132 else
4133 {
4134 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
4135 DeviceNode->BootResources = NULL;
4136 }
4137
4138 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4139
4140 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4141 &IoStatusBlock,
4142 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
4143 NULL);
4144 if (NT_SUCCESS(Status))
4145 {
4146 DeviceNode->ResourceRequirements =
4147 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
4148 }
4149 else
4150 {
4151 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
4152 DeviceNode->ResourceRequirements = NULL;
4153 }
4154
4155 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4156 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS)
4157 {
4158 DPRINT1("Restart after resource rebalance failed\n");
4159
4160 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
4161 DeviceNode->Flags |= DNF_START_FAILED;
4162
4163 IopRemoveDevice(DeviceNode);
4164 }
4165 }
4166 }
4167
4168 /**
4169 * @name IoOpenDeviceRegistryKey
4170 *
4171 * Open a registry key unique for a specified driver or device instance.
4172 *
4173 * @param DeviceObject Device to get the registry key for.
4174 * @param DevInstKeyType Type of the key to return.
4175 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4176 * @param DevInstRegKey Handle to the opened registry key on
4177 * successful return.
4178 *
4179 * @return Status.
4180 *
4181 * @implemented
4182 */
4183 NTSTATUS
4184 NTAPI
4185 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
4186 IN ULONG DevInstKeyType,
4187 IN ACCESS_MASK DesiredAccess,
4188 OUT PHANDLE DevInstRegKey)
4189 {
4190 static WCHAR RootKeyName[] =
4191 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4192 static WCHAR ProfileKeyName[] =
4193 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4194 static WCHAR ClassKeyName[] = L"Control\\Class\\";
4195 static WCHAR EnumKeyName[] = L"Enum\\";
4196 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4197 ULONG KeyNameLength;
4198 LPWSTR KeyNameBuffer;
4199 UNICODE_STRING KeyName;
4200 ULONG DriverKeyLength;
4201 OBJECT_ATTRIBUTES ObjectAttributes;
4202 PDEVICE_NODE DeviceNode = NULL;
4203 NTSTATUS Status;
4204
4205 DPRINT("IoOpenDeviceRegistryKey() called\n");
4206
4207 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
4208 {
4209 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4210 return STATUS_INVALID_PARAMETER;
4211 }
4212
4213 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
4214 return STATUS_INVALID_DEVICE_REQUEST;
4215 DeviceNode = IopGetDeviceNode(DeviceObject);
4216
4217 /*
4218 * Calculate the length of the base key name. This is the full
4219 * name for driver key or the name excluding "Device Parameters"
4220 * subkey for device key.
4221 */
4222
4223 KeyNameLength = sizeof(RootKeyName);
4224 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4225 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4226 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4227 {
4228 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4229 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4230 0, NULL, &DriverKeyLength);
4231 if (Status != STATUS_BUFFER_TOO_SMALL)
4232 return Status;
4233 KeyNameLength += DriverKeyLength;
4234 }
4235 else
4236 {
4237 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4238 DeviceNode->InstancePath.Length;
4239 }
4240
4241 /*
4242 * Now allocate the buffer for the key name...
4243 */
4244
4245 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4246 if (KeyNameBuffer == NULL)
4247 return STATUS_INSUFFICIENT_RESOURCES;
4248
4249 KeyName.Length = 0;
4250 KeyName.MaximumLength = (USHORT)KeyNameLength;
4251 KeyName.Buffer = KeyNameBuffer;
4252
4253 /*
4254 * ...and build the key name.
4255 */
4256
4257 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4258 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4259
4260 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4261 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4262
4263 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4264 {
4265 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4266 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4267 DriverKeyLength, KeyNameBuffer +
4268 (KeyName.Length / sizeof(WCHAR)),
4269 &DriverKeyLength);
4270 if (!NT_SUCCESS(Status))
4271 {
4272 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4273 ExFreePool(KeyNameBuffer);
4274 return Status;
4275 }
4276 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4277 }
4278 else
4279 {
4280 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4281 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
4282 if (DeviceNode->InstancePath.Length == 0)
4283 {
4284 ExFreePool(KeyNameBuffer);
4285 return Status;
4286 }
4287 }
4288
4289 /*
4290 * Open the base key.
4291 */
4292 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
4293 if (!NT_SUCCESS(Status))
4294 {
4295 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4296 ExFreePool(KeyNameBuffer);
4297 return Status;
4298 }
4299 ExFreePool(KeyNameBuffer);
4300
4301 /*
4302 * For driver key we're done now.
4303 */
4304
4305 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4306 return Status;
4307
4308 /*
4309 * Let's go further. For device key we must open "Device Parameters"
4310 * subkey and create it if it doesn't exist yet.
4311 */
4312
4313 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4314 InitializeObjectAttributes(&ObjectAttributes,
4315 &KeyName,
4316 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4317 *DevInstRegKey,
4318 NULL);
4319 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
4320 0, NULL, ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, NULL);
4321 ZwClose(ObjectAttributes.RootDirectory);
4322
4323 return Status;
4324 }
4325
4326 static
4327 NTSTATUS
4328 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force)
4329 {
4330 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
4331 NTSTATUS Status;
4332 KIRQL OldIrql;
4333
4334 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4335 ChildDeviceNode = ParentDeviceNode->Child;
4336 while (ChildDeviceNode != NULL)
4337 {
4338 NextDeviceNode = ChildDeviceNode->Sibling;
4339 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4340
4341 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force);
4342 if (!NT_SUCCESS(Status))
4343 {
4344 FailedRemoveDevice = ChildDeviceNode;
4345 goto cleanup;
4346 }
4347
4348 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4349 ChildDeviceNode = NextDeviceNode;
4350 }
4351 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4352
4353 return STATUS_SUCCESS;
4354
4355 cleanup:
4356 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4357 ChildDeviceNode = ParentDeviceNode->Child;
4358 while (ChildDeviceNode != NULL)
4359 {
4360 NextDeviceNode = ChildDeviceNode->Sibling;
4361 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4362
4363 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4364
4365 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4366 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4367 if (ChildDeviceNode == FailedRemoveDevice)
4368 return Status;
4369
4370 ChildDeviceNode = NextDeviceNode;
4371
4372 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4373 }
4374 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4375
4376 return Status;
4377 }
4378
4379 static
4380 VOID
4381 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4382 {
4383 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4384 KIRQL OldIrql;
4385
4386 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4387 ChildDeviceNode = ParentDeviceNode->Child;
4388 while (ChildDeviceNode != NULL)
4389 {
4390 NextDeviceNode = ChildDeviceNode->Sibling;
4391 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4392
4393 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
4394
4395 ChildDeviceNode = NextDeviceNode;
4396
4397 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4398 }
4399 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4400 }
4401
4402 static
4403 VOID
4404 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4405 {
4406 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4407 KIRQL OldIrql;
4408
4409 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4410 ChildDeviceNode = ParentDeviceNode->Child;
4411 while (ChildDeviceNode != NULL)
4412 {
4413 NextDeviceNode = ChildDeviceNode->Sibling;
4414 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4415
4416 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4417
4418 ChildDeviceNode = NextDeviceNode;
4419
4420 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4421 }
4422 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4423 }
4424
4425 static
4426 NTSTATUS
4427 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force)
4428 {
4429 /* This function DOES NOT dereference the device objects on SUCCESS
4430 * but it DOES dereference device objects on FAILURE */
4431
4432 ULONG i, j;
4433 NTSTATUS Status;
4434
4435 for (i = 0; i < DeviceRelations->Count; i++)
4436 {
4437 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force);
4438 if (!NT_SUCCESS(Status))
4439 {
4440 j = i;
4441 goto cleanup;
4442 }
4443 }
4444
4445 return STATUS_SUCCESS;
4446
4447 cleanup:
4448 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4449 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4450 for (i = 0; i <= j; i++)
4451 {
4452 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4453 ObDereferenceObject(DeviceRelations->Objects[i]);
4454 DeviceRelations->Objects[i] = NULL;
4455 }
4456 for (; i < DeviceRelations->Count; i++)
4457 {
4458 ObDereferenceObject(DeviceRelations->Objects[i]);
4459 DeviceRelations->Objects[i] = NULL;
4460 }
4461 ExFreePool(DeviceRelations);
4462
4463 return Status;
4464 }
4465
4466 static
4467 VOID
4468 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4469 {
4470 /* This function DOES dereference the device objects in all cases */
4471
4472 ULONG i;
4473
4474 for (i = 0; i < DeviceRelations->Count; i++)
4475 {
4476 IopSendRemoveDevice(DeviceRelations->Objects[i]);
4477 DeviceRelations->Objects[i] = NULL;
4478 }
4479
4480 ExFreePool(DeviceRelations);
4481 }
4482
4483 static
4484 VOID
4485 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4486 {
4487 /* This function DOES dereference the device objects in all cases */
4488
4489 ULONG i;
4490
4491 for (i = 0; i < DeviceRelations->Count; i++)
4492 {
4493 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4494 ObDereferenceObject(DeviceRelations->Objects[i]);
4495 DeviceRelations->Objects[i] = NULL;
4496 }
4497
4498 ExFreePool(DeviceRelations);
4499 }
4500
4501 VOID
4502 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
4503 {
4504 IO_STACK_LOCATION Stack;
4505 IO_STATUS_BLOCK IoStatusBlock;
4506 PDEVICE_RELATIONS DeviceRelations;
4507 NTSTATUS Status;
4508
4509 IopCancelRemoveDevice(DeviceObject);
4510
4511 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4512
4513 Status = IopInitiatePnpIrp(DeviceObject,
4514 &IoStatusBlock,
4515 IRP_MN_QUERY_DEVICE_RELATIONS,
4516 &Stack);
4517 if (!NT_SUCCESS(Status))
4518 {
4519 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4520 DeviceRelations = NULL;
4521 }
4522 else
4523 {
4524 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4525 }
4526
4527 if (DeviceRelations)
4528 IopCancelRemoveDeviceRelations(DeviceRelations);
4529 }
4530
4531 NTSTATUS
4532 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force)
4533 {
4534 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4535 IO_STACK_LOCATION Stack;
4536 IO_STATUS_BLOCK IoStatusBlock;
4537 PDEVICE_RELATIONS DeviceRelations;
4538 NTSTATUS Status;
4539
4540 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force)
4541 {
4542 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
4543 return STATUS_UNSUCCESSFUL;
4544 }
4545
4546 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
4547 {
4548 DPRINT1("Removal vetoed by failing the query remove request\n");
4549
4550 IopCancelRemoveDevice(DeviceObject);
4551
4552 return STATUS_UNSUCCESSFUL;
4553 }
4554
4555 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4556
4557 Status = IopInitiatePnpIrp(DeviceObject,
4558 &IoStatusBlock,
4559 IRP_MN_QUERY_DEVICE_RELATIONS,
4560 &Stack);
4561 if (!NT_SUCCESS(Status))
4562 {
4563 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4564 DeviceRelations = NULL;
4565 }
4566 else
4567 {
4568 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4569 }
4570
4571 if (DeviceRelations)
4572 {
4573 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force);
4574 if (!NT_SUCCESS(Status))
4575 return Status;
4576 }
4577
4578 Status = IopQueryRemoveChildDevices(DeviceNode, Force);
4579 if (!NT_SUCCESS(Status))
4580 {
4581 if (DeviceRelations)
4582 IopCancelRemoveDeviceRelations(DeviceRelations);
4583 return Status;
4584 }
4585
4586 if (DeviceRelations)
4587 IopSendRemoveDeviceRelations(DeviceRelations);
4588 IopSendRemoveChildDevices(DeviceNode);
4589
4590 return STATUS_SUCCESS;
4591 }
4592
4593 NTSTATUS
4594 IopRemoveDevice(PDEVICE_NODE DeviceNode)
4595 {
4596 NTSTATUS Status;
4597
4598 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
4599
4600 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE);
4601 if (NT_SUCCESS(Status))
4602 {
4603 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
4604 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
4605 &DeviceNode->InstancePath);
4606 return STATUS_SUCCESS;
4607 }
4608
4609 return Status;
4610 }
4611
4612 /*
4613 * @implemented
4614 */
4615 VOID
4616 NTAPI
4617 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
4618 {
4619 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4620 PDEVICE_RELATIONS DeviceRelations;
4621 IO_STATUS_BLOCK IoStatusBlock;
4622 IO_STACK_LOCATION Stack;
4623 DEVICE_CAPABILITIES Capabilities;
4624 NTSTATUS Status;
4625
4626 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
4627 &DeviceNode->InstancePath);
4628
4629 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
4630 {
4631 goto cleanup;
4632 }
4633
4634 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
4635
4636 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4637 &IoStatusBlock,
4638 IRP_MN_QUERY_DEVICE_RELATIONS,
4639 &Stack);
4640 if (!NT_SUCCESS(Status))
4641 {
4642 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4643 DeviceRelations = NULL;
4644 }
4645 else
4646 {
4647 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4648 }
4649
4650 if (DeviceRelations)
4651 {
4652 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE);
4653 if (!NT_SUCCESS(Status))
4654 goto cleanup;
4655 }
4656
4657 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE);
4658 if (!NT_SUCCESS(Status))
4659 {
4660 if (DeviceRelations)
4661 IopCancelRemoveDeviceRelations(DeviceRelations);
4662 goto cleanup;
4663 }
4664
4665 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS)
4666 {
4667 if (DeviceRelations)
4668 IopCancelRemoveDeviceRelations(DeviceRelations);
4669 IopCancelRemoveChildDevices(DeviceNode);
4670 goto cleanup;
4671 }
4672
4673 if (DeviceRelations)
4674 IopSendRemoveDeviceRelations(DeviceRelations);
4675 IopSendRemoveChildDevices(DeviceNode);
4676
4677 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT;
4678 if (Capabilities.EjectSupported)
4679 {
4680 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
4681 {
4682 goto cleanup;
4683 }
4684 }
4685 else
4686 {
4687 DeviceNode->Flags |= DNF_DISABLED;
4688 }
4689
4690 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
4691 &DeviceNode->InstancePath);
4692
4693 return;
4694
4695 cleanup:
4696 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
4697 &DeviceNode->InstancePath);
4698 }
4699
4700 /*
4701 * @implemented
4702 */
4703 VOID
4704 NTAPI
4705 IoInvalidateDeviceRelations(
4706 IN PDEVICE_OBJECT DeviceObject,
4707 IN DEVICE_RELATION_TYPE Type)
4708 {
4709 PINVALIDATE_DEVICE_RELATION_DATA Data;
4710 KIRQL OldIrql;
4711
4712 Data = ExAllocatePool(NonPagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
4713 if (!Data)
4714 return;
4715
4716 ObReferenceObject(DeviceObject);
4717 Data->DeviceObject = DeviceObject;
4718 Data->Type = Type;
4719
4720 KeAcquireSpinLock(&IopDeviceRelationsSpinLock, &OldIrql);
4721 InsertTailList(&IopDeviceRelationsRequestList, &Data->RequestListEntry);
4722 if (IopDeviceRelationsRequestInProgress)
4723 {
4724 KeReleaseSpinLock(&IopDeviceRelationsSpinLock, OldIrql);
4725 return;
4726 }
4727 IopDeviceRelationsRequestInProgress = TRUE;
4728 KeReleaseSpinLock(&IopDeviceRelationsSpinLock, OldIrql);
4729
4730 ExInitializeWorkItem(&IopDeviceRelationsWorkItem,
4731 IopDeviceRelationsWorker,
4732 NULL);
4733 ExQueueWorkItem(&IopDeviceRelationsWorkItem,
4734 DelayedWorkQueue);
4735 }
4736
4737 /*
4738 * @implemented
4739 */
4740 NTSTATUS
4741 NTAPI
4742 IoSynchronousInvalidateDeviceRelations(
4743 IN PDEVICE_OBJECT DeviceObject,
4744 IN DEVICE_RELATION_TYPE Type)
4745 {
4746 PAGED_CODE();
4747
4748 switch (Type)
4749 {
4750 case BusRelations:
4751 /* Enumerate the device */
4752 return IopEnumerateDevice(DeviceObject);
4753 case PowerRelations:
4754 /* Not handled yet */
4755 return STATUS_NOT_IMPLEMENTED;
4756 case TargetDeviceRelation:
4757 /* Nothing to do */
4758 return STATUS_SUCCESS;
4759 default:
4760 /* Ejection relations are not supported */
4761 return STATUS_NOT_SUPPORTED;
4762 }
4763 }
4764
4765 /*
4766 * @implemented
4767 */
4768 BOOLEAN
4769 NTAPI
4770 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
4771 IN ULONG BusNumber,
4772 IN PHYSICAL_ADDRESS BusAddress,
4773 IN OUT PULONG AddressSpace,
4774 OUT PPHYSICAL_ADDRESS TranslatedAddress)
4775 {
4776 /* FIXME: Notify the resource arbiter */
4777
4778 return HalTranslateBusAddress(InterfaceType,
4779 BusNumber,
4780 BusAddress,
4781 AddressSpace,
4782 TranslatedAddress);
4783 }