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