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