- Implement a helper registry key opening function to reduce code size.
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 *
7 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 //#define ENABLE_ACPI
19
20 /* GLOBALS *******************************************************************/
21
22 PDEVICE_NODE IopRootDeviceNode;
23 KSPIN_LOCK IopDeviceTreeLock;
24 ERESOURCE PpRegistryDeviceResource;
25 KGUARDED_MUTEX PpDeviceReferenceTableLock;
26 RTL_AVL_TABLE PpDeviceReferenceTable;
27
28 extern ULONG ExpInitializationPhase;
29
30 /* DATA **********************************************************************/
31
32 PDRIVER_OBJECT IopRootDriverObject;
33 PIO_BUS_TYPE_GUID_LIST IopBusTypeGuidList = NULL;
34
35 #if defined (ALLOC_PRAGMA)
36 #pragma alloc_text(INIT, PnpInit)
37 #pragma alloc_text(INIT, PnpInit2)
38 #endif
39
40 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
41 {
42 PDEVICE_OBJECT DeviceObject;
43 DEVICE_RELATION_TYPE Type;
44 PIO_WORKITEM WorkItem;
45 } INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
46
47 VOID
48 NTAPI
49 IoSynchronousInvalidateDeviceRelations(
50 IN PDEVICE_OBJECT DeviceObject,
51 IN DEVICE_RELATION_TYPE Type);
52
53
54 /* FUNCTIONS *****************************************************************/
55
56 static NTSTATUS
57 IopAssignDeviceResources(
58 IN PDEVICE_NODE DeviceNode,
59 OUT ULONG *pRequiredSize);
60 static NTSTATUS
61 IopTranslateDeviceResources(
62 IN PDEVICE_NODE DeviceNode,
63 IN ULONG RequiredSize);
64
65 PDEVICE_NODE
66 FASTCALL
67 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
68 {
69 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
70 }
71
72 NTSTATUS
73 FASTCALL
74 IopInitializeDevice(PDEVICE_NODE DeviceNode,
75 PDRIVER_OBJECT DriverObject)
76 {
77 PDEVICE_OBJECT Fdo;
78 NTSTATUS Status;
79
80 if (!DriverObject->DriverExtension->AddDevice)
81 return STATUS_SUCCESS;
82
83 /* This is a Plug and Play driver */
84 DPRINT("Plug and Play driver found\n");
85 ASSERT(DeviceNode->PhysicalDeviceObject);
86
87 /* Check if this plug-and-play driver is used as a legacy one for this device node */
88 if (IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
89 {
90 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
91 return STATUS_SUCCESS;
92 }
93
94 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
95 &DriverObject->DriverName,
96 &DeviceNode->InstancePath);
97 Status = DriverObject->DriverExtension->AddDevice(
98 DriverObject, DeviceNode->PhysicalDeviceObject);
99 if (!NT_SUCCESS(Status))
100 {
101 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
102 return Status;
103 }
104
105 /* Check if driver added a FDO above the PDO */
106 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
107 if (Fdo == DeviceNode->PhysicalDeviceObject)
108 {
109 /* FIXME: What do we do? Unload the driver or just disable the device? */
110 DPRINT1("An FDO was not attached\n");
111 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
112 return STATUS_UNSUCCESSFUL;
113 }
114
115 /* Check if we have a ACPI device (needed for power management) */
116 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
117 {
118 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
119
120 /* There can be only one system power device */
121 if (!SystemPowerDeviceNodeCreated)
122 {
123 PopSystemPowerDeviceNode = DeviceNode;
124 ObReferenceObject(PopSystemPowerDeviceNode);
125 SystemPowerDeviceNodeCreated = TRUE;
126 }
127 }
128
129 ObDereferenceObject(Fdo);
130
131 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
132 IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
133
134 return STATUS_SUCCESS;
135 }
136
137 NTSTATUS
138 IopStartDevice(
139 PDEVICE_NODE DeviceNode)
140 {
141 IO_STATUS_BLOCK IoStatusBlock;
142 IO_STACK_LOCATION Stack;
143 ULONG RequiredLength;
144 PDEVICE_OBJECT Fdo;
145 NTSTATUS Status;
146
147 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
148
149 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
150 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
151 Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
152 Status = IopInitiatePnpIrp(
153 Fdo,
154 &IoStatusBlock,
155 IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
156 &Stack);
157 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
158 {
159 DPRINT("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
160 return Status;
161 }
162 DeviceNode->ResourceRequirements = Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList;
163
164 Status = IopAssignDeviceResources(DeviceNode, &RequiredLength);
165 if (NT_SUCCESS(Status))
166 {
167 Status = IopTranslateDeviceResources(DeviceNode, RequiredLength);
168 if (NT_SUCCESS(Status))
169 {
170 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
171 }
172 else
173 {
174 DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)\n", Status);
175 }
176 }
177 else
178 {
179 DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)\n", Status);
180 }
181 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
182
183 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
184 Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList;
185 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated;
186
187 /*
188 * Windows NT Drivers receive IRP_MN_START_DEVICE in a critical region and
189 * actually _depend_ on this!. This is because NT will lock the Device Node
190 * with an ERESOURCE, which of course requires APCs to be disabled.
191 */
192 KeEnterCriticalRegion();
193
194 Status = IopInitiatePnpIrp(
195 Fdo,
196 &IoStatusBlock,
197 IRP_MN_START_DEVICE,
198 &Stack);
199
200 KeLeaveCriticalRegion();
201
202 if (!NT_SUCCESS(Status))
203 {
204 DPRINT("IopInitiatePnpIrp() failed\n");
205 }
206 else
207 {
208 if (IopDeviceNodeHasFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY))
209 {
210 DPRINT("Device needs enumeration, invalidating bus relations\n");
211 /* Invalidate device relations synchronously
212 (otherwise there will be dirty read of DeviceNode) */
213 IoSynchronousInvalidateDeviceRelations(DeviceNode->PhysicalDeviceObject, BusRelations);
214 IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
215 }
216 }
217
218 ObDereferenceObject(Fdo);
219
220 if (NT_SUCCESS(Status))
221 DeviceNode->Flags |= DN_STARTED;
222
223 return Status;
224 }
225
226 NTSTATUS
227 STDCALL
228 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
229 PDEVICE_CAPABILITIES DeviceCaps)
230 {
231 IO_STATUS_BLOCK StatusBlock;
232 IO_STACK_LOCATION Stack;
233
234 /* Set up the Header */
235 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
236 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
237 DeviceCaps->Version = 1;
238 DeviceCaps->Address = -1;
239 DeviceCaps->UINumber = -1;
240
241 /* Set up the Stack */
242 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
243 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
244
245 /* Send the IRP */
246 return IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
247 &StatusBlock,
248 IRP_MN_QUERY_CAPABILITIES,
249 &Stack);
250 }
251
252 static VOID NTAPI
253 IopAsynchronousInvalidateDeviceRelations(
254 IN PDEVICE_OBJECT DeviceObject,
255 IN PVOID InvalidateContext)
256 {
257 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
258
259 IoSynchronousInvalidateDeviceRelations(
260 Data->DeviceObject,
261 Data->Type);
262
263 ObDereferenceObject(Data->WorkItem);
264 IoFreeWorkItem(Data->WorkItem);
265 ExFreePool(Data);
266 }
267
268 /*
269 * @implemented
270 */
271 VOID
272 NTAPI
273 IoInvalidateDeviceRelations(
274 IN PDEVICE_OBJECT DeviceObject,
275 IN DEVICE_RELATION_TYPE Type)
276 {
277 PIO_WORKITEM WorkItem;
278 PINVALIDATE_DEVICE_RELATION_DATA Data;
279
280 Data = ExAllocatePool(PagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
281 if (!Data)
282 return;
283 WorkItem = IoAllocateWorkItem(DeviceObject);
284 if (!WorkItem)
285 {
286 ExFreePool(Data);
287 return;
288 }
289
290 ObReferenceObject(DeviceObject);
291 Data->DeviceObject = DeviceObject;
292 Data->Type = Type;
293 Data->WorkItem = WorkItem;
294
295 IoQueueWorkItem(
296 WorkItem,
297 IopAsynchronousInvalidateDeviceRelations,
298 DelayedWorkQueue,
299 Data);
300 }
301
302 /*
303 * @unimplemented
304 */
305 NTSTATUS
306 STDCALL
307 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
308 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
309 IN ULONG BufferLength,
310 OUT PVOID PropertyBuffer,
311 OUT PULONG ResultLength)
312 {
313 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
314 DEVICE_CAPABILITIES DeviceCaps;
315 ULONG Length;
316 PVOID Data = NULL;
317 PWSTR Ptr;
318 NTSTATUS Status;
319
320 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
321
322 *ResultLength = 0;
323
324 if (DeviceNode == NULL)
325 return STATUS_INVALID_DEVICE_REQUEST;
326
327 switch (DeviceProperty)
328 {
329 case DevicePropertyBusNumber:
330 Length = sizeof(ULONG);
331 Data = &DeviceNode->ChildBusNumber;
332 break;
333
334 /* Complete, untested */
335 case DevicePropertyBusTypeGuid:
336 /* Sanity check */
337 if ((DeviceNode->ChildBusTypeIndex != 0xFFFF) &&
338 (DeviceNode->ChildBusTypeIndex < IopBusTypeGuidList->GuidCount))
339 {
340 /* Return the GUID */
341 *ResultLength = sizeof(GUID);
342
343 /* Check if the buffer given was large enough */
344 if (BufferLength < *ResultLength)
345 {
346 return STATUS_BUFFER_TOO_SMALL;
347 }
348
349 /* Copy the GUID */
350 RtlCopyMemory(PropertyBuffer,
351 &(IopBusTypeGuidList->Guids[DeviceNode->ChildBusTypeIndex]),
352 sizeof(GUID));
353 return STATUS_SUCCESS;
354 }
355 else
356 {
357 return STATUS_OBJECT_NAME_NOT_FOUND;
358 }
359 break;
360
361 case DevicePropertyLegacyBusType:
362 Length = sizeof(INTERFACE_TYPE);
363 Data = &DeviceNode->ChildInterfaceType;
364 break;
365
366 case DevicePropertyAddress:
367 /* Query the device caps */
368 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
369 if (NT_SUCCESS(Status) && (DeviceCaps.Address != (ULONG)-1))
370 {
371 /* Return length */
372 *ResultLength = sizeof(ULONG);
373
374 /* Check if the buffer given was large enough */
375 if (BufferLength < *ResultLength)
376 {
377 return STATUS_BUFFER_TOO_SMALL;
378 }
379
380 /* Return address */
381 *(PULONG)PropertyBuffer = DeviceCaps.Address;
382 return STATUS_SUCCESS;
383 }
384 else
385 {
386 return STATUS_OBJECT_NAME_NOT_FOUND;
387 }
388 break;
389
390 // case DevicePropertyUINumber:
391 // if (DeviceNode->CapabilityFlags == NULL)
392 // return STATUS_INVALID_DEVICE_REQUEST;
393 // Length = sizeof(ULONG);
394 // Data = &DeviceNode->CapabilityFlags->UINumber;
395 // break;
396
397 case DevicePropertyClassName:
398 case DevicePropertyClassGuid:
399 case DevicePropertyDriverKeyName:
400 case DevicePropertyManufacturer:
401 case DevicePropertyFriendlyName:
402 case DevicePropertyHardwareID:
403 case DevicePropertyCompatibleIDs:
404 case DevicePropertyDeviceDescription:
405 case DevicePropertyLocationInformation:
406 case DevicePropertyUINumber:
407 {
408 LPCWSTR RegistryPropertyName;
409 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
410 UNICODE_STRING ValueName;
411 OBJECT_ATTRIBUTES ObjectAttributes;
412 KEY_VALUE_PARTIAL_INFORMATION *ValueInformation;
413 ULONG ValueInformationLength;
414 HANDLE KeyHandle, EnumRootHandle;
415 NTSTATUS Status;
416
417 switch (DeviceProperty)
418 {
419 case DevicePropertyClassName:
420 RegistryPropertyName = L"Class"; break;
421 case DevicePropertyClassGuid:
422 RegistryPropertyName = L"ClassGuid"; break;
423 case DevicePropertyDriverKeyName:
424 RegistryPropertyName = L"Driver"; break;
425 case DevicePropertyManufacturer:
426 RegistryPropertyName = L"Mfg"; break;
427 case DevicePropertyFriendlyName:
428 RegistryPropertyName = L"FriendlyName"; break;
429 case DevicePropertyHardwareID:
430 RegistryPropertyName = L"HardwareID"; break;
431 case DevicePropertyCompatibleIDs:
432 RegistryPropertyName = L"CompatibleIDs"; break;
433 case DevicePropertyDeviceDescription:
434 RegistryPropertyName = L"DeviceDesc"; break;
435 case DevicePropertyLocationInformation:
436 RegistryPropertyName = L"LocationInformation"; break;
437 case DevicePropertyUINumber:
438 RegistryPropertyName = L"UINumber"; break;
439 default:
440 /* Should not happen */
441 ASSERT(FALSE);
442 return STATUS_UNSUCCESSFUL;
443 }
444
445 DPRINT("Registry property %S\n", RegistryPropertyName);
446
447 /* Open Enum key */
448 InitializeObjectAttributes(&ObjectAttributes, &EnumRoot,
449 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
450 Status = ZwOpenKey(&EnumRootHandle, 0, &ObjectAttributes);
451 if (!NT_SUCCESS(Status))
452 {
453 DPRINT1("Error opening ENUM_ROOT, Status=0x%08x\n", Status);
454 return Status;
455 }
456
457 /* Open instance key */
458 InitializeObjectAttributes(&ObjectAttributes, &DeviceNode->InstancePath,
459 OBJ_CASE_INSENSITIVE, EnumRootHandle, NULL);
460
461 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
462 if (!NT_SUCCESS(Status))
463 {
464 DPRINT1("Error opening InstancePath, Status=0x%08x\n", Status);
465 return Status;
466 }
467
468 /* Allocate buffer to read as much data as required by the caller */
469 ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
470 Data[0]) + BufferLength;
471 ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
472 if (!ValueInformation)
473 {
474 ZwClose(KeyHandle);
475 return STATUS_INSUFFICIENT_RESOURCES;
476 }
477
478 /* Read the value */
479 RtlInitUnicodeString(&ValueName, RegistryPropertyName);
480 Status = ZwQueryValueKey(KeyHandle, &ValueName,
481 KeyValuePartialInformation, ValueInformation,
482 ValueInformationLength,
483 &ValueInformationLength);
484 ZwClose(KeyHandle);
485
486 /* Return data */
487 *ResultLength = ValueInformation->DataLength;
488
489 if (!NT_SUCCESS(Status))
490 {
491 DPRINT1("Problem: Status=0x%08x, ResultLength = %d\n", Status, *ResultLength);
492 ExFreePool(ValueInformation);
493 if (Status == STATUS_BUFFER_OVERFLOW)
494 return STATUS_BUFFER_TOO_SMALL;
495 else
496 return Status;
497 }
498
499 /* FIXME: Verify the value (NULL-terminated, correct format). */
500 RtlCopyMemory(PropertyBuffer, ValueInformation->Data,
501 ValueInformation->DataLength);
502 ExFreePool(ValueInformation);
503
504 return STATUS_SUCCESS;
505 }
506
507 case DevicePropertyBootConfiguration:
508 Length = 0;
509 if (DeviceNode->BootResources->Count != 0)
510 {
511 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
512 }
513 Data = &DeviceNode->BootResources;
514 break;
515
516 /* FIXME: use a translated boot configuration instead */
517 case DevicePropertyBootConfigurationTranslated:
518 Length = 0;
519 if (DeviceNode->BootResources->Count != 0)
520 {
521 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
522 }
523 Data = &DeviceNode->BootResources;
524 break;
525
526 case DevicePropertyEnumeratorName:
527 /* A buffer overflow can't happen here, since InstancePath
528 * always contains the enumerator name followed by \\ */
529 Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\');
530 ASSERT(Ptr);
531 Length = (Ptr - DeviceNode->InstancePath.Buffer + 1) * sizeof(WCHAR);
532 Data = DeviceNode->InstancePath.Buffer;
533 break;
534
535 case DevicePropertyPhysicalDeviceObjectName:
536 /* InstancePath buffer is NULL terminated, so we can do this */
537 Length = DeviceNode->InstancePath.MaximumLength;
538 Data = DeviceNode->InstancePath.Buffer;
539 break;
540
541 default:
542 return STATUS_INVALID_PARAMETER_2;
543 }
544
545 /* Prepare returned values */
546 *ResultLength = Length;
547 if (BufferLength < Length)
548 return STATUS_BUFFER_TOO_SMALL;
549 RtlCopyMemory(PropertyBuffer, Data, Length);
550
551 /* NULL terminate the string (if required) */
552 if (DeviceProperty == DevicePropertyEnumeratorName)
553 ((LPWSTR)PropertyBuffer)[Length / sizeof(WCHAR)] = UNICODE_NULL;
554
555 return STATUS_SUCCESS;
556 }
557
558 /*
559 * @unimplemented
560 */
561 VOID
562 STDCALL
563 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
564 {
565 UNIMPLEMENTED;
566 }
567
568 /**
569 * @name IoOpenDeviceRegistryKey
570 *
571 * Open a registry key unique for a specified driver or device instance.
572 *
573 * @param DeviceObject Device to get the registry key for.
574 * @param DevInstKeyType Type of the key to return.
575 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
576 * @param DevInstRegKey Handle to the opened registry key on
577 * successful return.
578 *
579 * @return Status.
580 *
581 * @implemented
582 */
583 NTSTATUS
584 STDCALL
585 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
586 IN ULONG DevInstKeyType,
587 IN ACCESS_MASK DesiredAccess,
588 OUT PHANDLE DevInstRegKey)
589 {
590 static WCHAR RootKeyName[] =
591 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
592 static WCHAR ProfileKeyName[] =
593 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
594 static WCHAR ClassKeyName[] = L"Control\\Class\\";
595 static WCHAR EnumKeyName[] = L"Enum\\";
596 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
597 ULONG KeyNameLength;
598 LPWSTR KeyNameBuffer;
599 UNICODE_STRING KeyName;
600 ULONG DriverKeyLength;
601 OBJECT_ATTRIBUTES ObjectAttributes;
602 PDEVICE_NODE DeviceNode = NULL;
603 NTSTATUS Status;
604
605 DPRINT("IoOpenDeviceRegistryKey() called\n");
606
607 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
608 {
609 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
610 return STATUS_INVALID_PARAMETER;
611 }
612
613 /*
614 * Calculate the length of the base key name. This is the full
615 * name for driver key or the name excluding "Device Parameters"
616 * subkey for device key.
617 */
618
619 KeyNameLength = sizeof(RootKeyName);
620 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
621 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
622 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
623 {
624 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
625 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
626 0, NULL, &DriverKeyLength);
627 if (Status != STATUS_BUFFER_TOO_SMALL)
628 return Status;
629 KeyNameLength += DriverKeyLength;
630 }
631 else
632 {
633 DeviceNode = IopGetDeviceNode(DeviceObject);
634 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
635 DeviceNode->InstancePath.Length;
636 }
637
638 /*
639 * Now allocate the buffer for the key name...
640 */
641
642 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
643 if (KeyNameBuffer == NULL)
644 return STATUS_INSUFFICIENT_RESOURCES;
645
646 KeyName.Length = 0;
647 KeyName.MaximumLength = (USHORT)KeyNameLength;
648 KeyName.Buffer = KeyNameBuffer;
649
650 /*
651 * ...and build the key name.
652 */
653
654 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
655 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
656
657 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
658 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
659
660 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
661 {
662 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
663 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
664 DriverKeyLength, KeyNameBuffer +
665 (KeyName.Length / sizeof(WCHAR)),
666 &DriverKeyLength);
667 if (!NT_SUCCESS(Status))
668 {
669 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
670 ExFreePool(KeyNameBuffer);
671 return Status;
672 }
673 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
674 }
675 else
676 {
677 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
678 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
679 if (DeviceNode->InstancePath.Length == 0)
680 {
681 ExFreePool(KeyNameBuffer);
682 return Status;
683 }
684 }
685
686 /*
687 * Open the base key.
688 */
689
690 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
691 OBJ_CASE_INSENSITIVE, NULL, NULL);
692 Status = ZwOpenKey(DevInstRegKey, DesiredAccess, &ObjectAttributes);
693 if (!NT_SUCCESS(Status))
694 {
695 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
696 ExFreePool(KeyNameBuffer);
697 return Status;
698 }
699 ExFreePool(KeyNameBuffer);
700
701 /*
702 * For driver key we're done now.
703 */
704
705 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
706 return Status;
707
708 /*
709 * Let's go further. For device key we must open "Device Parameters"
710 * subkey and create it if it doesn't exist yet.
711 */
712
713 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
714 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
715 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
716 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
717 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
718 ZwClose(ObjectAttributes.RootDirectory);
719
720 return Status;
721 }
722
723 /*
724 * @unimplemented
725 */
726 VOID
727 STDCALL
728 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
729 {
730 UNIMPLEMENTED;
731 }
732
733
734 NTSTATUS
735 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
736 {
737 KIRQL OldIrql;
738
739 if (PopSystemPowerDeviceNode)
740 {
741 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
742 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
743 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
744
745 return STATUS_SUCCESS;
746 }
747
748 return STATUS_UNSUCCESSFUL;
749 }
750
751 USHORT
752 STDCALL
753 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
754 {
755 USHORT i = 0, FoundIndex = 0xFFFF;
756 ULONG NewSize;
757 PVOID NewList;
758
759 /* Acquire the lock */
760 ExAcquireFastMutex(&IopBusTypeGuidList->Lock);
761
762 /* Loop all entries */
763 while (i < IopBusTypeGuidList->GuidCount)
764 {
765 /* Try to find a match */
766 if (RtlCompareMemory(BusTypeGuid,
767 &IopBusTypeGuidList->Guids[i],
768 sizeof(GUID)) == sizeof(GUID))
769 {
770 /* Found it */
771 FoundIndex = i;
772 goto Quickie;
773 }
774 i++;
775 }
776
777 /* Check if we have to grow the list */
778 if (IopBusTypeGuidList->GuidCount)
779 {
780 /* Calculate the new size */
781 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
782 (sizeof(GUID) * IopBusTypeGuidList->GuidCount);
783
784 /* Allocate the new copy */
785 NewList = ExAllocatePool(PagedPool, NewSize);
786
787 /* Now copy them, decrease the size too */
788 NewSize -= sizeof(GUID);
789 RtlCopyMemory(NewList, IopBusTypeGuidList, NewSize);
790
791 /* Free the old list */
792 ExFreePool(IopBusTypeGuidList);
793
794 /* Use the new buffer */
795 IopBusTypeGuidList = NewList;
796 }
797
798 /* Copy the new GUID */
799 RtlCopyMemory(&IopBusTypeGuidList->Guids[IopBusTypeGuidList->GuidCount],
800 BusTypeGuid,
801 sizeof(GUID));
802
803 /* The new entry is the index */
804 FoundIndex = (USHORT)IopBusTypeGuidList->GuidCount;
805 IopBusTypeGuidList->GuidCount++;
806
807 Quickie:
808 ExReleaseFastMutex(&IopBusTypeGuidList->Lock);
809 return FoundIndex;
810 }
811
812 /*
813 * DESCRIPTION
814 * Creates a device node
815 *
816 * ARGUMENTS
817 * ParentNode = Pointer to parent device node
818 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
819 * to have the root device node create one
820 * (eg. for legacy drivers)
821 * DeviceNode = Pointer to storage for created device node
822 *
823 * RETURN VALUE
824 * Status
825 */
826 NTSTATUS
827 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
828 PDEVICE_OBJECT PhysicalDeviceObject,
829 PUNICODE_STRING ServiceName,
830 PDEVICE_NODE *DeviceNode)
831 {
832 PDEVICE_NODE Node;
833 NTSTATUS Status;
834 KIRQL OldIrql;
835
836 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
837 ParentNode, PhysicalDeviceObject, ServiceName);
838
839 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
840 if (!Node)
841 {
842 return STATUS_INSUFFICIENT_RESOURCES;
843 }
844
845 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
846
847 if (!PhysicalDeviceObject)
848 {
849 Status = PnpRootCreateDevice(ServiceName, &PhysicalDeviceObject);
850 if (!NT_SUCCESS(Status))
851 {
852 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
853 ExFreePool(Node);
854 return Status;
855 }
856
857 /* This is for drivers passed on the command line to ntoskrnl.exe */
858 IopDeviceNodeSetFlag(Node, DNF_STARTED);
859 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
860 }
861
862 Node->PhysicalDeviceObject = PhysicalDeviceObject;
863
864 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
865
866 if (ParentNode)
867 {
868 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
869 Node->Parent = ParentNode;
870 Node->NextSibling = ParentNode->Child;
871 if (ParentNode->Child != NULL)
872 {
873 ParentNode->Child->PrevSibling = Node;
874 }
875 ParentNode->Child = Node;
876 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
877 Node->Level = ParentNode->Level + 1;
878 }
879
880 *DeviceNode = Node;
881
882 return STATUS_SUCCESS;
883 }
884
885 NTSTATUS
886 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
887 {
888 KIRQL OldIrql;
889
890 /* All children must be deleted before a parent is deleted */
891 ASSERT(!DeviceNode->Child);
892
893 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
894
895 ASSERT(DeviceNode->PhysicalDeviceObject);
896
897 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
898
899 /* Unlink from parent if it exists */
900
901 if ((DeviceNode->Parent) && (DeviceNode->Parent->Child == DeviceNode))
902 {
903 DeviceNode->Parent->Child = DeviceNode->NextSibling;
904 }
905
906 /* Unlink from sibling list */
907
908 if (DeviceNode->PrevSibling)
909 {
910 DeviceNode->PrevSibling->NextSibling = DeviceNode->NextSibling;
911 }
912
913 if (DeviceNode->NextSibling)
914 {
915 DeviceNode->NextSibling->PrevSibling = DeviceNode->PrevSibling;
916 }
917
918 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
919
920 RtlFreeUnicodeString(&DeviceNode->InstancePath);
921
922 RtlFreeUnicodeString(&DeviceNode->ServiceName);
923
924 if (DeviceNode->ResourceList)
925 {
926 ExFreePool(DeviceNode->ResourceList);
927 }
928
929 if (DeviceNode->ResourceListTranslated)
930 {
931 ExFreePool(DeviceNode->ResourceListTranslated);
932 }
933
934 if (DeviceNode->ResourceRequirements)
935 {
936 ExFreePool(DeviceNode->ResourceRequirements);
937 }
938
939 if (DeviceNode->BootResources)
940 {
941 ExFreePool(DeviceNode->BootResources);
942 }
943
944 ExFreePool(DeviceNode);
945
946 return STATUS_SUCCESS;
947 }
948
949 NTSTATUS
950 IopInitiatePnpIrp(PDEVICE_OBJECT DeviceObject,
951 PIO_STATUS_BLOCK IoStatusBlock,
952 ULONG MinorFunction,
953 PIO_STACK_LOCATION Stack OPTIONAL)
954 {
955 PDEVICE_OBJECT TopDeviceObject;
956 PIO_STACK_LOCATION IrpSp;
957 NTSTATUS Status;
958 KEVENT Event;
959 PIRP Irp;
960
961 /* Always call the top of the device stack */
962 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
963
964 KeInitializeEvent(
965 &Event,
966 NotificationEvent,
967 FALSE);
968
969 Irp = IoBuildSynchronousFsdRequest(
970 IRP_MJ_PNP,
971 TopDeviceObject,
972 NULL,
973 0,
974 NULL,
975 &Event,
976 IoStatusBlock);
977
978 /* PNP IRPs are initialized with a status code of STATUS_NOT_SUPPORTED */
979 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
980 Irp->IoStatus.Information = 0;
981
982 IrpSp = IoGetNextIrpStackLocation(Irp);
983 IrpSp->MinorFunction = (UCHAR)MinorFunction;
984
985 if (Stack)
986 {
987 RtlCopyMemory(&IrpSp->Parameters,
988 &Stack->Parameters,
989 sizeof(Stack->Parameters));
990 }
991
992 Status = IoCallDriver(TopDeviceObject, Irp);
993 if (Status == STATUS_PENDING)
994 {
995 KeWaitForSingleObject(&Event,
996 Executive,
997 KernelMode,
998 FALSE,
999 NULL);
1000 Status = IoStatusBlock->Status;
1001 }
1002
1003 ObDereferenceObject(TopDeviceObject);
1004
1005 return Status;
1006 }
1007
1008
1009 NTSTATUS
1010 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
1011 {
1012 PDEVICE_NODE ParentDeviceNode;
1013 PDEVICE_NODE ChildDeviceNode;
1014 NTSTATUS Status;
1015
1016 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1017 ParentDeviceNode = Context->DeviceNode;
1018
1019 /* Call the action routine */
1020 Status = (Context->Action)(ParentDeviceNode, Context->Context);
1021 if (!NT_SUCCESS(Status))
1022 {
1023 return Status;
1024 }
1025
1026 /* Traversal of all children nodes */
1027 for (ChildDeviceNode = ParentDeviceNode->Child;
1028 ChildDeviceNode != NULL;
1029 ChildDeviceNode = ChildDeviceNode->NextSibling)
1030 {
1031 /* Pass the current device node to the action routine */
1032 Context->DeviceNode = ChildDeviceNode;
1033
1034 Status = IopTraverseDeviceTreeNode(Context);
1035 if (!NT_SUCCESS(Status))
1036 {
1037 return Status;
1038 }
1039 }
1040
1041 return Status;
1042 }
1043
1044
1045 NTSTATUS
1046 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
1047 {
1048 NTSTATUS Status;
1049
1050 DPRINT("Context 0x%p\n", Context);
1051
1052 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
1053 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
1054
1055 /* Start from the specified device node */
1056 Context->DeviceNode = Context->FirstDeviceNode;
1057
1058 /* Recursively traverse the device tree */
1059 Status = IopTraverseDeviceTreeNode(Context);
1060 if (Status == STATUS_UNSUCCESSFUL)
1061 {
1062 /* The action routine just wanted to terminate the traversal with status
1063 code STATUS_SUCCESS */
1064 Status = STATUS_SUCCESS;
1065 }
1066
1067 return Status;
1068 }
1069
1070
1071 /*
1072 * IopCreateDeviceKeyPath
1073 *
1074 * Creates a registry key
1075 *
1076 * Parameters
1077 * RegistryPath
1078 * Name of the key to be created.
1079 * Handle
1080 * Handle to the newly created key
1081 *
1082 * Remarks
1083 * This method can create nested trees, so parent of RegistryPath can
1084 * be not existant, and will be created if needed.
1085 */
1086 NTSTATUS
1087 NTAPI
1088 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
1089 OUT PHANDLE Handle)
1090 {
1091 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
1092 HANDLE hParent = NULL, hKey;
1093 OBJECT_ATTRIBUTES ObjectAttributes;
1094 UNICODE_STRING KeyName;
1095 LPCWSTR Current, Last;
1096 ULONG dwLength;
1097 NTSTATUS Status;
1098
1099 /* Assume failure */
1100 *Handle = NULL;
1101
1102 /* Open root key for device instances */
1103 InitializeObjectAttributes(&ObjectAttributes,
1104 &EnumU,
1105 OBJ_CASE_INSENSITIVE,
1106 NULL,
1107 NULL);
1108 Status = ZwOpenKey(&hParent,
1109 KEY_CREATE_SUB_KEY,
1110 &ObjectAttributes);
1111 if (!NT_SUCCESS(Status))
1112 {
1113 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
1114 return Status;
1115 }
1116
1117 Current = KeyName.Buffer = RegistryPath->Buffer;
1118 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
1119
1120 /* Go up to the end of the string */
1121 while (Current <= Last)
1122 {
1123 if (Current != Last && *Current != '\\')
1124 {
1125 /* Not the end of the string and not a separator */
1126 Current++;
1127 continue;
1128 }
1129
1130 /* Prepare relative key name */
1131 dwLength = (ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer;
1132 KeyName.MaximumLength = KeyName.Length = dwLength;
1133 DPRINT("Create '%wZ'\n", &KeyName);
1134
1135 /* Open key */
1136 InitializeObjectAttributes(&ObjectAttributes,
1137 &KeyName,
1138 OBJ_CASE_INSENSITIVE,
1139 hParent,
1140 NULL);
1141 Status = ZwCreateKey(&hKey,
1142 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
1143 &ObjectAttributes,
1144 0,
1145 NULL,
1146 0,
1147 NULL);
1148
1149 /* Close parent key handle, we don't need it anymore */
1150 if (hParent)
1151 ZwClose(hParent);
1152
1153 /* Key opening/creating failed? */
1154 if (!NT_SUCCESS(Status))
1155 {
1156 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
1157 return Status;
1158 }
1159
1160 /* Check if it is the end of the string */
1161 if (Current == Last)
1162 {
1163 /* Yes, return success */
1164 *Handle = hKey;
1165 return STATUS_SUCCESS;
1166 }
1167
1168 /* Start with this new parent key */
1169 hParent = hKey;
1170 Current++;
1171 KeyName.Buffer = (LPWSTR)Current;
1172 }
1173
1174 return STATUS_UNSUCCESSFUL;
1175 }
1176
1177
1178 static
1179 NTSTATUS
1180 IopSetDeviceInstanceData(HANDLE InstanceKey,
1181 PDEVICE_NODE DeviceNode)
1182 {
1183 OBJECT_ATTRIBUTES ObjectAttributes;
1184 UNICODE_STRING KeyName;
1185 HANDLE LogConfKey;
1186 ULONG ResCount;
1187 ULONG ListSize, ResultLength;
1188 NTSTATUS Status;
1189
1190 DPRINT("IopSetDeviceInstanceData() called\n");
1191
1192 /* Create the 'LogConf' key */
1193 RtlInitUnicodeString(&KeyName, L"LogConf");
1194 InitializeObjectAttributes(&ObjectAttributes,
1195 &KeyName,
1196 OBJ_CASE_INSENSITIVE,
1197 InstanceKey,
1198 NULL);
1199 Status = ZwCreateKey(&LogConfKey,
1200 KEY_ALL_ACCESS,
1201 &ObjectAttributes,
1202 0,
1203 NULL,
1204 0,
1205 NULL);
1206 if (NT_SUCCESS(Status))
1207 {
1208 /* Set 'BootConfig' value */
1209 if (DeviceNode->BootResources != NULL)
1210 {
1211 ResCount = DeviceNode->BootResources->Count;
1212 if (ResCount != 0)
1213 {
1214 ListSize = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
1215
1216 RtlInitUnicodeString(&KeyName, L"BootConfig");
1217 Status = ZwSetValueKey(LogConfKey,
1218 &KeyName,
1219 0,
1220 REG_RESOURCE_LIST,
1221 &DeviceNode->BootResources,
1222 ListSize);
1223 }
1224 }
1225
1226 /* Set 'BasicConfigVector' value */
1227 if (DeviceNode->ResourceRequirements != NULL &&
1228 DeviceNode->ResourceRequirements->ListSize != 0)
1229 {
1230 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1231 Status = ZwSetValueKey(LogConfKey,
1232 &KeyName,
1233 0,
1234 REG_RESOURCE_REQUIREMENTS_LIST,
1235 DeviceNode->ResourceRequirements,
1236 DeviceNode->ResourceRequirements->ListSize);
1237 }
1238
1239 ZwClose(LogConfKey);
1240 }
1241
1242 /* Set the 'ConfigFlags' value */
1243 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1244 Status = ZwQueryValueKey(InstanceKey,
1245 &KeyName,
1246 KeyValueBasicInformation,
1247 NULL,
1248 0,
1249 &ResultLength);
1250 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1251 {
1252 /* Write the default value */
1253 ULONG DefaultConfigFlags = 0;
1254 Status = ZwSetValueKey(InstanceKey,
1255 &KeyName,
1256 0,
1257 REG_DWORD,
1258 &DefaultConfigFlags,
1259 sizeof(DefaultConfigFlags));
1260 }
1261
1262 DPRINT("IopSetDeviceInstanceData() done\n");
1263
1264 return STATUS_SUCCESS;
1265 }
1266
1267
1268 static NTSTATUS
1269 IopAssignDeviceResources(
1270 IN PDEVICE_NODE DeviceNode,
1271 OUT ULONG *pRequiredSize)
1272 {
1273 PIO_RESOURCE_LIST ResourceList;
1274 PIO_RESOURCE_DESCRIPTOR ResourceDescriptor;
1275 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw;
1276 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1277 ULONG NumberOfResources = 0;
1278 ULONG Size;
1279 ULONG i, j;
1280 NTSTATUS Status;
1281
1282 if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
1283 {
1284 /* No resource needed for this device */
1285 DeviceNode->ResourceList = NULL;
1286 return STATUS_SUCCESS;
1287 }
1288
1289 /* Fill DeviceNode->ResourceList
1290 * FIXME: the PnP arbiter should go there!
1291 * Actually, use the BootResources if provided, else the resource list #0
1292 */
1293
1294 if (DeviceNode->BootResources)
1295 {
1296 /* Browse the boot resources to know if we have some custom structures */
1297 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1298 for (i = 0; i < DeviceNode->BootResources->Count; i++)
1299 {
1300 pPartialResourceList = &DeviceNode->BootResources->List[i].PartialResourceList;
1301 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
1302 + pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1303 for (j = 0; j < pPartialResourceList->Count; j++)
1304 {
1305 if (pPartialResourceList->PartialDescriptors[j].Type == CmResourceTypeDeviceSpecific)
1306 Size += pPartialResourceList->PartialDescriptors[j].u.DeviceSpecificData.DataSize;
1307 }
1308 }
1309
1310 DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
1311 if (!DeviceNode->ResourceList)
1312 {
1313 Status = STATUS_NO_MEMORY;
1314 goto ByeBye;
1315 }
1316 RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, Size);
1317
1318 *pRequiredSize = Size;
1319 return STATUS_SUCCESS;
1320 }
1321
1322 /* Ok, here, we have to use the device requirement list */
1323 ResourceList = &DeviceNode->ResourceRequirements->List[0];
1324 if (ResourceList->Version != 1 || ResourceList->Revision != 1)
1325 {
1326 Status = STATUS_REVISION_MISMATCH;
1327 goto ByeBye;
1328 }
1329
1330 Size = sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1331 *pRequiredSize = Size;
1332 DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
1333 if (!DeviceNode->ResourceList)
1334 {
1335 Status = STATUS_NO_MEMORY;
1336 goto ByeBye;
1337 }
1338
1339 DeviceNode->ResourceList->Count = 1;
1340 DeviceNode->ResourceList->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType;
1341 DeviceNode->ResourceList->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber;
1342 DeviceNode->ResourceList->List[0].PartialResourceList.Version = 1;
1343 DeviceNode->ResourceList->List[0].PartialResourceList.Revision = 1;
1344
1345 for (i = 0; i < ResourceList->Count; i++)
1346 {
1347 ResourceDescriptor = &ResourceList->Descriptors[i];
1348
1349 if (ResourceDescriptor->Option == 0 || ResourceDescriptor->Option == IO_RESOURCE_PREFERRED)
1350 {
1351 DescriptorRaw = &DeviceNode->ResourceList->List[0].PartialResourceList.PartialDescriptors[NumberOfResources];
1352 NumberOfResources++;
1353
1354 /* Copy ResourceDescriptor to DescriptorRaw and DescriptorTranslated */
1355 DescriptorRaw->Type = ResourceDescriptor->Type;
1356 DescriptorRaw->ShareDisposition = ResourceDescriptor->ShareDisposition;
1357 DescriptorRaw->Flags = ResourceDescriptor->Flags;
1358 switch (ResourceDescriptor->Type)
1359 {
1360 case CmResourceTypePort:
1361 {
1362 DescriptorRaw->u.Port.Start = ResourceDescriptor->u.Port.MinimumAddress;
1363 DescriptorRaw->u.Port.Length = ResourceDescriptor->u.Port.Length;
1364 break;
1365 }
1366 case CmResourceTypeInterrupt:
1367 {
1368 INTERFACE_TYPE BusType;
1369 ULONG SlotNumber;
1370 ULONG ret;
1371 UCHAR Irq;
1372
1373 DescriptorRaw->u.Interrupt.Level = 0;
1374 DescriptorRaw->u.Interrupt.Vector = ResourceDescriptor->u.Interrupt.MinimumVector;
1375 /* FIXME: HACK: if we have a PCI device, we try
1376 * to keep the IRQ assigned by the BIOS */
1377 if (NT_SUCCESS(IoGetDeviceProperty(
1378 DeviceNode->PhysicalDeviceObject,
1379 DevicePropertyLegacyBusType,
1380 sizeof(INTERFACE_TYPE),
1381 &BusType,
1382 &ret)) && BusType == PCIBus)
1383 {
1384 /* We have a PCI bus */
1385 if (NT_SUCCESS(IoGetDeviceProperty(
1386 DeviceNode->PhysicalDeviceObject,
1387 DevicePropertyAddress,
1388 sizeof(ULONG),
1389 &SlotNumber,
1390 &ret)) && SlotNumber > 0)
1391 {
1392 /* We have a good slot number */
1393 ret = HalGetBusDataByOffset(PCIConfiguration,
1394 DeviceNode->ResourceRequirements->BusNumber,
1395 SlotNumber,
1396 &Irq,
1397 0x3c /* PCI_INTERRUPT_LINE */,
1398 sizeof(UCHAR));
1399 if (ret != 0 && ret != 2
1400 && ResourceDescriptor->u.Interrupt.MinimumVector <= Irq
1401 && ResourceDescriptor->u.Interrupt.MaximumVector >= Irq)
1402 {
1403 /* The device already has an assigned IRQ */
1404 DescriptorRaw->u.Interrupt.Vector = Irq;
1405 }
1406 else
1407 {
1408 DPRINT1("Trying to assign IRQ 0x%lx to %wZ\n",
1409 DescriptorRaw->u.Interrupt.Vector,
1410 &DeviceNode->InstancePath);
1411 Irq = (UCHAR)DescriptorRaw->u.Interrupt.Vector;
1412 ret = HalSetBusDataByOffset(PCIConfiguration,
1413 DeviceNode->ResourceRequirements->BusNumber,
1414 SlotNumber,
1415 &Irq,
1416 0x3c /* PCI_INTERRUPT_LINE */,
1417 sizeof(UCHAR));
1418 if (ret == 0 || ret == 2)
1419 KEBUGCHECK(0);
1420 }
1421 }
1422 }
1423 break;
1424 }
1425 case CmResourceTypeMemory:
1426 {
1427 DescriptorRaw->u.Memory.Start = ResourceDescriptor->u.Memory.MinimumAddress;
1428 DescriptorRaw->u.Memory.Length = ResourceDescriptor->u.Memory.Length;
1429 break;
1430 }
1431 case CmResourceTypeDma:
1432 {
1433 DescriptorRaw->u.Dma.Channel = ResourceDescriptor->u.Dma.MinimumChannel;
1434 DescriptorRaw->u.Dma.Port = 0; /* FIXME */
1435 DescriptorRaw->u.Dma.Reserved1 = 0;
1436 break;
1437 }
1438 case CmResourceTypeBusNumber:
1439 {
1440 DescriptorRaw->u.BusNumber.Start = ResourceDescriptor->u.BusNumber.MinBusNumber;
1441 DescriptorRaw->u.BusNumber.Length = ResourceDescriptor->u.BusNumber.Length;
1442 DescriptorRaw->u.BusNumber.Reserved = ResourceDescriptor->u.BusNumber.Reserved;
1443 break;
1444 }
1445 /*CmResourceTypeDevicePrivate:
1446 case CmResourceTypePcCardConfig:
1447 case CmResourceTypeMfCardConfig:
1448 {
1449 RtlCopyMemory(
1450 &DescriptorRaw->u.DevicePrivate,
1451 &ResourceDescriptor->u.DevicePrivate,
1452 sizeof(ResourceDescriptor->u.DevicePrivate));
1453 RtlCopyMemory(
1454 &DescriptorTranslated->u.DevicePrivate,
1455 &ResourceDescriptor->u.DevicePrivate,
1456 sizeof(ResourceDescriptor->u.DevicePrivate));
1457 break;
1458 }*/
1459 default:
1460 DPRINT1("IopAssignDeviceResources(): unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
1461 NumberOfResources--;
1462 }
1463 }
1464
1465 }
1466
1467 DeviceNode->ResourceList->List[0].PartialResourceList.Count = NumberOfResources;
1468
1469 return STATUS_SUCCESS;
1470
1471 ByeBye:
1472 if (DeviceNode->ResourceList)
1473 {
1474 ExFreePool(DeviceNode->ResourceList);
1475 DeviceNode->ResourceList = NULL;
1476 }
1477 return Status;
1478 }
1479
1480
1481 static NTSTATUS
1482 IopTranslateDeviceResources(
1483 IN PDEVICE_NODE DeviceNode,
1484 IN ULONG RequiredSize)
1485 {
1486 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1487 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
1488 ULONG i, j;
1489 NTSTATUS Status;
1490
1491 if (!DeviceNode->ResourceList)
1492 {
1493 DeviceNode->ResourceListTranslated = NULL;
1494 return STATUS_SUCCESS;
1495 }
1496
1497 /* That's easy to translate a resource list. Just copy the
1498 * untranslated one and change few fields in the copy
1499 */
1500 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, RequiredSize);
1501 if (!DeviceNode->ResourceListTranslated)
1502 {
1503 Status =STATUS_NO_MEMORY;
1504 goto cleanup;
1505 }
1506 RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, RequiredSize);
1507
1508 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
1509 {
1510 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
1511 for (j = 0; j < pPartialResourceList->Count; j++)
1512 {
1513 DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
1514 DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
1515 switch (DescriptorRaw->Type)
1516 {
1517 case CmResourceTypePort:
1518 {
1519 ULONG AddressSpace = 0; /* IO space */
1520 if (!HalTranslateBusAddress(
1521 DeviceNode->ResourceList->List[i].InterfaceType,
1522 DeviceNode->ResourceList->List[i].BusNumber,
1523 DescriptorRaw->u.Port.Start,
1524 &AddressSpace,
1525 &DescriptorTranslated->u.Port.Start))
1526 {
1527 Status = STATUS_UNSUCCESSFUL;
1528 goto cleanup;
1529 }
1530 break;
1531 }
1532 case CmResourceTypeInterrupt:
1533 {
1534 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
1535 DeviceNode->ResourceList->List[i].InterfaceType,
1536 DeviceNode->ResourceList->List[i].BusNumber,
1537 DescriptorRaw->u.Interrupt.Level,
1538 DescriptorRaw->u.Interrupt.Vector,
1539 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
1540 &DescriptorRaw->u.Interrupt.Affinity);
1541 break;
1542 }
1543 case CmResourceTypeMemory:
1544 {
1545 ULONG AddressSpace = 1; /* Memory space */
1546 if (!HalTranslateBusAddress(
1547 DeviceNode->ResourceList->List[i].InterfaceType,
1548 DeviceNode->ResourceList->List[i].BusNumber,
1549 DescriptorRaw->u.Memory.Start,
1550 &AddressSpace,
1551 &DescriptorTranslated->u.Memory.Start))
1552 {
1553 Status = STATUS_UNSUCCESSFUL;
1554 goto cleanup;
1555 }
1556 }
1557
1558 case CmResourceTypeDma:
1559 case CmResourceTypeBusNumber:
1560 case CmResourceTypeDeviceSpecific:
1561 /* Nothing to do */
1562 break;
1563 default:
1564 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
1565 Status = STATUS_NOT_IMPLEMENTED;
1566 goto cleanup;
1567 }
1568 }
1569 }
1570 return STATUS_SUCCESS;
1571
1572 cleanup:
1573 /* Yes! Also delete ResourceList because ResourceList and
1574 * ResourceListTranslated should be a pair! */
1575 ExFreePool(DeviceNode->ResourceList);
1576 DeviceNode->ResourceList = NULL;
1577 if (DeviceNode->ResourceListTranslated)
1578 {
1579 ExFreePool(DeviceNode->ResourceListTranslated);
1580 DeviceNode->ResourceList = NULL;
1581 }
1582 return Status;
1583 }
1584
1585
1586 /*
1587 * IopGetParentIdPrefix
1588 *
1589 * Retrieve (or create) a string which identifies a device.
1590 *
1591 * Parameters
1592 * DeviceNode
1593 * Pointer to device node.
1594 * ParentIdPrefix
1595 * Pointer to the string where is returned the parent node identifier
1596 *
1597 * Remarks
1598 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1599 * valid and its Buffer field is NULL-terminated. The caller needs to
1600 * to free the string with RtlFreeUnicodeString when it is no longer
1601 * needed.
1602 */
1603
1604 NTSTATUS
1605 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1606 PUNICODE_STRING ParentIdPrefix)
1607 {
1608 ULONG KeyNameBufferLength;
1609 PWSTR KeyNameBuffer = NULL;
1610 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1611 UNICODE_STRING KeyName;
1612 UNICODE_STRING KeyValue;
1613 UNICODE_STRING ValueName;
1614 OBJECT_ATTRIBUTES ObjectAttributes;
1615 HANDLE hKey = NULL;
1616 ULONG crc32;
1617 NTSTATUS Status;
1618
1619 /* HACK: As long as some devices have a NULL device
1620 * instance path, the following test is required :(
1621 */
1622 if (DeviceNode->Parent->InstancePath.Length == 0)
1623 {
1624 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1625 &DeviceNode->InstancePath);
1626 return STATUS_UNSUCCESSFUL;
1627 }
1628
1629 /* 1. Try to retrieve ParentIdPrefix from registry */
1630 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1631 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
1632 if (!ParentIdPrefixInformation)
1633 {
1634 Status = STATUS_INSUFFICIENT_RESOURCES;
1635 goto cleanup;
1636 }
1637 KeyNameBuffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
1638 if (!KeyNameBuffer)
1639 {
1640 Status = STATUS_INSUFFICIENT_RESOURCES;
1641 goto cleanup;
1642 }
1643 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1644 wcscat(KeyNameBuffer, DeviceNode->Parent->InstancePath.Buffer);
1645 RtlInitUnicodeString(&KeyName, KeyNameBuffer);
1646 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1647 Status = ZwOpenKey(&hKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes);
1648 if (!NT_SUCCESS(Status))
1649 goto cleanup;
1650 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1651 Status = ZwQueryValueKey(
1652 hKey, &ValueName,
1653 KeyValuePartialInformation, ParentIdPrefixInformation,
1654 KeyNameBufferLength, &KeyNameBufferLength);
1655 if (NT_SUCCESS(Status))
1656 {
1657 if (ParentIdPrefixInformation->Type != REG_SZ)
1658 Status = STATUS_UNSUCCESSFUL;
1659 else
1660 {
1661 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1662 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1663 }
1664 goto cleanup;
1665 }
1666 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1667 {
1668 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1669 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1670 goto cleanup;
1671 }
1672
1673 /* 2. Create the ParentIdPrefix value */
1674 crc32 = RtlComputeCrc32(0,
1675 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1676 DeviceNode->Parent->InstancePath.Length);
1677
1678 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
1679 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
1680
1681 /* 3. Try to write the ParentIdPrefix to registry */
1682 Status = ZwSetValueKey(hKey,
1683 &ValueName,
1684 0,
1685 REG_SZ,
1686 (PVOID)KeyValue.Buffer,
1687 (wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1688
1689 cleanup:
1690 if (NT_SUCCESS(Status))
1691 {
1692 /* Duplicate the string to return it */
1693 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
1694 }
1695 ExFreePool(ParentIdPrefixInformation);
1696 ExFreePool(KeyNameBuffer);
1697 if (hKey != NULL)
1698 ZwClose(hKey);
1699 return Status;
1700 }
1701
1702
1703 /*
1704 * IopActionInterrogateDeviceStack
1705 *
1706 * Retrieve information for all (direct) child nodes of a parent node.
1707 *
1708 * Parameters
1709 * DeviceNode
1710 * Pointer to device node.
1711 * Context
1712 * Pointer to parent node to retrieve child node information for.
1713 *
1714 * Remarks
1715 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1716 * when we reach a device node which is not a direct child of the device
1717 * node for which we retrieve information of child nodes for. Any errors
1718 * that occur is logged instead so that all child services have a chance
1719 * of being interrogated.
1720 */
1721
1722 NTSTATUS
1723 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
1724 PVOID Context)
1725 {
1726 IO_STATUS_BLOCK IoStatusBlock;
1727 PDEVICE_NODE ParentDeviceNode;
1728 WCHAR InstancePath[MAX_PATH];
1729 IO_STACK_LOCATION Stack;
1730 NTSTATUS Status;
1731 PWSTR KeyBuffer;
1732 PWSTR Ptr;
1733 USHORT Length;
1734 USHORT TotalLength;
1735 ULONG RequiredLength;
1736 LCID LocaleId;
1737 HANDLE InstanceKey = NULL;
1738 UNICODE_STRING ValueName;
1739 UNICODE_STRING ParentIdPrefix = { 0 };
1740 DEVICE_CAPABILITIES DeviceCapabilities;
1741
1742 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1743 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1744
1745 ParentDeviceNode = (PDEVICE_NODE)Context;
1746
1747 /*
1748 * We are called for the parent too, but we don't need to do special
1749 * handling for this node
1750 */
1751
1752 if (DeviceNode == ParentDeviceNode)
1753 {
1754 DPRINT("Success\n");
1755 return STATUS_SUCCESS;
1756 }
1757
1758 /*
1759 * Make sure this device node is a direct child of the parent device node
1760 * that is given as an argument
1761 */
1762
1763 if (DeviceNode->Parent != ParentDeviceNode)
1764 {
1765 /* Stop the traversal immediately and indicate successful operation */
1766 DPRINT("Stop\n");
1767 return STATUS_UNSUCCESSFUL;
1768 }
1769
1770 /* Get Locale ID */
1771 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
1772 if (!NT_SUCCESS(Status))
1773 {
1774 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
1775 return Status;
1776 }
1777
1778 /*
1779 * FIXME: For critical errors, cleanup and disable device, but always
1780 * return STATUS_SUCCESS.
1781 */
1782
1783 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1784
1785 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1786 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1787 &IoStatusBlock,
1788 IRP_MN_QUERY_ID,
1789 &Stack);
1790 if (NT_SUCCESS(Status))
1791 {
1792 /* Copy the device id string */
1793 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
1794
1795 /*
1796 * FIXME: Check for valid characters, if there is invalid characters
1797 * then bugcheck.
1798 */
1799 }
1800 else
1801 {
1802 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1803 }
1804
1805 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
1806
1807 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1808 if (!NT_SUCCESS(Status))
1809 {
1810 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1811 }
1812
1813 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
1814
1815 if (!DeviceCapabilities.UniqueID)
1816 {
1817 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1818 DPRINT("Instance ID is not unique\n");
1819 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1820 if (!NT_SUCCESS(Status))
1821 {
1822 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1823 }
1824 }
1825
1826 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1827
1828 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1829 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1830 &IoStatusBlock,
1831 IRP_MN_QUERY_ID,
1832 &Stack);
1833 if (NT_SUCCESS(Status))
1834 {
1835 /* Append the instance id string */
1836 wcscat(InstancePath, L"\\");
1837 if (ParentIdPrefix.Length > 0)
1838 {
1839 /* Add information from parent bus device to InstancePath */
1840 wcscat(InstancePath, ParentIdPrefix.Buffer);
1841 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
1842 wcscat(InstancePath, L"&");
1843 }
1844 if (IoStatusBlock.Information)
1845 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1846
1847 /*
1848 * FIXME: Check for valid characters, if there is invalid characters
1849 * then bugcheck
1850 */
1851 }
1852 else
1853 {
1854 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1855 }
1856 RtlFreeUnicodeString(&ParentIdPrefix);
1857
1858 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
1859 {
1860 DPRINT("No resources\n");
1861 /* FIXME: Cleanup and disable device */
1862 }
1863
1864 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1865
1866 /*
1867 * Create registry key for the instance id, if it doesn't exist yet
1868 */
1869 KeyBuffer = ExAllocatePool(
1870 PagedPool,
1871 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
1872 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1873 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
1874 Status = IopCreateDeviceKeyPath(/*KeyBuffer*/&DeviceNode->InstancePath, &InstanceKey);
1875 ExFreePool(KeyBuffer);
1876 if (!NT_SUCCESS(Status))
1877 {
1878 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1879 }
1880
1881
1882 {
1883 /* Set 'Capabilities' value */
1884 RtlInitUnicodeString(&ValueName, L"Capabilities");
1885 Status = ZwSetValueKey(InstanceKey,
1886 &ValueName,
1887 0,
1888 REG_DWORD,
1889 (PVOID)&DeviceNode->CapabilityFlags,
1890 sizeof(ULONG));
1891
1892 /* Set 'UINumber' value */
1893 if (DeviceCapabilities.UINumber != (ULONG)-1)
1894 {
1895 RtlInitUnicodeString(&ValueName, L"UINumber");
1896 Status = ZwSetValueKey(InstanceKey,
1897 &ValueName,
1898 0,
1899 REG_DWORD,
1900 &DeviceCapabilities.UINumber,
1901 sizeof(ULONG));
1902 }
1903 }
1904
1905 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1906
1907 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1908 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1909 &IoStatusBlock,
1910 IRP_MN_QUERY_ID,
1911 &Stack);
1912 if (NT_SUCCESS(Status))
1913 {
1914 /*
1915 * FIXME: Check for valid characters, if there is invalid characters
1916 * then bugcheck.
1917 */
1918 TotalLength = 0;
1919 Ptr = (PWSTR)IoStatusBlock.Information;
1920 DPRINT("Hardware IDs:\n");
1921 while (*Ptr)
1922 {
1923 DPRINT(" %S\n", Ptr);
1924 Length = wcslen(Ptr) + 1;
1925
1926 Ptr += Length;
1927 TotalLength += Length;
1928 }
1929 DPRINT("TotalLength: %hu\n", TotalLength);
1930 DPRINT("\n");
1931
1932 RtlInitUnicodeString(&ValueName, L"HardwareID");
1933 Status = ZwSetValueKey(InstanceKey,
1934 &ValueName,
1935 0,
1936 REG_MULTI_SZ,
1937 (PVOID)IoStatusBlock.Information,
1938 (TotalLength + 1) * sizeof(WCHAR));
1939 if (!NT_SUCCESS(Status))
1940 {
1941 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1942 }
1943 }
1944 else
1945 {
1946 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1947 }
1948
1949 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1950
1951 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1952 Status = IopInitiatePnpIrp(
1953 DeviceNode->PhysicalDeviceObject,
1954 &IoStatusBlock,
1955 IRP_MN_QUERY_ID,
1956 &Stack);
1957 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1958 {
1959 /*
1960 * FIXME: Check for valid characters, if there is invalid characters
1961 * then bugcheck.
1962 */
1963 TotalLength = 0;
1964 Ptr = (PWSTR)IoStatusBlock.Information;
1965 DPRINT("Compatible IDs:\n");
1966 while (*Ptr)
1967 {
1968 DPRINT(" %S\n", Ptr);
1969 Length = wcslen(Ptr) + 1;
1970
1971 Ptr += Length;
1972 TotalLength += Length;
1973 }
1974 DPRINT("TotalLength: %hu\n", TotalLength);
1975 DPRINT("\n");
1976
1977 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1978 Status = ZwSetValueKey(InstanceKey,
1979 &ValueName,
1980 0,
1981 REG_MULTI_SZ,
1982 (PVOID)IoStatusBlock.Information,
1983 (TotalLength + 1) * sizeof(WCHAR));
1984 if (!NT_SUCCESS(Status))
1985 {
1986 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1987 }
1988 }
1989 else
1990 {
1991 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1992 }
1993
1994 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1995
1996 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
1997 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
1998 Status = IopInitiatePnpIrp(
1999 DeviceNode->PhysicalDeviceObject,
2000 &IoStatusBlock,
2001 IRP_MN_QUERY_DEVICE_TEXT,
2002 &Stack);
2003 /* This key is mandatory, so even if the Irp fails, we still write it */
2004 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2005 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2006 {
2007 if (NT_SUCCESS(Status) &&
2008 IoStatusBlock.Information &&
2009 (*(PWSTR)IoStatusBlock.Information != 0))
2010 {
2011 /* This key is overriden when a driver is installed. Don't write the
2012 * new description if another one already exists */
2013 Status = ZwSetValueKey(InstanceKey,
2014 &ValueName,
2015 0,
2016 REG_SZ,
2017 (PVOID)IoStatusBlock.Information,
2018 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2019 }
2020 else
2021 {
2022 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2023 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2024
2025 Status = ZwSetValueKey(InstanceKey,
2026 &ValueName,
2027 0,
2028 REG_SZ,
2029 DeviceDesc.Buffer,
2030 DeviceDesc.MaximumLength);
2031
2032 if (!NT_SUCCESS(Status))
2033 {
2034 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2035 }
2036
2037 }
2038 }
2039
2040 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2041
2042 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2043 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2044 Status = IopInitiatePnpIrp(
2045 DeviceNode->PhysicalDeviceObject,
2046 &IoStatusBlock,
2047 IRP_MN_QUERY_DEVICE_TEXT,
2048 &Stack);
2049 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2050 {
2051 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
2052 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2053 Status = ZwSetValueKey(InstanceKey,
2054 &ValueName,
2055 0,
2056 REG_SZ,
2057 (PVOID)IoStatusBlock.Information,
2058 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2059 if (!NT_SUCCESS(Status))
2060 {
2061 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2062 }
2063 }
2064 else
2065 {
2066 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2067 }
2068
2069 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2070
2071 Status = IopInitiatePnpIrp(
2072 DeviceNode->PhysicalDeviceObject,
2073 &IoStatusBlock,
2074 IRP_MN_QUERY_BUS_INFORMATION,
2075 NULL);
2076 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2077 {
2078 PPNP_BUS_INFORMATION BusInformation =
2079 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2080
2081 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2082 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2083 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2084 ExFreePool(BusInformation);
2085 }
2086 else
2087 {
2088 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2089
2090 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2091 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2092 DeviceNode->ChildBusTypeIndex = -1;
2093 }
2094
2095 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2096
2097 Status = IopInitiatePnpIrp(
2098 DeviceNode->PhysicalDeviceObject,
2099 &IoStatusBlock,
2100 IRP_MN_QUERY_RESOURCES,
2101 NULL);
2102 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2103 {
2104 DeviceNode->BootResources =
2105 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2106 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
2107 }
2108 else
2109 {
2110 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2111 DeviceNode->BootResources = NULL;
2112 }
2113
2114 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2115
2116 Status = IopInitiatePnpIrp(
2117 DeviceNode->PhysicalDeviceObject,
2118 &IoStatusBlock,
2119 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2120 NULL);
2121 if (NT_SUCCESS(Status))
2122 {
2123 DeviceNode->ResourceRequirements =
2124 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2125 if (IoStatusBlock.Information)
2126 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_REPORTED);
2127 else
2128 IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED);
2129 }
2130 else
2131 {
2132 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2133 DeviceNode->ResourceRequirements = NULL;
2134 }
2135
2136
2137 if (InstanceKey != NULL)
2138 {
2139 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2140 }
2141
2142 ZwClose(InstanceKey);
2143
2144 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2145
2146 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2147 {
2148 /* Report the device to the user-mode pnp manager */
2149 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2150 &DeviceNode->InstancePath);
2151 }
2152
2153 return STATUS_SUCCESS;
2154 }
2155
2156 /*
2157 * @implemented
2158 */
2159 VOID
2160 NTAPI
2161 IoSynchronousInvalidateDeviceRelations(
2162 IN PDEVICE_OBJECT DeviceObject,
2163 IN DEVICE_RELATION_TYPE Type)
2164 {
2165 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2166 DEVICETREE_TRAVERSE_CONTEXT Context;
2167 PDEVICE_RELATIONS DeviceRelations;
2168 IO_STATUS_BLOCK IoStatusBlock;
2169 PDEVICE_NODE ChildDeviceNode;
2170 IO_STACK_LOCATION Stack;
2171 BOOLEAN BootDrivers;
2172 OBJECT_ATTRIBUTES ObjectAttributes;
2173 UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"\\SystemRoot");
2174 HANDLE Handle;
2175 NTSTATUS Status;
2176 ULONG i;
2177
2178 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2179
2180 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2181
2182 Stack.Parameters.QueryDeviceRelations.Type = Type;
2183
2184 Status = IopInitiatePnpIrp(
2185 DeviceObject,
2186 &IoStatusBlock,
2187 IRP_MN_QUERY_DEVICE_RELATIONS,
2188 &Stack);
2189 if (!NT_SUCCESS(Status))
2190 {
2191 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2192 return;
2193 }
2194
2195 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2196
2197 if (!DeviceRelations || DeviceRelations->Count <= 0)
2198 {
2199 DPRINT("No PDOs\n");
2200 if (DeviceRelations)
2201 {
2202 ExFreePool(DeviceRelations);
2203 }
2204 return;
2205 }
2206
2207 DPRINT("Got %d PDOs\n", DeviceRelations->Count);
2208
2209 /*
2210 * Create device nodes for all discovered devices
2211 */
2212 for (i = 0; i < DeviceRelations->Count; i++)
2213 {
2214 if (IopGetDeviceNode(DeviceRelations->Objects[i]) != NULL)
2215 {
2216 ObDereferenceObject(DeviceRelations->Objects[i]);
2217 continue;
2218 }
2219 Status = IopCreateDeviceNode(
2220 DeviceNode,
2221 DeviceRelations->Objects[i],
2222 NULL,
2223 &ChildDeviceNode);
2224 DeviceNode->Flags |= DNF_ENUMERATED;
2225 if (!NT_SUCCESS(Status))
2226 {
2227 DPRINT("No resources\n");
2228 for (i = 0; i < DeviceRelations->Count; i++)
2229 ObDereferenceObject(DeviceRelations->Objects[i]);
2230 ExFreePool(DeviceRelations);
2231 return;
2232 }
2233 }
2234 ExFreePool(DeviceRelations);
2235
2236 /*
2237 * Retrieve information about all discovered children from the bus driver
2238 */
2239 IopInitDeviceTreeTraverseContext(
2240 &Context,
2241 DeviceNode,
2242 IopActionInterrogateDeviceStack,
2243 DeviceNode);
2244
2245 Status = IopTraverseDeviceTree(&Context);
2246 if (!NT_SUCCESS(Status))
2247 {
2248 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2249 return;
2250 }
2251
2252 /*
2253 * Retrieve configuration from the registry for discovered children
2254 */
2255 IopInitDeviceTreeTraverseContext(
2256 &Context,
2257 DeviceNode,
2258 IopActionConfigureChildServices,
2259 DeviceNode);
2260
2261 Status = IopTraverseDeviceTree(&Context);
2262 if (!NT_SUCCESS(Status))
2263 {
2264 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2265 return;
2266 }
2267
2268 /*
2269 * Get the state of the system boot. If the \\SystemRoot link isn't
2270 * created yet, we will assume that it's possible to load only boot
2271 * drivers.
2272 */
2273 InitializeObjectAttributes(
2274 &ObjectAttributes,
2275 &LinkName,
2276 0,
2277 NULL,
2278 NULL);
2279 Status = ZwOpenFile(
2280 &Handle,
2281 FILE_ALL_ACCESS,
2282 &ObjectAttributes,
2283 &IoStatusBlock,
2284 0,
2285 0);
2286 if (NT_SUCCESS(Status))
2287 {
2288 BootDrivers = FALSE;
2289 ZwClose(Handle);
2290 }
2291 else
2292 BootDrivers = TRUE;
2293
2294 /*
2295 * Initialize services for discovered children. Only boot drivers will
2296 * be loaded from boot driver!
2297 */
2298 Status = IopInitializePnpServices(DeviceNode, BootDrivers);
2299 if (!NT_SUCCESS(Status))
2300 {
2301 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2302 return;
2303 }
2304
2305 DPRINT("IopInvalidateDeviceRelations() finished\n");
2306 }
2307
2308 /*
2309 * IopActionConfigureChildServices
2310 *
2311 * Retrieve configuration for all (direct) child nodes of a parent node.
2312 *
2313 * Parameters
2314 * DeviceNode
2315 * Pointer to device node.
2316 * Context
2317 * Pointer to parent node to retrieve child node configuration for.
2318 *
2319 * Remarks
2320 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2321 * when we reach a device node which is not a direct child of the device
2322 * node for which we configure child services for. Any errors that occur is
2323 * logged instead so that all child services have a chance of beeing
2324 * configured.
2325 */
2326
2327 NTSTATUS
2328 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2329 PVOID Context)
2330 {
2331 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2332 PDEVICE_NODE ParentDeviceNode;
2333 PUNICODE_STRING Service;
2334 UNICODE_STRING ClassGUID;
2335 NTSTATUS Status;
2336
2337 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2338
2339 ParentDeviceNode = (PDEVICE_NODE)Context;
2340
2341 /*
2342 * We are called for the parent too, but we don't need to do special
2343 * handling for this node
2344 */
2345 if (DeviceNode == ParentDeviceNode)
2346 {
2347 DPRINT("Success\n");
2348 return STATUS_SUCCESS;
2349 }
2350
2351 /*
2352 * Make sure this device node is a direct child of the parent device node
2353 * that is given as an argument
2354 */
2355 if (DeviceNode->Parent != ParentDeviceNode)
2356 {
2357 /* Stop the traversal immediately and indicate successful operation */
2358 DPRINT("Stop\n");
2359 return STATUS_UNSUCCESSFUL;
2360 }
2361
2362 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2363 {
2364 WCHAR RegKeyBuffer[MAX_PATH];
2365 UNICODE_STRING RegKey;
2366
2367 RegKey.Length = 0;
2368 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2369 RegKey.Buffer = RegKeyBuffer;
2370
2371 /*
2372 * Retrieve configuration from Enum key
2373 */
2374
2375 Service = &DeviceNode->ServiceName;
2376
2377 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2378 RtlInitUnicodeString(Service, NULL);
2379 RtlInitUnicodeString(&ClassGUID, NULL);
2380
2381 QueryTable[0].Name = L"Service";
2382 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
2383 QueryTable[0].EntryContext = Service;
2384
2385 QueryTable[1].Name = L"ClassGUID";
2386 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2387 QueryTable[1].EntryContext = &ClassGUID;
2388 QueryTable[1].DefaultType = REG_SZ;
2389 QueryTable[1].DefaultData = L"";
2390 QueryTable[1].DefaultLength = 0;
2391
2392 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2393 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2394
2395 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2396 RegKey.Buffer, QueryTable, NULL, NULL);
2397
2398 if (!NT_SUCCESS(Status))
2399 {
2400 /* FIXME: Log the error */
2401 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2402 &DeviceNode->InstancePath, Status);
2403 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2404 return STATUS_SUCCESS;
2405 }
2406
2407 if (Service->Buffer == NULL)
2408 {
2409 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2410
2411 if (ClassGUID.Length != 0)
2412 {
2413 /* Device has a ClassGUID value, but no Service value.
2414 * Suppose it is using the NULL driver, so state the
2415 * device is started */
2416 DPRINT1("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2417 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2418 DeviceNode->Flags |= DN_STARTED;
2419 }
2420 return STATUS_SUCCESS;
2421 }
2422
2423 DPRINT("Got Service %S\n", Service->Buffer);
2424 }
2425
2426 return STATUS_SUCCESS;
2427 }
2428
2429 /*
2430 * IopActionInitChildServices
2431 *
2432 * Initialize the service for all (direct) child nodes of a parent node
2433 *
2434 * Parameters
2435 * DeviceNode
2436 * Pointer to device node.
2437 * Context
2438 * Pointer to parent node to initialize child node services for.
2439 * BootDrivers
2440 * Load only driver marked as boot start.
2441 *
2442 * Remarks
2443 * If the driver image for a service is not loaded and initialized
2444 * it is done here too. We only return a status code indicating an
2445 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2446 * not a direct child of the device node for which we initialize
2447 * child services for. Any errors that occur is logged instead so
2448 * that all child services have a chance of being initialized.
2449 */
2450
2451 NTSTATUS
2452 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2453 PVOID Context,
2454 BOOLEAN BootDrivers)
2455 {
2456 PDEVICE_NODE ParentDeviceNode;
2457 NTSTATUS Status;
2458
2459 DPRINT("IopActionInitChildServices(%p, %p, %d)\n", DeviceNode, Context,
2460 BootDrivers);
2461
2462 ParentDeviceNode = (PDEVICE_NODE)Context;
2463
2464 /*
2465 * We are called for the parent too, but we don't need to do special
2466 * handling for this node
2467 */
2468 if (DeviceNode == ParentDeviceNode)
2469 {
2470 DPRINT("Success\n");
2471 return STATUS_SUCCESS;
2472 }
2473
2474 /*
2475 * Make sure this device node is a direct child of the parent device node
2476 * that is given as an argument
2477 */
2478 #if 0
2479 if (DeviceNode->Parent != ParentDeviceNode)
2480 {
2481 /*
2482 * Stop the traversal immediately and indicate unsuccessful operation
2483 */
2484 DPRINT("Stop\n");
2485 return STATUS_UNSUCCESSFUL;
2486 }
2487 #endif
2488
2489 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) &&
2490 !IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) &&
2491 !IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED))
2492 {
2493 PLDR_DATA_TABLE_ENTRY ModuleObject;
2494 PDRIVER_OBJECT DriverObject;
2495
2496 /* Get existing DriverObject pointer (in case the driver has
2497 already been loaded and initialized) */
2498 Status = IopGetDriverObject(
2499 &DriverObject,
2500 &DeviceNode->ServiceName,
2501 FALSE);
2502
2503 if (!NT_SUCCESS(Status))
2504 {
2505 /* Driver is not initialized, try to load it */
2506 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2507
2508 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2509 {
2510 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2511 was loaded by the bootloader */
2512 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
2513 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
2514 {
2515 /* Initialize the driver */
2516 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2517 &DeviceNode->ServiceName, FALSE, &DriverObject);
2518 }
2519 else
2520 {
2521 Status = STATUS_SUCCESS;
2522 }
2523 }
2524 else
2525 {
2526 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2527 &DeviceNode->ServiceName, Status);
2528 }
2529 }
2530
2531 /* Driver is loaded and initialized at this point */
2532 if (NT_SUCCESS(Status))
2533 {
2534 /* We have a driver for this DeviceNode */
2535 DeviceNode->Flags |= DN_DRIVER_LOADED;
2536 /* Attach lower level filter drivers. */
2537 IopAttachFilterDrivers(DeviceNode, TRUE);
2538 /* Initialize the function driver for the device node */
2539 Status = IopInitializeDevice(DeviceNode, DriverObject);
2540
2541 if (NT_SUCCESS(Status))
2542 {
2543 /* Attach upper level filter drivers. */
2544 IopAttachFilterDrivers(DeviceNode, FALSE);
2545 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2546
2547 Status = IopStartDevice(DeviceNode);
2548 }
2549 else
2550 {
2551 DPRINT1("IopInitializeDevice(%wZ) failed with status 0x%08x\n",
2552 &DeviceNode->InstancePath, Status);
2553 }
2554 }
2555 else
2556 {
2557 /*
2558 * Don't disable when trying to load only boot drivers
2559 */
2560 if (!BootDrivers)
2561 {
2562 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2563 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2564 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2565 CPRINT("Initialization of service %S failed (Status %x)\n",
2566 DeviceNode->ServiceName.Buffer, Status);
2567 }
2568 }
2569 }
2570 else
2571 {
2572 DPRINT("Device %wZ is disabled or already initialized\n",
2573 &DeviceNode->InstancePath);
2574 }
2575
2576 return STATUS_SUCCESS;
2577 }
2578
2579 /*
2580 * IopActionInitAllServices
2581 *
2582 * Initialize the service for all (direct) child nodes of a parent node. This
2583 * function just calls IopActionInitChildServices with BootDrivers = FALSE.
2584 */
2585
2586 NTSTATUS
2587 IopActionInitAllServices(PDEVICE_NODE DeviceNode,
2588 PVOID Context)
2589 {
2590 return IopActionInitChildServices(DeviceNode, Context, FALSE);
2591 }
2592
2593 /*
2594 * IopActionInitBootServices
2595 *
2596 * Initialize the boot start services for all (direct) child nodes of a
2597 * parent node. This function just calls IopActionInitChildServices with
2598 * BootDrivers = TRUE.
2599 */
2600 NTSTATUS
2601 IopActionInitBootServices(PDEVICE_NODE DeviceNode,
2602 PVOID Context)
2603 {
2604 return IopActionInitChildServices(DeviceNode, Context, TRUE);
2605 }
2606
2607 /*
2608 * IopInitializePnpServices
2609 *
2610 * Initialize services for discovered children
2611 *
2612 * Parameters
2613 * DeviceNode
2614 * Top device node to start initializing services.
2615 *
2616 * BootDrivers
2617 * When set to TRUE, only drivers marked as boot start will
2618 * be loaded. Otherwise, all drivers will be loaded.
2619 *
2620 * Return Value
2621 * Status
2622 */
2623 NTSTATUS
2624 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode,
2625 IN BOOLEAN BootDrivers)
2626 {
2627 DEVICETREE_TRAVERSE_CONTEXT Context;
2628
2629 DPRINT("IopInitializePnpServices(%p, %d)\n", DeviceNode, BootDrivers);
2630
2631 if (BootDrivers)
2632 {
2633 IopInitDeviceTreeTraverseContext(
2634 &Context,
2635 DeviceNode,
2636 IopActionInitBootServices,
2637 DeviceNode);
2638 }
2639 else
2640 {
2641 IopInitDeviceTreeTraverseContext(
2642 &Context,
2643 DeviceNode,
2644 IopActionInitAllServices,
2645 DeviceNode);
2646 }
2647
2648 return IopTraverseDeviceTree(&Context);
2649 }
2650
2651 static NTSTATUS INIT_FUNCTION
2652 IopEnumerateDetectedDevices(
2653 IN HANDLE hBaseKey,
2654 IN PUNICODE_STRING RelativePath OPTIONAL,
2655 IN HANDLE hRootKey,
2656 IN BOOLEAN EnumerateSubKeys,
2657 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2658 IN ULONG ParentBootResourcesLength)
2659 {
2660 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2661 UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
2662 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2663 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2664 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2665 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2666 OBJECT_ATTRIBUTES ObjectAttributes;
2667 HANDLE hDevicesKey = NULL;
2668 HANDLE hDeviceKey = NULL;
2669 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2670 UNICODE_STRING Level2NameU;
2671 WCHAR Level2Name[5];
2672 ULONG IndexDevice = 0;
2673 ULONG IndexSubKey;
2674 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2675 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2676 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2677 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2678 UNICODE_STRING DeviceName, ValueName;
2679 ULONG RequiredSize;
2680 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2681 ULONG BootResourcesLength;
2682 NTSTATUS Status;
2683
2684 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
2685 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
2686 static ULONG DeviceIndexPci = 0;
2687 #ifdef ENABLE_ACPI
2688 const UNICODE_STRING IdentifierAcpi = RTL_CONSTANT_STRING(L"ACPI BIOS");
2689 UNICODE_STRING HardwareIdAcpi = RTL_CONSTANT_STRING(L"*PNP0C08\0");
2690 static ULONG DeviceIndexAcpi = 0;
2691 #endif
2692 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2693 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2694 static ULONG DeviceIndexSerial = 0;
2695 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2696 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2697 static ULONG DeviceIndexKeyboard = 0;
2698 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2699 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2700 static ULONG DeviceIndexMouse = 0;
2701 UNICODE_STRING HardwareIdKey;
2702 PUNICODE_STRING pHardwareId;
2703 ULONG DeviceIndex = 0;
2704
2705 if (RelativePath)
2706 {
2707 InitializeObjectAttributes(&ObjectAttributes, RelativePath, OBJ_KERNEL_HANDLE, hBaseKey, NULL);
2708 Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
2709 if (!NT_SUCCESS(Status))
2710 {
2711 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2712 goto cleanup;
2713 }
2714 }
2715 else
2716 hDevicesKey = hBaseKey;
2717
2718 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2719 if (!pDeviceInformation)
2720 {
2721 DPRINT("ExAllocatePool() failed\n");
2722 Status = STATUS_NO_MEMORY;
2723 goto cleanup;
2724 }
2725
2726 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2727 if (!pValueInformation)
2728 {
2729 DPRINT("ExAllocatePool() failed\n");
2730 Status = STATUS_NO_MEMORY;
2731 goto cleanup;
2732 }
2733
2734 while (TRUE)
2735 {
2736 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2737 if (Status == STATUS_NO_MORE_ENTRIES)
2738 break;
2739 else if (Status == STATUS_BUFFER_OVERFLOW)
2740 {
2741 ExFreePool(pDeviceInformation);
2742 DeviceInfoLength = RequiredSize;
2743 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2744 if (!pDeviceInformation)
2745 {
2746 DPRINT("ExAllocatePool() failed\n");
2747 Status = STATUS_NO_MEMORY;
2748 goto cleanup;
2749 }
2750 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2751 }
2752 if (!NT_SUCCESS(Status))
2753 {
2754 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2755 goto cleanup;
2756 }
2757 IndexDevice++;
2758
2759 /* Open device key */
2760 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2761 DeviceName.Buffer = pDeviceInformation->Name;
2762 InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
2763 Status = ZwOpenKey(
2764 &hDeviceKey,
2765 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0),
2766 &ObjectAttributes);
2767 if (!NT_SUCCESS(Status))
2768 {
2769 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2770 goto cleanup;
2771 }
2772
2773 /* Read boot resources, and add then to parent ones */
2774 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2775 if (Status == STATUS_BUFFER_OVERFLOW)
2776 {
2777 ExFreePool(pValueInformation);
2778 ValueInfoLength = RequiredSize;
2779 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2780 if (!pValueInformation)
2781 {
2782 DPRINT("ExAllocatePool() failed\n");
2783 ZwDeleteKey(hLevel2Key);
2784 Status = STATUS_NO_MEMORY;
2785 goto cleanup;
2786 }
2787 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2788 }
2789 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2790 {
2791 BootResources = ParentBootResources;
2792 BootResourcesLength = ParentBootResourcesLength;
2793 }
2794 else if (!NT_SUCCESS(Status))
2795 {
2796 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2797 goto nextdevice;
2798 }
2799 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2800 {
2801 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2802 goto nextdevice;
2803 }
2804 else
2805 {
2806 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2807
2808 /* Concatenate current resources and parent ones */
2809 if (ParentBootResourcesLength == 0)
2810 BootResourcesLength = pValueInformation->DataLength;
2811 else
2812 BootResourcesLength = ParentBootResourcesLength
2813 + pValueInformation->DataLength
2814 - Header;
2815 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2816 if (!BootResources)
2817 {
2818 DPRINT("ExAllocatePool() failed\n");
2819 goto nextdevice;
2820 }
2821 if (ParentBootResourcesLength == 0)
2822 {
2823 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2824 }
2825 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2826 {
2827 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2828 RtlCopyMemory(
2829 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2830 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2831 ParentBootResourcesLength - Header);
2832 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2833 }
2834 else
2835 {
2836 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2837 RtlCopyMemory(
2838 (PVOID)((ULONG_PTR)BootResources + Header),
2839 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2840 ParentBootResourcesLength - Header);
2841 RtlCopyMemory(
2842 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2843 pValueInformation->Data + Header,
2844 pValueInformation->DataLength - Header);
2845 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2846 }
2847 }
2848
2849 if (EnumerateSubKeys)
2850 {
2851 IndexSubKey = 0;
2852 while (TRUE)
2853 {
2854 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2855 if (Status == STATUS_NO_MORE_ENTRIES)
2856 break;
2857 else if (Status == STATUS_BUFFER_OVERFLOW)
2858 {
2859 ExFreePool(pDeviceInformation);
2860 DeviceInfoLength = RequiredSize;
2861 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2862 if (!pDeviceInformation)
2863 {
2864 DPRINT("ExAllocatePool() failed\n");
2865 Status = STATUS_NO_MEMORY;
2866 goto cleanup;
2867 }
2868 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2869 }
2870 if (!NT_SUCCESS(Status))
2871 {
2872 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2873 goto cleanup;
2874 }
2875 IndexSubKey++;
2876 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2877 DeviceName.Buffer = pDeviceInformation->Name;
2878
2879 Status = IopEnumerateDetectedDevices(
2880 hDeviceKey,
2881 &DeviceName,
2882 hRootKey,
2883 TRUE,
2884 BootResources,
2885 BootResourcesLength);
2886 if (!NT_SUCCESS(Status))
2887 goto cleanup;
2888 }
2889 }
2890
2891 /* Read identifier */
2892 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2893 if (Status == STATUS_BUFFER_OVERFLOW)
2894 {
2895 ExFreePool(pValueInformation);
2896 ValueInfoLength = RequiredSize;
2897 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2898 if (!pValueInformation)
2899 {
2900 DPRINT("ExAllocatePool() failed\n");
2901 Status = STATUS_NO_MEMORY;
2902 goto cleanup;
2903 }
2904 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2905 }
2906 if (!NT_SUCCESS(Status))
2907 {
2908 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2909 {
2910 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2911 goto nextdevice;
2912 }
2913 ValueName.Length = ValueName.MaximumLength = 0;
2914 }
2915 else if (pValueInformation->Type != REG_SZ)
2916 {
2917 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2918 goto nextdevice;
2919 }
2920 else
2921 {
2922 /* Assign hardware id to this device */
2923 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
2924 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2925 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2926 ValueName.Length -= sizeof(WCHAR);
2927 }
2928
2929 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
2930 {
2931 pHardwareId = &HardwareIdSerial;
2932 DeviceIndex = DeviceIndexSerial++;
2933 }
2934 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
2935 {
2936 pHardwareId = &HardwareIdKeyboard;
2937 DeviceIndex = DeviceIndexKeyboard++;
2938 }
2939 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
2940 {
2941 pHardwareId = &HardwareIdMouse;
2942 DeviceIndex = DeviceIndexMouse++;
2943 }
2944 else if (NT_SUCCESS(Status))
2945 {
2946 /* Try to also match the device identifier */
2947 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
2948 {
2949 pHardwareId = &HardwareIdPci;
2950 DeviceIndex = DeviceIndexPci++;
2951 }
2952 #ifdef ENABLE_ACPI
2953 else if (RtlCompareUnicodeString(&ValueName, &IdentifierAcpi, FALSE) == 0)
2954 {
2955 pHardwareId = &HardwareIdAcpi;
2956 DeviceIndex = DeviceIndexAcpi++;
2957 }
2958 #endif
2959 else
2960 {
2961 /* Unknown device */
2962 DPRINT("Unknown device '%wZ'\n", &ValueName);
2963 goto nextdevice;
2964 }
2965 }
2966 else
2967 {
2968 /* Unknown key path */
2969 DPRINT("Unknown key path '%wZ'\n", RelativePath);
2970 goto nextdevice;
2971 }
2972
2973 /* Prepare hardware id key (hardware id value without final \0) */
2974 HardwareIdKey = *pHardwareId;
2975 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
2976
2977 /* Add the detected device to Root key */
2978 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
2979 Status = ZwCreateKey(
2980 &hLevel1Key,
2981 KEY_CREATE_SUB_KEY,
2982 &ObjectAttributes,
2983 0,
2984 NULL,
2985 REG_OPTION_NON_VOLATILE,
2986 NULL);
2987 if (!NT_SUCCESS(Status))
2988 {
2989 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2990 goto nextdevice;
2991 }
2992 swprintf(Level2Name, L"%04lu", DeviceIndex);
2993 RtlInitUnicodeString(&Level2NameU, Level2Name);
2994 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
2995 Status = ZwCreateKey(
2996 &hLevel2Key,
2997 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
2998 &ObjectAttributes,
2999 0,
3000 NULL,
3001 REG_OPTION_NON_VOLATILE,
3002 NULL);
3003 ZwClose(hLevel1Key);
3004 if (!NT_SUCCESS(Status))
3005 {
3006 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3007 goto nextdevice;
3008 }
3009 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3010 Status = ZwSetValueKey(hLevel2Key, &DeviceDescU, 0, REG_SZ, ValueName.Buffer, ValueName.MaximumLength);
3011 if (!NT_SUCCESS(Status))
3012 {
3013 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3014 ZwDeleteKey(hLevel2Key);
3015 goto nextdevice;
3016 }
3017 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3018 if (!NT_SUCCESS(Status))
3019 {
3020 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3021 ZwDeleteKey(hLevel2Key);
3022 goto nextdevice;
3023 }
3024 /* Create 'LogConf' subkey */
3025 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3026 Status = ZwCreateKey(
3027 &hLogConf,
3028 KEY_SET_VALUE,
3029 &ObjectAttributes,
3030 0,
3031 NULL,
3032 REG_OPTION_VOLATILE,
3033 NULL);
3034 if (!NT_SUCCESS(Status))
3035 {
3036 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3037 ZwDeleteKey(hLevel2Key);
3038 goto nextdevice;
3039 }
3040 if (BootResourcesLength > 0)
3041 {
3042 /* Save boot resources to 'LogConf\BootConfig' */
3043 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_FULL_RESOURCE_DESCRIPTOR, BootResources, BootResourcesLength);
3044 if (!NT_SUCCESS(Status))
3045 {
3046 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3047 ZwClose(hLogConf);
3048 ZwDeleteKey(hLevel2Key);
3049 goto nextdevice;
3050 }
3051 }
3052 ZwClose(hLogConf);
3053
3054 nextdevice:
3055 if (BootResources && BootResources != ParentBootResources)
3056 ExFreePool(BootResources);
3057 if (hLevel2Key)
3058 {
3059 ZwClose(hLevel2Key);
3060 hLevel2Key = NULL;
3061 }
3062 if (hDeviceKey)
3063 {
3064 ZwClose(hDeviceKey);
3065 hDeviceKey = NULL;
3066 }
3067 }
3068
3069 Status = STATUS_SUCCESS;
3070
3071 cleanup:
3072 if (hDevicesKey && hDevicesKey != hBaseKey)
3073 ZwClose(hDevicesKey);
3074 if (hDeviceKey)
3075 ZwClose(hDeviceKey);
3076 if (pDeviceInformation)
3077 ExFreePool(pDeviceInformation);
3078 if (pValueInformation)
3079 ExFreePool(pValueInformation);
3080 return Status;
3081 }
3082
3083 static BOOLEAN INIT_FUNCTION
3084 IopIsAcpiComputer(VOID)
3085 {
3086 #ifndef ENABLE_ACPI
3087 return FALSE;
3088 #else
3089 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3090 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3091 UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS");
3092 OBJECT_ATTRIBUTES ObjectAttributes;
3093 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3094 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3095 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3096 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3097 ULONG RequiredSize;
3098 ULONG IndexDevice = 0;
3099 UNICODE_STRING DeviceName, ValueName;
3100 HANDLE hDevicesKey = NULL;
3101 HANDLE hDeviceKey = NULL;
3102 NTSTATUS Status;
3103 BOOLEAN ret = FALSE;
3104
3105 InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_KERNEL_HANDLE, NULL, NULL);
3106 Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
3107 if (!NT_SUCCESS(Status))
3108 {
3109 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3110 goto cleanup;
3111 }
3112
3113 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3114 if (!pDeviceInformation)
3115 {
3116 DPRINT("ExAllocatePool() failed\n");
3117 Status = STATUS_NO_MEMORY;
3118 goto cleanup;
3119 }
3120
3121 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3122 if (!pDeviceInformation)
3123 {
3124 DPRINT("ExAllocatePool() failed\n");
3125 Status = STATUS_NO_MEMORY;
3126 goto cleanup;
3127 }
3128
3129 while (TRUE)
3130 {
3131 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3132 if (Status == STATUS_NO_MORE_ENTRIES)
3133 break;
3134 else if (Status == STATUS_BUFFER_OVERFLOW)
3135 {
3136 ExFreePool(pDeviceInformation);
3137 DeviceInfoLength = RequiredSize;
3138 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3139 if (!pDeviceInformation)
3140 {
3141 DPRINT("ExAllocatePool() failed\n");
3142 Status = STATUS_NO_MEMORY;
3143 goto cleanup;
3144 }
3145 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3146 }
3147 if (!NT_SUCCESS(Status))
3148 {
3149 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3150 goto cleanup;
3151 }
3152 IndexDevice++;
3153
3154 /* Open device key */
3155 DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
3156 DeviceName.Buffer = pDeviceInformation->Name;
3157 InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
3158 Status = ZwOpenKey(
3159 &hDeviceKey,
3160 KEY_QUERY_VALUE,
3161 &ObjectAttributes);
3162 if (!NT_SUCCESS(Status))
3163 {
3164 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3165 goto cleanup;
3166 }
3167
3168 /* Read identifier */
3169 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3170 if (Status == STATUS_BUFFER_OVERFLOW)
3171 {
3172 ExFreePool(pValueInformation);
3173 ValueInfoLength = RequiredSize;
3174 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3175 if (!pValueInformation)
3176 {
3177 DPRINT("ExAllocatePool() failed\n");
3178 Status = STATUS_NO_MEMORY;
3179 goto cleanup;
3180 }
3181 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3182 }
3183 if (!NT_SUCCESS(Status))
3184 {
3185 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3186 goto nextdevice;
3187 }
3188 else if (pValueInformation->Type != REG_SZ)
3189 {
3190 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3191 goto nextdevice;
3192 }
3193
3194 ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
3195 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3196 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3197 ValueName.Length -= sizeof(WCHAR);
3198 if (RtlCompareUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE) == 0)
3199 {
3200 DPRINT("Found ACPI BIOS\n");
3201 ret = TRUE;
3202 goto cleanup;
3203 }
3204
3205 nextdevice:
3206 ZwClose(hDeviceKey);
3207 hDeviceKey = NULL;
3208 }
3209
3210 cleanup:
3211 if (pDeviceInformation)
3212 ExFreePool(pDeviceInformation);
3213 if (pValueInformation)
3214 ExFreePool(pValueInformation);
3215 if (hDevicesKey)
3216 ZwClose(hDevicesKey);
3217 if (hDeviceKey)
3218 ZwClose(hDeviceKey);
3219 return ret;
3220 #endif
3221 }
3222
3223 static NTSTATUS INIT_FUNCTION
3224 IopUpdateRootKey(VOID)
3225 {
3226 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3227 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3228 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3229 UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
3230 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3231 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
3232 UNICODE_STRING HalAcpiDevice = RTL_CONSTANT_STRING(L"ACPI_HAL");
3233 UNICODE_STRING HalAcpiId = RTL_CONSTANT_STRING(L"0000");
3234 UNICODE_STRING HalAcpiDeviceDesc = RTL_CONSTANT_STRING(L"HAL ACPI");
3235 UNICODE_STRING HalAcpiHardwareID = RTL_CONSTANT_STRING(L"*PNP0C08\0");
3236 OBJECT_ATTRIBUTES ObjectAttributes;
3237 HANDLE hEnum, hRoot, hHalAcpiDevice, hHalAcpiId, hLogConf;
3238 NTSTATUS Status;
3239
3240 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE, NULL, NULL);
3241 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3242 if (!NT_SUCCESS(Status))
3243 {
3244 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3245 return Status;
3246 }
3247
3248 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE, hEnum, NULL);
3249 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3250 ZwClose(hEnum);
3251 if (!NT_SUCCESS(Status))
3252 {
3253 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3254 return Status;
3255 }
3256
3257 if (IopIsAcpiComputer())
3258 {
3259 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiDevice, OBJ_KERNEL_HANDLE, hRoot, NULL);
3260 Status = ZwCreateKey(&hHalAcpiDevice, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
3261 ZwClose(hRoot);
3262 if (!NT_SUCCESS(Status))
3263 return Status;
3264 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiId, OBJ_KERNEL_HANDLE, hHalAcpiDevice, NULL);
3265 Status = ZwCreateKey(&hHalAcpiId, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
3266 ZwClose(hHalAcpiDevice);
3267 if (!NT_SUCCESS(Status))
3268 return Status;
3269 Status = ZwSetValueKey(hHalAcpiId, &DeviceDescU, 0, REG_SZ, HalAcpiDeviceDesc.Buffer, HalAcpiDeviceDesc.MaximumLength);
3270 if (NT_SUCCESS(Status))
3271 Status = ZwSetValueKey(hHalAcpiId, &HardwareIDU, 0, REG_MULTI_SZ, HalAcpiHardwareID.Buffer, HalAcpiHardwareID.MaximumLength);
3272 if (NT_SUCCESS(Status))
3273 {
3274 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hHalAcpiId, NULL);
3275 Status = ZwCreateKey(&hLogConf, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
3276 if (NT_SUCCESS(Status))
3277 ZwClose(hLogConf);
3278 }
3279 ZwClose(hHalAcpiId);
3280 return Status;
3281 }
3282 else
3283 {
3284 InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_KERNEL_HANDLE, NULL, NULL);
3285 Status = ZwOpenKey(&hEnum, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
3286 if (!NT_SUCCESS(Status))
3287 {
3288 /* Nothing to do, don't return with an error status */
3289 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3290 ZwClose(hRoot);
3291 return STATUS_SUCCESS;
3292 }
3293 Status = IopEnumerateDetectedDevices(
3294 hEnum,
3295 NULL,
3296 hRoot,
3297 TRUE,
3298 NULL,
3299 0);
3300 ZwClose(hEnum);
3301 ZwClose(hRoot);
3302 return Status;
3303 }
3304 }
3305
3306 NTSTATUS
3307 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3308 HANDLE ParentKey,
3309 PUNICODE_STRING Name,
3310 ACCESS_MASK DesiredAccess)
3311 {
3312 OBJECT_ATTRIBUTES ObjectAttributes;
3313 NTSTATUS Status;
3314
3315 PAGED_CODE();
3316
3317 *KeyHandle = NULL;
3318
3319 InitializeObjectAttributes(&ObjectAttributes,
3320 Name,
3321 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3322 ParentKey,
3323 NULL);
3324
3325 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3326
3327 return Status;
3328 }
3329
3330 static NTSTATUS INIT_FUNCTION
3331 NTAPI
3332 PnpDriverInitializeEmpty(IN struct _DRIVER_OBJECT *DriverObject, IN PUNICODE_STRING RegistryPath)
3333 {
3334 return STATUS_SUCCESS;
3335 }
3336
3337 VOID INIT_FUNCTION
3338 PnpInit(VOID)
3339 {
3340 PDEVICE_OBJECT Pdo;
3341 NTSTATUS Status;
3342
3343 DPRINT("PnpInit()\n");
3344
3345 KeInitializeSpinLock(&IopDeviceTreeLock);
3346
3347 /* Initialize the Bus Type GUID List */
3348 IopBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
3349 RtlZeroMemory(IopBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
3350 ExInitializeFastMutex(&IopBusTypeGuidList->Lock);
3351
3352 /* Initialize PnP-Event notification support */
3353 Status = IopInitPlugPlayEvents();
3354 if (!NT_SUCCESS(Status))
3355 {
3356 CPRINT("IopInitPlugPlayEvents() failed\n");
3357 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3358 }
3359
3360 /*
3361 * Create root device node
3362 */
3363
3364 Status = IopCreateDriver(NULL, PnpDriverInitializeEmpty, NULL, 0, 0, &IopRootDriverObject);
3365 if (!NT_SUCCESS(Status))
3366 {
3367 CPRINT("IoCreateDriverObject() failed\n");
3368 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3369 }
3370
3371 Status = IoCreateDevice(IopRootDriverObject, 0, NULL, FILE_DEVICE_CONTROLLER,
3372 0, FALSE, &Pdo);
3373 if (!NT_SUCCESS(Status))
3374 {
3375 CPRINT("IoCreateDevice() failed\n");
3376 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3377 }
3378
3379 Status = IopCreateDeviceNode(NULL, Pdo, NULL, &IopRootDeviceNode);
3380 if (!NT_SUCCESS(Status))
3381 {
3382 CPRINT("Insufficient resources\n");
3383 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3384 }
3385
3386 if (!RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
3387 L"HTREE\\ROOT\\0"))
3388 {
3389 CPRINT("Failed to create the instance path!\n");
3390 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 0, 0, 0);
3391 }
3392
3393 /* Report the device to the user-mode pnp manager */
3394 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
3395 &IopRootDeviceNode->InstancePath);
3396
3397 IopRootDeviceNode->PhysicalDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
3398 PnpRootDriverEntry(IopRootDriverObject, NULL);
3399 IopRootDeviceNode->PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3400 IopRootDriverObject->DriverExtension->AddDevice(
3401 IopRootDriverObject,
3402 IopRootDeviceNode->PhysicalDeviceObject);
3403
3404 /* Move information about devices detected by Freeloader to SYSTEM\CurrentControlSet\Root\ */
3405 Status = IopUpdateRootKey();
3406 if (!NT_SUCCESS(Status))
3407 {
3408 CPRINT("IopUpdateRootKey() failed\n");
3409 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3410 }
3411 }
3412
3413 RTL_GENERIC_COMPARE_RESULTS
3414 NTAPI
3415 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3416 IN PVOID FirstStruct,
3417 IN PVOID SecondStruct)
3418 {
3419 /* FIXME: TODO */
3420 KEBUGCHECK(0);
3421 return 0;
3422 }
3423
3424 //
3425 // The allocation function is called by the generic table package whenever
3426 // it needs to allocate memory for the table.
3427 //
3428
3429 PVOID
3430 NTAPI
3431 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3432 IN CLONG ByteSize)
3433 {
3434 /* FIXME: TODO */
3435 KEBUGCHECK(0);
3436 return NULL;
3437 }
3438
3439 VOID
3440 NTAPI
3441 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3442 IN PVOID Buffer)
3443 {
3444 /* FIXME: TODO */
3445 KEBUGCHECK(0);
3446 }
3447
3448 VOID
3449 NTAPI
3450 PpInitializeDeviceReferenceTable(VOID)
3451 {
3452 /* Setup the guarded mutex and AVL table */
3453 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3454 RtlInitializeGenericTableAvl(
3455 &PpDeviceReferenceTable,
3456 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3457 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3458 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3459 NULL);
3460 }
3461
3462 BOOLEAN
3463 NTAPI
3464 PiInitPhase0(VOID)
3465 {
3466 /* Initialize the resource when accessing device registry data */
3467 ExInitializeResourceLite(&PpRegistryDeviceResource);
3468
3469 /* Setup the device reference AVL table */
3470 PpInitializeDeviceReferenceTable();
3471 return TRUE;
3472 }
3473
3474 BOOLEAN
3475 NTAPI
3476 PpInitSystem(VOID)
3477 {
3478 /* Check the initialization phase */
3479 switch (ExpInitializationPhase)
3480 {
3481 case 0:
3482
3483 /* Do Phase 0 */
3484 return PiInitPhase0();
3485
3486 case 1:
3487
3488 /* Do Phase 1 */
3489 return TRUE;
3490 //return PiInitPhase1();
3491
3492 default:
3493
3494 /* Don't know any other phase! Bugcheck! */
3495 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3496 return FALSE;
3497 }
3498 }
3499
3500 /* EOF */