1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 PdoPower.cpp
8
9 Abstract:
10
11 This module implements the Pnp package for Pdo devices.
12
13 Author:
14
15
16
17
18 Environment:
19
20 Both kernel and user mode
21
22 Revision History:
23
24
25
26 --*/
27
28 #include "pnppriv.hpp"
29
30 // Tracing support
31 #if defined(EVENT_TRACING)
32 extern "C" {
33 #include "PdoPower.tmh"
34 }
35 #endif
36
37 _Must_inspect_result_
38 NTSTATUS
_DispatchPowerSequence(__inout FxPkgPnp * This,__in FxIrp * Irp)39 FxPkgPdo::_DispatchPowerSequence(
40 __inout FxPkgPnp* This,
41 __in FxIrp *Irp
42 )
43 /*++
44
45 Routine Description:
46 report the power sequence for the child
47
48 Arguments:
49 This - the package
50
51 Irp - the request
52
53 Return Value:
54 STATUS_NOT_SUPPORTED
55
56 --*/
57 {
58 return ((FxPkgPdo*) This)->CompletePowerRequest(Irp, STATUS_NOT_SUPPORTED);
59 }
60
61 _Must_inspect_result_
62 NTSTATUS
_DispatchSetPower(__inout FxPkgPnp * This,__in FxIrp * Irp)63 FxPkgPdo::_DispatchSetPower(
64 __inout FxPkgPnp* This,
65 __in FxIrp *Irp
66 )
67 /*++
68
69 Routine Description:
70
71 This method is invoked when a SetPower IRP enters the driver.
72
73 Arguemnts:
74
75 Device - a pointer to the FxDevice
76
77 Irp - a pointer to the FxIrp
78
79 Returns:
80
81 NTSTATUS
82
83 --*/
84 {
85 if (Irp->GetParameterPowerType() == SystemPowerState) {
86 return ((FxPkgPdo*) This)->DispatchSystemSetPower(Irp);
87 }
88 else {
89 return ((FxPkgPdo*) This)->DispatchDeviceSetPower(Irp);
90 }
91 }
92
93 _Must_inspect_result_
94 NTSTATUS
DispatchSystemSetPower(__in FxIrp * Irp)95 FxPkgPdo::DispatchSystemSetPower(
96 __in FxIrp *Irp
97 )
98 {
99 KIRQL irql;
100 MxDeviceObject deviceObject(m_Device->GetDeviceObject());
101
102 m_SystemPowerState = (BYTE) Irp->GetParameterPowerStateSystemState();
103 deviceObject.SetPowerState(SystemPowerState,
104 Irp->GetParameterPowerState());
105
106 if (IsPowerPolicyOwner()) {
107 if (m_SystemPowerState == PowerSystemWorking) {
108 //
109 // Ideally we would like to complete the S0 irp before we start
110 // processing the event in the state machine so that the D0 irp
111 // comes after the S0 is moving up the stack...
112 //
113 // ... BUT ...
114 //
115 // ... by allowing the S0 irp to go up the stack first, we must then
116 // handle pnp requests from the current power policy state (because
117 // the S0 irp could be the last S irp in the system and when completed,
118 // the pnp lock is released). So, we process the event first so
119 // that we can move into a state where we can handle pnp events in
120 // the power policy state machine.
121 //
122 // We mitigate the situation a little bit by forcing the processing of the
123 // event to occur on the power policy thread rather then in the current
124 // context.
125 //
126 Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql);
127 PowerPolicyProcessEvent(PwrPolS0);
128 Mx::MxLowerIrql(irql);
129
130 return CompletePowerRequest(Irp, STATUS_SUCCESS);
131 }
132 else {
133 //
134 // Power policy state machine will complete the request later
135 //
136 SetPendingSystemPowerIrp(Irp);
137 PowerPolicyProcessEvent(PwrPolSx);
138 return STATUS_PENDING;
139 }
140 }
141 else {
142 //
143 // Since we are not the power policy owner, we just complete all S irps
144 //
145 return CompletePowerRequest(Irp, STATUS_SUCCESS);
146 }
147 }
148
149 _Must_inspect_result_
150 NTSTATUS
DispatchDeviceSetPower(__in FxIrp * Irp)151 FxPkgPdo::DispatchDeviceSetPower(
152 __in FxIrp *Irp
153 )
154 {
155 if (IsPowerPolicyOwner()) {
156 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp == FALSE &&
157 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp == FALSE) {
158 //
159 // A power irp arrived, but we did not request it. ASSERT and log
160 // an error.
161 //
162 DoTraceLevelMessage(
163 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
164 "Received set device power irp 0x%p on WDFDEVICE 0x%p !devobj 0x%p, "
165 "but the irp was not requested by the device (the power policy owner)",
166 Irp->GetIrp(),
167 m_Device->GetHandle(),
168 m_Device->GetDeviceObject());
169
170 ASSERTMSG("Received set device power irp but the irp was not "
171 "requested by the device (the power policy owner)\n",
172 FALSE);
173 }
174
175 //
176 // We are no longer requesting a power irp because we received the one
177 // we requested.
178 //
179 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) {
180 m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE;
181 }
182 else {
183 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE;
184 }
185 }
186
187 SetPendingDevicePowerIrp(Irp);
188
189 if (Irp->GetParameterPowerStateDeviceState() == PowerDeviceD0) {
190 PowerProcessEvent(PowerD0);
191 }
192 else {
193 PowerProcessEvent(PowerDx);
194 }
195
196 return STATUS_PENDING;
197 }
198
199 _Must_inspect_result_
200 NTSTATUS
_DispatchQueryPower(__inout FxPkgPnp * This,__in FxIrp * Irp)201 FxPkgPdo::_DispatchQueryPower(
202 __inout FxPkgPnp* This,
203 __in FxIrp *Irp
204 )
205 /*++
206
207 Routine Description:
208 Dispatches query power for system and device requests
209
210 Arguments:
211 This - the package
212
213 Irp - the query power request
214
215 Return Value:
216 NTSTATUS
217
218 --*/
219 {
220 FxPkgPdo* pThis;
221 NTSTATUS status;
222
223 pThis = ((FxPkgPdo*) This);
224
225 if (Irp->GetParameterPowerType() == SystemPowerState
226 &&
227 This->PowerPolicyIsWakeEnabled()) {
228
229 status = pThis->PowerPolicyHandleSystemQueryPower(
230 Irp->GetParameterPowerStateSystemState()
231 );
232 }
233 else {
234 status = STATUS_SUCCESS;
235 }
236
237 return pThis->CompletePowerRequest(Irp, status);
238 }
239
240 VOID
PowerReleasePendingDeviceIrp(__in BOOLEAN IrpMustBePresent)241 FxPkgPdo::PowerReleasePendingDeviceIrp(
242 __in BOOLEAN IrpMustBePresent
243 )
244 {
245 MdIrp pIrp;
246
247 pIrp = ClearPendingDevicePowerIrp();
248
249 UNREFERENCED_PARAMETER(IrpMustBePresent);
250 ASSERT(IrpMustBePresent == FALSE || pIrp != NULL);
251
252 if (pIrp != NULL) {
253 FxIrp irp(pIrp);
254
255 CompletePowerRequest(&irp, STATUS_SUCCESS);
256 }
257 }
258
259 _Must_inspect_result_
260 NTSTATUS
PowerCheckParentOverload(__in BOOLEAN * ParentOn)261 FxPkgPdo::PowerCheckParentOverload(
262 __in BOOLEAN* ParentOn
263 )
264 /*++
265
266 Routine Description:
267 This function implements the CheckParent state. Its
268 job is to determine which state we should go to next based on whether
269 the parent is in D0.
270
271 Arguments:
272 none
273
274 Return Value:
275
276 VOID
277
278 --*/
279 {
280
281
282
283
284 return (m_Device->m_ParentDevice->m_PkgPnp)->
285 PowerPolicyCanChildPowerUp(ParentOn);
286 }
287
288 WDF_DEVICE_POWER_STATE
PowerCheckDeviceTypeOverload(VOID)289 FxPkgPdo::PowerCheckDeviceTypeOverload(
290 VOID
291 )
292 /*++
293
294 Routine Description:
295 This function implements the Check Type state. This is a PDO.
296
297 Arguments:
298 none
299
300 Return Value:
301
302 new power state
303
304 --*/
305 {
306 return WdfDevStatePowerCheckParentState;
307 }
308
309 WDF_DEVICE_POWER_STATE
PowerCheckDeviceTypeNPOverload(VOID)310 FxPkgPdo::PowerCheckDeviceTypeNPOverload(
311 VOID
312 )
313 /*++
314
315 Routine Description:
316 This function implements the Check Type state. This is a PDO.
317
318 Arguments:
319 none
320
321 Return Value:
322
323 new power state
324
325 --*/
326 {
327 return WdfDevStatePowerCheckParentStateNP;
328 }
329
330 _Must_inspect_result_
331 NTSTATUS
PowerEnableWakeAtBusOverload(VOID)332 FxPkgPdo::PowerEnableWakeAtBusOverload(
333 VOID
334 )
335 /*++
336
337 Routine Description:
338 Arms the device at the bus level for wake. This arming is generic since
339 the bus driver can only configure the device generically. The power policy
340 owner has already armed the device for wake in a device specific fashion
341 when it processed the wake irp (EvtDeviceArmDeviceForWakeFromS0/x if the ppo
342 is a WDF driver).
343
344 Arguments:
345 None
346
347 Return Value:
348 NTSTATUS, !NT_SUCCESS if the arm failed
349
350 --*/
351 {
352 NTSTATUS status;
353
354 //
355 // The EnableWakeAtBus callback should not be called twice in a row without
356 // an intermediate call to the DisableWakeAtBus callback.
357 //
358 ASSERT(m_EnableWakeAtBusInvoked == FALSE);
359
360 status = m_DeviceEnableWakeAtBus.Invoke(
361 m_Device->GetHandle(),
362 (SYSTEM_POWER_STATE) m_SystemPowerState
363 );
364
365 if (NT_SUCCESS(status)) {
366 m_EnableWakeAtBusInvoked = TRUE;
367 PowerNotifyParentChildWakeArmed();
368 }
369
370 return status;
371 }
372
373 VOID
PowerDisableWakeAtBusOverload(VOID)374 FxPkgPdo::PowerDisableWakeAtBusOverload(
375 VOID
376 )
377 /*++
378
379 Routine Description:
380 Disarms the device at the bus level for wake. This disarming is generic
381 since the bus driver can only configure the device generically. The power
382 policy owner may have already disarmed the device for wake in a device
383 specific fashion. For a WDF ppo EvtDeviceDisarmDeviceForWakeFromS0/x is
384 called after the bus has disarmed.
385
386 Arguments:
387 None
388
389 Return Value:
390 None
391
392 --*/
393 {
394 if (m_EnableWakeAtBusInvoked) {
395 m_EnableWakeAtBusInvoked = FALSE;
396 PowerNotifyParentChildWakeDisarmed();
397
398 m_DeviceDisableWakeAtBus.Invoke(m_Device->GetHandle());
399 }
400 }
401
402 VOID
PowerParentPowerDereference(VOID)403 FxPkgPdo::PowerParentPowerDereference(
404 VOID
405 )
406 /*++
407
408 Routine Description:
409 Releases the child power reference on the parent device. This allows the
410 parent to enter into an idle capable state. This power reference does not
411 prevent the parent from moving into Dx when the system power state changes.
412
413 Arguments:
414 None
415
416 Return Value:
417 None
418
419 --*/
420 {
421
422 m_Device->m_ParentDevice->m_PkgPnp->PowerPolicyChildPoweredDown();
423 }
424
425 VOID
PowerNotifyParentChildWakeArmed(VOID)426 FxPkgPdo::PowerNotifyParentChildWakeArmed(
427 VOID
428 )
429 /*++
430
431 Routine Description:
432 Notifies the parent device that the child is armed for wake. This will
433 cause the parent to increment its count of children armed for wake.
434
435 Arguments:
436 None
437
438 Return Value:
439 None
440
441 --*/
442 {
443 FxPowerPolicyOwnerSettings* settings;
444
445 ASSERT(m_Device->m_ParentDevice != NULL);
446
447
448
449
450
451 settings = m_Device->m_ParentDevice->m_PkgPnp->
452 m_PowerPolicyMachine.m_Owner;
453 if (settings != NULL) {
454 settings->IncrementChildrenArmedForWakeCount();
455 }
456 }
457
458 VOID
PowerNotifyParentChildWakeDisarmed(VOID)459 FxPkgPdo::PowerNotifyParentChildWakeDisarmed(
460 VOID
461 )
462 /*++
463
464 Routine Description:
465 Notifies the parent device that the child is not armed for wake. This will
466 cause the parent to decrement its count of children armed for wake.
467
468 Arguments:
469 None
470
471 Return Value:
472 None
473
474 --*/
475 {
476 FxPowerPolicyOwnerSettings* settings;
477
478 ASSERT(m_Device->m_ParentDevice != NULL);
479
480
481
482
483
484 settings = m_Device->m_ParentDevice->m_PkgPnp->
485 m_PowerPolicyMachine.m_Owner;
486 if (settings != NULL) {
487 settings->DecrementChildrenArmedForWakeCount();
488 }
489 }
490