ReactOS  0.4.13-dev-464-g6b95727
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) + sizeof(L"12345678&12345678");
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  UNICODE_STRING RegKey;
2858 
2859  /* Install the service for this if it's in the CDDB */
2861 
2862  /*
2863  * Retrieve configuration from Enum key
2864  */
2865 
2866  Service = &DeviceNode->ServiceName;
2867 
2871 
2872  QueryTable[0].Name = L"Service";
2875 
2876  QueryTable[1].Name = L"ClassGUID";
2880  QueryTable[1].DefaultData = L"";
2881  QueryTable[1].DefaultLength = 0;
2882 
2883  RegKey.Length = 0;
2884  RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) + DeviceNode->InstancePath.Length;
2886  RegKey.MaximumLength,
2887  TAG_IO);
2888  if (RegKey.Buffer == NULL)
2889  {
2892  }
2893 
2895  RtlAppendUnicodeToString(&RegKey, L"\\");
2896  RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2897 
2899  RegKey.Buffer, QueryTable, NULL, NULL);
2900  ExFreePoolWithTag(RegKey.Buffer, TAG_IO);
2901 
2902  if (!NT_SUCCESS(Status))
2903  {
2904  /* FIXME: Log the error */
2905  DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2906  &DeviceNode->InstancePath, Status);
2908  return STATUS_SUCCESS;
2909  }
2910 
2911  if (Service->Buffer == NULL)
2912  {
2913  if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2914  DeviceCaps.RawDeviceOK)
2915  {
2916  DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2917  RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0);
2918  }
2919  else if (ClassGUID.Length != 0)
2920  {
2921  /* Device has a ClassGUID value, but no Service value.
2922  * Suppose it is using the NULL driver, so state the
2923  * device is started */
2924  DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2926  }
2927  else
2928  {
2931  }
2932  return STATUS_SUCCESS;
2933  }
2934 
2935  DPRINT("Got Service %S\n", Service->Buffer);
2936  }
2937 
2938  return STATUS_SUCCESS;
2939 }
2940 
2941 /*
2942  * IopActionInitChildServices
2943  *
2944  * Initialize the service for all (direct) child nodes of a parent node
2945  *
2946  * Parameters
2947  * DeviceNode
2948  * Pointer to device node.
2949  * Context
2950  * Pointer to parent node to initialize child node services for.
2951  *
2952  * Remarks
2953  * If the driver image for a service is not loaded and initialized
2954  * it is done here too. Any errors that occur are logged instead so
2955  * that all child services have a chance of being initialized.
2956  */
2957 
2958 NTSTATUS
2960  PVOID Context)
2961 {
2962  PDEVICE_NODE ParentDeviceNode;
2963  NTSTATUS Status;
2964  BOOLEAN BootDrivers = !PnpSystemInit;
2965 
2966  DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2967 
2968  ParentDeviceNode = Context;
2969 
2970  /*
2971  * We are called for the parent too, but we don't need to do special
2972  * handling for this node
2973  */
2974  if (DeviceNode == ParentDeviceNode)
2975  {
2976  DPRINT("Success\n");
2977  return STATUS_SUCCESS;
2978  }
2979 
2980  /*
2981  * We don't want to check for a direct child because
2982  * this function is called during boot to reinitialize
2983  * devices with drivers that couldn't load yet due to
2984  * stage 0 limitations (ie can't load from disk yet).
2985  */
2986 
2987  if (!(DeviceNode->Flags & DNF_PROCESSED))
2988  {
2989  DPRINT1("Child not ready to be added\n");
2990  return STATUS_SUCCESS;
2991  }
2992 
2996  return STATUS_SUCCESS;
2997 
2998  if (DeviceNode->ServiceName.Buffer == NULL)
2999  {
3000  /* We don't need to worry about loading the driver because we're
3001  * being driven in raw mode so our parent must be loaded to get here */
3003  if (NT_SUCCESS(Status))
3004  {
3006  if (!NT_SUCCESS(Status))
3007  {
3008  DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
3009  &DeviceNode->InstancePath, Status);
3010  }
3011  }
3012  }
3013  else
3014  {
3015  PLDR_DATA_TABLE_ENTRY ModuleObject;
3017 
3020  /* Get existing DriverObject pointer (in case the driver has
3021  already been loaded and initialized) */
3023  &DriverObject,
3024  &DeviceNode->ServiceName,
3025  FALSE);
3026 
3027  if (!NT_SUCCESS(Status))
3028  {
3029  /* Driver is not initialized, try to load it */
3030  Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
3031 
3033  {
3034  /* Initialize the driver */
3036  &DeviceNode->ServiceName, FALSE, &DriverObject);
3038  }
3040  {
3041  DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
3043  }
3044  else
3045  {
3046  DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
3047  &DeviceNode->ServiceName, Status);
3048  if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
3049  }
3050  }
3053 
3054  /* Driver is loaded and initialized at this point */
3055  if (NT_SUCCESS(Status))
3056  {
3057  /* Initialize the device, including all filters */
3059 
3060  /* Remove the extra reference */
3062  }
3063  else
3064  {
3065  /*
3066  * Don't disable when trying to load only boot drivers
3067  */
3068  if (!BootDrivers)
3069  {
3071  }
3072  }
3073  }
3074 
3075  return STATUS_SUCCESS;
3076 }
3077 
3078 /*
3079  * IopInitializePnpServices
3080  *
3081  * Initialize services for discovered children
3082  *
3083  * Parameters
3084  * DeviceNode
3085  * Top device node to start initializing services.
3086  *
3087  * Return Value
3088  * Status
3089  */
3090 NTSTATUS
3092 {
3094 
3095  DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
3096 
3098  &Context,
3099  DeviceNode,
3101  DeviceNode);
3102 
3103  return IopTraverseDeviceTree(&Context);
3104 }
3105 
3106 static
3107 INIT_FUNCTION
3108 NTSTATUS
3110  IN HANDLE hBaseKey,
3111  IN PUNICODE_STRING RelativePath OPTIONAL,
3112  IN HANDLE hRootKey,
3113  IN BOOLEAN EnumerateSubKeys,
3114  IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
3115  IN ULONG ParentBootResourcesLength)
3116 {
3117  UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3118  UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3119  UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
3120  UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
3121  UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
3123  HANDLE hDevicesKey = NULL;
3124  HANDLE hDeviceKey = NULL;
3125  HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
3126  UNICODE_STRING Level2NameU;
3127  WCHAR Level2Name[5];
3128  ULONG IndexDevice = 0;
3129  ULONG IndexSubKey;
3130  PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3131  ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3132  PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3133  ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3136  PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
3137  ULONG BootResourcesLength;
3138  NTSTATUS Status;
3139 
3140  const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
3141  UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
3142  static ULONG DeviceIndexSerial = 0;
3143  const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
3144  UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
3145  static ULONG DeviceIndexKeyboard = 0;
3146  const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
3147  UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
3148  static ULONG DeviceIndexMouse = 0;
3149  const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
3150  UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
3151  static ULONG DeviceIndexParallel = 0;
3152  const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
3153  UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
3154  static ULONG DeviceIndexFloppy = 0;
3155  UNICODE_STRING HardwareIdKey;
3156  PUNICODE_STRING pHardwareId;
3157  ULONG DeviceIndex = 0;
3158  PUCHAR CmResourceList;
3159  ULONG ListCount;
3160 
3161  if (RelativePath)
3162  {
3163  Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
3164  if (!NT_SUCCESS(Status))
3165  {
3166  DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3167  goto cleanup;
3168  }
3169  }
3170  else
3171  hDevicesKey = hBaseKey;
3172 
3173  pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3174  if (!pDeviceInformation)
3175  {
3176  DPRINT("ExAllocatePool() failed\n");
3178  goto cleanup;
3179  }
3180 
3181  pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3182  if (!pValueInformation)
3183  {
3184  DPRINT("ExAllocatePool() failed\n");
3186  goto cleanup;
3187  }
3188 
3189  while (TRUE)
3190  {
3191  Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3193  break;
3195  {
3196  ExFreePool(pDeviceInformation);
3197  DeviceInfoLength = RequiredSize;
3198  pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3199  if (!pDeviceInformation)
3200  {
3201  DPRINT("ExAllocatePool() failed\n");
3203  goto cleanup;
3204  }
3205  Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3206  }
3207  if (!NT_SUCCESS(Status))
3208  {
3209  DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3210  goto cleanup;
3211  }
3212  IndexDevice++;
3213 
3214  /* Open device key */
3215  DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3216  DeviceName.Buffer = pDeviceInformation->Name;
3217 
3218  Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3219  KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3220  if (!NT_SUCCESS(Status))
3221  {
3222  DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3223  goto cleanup;
3224  }
3225 
3226  /* Read boot resources, and add then to parent ones */
3227  Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3229  {
3230  ExFreePool(pValueInformation);
3231  ValueInfoLength = RequiredSize;
3232  pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3233  if (!pValueInformation)
3234  {
3235  DPRINT("ExAllocatePool() failed\n");
3236  ZwDeleteKey(hLevel2Key);
3238  goto cleanup;
3239  }
3240  Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3241  }
3243  {
3244  BootResources = ParentBootResources;
3245  BootResourcesLength = ParentBootResourcesLength;
3246  }
3247  else if (!NT_SUCCESS(Status))
3248  {
3249  DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3250  goto nextdevice;
3251  }
3252  else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3253  {
3254  DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3255  goto nextdevice;
3256  }
3257  else
3258  {
3259  static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3260 
3261  /* Concatenate current resources and parent ones */
3262  if (ParentBootResourcesLength == 0)
3263  BootResourcesLength = pValueInformation->DataLength;
3264  else
3265  BootResourcesLength = ParentBootResourcesLength
3266  + pValueInformation->DataLength
3267  - Header;
3268  BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3269  if (!BootResources)
3270  {
3271  DPRINT("ExAllocatePool() failed\n");
3272  goto nextdevice;
3273  }
3274  if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3275  {
3276  RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3277  }
3278  else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3279  {
3280  RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3281  RtlCopyMemory(
3282  (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3283  (PVOID)((ULONG_PTR)ParentBootResources + Header),
3284  ParentBootResourcesLength - Header);
3285  BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3286  }
3287  else
3288  {
3289  RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3290  RtlCopyMemory(
3291  (PVOID)((ULONG_PTR)BootResources + Header),
3292  (PVOID)((ULONG_PTR)ParentBootResources + Header),
3293  ParentBootResourcesLength - Header);
3294  RtlCopyMemory(
3295  (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3296  pValueInformation->Data + Header,
3297  pValueInformation->DataLength - Header);
3298  BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3299  }
3300  }
3301 
3302  if (EnumerateSubKeys)
3303  {
3304  IndexSubKey = 0;
3305  while (TRUE)
3306  {
3307  Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3309  break;
3311  {
3312  ExFreePool(pDeviceInformation);
3313  DeviceInfoLength = RequiredSize;
3314  pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3315  if (!pDeviceInformation)
3316  {
3317  DPRINT("ExAllocatePool() failed\n");
3319  goto cleanup;
3320  }
3321  Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3322  }
3323  if (!NT_SUCCESS(Status))
3324  {
3325  DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3326  goto cleanup;
3327  }
3328  IndexSubKey++;
3329  DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3330  DeviceName.Buffer = pDeviceInformation->Name;
3331 
3333  hDeviceKey,
3334  &DeviceName,
3335  hRootKey,
3336  TRUE,
3337  BootResources,
3338  BootResourcesLength);
3339  if (!NT_SUCCESS(Status))
3340  goto cleanup;
3341  }
3342  }
3343 
3344  /* Read identifier */
3345  Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3347  {
3348  ExFreePool(pValueInformation);
3349  ValueInfoLength = RequiredSize;
3350  pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3351  if (!pValueInformation)
3352  {
3353  DPRINT("ExAllocatePool() failed\n");
3355  goto cleanup;
3356  }
3357  Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3358  }
3359  if (!NT_SUCCESS(Status))
3360  {
3362  {
3363  DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3364  goto nextdevice;
3365  }
3367  }
3368  else if (pValueInformation->Type != REG_SZ)
3369  {
3370  DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3371  goto nextdevice;
3372  }
3373  else
3374  {
3375  /* Assign hardware id to this device */
3376  ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3377  ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3378  if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3379  ValueName.Length -= sizeof(WCHAR);
3380  }
3381 
3382  if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3383  {
3384  pHardwareId = &HardwareIdSerial;
3385  DeviceIndex = DeviceIndexSerial++;
3386  }
3387  else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3388  {
3389  pHardwareId = &HardwareIdKeyboard;
3390  DeviceIndex = DeviceIndexKeyboard++;
3391  }
3392  else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3393  {
3394  pHardwareId = &HardwareIdMouse;
3395  DeviceIndex = DeviceIndexMouse++;
3396  }
3397  else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3398  {
3399  pHardwareId = &HardwareIdParallel;
3400  DeviceIndex = DeviceIndexParallel++;
3401  }
3402  else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3403  {
3404  pHardwareId = &HardwareIdFloppy;
3405  DeviceIndex = DeviceIndexFloppy++;
3406  }
3407  else
3408  {
3409  /* Unknown key path */
3410  DPRINT("Unknown key path '%wZ'\n", RelativePath);
3411  goto nextdevice;
3412  }
3413 
3414  /* Prepare hardware id key (hardware id value without final \0) */
3415  HardwareIdKey = *pHardwareId;
3416  HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3417 
3418  /* Add the detected device to Root key */
3419  InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3420  Status = ZwCreateKey(
3421  &hLevel1Key,
3424  0,
3425  NULL,
3427  NULL);
3428  if (!NT_SUCCESS(Status))
3429  {
3430  DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3431  goto nextdevice;
3432  }
3433  swprintf(Level2Name, L"%04lu", DeviceIndex);
3434  RtlInitUnicodeString(&Level2NameU, Level2Name);
3435  InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3436  Status = ZwCreateKey(
3437  &hLevel2Key,
3440  0,
3441  NULL,
3443  NULL);
3444  ZwClose(hLevel1Key);
3445  if (!NT_SUCCESS(Status))
3446  {
3447  DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3448  goto nextdevice;
3449  }
3450  DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3451  Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3452  if (!NT_SUCCESS(Status))
3453  {
3454  DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3455  ZwDeleteKey(hLevel2Key);
3456  goto nextdevice;
3457  }
3458  /* Create 'LogConf' subkey */
3460  Status = ZwCreateKey(
3461  &hLogConf,
3462  KEY_SET_VALUE,
3464  0,
3465  NULL,
3467  NULL);
3468  if (!NT_SUCCESS(Status))
3469  {
3470  DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3471  ZwDeleteKey(hLevel2Key);
3472  goto nextdevice;
3473  }
3474  if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3475  {
3476  CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3477  if (!CmResourceList)
3478  {
3479  ZwClose(hLogConf);
3480  ZwDeleteKey(hLevel2Key);
3481  goto nextdevice;
3482  }
3483 
3484  /* Add the list count (1st member of CM_RESOURCE_LIST) */
3485  ListCount = 1;
3486  RtlCopyMemory(CmResourceList,
3487  &ListCount,
3488  sizeof(ULONG));
3489 
3490  /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3491  RtlCopyMemory(CmResourceList + sizeof(ULONG),
3492  BootResources,
3493  BootResourcesLength);
3494 
3495  /* Save boot resources to 'LogConf\BootConfig' */
3496  Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3497  if (!NT_SUCCESS(Status))
3498  {
3499  DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3500  ZwClose(hLogConf);
3501  ZwDeleteKey(hLevel2Key);
3502  goto nextdevice;
3503  }
3504  }
3505  ZwClose(hLogConf);
3506 
3507 nextdevice:
3508  if (BootResources && BootResources != ParentBootResources)
3509  {
3510  ExFreePool(BootResources);
3511  BootResources = NULL;
3512  }
3513  if (hLevel2Key)
3514  {
3515  ZwClose(hLevel2Key);
3516  hLevel2Key = NULL;
3517  }
3518  if (hDeviceKey)
3519  {
3520  ZwClose(hDeviceKey);
3521  hDeviceKey = NULL;
3522  }
3523  }
3524 
3526 
3527 cleanup:
3528  if (hDevicesKey && hDevicesKey != hBaseKey)
3529  ZwClose(hDevicesKey);
3530  if (hDeviceKey)
3531  ZwClose(hDeviceKey);
3532  if (pDeviceInformation)
3533  ExFreePool(pDeviceInformation);
3534  if (pValueInformation)
3535  ExFreePool(pValueInformation);
3536  return Status;
3537 }
3538 
3539 static
3540 INIT_FUNCTION
3541 BOOLEAN
3543 {
3544  UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3545  UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3547  HANDLE hPnpKey;
3548  PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3549  ULONG DesiredLength, Length;
3550  ULONG KeyValue = 0;
3551  NTSTATUS Status;
3552 
3554  Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3555  if (NT_SUCCESS(Status))
3556  {
3557  Status = ZwQueryValueKey(hPnpKey,
3558  &KeyNameU,
3560  NULL,
3561  0,
3562  &DesiredLength);
3563  if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3565  {
3566  Length = DesiredLength;
3567  KeyInformation = ExAllocatePool(PagedPool, Length);
3568  if (KeyInformation)
3569  {
3570  Status = ZwQueryValueKey(hPnpKey,
3571  &KeyNameU,
3573  KeyInformation,
3574  Length,
3575  &DesiredLength);
3576  if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3577  {
3578  KeyValue = (ULONG)(*KeyInformation->Data);
3579  }
3580  else
3581  {
3582  DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3583  }
3584 
3585  ExFreePool(KeyInformation);
3586  }
3587  else
3588  {
3589  DPRINT1("Failed to allocate memory for registry query\n");
3590  }
3591  }
3592  else
3593  {
3594  DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3595  }
3596 
3597  ZwClose(hPnpKey);
3598  }
3599  else
3600  {
3601  DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3602  }
3603 
3604  DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3605 
3606  return (KeyValue != 0) ? TRUE : FALSE;
3607 }
3608 
3609 INIT_FUNCTION
3610 NTSTATUS
3611 NTAPI
3613 {
3614  UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3615  UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3616  UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3618  HANDLE hEnum, hRoot;
3619  NTSTATUS Status;
3620 
3623  if (!NT_SUCCESS(Status))
3624  {
3625  DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3626  return Status;
3627  }
3628 
3631  ZwClose(hEnum);
3632  if (!NT_SUCCESS(Status))
3633  {
3634  DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3635  return Status;
3636  }
3637 
3639  {
3640  Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3641  if (!NT_SUCCESS(Status))
3642  {
3643  /* Nothing to do, don't return with an error status */
3644  DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3645  ZwClose(hRoot);
3646  return STATUS_SUCCESS;
3647  }
3649  hEnum,
3650  NULL,
3651  hRoot,
3652  TRUE,
3653  NULL,
3654  0);
3655  ZwClose(hEnum);
3656  }
3657  else
3658  {
3659  /* Enumeration is disabled */
3661  }
3662 
3663  ZwClose(hRoot);
3664 
3665  return Status;
3666 }
3667 
3668 NTSTATUS
3669 NTAPI
3671  HANDLE ParentKey,
3674 {
3676  NTSTATUS Status;
3677 
3678  PAGED_CODE();
3679 
3680  *KeyHandle = NULL;
3681 
3683  Name,
3685  ParentKey,
3686  NULL);
3687 
3689 
3690  return Status;
3691 }
3692 
3693 NTSTATUS
3694 NTAPI
3696  IN HANDLE RootHandle OPTIONAL,
3701 {
3703  ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3704  USHORT Length;
3705  HANDLE HandleArray[2];
3706  BOOLEAN Recursing = TRUE;
3707  PWCHAR pp, p, p1;
3708  UNICODE_STRING KeyString;
3710  PAGED_CODE();
3711 
3712  /* P1 is start, pp is end */
3713  p1 = KeyName->Buffer;
3714  pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3715 
3716  /* Create the target key */
3718  KeyName,
3720  RootHandle,
3721  NULL);
3722  Status = ZwCreateKey(&HandleArray[i],
3723  DesiredAccess,
3725  0,
3726  NULL,
3727  CreateOptions,
3728  &KeyDisposition);
3729 
3730  /* Now we check if this failed */
3731  if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3732  {
3733  /* Target key failed, so we'll need to create its parent. Setup array */
3734  HandleArray[0] = NULL;
3735  HandleArray[1] = RootHandle;
3736 
3737  /* Keep recursing for each missing parent */
3738  while (Recursing)
3739  {
3740  /* And if we're deep enough, close the last handle */
3741  if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3742 
3743  /* We're setup to ping-pong between the two handle array entries */
3744  RootHandleIndex = i;
3745  i = (i + 1) & 1;
3746 
3747  /* Clear the one we're attempting to open now */
3748  HandleArray[i] = NULL;
3749 
3750  /* Process the parent key name */
3751  for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3752  Length = (USHORT)(p - p1) * sizeof(WCHAR);
3753 
3754  /* Is there a parent name? */
3755  if (Length)
3756  {
3757  /* Build the unicode string for it */
3758  KeyString.Buffer = p1;
3759  KeyString.Length = KeyString.MaximumLength = Length;
3760 
3761  /* Now try opening the parent */
3763  &KeyString,
3765  HandleArray[RootHandleIndex],
3766  NULL);
3767  Status = ZwCreateKey(&HandleArray[i],
3768  DesiredAccess,
3770  0,
3771  NULL,
3772  CreateOptions,
3773  &KeyDisposition);
3774  if (NT_SUCCESS(Status))
3775  {
3776  /* It worked, we have one more handle */
3777  NestedCloseLevel++;
3778  }
3779  else
3780  {
3781  /* Parent key creation failed, abandon loop */
3782  Recursing = FALSE;
3783  continue;
3784  }
3785  }
3786  else
3787  {
3788  /* We don't have a parent name, probably corrupted key name */
3790  Recursing = FALSE;
3791  continue;
3792  }
3793 
3794  /* Now see if there's more parents to create */
3795  p1 = p + 1;
3796  if ((p == pp) || (p1 == pp))
3797  {
3798  /* We're done, hopefully successfully, so stop */
3799  Recursing = FALSE;
3800  }
3801  }
3802 
3803  /* Outer loop check for handle nesting that requires closing the top handle */
3804  if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3805  }
3806 
3807  /* Check if we broke out of the loop due to success */
3808  if (NT_SUCCESS(Status))
3809  {
3810  /* Return the target handle (we closed all the parent ones) and disposition */
3811  *Handle = HandleArray[i];
3812  if (Disposition) *Disposition = KeyDisposition;
3813  }
3814 
3815  /* Return the success state */
3816  return Status;
3817 }
3818 
3819 NTSTATUS
3820 NTAPI
3822  IN PWSTR ValueName,
3824 {
3825  UNICODE_STRING ValueString;
3826  NTSTATUS Status;
3827  PKEY_VALUE_FULL_INFORMATION FullInformation;
3828  ULONG Size;
3829  PAGED_CODE();
3830 
3831  RtlInitUnicodeString(&ValueString, ValueName);
3832 
3833  Status = ZwQueryValueKey(Handle,
3834  &ValueString,
3836  NULL,
3837  0,
3838  &Size);
3839  if ((Status != STATUS_BUFFER_OVERFLOW) &&
3841  {
3842  return Status;
3843  }
3844 
3845  FullInformation = ExAllocatePool(NonPagedPool, Size);
3846  if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3847 
3848  Status = ZwQueryValueKey(Handle,
3849  &ValueString,
3851  FullInformation,
3852  Size,
3853  &Size);
3854  if (!NT_SUCCESS(Status))
3855  {
3856  ExFreePool(FullInformation);
3857  return Status;
3858  }
3859 
3860  *Information = FullInformation;
3861  return STATUS_SUCCESS;
3862 }
3863 
3865 NTAPI
3869 {
3870  /* FIXME: TODO */
3871  ASSERT(FALSE);
3872  return 0;
3873 }
3874 
3875 //
3876 // The allocation function is called by the generic table package whenever
3877 // it needs to allocate memory for the table.
3878 //
3879 
3880 PVOID
3881 NTAPI
3883  IN CLONG ByteSize)
3884 {
3885  /* FIXME: TODO */
3886  ASSERT(FALSE);
3887  return NULL;
3888 }
3889 
3890 VOID
3891 NTAPI
3893  IN PVOID Buffer)
3894 {
3895  /* FIXME: TODO */
3896  ASSERT(FALSE);
3897 }
3898 
3899 VOID
3900 NTAPI
3902 {
3903  /* Setup the guarded mutex and AVL table */
3910  NULL);
3911 }
3912 
3913 BOOLEAN
3914 NTAPI
3916 {
3917  /* Initialize the resource when accessing device registry data */
3919 
3920  /* Setup the device reference AVL table */
3922  return TRUE;
3923 }
3924 
3925 BOOLEAN
3926 NTAPI
3928 {
3929  /* Check the initialization phase */
3930  switch (ExpInitializationPhase)
3931  {
3932  case 0:
3933 
3934  /* Do Phase 0 */
3935  return PiInitPhase0();
3936 
3937  case 1:
3938 
3939  /* Do Phase 1 */
3940  return TRUE;
3941  //return PiInitPhase1();
3942 
3943  default:
3944 
3945  /* Don't know any other phase! Bugcheck! */
3946  KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3947  return FALSE;
3948  }
3949 }
3950 
3952 
3954 NTAPI
3956 {
3958  PAGED_CODE();
3959 
3960  /* Allocate it */
3962  if (!DeviceNode) return DeviceNode;
3963 
3964  /* Statistics */
3966 
3967  /* Set it up */
3969  DeviceNode->InterfaceType = InterfaceTypeUndefined;
3970  DeviceNode->BusNumber = -1;
3971  DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3972  DeviceNode->ChildBusNumber = -1;
3973  DeviceNode->ChildBusTypeIndex = -1;
3974 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3975  InitializeListHead(&DeviceNode->DeviceArbiterList);
3976  InitializeListHead(&DeviceNode->DeviceTranslatorList);
3977  InitializeListHead(&DeviceNode->TargetDeviceNotify);
3978  InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3979  InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3980 
3981  /* Check if there is a PDO */
3983  {
3984  /* Link it and remove the init flag */
3985  DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3986  ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3988  }
3989 
3990  /* Return the node */
3991  return DeviceNode;
3992 }
3993 
3994 /* PUBLIC FUNCTIONS **********************************************************/
3995 
3996 NTSTATUS
3997 NTAPI
3999  IN LPGUID BusTypeGuid)
4000 {
4002 
4003  /* Acquire the lock */
4005 
4006  /* Validate size */
4007  if (Index < PnpBusTypeGuidList->GuidCount)
4008  {
4009  /* Copy the data */
4010  RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
4011  }
4012  else
4013  {
4014  /* Failure path */
4016  }
4017 
4018  /* Release lock and return status */
4020  return Status;
4021 }
4022 
4023 NTSTATUS
4024 NTAPI
4026  IN PHANDLE DeviceInstanceHandle,
4028 {
4029  NTSTATUS Status;
4030  HANDLE KeyHandle;
4032  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
4033  PAGED_CODE();
4034 
4035  /* Open the enum key */
4037  NULL,
4038  &KeyName,
4039  KEY_READ);
4040  if (!NT_SUCCESS(Status)) return Status;
4041 
4042  /* Make sure we have an instance path */
4044  if ((DeviceNode) && (DeviceNode->InstancePath.Length))
4045  {
4046  /* Get the instance key */
4047  Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
4048  KeyHandle,
4049  &DeviceNode->InstancePath,
4050  DesiredAccess);
4051  }
4052  else
4053  {
4054  /* Fail */
4056  }
4057 
4058  /* Close the handle and return status */
4059  ZwClose(KeyHandle);
4060  return Status;
4061 }
4062 
4063 ULONG
4064 NTAPI
4066 {
4067  ULONG FinalSize, PartialSize, EntrySize, i, j;
4068  PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
4069  PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
4070 
4071  /* If we don't have one, that's easy */
4072  if (!ResourceList) return 0;
4073 
4074  /* Start with the minimum size possible */
4075  FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
4076 
4077  /* Loop each full descriptor */
4078  FullDescriptor = ResourceList->List;
4079  for (i = 0; i < ResourceList->Count; i++)
4080  {
4081  /* Start with the minimum size possible */
4082  PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
4083  FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
4084 
4085  /* Loop each partial descriptor */
4086  PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
4087  for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
4088  {
4089  /* Start with the minimum size possible */
4091 
4092  /* Check if there is extra data */
4093  if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
4094  {
4095  /* Add that data */
4096  EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
4097  }
4098 
4099  /* The size of partial descriptors is bigger */
4100  PartialSize += EntrySize;
4101 
4102  /* Go to the next partial descriptor */
4103  PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
4104  }
4105 
4106  /* The size of full descriptors is bigger */
4107  FinalSize += PartialSize;
4108 
4109  /* Go to the next full descriptor */
4110  FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
4111  }
4112 
4113  /* Return the final size */
4114  return FinalSize;
4115 }
4116 
4117 NTSTATUS
4118 NTAPI
4120  IN ULONG ValueType,
4121  IN PWSTR ValueName,
4122  IN PWSTR KeyName,
4123  OUT PVOID Buffer,
4125 {
4126  NTSTATUS Status;
4127  HANDLE KeyHandle, SubHandle;
4128  UNICODE_STRING KeyString;
4129  PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
4130  ULONG Length;
4131  PAGED_CODE();
4132 
4133  /* Find the instance key */
4135  if (NT_SUCCESS(Status))
4136  {
4137  /* Check for name given by caller */
4138  if (KeyName)
4139  {
4140  /* Open this key */
4141  RtlInitUnicodeString(&KeyString, KeyName);
4142  Status = IopOpenRegistryKeyEx(&SubHandle,
4143  KeyHandle,
4144  &KeyString,
4145  KEY_READ);
4146  if (NT_SUCCESS(Status))
4147  {
4148  /* And use this handle instead */
4149  ZwClose(KeyHandle);
4150  KeyHandle = SubHandle;
4151  }
4152  }
4153 
4154  /* Check if sub-key handle succeeded (or no-op if no key name given) */
4155  if (NT_SUCCESS(Status))
4156  {
4157  /* Now get the size of the property */
4159  ValueName,
4160  &KeyValueInfo);
4161  }
4162 
4163  /* Close the key */
4164  ZwClose(KeyHandle);
4165  }
4166 
4167  /* Fail if any of the registry operations failed */
4168  if (!NT_SUCCESS(Status)) return Status;
4169 
4170  /* Check how much data we have to copy */
4171  Length = KeyValueInfo->DataLength;
4172  if (*BufferLength >= Length)
4173  {
4174  /* Check for a match in the value type */
4175  if (KeyValueInfo->Type == ValueType)
4176  {
4177  /* Copy the data */
4179  (PVOID)((ULONG_PTR)KeyValueInfo +
4180  KeyValueInfo->DataOffset),
4181  Length);
4182  }
4183  else
4184  {
4185  /* Invalid registry property type, fail */
4187  }
4188  }
4189  else
4190  {
4191  /* Buffer is too small to hold data */
4193  }
4194 
4195  /* Return the required buffer length, free the buffer, and return status */
4196  *BufferLength = Length;
4197  ExFreePool(KeyValueInfo);
4198  return Status;
4199 }
4200 
4201 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
4202 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
4203 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
4204 
4205 /*
4206  * @implemented
4207  */
4208 NTSTATUS
4209 NTAPI
4213  OUT PVOID PropertyBuffer,
4215 {
4217  DEVICE_CAPABILITIES DeviceCaps;
4218  ULONG ReturnLength = 0, Length = 0, ValueType;
4219  PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
4220  PVOID Data = NULL;
4222  GUID BusTypeGuid;
4223  POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
4224  BOOLEAN NullTerminate = FALSE;
4225 
4226  DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
4227 
4228  /* Assume failure */
4229  *ResultLength = 0;
4230 
4231  /* Only PDOs can call this */
4233 
4234  /* Handle all properties */
4235  switch (DeviceProperty)
4236  {
4238 
4239  /* Get the GUID from the internal cache */
4240  Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
4241  if (!NT_SUCCESS(Status)) return Status;
4242 
4243  /* This is the format of the returned data */
4244  PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
4245 
4247 
4248  /* Validate correct interface type */
4249  if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
4251 
4252  /* This is the format of the returned data */
4253  PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
4254 
4256 
4257  /* Validate correct bus number */
4258  if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
4260 
4261  /* This is the format of the returned data */
4262  PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
4263 
4265 
4266  /* Get the instance path */
4267  DeviceInstanceName = DeviceNode->InstancePath.Buffer;
4268 
4269  /* Sanity checks */
4270  ASSERT((BufferLength & 1) == 0);
4271  ASSERT(DeviceInstanceName != NULL);
4272 
4273  /* Get the name from the path */
4274  EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
4275  ASSERT(EnumeratorNameEnd);
4276 
4277  /* This string needs to be NULL-terminated */
4278  NullTerminate = TRUE;
4279 
4280  /* This is the format of the returned data */
4281  PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
4282  DeviceInstanceName);
4283 
4284  case DevicePropertyAddress:
4285 
4286  /* Query the device caps */
4288  if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
4290 
4291  /* This is the format of the returned data */
4292  PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
4293 
4295 
4296  /* Validate we have resources */
4297  if (!DeviceNode->BootResources)
4298 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
4299  {
4300  /* No resources will still fake success, but with 0 bytes */
4301  *ResultLength = 0;
4302  return STATUS_SUCCESS;
4303  }
4304 
4305  /* This is the format of the returned data */
4306  PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
4307  DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
4308 
4310 
4311  /* Sanity check for Unicode-sized string */
4312  ASSERT((BufferLength & 1) == 0);
4313 
4314  /* Allocate name buffer */
4316  ObjectNameInfo = ExAllocatePool(PagedPool, Length);
4317  if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
4318 
4319  /* Query the PDO name */
4321  ObjectNameInfo,
4322  Length,
4323  ResultLength);
4325  {
4326  /* It's up to the caller to try again */
4328  }
4329 
4330  /* This string needs to be NULL-terminated */
4331  NullTerminate = TRUE;
4332 
4333  /* Return if successful */
4334  if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
4335  ObjectNameInfo->Name.Buffer);
4336 
4337  /* Let the caller know how big the name is */
4339  break;
4340 
4342  PIP_RETURN_DATA(sizeof(UCHAR), &DeviceNode->RemovalPolicy);
4343 
4344  /* Handle the registry-based properties */
4368  //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
4370  break;
4373  break;
4378  default:
4380  }
4381 
4382  /* Having a registry value name implies registry data */
4383  if (ValueName)
4384  {
4385  /* We know up-front how much data to expect */
4387 
4388  /* Go get the data, use the LogConf subkey if necessary */
4390  ValueType,
4391  ValueName,
4392  (DeviceProperty ==
4394  L"LogConf": NULL,
4395  PropertyBuffer,
4396  ResultLength);
4397  }
4398  else if (NT_SUCCESS(Status))
4399  {
4400  /* We know up-front how much data to expect, check the caller's buffer */
4401  *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
4402  if (*ResultLength <= BufferLength)
4403  {
4404  /* Buffer is all good, copy the data */
4405  RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
4406 
4407  /* Check if we need to NULL-terminate the string */
4408  if (NullTerminate)
4409  {
4410  /* Terminate the string */
4411  ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
4412  }
4413 
4414  /* This is the success path */
4416  }
4417  else
4418  {
4419  /* Failure path */
4421  }
4422  }
4423 
4424  /* Free any allocation we may have made, and return the status code */
4425  if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
4426  return Status;
4427 }
4428 
4429 /*
4430  * @implemented
4431  */
4432 VOID
4433 NTAPI
4435 {
4437  IO_STACK_LOCATION Stack;
4438  ULONG PnPFlags;
4439  NTSTATUS Status;
4441 
4442  RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
4443  Stack.MajorFunction = IRP_MJ_PNP;
4445 
4446  Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
4447  if (!NT_SUCCESS(Status))
4448  {
4450  {
4451  DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status);
4452  }
4453  return;
4454  }
4455 
4456  if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
4457  DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
4458  else
4459  DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
4460 
4461  if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
4462  DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
4463  else
4464  DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
4465 
4466  if ((PnPFlags & PNP_DEVICE_REMOVED) ||
4467  ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
4468  {
4469  /* Flag it if it's failed */
4470  if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START;
4471 
4472  /* Send removal IRPs to all of its children */
4474 
4475  /* Send surprise removal */
4477 
4478  /* Tell the user-mode PnP manager that a device was removed */
4479  IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
4480  &DeviceNode->InstancePath);
4481 
4483  }
4484  else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
4485  {
4486  /* Stop for resource rebalance */
4488  if (!NT_SUCCESS(Status))
4489  {
4490  DPRINT1("Failed to stop device for rebalancing\n");
4491 
4492  /* Stop failed so don't rebalance */
4494  }
4495  }
4496 
4497  /* Resource rebalance */
4499  {
4500  DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4501 
4503  &IoStatusBlock,
4505  NULL);
4507  {
4508  DeviceNode->BootResources =
4511  }
4512  else
4513  {
4514  DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
4515  DeviceNode->BootResources = NULL;
4516  }
4517 
4518  DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4519 
4521  &IoStatusBlock,
4523  NULL);
4524  if (NT_SUCCESS(Status))
4525  {
4526  DeviceNode->ResourceRequirements =
4528  }
4529  else
4530  {
4531  DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
4532  DeviceNode->ResourceRequirements = NULL;
4533  }
4534 
4535  /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4537  {
4538  DPRINT1("Restart after resource rebalance failed\n");
4539 
4541  DeviceNode->Flags |= DNF_START_FAILED;
4542 
4544  }
4545  }
4546 }
4547 
4563 NTSTATUS
4564 NTAPI
4569 {
4570  static WCHAR RootKeyName[] =
4571  L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4572  static WCHAR ProfileKeyName[] =
4573  L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4574  static WCHAR ClassKeyName[] = L"Control\\Class\\";
4575  static WCHAR EnumKeyName[] = L"Enum\\";
4576  static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4578  PWSTR KeyNameBuffer;
4580  ULONG DriverKeyLength;
4583  NTSTATUS Status;
4584 
4585  DPRINT("IoOpenDeviceRegistryKey() called\n");
4586 
4588  {
4589  DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4590  return STATUS_INVALID_PARAMETER;
4591  }
4592 
4596 
4597  /*
4598  * Calculate the length of the base key name. This is the full
4599  * name for driver key or the name excluding "Device Parameters"
4600  * subkey for device key.
4601  */
4602 
4603  KeyNameLength = sizeof(RootKeyName);
4605  KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4607  {
4608  KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4610  0, NULL, &DriverKeyLength);
4612  return Status;
4613  KeyNameLength += DriverKeyLength;
4614  }
4615  else
4616  {
4617  KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4618  DeviceNode->InstancePath.Length;
4619  }
4620 
4621  /*
4622  * Now allocate the buffer for the key name...
4623  */
4624 
4625  KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4626  if (KeyNameBuffer == NULL)
4628 
4629  KeyName.Length = 0;
4630  KeyName.MaximumLength = (USHORT)KeyNameLength;
4631  KeyName.Buffer = KeyNameBuffer;
4632 
4633  /*
4634  * ...and build the key name.
4635  */
4636 
4637  KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4638  RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4639 
4641  RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4642 
4644  {
4645  RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4647  DriverKeyLength, KeyNameBuffer +
4648  (KeyName.Length / sizeof(WCHAR)),
4649  &DriverKeyLength);
4650  if (!NT_SUCCESS(Status))
4651  {
4652  DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4653  ExFreePool(KeyNameBuffer);
4654  return Status;
4655  }
4656  KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4657  }
4658  else
4659  {
4660  RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4662  if (DeviceNode->InstancePath.Length == 0)
4663  {
4664  ExFreePool(KeyNameBuffer);
4665  return Status;
4666  }
4667  }
4668 
4669  /*
4670  * Open the base key.
4671  */
4673  if (!NT_SUCCESS(Status))
4674  {
4675  DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4676  ExFreePool(KeyNameBuffer);
4677  return Status;
4678  }
4679  ExFreePool(KeyNameBuffer);
4680 
4681  /*
4682  * For driver key we're done now.
4683  */
4684 
4686  return Status;
4687 
4688  /*
4689  * Let's go further. For device key we must open "Device Parameters"
4690  * subkey and create it if it doesn't exist yet.
4691  */
4692 
4693  RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4695  &KeyName,
4697  *DevInstRegKey,
4698  NULL);
4699  Status = ZwCreateKey(DevInstRegKey,
4700  DesiredAccess,
4702  0,
4703  NULL,
4705  NULL);
4706  ZwClose(ObjectAttributes.RootDirectory);
4707 
4708  return Status;
4709 }
4710 
4711 static
4712 NTSTATUS
4714 {
4715  PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
4716  NTSTATUS Status;
4717  KIRQL OldIrql;
4718 
4720  ChildDeviceNode = ParentDeviceNode->Child;
4721  while (ChildDeviceNode != NULL)
4722  {
4723  NextDeviceNode = ChildDeviceNode->Sibling;
4725 
4727  if (!NT_SUCCESS(Status))
4728  {
4729  FailedRemoveDevice = ChildDeviceNode;
4730  goto cleanup;
4731  }
4732 
4734  ChildDeviceNode = NextDeviceNode;
4735  }
4737 
4738  return STATUS_SUCCESS;
4739 
4740 cleanup:
4742  ChildDeviceNode = ParentDeviceNode->Child;
4743  while (ChildDeviceNode != NULL)
4744  {
4745  NextDeviceNode = ChildDeviceNode->Sibling;
4747 
4749 
4750  /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4751  * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4752  if (ChildDeviceNode == FailedRemoveDevice)
4753  return Status;
4754 
4755  ChildDeviceNode = NextDeviceNode;