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