ReactOS  0.4.15-dev-2985-g54406bf
fxpkgpnp.cpp
Go to the documentation of this file.
1 /*++
2 
3 
4 Copyright (c) Microsoft. All rights reserved.
5 
6 Module Name:
7 
8  FxPkgPnp.cpp
9 
10 Abstract:
11 
12  This module implements the pnp IRP handlers for the driver framework.
13 
14 Author:
15 
16 
17 
18 Environment:
19 
20  Both kernel and user mode
21 
22 Revision History:
23 
24 
25 
26 
27 
28 --*/
29 
30 #include "pnppriv.hpp"
31 
32 #include <initguid.h>
33 #include <wdmguid.h>
34 
35 extern "C" {
36 
37 #if defined(EVENT_TRACING)
38 #include "FxPkgPnp.tmh"
39 #endif
40 
41 }
42 
43 /* dc7a8e51-49b3-4a3a-9e81-625205e7d729 */
45  0xdc7a8e51, 0x49b3, 0x4a3a, { 0x9e, 0x81, 0x62, 0x52, 0x05, 0xe7, 0xd7, 0x29 }
46 };
47 
49  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
52  ) :
53  FxPackage(FxDriverGlobals, Device, Type)
54 {
55  ULONG i;
56 
60 
61  //
62  // Initialize the structures to the default state and then override the
63  // non WDF std default values to the unsupported / off values.
64  //
72 
82  ;
83 
84  m_PnpCapsAddress = (ULONG) -1;
85  m_PnpCapsUINumber = (ULONG) -1;
86 
95  ;
96 
99 
100  m_PowerCaps.D1Latency = (ULONG) -1;
101  m_PowerCaps.D2Latency = (ULONG) -1;
102  m_PowerCaps.D3Latency = (ULONG) -1;
103 
104  m_PowerCaps.States = 0;
105  for (i = 0; i < PowerSystemMaximum; i++) {
107  }
108 
112 
123 
124  m_DeviceStopCount = 0;
128 
129  //
130  // We only set the pending child count to 1 once we know we have successfully
131  // created an FxDevice and initialized it fully. If we delete an FxDevice
132  // which is half baked, it cannot have any FxChildLists which have any
133  // pending children on them.
134  //
136 
138 
141 
142  m_Failed = FALSE;
144 
148 
153 
157 
159 
160  m_EnumInfo = NULL;
161 
162  m_Resources = NULL;
164 
172 
176 
178 
179 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
180  //
181  // Interrupt APIs for Vista and forward
182  //
185 
186  //
187  // Interrupt APIs for Windows 8 and forward
188  //
191 
192 #endif
193 
195 
197 }
198 
200 {
202 
204 
205  //
206  // We should either have zero pending children or we never made it out of
207  // the init state during a failed WDFDEVICE create or failed EvtDriverDeviceAdd
208  //
211 
212 
214  while (ple != NULL) {
215  FxDeviceInterface* pDI;
216 
218 
219  //
220  // Advance to the next before deleting the current
221  //
222  ple = ple->Next;
223 
224  //
225  // No longer in the list
226  //
227  pDI->m_Entry.Next = NULL;
228 
229  delete pDI;
230  }
232 
233  if (m_DmaEnablerList != NULL) {
234  delete m_DmaEnablerList;
236  }
237 
238  if (m_RemovalDeviceList != NULL) {
239  delete m_RemovalDeviceList;
241  }
242 
246  }
247 
248  if (m_PnpStateCallbacks != NULL) {
249  delete m_PnpStateCallbacks;
250  }
251 
252  if (m_PowerStateCallbacks != NULL) {
253  delete m_PowerStateCallbacks;
254  }
255 
258  }
259 
260  if (m_SelfManagedIoMachine != NULL) {
261  delete m_SelfManagedIoMachine;
263  }
264 
265  if (m_EnumInfo != NULL) {
266  delete m_EnumInfo;
267  m_EnumInfo = NULL;
268  }
269 
270  if (m_Resources != NULL) {
271  m_Resources->RELEASE(this);
272  m_Resources = NULL;
273  }
274 
275  if (m_ResourcesRaw != NULL) {
276  m_ResourcesRaw->RELEASE(this);
278  }
279 
281 }
282 
283 BOOLEAN
285  VOID
286  )
287 {
289 
290  //
291  // All of the interrupts were freed during this object's dispose path. This
292  // is because all of the interrupts were attached as children to this object.
293  //
294  // It is safe to just reinitialize the list head.
295  //
297 
298  m_QueryInterfaceLock.AcquireLock(GetDriverGlobals());
299 
300  //
301  // A derived class can insert an embedded FxQueryInterface into the QI list,
302  // so clear out the list before the destructor chain runs. (The derived
303  // class will be destructed first, as such, the embedded FxQueryInterface
304  // will also destruct first and complain it is still in a list.
305  //
307 
308  //
309  // Clear out the head while holding the lock so that we synchronize against
310  // processing a QI while deleting the list.
311  //
313 
314  m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals());
315 
316  while (ple != NULL) {
317  FxQueryInterface* pQI;
318 
320 
321  //
322  // Advance before we potentiall free the structure
323  //
324  ple = ple->Next;
325 
326  //
327  // FxQueryInterface's destructor requires Next be NULL
328  //
329  pQI->m_Entry.Next = NULL;
330 
331  if (pQI->m_EmbeddedInterface == FALSE) {
332  delete pQI;
333  }
334  }
335 
336 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
338 #endif
339 
340  //
341  // Call up the hierarchy
342  //
343  return FxPackage::Dispose(); // __super call
344 }
345 
346 
348 NTSTATUS
351  )
352 
353 /*++
354 
355 Routine Description:
356 
357  This function initializes state associated with an instance of FxPkgPnp.
358  This differs from the constructor because it can do operations which
359  will fail, and can return failure. (Constructors can't fail, they can
360  only throw exceptions, which we can't deal with in this kernel mode
361  environment.)
362 
363 Arguments:
364 
365  DeviceInit - Struct that the driver initialized that contains defaults.
366 
367 Returns:
368 
369  NTSTATUS
370 
371 --*/
372 
373 {
376 
378 
379  m_ReleaseHardwareAfterDescendantsOnFailure = (DeviceInit->ReleaseHardwareOrderOnFailure ==
381 
383  if (!NT_SUCCESS(status)) {
385  TRACINGPNP,
386  "Could not initialize QueryInterfaceLock for "
387  "WDFDEVICE %p, %!STATUS!",
389  return status;
390  }
391 
393  if (!NT_SUCCESS(status)) {
395  TRACINGPNP,
396  "Could not initialize DeviceInterfaceLock for "
397  "WDFDEVICE %p, %!STATUS!",
399  return status;
400  }
401 
402  //
403  // Initialize preallocated events for UM
404  // (For KM, events allocated on stack are used since event initialization
405  // doesn't fail in KM)
406  //
407 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
408 
410  if (!NT_SUCCESS(status)) {
412  TRACINGPNP,
413  "Could not initialize cleanup event for "
414  "WDFDEVICE %p, %!STATUS!",
416  return status;
417  }
418 
420  if (!NT_SUCCESS(status)) {
422  TRACINGPNP,
423  "Could not initialize remove event for "
424  "WDFDEVICE %p, %!STATUS!",
426  return status;
427  }
428 #endif
429 
430  if (DeviceInit->IsPwrPolOwner()) {
433 
436  }
437 
439  if (!NT_SUCCESS(status)) {
440  return status;
441  }
442 
443 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
445 #endif
446  }
447 
448  //
449  // we will change the access flags on the object later on when we build up
450  // the list from the wdm resources
451  //
454  m_Device,
457  if (!NT_SUCCESS(status)) {
458  return status;
459  }
460 
463  m_Device);
464 
465  //
466  // This should never fail
467  //
469  if (!NT_SUCCESS(status)) {
471  m_Resources = NULL;
472  return status;
473  }
474 
475  m_Resources->ADDREF(this);
476 
477  //
478  // we will change the access flags on the object later on when we build up
479  // the list from the wdm resources
480  //
483  m_Device,
486  if (!NT_SUCCESS(status)) {
487  return status;
488  }
489 
492  m_Device);
493 
494  //
495  // This should never fail
496  //
498  if (!NT_SUCCESS(status)) {
501  return status;
502  }
503 
504  m_ResourcesRaw->ADDREF(this);
505 
506  status = RegisterCallbacks(&DeviceInit->PnpPower.PnpPowerEventCallbacks);
507  if (!NT_SUCCESS(status)) {
508  return status;
509  }
510 
511  if (IsPowerPolicyOwner()) {
512  RegisterPowerPolicyCallbacks(&DeviceInit->PnpPower.PolicyEventCallbacks);
513  }
514 
515  return status;
516 }
517 
519 NTSTATUS
521  __in MdIrp Irp
522  )
523 
524 /*++
525 
526 Routine Description:
527 
528  This is the main dispatch handler for the pnp package. This method is
529  called by the framework manager when a PNP or Power IRP enters the driver.
530  This function will dispatch the IRP to a function designed to handle the
531  specific IRP.
532 
533 Arguments:
534 
535  Device - a pointer to the FxDevice
536 
537  Irp - a pointer to the FxIrp
538 
539 Returns:
540 
541  NTSTATUS
542 
543 --*/
544 
545 {
547  FxIrp irp(Irp);
548 
549 #if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
551 #endif
552 
553  if (irp.GetMajorFunction() == IRP_MJ_PNP) {
554 
555  switch (irp.GetMinorFunction()) {
556  case IRP_MN_START_DEVICE:
560  case IRP_MN_STOP_DEVICE:
564  case IRP_MN_EJECT:
568  "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p",
569  m_Device->GetHandle(),
572  break;
573 
577  "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! "
578  "type %!DEVICE_RELATION_TYPE! IRP 0x%p",
579  m_Device->GetHandle(),
583  break;
584 
585  default:
588  "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p",
589  m_Device->GetHandle(),
592  break;
593  }
594 
596  status = (*GetDispatchPnp()[irp.GetMinorFunction()])(this, &irp);
597  }
598  else {
599  //
600  // For Pnp IRPs we don't understand, just forget about them
601  //
603  }
604  }
605  else {
606  //
607  // If this isn't a PnP Irp, it must be a power irp.
608  //
609  switch (irp.GetMinorFunction()) {
610  case IRP_MN_WAIT_WAKE:
611  case IRP_MN_SET_POWER:
615  "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! "
616  "IRP 0x%p for %!SYSTEM_POWER_STATE! (S%d)",
617  m_Device->GetHandle(),
622  }
623  else {
626  "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! "
627  "IRP 0x%p for %!DEVICE_POWER_STATE!",
628  m_Device->GetHandle(),
632  }
633  break;
634 
635  default:
638  "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! IRP 0x%p",
639  m_Device->GetHandle(),
642  break;
643  }
644 
646 
648  status = (*GetDispatchPower()[irp.GetMinorFunction()])(this, &irp);
649  }
650  else {
651  //
652  // For Power IRPs we don't understand, just forget about them
653  //
655  }
656  }
657 
658  return status;
659 }
660 
663  __in PNP_DEVICE_STATE PnpDeviceState
664  )
665 
666 /*++
667 
668 Routine Description:
669 
670  This function handled IRP_MN_QUERY_DEVICE_STATE. Most of the bits are
671  just copied from internal Framework state.
672 
673 Arguments:
674 
675  PnpDeviceState - Bitfield that will be returned to the sender of the IRP.
676 
677 Returns:
678 
679  NTSTATUS
680 
681 --*/
682 
683 {
684  LONG state;
685 
687 
688  //
689  // Return device state set by driver.
690  //
691  SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
693  state,
694  Disabled);
695  SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
697  state,
698  DontDisplayInUI);
699  SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
701  state,
702  Failed);
703  SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
705  state,
706  NotDisableable);
707  SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
709  state,
710  Removed);
711  SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState,
713  state,
714  ResourcesChanged);
715 
717  LONG caps;
718 
719  //
720  // Mask off all caps except for NoDispalyInUI
721  //
723 
724  //
725  // If the driver didn't specify pnp state, see if they specified no
726  // display as a capability. For raw PDOs and just usability, it is not
727  // always clear to the driver writer that they must set both the pnp cap
728  // and the pnp state for the no display in UI property to stick after
729  // the device has been started.
730  //
731  if (caps == FxPnpCapNoDisplayInUITrue) {
732  PnpDeviceState |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
733  }
734  else if (caps == FxPnpCapNoDisplayInUIFalse) {
735  PnpDeviceState &= ~PNP_DEVICE_DONT_DISPLAY_IN_UI;
736  }
737  }
738 
739  //
740  // Return device state maintained by frameworks.
741  //
742  if (IsInSpecialUse()) {
743  PnpDeviceState |= PNP_DEVICE_NOT_DISABLEABLE;
744  }
745 
746  //
747  // If there is an internal failure, then indicate that up to pnp.
748  //
749  if (m_InternalFailure || m_Failed) {
750  PnpDeviceState |= PNP_DEVICE_FAILED;
751  }
752 
753  return PnpDeviceState;
754 }
755 
757 NTSTATUS
759  __inout FxIrp* Irp
760  )
761 /*++
762 
763 Routine Description:
764  Handles a query device relations for the bus relations type (all other types
765  are handled by HandleQueryDeviceRelations). This function will call into
766  each of the device's FxChildList objects to process the request.
767 
768 Arguments:
769  Irp - the request contain the query device relations
770 
771 Return Value:
772  NTSTATUS
773 
774  --*/
775 {
777  PDEVICE_RELATIONS pRelations;
779  NTSTATUS status, listStatus;
780  BOOLEAN changed;
781 
782  //
783  // Before we do anything, callback into the driver
784  //
786 
787  //
788  // Default to success unless list processing fails
789  //
791 
792  //
793  // Keep track of changes made by any list object. If anything changes,
794  // remember it for post-processing.
795  //
796  changed = FALSE;
797 
798  pRelations = (PDEVICE_RELATIONS) Irp->GetInformation();
799 
800  if (m_EnumInfo != NULL) {
802 
803  pList->LockForEnum(GetDriverGlobals());
804  }
805  else {
806  pList = NULL;
807  }
808 
809  ple = NULL;
810  while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) {
811  FxChildList* pChildList;
812 
813  pChildList = FxChildList::_FromEntry(ple);
814 
815  //
816  // ProcessBusRelations will free and reallocate pRelations if necessary
817  //
818  listStatus = pChildList->ProcessBusRelations(&pRelations);
819 
820  //
821  // STATUS_NOT_SUPPORTED is a special value. It indicates that the call
822  // to ProcessBusRelations did not modify pRelations in any way.
823  //
824  if (listStatus == STATUS_NOT_SUPPORTED) {
825  continue;
826  }
827 
828 
829  if (!NT_SUCCESS(listStatus)) {
832  "WDFDEVICE %p, WDFCHILDLIST %p returned %!STATUS! from "
833  "processing bus relations",
834  m_Device->GetHandle(), pChildList->GetHandle(), listStatus);
835  status = listStatus;
836  break;
837  }
838 
839  //
840  // We updated pRelations, change the status later
841  //
842  changed = TRUE;
843  }
844 
845  //
846  // By checking for NT_SUCCESS(status) below we account for
847  // both the cases - list changed, as well as list unchanged but possibly
848  // children being reported missing (that doesn't involve list change).
849  //
850  if (NT_SUCCESS(status)) {
851 
852  ple = NULL;
853  while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) {
854  FxChildList* pChildList;
855 
856  pChildList = FxChildList::_FromEntry(ple);
857 
858  //
859  // invoke the ReportedMissing callback for for children that are
860  // being reporte missing
861  //
862  pChildList->InvokeReportedMissingCallback();
863  }
864  }
865 
866  if (pList != NULL) {
867  pList->UnlockFromEnum(GetDriverGlobals());
868  }
869 
870  if (NT_SUCCESS(status) && changed == FALSE) {
871  //
872  // Went through the entire list of FxChildList objects, but no object
873  // modified the pRelations, so restore the caller's NTSTATUS.
874  //
875  status = Irp->GetStatus();
876  }
877 
878  //
879  // Re-set the relations into the structure so that any changes that any call
880  // to FxChildList::ProcessBusRelations takes effect and is reported.
881  //
882  Irp->SetInformation((ULONG_PTR) pRelations);
883  Irp->SetStatus(status);
884 
887  "WDFDEVICE %p, returning %!STATUS! from processing bus relations",
889  );
890 
891  if (NT_SUCCESS(status) && pRelations != NULL) {
892  ULONG i;
893 
896  "WDFDEVICE %p returning %d devices in relations %p",
897  m_Device->GetHandle(), pRelations->Count, pRelations
898  );
899 
900  //
901  // Try to not consume an IFR entry per DO reported. Instead, report up
902  // to 4 at a time.
903  //
904  for (i = 0; i < pRelations->Count && GetDriverGlobals()->FxVerboseOn; i += 4) {
905  if (i + 3 < pRelations->Count) {
908  "PDO %p PDO %p PDO %p PDO %p",
909  pRelations->Objects[i],
910  pRelations->Objects[i+1],
911  pRelations->Objects[i+2],
912  pRelations->Objects[i+3]
913  );
914  }
915  else if (i + 2 < pRelations->Count) {
918  "PDO %p PDO %p PDO %p",
919  pRelations->Objects[i],
920  pRelations->Objects[i+1],
921  pRelations->Objects[i+2]
922  );
923  }
924  else if (i + 1 < pRelations->Count) {
927  "PDO %p PDO %p",
928  pRelations->Objects[i],
929  pRelations->Objects[i+1]
930  );
931  }
932  else {
935  "PDO %p",
936  pRelations->Objects[i]
937  );
938  }
939  }
940  }
941 
942  return status;
943 }
944 
946 NTSTATUS
948  __inout FxIrp* Irp
949  )
950 {
952 
953  //
954  // Probably is a better check then this to see if the driver set the bus
955  // information
956  //
957  if (m_BusInformation.BusTypeGuid.Data1 != 0x0) {
958  PPNP_BUS_INFORMATION pBusInformation;
960 
964 
965  if (pBusInformation != NULL) {
966  //
967  // Initialize the PNP_BUS_INFORMATION structure with the data
968  // from PDO properties.
969  //
970  RtlCopyMemory(pBusInformation,
972  sizeof(PNP_BUS_INFORMATION));
973 
974  Irp->SetInformation((ULONG_PTR) pBusInformation);
976  }
977  else {
978  Irp->SetInformation(NULL);
980 
983  "WDFDEVICE %p could not allocate PNP_BUS_INFORMATION string, "
984  " %!STATUS!", m_Device->GetHandle(), status);
985  }
986  }
987  else {
988  status = Irp->GetStatus();
989  }
990 
991  return status;
992 }
993 
995 NTSTATUS
997  __inout FxIrp* Irp,
999  )
1000 /*++
1001 
1002 Routine Description:
1003  Handles the query device relations request for all relation types *except*
1004  for bus relations (HandleQueryBusRelations handles that type exclusively).
1005 
1006  This function will allocate a PDEVICE_RELATIONS structure if the passed in
1007  FxRelatedDeviceList contains any devices to add to the relations list.
1008 
1009 Arguments:
1010  Irp - the request
1011 
1012  List - list containing devices to report in the relations
1013 
1014 Return Value:
1015  NTSTATUS
1016 
1017  --*/
1018 {
1019  PDEVICE_RELATIONS pPriorRelations, pNewRelations;
1022  ULONG count;
1023  size_t size;
1024  NTSTATUS status;
1025  BOOLEAN retry;
1027 
1028  if (List == NULL) {
1029  //
1030  // Indicate that we didn't modify the irp at all since we have no list
1031  //
1032  return STATUS_NOT_SUPPORTED;
1033  }
1034 
1036  type = Irp->GetParameterQDRType();
1038 
1039  //
1040  // Notify driver that he should re-scan for device relations.
1041  //
1043 
1044  pPriorRelations = (PDEVICE_RELATIONS) Irp->GetInformation();
1045  retry = FALSE;
1046 
1047  count = 0;
1048 
1049  List->LockForEnum(pFxDriverGlobals);
1050 
1051  //
1052  // Count how many entries there are in the list
1053  //
1054  for (entry = NULL; (entry = List->GetNextEntry(entry)) != NULL; count++) {
1055  DO_NOTHING();
1056  }
1057 
1058  //
1059  // If we have
1060  // 1) no devices in the list AND
1061  // a) we have nothing to report OR
1062  // b) we have something to report and there are previous relations (which
1063  // if left unchanged will be used to report our missing devices)
1064  //
1065  // THEN we have nothing else to do, just return
1066  //
1067  if (count == 0 &&
1068  (List->m_NeedReportMissing == 0 || pPriorRelations != NULL)) {
1069  List->UnlockFromEnum(pFxDriverGlobals);
1070  return STATUS_NOT_SUPPORTED;
1071  }
1072 
1073  if (pPriorRelations != NULL) {
1074  //
1075  // Looks like another driver in the stack has already added some
1076  // entries. Make sure we allocate space for these additional entries.
1077  //
1078  count += pPriorRelations->Count;
1079  }
1080 
1081  //
1082  // Allocate space for the device relations structure (which includes
1083  // space for one PDEVICE_OBJECT, and then allocate enough additional
1084  // space for the extra PDEVICE_OBJECTS we need.
1085  //
1086  // (While no FxChildList objects are used in this function, this static
1087  // function from the class computes what we need.)
1088  //
1090 
1093 
1094  if (pNewRelations == NULL) {
1095  //
1096  // Dereference any previously reported relations before exiting. They
1097  // are dereferenced here because the PNP manager will see error and not
1098  // do anything while the driver which added these objects expects the
1099  // pnp manager to do the dereference. Since this device is changing the
1100  // status, it must act like the pnp manager.
1101  //
1102  if (pPriorRelations != NULL) {
1103  ULONG i;
1104 
1105  for (i = 0; i < pPriorRelations->Count; i++) {
1106  Mx::MxDereferenceObject(pPriorRelations->Objects[i]);
1107  }
1108  }
1109 
1110  if (List->IncrementRetries() < 3) {
1111  retry = TRUE;
1112  }
1113 
1115 
1118  "WDFDEVICE %p could not allocate device relations for type %d string, "
1119  " %!STATUS!", m_Device->GetHandle(), type, status);
1120 
1121  goto Done;
1122  }
1123 
1124  RtlZeroMemory(pNewRelations, size);
1125 
1126  //
1127  // If there was an existing device relations structure, copy
1128  // the entries to the new structure.
1129  //
1130  if (pPriorRelations != NULL && pPriorRelations->Count > 0) {
1131  RtlCopyMemory(
1132  pNewRelations,
1133  pPriorRelations,
1134  FxChildList::_ComputeRelationsSize(pPriorRelations->Count)
1135  );
1136  }
1137 
1138  //
1139  // Walk the list and return the relations here
1140  //
1141  for (entry = NULL;
1142  (entry = List->GetNextEntry(entry)) != NULL;
1143  pNewRelations->Count++) {
1144  MdDeviceObject pdo;
1145 
1146  pdo = entry->GetDevice();
1147 
1148  if (entry->m_State == RelatedDeviceStateNeedsReportPresent) {
1150  }
1151 
1152  //
1153  // Add it to the DEVICE_RELATIONS structure. Pnp dictates that each
1154  // PDO in the list be referenced.
1155  //
1156  pNewRelations->Objects[pNewRelations->Count] = reinterpret_cast<PDEVICE_OBJECT>(pdo);
1157  Mx::MxReferenceObject(pdo);
1158  }
1159 
1160 Done:
1161  if (NT_SUCCESS(status)) {
1162  List->ZeroRetries();
1163  }
1164 
1165  List->UnlockFromEnum(GetDriverGlobals());
1166 
1167  if (pPriorRelations != NULL) {
1168  MxMemory::MxFreePool(pPriorRelations);
1169  }
1170 
1171  if (retry) {
1172  MxDeviceObject physicalDeviceObject(
1174  );
1175 
1176  physicalDeviceObject.InvalidateDeviceRelations(type);
1177  }
1178 
1179  Irp->SetStatus(status);
1180  Irp->SetInformation((ULONG_PTR) pNewRelations);
1181 
1182  return status;
1183 }
1184 
1186 NTSTATUS
1188  VOID
1189  )
1190 
1191 /*++
1192 
1193 Routine Description:
1194 
1195  This function does any initialization to this object which must be done
1196  after the underlying device object has been attached to the device stack,
1197  i.e. you can send IRPs down this stack now.
1198 
1199 Arguments:
1200 
1201  none
1202 
1203 Returns:
1204 
1205  NTSTATUS
1206 
1207 --*/
1208 
1209 {
1210  NTSTATUS status;
1211 
1213  if (!NT_SUCCESS(status)) {
1215  "PnP State Machine init failed, %!STATUS!",
1216  status);
1217  return status;
1218  }
1219 
1221  if (!NT_SUCCESS(status)) {
1223  "Power State Machine init failed, %!STATUS!",
1224  status);
1225  return status;
1226  }
1227 
1229  if (!NT_SUCCESS(status)) {
1231  "Power Policy State Machine init failed, %!STATUS!",
1232  status);
1233  return status;
1234  }
1235 
1236  return status;
1237 }
1238 
1239 VOID
1242  )
1243 /*++
1244 
1245 Routine Description:
1246  Finish initializing the object. All initialization up until this point
1247  could fail. This function cannot fail, so all it can do is assign field
1248  values and take allocations from DeviceInit.
1249 
1250 Arguments:
1251  DeviceInit - device initialization structure that the driver writer has
1252  initialized
1253 
1254 Return Value:
1255  None
1256 
1257  --*/
1258 
1259 {
1260  //
1261  // Reassign the state callback arrays away from the init struct.
1262  // Set the init field to NULL so that it does not attempt to free the array
1263  // when it is destroyed.
1264  //
1265  m_PnpStateCallbacks = DeviceInit->PnpPower.PnpStateCallbacks;
1266  DeviceInit->PnpPower.PnpStateCallbacks = NULL;
1267 
1268  m_PowerStateCallbacks = DeviceInit->PnpPower.PowerStateCallbacks;
1269  DeviceInit->PnpPower.PowerStateCallbacks = NULL;
1270 
1271  m_PowerPolicyStateCallbacks = DeviceInit->PnpPower.PowerPolicyStateCallbacks;
1272  DeviceInit->PnpPower.PowerPolicyStateCallbacks = NULL;
1273 
1274  //
1275  // Bias the count towards one so that we can optimize the synchronous
1276  // cleanup case when the device is being destroyed.
1277  //
1278  m_PendingChildCount = 1;
1279 
1280  //
1281  // Now "Add" this device in the terms that the PnP state machine uses. This
1282  // will be in the context of an actual AddDevice function for FDOs, and
1283  // something very much like it for PDOs.
1284  //
1285  // Important that the posting of the event is after setting of the state
1286  // callback arrays so that we can guarantee that any state transition
1287  // callback will be made.
1288  //
1290 }
1291 
1292 VOID
1294  VOID
1295  )
1296 {
1299  "WDFDEVICE %p, !devobj %p processing delayed deletion from pnp state "
1300  "machine", m_Device->GetHandle(), m_Device->GetDeviceObject());
1301 
1303  DeleteDevice();
1304 }
1305 
1306 VOID
1310  )
1311 
1312 /*++
1313 
1314 Routine Description:
1315 
1316  This function marks the device as capable of handling the paging path,
1317  hibernation or crashdumps. Any device that is necessary for one of these
1318  three things will get notification. It is then responsible for forwarding
1319  the notification to its parent. The Framework handles that. This
1320  function just allows a driver to tell the Framework how to respond.
1321 
1322 
1323 Arguments:
1324 
1325  FileType - identifies which of the special paths the device is in
1326  Supported - Yes or No
1327 
1328 Returns:
1329 
1330  void
1331 
1332 --*/
1333 
1334 {
1335  switch (FileType) {
1336  case WdfSpecialFilePaging:
1338  case WdfSpecialFileDump:
1339  case WdfSpecialFileBoot:
1341  break;
1342 
1343  default:
1345  "Invalid special file type %x", FileType);
1346  }
1347 }
1348 
1350 NTSTATUS
1353  __inout FxIrp* Irp
1354  )
1355 
1356 /*++
1357 
1358 Routine Description:
1359 
1360  This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting
1361  a direct-call table from some driver in a device stack. In some cases, the
1362  right response is to turn around and send a similar query to the device's
1363  parent. This function does that.
1364 
1365 
1366 Arguments:
1367 
1368  Device - This WDFDEVICE.
1369  Irp - The IRP that was sent to us.
1370 
1371 Returns:
1372 
1373  NTSTATUS
1374 
1375 --*/
1376 
1377 {
1378  MdIrp pFwdIrp;
1379  NTSTATUS status;
1380  NTSTATUS prevStatus;
1382 
1383  prevStatus = Irp->GetStatus();
1384 
1385 
1386 
1387 
1388 
1389 
1390 
1391 
1392 
1393 
1394 
1395 
1396  pTopOfStack.SetObject(Device->m_ParentDevice->GetAttachedDeviceReference());
1397 
1398  pFwdIrp = FxIrp::AllocateIrp(pTopOfStack.GetStackSize());
1399 
1400  if (pFwdIrp != NULL) {
1401  FxAutoIrp fxFwdIrp(pFwdIrp);
1402 
1403  //
1404  // The worker routine copies stack parameters to forward-Irp, sends it
1405  // down the stack synchronously, then copies back the stack parameters
1406  // from forward-irp to original-irp
1407  //
1408  PnpPassThroughQIWorker(&pTopOfStack, Irp, &fxFwdIrp);
1409 
1410  if (fxFwdIrp.GetStatus() != STATUS_NOT_SUPPORTED) {
1411  status = fxFwdIrp.GetStatus();
1412  }
1413  else {
1414  status = prevStatus;
1415  }
1416 
1417  Irp->SetStatus(status);
1418  Irp->SetInformation(fxFwdIrp.GetInformation());
1419  }
1420  else {
1422 
1424  Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1425  "WDFDEVICE %p could not allocate IRP to send QI to parent !devobj "
1426  "%p, %!STATUS!", Device->GetHandle(), pTopOfStack.GetObject(),
1427  status);
1428  }
1429 
1430  pTopOfStack.DereferenceObject();
1431 
1432  return status;
1433 }
1434 
1436 NTSTATUS
1438  __inout FxIrp* Irp,
1440  )
1441 {
1442  NTSTATUS status;
1443 
1444  *CompleteRequest = TRUE;
1445 
1446  //
1447  // Send the request down the stack first. If someone lower handles it
1448  // or failed trying to, just return their status
1449  //
1451 
1453  //
1454  // Success or failure trying to handle it
1455  //
1456  return status;
1457  }
1458 
1459  //
1460  // The semantic of this QI is that it sent down while processing start or
1461  // a device usage notification on the way *up* the stack. That means that
1462  // by the time the QI gets to the lower part of the stack, the power thread
1463  // will have already been allocated and exported.
1464  //
1466 
1467  if (Irp->GetParameterQueryInterfaceVersion() == 1 &&
1468  Irp->GetParameterQueryInterfaceSize() >=
1470  //
1471  // Expose the interface to the requesting driver.
1472  //
1474 
1476 
1477  //
1478  // Caller assumes a reference has been taken.
1479  //
1482  );
1483  }
1484  else {
1486  }
1487 
1488  return status;
1489 }
1490 
1492 NTSTATUS
1494  __inout FxIrp* Irp,
1496  )
1497 
1498 /*++
1499 
1500 Routine Description:
1501 
1502  This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting
1503  a direct-call table from some driver in a device stack. This function
1504  looks into a list of interfaces that the driver has registered and, if
1505  the interface that is being sought is present, it answers the IRP.
1506 
1507 Arguments:
1508 
1509  Irp - The IRP that was sent to us.
1510  CompleteRequest - tells the caller whether the IRP should be completed
1511 
1512 Returns:
1513 
1514  NTSTATUS
1515 
1516 --*/
1517 
1518 {
1520  const GUID* pInterfaceType;
1522  FxQueryInterface *pQI;
1523  PVOID pFound;
1524  PINTERFACE pExposedInterface;
1525  PVOID pExposedInterfaceSpecificData;
1526  BOOLEAN sendToParent;
1527 
1528  NTSTATUS status;
1529 
1531 
1532  pFound = NULL;
1533  pQI = NULL;
1534  pExposedInterface = NULL;
1535  pExposedInterfaceSpecificData = NULL;
1536  sendToParent = FALSE;
1537 
1538  pInterfaceType = Irp->GetParameterQueryInterfaceType();
1539  //
1540  // The power thread is special cased because it has a different semantic
1541  // then the usual QI irp that we expose to the driver writer. In this case,
1542  // we want to fill in the interface if the lower stack does not support it.
1543  //
1544  if (FxIsEqualGuid(pInterfaceType, &GUID_POWER_THREAD_INTERFACE)) {
1546  }
1547  else if (FxIsEqualGuid(pInterfaceType, &GUID_REENUMERATE_SELF_INTERFACE_STANDARD)) {
1548  if (m_Device->IsPdo()) {
1549  return ((FxPkgPdo*) this)->HandleQueryInterfaceForReenumerate(
1550  Irp, CompleteRequest);
1551  }
1552  }
1553 
1554  status = Irp->GetStatus();
1555 
1556  //
1557  // Walk the interface collection and return the appropriate interface.
1558  //
1559  m_QueryInterfaceLock.AcquireLock(GetDriverGlobals());
1560 
1561  for (ple = m_QueryInterfaceHead.Next; ple != NULL; ple = ple->Next) {
1563 
1564  if (FxIsEqualGuid(Irp->GetParameterQueryInterfaceType(),
1565  &pQI->m_InterfaceType)) {
1566 
1567  pExposedInterface = Irp->GetParameterQueryInterfaceInterface();
1568  pExposedInterfaceSpecificData =
1569  Irp->GetParameterQueryInterfaceInterfaceSpecificData();
1570 
1571  if (pQI->m_Interface != NULL) {
1572  //
1573  // NOTE: If a driver has exposed the same interface GUID with
1574  // different sizes as a ways of versioning, then the driver
1575  // writer can specify the minimum size and version number
1576  // and then fill in the remaining fields in the callback
1577  // below.
1578  //
1579  if (pQI->m_Interface->Size <= Irp->GetParameterQueryInterfaceSize() &&
1580  pQI->m_Interface->Version <= Irp->GetParameterQueryInterfaceVersion()) {
1581 
1582  if (pQI->m_ImportInterface == FALSE) {
1583  //
1584  // Expose the interface to the requesting driver.
1585  //
1586  RtlCopyMemory(pExposedInterface,
1587  pQI->m_Interface,
1588  pQI->m_Interface->Size);
1589  }
1590  else {
1591  //
1592  // The interface contains data which the driver wants
1593  // before copying over its information, so don't do a
1594  // copy and let the event callback do the copy
1595  //
1596  DO_NOTHING();
1597  }
1598  }
1599  else {
1601  break;
1602  }
1603  }
1604 
1605  callback.m_Method = pQI->m_ProcessRequest.m_Method;
1606  sendToParent = pQI->m_SendQueryToParentStack;
1607  pFound = pQI;
1608 
1610  break;
1611  }
1612  }
1613 
1614  m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals());
1615 
1616  if (!NT_SUCCESS(status) || pFound == NULL) {
1617  goto Done;
1618  }
1619 
1620  //
1621  // Let the driver see the interface before it is handed out.
1622  //
1623  status = callback.Invoke(m_Device->GetHandle(),
1624  (LPGUID) Irp->GetParameterQueryInterfaceType(),
1625  pExposedInterface,
1626  pExposedInterfaceSpecificData);
1627 
1628  //
1629  // STATUS_NOT_SUPPORTED is a special cased error code which indicates that
1630  // the QI should travel down the rest of the stack.
1631  //
1633  goto Done;
1634  }
1635 
1636  //
1637  // If it is meant for the parent, send it down the parent stack
1638  //
1639  if (sendToParent) {
1641  goto Done;
1642  }
1643 
1644  //
1645  // Reference the interface before returning it to the requesting driver.
1646  // If this is an import interface, the event callback is free to not fill
1647  // in the InterfaceReference function pointer.
1648  //
1649  if (pExposedInterface->InterfaceReference != NULL) {
1650  pExposedInterface->InterfaceReference(pExposedInterface->Context);
1651  }
1652 
1653  //
1654  // If we are not a PDO in the stack, then send the fully formatted QI request
1655  // down the stack to allow others to filter the interface.
1656  //
1657  if (m_Device->IsPdo() == FALSE) {
1659 
1660  Irp->SetStatus(status);
1661  Irp->CopyCurrentIrpStackLocationToNext();
1662  status = Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
1663  }
1664 
1665 Done:
1666  if (pFound != NULL) {
1667  *CompleteRequest = TRUE;
1668  }
1669 
1670  return status;
1671 }
1672 
1674 NTSTATUS
1676  VOID
1677  )
1678 {
1680  NTSTATUS status;
1681 
1683 
1685 
1687  &deviceObject,
1689  &caps);
1690 
1691  if (NT_SUCCESS(status)) {
1692  ULONG states, i;
1693 
1694  ASSERT(caps.DeviceCaps.DeviceWake <= 0xFF && caps.DeviceCaps.SystemWake <= 0xFF);
1695 
1696  m_SystemWake = (BYTE) caps.DeviceCaps.SystemWake;
1697 
1698  //
1699  // Initialize the array of wakeable D-states to say that all system
1700  // states down to the one identified in the caps can generate wake.
1701  // This will be overridden below if the BIOS supplied more information.
1702  //
1703  // Compatibility Note: Non-ACPI bus drivers (root-enumerated drivers)
1704  // or other bus drivers that haven't set the power settings correctly
1705  // for their PDO may end up with a valid value for DeviceWake in the
1706  // device capabilities but a value of PowerSystemUnspecified for
1707  // SystemWake, in which case a call to WdfDeviceAssignS0IdleSettings or
1708  // WdfDeviceAssignSxWakeSettings DDIs will fail on 1.11+ resulting in
1709  // device compat issues. The failure is expected and right thing to do
1710  // but has compatibility implications - drivers that worked earlier now
1711  // fail on 1.11. Note that earlier versions of WDF did not have
1712  // m_DeviceWake as an array and stored just the capabilities->DeviceWake
1713  // value without regard to the SystemWake but the current implementation
1714  // introduces dependency on systemWake value). So for compat reasons,
1715  // for pre-1.11 compiled drivers we initilaize the array with DeviceWake
1716  // value ignoring SystemWake, removing any dependency of DeviceWake
1717  // on SystemWake value and thus preserving previous behavior for
1718  // pre-1.11 compiled drivers.
1719  //
1721 
1723 
1724  for (i = PowerSystemWorking; i <= m_SystemWake; i++) {
1725 
1726  //
1727  // Note that this cast is hiding a conversion between two slightly
1728  // incompatible types. DeviceWake is in terms of DEVICE_POWER_STATE
1729  // which is defined this way:
1730  //
1731  // typedef enum _DEVICE_POWER_STATE {
1732  // PowerDeviceUnspecified = 0,
1733  // PowerDeviceD0,
1734  // PowerDeviceD1,
1735  // PowerDeviceD2,
1736  // PowerDeviceD3,
1737  // PowerDeviceMaximum
1738  // } DEVICE_POWER_STATE, *PDEVICE_POWER_STATE;
1739  //
1740  // m_DeviceWake is defined in terms of DEVICE_WAKE_DEPTH which is
1741  // defined this way:
1742  //
1743  // typedef enum _DEVICE_WAKE_DEPTH {
1744  // DeviceWakeDepthNotWakeable = 0,
1745  // DeviceWakeDepthD0,
1746  // DeviceWakeDepthD1,
1747  // DeviceWakeDepthD2,
1748  // DeviceWakeDepthD3hot,
1749  // DeviceWakeDepthD3cold,
1750  // DeviceWakeDepthMaximum
1751  // } DEVICE_WAKE_DEPTH, *PDEVICE_WAKE_DEPTH;
1752  //
1753  // The result is that the conversion below will map D3 onto D3hot,
1754  // which is a safe assumption to start with, one which may be
1755  // overridden later.
1756  //
1757  C_ASSERT(PowerDeviceD0 == static_cast<DEVICE_POWER_STATE>(DeviceWakeDepthD0));
1758  m_DeviceWake[i - PowerSystemWorking] = (BYTE) caps.DeviceCaps.DeviceWake;
1759  }
1760  }
1761  else {
1762  //
1763  // See comments above for information on mapping of device power
1764  // state to device wake depth.
1765  //
1768  (BYTE) caps.DeviceCaps.DeviceWake);
1769  }
1770 
1771  //
1772  // Capture the S -> D state mapping table as a ULONG for use in the
1773  // power policy owner state machine when the machine moves into Sx and
1774  // the device is not armed for wake and has set an IdealDxStateForSx
1775  // value
1776  //
1777  states = 0x0;
1778 
1779  for (i = 0; i < ARRAY_SIZE(caps.DeviceCaps.DeviceState); i++) {
1780  _SetPowerCapState(i, caps.DeviceCaps.DeviceState[i], &states);
1781  }
1782 
1784 
1785  //
1786  // Query for the D3cold support interface. If present, it will tell
1787  // us specifically which D-states will work for generating wake signals
1788  // from specific S-states.
1789  //
1790  // Earlier versions of WDF didn't make this query, so for compatibility,
1791  // we only make it now if the driver was built against WDF 1.11 or
1792  // later. In truth, this just shifts the failure from initialization
1793  // time to run time, because the information that we're presumably
1794  // getting from the BIOS with this interrogation is saying that the
1795  // code in earlier verisions of WDF would have blindly enabled a device
1796  // for wake which simply wasn't capable of generating its wake signal
1797  // from the chosen D-state. Thus the device would have been put into
1798  // a low power state and then failed to resume in response to its wake
1799  // signal.
1800  //
1801 
1802  if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) {
1803 
1804  //
1805  // Cycle through all the system states that this device can wake
1806  // from. There's no need to look at deeper sleep states than
1807  // m_SystemWake because the driver will not arm for wake in
1808  // those states.
1809  //
1810  for (i = PowerSystemWorking; i <= m_SystemWake; i++) {
1813  }
1814  }
1815  }
1816  }
1817 
1818  return status;
1819 }
1820 
1822 NTSTATUS
1825  __inout FxIrp *Irp
1826  )
1827 /*++
1828 
1829 Routine Description:
1830  This method is called in response to a PnP StartDevice IRP coming down the
1831  stack.
1832 
1833 Arguments:
1834  This - device instance
1835  Irp - a pointer to the FxIrp
1836 
1837 Returns:
1838  STATUS_PENDING
1839 
1840 --*/
1841 {
1842  This->SetPendingPnpIrp(Irp);
1843  This->PnpProcessEvent(PnpEventStartDevice);
1844 
1845  return STATUS_PENDING;
1846 }
1847 
1849 NTSTATUS
1852  __inout FxIrp *Irp
1853  )
1854 
1855 /*++
1856 
1857 Routine Description:
1858 
1859  Pnp callback querying to see if the device can be stopped.
1860 
1861  The Framework philosophy surrounding Query Stop (and Query Remove) is that
1862  it's impossible to really know if you can stop unless you've tried to stop.
1863  This may not always be true, but it's hard to find a general strategy that
1864  works that is less conservative. Furthermore, I couldn't find good examples
1865  of drivers that would really benefit from continuing to handle requests
1866  until the actual Stop IRP arrived, particularly when you consider that
1867  most QueryStops are followed immediately by Stops.
1868 
1869  So this function sends an event to the PnP State machine that begins the
1870  stopping process. If it is successful, then ultimately the QueryStop IRP
1871  will be successfully completed.
1872 
1873 Arguments:
1874 
1875  This - a pointer to the PnP package
1876 
1877  Irp - a pointer to the FxIrp
1878 
1879 Return Value:
1880 
1881  STATUS_PENDING
1882 
1883  --*/
1884 
1885 {
1886  //
1887  // Keep this IRP around, since we're going to deal with it later.
1888  //
1889  This->SetPendingPnpIrp(Irp);
1890 
1891  //
1892  // Now run the state machine on this thread.
1893  //
1894  This->PnpProcessEvent(PnpEventQueryStop);
1895 
1896  return STATUS_PENDING;
1897 }
1898 
1900 NTSTATUS
1903  __inout FxIrp *Irp
1904  )
1905 /*++
1906 
1907 Routine Description:
1908 
1909  This routine is invoked in response to a query stop failing, somewhere in
1910  the stack. Note that we can receive a cancel stop without being in the
1911  query stop state if a driver above us in the stack failed the query stop.
1912 
1913  Again, this function just exists to bridge the gap between the WDM IRPs
1914  and the PnP state machine. This function does little more than send an
1915  event to the machine.
1916 
1917 Arguments:
1918 
1919  This - the package
1920 
1921  Irp - a pointer to the FxIrp
1922 
1923 Returns:
1924 
1925  STATUS_PENDING
1926 
1927 --*/
1928 {
1929  //
1930  // Seed the irp with success
1931  //
1932  Irp->SetStatus(STATUS_SUCCESS);
1933 
1934  //
1935  // Pend it and transition the state machine
1936  //
1937  This->SetPendingPnpIrp(Irp);
1938  This->PnpProcessEvent(PnpEventCancelStop);
1939 
1940  return STATUS_PENDING;
1941 }
1942 
1944 NTSTATUS
1947  __inout FxIrp *Irp
1948  )
1949 /*++
1950 
1951 Routine Description:
1952 
1953  This method is invoked in response to a Pnp StopDevice IRP.
1954 
1955 Arguments:
1956 
1957  Irp - a pointer to the FxIrp
1958 
1959 Returns:
1960 
1961  STATUS_PENDING
1962 
1963 --*/
1964 {
1965  //
1966  // Seed the irp with success
1967  //
1968  Irp->SetStatus(STATUS_SUCCESS);
1969 
1970  //
1971  // Pend and transition the state machine
1972  //
1973  This->SetPendingPnpIrp(Irp);
1974  This->PnpProcessEvent(PnpEventStop);
1975 
1976  return STATUS_PENDING;
1977 }
1978 
1980 NTSTATUS
1983  __inout FxIrp *Irp
1984  )
1985 /*++
1986 
1987 Routine Description:
1988 
1989  Again, the Framework handles QueryRemove by stopping everything going on
1990  related to the device and then asking the driver whether it can be
1991  removed. This function just kicks the state machine. Final completion
1992  of the IRP will come (much) later.
1993 
1994 Arguments:
1995 
1996  This - the package
1997 
1998  Irp - a pointer to the FxIrp
1999 
2000 Returns:
2001 
2002  STATUS_PENDING
2003 
2004 --*/
2005 {
2006  //
2007  // By default we handle this state.
2008  //
2009  Irp->SetStatus(STATUS_SUCCESS);
2010 
2011  //
2012  // Keep this IRP around, since we're going to deal with it later.
2013  //
2014  This->SetPendingPnpIrp(Irp);
2015 
2016  //
2017  // Now run the state machine on this thread.
2018  //
2019  This->PnpProcessEvent(PnpEventQueryRemove);
2020 
2021  return STATUS_PENDING;
2022 }
2023 
2025 NTSTATUS
2028  __inout FxIrp *Irp
2029  )
2030 
2031 /*++
2032 
2033 Routine Description:
2034 
2035  Notification of a previous remove being canceled. Kick the state machine.
2036 
2037 Arguments:
2038 
2039  This - the package
2040 
2041  Irp - FxIrp representing the notification
2042 
2043 Return Value:
2044 
2045  STATUS_PENDING
2046 
2047  --*/
2048 
2049 {
2050  //
2051  // Seed the irp with success
2052  //
2053  Irp->SetStatus(STATUS_SUCCESS);
2054 
2055  //
2056  // Pend it and transition the state machine
2057  //
2058 
2059  This->SetPendingPnpIrp(Irp);
2060  This->PnpProcessEvent(PnpEventCancelRemove);
2061 
2062  return STATUS_PENDING;
2063 }
2064 
2065 VOID
2067  __in BOOLEAN CleanupPnp
2068  )
2069 {
2070 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
2072 #else
2073  FxCREvent eventOnStack;
2074  eventOnStack.Initialize();
2075  FxCREvent * event = eventOnStack.GetSelfPointer();
2076 #endif
2077 
2078  //
2079  // Order of shutdown is important here.
2080  // o Pnp initiates events to power policy.
2081  // o Power policy initiates events to power and device-power-requirement
2082  // o Power does not initiate any events
2083  // o Device-power-requirement does not initiate any events
2084  //
2085  // By shutting them down in the order in which they send events, we can
2086  // guarantee that no new events will be posted into the subsidiary state
2087  // machines.
2088  //
2089 
2090  //
2091  // This will shut off the pnp state machine and synchronize any outstanding
2092  // threads of execution.
2093  //
2094  if (CleanupPnp && m_PnpMachine.SetFinished(
2095  event
2096  ) == FALSE) {
2099  "WDFDEVICE %p, !devobj %p waiting for pnp state machine to finish",
2101 
2102  //
2103  // Process the event *before* completing the irp so that this event is in
2104  // the queue before the device remove event which will be processed
2105  // right after the start irp has been completed.
2106  //
2107  event->EnterCRAndWaitAndLeave();
2108  }
2109 
2110  //
2111  // Even though event is a SynchronizationEvent, so we need to reset it for
2112  // the next wait because SetFinished will set it if even if the transition
2113  // to the finished state is immediate
2114  //
2115  event->Clear();
2116 
2120  "WDFDEVICE %p, !devobj %p waiting for pwr pol state machine to finish",
2122 
2123  event->EnterCRAndWaitAndLeave();
2124  }
2125 
2126  //
2127  // See previous comment about why we Clear()
2128  //
2129  event->Clear();
2130 
2134  "WDFDEVICE %p, !devobj %p waiting for pwr state machine to finish",
2136 
2137  event->EnterCRAndWaitAndLeave();
2138  }
2139 
2140  if (IsPowerPolicyOwner()) {
2141  //
2142  // See previous comment about why we Clear()
2143  //
2144  event->Clear();
2145 
2147  m_DevicePowerRequirementMachine) {
2148 
2150  m_DevicePowerRequirementMachine->SetFinished(event)) {
2151 
2154  "WDFDEVICE %p, !devobj %p waiting for device power "
2155  "requirement state machine to finish",
2156  m_Device->GetHandle(),
2158 
2159  event->EnterCRAndWaitAndLeave();
2160  }
2161  }
2162 
2164  }
2165 
2166  //
2167  // Release the power thread if we have one either through creation or query.
2168  // Since the power policy state machine is off, we should no longer need
2169  // a dedicated thread.
2170  //
2171  // *** NOTE ***
2172  // The power thread must be released *BEFORE* sending the irp down the stack
2173  // because this can happen
2174  // 1) this driver is not the power thread owner, but the last client
2175  // 2) we send the pnp irp first
2176  // 3) the power thread owner waits on this thread for all the clients to go
2177  // away, but this device still has a reference on it
2178  // 4) this device will not release the reference b/c the owner is waiting
2179  // in the same thread.
2180  //
2182 
2183  //
2184  // Deref the reenumeration interface
2185  //
2187 }
2188 
2189 VOID
2191  __in MxEvent * WaitEvent
2192  )
2193 /*++
2194 
2195 Routine Description:
2196  The device failed creation in some stage. It is assumed that the device has
2197  enough state that it can survive a transition through the pnp state machine
2198  (which means that pointers like m_PkgIo are valid and != NULL). When this
2199  function returns, it will have deleted the owning FxDevice.
2200 
2201 Arguments:
2202  WaitEvent - Event on which RemoveProcessed wait will be performed
2203 
2204  We can't initialize this event on stack as the initialization
2205  can fail in user-mode. We can't have Initialize method
2206  preinitailize this event either as this function may get called
2207  before initialize (or in case of initialization failure).
2208 
2209  Hence the caller preallocates the event and passes to this
2210  function.
2211 
2212  Caller must initialize this event as SynchronizationEvent
2213  and it must be unsignalled.
2214 Return Value:
2215  None
2216 
2217  --*/
2218 {
2220 
2221  //
2222  // Caller must initialize the event as Synchronization event and it should
2223  // be passed as non-signalled. But we Clear it just to be sure.
2224  //
2225  WaitEvent->Clear();
2226 
2227  ADDREF(WaitEvent);
2228 
2230  m_DeviceRemoveProcessed = WaitEvent;
2231 
2232  //
2233  // Simulate a remove event coming to the device. After this call returns
2234  // m_Device is still valid and must be deleted.
2235  //
2237 
2238  //
2239  // No need to wait in a critical region because we are in the context of a
2240  // pnp request which is in the system context.
2241  //
2242  WaitEvent->WaitFor(Executive, KernelMode, FALSE, NULL);
2244 
2245  RELEASE(WaitEvent);
2246 }
2247 
2248 VOID
2250  VOID
2251  )
2252 /*++
2253 
2254 Routine Description:
2255  This routine will detach and delete the device object and free the memory
2256  for the device if there are no other references to it. Before calling this
2257  routine, the state machines should have been cleaned up and the power thread
2258  released.
2259 
2260 --*/
2261 {
2262  //
2263  // This will detach and delete the device object
2264  //
2265  m_Device->Destroy();
2266 
2267  //
2268  // If this is the last reference, this will free the memory for the device
2269  //
2271 }
2272 
2274 NTSTATUS
2277  __inout FxIrp *Irp
2278  )
2279 
2280 /*++
2281 
2282 Routine Description:
2283 
2284  Notification of a remove. Kick the state machine.
2285 
2286 Arguments:
2287 
2288  This - the package
2289 
2290  Irp - FxIrp representing the notification
2291 
2292 Return Value:
2293 
2294  status
2295 
2296  --*/
2297 
2298 {
2299 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
2300  MxEvent * event = This->m_RemoveEventUm.GetSelfPointer();
2301 #else
2302  MxEvent eventOnStack;
2303  eventOnStack.Initialize(SynchronizationEvent, FALSE);
2304  MxEvent * event = eventOnStack.GetSelfPointer();
2305 #endif
2306 
2307  NTSTATUS status;
2308 
2310  This->m_Device->GetRemoveLock(),
2311  Irp->GetIrp());
2312 
2313 #if DBG
2315 #else
2317 #endif
2318 
2319  //
2320  // Keep this object around after m_Device has RELEASE'ed its reference to
2321  // this package.
2322  //
2323  This->ADDREF(Irp);
2324 
2325  //
2326  // Removes are always success
2327  //
2328  Irp->SetStatus(STATUS_SUCCESS);
2329 
2330  ASSERT(This->m_DeviceRemoveProcessed == NULL);
2331  This->m_DeviceRemoveProcessed = event;
2332 
2333  //
2334  // Post the event and wait for the FxDevice to destroy itself or determine
2335  // it has not been reported missing yet (for PDOs and bus filters).
2336  //
2337  This->PnpProcessEvent(PnpEventRemove);
2338 
2340  This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
2341  "WDFDEVICE %p, !devobj %p waiting for remove event to finish processing",
2342  This->m_Device->GetHandle(), This->m_Device->GetDeviceObject());
2343 
2344  //
2345  // No need to wait in a critical region because we are in the context of a
2346  // pnp request which is in the system context.
2347  //
2348  event->WaitFor(Executive, KernelMode, FALSE, NULL);
2349 
2350  This->m_DeviceRemoveProcessed = NULL;
2351 
2352  status = This->ProcessRemoveDeviceOverload(Irp);
2353 
2354  //
2355  // Release the reference added at the top. This is most likely going to be
2356  // the last reference on the package for KMDF. For UMDF, host manages the
2357  // lifetime of FxDevice so this may not be the last release for UMDF.
2358  //
2359  This->RELEASE(Irp);
2360 
2361  return status;
2362 }
2363 
2365 NTSTATUS
2367  __inout FxIrp* Irp
2368  )
2369 
2370 /*++
2371 
2372 Routine Description:
2373 
2374  Notification that the device has been surprise removed. Kick the state
2375  machine.
2376 
2377 Arguments:
2378 
2379  Irp - pointer to FxIrp representing this notification
2380 
2381 Return Value:
2382 
2383  STATUS_PENDING
2384 
2385 --*/
2386 
2387 {
2388  //
2389  // Package specific handling
2390  //
2391  Irp->SetStatus(STATUS_SUCCESS);
2394 
2395  return STATUS_PENDING;
2396 }
2397 
2399 NTSTATUS
2402  __inout FxIrp *Irp
2403  )
2404 
2405 /*++
2406 
2407 Routine Description:
2408 
2409  This the first-level dispatch routine for IRP_MN_WAIT_WAKE. What one
2410  does with a WaitWake IRP depends very much on whether one is an FDO, a PDO
2411  or a filter. So dispatch immediately to a subclassable function.
2412 
2413 Arguments:
2414 
2415  This - the package
2416 
2417  Irp - pointer to FxIrp representing this notification
2418 
2419 Return Value:
2420 
2421  status
2422 
2423 --*/
2424 
2425 {
2426  return This->DispatchWaitWake(Irp);
2427 }
2428 
2430 NTSTATUS
2432  __inout FxIrp *Irp
2433  )
2434 /*++
2435 
2436 Routine Description:
2437 
2438  Handles wait wake requests in a generic fashion
2439 
2440 Arguments:
2441 
2442 
2443 Return Value:
2444 
2445  --*/
2446 {
2447  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
2448  NTSTATUS status;
2449  PIRP oldIrp;
2450  KIRQL irql;
2451 
2452  if (IsPowerPolicyOwner()) {
2454  //
2455  // A power irp arrived, but we did not request it. log and bugcheck
2456  //
2459  "Received wait wake power irp %p on device %p, but the irp was "
2460  "not requested by the device (the power policy owner)",
2461  Irp->GetIrp(), m_Device->GetDeviceObject());
2462 
2463  FxVerifierBugCheck(GetDriverGlobals(), // globals
2464  WDF_POWER_MULTIPLE_PPO, // specific type
2465  (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2
2466  (ULONG_PTR)Irp->GetIrp()); // parm 3
2467 
2468  /* NOTREACHED */
2469  }
2470 
2471  //
2472  // We are no longer requesting a power irp because we received the one
2473  // we requested.
2474  //
2476  }
2477 
2478  //
2479  // The Framework has the concept of a "Wait/Wake Owner." This is the layer
2480  // in the stack that is enabling and disabling wake at the bus level. This
2481  // is probably the PDO or a bus filter like ACPI.sys. This is distinct
2482  // from being the "Power Policy Owner," which would mean that this driver
2483  // is deciding what D-state is appropriate for the device, and also
2484  // sending Wait/Wake IRPs.
2485  //
2486 
2489 
2490  if (m_SharedPower.m_WaitWakeIrp != NULL) {
2491  //
2492  // We only allow one pended wait wake irp in the stack at a time.
2493  // Fail this secondary wait wake request.
2494  //
2496 
2499  "Failing wait wake irp %p with %!STATUS! because wait wake irp "
2500  "%p already pended",
2501  Irp->GetIrp(), status, m_SharedPower.m_WaitWakeIrp);
2502  }
2503  else {
2504  MdCancelRoutine pRoutine;
2505 
2506  //
2507  // No wait wake irp is currently in the stack, so attempt to set
2508  // a cancel routine and transition the power state machine into a
2509  // a state where it can arm the device at the bus level for this
2510  // child.
2511  //
2512  // The power state machine expects the wait wake irp to have a cancel
2513  // routine set in all states. For those states which require a
2514  // non cancelable irp, those states clear the cancel routine as
2515  // appropriate.
2516  //
2517  pRoutine = Irp->SetCancelRoutine(_PowerWaitWakeCancelRoutine);
2518 #if DBG
2519  ASSERT(pRoutine == NULL);
2520 #else
2521  UNREFERENCED_PARAMETER(pRoutine);
2522 #endif
2524 
2525  if (Irp->IsCanceled()) {
2528  "wait wake irp %p already canceled", Irp->GetIrp());
2529 
2530  //
2531  // This IRP has already been cancelled, we must clear the cancel
2532  // routine before completing the IRP.
2533  //
2534  pRoutine = Irp->SetCancelRoutine(NULL);
2535 
2536  if (pRoutine != NULL) {
2537  //
2538  // Our cancel routine will not be called
2539  //
2540 #if DBG
2541  ASSERT(pRoutine == _PowerWaitWakeCancelRoutine);
2542 #else
2543  UNREFERENCED_PARAMETER(pRoutine);
2544 #endif
2545  Irp->SetStatus(STATUS_CANCELLED);
2547  }
2548  }
2549 
2550  if (status == STATUS_PENDING) {
2551  //
2552  // Either we successfully set the cancel routine or the irp
2553  // was canceled and the cancel routine is about to run when
2554  // we drop the lock. If the routine is about to run, we still
2555  // need to setup m_SharedPower to values that it expects.
2556  //
2557  Irp->MarkIrpPending();
2558  m_SharedPower.m_WaitWakeIrp = Irp->GetIrp();
2559  }
2560  }
2562 
2563  if (NT_SUCCESS(status)) {
2564  //
2565  // Post to the appropriate matchines
2566  //
2568 
2569  if (IsPowerPolicyOwner()) {
2571  }
2572  }
2573  else {
2575  }
2576 
2577  return status;
2578  }
2579  else if (IsPowerPolicyOwner()) {
2580  //
2581  // Try to set m_WaitWakeIrp to the new IRP value only if the current
2582  // value of m_WaitWakeIrp is NULL because there can only be one
2583  // active wait wake irp in the stack at a time. Since the power policy
2584  // state machine never sends more then one, this is really a guard
2585  // against some other device in the stack sending a wait wake irp to
2586  // this device in the wrong state.
2587  //
2590  Irp->GetIrp(),
2591  NULL
2592  );
2593 
2594  //
2595  // If oldIrp is NULL then there was no previous irp and we successfully
2596  // exchanged the new PIRP value into m_WaitWakeIrp
2597  //
2598  if (oldIrp == NULL) {
2600 
2601  //
2602  // NOTE: There is a built in race condition here that WDF cannot
2603  // solve with the given WDM primitives. After arming the
2604  // device for wake, there is a window where the wait wake irp
2605  // has not yet been processed by the wait wake owner. Until
2606  // the wake request is processed, wake events could be generated
2607  // and lost. There is nothing we can do about this until we
2608  // have synchronous "goto Dx and arm" command available.
2609  //
2610  Irp->CopyCurrentIrpStackLocationToNext();
2611  Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(),
2613  this);
2614 
2615  //
2616  // Technically, there should be a PDO vs FDO overload here which
2617  // does the right thing w/regard to this request and if it is at the
2618  // bottom of the stack or not. But, by design, we check for
2619  // m_WaitWakeOwner first which has the direct side affect of making
2620  // it impossible for a PDO to get to this point.
2621  //
2622  ASSERT(m_Device->IsFdo());
2623 
2624  status = Irp->PoCallDriver(m_Device->GetAttachedDevice());
2625 
2626  //
2627  // Send the wake arrived after sending the request as commented above.
2628  // This window between sending the request and sending the event to
2629  // the state machine allows the wait owner to complete the request
2630  // immediately. When completed synchronously, it has an effect on
2631  // both wake scenarios:
2632  //
2633  // 1) wake from S0: the device never transitions to Dx and the idle
2634  // timer is resumed if no i/o is present
2635  //
2636  // 2) wake from sx: the device is disarmed for wake from Sx and
2637  // put into Dx with being armed for wake.
2638  //
2640  }
2641  else {
2643 
2645  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
2646  "already have a ww irp %p, failing new ww irp %p with %!STATUS!",
2647  oldIrp, Irp->GetIrp(), status);
2648 
2650  }
2651  }
2652  else {
2653  //
2654  // Not the power policy owner, not the wait wake irp owner, ignore the
2655  // irp
2656  //
2657  // This will release the remove lock.
2658  //
2660  }
2661 
2662  return status;
2663 }
2664 
2666 NTSTATUS
2669  )
2670 {
2671  NTSTATUS status;
2672 
2673  //
2674  // Update the callback table.
2675  //
2676  m_DeviceD0Entry.m_Method = DispatchTable->EvtDeviceD0Entry;
2678  DispatchTable->EvtDeviceD0EntryPostInterruptsEnabled;
2680  DispatchTable->EvtDeviceD0ExitPreInterruptsDisabled;
2681  m_DeviceD0Exit.m_Method = DispatchTable->EvtDeviceD0Exit;
2682 
2683  m_DevicePrepareHardware.m_Method = DispatchTable->EvtDevicePrepareHardware;
2684  m_DeviceReleaseHardware.m_Method = DispatchTable->EvtDeviceReleaseHardware;
2685 
2686  m_DeviceQueryStop.m_Method = DispatchTable->EvtDeviceQueryStop;
2687  m_DeviceQueryRemove.m_Method = DispatchTable->EvtDeviceQueryRemove;
2688 
2689  m_DeviceSurpriseRemoval.m_Method = DispatchTable->EvtDeviceSurpriseRemoval;
2690 
2691  m_DeviceUsageNotification.m_Method = DispatchTable->EvtDeviceUsageNotification;
2692  m_DeviceUsageNotificationEx.m_Method = DispatchTable->EvtDeviceUsageNotificationEx;
2693  m_DeviceRelationsQuery.m_Method = DispatchTable->EvtDeviceRelationsQuery;
2694 
2695  if (DispatchTable->EvtDeviceSelfManagedIoCleanup != NULL ||
2696  DispatchTable->EvtDeviceSelfManagedIoFlush != NULL ||
2697  DispatchTable->EvtDeviceSelfManagedIoInit != NULL ||
2698  DispatchTable->EvtDeviceSelfManagedIoSuspend != NULL ||
2699  DispatchTable->EvtDeviceSelfManagedIoRestart != NULL) {
2700 
2702  this);
2703 
2704  if (!NT_SUCCESS(status)) {
2705  return status;
2706  }
2707 
2709  }
2710 
2711  return STATUS_SUCCESS;
2712 }
2713 
2714 VOID
2717  )
2718 {
2720  Callbacks->EvtDeviceArmWakeFromS0;
2722  Callbacks->EvtDeviceArmWakeFromSx;
2724  Callbacks->EvtDeviceArmWakeFromSxWithReason;
2725 
2727  Callbacks->EvtDeviceDisarmWakeFromS0;
2729  Callbacks->EvtDeviceDisarmWakeFromSx;
2730 
2732  Callbacks->EvtDeviceWakeFromS0Triggered;
2734  Callbacks->EvtDeviceWakeFromSxTriggered;
2735 }
2736 
2737 NTSTATUS
2739  __in const GUID* Guid,
2742  )
2743 {
2744  // WDF_WMI_PROVIDER_CONFIG config;
2745  // NTSTATUS status;
2746 
2747  // WDF_WMI_PROVIDER_CONFIG_INIT(&config, Guid);
2748 
2749  // //
2750  // // We are assuming we are registering either for the wait wake or device
2751  // // timeout GUIDs which both operate on BOOLEANs. If we expand this API in
2752  // // the future, have the caller pass in a config structure for the provider
2753  // // GUID.
2754  // //
2755  // config.MinInstanceBufferSize = sizeof(BOOLEAN);
2756 
2757  // status = m_Device->m_PkgWmi->AddPowerPolicyProviderAndInstance(
2758  // &config,
2759  // Callbacks,
2760  // Instance);
2761 
2762  // if (status == STATUS_OBJECT_NAME_COLLISION) {
2763  // status = STATUS_SUCCESS;
2764  // }
2765 
2766  // if (!NT_SUCCESS(status)) {
2767  // DoTraceLevelMessage(
2768  // GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2769  // "Failed to register WMI power GUID %!STATUS!", status);
2770  // }
2771  //
2772  // return status;
2774  return STATUS_SUCCESS;
2775 }
2776 
2777 NTSTATUS
2780  )
2781 /*++
2782 
2783 Routine Description:
2784 
2785  Updates the S0 Idle settings for the device and then posts an update event
2786  to the power policy state machine. The first this function is called, the
2787  ability to allow the user to control this setting is set.
2788 
2789 Arguments:
2790 
2791  Settings - The settings to apply.
2792 
2793 Return Value:
2794 
2795  NTSTATUS
2796 
2797  --*/
2798 {
2799  DEVICE_POWER_STATE dxState;
2800  ULONG idleTimeout;
2801  NTSTATUS status;
2802  BOOLEAN enabled, s0Capable, overridable, firstTime;
2803  WDF_TRI_STATE powerUpOnSystemWake;
2804  const LONGLONG negliblySmallIdleTimeout = -1; // 100 nanoseconds
2805 
2806  s0Capable = FALSE;
2807  dxState = PowerDeviceD3;
2808  overridable = FALSE;
2809  firstTime = TRUE;
2810 
2811  if (Settings->Enabled == WdfTrue) {
2812  enabled = TRUE;
2813 
2814  } else if (Settings->Enabled == WdfUseDefault) {
2815  enabled = TRUE;
2816 
2819 
2820  //
2821  // Read registry. If registry value is not found, the value of "enabled"
2822  // remains unchanged
2823  //
2824  ReadRegistryS0Idle(&valueName, &enabled);
2825  }
2826  else {
2829  "If registry value WdfDefaultIdleInWorkingState was present, "
2830  "it was not read because DDI WdfDeviceAssignS0IdleSettings "
2831  "was not called at PASSIVE_LEVEL");
2832  }
2833  }
2834  else {
2835  enabled = FALSE;
2836  }
2837 
2839  firstTime = FALSE;
2840  }
2841 
2844  if (!NT_SUCCESS(status)) {
2845  return status;
2846  }
2847 
2848  //
2849  // Do not set m_CapsQueried to TRUE yet because we will do that once we
2850  // know the entire stack has been built we will do the query again.
2851  //
2852  }
2853 
2854  switch (Settings->IdleCaps) {
2856  case IdleCanWakeFromS0:
2857  s0Capable = TRUE;
2858 
2859  if (Settings->DxState == PowerDeviceMaximum) {
2861 
2862  //
2863  // Some bus drivers
2864 
2865  // incorrectly report DeviceWake=D0 to
2866  // indicate that it does not support wake instead of specifying
2867  // PowerDeviceUnspecified and KMDF ends up requesting
2868  // a D0 irp when going to Dx. The check prevents this bug.
2869  //
2870  if (dxState < PowerDeviceD1 ||
2871  dxState > PowerDeviceD3 ||
2872  (dxState > PowerDeviceD2 && Settings->IdleCaps == IdleUsbSelectiveSuspend)
2873  ) {
2875 
2878  "DeviceWake power state reported in device capabilities "
2879  "%!DEVICE_POWER_STATE! indicates that device can not signal"
2880  " a wake event, %!STATUS!",
2881  dxState, status);
2882  return status;
2883  }
2884  }
2885  else {
2886  DEVICE_POWER_STATE dxDeepest;
2887 
2888  dxState = Settings->DxState;
2890 
2891  if (dxState > dxDeepest) {
2893 
2896  "DxState specified by driver %!DEVICE_POWER_STATE! cannot "
2897  "be lighter than lightest available device wake state"
2898  " %!DEVICE_POWER_STATE!, %!STATUS!", dxState,
2899  dxDeepest, status);
2900  return status;
2901  }
2902 
2903  //
2904  // Can only perform wait wake from D2 on a USB device
2905  //
2906  if (dxState > PowerDeviceD2 &&
2907  Settings->IdleCaps == IdleUsbSelectiveSuspend) {
2909 
2912  "DxState specified by driver %!DEVICE_POWER_STATE! cannot "
2913  "be lighter than PowerDeviceD2 for USB selective suspend "
2914  "%!STATUS!",
2915  dxState, status);
2916  return status;
2917  }
2918  }
2919 
2920  if (Settings->IdleCaps == IdleUsbSelectiveSuspend) {
2922 
2923  if (!NT_SUCCESS(status)) {
2926  "Failed to initialize USB selective suspend %!STATUS!",
2927  status);
2928  return status;
2929  }
2930  }
2931 
2932  break;
2933 
2934  case IdleCannotWakeFromS0:
2935  s0Capable = FALSE;
2936 
2937  if (Settings->DxState == PowerDeviceMaximum) {
2938  dxState = PowerDeviceD3;
2939  }
2940  else {
2941  dxState = Settings->DxState;
2942  }
2943 
2944  break;
2945 
2946  default:
2947  ASSERT(FALSE);
2948  break;
2949  }
2950 
2951  if (Settings->IdleTimeout == IdleTimeoutDefaultValue) {
2952  idleTimeout = FxPowerPolicyDefaultTimeout;
2953  }
2954  else {
2955  idleTimeout = Settings->IdleTimeout;
2956  }
2957 
2958  if (Settings->UserControlOfIdleSettings == IdleAllowUserControl) {
2959 
2960  // status = UpdateWmiInstanceForS0Idle(AddInstance);
2961  // if (!NT_SUCCESS(status)) {
2962  // return status;
2963  // } __REACTOS__
2964 
2965  if (Settings->Enabled == WdfUseDefault) {
2966  //
2967  // Read the registry entry for idle enabled if it's the first time.
2968  //
2969  if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
2971 
2972  //
2973  // Read registry. If registry value is not found, the value of
2974  // "enabled" remains unchanged
2975  //
2976  ReadRegistryS0Idle(&valueName, &enabled);
2977  }
2978  else {
2979  //
2980  // Use the saved value for idle enabled.
2981  //
2983  }
2984  }
2985 
2986  overridable = TRUE;
2987  }
2988  else if (Settings->UserControlOfIdleSettings == IdleDoNotAllowUserControl) {
2989  //
2990  // No user control
2991  //
2992  overridable = FALSE;
2993 
2994  // (void) UpdateWmiInstanceForS0Idle(RemoveInstance); __REACTOS__
2995  }
2996 
2997  //
2998  // !!!! DO NOT INTRODUCE FAILURES BEYOND THIS POINT !!!!
2999  //
3000  // We should not introduce any failures that are not due to driver errors
3001  // beyond this point. This is because we are going to commit the driver's
3002  // S0-idle settings now and any failure in the midst of that could leave us
3003  // in a bad state. Therefore, all failable code where the failure is beyond
3004  // the driver's control should be placed above this point.
3005  //
3006  // For example, a driver may want wake-from-S0 support, but the device may
3007  // not support it. We already checked for that failure above, before we
3008  // started committing any of the driver's S0-idle settings.
3009  //
3010  // Any failures below this point should only be due to driver errors, i.e.
3011  // the driver incorrectly calling the AssignS0IdleSettings DDI.
3012  //
3013 
3014  if (firstTime) {
3017  }
3018 
3019  //
3020  // IdleTimeoutType is available only on > 1.9
3021  //
3022 #ifndef __REACTOS__
3024  if (firstTime) {
3025  if ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) ||
3027  Settings->IdleTimeoutType)) {
3028  //
3029  // This is the first time S0-idle policy is being specified and
3030  // the caller has asked for the idle timeout to be determined
3031  // by the power manager.
3032  //
3034  m_TimeoutMgmt.UseSystemManagedIdleTimeout(
3036  );
3037  if (!NT_SUCCESS(status)) {
3038  return status;
3039  }
3040  }
3041  } else {
3042  //
3043  // This is not the first time S0-idle policy is being specified.
3044  // Verify that the caller is not trying to change their mind about
3045  // whether the idle timeout is determined by the power manager.
3046  //
3047  BOOLEAN currentlyUsingSystemManagedIdleTimeout;
3048  BOOLEAN callerWantsSystemManagedIdleTimeout;
3049 
3050  currentlyUsingSystemManagedIdleTimeout =
3052  UsingSystemManagedIdleTimeout();
3053  callerWantsSystemManagedIdleTimeout =
3054  ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) ||
3055  (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType));
3056 
3057  //
3058  // UMDF currently does not implement
3059  // IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable. So
3060  // that method must be called only as part of the second check in
3061  // the "if" statement below. Since UMDF currently does not support
3062  // system managed idle timeout, the first check will always evaluate
3063  // to 'FALSE', so the second check never gets executed for UMDF.
3064  //
3065  if ((callerWantsSystemManagedIdleTimeout !=
3066  currentlyUsingSystemManagedIdleTimeout)
3067  &&
3069  ) {
3070 
3074  "A previous call to assign S0-idle policy specified that "
3075  "the idle timeout %s be determined by the power manager. "
3076  "This decision cannot be changed. %!STATUS!",
3077  currentlyUsingSystemManagedIdleTimeout ?
3078  "should" :
3079  "should not",
3080  status);
3082  return status;
3083  }
3084  }
3085  }
3086 #endif
3087 
3088  if (Settings->IdleCaps == IdleCannotWakeFromS0) {
3089  //
3090  // PowerUpIdleDeviceOnSystemWake field added after v1.7.
3091  // By default KMDF uses an optimization where the device is not powered
3092  // up when resuming from Sx if it is idle. The field
3093  // PowerUpIdleDeviceOnSystemWake is used to turn off this optimization and allow
3094  // device to power up when resuming from Sx. Note that this optimization
3095  // is applicable only for IdleCannotWakeFromS0. In other cases the
3096  // device is always powered up in order to arm for wake.
3097  //
3098  powerUpOnSystemWake =
3100  Settings->PowerUpIdleDeviceOnSystemWake :
3101  WdfUseDefault;
3102 
3103  switch(powerUpOnSystemWake) {
3104  case WdfTrue:
3108  "Driver turned off S0Idle optimization. Device will be "
3109  "powered up on resume from Sx even when it is idle");
3110  break;
3111  case WdfFalse:
3115  "Driver turned on S0Idle optimization. Device will remain "
3116  "powered off if idle when resuming from Sx");
3117  break;
3118  case WdfUseDefault:
3119  DO_NOTHING();
3120  break;
3121  default:
3122  break;
3123  }
3124  }
3125 
3126  if (FALSE ==
3128  {
3129  if (Settings->IdleCaps == IdleUsbSelectiveSuspend) {
3132  m_IdleSettings.UsbSSCapabilityKnown = TRUE;
3133 
3134  } else if (Settings->IdleCaps == IdleCanWakeFromS0) {
3135 
3137  m_IdleSettings.UsbSSCapabilityKnown = TRUE;
3138  }
3139  }
3140 
3141  //
3142  // Wake FromS0Capable is set every time because we want to allow the driver
3143  // to swap between idle wake capable and idle not wake capable. This should
3144  // be allowed so that a scenario similar to the following can be implemented:
3145  //
3146  // a) when the device has an outstanding open, the device should arm itself
3147  // for wake when idle
3148  //
3149  // b) when the device does not have an outstanding open, the device should
3150  // be off and not armed.
3151  //
3152  // The only way to be off is to assign S0 wake settings, so the
3153  // WakeFromS0Capable field must change on each DDI call. This is not a
3154  // problem for the power policy state machine because it evaluates
3155  // WakeFromS0Capable state before enabling of idle. If we are not
3156  // WakeFromS0Capable and USB SS capable (ie a have a torn/unsynchronized
3157  // state) in m_IdleSettings, we will recover from it when processing
3158  // PwrPolS0IdlePolicyChanged in the state machine (b/c this event causes
3159  // both fields to be reevaluated).
3160  //
3162 
3164 
3166  m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) {
3167  //
3168  // With system managed idle timeout, we don't want to apply an idle
3169  // timeout of our own on top of that. Effectively, our idle timeout is
3170  // 0.
3171  // But we apply a negligibly small timeout value as this allows us to
3172  // keep the same logic in the idle state machine, regardless of whether
3173  // we're using system-managed idle timeout or driver-managed idle
3174  // timeout.
3175  //
3176  if (firstTime) {
3178  m_PowerIdleMachine.m_PowerTimeout.QuadPart =
3179  negliblySmallIdleTimeout;
3180  }
3181 
3182  if (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType) {
3183  //
3184  // We save the idle timeout hint, but we don't provide the hint to
3185  // the power framework immediately. This is because currently we may
3186  // or may not be registered with the power framework. Note that
3187  // WdfDeviceAssignS0IdleSettings might get called even when we are
3188  // not registered with the power framework.
3189  //
3190  // Therefore, we provide the hint to the power framework only when
3191  // we get to the WdfDevStatePwrPolStartingDecideS0Wake state. This
3192  // state is a good choice for providing the hint because:
3193  // 1. We know we would be registered with the power framework when
3194  // we are in this state.
3195  // 2. Any change in S0-idle settings causes us to go through this
3196  // state.
3197  //
3199  idleTimeout;
3200  }
3201 
3202  } else {
3204  = WDF_REL_TIMEOUT_IN_MS(idleTimeout);
3205  }
3206 
3207  //
3208  // If the driver is 1.11 or later, update the bus drivers with the client's
3209  // choice on the topic of D3hot or D3cold.
3210  //
3211  if ((Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) &&
3212  (Settings->ExcludeD3Cold != WdfUseDefault)) {
3214  BOOLEAN enableD3Cold;
3215 
3217 
3218  switch (Settings->ExcludeD3Cold) {
3219  case WdfFalse:
3220  enableD3Cold = TRUE;
3221  break;
3222  default:
3225  "Invalid tri-state value for ExcludeD3Cold %d",
3226  Settings->ExcludeD3Cold);
3227  __fallthrough;
3228  case WdfTrue:
3229  enableD3Cold = FALSE;
3230  break;
3231  }
3232 
3234  &deviceObject,
3236  enableD3Cold);
3237  }
3238 
3240 
3241  return STATUS_SUCCESS;
3242 }
3243 
3244 NTSTATUS
3247  __in BOOLEAN ArmForWakeIfChildrenAreArmedForWake,
3248  __in BOOLEAN IndicateChildWakeOnParentWake
3249  )
3250 /*++
3251 
3252 Routine Description:
3253 
3254  Updates the Sx wake settings for the device. No event is posted to the
3255  state machine because this setting is statically checked when the machine
3256  is entering an Sx state (unlike S0 idle which can be checked at any time).
3257 
3258  The first this function is called, the ability to allow the user to control
3259  this setting is set.
3260 
3261 Arguments:
3262 
3263  Settings - the new settings to apply
3264 
3265  ArmForWakeIfChildrenAreArmedForWake - Inidicates whether the device
3266  should arm for wake when one or more children are armed for wake
3267 
3268  IndicateChildWakeOnParentWake - Indicates whether the device should
3269  propagate the wake status to its children
3270 
3271 Return Value:
3272 
3273  NTSTATUS
3274 
3275  --*/
3276 {
3277  DEVICE_POWER_STATE dxState;
3278  NTSTATUS status;
3279  BOOLEAN overridable, firstTime, enabled;
3280 
3281  dxState = PowerDeviceD3;
3282  overridable = FALSE;
3283  firstTime = TRUE;
3284 
3285  if (Settings->Enabled == WdfTrue) {
3286  enabled = TRUE;
3287 
3288  }
3289  else if (Settings->Enabled == WdfUseDefault) {
3290  enabled = TRUE;
3291 
3294 
3295  //
3296  // Read registry. If registry value is not found, the value of "enabled"
3297  // remains unchanged
3298  //
3299  ReadRegistrySxWake(&valueName, &enabled);
3300  }
3301  else {
3304  "If registry value WdfDefaultWakeFromSleepState was present, "
3305  "it was not read because DDI WdfDeviceAssignSxWakeSettings "
3306  "was not called at PASSIVE_LEVEL");
3307  }
3308  }
3309  else {
3310  enabled = FALSE;
3311  }
3312 
3314  firstTime = FALSE;
3315  }
3316 
3319  if (!NT_SUCCESS(status)) {
3320  return status;
3321  }
3322 
3323  //
3324  // Do not set m_CapsQueried to TRUE yet because we will do that once we
3325  // know the entire stack has been built we will do the query again.
3326  //
3327  }
3328 
3329  if (Settings->DxState == PowerDeviceMaximum) {
3331 
3332  //
3333  // Some bus drivers
3334 
3335  // incorrectly report DeviceWake=D0 to
3336  // indicate that it does not support wake instead of specifying
3337  // PowerDeviceUnspecified and KMDF ends up requesting
3338  // a D0 irp when going to Dx. The check prevents this bug.
3339  //
3340  if (dxState < PowerDeviceD1 || dxState > PowerDeviceD3) {
3342 
3345  "DeviceWake power state reported in device capabilities "
3346  "%!DEVICE_POWER_STATE! indicates that device can not signal a "
3347  "wake event, %!STATUS!",
3348  dxState, status);
3349  return status;
3350  }
3351  }
3352  else {
3353  DEVICE_POWER_STATE dxDeepest;
3354 
3355  dxState = Settings->DxState;
3357 
3358  if (dxState > dxDeepest) {
3362  "DxState specified by driver %!DEVICE_POWER_STATE! cannot be"
3363  " lighter than lightest available device wake state "
3364  "%!DEVICE_POWER_STATE!, %!STATUS!", dxState,
3365  dxDeepest, status);
3366  return status;
3367  }
3368  }
3369 
3370  if (Settings->UserControlOfWakeSettings == WakeAllowUserControl) {
3371 
3372  // status = UpdateWmiInstanceForSxWake(AddInstance); __REACTOS__
3373 
3374  // if (!NT_SUCCESS(status)) {
3375  // return status;
3376  // }
3377 
3378  if (Settings->Enabled == WdfUseDefault) {
3379  //
3380  // Read the registry entry for wake enabled if it's the first time.
3381  //
3382  if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) {
3384 
3385  //
3386  // Read registry. If registry value is not found, the value of
3387  // "enabled" remains unchanged
3388  //
3389  ReadRegistrySxWake(&valueName, &enabled);
3390  }
3391  else {
3392  //
3393  // Use the saved value for wake enabled.
3394  //
3396  }
3397  }
3398 
3399  overridable = TRUE;
3400  }
3401  else if (Settings->UserControlOfWakeSettings == WakeDoNotAllowUserControl) {
3402  //
3403  // No user control, just set to enabled
3404  //
3405  overridable = FALSE;
3406 
3407  // (void) UpdateWmiInstanceForSxWake(RemoveInstance); __REACTOS__
3408  }
3409 
3410  if (firstTime) {
3413 
3414  //
3415  // If ArmForWakeIfChildrenAreArmedForWake setting is set to FALSE,
3416  // then we use the legacy framework behavior which did not depend
3417  // on the child device being capable of arming for wake or not.
3418  //
3420  ArmForWakeIfChildrenAreArmedForWake;
3421 
3422  //
3423  // If IndicateChildWakeOnParentWake setting is set to FALSE, then
3424  // we use the legacy framework behavior wherein the wake status
3425  // is not propagated from the parent device to the child device.
3426  //
3428  IndicateChildWakeOnParentWake;
3429  }
3430 
3432 
3434 
3435  return STATUS_SUCCESS;
3436 }
3437 
3438 
3439 
3440 
3441 
3442 
3443 
3444 
3445 
3446 
3447 
3448 
3449 
3450 
3451 
3452 
3453 
3454 NTSTATUS
3457  __in FxWmiInstanceInternal* /* Instance */,
3458  __in ULONG /* OutBufferSize */,
3461  )
3462 {
3463  *((BOOLEAN*) OutBuffer) =
3465  *BufferUsed = sizeof(BOOLEAN);
3466 
3467  return STATUS_SUCCESS;
3468 }
3469 
3470 NTSTATUS
3473  __in FxWmiInstanceInternal* /* Instance */,
3474  __in ULONG /* InBufferSize */,
3475  __in PVOID InBuffer
3476  )
3477 {
3478  BOOLEAN value;
3479 
3480 
3481  //
3482  // FxWmiIrpHandler makes sure the buffer is at least one byte big, so we
3483  // don't check the buffer size.
3484  //
3485 
3486  value = *(PBOOLEAN) InBuffer;
3487 
3488  (Device->m_PkgPnp)->PowerPolicySetS0IdleState(value);
3489 
3490  return STATUS_SUCCESS;
3491 }
3492 
3493 NTSTATUS
3496  __in FxWmiInstanceInternal* /* Instance */,
3499  __in PVOID InBuffer
3500  )
3501 {
3502  BOOLEAN value;
3503 
3504  if (DataItemId != 0) {
3506  }
3507 
3508  if (InBufferSize < sizeof(BOOLEAN)) {
3509  return STATUS_BUFFER_TOO_SMALL;
3510  }
3511 
3512  value = *(BOOLEAN*) InBuffer;
3513  (Device->m_PkgPnp)->PowerPolicySetS0IdleState(value);
3514 
3515  return STATUS_SUCCESS;
3516 }
3517 
3518 NTSTATUS
3521  __in FxWmiInstanceInternal* /* Instance */,
3522  __in ULONG /* OutBufferSize */,
3525  )
3526 {
3527  *((BOOLEAN*) OutBuffer) =
3529  *BufferUsed = sizeof(BOOLEAN);
3530 
3531  return STATUS_SUCCESS;
3532 }
3533 
3534 NTSTATUS
3537  __in FxWmiInstanceInternal* /* Instance */,
3538  __in ULONG /* InBufferSize */,
3539  __in PVOID InBuffer
3540  )
3541 {
3542  BOOLEAN value;
3543 
3544  //
3545  // FxWmiIrpHandler makes sure that the buffer is at least one byte big, so
3546  // we don't check the buffer size
3547  //
3548  value = *(PBOOLEAN) InBuffer;
3549 
3550  (Device->m_PkgPnp)->PowerPolicySetSxWakeState(value);
3551 
3552  return STATUS_SUCCESS;
3553 }
3554 
3555 NTSTATUS
3558  __in FxWmiInstanceInternal* /* Instance */,
3561  __in PVOID InBuffer
3562  )
3563 {
3564  BOOLEAN value;
3565 
3566  if (DataItemId != 0) {
3568  }
3569 
3570  if (InBufferSize < sizeof(BOOLEAN)) {
3571  return STATUS_BUFFER_TOO_SMALL;
3572  }
3573 
3574  value = *(BOOLEAN*) InBuffer;
3575  (Device->m_PkgPnp)->PowerPolicySetSxWakeState(value);
3576 
3577  return STATUS_SUCCESS;
3578 }
3579 
3581 NTSTATUS
3583  __in SYSTEM_POWER_STATE QueryState
3584  )
3585 /*++
3586 
3587 Framework Philosophy Discussion:
3588 
3589  WDM sends IRP_MN_QUERY_POWER for system power states (where system power
3590  states are S0-working, S1-light-sleep, S2-deeper-sleep, S3-deepest-sleep,
3591  S4-hibernation, S5-soft-off.) The idea is that, if a driver can't support
3592  a particular state, it fails the query. The problem is that this idea is
3593  horribly broken.
3594 
3595  The first problem is that WDM doesn't always send these IRPs. In some
3596  situations, (very low battery, system getting critically hot) WDM will
3597  attempt to preserve user data by sleeping or hibernating, rather than just
3598  crashing. This is good, but it makes a driver writer's life very difficult,
3599  since it means that you have to deal with being told to go to a particular
3600  state even if you think that your device won't be able to deal well with
3601  that state.
3602 
3603  The second problem is that, by the time the system is going to sleep, the
3604  user probably isn't still looking at the screen. This is especially true
3605  for laptop computers, as the system is very likely sleeping because the
3606  user closed the clamshell lid. So any attempt to ask the user how to
3607  resolve a situation where a driver doesn't want to go to a low power state
3608  is futile. Furthermore, even when the screen is still available, users
3609  dislike it when they push the sleep button or the power button on their
3610  machines and the machines don't do what they were told to do.
3611 
3612  The third problem is related to the second. While there may be completely
3613  legitimate reasons for the driver to want to delay or even to veto a
3614  transition into a sleep state, (an example of a valid scenario would be one
3615  in which the driver was involved in burning a CD, an operation which can't
3616  be interrupted,) there isn't any good way for a driver to interact with a
3617  user anyhow. (Which desktop is the right one to send messages to? What
3618  should the UI for problem resolution look like? How does a driver put up
3619  UI anyhow?)
3620 
3621  All the driver really knows is that it will or won't be able to maintain
3622  device state, and it will or won't be able to get enough power to arm
3623  any wake events that it might want to deliver (like PME#.)
3624 
3625  Consequently, the designers of the PnP/Power model in the Framework have
3626  decided that all QueryPower-Sx IRPs will be completed successfully
3627  except if the device cannot maintain enough power to trigger its wake
3628  signal *AND* if the system supports lighter sleep states than the
3629  one that is currently being queried. (If it does, then the kernel's power
3630  manager will turn right around and query for those, next.)
3631 
3632  This story usually brings up a few objections:
3633 
3634  1) My device is important! When it's operating, I don't want
3635  the machine to just fall asleep. I need to fail QueryPower-Sx to
3636  prevent that.
3637 
3638  This objection is an unfortunate consequence of the existing DDK. There
3639  is a perfectly good API that allows a driver to say that the machine
3640  shouldn't just fall asleep. (See PoSetSystemState.) If a user presses
3641  a button telling the machine to go to sleep, then the driver has a
3642  responsibility to do that.
3643 
3644  2) There are certain operations that just can't be interrupted!
3645 
3646  While that's true, those operations started somewhere, probably in user-
3647  mode. Those same user-mode components would be much, much better suited
3648  toward negotiating with the user or with other components to figure out
3649  what to do when the uninterruptable must be interrupted. User-mode
3650  components get notification that the system is going to sleep and they
3651  can delay or veto the transition. Get over the idea that your driver
3652  needs to be involved, too.
3653 
3654 Routine Description:
3655 
3656  Determines if for the passed in System state, if we can wake the machine
3657  from it. If the query state is the machine's minimum system state, then
3658  we always succeed it because we want the machine to go to at least some
3659  sleeping state. We always succeed hibernate and system off requests as well.
3660 
3661 Arguments:
3662 
3663  QueryState - The proposed system state
3664 
3665 Return Value:
3666 
3667  NT_SUCCESS if the queried state should be allowed, !NT_SUCCESS otherwise
3668 
3669  --*/
3670 {
3671  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
3672  NTSTATUS status;
3673 
3674  if (QueryState >= PowerSystemHibernate ||
3675  PowerPolicyCanWakeFromSystemState(QueryState)) {
3676  //
3677  // If the query is for the machine's minimum S state or we going into
3678  // hibernate or off, always succeed it.
3679  //
3681  }
3682  else {
3683 
3684  //
3685  // On Windows Vista and above, its OK to return a failure status code
3686  // if the system is going into an S state at which the device cannot
3687  // wake the system.
3688  //
3690 
3691  //
3692  // The S state the machine is going into is one where we can't
3693  // wake it up because our D state is too low for this S state.
3694  // Since this isn't the minimum S state the machine is capable
3695  // of, reject the current query.
3696  //
3698  FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP,
3699  "failing system query power because the device cannot wake the "
3700  "machine from S%d",
3701  QueryState - 1);
3702 
3704  }
3705 
3706  return status;
3707 }
3708 
3709 VOID
3712  )
3713 {
3717 }
3718 
3719 VOID
3722  )
3723 /*++
3724 
3725 Routine Description:
3726  Sets the wake from Sx state
3727 
3728  No need to post an event to the power policy state machine because we
3729  will not change any active due to a change in this setting. We only
3730  evaluate this state when going into Sx and once in this state we will not
3731  change our behavior until the next Sx, which will then evaluate this state.
3732 
3733 Arguments:
3734  State - New state
3735 
3736 Return Value:
3737  VOID
3738 
3739  --*/
3740 {
3743 
3744  //
3745  // Since we are not posting an event to the power policy state machine, try
3746  // to write out the value now, otherwise it will be written when we
3747  // transition
3748  //
3750  NTSTATUS status;
3751  LONGLONG timeout;
3752 
3753  timeout = 0;
3754 
3755  //
3756  // If the lock is already acquired on this thread, this will fail, which
3757  // is OK.
3758  //
3760  GetDriverGlobals(),
3761  &timeout
3762  );
3763 
3764  if (FxWaitLockInternal::IsLockAcquired(status)) {
3765  SaveState(TRUE);
3766 
3769  );
3770  }
3771  }
3772 }
3773 
3774 VOID
3777  )
3778 /*++
3779 
3780 Routine Description:
3781  Marks the device as a victim of catastrophic failure, either in software
3782  or in hardware.
3783 
3784  If AttemptToRestart is TRUE, then we should try to get the stack re-built
3785  after it has been torn down. This would typically be the case the failure
3786  was in the software, and possibly not be the case if the failure was in
3787  the hardware.
3788 
3789 Arguments:
3790  FailedAction - action to take once the stack has been removed
3791 
3792 Return Value:
3793  None
3794 
3795  --*/
3796 {
3797  NTSTATUS status;
3798  MdDeviceObject pdo;
3799 
3800 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
3801  if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(2, 15) == FALSE &&
3803 
3807  "WdfDeviceFailedAttemptRestart is only available for UMDF 2.15 "
3808  "and later drivers. Reverting to WdfDeviceFailedNoRestart.");
3809  }
3810 #endif
3811 
3813 
3814  //
3815  // This will cause the PnP manager to tear down this stack, even if
3816  // the PDO can't be surprise-removed.
3817  //
3818  m_Failed = TRUE;
3819 
3821  //
3822  // Attempt to get the PDO surprise-removed.
3823  //
3825 
3826  if (NT_SUCCESS(status)) {
3827  return;
3828  }
3829  }
3830 
3831 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
3832  //
3833  // In between creating a PDO WDFDEVICE and it starting, if this DDI is called,
3834  // we will not have a valid PDO. Make sure it is valid before we proceed.
3835  //
3837 
3838  if (pdo != NULL) {
3839  //
3840  // Now tell the PnP manager to re-query us for our state.
3841  //
3842  MxDeviceObject physicalDeviceObject(pdo);
3843 
3844  physicalDeviceObject.InvalidateDeviceState(
3846  );
3847  }
3848 #else // USER_MODE
3852 #endif
3853 }
3854 
3856 NTSTATUS
3859  __inout FxIrp *Irp
3860  )
3861 {
3862  return This->PnpDeviceUsageNotification(Irp);
3863 }
3864 
3866 NTSTATUS
3868  __inout FxIrp* Irp
3869  )
3870 {
3872  FxRelatedDevice *pDependent;
3873  FxAutoIrp relatedIrp(NULL), parentIrp(NULL);
3874  MxDeviceObject topOfParentStack;
3876  NTSTATUS status;
3877  MxDeviceObject pAttached;
3878  MdIrp pNewIrp;
3879  CCHAR maxStack;
3880  BOOLEAN inPath, supported;
3881  ULONG oldFlags;
3882  MxAutoWorkItem workItem;
3883 
3885  "Entering DeviceUsageNotification handler");
3886 
3888 
3889  type = Irp->GetParameterUsageNotificationType();
3890  inPath = Irp->GetParameterUsageNotificationInPath();
3891  supported = FALSE;
3892 
3895  "type %x, in path %x, can support paging %x, dump file %x, "
3896  "hiber file %x, boot file %x",
3897  type, inPath,
3902 
3903 
3904  if (type >= static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFilePaging)
3905  && type < static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileMax)) {
3906  if (inPath) {
3907  if (m_Device->IsFilter()) {
3908  //
3909  // Filters always support usage notifications
3910  //
3911  supported = TRUE;
3912  }
3913  else {
3914  supported = IsUsageSupported(type);
3915  }
3916  }
3917  else {
3918  //
3919  // We always handle notifications where we are out of the path
3920  //
3921  supported = TRUE;
3922  }
3923  }
3924 
3925  if (supported == FALSE) {
3927 
3930  "Usage type %x not supported, %!STATUS!", type, status);
3931 
3932  return CompletePnpRequest(Irp, status);
3933  }
3934 
3935  //
3936  // Usage notification IRP gets forwarded to parent stack or to
3937  // dependent stack. Since in such cases (with deep device tree) the stack
3938  // may run out quickly, ensure there is enough stack, otherwise use a
3939  // workitem.
3940  //
3942  (m_Device->IsPdo() ||
3944 
3945  status = workItem.Allocate(m_Device->GetDeviceObject());
3946  if (!NT_SUCCESS(status)) {
3949  "WDFDEVICE %p !devobj %p could not allocate workitem "
3950  "to send usage notification type %d, inpath %d, %!STATUS!",
3951  m_Device->GetHandle(),
3953  type, inPath, status);
3954 
3955  return CompletePnpRequest(Irp, status);
3956  }
3957  }
3958 
3959  //
3960  // Usage notification is supported. Set the flags on the device object
3961  // before processing this any further and save the current flags on the
3962  // device object.
3963  //
3964  oldFlags = SetUsageNotificationFlags(type, inPath);
3965 
3966  if (m_Device->IsPdo()) {
3967 
3968 
3969 
3970 
3971 
3972 
3973 
3974 
3975 
3976 
3977 
3978 
3979  topOfParentStack.SetObject(
3981 
3982  pNewIrp = FxIrp::AllocateIrp(topOfParentStack.GetStackSize());
3983  if (pNewIrp != NULL) {
3984  parentIrp.SetIrp(pNewIrp);
3985 
3986  //
3987  // parentIrp now owns the irp
3988  //
3989  pNewIrp = NULL;
3990 
3991  status = SendDeviceUsageNotification(&topOfParentStack,
3992  &parentIrp,
3993  &workItem,
3994  Irp,
3995  FALSE);
3996  }
3997  else {
3999 
4002  "WDFDEVICE %p could not allocate PIRP for parent !devobj %p to "
4003  "send usage notification type %d, inpath %d, %!STATUS!",
4004  m_Device->GetHandle(), topOfParentStack.GetObject(),
4005  type, inPath, status);
4006  }
4007  topOfParentStack.DereferenceObject();
4008  topOfParentStack.SetObject(NULL);
4009 
4010  if (!NT_SUCCESS(status)) {
4012  "Exit %!STATUS!", status);
4013 
4014  RevertUsageNotificationFlags(type, inPath, oldFlags);
4015  return CompletePnpRequest(Irp, status);
4016  }
4017  }
4018 
4019  maxStack = 0;
4020  pDependent = NULL;
4021 
4022  //
4023  // If the driver supports the given special file, lets notify dependent
4024  // stacks.
4025  //
4026 
4027  //
4028  // LockForEnum will lock out new changes to the list until we unlock the list.
4029  // We remain at passive level once we are locked.
4030  //
4032  //
4033  // We capture the m_UsageDependentDeviceList pointer value so that we
4034  // always use the same pointer value and that we have matched actions
4035  // (lock for enum / unlock from enum). What we are trying to avoid is
4036  // this:
4037  // 1) we do not lock for enum because m_UsageDependentDeviceList == NULL
4038  // 2) in the middle of this function, m_UsageDependentDeviceList is
4039  // assigned a pointer value
4040  // 3) we try to unlock from enum later (or iterate, thinking the enum
4041  // lock is held) by checking m_UsageDependentDeviceList for NULL, and
4042  // now that is != NULL, use it.
4043  //
4044  // By capturing the pointer now, we either have a list or not and we don't
4045  // hit situations 2 or 3. So, the rule is every subseqeunt time we need
4046  // to check if there is valid m_UsageDependentDeviceList pointer, we
4047  // use pList, but when we use the list, we can use m_UsageDependentDeviceList
4048  // directly.
4049  //
4051 
4053 
4054  while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4055 
4056  MxDeviceObject deviceObject(pDependent->GetDevice());
4057 
4058 
4059 
4060 
4061 
4062 
4063 
4064 
4065 
4066 
4067 
4068 
4069 
4071 
4072  if (pAttached.GetStackSize() > maxStack) {
4073  maxStack = pAttached.GetStackSize();
4074  }
4075 
4076  pAttached.DereferenceObject();
4077  }
4078  }
4079  else {
4080  pList = NULL;
4081  }
4082 
4083  if (maxStack > 0) {
4084  //
4085  // If we have a maxStack size, we have a list as well
4086  //
4088 
4089  //
4090  // Allocate one irp for all the stacks so that we don't have an
4091  // allocation later. This way, once we have the irp, we can send the
4092  // usage notification to all stacks reliably, as well as the reverting
4093  // of the notification if we encounter failure.
4094  //
4095  pNewIrp = FxIrp::AllocateIrp(maxStack);
4096  if (pNewIrp == NULL) {
4098 
4101  "WDFDEVICE %p could not allocate IRP to send usage notifications"
4102  " to related stacks, type %d, inpath %d, status %!STATUS!",
4103  m_Device->GetHandle(), type, inPath, status);
4104  }
4105  else {
4106  MxDeviceObject dependentDevice;
4107 
4108  //
4109  // relatedIrp will free the irp when it goes out of scope
4110  //
4111  relatedIrp.SetIrp(pNewIrp);
4112 
4113  //
4114  // Walk our collection of dependent device stacks, and notify
4115  // each stack of the device notification. If any fail, notify
4116  // the stacks who already were told of the reverted behavior.
4117  //
4118  pDependent = NULL;
4119  while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4120  dependentDevice.SetObject(pDependent->GetDevice());
4121  status = SendDeviceUsageNotification(&dependentDevice,
4122  &relatedIrp,
4123  &workItem,
4124  Irp,
4125  FALSE);
4126 
4127  if (!NT_SUCCESS(status)) {
4128  FxRelatedDevice* pDependent2;
4129 
4130  pDependent2 = NULL;
4131 
4132  //
4133  // A device failed the device usage notification request.
4134  // Notify the stacks that didn't fail, so they can unwind
4135  // the operation.
4136  //
4137  while ((pDependent2 = m_UsageDependentDeviceList->GetNextEntry(pDependent2)) != NULL &&
4138  pDependent2 != pDependent) {
4139  dependentDevice.SetObject(pDependent2->GetDevice());
4140 
4141  //
4142  // We're already in a failure path. We can't do anything
4143  // about yet another failure. So we ignore the return
4144  // value.
4145  //
4146  (void) SendDeviceUsageNotification(&dependentDevice,
4147  &relatedIrp,
4148  &workItem,
4149  Irp,
4150  TRUE);
4151  }
4152 
4153  //
4154  // Now break out of our outter loop.
4155  //
4156  break;
4157  }
4158  }
4159  }
4160  }
4161 
4162  //
4163  // If we are successful to this point, then send the IRP down the
4164  // stack.
4165  //
4166  if (NT_SUCCESS(status)) {
4167  BOOLEAN referenceSucceeded, sendDown;
4168 
4169  referenceSucceeded = FALSE;
4170  sendDown = TRUE;
4171 
4172  //
4173  // Make sure the stack is in D0 before sending down the request. This
4174  // will at least guarantee that all devices below this one are in D0
4175  // when the make the transition from power pageable to non or vice versa.
4176  //
4177  if (IsPowerPolicyOwner()) {
4179 
4180  if (NT_SUCCESS(status)) {
4181  referenceSucceeded = TRUE;
4182  }
4183  else {
4184  Irp->SetStatus(status);
4185  sendDown = FALSE;
4186  }
4187  }
4188 
4189  if (sendDown) {
4190  //
4191  // If we supported the usage, set the status to success, otherwise we
4192  // keep the status in the irp as it arrived to this device
4193  //
4194  if (supported) {
4195  Irp->SetStatus(status);
4196  }
4198  }
4199 
4200  //
4201  // Transitioning from a thread which was power pagable to non power
4202  // pagable. We now need a power thread for the stack, ask for it.
4203  // Note that there is no need for power thread in case of "boot"
4204  // notification since boot notification doesn't require clearing device's
4205  // DO_POWER_PAGABLE flag (power thread is required when handling power
4206  // irp at dispatch level which can happen if the DO_POWER_PAGABLE flag
4207  // is cleared).
4208  //
4209  // NOTE: Once we have a power thread, we never go back to using work
4210  // items even though the stack may revert to power pagable.
4211  // This is an acceptable tradeoff between resource usage and
4212  // WDF complexity.
4213  //
4214  //
4215  if (NT_SUCCESS(status) &&
4216  inPath &&
4217  (HasPowerThread() == FALSE) &&
4218  type != static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileBoot)
4219  ) {
4221 
4222  if (!NT_SUCCESS(status)) {
4223  //
4224  // Keep status the same through out so we can set it back in
4225  // the irp when we are done.
4226  //
4227  if (m_Device->IsPdo()) {
4228  //
4229  // need to revert our parent's stack
4230  //
4231 
4232 
4233 
4234 
4235 
4236 
4237 
4238 
4239 
4240 
4241 
4242 
4243  topOfParentStack.SetObject(
4245 
4246  //
4247  // Ignore the status because we can't do anything on failure
4248  //
4249  (void) SendDeviceUsageNotification(&topOfParentStack,
4250  &parentIrp,
4251  &workItem,
4252  Irp,
4253  TRUE);
4254 
4255  topOfParentStack.DereferenceObject();
4256  }
4257  else {
4258  //
4259  // Notify the stack below us
4260  //
4261  Irp->CopyCurrentIrpStackLocationToNext();
4262  Irp->SetParameterUsageNotificationInPath(FALSE);
4263 
4264  //
4265  // Required for pnp irps
4266  //
4267  Irp->SetStatus(STATUS_NOT_SUPPORTED);
4268 
4269  //
4270  // Ignore the status because we can't do anything on failure
4271  //
4272  (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
4273  }
4274 
4275  Irp->SetStatus(status);
4276  }
4277  }
4278 
4279  //
4280  // Now check whether the lower devices succeeded or failed. If they
4281  // failed, back out our changes and propogate the failure.
4282  //
4283  if (!NT_SUCCESS(status)) {
4284  //
4285  // Revert the flags set on the device object.
4286  //
4287  RevertUsageNotificationFlags(type, inPath, oldFlags);
4288 
4289  //
4290  // Notify dependent stacks of the failure.
4291  //
4292  pDependent = NULL;
4293 
4294  //
4295  // See pList initiatilazation as to why we compare pList for != NULL
4296  // and not m_UsageDependentDeviceList.
4297  //
4298  if (pList != NULL) {
4299  MxDeviceObject dependentDevice;
4300 
4301  while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4302  dependentDevice.SetObject(pDependent->GetDevice());
4303 
4304  //
4305  // We're already in a failure path. We can't do anything
4306  // about yet another failure. So we ignore the return value.
4307  //
4308  (void) SendDeviceUsageNotification(&dependentDevice,
4309  &relatedIrp,
4310  &workItem,
4311  Irp,
4312  TRUE);
4313  }
4314  }
4315  }
4316 
4317  //
4318  // By this point, we have propagated the notification to dependent devices
4319  // and lower stack, and if anyone failed during that time, we also
4320  // propagated failure to dependent stacks and lower stack.
4321  // If status is success at this point, invoke the driver's callback.
4322  //
4323  if (NT_SUCCESS(status)) {
4324  //
4325  // Invoke callback. Note that only one of the callbacks
4326  // DeviceUsageNotification or DeviceUsgeNotificationEx will get
4327  // invoked since only one of the callbacks at a time is supported.
4328  // We ensured that during registration of the callback.
4329  // Note that Ex callback will return success if driver did not
4330  // supply any callback.
4331  //
4334  inPath);
4335 
4337  m_Device->GetHandle(),
4339  inPath
4340  );
4341 
4342  if (!NT_SUCCESS(status)) {
4343  //
4344  // Driver's callback returned failure. We need to propagate
4345  // failure to lower stack and dependent stacks.
4346  //
4347  //
4348  // Keep status the same through out so we can set it back in
4349  // the irp when we are done.
4350  //
4351  if (m_Device->IsPdo()) {
4352  //
4353  // need to revert our parent's stack
4354  //
4355 
4356 
4357 
4358 
4359 
4360 
4361 
4362 
4363 
4364 
4365 
4366 
4367  topOfParentStack.SetObject(
4369 
4370  //
4371  // Ignore the status because we can't do anything on failure
4372  //
4373  (void) SendDeviceUsageNotification(&topOfParentStack,
4374  &parentIrp,
4375  &workItem,
4376  Irp,
4377  TRUE);
4378 
4379  topOfParentStack.DereferenceObject();
4380  }
4381  else {
4382  //
4383  // Notify the stack below us
4384  //
4385  Irp->CopyCurrentIrpStackLocationToNext();
4386  Irp->SetParameterUsageNotificationInPath(FALSE);
4387 
4388  //
4389  // Required for pnp irps
4390  //
4391  Irp->SetStatus(STATUS_NOT_SUPPORTED);
4392 
4393  //
4394  // Ignore the status because we can't do anything on failure
4395  //
4396  (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice());
4397  }
4398 
4399  Irp->SetStatus(status);
4400 
4401  //
4402  // Revert the flags set on the device object.
4403  //
4404  RevertUsageNotificationFlags(type, inPath, oldFlags);
4405 
4406  //
4407  // Notify dependent stacks of the failure.
4408  //
4409  pDependent = NULL;
4410 
4411  //
4412  // See pList initiatilazation as to why we compare pList for != NULL
4413  // and not m_UsageDependentDeviceList.
4414  //
4415  if (pList != NULL) {
4416  MxDeviceObject dependentDevice;
4417 
4418  while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) {
4419  dependentDevice.SetObject(pDependent->GetDevice());
4420 
4421  //
4422  // We're already in a failure path. We can't do anything
4423  // about yet another failure. So we ignore the return value.
4424  //
4425  (void) SendDeviceUsageNotification(&dependentDevice,
4426  &relatedIrp,
4427  &workItem,
4428  Irp,
4429  TRUE);
4430  }
4431  }
4432  }
4433 
4434  if (NT_SUCCESS(status)) {
4435 
4436  CommitUsageNotification(type, oldFlags);
4437 
4438  //
4439  // If we are in the dump file path, we cannot idle out because we
4440  // can experience a crash dump at any time.
4441  //
4443  //
4444  // Add a reference everytime we are notified of being in the
4445  // path, no need to match the first inPath notification and the
4446  // last !inPath notification.
4447  //
4448  if (inPath) {
4449  NTSTATUS refStatus;
4450 
4451  ASSERT(GetUsageCount(type) > 0);
4452 
4453  //
4454  // Since our previous synchronous power reference succeeded,
4455  // an addtional reference while we are powered up should
4456  // never fail.
4457  //
4458  refStatus = PowerReference(FALSE);
4459 #if DBG
4460  ASSERT(NT_SUCCESS(refStatus));
4461 #else
4462  UNREFERENCED_PARAMETER(refStatus);
4463 #endif
4464  }
4465  else {
4466  ASSERT(GetUsageCount(type) >= 0);
4467  PowerDereference();
4468  }
4469  }
4470  }
4471  }
4472 
4473  //
4474  // We no longer need to be in D0 if we don't have to be.
4475  //
4476  if (referenceSucceeded) {
4478  PowerDereference();
4479  }
4480  }
4481 
4482  //
4483  // See pList initiatilazation as to why we compare pList for != NULL
4484  // and not m_UsageDependentDeviceList.
4485  //
4486  if (pList != NULL) {
4488  }
4489 
4491  "Exit %!STATUS!", status);
4492 
4493  return CompletePnpRequest(Irp, status);
4494 }
4495 
4496 ULONG
4499  __in BOOLEAN InPath
4500  )
4501 /*++
4502 
4503 Routine Description:
4504 
4505  This routine sets the usage notification flags on the device object (for
4506  non-boot usages) and updates the special file usage count .
4507 
4508 Arguments:
4509 
4510  Type - the special file type - paging, hibernate, dump or boot file.
4511 
4512  InPath - indicates whether the system is creating or removing the special
4513  file on the device.
4514 
4515 Return Value:
4516 
4517  Returns the old flags on the device object.
4518 
4519 --*/
4520 {
4521  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4522  ULONG oldFlags, newFlags;
4523 
4524  oldFlags = m_Device->GetDeviceObjectFlags();
4525 
4526  //
4527 
4528  //
4530  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
4531  "Before: type %d, in path %d, special count %d, flags 0x%x, "
4532  "device %p (WDFDEVICE %p), is pageable capable %d",
4533  Type, InPath, GetUsageCount(Type), oldFlags,
4536 
4537  //
4538  // Adjust our "special file count".
4539  //
4540  AdjustUsageCount(Type, InPath);
4541 
4542  //
4543  // Boot notification doesn't require updating device flags.
4544  //
4545  if (Type == static_cast<DEVICE_USAGE_NOTIFICATION_TYPE>(WdfSpecialFileBoot)) {
4546  return oldFlags;
4547  }
4548 
4549  if (m_Device->IsFilter()) {
4550  //
4551  // Clear the previous flags and reset them to the attached
4552  // device's flags
4553  //
4554  newFlags = oldFlags & ~(DO_POWER_PAGABLE | DO_POWER_INRUSH);
4555  newFlags |= m_Device->GetAttachedDeviceObjectFlags() &
4557  m_Device->SetDeviceObjectFlags(newFlags);
4558  }
4559  else {
4560  if (InPath) {
4563  );
4564  }
4565  else {
4569  );
4570  }
4571  }
4572  }
4573 
4574  return oldFlags;
4575 }
4576 
4577 VOID
4580  __in BOOLEAN InPath,
4582  )
4583 /*++
4584 
4585 Routine Description:
4586 
4587  This routine reverts the usage notification flags to the old flags on
4588  the device object and updates the special file usage count.
4589 
4590 Arguments:
4591 
4592  Type - the special file type - paging, hibernate or dump file.
4593 
4594  InPath - indicates whether the system is creating or removing the special
4595  file on the device.
4596 
4597  OldFlags - the previous flags on the device object.
4598 
4599 --*/
4600 {
4601  //
4602  // Re-adjust our "special file count".
4603  //
4604  InPath = !InPath;
4605  AdjustUsageCount(Type, InPath);
4606 
4607  //
4608  // Restore the flags on the device object.
4609  //
4611 }
4612 
4613 VOID
4617  )
4618 /*++
4619 
4620 Routine Description:
4621 
4622  This routine commits the usage notification flags on the device object
4623  and invokes the usage notification callbacks. If the current flags on
4624  the device object indicates that there was a transition from power-pagable
4625  to non power-pagable, or vice-versa, then an event is posted to the power
4626  state machine to notify it of the change. After this routine is called
4627  the PNP manager will no longer be able to disable the device.
4628 
4629 Arguments:
4630 
4631  Type - the special file type - paging, hibernation or crash dump file.
4632 
4633  InPath - indicates whether the system is creating or removing the special
4634  file on the device.
4635 
4636  OldFlags - the previous flags on the device object.
4637 
4638 --*/
4639 {
4640  PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
4641  ULONG newFlags;
4642 
4643  newFlags = m_Device->GetDeviceObjectFlags();
4644 
4646  (newFlags & DO_POWER_PAGABLE) == 0) {
4647  //
4648  // We transitioned from a power pageable to a non power pageable
4649  // device. Move the power state machine to the appropriate
4650  // state.
4651  //
4653  }
4654 
4655  if ((OldFlags & DO_POWER_PAGABLE) == 0 &&
4656  (newFlags & DO_POWER_PAGABLE) == DO_POWER_PAGABLE) {
4657  //
4658  // We transitioned from a non power pageable to a power pageable
4659  // device. Move the power state machine to the appropriate
4660  // state.
4661  //
4663  }
4664 
4665  //
4666  // Notify PNP that it should no longer be able
4667  // to disable this device.
4668  //
4669  MxDeviceObject physicalDeviceObject(
4671  );
4672  physicalDeviceObject.InvalidateDeviceState(
4674  );
4675 
4677  FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP,
4678  "After: special count %d, flags 0x%x, device %p (WDFDEVICE %p)",
4679  GetUsageCount(Type), newFlags,
4681 }
4682 
4684 NTSTATUS
4687  )
4688 {
4689  FxRelatedDevice* pRelated;
4690  NTSTATUS status;
4691 
4693  KIRQL irql;
4694 
4695  Lock(&irql);
4698 
4701  }
4702  else {
4704 
4707  "Could not allocate usage device list for WDFDEVICE %p, "
4708  "%!STATUS!", m_Device->GetHandle(), status);
4709  }
4710 
4711  }
4712  else {
4713  //
4714  // another thread allocated the list already
4715  //
4717  }
4718  Unlock(irql);
4719 
4720  if (!NT_SUCCESS(status)) {
4721  return status;
4722  }
4723  }
4724 
4725  pRelated = new(GetDriverGlobals())
4727 
4728  if (pRelated == NULL) {
4730  }
4731 
4733 
4734  if (!NT_SUCCESS(status)) {
4735  pRelated->DeleteFromFailedCreate();
4736  }
4737 
4738  return status;
4739 }
4740 
4741 VOID
4744  )
4745 {
4748  }
4749 }
4750 
4752 NTSTATUS
4755  )
4756 {
4757  FxRelatedDevice* pRelated;
4758  NTSTATUS status;
4759 
4760  if (m_RemovalDeviceList == NULL) {
4761  KIRQL irql;
4762 
4763  Lock(&irql);
4764  if (m_RemovalDeviceList == NULL) {
4766 
4767  if (m_RemovalDeviceList != NULL) {
4769  }
4770  else {
4772 
4775  "Could not allocate removal device list for WDFDEVICE %p, "
4776  "%!STATUS!", m_Device->GetHandle(), status);
4777  }
4778  }
4779  else {
4780  //
4781  // another thread allocated the list already
4782  //
4784  }
4785  Unlock(irql);
4786 
4787  if (!NT_SUCCESS(status)) {
4788  return status;
4789  }
4790  }
4791 
4792  pRelated = new(GetDriverGlobals())
4794  if (pRelated == NULL) {
4796  }
4797 
4799 
4800  if (NT_SUCCESS(status)) {
4801  //
4802  // RemovalRelations are queried automatically by PnP when the device is
4803  // going to be query removed. No need to tell pnp that the list changed
4804  // until it needs to query for it.
4805  //
4806  DO_NOTHING();
4807  }
4808  else {
4809  pRelated->DeleteFromFailedCreate();
4810  }
4811 
4812  return status;
4813 }
4814 
4815 VOID
4818  )
4819 {
4820  if (m_RemovalDeviceList != NULL) {
4822  }
4823 
4824  //
4825  // RemovalRelations are queried automatically by PnP when the device is
4826  // going to be query removed. No need to tell pnp that the list changed
4827  // until it needs to query for it.
4828  //
4829 }
4830 
4831 VOID
4833  VOID
4834  )
4835 {
4837 
4838  if (m_RemovalDeviceList == NULL) {
4839  return;
4840  }
4841 
4843  while ((pEntry = m_RemovalDeviceList->GetNextEntry(NULL)) != NULL) {
4845  }
4847 
4848  //
4849  // RemovalRelations are queried automatically by PnP when the device is
4850  // going to be query removed. No need to tell pnp that the list changed
4851  // until it needs to query for it.
4852  //
4853 }
4854 
4855 VOID
4857  VOID
4858  )
4859 /*++
4860 
4861 Routine Description:
4862  Sets the failure field and then optionally invalidates the device state.
4863 
4864 Arguments:
4865  InvalidateState - If TRUE, the state is invalidated
4866 
4867 Return Value:
4868  None
4869 
4870  --*/
4871 {
4873 
4874  MxDeviceObject physicalDeviceObject(
4876  );
4877  physicalDeviceObject.InvalidateDeviceState(
4879  );
4880 }
4881 
4882 VOID
4884  __inout FxIrp* Irp,
4885  __in BOOLEAN MarkIrpPending
4886  )
4887 {
4888  if (m_PendingPnPIrp != NULL ) {
4889  FxIrp pendingIrp(m_PendingPnPIrp);
4890 
4891  //
4892  // A state changing pnp irp is already pended. If we don't bugcheck
4893  // the pended pnp irp will be overwritten with new pnp irp and the old
4894  // one may never get completed, which may have drastic implications (
4895  // unresponsive system, power manager not sending Sx Irp etc.)
4896  //
4898  "A new state changing pnp irp %!pnpmn! IRP %p arrived while another "
4899  "pnp irp %!pnpmn! IRP %p is still pending WDFDEVICE %p\n",
4900  Irp->GetMinorFunction(), Irp->GetIrp(),
4901  pendingIrp.GetMinorFunction(),pendingIrp.GetIrp(),
4902  m_Device->GetHandle());
4903 
4904  FxVerifierBugCheck(GetDriverGlobals(), // globals
4905  WDF_PNP_FATAL_ERROR, // specific type
4906  (ULONG_PTR)m_Device->GetHandle(), //parm 2
4907  (ULONG_PTR)Irp->GetIrp()); // parm 3
4908 
4909  /* NOTREACHED */
4910  return;
4911  }
4912  if (MarkIrpPending) {
4913  Irp->MarkIrpPending();
4914  }
4915  m_PendingPnPIrp = Irp->GetIrp();
4916 }
4917 
4919 NTSTATUS
4921  VOID
4922  )
4923 {
4924  KIRQL irql;
4925  NTSTATUS status;
4926 
4927  if (m_EnumInfo != NULL) {
4928  return STATUS_SUCCESS;
4929  }
4930 
4931  Lock(&irql);
4932  if (m_EnumInfo == NULL) {
4934 
4935  if (m_EnumInfo != NULL) {
4937 
4938  if (!NT_SUCCESS(status)) {
4939  delete m_EnumInfo;
4940  m_EnumInfo = NULL;
4941 
4943  TRACINGPNP,
4944  "Could not initialize enum info for "
4945  "WDFDEVICE %p, %!STATUS!",
4946  m_Device->GetHandle(), status);
4947  }
4948 
4949  }
4950  else {
4952 
4954  "Could not allocate enum info for WDFDEVICE %p, "
4955  "%!STATUS!", m_Device->GetHandle(), status);
4956  }
4957  }
4958  else {
4959  //
4960  // another thread allocated the list already
4961  //
4963  }
4964  Unlock(irql);
4965 
4966  return status;
4967 }
4968 
4969 VOID
4972  )
4973 {
4975  "Adding FxChildList %p, WDFCHILDLIST %p", List,
4976  List->GetHandle());
4977 
4979  &List->m_TransactionLink);
4980 }
4981 
4982 VOID
4985  )
4986 {
4988  "Removing FxChildList %p, WDFCHILDLIST %p", List,
4989  List->GetHandle());
4990 
4991  m_EnumInfo->m_ChildListList.Remove(GetDriverGlobals(), &List->m_TransactionLink);
4992 
4993  //
4994 
4995  //
4996 }
4997 
4998 VOID
5000  __inout PLONG PendingCount
5001  )
5002 {
5004 
5005  ple = NULL;
5006 
5007  if (m_EnumInfo != NULL) {
5009  while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) {
5011  }
5013  }
5014 }
5015 
5016 VOID
5019  __in BOOLEAN Lock
5020  )
5021 /*++
5022 
5023 Routine Description:
5024  Add a query interface structure to the list of interfaces supported
5025 
5026 Arguments:
5027  QI - the interface to add
5028 
5029  Lock - indication of the list lock should be acquired or not
5030 
5031 Return Value:
5032  None
5033 
5034  --*/
5035 {
5037 
5038  if (Lock) {
5039  m_QueryInterfaceLock.AcquireLock(GetDriverGlobals());
5040  }
5041 
5042  ASSERT(QI->m_Entry.Next == NULL);
5043 
5044  //
5045  // Iterate until we find the end of the list and then append the new
5046  // structure. ppPrev is the pointer to the Next pointer value. When we
5047  // get to the end, ppPrev will be equal to the Next field which points to NULL.
5048  //
5051 
5052  while (pCur != NULL) {
5053  ppPrev = &pCur->Next;
5054  pCur = pCur->Next;
5055  }
5056 
5057  *ppPrev = &QI->m_Entry;
5058 
5059  if (Lock) {
5060  m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals());
5061  }
5062 }
5063 
5068 VOID
5070  __in PKDPC Dpc,
5074  )
5075 /*++
5076 
5077 Routine Description:
5078 
5079  This routine's job is to crash the machine, attempting to get some data
5080  into the crashdump file (or minidump) about why the machine stopped
5081  responding during an attempt to put the machine to sleep.
5082 
5083 Arguments:
5084 
5085  This - the instance of FxPkgPnp
5086 
5087 Return Value:
5088 
5089  this routine never returns
5090 
5091 --*/
5092 {
5094  FxWatchdog* pThis;
5095  CfxDevice* pDevice;
5096 
5100 
5101  pThis = (FxWatchdog*) Context;
5102  pDevice = pThis->m_PkgPnp->GetDevice();
5103 
5106  "The driver failed to return from a callback routine "
5107  "in a reasonable period of time. This prevented the "
5108  "machine from going to sleep or from hibernating. The "
5109  "machine crashed because that was the best way to get "
5110  "data about the cause of the crash into a minidump file.");
5111 
5112  data.PowerState = pDevice->GetDevicePowerState();
5113  data.PowerPolicyState = pDevice->GetDevicePowerPolicyState();
5115  data.Device = pDevice->GetHandle();
5116  data.TimedOutThread = reinterpret_cast<PKTHREAD>(pThis->m_CallingThread);
5117 
5120  (ULONG_PTR) &data);
5121 }
5122 
5124 NTSTATUS
5126  VOID
5127  )
5128 /*++
5129 
5130 Routine Description:
5131  Creates a power thread for the device node. This thread is share among all
5132  the devices in the stack through the POWER_THREAD_INTERFACE structure and
5133  PnP query interface.
5134 
5135 Arguments:
5136  None
5137 
5138 Return Value:
5139  NTSTATUS
5140 
5141  --*/
5142 {
5143  FxSystemThread *pThread, *pOld;
5144  NTSTATUS status;
5145 
5147  &pThread,
5148  GetDriverGlobals(),
5149  m_Device->GetHandle(),
5151 
5152  if (!NT_SUCCESS(status)) {
5153  return status;
5154  }
5155 
5156  //
5157  // Simple locking logic in case N requests are conncurrent. (The requests
5158  // never should be concurrent, but in the case that there are 2 usage
5159  // notifications coming in from two different sources, it could
5160  // theoritically happen.)
5161  //
5163  (PVOID*) &m_PowerThread, pThread, NULL);
5164 
5165  if (pOld != NULL) {
5166  //
5167  // Someone also set the thread pointer value at the same time, free
5168  // our new one here.
5169  //
5170  pThread->ExitThread();
5171  pThread->DeleteObject();
5172  }
5173 
5175 
5176  return STATUS_SUCCESS;
5177 }
5178 
5179 VOID
5181  VOID
5182  )
5183 /*++
5184 
5185 Routine Description:
5186  If this device is the owner of the power thread, it kills the thread.
5187  Otherwise, if this device has acquired the thread from a lower device,
5188  release the reference now.
5189 
5190 Arguments:
5191  None
5192 
5193 Return Value:
5194  None
5195 
5196  --*/
5197 {
5198  BOOLEAN hadThread;
5199 
5200  hadThread = m_HasPowerThread;
5201 
5202  //
5203  // Set to FALSE before cleaning up the reference or thread itself in case
5204  // there is some other context trying to enqueue. The only way that could
5205  // be happening is if the power policy owner is not WDF and sends power irps
5206  // after query remove or surprise remove.
5207  //
5209 
5210  //
5211  // Check for ownership
5212  //
5213  if (m_PowerThread != NULL) {
5214 
5215  FxCREvent event;
5216 
5217  //
5218  // Event on stack is used, which is fine since this code is invoked
5219  // only in KM. Verify this assumption.
5220  //
5221  // If this code is ever needed for UM, m_PowerThreadEvent should be
5222  // pre-initialized (simlar to the way m_RemoveEventUm is used)
5223  //
5225 
5228 
5230  //
5231  // Wait for all references to go away before exitting the thread.
5232  // A reference will be taken for every device in the stack above this
5233  // one which queried for the interface.
5234  //
5235  event.EnterCRAndWaitAndLeave();
5236  }
5237 
5239 
5240  //
5241  // Wait for the thread to exit and then delete it. Since we have
5242  // turned off the power policy state machine, we can safely do this here.
5243  // Any upper level clients will have also turned off their power policy
5244  // state machines.
5245  //
5248 
5249  m_PowerThread = NULL;
5250  }
5251  else if (hadThread) {
5252  //
5253  // Release our reference
5254  //
5257  );
5258  }
5259 }
5260 
5261 VOID
5264  )
5265 /*++
5266 
5267 Routine Description:
5268  Increments the ref count on the thread interface.
5269 
5270 Arguments:
5271  Context - FxPkgPnp*
5272 
5273 Return Value:
5274  None
5275 
5276  --*/
5277 {
5278  LONG count;
5279 
5282  );
5283 
5284 #if DBG
5285  ASSERT(count >= 2);
5286 #else
5288 #endif
5289 }
5290 
5291 VOID
5294  )
5295 /*++
5296 
5297 Routine Description:
5298  Interface deref for the thread interface. If this is the last reference
5299  released, an event is set so that the thread which waiting for the last ref
5300  to go away can unblock.
5301 
5302 Arguments:
5303  Context - FxPkgPnp*
5304 
5305 Return Value:
5306  None
5307 
5308  --*/
5309 
5310 {
5311  FxPkgPnp* pThis;
5312 
5313  pThis = (FxPkgPnp*) Context;
5314 
5316  pThis->m_PowerThreadEvent->Set();
5317  }
5318 }
5319 
5321 NTSTATUS
5323  VOID
5324  )
5325 /*++
5326 
5327 Routine Description:
5328  Take a power reference during a query pnp transition.
5329 
5330 Arguments:
5331  None
5332 
5333 Return Value:
5334  None
5335 
5336  --*/
5337 {
5338  if (IsPowerPolicyOwner()) {
5339  //
5340  // We want to synchronously wait to move into D0
5341  //
5342  return PowerReference(TRUE);
5343  }
5344  else {
5345  return STATUS_SUCCESS;
5346  }
5347 }
5348 
5350 NTSTATUS
5352  VOID
5353  )
5354 /*++
5355 
5356 Routine Description:
5357  Take a power reference during a query pnp transition.
5358 
5359 Arguments:
5360  None
5361 
5362 Return Value:
5363  None
5364 
5365  --*/
5366 {
5367  if (IsPowerPolicyOwner()) {
5368  //
5369  // We want to synchronously wait to move into D0
5370  //
5371  return m_PowerPolicyMachine.m_Owner->
5372  m_PowerIdleMachine.PowerReferenceWithFlags(
5374  );
5375  }
5376  else {
5377  return STATUS_SUCCESS;
5378  }
5379 }
5380 
5381 VOID
5383  VOID
5384  )
5385 /*++
5386 
5387 Routine Description:
5388  Release the power reference taken during a query pnp transition
5389 
5390 Arguments:
5391  None
5392 
5393 Return Value:
5394  None
5395 
5396  --*/
5397 {
5398  if (IsPowerPolicyOwner()) {
5399  PowerDereference();
5400  }
5401 }
5402 
5403 NTSTATUS
5405  __inout FxIrp* Irp,
5407  )
5408 {
5409  MdIrp irp;
5410 
5411  //
5412  // Once we call CompleteRequest, 2 things happen
5413  // 1) this object may go away
5414  // 2) Irp->m_Irp will be cleared
5415  //
5416  // As such, we capture the underlying WDM objects so that we can use them
5417  // to release the remove lock and use the PIRP *value* as a tag to release
5418  // the remlock.
5419  //
5420  irp = Irp->GetIrp();
5421 
5422  Irp->SetStatus(Status);
5423  Irp->StartNextPowerIrp();
5424  Irp->CompleteRequest(IO_NO_INCREMENT);
5425