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