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