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