1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FdoPower.cpp
8
9 Abstract:
10
11 This module implements the pnp/power package for the driver
12 framework. This, specifically, is the power code.
13
14 Author:
15
16
17
18
19 Environment:
20
21 Both kernel and user mode
22
23 Revision History:
24
25
26
27
28 --*/
29
30 #include "pnppriv.hpp"
31
32
33
34
35 #if defined(EVENT_TRACING)
36 extern "C" {
37 #include "FdoPower.tmh"
38 }
39 #endif
40
41 _Must_inspect_result_
42 NTSTATUS
_PowerPassDown(__inout FxPkgPnp * This,__in FxIrp * Irp)43 FxPkgFdo::_PowerPassDown(
44 __inout FxPkgPnp* This,
45 __in FxIrp *Irp
46 )
47
48 /*++
49
50 Routine Description:
51
52 This method is invoked when a Power Irp we don't handle comes into the
53 driver.
54
55 Arguemnts:
56
57 This - the package
58
59 Irp - a pointer to the FxIrp
60
61 Returns:
62
63 NTSTATUS
64
65 --*/
66 {
67 FxPkgFdo* pThis;
68 NTSTATUS status;
69 MdIrp pIrp;
70
71 pIrp = Irp->GetIrp();
72 pThis = (FxPkgFdo*) This;
73
74 //
75 // FDOs don't handle this IRP, so simply pass it down.
76 //
77 Irp->StartNextPowerIrp();
78 Irp->CopyCurrentIrpStackLocationToNext();
79
80 status = Irp->PoCallDriver(pThis->m_Device->GetAttachedDevice());
81
82 Mx::MxReleaseRemoveLock(pThis->m_Device->GetRemoveLock(),
83 pIrp);
84
85 return status;
86 }
87
88 _Must_inspect_result_
89 NTSTATUS
_DispatchSetPower(__inout FxPkgPnp * This,__in FxIrp * Irp)90 FxPkgFdo::_DispatchSetPower(
91 __inout FxPkgPnp* This,
92 __in FxIrp *Irp
93 )
94 /*++
95
96 Routine Description:
97
98 This method is invoked when a SetPower IRP enters the driver.
99
100 Arguemnts:
101
102 Device - a pointer to the FxDevice
103
104 Irp - a pointer to the FxIrp
105
106 Returns:
107
108 NTSTATUS
109
110 --*/
111
112 {
113 if (Irp->GetParameterPowerType() == SystemPowerState) {
114 return ((FxPkgFdo*) This)->DispatchSystemSetPower(Irp);
115 }
116 else {
117 return ((FxPkgFdo*) This)->DispatchDeviceSetPower(Irp);
118 }
119 }
120
121 _Must_inspect_result_
122 NTSTATUS
_DispatchQueryPower(__inout FxPkgPnp * This,__in FxIrp * Irp)123 FxPkgFdo::_DispatchQueryPower(
124 __inout FxPkgPnp* This,
125 __in FxIrp *Irp
126 )
127
128 /*++
129
130 Routine Description:
131
132 This method is invoked when a QueryPower IRP enters the driver.
133
134 Arguemnts:
135
136 This - The package
137
138 Irp - a pointer to the FxIrp
139
140 Returns:
141
142 NTSTATUS
143
144 --*/
145
146 {
147 if (Irp->GetParameterPowerType() == SystemPowerState) {
148 return ((FxPkgFdo*) This)->DispatchSystemQueryPower(Irp);
149 }
150 else {
151 return ((FxPkgFdo*) This)->DispatchDeviceQueryPower(Irp);
152 }
153 }
154
155 _Must_inspect_result_
156 NTSTATUS
157 STDCALL
_SystemPowerS0Completion(__in MdDeviceObject DeviceObject,__in MdIrp OriginalIrp,__in PVOID Context)158 FxPkgFdo::_SystemPowerS0Completion(
159 __in MdDeviceObject DeviceObject,
160 __in MdIrp OriginalIrp,
161 __in PVOID Context
162 )
163 {
164 FxPkgPnp* pPkgPnp;
165 KIRQL irql;
166 FxIrp irp(OriginalIrp);
167
168 pPkgPnp = (FxPkgPnp*) Context;
169
170 //
171 // Ideally we would like to complete the S0 irp before we start
172 // processing the event in the state machine so that the D0 irp
173 // comes after the S0 is moving up the stack...
174 //
175 // ... BUT ...
176 //
177 // ... by allowing the S0 irp to go up the stack first, we must then
178 // handle pnp requests from the current power policy state (because
179 // the S0 irp could be the last S irp in the system and when completed,
180 // the pnp lock is released). So, we process the event first so
181 // that we can move into a state where we can handle pnp events in
182 // the power policy state machine.
183 //
184 // We mitigate the situation a little bit by forcing the processing of the
185 // event to occur on the power policy thread rather then in the current
186 // context.
187 //
188 Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql);
189 pPkgPnp->PowerPolicyProcessEvent(PwrPolS0);
190 Mx::MxLowerIrql(irql);
191
192 irp.StartNextPowerIrp();
193
194 //
195 // Let the irp continue on its way
196 //
197 if (irp.PendingReturned()) {
198 irp.MarkIrpPending();
199 }
200
201 Mx::MxReleaseRemoveLock((&FxDevice::_GetFxWdmExtension(DeviceObject)->IoRemoveLock),
202 OriginalIrp);
203
204 return irp.GetStatus();
205 }
206
207 _Must_inspect_result_
208 NTSTATUS
209 STDCALL
_SystemPowerSxCompletion(__in MdDeviceObject DeviceObject,__in MdIrp OriginalIrp,__in PVOID Context)210 FxPkgFdo::_SystemPowerSxCompletion(
211 __in MdDeviceObject DeviceObject,
212 __in MdIrp OriginalIrp,
213 __in PVOID Context
214 )
215 {
216 FxPkgFdo *pThis;
217 FxIrp irp(OriginalIrp);
218
219 UNREFERENCED_PARAMETER(DeviceObject);
220
221 pThis = (FxPkgFdo*) Context;
222
223 ASSERT(pThis->IsPowerPolicyOwner());
224 ASSERT(OriginalIrp == pThis->GetPendingSystemPowerIrp());
225
226 pThis->PowerPolicyProcessEvent(PwrPolSx);
227
228 //
229 // Power policy will complete the system irp
230 //
231 return STATUS_MORE_PROCESSING_REQUIRED;
232 }
233
234 _Must_inspect_result_
235 NTSTATUS
DispatchSystemSetPower(__in FxIrp * Irp)236 FxPkgFdo::DispatchSystemSetPower(
237 __in FxIrp *Irp
238 )
239 {
240 NTSTATUS status;
241 MxDeviceObject deviceObject(m_Device->GetDeviceObject());
242
243 m_SystemPowerState = (BYTE) Irp->GetParameterPowerStateSystemState();
244 deviceObject.SetPowerState(SystemPowerState,
245 Irp->GetParameterPowerState());
246
247 if (IsPowerPolicyOwner()) {
248 //
249 // If we are going to S0, we just notify the power policy state machine
250 // and then let the request go (per the fast resume spec). Otherwise,
251 // send the request down and on the way up, send the Dx request.
252 //
253 if (m_SystemPowerState == PowerSystemWorking) {
254 //
255 // Post the event into the state machine when the irp is going up
256 // the stack. See the comment in _SystemPowerS0Completion for more
257 // detail as to why.
258 //
259 Irp->CopyCurrentIrpStackLocationToNext();
260 Irp->SetCompletionRoutineEx(deviceObject.GetObject(),
261 _SystemPowerS0Completion,
262 this);
263
264 return Irp->PoCallDriver(m_Device->GetAttachedDevice());
265 }
266 else {
267 //
268 // Stash away the irp for the power policy state machine. We will
269 // post the event to the power policy state machine when the S irp
270 // completes back to this driver.
271 //
272 SetPendingSystemPowerIrp(Irp);
273
274 Irp->CopyCurrentIrpStackLocationToNext();
275 Irp->SetCompletionRoutineEx(deviceObject.GetObject(),
276 _SystemPowerSxCompletion,
277 this);
278
279 Irp->PoCallDriver(m_Device->GetAttachedDevice());
280
281 status = STATUS_PENDING;
282 }
283 }
284 else {
285 //
286 // We don't do anything with S irps if we are not the power policy
287 // owner.
288 //
289 // This will release the remove lock as well.
290 //
291 status = _PowerPassDown(this, Irp);
292 }
293
294 return status;
295 }
296
297 _Must_inspect_result_
298 NTSTATUS
DispatchDeviceSetPower(__in FxIrp * Irp)299 FxPkgFdo::DispatchDeviceSetPower(
300 __in FxIrp *Irp
301 )
302
303 {
304 NTSTATUS status;
305
306 if (IsPowerPolicyOwner()) {
307 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp == FALSE &&
308 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp == FALSE) {
309 //
310 // A power irp arrived, but we did not request it. log and bugcheck
311 //
312 DoTraceLevelMessage(
313 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
314 "Received set device power irp 0x%p on WDFDEVICE 0x%p !devobj 0x%p, "
315 "but the irp was not requested by the device (the power policy owner)",
316 Irp->GetIrp(), m_Device->GetHandle(),
317 m_Device->GetDeviceObject());
318
319 FxVerifierBugCheck(GetDriverGlobals(), // globals
320 WDF_POWER_MULTIPLE_PPO, // specific type
321 (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2
322 (ULONG_PTR)Irp->GetIrp()); // parm 3
323
324 /* NOTREACHED */
325 }
326
327 //
328 // We are no longer requesting a power irp because we received the one
329 // we requested.
330 //
331 if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) {
332 m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE;
333 } else {
334 m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE;
335 }
336 }
337
338 //
339 // Determine if we are raising or lowering the device power state.
340 //
341 if (Irp->GetParameterPowerStateDeviceState() == PowerDeviceD0) {
342 status = RaiseDevicePower(Irp);
343 }
344 else {
345 status = LowerDevicePower(Irp);
346 }
347
348 return status;
349 }
350
351 _Must_inspect_result_
352 NTSTATUS
RaiseDevicePower(__in FxIrp * Irp)353 FxPkgFdo::RaiseDevicePower(
354 __in FxIrp *Irp
355 )
356 {
357 Irp->MarkIrpPending();
358 Irp->CopyCurrentIrpStackLocationToNext();
359 Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(),
360 RaiseDevicePowerCompletion,
361 this);
362
363 Irp->PoCallDriver(m_Device->GetAttachedDevice());
364
365 return STATUS_PENDING;
366 }
367
368 _Must_inspect_result_
369 NTSTATUS
370 STDCALL
RaiseDevicePowerCompletion(__in MdDeviceObject DeviceObject,__in MdIrp OriginalIrp,__in PVOID Context)371 FxPkgFdo::RaiseDevicePowerCompletion(
372 __in MdDeviceObject DeviceObject,
373 __in MdIrp OriginalIrp,
374 __in PVOID Context
375 )
376 {
377 FxPkgFdo* pThis;
378 FxIrp irp(OriginalIrp);
379
380 UNREFERENCED_PARAMETER(DeviceObject);
381
382 pThis = (FxPkgFdo*) Context;
383
384 //
385 // We can safely cache away the device power irp in our fdo package
386 // storage because we know we can only get one device power irp at
387 // a time.
388 //
389 pThis->SetPendingDevicePowerIrp(&irp);
390
391 //
392 // Kick off the power state machine.
393 //
394 pThis->PowerProcessEvent(PowerD0);
395
396 return STATUS_MORE_PROCESSING_REQUIRED;
397 }
398
399 _Must_inspect_result_
400 NTSTATUS
LowerDevicePower(__in FxIrp * Irp)401 FxPkgFdo::LowerDevicePower(
402 __in FxIrp *Irp
403 )
404 {
405 SetPendingDevicePowerIrp(Irp);
406
407 //
408 // Kick off the power state machine.
409 //
410 PowerProcessEvent(PowerDx);
411
412 return STATUS_PENDING;
413 }
414
415 _Must_inspect_result_
416 NTSTATUS
DispatchSystemQueryPower(__in FxIrp * Irp)417 FxPkgFdo::DispatchSystemQueryPower(
418 __in FxIrp *Irp
419 )
420 {
421 if (PowerPolicyIsWakeEnabled()) {
422 NTSTATUS status;
423
424 status = PowerPolicyHandleSystemQueryPower(
425 Irp->GetParameterPowerStateSystemState()
426 );
427
428 Irp->SetStatus(status);
429
430 if (!NT_SUCCESS(status)) {
431 return CompletePowerRequest(Irp, status);
432 }
433 }
434
435 //
436 // Passing down the irp because one of the following
437 // a) We don't care b/c we don't control the power policy
438 // b) we are not enabled for arming for wake from Sx
439 // c) we can wake from the queried S state
440 //
441 return _PowerPassDown(this, Irp);
442 }
443
444 _Must_inspect_result_
445 NTSTATUS
DispatchDeviceQueryPower(__in FxIrp * Irp)446 FxPkgFdo::DispatchDeviceQueryPower(
447 __in FxIrp *Irp
448 )
449 {
450 //
451 // Either the framework is the power policy owner and we wouldn't be sending
452 // a device query power or we are a subordinate will do what the power
453 // policy owner wants 100% of the time.
454 //
455 Irp->SetStatus(STATUS_SUCCESS);
456
457 //
458 // This will release the remove lock
459 //
460 return _PowerPassDown(this, Irp);
461 }
462
463 VOID
PowerReleasePendingDeviceIrp(__in BOOLEAN IrpMustBePresent)464 FxPkgFdo::PowerReleasePendingDeviceIrp(
465 __in BOOLEAN IrpMustBePresent
466 )
467 {
468 MdIrp pIrp;
469
470 pIrp = ClearPendingDevicePowerIrp();
471
472 UNREFERENCED_PARAMETER(IrpMustBePresent);
473 ASSERT(IrpMustBePresent == FALSE || pIrp != NULL);
474
475 if (pIrp != NULL) {
476 FxIrp irp(pIrp);
477
478 if (irp.GetParameterPowerStateDeviceState() == PowerDeviceD0) {
479 //
480 // We catch D0 irps on the way up, so complete it
481 //
482 CompletePowerRequest(&irp, STATUS_SUCCESS);
483 }
484 else {
485 irp.SetStatus(STATUS_SUCCESS);
486
487 //
488 // We catch Dx irps on the way down, so send it on its way
489 //
490 // This will also release the remove lock
491 //
492 (void) _PowerPassDown(this, &irp);
493 }
494 }
495 }
496
497 WDF_DEVICE_POWER_STATE
PowerCheckDeviceTypeOverload(VOID)498 FxPkgFdo::PowerCheckDeviceTypeOverload(
499 VOID
500 )
501 /*++
502
503 Routine Description:
504 This function implements the Check Type state. This is FDO code,
505 so the answer is reductionistly simple.
506
507 Arguments:
508 none
509
510 Return Value:
511
512 new power state
513
514 --*/
515 {
516 return WdfDevStatePowerWaking;
517 }
518
519 WDF_DEVICE_POWER_STATE
PowerCheckDeviceTypeNPOverload(VOID)520 FxPkgFdo::PowerCheckDeviceTypeNPOverload(
521 VOID
522 )
523 /*++
524
525 Routine Description:
526 This function implements the Check Type state. This is FDO code,
527 so the answer is reductionistly simple.
528
529 Arguments:
530 none
531
532 Return Value:
533
534 new power state
535
536 --*/
537 {
538 return WdfDevStatePowerWakingNP;
539 }
540
541 _Must_inspect_result_
542 NTSTATUS
PowerCheckParentOverload(__out BOOLEAN * ParentOn)543 FxPkgFdo::PowerCheckParentOverload(
544 __out BOOLEAN* ParentOn
545 )
546 /*++
547
548 Routine Description:
549 This function implements the CheckParent state. Its
550 job is to determine which state we should go to next based on whether
551 the parent is in D0. But since this is the FDO code, we can't know
552 that. So just assume that the PDO will guarantee it.
553
554 Arguments:
555 none
556
557 Return Value:
558
559 new power state
560
561 --*/
562 {
563 ASSERT(!"This state shouldn't be reachable for an FDO.");
564 *ParentOn = TRUE;
565 return STATUS_SUCCESS;
566 }
567
568 VOID
PowerParentPowerDereference(VOID)569 FxPkgFdo::PowerParentPowerDereference(
570 VOID
571 )
572 /*++
573
574 Routine Description:
575 This virtual function is a nop for an FDO. PDOs implement this function
576
577 Arguments:
578 None
579
580 Return Value:
581 None
582
583 --*/
584 {
585 DO_NOTHING();
586 }
587