* Branch for the 0.3.14 release.
[reactos.git] / 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->PhysicalDeviceObject);
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 = {0, 0, NULL};
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 return STATUS_INSUFFICIENT_RESOURCES;
1271 }
1272
1273 KeyName.Buffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
1274 if (!KeyName.Buffer)
1275 {
1276 Status = STATUS_INSUFFICIENT_RESOURCES;
1277 goto cleanup;
1278 }
1279 KeyName.Length = 0;
1280 KeyName.MaximumLength = (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length;
1281
1282 RtlAppendUnicodeToString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1283 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1284
1285 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
1286 if (!NT_SUCCESS(Status))
1287 goto cleanup;
1288 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1289 Status = ZwQueryValueKey(
1290 hKey, &ValueName,
1291 KeyValuePartialInformation, ParentIdPrefixInformation,
1292 KeyNameBufferLength, &KeyNameBufferLength);
1293 if (NT_SUCCESS(Status))
1294 {
1295 if (ParentIdPrefixInformation->Type != REG_SZ)
1296 Status = STATUS_UNSUCCESSFUL;
1297 else
1298 {
1299 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1300 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1301 }
1302 goto cleanup;
1303 }
1304 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1305 {
1306 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1307 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1308 goto cleanup;
1309 }
1310
1311 /* 2. Create the ParentIdPrefix value */
1312 crc32 = RtlComputeCrc32(0,
1313 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1314 DeviceNode->Parent->InstancePath.Length);
1315
1316 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
1317 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
1318
1319 /* 3. Try to write the ParentIdPrefix to registry */
1320 Status = ZwSetValueKey(hKey,
1321 &ValueName,
1322 0,
1323 REG_SZ,
1324 (PVOID)KeyValue.Buffer,
1325 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1326
1327 cleanup:
1328 if (NT_SUCCESS(Status))
1329 {
1330 /* Duplicate the string to return it */
1331 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
1332 }
1333 ExFreePool(ParentIdPrefixInformation);
1334 RtlFreeUnicodeString(&KeyName);
1335 if (hKey != NULL)
1336 ZwClose(hKey);
1337 return Status;
1338 }
1339
1340 NTSTATUS
1341 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
1342 HANDLE InstanceKey)
1343 {
1344 IO_STACK_LOCATION Stack;
1345 IO_STATUS_BLOCK IoStatusBlock;
1346 PWSTR Ptr;
1347 UNICODE_STRING ValueName;
1348 NTSTATUS Status;
1349 ULONG Length, TotalLength;
1350
1351 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1352
1353 RtlZeroMemory(&Stack, sizeof(Stack));
1354 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1355 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1356 &IoStatusBlock,
1357 IRP_MN_QUERY_ID,
1358 &Stack);
1359 if (NT_SUCCESS(Status))
1360 {
1361 /*
1362 * FIXME: Check for valid characters, if there is invalid characters
1363 * then bugcheck.
1364 */
1365 TotalLength = 0;
1366 Ptr = (PWSTR)IoStatusBlock.Information;
1367 DPRINT("Hardware IDs:\n");
1368 while (*Ptr)
1369 {
1370 DPRINT(" %S\n", Ptr);
1371 Length = (ULONG)wcslen(Ptr) + 1;
1372
1373 Ptr += Length;
1374 TotalLength += Length;
1375 }
1376 DPRINT("TotalLength: %hu\n", TotalLength);
1377 DPRINT("\n");
1378
1379 RtlInitUnicodeString(&ValueName, L"HardwareID");
1380 Status = ZwSetValueKey(InstanceKey,
1381 &ValueName,
1382 0,
1383 REG_MULTI_SZ,
1384 (PVOID)IoStatusBlock.Information,
1385 (TotalLength + 1) * sizeof(WCHAR));
1386 if (!NT_SUCCESS(Status))
1387 {
1388 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1389 }
1390 }
1391 else
1392 {
1393 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1394 }
1395
1396 return Status;
1397 }
1398
1399 NTSTATUS
1400 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
1401 HANDLE InstanceKey)
1402 {
1403 IO_STACK_LOCATION Stack;
1404 IO_STATUS_BLOCK IoStatusBlock;
1405 PWSTR Ptr;
1406 UNICODE_STRING ValueName;
1407 NTSTATUS Status;
1408 ULONG Length, TotalLength;
1409
1410 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1411
1412 RtlZeroMemory(&Stack, sizeof(Stack));
1413 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1414 Status = IopInitiatePnpIrp(
1415 DeviceNode->PhysicalDeviceObject,
1416 &IoStatusBlock,
1417 IRP_MN_QUERY_ID,
1418 &Stack);
1419 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1420 {
1421 /*
1422 * FIXME: Check for valid characters, if there is invalid characters
1423 * then bugcheck.
1424 */
1425 TotalLength = 0;
1426 Ptr = (PWSTR)IoStatusBlock.Information;
1427 DPRINT("Compatible IDs:\n");
1428 while (*Ptr)
1429 {
1430 DPRINT(" %S\n", Ptr);
1431 Length = (ULONG)wcslen(Ptr) + 1;
1432
1433 Ptr += Length;
1434 TotalLength += Length;
1435 }
1436 DPRINT("TotalLength: %hu\n", TotalLength);
1437 DPRINT("\n");
1438
1439 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1440 Status = ZwSetValueKey(InstanceKey,
1441 &ValueName,
1442 0,
1443 REG_MULTI_SZ,
1444 (PVOID)IoStatusBlock.Information,
1445 (TotalLength + 1) * sizeof(WCHAR));
1446 if (!NT_SUCCESS(Status))
1447 {
1448 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1449 }
1450 }
1451 else
1452 {
1453 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1454 }
1455
1456 return Status;
1457 }
1458
1459
1460 /*
1461 * IopActionInterrogateDeviceStack
1462 *
1463 * Retrieve information for all (direct) child nodes of a parent node.
1464 *
1465 * Parameters
1466 * DeviceNode
1467 * Pointer to device node.
1468 * Context
1469 * Pointer to parent node to retrieve child node information for.
1470 *
1471 * Remarks
1472 * Any errors that occur are logged instead so that all child services have a chance
1473 * of being interrogated.
1474 */
1475
1476 NTSTATUS
1477 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
1478 PVOID Context)
1479 {
1480 IO_STATUS_BLOCK IoStatusBlock;
1481 PDEVICE_NODE ParentDeviceNode;
1482 WCHAR InstancePath[MAX_PATH];
1483 IO_STACK_LOCATION Stack;
1484 NTSTATUS Status;
1485 ULONG RequiredLength;
1486 LCID LocaleId;
1487 HANDLE InstanceKey = NULL;
1488 UNICODE_STRING ValueName;
1489 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
1490 DEVICE_CAPABILITIES DeviceCapabilities;
1491
1492 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1493 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1494
1495 ParentDeviceNode = (PDEVICE_NODE)Context;
1496
1497 /*
1498 * We are called for the parent too, but we don't need to do special
1499 * handling for this node
1500 */
1501
1502 if (DeviceNode == ParentDeviceNode)
1503 {
1504 DPRINT("Success\n");
1505 return STATUS_SUCCESS;
1506 }
1507
1508 /*
1509 * Make sure this device node is a direct child of the parent device node
1510 * that is given as an argument
1511 */
1512
1513 if (DeviceNode->Parent != ParentDeviceNode)
1514 {
1515 DPRINT("Skipping 2+ level child\n");
1516 return STATUS_SUCCESS;
1517 }
1518
1519 /* Skip processing if it was already completed before */
1520 if (DeviceNode->Flags & DNF_PROCESSED)
1521 {
1522 /* Nothing to do */
1523 return STATUS_SUCCESS;
1524 }
1525
1526 /* Get Locale ID */
1527 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
1528 if (!NT_SUCCESS(Status))
1529 {
1530 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
1531 return Status;
1532 }
1533
1534 /*
1535 * FIXME: For critical errors, cleanup and disable device, but always
1536 * return STATUS_SUCCESS.
1537 */
1538
1539 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1540
1541 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1542 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1543 &IoStatusBlock,
1544 IRP_MN_QUERY_ID,
1545 &Stack);
1546 if (NT_SUCCESS(Status))
1547 {
1548 /* Copy the device id string */
1549 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
1550
1551 /*
1552 * FIXME: Check for valid characters, if there is invalid characters
1553 * then bugcheck.
1554 */
1555 }
1556 else
1557 {
1558 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1559
1560 /* We have to return success otherwise we abort the traverse operation */
1561 return STATUS_SUCCESS;
1562 }
1563
1564 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1565
1566 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1567 if (!NT_SUCCESS(Status))
1568 {
1569 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1570
1571 /* We have to return success otherwise we abort the traverse operation */
1572 return STATUS_SUCCESS;
1573 }
1574
1575 /* This bit is only check after enumeration */
1576 if (DeviceCapabilities.HardwareDisabled)
1577 {
1578 /* FIXME: Cleanup device */
1579 DeviceNode->Flags |= DNF_DISABLED;
1580 return STATUS_SUCCESS;
1581 }
1582 else
1583 DeviceNode->Flags &= ~DNF_DISABLED;
1584
1585 if (!DeviceCapabilities.UniqueID)
1586 {
1587 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1588 DPRINT("Instance ID is not unique\n");
1589 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1590 if (!NT_SUCCESS(Status))
1591 {
1592 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1593
1594 /* We have to return success otherwise we abort the traverse operation */
1595 return STATUS_SUCCESS;
1596 }
1597 }
1598
1599 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1600
1601 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1602 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1603 &IoStatusBlock,
1604 IRP_MN_QUERY_ID,
1605 &Stack);
1606 if (NT_SUCCESS(Status))
1607 {
1608 /* Append the instance id string */
1609 wcscat(InstancePath, L"\\");
1610 if (ParentIdPrefix.Length > 0)
1611 {
1612 /* Add information from parent bus device to InstancePath */
1613 wcscat(InstancePath, ParentIdPrefix.Buffer);
1614 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
1615 wcscat(InstancePath, L"&");
1616 }
1617 if (IoStatusBlock.Information)
1618 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1619
1620 /*
1621 * FIXME: Check for valid characters, if there is invalid characters
1622 * then bugcheck
1623 */
1624 }
1625 else
1626 {
1627 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1628 }
1629 RtlFreeUnicodeString(&ParentIdPrefix);
1630
1631 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
1632 {
1633 DPRINT("No resources\n");
1634 /* FIXME: Cleanup and disable device */
1635 }
1636
1637 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1638
1639 /*
1640 * Create registry key for the instance id, if it doesn't exist yet
1641 */
1642 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
1643 if (!NT_SUCCESS(Status))
1644 {
1645 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1646
1647 /* We have to return success otherwise we abort the traverse operation */
1648 return STATUS_SUCCESS;
1649 }
1650
1651 IopQueryHardwareIds(DeviceNode, InstanceKey);
1652
1653 IopQueryCompatibleIds(DeviceNode, InstanceKey);
1654
1655 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1656
1657 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
1658 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
1659 Status = IopInitiatePnpIrp(
1660 DeviceNode->PhysicalDeviceObject,
1661 &IoStatusBlock,
1662 IRP_MN_QUERY_DEVICE_TEXT,
1663 &Stack);
1664 /* This key is mandatory, so even if the Irp fails, we still write it */
1665 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
1666 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
1667 {
1668 if (NT_SUCCESS(Status) &&
1669 IoStatusBlock.Information &&
1670 (*(PWSTR)IoStatusBlock.Information != 0))
1671 {
1672 /* This key is overriden when a driver is installed. Don't write the
1673 * new description if another one already exists */
1674 Status = ZwSetValueKey(InstanceKey,
1675 &ValueName,
1676 0,
1677 REG_SZ,
1678 (PVOID)IoStatusBlock.Information,
1679 ((ULONG)wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1680 }
1681 else
1682 {
1683 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
1684 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
1685
1686 Status = ZwSetValueKey(InstanceKey,
1687 &ValueName,
1688 0,
1689 REG_SZ,
1690 DeviceDesc.Buffer,
1691 DeviceDesc.MaximumLength);
1692
1693 if (!NT_SUCCESS(Status))
1694 {
1695 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
1696 }
1697
1698 }
1699 }
1700
1701 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1702
1703 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
1704 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
1705 Status = IopInitiatePnpIrp(
1706 DeviceNode->PhysicalDeviceObject,
1707 &IoStatusBlock,
1708 IRP_MN_QUERY_DEVICE_TEXT,
1709 &Stack);
1710 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1711 {
1712 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
1713 RtlInitUnicodeString(&ValueName, L"LocationInformation");
1714 Status = ZwSetValueKey(InstanceKey,
1715 &ValueName,
1716 0,
1717 REG_SZ,
1718 (PVOID)IoStatusBlock.Information,
1719 ((ULONG)wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1720 if (!NT_SUCCESS(Status))
1721 {
1722 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1723 }
1724 }
1725 else
1726 {
1727 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1728 }
1729
1730 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1731
1732 Status = IopInitiatePnpIrp(
1733 DeviceNode->PhysicalDeviceObject,
1734 &IoStatusBlock,
1735 IRP_MN_QUERY_BUS_INFORMATION,
1736 NULL);
1737 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1738 {
1739 PPNP_BUS_INFORMATION BusInformation =
1740 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
1741
1742 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
1743 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
1744 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
1745 ExFreePool(BusInformation);
1746 }
1747 else
1748 {
1749 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1750
1751 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
1752 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
1753 DeviceNode->ChildBusTypeIndex = -1;
1754 }
1755
1756 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1757
1758 Status = IopInitiatePnpIrp(
1759 DeviceNode->PhysicalDeviceObject,
1760 &IoStatusBlock,
1761 IRP_MN_QUERY_RESOURCES,
1762 NULL);
1763 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1764 {
1765 DeviceNode->BootResources =
1766 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
1767 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
1768 }
1769 else
1770 {
1771 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1772 DeviceNode->BootResources = NULL;
1773 }
1774
1775 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1776
1777 Status = IopInitiatePnpIrp(
1778 DeviceNode->PhysicalDeviceObject,
1779 &IoStatusBlock,
1780 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
1781 NULL);
1782 if (NT_SUCCESS(Status))
1783 {
1784 DeviceNode->ResourceRequirements =
1785 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
1786 }
1787 else
1788 {
1789 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
1790 DeviceNode->ResourceRequirements = NULL;
1791 }
1792
1793 if (InstanceKey != NULL)
1794 {
1795 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
1796 }
1797
1798 ZwClose(InstanceKey);
1799
1800 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
1801
1802 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
1803 {
1804 /* Report the device to the user-mode pnp manager */
1805 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
1806 &DeviceNode->InstancePath);
1807 }
1808
1809 return STATUS_SUCCESS;
1810 }
1811
1812 static
1813 VOID
1814 IopHandleDeviceRemoval(
1815 IN PDEVICE_NODE DeviceNode,
1816 IN PDEVICE_RELATIONS DeviceRelations)
1817 {
1818 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
1819 ULONG i;
1820 BOOLEAN Found;
1821
1822 while (Child != NULL)
1823 {
1824 NextChild = Child->Sibling;
1825 Found = FALSE;
1826
1827 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
1828 {
1829 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
1830 {
1831 Found = TRUE;
1832 break;
1833 }
1834 }
1835
1836 if (!Found)
1837 {
1838 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
1839
1840 /* Tell the user-mode PnP manager that a device was removed */
1841 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
1842 &Child->InstancePath);
1843
1844 IopSendRemoveDevice(Child->PhysicalDeviceObject);
1845 }
1846
1847 Child = NextChild;
1848 }
1849 }
1850
1851 NTSTATUS
1852 IopEnumerateDevice(
1853 IN PDEVICE_OBJECT DeviceObject)
1854 {
1855 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
1856 DEVICETREE_TRAVERSE_CONTEXT Context;
1857 PDEVICE_RELATIONS DeviceRelations;
1858 PDEVICE_OBJECT ChildDeviceObject;
1859 IO_STATUS_BLOCK IoStatusBlock;
1860 PDEVICE_NODE ChildDeviceNode;
1861 IO_STACK_LOCATION Stack;
1862 NTSTATUS Status;
1863 ULONG i;
1864
1865 DPRINT("DeviceObject 0x%p\n", DeviceObject);
1866
1867 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
1868 {
1869 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
1870
1871 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
1872 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
1873 &DeviceNode->InstancePath);
1874 }
1875
1876 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1877
1878 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
1879
1880 Status = IopInitiatePnpIrp(
1881 DeviceObject,
1882 &IoStatusBlock,
1883 IRP_MN_QUERY_DEVICE_RELATIONS,
1884 &Stack);
1885 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
1886 {
1887 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
1888 return Status;
1889 }
1890
1891 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1892
1893 /*
1894 * Send removal IRPs for devices that have disappeared
1895 * NOTE: This code handles the case where no relations are specified
1896 */
1897 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
1898
1899 /* Now we bail if nothing was returned */
1900 if (!DeviceRelations)
1901 {
1902 /* We're all done */
1903 DPRINT("No PDOs\n");
1904 return STATUS_SUCCESS;
1905 }
1906
1907 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
1908
1909 /*
1910 * Create device nodes for all discovered devices
1911 */
1912 for (i = 0; i < DeviceRelations->Count; i++)
1913 {
1914 ChildDeviceObject = DeviceRelations->Objects[i];
1915 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
1916
1917 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
1918 if (!ChildDeviceNode)
1919 {
1920 /* One doesn't exist, create it */
1921 Status = IopCreateDeviceNode(
1922 DeviceNode,
1923 ChildDeviceObject,
1924 NULL,
1925 &ChildDeviceNode);
1926 if (NT_SUCCESS(Status))
1927 {
1928 /* Mark the node as enumerated */
1929 ChildDeviceNode->Flags |= DNF_ENUMERATED;
1930
1931 /* Mark the DO as bus enumerated */
1932 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
1933 }
1934 else
1935 {
1936 /* Ignore this DO */
1937 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
1938 ObDereferenceObject(ChildDeviceObject);
1939 }
1940 }
1941 else
1942 {
1943 /* Mark it as enumerated */
1944 ChildDeviceNode->Flags |= DNF_ENUMERATED;
1945 ObDereferenceObject(ChildDeviceObject);
1946 }
1947 }
1948 ExFreePool(DeviceRelations);
1949
1950 /*
1951 * Retrieve information about all discovered children from the bus driver
1952 */
1953 IopInitDeviceTreeTraverseContext(
1954 &Context,
1955 DeviceNode,
1956 IopActionInterrogateDeviceStack,
1957 DeviceNode);
1958
1959 Status = IopTraverseDeviceTree(&Context);
1960 if (!NT_SUCCESS(Status))
1961 {
1962 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
1963 return Status;
1964 }
1965
1966 /*
1967 * Retrieve configuration from the registry for discovered children
1968 */
1969 IopInitDeviceTreeTraverseContext(
1970 &Context,
1971 DeviceNode,
1972 IopActionConfigureChildServices,
1973 DeviceNode);
1974
1975 Status = IopTraverseDeviceTree(&Context);
1976 if (!NT_SUCCESS(Status))
1977 {
1978 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
1979 return Status;
1980 }
1981
1982 /*
1983 * Initialize services for discovered children.
1984 */
1985 Status = IopInitializePnpServices(DeviceNode);
1986 if (!NT_SUCCESS(Status))
1987 {
1988 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
1989 return Status;
1990 }
1991
1992 DPRINT("IopEnumerateDevice() finished\n");
1993 return STATUS_SUCCESS;
1994 }
1995
1996
1997 /*
1998 * IopActionConfigureChildServices
1999 *
2000 * Retrieve configuration for all (direct) child nodes of a parent node.
2001 *
2002 * Parameters
2003 * DeviceNode
2004 * Pointer to device node.
2005 * Context
2006 * Pointer to parent node to retrieve child node configuration for.
2007 *
2008 * Remarks
2009 * Any errors that occur are logged instead so that all child services have a chance of beeing
2010 * configured.
2011 */
2012
2013 NTSTATUS
2014 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2015 PVOID Context)
2016 {
2017 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2018 PDEVICE_NODE ParentDeviceNode;
2019 PUNICODE_STRING Service;
2020 UNICODE_STRING ClassGUID;
2021 NTSTATUS Status;
2022 DEVICE_CAPABILITIES DeviceCaps;
2023
2024 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2025
2026 ParentDeviceNode = (PDEVICE_NODE)Context;
2027
2028 /*
2029 * We are called for the parent too, but we don't need to do special
2030 * handling for this node
2031 */
2032 if (DeviceNode == ParentDeviceNode)
2033 {
2034 DPRINT("Success\n");
2035 return STATUS_SUCCESS;
2036 }
2037
2038 /*
2039 * Make sure this device node is a direct child of the parent device node
2040 * that is given as an argument
2041 */
2042
2043 if (DeviceNode->Parent != ParentDeviceNode)
2044 {
2045 DPRINT("Skipping 2+ level child\n");
2046 return STATUS_SUCCESS;
2047 }
2048
2049 if (!(DeviceNode->Flags & DNF_PROCESSED))
2050 {
2051 DPRINT1("Child not ready to be configured\n");
2052 return STATUS_SUCCESS;
2053 }
2054
2055 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2056 {
2057 WCHAR RegKeyBuffer[MAX_PATH];
2058 UNICODE_STRING RegKey;
2059
2060 RegKey.Length = 0;
2061 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2062 RegKey.Buffer = RegKeyBuffer;
2063
2064 /*
2065 * Retrieve configuration from Enum key
2066 */
2067
2068 Service = &DeviceNode->ServiceName;
2069
2070 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2071 RtlInitUnicodeString(Service, NULL);
2072 RtlInitUnicodeString(&ClassGUID, NULL);
2073
2074 QueryTable[0].Name = L"Service";
2075 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2076 QueryTable[0].EntryContext = Service;
2077
2078 QueryTable[1].Name = L"ClassGUID";
2079 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2080 QueryTable[1].EntryContext = &ClassGUID;
2081 QueryTable[1].DefaultType = REG_SZ;
2082 QueryTable[1].DefaultData = L"";
2083 QueryTable[1].DefaultLength = 0;
2084
2085 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2086 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2087
2088 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2089 RegKey.Buffer, QueryTable, NULL, NULL);
2090
2091 if (!NT_SUCCESS(Status))
2092 {
2093 /* FIXME: Log the error */
2094 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2095 &DeviceNode->InstancePath, Status);
2096 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2097 return STATUS_SUCCESS;
2098 }
2099
2100 if (Service->Buffer == NULL)
2101 {
2102 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2103 DeviceCaps.RawDeviceOK)
2104 {
2105 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2106
2107 DeviceNode->ServiceName.Length = 0;
2108 DeviceNode->ServiceName.MaximumLength = 0;
2109 DeviceNode->ServiceName.Buffer = NULL;
2110 }
2111 else if (ClassGUID.Length != 0)
2112 {
2113 /* Device has a ClassGUID value, but no Service value.
2114 * Suppose it is using the NULL driver, so state the
2115 * device is started */
2116 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2117 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2118 }
2119 else
2120 {
2121 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2122 }
2123 return STATUS_SUCCESS;
2124 }
2125
2126 DPRINT("Got Service %S\n", Service->Buffer);
2127 }
2128
2129 return STATUS_SUCCESS;
2130 }
2131
2132 /*
2133 * IopActionInitChildServices
2134 *
2135 * Initialize the service for all (direct) child nodes of a parent node
2136 *
2137 * Parameters
2138 * DeviceNode
2139 * Pointer to device node.
2140 * Context
2141 * Pointer to parent node to initialize child node services for.
2142 *
2143 * Remarks
2144 * If the driver image for a service is not loaded and initialized
2145 * it is done here too. Any errors that occur are logged instead so
2146 * that all child services have a chance of being initialized.
2147 */
2148
2149 NTSTATUS
2150 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2151 PVOID Context)
2152 {
2153 PDEVICE_NODE ParentDeviceNode;
2154 NTSTATUS Status;
2155 BOOLEAN BootDrivers = !PnpSystemInit;
2156
2157 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2158
2159 ParentDeviceNode = (PDEVICE_NODE)Context;
2160
2161 /*
2162 * We are called for the parent too, but we don't need to do special
2163 * handling for this node
2164 */
2165 if (DeviceNode == ParentDeviceNode)
2166 {
2167 DPRINT("Success\n");
2168 return STATUS_SUCCESS;
2169 }
2170
2171 /*
2172 * Make sure this device node is a direct child of the parent device node
2173 * that is given as an argument
2174 */
2175
2176 if (DeviceNode->Parent != ParentDeviceNode)
2177 {
2178 DPRINT("Skipping 2+ level child\n");
2179 return STATUS_SUCCESS;
2180 }
2181
2182 if (!(DeviceNode->Flags & DNF_PROCESSED))
2183 {
2184 DPRINT1("Child not ready to be added\n");
2185 return STATUS_SUCCESS;
2186 }
2187
2188 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2189 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2190 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2191 return STATUS_SUCCESS;
2192
2193 if (DeviceNode->ServiceName.Buffer == NULL)
2194 {
2195 /* We don't need to worry about loading the driver because we're
2196 * being driven in raw mode so our parent must be loaded to get here */
2197 Status = IopInitializeDevice(DeviceNode, NULL);
2198 if (NT_SUCCESS(Status))
2199 {
2200 Status = IopStartDevice(DeviceNode);
2201 if (!NT_SUCCESS(Status))
2202 {
2203 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2204 &DeviceNode->InstancePath, Status);
2205 }
2206 }
2207 }
2208 else
2209 {
2210 PLDR_DATA_TABLE_ENTRY ModuleObject;
2211 PDRIVER_OBJECT DriverObject;
2212
2213 /* Get existing DriverObject pointer (in case the driver has
2214 already been loaded and initialized) */
2215 Status = IopGetDriverObject(
2216 &DriverObject,
2217 &DeviceNode->ServiceName,
2218 FALSE);
2219
2220 if (!NT_SUCCESS(Status))
2221 {
2222 /* Driver is not initialized, try to load it */
2223 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2224
2225 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2226 {
2227 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2228 was loaded by the bootloader */
2229 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
2230 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
2231 {
2232 /* Initialize the driver */
2233 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2234 &DeviceNode->ServiceName, FALSE, &DriverObject);
2235 }
2236 else
2237 {
2238 Status = STATUS_SUCCESS;
2239 }
2240 }
2241 else
2242 {
2243 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2244 &DeviceNode->ServiceName, Status);
2245 }
2246 }
2247
2248 /* Driver is loaded and initialized at this point */
2249 if (NT_SUCCESS(Status))
2250 {
2251 /* Initialize the device, including all filters */
2252 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2253 }
2254 else
2255 {
2256 /*
2257 * Don't disable when trying to load only boot drivers
2258 */
2259 if (!BootDrivers)
2260 {
2261 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2262 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2263 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2264 DPRINT1("Initialization of service %S failed (Status %x)\n",
2265 DeviceNode->ServiceName.Buffer, Status);
2266 }
2267 }
2268 }
2269
2270 return STATUS_SUCCESS;
2271 }
2272
2273 /*
2274 * IopInitializePnpServices
2275 *
2276 * Initialize services for discovered children
2277 *
2278 * Parameters
2279 * DeviceNode
2280 * Top device node to start initializing services.
2281 *
2282 * Return Value
2283 * Status
2284 */
2285 NTSTATUS
2286 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2287 {
2288 DEVICETREE_TRAVERSE_CONTEXT Context;
2289
2290 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2291
2292 IopInitDeviceTreeTraverseContext(
2293 &Context,
2294 DeviceNode,
2295 IopActionInitChildServices,
2296 DeviceNode);
2297
2298 return IopTraverseDeviceTree(&Context);
2299 }
2300
2301 static NTSTATUS INIT_FUNCTION
2302 IopEnumerateDetectedDevices(
2303 IN HANDLE hBaseKey,
2304 IN PUNICODE_STRING RelativePath OPTIONAL,
2305 IN HANDLE hRootKey,
2306 IN BOOLEAN EnumerateSubKeys,
2307 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2308 IN ULONG ParentBootResourcesLength)
2309 {
2310 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2311 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2312 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2313 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2314 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2315 OBJECT_ATTRIBUTES ObjectAttributes;
2316 HANDLE hDevicesKey = NULL;
2317 HANDLE hDeviceKey = NULL;
2318 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2319 UNICODE_STRING Level2NameU;
2320 WCHAR Level2Name[5];
2321 ULONG IndexDevice = 0;
2322 ULONG IndexSubKey;
2323 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2324 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2325 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2326 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2327 UNICODE_STRING DeviceName, ValueName;
2328 ULONG RequiredSize;
2329 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2330 ULONG BootResourcesLength;
2331 NTSTATUS Status;
2332
2333 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
2334 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
2335 static ULONG DeviceIndexPci = 0;
2336 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2337 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2338 static ULONG DeviceIndexSerial = 0;
2339 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2340 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2341 static ULONG DeviceIndexKeyboard = 0;
2342 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2343 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2344 static ULONG DeviceIndexMouse = 0;
2345 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2346 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2347 static ULONG DeviceIndexParallel = 0;
2348 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2349 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2350 static ULONG DeviceIndexFloppy = 0;
2351 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
2352 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
2353 static ULONG DeviceIndexIsa = 0;
2354 UNICODE_STRING HardwareIdKey;
2355 PUNICODE_STRING pHardwareId;
2356 ULONG DeviceIndex = 0;
2357 PUCHAR CmResourceList;
2358 ULONG ListCount;
2359
2360 if (RelativePath)
2361 {
2362 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2363 if (!NT_SUCCESS(Status))
2364 {
2365 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2366 goto cleanup;
2367 }
2368 }
2369 else
2370 hDevicesKey = hBaseKey;
2371
2372 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2373 if (!pDeviceInformation)
2374 {
2375 DPRINT("ExAllocatePool() failed\n");
2376 Status = STATUS_NO_MEMORY;
2377 goto cleanup;
2378 }
2379
2380 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2381 if (!pValueInformation)
2382 {
2383 DPRINT("ExAllocatePool() failed\n");
2384 Status = STATUS_NO_MEMORY;
2385 goto cleanup;
2386 }
2387
2388 while (TRUE)
2389 {
2390 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2391 if (Status == STATUS_NO_MORE_ENTRIES)
2392 break;
2393 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2394 {
2395 ExFreePool(pDeviceInformation);
2396 DeviceInfoLength = RequiredSize;
2397 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2398 if (!pDeviceInformation)
2399 {
2400 DPRINT("ExAllocatePool() failed\n");
2401 Status = STATUS_NO_MEMORY;
2402 goto cleanup;
2403 }
2404 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2405 }
2406 if (!NT_SUCCESS(Status))
2407 {
2408 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2409 goto cleanup;
2410 }
2411 IndexDevice++;
2412
2413 /* Open device key */
2414 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2415 DeviceName.Buffer = pDeviceInformation->Name;
2416
2417 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
2418 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
2419 if (!NT_SUCCESS(Status))
2420 {
2421 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2422 goto cleanup;
2423 }
2424
2425 /* Read boot resources, and add then to parent ones */
2426 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2427 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2428 {
2429 ExFreePool(pValueInformation);
2430 ValueInfoLength = RequiredSize;
2431 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2432 if (!pValueInformation)
2433 {
2434 DPRINT("ExAllocatePool() failed\n");
2435 ZwDeleteKey(hLevel2Key);
2436 Status = STATUS_NO_MEMORY;
2437 goto cleanup;
2438 }
2439 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2440 }
2441 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2442 {
2443 BootResources = ParentBootResources;
2444 BootResourcesLength = ParentBootResourcesLength;
2445 }
2446 else if (!NT_SUCCESS(Status))
2447 {
2448 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2449 goto nextdevice;
2450 }
2451 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2452 {
2453 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2454 goto nextdevice;
2455 }
2456 else
2457 {
2458 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2459
2460 /* Concatenate current resources and parent ones */
2461 if (ParentBootResourcesLength == 0)
2462 BootResourcesLength = pValueInformation->DataLength;
2463 else
2464 BootResourcesLength = ParentBootResourcesLength
2465 + pValueInformation->DataLength
2466 - Header;
2467 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2468 if (!BootResources)
2469 {
2470 DPRINT("ExAllocatePool() failed\n");
2471 goto nextdevice;
2472 }
2473 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2474 {
2475 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2476 }
2477 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2478 {
2479 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2480 RtlCopyMemory(
2481 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2482 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2483 ParentBootResourcesLength - Header);
2484 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2485 }
2486 else
2487 {
2488 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2489 RtlCopyMemory(
2490 (PVOID)((ULONG_PTR)BootResources + Header),
2491 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2492 ParentBootResourcesLength - Header);
2493 RtlCopyMemory(
2494 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2495 pValueInformation->Data + Header,
2496 pValueInformation->DataLength - Header);
2497 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2498 }
2499 }
2500
2501 if (EnumerateSubKeys)
2502 {
2503 IndexSubKey = 0;
2504 while (TRUE)
2505 {
2506 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2507 if (Status == STATUS_NO_MORE_ENTRIES)
2508 break;
2509 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2510 {
2511 ExFreePool(pDeviceInformation);
2512 DeviceInfoLength = RequiredSize;
2513 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2514 if (!pDeviceInformation)
2515 {
2516 DPRINT("ExAllocatePool() failed\n");
2517 Status = STATUS_NO_MEMORY;
2518 goto cleanup;
2519 }
2520 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2521 }
2522 if (!NT_SUCCESS(Status))
2523 {
2524 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2525 goto cleanup;
2526 }
2527 IndexSubKey++;
2528 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2529 DeviceName.Buffer = pDeviceInformation->Name;
2530
2531 Status = IopEnumerateDetectedDevices(
2532 hDeviceKey,
2533 &DeviceName,
2534 hRootKey,
2535 TRUE,
2536 BootResources,
2537 BootResourcesLength);
2538 if (!NT_SUCCESS(Status))
2539 goto cleanup;
2540 }
2541 }
2542
2543 /* Read identifier */
2544 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2545 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2546 {
2547 ExFreePool(pValueInformation);
2548 ValueInfoLength = RequiredSize;
2549 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2550 if (!pValueInformation)
2551 {
2552 DPRINT("ExAllocatePool() failed\n");
2553 Status = STATUS_NO_MEMORY;
2554 goto cleanup;
2555 }
2556 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2557 }
2558 if (!NT_SUCCESS(Status))
2559 {
2560 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2561 {
2562 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2563 goto nextdevice;
2564 }
2565 ValueName.Length = ValueName.MaximumLength = 0;
2566 }
2567 else if (pValueInformation->Type != REG_SZ)
2568 {
2569 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2570 goto nextdevice;
2571 }
2572 else
2573 {
2574 /* Assign hardware id to this device */
2575 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
2576 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2577 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2578 ValueName.Length -= sizeof(WCHAR);
2579 }
2580
2581 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
2582 {
2583 pHardwareId = &HardwareIdSerial;
2584 DeviceIndex = DeviceIndexSerial++;
2585 }
2586 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
2587 {
2588 pHardwareId = &HardwareIdKeyboard;
2589 DeviceIndex = DeviceIndexKeyboard++;
2590 }
2591 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
2592 {
2593 pHardwareId = &HardwareIdMouse;
2594 DeviceIndex = DeviceIndexMouse++;
2595 }
2596 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
2597 {
2598 pHardwareId = &HardwareIdParallel;
2599 DeviceIndex = DeviceIndexParallel++;
2600 }
2601 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
2602 {
2603 pHardwareId = &HardwareIdFloppy;
2604 DeviceIndex = DeviceIndexFloppy++;
2605 }
2606 else if (NT_SUCCESS(Status))
2607 {
2608 /* Try to also match the device identifier */
2609 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
2610 {
2611 pHardwareId = &HardwareIdPci;
2612 DeviceIndex = DeviceIndexPci++;
2613 }
2614 else if (RtlCompareUnicodeString(&ValueName, &IdentifierIsa, FALSE) == 0)
2615 {
2616 pHardwareId = &HardwareIdIsa;
2617 DeviceIndex = DeviceIndexIsa++;
2618 }
2619 else
2620 {
2621 DPRINT("Unknown device '%wZ'\n", &ValueName);
2622 goto nextdevice;
2623 }
2624 }
2625 else
2626 {
2627 /* Unknown key path */
2628 DPRINT("Unknown key path '%wZ'\n", RelativePath);
2629 goto nextdevice;
2630 }
2631
2632 /* Prepare hardware id key (hardware id value without final \0) */
2633 HardwareIdKey = *pHardwareId;
2634 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
2635
2636 /* Add the detected device to Root key */
2637 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
2638 Status = ZwCreateKey(
2639 &hLevel1Key,
2640 KEY_CREATE_SUB_KEY,
2641 &ObjectAttributes,
2642 0,
2643 NULL,
2644 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
2645 NULL);
2646 if (!NT_SUCCESS(Status))
2647 {
2648 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2649 goto nextdevice;
2650 }
2651 swprintf(Level2Name, L"%04lu", DeviceIndex);
2652 RtlInitUnicodeString(&Level2NameU, Level2Name);
2653 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
2654 Status = ZwCreateKey(
2655 &hLevel2Key,
2656 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
2657 &ObjectAttributes,
2658 0,
2659 NULL,
2660 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
2661 NULL);
2662 ZwClose(hLevel1Key);
2663 if (!NT_SUCCESS(Status))
2664 {
2665 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2666 goto nextdevice;
2667 }
2668 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
2669 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
2670 if (!NT_SUCCESS(Status))
2671 {
2672 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2673 ZwDeleteKey(hLevel2Key);
2674 goto nextdevice;
2675 }
2676 /* Create 'LogConf' subkey */
2677 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
2678 Status = ZwCreateKey(
2679 &hLogConf,
2680 KEY_SET_VALUE,
2681 &ObjectAttributes,
2682 0,
2683 NULL,
2684 REG_OPTION_VOLATILE,
2685 NULL);
2686 if (!NT_SUCCESS(Status))
2687 {
2688 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2689 ZwDeleteKey(hLevel2Key);
2690 goto nextdevice;
2691 }
2692 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2693 {
2694 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
2695 if (!CmResourceList)
2696 {
2697 ZwClose(hLogConf);
2698 ZwDeleteKey(hLevel2Key);
2699 goto nextdevice;
2700 }
2701
2702 /* Add the list count (1st member of CM_RESOURCE_LIST) */
2703 ListCount = 1;
2704 RtlCopyMemory(CmResourceList,
2705 &ListCount,
2706 sizeof(ULONG));
2707
2708 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
2709 RtlCopyMemory(CmResourceList + sizeof(ULONG),
2710 BootResources,
2711 BootResourcesLength);
2712
2713 /* Save boot resources to 'LogConf\BootConfig' */
2714 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
2715 if (!NT_SUCCESS(Status))
2716 {
2717 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2718 ZwClose(hLogConf);
2719 ZwDeleteKey(hLevel2Key);
2720 goto nextdevice;
2721 }
2722 }
2723 ZwClose(hLogConf);
2724
2725 nextdevice:
2726 if (BootResources && BootResources != ParentBootResources)
2727 {
2728 ExFreePool(BootResources);
2729 BootResources = NULL;
2730 }
2731 if (hLevel2Key)
2732 {
2733 ZwClose(hLevel2Key);
2734 hLevel2Key = NULL;
2735 }
2736 if (hDeviceKey)
2737 {
2738 ZwClose(hDeviceKey);
2739 hDeviceKey = NULL;
2740 }
2741 }
2742
2743 Status = STATUS_SUCCESS;
2744
2745 cleanup:
2746 if (hDevicesKey && hDevicesKey != hBaseKey)
2747 ZwClose(hDevicesKey);
2748 if (hDeviceKey)
2749 ZwClose(hDeviceKey);
2750 if (pDeviceInformation)
2751 ExFreePool(pDeviceInformation);
2752 if (pValueInformation)
2753 ExFreePool(pValueInformation);
2754 return Status;
2755 }
2756
2757 static BOOLEAN INIT_FUNCTION
2758 IopIsFirmwareMapperDisabled(VOID)
2759 {
2760 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
2761 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
2762 OBJECT_ATTRIBUTES ObjectAttributes;
2763 HANDLE hPnpKey;
2764 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
2765 ULONG DesiredLength, Length;
2766 ULONG KeyValue = 0;
2767 NTSTATUS Status;
2768
2769 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2770 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
2771 if (NT_SUCCESS(Status))
2772 {
2773 Status = ZwQueryValueKey(hPnpKey,
2774 &KeyNameU,
2775 KeyValuePartialInformation,
2776 NULL,
2777 0,
2778 &DesiredLength);
2779 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
2780 (Status == STATUS_BUFFER_OVERFLOW))
2781 {
2782 Length = DesiredLength;
2783 KeyInformation = ExAllocatePool(PagedPool, Length);
2784 if (KeyInformation)
2785 {
2786 Status = ZwQueryValueKey(hPnpKey,
2787 &KeyNameU,
2788 KeyValuePartialInformation,
2789 KeyInformation,
2790 Length,
2791 &DesiredLength);
2792 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
2793 {
2794 KeyValue = (ULONG)(*KeyInformation->Data);
2795 }
2796 else
2797 {
2798 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
2799 }
2800
2801 ExFreePool(KeyInformation);
2802 }
2803 else
2804 {
2805 DPRINT1("Failed to allocate memory for registry query\n");
2806 }
2807 }
2808 else
2809 {
2810 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
2811 }
2812
2813 ZwClose(hPnpKey);
2814 }
2815 else
2816 {
2817 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
2818 }
2819
2820 DPRINT1("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
2821
2822 return (KeyValue != 0) ? TRUE : FALSE;
2823 }
2824
2825 NTSTATUS
2826 NTAPI
2827 INIT_FUNCTION
2828 IopUpdateRootKey(VOID)
2829 {
2830 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
2831 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
2832 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
2833 OBJECT_ATTRIBUTES ObjectAttributes;
2834 HANDLE hEnum, hRoot;
2835 NTSTATUS Status;
2836
2837 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2838 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2839 if (!NT_SUCCESS(Status))
2840 {
2841 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
2842 return Status;
2843 }
2844
2845 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
2846 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
2847 ZwClose(hEnum);
2848 if (!NT_SUCCESS(Status))
2849 {
2850 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
2851 return Status;
2852 }
2853
2854 if (!IopIsFirmwareMapperDisabled())
2855 {
2856 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
2857 if (!NT_SUCCESS(Status))
2858 {
2859 /* Nothing to do, don't return with an error status */
2860 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2861 ZwClose(hRoot);
2862 return STATUS_SUCCESS;
2863 }
2864 Status = IopEnumerateDetectedDevices(
2865 hEnum,
2866 NULL,
2867 hRoot,
2868 TRUE,
2869 NULL,
2870 0);
2871 ZwClose(hEnum);
2872 }
2873 else
2874 {
2875 /* Enumeration is disabled */
2876 Status = STATUS_SUCCESS;
2877 }
2878
2879 ZwClose(hRoot);
2880
2881 return Status;
2882 }
2883
2884 NTSTATUS
2885 NTAPI
2886 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
2887 HANDLE ParentKey,
2888 PUNICODE_STRING Name,
2889 ACCESS_MASK DesiredAccess)
2890 {
2891 OBJECT_ATTRIBUTES ObjectAttributes;
2892 NTSTATUS Status;
2893
2894 PAGED_CODE();
2895
2896 *KeyHandle = NULL;
2897
2898 InitializeObjectAttributes(&ObjectAttributes,
2899 Name,
2900 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2901 ParentKey,
2902 NULL);
2903
2904 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
2905
2906 return Status;
2907 }
2908
2909 NTSTATUS
2910 NTAPI
2911 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
2912 IN HANDLE RootHandle OPTIONAL,
2913 IN PUNICODE_STRING KeyName,
2914 IN ACCESS_MASK DesiredAccess,
2915 IN ULONG CreateOptions,
2916 OUT PULONG Disposition OPTIONAL)
2917 {
2918 OBJECT_ATTRIBUTES ObjectAttributes;
2919 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
2920 USHORT Length;
2921 HANDLE HandleArray[2];
2922 BOOLEAN Recursing = TRUE;
2923 PWCHAR pp, p, p1;
2924 UNICODE_STRING KeyString;
2925 NTSTATUS Status = STATUS_SUCCESS;
2926 PAGED_CODE();
2927
2928 /* P1 is start, pp is end */
2929 p1 = KeyName->Buffer;
2930 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
2931
2932 /* Create the target key */
2933 InitializeObjectAttributes(&ObjectAttributes,
2934 KeyName,
2935 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2936 RootHandle,
2937 NULL);
2938 Status = ZwCreateKey(&HandleArray[i],
2939 DesiredAccess,
2940 &ObjectAttributes,
2941 0,
2942 NULL,
2943 CreateOptions,
2944 &KeyDisposition);
2945
2946 /* Now we check if this failed */
2947 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
2948 {
2949 /* Target key failed, so we'll need to create its parent. Setup array */
2950 HandleArray[0] = NULL;
2951 HandleArray[1] = RootHandle;
2952
2953 /* Keep recursing for each missing parent */
2954 while (Recursing)
2955 {
2956 /* And if we're deep enough, close the last handle */
2957 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
2958
2959 /* We're setup to ping-pong between the two handle array entries */
2960 RootHandleIndex = i;
2961 i = (i + 1) & 1;
2962
2963 /* Clear the one we're attempting to open now */
2964 HandleArray[i] = NULL;
2965
2966 /* Process the parent key name */
2967 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
2968 Length = (USHORT)(p - p1) * sizeof(WCHAR);
2969
2970 /* Is there a parent name? */
2971 if (Length)
2972 {
2973 /* Build the unicode string for it */
2974 KeyString.Buffer = p1;
2975 KeyString.Length = KeyString.MaximumLength = Length;
2976
2977 /* Now try opening the parent */
2978 InitializeObjectAttributes(&ObjectAttributes,
2979 &KeyString,
2980 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2981 HandleArray[RootHandleIndex],
2982 NULL);
2983 Status = ZwCreateKey(&HandleArray[i],
2984 DesiredAccess,
2985 &ObjectAttributes,
2986 0,
2987 NULL,
2988 CreateOptions,
2989 &KeyDisposition);
2990 if (NT_SUCCESS(Status))
2991 {
2992 /* It worked, we have one more handle */
2993 NestedCloseLevel++;
2994 }
2995 else
2996 {
2997 /* Parent key creation failed, abandon loop */
2998 Recursing = FALSE;
2999 continue;
3000 }
3001 }
3002 else
3003 {
3004 /* We don't have a parent name, probably corrupted key name */
3005 Status = STATUS_INVALID_PARAMETER;
3006 Recursing = FALSE;
3007 continue;
3008 }
3009
3010 /* Now see if there's more parents to create */
3011 p1 = p + 1;
3012 if ((p == pp) || (p1 == pp))
3013 {
3014 /* We're done, hopefully successfully, so stop */
3015 Recursing = FALSE;
3016 }
3017 }
3018
3019 /* Outer loop check for handle nesting that requires closing the top handle */
3020 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3021 }
3022
3023 /* Check if we broke out of the loop due to success */
3024 if (NT_SUCCESS(Status))
3025 {
3026 /* Return the target handle (we closed all the parent ones) and disposition */
3027 *Handle = HandleArray[i];
3028 if (Disposition) *Disposition = KeyDisposition;
3029 }
3030
3031 /* Return the success state */
3032 return Status;
3033 }
3034
3035 NTSTATUS
3036 NTAPI
3037 IopGetRegistryValue(IN HANDLE Handle,
3038 IN PWSTR ValueName,
3039 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3040 {
3041 UNICODE_STRING ValueString;
3042 NTSTATUS Status;
3043 PKEY_VALUE_FULL_INFORMATION FullInformation;
3044 ULONG Size;
3045 PAGED_CODE();
3046
3047 RtlInitUnicodeString(&ValueString, ValueName);
3048
3049 Status = ZwQueryValueKey(Handle,
3050 &ValueString,
3051 KeyValueFullInformation,
3052 NULL,
3053 0,
3054 &Size);
3055 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3056 (Status != STATUS_BUFFER_TOO_SMALL))
3057 {
3058 return Status;
3059 }
3060
3061 FullInformation = ExAllocatePool(NonPagedPool, Size);
3062 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3063
3064 Status = ZwQueryValueKey(Handle,
3065 &ValueString,
3066 KeyValueFullInformation,
3067 FullInformation,
3068 Size,
3069 &Size);
3070 if (!NT_SUCCESS(Status))
3071 {
3072 ExFreePool(FullInformation);
3073 return Status;
3074 }
3075
3076 *Information = FullInformation;
3077 return STATUS_SUCCESS;
3078 }
3079
3080 RTL_GENERIC_COMPARE_RESULTS
3081 NTAPI
3082 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3083 IN PVOID FirstStruct,
3084 IN PVOID SecondStruct)
3085 {
3086 /* FIXME: TODO */
3087 ASSERT(FALSE);
3088 return 0;
3089 }
3090
3091 //
3092 // The allocation function is called by the generic table package whenever
3093 // it needs to allocate memory for the table.
3094 //
3095
3096 PVOID
3097 NTAPI
3098 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3099 IN CLONG ByteSize)
3100 {
3101 /* FIXME: TODO */
3102 ASSERT(FALSE);
3103 return NULL;
3104 }
3105
3106 VOID
3107 NTAPI
3108 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3109 IN PVOID Buffer)
3110 {
3111 /* FIXME: TODO */
3112 ASSERT(FALSE);
3113 }
3114
3115 VOID
3116 NTAPI
3117 PpInitializeDeviceReferenceTable(VOID)
3118 {
3119 /* Setup the guarded mutex and AVL table */
3120 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3121 RtlInitializeGenericTableAvl(
3122 &PpDeviceReferenceTable,
3123 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3124 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3125 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3126 NULL);
3127 }
3128
3129 BOOLEAN
3130 NTAPI
3131 PiInitPhase0(VOID)
3132 {
3133 /* Initialize the resource when accessing device registry data */
3134 ExInitializeResourceLite(&PpRegistryDeviceResource);
3135
3136 /* Setup the device reference AVL table */
3137 PpInitializeDeviceReferenceTable();
3138 return TRUE;
3139 }
3140
3141 BOOLEAN
3142 NTAPI
3143 PpInitSystem(VOID)
3144 {
3145 /* Check the initialization phase */
3146 switch (ExpInitializationPhase)
3147 {
3148 case 0:
3149
3150 /* Do Phase 0 */
3151 return PiInitPhase0();
3152
3153 case 1:
3154
3155 /* Do Phase 1 */
3156 return TRUE;
3157 //return PiInitPhase1();
3158
3159 default:
3160
3161 /* Don't know any other phase! Bugcheck! */
3162 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3163 return FALSE;
3164 }
3165 }
3166
3167 LONG IopNumberDeviceNodes;
3168
3169 PDEVICE_NODE
3170 NTAPI
3171 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
3172 {
3173 PDEVICE_NODE DeviceNode;
3174 PAGED_CODE();
3175
3176 /* Allocate it */
3177 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), 'donD');
3178 if (!DeviceNode) return DeviceNode;
3179
3180 /* Statistics */
3181 InterlockedIncrement(&IopNumberDeviceNodes);
3182
3183 /* Set it up */
3184 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3185 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3186 DeviceNode->BusNumber = -1;
3187 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3188 DeviceNode->ChildBusNumber = -1;
3189 DeviceNode->ChildBusTypeIndex = -1;
3190 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3191 InitializeListHead(&DeviceNode->DeviceArbiterList);
3192 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3193 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3194 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3195 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3196
3197 /* Check if there is a PDO */
3198 if (PhysicalDeviceObject)
3199 {
3200 /* Link it and remove the init flag */
3201 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3202 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3203 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3204 }
3205
3206 /* Return the node */
3207 return DeviceNode;
3208 }
3209
3210 /* PUBLIC FUNCTIONS **********************************************************/
3211
3212 NTSTATUS
3213 NTAPI
3214 PnpBusTypeGuidGet(IN USHORT Index,
3215 IN LPGUID BusTypeGuid)
3216 {
3217 NTSTATUS Status = STATUS_SUCCESS;
3218
3219 /* Acquire the lock */
3220 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3221
3222 /* Validate size */
3223 if (Index < PnpBusTypeGuidList->GuidCount)
3224 {
3225 /* Copy the data */
3226 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3227 }
3228 else
3229 {
3230 /* Failure path */
3231 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3232 }
3233
3234 /* Release lock and return status */
3235 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3236 return Status;
3237 }
3238
3239 NTSTATUS
3240 NTAPI
3241 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3242 IN PHANDLE DeviceInstanceHandle,
3243 IN ACCESS_MASK DesiredAccess)
3244 {
3245 NTSTATUS Status;
3246 HANDLE KeyHandle;
3247 PDEVICE_NODE DeviceNode;
3248 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3249 PAGED_CODE();
3250
3251 /* Open the enum key */
3252 Status = IopOpenRegistryKeyEx(&KeyHandle,
3253 NULL,
3254 &KeyName,
3255 KEY_READ);
3256 if (!NT_SUCCESS(Status)) return Status;
3257
3258 /* Make sure we have an instance path */
3259 DeviceNode = IopGetDeviceNode(DeviceObject);
3260 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3261 {
3262 /* Get the instance key */
3263 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3264 KeyHandle,
3265 &DeviceNode->InstancePath,
3266 DesiredAccess);
3267 }
3268 else
3269 {
3270 /* Fail */
3271 Status = STATUS_INVALID_DEVICE_REQUEST;
3272 }
3273
3274 /* Close the handle and return status */
3275 ZwClose(KeyHandle);
3276 return Status;
3277 }
3278
3279 ULONG
3280 NTAPI
3281 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3282 {
3283 ULONG FinalSize, PartialSize, EntrySize, i, j;
3284 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3285 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3286
3287 /* If we don't have one, that's easy */
3288 if (!ResourceList) return 0;
3289
3290 /* Start with the minimum size possible */
3291 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3292
3293 /* Loop each full descriptor */
3294 FullDescriptor = ResourceList->List;
3295 for (i = 0; i < ResourceList->Count; i++)
3296 {
3297 /* Start with the minimum size possible */
3298 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3299 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3300
3301 /* Loop each partial descriptor */
3302 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3303 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3304 {
3305 /* Start with the minimum size possible */
3306 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3307
3308 /* Check if there is extra data */
3309 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3310 {
3311 /* Add that data */
3312 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3313 }
3314
3315 /* The size of partial descriptors is bigger */
3316 PartialSize += EntrySize;
3317
3318 /* Go to the next partial descriptor */
3319 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3320 }
3321
3322 /* The size of full descriptors is bigger */
3323 FinalSize += PartialSize;
3324
3325 /* Go to the next full descriptor */
3326 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3327 }
3328
3329 /* Return the final size */
3330 return FinalSize;
3331 }
3332
3333 NTSTATUS
3334 NTAPI
3335 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3336 IN ULONG ValueType,
3337 IN PWSTR ValueName,
3338 IN PWSTR KeyName,
3339 OUT PVOID Buffer,
3340 IN PULONG BufferLength)
3341 {
3342 NTSTATUS Status;
3343 HANDLE KeyHandle, SubHandle;
3344 UNICODE_STRING KeyString;
3345 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3346 ULONG Length;
3347 PAGED_CODE();
3348
3349 /* Find the instance key */
3350 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3351 if (NT_SUCCESS(Status))
3352 {
3353 /* Check for name given by caller */
3354 if (KeyName)
3355 {
3356 /* Open this key */
3357 RtlInitUnicodeString(&KeyString, KeyName);
3358 Status = IopOpenRegistryKeyEx(&SubHandle,
3359 KeyHandle,
3360 &KeyString,
3361 KEY_READ);
3362 if (NT_SUCCESS(Status))
3363 {
3364 /* And use this handle instead */
3365 ZwClose(KeyHandle);
3366 KeyHandle = SubHandle;
3367 }
3368 }
3369
3370 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3371 if (NT_SUCCESS(Status))
3372 {
3373 /* Now get the size of the property */
3374 Status = IopGetRegistryValue(KeyHandle,
3375 ValueName,
3376 &KeyValueInfo);
3377 }
3378
3379 /* Close the key */
3380 ZwClose(KeyHandle);
3381 }
3382
3383 /* Fail if any of the registry operations failed */
3384 if (!NT_SUCCESS(Status)) return Status;
3385
3386 /* Check how much data we have to copy */
3387 Length = KeyValueInfo->DataLength;
3388 if (*BufferLength >= Length)
3389 {
3390 /* Check for a match in the value type */
3391 if (KeyValueInfo->Type == ValueType)
3392 {
3393 /* Copy the data */
3394 RtlCopyMemory(Buffer,
3395 (PVOID)((ULONG_PTR)KeyValueInfo +
3396 KeyValueInfo->DataOffset),
3397 Length);
3398 }
3399 else
3400 {
3401 /* Invalid registry property type, fail */
3402 Status = STATUS_INVALID_PARAMETER_2;
3403 }
3404 }
3405 else
3406 {
3407 /* Buffer is too small to hold data */
3408 Status = STATUS_BUFFER_TOO_SMALL;
3409 }
3410
3411 /* Return the required buffer length, free the buffer, and return status */
3412 *BufferLength = Length;
3413 ExFreePool(KeyValueInfo);
3414 return Status;
3415 }
3416
3417 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3418 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3419 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED; while(TRUE); break;}
3420
3421 /*
3422 * @implemented
3423 */
3424 NTSTATUS
3425 NTAPI
3426 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
3427 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
3428 IN ULONG BufferLength,
3429 OUT PVOID PropertyBuffer,
3430 OUT PULONG ResultLength)
3431 {
3432 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
3433 DEVICE_CAPABILITIES DeviceCaps;
3434 ULONG ReturnLength = 0, Length = 0, ValueType;
3435 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
3436 PVOID Data = NULL;
3437 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
3438 GUID BusTypeGuid;
3439 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
3440 BOOLEAN NullTerminate = FALSE;
3441
3442 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
3443
3444 /* Assume failure */
3445 *ResultLength = 0;
3446
3447 /* Only PDOs can call this */
3448 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
3449
3450 /* Handle all properties */
3451 switch (DeviceProperty)
3452 {
3453 case DevicePropertyBusTypeGuid:
3454
3455 /* Get the GUID from the internal cache */
3456 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
3457 if (!NT_SUCCESS(Status)) return Status;
3458
3459 /* This is the format of the returned data */
3460 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
3461
3462 case DevicePropertyLegacyBusType:
3463
3464 /* Validate correct interface type */
3465 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
3466 return STATUS_OBJECT_NAME_NOT_FOUND;
3467
3468 /* This is the format of the returned data */
3469 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
3470
3471 case DevicePropertyBusNumber:
3472
3473 /* Validate correct bus number */
3474 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
3475 return STATUS_OBJECT_NAME_NOT_FOUND;
3476
3477 /* This is the format of the returned data */
3478 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
3479
3480 case DevicePropertyEnumeratorName:
3481
3482 /* Get the instance path */
3483 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
3484
3485 /* Sanity checks */
3486 ASSERT((BufferLength & 1) == 0);
3487 ASSERT(DeviceInstanceName != NULL);
3488
3489 /* Get the name from the path */
3490 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
3491 ASSERT(EnumeratorNameEnd);
3492
3493 /* This string needs to be NULL-terminated */
3494 NullTerminate = TRUE;
3495
3496 /* This is the format of the returned data */
3497 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
3498 DeviceInstanceName);
3499
3500 case DevicePropertyAddress:
3501
3502 /* Query the device caps */
3503 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
3504 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
3505 return STATUS_OBJECT_NAME_NOT_FOUND;
3506
3507 /* This is the format of the returned data */
3508 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
3509
3510 case DevicePropertyBootConfigurationTranslated:
3511
3512 /* Validate we have resources */
3513 if (!DeviceNode->BootResources)
3514 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3515 {
3516 /* No resources will still fake success, but with 0 bytes */
3517 *ResultLength = 0;
3518 return STATUS_SUCCESS;
3519 }
3520
3521 /* This is the format of the returned data */
3522 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
3523 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
3524
3525 case DevicePropertyPhysicalDeviceObjectName:
3526
3527 /* Sanity check for Unicode-sized string */
3528 ASSERT((BufferLength & 1) == 0);
3529
3530 /* Allocate name buffer */
3531 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
3532 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
3533 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
3534
3535 /* Query the PDO name */
3536 Status = ObQueryNameString(DeviceObject,
3537 ObjectNameInfo,
3538 Length,
3539 ResultLength);
3540 if (Status == STATUS_INFO_LENGTH_MISMATCH)
3541 {
3542 /* It's up to the caller to try again */
3543 Status = STATUS_BUFFER_TOO_SMALL;
3544 }
3545
3546 /* This string needs to be NULL-terminated */
3547 NullTerminate = TRUE;
3548
3549 /* Return if successful */
3550 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
3551 ObjectNameInfo->Name.Buffer);
3552
3553 /* Let the caller know how big the name is */
3554 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
3555 break;
3556
3557 /* Handle the registry-based properties */
3558 case DevicePropertyUINumber:
3559 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
3560 case DevicePropertyLocationInformation:
3561 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
3562 case DevicePropertyDeviceDescription:
3563 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
3564 case DevicePropertyHardwareID:
3565 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
3566 case DevicePropertyCompatibleIDs:
3567 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
3568 case DevicePropertyBootConfiguration:
3569 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
3570 case DevicePropertyClassName:
3571 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
3572 case DevicePropertyClassGuid:
3573 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
3574 case DevicePropertyDriverKeyName:
3575 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
3576 case DevicePropertyManufacturer:
3577 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
3578 case DevicePropertyFriendlyName:
3579 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
3580 case DevicePropertyContainerID:
3581 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3582 PIP_UNIMPLEMENTED();
3583 case DevicePropertyRemovalPolicy:
3584 PIP_UNIMPLEMENTED();
3585 case DevicePropertyInstallState:
3586 PIP_UNIMPLEMENTED();
3587 case DevicePropertyResourceRequirements:
3588 PIP_UNIMPLEMENTED();
3589 case DevicePropertyAllocatedResources:
3590 PIP_UNIMPLEMENTED();
3591 default:
3592 return STATUS_INVALID_PARAMETER_2;
3593 }
3594
3595 /* Having a registry value name implies registry data */
3596 if (ValueName)
3597 {
3598 /* We know up-front how much data to expect */
3599 *ResultLength = BufferLength;
3600
3601 /* Go get the data, use the LogConf subkey if necessary */
3602 Status = PiGetDeviceRegistryProperty(DeviceObject,
3603 ValueType,
3604 ValueName,
3605 (DeviceProperty ==
3606 DevicePropertyBootConfiguration) ?
3607 L"LogConf": NULL,
3608 PropertyBuffer,
3609 ResultLength);
3610 }
3611 else if (NT_SUCCESS(Status))
3612 {
3613 /* We know up-front how much data to expect, check the caller's buffer */
3614 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
3615 if (*ResultLength <= BufferLength)
3616 {
3617 /* Buffer is all good, copy the data */
3618 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
3619
3620 /* Check if we need to NULL-terminate the string */
3621 if (NullTerminate)
3622 {
3623 /* Terminate the string */
3624 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
3625 }
3626
3627 /* This is the success path */
3628 Status = STATUS_SUCCESS;
3629 }
3630 else
3631 {
3632 /* Failure path */
3633 Status = STATUS_BUFFER_TOO_SMALL;
3634 }
3635 }
3636
3637 /* Free any allocation we may have made, and return the status code */
3638 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
3639 return Status;
3640 }
3641
3642 /*
3643 * @implemented
3644 */
3645 VOID
3646 NTAPI
3647 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
3648 {
3649 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
3650 IO_STACK_LOCATION Stack;
3651 ULONG PnPFlags;
3652 NTSTATUS Status;
3653 IO_STATUS_BLOCK IoStatusBlock;
3654
3655 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
3656 Stack.MajorFunction = IRP_MJ_PNP;
3657 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
3658
3659 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
3660 if (!NT_SUCCESS(Status))
3661 {
3662 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status);
3663 return;
3664 }
3665
3666 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
3667 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
3668 else
3669 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
3670
3671 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
3672 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
3673 else
3674 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
3675
3676 if ((PnPFlags & PNP_DEVICE_REMOVED) ||
3677 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
3678 {
3679 /* Surprise removal */
3680
3681 IopSendSurpriseRemoval(PhysicalDeviceObject);
3682
3683 /* Tell the user-mode PnP manager that a device was removed */
3684 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
3685 &DeviceNode->InstancePath);
3686
3687 IopSendRemoveDevice(PhysicalDeviceObject);
3688 }
3689 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
3690 {
3691 /* Stop for resource rebalance */
3692
3693 Status = IopStopDevice(DeviceNode);
3694 if (!NT_SUCCESS(Status))
3695 {
3696 DPRINT1("Failed to stop device for rebalancing\n");
3697
3698 /* Stop failed so don't rebalance */
3699 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED;
3700 }
3701 }
3702
3703 /* Resource rebalance */
3704 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
3705 {
3706 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
3707
3708 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
3709 &IoStatusBlock,
3710 IRP_MN_QUERY_RESOURCES,
3711 NULL);
3712 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
3713 {
3714 DeviceNode->BootResources =
3715 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
3716 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
3717 }
3718 else
3719 {
3720 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
3721 DeviceNode->BootResources = NULL;
3722 }
3723
3724 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
3725
3726 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
3727 &IoStatusBlock,
3728 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
3729 NULL);
3730 if (NT_SUCCESS(Status))
3731 {
3732 DeviceNode->ResourceRequirements =
3733 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
3734 }
3735 else
3736 {
3737 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
3738 DeviceNode->ResourceRequirements = NULL;
3739 }
3740
3741 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
3742 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS)
3743 {
3744 DPRINT1("Restart after resource rebalance failed\n");
3745
3746 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
3747 DeviceNode->Flags |= DNF_START_FAILED;
3748
3749 IopRemoveDevice(DeviceNode);
3750 }
3751 }
3752 }
3753
3754 /**
3755 * @name IoOpenDeviceRegistryKey
3756 *
3757 * Open a registry key unique for a specified driver or device instance.
3758 *
3759 * @param DeviceObject Device to get the registry key for.
3760 * @param DevInstKeyType Type of the key to return.
3761 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
3762 * @param DevInstRegKey Handle to the opened registry key on
3763 * successful return.
3764 *
3765 * @return Status.
3766 *
3767 * @implemented
3768 */
3769 NTSTATUS
3770 NTAPI
3771 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
3772 IN ULONG DevInstKeyType,
3773 IN ACCESS_MASK DesiredAccess,
3774 OUT PHANDLE DevInstRegKey)
3775 {
3776 static WCHAR RootKeyName[] =
3777 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
3778 static WCHAR ProfileKeyName[] =
3779 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
3780 static WCHAR ClassKeyName[] = L"Control\\Class\\";
3781 static WCHAR EnumKeyName[] = L"Enum\\";
3782 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
3783 ULONG KeyNameLength;
3784 LPWSTR KeyNameBuffer;
3785 UNICODE_STRING KeyName;
3786 ULONG DriverKeyLength;
3787 OBJECT_ATTRIBUTES ObjectAttributes;
3788 PDEVICE_NODE DeviceNode = NULL;
3789 NTSTATUS Status;
3790
3791 DPRINT("IoOpenDeviceRegistryKey() called\n");
3792
3793 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
3794 {
3795 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
3796 return STATUS_INVALID_PARAMETER;
3797 }
3798
3799 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
3800 return STATUS_INVALID_DEVICE_REQUEST;
3801 DeviceNode = IopGetDeviceNode(DeviceObject);
3802
3803 /*
3804 * Calculate the length of the base key name. This is the full
3805 * name for driver key or the name excluding "Device Parameters"
3806 * subkey for device key.
3807 */
3808
3809 KeyNameLength = sizeof(RootKeyName);
3810 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
3811 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
3812 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3813 {
3814 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
3815 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
3816 0, NULL, &DriverKeyLength);
3817 if (Status != STATUS_BUFFER_TOO_SMALL)
3818 return Status;
3819 KeyNameLength += DriverKeyLength;
3820 }
3821 else
3822 {
3823 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
3824 DeviceNode->InstancePath.Length;
3825 }
3826
3827 /*
3828 * Now allocate the buffer for the key name...
3829 */
3830
3831 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
3832 if (KeyNameBuffer == NULL)
3833 return STATUS_INSUFFICIENT_RESOURCES;
3834
3835 KeyName.Length = 0;
3836 KeyName.MaximumLength = (USHORT)KeyNameLength;
3837 KeyName.Buffer = KeyNameBuffer;
3838
3839 /*
3840 * ...and build the key name.
3841 */
3842
3843 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
3844 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
3845
3846 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
3847 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
3848
3849 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3850 {
3851 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
3852 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
3853 DriverKeyLength, KeyNameBuffer +
3854 (KeyName.Length / sizeof(WCHAR)),
3855 &DriverKeyLength);
3856 if (!NT_SUCCESS(Status))
3857 {
3858 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
3859 ExFreePool(KeyNameBuffer);
3860 return Status;
3861 }
3862 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
3863 }
3864 else
3865 {
3866 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
3867 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
3868 if (DeviceNode->InstancePath.Length == 0)
3869 {
3870 ExFreePool(KeyNameBuffer);
3871 return Status;
3872 }
3873 }
3874
3875 /*
3876 * Open the base key.
3877 */
3878 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
3879 if (!NT_SUCCESS(Status))
3880 {
3881 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
3882 ExFreePool(KeyNameBuffer);
3883 return Status;
3884 }
3885 ExFreePool(KeyNameBuffer);
3886
3887 /*
3888 * For driver key we're done now.
3889 */
3890
3891 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
3892 return Status;
3893
3894 /*
3895 * Let's go further. For device key we must open "Device Parameters"
3896 * subkey and create it if it doesn't exist yet.
3897 */
3898
3899 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
3900 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
3901 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
3902 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
3903 0, NULL, ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, NULL);
3904 ZwClose(ObjectAttributes.RootDirectory);
3905
3906 return Status;
3907 }
3908
3909 static
3910 NTSTATUS
3911 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
3912 {
3913 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
3914 NTSTATUS Status;
3915 KIRQL OldIrql;
3916
3917 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
3918 ChildDeviceNode = ParentDeviceNode->Child;
3919 while (ChildDeviceNode != NULL)
3920 {
3921 NextDeviceNode = ChildDeviceNode->Sibling;
3922 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
3923
3924 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
3925 if (!NT_SUCCESS(Status))
3926 {
3927 FailedRemoveDevice = ChildDeviceNode;
3928 goto cleanup;
3929 }
3930
3931 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
3932 ChildDeviceNode = NextDeviceNode;
3933 }
3934 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
3935
3936 return STATUS_SUCCESS;
3937
3938 cleanup:
3939 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
3940 ChildDeviceNode = ParentDeviceNode->Child;
3941 while (ChildDeviceNode != NULL)
3942 {
3943 NextDeviceNode = ChildDeviceNode->Sibling;
3944 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
3945
3946 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
3947
3948 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
3949 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
3950 if (ChildDeviceNode == FailedRemoveDevice)
3951 return Status;
3952
3953 ChildDeviceNode = NextDeviceNode;
3954
3955 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
3956 }
3957 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
3958
3959 return Status;
3960 }
3961
3962 static
3963 VOID
3964 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
3965 {
3966 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
3967 KIRQL OldIrql;
3968
3969 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
3970 ChildDeviceNode = ParentDeviceNode->Child;
3971 while (ChildDeviceNode != NULL)
3972 {
3973 NextDeviceNode = ChildDeviceNode->Sibling;
3974 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
3975
3976 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
3977
3978 ChildDeviceNode = NextDeviceNode;
3979
3980 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
3981 }
3982 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
3983 }
3984
3985 static
3986 VOID
3987 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
3988 {
3989 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
3990 KIRQL OldIrql;
3991
3992 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
3993 ChildDeviceNode = ParentDeviceNode->Child;
3994 while (ChildDeviceNode != NULL)
3995 {
3996 NextDeviceNode = ChildDeviceNode->Sibling;
3997 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
3998
3999 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4000
4001 ChildDeviceNode = NextDeviceNode;
4002
4003 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4004 }
4005 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4006 }
4007
4008 static
4009 NTSTATUS
4010 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4011 {
4012 /* This function DOES NOT dereference the device objects on SUCCESS
4013 * but it DOES dereference device objects on FAILURE */
4014
4015 ULONG i, j;
4016 NTSTATUS Status;
4017
4018 for (i = 0; i < DeviceRelations->Count; i++)
4019 {
4020 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4021 if (!NT_SUCCESS(Status))
4022 {
4023 j = i;
4024 goto cleanup;
4025 }
4026 }
4027
4028 return STATUS_SUCCESS;
4029
4030 cleanup:
4031 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4032 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4033 for (i = 0; i <= j; i++)
4034 {
4035 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4036 ObDereferenceObject(DeviceRelations->Objects[i]);
4037 DeviceRelations->Objects[i] = NULL;
4038 }
4039 for (; i < DeviceRelations->Count; i++)
4040 {
4041 ObDereferenceObject(DeviceRelations->Objects[i]);
4042 DeviceRelations->Objects[i] = NULL;
4043 }
4044 ExFreePool(DeviceRelations);
4045
4046 return Status;
4047 }
4048
4049 static
4050 VOID
4051 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4052 {
4053 /* This function DOES dereference the device objects in all cases */
4054
4055 ULONG i;
4056
4057 for (i = 0; i < DeviceRelations->Count; i++)
4058 {
4059 IopSendRemoveDevice(DeviceRelations->Objects[i]);
4060 ObDereferenceObject(DeviceRelations->Objects[i]);
4061 DeviceRelations->Objects[i] = NULL;
4062 }
4063
4064 ExFreePool(DeviceRelations);
4065 }
4066
4067 static
4068 VOID
4069 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4070 {
4071 /* This function DOES dereference the device objects in all cases */
4072
4073 ULONG i;
4074
4075 for (i = 0; i < DeviceRelations->Count; i++)
4076 {
4077 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4078 ObDereferenceObject(DeviceRelations->Objects[i]);
4079 DeviceRelations->Objects[i] = NULL;
4080 }
4081
4082 ExFreePool(DeviceRelations);
4083 }
4084
4085 VOID
4086 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
4087 {
4088 IO_STACK_LOCATION Stack;
4089 IO_STATUS_BLOCK IoStatusBlock;
4090 PDEVICE_RELATIONS DeviceRelations;
4091 NTSTATUS Status;
4092
4093 IopCancelRemoveDevice(DeviceObject);
4094
4095 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4096
4097 Status = IopInitiatePnpIrp(DeviceObject,
4098 &IoStatusBlock,
4099 IRP_MN_QUERY_DEVICE_RELATIONS,
4100 &Stack);
4101 if (!NT_SUCCESS(Status))
4102 {
4103 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4104 DeviceRelations = NULL;
4105 }
4106 else
4107 {
4108 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4109 }
4110
4111 if (DeviceRelations)
4112 IopCancelRemoveDeviceRelations(DeviceRelations);
4113 }
4114
4115 NTSTATUS
4116 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject)
4117 {
4118 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4119 IO_STACK_LOCATION Stack;
4120 IO_STATUS_BLOCK IoStatusBlock;
4121 PDEVICE_RELATIONS DeviceRelations;
4122 NTSTATUS Status;
4123
4124 if (DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE)
4125 {
4126 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
4127 return STATUS_UNSUCCESSFUL;
4128 }
4129
4130 if (IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
4131 {
4132 DPRINT1("Removal vetoed by failing the query remove request\n");
4133
4134 IopCancelRemoveDevice(DeviceObject);
4135
4136 return STATUS_UNSUCCESSFUL;
4137 }
4138
4139 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4140
4141 Status = IopInitiatePnpIrp(DeviceObject,
4142 &IoStatusBlock,
4143 IRP_MN_QUERY_DEVICE_RELATIONS,
4144 &Stack);
4145 if (!NT_SUCCESS(Status))
4146 {
4147 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4148 DeviceRelations = NULL;
4149 }
4150 else
4151 {
4152 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4153 }
4154
4155 if (DeviceRelations)
4156 {
4157 Status = IopQueryRemoveDeviceRelations(DeviceRelations);
4158 if (!NT_SUCCESS(Status))
4159 return Status;
4160 }
4161
4162 Status = IopQueryRemoveChildDevices(DeviceNode);
4163 if (!NT_SUCCESS(Status))
4164 {
4165 if (DeviceRelations)
4166 IopCancelRemoveDeviceRelations(DeviceRelations);
4167 return Status;
4168 }
4169
4170 if (DeviceRelations)
4171 IopSendRemoveDeviceRelations(DeviceRelations);
4172 IopSendRemoveChildDevices(DeviceNode);
4173
4174 return STATUS_SUCCESS;
4175 }
4176
4177 NTSTATUS
4178 IopRemoveDevice(PDEVICE_NODE DeviceNode)
4179 {
4180 NTSTATUS Status;
4181
4182 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
4183
4184 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject);
4185 if (NT_SUCCESS(Status))
4186 {
4187 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
4188 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
4189 &DeviceNode->InstancePath);
4190 DeviceNode->Flags |= DNF_WILL_BE_REMOVED;
4191 return STATUS_SUCCESS;
4192 }
4193
4194 return Status;
4195 }
4196
4197 /*
4198 * @implemented
4199 */
4200 VOID
4201 NTAPI
4202 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
4203 {
4204 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4205 PDEVICE_RELATIONS DeviceRelations;
4206 IO_STATUS_BLOCK IoStatusBlock;
4207 IO_STACK_LOCATION Stack;
4208 DEVICE_CAPABILITIES Capabilities;
4209 NTSTATUS Status;
4210
4211 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
4212 &DeviceNode->InstancePath);
4213
4214 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
4215 {
4216 goto cleanup;
4217 }
4218
4219 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
4220
4221 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4222 &IoStatusBlock,
4223 IRP_MN_QUERY_DEVICE_RELATIONS,
4224 &Stack);
4225 if (!NT_SUCCESS(Status))
4226 {
4227 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4228 DeviceRelations = NULL;
4229 }
4230 else
4231 {
4232 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4233 }
4234
4235 if (DeviceRelations)
4236 {
4237 Status = IopQueryRemoveDeviceRelations(DeviceRelations);
4238 if (!NT_SUCCESS(Status))
4239 goto cleanup;
4240 }
4241
4242 Status = IopQueryRemoveChildDevices(DeviceNode);
4243 if (!NT_SUCCESS(Status))
4244 {
4245 if (DeviceRelations)
4246 IopCancelRemoveDeviceRelations(DeviceRelations);
4247 goto cleanup;
4248 }
4249
4250 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject) != STATUS_SUCCESS)
4251 {
4252 if (DeviceRelations)
4253 IopCancelRemoveDeviceRelations(DeviceRelations);
4254 IopCancelRemoveChildDevices(DeviceNode);
4255 goto cleanup;
4256 }
4257
4258 if (DeviceRelations)
4259 IopSendRemoveDeviceRelations(DeviceRelations);
4260 IopSendRemoveChildDevices(DeviceNode);
4261
4262 if (Capabilities.EjectSupported)
4263 {
4264 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
4265 {
4266 goto cleanup;
4267 }
4268 }
4269 else
4270 {
4271 DeviceNode->Flags |= DNF_DISABLED;
4272 }
4273
4274 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
4275 &DeviceNode->InstancePath);
4276
4277 return;
4278
4279 cleanup:
4280 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
4281 &DeviceNode->InstancePath);
4282 }
4283
4284 /*
4285 * @implemented
4286 */
4287 VOID
4288 NTAPI
4289 IoInvalidateDeviceRelations(
4290 IN PDEVICE_OBJECT DeviceObject,
4291 IN DEVICE_RELATION_TYPE Type)
4292 {
4293 PIO_WORKITEM WorkItem;
4294 PINVALIDATE_DEVICE_RELATION_DATA Data;
4295
4296 Data = ExAllocatePool(NonPagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
4297 if (!Data)
4298 return;
4299 WorkItem = IoAllocateWorkItem(DeviceObject);
4300 if (!WorkItem)
4301 {
4302 ExFreePool(Data);
4303 return;
4304 }
4305
4306 ObReferenceObject(DeviceObject);
4307 Data->DeviceObject = DeviceObject;
4308 Data->Type = Type;
4309 Data->WorkItem = WorkItem;
4310
4311 IoQueueWorkItem(
4312 WorkItem,
4313 IopAsynchronousInvalidateDeviceRelations,
4314 DelayedWorkQueue,
4315 Data);
4316 }
4317
4318 /*
4319 * @implemented
4320 */
4321 NTSTATUS
4322 NTAPI
4323 IoSynchronousInvalidateDeviceRelations(
4324 IN PDEVICE_OBJECT DeviceObject,
4325 IN DEVICE_RELATION_TYPE Type)
4326 {
4327 PAGED_CODE();
4328
4329 switch (Type)
4330 {
4331 case BusRelations:
4332 /* Enumerate the device */
4333 return IopEnumerateDevice(DeviceObject);
4334 case PowerRelations:
4335 /* Not handled yet */
4336 return STATUS_NOT_IMPLEMENTED;
4337 case TargetDeviceRelation:
4338 /* Nothing to do */
4339 return STATUS_SUCCESS;
4340 default:
4341 /* Ejection relations are not supported */
4342 return STATUS_NOT_SUPPORTED;
4343 }
4344 }
4345
4346 /*
4347 * @implemented
4348 */
4349 BOOLEAN
4350 NTAPI
4351 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
4352 IN ULONG BusNumber,
4353 IN PHYSICAL_ADDRESS BusAddress,
4354 IN OUT PULONG AddressSpace,
4355 OUT PPHYSICAL_ADDRESS TranslatedAddress)
4356 {
4357 /* FIXME: Notify the resource arbiter */
4358
4359 return HalTranslateBusAddress(InterfaceType,
4360 BusNumber,
4361 BusAddress,
4362 AddressSpace,
4363 TranslatedAddress);
4364 }