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