ReactOS  0.4.14-dev-77-gd9e7c48
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->MajorFunction == IRP_MJ_PNP) &&
1445  (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS))
1446  {
1447  /* Copy the resource requirements list into the IOSB */
1448  Irp->IoStatus.Information =
1449  IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
1450  }
1451 
1452  /* Initialize the event */
1454 
1455  /* Set them up */
1456  Irp->UserIosb = &IoStatusBlock;
1457  Irp->UserEvent = &Event;
1458 
1459  /* Queue the IRP */
1460  Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1462 
1463  /* Copy-in the stack */
1464  IrpStack = IoGetNextIrpStackLocation(Irp);
1465  *IrpStack = *IoStackLocation;
1466 
1467  /* Call the driver */
1468  Status = IoCallDriver(TopDeviceObject, Irp);
1469  if (Status == STATUS_PENDING)
1470  {
1471  /* Wait for it */
1473  Executive,
1474  KernelMode,
1475  FALSE,
1476  NULL);
1478  }
1479 
1480  /* Remove the reference */
1481  ObDereferenceObject(TopDeviceObject);
1482 
1483  /* Return the information */
1485  return Status;
1486 }
1487 
1488 NTSTATUS
1489 NTAPI
1494 {
1495  IO_STACK_LOCATION IoStackLocation;
1496 
1497  /* Fill out the stack information */
1498  RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
1499  IoStackLocation.MajorFunction = IRP_MJ_PNP;
1500  IoStackLocation.MinorFunction = MinorFunction;
1501  if (Stack)
1502  {
1503  /* Copy the rest */
1504  RtlCopyMemory(&IoStackLocation.Parameters,
1505  &Stack->Parameters,
1506  sizeof(Stack->Parameters));
1507  }
1508 
1509  /* Do the PnP call */
1511  &IoStackLocation,
1513  return IoStatusBlock->Status;
1514 }
1515 
1516 NTSTATUS
1518 {
1519  PDEVICE_NODE ParentDeviceNode;
1520  PDEVICE_NODE ChildDeviceNode;
1521  PDEVICE_NODE NextDeviceNode;
1522  NTSTATUS Status;
1523 
1524  /* Copy context data so we don't overwrite it in subsequent calls to this function */
1525  ParentDeviceNode = Context->DeviceNode;
1526 
1527  /* HACK: Keep a reference to the PDO so we can keep traversing the tree
1528  * if the device is deleted. In a perfect world, children would have to be
1529  * deleted before their parents, and we'd restart the traversal after
1530  * deleting a device node. */
1531  ObReferenceObject(ParentDeviceNode->PhysicalDeviceObject);
1532 
1533  /* Call the action routine */
1534  Status = (Context->Action)(ParentDeviceNode, Context->Context);
1535  if (!NT_SUCCESS(Status))
1536  {
1537  ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
1538  return Status;
1539  }
1540 
1541  /* Traversal of all children nodes */
1542  for (ChildDeviceNode = ParentDeviceNode->Child;
1543  ChildDeviceNode != NULL;
1544  ChildDeviceNode = NextDeviceNode)
1545  {
1546  /* HACK: We need this reference to ensure we can get Sibling below. */
1547  ObReferenceObject(ChildDeviceNode->PhysicalDeviceObject);
1548 
1549  /* Pass the current device node to the action routine */
1550  Context->DeviceNode = ChildDeviceNode;
1551 
1553  if (!NT_SUCCESS(Status))
1554  {
1555  ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject);
1556  ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
1557  return Status;
1558  }
1559 
1560  NextDeviceNode = ChildDeviceNode->Sibling;
1561  ObDereferenceObject(ChildDeviceNode->PhysicalDeviceObject);
1562  }
1563 
1564  ObDereferenceObject(ParentDeviceNode->PhysicalDeviceObject);
1565  return Status;
1566 }
1567 
1568 
1569 NTSTATUS
1571 {
1572  NTSTATUS Status;
1573 
1574  DPRINT("Context 0x%p\n", Context);
1575 
1576  DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %p Context 0x%p)\n",
1577  Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
1578 
1579  /* Start from the specified device node */
1580  Context->DeviceNode = Context->FirstDeviceNode;
1581 
1582  /* Recursively traverse the device tree */
1584  if (Status == STATUS_UNSUCCESSFUL)
1585  {
1586  /* The action routine just wanted to terminate the traversal with status
1587  code STATUS_SUCCESS */
1589  }
1590 
1591  return Status;
1592 }
1593 
1594 
1595 /*
1596  * IopCreateDeviceKeyPath
1597  *
1598  * Creates a registry key
1599  *
1600  * Parameters
1601  * RegistryPath
1602  * Name of the key to be created.
1603  * Handle
1604  * Handle to the newly created key
1605  *
1606  * Remarks
1607  * This method can create nested trees, so parent of RegistryPath can
1608  * be not existant, and will be created if needed.
1609  */
1610 NTSTATUS
1611 NTAPI
1614  OUT PHANDLE Handle)
1615 {
1617  HANDLE hParent = NULL, hKey;
1620  PCWSTR Current, Last;
1621  USHORT Length;
1622  NTSTATUS Status;
1623 
1624  /* Assume failure */
1625  *Handle = NULL;
1626 
1627  /* Open root key for device instances */
1629  if (!NT_SUCCESS(Status))
1630  {
1631  DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
1632  return Status;
1633  }
1634 
1635  Current = KeyName.Buffer = RegistryPath->Buffer;
1636  Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
1637 
1638  /* Go up to the end of the string */
1639  while (Current <= Last)
1640  {
1641  if (Current != Last && *Current != L'\\')
1642  {
1643  /* Not the end of the string and not a separator */
1644  Current++;
1645  continue;
1646  }
1647 
1648  /* Prepare relative key name */
1649  Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
1650  KeyName.MaximumLength = KeyName.Length = Length;
1651  DPRINT("Create '%wZ'\n", &KeyName);
1652 
1653  /* Open key */
1655  &KeyName,
1657  hParent,
1658  NULL);
1659  Status = ZwCreateKey(&hKey,
1660  Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
1662  0,
1663  NULL,
1664  CreateOptions,
1665  NULL);
1666 
1667  /* Close parent key handle, we don't need it anymore */
1668  if (hParent)
1669  ZwClose(hParent);
1670 
1671  /* Key opening/creating failed? */
1672  if (!NT_SUCCESS(Status))
1673  {
1674  DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
1675  return Status;
1676  }
1677 
1678  /* Check if it is the end of the string */
1679  if (Current == Last)
1680  {
1681  /* Yes, return success */
1682  *Handle = hKey;
1683  return STATUS_SUCCESS;
1684  }
1685 
1686  /* Start with this new parent key */
1687  hParent = hKey;
1688  Current++;
1689  KeyName.Buffer = (PWSTR)Current;
1690  }
1691 
1692  return STATUS_UNSUCCESSFUL;
1693 }
1694 
1695 NTSTATUS
1698 {
1701  HANDLE LogConfKey, ControlKey, DeviceParamsKey;
1702  ULONG ResCount;
1704  NTSTATUS Status;
1705 
1706  DPRINT("IopSetDeviceInstanceData() called\n");
1707 
1708  /* Create the 'LogConf' key */
1709  RtlInitUnicodeString(&KeyName, L"LogConf");
1711  &KeyName,
1713  InstanceKey,
1714  NULL);
1715  Status = ZwCreateKey(&LogConfKey,
1718  0,
1719  NULL,
1720  // FIXME? In r53694 it was silently turned from non-volatile into this,
1721  // without any extra warning. Is this still needed??
1723  NULL);
1724  if (NT_SUCCESS(Status))
1725  {
1726  /* Set 'BootConfig' value */
1727  if (DeviceNode->BootResources != NULL)
1728  {
1729  ResCount = DeviceNode->BootResources->Count;
1730  if (ResCount != 0)
1731  {
1732  RtlInitUnicodeString(&KeyName, L"BootConfig");
1733  Status = ZwSetValueKey(LogConfKey,
1734  &KeyName,
1735  0,
1737  DeviceNode->BootResources,
1738  PnpDetermineResourceListSize(DeviceNode->BootResources));
1739  }
1740  }
1741 
1742  /* Set 'BasicConfigVector' value */
1743  if (DeviceNode->ResourceRequirements != NULL &&
1744  DeviceNode->ResourceRequirements->ListSize != 0)
1745  {
1746  RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1747  Status = ZwSetValueKey(LogConfKey,
1748  &KeyName,
1749  0,
1751  DeviceNode->ResourceRequirements,
1752  DeviceNode->ResourceRequirements->ListSize);
1753  }
1754 
1755  ZwClose(LogConfKey);
1756  }
1757 
1758  /* Set the 'ConfigFlags' value */
1759  RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1760  Status = ZwQueryValueKey(InstanceKey,
1761  &KeyName,
1763  NULL,
1764  0,
1765  &ResultLength);
1767  {
1768  /* Write the default value */
1769  ULONG DefaultConfigFlags = 0;
1770  Status = ZwSetValueKey(InstanceKey,
1771  &KeyName,
1772  0,
1773  REG_DWORD,
1774  &DefaultConfigFlags,
1775  sizeof(DefaultConfigFlags));
1776  }
1777 
1778  /* Create the 'Control' key */
1779  RtlInitUnicodeString(&KeyName, L"Control");
1781  &KeyName,
1783  InstanceKey,
1784  NULL);
1785  Status = ZwCreateKey(&ControlKey,
1786  0,
1788  0,
1789  NULL,
1791  NULL);
1792  if (NT_SUCCESS(Status))
1793  ZwClose(ControlKey);
1794 
1795  /* Create the 'Device Parameters' key and set the 'FirmwareIdentified' value for all ACPI-enumerated devices */
1796  if (_wcsnicmp(DeviceNode->InstancePath.Buffer, L"ACPI\\", 5) == 0)
1797  {
1798  RtlInitUnicodeString(&KeyName, L"Device Parameters");
1800  &KeyName,
1802  InstanceKey,
1803  NULL);
1804  Status = ZwCreateKey(&DeviceParamsKey,
1805  0,
1807  0,
1808  NULL,
1810  NULL);
1811  if (NT_SUCCESS(Status))
1812  {
1813  ULONG FirmwareIdentified = 1;
1814  RtlInitUnicodeString(&KeyName, L"FirmwareIdentified");
1815  Status = ZwSetValueKey(DeviceParamsKey,
1816  &KeyName,
1817  0,
1818  REG_DWORD,
1819  &FirmwareIdentified,
1820  sizeof(FirmwareIdentified));
1821 
1822  ZwClose(DeviceParamsKey);
1823  }
1824  }
1825 
1826  DPRINT("IopSetDeviceInstanceData() done\n");
1827 
1828  return Status;
1829 }
1830 
1831 /*
1832  * IopGetParentIdPrefix
1833  *
1834  * Retrieve (or create) a string which identifies a device.
1835  *
1836  * Parameters
1837  * DeviceNode
1838  * Pointer to device node.
1839  * ParentIdPrefix
1840  * Pointer to the string where is returned the parent node identifier
1841  *
1842  * Remarks
1843  * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1844  * valid and its Buffer field is NULL-terminated. The caller needs to
1845  * to free the string with RtlFreeUnicodeString when it is no longer
1846  * needed.
1847  */
1848 
1849 NTSTATUS
1851  PUNICODE_STRING ParentIdPrefix)
1852 {
1853  const UNICODE_STRING EnumKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1854  ULONG KeyNameBufferLength;
1855  PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1856  UNICODE_STRING KeyName = {0, 0, NULL};
1857  UNICODE_STRING KeyValue;
1859  HANDLE hKey = NULL;
1860  ULONG crc32;
1861  NTSTATUS Status;
1862 
1863  /* HACK: As long as some devices have a NULL device
1864  * instance path, the following test is required :(
1865  */
1866  if (DeviceNode->Parent->InstancePath.Length == 0)
1867  {
1868  DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1869  &DeviceNode->InstancePath);
1870  return STATUS_UNSUCCESSFUL;
1871  }
1872 
1873  /* 1. Try to retrieve ParentIdPrefix from registry */
1874  KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(L"12345678&12345678");
1875  ParentIdPrefixInformation = ExAllocatePoolWithTag(PagedPool,
1876  KeyNameBufferLength + sizeof(UNICODE_NULL),
1877  TAG_IO);
1878  if (!ParentIdPrefixInformation)
1879  {
1881  }
1882 
1883  KeyName.Length = 0;
1884  KeyName.MaximumLength = EnumKeyPath.Length +
1885  DeviceNode->Parent->InstancePath.Length +
1886  sizeof(UNICODE_NULL);
1888  KeyName.MaximumLength,
1889  TAG_IO);
1890  if (!KeyName.Buffer)
1891  {
1893  goto cleanup;
1894  }
1895 
1896  RtlCopyUnicodeString(&KeyName, &EnumKeyPath);
1897  RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1898 
1900  if (!NT_SUCCESS(Status))
1901  {
1902  goto cleanup;
1903  }
1904  RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1905  Status = ZwQueryValueKey(hKey,
1906  &ValueName,
1908  ParentIdPrefixInformation,
1909  KeyNameBufferLength,
1910  &KeyNameBufferLength);
1911  if (NT_SUCCESS(Status))
1912  {
1913  if (ParentIdPrefixInformation->Type != REG_SZ)
1914  {
1916  }
1917  else
1918  {
1919  KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1920  KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1921  KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1922  ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1923  }
1924  goto cleanup;
1925  }
1927  {
1928  /* FIXME how do we get here and why is ParentIdPrefixInformation valid? */
1929  KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1930  KeyValue.Length = KeyValue.MaximumLength - sizeof(UNICODE_NULL);
1931  KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1932  ASSERT(KeyValue.Buffer[KeyValue.Length / sizeof(WCHAR)] == UNICODE_NULL);
1933  goto cleanup;
1934  }
1935 
1936  /* 2. Create the ParentIdPrefix value */
1937  crc32 = RtlComputeCrc32(0,
1938  (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1939  DeviceNode->Parent->InstancePath.Length);
1940 
1941  RtlStringCbPrintfW((PWSTR)ParentIdPrefixInformation,
1942  KeyNameBufferLength,
1943  L"%lx&%lx",
1944  DeviceNode->Parent->Level,
1945  crc32);
1946  RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation);
1947 
1948  /* 3. Try to write the ParentIdPrefix to registry */
1949  Status = ZwSetValueKey(hKey,
1950  &ValueName,
1951  0,
1952  REG_SZ,
1953  KeyValue.Buffer,
1954  ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1955 
1956 cleanup:
1957  if (NT_SUCCESS(Status))
1958  {
1959  /* Duplicate the string to return it */
1961  &KeyValue,
1962  ParentIdPrefix);
1963  }
1964  ExFreePoolWithTag(ParentIdPrefixInformation, TAG_IO);
1966  if (hKey != NULL)
1967  {
1968  ZwClose(hKey);
1969  }
1970  return Status;
1971 }
1972 
1973 static
1974 BOOLEAN
1976  _In_ PWCHAR Id,
1978 {
1979  PWCHAR PtrChar;
1980  PWCHAR StringEnd;
1981  WCHAR Char;
1982  ULONG SeparatorsCount = 0;
1983  PWCHAR PtrPrevChar = NULL;
1984  ULONG MaxSeparators;
1985  BOOLEAN IsMultiSz;
1986 
1987  PAGED_CODE();
1988 
1989  switch (QueryType)
1990  {
1991  case BusQueryDeviceID:
1992  MaxSeparators = MAX_SEPARATORS_DEVICEID;
1993  IsMultiSz = FALSE;
1994  break;
1995  case BusQueryInstanceID:
1996  MaxSeparators = MAX_SEPARATORS_INSTANCEID;
1997  IsMultiSz = FALSE;
1998  break;
1999 
2000  case BusQueryHardwareIDs:
2001  case BusQueryCompatibleIDs:
2002  MaxSeparators = MAX_SEPARATORS_DEVICEID;
2003  IsMultiSz = TRUE;
2004  break;
2005 
2006  default:
2007  DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
2008  return FALSE;
2009  }
2010 
2011  StringEnd = Id + MAX_DEVICE_ID_LEN;
2012 
2013  for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
2014  {
2015  Char = *PtrChar;
2016 
2017  if (Char == UNICODE_NULL)
2018  {
2019  if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
2020  {
2021  if (MaxSeparators == SeparatorsCount || IsMultiSz)
2022  {
2023  return TRUE;
2024  }
2025 
2026  DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
2027  SeparatorsCount, MaxSeparators);
2028  goto ErrorExit;
2029  }
2030 
2031  StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
2032  PtrPrevChar = PtrChar;
2033  SeparatorsCount = 0;
2034  }
2035  else if (Char < ' ' || Char > 0x7F || Char == ',')
2036  {
2037  DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
2038  goto ErrorExit;
2039  }
2040  else if (Char == ' ')
2041  {
2042  *PtrChar = '_';
2043  }
2044  else if (Char == '\\')
2045  {
2046  SeparatorsCount++;
2047 
2048  if (SeparatorsCount > MaxSeparators)
2049  {
2050  DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
2051  SeparatorsCount, MaxSeparators);
2052  goto ErrorExit;
2053  }
2054  }
2055  }
2056 
2057  DPRINT1("IopValidateID: Not terminated ID\n");
2058 
2059 ErrorExit:
2060  // FIXME logging
2061  return FALSE;
2062 }
2063 
2064 NTSTATUS
2066  HANDLE InstanceKey)
2067 {
2068  IO_STACK_LOCATION Stack;
2070  PWSTR Ptr;
2072  NTSTATUS Status;
2074  BOOLEAN IsValidID;
2075 
2076  DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2077 
2078  RtlZeroMemory(&Stack, sizeof(Stack));
2079  Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
2080  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2081  &IoStatusBlock,
2083  &Stack);
2084  if (NT_SUCCESS(Status))
2085  {
2087 
2088  if (!IsValidID)
2089  {
2090  DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
2091  }
2092 
2093  TotalLength = 0;
2094 
2096  DPRINT("Hardware IDs:\n");
2097  while (*Ptr)
2098  {
2099  DPRINT(" %S\n", Ptr);
2100  Length = (ULONG)wcslen(Ptr) + 1;
2101 
2102  Ptr += Length;
2103  TotalLength += Length;
2104  }
2105  DPRINT("TotalLength: %hu\n", TotalLength);
2106  DPRINT("\n");
2107 
2108  RtlInitUnicodeString(&ValueName, L"HardwareID");
2109  Status = ZwSetValueKey(InstanceKey,
2110  &ValueName,
2111  0,
2112  REG_MULTI_SZ,
2114  (TotalLength + 1) * sizeof(WCHAR));
2115  if (!NT_SUCCESS(Status))
2116  {
2117  DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2118  }
2119  }
2120  else
2121  {
2122  DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2123  }
2124 
2125  return Status;
2126 }
2127 
2128 NTSTATUS
2130  HANDLE InstanceKey)
2131 {
2132  IO_STACK_LOCATION Stack;
2134  PWSTR Ptr;
2136  NTSTATUS Status;
2138  BOOLEAN IsValidID;
2139 
2140  DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2141 
2142  RtlZeroMemory(&Stack, sizeof(Stack));
2143  Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
2144  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2145  &IoStatusBlock,
2147  &Stack);
2149  {
2151 
2152  if (!IsValidID)
2153  {
2154  DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
2155  }
2156 
2157  TotalLength = 0;
2158 
2160  DPRINT("Compatible IDs:\n");
2161  while (*Ptr)
2162  {
2163  DPRINT(" %S\n", Ptr);
2164  Length = (ULONG)wcslen(Ptr) + 1;
2165 
2166  Ptr += Length;
2167  TotalLength += Length;
2168  }
2169  DPRINT("TotalLength: %hu\n", TotalLength);
2170  DPRINT("\n");
2171 
2172  RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
2173  Status = ZwSetValueKey(InstanceKey,
2174  &ValueName,
2175  0,
2176  REG_MULTI_SZ,
2178  (TotalLength + 1) * sizeof(WCHAR));
2179  if (!NT_SUCCESS(Status))
2180  {
2181  DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
2182  }
2183  }
2184  else
2185  {
2186  DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2187  }
2188 
2189  return Status;
2190 }
2191 
2192 NTSTATUS
2195  _Out_ PUNICODE_STRING InstancePath)
2196 {
2198  UNICODE_STRING DeviceId;
2200  IO_STACK_LOCATION Stack;
2201  NTSTATUS Status;
2202  UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
2204  BOOLEAN IsValidID;
2205 
2206  DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2207 
2208  Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
2209  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2210  &IoStatusBlock,
2212  &Stack);
2213  if (!NT_SUCCESS(Status))
2214  {
2215  DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
2216  return Status;
2217  }
2218 
2220 
2221  if (!IsValidID)
2222  {
2223  DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
2224  }
2225 
2226  /* Save the device id string */
2228 
2229  DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
2230 
2232  if (!NT_SUCCESS(Status))
2233  {
2234  DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
2235  RtlFreeUnicodeString(&DeviceId);
2236  return Status;
2237  }
2238 
2239  /* This bit is only check after enumeration */
2240  if (DeviceCapabilities.HardwareDisabled)
2241  {
2242  /* FIXME: Cleanup device */
2243  DeviceNode->Flags |= DNF_DISABLED;
2244  RtlFreeUnicodeString(&DeviceId);
2246  }
2247  else
2248  {
2249  DeviceNode->Flags &= ~DNF_DISABLED;
2250  }
2251 
2252  if (!DeviceCapabilities.UniqueID)
2253  {
2254  /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2255  DPRINT("Instance ID is not unique\n");
2256  Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
2257  if (!NT_SUCCESS(Status))
2258  {
2259  DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
2260  RtlFreeUnicodeString(&DeviceId);
2261  return Status;
2262  }
2263  }
2264 
2265  DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2266 
2267  Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
2268  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2269  &IoStatusBlock,
2271  &Stack);
2272  if (!NT_SUCCESS(Status))
2273  {
2274  DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
2276  }
2277 
2279  {
2281 
2282  if (!IsValidID)
2283  {
2284  DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
2285  }
2286  }
2287 
2290 
2291  InstancePath->Length = 0;
2292  InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
2293  ParentIdPrefix.Length +
2294  InstanceId.Length +
2295  sizeof(UNICODE_NULL);
2296  if (ParentIdPrefix.Length && InstanceId.Length)
2297  {
2298  InstancePath->MaximumLength += sizeof(WCHAR);
2299  }
2300 
2301  InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
2302  InstancePath->MaximumLength,
2303  TAG_IO);
2304  if (!InstancePath->Buffer)
2305  {
2307  RtlFreeUnicodeString(&ParentIdPrefix);
2308  RtlFreeUnicodeString(&DeviceId);
2310  }
2311 
2312  /* Start with the device id */
2313  RtlCopyUnicodeString(InstancePath, &DeviceId);
2314  RtlAppendUnicodeToString(InstancePath, L"\\");
2315 
2316  /* Add information from parent bus device to InstancePath */
2317  RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
2318  if (ParentIdPrefix.Length && InstanceId.Length)
2319  {
2320  RtlAppendUnicodeToString(InstancePath, L"&");
2321  }
2322 
2323  /* Finally, add the id returned by the driver stack */
2325 
2326  /*
2327  * FIXME: Check for valid characters, if there is invalid characters
2328  * then bugcheck
2329  */
2330 
2332  RtlFreeUnicodeString(&DeviceId);
2333  RtlFreeUnicodeString(&ParentIdPrefix);
2334 
2335  return STATUS_SUCCESS;
2336 }
2337 
2338 /*
2339  * IopActionInterrogateDeviceStack
2340  *
2341  * Retrieve information for all (direct) child nodes of a parent node.
2342  *
2343  * Parameters
2344  * DeviceNode
2345  * Pointer to device node.
2346  * Context
2347  * Pointer to parent node to retrieve child node information for.
2348  *
2349  * Remarks
2350  * Any errors that occur are logged instead so that all child services have a chance
2351  * of being interrogated.
2352  */
2353 
2354 NTSTATUS
2356  PVOID Context)
2357 {
2360  PWSTR LocationInformation;
2361  PDEVICE_NODE ParentDeviceNode;
2362  IO_STACK_LOCATION Stack;
2363  NTSTATUS Status;
2365  LCID LocaleId;
2366  HANDLE InstanceKey = NULL;
2368  UNICODE_STRING InstancePathU;
2369  PDEVICE_OBJECT OldDeviceObject;
2370 
2371  DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2372  DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2373 
2374  ParentDeviceNode = (PDEVICE_NODE)Context;
2375 
2376  /*
2377  * We are called for the parent too, but we don't need to do special
2378  * handling for this node
2379  */
2380  if (DeviceNode == ParentDeviceNode)
2381  {
2382  DPRINT("Success\n");
2383  return STATUS_SUCCESS;
2384  }
2385 
2386  /*
2387  * Make sure this device node is a direct child of the parent device node
2388  * that is given as an argument
2389  */
2390  if (DeviceNode->Parent != ParentDeviceNode)
2391  {
2392  DPRINT("Skipping 2+ level child\n");
2393  return STATUS_SUCCESS;
2394  }
2395 
2396  /* Skip processing if it was already completed before */
2397  if (DeviceNode->Flags & DNF_PROCESSED)
2398  {
2399  /* Nothing to do */
2400  return STATUS_SUCCESS;
2401  }
2402 
2403  /* Get Locale ID */
2404  Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2405  if (!NT_SUCCESS(Status))
2406  {
2407  DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2408  return Status;
2409  }
2410 
2411  /*
2412  * FIXME: For critical errors, cleanup and disable device, but always
2413  * return STATUS_SUCCESS.
2414  */
2415 
2416  Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
2417  if (!NT_SUCCESS(Status))
2418  {
2420  {
2421  DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
2422  }
2423 
2424  /* We have to return success otherwise we abort the traverse operation */
2425  return STATUS_SUCCESS;
2426  }
2427 
2428  /* Verify that this is not a duplicate */
2429  OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
2430  if (OldDeviceObject != NULL)
2431  {
2432  PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
2433 
2434  DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
2435  DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
2436  DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
2437 
2438  KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
2439  0x01,
2440  (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
2441  (ULONG_PTR)OldDeviceObject,
2442  0);
2443  }
2444 
2445  DeviceNode->InstancePath = InstancePathU;
2446 
2447  DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2448 
2449  /*
2450  * Create registry key for the instance id, if it doesn't exist yet
2451  */
2452  Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
2453  if (!NT_SUCCESS(Status))
2454  {
2455  DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2456 
2457  /* We have to return success otherwise we abort the traverse operation */
2458  return STATUS_SUCCESS;
2459  }
2460 
2461  IopQueryHardwareIds(DeviceNode, InstanceKey);
2462 
2463  IopQueryCompatibleIds(DeviceNode, InstanceKey);
2464 
2465  DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2466 
2467  Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2468  Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2469  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2470  &IoStatusBlock,
2472  &Stack);
2474  : NULL;
2475  /* This key is mandatory, so even if the Irp fails, we still write it */
2476  RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2477  if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2478  {
2479  if (DeviceDescription &&
2481  {
2482  /* This key is overriden when a driver is installed. Don't write the
2483  * new description if another one already exists */
2484  Status = ZwSetValueKey(InstanceKey,
2485  &ValueName,
2486  0,
2487  REG_SZ,
2489  ((ULONG)wcslen(DeviceDescription) + 1) * sizeof(WCHAR));
2490  }
2491  else
2492  {
2493  UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2494  DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2495 
2496  Status = ZwSetValueKey(InstanceKey,
2497  &ValueName,
2498  0,
2499  REG_SZ,
2500  DeviceDesc.Buffer,
2501  DeviceDesc.MaximumLength);
2502  if (!NT_SUCCESS(Status))
2503  {
2504  DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2505  }
2506 
2507  }
2508  }
2509 
2510  if (DeviceDescription)
2511  {
2513  }
2514 
2515  DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2516 
2517  Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2518  Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2519  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2520  &IoStatusBlock,
2522  &Stack);
2524  {
2525  LocationInformation = (PWSTR)IoStatusBlock.Information;
2526  DPRINT("LocationInformation: %S\n", LocationInformation);
2527  RtlInitUnicodeString(&ValueName, L"LocationInformation");
2528  Status = ZwSetValueKey(InstanceKey,
2529  &ValueName,
2530  0,
2531  REG_SZ,
2532  LocationInformation,
2533  ((ULONG)wcslen(LocationInformation) + 1) * sizeof(WCHAR));
2534  if (!NT_SUCCESS(Status))
2535  {
2536  DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2537  }
2538 
2539  ExFreePoolWithTag(LocationInformation, 0);
2540  }
2541  else
2542  {
2543  DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2544  }
2545 
2546  DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2547 
2548  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2549  &IoStatusBlock,
2551  NULL);
2553  {
2555 
2556  DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2557  DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2558  DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2559  ExFreePoolWithTag(BusInformation, 0);
2560  }
2561  else
2562  {
2563  DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2564 
2565  DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2566  DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2567  DeviceNode->ChildBusTypeIndex = -1;
2568  }
2569 
2570  DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2571 
2572  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2573  &IoStatusBlock,
2575  NULL);
2577  {
2580  }
2581  else
2582  {
2583  DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2584  DeviceNode->BootResources = NULL;
2585  }
2586 
2587  DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2588 
2589  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2590  &IoStatusBlock,
2592  NULL);
2593  if (NT_SUCCESS(Status))
2594  {
2596  }
2597  else
2598  {
2599  DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2600  DeviceNode->ResourceRequirements = NULL;
2601  }
2602 
2603  if (InstanceKey != NULL)
2604  {
2605  IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2606  }
2607 
2608  ZwClose(InstanceKey);
2609 
2611 
2613  {
2614  /* Report the device to the user-mode pnp manager */
2615  IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2616  &DeviceNode->InstancePath);
2617  }
2618 
2619  return STATUS_SUCCESS;
2620 }
2621 
2622 static
2623 VOID
2626  IN PDEVICE_RELATIONS DeviceRelations)
2627 {
2628  PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2629  ULONG i;
2630  BOOLEAN Found;
2631 
2633  return;
2634 
2635  while (Child != NULL)
2636  {
2637  NextChild = Child->Sibling;
2638  Found = FALSE;
2639 
2640  for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
2641  {
2642  if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
2643  {
2644  Found = TRUE;
2645  break;
2646  }
2647  }
2648 
2649  if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
2650  {
2651  /* Send removal IRPs to all of its children */
2652  IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
2653 
2654  /* Send the surprise removal IRP */
2655  IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
2656 
2657  /* Tell the user-mode PnP manager that a device was removed */
2658  IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
2659  &Child->InstancePath);
2660 
2661  /* Send the remove device IRP */
2662  IopSendRemoveDevice(Child->PhysicalDeviceObject);
2663  }
2664 
2665  Child = NextChild;
2666  }
2667 }
2668 
2669 NTSTATUS
2672 {
2675  PDEVICE_RELATIONS DeviceRelations;
2676  PDEVICE_OBJECT ChildDeviceObject;
2678  PDEVICE_NODE ChildDeviceNode;
2679  IO_STACK_LOCATION Stack;
2680  NTSTATUS Status;
2681  ULONG i;
2682 
2683  DPRINT("DeviceObject 0x%p\n", DeviceObject);
2684 
2686  {
2688 
2689  DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2690  IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2691  &DeviceNode->InstancePath);
2692  }
2693 
2694  DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2695 
2696  Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2697 
2699  DeviceObject,
2700  &IoStatusBlock,
2702  &Stack);
2703  if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2704  {
2705  DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2706  return Status;
2707  }
2708 
2709  DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2710 
2711  /*
2712  * Send removal IRPs for devices that have disappeared
2713  * NOTE: This code handles the case where no relations are specified
2714  */
2715  IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2716 
2717  /* Now we bail if nothing was returned */
2718  if (!DeviceRelations)
2719  {
2720  /* We're all done */
2721  DPRINT("No PDOs\n");
2722  return STATUS_SUCCESS;
2723  }
2724 
2725  DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2726 
2727  /*
2728  * Create device nodes for all discovered devices
2729  */
2730  for (i = 0; i < DeviceRelations->Count; i++)
2731  {
2732  ChildDeviceObject = DeviceRelations->Objects[i];
2733  ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2734 
2735  ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2736  if (!ChildDeviceNode)
2737  {
2738  /* One doesn't exist, create it */
2740  DeviceNode,
2741  ChildDeviceObject,
2742  NULL,
2743  &ChildDeviceNode);
2744  if (NT_SUCCESS(Status))
2745  {
2746  /* Mark the node as enumerated */
2747  ChildDeviceNode->Flags |= DNF_ENUMERATED;
2748 
2749  /* Mark the DO as bus enumerated */
2750  ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2751  }
2752  else
2753  {
2754  /* Ignore this DO */
2755  DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2756  ObDereferenceObject(ChildDeviceObject);
2757  }
2758  }
2759  else
2760  {
2761  /* Mark it as enumerated */
2762  ChildDeviceNode->Flags |= DNF_ENUMERATED;
2763  ObDereferenceObject(ChildDeviceObject);
2764  }
2765  }
2766  ExFreePool(DeviceRelations);
2767 
2768  /*
2769  * Retrieve information about all discovered children from the bus driver
2770  */
2772  &Context,
2773  DeviceNode,
2775  DeviceNode);
2776 
2778  if (!NT_SUCCESS(Status))
2779  {
2780  DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2781  return Status;
2782  }
2783 
2784  /*
2785  * Retrieve configuration from the registry for discovered children
2786  */
2788  &Context,
2789  DeviceNode,
2791  DeviceNode);
2792 
2794  if (!NT_SUCCESS(Status))
2795  {
2796  DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2797  return Status;
2798  }
2799 
2800  /*
2801  * Initialize services for discovered children.
2802  */
2804  if (!NT_SUCCESS(Status))
2805  {
2806  DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2807  return Status;
2808  }
2809 
2810  DPRINT("IopEnumerateDevice() finished\n");
2811  return STATUS_SUCCESS;
2812 }
2813 
2814 
2815 /*
2816  * IopActionConfigureChildServices
2817  *
2818  * Retrieve configuration for all (direct) child nodes of a parent node.
2819  *
2820  * Parameters
2821  * DeviceNode
2822  * Pointer to device node.
2823  * Context
2824  * Pointer to parent node to retrieve child node configuration for.
2825  *
2826  * Remarks
2827  * Any errors that occur are logged instead so that all child services have a chance of beeing
2828  * configured.
2829  */
2830 
2831 NTSTATUS
2833  PVOID Context)
2834 {
2836  PDEVICE_NODE ParentDeviceNode;
2839  NTSTATUS Status;
2840  DEVICE_CAPABILITIES DeviceCaps;
2841 
2842  DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2843 
2844  ParentDeviceNode = (PDEVICE_NODE)Context;
2845 
2846  /*
2847  * We are called for the parent too, but we don't need to do special
2848  * handling for this node
2849  */
2850  if (DeviceNode == ParentDeviceNode)
2851  {
2852  DPRINT("Success\n");
2853  return STATUS_SUCCESS;
2854  }
2855 
2856  /*
2857  * Make sure this device node is a direct child of the parent device node
2858  * that is given as an argument
2859  */
2860 
2861  if (DeviceNode->Parent != ParentDeviceNode)
2862  {
2863  DPRINT("Skipping 2+ level child\n");
2864  return STATUS_SUCCESS;
2865  }
2866 
2867  if (!(DeviceNode->Flags & DNF_PROCESSED))
2868  {
2869  DPRINT1("Child not ready to be configured\n");
2870  return STATUS_SUCCESS;
2871  }
2872 
2873  if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2874  {
2875  UNICODE_STRING RegKey;
2876 
2877  /* Install the service for this if it's in the CDDB */
2879 
2880  /*
2881  * Retrieve configuration from Enum key
2882  */
2883 
2884  Service = &DeviceNode->ServiceName;
2885 
2889 
2890  QueryTable[0].Name = L"Service";
2893 
2894  QueryTable[1].Name = L"ClassGUID";
2898  QueryTable[1].DefaultData = L"";
2899  QueryTable[1].DefaultLength = 0;
2900 
2901  RegKey.Length = 0;
2902  RegKey.MaximumLength = sizeof(ENUM_ROOT) + sizeof(WCHAR) + DeviceNode->InstancePath.Length;
2904  RegKey.MaximumLength,
2905  TAG_IO);
2906  if (RegKey.Buffer == NULL)
2907  {
2910  }
2911 
2913  RtlAppendUnicodeToString(&RegKey, L"\\");
2914  RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2915 
2917  RegKey.Buffer, QueryTable, NULL, NULL);
2918  ExFreePoolWithTag(RegKey.Buffer, TAG_IO);
2919 
2920  if (!NT_SUCCESS(Status))
2921  {
2922  /* FIXME: Log the error */
2923  DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2924  &DeviceNode->InstancePath, Status);
2926  return STATUS_SUCCESS;
2927  }
2928 
2929  if (Service->Buffer == NULL)
2930  {
2931  if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2932  DeviceCaps.RawDeviceOK)
2933  {
2934  DPRINT("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2935  RtlInitEmptyUnicodeString(&DeviceNode->ServiceName, NULL, 0);
2936  }
2937  else if (ClassGUID.Length != 0)
2938  {
2939  /* Device has a ClassGUID value, but no Service value.
2940  * Suppose it is using the NULL driver, so state the
2941  * device is started */
2942  DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2944  }
2945  else
2946  {
2949  }
2950  return STATUS_SUCCESS;
2951  }
2952 
2953  DPRINT("Got Service %S\n", Service->Buffer);
2954  }
2955 
2956  return STATUS_SUCCESS;
2957 }
2958 
2959 /*
2960  * IopActionInitChildServices
2961  *
2962  * Initialize the service for all (direct) child nodes of a parent node
2963  *
2964  * Parameters
2965  * DeviceNode
2966  * Pointer to device node.
2967  * Context
2968  * Pointer to parent node to initialize child node services for.
2969  *
2970  * Remarks
2971  * If the driver image for a service is not loaded and initialized
2972  * it is done here too. Any errors that occur are logged instead so
2973  * that all child services have a chance of being initialized.
2974  */
2975 
2976 NTSTATUS
2978  PVOID Context)
2979 {
2980  PDEVICE_NODE ParentDeviceNode;
2981  NTSTATUS Status;
2982  BOOLEAN BootDrivers = !PnpSystemInit;
2983 
2984  DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2985 
2986  ParentDeviceNode = Context;
2987 
2988  /*
2989  * We are called for the parent too, but we don't need to do special
2990  * handling for this node
2991  */
2992  if (DeviceNode == ParentDeviceNode)
2993  {
2994  DPRINT("Success\n");
2995  return STATUS_SUCCESS;
2996  }
2997 
2998  /*
2999  * We don't want to check for a direct child because
3000  * this function is called during boot to reinitialize
3001  * devices with drivers that couldn't load yet due to
3002  * stage 0 limitations (ie can't load from disk yet).
3003  */
3004 
3005  if (!(DeviceNode->Flags & DNF_PROCESSED))
3006  {
3007  DPRINT1("Child not ready to be added\n");
3008  return STATUS_SUCCESS;
3009  }
3010 
3014  return STATUS_SUCCESS;
3015 
3016  if (DeviceNode->ServiceName.Buffer == NULL)
3017  {
3018  /* We don't need to worry about loading the driver because we're
3019  * being driven in raw mode so our parent must be loaded to get here */
3021  if (NT_SUCCESS(Status))
3022  {
3024  if (!NT_SUCCESS(Status))
3025  {
3026  DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
3027  &DeviceNode->InstancePath, Status);
3028  }
3029  }
3030  }
3031  else
3032  {
3033  PLDR_DATA_TABLE_ENTRY ModuleObject;
3035 
3038  /* Get existing DriverObject pointer (in case the driver has
3039  already been loaded and initialized) */
3041  &DriverObject,
3042  &DeviceNode->ServiceName,
3043  FALSE);
3044 
3045  if (!NT_SUCCESS(Status))
3046  {
3047  /* Driver is not initialized, try to load it */
3048  Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
3049 
3051  {
3052  /* Initialize the driver */
3054  &DeviceNode->ServiceName, FALSE, &DriverObject);
3056  }
3058  {
3059  DPRINT1("Service '%wZ' is disabled\n", &DeviceNode->ServiceName);
3061  }
3062  else
3063  {
3064  DPRINT("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
3065  &DeviceNode->ServiceName, Status);
3066  if (!BootDrivers) DeviceNode->Problem = CM_PROB_DRIVER_FAILED_LOAD;
3067  }
3068  }
3071 
3072  /* Driver is loaded and initialized at this point */
3073  if (NT_SUCCESS(Status))
3074  {
3075  /* Initialize the device, including all filters */
3077 
3078  /* Remove the extra reference */
3080  }
3081  else
3082  {
3083  /*
3084  * Don't disable when trying to load only boot drivers
3085  */
3086  if (!BootDrivers)
3087  {
3089  }
3090  }
3091  }
3092 
3093  return STATUS_SUCCESS;
3094 }
3095 
3096 /*
3097  * IopInitializePnpServices
3098  *
3099  * Initialize services for discovered children
3100  *
3101  * Parameters
3102  * DeviceNode
3103  * Top device node to start initializing services.
3104  *
3105  * Return Value
3106  * Status
3107  */
3108 NTSTATUS
3110 {
3112 
3113  DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
3114 
3116  &Context,
3117  DeviceNode,
3119  DeviceNode);
3120 
3121  return IopTraverseDeviceTree(&Context);
3122 }
3123 
3124 static
3125 INIT_FUNCTION
3126 NTSTATUS
3128  IN HANDLE hBaseKey,
3129  IN PUNICODE_STRING RelativePath OPTIONAL,
3130  IN HANDLE hRootKey,
3131  IN BOOLEAN EnumerateSubKeys,
3132  IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
3133  IN ULONG ParentBootResourcesLength)
3134 {
3135  UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3136  UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3137  UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
3138  UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
3139  UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
3141  HANDLE hDevicesKey = NULL;
3142  HANDLE hDeviceKey = NULL;
3143  HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
3144  UNICODE_STRING Level2NameU;
3145  WCHAR Level2Name[5];
3146  ULONG IndexDevice = 0;
3147  ULONG IndexSubKey;
3148  PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3149  ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3150  PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3151  ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3154  PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
3155  ULONG BootResourcesLength;
3156  NTSTATUS Status;
3157 
3158  const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
3159  UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
3160  static ULONG DeviceIndexSerial = 0;
3161  const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
3162  UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
3163  static ULONG DeviceIndexKeyboard = 0;
3164  const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
3165  UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
3166  static ULONG DeviceIndexMouse = 0;
3167  const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
3168  UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
3169  static ULONG DeviceIndexParallel = 0;
3170  const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
3171  UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
3172  static ULONG DeviceIndexFloppy = 0;
3173  UNICODE_STRING HardwareIdKey;
3174  PUNICODE_STRING pHardwareId;
3175  ULONG DeviceIndex = 0;
3176  PUCHAR CmResourceList;
3177  ULONG ListCount;
3178 
3179  if (RelativePath)
3180  {
3181  Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
3182  if (!NT_SUCCESS(Status))
3183  {
3184  DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3185  goto cleanup;
3186  }
3187  }
3188  else
3189  hDevicesKey = hBaseKey;
3190 
3191  pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3192  if (!pDeviceInformation)
3193  {
3194  DPRINT("ExAllocatePool() failed\n");
3196  goto cleanup;
3197  }
3198 
3199  pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3200  if (!pValueInformation)
3201  {
3202  DPRINT("ExAllocatePool() failed\n");
3204  goto cleanup;
3205  }
3206 
3207  while (TRUE)
3208  {
3209  Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3211  break;
3213  {
3214  ExFreePool(pDeviceInformation);
3215  DeviceInfoLength = RequiredSize;
3216  pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3217  if (!pDeviceInformation)
3218  {
3219  DPRINT("ExAllocatePool() failed\n");
3221  goto cleanup;
3222  }
3223  Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3224  }
3225  if (!NT_SUCCESS(Status))
3226  {
3227  DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3228  goto cleanup;
3229  }
3230  IndexDevice++;
3231 
3232  /* Open device key */
3233  DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3234  DeviceName.Buffer = pDeviceInformation->Name;
3235 
3236  Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3237  KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3238  if (!NT_SUCCESS(Status))
3239  {
3240  DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3241  goto cleanup;
3242  }
3243 
3244  /* Read boot resources, and add then to parent ones */
3245  Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3247  {
3248  ExFreePool(pValueInformation);
3249  ValueInfoLength = RequiredSize;
3250  pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3251  if (!pValueInformation)
3252  {
3253  DPRINT("ExAllocatePool() failed\n");
3254  ZwDeleteKey(hLevel2Key);
3256  goto cleanup;
3257  }
3258  Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3259  }
3261  {
3262  BootResources = ParentBootResources;
3263  BootResourcesLength = ParentBootResourcesLength;
3264  }
3265  else if (!NT_SUCCESS(Status))
3266  {
3267  DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3268  goto nextdevice;
3269  }
3270  else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3271  {
3272  DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3273  goto nextdevice;
3274  }
3275  else
3276  {
3277  static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3278 
3279  /* Concatenate current resources and parent ones */
3280  if (ParentBootResourcesLength == 0)
3281  BootResourcesLength = pValueInformation->DataLength;
3282  else
3283  BootResourcesLength = ParentBootResourcesLength
3284  + pValueInformation->DataLength
3285  - Header;
3286  BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3287  if (!BootResources)
3288  {
3289  DPRINT("ExAllocatePool() failed\n");
3290  goto nextdevice;
3291  }
3292  if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3293  {
3294  RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3295  }
3296  else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3297  {
3298  RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3299  RtlCopyMemory(
3300  (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3301  (PVOID)((ULONG_PTR)ParentBootResources + Header),
3302  ParentBootResourcesLength - Header);
3303  BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3304  }
3305  else
3306  {
3307  RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3308  RtlCopyMemory(
3309  (PVOID)((ULONG_PTR)BootResources + Header),
3310  (PVOID)((ULONG_PTR)ParentBootResources + Header),
3311  ParentBootResourcesLength - Header);
3312  RtlCopyMemory(
3313  (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3314  pValueInformation->Data + Header,
3315  pValueInformation->DataLength - Header);
3316  BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3317  }
3318  }
3319 
3320  if (EnumerateSubKeys)
3321  {
3322  IndexSubKey = 0;
3323  while (TRUE)
3324  {
3325  Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3327  break;
3329  {
3330  ExFreePool(pDeviceInformation);
3331  DeviceInfoLength = RequiredSize;
3332  pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3333  if (!pDeviceInformation)
3334  {
3335  DPRINT("ExAllocatePool() failed\n");
3337  goto cleanup;
3338  }
3339  Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3340  }
3341  if (!NT_SUCCESS(Status))
3342  {
3343  DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3344  goto cleanup;
3345  }
3346  IndexSubKey++;
3347  DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3348  DeviceName.Buffer = pDeviceInformation->Name;
3349 
3351  hDeviceKey,
3352  &DeviceName,
3353  hRootKey,
3354  TRUE,
3355  BootResources,
3356  BootResourcesLength);
3357  if (!NT_SUCCESS(Status))
3358  goto cleanup;
3359  }
3360  }
3361 
3362  /* Read identifier */
3363  Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3365  {
3366  ExFreePool(pValueInformation);
3367  ValueInfoLength = RequiredSize;
3368  pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3369  if (!pValueInformation)
3370  {
3371  DPRINT("ExAllocatePool() failed\n");
3373  goto cleanup;
3374  }
3375  Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3376  }
3377  if (!NT_SUCCESS(Status))
3378  {
3380  {
3381  DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3382  goto nextdevice;
3383  }
3385  }
3386  else if (pValueInformation->Type != REG_SZ)
3387  {
3388  DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3389  goto nextdevice;
3390  }
3391  else
3392  {
3393  /* Assign hardware id to this device */
3394  ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3395  ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3396  if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3397  ValueName.Length -= sizeof(WCHAR);
3398  }
3399 
3400  if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3401  {
3402  pHardwareId = &HardwareIdSerial;
3403  DeviceIndex = DeviceIndexSerial++;
3404  }
3405  else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3406  {
3407  pHardwareId = &HardwareIdKeyboard;
3408  DeviceIndex = DeviceIndexKeyboard++;
3409  }
3410  else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3411  {
3412  pHardwareId = &HardwareIdMouse;
3413  DeviceIndex = DeviceIndexMouse++;
3414  }
3415  else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3416  {
3417  pHardwareId = &HardwareIdParallel;
3418  DeviceIndex = DeviceIndexParallel++;
3419  }
3420  else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3421  {
3422  pHardwareId = &HardwareIdFloppy;
3423  DeviceIndex = DeviceIndexFloppy++;
3424  }
3425  else
3426  {
3427  /* Unknown key path */
3428  DPRINT("Unknown key path '%wZ'\n", RelativePath);
3429  goto nextdevice;
3430  }
3431 
3432  /* Prepare hardware id key (hardware id value without final \0) */
3433  HardwareIdKey = *pHardwareId;
3434  HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3435 
3436  /* Add the detected device to Root key */
3437  InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3438  Status = ZwCreateKey(
3439  &hLevel1Key,
3442  0,
3443  NULL,
3445  NULL);
3446  if (!NT_SUCCESS(Status))
3447  {
3448  DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3449  goto nextdevice;
3450  }
3451  swprintf(Level2Name, L"%04lu", DeviceIndex);
3452  RtlInitUnicodeString(&Level2NameU, Level2Name);
3453  InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3454  Status = ZwCreateKey(
3455  &hLevel2Key,
3458  0,
3459  NULL,
3461  NULL);
3462  ZwClose(hLevel1Key);
3463  if (!NT_SUCCESS(Status))
3464  {
3465  DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3466  goto nextdevice;
3467  }
3468  DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3469  Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3470  if (!NT_SUCCESS(Status))
3471  {
3472  DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3473  ZwDeleteKey(hLevel2Key);
3474  goto nextdevice;
3475  }
3476  /* Create 'LogConf' subkey */
3478  Status = ZwCreateKey(
3479  &hLogConf,
3480  KEY_SET_VALUE,
3482  0,
3483  NULL,
3485  NULL);
3486  if (!NT_SUCCESS(Status))
3487  {
3488  DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3489  ZwDeleteKey(hLevel2Key);
3490  goto nextdevice;
3491  }
3492  if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3493  {
3494  CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3495  if (!CmResourceList)
3496  {
3497  ZwClose(hLogConf);
3498  ZwDeleteKey(hLevel2Key);
3499  goto nextdevice;
3500  }
3501 
3502  /* Add the list count (1st member of CM_RESOURCE_LIST) */
3503  ListCount = 1;
3504  RtlCopyMemory(CmResourceList,
3505  &ListCount,
3506  sizeof(ULONG));
3507 
3508  /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3509  RtlCopyMemory(CmResourceList + sizeof(ULONG),
3510  BootResources,
3511  BootResourcesLength);
3512 
3513  /* Save boot resources to 'LogConf\BootConfig' */
3514  Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3515  if (!NT_SUCCESS(Status))
3516  {
3517  DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3518  ZwClose(hLogConf);
3519  ZwDeleteKey(hLevel2Key);
3520  goto nextdevice;
3521  }
3522  }
3523  ZwClose(hLogConf);
3524 
3525 nextdevice:
3526  if (BootResources && BootResources != ParentBootResources)
3527  {
3528  ExFreePool(BootResources);
3529  BootResources = NULL;
3530  }
3531  if (hLevel2Key)
3532  {
3533  ZwClose(hLevel2Key);
3534  hLevel2Key = NULL;
3535  }
3536  if (hDeviceKey)
3537  {
3538  ZwClose(hDeviceKey);
3539  hDeviceKey = NULL;
3540  }
3541  }
3542 
3544 
3545 cleanup:
3546  if (hDevicesKey && hDevicesKey != hBaseKey)
3547  ZwClose(hDevicesKey);
3548  if (hDeviceKey)
3549  ZwClose(hDeviceKey);
3550  if (pDeviceInformation)
3551  ExFreePool(pDeviceInformation);
3552  if (pValueInformation)
3553  ExFreePool(pValueInformation);
3554  return Status;
3555 }
3556 
3557 static
3558 INIT_FUNCTION
3559 BOOLEAN
3561 {
3562  UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3563  UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3565  HANDLE hPnpKey;
3566  PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3567  ULONG DesiredLength, Length;
3568  ULONG KeyValue = 0;
3569  NTSTATUS Status;
3570 
3572  Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3573  if (NT_SUCCESS(Status))
3574  {
3575  Status = ZwQueryValueKey(hPnpKey,
3576  &KeyNameU,
3578  NULL,
3579  0,
3580  &DesiredLength);
3581  if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3583  {
3584  Length = DesiredLength;
3585  KeyInformation = ExAllocatePool(PagedPool, Length);
3586  if (KeyInformation)
3587  {
3588  Status = ZwQueryValueKey(hPnpKey,
3589  &KeyNameU,
3591  KeyInformation,
3592  Length,
3593  &DesiredLength);
3594  if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3595  {
3596  KeyValue = (ULONG)(*KeyInformation->Data);
3597  }
3598  else
3599  {
3600  DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3601  }
3602 
3603  ExFreePool(KeyInformation);
3604  }
3605  else
3606  {
3607  DPRINT1("Failed to allocate memory for registry query\n");
3608  }
3609  }
3610  else
3611  {
3612  DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3613  }
3614 
3615  ZwClose(hPnpKey);
3616  }
3617  else
3618  {
3619  DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3620  }
3621 
3622  DPRINT("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3623 
3624  return (KeyValue != 0) ? TRUE : FALSE;
3625 }
3626 
3627 INIT_FUNCTION
3628 NTSTATUS
3629 NTAPI
3631 {
3632  UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3633  UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3634  UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3636  HANDLE hEnum, hRoot;
3637  NTSTATUS Status;
3638 
3641  if (!NT_SUCCESS(Status))
3642  {
3643  DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3644  return Status;
3645  }
3646 
3649  ZwClose(hEnum);
3650  if (!NT_SUCCESS(Status))
3651  {
3652  DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3653  return Status;
3654  }
3655 
3657  {
3658  Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3659  if (!NT_SUCCESS(Status))
3660  {
3661  /* Nothing to do, don't return with an error status */
3662  DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3663  ZwClose(hRoot);
3664  return STATUS_SUCCESS;
3665  }
3667  hEnum,
3668  NULL,
3669  hRoot,
3670  TRUE,
3671  NULL,
3672  0);
3673  ZwClose(hEnum);
3674  }
3675  else
3676  {
3677  /* Enumeration is disabled */
3679  }
3680 
3681  ZwClose(hRoot);
3682 
3683  return Status;
3684 }
3685 
3686 NTSTATUS
3687 NTAPI
3689  HANDLE ParentKey,
3692 {
3694  NTSTATUS Status;
3695 
3696  PAGED_CODE();
3697 
3698  *KeyHandle = NULL;
3699 
3701  Name,
3703  ParentKey,
3704  NULL);
3705 
3707 
3708  return Status;
3709 }
3710 
3711 NTSTATUS
3712 NTAPI
3714  IN HANDLE RootHandle OPTIONAL,
3719 {
3721  ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3722  USHORT Length;
3723  HANDLE HandleArray[2];
3724  BOOLEAN Recursing = TRUE;
3725  PWCHAR pp, p, p1;
3726  UNICODE_STRING KeyString;
3728  PAGED_CODE();
3729 
3730  /* P1 is start, pp is end */
3731  p1 = KeyName->Buffer;
3732  pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3733 
3734  /* Create the target key */
3736  KeyName,
3738  RootHandle,
3739  NULL);
3740  Status = ZwCreateKey(&HandleArray[i],
3741  DesiredAccess,
3743  0,
3744  NULL,
3745  CreateOptions,
3746  &KeyDisposition);
3747 
3748  /* Now we check if this failed */
3749  if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3750  {
3751  /* Target key failed, so we'll need to create its parent. Setup array */
3752  HandleArray[0] = NULL;
3753  HandleArray[1] = RootHandle;
3754 
3755  /* Keep recursing for each missing parent */
3756  while (Recursing)
3757  {
3758  /* And if we're deep enough, close the last handle */
3759  if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3760 
3761  /* We're setup to ping-pong between the two handle array entries */
3762  RootHandleIndex = i;
3763  i = (i + 1) & 1;
3764 
3765  /* Clear the one we're attempting to open now */
3766  HandleArray[i] = NULL;
3767 
3768  /* Process the parent key name */
3769  for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3770  Length = (USHORT)(p - p1) * sizeof(WCHAR);
3771 
3772  /* Is there a parent name? */
3773  if (Length)
3774  {
3775  /* Build the unicode string for it */
3776  KeyString.Buffer = p1;
3777  KeyString.Length = KeyString.MaximumLength = Length;
3778 
3779  /* Now try opening the parent */
3781  &KeyString,
3783  HandleArray[RootHandleIndex],
3784  NULL);
3785  Status = ZwCreateKey(&HandleArray[i],
3786  DesiredAccess,
3788  0,
3789  NULL,
3790  CreateOptions,
3791  &KeyDisposition);
3792  if (NT_SUCCESS(Status))
3793  {
3794  /* It worked, we have one more handle */
3795  NestedCloseLevel++;
3796  }
3797  else
3798  {
3799  /* Parent key creation failed, abandon loop */
3800  Recursing = FALSE;
3801  continue;
3802  }
3803  }
3804  else
3805  {
3806  /* We don't have a parent name, probably corrupted key name */
3808  Recursing = FALSE;
3809  continue;
3810  }
3811 
3812  /* Now see if there's more parents to create */
3813  p1 = p + 1;
3814  if ((p == pp) || (p1 == pp))
3815  {
3816  /* We're done, hopefully successfully, so stop */
3817  Recursing = FALSE;
3818  }
3819  }
3820 
3821  /* Outer loop check for handle nesting that requires closing the top handle */
3822  if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3823  }
3824 
3825  /* Check if we broke out of the loop due to success */
3826  if (NT_SUCCESS(Status))
3827  {
3828  /* Return the target handle (we closed all the parent ones) and disposition */
3829  *Handle = HandleArray[i];
3830  if (Disposition) *Disposition = KeyDisposition;
3831  }
3832 
3833  /* Return the success state */
3834  return Status;
3835 }
3836 
3837 NTSTATUS
3838 NTAPI
3840  IN PWSTR ValueName,
3842 {
3843  UNICODE_STRING ValueString;
3844  NTSTATUS Status;
3845  PKEY_VALUE_FULL_INFORMATION FullInformation;
3846  ULONG Size;
3847  PAGED_CODE();
3848 
3849  RtlInitUnicodeString(&ValueString, ValueName);
3850 
3851  Status = ZwQueryValueKey(Handle,
3852  &ValueString,
3854  NULL,
3855  0,
3856  &Size);
3857  if ((Status != STATUS_BUFFER_OVERFLOW) &&
3859  {
3860  return Status;
3861  }
3862 
3863  FullInformation = ExAllocatePool(NonPagedPool, Size);
3864  if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3865 
3866  Status = ZwQueryValueKey(Handle,
3867  &ValueString,
3869  FullInformation,
3870  Size,
3871  &Size);
3872  if (!NT_SUCCESS(Status))
3873  {
3874  ExFreePool(FullInformation);
3875  return Status;
3876  }
3877 
3878  *Information = FullInformation;
3879  return STATUS_SUCCESS;
3880 }
3881 
3883 NTAPI
3887 {
3888  /* FIXME: TODO */
3889  ASSERT(FALSE);
3890  return 0;
3891 }
3892 
3893 //
3894 // The allocation function is called by the generic table package whenever
3895 // it needs to allocate memory for the table.
3896 //
3897 
3898 PVOID
3899 NTAPI
3901  IN CLONG ByteSize)
3902 {
3903  /* FIXME: TODO */
3904  ASSERT(FALSE);
3905  return NULL;
3906 }
3907 
3908 VOID
3909 NTAPI
3911  IN PVOID Buffer)
3912 {
3913  /* FIXME: TODO */
3914  ASSERT(FALSE);
3915 }
3916 
3917 VOID
3918 NTAPI
3920 {
3921  /* Setup the guarded mutex and AVL table */
3928  NULL);
3929 }
3930 
3931 BOOLEAN
3932 NTAPI
3934 {
3935  /* Initialize the resource when accessing device registry data */
3937 
3938  /* Setup the device reference AVL table */
3940  return TRUE;
3941 }
3942 
3943 BOOLEAN
3944 NTAPI
3946 {
3947  /* Check the initialization phase */
3948  switch (ExpInitializationPhase)
3949  {
3950  case 0:
3951 
3952  /* Do Phase 0 */
3953  return PiInitPhase0();
3954 
3955  case 1:
3956 
3957  /* Do Phase 1 */
3958  return TRUE;
3959  //return PiInitPhase1();
3960 
3961  default:
3962 
3963  /* Don't know any other phase! Bugcheck! */
3964  KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3965  return FALSE;
3966  }
3967 }
3968 
3970 
3972 NTAPI
3974 {
3976  PAGED_CODE();
3977 
3978  /* Allocate it */
3980  if (!DeviceNode) return DeviceNode;
3981 
3982  /* Statistics */
3984 
3985  /* Set it up */
3987  DeviceNode->InterfaceType = InterfaceTypeUndefined;
3988  DeviceNode->BusNumber = -1;
3989  DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3990  DeviceNode->ChildBusNumber = -1;
3991  DeviceNode->ChildBusTypeIndex = -1;
3992 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3993  InitializeListHead(&DeviceNode->DeviceArbiterList);
3994  InitializeListHead(&DeviceNode->DeviceTranslatorList);
3995  InitializeListHead(&DeviceNode->TargetDeviceNotify);
3996  InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3997  InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3998 
3999  /* Check if there is a PDO */
4001  {
4002  /* Link it and remove the init flag */
4003  DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
4004  ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
4006  }
4007 
4008  /* Return the node */
4009  return DeviceNode;
4010 }
4011 
4012 /* PUBLIC FUNCTIONS **********************************************************/
4013 
4014 NTSTATUS
4015 NTAPI
4017  IN LPGUID BusTypeGuid)
4018 {
4020 
4021  /* Acquire the lock */
4023 
4024  /* Validate size */
4025  if (Index < PnpBusTypeGuidList->GuidCount)
4026  {
4027  /* Copy the data */
4028  RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
4029  }
4030  else
4031  {
4032  /* Failure path */
4034  }
4035 
4036  /* Release lock and return status */
4038  return Status;
4039 }
4040 
4041 NTSTATUS
4042 NTAPI
4044  IN PHANDLE DeviceInstanceHandle,
4046 {
4047  NTSTATUS Status;
4048  HANDLE KeyHandle;
4050  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
4051  PAGED_CODE();
4052 
4053  /* Open the enum key */
4055  NULL,
4056  &KeyName,
4057  KEY_READ);
4058  if (!NT_SUCCESS(Status)) return Status;
4059 
4060  /* Make sure we have an instance path */
4062  if ((DeviceNode) && (DeviceNode->InstancePath.Length))
4063  {
4064  /* Get the instance key */
4065  Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
4066  KeyHandle,
4067  &DeviceNode->InstancePath,
4068  DesiredAccess);
4069  }
4070  else
4071  {
4072  /* Fail */
4074  }
4075 
4076  /* Close the handle and return status */
4077  ZwClose(KeyHandle);
4078  return Status;
4079 }
4080 
4081 ULONG
4082 NTAPI
4084 {
4085  ULONG FinalSize, PartialSize, EntrySize, i, j;
4086  PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
4087  PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
4088 
4089  /* If we don't have one, that's easy */
4090  if (!ResourceList) return 0;
4091 
4092  /* Start with the minimum size possible */
4093  FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
4094 
4095  /* Loop each full descriptor */
4096  FullDescriptor = ResourceList->List;
4097  for (i = 0; i < ResourceList->Count; i++)
4098  {
4099  /* Start with the minimum size possible */
4100  PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
4101  FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
4102 
4103  /* Loop each partial descriptor */
4104  PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
4105  for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
4106  {
4107  /* Start with the minimum size possible */
4109 
4110  /* Check if there is extra data */
4111  if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
4112  {
4113  /* Add that data */
4114  EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
4115  }
4116 
4117  /* The size of partial descriptors is bigger */
4118  PartialSize += EntrySize;
4119 
4120  /* Go to the next partial descriptor */
4121  PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
4122  }
4123 
4124  /* The size of full descriptors is bigger */
4125  FinalSize += PartialSize;
4126 
4127  /* Go to the next full descriptor */
4128  FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
4129  }
4130 
4131  /* Return the final size */
4132  return FinalSize;
4133 }
4134 
4135 NTSTATUS
4136 NTAPI
4138  IN ULONG ValueType,
4139  IN PWSTR ValueName,
4140  IN PWSTR KeyName,
4141  OUT PVOID Buffer,
4143 {
4144  NTSTATUS Status;
4145  HANDLE KeyHandle, SubHandle;
4146  UNICODE_STRING KeyString;
4147  PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
4148  ULONG Length;
4149  PAGED_CODE();
4150 
4151  /* Find the instance key */
4153  if (NT_SUCCESS(Status))
4154  {
4155  /* Check for name given by caller */
4156  if (KeyName)
4157  {
4158  /* Open this key */
4159  RtlInitUnicodeString(&KeyString, KeyName);
4160  Status = IopOpenRegistryKeyEx(&SubHandle,
4161  KeyHandle,
4162  &KeyString,
4163  KEY_READ);
4164  if (NT_SUCCESS(Status))
4165  {
4166  /* And use this handle instead */
4167  ZwClose(KeyHandle);
4168  KeyHandle = SubHandle;
4169  }
4170  }
4171 
4172  /* Check if sub-key handle succeeded (or no-op if no key name given) */
4173  if (NT_SUCCESS(Status))
4174  {
4175  /* Now get the size of the property */
4177  ValueName,
4178  &KeyValueInfo);
4179  }
4180 
4181  /* Close the key */
4182  ZwClose(KeyHandle);
4183  }
4184 
4185  /* Fail if any of the registry operations failed */
4186  if (!NT_SUCCESS(Status)) return Status;
4187 
4188  /* Check how much data we have to copy */
4189  Length = KeyValueInfo->DataLength;
4190  if (*BufferLength >= Length)
4191  {
4192  /* Check for a match in the value type */
4193  if (KeyValueInfo->Type == ValueType)
4194  {
4195  /* Copy the data */
4197  (PVOID)((ULONG_PTR)KeyValueInfo +
4198  KeyValueInfo->DataOffset),
4199  Length);
4200  }
4201  else
4202  {
4203  /* Invalid registry property type, fail */
4205  }
4206  }
4207  else
4208  {
4209  /* Buffer is too small to hold data */
4211  }
4212 
4213  /* Return the required buffer length, free the buffer, and return status */
4214  *BufferLength = Length;
4215  ExFreePool(KeyValueInfo);
4216  return Status;
4217 }
4218 
4219 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
4220 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
4221 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED_DBGBREAK(); break;}
4222 
4223 /*
4224  * @implemented
4225  */
4226 NTSTATUS
4227 NTAPI
4231  OUT PVOID PropertyBuffer,
4233 {
4235  DEVICE_CAPABILITIES DeviceCaps;
4236  ULONG ReturnLength = 0, Length = 0, ValueType;
4237  PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
4238  PVOID Data = NULL;
4240  GUID BusTypeGuid;
4241  POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
4242  BOOLEAN NullTerminate = FALSE;
4243 
4244  DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
4245 
4246  /* Assume failure */
4247  *ResultLength = 0;
4248 
4249  /* Only PDOs can call this */
4251 
4252  /* Handle all properties */
4253  switch (DeviceProperty)
4254  {
4256 
4257  /* Get the GUID from the internal cache */
4258  Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
4259  if (!NT_SUCCESS(Status)) return Status;
4260 
4261  /* This is the format of the returned data */
4262  PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
4263 
4265 
4266  /* Validate correct interface type */
4267  if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
4269 
4270  /* This is the format of the returned data */
4271  PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
4272 
4274 
4275  /* Validate correct bus number */
4276  if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
4278 
4279  /* This is the format of the returned data */
4280  PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
4281 
4283 
4284  /* Get the instance path */
4285  DeviceInstanceName = DeviceNode->InstancePath.Buffer;
4286 
4287  /* Sanity checks */
4288  ASSERT((BufferLength & 1) == 0);
4289  ASSERT(DeviceInstanceName != NULL);
4290 
4291  /* Get the name from the path */
4292  EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
4293  ASSERT(EnumeratorNameEnd);
4294 
4295  /* This string needs to be NULL-terminated */
4296  NullTerminate = TRUE;
4297 
4298  /* This is the format of the returned data */
4299  PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
4300  DeviceInstanceName);
4301 
4302  case DevicePropertyAddress:
4303 
4304  /* Query the device caps */
4306  if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
4308 
4309  /* This is the format of the returned data */
4310  PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
4311 
4313 
4314  /* Validate we have resources */
4315  if (!DeviceNode->BootResources)
4316 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
4317  {
4318  /* No resources will still fake success, but with 0 bytes */
4319  *ResultLength = 0;
4320  return STATUS_SUCCESS;
4321  }
4322 
4323  /* This is the format of the returned data */
4324  PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
4325  DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
4326 
4328 
4329  /* Sanity check for Unicode-sized string */
4330  ASSERT((BufferLength & 1) == 0);
4331 
4332  /* Allocate name buffer */
4334  ObjectNameInfo = ExAllocatePool(PagedPool, Length);
4335  if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
4336 
4337  /* Query the PDO name */
4339  ObjectNameInfo,
4340  Length,
4341  ResultLength);
4343  {
4344  /* It's up to the caller to try again */
4346  }
4347 
4348  /* This string needs to be NULL-terminated */
4349  NullTerminate = TRUE;
4350 
4351  /* Return if successful */
4352  if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
4353  ObjectNameInfo->Name.Buffer);
4354 
4355  /* Let the caller know how big the name is */
4357  break;
4358 
4360  PIP_RETURN_DATA(sizeof(UCHAR), &DeviceNode->RemovalPolicy);
4361 
4362  /* Handle the registry-based properties */
4386  //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
4388  break;
4391  break;
4396  default:
4398  }
4399 
4400  /* Having a registry value name implies registry data */
4401  if (ValueName)
4402  {
4403  /* We know up-front how much data to expect */
4405 
4406  /* Go get the data, use the LogConf subkey if necessary */
4408  ValueType,
4409  ValueName,
4410  (DeviceProperty ==
4412  L"LogConf": NULL,
4413  PropertyBuffer,
4414  ResultLength);
4415  }
4416  else if (NT_SUCCESS(Status))
4417  {
4418  /* We know up-front how much data to expect, check the caller's buffer */
4419  *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
4420  if (*ResultLength <= BufferLength)
4421  {
4422  /* Buffer is all good, copy the data */
4423  RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
4424 
4425  /* Check if we need to NULL-terminate the string */
4426  if (NullTerminate)
4427  {
4428  /* Terminate the string */
4429  ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
4430  }
4431 
4432  /* This is the success path */
4434  }
4435  else
4436  {
4437  /* Failure path */
4439  }
4440  }
4441 
4442  /* Free any allocation we may have made, and return the status code */
4443  if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
4444  return Status;
4445 }
4446 
4447 /*
4448  * @implemented
4449  */
4450 VOID
4451 NTAPI
4453 {
4455  IO_STACK_LOCATION Stack;
4456  ULONG PnPFlags;
4457  NTSTATUS Status;
4459 
4460  RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
4461  Stack.MajorFunction = IRP_MJ_PNP;
4463 
4464  Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
4465  if (!NT_SUCCESS(Status))
4466  {
4468  {
4469  DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%lx\n", Status);
4470  }
4471  return;
4472  }
4473 
4474  if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
4475  DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
4476  else
4477  DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
4478 
4479  if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
4480  DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
4481  else
4482  DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
4483 
4484  if ((PnPFlags & PNP_DEVICE_REMOVED) ||
4485  ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
4486  {
4487  /* Flag it if it's failed */
4488  if (PnPFlags & PNP_DEVICE_FAILED) DeviceNode->Problem = CM_PROB_FAILED_POST_START;
4489 
4490  /* Send removal IRPs to all of its children */
4492 
4493  /* Send surprise removal */
4495 
4496  /* Tell the user-mode PnP manager that a device was removed */
4497  IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
4498  &DeviceNode->InstancePath);
4499 
4501  }
4502  else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
4503  {
4504  /* Stop for resource rebalance */
4506  if (!NT_SUCCESS(Status))
4507  {
4508  DPRINT1("Failed to stop device for rebalancing\n");
4509 
4510  /* Stop failed so don't rebalance */
4512  }
4513  }
4514 
4515  /* Resource rebalance */
4517  {
4518  DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4519 
4521  &IoStatusBlock,
4523  NULL);
4525  {
4526  DeviceNode->BootResources =
4529  }
4530  else
4531  {
4532  DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
4533  DeviceNode->BootResources = NULL;
4534  }
4535 
4536  DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4537 
4539  &IoStatusBlock,
4541  NULL);
4542  if (NT_SUCCESS(Status))
4543  {
4544  DeviceNode->ResourceRequirements =
4546  }
4547  else
4548  {
4549  DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
4550  DeviceNode->ResourceRequirements = NULL;
4551  }
4552 
4553  /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4555  {
4556  DPRINT1("Restart after resource rebalance failed\n");
4557 
4559  DeviceNode->Flags |= DNF_START_FAILED;
4560 
4562  }
4563  }
4564 }
4565 
4581 NTSTATUS
4582 NTAPI
4587 {
4588  static WCHAR RootKeyName[] =
4589  L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4590  static WCHAR ProfileKeyName[] =
4591  L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4592  static WCHAR ClassKeyName[] = L"Control\\Class\\";
4593  static WCHAR EnumKeyName[] = L"Enum\\";
4594  static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4596  PWSTR KeyNameBuffer;
4598  ULONG DriverKeyLength;
4601  NTSTATUS Status;
4602 
4603  DPRINT("IoOpenDeviceRegistryKey() called\n");
4604 
4606  {
4607  DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4608  return STATUS_INVALID_PARAMETER;
4609  }
4610 
4614 
4615  /*
4616  * Calculate the length of the base key name. This is the full
4617  * name for driver key or the name excluding "Device Parameters"
4618  * subkey for device key.
4619  */
4620 
4621  KeyNameLength = sizeof(RootKeyName);
4623  KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4625  {
4626  KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4628  0, NULL, &DriverKeyLength);
4630  return Status;
4631  KeyNameLength += DriverKeyLength;
4632  }
4633  else
4634  {
4635  KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4636  DeviceNode->InstancePath.Length;
4637  }
4638 
4639  /*
4640  * Now allocate the buffer for the key name...
4641  */
4642 
4643  KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4644  if (KeyNameBuffer == NULL)
4646 
4647  KeyName.Length = 0;
4648  KeyName.MaximumLength = (USHORT)KeyNameLength;
4649  KeyName.Buffer = KeyNameBuffer;
4650 
4651  /*
4652  * ...and build the key name.
4653  */
4654 
4655  KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4656  RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4657 
4659  RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4660 
4662  {
4663  RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4665  DriverKeyLength, KeyNameBuffer +
4666  (KeyName.Length / sizeof(WCHAR)),
4667  &DriverKeyLength);
4668  if (!NT_SUCCESS(Status))
4669  {
4670  DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4671  ExFreePool(KeyNameBuffer);
4672  return Status;
4673  }
4674  KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4675  }
4676  else
4677  {
4678  RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4680  if (DeviceNode->InstancePath.Length == 0)
4681  {
4682  ExFreePool(KeyNameBuffer);
4683  return Status;
4684  }
4685  }
4686 
4687  /*
4688  * Open the base key.
4689  */
4691  if (!NT_SUCCESS(Status))
4692  {
4693  DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4694  ExFreePool(KeyNameBuffer);
4695  return Status;
4696  }
4697  ExFreePool(KeyNameBuffer);
4698 
4699  /*
4700  * For driver key we're done now.
4701  */
4702 
4704  return Status;
4705 
4706  /*
4707  * Let's go further. For device key we must open "Device Parameters"
4708  * subkey and create it if it doesn't exist yet.
4709  */
4710 
4711  RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4713  &KeyName,
4715  *DevInstRegKey,
4716  NULL);
4717  Status = ZwCreateKey(DevInstRegKey,
4718  DesiredAccess,
4720  0,
4721  NULL,
4723  NULL);
4724  ZwClose(ObjectAttributes.RootDirectory);
4725 
4726  return Status;
4727 }
4728 
4729 static
4730 NTSTATUS
4732 {
4733  PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
4734  NTSTATUS Status;
4735  KIRQL OldIrql;
4736 
4738  ChildDeviceNode = ParentDeviceNode->Child;
4739  while (ChildDeviceNode != NULL)
4740  {
4741  NextDeviceNode = ChildDeviceNode->Sibling;
4743 
4745  if (!NT_SUCCESS(Status))
4746  {
4747  FailedRemoveDevice = ChildDeviceNode;
4748  goto cleanup;
4749  }
4750 
4752  ChildDeviceNode = NextDeviceNode;
4753  }