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