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