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