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