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