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