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