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