ReactOS  0.4.15-dev-5097-g328cc41
devaction.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE: PnP manager device manipulation functions
5  * COPYRIGHT: Casper S. Hornstrup (chorns@users.sourceforge.net)
6  * 2007 HervĂ© Poussineau (hpoussin@reactos.org)
7  * 2014-2017 Thomas Faber (thomas.faber@reactos.org)
8  * 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
9  */
10 
11 /* Device tree is a resource shared among all system services: hal, kernel, drivers etc.
12  * Thus all code which interacts with the tree needs to be synchronized.
13  * Here it's done via a list of DEVICE_ACTION_REQUEST structures, which represents
14  * the device action queue. It is being processed exclusively by the PipDeviceActionWorker.
15  *
16  * Operation queuing can be done with the PiQueueDeviceAction function or with
17  * the PiPerfomSyncDeviceAction for synchronous operations.
18  * All device manipulation like starting, removing, enumeration (see DEVICE_ACTION enum)
19  * have to be done with the PiQueueDeviceAction in order to avoid race conditions.
20  *
21  * Note: there is one special operation here - PiActionEnumRootDevices. It is meant to be done
22  * during initialization process (and be the first device tree operation executed) and
23  * is always executed synchronously.
24  */
25 
26 /* INCLUDES ******************************************************************/
27 
28 #include <ntoskrnl.h>
29 #define NDEBUG
30 #include <debug.h>
31 
32 /* GLOBALS *******************************************************************/
33 
35 extern BOOLEAN PnpSystemInit;
39 
40 #define MAX_DEVICE_ID_LEN 200
41 #define MAX_SEPARATORS_INSTANCEID 0
42 #define MAX_SEPARATORS_DEVICEID 1
43 
44 /* DATA **********************************************************************/
45 
51 static const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
52 
53 /* TYPES *********************************************************************/
54 
55 typedef struct _DEVICE_ACTION_REQUEST
56 {
63 
65 {
72 
73 typedef struct _ADD_DEV_DRIVERS_LIST
74 {
79 
81 {
86 
87 /* FUNCTIONS *****************************************************************/
88 
91 
94 
95 USHORT
96 NTAPI
97 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid);
98 
101 
102 VOID
103 NTAPI
105 
106 static
107 VOID
109 
110 static
111 NTSTATUS
113 
114 static
115 NTSTATUS
118  _In_ HANDLE InstanceHandle);
119 
120 static
121 BOOLEAN
123  _In_ PWCHAR Id,
125 {
126  PWCHAR PtrChar;
127  PWCHAR StringEnd;
128  WCHAR Char;
129  ULONG SeparatorsCount = 0;
130  PWCHAR PtrPrevChar = NULL;
131  ULONG MaxSeparators;
132  BOOLEAN IsMultiSz;
133 
134  PAGED_CODE();
135 
136  switch (QueryType)
137  {
138  case BusQueryDeviceID:
139  MaxSeparators = MAX_SEPARATORS_DEVICEID;
140  IsMultiSz = FALSE;
141  break;
142  case BusQueryInstanceID:
143  MaxSeparators = MAX_SEPARATORS_INSTANCEID;
144  IsMultiSz = FALSE;
145  break;
146 
147  case BusQueryHardwareIDs:
149  MaxSeparators = MAX_SEPARATORS_DEVICEID;
150  IsMultiSz = TRUE;
151  break;
152 
153  default:
154  DPRINT1("IopValidateID: Not handled QueryType - %x\n", QueryType);
155  return FALSE;
156  }
157 
158  StringEnd = Id + MAX_DEVICE_ID_LEN;
159 
160  for (PtrChar = Id; PtrChar < StringEnd; PtrChar++)
161  {
162  Char = *PtrChar;
163 
164  if (Char == UNICODE_NULL)
165  {
166  if (!IsMultiSz || (PtrPrevChar && PtrChar == PtrPrevChar + 1))
167  {
168  if (MaxSeparators == SeparatorsCount || IsMultiSz)
169  {
170  return TRUE;
171  }
172 
173  DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
174  SeparatorsCount, MaxSeparators);
175  goto ErrorExit;
176  }
177 
178  StringEnd = PtrChar + MAX_DEVICE_ID_LEN + 1;
179  PtrPrevChar = PtrChar;
180  SeparatorsCount = 0;
181  }
182  else if (Char < ' ' || Char > 0x7F || Char == ',')
183  {
184  DPRINT1("IopValidateID: Invalid character - %04X\n", Char);
185  goto ErrorExit;
186  }
187  else if (Char == ' ')
188  {
189  *PtrChar = '_';
190  }
191  else if (Char == '\\')
192  {
193  SeparatorsCount++;
194 
195  if (SeparatorsCount > MaxSeparators)
196  {
197  DPRINT1("IopValidateID: SeparatorsCount - %lu, MaxSeparators - %lu\n",
198  SeparatorsCount, MaxSeparators);
199  goto ErrorExit;
200  }
201  }
202  }
203 
204  DPRINT1("IopValidateID: Not terminated ID\n");
205 
206 ErrorExit:
207  // FIXME logging
208  return FALSE;
209 }
210 
211 static
212 NTSTATUS
215  _Out_ PUNICODE_STRING InstancePath)
216 {
218  UNICODE_STRING DeviceId;
222  UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
224  BOOLEAN IsValidID;
225 
226  DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
227 
228  Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
229  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
230  &IoStatusBlock,
232  &Stack);
233  if (!NT_SUCCESS(Status))
234  {
235  DPRINT1("IopInitiatePnpIrp(BusQueryDeviceID) failed (Status %x)\n", Status);
236  return Status;
237  }
238 
240 
241  if (!IsValidID)
242  {
243  DPRINT1("Invalid DeviceID. DeviceNode - %p\n", DeviceNode);
244  }
245 
246  /* Save the device id string */
248 
249  DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
250 
252  if (!NT_SUCCESS(Status))
253  {
255  {
256  DPRINT1("IopQueryDeviceCapabilities() failed (Status 0x%08lx)\n", Status);
257  }
258  RtlFreeUnicodeString(&DeviceId);
259  return Status;
260  }
261 
262  /* This bit is only check after enumeration */
263  if (DeviceCapabilities.HardwareDisabled)
264  {
265  /* FIXME: Cleanup device */
266  RtlFreeUnicodeString(&DeviceId);
268  }
269 
270  if (!DeviceCapabilities.UniqueID)
271  {
272  /* Device has not a unique ID. We need to prepend parent bus unique identifier */
273  DPRINT("Instance ID is not unique\n");
274  Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
275  if (!NT_SUCCESS(Status))
276  {
277  DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
278  RtlFreeUnicodeString(&DeviceId);
279  return Status;
280  }
281  }
282 
283  DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
284 
285  Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
286  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
287  &IoStatusBlock,
289  &Stack);
290  if (!NT_SUCCESS(Status))
291  {
292  DPRINT("IopInitiatePnpIrp(BusQueryInstanceID) failed (Status %lx)\n", Status);
294  }
295 
297  {
299 
300  if (!IsValidID)
301  {
302  DPRINT1("Invalid InstanceID. DeviceNode - %p\n", DeviceNode);
303  }
304  }
305 
308 
309  InstancePath->Length = 0;
310  InstancePath->MaximumLength = DeviceId.Length + sizeof(WCHAR) +
311  ParentIdPrefix.Length +
312  InstanceId.Length +
313  sizeof(UNICODE_NULL);
314  if (ParentIdPrefix.Length && InstanceId.Length)
315  {
316  InstancePath->MaximumLength += sizeof(WCHAR);
317  }
318 
319  InstancePath->Buffer = ExAllocatePoolWithTag(PagedPool,
320  InstancePath->MaximumLength,
321  TAG_IO);
322  if (!InstancePath->Buffer)
323  {
325  RtlFreeUnicodeString(&ParentIdPrefix);
326  RtlFreeUnicodeString(&DeviceId);
328  }
329 
330  /* Start with the device id */
331  RtlCopyUnicodeString(InstancePath, &DeviceId);
332  RtlAppendUnicodeToString(InstancePath, L"\\");
333 
334  /* Add information from parent bus device to InstancePath */
335  RtlAppendUnicodeStringToString(InstancePath, &ParentIdPrefix);
336  if (ParentIdPrefix.Length && InstanceId.Length)
337  {
338  RtlAppendUnicodeToString(InstancePath, L"&");
339  }
340 
341  /* Finally, add the id returned by the driver stack */
343 
344  /*
345  * FIXME: Check for valid characters, if there is invalid characters
346  * then bugcheck
347  */
348 
350  RtlFreeUnicodeString(&DeviceId);
351  RtlFreeUnicodeString(&ParentIdPrefix);
352 
353  return STATUS_SUCCESS;
354 }
355 
360 static
361 NTSTATUS
362 NTAPI
368  PVOID Ctx,
370 {
374  BOOLEAN loadDrivers = (BOOLEAN)(ULONG_PTR)EntryContext;
375 
376  PAGED_CODE();
377 
378  // No filter value present
379  if (ValueType != REG_SZ)
380  return STATUS_SUCCESS;
381 
382  if (ValueLength <= sizeof(WCHAR))
384 
385  // open the service registry key
386  UNICODE_STRING serviceName = { .Length = 0 }, servicesKeyName;
388  RtlInitUnicodeString(&servicesKeyName, ServicesKeyName);
389 
390  HANDLE ccsServicesHandle, serviceHandle = NULL;
391 
392  Status = IopOpenRegistryKeyEx(&ccsServicesHandle, NULL, &servicesKeyName, KEY_READ);
393  if (!NT_SUCCESS(Status))
394  {
395  DPRINT1("Failed to open a registry key for \"%wZ\" (status %x)\n", &serviceName, Status);
396  return Status;
397  }
398 
399  Status = IopOpenRegistryKeyEx(&serviceHandle, ccsServicesHandle, &serviceName, KEY_READ);
400  ZwClose(ccsServicesHandle);
401  if (!NT_SUCCESS(Status))
402  {
403  DPRINT1("Failed to open a registry key for \"%wZ\" (status %x)\n", &serviceName, Status);
404  return Status;
405  }
406 
408  sizeof(*driverEntry),
410 
411  if (!driverEntry)
412  {
413  DPRINT1("Failed to allocate driverEntry for \"%wZ\"\n", &serviceName);
414  ZwClose(serviceHandle);
416  }
417 
418  // check if the driver is disabled
420  SERVICE_LOAD_TYPE startType = DisableLoad;
421 
422  Status = IopGetRegistryValue(serviceHandle, L"Start", &kvInfo);
423  if (NT_SUCCESS(Status))
424  {
425  if (kvInfo->Type == REG_DWORD)
426  {
427  RtlMoveMemory(&startType,
428  (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset),
429  sizeof(startType));
430  }
431 
432  ExFreePool(kvInfo);
433  }
434 
435  // TODO: take into account other start types (like SERVICE_DEMAND_START)
436  if (startType >= DisableLoad)
437  {
438  if (!(context->DeviceNode->Flags & DNF_HAS_PROBLEM))
439  {
441  }
442 
443  DPRINT("Service \"%wZ\" is disabled (start type %u)\n", &serviceName, startType);
445  goto Cleanup;
446  }
447 
448  // check if the driver is already loaded
449  UNICODE_STRING driverName;
450  Status = IopGetDriverNames(serviceHandle, &driverName, NULL);
451  if (!NT_SUCCESS(Status))
452  {
453  DPRINT1("Unable to obtain the driver name for \"%wZ\"\n", &serviceName);
454  goto Cleanup;
455  }
456 
457  // try to open it
458  Status = ObReferenceObjectByName(&driverName,
460  NULL, /* PassedAccessState */
461  0, /* DesiredAccess */
463  KernelMode,
464  NULL, /* ParseContext */
465  (PVOID*)&DriverObject);
466  RtlFreeUnicodeString(&driverName);
467 
468  // the driver was not probably loaded, try to load
469  if (!NT_SUCCESS(Status))
470  {
471  if (loadDrivers)
472  {
473  Status = IopLoadDriver(serviceHandle, &DriverObject);
474  }
475  else
476  {
477  DPRINT("Service \"%wZ\" will not be loaded now\n", &serviceName);
478  // return failure, the driver will be loaded later (in a subsequent call)
480  goto Cleanup;
481  }
482  }
483 
484  if (NT_SUCCESS(Status))
485  {
486  driverEntry->DriverObject = DriverObject;
487  driverEntry->DriverType = context->DriverType;
488  InsertTailList(context->DriversListHead, &driverEntry->ListEntry);
489  ZwClose(serviceHandle);
490  return STATUS_SUCCESS;
491  }
492  else
493  {
494  if (!(context->DeviceNode->Flags & DNF_HAS_PROBLEM))
495  {
496  switch (Status)
497  {
500  break;
503  break;
506  break;
507  default:
509  break;
510  }
511  }
512 
513  DPRINT1("Failed to load driver \"%wZ\" for %wZ (status %x)\n",
514  &serviceName, &context->DeviceNode->InstancePath, Status);
515  }
516 
517 Cleanup:
518  ExFreePoolWithTag(driverEntry, TAG_PNP_DEVACTION);
519  if (serviceHandle)
520  {
521  ZwClose(serviceHandle);
522  }
523  return Status;
524 }
525 
526 
530 static
531 NTSTATUS
533  PLIST_ENTRY DriversListHead,
535  HANDLE EnumSubKey,
536  HANDLE ClassKey,
537  BOOLEAN Lower,
538  BOOLEAN LoadDrivers)
539 {
540  RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
541  ATTACH_FILTER_DRIVERS_CONTEXT routineContext;
543 
544  PAGED_CODE();
545 
546  routineContext.DriversListHead = DriversListHead;
547  routineContext.DeviceNode = DeviceNode;
548 
549  // First add device filters
550  routineContext.DriverType = Lower ? LowerFilter : UpperFilter;
553  .Name = Lower ? L"LowerFilters" : L"UpperFilters",
554  .DefaultType = REG_NONE,
555  .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
556  };
557 
559  (PWSTR)EnumSubKey,
560  QueryTable,
561  &routineContext,
562  NULL);
563  if (ClassKey == NULL)
564  {
565  return Status;
566  }
567 
568  // Then add device class filters
569  routineContext.DriverType = Lower ? LowerClassFilter : UpperClassFilter;
572  .Name = Lower ? L"LowerFilters" : L"UpperFilters",
573  .DefaultType = REG_NONE,
574  .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
575  };
576 
578  (PWSTR)ClassKey,
579  QueryTable,
580  &routineContext,
581  NULL);
582  return Status;
583 }
584 
593 static
594 NTSTATUS
597  _In_ BOOLEAN LoadDrivers)
598 {
600  HANDLE EnumRootKey, SubKey;
601  HANDLE ClassKey = NULL;
603  static UNICODE_STRING ccsControlClass =
604  RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
606 
607  PAGED_CODE();
608 
609  // open the enumeration root key
610  Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL, &EnumRoot, KEY_READ);
611  if (!NT_SUCCESS(Status))
612  {
613  DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &EnumRoot, Status);
614  return Status;
615  }
616 
617  // open an instance subkey
618  Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey, &DeviceNode->InstancePath, KEY_READ);
619  ZwClose(EnumRootKey);
620  if (!NT_SUCCESS(Status))
621  {
622  DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n",
623  &DeviceNode->InstancePath, Status);
624  return Status;
625  }
626 
627  // try to get the class GUID of an instance and its registry key
628  Status = IopGetRegistryValue(SubKey, REGSTR_VAL_CLASSGUID, &kvInfo);
629  if (NT_SUCCESS(Status))
630  {
631  if (kvInfo->Type == REG_SZ && kvInfo->DataLength > sizeof(WCHAR))
632  {
633  UNICODE_STRING classGUID = {
634  .MaximumLength = kvInfo->DataLength,
635  .Length = kvInfo->DataLength - sizeof(UNICODE_NULL),
636  .Buffer = (PVOID)((ULONG_PTR)kvInfo + kvInfo->DataOffset)
637  };
638  HANDLE ccsControlHandle;
639 
640  Status = IopOpenRegistryKeyEx(&ccsControlHandle, NULL, &ccsControlClass, KEY_READ);
641  if (!NT_SUCCESS(Status))
642  {
643  DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n",
644  &ccsControlClass, Status);
645  }
646  else
647  {
648  // open the CCS\Control\Class<ClassGUID> key
649  Status = IopOpenRegistryKeyEx(&ClassKey, ccsControlHandle, &classGUID, KEY_READ);
650  ZwClose(ccsControlHandle);
651  if (!NT_SUCCESS(Status))
652  {
653  DPRINT1("Failed to open class key \"%wZ\" (status %x)\n", &classGUID, Status);
654  }
655  }
656 
657  if (ClassKey)
658  {
659  // Check the Properties key of a class too
660  // Windows fills some device properties from this key (which is protected)
661  // TODO: add the device properties from this key
662 
664  HANDLE propertiesHandle;
665 
666  Status = IopOpenRegistryKeyEx(&propertiesHandle, ClassKey, &properties, KEY_READ);
667  if (!NT_SUCCESS(Status))
668  {
669  DPRINT("Properties key failed to open for \"%wZ\" (status %x)\n",
670  &classGUID, Status);
671  }
672  else
673  {
674  ZwClose(propertiesHandle);
675  }
676  }
677  }
678 
679  ExFreePool(kvInfo);
680  }
681 
682  // the driver loading order:
683  // 1. LowerFilters
684  // 2. LowerClassFilters
685  // 3. Device driver (only one service!)
686  // 4. UpperFilters
687  // 5. UpperClassFilters
688 
689  LIST_ENTRY drvListHead;
690  InitializeListHead(&drvListHead);
691 
692  // lower (class) filters
693  Status = PiAttachFilterDrivers(&drvListHead, DeviceNode, SubKey, ClassKey, TRUE, LoadDrivers);
694  if (!NT_SUCCESS(Status))
695  {
696  goto Cleanup;
697  }
698 
699  ATTACH_FILTER_DRIVERS_CONTEXT routineContext = {
700  .DriversListHead = &drvListHead,
701  .DriverType = DeviceDriver,
702  .DeviceNode = DeviceNode
703  };
704 
705  RTL_QUERY_REGISTRY_TABLE queryTable[2] = {{
707  .Name = L"Service",
709  .DefaultType = REG_SZ, // REG_MULTI_SZ is not allowed here
710  .DefaultData = L"",
711  .EntryContext = (PVOID)(ULONG_PTR)LoadDrivers
712  },};
713 
714  // device driver
716  (PWSTR)SubKey,
717  queryTable,
718  &routineContext,
719  NULL);
720  if (NT_SUCCESS(Status))
721  {
722  // do nothing
723  }
724  // if a driver is not found, but a device allows raw access -> proceed
725  else if (Status == STATUS_OBJECT_NAME_NOT_FOUND &&
726  (DeviceNode->CapabilityFlags & 0x00000040)) // CM_DEVCAP_RAWDEVICEOK
727  {
728  // add a dummy entry to the drivers list (need for later processing)
729  PADD_DEV_DRIVERS_LIST driverEntry = ExAllocatePoolZero(PagedPool,
730  sizeof(*driverEntry),
732  driverEntry->DriverType = DeviceDriver;
733  InsertTailList(&drvListHead, &driverEntry->ListEntry);
734  DPRINT("No service for \"%wZ\" (RawDeviceOK)\n", &DeviceNode->InstancePath);
735  }
736  else
737  {
739  {
741  }
742  DPRINT("No service for \"%wZ\" (loadDrv: %u)\n", &DeviceNode->InstancePath, LoadDrivers);
743  goto Cleanup;
744  }
745 
746  // upper (class) filters
747  Status = PiAttachFilterDrivers(&drvListHead, DeviceNode, SubKey, ClassKey, FALSE, LoadDrivers);
748  if (!NT_SUCCESS(Status))
749  {
750  goto Cleanup;
751  }
752 
753  // finally loop through the stack and call AddDevice for every driver
754  for (PLIST_ENTRY listEntry = drvListHead.Flink;
755  listEntry != &drvListHead;
756  listEntry = listEntry->Flink)
757  {
758  PADD_DEV_DRIVERS_LIST driverEntry;
759  driverEntry = CONTAINING_RECORD(listEntry, ADD_DEV_DRIVERS_LIST, ListEntry);
760  PDRIVER_OBJECT driverObject = driverEntry->DriverObject;
761 
762  // FIXME: ReactOS is not quite ready for this assert
763  // (legacy drivers should not have AddDevice routine)
764  // ASSERT(!(DriverObject->Flags & DRVO_LEGACY_DRIVER));
765 
766  if (driverObject && driverObject->DriverExtension->AddDevice)
767  {
768  Status = driverObject->DriverExtension->AddDevice(driverEntry->DriverObject,
769  DeviceNode->PhysicalDeviceObject);
770  }
771  else if (driverObject == NULL)
772  {
773  // valid only for DeviceDriver
774  ASSERT(driverEntry->DriverType == DeviceDriver);
775  ASSERT(DeviceNode->CapabilityFlags & 0x00000040); // CM_DEVCAP_RAWDEVICEOK
777  }
778  else
779  {
780  // HACK: the driver doesn't have a AddDevice routine. We shouldn't be here,
781  // but ReactOS' PnP stack is not that correct yet
782  DeviceNode->Flags |= DNF_LEGACY_DRIVER;
784  }
785 
786  // for filter drivers we don't care about the AddDevice result
787  if (driverEntry->DriverType == DeviceDriver)
788  {
789  if (NT_SUCCESS(Status))
790  {
791  PDEVICE_OBJECT fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
792 
793  // HACK: Check if we have a ACPI device (needed for power management)
794  if (fdo->DeviceType == FILE_DEVICE_ACPI)
795  {
796  static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
797 
798  // There can be only one system power device
799  if (!SystemPowerDeviceNodeCreated)
800  {
803  SystemPowerDeviceNodeCreated = TRUE;
804  }
805  }
806 
807  ObDereferenceObject(fdo);
809  }
810  else
811  {
812  // lower filters (if already started) will be removed upon this request
815  break;
816  }
817  }
818 
819 #if DBG
820  PDEVICE_OBJECT attachedDO = IoGetAttachedDevice(DeviceNode->PhysicalDeviceObject);
821  if (attachedDO->Flags & DO_DEVICE_INITIALIZING)
822  {
823  DPRINT1("DO_DEVICE_INITIALIZING is not cleared on a device 0x%p!\n", attachedDO);
824  }
825 #endif
826  }
827 
828 Cleanup:
829  while (!IsListEmpty(&drvListHead))
830  {
831  PLIST_ENTRY listEntry = RemoveHeadList(&drvListHead);
832  PADD_DEV_DRIVERS_LIST driverEntry;
833  driverEntry = CONTAINING_RECORD(listEntry, ADD_DEV_DRIVERS_LIST, ListEntry);
834 
835  // drivers which don't have any devices (in case of failure) will be cleaned up
836  if (driverEntry->DriverObject)
837  {
838  ObDereferenceObject(driverEntry->DriverObject);
839  }
840  ExFreePoolWithTag(driverEntry, TAG_PNP_DEVACTION);
841  }
842 
843  ZwClose(SubKey);
844  if (ClassKey != NULL)
845  {
846  ZwClose(ClassKey);
847  }
848 
849  return Status;
850 }
851 
852 NTSTATUS
853 NTAPI
855  PDEVICE_CAPABILITIES DeviceCaps)
856 {
857  IO_STATUS_BLOCK StatusBlock;
860  HANDLE InstanceKey;
862 
863  /* Set up the Header */
864  RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
865  DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
866  DeviceCaps->Version = 1;
867  DeviceCaps->Address = -1;
868  DeviceCaps->UINumber = -1;
869 
870  /* Set up the Stack */
872  Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
873 
874  /* Send the IRP */
875  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
876  &StatusBlock,
878  &Stack);
879  if (!NT_SUCCESS(Status))
880  {
882  {
883  DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%lx\n", Status);
884  }
885  return Status;
886  }
887 
888  /* Map device capabilities to capability flags */
889  DeviceNode->CapabilityFlags = 0;
890  if (DeviceCaps->LockSupported)
891  DeviceNode->CapabilityFlags |= 0x00000001; // CM_DEVCAP_LOCKSUPPORTED
892 
893  if (DeviceCaps->EjectSupported)
894  DeviceNode->CapabilityFlags |= 0x00000002; // CM_DEVCAP_EJECTSUPPORTED
895 
896  if (DeviceCaps->Removable)
897  DeviceNode->CapabilityFlags |= 0x00000004; // CM_DEVCAP_REMOVABLE
898 
899  if (DeviceCaps->DockDevice)
900  DeviceNode->CapabilityFlags |= 0x00000008; // CM_DEVCAP_DOCKDEVICE
901 
902  if (DeviceCaps->UniqueID)
903  DeviceNode->CapabilityFlags |= 0x00000010; // CM_DEVCAP_UNIQUEID
904 
905  if (DeviceCaps->SilentInstall)
906  DeviceNode->CapabilityFlags |= 0x00000020; // CM_DEVCAP_SILENTINSTALL
907 
908  if (DeviceCaps->RawDeviceOK)
909  DeviceNode->CapabilityFlags |= 0x00000040; // CM_DEVCAP_RAWDEVICEOK
910 
911  if (DeviceCaps->SurpriseRemovalOK)
912  DeviceNode->CapabilityFlags |= 0x00000080; // CM_DEVCAP_SURPRISEREMOVALOK
913 
914  if (DeviceCaps->HardwareDisabled)
915  DeviceNode->CapabilityFlags |= 0x00000100; // CM_DEVCAP_HARDWAREDISABLED
916 
917  if (DeviceCaps->NonDynamic)
918  DeviceNode->CapabilityFlags |= 0x00000200; // CM_DEVCAP_NONDYNAMIC
919 
920  if (DeviceCaps->NoDisplayInUI)
921  DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
922  else
923  DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
924 
925  Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
926  if (NT_SUCCESS(Status))
927  {
928  /* Set 'Capabilities' value */
929  RtlInitUnicodeString(&ValueName, L"Capabilities");
930  Status = ZwSetValueKey(InstanceKey,
931  &ValueName,
932  0,
933  REG_DWORD,
934  &DeviceNode->CapabilityFlags,
935  sizeof(ULONG));
936 
937  /* Set 'UINumber' value */
938  if (DeviceCaps->UINumber != MAXULONG)
939  {
940  RtlInitUnicodeString(&ValueName, L"UINumber");
941  Status = ZwSetValueKey(InstanceKey,
942  &ValueName,
943  0,
944  REG_DWORD,
945  &DeviceCaps->UINumber,
946  sizeof(ULONG));
947  }
948 
949  ZwClose(InstanceKey);
950  }
951 
952  return Status;
953 }
954 
955 static
956 NTSTATUS
958  HANDLE InstanceKey)
959 {
962  PWSTR Ptr;
966  BOOLEAN IsValidID;
967 
968  DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
969 
970  RtlZeroMemory(&Stack, sizeof(Stack));
971  Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
972  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
973  &IoStatusBlock,
975  &Stack);
976  if (NT_SUCCESS(Status))
977  {
979 
980  if (!IsValidID)
981  {
982  DPRINT1("Invalid HardwareIDs. DeviceNode - %p\n", DeviceNode);
983  }
984 
985  TotalLength = 0;
986 
988  DPRINT("Hardware IDs:\n");
989  while (*Ptr)
990  {
991  DPRINT(" %S\n", Ptr);
992  Length = (ULONG)wcslen(Ptr) + 1;
993 
994  Ptr += Length;
995  TotalLength += Length;
996  }
997  DPRINT("TotalLength: %hu\n", TotalLength);
998  DPRINT("\n");
999 
1000  RtlInitUnicodeString(&ValueName, L"HardwareID");
1001  Status = ZwSetValueKey(InstanceKey,
1002  &ValueName,
1003  0,
1004  REG_MULTI_SZ,
1006  (TotalLength + 1) * sizeof(WCHAR));
1007  if (!NT_SUCCESS(Status))
1008  {
1009  DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1010  }
1011  }
1012  else
1013  {
1014  DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1015  }
1016 
1017  return Status;
1018 }
1019 
1020 static
1021 NTSTATUS
1023  HANDLE InstanceKey)
1024 {
1027  PWSTR Ptr;
1029  NTSTATUS Status;
1031  BOOLEAN IsValidID;
1032 
1033  DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1034 
1035  RtlZeroMemory(&Stack, sizeof(Stack));
1036  Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1037  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1038  &IoStatusBlock,
1040  &Stack);
1042  {
1044 
1045  if (!IsValidID)
1046  {
1047  DPRINT1("Invalid CompatibleIDs. DeviceNode - %p\n", DeviceNode);
1048  }
1049 
1050  TotalLength = 0;
1051 
1053  DPRINT("Compatible IDs:\n");
1054  while (*Ptr)
1055  {
1056  DPRINT(" %S\n", Ptr);
1057  Length = (ULONG)wcslen(Ptr) + 1;
1058 
1059  Ptr += Length;
1060  TotalLength += Length;
1061  }
1062  DPRINT("TotalLength: %hu\n", TotalLength);
1063  DPRINT("\n");
1064 
1065  RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1066  Status = ZwSetValueKey(InstanceKey,
1067  &ValueName,
1068  0,
1069  REG_MULTI_SZ,
1071  (TotalLength + 1) * sizeof(WCHAR));
1072  if (!NT_SUCCESS(Status))
1073  {
1074  DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1075  }
1076  }
1077  else
1078  {
1079  DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1080  }
1081 
1082  return Status;
1083 }
1084 
1088 VOID
1091  _In_ HANDLE InstanceKey)
1092 {
1093  PAGED_CODE();
1094 
1095  LCID localeId;
1096 
1097  // Get the Locale ID
1098  NTSTATUS status = ZwQueryDefaultLocale(FALSE, &localeId);
1099  if (!NT_SUCCESS(status))
1100  {
1101  DPRINT1("ZwQueryDefaultLocale() failed with status %x\n", status);
1102  return;
1103  }
1104 
1105  // Step 1: Write the DeviceDesc value if does not exist
1106 
1107  UNICODE_STRING valDeviceDesc = RTL_CONSTANT_STRING(L"DeviceDesc");
1108  ULONG len;
1109 
1110  status = ZwQueryValueKey(InstanceKey, &valDeviceDesc, KeyValueBasicInformation, NULL, 0, &len);
1112  {
1113  PWSTR deviceDesc = NULL;
1114  status = PiIrpQueryDeviceText(DeviceNode, localeId, DeviceTextDescription, &deviceDesc);
1115 
1116  if (deviceDesc && deviceDesc[0] != UNICODE_NULL)
1117  {
1118  status = ZwSetValueKey(InstanceKey,
1119  &valDeviceDesc,
1120  0,
1121  REG_SZ,
1122  deviceDesc,
1123  ((ULONG)wcslen(deviceDesc) + 1) * sizeof(WCHAR));
1124 
1125  if (!NT_SUCCESS(status))
1126  {
1127  DPRINT1("ZwSetValueKey() failed (Status %x)\n", status);
1128  }
1129  }
1130  else
1131  {
1132  // This key is mandatory, so even if the Irp fails, we still write it
1133  UNICODE_STRING unknownDeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
1134  DPRINT("Driver didn't return DeviceDesc (status %x)\n", status);
1135 
1136  status = ZwSetValueKey(InstanceKey,
1137  &valDeviceDesc,
1138  0,
1139  REG_SZ,
1140  unknownDeviceDesc.Buffer,
1141  unknownDeviceDesc.MaximumLength);
1142  if (!NT_SUCCESS(status))
1143  {
1144  DPRINT1("ZwSetValueKey() failed (Status %x)\n", status);
1145  }
1146  }
1147 
1148  if (deviceDesc)
1149  {
1150  ExFreePoolWithTag(deviceDesc, 0);
1151  }
1152  }
1153 
1154  // Step 2: LocaltionInformation is overwritten unconditionally
1155 
1156  PWSTR deviceLocationInfo = NULL;
1158  localeId,
1160  &deviceLocationInfo);
1161 
1162  if (deviceLocationInfo && deviceLocationInfo[0] != UNICODE_NULL)
1163  {
1164  UNICODE_STRING valLocationInfo = RTL_CONSTANT_STRING(L"LocationInformation");
1165 
1166  status = ZwSetValueKey(InstanceKey,
1167  &valLocationInfo,
1168  0,
1169  REG_SZ,
1170  deviceLocationInfo,
1171  ((ULONG)wcslen(deviceLocationInfo) + 1) * sizeof(WCHAR));
1172  if (!NT_SUCCESS(status))
1173  {
1174  DPRINT1("ZwSetValueKey() failed (Status %x)\n", status);
1175  }
1176  }
1177 
1178  if (deviceLocationInfo)
1179  {
1180  ExFreePoolWithTag(deviceLocationInfo, 0);
1181  }
1182  else
1183  {
1184  DPRINT("Driver didn't return LocationInformation (status %x)\n", status);
1185  }
1186 }
1187 
1188 static
1189 NTSTATUS
1192 {
1194  NTSTATUS Status;
1195  HANDLE InstanceKey = NULL;
1196  UNICODE_STRING InstancePathU;
1197  PDEVICE_OBJECT OldDeviceObject;
1198 
1199  DPRINT("PiProcessNewDevNode(%p)\n", DeviceNode);
1200  DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1201 
1202  /*
1203  * FIXME: For critical errors, cleanup and disable device, but always
1204  * return STATUS_SUCCESS.
1205  */
1206 
1207  Status = IopCreateDeviceInstancePath(DeviceNode, &InstancePathU);
1208  if (!NT_SUCCESS(Status))
1209  {
1211  {
1212  DPRINT1("IopCreateDeviceInstancePath() failed with status 0x%lx\n", Status);
1213  }
1214  return Status;
1215  }
1216 
1217  /* Verify that this is not a duplicate */
1218  OldDeviceObject = IopGetDeviceObjectFromDeviceInstance(&InstancePathU);
1219  if (OldDeviceObject != NULL)
1220  {
1221  PDEVICE_NODE OldDeviceNode = IopGetDeviceNode(OldDeviceObject);
1222 
1223  DPRINT1("Duplicate device instance '%wZ'\n", &InstancePathU);
1224  DPRINT1("Current instance parent: '%wZ'\n", &DeviceNode->Parent->InstancePath);
1225  DPRINT1("Old instance parent: '%wZ'\n", &OldDeviceNode->Parent->InstancePath);
1226 
1227  KeBugCheckEx(PNP_DETECTED_FATAL_ERROR,
1228  0x01,
1229  (ULONG_PTR)DeviceNode->PhysicalDeviceObject,
1230  (ULONG_PTR)OldDeviceObject,
1231  0);
1232  }
1233 
1234  DeviceNode->InstancePath = InstancePathU;
1235 
1236  DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1237 
1238  /*
1239  * Create registry key for the instance id, if it doesn't exist yet
1240  */
1241  Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_NON_VOLATILE, &InstanceKey);
1242  if (!NT_SUCCESS(Status))
1243  {
1244  DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1245 
1246  /* We have to return success otherwise we abort the traverse operation */
1247  return STATUS_SUCCESS;
1248  }
1249 
1250  IopQueryHardwareIds(DeviceNode, InstanceKey);
1251 
1252  IopQueryCompatibleIds(DeviceNode, InstanceKey);
1253 
1254  DeviceNode->Flags |= DNF_IDS_QUERIED;
1255 
1256  // Set the device's DeviceDesc and LocationInformation fields
1257  PiSetDevNodeText(DeviceNode, InstanceKey);
1258 
1259  DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1260 
1261  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1262  &IoStatusBlock,
1264  NULL);
1266  {
1268 
1269  DeviceNode->ChildBusNumber = BusInformation->BusNumber;
1270  DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
1271  DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
1273  }
1274  else
1275  {
1276  DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1277 
1278  DeviceNode->ChildBusNumber = 0xFFFFFFF0;
1279  DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
1280  DeviceNode->ChildBusTypeIndex = -1;
1281  }
1282 
1283  DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1284 
1285  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1286  &IoStatusBlock,
1288  NULL);
1290  {
1293  }
1294  else
1295  {
1296  DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
1297  DeviceNode->BootResources = NULL;
1298  }
1299 
1300  DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1301 
1302  Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1303  &IoStatusBlock,
1305  NULL);
1306  if (NT_SUCCESS(Status))
1307  {
1309  }
1310  else
1311  {
1312  DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
1313  DeviceNode->ResourceRequirements = NULL;
1314  }
1315 
1316  if (InstanceKey != NULL)
1317  {
1318  IopSetDeviceInstanceData(InstanceKey, DeviceNode);
1319  }
1320 
1321  // Try installing a critical device, so its Service key is populated
1322  // then call IopSetServiceEnumData to populate service's Enum key.
1323  // That allows us to start devices during an early boot
1325  IopSetServiceEnumData(DeviceNode, InstanceKey);
1326 
1327  ZwClose(InstanceKey);
1328 
1330 
1332  {
1333  /* Report the device to the user-mode pnp manager */
1334  IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
1335  &DeviceNode->InstancePath);
1336  }
1337 
1338  return STATUS_SUCCESS;
1339 }
1340 
1341 static
1342 NTSTATUS
1345  _In_ HANDLE InstanceHandle)
1346 {
1347  UNICODE_STRING ServicesKeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1348  UNICODE_STRING ServiceKeyName;
1349  UNICODE_STRING EnumKeyName;
1352  PKEY_VALUE_FULL_INFORMATION KeyValueInformation, kvInfo2;
1353  HANDLE ServiceKey = NULL, ServiceEnumKey = NULL;
1355  ULONG Count = 0, NextInstance = 0;
1356  WCHAR ValueBuffer[6];
1358 
1359  // obtain the device node's ServiceName
1360  Status = IopGetRegistryValue(InstanceHandle, L"Service", &kvInfo2);
1361  if (!NT_SUCCESS(Status))
1362  {
1363  return Status;
1364  }
1365 
1366  if (kvInfo2->Type != REG_SZ || kvInfo2->DataLength <= sizeof(WCHAR))
1367  {
1368  ExFreePool(kvInfo2);
1369  return STATUS_UNSUCCESSFUL;
1370  }
1371 
1372  ServiceName.MaximumLength = kvInfo2->DataLength;
1373  ServiceName.Length = kvInfo2->DataLength - sizeof(UNICODE_NULL);
1374  ServiceName.Buffer = (PVOID)((ULONG_PTR)kvInfo2 + kvInfo2->DataOffset);
1375 
1376  DPRINT("IopSetServiceEnumData(%p)\n", DeviceNode);
1377  DPRINT("Instance: %wZ\n", &DeviceNode->InstancePath);
1378  DPRINT("Service: %wZ\n", &ServiceName);
1379 
1380  ServiceKeyName.MaximumLength = ServicesKeyPath.Length + ServiceName.Length + sizeof(UNICODE_NULL);
1381  ServiceKeyName.Length = 0;
1382  ServiceKeyName.Buffer = ExAllocatePool(PagedPool, ServiceKeyName.MaximumLength);
1383  if (ServiceKeyName.Buffer == NULL)
1384  {
1385  DPRINT1("No ServiceKeyName.Buffer!\n");
1387  }
1388 
1389  RtlAppendUnicodeStringToString(&ServiceKeyName, &ServicesKeyPath);
1390  RtlAppendUnicodeStringToString(&ServiceKeyName, &ServiceName);
1391 
1392  DPRINT("ServiceKeyName: %wZ\n", &ServiceKeyName);
1393 
1394  Status = IopOpenRegistryKeyEx(&ServiceKey, NULL, &ServiceKeyName, KEY_CREATE_SUB_KEY);
1395  if (!NT_SUCCESS(Status))
1396  {
1397  goto done;
1398  }
1399 
1401  &ServiceName,
1402  &DeviceNode->ServiceName);
1403  if (!NT_SUCCESS(Status))
1404  {
1405  goto done;
1406  }
1407 
1408  RtlInitUnicodeString(&EnumKeyName, L"Enum");
1409  Status = IopCreateRegistryKeyEx(&ServiceEnumKey,
1410  ServiceKey,
1411  &EnumKeyName,
1412  KEY_SET_VALUE,
1414  &Disposition);
1415  if (NT_SUCCESS(Status))
1416  {
1418  {
1419  /* Read the NextInstance value */
1420  Status = IopGetRegistryValue(ServiceEnumKey,
1421  L"Count",
1422  &KeyValueInformation);
1423  if (!NT_SUCCESS(Status))
1424  goto done;
1425 
1426  if ((KeyValueInformation->Type == REG_DWORD) &&
1427  (KeyValueInformation->DataLength))
1428  {
1429  /* Read it */
1430  Count = *(PULONG)((ULONG_PTR)KeyValueInformation +
1431  KeyValueInformation->DataOffset);
1432  }
1433 
1434  ExFreePool(KeyValueInformation);
1435  KeyValueInformation = NULL;
1436 
1437  /* Read the NextInstance value */
1438  Status = IopGetRegistryValue(ServiceEnumKey,
1439  L"NextInstance",
1440  &KeyValueInformation);
1441  if (!NT_SUCCESS(Status))
1442  goto done;
1443 
1444  if ((KeyValueInformation->Type == REG_DWORD) &&
1445  (KeyValueInformation->DataLength))
1446  {
1447  NextInstance = *(PULONG)((ULONG_PTR)KeyValueInformation +
1448  KeyValueInformation->DataOffset);
1449  }
1450 
1451  ExFreePool(KeyValueInformation);
1452  KeyValueInformation = NULL;
1453  }
1454 
1455  /* Set the instance path */
1456  swprintf(ValueBuffer, L"%lu", NextInstance);
1457  RtlInitUnicodeString(&ValueName, ValueBuffer);
1458  Status = ZwSetValueKey(ServiceEnumKey,
1459  &ValueName,
1460  0,
1461  REG_SZ,
1462  DeviceNode->InstancePath.Buffer,
1463  DeviceNode->InstancePath.MaximumLength);
1464  if (!NT_SUCCESS(Status))
1465  goto done;
1466 
1467  /* Increment Count and NextInstance */
1468  Count++;
1469  NextInstance++;
1470 
1471  /* Set the new Count value */
1472  RtlInitUnicodeString(&ValueName, L"Count");
1473  Status = ZwSetValueKey(ServiceEnumKey,
1474  &ValueName,
1475  0,
1476  REG_DWORD,
1477  &Count,
1478  sizeof(Count));
1479  if (!NT_SUCCESS(Status))
1480  goto done;
1481 
1482  /* Set the new NextInstance value */
1483  RtlInitUnicodeString(&ValueName, L"NextInstance");
1484  Status = ZwSetValueKey(ServiceEnumKey,
1485  &ValueName,
1486  0,
1487  REG_DWORD,
1488  &NextInstance,
1489  sizeof(NextInstance));
1490  }
1491 
1492 done:
1493  if (ServiceEnumKey != NULL)
1494  ZwClose(ServiceEnumKey);
1495 
1496  if (ServiceKey != NULL)
1497  ZwClose(ServiceKey);
1498 
1499  ExFreePool(ServiceKeyName.Buffer);
1500  ExFreePool(kvInfo2);
1501 
1502  return Status;
1503 }
1504 
1514 static
1515 NTSTATUS
1518 {
1519  PNP_DEVICE_STATE PnPFlags;
1520  NTSTATUS Status;
1521 
1523  if (!NT_SUCCESS(Status))
1524  {
1525  return Status;
1526  }
1527 
1528  if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
1529  DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
1530  else
1531  DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
1532 
1533  if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
1534  DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
1535  else
1536  DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
1537 
1538  if (PnPFlags & PNP_DEVICE_REMOVED || PnPFlags & PNP_DEVICE_DISABLED)
1539  {
1541  PnPFlags & PNP_DEVICE_DISABLED
1544 
1546  }
1547  else if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
1548  {
1549  // Query resource rebalance
1550 
1551  if (PnPFlags & PNP_DEVICE_FAILED)
1553  else
1555 
1556  // Clear DNF_NO_RESOURCE_REQUIRED just in case (will be set back if needed)
1558 
1559  // This will be caught up later by enumeration
1561  }
1562  else if (PnPFlags & PNP_DEVICE_FAILED)
1563  {
1566  }
1567 
1568  return STATUS_SUCCESS;
1569 }
1570 
1571 static
1572 NTSTATUS
1575 {
1577  NTSTATUS Status;
1578 
1579  if (!(DeviceNode->Flags & DNF_IDS_QUERIED))
1580  {
1581  // query ids (for reported devices)
1583  HANDLE enumRootHandle, instanceHandle;
1584 
1585  // open the enumeration root key
1586  Status = IopOpenRegistryKeyEx(&enumRootHandle, NULL, &enumRoot, KEY_READ);
1587  if (!NT_SUCCESS(Status))
1588  {
1589  DPRINT1("IopOpenRegistryKeyEx() failed for \"%wZ\" (status %x)\n", &enumRoot, Status);
1590  return Status;
1591  }
1592 
1593  // open an instance subkey
1594  Status = IopOpenRegistryKeyEx(&instanceHandle, enumRootHandle, &DeviceNode->InstancePath, KEY_READ);
1595  ZwClose(enumRootHandle);
1596  if (!NT_SUCCESS(Status))
1597  {
1598  DPRINT1("Failed to open a devnode instance key for \"%wZ\" (status %x)\n",
1599  &DeviceNode->InstancePath, Status);
1600  return Status;
1601  }
1602 
1603  IopQueryHardwareIds(DeviceNode, instanceHandle);
1604  IopQueryCompatibleIds(DeviceNode, instanceHandle);
1605 
1606  DeviceNode->Flags |= DNF_IDS_QUERIED;
1607  ZwClose(instanceHandle);
1608  }
1609 
1610  // we're about to start - needs enumeration
1611  DeviceNode->Flags |= DNF_REENUMERATE;
1612 
1613  DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
1614 
1616  if (!NT_SUCCESS(Status))
1617  {
1618  DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1619  }
1620 
1621  // Query the device state (IRP_MN_QUERY_PNP_DEVICE_STATE)
1623 
1624  DPRINT("Sending GUID_DEVICE_ARRIVAL %wZ\n", &DeviceNode->InstancePath);
1625  IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath);
1626 
1628 
1629  return STATUS_SUCCESS;
1630 }
1631 
1632 /* PUBLIC FUNCTIONS **********************************************************/
1633 
1643 static
1644 NTSTATUS
1648 {
1649  KIRQL oldIrql;
1650 
1655 
1656  PDEVICE_OBJECT vpbDevObj = DeviceObject, targetDevice = DeviceObject;
1657 
1658  // walk the device stack down, stop on a first mounted device
1659  do
1660  {
1661  if (vpbDevObj->Vpb)
1662  {
1663  // two locks are needed here
1664  KeWaitForSingleObject(&vpbDevObj->DeviceLock, Executive, KernelMode, FALSE, NULL);
1665  IoAcquireVpbSpinLock(&oldIrql);
1666 
1668  {
1669  vpbDevObj->Vpb->Flags &= ~VPB_REMOVE_PENDING;
1670  }
1671  else
1672  {
1673  vpbDevObj->Vpb->Flags |= VPB_REMOVE_PENDING;
1674  }
1675 
1676  BOOLEAN isMounted = (_Bool)(vpbDevObj->Vpb->Flags & VPB_MOUNTED);
1677 
1678  if (isMounted)
1679  {
1680  targetDevice = vpbDevObj->Vpb->DeviceObject;
1681  }
1682 
1683  IoReleaseVpbSpinLock(oldIrql);
1684  KeSetEvent(&vpbDevObj->DeviceLock, IO_NO_INCREMENT, FALSE);
1685 
1686  if (isMounted)
1687  {
1688  break;
1689  }
1690  }
1691 
1693  vpbDevObj = vpbDevObj->AttachedDevice;
1695  } while (vpbDevObj);
1696 
1697  ASSERT(targetDevice);
1698 
1699  PVOID info;
1700  IO_STACK_LOCATION stack = {.MajorFunction = IRP_MJ_PNP, .MinorFunction = MinorFunction};
1701 
1702  return IopSynchronousCall(targetDevice, &stack, &info);
1703 }
1704 
1705 NTSTATUS
1708 
1709 static
1710 VOID
1711 NTAPI
1713 {
1715 
1717 
1718  /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
1720 
1721  /* Start of HACK: update resources stored in registry, so IopDetectResourceConflict works */
1722  if (DeviceNode->ResourceList)
1723  {
1724  ASSERT(DeviceNode->ResourceListTranslated);
1725  DeviceNode->ResourceList->Count = 0;
1726  DeviceNode->ResourceListTranslated->Count = 0;
1728  }
1729  /* End of HACK */
1730 
1732  PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_COMPLETE, DeviceObject, NULL);
1734  if (refCount != 0)
1735  {
1736  DPRINT1("Leaking device %wZ, refCount = %d\n", &DeviceNode->InstancePath, (INT32)refCount);
1737  }
1738 }
1739 
1740 static
1741 VOID
1743 {
1744  /* This function DOES dereference the device objects in all cases */
1745 
1746  ULONG i;
1747 
1748  for (i = 0; i < DeviceRelations->Count; i++)
1749  {
1750  IopSendRemoveDevice(DeviceRelations->Objects[i]);
1751  DeviceRelations->Objects[i] = NULL;
1752  }
1753 
1754  ExFreePool(DeviceRelations);
1755 }
1756 
1757 static
1758 VOID
1760 {
1761  PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
1762  KIRQL OldIrql;
1763 
1765  ChildDeviceNode = ParentDeviceNode->Child;
1766  while (ChildDeviceNode != NULL)
1767  {
1768  NextDeviceNode = ChildDeviceNode->Sibling;
1770 
1771  IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
1772 
1773  ChildDeviceNode = NextDeviceNode;
1774 
1776  }
1778 }
1779 
1780 static
1781 VOID
1782 NTAPI
1784 {
1786  /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
1788 }
1789 
1790 static
1791 VOID
1792 NTAPI
1794 {
1795  /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
1797 
1798  PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_REMOVE_CANCELLED, DeviceObject, NULL);
1799 }
1800 
1801 static
1802 VOID
1804 {
1805  PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
1806  KIRQL OldIrql;
1807 
1809  ChildDeviceNode = ParentDeviceNode->Child;
1810  while (ChildDeviceNode != NULL)
1811  {
1812  NextDeviceNode = ChildDeviceNode->Sibling;
1814 
1816 
1817  ChildDeviceNode = NextDeviceNode;
1818 
1820  }
1822 }
1823 
1824 static
1825 VOID
1827 {
1828  /* This function DOES dereference the device objects in all cases */
1829 
1830  ULONG i;
1831 
1832  for (i = 0; i < DeviceRelations->Count; i++)
1833  {
1834  IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
1835  ObDereferenceObject(DeviceRelations->Objects[i]);
1836  DeviceRelations->Objects[i] = NULL;
1837  }
1838 
1839  ExFreePool(DeviceRelations);
1840 }
1841 
1842 static
1843 VOID
1845 {
1848  PDEVICE_RELATIONS DeviceRelations;
1849  NTSTATUS Status;
1850 
1852 
1853  Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
1854 
1856  &IoStatusBlock,
1858  &Stack);
1859  if (!NT_SUCCESS(Status))
1860  {
1861  DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
1862  DeviceRelations = NULL;
1863  }
1864  else
1865  {
1866  DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1867  }
1868 
1869  if (DeviceRelations)
1870  IopCancelRemoveDeviceRelations(DeviceRelations);
1871 }
1872 
1873 static
1874 NTSTATUS
1875 NTAPI
1877 {
1879  NTSTATUS Status;
1880 
1881  ASSERT(DeviceNode);
1882 
1883  IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
1884  &DeviceNode->InstancePath);
1885 
1887 
1888  PiNotifyTargetDeviceChange(&GUID_TARGET_DEVICE_QUERY_REMOVE, DeviceObject, NULL);
1889 
1890  if (!NT_SUCCESS(Status))
1891  {
1892  DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath);
1893  IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
1894  &DeviceNode->InstancePath);
1895  }
1896 
1897  return Status;
1898 }
1899 
1900 static
1901 NTSTATUS
1903 {
1904  PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
1905  NTSTATUS Status;
1906  KIRQL OldIrql;
1907 
1909  ChildDeviceNode = ParentDeviceNode->Child;
1910  while (ChildDeviceNode != NULL)
1911  {
1912  NextDeviceNode = ChildDeviceNode->Sibling;
1915 
1917  if (!NT_SUCCESS(Status))
1918  {
1919  FailedRemoveDevice = ChildDeviceNode;
1920  goto cleanup;
1921  }
1922 
1924  ChildDeviceNode = NextDeviceNode;
1925  }
1927 
1928  return STATUS_SUCCESS;
1929 
1930 cleanup:
1932  ChildDeviceNode = ParentDeviceNode->Child;
1933  while (ChildDeviceNode != NULL)
1934  {
1935  NextDeviceNode = ChildDeviceNode->Sibling;
1937 
1939 
1940  /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
1941  * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
1942  if (ChildDeviceNode == FailedRemoveDevice)
1943  return Status;
1944 
1945  ChildDeviceNode = NextDeviceNode;
1946 
1948  }
1950 
1951  return Status;
1952 }
1953 
1954 static
1955 NTSTATUS
1957 {
1958  /* This function DOES NOT dereference the device objects on SUCCESS
1959  * but it DOES dereference device objects on FAILURE */
1960 
1961  ULONG i, j;
1962  NTSTATUS Status;
1963 
1964  for (i = 0; i < DeviceRelations->Count; i++)
1965  {
1966  Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force);
1967  if (!NT_SUCCESS(Status))
1968  {
1969  j = i;
1970  goto cleanup;
1971  }
1972  }
1973 
1974  return STATUS_SUCCESS;
1975 
1976 cleanup:
1977  /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
1978  * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
1979  for (i = 0; i <= j; i++)
1980  {
1981  IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
1982  ObDereferenceObject(DeviceRelations->Objects[i]);
1983  DeviceRelations->Objects[i] = NULL;
1984  }
1985  for (; i < DeviceRelations->Count; i++)
1986  {
1987  ObDereferenceObject(DeviceRelations->Objects[i]);
1988  DeviceRelations->Objects[i] = NULL;
1989  }
1990  ExFreePool(DeviceRelations);
1991 
1992  return Status;
1993 }
1994 
1995 static
1996 NTSTATUS
1998 {
2002  PDEVICE_RELATIONS DeviceRelations;
2003  NTSTATUS Status;
2004 
2005  if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force)
2006  {
2007  DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
2008  return STATUS_UNSUCCESSFUL;
2009  }
2010 
2012  {
2013  DPRINT1("Removal vetoed by failing the query remove request\n");
2014 
2016 
2017  return STATUS_UNSUCCESSFUL;
2018  }
2019 
2020  Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
2021 
2023  &IoStatusBlock,
2025  &Stack);
2026  if (!NT_SUCCESS(Status))
2027  {
2028  DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2029  DeviceRelations = NULL;
2030  }
2031  else
2032  {
2033  DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2034  }
2035 
2036  if (DeviceRelations)
2037  {
2038  Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force);
2039  if (!NT_SUCCESS(Status))
2040  return Status;
2041  }
2042 
2044  if (!NT_SUCCESS(Status))
2045  {
2046  if (DeviceRelations)
2047  IopCancelRemoveDeviceRelations(DeviceRelations);
2048  return Status;
2049  }
2050 
2051  if (DeviceRelations)
2052  IopSendRemoveDeviceRelations(DeviceRelations);
2054 
2055  return STATUS_SUCCESS;
2056 }
2057 
2058 static
2059 NTSTATUS
2061 {
2062  NTSTATUS Status;
2063 
2064  // This function removes the device subtree, with the root in DeviceNode
2065  // atm everyting is in fact done inside this function, which is completely wrong.
2066  // The right implementation should have a separate removal worker thread and
2067  // properly do device node state transitions
2068 
2069  DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
2070 
2071  BOOLEAN surpriseRemoval = (_Bool)(DeviceNode->Flags & DNF_DEVICE_GONE);
2072 
2073  Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, surpriseRemoval);
2074 
2075  if (surpriseRemoval)
2076  {
2077  IopSendSurpriseRemoval(DeviceNode->PhysicalDeviceObject);
2078  IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL, &DeviceNode->InstancePath);
2079  }
2080 
2081  if (NT_SUCCESS(Status))
2082  {
2083  IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
2084  if (surpriseRemoval)
2085  {
2086  IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL, &DeviceNode->InstancePath);
2087  }
2088  return STATUS_SUCCESS;
2089  }
2090 
2091  return Status;
2092 }
2093 
2094 static
2095 NTSTATUS
2098 {
2099  PDEVICE_OBJECT ChildDeviceObject;
2100  PDEVICE_NODE ChildDeviceNode;
2101  ULONG i;
2102 
2103  // bus relations are already obtained for this device node
2104 
2105  if (!NT_SUCCESS(DeviceNode->CompletionStatus))
2106  {
2107  DPRINT("QDR request failed for %wZ, status %x\n",
2108  &DeviceNode->InstancePath, DeviceNode->CompletionStatus);
2109  // treat as if there are no child objects
2110  }
2111 
2112  PDEVICE_RELATIONS DeviceRelations = DeviceNode->OverUsed1.PendingDeviceRelations;
2113  DeviceNode->OverUsed1.PendingDeviceRelations = NULL;
2114 
2115  // it's acceptable not to have PDOs
2116  if (!DeviceRelations)
2117  {
2119  DPRINT("No PDOs\n");
2120  return STATUS_SUCCESS;
2121  }
2122 
2123  // mark children nodes as non-present (those not returned in DR request will be removed)
2124  for (PDEVICE_NODE child = DeviceNode->Child; child != NULL; child = child->Sibling)
2125  {
2126  child->Flags &= ~DNF_ENUMERATED;
2127  }
2128 
2129  DPRINT("PiEnumerateDevice: enumerating %u children\n", DeviceRelations->Count);
2130 
2131  // create device nodes for all new children and set DNF_ENUMERATED back for old ones
2132  for (i = 0; i < DeviceRelations->Count; i++)
2133  {
2134  ChildDeviceObject = DeviceRelations->Objects[i];
2135  ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2136 
2137  ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2138  if (!ChildDeviceNode)
2139  {
2140  /* One doesn't exist, create it */
2141  ChildDeviceNode = PipAllocateDeviceNode(ChildDeviceObject);
2142  if (ChildDeviceNode)
2143  {
2144  PiInsertDevNode(ChildDeviceNode, DeviceNode);
2145 
2146  /* Mark the node as enumerated */
2147  ChildDeviceNode->Flags |= DNF_ENUMERATED;
2148 
2149  /* Mark the DO as bus enumerated */
2150  ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2151  }
2152  else
2153  {
2154  /* Ignore this DO */
2155  DPRINT1("PipAllocateDeviceNode() failed. Skipping PDO %u\n", i);
2156  ObDereferenceObject(ChildDeviceObject);
2157  }
2158  }
2159  else
2160  {
2161  /* Mark it as enumerated */
2162  ChildDeviceNode->Flags |= DNF_ENUMERATED;
2163  ObDereferenceObject(ChildDeviceObject);
2164  }
2165  }
2166  ExFreePool(DeviceRelations);
2167 
2168  // time to remove non-reported devices
2169  for (PDEVICE_NODE child = DeviceNode->Child; child != NULL; child = child->Sibling)
2170  {
2171  if (!(child->Flags & (DNF_ENUMERATED|DNF_DEVICE_GONE)))
2172  {
2173  // this flag indicates that this is a surprise removal
2174  child->Flags |= DNF_DEVICE_GONE;
2176  }
2177  }
2178 
2180  return STATUS_SUCCESS;
2181 }
2182 
2183 static
2184 NTSTATUS
2185 NTAPI
2187 {
2189  PVOID Dummy;
2190 
2192  Stack.MajorFunction = IRP_MJ_PNP;
2193  Stack.MinorFunction = IRP_MN_EJECT;
2194 
2195  return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
2196 }
2197 
2198 /*
2199  * @implemented
2200  */
2201 VOID
2202 NTAPI
2204 {
2206  PDEVICE_RELATIONS DeviceRelations;
2210  NTSTATUS Status;
2211 
2212  IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
2213  &DeviceNode->InstancePath);
2214 
2216  {
2217  goto cleanup;
2218  }
2219 
2220  Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
2221 
2223  &IoStatusBlock,
2225  &Stack);
2226  if (!NT_SUCCESS(Status))
2227  {
2228  DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2229  DeviceRelations = NULL;
2230  }
2231  else
2232  {
2233  DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2234  }
2235 
2236  if (DeviceRelations)
2237  {
2238  Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE);
2239  if (!NT_SUCCESS(Status))
2240  goto cleanup;
2241  }
2242 
2244  if (!NT_SUCCESS(Status))
2245  {
2246  if (DeviceRelations)
2247  IopCancelRemoveDeviceRelations(DeviceRelations);
2248  goto cleanup;
2249  }
2250 
2252  {
2253  if (DeviceRelations)
2254  IopCancelRemoveDeviceRelations(DeviceRelations);
2256  goto cleanup;
2257  }
2258 
2259  if (DeviceRelations)
2260  IopSendRemoveDeviceRelations(DeviceRelations);
2262 
2264  if (Capabilities.EjectSupported)
2265  {
2267  {
2268  goto cleanup;
2269  }
2270  }
2271  else
2272  {
2273  // DeviceNode->Flags |= DNF_DISABLED;
2274  }
2275 
2276  IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
2277  &DeviceNode->InstancePath);
2278 
2279  return;
2280 
2281 cleanup:
2282  IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
2283  &DeviceNode->InstancePath);
2284 }
2285 
2286 static
2287 VOID
2290 {
2292 
2293  PCM_RESOURCE_LIST bootConfig = NULL;
2294  PIO_RESOURCE_REQUIREMENTS_LIST resourceRequirements = NULL;
2295 
2296  PiIrpQueryResources(DeviceNode, &bootConfig);
2297  PiIrpQueryResourceRequirements(DeviceNode, &resourceRequirements);
2298 
2299  DeviceNode->BootResources = bootConfig;
2300  DeviceNode->ResourceRequirements = resourceRequirements;
2301 
2302  if (bootConfig)
2303  {
2304  DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
2305  }
2306 
2308 }
2309 
2310 static
2311 VOID
2314 {
2315  NTSTATUS status;
2316  BOOLEAN doProcessAgain;
2317  PDEVICE_NODE currentNode = RootNode;
2318  PDEVICE_OBJECT referencedObject;
2319 
2320  do
2321  {
2322  doProcessAgain = FALSE;
2323 
2324  // The device can be removed during processing, but we still need its Parent and Sibling
2325  // links to continue the tree traversal. So keep the link till the and of a cycle
2326  referencedObject = currentNode->PhysicalDeviceObject;
2327  ObReferenceObject(referencedObject);
2328 
2329  // Devices with problems are skipped (unless they are not being removed)
2330  if (currentNode->Flags & DNF_HAS_PROBLEM &&
2331  currentNode->State != DeviceNodeAwaitingQueuedRemoval)
2332  {
2333  goto skipEnum;
2334  }
2335 
2336  switch (currentNode->State)
2337  {
2338  case DeviceNodeUnspecified: // this state is not used
2339  break;
2341  DPRINT("DeviceNodeUninitialized %wZ\n", &currentNode->InstancePath);
2342  status = PiInitializeDevNode(currentNode);
2343  doProcessAgain = NT_SUCCESS(status);
2344  break;
2345  case DeviceNodeInitialized:
2346  DPRINT("DeviceNodeInitialized %wZ\n", &currentNode->InstancePath);
2348  doProcessAgain = NT_SUCCESS(status);
2349  break;
2351  DPRINT("DeviceNodeDriversAdded %wZ\n", &currentNode->InstancePath);
2352  status = IopAssignDeviceResources(currentNode);
2353  doProcessAgain = NT_SUCCESS(status);
2354  break;
2356  DPRINT("DeviceNodeResourcesAssigned %wZ\n", &currentNode->InstancePath);
2357  // send IRP_MN_START_DEVICE
2358  PiIrpStartDevice(currentNode);
2359 
2360  // skip DeviceNodeStartPending, it is probably used for an async IRP_MN_START_DEVICE
2362  doProcessAgain = TRUE;
2363  break;
2364  case DeviceNodeStartPending: // skipped on XP/2003
2365  break;
2367  DPRINT("DeviceNodeStartCompletion %wZ\n", &currentNode->InstancePath);
2368  status = currentNode->CompletionStatus;
2369  doProcessAgain = TRUE;
2370  if (!NT_SUCCESS(status))
2371  {
2375 
2376  PiSetDevNodeProblem(currentNode, problem);
2378  }
2379  else
2380  {
2381  // TODO: IopDoDeferredSetInterfaceState and IopAllocateLegacyBootResources
2382  // are called here too
2383 
2385  }
2386  break;
2388  DPRINT("DeviceNodeStartPostWork %wZ\n", &currentNode->InstancePath);
2389  // TODO: inspect the status
2390  status = PiStartDeviceFinal(currentNode);
2391  doProcessAgain = TRUE;
2392  break;
2393  case DeviceNodeStarted:
2394  if (currentNode->Flags & DNF_REENUMERATE)
2395  {
2396  DPRINT("DeviceNodeStarted REENUMERATE %wZ\n", &currentNode->InstancePath);
2397  currentNode->Flags &= ~DNF_REENUMERATE;
2399 
2400  // again, skip DeviceNodeEnumeratePending as with the starting sequence
2402  doProcessAgain = TRUE;
2403  }
2404  else if (currentNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED)
2405  {
2406  if (currentNode->Flags & DNF_NON_STOPPED_REBALANCE)
2407  {
2408  PiFakeResourceRebalance(currentNode);
2409  currentNode->Flags &= ~DNF_NON_STOPPED_REBALANCE;
2410  }
2411  else
2412  {
2413  PiIrpQueryStopDevice(currentNode);
2415  }
2416 
2417  doProcessAgain = TRUE;
2418  }
2419  break;
2421  // we're here after sending IRP_MN_QUERY_STOP_DEVICE
2422  status = currentNode->CompletionStatus;
2423  if (NT_SUCCESS(status))
2424  {
2425  PiIrpStopDevice(currentNode);
2426  PiSetDevNodeState(currentNode, DeviceNodeStopped);
2427  }
2428  else
2429  {
2430  PiIrpCancelStopDevice(currentNode);
2431  PiSetDevNodeState(currentNode, DeviceNodeStarted);
2432  }
2433  doProcessAgain = TRUE;
2434  break;
2435  case DeviceNodeStopped:
2436  // TODO: do resource rebalance (not implemented)
2437  PiFakeResourceRebalance(currentNode);
2438 
2440  doProcessAgain = TRUE;
2441  break;
2443  break;
2444  case DeviceNodeEnumeratePending: // skipped on XP/2003
2445  break;
2447  DPRINT("DeviceNodeEnumerateCompletion %wZ\n", &currentNode->InstancePath);
2448  status = PiEnumerateDevice(currentNode);
2449  doProcessAgain = TRUE;
2450  break;
2452  break;
2454  DPRINT("DeviceNodeAwaitingQueuedRemoval %wZ\n", &currentNode->InstancePath);
2455  status = IopRemoveDevice(currentNode);
2456  break;
2458  break;
2460  break;
2461  case DeviceNodeRemoved:
2462  break;
2464  break;
2465  case DeviceNodeDeleted:
2466  break;
2467  default:
2468  break;
2469  }
2470 
2471 skipEnum:
2472  if (!doProcessAgain)
2473  {
2474  KIRQL OldIrql;
2476  /* If we have a child, simply go down the tree */
2477  if (currentNode->State != DeviceNodeRemoved && currentNode->Child != NULL)
2478  {
2479  ASSERT(currentNode->Child->Parent == currentNode);
2480  currentNode = currentNode->Child;
2481  }
2482  else
2483  {
2484  while (currentNode != RootNode)
2485  {
2486  /* All children processed -- go sideways */
2487  if (currentNode->Sibling != NULL)
2488  {
2489  ASSERT(currentNode->Sibling->Parent == currentNode->Parent);
2490  currentNode = currentNode->Sibling;
2491  break;
2492  }
2493  else
2494  {
2495  /* We're the last sibling -- go back up */
2496  ASSERT(currentNode->Parent->LastChild == currentNode);
2497  currentNode = currentNode->Parent;
2498  }
2499  /* We already visited the parent and all its children, so keep looking */
2500  }
2501  }
2503  }
2504  ObDereferenceObject(referencedObject);
2505  } while (doProcessAgain || currentNode != RootNode);
2506 }
2507 
2508 #ifdef DBG
2509 static
2510 PCSTR
2511 ActionToStr(
2513 {
2514  switch (Action)
2515  {
2517  return "PiActionEnumDeviceTree";
2519  return "PiActionEnumRootDevices";
2520  case PiActionResetDevice:
2521  return "PiActionResetDevice";
2523  return "PiActionAddBootDevices";
2524  case PiActionStartDevice:
2525  return "PiActionStartDevice";
2526  case PiActionQueryState:
2527  return "PiActionQueryState";
2528  default:
2529  return "(request unknown)";
2530  }
2531 }
2532 #endif
2533 
2534 static
2535 VOID
2536 NTAPI
2539 {
2540  PLIST_ENTRY ListEntry;
2542  KIRQL OldIrql;
2543  PDEVICE_NODE deviceNode;
2544  NTSTATUS status;
2545 
2548  {
2551  Request = CONTAINING_RECORD(ListEntry, DEVICE_ACTION_REQUEST, RequestListEntry);
2552 
2553  ASSERT(Request->DeviceObject);
2554 
2555  deviceNode = IopGetDeviceNode(Request->DeviceObject);
2556  ASSERT(deviceNode);
2557 
2559 
2560  DPRINT("Processing PnP request %p: DeviceObject - %p, Action - %s\n",
2561  Request, Request->DeviceObject, ActionToStr(Request->Action));
2562 
2563  switch (Request->Action)
2564  {
2566  {
2567  if (deviceNode->State == DeviceNodeInitialized &&
2568  !(deviceNode->Flags & DNF_HAS_PROBLEM))
2569  {
2571  }
2572  break;
2573  }
2576  deviceNode->Flags |= DNF_REENUMERATE;
2577  PiDevNodeStateMachine(deviceNode);
2578  break;
2579 
2580  case PiActionResetDevice:
2581  // TODO: the operation is a no-op for everything except removed nodes
2582  // for removed nodes, it returns them back to DeviceNodeUninitialized
2584  break;
2585 
2586  case PiActionStartDevice:
2587  // This action is triggered from usermode, when a driver is installed
2588  // for a non-critical PDO
2589  if (deviceNode->State == DeviceNodeInitialized &&
2590  !(deviceNode->Flags & DNF_HAS_PROBLEM))
2591  {
2592  PiDevNodeStateMachine(deviceNode);
2593  }
2594  else
2595  {
2596  DPRINT1("NOTE: attempt to start an already started/uninitialized device %wZ\n",
2597  &deviceNode->InstancePath);
2599  }
2600  break;
2601 
2602  case PiActionQueryState:
2603  // This action is only valid for started devices. If the device is not yet
2604  // started, the PnP manager issues IRP_MN_QUERY_PNP_DEVICE_STATE by itself.
2605  if (deviceNode->State == DeviceNodeStarted)
2606  {
2607  // Issue a IRP_MN_QUERY_PNP_DEVICE_STATE request: it will update node's flags
2608  // and then do enumeration if something has changed
2609  status = PiUpdateDeviceState(deviceNode);
2610  if (NT_SUCCESS(status))
2611  {
2612  PiDevNodeStateMachine(deviceNode);
2613  }
2614  }
2615  // TODO: Windows may return STATUS_DELETE_PENDING here
2617  break;
2618 
2619  default:
2620  DPRINT1("Unimplemented device action %u\n", Request->Action);
2622  break;
2623  }
2624 
2625  if (Request->CompletionStatus)
2626  {
2627  *Request->CompletionStatus = status;
2628  }
2629 
2630  if (Request->CompletionEvent)
2631  {
2632  KeSetEvent(Request->CompletionEvent, IO_NO_INCREMENT, FALSE);
2633  }
2634 
2635  DPRINT("Finished processing PnP request %p\n", Request);
2636  ObDereferenceObject(Request->DeviceObject);
2639  }
2643 }
2644 
2654 VOID
2658  _In_opt_ PKEVENT CompletionEvent,
2659  _Out_opt_ NTSTATUS *CompletionStatus)
2660 {
2662  KIRQL OldIrql;
2663 
2665 
2666  DPRINT("PiQueueDeviceAction: DeviceObject - %p, Request - %p, Action - %s\n",
2667  DeviceObject, Request, ActionToStr(Action));
2668 
2670 
2671  Request->DeviceObject = DeviceObject;
2672  Request->Action = Action;
2673  Request->CompletionEvent = CompletionEvent;
2674  Request->CompletionStatus = CompletionStatus;
2675 
2677  InsertTailList(&IopDeviceActionRequestList, &Request->RequestListEntry);
2678 
2680  {
2682 
2686 
2688  return;
2689  }
2690 
2692  {
2694  return;
2695  }
2699 
2702 }
2703 
2713 NTSTATUS
2717 {
2718  KEVENT opFinished;
2719  NTSTATUS status;
2720 
2722  PiQueueDeviceAction(DeviceObject, Action, &opFinished, &status);
2724 
2725  return status;
2726 }
#define DO_DEVICE_INITIALIZING
Definition: env_spec_w32.h:399
BOOLEAN PnPBootDriversLoaded
Definition: pnpinit.c:26
#define IRP_MN_CANCEL_REMOVE_DEVICE
struct _CM_RESOURCE_LIST * PCM_RESOURCE_LIST
struct _ADD_DEV_DRIVERS_LIST ADD_DEV_DRIVERS_LIST
LIST_ENTRY IopDeviceActionRequestList
Definition: devaction.c:46
struct _ATTACH_FILTER_DRIVERS_CONTEXT * PATTACH_FILTER_DRIVERS_CONTEXT
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:4182
#define IN
Definition: typedefs.h:39
return STATUS_NOT_SUPPORTED
NTSTATUS IopGetDriverNames(_In_ HANDLE ServiceHandle, _Out_ PUNICODE_STRING DriverName, _Out_opt_ PUNICODE_STRING ServiceName)
Definition: driver.c:123
ULONG Flags
Definition: iotypes.h:852
static NTSTATUS PiInitializeDevNode(_In_ PDEVICE_NODE DeviceNode)
Definition: devaction.c:1190
#define STATUS_PLUGPLAY_NO_DEVICE
Definition: ntstatus.h:731
#define DNF_NON_STOPPED_REBALANCE
Definition: iotypes.h:181
PDEVICE_OBJECT PhysicalDeviceObject
Definition: iotypes.h:855
static NTSTATUS IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force)
Definition: devaction.c:1902
#define IRP_MN_QUERY_RESOURCES
enum _BUS_QUERY_ID_TYPE BUS_QUERY_ID_TYPE
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:723
static VOID IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
Definition: devaction.c:1803
static NTSTATUS PiEnumerateDevice(_In_ PDEVICE_NODE DeviceNode)
Definition: devaction.c:2096
#define IRP_MN_REMOVE_DEVICE
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define IRP_MN_QUERY_ID
struct _ATTACH_FILTER_DRIVERS_CONTEXT ATTACH_FILTER_DRIVERS_CONTEXT
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
static VOID PiDevNodeStateMachine(_In_ PDEVICE_NODE RootNode)
Definition: devaction.c:2312
#define DNF_HAS_PROBLEM
Definition: iotypes.h:183
#define TAG_IO
Definition: tag.h:77
#define _In_opt_
Definition: ms_sal.h:309
static NTSTATUS NTAPI IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: devaction.c:1876
#define PNP_DEVICE_REMOVED
Definition: iotypes.h:1004
PNP_DEVNODE_STATE PiSetDevNodeState(_In_ PDEVICE_NODE DeviceNode, _In_ PNP_DEVNODE_STATE NewState)
Definition: devnode.c:108
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
#define KEY_SET_VALUE
Definition: nt_native.h:1017
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
NTSTATUS PiIrpCancelStopDevice(_In_ PDEVICE_NODE DeviceNode)
Definition: pnpirp.c:154
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define _Out_
Definition: ms_sal.h:345
#define DNUF_NOT_DISABLEABLE
Definition: iotypes.h:211
Definition: http.c:7251
NTSTATUS PiIrpQueryDeviceText(_In_ PDEVICE_NODE DeviceNode, _In_ LCID LocaleId, _In_ DEVICE_TEXT_TYPE Type, _Out_ PWSTR *DeviceText)
Definition: pnpirp.c:253
#define CM_PROB_HELD_FOR_EJECT
Definition: cfg.h:77
#define KEY_READ
Definition: nt_native.h:1023
struct _DEVICE_ACTION_REQUEST DEVICE_ACTION_REQUEST
#define TRUE
Definition: types.h:120
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
uint16_t * PWSTR
Definition: typedefs.h:56
#define RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING
Definition: green.h:16
#define IRP_MN_QUERY_RESOURCE_REQUIREMENTS
PDEVICE_OBJECT Objects[1]
Definition: iotypes.h:2163
#define CM_PROB_OUT_OF_MEMORY
Definition: cfg.h:33
NTSTATUS NTAPI IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, IN ULONG CreateOptions, OUT PHANDLE Handle)
Definition: pnpmgr.c:522
#define IRP_MJ_PNP
Definition: cdrw_usr.h:52
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
NTSTATUS PiIrpQueryResourceRequirements(_In_ PDEVICE_NODE DeviceNode, _Out_ PIO_RESOURCE_REQUIREMENTS_LIST *Resources)
Definition: pnpirp.c:227
enum _CM_SERVICE_LOAD_TYPE SERVICE_LOAD_TYPE
LONG NTSTATUS
Definition: precomp.h:26
ULONG PNP_DEVICE_STATE
Definition: iotypes.h:997
DEVICE_ACTION Action
Definition: devaction.c:61
#define STATUS_FAILED_DRIVER_ENTRY
Definition: ntstatus.h:911
static VOID NTAPI IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: devaction.c:1793
VOID NTAPI KeAcquireSpinLock(PKSPIN_LOCK SpinLock, PKIRQL OldIrql)
Definition: spinlock.c:50
#define DNF_NO_RESOURCE_REQUIRED
Definition: iotypes.h:178
NTSTATUS PiIrpQueryStopDevice(_In_ PDEVICE_NODE DeviceNode)
Definition: pnpirp.c:133
VOID NTAPI IoAcquireVpbSpinLock(OUT PKIRQL Irql)
Definition: volume.c:1204
NTSYSAPI NTSTATUS NTAPI ZwQueryDefaultLocale(_In_ BOOLEAN UserProfile, _Out_ PLCID DefaultLocaleId)
#define DNF_HAS_BOOT_CONFIG
Definition: iotypes.h:176
struct _IO_RESOURCE_REQUIREMENTS_LIST * PIO_RESOURCE_REQUIREMENTS_LIST
_In_ WDFREQUEST Request
Definition: wdfdevice.h:547
#define CM_PROB_FAILED_START
Definition: cfg.h:40
DEVICE_CAPABILITIES
Definition: iotypes.h:965
#define CM_PROB_FAILED_POST_START
Definition: cfg.h:73
DWORD LCID
Definition: nls.h:13
static NTSTATUS PiIrpSendRemoveCheckVpb(_In_ PDEVICE_OBJECT DeviceObject, _In_ UCHAR MinorFunction)
Sends one of the remove IRPs to the device stack.
Definition: devaction.c:1645
POBJECT_TYPE IoDriverObjectType
Definition: driver.c:33
#define IRP_MN_EJECT
#define REG_OPENED_EXISTING_KEY
Definition: nt_native.h:1085
#define CM_PROB_FAILED_DRIVER_ENTRY
Definition: cfg.h:67
uint16_t * PWCHAR
Definition: typedefs.h:56
PDEVICE_OBJECT PhysicalDeviceObject
Definition: btrfs_drv.h:1149
#define InsertTailList(ListHead, Entry)
_In_ ULONG TotalLength
Definition: usbdlib.h:158
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG _Out_opt_ PULONG _Out_opt_ PULONG ValueType
Definition: wdfregistry.h:279
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
NTSTATUS PiIrpStartDevice(_In_ PDEVICE_NODE DeviceNode)
Definition: pnpirp.c:87
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define PNP_DEVICE_DISABLED
Definition: iotypes.h:1001
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
struct _DEVICE_NODE * Parent
Definition: iotypes.h:841
static HWND child
Definition: cursoricon.c:298
#define PNP_DEVICE_DONT_DISPLAY_IN_UI
Definition: iotypes.h:1002
_In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Reserved_ ULONG _In_opt_ PUNICODE_STRING _In_ ULONG _Out_opt_ PULONG Disposition
Definition: cmfuncs.h:50
#define OBJ_OPENIF
Definition: winternl.h:229
static NTSTATUS IopRemoveDevice(PDEVICE_NODE DeviceNode)
Definition: devaction.c:2060
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
static NTSTATUS IopQueryHardwareIds(PDEVICE_NODE DeviceNode, HANDLE InstanceKey)
Definition: devaction.c:957
DWORD Id
uint32_t ULONG_PTR
Definition: typedefs.h:65
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:636
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS IopLoadDriver(_In_ HANDLE ServiceHandle, _Out_ PDRIVER_OBJECT *DriverObject)
Definition: driver.c:1909
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
static NTSTATUS IopQueryCompatibleIds(PDEVICE_NODE DeviceNode, HANDLE InstanceKey)
Definition: devaction.c:1022
return STATUS_NOT_IMPLEMENTED
NTSTATUS NTAPI IopCreateRegistryKeyEx(OUT PHANDLE Handle, IN HANDLE BaseHandle OPTIONAL, IN PUNICODE_STRING KeyName, IN ACCESS_MASK DesiredAccess, IN ULONG CreateOptions, OUT PULONG Disposition OPTIONAL)
#define L(x)
Definition: ntvdm.h:50
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
struct _DEVICE_NODE * Child
Definition: iotypes.h:840
KSPIN_LOCK IopDeviceActionLock
Definition: devaction.c:49
#define FALSE
Definition: types.h:117
#define UNICODE_NULL
unsigned int UINT32
#define IRP_MN_QUERY_REMOVE_DEVICE
_Must_inspect_result_ typedef _Out_ PHIDP_CAPS Capabilities
Definition: hidclass.h:103
#define DNUF_DONT_SHOW_IN_UI
Definition: iotypes.h:209
NTSTATUS IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode)
Definition: pnpres.c:961
PDEVICE_NODE PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
LIST_ENTRY ListEntry
Definition: devaction.c:75
static struct _test_info info[]
Definition: SetCursorPos.c:19
#define REG_MULTI_SZ
Definition: nt_native.h:1501
NTSTATUS NTAPI IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode, PDEVICE_CAPABILITIES DeviceCaps)
Definition: devaction.c:854
PDRIVER_EXTENSION DriverExtension
Definition: iotypes.h:2282
_In_ UCHAR _In_ UCHAR MinorFunction
Definition: wdfdevice.h:1697
LIST_ENTRY RequestListEntry
Definition: devaction.c:57
NTSTATUS PiPerformSyncDeviceAction(_In_ PDEVICE_OBJECT DeviceObject, _In_ DEVICE_ACTION Action)
Perfom a device operation synchronously via PiQueueDeviceAction.
Definition: devaction.c:2714
_Must_inspect_result_ _In_opt_ PVOID _In_opt_ PVOID InstanceId
Definition: fsrtlfuncs.h:907
PDEVICE_OBJECT DeviceObject
Definition: devaction.c:58
static NTSTATUS IopCreateDeviceInstancePath(_In_ PDEVICE_NODE DeviceNode, _Out_ PUNICODE_STRING InstancePath)
Definition: devaction.c:213
struct _DEVICE_RELATIONS * PDEVICE_RELATIONS
#define IopDeviceNodeSetFlag(DeviceNode, Flag)
Definition: io.h:146
VOID NTAPI IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
Definition: pnpmgr.c:45
unsigned char BOOLEAN
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4182
#define DO_BUS_ENUMERATED_DEVICE
struct _PNP_BUS_INFORMATION * PPNP_BUS_INFORMATION
PNP_DEVNODE_STATE State
Definition: iotypes.h:846
#define _In_
Definition: ms_sal.h:308
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
KEVENT PiEnumerationFinished
Definition: devaction.c:50
#define DeviceCapabilities
Definition: wingdi.h:4449
NTSTATUS PiIrpStopDevice(_In_ PDEVICE_NODE DeviceNode)
Definition: pnpirp.c:111
Definition: bufpool.h:45
_ADD_DEV_DRIVER_TYPE
Definition: devaction.c:64
void * PVOID
Definition: retypes.h:9
ADD_DEV_DRIVER_TYPE DriverType
Definition: devaction.c:77
static int isMounted
Definition: fatten.c:16
#define VPB_REMOVE_PENDING
Definition: ntifs_ex.h:428
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
PDEVICE_OBJECT NTAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
Definition: device.c:1406
_Must_inspect_result_ _In_ PDRIVER_OBJECT DriverObject
Definition: wdfdriver.h:213
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
enum _DEVICE_ACTION DEVICE_ACTION
Definition: _stack.h:47
#define STATUS_ILL_FORMED_SERVICE_ENTRY
Definition: ntstatus.h:588
static VOID NTAPI IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: devaction.c:1712
BOOLEAN PnpSystemInit
Definition: iomgr.c:17
Status
Definition: gdiplustypes.h:24
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
enum _ADD_DEV_DRIVER_TYPE ADD_DEV_DRIVER_TYPE
char serviceName[]
Definition: tftpd.cpp:34
NTSTATUS RtlAppendUnicodeToString(IN PUNICODE_STRING Str1, IN PWSTR Str2)
Definition: string_lib.cpp:62
VOID PiSetDevNodeProblem(_In_ PDEVICE_NODE DeviceNode, _In_ UINT32 Problem)
Definition: devnode.c:132
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
int Count
Definition: noreturn.cpp:7
#define CM_PROB_HARDWARE_DISABLED
Definition: cfg.h:59
NTSTATUS IopQueueTargetDeviceEvent(const GUID *Guid, PUNICODE_STRING DeviceIds)
Definition: plugplay.c:43
#define IRP_MN_SURPRISE_REMOVAL
Definition: ntifs_ex.h:408
#define STATUS_OBJECT_TYPE_MISMATCH
Definition: ntstatus.h:273
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
static BOOLEAN IopValidateID(_In_ PWCHAR Id, _In_ BUS_QUERY_ID_TYPE QueryType)
Definition: devaction.c:122
PDRIVER_OBJECT DriverObject
Definition: devaction.c:76
LPTSTR ServiceName
Definition: ServiceMain.c:15
#define PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED
Definition: iotypes.h:1005
NTSTATUS IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject, IN PIO_STACK_LOCATION IoStackLocation, OUT PVOID *Information)
#define ASSERT(a)
Definition: mode.c:44
USHORT NTAPI IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
Definition: pnpmgr.c:411
NTSTATUS IopGetParentIdPrefix(PDEVICE_NODE DeviceNode, PUNICODE_STRING ParentIdPrefix)
Definition: pnpmgr.c:760
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define TAG_PNP_DEVACTION
Definition: tag.h:95
NTSTATUS CompletionStatus
Definition: iotypes.h:850
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define DNF_REENUMERATE
Definition: iotypes.h:173
PDEVICE_OBJECT IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
Definition: plugplay.c:122
NTSYSAPI NTSTATUS WINAPI RtlDuplicateUnicodeString(int, const UNICODE_STRING *, UNICODE_STRING *)
#define CM_PROB_DISABLED_SERVICE
Definition: cfg.h:62
#define ENUM_ROOT
Definition: io.h:53
static NTSTATUS PiCallDriverAddDevice(_In_ PDEVICE_NODE DeviceNode, _In_ BOOLEAN LoadDrivers)
Loads all drivers for a device node (actual service and filters) and calls their AddDevice routine.
Definition: devaction.c:595
#define ObDereferenceObject
Definition: obfuncs.h:203
static NTSTATUS PiAttachFilterDrivers(PLIST_ENTRY DriversListHead, PDEVICE_NODE DeviceNode, HANDLE EnumSubKey, HANDLE ClassKey, BOOLEAN Lower, BOOLEAN LoadDrivers)
Calls PiAttachFilterDriversCallback for filter drivers (if any)
Definition: devaction.c:532
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:311
#define PNP_DEVICE_NOT_DISABLEABLE
Definition: iotypes.h:1006
VOID FASTCALL KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, IN KIRQL OldIrql)
Definition: spinlock.c:154
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define REGSTR_VAL_CLASSGUID
Definition: regstr.h:422
static VOID IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
Definition: devaction.c:1759
_Must_inspect_result_ _In_ KTMOBJECT_TYPE QueryType
Definition: nttmapi.h:404
static NTSTATUS NTAPI PiAttachFilterDriversCallback(PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Ctx, PVOID EntryContext)
Loads and/or returns the driver associated with the registry entry if the driver is enabled....
Definition: devaction.c:363
struct _RTL_QUERY_REGISTRY_TABLE RTL_QUERY_REGISTRY_TABLE
PDEVICE_NODE PopSystemPowerDeviceNode
Definition: power.c:25
Definition: Node.h:9
static VOID NTAPI IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
Definition: devaction.c:1783
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
WORK_QUEUE_ITEM IopDeviceActionWorkItem
Definition: devaction.c:47
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
static VOID NTAPI PipDeviceActionWorker(_In_opt_ PVOID Context)
Definition: devaction.c:2537
#define IRP_MN_QUERY_BUS_INFORMATION
#define MAX_DEVICE_ID_LEN
Definition: devaction.c:40
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:240
static NTSTATUS PiUpdateDeviceState(_In_ PDEVICE_NODE DeviceNode)
Processes the IoInvalidateDeviceState request.
Definition: devaction.c:1516
unsigned char UCHAR
Definition: xmlstorage.h:181
BOOLEAN PnPBootDriversInitialized
Definition: pnpinit.c:27
NTSTATUS PiIrpQueryResources(_In_ PDEVICE_NODE DeviceNode, _Out_ PCM_RESOURCE_LIST *Resources)
Definition: pnpirp.c:201
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:792
#define DNF_DEVICE_GONE
Definition: iotypes.h:186
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
#define CM_PROB_DRIVER_FAILED_LOAD
Definition: cfg.h:69
#define RTL_REGISTRY_HANDLE
Definition: nt_native.h:168
#define DNF_LEGACY_DRIVER
Definition: iotypes.h:182
static NTSTATUS IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force)
_In_ PNDIS_STRING DeviceInstance
Definition: ndis.h:5202
GLenum GLsizei len
Definition: glext.h:6722
Definition: typedefs.h:119
#define PNP_DEVICE_FAILED
Definition: iotypes.h:1003
static const WCHAR Cleanup[]
Definition: register.c:80
VOID NTAPI IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
Definition: devaction.c:2203
int _cdecl swprintf(const WCHAR *,...)
KIRQL FASTCALL KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber)
Definition: spinlock.c:108
#define IopDeviceNodeHasFlag(DeviceNode, Flag)
Definition: io.h:164
#define REGSTR_KEY_DEVICE_PROPERTIES
Definition: regstr.h:752
#define MAX_SEPARATORS_INSTANCEID
Definition: devaction.c:41
#define CM_PROB_NEED_RESTART
Definition: cfg.h:44
* PDEVICE_CAPABILITIES
Definition: iotypes.h:965
UNICODE_STRING InstancePath
Definition: iotypes.h:858
#define MAXULONG
Definition: typedefs.h:251
static VOID IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
Definition: devaction.c:1742
KSPIN_LOCK IopDeviceTreeLock
Definition: devnode.c:19
PDRIVER_ADD_DEVICE AddDevice
Definition: iotypes.h:2220
static NTSTATUS NTAPI IopSendEject(IN PDEVICE_OBJECT DeviceObject)
Definition: devaction.c:2186
NTSTATUS NTAPI IopGetRegistryValue(IN HANDLE Handle, IN PWSTR ValueName, OUT PKEY_VALUE_FULL_INFORMATION *Information)
Definition: pnpmgr.c:1606
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
NTSTATUS NTAPI IopOpenRegistryKeyEx(PHANDLE KeyHandle, HANDLE ParentKey, PUNICODE_STRING Name, ACCESS_MASK DesiredAccess)
Definition: pnpmgr.c:1455
static VOID IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
Definition: devaction.c:1844
static NTSTATUS IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force)
Definition: devaction.c:1956
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS PiIrpQueryPnPDeviceState(_In_ PDEVICE_NODE DeviceNode, _Out_ PPNP_DEVICE_STATE DeviceState)
Definition: pnpirp.c:284
unsigned short USHORT
Definition: pedump.c:61
_In_ WDFIOTARGET _In_ _Strict_type_match_ WDF_IO_TARGET_SENT_IO_ACTION Action
Definition: wdfiotarget.h:506
#define DNF_RESOURCE_REQUIREMENTS_CHANGED
Definition: iotypes.h:180
static VOID ErrorExit(LPTSTR lpszMessage)
Definition: telnetd.c:647
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
PDEVICE_OBJECT NTAPI IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
Definition: device.c:1385
#define STATUS_PNP_REBOOT_REQUIRED
Definition: ntstatus.h:830
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define _Out_opt_
Definition: ms_sal.h:346
#define CM_PROB_DEVICE_NOT_THERE
Definition: cfg.h:54
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
#define IRP_MN_QUERY_DEVICE_RELATIONS
struct _DEVICE_NODE * Sibling
Definition: iotypes.h:839
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
static VOID IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
Definition: devaction.c:1826
#define DPRINT1
Definition: precomp.h:8
VOID PiNotifyTargetDeviceChange(_In_ LPCGUID Event, _In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PTARGET_DEVICE_CUSTOM_NOTIFICATION CustomNotification)
Delivers the event to all drivers subscribed to EventCategoryTargetDeviceChange PnP event.
Definition: pnpnotify.c:258
static VOID PiFakeResourceRebalance(_In_ PDEVICE_NODE DeviceNode)
Definition: devaction.c:2288
ERESOURCE IopDriverLoadResource
Definition: driver.c:19
VOID PiInsertDevNode(_In_ PDEVICE_NODE DeviceNode, _In_ PDEVICE_NODE ParentNode)
Definition: devnode.c:80
#define BOOLEAN
Definition: pedump.c:73
#define ObReferenceObject
Definition: obfuncs.h:204
static NTSTATUS PiStartDeviceFinal(_In_ PDEVICE_NODE DeviceNode)
Definition: devaction.c:1573
static NTSTATUS IopSetServiceEnumData(_In_ PDEVICE_NODE DeviceNode, _In_ HANDLE InstanceHandle)
Definition: devaction.c:1343
#define DNF_IDS_QUERIED
Definition: iotypes.h:175
#define FILE_DEVICE_ACPI
Definition: winioctl.h:156
NTSTATUS NTAPI IopAssignDeviceResources(IN PDEVICE_NODE DeviceNode)
Definition: pnpres.c:1116
BOOLEAN IopDeviceActionInProgress
Definition: devaction.c:48
#define CM_PROB_DRIVER_SERVICE_KEY_INVALID
Definition: cfg.h:70
ULONG ERESOURCE
Definition: env_spec_w32.h:594
static const WCHAR ServicesKeyName[]
Definition: devaction.c:51
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:598
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
signed int INT32
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define ULONG_PTR
Definition: config.h:101
char * cleanup(char *str)
Definition: wpickclick.c:99
NTSTATUS * CompletionStatus
Definition: devaction.c:60
#define DNF_ENUMERATED
Definition: iotypes.h:174
VOID PiQueueDeviceAction(_In_ PDEVICE_OBJECT DeviceObject, _In_ DEVICE_ACTION Action, _In_opt_ PKEVENT CompletionEvent, _Out_opt_ NTSTATUS *CompletionStatus)
Queue a device operation to a worker thread.
Definition: devaction.c:2655
const char * PCSTR
Definition: typedefs.h:52
#define STATUS_SUCCESS
Definition: shellext.h:65
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1060
#define CM_PROB_FAILED_ADD
Definition: cfg.h:61
#define REG_NONE
Definition: nt_native.h:1492
#define DPRINT
Definition: sndvol32.h:71
_In_ WDFDEVICE _In_ PPNP_BUS_INFORMATION BusInformation
Definition: wdfdevice.h:3912
PDEVICE_NODE IopRootDeviceNode
Definition: devnode.c:18
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
#define RTL_QUERY_REGISTRY_REQUIRED
Definition: nt_native.h:132
#define REG_DWORD
Definition: sdbapi.c:596
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define VPB_MOUNTED
Definition: iotypes.h:1807
NTSTATUS PiIrpQueryDeviceRelations(_In_ PDEVICE_NODE DeviceNode, _In_ DEVICE_RELATION_TYPE Type)
Definition: pnpirp.c:176
NTSTATUS NTAPI ObReferenceObjectByName(IN PUNICODE_STRING ObjectPath, IN ULONG Attributes, IN PACCESS_STATE PassedAccessState, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext, OUT PVOID *ObjectPtr)
Definition: obref.c:409
static SERVICE_STATUS status
Definition: service.c:31
#define KEY_CREATE_SUB_KEY
Definition: nt_native.h:1018
NTSTATUS NTAPI IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject, IN PIO_STATUS_BLOCK IoStatusBlock, IN UCHAR MinorFunction, IN PIO_STACK_LOCATION Stack)
VOID NTAPI IoReleaseVpbSpinLock(IN KIRQL Irql)
Definition: volume.c:1215
#define MAX_SEPARATORS_DEVICEID
Definition: devaction.c:42
struct _ADD_DEV_DRIVERS_LIST * PADD_DEV_DRIVERS_LIST
#define CM_PROB_REGISTRY
Definition: cfg.h:49
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
struct _DEVICE_ACTION_REQUEST * PDEVICE_ACTION_REQUEST
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
ADD_DEV_DRIVER_TYPE DriverType
Definition: devaction.c:82
VOID PiSetDevNodeText(_In_ PDEVICE_NODE DeviceNode, _In_ HANDLE InstanceKey)
Sets the DeviceNode's DeviceDesc and LocationInformation registry values.
Definition: devaction.c:1089
PDEVICE_NODE FASTCALL IopGetDeviceNode(IN PDEVICE_OBJECT DeviceObject)
NTSTATUS IopSetDeviceInstanceData(HANDLE InstanceKey, PDEVICE_NODE DeviceNode)
Definition: pnpmgr.c:606
#define IRP_MN_QUERY_CAPABILITIES
PCONFIGURATION_COMPONENT_DATA RootNode
Definition: macharm.c:19
_Inout_ PVCB _In_ BOOLEAN Force
Definition: cdprocs.h:1415
#define PAGED_CODE()
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
#define REG_SZ
Definition: layer.c:22
Definition: ps.c:97
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:271