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