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