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