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