[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 //#define ENABLE_ACPI
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 extern BOOLEAN PnpSystemInit;
28
29 /* DATA **********************************************************************/
30
31 PDRIVER_OBJECT IopRootDriverObject;
32 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
33
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, PnpInit)
36 #pragma alloc_text(INIT, PnpInit2)
37 #endif
38
39 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
40 {
41 PDEVICE_OBJECT DeviceObject;
42 DEVICE_RELATION_TYPE Type;
43 PIO_WORKITEM WorkItem;
44 } INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
45
46 /* FUNCTIONS *****************************************************************/
47
48 NTSTATUS
49 IopAssignDeviceResources(
50 IN PDEVICE_NODE DeviceNode,
51 OUT ULONG *pRequiredSize);
52
53 NTSTATUS
54 IopTranslateDeviceResources(
55 IN PDEVICE_NODE DeviceNode,
56 IN ULONG RequiredSize);
57
58 NTSTATUS
59 IopUpdateResourceMapForPnPDevice(
60 IN PDEVICE_NODE DeviceNode);
61
62 NTSTATUS
63 NTAPI
64 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
65 IN ULONG CreateOptions,
66 OUT PHANDLE Handle);
67
68 PDEVICE_NODE
69 FASTCALL
70 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
71 {
72 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
73 }
74
75 NTSTATUS
76 FASTCALL
77 IopInitializeDevice(PDEVICE_NODE DeviceNode,
78 PDRIVER_OBJECT DriverObject)
79 {
80 PDEVICE_OBJECT Fdo;
81 NTSTATUS Status;
82
83 if (!DriverObject->DriverExtension->AddDevice)
84 return STATUS_SUCCESS;
85
86 /* This is a Plug and Play driver */
87 DPRINT("Plug and Play driver found\n");
88 ASSERT(DeviceNode->PhysicalDeviceObject);
89
90 /* Check if this plug-and-play driver is used as a legacy one for this device node */
91 if (IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
92 {
93 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
94 return STATUS_SUCCESS;
95 }
96
97 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
98 &DriverObject->DriverName,
99 &DeviceNode->InstancePath);
100 Status = DriverObject->DriverExtension->AddDevice(
101 DriverObject, DeviceNode->PhysicalDeviceObject);
102 if (!NT_SUCCESS(Status))
103 {
104 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
105 return Status;
106 }
107
108 /* Check if driver added a FDO above the PDO */
109 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
110 if (Fdo == DeviceNode->PhysicalDeviceObject)
111 {
112 /* FIXME: What do we do? Unload the driver or just disable the device? */
113 DPRINT1("An FDO was not attached\n");
114 ObDereferenceObject(Fdo);
115 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
116 return STATUS_UNSUCCESSFUL;
117 }
118
119 /* Check if we have a ACPI device (needed for power management) */
120 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
121 {
122 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
123
124 /* There can be only one system power device */
125 if (!SystemPowerDeviceNodeCreated)
126 {
127 PopSystemPowerDeviceNode = DeviceNode;
128 ObReferenceObject(PopSystemPowerDeviceNode);
129 SystemPowerDeviceNodeCreated = TRUE;
130 }
131 }
132
133 ObDereferenceObject(Fdo);
134
135 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
136 IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
137
138 return STATUS_SUCCESS;
139 }
140
141 VOID
142 NTAPI
143 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
144 {
145 IO_STACK_LOCATION Stack;
146 PDEVICE_NODE DeviceNode;
147 NTSTATUS Status;
148 PVOID Dummy;
149
150 /* Get the device node */
151 DeviceNode = IopGetDeviceNode(DeviceObject);
152
153 /* Build the I/O stack locaiton */
154 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
155 Stack.MajorFunction = IRP_MJ_PNP;
156 Stack.MinorFunction = IRP_MN_START_DEVICE;
157
158 /* Check if we didn't already report the resources */
159 // if (!DeviceNode->Flags & DNF_RESOURCE_REPORTED)
160 {
161 /* Report them */
162 if (DeviceNode->Flags & DNF_RESOURCE_REPORTED)
163 {
164 DPRINT1("Warning: Setting resource pointers even though DNF_RESOURCE_REPORTED is set\n");
165 }
166 Stack.Parameters.StartDevice.AllocatedResources =
167 DeviceNode->ResourceList;
168 Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
169 DeviceNode->ResourceListTranslated;
170 }
171
172 /* I don't think we set this flag yet */
173 ASSERT(!(DeviceNode->Flags & DNF_STOPPED));
174
175 /* Do the call */
176 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
177 if (!NT_SUCCESS(Status))
178 {
179 /* FIXME: TODO */
180 DPRINT1("Warning: PnP Start failed\n");
181 //ASSERT(FALSE);
182 return;
183 }
184
185 /* Otherwise, mark us as started */
186 DeviceNode->Flags |= DNF_STARTED;
187
188 /* We now need enumeration */
189 DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
190 }
191
192 NTSTATUS
193 NTAPI
194 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
195 {
196 PDEVICE_OBJECT DeviceObject;
197 NTSTATUS Status;
198 PAGED_CODE();
199
200 /* Sanity check */
201 // ASSERT((DeviceNode->Flags & DNF_ADDED));
202 if (!(DeviceNode->Flags & DNF_ADDED)) DPRINT1("Warning: Starting a device node without DNF_ADDED\n");
203 ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED |
204 DNF_RESOURCE_REPORTED |
205 DNF_NO_RESOURCE_REQUIRED |
206 DNF_NO_RESOURCE_REQUIRED)));
207 ASSERT((!(DeviceNode->Flags & (DNF_HAS_PROBLEM |
208 DNF_STARTED |
209 DNF_START_REQUEST_PENDING))));
210
211 /* Get the device object */
212 DeviceObject = DeviceNode->PhysicalDeviceObject;
213
214 /* Check if we're not started yet */
215 //if (!DeviceNode->Flags & DNF_STARTED)
216 {
217 /* Start us */
218 IopStartDevice2(DeviceObject);
219 }
220
221 /* Do we need to query IDs? This happens in the case of manual reporting */
222 //if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
223 //{
224 // DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
225 /* And that case shouldn't happen yet */
226 // ASSERT(FALSE);
227 //}
228
229 /* Make sure we're started, and check if we need enumeration */
230 if ((DeviceNode->Flags & DNF_STARTED) &&
231 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY))
232 {
233 /* Enumerate us */
234 //Status = IopEnumerateDevice(DeviceObject);
235 IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations);
236 IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
237 Status = STATUS_SUCCESS;
238 }
239 else
240 {
241 /* Nothing to do */
242 Status = STATUS_SUCCESS;
243 }
244
245 /* Return */
246 return Status;
247 }
248
249 NTSTATUS
250 IopStartDevice(
251 PDEVICE_NODE DeviceNode)
252 {
253 IO_STATUS_BLOCK IoStatusBlock;
254 IO_STACK_LOCATION Stack;
255 ULONG RequiredLength;
256 NTSTATUS Status;
257 HANDLE InstanceHandle = INVALID_HANDLE_VALUE, ControlHandle = INVALID_HANDLE_VALUE;
258 UNICODE_STRING KeyName;
259 OBJECT_ATTRIBUTES ObjectAttributes;
260
261 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
262 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
263 Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
264 Status = IopInitiatePnpIrp(
265 DeviceNode->PhysicalDeviceObject,
266 &IoStatusBlock,
267 IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
268 &Stack);
269 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
270 {
271 DPRINT("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
272 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
273 return Status;
274 }
275 else if (NT_SUCCESS(Status))
276 {
277 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
278 }
279
280 Status = IopAssignDeviceResources(DeviceNode, &RequiredLength);
281 if (NT_SUCCESS(Status))
282 {
283 Status = IopTranslateDeviceResources(DeviceNode, RequiredLength);
284 if (NT_SUCCESS(Status))
285 {
286 Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
287 if (!NT_SUCCESS(Status))
288 {
289 DPRINT("IopUpdateResourceMap() failed (Status 0x%08lx)\n", Status);
290 }
291 }
292 else
293 {
294 DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)\n", Status);
295 }
296 }
297 else
298 {
299 DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)\n", Status);
300 }
301 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
302
303 if (!NT_SUCCESS(Status))
304 goto ByeBye;
305
306 /* New PnP ABI */
307 IopStartAndEnumerateDevice(DeviceNode);
308
309 /* FIX: Should be done in new device instance code */
310 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceHandle);
311 if (!NT_SUCCESS(Status))
312 goto ByeBye;
313
314 /* FIX: Should be done in IoXxxPrepareDriverLoading */
315 // {
316 RtlInitUnicodeString(&KeyName, L"Control");
317 InitializeObjectAttributes(&ObjectAttributes,
318 &KeyName,
319 OBJ_CASE_INSENSITIVE,
320 InstanceHandle,
321 NULL);
322 Status = ZwCreateKey(&ControlHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
323 if (!NT_SUCCESS(Status))
324 goto ByeBye;
325
326 RtlInitUnicodeString(&KeyName, L"ActiveService");
327 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, DeviceNode->ServiceName.Buffer, DeviceNode->ServiceName.Length);
328 // }
329
330 /* FIX: Should be done somewhere in resoure code? */
331 if (NT_SUCCESS(Status) && DeviceNode->ResourceList)
332 {
333 RtlInitUnicodeString(&KeyName, L"AllocConfig");
334 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_RESOURCE_LIST,
335 DeviceNode->ResourceList, CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceList));
336 }
337
338 ByeBye:
339 if (NT_SUCCESS(Status))
340 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
341 else
342 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
343
344 if (ControlHandle != INVALID_HANDLE_VALUE)
345 ZwClose(ControlHandle);
346
347 if (InstanceHandle != INVALID_HANDLE_VALUE)
348 ZwClose(InstanceHandle);
349
350 return Status;
351 }
352
353 NTSTATUS
354 NTAPI
355 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
356 PDEVICE_CAPABILITIES DeviceCaps)
357 {
358 IO_STATUS_BLOCK StatusBlock;
359 IO_STACK_LOCATION Stack;
360
361 /* Set up the Header */
362 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
363 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
364 DeviceCaps->Version = 1;
365 DeviceCaps->Address = -1;
366 DeviceCaps->UINumber = -1;
367
368 /* Set up the Stack */
369 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
370 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
371
372 /* Send the IRP */
373 return IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
374 &StatusBlock,
375 IRP_MN_QUERY_CAPABILITIES,
376 &Stack);
377 }
378
379 static VOID NTAPI
380 IopAsynchronousInvalidateDeviceRelations(
381 IN PDEVICE_OBJECT DeviceObject,
382 IN PVOID InvalidateContext)
383 {
384 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
385
386 IoSynchronousInvalidateDeviceRelations(
387 Data->DeviceObject,
388 Data->Type);
389
390 ObDereferenceObject(Data->DeviceObject);
391 IoFreeWorkItem(Data->WorkItem);
392 ExFreePool(Data);
393 }
394
395 NTSTATUS
396 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
397 {
398 KIRQL OldIrql;
399
400 if (PopSystemPowerDeviceNode)
401 {
402 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
403 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
404 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
405
406 return STATUS_SUCCESS;
407 }
408
409 return STATUS_UNSUCCESSFUL;
410 }
411
412 USHORT
413 NTAPI
414 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
415 {
416 USHORT i = 0, FoundIndex = 0xFFFF;
417 ULONG NewSize;
418 PVOID NewList;
419
420 /* Acquire the lock */
421 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
422
423 /* Loop all entries */
424 while (i < PnpBusTypeGuidList->GuidCount)
425 {
426 /* Try to find a match */
427 if (RtlCompareMemory(BusTypeGuid,
428 &PnpBusTypeGuidList->Guids[i],
429 sizeof(GUID)) == sizeof(GUID))
430 {
431 /* Found it */
432 FoundIndex = i;
433 goto Quickie;
434 }
435 i++;
436 }
437
438 /* Check if we have to grow the list */
439 if (PnpBusTypeGuidList->GuidCount)
440 {
441 /* Calculate the new size */
442 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
443 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
444
445 /* Allocate the new copy */
446 NewList = ExAllocatePool(PagedPool, NewSize);
447
448 if (!NewList) {
449 /* Fail */
450 ExFreePool(PnpBusTypeGuidList);
451 goto Quickie;
452 }
453
454 /* Now copy them, decrease the size too */
455 NewSize -= sizeof(GUID);
456 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
457
458 /* Free the old list */
459 ExFreePool(PnpBusTypeGuidList);
460
461 /* Use the new buffer */
462 PnpBusTypeGuidList = NewList;
463 }
464
465 /* Copy the new GUID */
466 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
467 BusTypeGuid,
468 sizeof(GUID));
469
470 /* The new entry is the index */
471 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
472 PnpBusTypeGuidList->GuidCount++;
473
474 Quickie:
475 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
476 return FoundIndex;
477 }
478
479 /*
480 * DESCRIPTION
481 * Creates a device node
482 *
483 * ARGUMENTS
484 * ParentNode = Pointer to parent device node
485 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
486 * to have the root device node create one
487 * (eg. for legacy drivers)
488 * DeviceNode = Pointer to storage for created device node
489 *
490 * RETURN VALUE
491 * Status
492 */
493 NTSTATUS
494 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
495 PDEVICE_OBJECT PhysicalDeviceObject,
496 PUNICODE_STRING ServiceName,
497 PDEVICE_NODE *DeviceNode)
498 {
499 PDEVICE_NODE Node;
500 NTSTATUS Status;
501 KIRQL OldIrql;
502 UNICODE_STRING FullServiceName;
503 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
504 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
505 UNICODE_STRING KeyName, ClassName;
506 PUNICODE_STRING ServiceName1;
507 ULONG LegacyValue;
508 #if 0
509 UNICODE_STRING ClassGUID;
510 #endif
511 HANDLE InstanceHandle;
512
513 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
514 ParentNode, PhysicalDeviceObject, ServiceName);
515
516 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
517 if (!Node)
518 {
519 return STATUS_INSUFFICIENT_RESOURCES;
520 }
521
522 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
523
524 if (!ServiceName)
525 ServiceName1 = &UnknownDeviceName;
526 else
527 ServiceName1 = ServiceName;
528
529 if (!PhysicalDeviceObject)
530 {
531 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length;
532 FullServiceName.Length = 0;
533 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
534 if (!FullServiceName.Buffer)
535 {
536 ExFreePool(Node);
537 return STATUS_INSUFFICIENT_RESOURCES;
538 }
539
540 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
541 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
542
543 Status = PnpRootCreateDevice(&FullServiceName, &PhysicalDeviceObject, &Node->InstancePath);
544 if (!NT_SUCCESS(Status))
545 {
546 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
547 ExFreePool(Node);
548 return Status;
549 }
550
551 /* Create the device key for legacy drivers */
552 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
553 if (!NT_SUCCESS(Status))
554 {
555 ZwClose(InstanceHandle);
556 ExFreePool(Node);
557 ExFreePool(FullServiceName.Buffer);
558 return Status;
559 }
560
561 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, ServiceName1->Length);
562 if (!Node->ServiceName.Buffer)
563 {
564 ZwClose(InstanceHandle);
565 ExFreePool(Node);
566 ExFreePool(FullServiceName.Buffer);
567 return Status;
568 }
569
570 Node->ServiceName.MaximumLength = ServiceName1->Length;
571 Node->ServiceName.Length = 0;
572
573 RtlAppendUnicodeStringToString(&Node->ServiceName, ServiceName1);
574
575 if (ServiceName)
576 {
577 RtlInitUnicodeString(&KeyName, L"Service");
578 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length);
579 }
580
581 if (NT_SUCCESS(Status))
582 {
583 RtlInitUnicodeString(&KeyName, L"Legacy");
584
585 LegacyValue = 1;
586 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
587 if (NT_SUCCESS(Status))
588 {
589 RtlInitUnicodeString(&KeyName, L"Class");
590
591 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
592 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length);
593 #if 0
594 if (NT_SUCCESS(Status))
595 {
596 RtlInitUnicodeString(&KeyName, L"ClassGUID");
597
598 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
599 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length);
600 }
601 #endif
602 }
603 }
604
605 ZwClose(InstanceHandle);
606 ExFreePool(FullServiceName.Buffer);
607
608 if (!NT_SUCCESS(Status))
609 {
610 ExFreePool(Node);
611 return Status;
612 }
613
614 /* This is for drivers passed on the command line to ntoskrnl.exe */
615 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
616 }
617
618 Node->PhysicalDeviceObject = PhysicalDeviceObject;
619
620 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
621
622 if (ParentNode)
623 {
624 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
625 Node->Parent = ParentNode;
626 Node->Sibling = ParentNode->Child;
627 ParentNode->Child = Node;
628 if (ParentNode->LastChild == NULL)
629 ParentNode->LastChild = Node;
630 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
631 Node->Level = ParentNode->Level + 1;
632 }
633
634 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
635
636 *DeviceNode = Node;
637
638 return STATUS_SUCCESS;
639 }
640
641 NTSTATUS
642 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
643 {
644 KIRQL OldIrql;
645 PDEVICE_NODE PrevSibling = NULL;
646
647 /* All children must be deleted before a parent is deleted */
648 ASSERT(!DeviceNode->Child);
649
650 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
651
652 ASSERT(DeviceNode->PhysicalDeviceObject);
653
654 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
655
656 /* Get previous sibling */
657 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
658 {
659 PrevSibling = DeviceNode->Parent->Child;
660 while (PrevSibling->Sibling != DeviceNode)
661 PrevSibling = PrevSibling->Sibling;
662 }
663
664 /* Unlink from parent if it exists */
665 if (DeviceNode->Parent)
666 {
667 if (DeviceNode->Parent->LastChild == DeviceNode)
668 {
669 DeviceNode->Parent->LastChild = PrevSibling;
670 if (PrevSibling)
671 PrevSibling->Sibling = NULL;
672 }
673 if (DeviceNode->Parent->Child == DeviceNode)
674 DeviceNode->Parent->Child = DeviceNode->Sibling;
675 }
676
677 /* Unlink from sibling list */
678 if (PrevSibling)
679 PrevSibling->Sibling = DeviceNode->Sibling;
680
681 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
682
683 RtlFreeUnicodeString(&DeviceNode->InstancePath);
684
685 RtlFreeUnicodeString(&DeviceNode->ServiceName);
686
687 if (DeviceNode->ResourceList)
688 {
689 ExFreePool(DeviceNode->ResourceList);
690 }
691
692 if (DeviceNode->ResourceListTranslated)
693 {
694 ExFreePool(DeviceNode->ResourceListTranslated);
695 }
696
697 if (DeviceNode->ResourceRequirements)
698 {
699 ExFreePool(DeviceNode->ResourceRequirements);
700 }
701
702 if (DeviceNode->BootResources)
703 {
704 ExFreePool(DeviceNode->BootResources);
705 }
706
707 ExFreePool(DeviceNode);
708
709 return STATUS_SUCCESS;
710 }
711
712 NTSTATUS
713 NTAPI
714 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
715 IN PIO_STACK_LOCATION IoStackLocation,
716 OUT PVOID *Information)
717 {
718 PIRP Irp;
719 PIO_STACK_LOCATION IrpStack;
720 IO_STATUS_BLOCK IoStatusBlock;
721 KEVENT Event;
722 NTSTATUS Status;
723 PDEVICE_OBJECT TopDeviceObject;
724 PAGED_CODE();
725
726 /* Call the top of the device stack */
727 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
728
729 /* Allocate an IRP */
730 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
731 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
732
733 /* Initialize to failure */
734 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
735 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
736
737 /* Initialize the event */
738 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
739
740 /* Set them up */
741 Irp->UserIosb = &IoStatusBlock;
742 Irp->UserEvent = &Event;
743
744 /* Queue the IRP */
745 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
746 IoQueueThreadIrp(Irp);
747
748 /* Copy-in the stack */
749 IrpStack = IoGetNextIrpStackLocation(Irp);
750 *IrpStack = *IoStackLocation;
751
752 /* Call the driver */
753 Status = IoCallDriver(TopDeviceObject, Irp);
754 if (Status == STATUS_PENDING)
755 {
756 /* Wait for it */
757 KeWaitForSingleObject(&Event,
758 Executive,
759 KernelMode,
760 FALSE,
761 NULL);
762 Status = IoStatusBlock.Status;
763 }
764
765 /* Return the information */
766 *Information = (PVOID)IoStatusBlock.Information;
767 return Status;
768 }
769
770 NTSTATUS
771 NTAPI
772 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
773 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
774 IN ULONG MinorFunction,
775 IN PIO_STACK_LOCATION Stack OPTIONAL)
776 {
777 IO_STACK_LOCATION IoStackLocation;
778
779 /* Fill out the stack information */
780 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
781 IoStackLocation.MajorFunction = IRP_MJ_PNP;
782 IoStackLocation.MinorFunction = MinorFunction;
783 if (Stack)
784 {
785 /* Copy the rest */
786 RtlCopyMemory(&IoStackLocation.Parameters,
787 &Stack->Parameters,
788 sizeof(Stack->Parameters));
789 }
790
791 /* Do the PnP call */
792 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
793 &IoStackLocation,
794 (PVOID)&IoStatusBlock->Information);
795 return IoStatusBlock->Status;
796 }
797
798 NTSTATUS
799 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
800 {
801 PDEVICE_NODE ParentDeviceNode;
802 PDEVICE_NODE ChildDeviceNode;
803 NTSTATUS Status;
804
805 /* Copy context data so we don't overwrite it in subsequent calls to this function */
806 ParentDeviceNode = Context->DeviceNode;
807
808 /* Call the action routine */
809 Status = (Context->Action)(ParentDeviceNode, Context->Context);
810 if (!NT_SUCCESS(Status))
811 {
812 return Status;
813 }
814
815 /* Traversal of all children nodes */
816 for (ChildDeviceNode = ParentDeviceNode->Child;
817 ChildDeviceNode != NULL;
818 ChildDeviceNode = ChildDeviceNode->Sibling)
819 {
820 /* Pass the current device node to the action routine */
821 Context->DeviceNode = ChildDeviceNode;
822
823 Status = IopTraverseDeviceTreeNode(Context);
824 if (!NT_SUCCESS(Status))
825 {
826 return Status;
827 }
828 }
829
830 return Status;
831 }
832
833
834 NTSTATUS
835 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
836 {
837 NTSTATUS Status;
838
839 DPRINT("Context 0x%p\n", Context);
840
841 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
842 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
843
844 /* Start from the specified device node */
845 Context->DeviceNode = Context->FirstDeviceNode;
846
847 /* Recursively traverse the device tree */
848 Status = IopTraverseDeviceTreeNode(Context);
849 if (Status == STATUS_UNSUCCESSFUL)
850 {
851 /* The action routine just wanted to terminate the traversal with status
852 code STATUS_SUCCESS */
853 Status = STATUS_SUCCESS;
854 }
855
856 return Status;
857 }
858
859
860 /*
861 * IopCreateDeviceKeyPath
862 *
863 * Creates a registry key
864 *
865 * Parameters
866 * RegistryPath
867 * Name of the key to be created.
868 * Handle
869 * Handle to the newly created key
870 *
871 * Remarks
872 * This method can create nested trees, so parent of RegistryPath can
873 * be not existant, and will be created if needed.
874 */
875 NTSTATUS
876 NTAPI
877 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
878 IN ULONG CreateOptions,
879 OUT PHANDLE Handle)
880 {
881 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
882 HANDLE hParent = NULL, hKey;
883 OBJECT_ATTRIBUTES ObjectAttributes;
884 UNICODE_STRING KeyName;
885 LPCWSTR Current, Last;
886 ULONG dwLength;
887 NTSTATUS Status;
888
889 /* Assume failure */
890 *Handle = NULL;
891
892 /* Open root key for device instances */
893 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
894 if (!NT_SUCCESS(Status))
895 {
896 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
897 return Status;
898 }
899
900 Current = KeyName.Buffer = RegistryPath->Buffer;
901 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
902
903 /* Go up to the end of the string */
904 while (Current <= Last)
905 {
906 if (Current != Last && *Current != '\\')
907 {
908 /* Not the end of the string and not a separator */
909 Current++;
910 continue;
911 }
912
913 /* Prepare relative key name */
914 dwLength = (ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer;
915 KeyName.MaximumLength = KeyName.Length = dwLength;
916 DPRINT("Create '%wZ'\n", &KeyName);
917
918 /* Open key */
919 InitializeObjectAttributes(&ObjectAttributes,
920 &KeyName,
921 OBJ_CASE_INSENSITIVE,
922 hParent,
923 NULL);
924 Status = ZwCreateKey(&hKey,
925 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
926 &ObjectAttributes,
927 0,
928 NULL,
929 CreateOptions,
930 NULL);
931
932 /* Close parent key handle, we don't need it anymore */
933 if (hParent)
934 ZwClose(hParent);
935
936 /* Key opening/creating failed? */
937 if (!NT_SUCCESS(Status))
938 {
939 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
940 return Status;
941 }
942
943 /* Check if it is the end of the string */
944 if (Current == Last)
945 {
946 /* Yes, return success */
947 *Handle = hKey;
948 return STATUS_SUCCESS;
949 }
950
951 /* Start with this new parent key */
952 hParent = hKey;
953 Current++;
954 KeyName.Buffer = (LPWSTR)Current;
955 }
956
957 return STATUS_UNSUCCESSFUL;
958 }
959
960 NTSTATUS
961 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode, PWCHAR Level1Key, PWCHAR Level2Key)
962 {
963 NTSTATUS Status;
964 ULONG Disposition;
965 HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey;
966 UNICODE_STRING KeyName;
967 OBJECT_ATTRIBUTES ObjectAttributes;
968
969 RtlInitUnicodeString(&KeyName,
970 L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
971 InitializeObjectAttributes(&ObjectAttributes,
972 &KeyName,
973 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
974 0,
975 NULL);
976 Status = ZwCreateKey(&ResourceMapKey,
977 KEY_ALL_ACCESS,
978 &ObjectAttributes,
979 0,
980 NULL,
981 REG_OPTION_VOLATILE,
982 &Disposition);
983 if (!NT_SUCCESS(Status))
984 return Status;
985
986 RtlInitUnicodeString(&KeyName, Level1Key);
987 InitializeObjectAttributes(&ObjectAttributes,
988 &KeyName,
989 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
990 ResourceMapKey,
991 NULL);
992 Status = ZwCreateKey(&PnpMgrLevel1,
993 KEY_ALL_ACCESS,
994 &ObjectAttributes,
995 0,
996 NULL,
997 REG_OPTION_VOLATILE,
998 &Disposition);
999 ZwClose(ResourceMapKey);
1000 if (!NT_SUCCESS(Status))
1001 return Status;
1002
1003 RtlInitUnicodeString(&KeyName, Level2Key);
1004 InitializeObjectAttributes(&ObjectAttributes,
1005 &KeyName,
1006 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1007 PnpMgrLevel1,
1008 NULL);
1009 Status = ZwCreateKey(&PnpMgrLevel2,
1010 KEY_ALL_ACCESS,
1011 &ObjectAttributes,
1012 0,
1013 NULL,
1014 REG_OPTION_VOLATILE,
1015 &Disposition);
1016 ZwClose(PnpMgrLevel1);
1017 if (!NT_SUCCESS(Status))
1018 return Status;
1019
1020 if (DeviceNode->ResourceList)
1021 {
1022 WCHAR NameBuff[256];
1023 UNICODE_STRING NameU;
1024 UNICODE_STRING Suffix;
1025 ULONG OldLength;
1026
1027 ASSERT(DeviceNode->ResourceListTranslated);
1028
1029 NameU.Buffer = NameBuff;
1030 NameU.Length = 0;
1031 NameU.MaximumLength = 256 * sizeof(WCHAR);
1032
1033 Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
1034 DevicePropertyPhysicalDeviceObjectName,
1035 NameU.MaximumLength,
1036 NameU.Buffer,
1037 &OldLength);
1038 ASSERT(Status == STATUS_SUCCESS);
1039
1040 NameU.Length = (USHORT)OldLength;
1041
1042 RtlInitUnicodeString(&Suffix, L".Raw");
1043 RtlAppendUnicodeStringToString(&NameU, &Suffix);
1044
1045 Status = ZwSetValueKey(PnpMgrLevel2,
1046 &NameU,
1047 0,
1048 REG_RESOURCE_LIST,
1049 DeviceNode->ResourceList,
1050 CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceList));
1051 if (!NT_SUCCESS(Status))
1052 {
1053 ZwClose(PnpMgrLevel2);
1054 return Status;
1055 }
1056
1057 /* "Remove" the suffix by setting the length back to what it used to be */
1058 NameU.Length = (USHORT)OldLength;
1059
1060 RtlInitUnicodeString(&Suffix, L".Translated");
1061 RtlAppendUnicodeStringToString(&NameU, &Suffix);
1062
1063 Status = ZwSetValueKey(PnpMgrLevel2,
1064 &NameU,
1065 0,
1066 REG_RESOURCE_LIST,
1067 DeviceNode->ResourceListTranslated,
1068 CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceListTranslated));
1069 ZwClose(PnpMgrLevel2);
1070 if (!NT_SUCCESS(Status))
1071 return Status;
1072 }
1073 else
1074 {
1075 ZwClose(PnpMgrLevel2);
1076 }
1077
1078 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
1079
1080 return STATUS_SUCCESS;
1081 }
1082
1083 NTSTATUS
1084 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode)
1085 {
1086 return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager");
1087 }
1088
1089 NTSTATUS
1090 IopSetDeviceInstanceData(HANDLE InstanceKey,
1091 PDEVICE_NODE DeviceNode)
1092 {
1093 OBJECT_ATTRIBUTES ObjectAttributes;
1094 UNICODE_STRING KeyName;
1095 HANDLE LogConfKey;
1096 ULONG ResCount;
1097 ULONG ListSize, ResultLength;
1098 NTSTATUS Status;
1099 HANDLE ControlHandle;
1100
1101 DPRINT("IopSetDeviceInstanceData() called\n");
1102
1103 /* Create the 'LogConf' key */
1104 RtlInitUnicodeString(&KeyName, L"LogConf");
1105 InitializeObjectAttributes(&ObjectAttributes,
1106 &KeyName,
1107 OBJ_CASE_INSENSITIVE,
1108 InstanceKey,
1109 NULL);
1110 Status = ZwCreateKey(&LogConfKey,
1111 KEY_ALL_ACCESS,
1112 &ObjectAttributes,
1113 0,
1114 NULL,
1115 0,
1116 NULL);
1117 if (NT_SUCCESS(Status))
1118 {
1119 /* Set 'BootConfig' value */
1120 if (DeviceNode->BootResources != NULL)
1121 {
1122 ResCount = DeviceNode->BootResources->Count;
1123 if (ResCount != 0)
1124 {
1125 ListSize = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
1126
1127 RtlInitUnicodeString(&KeyName, L"BootConfig");
1128 Status = ZwSetValueKey(LogConfKey,
1129 &KeyName,
1130 0,
1131 REG_RESOURCE_LIST,
1132 DeviceNode->BootResources,
1133 ListSize);
1134 }
1135 }
1136
1137 /* Set 'BasicConfigVector' value */
1138 if (DeviceNode->ResourceRequirements != NULL &&
1139 DeviceNode->ResourceRequirements->ListSize != 0)
1140 {
1141 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1142 Status = ZwSetValueKey(LogConfKey,
1143 &KeyName,
1144 0,
1145 REG_RESOURCE_REQUIREMENTS_LIST,
1146 DeviceNode->ResourceRequirements,
1147 DeviceNode->ResourceRequirements->ListSize);
1148 }
1149
1150 ZwClose(LogConfKey);
1151 }
1152
1153 /* Set the 'ConfigFlags' value */
1154 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1155 Status = ZwQueryValueKey(InstanceKey,
1156 &KeyName,
1157 KeyValueBasicInformation,
1158 NULL,
1159 0,
1160 &ResultLength);
1161 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1162 {
1163 /* Write the default value */
1164 ULONG DefaultConfigFlags = 0;
1165 Status = ZwSetValueKey(InstanceKey,
1166 &KeyName,
1167 0,
1168 REG_DWORD,
1169 &DefaultConfigFlags,
1170 sizeof(DefaultConfigFlags));
1171 }
1172
1173 /* Create the 'Control' key */
1174 RtlInitUnicodeString(&KeyName, L"Control");
1175 InitializeObjectAttributes(&ObjectAttributes,
1176 &KeyName,
1177 OBJ_CASE_INSENSITIVE,
1178 InstanceKey,
1179 NULL);
1180 Status = ZwCreateKey(&ControlHandle, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
1181
1182 if (NT_SUCCESS(Status))
1183 ZwClose(ControlHandle);
1184
1185 DPRINT("IopSetDeviceInstanceData() done\n");
1186
1187 return Status;
1188 }
1189
1190 BOOLEAN
1191 IopCheckResourceDescriptor(
1192 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc,
1193 IN PCM_RESOURCE_LIST ResourceList,
1194 IN BOOLEAN Silent,
1195 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1196 {
1197 ULONG i, ii;
1198 BOOLEAN Result = FALSE;
1199
1200 if (ResDesc->ShareDisposition == CmResourceShareShared)
1201 return FALSE;
1202
1203 for (i = 0; i < ResourceList->Count; i++)
1204 {
1205 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList->List[i].PartialResourceList;
1206 for (ii = 0; ii < ResList->Count; ii++)
1207 {
1208 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList->PartialDescriptors[ii];
1209
1210 /* We don't care about shared resources */
1211 if (ResDesc->ShareDisposition == CmResourceShareShared &&
1212 ResDesc2->ShareDisposition == CmResourceShareShared)
1213 continue;
1214
1215 /* Make sure we're comparing the same types */
1216 if (ResDesc->Type != ResDesc2->Type)
1217 continue;
1218
1219 switch (ResDesc->Type)
1220 {
1221 case CmResourceTypeMemory:
1222 if ((ResDesc->u.Memory.Start.QuadPart < ResDesc2->u.Memory.Start.QuadPart &&
1223 ResDesc->u.Memory.Start.QuadPart + ResDesc->u.Memory.Length >
1224 ResDesc2->u.Memory.Start.QuadPart) || (ResDesc2->u.Memory.Start.QuadPart <
1225 ResDesc->u.Memory.Start.QuadPart && ResDesc2->u.Memory.Start.QuadPart +
1226 ResDesc2->u.Memory.Length > ResDesc->u.Memory.Start.QuadPart))
1227 {
1228 if (!Silent)
1229 {
1230 DPRINT1("Resource conflict: Memory (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1231 ResDesc->u.Memory.Start.QuadPart, ResDesc->u.Memory.Start.QuadPart +
1232 ResDesc->u.Memory.Length, ResDesc2->u.Memory.Start.QuadPart,
1233 ResDesc2->u.Memory.Start.QuadPart + ResDesc2->u.Memory.Length);
1234 }
1235
1236 Result = TRUE;
1237
1238 goto ByeBye;
1239 }
1240 break;
1241
1242 case CmResourceTypePort:
1243 if ((ResDesc->u.Port.Start.QuadPart < ResDesc2->u.Port.Start.QuadPart &&
1244 ResDesc->u.Port.Start.QuadPart + ResDesc->u.Port.Length >
1245 ResDesc2->u.Port.Start.QuadPart) || (ResDesc2->u.Port.Start.QuadPart <
1246 ResDesc->u.Port.Start.QuadPart && ResDesc2->u.Port.Start.QuadPart +
1247 ResDesc2->u.Port.Length > ResDesc->u.Port.Start.QuadPart))
1248 {
1249 if (!Silent)
1250 {
1251 DPRINT1("Resource conflict: Port (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1252 ResDesc->u.Port.Start.QuadPart, ResDesc->u.Port.Start.QuadPart +
1253 ResDesc->u.Port.Length, ResDesc2->u.Port.Start.QuadPart,
1254 ResDesc2->u.Port.Start.QuadPart + ResDesc2->u.Port.Length);
1255 }
1256
1257 Result = TRUE;
1258
1259 goto ByeBye;
1260 }
1261 break;
1262
1263 case CmResourceTypeInterrupt:
1264 if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector)
1265 {
1266 if (!Silent)
1267 {
1268 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
1269 ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level,
1270 ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level);
1271 }
1272
1273 Result = TRUE;
1274
1275 goto ByeBye;
1276 }
1277 break;
1278
1279 case CmResourceTypeBusNumber:
1280 if ((ResDesc->u.BusNumber.Start < ResDesc2->u.BusNumber.Start &&
1281 ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length >
1282 ResDesc2->u.BusNumber.Start) || (ResDesc2->u.BusNumber.Start <
1283 ResDesc->u.BusNumber.Start && ResDesc2->u.BusNumber.Start +
1284 ResDesc2->u.BusNumber.Length > ResDesc->u.BusNumber.Start))
1285 {
1286 if (!Silent)
1287 {
1288 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1289 ResDesc->u.BusNumber.Start, ResDesc->u.BusNumber.Start +
1290 ResDesc->u.BusNumber.Length, ResDesc2->u.BusNumber.Start,
1291 ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length);
1292 }
1293
1294 Result = TRUE;
1295
1296 goto ByeBye;
1297 }
1298 break;
1299
1300 case CmResourceTypeDma:
1301 if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel)
1302 {
1303 if (!Silent)
1304 {
1305 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
1306 ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port,
1307 ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port);
1308 }
1309
1310 Result = TRUE;
1311
1312 goto ByeBye;
1313 }
1314 break;
1315 }
1316 }
1317 }
1318
1319 ByeBye:
1320
1321 if (Result && ConflictingDescriptor)
1322 {
1323 RtlCopyMemory(ConflictingDescriptor,
1324 ResDesc,
1325 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1326 }
1327
1328 return Result;
1329 }
1330
1331
1332 BOOLEAN
1333 IopCheckForResourceConflict(
1334 IN PCM_RESOURCE_LIST ResourceList1,
1335 IN PCM_RESOURCE_LIST ResourceList2,
1336 IN BOOLEAN Silent,
1337 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1338 {
1339 ULONG i, ii;
1340 BOOLEAN Result = FALSE;
1341
1342 for (i = 0; i < ResourceList1->Count; i++)
1343 {
1344 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList1->List[i].PartialResourceList;
1345 for (ii = 0; ii < ResList->Count; ii++)
1346 {
1347 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
1348
1349 Result = IopCheckResourceDescriptor(ResDesc,
1350 ResourceList2,
1351 Silent,
1352 ConflictingDescriptor);
1353 if (Result) goto ByeBye;
1354 }
1355 }
1356
1357
1358 ByeBye:
1359
1360 return Result;
1361 }
1362
1363 NTSTATUS
1364 IopDetectResourceConflict(
1365 IN PCM_RESOURCE_LIST ResourceList,
1366 IN BOOLEAN Silent,
1367 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1368 {
1369 OBJECT_ATTRIBUTES ObjectAttributes;
1370 UNICODE_STRING KeyName;
1371 HANDLE ResourceMapKey = INVALID_HANDLE_VALUE, ChildKey2 = INVALID_HANDLE_VALUE, ChildKey3 = INVALID_HANDLE_VALUE;
1372 ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
1373 PKEY_BASIC_INFORMATION KeyInformation;
1374 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
1375 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
1376 ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0;
1377 NTSTATUS Status;
1378
1379 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1380 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL);
1381 Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1382 if (!NT_SUCCESS(Status))
1383 {
1384 /* The key is missing which means we are the first device */
1385 return STATUS_SUCCESS;
1386 }
1387
1388 while (TRUE)
1389 {
1390 Status = ZwEnumerateKey(ResourceMapKey,
1391 ChildKeyIndex1,
1392 KeyBasicInformation,
1393 NULL,
1394 0,
1395 &RequiredLength);
1396 if (Status == STATUS_NO_MORE_ENTRIES)
1397 break;
1398 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1399 {
1400 KeyInformationLength = RequiredLength;
1401 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1402 if (!KeyInformation)
1403 {
1404 Status = STATUS_INSUFFICIENT_RESOURCES;
1405 goto cleanup;
1406 }
1407
1408 Status = ZwEnumerateKey(ResourceMapKey,
1409 ChildKeyIndex1,
1410 KeyBasicInformation,
1411 KeyInformation,
1412 KeyInformationLength,
1413 &RequiredLength);
1414 }
1415 else
1416 goto cleanup;
1417 ChildKeyIndex1++;
1418 if (!NT_SUCCESS(Status))
1419 goto cleanup;
1420
1421 KeyName.Buffer = KeyInformation->Name;
1422 KeyName.MaximumLength = KeyName.Length = KeyInformation->NameLength;
1423 InitializeObjectAttributes(&ObjectAttributes,
1424 &KeyName,
1425 OBJ_CASE_INSENSITIVE,
1426 ResourceMapKey,
1427 NULL);
1428 Status = ZwOpenKey(&ChildKey2, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1429 ExFreePool(KeyInformation);
1430 if (!NT_SUCCESS(Status))
1431 goto cleanup;
1432
1433 while (TRUE)
1434 {
1435 Status = ZwEnumerateKey(ChildKey2,
1436 ChildKeyIndex2,
1437 KeyBasicInformation,
1438 NULL,
1439 0,
1440 &RequiredLength);
1441 if (Status == STATUS_NO_MORE_ENTRIES)
1442 break;
1443 else if (Status == STATUS_BUFFER_TOO_SMALL)
1444 {
1445 KeyInformationLength = RequiredLength;
1446 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1447 if (!KeyInformation)
1448 {
1449 Status = STATUS_INSUFFICIENT_RESOURCES;
1450 goto cleanup;
1451 }
1452
1453 Status = ZwEnumerateKey(ChildKey2,
1454 ChildKeyIndex2,
1455 KeyBasicInformation,
1456 KeyInformation,
1457 KeyInformationLength,
1458 &RequiredLength);
1459 }
1460 else
1461 goto cleanup;
1462 ChildKeyIndex2++;
1463 if (!NT_SUCCESS(Status))
1464 goto cleanup;
1465
1466 KeyName.Buffer = KeyInformation->Name;
1467 KeyName.MaximumLength = KeyName.Length = KeyInformation->NameLength;
1468 InitializeObjectAttributes(&ObjectAttributes,
1469 &KeyName,
1470 OBJ_CASE_INSENSITIVE,
1471 ChildKey2,
1472 NULL);
1473 Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
1474 ExFreePool(KeyInformation);
1475 if (!NT_SUCCESS(Status))
1476 goto cleanup;
1477
1478 while (TRUE)
1479 {
1480 Status = ZwEnumerateValueKey(ChildKey3,
1481 ChildKeyIndex3,
1482 KeyValuePartialInformation,
1483 NULL,
1484 0,
1485 &RequiredLength);
1486 if (Status == STATUS_NO_MORE_ENTRIES)
1487 break;
1488 else if (Status == STATUS_BUFFER_TOO_SMALL)
1489 {
1490 KeyValueInformationLength = RequiredLength;
1491 KeyValueInformation = ExAllocatePool(PagedPool, KeyValueInformationLength);
1492 if (!KeyValueInformation)
1493 {
1494 Status = STATUS_INSUFFICIENT_RESOURCES;
1495 goto cleanup;
1496 }
1497
1498 Status = ZwEnumerateValueKey(ChildKey3,
1499 ChildKeyIndex3,
1500 KeyValuePartialInformation,
1501 KeyValueInformation,
1502 KeyValueInformationLength,
1503 &RequiredLength);
1504 }
1505 else
1506 goto cleanup;
1507 if (!NT_SUCCESS(Status))
1508 goto cleanup;
1509
1510 Status = ZwEnumerateValueKey(ChildKey3,
1511 ChildKeyIndex3,
1512 KeyValueBasicInformation,
1513 NULL,
1514 0,
1515 &RequiredLength);
1516 if (Status == STATUS_BUFFER_TOO_SMALL)
1517 {
1518 KeyNameInformationLength = RequiredLength;
1519 KeyNameInformation = ExAllocatePool(PagedPool, KeyNameInformationLength + sizeof(WCHAR));
1520 if (!KeyNameInformation)
1521 {
1522 Status = STATUS_INSUFFICIENT_RESOURCES;
1523 goto cleanup;
1524 }
1525
1526 Status = ZwEnumerateValueKey(ChildKey3,
1527 ChildKeyIndex3,
1528 KeyValueBasicInformation,
1529 KeyNameInformation,
1530 KeyNameInformationLength,
1531 &RequiredLength);
1532 }
1533 else
1534 goto cleanup;
1535
1536 ChildKeyIndex3++;
1537
1538 if (!NT_SUCCESS(Status))
1539 goto cleanup;
1540
1541 KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
1542
1543 /* Skip translated entries */
1544 if (wcsstr(KeyNameInformation->Name, L".Translated"))
1545 {
1546 ExFreePool(KeyNameInformation);
1547 continue;
1548 }
1549
1550 ExFreePool(KeyNameInformation);
1551
1552 if (IopCheckForResourceConflict(ResourceList,
1553 (PCM_RESOURCE_LIST)KeyValueInformation->Data,
1554 Silent,
1555 ConflictingDescriptor))
1556 {
1557 ExFreePool(KeyValueInformation);
1558 Status = STATUS_CONFLICTING_ADDRESSES;
1559 goto cleanup;
1560 }
1561
1562 ExFreePool(KeyValueInformation);
1563 }
1564 }
1565 }
1566
1567 cleanup:
1568 if (ResourceMapKey != INVALID_HANDLE_VALUE)
1569 ZwClose(ResourceMapKey);
1570 if (ChildKey2 != INVALID_HANDLE_VALUE)
1571 ZwClose(ChildKey2);
1572 if (ChildKey3 != INVALID_HANDLE_VALUE)
1573 ZwClose(ChildKey3);
1574
1575 if (Status == STATUS_NO_MORE_ENTRIES)
1576 Status = STATUS_SUCCESS;
1577
1578 return Status;
1579 }
1580
1581 BOOLEAN
1582 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1583 {
1584 CM_RESOURCE_LIST CmList;
1585 NTSTATUS Status;
1586
1587 CmList.Count = 1;
1588 CmList.List[0].InterfaceType = InterfaceTypeUndefined;
1589 CmList.List[0].BusNumber = 0;
1590 CmList.List[0].PartialResourceList.Version = 1;
1591 CmList.List[0].PartialResourceList.Revision = 1;
1592 CmList.List[0].PartialResourceList.Count = 1;
1593 CmList.List[0].PartialResourceList.PartialDescriptors[0] = *CmDesc;
1594
1595 Status = IopDetectResourceConflict(&CmList, TRUE, ConflictingDescriptor);
1596 if (Status == STATUS_CONFLICTING_ADDRESSES)
1597 return TRUE;
1598
1599 return FALSE;
1600 }
1601
1602 BOOLEAN
1603 IopFindBusNumberResource(
1604 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1605 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1606 {
1607 ULONG Start;
1608 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1609
1610 ASSERT(IoDesc->Type == CmDesc->Type);
1611 ASSERT(IoDesc->Type == CmResourceTypeBusNumber);
1612
1613 for (Start = IoDesc->u.BusNumber.MinBusNumber;
1614 Start < IoDesc->u.BusNumber.MaxBusNumber;
1615 Start++)
1616 {
1617 CmDesc->u.BusNumber.Length = IoDesc->u.BusNumber.Length;
1618 CmDesc->u.BusNumber.Start = Start;
1619
1620 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1621 {
1622 Start += ConflictingDesc.u.BusNumber.Start + ConflictingDesc.u.BusNumber.Length;
1623 }
1624 else
1625 {
1626 return TRUE;
1627 }
1628 }
1629
1630 return FALSE;
1631 }
1632
1633 BOOLEAN
1634 IopFindMemoryResource(
1635 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1636 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1637 {
1638 ULONGLONG Start;
1639 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1640
1641 ASSERT(IoDesc->Type == CmDesc->Type);
1642 ASSERT(IoDesc->Type == CmResourceTypeMemory);
1643
1644 for (Start = IoDesc->u.Memory.MinimumAddress.QuadPart;
1645 Start < IoDesc->u.Memory.MaximumAddress.QuadPart;
1646 Start++)
1647 {
1648 CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
1649 CmDesc->u.Memory.Start.QuadPart = Start;
1650
1651 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1652 {
1653 Start += ConflictingDesc.u.Memory.Start.QuadPart + ConflictingDesc.u.Memory.Length;
1654 }
1655 else
1656 {
1657 return TRUE;
1658 }
1659 }
1660
1661 return FALSE;
1662 }
1663
1664 BOOLEAN
1665 IopFindPortResource(
1666 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1667 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1668 {
1669 ULONGLONG Start;
1670 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1671
1672 ASSERT(IoDesc->Type == CmDesc->Type);
1673 ASSERT(IoDesc->Type == CmResourceTypePort);
1674
1675 for (Start = IoDesc->u.Port.MinimumAddress.QuadPart;
1676 Start < IoDesc->u.Port.MaximumAddress.QuadPart;
1677 Start++)
1678 {
1679 CmDesc->u.Port.Length = IoDesc->u.Port.Length;
1680 CmDesc->u.Port.Start.QuadPart = Start;
1681
1682 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1683 {
1684 Start += ConflictingDesc.u.Port.Start.QuadPart + ConflictingDesc.u.Port.Length;
1685 }
1686 else
1687 {
1688 return TRUE;
1689 }
1690 }
1691
1692 return FALSE;
1693 }
1694
1695 BOOLEAN
1696 IopFindDmaResource(
1697 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1698 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1699 {
1700 ULONG Channel;
1701
1702 ASSERT(IoDesc->Type == CmDesc->Type);
1703 ASSERT(IoDesc->Type == CmResourceTypeDma);
1704
1705 for (Channel = IoDesc->u.Dma.MinimumChannel;
1706 Channel < IoDesc->u.Dma.MaximumChannel;
1707 Channel++)
1708 {
1709 CmDesc->u.Dma.Channel = Channel;
1710 CmDesc->u.Dma.Port = 0;
1711
1712 if (!IopCheckDescriptorForConflict(CmDesc, NULL))
1713 return TRUE;
1714 }
1715
1716 return FALSE;
1717 }
1718
1719 BOOLEAN
1720 IopFindInterruptResource(
1721 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1722 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1723 {
1724 ULONG Vector;
1725
1726 ASSERT(IoDesc->Type == CmDesc->Type);
1727 ASSERT(IoDesc->Type == CmResourceTypeInterrupt);
1728
1729 for (Vector = IoDesc->u.Interrupt.MinimumVector;
1730 Vector < IoDesc->u.Interrupt.MaximumVector;
1731 Vector++)
1732 {
1733 CmDesc->u.Interrupt.Vector = Vector;
1734 CmDesc->u.Interrupt.Level = Vector;
1735 CmDesc->u.Interrupt.Affinity = (KAFFINITY)-1;
1736
1737 if (!IopCheckDescriptorForConflict(CmDesc, NULL))
1738 return TRUE;
1739 }
1740
1741 return FALSE;
1742 }
1743
1744 NTSTATUS
1745 IopCreateResourceListFromRequirements(
1746 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList,
1747 OUT PCM_RESOURCE_LIST *ResourceList)
1748 {
1749 ULONG i, ii, Size;
1750 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc;
1751
1752 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1753 for (i = 0; i < RequirementsList->AlternativeLists; i++)
1754 {
1755 PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
1756 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
1757 + ResList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1758 }
1759
1760 *ResourceList = ExAllocatePool(PagedPool, Size);
1761 if (!*ResourceList)
1762 return STATUS_INSUFFICIENT_RESOURCES;
1763
1764 (*ResourceList)->Count = 1;
1765 (*ResourceList)->List[0].BusNumber = RequirementsList->BusNumber;
1766 (*ResourceList)->List[0].InterfaceType = RequirementsList->InterfaceType;
1767 (*ResourceList)->List[0].PartialResourceList.Version = 1;
1768 (*ResourceList)->List[0].PartialResourceList.Revision = 1;
1769 (*ResourceList)->List[0].PartialResourceList.Count = 0;
1770
1771 ResDesc = &(*ResourceList)->List[0].PartialResourceList.PartialDescriptors[0];
1772
1773 for (i = 0; i < RequirementsList->AlternativeLists; i++)
1774 {
1775 PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
1776 for (ii = 0; ii < ResList->Count; ii++)
1777 {
1778 PIO_RESOURCE_DESCRIPTOR ReqDesc = &ResList->Descriptors[ii];
1779
1780 /* FIXME: Handle alternate ranges */
1781 if (ReqDesc->Option == IO_RESOURCE_ALTERNATIVE)
1782 continue;
1783
1784 ResDesc->Type = ReqDesc->Type;
1785 ResDesc->Flags = ReqDesc->Flags;
1786 ResDesc->ShareDisposition = ReqDesc->ShareDisposition;
1787
1788 switch (ReqDesc->Type)
1789 {
1790 case CmResourceTypeInterrupt:
1791 if (!IopFindInterruptResource(ReqDesc, ResDesc))
1792 {
1793 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
1794 ReqDesc->u.Interrupt.MinimumVector, ReqDesc->u.Interrupt.MaximumVector);
1795
1796 if (ReqDesc->Option == 0)
1797 {
1798 ExFreePool(*ResourceList);
1799 return STATUS_CONFLICTING_ADDRESSES;
1800 }
1801 }
1802 break;
1803
1804 case CmResourceTypePort:
1805 if (!IopFindPortResource(ReqDesc, ResDesc))
1806 {
1807 DPRINT1("Failed to find an available port resource (0x%x to 0x%x length: 0x%x)\n",
1808 ReqDesc->u.Port.MinimumAddress.QuadPart, ReqDesc->u.Port.MaximumAddress.QuadPart,
1809 ReqDesc->u.Port.Length);
1810
1811 if (ReqDesc->Option == 0)
1812 {
1813 ExFreePool(*ResourceList);
1814 return STATUS_CONFLICTING_ADDRESSES;
1815 }
1816 }
1817 break;
1818
1819 case CmResourceTypeMemory:
1820 if (!IopFindMemoryResource(ReqDesc, ResDesc))
1821 {
1822 DPRINT1("Failed to find an available memory resource (0x%x to 0x%x length: 0x%x)\n",
1823 ReqDesc->u.Memory.MinimumAddress.QuadPart, ReqDesc->u.Memory.MaximumAddress.QuadPart,
1824 ReqDesc->u.Memory.Length);
1825
1826 if (ReqDesc->Option == 0)
1827 {
1828 ExFreePool(*ResourceList);
1829 return STATUS_CONFLICTING_ADDRESSES;
1830 }
1831 }
1832 break;
1833
1834 case CmResourceTypeBusNumber:
1835 if (!IopFindBusNumberResource(ReqDesc, ResDesc))
1836 {
1837 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
1838 ReqDesc->u.BusNumber.MinBusNumber, ReqDesc->u.BusNumber.MaxBusNumber,
1839 ReqDesc->u.BusNumber.Length);
1840
1841 if (ReqDesc->Option == 0)
1842 {
1843 ExFreePool(*ResourceList);
1844 return STATUS_CONFLICTING_ADDRESSES;
1845 }
1846 }
1847 break;
1848
1849 case CmResourceTypeDma:
1850 if (!IopFindDmaResource(ReqDesc, ResDesc))
1851 {
1852 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
1853 ReqDesc->u.Dma.MinimumChannel, ReqDesc->u.Dma.MaximumChannel);
1854
1855 if (ReqDesc->Option == 0)
1856 {
1857 ExFreePool(*ResourceList);
1858 return STATUS_CONFLICTING_ADDRESSES;
1859 }
1860 }
1861 break;
1862
1863 default:
1864 DPRINT1("Unsupported resource type: %x\n", ReqDesc->Type);
1865 break;
1866 }
1867
1868 (*ResourceList)->List[0].PartialResourceList.Count++;
1869 ResDesc++;
1870 }
1871 }
1872
1873 return STATUS_SUCCESS;
1874 }
1875
1876 NTSTATUS
1877 IopAssignDeviceResources(
1878 IN PDEVICE_NODE DeviceNode,
1879 OUT ULONG *pRequiredSize)
1880 {
1881 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1882 ULONG Size;
1883 ULONG i;
1884 ULONG j;
1885 NTSTATUS Status;
1886
1887 if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
1888 {
1889 /* No resource needed for this device */
1890 DeviceNode->ResourceList = NULL;
1891 *pRequiredSize = 0;
1892 return STATUS_SUCCESS;
1893 }
1894
1895 /* Fill DeviceNode->ResourceList
1896 * FIXME: the PnP arbiter should go there!
1897 * Actually, use the BootResources if provided, else the resource requirements
1898 */
1899
1900 if (DeviceNode->BootResources)
1901 {
1902 /* Browse the boot resources to know if we have some custom structures */
1903 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1904 for (i = 0; i < DeviceNode->BootResources->Count; i++)
1905 {
1906 pPartialResourceList = &DeviceNode->BootResources->List[i].PartialResourceList;
1907 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors) +
1908 pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1909 for (j = 0; j < pPartialResourceList->Count; j++)
1910 {
1911 if (pPartialResourceList->PartialDescriptors[j].Type == CmResourceTypeDeviceSpecific)
1912 Size += pPartialResourceList->PartialDescriptors[j].u.DeviceSpecificData.DataSize;
1913 }
1914 }
1915
1916 DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
1917 if (!DeviceNode->ResourceList)
1918 {
1919 Status = STATUS_NO_MEMORY;
1920 goto ByeBye;
1921 }
1922 RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, Size);
1923
1924 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1925 if (NT_SUCCESS(Status) || !DeviceNode->ResourceRequirements)
1926 {
1927 if (!NT_SUCCESS(Status) && !DeviceNode->ResourceRequirements)
1928 {
1929 DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
1930 }
1931
1932 *pRequiredSize = Size;
1933 return STATUS_SUCCESS;
1934 }
1935 else
1936 {
1937 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
1938 ExFreePool(DeviceNode->ResourceList);
1939 }
1940 }
1941
1942 Status = IopCreateResourceListFromRequirements(DeviceNode->ResourceRequirements,
1943 &DeviceNode->ResourceList);
1944 if (!NT_SUCCESS(Status))
1945 goto ByeBye;
1946
1947 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1948 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
1949 {
1950 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
1951 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors) +
1952 pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1953 }
1954
1955 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1956 if (!NT_SUCCESS(Status))
1957 goto ByeBye;
1958
1959 *pRequiredSize = Size;
1960 return STATUS_SUCCESS;
1961
1962 ByeBye:
1963 if (DeviceNode->ResourceList)
1964 {
1965 ExFreePool(DeviceNode->ResourceList);
1966 DeviceNode->ResourceList = NULL;
1967 }
1968 *pRequiredSize = 0;
1969 return Status;
1970 }
1971
1972
1973 NTSTATUS
1974 IopTranslateDeviceResources(
1975 IN PDEVICE_NODE DeviceNode,
1976 IN ULONG RequiredSize)
1977 {
1978 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1979 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
1980 ULONG i, j;
1981 NTSTATUS Status;
1982
1983 if (!DeviceNode->ResourceList)
1984 {
1985 DeviceNode->ResourceListTranslated = NULL;
1986 return STATUS_SUCCESS;
1987 }
1988
1989 /* That's easy to translate a resource list. Just copy the
1990 * untranslated one and change few fields in the copy
1991 */
1992 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, RequiredSize);
1993 if (!DeviceNode->ResourceListTranslated)
1994 {
1995 Status =STATUS_NO_MEMORY;
1996 goto cleanup;
1997 }
1998 RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, RequiredSize);
1999
2000 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
2001 {
2002 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
2003 for (j = 0; j < pPartialResourceList->Count; j++)
2004 {
2005 DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
2006 DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
2007 switch (DescriptorRaw->Type)
2008 {
2009 case CmResourceTypePort:
2010 {
2011 ULONG AddressSpace = 1; /* IO space */
2012 if (!HalTranslateBusAddress(
2013 DeviceNode->ResourceList->List[i].InterfaceType,
2014 DeviceNode->ResourceList->List[i].BusNumber,
2015 DescriptorRaw->u.Port.Start,
2016 &AddressSpace,
2017 &DescriptorTranslated->u.Port.Start))
2018 {
2019 Status = STATUS_UNSUCCESSFUL;
2020 goto cleanup;
2021 }
2022 break;
2023 }
2024 case CmResourceTypeInterrupt:
2025 {
2026 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
2027 DeviceNode->ResourceList->List[i].InterfaceType,
2028 DeviceNode->ResourceList->List[i].BusNumber,
2029 DescriptorRaw->u.Interrupt.Level,
2030 DescriptorRaw->u.Interrupt.Vector,
2031 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
2032 &DescriptorRaw->u.Interrupt.Affinity);
2033 break;
2034 }
2035 case CmResourceTypeMemory:
2036 {
2037 ULONG AddressSpace = 0; /* Memory space */
2038 if (!HalTranslateBusAddress(
2039 DeviceNode->ResourceList->List[i].InterfaceType,
2040 DeviceNode->ResourceList->List[i].BusNumber,
2041 DescriptorRaw->u.Memory.Start,
2042 &AddressSpace,
2043 &DescriptorTranslated->u.Memory.Start))
2044 {
2045 Status = STATUS_UNSUCCESSFUL;
2046 goto cleanup;
2047 }
2048 }
2049
2050 case CmResourceTypeDma:
2051 case CmResourceTypeBusNumber:
2052 case CmResourceTypeDeviceSpecific:
2053 /* Nothing to do */
2054 break;
2055 default:
2056 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
2057 Status = STATUS_NOT_IMPLEMENTED;
2058 goto cleanup;
2059 }
2060 }
2061 }
2062 return STATUS_SUCCESS;
2063
2064 cleanup:
2065 /* Yes! Also delete ResourceList because ResourceList and
2066 * ResourceListTranslated should be a pair! */
2067 ExFreePool(DeviceNode->ResourceList);
2068 DeviceNode->ResourceList = NULL;
2069 if (DeviceNode->ResourceListTranslated)
2070 {
2071 ExFreePool(DeviceNode->ResourceListTranslated);
2072 DeviceNode->ResourceList = NULL;
2073 }
2074 return Status;
2075 }
2076
2077
2078 /*
2079 * IopGetParentIdPrefix
2080 *
2081 * Retrieve (or create) a string which identifies a device.
2082 *
2083 * Parameters
2084 * DeviceNode
2085 * Pointer to device node.
2086 * ParentIdPrefix
2087 * Pointer to the string where is returned the parent node identifier
2088 *
2089 * Remarks
2090 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
2091 * valid and its Buffer field is NULL-terminated. The caller needs to
2092 * to free the string with RtlFreeUnicodeString when it is no longer
2093 * needed.
2094 */
2095
2096 NTSTATUS
2097 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
2098 PUNICODE_STRING ParentIdPrefix)
2099 {
2100 ULONG KeyNameBufferLength;
2101 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
2102 UNICODE_STRING KeyName;
2103 UNICODE_STRING KeyValue;
2104 UNICODE_STRING ValueName;
2105 HANDLE hKey = NULL;
2106 ULONG crc32;
2107 NTSTATUS Status;
2108
2109 /* HACK: As long as some devices have a NULL device
2110 * instance path, the following test is required :(
2111 */
2112 if (DeviceNode->Parent->InstancePath.Length == 0)
2113 {
2114 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
2115 &DeviceNode->InstancePath);
2116 return STATUS_UNSUCCESSFUL;
2117 }
2118
2119 /* 1. Try to retrieve ParentIdPrefix from registry */
2120 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
2121 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
2122 if (!ParentIdPrefixInformation)
2123 {
2124 Status = STATUS_INSUFFICIENT_RESOURCES;
2125 goto cleanup;
2126 }
2127
2128
2129 KeyName.Buffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
2130 if (!KeyName.Buffer)
2131 {
2132 Status = STATUS_INSUFFICIENT_RESOURCES;
2133 goto cleanup;
2134 }
2135 KeyName.Length = 0;
2136 KeyName.MaximumLength = (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length;
2137
2138 RtlAppendUnicodeToString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2139 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
2140
2141 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
2142 if (!NT_SUCCESS(Status))
2143 goto cleanup;
2144 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
2145 Status = ZwQueryValueKey(
2146 hKey, &ValueName,
2147 KeyValuePartialInformation, ParentIdPrefixInformation,
2148 KeyNameBufferLength, &KeyNameBufferLength);
2149 if (NT_SUCCESS(Status))
2150 {
2151 if (ParentIdPrefixInformation->Type != REG_SZ)
2152 Status = STATUS_UNSUCCESSFUL;
2153 else
2154 {
2155 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
2156 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
2157 }
2158 goto cleanup;
2159 }
2160 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2161 {
2162 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
2163 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
2164 goto cleanup;
2165 }
2166
2167 /* 2. Create the ParentIdPrefix value */
2168 crc32 = RtlComputeCrc32(0,
2169 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
2170 DeviceNode->Parent->InstancePath.Length);
2171
2172 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
2173 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
2174
2175 /* 3. Try to write the ParentIdPrefix to registry */
2176 Status = ZwSetValueKey(hKey,
2177 &ValueName,
2178 0,
2179 REG_SZ,
2180 (PVOID)KeyValue.Buffer,
2181 (wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
2182
2183 cleanup:
2184 if (NT_SUCCESS(Status))
2185 {
2186 /* Duplicate the string to return it */
2187 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
2188 }
2189 ExFreePool(ParentIdPrefixInformation);
2190 RtlFreeUnicodeString(&KeyName);
2191 if (hKey != NULL)
2192 ZwClose(hKey);
2193 return Status;
2194 }
2195
2196
2197 /*
2198 * IopActionInterrogateDeviceStack
2199 *
2200 * Retrieve information for all (direct) child nodes of a parent node.
2201 *
2202 * Parameters
2203 * DeviceNode
2204 * Pointer to device node.
2205 * Context
2206 * Pointer to parent node to retrieve child node information for.
2207 *
2208 * Remarks
2209 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2210 * when we reach a device node which is not a direct child of the device
2211 * node for which we retrieve information of child nodes for. Any errors
2212 * that occur is logged instead so that all child services have a chance
2213 * of being interrogated.
2214 */
2215
2216 NTSTATUS
2217 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
2218 PVOID Context)
2219 {
2220 IO_STATUS_BLOCK IoStatusBlock;
2221 PDEVICE_NODE ParentDeviceNode;
2222 WCHAR InstancePath[MAX_PATH];
2223 IO_STACK_LOCATION Stack;
2224 NTSTATUS Status;
2225 PWSTR Ptr;
2226 USHORT Length;
2227 USHORT TotalLength;
2228 ULONG RequiredLength;
2229 LCID LocaleId;
2230 HANDLE InstanceKey = NULL;
2231 UNICODE_STRING ValueName;
2232 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
2233 DEVICE_CAPABILITIES DeviceCapabilities;
2234
2235 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2236 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2237
2238 ParentDeviceNode = (PDEVICE_NODE)Context;
2239
2240 /*
2241 * We are called for the parent too, but we don't need to do special
2242 * handling for this node
2243 */
2244
2245 if (DeviceNode == ParentDeviceNode)
2246 {
2247 DPRINT("Success\n");
2248 return STATUS_SUCCESS;
2249 }
2250
2251 /*
2252 * Make sure this device node is a direct child of the parent device node
2253 * that is given as an argument
2254 */
2255
2256 if (DeviceNode->Parent != ParentDeviceNode)
2257 {
2258 /* Stop the traversal immediately and indicate successful operation */
2259 DPRINT("Stop\n");
2260 return STATUS_UNSUCCESSFUL;
2261 }
2262
2263 /* Get Locale ID */
2264 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2265 if (!NT_SUCCESS(Status))
2266 {
2267 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2268 return Status;
2269 }
2270
2271 /*
2272 * FIXME: For critical errors, cleanup and disable device, but always
2273 * return STATUS_SUCCESS.
2274 */
2275
2276 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2277
2278 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
2279 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2280 &IoStatusBlock,
2281 IRP_MN_QUERY_ID,
2282 &Stack);
2283 if (NT_SUCCESS(Status))
2284 {
2285 /* Copy the device id string */
2286 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
2287
2288 /*
2289 * FIXME: Check for valid characters, if there is invalid characters
2290 * then bugcheck.
2291 */
2292 }
2293 else
2294 {
2295 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2296 }
2297
2298 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
2299
2300 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
2301 if (!NT_SUCCESS(Status))
2302 {
2303 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
2304 }
2305
2306 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
2307
2308 if (!DeviceCapabilities.UniqueID)
2309 {
2310 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2311 DPRINT("Instance ID is not unique\n");
2312 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
2313 if (!NT_SUCCESS(Status))
2314 {
2315 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
2316 }
2317 }
2318
2319 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2320
2321 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
2322 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2323 &IoStatusBlock,
2324 IRP_MN_QUERY_ID,
2325 &Stack);
2326 if (NT_SUCCESS(Status))
2327 {
2328 /* Append the instance id string */
2329 wcscat(InstancePath, L"\\");
2330 if (ParentIdPrefix.Length > 0)
2331 {
2332 /* Add information from parent bus device to InstancePath */
2333 wcscat(InstancePath, ParentIdPrefix.Buffer);
2334 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
2335 wcscat(InstancePath, L"&");
2336 }
2337 if (IoStatusBlock.Information)
2338 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
2339
2340 /*
2341 * FIXME: Check for valid characters, if there is invalid characters
2342 * then bugcheck
2343 */
2344 }
2345 else
2346 {
2347 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2348 }
2349 RtlFreeUnicodeString(&ParentIdPrefix);
2350
2351 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
2352 {
2353 DPRINT("No resources\n");
2354 /* FIXME: Cleanup and disable device */
2355 }
2356
2357 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2358
2359 /*
2360 * Create registry key for the instance id, if it doesn't exist yet
2361 */
2362 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
2363 if (!NT_SUCCESS(Status))
2364 {
2365 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2366 }
2367
2368 {
2369 /* Set 'Capabilities' value */
2370 RtlInitUnicodeString(&ValueName, L"Capabilities");
2371 Status = ZwSetValueKey(InstanceKey,
2372 &ValueName,
2373 0,
2374 REG_DWORD,
2375 (PVOID)&DeviceNode->CapabilityFlags,
2376 sizeof(ULONG));
2377
2378 /* Set 'UINumber' value */
2379 if (DeviceCapabilities.UINumber != MAXULONG)
2380 {
2381 RtlInitUnicodeString(&ValueName, L"UINumber");
2382 Status = ZwSetValueKey(InstanceKey,
2383 &ValueName,
2384 0,
2385 REG_DWORD,
2386 &DeviceCapabilities.UINumber,
2387 sizeof(ULONG));
2388 }
2389 }
2390
2391 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2392
2393 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
2394 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2395 &IoStatusBlock,
2396 IRP_MN_QUERY_ID,
2397 &Stack);
2398 if (NT_SUCCESS(Status))
2399 {
2400 /*
2401 * FIXME: Check for valid characters, if there is invalid characters
2402 * then bugcheck.
2403 */
2404 TotalLength = 0;
2405 Ptr = (PWSTR)IoStatusBlock.Information;
2406 DPRINT("Hardware IDs:\n");
2407 while (*Ptr)
2408 {
2409 DPRINT(" %S\n", Ptr);
2410 Length = wcslen(Ptr) + 1;
2411
2412 Ptr += Length;
2413 TotalLength += Length;
2414 }
2415 DPRINT("TotalLength: %hu\n", TotalLength);
2416 DPRINT("\n");
2417
2418 RtlInitUnicodeString(&ValueName, L"HardwareID");
2419 Status = ZwSetValueKey(InstanceKey,
2420 &ValueName,
2421 0,
2422 REG_MULTI_SZ,
2423 (PVOID)IoStatusBlock.Information,
2424 (TotalLength + 1) * sizeof(WCHAR));
2425 if (!NT_SUCCESS(Status))
2426 {
2427 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2428 }
2429 }
2430 else
2431 {
2432 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2433 }
2434
2435 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2436
2437 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
2438 Status = IopInitiatePnpIrp(
2439 DeviceNode->PhysicalDeviceObject,
2440 &IoStatusBlock,
2441 IRP_MN_QUERY_ID,
2442 &Stack);
2443 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2444 {
2445 /*
2446 * FIXME: Check for valid characters, if there is invalid characters
2447 * then bugcheck.
2448 */
2449 TotalLength = 0;
2450 Ptr = (PWSTR)IoStatusBlock.Information;
2451 DPRINT("Compatible IDs:\n");
2452 while (*Ptr)
2453 {
2454 DPRINT(" %S\n", Ptr);
2455 Length = wcslen(Ptr) + 1;
2456
2457 Ptr += Length;
2458 TotalLength += Length;
2459 }
2460 DPRINT("TotalLength: %hu\n", TotalLength);
2461 DPRINT("\n");
2462
2463 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
2464 Status = ZwSetValueKey(InstanceKey,
2465 &ValueName,
2466 0,
2467 REG_MULTI_SZ,
2468 (PVOID)IoStatusBlock.Information,
2469 (TotalLength + 1) * sizeof(WCHAR));
2470 if (!NT_SUCCESS(Status))
2471 {
2472 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
2473 }
2474 }
2475 else
2476 {
2477 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2478 }
2479
2480 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2481
2482 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2483 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2484 Status = IopInitiatePnpIrp(
2485 DeviceNode->PhysicalDeviceObject,
2486 &IoStatusBlock,
2487 IRP_MN_QUERY_DEVICE_TEXT,
2488 &Stack);
2489 /* This key is mandatory, so even if the Irp fails, we still write it */
2490 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2491 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2492 {
2493 if (NT_SUCCESS(Status) &&
2494 IoStatusBlock.Information &&
2495 (*(PWSTR)IoStatusBlock.Information != 0))
2496 {
2497 /* This key is overriden when a driver is installed. Don't write the
2498 * new description if another one already exists */
2499 Status = ZwSetValueKey(InstanceKey,
2500 &ValueName,
2501 0,
2502 REG_SZ,
2503 (PVOID)IoStatusBlock.Information,
2504 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2505 }
2506 else
2507 {
2508 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2509 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2510
2511 Status = ZwSetValueKey(InstanceKey,
2512 &ValueName,
2513 0,
2514 REG_SZ,
2515 DeviceDesc.Buffer,
2516 DeviceDesc.MaximumLength);
2517
2518 if (!NT_SUCCESS(Status))
2519 {
2520 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2521 }
2522
2523 }
2524 }
2525
2526 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2527
2528 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2529 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2530 Status = IopInitiatePnpIrp(
2531 DeviceNode->PhysicalDeviceObject,
2532 &IoStatusBlock,
2533 IRP_MN_QUERY_DEVICE_TEXT,
2534 &Stack);
2535 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2536 {
2537 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
2538 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2539 Status = ZwSetValueKey(InstanceKey,
2540 &ValueName,
2541 0,
2542 REG_SZ,
2543 (PVOID)IoStatusBlock.Information,
2544 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2545 if (!NT_SUCCESS(Status))
2546 {
2547 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2548 }
2549 }
2550 else
2551 {
2552 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2553 }
2554
2555 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2556
2557 Status = IopInitiatePnpIrp(
2558 DeviceNode->PhysicalDeviceObject,
2559 &IoStatusBlock,
2560 IRP_MN_QUERY_BUS_INFORMATION,
2561 NULL);
2562 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2563 {
2564 PPNP_BUS_INFORMATION BusInformation =
2565 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2566
2567 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2568 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2569 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2570 ExFreePool(BusInformation);
2571 }
2572 else
2573 {
2574 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2575
2576 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2577 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2578 DeviceNode->ChildBusTypeIndex = -1;
2579 }
2580
2581 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2582
2583 Status = IopInitiatePnpIrp(
2584 DeviceNode->PhysicalDeviceObject,
2585 &IoStatusBlock,
2586 IRP_MN_QUERY_RESOURCES,
2587 NULL);
2588 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2589 {
2590 DeviceNode->BootResources =
2591 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2592 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2593 }
2594 else
2595 {
2596 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2597 DeviceNode->BootResources = NULL;
2598 }
2599
2600 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2601
2602 Status = IopInitiatePnpIrp(
2603 DeviceNode->PhysicalDeviceObject,
2604 &IoStatusBlock,
2605 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2606 NULL);
2607 if (NT_SUCCESS(Status))
2608 {
2609 DeviceNode->ResourceRequirements =
2610 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2611 if (IoStatusBlock.Information)
2612 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_REPORTED);
2613 else
2614 IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED);
2615 }
2616 else
2617 {
2618 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2619 DeviceNode->ResourceRequirements = NULL;
2620 }
2621
2622
2623 if (InstanceKey != NULL)
2624 {
2625 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2626 }
2627
2628 ZwClose(InstanceKey);
2629
2630 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2631
2632 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2633 {
2634 /* Report the device to the user-mode pnp manager */
2635 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2636 &DeviceNode->InstancePath);
2637 }
2638
2639 return STATUS_SUCCESS;
2640 }
2641
2642
2643 NTSTATUS
2644 IopEnumerateDevice(
2645 IN PDEVICE_OBJECT DeviceObject)
2646 {
2647 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2648 DEVICETREE_TRAVERSE_CONTEXT Context;
2649 PDEVICE_RELATIONS DeviceRelations;
2650 PDEVICE_OBJECT ChildDeviceObject;
2651 IO_STATUS_BLOCK IoStatusBlock;
2652 PDEVICE_NODE ChildDeviceNode;
2653 IO_STACK_LOCATION Stack;
2654 NTSTATUS Status;
2655 ULONG i;
2656
2657 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2658
2659 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2660
2661 /* Report the device to the user-mode pnp manager */
2662 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2663 &DeviceNode->InstancePath);
2664
2665 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2666
2667 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2668
2669 Status = IopInitiatePnpIrp(
2670 DeviceObject,
2671 &IoStatusBlock,
2672 IRP_MN_QUERY_DEVICE_RELATIONS,
2673 &Stack);
2674 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2675 {
2676 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2677 return Status;
2678 }
2679
2680 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2681
2682 if (!DeviceRelations)
2683 {
2684 DPRINT("No PDOs\n");
2685 return STATUS_UNSUCCESSFUL;
2686 }
2687
2688 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2689
2690 /*
2691 * Create device nodes for all discovered devices
2692 */
2693 for (i = 0; i < DeviceRelations->Count; i++)
2694 {
2695 ChildDeviceObject = DeviceRelations->Objects[i];
2696 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2697
2698 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2699 if (!ChildDeviceNode)
2700 {
2701 /* One doesn't exist, create it */
2702 Status = IopCreateDeviceNode(
2703 DeviceNode,
2704 ChildDeviceObject,
2705 NULL,
2706 &ChildDeviceNode);
2707 if (NT_SUCCESS(Status))
2708 {
2709 /* Mark the node as enumerated */
2710 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2711
2712 /* Mark the DO as bus enumerated */
2713 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2714 }
2715 else
2716 {
2717 /* Ignore this DO */
2718 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2719 ObDereferenceObject(ChildDeviceNode);
2720 }
2721 }
2722 else
2723 {
2724 /* Mark it as enumerated */
2725 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2726 ObDereferenceObject(ChildDeviceObject);
2727 }
2728 }
2729 ExFreePool(DeviceRelations);
2730
2731 /*
2732 * Retrieve information about all discovered children from the bus driver
2733 */
2734 IopInitDeviceTreeTraverseContext(
2735 &Context,
2736 DeviceNode,
2737 IopActionInterrogateDeviceStack,
2738 DeviceNode);
2739
2740 Status = IopTraverseDeviceTree(&Context);
2741 if (!NT_SUCCESS(Status))
2742 {
2743 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2744 return Status;
2745 }
2746
2747 /*
2748 * Retrieve configuration from the registry for discovered children
2749 */
2750 IopInitDeviceTreeTraverseContext(
2751 &Context,
2752 DeviceNode,
2753 IopActionConfigureChildServices,
2754 DeviceNode);
2755
2756 Status = IopTraverseDeviceTree(&Context);
2757 if (!NT_SUCCESS(Status))
2758 {
2759 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2760 return Status;
2761 }
2762
2763 /*
2764 * Initialize services for discovered children.
2765 */
2766 Status = IopInitializePnpServices(DeviceNode);
2767 if (!NT_SUCCESS(Status))
2768 {
2769 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2770 return Status;
2771 }
2772
2773 DPRINT("IopEnumerateDevice() finished\n");
2774 return STATUS_SUCCESS;
2775 }
2776
2777
2778 /*
2779 * IopActionConfigureChildServices
2780 *
2781 * Retrieve configuration for all (direct) child nodes of a parent node.
2782 *
2783 * Parameters
2784 * DeviceNode
2785 * Pointer to device node.
2786 * Context
2787 * Pointer to parent node to retrieve child node configuration for.
2788 *
2789 * Remarks
2790 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2791 * when we reach a device node which is not a direct child of the device
2792 * node for which we configure child services for. Any errors that occur is
2793 * logged instead so that all child services have a chance of beeing
2794 * configured.
2795 */
2796
2797 NTSTATUS
2798 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2799 PVOID Context)
2800 {
2801 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2802 PDEVICE_NODE ParentDeviceNode;
2803 PUNICODE_STRING Service;
2804 UNICODE_STRING ClassGUID;
2805 NTSTATUS Status;
2806 DEVICE_CAPABILITIES DeviceCaps;
2807
2808 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2809
2810 ParentDeviceNode = (PDEVICE_NODE)Context;
2811
2812 /*
2813 * We are called for the parent too, but we don't need to do special
2814 * handling for this node
2815 */
2816 if (DeviceNode == ParentDeviceNode)
2817 {
2818 DPRINT("Success\n");
2819 return STATUS_SUCCESS;
2820 }
2821
2822 /*
2823 * Make sure this device node is a direct child of the parent device node
2824 * that is given as an argument
2825 */
2826 if (DeviceNode->Parent != ParentDeviceNode)
2827 {
2828 /* Stop the traversal immediately and indicate successful operation */
2829 DPRINT("Stop\n");
2830 return STATUS_UNSUCCESSFUL;
2831 }
2832
2833 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2834 {
2835 WCHAR RegKeyBuffer[MAX_PATH];
2836 UNICODE_STRING RegKey;
2837
2838 RegKey.Length = 0;
2839 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2840 RegKey.Buffer = RegKeyBuffer;
2841
2842 /*
2843 * Retrieve configuration from Enum key
2844 */
2845
2846 Service = &DeviceNode->ServiceName;
2847
2848 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2849 RtlInitUnicodeString(Service, NULL);
2850 RtlInitUnicodeString(&ClassGUID, NULL);
2851
2852 QueryTable[0].Name = L"Service";
2853 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2854 QueryTable[0].EntryContext = Service;
2855
2856 QueryTable[1].Name = L"ClassGUID";
2857 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2858 QueryTable[1].EntryContext = &ClassGUID;
2859 QueryTable[1].DefaultType = REG_SZ;
2860 QueryTable[1].DefaultData = L"";
2861 QueryTable[1].DefaultLength = 0;
2862
2863 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2864 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2865
2866 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2867 RegKey.Buffer, QueryTable, NULL, NULL);
2868
2869 if (!NT_SUCCESS(Status))
2870 {
2871 /* FIXME: Log the error */
2872 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2873 &DeviceNode->InstancePath, Status);
2874 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2875 return STATUS_SUCCESS;
2876 }
2877
2878 if (Service->Buffer == NULL)
2879 {
2880 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2881 DeviceCaps.RawDeviceOK)
2882 {
2883 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2884
2885 DeviceNode->ServiceName.Length = 0;
2886 DeviceNode->ServiceName.MaximumLength = 0;
2887 DeviceNode->ServiceName.Buffer = NULL;
2888 }
2889 else if (ClassGUID.Length != 0)
2890 {
2891 /* Device has a ClassGUID value, but no Service value.
2892 * Suppose it is using the NULL driver, so state the
2893 * device is started */
2894 DPRINT1("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2895 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2896 }
2897 else
2898 {
2899 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2900 }
2901 return STATUS_SUCCESS;
2902 }
2903
2904 DPRINT("Got Service %S\n", Service->Buffer);
2905 }
2906
2907 return STATUS_SUCCESS;
2908 }
2909
2910 /*
2911 * IopActionInitChildServices
2912 *
2913 * Initialize the service for all (direct) child nodes of a parent node
2914 *
2915 * Parameters
2916 * DeviceNode
2917 * Pointer to device node.
2918 * Context
2919 * Pointer to parent node to initialize child node services for.
2920 *
2921 * Remarks
2922 * If the driver image for a service is not loaded and initialized
2923 * it is done here too. We only return a status code indicating an
2924 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2925 * not a direct child of the device node for which we initialize
2926 * child services for. Any errors that occur is logged instead so
2927 * that all child services have a chance of being initialized.
2928 */
2929
2930 NTSTATUS
2931 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2932 PVOID Context)
2933 {
2934 PDEVICE_NODE ParentDeviceNode;
2935 NTSTATUS Status;
2936 BOOLEAN BootDrivers = !PnpSystemInit;
2937
2938 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2939
2940 ParentDeviceNode = (PDEVICE_NODE)Context;
2941
2942 /*
2943 * We are called for the parent too, but we don't need to do special
2944 * handling for this node
2945 */
2946 if (DeviceNode == ParentDeviceNode)
2947 {
2948 DPRINT("Success\n");
2949 return STATUS_SUCCESS;
2950 }
2951
2952 /*
2953 * Make sure this device node is a direct child of the parent device node
2954 * that is given as an argument
2955 */
2956 #if 0
2957 if (DeviceNode->Parent != ParentDeviceNode)
2958 {
2959 /*
2960 * Stop the traversal immediately and indicate unsuccessful operation
2961 */
2962 DPRINT("Stop\n");
2963 return STATUS_UNSUCCESSFUL;
2964 }
2965 #endif
2966 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2967 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2968 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2969 return STATUS_SUCCESS;
2970
2971 if (DeviceNode->ServiceName.Buffer == NULL)
2972 {
2973 /* We don't need to worry about loading the driver because we're
2974 * being driven in raw mode so our parent must be loaded to get here */
2975 Status = IopStartDevice(DeviceNode);
2976 if (!NT_SUCCESS(Status))
2977 {
2978 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2979 &DeviceNode->InstancePath, Status);
2980 }
2981 }
2982 else
2983 {
2984 PLDR_DATA_TABLE_ENTRY ModuleObject;
2985 PDRIVER_OBJECT DriverObject;
2986
2987 /* Get existing DriverObject pointer (in case the driver has
2988 already been loaded and initialized) */
2989 Status = IopGetDriverObject(
2990 &DriverObject,
2991 &DeviceNode->ServiceName,
2992 FALSE);
2993
2994 if (!NT_SUCCESS(Status))
2995 {
2996 /* Driver is not initialized, try to load it */
2997 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2998
2999 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
3000 {
3001 /* STATUS_IMAGE_ALREADY_LOADED means this driver
3002 was loaded by the bootloader */
3003 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
3004 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
3005 {
3006 /* Initialize the driver */
3007 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
3008 &DeviceNode->ServiceName, FALSE, &DriverObject);
3009 }
3010 else
3011 {
3012 Status = STATUS_SUCCESS;
3013 }
3014 }
3015 else
3016 {
3017 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
3018 &DeviceNode->ServiceName, Status);
3019 }
3020 }
3021
3022 /* Driver is loaded and initialized at this point */
3023 if (NT_SUCCESS(Status))
3024 {
3025 /* Initialize the device, including all filters */
3026 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
3027 }
3028 else
3029 {
3030 /*
3031 * Don't disable when trying to load only boot drivers
3032 */
3033 if (!BootDrivers)
3034 {
3035 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
3036 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
3037 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
3038 DPRINT1("Initialization of service %S failed (Status %x)\n",
3039 DeviceNode->ServiceName.Buffer, Status);
3040 }
3041 }
3042 }
3043
3044 return STATUS_SUCCESS;
3045 }
3046
3047 /*
3048 * IopInitializePnpServices
3049 *
3050 * Initialize services for discovered children
3051 *
3052 * Parameters
3053 * DeviceNode
3054 * Top device node to start initializing services.
3055 *
3056 * Return Value
3057 * Status
3058 */
3059 NTSTATUS
3060 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
3061 {
3062 DEVICETREE_TRAVERSE_CONTEXT Context;
3063
3064 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
3065
3066 IopInitDeviceTreeTraverseContext(
3067 &Context,
3068 DeviceNode,
3069 IopActionInitChildServices,
3070 DeviceNode);
3071
3072 return IopTraverseDeviceTree(&Context);
3073 }
3074
3075 static NTSTATUS INIT_FUNCTION
3076 IopEnumerateDetectedDevices(
3077 IN HANDLE hBaseKey,
3078 IN PUNICODE_STRING RelativePath OPTIONAL,
3079 IN HANDLE hRootKey,
3080 IN BOOLEAN EnumerateSubKeys,
3081 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
3082 IN ULONG ParentBootResourcesLength)
3083 {
3084 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3085 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3086 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
3087 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
3088 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
3089 OBJECT_ATTRIBUTES ObjectAttributes;
3090 HANDLE hDevicesKey = NULL;
3091 HANDLE hDeviceKey = NULL;
3092 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
3093 UNICODE_STRING Level2NameU;
3094 WCHAR Level2Name[5];
3095 ULONG IndexDevice = 0;
3096 ULONG IndexSubKey;
3097 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3098 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3099 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3100 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3101 UNICODE_STRING DeviceName, ValueName;
3102 ULONG RequiredSize;
3103 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
3104 ULONG BootResourcesLength;
3105 NTSTATUS Status;
3106
3107 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
3108 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
3109 static ULONG DeviceIndexPci = 0;
3110 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
3111 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
3112 static ULONG DeviceIndexSerial = 0;
3113 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
3114 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
3115 static ULONG DeviceIndexKeyboard = 0;
3116 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
3117 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
3118 static ULONG DeviceIndexMouse = 0;
3119 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
3120 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
3121 static ULONG DeviceIndexParallel = 0;
3122 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
3123 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
3124 static ULONG DeviceIndexFloppy = 0;
3125 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
3126 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
3127 static ULONG DeviceIndexIsa = 0;
3128 UNICODE_STRING HardwareIdKey;
3129 PUNICODE_STRING pHardwareId;
3130 ULONG DeviceIndex = 0;
3131 PUCHAR CmResourceList;
3132 ULONG ListCount;
3133
3134 if (RelativePath)
3135 {
3136 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
3137 if (!NT_SUCCESS(Status))
3138 {
3139 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3140 goto cleanup;
3141 }
3142 }
3143 else
3144 hDevicesKey = hBaseKey;
3145
3146 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3147 if (!pDeviceInformation)
3148 {
3149 DPRINT("ExAllocatePool() failed\n");
3150 Status = STATUS_NO_MEMORY;
3151 goto cleanup;
3152 }
3153
3154 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3155 if (!pValueInformation)
3156 {
3157 DPRINT("ExAllocatePool() failed\n");
3158 Status = STATUS_NO_MEMORY;
3159 goto cleanup;
3160 }
3161
3162 while (TRUE)
3163 {
3164 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3165 if (Status == STATUS_NO_MORE_ENTRIES)
3166 break;
3167 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3168 {
3169 ExFreePool(pDeviceInformation);
3170 DeviceInfoLength = RequiredSize;
3171 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3172 if (!pDeviceInformation)
3173 {
3174 DPRINT("ExAllocatePool() failed\n");
3175 Status = STATUS_NO_MEMORY;
3176 goto cleanup;
3177 }
3178 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3179 }
3180 if (!NT_SUCCESS(Status))
3181 {
3182 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3183 goto cleanup;
3184 }
3185 IndexDevice++;
3186
3187 /* Open device key */
3188 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3189 DeviceName.Buffer = pDeviceInformation->Name;
3190
3191 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3192 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3193 if (!NT_SUCCESS(Status))
3194 {
3195 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3196 goto cleanup;
3197 }
3198
3199 /* Read boot resources, and add then to parent ones */
3200 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3201 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3202 {
3203 ExFreePool(pValueInformation);
3204 ValueInfoLength = RequiredSize;
3205 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3206 if (!pValueInformation)
3207 {
3208 DPRINT("ExAllocatePool() failed\n");
3209 ZwDeleteKey(hLevel2Key);
3210 Status = STATUS_NO_MEMORY;
3211 goto cleanup;
3212 }
3213 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3214 }
3215 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3216 {
3217 BootResources = ParentBootResources;
3218 BootResourcesLength = ParentBootResourcesLength;
3219 }
3220 else if (!NT_SUCCESS(Status))
3221 {
3222 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3223 goto nextdevice;
3224 }
3225 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3226 {
3227 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3228 goto nextdevice;
3229 }
3230 else
3231 {
3232 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3233
3234 /* Concatenate current resources and parent ones */
3235 if (ParentBootResourcesLength == 0)
3236 BootResourcesLength = pValueInformation->DataLength;
3237 else
3238 BootResourcesLength = ParentBootResourcesLength
3239 + pValueInformation->DataLength
3240 - Header;
3241 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3242 if (!BootResources)
3243 {
3244 DPRINT("ExAllocatePool() failed\n");
3245 goto nextdevice;
3246 }
3247 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3248 {
3249 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3250 }
3251 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3252 {
3253 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3254 RtlCopyMemory(
3255 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3256 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3257 ParentBootResourcesLength - Header);
3258 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3259 }
3260 else
3261 {
3262 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3263 RtlCopyMemory(
3264 (PVOID)((ULONG_PTR)BootResources + Header),
3265 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3266 ParentBootResourcesLength - Header);
3267 RtlCopyMemory(
3268 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3269 pValueInformation->Data + Header,
3270 pValueInformation->DataLength - Header);
3271 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3272 }
3273 }
3274
3275 if (EnumerateSubKeys)
3276 {
3277 IndexSubKey = 0;
3278 while (TRUE)
3279 {
3280 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3281 if (Status == STATUS_NO_MORE_ENTRIES)
3282 break;
3283 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3284 {
3285 ExFreePool(pDeviceInformation);
3286 DeviceInfoLength = RequiredSize;
3287 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3288 if (!pDeviceInformation)
3289 {
3290 DPRINT("ExAllocatePool() failed\n");
3291 Status = STATUS_NO_MEMORY;
3292 goto cleanup;
3293 }
3294 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3295 }
3296 if (!NT_SUCCESS(Status))
3297 {
3298 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3299 goto cleanup;
3300 }
3301 IndexSubKey++;
3302 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3303 DeviceName.Buffer = pDeviceInformation->Name;
3304
3305 Status = IopEnumerateDetectedDevices(
3306 hDeviceKey,
3307 &DeviceName,
3308 hRootKey,
3309 TRUE,
3310 BootResources,
3311 BootResourcesLength);
3312 if (!NT_SUCCESS(Status))
3313 goto cleanup;
3314 }
3315 }
3316
3317 /* Read identifier */
3318 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3319 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3320 {
3321 ExFreePool(pValueInformation);
3322 ValueInfoLength = RequiredSize;
3323 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3324 if (!pValueInformation)
3325 {
3326 DPRINT("ExAllocatePool() failed\n");
3327 Status = STATUS_NO_MEMORY;
3328 goto cleanup;
3329 }
3330 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3331 }
3332 if (!NT_SUCCESS(Status))
3333 {
3334 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
3335 {
3336 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3337 goto nextdevice;
3338 }
3339 ValueName.Length = ValueName.MaximumLength = 0;
3340 }
3341 else if (pValueInformation->Type != REG_SZ)
3342 {
3343 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3344 goto nextdevice;
3345 }
3346 else
3347 {
3348 /* Assign hardware id to this device */
3349 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3350 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3351 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3352 ValueName.Length -= sizeof(WCHAR);
3353 }
3354
3355 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3356 {
3357 pHardwareId = &HardwareIdSerial;
3358 DeviceIndex = DeviceIndexSerial++;
3359 }
3360 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3361 {
3362 pHardwareId = &HardwareIdKeyboard;
3363 DeviceIndex = DeviceIndexKeyboard++;
3364 }
3365 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3366 {
3367 pHardwareId = &HardwareIdMouse;
3368 DeviceIndex = DeviceIndexMouse++;
3369 }
3370 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3371 {
3372 pHardwareId = &HardwareIdParallel;
3373 DeviceIndex = DeviceIndexParallel++;
3374 }
3375 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3376 {
3377 pHardwareId = &HardwareIdFloppy;
3378 DeviceIndex = DeviceIndexFloppy++;
3379 }
3380 else if (NT_SUCCESS(Status))
3381 {
3382 /* Try to also match the device identifier */
3383 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
3384 {
3385 pHardwareId = &HardwareIdPci;
3386 DeviceIndex = DeviceIndexPci++;
3387 }
3388 else if (RtlCompareUnicodeString(&ValueName, &IdentifierIsa, FALSE) == 0)
3389 {
3390 pHardwareId = &HardwareIdIsa;
3391 DeviceIndex = DeviceIndexIsa++;
3392 }
3393 else
3394 {
3395 DPRINT("Unknown device '%wZ'\n", &ValueName);
3396 goto nextdevice;
3397 }
3398 }
3399 else
3400 {
3401 /* Unknown key path */
3402 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3403 goto nextdevice;
3404 }
3405
3406 /* Prepare hardware id key (hardware id value without final \0) */
3407 HardwareIdKey = *pHardwareId;
3408 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3409
3410 /* Add the detected device to Root key */
3411 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3412 Status = ZwCreateKey(
3413 &hLevel1Key,
3414 KEY_CREATE_SUB_KEY,
3415 &ObjectAttributes,
3416 0,
3417 NULL,
3418 REG_OPTION_NON_VOLATILE,
3419 NULL);
3420 if (!NT_SUCCESS(Status))
3421 {
3422 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3423 goto nextdevice;
3424 }
3425 swprintf(Level2Name, L"%04lu", DeviceIndex);
3426 RtlInitUnicodeString(&Level2NameU, Level2Name);
3427 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3428 Status = ZwCreateKey(
3429 &hLevel2Key,
3430 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3431 &ObjectAttributes,
3432 0,
3433 NULL,
3434 REG_OPTION_NON_VOLATILE,
3435 NULL);
3436 ZwClose(hLevel1Key);
3437 if (!NT_SUCCESS(Status))
3438 {
3439 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3440 goto nextdevice;
3441 }
3442 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3443 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3444 if (!NT_SUCCESS(Status))
3445 {
3446 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3447 ZwDeleteKey(hLevel2Key);
3448 goto nextdevice;
3449 }
3450 /* Create 'LogConf' subkey */
3451 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3452 Status = ZwCreateKey(
3453 &hLogConf,
3454 KEY_SET_VALUE,
3455 &ObjectAttributes,
3456 0,
3457 NULL,
3458 REG_OPTION_VOLATILE,
3459 NULL);
3460 if (!NT_SUCCESS(Status))
3461 {
3462 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3463 ZwDeleteKey(hLevel2Key);
3464 goto nextdevice;
3465 }
3466 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3467 {
3468 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3469 if (!CmResourceList)
3470 {
3471 ZwClose(hLogConf);
3472 ZwDeleteKey(hLevel2Key);
3473 goto nextdevice;
3474 }
3475
3476 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3477 ListCount = 1;
3478 RtlCopyMemory(CmResourceList,
3479 &ListCount,
3480 sizeof(ULONG));
3481
3482 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3483 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3484 BootResources,
3485 BootResourcesLength);
3486
3487 /* Save boot resources to 'LogConf\BootConfig' */
3488 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3489 if (!NT_SUCCESS(Status))
3490 {
3491 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3492 ZwClose(hLogConf);
3493 ZwDeleteKey(hLevel2Key);
3494 goto nextdevice;
3495 }
3496 }
3497 ZwClose(hLogConf);
3498
3499 nextdevice:
3500 if (BootResources && BootResources != ParentBootResources)
3501 {
3502 ExFreePool(BootResources);
3503 BootResources = NULL;
3504 }
3505 if (hLevel2Key)
3506 {
3507 ZwClose(hLevel2Key);
3508 hLevel2Key = NULL;
3509 }
3510 if (hDeviceKey)
3511 {
3512 ZwClose(hDeviceKey);
3513 hDeviceKey = NULL;
3514 }
3515 }
3516
3517 Status = STATUS_SUCCESS;
3518
3519 cleanup:
3520 if (hDevicesKey && hDevicesKey != hBaseKey)
3521 ZwClose(hDevicesKey);
3522 if (hDeviceKey)
3523 ZwClose(hDeviceKey);
3524 if (pDeviceInformation)
3525 ExFreePool(pDeviceInformation);
3526 if (pValueInformation)
3527 ExFreePool(pValueInformation);
3528 return Status;
3529 }
3530
3531 static BOOLEAN INIT_FUNCTION
3532 IopIsAcpiComputer(VOID)
3533 {
3534 #ifndef ENABLE_ACPI
3535 return FALSE;
3536 #else
3537 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3538 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3539 UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS");
3540 OBJECT_ATTRIBUTES ObjectAttributes;
3541 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3542 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3543 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3544 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3545 ULONG RequiredSize;
3546 ULONG IndexDevice = 0;
3547 UNICODE_STRING DeviceName, ValueName;
3548 HANDLE hDevicesKey = NULL;
3549 HANDLE hDeviceKey = NULL;
3550 NTSTATUS Status;
3551 BOOLEAN ret = FALSE;
3552
3553 InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3554 Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
3555 if (!NT_SUCCESS(Status))
3556 {
3557 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3558 goto cleanup;
3559 }
3560
3561 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3562 if (!pDeviceInformation)
3563 {
3564 DPRINT("ExAllocatePool() failed\n");
3565 Status = STATUS_NO_MEMORY;
3566 goto cleanup;
3567 }
3568
3569 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3570 if (!pDeviceInformation)
3571 {
3572 DPRINT("ExAllocatePool() failed\n");
3573 Status = STATUS_NO_MEMORY;
3574 goto cleanup;
3575 }
3576
3577 while (TRUE)
3578 {
3579 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3580 if (Status == STATUS_NO_MORE_ENTRIES)
3581 break;
3582 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3583 {
3584 ExFreePool(pDeviceInformation);
3585 DeviceInfoLength = RequiredSize;
3586 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3587 if (!pDeviceInformation)
3588 {
3589 DPRINT("ExAllocatePool() failed\n");
3590 Status = STATUS_NO_MEMORY;
3591 goto cleanup;
3592 }
3593 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3594 }
3595 if (!NT_SUCCESS(Status))
3596 {
3597 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3598 goto cleanup;
3599 }
3600 IndexDevice++;
3601
3602 /* Open device key */
3603 DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
3604 DeviceName.Buffer = pDeviceInformation->Name;
3605 InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
3606 Status = ZwOpenKey(
3607 &hDeviceKey,
3608 KEY_QUERY_VALUE,
3609 &ObjectAttributes);
3610 if (!NT_SUCCESS(Status))
3611 {
3612 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3613 goto cleanup;
3614 }
3615
3616 /* Read identifier */
3617 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3618 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3619 {
3620 ExFreePool(pValueInformation);
3621 ValueInfoLength = RequiredSize;
3622 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3623 if (!pValueInformation)
3624 {
3625 DPRINT("ExAllocatePool() failed\n");
3626 Status = STATUS_NO_MEMORY;
3627 goto cleanup;
3628 }
3629 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3630 }
3631 if (!NT_SUCCESS(Status))
3632 {
3633 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3634 goto nextdevice;
3635 }
3636 else if (pValueInformation->Type != REG_SZ)
3637 {
3638 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3639 goto nextdevice;
3640 }
3641
3642 ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
3643 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3644 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3645 ValueName.Length -= sizeof(WCHAR);
3646 if (RtlCompareUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE) == 0)
3647 {
3648 DPRINT("Found ACPI BIOS\n");
3649 ret = TRUE;
3650 goto cleanup;
3651 }
3652
3653 nextdevice:
3654 ZwClose(hDeviceKey);
3655 hDeviceKey = NULL;
3656 }
3657
3658 cleanup:
3659 if (pDeviceInformation)
3660 ExFreePool(pDeviceInformation);
3661 if (pValueInformation)
3662 ExFreePool(pValueInformation);
3663 if (hDevicesKey)
3664 ZwClose(hDevicesKey);
3665 if (hDeviceKey)
3666 ZwClose(hDeviceKey);
3667 return ret;
3668 #endif
3669 }
3670
3671 NTSTATUS
3672 NTAPI
3673 IopUpdateRootKey(VOID)
3674 {
3675 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3676 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3677 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3678 UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
3679 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3680 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
3681 UNICODE_STRING HalAcpiDevice = RTL_CONSTANT_STRING(L"ACPI_HAL");
3682 UNICODE_STRING HalAcpiId = RTL_CONSTANT_STRING(L"0000");
3683 UNICODE_STRING HalAcpiDeviceDesc = RTL_CONSTANT_STRING(L"HAL ACPI");
3684 UNICODE_STRING HalAcpiHardwareID = RTL_CONSTANT_STRING(L"*PNP0C08\0");
3685 OBJECT_ATTRIBUTES ObjectAttributes;
3686 HANDLE hEnum, hRoot, hHalAcpiDevice, hHalAcpiId, hLogConf;
3687 NTSTATUS Status;
3688
3689 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3690 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3691 if (!NT_SUCCESS(Status))
3692 {
3693 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3694 return Status;
3695 }
3696
3697 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3698 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3699 ZwClose(hEnum);
3700 if (!NT_SUCCESS(Status))
3701 {
3702 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3703 return Status;
3704 }
3705
3706 if (IopIsAcpiComputer())
3707 {
3708 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiDevice, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hRoot, NULL);
3709 Status = ZwCreateKey(&hHalAcpiDevice, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3710 ZwClose(hRoot);
3711 if (!NT_SUCCESS(Status))
3712 return Status;
3713 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiId, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiDevice, NULL);
3714 Status = ZwCreateKey(&hHalAcpiId, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3715 ZwClose(hHalAcpiDevice);
3716 if (!NT_SUCCESS(Status))
3717 return Status;
3718 Status = ZwSetValueKey(hHalAcpiId, &DeviceDescU, 0, REG_SZ, HalAcpiDeviceDesc.Buffer, HalAcpiDeviceDesc.MaximumLength);
3719 if (NT_SUCCESS(Status))
3720 Status = ZwSetValueKey(hHalAcpiId, &HardwareIDU, 0, REG_MULTI_SZ, HalAcpiHardwareID.Buffer, HalAcpiHardwareID.MaximumLength);
3721 if (NT_SUCCESS(Status))
3722 {
3723 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiId, NULL);
3724 Status = ZwCreateKey(&hLogConf, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
3725 if (NT_SUCCESS(Status))
3726 ZwClose(hLogConf);
3727 }
3728 ZwClose(hHalAcpiId);
3729 return Status;
3730 }
3731 else
3732 {
3733 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3734 if (!NT_SUCCESS(Status))
3735 {
3736 /* Nothing to do, don't return with an error status */
3737 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3738 ZwClose(hRoot);
3739 return STATUS_SUCCESS;
3740 }
3741 Status = IopEnumerateDetectedDevices(
3742 hEnum,
3743 NULL,
3744 hRoot,
3745 TRUE,
3746 NULL,
3747 0);
3748 ZwClose(hEnum);
3749 ZwClose(hRoot);
3750 return Status;
3751 }
3752 }
3753
3754 NTSTATUS
3755 NTAPI
3756 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3757 HANDLE ParentKey,
3758 PUNICODE_STRING Name,
3759 ACCESS_MASK DesiredAccess)
3760 {
3761 OBJECT_ATTRIBUTES ObjectAttributes;
3762 NTSTATUS Status;
3763
3764 PAGED_CODE();
3765
3766 *KeyHandle = NULL;
3767
3768 InitializeObjectAttributes(&ObjectAttributes,
3769 Name,
3770 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3771 ParentKey,
3772 NULL);
3773
3774 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3775
3776 return Status;
3777 }
3778
3779 NTSTATUS
3780 NTAPI
3781 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3782 IN HANDLE RootHandle OPTIONAL,
3783 IN PUNICODE_STRING KeyName,
3784 IN ACCESS_MASK DesiredAccess,
3785 IN ULONG CreateOptions,
3786 OUT PULONG Disposition OPTIONAL)
3787 {
3788 OBJECT_ATTRIBUTES ObjectAttributes;
3789 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0, Length;
3790 HANDLE HandleArray[2];
3791 BOOLEAN Recursing = TRUE;
3792 PWCHAR pp, p, p1;
3793 UNICODE_STRING KeyString;
3794 NTSTATUS Status = STATUS_SUCCESS;
3795 PAGED_CODE();
3796
3797 /* P1 is start, pp is end */
3798 p1 = KeyName->Buffer;
3799 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3800
3801 /* Create the target key */
3802 InitializeObjectAttributes(&ObjectAttributes,
3803 KeyName,
3804 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3805 RootHandle,
3806 NULL);
3807 Status = ZwCreateKey(&HandleArray[i],
3808 DesiredAccess,
3809 &ObjectAttributes,
3810 0,
3811 NULL,
3812 CreateOptions,
3813 &KeyDisposition);
3814
3815 /* Now we check if this failed */
3816 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3817 {
3818 /* Target key failed, so we'll need to create its parent. Setup array */
3819 HandleArray[0] = NULL;
3820 HandleArray[1] = RootHandle;
3821
3822 /* Keep recursing for each missing parent */
3823 while (Recursing)
3824 {
3825 /* And if we're deep enough, close the last handle */
3826 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3827
3828 /* We're setup to ping-pong between the two handle array entries */
3829 RootHandleIndex = i;
3830 i = (i + 1) & 1;
3831
3832 /* Clear the one we're attempting to open now */
3833 HandleArray[i] = NULL;
3834
3835 /* Process the parent key name */
3836 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3837 Length = (p - p1) * sizeof(WCHAR);
3838
3839 /* Is there a parent name? */
3840 if (Length)
3841 {
3842 /* Build the unicode string for it */
3843 KeyString.Buffer = p1;
3844 KeyString.Length = KeyString.MaximumLength = Length;
3845
3846 /* Now try opening the parent */
3847 InitializeObjectAttributes(&ObjectAttributes,
3848 &KeyString,
3849 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3850 HandleArray[RootHandleIndex],
3851 NULL);
3852 Status = ZwCreateKey(&HandleArray[i],
3853 DesiredAccess,
3854 &ObjectAttributes,
3855 0,
3856 NULL,
3857 CreateOptions,
3858 &KeyDisposition);
3859 if (NT_SUCCESS(Status))
3860 {
3861 /* It worked, we have one more handle */
3862 NestedCloseLevel++;
3863 }
3864 else
3865 {
3866 /* Parent key creation failed, abandon loop */
3867 Recursing = FALSE;
3868 continue;
3869 }
3870 }
3871 else
3872 {
3873 /* We don't have a parent name, probably corrupted key name */
3874 Status = STATUS_INVALID_PARAMETER;
3875 Recursing = FALSE;
3876 continue;
3877 }
3878
3879 /* Now see if there's more parents to create */
3880 p1 = p + 1;
3881 if ((p == pp) || (p1 == pp))
3882 {
3883 /* We're done, hopefully successfully, so stop */
3884 Recursing = FALSE;
3885 }
3886 }
3887
3888 /* Outer loop check for handle nesting that requires closing the top handle */
3889 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3890 }
3891
3892 /* Check if we broke out of the loop due to success */
3893 if (NT_SUCCESS(Status))
3894 {
3895 /* Return the target handle (we closed all the parent ones) and disposition */
3896 *Handle = HandleArray[i];
3897 if (Disposition) *Disposition = KeyDisposition;
3898 }
3899
3900 /* Return the success state */
3901 return Status;
3902 }
3903
3904 NTSTATUS
3905 NTAPI
3906 IopGetRegistryValue(IN HANDLE Handle,
3907 IN PWSTR ValueName,
3908 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3909 {
3910 UNICODE_STRING ValueString;
3911 NTSTATUS Status;
3912 PKEY_VALUE_FULL_INFORMATION FullInformation;
3913 ULONG Size;
3914 PAGED_CODE();
3915
3916 RtlInitUnicodeString(&ValueString, ValueName);
3917
3918 Status = ZwQueryValueKey(Handle,
3919 &ValueString,
3920 KeyValueFullInformation,
3921 NULL,
3922 0,
3923 &Size);
3924 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3925 (Status != STATUS_BUFFER_TOO_SMALL))
3926 {
3927 return Status;
3928 }
3929
3930 FullInformation = ExAllocatePool(NonPagedPool, Size);
3931 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3932
3933 Status = ZwQueryValueKey(Handle,
3934 &ValueString,
3935 KeyValueFullInformation,
3936 FullInformation,
3937 Size,
3938 &Size);
3939 if (!NT_SUCCESS(Status))
3940 {
3941 ExFreePool(FullInformation);
3942 return Status;
3943 }
3944
3945 *Information = FullInformation;
3946 return STATUS_SUCCESS;
3947 }
3948
3949 RTL_GENERIC_COMPARE_RESULTS
3950 NTAPI
3951 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3952 IN PVOID FirstStruct,
3953 IN PVOID SecondStruct)
3954 {
3955 /* FIXME: TODO */
3956 ASSERT(FALSE);
3957 return 0;
3958 }
3959
3960 //
3961 // The allocation function is called by the generic table package whenever
3962 // it needs to allocate memory for the table.
3963 //
3964
3965 PVOID
3966 NTAPI
3967 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3968 IN CLONG ByteSize)
3969 {
3970 /* FIXME: TODO */
3971 ASSERT(FALSE);
3972 return NULL;
3973 }
3974
3975 VOID
3976 NTAPI
3977 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3978 IN PVOID Buffer)
3979 {
3980 /* FIXME: TODO */
3981 ASSERT(FALSE);
3982 }
3983
3984 VOID
3985 NTAPI
3986 PpInitializeDeviceReferenceTable(VOID)
3987 {
3988 /* Setup the guarded mutex and AVL table */
3989 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3990 RtlInitializeGenericTableAvl(
3991 &PpDeviceReferenceTable,
3992 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3993 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3994 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3995 NULL);
3996 }
3997
3998 BOOLEAN
3999 NTAPI
4000 PiInitPhase0(VOID)
4001 {
4002 /* Initialize the resource when accessing device registry data */
4003 ExInitializeResourceLite(&PpRegistryDeviceResource);
4004
4005 /* Setup the device reference AVL table */
4006 PpInitializeDeviceReferenceTable();
4007 return TRUE;
4008 }
4009
4010 BOOLEAN
4011 NTAPI
4012 PpInitSystem(VOID)
4013 {
4014 /* Check the initialization phase */
4015 switch (ExpInitializationPhase)
4016 {
4017 case 0:
4018
4019 /* Do Phase 0 */
4020 return PiInitPhase0();
4021
4022 case 1:
4023
4024 /* Do Phase 1 */
4025 return TRUE;
4026 //return PiInitPhase1();
4027
4028 default:
4029
4030 /* Don't know any other phase! Bugcheck! */
4031 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
4032 return FALSE;
4033 }
4034 }
4035
4036 LONG IopNumberDeviceNodes;
4037
4038 PDEVICE_NODE
4039 NTAPI
4040 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
4041 {
4042 PDEVICE_NODE DeviceNode;
4043 PAGED_CODE();
4044
4045 /* Allocate it */
4046 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), 'donD');
4047 if (!DeviceNode) return DeviceNode;
4048
4049 /* Statistics */
4050 InterlockedIncrement(&IopNumberDeviceNodes);
4051
4052 /* Set it up */
4053 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
4054 DeviceNode->InterfaceType = InterfaceTypeUndefined;
4055 DeviceNode->BusNumber = -1;
4056 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
4057 DeviceNode->ChildBusNumber = -1;
4058 DeviceNode->ChildBusTypeIndex = -1;
4059 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
4060 InitializeListHead(&DeviceNode->DeviceArbiterList);
4061 InitializeListHead(&DeviceNode->DeviceTranslatorList);
4062 InitializeListHead(&DeviceNode->TargetDeviceNotify);
4063 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
4064 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
4065
4066 /* Check if there is a PDO */
4067 if (PhysicalDeviceObject)
4068 {
4069 /* Link it and remove the init flag */
4070 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
4071 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
4072 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
4073 }
4074
4075 /* Return the node */
4076 return DeviceNode;
4077 }
4078
4079 /* PUBLIC FUNCTIONS **********************************************************/
4080
4081 /*
4082 * @implemented
4083 */
4084 NTSTATUS
4085 NTAPI
4086 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
4087 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
4088 IN ULONG BufferLength,
4089 OUT PVOID PropertyBuffer,
4090 OUT PULONG ResultLength)
4091 {
4092 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4093 DEVICE_CAPABILITIES DeviceCaps;
4094 ULONG Length;
4095 PVOID Data = NULL;
4096 PWSTR Ptr;
4097 NTSTATUS Status;
4098 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
4099 ULONG RequiredLength, ObjectNameInfoLength;
4100
4101 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
4102
4103 *ResultLength = 0;
4104
4105 if (DeviceNode == NULL)
4106 return STATUS_INVALID_DEVICE_REQUEST;
4107
4108 switch (DeviceProperty)
4109 {
4110 case DevicePropertyBusNumber:
4111 Length = sizeof(ULONG);
4112 Data = &DeviceNode->ChildBusNumber;
4113 break;
4114
4115 /* Complete, untested */
4116 case DevicePropertyBusTypeGuid:
4117 /* Sanity check */
4118 if ((DeviceNode->ChildBusTypeIndex != 0xFFFF) &&
4119 (DeviceNode->ChildBusTypeIndex < PnpBusTypeGuidList->GuidCount))
4120 {
4121 /* Return the GUID */
4122 *ResultLength = sizeof(GUID);
4123
4124 /* Check if the buffer given was large enough */
4125 if (BufferLength < *ResultLength)
4126 {
4127 return STATUS_BUFFER_TOO_SMALL;
4128 }
4129
4130 /* Copy the GUID */
4131 RtlCopyMemory(PropertyBuffer,
4132 &(PnpBusTypeGuidList->Guids[DeviceNode->ChildBusTypeIndex]),
4133 sizeof(GUID));
4134 return STATUS_SUCCESS;
4135 }
4136 else
4137 {
4138 return STATUS_OBJECT_NAME_NOT_FOUND;
4139 }
4140 break;
4141
4142 case DevicePropertyLegacyBusType:
4143 Length = sizeof(INTERFACE_TYPE);
4144 Data = &DeviceNode->ChildInterfaceType;
4145 break;
4146
4147 case DevicePropertyAddress:
4148 /* Query the device caps */
4149 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
4150 if (NT_SUCCESS(Status) && (DeviceCaps.Address != MAXULONG))
4151 {
4152 /* Return length */
4153 *ResultLength = sizeof(ULONG);
4154
4155 /* Check if the buffer given was large enough */
4156 if (BufferLength < *ResultLength)
4157 {
4158 return STATUS_BUFFER_TOO_SMALL;
4159 }
4160
4161 /* Return address */
4162 *(PULONG)PropertyBuffer = DeviceCaps.Address;
4163 return STATUS_SUCCESS;
4164 }
4165 else
4166 {
4167 return STATUS_OBJECT_NAME_NOT_FOUND;
4168 }
4169 break;
4170
4171 // case DevicePropertyUINumber:
4172 // if (DeviceNode->CapabilityFlags == NULL)
4173 // return STATUS_INVALID_DEVICE_REQUEST;
4174 // Length = sizeof(ULONG);
4175 // Data = &DeviceNode->CapabilityFlags->UINumber;
4176 // break;
4177
4178 case DevicePropertyClassName:
4179 case DevicePropertyClassGuid:
4180 case DevicePropertyDriverKeyName:
4181 case DevicePropertyManufacturer:
4182 case DevicePropertyFriendlyName:
4183 case DevicePropertyHardwareID:
4184 case DevicePropertyCompatibleIDs:
4185 case DevicePropertyDeviceDescription:
4186 case DevicePropertyLocationInformation:
4187 case DevicePropertyUINumber:
4188 {
4189 LPCWSTR RegistryPropertyName;
4190 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
4191 UNICODE_STRING ValueName;
4192 KEY_VALUE_PARTIAL_INFORMATION *ValueInformation;
4193 ULONG ValueInformationLength;
4194 HANDLE KeyHandle, EnumRootHandle;
4195 NTSTATUS Status;
4196
4197 switch (DeviceProperty)
4198 {
4199 case DevicePropertyClassName:
4200 RegistryPropertyName = L"Class"; break;
4201 case DevicePropertyClassGuid:
4202 RegistryPropertyName = L"ClassGuid"; break;
4203 case DevicePropertyDriverKeyName:
4204 RegistryPropertyName = L"Driver"; break;
4205 case DevicePropertyManufacturer:
4206 RegistryPropertyName = L"Mfg"; break;
4207 case DevicePropertyFriendlyName:
4208 RegistryPropertyName = L"FriendlyName"; break;
4209 case DevicePropertyHardwareID:
4210 RegistryPropertyName = L"HardwareID"; break;
4211 case DevicePropertyCompatibleIDs:
4212 RegistryPropertyName = L"CompatibleIDs"; break;
4213 case DevicePropertyDeviceDescription:
4214 RegistryPropertyName = L"DeviceDesc"; break;
4215 case DevicePropertyLocationInformation:
4216 RegistryPropertyName = L"LocationInformation"; break;
4217 case DevicePropertyUINumber:
4218 RegistryPropertyName = L"UINumber"; break;
4219 default:
4220 /* Should not happen */
4221 ASSERT(FALSE);
4222 return STATUS_UNSUCCESSFUL;
4223 }
4224
4225 DPRINT("Registry property %S\n", RegistryPropertyName);
4226
4227 /* Open Enum key */
4228 Status = IopOpenRegistryKeyEx(&EnumRootHandle, NULL,
4229 &EnumRoot, KEY_READ);
4230 if (!NT_SUCCESS(Status))
4231 {
4232 DPRINT1("Error opening ENUM_ROOT, Status=0x%08x\n", Status);
4233 return Status;
4234 }
4235
4236 /* Open instance key */
4237 Status = IopOpenRegistryKeyEx(&KeyHandle, EnumRootHandle,
4238 &DeviceNode->InstancePath, KEY_READ);
4239 if (!NT_SUCCESS(Status))
4240 {
4241 DPRINT1("Error opening InstancePath, Status=0x%08x\n", Status);
4242 ZwClose(EnumRootHandle);
4243 return Status;
4244 }
4245
4246 /* Allocate buffer to read as much data as required by the caller */
4247 ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
4248 Data[0]) + BufferLength;
4249 ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
4250 if (!ValueInformation)
4251 {
4252 ZwClose(KeyHandle);
4253 return STATUS_INSUFFICIENT_RESOURCES;
4254 }
4255
4256 /* Read the value */
4257 RtlInitUnicodeString(&ValueName, RegistryPropertyName);
4258 Status = ZwQueryValueKey(KeyHandle, &ValueName,
4259 KeyValuePartialInformation, ValueInformation,
4260 ValueInformationLength,
4261 &ValueInformationLength);
4262 ZwClose(KeyHandle);
4263
4264 /* Return data */
4265 *ResultLength = ValueInformation->DataLength;
4266
4267 if (!NT_SUCCESS(Status))
4268 {
4269 ExFreePool(ValueInformation);
4270 if (Status == STATUS_BUFFER_OVERFLOW)
4271 return STATUS_BUFFER_TOO_SMALL;
4272 DPRINT1("Problem: Status=0x%08x, ResultLength = %d\n", Status, *ResultLength);
4273 return Status;
4274 }
4275
4276 /* FIXME: Verify the value (NULL-terminated, correct format). */
4277 RtlCopyMemory(PropertyBuffer, ValueInformation->Data,
4278 ValueInformation->DataLength);
4279 ExFreePool(ValueInformation);
4280
4281 return STATUS_SUCCESS;
4282 }
4283
4284 case DevicePropertyBootConfiguration:
4285 Length = 0;
4286 if (DeviceNode->BootResources->Count != 0)
4287 {
4288 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
4289 }
4290 Data = DeviceNode->BootResources;
4291 break;
4292
4293 /* FIXME: use a translated boot configuration instead */
4294 case DevicePropertyBootConfigurationTranslated:
4295 Length = 0;
4296 if (DeviceNode->BootResources->Count != 0)
4297 {
4298 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
4299 }
4300 Data = DeviceNode->BootResources;
4301 break;
4302
4303 case DevicePropertyEnumeratorName:
4304 /* A buffer overflow can't happen here, since InstancePath
4305 * always contains the enumerator name followed by \\ */
4306 Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\');
4307 ASSERT(Ptr);
4308 Length = (Ptr - DeviceNode->InstancePath.Buffer) * sizeof(WCHAR);
4309 Data = DeviceNode->InstancePath.Buffer;
4310 break;
4311
4312 case DevicePropertyPhysicalDeviceObjectName:
4313 Status = ObQueryNameString(DeviceNode->PhysicalDeviceObject,
4314 NULL,
4315 0,
4316 &RequiredLength);
4317 if (Status == STATUS_SUCCESS)
4318 {
4319 Length = 0;
4320 Data = L"";
4321 }
4322 else if (Status == STATUS_INFO_LENGTH_MISMATCH)
4323 {
4324 ObjectNameInfoLength = RequiredLength;
4325 ObjectNameInfo = ExAllocatePool(PagedPool, ObjectNameInfoLength);
4326 if (!ObjectNameInfo)
4327 return STATUS_INSUFFICIENT_RESOURCES;
4328
4329 Status = ObQueryNameString(DeviceNode->PhysicalDeviceObject,
4330 ObjectNameInfo,
4331 ObjectNameInfoLength,
4332 &RequiredLength);
4333 if (NT_SUCCESS(Status))
4334 {
4335 Length = ObjectNameInfo->Name.Length;
4336 Data = ObjectNameInfo->Name.Buffer;
4337 }
4338 else
4339 return Status;
4340 }
4341 else
4342 return Status;
4343 break;
4344
4345 default:
4346 return STATUS_INVALID_PARAMETER_2;
4347 }
4348
4349 /* Prepare returned values */
4350 *ResultLength = Length;
4351 if (BufferLength < Length)
4352 {
4353 if (ObjectNameInfo != NULL)
4354 ExFreePool(ObjectNameInfo);
4355
4356 return STATUS_BUFFER_TOO_SMALL;
4357 }
4358 RtlCopyMemory(PropertyBuffer, Data, Length);
4359
4360 /* NULL terminate the string (if required) */
4361 if (DeviceProperty == DevicePropertyEnumeratorName ||
4362 DeviceProperty == DevicePropertyPhysicalDeviceObjectName)
4363 ((LPWSTR)PropertyBuffer)[Length / sizeof(WCHAR)] = UNICODE_NULL;
4364
4365 if (ObjectNameInfo != NULL)
4366 ExFreePool(ObjectNameInfo);
4367
4368 return STATUS_SUCCESS;
4369 }
4370
4371 /*
4372 * @unimplemented
4373 */
4374 VOID
4375 NTAPI
4376 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
4377 {
4378 UNIMPLEMENTED;
4379 }
4380
4381 /**
4382 * @name IoOpenDeviceRegistryKey
4383 *
4384 * Open a registry key unique for a specified driver or device instance.
4385 *
4386 * @param DeviceObject Device to get the registry key for.
4387 * @param DevInstKeyType Type of the key to return.
4388 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4389 * @param DevInstRegKey Handle to the opened registry key on
4390 * successful return.
4391 *
4392 * @return Status.
4393 *
4394 * @implemented
4395 */
4396 NTSTATUS
4397 NTAPI
4398 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
4399 IN ULONG DevInstKeyType,
4400 IN ACCESS_MASK DesiredAccess,
4401 OUT PHANDLE DevInstRegKey)
4402 {
4403 static WCHAR RootKeyName[] =
4404 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4405 static WCHAR ProfileKeyName[] =
4406 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4407 static WCHAR ClassKeyName[] = L"Control\\Class\\";
4408 static WCHAR EnumKeyName[] = L"Enum\\";
4409 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4410 ULONG KeyNameLength;
4411 LPWSTR KeyNameBuffer;
4412 UNICODE_STRING KeyName;
4413 ULONG DriverKeyLength;
4414 OBJECT_ATTRIBUTES ObjectAttributes;
4415 PDEVICE_NODE DeviceNode = NULL;
4416 NTSTATUS Status;
4417
4418 DPRINT("IoOpenDeviceRegistryKey() called\n");
4419
4420 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
4421 {
4422 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4423 return STATUS_INVALID_PARAMETER;
4424 }
4425
4426 /*
4427 * Calculate the length of the base key name. This is the full
4428 * name for driver key or the name excluding "Device Parameters"
4429 * subkey for device key.
4430 */
4431
4432 KeyNameLength = sizeof(RootKeyName);
4433 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4434 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4435 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4436 {
4437 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4438 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4439 0, NULL, &DriverKeyLength);
4440 if (Status != STATUS_BUFFER_TOO_SMALL)
4441 return Status;
4442 KeyNameLength += DriverKeyLength;
4443 }
4444 else
4445 {
4446 DeviceNode = IopGetDeviceNode(DeviceObject);
4447 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4448 DeviceNode->InstancePath.Length;
4449 }
4450
4451 /*
4452 * Now allocate the buffer for the key name...
4453 */
4454
4455 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4456 if (KeyNameBuffer == NULL)
4457 return STATUS_INSUFFICIENT_RESOURCES;
4458
4459 KeyName.Length = 0;
4460 KeyName.MaximumLength = (USHORT)KeyNameLength;
4461 KeyName.Buffer = KeyNameBuffer;
4462
4463 /*
4464 * ...and build the key name.
4465 */
4466
4467 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4468 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4469
4470 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4471 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4472
4473 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4474 {
4475 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4476 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4477 DriverKeyLength, KeyNameBuffer +
4478 (KeyName.Length / sizeof(WCHAR)),
4479 &DriverKeyLength);
4480 if (!NT_SUCCESS(Status))
4481 {
4482 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4483 ExFreePool(KeyNameBuffer);
4484 return Status;
4485 }
4486 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4487 }
4488 else
4489 {
4490 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4491 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
4492 if (DeviceNode->InstancePath.Length == 0)
4493 {
4494 ExFreePool(KeyNameBuffer);
4495 return Status;
4496 }
4497 }
4498
4499 /*
4500 * Open the base key.
4501 */
4502 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
4503 if (!NT_SUCCESS(Status))
4504 {
4505 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4506 ExFreePool(KeyNameBuffer);
4507 return Status;
4508 }
4509 ExFreePool(KeyNameBuffer);
4510
4511 /*
4512 * For driver key we're done now.
4513 */
4514
4515 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4516 return Status;
4517
4518 /*
4519 * Let's go further. For device key we must open "Device Parameters"
4520 * subkey and create it if it doesn't exist yet.
4521 */
4522
4523 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4524 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
4525 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
4526 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
4527 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
4528 ZwClose(ObjectAttributes.RootDirectory);
4529
4530 return Status;
4531 }
4532
4533 /*
4534 * @unimplemented
4535 */
4536 VOID
4537 NTAPI
4538 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
4539 {
4540 UNIMPLEMENTED;
4541 }
4542
4543 /*
4544 * @implemented
4545 */
4546 VOID
4547 NTAPI
4548 IoInvalidateDeviceRelations(
4549 IN PDEVICE_OBJECT DeviceObject,
4550 IN DEVICE_RELATION_TYPE Type)
4551 {
4552 PIO_WORKITEM WorkItem;
4553 PINVALIDATE_DEVICE_RELATION_DATA Data;
4554
4555 Data = ExAllocatePool(PagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
4556 if (!Data)
4557 return;
4558 WorkItem = IoAllocateWorkItem(DeviceObject);
4559 if (!WorkItem)
4560 {
4561 ExFreePool(Data);
4562 return;
4563 }
4564
4565 ObReferenceObject(DeviceObject);
4566 Data->DeviceObject = DeviceObject;
4567 Data->Type = Type;
4568 Data->WorkItem = WorkItem;
4569
4570 IoQueueWorkItem(
4571 WorkItem,
4572 IopAsynchronousInvalidateDeviceRelations,
4573 DelayedWorkQueue,
4574 Data);
4575 }
4576
4577 /*
4578 * @implemented
4579 */
4580 NTSTATUS
4581 NTAPI
4582 IoSynchronousInvalidateDeviceRelations(
4583 IN PDEVICE_OBJECT DeviceObject,
4584 IN DEVICE_RELATION_TYPE Type)
4585 {
4586 PAGED_CODE();
4587
4588 switch (Type)
4589 {
4590 case BusRelations:
4591 /* Enumerate the device */
4592 return IopEnumerateDevice(DeviceObject);
4593 case PowerRelations:
4594 /* Not handled yet */
4595 return STATUS_NOT_IMPLEMENTED;
4596 case TargetDeviceRelation:
4597 /* Nothing to do */
4598 return STATUS_SUCCESS;
4599 default:
4600 /* Ejection relations are not supported */
4601 return STATUS_NOT_SUPPORTED;
4602 }
4603 }
4604
4605 /*
4606 * @unimplemented
4607 */
4608 BOOLEAN
4609 NTAPI
4610 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
4611 IN ULONG BusNumber,
4612 IN PHYSICAL_ADDRESS BusAddress,
4613 IN OUT PULONG AddressSpace,
4614 OUT PPHYSICAL_ADDRESS TranslatedAddress)
4615 {
4616 UNIMPLEMENTED;
4617 return FALSE;
4618 }