ReactOS  0.4.15-dev-3193-g74513a7
pnpstatemachine.cpp
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft. All rights reserved.
4 
5 Module Name:
6 
7  PnpStateMachine.cpp
8 
9 Abstract:
10 
11  This module implements the PnP state machine for the driver framework.
12  This code was split out from FxPkgPnp.cpp.
13 
14 Author:
15 
16 
17 
18 
19 Environment:
20 
21  Both kernel and user mode
22 
23 Revision History:
24 
25 
26 
27 --*/
28 
29 #include "pnppriv.hpp"
30 #include <wdmguid.h>
31 
32 #include<ntstrsafe.h>
33 
34 extern "C" {
35 #if defined(EVENT_TRACING)
36 #include "PnpStateMachine.tmh"
37 #endif
38 }
39 
40 
41 //
42 // The PnP State Machine
43 //
44 // This state machine responds to several PnP events:
45 //
46 // AddDevice -- Always targets the same state
47 // IRP_MN_START_DEVICE
48 // IRP_MN_START_DEVICE Complete -- Handled on the way up the stack
49 // IRP_MN_QUERY_REMOVE_DEVICE
50 // IRP_MN_QUERY_STOP_DEVICE
51 // IRP_MN_CANCEL_REMOVE_DEVICE
52 // IRP_MN_CANCEL_STOP_DEVICE
53 // IRP_MN_STOP_DEVICE
54 // IRP_MN_REMOVE_DEVICE
55 // IRP_MN_SURPRISE_REMOVE_DEVICE -- Always targets the same state
56 // IRP_MN_EJECT
57 //
58 // Each state has an entry for each of these events, listing the
59 // target state for each of them.
60 //
61 
62 #if FX_STATE_MACHINE_VERIFY
63  #define VALIDATE_PNP_STATE(_CurrentState, _NewState) \
64  ValidatePnpStateEntryFunctionReturnValue((_CurrentState), (_NewState))
65 #else
66  #define VALIDATE_PNP_STATE(_CurrentState, _NewState) (0)
67 #endif //FX_STATE_MACHINE_VERIFY
68 
69 // @@SMVERIFY_SPLIT_BEGIN
70 
72 {
79 };
80 
82 {
85 };
86 
88 {
91 };
92 
94 {
98 };
99 
101 {
107 };
108 
110 {
113 };
114 
116 {
126 };
127 
129 {
133 };
134 
136 {
139 };
140 
142 {
145 };
146 
148 {
151 };
152 
154 {
157 };
158 
160 {
163 };
164 
166 {
169 };
170 
172 {
175 };
176 
178 {
181 };
182 
184 {
187 };
188 
190 {
193 };
194 
196 {
200 };
201 
203 {
206 };
207 
209 {
212 };
213 
215 {
218 };
219 
221  // State function
222  // First transition event & state
223  // Other transition events & states
224  // state info
225 
226  // WdfDevStatePnpObjectCreated
227  { NULL,
229  NULL,
230  { TRUE,
231  0 },
232  },
233 
234  // WdfDevStatePnpCheckForDevicePresence
237  NULL,
238  { FALSE,
239  0 },
240  },
241 
242  // WdfDevStatePnpEjectFailed
243  { NULL,
246  { TRUE,
247  0 },
248  },
249 
250  // WdfDevStatePnpEjectHardware
253  NULL,
254  { FALSE,
255  0 },
256  },
257 
258  // WdfDevStatePnpEjectedWaitingForRemove
259  { NULL,
261  NULL,
262  { TRUE,
263  PnpEventSurpriseRemove }, // can receive this if parent is surprise
264  // removed while the ejected pdo is waiting
265  // for remove.
266  },
267 
268  // WdfDevStatePnpInit
269  { NULL,
272  { TRUE,
274  },
275 
276  // WdfDevStatePnpInitStarting
280  { TRUE,
281  0 },
282  },
283 
284  // WdfDevStatePnpInitSurpriseRemoved
287  NULL,
288  { FALSE,
289  0 },
290  },
291 
292  // WdfDevStatePnpHardwareAvailable
296  { FALSE,
298  },
299  },
300 
301  // WdfDevStatePnpEnableInterfaces
304  NULL,
305  { FALSE,
306  0 },
307  },
308 
309  // WdfDevStatePnpHardwareAvailablePowerPolicyFailed
312  NULL,
313  { FALSE,
314  0 },
315  },
316 
317  // WdfDevStatePnpQueryRemoveAskDriver
320  NULL,
321  { FALSE,
322  0 },
323  },
324 
325  // WdfDevStatePnpQueryRemovePending
329  { TRUE,
330  0,
331  },
332  },
333 
334  // WdfDevStatePnpQueryRemoveStaticCheck
337  NULL,
338  { FALSE,
339  0 },
340  },
341 
342  // WdfDevStatePnpQueriedRemoving,
346  { FALSE,
347  PnpEventPowerDownFailed | // We ignore these power failed events because
348  PnpEventPowerUpFailed // they will be translated into failed power
349  // policy events.
350  },
351  },
352 
353  // WdfDevStatePnpQueryStopAskDriver
356  NULL,
357  { FALSE,
358  0 },
359  },
360 
361  // WdfDevStatePnpQueryStopPending
365  { TRUE,
366  0,
367  },
368  },
369 
370  // WdfDevStatePnpQueryStopStaticCheck
373  NULL,
374  { FALSE,
375  0 },
376  },
377 
378  // WdfDevStatePnpQueryCanceled,
381  NULL,
382  { FALSE,
383  0 },
384  },
385 
386  // WdfDevStatePnpRemoved
389  NULL,
390  { FALSE,
391  0 },
392  },
393 
394  // WdfDevStatePnpPdoRemoved
397  NULL,
398  { FALSE,
399  0 },
400  },
401 
402  // WdfDevStatePnpRemovedPdoWait
406  { TRUE,
407  PnpEventCancelRemove | // Amazingly enough, you can get a cancel q.r.
408  // on a PDO without seeing the query remove if
409  // the stack is partially built
410  PnpEventQueryRemove | // Can get a query remove from the removed state
411  // when installing a PDO that is disabled
412  PnpEventPowerDownFailed // We may get this for a PDO if implicit power
413  // down callbacks were failed. The failed power
414  // policy stop event took care of rundown.
415  },
416  },
417 
418  // WdfDevStatePnpRemovedPdoSurpriseRemoved
421  NULL,
422  { FALSE,
423  0 },
424  },
425 
426  // WdfDevStatePnpRemovingDisableInterfaces
429  NULL,
430  { FALSE,
431  0 },
432  },
433 
434  // WdfDevStatePnpRestarting
438  { FALSE,
440  },
441  },
442 
443  // WdfDevStatePnpStarted
447  { TRUE,
448  0,
449  },
450  },
451 
452  // WdfDevStatePnpStartedCancelStop
455  NULL,
456  { FALSE,
457  0 },
458  },
459 
460  // WdfDevStatePnpStartedCancelRemove
463  NULL,
464  { FALSE,
465  0 },
466  },
467 
468  // WdfDevStatePnpStartedRemoving
472  { TRUE,
473  PnpEventPowerUpFailed | // device was idled out and in Dx when we got removed
474  // and this event is due to the power up that occured
475  // to move it into D0 so it could be disarmed
477  },
478  },
479 
480  // WdfDevStatePnpStartingFromStopped
483  NULL,
484  { FALSE,
485  0 },
486  },
487 
488  // WdfDevStatePnpStopped
492  { TRUE,
493  0,
494  },
495  },
496 
497  // WdfDevStatePnpStoppedWaitForStartCompletion
501  { TRUE,
502  0 },
503  },
504 
505  // WdfDevStatePnpStartedStopping
509  { TRUE,
510  PnpEventPowerUpFailed | // device was idled out and in Dx when we got stopped
511  // and this event is due to the power up that occured
512  // to move it into D0 so it could be disarmed
514  },
515  },
516 
517  // The function is named PnpEventSurpriseRemoved with a 'd' because
518  // PnpEventSurpriseRemove (no 'd') is an event name
519 
520  // WdfDevStatePnpSurpriseRemove
523  NULL,
524  { FALSE,
525  0 },
526  },
527 
528  // WdfDevStatePnpInitQueryRemove
532  { TRUE,
533  0 },
534  },
535 
536  // WdfDevStatePnpInitQueryRemoveCanceled
539  NULL,
540  { TRUE,
541  0 },
542  },
543 
544  // WdfDevStatePnpFdoRemoved
547  NULL,
548  { FALSE,
549  0 },
550  },
551 
552  // WdfDevStatePnpRemovedWaitForChildren
553  { NULL,
555  NULL,
556  { TRUE,
557  PnpEventPowerDownFailed // device power down even from processing remove
558  },
559  },
560 
561  // WdfDevStatePnpQueriedSurpriseRemove
564  NULL,
565  { FALSE,
566  0 },
567  },
568 
569  // WdfDevStatePnpSurpriseRemoveIoStarted
572  NULL,
573  { FALSE,
574  0 },
575  },
576 
577  // WdfDevStatePnpFailedPowerDown
581  { FALSE,
583  },
584  },
585 
586  // WdfDevStatePnpFailedIoStarting
590  { FALSE,
592 
593  PnpEventPowerUpFailed // if the device idled out and then failed
594  // d0 entry, the power up failed can be passed
595  // up by the IoInvalidateDeviceRelations and
596  // subsequence surprise remove event.
597  },
598  },
599 
600  // WdfDevStatePnpFailedOwnHardware
603  NULL,
604  { FALSE,
605  0 },
606  },
607 
608  // WdfDevStatePnpFailed
611  NULL,
612  { FALSE,
613  0,
614  },
615  },
616 
617  // WdfDevStatePnpFailedSurpriseRemoved
620  NULL,
621  { FALSE,
622  0, },
623  },
624 
625  // WdfDevStatePnpFailedStarted
628  NULL,
629  { FALSE,
630  0, },
631  },
632 
633  // WdfDevStatePnpFailedWaitForRemove,
634  { NULL,
637  { TRUE,
638  PnpEventPowerUpFailed | // initial power up failed, power policy start
639  // failed event moved the state machine to the
640  // failed state first
641  PnpEventPowerDownFailed | // implicitD3 power down failed
642  PnpEventQueryRemove | // start succeeded, but we still get a query in
643  // the removed case
644  PnpEventCancelStop | // power down failure while processing query stop
645  // and q.s. irp completed with error
646  PnpEventCancelRemove // power down failure while processing query remove
647  // and q.r. irp completed with error
648  },
649  },
650 
651  // WdfDevStatePnpFailedInit
654  NULL,
655  { FALSE,
656  0 },
657  },
658 
659  // WdfDevStatePnpPdoInitFailed
662  NULL,
663  { FALSE,
664  0 },
665  },
666 
667  // WdfDevStatePnpRestart
671  { FALSE,
672  PnpEventPowerUpFailed | // when stopping power policy, device was in
673  // Dx and bringing it to D0 succeeded or failed
674  PnpEventPowerDownFailed // same as power up
675  },
676  },
677 
678  // WdfDevStatePnpRestartReleaseHardware
682  { TRUE,
683  PnpEventPowerDownFailed // the previous pwr policy stop
684  // in WdfDevStaePnpRestart will
685  // cause these events to show up here
686  },
687  },
688 
689  // WdfDevStatePnpRestartHardwareAvailable
693  { TRUE,
695  },
696  },
697 
698  // WdfDevStatePnpPdoRestart
701  NULL,
702  { FALSE,
703  0 },
704  },
705 
706  // WdfDevStatePnpFinal
709  NULL,
710  { TRUE,
711  PnpEventPowerDownFailed, // on the final implicit power down, a
712  // callback returned !NT_SUCCESS
713  },
714  },
715 
716  // WdfDevStatePnpRemovedChildrenRemoved
719  NULL,
720  { TRUE,
721  0 } ,
722  },
723 
724  // WdfDevStatePnpQueryRemoveEnsureDeviceAwake
727  NULL,
728  { FALSE,
729  0 },
730  },
731 
732  // WdfDevStatePnpQueryStopEnsureDeviceAwake
735  NULL,
736  { FALSE,
737  0 },
738  },
739 
740  // WdfDevStatePnpFailedPowerPolicyRemoved
743  NULL,
744  { FALSE,
745  0 } ,
746  },
747 };
748 
749 // @@SMVERIFY_SPLIT_END
750 
751 VOID
753  VOID
754  )
755 /*++
756 
757 Routine Description:
758  This routine is never actually called by running code, it just has
759  WDFCASSERTs who upon failure, would not allow this file to be compiled.
760 
761  DO NOT REMOVE THIS FUNCTION just because it is not callec by any running
762  code.
763 
764 Arguments:
765  None
766 
767 Return Value:
768  None
769 
770  --*/
771 {
772  WDFCASSERT(sizeof(FxPnpStateInfo) == sizeof(ULONG));
773 
774  WDFCASSERT((sizeof(m_WdfPnpStates)/sizeof(m_WdfPnpStates[0]))
775  ==
777 
778  // we assume these are the same length when we update the history index
779  WDFCASSERT((sizeof(m_PnpMachine.m_Queue)/sizeof(m_PnpMachine.m_Queue[0]))
780  ==
781  (sizeof(m_PnpMachine.m_States.History)/
782  sizeof(m_PnpMachine.m_States.History[0])));
783 }
784 
785 /*++
786 
787 The locking model for the PnP state machine requires that events be enqueued
788 possibly at DISPATCH_LEVEL. It also requires that the PnP state machine be
789 runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL
790 lock that guards the event queue and one PASSIVE_LEVEL lock that guards the
791 state machine itself.
792 
793 Algorithm:
794 
795 1) Acquire the PnP queue lock.
796 2) Enqueue the request. Requests are put at the end of the queue, except if
797  they are PowerUp, or PowerDown, in which case they are put at the head of
798  the queue.
799 3) Drop the PnP queue lock.
800 4) If the thread is running at PASSIVE_LEVEL, skip to step 6.
801 5) Queue a work item onto any work queue.
802 6) Attempt to acquire the state machine lock, with a near-zero-length timeout.
803 7) If successful, skip to step 10.
804 8) Queue a work item onto any work queue.
805 9) Acquire the state machine lock.
806 10) Acquire the PnP queue lock.
807 11) Attempt to dequeue an event.
808 12) Drop the PnP queue lock.
809 13) If there was no event to dequeue, drop the state machine lock and exit.
810 14) Execute the state handler. This may involve taking one of the other state
811  machine queue locks, briefly, to deliver an event.
812 15) Go to Step 10.
813 
814 Implementing this algorithm requires three functions.
815 
816 PnpProcessEvent -- Implements steps 1-8.
817 _PnpProcessEventInner -- Implements step 9.
818 PnpProcessEventInner -- Implements steps 10-15.
819 
820 --*/
821 
822 VOID
825  __in BOOLEAN ProcessOnDifferentThread
826  )
827 /*++
828 
829 Routine Description:
830  This function implements steps 1-8 of the algorithm described above.
831 
832 Arguments:
833  Event - Current PnP event
834 
835 Return Value:
836 
837  NTSTATUS
838 
839 --*/
840 {
842  KIRQL oldIrql;
843 
844  //
845  // Take the lock, raising to DISPATCH_LEVEL.
846  //
847  m_PnpMachine.Lock(&oldIrql);
848 
849  if (m_PnpMachine.IsFull()) {
852  "WDFDEVICE 0x%p !devobj 0x%p current pnp state %!WDF_DEVICE_PNP_STATE! "
853  "dropping event %!FxPnpEvent! because of a full queue",
854  m_Device->GetHandle(),
857  Event);
858 
859  //
860  // The queue is full. Bail.
861  //
862  m_PnpMachine.Unlock(oldIrql);
863 
864  ASSERT(!"The PnP queue is full. This shouldn't be able to happen.");
865  return;
866  }
867 
871  "WDFDEVICE 0x%p !devobj 0x%p current pnp state %!WDF_DEVICE_PNP_STATE! "
872  "dropping event %!FxPnpEvent! because of a closed queue",
873  m_Device->GetHandle(),
876  Event);
877 
878  //
879  // The queue is closed. Bail
880  //
881  m_PnpMachine.Unlock(oldIrql);
882 
883  return;
884  }
885 
886  //
887  // Enqueue the event. Whether the event goes on the front
888  // or the end of the queue depends on which event it is.
889  //
891  //
892  // Stick it on the front of the queue, making it the next
893  // event that will be processed.
894  //
896  }
897  else {
898  //
899  // Stick it on the end of the queue.
900  //
902  }
903 
904  //
905  // Drop the lock.
906  //
907  m_PnpMachine.Unlock(oldIrql);
908 
909  //
910  // Now, if we are running at PASSIVE_LEVEL, attempt to run the state
911  // machine on this thread. If we can't do that, then queue a work item.
912  //
913 
915  oldIrql,
916  ProcessOnDifferentThread
917  )) {
918 
919  LONGLONG timeout = 0;
920 
922  &timeout);
923 
924  if (FxWaitLockInternal::IsLockAcquired(status)) {
926 
927  //
928  // We now hold the state machine lock. So call the function that
929  // dispatches the next state.
930  //
932 
934 
935  info.Evaluate(this);
936  return;
937  }
938  }
939 
940  //
941  // For one reason or another, we couldn't run the state machine on this
942  // thread. So queue a work item to do it. If m_PnPWorkItemEnqueuing
943  // is non-zero, that means that the work item is already being enqueued
944  // on another thread. This is significant, since it means that we can't do
945  // anything with the work item on this thread, but it's okay, since the
946  // work item will pick up our work and do it.
947  //
949 }
950 
951 VOID
955  __in PVOID WorkerContext
956  )
957 {
958  UNREFERENCED_PARAMETER(WorkerContext);
959 
960  //
961  // Take the state machine lock.
962  //
963  This->m_PnpMachine.m_StateMachineLock.AcquireLock(
964  This->GetDriverGlobals()
965  );
966 
967  //
968  // Call the function that will actually run the state machine.
969  //
970  This->PnpProcessEventInner(Info);
971 
972  //
973  // We are being called from the work item and m_WorkItemRunning is > 0, so
974  // we cannot be deleted yet.
975  //
976  ASSERT(Info->SomethingToDo() == FALSE);
977 
978  //
979  // Now release the lock
980  //
981  This->m_PnpMachine.m_StateMachineLock.ReleaseLock(
982  This->GetDriverGlobals()
983  );
984 }
985 
986 VOID
989  )
990 /*++
991 
992 Routine Description:
993  This routine runs the state machine. It implements steps 10-15 of the
994  algorithm described above.
995 
996 --*/
997 {
998  WDF_DEVICE_PNP_STATE newState;
1000  FxPnpEvent event;
1001  KIRQL oldIrql;
1002 
1003  //
1004  // Process as many events as we can.
1005  //
1006  for ( ; ; ) {
1008 
1009  //
1010  // Get an event from the queue.
1011  //
1012  m_PnpMachine.Lock(&oldIrql);
1013 
1014  if (m_PnpMachine.IsEmpty()) {
1016 
1019  Info->m_FireAndForgetIrp = ClearPendingPnpIrp();
1020 
1021  ASSERT(Info->m_FireAndForgetIrp != NULL);
1022  }
1023 
1024  Info->m_SetRemovedEvent = m_SetDeviceRemoveProcessed;
1026 
1027  //
1028  // The queue is empty.
1029  //
1030  m_PnpMachine.Unlock(oldIrql);
1031 
1032  return;
1033  }
1034 
1036 
1037  //
1038  // At this point, we need to determine whether we can process this
1039  // event.
1040  //
1041  if (event & PnpPriorityEventsMask) {
1042  //
1043  // These are always possible to handle.
1044  //
1045  DO_NOTHING();
1046  }
1047  else {
1048  //
1049  // Check to see if this state can handle new events.
1050  //
1051  if (entry->StateInfo.Bits.QueueOpen == FALSE) {
1052  //
1053  // This state can't handle new events.
1054  //
1055  m_PnpMachine.Unlock(oldIrql);
1056  return;
1057  }
1058  }
1059 
1061  m_PnpMachine.Unlock(oldIrql);
1062 
1063  //
1064  // Find the entry in the PnP state table that corresponds
1065  // to this event.
1066  //
1067  newState = WdfDevStatePnpNull;
1068 
1069  if (entry->FirstTargetState.PnpEvent == event) {
1070  newState = entry->FirstTargetState.TargetState;
1071 
1072  DO_EVENT_TRAP(&entry->FirstTargetState);
1073  }
1074  else if (entry->OtherTargetStates != NULL) {
1075  ULONG i = 0;
1076 
1077  for (i = 0;
1078  entry->OtherTargetStates[i].PnpEvent != PnpEventNull;
1079  i++) {
1080  if (entry->OtherTargetStates[i].PnpEvent == event) {
1081  newState = entry->OtherTargetStates[i].TargetState;
1082  DO_EVENT_TRAP(&entry->OtherTargetStates[i]);
1083  break;
1084  }
1085  }
1086  }
1087 
1088  if (newState == WdfDevStatePnpNull) {
1091  "WDFDEVICE 0x%p !devobj 0x%p current pnp state "
1092  "%!WDF_DEVICE_PNP_STATE! dropping event %!FxPnpEvent!",
1093  m_Device->GetHandle(),
1096  event);
1097 
1098  if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) {
1099  COVERAGE_TRAP();
1100 
1103  "WDFDEVICE 0x%p !devobj %p current state "
1104  "%!WDF_DEVICE_PNP_STATE!, policy event %!FxPnpEvent! is not"
1105  " a known dropped event, known dropped events are "
1106  "%!FxPnpEvent!",
1107  m_Device->GetHandle(),
1110  event,
1111  entry->StateInfo.Bits.KnownDroppedEvents);
1112 
1113  // DIAG: add diag code here
1114  }
1115 
1116  //
1117  // This state doesn't respond to the Event. Make sure we do not
1118  // drop an event which pends a pnp irp on the floor though.
1119  //
1120  if (event & PnpEventPending) {
1121  //
1122  // In the case of a previous power up/down failure, the following
1123  // can happen
1124  // 1 invalidate device relations
1125  // 2 failure event is posted to pnp state machine
1126  // 3 process power failure event first, but while processing,
1127  // query device state is completed, and failed /removed is reported
1128  // 4 surprise remove comes, the irp is queued, the event is queued
1129  // 5 processing of power failure event continues, gets to
1130  // Failed and completes the s.r irp
1131  // 6 the surprise remove event is processed (the current value
1132  // of the local var event), but since we are already in the
1133  // Failed state, we ignore this event and end up
1134  // here.
1135  //
1136  // This means that if we are processing surprise remove, we cannot
1137  // 100% expect that an irp has been pended.
1138  //
1141  }
1142  else {
1143  DO_NOTHING();
1144  }
1145  }
1146  else {
1147  //
1148  // Now enter the new state.
1149  //
1150  PnpEnterNewState(newState);
1151  }
1152  }
1153 }
1154 
1155 VOID
1158  )
1159 /*++
1160 
1161 Routine Description:
1162  This function looks up the handler for a state and
1163  then calls it.
1164 
1165 Arguments:
1166  Event - Current PnP event
1167 
1168 Return Value:
1169  None.
1170 
1171 --*/
1172 {
1174  WDF_DEVICE_PNP_STATE currentState, newState;
1176 
1177  currentState = m_Device->GetDevicePnpState();
1178  newState = State;
1179 
1180  while (newState != WdfDevStatePnpNull) {
1183  "WDFDEVICE 0x%p !devobj 0x%p entering PnP State "
1184  "%!WDF_DEVICE_PNP_STATE! from %!WDF_DEVICE_PNP_STATE!",
1185  m_Device->GetHandle(),
1187  newState,
1188  currentState);
1189 
1190  if (m_PnpStateCallbacks != NULL) {
1191  //
1192  // Callback for leaving the old state
1193  //
1194  RtlZeroMemory(&data, sizeof(data));
1195 
1197  data.Data.LeaveState.CurrentState = currentState;
1198  data.Data.LeaveState.NewState = newState;
1199 
1200  m_PnpStateCallbacks->Invoke(currentState,
1202  m_Device->GetHandle(),
1203  &data);
1204  }
1205 
1207  (USHORT) newState;
1208 
1209  if (m_PnpStateCallbacks != NULL) {
1210  //
1211  // Callback for entering the new state
1212  //
1213  RtlZeroMemory(&data, sizeof(data));
1214 
1216  data.Data.EnterState.CurrentState = currentState;
1217  data.Data.EnterState.NewState = newState;
1218 
1219  m_PnpStateCallbacks->Invoke(newState,
1221  m_Device->GetHandle(),
1222  &data);
1223  }
1224 
1225  m_Device->SetDevicePnpState(newState);
1226  currentState = newState;
1227 
1228  entry = GetPnpTableEntry(currentState);
1229 
1230  //
1231  // Call the state handler if one is present and record our new state
1232  //
1233  if (entry->StateFunc != NULL) {
1234  newState = entry->StateFunc(this);
1235 
1236  //
1237  // Validate the return value if FX_STATE_MACHINE_VERIFY is enabled
1238  //
1239  VALIDATE_PNP_STATE(currentState, newState);
1240  }
1241  else {
1242  newState = WdfDevStatePnpNull;
1243  }
1244 
1245  if (m_PnpStateCallbacks != NULL) {
1246  //
1247  // Callback for post processing the new state
1248  //
1249  RtlZeroMemory(&data, sizeof(data));
1250 
1252  data.Data.PostProcessState.CurrentState = currentState;
1253 
1254  m_PnpStateCallbacks->Invoke(currentState,
1256  m_Device->GetHandle(),
1257  &data);
1258  }
1259  }
1260 }
1261 
1265  )
1266 /*++
1267 
1268 Routine Description:
1269  This function implements the Check For Device
1270  Presence state. This is a state that is specific
1271  to PDOs, so this function should be overloaded by
1272  the PDO class and never called.
1273 
1274 Arguments:
1275  none
1276 
1277 Return Value:
1278 
1279  VOID
1280 
1281 --*/
1282 {
1283  return This->PnpEventCheckForDevicePresenceOverload();
1284 }
1285 
1289  )
1290 /*++
1291 
1292 Routine Description:
1293  This function implements the Eject Hardware state.
1294  This is a state that is specific to PDOs, so this
1295  function should be overloaded by the PDO class
1296  and never called.
1297 
1298 Arguments:
1299  none
1300 
1301 Return Value:
1302 
1303  VOID
1304 
1305 --*/
1306 {
1307  return This->PnpEventEjectHardwareOverload();
1308 }
1309 
1313  )
1314 /*++
1315 
1316 Routine Description:
1317  The device is recieving a start for the first time. The start is on the way
1318  down the stack.
1319 
1320 Arguments:
1321  This - instance of the state machine
1322 
1323 Return Value:
1324  new machine state
1325 
1326  --*/
1327 {
1328  if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) {
1329  //
1330  // Start was sent asynchronously down the stack, the irp's completion
1331  // routine will move the state machine to the new state.
1332  //
1333  return WdfDevStatePnpNull;
1334  }
1335 
1337 }
1338 
1342  )
1343 /*++
1344 
1345 Routine Description:
1346  This transition should only occur for a PDO.
1347 
1348  The device was initialized, but then it's parent bus was surprise removed.
1349  Complete the surprise remove and wait for the remove.
1350 
1351 Arguments:
1352  This - instance of the state machine
1353 
1354 Return Value:
1355  WdfDevStatePnpInit
1356 
1357  --*/
1358 {
1359  This->PnpFinishProcessingIrp(TRUE);
1360 
1361  return WdfDevStatePnpInit;
1362 }
1363 
1367  )
1368 /*++
1369 
1370 Routine Description:
1371  This function implements the Hardware Available state.
1372 
1373 Arguments:
1374  none
1375 
1376 Return Value:
1377 
1378  VOID
1379 
1380 --*/
1381 {
1382  NTSTATUS status;
1383  BOOLEAN matched;
1384 
1386  matched = FALSE;
1387 
1388  This->QueryForReenumerationInterface();
1389 
1390  status = This->CreatePowerThreadIfNeeded();
1391 
1392  if (NT_SUCCESS(status)) {
1393  status = This->PnpPrepareHardware(&matched);
1394  }
1395 
1396  if (!NT_SUCCESS(status)) {
1397  if (matched == FALSE) {
1398  //
1399  // NOTE: consider going to WdfDevStatePnpFailed instead of yet
1400  // another failed state out of start device handling.
1401  //
1402 
1403  //
1404  // We can handle remove out of the init state, revert back to that
1405  // state.
1406  //
1407  return WdfDevStatePnpFailedInit;
1408  }
1409  else {
1410  //
1411  // EvtDevicePrepareHardware is what failed, goto a state where we
1412  // undo that call.
1413  //
1415  }
1416  }
1417 
1418  //
1419  // We only query for the capabilities for the power policy owner because
1420  // we use the capabilities to determine the right Dx state when we want to
1421  // wake from S0 or Sx. Since only the power policy owner can enable wake
1422  // behavior, only the owner needs to query for the information.
1423  //
1424  // ALSO, if we are a filter, there are issues in stacks wrt pnp reentrancy.
1425 
1426 
1427 
1428 
1429 
1430 
1431 
1432  //
1433  if (This->IsPowerPolicyOwner()) {
1434  //
1435  // Query the stack for capabilities before telling the stack hw is
1436  // available
1437  //
1438  status = This->QueryForCapabilities();
1439 
1440  if (!NT_SUCCESS(status)) {
1442  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1443  "could not query caps for stack, %!STATUS!", status);
1444 
1445  This->SetPendingPnpIrpStatus(status);
1447  }
1448 
1449  This->m_CapsQueried = TRUE;
1450  }
1451 
1452  This->PnpPowerPolicyStart();
1453 
1454  return WdfDevStatePnpNull;
1455 }
1456 
1460  )
1461 /*++
1462 
1463 Routine Description:
1464  The device has powered up and fully started, now enable the device
1465  interfaces and WMI. We wait until the last possible moment because on
1466  win2k WMI registration is not synchronized with the completion of start
1467  device, so if we register WMI early in start device processing, we could get
1468  wmi requests while we are initializing, which is a race condition we want
1469  to eliminate.
1470 
1471 Arguments:
1472  This - instance of the state machine
1473 
1474 Return Value:
1475  new state
1476 
1477  --*/
1478 {
1479  NTSTATUS status;
1480 
1481  status = This->PnpEnableInterfacesAndRegisterWmi();
1482 
1483  if (!NT_SUCCESS(status)) {
1484  //
1485  // Upon failure, PnpEnableInterfacesAndRegisterWmi already marked the
1486  // irp as failed and recorded an internal error.
1487  //
1488  // FailedPowerDown will gracefully tear down the stack and bring it out
1489  // of D0.
1490  //
1492  }
1493 
1494  return WdfDevStatePnpStarted;
1495 }
1496 
1500  )
1501 /*++
1502 
1503 Routine Description:
1504  Our previous state called PowerPolicyStart or PowerPolicyStopRemove and the
1505  power state machine could not perform the requested action. We still have
1506  a start irp pending, so set its status and then proceed down the start failure
1507  path.
1508 
1509 Arguments:
1510  This - instance of the state machien
1511 
1512 Return Value:
1513  WdfDevStatePnpFailedOwnHardware
1514 
1515  --*/
1516 {
1517  This->SetPendingPnpIrpStatus(STATUS_DEVICE_POWER_FAILURE);
1518 
1520 }
1521 
1525  )
1526 /*++
1527 
1528 Routine Description:
1529  This function implements the Query Remove Ask Driver
1530  state. It's job is to invoke EvtDeviceQueryRemove and then complete the
1531  QueryRemove IRP if needed.
1532 
1533 Arguments:
1534  This - instance of the state machine
1535 
1536 Return Value:
1537  new state
1538 
1539 --*/
1540 {
1542  NTSTATUS status;
1543 
1544  //
1545  // First, call the driver. If it succeeds, look at whether
1546  // it managed to stop its stuff.
1547  //
1548  status = This->m_DeviceQueryRemove.Invoke(This->m_Device->GetHandle());
1549 
1550  if (NT_SUCCESS(status)) {
1551  //
1552  // The driver has stopped all of its self managed io. Proceed to
1553  // stop everything before passing the request down the stack.
1554  //
1556  }
1557  else {
1558  //
1559  // The callback didn't manage to stop. Go back to the Started state
1560  // where we will complete the pended pnp irp
1561  //
1563  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1564  "EvtDeviceQueryRemove failed, %!STATUS!", status);
1565 
1566  if (status == STATUS_NOT_SUPPORTED) {
1568  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1569  "EvtDeviceQueryRemove returned an invalid status "
1570  "STATUS_NOT_SUPPORTED");
1571 
1572  if (This->GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) {
1573  FxVerifierDbgBreakPoint(This->GetDriverGlobals());
1574  }
1575  }
1576 
1578  }
1579 
1580  This->SetPendingPnpIrpStatus(status);
1581 
1582  return state;
1583 }
1584 
1588  )
1589 /*++
1590 Routine Description:
1591  This function brings the device to a working state if it is idle. If the
1592  device is already in working state, it ensures that it does not idle out.
1593 
1594 Arguments:
1595  This - instance of the state machine
1596 
1597 Return Value:
1598  new state
1599 --*/
1600 {
1601  NTSTATUS status;
1603 
1604  //
1605  // Make sure that the device is powered on before we send the query remove
1606  // on its way. If we do this after we send the query remove, we could race
1607  // with the remove which removes the reference and we want the device
1608  // powered on when processing remove.
1609  //
1610  status = This->PnpPowerReferenceDuringQueryPnp();
1611  if (STATUS_PENDING == status) {
1612  //
1613  // Device is transitioning to D0. The Pnp state machine will wait in
1614  // the current state until the transition is complete
1615  //
1617  }
1618  else if (NT_SUCCESS(status)) {
1619  //
1620  // Already in D0
1621  //
1623  }
1624  else {
1626  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1627  "StopIdle on WDFDEVICE %p failed, %!STATUS!, failing query remove",
1628  This->m_Device->GetHandle(), status);
1629 
1630  This->SetPendingPnpIrpStatus(status);
1631 
1632  //
1633  // The Started state will complete the irp when it sees the failure
1634  // status set on the irp.
1635  //
1637  }
1638 
1639  return state;
1640 }
1641 
1645  )
1646 /*++
1647 
1648 Routine Description:
1649  The device has fully stopped. Let go of the query remove irp.
1650 
1651 Arguments:
1652  This - instance of the state machine for this device
1653 
1654 Return Value:
1655  WdfDevStatePnpNull
1656 
1657  --*/
1658 
1659 {
1660  FxIrp irp;
1661 
1662  irp.SetIrp(This->ClearPendingPnpIrp());
1663  (void) This->FireAndForgetIrp(&irp);
1664  return WdfDevStatePnpNull;
1665 }
1666 
1670  )
1671 /*++
1672 
1673 Routine Description:
1674  This function implements the Query Remove Static Check
1675  state. It's job is to determine whether this device,
1676  in general, can stop. If it can, then we proceed on
1677  to Query Remove Ask Driver. If not, then we go to
1678  back to Started.
1679 
1680 Arguments:
1681  none
1682 
1683 Return Value:
1684 
1685  VOID
1686 
1687 --*/
1688 {
1689  NTSTATUS status;
1690  BOOLEAN completeQuery;
1691 
1692  completeQuery = TRUE;
1693 
1694  if (This->m_DeviceStopCount != 0) {
1696  This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1697  "Failing QueryRemoveDevice because the driver "
1698  "has indicated that it cannot be stopped, count %d",
1699  This->m_DeviceStopCount);
1700 
1702  }
1703  else if (This->IsInSpecialUse()) {
1705  This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1706  "Failing QueryRemoveDevice due to open special file counts "
1707  "(paging %d, hiber %d, dump %d, boot %d)",
1708  This->GetUsageCount(WdfSpecialFilePaging),
1709  This->GetUsageCount(WdfSpecialFileHibernation),
1710  This->GetUsageCount(WdfSpecialFileDump),
1711  This->GetUsageCount(WdfSpecialFileBoot));
1712 
1714  }
1715  else {
1716  //
1717  // Go on to next state in the "remove" progression.
1718  //
1719  completeQuery = FALSE;
1721  }
1722 
1723  if (completeQuery) {
1724  //
1725  // Store the status which Started will complete
1726  //
1727  This->SetPendingPnpIrpStatus(status);
1728 
1729  //
1730  // Revert to started
1731  //
1732  return WdfDevStatePnpStarted;
1733  }
1734  else {
1735  //
1736  // Wait for the other state machines to stop
1737  //
1739  }
1740 }
1741 
1745  )
1746 /*++
1747 
1748 Routine Description:
1749  The device was query removed and is now in the removed state.
1750 
1751 Arguments:
1752  This - instance of the state machine
1753 
1754 Return Value:
1755  WdfDevStatePnpNull
1756 
1757  --*/
1758 {
1759  //
1760  // It is important to stop power policy before releasing the reference.
1761  // If the reference was released first, we could get into a situation where
1762  // we immediately go idle and then we must send a D0 irp when in the remove.
1763  // If there are devices on top of this device and we send a D0 irp during
1764  // remove processing, the upper devices will be sent an irp after getting a
1765  // pnp remove (and either crash or fail the power irp upon receiving it).
1766  //
1767  This->PnpPowerPolicyStop();
1768  This->PnpPowerDereferenceSelf();
1769 
1770  return WdfDevStatePnpNull;
1771 }
1772 
1776  )
1777 /*++
1778 
1779 Routine Description:
1780  This function implements the Query Stop Ask Driver
1781  state. It's job is to invoke the EvtDeviceQueryStop
1782  callback and then complete the QueryStop IRP if needed.
1783 
1784 Arguments:
1785  This - instance of the state machine
1786 
1787 Return Value:
1788  new state
1789 
1790 --*/
1791 {
1793  NTSTATUS status;
1794 
1795  //
1796  // First, call the driver. If it succeeds, look at whether
1797  // it managed to stop its stuff.
1798  //
1799  status = This->m_DeviceQueryStop.Invoke(This->m_Device->GetHandle());
1800 
1801  if (NT_SUCCESS(status)) {
1802  //
1803  // Tell the other state machines to stop
1804  //
1806  }
1807  else {
1809  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1810  "EvtDeviceQueryStop failed, %!STATUS!", status);
1811 
1812  if (status == STATUS_NOT_SUPPORTED) {
1814  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1815  "EvtDeviceQueryStop returned an invalid status "
1816  "STATUS_NOT_SUPPORTED");
1817 
1818  if (This->GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) {
1819  FxVerifierDbgBreakPoint(This->GetDriverGlobals());
1820  }
1821  }
1822 
1823  //
1824  // The callback didn't manage to stop. Go back to the Started state.
1825  //
1827  }
1828 
1829  This->SetPendingPnpIrpStatus(status);
1830 
1831  return state;
1832 }
1833 
1837  )
1838 /*++
1839 Routine Description:
1840  This function brings the device to a working state if it is idle. If the
1841  device is already in working state, it ensures that it does not idle out.
1842 
1843 Arguments:
1844  This - instance of the state machine
1845 
1846 Return Value:
1847  new state
1848 --*/
1849 {
1850  NTSTATUS status;
1852 
1853  //
1854  // Make sure that the device is powered on before we send the query stop
1855  // on its way. If we do this after we send the query stop, we could race
1856  // with the stop and we want the device powered on when processing stop.
1857  //
1858  status = This->PnpPowerReferenceDuringQueryPnp();
1859  if (STATUS_PENDING == status) {
1860  //
1861  // Device is transitioning to D0. The Pnp state machine will wait in
1862  // the current state until the transition is complete
1863  //
1865  }
1866  else if (NT_SUCCESS(status)) {
1867  //
1868  // Already in D0
1869  //
1871  }
1872  else {
1874  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
1875  "StopIdle on WDFDEVICE %p failed, %!STATUS!, failing query stop",
1876  This->m_Device->GetHandle(), status);
1877 
1878  This->SetPendingPnpIrpStatus(status);
1879 
1880  //
1881  // The Started state will complete the irp when it sees the failure
1882  // status set on the irp.
1883  //
1885  }
1886 
1887  return state;
1888 }
1889 
1893  )
1894 /*++
1895 
1896 Routine Description:
1897  Everything in the device has stopped due to the stop device irp. Complete
1898  it now
1899 
1900 Arguments:
1901  This - instance of the state machine
1902 
1903 Return Value:
1904  WdfDevStatePnpNull
1905 
1906  --*/
1907 
1908 {
1909  FxIrp irp;
1910 
1911  irp.SetIrp(This->ClearPendingPnpIrp());
1912  (void) This->FireAndForgetIrp(&irp);
1913  return WdfDevStatePnpNull;
1914 }
1915 
1919  )
1920 /*++
1921 
1922 Routine Description:
1923  This function implements the Query Stop Static Check state. It's job is to
1924  determine whether this device, in general, can stop. If it can, then we
1925  proceed on to Query Stop Ask Driver. Otherwise we will return to the
1926  Started state. If the driver has set that the state machine should ignore
1927  query stop/remove, the query will succeed, otherwise it will fail
1928 
1929 Arguments:
1930  This - instance of the state machine
1931 
1932 Return Value:
1933  new machine state
1934 
1935 --*/
1936 {
1937  NTSTATUS status;
1938  BOOLEAN completeQuery = TRUE;
1939 
1940  if (This->m_DeviceStopCount != 0) {
1942  This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1943  "Failing QueryStopDevice because the driver "
1944  "has indicated that it cannot be stopped, count %d",
1945  This->m_DeviceStopCount);
1946 
1948  }
1949  else if (This->IsInSpecialUse()) {
1951  This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP,
1952  "Failing QueryStopDevice due to open special file counts (paging %d,"
1953  " hiber %d, dump %d, boot %d)",
1954  This->GetUsageCount(WdfSpecialFilePaging),
1955  This->GetUsageCount(WdfSpecialFileHibernation),
1956  This->GetUsageCount(WdfSpecialFileDump),
1957  This->GetUsageCount(WdfSpecialFileBoot));
1958 
1960  }
1961  else {
1962  //
1963  // Go on to next state in the "stop" progression.
1964  //
1966  completeQuery = FALSE;
1967  }
1968 
1969  if (completeQuery) {
1970  //
1971  // Set the state which started will complete the request with
1972  //
1973  This->SetPendingPnpIrpStatus(status);
1974 
1975  //
1976  // Revert to started
1977  //
1978  return WdfDevStatePnpStarted;
1979  }
1980  else {
1981  //
1982  // Go ask power what the self managed io state is
1983  //
1985  }
1986 }
1987 
1988 VOID
1990  VOID
1991  )
1992 /*++
1993 
1994 Routine Description:
1995  This function implements the Removed state.
1996 
1997 Arguments:
1998  none
1999 
2000 Return Value:
2001 
2002  VOID
2003 
2004 --*/
2005 {
2006  //
2007  // Purge non power managed queues now
2008  //
2011  );
2012 
2013  if (m_SelfManagedIoMachine != NULL) {
2015  }
2016 
2017  //
2018  // Cleanup WMI *after* EvtDeviceSelfManagedIoCleanup b/c we want to cleanup
2019  // after a well known and documented time. The WMI docs state that you can
2020  // register providers and instances all the way through
2021  // EvtDeviceSelfManagedIoCleanup, so we mark WMI as cleaned up after that
2022  // call.
2023  //
2025 
2026  //
2027  // Mark the device as removed.
2028  //
2031 
2032  //
2033  // Now call the driver and tell it to cleanup all its software state.
2034  //
2035  // We do the dispose early here before deleting the object
2036  // since the PNP remove event is the main trigger for
2037  // the Dispose chain in the framework.
2038  //
2039  // (Almost everything in the driver is rooted on the device object)
2040  //
2041 
2043 
2044  //
2045  // All the children are in the disposed state, destroy them all. m_Device
2046  // is not destroyed in this call.
2047  //
2048 
2050 
2051  //
2052  // Wait for all children to drain out and cleanup.
2053  //
2054 
2056 
2057 }
2058 
2062  )
2063 /*++
2064 
2065 Routine Description:
2066  The device was in the queried state (remove or stop) and the query was
2067  canceled. Remove the power reference taken and return to the started state.
2068 
2069 Arguments:
2070  This - instance of the state machine
2071 
2072 Return Value:
2073  WdfDevStatePnpStarted
2074 
2075  --*/
2076 {
2077  This->PnpPowerDereferenceSelf();
2078 
2079  return WdfDevStatePnpStarted;
2080 }
2081 
2085  )
2086 /*++
2087 
2088 Routine Description:
2089  This function implements the Removed state. It tears down any remaining
2090  children and the moves into a role (FDO/PDO) specific state.
2091 
2092 Arguments:
2093  This - instance of the state machine
2094 
2095 Return Value:
2096  new machine state
2097 
2098 --*/
2099 {
2100  //
2101  // Remove any child PDOs which may still be lingering around. We do
2102  // the cleanup here so that we do it only once for the PDO which is being
2103  // removed (but may stick around) b/c it was not reported as missing.
2104  //
2105  //
2106  // Iterate over all of the reported children
2107  //
2108  This->ChildListNotifyRemove(&This->m_PendingChildCount);
2109 
2110  //
2111  // Decrement our bias from when the device was (re)started. If all of the
2112  // children removed themselves synchronously, we just move to the cleanup
2113  // state, otherwise wait for all the children to fully process the remove
2114  // before remove the parent so that ordering of removal between parent and
2115  // child is guaranteed (where the order is that all children are cleaned
2116  // up before the parent is cleaned up).
2117  //
2118  if (InterlockedDecrement(&This->m_PendingChildCount) > 0) {
2120  }
2121  else {
2123  }
2124 }
2125 
2129  )
2130 /*++
2131 
2132 Routine Description:
2133  This function implements the PDO Removed state. This function is called
2134  when the PDO is actually reported missing to the OS or the FDO is removed.
2135 
2136 Arguments:
2137  none
2138 
2139 Return Value:
2140  new state
2141 
2142 --*/
2143 {
2144  return This->PnpEventPdoRemovedOverload();
2145 }
2146 
2150  )
2151 /*++
2152 
2153 Routine Description:
2154  Indicates to the remove path that remove processing is done and we will
2155  wait for additional PNP events to arrive at this state machine
2156 
2157 Arguments:
2158  This - Instance of the state machine
2159 
2160 Return Value:
2161  WdfDevStatePnpNull
2162 
2163  --*/
2164 {
2165  if (This->m_DeviceRemoveProcessed != NULL) {
2166  This->m_SetDeviceRemoveProcessed = TRUE;
2167  }
2168 
2169  return WdfDevStatePnpNull;
2170 }
2171 
2175  )
2176 /*++
2177 
2178 Routine Description:
2179  PDO has been removed (could have been disabled in user mode) and is now
2180  surprise removed by the underlying bus.
2181 
2182 Arguments:
2183  This - instance of the state machine
2184 
2185 Return Value:
2186  WdfDevStatePnpRemovedPdoWait
2187 
2188  --*/
2189 {
2190  //
2191  // Invoke EvtDeviceSurpriseRemove
2192  //
2193  This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle());
2194 
2195  //
2196  // Call the overloaded surprise remove handler since
2197  // PnpEventSurpriseRemovePendingOverload will not get called
2198  //
2199  This->PnpEventSurpriseRemovePendingOverload();
2200 
2201  //
2202  // The surprise remove irp was pended, complete it now
2203  //
2204  This->PnpFinishProcessingIrp();
2205 
2207 }
2208 
2209 VOID
2211  __in BOOLEAN GracefulRemove
2212  )
2213 /*++
2214 
2215 Routine Description:
2216  This is a common worker function between surprise remove and the graceful
2217  remove path to do common cleanup. This involves deregistering from WMI,
2218  device interfaces, symbolic links and stopping power managed i/o.
2219 
2220 Arguments:
2221  GracefulRemove - if TRUE, we are in the graceful remove path, otherwise we
2222  are in the surprise remove path.
2223 
2224 Return Value:
2225  None
2226 
2227  --*/
2228 {
2229  //
2230  // Disable WMI.
2231  //
2233 
2234  //
2235  // Disable any device interfaces.
2236  //
2238 
2239  DeleteSymbolicLinkOverload(GracefulRemove);
2240 
2241 
2242 
2243 
2244 
2245 
2246 
2247 
2248  // Flush/purge top-edge queues
2251  );
2252 
2253  //
2254  // Invoke EvtDeviceSelfManagedIoFlush
2255  //
2256  if (m_SelfManagedIoMachine != NULL) {
2258  }
2259 
2260  //
2261  // Tell all the resource objects that they no longer own anything.
2262  //
2264 
2265  //
2266  // Flush persistent state to permanent storage. We do this in the failed
2267  // state for the surprise removed case. By storing the state when we are
2268  // surprise removed, if the stack is reenumerated, it will pick up the saved
2269  // state that was just committed. If the state was saved during remove
2270  // device it can be too late because the new instance of the same device
2271  // could already be up and running and not pick up the saved state.
2272  //
2273  // It is important to save the state before completing the (potentially)
2274  // pended pnp irp. Completing the pnp irp will allow a new instance of the
2275  // device to be enumerated and we want to save state before that happens.
2276  //
2277  SaveState(FALSE);
2278 
2280  //
2281  // Don't care about the return code, just blindly try to complete the
2282  // wake request. The function can handle the case where there is no
2283  // irp to complete.
2284  //
2286  }
2287 }
2288 
2292  )
2293 /*++
2294 
2295 Routine Description:
2296  This function implements the Removing Disable
2297  Interfaces state. It disables any device interfaces
2298  and then tells the power policy state machine to prepare for device removal.
2299 
2300 Arguments:
2301  none
2302 
2303 Return Value:
2304 
2305  WdfDevStatePnpNull
2306 
2307 --*/
2308 {
2309  NTSTATUS status;
2310 
2311  //
2312  // Surprise remove path releases hardware first then disables the interfaces,
2313  // so do the same in the graceful remove path.
2314  //
2315 
2316  //
2317  // Call the driver and tell it to unmap resources.
2318  //
2319  status = This->PnpReleaseHardware();
2320  if (!NT_SUCCESS(status)) {
2321  //
2322  // The driver failed to unmap resources. Presumably this means that
2323  // there are now some leaked PTEs. Just log the failure.
2324  //
2326  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2327  "EvtDeviceReleaseHardware %p failed, %!STATUS!",
2328  This->m_Device->GetHandle(), status);
2329  }
2330 
2331  This->PnpCleanupForRemove(TRUE);
2332 
2333  //
2334  // Tell the power policy state machine to prepare for device removal
2335  //
2336  This->PnpPowerPolicyRemove();
2337 
2338  return WdfDevStatePnpNull;
2339 }
2340 
2344  )
2345 /*++
2346 
2347 Routine Description:
2348  Completes the pending request or sends it on its way.
2349 
2350 Arguments:
2351  This - instance of the state machine for the device
2352 
2353 Return Value:
2354  WdfDevStatePnpNull
2355 
2356  --*/
2357 {
2358 
2359  This->m_AchievedStart = TRUE;
2360 
2361  //
2362  // Log Telemetry event for the FDO
2363  //
2364  if (This->m_Device->IsPdo() == FALSE) {
2365  This->m_Device->FxLogDeviceStartTelemetryEvent();
2366  }
2367 
2368  This->PnpFinishProcessingIrp();
2369 
2370  return WdfDevStatePnpNull;
2371 }
2372 
2376  )
2377 /*++
2378 
2379 Routine Description:
2380  Cancel stop received from the started state. Just return to the started
2381  state where we will handle the pended irp.
2382 
2383 Arguments:
2384  This - Instance of the state machine
2385 
2386 Return Value:
2387  WdfDevStatePnpStarted
2388 
2389  --*/
2390 {
2392  return WdfDevStatePnpStarted;
2393 }
2394 
2398  )
2399 /*++
2400 
2401 Routine Description:
2402  Cancel remove received from the started state. Just return to the started
2403  state where we will handle the pended irp.
2404 
2405 Arguments:
2406  This - Instance of the state machine
2407 
2408 Return Value:
2409  WdfDevStatePnpStarted
2410 
2411  --*/
2412 {
2414 
2415  return WdfDevStatePnpStarted;
2416 }
2417 
2421  )
2422 /*++
2423 
2424 Routine Description:
2425  Remove directly from started. Power down the other state machines.
2426 
2427 Arguments:
2428  This - instance of the state machine
2429 
2430 Return Value:
2431  WdfDevStatePnpNull
2432 
2433  --*/
2434 {
2435  This->PnpPowerPolicyStop();
2436 
2437  return WdfDevStatePnpNull;
2438 }
2439 
2443  )
2444 /*++
2445 
2446 Routine Description:
2447  This function implements the Cancelling Stop state.
2448 
2449 Arguments:
2450  none
2451 
2452 Return Value:
2453 
2454  VOID
2455 
2456 --*/
2457 {
2458  //
2459  // Send an event to the Power Policy State Machine
2460  // telling it to "Start."
2461  //
2462  This->PnpPowerPolicyStart();
2463 
2464  return WdfDevStatePnpNull;
2465 }
2466 
2470  )
2471 /*++
2472 
2473 Routine Description:
2474  This function implements the Restarting From Stopped state. It's job
2475  is to map new resources and then proceed to the Restarting state.
2476 
2477 Arguments:
2478  none
2479 
2480 Return Value:
2481 
2482  VOID
2483 
2484 --*/
2485 {
2486  NTSTATUS status;
2487  BOOLEAN matched;
2488 
2489  status = This->PnpPrepareHardware(&matched);
2490 
2491  if (!NT_SUCCESS(status)) {
2492  //
2493  // We can handle remove out of the init state, revert back to that state
2494  //
2495  if (matched == FALSE) {
2496  //
2497  // Wait for the remove irp to come in
2498  //
2499  COVERAGE_TRAP();
2500  return WdfDevStatePnpFailed;
2501  }
2502  else {
2503  //
2504  // EvtDevicePrepareHardware is what failed, goto a state where we
2505  // undo that call.
2506  //
2507  COVERAGE_TRAP();
2509  }
2510  }
2511 
2512  return WdfDevStatePnpRestarting;
2513 }
2514 
2518  )
2519 /*++
2520 
2521 Routine Description:
2522  This function implements the Stopped state. It's job is to invoke
2523  EvtDeviceReleaseHardware.
2524 
2525 Arguments:
2526  none
2527 
2528 Return Value:
2529 
2530  VOID
2531 
2532 --*/
2533 {
2535  NTSTATUS status;
2536 
2537  status = This->PnpReleaseHardware();
2538  if (NT_SUCCESS(status)) {
2539  //
2540  // Tell all the resource objects that they no longer own anything.
2541  //
2542  This->NotifyResourceobjectsToReleaseResources();
2543 
2545  }
2546  else {
2547  DoTraceLevelMessage(This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
2548  "EvtDeviceReleaseHardware failed - %!STATUS!",
2549  status);
2550  COVERAGE_TRAP();
2551 
2552  This->SetInternalFailure();
2554  }
2555 
2556  //
2557  // Send the irp on its merry way. This irp (stop device) cannot be failed
2558  // and must always be sent down the stack.
2559  //
2560  This->PnpFinishProcessingIrp();
2561 
2562  return state;
2563 }
2564 
2568  )
2569 /*++
2570 
2571 Routine Description:
2572  The start irp is coming down from the stopped state. Send it down the stack
2573  and transition to the new state if needed.
2574 
2575 Arguments:
2576  This - instance of the state machine
2577 
2578 Return Value:
2579  new machine state
2580 
2581  --*/
2582 {
2583  if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) {
2584  //
2585  // The start irp's completion routine will move the state machine into
2586  // the new state.
2587  //
2588  return WdfDevStatePnpNull;
2589  }
2590 
2592 }
2593 
2597  )
2598 /*++
2599 
2600 Routine Description:
2601  Received a stop irp. Stop the power policy machine and then wait for it to
2602  complete.
2603 
2604 Arguments:
2605  This - instance of the state machine
2606 
2607 Return Value:
2608  WdfDevStatePnpNull
2609 
2610  --*/
2611 {
2612  //
2613  // It is important to stop power policy before releasing the reference.
2614  // If the reference was released first, we could get into a situation where
2615  // we immediately go idle and then we must send a D0 irp when in the remove.
2616  // If there are devices on top of this device and we send a D0 irp during
2617  // remove processing, the upper devices will be sent an irp after getting a
2618  // pnp remove (and either crash or fail the power irp upon receiving it).
2619  //
2620  This->PnpPowerPolicyStop();
2621  This->PnpPowerDereferenceSelf();
2622 
2623  return WdfDevStatePnpNull;
2624 }
2625 
2629  )
2630 /*++
2631 
2632 Routine Description:
2633  We got IRP_MN_SURPRISE_REMOVE_DEVICE while the system was pretty far down
2634  the removal path, or never started. Call EvtDeviceSurpriseRemoval, call the
2635  surprise remove virtual and drop into the Failed path.
2636 
2637 Arguments:
2638  This - instance of the state machine
2639 
2640 Return Value:
2641  new device pnp state
2642 
2643  --*/
2644 {
2645  //
2646  // Invoke EvtDeviceSurpriseRemove
2647  //
2648  This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle());
2649 
2650  //
2651  // Notify the virtual override of the surprise remove.
2652  //
2653  This->PnpEventSurpriseRemovePendingOverload();
2654 
2655  return WdfDevStatePnpFailed;
2656 }
2657 
2661  )
2662 /*++
2663 
2664 Routine Description:
2665  Query remove from the init state. Complete the pended request.
2666 
2667 Arguments:
2668  This - instance of th state machine.
2669 
2670 Return Value:
2671  WdfDevStatePnpNull
2672 
2673  --*/
2674 {
2675  FxIrp irp(This->ClearPendingPnpIrp());
2676 
2678  This->FireAndForgetIrp(&irp);
2679 
2680  return WdfDevStatePnpNull;
2681 }
2682 
2686  )
2687 /*++
2688 
2689 Routine Description:
2690  Handle a query remove canceled from the init state. Complete the pended
2691  request.
2692 
2693 Arguments:
2694  This - instance of the state machine
2695 
2696 Return Value:
2697  WdfDevStatePnpInit
2698 
2699  --*/
2700 {
2701  FxIrp irp(This->ClearPendingPnpIrp());
2702 
2703  This->FireAndForgetIrp(&irp);
2704 
2705  return WdfDevStatePnpInit;
2706 }
2707 
2711  )
2712 /*++
2713 
2714 Routine Description:
2715  FDO is being removed, hand off to the derived pnp package
2716 
2717 Arguments:
2718  This - instance of the state machine
2719 
2720 Return Value:
2721  new device pnp state
2722 
2723  --*/
2724 {
2725  return This->PnpEventFdoRemovedOverload();
2726 }
2727 
2731  )
2732 /*++
2733 
2734 Routine Description:
2735  The device was in a queried (either stop or cancel) state and was surprise
2736  removed from it.
2737 
2738 Arguments:
2739  This - instance of the state machine
2740 
2741 Return Value:
2742  new state, WdfDevStatePnpSurpriseRemoveIoStarted
2743 
2744  --*/
2745 {
2746  COVERAGE_TRAP();
2747 
2748  This->PnpPowerDereferenceSelf();
2749 
2751 }
2752 
2756  )
2757 /*++
2758 
2759 Routine Description:
2760  We got IRP_MN_SURPRISE_REMOVE_DEVICE while the system was more or less
2761  running. Start down the Surprise Remove/Device Failed path. This state
2762  calls EvtDeviceSurpriseRemoval, calls the virtual surprise remove overload,
2763  and then drops into the Failed path.
2764 
2765 Arguments:
2766  This - instance of the state machine
2767 
2768 Return Value:
2769  new device pnp state
2770 
2771  --*/
2772 {
2773  //
2774  // Invoke EvtDeviceSurpriseRemove
2775  //
2776 
2777  This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle());
2778 
2779  //
2780  // Notify the virtual override of the surprise remove.
2781  //
2782  This->PnpEventSurpriseRemovePendingOverload();
2783 
2785 }
2786 
2790  )
2791 /*++
2792 
2793 Routine Description:
2794  The device was in the started state and failed power down or could not
2795  enable its interfaces. Gracefully power down the device and tear down
2796  the stack.
2797 
2798  The difference between this routine and PnpEventFailedIoStarting is that
2799  FailedIoStarting sends a surprise remove to the power state machine. After
2800  surprise remove has been sent to the power state machine, it will not attempt
2801  to put the device into Dx because it assumes the device is no longer present.
2802  In this error case, we still want the device to be powered down, so we send
2803  a normal stop remove.
2804 
2805 Arguments:
2806  This - instance of the state machine
2807 
2808 Return Value:
2809  new state
2810 
2811  --*/
2812 {
2813  //
2814  // Normal stop so that the power state machine will go through the power off
2815  // path and not skip directly to off like it would if we sent it a surprise
2816  // remove notification.
2817  //
2818  This->PnpPowerPolicyStop();
2819 
2820  return WdfDevStatePnpNull;
2821 }
2822 
2826  )
2827 /*++
2828 
2829 Routine Description:
2830  The device failed (or was yanked out of the machine) while it was more
2831  or less running. Tell the driver to stop self-managed I/O and drop into
2832  the next state on the failure path.
2833 
2834 Arguments: j
2835  This - instance of the state machine
2836 
2837 Return Value:
2838  new device pnp state
2839 
2840  --*/
2841 {
2842  This->PnpPowerPolicySurpriseRemove();
2843 
2844  return WdfDevStatePnpNull;
2845 }
2846 
2850  )
2851 /*++
2852 
2853 Routine Description:
2854  The device failed (or was yanked out of the machine) while it owned access
2855  to the hardware. Tell the driver to release resources and drop into
2856  the next state on the failure path.
2857 
2858 Arguments:
2859  This - instance of the state machine
2860 
2861 Return Value:
2862  new device pnp state
2863 
2864  --*/
2865 {
2866  //
2867  // Invoke EvtDeviceReleaseHardware
2868  //
2869  (void) This->PnpReleaseHardware();
2870 
2871  return WdfDevStatePnpFailed;
2872 }
2873 
2877  )
2878 /*++
2879 
2880 Routine Description:
2881  The device failed (or was yanked out of the machine). Disable interfaces,
2882  flush queues and tell the driver to clean up random stuff.
2883  Also ask the power policy state machine to prepare for device removal.
2884 
2885 Arguments:
2886  This - instance of the state machine
2887 
2888 Return Value:
2889  WdfDevStatePnpNull
2890 
2891  --*/
2892 {
2893  This->PnpCleanupForRemove(FALSE);
2894 
2895  //
2896  // Tell the power policy state machine to prepare for device removal
2897  //
2898  This->PnpPowerPolicyRemove();
2899 
2900  return WdfDevStatePnpNull;
2901 }
2902 
2906  )
2907 /*++
2908 
2909 Routine Description:
2910  The power policy state machine has prepared for device removal. Invalidate
2911  the device state and wait for IRP_MN_REMOVE_DEVICE.
2912 
2913 Arguments:
2914  This - instance of the state machine
2915 
2916 Return Value:
2917  WdfDevStatePnpFailedWaitForRemove
2918 
2919  --*/
2920 {
2921  //
2922  // Finish processing any pended PnP IRP. Since we can reach this state from
2923  // states where a pnp irp was *not* pended, we do not require a pnp irp to
2924  // have been pended when trying to complete it.
2925  //
2926  This->PnpFinishProcessingIrp(FALSE);
2927 
2928  //
2929  // Request reenumeration if the client driver asked for it or if there was
2930  // an internal failure *and* if the client driver didn't specify failure...
2931  // AND if we have not yet exceeded our restart count within a period of time.
2932  //
2933  if ((This->m_FailedAction == WdfDeviceFailedAttemptRestart ||
2934  (This->m_FailedAction == WdfDeviceFailedUndefined && This->m_InternalFailure))
2935  &&
2936  This->PnpCheckAndIncrementRestartCount()) {
2937  //
2938  // No need to invalidate state because we are in a state waiting for
2939  // a remove device anyways so failure is imminent.
2940  //
2941  This->AskParentToRemoveAndReenumerate();
2942  }
2943 
2944  if (This->m_FailedAction != WdfDeviceFailedUndefined || This->m_InternalFailure) {
2945  //
2946  // If the failure occurred in this device, then tear down the stack if
2947  // we are in a state in which pnp thinks we are started. If we are
2948  // already in a stopped state, this invalidation will do no harm.
2949  //
2950  MxDeviceObject physicalDeviceObject(
2951  This->m_Device->GetPhysicalDevice()
2952  );
2953 
2954  //
2955  // We need to pass FDO as a parameter as UMDF currently doesn't have
2956  // PDOs and instead needs FDO to invalidate device state.
2957  //
2958  physicalDeviceObject.InvalidateDeviceState(
2959  This->m_Device->GetDeviceObject() //FDO
2960  );
2961  }
2962 
2964 }
2965 
2969  )
2970 /*++
2971 
2972 Routine Description:
2973  The device has failed and then received a surprise remove. This can easily
2974  happen on return from low power as following:
2975 
2976  1 device attempts to enter D0, D0Entry fails
2977  2 pnp state machine proceeds down failure path and stops at FailedWaitForRemove
2978  3 bus driver finds device missing, reports it as such and a s.r. irp
2979  arrives
2980 
2981 Arguments:
2982  This - instance of the state machine
2983 
2984 Return Value:
2985  WdfDevStatePnpFailedWaitForRemove
2986 
2987  --*/
2988 {
2989  //
2990  // Invoke EvtDeviceSurpriseRemove
2991  //
2992  This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle());
2993 
2994  //
2995  // Call the overloaded surprise remove handler
2996  //
2997  This->PnpEventSurpriseRemovePendingOverload();
2998 
2999  //
3000  // The surprise remove irp was pended, complete it now. The irp need not
3001  // be present. If we failed before the surprise irp was sent and the irp
3002  // arrived in the middle of processing the failure, we could have completed
3003  // the s.r. irp in FailedWaitForRemove, which is OK.
3004  //
3005  This->PnpFinishProcessingIrp(FALSE);
3006 
3007  //
3008  // Return back to the failed state where will wait for remove
3009  //
3011 }
3012 
3016  )
3017 /*++
3018 
3019 Routine Description:
3020  Device failed (probably somewhere in the start path) and got another start
3021  request. Fail the start and return to the state where we will wait for a
3022  remove irp.
3023 
3024 Arguments:
3025  This - instance of the state machine
3026 
3027 Return Value:
3028  WdfDevStatePnpFailedWaitForRemove
3029 
3030  --*/
3031 {
3032  //
3033  // Complete the pended start irp with error
3034  //
3035  This->SetPendingPnpIrpStatus(STATUS_INVALID_DEVICE_STATE);
3036  This->PnpFinishProcessingIrp();
3037 
3039 }
3040 
3044  )
3045 /*++
3046 
3047 Routine Description:
3048  Processing of the start irp's resources failed. Complete the start irp.
3049 
3050 Arguments:
3051  This - instance of the state machine
3052 
3053 Return Value:
3054  WdfDevStatePnpNull
3055 
3056  --*/
3057 {
3058  //
3059  // Release the power thread that we may have previously acquired in
3060  // HardwareAvailable.
3061  //
3062  This->ReleasePowerThread();
3063 
3064  //
3065  // Deref the reenumeration interface
3066  //
3067  This->ReleaseReenumerationInterface();
3068 
3069  This->PnpFinishProcessingIrp();
3070 
3071  return WdfDevStatePnpInit;
3072 }
3073 
3077  )
3078 /*++
3079 
3080 Routine Description:
3081  The driver failed EvtDeviceSoftwareInit. Run cleanup and die.
3082 
3083 Arguments:
3084  This - instance of the state machine
3085 
3086 Return Value:
3087  new device pnp state
3088 
3089  --*/
3090 {
3091  COVERAGE_TRAP();
3092 
3093 
3094  This->m_Device->EarlyDispose();
3095 
3096  //
3097  // All the children are in the disposed state, destroy them all. m_Device
3098  // is not destroyed in this call.
3099  //
3100 
3101  This->m_Device->DestroyChildren();
3102 
3103  return WdfDevStatePnpFinal;
3104 }
3105 
3109  )
3110 /*++
3111 
3112 Routine Description:
3113  A start to start transition has occurred. Go through the normal stop path
3114  first and then restart things.
3115 
3116 Arguments:
3117  This - instance of the state machine
3118 
3119 Return Value:
3120  WdfDevStateNull or new machine state
3121 
3122  --*/
3123 {
3124  //
3125  // Stop the power policy machine so that we simulate stopping first
3126  //
3127  This->PnpPowerPolicyStop();
3128 
3129  return WdfDevStatePnpNull;
3130 }
3131 
3135  )
3136 /*++
3137 
3138 Routine Description:
3139  Release the hardware resources and send the start irp down the stack
3140 
3141 Arguments:
3142  This - instance of the state machine
3143 
3144 Return Value:
3145  new machine state
3146 
3147  --*/
3148 {
3149  NTSTATUS status;
3150 
3151  status = This->PnpReleaseHardware();
3152  if (!NT_SUCCESS(status)) {
3154  This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
3155  "EvtDeviceReleaseHardware failed with %!STATUS!", status);
3156 
3157  COVERAGE_TRAP();
3158 
3159  This->SetInternalFailure();
3160  This->SetPendingPnpIrpStatus(status);
3161 
3162  return WdfDevStatePnpFailed;
3163  }
3164 
3165  if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) {
3166  //
3167  // The start irp's completion routine will move the state machine into
3168  // the new state.
3169  //
3170  return WdfDevStatePnpNull;
3171  }
3172 
3173  //
3174  // Start happened synchronously. Transition to the new state now.
3175  //
3177 }
3178 
3182  )
3183 /*++
3184 
3185 Routine Description:
3186  Prepare the hardware and restart the power and power policy state machines
3187  after a successful start -> start transition where the start irp is coming
3188  up the stack.
3189 
3190 Arguments:
3191  This - instance of the state machine
3192 
3193 Return Value:
3194  new machine state
3195 
3196  --*/
3197 {
3198  NTSTATUS status;
3199  BOOLEAN matched;
3200 
3201  status = This->PnpPrepareHardware(&matched);
3202 
3203  if (!NT_SUCCESS(status)) {
3204  if (matched == FALSE) {
3205  //
3206  // Wait for the remove irp to come in
3207  //
3208  COVERAGE_TRAP();
3209  return WdfDevStatePnpFailed;
3210  }
3211  else {
3212  //
3213  // EvtDevicePrepareHardware is what failed, goto a state where we
3214  // undo that call.
3215  //
3216  COVERAGE_TRAP();
3218  }
3219  }
3220 
3221  This->PnpPowerPolicyStart();
3222 
3223  return WdfDevStatePnpNull;
3224 }
3225 
3229  )
3230 /*++
3231 
3232 Routine Description:
3233  The PDO was in the removed state has received another start irp. Reset state
3234  and then move into the start sequence.
3235 
3236 Arguments:
3237  This - instance of the state machine
3238 
3239 Return Value:
3240  WdfDevStatePnpHardwareAvailable
3241 
3242  --*/
3243 {
3244  //
3245  // Since this is a PDO and it is being restarted, it could have had an internal
3246  // failure during its previous start. Since we use m_InternalFailure to set
3247  // PNP_DEVICE_FAILED when handling IRP_MN_QUERY_PNP_DEVICE_STATE, it should
3248  // be set to FALSE so we don't immediately fail the device after the start
3249  // has been succeeded.
3250  //
3251  This->m_InternalFailure = FALSE;
3252  This->m_Failed = FALSE;
3253 
3254  //
3255  // The PDO is being restarted and could have previous had a power thread
3256  // running. If so, the reference count goes to zero when removed from a
3257  // started state. Reset back to 1.
3258  //
3259  This->m_PowerThreadInterfaceReferenceCount = 1;
3260 
3261  //
3262  // The count is decremented on the initial started->removed transition (and
3263  // not subsequent removed -> removed transitiosn). On removed -> restarted,
3264  // we need to set the count back to a bias of 1 so when we process the remove
3265  // again we can know if there are any pending child (of this PDO) removals
3266  // that we must wait for.
3267  //
3268  This->m_PendingChildCount = 1;
3269 
3270  //
3271  // Reset WMI state
3272  //
3273  // This->m_Device->m_PkgWmi->ResetStateForPdoRestart(); __REACTOS__
3274 
3275 
3276  This->m_Device->m_PkgIo->ResetStateForRestart();
3277 
3278  if (This->IsPowerPolicyOwner()) {
3279  This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Reset();
3280  }
3281 
3282  //
3283  // Set STATUS_SUCCESS in the irp so that the stack will start smoothly after
3284  // we have powered up.
3285  //
3286  This->SetPendingPnpIrpStatus(STATUS_SUCCESS);
3287 
3288  //
3289  // This flag is set on the wake-enabled device powering down path,
3290  // but if the device power down failed it may not have been cleared.
3291  //
3292  This->m_WakeInterruptsKeepConnected = FALSE;
3293 
3294 
3295  //
3296  // This flag is cleared so we can reacquire the start time and state
3297  //
3298  This->m_AchievedStart = FALSE;
3299 
3301 }
3302 
3306  )
3307 /*++
3308 
3309 Routine Description:
3310  All of this device's previously enumerated children have been removed. Move
3311  the state machine into its next state based on the device's role.
3312 
3313 Arguments:
3314  This - instance of the state machine
3315 
3316 Return Value:
3317  new state
3318 
3319  --*/
3320 {
3321  return This->PnpGetPostRemoveState();
3322 }
3323 
3327  )
3328 /*++
3329 
3330 Routine Description:
3331  The final resting and dead state for the FxDevice that has been removed. We
3332  release our final reference here and destroy the object.
3333 
3334 Arguments:
3335  This - This instance of the state machine
3336 
3337 Return Value:
3338  WdfDevStatePnpNull
3339 
3340  --*/
3341 {
3342  NTSTATUS status;
3343 
3344  //
3345  // We may not have a pnp irp at this stage (esp for PDO which are in the
3346  // removed state and whose parent is being removed) so we use the function
3347  // pointer as the unique tag.
3348  //
3349  // IoReleaseRemoveLockAndWait requires an outstanding reference to release,
3350  // so acquire it before calling it if we are in the case where the PDO is
3351  // being removed with no outstanding PNP remove irp b/c the parent is being
3352  // removed.
3353  //
3354  if (This->m_DeviceRemoveProcessed == NULL) {
3356  This->m_Device->GetRemoveLock(),
3358 
3361  }
3362 
3363  //
3364  // Indicate to the parent device that we are removed now (vs the destructor
3365  // of the object where we would never reach because in the case of the PDO
3366  // being removed b/c the parent is going away, the parent has a reference
3367  // on the PDO).
3368 
3369 
3370 
3371 
3372 
3373 
3374 
3375  if (This->m_Device->m_ParentWaitingOnChild) {
3376  (This->m_Device->m_ParentDevice->m_PkgPnp)->ChildRemoved();
3377  }
3378 
3379 
3380  if (This->m_DeviceRemoveProcessed == NULL) {
3381  //
3382  // We can get into this state w/out an event to set when a PDO (this
3383  // device) is in the removed state and then the parent is removed.
3384  //
3385 
3386  //
3387  // After this is called, any irp dispatched to FxDevice::DispatchWithLock
3388  // will fail with STATUS_INVALID_DEVICE_REQUEST.
3389  //
3391  This->m_Device->GetRemoveLock(),
3393 
3394  //
3395  // Delete the object when we exit the state machine. Dispose was run
3396  // early in a previous state.
3397  //
3398  This->m_PnpMachine.SetDelayedDeletion();
3399  }
3400  else {
3401  //
3402  // The thread which received the pnp remove irp will delete the device
3403  //
3404  This->m_SetDeviceRemoveProcessed = TRUE;
3405  }
3406 
3407  return WdfDevStatePnpNull;
3408 }
3409 
3411 NTSTATUS
3413  VOID
3414  )
3415 /*++
3416 
3417 Routine Description:
3418  Enables all of the device interfaces and then registers wmi.
3419 
3420 Arguments:
3421  None
3422 
3423 Return Value:
3424  NT_SUCCESS if all goes well, !NT_SUCCESS otherwise
3425 
3426  --*/
3427 {
3429  NTSTATUS status;
3430 
3432 
3433  //
3434  // Enable any device interfaces.
3435  //
3436  m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals());
3437 
3439 
3440  for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
3442 
3444 
3445 
3446 
3447 
3448 
3449 
3450 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
3451  //
3452  // By this time, the device interface, no matter what the WDFDEVICE role
3453  // will have been registered.
3454  //
3456 #endif
3458 
3460  }
3461 
3462  m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals());
3463 
3464  if (NT_SUCCESS(status)) {
3466  }
3467 
3468  if (!NT_SUCCESS(status)) {
3471  }
3472 
3473  return status;
3474 }
3475 
3477 NTSTATUS
3478 FxPkgPnp::PnpPrepareHardware(
3479  __inout PBOOLEAN ResourcesMatched
3480  )
3481 /*++
3482 
3483 Routine Description:
3484  Matches the PNP resources with the WDFINTERRUPT objects registered and then
3485  calls EvtDevicePrepareHardware. All start paths call this function
3486 
3487 Arguments:
3488  ResourcesMatched - indicates to the caller what stage failed if !NT_SUCCESS
3489  is returned
3490 
3491 Return Value:
3492  NT_SUCCESS if all goes well, !NT_SUCCESS if failure occurrs
3493 
3494  --*/
3495 {
3496  NTSTATUS status;
3497  *ResourcesMatched = FALSE;
3498 
3499  //
3500  // FxPnpStateRemoved:
3501  // Mark the device a not removed. This is just so that anybody sending
3502  // a PnP IRP_MN_QUERY_DEVICE_STATE gets a reasonable answer.
3503  //
3504  // FxPnpStateFailed, FxPnpStateResourcesChanged:
3505  // Both of these values can be set to true and cause another start to
3506  // be sent down the stack. Reset these values back to false. If there is
3507  // a need to set these values, the driver can set them in
3508  // EvtDevicePrepareHardware.
3509  //
3516 
3517  //
3518  // This will parse the resources and setup all the WDFINTERRUPT handles
3519  //
3521 
3522  if (!NT_SUCCESS(status)) {
3523  *ResourcesMatched = FALSE;
3526  return status;
3527  }
3528 
3529 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
3530  //
3531  // Build register resource table
3532  //
3534  if (!NT_SUCCESS(status)) {
3537  goto exit;
3538  }
3539 
3540  //
3541  // Build Port resource table
3542  //
3544  if (!NT_SUCCESS(status)) {
3547  goto exit;
3548  }
3549 
3550  //
3551  // We keep track if the device has any connection resources,
3552  // in which case we allow unrestricted access to interrupts
3553  // regardless of the UmdfDirectHardwareAccess directive.
3554  //
3556  if (!NT_SUCCESS(status)) {
3559  goto exit;
3560  }
3561 #endif
3562 
3563  *ResourcesMatched = TRUE;
3564 
3567  );
3568 
3571  m_Resources->GetHandle());
3572 
3575  );
3576 
3577  if (!NT_SUCCESS(status)) {
3579  "EvtDevicePrepareHardware failed %!STATUS!", status);
3580 
3581  if (status == STATUS_NOT_SUPPORTED) {
3584  "EvtDevicePrepareHardware returned an invalid status "
3585  "STATUS_NOT_SUPPORTED");
3586 
3587  if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) {
3589  }
3590  }
3591 
3594  goto exit;
3595  }
3596 
3597  //
3598  // Now that we have assigned the resources to all the interrupts, figure out
3599  // the highest synch irql for each interrupt set which shares a spinlock.
3600  //
3602 
3603  //
3604  // Do mode-specific work. For KMDF, there is nothing additional to do.
3605  //
3607  if (!NT_SUCCESS(status)) {
3609  "PrepareHardware failed %!STATUS!", status);
3610 
3613  }
3614 
3615 exit:
3616  return status;
3617 }
3618 
3620 NTSTATUS
3622  VOID
3623  )
3624 /*++
3625 
3626 Routine Description:
3627  Invokes the driver's release hardware callback if present.
3628  Releases any interrupt resources allocated during the prepare hardware callback.
3629 
3630 Arguments:
3631  None
3632 
3633 Return Value:
3634  Driver's release hardware callback return status or
3635  STATUS_SUCCESS if callback is not present.
3636 
3637  --*/
3638 {
3639  NTSTATUS status;
3640  FxInterrupt* interrupt;
3641  PLIST_ENTRY le;
3642 
3643  //
3644  // Invoke the device's release hardware callback.
3645  //
3647  m_Device->GetHandle(),
3648  m_Resources->GetHandle());
3649 
3650  if (status == STATUS_NOT_SUPPORTED) {
3653  "EvtDeviceReleaseHardware returned an invalid status "
3654  "STATUS_NOT_SUPPORTED");
3655 
3656  if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) {
3658  }
3659  }
3660 
3661 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
3662  if (NT_SUCCESS(status)) {
3663  //
3664  // make sure driver has unmapped its resources
3665  //
3667  }
3668 
3669  //
3670  // delete the register and port resource tables
3671  //
3674 #endif
3675 
3676  //
3677  // Delete all interrupt objects that were created in the prepare hardware
3678  // callback that the driver did not explicitly delete (in reverse order).
3679  //
3681 
3682  while(le != &m_InterruptListHead) {
3683 
3684  // Find the interrupt object pointer.
3685  interrupt = CONTAINING_RECORD(le, FxInterrupt, m_PnpList);
3686 
3687  // Advance the entry before it becomes invalid.
3688  le = le->Blink;
3689 
3690  // Let the interrupt know that 'release hardware' was called.
3691  interrupt->OnPostReleaseHardware();
3692  }
3693 
3694  return status;
3695 }
3696 
3697 VOID
3699  VOID
3700  )
3701 /*++
3702 
3703 Routine Description:
3704  Informs the power policy state machine that it should start.
3705 
3706 Arguments:
3707  None
3708 
3709 Return Value:
3710  None
3711 
3712  --*/
3713 {
3715 }
3716 
3717 VOID
3719  VOID
3720  )
3721 /*++
3722 
3723 Routine Description:
3724  Informs the power and power policy state machines that they should stop.
3725 
3726 Arguments:
3727  None
3728 
3729 Return Value:
3730  None
3731 
3732  --*/
3733 {
3735 }
3736 
3737 VOID
3739  VOID
3740  )
3741 /*++
3742 
3743 Routine Description:
3744  Informs the policy state machines that it should stop due to the hardware
3745  being surprise removed.
3746 
3747 Arguments:
3748  None
3749 
3750 Return Value:
3751  None
3752 
3753  --*/
3754 {
3756 }
3757 
3758 VOID
3760  VOID
3761  )
3762 /*++
3763 
3764 Routine Description:
3765  Informs the policy state machine that it should prepare for device removal.
3766 
3767 Arguments:
3768  None
3769 
3770 Return Value:
3771  None
3772 
3773  --*/
3774 {
3776 }
3777 
3778 VOID
3780  __in BOOLEAN IrpMustBePresent
3781  )
3782 /*++
3783 
3784 Routine Description:
3785  Finishes handling a pended pnp irp
3786 
3787 Arguments:
3788  None
3789 
3790 Return Value:
3791  None
3792 
3793  --*/
3794 {
3795  FxIrp irp;
3796 
3797  UNREFERENCED_PARAMETER(IrpMustBePresent);
3798  ASSERT(IrpMustBePresent == FALSE || IsPresentPendingPnpIrp());
3799 
3800  //
3801  // Start device is the only request we handle on the way back up the stack.
3802  // Also, if we fail any pnp irps that we are allowed to fail, we just
3803  // complete them.
3804  //
3805  if (IsPresentPendingPnpIrp()) {
3806 
3809  ||
3810  !NT_SUCCESS(irp.GetStatus())) {
3811 
3814  }
3815  else {
3817  }
3818  }
3819 }
3820 
3821 VOID
3823  VOID
3824  )
3825 /*++
3826 
3827 Routine Description:
3828  Disables all of the registerd interfaces on the device.
3829 
3830 Arguments:
3831  None
3832 
3833 Return Value:
3834  None
3835 
3836  --*/
3837 {
3839 
3840  m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals());
3841 
3843 
3844  for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
3845 
3849  }
3850 
3851  m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals());
3852 }
3853 
3854 VOID
3856  VOID
3857  )
3858 {
3859 
3860  //
3861  // Mark all of the children as missing because the parent has just been
3862  // removed. Note that this will happen after all of the children have
3863  // already received the surprise remove event. This is OK because the
3864  // reported status is inspected during the remove device event which will
3865  // happen after the parent finishes processing the surprise event.
3866  //
3867  if (m_EnumInfo != NULL) {
3870 
3871  ple = NULL;
3872  while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) {
3874  }
3875 
3877  }
3878 }
3879 
3881 NTSTATUS
3883  VOID
3884  )
3885 /*++
3886 
3887 Routine Description:
3888 
3889  This method is called in response to a PnP StartDevice IRP
3890  coming up the stack. It:
3891 
3892  - Captures the device's resources
3893  - Calls out to interested resource objects
3894  - Sends an event to the PnP state machine
3895 
3896 Arguemnts:
3897 
3898  Irp - a pointer to the FxIrp
3899 
3900 Returns:
3901 
3902  NTSTATUS
3903 
3904 --*/
3905 {
3906  PCM_RESOURCE_LIST pResourcesRaw;
3907  PCM_RESOURCE_LIST pResourcesTranslated;
3908  FxResourceCm* resCmRaw;
3909  FxResourceCm* resCmTrans;
3910  FxInterrupt* interrupt;
3911  PLIST_ENTRY ple;
3912  NTSTATUS status;
3913  FxCollectionEntry *curRaw, *curTrans, *endTrans;
3914  ULONG messageCount;
3915  FxIrp irp;
3916 
3918  "Entering PnpMatchResources");
3919 
3920  //
3921  // We must clear these flags before calling into the event handler because
3922  // it might set these states back (which is OK). If we don't clear these
3923  // states and the start succeeds, we would endlessly report that our
3924  // resources have changed and be restarted over and over.
3925  //
3930 
3932  pResourcesRaw = irp.GetParameterAllocatedResources();
3933  pResourcesTranslated = irp.GetParameterAllocatedResourcesTranslated();
3934 
3936  if (!NT_SUCCESS(status)) {
3939  "Could not allocate raw resource list for WDFDEVICE 0x%p, %!STATUS!",
3940  m_Device->GetHandle(), status);
3941  goto Done;
3942  }
3943 
3944  status = m_Resources->BuildFromWdmList(pResourcesTranslated, FxResourceNoAccess);
3945  if (!NT_SUCCESS(status)) {
3948  "Could not allocate translated resource list for WDFDEVICE 0x%p, %!STATUS!",
3949  m_Device->GetHandle(), status);
3950  goto Done;
3951  }
3952 
3953  //
3954  // reset the stored information in all interrupts in the rebalance case
3955  //
3956  for (ple = m_InterruptListHead.Flink;
3958  ple = ple->Flink) {
3959  interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList);
3960  interrupt->Reset();
3961  }
3962 
3963  //
3964  // Now iterate across the resources, looking for ones that correspond
3965  // to objects that we are managing. Tell those objects about the resources
3966  // that were assigned.
3967  //
3969 
3970  endTrans = m_Resources->End();
3971 
3972  for (curTrans = m_Resources->Start(), curRaw = m_ResourcesRaw->Start();
3973  curTrans != endTrans;
3974  curTrans = curTrans->Next(), curRaw = curRaw->Next()) {
3975 
3976  ASSERT(curTrans->m_Object->GetType() == FX_TYPE_RESOURCE_CM);
3977  ASSERT(curRaw->m_Object->GetType() == FX_TYPE_RESOURCE_CM);
3978 
3979  resCmRaw = (FxResourceCm*) curRaw->m_Object;
3980 
3981  if (resCmRaw->m_Descriptor.Type == CmResourceTypeInterrupt) {
3982  //
3983  // We're looking at an interrupt resource.
3984  //
3985  if (ple->Flink == &m_InterruptListHead) {
3986  //
3987  // Oops, there are no more interrupt objects.
3988  //
3991  "Not enough interrupt objects created by WDFDEVICE 0x%p",
3992  m_Device->GetHandle());
3993  break;
3994  }
3995 
3996  resCmTrans = (FxResourceCm*) curTrans->m_Object;
3998 
3999  messageCount = resCmRaw->m_Descriptor.u.MessageInterrupt.Raw.MessageCount;
4000 
4002  &&
4003  (messageCount > 1)) {
4004  ULONG i;
4005  //
4006  // Multi-message MSI 2.2 needs to be handled differently
4007  //
4008  for (i = 0, ple = ple->Flink;
4009  i < messageCount && ple != &m_InterruptListHead;
4010  i++, ple = ple->Flink) {
4011 
4012  //
4013  // Get the next interrupt object.
4014  //
4015  interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList);
4016 
4017  //
4018  // Tell the interrupt object what its resources are.
4019  //
4020  interrupt->AssignResources(&resCmRaw->m_Descriptor,
4021  &resCmTrans->m_Descriptor);
4022  }
4023  }
4024  else {
4025  //
4026  // This is either MSI2.2 with 1 message, MSI-X or Line based.
4027  //
4028  ple = ple->Flink;
4029  interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList);
4030 
4031  //
4032  // Tell the interrupt object what its resources are.
4033  //
4034  interrupt->AssignResources(&resCmRaw->m_Descriptor,
4035  &resCmTrans->m_Descriptor);
4036  }
4037  }
4038  }
4039 
4040 #if FX_IS_KERNEL_MODE
4041 
4042 
4043 
4044 
4045 
4046 
4047 
4048 
4049 
4050  //
4051  // If there are any pended I/Os that were sent to the target
4052  // that were pended in the transition to stop, then this will
4053  // resend them.
4054  //
4055  // ISSUE: This has the potential of I/O completing
4056  // before the driver's start callback has been called...but,
4057  // this is the same as the PDO pending a sent irp and completing
4058  // it when the PDO is restarted before the FDO has a change to
4059  // process the start irp which was still pended below.
4060  //
4061  if (m_Device->IsFilter()) {
4062  //
4063  // If this is a filter device, then copy the FILE_REMOVABLE_MEDIA
4064  // characteristic from the lower device.
4065  //
4066  if (m_Device->GetAttachedDevice()->Characteristics & FILE_REMOVABLE_MEDIA) {
4067  ULONG characteristics;
4068 
4069  characteristics =
4070  m_Device->GetDeviceObject()->Characteristics | FILE_REMOVABLE_MEDIA;
4071 
4072  m_Device->GetDeviceObject()->Characteristics = characteristics;
4073  }
4074 
4075 
4076 
4077 
4078 
4079 
4080 
4081 
4082 
4083 
4085  }
4086 
4087 #endif // FX_IS_KERNEL_MODE
4088 
4089 Done:
4091  "Exiting PnpMatchResources %!STATUS!", status);
4092 
4093  return status;
4094 }
4095 
4096 VOID
4098  VOID
4099  )
4100 /*++
4101 
4102 Routine Description:
4103  Figure out the highest synch irql for each interrupt set which shares a
4104  spinlock.
4105 
4106  foreach(interrupt assigned to this instance)
4107  determine the max sync irql in the set
4108  set all the associated interrupts to the sync irql
4109  set the sync irql on the first interrupt in the set
4110 
4111 Arguments:
4112  None
4113 
4114 Return Value:
4115  None
4116 
4117  --*/
4118 {
4119  PLIST_ENTRY ple;
4120  FxInterrupt* pInterrupt;
4121 
4122  for (ple = m_InterruptListHead.Flink;
4124  ple = ple->Flink) {
4125 
4126  KIRQL syncIrql;
4127 
4128  pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList);
4129 
4130  syncIrql = pInterrupt->GetResourceIrql();
4131 
4132  if (syncIrql == PASSIVE_LEVEL) {
4133  //
4134  // The irql associated with the resources assigned is passive,
4135  // this can happen in the following scenarios:
4136  //
4137  // (1) no resources were assigned. Skip this interrupt b/c it has
4138  // no associated resources. Note: setting the SynchronizeIrql
4139  // to PASSIVE_LEVEL is a no-op.
4140  //
4141  // (2) this interrupt is handled at passive-level.
4142  // Set SynchronizeIrql to passive-level and continue.
4143  //
4144  pInterrupt->SetSyncIrql(PASSIVE_LEVEL);
4145  continue;
4146  }
4147 
4148  if (pInterrupt->IsSharedSpinLock() == FALSE) {
4149  //
4150  // If the interrupt spinlock is not shared, it's sync irql is the
4151  // irql assigned to it in the resources.
4152  //
4153  pInterrupt->SetSyncIrql(syncIrql);
4154  }
4155  else if (pInterrupt->IsSyncIrqlSet() == FALSE) {
4156  FxInterrupt* pFwdInterrupt;
4157  PLIST_ENTRY pleFwd;
4158 
4159  //
4160  // Find all of the other interrupts which share the lock and compute
4161  // the max sync irql.
4162  //
4163  for (pleFwd = ple->Flink;
4164  pleFwd != &m_InterruptListHead;
4165  pleFwd = pleFwd->Flink) {
4166 
4167  pFwdInterrupt = CONTAINING_RECORD(pleFwd, FxInterrupt, m_PnpList);
4168 
4169  //
4170  // If the 2 do not share the same lock, they are not in the same
4171  // set.
4172  //
4173  if (pFwdInterrupt->SharesLock(pInterrupt) == FALSE) {
4174  continue;
4175  }
4176 
4177  if (pFwdInterrupt->GetResourceIrql() > syncIrql) {
4178  syncIrql = pFwdInterrupt->GetResourceIrql();
4179  }
4180  }
4181 
4182  //
4183  // Now that we found the max sync irql, set it for all interrupts in
4184  // the set which share the lock
4185  //
4186  for (pleFwd = ple->Flink;
4187  pleFwd != &m_InterruptListHead;
4188  pleFwd = pleFwd->Flink) {
4189 
4190  pFwdInterrupt = CONTAINING_RECORD(pleFwd, FxInterrupt, m_PnpList);
4191 
4192  //
4193  // If the 2 do not share the same lock, they are not in the same
4194  // set.
4195  //
4196  if (pFwdInterrupt->SharesLock(pInterrupt) == FALSE) {
4197  continue;
4198  }
4199 
4200  pFwdInterrupt->SetSyncIrql(syncIrql);
4201  }
4202 
4203  //
4204  // Set the sync irql for the first interrupt in the set. We have set
4205  // the sync irql for all other interrupts in the set.
4206  //
4207  pInterrupt->SetSyncIrql(syncIrql);
4208  }
4209  else {
4210  //
4211  // If IsSyncIrqlSet is TRUE, we already covered this interrupt in a
4212  // previous pass of this loop when we computed the max sync irql for
4213  // an interrupt set.
4214  //
4215  ASSERT(pInterrupt->GetSyncIrql() > PASSIVE_LEVEL);
4216  DO_NOTHING();
4217  }
4218  }
4219 }
4220 
4222 NTSTATUS
4226  )
4227 /*++
4228 
4229 Routine Description:
4230  Makes sure the specified resource is valid.
4231 
4232 Arguments:
4233  CmResourceRaw - the raw resource to validate.
4234  CmResource - the translated resources to validate.
4235 
4236 Return Value:
4237  STATUS_SUCCESS if resource is valid or
4238  NTSTATUS error.
4239 
4240  --*/
4241 {
4242  NTSTATUS status;
4244  FxCollectionEntry* curRaw;
4245  FxResourceCm* res;
4246  FxResourceCm* resRaw;
4248 
4250  ASSERT(m_Resources != NULL);
4251 
4252  res = NULL;
4253  resRaw = NULL;
4254 
4256 
4257  //
4258  // Find the resource in our list.
4259  //
4260  for (cur = m_Resources->Start(), curRaw = m_ResourcesRaw->Start();
4261  cur != m_Resources->End();
4262  cur = cur->Next(), curRaw = curRaw->Next()) {
4263 
4264  res = (FxResourceCm*) cur->m_Object;
4265  resRaw = (FxResourceCm*) curRaw->m_Object;
4266 
4267  if (&res->m_DescriptorClone == *CmResource) {
4268  break;
4269  }
4270  }
4271 
4272  //
4273  // Error out if not found.
4274  //
4275  if (cur == m_Resources->End()) {
4279  "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, "
4280  "WDFDEVICE 0x%p, %!STATUS!",
4281  *CmResource, m_Device->GetHandle(), status);
4283  goto Done;
4284  }
4285 
4286  //
4287  // Error out if the associated raw resource is not the same.
4288  //
4289  if (&resRaw->m_DescriptorClone != *CmResourceRaw) {
4293  "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, "
4294  "WDFDEVICE 0x%p, %!STATUS!",
4295  *CmResourceRaw, m_Device->GetHandle(), status);
4297  goto Done;
4298  }
4299 
4300  //
4301  // Make sure driver didn't change any of the PnP settings.
4302  //
4303  if (sizeof(res->m_Descriptor) !=
4304  RtlCompareMemory(&res->m_DescriptorClone,
4305  &res->m_Descriptor,
4306  sizeof(res->m_Descriptor))) {
4310  "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, "
4311  "driver cannot change the assigned PnP resources, WDFDEVICE 0x%p, "
4312  "%!STATUS!",
4313  *CmResource, m_Device->GetHandle(), status);
4315  goto Done;
4316  }
4317 
4318  if (sizeof(resRaw->m_Descriptor) !=
4320  &resRaw->m_Descriptor,
4321  sizeof(resRaw->m_Descriptor))) {
4325  "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, "
4326  "driver cannot change the assigned PnP resources, WDFDEVICE 0x%p, "
4327  "%!STATUS!",
4328  *CmResourceRaw, m_Device->GetHandle(), status);
4330  goto Done;
4331  }
4332 
4333  //
4334  // Return the real descriptor.
4335  //
4336  ASSERT(res != NULL && resRaw != NULL);
4337  *CmResource = &res->m_Descriptor;
4338  *CmResourceRaw = &resRaw->m_Descriptor;
4339 
4341 
4342 Done:
4343  return status;
4344 }
4345 
4347 NTSTATUS
4349  __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResourceRaw,
4350  __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResource,
4352  )
4353 /*++
4354 
4355 Routine Description:
4356  Makes sure the specified resource is valid for an interrupt resource.
4357 
4358 Arguments:
4359  CmIntResourceRaw - the raw interrupt resource to validate.
4360  CmIntResource - the translated interrupt resource to validate.
4361 
4362 Return Value:
4363  STATUS_SUCCESS if resource is valid or
4364  NTSTATUS error.
4365 
4366  --*/
4367 {
4368  NTSTATUS status;
4369  PLIST_ENTRY le;
4370  FxInterrupt* interrupt;
4371  ULONG messageCount;
4373  PCM_PARTIAL_RESOURCE_DESCRIPTOR cmIntResourceRaw;
4374  PCM_PARTIAL_RESOURCE_DESCRIPTOR cmIntResource;
4375 
4376  cmIntResourceRaw = CmIntResourceRaw;
4377  cmIntResource = CmIntResource;
4379 
4380  //
4381  // Get the real descriptor not the copy.
4382  //
4383  status = ValidateCmResource(&cmIntResourceRaw, &cmIntResource);
4384  if (!NT_SUCCESS(status)) {
4385  goto Done;
4386  }
4387 
4388  //
4389  // Make sure this is an interrupt resource.
4390  //
4391  if (cmIntResourceRaw->Type != CmResourceTypeInterrupt) {
4395  "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not an "
4396  "interrupt resource, WDFDEVICE 0x%p, %!STATUS!",
4397  CmIntResourceRaw, m_Device->GetHandle(), status);
4399  goto Done;
4400  }
4401 
4402  if (cmIntResource->Type != CmResourceTypeInterrupt) {
4406  "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not an "
4407  "interrupt resource, WDFDEVICE 0x%p, %!STATUS!",
4408  CmIntResource, m_Device->GetHandle(), status);
4410  goto Done;
4411  }
4412 
4413  //
4414  // Make sure resource was not claimed by another interrupt.
4415  // Multi-message MSI 2.2 interrupts: allowed to reuse claimed resources.
4416  // Driver must create them sequentially.
4417  // Line-based interrupts: allowed to reuse claimed resources.
4418  // Driver can create them out-of-order.
4419  // Other MSI: not allowed to reuse claimed resources.
4420  //
4421  messageCount = 0;
4422 
4423  for (le = m_InterruptListHead.Flink;
4424  le != &m_InterruptListHead;
4425  le = le->Flink) {
4426 
4427  interrupt = CONTAINING_RECORD(le, FxInterrupt, m_PnpList);
4428 
4429  if (cmIntResource != interrupt->GetResources()) {
4430  //
4431  // Multi-message MSI 2.2 interrupts must be sequential.
4432  //
4433  if (messageCount != 0) {
4437  "Multi-message MSI 2.2 interrupts must be created "
4438  "sequentially, WDFDEVICE 0x%p, %!STATUS!",
4439  m_Device->GetHandle(), status);
4441  goto Done;
4442  }
4443 
4444  continue;
4445  }
4446 
4447  if (interrupt->IsWakeCapable() &&
4448  Configuration->PassiveHandling) {
4451  "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used "
4452  "to create a wakable interrupt 0x%p, WDFDEVICE 0x%p and "
4453  "any functional interrupt being shared with wakable interrupt "
4454  "can not use passive level handling",
4455  CmIntResource, interrupt->GetHandle(),
4456  m_Device->GetHandle());
4458  goto Done;
4459  }
4460 
4461  if (interrupt->IsPassiveHandling() &&
4462  Configuration->CanWakeDevice) {
4465  "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used "
4466  "to create a passive level interrupt 0x%p, WDFDEVICE 0x%p and "
4467  "is now being used to create a wakable interrupt. A functional "
4468  "passive level interrupt can not be shared with wakable interrupt",
4469  CmIntResource, interrupt->GetHandle(),
4470  m_Device->GetHandle());
4472  goto Done;
4473  }
4474 
4475  //
4476  // Check for multi-message MSI 2.2 interrupts. These are allowed
4477  // to use the same resource.
4478  // We allow line based interrupts to reuse claimed resources.
4479  //
4480  if (FxInterrupt::_IsMessageInterrupt(cmIntResource->Flags) == FALSE) {
4483  "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used "
4484  "to create interrupt 0x%p, WDFDEVICE 0x%p",
4485  CmIntResource, interrupt->GetHandle(),
4486  m_Device->GetHandle());
4487  continue;
4488  }
4489 
4490  //
4491  // Only allow the correct # of messages.
4492  //
4493  messageCount++;
4494  if (messageCount >
4495  cmIntResourceRaw->u.MessageInterrupt.Raw.MessageCount) {
4496 
4500  "All the MSI 2.2 interrupts for "
4501  "PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p are already created, "
4502  "WDFDEVICE 0x%p, %!STATUS!",
4503  CmIntResource, m_Device->GetHandle(), status);
4505  goto Done;
4506  }
4507  }
4508 
4510 
4511 Done:
4512  return status;
4513 }
4514 
4515 #define RESTART_START_ACHIEVED_NAME L"StartAchieved"
4516 #define RESTART_START_TIME_NAME L"StartTime"
4517 #define RESTART_COUNT_NAME L"Count"
4518 
4522 
4525 
4526 BOOLEAN
4528  _In_ HANDLE RestartKey,
4529  _In_ BOOLEAN CreatedNewKey
4530  )
4531 /*++
4532 
4533 Routine Description:
4534  This routine determines if this device should ask the bus driver to
4535  reenumerate the device. This is determined by how many times the entire
4536  stack has asked for a restart within a given period. This is stack wide
4537  because the settings are stored in a key in the device node itself (which all
4538  devices share).
4539 
4540  The period and number of times a restart are attempted are defined as constants
4541  (m_RestartTimePeriodMaximum, m_RestartCountMaximum)in this class. They are
4542  current defined as a period of 60 seconds and a restart max count of 5.
4543 
4544  The settings are stored in a volatile key so that they do not persist across
4545  machine reboots. Persisting across reboots makes no sense if we restrict the
4546  number of restarts w/in a period.
4547 
4548  The rules are as follows
4549  1) if the key does not exist, treat this as the beginning of the period
4550  and ask for a reenumeration
4551  2) if the key exists
4552  a) if the beginning of the period and the restart count cannot be read
4553  do not ask for a reenumeration
4554  b) if the beginning of the period is after the current time, either the
4555  current tick count has wrapped or the key has somehow survived a
4556  reboot. Either way, treat this as a reset of the period and ask
4557  for a reenumeration
4558  c) if the current time is after the period start time and within the
4559  restart period, increment the restart count. if the count is <=
4560  the max restart count, ask for a reenumeration. If it exceeds the
4561  max, do not ask for a reenumeration.
4562  d) if the current time is after the period stat time and exceeds the
4563  maximum period, and if the device as reached the started state,
4564  reset the period, count, and started state, then ask for a
4565  reenumeration.
4566 
4567 Considerations:
4568  There is a reenumeration loop that a device can get caught in. If a device
4569  takes more than m_RestartTimePeriodMaximum to fail m_RestartCountMaximum
4570  times then the device will be caught in this loop. If it is failing on the
4571  way to PnpEventStarted then the device will likely cause a 9F bugcheck.
4572  This is because they hold a power lock while in this loop. If the device
4573  fails after PnpEventStarted then pnp can progress and the device can loop
4574  here indefinitely. We have shipped with this behavior for several releases,
4575  so we are hesitant to completely change this behavior. The concern is that
4576  a device out there relies on this behavior.
4577 
4578 Arguments:
4579  RestartKey - opened handle to the Restart registry key
4580  CreatedNewKey - TRUE if the Restart key was created just now
4581 
4582 Return Value:
4583  TRUE if a restart should be requested.
4584 
4585 --*/
4586 {
4588  ULONG count;
4589  LARGE_INTEGER currentTickCount, startTickCount;
4590  BOOLEAN started, writeTick, writeCount, writeStarted;
4591 
4595 
4596  count = 0;
4597  started = FALSE;
4598  writeTick = FALSE;
4599  writeCount = FALSE;
4600  writeStarted = FALSE;
4601 
4602  Mx::MxQueryTickCount(&currentTickCount);
4603 
4604  started = m_AchievedStart;
4605  if (started) {
4606  //
4607  // Save the fact the driver started without failing
4608  //
4609  writeStarted = TRUE;
4610  }
4611 
4612 
4613  //
4614  // If the key was created right now, there is nothing to check, just write out
4615  // the data.
4616  //
4617  if (CreatedNewKey) {
4618  writeTick = TRUE;
4619  writeCount = TRUE;
4620 
4621  //
4622  // First restart
4623  //
4624  count = 1;
4625  }
4626  else {
4627  ULONG length, type;
4628 
4629  //
4630  // First try to get the start time of when we first attempted a restart
4631  //
4632  status = FxRegKey::_QueryValue(GetDriverGlobals(),
4633  RestartKey,
4634  &valueNameStartTime,
4635  sizeof(startTickCount.QuadPart),
4636  &startTickCount.QuadPart,
4637  &length,
4638  &type);
4639 
4640  if (NT_SUCCESS(status) &&
4641  length == sizeof(startTickCount.QuadPart) && type == REG_BINARY) {
4642 
4643  //
4644  // Now try to get the last restart count
4645  //
4646  status = FxRegKey::_QueryULong(RestartKey,
4647  &valueNameCount,
4648  &count);
4649 
4651  //
4652  // We read the start time, but not the count. Assume there was
4653  // at least one previous restart.
4654  //
4655  count = 1;
4657  }
4658  }
4659 
4660  if (NT_SUCCESS(status)) {
4661  if (currentTickCount.QuadPart < startTickCount.QuadPart) {
4662  //
4663  // Somehow the key survived a reboot or the clock overflowed
4664  // and the current time is less then the last time we started
4665  // timing restarts. Either way, just treat this as the first
4666  // time we are restarting.
4667  //
4668  writeTick = TRUE;
4669  writeCount = TRUE;
4670  count = 1;
4671  }
4672  else {
4673  LONGLONG delta;
4674 
4675  //
4676  // Compute the difference in time in 100 ns units
4677  //
4678  delta = (currentTickCount.QuadPart - startTickCount.QuadPart) *
4680 
4682  //
4683  // We are within the time limit, see if we are within the
4684  // count limit
4685  count++;
4686 
4687  //
4688  // The count starts at one, so include the maximum in the
4689  // compare.
4690  //
4691  if (count <= m_RestartCountMaximum) {
4692  writeCount = TRUE;
4693  }
4694  else {
4695  //
4696  // Exceeded the restart count, do not attempt to restart
4697  // the device.
4698  //
4700  }
4701  }
4702  else {
4703  if (started == FALSE) {
4704  ULONG length, type, value;
4705  status = FxRegKey::_QueryValue(GetDriverGlobals(),
4706  RestartKey,
4707  &valueNameStartAchieved,
4708  sizeof(value),
4709  &value,
4710  &length,
4711  &type);
4712  if (!NT_SUCCESS(status) || length != sizeof(value) ||
4713  type != REG_DWORD) {
4714  value = 0;
4715  }
4716  started = value != 0;
4718  }
4719 
4720  if (started) {
4721  //
4722  // Exceeded the time limit. This is treated as a reset of
4723  // the time limit, so we will try to restart and reset the
4724  // start time and restart count.
4725  //
4726  writeTick = TRUE;
4727  writeCount = TRUE;
4728  count = 1;
4729 
4730  //
4731  // Erase the fact the driver once started and
4732  // make it do it again to get another 5 attempts to
4733  // restart.
4734  //
4735  writeStarted = TRUE;
4736  started = FALSE;
4737  }
4738  else {
4739  //
4740  // Device never started
4741  //
4743  }
4744  }
4745  }
4746  }
4747  }
4748 
4749  if (writeTick) {
4750  //
4751  // Write out the time and the count
4752  //
4753  NTSTATUS status2;
4754  status2 = FxRegKey::_SetValue(RestartKey,
4755  (PUNICODE_STRING)&valueNameStartTime,
4756  REG_BINARY,
4757  &currentTickCount.QuadPart,
4758  sizeof(currentTickCount.QuadPart));
4759  //
4760  // Don't let status report success if it was an error prior to _SetValue
4761  //
4762  if(NT_SUCCESS(status)) {
4763  status = status2;
4764  }
4765  }
4766 
4767  if (NT_SUCCESS(status) && writeCount) {
4768  status = FxRegKey::_SetValue(RestartKey,
4769  (PUNICODE_STRING)&valueNameCount,
4770  REG_DWORD,
4771  &count,
4772  sizeof(count));
4773  }
4774 
4775  if (writeStarted) {
4776  NTSTATUS status2;
4777  DWORD value = started;
4778  status2 = FxRegKey::_SetValue(RestartKey,
4779  (PUNICODE_STRING)&valueNameStartAchieved,
4780  REG_DWORD,
4781  &value,
4782  sizeof(value));
4783  //
4784  // Don't let status report success if it was an error prior to _SetValue
4785  //
4786  if(NT_SUCCESS(status)) {
4787  status = status2;
4788  }
4789  }
4790 
4791  return NT_SUCCESS(status) ? TRUE : FALSE;
4792 }
4793 
VOID SaveState(__in BOOLEAN UseCanSaveState)
Definition: fxpkgpnp.cpp:5831
static __inline NTSTATUS MxAcquireRemoveLock(__in MdRemoveLock RemoveLock, __in_opt PVOID Tag)
Definition: mxgeneralkm.h:268
enum _WDF_DEVICE_PNP_STATE WDF_DEVICE_PNP_STATE
BOOLEAN IsSharedSpinLock(VOID)
static WDF_DEVICE_PNP_STATE PnpEventQueriedRemoving(__inout FxPkgPnp *This)
FxPnpMachineStateHistory m_States
FxPnpDeviceReleaseHardware m_DeviceReleaseHardware
Definition: fxpkgpnp.hpp:4557
static WDF_DEVICE_PNP_STATE PnpEventQueryRemovePending(__inout FxPkgPnp *This)
#define TRAP_ON_EVENT
Definition: fxpkgpnp.hpp:60
VOID NotifyResourceobjectsToReleaseResources(VOID)
Definition: fxpkgpnp.cpp:5990
CfxDevice * m_Device
Definition: fxobject.hpp:329
UCHAR GetHead(VOID)
return STATUS_NOT_SUPPORTED
VOID PnpPowerPolicySurpriseRemove(VOID)
Definition: pdh_main.c:93
PCM_PARTIAL_RESOURCE_DESCRIPTOR GetResources(VOID)
static FxChildList * _FromEntry(__in FxTransactionedEntry *Entry)
static WDF_DEVICE_PNP_STATE PnpEventFailed(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpRestartHardwareAvailableOtherStates[]
Definition: fxpkgpnp.hpp:4406
_Must_inspect_result_ FxCollectionEntry * Start(VOID)
static WDF_DEVICE_PNP_STATE PnpEventInitQueryRemoveCanceled(__inout FxPkgPnp *This)
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
static const PNP_EVENT_TARGET_STATE m_PnpStartedStoppingOtherStates[]
Definition: fxpkgpnp.hpp:4397
static FxDeviceInterface * _FromEntry(__in PSINGLE_LIST_ENTRY Entry)
VOID AssignResources(__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw, __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans)
static WDF_DEVICE_PNP_STATE PnpEventRestart(__inout FxPkgPnp *This)
MdDeviceObject __inline GetDeviceObject(VOID)
Definition: fxdevice.hpp:174
VOID SetStatus(__in NTSTATUS Status)
Definition: fxirpum.cpp:457
static WDF_DEVICE_PNP_STATE PnpEventQueriedSurpriseRemove(__inout FxPkgPnp *This)
BOOLEAN SharesLock(FxInterrupt *Interrupt)
VOID PnpProcessEvent(__in FxPnpEvent Event, __in BOOLEAN ProcessEventOnDifferentThread=FALSE)
Definition: ntbasedef.h:628
static __inline VOID MxQueryTickCount(__out PLARGE_INTEGER TickCount)
Definition: mxgeneralkm.h:116
KIRQL GetSyncIrql(VOID)
VOID PnpFinishProcessingIrp(__in BOOLEAN IrpMustBePresent=TRUE)
VOID DeletePortResourceTable(VOID)
Definition: fxresource.hpp:595
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG Configuration
Definition: wdfinterrupt.h:372
#define REG_BINARY
Definition: nt_native.h:1496
static WDF_DEVICE_PNP_STATE PnpEventQueryRemoveEnsureDeviceAwake(__inout FxPkgPnp *This)
VOID NotifyDeviceSurpriseRemove(VOID)
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
WDFDEVICE __inline GetHandle(VOID)
Definition: fxdevice.hpp:237
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
WDFCASSERT(sizeof(WDF_DRIVER_CONFIG_V1_0)==sizeof(WDF_DRIVER_CONFIG_V1_1))
GLuint GLuint GLsizei count
Definition: gl.h:1545
VOID Reset(VOID)
BYTE m_SetDeviceRemoveProcessed
Definition: fxpkgpnp.hpp:4198
FxDeviceInterface * pDeviceInterface
LONG NTSTATUS
Definition: precomp.h:26
VOID PnpCheckAssumptions(VOID)
static WDF_DEVICE_PNP_STATE PnpEventInitQueryRemove(__inout FxPkgPnp *This)
FxPnpDevicePrepareHardware m_DevicePrepareHardware
Definition: fxpkgpnp.hpp:4556
#define RESTART_COUNT_NAME
_In_ ULONG _In_ ULONG State
Definition: potypes.h:516
static const PNP_EVENT_TARGET_STATE m_PnpInitOtherStates[]
Definition: fxpkgpnp.hpp:4385
Definition: fxirp.hpp:28
LIST_ENTRY m_InterruptListHead
Definition: fxpkgpnp.hpp:4310
VOID SetInternalFailure(VOID)
Definition: fxpkgpnp.cpp:4856
static WDF_DEVICE_PNP_STATE PnpEventRestarting(__inout FxPkgPnp *This)
VOID Invoke(__in WDF_DEVICE_PNP_STATE State, __in WDF_STATE_NOTIFICATION_TYPE Type, __in WDFDEVICE Device, __in PCWDF_DEVICE_PNP_NOTIFICATION_DATA NotificationData)
Definition: dhcpd.h:245
VOID PnpEnterNewState(__in WDF_DEVICE_PNP_STATE State)
uint16_t * PWCHAR
Definition: typedefs.h:56
virtual VOID PnpEventSurpriseRemovePendingOverload(VOID)
UCHAR IncrementHistoryIndex(VOID)
if(dx==0 &&dy==0)
Definition: linetemp.h:174
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
static const PNP_EVENT_TARGET_STATE m_PnpStartedRemovingOtherStates[]
Definition: fxpkgpnp.hpp:4400
UNICODE_STRING m_SymbolicLinkName
VOID WmiPkgDeregister(VOID)
Definition: fxdevicekm.cpp:497
#define TRACINGPNPPOWERSTATES
Definition: dbgtrace.h:69
PCM_RESOURCE_LIST GetParameterAllocatedResources()
Definition: fxirpum.cpp:843
static WDF_DEVICE_PNP_STATE PnpEventStartingFromStopped(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventStopped(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpStoppedWaitForStartCompletionOtherStates[]
Definition: fxpkgpnp.hpp:4396
WDFTYPE GetType(VOID)
Definition: fxobject.hpp:742
static WDF_DEVICE_PNP_STATE PnpEventFailedPowerPolicyRemoved(__inout FxPkgPnp *This)
_Must_inspect_result_ NTSTATUS PnpEnableInterfacesAndRegisterWmi(VOID)
VOID InvalidateDeviceState(__in MdDeviceObject Fdo)
VOID PnpDisableInterfaces(VOID)
PSINGLE_LIST_ENTRY ple
NTSTATUS BuildPortResourceTable(VOID)
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
VOID PnpPowerPolicyStop(VOID)
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:683
VOID UnlockFromEnum(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
VOID DeleteRegisterResourceTable(VOID)
Definition: fxresource.hpp:581
static const PNP_EVENT_TARGET_STATE m_PnpHardwareAvailableOtherStates[]
Definition: fxpkgpnp.hpp:4387
BOOLEAN EarlyDispose(VOID)
union _CM_PARTIAL_RESOURCE_DESCRIPTOR::@376 u
UCHAR KIRQL
Definition: env_spec_w32.h:591
CM_PARTIAL_RESOURCE_DESCRIPTOR m_Descriptor
Definition: fxresource.hpp:251
BOOLEAN IsFull(VOID)
static const PNP_EVENT_TARGET_STATE m_PnpFailedWaitForRemoveOtherStates[]
Definition: fxpkgpnp.hpp:4403
FxEnumerationInfo * m_EnumInfo
Definition: fxpkgpnp.hpp:4215
VOID IncrementHead(VOID)
FxWaitLockTransactionedList m_ChildListList
Definition: fxpkgpnp.hpp:485
#define RESTART_START_ACHIEVED_NAME
FORCEINLINE LONGLONG WDF_ABS_TIMEOUT_IN_SEC(_In_ ULONGLONG Time)
Definition: wdfcore.h:71
BOOLEAN IsPresentPendingPnpIrp(VOID)
Definition: fxpkgpnp.hpp:3004
VOID WmiPkgCleanup(VOID)
Definition: fxdevicekm.cpp:505
#define FALSE
Definition: types.h:117
FxCmResList * m_Resources
Definition: fxpkgpnp.hpp:4220
VOID OnPostReleaseHardware(VOID)
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
_Must_inspect_result_ NTSTATUS Invoke(__in WDFDEVICE Device, __in WDFCMRESLIST ResourcesRaw, __in WDFCMRESLIST ResourcesTranslated)
NTSTATUS WmiPkgRegister(VOID)
Definition: fxdevicekm.cpp:488
CM_PARTIAL_RESOURCE_DESCRIPTOR m_DescriptorClone
Definition: fxresource.hpp:259
_Must_inspect_result_ NTSTATUS ValidateCmResource(__inout PCM_PARTIAL_RESOURCE_DESCRIPTOR *CmResourceRaw, __inout PCM_PARTIAL_RESOURCE_DESCRIPTOR *CmResource)
#define VALIDATE_PNP_STATE(_CurrentState, _NewState)
static WDF_DEVICE_PNP_STATE PnpEventQueryRemoveAskDriver(__inout FxPkgPnp *This)
__inline VOID SetCallbackFlags(__in BYTE Flags)
Definition: fxdevice.hpp:1526
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
PCM_RESOURCE_LIST GetParameterAllocatedResourcesTranslated()
Definition: fxirpum.cpp:877
static WDF_DEVICE_PNP_STATE PnpEventSurpriseRemoved(__inout FxPkgPnp *This)
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
static const PNP_EVENT_TARGET_STATE m_PnpFailedPowerDownOtherStates[]
Definition: fxpkgpnp.hpp:4401
virtual VOID DeleteSymbolicLinkOverload(BOOLEAN GracefulRemove)=0
_In_ PVOID _In_ ULONG Event
Definition: iotypes.h:467
#define DO_EVENT_TRAP(x)
Definition: fxpkgpnp.hpp:61
static const PWCHAR m_RestartCountName
Definition: fxpkgpnp.hpp:4527
_Must_inspect_result_ NTSTATUS PnpPrepareHardwareInternal(VOID)
static WDF_DEVICE_PNP_STATE PnpEventQueryStopAskDriver(__inout FxPkgPnp *This)
unsigned char BOOLEAN
static WDF_DEVICE_PNP_STATE PnpEventStartedCancelRemove(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventFailedPowerDown(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventRemovedPdoWait(__inout FxPkgPnp *This)
_Must_inspect_result_ FxCollectionEntry * End(VOID)
#define COVERAGE_TRAP()
Definition: fxmacros.hpp:246
MdDeviceObject __inline GetAttachedDevice(VOID)
Definition: fxdevice.hpp:210
_Must_inspect_result_ NTSTATUS PnpMatchResources(VOID)
#define _In_
Definition: ms_sal.h:308
static const PNP_EVENT_TARGET_STATE m_PnpQueriedRemovingOtherStates[]
Definition: fxpkgpnp.hpp:4393
static const PNP_EVENT_TARGET_STATE m_PnpRestartingOtherStates[]
Definition: fxpkgpnp.hpp:4390
static WDF_DEVICE_PNP_STATE PnpEventFailedInit(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventQueryCanceled(__inout FxPkgPnp *This)
VOID PnpPowerPolicyStart(VOID)
void * PVOID
Definition: retypes.h:9
VOID ValidateResourceUnmap(VOID)
static WDF_DEVICE_PNP_STATE PnpEventQueryStopPending(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpStartedOtherStates[]
Definition: fxpkgpnp.hpp:4391
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
VOID LockForEnum(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
#define RESTART_START_TIME_NAME
static WDF_DEVICE_PNP_STATE PnpEventEnableInterfaces(__inout FxPkgPnp *This)
VOID SetSyncIrql(KIRQL SyncIrql)
VOID ChildRemoved(VOID)
Definition: fxpkgpnp.hpp:3415
VOID PnpCleanupForRemove(__in BOOLEAN GracefulRemove)
static const ULONG m_RestartCountMaximum
Definition: fxpkgpnp.hpp:4539
BOOLEAN IsSyncIrqlSet(VOID)
FxDisposeList * m_DisposeList
Definition: fxdevice.hpp:466
static WDF_DEVICE_PNP_STATE PnpEventSurpriseRemoveIoStarted(__inout FxPkgPnp *This)
int64_t LONGLONG
Definition: typedefs.h:68
VOID SetState(__in BOOLEAN State)
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
UCHAR InsertAtTail(VOID)
NTSTATUS BuildRegisterResourceTable(VOID)
#define ASSERT(a)
Definition: mode.c:44
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
static WDF_DEVICE_PNP_STATE PnpEventRestartHardwareAvailable(__inout FxPkgPnp *This)
FxPnpEvent m_Queue[PnpEventQueueDepth]
__inline BOOLEAN IsFilter()
Definition: fxdevice.hpp:1408
static WDF_DEVICE_PNP_STATE PnpEventRestartReleaseHardware(__inout FxPkgPnp *This)
VOID PnpEventRemovedCommonCode(VOID)
UCHAR InsertAtHead(VOID)
#define DECLARE_CONST_UNICODE_STRING(_variablename, _string)
Definition: wdfcore.h:161
static WDF_DEVICE_PNP_STATE PnpEventStartedCancelStop(__inout FxPkgPnp *This)
FxObject * m_Object
#define IRP_MN_START_DEVICE
static WDF_DEVICE_PNP_STATE PnpEventFailedStarted(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventStartedRemoving(__inout FxPkgPnp *This)
unsigned long DWORD
Definition: ntddk_ex.h:95
static __inline VOID MxReleaseRemoveLockAndWait(__in MdRemoveLock RemoveLock, __in PVOID Tag)
Definition: mxgeneralkm.h:288
FxWaitLockInternal m_DeviceInterfaceLock
Definition: fxpkgpnp.hpp:4124
_Must_inspect_result_ FxTransactionedEntry * GetNextEntry(__in_opt FxTransactionedEntry *Entry)
VOID PowerPolicyProcessEvent(__in FxPowerPolicyEvent Event, __in BOOLEAN ProcessEventOnDifferentThread=FALSE)
_Must_inspect_result_ NTSTATUS BuildFromWdmList(__in PCM_RESOURCE_LIST ResourceList, __in UCHAR AccessFlags)
_Must_inspect_result_ NTSTATUS ValidateInterruptResourceCm(__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResourceRaw, __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResource, __in PWDF_INTERRUPT_CONFIG Configuration)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
static WDF_DEVICE_PNP_STATE PnpEventPdoInitFailed(__inout FxPkgPnp *This)
BOOLEAN ShouldProcessPnpEventOnDifferentThread(__in KIRQL CurrentIrql, __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread)
struct _test_info info[]
Definition: SetCursorPos.c:19
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
static const PNP_EVENT_TARGET_STATE m_PnpQueryStopPendingOtherStates[]
Definition: fxpkgpnp.hpp:4388
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:629
char * PBOOLEAN
Definition: retypes.h:11
__inline WDF_DEVICE_PNP_STATE GetDevicePnpState()
Definition: fxdevice.hpp:1149
#define InterlockedDecrement
Definition: armddk.h:52
MdIrp GetPendingPnpIrp(VOID)
Definition: fxpkgpnp.hpp:3042
SINGLE_LIST_ENTRY m_DeviceInterfaceHead
Definition: fxpkgpnp.hpp:4126
static WDF_DEVICE_PNP_STATE PnpEventFailedSurpriseRemoved(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventFdoRemoved(__inout FxPkgPnp *This)
FxPkgIo * m_PkgIo
Definition: fxdevice.hpp:669
BOOLEAN PowerIndicateWaitWakeStatus(__in NTSTATUS WaitWakeStatus)
static int state
Definition: maze.c:121
uint32_t entry
Definition: isohybrid.c:63
#define DEBUGGED_EVENT
Definition: fxpkgpnp.hpp:59
static WDF_DEVICE_PNP_STATE PnpEventFinal(__inout FxPkgPnp *This)
static const ULONG m_RestartTimePeriodMaximum
Definition: fxpkgpnp.hpp:4533
#define __inout
Definition: dbghelp.h:50
GLsizei const GLfloat * value
Definition: glext.h:6069
__inline BOOLEAN IsWakeCapable(VOID)
Definition: typedefs.h:119
struct _cl_event * event
Definition: glext.h:7739
MdIrp ClearPendingPnpIrp(VOID)
Definition: fxpkgpnp.hpp:3029
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
static const PWCHAR m_RestartStartTimeName
Definition: fxpkgpnp.hpp:4526
#define _Must_inspect_result_
Definition: ms_sal.h:558
BOOLEAN IsClosedLocked(VOID)
FxCollectionEntry * cur
VOID __inline DestroyChildren(VOID)
Definition: fxobject.hpp:464
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
VOID GetFinishedState(__inout FxPostProcessInfo *Info)
FxPnpStateAndCaps m_PnpStateAndCaps
Definition: fxpkgpnp.hpp:4088
static WDF_DEVICE_PNP_STATE PnpEventQueryStopStaticCheck(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpEjectFailedOtherStates[]
Definition: fxpkgpnp.hpp:4399
static const PNP_EVENT_TARGET_STATE m_PnpInitStartingOtherStates[]
Definition: fxpkgpnp.hpp:4386
#define TRACINGPNP
Definition: dbgtrace.h:67
static WDF_DEVICE_PNP_STATE PnpEventFailedOwnHardware(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventQueryStopEnsureDeviceAwake(__inout FxPkgPnp *This)
USHORT History[PnpEventQueueDepth]
__inline BOOLEAN IsPassiveHandling(VOID)
BOOLEAN PnpIncrementRestartCountLogic(_In_ HANDLE RestartKey, _In_ BOOLEAN CreatedNewKey)
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
_Must_inspect_result_ NTSTATUS CheckForConnectionResources(VOID)
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
BOOLEAN IsEmpty(VOID)
unsigned short USHORT
Definition: pedump.c:61
PFX_DRIVER_GLOBALS fxDriverGlobals
static const PNP_EVENT_TARGET_STATE m_PnpStartedStoppingFailedOtherStates[]
Definition: fxpkgpnp.hpp:4398
WDFCMRESLIST GetHandle(VOID)
Definition: fxresource.hpp:449
VOID WaitForEmpty(VOID)
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
__inline VOID ClearCallbackFlags(__in BYTE Flags)
Definition: fxdevice.hpp:1548
static WDF_DEVICE_PNP_STATE PnpEventInitSurpriseRemoved(__inout FxPkgPnp *This)
#define NULL
Definition: types.h:112
KIRQL GetResourceIrql(VOID)
BOOLEAN m_AchievedStart
Definition: fxpkgpnp.hpp:4344
#define CmResourceTypeInterrupt
Definition: hwresource.cpp:124
static WDF_DEVICE_PNP_STATE PnpEventHardwareAvailablePowerPolicyFailed(__inout FxPkgPnp *This)
WDFINTERRUPT GetHandle(VOID)
VOID PnpPowerPolicyRemove(VOID)
static const PNP_EVENT_TARGET_STATE m_PnpStoppedOtherStates[]
Definition: fxpkgpnp.hpp:4395
static const PWCHAR m_RestartStartAchievedName
Definition: fxpkgpnp.hpp:4525
static WDF_DEVICE_PNP_STATE PnpEventQueryRemoveStaticCheck(__inout FxPkgPnp *This)
static const PNP_STATE_TABLE m_WdfPnpStates[]
Definition: fxpkgpnp.hpp:4380
static WDF_DEVICE_PNP_STATE PnpEventStoppedWaitForStartCompletion(__inout FxPkgPnp *This)
FxPnpStateCallback * m_PnpStateCallbacks
Definition: fxpkgpnp.hpp:4374
SharedPowerData m_SharedPower
Definition: fxpkgpnp.hpp:4161
static WDF_DEVICE_PNP_STATE PnpEventHardwareAvailable(__inout FxPkgPnp *This)
VOID SetPendingPnpIrpStatus(__in NTSTATUS Status)
Definition: fxpkgpnp.hpp:3018
static const PNP_EVENT_TARGET_STATE m_PnpRemovedPdoWaitOtherStates[]
Definition: fxpkgpnp.hpp:4389
GLuint res
Definition: glext.h:9613
UCHAR GetMinorFunction(VOID)
Definition: fxirpum.cpp:297
__inline VOID SetDevicePnpState(__in WDF_DEVICE_PNP_STATE DeviceState)
Definition: fxdevice.hpp:1173
unsigned int ULONG
Definition: retypes.h:1
FxCmResList * m_ResourcesRaw
Definition: fxpkgpnp.hpp:4225
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
static WDF_DEVICE_PNP_STATE PnpEventRemoved(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventRemovedChildrenRemoved(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpFailedIoStartingOtherStates[]
Definition: fxpkgpnp.hpp:4402
MdIrp m_PendingPnPIrp
Definition: fxpkgpnp.hpp:4360
BOOLEAN m_DeviceInterfacesCanBeEnabled
Definition: fxpkgpnp.hpp:4128
static WDF_DEVICE_PNP_STATE PnpEventFailedIoStarting(__inout FxPkgPnp *This)
static VOID _PnpProcessEventInner(__inout FxPkgPnp *This, __inout FxPostProcessInfo *Info, __in PVOID WorkerContext)
static WDF_DEVICE_PNP_STATE PnpEventInitStarting(__inout FxPkgPnp *This)
__drv_when(!NT_SUCCESS(return), __drv_arg(ResourcesMatched, _Must_inspect_result_)) NTSTATUS FxPkgPnp
#define STATUS_SUCCESS
Definition: shellext.h:65
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define STATUS_DEVICE_POWER_FAILURE
Definition: ntstatus.h:394
static __inline ULONG MxQueryTimeIncrement()
Definition: mxgeneralkm.h:125
void exit(int exitcode)
Definition: _exit.c:33
static WDF_DEVICE_PNP_STATE PnpEventStartedStopping(__inout FxPkgPnp *This)
_Must_inspect_result_ NTSTATUS PnpReleaseHardware(VOID)
VOID PnpProcessEventInner(__inout FxPostProcessInfo *Info)
MdIrp SetIrp(MdIrp irp)
Definition: fxirpkm.hpp:71
FxSelfManagedIoMachine * m_SelfManagedIoMachine
Definition: fxpkgpnp.hpp:4155
static WDF_DEVICE_PNP_STATE PnpEventRemovingDisableInterfaces(__inout FxPkgPnp *This)
static CPPNP_STATE_TABLE GetPnpTableEntry(__in WDF_DEVICE_PNP_STATE State)
Definition: fxpkgpnp.hpp:2853
#define __in
Definition: dbghelp.h:35
static BOOLEAN _IsMessageInterrupt(__in USHORT ResourceFlags)
#define REG_DWORD
Definition: sdbapi.c:596
static SERVICE_STATUS status
Definition: service.c:31
FxCollectionEntry * Next(VOID)
static WDF_DEVICE_PNP_STATE PnpEventCheckForDevicePresence(__inout FxPkgPnp *This)
_Must_inspect_result_ NTSTATUS Invoke(__in WDFDEVICE Device, __in WDFCMRESLIST ResourcesTranslated)
static WDF_DEVICE_PNP_STATE PnpEventPdoRestart(__inout FxPkgPnp *This)
FxIrp * irp
static const PNP_EVENT_TARGET_STATE m_PnpInitQueryRemoveOtherStates[]
Definition: fxpkgpnp.hpp:4394
_Must_inspect_result_ NTSTATUS StopProcessingForPower(__in FxIoStopProcessingForPowerAction Action)
Definition: fxpkgio.cpp:1143
FxWaitLockInternal m_StateMachineLock
static const PNP_EVENT_TARGET_STATE m_PnpRestartOtherStates[]
Definition: fxpkgpnp.hpp:4404
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
FxVerifierDbgBreakPoint(pFxDriverGlobals)
VOID SetFilterIoType(VOID)
Definition: fxdevice.cpp:1873
static const PNP_EVENT_TARGET_STATE m_PnpQueryRemovePendingOtherStates[]
Definition: fxpkgpnp.hpp:4392
LONGLONG QuadPart
Definition: typedefs.h:114
#define __drv_arg(expr, annotes)
Definition: driverspecs.h:257
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@376::@380 MessageInterrupt
VOID PnpAssignInterruptsSyncIrql(VOID)
static const PNP_EVENT_TARGET_STATE m_PnpRestartReleaseHardware[]
Definition: fxpkgpnp.hpp:4405
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:70
NTSTATUS CompletePnpRequest(__inout FxIrp *Irp, __in NTSTATUS Status)
Definition: fxpkgpnp.cpp:5752
static WDF_DEVICE_PNP_STATE PnpEventPdoRemoved(__inout FxPkgPnp *This)
FxPnpMachine m_PnpMachine
Definition: fxpkgpnp.hpp:4151
#define DO_NOTHING()
Definition: mxgeneral.h:32
NTSTATUS GetStatus()
Definition: fxirpum.cpp:466
static WDF_DEVICE_PNP_STATE PnpEventRemovedPdoSurpriseRemoved(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventStarted(__inout FxPkgPnp *This)
BOOLEAN m_WaitWakeOwner
Definition: fxpkgpnp.hpp:186