[NTOS:PNP] Use pool tagging for DEVICE_ACTION_DATA. CORE-10456
[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 IopDeviceActionRequestList;
38 WORK_QUEUE_ITEM IopDeviceActionWorkItem;
39 BOOLEAN IopDeviceActionInProgress;
40 KSPIN_LOCK IopDeviceActionLock;
41
42 typedef struct _DEVICE_ACTION_DATA
43 {
44 LIST_ENTRY RequestListEntry;
45 PDEVICE_OBJECT DeviceObject;
46 DEVICE_RELATION_TYPE Type;
47 } DEVICE_ACTION_DATA, *PDEVICE_ACTION_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 IopDeviceActionWorker(
910 _In_ PVOID Context)
911 {
912 PLIST_ENTRY ListEntry;
913 PDEVICE_ACTION_DATA Data;
914 KIRQL OldIrql;
915
916 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
917 while (!IsListEmpty(&IopDeviceActionRequestList))
918 {
919 ListEntry = RemoveHeadList(&IopDeviceActionRequestList);
920 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
921 Data = CONTAINING_RECORD(ListEntry,
922 DEVICE_ACTION_DATA,
923 RequestListEntry);
924
925 IoSynchronousInvalidateDeviceRelations(Data->DeviceObject,
926 Data->Type);
927
928 ObDereferenceObject(Data->DeviceObject);
929 ExFreePoolWithTag(Data, TAG_IO);
930 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
931 }
932 IopDeviceActionInProgress = FALSE;
933 KeReleaseSpinLock(&IopDeviceActionLock, 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 MaxSeparators = MAX_SEPARATORS_DEVICEID;
1797 IsMultiSz = TRUE;
1798 break;
1799
1800 default:
1801 DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
1802 return FALSE;
1803 }
1804
1805 StringEnd = Id + MAX_DEVICE_ID_LEN;
1806
1807 for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
1808 {
1809 Char = *PtrChar;
1810
1811 if (Char == UNICODE_NULL)
1812 {
1813 if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
1814 {
1815 if (MaxSeparators == SeparatorsCount || IsMultiSz)
1816 {
1817 return TRUE;
1818 }
1819
1820 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1821 SeparatorsCount, MaxSeparators);
1822 goto ErrorExit;
1823 }
1824
1825 StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
1826 PtrPrevChar = PtrChar;
1827 SeparatorsCount = 0;
1828 }
1829 else if (Char < ' ' || Char > 0x7F || Char == ',')
1830 {
1831 DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
1832 goto ErrorExit;
1833 }
1834 else if (Char == ' ')
1835 {
1836 *PtrChar = '_';
1837 }
1838 else if (Char == '\\')
1839 {
1840 SeparatorsCount++;
1841
1842 if (SeparatorsCount > MaxSeparators)
1843 {
1844 DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
1845 SeparatorsCount, MaxSeparators);
1846 goto ErrorExit;
1847 }
1848 }
1849 }
1850
1851 DPRINT1("IopValidateID: Not terminated ID\n");
1852
1853 ErrorExit:
1854 // FIXME logging
1855 return FALSE;
1856 }
1857
1858 NTSTATUS
1859 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
1860 HANDLE InstanceKey)
1861 {
1862 IO_STACK_LOCATION Stack;
1863 IO_STATUS_BLOCK IoStatusBlock;
1864 PWSTR Ptr;
1865 UNICODE_STRING ValueName;
1866 NTSTATUS Status;
1867 ULONG Length, TotalLength;
1868 BOOLEAN IsValidID;
1869
1870 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1871
1872 RtlZeroMemory(&Stack, sizeof(Stack));
1873 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1874 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1875 &IoStatusBlock,
1876 IRP_MN_QUERY_ID,
1877 &Stack);
1878 if (NT_SUCCESS(Status))
1879 {
1880 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryHardwareIDs);
1881
1882 if (!IsValidID)
1883 {
1884 DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
1885 }
1886
1887 TotalLength = 0;
1888
1889 Ptr = (PWSTR)IoStatusBlock.Information;
1890 DPRINT("Hardware IDs:\n");
1891 while (*Ptr)
1892 {
1893 DPRINT(" %S\n", Ptr);
1894 Length = (ULONG)wcslen(Ptr) + 1;
1895
1896 Ptr += Length;
1897 TotalLength += Length;
1898 }
1899 DPRINT("TotalLength: %hu\n", TotalLength);
1900 DPRINT("\n");
1901
1902 RtlInitUnicodeString(&ValueName, L"HardwareID");
1903 Status = ZwSetValueKey(InstanceKey,
1904 &ValueName,
1905 0,
1906 REG_MULTI_SZ,
1907 (PVOID)IoStatusBlock.Information,
1908 (TotalLength + 1) * sizeof(WCHAR));
1909 if (!NT_SUCCESS(Status))
1910 {
1911 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1912 }
1913 }
1914 else
1915 {
1916 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1917 }
1918
1919 return Status;
1920 }
1921
1922 NTSTATUS
1923 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
1924 HANDLE InstanceKey)
1925 {
1926 IO_STACK_LOCATION Stack;
1927 IO_STATUS_BLOCK IoStatusBlock;
1928 PWSTR Ptr;
1929 UNICODE_STRING ValueName;
1930 NTSTATUS Status;
1931 ULONG Length, TotalLength;
1932 BOOLEAN IsValidID;
1933
1934 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1935
1936 RtlZeroMemory(&Stack, sizeof(Stack));
1937 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1938 Status = IopInitiatePnpIrp(
1939 DeviceNode->PhysicalDeviceObject,
1940 &IoStatusBlock,
1941 IRP_MN_QUERY_ID,
1942 &Stack);
1943 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1944 {
1945 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryCompatibleIDs);
1946
1947 if (!IsValidID)
1948 {
1949 DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
1950 }
1951
1952 TotalLength = 0;
1953
1954 Ptr = (PWSTR)IoStatusBlock.Information;
1955 DPRINT("Compatible IDs:\n");
1956 while (*Ptr)
1957 {
1958 DPRINT(" %S\n", Ptr);
1959 Length = (ULONG)wcslen(Ptr) + 1;
1960
1961 Ptr += Length;
1962 TotalLength += Length;
1963 }
1964 DPRINT("TotalLength: %hu\n", TotalLength);
1965 DPRINT("\n");
1966
1967 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1968 Status = ZwSetValueKey(InstanceKey,
1969 &ValueName,
1970 0,
1971 REG_MULTI_SZ,
1972 (PVOID)IoStatusBlock.Information,
1973 (TotalLength + 1) * sizeof(WCHAR));
1974 if (!NT_SUCCESS(Status))
1975 {
1976 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1977 }
1978 }
1979 else
1980 {
1981 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1982 }
1983
1984 return Status;
1985 }
1986
1987 NTSTATUS
1988 IopCreateDeviceInstancePath(
1989 _In_ PDEVICE_NODE DeviceNode,
1990 _Out_ PUNICODE_STRING InstancePath)
1991 {
1992 IO_STATUS_BLOCK IoStatusBlock;
1993 UNICODE_STRING DeviceId;
1994 UNICODE_STRING InstanceId;
1995 IO_STACK_LOCATION Stack;
1996 NTSTATUS Status;
1997 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
1998 DEVICE_CAPABILITIES DeviceCapabilities;
1999 BOOLEAN IsValidID;
2000
2001 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2002
2003 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
2004 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2005 &IoStatusBlock,
2006 IRP_MN_QUERY_ID,
2007 &Stack);
2008 if (!NT_SUCCESS(Status))
2009 {
2010 DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
2011 return Status;
2012 }
2013
2014 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryDeviceID);
2015
2016 if (!IsValidID)
2017 {
2018 DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
2019 }
2020
2021 /* Save the device id string */
2022 RtlInitUnicodeString(&DeviceId, (PWSTR)IoStatusBlock.Information);
2023
2024 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
2025
2026 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
2027 if (!NT_SUCCESS(Status))
2028 {
2029 DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
2030 RtlFreeUnicodeString(&DeviceId);
2031 return Status;
2032 }
2033
2034 /* This bit is only check after enumeration */
2035 if (DeviceCapabilities.HardwareDisabled)
2036 {
2037 /* FIXME: Cleanup device */
2038 DeviceNode->Flags |= DNF_DISABLED;
2039 RtlFreeUnicodeString(&DeviceId);
2040 return STATUS_PLUGPLAY_NO_DEVICE;
2041 }
2042 else
2043 {
2044 DeviceNode->Flags &= ~DNF_DISABLED;
2045 }
2046
2047 if (!DeviceCapabilities.UniqueID)
2048 {
2049 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2050 DPRINT("Instance ID is not unique\n");
2051 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
2052 if (!NT_SUCCESS(Status))
2053 {
2054 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
2055 RtlFreeUnicodeString(&DeviceId);
2056 return Status;
2057 }
2058 }
2059
2060 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2061
2062 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
2063 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2064 &IoStatusBlock,
2065 IRP_MN_QUERY_ID,
2066 &Stack);
2067 if (!NT_SUCCESS(Status))
2068 {
2069 DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
2070 ASSERT(IoStatusBlock.Information == 0);
2071 }
2072
2073 if (IoStatusBlock.Information)
2074 {
2075 IsValidID = IopValidateID((PWCHAR)IoStatusBlock.Information, BusQueryInstanceID);
2076
2077 if (!IsValidID)
2078 {
2079 DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
2080 }
2081 }
2082
2083 RtlInitUnicodeString(&InstanceId,
2084 (PWSTR)IoStatusBlock.Information);
2085
2086 InstancePath->Length = 0;
2087 InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
2088 ParentIdPrefix.Length +
2089 InstanceId.Length +
2090 sizeof(UNICODE_NULL);
2091 if (ParentIdPrefix.Length && InstanceId.Length)
2092 {
2093 InstancePath->MaximumLength += sizeof(WCHAR);
2094 }
2095
2096 InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
2097 InstancePath->MaximumLength,
2098 TAG_IO);
2099 if (!InstancePath->Buffer)
2100 {
2101 RtlFreeUnicodeString(&InstanceId);
2102 RtlFreeUnicodeString(&ParentIdPrefix);
2103 RtlFreeUnicodeString(&DeviceId);
2104 return STATUS_INSUFFICIENT_RESOURCES;
2105 }
2106
2107 /* Start with the device id */
2108 RtlCopyUnicodeString(InstancePath, &DeviceId);
2109 RtlAppendUnicodeToString(InstancePath, L"\\");
2110
2111 /* Add information from parent bus device to InstancePath */
2112 RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
2113 if (ParentIdPrefix.Length && InstanceId.Length)
2114 {
2115 RtlAppendUnicodeToString(InstancePath, L"&");
2116 }
2117
2118 /* Finally, add the id returned by the driver stack */
2119 RtlAppendUnicodeStringToString(InstancePath, &InstanceId);
2120
2121 /*
2122 * FIXME: Check for valid characters, if there is invalid characters
2123 * then bugcheck
2124 */
2125
2126 RtlFreeUnicodeString(&InstanceId);
2127 RtlFreeUnicodeString(&DeviceId);
2128 RtlFreeUnicodeString(&ParentIdPrefix);
2129
2130 return STATUS_SUCCESS;
2131 }
2132
2133 /*
2134 * IopActionInterrogateDeviceStack
2135 *
2136 * Retrieve information for all (direct) child nodes of a parent node.
2137 *
2138 * Parameters
2139 * DeviceNode
2140 * Pointer to device node.
2141 * Context
2142 * Pointer to parent node to retrieve child node information for.
2143 *
2144 * Remarks
2145 * Any errors that occur are logged instead so that all child services have a chance
2146 * of being interrogated.
2147 */
2148
2149 NTSTATUS
2150 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
2151 PVOID Context)
2152 {
2153 IO_STATUS_BLOCK IoStatusBlock;
2154 PWSTR DeviceDescription;
2155 PWSTR LocationInformation;
2156 PDEVICE_NODE ParentDeviceNode;
2157 IO_STACK_LOCATION Stack;
2158 NTSTATUS Status;
2159 ULONG RequiredLength;
2160 LCID LocaleId;
2161 HANDLE InstanceKey = NULL;
2162 UNICODE_STRING ValueName;
2163 UNICODE_STRING InstancePathU;
2164 PDEVICE_OBJECT OldDeviceObject;
2165
2166 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2167 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2168
2169 ParentDeviceNode = (PDEVICE_NODE)Context;
2170
2171 /*
2172 * We are called for the parent too, but we don't need to do special
2173 * handling for this node
2174 */
2175 if (DeviceNode == ParentDeviceNode)
2176 {
2177 DPRINT("Success\n");
2178 return STATUS_SUCCESS;
2179 }
2180
2181 /*
2182 * Make sure this device node is a direct child of the parent device node
2183 * that is given as an argument
2184 */
2185 if (DeviceNode->Parent != ParentDeviceNode)
2186 {
2187 DPRINT("Skipping 2+ level child\n");
2188 return STATUS_SUCCESS;
2189 }
2190
2191 /* Skip processing if it was already completed before */
2192 if (DeviceNode->Flags & DNF_PROCESSED)
2193 {
2194 /* Nothing to do */
2195 return STATUS_SUCCESS;
2196 }
2197
2198 /* Get Locale ID */
2199 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2200 if (!NT_SUCCESS(Status))
2201 {
2202 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2203 return Status;
2204 }
2205
2206 /*
2207 * FIXME: For critical errors, cleanup and disable device, but always
2208 * return STATUS_SUCCESS.
2209 */
2210
2211 Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
2212 if (!NT_SUCCESS(Status))
2213 {
2214 if (Status != STATUS_PLUGPLAY_NO_DEVICE)
2215 {
2216 DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
2217 }
2218
2219 /* We have to return success otherwise we abort the traverse operation */
2220 return STATUS_SUCCESS;
2221 }
2222
2223 /* Verify that this is not a duplicate */
2224 OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
2225 if (OldDeviceObject != NULL)
2226 {
2227 PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
2228
2229 DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
2230 DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
2231 DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
2232
2233 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
2234 0x01,
2235 (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
2236 (ULONG_PTR)OldDeviceObject,
2237 0);
2238 }
2239
2240 DeviceNode->InstancePath = InstancePathU;
2241
2242 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2243
2244 /*
2245 * Create registry key for the instance id, if it doesn't exist yet
2246 */
2247 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
2248 if (!NT_SUCCESS(Status))
2249 {
2250 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2251
2252 /* We have to return success otherwise we abort the traverse operation */
2253 return STATUS_SUCCESS;
2254 }
2255
2256 IopQueryHardwareIds(DeviceNode, InstanceKey);
2257
2258 IopQueryCompatibleIds(DeviceNode, InstanceKey);
2259
2260 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2261
2262 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2263 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2264 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2265 &IoStatusBlock,
2266 IRP_MN_QUERY_DEVICE_TEXT,
2267 &Stack);
2268 DeviceDescription = NT_SUCCESS(Status) ? (PWSTR)IoStatusBlock.Information
2269 : NULL;
2270 /* This key is mandatory, so even if the Irp fails, we still write it */
2271 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2272 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2273 {
2274 if (DeviceDescription &&
2275 *DeviceDescription != UNICODE_NULL)
2276 {
2277 /* This key is overriden when a driver is installed. Don't write the
2278 * new description if another one already exists */
2279 Status = ZwSetValueKey(InstanceKey,
2280 &ValueName,
2281 0,
2282 REG_SZ,
2283 DeviceDescription,
2284 ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR));
2285 }
2286 else
2287 {
2288 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2289 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2290
2291 Status = ZwSetValueKey(InstanceKey,
2292 &ValueName,
2293 0,
2294 REG_SZ,
2295 DeviceDesc.Buffer,
2296 DeviceDesc.MaximumLength);
2297 if (!NT_SUCCESS(Status))
2298 {
2299 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2300 }
2301
2302 }
2303 }
2304
2305 if (DeviceDescription)
2306 {
2307 ExFreePoolWithTag(DeviceDescription, 0);
2308 }
2309
2310 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2311
2312 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2313 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2314 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2315 &IoStatusBlock,
2316 IRP_MN_QUERY_DEVICE_TEXT,
2317 &Stack);
2318 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2319 {
2320 LocationInformation = (PWSTR)IoStatusBlock.Information;
2321 DPRINT("LocationInformation: %S\n", LocationInformation);
2322 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2323 Status = ZwSetValueKey(InstanceKey,
2324 &ValueName,
2325 0,
2326 REG_SZ,
2327 LocationInformation,
2328 ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR));
2329 if (!NT_SUCCESS(Status))
2330 {
2331 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2332 }
2333
2334 ExFreePoolWithTag(LocationInformation, 0);
2335 }
2336 else
2337 {
2338 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2339 }
2340
2341 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2342
2343 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2344 &IoStatusBlock,
2345 IRP_MN_QUERY_BUS_INFORMATION,
2346 NULL);
2347 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2348 {
2349 PPNP_BUS_INFORMATION BusInformation = (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2350
2351 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2352 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2353 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2354 ExFreePoolWithTag(BusInformation, 0);
2355 }
2356 else
2357 {
2358 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2359
2360 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2361 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2362 DeviceNode->ChildBusTypeIndex = -1;
2363 }
2364
2365 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2366
2367 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2368 &IoStatusBlock,
2369 IRP_MN_QUERY_RESOURCES,
2370 NULL);
2371 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2372 {
2373 DeviceNode->BootResources = (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2374 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2375 }
2376 else
2377 {
2378 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2379 DeviceNode->BootResources = NULL;
2380 }
2381
2382 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2383
2384 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2385 &IoStatusBlock,
2386 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2387 NULL);
2388 if (NT_SUCCESS(Status))
2389 {
2390 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2391 }
2392 else
2393 {
2394 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2395 DeviceNode->ResourceRequirements = NULL;
2396 }
2397
2398 if (InstanceKey != NULL)
2399 {
2400 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2401 }
2402
2403 ZwClose(InstanceKey);
2404
2405 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2406
2407 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2408 {
2409 /* Report the device to the user-mode pnp manager */
2410 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2411 &DeviceNode->InstancePath);
2412 }
2413
2414 return STATUS_SUCCESS;
2415 }
2416
2417 static
2418 VOID
2419 IopHandleDeviceRemoval(
2420 IN PDEVICE_NODE DeviceNode,
2421 IN PDEVICE_RELATIONS DeviceRelations)
2422 {
2423 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2424 ULONG i;
2425 BOOLEAN Found;
2426
2427 if (DeviceNode == IopRootDeviceNode)
2428 return;
2429
2430 while (Child != NULL)
2431 {
2432 NextChild = Child->Sibling;
2433 Found = FALSE;
2434
2435 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
2436 {
2437 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
2438 {
2439 Found = TRUE;
2440 break;
2441 }
2442 }
2443
2444 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
2445 {
2446 /* Send removal IRPs to all of its children */
2447 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
2448
2449 /* Send the surprise removal IRP */
2450 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
2451
2452 /* Tell the user-mode PnP manager that a device was removed */
2453 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
2454 &Child->InstancePath);
2455
2456 /* Send the remove device IRP */
2457 IopSendRemoveDevice(Child->PhysicalDeviceObject);
2458 }
2459
2460 Child = NextChild;
2461 }
2462 }
2463
2464 NTSTATUS
2465 IopEnumerateDevice(
2466 IN PDEVICE_OBJECT DeviceObject)
2467 {
2468 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2469 DEVICETREE_TRAVERSE_CONTEXT Context;
2470 PDEVICE_RELATIONS DeviceRelations;
2471 PDEVICE_OBJECT ChildDeviceObject;
2472 IO_STATUS_BLOCK IoStatusBlock;
2473 PDEVICE_NODE ChildDeviceNode;
2474 IO_STACK_LOCATION Stack;
2475 NTSTATUS Status;
2476 ULONG i;
2477
2478 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2479
2480 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
2481 {
2482 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
2483
2484 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2485 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2486 &DeviceNode->InstancePath);
2487 }
2488
2489 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2490
2491 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2492
2493 Status = IopInitiatePnpIrp(
2494 DeviceObject,
2495 &IoStatusBlock,
2496 IRP_MN_QUERY_DEVICE_RELATIONS,
2497 &Stack);
2498 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2499 {
2500 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2501 return Status;
2502 }
2503
2504 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2505
2506 /*
2507 * Send removal IRPs for devices that have disappeared
2508 * NOTE: This code handles the case where no relations are specified
2509 */
2510 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2511
2512 /* Now we bail if nothing was returned */
2513 if (!DeviceRelations)
2514 {
2515 /* We're all done */
2516 DPRINT("No PDOs\n");
2517 return STATUS_SUCCESS;
2518 }
2519
2520 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2521
2522 /*
2523 * Create device nodes for all discovered devices
2524 */
2525 for (i = 0; i < DeviceRelations->Count; i++)
2526 {
2527 ChildDeviceObject = DeviceRelations->Objects[i];
2528 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2529
2530 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2531 if (!ChildDeviceNode)
2532 {
2533 /* One doesn't exist, create it */
2534 Status = IopCreateDeviceNode(
2535 DeviceNode,
2536 ChildDeviceObject,
2537 NULL,
2538 &ChildDeviceNode);
2539 if (NT_SUCCESS(Status))
2540 {
2541 /* Mark the node as enumerated */
2542 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2543
2544 /* Mark the DO as bus enumerated */
2545 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2546 }
2547 else
2548 {
2549 /* Ignore this DO */
2550 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2551 ObDereferenceObject(ChildDeviceObject);
2552 }
2553 }
2554 else
2555 {
2556 /* Mark it as enumerated */
2557 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2558 ObDereferenceObject(ChildDeviceObject);
2559 }
2560 }
2561 ExFreePool(DeviceRelations);
2562
2563 /*
2564 * Retrieve information about all discovered children from the bus driver
2565 */
2566 IopInitDeviceTreeTraverseContext(
2567 &Context,
2568 DeviceNode,
2569 IopActionInterrogateDeviceStack,
2570 DeviceNode);
2571
2572 Status = IopTraverseDeviceTree(&Context);
2573 if (!NT_SUCCESS(Status))
2574 {
2575 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2576 return Status;
2577 }
2578
2579 /*
2580 * Retrieve configuration from the registry for discovered children
2581 */
2582 IopInitDeviceTreeTraverseContext(
2583 &Context,
2584 DeviceNode,
2585 IopActionConfigureChildServices,
2586 DeviceNode);
2587
2588 Status = IopTraverseDeviceTree(&Context);
2589 if (!NT_SUCCESS(Status))
2590 {
2591 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2592 return Status;
2593 }
2594
2595 /*
2596 * Initialize services for discovered children.
2597 */
2598 Status = IopInitializePnpServices(DeviceNode);
2599 if (!NT_SUCCESS(Status))
2600 {
2601 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2602 return Status;
2603 }
2604
2605 DPRINT("IopEnumerateDevice() finished\n");
2606 return STATUS_SUCCESS;
2607 }
2608
2609
2610 /*
2611 * IopActionConfigureChildServices
2612 *
2613 * Retrieve configuration for all (direct) child nodes of a parent node.
2614 *
2615 * Parameters
2616 * DeviceNode
2617 * Pointer to device node.
2618 * Context
2619 * Pointer to parent node to retrieve child node configuration for.
2620 *
2621 * Remarks
2622 * Any errors that occur are logged instead so that all child services have a chance of beeing
2623 * configured.
2624 */
2625
2626 NTSTATUS
2627 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2628 PVOID Context)
2629 {
2630 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2631 PDEVICE_NODE ParentDeviceNode;
2632 PUNICODE_STRING Service;
2633 UNICODE_STRING ClassGUID;
2634 NTSTATUS Status;
2635 DEVICE_CAPABILITIES DeviceCaps;
2636
2637 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2638
2639 ParentDeviceNode = (PDEVICE_NODE)Context;
2640
2641 /*
2642 * We are called for the parent too, but we don't need to do special
2643 * handling for this node
2644 */
2645 if (DeviceNode == ParentDeviceNode)
2646 {
2647 DPRINT("Success\n");
2648 return STATUS_SUCCESS;
2649 }
2650
2651 /*
2652 * Make sure this device node is a direct child of the parent device node
2653 * that is given as an argument
2654 */
2655
2656 if (DeviceNode->Parent != ParentDeviceNode)
2657 {
2658 DPRINT("Skipping 2+ level child\n");
2659 return STATUS_SUCCESS;
2660 }
2661
2662 if (!(DeviceNode->Flags & DNF_PROCESSED))
2663 {
2664 DPRINT1("Child not ready to be configured\n");
2665 return STATUS_SUCCESS;
2666 }
2667
2668 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2669 {
2670 WCHAR RegKeyBuffer[MAX_PATH];
2671 UNICODE_STRING RegKey;
2672
2673 /* Install the service for this if it's in the CDDB */
2674 IopInstallCriticalDevice(DeviceNode);
2675
2676 RegKey.Length = 0;
2677 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2678 RegKey.Buffer = RegKeyBuffer;
2679
2680 /*
2681 * Retrieve configuration from Enum key
2682 */
2683
2684 Service = &DeviceNode->ServiceName;
2685
2686 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2687 RtlInitUnicodeString(Service, NULL);
2688 RtlInitUnicodeString(&ClassGUID, NULL);
2689
2690 QueryTable[0].Name = L"Service";
2691 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2692 QueryTable[0].EntryContext = Service;
2693
2694 QueryTable[1].Name = L"ClassGUID";
2695 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2696 QueryTable[1].EntryContext = &ClassGUID;
2697 QueryTable[1].DefaultType = REG_SZ;
2698 QueryTable[1].DefaultData = L"";
2699 QueryTable[1].DefaultLength = 0;
2700
2701 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2702 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2703
2704 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2705 RegKey.Buffer, QueryTable, NULL, NULL);
2706
2707 if (!NT_SUCCESS(Status))
2708 {
2709 /* FIXME: Log the error */
2710 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2711 &DeviceNode->InstancePath, Status);
2712 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2713 return STATUS_SUCCESS;
2714 }
2715
2716 if (Service->Buffer == NULL)
2717 {
2718 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2719 DeviceCaps.RawDeviceOK)
2720 {
2721 DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2722
2723 DeviceNode->ServiceName.Length = 0;
2724 DeviceNode->ServiceName.MaximumLength = 0;
2725 DeviceNode->ServiceName.Buffer = NULL;
2726 }
2727 else if (ClassGUID.Length != 0)
2728 {
2729 /* Device has a ClassGUID value, but no Service value.
2730 * Suppose it is using the NULL driver, so state the
2731 * device is started */
2732 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2733 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2734 }
2735 else
2736 {
2737 DeviceNode->Problem = CM_PROB_FAILED_INSTALL;
2738 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2739 }
2740 return STATUS_SUCCESS;
2741 }
2742
2743 DPRINT("Got Service %S\n", Service->Buffer);
2744 }
2745
2746 return STATUS_SUCCESS;
2747 }
2748
2749 /*
2750 * IopActionInitChildServices
2751 *
2752 * Initialize the service for all (direct) child nodes of a parent node
2753 *
2754 * Parameters
2755 * DeviceNode
2756 * Pointer to device node.
2757 * Context
2758 * Pointer to parent node to initialize child node services for.
2759 *
2760 * Remarks
2761 * If the driver image for a service is not loaded and initialized
2762 * it is done here too. Any errors that occur are logged instead so
2763 * that all child services have a chance of being initialized.
2764 */
2765
2766 NTSTATUS
2767 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2768 PVOID Context)
2769 {
2770 PDEVICE_NODE ParentDeviceNode;
2771 NTSTATUS Status;
2772 BOOLEAN BootDrivers = !PnpSystemInit;
2773
2774 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2775
2776 ParentDeviceNode = Context;
2777
2778 /*
2779 * We are called for the parent too, but we don't need to do special
2780 * handling for this node
2781 */
2782 if (DeviceNode == ParentDeviceNode)
2783 {
2784 DPRINT("Success\n");
2785 return STATUS_SUCCESS;
2786 }
2787
2788 /*
2789 * We don't want to check for a direct child because
2790 * this function is called during boot to reinitialize
2791 * devices with drivers that couldn't load yet due to
2792 * stage 0 limitations (ie can't load from disk yet).
2793 */
2794
2795 if (!(DeviceNode->Flags & DNF_PROCESSED))
2796 {
2797 DPRINT1("Child not ready to be added\n");
2798 return STATUS_SUCCESS;
2799 }
2800
2801 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2802 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2803 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2804 return STATUS_SUCCESS;
2805
2806 if (DeviceNode->ServiceName.Buffer == NULL)
2807 {
2808 /* We don't need to worry about loading the driver because we're
2809 * being driven in raw mode so our parent must be loaded to get here */
2810 Status = IopInitializeDevice(DeviceNode, NULL);
2811 if (NT_SUCCESS(Status))
2812 {
2813 Status = IopStartDevice(DeviceNode);
2814 if (!NT_SUCCESS(Status))
2815 {
2816 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2817 &DeviceNode->InstancePath, Status);
2818 }
2819 }
2820 }
2821 else
2822 {
2823 PLDR_DATA_TABLE_ENTRY ModuleObject;
2824 PDRIVER_OBJECT DriverObject;
2825
2826 KeEnterCriticalRegion();
2827 ExAcquireResourceExclusiveLite(&IopDriverLoadResource, TRUE);
2828 /* Get existing DriverObject pointer (in case the driver has
2829 already been loaded and initialized) */
2830 Status = IopGetDriverObject(
2831 &DriverObject,
2832 &DeviceNode->ServiceName,
2833 FALSE);
2834
2835 if (!NT_SUCCESS(Status))
2836 {
2837 /* Driver is not initialized, try to load it */
2838 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2839
2840 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2841 {
2842 /* Initialize the driver */
2843 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2844 &DeviceNode->ServiceName, FALSE, &DriverObject);
2845 if (!NT_SUCCESS(Status)) DeviceNode->Problem = CM_PROB_FAILED_DRIVER_ENTRY;
2846 }
2847 else if (Status == STATUS_DRIVER_UNABLE_TO_LOAD)
2848 {
2849 DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
2850 DeviceNode->Problem = CM_PROB_DISABLED_SERVICE;
2851 }
2852 else
2853 {
2854 DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2855 &DeviceNode->ServiceName, Status);
2856 if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
2857 }
2858 }
2859 ExReleaseResourceLite(&IopDriverLoadResource);
2860 KeLeaveCriticalRegion();
2861
2862 /* Driver is loaded and initialized at this point */
2863 if (NT_SUCCESS(Status))
2864 {
2865 /* Initialize the device, including all filters */
2866 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2867
2868 /* Remove the extra reference */
2869 ObDereferenceObject(DriverObject);
2870 }
2871 else
2872 {
2873 /*
2874 * Don't disable when trying to load only boot drivers
2875 */
2876 if (!BootDrivers)
2877 {
2878 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2879 }
2880 }
2881 }
2882
2883 return STATUS_SUCCESS;
2884 }
2885
2886 /*
2887 * IopInitializePnpServices
2888 *
2889 * Initialize services for discovered children
2890 *
2891 * Parameters
2892 * DeviceNode
2893 * Top device node to start initializing services.
2894 *
2895 * Return Value
2896 * Status
2897 */
2898 NTSTATUS
2899 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2900 {
2901 DEVICETREE_TRAVERSE_CONTEXT Context;
2902
2903 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2904
2905 IopInitDeviceTreeTraverseContext(
2906 &Context,
2907 DeviceNode,
2908 IopActionInitChildServices,
2909 DeviceNode);
2910
2911 return IopTraverseDeviceTree(&Context);
2912 }
2913
2914 static NTSTATUS INIT_FUNCTION
2915 IopEnumerateDetectedDevices(
2916 IN HANDLE hBaseKey,
2917 IN PUNICODE_STRING RelativePath OPTIONAL,
2918 IN HANDLE hRootKey,
2919 IN BOOLEAN EnumerateSubKeys,
2920 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2921 IN ULONG ParentBootResourcesLength)
2922 {
2923 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2924 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2925 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2926 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2927 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2928 OBJECT_ATTRIBUTES ObjectAttributes;
2929 HANDLE hDevicesKey = NULL;
2930 HANDLE hDeviceKey = NULL;
2931 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2932 UNICODE_STRING Level2NameU;
2933 WCHAR Level2Name[5];
2934 ULONG IndexDevice = 0;
2935 ULONG IndexSubKey;
2936 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2937 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2938 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2939 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2940 UNICODE_STRING DeviceName, ValueName;
2941 ULONG RequiredSize;
2942 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2943 ULONG BootResourcesLength;
2944 NTSTATUS Status;
2945
2946 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2947 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2948 static ULONG DeviceIndexSerial = 0;
2949 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2950 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2951 static ULONG DeviceIndexKeyboard = 0;
2952 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2953 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2954 static ULONG DeviceIndexMouse = 0;
2955 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2956 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2957 static ULONG DeviceIndexParallel = 0;
2958 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2959 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2960 static ULONG DeviceIndexFloppy = 0;
2961 UNICODE_STRING HardwareIdKey;
2962 PUNICODE_STRING pHardwareId;
2963 ULONG DeviceIndex = 0;
2964 PUCHAR CmResourceList;
2965 ULONG ListCount;
2966
2967 if (RelativePath)
2968 {
2969 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2970 if (!NT_SUCCESS(Status))
2971 {
2972 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2973 goto cleanup;
2974 }
2975 }
2976 else
2977 hDevicesKey = hBaseKey;
2978
2979 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2980 if (!pDeviceInformation)
2981 {
2982 DPRINT("ExAllocatePool() failed\n");
2983 Status = STATUS_NO_MEMORY;
2984 goto cleanup;
2985 }
2986
2987 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2988 if (!pValueInformation)
2989 {
2990 DPRINT("ExAllocatePool() failed\n");
2991 Status = STATUS_NO_MEMORY;
2992 goto cleanup;
2993 }
2994
2995 while (TRUE)
2996 {
2997 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2998 if (Status == STATUS_NO_MORE_ENTRIES)
2999 break;
3000 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3001 {
3002 ExFreePool(pDeviceInformation);
3003 DeviceInfoLength = RequiredSize;
3004 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3005 if (!pDeviceInformation)
3006 {
3007 DPRINT("ExAllocatePool() failed\n");
3008 Status = STATUS_NO_MEMORY;
3009 goto cleanup;
3010 }
3011 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3012 }
3013 if (!NT_SUCCESS(Status))
3014 {
3015 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3016 goto cleanup;
3017 }
3018 IndexDevice++;
3019
3020 /* Open device key */
3021 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3022 DeviceName.Buffer = pDeviceInformation->Name;
3023
3024 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3025 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3026 if (!NT_SUCCESS(Status))
3027 {
3028 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3029 goto cleanup;
3030 }
3031
3032 /* Read boot resources, and add then to parent ones */
3033 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3034 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3035 {
3036 ExFreePool(pValueInformation);
3037 ValueInfoLength = RequiredSize;
3038 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3039 if (!pValueInformation)
3040 {
3041 DPRINT("ExAllocatePool() failed\n");
3042 ZwDeleteKey(hLevel2Key);
3043 Status = STATUS_NO_MEMORY;
3044 goto cleanup;
3045 }
3046 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3047 }
3048 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3049 {
3050 BootResources = ParentBootResources;
3051 BootResourcesLength = ParentBootResourcesLength;
3052 }
3053 else if (!NT_SUCCESS(Status))
3054 {
3055 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3056 goto nextdevice;
3057 }
3058 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3059 {
3060 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3061 goto nextdevice;
3062 }
3063 else
3064 {
3065 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3066
3067 /* Concatenate current resources and parent ones */
3068 if (ParentBootResourcesLength == 0)
3069 BootResourcesLength = pValueInformation->DataLength;
3070 else
3071 BootResourcesLength = ParentBootResourcesLength
3072 + pValueInformation->DataLength
3073 - Header;
3074 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3075 if (!BootResources)
3076 {
3077 DPRINT("ExAllocatePool() failed\n");
3078 goto nextdevice;
3079 }
3080 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3081 {
3082 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3083 }
3084 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3085 {
3086 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3087 RtlCopyMemory(
3088 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3089 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3090 ParentBootResourcesLength - Header);
3091 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3092 }
3093 else
3094 {
3095 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3096 RtlCopyMemory(
3097 (PVOID)((ULONG_PTR)BootResources + Header),
3098 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3099 ParentBootResourcesLength - Header);
3100 RtlCopyMemory(
3101 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3102 pValueInformation->Data + Header,
3103 pValueInformation->DataLength - Header);
3104 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3105 }
3106 }
3107
3108 if (EnumerateSubKeys)
3109 {
3110 IndexSubKey = 0;
3111 while (TRUE)
3112 {
3113 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3114 if (Status == STATUS_NO_MORE_ENTRIES)
3115 break;
3116 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3117 {
3118 ExFreePool(pDeviceInformation);
3119 DeviceInfoLength = RequiredSize;
3120 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3121 if (!pDeviceInformation)
3122 {
3123 DPRINT("ExAllocatePool() failed\n");
3124 Status = STATUS_NO_MEMORY;
3125 goto cleanup;
3126 }
3127 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3128 }
3129 if (!NT_SUCCESS(Status))
3130 {
3131 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3132 goto cleanup;
3133 }
3134 IndexSubKey++;
3135 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3136 DeviceName.Buffer = pDeviceInformation->Name;
3137
3138 Status = IopEnumerateDetectedDevices(
3139 hDeviceKey,
3140 &DeviceName,
3141 hRootKey,
3142 TRUE,
3143 BootResources,
3144 BootResourcesLength);
3145 if (!NT_SUCCESS(Status))
3146 goto cleanup;
3147 }
3148 }
3149
3150 /* Read identifier */
3151 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3152 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3153 {
3154 ExFreePool(pValueInformation);
3155 ValueInfoLength = RequiredSize;
3156 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3157 if (!pValueInformation)
3158 {
3159 DPRINT("ExAllocatePool() failed\n");
3160 Status = STATUS_NO_MEMORY;
3161 goto cleanup;
3162 }
3163 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3164 }
3165 if (!NT_SUCCESS(Status))
3166 {
3167 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
3168 {
3169 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3170 goto nextdevice;
3171 }
3172 ValueName.Length = ValueName.MaximumLength = 0;
3173 }
3174 else if (pValueInformation->Type != REG_SZ)
3175 {
3176 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3177 goto nextdevice;
3178 }
3179 else
3180 {
3181 /* Assign hardware id to this device */
3182 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3183 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3184 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3185 ValueName.Length -= sizeof(WCHAR);
3186 }
3187
3188 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3189 {
3190 pHardwareId = &HardwareIdSerial;
3191 DeviceIndex = DeviceIndexSerial++;
3192 }
3193 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3194 {
3195 pHardwareId = &HardwareIdKeyboard;
3196 DeviceIndex = DeviceIndexKeyboard++;
3197 }
3198 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3199 {
3200 pHardwareId = &HardwareIdMouse;
3201 DeviceIndex = DeviceIndexMouse++;
3202 }
3203 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3204 {
3205 pHardwareId = &HardwareIdParallel;
3206 DeviceIndex = DeviceIndexParallel++;
3207 }
3208 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3209 {
3210 pHardwareId = &HardwareIdFloppy;
3211 DeviceIndex = DeviceIndexFloppy++;
3212 }
3213 else
3214 {
3215 /* Unknown key path */
3216 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3217 goto nextdevice;
3218 }
3219
3220 /* Prepare hardware id key (hardware id value without final \0) */
3221 HardwareIdKey = *pHardwareId;
3222 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3223
3224 /* Add the detected device to Root key */
3225 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3226 Status = ZwCreateKey(
3227 &hLevel1Key,
3228 KEY_CREATE_SUB_KEY,
3229 &ObjectAttributes,
3230 0,
3231 NULL,
3232 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3233 NULL);
3234 if (!NT_SUCCESS(Status))
3235 {
3236 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3237 goto nextdevice;
3238 }
3239 swprintf(Level2Name, L"%04lu", DeviceIndex);
3240 RtlInitUnicodeString(&Level2NameU, Level2Name);
3241 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3242 Status = ZwCreateKey(
3243 &hLevel2Key,
3244 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3245 &ObjectAttributes,
3246 0,
3247 NULL,
3248 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3249 NULL);
3250 ZwClose(hLevel1Key);
3251 if (!NT_SUCCESS(Status))
3252 {
3253 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3254 goto nextdevice;
3255 }
3256 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3257 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3258 if (!NT_SUCCESS(Status))
3259 {
3260 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3261 ZwDeleteKey(hLevel2Key);
3262 goto nextdevice;
3263 }
3264 /* Create 'LogConf' subkey */
3265 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3266 Status = ZwCreateKey(
3267 &hLogConf,
3268 KEY_SET_VALUE,
3269 &ObjectAttributes,
3270 0,
3271 NULL,
3272 REG_OPTION_VOLATILE,
3273 NULL);
3274 if (!NT_SUCCESS(Status))
3275 {
3276 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3277 ZwDeleteKey(hLevel2Key);
3278 goto nextdevice;
3279 }
3280 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3281 {
3282 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3283 if (!CmResourceList)
3284 {
3285 ZwClose(hLogConf);
3286 ZwDeleteKey(hLevel2Key);
3287 goto nextdevice;
3288 }
3289
3290 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3291 ListCount = 1;
3292 RtlCopyMemory(CmResourceList,
3293 &ListCount,
3294 sizeof(ULONG));
3295
3296 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3297 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3298 BootResources,
3299 BootResourcesLength);
3300
3301 /* Save boot resources to 'LogConf\BootConfig' */
3302 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3303 if (!NT_SUCCESS(Status))
3304 {
3305 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3306 ZwClose(hLogConf);
3307 ZwDeleteKey(hLevel2Key);
3308 goto nextdevice;
3309 }
3310 }
3311 ZwClose(hLogConf);
3312
3313 nextdevice:
3314 if (BootResources && BootResources != ParentBootResources)
3315 {
3316 ExFreePool(BootResources);
3317 BootResources = NULL;
3318 }
3319 if (hLevel2Key)
3320 {
3321 ZwClose(hLevel2Key);
3322 hLevel2Key = NULL;
3323 }
3324 if (hDeviceKey)
3325 {
3326 ZwClose(hDeviceKey);
3327 hDeviceKey = NULL;
3328 }
3329 }
3330
3331 Status = STATUS_SUCCESS;
3332
3333 cleanup:
3334 if (hDevicesKey && hDevicesKey != hBaseKey)
3335 ZwClose(hDevicesKey);
3336 if (hDeviceKey)
3337 ZwClose(hDeviceKey);
3338 if (pDeviceInformation)
3339 ExFreePool(pDeviceInformation);
3340 if (pValueInformation)
3341 ExFreePool(pValueInformation);
3342 return Status;
3343 }
3344
3345 static BOOLEAN INIT_FUNCTION
3346 IopIsFirmwareMapperDisabled(VOID)
3347 {
3348 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3349 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3350 OBJECT_ATTRIBUTES ObjectAttributes;
3351 HANDLE hPnpKey;
3352 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3353 ULONG DesiredLength, Length;
3354 ULONG KeyValue = 0;
3355 NTSTATUS Status;
3356
3357 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3358 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3359 if (NT_SUCCESS(Status))
3360 {
3361 Status = ZwQueryValueKey(hPnpKey,
3362 &KeyNameU,
3363 KeyValuePartialInformation,
3364 NULL,
3365 0,
3366 &DesiredLength);
3367 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3368 (Status == STATUS_BUFFER_OVERFLOW))
3369 {
3370 Length = DesiredLength;
3371 KeyInformation = ExAllocatePool(PagedPool, Length);
3372 if (KeyInformation)
3373 {
3374 Status = ZwQueryValueKey(hPnpKey,
3375 &KeyNameU,
3376 KeyValuePartialInformation,
3377 KeyInformation,
3378 Length,
3379 &DesiredLength);
3380 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3381 {
3382 KeyValue = (ULONG)(*KeyInformation->Data);
3383 }
3384 else
3385 {
3386 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3387 }
3388
3389 ExFreePool(KeyInformation);
3390 }
3391 else
3392 {
3393 DPRINT1("Failed to allocate memory for registry query\n");
3394 }
3395 }
3396 else
3397 {
3398 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3399 }
3400
3401 ZwClose(hPnpKey);
3402 }
3403 else
3404 {
3405 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3406 }
3407
3408 DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3409
3410 return (KeyValue != 0) ? TRUE : FALSE;
3411 }
3412
3413 NTSTATUS
3414 NTAPI
3415 INIT_FUNCTION
3416 IopUpdateRootKey(VOID)
3417 {
3418 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3419 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3420 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3421 OBJECT_ATTRIBUTES ObjectAttributes;
3422 HANDLE hEnum, hRoot;
3423 NTSTATUS Status;
3424
3425 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3426 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3427 if (!NT_SUCCESS(Status))
3428 {
3429 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3430 return Status;
3431 }
3432
3433 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3434 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3435 ZwClose(hEnum);
3436 if (!NT_SUCCESS(Status))
3437 {
3438 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3439 return Status;
3440 }
3441
3442 if (!IopIsFirmwareMapperDisabled())
3443 {
3444 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3445 if (!NT_SUCCESS(Status))
3446 {
3447 /* Nothing to do, don't return with an error status */
3448 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3449 ZwClose(hRoot);
3450 return STATUS_SUCCESS;
3451 }
3452 Status = IopEnumerateDetectedDevices(
3453 hEnum,
3454 NULL,
3455 hRoot,
3456 TRUE,
3457 NULL,
3458 0);
3459 ZwClose(hEnum);
3460 }
3461 else
3462 {
3463 /* Enumeration is disabled */
3464 Status = STATUS_SUCCESS;
3465 }
3466
3467 ZwClose(hRoot);
3468
3469 return Status;
3470 }
3471
3472 NTSTATUS
3473 NTAPI
3474 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3475 HANDLE ParentKey,
3476 PUNICODE_STRING Name,
3477 ACCESS_MASK DesiredAccess)
3478 {
3479 OBJECT_ATTRIBUTES ObjectAttributes;
3480 NTSTATUS Status;
3481
3482 PAGED_CODE();
3483
3484 *KeyHandle = NULL;
3485
3486 InitializeObjectAttributes(&ObjectAttributes,
3487 Name,
3488 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3489 ParentKey,
3490 NULL);
3491
3492 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3493
3494 return Status;
3495 }
3496
3497 NTSTATUS
3498 NTAPI
3499 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3500 IN HANDLE RootHandle OPTIONAL,
3501 IN PUNICODE_STRING KeyName,
3502 IN ACCESS_MASK DesiredAccess,
3503 IN ULONG CreateOptions,
3504 OUT PULONG Disposition OPTIONAL)
3505 {
3506 OBJECT_ATTRIBUTES ObjectAttributes;
3507 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3508 USHORT Length;
3509 HANDLE HandleArray[2];
3510 BOOLEAN Recursing = TRUE;
3511 PWCHAR pp, p, p1;
3512 UNICODE_STRING KeyString;
3513 NTSTATUS Status = STATUS_SUCCESS;
3514 PAGED_CODE();
3515
3516 /* P1 is start, pp is end */
3517 p1 = KeyName->Buffer;
3518 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3519
3520 /* Create the target key */
3521 InitializeObjectAttributes(&ObjectAttributes,
3522 KeyName,
3523 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3524 RootHandle,
3525 NULL);
3526 Status = ZwCreateKey(&HandleArray[i],
3527 DesiredAccess,
3528 &ObjectAttributes,
3529 0,
3530 NULL,
3531 CreateOptions,
3532 &KeyDisposition);
3533
3534 /* Now we check if this failed */
3535 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3536 {
3537 /* Target key failed, so we'll need to create its parent. Setup array */
3538 HandleArray[0] = NULL;
3539 HandleArray[1] = RootHandle;
3540
3541 /* Keep recursing for each missing parent */
3542 while (Recursing)
3543 {
3544 /* And if we're deep enough, close the last handle */
3545 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3546
3547 /* We're setup to ping-pong between the two handle array entries */
3548 RootHandleIndex = i;
3549 i = (i + 1) & 1;
3550
3551 /* Clear the one we're attempting to open now */
3552 HandleArray[i] = NULL;
3553
3554 /* Process the parent key name */
3555 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3556 Length = (USHORT)(p - p1) * sizeof(WCHAR);
3557
3558 /* Is there a parent name? */
3559 if (Length)
3560 {
3561 /* Build the unicode string for it */
3562 KeyString.Buffer = p1;
3563 KeyString.Length = KeyString.MaximumLength = Length;
3564
3565 /* Now try opening the parent */
3566 InitializeObjectAttributes(&ObjectAttributes,
3567 &KeyString,
3568 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3569 HandleArray[RootHandleIndex],
3570 NULL);
3571 Status = ZwCreateKey(&HandleArray[i],
3572 DesiredAccess,
3573 &ObjectAttributes,
3574 0,
3575 NULL,
3576 CreateOptions,
3577 &KeyDisposition);
3578 if (NT_SUCCESS(Status))
3579 {
3580 /* It worked, we have one more handle */
3581 NestedCloseLevel++;
3582 }
3583 else
3584 {
3585 /* Parent key creation failed, abandon loop */
3586 Recursing = FALSE;
3587 continue;
3588 }
3589 }
3590 else
3591 {
3592 /* We don't have a parent name, probably corrupted key name */
3593 Status = STATUS_INVALID_PARAMETER;
3594 Recursing = FALSE;
3595 continue;
3596 }
3597
3598 /* Now see if there's more parents to create */
3599 p1 = p + 1;
3600 if ((p == pp) || (p1 == pp))
3601 {
3602 /* We're done, hopefully successfully, so stop */
3603 Recursing = FALSE;
3604 }
3605 }
3606
3607 /* Outer loop check for handle nesting that requires closing the top handle */
3608 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3609 }
3610
3611 /* Check if we broke out of the loop due to success */
3612 if (NT_SUCCESS(Status))
3613 {
3614 /* Return the target handle (we closed all the parent ones) and disposition */
3615 *Handle = HandleArray[i];
3616 if (Disposition) *Disposition = KeyDisposition;
3617 }
3618
3619 /* Return the success state */
3620 return Status;
3621 }
3622
3623 NTSTATUS
3624 NTAPI
3625 IopGetRegistryValue(IN HANDLE Handle,
3626 IN PWSTR ValueName,
3627 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3628 {
3629 UNICODE_STRING ValueString;
3630 NTSTATUS Status;
3631 PKEY_VALUE_FULL_INFORMATION FullInformation;
3632 ULONG Size;
3633 PAGED_CODE();
3634
3635 RtlInitUnicodeString(&ValueString, ValueName);
3636
3637 Status = ZwQueryValueKey(Handle,
3638 &ValueString,
3639 KeyValueFullInformation,
3640 NULL,
3641 0,
3642 &Size);
3643 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3644 (Status != STATUS_BUFFER_TOO_SMALL))
3645 {
3646 return Status;
3647 }
3648
3649 FullInformation = ExAllocatePool(NonPagedPool, Size);
3650 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3651
3652 Status = ZwQueryValueKey(Handle,
3653 &ValueString,
3654 KeyValueFullInformation,
3655 FullInformation,
3656 Size,
3657 &Size);
3658 if (!NT_SUCCESS(Status))
3659 {
3660 ExFreePool(FullInformation);
3661 return Status;
3662 }
3663
3664 *Information = FullInformation;
3665 return STATUS_SUCCESS;
3666 }
3667
3668 RTL_GENERIC_COMPARE_RESULTS
3669 NTAPI
3670 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3671 IN PVOID FirstStruct,
3672 IN PVOID SecondStruct)
3673 {
3674 /* FIXME: TODO */
3675 ASSERT(FALSE);
3676 return 0;
3677 }
3678
3679 //
3680 // The allocation function is called by the generic table package whenever
3681 // it needs to allocate memory for the table.
3682 //
3683
3684 PVOID
3685 NTAPI
3686 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3687 IN CLONG ByteSize)
3688 {
3689 /* FIXME: TODO */
3690 ASSERT(FALSE);
3691 return NULL;
3692 }
3693
3694 VOID
3695 NTAPI
3696 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3697 IN PVOID Buffer)
3698 {
3699 /* FIXME: TODO */
3700 ASSERT(FALSE);
3701 }
3702
3703 VOID
3704 NTAPI
3705 PpInitializeDeviceReferenceTable(VOID)
3706 {
3707 /* Setup the guarded mutex and AVL table */
3708 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3709 RtlInitializeGenericTableAvl(
3710 &PpDeviceReferenceTable,
3711 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3712 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3713 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3714 NULL);
3715 }
3716
3717 BOOLEAN
3718 NTAPI
3719 PiInitPhase0(VOID)
3720 {
3721 /* Initialize the resource when accessing device registry data */
3722 ExInitializeResourceLite(&PpRegistryDeviceResource);
3723
3724 /* Setup the device reference AVL table */
3725 PpInitializeDeviceReferenceTable();
3726 return TRUE;
3727 }
3728
3729 BOOLEAN
3730 NTAPI
3731 PpInitSystem(VOID)
3732 {
3733 /* Check the initialization phase */
3734 switch (ExpInitializationPhase)
3735 {
3736 case 0:
3737
3738 /* Do Phase 0 */
3739 return PiInitPhase0();
3740
3741 case 1:
3742
3743 /* Do Phase 1 */
3744 return TRUE;
3745 //return PiInitPhase1();
3746
3747 default:
3748
3749 /* Don't know any other phase! Bugcheck! */
3750 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3751 return FALSE;
3752 }
3753 }
3754
3755 LONG IopNumberDeviceNodes;
3756
3757 PDEVICE_NODE
3758 NTAPI
3759 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
3760 {
3761 PDEVICE_NODE DeviceNode;
3762 PAGED_CODE();
3763
3764 /* Allocate it */
3765 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), TAG_IO_DEVNODE);
3766 if (!DeviceNode) return DeviceNode;
3767
3768 /* Statistics */
3769 InterlockedIncrement(&IopNumberDeviceNodes);
3770
3771 /* Set it up */
3772 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3773 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3774 DeviceNode->BusNumber = -1;
3775 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3776 DeviceNode->ChildBusNumber = -1;
3777 DeviceNode->ChildBusTypeIndex = -1;
3778 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3779 InitializeListHead(&DeviceNode->DeviceArbiterList);
3780 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3781 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3782 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3783 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3784
3785 /* Check if there is a PDO */
3786 if (PhysicalDeviceObject)
3787 {
3788 /* Link it and remove the init flag */
3789 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3790 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3791 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3792 }
3793
3794 /* Return the node */
3795 return DeviceNode;
3796 }
3797
3798 /* PUBLIC FUNCTIONS **********************************************************/
3799
3800 NTSTATUS
3801 NTAPI
3802 PnpBusTypeGuidGet(IN USHORT Index,
3803 IN LPGUID BusTypeGuid)
3804 {
3805 NTSTATUS Status = STATUS_SUCCESS;
3806
3807 /* Acquire the lock */
3808 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3809
3810 /* Validate size */
3811 if (Index < PnpBusTypeGuidList->GuidCount)
3812 {
3813 /* Copy the data */
3814 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3815 }
3816 else
3817 {
3818 /* Failure path */
3819 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3820 }
3821
3822 /* Release lock and return status */
3823 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3824 return Status;
3825 }
3826
3827 NTSTATUS
3828 NTAPI
3829 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3830 IN PHANDLE DeviceInstanceHandle,
3831 IN ACCESS_MASK DesiredAccess)
3832 {
3833 NTSTATUS Status;
3834 HANDLE KeyHandle;
3835 PDEVICE_NODE DeviceNode;
3836 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3837 PAGED_CODE();
3838
3839 /* Open the enum key */
3840 Status = IopOpenRegistryKeyEx(&KeyHandle,
3841 NULL,
3842 &KeyName,
3843 KEY_READ);
3844 if (!NT_SUCCESS(Status)) return Status;
3845
3846 /* Make sure we have an instance path */
3847 DeviceNode = IopGetDeviceNode(DeviceObject);
3848 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3849 {
3850 /* Get the instance key */
3851 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3852 KeyHandle,
3853 &DeviceNode->InstancePath,
3854 DesiredAccess);
3855 }
3856 else
3857 {
3858 /* Fail */
3859 Status = STATUS_INVALID_DEVICE_REQUEST;
3860 }
3861
3862 /* Close the handle and return status */
3863 ZwClose(KeyHandle);
3864 return Status;
3865 }
3866
3867 ULONG
3868 NTAPI
3869 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3870 {
3871 ULONG FinalSize, PartialSize, EntrySize, i, j;
3872 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3873 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3874
3875 /* If we don't have one, that's easy */
3876 if (!ResourceList) return 0;
3877
3878 /* Start with the minimum size possible */
3879 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3880
3881 /* Loop each full descriptor */
3882 FullDescriptor = ResourceList->List;
3883 for (i = 0; i < ResourceList->Count; i++)
3884 {
3885 /* Start with the minimum size possible */
3886 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3887 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3888
3889 /* Loop each partial descriptor */
3890 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3891 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3892 {
3893 /* Start with the minimum size possible */
3894 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3895
3896 /* Check if there is extra data */
3897 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3898 {
3899 /* Add that data */
3900 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3901 }
3902
3903 /* The size of partial descriptors is bigger */
3904 PartialSize += EntrySize;
3905
3906 /* Go to the next partial descriptor */
3907 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3908 }
3909
3910 /* The size of full descriptors is bigger */
3911 FinalSize += PartialSize;
3912
3913 /* Go to the next full descriptor */
3914 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3915 }
3916
3917 /* Return the final size */
3918 return FinalSize;
3919 }
3920
3921 NTSTATUS
3922 NTAPI
3923 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3924 IN ULONG ValueType,
3925 IN PWSTR ValueName,
3926 IN PWSTR KeyName,
3927 OUT PVOID Buffer,
3928 IN PULONG BufferLength)
3929 {
3930 NTSTATUS Status;
3931 HANDLE KeyHandle, SubHandle;
3932 UNICODE_STRING KeyString;
3933 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3934 ULONG Length;
3935 PAGED_CODE();
3936
3937 /* Find the instance key */
3938 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3939 if (NT_SUCCESS(Status))
3940 {
3941 /* Check for name given by caller */
3942 if (KeyName)
3943 {
3944 /* Open this key */
3945 RtlInitUnicodeString(&KeyString, KeyName);
3946 Status = IopOpenRegistryKeyEx(&SubHandle,
3947 KeyHandle,
3948 &KeyString,
3949 KEY_READ);
3950 if (NT_SUCCESS(Status))
3951 {
3952 /* And use this handle instead */
3953 ZwClose(KeyHandle);
3954 KeyHandle = SubHandle;
3955 }
3956 }
3957
3958 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3959 if (NT_SUCCESS(Status))
3960 {
3961 /* Now get the size of the property */
3962 Status = IopGetRegistryValue(KeyHandle,
3963 ValueName,
3964 &KeyValueInfo);
3965 }
3966
3967 /* Close the key */
3968 ZwClose(KeyHandle);
3969 }
3970
3971 /* Fail if any of the registry operations failed */
3972 if (!NT_SUCCESS(Status)) return Status;
3973
3974 /* Check how much data we have to copy */
3975 Length = KeyValueInfo->DataLength;
3976 if (*BufferLength >= Length)
3977 {
3978 /* Check for a match in the value type */
3979 if (KeyValueInfo->Type == ValueType)
3980 {
3981 /* Copy the data */
3982 RtlCopyMemory(Buffer,
3983 (PVOID)((ULONG_PTR)KeyValueInfo +
3984 KeyValueInfo->DataOffset),
3985 Length);
3986 }
3987 else
3988 {
3989 /* Invalid registry property type, fail */
3990 Status = STATUS_INVALID_PARAMETER_2;
3991 }
3992 }
3993 else
3994 {
3995 /* Buffer is too small to hold data */
3996 Status = STATUS_BUFFER_TOO_SMALL;
3997 }
3998
3999 /* Return the required buffer length, free the buffer, and return status */
4000 *BufferLength = Length;
4001 ExFreePool(KeyValueInfo);
4002 return Status;
4003 }
4004
4005 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
4006 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
4007 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
4008
4009 /*
4010 * @implemented
4011 */
4012 NTSTATUS
4013 NTAPI
4014 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
4015 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
4016 IN ULONG BufferLength,
4017 OUT PVOID PropertyBuffer,
4018 OUT PULONG ResultLength)
4019 {
4020 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4021 DEVICE_CAPABILITIES DeviceCaps;
4022 ULONG ReturnLength = 0, Length = 0, ValueType;
4023 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
4024 PVOID Data = NULL;
4025 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
4026 GUID BusTypeGuid;
4027 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
4028 BOOLEAN NullTerminate = FALSE;
4029
4030 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
4031
4032 /* Assume failure */
4033 *ResultLength = 0;
4034
4035 /* Only PDOs can call this */
4036 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
4037
4038 /* Handle all properties */
4039 switch (DeviceProperty)
4040 {
4041 case DevicePropertyBusTypeGuid:
4042
4043 /* Get the GUID from the internal cache */
4044 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
4045 if (!NT_SUCCESS(Status)) return Status;
4046
4047 /* This is the format of the returned data */
4048 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
4049
4050 case DevicePropertyLegacyBusType:
4051
4052 /* Validate correct interface type */
4053 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
4054 return STATUS_OBJECT_NAME_NOT_FOUND;
4055
4056 /* This is the format of the returned data */
4057 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
4058
4059 case DevicePropertyBusNumber:
4060
4061 /* Validate correct bus number */
4062 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
4063 return STATUS_OBJECT_NAME_NOT_FOUND;
4064
4065 /* This is the format of the returned data */
4066 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
4067
4068 case DevicePropertyEnumeratorName:
4069
4070 /* Get the instance path */
4071 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
4072
4073 /* Sanity checks */
4074 ASSERT((BufferLength & 1) == 0);
4075 ASSERT(DeviceInstanceName != NULL);
4076
4077 /* Get the name from the path */
4078 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
4079 ASSERT(EnumeratorNameEnd);
4080
4081 /* This string needs to be NULL-terminated */
4082 NullTerminate = TRUE;
4083
4084 /* This is the format of the returned data */
4085 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
4086 DeviceInstanceName);
4087
4088 case DevicePropertyAddress:
4089
4090 /* Query the device caps */
4091 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
4092 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
4093 return STATUS_OBJECT_NAME_NOT_FOUND;
4094
4095 /* This is the format of the returned data */
4096 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
4097
4098 case DevicePropertyBootConfigurationTranslated:
4099
4100 /* Validate we have resources */
4101 if (!DeviceNode->BootResources)
4102 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
4103 {
4104 /* No resources will still fake success, but with 0 bytes */
4105 *ResultLength = 0;
4106 return STATUS_SUCCESS;
4107 }
4108
4109 /* This is the format of the returned data */
4110 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
4111 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
4112
4113 case DevicePropertyPhysicalDeviceObjectName:
4114
4115 /* Sanity check for Unicode-sized string */
4116 ASSERT((BufferLength & 1) == 0);
4117
4118 /* Allocate name buffer */
4119 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
4120 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
4121 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
4122
4123 /* Query the PDO name */
4124 Status = ObQueryNameString(DeviceObject,
4125 ObjectNameInfo,
4126 Length,
4127 ResultLength);
4128 if (Status == STATUS_INFO_LENGTH_MISMATCH)
4129 {
4130 /* It's up to the caller to try again */
4131 Status = STATUS_BUFFER_TOO_SMALL;
4132 }
4133
4134 /* This string needs to be NULL-terminated */
4135 NullTerminate = TRUE;
4136
4137 /* Return if successful */
4138 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
4139 ObjectNameInfo->Name.Buffer);
4140
4141 /* Let the caller know how big the name is */
4142 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
4143 break;
4144
4145 /* Handle the registry-based properties */
4146 case DevicePropertyUINumber:
4147 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
4148 case DevicePropertyLocationInformation:
4149 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
4150 case DevicePropertyDeviceDescription:
4151 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
4152 case DevicePropertyHardwareID:
4153 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
4154 case DevicePropertyCompatibleIDs:
4155 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
4156 case DevicePropertyBootConfiguration:
4157 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
4158 case DevicePropertyClassName:
4159 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
4160 case DevicePropertyClassGuid:
4161 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
4162 case DevicePropertyDriverKeyName:
4163 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
4164 case DevicePropertyManufacturer:
4165 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
4166 case DevicePropertyFriendlyName:
4167 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
4168 case DevicePropertyContainerID:
4169 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
4170 PIP_UNIMPLEMENTED();
4171 case DevicePropertyRemovalPolicy:
4172 PIP_UNIMPLEMENTED();
4173 break;
4174 case DevicePropertyInstallState:
4175 PIP_REGISTRY_DATA(REGSTR_VAL_CONFIGFLAGS, REG_DWORD);
4176 break;
4177 case DevicePropertyResourceRequirements:
4178 PIP_UNIMPLEMENTED();
4179 case DevicePropertyAllocatedResources:
4180 PIP_UNIMPLEMENTED();
4181 default:
4182 return STATUS_INVALID_PARAMETER_2;
4183 }
4184
4185 /* Having a registry value name implies registry data */
4186 if (ValueName)
4187 {
4188 /* We know up-front how much data to expect */
4189 *ResultLength = BufferLength;
4190
4191 /* Go get the data, use the LogConf subkey if necessary */
4192 Status = PiGetDeviceRegistryProperty(DeviceObject,
4193 ValueType,
4194 ValueName,
4195 (DeviceProperty ==
4196 DevicePropertyBootConfiguration) ?
4197 L"LogConf": NULL,
4198 PropertyBuffer,
4199 ResultLength);
4200 }
4201 else if (NT_SUCCESS(Status))
4202 {
4203 /* We know up-front how much data to expect, check the caller's buffer */
4204 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
4205 if (*ResultLength <= BufferLength)
4206 {
4207 /* Buffer is all good, copy the data */
4208 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
4209
4210 /* Check if we need to NULL-terminate the string */
4211 if (NullTerminate)
4212 {
4213 /* Terminate the string */
4214 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
4215 }
4216
4217 /* This is the success path */
4218 Status = STATUS_SUCCESS;
4219 }
4220 else
4221 {
4222 /* Failure path */
4223 Status = STATUS_BUFFER_TOO_SMALL;
4224 }
4225 }
4226
4227 /* Free any allocation we may have made, and return the status code */
4228 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
4229 return Status;
4230 }
4231
4232 /*
4233 * @implemented
4234 */
4235 VOID
4236 NTAPI
4237 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
4238 {
4239 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4240 IO_STACK_LOCATION Stack;
4241 ULONG PnPFlags;
4242 NTSTATUS Status;
4243 IO_STATUS_BLOCK IoStatusBlock;
4244
4245 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
4246 Stack.MajorFunction = IRP_MJ_PNP;
4247 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
4248
4249 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
4250 if (!NT_SUCCESS(Status))
4251 {
4252 if (Status != STATUS_NOT_SUPPORTED)
4253 {
4254 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status);
4255 }
4256 return;
4257 }
4258
4259 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
4260 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
4261 else
4262 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
4263
4264 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
4265 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
4266 else
4267 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
4268
4269 if ((PnPFlags & PNP_DEVICE_REMOVED) ||
4270 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
4271 {
4272 /* Flag it if it's failed */
4273 if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START;
4274
4275 /* Send removal IRPs to all of its children */
4276 IopPrepareDeviceForRemoval(PhysicalDeviceObject, TRUE);
4277
4278 /* Send surprise removal */
4279 IopSendSurpriseRemoval(PhysicalDeviceObject);
4280
4281 /* Tell the user-mode PnP manager that a device was removed */
4282 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
4283 &DeviceNode->InstancePath);
4284
4285 IopSendRemoveDevice(PhysicalDeviceObject);
4286 }
4287 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
4288 {
4289 /* Stop for resource rebalance */
4290 Status = IopStopDevice(DeviceNode);
4291 if (!NT_SUCCESS(Status))
4292 {
4293 DPRINT1("Failed to stop device for rebalancing\n");
4294
4295 /* Stop failed so don't rebalance */
4296 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED;
4297 }
4298 }
4299
4300 /* Resource rebalance */
4301 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
4302 {
4303 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4304
4305 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4306 &IoStatusBlock,
4307 IRP_MN_QUERY_RESOURCES,
4308 NULL);
4309 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
4310 {
4311 DeviceNode->BootResources =
4312 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
4313 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
4314 }
4315 else
4316 {
4317 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
4318 DeviceNode->BootResources = NULL;
4319 }
4320
4321 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4322
4323 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4324 &IoStatusBlock,
4325 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
4326 NULL);
4327 if (NT_SUCCESS(Status))
4328 {
4329 DeviceNode->ResourceRequirements =
4330 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
4331 }
4332 else
4333 {
4334 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
4335 DeviceNode->ResourceRequirements = NULL;
4336 }
4337
4338 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4339 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS)
4340 {
4341 DPRINT1("Restart after resource rebalance failed\n");
4342
4343 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
4344 DeviceNode->Flags |= DNF_START_FAILED;
4345
4346 IopRemoveDevice(DeviceNode);
4347 }
4348 }
4349 }
4350
4351 /**
4352 * @name IoOpenDeviceRegistryKey
4353 *
4354 * Open a registry key unique for a specified driver or device instance.
4355 *
4356 * @param DeviceObject Device to get the registry key for.
4357 * @param DevInstKeyType Type of the key to return.
4358 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4359 * @param DevInstRegKey Handle to the opened registry key on
4360 * successful return.
4361 *
4362 * @return Status.
4363 *
4364 * @implemented
4365 */
4366 NTSTATUS
4367 NTAPI
4368 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
4369 IN ULONG DevInstKeyType,
4370 IN ACCESS_MASK DesiredAccess,
4371 OUT PHANDLE DevInstRegKey)
4372 {
4373 static WCHAR RootKeyName[] =
4374 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4375 static WCHAR ProfileKeyName[] =
4376 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4377 static WCHAR ClassKeyName[] = L"Control\\Class\\";
4378 static WCHAR EnumKeyName[] = L"Enum\\";
4379 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4380 ULONG KeyNameLength;
4381 PWSTR KeyNameBuffer;
4382 UNICODE_STRING KeyName;
4383 ULONG DriverKeyLength;
4384 OBJECT_ATTRIBUTES ObjectAttributes;
4385 PDEVICE_NODE DeviceNode = NULL;
4386 NTSTATUS Status;
4387
4388 DPRINT("IoOpenDeviceRegistryKey() called\n");
4389
4390 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
4391 {
4392 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4393 return STATUS_INVALID_PARAMETER;
4394 }
4395
4396 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
4397 return STATUS_INVALID_DEVICE_REQUEST;
4398 DeviceNode = IopGetDeviceNode(DeviceObject);
4399
4400 /*
4401 * Calculate the length of the base key name. This is the full
4402 * name for driver key or the name excluding "Device Parameters"
4403 * subkey for device key.
4404 */
4405
4406 KeyNameLength = sizeof(RootKeyName);
4407 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4408 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4409 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4410 {
4411 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4412 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4413 0, NULL, &DriverKeyLength);
4414 if (Status != STATUS_BUFFER_TOO_SMALL)
4415 return Status;
4416 KeyNameLength += DriverKeyLength;
4417 }
4418 else
4419 {
4420 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4421 DeviceNode->InstancePath.Length;
4422 }
4423
4424 /*
4425 * Now allocate the buffer for the key name...
4426 */
4427
4428 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4429 if (KeyNameBuffer == NULL)
4430 return STATUS_INSUFFICIENT_RESOURCES;
4431
4432 KeyName.Length = 0;
4433 KeyName.MaximumLength = (USHORT)KeyNameLength;
4434 KeyName.Buffer = KeyNameBuffer;
4435
4436 /*
4437 * ...and build the key name.
4438 */
4439
4440 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4441 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4442
4443 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4444 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4445
4446 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4447 {
4448 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4449 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4450 DriverKeyLength, KeyNameBuffer +
4451 (KeyName.Length / sizeof(WCHAR)),
4452 &DriverKeyLength);
4453 if (!NT_SUCCESS(Status))
4454 {
4455 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4456 ExFreePool(KeyNameBuffer);
4457 return Status;
4458 }
4459 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4460 }
4461 else
4462 {
4463 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4464 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
4465 if (DeviceNode->InstancePath.Length == 0)
4466 {
4467 ExFreePool(KeyNameBuffer);
4468 return Status;
4469 }
4470 }
4471
4472 /*
4473 * Open the base key.
4474 */
4475 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
4476 if (!NT_SUCCESS(Status))
4477 {
4478 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4479 ExFreePool(KeyNameBuffer);
4480 return Status;
4481 }
4482 ExFreePool(KeyNameBuffer);
4483
4484 /*
4485 * For driver key we're done now.
4486 */
4487
4488 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4489 return Status;
4490
4491 /*
4492 * Let's go further. For device key we must open "Device Parameters"
4493 * subkey and create it if it doesn't exist yet.
4494 */
4495
4496 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4497 InitializeObjectAttributes(&ObjectAttributes,
4498 &KeyName,
4499 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4500 *DevInstRegKey,
4501 NULL);
4502 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
4503 0, NULL, ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, NULL);
4504 ZwClose(ObjectAttributes.RootDirectory);
4505
4506 return Status;
4507 }
4508
4509 static
4510 NTSTATUS
4511 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force)
4512 {
4513 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
4514 NTSTATUS Status;
4515 KIRQL OldIrql;
4516
4517 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4518 ChildDeviceNode = ParentDeviceNode->Child;
4519 while (ChildDeviceNode != NULL)
4520 {
4521 NextDeviceNode = ChildDeviceNode->Sibling;
4522 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4523
4524 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force);
4525 if (!NT_SUCCESS(Status))
4526 {
4527 FailedRemoveDevice = ChildDeviceNode;
4528 goto cleanup;
4529 }
4530
4531 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4532 ChildDeviceNode = NextDeviceNode;
4533 }
4534 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4535
4536 return STATUS_SUCCESS;
4537
4538 cleanup:
4539 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4540 ChildDeviceNode = ParentDeviceNode->Child;
4541 while (ChildDeviceNode != NULL)
4542 {
4543 NextDeviceNode = ChildDeviceNode->Sibling;
4544 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4545
4546 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4547
4548 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4549 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4550 if (ChildDeviceNode == FailedRemoveDevice)
4551 return Status;
4552
4553 ChildDeviceNode = NextDeviceNode;
4554
4555 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4556 }
4557 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4558
4559 return Status;
4560 }
4561
4562 static
4563 VOID
4564 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4565 {
4566 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4567 KIRQL OldIrql;
4568
4569 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4570 ChildDeviceNode = ParentDeviceNode->Child;
4571 while (ChildDeviceNode != NULL)
4572 {
4573 NextDeviceNode = ChildDeviceNode->Sibling;
4574 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4575
4576 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
4577
4578 ChildDeviceNode = NextDeviceNode;
4579
4580 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4581 }
4582 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4583 }
4584
4585 static
4586 VOID
4587 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4588 {
4589 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4590 KIRQL OldIrql;
4591
4592 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4593 ChildDeviceNode = ParentDeviceNode->Child;
4594 while (ChildDeviceNode != NULL)
4595 {
4596 NextDeviceNode = ChildDeviceNode->Sibling;
4597 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4598
4599 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4600
4601 ChildDeviceNode = NextDeviceNode;
4602
4603 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4604 }
4605 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4606 }
4607
4608 static
4609 NTSTATUS
4610 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force)
4611 {
4612 /* This function DOES NOT dereference the device objects on SUCCESS
4613 * but it DOES dereference device objects on FAILURE */
4614
4615 ULONG i, j;
4616 NTSTATUS Status;
4617
4618 for (i = 0; i < DeviceRelations->Count; i++)
4619 {
4620 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force);
4621 if (!NT_SUCCESS(Status))
4622 {
4623 j = i;
4624 goto cleanup;
4625 }
4626 }
4627
4628 return STATUS_SUCCESS;
4629
4630 cleanup:
4631 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4632 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4633 for (i = 0; i <= j; i++)
4634 {
4635 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4636 ObDereferenceObject(DeviceRelations->Objects[i]);
4637 DeviceRelations->Objects[i] = NULL;
4638 }
4639 for (; i < DeviceRelations->Count; i++)
4640 {
4641 ObDereferenceObject(DeviceRelations->Objects[i]);
4642 DeviceRelations->Objects[i] = NULL;
4643 }
4644 ExFreePool(DeviceRelations);
4645
4646 return Status;
4647 }
4648
4649 static
4650 VOID
4651 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4652 {
4653 /* This function DOES dereference the device objects in all cases */
4654
4655 ULONG i;
4656
4657 for (i = 0; i < DeviceRelations->Count; i++)
4658 {
4659 IopSendRemoveDevice(DeviceRelations->Objects[i]);
4660 DeviceRelations->Objects[i] = NULL;
4661 }
4662
4663 ExFreePool(DeviceRelations);
4664 }
4665
4666 static
4667 VOID
4668 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4669 {
4670 /* This function DOES dereference the device objects in all cases */
4671
4672 ULONG i;
4673
4674 for (i = 0; i < DeviceRelations->Count; i++)
4675 {
4676 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4677 ObDereferenceObject(DeviceRelations->Objects[i]);
4678 DeviceRelations->Objects[i] = NULL;
4679 }
4680
4681 ExFreePool(DeviceRelations);
4682 }
4683
4684 VOID
4685 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
4686 {
4687 IO_STACK_LOCATION Stack;
4688 IO_STATUS_BLOCK IoStatusBlock;
4689 PDEVICE_RELATIONS DeviceRelations;
4690 NTSTATUS Status;
4691
4692 IopCancelRemoveDevice(DeviceObject);
4693
4694 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4695
4696 Status = IopInitiatePnpIrp(DeviceObject,
4697 &IoStatusBlock,
4698 IRP_MN_QUERY_DEVICE_RELATIONS,
4699 &Stack);
4700 if (!NT_SUCCESS(Status))
4701 {
4702 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4703 DeviceRelations = NULL;
4704 }
4705 else
4706 {
4707 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4708 }
4709
4710 if (DeviceRelations)
4711 IopCancelRemoveDeviceRelations(DeviceRelations);
4712 }
4713
4714 NTSTATUS
4715 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force)
4716 {
4717 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4718 IO_STACK_LOCATION Stack;
4719 IO_STATUS_BLOCK IoStatusBlock;
4720 PDEVICE_RELATIONS DeviceRelations;
4721 NTSTATUS Status;
4722
4723 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force)
4724 {
4725 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
4726 return STATUS_UNSUCCESSFUL;
4727 }
4728
4729 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
4730 {
4731 DPRINT1("Removal vetoed by failing the query remove request\n");
4732
4733 IopCancelRemoveDevice(DeviceObject);
4734
4735 return STATUS_UNSUCCESSFUL;
4736 }
4737
4738 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4739
4740 Status = IopInitiatePnpIrp(DeviceObject,
4741 &IoStatusBlock,
4742 IRP_MN_QUERY_DEVICE_RELATIONS,
4743 &Stack);
4744 if (!NT_SUCCESS(Status))
4745 {
4746 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4747 DeviceRelations = NULL;
4748 }
4749 else
4750 {
4751 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4752 }
4753
4754 if (DeviceRelations)
4755 {
4756 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force);
4757 if (!NT_SUCCESS(Status))
4758 return Status;
4759 }
4760
4761 Status = IopQueryRemoveChildDevices(DeviceNode, Force);
4762 if (!NT_SUCCESS(Status))
4763 {
4764 if (DeviceRelations)
4765 IopCancelRemoveDeviceRelations(DeviceRelations);
4766 return Status;
4767 }
4768
4769 if (DeviceRelations)
4770 IopSendRemoveDeviceRelations(DeviceRelations);
4771 IopSendRemoveChildDevices(DeviceNode);
4772
4773 return STATUS_SUCCESS;
4774 }
4775
4776 NTSTATUS
4777 IopRemoveDevice(PDEVICE_NODE DeviceNode)
4778 {
4779 NTSTATUS Status;
4780
4781 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
4782
4783 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE);
4784 if (NT_SUCCESS(Status))
4785 {
4786 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
4787 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
4788 &DeviceNode->InstancePath);
4789 return STATUS_SUCCESS;
4790 }
4791
4792 return Status;
4793 }
4794
4795 /*
4796 * @implemented
4797 */
4798 VOID
4799 NTAPI
4800 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
4801 {
4802 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4803 PDEVICE_RELATIONS DeviceRelations;
4804 IO_STATUS_BLOCK IoStatusBlock;
4805 IO_STACK_LOCATION Stack;
4806 DEVICE_CAPABILITIES Capabilities;
4807 NTSTATUS Status;
4808
4809 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
4810 &DeviceNode->InstancePath);
4811
4812 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
4813 {
4814 goto cleanup;
4815 }
4816
4817 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
4818
4819 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4820 &IoStatusBlock,
4821 IRP_MN_QUERY_DEVICE_RELATIONS,
4822 &Stack);
4823 if (!NT_SUCCESS(Status))
4824 {
4825 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4826 DeviceRelations = NULL;
4827 }
4828 else
4829 {
4830 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4831 }
4832
4833 if (DeviceRelations)
4834 {
4835 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE);
4836 if (!NT_SUCCESS(Status))
4837 goto cleanup;
4838 }
4839
4840 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE);
4841 if (!NT_SUCCESS(Status))
4842 {
4843 if (DeviceRelations)
4844 IopCancelRemoveDeviceRelations(DeviceRelations);
4845 goto cleanup;
4846 }
4847
4848 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS)
4849 {
4850 if (DeviceRelations)
4851 IopCancelRemoveDeviceRelations(DeviceRelations);
4852 IopCancelRemoveChildDevices(DeviceNode);
4853 goto cleanup;
4854 }
4855
4856 if (DeviceRelations)
4857 IopSendRemoveDeviceRelations(DeviceRelations);
4858 IopSendRemoveChildDevices(DeviceNode);
4859
4860 DeviceNode->Problem = CM_PROB_HELD_FOR_EJECT;
4861 if (Capabilities.EjectSupported)
4862 {
4863 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
4864 {
4865 goto cleanup;
4866 }
4867 }
4868 else
4869 {
4870 DeviceNode->Flags |= DNF_DISABLED;
4871 }
4872
4873 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
4874 &DeviceNode->InstancePath);
4875
4876 return;
4877
4878 cleanup:
4879 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
4880 &DeviceNode->InstancePath);
4881 }
4882
4883 /*
4884 * @implemented
4885 */
4886 VOID
4887 NTAPI
4888 IoInvalidateDeviceRelations(
4889 IN PDEVICE_OBJECT DeviceObject,
4890 IN DEVICE_RELATION_TYPE Type)
4891 {
4892 PDEVICE_ACTION_DATA Data;
4893 KIRQL OldIrql;
4894
4895 Data = ExAllocatePoolWithTag(NonPagedPool,
4896 sizeof(DEVICE_ACTION_DATA),
4897 TAG_IO);
4898 if (!Data)
4899 return;
4900
4901 ObReferenceObject(DeviceObject);
4902 Data->DeviceObject = DeviceObject;
4903 Data->Type = Type;
4904
4905 KeAcquireSpinLock(&IopDeviceActionLock, &OldIrql);
4906 InsertTailList(&IopDeviceActionRequestList, &Data->RequestListEntry);
4907 if (IopDeviceActionInProgress)
4908 {
4909 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
4910 return;
4911 }
4912 IopDeviceActionInProgress = TRUE;
4913 KeReleaseSpinLock(&IopDeviceActionLock, OldIrql);
4914
4915 ExInitializeWorkItem(&IopDeviceActionWorkItem,
4916 IopDeviceActionWorker,
4917 NULL);
4918 ExQueueWorkItem(&IopDeviceActionWorkItem,
4919 DelayedWorkQueue);
4920 }
4921
4922 /*
4923 * @implemented
4924 */
4925 NTSTATUS
4926 NTAPI
4927 IoSynchronousInvalidateDeviceRelations(
4928 IN PDEVICE_OBJECT DeviceObject,
4929 IN DEVICE_RELATION_TYPE Type)
4930 {
4931 PAGED_CODE();
4932
4933 switch (Type)
4934 {
4935 case BusRelations:
4936 /* Enumerate the device */
4937 return IopEnumerateDevice(DeviceObject);
4938 case PowerRelations:
4939 /* Not handled yet */
4940 return STATUS_NOT_IMPLEMENTED;
4941 case TargetDeviceRelation:
4942 /* Nothing to do */
4943 return STATUS_SUCCESS;
4944 default:
4945 /* Ejection relations are not supported */
4946 return STATUS_NOT_SUPPORTED;
4947 }
4948 }
4949
4950 /*
4951 * @implemented
4952 */
4953 BOOLEAN
4954 NTAPI
4955 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
4956 IN ULONG BusNumber,
4957 IN PHYSICAL_ADDRESS BusAddress,
4958 IN OUT PULONG AddressSpace,
4959 OUT PPHYSICAL_ADDRESS TranslatedAddress)
4960 {
4961 /* FIXME: Notify the resource arbiter */
4962
4963 return HalTranslateBusAddress(InterfaceType,
4964 BusNumber,
4965 BusAddress,
4966 AddressSpace,
4967 TranslatedAddress);
4968 }