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