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