1 /*++
2 
3 Copyright (c) Microsoft. All rights reserved.
4 
5 Module Name:
6 
7     PnpStateMachine.cpp
8 
9 Abstract:
10 
11     This module implements the PnP state machine for the driver framework.
12     This code was split out from FxPkgPnp.cpp.
13 
14 Author:
15 
16 
17 
18 
19 Environment:
20 
21     Kernel mode only
22 
23 Revision History:
24 
25 --*/
26 
27 #include "../pnppriv.hpp"
28 #include <wdmguid.h>
29 
30 #include<ntstrsafe.h>
31 
32 extern "C" {
33 #if defined(EVENT_TRACING)
34 #include "PnpStateMachineKM.tmh"
35 #endif
36 }
37 
38 BOOLEAN
39 FxPkgPnp::PnpCheckAndIncrementRestartCount(
40     VOID
41     )
42 /*++
43 
44 Routine Description:
45     This is a mode-dependent wrapper for PnpIncrementRestartCountLogic,
46     which determines if this device should ask the bus driver to
47     reenumerate the device. Please refer to PnpIncrementRestartCountLogic's
48     comment block for more information.
49 
50 Arguments:
51     None
52 
53 Return Value:
54     TRUE if a restart should be requested.
55 
56 --*/
57 {
58     NTSTATUS status;
59     FxAutoRegKey settings, restart;
60     ULONG disposition = 0;
61 
62     DECLARE_CONST_UNICODE_STRING(keyNameRestart, L"Restart");
63 
64     status = m_Device->OpenSettingsKey(&settings.m_Key);
65     if (!NT_SUCCESS(status)) {
66         return FALSE;
67     }
68 
69     //
70     // We ask for a volatile key so that upon reboot, the count is purged and we
71     // start a new fresh restart count.
72     //
73     status = FxRegKey::_Create(settings.m_Key,
74                                &keyNameRestart,
75                                &restart.m_Key,
76                                KEY_ALL_ACCESS,
77                                REG_OPTION_VOLATILE,
78                                &disposition);
79     if (!NT_SUCCESS(status)) {
80         return FALSE;
81     }
82 
83     return PnpIncrementRestartCountLogic(restart.m_Key,
84                                          disposition == REG_CREATED_NEW_KEY);
85 }
86 
87 BOOLEAN
88 FxPkgPnp::ShouldProcessPnpEventOnDifferentThread(
89     __in KIRQL CurrentIrql,
90     __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread
91     )
92 /*++
93 Routine Description:
94 
95     This function returns whether the PnP state machine should process the
96     current event on the same thread or on a different one.
97 
98 
99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 Arguemnts:
128 
129     CurrentIrql - The current IRQL
130 
131     CallerSpecifiedProcessingOnDifferentThread - Whether or not caller of
132         PnpProcessEvent specified that the event be processed on a different
133         thread.
134 
135 Returns:
136     TRUE if the PnP state machine should process the event on a different
137        thread.
138 
139     FALSE if the PnP state machine should process the event on the same thread
140 
141 --*/
142 {
143     //
144     // For KMDF, we ignore what the caller of PnpProcessEvent specified (which
145     // should always be FALSE, BTW) and base our decision on the current IRQL.
146     // If we are running at PASSIVE_LEVEL, we process on the same thread else
147     // we queue a work item.
148     //
149     UNREFERENCED_PARAMETER(CallerSpecifiedProcessingOnDifferentThread);
150 
151     ASSERT(FALSE == CallerSpecifiedProcessingOnDifferentThread);
152 
153     return (CurrentIrql == PASSIVE_LEVEL) ? FALSE : TRUE;
154 }
155 
156 _Must_inspect_result_
157 NTSTATUS
158 FxPkgPnp::CreatePowerThreadIfNeeded(
159     VOID
160     )
161 /*++
162 Routine description:
163     If needed, creates a thread for processing power IRPs
164 
165 Arguments:
166     None
167 
168 Return value:
169     An NTSTATUS code indicating success or failure of this function
170 --*/
171 {
172     NTSTATUS status = STATUS_SUCCESS;
173     MxDeviceObject pTopOfStack;
174 
175 
176 
177 
178 
179 
180 
181 
182 
183 
184 
185 
186     pTopOfStack.SetObject(
187         m_Device->GetAttachedDeviceReference());
188 
189     ASSERT(pTopOfStack.GetObject() != NULL);
190 
191     if (pTopOfStack.GetObject() != NULL) {
192         //
193         // If the top of the stack is not power pageable, the stack needs a power
194         // thread.  Query for it if we are not a PDO (and create it if the lower
195         // stack does not support it), and create it if we are a PDO.
196         //
197         // Some stacks send a usage notification when processing a start device, so
198         // a notification could have already traveled through the stack by the time
199         // the start irp has completed back up to this device.
200         //
201         if ((pTopOfStack.GetFlags() & DO_POWER_PAGABLE) == 0 &&
202             HasPowerThread() == FALSE) {
203             status = QueryForPowerThread();
204 
205             if (!NT_SUCCESS(status)) {
206                 SetInternalFailure();
207                 SetPendingPnpIrpStatus(status);
208             }
209         }
210 
211         pTopOfStack.DereferenceObject();
212         pTopOfStack.SetObject(NULL);
213     }
214 
215     return status;
216 }
217 
218 NTSTATUS
219 FxPkgPnp::PnpPrepareHardwareInternal(
220     VOID
221     )
222 /*++
223 Routine description:
224     This is mode-specific routine for Prepare hardware
225 
226 Arguments:
227     None
228 
229 Return value:
230     none.
231 --*/
232 {
233     //
234     // nothing to do for KMDF.
235     //
236     return STATUS_SUCCESS;
237 }
238 
239