ReactOS 0.4.16-dev-297-gc569aee
pnpstatemachine.cpp
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft. All rights reserved.
4
5Module Name:
6
7 PnpStateMachine.cpp
8
9Abstract:
10
11 This module implements the PnP state machine for the driver framework.
12 This code was split out from FxPkgPnp.cpp.
13
14Author:
15
16
17
18
19Environment:
20
21 Both kernel and user mode
22
23Revision History:
24
25
26
27--*/
28
29#include "pnppriv.hpp"
30#include <wdmguid.h>
31
32#include<ntstrsafe.h>
33
34extern "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
751VOID
753 VOID
754 )
755/*++
756
757Routine 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
764Arguments:
765 None
766
767Return 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
780 ==
782 sizeof(m_PnpMachine.m_States.History[0])));
783}
784
785/*++
786
787The locking model for the PnP state machine requires that events be enqueued
788possibly at DISPATCH_LEVEL. It also requires that the PnP state machine be
789runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL
790lock that guards the event queue and one PASSIVE_LEVEL lock that guards the
791state machine itself.
792
793Algorithm:
794
7951) Acquire the PnP queue lock.
7962) 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.
7993) Drop the PnP queue lock.
8004) If the thread is running at PASSIVE_LEVEL, skip to step 6.
8015) Queue a work item onto any work queue.
8026) Attempt to acquire the state machine lock, with a near-zero-length timeout.
8037) If successful, skip to step 10.
8048) Queue a work item onto any work queue.
8059) Acquire the state machine lock.
80610) Acquire the PnP queue lock.
80711) Attempt to dequeue an event.
80812) Drop the PnP queue lock.
80913) If there was no event to dequeue, drop the state machine lock and exit.
81014) Execute the state handler. This may involve taking one of the other state
811 machine queue locks, briefly, to deliver an event.
81215) Go to Step 10.
813
814Implementing this algorithm requires three functions.
815
816PnpProcessEvent -- Implements steps 1-8.
817_PnpProcessEventInner -- Implements step 9.
818PnpProcessEventInner -- Implements steps 10-15.
819
820--*/
821
822VOID
825 __in BOOLEAN ProcessOnDifferentThread
826 )
827/*++
828
829Routine Description:
830 This function implements steps 1-8 of the algorithm described above.
831
832Arguments:
833 Event - Current PnP event
834
835Return 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",
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",
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
951VOID
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
986VOID
989 )
990/*++
991
992Routine 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;
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 //
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!",
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!",
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
1155VOID
1158 )
1159/*++
1160
1161Routine Description:
1162 This function looks up the handler for a state and
1163 then calls it.
1164
1165Arguments:
1166 Event - Current PnP event
1167
1168Return 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!",
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,
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,
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,
1257 &data);
1258 }
1259 }
1260}
1261
1265 )
1266/*++
1267
1268Routine 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
1274Arguments:
1275 none
1276
1277Return Value:
1278
1279 VOID
1280
1281--*/
1282{
1283 return This->PnpEventCheckForDevicePresenceOverload();
1284}
1285
1289 )
1290/*++
1291
1292Routine 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
1298Arguments:
1299 none
1300
1301Return Value:
1302
1303 VOID
1304
1305--*/
1306{
1307 return This->PnpEventEjectHardwareOverload();
1308}
1309
1313 )
1314/*++
1315
1316Routine Description:
1317 The device is recieving a start for the first time. The start is on the way
1318 down the stack.
1319
1320Arguments:
1321 This - instance of the state machine
1322
1323Return 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
1345Routine 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
1351Arguments:
1352 This - instance of the state machine
1353
1354Return Value:
1355 WdfDevStatePnpInit
1356
1357 --*/
1358{
1359 This->PnpFinishProcessingIrp(TRUE);
1360
1361 return WdfDevStatePnpInit;
1362}
1363
1367 )
1368/*++
1369
1370Routine Description:
1371 This function implements the Hardware Available state.
1372
1373Arguments:
1374 none
1375
1376Return Value:
1377
1378 VOID
1379
1380--*/
1381{
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 //
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
1463Routine 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
1471Arguments:
1472 This - instance of the state machine
1473
1474Return Value:
1475 new state
1476
1477 --*/
1478{
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
1503Routine 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
1509Arguments:
1510 This - instance of the state machien
1511
1512Return Value:
1513 WdfDevStatePnpFailedOwnHardware
1514
1515 --*/
1516{
1517 This->SetPendingPnpIrpStatus(STATUS_DEVICE_POWER_FAILURE);
1518
1520}
1521
1525 )
1526/*++
1527
1528Routine 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
1533Arguments:
1534 This - instance of the state machine
1535
1536Return Value:
1537 new state
1538
1539--*/
1540{
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
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/*++
1590Routine 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
1594Arguments:
1595 This - instance of the state machine
1596
1597Return Value:
1598 new state
1599--*/
1600{
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
1648Routine Description:
1649 The device has fully stopped. Let go of the query remove irp.
1650
1651Arguments:
1652 This - instance of the state machine for this device
1653
1654Return 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
1673Routine 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
1680Arguments:
1681 none
1682
1683Return Value:
1684
1685 VOID
1686
1687--*/
1688{
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
1748Routine Description:
1749 The device was query removed and is now in the removed state.
1750
1751Arguments:
1752 This - instance of the state machine
1753
1754Return 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
1779Routine 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
1784Arguments:
1785 This - instance of the state machine
1786
1787Return Value:
1788 new state
1789
1790--*/
1791{
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
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/*++
1839Routine 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
1843Arguments:
1844 This - instance of the state machine
1845
1846Return Value:
1847 new state
1848--*/
1849{
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
1896Routine Description:
1897 Everything in the device has stopped due to the stop device irp. Complete
1898 it now
1899
1900Arguments:
1901 This - instance of the state machine
1902
1903Return 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
1922Routine 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
1929Arguments:
1930 This - instance of the state machine
1931
1932Return Value:
1933 new machine state
1934
1935--*/
1936{
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
1988VOID
1990 VOID
1991 )
1992/*++
1993
1994Routine Description:
1995 This function implements the Removed state.
1996
1997Arguments:
1998 none
1999
2000Return Value:
2001
2002 VOID
2003
2004--*/
2005{
2006 //
2007 // Purge non power managed queues now
2008 //
2011 );
2012
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 //
2029 m_PnpStateAndCaps.Value &= ~FxPnpStateRemovedMask;
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
2065Routine 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
2069Arguments:
2070 This - instance of the state machine
2071
2072Return Value:
2073 WdfDevStatePnpStarted
2074
2075 --*/
2076{
2077 This->PnpPowerDereferenceSelf();
2078
2079 return WdfDevStatePnpStarted;
2080}
2081
2085 )
2086/*++
2087
2088Routine 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
2092Arguments:
2093 This - instance of the state machine
2094
2095Return 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
2132Routine 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
2136Arguments:
2137 none
2138
2139Return Value:
2140 new state
2141
2142--*/
2143{
2144 return This->PnpEventPdoRemovedOverload();
2145}
2146
2150 )
2151/*++
2152
2153Routine 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
2157Arguments:
2158 This - Instance of the state machine
2159
2160Return 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
2178Routine Description:
2179 PDO has been removed (could have been disabled in user mode) and is now
2180 surprise removed by the underlying bus.
2181
2182Arguments:
2183 This - instance of the state machine
2184
2185Return 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
2209VOID
2211 __in BOOLEAN GracefulRemove
2212 )
2213/*++
2214
2215Routine 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
2220Arguments:
2221 GracefulRemove - if TRUE, we are in the graceful remove path, otherwise we
2222 are in the surprise remove path.
2223
2224Return 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 //
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 //
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
2295Routine 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
2300Arguments:
2301 none
2302
2303Return Value:
2304
2305 WdfDevStatePnpNull
2306
2307--*/
2308{
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
2347Routine Description:
2348 Completes the pending request or sends it on its way.
2349
2350Arguments:
2351 This - instance of the state machine for the device
2352
2353Return 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
2379Routine Description:
2380 Cancel stop received from the started state. Just return to the started
2381 state where we will handle the pended irp.
2382
2383Arguments:
2384 This - Instance of the state machine
2385
2386Return Value:
2387 WdfDevStatePnpStarted
2388
2389 --*/
2390{
2392 return WdfDevStatePnpStarted;
2393}
2394
2398 )
2399/*++
2400
2401Routine Description:
2402 Cancel remove received from the started state. Just return to the started
2403 state where we will handle the pended irp.
2404
2405Arguments:
2406 This - Instance of the state machine
2407
2408Return Value:
2409 WdfDevStatePnpStarted
2410
2411 --*/
2412{
2414
2415 return WdfDevStatePnpStarted;
2416}
2417
2421 )
2422/*++
2423
2424Routine Description:
2425 Remove directly from started. Power down the other state machines.
2426
2427Arguments:
2428 This - instance of the state machine
2429
2430Return Value:
2431 WdfDevStatePnpNull
2432
2433 --*/
2434{
2435 This->PnpPowerPolicyStop();
2436
2437 return WdfDevStatePnpNull;
2438}
2439
2443 )
2444/*++
2445
2446Routine Description:
2447 This function implements the Cancelling Stop state.
2448
2449Arguments:
2450 none
2451
2452Return 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
2473Routine 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
2477Arguments:
2478 none
2479
2480Return Value:
2481
2482 VOID
2483
2484--*/
2485{
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
2513}
2514
2518 )
2519/*++
2520
2521Routine Description:
2522 This function implements the Stopped state. It's job is to invoke
2523 EvtDeviceReleaseHardware.
2524
2525Arguments:
2526 none
2527
2528Return Value:
2529
2530 VOID
2531
2532--*/
2533{
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 {
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
2571Routine 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
2575Arguments:
2576 This - instance of the state machine
2577
2578Return 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
2600Routine Description:
2601 Received a stop irp. Stop the power policy machine and then wait for it to
2602 complete.
2603
2604Arguments:
2605 This - instance of the state machine
2606
2607Return 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
2632Routine 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
2637Arguments:
2638 This - instance of the state machine
2639
2640Return 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
2664Routine Description:
2665 Query remove from the init state. Complete the pended request.
2666
2667Arguments:
2668 This - instance of th state machine.
2669
2670Return 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
2689Routine Description:
2690 Handle a query remove canceled from the init state. Complete the pended
2691 request.
2692
2693Arguments:
2694 This - instance of the state machine
2695
2696Return 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
2714Routine Description:
2715 FDO is being removed, hand off to the derived pnp package
2716
2717Arguments:
2718 This - instance of the state machine
2719
2720Return Value:
2721 new device pnp state
2722
2723 --*/
2724{
2725 return This->PnpEventFdoRemovedOverload();
2726}
2727
2731 )
2732/*++
2733
2734Routine Description:
2735 The device was in a queried (either stop or cancel) state and was surprise
2736 removed from it.
2737
2738Arguments:
2739 This - instance of the state machine
2740
2741Return Value:
2742 new state, WdfDevStatePnpSurpriseRemoveIoStarted
2743
2744 --*/
2745{
2746 COVERAGE_TRAP();
2747
2748 This->PnpPowerDereferenceSelf();
2749
2751}
2752
2756 )
2757/*++
2758
2759Routine 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
2765Arguments:
2766 This - instance of the state machine
2767
2768Return 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
2793Routine 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
2805Arguments:
2806 This - instance of the state machine
2807
2808Return 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
2829Routine 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
2834Arguments: j
2835 This - instance of the state machine
2836
2837Return Value:
2838 new device pnp state
2839
2840 --*/
2841{
2842 This->PnpPowerPolicySurpriseRemove();
2843
2844 return WdfDevStatePnpNull;
2845}
2846
2850 )
2851/*++
2852
2853Routine 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
2858Arguments:
2859 This - instance of the state machine
2860
2861Return 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
2880Routine 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
2885Arguments:
2886 This - instance of the state machine
2887
2888Return 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
2909Routine 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
2913Arguments:
2914 This - instance of the state machine
2915
2916Return 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
2972Routine 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
2981Arguments:
2982 This - instance of the state machine
2983
2984Return 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
3019Routine 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
3024Arguments:
3025 This - instance of the state machine
3026
3027Return 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
3047Routine Description:
3048 Processing of the start irp's resources failed. Complete the start irp.
3049
3050Arguments:
3051 This - instance of the state machine
3052
3053Return 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
3080Routine Description:
3081 The driver failed EvtDeviceSoftwareInit. Run cleanup and die.
3082
3083Arguments:
3084 This - instance of the state machine
3085
3086Return 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
3112Routine Description:
3113 A start to start transition has occurred. Go through the normal stop path
3114 first and then restart things.
3115
3116Arguments:
3117 This - instance of the state machine
3118
3119Return 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
3138Routine Description:
3139 Release the hardware resources and send the start irp down the stack
3140
3141Arguments:
3142 This - instance of the state machine
3143
3144Return Value:
3145 new machine state
3146
3147 --*/
3148{
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
3185Routine 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
3190Arguments:
3191 This - instance of the state machine
3192
3193Return Value:
3194 new machine state
3195
3196 --*/
3197{
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
3232Routine 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
3236Arguments:
3237 This - instance of the state machine
3238
3239Return 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
3309Routine 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
3313Arguments:
3314 This - instance of the state machine
3315
3316Return Value:
3317 new state
3318
3319 --*/
3320{
3321 return This->PnpGetPostRemoveState();
3322}
3323
3327 )
3328/*++
3329
3330Routine 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
3334Arguments:
3335 This - This instance of the state machine
3336
3337Return Value:
3338 WdfDevStatePnpNull
3339
3340 --*/
3341{
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
3413 VOID
3414 )
3415/*++
3416
3417Routine Description:
3418 Enables all of the device interfaces and then registers wmi.
3419
3420Arguments:
3421 None
3422
3423Return Value:
3424 NT_SUCCESS if all goes well, !NT_SUCCESS otherwise
3425
3426 --*/
3427{
3430
3432
3433 //
3434 // Enable any device interfaces.
3435 //
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
3463
3464 if (NT_SUCCESS(status)) {
3466 }
3467
3468 if (!NT_SUCCESS(status)) {
3471 }
3472
3473 return status;
3474}
3475
3478FxPkgPnp::PnpPrepareHardware(
3479 __inout PBOOLEAN ResourcesMatched
3480 )
3481/*++
3482
3483Routine Description:
3484 Matches the PNP resources with the WDFINTERRUPT objects registered and then
3485 calls EvtDevicePrepareHardware. All start paths call this function
3486
3487Arguments:
3488 ResourcesMatched - indicates to the caller what stage failed if !NT_SUCCESS
3489 is returned
3490
3491Return Value:
3492 NT_SUCCESS if all goes well, !NT_SUCCESS if failure occurrs
3493
3494 --*/
3495{
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
3572
3575 );
3576
3577 if (!NT_SUCCESS(status)) {
3579 "EvtDevicePrepareHardware failed %!STATUS!", status);
3580
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
3615exit:
3616 return status;
3617}
3618
3622 VOID
3623 )
3624/*++
3625
3626Routine Description:
3627 Invokes the driver's release hardware callback if present.
3628 Releases any interrupt resources allocated during the prepare hardware callback.
3629
3630Arguments:
3631 None
3632
3633Return Value:
3634 Driver's release hardware callback return status or
3635 STATUS_SUCCESS if callback is not present.
3636
3637 --*/
3638{
3640 FxInterrupt* interrupt;
3641 PLIST_ENTRY le;
3642
3643 //
3644 // Invoke the device's release hardware callback.
3645 //
3649
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
3697VOID
3699 VOID
3700 )
3701/*++
3702
3703Routine Description:
3704 Informs the power policy state machine that it should start.
3705
3706Arguments:
3707 None
3708
3709Return Value:
3710 None
3711
3712 --*/
3713{
3715}
3716
3717VOID
3719 VOID
3720 )
3721/*++
3722
3723Routine Description:
3724 Informs the power and power policy state machines that they should stop.
3725
3726Arguments:
3727 None
3728
3729Return Value:
3730 None
3731
3732 --*/
3733{
3735}
3736
3737VOID
3739 VOID
3740 )
3741/*++
3742
3743Routine Description:
3744 Informs the policy state machines that it should stop due to the hardware
3745 being surprise removed.
3746
3747Arguments:
3748 None
3749
3750Return Value:
3751 None
3752
3753 --*/
3754{
3756}
3757
3758VOID
3760 VOID
3761 )
3762/*++
3763
3764Routine Description:
3765 Informs the policy state machine that it should prepare for device removal.
3766
3767Arguments:
3768 None
3769
3770Return Value:
3771 None
3772
3773 --*/
3774{
3776}
3777
3778VOID
3780 __in BOOLEAN IrpMustBePresent
3781 )
3782/*++
3783
3784Routine Description:
3785 Finishes handling a pended pnp irp
3786
3787Arguments:
3788 None
3789
3790Return 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
3821VOID
3823 VOID
3824 )
3825/*++
3826
3827Routine Description:
3828 Disables all of the registerd interfaces on the device.
3829
3830Arguments:
3831 None
3832
3833Return Value:
3834 None
3835
3836 --*/
3837{
3839
3841
3843
3844 for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
3845
3849 }
3850
3852}
3853
3854VOID
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;
3874 }
3875
3877 }
3878}
3879
3883 VOID
3884 )
3885/*++
3886
3887Routine 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
3896Arguemnts:
3897
3898 Irp - a pointer to the FxIrp
3899
3900Returns:
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;
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!",
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!",
3950 goto Done;
3951 }
3952
3953 //
3954 // reset the stored information in all interrupts in the rebalance case
3955 //
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);
3978
3979 resCmRaw = (FxResourceCm*) curRaw->m_Object;
3980
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
4089Done:
4091 "Exiting PnpMatchResources %!STATUS!", status);
4092
4093 return status;
4094}
4095
4096VOID
4098 VOID
4099 )
4100/*++
4101
4102Routine 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
4111Arguments:
4112 None
4113
4114Return Value:
4115 None
4116
4117 --*/
4118{
4120 FxInterrupt* pInterrupt;
4121
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
4226 )
4227/*++
4228
4229Routine Description:
4230 Makes sure the specified resource is valid.
4231
4232Arguments:
4233 CmResourceRaw - the raw resource to validate.
4234 CmResource - the translated resources to validate.
4235
4236Return Value:
4237 STATUS_SUCCESS if resource is valid or
4238 NTSTATUS error.
4239
4240 --*/
4241{
4244 FxCollectionEntry* curRaw;
4246 FxResourceCm* resRaw;
4248
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
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
4342Done:
4343 return status;
4344}
4345
4349 __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResourceRaw,
4352 )
4353/*++
4354
4355Routine Description:
4356 Makes sure the specified resource is valid for an interrupt resource.
4357
4358Arguments:
4359 CmIntResourceRaw - the raw interrupt resource to validate.
4360 CmIntResource - the translated interrupt resource to validate.
4361
4362Return Value:
4363 STATUS_SUCCESS if resource is valid or
4364 NTSTATUS error.
4365
4366 --*/
4367{
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!",
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
4511Done:
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
4526BOOLEAN
4528 _In_ HANDLE RestartKey,
4529 _In_ BOOLEAN CreatedNewKey
4530 )
4531/*++
4532
4533Routine 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
4567Considerations:
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
4578Arguments:
4579 RestartKey - opened handle to the Restart registry key
4580 CreatedNewKey - TRUE if the Restart key was created just now
4581
4582Return 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 //
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) {
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
#define SaveState(State)
unsigned char BOOLEAN
static int state
Definition: maze.c:121
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
static FxChildList * _FromEntry(__in FxTransactionedEntry *Entry)
VOID NotifyDeviceSurpriseRemove(VOID)
VOID DeletePortResourceTable(VOID)
Definition: fxresource.hpp:595
VOID ValidateResourceUnmap(VOID)
NTSTATUS BuildPortResourceTable(VOID)
VOID DeleteRegisterResourceTable(VOID)
Definition: fxresource.hpp:581
WDFCMRESLIST GetHandle(VOID)
Definition: fxresource.hpp:449
_Must_inspect_result_ NTSTATUS CheckForConnectionResources(VOID)
NTSTATUS BuildRegisterResourceTable(VOID)
_Must_inspect_result_ NTSTATUS BuildFromWdmList(__in PCM_RESOURCE_LIST ResourceList, __in UCHAR AccessFlags)
FxObject * m_Object
FxCollectionEntry * Next(VOID)
WDFDEVICE __inline GetHandle(VOID)
Definition: fxdevice.hpp:237
MdDeviceObject __inline GetAttachedDevice(VOID)
Definition: fxdevice.hpp:210
FxDisposeList * m_DisposeList
Definition: fxdevice.hpp:466
MdDeviceObject __inline GetDeviceObject(VOID)
Definition: fxdevice.hpp:174
VOID SetState(__in BOOLEAN State)
UNICODE_STRING m_SymbolicLinkName
static FxDeviceInterface * _FromEntry(__in PSINGLE_LIST_ENTRY Entry)
__inline VOID SetCallbackFlags(__in BYTE Flags)
Definition: fxdevice.hpp:1526
VOID WmiPkgCleanup(VOID)
Definition: fxdevicekm.cpp:505
__inline VOID SetDevicePnpState(__in WDF_DEVICE_PNP_STATE DeviceState)
Definition: fxdevice.hpp:1173
VOID WmiPkgDeregister(VOID)
Definition: fxdevicekm.cpp:497
VOID SetFilterIoType(VOID)
Definition: fxdevice.cpp:1873
FxPkgIo * m_PkgIo
Definition: fxdevice.hpp:669
__inline BOOLEAN IsFilter()
Definition: fxdevice.hpp:1408
NTSTATUS WmiPkgRegister(VOID)
Definition: fxdevicekm.cpp:488
__inline VOID ClearCallbackFlags(__in BYTE Flags)
Definition: fxdevice.hpp:1548
__inline WDF_DEVICE_PNP_STATE GetDevicePnpState()
Definition: fxdevice.hpp:1149
VOID WaitForEmpty(VOID)
BOOLEAN IsSyncIrqlSet(VOID)
VOID Reset(VOID)
__inline BOOLEAN IsPassiveHandling(VOID)
VOID AssignResources(__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw, __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans)
VOID SetSyncIrql(KIRQL SyncIrql)
__inline BOOLEAN IsWakeCapable(VOID)
VOID OnPostReleaseHardware(VOID)
PCM_PARTIAL_RESOURCE_DESCRIPTOR GetResources(VOID)
BOOLEAN IsSharedSpinLock(VOID)
static BOOLEAN _IsMessageInterrupt(__in USHORT ResourceFlags)
BOOLEAN SharesLock(FxInterrupt *Interrupt)
KIRQL GetSyncIrql(VOID)
WDFINTERRUPT GetHandle(VOID)
KIRQL GetResourceIrql(VOID)
Definition: fxirp.hpp:28
PCM_RESOURCE_LIST GetParameterAllocatedResources()
Definition: fxirpum.cpp:843
PCM_RESOURCE_LIST GetParameterAllocatedResourcesTranslated()
Definition: fxirpum.cpp:877
VOID SetStatus(__in NTSTATUS Status)
Definition: fxirpum.cpp:457
NTSTATUS GetStatus()
Definition: fxirpum.cpp:466
MdIrp SetIrp(MdIrp irp)
Definition: fxirpkm.hpp:71
UCHAR GetMinorFunction(VOID)
Definition: fxirpum.cpp:297
WDFTYPE GetType(VOID)
Definition: fxobject.hpp:742
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
VOID __inline DestroyChildren(VOID)
Definition: fxobject.hpp:464
CfxDevice * m_Device
Definition: fxobject.hpp:329
BOOLEAN EarlyDispose(VOID)
_Must_inspect_result_ NTSTATUS StopProcessingForPower(__in FxIoStopProcessingForPowerAction Action)
Definition: fxpkgio.cpp:1143
static const PNP_EVENT_TARGET_STATE m_PnpInitOtherStates[]
Definition: fxpkgpnp.hpp:4385
MdIrp m_PendingPnPIrp
Definition: fxpkgpnp.hpp:4360
VOID SetInternalFailure(VOID)
Definition: fxpkgpnp.cpp:4856
static WDF_DEVICE_PNP_STATE PnpEventRestartReleaseHardware(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpQueriedRemovingOtherStates[]
Definition: fxpkgpnp.hpp:4393
static WDF_DEVICE_PNP_STATE PnpEventHardwareAvailablePowerPolicyFailed(__inout FxPkgPnp *This)
FxPnpStateCallback * m_PnpStateCallbacks
Definition: fxpkgpnp.hpp:4374
VOID PnpCheckAssumptions(VOID)
BOOLEAN IsPresentPendingPnpIrp(VOID)
Definition: fxpkgpnp.hpp:3004
FxCmResList * m_Resources
Definition: fxpkgpnp.hpp:4220
static WDF_DEVICE_PNP_STATE PnpEventInitSurpriseRemoved(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventRemovedChildrenRemoved(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpStartedStoppingOtherStates[]
Definition: fxpkgpnp.hpp:4397
static const PNP_EVENT_TARGET_STATE m_PnpStoppedOtherStates[]
Definition: fxpkgpnp.hpp:4395
static WDF_DEVICE_PNP_STATE PnpEventQueryCanceled(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventQueryStopStaticCheck(__inout FxPkgPnp *This)
SINGLE_LIST_ENTRY m_DeviceInterfaceHead
Definition: fxpkgpnp.hpp:4126
FxSelfManagedIoMachine * m_SelfManagedIoMachine
Definition: fxpkgpnp.hpp:4155
static WDF_DEVICE_PNP_STATE PnpEventStartedCancelStop(__inout FxPkgPnp *This)
FxCmResList * m_ResourcesRaw
Definition: fxpkgpnp.hpp:4225
static const PNP_EVENT_TARGET_STATE m_PnpRemovedPdoWaitOtherStates[]
Definition: fxpkgpnp.hpp:4389
_Must_inspect_result_ NTSTATUS PnpEnableInterfacesAndRegisterWmi(VOID)
VOID PnpPowerPolicySurpriseRemove(VOID)
static const PNP_EVENT_TARGET_STATE m_PnpStartedStoppingFailedOtherStates[]
Definition: fxpkgpnp.hpp:4398
static WDF_DEVICE_PNP_STATE PnpEventQueriedRemoving(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventQueriedSurpriseRemove(__inout FxPkgPnp *This)
VOID ChildRemoved(VOID)
Definition: fxpkgpnp.hpp:3415
static WDF_DEVICE_PNP_STATE PnpEventStartedRemoving(__inout FxPkgPnp *This)
static const PWCHAR m_RestartStartAchievedName
Definition: fxpkgpnp.hpp:4525
static WDF_DEVICE_PNP_STATE PnpEventFailedSurpriseRemoved(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpRestartHardwareAvailableOtherStates[]
Definition: fxpkgpnp.hpp:4406
static WDF_DEVICE_PNP_STATE PnpEventFailedIoStarting(__inout FxPkgPnp *This)
FxWaitLockInternal m_DeviceInterfaceLock
Definition: fxpkgpnp.hpp:4124
MdIrp GetPendingPnpIrp(VOID)
Definition: fxpkgpnp.hpp:3042
static const PNP_EVENT_TARGET_STATE m_PnpHardwareAvailableOtherStates[]
Definition: fxpkgpnp.hpp:4387
static WDF_DEVICE_PNP_STATE PnpEventFailedInit(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpStartedRemovingOtherStates[]
Definition: fxpkgpnp.hpp:4400
BYTE m_SetDeviceRemoveProcessed
Definition: fxpkgpnp.hpp:4198
VOID PnpEnterNewState(__in WDF_DEVICE_PNP_STATE State)
static const PNP_EVENT_TARGET_STATE m_PnpQueryStopPendingOtherStates[]
Definition: fxpkgpnp.hpp:4388
FxEnumerationInfo * m_EnumInfo
Definition: fxpkgpnp.hpp:4215
VOID PnpPowerPolicyStart(VOID)
static WDF_DEVICE_PNP_STATE PnpEventRemoved(__inout FxPkgPnp *This)
BOOLEAN ShouldProcessPnpEventOnDifferentThread(__in KIRQL CurrentIrql, __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread)
static const PNP_EVENT_TARGET_STATE m_PnpStoppedWaitForStartCompletionOtherStates[]
Definition: fxpkgpnp.hpp:4396
VOID PnpDisableInterfaces(VOID)
static WDF_DEVICE_PNP_STATE PnpEventInitQueryRemove(__inout FxPkgPnp *This)
_Must_inspect_result_ NTSTATUS PnpMatchResources(VOID)
static WDF_DEVICE_PNP_STATE PnpEventFailed(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventQueryStopPending(__inout FxPkgPnp *This)
VOID SetPendingPnpIrpStatus(__in NTSTATUS Status)
Definition: fxpkgpnp.hpp:3018
FxPnpMachine m_PnpMachine
Definition: fxpkgpnp.hpp:4151
static WDF_DEVICE_PNP_STATE PnpEventStartedStopping(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventRestart(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpFailedIoStartingOtherStates[]
Definition: fxpkgpnp.hpp:4402
static const PWCHAR m_RestartCountName
Definition: fxpkgpnp.hpp:4527
static WDF_DEVICE_PNP_STATE PnpEventFailedStarted(__inout FxPkgPnp *This)
VOID PnpCleanupForRemove(__in BOOLEAN GracefulRemove)
static const PNP_EVENT_TARGET_STATE m_PnpRestartOtherStates[]
Definition: fxpkgpnp.hpp:4404
static WDF_DEVICE_PNP_STATE PnpEventEnableInterfaces(__inout FxPkgPnp *This)
virtual VOID DeleteSymbolicLinkOverload(BOOLEAN GracefulRemove)=0
BOOLEAN m_AchievedStart
Definition: fxpkgpnp.hpp:4344
static const PNP_EVENT_TARGET_STATE m_PnpInitQueryRemoveOtherStates[]
Definition: fxpkgpnp.hpp:4394
MdIrp ClearPendingPnpIrp(VOID)
Definition: fxpkgpnp.hpp:3029
VOID NotifyResourceobjectsToReleaseResources(VOID)
Definition: fxpkgpnp.cpp:5990
static WDF_DEVICE_PNP_STATE PnpEventFailedPowerPolicyRemoved(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventQueryRemoveStaticCheck(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventQueryRemoveEnsureDeviceAwake(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpFailedWaitForRemoveOtherStates[]
Definition: fxpkgpnp.hpp:4403
static WDF_DEVICE_PNP_STATE PnpEventFailedPowerDown(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventHardwareAvailable(__inout FxPkgPnp *This)
static const ULONG m_RestartTimePeriodMaximum
Definition: fxpkgpnp.hpp:4533
static WDF_DEVICE_PNP_STATE PnpEventInitQueryRemoveCanceled(__inout FxPkgPnp *This)
virtual VOID PnpEventSurpriseRemovePendingOverload(VOID)
static WDF_DEVICE_PNP_STATE PnpEventStartedCancelRemove(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventStopped(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventCheckForDevicePresence(__inout FxPkgPnp *This)
VOID PnpPowerPolicyRemove(VOID)
static WDF_DEVICE_PNP_STATE PnpEventQueryStopEnsureDeviceAwake(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpRestartingOtherStates[]
Definition: fxpkgpnp.hpp:4390
static WDF_DEVICE_PNP_STATE PnpEventQueryRemoveAskDriver(__inout FxPkgPnp *This)
static const PNP_STATE_TABLE m_WdfPnpStates[]
Definition: fxpkgpnp.hpp:4380
BOOLEAN PowerIndicateWaitWakeStatus(__in NTSTATUS WaitWakeStatus)
static WDF_DEVICE_PNP_STATE PnpEventSurpriseRemoved(__inout FxPkgPnp *This)
static VOID _PnpProcessEventInner(__inout FxPkgPnp *This, __inout FxPostProcessInfo *Info, __in PVOID WorkerContext)
_Must_inspect_result_ NTSTATUS ValidateInterruptResourceCm(__in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResourceRaw, __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResource, __in PWDF_INTERRUPT_CONFIG Configuration)
static const PNP_EVENT_TARGET_STATE m_PnpEjectFailedOtherStates[]
Definition: fxpkgpnp.hpp:4399
VOID PnpAssignInterruptsSyncIrql(VOID)
static WDF_DEVICE_PNP_STATE PnpEventStartingFromStopped(__inout FxPkgPnp *This)
static CPPNP_STATE_TABLE GetPnpTableEntry(__in WDF_DEVICE_PNP_STATE State)
Definition: fxpkgpnp.hpp:2853
FxPnpDeviceReleaseHardware m_DeviceReleaseHardware
Definition: fxpkgpnp.hpp:4557
SharedPowerData m_SharedPower
Definition: fxpkgpnp.hpp:4161
static WDF_DEVICE_PNP_STATE PnpEventRemovedPdoSurpriseRemoved(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpQueryRemovePendingOtherStates[]
Definition: fxpkgpnp.hpp:4392
FxPnpDevicePrepareHardware m_DevicePrepareHardware
Definition: fxpkgpnp.hpp:4556
VOID PnpEventRemovedCommonCode(VOID)
static const PNP_EVENT_TARGET_STATE m_PnpStartedOtherStates[]
Definition: fxpkgpnp.hpp:4391
VOID PnpProcessEvent(__in FxPnpEvent Event, __in BOOLEAN ProcessEventOnDifferentThread=FALSE)
static WDF_DEVICE_PNP_STATE PnpEventStoppedWaitForStartCompletion(__inout FxPkgPnp *This)
LIST_ENTRY m_InterruptListHead
Definition: fxpkgpnp.hpp:4310
VOID PnpFinishProcessingIrp(__in BOOLEAN IrpMustBePresent=TRUE)
_Must_inspect_result_ NTSTATUS ValidateCmResource(__inout PCM_PARTIAL_RESOURCE_DESCRIPTOR *CmResourceRaw, __inout PCM_PARTIAL_RESOURCE_DESCRIPTOR *CmResource)
static const PWCHAR m_RestartStartTimeName
Definition: fxpkgpnp.hpp:4526
FxPnpStateAndCaps m_PnpStateAndCaps
Definition: fxpkgpnp.hpp:4088
static WDF_DEVICE_PNP_STATE PnpEventQueryStopAskDriver(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpInitStartingOtherStates[]
Definition: fxpkgpnp.hpp:4386
BOOLEAN m_DeviceInterfacesCanBeEnabled
Definition: fxpkgpnp.hpp:4128
static WDF_DEVICE_PNP_STATE PnpEventInitStarting(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventQueryRemovePending(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventRestarting(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventPdoInitFailed(__inout FxPkgPnp *This)
NTSTATUS CompletePnpRequest(__inout FxIrp *Irp, __in NTSTATUS Status)
Definition: fxpkgpnp.cpp:5752
_Must_inspect_result_ NTSTATUS PnpReleaseHardware(VOID)
static const PNP_EVENT_TARGET_STATE m_PnpFailedPowerDownOtherStates[]
Definition: fxpkgpnp.hpp:4401
static WDF_DEVICE_PNP_STATE PnpEventPdoRestart(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventPdoRemoved(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventEjectHardware(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventStarted(__inout FxPkgPnp *This)
_Must_inspect_result_ NTSTATUS PnpPrepareHardwareInternal(VOID)
static WDF_DEVICE_PNP_STATE PnpEventFailedOwnHardware(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventFinal(__inout FxPkgPnp *This)
static WDF_DEVICE_PNP_STATE PnpEventRemovingDisableInterfaces(__inout FxPkgPnp *This)
VOID PnpProcessEventInner(__inout FxPostProcessInfo *Info)
static WDF_DEVICE_PNP_STATE PnpEventFdoRemoved(__inout FxPkgPnp *This)
static const ULONG m_RestartCountMaximum
Definition: fxpkgpnp.hpp:4539
static WDF_DEVICE_PNP_STATE PnpEventSurpriseRemoveIoStarted(__inout FxPkgPnp *This)
BOOLEAN PnpIncrementRestartCountLogic(_In_ HANDLE RestartKey, _In_ BOOLEAN CreatedNewKey)
static WDF_DEVICE_PNP_STATE PnpEventRestartHardwareAvailable(__inout FxPkgPnp *This)
static const PNP_EVENT_TARGET_STATE m_PnpRestartReleaseHardware[]
Definition: fxpkgpnp.hpp:4405
static WDF_DEVICE_PNP_STATE PnpEventRemovedPdoWait(__inout FxPkgPnp *This)
VOID PnpPowerPolicyStop(VOID)
VOID PowerPolicyProcessEvent(__in FxPowerPolicyEvent Event, __in BOOLEAN ProcessEventOnDifferentThread=FALSE)
_Must_inspect_result_ NTSTATUS Invoke(__in WDFDEVICE Device, __in WDFCMRESLIST ResourcesRaw, __in WDFCMRESLIST ResourcesTranslated)
_Must_inspect_result_ NTSTATUS Invoke(__in WDFDEVICE Device, __in WDFCMRESLIST ResourcesTranslated)
CM_PARTIAL_RESOURCE_DESCRIPTOR m_DescriptorClone
Definition: fxresource.hpp:259
CM_PARTIAL_RESOURCE_DESCRIPTOR m_Descriptor
Definition: fxresource.hpp:251
_Must_inspect_result_ FxTransactionedEntry * GetNextEntry(__in_opt FxTransactionedEntry *Entry)
VOID UnlockFromEnum(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
VOID LockForEnum(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
VOID InvalidateDeviceState(__in MdDeviceObject Fdo)
static __inline VOID MxQueryTickCount(__out PLARGE_INTEGER TickCount)
Definition: mxgeneralkm.h:116
static __inline VOID MxReleaseRemoveLockAndWait(__in MdRemoveLock RemoveLock, __in PVOID Tag)
Definition: mxgeneralkm.h:288
static __inline NTSTATUS MxAcquireRemoveLock(__in MdRemoveLock RemoveLock, __in_opt PVOID Tag)
Definition: mxgeneralkm.h:268
static __inline ULONG MxQueryTimeIncrement()
Definition: mxgeneralkm.h:125
#define STATUS_PENDING
Definition: d3dkmdt.h:43
#define STATUS_NOT_SUPPORTED
Definition: d3dkmdt.h:48
#define __in
Definition: dbghelp.h:35
#define __inout
Definition: dbghelp.h:50
#define TRACINGPNPPOWERSTATES
Definition: dbgtrace.h:69
#define TRACINGPNP
Definition: dbgtrace.h:67
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define __drv_when(cond, annotes)
Definition: driverspecs.h:335
#define __drv_arg(expr, annotes)
Definition: driverspecs.h:258
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
unsigned long DWORD
Definition: ntddk_ex.h:95
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
PFX_DRIVER_GLOBALS fxDriverGlobals
FxDeviceInterface * pDeviceInterface
PSINGLE_LIST_ENTRY ple
FxVerifierDbgBreakPoint(pFxDriverGlobals)
@ OkForDownLevel
Definition: fxglobals.h:80
#define COVERAGE_TRAP()
Definition: fxmacros.hpp:246
@ FxIoStopProcessingForPowerPurgeNonManaged
@ FxIoStopProcessingForPowerPurgeManaged
@ FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE
Definition: fxpkgpnp.hpp:88
#define DO_EVENT_TRAP(x)
Definition: fxpkgpnp.hpp:61
#define DEBUGGED_EVENT
Definition: fxpkgpnp.hpp:59
@ FxPnpStateResourcesChangedUseDefault
Definition: fxpkgpnp.hpp:277
@ FxPnpStateRemovedMask
Definition: fxpkgpnp.hpp:273
@ FxPnpStateFailedMask
Definition: fxpkgpnp.hpp:263
@ FxPnpStateRemovedUseDefault
Definition: fxpkgpnp.hpp:272
@ FxPnpStateFailedUseDefault
Definition: fxpkgpnp.hpp:262
@ FxPnpStateResourcesChangedMask
Definition: fxpkgpnp.hpp:278
@ FxPnpStateRemovedTrue
Definition: fxpkgpnp.hpp:271
#define TRAP_ON_EVENT
Definition: fxpkgpnp.hpp:60
@ PnpEventEject
@ PnpEventNull
@ PnpEventRemove
@ PnpEventPowerUpFailed
@ PnpEventPending
@ PnpEventSurpriseRemove
@ PnpEventStartDeviceComplete
@ PnpEventPwrPolStopFailed
@ PnpEventPwrPolStarted
@ PnpEventStop
@ PnpEventPwrPolRemoved
@ PnpEventPwrPolStartFailed
@ PnpEventQueryRemove
@ PnpEventStartDevice
@ PnpEventCancelStop
@ PnpEventStartDeviceFailed
@ PnpEventQueryStop
@ PnpEventPowerDownFailed
@ PnpEventCancelRemove
@ PnpEventParentRemoved
@ PnpEventPwrPolStopped
@ PnpEventAddDevice
@ PnpPriorityEventsMask
@ PnpEventDeviceInD0
@ PnpEventChildrenRemovalComplete
FxIrp * irp
@ FxResourceNoAccess
Definition: fxresource.hpp:274
FxCollectionEntry * cur
@ FX_TYPE_RESOURCE_CM
Definition: fxtypes.h:70
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
struct _cl_event * event
Definition: glext.h:7739
GLuint res
Definition: glext.h:9613
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
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
#define CmResourceTypeInterrupt
Definition: hwresource.cpp:124
uint32_t entry
Definition: isohybrid.c:63
if(dx< 0)
Definition: linetemp.h:194
#define ASSERT(a)
Definition: mode.c:44
#define DO_NOTHING()
Definition: mxgeneral.h:32
#define _Must_inspect_result_
Definition: no_sal2.h:62
#define _In_
Definition: no_sal2.h:158
#define REG_BINARY
Definition: nt_native.h:1496
#define FILE_REMOVABLE_MEDIA
Definition: nt_native.h:807
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
#define STATUS_DEVICE_POWER_FAILURE
Definition: ntstatus.h:394
unsigned short USHORT
Definition: pedump.c:61
#define RESTART_START_ACHIEVED_NAME
#define RESTART_COUNT_NAME
#define VALIDATE_PNP_STATE(_CurrentState, _NewState)
#define RESTART_START_TIME_NAME
#define REG_DWORD
Definition: sdbapi.c:596
#define exit(n)
Definition: config.h:202
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:70
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define TRACE_LEVEL_VERBOSE
Definition: storswtr.h:30
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_INFORMATION
Definition: storswtr.h:29
_Must_inspect_result_ FxCollectionEntry * Start(VOID)
_Must_inspect_result_ FxCollectionEntry * End(VOID)
FxWaitLockTransactionedList m_ChildListList
Definition: fxpkgpnp.hpp:485
VOID IncrementHead(VOID)
UCHAR IncrementHistoryIndex(VOID)
UCHAR InsertAtTail(VOID)
BOOLEAN IsEmpty(VOID)
UCHAR InsertAtHead(VOID)
FxWaitLockInternal m_StateMachineLock
BOOLEAN IsClosedLocked(VOID)
UCHAR GetHead(VOID)
VOID GetFinishedState(__inout FxPostProcessInfo *Info)
BOOLEAN IsFull(VOID)
FxPnpMachineStateHistory m_States
FxPnpEvent m_Queue[PnpEventQueueDepth]
VOID Invoke(__in WDF_DEVICE_PNP_STATE State, __in WDF_STATE_NOTIFICATION_TYPE Type, __in WDFDEVICE Device, __in PCWDF_DEVICE_PNP_NOTIFICATION_DATA NotificationData)
BOOLEAN m_WaitWakeOwner
Definition: fxpkgpnp.hpp:186
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@391::@395 MessageInterrupt
union _CM_PARTIAL_RESOURCE_DESCRIPTOR::@391 u
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: ntbasedef.h:636
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:637
Definition: ps.c:97
Definition: dhcpd.h:245
unsigned char * PBOOLEAN
Definition: typedefs.h:53
int64_t LONGLONG
Definition: typedefs.h:68
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
USHORT History[PnpEventQueueDepth]
LONGLONG QuadPart
Definition: typedefs.h:114
Definition: pdh_main.c:94
#define WDFCASSERT(c)
Definition: wdfassert.h:93
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
#define DECLARE_CONST_UNICODE_STRING(_variablename, _string)
Definition: wdfcore.h:161
FORCEINLINE LONGLONG WDF_ABS_TIMEOUT_IN_SEC(_In_ ULONGLONG Time)
Definition: wdfcore.h:71
@ WdfDevStatePnpInit
Definition: wdfdevice.h:69
@ WdfDevStatePnpFailedPowerPolicyRemoved
Definition: wdfdevice.h:121
@ WdfDevStatePnpFinal
Definition: wdfdevice.h:117
@ WdfDevStatePnpFailedSurpriseRemoved
Definition: wdfdevice.h:108
@ WdfDevStatePnpFailed
Definition: wdfdevice.h:107
@ WdfDevStatePnpInitQueryRemove
Definition: wdfdevice.h:98
@ WdfDevStatePnpHardwareAvailablePowerPolicyFailed
Definition: wdfdevice.h:74
@ WdfDevStatePnpQueryRemovePending
Definition: wdfdevice.h:76
@ WdfDevStatePnpStartedStopping
Definition: wdfdevice.h:96
@ WdfDevStatePnpInitSurpriseRemoved
Definition: wdfdevice.h:71
@ WdfDevStatePnpRemovedChildrenRemoved
Definition: wdfdevice.h:118
@ WdfDevStatePnpRemovingDisableInterfaces
Definition: wdfdevice.h:87
@ WdfDevStatePnpRemoved
Definition: wdfdevice.h:83
@ WdfDevStatePnpStartedCancelStop
Definition: wdfdevice.h:90
@ WdfDevStatePnpStartedRemoving
Definition: wdfdevice.h:92
@ WdfDevStatePnpRemovedWaitForChildren
Definition: wdfdevice.h:101
@ WdfDevStatePnpQueryStopAskDriver
Definition: wdfdevice.h:79
@ WdfDevStatePnpQueriedSurpriseRemove
Definition: wdfdevice.h:102
@ WdfDevStatePnpFailedIoStarting
Definition: wdfdevice.h:105
@ WdfDevStatePnpRestart
Definition: wdfdevice.h:113
@ WdfDevStatePnpStarted
Definition: wdfdevice.h:89
@ WdfDevStatePnpPdoRemoved
Definition: wdfdevice.h:84
@ WdfDevStatePnpInitStarting
Definition: wdfdevice.h:70
@ WdfDevStatePnpFailedPowerDown
Definition: wdfdevice.h:104
@ WdfDevStatePnpStartingFromStopped
Definition: wdfdevice.h:93
@ WdfDevStatePnpStopped
Definition: wdfdevice.h:94
@ WdfDevStatePnpSurpriseRemove
Definition: wdfdevice.h:97
@ WdfDevStatePnpQueryStopStaticCheck
Definition: wdfdevice.h:81
@ WdfDevStatePnpEnableInterfaces
Definition: wdfdevice.h:73
@ WdfDevStatePnpFailedOwnHardware
Definition: wdfdevice.h:106
@ WdfDevStatePnpRemovedPdoWait
Definition: wdfdevice.h:85
@ WdfDevStatePnpQueryRemoveStaticCheck
Definition: wdfdevice.h:77
@ WdfDevStatePnpRestartHardwareAvailable
Definition: wdfdevice.h:115
@ WdfDevStatePnpFailedStarted
Definition: wdfdevice.h:109
@ WdfDevStatePnpQueryRemoveEnsureDeviceAwake
Definition: wdfdevice.h:119
@ WdfDevStatePnpStartedCancelRemove
Definition: wdfdevice.h:91
@ WdfDevStatePnpQueriedRemoving
Definition: wdfdevice.h:78
@ WdfDevStatePnpEjectHardware
Definition: wdfdevice.h:67
@ WdfDevStatePnpQueryStopEnsureDeviceAwake
Definition: wdfdevice.h:120
@ WdfDevStatePnpQueryStopPending
Definition: wdfdevice.h:80
@ WdfDevStatePnpPdoRestart
Definition: wdfdevice.h:116
@ WdfDevStatePnpQueryCanceled
Definition: wdfdevice.h:82
@ WdfDevStatePnpQueryRemoveAskDriver
Definition: wdfdevice.h:75
@ WdfDevStatePnpRemovedPdoSurpriseRemoved
Definition: wdfdevice.h:86
@ WdfDevStatePnpStoppedWaitForStartCompletion
Definition: wdfdevice.h:95
@ WdfDevStatePnpRestarting
Definition: wdfdevice.h:88
@ WdfDevStatePnpFailedInit
Definition: wdfdevice.h:111
@ WdfDevStatePnpCheckForDevicePresence
Definition: wdfdevice.h:65
@ WdfDevStatePnpRestartReleaseHardware
Definition: wdfdevice.h:114
@ WdfDevStatePnpNull
Definition: wdfdevice.h:122
@ WdfDevStatePnpInitQueryRemoveCanceled
Definition: wdfdevice.h:99
@ WdfDevStatePnpObjectCreated
Definition: wdfdevice.h:64
@ WdfDevStatePnpFailedWaitForRemove
Definition: wdfdevice.h:110
@ WdfDevStatePnpSurpriseRemoveIoStarted
Definition: wdfdevice.h:103
@ WdfDevStatePnpHardwareAvailable
Definition: wdfdevice.h:72
@ StateNotificationEnterState
Definition: wdfdevice.h:392
@ StateNotificationPostProcessState
Definition: wdfdevice.h:393
@ StateNotificationLeaveState
Definition: wdfdevice.h:394
@ WdfDeviceFailedAttemptRestart
Definition: wdfdevice.h:469
@ WdfDeviceFailedUndefined
Definition: wdfdevice.h:468
@ WdfSpecialFileBoot
Definition: wdfdevice.h:445
@ WdfSpecialFileHibernation
Definition: wdfdevice.h:443
@ WdfSpecialFileDump
Definition: wdfdevice.h:444
@ WdfSpecialFilePaging
Definition: wdfdevice.h:442
enum _WDF_DEVICE_PNP_STATE WDF_DEVICE_PNP_STATE
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG Configuration
Definition: wdfinterrupt.h:374
#define IRP_MN_START_DEVICE